diff --git a/CHANGELOG.md b/CHANGELOG.md index efb42a832ab..43bb3501a0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,27 +4,27 @@ CHANGELOG
Note: This is in reverse chronological order, so newer entries are added to the top. -| Contents | -| :--------------------- | -| [Swift Next](#swift-next) | -| [Swift 5.1](#swift-51) | -| [Swift 5.0](#swift-50) | -| [Swift 4.2](#swift-42) | -| [Swift 4.1](#swift-41) | -| [Swift 4.0](#swift-40) | -| [Swift 3.1](#swift-31) | -| [Swift 3.0](#swift-30) | -| [Swift 2.2](#swift-22) | -| [Swift 2.1](#swift-21) | -| [Swift 2.0](#swift-20) | -| [Swift 1.2](#swift-12) | -| [Swift 1.1](#swift-11) | -| [Swift 1.0](#swift-10) | +| Version | Released | Toolchain | +| :--------------------- | :--------- | :---------- | +| [Swift 5.2](#swift-52) | | | +| [Swift 5.1](#swift-51) | 2019-09-20 | Xcode 11.0 | +| [Swift 5.0](#swift-50) | 2019-03-25 | Xcode 10.2 | +| [Swift 4.2](#swift-42) | 2018-09-17 | Xcode 10.0 | +| [Swift 4.1](#swift-41) | 2018-03-29 | Xcode 9.3 | +| [Swift 4.0](#swift-40) | 2017-09-19 | Xcode 9.0 | +| [Swift 3.1](#swift-31) | 2017-03-27 | Xcode 8.3 | +| [Swift 3.0](#swift-30) | 2016-09-13 | Xcode 8.0 | +| [Swift 2.2](#swift-22) | 2016-03-21 | Xcode 7.3 | +| [Swift 2.1](#swift-21) | 2015-10-21 | Xcode 7.1 | +| [Swift 2.0](#swift-20) | 2015-09-17 | Xcode 7.0 | +| [Swift 1.2](#swift-12) | 2015-04-08 | Xcode 6.3 | +| [Swift 1.1](#swift-11) | 2014-12-02 | Xcode 6.1.1 | +| [Swift 1.0](#swift-10) | 2014-09-15 | Xcode 6.0 |
-Swift Next ----------- +Swift 5.2 +--------- * [SR-11429][]: diff --git a/CMakeLists.txt b/CMakeLists.txt index 95999d4aecc..bad49ba082b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -125,7 +125,7 @@ set(SWIFT_ANALYZE_CODE_COVERAGE FALSE CACHE STRING # SWIFT_VERSION is deliberately /not/ cached so that an existing build directory # can be reused when a new version of Swift comes out (assuming the user hasn't # manually set it as part of their own CMake configuration). -set(SWIFT_VERSION "5.1") +set(SWIFT_VERSION "5.1.1") set(SWIFT_VENDOR "" CACHE STRING "The vendor name of the Swift compiler") diff --git a/README.md b/README.md index dd00bfd1f34..f1cfae1a83d 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,6 @@ | | **Architecture** | **Master** | **Package** | |---|:---:|:---:|:---:| | **macOS** | x86_64 |[![Build Status](https://ci.swift.org/job/oss-swift-incremental-RA-osx/lastCompletedBuild/badge/icon)](https://ci.swift.org/job/oss-swift-incremental-RA-osx)|[![Build Status](https://ci.swift.org/job/oss-swift-package-osx/lastCompletedBuild/badge/icon)](https://ci.swift.org/job/oss-swift-package-osx)| -| **Ubuntu 14.04** | x86_64 | [![Build Status](https://ci.swift.org/job/oss-swift-incremental-RA-linux-ubuntu-14_04/lastCompletedBuild/badge/icon)](https://ci.swift.org/job/oss-swift-incremental-RA-linux-ubuntu-14_04)|[![Build Status](https://ci.swift.org/job/oss-swift-package-linux-ubuntu-14_04/lastCompletedBuild/badge/icon)](https://ci.swift.org/job/oss-swift-package-linux-ubuntu-14_04)| | **Ubuntu 16.04** | x86_64 | [![Build Status](https://ci.swift.org/job/oss-swift-incremental-RA-linux-ubuntu-16_04/lastCompletedBuild/badge/icon)](https://ci.swift.org/job/oss-swift-incremental-RA-linux-ubuntu-16_04)|[![Build Status](https://ci.swift.org/job/oss-swift-package-linux-ubuntu-16_04/lastCompletedBuild/badge/icon)](https://ci.swift.org/job/oss-swift-package-linux-ubuntu-16_04)| | **Ubuntu 18.04** | x86_64 | [![Build Status](https://ci.swift.org/job/oss-swift-incremental-RA-linux-ubuntu-18_04/lastCompletedBuild/badge/icon)](https://ci.swift.org/job/oss-swift-incremental-RA-linux-ubuntu-18_04)|[![Build Status](https://ci.swift.org/job/oss-swift-package-linux-ubuntu-18_04/lastCompletedBuild/badge/icon)](https://ci.swift.org/job/oss-swift-package-linux-ubuntu-18_04)| diff --git a/docs/CToSwiftNameTranslation.md b/docs/CToSwiftNameTranslation.md index d9a3778f663..5dcb5f83226 100644 --- a/docs/CToSwiftNameTranslation.md +++ b/docs/CToSwiftNameTranslation.md @@ -212,6 +212,29 @@ Additionally, typedefs for `void *` or `const void *` that are themselves annota If a typedef's underlying type is itself a "CF pointer" typedef, the "alias" typedef will be imported as a regular typealias, with the suffix "Ref" still dropped from its name (if present) unless doing so would conflict with another declaration in the same module as the typedef. +## Objective-C Properties + +By default, most property names are not transformed at all. However, if the getter of a property overrides a superclass or adopted protocol method that is also a property accessor, the Swift name of the overridden accessor's property will be used for consistency. If there's more than one such name, one is chosen arbitrarily. + +Properties with the type `BOOL` or `Boolean` use the name of the getter as the name of the Swift property by default, rather than the name of the property in Objective-C. This accounts for a difference in Swift and Objective-C naming conventions for boolean properties that use "is". + +```objc +@property(getter=isContrivedExample) BOOL contrivedExample; +@property BOOL hasAnotherForm; +``` + +```swift +var isContrivedExample: Bool { get set } +var hasAnotherForm: Bool { get set } +``` + +_This rule should probably have applied to C's native `bool` as well._ + +A property declaration with the `SwiftImportPropertyAsAccessors` API note will not be imported at all, and its accessors will be imported as methods. Additionally, properties whose names start with "accessibility" in the NSAccessibility protocol are always imported as methods, as are properties whose names start with "accessibility" in an `@interface` declaration (class or category) that provides the adoption of NSAccessibility. + +_Objective-C code has historically not been consistent about whether the NSAccessibility declarations should be considered properties and therefore the Swift compiler chooses to import them as methods, as a sort of lowest common denominator._ + + ## `swift_private` The `swift_private` Clang attribute prepends `__` onto the base name of any declaration being imported except initializers. For initializers with no arguments, a dummy `Void` argument with the name `__` is inserted; otherwise, the label for the first argument has `__` prepended. This transformation takes place after any other name manipulation, unless the declaration has a custom name. It will not occur if the declaration is an override; in that case the name needs to match the overridden declaration. @@ -252,6 +275,8 @@ __attribute__((swift_name("SpacecraftCoordinates"))) struct SPKSpacecraftCoordinates { double x, y, z, t; // space and time, of course }; + +// Usually seen as NS_SWIFT_NAME. ``` ```swift @@ -287,12 +312,10 @@ The `swift_name` attribute can be used to give a C function a custom name. The v ```objc __attribute__((swift_name("doSomething(to:bar:)"))) void doSomethingToFoo(Foo *foo, int bar); - -// Usually seen as NS_SWIFT_NAME. ``` ```swift -func doSomething(foo: UnsafeMutablePointer, bar: Int32) +func doSomething(to foo: UnsafeMutablePointer, bar: Int32) ``` An underscore can be used in place of an empty parameter label, as in Swift. @@ -430,4 +453,86 @@ Although enumerators always have global scope in C, they are often imported as m _Currently, `swift_name` does not even allow importing an enum case as a member of the enum type itself, even if the enum is not recognized as an `@objc` enum, error code enum, or option set (i.e. the situation where a case is imported as a global constant)._ + +### Fields of structs and unions; Objective-C properties + +The `swift_name` attribute can be applied to rename a struct or union field or an Objective-C property (whether on a class or a protocol). The value of the attribute must be a valid Swift identifier. + +```objc +struct SPKSpaceflightBooking { + const SPKLocation * _Nullable destination; + bool roundTrip __attribute__((swift_name("isRoundTrip"))); +}; +``` + +```swift +struct SPKSpaceflightBooking { + var destination: UnsafePointer? + var isRoundTrip: Bool +} +``` + + +### Objective-C methods + +The `swift_name` attribute can be used to give an Objective-C method a custom name. The value of the attribute must be a full Swift function name, including parameter labels. + +```objc +- (void)doSomethingToFoo:(Foo *)foo bar:(int)bar + __attribute__((swift_name("doSomethingImportant(to:bar:)"))); +``` + +```swift +func doSomethingImportant(to foo: UnsafeMutablePointer, bar: Int32) +``` + +As with functions, an underscore can be used to represent an empty parameter label. + +Methods that follow the NSError out-parameter convention may provide one fewer parameter label than the number of parameters in the original method to indicate that a parameter should be dropped, but they do not have to. The `swift_error` attribute is still respected even when using a custom name for purposes of transforming an NSError out-parameter and the method return type. + +```objc +- (BOOL)doSomethingRiskyAndReturnError:(NSError **)error + __attribute__((swift_name("doSomethingRisky()"))); +- (BOOL)doSomethingContrived:(NSString *)action error:(NSError **)outError + __attribute__((swift_name("doSomethingContrived(_:error:)"))); +``` + +```swift +func doSomethingRisky() throws +func doSomethingContrived(_ action: String, error: ()) throws +``` + +A base name of "init" can be used on a *class* method that returns `instancetype` or the containing static type in order to import that method as an initializer. Any other custom name *prevents* a class method from being imported as an initializer even if it would normally be inferred as one. + +```objc ++ (Action *)makeActionWithHandler:(void(^)(void))handler + __attribute__((swift_name("init(handler:)"))); ++ (instancetype)makeActionWithName:(NSString *)name + __attribute__((swift_name("init(name:)"))); +``` + +```swift +/* non-inherited */ init(handler: () -> Void) +init(name: String) +``` + +A no-argument method imported as an initializer can be given a dummy argument label to disambiguate it from the no-argument `init()`, whether the method is an init-family instance method or a factory class method in Objective-C. + +```objc +- (instancetype)initSafely + __attribute__((swift_name("init(safe:)"))); ++ (instancetype)makeDefaultAction + __attribute__((swift_name("init(default:)"))); +``` + +```swift +init(safe: ()) +init(default: ()) +``` + +A custom name on an instance method with one of Objective-C's subscript selectors (`objectAtIndexedSubscript:`, `objectForKeyedSubscript:`, `setObject:atIndexedSubscript:`, or `setObject:forKeyedSubscript:`) prevents that method from being imported as a subscript or used as the accessor for another subscript. + +_Currently, this only works if *both* methods in a read/write subscript are given custom names; if just one is, a read/write subscript will still be formed. A read-only subscript only has one method to rename._ + + ## More to come... diff --git a/docs/Diagnostics.md b/docs/Diagnostics.md index 08010b83570..827d2a2e49c 100644 --- a/docs/Diagnostics.md +++ b/docs/Diagnostics.md @@ -104,3 +104,19 @@ Most diagnostics have no reason to change behavior under editor mode. An example - `%error` - Represents a branch in a `%select` that should never be taken. In debug builds of the compiler this produces an assertion failure. - `%%` - Emits a literal percent sign. + +### Diagnostic Verifier ### + +(This section is specific to the Swift compiler's diagnostic engine.) + +If the `-verify` frontend flag is used, the Swift compiler will check emitted diagnostics against specially formatted comments in the source. This feature is used extensively throughout the test suite to ensure diagnostics are emitted with the correct message and source location. + +An expected diagnostic is denoted by a comment which begins with `expected-error`, `expected-warning`, `expected-note`, or `expected-remark`. It is followed by: + +- (Optional) Location information. By default, the comment will match any diagnostic emitted on the same line. However, it's possible to override this behavior and/or specify column information as well. `// expected-error@-1 ...` looks for an error on the previous line, `// expected-warning@+1:3 ...` looks for a warning on the next line at the third column, and `// expected-note@:7 ...` looks for a note on the same line at the seventh column. + +- (Optional) A match count which specifies how many times the diagnostic is expected to appear. This may be a positive integer or `*`, which allows for zero or more matches. The match count must be surrounded by whitespace if present. For example, `// expected-error 2 ...` looks for two matching errors, and `// expected-warning * ...` looks for any number of matching warnings. + +- (Required) The expected error message. The message should be enclosed in double curly braces and should not include the `error:`/`warning:`/`note:`/`remark:` prefix. For example, `// expected-error {{invalid redeclaration of 'y'}}` would match an error with that message on the same line. The expected message does not need to match the emitted message verbatim. As long as the expected message is a substring of the original message, they will match. + +- (Optional) Expected fix-its. These are each enclosed in double curly braces and appear after the expected message. An expected fix-it consists of a column range followed by the text it's expected to be replaced with. For example, `let r : Int i = j // expected-error{{consecutive statements}} {{12-12=;}}` will match a fix-it attached to the consecutive statements error which inserts a semicolon at column 12, just after the 't' in 'Int'. The special {{none}} specifier is also supported, which will cause the diagnostic match to fail if unexpected fix-its are produced. diff --git a/docs/Testing.md b/docs/Testing.md index c2a7fead5a9..8098f8f2095 100644 --- a/docs/Testing.md +++ b/docs/Testing.md @@ -232,7 +232,7 @@ code for the target that is not the build machine: * ``%target-typecheck-verify-swift``: parse and type check the current Swift file for the target platform and verify diagnostics, like ``swift -frontend -typecheck -verify - %s``. + %s``. For further explanation of `-verify` mode, see [Diagnostics.md](Diagnostics.md). Use this substitution for testing semantic analysis in the compiler. diff --git a/docs/WindowsBuild.md b/docs/WindowsBuild.md index 01a43744394..74571357f1a 100644 --- a/docs/WindowsBuild.md +++ b/docs/WindowsBuild.md @@ -186,13 +186,11 @@ cmake -G "Visual Studio 2017" -A x64 -T "host=x64"^ ... md "S:\b\lldb" cd "S:\b\lldb" cmake -G Ninja^ + -DLLVM_DIR="S:/b/llvm/lib/cmake/llvm"^ + -DClang_DIR="S:/b/llvm/lib/cmake/clang"^ + -DSwift_DIR="S:/b/swift/lib/cmake/swift"^ -DCMAKE_BUILD_TYPE=RelWithDebInfo^ -DLLDB_ALLOW_STATIC_BINDINGS=YES^ - -DLLDB_PATH_TO_CLANG_SOURCE="S:\clang"^ - -DLLDB_PATH_TO_SWIFT_SOURCE="S:\swift"^ - -DLLDB_PATH_TO_CLANG_BUILD="S:\b\llvm"^ - -DLLDB_PATH_TO_LLVM_BUILD="S:\b\llvm"^ - -DLLDB_PATH_TO_SWIFT_BUILD="S:\b\swift"^ -DLLVM_ENABLE_ASSERTIONS=ON^ -DPYTHON_HOME="%ProgramFiles(x86)%\Microsoft Visual Studio\Shared\Python37_64"^ S:\lldb diff --git a/include/swift/ABI/Metadata.h b/include/swift/ABI/Metadata.h index 13766055ad2..2c2c7a65a0a 100644 --- a/include/swift/ABI/Metadata.h +++ b/include/swift/ABI/Metadata.h @@ -998,8 +998,6 @@ struct TargetClassMetadata : public TargetAnyClassMetadata { using StoredPointer = typename Runtime::StoredPointer; using StoredSize = typename Runtime::StoredSize; - friend class ReflectionContext; - TargetClassMetadata() = default; constexpr TargetClassMetadata(const TargetAnyClassMetadata &base, ClassFlags flags, diff --git a/include/swift/AST/ASTNode.h b/include/swift/AST/ASTNode.h index a549ce939b2..db6884b8472 100644 --- a/include/swift/AST/ASTNode.h +++ b/include/swift/AST/ASTNode.h @@ -36,10 +36,10 @@ namespace swift { enum class DeclKind : uint8_t; enum class StmtKind; - struct ASTNode : public llvm::PointerUnion3 { + struct ASTNode : public llvm::PointerUnion { // Inherit the constructors from PointerUnion. - using PointerUnion3::PointerUnion3; - + using PointerUnion::PointerUnion; + SourceRange getSourceRange() const; /// Return the location of the start of the statement. diff --git a/include/swift/AST/ASTTypeIDZone.def b/include/swift/AST/ASTTypeIDZone.def index 124c990c357..2ca97768b86 100644 --- a/include/swift/AST/ASTTypeIDZone.def +++ b/include/swift/AST/ASTTypeIDZone.def @@ -26,6 +26,7 @@ SWIFT_TYPEID(Type) SWIFT_TYPEID(TypePair) SWIFT_TYPEID_NAMED(CustomAttr *, CustomAttr) SWIFT_TYPEID_NAMED(Decl *, Decl) +SWIFT_TYPEID_NAMED(EnumDecl *, EnumDecl) SWIFT_TYPEID_NAMED(GenericParamList *, GenericParamList) SWIFT_TYPEID_NAMED(GenericTypeParamType *, GenericTypeParamType) SWIFT_TYPEID_NAMED(InfixOperatorDecl *, InfixOperatorDecl) diff --git a/include/swift/AST/ASTTypeIDs.h b/include/swift/AST/ASTTypeIDs.h index c64b1290d3d..c05fde9e2d9 100644 --- a/include/swift/AST/ASTTypeIDs.h +++ b/include/swift/AST/ASTTypeIDs.h @@ -25,6 +25,7 @@ class AbstractFunctionDecl; class BraceStmt; class CustomAttr; class Decl; +class EnumDecl; class GenericParamList; class GenericSignature; class GenericTypeParamType; diff --git a/include/swift/AST/AnyRequest.h b/include/swift/AST/AnyRequest.h index 623fa81d1c8..0b6b9b5f4cf 100644 --- a/include/swift/AST/AnyRequest.h +++ b/include/swift/AST/AnyRequest.h @@ -54,7 +54,7 @@ class AnyRequest { friend llvm::DenseMapInfo; static hash_code hashForHolder(uint64_t typeID, hash_code requestHash) { - return hash_combine(hash_value(typeID), requestHash); + return hash_combine(typeID, requestHash); } /// Abstract base class used to hold the specific request kind. diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 10aca42d60c..571dffe1cc6 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -340,12 +340,7 @@ protected: IsUserAccessible : 1 ); - SWIFT_INLINE_BITFIELD(AbstractStorageDecl, ValueDecl, 1+1+1, - /// Whether a keypath component can directly reference this storage, - /// or if it must use the overridden declaration instead. - HasComputedValidKeyPathComponent : 1, - ValidKeyPathComponent : 1, - + SWIFT_INLINE_BITFIELD(AbstractStorageDecl, ValueDecl, 1, /// Whether this property is a type property (currently unfortunately /// called 'static'). IsStatic : 1 @@ -3519,12 +3514,37 @@ public: class EnumDecl final : public NominalTypeDecl { SourceLoc EnumLoc; + enum SemanticInfoFlags : uint8_t { + // Is the raw type valid? + HasComputedRawType = 1 << 0, + // Is the complete set of (auto-incremented) raw values available? + HasFixedRawValues = 1 << 1, + // Is the complete set of raw values type checked? + HasFixedRawValuesAndTypes = 1 << 2, + }; + struct { /// The raw type and a bit to indicate whether the /// raw was computed yet or not. - llvm::PointerIntPair RawType; + llvm::PointerIntPair> RawTypeAndFlags; + + bool hasRawType() const { + return RawTypeAndFlags.getInt().contains(HasComputedRawType); + } + void cacheRawType(Type ty) { + auto flags = RawTypeAndFlags.getInt() | HasComputedRawType; + RawTypeAndFlags.setPointerAndInt(ty, flags); + } + + bool hasFixedRawValues() const { + return RawTypeAndFlags.getInt().contains(HasFixedRawValues); + } + bool hasCheckedRawValues() const { + return RawTypeAndFlags.getInt().contains(HasFixedRawValuesAndTypes); + } } LazySemanticInfo; + friend class EnumRawValuesRequest; friend class EnumRawTypeRequest; friend class TypeChecker; @@ -3583,6 +3603,9 @@ public: Bits.EnumDecl.Circularity = static_cast(circularity); } + /// Record that this enum has had all of its raw values computed. + void setHasFixedRawValues(); + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return D->getKind() == DeclKind::Enum; @@ -3612,9 +3635,11 @@ public: /// Set the raw type of the enum from its inheritance clause. void setRawType(Type rawType) { - LazySemanticInfo.RawType.setPointerAndInt(rawType, true); + auto flags = LazySemanticInfo.RawTypeAndFlags.getInt(); + LazySemanticInfo.RawTypeAndFlags.setPointerAndInt( + rawType, flags | HasComputedRawType); } - + /// True if none of the enum cases have associated values. /// /// Note that this is true for enums with absolutely no cases. @@ -4505,8 +4530,6 @@ protected: Bits.AbstractStorageDecl.IsStatic = IsStatic; } - void computeIsValidKeyPathComponent(); - OpaqueTypeDecl *OpaqueReturn = nullptr; public: @@ -4749,18 +4772,9 @@ public: /// property from the given module? bool isResilient(ModuleDecl *M, ResilienceExpansion expansion) const; - void setIsValidKeyPathComponent(bool value) { - Bits.AbstractStorageDecl.HasComputedValidKeyPathComponent = true; - Bits.AbstractStorageDecl.ValidKeyPathComponent = value; - } - /// True if the storage can be referenced by a keypath directly. /// Otherwise, its override must be referenced. - bool isValidKeyPathComponent() const { - if (!Bits.AbstractStorageDecl.HasComputedValidKeyPathComponent) - const_cast(this)->computeIsValidKeyPathComponent(); - return Bits.AbstractStorageDecl.ValidKeyPathComponent; - } + bool isValidKeyPathComponent() const; /// True if the storage exports a property descriptor for key paths in /// other modules. @@ -4810,7 +4824,7 @@ public: }; protected: - PointerUnion3 Parent; + PointerUnion Parent; VarDecl(DeclKind kind, bool isStatic, Introducer introducer, bool issCaptureList, SourceLoc nameLoc, Identifier name, @@ -6354,6 +6368,8 @@ public: /// parent EnumDecl, although syntactically they are subordinate to the /// EnumCaseDecl. class EnumElementDecl : public DeclContext, public ValueDecl { + friend class EnumRawValuesRequest; + /// This is the type specified with the enum element, for /// example 'Int' in 'case Y(Int)'. This is null if there is no type /// associated with this element, as in 'case Z' or in all elements of enum @@ -6394,9 +6410,20 @@ public: ParameterList *getParameterList() const { return Params; } - bool hasRawValueExpr() const { return RawValueExpr; } - LiteralExpr *getRawValueExpr() const { return RawValueExpr; } - void setRawValueExpr(LiteralExpr *e) { RawValueExpr = e; } + /// Retrieves a fully typechecked raw value expression associated + /// with this enum element, if it exists. + LiteralExpr *getRawValueExpr() const; + + /// Retrieves a "structurally" checked raw value expression associated + /// with this enum element, if it exists. + /// + /// The structural raw value may or may not have a type set, but it is + /// guaranteed to be suitable for retrieving any non-semantic information + /// like digit text for an integral raw value or user text for a string raw value. + LiteralExpr *getStructuralRawValueExpr() const; + + /// Reset the raw value expression. + void setRawValueExpr(LiteralExpr *e); /// Return the containing EnumDecl. EnumDecl *getParentEnum() const { @@ -6419,6 +6446,10 @@ public: bool isIndirect() const { return getAttrs().hasAttribute(); } + + /// Do not call this! + /// It exists to let the AST walkers get the raw value without forcing a request. + LiteralExpr *getRawValueUnchecked() const { return RawValueExpr; } static bool classof(const Decl *D) { return D->getKind() == DeclKind::EnumElement; diff --git a/include/swift/AST/DiagnosticConsumer.h b/include/swift/AST/DiagnosticConsumer.h index ee137ee7d04..809463a898b 100644 --- a/include/swift/AST/DiagnosticConsumer.h +++ b/include/swift/AST/DiagnosticConsumer.h @@ -38,10 +38,17 @@ enum class DiagnosticKind : uint8_t { Note }; -/// Extra information carried along with a diagnostic, which may or -/// may not be of interest to a given diagnostic consumer. +/// Information about a diagnostic passed to DiagnosticConsumers. struct DiagnosticInfo { DiagID ID = DiagID(0); + SourceLoc Loc; + DiagnosticKind Kind; + StringRef FormatString; + ArrayRef FormatArgs; + SourceLoc BufferIndirectlyCausingDiagnostic; + + /// DiagnosticInfo of notes which are children of this diagnostic, if any + ArrayRef ChildDiagnosticInfo; /// Represents a fix-it, a replacement of one range of text with another. class FixIt { @@ -60,6 +67,24 @@ struct DiagnosticInfo { /// Extra source ranges that are attached to the diagnostic. ArrayRef FixIts; + + /// This is a note which has a parent error or warning + bool IsChildNote = false; + + DiagnosticInfo() {} + + DiagnosticInfo(DiagID ID, SourceLoc Loc, DiagnosticKind Kind, + StringRef FormatString, + ArrayRef FormatArgs, + SourceLoc BufferIndirectlyCausingDiagnostic, + ArrayRef ChildDiagnosticInfo, + ArrayRef Ranges, ArrayRef FixIts, + bool IsChildNote) + : ID(ID), Loc(Loc), Kind(Kind), FormatString(FormatString), + FormatArgs(FormatArgs), + BufferIndirectlyCausingDiagnostic(BufferIndirectlyCausingDiagnostic), + ChildDiagnosticInfo(ChildDiagnosticInfo), Ranges(Ranges), + FixIts(FixIts), IsChildNote(IsChildNote) {} }; /// Abstract interface for classes that present diagnostics to the user. diff --git a/include/swift/AST/DiagnosticEngine.h b/include/swift/AST/DiagnosticEngine.h index a4ec15134e7..c632d7f251f 100644 --- a/include/swift/AST/DiagnosticEngine.h +++ b/include/swift/AST/DiagnosticEngine.h @@ -337,7 +337,9 @@ namespace swift { SmallVector Args; SmallVector Ranges; SmallVector FixIts; + std::vector ChildNotes; SourceLoc Loc; + bool IsChildNote = false; const Decl *Decl = nullptr; friend DiagnosticEngine; @@ -362,10 +364,13 @@ namespace swift { ArrayRef getArgs() const { return Args; } ArrayRef getRanges() const { return Ranges; } ArrayRef getFixIts() const { return FixIts; } + ArrayRef getChildNotes() const { return ChildNotes; } + bool isChildNote() const { return IsChildNote; } SourceLoc getLoc() const { return Loc; } const class Decl *getDecl() const { return Decl; } void setLoc(SourceLoc loc) { Loc = loc; } + void setIsChildNote(bool isChildNote) { IsChildNote = isChildNote; } void setDecl(const class Decl *decl) { Decl = decl; } /// Returns true if this object represents a particular diagnostic. @@ -386,6 +391,8 @@ namespace swift { void addFixIt(FixIt &&F) { FixIts.push_back(std::move(F)); } + + void addChildNote(Diagnostic &&D); }; /// Describes an in-flight diagnostic, which is currently active @@ -665,7 +672,8 @@ namespace swift { friend class InFlightDiagnostic; friend class DiagnosticTransaction; - + friend class CompoundDiagnosticTransaction; + public: explicit DiagnosticEngine(SourceManager &SourceMgr) : SourceMgr(SourceMgr), ActiveDiagnostic(), @@ -878,6 +886,15 @@ namespace swift { return diagnose(decl, Diagnostic(id, std::move(args)...)); } + /// Emit a parent diagnostic and attached notes. + /// + /// \param parentDiag An InFlightDiagnostic representing the parent diag. + /// + /// \param builder A closure which builds and emits notes to be attached to + /// the parent diag. + void diagnoseWithNotes(InFlightDiagnostic parentDiag, + llvm::function_ref builder); + /// \returns true if diagnostic is marked with PointsToFirstBadToken /// option. bool isDiagnosticPointsToFirstBadToken(DiagID id) const; @@ -905,6 +922,10 @@ namespace swift { /// Retrieve the active diagnostic. Diagnostic &getActiveDiagnostic() { return *ActiveDiagnostic; } + /// Generate DiagnosticInfo for a Diagnostic to be passed to consumers. + Optional + diagnosticInfoForDiagnostic(const Diagnostic &diagnostic); + /// Send \c diag to all diagnostic consumers. void emitDiagnostic(const Diagnostic &diag); @@ -945,6 +966,7 @@ namespace swift { /// in LIFO order. An open transaction is implicitly committed upon /// destruction. class DiagnosticTransaction { + protected: DiagnosticEngine &Engine; /// How many tentative diagnostics there were when the transaction @@ -968,7 +990,6 @@ namespace swift { Depth(Engine.TransactionCount), IsOpen(true) { - assert(!Engine.ActiveDiagnostic); Engine.TransactionCount++; } @@ -1011,6 +1032,61 @@ namespace swift { "transactions must be closed LIFO"); } }; + + /// Represents a diagnostic transaction which constructs a compound diagnostic + /// from any diagnostics emitted inside. A compound diagnostic consists of a + /// parent error, warning, or remark followed by a variable number of child + /// notes. The semantics are otherwise the same as a regular + /// DiagnosticTransaction. + class CompoundDiagnosticTransaction : public DiagnosticTransaction { + public: + explicit CompoundDiagnosticTransaction(DiagnosticEngine &engine) + : DiagnosticTransaction(engine) {} + + ~CompoundDiagnosticTransaction() { + if (IsOpen) { + commit(); + } + + if (Depth == 0) { + Engine.TransactionStrings.clear(); + Engine.TransactionAllocator.Reset(); + } + } + + void commit() { + assert(PrevDiagnostics < Engine.TentativeDiagnostics.size() && + "CompoundDiagnosticTransaction must contain at least one diag"); + + // The first diagnostic is assumed to be the parent. If this is not an + // error or warning, we'll assert later when trying to add children. + Diagnostic &parent = Engine.TentativeDiagnostics[PrevDiagnostics]; + + // Associate the children with the parent. + for (auto diag = + Engine.TentativeDiagnostics.begin() + PrevDiagnostics + 1; + diag != Engine.TentativeDiagnostics.end(); ++diag) { + diag->setIsChildNote(true); + parent.addChildNote(std::move(*diag)); + } + + // Erase the children, they'll be emitted alongside their parent. + Engine.TentativeDiagnostics.erase(Engine.TentativeDiagnostics.begin() + + PrevDiagnostics + 1, + Engine.TentativeDiagnostics.end()); + + DiagnosticTransaction::commit(); + } + }; + + inline void + DiagnosticEngine::diagnoseWithNotes(InFlightDiagnostic parentDiag, + llvm::function_ref builder) { + CompoundDiagnosticTransaction transaction(*this); + parentDiag.flush(); + builder(); + } + } // end namespace swift #endif diff --git a/include/swift/AST/DiagnosticsClangImporter.def b/include/swift/AST/DiagnosticsClangImporter.def index bad492d8f0a..285694e764b 100644 --- a/include/swift/AST/DiagnosticsClangImporter.def +++ b/include/swift/AST/DiagnosticsClangImporter.def @@ -91,10 +91,6 @@ WARNING(implicit_bridging_header_imported_from_module,none, "is deprecated and will be removed in a later version of Swift", (StringRef, Identifier)) -WARNING(clang_vfs_overlay_is_ignored,none, - "ignoring '-ivfsoverlay' options provided to '-Xcc' in favor of " - "'-vfsoverlay'", ()) - #ifndef DIAG_NO_UNDEF # if defined(DIAG) # undef DIAG diff --git a/include/swift/AST/GenericSignatureBuilder.h b/include/swift/AST/GenericSignatureBuilder.h index 4bc41f1e37f..ba6a43eeb3b 100644 --- a/include/swift/AST/GenericSignatureBuilder.h +++ b/include/swift/AST/GenericSignatureBuilder.h @@ -92,10 +92,10 @@ public: class ResolvedType; using UnresolvedRequirementRHS = - llvm::PointerUnion3; + llvm::PointerUnion; using RequirementRHS = - llvm::PointerUnion3; + llvm::PointerUnion; /// The location of a requirement as written somewhere in the source. typedef llvm::PointerUnion @@ -1373,8 +1373,8 @@ class GenericSignatureBuilder::FloatingRequirementSource { } kind; using Storage = - llvm::PointerUnion3; + llvm::PointerUnion; Storage storage; diff --git a/include/swift/AST/Identifier.h b/include/swift/AST/Identifier.h index 4517315cf46..035fc07c424 100644 --- a/include/swift/AST/Identifier.h +++ b/include/swift/AST/Identifier.h @@ -56,8 +56,26 @@ class Identifier { const char *Pointer; +public: + enum : size_t { + NumLowBitsAvailable = 2, + RequiredAlignment = 1 << NumLowBitsAvailable, + SpareBitMask = ((intptr_t)1 << NumLowBitsAvailable) - 1 + }; + +private: /// Constructor, only accessible by ASTContext, which handles the uniquing. - explicit Identifier(const char *Ptr) : Pointer(Ptr) {} + explicit Identifier(const char *Ptr) : Pointer(Ptr) { + assert(((uintptr_t)Ptr & SpareBitMask) == 0 + && "Identifier pointer does not use any spare bits"); + } + + /// A type with the alignment expected of a valid \c Identifier::Pointer . + struct alignas(uint32_t) Aligner {}; + + static_assert(alignof(Aligner) >= RequiredAlignment, + "Identifier table will provide enough spare bits"); + public: explicit Identifier() : Pointer(nullptr) {} @@ -153,12 +171,15 @@ public: bool operator<(Identifier RHS) const { return Pointer < RHS.Pointer; } static Identifier getEmptyKey() { - return Identifier((const char*) - llvm::DenseMapInfo::getEmptyKey()); + uintptr_t Val = static_cast(-1); + Val <<= NumLowBitsAvailable; + return Identifier((const char*)Val); } + static Identifier getTombstoneKey() { - return Identifier((const char*) - llvm::DenseMapInfo::getTombstoneKey()); + uintptr_t Val = static_cast(-2); + Val <<= NumLowBitsAvailable; + return Identifier((const char*)Val); } private: @@ -202,7 +223,7 @@ namespace llvm { static inline swift::Identifier getFromVoidPointer(void *P) { return swift::Identifier::getFromOpaquePointer(P); } - enum { NumLowBitsAvailable = 2 }; + enum { NumLowBitsAvailable = swift::Identifier::NumLowBitsAvailable }; }; } // end namespace llvm @@ -221,15 +242,15 @@ public: }; private: - /// In a special DeclName represenenting a subscript, this opaque pointer + /// In a special DeclName representing a subscript, this opaque pointer /// is used as the data of the base name identifier. /// This is an implementation detail that should never leak outside of /// DeclName. - static void *SubscriptIdentifierData; + static const Identifier::Aligner SubscriptIdentifierData; /// As above, for special constructor DeclNames. - static void *ConstructorIdentifierData; + static const Identifier::Aligner ConstructorIdentifierData; /// As above, for special destructor DeclNames. - static void *DestructorIdentifierData; + static const Identifier::Aligner DestructorIdentifierData; Identifier Ident; @@ -239,23 +260,23 @@ public: DeclBaseName(Identifier I) : Ident(I) {} static DeclBaseName createSubscript() { - return DeclBaseName(Identifier((const char *)SubscriptIdentifierData)); + return DeclBaseName(Identifier((const char *)&SubscriptIdentifierData)); } static DeclBaseName createConstructor() { - return DeclBaseName(Identifier((const char *)ConstructorIdentifierData)); + return DeclBaseName(Identifier((const char *)&ConstructorIdentifierData)); } static DeclBaseName createDestructor() { - return DeclBaseName(Identifier((const char *)DestructorIdentifierData)); + return DeclBaseName(Identifier((const char *)&DestructorIdentifierData)); } Kind getKind() const { - if (Ident.get() == SubscriptIdentifierData) { + if (Ident.get() == (const char *)&SubscriptIdentifierData) { return Kind::Subscript; - } else if (Ident.get() == ConstructorIdentifierData) { + } else if (Ident.get() == (const char *)&ConstructorIdentifierData) { return Kind::Constructor; - } else if (Ident.get() == DestructorIdentifierData) { + } else if (Ident.get() == (const char *)&DestructorIdentifierData) { return Kind::Destructor; } else { return Kind::Normal; @@ -720,7 +741,7 @@ namespace llvm { static inline swift::DeclName getFromVoidPointer(void *ptr) { return swift::DeclName::getFromOpaqueValue(ptr); } - enum { NumLowBitsAvailable = 0 }; + enum { NumLowBitsAvailable = PointerLikeTypeTraits::NumLowBitsAvailable - 2 }; }; // DeclNames hash just like pointers. diff --git a/include/swift/AST/ModuleLoader.h b/include/swift/AST/ModuleLoader.h index 8aca44f43b3..af1d372659b 100644 --- a/include/swift/AST/ModuleLoader.h +++ b/include/swift/AST/ModuleLoader.h @@ -24,6 +24,10 @@ #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/TinyPtrVector.h" +namespace llvm { +class FileCollector; +} + namespace clang { class DependencyCollector; } @@ -54,8 +58,9 @@ enum class Bridgeability : unsigned { class DependencyTracker { std::shared_ptr clangCollector; public: - - explicit DependencyTracker(bool TrackSystemDeps); + explicit DependencyTracker( + bool TrackSystemDeps, + std::shared_ptr FileCollector = {}); /// Adds a file as a dependency. /// diff --git a/include/swift/AST/SearchPathOptions.h b/include/swift/AST/SearchPathOptions.h index c6eddea58bc..86d95675531 100644 --- a/include/swift/AST/SearchPathOptions.h +++ b/include/swift/AST/SearchPathOptions.h @@ -13,6 +13,7 @@ #ifndef SWIFT_AST_SEARCHPATHOPTIONS_H #define SWIFT_AST_SEARCHPATHOPTIONS_H +#include "swift/Basic/ArrayRefView.h" #include "llvm/ADT/Hashing.h" #include @@ -81,30 +82,38 @@ public: /// would for a non-system header. bool DisableModulesValidateSystemDependencies = false; +private: + static StringRef + pathStringFromFrameworkSearchPath(const FrameworkSearchPath &next) { + return next.Path; + }; + +public: /// Return a hash code of any components from these options that should /// contribute to a Swift Bridging PCH hash. llvm::hash_code getPCHHashComponents() const { - using llvm::hash_value; using llvm::hash_combine; - auto Code = hash_value(SDKPath); - for (auto Import : ImportSearchPaths) { - Code = hash_combine(Code, Import); - } - for (auto VFSFile : VFSOverlayFiles) { - Code = hash_combine(Code, VFSFile); - } - for (const auto &FrameworkPath : FrameworkSearchPaths) { - Code = hash_combine(Code, FrameworkPath.Path); - } - for (auto LibraryPath : LibrarySearchPaths) { - Code = hash_combine(Code, LibraryPath); - } - Code = hash_combine(Code, RuntimeResourcePath); - for (auto RuntimeLibraryImportPath : RuntimeLibraryImportPaths) { - Code = hash_combine(Code, RuntimeLibraryImportPath); - } - Code = hash_combine(Code, DisableModulesValidateSystemDependencies); - return Code; + using llvm::hash_combine_range; + + using FrameworkPathView = ArrayRefView; + FrameworkPathView frameworkPathsOnly{FrameworkSearchPaths}; + + return hash_combine(SDKPath, + hash_combine_range(ImportSearchPaths.begin(), + ImportSearchPaths.end()), + hash_combine_range(VFSOverlayFiles.begin(), + VFSOverlayFiles.end()), + // FIXME: Should we include the system-ness of framework + // search paths too? + hash_combine_range(frameworkPathsOnly.begin(), + frameworkPathsOnly.end()), + hash_combine_range(LibrarySearchPaths.begin(), + LibrarySearchPaths.end()), + RuntimeResourcePath, + hash_combine_range(RuntimeLibraryImportPaths.begin(), + RuntimeLibraryImportPaths.end()), + DisableModulesValidateSystemDependencies); } }; diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index 2df81da4998..510a7c21032 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -367,7 +367,7 @@ struct WhereClauseOwner { /// The source of the where clause, which can be a generic parameter list /// or a declaration that can have a where clause. - llvm::PointerUnion3 source; + llvm::PointerUnion source; WhereClauseOwner(Decl *decl); @@ -380,8 +380,7 @@ struct WhereClauseOwner { SourceLoc getLoc() const; friend hash_code hash_value(const WhereClauseOwner &owner) { - return hash_combine(hash_value(owner.dc), - hash_value(owner.source.getOpaqueValue())); + return llvm::hash_combine(owner.dc, owner.source.getOpaqueValue()); } friend bool operator==(const WhereClauseOwner &lhs, @@ -1209,6 +1208,7 @@ public: bool isCached() const { return true; } Optional getCachedResult() const; void cacheResult(Type value) const; + void diagnoseCycle(DiagnosticEngine &diags) const; }; class OperatorPrecedenceGroupRequest @@ -1230,6 +1230,48 @@ public: bool isCached() const { return true; } }; +class EnumRawValuesRequest : + public SimpleRequest { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + // Evaluation. + llvm::Expected + evaluate(Evaluator &evaluator, EnumDecl *ED, TypeResolutionStage stage) const; + +public: + // Cycle handling. + void diagnoseCycle(DiagnosticEngine &diags) const; + void noteCycleStep(DiagnosticEngine &diags) const; + + // Separate caching. + bool isCached() const; + Optional getCachedResult() const; + void cacheResult(bool value) const; +}; + +class IsABICompatibleOverrideRequest + : public SimpleRequest { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + // Evaluation. + llvm::Expected evaluate(Evaluator &evaluator, ValueDecl *decl) const; + +public: + // Caching. + bool isCached() const { return true; } +}; + // Allow AnyValue to compare two Type values, even though Type doesn't // support ==. template<> diff --git a/include/swift/AST/TypeCheckerTypeIDZone.def b/include/swift/AST/TypeCheckerTypeIDZone.def index 3dceae84ada..c5e56a34a6a 100644 --- a/include/swift/AST/TypeCheckerTypeIDZone.def +++ b/include/swift/AST/TypeCheckerTypeIDZone.def @@ -36,6 +36,9 @@ SWIFT_REQUEST(TypeChecker, DefaultTypeRequest, NoLocationInfo) SWIFT_REQUEST(TypeChecker, EmittedMembersRequest, DeclRange(ClassDecl *), SeparatelyCached, NoLocationInfo) +SWIFT_REQUEST(TypeChecker, EnumRawValuesRequest, + bool (EnumDecl *, TypeResolutionStage), SeparatelyCached, + NoLocationInfo) SWIFT_REQUEST(TypeChecker, EnumRawTypeRequest, Type(EnumDecl *, TypeResolutionStage), SeparatelyCached, NoLocationInfo) @@ -139,3 +142,5 @@ SWIFT_REQUEST(TypeChecker, UnderlyingTypeRequest, Type(TypeAliasDecl *), SeparatelyCached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, USRGenerationRequest, std::string(const ValueDecl *), Cached, NoLocationInfo) +SWIFT_REQUEST(TypeChecker, IsABICompatibleOverrideRequest, + bool(ValueDecl *), Cached, NoLocationInfo) diff --git a/include/swift/AST/TypeLoc.h b/include/swift/AST/TypeLoc.h index 51356fa7d2f..bf4904514a7 100644 --- a/include/swift/AST/TypeLoc.h +++ b/include/swift/AST/TypeLoc.h @@ -68,8 +68,7 @@ public: TypeLoc clone(ASTContext &ctx) const; friend llvm::hash_code hash_value(const TypeLoc &owner) { - return hash_combine(llvm::hash_value(owner.Ty.getPointer()), - llvm::hash_value(owner.TyR)); + return llvm::hash_combine(owner.Ty.getPointer(), owner.TyR); } friend bool operator==(const TypeLoc &lhs, diff --git a/include/swift/Basic/LLVM.h b/include/swift/Basic/LLVM.h index ad6327b7432..3ce78f9e583 100644 --- a/include/swift/Basic/LLVM.h +++ b/include/swift/Basic/LLVM.h @@ -42,8 +42,7 @@ namespace llvm { template class MutableArrayRef; template class TinyPtrVector; template class Optional; - template class PointerUnion; - template class PointerUnion3; + template class PointerUnion; class SmallBitVector; // Other common classes. @@ -68,7 +67,6 @@ namespace swift { using llvm::None; using llvm::Optional; using llvm::PointerUnion; - using llvm::PointerUnion3; using llvm::SmallBitVector; using llvm::SmallPtrSet; using llvm::SmallPtrSetImpl; diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index 74e80db3f05..96e35f5dff9 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -441,12 +441,10 @@ namespace swift { /// Return a hash code of any components from these options that should /// contribute to a Swift Bridging PCH hash. llvm::hash_code getPCHHashComponents() const { - auto code = llvm::hash_value(Target.str()); SmallString<16> Scratch; llvm::raw_svector_ostream OS(Scratch); OS << EffectiveLanguageVersion; - code = llvm::hash_combine(code, OS.str()); - return code; + return llvm::hash_combine(Target.str(), OS.str()); } private: diff --git a/include/swift/Basic/STLExtras.h b/include/swift/Basic/STLExtras.h index 1fad1fa1696..231737fecaf 100644 --- a/include/swift/Basic/STLExtras.h +++ b/include/swift/Basic/STLExtras.h @@ -253,7 +253,7 @@ inline Iterator prev_or_begin(Iterator it, Iterator begin) { /// A range of iterators. /// TODO: Add `llvm::iterator_range::empty()`, then remove this helper, along -/// with the superfluous FilterIterator and TransformIterator. +/// with the superfluous TransformIterator. template class IteratorRange { Iterator First, Last; @@ -279,136 +279,6 @@ makeIteratorRange(Iterator first, Iterator last) { return IteratorRange(first, last); } -/// An iterator that filters the results of an underlying forward -/// iterator, only passing through those values that satisfy a predicate. -/// -/// \tparam Iterator the underlying iterator. -/// -/// \tparam Predicate A predicate that determines whether a value of the -/// underlying iterator is available in the resulting sequence. -template -class FilterIterator { - Iterator Current, End; - - /// FIXME: Could optimize away this storage with EBCO tricks. - Predicate Pred; - - /// Skip any non-matching elements. - void skipNonMatching() { - while (Current != End && !Pred(*Current)) - ++Current; - } - -public: - /// Used to indicate when the current iterator has already been - /// "primed", meaning that it's at the end or points to a value that - /// satisfies the predicate. - enum PrimedT { Primed }; - - using iterator_category = std::forward_iterator_tag; - using value_type = typename std::iterator_traits::value_type; - using reference = typename std::iterator_traits::reference; - using pointer = typename std::iterator_traits::pointer; - using difference_type = - typename std::iterator_traits::difference_type; - - /// Construct a new filtering iterator for the given iterator range - /// and predicate. - FilterIterator(Iterator current, Iterator end, Predicate pred) - : Current(current), End(end), Pred(pred) - { - // Prime the iterator. - skipNonMatching(); - } - - /// Construct a new filtering iterator for the given iterator range - /// and predicate, where the iterator range has already been - /// "primed" by ensuring that it is empty or the current iterator - /// points to something that matches the predicate. - FilterIterator(Iterator current, Iterator end, Predicate pred, PrimedT) - : Current(current), End(end), Pred(pred) - { - // Assert that the iterators have already been primed. - assert(Current == End || Pred(*Current) && "Not primed!"); - } - - reference operator*() const { - return *Current; - } - - pointer operator->() const { - return Current.operator->(); - } - - FilterIterator &operator++() { - ++Current; - skipNonMatching(); - return *this; - } - - FilterIterator operator++(int) { - FilterIterator old = *this; - ++*this; - return old; - } - - friend bool operator==(FilterIterator lhs, FilterIterator rhs) { - return lhs.Current == rhs.Current; - } - friend bool operator!=(FilterIterator lhs, FilterIterator rhs) { - return !(lhs == rhs); - } -}; - -/// Create a new filter iterator. -template -inline FilterIterator -makeFilterIterator(Iterator current, Iterator end, Predicate pred) { - return FilterIterator(current, end, pred); -} - -/// A range filtered by a specific predicate. -template -class FilterRange { - using Iterator = typename Range::iterator; - - Iterator First, Last; - Predicate Pred; - -public: - using iterator = FilterIterator; - - FilterRange(Range range, Predicate pred) - : First(range.begin()), Last(range.end()), Pred(pred) - { - // Prime the sequence. - while (First != Last && !Pred(*First)) - ++First; - } - - iterator begin() const { - return iterator(First, Last, Pred, iterator::Primed); - } - - iterator end() const { - return iterator(Last, Last, Pred, iterator::Primed); - } - - bool empty() const { return First == Last; } - - typename std::iterator_traits::value_type front() const { - assert(!empty() && "Front of empty range"); - return *begin(); - } -}; - -/// Create a new filter range. -template -inline FilterRange -makeFilterRange(Range range, Predicate pred) { - return FilterRange(range, pred); -} - /// An iterator that transforms the result of an underlying bidirectional /// iterator with a given operation. /// @@ -488,7 +358,7 @@ class TransformRange { Operation Op; public: - using iterator = TransformIterator; + using iterator = TransformIterator; TransformRange(Range range, Operation op) : Rng(range), Op(op) { } @@ -497,6 +367,20 @@ public: iterator end() const { return iterator(Rng.end(), Op); } bool empty() const { return begin() == end(); } + // The dummy template parameter keeps 'size()' from being eagerly + // instantiated. + template + typename function_traits::result_type + size() const { + return Rng.size(); + } + + template + typename function_traits::result_type + operator[](Index index) const { + return Op(Rng[index]); + } + typename std::iterator_traits::value_type front() const { assert(!empty() && "Front of empty range"); return *begin(); diff --git a/include/swift/Basic/SourceLoc.h b/include/swift/Basic/SourceLoc.h index 594dadae7ec..7d351d675a6 100644 --- a/include/swift/Basic/SourceLoc.h +++ b/include/swift/Basic/SourceLoc.h @@ -265,10 +265,8 @@ template <> struct DenseMapInfo { } static unsigned getHashValue(const swift::SourceRange &Val) { - return hash_combine(DenseMapInfo::getHashValue( - Val.Start.getOpaquePointerValue()), - DenseMapInfo::getHashValue( - Val.End.getOpaquePointerValue())); + return hash_combine(Val.Start.getOpaquePointerValue(), + Val.End.getOpaquePointerValue()); } static bool isEqual(const swift::SourceRange &LHS, diff --git a/include/swift/Basic/TransformArrayRef.h b/include/swift/Basic/TransformArrayRef.h deleted file mode 100644 index ce43292f494..00000000000 --- a/include/swift/Basic/TransformArrayRef.h +++ /dev/null @@ -1,136 +0,0 @@ -//===--- TransformArrayRef.h ------------------------------------*- C++ -*-===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// -/// This file defines TransformArrayRef, a template class that provides a -/// transformed view of an ArrayRef. The difference from ArrayRefView is that -/// ArrayRefView takes its transform as a template argument, while -/// TransformArrayRef only takes a type as its template argument. This means it -/// can be used to define types used with forward declaration pointers without -/// needing to define the relevant function in headers. -/// -//===----------------------------------------------------------------------===// - -#ifndef SWIFT_BASIC_TRANSFORMARRAYREF_H -#define SWIFT_BASIC_TRANSFORMARRAYREF_H - -#include "swift/Basic/STLExtras.h" -#include "llvm/ADT/ArrayRef.h" - -namespace swift { - -/// A transformation of an ArrayRef using a function of type FuncTy. This is -/// different than ArrayRefView since the underlying function is stored instead -/// of used as a template parameter. This allows it to be used in declarations -/// where the underlying function is not known. This is useful when defining the -/// underlying function would require forward declarations to need to be -/// defined. -template -class TransformArrayRef { -public: - using FunctionTraits = function_traits; - using Orig = - typename std::tuple_element<0, typename FunctionTraits::argument_types>::type; - using Projected = typename FunctionTraits::result_type; - -private: - llvm::ArrayRef Array; - FuncTy Func; - -public: - TransformArrayRef(llvm::ArrayRef array, FuncTy func) : Array(array), Func(func) {} - - class iterator { - friend class TransformArrayRef; - const Orig *Ptr; - FuncTy Func; - iterator(const Orig *ptr, FuncTy func) : Ptr(ptr), Func(func) {} - public: - using value_type = Projected; - using reference = Projected; - using pointer = void; - using difference_type = ptrdiff_t; - using iterator_category = std::random_access_iterator_tag; - - Projected operator*() const { return Func(*Ptr); } - iterator &operator++() { Ptr++; return *this; } - iterator operator++(int) { return iterator(Ptr++, Func); } - iterator &operator--() { --Ptr; return *this; } - iterator operator--(int) { return iterator(Ptr--, Func); } - - bool operator==(iterator rhs) const { return Ptr == rhs.Ptr; } - bool operator!=(iterator rhs) const { return Ptr != rhs.Ptr; } - - iterator &operator+=(difference_type i) { - Ptr += i; - return *this; - } - iterator operator+(difference_type i) const { - return iterator(Ptr + i, Func); - } - friend iterator operator+(difference_type i, iterator base) { - return iterator(base.Ptr + i, base.Func); - } - iterator &operator-=(difference_type i) { - Ptr -= i; - return *this; - } - iterator operator-(difference_type i) const { - return iterator(Ptr - i, Func); - } - difference_type operator-(iterator rhs) const { - return Ptr - rhs.Ptr; - } - Projected operator[](difference_type i) const { - return Func(Ptr[i]); - } - bool operator<(iterator rhs) const { - return Ptr < rhs.Ptr; - } - bool operator<=(iterator rhs) const { - return Ptr <= rhs.Ptr; - } - bool operator>(iterator rhs) const { - return Ptr > rhs.Ptr; - } - bool operator>=(iterator rhs) const { - return Ptr >= rhs.Ptr; - } - }; - iterator begin() const { return iterator(Array.begin(), Func); } - iterator end() const { return iterator(Array.end(), Func); } - - bool empty() const { return Array.empty(); } - size_t size() const { return Array.size(); } - Projected operator[](unsigned i) const { return Func(Array[i]); } - Projected front() const { return Func(Array.front()); } - Projected back() const { return Func(Array.back()); } - - TransformArrayRef slice(unsigned start) const { - return TransformArrayRef(Array.slice(start), Func); - } - TransformArrayRef slice(unsigned start, unsigned length) const { - return TransformArrayRef(Array.slice(start, length), Func); - } -}; - -template -TransformArrayRef> -makeTransformArrayRef(llvm::ArrayRef Array, - std::function Func) { - return TransformArrayRef(Array, Func); -} - -} // namespace swift - -#endif diff --git a/include/swift/ClangImporter/ClangImporter.h b/include/swift/ClangImporter/ClangImporter.h index bd4a68d73d9..eaa9ecd7a29 100644 --- a/include/swift/ClangImporter/ClangImporter.h +++ b/include/swift/ClangImporter/ClangImporter.h @@ -23,6 +23,7 @@ namespace llvm { class Triple; + class FileCollector; template class function_ref; } @@ -149,7 +150,8 @@ public: /// Create a new clang::DependencyCollector customized to /// ClangImporter's specific uses. static std::shared_ptr - createDependencyCollector(bool TrackSystemDeps); + createDependencyCollector(bool TrackSystemDeps, + std::shared_ptr FileCollector); /// Append visible module names to \p names. Note that names are possibly /// duplicated, and not guaranteed to be ordered in any way. diff --git a/include/swift/ClangImporter/ClangImporterOptions.h b/include/swift/ClangImporter/ClangImporterOptions.h index 5e3f0afda83..3cfa1ba678c 100644 --- a/include/swift/ClangImporter/ClangImporterOptions.h +++ b/include/swift/ClangImporter/ClangImporterOptions.h @@ -96,29 +96,24 @@ public: /// When set, don't enforce warnings with -Werror. bool DebuggerSupport = false; - /// When set, clobber the Clang instance's virtual file system with the Swift - /// virtual file system. - bool ForceUseSwiftVirtualFileSystem = false; - /// Return a hash code of any components from these options that should /// contribute to a Swift Bridging PCH hash. llvm::hash_code getPCHHashComponents() const { - using llvm::hash_value; using llvm::hash_combine; + using llvm::hash_combine_range; - auto Code = hash_value(ModuleCachePath); - // ExtraArgs ignored - already considered in Clang's module hashing. - Code = hash_combine(Code, OverrideResourceDir); - Code = hash_combine(Code, TargetCPU); - Code = hash_combine(Code, BridgingHeader); - Code = hash_combine(Code, PrecompiledHeaderOutputDir); - Code = hash_combine(Code, static_cast(Mode)); - Code = hash_combine(Code, DetailedPreprocessingRecord); - Code = hash_combine(Code, ImportForwardDeclarations); - Code = hash_combine(Code, InferImportAsMember); - Code = hash_combine(Code, DisableSwiftBridgeAttr); - Code = hash_combine(Code, DisableOverlayModules); - return Code; + return hash_combine(ModuleCachePath, + hash_combine_range(ExtraArgs.begin(), ExtraArgs.end()), + OverrideResourceDir, + TargetCPU, + BridgingHeader, + PrecompiledHeaderOutputDir, + static_cast(Mode), + DetailedPreprocessingRecord, + ImportForwardDeclarations, + InferImportAsMember, + DisableSwiftBridgeAttr, + DisableOverlayModules); } }; diff --git a/include/swift/Frontend/PrintingDiagnosticConsumer.h b/include/swift/Frontend/PrintingDiagnosticConsumer.h index 22a7696c2ac..b6768f1591f 100644 --- a/include/swift/Frontend/PrintingDiagnosticConsumer.h +++ b/include/swift/Frontend/PrintingDiagnosticConsumer.h @@ -50,6 +50,13 @@ public: bool didErrorOccur() { return DidErrorOccur; } + +private: + void printDiagnostic(SourceManager &SM, SourceLoc Loc, DiagnosticKind Kind, + StringRef FormatString, + ArrayRef FormatArgs, + const DiagnosticInfo &Info, + SourceLoc bufferIndirectlyCausingDiagnostic); }; } diff --git a/include/swift/IDE/IDERequests.h b/include/swift/IDE/IDERequests.h index 2247fe65afa..11351e59c85 100644 --- a/include/swift/IDE/IDERequests.h +++ b/include/swift/IDE/IDERequests.h @@ -38,8 +38,7 @@ struct CursorInfoOwner { CursorInfoOwner(SourceFile *File, SourceLoc Loc): File(File), Loc(Loc) { } friend llvm::hash_code hash_value(const CursorInfoOwner &CI) { - return hash_combine(hash_value(CI.File), - hash_value(CI.Loc.getOpaquePointerValue())); + return llvm::hash_combine(CI.File, CI.Loc.getOpaquePointerValue()); } friend bool operator==(const CursorInfoOwner &lhs, const CursorInfoOwner &rhs) { @@ -97,9 +96,9 @@ struct RangeInfoOwner { RangeInfoOwner(SourceFile *File, unsigned Offset, unsigned Length); friend llvm::hash_code hash_value(const RangeInfoOwner &CI) { - return hash_combine(hash_value(CI.File), - hash_value(CI.StartLoc.getOpaquePointerValue()), - hash_value(CI.EndLoc.getOpaquePointerValue())); + return llvm::hash_combine(CI.File, + CI.StartLoc.getOpaquePointerValue(), + CI.EndLoc.getOpaquePointerValue()); } friend bool operator==(const RangeInfoOwner &lhs, const RangeInfoOwner &rhs) { @@ -183,9 +182,9 @@ struct OverridenDeclsOwner { Transitive(Transitive) {} friend llvm::hash_code hash_value(const OverridenDeclsOwner &CI) { - return hash_combine(hash_value(CI.VD), - hash_value(CI.IncludeProtocolRequirements), - hash_value(CI.Transitive)); + return llvm::hash_combine(CI.VD, + CI.IncludeProtocolRequirements, + CI.Transitive); } friend bool operator==(const OverridenDeclsOwner &lhs, diff --git a/include/swift/LLVMPasses/Passes.h b/include/swift/LLVMPasses/Passes.h index 6a17d7ce46f..4594d11fec6 100644 --- a/include/swift/LLVMPasses/Passes.h +++ b/include/swift/LLVMPasses/Passes.h @@ -30,8 +30,14 @@ namespace swift { const llvm::PreservedAnalyses &) { return false; } using AAResultBase::getModRefInfo; - llvm::ModRefInfo getModRefInfo(llvm::ImmutableCallSite CS, - const llvm::MemoryLocation &Loc); + llvm::ModRefInfo getModRefInfo(const llvm::CallBase *Call, + const llvm::MemoryLocation &Loc) { + llvm::AAQueryInfo AAQI; + return getModRefInfo(Call, Loc, AAQI); + } + llvm::ModRefInfo getModRefInfo(const llvm::CallBase *Call, + const llvm::MemoryLocation &Loc, + llvm::AAQueryInfo &AAQI); }; class SwiftAAWrapperPass : public llvm::ImmutablePass { diff --git a/include/swift/Parse/ASTGen.h b/include/swift/Parse/ASTGen.h index fe555157065..bfb1270075c 100644 --- a/include/swift/Parse/ASTGen.h +++ b/include/swift/Parse/ASTGen.h @@ -16,6 +16,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" +#include "swift/AST/TypeRepr.h" #include "swift/Parse/PersistentParserState.h" #include "swift/Syntax/SyntaxNodes.h" #include "llvm/ADT/DenseMap.h" @@ -36,9 +37,8 @@ class ASTGen { // FIXME: remove when Syntax can represent all types and ASTGen can handle // them - /// Types that cannot be represented by Syntax or generated by ASTGen. - llvm::DenseMap Types; - + /// Decl attributes that cannot be represented by Syntax or generated by + /// ASTGen. llvm::DenseMap ParsedDeclAttrs; public: @@ -46,6 +46,35 @@ public: SourceLoc generate(const syntax::TokenSyntax &Tok, const SourceLoc Loc); + SourceLoc generateIdentifierDeclName(const syntax::TokenSyntax &Tok, + const SourceLoc, Identifier &Identifier); + +public: + //===--------------------------------------------------------------------===// + // Decls. + + Decl *generate(const syntax::DeclSyntax &Decl, const SourceLoc Loc); + TypeDecl *generate(const syntax::AssociatedtypeDeclSyntax &Decl, + const SourceLoc Loc); + TypeDecl *generate(const syntax::TypealiasDeclSyntax &Decl, + const SourceLoc Loc); + + TrailingWhereClause *generate(const syntax::GenericWhereClauseSyntax &syntax, + const SourceLoc Loc); + MutableArrayRef + generate(const syntax::TypeInheritanceClauseSyntax &syntax, + const SourceLoc Loc, bool allowClassRequirement); + +private: + DeclAttributes + generateDeclAttributes(const syntax::Syntax &D, SourceLoc Loc, + bool includeComments); + + void generateFreeStandingGenericWhereClause( + const syntax::GenericWhereClauseSyntax &syntax, + const SourceLoc Loc, + GenericParamList *genericParams); + public: //===--------------------------------------------------------------------===// // Expressions. @@ -78,7 +107,8 @@ public: //===--------------------------------------------------------------------===// // Types. - TypeRepr *generate(const syntax::TypeSyntax &Type, const SourceLoc Loc); + TypeRepr *generate(const syntax::TypeSyntax &Type, const SourceLoc Loc, + bool IsSILFuncDecl = false); TypeRepr *generate(const syntax::SomeTypeSyntax &Type, const SourceLoc Loc); TypeRepr *generate(const syntax::CompositionTypeSyntax &Type, const SourceLoc Loc); @@ -100,11 +130,21 @@ public: const SourceLoc Loc); TypeRepr *generate(const syntax::ImplicitlyUnwrappedOptionalTypeSyntax &Type, const SourceLoc Loc); + TypeRepr *generate(const syntax::ClassRestrictionTypeSyntax &Type, + const SourceLoc Loc); + TypeRepr *generate(const syntax::SILBoxTypeSyntax &Type, const SourceLoc Loc, + bool IsSILFuncDecl); + TypeRepr *generate(const syntax::SILFunctionTypeSyntax &Type, + const SourceLoc Loc, bool IsSILFuncDecl); TypeRepr *generate(const syntax::CodeCompletionTypeSyntax &Type, const SourceLoc Loc); TypeRepr *generate(const syntax::UnknownTypeSyntax &Type, const SourceLoc Loc); + TypeAttributes + generateTypeAttributes(const syntax::AttributeListSyntax &syntax, + const SourceLoc Loc); + private: TupleTypeRepr * generateTuple(const syntax::TokenSyntax &LParen, @@ -169,10 +209,6 @@ private: TypeRepr *lookupType(syntax::TypeSyntax Type); public: - void addType(TypeRepr *Type, const SourceLoc Loc); - bool hasType(const SourceLoc Loc) const; - TypeRepr *getType(const SourceLoc Loc) const; - void addDeclAttributes(DeclAttributes attrs, const SourceLoc Loc); bool hasDeclAttributes(SourceLoc Loc) const; DeclAttributes getDeclAttributes(const SourceLoc Loc) const; diff --git a/include/swift/Parse/LibSyntaxGenerator.h b/include/swift/Parse/LibSyntaxGenerator.h index 1333ed74af2..1e8dc2b74b6 100644 --- a/include/swift/Parse/LibSyntaxGenerator.h +++ b/include/swift/Parse/LibSyntaxGenerator.h @@ -38,13 +38,14 @@ public: assert(Node.isDeferredToken()); auto Kind = Node.getTokenKind(); - auto Range = Node.getDeferredTokenRangeWithTrivia(); + auto Range = Node.getDeferredTokenRange(); auto LeadingTriviaPieces = Node.getDeferredLeadingTriviaPieces(); auto TrailingTriviaPieces = Node.getDeferredTrailingTriviaPieces(); auto Recorded = Recorder.recordToken(Kind, Range, LeadingTriviaPieces, TrailingTriviaPieces); - auto Raw = static_cast(Recorded.takeOpaqueNode()); + RC Raw{static_cast(Recorded.takeOpaqueNode())}; + Raw->Release(); // -1 since it's transfer of ownership. return make(Raw); } @@ -55,7 +56,7 @@ public: auto Children = Node.getDeferredChildren(); auto Recorded = Recorder.recordRawSyntax(Kind, Children); - RC Raw {static_cast(Recorded.takeOpaqueNode()) }; + RC Raw{static_cast(Recorded.takeOpaqueNode())}; Raw->Release(); // -1 since it's transfer of ownership. return make(Raw); } diff --git a/include/swift/Parse/ParsedRawSyntaxNode.h b/include/swift/Parse/ParsedRawSyntaxNode.h index eb55cff04b2..4cbd13f6dfb 100644 --- a/include/swift/Parse/ParsedRawSyntaxNode.h +++ b/include/swift/Parse/ParsedRawSyntaxNode.h @@ -119,8 +119,20 @@ public: assert(getTokenKind() == tokKind && "Token kind with too large value!"); } +#ifndef NDEBUG + bool ensureDataIsNotRecorded() { + if (DK != DataKind::Recorded) + return true; + llvm::dbgs() << "Leaking node: "; + dump(llvm::dbgs()); + llvm::dbgs() << "\n"; + return false; + } +#endif + ParsedRawSyntaxNode &operator=(ParsedRawSyntaxNode &&other) { - assert(DK != DataKind::Recorded); + assert(ensureDataIsNotRecorded() && + "recorded data is being destroyed by assignment"); switch (other.DK) { case DataKind::Null: break; @@ -145,7 +157,7 @@ public: *this = std::move(other); } ~ParsedRawSyntaxNode() { - assert(DK != DataKind::Recorded); + assert(ensureDataIsNotRecorded() && "recorded data is being destructed"); } syntax::SyntaxKind getKind() const { return syntax::SyntaxKind(SynKind); } diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index 840b0dac37e..8ddfcae2ffc 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -40,7 +40,7 @@ #include "llvm/ADT/SetVector.h" namespace llvm { - template class PointerUnion3; + template class PointerUnion; } namespace swift { @@ -1004,12 +1004,28 @@ public: bool delayParsingDeclList(SourceLoc LBLoc, SourceLoc &RBLoc, IterableDeclContext *IDC); + ParsedSyntaxResult + parseTypeInheritanceClauseSyntax(bool allowClassRequirement, + bool allowAnyObject); + + ParsedSyntaxResult + parseDeclAssociatedTypeSyntax(ParseDeclOptions flags, + Optional attrs, + Optional modifiers); + + ParsedSyntaxResult + parseDeclTypeAliasSyntax(ParseDeclOptions flags, + Optional attrs, + Optional modifiers); + ParserResult parseDeclTypeAlias(ParseDeclOptions Flags, - DeclAttributes &Attributes); + DeclAttributes &Attributes, + SourceLoc leadingLoc); ParserResult parseDeclAssociatedType(ParseDeclOptions Flags, - DeclAttributes &Attributes); - + DeclAttributes &Attributes, + SourceLoc leadingLoc); + /// Parse a #if ... #endif directive. /// Delegate callback function to parse elements in the blocks. ParserResult parseIfConfig( @@ -1071,27 +1087,16 @@ public: /// an error parsing. bool parseVersionTuple(llvm::VersionTuple &Version, SourceRange &Range, const Diagnostic &D); - bool parseTypeAttributeList(ParamDecl::Specifier &Specifier, SourceLoc &SpecifierLoc, - TypeAttributes &Attributes) { - if (Tok.isAny(tok::at_sign, tok::kw_inout) || - (Tok.is(tok::identifier) && - (Tok.getRawText().equals("__shared") || - Tok.getRawText().equals("__owned")))) - return parseTypeAttributeListPresent(Specifier, SpecifierLoc, Attributes); - return false; - } - bool parseTypeAttributeListPresent(ParamDecl::Specifier &Specifier, - SourceLoc &SpecifierLoc, - TypeAttributes &Attributes); - bool parseTypeAttribute(TypeAttributes &Attributes, SourceLoc AtLoc, - bool justChecking = false); - - + TypeAttributes &Attributes); + ParserStatus parseTypeAttributeListSyntax(Optional &specifier, + Optional &attrs); + ParsedSyntaxResult parseTypeAttributeSyntax(); + ParserResult parseDeclImport(ParseDeclOptions Flags, DeclAttributes &Attributes); - ParserStatus parseInheritance(SmallVectorImpl &Inherited, + ParserStatus parseInheritance(MutableArrayRef &Inherited, bool allowClassRequirement, bool allowAnyObject); ParserStatus parseDeclItem(bool &PreviousHadSemi, @@ -1179,44 +1184,47 @@ public: //===--------------------------------------------------------------------===// // Type Parsing - using TypeASTResult = ParserResult; - using TypeResult = ParsedSyntaxResult; + ParserResult parseType(); + ParserResult parseType(Diag<> MessageID, + bool HandleCodeCompletion = true, + bool IsSILFuncDecl = false); + ParserStatus parseGenericArguments(llvm::SmallVectorImpl &ArgsAST, + SourceLoc &LAngleLoc, + SourceLoc &RAngleLoc); + TypeRepr *applyAttributeToType(TypeRepr *Ty, const TypeAttributes &Attr, + ParamDecl::Specifier Specifier, + SourceLoc SpecifierLoc); + ParserResult parseAnyTypeAST(); ParsedSyntaxResult parseLayoutConstraintSyntax(); - TypeResult parseTypeSyntax(); - TypeResult parseTypeSyntax(Diag<> MessageID, bool HandleCodeCompletion = true, - bool IsSILFuncDecl = false); - - TypeASTResult parseType(); - TypeASTResult parseType(Diag<> MessageID, bool HandleCodeCompletion = true, - bool IsSILFuncDecl = false); - ParserStatus - parseGenericArgumentsAST(llvm::SmallVectorImpl &ArgsAST, - SourceLoc &LAngleLoc, SourceLoc &RAngleLoc); - TypeASTResult parseSILBoxType(GenericParamList *generics, - const TypeAttributes &attrs, - Optional &GenericsScope); - TypeASTResult parseTypeSimpleOrCompositionAST(Diag<> MessageID, - bool HandleCodeCompletion); - TypeASTResult parseAnyTypeAST(); + ParsedSyntaxResult parseTypeSyntax(); + ParsedSyntaxResult + parseTypeSyntax(Diag<> MessageID, bool HandleCodeCompletion = true, + bool IsSILFuncDecl = false); ParsedSyntaxResult parseGenericArgumentClauseSyntax(); - TypeResult parseTypeSimple(Diag<> MessageID, bool HandleCodeCompletion); - TypeResult parseTypeSimpleOrComposition(Diag<> MessageID, bool HandleCodeCompletion); - TypeResult parseTypeIdentifier(); - TypeResult parseAnyType(); - TypeResult parseTypeTupleBody(); - TypeResult parseTypeCollection(); - TypeResult parseMetatypeType(ParsedTypeSyntax Base); - TypeResult parseOptionalType(ParsedTypeSyntax Base); - TypeResult parseImplicitlyUnwrappedOptionalType(ParsedTypeSyntax Base); + ParsedSyntaxResult + parseTypeSimple(Diag<> MessageID, bool HandleCodeCompletion); + ParsedSyntaxResult + parseTypeSimpleOrComposition(Diag<> MessageID, bool HandleCodeCompletion); + ParsedSyntaxResult parseTypeIdentifier(); + ParsedSyntaxResult parseAnyType(); + ParsedSyntaxResult parseTypeTupleBody(); + ParsedSyntaxResult parseTypeCollection(); + ParsedSyntaxResult parseMetatypeType(ParsedTypeSyntax Base); + ParsedSyntaxResult parseOptionalType(ParsedTypeSyntax Base); + ParsedSyntaxResult + parseImplicitlyUnwrappedOptionalType(ParsedTypeSyntax Base); + ParsedSyntaxResult parseSILBoxTypeSyntax( + Optional genericParams); - TypeResult parseTypeArray(ParsedTypeSyntax Base, SourceLoc BaseLoc); - TypeResult parseOldStyleProtocolComposition(); + ParsedSyntaxResult parseTypeArray(ParsedTypeSyntax Base, + SourceLoc BaseLoc); + ParsedSyntaxResult parseOldStyleProtocolComposition(); bool isOptionalToken(const Token &T) const; ParsedTokenSyntax consumeOptionalTokenSyntax(); @@ -1226,9 +1234,10 @@ public: ParsedTokenSyntax consumeImplicitlyUnwrappedOptionalTokenSyntax(); SourceLoc consumeImplicitlyUnwrappedOptionalToken(); - TypeRepr *applyAttributeToType(TypeRepr *Ty, const TypeAttributes &Attr, - ParamDecl::Specifier Specifier, - SourceLoc SpecifierLoc); + ParsedSyntaxResult + applyAttributeToTypeSyntax(ParsedSyntaxResult &&ty, + Optional specifier, + Optional attrs); //===--------------------------------------------------------------------===// // Pattern Parsing @@ -1624,6 +1633,9 @@ public: SmallVectorImpl &GenericParams); ParserResult maybeParseGenericParams(); void + diagnoseWhereClauseInGenericParamList(const GenericParamList *GenericParams, + SourceLoc whereLoc); + void diagnoseWhereClauseInGenericParamList(const GenericParamList *GenericParams); enum class WhereClauseKind : unsigned { diff --git a/include/swift/Parse/SyntaxParsingContext.h b/include/swift/Parse/SyntaxParsingContext.h index 6df76bebca0..96d4d579244 100644 --- a/include/swift/Parse/SyntaxParsingContext.h +++ b/include/swift/Parse/SyntaxParsingContext.h @@ -279,17 +279,9 @@ public: } /// Returns the topmost Syntax node. - template SyntaxNode topNode() { - ParsedRawSyntaxNode &TopNode = getStorage().back(); - if (TopNode.isRecorded()) { - OpaqueSyntaxNode OpaqueNode = TopNode.getOpaqueNode(); - return getSyntaxCreator().getLibSyntaxNodeFor(OpaqueNode); - } - return getSyntaxCreator().createNode(TopNode.copyDeferred()); - } + template SyntaxNode topNode(); - template - llvm::Optional popIf() { + template llvm::Optional popIf() { auto &Storage = getStorage(); if (Storage.size() <= Offset) return llvm::None; @@ -376,5 +368,24 @@ public: "Only meant for use in the debugger"); }; +template +inline SyntaxNode SyntaxParsingContext::topNode() { + ParsedRawSyntaxNode &TopNode = getStorage().back(); + if (TopNode.isRecorded()) { + OpaqueSyntaxNode OpaqueNode = TopNode.getOpaqueNode(); + return getSyntaxCreator().getLibSyntaxNodeFor(OpaqueNode); + } + return getSyntaxCreator().createNode(TopNode.copyDeferred()); +} + +template <> inline TokenSyntax SyntaxParsingContext::topNode() { + ParsedRawSyntaxNode &TopNode = getStorage().back(); + if (TopNode.isRecorded()) { + OpaqueSyntaxNode OpaqueNode = TopNode.getOpaqueNode(); + return getSyntaxCreator().getLibSyntaxNodeFor(OpaqueNode); + } + return getSyntaxCreator().createToken(TopNode.copyDeferred()); +} + } // namespace swift #endif // SWIFT_SYNTAX_PARSING_CONTEXT_H diff --git a/include/swift/Reflection/ReflectionContext.h b/include/swift/Reflection/ReflectionContext.h index 171f2df7b6d..d534379cf54 100644 --- a/include/swift/Reflection/ReflectionContext.h +++ b/include/swift/Reflection/ReflectionContext.h @@ -393,6 +393,8 @@ public: auto SecBuf = this->getReader().readBytes( RemoteAddress(SectionHdrAddress + (I * SectionEntrySize)), SectionEntrySize); + if (!SecBuf) + return false; auto SecHdr = reinterpret_cast(SecBuf.get()); SecHdrVec.push_back(SecHdr); diff --git a/include/swift/Reflection/TypeRefBuilder.h b/include/swift/Reflection/TypeRefBuilder.h index 4c88a7b7ad0..abf7d17cd68 100644 --- a/include/swift/Reflection/TypeRefBuilder.h +++ b/include/swift/Reflection/TypeRefBuilder.h @@ -376,11 +376,8 @@ public: // Try to resolve to the underlying type, if we can. if (opaqueDescriptor->getKind() == Node::Kind::OpaqueTypeDescriptorSymbolicReference) { - if (!OpaqueUnderlyingTypeReader) - return nullptr; - auto underlyingTy = OpaqueUnderlyingTypeReader( - (const void *)opaqueDescriptor->getIndex(), ordinal); + opaqueDescriptor->getIndex(), ordinal); if (!underlyingTy) return nullptr; @@ -598,7 +595,7 @@ private: unsigned PointerSize; std::function)> TypeRefDemangler; - std::function + std::function OpaqueUnderlyingTypeReader; public: @@ -613,9 +610,8 @@ public: Dem, /*useOpaqueTypeSymbolicReferences*/ true); }), OpaqueUnderlyingTypeReader( - [&reader](const void *descriptor, unsigned ordinal) -> const TypeRef* { - auto context = (typename Runtime::StoredPointer)descriptor; - return reader.readUnderlyingTypeForOpaqueTypeDescriptor(context, + [&reader](uint64_t descriptorAddr, unsigned ordinal) -> const TypeRef* { + return reader.readUnderlyingTypeForOpaqueTypeDescriptor(descriptorAddr, ordinal); }) {} diff --git a/include/swift/Remote/CMemoryReader.h b/include/swift/Remote/CMemoryReader.h index f7575fa6f9c..989f6bf87c6 100644 --- a/include/swift/Remote/CMemoryReader.h +++ b/include/swift/Remote/CMemoryReader.h @@ -66,8 +66,13 @@ public: bool readString(RemoteAddress address, std::string &dest) override { auto length = getStringLength(address); - if (!length) - return false; + if (length == 0) { + // A length of zero unfortunately might mean either that there's a zero + // length string at the location we're trying to read, or that reading + // failed. We can do a one-byte read to tell them apart. + auto buf = readBytes(address, 1); + return buf && ((const char*)buf.get())[0] == 0; + } auto Buf = readBytes(address, length); if (!Buf) diff --git a/include/swift/SIL/OptimizationRemark.h b/include/swift/SIL/OptimizationRemark.h index f5c74888dcc..5accdbc2e76 100644 --- a/include/swift/SIL/OptimizationRemark.h +++ b/include/swift/SIL/OptimizationRemark.h @@ -157,9 +157,9 @@ public: using RemarkT = decltype(RemarkBuilder()); // Avoid building the remark unless remarks are enabled. if (isEnabled() || Module.getOptRecordStream()) { - auto R = RemarkBuilder(); - R.setPassName(PassName); - emit(R); + auto rb = RemarkBuilder(); + rb.setPassName(PassName); + emit(rb); } } diff --git a/include/swift/SIL/SILArgumentArrayRef.h b/include/swift/SIL/SILArgumentArrayRef.h index ce5c1d8ec60..c01a656efd2 100644 --- a/include/swift/SIL/SILArgumentArrayRef.h +++ b/include/swift/SIL/SILArgumentArrayRef.h @@ -22,7 +22,6 @@ #include "swift/Basic/LLVM.h" #include "swift/Basic/STLExtras.h" -#include "swift/Basic/TransformArrayRef.h" namespace swift { @@ -31,10 +30,11 @@ class SILPhiArgument; class SILFunctionArgument; using PhiArgumentArrayRef = - TransformArrayRef>; + TransformRange, SILPhiArgument *(*)(SILArgument *)>; using FunctionArgumentArrayRef = - TransformArrayRef>; + TransformRange, + SILFunctionArgument *(*)(SILArgument *)>; } // namespace swift diff --git a/include/swift/SIL/SILBasicBlock.h b/include/swift/SIL/SILBasicBlock.h index 3536aed2f57..db7f53cd6a5 100644 --- a/include/swift/SIL/SILBasicBlock.h +++ b/include/swift/SIL/SILBasicBlock.h @@ -19,7 +19,6 @@ #include "swift/Basic/Compiler.h" #include "swift/Basic/Range.h" -#include "swift/Basic/TransformArrayRef.h" #include "swift/SIL/SILArgumentArrayRef.h" #include "swift/SIL/SILInstruction.h" diff --git a/include/swift/SIL/SILGlobalVariable.h b/include/swift/SIL/SILGlobalVariable.h index 0684c4832f2..eedc850458e 100644 --- a/include/swift/SIL/SILGlobalVariable.h +++ b/include/swift/SIL/SILGlobalVariable.h @@ -17,7 +17,6 @@ #ifndef SWIFT_SIL_SILGLOBALVARIABLE_H #define SWIFT_SIL_SILGLOBALVARIABLE_H -#include #include "swift/SIL/SILLinkage.h" #include "swift/SIL/SILLocation.h" #include "swift/SIL/SILBasicBlock.h" diff --git a/include/swift/SIL/SILInstructionWorklist.h b/include/swift/SIL/SILInstructionWorklist.h index af43d47bf4a..36af8225211 100644 --- a/include/swift/SIL/SILInstructionWorklist.h +++ b/include/swift/SIL/SILInstructionWorklist.h @@ -33,7 +33,7 @@ #include "swift/Basic/BlotSetVector.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILValue.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" diff --git a/include/swift/SIL/SILValue.h b/include/swift/SIL/SILValue.h index 46b3eeb573d..03be26fabe5 100644 --- a/include/swift/SIL/SILValue.h +++ b/include/swift/SIL/SILValue.h @@ -387,6 +387,18 @@ public: NumLowBitsAvailable }; + /// If this SILValue is a result of an instruction, return its + /// defining instruction. Returns nullptr otherwise. + SILInstruction *getDefiningInstruction() { + return Value->getDefiningInstruction(); + } + + /// If this SILValue is a result of an instruction, return its + /// defining instruction. Returns nullptr otherwise. + const SILInstruction *getDefiningInstruction() const { + return Value->getDefiningInstruction(); + } + /// Returns the ValueOwnershipKind that describes this SILValue's ownership /// semantics if the SILValue has ownership semantics. Returns is a value /// without any Ownership Semantics. diff --git a/include/swift/SIL/TypeSubstCloner.h b/include/swift/SIL/TypeSubstCloner.h index 5bca456a3f4..3bbb363945a 100644 --- a/include/swift/SIL/TypeSubstCloner.h +++ b/include/swift/SIL/TypeSubstCloner.h @@ -21,10 +21,10 @@ #include "swift/AST/GenericEnvironment.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/Type.h" -#include "swift/SIL/SILCloner.h" #include "swift/SIL/DynamicCasts.h" +#include "swift/SIL/SILCloner.h" #include "swift/SIL/SILFunctionBuilder.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/SpecializationMangler.h" #include "llvm/Support/Debug.h" diff --git a/include/swift/SILOptimizer/Analysis/CFG.h b/include/swift/SILOptimizer/Analysis/CFG.h deleted file mode 100644 index 2f8b195b1e0..00000000000 --- a/include/swift/SILOptimizer/Analysis/CFG.h +++ /dev/null @@ -1,50 +0,0 @@ -//===--- CFG.h - Routines which analyze the CFG of a function ---*- C++ -*-===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// - -#ifndef SWIFT_SILOPTIMIZER_ANALYSIS_CFG_H -#define SWIFT_SILOPTIMIZER_ANALYSIS_CFG_H - -namespace llvm { - -template class TinyPtrVector; - -} // end namespace llvm - -namespace swift { - -class SILFunction; -class SILBasicBlock; - -/// Return true if we conservatively find all BB's that are non-failure exit -/// basic blocks and place them in \p BBs. If we find something we don't -/// understand, bail. -/// -/// A non-failure exit BB is defined as a BB that: -/// -/// 1. Has a return terminator. -/// 2. unreachable + noreturn terminator sequence. -/// 3. has a throw terminator. -/// -/// If we just have an unreachable without a noreturn call before it, we must -/// have a failure BB. -/// -/// We use a TinyPtrVector since in most cases this will only return one -/// SILBasicBlock since non-failure noreturn functions should not occur often -/// implying in most cases this will be one element. -/// -/// TODO: -bool findAllNonFailureExitBBs(SILFunction *F, - llvm::TinyPtrVector &BBs); - -} // end namespace swift - -#endif diff --git a/include/swift/SILOptimizer/Analysis/CallerAnalysis.h b/include/swift/SILOptimizer/Analysis/CallerAnalysis.h index b23570c2e49..b2a722f3ed6 100644 --- a/include/swift/SILOptimizer/Analysis/CallerAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/CallerAnalysis.h @@ -17,7 +17,7 @@ #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILModule.h" #include "swift/SILOptimizer/Analysis/Analysis.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallSet.h" diff --git a/include/swift/SILOptimizer/Analysis/LoopRegionAnalysis.h b/include/swift/SILOptimizer/Analysis/LoopRegionAnalysis.h index ffce0af3c36..c3682a33f01 100644 --- a/include/swift/SILOptimizer/Analysis/LoopRegionAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/LoopRegionAnalysis.h @@ -384,7 +384,7 @@ public: private: /// A pointer to one of a Loop, Basic Block, or Function represented by this /// region. - llvm::PointerUnion3 Ptr; + llvm::PointerUnion Ptr; /// The ID of this region. unsigned ID; diff --git a/include/swift/SILOptimizer/Utils/BasicBlockOptUtils.h b/include/swift/SILOptimizer/Utils/BasicBlockOptUtils.h new file mode 100644 index 00000000000..2d0bb0e4578 --- /dev/null +++ b/include/swift/SILOptimizer/Utils/BasicBlockOptUtils.h @@ -0,0 +1,260 @@ +//===--- BasicBlockOptUtils.h - SIL basic block utilities -------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +/// +/// Utilities used by the SILOptimizer for analyzing and operating on whole +/// basic blocks, including as removal, cloning, and SSA update. +/// +/// CFGOptUtils.h provides lower-level CFG branch and edge utilities. +/// +/// SIL/BasicBlockUtils.h provides essential SILBasicBlock utilities. +/// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_SILOPTIMIZER_UTILS_BASICBLOCKOPTUTILS_H +#define SWIFT_SILOPTIMIZER_UTILS_BASICBLOCKOPTUTILS_H + +#include "swift/SIL/SILInstruction.h" +#include "swift/SIL/SILBasicBlock.h" +#include "swift/SIL/SILCloner.h" + +namespace swift { + +class BasicBlockCloner; +class SILLoop; +class SILLoopInfo; + +/// Remove all instructions in the body of \p bb in safe manner by using +/// undef. +void clearBlockBody(SILBasicBlock *bb); + +/// Handle the mechanical aspects of removing an unreachable block. +void removeDeadBlock(SILBasicBlock *bb); + +/// Remove all unreachable blocks in a function. +bool removeUnreachableBlocks(SILFunction &f); + +/// Return true if there are any users of v outside the specified block. +inline bool isUsedOutsideOfBlock(SILValue v) { + auto *bb = v->getParentBlock(); + for (auto *use : v->getUses()) + if (use->getUser()->getParent() != bb) + return true; + return false; +} + +/// Rotate a loop's header as long as it is exiting and not equal to the +/// passed basic block. +/// If \p RotateSingleBlockLoops is true a single basic block loop will be +/// rotated once. ShouldVerify specifies whether to perform verification after +/// the transformation. +/// Returns true if the loop could be rotated. +bool rotateLoop(SILLoop *loop, DominanceInfo *domInfo, SILLoopInfo *loopInfo, + bool rotateSingleBlockLoops, SILBasicBlock *upToBB, + bool shouldVerify); + +/// Helper function to perform SSA updates in case of jump threading. +void updateSSAAfterCloning(BasicBlockCloner &cloner, SILBasicBlock *srcBB, + SILBasicBlock *destBB); + +/// Clone a single basic block and any required successor edges within the same +/// function. +class BasicBlockCloner : public SILCloner { + using SuperTy = SILCloner; + friend class SILCloner; + +protected: + /// The original block to be cloned. + SILBasicBlock *origBB; + +public: + /// An ordered list of old to new available value pairs. + /// + /// updateSSAAfterCloning() expects this public field to hold values that may + /// be remapped in the cloned block and live out. + SmallVector, 16> AvailVals; + + // Clone blocks starting at `origBB`, within the same function. + BasicBlockCloner(SILBasicBlock *origBB) + : SILCloner(*origBB->getParent()), origBB(origBB) {} + + void cloneBlock(SILBasicBlock *insertAfterBB = nullptr) { + SmallVector successorBBs; + successorBBs.reserve(origBB->getSuccessors().size()); + llvm::copy(origBB->getSuccessors(), std::back_inserter(successorBBs)); + cloneReachableBlocks(origBB, successorBBs, insertAfterBB); + } + + /// Clone the given branch instruction's destination block, splitting + /// its successors, and rewrite the branch instruction. + void cloneBranchTarget(BranchInst *bi) { + assert(origBB == bi->getDestBB()); + + cloneBlock(/*insertAfter*/ bi->getParent()); + + SILBuilderWithScope(bi).createBranch(bi->getLoc(), getNewBB(), + bi->getArgs()); + bi->eraseFromParent(); + } + + /// Get the newly cloned block corresponding to `origBB`. + SILBasicBlock *getNewBB() { + return remapBasicBlock(origBB); + } + + /// Call this after processing all instructions to fix the control flow + /// graph. The branch cloner may have left critical edges. + bool splitCriticalEdges(DominanceInfo *domInfo, SILLoopInfo *loopInfo); + +protected: + // MARK: CRTP overrides. + + /// Override getMappedValue to allow values defined outside the block to be + /// cloned to be reused in the newly cloned block. + SILValue getMappedValue(SILValue value) { + if (auto si = value->getDefiningInstruction()) { + if (!isBlockCloned(si->getParent())) + return value; + } else if (auto bbArg = dyn_cast(value)) { + if (!isBlockCloned(bbArg->getParent())) + return value; + } else { + assert(isa(value) && "Unexpected Value kind"); + return value; + } + // `value` is not defined outside the cloned block, so consult the cloner's + // map of cloned values. + return SuperTy::getMappedValue(value); + } + + void mapValue(SILValue origValue, SILValue mappedValue) { + SuperTy::mapValue(origValue, mappedValue); + AvailVals.emplace_back(origValue, mappedValue); + } +}; + +// Helper class that provides a callback that can be used in +// inliners/cloners for collecting new call sites. +class CloneCollector { +public: + typedef std::pair value_type; + typedef std::function CallbackType; + typedef std::function FilterType; + +private: + FilterType filter; + + // Pairs of collected instructions; (new, old) + llvm::SmallVector instructionpairs; + + void collect(SILInstruction *oldI, SILInstruction *newI) { + if (filter(newI)) + instructionpairs.push_back(std::make_pair(newI, oldI)); + } + +public: + CloneCollector(FilterType filter) : filter(filter) {} + + CallbackType getCallback() { + return std::bind(&CloneCollector::collect, this, std::placeholders::_1, + std::placeholders::_2); + } + + llvm::SmallVectorImpl &getInstructionPairs() { + return instructionpairs; + } +}; + +/// Sink address projections to their out-of-block uses. This is +/// required after cloning a block and before calling +/// updateSSAAfterCloning to avoid address-type phis. +/// +/// This clones address projections at their use points, but does not +/// mutate the block containing the projections. +class SinkAddressProjections { + // Projections ordered from last to first in the chain. + SmallVector projections; + SmallSetVector inBlockDefs; + +public: + /// Check for an address projection chain ending at \p inst. Return true if + /// the given instruction is successfully analyzed. + /// + /// If \p inst does not produce an address, then return + /// true. getInBlockDefs() will contain \p inst if any of its + /// (non-address) values are used outside its block. + /// + /// If \p inst does produce an address, return true only of the + /// chain of address projections within this block is clonable at + /// their use sites. getInBlockDefs will return all non-address + /// operands in the chain that are also defined in this block. These + /// may require phis after cloning the projections. + bool analyzeAddressProjections(SILInstruction *inst); + + /// After analyzing projections, returns the list of (non-address) values + /// defined in the same block as the projections which will have uses outside + /// the block after cloning. + ArrayRef getInBlockDefs() const { + return inBlockDefs.getArrayRef(); + } + /// Clone the chain of projections at their use sites. + /// + /// Return true if anything was done. + /// + /// getInBlockProjectionOperandValues() can be called before or after cloning. + bool cloneProjections(); +}; + +/// Utility class for cloning init values into the static initializer of a +/// SILGlobalVariable. +class StaticInitCloner : public SILCloner { + friend class SILInstructionVisitor; + friend class SILCloner; + + /// The number of not yet cloned operands for each instruction. + llvm::DenseMap numOpsToClone; + + /// List of instructions for which all operands are already cloned (or which + /// don't have any operands). + llvm::SmallVector readyToClone; + +public: + StaticInitCloner(SILGlobalVariable *gVar) + : SILCloner(gVar) {} + + /// Add \p InitVal and all its operands (transitively) for cloning. + /// + /// Note: all init values must are added, before calling clone(). + void add(SILInstruction *initVal); + + /// Clone \p InitVal and all its operands into the initializer of the + /// SILGlobalVariable. + /// + /// \return Returns the cloned instruction in the SILGlobalVariable. + SingleValueInstruction *clone(SingleValueInstruction *initVal); + + /// Convenience function to clone a single \p InitVal. + static void appendToInitializer(SILGlobalVariable *gVar, + SingleValueInstruction *initVal) { + StaticInitCloner cloner(gVar); + cloner.add(initVal); + cloner.clone(initVal); + } + +protected: + SILLocation remapLocation(SILLocation loc) { + return ArtificialUnreachableLocation(); + } +}; + +} // namespace swift + +#endif diff --git a/include/swift/SILOptimizer/Utils/CFG.h b/include/swift/SILOptimizer/Utils/CFGOptUtils.h similarity index 56% rename from include/swift/SILOptimizer/Utils/CFG.h rename to include/swift/SILOptimizer/Utils/CFGOptUtils.h index ceaea27b91f..9c3f8189ff7 100644 --- a/include/swift/SILOptimizer/Utils/CFG.h +++ b/include/swift/SILOptimizer/Utils/CFGOptUtils.h @@ -1,20 +1,34 @@ -//===--- CFG.h - Utilities for SIL CFG transformations ----------*- C++ -*-===// +//===--- CFGOptUtils.h - SIL CFG edge utilities -----------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// +/// +/// APIs used by the SILOptimizer for low-level branch and CFG edge analysis +/// and operations. These may merge blocks, split blocks, or create empty +/// blocks, but don't duplicate whole blocks. +/// +/// Essential CFG utilities are in SIL/CFG.h. +/// +/// Whole block-level transformations are in BasicBlockOptUtils.h. +/// +//===----------------------------------------------------------------------===// -#ifndef SWIFT_SILOPTIMIZER_UTILS_CFG_H -#define SWIFT_SILOPTIMIZER_UTILS_CFG_H +#ifndef SWIFT_SILOPTIMIZER_UTILS_CFGOPTUTILS_H +#define SWIFT_SILOPTIMIZER_UTILS_CFGOPTUTILS_H -#include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILBuilder.h" +#include "swift/SIL/SILInstruction.h" + +namespace llvm { +template class TinyPtrVector; +} namespace swift { @@ -25,25 +39,25 @@ class SILLoopInfo; /// Adds a new argument to an edge between a branch and a destination /// block. /// -/// \param Branch The terminator to add the argument to. -/// \param Dest The destination block of the edge. -/// \param Val The value to the arguments of the branch. +/// \param branch The terminator to add the argument to. +/// \param dest The destination block of the edge. +/// \param val The value to the arguments of the branch. /// \return The created branch. The old branch is deleted. /// The argument is appended at the end of the argument tuple. -TermInst *addNewEdgeValueToBranch(TermInst *Branch, SILBasicBlock *Dest, - SILValue Val); +TermInst *addNewEdgeValueToBranch(TermInst *branch, SILBasicBlock *dest, + SILValue val); /// Changes the edge value between a branch and destination basic block /// at the specified index. Changes all edges from \p Branch to \p Dest to carry /// the value. /// -/// \param Branch The branch to modify. -/// \param Dest The destination of the edge. -/// \param Idx The index of the argument to modify. -/// \param Val The new value to use. +/// \param branch The branch to modify. +/// \param dest The destination of the edge. +/// \param idx The index of the argument to modify. +/// \param val The new value to use. /// \return The new branch. Deletes the old one. -TermInst *changeEdgeValue(TermInst *Branch, SILBasicBlock *Dest, size_t Idx, - SILValue Val); +TermInst *changeEdgeValue(TermInst *branch, SILBasicBlock *dest, size_t idx, + SILValue val); /// Deletes the edge value between a branch and a destination basic block at the /// specified index. Asserts internally that the argument along the edge does @@ -59,24 +73,24 @@ void erasePhiArgument(SILBasicBlock *block, unsigned argIndex); /// Replace a branch target. /// -/// \param T The terminating instruction to modify. -/// \param OldDest The successor block that will be replaced. -/// \param NewDest The new target block. -/// \param PreserveArgs If set, preserve arguments on the replaced edge. -void replaceBranchTarget(TermInst *T, SILBasicBlock *OldDest, - SILBasicBlock *NewDest, bool PreserveArgs); +/// \param t The terminating instruction to modify. +/// \param oldDest The successor block that will be replaced. +/// \param newDest The new target block. +/// \param preserveArgs If set, preserve arguments on the replaced edge. +void replaceBranchTarget(TermInst *t, SILBasicBlock *oldDest, + SILBasicBlock *newDest, bool preserveArgs); /// Check if the edge from the terminator is critical. -bool isCriticalEdge(TermInst *T, unsigned EdgeIdx); +bool isCriticalEdge(TermInst *t, unsigned edgeIdx); /// Splits the edge from terminator if it is critical. /// /// Updates dominance information and loop information if not null. /// Returns the newly created basic block on success or nullptr otherwise (if /// the edge was not critical). -SILBasicBlock *splitCriticalEdge(TermInst *T, unsigned EdgeIdx, - DominanceInfo *DT = nullptr, - SILLoopInfo *LI = nullptr); +SILBasicBlock *splitCriticalEdge(TermInst *, unsigned edgeIdx, + DominanceInfo *domInfo = nullptr, + SILLoopInfo *loopInfo = nullptr); /// Splits the critical edges between from and to. This code assumes there is /// exactly one edge between the two basic blocks. It will return the wrong @@ -84,45 +98,39 @@ SILBasicBlock *splitCriticalEdge(TermInst *T, unsigned EdgeIdx, /// between the two blocks. /// /// Updates dominance information and loop information if not null. -SILBasicBlock *splitIfCriticalEdge(SILBasicBlock *From, SILBasicBlock *To, - DominanceInfo *DT = nullptr, - SILLoopInfo *LI = nullptr); +SILBasicBlock *splitIfCriticalEdge(SILBasicBlock *from, SILBasicBlock *to, + DominanceInfo *domInfo = nullptr, + SILLoopInfo *loopInfo = nullptr); /// Splits all critical edges originating from `fromBB`. -bool splitCriticalEdgesFrom(SILBasicBlock *fromBB, DominanceInfo *DT = nullptr, - SILLoopInfo *LI = nullptr); +bool splitCriticalEdgesFrom(SILBasicBlock *fromBB, + DominanceInfo *domInfo = nullptr, + SILLoopInfo *loopInfo = nullptr); /// Splits the edges between two basic blocks. /// /// Updates dominance information and loop information if not null. -void splitEdgesFromTo(SILBasicBlock *From, SILBasicBlock *To, - DominanceInfo *DT = nullptr, SILLoopInfo *LI = nullptr); - -/// Rotate a loop's header as long as it is exiting and not equal to the -/// passed basic block. -/// If \p RotateSingleBlockLoops is true a single basic block loop will be -/// rotated once. ShouldVerify specifies whether to perform verification after -/// the transformation. -/// Returns true if the loop could be rotated. -bool rotateLoop(SILLoop *L, DominanceInfo *DT, SILLoopInfo *LI, - bool RotateSingleBlockLoops, SILBasicBlock *UpTo, - bool ShouldVerify); +void splitEdgesFromTo(SILBasicBlock *from, SILBasicBlock *to, + DominanceInfo *domInfo = nullptr, + SILLoopInfo *loopInfo = nullptr); /// Splits the basic block before the instruction with an unconditional branch /// and updates the dominator tree and loop info. Returns the new, branched to /// block that contains the end of \p SplitBeforeInst's block. -SILBasicBlock *splitBasicBlockAndBranch(SILBuilder &B, - SILInstruction *SplitBeforeInst, - DominanceInfo *DT, SILLoopInfo *LI); +SILBasicBlock *splitBasicBlockAndBranch(SILBuilder &builder, + SILInstruction *splitBeforeInst, + DominanceInfo *domInfo, + SILLoopInfo *loopInfo); /// Return true if the function has a critical edge, false otherwise. -bool hasCriticalEdges(SILFunction &F, bool OnlyNonCondBr); +bool hasCriticalEdges(SILFunction &f, bool onlyNonCondBr); /// Split all critical edges in the given function, updating the /// dominator tree and loop information if they are provided. /// /// FIXME: This should never be called! Fix passes that create critical edges. -bool splitAllCriticalEdges(SILFunction &F, DominanceInfo *DT, SILLoopInfo *LI); +bool splitAllCriticalEdges(SILFunction &F, DominanceInfo *domInfo, + SILLoopInfo *loopInfo); /// Split all cond_br critical edges with non-trivial arguments in the /// function updating the dominator tree and loop information (if they are not @@ -130,15 +138,15 @@ bool splitAllCriticalEdges(SILFunction &F, DominanceInfo *DT, SILLoopInfo *LI); /// /// A current invariant of Ownership SIL is that cond_br can only have critical /// edges with non-trivial arguments. This simplifies computation. -bool splitAllCondBrCriticalEdgesWithNonTrivialArgs(SILFunction &Fn, - DominanceInfo *DT, - SILLoopInfo *LI); +bool splitAllCondBrCriticalEdgesWithNonTrivialArgs(SILFunction &fn, + DominanceInfo *domInfo, + SILLoopInfo *loopInfo); /// Merge a basic block ending in a branch with its successor /// if possible. If dominance information or loop info is non null update it. /// Return true if block was merged. -bool mergeBasicBlockWithSuccessor(SILBasicBlock *BB, DominanceInfo *DT, - SILLoopInfo *LI); +bool mergeBasicBlockWithSuccessor(SILBasicBlock *bb, DominanceInfo *domInfo, + SILLoopInfo *loopInfo); /// Merge basic blocks in the given function by eliminating all unconditional /// branches to single-predecessor branch targets. @@ -148,7 +156,7 @@ bool mergeBasicBlockWithSuccessor(SILBasicBlock *BB, DominanceInfo *DT, /// is not done on-the-fly after splitting blocks because merging is linear in /// the number of instructions, so interleaved merging and splitting is /// quadratic. -bool mergeBasicBlocks(SILFunction *F); +bool mergeBasicBlocks(SILFunction *f); /// Given a list of \p UserBlocks and a list of \p DefBlocks, find a set of /// blocks that together with \p UserBlocks joint-postdominate \p @@ -177,11 +185,29 @@ bool mergeBasicBlocks(SILFunction *F); /// /// *NOTE* This completion may not be unique. void completeJointPostDominanceSet( - ArrayRef UserBlocks, ArrayRef DefBlocks, - llvm::SmallVectorImpl &Completion); + ArrayRef userBlocks, ArrayRef defBlocks, + llvm::SmallVectorImpl &completion); -/// Remove all unreachable blocks in a function. -bool removeUnreachableBlocks(SILFunction &Fn); +/// Return true if we conservatively find all bb's that are non-failure exit +/// basic blocks and place them in \p bbs. If we find something we don't +/// understand, bail. +/// +/// A non-failure exit BB is defined as a BB that: +/// +/// 1. Has a return terminator. +/// 2. unreachable + noreturn terminator sequence. +/// 3. has a throw terminator. +/// +/// If we just have an unreachable without a noreturn call before it, we must +/// have a failure BB. +/// +/// We use a TinyPtrVector since in most cases this will only return one +/// SILBasicBlock since non-failure noreturn functions should not occur often +/// implying in most cases this will be one element. +/// +/// TODO: +bool findAllNonFailureExitBBs(SILFunction *f, + llvm::TinyPtrVector &bbs); } // end namespace swift diff --git a/include/swift/SILOptimizer/Utils/Devirtualize.h b/include/swift/SILOptimizer/Utils/Devirtualize.h index d99810f951c..6301c64725e 100644 --- a/include/swift/SILOptimizer/Utils/Devirtualize.h +++ b/include/swift/SILOptimizer/Utils/Devirtualize.h @@ -27,7 +27,7 @@ #include "swift/SIL/SILType.h" #include "swift/SIL/SILValue.h" #include "swift/SILOptimizer/Analysis/ClassHierarchyAnalysis.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/ArrayRef.h" namespace swift { diff --git a/include/swift/SILOptimizer/Utils/GenericCloner.h b/include/swift/SILOptimizer/Utils/GenericCloner.h index 1c54bdecf16..ea0d3aa617d 100644 --- a/include/swift/SILOptimizer/Utils/GenericCloner.h +++ b/include/swift/SILOptimizer/Utils/GenericCloner.h @@ -22,7 +22,7 @@ #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/TypeSubstCloner.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h" #include "swift/SILOptimizer/Utils/Generics.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" diff --git a/include/swift/SILOptimizer/Utils/Generics.h b/include/swift/SILOptimizer/Utils/Generics.h index 3c78e3c6a1a..50c80b51578 100644 --- a/include/swift/SILOptimizer/Utils/Generics.h +++ b/include/swift/SILOptimizer/Utils/Generics.h @@ -20,7 +20,7 @@ #include "swift/AST/SubstitutionMap.h" #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILInstruction.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" diff --git a/include/swift/SILOptimizer/Utils/InstOptUtils.h b/include/swift/SILOptimizer/Utils/InstOptUtils.h new file mode 100644 index 00000000000..15c5f82089d --- /dev/null +++ b/include/swift/SILOptimizer/Utils/InstOptUtils.h @@ -0,0 +1,390 @@ +//===--- InstOptUtils.h - SILOptimizer instruction utilities ----*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +/// +/// Utilities used by the SILOptimizer for analyzing and transforming +/// SILInstructions. +/// +/// SIL/InstUtils.h provides essential SILInstruction utilities. +/// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_SILOPTIMIZER_UTILS_INSTOPTUTILS_H +#define SWIFT_SILOPTIMIZER_UTILS_INSTOPTUTILS_H + +#include "swift/SIL/SILBuilder.h" +#include "swift/SIL/SILInstruction.h" +#include "swift/SILOptimizer/Analysis/ARCAnalysis.h" +#include "swift/SILOptimizer/Analysis/ClassHierarchyAnalysis.h" +#include "swift/SILOptimizer/Analysis/EpilogueARCAnalysis.h" +#include "swift/SILOptimizer/Analysis/SimplifyInstruction.h" +#include "llvm/ADT/SmallPtrSet.h" +#include +#include + +namespace swift { + +class DominanceInfo; +template class NullablePtr; + +/// Transform a Use Range (Operand*) into a User Range (SILInstruction*) +using UserTransform = std::function; +using ValueBaseUserRange = + TransformRange, UserTransform>; + +inline ValueBaseUserRange +makeUserRange(iterator_range range) { + auto toUser = [](Operand *operand) { return operand->getUser(); }; + return makeTransformRange(makeIteratorRange(range.begin(), range.end()), + UserTransform(toUser)); +} + +using DeadInstructionSet = llvm::SmallSetVector; + +/// Create a retain of \p Ptr before the \p InsertPt. +NullablePtr createIncrementBefore(SILValue ptr, + SILInstruction *insertpt); + +/// Create a release of \p Ptr before the \p InsertPt. +NullablePtr createDecrementBefore(SILValue ptr, + SILInstruction *insertpt); + +/// For each of the given instructions, if they are dead delete them +/// along with their dead operands. +/// +/// \param inst The ArrayRef of instructions to be deleted. +/// \param force If Force is set, don't check if the top level instructions +/// are considered dead - delete them regardless. +/// \param callback a callback called whenever an instruction is deleted. +void recursivelyDeleteTriviallyDeadInstructions( + ArrayRef inst, bool force = false, + llvm::function_ref callback = [](SILInstruction *) { + }); + +/// If the given instruction is dead, delete it along with its dead +/// operands. +/// +/// \param inst The instruction to be deleted. +/// \param force If Force is set, don't check if the top level instruction is +/// considered dead - delete it regardless. +/// \param callback a callback called whenever an instruction is deleted. +void recursivelyDeleteTriviallyDeadInstructions( + SILInstruction *inst, bool force = false, + llvm::function_ref callback = [](SILInstruction *) { + }); + +/// Perform a fast local check to see if the instruction is dead. +/// +/// This routine only examines the state of the instruction at hand. +bool isInstructionTriviallyDead(SILInstruction *inst); + +/// Return true if this is a release instruction that's not going to +/// free the object. +bool isIntermediateRelease(SILInstruction *inst, EpilogueARCFunctionInfo *erfi); + +/// Recursively collect all the uses and transitive uses of the +/// instruction. +void collectUsesOfValue(SILValue V, + llvm::SmallPtrSetImpl &Insts); + +/// Recursively erase all of the uses of the instruction (but not the +/// instruction itself) +void eraseUsesOfInstruction( + SILInstruction *inst, llvm::function_ref callback = + [](SILInstruction *) {}); + +/// Recursively erase all of the uses of the value (but not the +/// value itself) +void eraseUsesOfValue(SILValue value); + +FullApplySite findApplyFromDevirtualizedResult(SILValue value); + +/// Cast a value into the expected, ABI compatible type if necessary. +/// This may happen e.g. when: +/// - a type of the return value is a subclass of the expected return type. +/// - actual return type and expected return type differ in optionality. +/// - both types are tuple-types and some of the elements need to be casted. +SILValue castValueToABICompatibleType(SILBuilder *builder, SILLocation Loc, + SILValue value, SILType srcTy, + SILType destTy); +/// Peek through trivial Enum initialization, typically for pointless +/// Optionals. +/// +/// The returned InitEnumDataAddr dominates the given +/// UncheckedTakeEnumDataAddrInst. +InitEnumDataAddrInst * +findInitAddressForTrivialEnum(UncheckedTakeEnumDataAddrInst *utedai); + +/// Returns a project_box if it is the next instruction after \p ABI and +/// and has \p ABI as operand. Otherwise it creates a new project_box right +/// after \p ABI and returns it. +ProjectBoxInst *getOrCreateProjectBox(AllocBoxInst *abi, unsigned index); + +/// Return true if any call inside the given function may bind dynamic +/// 'Self' to a generic argument of the callee. +bool mayBindDynamicSelf(SILFunction *f); + +/// Check whether the \p addr is an address of a tail-allocated array element. +bool isAddressOfArrayElement(SILValue addr); + +/// Move an ApplyInst's FuncRef so that it dominates the call site. +void placeFuncRef(ApplyInst *ai, DominanceInfo *dt); + +/// Add an argument, \p val, to the branch-edge that is pointing into +/// block \p Dest. Return a new instruction and do not erase the old +/// instruction. +TermInst *addArgumentToBranch(SILValue val, SILBasicBlock *dest, + TermInst *branch); + +/// Get the linkage to be used for specializations of a function with +/// the given linkage. +SILLinkage getSpecializedLinkage(SILFunction *f, SILLinkage linkage); + +/// Tries to optimize a given apply instruction if it is a concatenation of +/// string literals. Returns a new instruction if optimization was possible. +SingleValueInstruction *tryToConcatenateStrings(ApplyInst *ai, + SILBuilder &builder); + +/// Tries to perform jump-threading on all checked_cast_br instruction in +/// function \p Fn. +bool tryCheckedCastBrJumpThreading( + SILFunction *fn, DominanceInfo *dt, + SmallVectorImpl &blocksForWorklist); + +/// A structure containing callbacks that are called when an instruction is +/// removed or added. +struct InstModCallbacks { + using CallbackTy = std::function; + CallbackTy deleteInst = [](SILInstruction *inst) { inst->eraseFromParent(); }; + CallbackTy createdNewInst = [](SILInstruction *) {}; + + InstModCallbacks(CallbackTy deleteInst, CallbackTy createdNewInst) + : deleteInst(deleteInst), createdNewInst(createdNewInst) {} + InstModCallbacks() = default; + ~InstModCallbacks() = default; + InstModCallbacks(const InstModCallbacks &) = default; + InstModCallbacks(InstModCallbacks &&) = default; +}; + +/// If Closure is a partial_apply or thin_to_thick_function with only local +/// ref count users and a set of post-dominating releases: +/// +/// 1. Remove all ref count operations and the closure. +/// 2. Add each one of the last release locations insert releases for the +/// captured args if we have a partial_apply. +/// +/// In the future this should be extended to be less conservative with users. +bool tryDeleteDeadClosure(SingleValueInstruction *closure, + InstModCallbacks callbacks = InstModCallbacks()); + +/// Given a SILValue argument to a partial apply \p Arg and the associated +/// parameter info for that argument, perform the necessary cleanups to Arg when +/// one is attempting to delete the partial apply. +void releasePartialApplyCapturedArg( + SILBuilder &builder, SILLocation loc, SILValue arg, + SILParameterInfo paramInfo, + InstModCallbacks callbacks = InstModCallbacks()); + +/// Insert destroys of captured arguments of partial_apply [stack]. +void insertDestroyOfCapturedArguments( + PartialApplyInst *pai, SILBuilder &builder, + llvm::function_ref shouldInsertDestroy = + [](SILValue arg) -> bool { return true; }); + +/// This iterator 'looks through' one level of builtin expect users exposing all +/// users of the looked through builtin expect instruction i.e it presents a +/// view that shows all users as if there were no builtin expect instructions +/// interposed. +class IgnoreExpectUseIterator + : public std::iterator { + ValueBaseUseIterator origUseChain; + ValueBaseUseIterator currentIter; + + static BuiltinInst *isExpect(Operand *use) { + if (auto *bi = dyn_cast(use->getUser())) + if (bi->getIntrinsicInfo().ID == llvm::Intrinsic::expect) + return bi; + return nullptr; + } + + // Advance through expect users to their users until we encounter a user that + // is not an expect. + void advanceThroughExpects() { + while (currentIter == origUseChain + && currentIter != ValueBaseUseIterator(nullptr)) { + auto *Expect = isExpect(*currentIter); + if (!Expect) + return; + currentIter = Expect->use_begin(); + // Expect with no users advance to next item in original use chain. + if (currentIter == Expect->use_end()) + currentIter = ++origUseChain; + } + } + +public: + IgnoreExpectUseIterator(ValueBase *value) + : origUseChain(value->use_begin()), currentIter(value->use_begin()) { + advanceThroughExpects(); + } + + IgnoreExpectUseIterator() = default; + + Operand *operator*() const { return *currentIter; } + Operand *operator->() const { return *currentIter; } + SILInstruction *getUser() const { return currentIter->getUser(); } + + IgnoreExpectUseIterator &operator++() { + assert(**this && "increment past end()!"); + if (origUseChain == currentIter) { + // Use chain of the original value. + ++origUseChain; + ++currentIter; + // Ignore expects. + advanceThroughExpects(); + } else { + // Use chain of an expect. + ++currentIter; + if (currentIter == ValueBaseUseIterator(nullptr)) { + // At the end of the use chain of an expect. + currentIter = ++origUseChain; + advanceThroughExpects(); + } + } + return *this; + } + + IgnoreExpectUseIterator operator++(int unused) { + IgnoreExpectUseIterator copy = *this; + ++*this; + return copy; + } + friend bool operator==(IgnoreExpectUseIterator lhs, + IgnoreExpectUseIterator rhs) { + return lhs.currentIter == rhs.currentIter; + } + friend bool operator!=(IgnoreExpectUseIterator lhs, + IgnoreExpectUseIterator rhs) { + return !(lhs == rhs); + } +}; + +inline iterator_range +ignore_expect_uses(ValueBase *value) { + return make_range(IgnoreExpectUseIterator(value), IgnoreExpectUseIterator()); +} + +/// Run simplifyInstruction() on all of the instruction I's users if they only +/// have one result (since simplifyInstruction assumes that). Replace all uses +/// of the user with its simplification of we succeed. Returns true if we +/// succeed and false otherwise. +/// +/// An example of how this is useful is in cases where one is splitting up an +/// aggregate and reforming it, the reformed aggregate may have extract +/// operations from it. These can be simplified and removed. +bool simplifyUsers(SingleValueInstruction *inst); + +/// True if a type can be expanded +/// without a significant increase to code size. +bool shouldExpand(SILModule &module, SILType ty); + +/// Check if the value of value is computed by means of a simple initialization. +/// Store the actual SILValue into \p Val and the reversed list of instructions +/// initializing it in \p Insns. +/// The check is performed by recursively walking the computation of the +/// SIL value being analyzed. +bool analyzeStaticInitializer(SILValue value, + SmallVectorImpl &insns); + +/// Returns true if the below operation will succeed. +bool canReplaceLoadSequence(SILInstruction *inst); + +/// Replace load sequence which may contain +/// a chain of struct_element_addr followed by a load. +/// The sequence is traversed inside out, i.e. +/// starting with the innermost struct_element_addr +void replaceLoadSequence(SILInstruction *inst, SILValue value); + +/// Do we have enough information to determine all callees that could +/// be reached by calling the function represented by Decl? +bool calleesAreStaticallyKnowable(SILModule &module, SILDeclRef decl); + +// Attempt to get the instance for , whose static type is the same as +// its exact dynamic type, returning a null SILValue() if we cannot find it. +// The information that a static type is the same as the exact dynamic, +// can be derived e.g.: +// - from a constructor or +// - from a successful outcome of a checked_cast_br [exact] instruction. +SILValue getInstanceWithExactDynamicType(SILValue instance, + ClassHierarchyAnalysis *cha); + +/// Try to determine the exact dynamic type of an object. +/// returns the exact dynamic type of the object, or an empty type if the exact +/// type could not be determined. +SILType getExactDynamicType(SILValue instance, ClassHierarchyAnalysis *cha, + bool forUnderlyingObject = false); + +/// Try to statically determine the exact dynamic type of the underlying object. +/// returns the exact dynamic type of the underlying object, or an empty SILType +/// if the exact type could not be determined. +SILType getExactDynamicTypeOfUnderlyingObject(SILValue instance, + ClassHierarchyAnalysis *cha); + +// Move only data structure that is the result of findLocalApplySite. +/// +/// NOTE: Generally it is not suggested to have move only types that contain +/// small vectors. Since our small vectors contain one element or a std::vector +/// like data structure , this is ok since we will either just copy the single +/// element when we do the move or perform a move of the vector type. +struct LLVM_LIBRARY_VISIBILITY FindLocalApplySitesResult { + /// Contains the list of local non fully applied partial apply sites that we + /// found. + SmallVector partialApplySites; + + /// Contains the list of full apply sites that we found. + SmallVector fullApplySites; + + /// Set to true if the function_ref escapes into a use that our analysis does + /// not understand. Set to false if we found a use that had an actual + /// escape. Set to None if we did not find any call sites, but also didn't + /// find any "escaping uses" as well. + /// + /// The none case is so that we can distinguish in between saying that a value + /// did escape and saying that we did not find any conservative information. + bool escapes; + + FindLocalApplySitesResult() = default; + FindLocalApplySitesResult(const FindLocalApplySitesResult &) = delete; + FindLocalApplySitesResult & + operator=(const FindLocalApplySitesResult &) = delete; + FindLocalApplySitesResult(FindLocalApplySitesResult &&) = default; + FindLocalApplySitesResult &operator=(FindLocalApplySitesResult &&) = default; + ~FindLocalApplySitesResult() = default; + + /// Treat this function ref as escaping only if we found an actual user we + /// didn't understand. Do not treat it as escaping if we did not find any + /// users at all. + bool isEscaping() const { return escapes; } +}; + +/// Returns .some(FindLocalApplySitesResult) if we found any interesting +/// information for the given function_ref. Otherwise, returns None. +/// +/// We consider "interesting information" to mean inclusively that: +/// +/// 1. We discovered that the function_ref never escapes. +/// 2. We were able to find either a partial apply or a full apply site. +Optional +findLocalApplySites(FunctionRefBaseInst *fri); + +} // end namespace swift + +#endif diff --git a/include/swift/SILOptimizer/Utils/LoadStoreOptUtils.h b/include/swift/SILOptimizer/Utils/LoadStoreOptUtils.h index 5613af10681..f11fbcd3042 100644 --- a/include/swift/SILOptimizer/Utils/LoadStoreOptUtils.h +++ b/include/swift/SILOptimizer/Utils/LoadStoreOptUtils.h @@ -33,7 +33,7 @@ #include "swift/SILOptimizer/Analysis/EscapeAnalysis.h" #include "swift/SILOptimizer/Analysis/TypeExpansionAnalysis.h" #include "swift/SILOptimizer/Analysis/ValueTracking.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/Hashing.h" diff --git a/include/swift/SILOptimizer/Utils/Local.h b/include/swift/SILOptimizer/Utils/Local.h deleted file mode 100644 index c7a33d8afa0..00000000000 --- a/include/swift/SILOptimizer/Utils/Local.h +++ /dev/null @@ -1,684 +0,0 @@ -//===--- Local.h - Local SIL transformations. -------------------*- C++ -*-===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// - -#ifndef SWIFT_SILOPTIMIZER_UTILS_LOCAL_H -#define SWIFT_SILOPTIMIZER_UTILS_LOCAL_H - -#include "swift/SILOptimizer/Analysis/ARCAnalysis.h" -#include "swift/SILOptimizer/Analysis/EpilogueARCAnalysis.h" -#include "swift/SILOptimizer/Analysis/ClassHierarchyAnalysis.h" -#include "swift/SILOptimizer/Analysis/SimplifyInstruction.h" -#include "swift/SIL/SILInstruction.h" -#include "swift/SIL/SILBuilder.h" -#include "swift/SIL/SILCloner.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/Support/Allocator.h" -#include -#include - -namespace swift { - -class DominanceInfo; -template class NullablePtr; - -/// Transform a Use Range (Operand*) into a User Range (SILInstruction*) -using UserTransform = std::function; -using ValueBaseUserRange = - TransformRange, UserTransform>; - -inline ValueBaseUserRange makeUserRange( - iterator_range R) { - auto toUser = [](Operand *O) { return O->getUser(); }; - return makeTransformRange(makeIteratorRange(R.begin(), R.end()), - UserTransform(toUser)); -} - -using DeadInstructionSet = llvm::SmallSetVector; - -/// Create a retain of \p Ptr before the \p InsertPt. -NullablePtr createIncrementBefore(SILValue Ptr, - SILInstruction *InsertPt); - -/// Create a release of \p Ptr before the \p InsertPt. -NullablePtr createDecrementBefore(SILValue Ptr, - SILInstruction *InsertPt); - -/// For each of the given instructions, if they are dead delete them -/// along with their dead operands. -/// -/// \param I The ArrayRef of instructions to be deleted. -/// \param Force If Force is set, don't check if the top level instructions -/// are considered dead - delete them regardless. -/// \param C a callback called whenever an instruction is deleted. -void -recursivelyDeleteTriviallyDeadInstructions( - ArrayRef I, bool Force = false, - llvm::function_ref C = [](SILInstruction *){}); - -/// If the given instruction is dead, delete it along with its dead -/// operands. -/// -/// \param I The instruction to be deleted. -/// \param Force If Force is set, don't check if the top level instruction is -/// considered dead - delete it regardless. -/// \param C a callback called whenever an instruction is deleted. -void recursivelyDeleteTriviallyDeadInstructions( - SILInstruction *I, bool Force = false, - llvm::function_ref C = [](SILInstruction *) {}); - -/// Perform a fast local check to see if the instruction is dead. -/// -/// This routine only examines the state of the instruction at hand. -bool isInstructionTriviallyDead(SILInstruction *I); - -/// Return true if this is a release instruction that's not going to -/// free the object. -bool isIntermediateRelease(SILInstruction *I, EpilogueARCFunctionInfo *ERFI); - -/// Recursively collect all the uses and transitive uses of the -/// instruction. -void -collectUsesOfValue(SILValue V, llvm::SmallPtrSetImpl &Insts); - -/// Recursively erase all of the uses of the instruction (but not the -/// instruction itself) -void eraseUsesOfInstruction( - SILInstruction *Inst, - llvm::function_ref C = [](SILInstruction *){}); - -/// Recursively erase all of the uses of the value (but not the -/// value itself) -void eraseUsesOfValue(SILValue V); - -FullApplySite findApplyFromDevirtualizedResult(SILValue value); - -/// Cast a value into the expected, ABI compatible type if necessary. -/// This may happen e.g. when: -/// - a type of the return value is a subclass of the expected return type. -/// - actual return type and expected return type differ in optionality. -/// - both types are tuple-types and some of the elements need to be casted. -SILValue castValueToABICompatibleType(SILBuilder *B, SILLocation Loc, - SILValue Value, - SILType SrcTy, - SILType DestTy); -/// Peek through trivial Enum initialization, typically for pointless -/// Optionals. -/// -/// The returned InitEnumDataAddr dominates the given -/// UncheckedTakeEnumDataAddrInst. -InitEnumDataAddrInst * -findInitAddressForTrivialEnum(UncheckedTakeEnumDataAddrInst *UTEDAI); - -/// Returns a project_box if it is the next instruction after \p ABI and -/// and has \p ABI as operand. Otherwise it creates a new project_box right -/// after \p ABI and returns it. -ProjectBoxInst *getOrCreateProjectBox(AllocBoxInst *ABI, unsigned Index); - -/// Return true if any call inside the given function may bind dynamic -/// 'Self' to a generic argument of the callee. -bool mayBindDynamicSelf(SILFunction *F); - -/// Check whether the \p addr is an address of a tail-allocated array element. -bool isAddressOfArrayElement(SILValue addr); - -/// Move an ApplyInst's FuncRef so that it dominates the call site. -void placeFuncRef(ApplyInst *AI, DominanceInfo *DT); - -/// Add an argument, \p val, to the branch-edge that is pointing into -/// block \p Dest. Return a new instruction and do not erase the old -/// instruction. -TermInst *addArgumentToBranch(SILValue Val, SILBasicBlock *Dest, - TermInst *Branch); - -/// Handle the mechanical aspects of removing an unreachable block. -void removeDeadBlock(SILBasicBlock *BB); - -/// Remove all instructions in the body of \p BB in safe manner by using -/// undef. -void clearBlockBody(SILBasicBlock *BB); - -/// Get the linkage to be used for specializations of a function with -/// the given linkage. -SILLinkage getSpecializedLinkage(SILFunction *F, SILLinkage L); - -/// Tries to optimize a given apply instruction if it is a concatenation of -/// string literals. Returns a new instruction if optimization was possible. -SingleValueInstruction *tryToConcatenateStrings(ApplyInst *AI, SILBuilder &B); - -/// Tries to perform jump-threading on all checked_cast_br instruction in -/// function \p Fn. -bool tryCheckedCastBrJumpThreading(SILFunction *Fn, DominanceInfo *DT, - SmallVectorImpl &BlocksForWorklist); - -/// A structure containing callbacks that are called when an instruction is -/// removed or added. -struct InstModCallbacks { - using CallbackTy = std::function; - CallbackTy DeleteInst = [](SILInstruction *I) { - I->eraseFromParent(); - }; - CallbackTy CreatedNewInst = [](SILInstruction *){}; - - InstModCallbacks(CallbackTy DeleteInst, CallbackTy CreatedNewInst) - : DeleteInst(DeleteInst), CreatedNewInst(CreatedNewInst) {} - InstModCallbacks() = default; - ~InstModCallbacks() = default; - InstModCallbacks(const InstModCallbacks &) = default; - InstModCallbacks(InstModCallbacks &&) = default; -}; - -/// If Closure is a partial_apply or thin_to_thick_function with only local -/// ref count users and a set of post-dominating releases: -/// -/// 1. Remove all ref count operations and the closure. -/// 2. Add each one of the last release locations insert releases for the -/// captured args if we have a partial_apply. -/// -/// In the future this should be extended to be less conservative with users. -bool -tryDeleteDeadClosure(SingleValueInstruction *Closure, - InstModCallbacks Callbacks = InstModCallbacks()); - -/// Given a SILValue argument to a partial apply \p Arg and the associated -/// parameter info for that argument, perform the necessary cleanups to Arg when -/// one is attempting to delete the partial apply. -void releasePartialApplyCapturedArg( - SILBuilder &Builder, SILLocation Loc, SILValue Arg, SILParameterInfo PInfo, - InstModCallbacks Callbacks = InstModCallbacks()); - -/// Insert destroys of captured arguments of partial_apply [stack]. -void insertDestroyOfCapturedArguments( - PartialApplyInst *PAI, SILBuilder &B, - llvm::function_ref shouldInsertDestroy = - [](SILValue arg) -> bool { return true; }); - -/// This computes the lifetime of a single SILValue. -/// -/// This does not compute a set of jointly postdominating use points. Instead it -/// assumes that the value's existing uses already jointly postdominate the -/// definition. This makes sense for values that are returned +1 from an -/// instruction, like partial_apply, and therefore must be released on all paths -/// via strong_release or apply. -class ValueLifetimeAnalysis { -public: - - /// The lifetime frontier for the value. It is the list of instructions - /// following the last uses of the value. All the frontier instructions - /// end the value's lifetime. - typedef llvm::SmallVector Frontier; - - /// Constructor for the value \p Def with a specific set of users of Def's - /// users. - ValueLifetimeAnalysis(SILInstruction *Def, ArrayRef UserList) : - DefValue(Def), UserSet(UserList.begin(), UserList.end()) { - propagateLiveness(); - } - - /// Constructor for the value \p Def considering all the value's uses. - ValueLifetimeAnalysis(SILInstruction *Def) : DefValue(Def) { - for (auto result : Def->getResults()) { - for (Operand *op : result->getUses()) { - UserSet.insert(op->getUser()); - } - } - propagateLiveness(); - } - - enum Mode { - /// Don't split critical edges if the frontier instructions are located on - /// a critical edges. Instead fail. - DontModifyCFG, - - /// Split critical edges if the frontier instructions are located on - /// a critical edges. - AllowToModifyCFG, - - /// Require that all users must commonly post-dominate the definition. In - /// other words: All paths from the definition to the function exit must - /// contain at least one use. Fail if this is not the case. - UsersMustPostDomDef - }; - - /// Computes and returns the lifetime frontier for the value in \p Fr. - /// - /// Returns true if all instructions in the frontier could be found in - /// non-critical edges. - /// Returns false if some frontier instructions are located on critical edges. - /// In this case, if \p mode is AllowToModifyCFG, those critical edges are - /// split, otherwise nothing is done and the returned \p Fr is not valid. - /// - /// If \p deadEndBlocks is provided, all dead-end blocks are ignored. This - /// prevents unreachable-blocks to be included in the frontier. - bool computeFrontier(Frontier &Fr, Mode mode, - DeadEndBlocks *DEBlocks = nullptr); - - /// Returns true if the instruction \p Inst is located within the value's - /// lifetime. - /// It is assumed that \p Inst is located after the value's definition. - bool isWithinLifetime(SILInstruction *Inst); - - /// Returns true if the value is alive at the begin of block \p BB. - bool isAliveAtBeginOfBlock(SILBasicBlock *BB) { - return LiveBlocks.count(BB) && BB != DefValue->getParent(); - } - - /// Checks if there is a dealloc_ref inside the value's live range. - bool containsDeallocRef(const Frontier &Frontier); - - /// For debug dumping. - void dump() const; - -private: - - /// The value. - SILInstruction *DefValue; - - /// The set of blocks where the value is live. - llvm::SmallSetVector LiveBlocks; - - /// The set of instructions where the value is used, or the users-list - /// provided with the constructor. - llvm::SmallPtrSet UserSet; - - /// Propagates the liveness information up the control flow graph. - void propagateLiveness(); - - /// Returns the last use of the value in the live block \p BB. - SILInstruction *findLastUserInBlock(SILBasicBlock *BB); -}; - -/// Clone a single basic block and any required successor edges within the same -/// function. -class BasicBlockCloner : public SILCloner { - using SuperTy = SILCloner; - friend class SILCloner; - -protected: - /// The original block to be cloned. - SILBasicBlock *origBB; - -public: - /// An ordered list of old to new available value pairs. - /// - /// updateSSAAfterCloning() expects this public field to hold values that may - /// be remapped in the cloned block and live out. - SmallVector, 16> AvailVals; - - // Clone blocks starting at `origBB`, within the same function. - BasicBlockCloner(SILBasicBlock *origBB) - : SILCloner(*origBB->getParent()), origBB(origBB) {} - - void cloneBlock(SILBasicBlock *insertAfterBB = nullptr) { - SmallVector successorBBs; - successorBBs.reserve(origBB->getSuccessors().size()); - llvm::copy(origBB->getSuccessors(), std::back_inserter(successorBBs)); - cloneReachableBlocks(origBB, successorBBs, insertAfterBB); - } - - /// Clone the given branch instruction's destination block, splitting - /// its successors, and rewrite the branch instruction. - void cloneBranchTarget(BranchInst *BI) { - assert(origBB == BI->getDestBB()); - - cloneBlock(/*insertAfter*/BI->getParent()); - - SILBuilderWithScope(BI).createBranch(BI->getLoc(), getNewBB(), - BI->getArgs()); - BI->eraseFromParent(); - } - - /// Get the newly cloned block corresponding to `origBB`. - SILBasicBlock *getNewBB() { - return remapBasicBlock(origBB); - } - - /// Call this after processing all instructions to fix the control flow - /// graph. The branch cloner may have left critical edges. - bool splitCriticalEdges(DominanceInfo *DT, SILLoopInfo *LI); - -protected: - // MARK: CRTP overrides. - - /// Override getMappedValue to allow values defined outside the block to be - /// cloned to be reused in the newly cloned block. - SILValue getMappedValue(SILValue Value) { - if (auto SI = Value->getDefiningInstruction()) { - if (!isBlockCloned(SI->getParent())) - return Value; - } else if (auto BBArg = dyn_cast(Value)) { - if (!isBlockCloned(BBArg->getParent())) - return Value; - } else { - assert(isa(Value) && "Unexpected Value kind"); - return Value; - } - // `value` is not defined outside the cloned block, so consult the cloner's - // map of cloned values. - return SuperTy::getMappedValue(Value); - } - - void mapValue(SILValue origValue, SILValue mappedValue) { - SuperTy::mapValue(origValue, mappedValue); - AvailVals.emplace_back(origValue, mappedValue); - } -}; - -/// Sink address projections to their out-of-block uses. This is -/// required after cloning a block and before calling -/// updateSSAAfterCloning to avoid address-type phis. -/// -/// This clones address projections at their use points, but does not -/// mutate the block containing the projections. -class SinkAddressProjections { - // Projections ordered from last to first in the chain. - SmallVector projections; - SmallSetVector inBlockDefs; - -public: - /// Check for an address projection chain ending at \p inst. Return true if - /// the given instruction is successfully analyzed. - /// - /// If \p inst does not produce an address, then return - /// true. getInBlockDefs() will contain \p inst if any of its - /// (non-address) values are used outside its block. - /// - /// If \p inst does produce an address, return true only of the - /// chain of address projections within this block is clonable at - /// their use sites. getInBlockDefs will return all non-address - /// operands in the chain that are also defined in this block. These - /// may require phis after cloning the projections. - bool analyzeAddressProjections(SILInstruction *inst); - - /// After analyzing projections, returns the list of (non-address) values - /// defined in the same block as the projections which will have uses outside - /// the block after cloning. - ArrayRef getInBlockDefs() const { - return inBlockDefs.getArrayRef(); - } - /// Clone the chain of projections at their use sites. - /// - /// Return true if anything was done. - /// - /// getInBlockProjectionOperandValues() can be called before or after cloning. - bool cloneProjections(); -}; - -/// Helper function to perform SSA updates in case of jump threading. -void updateSSAAfterCloning(BasicBlockCloner &Cloner, SILBasicBlock *SrcBB, - SILBasicBlock *DestBB); - -// Helper class that provides a callback that can be used in -// inliners/cloners for collecting new call sites. -class CloneCollector { -public: - typedef std::pair value_type; - typedef std::function CallbackType; - typedef std::function FilterType; - -private: - FilterType Filter; - - // Pairs of collected instructions; (new, old) - llvm::SmallVector InstructionPairs; - - void collect(SILInstruction *Old, SILInstruction *New) { - if (Filter(New)) - InstructionPairs.push_back(std::make_pair(New, Old)); - } - -public: - CloneCollector(FilterType Filter) : Filter(Filter) {} - - CallbackType getCallback() { - return std::bind(&CloneCollector::collect, this, std::placeholders::_1, - std::placeholders::_2); - } - - llvm::SmallVectorImpl &getInstructionPairs() { - return InstructionPairs; - } -}; - -/// This iterator 'looks through' one level of builtin expect users exposing all -/// users of the looked through builtin expect instruction i.e it presents a -/// view that shows all users as if there were no builtin expect instructions -/// interposed. -class IgnoreExpectUseIterator - : public std::iterator { - ValueBaseUseIterator OrigUseChain; - ValueBaseUseIterator CurrentIter; - - static BuiltinInst *isExpect(Operand *Use) { - if (auto *BI = dyn_cast(Use->getUser())) - if (BI->getIntrinsicInfo().ID == llvm::Intrinsic::expect) - return BI; - return nullptr; - } - - // Advance through expect users to their users until we encounter a user that - // is not an expect. - void advanceThroughExpects() { - while (CurrentIter == OrigUseChain && - CurrentIter != ValueBaseUseIterator(nullptr)) { - auto *Expect = isExpect(*CurrentIter); - if (!Expect) return; - CurrentIter = Expect->use_begin(); - // Expect with no users advance to next item in original use chain. - if (CurrentIter == Expect->use_end()) - CurrentIter = ++OrigUseChain; - } - } - -public: - IgnoreExpectUseIterator(ValueBase *V) - : OrigUseChain(V->use_begin()), CurrentIter(V->use_begin()) { - advanceThroughExpects(); - } - - IgnoreExpectUseIterator() = default; - - Operand *operator*() const { return *CurrentIter; } - Operand *operator->() const { return *CurrentIter; } - SILInstruction *getUser() const { return CurrentIter->getUser(); } - - IgnoreExpectUseIterator &operator++() { - assert(**this && "increment past end()!"); - if (OrigUseChain == CurrentIter) { - // Use chain of the original value. - ++OrigUseChain; - ++CurrentIter; - // Ignore expects. - advanceThroughExpects(); - } else { - // Use chain of an expect. - ++CurrentIter; - if (CurrentIter == ValueBaseUseIterator(nullptr)) { - // At the end of the use chain of an expect. - CurrentIter = ++OrigUseChain; - advanceThroughExpects(); - } - } - return *this; - } - - IgnoreExpectUseIterator operator++(int unused) { - IgnoreExpectUseIterator Copy = *this; - ++*this; - return Copy; - } - friend bool operator==(IgnoreExpectUseIterator lhs, - IgnoreExpectUseIterator rhs) { - return lhs.CurrentIter == rhs.CurrentIter; - } - friend bool operator!=(IgnoreExpectUseIterator lhs, - IgnoreExpectUseIterator rhs) { - return !(lhs == rhs); - } -}; - -inline iterator_range -ignore_expect_uses(ValueBase *V) { - return make_range(IgnoreExpectUseIterator(V), - IgnoreExpectUseIterator()); -} - -/// Run simplifyInstruction() on all of the instruction I's users if they only -/// have one result (since simplifyInstruction assumes that). Replace all uses -/// of the user with its simplification of we succeed. Returns true if we -/// succeed and false otherwise. -/// -/// An example of how this is useful is in cases where one is splitting up an -/// aggregate and reforming it, the reformed aggregate may have extract -/// operations from it. These can be simplified and removed. -bool simplifyUsers(SingleValueInstruction *I); - -/// True if a type can be expanded -/// without a significant increase to code size. -bool shouldExpand(SILModule &Module, SILType Ty); - -/// Check if the value of V is computed by means of a simple initialization. -/// Store the actual SILValue into \p Val and the reversed list of instructions -/// initializing it in \p Insns. -/// The check is performed by recursively walking the computation of the -/// SIL value being analyzed. -bool analyzeStaticInitializer(SILValue V, - SmallVectorImpl &Insns); - -/// Returns true if the below operation will succeed. -bool canReplaceLoadSequence(SILInstruction *I); - -/// Replace load sequence which may contain -/// a chain of struct_element_addr followed by a load. -/// The sequence is traversed inside out, i.e. -/// starting with the innermost struct_element_addr -void replaceLoadSequence(SILInstruction *I, - SILValue Value); - - -/// Do we have enough information to determine all callees that could -/// be reached by calling the function represented by Decl? -bool calleesAreStaticallyKnowable(SILModule &M, SILDeclRef Decl); - -// Attempt to get the instance for S, whose static type is the same as -// its exact dynamic type, returning a null SILValue() if we cannot find it. -// The information that a static type is the same as the exact dynamic, -// can be derived e.g.: -// - from a constructor or -// - from a successful outcome of a checked_cast_br [exact] instruction. -SILValue getInstanceWithExactDynamicType(SILValue S, - ClassHierarchyAnalysis *CHA); - -/// Try to determine the exact dynamic type of an object. -/// returns the exact dynamic type of the object, or an empty type if the exact -/// type could not be determined. -SILType getExactDynamicType(SILValue S, - ClassHierarchyAnalysis *CHA, - bool ForUnderlyingObject = false); - -/// Try to statically determine the exact dynamic type of the underlying object. -/// returns the exact dynamic type of the underlying object, or an empty SILType -/// if the exact type could not be determined. -SILType getExactDynamicTypeOfUnderlyingObject(SILValue S, - ClassHierarchyAnalysis *CHA); - -/// Utility class for cloning init values into the static initializer of a -/// SILGlobalVariable. -class StaticInitCloner : public SILCloner { - friend class SILInstructionVisitor; - friend class SILCloner; - - /// The number of not yet cloned operands for each instruction. - llvm::DenseMap NumOpsToClone; - - /// List of instructions for which all operands are already cloned (or which - /// don't have any operands). - llvm::SmallVector ReadyToClone; - -public: - StaticInitCloner(SILGlobalVariable *GVar) - : SILCloner(GVar) { } - - /// Add \p InitVal and all its operands (transitively) for cloning. - /// - /// Note: all init values must are added, before calling clone(). - void add(SILInstruction *InitVal); - - /// Clone \p InitVal and all its operands into the initializer of the - /// SILGlobalVariable. - /// - /// \return Returns the cloned instruction in the SILGlobalVariable. - SingleValueInstruction *clone(SingleValueInstruction *InitVal); - - /// Convenience function to clone a single \p InitVal. - static void appendToInitializer(SILGlobalVariable *GVar, - SingleValueInstruction *InitVal) { - StaticInitCloner Cloner(GVar); - Cloner.add(InitVal); - Cloner.clone(InitVal); - } - -protected: - SILLocation remapLocation(SILLocation Loc) { - return ArtificialUnreachableLocation(); - } -}; - -/// Move only data structure that is the result of findLocalApplySite. -/// -/// NOTE: Generally it is not suggested to have move only types that contain -/// small vectors. Since our small vectors contain one element or a std::vector -/// like data structure , this is ok since we will either just copy the single -/// element when we do the move or perform a move of the vector type. -struct LLVM_LIBRARY_VISIBILITY FindLocalApplySitesResult { - /// Contains the list of local non fully applied partial apply sites that we - /// found. - SmallVector partialApplySites; - - /// Contains the list of full apply sites that we found. - SmallVector fullApplySites; - - /// Set to true if the function_ref escapes into a use that our analysis does - /// not understand. Set to false if we found a use that had an actual - /// escape. Set to None if we did not find any call sites, but also didn't - /// find any "escaping uses" as well. - /// - /// The none case is so that we can distinguish in between saying that a value - /// did escape and saying that we did not find any conservative information. - bool escapes; - - FindLocalApplySitesResult() = default; - FindLocalApplySitesResult(const FindLocalApplySitesResult &) = delete; - FindLocalApplySitesResult & - operator=(const FindLocalApplySitesResult &) = delete; - FindLocalApplySitesResult(FindLocalApplySitesResult &&) = default; - FindLocalApplySitesResult &operator=(FindLocalApplySitesResult &&) = default; - ~FindLocalApplySitesResult() = default; - - /// Treat this function ref as escaping only if we found an actual user we - /// didn't understand. Do not treat it as escaping if we did not find any - /// users at all. - bool isEscaping() const { return escapes; } -}; - -/// Returns .some(FindLocalApplySitesResult) if we found any interesting -/// information for the given function_ref. Otherwise, returns None. -/// -/// We consider "interesting information" to mean inclusively that: -/// -/// 1. We discovered that the function_ref never escapes. -/// 2. We were able to find either a partial apply or a full apply site. -Optional -findLocalApplySites(FunctionRefBaseInst *FRI); - -} // end namespace swift - -#endif diff --git a/include/swift/SILOptimizer/Utils/ValueLifetime.h b/include/swift/SILOptimizer/Utils/ValueLifetime.h new file mode 100644 index 00000000000..85be58077e6 --- /dev/null +++ b/include/swift/SILOptimizer/Utils/ValueLifetime.h @@ -0,0 +1,125 @@ +//===--- ValueLifetime.h - ValueLifetimeAnalysis ----------------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +/// +/// Utilities used by the SILOptimizer for SSA analysis and update. +/// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_SILOPTIMIZER_UTILS_CFG_H +#define SWIFT_SILOPTIMIZER_UTILS_CFG_H + +#include "swift/SIL/SILInstruction.h" +#include "swift/SIL/SILBuilder.h" + +namespace swift { + +/// This computes the lifetime of a single SILValue. +/// +/// This does not compute a set of jointly postdominating use points. Instead it +/// assumes that the value's existing uses already jointly postdominate the +/// definition. This makes sense for values that are returned +1 from an +/// instruction, like partial_apply, and therefore must be released on all paths +/// via strong_release or apply. +class ValueLifetimeAnalysis { +public: + + /// The lifetime frontier for the value. It is the list of instructions + /// following the last uses of the value. All the frontier instructions + /// end the value's lifetime. + typedef llvm::SmallVector Frontier; + + /// Constructor for the value \p Def with a specific set of users of Def's + /// users. + ValueLifetimeAnalysis(SILInstruction *def, + ArrayRef userList) + : defValue(def), userSet(userList.begin(), userList.end()) { + propagateLiveness(); + } + + /// Constructor for the value \p def considering all the value's uses. + ValueLifetimeAnalysis(SILInstruction *def) : defValue(def) { + for (auto result : def->getResults()) { + for (Operand *op : result->getUses()) { + userSet.insert(op->getUser()); + } + } + propagateLiveness(); + } + + enum Mode { + /// Don't split critical edges if the frontier instructions are located on + /// a critical edges. Instead fail. + DontModifyCFG, + + /// Split critical edges if the frontier instructions are located on + /// a critical edges. + AllowToModifyCFG, + + /// Require that all users must commonly post-dominate the definition. In + /// other words: All paths from the definition to the function exit must + /// contain at least one use. Fail if this is not the case. + UsersMustPostDomDef + }; + + /// Computes and returns the lifetime frontier for the value in \p frontier. + /// + /// Returns true if all instructions in the frontier could be found in + /// non-critical edges. + /// Returns false if some frontier instructions are located on critical edges. + /// In this case, if \p mode is AllowToModifyCFG, those critical edges are + /// split, otherwise nothing is done and the returned \p frontier is not + /// valid. + /// + /// If \p deBlocks is provided, all dead-end blocks are ignored. This + /// prevents unreachable-blocks to be included in the frontier. + bool computeFrontier(Frontier &frontier, Mode mode, + DeadEndBlocks *deBlocks = nullptr); + + /// Returns true if the instruction \p Inst is located within the value's + /// lifetime. + /// It is assumed that \p inst is located after the value's definition. + bool isWithinLifetime(SILInstruction *inst); + + /// Returns true if the value is alive at the begin of block \p bb. + bool isAliveAtBeginOfBlock(SILBasicBlock *bb) { + return liveBlocks.count(bb) && bb != defValue->getParent(); + } + + /// Checks if there is a dealloc_ref inside the value's live range. + bool containsDeallocRef(const Frontier &frontier); + + /// For debug dumping. + void dump() const; + +private: + + /// The value. + SILInstruction *defValue; + + /// The set of blocks where the value is live. + llvm::SmallSetVector liveBlocks; + + /// The set of instructions where the value is used, or the users-list + /// provided with the constructor. + llvm::SmallPtrSet userSet; + + /// Propagates the liveness information up the control flow graph. + void propagateLiveness(); + + /// Returns the last use of the value in the live block \p bb. + SILInstruction *findLastUserInBlock(SILBasicBlock *bb); +}; + + +} // end namespace swift + +#endif diff --git a/include/swift/Sema/IDETypeCheckingRequests.h b/include/swift/Sema/IDETypeCheckingRequests.h index 15b4fd6d464..66db9ae7c04 100644 --- a/include/swift/Sema/IDETypeCheckingRequests.h +++ b/include/swift/Sema/IDETypeCheckingRequests.h @@ -38,8 +38,7 @@ struct DeclApplicabilityOwner { DC(DC), Ty(Ty), ExtensionOrMember(VD) {} friend llvm::hash_code hash_value(const DeclApplicabilityOwner &CI) { - return hash_combine(hash_value(CI.Ty.getPointer()), - hash_value(CI.ExtensionOrMember)); + return llvm::hash_combine(CI.Ty.getPointer(), CI.ExtensionOrMember); } friend bool operator==(const DeclApplicabilityOwner &lhs, @@ -96,8 +95,8 @@ struct TypePair { TypePair(Type FirstTy, Type SecondTy): FirstTy(FirstTy), SecondTy(SecondTy) {} TypePair(): TypePair(Type(), Type()) {} friend llvm::hash_code hash_value(const TypePair &TI) { - return hash_combine(hash_value(TI.FirstTy.getPointer()), - hash_value(TI.SecondTy.getPointer())); + return llvm::hash_combine(TI.FirstTy.getPointer(), + TI.SecondTy.getPointer()); } friend bool operator==(const TypePair &lhs, @@ -133,9 +132,7 @@ struct TypeRelationCheckInput { OpenArchetypes(OpenArchetypes) {} friend llvm::hash_code hash_value(const TypeRelationCheckInput &TI) { - return hash_combine(hash_value(TI.Pair), - hash_value(TI.Relation), - hash_value(TI.OpenArchetypes)); + return llvm::hash_combine(TI.Pair, TI.Relation, TI.OpenArchetypes); } friend bool operator==(const TypeRelationCheckInput &lhs, diff --git a/include/swift/Syntax/Syntax.h b/include/swift/Syntax/Syntax.h index c4b2d8f227d..31fac98aa9a 100644 --- a/include/swift/Syntax/Syntax.h +++ b/include/swift/Syntax/Syntax.h @@ -83,7 +83,7 @@ public: SyntaxKind getKind() const; /// Get the shared raw syntax. - RC getRaw() const; + const RC &getRaw() const; /// Get an ID for this node that is stable across incremental parses SyntaxNodeId getId() const { return getRaw()->getId(); } diff --git a/include/swift/Syntax/SyntaxData.h b/include/swift/Syntax/SyntaxData.h index aa6a69f1369..6159f2e01e2 100644 --- a/include/swift/Syntax/SyntaxData.h +++ b/include/swift/Syntax/SyntaxData.h @@ -186,7 +186,7 @@ public: CursorIndex IndexInParent = 0); /// Returns the raw syntax node for this syntax node. - const RC getRaw() const { + const RC &getRaw() const { return Raw; } diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 42c2be51c72..3a92c60cffe 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -165,7 +165,8 @@ struct ASTContext::Implementation { // FIXME: This is a StringMap rather than a StringSet because StringSet // doesn't allow passing in a pre-existing allocator. - llvm::StringMap IdentifierTable; + llvm::StringMap + IdentifierTable; /// The declaration of Swift.AssignmentPrecedence. PrecedenceGroupDecl *AssignmentPrecedence = nullptr; @@ -642,7 +643,8 @@ Identifier ASTContext::getIdentifier(StringRef Str) const { if (Str.data() == nullptr) return Identifier(nullptr); - auto I = getImpl().IdentifierTable.insert(std::make_pair(Str, char())).first; + auto pair = std::make_pair(Str, Identifier::Aligner()); + auto I = getImpl().IdentifierTable.insert(pair).first; return Identifier(I->getKeyData()); } @@ -3405,8 +3407,6 @@ ProtocolType::ProtocolType(ProtocolDecl *TheDecl, Type Parent, : NominalType(TypeKind::Protocol, &Ctx, TheDecl, Parent, properties) { } LValueType *LValueType::get(Type objectTy) { - assert(!objectTy->hasError() && - "cannot have ErrorType wrapped inside LValueType"); assert(!objectTy->is() && !objectTy->is() && "cannot have 'inout' or @lvalue wrapped inside an @lvalue"); diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index 8de810cab47..4c4078346de 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -1491,6 +1491,10 @@ void ASTMangler::appendImplFunctionType(SILFunctionType *fn) { Optional ASTMangler::getSpecialManglingContext(const ValueDecl *decl, bool useObjCProtocolNames) { + #if SWIFT_BUILD_ONLY_SYNTAXPARSERLIB + return None; // not needed for the parser library. + #endif + // Declarations provided by a C module have a special context mangling. // known-context ::= 'So' // diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 8ba90209ea0..86e8f0eb4b6 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -2893,7 +2893,7 @@ void PrintAST::printEnumElement(EnumElementDecl *elt) { break; } - auto *raw = elt->getRawValueExpr(); + auto *raw = elt->getStructuralRawValueExpr(); if (!raw || raw->isImplicit()) return; diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index 7d4b08d752c..464e218a5d8 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -1346,8 +1346,12 @@ void EnumElementScope::expandAScopeThatDoesNotCreateANewInsertionPoint( if (auto *pl = decl->getParameterList()) scopeCreator.constructExpandAndInsertUncheckable( this, pl, nullptr); - // might contain a closure - scopeCreator.addToScopeTree(decl->getRawValueExpr(), this); + // The invariant that the raw value expression can never introduce a new scope + // is checked in Parse. However, this guarantee is not future-proof. Compute + // and add the raw value expression anyways just to be defensive. + // + // FIXME: Re-enable this. It currently crashes for malformed enum cases. + // scopeCreator.addToScopeTree(decl->getStructuralRawValueExpr(), this); } void AbstractFunctionBodyScope::expandAScopeThatDoesNotCreateANewInsertionPoint( diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp index 9364757717e..0e354d1f1ff 100644 --- a/lib/AST/ASTWalker.cpp +++ b/lib/AST/ASTWalker.cpp @@ -403,7 +403,7 @@ class Traversal : public ASTVisitorgetRawValueExpr()) { + if (auto *rawLiteralExpr = ED->getRawValueUnchecked()) { Expr *newRawExpr = doIt(rawLiteralExpr); if (auto newRawLiteralExpr = dyn_cast(newRawExpr)) ED->setRawValueExpr(newRawLiteralExpr); diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp index 6029890ebc7..7af12aafbaa 100644 --- a/lib/AST/Builtins.cpp +++ b/lib/AST/Builtins.cpp @@ -162,7 +162,6 @@ getBuiltinFunction(Identifier Id, ArrayRef argTypes, Type ResType, ParamDecl(ParamDecl::Specifier::Default, SourceLoc(), SourceLoc(), Identifier(), SourceLoc(), Identifier(), DC); PD->setInterfaceType(argType); - PD->setValidationToChecked(); PD->setImplicit(); params.push_back(PD); } @@ -179,7 +178,6 @@ getBuiltinFunction(Identifier Id, ArrayRef argTypes, Type ResType, paramList, TypeLoc::withoutLoc(ResType), DC); FD->computeType(Info); - FD->setValidationToChecked(); FD->setImplicit(); FD->setAccess(AccessLevel::Public); return FD; @@ -209,7 +207,6 @@ getBuiltinGenericFunction(Identifier Id, Identifier(), SourceLoc(), Identifier(), DC); PD->setInterfaceType(paramIfaceType); - PD->setValidationToChecked(); PD->setImplicit(); params.push_back(PD); } @@ -228,7 +225,6 @@ getBuiltinGenericFunction(Identifier Id, func->setGenericSignature(Sig); func->computeType(); - func->setValidationToChecked(); func->setImplicit(); func->setAccess(AccessLevel::Public); @@ -1378,6 +1374,7 @@ Type IntrinsicTypeDecoder::decodeImmediate() { case IITDescriptor::HalfVecArgument: case IITDescriptor::VarArg: case IITDescriptor::Token: + case IITDescriptor::VecElementArgument: case IITDescriptor::VecOfAnyPtrsToElt: // These types cannot be expressed in swift yet. return Type(); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 8f579444bbd..3808f1c99e7 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -1361,7 +1361,6 @@ ParamDecl *PatternBindingInitializer::getImplicitSelfDecl() { C.Id_self, this); SelfParam->setImplicit(); SelfParam->setInterfaceType(DC->getSelfInterfaceType()); - SelfParam->setValidationToChecked(); } } @@ -2142,32 +2141,15 @@ bool AbstractStorageDecl::isResilient(ModuleDecl *M, llvm_unreachable("bad resilience expansion"); } -static bool isValidKeyPathComponent(AbstractStorageDecl *decl) { - // If this property or subscript is not an override, we can reference it - // from a keypath component. - auto base = decl->getOverriddenDecl(); - if (!base) - return true; - - // Otherwise, we can only reference it if the type is not ABI-compatible - // with the type of the base. - // - // If the type is ABI compatible with the type of the base, we have to - // reference the base instead. - auto baseInterfaceTy = base->getInterfaceType(); - auto derivedInterfaceTy = decl->getInterfaceType(); - - auto selfInterfaceTy = decl->getDeclContext()->getDeclaredInterfaceType(); - - auto overrideInterfaceTy = selfInterfaceTy->adjustSuperclassMemberDeclType( - base, decl, baseInterfaceTy); - - return !derivedInterfaceTy->matches(overrideInterfaceTy, - TypeMatchFlags::AllowABICompatible); -} - -void AbstractStorageDecl::computeIsValidKeyPathComponent() { - setIsValidKeyPathComponent(::isValidKeyPathComponent(this)); +bool AbstractStorageDecl::isValidKeyPathComponent() const { + // Check whether we're an ABI compatible override of another property. If we + // are, then the key path should refer to the base decl instead. + auto &ctx = getASTContext(); + auto isABICompatibleOverride = evaluateOrDefault( + ctx.evaluator, + IsABICompatibleOverrideRequest{const_cast(this)}, + false); + return !isABICompatibleOverride; } bool AbstractStorageDecl::isGetterMutating() const { @@ -3864,7 +3846,6 @@ GetDestructorRequest::evaluate(Evaluator &evaluator, ClassDecl *CD) const { auto *DD = new (ctx) DestructorDecl(CD->getLoc(), CD); DD->setImplicit(); - DD->setValidationToChecked(); // Synthesize an empty body for the destructor as needed. DD->setBodySynthesizer(synthesizeEmptyFunctionBody); @@ -4292,6 +4273,12 @@ bool EnumDecl::isEffectivelyExhaustive(ModuleDecl *M, "these should match up"); return !isResilient(M, expansion); } + +void EnumDecl::setHasFixedRawValues() { + auto flags = LazySemanticInfo.RawTypeAndFlags.getInt() | + EnumDecl::HasFixedRawValues; + LazySemanticInfo.RawTypeAndFlags.setInt(flags); +} ProtocolDecl::ProtocolDecl(DeclContext *DC, SourceLoc ProtocolLoc, SourceLoc NameLoc, Identifier Name, @@ -5079,6 +5066,10 @@ bool VarDecl::isSettable(const DeclContext *UseDC, if (!isLet()) return supportsMutation(); + // Debugger expression 'let's are initialized through a side-channel. + if (isDebuggerVar()) + return false; + // We have a 'let'; we must be checking settability from a specific // DeclContext to go on further. if (UseDC == nullptr) @@ -6578,26 +6569,22 @@ static bool requiresNewVTableEntry(const AbstractFunctionDecl *decl) { if (decl->isEffectiveLinkageMoreVisibleThan(base)) return true; - // If the method overrides something, we only need a new entry if the - // override has a more general AST type. However an abstraction - // change is OK; we don't want to add a whole new vtable entry just - // because an @in parameter because @owned, or whatever. - auto baseInterfaceTy = base->getInterfaceType(); - auto derivedInterfaceTy = decl->getInterfaceType(); - using Direction = ASTContext::OverrideGenericSignatureReqCheck; if (!ctx.overrideGenericSignatureReqsSatisfied( base, decl, Direction::BaseReqSatisfiedByDerived)) { return true; } - auto selfInterfaceTy = decl->getDeclContext()->getDeclaredInterfaceType(); - - auto overrideInterfaceTy = selfInterfaceTy->adjustSuperclassMemberDeclType( - base, decl, baseInterfaceTy); - - return !derivedInterfaceTy->matches(overrideInterfaceTy, - TypeMatchFlags::AllowABICompatible); + // If this method is an ABI compatible override, then we don't need a new + // vtable entry. Otherwise, if it's not ABI compatible, for example if the + // base has a more general AST type, then we need a new entry. Note that an + // abstraction change is OK; we don't want to add a whole new vtable entry + // just because an @in parameter becomes @owned, or whatever. + auto isABICompatibleOverride = evaluateOrDefault( + ctx.evaluator, + IsABICompatibleOverrideRequest{const_cast(decl)}, + false); + return !isABICompatibleOverride; } void AbstractFunctionDecl::computeNeedsNewVTableEntry() { @@ -6654,8 +6641,6 @@ void AbstractFunctionDecl::computeSelfDeclType() { ? ParamDecl::Specifier::InOut : ParamDecl::Specifier::Default; selfDecl->setSpecifier(specifier); - - selfDecl->setValidationToChecked(); } void AbstractFunctionDecl::setParameters(ParameterList *BodyParams) { @@ -6995,11 +6980,8 @@ StaticSpellingKind FuncDecl::getCorrectStaticSpelling() const { } Type FuncDecl::getResultInterfaceType() const { - if (!hasInterfaceType()) - return nullptr; - Type resultTy = getInterfaceType(); - if (resultTy->is()) + if (resultTy.isNull() || resultTy->is()) return resultTy; if (hasImplicitSelfDecl()) @@ -7196,6 +7178,32 @@ EnumCaseDecl *EnumElementDecl::getParentCase() const { llvm_unreachable("enum element not in case of parent enum"); } + +LiteralExpr *EnumElementDecl::getRawValueExpr() const { + // The return value of this request is irrelevant - it exists as + // a cache-warmer. + (void)evaluateOrDefault( + getASTContext().evaluator, + EnumRawValuesRequest{getParentEnum(), TypeResolutionStage::Interface}, + true); + return RawValueExpr; +} + +LiteralExpr *EnumElementDecl::getStructuralRawValueExpr() const { + // The return value of this request is irrelevant - it exists as + // a cache-warmer. + (void)evaluateOrDefault( + getASTContext().evaluator, + EnumRawValuesRequest{getParentEnum(), TypeResolutionStage::Structural}, + true); + return RawValueExpr; +} + +void EnumElementDecl::setRawValueExpr(LiteralExpr *e) { + assert((!RawValueExpr || e == RawValueExpr || e->getType()) && + "Illegal mutation of raw value expr"); + RawValueExpr = e; +} SourceRange ConstructorDecl::getSourceRange() const { if (isImplicit()) diff --git a/lib/AST/DiagnosticEngine.cpp b/lib/AST/DiagnosticEngine.cpp index 9c91a3e80ab..08d87b482c2 100644 --- a/lib/AST/DiagnosticEngine.cpp +++ b/lib/AST/DiagnosticEngine.cpp @@ -279,6 +279,14 @@ void InFlightDiagnostic::flush() { Engine->flushActiveDiagnostic(); } +void Diagnostic::addChildNote(Diagnostic &&D) { + assert(storedDiagnosticInfos[(unsigned)D.ID].kind == DiagnosticKind::Note && + "Only notes can have a parent."); + assert(storedDiagnosticInfos[(unsigned)ID].kind != DiagnosticKind::Note && + "Notes can't have children."); + ChildNotes.push_back(std::move(D)); +} + bool DiagnosticEngine::isDiagnosticPointsToFirstBadToken(DiagID ID) const { return storedDiagnosticInfos[(unsigned) ID].pointsToFirstBadToken; } @@ -803,10 +811,11 @@ void DiagnosticEngine::emitTentativeDiagnostics() { TentativeDiagnostics.clear(); } -void DiagnosticEngine::emitDiagnostic(const Diagnostic &diagnostic) { +Optional +DiagnosticEngine::diagnosticInfoForDiagnostic(const Diagnostic &diagnostic) { auto behavior = state.determineBehavior(diagnostic.getID()); if (behavior == DiagnosticState::Behavior::Ignore) - return; + return None; // Figure out the source location. SourceLoc loc = diagnostic.getLoc(); @@ -846,7 +855,7 @@ void DiagnosticEngine::emitDiagnostic(const Diagnostic &diagnostic) { // FIXME: Horrible, horrible hackaround. We're not getting a // DeclContext everywhere we should. if (!dc) { - return; + return None; } while (!dc->isModuleContext()) { @@ -923,17 +932,37 @@ void DiagnosticEngine::emitDiagnostic(const Diagnostic &diagnostic) { } } - // Pass the diagnostic off to the consumer. - DiagnosticInfo Info; - Info.ID = diagnostic.getID(); - Info.Ranges = diagnostic.getRanges(); - Info.FixIts = diagnostic.getFixIts(); - for (auto &Consumer : Consumers) { - Consumer->handleDiagnostic( - SourceMgr, loc, toDiagnosticKind(behavior), - diagnosticStringFor(Info.ID, getPrintDiagnosticNames()), - diagnostic.getArgs(), Info, getDefaultDiagnosticLoc()); + return DiagnosticInfo( + diagnostic.getID(), loc, toDiagnosticKind(behavior), + diagnosticStringFor(diagnostic.getID(), getPrintDiagnosticNames()), + diagnostic.getArgs(), getDefaultDiagnosticLoc(), /*child note info*/ {}, + diagnostic.getRanges(), diagnostic.getFixIts(), diagnostic.isChildNote()); +} + +void DiagnosticEngine::emitDiagnostic(const Diagnostic &diagnostic) { + if (auto info = diagnosticInfoForDiagnostic(diagnostic)) { + SmallVector childInfo; + TinyPtrVector childInfoPtrs; + auto childNotes = diagnostic.getChildNotes(); + for (unsigned idx = 0; idx < childNotes.size(); ++idx) { + if (auto child = diagnosticInfoForDiagnostic(childNotes[idx])) { + childInfo.push_back(*child); + childInfoPtrs.push_back(&childInfo[idx]); + } + } + info->ChildDiagnosticInfo = childInfoPtrs; + for (auto &consumer : Consumers) { + consumer->handleDiagnostic(SourceMgr, info->Loc, info->Kind, + info->FormatString, info->FormatArgs, *info, + info->BufferIndirectlyCausingDiagnostic); + } } + + // For compatibility with DiagnosticConsumers which don't know about child + // notes. These can be ignored by consumers which do take advantage of the + // grouping. + for (auto &childNote : diagnostic.getChildNotes()) + emitDiagnostic(childNote); } const char *DiagnosticEngine::diagnosticStringFor(const DiagID id, diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp index a9c1c33bc90..e3a5a05a441 100644 --- a/lib/AST/GenericSignatureBuilder.cpp +++ b/lib/AST/GenericSignatureBuilder.cpp @@ -599,127 +599,6 @@ namespace { }; } -namespace std { - // FIXME: Egregious hack to work around a bogus static_assert in - // llvm::GraphWriter. Good thing nobody else cares about this trait... - template<> - struct is_pointer - : std::integral_constant { }; -} - -namespace llvm { - // Visualize the same-type constraints within an equivalence class. - template<> - struct GraphTraits { - using NodeRef = EquivalenceClassVizNode; - - static NodeRef getEntryNode(const EquivalenceClass *equivClass) { - return { equivClass, equivClass->members.front()->getDependentType({ }) }; - } - - class nodes_iterator { - using BaseIterator = PotentialArchetype * const *; - - const EquivalenceClass *equivClass; - BaseIterator base; - - public: - using difference_type = ptrdiff_t; - using value_type = EquivalenceClassVizNode; - using reference = value_type; - using pointer = value_type*; - using iterator_category = std::forward_iterator_tag; - - nodes_iterator(const EquivalenceClass *equivClass, BaseIterator base) - : equivClass(equivClass), base(base) { } - - BaseIterator &getBase() { return base; } - const BaseIterator &getBase() const { return base; } - - reference operator*() const { - return { equivClass, (*getBase())->getDependentType({ }) }; - } - - nodes_iterator& operator++() { - ++getBase(); - return *this; - } - - nodes_iterator operator++(int) { - nodes_iterator result = *this; - ++(*this); - return result; - } - - friend bool operator==(const nodes_iterator &lhs, - const nodes_iterator &rhs) { - return lhs.getBase() == rhs.getBase(); - } - - friend bool operator!=(const nodes_iterator &lhs, - const nodes_iterator &rhs) { - return lhs.getBase() != rhs.getBase(); - } - }; - - static nodes_iterator nodes_begin(const EquivalenceClass *equivClass) { - return nodes_iterator(equivClass, equivClass->members.begin()); - } - - static nodes_iterator nodes_end(const EquivalenceClass *equivClass) { - return nodes_iterator(equivClass, equivClass->members.end()); - } - - static unsigned size(const EquivalenceClass *equivClass) { - return equivClass->members.size(); - } - - using ChildIteratorType = EquivalenceClassVizIterator; - - static ChildIteratorType child_begin(NodeRef node) { - auto base = node.first->sameTypeConstraints.data(); - auto baseEnd = base + node.first->sameTypeConstraints.size(); - return ChildIteratorType(node, base, baseEnd); - } - - static ChildIteratorType child_end(NodeRef node) { - auto base = node.first->sameTypeConstraints.data(); - auto baseEnd = base + node.first->sameTypeConstraints.size(); - return ChildIteratorType(node, baseEnd, baseEnd); - } - }; - - template <> - struct DOTGraphTraits - : public DefaultDOTGraphTraits - { - DOTGraphTraits(bool = false) { } - - static std::string getGraphName(const EquivalenceClass *equivClass) { - return "Equivalence class for '" + - equivClass->members.front()->getDebugName() + "'"; - } - - std::string getNodeLabel(EquivalenceClassVizNode node, - const EquivalenceClass *equivClass) const { - return node.second.getString(); - } - - static std::string getEdgeAttributes(EquivalenceClassVizNode node, - EquivalenceClassVizIterator iter, - const EquivalenceClass *equivClass) { - if (iter.getBase()->source->kind - == RequirementSource::NestedTypeNameMatch) - return "color=\"blue\""; - - if (iter.getBase()->source->isDerivedRequirement()) - return "color=\"gray\""; - - return "color=\"red\""; - } - }; -} // end namespace llvm - namespace { /// Retrieve the type described by the given unresolved tyoe. Type getUnresolvedType(GSBUnresolvedType type, @@ -2370,37 +2249,6 @@ void EquivalenceClass::dump(llvm::raw_ostream &out, rewriteRoot->dump(out); } } - - { - out << "---GraphViz output for same-type constraints---\n"; - - // Render the output - std::string graphviz; - { - llvm::raw_string_ostream graphvizOut(graphviz); - llvm::WriteGraph(graphvizOut, this); - } - - // Clean up the output to turn it into an undirected graph. - // FIXME: This is horrible, GraphWriter should be able to support - // undirected graphs. - auto digraphPos = graphviz.find("digraph"); - if (digraphPos != std::string::npos) { - // digraph -> graph - graphviz.erase(graphviz.begin() + digraphPos, - graphviz.begin() + digraphPos + 2); - } - - // Directed edges to undirected edges: -> to -- - while (true) { - auto arrowPos = graphviz.find("->"); - if (arrowPos == std::string::npos) break; - - graphviz.replace(arrowPos, 2, "--"); - } - - out << graphviz; - } } void EquivalenceClass::dump(GenericSignatureBuilder *builder) const { diff --git a/lib/AST/Identifier.cpp b/lib/AST/Identifier.cpp index 4ba266bdc70..8fbf7e20416 100644 --- a/lib/AST/Identifier.cpp +++ b/lib/AST/Identifier.cpp @@ -21,12 +21,9 @@ #include "clang/Basic/CharInfo.h" using namespace swift; -void *DeclBaseName::SubscriptIdentifierData = - &DeclBaseName::SubscriptIdentifierData; -void *DeclBaseName::ConstructorIdentifierData = - &DeclBaseName::ConstructorIdentifierData; -void *DeclBaseName::DestructorIdentifierData = - &DeclBaseName::DestructorIdentifierData; +constexpr const Identifier::Aligner DeclBaseName::SubscriptIdentifierData{}; +constexpr const Identifier::Aligner DeclBaseName::ConstructorIdentifierData{}; +constexpr const Identifier::Aligner DeclBaseName::DestructorIdentifierData{}; raw_ostream &llvm::operator<<(raw_ostream &OS, Identifier I) { if (I.get() == nullptr) diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp index de8f80a4f82..f93aa842e10 100644 --- a/lib/AST/Module.cpp +++ b/lib/AST/Module.cpp @@ -103,7 +103,6 @@ void BuiltinUnit::LookupCache::lookupValue( const_cast(&M)); TAD->setUnderlyingType(Ty); TAD->setAccess(AccessLevel::Public); - TAD->setValidationToChecked(); TAD->computeType(); Entry = TAD; } @@ -399,9 +398,6 @@ ModuleDecl::ModuleDecl(Identifier name, ASTContext &ctx) setImplicit(); setInterfaceType(ModuleType::get(this)); - // validateDecl() should return immediately given a ModuleDecl. - setValidationToChecked(); - setAccess(AccessLevel::Public); } diff --git a/lib/AST/ModuleLoader.cpp b/lib/AST/ModuleLoader.cpp index 31d46c88b19..fbcf3f96211 100644 --- a/lib/AST/ModuleLoader.cpp +++ b/lib/AST/ModuleLoader.cpp @@ -18,17 +18,21 @@ #include "clang/Frontend/Utils.h" #include "swift/ClangImporter/ClangImporter.h" +namespace llvm { +class FileCollector; +} + namespace swift { -DependencyTracker::DependencyTracker(bool TrackSystemDeps) - // NB: The ClangImporter believes it's responsible for the construction of - // this instance, and it static_cast<>s the instance pointer to its own - // subclass based on that belief. If you change this to be some other - // instance, you will need to change ClangImporter's code to handle the - // difference. - : clangCollector(ClangImporter::createDependencyCollector(TrackSystemDeps)) -{ -} +DependencyTracker::DependencyTracker( + bool TrackSystemDeps, std::shared_ptr FileCollector) + // NB: The ClangImporter believes it's responsible for the construction of + // this instance, and it static_cast<>s the instance pointer to its own + // subclass based on that belief. If you change this to be some other + // instance, you will need to change ClangImporter's code to handle the + // difference. + : clangCollector(ClangImporter::createDependencyCollector(TrackSystemDeps, + FileCollector)) {} void DependencyTracker::addDependency(StringRef File, bool IsSystem) { diff --git a/lib/AST/TypeCheckRequests.cpp b/lib/AST/TypeCheckRequests.cpp index 3e6250090d5..2d5f98e164d 100644 --- a/lib/AST/TypeCheckRequests.cpp +++ b/lib/AST/TypeCheckRequests.cpp @@ -12,6 +12,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" #include "swift/AST/DiagnosticsCommon.h" +#include "swift/AST/DiagnosticsSema.h" #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" #include "swift/AST/PropertyWrappers.h" @@ -167,15 +168,15 @@ bool EnumRawTypeRequest::isCached() const { Optional EnumRawTypeRequest::getCachedResult() const { auto enumDecl = std::get<0>(getStorage()); - if (enumDecl->LazySemanticInfo.RawType.getInt()) - return enumDecl->LazySemanticInfo.RawType.getPointer(); + if (enumDecl->LazySemanticInfo.hasRawType()) + return enumDecl->LazySemanticInfo.RawTypeAndFlags.getPointer(); return None; } void EnumRawTypeRequest::cacheResult(Type value) const { auto enumDecl = std::get<0>(getStorage()); - enumDecl->LazySemanticInfo.RawType.setPointerAndInt(value, true); + enumDecl->LazySemanticInfo.cacheRawType(value); } //----------------------------------------------------------------------------// @@ -839,7 +840,7 @@ void InferredGenericSignatureRequest::noteCycleStep(DiagnosticEngine &d) const { } //----------------------------------------------------------------------------// -// IsImplicitlyUnwrappedOptionalRequest computation. +// UnderlyingTypeRequest computation. //----------------------------------------------------------------------------// Optional @@ -854,3 +855,43 @@ void UnderlyingTypeRequest::cacheResult(Type value) const { auto *typeAlias = std::get<0>(getStorage()); typeAlias->UnderlyingTy.setType(value); } + +void UnderlyingTypeRequest::diagnoseCycle(DiagnosticEngine &diags) const { + auto aliasDecl = std::get<0>(getStorage()); + diags.diagnose(aliasDecl, diag::recursive_decl_reference, + aliasDecl->getDescriptiveKind(), + aliasDecl->getName()); +} + +//----------------------------------------------------------------------------// +// EnumRawValuesRequest computation. +//----------------------------------------------------------------------------// + +bool EnumRawValuesRequest::isCached() const { + return std::get<1>(getStorage()) == TypeResolutionStage::Interface; +} + +Optional EnumRawValuesRequest::getCachedResult() const { + auto *ED = std::get<0>(getStorage()); + if (ED->LazySemanticInfo.hasCheckedRawValues()) + return true; + return None; +} + +void EnumRawValuesRequest::cacheResult(bool) const { + auto *ED = std::get<0>(getStorage()); + auto flags = ED->LazySemanticInfo.RawTypeAndFlags.getInt() | + EnumDecl::HasFixedRawValues | + EnumDecl::HasFixedRawValuesAndTypes; + ED->LazySemanticInfo.RawTypeAndFlags.setInt(flags); +} + +void EnumRawValuesRequest::diagnoseCycle(DiagnosticEngine &diags) const { + // This request computes the raw type, and so participates in cycles involving + // it. For now, the raw type provides a rich enough circularity diagnostic + // that we can silence ourselves. +} + +void EnumRawValuesRequest::noteCycleStep(DiagnosticEngine &diags) const { + +} diff --git a/lib/Basic/CMakeLists.txt b/lib/Basic/CMakeLists.txt index 93acc3f9012..8504b672afc 100644 --- a/lib/Basic/CMakeLists.txt +++ b/lib/Basic/CMakeLists.txt @@ -30,7 +30,7 @@ macro(find_first_existing_vc_file out_var path) ) endmacro() -set(get_svn_script "${LLVM_MAIN_SRC_DIR}/cmake/modules/GetSVN.cmake") +set(generate_vcs_version_script "${LLVM_MAIN_SRC_DIR}/cmake/modules/GenerateVersionFromVCS.cmake") function(generate_revision_inc revision_inc_var name dir) find_first_existing_vc_file(dep_file "${dir}") @@ -39,12 +39,12 @@ function(generate_revision_inc revision_inc_var name dir) string(TOUPPER ${name} upper_name) if(DEFINED dep_file) add_custom_command(OUTPUT "${revision_inc}" - DEPENDS "${dep_file}" "${get_svn_script}" + DEPENDS "${dep_file}" "${generate_vcs_version_script}" COMMAND - ${CMAKE_COMMAND} "-DFIRST_SOURCE_DIR=${dir}" - "-DFIRST_NAME=${upper_name}" + ${CMAKE_COMMAND} "-DNAMES=${upper_name}" + "-D${upper_name}_SOURCE_DIR=${dir}" "-DHEADER_FILE=${revision_inc}" - -P "${get_svn_script}") + -P "${generate_vcs_version_script}") else() # Generate an empty Revision.inc file if we are not using git or SVN. file(WRITE "${revision_inc}" "") diff --git a/lib/Basic/Platform.cpp b/lib/Basic/Platform.cpp index cd6c9f6f946..356a7d41861 100644 --- a/lib/Basic/Platform.cpp +++ b/lib/Basic/Platform.cpp @@ -141,6 +141,7 @@ StringRef swift::getPlatformNameForTriple(const llvm::Triple &triple) { case llvm::Triple::Ananas: case llvm::Triple::CloudABI: case llvm::Triple::DragonFly: + case llvm::Triple::Emscripten: case llvm::Triple::Fuchsia: case llvm::Triple::KFreeBSD: case llvm::Triple::Lv2: @@ -161,6 +162,7 @@ StringRef swift::getPlatformNameForTriple(const llvm::Triple &triple) { case llvm::Triple::AMDPAL: case llvm::Triple::HermitCore: case llvm::Triple::Hurd: + case llvm::Triple::WASI: return ""; case llvm::Triple::Darwin: case llvm::Triple::MacOSX: diff --git a/lib/Basic/QuotedString.cpp b/lib/Basic/QuotedString.cpp index c99116e6173..c8ce0f67a35 100644 --- a/lib/Basic/QuotedString.cpp +++ b/lib/Basic/QuotedString.cpp @@ -36,7 +36,7 @@ void swift::printAsQuotedString(llvm::raw_ostream &out, llvm::StringRef text) { }; out << "\\u{" << hexdigit[c >> 4] << hexdigit[c & 0xF] << '}'; } else { - out << c; + out << (char)c; } break; } diff --git a/lib/ClangImporter/ClangAdapter.cpp b/lib/ClangImporter/ClangAdapter.cpp index c42d8616af9..6260ccdb911 100644 --- a/lib/ClangImporter/ClangAdapter.cpp +++ b/lib/ClangImporter/ClangAdapter.cpp @@ -436,6 +436,21 @@ OmissionTypeName importer::getClangTypeNameForOmission(clang::ASTContext &ctx, // OpenMP types that don't have Swift equivalents. case clang::BuiltinType::OMPArraySection: return OmissionTypeName(); + + // SVE builtin types that don't have Swift equivalents. + case clang::BuiltinType::SveInt8: + case clang::BuiltinType::SveInt16: + case clang::BuiltinType::SveInt32: + case clang::BuiltinType::SveInt64: + case clang::BuiltinType::SveUint8: + case clang::BuiltinType::SveUint16: + case clang::BuiltinType::SveUint32: + case clang::BuiltinType::SveUint64: + case clang::BuiltinType::SveFloat16: + case clang::BuiltinType::SveFloat32: + case clang::BuiltinType::SveFloat64: + case clang::BuiltinType::SveBool: + return OmissionTypeName(); } } diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 0603e8e3eb5..885ed98d343 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -14,11 +14,9 @@ // //===----------------------------------------------------------------------===// #include "swift/ClangImporter/ClangImporter.h" -#include "swift/ClangImporter/ClangModule.h" +#include "ClangDiagnosticConsumer.h" #include "IAMInference.h" #include "ImporterImpl.h" -#include "ClangDiagnosticConsumer.h" -#include "swift/Subsystems.h" #include "swift/AST/ASTContext.h" #include "swift/AST/ClangModuleLoader.h" #include "swift/AST/DiagnosticEngine.h" @@ -36,9 +34,11 @@ #include "swift/Basic/Version.h" #include "swift/ClangImporter/ClangImporterOptions.h" #include "swift/Demangling/Demangle.h" +#include "swift/ClangImporter/ClangModule.h" +#include "swift/Config.h" #include "swift/Parse/Lexer.h" #include "swift/Parse/Parser.h" -#include "swift/Config.h" +#include "swift/Subsystems.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Mangle.h" #include "clang/Basic/CharInfo.h" @@ -50,8 +50,6 @@ #include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/Utils.h" #include "clang/Index/IndexingAction.h" -#include "clang/Serialization/ASTReader.h" -#include "clang/Serialization/ASTWriter.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/PreprocessorOptions.h" #include "clang/Parse/Parser.h" @@ -59,9 +57,12 @@ #include "clang/Rewrite/Frontend/Rewriters.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Sema.h" +#include "clang/Serialization/ASTReader.h" +#include "clang/Serialization/ASTWriter.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/CrashRecoveryContext.h" +#include "llvm/Support/FileCollector.h" #include "llvm/Support/Memory.h" #include "llvm/Support/Path.h" #include @@ -224,7 +225,7 @@ namespace { error); assert(!error && "failed to allocated read-only zero-filled memory"); init(static_cast(memory.base()), - static_cast(memory.base()) + memory.size() - 1, + static_cast(memory.base()) + memory.allocatedSize() - 1, /*null-terminated*/true); } @@ -322,11 +323,15 @@ private: class ClangImporterDependencyCollector : public clang::DependencyCollector { llvm::StringSet<> ExcludedPaths; + /// The FileCollector is used by LLDB to generate reproducers. It's not used + /// by Swift to track dependencies. + std::shared_ptr FileCollector; const bool TrackSystemDeps; public: - ClangImporterDependencyCollector(bool TrackSystemDeps) - : TrackSystemDeps(TrackSystemDeps) {} + ClangImporterDependencyCollector( + bool TrackSystemDeps, std::shared_ptr FileCollector) + : FileCollector(FileCollector), TrackSystemDeps(TrackSystemDeps) {} void excludePath(StringRef filename) { ExcludedPaths.insert(filename); @@ -355,13 +360,22 @@ public: return false; return true; } + + void maybeAddDependency(StringRef Filename, bool FromModule, bool IsSystem, + bool IsModuleFile, bool IsMissing) override { + if (FileCollector) + FileCollector->addFile(Filename); + clang::DependencyCollector::maybeAddDependency( + Filename, FromModule, IsSystem, IsModuleFile, IsMissing); + } }; } // end anonymous namespace std::shared_ptr -ClangImporter::createDependencyCollector(bool TrackSystemDeps) -{ - return std::make_shared(TrackSystemDeps); +ClangImporter::createDependencyCollector( + bool TrackSystemDeps, std::shared_ptr FileCollector) { + return std::make_shared(TrackSystemDeps, + FileCollector); } void ClangImporter::Implementation::addBridgeHeaderTopLevelDecls( @@ -1017,17 +1031,11 @@ ClangImporter::create(ASTContext &ctx, const ClangImporterOptions &importerOpts, // Set up the file manager. { - if (!ctx.SearchPathOpts.VFSOverlayFiles.empty() || - importerOpts.ForceUseSwiftVirtualFileSystem) { - // If the clang instance has overlays it means the user has provided - // -ivfsoverlay options. We're going to clobber their file system with - // the Swift file system, so warn about it. - if (!instance.getHeaderSearchOpts().VFSOverlayFiles.empty()) { - ctx.Diags.diagnose(SourceLoc(), diag::clang_vfs_overlay_is_ignored); - } - instance.setVirtualFileSystem(ctx.SourceMgr.getFileSystem()); - } - instance.createFileManager(); + llvm::IntrusiveRefCntPtr VFS = + clang::createVFSFromCompilerInvocation(instance.getInvocation(), + instance.getDiagnostics(), + ctx.SourceMgr.getFileSystem()); + instance.createFileManager(std::move(VFS)); } // Don't stop emitting messages if we ever can't load a module. @@ -1041,8 +1049,7 @@ ClangImporter::create(ASTContext &ctx, const ClangImporterOptions &importerOpts, clangDiags.setSeverity(clang::diag::err_module_not_built, clang::diag::Severity::Error, clang::SourceLocation()); - clangDiags.setSuppressAfterFatalError( - !ctx.Diags.getShowDiagnosticsAfterFatalError()); + clangDiags.setFatalsAsError(ctx.Diags.getShowDiagnosticsAfterFatalError()); // Create the associated action. @@ -1157,17 +1164,18 @@ ClangImporter::create(ASTContext &ctx, const ClangImporterOptions &importerOpts, bool ClangImporter::addSearchPath(StringRef newSearchPath, bool isFramework, bool isSystem) { clang::FileManager &fileMgr = Impl.Instance->getFileManager(); - const clang::DirectoryEntry *entry = fileMgr.getDirectory(newSearchPath); - if (!entry) + auto optionalEntry = fileMgr.getOptionalDirectoryRef(newSearchPath); + if (!optionalEntry) return true; + auto entry = *optionalEntry; auto &headerSearchInfo = Impl.getClangPreprocessor().getHeaderSearchInfo(); auto exists = std::any_of(headerSearchInfo.search_dir_begin(), headerSearchInfo.search_dir_end(), [&](const clang::DirectoryLookup &lookup) -> bool { if (isFramework) - return lookup.getFrameworkDir() == entry; - return lookup.getDir() == entry; + return lookup.getFrameworkDir() == &entry.getDirEntry(); + return lookup.getDir() == &entry.getDirEntry(); }); if (exists) { // Don't bother adding a search path that's already there. Clang would have @@ -1338,10 +1346,9 @@ bool ClangImporter::importHeader(StringRef header, ModuleDecl *adapter, off_t expectedSize, time_t expectedModTime, StringRef cachedContents, SourceLoc diagLoc) { clang::FileManager &fileManager = Impl.Instance->getFileManager(); - const clang::FileEntry *headerFile = fileManager.getFile(header, - /*OpenFile=*/true); - if (headerFile && headerFile->getSize() == expectedSize && - headerFile->getModificationTime() == expectedModTime) { + auto headerFile = fileManager.getFile(header, /*OpenFile=*/true); + if (headerFile && (*headerFile)->getSize() == expectedSize && + (*headerFile)->getModificationTime() == expectedModTime) { return importBridgingHeader(header, adapter, diagLoc, false, true); } @@ -1374,8 +1381,7 @@ bool ClangImporter::importBridgingHeader(StringRef header, ModuleDecl *adapter, } clang::FileManager &fileManager = Impl.Instance->getFileManager(); - const clang::FileEntry *headerFile = fileManager.getFile(header, - /*OpenFile=*/true); + auto headerFile = fileManager.getFile(header, /*OpenFile=*/true); if (!headerFile) { Impl.SwiftContext.Diags.diagnose(diagLoc, diag::bridging_header_missing, header); @@ -1408,7 +1414,7 @@ std::string ClangImporter::getBridgingHeaderContents(StringRef headerPath, invocation->getFrontendOpts().DisableFree = false; invocation->getFrontendOpts().Inputs.clear(); invocation->getFrontendOpts().Inputs.push_back( - clang::FrontendInputFile(headerPath, clang::InputKind::ObjC)); + clang::FrontendInputFile(headerPath, clang::Language::ObjC)); invocation->getPreprocessorOpts().resetNonModularOptions(); @@ -1451,9 +1457,10 @@ std::string ClangImporter::getBridgingHeaderContents(StringRef headerPath, return ""; } - const clang::FileEntry *fileInfo = fileManager.getFile(headerPath); - fileSize = fileInfo->getSize(); - fileModTime = fileInfo->getModificationTime(); + if (auto fileInfo = fileManager.getFile(headerPath)) { + fileSize = (*fileInfo)->getSize(); + fileModTime = (*fileInfo)->getModificationTime(); + } return result; } @@ -1465,7 +1472,7 @@ ClangImporter::emitBridgingPCH(StringRef headerPath, invocation->getFrontendOpts().DisableFree = false; invocation->getFrontendOpts().Inputs.clear(); invocation->getFrontendOpts().Inputs.push_back( - clang::FrontendInputFile(headerPath, clang::InputKind::ObjC)); + clang::FrontendInputFile(headerPath, clang::Language::ObjC)); invocation->getFrontendOpts().OutputFile = outputPCHPath; invocation->getFrontendOpts().ProgramAction = clang::frontend::GeneratePCH; invocation->getPreprocessorOpts().resetNonModularOptions(); @@ -2376,8 +2383,7 @@ void ClangImporter::lookupBridgingHeaderDecls( bool ClangImporter::lookupDeclsFromHeader(StringRef Filename, llvm::function_ref filter, llvm::function_ref receiver) const { - const clang::FileEntry *File = - getClangPreprocessor().getFileManager().getFile(Filename); + auto File = getClangPreprocessor().getFileManager().getFile(Filename); if (!File) return true; @@ -2386,7 +2392,7 @@ bool ClangImporter::lookupDeclsFromHeader(StringRef Filename, auto &ClangPP = getClangPreprocessor(); // Look up the header in the includes of the bridging header. - if (Impl.BridgeHeaderFiles.count(File)) { + if (Impl.BridgeHeaderFiles.count(*File)) { auto headerFilter = [&](ClangNode ClangN) -> bool { if (ClangN.isNull()) return false; @@ -2395,7 +2401,7 @@ bool ClangImporter::lookupDeclsFromHeader(StringRef Filename, if (ClangLoc.isInvalid()) return false; - if (ClangSM.getFileEntryForID(ClangSM.getFileID(ClangLoc)) != File) + if (ClangSM.getFileEntryForID(ClangSM.getFileID(ClangLoc)) != *File) return false; return filter(ClangN); @@ -2405,7 +2411,7 @@ bool ClangImporter::lookupDeclsFromHeader(StringRef Filename, return false; } - clang::FileID FID = ClangSM.translateFile(File); + clang::FileID FID = ClangSM.translateFile(*File); if (FID.isInvalid()) return false; diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 45ceeb569b1..a9c808ffdc7 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -137,7 +137,6 @@ createVarWithPattern(ASTContext &ctx, DeclContext *dc, Identifier name, Type ty, if (isImplicit) var->setImplicit(); var->setInterfaceType(ty); - var->setValidationToChecked(); var->setAccess(access); var->setSetterAccess(setterAccess); @@ -528,7 +527,6 @@ makeEnumRawValueConstructor(ClangImporter::Implementation &Impl, SourceLoc(), C.Id_rawValue, enumDecl); param->setInterfaceType(rawTy); - param->setValidationToChecked(); auto paramPL = ParameterList::createWithoutLoc(param); @@ -543,7 +541,6 @@ makeEnumRawValueConstructor(ClangImporter::Implementation &Impl, ctorDecl->setAccess(AccessLevel::Public); ctorDecl->computeType(); - ctorDecl->setValidationToChecked(); ctorDecl->setBodySynthesizer(synthesizeEnumRawValueConstructorBody, enumDecl); return ctorDecl; } @@ -620,7 +617,6 @@ static void makeEnumRawValueGetter(ClangImporter::Implementation &Impl, getterDecl->setIsTransparent(false); getterDecl->computeType(); - getterDecl->setValidationToChecked(); getterDecl->setAccess(AccessLevel::Public); getterDecl->setBodySynthesizer(synthesizeEnumRawValueGetterBody, enumDecl); @@ -702,7 +698,6 @@ static AccessorDecl *makeStructRawValueGetter( getterDecl->setIsTransparent(false); getterDecl->computeType(); - getterDecl->setValidationToChecked(); getterDecl->setAccess(AccessLevel::Public); getterDecl->setBodySynthesizer(synthesizeStructRawValueGetterBody, storedVar); @@ -734,7 +729,6 @@ static AccessorDecl *makeFieldGetterDecl(ClangImporter::Implementation &Impl, getterDecl->setIsDynamic(false); getterDecl->computeType(); - getterDecl->setValidationToChecked(); return getterDecl; } @@ -771,7 +765,6 @@ static AccessorDecl *makeFieldSetterDecl(ClangImporter::Implementation &Impl, setterDecl->setAccess(AccessLevel::Public); setterDecl->computeType(); - setterDecl->setValidationToChecked(); return setterDecl; } @@ -1106,8 +1099,6 @@ makeBitFieldAccessors(ClangImporter::Implementation &Impl, auto recordType = Ctx.getRecordType(structDecl); auto recordPointerType = Ctx.getPointerType(recordType); auto fieldType = fieldDecl->getType(); - auto fieldNameInfo = clang::DeclarationNameInfo(fieldDecl->getDeclName(), - clang::SourceLocation()); auto cGetterName = getAccessorDeclarationName(Ctx, importedStructDecl, importedFieldDecl, "getter"); @@ -1179,14 +1170,14 @@ makeBitFieldAccessors(ClangImporter::Implementation &Impl, recordType, clang::VK_RValue, clang::SourceLocation()); - auto cGetterExpr = new (Ctx) clang::MemberExpr(cGetterSelfExpr, - /*isarrow=*/ false, - clang::SourceLocation(), - fieldDecl, - fieldNameInfo, - fieldType, - clang::VK_RValue, - clang::OK_BitField); + auto cGetterExpr = clang::MemberExpr::CreateImplicit(Ctx, + cGetterSelfExpr, + /*isarrow=*/ false, + fieldDecl, + fieldType, + clang::VK_RValue, + clang::OK_BitField); + auto cGetterBody = clang::ReturnStmt::Create(Ctx, clang::SourceLocation(), cGetterExpr, @@ -1224,14 +1215,13 @@ makeBitFieldAccessors(ClangImporter::Implementation &Impl, clang::VK_RValue, clang::SourceLocation()); - auto cSetterMemberExpr = new (Ctx) clang::MemberExpr(cSetterSelfExpr, - /*isarrow=*/ true, - clang::SourceLocation(), - fieldDecl, - fieldNameInfo, - fieldType, - clang::VK_LValue, - clang::OK_BitField); + auto cSetterMemberExpr = clang::MemberExpr::CreateImplicit(Ctx, + cSetterSelfExpr, + /*isarrow=*/true, + fieldDecl, + fieldType, + clang::VK_LValue, + clang::OK_BitField); auto cSetterValueExpr = new (Ctx) clang::DeclRefExpr(Ctx, cSetterValue, false, fieldType, @@ -1319,7 +1309,6 @@ createDefaultConstructor(ClangImporter::Implementation &Impl, // Set the constructor's type. constructor->computeType(); - constructor->setValidationToChecked(); constructor->setAccess(AccessLevel::Public); @@ -1432,7 +1421,6 @@ createValueConstructor(ClangImporter::Implementation &Impl, ParamDecl(ParamDecl::Specifier::Default, SourceLoc(), SourceLoc(), argName, SourceLoc(), var->getName(), structDecl); param->setInterfaceType(var->getInterfaceType()); - param->setValidationToChecked(); Impl.recordImplicitUnwrapForDecl(param, var->isImplicitlyUnwrappedOptional()); valueParameters.push_back(param); } @@ -1449,7 +1437,6 @@ createValueConstructor(ClangImporter::Implementation &Impl, // Set the constructor's type. constructor->computeType(); - constructor->setValidationToChecked(); constructor->setAccess(AccessLevel::Public); @@ -1491,7 +1478,6 @@ static void addSynthesizedTypealias(NominalTypeDecl *nominal, Identifier name, nullptr, nominal); typealias->setUnderlyingType(underlyingType); typealias->setAccess(AccessLevel::Public); - typealias->setValidationToChecked(); typealias->setImplicit(); typealias->computeType(); @@ -1667,7 +1653,6 @@ static void makeStructRawValuedWithBridge( computedVar->setImplicit(); computedVar->setAccess(AccessLevel::Public); computedVar->setSetterAccess(AccessLevel::Private); - computedVar->setValidationToChecked(); // Create the getter for the computed value variable. auto computedVarGetter = makeStructRawValueGetter( @@ -1730,7 +1715,6 @@ buildSubscriptGetterDecl(ClangImporter::Implementation &Impl, thunk->setGenericSignature(dc->getGenericSignatureOfContext()); thunk->computeType(); - thunk->setValidationToChecked(); thunk->setAccess(getOverridableAccessLevel(dc)); @@ -1765,7 +1749,6 @@ buildSubscriptSetterDecl(ClangImporter::Implementation &Impl, new (C) ParamDecl(ParamDecl::Specifier::Default, SourceLoc(), SourceLoc(), Identifier(), loc, valueIndex->get(0)->getName(), dc); paramVarDecl->setInterfaceType(elementInterfaceTy); - paramVarDecl->setValidationToChecked(); auto valueIndicesPL = ParameterList::create(C, {paramVarDecl, index}); @@ -1785,7 +1768,6 @@ buildSubscriptSetterDecl(ClangImporter::Implementation &Impl, setter->getClangNode()); thunk->setGenericSignature(dc->getGenericSignatureOfContext()); thunk->computeType(); - thunk->setValidationToChecked(); thunk->setAccess(getOverridableAccessLevel(dc)); @@ -1954,7 +1936,6 @@ static bool addErrorDomain(NominalTypeDecl *swiftDecl, /*IsStatic*/isStatic, VarDecl::Introducer::Var, /*IsCaptureList*/false, SourceLoc(), C.Id_errorDomain, swiftDecl); errorDomainPropertyDecl->setInterfaceType(stringTy); - errorDomainPropertyDecl->setValidationToChecked(); errorDomainPropertyDecl->setAccess(AccessLevel::Public); auto *params = ParameterList::createEmpty(C); @@ -1973,7 +1954,6 @@ static bool addErrorDomain(NominalTypeDecl *swiftDecl, TypeLoc::withoutLoc(stringTy), swiftDecl); getterDecl->setStatic(isStatic); getterDecl->computeType(); - getterDecl->setValidationToChecked(); getterDecl->setIsObjC(false); getterDecl->setIsDynamic(false); getterDecl->setIsTransparent(false); @@ -2564,7 +2544,6 @@ namespace { /*genericparams*/nullptr, DC); typealias->setUnderlyingType( underlying->getDeclaredInterfaceType()); - typealias->setValidationToChecked(); typealias->computeType(); Impl.SpecialTypedefNames[Decl->getCanonicalDecl()] = @@ -2585,7 +2564,6 @@ namespace { /*genericparams*/nullptr, DC); typealias->setUnderlyingType( Impl.SwiftContext.getAnyObjectType()); - typealias->setValidationToChecked(); typealias->computeType(); Impl.SpecialTypedefNames[Decl->getCanonicalDecl()] = @@ -2654,7 +2632,6 @@ namespace { Loc, /*genericparams*/nullptr, DC); Result->setUnderlyingType(SwiftType); - Result->setValidationToChecked(); Result->computeType(); // Make Objective-C's 'id' unavailable. @@ -2808,7 +2785,6 @@ namespace { // Create the wrapper struct. errorWrapper = new (C) StructDecl(loc, name, loc, None, nullptr, dc); errorWrapper->computeType(); - errorWrapper->setValidationToChecked(); errorWrapper->setAddedImplicitInitializers(); errorWrapper->setAccess(AccessLevel::Public); errorWrapper->getAttrs().add( @@ -2843,7 +2819,6 @@ namespace { nsErrorProp->setImplicit(); nsErrorProp->setAccess(AccessLevel::Public); nsErrorProp->setInterfaceType(nsErrorType); - nsErrorProp->setValidationToChecked(); // Create a pattern binding to describe the variable. Pattern *nsErrorPattern = createTypedNamedPattern(nsErrorProp); @@ -2921,7 +2896,6 @@ namespace { rawValue->setAccess(AccessLevel::Public); rawValue->setSetterAccess(AccessLevel::Private); rawValue->setInterfaceType(underlyingType); - rawValue->setValidationToChecked(); // Create a pattern binding to describe the variable. Pattern *varPattern = createTypedNamedPattern(rawValue); @@ -2950,7 +2924,6 @@ namespace { C.Id_ErrorType, loc, /*genericparams=*/nullptr, enumDecl); alias->setUnderlyingType(errorWrapper->getDeclaredInterfaceType()); - alias->setValidationToChecked(); alias->computeType(); enumDecl->addMember(alias); @@ -3778,7 +3751,6 @@ namespace { result->setIsObjC(false); result->setIsDynamic(false); result->computeType(); - result->setValidationToChecked(); Impl.recordImplicitUnwrapForDecl(result, importedType.isImplicitlyUnwrapped()); @@ -4036,7 +4008,6 @@ namespace { Loc, /*genericparams*/nullptr, DC); Result->setUnderlyingType(SwiftTypeDecl->getDeclaredInterfaceType()); - Result->setValidationToChecked(); Result->computeType(); return Result; @@ -4367,7 +4338,6 @@ namespace { // Compute the interface type. result->computeType(); - result->setValidationToChecked(); Impl.recordImplicitUnwrapForDecl(result, isIUO); @@ -4575,7 +4545,6 @@ namespace { SmallVector inheritedTypes; importObjCProtocols(result, decl->getReferencedProtocols(), inheritedTypes); - result->setValidationToChecked(); result->setInherited(Impl.SwiftContext.AllocateCopy(inheritedTypes)); result->setMemberLoader(&Impl, 0); @@ -5172,7 +5141,6 @@ namespace { } typealias->setUnderlyingType(typeDecl->getDeclaredInterfaceType()); - typealias->setValidationToChecked(); typealias->computeType(); return typealias; } @@ -5409,7 +5377,6 @@ Decl *SwiftDeclConverter::importCompatibilityTypeAlias( } alias->setUnderlyingType(typeDecl->getDeclaredInterfaceType()); - alias->setValidationToChecked(); alias->computeType(); // Record that this is the official version of this declaration. @@ -5819,7 +5786,6 @@ Decl *SwiftDeclConverter::importGlobalAsInitializer( ParamDecl::Specifier::Default, SourceLoc(), SourceLoc(), argNames.front(), SourceLoc(), argNames.front(), dc); paramDecl->setInterfaceType(Impl.SwiftContext.TheEmptyTupleType); - paramDecl->setValidationToChecked(); parameterList = ParameterList::createWithoutLoc(paramDecl); } else { @@ -8141,7 +8107,6 @@ ClangImporter::Implementation::importDeclContextOf( nominal->getDeclaredType()); SwiftContext.evaluator.cacheOutput(ExtendedNominalRequest{ext}, std::move(nominal)); - ext->setValidationToChecked(); ext->setMemberLoader(this, reinterpret_cast(declSubmodule)); if (auto protoDecl = ext->getExtendedProtocolDecl()) { @@ -8187,10 +8152,12 @@ ClangImporter::Implementation::createConstant(Identifier name, DeclContext *dc, case clang::APValue::Array: case clang::APValue::ComplexFloat: case clang::APValue::ComplexInt: + case clang::APValue::FixedPoint: + case clang::APValue::Indeterminate: case clang::APValue::LValue: case clang::APValue::MemberPointer: + case clang::APValue::None: case clang::APValue::Struct: - case clang::APValue::Uninitialized: case clang::APValue::Union: case clang::APValue::Vector: llvm_unreachable("Unhandled APValue kind"); @@ -8385,7 +8352,6 @@ ClangImporter::Implementation::createConstant(Identifier name, DeclContext *dc, var = new (SwiftContext) VarDecl(/*IsStatic*/isStatic, VarDecl::Introducer::Var, /*IsCaptureList*/false, SourceLoc(), name, dc); - var->setValidationToChecked(); } var->setInterfaceType(type); @@ -8410,7 +8376,6 @@ ClangImporter::Implementation::createConstant(Identifier name, DeclContext *dc, func->setStatic(isStatic); func->computeType(); func->setAccess(getOverridableAccessLevel(dc)); - func->setValidationToChecked(); func->setIsObjC(false); func->setIsDynamic(false); diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index 440c90e85d2..57fc37bce4d 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -178,13 +178,15 @@ namespace { return IR; } + ImportResult VisitType(const Type*) = delete; + #define DEPENDENT_TYPE(Class, Base) \ ImportResult Visit##Class##Type(const clang::Class##Type *) { \ llvm_unreachable("Dependent types cannot be converted"); \ } #define TYPE(Class, Base) #include "clang/AST/TypeNodes.def" - + // Given a loaded type like CInt, look through the type alias sugar that the // stdlib uses to show the underlying type. We want to import the signature // of the exit(3) libc function as "func exit(Int32)", not as @@ -318,11 +320,31 @@ namespace { // OpenMP types that don't have Swift equivalents. case clang::BuiltinType::OMPArraySection: return Type(); + + // SVE builtin types that don't have Swift equivalents. + case clang::BuiltinType::SveInt8: + case clang::BuiltinType::SveInt16: + case clang::BuiltinType::SveInt32: + case clang::BuiltinType::SveInt64: + case clang::BuiltinType::SveUint8: + case clang::BuiltinType::SveUint16: + case clang::BuiltinType::SveUint32: + case clang::BuiltinType::SveUint64: + case clang::BuiltinType::SveFloat16: + case clang::BuiltinType::SveFloat32: + case clang::BuiltinType::SveFloat64: + case clang::BuiltinType::SveBool: + return Type(); } llvm_unreachable("Invalid BuiltinType."); } + ImportResult VisitPipeType(const clang::PipeType *) { + // OpenCL types are not supported in Swift. + return Type(); + } + ImportResult VisitComplexType(const clang::ComplexType *type) { // FIXME: Implement once Complex is in the library. return Type(); @@ -768,12 +790,11 @@ namespace { SUGAR_TYPE(SubstTemplateTypeParm) SUGAR_TYPE(TemplateSpecialization) SUGAR_TYPE(Auto) + SUGAR_TYPE(DeducedTemplateSpecialization) SUGAR_TYPE(Adjusted) SUGAR_TYPE(PackExpansion) - - ImportResult VisitAttributedType(const clang::AttributedType *type) { - return Visit(type->desugar()); - } + SUGAR_TYPE(Attributed) + SUGAR_TYPE(MacroQualified) ImportResult VisitDecayedType(const clang::DecayedType *type) { clang::ASTContext &clangCtx = Impl.getClangASTContext(); diff --git a/lib/ClangImporter/ImporterImpl.h b/lib/ClangImporter/ImporterImpl.h index ca5ceb35b5e..92107215752 100644 --- a/lib/ClangImporter/ImporterImpl.h +++ b/lib/ClangImporter/ImporterImpl.h @@ -1234,8 +1234,6 @@ public: D->setAccess(access); if (auto ASD = dyn_cast(D)) ASD->setSetterAccess(access); - // All imported decls are constructed fully validated. - D->setValidationToChecked(); if (auto AFD = dyn_cast(static_cast(D))) AFD->setNeedsNewVTableEntry(false); return D; diff --git a/lib/ClangImporter/SwiftLookupTable.h b/lib/ClangImporter/SwiftLookupTable.h index 977a31f1f0e..168428bde00 100644 --- a/lib/ClangImporter/SwiftLookupTable.h +++ b/lib/ClangImporter/SwiftLookupTable.h @@ -309,8 +309,8 @@ public: static bool contextRequiresName(ContextKind kind); /// A single entry referencing either a named declaration or a macro. - typedef llvm::PointerUnion3 + typedef llvm::PointerUnion SingleEntry; /// A stored version of the context of an entity, which is Clang diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp index 04df4698c4e..f6b5c3d4a8f 100644 --- a/lib/Demangling/Demangler.cpp +++ b/lib/Demangling/Demangler.cpp @@ -317,6 +317,7 @@ Node::iterator Node::end() const { } void Node::addChild(NodePointer Child, NodeFactory &Factory) { + assert(Child); switch (NodePayloadKind) { case PayloadKind::None: InlineChildren[0] = Child; diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index 13952af1d04..df6b3decd53 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -46,17 +46,15 @@ CompilerInstance::CompilerInstance() = default; CompilerInstance::~CompilerInstance() = default; std::string CompilerInvocation::getPCHHash() const { - using llvm::hash_code; - using llvm::hash_value; using llvm::hash_combine; - auto Code = hash_value(LangOpts.getPCHHashComponents()); - Code = hash_combine(Code, FrontendOpts.getPCHHashComponents()); - Code = hash_combine(Code, ClangImporterOpts.getPCHHashComponents()); - Code = hash_combine(Code, SearchPathOpts.getPCHHashComponents()); - Code = hash_combine(Code, DiagnosticOpts.getPCHHashComponents()); - Code = hash_combine(Code, SILOpts.getPCHHashComponents()); - Code = hash_combine(Code, IRGenOpts.getPCHHashComponents()); + auto Code = hash_combine(LangOpts.getPCHHashComponents(), + FrontendOpts.getPCHHashComponents(), + ClangImporterOpts.getPCHHashComponents(), + SearchPathOpts.getPCHHashComponents(), + DiagnosticOpts.getPCHHashComponents(), + SILOpts.getPCHHashComponents(), + IRGenOpts.getPCHHashComponents()); return llvm::APInt(64, Code).toString(36, /*Signed=*/false); } @@ -253,9 +251,6 @@ static bool loadAndValidateVFSOverlay( const llvm::IntrusiveRefCntPtr &BaseFS, const llvm::IntrusiveRefCntPtr &OverlayFS, DiagnosticEngine &Diag) { - // FIXME: It should be possible to allow chained lookup of later VFS overlays - // through the mapping defined by earlier overlays. - // See rdar://problem/39440687 auto Buffer = BaseFS->getBufferForFile(File); if (!Buffer) { Diag.diagnose(SourceLoc(), diag::cannot_open_file, File, diff --git a/lib/Frontend/ModuleInterfaceLoader.cpp b/lib/Frontend/ModuleInterfaceLoader.cpp index d61714a88bc..d77111a6623 100644 --- a/lib/Frontend/ModuleInterfaceLoader.cpp +++ b/lib/Frontend/ModuleInterfaceLoader.cpp @@ -380,31 +380,36 @@ class ModuleInterfaceLoaderImpl { /// with dead entries -- when other factors change, such as the contents of /// the .swiftinterface input or its dependencies. std::string getCacheHash(const CompilerInvocation &SubInvocation) { - // Start with the compiler version (which will be either tag names or revs). - // Explicitly don't pass in the "effective" language version -- this would - // mean modules built in different -swift-version modes would rebuild their - // dependencies. - llvm::hash_code H = hash_value(swift::version::getSwiftFullVersion()); + auto normalizedTargetTriple = + getTargetSpecificModuleTriple(SubInvocation.getLangOptions().Target); - // Simplest representation of input "identity" (not content) is just a - // pathname, and probably all we can get from the VFS in this regard - // anyways. - H = hash_combine(H, interfacePath); + llvm::hash_code H = hash_combine( + // Start with the compiler version (which will be either tag names or + // revs). Explicitly don't pass in the "effective" language version -- + // this would mean modules built in different -swift-version modes would + // rebuild their dependencies. + swift::version::getSwiftFullVersion(), - // Include the target CPU architecture. In practice, .swiftinterface files - // will be in architecture-specific subdirectories and would have - // architecture-specific pieces #if'd out. However, it doesn't hurt to - // include it, and it guards against mistakenly reusing cached modules - // across architectures. - H = hash_combine(H, SubInvocation.getLangOptions().Target.getArchName()); + // Simplest representation of input "identity" (not content) is just a + // pathname, and probably all we can get from the VFS in this regard + // anyways. + interfacePath, - // The SDK path is going to affect how this module is imported, so include - // it. - H = hash_combine(H, SubInvocation.getSDKPath()); + // Include the normalized target triple. In practice, .swiftinterface + // files will be in target-specific subdirectories and would have + // target-specific pieces #if'd out. However, it doesn't hurt to include + // it, and it guards against mistakenly reusing cached modules across + // targets. Note that this normalization explicitly doesn't include the + // minimum deployment target (e.g. the '12.0' in 'ios12.0'). + normalizedTargetTriple.str(), - // Whether or not we're tracking system dependencies affects the - // invalidation behavior of this cache item. - H = hash_combine(H, SubInvocation.getFrontendOptions().TrackSystemDeps); + // The SDK path is going to affect how this module is imported, so + // include it. + SubInvocation.getSDKPath(), + + // Whether or not we're tracking system dependencies affects the + // invalidation behavior of this cache item. + SubInvocation.getFrontendOptions().TrackSystemDeps); return llvm::APInt(64, H).toString(36, /*Signed=*/false); } diff --git a/lib/Frontend/PrintingDiagnosticConsumer.cpp b/lib/Frontend/PrintingDiagnosticConsumer.cpp index 0b9e322cbd5..0cba82aab26 100644 --- a/lib/Frontend/PrintingDiagnosticConsumer.cpp +++ b/lib/Frontend/PrintingDiagnosticConsumer.cpp @@ -68,6 +68,25 @@ void PrintingDiagnosticConsumer::handleDiagnostic( StringRef FormatString, ArrayRef FormatArgs, const DiagnosticInfo &Info, const SourceLoc bufferIndirectlyCausingDiagnostic) { + if (Info.IsChildNote) + return; + + printDiagnostic(SM, Loc, Kind, FormatString, FormatArgs, Info, + bufferIndirectlyCausingDiagnostic); + + for (auto ChildInfo : Info.ChildDiagnosticInfo) { + printDiagnostic(SM, ChildInfo->Loc, ChildInfo->Kind, + ChildInfo->FormatString, ChildInfo->FormatArgs, *ChildInfo, + ChildInfo->BufferIndirectlyCausingDiagnostic); + } +} + +void PrintingDiagnosticConsumer::printDiagnostic( + SourceManager &SM, SourceLoc Loc, DiagnosticKind Kind, + StringRef FormatString, ArrayRef FormatArgs, + const DiagnosticInfo &Info, + const SourceLoc bufferIndirectlyCausingDiagnostic) { + // Determine what kind of diagnostic we're emitting. llvm::SourceMgr::DiagKind SMKind; switch (Kind) { diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index e3f45ba4152..7596ee59aa8 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -406,7 +406,8 @@ static bool writeSIL(SILModule &SM, ModuleDecl *M, bool EmitVerboseSIL, auto OS = getFileOutputStream(OutputFilename, M->getASTContext()); if (!OS) return true; SM.print(*OS, EmitVerboseSIL, M, SortSIL); - return false; + + return M->getASTContext().hadError(); } static bool writeSIL(SILModule &SM, const PrimarySpecificPaths &PSPs, diff --git a/lib/IDE/SyntaxModel.cpp b/lib/IDE/SyntaxModel.cpp index 33f07fbcd2f..05884008786 100644 --- a/lib/IDE/SyntaxModel.cpp +++ b/lib/IDE/SyntaxModel.cpp @@ -916,7 +916,7 @@ bool ModelASTWalker::walkToDeclPre(Decl *D) { EnumElemD->getName().getLength()); } - if (auto *E = EnumElemD->getRawValueExpr()) { + if (auto *E = EnumElemD->getRawValueUnchecked()) { SourceRange ElemRange = E->getSourceRange(); SN.Elements.emplace_back(SyntaxStructureElementKind::InitExpr, charSourceRangeFromSourceRange(SM, ElemRange)); diff --git a/lib/IDE/Utils.cpp b/lib/IDE/Utils.cpp index cda233c4c42..ec7393c3763 100644 --- a/lib/IDE/Utils.cpp +++ b/lib/IDE/Utils.cpp @@ -481,7 +481,7 @@ ide::replacePlaceholders(std::unique_ptr InputBuf, static std::string getPlistEntry(const llvm::Twine &Path, StringRef KeyName) { auto BufOrErr = llvm::MemoryBuffer::getFile(Path); if (!BufOrErr) { - llvm::errs() << BufOrErr.getError().message() << '\n'; + llvm::errs() << "could not open '" << Path << "': " << BufOrErr.getError().message() << '\n'; return {}; } diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp index c996d87679e..89ce5bf08e4 100644 --- a/lib/IRGen/GenCall.cpp +++ b/lib/IRGen/GenCall.cpp @@ -869,6 +869,21 @@ namespace { case clang::BuiltinType::OCLIntelSubgroupAVCImeDualRefStreamin: llvm_unreachable("OpenCL type in ABI lowering"); + // We should never see the SVE types at all. + case clang::BuiltinType::SveInt8: + case clang::BuiltinType::SveInt16: + case clang::BuiltinType::SveInt32: + case clang::BuiltinType::SveInt64: + case clang::BuiltinType::SveUint8: + case clang::BuiltinType::SveUint16: + case clang::BuiltinType::SveUint32: + case clang::BuiltinType::SveUint64: + case clang::BuiltinType::SveFloat16: + case clang::BuiltinType::SveFloat32: + case clang::BuiltinType::SveFloat64: + case clang::BuiltinType::SveBool: + llvm_unreachable("SVE type in ABI lowering"); + // Handle all the integer types as opaque values. #define BUILTIN_TYPE(Id, SingletonId) #define SIGNED_TYPE(Id, SingletonId) \ @@ -1607,7 +1622,7 @@ llvm::CallSite CallEmission::emitCallSite() { { opaqueCallee }); opaqueCallee = IGF.Builder.CreateBitCast(opaqueCallee, origCallee->getType()); - call->setCalledFunction(opaqueCallee); + call->setCalledFunction(fn.getFunctionType(), opaqueCallee); // Reset the insert point to after the call. IGF.Builder.SetInsertPoint(call->getParent()); diff --git a/lib/IRGen/GenClangType.cpp b/lib/IRGen/GenClangType.cpp index 00dfd1fd016..dca3107e61c 100644 --- a/lib/IRGen/GenClangType.cpp +++ b/lib/IRGen/GenClangType.cpp @@ -86,6 +86,10 @@ getClangBuiltinTypeFromKind(const clang::ASTContext &context, case clang::BuiltinType::Id: \ return context.Id##Ty; #include "clang/Basic/OpenCLExtensionTypes.def" +#define SVE_TYPE(Name, Id, SingletonId) \ + case clang::BuiltinType::Id: \ + return context.SingletonId; +#include "clang/Basic/AArch64SVEACLETypes.def" } llvm_unreachable("Not a valid BuiltinType."); diff --git a/lib/IRGen/GenClass.cpp b/lib/IRGen/GenClass.cpp index 302f9c13fa7..7543269a382 100644 --- a/lib/IRGen/GenClass.cpp +++ b/lib/IRGen/GenClass.cpp @@ -1998,6 +1998,7 @@ namespace { case llvm::Triple::MachO: var->setSection("__DATA, __objc_const"); break; + case llvm::Triple::XCOFF: case llvm::Triple::COFF: var->setSection(".data"); break; diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 1068cb8e830..9567db34be2 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -41,7 +41,6 @@ #include "llvm/IR/GlobalAlias.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/Module.h" -#include "llvm/IR/TypeBuilder.h" #include "llvm/IR/Value.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ConvertUTF.h" @@ -911,6 +910,7 @@ std::string IRGenModule::GetObjCSectionName(StringRef Section, : ("__DATA," + Section + "," + MachOAttributes).str(); case llvm::Triple::ELF: return Section.substr(2).str(); + case llvm::Triple::XCOFF: case llvm::Triple::COFF: return ("." + Section.substr(2) + "$B").str(); case llvm::Triple::Wasm: @@ -942,6 +942,7 @@ void IRGenModule::SetCStringLiteralSection(llvm::GlobalVariable *GV, } case llvm::Triple::ELF: return; + case llvm::Triple::XCOFF: case llvm::Triple::COFF: return; case llvm::Triple::Wasm: @@ -1351,6 +1352,7 @@ static std::string getDynamicReplacementSection(IRGenModule &IGM) { case llvm::Triple::Wasm: sectionName = "swift5_replace"; break; + case llvm::Triple::XCOFF: case llvm::Triple::COFF: sectionName = ".sw5repl$B"; break; @@ -1371,6 +1373,7 @@ static std::string getDynamicReplacementSomeSection(IRGenModule &IGM) { case llvm::Triple::Wasm: sectionName = "swift5_replac2"; break; + case llvm::Triple::XCOFF: case llvm::Triple::COFF: sectionName = ".sw5reps$B"; break; @@ -3043,6 +3046,7 @@ llvm::Constant *IRGenModule::emitSwiftProtocols() { case llvm::Triple::Wasm: sectionName = "swift5_protocols"; break; + case llvm::Triple::XCOFF: case llvm::Triple::COFF: sectionName = ".sw5prt$B"; break; @@ -3103,6 +3107,7 @@ llvm::Constant *IRGenModule::emitProtocolConformances() { case llvm::Triple::Wasm: sectionName = "swift5_protocol_conformances"; break; + case llvm::Triple::XCOFF: case llvm::Triple::COFF: sectionName = ".sw5prtc$B"; break; @@ -3128,6 +3133,7 @@ llvm::Constant *IRGenModule::emitTypeMetadataRecords() { case llvm::Triple::Wasm: sectionName = "swift5_type_metadata"; break; + case llvm::Triple::XCOFF: case llvm::Triple::COFF: sectionName = ".sw5tymd$B"; break; @@ -3196,6 +3202,7 @@ llvm::Constant *IRGenModule::emitFieldDescriptors() { case llvm::Triple::Wasm: sectionName = "swift5_fieldmd"; break; + case llvm::Triple::XCOFF: case llvm::Triple::COFF: sectionName = ".sw5flmd$B"; break; @@ -4473,7 +4480,10 @@ IRGenModule::getOrCreateHelperFunction(StringRef fnName, llvm::Type *resultTy, llvm::FunctionType *fnTy = llvm::FunctionType::get(resultTy, paramTys, false); - llvm::Constant *fn = Module.getOrInsertFunction(fnName, fnTy); + llvm::Constant *fn = + cast(Module.getOrInsertFunction(fnName, fnTy) + .getCallee() + ->stripPointerCasts()); if (llvm::Function *def = shouldDefineHelper(*this, fn, setIsNoInline)) { IRGenFunction IGF(*this, def); diff --git a/lib/IRGen/GenEnum.cpp b/lib/IRGen/GenEnum.cpp index daf017d338c..7108fe82f08 100644 --- a/lib/IRGen/GenEnum.cpp +++ b/lib/IRGen/GenEnum.cpp @@ -1128,7 +1128,7 @@ namespace { int64_t getDiscriminatorIndex(EnumElementDecl *target) const override { // The elements are assigned discriminators ABI-compatible with their // raw values from C. - assert(target->hasRawValueExpr() + assert(target->getRawValueExpr() && "c-compatible enum elt has no raw value?!"); auto intExpr = cast(target->getRawValueExpr()); auto intType = getDiscriminatorType(); diff --git a/lib/IRGen/GenKeyPath.cpp b/lib/IRGen/GenKeyPath.cpp index 88b7e8f07e8..e014f91a013 100644 --- a/lib/IRGen/GenKeyPath.cpp +++ b/lib/IRGen/GenKeyPath.cpp @@ -929,7 +929,7 @@ emitKeyPathComponent(IRGenModule &IGM, fnName.append("keypath_get_selector_"); fnName.append(selectorName); auto fn = cast( - IGM.Module.getOrInsertFunction(fnName, fnTy)); + IGM.Module.getOrInsertFunction(fnName, fnTy).getCallee()); if (fn->empty()) { fn->setLinkage(llvm::Function::PrivateLinkage); IRGenFunction subIGF(IGM, fn); diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index ca1efb045fb..aa570cf02c3 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -115,6 +115,7 @@ void IRGenModule::setTrueConstGlobal(llvm::GlobalVariable *var) { case llvm::Triple::ELF: var->setSection(".rodata"); break; + case llvm::Triple::XCOFF: case llvm::Triple::COFF: var->setSection(".rdata"); break; diff --git a/lib/IRGen/GenObjC.cpp b/lib/IRGen/GenObjC.cpp index ec7d69af906..cd8feb4bf8d 100644 --- a/lib/IRGen/GenObjC.cpp +++ b/lib/IRGen/GenObjC.cpp @@ -364,6 +364,11 @@ IRGenModule::getObjCProtocolGlobalVars(ProtocolDecl *proto) { protocolLabel->setSection(GetObjCSectionName("__objc_protolist", "coalesced,no_dead_strip")); + // Mark used to prevent DCE of public unreferenced protocols to ensure + // that they are available for external use when a used module is used + // as a library. + addUsedGlobal(protocolLabel); + // Introduce a variable to reference the protocol. auto *protocolRef = new llvm::GlobalVariable(Module, Int8PtrTy, /*constant*/ false, @@ -375,6 +380,11 @@ IRGenModule::getObjCProtocolGlobalVars(ProtocolDecl *proto) { protocolRef->setSection(GetObjCSectionName("__objc_protorefs", "coalesced,no_dead_strip")); + // Mark used to prevent DCE of public unreferenced protocols to ensure + // that they are available for external use when a used module is used + // as a library. + addUsedGlobal(protocolRef); + ObjCProtocolPair pair{protocolRecord, protocolRef}; ObjCProtocols.insert({proto, pair}); diff --git a/lib/IRGen/GenReflection.cpp b/lib/IRGen/GenReflection.cpp index 3edd7e51bee..50eeb1126a6 100644 --- a/lib/IRGen/GenReflection.cpp +++ b/lib/IRGen/GenReflection.cpp @@ -1129,6 +1129,7 @@ static std::string getReflectionSectionName(IRGenModule &IGM, switch (IGM.TargetInfo.OutputObjectFormat) { case llvm::Triple::UnknownObjectFormat: llvm_unreachable("unknown object format"); + case llvm::Triple::XCOFF: case llvm::Triple::COFF: assert(FourCC.size() <= 4 && "COFF section name length must be <= 8 characters"); diff --git a/lib/IRGen/IRGen.cpp b/lib/IRGen/IRGen.cpp index dd947091077..a7f3fc0643f 100644 --- a/lib/IRGen/IRGen.cpp +++ b/lib/IRGen/IRGen.cpp @@ -70,6 +70,8 @@ #include "llvm/Transforms/IPO/AlwaysInliner.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" #include "llvm/Transforms/Instrumentation.h" +#include "llvm/Transforms/Instrumentation/AddressSanitizer.h" +#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h" #include "llvm/Transforms/ObjCARC.h" #include @@ -125,12 +127,12 @@ static void addSwiftMergeFunctionsPass(const PassManagerBuilder &Builder, static void addAddressSanitizerPasses(const PassManagerBuilder &Builder, legacy::PassManagerBase &PM) { PM.add(createAddressSanitizerFunctionPass()); - PM.add(createAddressSanitizerModulePass()); + PM.add(createModuleAddressSanitizerLegacyPassPass()); } static void addThreadSanitizerPass(const PassManagerBuilder &Builder, legacy::PassManagerBase &PM) { - PM.add(createThreadSanitizerPass()); + PM.add(createThreadSanitizerLegacyPassPass()); } static void addSanitizerCoveragePass(const PassManagerBuilder &Builder, @@ -383,11 +385,13 @@ static bool needsRecompile(StringRef OutputFilename, ArrayRef HashData, StringRef SectionName; Section.getName(SectionName); if (SectionName == HashSectionName) { - StringRef SectionData; - Section.getContents(SectionData); + llvm::Expected SectionData = Section.getContents(); + if (!SectionData) { + return true; + } ArrayRef PrevHashData( - reinterpret_cast(SectionData.data()), - SectionData.size()); + reinterpret_cast(SectionData->data()), + SectionData->size()); LLVM_DEBUG(if (PrevHashData.size() == sizeof(MD5::MD5Result)) { if (DiagMutex) DiagMutex->lock(); SmallString<32> HashStr; @@ -1298,6 +1302,7 @@ swift::createSwiftModuleObjectFile(SILModule &SILMod, StringRef Buffer, switch (IGM.TargetInfo.OutputObjectFormat) { case llvm::Triple::UnknownObjectFormat: llvm_unreachable("unknown object format"); + case llvm::Triple::XCOFF: case llvm::Triple::COFF: Section = COFFASTSectionName; break; diff --git a/lib/IRGen/IRGenDebugInfo.cpp b/lib/IRGen/IRGenDebugInfo.cpp index 75812053a56..91d40d3be00 100644 --- a/lib/IRGen/IRGenDebugInfo.cpp +++ b/lib/IRGen/IRGenDebugInfo.cpp @@ -168,8 +168,7 @@ public: void emitVariableDeclaration(IRBuilder &Builder, ArrayRef Storage, DebugTypeInfo Ty, const SILDebugScope *DS, - ValueDecl *VarDecl, StringRef Name, - unsigned ArgNo = 0, + ValueDecl *VarDecl, SILDebugVariable VarInfo, IndirectionKind = DirectValue, ArtificialKind = RealValue); void emitDbgIntrinsic(IRBuilder &Builder, llvm::Value *Storage, @@ -309,7 +308,7 @@ private: // reports back a size. while (isa(Ty) && !Ty->getSizeInBits()) { auto *DT = cast(Ty); - Ty = DT->getBaseType().resolve(); + Ty = DT->getBaseType(); if (!Ty) return 0; } @@ -320,7 +319,7 @@ private: /// Return the size reported by the variable's type. static unsigned getSizeInBits(const llvm::DILocalVariable *Var) { - llvm::DIType *Ty = Var->getType().resolve(); + llvm::DIType *Ty = Var->getType(); return getSizeInBits(Ty); } @@ -734,7 +733,6 @@ private: NoLoc, NoLoc, IGM.Context.getIdentifier(ArchetypeName), NoLoc, /*genericparams*/ nullptr, IGM.Context.TheBuiltinModule); Entry->setUnderlyingType(IGM.Context.TheRawPointerType); - Entry->setValidationToChecked(); Entry->computeType(); return Entry; } @@ -2133,7 +2131,7 @@ void IRGenDebugInfoImpl::emitArtificialFunction(IRBuilder &Builder, void IRGenDebugInfoImpl::emitVariableDeclaration( IRBuilder &Builder, ArrayRef Storage, DebugTypeInfo DbgTy, - const SILDebugScope *DS, ValueDecl *VarDecl, StringRef Name, unsigned ArgNo, + const SILDebugScope *DS, ValueDecl *VarDecl, SILDebugVariable VarInfo, IndirectionKind Indirection, ArtificialKind Artificial) { assert(DS && "variable has no scope"); @@ -2153,7 +2151,7 @@ void IRGenDebugInfoImpl::emitVariableDeclaration( // FIXME: this should be the scope of the type's declaration. // If this is an argument, attach it to the current function scope. - if (ArgNo > 0) { + if (VarInfo.ArgNo > 0) { while (isa(Scope)) Scope = cast(Scope)->getScope(); } @@ -2161,11 +2159,13 @@ void IRGenDebugInfoImpl::emitVariableDeclaration( llvm::DIFile *Unit = getFile(Scope); llvm::DIType *DITy = getOrCreateType(DbgTy); assert(DITy && "could not determine debug type of variable"); + if (VarInfo.Constant) + DITy = DBuilder.createQualifiedType(llvm::dwarf::DW_TAG_const_type, DITy); unsigned Line = Loc.Line; // Self is always an artificial argument, so are variables without location. - if (!Line || (ArgNo > 0 && Name == IGM.Context.Id_self.str())) + if (!Line || (VarInfo.ArgNo > 0 && VarInfo.Name == IGM.Context.Id_self.str())) Artificial = ArtificialValue; llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; @@ -2176,10 +2176,11 @@ void IRGenDebugInfoImpl::emitVariableDeclaration( bool Optimized = false; // Create the descriptor for the variable. llvm::DILocalVariable *Var = - (ArgNo > 0) ? DBuilder.createParameterVariable( - Scope, Name, ArgNo, Unit, Line, DITy, Optimized, Flags) - : DBuilder.createAutoVariable(Scope, Name, Unit, Line, DITy, - Optimized, Flags); + (VarInfo.ArgNo > 0) + ? DBuilder.createParameterVariable(Scope, VarInfo.Name, VarInfo.ArgNo, + Unit, Line, DITy, Optimized, Flags) + : DBuilder.createAutoVariable(Scope, VarInfo.Name, Unit, Line, DITy, + Optimized, Flags); // Running variables for the current/previous piece. bool IsPiece = Storage.size() > 1; @@ -2263,8 +2264,14 @@ void IRGenDebugInfoImpl::emitGlobalVariableDeclaration( if (Opts.DebugInfoLevel <= IRGenDebugInfoLevel::LineTables) return; - llvm::DIType *Ty = getOrCreateType(DbgTy); - if (Ty->isArtificial() || Ty == InternalType || !Loc) + llvm::DIType *DITy = getOrCreateType(DbgTy); + VarDecl *VD = nullptr; + if (Loc) + VD = dyn_cast_or_null(Loc->getAsASTNode()); + if (!VD || VD->isLet()) + DITy = DBuilder.createQualifiedType(llvm::dwarf::DW_TAG_const_type, DITy); + + if (DITy->isArtificial() || DITy == InternalType || !Loc) // FIXME: Really these should be marked as artificial, but LLVM // currently has no support for flags to be put on global // variables. In the mean time, elide these variables, they @@ -2272,7 +2279,7 @@ void IRGenDebugInfoImpl::emitGlobalVariableDeclaration( return; if (InFixedBuffer) - Ty = createFixedValueBufferStruct(Ty); + DITy = createFixedValueBufferStruct(DITy); auto L = getStartLocation(Loc); auto File = getOrCreateFile(L.Filename); @@ -2282,7 +2289,7 @@ void IRGenDebugInfoImpl::emitGlobalVariableDeclaration( if (!Var) Expr = DBuilder.createConstantValueExpression(0); auto *GV = DBuilder.createGlobalVariableExpression( - MainModule, Name, LinkageName, File, L.Line, Ty, IsLocalToUnit, Expr); + MainModule, Name, LinkageName, File, L.Line, DITy, IsLocalToUnit, Expr); if (Var) Var->addDebugInfo(GV); } @@ -2308,7 +2315,7 @@ void IRGenDebugInfoImpl::emitTypeMetadata(IRGenFunction &IGF, Metadata->getType(), Size(CI.getTargetInfo().getPointerWidth(0)), Alignment(CI.getTargetInfo().getPointerAlign(0))); emitVariableDeclaration(IGF.Builder, Metadata, DbgTy, IGF.getDebugScope(), - nullptr, OS.str().str(), 0, + nullptr, {OS.str().str(), 0, false}, // swift.type is already a pointer type, // having a shadow copy doesn't add another // layer of indirection. @@ -2407,11 +2414,10 @@ void IRGenDebugInfo::emitArtificialFunction(IRBuilder &Builder, void IRGenDebugInfo::emitVariableDeclaration( IRBuilder &Builder, ArrayRef Storage, DebugTypeInfo Ty, - const SILDebugScope *DS, ValueDecl *VarDecl, StringRef Name, - unsigned ArgNo, IndirectionKind Indirection, - ArtificialKind Artificial) { + const SILDebugScope *DS, ValueDecl *VarDecl, SILDebugVariable VarInfo, + IndirectionKind Indirection, ArtificialKind Artificial) { static_cast(this)->emitVariableDeclaration( - Builder, Storage, Ty, DS, VarDecl, Name, ArgNo, Indirection, Artificial); + Builder, Storage, Ty, DS, VarDecl, VarInfo, Indirection, Artificial); } void IRGenDebugInfo::emitDbgIntrinsic(IRBuilder &Builder, llvm::Value *Storage, diff --git a/lib/IRGen/IRGenDebugInfo.h b/lib/IRGen/IRGenDebugInfo.h index 1a829811ba6..6b59daeaaf7 100644 --- a/lib/IRGen/IRGenDebugInfo.h +++ b/lib/IRGen/IRGenDebugInfo.h @@ -17,6 +17,7 @@ #ifndef SWIFT_IRGEN_DEBUGINFO_H #define SWIFT_IRGEN_DEBUGINFO_H +#include #include "DebugTypeInfo.h" #include "IRGenFunction.h" @@ -133,8 +134,7 @@ public: void emitVariableDeclaration(IRBuilder &Builder, ArrayRef Storage, DebugTypeInfo Ty, const SILDebugScope *DS, - ValueDecl *VarDecl, StringRef Name, - unsigned ArgNo = 0, + ValueDecl *VarDecl, SILDebugVariable VarInfo, IndirectionKind Indirection = DirectValue, ArtificialKind Artificial = RealValue); diff --git a/lib/IRGen/IRGenMangler.cpp b/lib/IRGen/IRGenMangler.cpp index 7ca38e80ba4..a368458702c 100644 --- a/lib/IRGen/IRGenMangler.cpp +++ b/lib/IRGen/IRGenMangler.cpp @@ -93,26 +93,44 @@ IRGenMangler::withSymbolicReferences(IRGenModule &IGM, AllowSymbolicReferences = true; CanSymbolicReference = [&IGM](SymbolicReferent s) -> bool { if (auto type = s.dyn_cast()) { - // FIXME: Sometimes we fail to emit metadata for Clang imported types - // even after noting use of their type descriptor or metadata. Work - // around by not symbolic-referencing imported types for now. - if (type->hasClangNode()) + // The short-substitution types in the standard library have compact + // manglings already, and the runtime ought to have a lookup table for + // them. Symbolic referencing would be wasteful. + if (type->getModuleContext()->isStdlibModule() + && Mangle::getStandardTypeSubst(type->getName().str())) { return false; + } - // TODO: We ought to be able to use indirect symbolic references even - // when the referent may be in another file, once the on-disk - // ObjectMemoryReader can handle them. - // Private entities are known to be accessible. - auto formalAccessScope = type->getFormalAccessScope(nullptr, true); - if ((formalAccessScope.isPublic() || formalAccessScope.isInternal()) && - (!IGM.CurSourceFile || - IGM.CurSourceFile != type->getParentSourceFile())) - return false; - - // @objc protocols don't have descriptors. - if (auto proto = dyn_cast(type)) - if (proto->isObjC()) + // TODO: We could assign a symbolic reference discriminator to refer + // to objc protocol refs. + if (auto proto = dyn_cast(type)) { + if (proto->isObjC()) { return false; + } + } + + // Classes defined in Objective-C don't have descriptors. + // TODO: We could assign a symbolic reference discriminator to refer + // to objc class refs. + if (auto clas = dyn_cast(type)) { + if (clas->hasClangNode() + && clas->getForeignClassKind() != ClassDecl::ForeignKind::CFType) { + return false; + } + } + + // TODO: ObjectMemoryReader for PE platforms still does not + // implement symbol relocations. For now, on non-Mach-O platforms, + // only symbolic reference things in the same module. + if (IGM.TargetInfo.OutputObjectFormat != llvm::Triple::MachO + && IGM.TargetInfo.OutputObjectFormat != llvm::Triple::ELF) { + auto formalAccessScope = type->getFormalAccessScope(nullptr, true); + if ((formalAccessScope.isPublic() || formalAccessScope.isInternal()) && + (!IGM.CurSourceFile || + IGM.CurSourceFile != type->getParentSourceFile())) { + return false; + } + } return true; } else if (auto opaque = s.dyn_cast()) { diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp index 042aad62656..11c201f7f98 100644 --- a/lib/IRGen/IRGenModule.cpp +++ b/lib/IRGen/IRGenModule.cpp @@ -95,7 +95,9 @@ static clang::CodeGenerator *createClangCodeGenerator(ASTContext &Context, auto &CGO = Importer->getClangCodeGenOpts(); CGO.OptimizationLevel = Opts.shouldOptimize() ? 3 : 0; - CGO.DisableFPElim = Opts.DisableFPElim; + CGO.setFramePointer(Opts.DisableFPElim + ? clang::CodeGenOptions::FramePointerKind::All + : clang::CodeGenOptions::FramePointerKind::None); CGO.DiscardValueNames = !Opts.shouldProvideValueNames(); switch (Opts.DebugInfoLevel) { case IRGenDebugInfoLevel::None: @@ -648,7 +650,8 @@ llvm::Constant *swift::getRuntimeFn(llvm::Module &Module, {argTypes.begin(), argTypes.end()}, /*isVararg*/ false); - cache = Module.getOrInsertFunction(functionName.c_str(), fnTy); + cache = + cast(Module.getOrInsertFunction(functionName.c_str(), fnTy).getCallee()); // Add any function attributes and set the calling convention. if (auto fn = dyn_cast(cache)) { @@ -894,13 +897,7 @@ bool swift::irgen::shouldRemoveTargetFeature(StringRef feature) { void IRGenModule::setHasFramePointer(llvm::AttrBuilder &Attrs, bool HasFramePointer) { - if (HasFramePointer) { - Attrs.addAttribute("no-frame-pointer-elim", "true"); - Attrs.addAttribute("no-frame-pointer-elim-non-leaf"); - } else { - Attrs.addAttribute("no-frame-pointer-elim", "false"); - Attrs.removeAttribute("no-frame-pointer-elim-non-leaf"); - } + Attrs.addAttribute("frame-pointer", HasFramePointer ? "all" : "none"); } void IRGenModule::setHasFramePointer(llvm::Function *F, @@ -1057,8 +1054,9 @@ void IRGenModule::addLinkLibrary(const LinkLibrary &linkLib) { if (linkLib.shouldForceLoad()) { llvm::SmallString<64> buf; encodeForceLoadSymbolName(buf, linkLib.getName()); - auto ForceImportThunk = - Module.getOrInsertFunction(buf, llvm::FunctionType::get(VoidTy, false)); + auto ForceImportThunk = cast( + Module.getOrInsertFunction(buf, llvm::FunctionType::get(VoidTy, false)) + .getCallee()); const IRLinkage IRL = llvm::Triple(Module.getTargetTriple()).isOSBinFormatCOFF() diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index 6ab7188e7d7..46f0183dfd8 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -761,13 +761,14 @@ public: /// Unconditionally emit a stack shadow copy of an \c llvm::Value. llvm::Value *emitShadowCopy(llvm::Value *Storage, const SILDebugScope *Scope, - StringRef Name, unsigned ArgNo, Alignment Align) { + SILDebugVariable VarInfo, Alignment Align) { if (Align.isZero()) Align = IGM.getPointerAlignment(); - auto &Alloca = ShadowStackSlots[{ArgNo, {Scope, Name}}]; + unsigned ArgNo = VarInfo.ArgNo; + auto &Alloca = ShadowStackSlots[{ArgNo, {Scope, VarInfo.Name}}]; if (!Alloca.isValid()) - Alloca = createAlloca(Storage->getType(), Align, Name+".debug"); + Alloca = createAlloca(Storage->getType(), Align, VarInfo.Name + ".debug"); zeroInit(cast(Alloca.getAddress())); ArtificialLocation AutoRestore(Scope, IGM.DebugInfo.get(), Builder); @@ -781,7 +782,7 @@ public: /// shadow copies, we lose the precise lifetime. llvm::Value *emitShadowCopyIfNeeded(llvm::Value *Storage, const SILDebugScope *Scope, - StringRef Name, unsigned ArgNo, + SILDebugVariable VarInfo, bool IsAnonymous, Alignment Align = Alignment(0)) { // Never emit shadow copies when optimizing, or if already on the stack. @@ -792,7 +793,7 @@ public: return Storage; // Always emit shadow copies for function arguments. - if (ArgNo == 0) + if (VarInfo.ArgNo == 0) // Otherwise only if debug value range extension is not feasible. if (!needsShadowCopy(Storage)) { // Mark for debug value range extension unless this is a constant, or @@ -809,22 +810,22 @@ public: return Storage; } - return emitShadowCopy(Storage, Scope, Name, ArgNo, Align); + return emitShadowCopy(Storage, Scope, VarInfo, Align); } /// Like \c emitShadowCopyIfNeeded() but takes an \c Address instead of an /// \c llvm::Value. llvm::Value *emitShadowCopyIfNeeded(Address Storage, const SILDebugScope *Scope, - StringRef Name, unsigned ArgNo, + SILDebugVariable VarInfo, bool IsAnonymous) { - return emitShadowCopyIfNeeded(Storage.getAddress(), Scope, Name, ArgNo, + return emitShadowCopyIfNeeded(Storage.getAddress(), Scope, VarInfo, IsAnonymous, Storage.getAlignment()); } /// Like \c emitShadowCopyIfNeeded() but takes an exploded value. void emitShadowCopyIfNeeded(SILValue &SILVal, const SILDebugScope *Scope, - StringRef Name, unsigned ArgNo, bool IsAnonymous, + SILDebugVariable VarInfo, bool IsAnonymous, llvm::SmallVectorImpl ©) { Explosion e = getLoweredExplosion(SILVal); @@ -840,13 +841,13 @@ public: auto vals = e.claimAll(); for (auto val : vals) copy.push_back( - emitShadowCopyIfNeeded(val, Scope, Name, ArgNo, IsAnonymous)); + emitShadowCopyIfNeeded(val, Scope, VarInfo, IsAnonymous)); return; } SILType Type = SILVal->getType(); auto <I = cast(IGM.getTypeInfo(Type)); - auto Alloca = LTI.allocateStack(*this, Type, Name+".debug"); + auto Alloca = LTI.allocateStack(*this, Type, VarInfo.Name + ".debug"); zeroInit(cast(Alloca.getAddress().getAddress())); ArtificialLocation AutoRestore(Scope, IGM.DebugInfo.get(), Builder); LTI.initialize(*this, e, Alloca.getAddress(), false /* isOutlined */); @@ -867,22 +868,18 @@ public: /// Emit debug info for a function argument or a local variable. template - void emitDebugVariableDeclaration(StorageType Storage, - DebugTypeInfo Ty, - SILType SILTy, - const SILDebugScope *DS, - VarDecl *VarDecl, - StringRef Name, - unsigned ArgNo = 0, + void emitDebugVariableDeclaration(StorageType Storage, DebugTypeInfo Ty, + SILType SILTy, const SILDebugScope *DS, + VarDecl *VarDecl, SILDebugVariable VarInfo, IndirectionKind Indirection = DirectValue) { assert(IGM.DebugInfo && "debug info not enabled"); - if (ArgNo) { + if (VarInfo.ArgNo) { PrologueLocation AutoRestore(IGM.DebugInfo.get(), Builder); IGM.DebugInfo->emitVariableDeclaration(Builder, Storage, Ty, DS, VarDecl, - Name, ArgNo, Indirection); + VarInfo, Indirection); } else IGM.DebugInfo->emitVariableDeclaration(Builder, Storage, Ty, DS, VarDecl, - Name, 0, Indirection); + VarInfo, Indirection); } void emitFailBB() { @@ -1642,9 +1639,6 @@ void IRGenSILFunction::emitSILFunction() { assert(!CurSILFn->empty() && "function has no basic blocks?!"); - if (CurSILFn->isThunk()) - IGM.setHasFramePointer(CurFn, false); - if (CurSILFn->getDynamicallyReplacedFunction()) IGM.IRGen.addDynamicReplacement(CurSILFn); @@ -3649,17 +3643,16 @@ void IRGenSILFunction::emitErrorResultVar(SILResultInfo ErrorInfo, auto ErrorResultSlot = getErrorResultSlot(IGM.silConv.getSILType(ErrorInfo)); auto Var = DbgValue->getVarInfo(); assert(Var && "error result without debug info"); - auto Storage = - emitShadowCopyIfNeeded(ErrorResultSlot.getAddress(), getDebugScope(), - Var->Name, Var->ArgNo, false); + auto Storage = emitShadowCopyIfNeeded(ErrorResultSlot.getAddress(), + getDebugScope(), *Var, false); if (!IGM.DebugInfo) return; auto DbgTy = DebugTypeInfo::getErrorResult( ErrorInfo.getType(), ErrorResultSlot->getType(), IGM.getPointerSize(), IGM.getPointerAlignment()); - IGM.DebugInfo->emitVariableDeclaration( - Builder, Storage, DbgTy, getDebugScope(), nullptr, Var->Name, Var->ArgNo, - IndirectValue, ArtificialValue); + IGM.DebugInfo->emitVariableDeclaration(Builder, Storage, DbgTy, + getDebugScope(), nullptr, *Var, + IndirectValue, ArtificialValue); } void IRGenSILFunction::visitDebugValueInst(DebugValueInst *i) { @@ -3680,7 +3673,7 @@ void IRGenSILFunction::visitDebugValueInst(DebugValueInst *i) { } bool IsAnonymous = false; - StringRef Name = getVarName(i, IsAnonymous); + VarInfo->Name = getVarName(i, IsAnonymous); DebugTypeInfo DbgTy; SILType SILTy = SILVal->getType(); auto RealTy = SILVal->getType().getASTType(); @@ -3688,7 +3681,7 @@ void IRGenSILFunction::visitDebugValueInst(DebugValueInst *i) { DbgTy = DebugTypeInfo::getLocalVariable( Decl, RealTy, getTypeInfo(SILVal->getType())); } else if (i->getFunction()->isBare() && - !SILTy.hasArchetype() && !Name.empty()) { + !SILTy.hasArchetype() && !VarInfo->Name.empty()) { // Preliminary support for .sil debug information. DbgTy = DebugTypeInfo::getFromTypeInfo(RealTy, getTypeInfo(SILTy)); } else @@ -3696,14 +3689,14 @@ void IRGenSILFunction::visitDebugValueInst(DebugValueInst *i) { // Put the value into a stack slot at -Onone. llvm::SmallVector Copy; - emitShadowCopyIfNeeded(SILVal, i->getDebugScope(), Name, VarInfo->ArgNo, - IsAnonymous, Copy); + emitShadowCopyIfNeeded(SILVal, i->getDebugScope(), *VarInfo, IsAnonymous, + Copy); bindArchetypes(DbgTy.getType()); if (!IGM.DebugInfo) return; emitDebugVariableDeclaration(Copy, DbgTy, SILTy, i->getDebugScope(), - i->getDecl(), Name, VarInfo->ArgNo); + i->getDecl(), *VarInfo); } void IRGenSILFunction::visitDebugValueAddrInst(DebugValueAddrInst *i) { @@ -3722,7 +3715,7 @@ void IRGenSILFunction::visitDebugValueAddrInst(DebugValueAddrInst *i) { assert(VarInfo && "debug_value_addr without debug info"); bool IsAnonymous = false; bool IsLoadablyByAddress = isa(SILVal); - StringRef Name = getVarName(i, IsAnonymous); + VarInfo->Name = getVarName(i, IsAnonymous); auto Addr = getLoweredAddress(SILVal).getAddress(); SILType SILTy = SILVal->getType(); auto RealType = SILTy.getASTType(); @@ -3736,9 +3729,8 @@ void IRGenSILFunction::visitDebugValueAddrInst(DebugValueAddrInst *i) { // Put the value's address into a stack slot at -Onone and emit a debug // intrinsic. emitDebugVariableDeclaration( - emitShadowCopyIfNeeded(Addr, i->getDebugScope(), Name, VarInfo->ArgNo, - IsAnonymous), - DbgTy, SILType(), i->getDebugScope(), Decl, Name, VarInfo->ArgNo, + emitShadowCopyIfNeeded(Addr, i->getDebugScope(), *VarInfo, IsAnonymous), + DbgTy, SILType(), i->getDebugScope(), Decl, *VarInfo, (IsLoadablyByAddress) ? DirectValue : IndirectValue); } @@ -4000,7 +3992,7 @@ void IRGenSILFunction::emitDebugInfoForAllocStack(AllocStackInst *i, return; bool IsAnonymous = false; - StringRef Name = getVarName(i, IsAnonymous); + VarInfo->Name = getVarName(i, IsAnonymous); // At this point addr must be an alloca or an undef. assert(isa(addr) || isa(addr) || @@ -4011,8 +4003,7 @@ void IRGenSILFunction::emitDebugInfoForAllocStack(AllocStackInst *i, if (auto *Alloca = dyn_cast(addr)) if (!Alloca->isStaticAlloca()) { // Store the address of the dynamic alloca on the stack. - addr = emitShadowCopy(addr, DS, Name, VarInfo->ArgNo, - IGM.getPointerAlignment()); + addr = emitShadowCopy(addr, DS, *VarInfo, IGM.getPointerAlignment()); Indirection = IndirectValue; } @@ -4031,8 +4022,8 @@ void IRGenSILFunction::emitDebugInfoForAllocStack(AllocStackInst *i, bindArchetypes(DbgTy.getType()); if (IGM.DebugInfo) - emitDebugVariableDeclaration(addr, DbgTy, SILTy, DS, Decl, Name, - VarInfo->ArgNo, Indirection); + emitDebugVariableDeclaration(addr, DbgTy, SILTy, DS, Decl, *VarInfo, + Indirection); } void IRGenSILFunction::visitAllocStackInst(swift::AllocStackInst *i) { @@ -4232,16 +4223,18 @@ void IRGenSILFunction::visitAllocBoxInst(swift::AllocBoxInst *i) { auto RealType = SILTy.getASTType(); auto DbgTy = DebugTypeInfo::getLocalVariable(Decl, RealType, type); + auto VarInfo = i->getVarInfo(); + assert(VarInfo && "debug_value without debug info"); + auto Storage = emitShadowCopyIfNeeded( - boxWithAddr.getAddress(), i->getDebugScope(), Name, 0, IsAnonymous); + boxWithAddr.getAddress(), i->getDebugScope(), *VarInfo, IsAnonymous); if (!IGM.DebugInfo) return; - IGM.DebugInfo->emitVariableDeclaration( - Builder, - Storage, - DbgTy, i->getDebugScope(), Decl, Name, 0, IndirectValue); + IGM.DebugInfo->emitVariableDeclaration(Builder, Storage, DbgTy, + i->getDebugScope(), Decl, *VarInfo, + IndirectValue); } void IRGenSILFunction::visitProjectBoxInst(swift::ProjectBoxInst *i) { diff --git a/lib/IRGen/LoadableByAddress.cpp b/lib/IRGen/LoadableByAddress.cpp index 2e01eaa55e7..4a3b79b25f3 100644 --- a/lib/IRGen/LoadableByAddress.cpp +++ b/lib/IRGen/LoadableByAddress.cpp @@ -27,7 +27,7 @@ #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILBuilder.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SetVector.h" #include "llvm/Support/CommandLine.h" diff --git a/lib/IRGen/MetadataRequest.cpp b/lib/IRGen/MetadataRequest.cpp index 0f6b30d0458..62adc6a2255 100644 --- a/lib/IRGen/MetadataRequest.cpp +++ b/lib/IRGen/MetadataRequest.cpp @@ -1723,7 +1723,7 @@ emitGenericTypeMetadataAccessFunction(IRGenFunction &IGF, IGM.Int8PtrTy, // arg 1 IGM.Int8PtrTy, // arg 2 IGM.TypeContextDescriptorPtrTy) // type context descriptor - ->stripPointerCasts()); + .getCallee()); if (thunkFn->empty()) { ApplyIRLinkage(IRLinkage::InternalLinkOnceODR) @@ -2195,7 +2195,7 @@ emitMetadataAccessByMangledName(IRGenFunction &IGF, CanType type, IGM.getModule() ->getOrInsertFunction("__swift_instantiateConcreteTypeFromMangledName", IGF.IGM.TypeMetadataPtrTy, cache->getType()) - ->stripPointerCasts()); + .getCallee()); if (instantiationFn->empty()) { ApplyIRLinkage(IRLinkage::InternalLinkOnceODR) .to(instantiationFn); diff --git a/lib/Index/IndexRecord.cpp b/lib/Index/IndexRecord.cpp index 162e47a6a49..6fe087b94f5 100644 --- a/lib/Index/IndexRecord.cpp +++ b/lib/Index/IndexRecord.cpp @@ -406,7 +406,7 @@ static void addModuleDependencies(ArrayRef imports, case FileUnitKind::DWARFModule: case FileUnitKind::ClangModule: { auto *LFU = cast(FU); - if (auto *F = fileMgr.getFile(LFU->getFilename())) { + if (auto F = fileMgr.getFile(LFU->getFilename())) { std::string moduleName = mod->getNameStr(); bool withoutUnitName = true; if (FU->getKind() == FileUnitKind::ClangModule) { @@ -435,7 +435,7 @@ static void addModuleDependencies(ArrayRef imports, } clang::index::writer::OpaqueModule opaqMod = moduleNameScratch.createString(moduleName); - unitWriter.addASTFileDependency(F, mod->isSystemModule(), opaqMod, + unitWriter.addASTFileDependency(*F, mod->isSystemModule(), opaqMod, withoutUnitName); } break; @@ -548,7 +548,7 @@ emitDataForSwiftSerializedModule(ModuleDecl *module, /*MainFile=*/nullptr, isSystem, /*IsModuleUnit=*/true, isDebugCompilation, targetTriple, sysrootPath, getModuleInfoFromOpaqueModule); - const clang::FileEntry *FE = fileMgr.getFile(filename); + auto FE = fileMgr.getFile(filename); bool isSystemModule = module->isSystemModule(); for (auto &pair : records) { std::string &recordFile = pair.first; @@ -556,7 +556,7 @@ emitDataForSwiftSerializedModule(ModuleDecl *module, if (recordFile.empty()) continue; clang::index::writer::OpaqueModule mod = &groupName; - unitWriter.addRecordFile(recordFile, FE, isSystemModule, mod); + unitWriter.addRecordFile(recordFile, *FE, isSystemModule, mod); } ModuleDecl::ImportFilter importFilter; @@ -586,15 +586,16 @@ recordSourceFileUnit(SourceFile *primarySourceFile, StringRef indexUnitToken, auto &fileMgr = clangCI.getFileManager(); auto *module = primarySourceFile->getParentModule(); bool isSystem = module->isSystemModule(); - auto *mainFile = fileMgr.getFile(primarySourceFile->getFilename()); + auto mainFile = fileMgr.getFile(primarySourceFile->getFilename()); // FIXME: Get real values for the following. StringRef swiftVersion; StringRef sysrootPath = clangCI.getHeaderSearchOpts().Sysroot; - IndexUnitWriter unitWriter(fileMgr, indexStorePath, - "swift", swiftVersion, indexUnitToken, module->getNameStr(), - mainFile, isSystem, /*isModuleUnit=*/false, isDebugCompilation, - targetTriple, sysrootPath, getModuleInfoFromOpaqueModule); + IndexUnitWriter unitWriter( + fileMgr, indexStorePath, "swift", swiftVersion, indexUnitToken, + module->getNameStr(), mainFile ? *mainFile : nullptr, isSystem, + /*isModuleUnit=*/false, isDebugCompilation, targetTriple, sysrootPath, + getModuleInfoFromOpaqueModule); // Module dependencies. ModuleDecl::ImportFilter importFilter; @@ -613,9 +614,11 @@ recordSourceFileUnit(SourceFile *primarySourceFile, StringRef indexUnitToken, recordSourceFile(primarySourceFile, indexStorePath, diags, [&](StringRef recordFile, StringRef filename) { - unitWriter.addRecordFile(recordFile, fileMgr.getFile(filename), - module->isSystemModule(), /*Module=*/nullptr); - }); + auto file = fileMgr.getFile(filename); + unitWriter.addRecordFile( + recordFile, file ? *file : nullptr, + module->isSystemModule(), /*Module=*/nullptr); + }); std::string error; if (unitWriter.write(error)) { diff --git a/lib/LLVMPasses/ARCEntryPointBuilder.h b/lib/LLVMPasses/ARCEntryPointBuilder.h index 31b3eb619d4..ef3baae3dc5 100644 --- a/lib/LLVMPasses/ARCEntryPointBuilder.h +++ b/lib/LLVMPasses/ARCEntryPointBuilder.h @@ -252,9 +252,10 @@ private: auto AttrList = AttributeList::get(M.getContext(), 1, Attribute::NoCapture); AttrList = AttrList.addAttribute( M.getContext(), AttributeList::FunctionIndex, Attribute::NoUnwind); - CheckUnowned = M.getOrInsertFunction("swift_checkUnowned", AttrList, - Type::getVoidTy(M.getContext()), - ObjectPtrTy); + CheckUnowned = cast( + M.getOrInsertFunction("swift_checkUnowned", AttrList, + Type::getVoidTy(M.getContext()), ObjectPtrTy) + .getCallee()); if (llvm::Triple(M.getTargetTriple()).isOSBinFormatCOFF() && !llvm::Triple(M.getTargetTriple()).isOSCygMing()) if (auto *F = llvm::dyn_cast(CheckUnowned.get())) diff --git a/lib/LLVMPasses/LLVMSwiftAA.cpp b/lib/LLVMPasses/LLVMSwiftAA.cpp index 97e3350dc7c..e83898f0eac 100644 --- a/lib/LLVMPasses/LLVMSwiftAA.cpp +++ b/lib/LLVMPasses/LLVMSwiftAA.cpp @@ -32,17 +32,17 @@ static ModRefInfo getConservativeModRefForKind(const llvm::Instruction &I) { llvm_unreachable("Not a valid Instruction."); } -ModRefInfo SwiftAAResult::getModRefInfo(llvm::ImmutableCallSite CS, - const llvm::MemoryLocation &Loc) { +ModRefInfo SwiftAAResult::getModRefInfo(const llvm::CallBase *Call, + const llvm::MemoryLocation &Loc, + llvm::AAQueryInfo &AAQI) { // We know at compile time that certain entry points do not modify any // compiler-visible state ever. Quickly check if we have one of those // instructions and return if so. - if (ModRefInfo::NoModRef == - getConservativeModRefForKind(*CS.getInstruction())) + if (ModRefInfo::NoModRef == getConservativeModRefForKind(*Call)) return ModRefInfo::NoModRef; // Otherwise, delegate to the rest of the AA ModRefInfo machinery. - return AAResultBase::getModRefInfo(CS, Loc); + return AAResultBase::getModRefInfo(Call, Loc, AAQI); } //===----------------------------------------------------------------------===// diff --git a/lib/Parse/ASTGen.cpp b/lib/Parse/ASTGen.cpp index 9681134650d..67904c4738f 100644 --- a/lib/Parse/ASTGen.cpp +++ b/lib/Parse/ASTGen.cpp @@ -14,9 +14,11 @@ #include "swift/AST/TypeRepr.h" #include "swift/Basic/SourceManager.h" +#include "DebuggerContextChange.h" #include "swift/Basic/SourceManager.h" #include "swift/Parse/CodeCompletionCallbacks.h" #include "swift/Parse/Parser.h" +#include "swift/Parse/Scope.h" using namespace swift; using namespace swift::syntax; @@ -25,6 +27,208 @@ SourceLoc ASTGen::generate(const TokenSyntax &Tok, const SourceLoc Loc) { return advanceLocBegin(Loc, Tok); } +SourceLoc ASTGen::generateIdentifierDeclName(const syntax::TokenSyntax &Tok, + const SourceLoc Loc, + Identifier &Id) { + StringRef text; + if (Tok.getText() == "Any") + // Special handle 'Any' because we don't want to accidantaly declare 'Any' + // type in any way. + text = "#Any"; + else + text = Tok.getIdentifierText(); + + Id = Context.getIdentifier(text); + return advanceLocBegin(Loc, Tok); +} + +Decl *ASTGen::generate(const DeclSyntax &D, const SourceLoc Loc) { + Decl *DeclAST = nullptr; + + if (auto associatedTypeDecl = D.getAs()) { + DeclAST = generate(*associatedTypeDecl, Loc); + } else if (auto typealiasDecl = D.getAs()) { + DeclAST = generate(*typealiasDecl, Loc); + } else { + llvm_unreachable("unsupported decl kind"); + } + + return DeclAST; +} + +DeclAttributes +ASTGen::generateDeclAttributes(const Syntax &D, SourceLoc Loc, + bool includeComments) { + // Find the AST attribute-list from the lookup table. + if (auto firstTok = D.getFirstToken()) { + auto declLoc = advanceLocBegin(Loc, *firstTok); + if (hasDeclAttributes(declLoc)) + return getDeclAttributes(declLoc); + } + return DeclAttributes(); +} + +MutableArrayRef +ASTGen::generate(const TypeInheritanceClauseSyntax &clause, SourceLoc Loc, + bool allowClassRequirement) { + SmallVector inherited; + + bool hasClass = false; + for (const auto elem : clause.getInheritedTypeCollection()) { + const auto &tySyntax = elem.getTypeName(); + if (tySyntax.is()) { + // Accept 'class' only if it's allowed and it's the first one. + if (!allowClassRequirement || hasClass) + continue; + hasClass = true; + } + if (auto ty = generate(tySyntax, Loc)) + inherited.emplace_back(ty); + } + + return Context.AllocateCopy(inherited); +} + +TypeDecl *ASTGen::generate(const AssociatedtypeDeclSyntax &D, + const SourceLoc Loc) { + if (!isa(P.CurDeclContext)) { + // This is already diagnosed in Parser. + return nullptr; + } + + auto idToken = D.getIdentifier(); + if (idToken.isMissing()) + return nullptr; + + auto keywordLoc = advanceLocBegin(Loc, D.getAssociatedtypeKeyword()); + Identifier name; + SourceLoc nameLoc = generateIdentifierDeclName(idToken, Loc, name); + + DeclAttributes attrs = generateDeclAttributes(D, Loc, true); + + DebuggerContextChange DCC(P, name, DeclKind::AssociatedType); + + ArrayRef inherited; + if (const auto inheritanceClause = D.getInheritanceClause()) + inherited = + generate(*inheritanceClause, Loc, /*allowClassRequirement=*/true); + + TypeRepr *defaultTy = nullptr; + if (const auto init = D.getInitializer()) + defaultTy = generate(init->getValue(), Loc); + + TrailingWhereClause *trailingWhere = nullptr; + if (auto whereClause = D.getGenericWhereClause()) + trailingWhere = generate(*whereClause, Loc); + + auto assocType = new (Context) + AssociatedTypeDecl(P.CurDeclContext, keywordLoc, name, nameLoc, defaultTy, + trailingWhere); + assocType->getAttrs() = attrs; + if (!inherited.empty()) + assocType->setInherited(Context.AllocateCopy(inherited)); + addToScope(assocType); + return assocType; +} + +TypeDecl *ASTGen::generate(const TypealiasDeclSyntax &D, const SourceLoc Loc) { + auto idToken = D.getIdentifier(); + if (idToken.isMissing()) + return nullptr; + + auto keywordLoc = advanceLocBegin(Loc, D.getTypealiasKeyword()); + Identifier name; + SourceLoc nameLoc = generateIdentifierDeclName(idToken, Loc, name); + auto attrs = generateDeclAttributes(D, Loc, true); + SourceLoc equalLoc; + + DebuggerContextChange DCC(P, name, DeclKind::TypeAlias); + + Optional GenericScope; + GenericParamList *genericParams = nullptr; + GenericScope.emplace(&P, ScopeKind::Generics); + if (auto clause = D.getGenericParameterClause()) + genericParams = generate(*clause, Loc); + + auto *TAD = new (Context) TypeAliasDecl(keywordLoc, equalLoc, name, nameLoc, + genericParams, P.CurDeclContext); + P.setLocalDiscriminator(TAD); + TAD->getAttrs() = attrs; + + TypeRepr *underlyingType = nullptr; + SourceLoc typeEndLoc; + if (auto init = D.getInitializer()) { + Parser::ContextChange CC(P, TAD); + equalLoc = generate(init->getEqual(), Loc); + underlyingType = generate(init->getValue(), Loc); + if (auto lastToken = init->getLastToken()) + typeEndLoc = generate(*lastToken, Loc); + } + TAD->setUnderlyingTypeRepr(underlyingType); + + SourceLoc whereLoc; + if (auto clause = D.getGenericWhereClause()) { + whereLoc = advanceLocBegin(Loc, clause->getWhereKeyword()); + Parser::ContextChange CC(P, TAD); + generateFreeStandingGenericWhereClause(*clause, Loc, genericParams); + } + P.diagnoseWhereClauseInGenericParamList(genericParams, whereLoc); + + if (equalLoc.isInvalid()) + return nullptr; + + GenericScope.reset(); + + addToScope(TAD); + return DCC.fixupParserResult(TAD).getPtrOrNull(); +} + +void ASTGen::generateFreeStandingGenericWhereClause( + const syntax::GenericWhereClauseSyntax &syntax, const SourceLoc Loc, + GenericParamList *genericParams) { + + SourceLoc whereLoc = generate(syntax.getWhereKeyword(), Loc); + + if (!genericParams) { + P.diagnose(whereLoc, diag::where_without_generic_params, + unsigned(Parser::WhereClauseKind::Declaration)); + return; + } + + // Push the generic parameters back into a local scope so that references + // will find them. + Scope S(&P, ScopeKind::Generics); + for (auto pd : genericParams->getParams()) + addToScope(pd); + + SmallVector requirements; + requirements.reserve(syntax.getRequirementList().size()); + for (auto elem : syntax.getRequirementList()) { + if (auto req = generate(elem, Loc)) + requirements.push_back(*req); + } + if (requirements.empty()) + return; + + genericParams->addTrailingWhereClause(Context, whereLoc, requirements); +} + +TrailingWhereClause *ASTGen::generate(const GenericWhereClauseSyntax &syntax, + const SourceLoc Loc) { + SourceLoc whereLoc = advanceLocBegin(Loc, syntax.getWhereKeyword()); + + SmallVector requirements; + requirements.reserve(syntax.getRequirementList().size()); + for (auto elem : syntax.getRequirementList()) { + if (auto req = generate(elem, Loc)) + requirements.push_back(*req); + } + + if (requirements.empty()) + return nullptr; + return TrailingWhereClause::create(Context, whereLoc, requirements); +} + Expr *ASTGen::generate(const IntegerLiteralExprSyntax &Expr, const SourceLoc Loc) { auto Digits = Expr.getDigits(); @@ -99,7 +303,8 @@ Expr *ASTGen::generate(const UnknownExprSyntax &Expr, const SourceLoc Loc) { return nullptr; } -TypeRepr *ASTGen::generate(const TypeSyntax &Type, const SourceLoc Loc) { +TypeRepr *ASTGen::generate(const TypeSyntax &Type, const SourceLoc Loc, + bool IsSILFuncDecl) { TypeRepr *TypeAST = nullptr; if (auto SimpleIdentifier = Type.getAs()) @@ -126,24 +331,44 @@ TypeRepr *ASTGen::generate(const TypeSyntax &Type, const SourceLoc Loc) { TypeAST = generate(*Unwrapped, Loc); else if (auto Attributed = Type.getAs()) TypeAST = generate(*Attributed, Loc); + else if (auto ClassRestriction = Type.getAs()) + TypeAST = generate(*ClassRestriction, Loc); + else if (auto SILBoxType = Type.getAs()) + TypeAST = generate(*SILBoxType, Loc, IsSILFuncDecl); + else if (auto SILFunctionType = Type.getAs()) + TypeAST = generate(*SILFunctionType, Loc, IsSILFuncDecl); else if (auto CompletionTy = Type.getAs()) TypeAST = generate(*CompletionTy, Loc); else if (auto Unknown = Type.getAs()) TypeAST = generate(*Unknown, Loc); - // todo [gsoc]: handle InheritedTypeSyntax & ClassRestrictionTypeSyntax? - - if (!TypeAST && hasType(advanceLocBegin(Loc, Type))) - TypeAST = getType(advanceLocBegin(Loc, Type)); - return cacheType(Type, TypeAST); } TypeRepr *ASTGen::generate(const FunctionTypeSyntax &Type, const SourceLoc Loc) { - auto ArgumentTypes = generateTuple(Type.getLeftParen(), Type.getArguments(), - Type.getRightParen(), Loc, - /*IsFunction=*/true); + TupleTypeRepr *ArgumentTypes = nullptr; + + SourceLoc VoidLoc; + if (Type.getLeftParen().isMissing() && Type.getArguments().size() == 1) { + if (auto ident = Type.getArguments()[0] + .getType() + .getAs()) { + if (!ident->getGenericArgumentClause().hasValue() && + ident->getName().getText() == "Void") + VoidLoc = advanceLocBegin(Loc, ident->getName()); + } + } + + if (VoidLoc.isValid()) + ArgumentTypes = TupleTypeRepr::createEmpty(Context, VoidLoc); + else { + ArgumentTypes = generateTuple(Type.getLeftParen(), Type.getArguments(), + Type.getRightParen(), Loc, + /*IsFunction=*/true); + } + if (!ArgumentTypes) + return nullptr; auto ThrowsLoc = Type.getThrowsOrRethrowsKeyword() ? generate(*Type.getThrowsOrRethrowsKeyword(), Loc) @@ -151,6 +376,8 @@ TypeRepr *ASTGen::generate(const FunctionTypeSyntax &Type, auto ArrowLoc = generate(Type.getArrow(), Loc); auto ReturnType = generate(Type.getReturnType(), Loc); + if (!ReturnType) + return nullptr; return new (Context) FunctionTypeRepr(nullptr, ArgumentTypes, ThrowsLoc, ArrowLoc, ReturnType); @@ -216,42 +443,109 @@ TupleTypeRepr *ASTGen::generateTuple(const TokenSyntax &LParen, EllipsisLoc, EllipsisIdx); } -TypeRepr *ASTGen::generate(const AttributedTypeSyntax &Type, - const SourceLoc Loc) { - // todo [gsoc]: improve this after refactoring attribute parsing +TypeAttributes ASTGen::generateTypeAttributes(const AttributeListSyntax &syntax, + const SourceLoc Loc) { + TypeAttributes attrs; - auto TypeAST = generate(Type.getBaseType(), Loc); + for (auto elem : syntax) { + auto attrSyntax = elem.castTo(); + if (attrSyntax.getAttributeName().isMissing()) + continue; - if (auto Attributes = Type.getAttributes()) { - TypeAttributes TypeAttrs; + auto attrName = attrSyntax.getAttributeName().getText(); - for (auto Attribute : *Attributes) { - auto Attr = Attribute.castTo(); - auto AttrNameStr = Attr.getAttributeName().getText(); + auto atLoc = advanceLocBegin(Loc, attrSyntax.getAtSignToken()); + if (attrs.AtLoc.isInvalid()) + attrs.AtLoc = atLoc; - auto AtLoc = advanceLocBegin(Loc, Attr.getAtSignToken()); - auto AttrKind = TypeAttributes::getAttrKindFromString(AttrNameStr); + auto attr = TypeAttributes::getAttrKindFromString(attrName); + if (attr == TAK_Count) + continue; - TypeAttrs.setAttr(AttrKind, AtLoc); - - if (AttrKind == TAK_convention) { - auto Argument = Attr.getArgument()->castTo(); - auto Convention = Context.getIdentifier(Argument.getIdentifierText()); - TypeAttrs.convention = Convention.str(); - } - - if (AttrKind == TAK_opened) { - auto AttrText = Attr.getArgument()->castTo().getText(); - auto LiteralText = AttrText.slice(1, AttrText.size() - 1); - TypeAttrs.OpenedID = UUID::fromString(LiteralText.str().c_str()); - } - - if (TypeAttrs.AtLoc.isInvalid()) - TypeAttrs.AtLoc = AtLoc; + if (attrs.has(attr)) { + P.diagnose(atLoc, diag::duplicate_attribute, /*isModifier=*/false); + continue; } - if (!TypeAttrs.empty()) - TypeAST = new (Context) AttributedTypeRepr(TypeAttrs, TypeAST); + auto arg = attrSyntax.getArgument(); + + if (attr == TAK_sil_weak || attr == TAK_sil_unowned) { + if (attrs.hasOwnership()) { + P.diagnose(atLoc, diag::duplicate_attribute, /*isModifier*/false); + } + } else if (attr == TAK_convention) { + // @convention(block) + // @convention(witness_method: ProtocolName) + if (!arg) + continue; + + if (auto conventionNameTok = arg->getAs()) { + assert(conventionNameTok->getTokenKind() == tok::identifier); + auto convention = + Context.getIdentifier(conventionNameTok->getIdentifierText()); + attrs.convention = convention.str(); + } else if (auto witness = + arg->getAs()) { + assert(witness->getNameTok().getIdentifierText() == "witness_method"); + if (witness->getStringOrDeclname().isMissing()) + continue; + auto protocolName = + witness->getStringOrDeclname().castTo(); + auto protocol = Context.getIdentifier( + protocolName.getDeclBaseName().getIdentifierText()); + attrs.convention = "witness_method"; + attrs.conventionWitnessMethodProtocol = protocol.str(); + } else { + continue; + } + } else if (attr == TAK_opened) { + // @opened("01234567-89ab-cdef-0123-111111111111") + if (!arg) + continue; + + assert(arg->castTo().getTokenKind() == + tok::string_literal); + auto tokText = arg->castTo().getText(); + auto literalText = tokText.slice(1, tokText.size() - 1); + attrs.OpenedID = UUID::fromString(literalText.str().c_str()); + } else if (attr == TAK__opaqueReturnTypeOf) { + // @_opaqueReturnTypeOf("$sMangledName", 0) + if (!arg) + continue; + + auto opaqueArg = + arg->castTo(); + + auto manglingTok = opaqueArg.getMangledName(); + auto indexTok = opaqueArg.getIndex(); + if (manglingTok.isMissing() || indexTok.isMissing()) + continue; + + auto tokText = manglingTok.getText(); + auto mangling = + Context.getIdentifier(tokText.slice(1, tokText.size() - 1)); + unsigned index; + if (indexTok.getText().getAsInteger(10, index)) + continue; + attrs.setOpaqueReturnTypeOf(mangling.str(), index); + } + + attrs.setAttr(attr, atLoc); + } + + return attrs; +} + +TypeRepr *ASTGen::generate(const AttributedTypeSyntax &Type, + const SourceLoc Loc) { + auto TypeAST = generate(Type.getBaseType(), Loc); + if (!TypeAST) + return nullptr; + + if (auto Attributes = Type.getAttributes()) { + TypeAttributes attrs = generateTypeAttributes(*Attributes, Loc); + if (!attrs.empty()) + TypeAST = new (Context) AttributedTypeRepr(attrs, TypeAST); } if (auto Specifier = Type.getSpecifier()) { @@ -386,11 +680,6 @@ TypeRepr *ASTGen::generate(const SimpleTypeIdentifierSyntax &Type, auto AnyLoc = advanceLocBegin(Loc, Type.getName()); return CompositionTypeRepr::createEmptyComposition(Context, AnyLoc); } - if (Type.getName().getText() == "class") { - auto classLoc = advanceLocBegin(Loc, Type.getName()); - return new (Context) - SimpleIdentTypeRepr(classLoc, Context.getIdentifier("AnyObject")); - } return generateSimpleOrMemberIdentifier(Type, Loc); } @@ -404,25 +693,37 @@ TypeRepr *ASTGen::generate(const DictionaryTypeSyntax &Type, const SourceLoc Loc) { TypeRepr *ValueType = generate(Type.getValueType(), Loc); TypeRepr *KeyType = generate(Type.getKeyType(), Loc); - auto LBraceLoc = advanceLocBegin(Loc, Type.getLeftSquareBracket()); + if (!ValueType || !KeyType) + return nullptr; auto ColonLoc = advanceLocBegin(Loc, Type.getColon()); - auto RBraceLoc = advanceLocBegin(Loc, Type.getRightSquareBracket()); - SourceRange Range{LBraceLoc, RBraceLoc}; + + SourceLoc LBracketLoc, RBracketLoc; + if (Type.getLeftSquareBracket().isPresent()) + LBracketLoc = advanceLocBegin(Loc, Type.getLeftSquareBracket()); + else + LBracketLoc = advanceLocBegin(Loc, *Type.getFirstToken()); + if (Type.getRightSquareBracket().isPresent()) + RBracketLoc = advanceLocBegin(Loc, Type.getRightSquareBracket()); + else + RBracketLoc = advanceLocBegin(Loc, *Type.getLastToken()); + SourceRange Range{LBracketLoc, RBracketLoc}; return new (Context) DictionaryTypeRepr(KeyType, ValueType, ColonLoc, Range); } TypeRepr *ASTGen::generate(const ArrayTypeSyntax &Type, SourceLoc Loc) { TypeRepr *ElementType = generate(Type.getElementType(), Loc); - SourceLoc LBraceLoc, RBraceLoc; + if (!ElementType) + return nullptr; + SourceLoc LBracketLoc, RBracketLoc; if (Type.getLeftSquareBracket().isPresent()) - LBraceLoc = advanceLocBegin(Loc, Type.getLeftSquareBracket()); + LBracketLoc = advanceLocBegin(Loc, Type.getLeftSquareBracket()); else - LBraceLoc = advanceLocBegin(Loc, Type.getElementType()); - if (Type.getLeftSquareBracket().isPresent()) - RBraceLoc = advanceLocBegin(Loc, Type.getRightSquareBracket()); + LBracketLoc = advanceLocBegin(Loc, *Type.getFirstToken()); + if (Type.getRightSquareBracket().isPresent()) + RBracketLoc = advanceLocBegin(Loc, Type.getRightSquareBracket()); else - RBraceLoc = advanceLocBegin(Loc, *Type.getLastToken()); - return new (Context) ArrayTypeRepr(ElementType, {LBraceLoc, RBraceLoc}); + RBracketLoc = advanceLocBegin(Loc, *Type.getLastToken()); + return new (Context) ArrayTypeRepr(ElementType, {LBracketLoc, RBracketLoc}); } TypeRepr *ASTGen::generate(const MetatypeTypeSyntax &Type, @@ -450,18 +751,106 @@ TypeRepr *ASTGen::generate(const ImplicitlyUnwrappedOptionalTypeSyntax &Type, ImplicitlyUnwrappedOptionalTypeRepr(WrappedType, ExclamationLoc); } +TypeRepr * +ASTGen::generate(const ClassRestrictionTypeSyntax &Type, const SourceLoc Loc) { + auto classLoc = advanceLocBegin(Loc, Type); + return new (Context) + SimpleIdentTypeRepr(classLoc, Context.getIdentifier("AnyObject")); +} + +TypeRepr *ASTGen::generate(const SILBoxTypeSyntax &Type, const SourceLoc Loc, + bool IsSILFuncDecl) { + if (Type.getRightBrace().isMissing()) + return nullptr; + + // If this is part of a sil function decl, generic parameters are visible in + // the function body; otherwise, they are visible when parsing the type. + Optional GenericsScope; + if (!IsSILFuncDecl) + GenericsScope.emplace(&P, ScopeKind::Generics); + + GenericParamList *generics = nullptr; + if (auto genericParamsSyntax = Type.getGenericParameterClauses()) + generics = generate(*genericParamsSyntax, Loc); + + SmallVector Fields; + for (auto field : Type.getFields()) { + auto specifier = field.getSpecifier(); + if (specifier.isMissing()) + return nullptr; + bool Mutable; + if (specifier.getTokenKind() == tok::kw_let) + Mutable = false; + else if (specifier.getTokenKind() == tok::kw_var) + Mutable = true; + else + return nullptr; + SourceLoc VarOrLetLoc = advanceLocBegin(Loc, specifier);; + auto fieldTy = generate(field.getType(), Loc); + if (!fieldTy) + return nullptr; + + Fields.emplace_back(VarOrLetLoc, Mutable, fieldTy); + } + GenericsScope.reset(); + + auto LBraceLoc = advanceLocBegin(Loc, Type.getLeftBrace()); + auto RBraceLoc = advanceLocBegin(Loc, Type.getRightBrace()); + + SourceLoc LAngleLoc, RAngleLoc; + SmallVector Args; + if (auto genericArgs = Type.getGenericArgumentClause()) { + if (genericArgs->getRightAngleBracket().isMissing()) + return nullptr; + LAngleLoc = advanceLocBegin(Loc, genericArgs->getLeftAngleBracket()); + RAngleLoc = advanceLocBegin(Loc, genericArgs->getRightAngleBracket()); + Args = generate(genericArgs->getArguments(), Loc); + } + + auto SILType = SILBoxTypeRepr::create(Context, generics, LBraceLoc, Fields, + RBraceLoc, LAngleLoc, Args, RAngleLoc); + return SILType; +} + +TypeRepr *ASTGen::generate(const SILFunctionTypeSyntax &Type, + const SourceLoc Loc, bool IsSILFuncDecl) { + // If this is part of a sil function decl, generic parameters are visible in + // the function body; otherwise, they are visible when parsing the type. + Optional GenericsScope; + if (!IsSILFuncDecl) + GenericsScope.emplace(&P, ScopeKind::Generics); + + GenericParamList *generics = nullptr; + if (auto genericParamsSyntax = Type.getGenericParameterClauses()) + generics = generate(*genericParamsSyntax, Loc); + + auto tyR = cast(generate(Type.getFunction(), Loc)); + return new (Context) + FunctionTypeRepr(generics, tyR->getArgsTypeRepr(), tyR->getThrowsLoc(), + tyR->getArrowLoc(), tyR->getResultTypeRepr()); +} + TypeRepr *ASTGen::generate(const CodeCompletionTypeSyntax &Type, const SourceLoc Loc) { auto base = Type.getBase(); - if (!base) - return nullptr; - - TypeRepr *parsedTyR = generate(*base, Loc); - if (parsedTyR) { + if (!base) { if (P.CodeCompletion) - P.CodeCompletion->setParsedTypeLoc(parsedTyR); + P.CodeCompletion->completeTypeSimpleBeginning(); + return nullptr; } - return parsedTyR; + + if (P.CodeCompletion) { + if (auto *parsedTyR = generate(*base, Loc)) { + P.CodeCompletion->setParsedTypeLoc(parsedTyR); + if (Type.getPeriod()) + P.CodeCompletion->completeTypeIdentifierWithDot(); + else + P.CodeCompletion->completeTypeIdentifierWithoutDot(); + } + } + + // Return nullptr to typecheck this TypeRepr independently in code completion. + return nullptr; } TypeRepr *ASTGen::generate(const UnknownTypeSyntax &Type, const SourceLoc Loc) { @@ -505,6 +894,13 @@ TypeRepr *ASTGen::generate(const UnknownTypeSyntax &Type, const SourceLoc Loc) { if (ChildrenCount >= 1) { auto LParen = Type.getChild(0)->getAs(); if (LParen && LParen->getTokenKind() == tok::l_paren) { + // generate child 'TypeSyntax' anyway to trigger the side effects e.g. + // code-completion. + for (size_t i = 1; i != ChildrenCount; ++i) { + auto elem = *Type.getChild(i); + if (auto ty = elem.getAs()) + (void)generate(*ty, Loc); + } auto LParenLoc = advanceLocBegin(Loc, *LParen); auto EndLoc = advanceLocBegin(Loc, *Type.getChild(Type.getNumChildren() - 1)); @@ -512,6 +908,14 @@ TypeRepr *ASTGen::generate(const UnknownTypeSyntax &Type, const SourceLoc Loc) { } } + // generate child 'TypeSyntax' anyway to trigger the side effects e.g. + // code-completion. + for (size_t i = 0; i != ChildrenCount; ++i) { + auto elem = *Type.getChild(i); + if (auto ty = elem.getAs()) + (void)generate(*ty, Loc); + } + // let's hope the main `generate` method can find this node in the type map return nullptr; } @@ -519,12 +923,11 @@ TypeRepr *ASTGen::generate(const UnknownTypeSyntax &Type, const SourceLoc Loc) { SmallVector ASTGen::generate(const GenericArgumentListSyntax &Args, const SourceLoc Loc) { SmallVector Types; - Types.resize(Args.size()); - - for (int i = Args.size() - 1; i >= 0; i--) { - auto Arg = Args.getChild(i).getValue().castTo(); - auto Type = generate(Arg, Loc); - Types[i] = Type; + for (auto Arg : Args) { + auto tyR = generate(Arg, Loc); + if (!tyR) + tyR = new (Context) ErrorTypeRepr(advanceLocBegin(Loc, Arg)); + Types.push_back(tyR); } return Types; @@ -574,14 +977,7 @@ GenericParamList *ASTGen::generate(const GenericParameterClauseSyntax &clause, for (auto elem : clause.getGenericParameterList()) { - DeclAttributes attrs; - if (auto attrsSyntax = elem.getAttributes()) { - if (auto firstTok = attrsSyntax->getFirstToken()) { - auto attrsLoc = advanceLocBegin(Loc, *firstTok); - if (hasDeclAttributes(attrsLoc)) - attrs = getDeclAttributes(attrsLoc); - } - } + DeclAttributes attrs = generateDeclAttributes(elem, Loc, false); Identifier name = Context.getIdentifier(elem.getName().getIdentifierText()); SourceLoc nameLoc = advanceLocBegin(Loc, elem.getName()); @@ -594,7 +990,7 @@ GenericParamList *ASTGen::generate(const GenericParameterClauseSyntax &clause, if (auto inherited = elem.getInheritedType()) { if (auto ty = generate(*inherited, Loc)) { - SmallVector constraints = {generate(*inherited, Loc)}; + SmallVector constraints = {ty}; param->setInherited(Context.AllocateCopy(constraints)); } } @@ -768,18 +1164,6 @@ TypeRepr *ASTGen::lookupType(TypeSyntax Type) { return Found != TypeCache.end() ? Found->second : nullptr; } -void ASTGen::addType(TypeRepr *Type, const SourceLoc Loc) { - Types.insert({Loc, Type}); -} - -bool ASTGen::hasType(const SourceLoc Loc) const { - return Types.find(Loc) != Types.end(); -} - -TypeRepr *ASTGen::getType(const SourceLoc Loc) const { - return Types.find(Loc)->second; -} - void ASTGen::addDeclAttributes(DeclAttributes attrs, SourceLoc Loc) { ParsedDeclAttrs.insert({Loc, attrs}); } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 15ff71a34df..998daf38a3c 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1804,155 +1804,104 @@ ParserStatus Parser::parseDeclAttribute(DeclAttributes &Attributes, SourceLoc At return makeParserError(); } -bool Parser::canParseTypeAttribute() { - TypeAttributes attrs; // ignored - return !parseTypeAttribute(attrs, /*atLoc=*/SourceLoc(), - /*justChecking*/ true); +/// Parses specifier and attributes for types. +/// +/// specifier: +/// 'inout' +/// '__shared' +/// '__owned' +/// +/// attribute-list: +/// attribute-type (',' attribute-type)? +ParserStatus Parser::parseTypeAttributeListSyntax( + Optional &specifier, + Optional &attrs) { + // Parser a specifier. + while (Tok.is(tok::kw_inout) || + (Tok.is(tok::identifier) && + (Tok.getRawText().equals("__shared") || + Tok.getRawText().equals("__owned")))) { + if (specifier) { + diagnose(Tok, diag::parameter_specifier_repeated) + .fixItRemove(Tok.getLoc()); + ignoreToken(); + } else { + specifier = consumeTokenSyntax(); + } + } + + ParserStatus status; + SmallVector attrsList; + while (Tok.is(tok::at_sign) && status.isSuccess()) { + auto attr = parseTypeAttributeSyntax(); + status |= attr.getStatus(); + if (!attr.isNull()) + attrsList.emplace_back(attr.get()); + } + if (!attrsList.empty()) + attrs = ParsedSyntaxRecorder::makeAttributeList(attrsList, *SyntaxContext); + + return status; } -/// \verbatim -/// attribute-type: -/// 'noreturn' -/// \endverbatim +bool Parser::parseTypeAttributeList(ParamDecl::Specifier &Specifier, + SourceLoc &SpecifierLoc, + TypeAttributes &Attributes) { + SourceLoc leadingLoc = leadingTriviaLoc(); + Optional parsedSpecifier; + Optional parsedAttrs; + auto status = parseTypeAttributeListSyntax(parsedSpecifier, parsedAttrs); + + if (parsedSpecifier) { + SyntaxContext->addSyntax(std::move(*parsedSpecifier)); + auto tok = SyntaxContext->topNode(); + Specifier = llvm::StringSwitch(Tok.getText()) + .Case("inout", ParamDecl::Specifier::InOut) + .Case("__shared", ParamDecl::Specifier::Shared) + .Case("__owned", ParamDecl::Specifier::Owned) + .Default(ParamDecl::Specifier::Default); + SpecifierLoc = Generator.generate(tok, leadingLoc); + + leadingLoc = leadingLoc.getAdvancedLoc(tok.getTextLength()); + } + + if (parsedAttrs) { + SyntaxContext->addSyntax(std::move(*parsedAttrs)); + auto syntax = SyntaxContext->topNode(); + Attributes = Generator.generateTypeAttributes(syntax, leadingLoc); + } + return status.isError(); +} + +/// Parses an attribute for types. /// -/// \param justChecking - if true, we're just checking whether we -/// canParseTypeAttribute; don't emit any diagnostics, and there's -/// no need to actually record the attribute -bool Parser::parseTypeAttribute(TypeAttributes &Attributes, SourceLoc AtLoc, - bool justChecking) { - // If this not an identifier, the attribute is malformed. - if (Tok.isNot(tok::identifier) && - // These are keywords that we accept as attribute names. - Tok.isNot(tok::kw_in) && Tok.isNot(tok::kw_inout)) { - if (!justChecking) - diagnose(Tok, diag::expected_attribute_name); - return true; +/// attribute-type: +/// '@' identifier +/// '@' 'convention' '(' identifier ')' +/// '@' 'convention' '(' 'witness_method' ':' identifier ')' +/// '@' 'opened' '(' string-literal ')' +/// '@' '_opaqureResultTypeOf' '(' string-literal ',' integer-literal ')' +ParsedSyntaxResult Parser::parseTypeAttributeSyntax() { + ParsedAttributeSyntaxBuilder builder(*SyntaxContext); + ParserStatus status; + + // Parse '@'. + auto atLoc = Tok.getLoc(); + builder.useAtSignToken(consumeTokenSyntax(tok::at_sign)); + + // Parse attribute name. + if (Tok.isNot(tok::identifier, tok::kw_in, tok::kw_inout)) { + diagnose(Tok, diag::expected_attribute_name); + if (Tok.is(tok::code_complete)) { + // TODO: Implement type attribute completion. + } + return makeParsedError(builder.build()); } - - // Determine which attribute it is, and diagnose it if unknown. - TypeAttrKind attr = TypeAttributes::getAttrKindFromString(Tok.getText()); + StringRef attrName = Tok.getText(); + builder.useAttributeName(consumeTokenSyntax()); - if (attr == TAK_Count) { - if (justChecking) return true; - - auto declAttrID = DeclAttribute::getAttrKindFromString(Tok.getText()); - if (declAttrID == DAK_Count) { - // Not a decl or type attribute. - diagnose(Tok, diag::unknown_attribute, Tok.getText()); - } else { - // Otherwise this is a valid decl attribute so they should have put it on - // the decl instead of the type. - - // If this is the first attribute, and if we are on a simple decl, emit a - // fixit to move the attribute. Otherwise, we don't have the location of - // the @ sign, or we don't have confidence that the fixit will be right. - if (!Attributes.empty() || StructureMarkers.empty() || - StructureMarkers.back().Kind != StructureMarkerKind::Declaration || - StructureMarkers.back().Loc.isInvalid() || - peekToken().is(tok::equal)) { - diagnose(Tok, diag::decl_attribute_applied_to_type); - } else { - // Otherwise, this is the first type attribute and we know where the - // declaration is. Emit the same diagnostic, but include a fixit to - // move the attribute. Unfortunately, we don't have enough info to add - // the attribute to DeclAttributes. - diagnose(Tok, diag::decl_attribute_applied_to_type) - .fixItRemove(SourceRange(Attributes.AtLoc, Tok.getLoc())) - .fixItInsert(StructureMarkers.back().Loc, - "@" + Tok.getText().str()+" "); - } - } - - // Recover by eating @foo(...) when foo is not known. - consumeToken(); - SyntaxParsingContext TokListContext(SyntaxContext, SyntaxKind::TokenList); - - if (Tok.is(tok::l_paren) && getEndOfPreviousLoc() == Tok.getLoc()) { - BacktrackingScope backtrack(*this); - skipSingle(); - // If we found '->', or 'throws' after paren, it's likely a parameter - // of function type. - if (Tok.isNot(tok::arrow, tok::kw_throws, tok::kw_rethrows, - tok::kw_throw)) - backtrack.cancelBacktrack(); - } - return true; - } - - // Ok, it is a valid attribute, eat it, and then process it. - StringRef Text = Tok.getText(); - consumeToken(); - - StringRef conventionName; - StringRef witnessMethodProtocol; - - if (attr == TAK_convention) { - SourceLoc LPLoc; - if (!consumeIfNotAtStartOfLine(tok::l_paren)) { - if (!justChecking) - diagnose(Tok, diag::convention_attribute_expected_lparen); - return true; - } - - if (Tok.isNot(tok::identifier)) { - if (!justChecking) - diagnose(Tok, diag::convention_attribute_expected_name); - return true; - } - - conventionName = Tok.getText(); - consumeToken(tok::identifier); - - if (conventionName == "witness_method") { - if (Tok.isNot(tok::colon)) { - if (!justChecking) - diagnose(Tok, - diag::convention_attribute_witness_method_expected_colon); - return true; - } - consumeToken(tok::colon); - if (Tok.isNot(tok::identifier)) { - if (!justChecking) - diagnose(Tok, - diag::convention_attribute_witness_method_expected_protocol); - return true; - } - - witnessMethodProtocol = Tok.getText(); - consumeToken(tok::identifier); - } - - // Parse the ')'. We can't use parseMatchingToken if we're in - // just-checking mode. - if (justChecking && Tok.isNot(tok::r_paren)) - return true; - - SourceLoc RPLoc; - parseMatchingToken(tok::r_paren, RPLoc, - diag::convention_attribute_expected_rparen, - LPLoc); - } - - - // In just-checking mode, we only need to consume the tokens, and we don't - // want to do any other analysis. - if (justChecking) - return false; - - // Diagnose duplicated attributes. - if (Attributes.has(attr)) { - diagnose(AtLoc, diag::duplicate_attribute, /*isModifier=*/false); - return false; - } - - // Handle any attribute-specific processing logic. + TypeAttrKind attr = TypeAttributes::getAttrKindFromString(attrName); switch (attr) { - default: break; - case TAK_autoclosure: - case TAK_escaping: - case TAK_noescape: - break; - case TAK_out: case TAK_in: case TAK_owned: @@ -1962,118 +1911,238 @@ bool Parser::parseTypeAttribute(TypeAttributes &Attributes, SourceLoc AtLoc, case TAK_callee_owned: case TAK_callee_guaranteed: case TAK_objc_metatype: - if (!isInSILMode()) { - diagnose(AtLoc, diag::only_allowed_in_sil, Text); - return false; - } - break; - - // Ownership attributes. case TAK_sil_weak: case TAK_sil_unowned: if (!isInSILMode()) { - diagnose(AtLoc, diag::only_allowed_in_sil, Text); - return false; - } - - if (Attributes.hasOwnership()) { - diagnose(AtLoc, diag::duplicate_attribute, /*isModifier*/false); - return false; + diagnose(atLoc, diag::only_allowed_in_sil, attrName); + status.setIsParseError(); } break; - // 'inout' attribute. - case TAK_inout: - if (!isInSILMode()) { - diagnose(AtLoc, diag::inout_not_attribute); - return false; - } - break; - - case TAK_opened: { - if (!isInSILMode()) { - diagnose(AtLoc, diag::only_allowed_in_sil, "opened"); - return false; - } - - // Parse the opened existential ID string in parens - SourceLoc beginLoc = Tok.getLoc(), idLoc, endLoc; - if (consumeIfNotAtStartOfLine(tok::l_paren)) { - if (Tok.is(tok::string_literal)) { - UUID openedID; - idLoc = Tok.getLoc(); - auto literalText = Tok.getText().slice(1, Tok.getText().size() - 1); - llvm::SmallString text(literalText); - if (auto openedID = UUID::fromString(text.c_str())) { - Attributes.OpenedID = openedID; - } else { - diagnose(Tok, diag::opened_attribute_id_value); - } - consumeToken(); - } else { - diagnose(Tok, diag::opened_attribute_id_value); - } - parseMatchingToken(tok::r_paren, endLoc, - diag::opened_attribute_expected_rparen, - beginLoc); + case TAK_Count: { + auto declAttrID = DeclAttribute::getAttrKindFromString(attrName); + if (declAttrID == DAK_Count) { + // Not a decl or type attribute. + diagnose(Tok, diag::unknown_attribute, attrName); } else { - diagnose(Tok, diag::opened_attribute_expected_lparen); + // Otherwise this is a valid decl attribute so they should have put it on + // the decl instead of the type. + diagnose(Tok, diag::decl_attribute_applied_to_type); } + // Recover by eating @foo(...) when foo is not known. + if (Tok.is(tok::l_paren) && getEndOfPreviousLoc() == Tok.getLoc()) { + BacktrackingScope backtrack(*this); + auto lParen = consumeTokenSyntax(tok::l_paren); + ignoreUntil(tok::r_paren); + auto rParen = consumeTokenSyntaxIf(tok::r_paren); + // If we found '->', or 'throws' after paren, it's likely a parameter + // of function type. + if (Tok.isNot(tok::arrow, tok::kw_throws, tok::kw_rethrows, + tok::kw_throw)) { + backtrack.cancelBacktrack(); + builder.useLeftParen(std::move(lParen)); + if (rParen) + builder.useRightParen(std::move(*rParen)); + } + } + status.setIsParseError(); break; } - // Convention attribute. case TAK_convention: - Attributes.convention = conventionName; - Attributes.conventionWitnessMethodProtocol = witnessMethodProtocol; - break; - - case TAK__opaqueReturnTypeOf: { - // Parse the mangled decl name and index. - auto beginLoc = Tok.getLoc(); - if (!consumeIfNotAtStartOfLine(tok::l_paren)) { - diagnose(Tok, diag::attr_expected_lparen, "_opaqueReturnTypeOf", false); - return true; - } - - if (!Tok.is(tok::string_literal)) { - diagnose(Tok, diag::opened_attribute_id_value); - return true; - } - auto mangling = Tok.getText().slice(1, Tok.getText().size() - 1); - consumeToken(tok::string_literal); - - if (!Tok.is(tok::comma)) { - diagnose(Tok, diag::attr_expected_comma, "_opaqueReturnTypeOf", false); - return true; - } - consumeToken(tok::comma); - - if (!Tok.is(tok::integer_literal)) { - diagnose(Tok, diag::attr_expected_string_literal, "_opaqueReturnTypeOf"); - return true; - } - - unsigned index; - if (Tok.getText().getAsInteger(10, index)) { - diagnose(Tok, diag::attr_expected_string_literal, "_opaqueReturnTypeOf"); - return true; - } - consumeToken(tok::integer_literal); - - SourceLoc endLoc; - parseMatchingToken(tok::r_paren, endLoc, - diag::expected_rparen_expr_list, - beginLoc); + status |= [&]() -> ParserStatus { + // Parse '('. + if (!Tok.is(tok::l_paren) || Tok.isAtStartOfLine()) { + diagnose(Tok, diag::convention_attribute_expected_lparen); + return makeParserError(); + } + SourceLoc LParenLoc = Tok.getLoc(); + builder.useLeftParen(consumeTokenSyntax(tok::l_paren)); - Attributes.setOpaqueReturnTypeOf(mangling, index); + // Parse convention name. + if (Tok.isNot(tok::identifier)) { + diagnose(Tok, diag::convention_attribute_expected_name); + return makeParserError(); + } + auto conventionName = Tok.getText(); + auto convention = consumeTokenSyntax(tok::identifier); + + // Parse convention name. + if (conventionName == "witness_method") { + ParsedNamedAttributeStringArgumentSyntaxBuilder argBuilder( + *SyntaxContext); + argBuilder.useNameTok(std::move(convention)); + + // Parse ':'. + if (Tok.isNot(tok::colon)) { + diagnose(Tok, + diag::convention_attribute_witness_method_expected_colon); + builder.useArgument(argBuilder.build()); + return makeParserError(); + } + argBuilder.useColon(consumeTokenSyntax(tok::colon)); + + // Parse protocol name. + if (Tok.isNot(tok::identifier)) { + diagnose(Tok, + diag::convention_attribute_witness_method_expected_protocol); + builder.useArgument(argBuilder.build()); + return makeParserError(); + } + auto name = ParsedSyntaxRecorder::makeDeclName( + consumeTokenSyntax(tok::identifier), None, *SyntaxContext); + argBuilder.useStringOrDeclname(std::move(name)); + builder.useArgument(argBuilder.build()); + } else { + builder.useArgument(std::move(convention)); + } + + // Parse ')'. + SourceLoc RParenLoc; + auto RParen = parseMatchingTokenSyntax( + tok::r_paren, RParenLoc, diag::convention_attribute_expected_rparen, + LParenLoc); + if (!RParen) + return makeParserError(); + builder.useRightParen(std::move(*RParen)); + + return makeParserSuccess(); + }(); + break; + + case TAK_opened: + status |= [&]() -> ParserStatus { + if (!isInSILMode()) { + diagnose(atLoc, diag::only_allowed_in_sil, "opened"); + return makeParserError(); + } + + // Parse '('. + if (!Tok.is(tok::l_paren) || Tok.isAtStartOfLine()) { + diagnose(Tok, diag::opened_attribute_expected_lparen); + return makeParserError(); + } + SourceLoc LParenLoc = Tok.getLoc(); + builder.useLeftParen(consumeTokenSyntax(tok::l_paren)); + + if (!Tok.is(tok::string_literal)) { + diagnose(Tok, diag::opened_attribute_id_value); + return makeParserError(); + } + builder.useArgument(consumeTokenSyntax(tok::string_literal)); + + // Parse ')'. + SourceLoc RParenLoc; + auto RParen = parseMatchingTokenSyntax( + tok::r_paren, RParenLoc, diag::opened_attribute_expected_rparen, + LParenLoc); + if (!RParen) + return makeParserError(); + builder.useRightParen(std::move(*RParen)); + + return makeParserSuccess(); + }(); + break; + + case TAK__opaqueReturnTypeOf: + status |= [&]() -> ParserStatus { + // Parse '('. + if (!Tok.is(tok::l_paren) || Tok.isAtStartOfLine()) { + diagnose(Tok, diag::attr_expected_lparen, "_opaqueReturnTypeOf", false); + return makeParserError(); + } + SourceLoc LParenLoc = Tok.getLoc(); + builder.useLeftParen(consumeTokenSyntax(tok::l_paren)); + + ParsedOpaqueReturnTypeOfAttributeArgumentsSyntaxBuilder argBuilder( + *SyntaxContext); + + // Parse the mangled decl name and index. + if (!Tok.is(tok::string_literal)) { + diagnose(Tok, diag::opened_attribute_id_value); + return makeParserError(); + } + argBuilder.useMangledName(consumeTokenSyntax(tok::string_literal)); + + // Parse ','. + if (!Tok.is(tok::comma)) { + diagnose(Tok, diag::attr_expected_comma, "_opaqueReturnTypeOf", false); + builder.useArgument(builder.build()); + return makeParserError(); + } + argBuilder.useComma(consumeTokenSyntax(tok::comma)); + + // Parse index number. + if (!Tok.is(tok::integer_literal)) { + diagnose(Tok, diag::attr_expected_string_literal, + "_opaqueReturnTypeOf"); + builder.useArgument(builder.build()); + return makeParserError(); + } + argBuilder.useIndex(consumeTokenSyntax(tok::integer_literal)); + + builder.useArgument(argBuilder.build()); + + // Parse ')'. + SourceLoc RParenLoc; + auto RParen = parseMatchingTokenSyntax( + tok::r_paren, RParenLoc, diag::expected_rparen_expr_list, LParenLoc); + if (!RParen) + return makeParserError(); + builder.useRightParen(std::move(*RParen)); + + return makeParserSuccess(); + }(); + break; + + default: break; } - } + return makeParsedResult(builder.build(), status); +} - Attributes.setAttr(attr, AtLoc); - return false; +bool Parser::canParseTypeAttribute() { + if (!Tok.isAny(tok::identifier, tok::kw_in, tok::kw_inout)) + return false; + + TypeAttrKind attr = TypeAttributes::getAttrKindFromString(Tok.getText()); + consumeToken(); + + switch (attr) { + case TAK_Count: + return false; + case TAK_convention: { + if (!consumeIf(tok::l_paren)) + return false; + if (!Tok.is(tok::identifier)) + return false; + auto name = Tok.getText(); + consumeToken(tok::identifier); + if (name == "witness_method") { + consumeToken(); + if (!consumeIf(tok::colon)) + return false; + if (!consumeIf(tok::identifier)) + return false; + } + if (!consumeIf(tok::r_paren)) + return false; + return true; + } + case TAK_opened: + return (consumeIf(tok::l_paren) && // '(' + consumeIf(tok::string_literal) && // UUID + consumeIf(tok::r_paren)); // ')' + case TAK__opaqueReturnTypeOf: + return (consumeIf(tok::l_paren) && // '(' + consumeIf(tok::string_literal) && // Mangled name + consumeIf(tok::comma) && // ',' + consumeIf(tok::integer_literal) && // Index + consumeIf(tok::r_paren)); // ')' + default: + return true; + } } /// \verbatim @@ -2243,60 +2312,6 @@ bool Parser::parseDeclModifierList(DeclAttributes &Attributes, } } -/// This is the internal implementation of \c parseTypeAttributeList, -/// which we expect to be inlined to handle the common case of an absent -/// attribute list. -/// -/// \verbatim -/// attribute-list: -/// /*empty*/ -/// attribute-list-clause attribute-list -/// 'inout' attribute-list-clause attribute-list -/// '__shared' attribute-list-clause attribute-list -/// '__owned' attribute-list-clause attribute-list -/// 'some' attribute-list-clause attribute-list -/// attribute-list-clause: -/// '@' attribute -/// '@' attribute attribute-list-clause -/// \endverbatim -bool Parser::parseTypeAttributeListPresent(ParamDecl::Specifier &Specifier, - SourceLoc &SpecifierLoc, - TypeAttributes &Attributes) { - Specifier = ParamDecl::Specifier::Default; - while (Tok.is(tok::kw_inout) || - (Tok.is(tok::identifier) && - (Tok.getRawText().equals("__shared") || - Tok.getRawText().equals("__owned")))) { - if (SpecifierLoc.isValid()) { - diagnose(Tok, diag::parameter_specifier_repeated) - .fixItRemove(SpecifierLoc); - } else { - if (Tok.is(tok::kw_inout)) { - Specifier = ParamDecl::Specifier::InOut; - } else if (Tok.is(tok::identifier)) { - if (Tok.getRawText().equals("__shared")) { - Specifier = ParamDecl::Specifier::Shared; - } else if (Tok.getRawText().equals("__owned")) { - Specifier = ParamDecl::Specifier::Owned; - } - } - } - SpecifierLoc = consumeToken(); - } - - SyntaxParsingContext AttrListCtx(SyntaxContext, SyntaxKind::AttributeList); - while (Tok.is(tok::at_sign)) { - if (Attributes.AtLoc.isInvalid()) - Attributes.AtLoc = Tok.getLoc(); - SyntaxParsingContext AttrCtx(SyntaxContext, SyntaxKind::Attribute); - SourceLoc AtLoc = consumeToken(); - if (parseTypeAttribute(Attributes, AtLoc)) - return true; - } - - return false; -} - static bool isStartOfOperatorDecl(const Token &Tok, const Token &Tok2) { return Tok.isContextualKeyword("operator") && (Tok2.isContextualKeyword("prefix") || @@ -2692,12 +2707,14 @@ Parser::parseDecl(ParseDeclOptions Flags, SyntaxParsingContext DeclParsingContext(SyntaxContext, SyntaxContextKind::Decl); + SourceLoc leadingLoc = leadingTriviaLoc(); // Note that we're parsing a declaration. StructureMarkerRAII ParsingDecl(*this, Tok.getLoc(), StructureMarkerKind::Declaration); // Parse attributes. + SourceLoc AttrsLoc = Tok.getLoc(); DeclAttributes Attributes; if (Tok.hasComment()) Attributes.add(new (Context) RawDocCommentAttr(Tok.getCommentRange())); @@ -2709,6 +2726,9 @@ Parser::parseDecl(ParseDeclOptions Flags, StaticSpellingKind StaticSpelling = StaticSpellingKind::None; parseDeclModifierList(Attributes, StaticLoc, StaticSpelling); + if (!Attributes.isEmpty()) + Generator.addDeclAttributes(Attributes, AttrsLoc); + // We emit diagnostics for 'try let ...' in parseDeclVar(). SourceLoc tryLoc; if (Tok.is(tok::kw_try) && peekToken().isAny(tok::kw_let, tok::kw_var)) @@ -2759,13 +2779,11 @@ Parser::parseDecl(ParseDeclOptions Flags, break; } case tok::kw_typealias: - DeclParsingContext.setCreateSyntax(SyntaxKind::TypealiasDecl); - DeclResult = parseDeclTypeAlias(Flags, Attributes); + DeclResult = parseDeclTypeAlias(Flags, Attributes, leadingLoc); MayNeedOverrideCompletion = true; break; case tok::kw_associatedtype: - DeclParsingContext.setCreateSyntax(SyntaxKind::AssociatedtypeDecl); - DeclResult = parseDeclAssociatedType(Flags, Attributes); + DeclResult = parseDeclAssociatedType(Flags, Attributes, leadingLoc); break; case tok::kw_enum: DeclParsingContext.setCreateSyntax(SyntaxKind::EnumDecl); @@ -3304,100 +3322,107 @@ ParserResult Parser::parseDeclImport(ParseDeclOptions Flags, /// 'class' /// type-identifier /// \endverbatim -ParserStatus Parser::parseInheritance(SmallVectorImpl &Inherited, - bool allowClassRequirement, - bool allowAnyObject) { - SyntaxParsingContext InheritanceContext(SyntaxContext, - SyntaxKind::TypeInheritanceClause); - Scope S(this, ScopeKind::InheritanceClause); - consumeToken(tok::colon); +ParsedSyntaxResult +Parser::parseTypeInheritanceClauseSyntax(bool allowClassRequirement, + bool allowAnyObject) { + ParsedTypeInheritanceClauseSyntaxBuilder builder(*SyntaxContext); + ParserStatus status; - SyntaxParsingContext TypeListContext(SyntaxContext, - SyntaxKind::InheritedTypeList); - SourceLoc classRequirementLoc; + builder.useColon(consumeTokenSyntax(tok::colon)); - ParserStatus Status; - SourceLoc prevComma; - bool HasNextType; + SourceLoc startLoc = Tok.getLoc(); + SourceLoc classRequirementLoc, prevCommaLoc; + bool hasNext = true; do { - SyntaxParsingContext TypeContext(SyntaxContext, SyntaxKind::InheritedType); - SWIFT_DEFER { - // Check for a ',', which indicates that there are more protocols coming. - HasNextType = consumeIf(tok::comma, prevComma); - }; + ParsedInheritedTypeSyntaxBuilder elemBuilder(*SyntaxContext); + // Parse the 'class' keyword for a class requirement. if (Tok.is(tok::kw_class)) { - SyntaxParsingContext ClassTypeContext(SyntaxContext, - SyntaxKind::ClassRestrictionType); - // If we aren't allowed to have a class requirement here, complain. - auto classLoc = consumeToken(); + auto classLoc = Tok.getLoc(); + auto classTok = consumeTokenSyntax(tok::kw_class); + auto restriction = ParsedSyntaxRecorder::makeClassRestrictionType( + std::move(classTok), *SyntaxContext); + elemBuilder.useTypeName(std::move(restriction)); + if (!allowClassRequirement) { + // If we aren't allowed to have a class requirement here, complain. diagnose(classLoc, diag::unexpected_class_constraint); - // Note that it makes no sense to suggest fixing - // 'struct S : class' to 'struct S : AnyObject' for - // example; in that case we just complain about - // 'class' being invalid here. + // Note that it makes no sense to suggest fixing 'struct S : class' to + // 'struct S : AnyObject' for example; in that case we just complain + // about 'class' being invalid here. if (allowAnyObject) { diagnose(classLoc, diag::suggest_anyobject) - .fixItReplace(classLoc, "AnyObject"); + .fixItReplace(classLoc, "AnyObject"); } - continue; - } - // If we already saw a class requirement, complain. - if (classRequirementLoc.isValid()) { - diagnose(classLoc, diag::redundant_class_requirement) + } else if (classRequirementLoc.isValid()) { + // If we already saw a class requirement, complain. + diagnose(Tok.getLoc(), diag::redundant_class_requirement) .highlight(classRequirementLoc) - .fixItRemove(SourceRange(prevComma, classLoc)); - continue; - } + .fixItRemove(SourceRange(prevCommaLoc, classLoc)); - // If the class requirement was not the first requirement, complain. - if (!Inherited.empty()) { - SourceLoc properLoc = Inherited[0].getSourceRange().Start; + } else if (prevCommaLoc.isValid()) { + // If the class requirement was not the first requirement, complain. diagnose(classLoc, diag::late_class_requirement) - .fixItInsert(properLoc, "class, ") - .fixItRemove(SourceRange(prevComma, classLoc)); + .fixItInsert(startLoc, "class, ") + .fixItRemove(SourceRange(prevCommaLoc, classLoc)); } // Record the location of the 'class' keyword. - classRequirementLoc = classLoc; - - // Add 'AnyObject' to the inherited list. - Inherited.push_back( - new (Context) SimpleIdentTypeRepr(classLoc, - Context.getIdentifier("AnyObject"))); - continue; + if (!classRequirementLoc.isValid()) + classRequirementLoc = classLoc; + } else { + // Parse inherited type. + auto inheritedType = parseTypeSyntax(); + status |= inheritedType.getStatus(); + if (!inheritedType.isNull()) + elemBuilder.useTypeName(inheritedType.get()); + else + elemBuilder.useTypeName( + ParsedSyntaxRecorder::makeUnknownType({}, *SyntaxContext)); } - auto ParsedTypeResult = parseType(); - Status |= ParsedTypeResult; + // Parse ','. + if (Tok.is(tok::comma)) { + prevCommaLoc = Tok.getLoc(); + elemBuilder.useTrailingComma(consumeTokenSyntax(tok::comma)); + } else { + hasNext = false; + } - // Record the type if its a single type. - if (ParsedTypeResult.isNonNull()) - Inherited.push_back(ParsedTypeResult.get()); - } while (HasNextType); + builder.addInheritedTypeCollectionMember(elemBuilder.build()); + } while (hasNext); - return Status; + return makeParsedResult(builder.build(), status); } -static ParserStatus -parseIdentifierDeclName(Parser &P, Identifier &Result, SourceLoc &Loc, - StringRef DeclKindName, - llvm::function_ref canRecover) { - if (P.Tok.is(tok::identifier)) { - Loc = P.consumeIdentifier(&Result); +ParserStatus Parser::parseInheritance(MutableArrayRef &Inherited, + bool allowClassRequirement, + bool allowAnyObject) { + auto leadingLoc = leadingTriviaLoc(); + auto parsed = parseTypeInheritanceClauseSyntax(allowClassRequirement, + allowAnyObject); + SyntaxContext->addSyntax(parsed.get()); + auto clause = SyntaxContext->topNode(); + Inherited = Generator.generate(clause, leadingLoc, allowClassRequirement); + return parsed.getStatus(); +} - // We parsed an identifier for the declaration. If we see another - // identifier, it might've been a single identifier that got broken by a - // space or newline accidentally. +static ParsedSyntaxResult +parseIdentifierDeclNameSyntax(Parser &P, StringRef DeclKindName, + llvm::function_ref canRecover) { + if (P.Tok.is(tok::identifier)) { + auto text = P.Tok.getText(); + auto loc = P.Tok.getLoc(); + + auto tok = P.consumeIdentifierSyntax(); if (P.Tok.isIdentifierOrUnderscore() && !P.Tok.isContextualDeclKeyword()) - P.diagnoseConsecutiveIDs(Result.str(), Loc, DeclKindName); + P.diagnoseConsecutiveIDs(text, loc, DeclKindName); // Return success anyway - return makeParserSuccess(); + return makeParsedResult(std::move(tok)); } P.checkForInputIncomplete(); @@ -3411,12 +3436,8 @@ parseIdentifierDeclName(Parser &P, Identifier &Result, SourceLoc &Loc, // Pretend this works as an identifier, which shouldn't be observable since // actual uses of it will hit random other errors, e.g. `1()` won't be // callable. - Result = P.Context.getIdentifier(P.Tok.getText()); - Loc = P.Tok.getLoc(); - P.consumeToken(); - - // We recovered, so this is a success. - return makeParserSuccess(); + P.Tok.setKind(tok::identifier); + return makeParsedResult(P.consumeTokenSyntax()); } if (P.Tok.isKeyword()) { @@ -3426,14 +3447,8 @@ parseIdentifierDeclName(Parser &P, Identifier &Result, SourceLoc &Loc, // Recover if the next token is one of the expected tokens. if (canRecover(P.peekToken())) { - llvm::SmallString<32> Name(P.Tok.getText()); - // Append an invalid character so that nothing can resolve to this name. - Name += "#"; - Result = P.Context.getIdentifier(Name.str()); - Loc = P.Tok.getLoc(); - P.consumeToken(); - // Return success because we recovered. - return makeParserSuccess(); + P.Tok.setKind(tok::identifier); + return makeParsedResult(P.consumeTokenSyntax()); } return makeParserError(); } @@ -3442,6 +3457,20 @@ parseIdentifierDeclName(Parser &P, Identifier &Result, SourceLoc &Loc, return makeParserError(); } +static ParserStatus +parseIdentifierDeclName(Parser &P, Identifier &Result, SourceLoc &Loc, + StringRef DeclKindName, + llvm::function_ref canRecover) { + auto leadingLoc = P.leadingTriviaLoc(); + auto parsed = parseIdentifierDeclNameSyntax(P, DeclKindName, canRecover); + if (!parsed.isNull()) { + P.SyntaxContext->addSyntax(parsed.get()); + auto syntax = P.SyntaxContext->topNode(); + Loc = P.Generator.generateIdentifierDeclName(syntax, leadingLoc, Result); + } + return parsed.getStatus(); +} + /// Add a fix-it to remove the space in consecutive identifiers. /// Add a camel-cased option if it is different than the first option. void Parser::diagnoseConsecutiveIDs(StringRef First, SourceLoc FirstLoc, @@ -3450,7 +3479,8 @@ void Parser::diagnoseConsecutiveIDs(StringRef First, SourceLoc FirstLoc, diagnose(Tok, diag::repeated_identifier, DeclKindName); auto Second = Tok.getText(); - auto SecondLoc = consumeToken(); + auto SecondLoc = Tok.getLoc(); + ignoreToken(); SourceRange FixRange(FirstLoc, SecondLoc); // Provide two fix-its: a direct concatenation of the two identifiers @@ -3650,7 +3680,7 @@ Parser::parseDeclExtension(ParseDeclOptions Flags, DeclAttributes &Attributes) { status |= extendedType; // Parse optional inheritance clause. - SmallVector Inherited; + MutableArrayRef Inherited; if (Tok.is(tok::colon)) status |= parseInheritance(Inherited, /*allowClassRequirement=*/false, @@ -3677,7 +3707,7 @@ Parser::parseDeclExtension(ParseDeclOptions Flags, DeclAttributes &Attributes) { ExtensionDecl *ext = ExtensionDecl::create(Context, ExtensionLoc, extendedType.getPtrOrNull(), - Context.AllocateCopy(Inherited), + Inherited, CurDeclContext, trailingWhereClause); ext->getAttrs() = Attributes; @@ -3943,207 +3973,240 @@ ParserStatus Parser::parseLineDirective(bool isLine) { /// Parse a typealias decl. /// -/// \verbatim /// decl-typealias: -/// 'typealias' identifier generic-params? '=' type requirement-clause? -/// \endverbatim -ParserResult Parser:: -parseDeclTypeAlias(Parser::ParseDeclOptions Flags, DeclAttributes &Attributes) { +/// 'typealias' identifier generic-params? '=' type +/// generic-where-clause? +ParsedSyntaxResult +Parser::parseDeclTypeAliasSyntax(Parser::ParseDeclOptions Flags, + Optional attrs, + Optional modifiers) { ParserPosition startPosition = getParserPosition(); llvm::Optional TmpCtxt; TmpCtxt.emplace(SyntaxContext); TmpCtxt->setBackTracking(); - SourceLoc TypeAliasLoc = consumeToken(tok::kw_typealias); - SourceLoc EqualLoc; - Identifier Id; - SourceLoc IdLoc; - ParserStatus Status; + auto typealiasKeyword = consumeTokenSyntax(tok::kw_typealias); - Status |= parseIdentifierDeclName( - *this, Id, IdLoc, "typealias", - [](const Token &next) { return next.isAny(tok::colon, tok::equal); }); - if (Status.isError()) { + ParserStatus status; + + auto applyIntroducer = [&](ParsedTypealiasDeclSyntaxBuilder &builder) { + if (attrs) + builder.useAttributes(std::move(*attrs)); + if (modifiers) + builder.useModifiers(std::move(*modifiers)); + builder.useTypealiasKeyword(std::move(typealiasKeyword)); + }; + + // Parse the name. + auto name = + parseIdentifierDeclNameSyntax(*this, "typealias", [](const Token &next) { + return next.isAny(tok::colon, tok::equal); + }); + if (name.isNull()) { TmpCtxt->setTransparent(); - return nullptr; + TmpCtxt.reset(); + ParsedTypealiasDeclSyntaxBuilder builder(*SyntaxContext); + applyIntroducer(builder); + return makeParsedError(builder.build()); } - - DebuggerContextChange DCC(*this, Id, DeclKind::TypeAlias); - Optional GenericsScope; - GenericsScope.emplace(this, ScopeKind::Generics); - - // Parse a generic parameter list if it is present. - GenericParamList *genericParams = nullptr; + // Parse optional generic parameters. + Optional genericParams; if (startsWithLess(Tok)) { - auto Result = parseGenericParameters(); - if (Result.hasCodeCompletion() && !CodeCompletion) - return makeParserCodeCompletionStatus(); - genericParams = Result.getPtrOrNull(); - - if (!genericParams) { - // If the parser returned null, it is an already diagnosed parse error. - } else if (!genericParams->getRequirements().empty()) { - // Reject a where clause. - diagnose(genericParams->getWhereLoc(), - diag::associated_type_generic_parameter_list) - .highlight(genericParams->getWhereClauseSourceRange()); - } + auto result = parseGenericParameterClauseSyntax(); + status |= result.getStatus(); + if (!result.isNull()) + genericParams = result.get(); } if (Flags.contains(PD_InProtocol) && !genericParams && !Tok.is(tok::equal)) { + // If we're in a protocol and don't see an '=' this looks like leftover + // Swift 2 code intending to be an associatedtype. TmpCtxt.reset(); - // If we're in a protocol and don't see an '=' this looks like leftover Swift 2 - // code intending to be an associatedtype. backtrackToPosition(startPosition); - return parseDeclAssociatedType(Flags, Attributes); + return parseDeclAssociatedTypeSyntax(Flags, std::move(attrs), + std::move(modifiers)); } + TmpCtxt->setTransparent(); TmpCtxt.reset(); - auto *TAD = new (Context) TypeAliasDecl(TypeAliasLoc, EqualLoc, Id, IdLoc, - genericParams, CurDeclContext); - setLocalDiscriminator(TAD); - ParserResult UnderlyingTy; + ParsedTypealiasDeclSyntaxBuilder builder(*SyntaxContext); + applyIntroducer(builder); + builder.useIdentifier(name.get()); + if (genericParams) + builder.useGenericParameterClause(std::move(*genericParams)); - if (Tok.is(tok::colon) || Tok.is(tok::equal)) { - ContextChange CC(*this, TAD); + // Parse underlying type clause. + if (Tok.isAny(tok::equal, tok::colon)) { + ParsedTypeInitializerClauseSyntaxBuilder initBuilder(*SyntaxContext); - SyntaxParsingContext InitCtx(SyntaxContext, - SyntaxKind::TypeInitializerClause); + // Parse '='. if (Tok.is(tok::colon)) { // It is a common mistake to write "typealias A : Int" instead of = Int. // Recognize this and produce a fixit. diagnose(Tok, diag::expected_equal_in_typealias) .fixItReplace(Tok.getLoc(), " = "); - EqualLoc = consumeToken(tok::colon); + ignoreToken(tok::colon); } else { - EqualLoc = consumeToken(tok::equal); + initBuilder.useEqual(consumeTokenSyntax()); } - UnderlyingTy = parseType(diag::expected_type_in_typealias); - TAD->setTypeEndLoc(PreviousLoc); - Status |= UnderlyingTy; + // Parse the underlying type. + auto underlyingType = parseTypeSyntax(diag::expected_type_in_typealias); + status |= underlyingType.getStatus(); + if (!underlyingType.isNull()) { + initBuilder.useValue(underlyingType.get()); + } else { + initBuilder.useValue( + ParsedSyntaxRecorder::makeUnknownType({}, *SyntaxContext)); + } + builder.useInitializer(initBuilder.build()); + } else { + diagnose(Tok, diag::expected_equal_in_typealias); + status.setIsParseError(); } - TAD->setUnderlyingTypeRepr(UnderlyingTy.getPtrOrNull()); - TAD->getAttrs() = Attributes; - - // Parse a 'where' clause if present, adding it to our GenericParamList. + // Parse optional where clause. if (Tok.is(tok::kw_where)) { - ContextChange CC(*this, TAD); - Status |= parseFreestandingGenericWhereClause(genericParams); + bool FirstTypeInComplete = false; + auto whereClause = parseGenericWhereClauseSyntax(FirstTypeInComplete); + status |= whereClause.getStatus(); + builder.useGenericWhereClause(whereClause.get()); } - if (UnderlyingTy.isNull()) { - // If there is an attempt to do code completion - // inside of typealias type, let's just return - // because we've seen required '=' token. - if (EqualLoc.isInvalid()) { - diagnose(Tok, diag::expected_equal_in_typealias); - Status.setIsParseError(); - return Status; - } - } + return makeParsedResult(builder.build(), status); +} - // Exit the scope introduced for the generic parameters. - GenericsScope.reset(); +ParserResult +Parser::parseDeclTypeAlias(Parser::ParseDeclOptions Flags, + DeclAttributes &Attributes, SourceLoc leadingLoc) { + auto modifiers = SyntaxContext->popIf(); + auto attrs = SyntaxContext->popIf(); - addToScope(TAD); - return DCC.fixupParserResult(Status, TAD); + auto parsed = + parseDeclTypeAliasSyntax(Flags, std::move(attrs), std::move(modifiers)); + assert(!parsed.isNull()); + + SyntaxContext->addSyntax(parsed.get()); + auto syntax = SyntaxContext->topNode(); + TypeDecl *result = + cast_or_null(Generator.generate(syntax, leadingLoc)); + return makeParserResult(parsed.getStatus(), result); } /// Parse an associatedtype decl. /// -/// \verbatim /// decl-associatedtype: -/// 'associatedtype' identifier inheritance? ('=' type)? where-clause? -/// \endverbatim +/// 'associatedtype' identifier type-inheritance-clause? +/// ('=' type)? where-clause? +ParsedSyntaxResult +Parser::parseDeclAssociatedTypeSyntax(ParseDeclOptions flags, + Optional attrs, + Optional modifiers) { + ParsedAssociatedtypeDeclSyntaxBuilder builder(*SyntaxContext); + ParserStatus status; -ParserResult Parser::parseDeclAssociatedType(Parser::ParseDeclOptions Flags, - DeclAttributes &Attributes) { - SourceLoc AssociatedTypeLoc; - ParserStatus Status; - Identifier Id; - SourceLoc IdLoc; - - // Look for 'typealias' here and diagnose a fixit because parseDeclTypeAlias can - // ask us to fix up leftover Swift 2 code intending to be an associatedtype. + if (attrs) + builder.useAttributes(std::move(*attrs)); + if (modifiers) + builder.useModifiers(std::move(*modifiers)); + + // Parse 'associatedtype' keyword. + // Look for 'typealias' here and diagnose a fixit because parseDeclTypeAlias + // can ask us to fix up leftover Swift 2 code intending to be an + // associatedtype. + auto keywordLoc = Tok.getLoc(); if (Tok.is(tok::kw_typealias)) { - AssociatedTypeLoc = consumeToken(tok::kw_typealias); - diagnose(AssociatedTypeLoc, diag::typealias_inside_protocol_without_type) - .fixItReplace(AssociatedTypeLoc, "associatedtype"); + diagnose(Tok.getLoc(), diag::typealias_inside_protocol_without_type) + .fixItReplace(Tok.getLoc(), "associatedtype"); + ignoreToken(tok::kw_typealias); } else { - AssociatedTypeLoc = consumeToken(tok::kw_associatedtype); + builder.useAssociatedtypeKeyword( + consumeTokenSyntax(tok::kw_associatedtype)); } - Status = parseIdentifierDeclName( - *this, Id, IdLoc, "associatedtype", - [](const Token &next) { return next.isAny(tok::colon, tok::equal); }); - if (Status.isError()) - return nullptr; - - DebuggerContextChange DCC(*this, Id, DeclKind::AssociatedType); - - // Reject generic parameters with a specific error. + // Parse the name. + auto name = parseIdentifierDeclNameSyntax( + *this, "associatedtype", + [&](const Token &next) { return next.isAny(tok::colon, tok::equal); }); + if (name.isNull()) + return makeParsedResult(builder.build(), name.getStatus()); + assert(name.isSuccess()); + builder.useIdentifier(name.get()); + + // Diagnose generic parameters. if (startsWithLess(Tok)) { - // Introduce a throwaway scope to capture the generic parameters. We - // don't want them visible anywhere! - Scope S(this, ScopeKind::Generics); + auto loc = Tok.getLoc(); + ignoreToken(); + if (ignoreUntilGreaterInTypeList()) + ignoreToken(); - if (auto genericParams = parseGenericParameters().getPtrOrNull()) { - diagnose(genericParams->getLAngleLoc(), - diag::associated_type_generic_parameter_list) - .fixItRemove(genericParams->getSourceRange()); - } + diagnose(loc, diag::associated_type_generic_parameter_list) + .fixItRemove({loc, PreviousLoc}); } - + // Parse optional inheritance clause. - // FIXME: Allow class requirements here. - SmallVector Inherited; - if (Tok.is(tok::colon)) - Status |= parseInheritance(Inherited, - /*allowClassRequirement=*/false, - /*allowAnyObject=*/true); - - ParserResult UnderlyingTy; + if (Tok.is(tok::colon)) { + auto inheritance = parseTypeInheritanceClauseSyntax( + /*allowClassRequirement=*/false, /*allowAnyObject=*/true); + status |= inheritance.getStatus(); + if (!inheritance.isNull()) + builder.useInheritanceClause(inheritance.get()); + } + + // Parse optional default type. if (Tok.is(tok::equal)) { - SyntaxParsingContext InitContext(SyntaxContext, - SyntaxKind::TypeInitializerClause); - consumeToken(tok::equal); - UnderlyingTy = parseType(diag::expected_type_in_associatedtype); - Status |= UnderlyingTy; - if (UnderlyingTy.isNull()) - return Status; + ParsedTypeInitializerClauseSyntaxBuilder initBuilder(*SyntaxContext); + initBuilder.useEqual(consumeTokenSyntax(tok::equal)); + + // Parse type. + auto type = parseTypeSyntax(diag::expected_type_in_associatedtype); + status |= type.getStatus(); + if (!type.isNull()) + initBuilder.useValue(type.get()); + else + initBuilder.useValue( + ParsedSyntaxRecorder::makeUnknownType({}, *SyntaxContext)); + + builder.useInitializer(initBuilder.build()); } - TrailingWhereClause *TrailingWhere = nullptr; - // Parse a 'where' clause if present. + // Parse optional 'where' clause. if (Tok.is(tok::kw_where)) { - auto whereStatus = parseProtocolOrAssociatedTypeWhereClause( - TrailingWhere, /*isProtocol=*/false); - Status |= whereStatus; - if (whereStatus.hasCodeCompletion() && !CodeCompletion) { - // Trigger delayed parsing, no need to continue. - return whereStatus; - } + bool firstTypeInComplete = false; + auto where = parseGenericWhereClauseSyntax(firstTypeInComplete); + status |= where.getStatus(); + if (!where.isNull()) + builder.useGenericWhereClause(where.get()); } - if (!Flags.contains(PD_InProtocol)) { - diagnose(AssociatedTypeLoc, diag::associatedtype_outside_protocol) - .fixItReplace(AssociatedTypeLoc, "typealias"); - Status.setIsParseError(); - return Status; + // Diagnose if it's not in protocol decl. + // TODO: Move this to ASTGen. + if (!flags.contains(PD_InProtocol)) { + diagnose(keywordLoc, diag::associatedtype_outside_protocol) + .fixItReplace(keywordLoc, "typealias"); + status.setIsParseError(); } - auto assocType = new (Context) - AssociatedTypeDecl(CurDeclContext, AssociatedTypeLoc, Id, IdLoc, - UnderlyingTy.getPtrOrNull(), TrailingWhere); - assocType->getAttrs() = Attributes; - if (!Inherited.empty()) - assocType->setInherited(Context.AllocateCopy(Inherited)); - addToScope(assocType); - return makeParserResult(Status, assocType); + return makeParsedResult(builder.build(), status); +} + +ParserResult +Parser::parseDeclAssociatedType(Parser::ParseDeclOptions Flags, + DeclAttributes &Attributes, + SourceLoc leadingLoc) { + auto modifiers = SyntaxContext->popIf(); + auto attrs = SyntaxContext->popIf(); + + auto parsed = parseDeclAssociatedTypeSyntax(Flags, std::move(attrs), + std::move(modifiers)); + assert(!parsed.isNull()); + + SyntaxContext->addSyntax(parsed.get()); + auto syntax = SyntaxContext->topNode(); + auto result = Generator.generate(syntax, leadingLoc); + return makeParserResult(parsed.getStatus(), result); } /// This function creates an accessor function (with no body) for a computed @@ -5574,11 +5637,11 @@ ParserResult Parser::parseDeclEnum(ParseDeclOptions Flags, // Parse optional inheritance clause within the context of the enum. if (Tok.is(tok::colon)) { - SmallVector Inherited; + MutableArrayRef Inherited; Status |= parseInheritance(Inherited, /*allowClassRequirement=*/false, /*allowAnyObject=*/false); - ED->setInherited(Context.AllocateCopy(Inherited)); + ED->setInherited(Inherited); } diagnoseWhereClauseInGenericParamList(GenericParams); @@ -5860,11 +5923,11 @@ ParserResult Parser::parseDeclStruct(ParseDeclOptions Flags, // Parse optional inheritance clause within the context of the struct. if (Tok.is(tok::colon)) { - SmallVector Inherited; + MutableArrayRef Inherited; Status |= parseInheritance(Inherited, /*allowClassRequirement=*/false, /*allowAnyObject=*/false); - SD->setInherited(Context.AllocateCopy(Inherited)); + SD->setInherited(Inherited); } diagnoseWhereClauseInGenericParamList(GenericParams); @@ -5953,11 +6016,11 @@ ParserResult Parser::parseDeclClass(ParseDeclOptions Flags, // Parse optional inheritance clause within the context of the class. if (Tok.is(tok::colon)) { - SmallVector Inherited; + MutableArrayRef Inherited; Status |= parseInheritance(Inherited, /*allowClassRequirement=*/false, /*allowAnyObject=*/false); - CD->setInherited(Context.AllocateCopy(Inherited)); + CD->setInherited(Inherited); // Parse python style inheritance clause and replace parentheses with a colon } else if (Tok.is(tok::l_paren)) { @@ -6059,7 +6122,7 @@ parseDeclProtocol(ParseDeclOptions Flags, DeclAttributes &Attributes) { DebuggerContextChange DCC (*this); // Parse optional inheritance clause. - SmallVector InheritedProtocols; + MutableArrayRef InheritedProtocols; SourceLoc colonLoc; if (Tok.is(tok::colon)) { colonLoc = Tok.getLoc(); @@ -6079,7 +6142,7 @@ parseDeclProtocol(ParseDeclOptions Flags, DeclAttributes &Attributes) { ProtocolDecl *Proto = new (Context) ProtocolDecl(CurDeclContext, ProtocolLoc, NameLoc, ProtocolName, - Context.AllocateCopy(InheritedProtocols), TrailingWhere); + InheritedProtocols, TrailingWhere); // No need to setLocalDiscriminator: protocols can't appear in local contexts. Proto->getAttrs() = Attributes; diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index be0fd255067..386f5aeb8ce 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -1081,7 +1081,7 @@ Parser::parseExprPostfixSuffix(ParserResult Result, bool isExprBasic, if (canParseAsGenericArgumentList()) { SmallVector args; SourceLoc LAngleLoc, RAngleLoc; - auto argStat = parseGenericArgumentsAST(args, LAngleLoc, RAngleLoc); + auto argStat = parseGenericArguments(args, LAngleLoc, RAngleLoc); if (argStat.isError()) diagnose(LAngleLoc, diag::while_parsing_as_left_angle_bracket); @@ -2209,7 +2209,7 @@ Expr *Parser::parseExprIdentifier() { if (canParseAsGenericArgumentList()) { SyntaxContext->createNodeInPlace(SyntaxKind::IdentifierExpr); SyntaxContext->setCreateSyntax(SyntaxKind::SpecializeExpr); - auto argStat = parseGenericArgumentsAST(args, LAngleLoc, RAngleLoc); + auto argStat = parseGenericArguments(args, LAngleLoc, RAngleLoc); if (argStat.isError()) diagnose(LAngleLoc, diag::while_parsing_as_left_angle_bracket); diff --git a/lib/Parse/ParseGeneric.cpp b/lib/Parse/ParseGeneric.cpp index b2edfebb3d1..7dfae6092ec 100644 --- a/lib/Parse/ParseGeneric.cpp +++ b/lib/Parse/ParseGeneric.cpp @@ -78,10 +78,11 @@ Parser::parseGenericParameterClauseSyntax() { SyntaxParsingContext TmpCtxt(SyntaxContext); TmpCtxt.setTransparent(); + auto AttrsLoc = Tok.getLoc(); DeclAttributes attrsAST; parseDeclAttributeList(attrsAST); if (!attrsAST.isEmpty()) - Generator.addDeclAttributes(attrsAST, attrsAST.getStartLoc()); + Generator.addDeclAttributes(attrsAST, AttrsLoc); auto attrs = SyntaxContext->popIf(); if (attrs) paramBuilder.useAttributes(std::move(*attrs)); @@ -110,9 +111,8 @@ Parser::parseGenericParameterClauseSyntax() { diagnose(Tok, diag::unexpected_class_constraint); diagnose(Tok, diag::suggest_anyobject) .fixItReplace(Tok.getLoc(), "AnyObject"); - Tok.setKind(tok::identifier); - auto ty = ParsedSyntaxRecorder::makeSimpleTypeIdentifier( - consumeTokenSyntax(), None, *SyntaxContext); + auto ty = ParsedSyntaxRecorder::makeClassRestrictionType( + consumeTokenSyntax(tok::kw_class), *SyntaxContext); paramBuilder.useInheritedType(std::move(ty)); } else { diagnose(Tok, diag::expected_generics_type_restriction, ident); @@ -197,9 +197,8 @@ ParserResult Parser::parseSILGenericParams() { return makeParserResult(status, ret); } -void -Parser::diagnoseWhereClauseInGenericParamList(const GenericParamList * - GenericParams) { +void Parser::diagnoseWhereClauseInGenericParamList( + const GenericParamList *GenericParams, SourceLoc whereLoc) { if (GenericParams == nullptr || GenericParams->getWhereLoc().isInvalid()) return; @@ -224,7 +223,7 @@ Parser::diagnoseWhereClauseInGenericParamList(const GenericParamList * SmallString<64> Buffer; llvm::raw_svector_ostream WhereClauseText(Buffer); - WhereClauseText << SourceMgr.extractText(Tok.is(tok::kw_where) + WhereClauseText << SourceMgr.extractText(whereLoc.isValid() ? WhereCharRange : RemoveWhereRange); @@ -240,14 +239,22 @@ Parser::diagnoseWhereClauseInGenericParamList(const GenericParamList * Diag.fixItRemoveChars(RemoveWhereRange.getStart(), RemoveWhereRange.getEnd()); - if (Tok.is(tok::kw_where)) { - Diag.fixItReplace(Tok.getLoc(), WhereClauseText.str()); + if (whereLoc.isValid()) { + Diag.fixItReplace(whereLoc, WhereClauseText.str()); } else { Diag.fixItInsert(Lexer::getLocForEndOfToken(SourceMgr, PreviousLoc), WhereClauseText.str()); } } +void Parser::diagnoseWhereClauseInGenericParamList( + const GenericParamList *GenericParams) { + SourceLoc whereLoc; + if (Tok.is(tok::kw_where)) + whereLoc = Tok.getLoc(); + diagnoseWhereClauseInGenericParamList(GenericParams, whereLoc); +} + /// Parse a 'where' clause, which places additional constraints on generic /// parameters or types based on them. /// diff --git a/lib/Parse/ParseRequests.cpp b/lib/Parse/ParseRequests.cpp index 620c2e79996..dbc96e6e048 100644 --- a/lib/Parse/ParseRequests.cpp +++ b/lib/Parse/ParseRequests.cpp @@ -70,6 +70,7 @@ BraceStmt *ParseAbstractFunctionBodyRequest::evaluate( std::tie(body, isTypeChecked) = (afd->Synthesizer.Fn)( afd, afd->Synthesizer.Context); + assert(body && "cannot synthesize a null body"); afd->setBodyKind(isTypeChecked ? BodyKind::TypeChecked : BodyKind::Parsed); return body; } diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index 9051d506e49..8fbf84140ea 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -62,6 +62,31 @@ TypeRepr *Parser::applyAttributeToType(TypeRepr *ty, return ty; } +/// Apply specifier and attributes to the parsed type. +ParsedSyntaxResult +Parser::applyAttributeToTypeSyntax(ParsedSyntaxResult &&ty, + Optional specifier, + Optional attrs) { + if (!attrs && !specifier) + return std::move(ty); + + if (ty.isNull()) { + SmallVector junk; + if (specifier) + junk.emplace_back(std::move(*specifier)); + if (attrs) + junk.emplace_back(std::move(*attrs)); + return makeParsedResult( + ParsedSyntaxRecorder::makeUnknownType(junk, *SyntaxContext), + ty.getStatus()); + } + + return makeParsedResult( + ParsedSyntaxRecorder::makeAttributedType( + std::move(specifier), std::move(attrs), ty.get(), *SyntaxContext), + ty.getStatus()); +} + /// Parse layout constraint for 'where' clause in '@_specialize' attribute /// and in SIL. /// @@ -132,8 +157,8 @@ Parser::parseLayoutConstraintSyntax() { /// type-simple '!' /// type-collection /// type-array -Parser::TypeResult Parser::parseTypeSimple(Diag<> MessageID, - bool HandleCodeCompletion) { +ParsedSyntaxResult +Parser::parseTypeSimple(Diag<> MessageID, bool HandleCodeCompletion) { if (Tok.is(tok::kw_inout) || (Tok.is(tok::identifier) && (Tok.getRawText().equals("__shared") || Tok.getRawText().equals("__owned")))) { @@ -145,7 +170,7 @@ Parser::TypeResult Parser::parseTypeSimple(Diag<> MessageID, auto TypeLoc = leadingTriviaLoc(); - TypeResult Result; + ParsedSyntaxResult Result; switch (Tok.getKind()) { case tok::kw_Self: case tok::kw_Any: @@ -158,12 +183,8 @@ Parser::TypeResult Parser::parseTypeSimple(Diag<> MessageID, case tok::code_complete: { if (!HandleCodeCompletion) break; - if (CodeCompletion) - CodeCompletion->completeTypeSimpleBeginning(); - // Eat the code completion token because we handled it. - auto CCTok = consumeTokenSyntax(tok::code_complete); - ParsedTypeSyntax ty = - ParsedSyntaxRecorder::makeUnknownType({&CCTok, 1}, *SyntaxContext); + ParsedTypeSyntax ty = ParsedSyntaxRecorder::makeCodeCompletionType( + None, None, consumeTokenSyntax(), *SyntaxContext); return makeParsedCodeCompletion(std::move(ty)); } case tok::l_square: @@ -188,7 +209,8 @@ Parser::TypeResult Parser::parseTypeSimple(Diag<> MessageID, auto token = consumeTokenSyntax(); ParsedTypeSyntax ty = ParsedSyntaxRecorder::makeUnknownType( {&token, 1}, *SyntaxContext); - return makeParsedError(std::move(ty)); + // Return success result because we recovered. + return makeParsedResult(std::move(ty)); } checkForInputIncomplete(); @@ -225,284 +247,246 @@ Parser::TypeResult Parser::parseTypeSimple(Diag<> MessageID, return Result; } -ParsedSyntaxResult Parser::parseTypeSyntax() { - return parseTypeSyntax(diag::expected_type); -} +ParsedSyntaxResult Parser::parseSILBoxTypeSyntax( + Optional generics) { + ParsedSILBoxTypeSyntaxBuilder builder(*SyntaxContext); + ParserStatus status; -ParsedSyntaxResult -Parser::parseTypeSyntax(Diag<> messageID, bool HandleCodeCompletion, - bool IsSILFuncDecl) { - SyntaxParsingContext ctxt(SyntaxContext); - ctxt.setTransparent(); + if (generics) + builder.useGenericParameterClauses(std::move(*generics)); - auto loc = Tok.getLoc(); - auto tyR = parseType(messageID, HandleCodeCompletion, IsSILFuncDecl); - if (auto ty = SyntaxContext->popIf()) { - Generator.addType(tyR.getPtrOrNull(), loc); - return makeParsedResult(std::move(*ty), tyR.getStatus()); - } - return tyR.getStatus(); -} + // Parse '{'. + builder.useLeftBrace(consumeTokenSyntax(tok::l_brace)); -Parser::TypeASTResult Parser::parseType() { - return parseType(diag::expected_type); -} - -Parser::TypeASTResult Parser::parseSILBoxType(GenericParamList *generics, - const TypeAttributes &attrs, - Optional &GenericsScope) { - auto LBraceLoc = consumeToken(tok::l_brace); - - SmallVector Fields; + // Parse comma separated field list. if (!Tok.is(tok::r_brace)) { - for (;;) { - bool Mutable; - if (Tok.is(tok::kw_var)) { - Mutable = true; - } else if (Tok.is(tok::kw_let)) { - Mutable = false; - } else { + bool hasNext = true; + do { + ParsedSILBoxTypeFieldSyntaxBuilder fieldBuilder(*SyntaxContext); + + // Parse 'let' or 'var'. + if (!Tok.isAny(tok::kw_var, tok::kw_let)) { diagnose(Tok, diag::sil_box_expected_var_or_let); - return makeParserError(); + break; } - SourceLoc VarOrLetLoc = consumeToken(); + fieldBuilder.useSpecifier(consumeTokenSyntax()); - auto fieldTy = parseType(); - if (!fieldTy.getPtrOrNull()) - return makeParserError(); - Fields.push_back({VarOrLetLoc, Mutable, fieldTy.get()}); + // Parse the type. + auto ty = parseTypeSyntax(); + status |= ty.getStatus(); + if (!ty.isNull()) + fieldBuilder.useType(ty.get()); + else + fieldBuilder.useType( + ParsedSyntaxRecorder::makeUnknownType({}, *SyntaxContext)); - if (consumeIf(tok::comma)) - continue; + // Parse ','. + hasNext = (status.isSuccess() && Tok.is(tok::comma)); + if (hasNext) + fieldBuilder.useTrailingComma(consumeTokenSyntax()); - break; - } + builder.addFieldsMember(fieldBuilder.build()); + } while (hasNext); } + // Parse '}'. if (!Tok.is(tok::r_brace)) { diagnose(Tok, diag::sil_box_expected_r_brace); - return makeParserError(); + return makeParsedError(builder.build()); + } + builder.useRightBrace(consumeTokenSyntax(tok::r_brace)); + + // Parse the generic argument. + if (startsWithLess(Tok)) { + auto genericArgs = parseGenericArgumentClauseSyntax(); + status |= genericArgs.getStatus(); + if (!genericArgs.isNull()) + builder.useGenericArgumentClause(genericArgs.get()); } - auto RBraceLoc = consumeToken(tok::r_brace); - - // The generic arguments are taken from the enclosing scope. Pop the - // box layout's scope now. - GenericsScope.reset(); - - SourceLoc LAngleLoc, RAngleLoc; - SmallVector Args; - if (Tok.isContextualPunctuator("<")) { - LAngleLoc = consumeToken(); - for (;;) { - auto argTy = parseType(); - if (!argTy.getPtrOrNull()) - return makeParserError(); - Args.push_back(argTy.get()); - if (consumeIf(tok::comma)) - continue; - break; - } - if (!Tok.isContextualPunctuator(">")) { - diagnose(Tok, diag::sil_box_expected_r_angle); - return makeParserError(); - } - - RAngleLoc = consumeToken(); - } - - auto SILType = SILBoxTypeRepr::create(Context, generics, LBraceLoc, Fields, - RBraceLoc, LAngleLoc, Args, RAngleLoc); - - auto AttributedType = applyAttributeToType( - SILType, attrs, ParamDecl::Specifier::Owned, SourceLoc()); - - return makeParserResult(AttributedType); + return makeParsedResult(builder.build()); } /// parseType /// type: /// attribute-list type-composition /// attribute-list type-function +/// attribute-list sil-generic-function-type +/// sil-box-type /// /// type-function: -/// type-composition 'throws'? '->' type +/// '(' tuple-type-element-list ')' 'throws'? '->' type /// -Parser::TypeASTResult Parser::parseType(Diag<> MessageID, - bool HandleCodeCompletion, - bool IsSILFuncDecl) { - // Start a context for creating type syntax. - SyntaxParsingContext TypeParsingContext(SyntaxContext, - SyntaxContextKind::Type); - auto TypeLoc = Tok.getLoc(); +/// sil-generic-function-type: +/// generic-parameter-clause-list type-function +ParsedSyntaxResult +Parser::parseTypeSyntax(Diag<> MessageID, bool HandleCodeCompletion, + bool IsSILFuncDecl) { + ParserStatus status; // Parse attributes. - ParamDecl::Specifier specifier; - SourceLoc specifierLoc; - TypeAttributes attrs; - parseTypeAttributeList(specifier, specifierLoc, attrs); - - Optional GenericsScope; + Optional specifier; + Optional attrs; + if (Tok.isAny(tok::at_sign, tok::kw_inout) || + (Tok.is(tok::identifier) && (Tok.getRawText().equals("__shared") || + Tok.getRawText().equals("__owned")))) + status |= parseTypeAttributeListSyntax(specifier, attrs); // Parse generic parameters in SIL mode. - GenericParamList *generics = nullptr; - if (isInSILMode()) { - // If this is part of a sil function decl, generic parameters are visible in - // the function body; otherwise, they are visible when parsing the type. - if (!IsSILFuncDecl) - GenericsScope.emplace(this, ScopeKind::Generics); - generics = parseSILGenericParams().getPtrOrNull(); - } + Optional genericParams; + SourceLoc genericParamsLoc = Tok.getLoc(); + if (isInSILMode()) + (void)parseSILGenericParamsSyntax(genericParams); // In SIL mode, parse box types { ... }. if (isInSILMode() && Tok.is(tok::l_brace)) { - auto SILBoxType = parseSILBoxType(generics, attrs, GenericsScope); - Generator.addType(SILBoxType.getPtrOrNull(), TypeLoc); - return SILBoxType; + auto ty = parseSILBoxTypeSyntax(std::move(genericParams)); + return applyAttributeToTypeSyntax(std::move(ty), std::move(specifier), + std::move(attrs)); } - auto RealTypeLoc = leadingTriviaLoc(); + auto startLoc = Tok.getLoc(); + // Parse the type. + auto ty = parseTypeSimpleOrComposition(MessageID, HandleCodeCompletion); + status |= ty.getStatus(); + auto endLoc = PreviousLoc; - ParserResult ty = - parseTypeSimpleOrCompositionAST(MessageID, HandleCodeCompletion); - if (ty.hasCodeCompletion()) - return makeParserCodeCompletionResult(); - if (ty.isNull()) - return nullptr; - auto tyR = ty.get(); - - // Parse a throws specifier. // Don't consume 'throws', if the next token is not '->', so we can emit a // more useful diagnostic when parsing a function decl. - Optional Throws; + bool canBeFunctionTy = + Tok.is(tok::arrow) || + (Tok.isAny(tok::kw_throws, tok::kw_rethrows, tok::kw_throw) && + peekToken().is(tok::arrow)); + + // If the first type has an error, or this is not a function type, return the + // first result. + if (ty.isNull() || !canBeFunctionTy) { + // Diagnose generic parameter for non-function types. + if (!genericParams && !specifier && !attrs) + return ty; + + if (genericParams) { + SmallVector junk; + diagnose(genericParamsLoc, diag::generic_non_function); + junk.push_back(std::move(*genericParams)); + if (!ty.isNull()) + junk.emplace_back(ty.get()); + ty = makeParsedResult( + ParsedSyntaxRecorder::makeUnknownType(junk, *SyntaxContext), + status); + } + + return applyAttributeToTypeSyntax(std::move(ty), std::move(specifier), + std::move(attrs)); + } + + // Parse a throws specifier. + Optional throws; if (Tok.isAny(tok::kw_throws, tok::kw_rethrows, tok::kw_throw) && peekToken().is(tok::arrow)) { if (Tok.isNot(tok::kw_throws)) { // 'rethrows' is only allowed on function declarations for now. // 'throw' is probably a typo for 'throws'. - Diag<> DiagID = Tok.is(tok::kw_rethrows) ? - diag::rethrowing_function_type : diag::throw_in_function_type; - diagnose(Tok.getLoc(), DiagID) - .fixItReplace(Tok.getLoc(), "throws"); - } - - Throws = consumeTokenSyntax(); - } - - if (Tok.is(tok::arrow)) { - auto InputNode(std::move(SyntaxContext->popIf().getValue())); - // Handle type-function if we have an arrow. - auto ArrowLoc = Tok.getLoc(); - auto Arrow = consumeTokenSyntax(); - if (Tok.is(tok::kw_throws)) { - Diag<> DiagID = diag::throws_in_wrong_position; - diagnose(Tok.getLoc(), DiagID) - .fixItInsert(ArrowLoc, "throws ") - .fixItRemove(Tok.getLoc()); + Diag<> DiagID = Tok.is(tok::kw_rethrows) ? diag::rethrowing_function_type + : diag::throw_in_function_type; + diagnose(Tok.getLoc(), DiagID).fixItReplace(Tok.getLoc(), "throws"); ignoreToken(); - } - ParserResult SecondHalf = - parseType(diag::expected_type_function_result); - auto SecondTy = SyntaxContext->popIf(); - if (SecondHalf.isParseError()) { - SyntaxContext->addSyntax(std::move(InputNode)); - if (Throws) - SyntaxContext->addSyntax(std::move(*Throws)); - SyntaxContext->addSyntax(std::move(Arrow)); - if (SecondTy) - SyntaxContext->addSyntax(std::move(*SecondTy)); - if (SecondHalf.hasCodeCompletion()) - return makeParserCodeCompletionResult(); - return makeParserErrorResult(); - } - - ParsedFunctionTypeSyntaxBuilder Builder(*SyntaxContext); - bool isVoid = false; - if (auto TupleTypeNode = InputNode.getAs()) { - // Decompose TupleTypeSyntax and repack into FunctionType. - auto LeftParen = TupleTypeNode->getDeferredLeftParen(); - auto Arguments = TupleTypeNode->getDeferredElements(); - auto RightParen = TupleTypeNode->getDeferredRightParen(); - Builder - .useLeftParen(std::move(LeftParen)) - .useArguments(std::move(Arguments)) - .useRightParen(std::move(RightParen)); } else { - // FIXME(syntaxparse): Extract 'Void' text from recoreded node. - if (const auto Void = dyn_cast(tyR)) - isVoid = (Void->getIdentifier().str() == "Void"); - - if (isVoid) { - diagnose(tyR->getStartLoc(), diag::function_type_no_parens) - .fixItReplace(tyR->getStartLoc(), "()"); - } else { - diagnose(tyR->getStartLoc(), diag::function_type_no_parens) - .highlight(tyR->getSourceRange()) - .fixItInsert(tyR->getStartLoc(), "(") - .fixItInsertAfter(tyR->getEndLoc(), ")"); - } - Builder.addArgumentsMember(ParsedSyntaxRecorder::makeTupleTypeElement( - std::move(InputNode), /*TrailingComma=*/None, *SyntaxContext)); + throws = consumeTokenSyntax(); } - - if (Throws) - Builder.useThrowsOrRethrowsKeyword(std::move(*Throws)); - Builder.useArrow(std::move(Arrow)); - Builder.useReturnType(std::move(*SecondTy)); - - SyntaxContext->addSyntax(Builder.build()); - - auto FunctionType = SyntaxContext->topNode(); - tyR = Generator.generate(FunctionType, RealTypeLoc); - - if (generics || isVoid) { - auto FunctionTypeAST = cast(tyR); - - // TODO(syntaxparse): Represent 'Void -> ()' in libSyntax? - auto argsTyR = FunctionTypeAST->getArgsTypeRepr(); - if (isVoid) - argsTyR = TupleTypeRepr::createEmpty(Context, tyR->getSourceRange()); - - // TODO(syntaxparse): Represent SIL generic type in libSyntax. - tyR = new (Context) FunctionTypeRepr( - generics, argsTyR, FunctionTypeAST->getThrowsLoc(), - FunctionTypeAST->getArrowLoc(), FunctionTypeAST->getResultTypeRepr()); - } - } else if (generics) { - // Only function types may be generic. - auto brackets = generics->getSourceRange(); - diagnose(brackets.Start, diag::generic_non_function); - GenericsScope.reset(); - - // Forget any generic parameters we saw in the type. - class EraseTypeParamWalker : public ASTWalker { - public: - bool walkToTypeReprPre(TypeRepr *T) override { - if (auto ident = dyn_cast(T)) { - if (auto decl = ident->getBoundDecl()) { - if (auto genericParam = dyn_cast(decl)) - ident->overwriteIdentifier(genericParam->getName()); - } - } - return true; - } - - } walker; - - if (tyR) - tyR->walk(walker); } - if (specifierLoc.isValid() || !attrs.empty()) - SyntaxContext->setCreateSyntax(SyntaxKind::AttributedType); - auto attributedType = applyAttributeToType(tyR, attrs, specifier, specifierLoc); + auto arrowLoc = Tok.getLoc(); + auto arrow = consumeTokenSyntax(tok::arrow); + if (Tok.is(tok::kw_throws)) { + Diag<> DiagID = diag::throws_in_wrong_position; + diagnose(Tok.getLoc(), DiagID) + .fixItInsert(arrowLoc, "throws ") + .fixItRemove(Tok.getLoc()); + ignoreToken(); + } - Generator.addType(attributedType, TypeLoc); + auto input = ty.get(); + auto result = parseTypeSyntax(diag::expected_type_function_result); + status |= result.getStatus(); - return makeParserResult(attributedType); + ParsedFunctionTypeSyntaxBuilder builder(*SyntaxContext); + if (auto tuple = input.getAs()) { + assert(tuple->getRaw().isDeferredLayout()); + builder.useLeftParen(tuple->getDeferredLeftParen()); + builder.useArguments(tuple->getDeferredElements()); + builder.useRightParen(tuple->getDeferredRightParen()); + } else { + builder.addArgumentsMember(ParsedSyntaxRecorder::makeTupleTypeElement( + std::move(input), /*TrailingComma=*/None, *SyntaxContext)); + + // Diagnose only if the result type is successfully parsed, to reduce the + // noisy diagnostics. + if (result.isSuccess()) { + auto charRange = Lexer::getCharSourceRangeFromSourceRange( + SourceMgr, {startLoc, endLoc}); + auto diag = diagnose(startLoc, diag::function_type_no_parens); + if (SourceMgr.extractText(charRange) == "Void") { + diag.fixItReplace(startLoc, "()"); + } else { + diag.highlight(SourceRange(startLoc, endLoc)); + diag.fixItInsert(startLoc, "("); + diag.fixItInsertAfter(endLoc, ")"); + } + } + } + + if (throws) + builder.useThrowsOrRethrowsKeyword(std::move(*throws)); + builder.useArrow(std::move(arrow)); + if (!result.isNull()) + builder.useReturnType(result.get()); + else + builder.useReturnType( + ParsedSyntaxRecorder::makeUnknownType({}, *SyntaxContext)); + + ParsedFunctionTypeSyntax funcTy = builder.build(); + + // Apply generic parameters if exists in SIL mode. + if (genericParams) { + auto silTy = ParsedSyntaxRecorder::makeSILFunctionType( + std::move(*genericParams), std::move(funcTy), *SyntaxContext); + return applyAttributeToTypeSyntax( + makeParsedResult(std::move(silTy), status), std::move(specifier), + std::move(attrs)); + } + + return applyAttributeToTypeSyntax(makeParsedResult(std::move(funcTy), status), + std::move(specifier), std::move(attrs)); } -Parser::TypeASTResult Parser::parseDeclResultType(Diag<> MessageID) { +ParsedSyntaxResult Parser::parseTypeSyntax() { + return parseTypeSyntax(diag::expected_type); +} + +ParserResult Parser::parseType(Diag<> MessageID, + bool HandleCodeCompletion, + bool IsSILFuncDecl) { + auto leadingLoc = leadingTriviaLoc(); + auto result = parseTypeSyntax(MessageID, HandleCodeCompletion, IsSILFuncDecl); + auto status = result.getStatus(); + if (result.isNull()) + return status; + + SyntaxContext->addSyntax(result.get()); + auto syntax = SyntaxContext->topNode(); + auto tyR = Generator.generate(syntax, leadingLoc, IsSILFuncDecl); + if (!tyR) + status.setIsParseError(); + return makeParserResult(status, tyR); +} + +ParserResult Parser::parseType() { + return parseType(diag::expected_type); +} + + +ParserResult Parser::parseDeclResultType(Diag<> MessageID) { if (Tok.is(tok::code_complete)) { if (CodeCompletion) CodeCompletion->completeTypeDeclResultBeginning(); @@ -588,9 +572,9 @@ Parser::parseGenericArgumentClauseSyntax() { return makeParsedResult(builder.build(), status); } -ParserStatus -Parser::parseGenericArgumentsAST(SmallVectorImpl &ArgsAST, - SourceLoc &LAngleLoc, SourceLoc &RAngleLoc) { +ParserStatus Parser::parseGenericArguments(SmallVectorImpl &ArgsAST, + SourceLoc &LAngleLoc, + SourceLoc &RAngleLoc) { auto StartLoc = leadingTriviaLoc(); auto ParsedClauseResult = parseGenericArgumentClauseSyntax(); if (ParsedClauseResult.isNull()) @@ -613,16 +597,13 @@ Parser::parseGenericArgumentsAST(SmallVectorImpl &ArgsAST, /// type-identifier: /// identifier generic-args? ('.' identifier generic-args?)* /// -Parser::TypeResult Parser::parseTypeIdentifier() { +ParsedSyntaxResult Parser::parseTypeIdentifier() { if (Tok.isNot(tok::identifier) && Tok.isNot(tok::kw_Self)) { // is this the 'Any' type if (Tok.is(tok::kw_Any)) return parseAnyType(); if (Tok.is(tok::code_complete)) { - if (CodeCompletion) - CodeCompletion->completeTypeSimpleBeginning(); - auto CCTok = consumeTokenSyntax(tok::code_complete); auto ty = ParsedSyntaxRecorder::makeCodeCompletionType( None, None, std::move(CCTok), *SyntaxContext); @@ -713,9 +694,6 @@ Parser::TypeResult Parser::parseTypeIdentifier() { assert(!genericArgs); if (Tok.is(tok::code_complete)) { - if (CodeCompletion) - CodeCompletion->completeTypeIdentifierWithDot(); - auto ty = ParsedSyntaxRecorder::makeCodeCompletionType( result.get(), std::move(period), consumeTokenSyntax(), *SyntaxContext); @@ -730,9 +708,6 @@ Parser::TypeResult Parser::parseTypeIdentifier() { if (result.isSuccess() && Tok.is(tok::code_complete) && !Tok.isAtStartOfLine()) { - if (CodeCompletion) - CodeCompletion->completeTypeIdentifierWithoutDot(); - auto ty = ParsedSyntaxRecorder::makeCodeCompletionType( result.get(), None, consumeTokenSyntax(), *SyntaxContext); return makeParsedCodeCompletion(std::move(ty)); @@ -749,28 +724,12 @@ Parser::TypeResult Parser::parseTypeIdentifier() { return result; } -Parser::TypeASTResult -Parser::parseTypeSimpleOrCompositionAST(Diag<> MessageID, - bool HandleCodeCompletion) { - auto Loc = leadingTriviaLoc(); - - auto Result = - parseTypeSimpleOrComposition(MessageID, HandleCodeCompletion); - if (!Result.isNull()) { - SyntaxContext->addSyntax(Result.get()); - auto ty = SyntaxContext->topNode(); - return makeParserResult(Result.getStatus(), Generator.generate(ty, Loc)); - } else { - return Result.getStatus(); - } -} - /// parseTypeSimpleOrComposition /// /// type-composition: /// 'some'? type-simple /// type-composition '&' type-simple -Parser::TypeResult +ParsedSyntaxResult Parser::parseTypeSimpleOrComposition(Diag<> MessageID, bool HandleCodeCompletion) { // Check for the opaque modifier. @@ -858,7 +817,7 @@ Parser::parseTypeSimpleOrComposition(Diag<> MessageID, ApplySome(std::move(Composition), std::move(FirstSome)), Status); } -Parser::TypeASTResult Parser::parseAnyTypeAST() { +ParserResult Parser::parseAnyTypeAST() { auto AnyLoc = leadingTriviaLoc(); auto ParsedAny = parseAnyType().get(); SyntaxContext->addSyntax(std::move(ParsedAny)); @@ -866,7 +825,7 @@ Parser::TypeASTResult Parser::parseAnyTypeAST() { return makeParserResult(Generator.generate(Any, AnyLoc)); } -Parser::TypeResult Parser::parseAnyType() { +ParsedSyntaxResult Parser::parseAnyType() { auto Any = consumeTokenSyntax(tok::kw_Any); auto Type = ParsedSyntaxRecorder::makeSimpleTypeIdentifier( std::move(Any), llvm::None, *SyntaxContext); @@ -881,7 +840,8 @@ Parser::TypeResult Parser::parseAnyType() { /// type-composition-list-deprecated: /// type-identifier /// type-composition-list-deprecated ',' type-identifier -Parser::TypeResult Parser::parseOldStyleProtocolComposition() { +ParsedSyntaxResult +Parser::parseOldStyleProtocolComposition() { // Defer all nodes so that we can de-structure the composed types in case we // need to emit a diagnostic (below). DeferringContextRAII Deferring(*SyntaxContext); @@ -997,7 +957,7 @@ Parser::TypeResult Parser::parseOldStyleProtocolComposition() { /// type-tuple-element: /// identifier? identifier ':' type /// type -Parser::TypeResult Parser::parseTypeTupleBody() { +ParsedSyntaxResult Parser::parseTypeTupleBody() { // Force the context to create deferred nodes, as we might need to // de-structure the tuple type to create a function type. DeferringContextRAII Deferring(*SyntaxContext); @@ -1104,7 +1064,7 @@ Parser::TypeResult Parser::parseTypeTupleBody() { // Parse the type annotation. auto TypeLoc = Tok.getLoc(); auto ty = parseTypeSyntax(diag::expected_type); - if (ty.hasCodeCompletion() || ty.isNull()) { + if (ty.isError()) { std::move(LocalJunk.begin(), LocalJunk.end(), std::back_inserter(Junk)); if (!ty.isNull()) Junk.push_back(ty.get()); @@ -1112,22 +1072,28 @@ Parser::TypeResult Parser::parseTypeTupleBody() { return ty.getStatus(); } - if (IsInOutObsoleted) { - bool IsTypeAlreadyAttributed = false; - if (auto AttributedType = ty.getAs()) { - IsTypeAlreadyAttributed = - AttributedType->getDeferredSpecifier().hasValue(); - ty = makeParsedResult(std::move(*AttributedType), ty.getStatus()); - } - - if (IsTypeAlreadyAttributed) { - // If the parsed type is already attributed, suggest removing `inout`. - diagnose(Tok, diag::parameter_specifier_repeated) - .fixItRemove(InOutLoc); + if (InOut) { + if (IsInOutObsoleted) { + bool IsTypeAlreadyAttributed = false; + if (auto AttributedType = ty.getAs()) { + IsTypeAlreadyAttributed = + AttributedType->getDeferredSpecifier().hasValue(); + ty = makeParsedResult(std::move(*AttributedType), ty.getStatus()); + } + if (IsTypeAlreadyAttributed) { + // If the parsed type is already attributed, suggest removing `inout`. + diagnose(Tok, diag::parameter_specifier_repeated) + .fixItRemove(InOutLoc); + } else { + diagnose(InOutLoc, diag::parameter_specifier_as_attr_disallowed, "inout") + .fixItRemove(InOutLoc) + .fixItInsert(TypeLoc, "inout "); + } } else { - diagnose(InOutLoc, diag::parameter_specifier_as_attr_disallowed, "inout") - .fixItRemove(InOutLoc) - .fixItInsert(TypeLoc, "inout "); + // Apply 'inout' to the parsed type. + ParsedAttributedTypeSyntaxBuilder builder(*SyntaxContext); + ty = applyAttributeToTypeSyntax(std::move(ty), std::move(InOut), None); + InOut.reset(); } } @@ -1256,8 +1222,8 @@ Parser::TypeResult Parser::parseTypeTupleBody() { /// type-array '[' ']' /// type-array '[' expr ']' /// -Parser::TypeResult Parser::parseTypeArray(ParsedTypeSyntax Base, - SourceLoc BaseLoc) { +ParsedSyntaxResult +Parser::parseTypeArray(ParsedTypeSyntax Base, SourceLoc BaseLoc) { assert(Tok.isFollowingLSquare()); auto LSquareLoc = Tok.getLoc(); ignoreToken(tok::l_square); @@ -1278,18 +1244,23 @@ Parser::TypeResult Parser::parseTypeArray(ParsedTypeSyntax Base, } ParsedArrayTypeSyntaxBuilder builder(*SyntaxContext); - builder.useElementType(std::move(Base)); - if (RSquare) - builder.useRightSquareBracket(std::move(*RSquare)); + ParserStatus status; - return makeParsedError(builder.build()); + builder.useElementType(std::move(Base)); + if (RSquare) { + builder.useRightSquareBracket(std::move(*RSquare)); + } else { + status.setIsParseError(); + } + + return makeParsedResult(builder.build(), status); } /// Parse a collection type. /// type-simple: /// '[' type ']' /// '[' type ':' type ']' -Parser::TypeResult Parser::parseTypeCollection() { +ParsedSyntaxResult Parser::parseTypeCollection() { ParserStatus Status; assert(Tok.is(tok::l_square)); Parser::StructureMarkerRAII parsingCollection(*this, Tok); @@ -1299,14 +1270,19 @@ Parser::TypeResult Parser::parseTypeCollection() { auto ElementTypeResult = parseTypeSyntax(diag::expected_element_type); Status |= ElementTypeResult.getStatus(); auto ElementType = ElementTypeResult.getOrNull(); + if (!ElementType) + ElementType = ParsedSyntaxRecorder::makeUnknownType({}, *SyntaxContext); Optional Colon; Optional ValueType; if (Tok.is(tok::colon)) { Colon = consumeTokenSyntax(tok::colon); - auto ValueTypeResult = parseTypeSyntax(diag::expected_dictionary_value_type); + auto ValueTypeResult = + parseTypeSyntax(diag::expected_dictionary_value_type); ValueType = ValueTypeResult.getOrNull(); + if (!ValueType) + ValueType = ParsedSyntaxRecorder::makeUnknownType({}, *SyntaxContext); Status |= ValueTypeResult.getStatus(); } @@ -1314,39 +1290,32 @@ Parser::TypeResult Parser::parseTypeCollection() { : diag::expected_rbracket_array_type; SourceLoc RSquareLoc; - auto RSquare = parseMatchingTokenSyntax(tok::r_square, RSquareLoc, Diag, - LSquareLoc); + auto RSquare = + parseMatchingTokenSyntax(tok::r_square, RSquareLoc, Diag, LSquareLoc); if (!RSquare) Status.setIsParseError(); - if (!Status.isSuccess()) { - SmallVector Pieces; - Pieces.push_back(std::move(LSquare)); - if (ElementType) - Pieces.push_back(std::move(*ElementType)); - if (Colon) - Pieces.push_back(std::move(*Colon)); - if (ValueType) - Pieces.push_back(std::move(*ValueType)); + if (Colon) { + ParsedDictionaryTypeSyntaxBuilder builder(*SyntaxContext); + builder.useLeftSquareBracket(std::move(LSquare)); + builder.useKeyType(std::move(*ElementType)); + builder.useColon(std::move(*Colon)); + builder.useValueType(std::move(*ValueType)); if (RSquare) - Pieces.push_back(std::move(*RSquare)); - - ParsedTypeSyntax ty = - ParsedSyntaxRecorder::makeUnknownType(Pieces, *SyntaxContext); - return makeParsedResult(std::move(ty), Status); + builder.useRightSquareBracket(std::move(*RSquare)); + return makeParsedResult(builder.build(), Status); + } else { + ParsedArrayTypeSyntaxBuilder builder(*SyntaxContext); + builder.useLeftSquareBracket(std::move(LSquare)); + builder.useElementType(std::move(*ElementType)); + if (RSquare) + builder.useRightSquareBracket(std::move(*RSquare)); + return makeParsedResult(builder.build(), Status); } - - if (Colon) - return makeParsedResult(ParsedSyntaxRecorder::makeDictionaryType( - std::move(LSquare), std::move(*ElementType), std::move(*Colon), - std::move(*ValueType), std::move(*RSquare), *SyntaxContext)); - - return makeParsedResult(ParsedSyntaxRecorder::makeArrayType( - std::move(LSquare), std::move(*ElementType), std::move(*RSquare), - *SyntaxContext)); } -Parser::TypeResult Parser::parseMetatypeType(ParsedTypeSyntax Base) { +ParsedSyntaxResult +Parser::parseMetatypeType(ParsedTypeSyntax Base) { auto Period = consumeTokenSyntax(); // tok::period or tok::period_prefix auto Keyword = consumeTokenSyntax(tok::identifier); // "Type" or "Protocol" auto MetatypeType = ParsedSyntaxRecorder::makeMetatypeType( @@ -1405,14 +1374,15 @@ SourceLoc Parser::consumeImplicitlyUnwrappedOptionalToken() { return consumeStartingCharacterOfCurrentToken(tok::exclaim_postfix); } -Parser::TypeResult Parser::parseOptionalType(ParsedTypeSyntax Base) { +ParsedSyntaxResult +Parser::parseOptionalType(ParsedTypeSyntax Base) { auto Question = consumeOptionalTokenSyntax(); auto Optional = ParsedSyntaxRecorder::makeOptionalType( std::move(Base), std::move(Question), *SyntaxContext); return makeParsedResult(std::move(Optional)); } -Parser::TypeResult +ParsedSyntaxResult Parser::parseImplicitlyUnwrappedOptionalType(ParsedTypeSyntax Base) { auto Exclamation = consumeImplicitlyUnwrappedOptionalTokenSyntax(); auto Unwrapped = ParsedSyntaxRecorder::makeImplicitlyUnwrappedOptionalType( diff --git a/lib/Parse/ParsedSyntaxBuilders.cpp.gyb b/lib/Parse/ParsedSyntaxBuilders.cpp.gyb index 2d574a05986..da17313b2c7 100644 --- a/lib/Parse/ParsedSyntaxBuilders.cpp.gyb +++ b/lib/Parse/ParsedSyntaxBuilders.cpp.gyb @@ -88,6 +88,8 @@ void Parsed${node.name}Builder::finishLayout(bool deferred) { % child_node = NODE_MAP.get(child.syntax_kind) % if child_node and child_node.is_syntax_collection(): % child_elt = child_node.collection_element_name +% child_elt_type = child_node.collection_element_type +% child_elt_name = child.name + 'Member' % if child_elt: if (!${child_elt_name}s.empty()) { if (deferred) { diff --git a/lib/PrintAsObjC/DeclAndTypePrinter.cpp b/lib/PrintAsObjC/DeclAndTypePrinter.cpp index 3df71be5f82..64fd30bd96c 100644 --- a/lib/PrintAsObjC/DeclAndTypePrinter.cpp +++ b/lib/PrintAsObjC/DeclAndTypePrinter.cpp @@ -393,12 +393,12 @@ private: os << " SWIFT_COMPILE_NAME(\"" << Elt->getName() << "\")"; } - if (auto ILE = cast_or_null(Elt->getRawValueExpr())) { - os << " = "; - if (ILE->isNegative()) - os << "-"; - os << ILE->getDigitsText(); - } + // Print the raw values, even the ones that we synthesize. + auto *ILE = cast(Elt->getStructuralRawValueExpr()); + os << " = "; + if (ILE->isNegative()) + os << "-"; + os << ILE->getDigitsText(); os << ",\n"; } os << "};\n"; diff --git a/lib/SIL/AbstractionPattern.cpp b/lib/SIL/AbstractionPattern.cpp index f95ab07f8fb..ff1b499c681 100644 --- a/lib/SIL/AbstractionPattern.cpp +++ b/lib/SIL/AbstractionPattern.cpp @@ -368,7 +368,7 @@ AbstractionPattern::getCXXMethodSelfPattern(CanType selfType) const { // insufficient --- if we have interesting bridging to do to // 'self' --- we have the right information to be more exact. auto clangSelfType = - CXXMethod->getThisType(CXXMethod->getASTContext()).getTypePtr(); + CXXMethod->getThisType().getTypePtr(); return AbstractionPattern(getGenericSignatureForFunctionComponent(), selfType, clangSelfType); } diff --git a/lib/SIL/MemoryLifetime.cpp b/lib/SIL/MemoryLifetime.cpp index ab798689035..a80b13eef44 100644 --- a/lib/SIL/MemoryLifetime.cpp +++ b/lib/SIL/MemoryLifetime.cpp @@ -806,7 +806,7 @@ void MemoryLifetimeVerifier::checkFunction(MemoryDataflow &dataFlow) { const Bits &nonTrivialLocations = locations.getNonTrivialLocations(); Bits bits(locations.getNumLocations()); for (BlockState &st : dataFlow) { - if (!st.reachableFromEntry) + if (!st.reachableFromEntry || !st.exitReachable) continue; // Check all instructions in the block. @@ -976,6 +976,7 @@ void MemoryLifetimeVerifier::verify() { if (locations.getNumLocations() > 0) { MemoryDataflow dataFlow(function, locations.getNumLocations()); dataFlow.entryReachabilityAnalysis(); + dataFlow.exitReachableAnalysis(); initDataflow(dataFlow); dataFlow.solveForwardWithIntersect(); checkFunction(dataFlow); diff --git a/lib/SIL/SILOwnershipVerifier.cpp b/lib/SIL/SILOwnershipVerifier.cpp index c4b19b0422e..17040c08299 100644 --- a/lib/SIL/SILOwnershipVerifier.cpp +++ b/lib/SIL/SILOwnershipVerifier.cpp @@ -20,7 +20,6 @@ #include "swift/AST/Types.h" #include "swift/Basic/Range.h" #include "swift/Basic/STLExtras.h" -#include "swift/Basic/TransformArrayRef.h" #include "swift/ClangImporter/ClangModule.h" #include "swift/SIL/BasicBlockUtils.h" #include "swift/SIL/BranchPropagatedUser.h" @@ -569,13 +568,19 @@ bool SILValueOwnershipChecker::checkUses() { //===----------------------------------------------------------------------===// void SILInstruction::verifyOperandOwnership() const { -#ifndef NDEBUG if (DisableOwnershipVerification) return; if (isStaticInitializerInst()) return; +#ifdef NDEBUG + // When compiling without asserts enabled, only verify ownership if + // -sil-verify-all is set. + if (!getModule().getOptions().VerifyAll) + return; +#endif + // If SILOwnership is not enabled, do not perform verification. if (!getModule().getOptions().VerifySILOwnership) return; @@ -631,14 +636,37 @@ void SILInstruction::verifyOperandOwnership() const { "At this point, we are expected to assert"); llvm_unreachable("triggering standard assertion failure routine"); } -#endif } void SILValue::verifyOwnership(DeadEndBlocks *deadEndBlocks) const { -#ifndef NDEBUG if (DisableOwnershipVerification) return; + // Do not validate SILUndef values. + if (isa(Value)) + return; + +#ifdef NDEBUG + // When compiling without asserts enabled, only verify ownership if + // -sil-verify-all is set. + // + // NOTE: We purposely return if we do can not look up a module here to ensure + // that if we run into something that we do not understand, we do not assert + // in user code even tohugh we aren't going to actually verify (the default + // behavior when -sil-verify-all is disabled). + auto *Mod = Value->getModule(); + if (!Mod || !Mod->getOptions().VerifyAll) + return; +#endif + + // Make sure that we are not a value of an instruction in a SILGlobalVariable + // block. + if (auto *definingInst = getDefiningInstruction()) { + if (definingInst->isStaticInitializerInst()) { + return; + } + } + // Since we do not have SILUndef, we now know that getFunction() should return // a real function. Assert in case this assumption is no longer true. SILFunction *f = (*this)->getFunction(); @@ -667,5 +695,4 @@ void SILValue::verifyOwnership(DeadEndBlocks *deadEndBlocks) const { liveBlocks) .check(); } -#endif } diff --git a/lib/SILOptimizer/ARC/ARCMatchingSet.cpp b/lib/SILOptimizer/ARC/ARCMatchingSet.cpp index dff2579427d..442a4c9011b 100644 --- a/lib/SILOptimizer/ARC/ARCMatchingSet.cpp +++ b/lib/SILOptimizer/ARC/ARCMatchingSet.cpp @@ -12,24 +12,24 @@ #define DEBUG_TYPE "arc-sequence-opts" -#include "RefCountState.h" #include "ARCMatchingSet.h" +#include "RefCountState.h" #include "swift/Basic/BlotMapVector.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILVisitor.h" -#include "swift/SILOptimizer/Utils/Local.h" -#include "swift/SILOptimizer/PassManager/Transforms.h" #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" #include "swift/SILOptimizer/Analysis/AliasAnalysis.h" #include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h" #include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h" +#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "llvm/ADT/MapVector.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/MapVector.h" -#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Statistic.h" -#include "llvm/Support/Debug.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" using namespace swift; diff --git a/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp b/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp index f4e0cdc07c4..00d284761f6 100644 --- a/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp +++ b/lib/SILOptimizer/ARC/ARCSequenceOpts.cpp @@ -12,28 +12,28 @@ #define DEBUG_TYPE "arc-sequence-opts" -#include "swift/SILOptimizer/PassManager/Passes.h" #include "ARCSequenceOpts.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILVisitor.h" -#include "swift/SILOptimizer/Utils/Local.h" -#include "swift/SILOptimizer/Utils/LoopUtils.h" -#include "swift/SILOptimizer/PassManager/Transforms.h" #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" #include "swift/SILOptimizer/Analysis/AliasAnalysis.h" #include "swift/SILOptimizer/Analysis/EpilogueARCAnalysis.h" -#include "swift/SILOptimizer/Analysis/ProgramTerminationAnalysis.h" -#include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h" -#include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h" -#include "swift/SILOptimizer/Analysis/LoopRegionAnalysis.h" #include "swift/SILOptimizer/Analysis/LoopAnalysis.h" +#include "swift/SILOptimizer/Analysis/LoopRegionAnalysis.h" +#include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h" +#include "swift/SILOptimizer/Analysis/ProgramTerminationAnalysis.h" +#include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h" +#include "swift/SILOptimizer/PassManager/Passes.h" +#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "swift/SILOptimizer/Utils/LoopUtils.h" +#include "llvm/ADT/MapVector.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/MapVector.h" -#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Statistic.h" -#include "llvm/Support/Debug.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" using namespace swift; diff --git a/lib/SILOptimizer/Analysis/ARCAnalysis.cpp b/lib/SILOptimizer/Analysis/ARCAnalysis.cpp index 74d1ceb5ffd..f600f0d0523 100644 --- a/lib/SILOptimizer/Analysis/ARCAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/ARCAnalysis.cpp @@ -15,16 +15,16 @@ #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" #include "swift/SIL/DebugUtils.h" #include "swift/SIL/InstructionUtils.h" +#include "swift/SIL/Projection.h" #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILInstruction.h" -#include "swift/SIL/Projection.h" #include "swift/SILOptimizer/Analysis/AliasAnalysis.h" #include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h" #include "swift/SILOptimizer/Analysis/ValueTracking.h" -#include "swift/SILOptimizer/Utils/Local.h" -#include "llvm/ADT/StringSwitch.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Debug.h" using namespace swift; diff --git a/lib/SILOptimizer/Analysis/AliasAnalysis.cpp b/lib/SILOptimizer/Analysis/AliasAnalysis.cpp index acbd467d374..b70518c0b81 100644 --- a/lib/SILOptimizer/Analysis/AliasAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/AliasAnalysis.cpp @@ -12,18 +12,18 @@ #define DEBUG_TYPE "sil-aa" #include "swift/SILOptimizer/Analysis/AliasAnalysis.h" -#include "swift/SILOptimizer/Analysis/ValueTracking.h" -#include "swift/SILOptimizer/Analysis/SideEffectAnalysis.h" -#include "swift/SILOptimizer/Analysis/EscapeAnalysis.h" -#include "swift/SILOptimizer/Utils/Local.h" -#include "swift/SILOptimizer/PassManager/PassManager.h" +#include "swift/SIL/InstructionUtils.h" #include "swift/SIL/Projection.h" -#include "swift/SIL/SILValue.h" -#include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILFunction.h" +#include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILModule.h" -#include "swift/SIL/InstructionUtils.h" +#include "swift/SIL/SILValue.h" +#include "swift/SILOptimizer/Analysis/EscapeAnalysis.h" +#include "swift/SILOptimizer/Analysis/SideEffectAnalysis.h" +#include "swift/SILOptimizer/Analysis/ValueTracking.h" +#include "swift/SILOptimizer/PassManager/PassManager.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" diff --git a/lib/SILOptimizer/Analysis/Analysis.cpp b/lib/SILOptimizer/Analysis/Analysis.cpp index 2fc7354f9ec..ac1b76de4bb 100644 --- a/lib/SILOptimizer/Analysis/Analysis.cpp +++ b/lib/SILOptimizer/Analysis/Analysis.cpp @@ -12,19 +12,19 @@ #define DEBUG_TYPE "sil-analysis" #include "swift/SILOptimizer/Analysis/Analysis.h" +#include "swift/AST/Module.h" +#include "swift/AST/SILOptions.h" +#include "swift/SIL/SILFunction.h" +#include "swift/SIL/SILModule.h" #include "swift/SILOptimizer/Analysis/BasicCalleeAnalysis.h" +#include "swift/SILOptimizer/Analysis/ClassHierarchyAnalysis.h" #include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" #include "swift/SILOptimizer/Analysis/IVAnalysis.h" #include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h" -#include "swift/SILOptimizer/Analysis/ClassHierarchyAnalysis.h" #include "swift/SILOptimizer/Analysis/ProtocolConformanceAnalysis.h" -#include "swift/AST/Module.h" -#include "swift/AST/SILOptions.h" -#include "swift/SIL/SILModule.h" -#include "swift/SIL/SILFunction.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/Debug.h" -#include "swift/SILOptimizer/Utils/Local.h" using namespace swift; diff --git a/lib/SILOptimizer/Analysis/ArraySemantic.cpp b/lib/SILOptimizer/Analysis/ArraySemantic.cpp index e01864c3089..52282d2a7cf 100644 --- a/lib/SILOptimizer/Analysis/ArraySemantic.cpp +++ b/lib/SILOptimizer/Analysis/ArraySemantic.cpp @@ -10,14 +10,14 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/StringSwitch.h" #include "swift/SILOptimizer/Analysis/ArraySemantic.h" -#include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" -#include "swift/SILOptimizer/Utils/Local.h" #include "swift/SIL/DebugUtils.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILFunction.h" +#include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "llvm/ADT/StringSwitch.h" using namespace swift; diff --git a/lib/SILOptimizer/Analysis/BasicCalleeAnalysis.cpp b/lib/SILOptimizer/Analysis/BasicCalleeAnalysis.cpp index 5aae7d49271..904518a21b8 100644 --- a/lib/SILOptimizer/Analysis/BasicCalleeAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/BasicCalleeAnalysis.cpp @@ -13,9 +13,10 @@ #include "swift/SILOptimizer/Analysis/BasicCalleeAnalysis.h" #include "swift/AST/Decl.h" +#include "swift/AST/ProtocolConformance.h" #include "swift/Basic/Statistic.h" #include "swift/SIL/SILModule.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/Support/Compiler.h" #include diff --git a/lib/SILOptimizer/Analysis/CFG.cpp b/lib/SILOptimizer/Analysis/CFG.cpp deleted file mode 100644 index a079be8ce56..00000000000 --- a/lib/SILOptimizer/Analysis/CFG.cpp +++ /dev/null @@ -1,107 +0,0 @@ -//===--- CFG.cpp ----------------------------------------------------------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// - -#include "swift/SILOptimizer/Analysis/CFG.h" -#include "swift/SIL/SILFunction.h" -#include "swift/SIL/SILInstruction.h" -#include "swift/SIL/SILValue.h" -#include "swift/Demangling/ManglingMacros.h" -#include "llvm/ADT/TinyPtrVector.h" - -using namespace swift; - -static bool isSafeNonExitTerminator(TermInst *TI) { - switch (TI->getTermKind()) { - case TermKind::BranchInst: - case TermKind::CondBranchInst: - case TermKind::SwitchValueInst: - case TermKind::SwitchEnumInst: - case TermKind::SwitchEnumAddrInst: - case TermKind::DynamicMethodBranchInst: - case TermKind::CheckedCastBranchInst: - case TermKind::CheckedCastValueBranchInst: - case TermKind::CheckedCastAddrBranchInst: - return true; - case TermKind::UnreachableInst: - case TermKind::ReturnInst: - case TermKind::ThrowInst: - case TermKind::UnwindInst: - return false; - // yield is special because it can do arbitrary, - // potentially-process-terminating things. - case TermKind::YieldInst: - return false; - case TermKind::TryApplyInst: - return true; - } - - llvm_unreachable("Unhandled TermKind in switch."); -} - -static bool isTrapNoReturnFunction(ApplyInst *AI) { - const char *fatalName = - MANGLE_AS_STRING(MANGLE_SYM(s18_fatalErrorMessageyys12StaticStringV_AcCSutF)); - auto *Fn = AI->getReferencedFunctionOrNull(); - - // We use endswith here since if we specialize fatal error we will always - // prepend the specialization records to fatalName. - if (!Fn || !Fn->getName().endswith(fatalName)) - return false; - - return true; -} - -bool -swift:: -findAllNonFailureExitBBs(SILFunction *F, - llvm::TinyPtrVector &BBs) { - for (SILBasicBlock &BB : *F) { - TermInst *TI = BB.getTerminator(); - - // If we know that this terminator is not an exit terminator, continue. - if (isSafeNonExitTerminator(TI)) - continue; - - // A return inst is always a non-failure exit bb. - if (TI->isFunctionExiting()) { - BBs.push_back(&BB); - continue; - } - - // If we don't have an unreachable inst at this point, this is a terminator - // we don't understand. Be conservative and return false. - if (!isa(TI)) - return false; - - // Ok, at this point we know we have a terminator. If it is the only - // instruction in our BB, it is a failure BB. continue... - if (TI == &*BB.begin()) - continue; - - // If the unreachable is preceded by a no-return apply inst, then it is a - // non-failure exit BB. Add it to our list and continue. - auto PrevIter = std::prev(SILBasicBlock::iterator(TI)); - if (auto *AI = dyn_cast(&*PrevIter)) { - if (AI->isCalleeNoReturn() && - !isTrapNoReturnFunction(AI)) { - BBs.push_back(&BB); - continue; - } - } - - // Otherwise, it must be a failure BB where we leak, continue. - continue; - } - - // We understood all terminators, return true. - return true; -} diff --git a/lib/SILOptimizer/Analysis/CMakeLists.txt b/lib/SILOptimizer/Analysis/CMakeLists.txt index 009fea5b7e3..58be25ffa01 100644 --- a/lib/SILOptimizer/Analysis/CMakeLists.txt +++ b/lib/SILOptimizer/Analysis/CMakeLists.txt @@ -7,7 +7,6 @@ silopt_register_sources( ArraySemantic.cpp BasicCalleeAnalysis.cpp CallerAnalysis.cpp - CFG.cpp ClassHierarchyAnalysis.cpp ClosureScope.cpp ColdBlockInfo.cpp diff --git a/lib/SILOptimizer/Analysis/CallerAnalysis.cpp b/lib/SILOptimizer/Analysis/CallerAnalysis.cpp index c2894f10725..f27316bd95e 100644 --- a/lib/SILOptimizer/Analysis/CallerAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/CallerAnalysis.cpp @@ -14,7 +14,8 @@ #include "swift/SILOptimizer/Analysis/CallerAnalysis.h" #include "swift/SIL/InstructionUtils.h" #include "swift/SIL/SILModule.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SIL/SILVisitor.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/YAMLTraits.h" diff --git a/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp b/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp index 8924baa8f90..0b6316d9b80 100644 --- a/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp @@ -12,13 +12,13 @@ #define DEBUG_TYPE "sil-escape" #include "swift/SILOptimizer/Analysis/EscapeAnalysis.h" -#include "swift/SILOptimizer/Analysis/BasicCalleeAnalysis.h" +#include "swift/SIL/DebugUtils.h" +#include "swift/SIL/SILArgument.h" #include "swift/SILOptimizer/Analysis/ArraySemantic.h" +#include "swift/SILOptimizer/Analysis/BasicCalleeAnalysis.h" #include "swift/SILOptimizer/Analysis/ValueTracking.h" #include "swift/SILOptimizer/PassManager/PassManager.h" -#include "swift/SILOptimizer/Utils/Local.h" -#include "swift/SIL/SILArgument.h" -#include "swift/SIL/DebugUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/Support/GraphWriter.h" #include "llvm/Support/raw_ostream.h" diff --git a/lib/SILOptimizer/Analysis/SimplifyInstruction.cpp b/lib/SILOptimizer/Analysis/SimplifyInstruction.cpp index 914650a6bda..1ffe2bb525b 100644 --- a/lib/SILOptimizer/Analysis/SimplifyInstruction.cpp +++ b/lib/SILOptimizer/Analysis/SimplifyInstruction.cpp @@ -25,7 +25,7 @@ #include "swift/SIL/PatternMatch.h" #include "swift/SIL/SILVisitor.h" #include "swift/SILOptimizer/Analysis/ValueTracking.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" using namespace swift; using namespace swift::PatternMatch; diff --git a/lib/SILOptimizer/Analysis/TypeExpansionAnalysis.cpp b/lib/SILOptimizer/Analysis/TypeExpansionAnalysis.cpp index 9758746fb8a..203e7cca659 100644 --- a/lib/SILOptimizer/Analysis/TypeExpansionAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/TypeExpansionAnalysis.cpp @@ -14,7 +14,7 @@ #include "swift/SILOptimizer/Analysis/TypeExpansionAnalysis.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILModule.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/Support/Debug.h" using namespace swift; diff --git a/lib/SILOptimizer/Analysis/ValueTracking.cpp b/lib/SILOptimizer/Analysis/ValueTracking.cpp index 58d0e3aac98..43a067b3224 100644 --- a/lib/SILOptimizer/Analysis/ValueTracking.cpp +++ b/lib/SILOptimizer/Analysis/ValueTracking.cpp @@ -12,13 +12,13 @@ #define DEBUG_TYPE "sil-value-tracking" #include "swift/SILOptimizer/Analysis/ValueTracking.h" -#include "swift/SILOptimizer/Analysis/SimplifyInstruction.h" +#include "swift/SIL/InstructionUtils.h" +#include "swift/SIL/PatternMatch.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILValue.h" -#include "swift/SIL/InstructionUtils.h" -#include "swift/SILOptimizer/Utils/Local.h" -#include "swift/SIL/PatternMatch.h" +#include "swift/SILOptimizer/Analysis/SimplifyInstruction.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/Support/Debug.h" using namespace swift; using namespace swift::PatternMatch; diff --git a/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialSpecializer.cpp b/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialSpecializer.cpp index 0d93ef676ec..6a10833dc58 100644 --- a/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialSpecializer.cpp +++ b/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialSpecializer.cpp @@ -22,7 +22,7 @@ #include "swift/SILOptimizer/Analysis/ProtocolConformanceAnalysis.h" #include "swift/SILOptimizer/PassManager/Transforms.h" #include "swift/SILOptimizer/Utils/Existential.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" diff --git a/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp b/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp index 85006473260..37f1fbaf2c6 100644 --- a/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp +++ b/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp @@ -23,10 +23,9 @@ #include "swift/SIL/SILInstruction.h" #include "swift/SIL/TypeSubstCloner.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" +#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h" #include "swift/SILOptimizer/Utils/Existential.h" #include "swift/SILOptimizer/Utils/Generics.h" -#include "swift/SILOptimizer/Utils/Local.h" #include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "swift/SILOptimizer/Utils/SpecializationMangler.h" #include "llvm/ADT/SmallVector.h" diff --git a/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.h b/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.h index 424595c8d4e..79ad59ec7eb 100644 --- a/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.h +++ b/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.h @@ -20,7 +20,7 @@ #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILInstruction.h" #include "swift/SILOptimizer/Utils/Existential.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "swift/SILOptimizer/Utils/SpecializationMangler.h" #include "llvm/ADT/SmallBitVector.h" diff --git a/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp b/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp index b683e260647..106503643ae 100644 --- a/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp +++ b/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp @@ -34,7 +34,6 @@ #include "swift/SIL/DebugUtils.h" #include "swift/SIL/SILCloner.h" #include "swift/SIL/SILFunction.h" -#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "swift/SIL/SILValue.h" #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" #include "swift/SILOptimizer/Analysis/CallerAnalysis.h" @@ -42,8 +41,9 @@ #include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/SILInliner.h" +#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "swift/SILOptimizer/Utils/SpecializationMangler.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/CommandLine.h" diff --git a/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.h b/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.h index 84c1f62847a..764510db9bd 100644 --- a/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.h +++ b/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.h @@ -26,7 +26,7 @@ #include "swift/SILOptimizer/Analysis/CallerAnalysis.h" #include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h" #include "swift/SILOptimizer/PassManager/PassManager.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "swift/SILOptimizer/Utils/SpecializationMangler.h" #include "llvm/ADT/DenseMap.h" diff --git a/lib/SILOptimizer/IPO/CapturePropagation.cpp b/lib/SILOptimizer/IPO/CapturePropagation.cpp index 43aec92f08d..614f8781b8b 100644 --- a/lib/SILOptimizer/IPO/CapturePropagation.cpp +++ b/lib/SILOptimizer/IPO/CapturePropagation.cpp @@ -14,7 +14,6 @@ #include "swift/AST/GenericEnvironment.h" #include "swift/Demangling/Demangle.h" #include "swift/SIL/SILCloner.h" -#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/TypeSubstCloner.h" #include "swift/SILOptimizer/Analysis/ColdBlockInfo.h" @@ -22,7 +21,8 @@ #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" #include "swift/SILOptimizer/Utils/Generics.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "swift/SILOptimizer/Utils/SpecializationMangler.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/Statistic.h" diff --git a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp index 38184d982ae..335961d249e 100644 --- a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp +++ b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp @@ -63,18 +63,19 @@ #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILModule.h" #include "swift/SILOptimizer/Analysis/BasicCalleeAnalysis.h" -#include "swift/SILOptimizer/Analysis/CFG.h" #include "swift/SILOptimizer/Analysis/FunctionOrder.h" #include "swift/SILOptimizer/Analysis/ValueTracking.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/SILInliner.h" #include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "swift/SILOptimizer/Utils/SpecializationMangler.h" #include "swift/SILOptimizer/Utils/StackNesting.h" -#include "llvm/ADT/SmallString.h" +#include "swift/SILOptimizer/Utils/ValueLifetime.h" #include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" diff --git a/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp b/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp index a533cc5f764..48bba4ae285 100644 --- a/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp +++ b/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp @@ -12,13 +12,13 @@ #define DEBUG_TYPE "sil-dead-function-elimination" #include "swift/AST/ProtocolConformance.h" -#include "swift/SILOptimizer/PassManager/Passes.h" -#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SIL/InstructionUtils.h" #include "swift/SIL/PatternMatch.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILVisitor.h" -#include "swift/SIL/InstructionUtils.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/PassManager/Passes.h" +#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" diff --git a/lib/SILOptimizer/IPO/GlobalOpt.cpp b/lib/SILOptimizer/IPO/GlobalOpt.cpp index f2e18428c6b..0fcd0d7f390 100644 --- a/lib/SILOptimizer/IPO/GlobalOpt.cpp +++ b/lib/SILOptimizer/IPO/GlobalOpt.cpp @@ -17,14 +17,16 @@ #include "swift/Demangling/ManglingMacros.h" #include "swift/SIL/CFG.h" #include "swift/SIL/DebugUtils.h" -#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" +#include "swift/SIL/SILCloner.h" #include "swift/SIL/SILGlobalVariable.h" #include "swift/SIL/SILInstruction.h" #include "swift/SILOptimizer/Analysis/ColdBlockInfo.h" #include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SCCIterator.h" #include "llvm/Support/CommandLine.h" diff --git a/lib/SILOptimizer/IPO/GlobalPropertyOpt.cpp b/lib/SILOptimizer/IPO/GlobalPropertyOpt.cpp index 86500322f54..b0b6dc0ecd1 100644 --- a/lib/SILOptimizer/IPO/GlobalPropertyOpt.cpp +++ b/lib/SILOptimizer/IPO/GlobalPropertyOpt.cpp @@ -11,20 +11,20 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "globalpropertyopt" -#include "swift/SILOptimizer/PassManager/Passes.h" +#include "swift/SIL/SILArgument.h" +#include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILInstruction.h" -#include "swift/SIL/SILArgument.h" #include "swift/SIL/SILModule.h" -#include "swift/SIL/SILBuilder.h" -#include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" #include "swift/SILOptimizer/Analysis/ArraySemantic.h" +#include "swift/SILOptimizer/PassManager/Passes.h" +#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseMapInfo.h" #include "llvm/ADT/Statistic.h" -#include "llvm/Support/Debug.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/Debug.h" using namespace swift; diff --git a/lib/SILOptimizer/IPO/LetPropertiesOpts.cpp b/lib/SILOptimizer/IPO/LetPropertiesOpts.cpp index ed90ade92b1..6fc43adc5fe 100644 --- a/lib/SILOptimizer/IPO/LetPropertiesOpts.cpp +++ b/lib/SILOptimizer/IPO/LetPropertiesOpts.cpp @@ -26,7 +26,8 @@ #include "swift/SIL/SILLinkage.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/MapVector.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" diff --git a/lib/SILOptimizer/IPO/UsePrespecialized.cpp b/lib/SILOptimizer/IPO/UsePrespecialized.cpp index 42f39f5c203..2b1e8f58aa4 100644 --- a/lib/SILOptimizer/IPO/UsePrespecialized.cpp +++ b/lib/SILOptimizer/IPO/UsePrespecialized.cpp @@ -11,16 +11,16 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "use-prespecialized" +#include "swift/SIL/SILBuilder.h" +#include "swift/SIL/SILFunction.h" +#include "swift/SIL/SILInstruction.h" +#include "swift/SIL/SILModule.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" -#include "swift/SILOptimizer/Utils/SpecializationMangler.h" -#include "swift/SIL/SILBuilder.h" -#include "swift/SIL/SILInstruction.h" -#include "swift/SIL/SILFunction.h" -#include "swift/SIL/SILModule.h" -#include "llvm/Support/Debug.h" #include "swift/SILOptimizer/Utils/Generics.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "swift/SILOptimizer/Utils/SpecializationMangler.h" +#include "llvm/Support/Debug.h" using namespace swift; diff --git a/lib/SILOptimizer/LoopTransforms/ArrayBoundsCheckOpts.cpp b/lib/SILOptimizer/LoopTransforms/ArrayBoundsCheckOpts.cpp index c9c07299331..3af89ed40f5 100644 --- a/lib/SILOptimizer/LoopTransforms/ArrayBoundsCheckOpts.cpp +++ b/lib/SILOptimizer/LoopTransforms/ArrayBoundsCheckOpts.cpp @@ -12,8 +12,15 @@ #define DEBUG_TYPE "sil-abcopts" -#include "swift/Basic/STLExtras.h" #include "swift/AST/Builtins.h" +#include "swift/Basic/STLExtras.h" +#include "swift/SIL/Dominance.h" +#include "swift/SIL/InstructionUtils.h" +#include "swift/SIL/PatternMatch.h" +#include "swift/SIL/SILArgument.h" +#include "swift/SIL/SILBuilder.h" +#include "swift/SIL/SILFunction.h" +#include "swift/SIL/SILInstruction.h" #include "swift/SILOptimizer/Analysis/AliasAnalysis.h" #include "swift/SILOptimizer/Analysis/Analysis.h" #include "swift/SILOptimizer/Analysis/ArraySemantic.h" @@ -24,16 +31,9 @@ #include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/SILSSAUpdater.h" -#include "swift/SIL/Dominance.h" -#include "swift/SIL/PatternMatch.h" -#include "swift/SIL/SILArgument.h" -#include "swift/SIL/SILBuilder.h" -#include "swift/SIL/SILFunction.h" -#include "swift/SIL/SILInstruction.h" -#include "swift/SIL/InstructionUtils.h" #include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/PointerIntPair.h" diff --git a/lib/SILOptimizer/LoopTransforms/COWArrayOpt.cpp b/lib/SILOptimizer/LoopTransforms/COWArrayOpt.cpp index 4afd42b8640..b7838207e27 100644 --- a/lib/SILOptimizer/LoopTransforms/COWArrayOpt.cpp +++ b/lib/SILOptimizer/LoopTransforms/COWArrayOpt.cpp @@ -11,26 +11,26 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "cowarray-opts" -#include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SIL/CFG.h" +#include "swift/SIL/DebugUtils.h" +#include "swift/SIL/InstructionUtils.h" #include "swift/SIL/Projection.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILCloner.h" #include "swift/SIL/SILInstruction.h" -#include "swift/SIL/DebugUtils.h" -#include "swift/SIL/InstructionUtils.h" -#include "swift/SILOptimizer/Analysis/ArraySemantic.h" -#include "swift/SILOptimizer/Analysis/AliasAnalysis.h" #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" +#include "swift/SILOptimizer/Analysis/AliasAnalysis.h" +#include "swift/SILOptimizer/Analysis/ArraySemantic.h" #include "swift/SILOptimizer/Analysis/ColdBlockInfo.h" #include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" #include "swift/SILOptimizer/Analysis/LoopAnalysis.h" #include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h" #include "swift/SILOptimizer/Analysis/ValueTracking.h" +#include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/SILSSAUpdater.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/StringExtras.h" diff --git a/lib/SILOptimizer/LoopTransforms/LICM.cpp b/lib/SILOptimizer/LoopTransforms/LICM.cpp index a3921290eec..10e4d6b7012 100644 --- a/lib/SILOptimizer/LoopTransforms/LICM.cpp +++ b/lib/SILOptimizer/LoopTransforms/LICM.cpp @@ -27,8 +27,8 @@ #include "swift/SILOptimizer/Analysis/SideEffectAnalysis.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/SILSSAUpdater.h" #include "llvm/ADT/DepthFirstIterator.h" diff --git a/lib/SILOptimizer/LoopTransforms/LoopRotate.cpp b/lib/SILOptimizer/LoopTransforms/LoopRotate.cpp index 52c622c4821..31500702043 100644 --- a/lib/SILOptimizer/LoopTransforms/LoopRotate.cpp +++ b/lib/SILOptimizer/LoopTransforms/LoopRotate.cpp @@ -13,17 +13,18 @@ #define DEBUG_TYPE "sil-looprotate" #include "swift/SIL/Dominance.h" +#include "swift/SIL/SILArgument.h" +#include "swift/SIL/SILBuilder.h" +#include "swift/SIL/SILInstruction.h" #include "swift/SILOptimizer/Analysis/Analysis.h" #include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" #include "swift/SILOptimizer/Analysis/LoopAnalysis.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" -#include "swift/SILOptimizer/Utils/SILSSAUpdater.h" +#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" #include "swift/SILOptimizer/Utils/LoopUtils.h" -#include "swift/SIL/SILArgument.h" -#include "swift/SIL/SILBuilder.h" -#include "swift/SIL/SILInstruction.h" +#include "swift/SILOptimizer/Utils/SILSSAUpdater.h" #include "llvm/Support/Debug.h" #include "llvm/Support/CommandLine.h" @@ -34,18 +35,18 @@ static llvm::cl::opt ShouldRotate("sil-looprotate", llvm::cl::init(true)); /// Check whether all operands are loop invariant. -static bool hasLoopInvariantOperands(SILInstruction *I, SILLoop *L, - llvm::DenseSet &Inv) { - auto Opds = I->getAllOperands(); +static bool +hasLoopInvariantOperands(SILInstruction *inst, SILLoop *loop, + llvm::DenseSet &invariant) { + auto operands = inst->getAllOperands(); - return std::all_of(Opds.begin(), Opds.end(), [=](Operand &Op) { - - ValueBase *Def = Op.get(); + return llvm::all_of(operands, [=](Operand &operand) { + ValueBase *def = operand.get(); // Operand is outside the loop or marked invariant. - if (auto *Inst = Def->getDefiningInstruction()) - return !L->contains(Inst->getParent()) || Inv.count(Inst); - if (auto *Arg = dyn_cast(Def)) - return !L->contains(Arg->getParent()); + if (auto *inst = def->getDefiningInstruction()) + return !loop->contains(inst->getParent()) || invariant.count(inst); + if (auto *arg = dyn_cast(def)) + return !loop->contains(arg->getParent()); return false; }); @@ -54,76 +55,72 @@ static bool hasLoopInvariantOperands(SILInstruction *I, SILLoop *L, /// We cannot duplicate blocks with AllocStack instructions (they need to be /// FIFO). Other instructions can be moved to the preheader. static bool -canDuplicateOrMoveToPreheader(SILLoop *L, SILBasicBlock *Preheader, - SILBasicBlock *Blk, - SmallVectorImpl &Move) { - llvm::DenseSet Invariant; - for (auto &I : *Blk) { - auto *Inst = &I; - if (auto *MI = dyn_cast(Inst)) { +canDuplicateOrMoveToPreheader(SILLoop *loop, SILBasicBlock *preheader, + SILBasicBlock *bb, + SmallVectorImpl &moves) { + llvm::DenseSet invariants; + for (auto &instRef : *bb) { + auto *inst = &instRef; + if (auto *MI = dyn_cast(inst)) { if (MI->getMember().isForeign) return false; - if (!hasLoopInvariantOperands(Inst, L, Invariant)) + if (!hasLoopInvariantOperands(inst, loop, invariants)) continue; - Move.push_back(Inst); - Invariant.insert(Inst); - } else if (!I.isTriviallyDuplicatable()) + moves.push_back(inst); + invariants.insert(inst); + } else if (!inst->isTriviallyDuplicatable()) return false; - else if (isa(Inst)) { - Move.push_back(Inst); - Invariant.insert(Inst); - } else if (isa(Inst)) { - Move.push_back(Inst); - Invariant.insert(Inst); - } - else if (isa(Inst)) { - Move.push_back(Inst); - Invariant.insert(Inst); - } else if (isa(Inst)) { - Move.push_back(Inst); - Invariant.insert(Inst); - } else if (!Inst->mayHaveSideEffects() && - !Inst->mayReadFromMemory() && - !isa(Inst) && - !isa(Inst) && /* not marked mayhavesideffects */ - hasLoopInvariantOperands(Inst, L, Invariant)) { - Move.push_back(Inst); - Invariant.insert(Inst); + else if (isa(inst)) { + moves.push_back(inst); + invariants.insert(inst); + } else if (isa(inst)) { + moves.push_back(inst); + invariants.insert(inst); + } else if (isa(inst)) { + moves.push_back(inst); + invariants.insert(inst); + } else if (isa(inst)) { + moves.push_back(inst); + invariants.insert(inst); + } else if (!inst->mayHaveSideEffects() && !inst->mayReadFromMemory() + && !isa(inst) && !isa(inst) + && /* not marked mayhavesideffects */ + hasLoopInvariantOperands(inst, loop, invariants)) { + moves.push_back(inst); + invariants.insert(inst); } } return true; } -static void mapOperands(SILInstruction *I, - const llvm::DenseMap &ValueMap) { - for (auto &Opd : I->getAllOperands()) { - SILValue OrigVal = Opd.get(); - ValueBase *OrigDef = OrigVal; - auto Found = ValueMap.find(OrigDef); - if (Found != ValueMap.end()) { - SILValue MappedVal = Found->second; - Opd.set(MappedVal); +static void mapOperands(SILInstruction *inst, + const llvm::DenseMap &valueMap) { + for (auto &operand : inst->getAllOperands()) { + SILValue origVal = operand.get(); + ValueBase *origDef = origVal; + auto found = valueMap.find(origDef); + if (found != valueMap.end()) { + SILValue mappedVal = found->second; + operand.set(mappedVal); } } } static void updateSSAForUseOfValue( - SILSSAUpdater &Updater, SmallVectorImpl &InsertedPHIs, - const llvm::DenseMap &ValueMap, - SILBasicBlock *Header, SILBasicBlock *EntryCheckBlock, - SILValue Res) { + SILSSAUpdater &updater, SmallVectorImpl &insertedPhis, + const llvm::DenseMap &valueMap, + SILBasicBlock *Header, SILBasicBlock *EntryCheckBlock, SILValue Res) { // Find the mapped instruction. - assert(ValueMap.count(Res) && "Expected to find value in map!"); - SILValue MappedValue = ValueMap.find(Res)->second; + assert(valueMap.count(Res) && "Expected to find value in map!"); + SILValue MappedValue = valueMap.find(Res)->second; assert(MappedValue); assert(Res->getType() == MappedValue->getType() && "The types must match"); - InsertedPHIs.clear(); - Updater.Initialize(Res->getType()); - Updater.AddAvailableValue(Header, Res); - Updater.AddAvailableValue(EntryCheckBlock, MappedValue); - + insertedPhis.clear(); + updater.Initialize(Res->getType()); + updater.AddAvailableValue(Header, Res); + updater.AddAvailableValue(EntryCheckBlock, MappedValue); // Because of the way that phi nodes are represented we have to collect all // uses before we update SSA. Modifying one phi node can invalidate another @@ -131,26 +128,26 @@ static void updateSSAForUseOfValue( // has to be modified). This would invalidate a plain ValueUseIterator. // Instead we collect uses wrapping uses in branches specially so that we // can reconstruct the use even after the branch has been modified. - SmallVector StoredUses; - for (auto *U : Res->getUses()) - StoredUses.push_back(UseWrapper(U)); - for (auto U : StoredUses) { - Operand *Use = U; - SILInstruction *User = Use->getUser(); - assert(User && "Missing user"); + SmallVector storedUses; + for (auto *use : Res->getUses()) + storedUses.push_back(UseWrapper(use)); + for (auto useWrapper : storedUses) { + Operand *use = useWrapper; + SILInstruction *user = use->getUser(); + assert(user && "Missing user"); // Ignore uses in the same basic block. - if (User->getParent() == Header) + if (user->getParent() == Header) continue; - assert(User->getParent() != EntryCheckBlock && - "The entry check block should dominate the header"); - Updater.RewriteUse(*Use); + assert(user->getParent() != EntryCheckBlock + && "The entry check block should dominate the header"); + updater.RewriteUse(*use); } // Canonicalize inserted phis to avoid extra BB Args. - for (SILPhiArgument *Arg : InsertedPHIs) { - if (SILValue Inst = replaceBBArgWithCast(Arg)) { - Arg->replaceAllUsesWith(Inst); + for (SILPhiArgument *arg : insertedPhis) { + if (SILValue inst = replaceBBArgWithCast(arg)) { + arg->replaceAllUsesWith(inst); // DCE+SimplifyCFG runs as a post-pass cleanup. // DCE replaces dead arg values with undef. // SimplifyCFG deletes the dead BB arg. @@ -158,72 +155,76 @@ static void updateSSAForUseOfValue( } } -static void updateSSAForUseOfInst( - SILSSAUpdater &Updater, SmallVectorImpl &InsertedPHIs, - const llvm::DenseMap &ValueMap, - SILBasicBlock *Header, SILBasicBlock *EntryCheckBlock, - SILInstruction *Inst) { - for (auto result : Inst->getResults()) - updateSSAForUseOfValue(Updater, InsertedPHIs, ValueMap, Header, - EntryCheckBlock, result); +static void +updateSSAForUseOfInst(SILSSAUpdater &updater, + SmallVectorImpl &insertedPhis, + const llvm::DenseMap &valueMap, + SILBasicBlock *header, SILBasicBlock *entryCheckBlock, + SILInstruction *inst) { + for (auto result : inst->getResults()) + updateSSAForUseOfValue(updater, insertedPhis, valueMap, header, + entryCheckBlock, result); } /// Rewrite the code we just created in the preheader and update SSA form. -static void -rewriteNewLoopEntryCheckBlock(SILBasicBlock *Header, - SILBasicBlock *EntryCheckBlock, - const llvm::DenseMap &ValueMap) { - SmallVector InsertedPHIs; - SILSSAUpdater Updater(&InsertedPHIs); +static void rewriteNewLoopEntryCheckBlock( + SILBasicBlock *header, SILBasicBlock *entryCheckBlock, + const llvm::DenseMap &valueMap) { + SmallVector insertedPhis; + SILSSAUpdater updater(&insertedPhis); // Fix PHIs (incoming arguments). - for (auto *Arg : Header->getArguments()) - updateSSAForUseOfValue(Updater, InsertedPHIs, ValueMap, Header, - EntryCheckBlock, Arg); + for (auto *arg : header->getArguments()) + updateSSAForUseOfValue(updater, insertedPhis, valueMap, header, + entryCheckBlock, arg); - auto InstIter = Header->begin(); + auto instIter = header->begin(); // The terminator might change from under us. - while (InstIter != Header->end()) { - auto &Inst = *InstIter; - updateSSAForUseOfInst(Updater, InsertedPHIs, ValueMap, Header, - EntryCheckBlock, &Inst); - InstIter++; + while (instIter != header->end()) { + auto &inst = *instIter; + updateSSAForUseOfInst(updater, insertedPhis, valueMap, header, + entryCheckBlock, &inst); + instIter++; } } /// Update the dominator tree after rotating the loop. /// The former preheader now dominates all of the former headers children. The /// former latch now dominates the former header. -static void updateDomTree(DominanceInfo *DT, SILBasicBlock *Preheader, - SILBasicBlock *Latch, SILBasicBlock *Header) { - auto *HeaderN = DT->getNode(Header); - SmallVector Children(HeaderN->begin(), - HeaderN->end()); - auto *PreheaderN = DT->getNode(Preheader); +static void updateDomTree(DominanceInfo *domInfo, SILBasicBlock *preheader, + SILBasicBlock *latch, SILBasicBlock *header) { + auto *headerN = domInfo->getNode(header); + SmallVector Children(headerN->begin(), + headerN->end()); + auto *preheaderN = domInfo->getNode(preheader); for (auto *Child : Children) - DT->changeImmediateDominator(Child, PreheaderN); + domInfo->changeImmediateDominator(Child, preheaderN); - if (Header != Latch) - DT->changeImmediateDominator(HeaderN, DT->getNode(Latch)); + if (header != latch) + domInfo->changeImmediateDominator(headerN, domInfo->getNode(latch)); } -static bool rotateLoopAtMostUpToLatch(SILLoop *L, DominanceInfo *DT, - SILLoopInfo *LI, bool ShouldVerify) { - auto *Latch = L->getLoopLatch(); - if (!Latch) { - LLVM_DEBUG(llvm::dbgs() << *L << " does not have a single latch block\n"); +static bool rotateLoopAtMostUpToLatch(SILLoop *loop, DominanceInfo *domInfo, + SILLoopInfo *loopInfo, + bool ShouldVerify) { + auto *latch = loop->getLoopLatch(); + if (!latch) { + LLVM_DEBUG(llvm::dbgs() + << *loop << " does not have a single latch block\n"); return false; } - bool DidRotate = rotateLoop(L, DT, LI, false /* RotateSingleBlockLoops */, - Latch, ShouldVerify); + bool didRotate = + rotateLoop(loop, domInfo, loopInfo, false /* rotateSingleBlockLoops */, + latch, ShouldVerify); // Keep rotating at most until we hit the original latch. - if (DidRotate) - while (rotateLoop(L, DT, LI, false, Latch, ShouldVerify)) {} + if (didRotate) + while (rotateLoop(loop, domInfo, loopInfo, false, latch, ShouldVerify)) { + } - return DidRotate; + return didRotate; } /// Check whether this a single basic block loop - ignoring split back edges. @@ -236,16 +237,16 @@ static bool isSingleBlockLoop(SILLoop *L) { if (NumBlocks == 1) return true; - auto *Header = L->getHeader(); + auto *header = L->getHeader(); auto *BackEdge = Blocks[1]; - if (BackEdge == Header) + if (BackEdge == header) BackEdge = Blocks[0]; if (!BackEdge->getSingleSuccessorBlock()) return false; - assert(BackEdge->getSingleSuccessorBlock() == Header && - "Loop not well formed"); + assert(BackEdge->getSingleSuccessorBlock() == header + && "Loop not well formed"); // Check whether the back-edge block is just a split-edge. return ++BackEdge->begin() == BackEdge->end(); @@ -259,153 +260,155 @@ static bool isSingleBlockLoop(SILLoop *L) { /// /// We will rotate at most up to the basic block passed as an argument. /// We will not rotate a loop where the header is equal to the latch except is -/// RotateSingleBlockLoops is true. +/// rotateSingleBlockLoops is true. /// /// Note: The code relies on the 'UpTo' basic block to stay within the rotate /// loop for termination. -bool swift::rotateLoop(SILLoop *L, DominanceInfo *DT, SILLoopInfo *LI, - bool RotateSingleBlockLoops, SILBasicBlock *UpTo, - bool ShouldVerify) { - assert(L != nullptr && DT != nullptr && LI != nullptr && - "Missing loop information"); +bool swift::rotateLoop(SILLoop *loop, DominanceInfo *domInfo, + SILLoopInfo *loopInfo, bool rotateSingleBlockLoops, + SILBasicBlock *upToBB, bool shouldVerify) { + assert(loop != nullptr && domInfo != nullptr && loopInfo != nullptr + && "Missing loop information"); - auto *Header = L->getHeader(); - if (!Header) + auto *header = loop->getHeader(); + if (!header) return false; // We need a preheader - this is also a canonicalization for follow-up // passes. - auto *Preheader = L->getLoopPreheader(); - if (!Preheader) { - LLVM_DEBUG(llvm::dbgs() << *L << " no preheader\n"); - LLVM_DEBUG(L->getHeader()->getParent()->dump()); + auto *preheader = loop->getLoopPreheader(); + if (!preheader) { + LLVM_DEBUG(llvm::dbgs() << *loop << " no preheader\n"); + LLVM_DEBUG(loop->getHeader()->getParent()->dump()); return false; } - if (!RotateSingleBlockLoops && (Header == UpTo || isSingleBlockLoop(L))) + if (!rotateSingleBlockLoops && (header == upToBB || isSingleBlockLoop(loop))) return false; - assert(RotateSingleBlockLoops || L->getBlocks().size() != 1); + assert(rotateSingleBlockLoops || loop->getBlocks().size() != 1); // Need a conditional branch that guards the entry into the loop. - auto *LoopEntryBranch = dyn_cast(Header->getTerminator()); - if (!LoopEntryBranch) + auto *loopEntryBranch = dyn_cast(header->getTerminator()); + if (!loopEntryBranch) return false; // The header needs to exit the loop. - if (!L->isLoopExiting(Header)) { - LLVM_DEBUG(llvm::dbgs() << *L << " not an exiting header\n"); - LLVM_DEBUG(L->getHeader()->getParent()->dump()); + if (!loop->isLoopExiting(header)) { + LLVM_DEBUG(llvm::dbgs() << *loop << " not an exiting header\n"); + LLVM_DEBUG(loop->getHeader()->getParent()->dump()); return false; } // We need a single backedge and the latch must not exit the loop if it is // also the header. - auto *Latch = L->getLoopLatch(); - if (!Latch) { - LLVM_DEBUG(llvm::dbgs() << *L << " no single latch\n"); + auto *latch = loop->getLoopLatch(); + if (!latch) { + LLVM_DEBUG(llvm::dbgs() << *loop << " no single latch\n"); return false; } // Make sure we can duplicate the header. - SmallVector MoveToPreheader; - if (!canDuplicateOrMoveToPreheader(L, Preheader, Header, MoveToPreheader)) { - LLVM_DEBUG(llvm::dbgs() << *L - << " instructions in header preventing rotating\n"); + SmallVector moveToPreheader; + if (!canDuplicateOrMoveToPreheader(loop, preheader, header, + moveToPreheader)) { + LLVM_DEBUG(llvm::dbgs() + << *loop << " instructions in header preventing rotating\n"); return false; } - auto *NewHeader = LoopEntryBranch->getTrueBB(); - auto *Exit = LoopEntryBranch->getFalseBB(); - if (L->contains(Exit)) - std::swap(NewHeader, Exit); - assert(L->contains(NewHeader) && !L->contains(Exit) && - "Could not find loop header and exit block"); + auto *newHeader = loopEntryBranch->getTrueBB(); + auto *exit = loopEntryBranch->getFalseBB(); + if (loop->contains(exit)) + std::swap(newHeader, exit); + assert(loop->contains(newHeader) && !loop->contains(exit) + && "Could not find loop header and exit block"); // We don't want to rotate such that we merge two headers of separate loops // into one. This can be turned into an assert again once we have guaranteed // preheader insertions. - if (!NewHeader->getSinglePredecessorBlock() && Header != Latch) + if (!newHeader->getSinglePredecessorBlock() && header != latch) return false; // Now that we know we can perform the rotation - move the instructions that // need moving. - for (auto *Inst : MoveToPreheader) - Inst->moveBefore(Preheader->getTerminator()); + for (auto *inst : moveToPreheader) + inst->moveBefore(preheader->getTerminator()); - LLVM_DEBUG(llvm::dbgs() << " Rotating " << *L); + LLVM_DEBUG(llvm::dbgs() << " Rotating " << *loop); // Map the values for the duplicated header block. We are duplicating the // header instructions into the end of the preheader. - llvm::DenseMap ValueMap; + llvm::DenseMap valueMap; // The original 'phi' argument values are just the values coming from the // preheader edge. - ArrayRef PHIs = Header->getArguments(); - OperandValueArrayRef PreheaderArgs = - cast(Preheader->getTerminator())->getArgs(); - assert(PHIs.size() == PreheaderArgs.size() && - "Basic block arguments and incoming edge mismatch"); + ArrayRef phis = header->getArguments(); + OperandValueArrayRef preheaderArgs = + cast(preheader->getTerminator())->getArgs(); + assert(phis.size() == preheaderArgs.size() + && "Basic block arguments and incoming edge mismatch"); // Here we also store the value index to use into the value map (versus // non-argument values where the operand use decides which value index to // use). - for (unsigned Idx = 0, E = PHIs.size(); Idx != E; ++Idx) - ValueMap[PHIs[Idx]] = PreheaderArgs[Idx]; + for (unsigned Idx = 0, E = phis.size(); Idx != E; ++Idx) + valueMap[phis[Idx]] = preheaderArgs[Idx]; // The other instructions are just cloned to the preheader. - TermInst *PreheaderBranch = Preheader->getTerminator(); - for (auto &Inst : *Header) { - if (SILInstruction *cloned = Inst.clone(PreheaderBranch)) { - mapOperands(cloned, ValueMap); + TermInst *preheaderBranch = preheader->getTerminator(); + for (auto &inst : *header) { + if (SILInstruction *cloned = inst.clone(preheaderBranch)) { + mapOperands(cloned, valueMap); // The actual operand will sort out which result idx to use. - auto instResults = Inst.getResults(); + auto instResults = inst.getResults(); auto clonedResults = cloned->getResults(); assert(instResults.size() == clonedResults.size()); for (auto i : indices(instResults)) - ValueMap[instResults[i]] = clonedResults[i]; + valueMap[instResults[i]] = clonedResults[i]; } } - PreheaderBranch->dropAllReferences(); - PreheaderBranch->eraseFromParent(); + preheaderBranch->dropAllReferences(); + preheaderBranch->eraseFromParent(); // If there were any uses of instructions in the duplicated loop entry check // block rewrite them using the ssa updater. - rewriteNewLoopEntryCheckBlock(Header, Preheader, ValueMap); + rewriteNewLoopEntryCheckBlock(header, preheader, valueMap); - L->moveToHeader(NewHeader); + loop->moveToHeader(newHeader); // Now the original preheader dominates all of headers children and the // original latch dominates the header. - updateDomTree(DT, Preheader, Latch, Header); + updateDomTree(domInfo, preheader, latch, header); - assert(DT->getNode(NewHeader)->getIDom() == DT->getNode(Preheader)); - assert(!DT->dominates(Header, Exit) || - DT->getNode(Exit)->getIDom() == DT->getNode(Preheader)); - assert(DT->getNode(Header)->getIDom() == DT->getNode(Latch) || - ((Header == Latch) && - DT->getNode(Header)->getIDom() == DT->getNode(Preheader))); + assert(domInfo->getNode(newHeader)->getIDom() == domInfo->getNode(preheader)); + assert(!domInfo->dominates(header, exit) + || domInfo->getNode(exit)->getIDom() == domInfo->getNode(preheader)); + assert(domInfo->getNode(header)->getIDom() == domInfo->getNode(latch) + || ((header == latch) + && domInfo->getNode(header)->getIDom() + == domInfo->getNode(preheader))); // Beautify the IR. Move the old header to after the old latch as it is now // the latch. - Header->moveAfter(Latch); + header->moveAfter(latch); // Merge the old latch with the old header if possible. - mergeBasicBlockWithSuccessor(Latch, DT, LI); + mergeBasicBlockWithSuccessor(latch, domInfo, loopInfo); // Create a new preheader. - splitIfCriticalEdge(Preheader, NewHeader, DT, LI); + splitIfCriticalEdge(preheader, newHeader, domInfo, loopInfo); - if (ShouldVerify) { - DT->verify(); - LI->verify(); - Latch->getParent()->verify(); + if (shouldVerify) { + domInfo->verify(); + loopInfo->verify(); + latch->getParent()->verify(); } - LLVM_DEBUG(llvm::dbgs() << " to " << *L); - LLVM_DEBUG(L->getHeader()->getParent()->dump()); + LLVM_DEBUG(llvm::dbgs() << " to " << *loop); + LLVM_DEBUG(loop->getHeader()->getParent()->dump()); return true; } @@ -414,58 +417,59 @@ namespace { class LoopRotation : public SILFunctionTransform { void run() override { - SILLoopAnalysis *LA = PM->getAnalysis(); - assert(LA); - DominanceAnalysis *DA = PM->getAnalysis(); - assert(DA); + SILLoopAnalysis *loopAnalysis = PM->getAnalysis(); + assert(loopAnalysis); + DominanceAnalysis *domAnalysis = PM->getAnalysis(); + assert(domAnalysis); - SILFunction *F = getFunction(); - assert(F); + SILFunction *f = getFunction(); + assert(f); // FIXME: Add ownership support. - if (F->hasOwnership()) + if (f->hasOwnership()) return; - SILLoopInfo *LI = LA->get(F); - assert(LI); - DominanceInfo *DT = DA->get(F); + SILLoopInfo *loopInfo = loopAnalysis->get(f); + assert(loopInfo); + DominanceInfo *domInfo = domAnalysis->get(f); - if (LI->empty()) { - LLVM_DEBUG(llvm::dbgs() << "No loops in " << F->getName() << "\n"); + if (loopInfo->empty()) { + LLVM_DEBUG(llvm::dbgs() << "No loops in " << f->getName() << "\n"); return; } if (!ShouldRotate) { - LLVM_DEBUG(llvm::dbgs() << "Skipping loop rotation in " << F->getName() - << "\n"); + LLVM_DEBUG(llvm::dbgs() + << "Skipping loop rotation in " << f->getName() << "\n"); return; } - LLVM_DEBUG(llvm::dbgs() << "Rotating loops in " << F->getName() << "\n"); - bool ShouldVerify = getOptions().VerifyAll; + LLVM_DEBUG(llvm::dbgs() << "Rotating loops in " << f->getName() << "\n"); + bool shouldVerify = getOptions().VerifyAll; - bool Changed = false; - for (auto *LoopIt : *LI) { + bool changed = false; + for (auto *LoopIt : *loopInfo) { // Rotate loops recursively bottom-up in the loop tree. - SmallVector Worklist; - Worklist.push_back(LoopIt); - for (unsigned i = 0; i < Worklist.size(); ++i) { - auto *L = Worklist[i]; + SmallVector worklist; + worklist.push_back(LoopIt); + for (unsigned i = 0; i < worklist.size(); ++i) { + auto *L = worklist[i]; for (auto *SubLoop : *L) - Worklist.push_back(SubLoop); + worklist.push_back(SubLoop); } - while (!Worklist.empty()) { - SILLoop *Loop = Worklist.pop_back_val(); - Changed |= canonicalizeLoop(Loop, DT, LI); - Changed |= rotateLoopAtMostUpToLatch(Loop, DT, LI, ShouldVerify); + while (!worklist.empty()) { + SILLoop *loop = worklist.pop_back_val(); + changed |= canonicalizeLoop(loop, domInfo, loopInfo); + changed |= + rotateLoopAtMostUpToLatch(loop, domInfo, loopInfo, shouldVerify); } } - if (Changed) { + if (changed) { // We preserve loop info and the dominator tree. - DA->lockInvalidation(); - LA->lockInvalidation(); - PM->invalidateAnalysis(F, SILAnalysis::InvalidationKind::FunctionBody); - DA->unlockInvalidation(); - LA->unlockInvalidation(); + domAnalysis->lockInvalidation(); + loopAnalysis->lockInvalidation(); + PM->invalidateAnalysis(f, SILAnalysis::InvalidationKind::FunctionBody); + domAnalysis->unlockInvalidation(); + loopAnalysis->unlockInvalidation(); } } }; diff --git a/lib/SILOptimizer/Mandatory/AddressLowering.cpp b/lib/SILOptimizer/Mandatory/AddressLowering.cpp index 864f1464ab0..061bdab9cb2 100644 --- a/lib/SILOptimizer/Mandatory/AddressLowering.cpp +++ b/lib/SILOptimizer/Mandatory/AddressLowering.cpp @@ -96,7 +96,7 @@ #include "swift/SIL/SILVisitor.h" #include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SetVector.h" #include "llvm/Support/CommandLine.h" diff --git a/lib/SILOptimizer/Mandatory/ClosureLifetimeFixup.cpp b/lib/SILOptimizer/Mandatory/ClosureLifetimeFixup.cpp index 2a54afb4835..d0c9c67e5c4 100644 --- a/lib/SILOptimizer/Mandatory/ClosureLifetimeFixup.cpp +++ b/lib/SILOptimizer/Mandatory/ClosureLifetimeFixup.cpp @@ -19,8 +19,8 @@ #include "swift/SIL/SILInstruction.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/SILSSAUpdater.h" #include "swift/SILOptimizer/Utils/StackNesting.h" diff --git a/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp b/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp index dbab75c357f..531d68083f6 100644 --- a/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp +++ b/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp @@ -22,8 +22,8 @@ #include "swift/SIL/SILBuilder.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/Statistic.h" diff --git a/lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp b/lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp index d7af3f17fc2..3a60405702a 100644 --- a/lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp +++ b/lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp @@ -22,8 +22,8 @@ #include "swift/SIL/SILUndef.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/Debug.h" diff --git a/lib/SILOptimizer/Mandatory/IRGenPrepare.cpp b/lib/SILOptimizer/Mandatory/IRGenPrepare.cpp index 811b212bdd6..6da647c6944 100644 --- a/lib/SILOptimizer/Mandatory/IRGenPrepare.cpp +++ b/lib/SILOptimizer/Mandatory/IRGenPrepare.cpp @@ -27,7 +27,7 @@ #include "swift/SIL/SILModule.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/Strings.h" using namespace swift; diff --git a/lib/SILOptimizer/Mandatory/MandatoryCombine.cpp b/lib/SILOptimizer/Mandatory/MandatoryCombine.cpp index ea6126fa0f1..3e0d256aaeb 100644 --- a/lib/SILOptimizer/Mandatory/MandatoryCombine.cpp +++ b/lib/SILOptimizer/Mandatory/MandatoryCombine.cpp @@ -31,7 +31,7 @@ #include "swift/SIL/SILVisitor.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/raw_ostream.h" diff --git a/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp b/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp index 76341b3f622..6504b6f338f 100644 --- a/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp +++ b/lib/SILOptimizer/Mandatory/MandatoryInlining.cpp @@ -20,9 +20,9 @@ #include "swift/SIL/OwnershipUtils.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" #include "swift/SILOptimizer/Utils/Devirtualize.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/SILInliner.h" #include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "swift/SILOptimizer/Utils/StackNesting.h" diff --git a/lib/SILOptimizer/Mandatory/OSLogOptimization.cpp b/lib/SILOptimizer/Mandatory/OSLogOptimization.cpp index 09551d05779..6a3f5dcb2cb 100644 --- a/lib/SILOptimizer/Mandatory/OSLogOptimization.cpp +++ b/lib/SILOptimizer/Mandatory/OSLogOptimization.cpp @@ -87,10 +87,13 @@ #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" #include "swift/SILOptimizer/Utils/ConstExpr.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/SILInliner.h" #include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "llvm/ADT/MapVector.h" +#include "swift/SIL/BasicBlockUtils.h" +#include "swift/SIL/CFG.h" +#include "llvm/ADT/BreadthFirstIterator.h" using namespace swift; @@ -661,52 +664,99 @@ static void constantFold(SILInstruction *start, static SILInstruction *beginOfInterpolation(ApplyInst *oslogInit) { auto oslogInitCallSite = FullApplySite(oslogInit); SILFunction *callee = oslogInitCallSite.getCalleeFunction(); - auto &astContext = oslogInit->getFunction()->getASTContext(); + assert (callee->hasSemanticsAttrThatStartsWith("oslog.message.init")); // The initializer must return the OSLogMessage instance directly. assert(oslogInitCallSite.getNumArguments() >= 1 && oslogInitCallSite.getNumIndirectSILResults() == 0); - SILInstruction *firstArgumentInst = - oslogInitCallSite.getArgument(0)->getDefiningInstruction(); - if (!firstArgumentInst) { - // oslogInit call does not correspond to an auto-generated initialization - // done by the compiler on seeing a string interpolation. Ignore this. - return nullptr; + // List of backward dependencies that needs to be analyzed. + SmallVector worklist = { oslogInit }; + SmallPtrSet seenInstructions = { oslogInit }; + // List of instructions that could potentially mark the beginning of the + // interpolation. + SmallPtrSet candidateStartInstructions; + + unsigned i = 0; + while (i < worklist.size()) { + SILInstruction *inst = worklist[i++]; + + if (isa(inst)) { + // Partial applies are used to capture the dynamic arguments passed to + // the string interpolation. Their arguments are not required to be + // known at compile time and they need not be constant evaluated. + // Therefore, do not follow this dependency chain. + continue; + } + + for (Operand &operand : inst->getAllOperands()) { + if (SILInstruction *definingInstruction = + operand.get()->getDefiningInstruction()) { + if (seenInstructions.count(definingInstruction)) + continue; + worklist.push_back(definingInstruction); + seenInstructions.insert(definingInstruction); + candidateStartInstructions.insert(definingInstruction); + } + // If there is no definining instruction for this operand, it could be a + // basic block or function parameter. Such operands are not considered + // in the backward slice. Dependencies through them are safe to ignore + // in this context. + } + + // If the instruction: `inst` has an operand, its definition should precede + // `inst` in the control-flow order. Therefore, remove `inst` from the + // candidate start instructions. + if (inst->getNumOperands() > 0) { + candidateStartInstructions.erase(inst); + } + + if (!isa(inst)) { + continue; + } + + // If we have an alloc_stack instruction, include stores into it into the + // backward dependency list. However, whether alloc_stack precedes its in + // control-flow order can only be determined by traversing the instrutions + // in the control-flow order. + AllocStackInst *allocStackInst = cast(inst); + for (StoreInst *storeInst : allocStackInst->getUsersOfType()) { + worklist.push_back(storeInst); + candidateStartInstructions.insert(storeInst); + } } + // Find the first basic block in the control-flow order. TODO: if we do not + // madatorily inline appendLiteral/Interpolation functions of + // OSLogInterpolation, we can expect all candidate instructions to be in the + // same basic block. Once @_transparent is removed from those functions, + // simplify this code. + SmallPtrSet candidateBBs; + for (auto *candidate: candidateStartInstructions) { + SILBasicBlock *candidateBB = candidate->getParent(); + candidateBBs.insert(candidateBB); + } + + SILBasicBlock *firstBB = nullptr; + SILBasicBlock *entryBB = oslogInit->getFunction()->getEntryBlock(); + for (SILBasicBlock *bb: llvm::breadth_first(entryBB)) { + if (candidateBBs.count(bb)) { + firstBB = bb; + break; + } + } + assert(firstBB); + + // Iterate over the instructions in the firstBB and find the instruction that + // starts the interpolation. SILInstruction *startInst = nullptr; - - // If this is an initialization from string interpolation, the first argument - // to the initializer is a load of an auto-generated alloc-stack of - // OSLogInterpolation: - // 'alloc_stack $OSLogInterpolation, var, name $interpolation' - // If no such instruction exists, ignore this call as this is not a - // OSLogMessage instantiation through string interpolation. - if (callee->hasSemanticsAttr("oslog.message.init_interpolation")) { - auto *loadInst = dyn_cast(firstArgumentInst); - if (!loadInst) - return nullptr; - - auto *allocStackInst = dyn_cast(loadInst->getOperand()); - if (!allocStackInst) - return nullptr; - - Optional varInfo = allocStackInst->getVarInfo(); - if (!varInfo && varInfo->Name != astContext.Id_dollarInterpolation.str()) - return nullptr; - - startInst = allocStackInst; + for (SILInstruction &inst : *firstBB) { + if (candidateStartInstructions.count(&inst)) { + startInst = &inst; + break; + } } - - // If this is an initialization from a string literal, the first argument - // should be the creation of the string literal. - if (callee->hasSemanticsAttr("oslog.message.init_stringliteral")) { - if (!getStringMakeUTF8Init(firstArgumentInst)) - return nullptr; - startInst = firstArgumentInst; - } - + assert(startInst); return startInst; } @@ -733,6 +783,27 @@ static ApplyInst *getAsOSLogMessageInit(SILInstruction *inst) { return nullptr; } +/// Return true iff this function is a protocol witness for +/// ExpressibleByStringInterpolation.init(stringInterpolation:) in OSLogMessage. +bool isAutoGeneratedInitOfOSLogMessage(SILFunction &fun) { + DeclContext *declContext = fun.getDeclContext(); + if (!declContext) + return false; + Decl *decl = declContext->getAsDecl(); + if (!decl) + return false; + ConstructorDecl *ctor = dyn_cast(decl); + if (!ctor) + return false; + DeclContext *parentContext = ctor->getParent(); + if (!parentContext) + return false; + NominalTypeDecl *typeDecl = parentContext->getSelfNominalTypeDecl(); + if (!typeDecl) + return false; + return typeDecl->getName() == fun.getASTContext().Id_OSLogMessage; +} + class OSLogOptimization : public SILFunctionTransform { ~OSLogOptimization() override {} @@ -747,6 +818,14 @@ class OSLogOptimization : public SILFunctionTransform { return; } + // Skip the auto-generated (transparent) witness method of OSLogMessage, + // which ends up invoking the OSLogMessage initializer: + // "oslog.message.init_interpolation" but without an interpolated + // string literal. + if (isAutoGeneratedInitOfOSLogMessage(fun)) { + return; + } + // Collect all 'OSLogMessage.init' in the function. 'OSLogMessage' is a // custom string interpolation type used by the new OS log APIs. SmallVector oslogMessageInits; diff --git a/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp b/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp index df5a0c71421..2e814332b30 100644 --- a/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp +++ b/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp @@ -19,7 +19,7 @@ #include "swift/SIL/SILBuilder.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/SILSSAUpdater.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/Statistic.h" diff --git a/lib/SILOptimizer/Mandatory/SILGenCleanup.cpp b/lib/SILOptimizer/Mandatory/SILGenCleanup.cpp index 5b51c722ec2..eb4c12f4d99 100644 --- a/lib/SILOptimizer/Mandatory/SILGenCleanup.cpp +++ b/lib/SILOptimizer/Mandatory/SILGenCleanup.cpp @@ -19,7 +19,7 @@ #include "swift/SIL/SILInstruction.h" #include "swift/SILOptimizer/PassManager/Transforms.h" #include "swift/SILOptimizer/Utils/CanonicalizeInstruction.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" using namespace swift; diff --git a/lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp b/lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp index 3894db77610..72fa8368a7f 100644 --- a/lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp +++ b/lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp @@ -24,7 +24,7 @@ #include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" diff --git a/lib/SILOptimizer/PassManager/PassPipeline.cpp b/lib/SILOptimizer/PassManager/PassPipeline.cpp index 997efa8264c..79974aaa9db 100644 --- a/lib/SILOptimizer/PassManager/PassPipeline.cpp +++ b/lib/SILOptimizer/PassManager/PassPipeline.cpp @@ -27,7 +27,7 @@ #include "swift/SILOptimizer/Analysis/Analysis.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/CommandLine.h" diff --git a/lib/SILOptimizer/PassManager/Passes.cpp b/lib/SILOptimizer/PassManager/Passes.cpp index 4317e83ffad..ce715dbd658 100644 --- a/lib/SILOptimizer/PassManager/Passes.cpp +++ b/lib/SILOptimizer/PassManager/Passes.cpp @@ -21,14 +21,14 @@ #define DEBUG_TYPE "sil-optimizer" +#include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/AST/ASTContext.h" #include "swift/AST/Module.h" #include "swift/SIL/SILModule.h" #include "swift/SILOptimizer/Analysis/Analysis.h" #include "swift/SILOptimizer/PassManager/PassManager.h" -#include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/CommandLine.h" diff --git a/lib/SILOptimizer/SILCombiner/SILCombine.cpp b/lib/SILOptimizer/SILCombiner/SILCombine.cpp index 7f0893d0b8f..e0b9dae9019 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombine.cpp +++ b/lib/SILOptimizer/SILCombiner/SILCombine.cpp @@ -28,7 +28,7 @@ #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" #include "swift/SILOptimizer/Utils/CanonicalizeInstruction.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" diff --git a/lib/SILOptimizer/SILCombiner/SILCombiner.h b/lib/SILOptimizer/SILCombiner/SILCombiner.h index 1a76e0d8425..609bfe79df3 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombiner.h +++ b/lib/SILOptimizer/SILCombiner/SILCombiner.h @@ -30,7 +30,7 @@ #include "swift/SILOptimizer/Analysis/ProtocolConformanceAnalysis.h" #include "swift/SILOptimizer/Utils/CastOptimizer.h" #include "swift/SILOptimizer/Utils/Existential.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp index aefddbd51de..6f9af158319 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp +++ b/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp @@ -24,9 +24,10 @@ #include "swift/SIL/SILVisitor.h" #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" #include "swift/SILOptimizer/Analysis/AliasAnalysis.h" -#include "swift/SILOptimizer/Analysis/CFG.h" #include "swift/SILOptimizer/Analysis/ValueTracking.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" #include "swift/SILOptimizer/Utils/Existential.h" +#include "swift/SILOptimizer/Utils/ValueLifetime.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerBuiltinVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerBuiltinVisitors.cpp index 9227db10cf1..7c37686e464 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombinerBuiltinVisitors.cpp +++ b/lib/SILOptimizer/SILCombiner/SILCombinerBuiltinVisitors.cpp @@ -12,19 +12,19 @@ #define DEBUG_TYPE "sil-combine" #include "SILCombiner.h" +#include "swift/SIL/DebugUtils.h" #include "swift/SIL/DynamicCasts.h" #include "swift/SIL/PatternMatch.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILVisitor.h" -#include "swift/SIL/DebugUtils.h" -#include "swift/SILOptimizer/Analysis/AliasAnalysis.h" #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" -#include "swift/SILOptimizer/Analysis/CFG.h" +#include "swift/SILOptimizer/Analysis/AliasAnalysis.h" #include "swift/SILOptimizer/Analysis/ValueTracking.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/DenseMap.h" using namespace swift; using namespace swift::PatternMatch; diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerCastVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerCastVisitors.cpp index 9d020bbb4ff..eee7bf3a22f 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombinerCastVisitors.cpp +++ b/lib/SILOptimizer/SILCombiner/SILCombinerCastVisitors.cpp @@ -12,19 +12,19 @@ #define DEBUG_TYPE "sil-combine" #include "SILCombiner.h" +#include "swift/SIL/DebugUtils.h" #include "swift/SIL/DynamicCasts.h" #include "swift/SIL/PatternMatch.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILVisitor.h" -#include "swift/SIL/DebugUtils.h" -#include "swift/SILOptimizer/Analysis/AliasAnalysis.h" #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" -#include "swift/SILOptimizer/Analysis/CFG.h" +#include "swift/SILOptimizer/Analysis/AliasAnalysis.h" #include "swift/SILOptimizer/Analysis/ValueTracking.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/DenseMap.h" using namespace swift; using namespace swift::PatternMatch; diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp index 0cf87916044..aa41f2c8d55 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp +++ b/lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp @@ -22,10 +22,10 @@ #include "swift/SIL/SILVisitor.h" #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" #include "swift/SILOptimizer/Analysis/AliasAnalysis.h" -#include "swift/SILOptimizer/Analysis/CFG.h" #include "swift/SILOptimizer/Analysis/ValueTracking.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" #include "swift/SILOptimizer/Utils/Devirtualize.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" diff --git a/lib/SILOptimizer/Transforms/ARCCodeMotion.cpp b/lib/SILOptimizer/Transforms/ARCCodeMotion.cpp index 8815b5be162..22af78be9fc 100644 --- a/lib/SILOptimizer/Transforms/ARCCodeMotion.cpp +++ b/lib/SILOptimizer/Transforms/ARCCodeMotion.cpp @@ -80,8 +80,8 @@ #include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/Strings.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/SmallPtrSet.h" diff --git a/lib/SILOptimizer/Transforms/AccessEnforcementDom.cpp b/lib/SILOptimizer/Transforms/AccessEnforcementDom.cpp index a9a6a88512b..d454493053f 100644 --- a/lib/SILOptimizer/Transforms/AccessEnforcementDom.cpp +++ b/lib/SILOptimizer/Transforms/AccessEnforcementDom.cpp @@ -56,7 +56,7 @@ #include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" #include "swift/SILOptimizer/Analysis/LoopAnalysis.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/DepthFirstIterator.h" using namespace swift; diff --git a/lib/SILOptimizer/Transforms/AccessEnforcementOpts.cpp b/lib/SILOptimizer/Transforms/AccessEnforcementOpts.cpp index 9ea227ae398..8aadfb4ce1f 100644 --- a/lib/SILOptimizer/Transforms/AccessEnforcementOpts.cpp +++ b/lib/SILOptimizer/Transforms/AccessEnforcementOpts.cpp @@ -84,7 +84,7 @@ #include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" #include "swift/SILOptimizer/Analysis/LoopRegionAnalysis.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SCCIterator.h" diff --git a/lib/SILOptimizer/Transforms/AccessEnforcementWMO.cpp b/lib/SILOptimizer/Transforms/AccessEnforcementWMO.cpp index 3dd7fd1bfc2..65df81551ad 100644 --- a/lib/SILOptimizer/Transforms/AccessEnforcementWMO.cpp +++ b/lib/SILOptimizer/Transforms/AccessEnforcementWMO.cpp @@ -59,7 +59,7 @@ #include "swift/SIL/MemAccessUtils.h" #include "swift/SIL/SILFunction.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" using namespace swift; diff --git a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp index 5168f730e1b..3f52bb1c059 100644 --- a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp +++ b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp @@ -11,16 +11,17 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "allocbox-to-stack" +#include "swift/SIL/ApplySite.h" #include "swift/SIL/Dominance.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILCloner.h" -#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "swift/SILOptimizer/Utils/SpecializationMangler.h" #include "swift/SILOptimizer/Utils/StackNesting.h" +#include "swift/SILOptimizer/Utils/ValueLifetime.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallSet.h" diff --git a/lib/SILOptimizer/Transforms/AssumeSingleThreaded.cpp b/lib/SILOptimizer/Transforms/AssumeSingleThreaded.cpp index 558752006ea..8668a6971fc 100644 --- a/lib/SILOptimizer/Transforms/AssumeSingleThreaded.cpp +++ b/lib/SILOptimizer/Transforms/AssumeSingleThreaded.cpp @@ -25,12 +25,12 @@ // //===----------------------------------------------------------------------===// -#include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILModule.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/Support/CommandLine.h" using namespace swift; diff --git a/lib/SILOptimizer/Transforms/CSE.cpp b/lib/SILOptimizer/Transforms/CSE.cpp index 79d57506eba..8021602717f 100644 --- a/lib/SILOptimizer/Transforms/CSE.cpp +++ b/lib/SILOptimizer/Transforms/CSE.cpp @@ -16,24 +16,25 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "sil-cse" -#include "swift/SILOptimizer/PassManager/Passes.h" +#include "swift/SIL/DebugUtils.h" #include "swift/SIL/Dominance.h" +#include "swift/SIL/SILCloner.h" #include "swift/SIL/SILModule.h" #include "swift/SIL/SILOpenedArchetypesTracker.h" #include "swift/SIL/SILType.h" #include "swift/SIL/SILValue.h" #include "swift/SIL/SILVisitor.h" -#include "swift/SIL/DebugUtils.h" -#include "swift/SILOptimizer/Utils/Local.h" -#include "swift/SILOptimizer/PassManager/Transforms.h" #include "swift/SILOptimizer/Analysis/ArraySemantic.h" #include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" -#include "swift/SILOptimizer/Analysis/SimplifyInstruction.h" #include "swift/SILOptimizer/Analysis/SideEffectAnalysis.h" +#include "swift/SILOptimizer/Analysis/SimplifyInstruction.h" +#include "swift/SILOptimizer/PassManager/Passes.h" +#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/Hashing.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/ScopedHashTable.h" #include "llvm/ADT/Statistic.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/Support/Debug.h" #include "llvm/Support/RecyclingAllocator.h" diff --git a/lib/SILOptimizer/Transforms/CopyForwarding.cpp b/lib/SILOptimizer/Transforms/CopyForwarding.cpp index ae4d669aa85..c33bf4bddbf 100644 --- a/lib/SILOptimizer/Transforms/CopyForwarding.cpp +++ b/lib/SILOptimizer/Transforms/CopyForwarding.cpp @@ -68,7 +68,7 @@ #include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/CommandLine.h" diff --git a/lib/SILOptimizer/Transforms/CopyPropagation.cpp b/lib/SILOptimizer/Transforms/CopyPropagation.cpp index 72fd3d8c259..185e900052f 100644 --- a/lib/SILOptimizer/Transforms/CopyPropagation.cpp +++ b/lib/SILOptimizer/Transforms/CopyPropagation.cpp @@ -127,9 +127,9 @@ #include "swift/SIL/Projection.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" #include "swift/SILOptimizer/Utils/IndexTrie.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Statistic.h" diff --git a/lib/SILOptimizer/Transforms/DeadCodeElimination.cpp b/lib/SILOptimizer/Transforms/DeadCodeElimination.cpp index c8e2bee00b9..bc9dc78059b 100644 --- a/lib/SILOptimizer/Transforms/DeadCodeElimination.cpp +++ b/lib/SILOptimizer/Transforms/DeadCodeElimination.cpp @@ -11,19 +11,19 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "sil-dce" +#include "swift/SIL/DebugUtils.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILBasicBlock.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILUndef.h" -#include "swift/SIL/DebugUtils.h" #include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" diff --git a/lib/SILOptimizer/Transforms/DeadObjectElimination.cpp b/lib/SILOptimizer/Transforms/DeadObjectElimination.cpp index 442978d1383..6056b412224 100644 --- a/lib/SILOptimizer/Transforms/DeadObjectElimination.cpp +++ b/lib/SILOptimizer/Transforms/DeadObjectElimination.cpp @@ -24,8 +24,10 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "dead-object-elim" -#include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/AST/ResilienceExpansion.h" +#include "swift/SIL/BasicBlockUtils.h" +#include "swift/SIL/DebugUtils.h" +#include "swift/SIL/InstructionUtils.h" #include "swift/SIL/Projection.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILDeclRef.h" @@ -33,14 +35,13 @@ #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILModule.h" #include "swift/SIL/SILUndef.h" -#include "swift/SIL/DebugUtils.h" -#include "swift/SIL/InstructionUtils.h" -#include "swift/SIL/BasicBlockUtils.h" #include "swift/SILOptimizer/Analysis/ArraySemantic.h" -#include "swift/SILOptimizer/Utils/IndexTrie.h" -#include "swift/SILOptimizer/Utils/Local.h" -#include "swift/SILOptimizer/Utils/SILSSAUpdater.h" +#include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SILOptimizer/Utils/IndexTrie.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "swift/SILOptimizer/Utils/SILSSAUpdater.h" +#include "swift/SILOptimizer/Utils/ValueLifetime.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/Debug.h" diff --git a/lib/SILOptimizer/Transforms/DeadStoreElimination.cpp b/lib/SILOptimizer/Transforms/DeadStoreElimination.cpp index 057d122b01b..9dc817b7337 100644 --- a/lib/SILOptimizer/Transforms/DeadStoreElimination.cpp +++ b/lib/SILOptimizer/Transforms/DeadStoreElimination.cpp @@ -64,12 +64,12 @@ #include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/LoadStoreOptUtils.h" -#include "swift/SILOptimizer/Utils/Local.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/BitVector.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/Statistic.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" diff --git a/lib/SILOptimizer/Transforms/DestroyHoisting.cpp b/lib/SILOptimizer/Transforms/DestroyHoisting.cpp index e23458a2cf1..d3ab5ab15fd 100644 --- a/lib/SILOptimizer/Transforms/DestroyHoisting.cpp +++ b/lib/SILOptimizer/Transforms/DestroyHoisting.cpp @@ -13,9 +13,9 @@ #define DEBUG_TYPE "sil-destroy-hoisting" #include "swift/SIL/MemoryLifetime.h" -#include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" #include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" +#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" #include "llvm/Support/Debug.h" using namespace swift; diff --git a/lib/SILOptimizer/Transforms/GenericSpecializer.cpp b/lib/SILOptimizer/Transforms/GenericSpecializer.cpp index 14965b38849..82dd9d4d33c 100644 --- a/lib/SILOptimizer/Transforms/GenericSpecializer.cpp +++ b/lib/SILOptimizer/Transforms/GenericSpecializer.cpp @@ -20,9 +20,9 @@ #include "swift/SIL/OptimizationRemark.h" #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILInstruction.h" -#include "swift/SILOptimizer/Utils/Generics.h" -#include "swift/SILOptimizer/Utils/Local.h" #include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SILOptimizer/Utils/Generics.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "llvm/ADT/SmallVector.h" diff --git a/lib/SILOptimizer/Transforms/MergeCondFail.cpp b/lib/SILOptimizer/Transforms/MergeCondFail.cpp index e8ad4f8fc5c..0b293850eb7 100644 --- a/lib/SILOptimizer/Transforms/MergeCondFail.cpp +++ b/lib/SILOptimizer/Transforms/MergeCondFail.cpp @@ -12,12 +12,12 @@ #define DEBUG_TYPE "merge-cond_fail" +#include "swift/SIL/SILBuilder.h" +#include "swift/SIL/SILInstruction.h" #include "swift/SILOptimizer/Analysis/Analysis.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" -#include "swift/SIL/SILBuilder.h" -#include "swift/SIL/SILInstruction.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/Support/Debug.h" diff --git a/lib/SILOptimizer/Transforms/ObjectOutliner.cpp b/lib/SILOptimizer/Transforms/ObjectOutliner.cpp index 71c67baedc9..688ca6c30db 100644 --- a/lib/SILOptimizer/Transforms/ObjectOutliner.cpp +++ b/lib/SILOptimizer/Transforms/ObjectOutliner.cpp @@ -14,9 +14,9 @@ #include "swift/AST/ASTMangler.h" #include "swift/SIL/DebugUtils.h" #include "swift/SIL/SILBuilder.h" -#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h" +#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "llvm/Support/Debug.h" using namespace swift; diff --git a/lib/SILOptimizer/Transforms/OwnershipModelEliminator.cpp b/lib/SILOptimizer/Transforms/OwnershipModelEliminator.cpp index 5ba171e539e..dce868a8902 100644 --- a/lib/SILOptimizer/Transforms/OwnershipModelEliminator.cpp +++ b/lib/SILOptimizer/Transforms/OwnershipModelEliminator.cpp @@ -29,7 +29,7 @@ #include "swift/SIL/SILVisitor.h" #include "swift/SILOptimizer/Analysis/SimplifyInstruction.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/Support/CommandLine.h" using namespace swift; @@ -383,7 +383,25 @@ struct OwnershipModelEliminator : SILModuleTransform { continue; // Verify here to make sure ownership is correct before we strip. - F.verify(); + { + // Add a pretty stack trace entry to tell users who see a verification + // failure triggered by this verification check that they need to re-run + // with -sil-verify-all to actually find the pass that introduced the + // verification error. + // + // DISCUSSION: This occurs due to the crash from the verification + // failure happening in the pass itself. This causes us to dump the + // SILFunction and emit a msg that this pass (OME) is the culprit. This + // is generally correct for most passes, but not for OME since we are + // verifying before we have even modified the function to ensure that + // all ownership invariants have been respected before we lower + // ownership from the function. + llvm::PrettyStackTraceString silVerifyAllMsgOnFailure( + "Found verification error when verifying before lowering " + "ownership. Please re-run with -sil-verify-all to identify the " + "actual pass that introduced the verification error."); + F.verify(); + } if (stripOwnership(F)) { auto InvalidKind = diff --git a/lib/SILOptimizer/Transforms/PerformanceInliner.cpp b/lib/SILOptimizer/Transforms/PerformanceInliner.cpp index a8f04bb04c9..961c6b57419 100644 --- a/lib/SILOptimizer/Transforms/PerformanceInliner.cpp +++ b/lib/SILOptimizer/Transforms/PerformanceInliner.cpp @@ -17,7 +17,7 @@ #include "swift/SILOptimizer/Analysis/SideEffectAnalysis.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" #include "swift/SILOptimizer/Utils/Devirtualize.h" #include "swift/SILOptimizer/Utils/Generics.h" #include "swift/SILOptimizer/Utils/PerformanceInlinerUtils.h" diff --git a/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp b/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp index 6bfe200e5c5..51af6042e5a 100644 --- a/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp +++ b/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp @@ -76,15 +76,15 @@ #include "swift/SIL/Projection.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILBuilder.h" -#include "swift/SILOptimizer/Analysis/AliasAnalysis.h" #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" +#include "swift/SILOptimizer/Analysis/AliasAnalysis.h" #include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" #include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h" #include "swift/SILOptimizer/Analysis/ValueTracking.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/LoadStoreOptUtils.h" #include "swift/SILOptimizer/Utils/SILSSAUpdater.h" #include "llvm/ADT/BitVector.h" diff --git a/lib/SILOptimizer/Transforms/RedundantOverflowCheckRemoval.cpp b/lib/SILOptimizer/Transforms/RedundantOverflowCheckRemoval.cpp index 483ec3eab3d..63615c2c5cc 100644 --- a/lib/SILOptimizer/Transforms/RedundantOverflowCheckRemoval.cpp +++ b/lib/SILOptimizer/Transforms/RedundantOverflowCheckRemoval.cpp @@ -16,13 +16,13 @@ #define DEBUG_TYPE "remove-redundant-overflow-checks" #include "swift/SIL/Dominance.h" +#include "swift/SIL/SILInstruction.h" +#include "swift/SILOptimizer/Analysis/Analysis.h" #include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" #include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h" -#include "swift/SILOptimizer/Analysis/Analysis.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" -#include "swift/SIL/SILInstruction.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/Debug.h" diff --git a/lib/SILOptimizer/Transforms/SILCodeMotion.cpp b/lib/SILOptimizer/Transforms/SILCodeMotion.cpp index cbb85bf7e16..a732dc12d8b 100644 --- a/lib/SILOptimizer/Transforms/SILCodeMotion.cpp +++ b/lib/SILOptimizer/Transforms/SILCodeMotion.cpp @@ -11,21 +11,21 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "sil-codemotion" -#include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/AST/Module.h" #include "swift/Basic/BlotMapVector.h" +#include "swift/SIL/DebugUtils.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILModule.h" #include "swift/SIL/SILType.h" #include "swift/SIL/SILValue.h" #include "swift/SIL/SILVisitor.h" -#include "swift/SIL/DebugUtils.h" #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" #include "swift/SILOptimizer/Analysis/AliasAnalysis.h" #include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h" #include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h" +#include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Statistic.h" diff --git a/lib/SILOptimizer/Transforms/SILLowerAggregateInstrs.cpp b/lib/SILOptimizer/Transforms/SILLowerAggregateInstrs.cpp index ad6f1f757d0..bb03fe51795 100644 --- a/lib/SILOptimizer/Transforms/SILLowerAggregateInstrs.cpp +++ b/lib/SILOptimizer/Transforms/SILLowerAggregateInstrs.cpp @@ -23,7 +23,7 @@ #include "swift/SIL/TypeLowering.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/Debug.h" using namespace swift; diff --git a/lib/SILOptimizer/Transforms/SILMem2Reg.cpp b/lib/SILOptimizer/Transforms/SILMem2Reg.cpp index 7386f16c3b9..51a4493a7da 100644 --- a/lib/SILOptimizer/Transforms/SILMem2Reg.cpp +++ b/lib/SILOptimizer/Transforms/SILMem2Reg.cpp @@ -20,23 +20,23 @@ #define DEBUG_TYPE "sil-mem2reg" -#include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/AST/DiagnosticsSIL.h" #include "swift/SIL/Dominance.h" +#include "swift/SIL/Projection.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILModule.h" -#include "swift/SIL/Projection.h" #include "swift/SIL/TypeLowering.h" -#include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" -#include "swift/SILOptimizer/Utils/Local.h" #include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" -#include "llvm/ADT/DenseSet.h" +#include "swift/SILOptimizer/PassManager/Passes.h" +#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/Statistic.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Statistic.h" #include "llvm/Support/Debug.h" #include #include diff --git a/lib/SILOptimizer/Transforms/SILSROA.cpp b/lib/SILOptimizer/Transforms/SILSROA.cpp index 50fa0d4f5a7..a15fe415ebf 100644 --- a/lib/SILOptimizer/Transforms/SILSROA.cpp +++ b/lib/SILOptimizer/Transforms/SILSROA.cpp @@ -26,7 +26,7 @@ #include "swift/SIL/SILUndef.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Debug.h" diff --git a/lib/SILOptimizer/Transforms/SimplifyCFG.cpp b/lib/SILOptimizer/Transforms/SimplifyCFG.cpp index 64e5545b264..bb4c3fb97d8 100644 --- a/lib/SILOptimizer/Transforms/SimplifyCFG.cpp +++ b/lib/SILOptimizer/Transforms/SimplifyCFG.cpp @@ -24,12 +24,13 @@ #include "swift/SILOptimizer/Analysis/SimplifyInstruction.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" +#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" #include "swift/SILOptimizer/Utils/CastOptimizer.h" -#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" -#include "swift/SILOptimizer/Utils/Local.h" #include "swift/SILOptimizer/Utils/ConstantFolding.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/SILInliner.h" +#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "swift/SILOptimizer/Utils/SILSSAUpdater.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" @@ -201,125 +202,6 @@ namespace { } // end anonymous namespace -/// Return true if there are any users of V outside the specified block. -static bool isUsedOutsideOfBlock(SILValue V, SILBasicBlock *BB) { - for (auto UI : V->getUses()) - if (UI->getUser()->getParent() != BB) - return true; - return false; -} - -// Populate 'projections' with the chain of address projections leading -// to and including 'inst'. -// -// Populate 'inBlockDefs' with all the non-address value definitions in -// the block that will be used outside this block after projection sinking. -// -// Return true on success, even if projections is empty. -bool SinkAddressProjections::analyzeAddressProjections(SILInstruction *inst) { - projections.clear(); - inBlockDefs.clear(); - - SILBasicBlock *bb = inst->getParent(); - auto pushOperandVal = [&](SILValue def) { - if (def->getParentBlock() != bb) - return true; - - if (!def->getType().isAddress()) { - inBlockDefs.insert(def); - return true; - } - if (auto *addressProj = dyn_cast(def)) { - if (addressProj->isTriviallyDuplicatable()) { - projections.push_back(addressProj); - return true; - } - } - // Can't handle a multi-value or unclonable address producer. - return false; - }; - // Check the given instruction for any address-type results. - for (auto result : inst->getResults()) { - if (!isUsedOutsideOfBlock(result, bb)) - continue; - if (!pushOperandVal(result)) - return false; - } - // Recurse upward through address projections. - for (unsigned idx = 0; idx < projections.size(); ++idx) { - // Only one address result/operand can be handled per instruction. - if (projections.size() != idx + 1) - return false; - - for (SILValue operandVal : projections[idx]->getOperandValues()) - pushOperandVal(operandVal); - } - return true; -} - -// Clone the projections gathered by 'analyzeAddressProjections' at -// their use site outside this block. -bool SinkAddressProjections::cloneProjections() { - if (projections.empty()) - return false; - - SILBasicBlock *bb = projections.front()->getParent(); - SmallVector usesToReplace; - // Clone projections in last-to-first order. - for (unsigned idx = 0; idx < projections.size(); ++idx) { - auto *oldProj = projections[idx]; - assert(oldProj->getParent() == bb); - usesToReplace.clear(); - for (Operand *use : oldProj->getUses()) { - if (use->getUser()->getParent() != bb) - usesToReplace.push_back(use); - } - for (Operand *use : usesToReplace) { - auto *newProj = oldProj->clone(use->getUser()); - use->set(cast(newProj)); - } - } - return true; -} - -/// Helper function to perform SSA updates in case of jump threading. -void swift::updateSSAAfterCloning(BasicBlockCloner &Cloner, - SILBasicBlock *SrcBB, SILBasicBlock *DestBB) { - SILSSAUpdater SSAUp; - for (auto AvailValPair : Cloner.AvailVals) { - ValueBase *Inst = AvailValPair.first; - if (Inst->use_empty()) - continue; - - SILValue NewRes(AvailValPair.second); - - SmallVector UseList; - // Collect the uses of the value. - for (auto Use : Inst->getUses()) - UseList.push_back(UseWrapper(Use)); - - SSAUp.Initialize(Inst->getType()); - SSAUp.AddAvailableValue(DestBB, Inst); - SSAUp.AddAvailableValue(SrcBB, NewRes); - - if (UseList.empty()) - continue; - - // Update all the uses. - for (auto U : UseList) { - Operand *Use = U; - SILInstruction *User = Use->getUser(); - assert(User && "Missing user"); - - // Ignore uses in the same basic block. - if (User->getParent() == DestBB) - continue; - - SSAUp.RewriteUse(*Use); - } - } -} - static SILValue getTerminatorCondition(TermInst *Term) { if (auto *CondBr = dyn_cast(Term)) return stripExpectIntrinsic(CondBr->getCondition()); @@ -1044,7 +926,7 @@ bool SimplifyCFG::tryJumpThreading(BranchInst *BI) { // Are the arguments to this block used outside of the block. for (auto Arg : DestBB->getArguments()) - if ((NeedToUpdateSSA |= isUsedOutsideOfBlock(Arg, DestBB))) { + if ((NeedToUpdateSSA |= isUsedOutsideOfBlock(Arg))) { break; } @@ -1293,9 +1175,17 @@ static bool isReachable(SILBasicBlock *Block) { } #endif +static llvm::cl::opt SimplifyUnconditionalBranches( + "simplify-cfg-simplify-unconditional-branches", llvm::cl::init(true)); + /// simplifyBranchBlock - Simplify a basic block that ends with an unconditional /// branch. bool SimplifyCFG::simplifyBranchBlock(BranchInst *BI) { + // If we are asked to not simplify unconditional branches (for testing + // purposes), exit early. + if (!SimplifyUnconditionalBranches) + return false; + // First simplify instructions generating branch operands since that // can expose CFG simplifications. bool Simplified = simplifyBranchOperands(BI->getArgs()); @@ -1956,43 +1846,88 @@ static bool onlyForwardsNone(SILBasicBlock *noneBB, SILBasicBlock *someBB, return true; } -/// Check whether \p noneBB has the same ultimate successor as the successor to someBB. -/// someBB noneBB -/// \ | -/// \ ... (more bbs?) +/// Check whether the \p someBB has only one single successor and that successor +/// post-dominates \p noneBB. +/// +/// (maybe otherNoneBB) +/// someBB noneBB / +/// \ | v +/// \ ... more bbs? (A) /// \ / /// ulimateBB +/// +/// This routine does not support diverging control flow in (A). This means that +/// there must not be any loops or diamonds beginning in that region. We do +/// support side-entrances from blocks not reachable from noneBB in order to +/// ensure that we properly handle other failure cases where the failure case +/// merges into .noneBB before ultimate BB. +/// +/// DISCUSSION: We allow this side-entrance pattern to handle iterative +/// conditional checks which all feed the failing case through the .none +/// path. This is a common pattern in swift code. As an example consider a +/// switch statement with multiple pattern binding matching that use the same +/// cleanup code upon failure. static bool hasSameUltimateSuccessor(SILBasicBlock *noneBB, SILBasicBlock *someBB) { // Make sure that both our some, none blocks both have single successors that // are not themselves (which can happen due to single block loops). auto *someSuccessorBB = someBB->getSingleSuccessorBlock(); if (!someSuccessorBB || someSuccessorBB == someBB) return false; + auto *noneSuccessorBB = noneBB->getSingleSuccessorBlock(); if (!noneSuccessorBB || noneSuccessorBB == noneBB) return false; - // If we immediately find a diamond, return true. We are done. + // If we immediately find a simple diamond, return true. We are done. if (noneSuccessorBB == someSuccessorBB) return true; - // Otherwise, lets keep looking down the none case. - auto *next = noneSuccessorBB; - while (next != someSuccessorBB) { - noneSuccessorBB = next; - next = noneSuccessorBB->getSingleSuccessorBlock(); + // Otherwise, lets begin a traversal along the successors of noneSuccessorBB, + // searching for someSuccessorBB, being careful to only allow for blocks to be + // visited once. This enables us to guarantee that there are not any loops or + // any sub-diamonds in the part of the CFG we are traversing. This /does/ + // allow for side-entrances to the region from blocks not reachable from + // noneSuccessorBB. See function level comment above. + SILBasicBlock *iter = noneSuccessorBB; + SmallPtrSet visitedBlocks; + visitedBlocks.insert(iter); - // If we find another single successor and it is not our own block (due to a - // self-loop), continue. - if (next && next != noneSuccessorBB) - continue; + do { + // First try to grab our single successor if we have only one. If we have no + // successor or more than one successor, bail and do not optimize. + // + // DISCUSSION: Trivially, if we do not have a successor, then we have + // reached either a return/unreachable and this path will never merge with + // the ultimate block. If we have more than one successor, then for our + // condition to pass, we must have that both successors eventually join into + // someSuccessorBB. But this would imply that either someSuccessorBB has + // more than two predecessors and or that we merge the two paths before we + // visit someSuccessorBB. + auto *succBlock = iter->getSingleSuccessorBlock(); + if (!succBlock) + return false; - // Otherwise, we either have multiple successors or a self-loop. We do not - // support this, return false. - return false; - } + // Then check if our single successor block has been visited already. If so, + // we have some sort of loop or have some sort of merge point that is not + // the final merge point. + // + // NOTE: We do not need to worry about someSuccessorBB being in + // visitedBlocks since before we begin the loop, we check that + // someSuccessorBB != iter and also check that in the do-while condition. So + // we can never have visited someSuccessorBB on any previous iteration + // meaning that the only time we can have succBlock equal to someSuccessorBB + // is on the last iteration before we exit the loop. + if (!visitedBlocks.insert(succBlock).second) + return false; + + // Otherwise, set iter to succBlock. + iter = succBlock; + + // And then check if this new successor block is someSuccessorBB. If so, we + // break and then return true since we have found our target. Otherwise, we + // need to visit further successors, so go back around the loop. + } while (iter != someSuccessorBB); - // At this point, we know that next must be someSuccessorBB. return true; } diff --git a/lib/SILOptimizer/Transforms/Sink.cpp b/lib/SILOptimizer/Transforms/Sink.cpp index a1077f0cf0c..b9b7342c9f7 100644 --- a/lib/SILOptimizer/Transforms/Sink.cpp +++ b/lib/SILOptimizer/Transforms/Sink.cpp @@ -19,18 +19,18 @@ #define DEBUG_TYPE "sink-instructions" -#include "swift/SIL/Dominance.h" -#include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" -#include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h" -#include "swift/SILOptimizer/Analysis/LoopAnalysis.h" -#include "swift/SILOptimizer/PassManager/Passes.h" -#include "swift/SIL/SILArgument.h" -#include "swift/SIL/SILValue.h" -#include "swift/SIL/SILDebugScope.h" #include "swift/SIL/DebugUtils.h" -#include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SIL/Dominance.h" +#include "swift/SIL/SILArgument.h" +#include "swift/SIL/SILDebugScope.h" #include "swift/SIL/SILInstruction.h" +#include "swift/SIL/SILValue.h" +#include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" +#include "swift/SILOptimizer/Analysis/LoopAnalysis.h" +#include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h" +#include "swift/SILOptimizer/PassManager/Passes.h" +#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/Debug.h" diff --git a/lib/SILOptimizer/Transforms/SpecializeOpaqueArchetypes.cpp b/lib/SILOptimizer/Transforms/SpecializeOpaqueArchetypes.cpp index 25d43696336..b8968e0414e 100644 --- a/lib/SILOptimizer/Transforms/SpecializeOpaqueArchetypes.cpp +++ b/lib/SILOptimizer/Transforms/SpecializeOpaqueArchetypes.cpp @@ -18,10 +18,10 @@ #include "swift/AST/Types.h" #include "swift/SIL/SILFunction.h" -#include "swift/SIL/TypeSubstCloner.h" #include "swift/SIL/SILInstruction.h" +#include "swift/SIL/TypeSubstCloner.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/CFG.h" +#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h" #include "llvm/Support/CommandLine.h" diff --git a/lib/SILOptimizer/Transforms/StackPromotion.cpp b/lib/SILOptimizer/Transforms/StackPromotion.cpp index 1d3775668a4..b0243dc3198 100644 --- a/lib/SILOptimizer/Transforms/StackPromotion.cpp +++ b/lib/SILOptimizer/Transforms/StackPromotion.cpp @@ -10,15 +10,16 @@ // //===----------------------------------------------------------------------===// -#include "swift/SILOptimizer/PassManager/Passes.h" -#include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Analysis/EscapeAnalysis.h" -#include "swift/SILOptimizer/Utils/Local.h" -#include "swift/SILOptimizer/Utils/StackNesting.h" -#include "swift/SIL/SILArgument.h" -#include "swift/SIL/SILBuilder.h" #include "swift/SIL/BasicBlockUtils.h" #include "swift/SIL/CFG.h" +#include "swift/SIL/SILArgument.h" +#include "swift/SIL/SILBuilder.h" +#include "swift/SILOptimizer/Analysis/EscapeAnalysis.h" +#include "swift/SILOptimizer/PassManager/Passes.h" +#include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "swift/SILOptimizer/Utils/StackNesting.h" +#include "swift/SILOptimizer/Utils/ValueLifetime.h" #include "llvm/ADT/Statistic.h" #define DEBUG_TYPE "stack-promotion" diff --git a/lib/SILOptimizer/Transforms/UnsafeGuaranteedPeephole.cpp b/lib/SILOptimizer/Transforms/UnsafeGuaranteedPeephole.cpp index 9aa693dc8f6..aa2de64bc4c 100644 --- a/lib/SILOptimizer/Transforms/UnsafeGuaranteedPeephole.cpp +++ b/lib/SILOptimizer/Transforms/UnsafeGuaranteedPeephole.cpp @@ -31,7 +31,6 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "unsafe-guaranteed-peephole" -#include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SIL/DebugUtils.h" #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILInstruction.h" @@ -39,8 +38,9 @@ #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" #include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" #include "swift/SILOptimizer/Analysis/RCIdentityAnalysis.h" +#include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" using namespace swift; diff --git a/lib/SILOptimizer/Utils/BasicBlockOptUtils.cpp b/lib/SILOptimizer/Utils/BasicBlockOptUtils.cpp new file mode 100644 index 00000000000..88f11083c49 --- /dev/null +++ b/lib/SILOptimizer/Utils/BasicBlockOptUtils.cpp @@ -0,0 +1,244 @@ +//===--- BasicBlockOptUtils.cpp - SILOptimizer basic block utilities ------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "swift/SILOptimizer/Utils/SILSSAUpdater.h" + +using namespace swift; + +/// Remove all instructions in the body of \p bb in safe manner by using +/// undef. +void swift::clearBlockBody(SILBasicBlock *bb) { + // Instructions in the dead block may be used by other dead blocks. Replace + // any uses of them with undef values. + while (!bb->empty()) { + // Grab the last instruction in the bb. + auto *inst = &bb->back(); + + // Replace any still-remaining uses with undef values and erase. + inst->replaceAllUsesOfAllResultsWithUndef(); + inst->eraseFromParent(); + } +} + +// Handle the mechanical aspects of removing an unreachable block. +void swift::removeDeadBlock(SILBasicBlock *bb) { + // Clear the body of bb. + clearBlockBody(bb); + + // Now that the bb is empty, eliminate it. + bb->eraseFromParent(); +} + +bool swift::removeUnreachableBlocks(SILFunction &f) { + // All reachable blocks, but does not include the entry block. + llvm::SmallPtrSet visited; + + // Walk over the CFG, starting at the entry block, until all reachable blocks are visited. + llvm::SmallVector worklist(1, f.getEntryBlock()); + while (!worklist.empty()) { + SILBasicBlock *bb = worklist.pop_back_val(); + for (auto &Succ : bb->getSuccessors()) { + if (visited.insert(Succ).second) + worklist.push_back(Succ); + } + } + + // Remove the blocks we never reached. Exclude the entry block from the iteration because it's + // not included in the Visited set. + bool changed = false; + for (auto ii = std::next(f.begin()), end = f.end(); ii != end;) { + auto *bb = &*ii++; + if (!visited.count(bb)) { + removeDeadBlock(bb); + changed = true; + } + } + return changed; +} + +/// Helper function to perform SSA updates in case of jump threading. +void swift::updateSSAAfterCloning(BasicBlockCloner &cloner, + SILBasicBlock *srcBB, SILBasicBlock *destBB) { + SILSSAUpdater ssaUpdater; + for (auto availValPair : cloner.AvailVals) { + ValueBase *inst = availValPair.first; + if (inst->use_empty()) + continue; + + SILValue newResult(availValPair.second); + + SmallVector useList; + // Collect the uses of the value. + for (auto *use : inst->getUses()) + useList.push_back(UseWrapper(use)); + + ssaUpdater.Initialize(inst->getType()); + ssaUpdater.AddAvailableValue(destBB, inst); + ssaUpdater.AddAvailableValue(srcBB, newResult); + + if (useList.empty()) + continue; + + // Update all the uses. + for (auto useWrapper : useList) { + Operand *use = useWrapper; + SILInstruction *user = use->getUser(); + assert(user && "Missing user"); + + // Ignore uses in the same basic block. + if (user->getParent() == destBB) + continue; + + ssaUpdater.RewriteUse(*use); + } + } +} + +// FIXME: Remove this. SILCloner should not create critical edges. +bool BasicBlockCloner::splitCriticalEdges(DominanceInfo *domInfo, + SILLoopInfo *loopInfo) { + bool changed = false; + // Remove any critical edges that the EdgeThreadingCloner may have + // accidentally created. + for (unsigned succIdx = 0, succEnd = origBB->getSuccessors().size(); + succIdx != succEnd; ++succIdx) { + if (nullptr + != splitCriticalEdge(origBB->getTerminator(), succIdx, domInfo, + loopInfo)) + changed |= true; + } + for (unsigned succIdx = 0, succEnd = getNewBB()->getSuccessors().size(); + succIdx != succEnd; ++succIdx) { + auto *newBB = splitCriticalEdge(getNewBB()->getTerminator(), succIdx, + domInfo, loopInfo); + changed |= (newBB != nullptr); + } + return changed; +} + +// Populate 'projections' with the chain of address projections leading +// to and including 'inst'. +// +// Populate 'inBlockDefs' with all the non-address value definitions in +// the block that will be used outside this block after projection sinking. +// +// Return true on success, even if projections is empty. +bool SinkAddressProjections::analyzeAddressProjections(SILInstruction *inst) { + projections.clear(); + inBlockDefs.clear(); + + SILBasicBlock *bb = inst->getParent(); + auto pushOperandVal = [&](SILValue def) { + if (def->getParentBlock() != bb) + return true; + + if (!def->getType().isAddress()) { + inBlockDefs.insert(def); + return true; + } + if (auto *addressProj = dyn_cast(def)) { + if (addressProj->isTriviallyDuplicatable()) { + projections.push_back(addressProj); + return true; + } + } + // Can't handle a multi-value or unclonable address producer. + return false; + }; + // Check the given instruction for any address-type results. + for (auto result : inst->getResults()) { + if (!isUsedOutsideOfBlock(result)) + continue; + if (!pushOperandVal(result)) + return false; + } + // Recurse upward through address projections. + for (unsigned idx = 0; idx < projections.size(); ++idx) { + // Only one address result/operand can be handled per instruction. + if (projections.size() != idx + 1) + return false; + + for (SILValue operandVal : projections[idx]->getOperandValues()) + pushOperandVal(operandVal); + } + return true; +} + +// Clone the projections gathered by 'analyzeAddressProjections' at +// their use site outside this block. +bool SinkAddressProjections::cloneProjections() { + if (projections.empty()) + return false; + + SILBasicBlock *bb = projections.front()->getParent(); + SmallVector usesToReplace; + // Clone projections in last-to-first order. + for (unsigned idx = 0; idx < projections.size(); ++idx) { + auto *oldProj = projections[idx]; + assert(oldProj->getParent() == bb); + usesToReplace.clear(); + for (Operand *use : oldProj->getUses()) { + if (use->getUser()->getParent() != bb) + usesToReplace.push_back(use); + } + for (Operand *use : usesToReplace) { + auto *newProj = oldProj->clone(use->getUser()); + use->set(cast(newProj)); + } + } + return true; +} + +void StaticInitCloner::add(SILInstruction *initVal) { + // Don't schedule an instruction twice for cloning. + if (numOpsToClone.count(initVal) != 0) + return; + + ArrayRef operands = initVal->getAllOperands(); + numOpsToClone[initVal] = operands.size(); + if (operands.empty()) { + // It's an instruction without operands, e.g. a literal. It's ready to be + // cloned first. + readyToClone.push_back(initVal); + } else { + // Recursively add all operands. + for (const Operand &operand : operands) { + add(cast(operand.get())); + } + } +} + +SingleValueInstruction * +StaticInitCloner::clone(SingleValueInstruction *initVal) { + assert(numOpsToClone.count(initVal) != 0 && "initVal was not added"); + // Find the right order to clone: all operands of an instruction must be + // cloned before the instruction itself. + while (!readyToClone.empty()) { + SILInstruction *inst = readyToClone.pop_back_val(); + + // Clone the instruction into the SILGlobalVariable + visit(inst); + + // Check if users of I can now be cloned. + for (SILValue result : inst->getResults()) { + for (Operand *use : result->getUses()) { + SILInstruction *user = use->getUser(); + if (numOpsToClone.count(user) != 0 && --numOpsToClone[user] == 0) + readyToClone.push_back(user); + } + } + } + return cast(getMappedValue(initVal)); +} diff --git a/lib/SILOptimizer/Utils/CFG.cpp b/lib/SILOptimizer/Utils/CFG.cpp deleted file mode 100644 index e92b57bb9ed..00000000000 --- a/lib/SILOptimizer/Utils/CFG.cpp +++ /dev/null @@ -1,743 +0,0 @@ -//===--- CFG.cpp - Utilities for SIL CFG transformations ------------------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// - -#include "swift/SIL/BasicBlockUtils.h" -#include "swift/SIL/Dominance.h" -#include "swift/SIL/LoopInfo.h" -#include "swift/SIL/BasicBlockUtils.h" -#include "swift/SIL/SILArgument.h" -#include "swift/SIL/SILBuilder.h" -#include "swift/SILOptimizer/Utils/CFG.h" -#include "swift/SILOptimizer/Utils/Local.h" - -using namespace swift; - -/// Adds a new argument to an edge between a branch and a destination -/// block. -/// -/// \param Branch The terminator to add the argument to. -/// \param Dest The destination block of the edge. -/// \param Val The value to the arguments of the branch. -/// \return The created branch. The old branch is deleted. -/// The argument is appended at the end of the argument tuple. -TermInst *swift::addNewEdgeValueToBranch(TermInst *Branch, SILBasicBlock *Dest, - SILValue Val) { - SILBuilderWithScope Builder(Branch); - TermInst *NewBr = nullptr; - - if (auto *CBI = dyn_cast(Branch)) { - SmallVector TrueArgs; - SmallVector FalseArgs; - - for (auto A : CBI->getTrueArgs()) - TrueArgs.push_back(A); - - for (auto A : CBI->getFalseArgs()) - FalseArgs.push_back(A); - - if (Dest == CBI->getTrueBB()) { - TrueArgs.push_back(Val); - assert(TrueArgs.size() == Dest->getNumArguments()); - } - if (Dest == CBI->getFalseBB()) { - FalseArgs.push_back(Val); - assert(FalseArgs.size() == Dest->getNumArguments()); - } - - NewBr = Builder.createCondBranch( - CBI->getLoc(), CBI->getCondition(), CBI->getTrueBB(), TrueArgs, - CBI->getFalseBB(), FalseArgs, CBI->getTrueBBCount(), - CBI->getFalseBBCount()); - } else if (auto *BI = dyn_cast(Branch)) { - SmallVector Args; - - for (auto A : BI->getArgs()) - Args.push_back(A); - - Args.push_back(Val); - assert(Args.size() == Dest->getNumArguments()); - NewBr = Builder.createBranch(BI->getLoc(), BI->getDestBB(), Args); - } else { - // At the moment we can only add arguments to br and cond_br. - llvm_unreachable("Can't add argument to terminator"); - } - - Branch->dropAllReferences(); - Branch->eraseFromParent(); - - return NewBr; -} - -static void -deleteTriviallyDeadOperandsOfDeadArgument(MutableArrayRef termOperands, - unsigned deadArgIndex) { - Operand &op = termOperands[deadArgIndex]; - auto *i = op.get()->getDefiningInstruction(); - if (!i) - return; - op.set(SILUndef::get(op.get()->getType(), *i->getFunction())); - recursivelyDeleteTriviallyDeadInstructions(i); -} - -// Our implementation assumes that our caller is attempting to remove a dead -// SILPhiArgument from a SILBasicBlock and has already RAUWed the argument. -TermInst *swift::deleteEdgeValue(TermInst *branch, SILBasicBlock *destBlock, - size_t argIndex) { - if (auto *cbi = dyn_cast(branch)) { - SmallVector trueArgs; - SmallVector falseArgs; - - llvm::copy(cbi->getTrueArgs(), std::back_inserter(trueArgs)); - llvm::copy(cbi->getFalseArgs(), std::back_inserter(falseArgs)); - - if (destBlock == cbi->getTrueBB()) { - deleteTriviallyDeadOperandsOfDeadArgument(cbi->getTrueOperands(), argIndex); - trueArgs.erase(trueArgs.begin() + argIndex); - } - - if (destBlock == cbi->getFalseBB()) { - deleteTriviallyDeadOperandsOfDeadArgument(cbi->getFalseOperands(), argIndex); - falseArgs.erase(falseArgs.begin() + argIndex); - } - - SILBuilderWithScope builder(cbi); - auto *result = builder.createCondBranch(cbi->getLoc(), cbi->getCondition(), - cbi->getTrueBB(), trueArgs, cbi->getFalseBB(), - falseArgs, cbi->getTrueBBCount(), - cbi->getFalseBBCount()); - branch->eraseFromParent(); - return result; - } - - if (auto *bi = dyn_cast(branch)) { - SmallVector args; - llvm::copy(bi->getArgs(), std::back_inserter(args)); - - deleteTriviallyDeadOperandsOfDeadArgument(bi->getAllOperands(), argIndex); - args.erase(args.begin() + argIndex); - auto *result = SILBuilderWithScope(bi).createBranch(bi->getLoc(), bi->getDestBB(), args); - branch->eraseFromParent(); - return result; - } - - llvm_unreachable("unsupported terminator"); -} - -void swift::erasePhiArgument(SILBasicBlock *block, unsigned argIndex) { - assert(block->getArgument(argIndex)->isPhiArgument() && - "Only should be used on phi arguments"); - block->eraseArgument(argIndex); - - // Determine the set of predecessors in case any predecessor has - // two edges to this block (e.g. a conditional branch where both - // sides reach this block). - // - // NOTE: This needs to be a SmallSetVector since we need both uniqueness /and/ - // insertion order. Otherwise non-determinism can result. - SmallSetVector predBlocks; - - for (auto *pred : block->getPredecessorBlocks()) - predBlocks.insert(pred); - - for (auto *pred : predBlocks) - deleteEdgeValue(pred->getTerminator(), block, argIndex); -} - -/// Changes the edge value between a branch and destination basic block -/// at the specified index. Changes all edges from \p Branch to \p Dest to carry -/// the value. -/// -/// \param Branch The branch to modify. -/// \param Dest The destination of the edge. -/// \param Idx The index of the argument to modify. -/// \param Val The new value to use. -/// \return The new branch. Deletes the old one. -/// Changes the edge value between a branch and destination basic block at the -/// specified index. -TermInst *swift::changeEdgeValue(TermInst *Branch, SILBasicBlock *Dest, - size_t Idx, SILValue Val) { - SILBuilderWithScope Builder(Branch); - - if (auto *CBI = dyn_cast(Branch)) { - SmallVector TrueArgs; - SmallVector FalseArgs; - - OperandValueArrayRef OldTrueArgs = CBI->getTrueArgs(); - bool BranchOnTrue = CBI->getTrueBB() == Dest; - assert((!BranchOnTrue || Idx < OldTrueArgs.size()) && "Not enough edges"); - - // Copy the edge values overwriting the edge at Idx. - for (unsigned i = 0, e = OldTrueArgs.size(); i != e; ++i) { - if (BranchOnTrue && Idx == i) - TrueArgs.push_back(Val); - else - TrueArgs.push_back(OldTrueArgs[i]); - } - assert(TrueArgs.size() == CBI->getTrueBB()->getNumArguments() && - "Destination block's number of arguments must match"); - - OperandValueArrayRef OldFalseArgs = CBI->getFalseArgs(); - bool BranchOnFalse = CBI->getFalseBB() == Dest; - assert((!BranchOnFalse || Idx < OldFalseArgs.size()) && "Not enough edges"); - - // Copy the edge values overwriting the edge at Idx. - for (unsigned i = 0, e = OldFalseArgs.size(); i != e; ++i) { - if (BranchOnFalse && Idx == i) - FalseArgs.push_back(Val); - else - FalseArgs.push_back(OldFalseArgs[i]); - } - assert(FalseArgs.size() == CBI->getFalseBB()->getNumArguments() && - "Destination block's number of arguments must match"); - - CBI = Builder.createCondBranch( - CBI->getLoc(), CBI->getCondition(), CBI->getTrueBB(), TrueArgs, - CBI->getFalseBB(), FalseArgs, CBI->getTrueBBCount(), - CBI->getFalseBBCount()); - Branch->dropAllReferences(); - Branch->eraseFromParent(); - return CBI; - } - - if (auto *BI = dyn_cast(Branch)) { - SmallVector Args; - - assert(Idx < BI->getNumArgs() && "Not enough edges"); - OperandValueArrayRef OldArgs = BI->getArgs(); - - // Copy the edge values overwriting the edge at Idx. - for (unsigned i = 0, e = OldArgs.size(); i != e; ++i) { - if (Idx == i) - Args.push_back(Val); - else - Args.push_back(OldArgs[i]); - } - assert(Args.size() == Dest->getNumArguments()); - - BI = Builder.createBranch(BI->getLoc(), BI->getDestBB(), Args); - Branch->dropAllReferences(); - Branch->eraseFromParent(); - return BI; - } - - llvm_unreachable("Unhandled terminator leading to merge block"); -} - -template -SILBasicBlock *replaceSwitchDest(SwitchEnumTy *S, - SmallVectorImpl &Cases, - unsigned EdgeIdx, SILBasicBlock *NewDest) { - auto *DefaultBB = S->hasDefault() ? S->getDefaultBB() : nullptr; - for (unsigned i = 0, e = S->getNumCases(); i != e; ++i) - if (EdgeIdx != i) - Cases.push_back(S->getCase(i)); - else - Cases.push_back(std::make_pair(S->getCase(i).first, NewDest)); - if (EdgeIdx == S->getNumCases()) - DefaultBB = NewDest; - return DefaultBB; -} - -template -SILBasicBlock *replaceSwitchDest(SwitchEnumTy *S, - SmallVectorImpl &Cases, - SILBasicBlock *OldDest, SILBasicBlock *NewDest) { - auto *DefaultBB = S->hasDefault() ? S->getDefaultBB() : nullptr; - for (unsigned i = 0, e = S->getNumCases(); i != e; ++i) - if (S->getCase(i).second != OldDest) - Cases.push_back(S->getCase(i)); - else - Cases.push_back(std::make_pair(S->getCase(i).first, NewDest)); - if (OldDest == DefaultBB) - DefaultBB = NewDest; - return DefaultBB; -} - -/// Replace a branch target. -/// -/// \param T The terminating instruction to modify. -/// \param OldDest The successor block that will be replaced. -/// \param NewDest The new target block. -/// \param PreserveArgs If set, preserve arguments on the replaced edge. -void swift::replaceBranchTarget(TermInst *T, SILBasicBlock *OldDest, - SILBasicBlock *NewDest, bool PreserveArgs) { - SILBuilderWithScope B(T); - - switch (T->getTermKind()) { - // Only Branch and CondBranch may have arguments. - case TermKind::BranchInst: { - auto Br = cast(T); - assert(OldDest == Br->getDestBB() && "wrong branch target"); - SmallVector Args; - if (PreserveArgs) { - for (auto Arg : Br->getArgs()) - Args.push_back(Arg); - } - B.createBranch(T->getLoc(), NewDest, Args); - Br->dropAllReferences(); - Br->eraseFromParent(); - return; - } - - case TermKind::CondBranchInst: { - auto CondBr = cast(T); - SmallVector TrueArgs; - if (OldDest == CondBr->getFalseBB() || PreserveArgs) { - for (auto Arg : CondBr->getTrueArgs()) - TrueArgs.push_back(Arg); - } - SmallVector FalseArgs; - if (OldDest == CondBr->getTrueBB() || PreserveArgs) { - for (auto Arg : CondBr->getFalseArgs()) - FalseArgs.push_back(Arg); - } - SILBasicBlock *TrueDest = CondBr->getTrueBB(); - SILBasicBlock *FalseDest = CondBr->getFalseBB(); - if (OldDest == CondBr->getTrueBB()) { - TrueDest = NewDest; - } else { - assert(OldDest == CondBr->getFalseBB() && "wrong cond_br target"); - FalseDest = NewDest; - } - - B.createCondBranch(CondBr->getLoc(), CondBr->getCondition(), TrueDest, - TrueArgs, FalseDest, FalseArgs, CondBr->getTrueBBCount(), - CondBr->getFalseBBCount()); - CondBr->dropAllReferences(); - CondBr->eraseFromParent(); - return; - } - - case TermKind::SwitchValueInst: { - auto SII = cast(T); - SmallVector, 8> Cases; - auto *DefaultBB = replaceSwitchDest(SII, Cases, OldDest, NewDest); - B.createSwitchValue(SII->getLoc(), SII->getOperand(), DefaultBB, Cases); - SII->eraseFromParent(); - return; - } - - case TermKind::SwitchEnumInst: { - auto SEI = cast(T); - SmallVector, 8> Cases; - auto *DefaultBB = replaceSwitchDest(SEI, Cases, OldDest, NewDest); - B.createSwitchEnum(SEI->getLoc(), SEI->getOperand(), DefaultBB, Cases); - SEI->eraseFromParent(); - return; - } - - case TermKind::SwitchEnumAddrInst: { - auto SEI = cast(T); - SmallVector, 8> Cases; - auto *DefaultBB = replaceSwitchDest(SEI, Cases, OldDest, NewDest); - B.createSwitchEnumAddr(SEI->getLoc(), SEI->getOperand(), DefaultBB, Cases); - SEI->eraseFromParent(); - return; - } - - case TermKind::DynamicMethodBranchInst: { - auto DMBI = cast(T); - assert(OldDest == DMBI->getHasMethodBB() || OldDest == DMBI->getNoMethodBB() && "Invalid edge index"); - auto HasMethodBB = OldDest == DMBI->getHasMethodBB() ? NewDest : DMBI->getHasMethodBB(); - auto NoMethodBB = OldDest == DMBI->getNoMethodBB() ? NewDest : DMBI->getNoMethodBB(); - B.createDynamicMethodBranch(DMBI->getLoc(), DMBI->getOperand(), - DMBI->getMember(), HasMethodBB, NoMethodBB); - DMBI->eraseFromParent(); - return; - } - - case TermKind::CheckedCastBranchInst: { - auto CBI = cast(T); - assert(OldDest == CBI->getSuccessBB() || OldDest == CBI->getFailureBB() && "Invalid edge index"); - auto SuccessBB = OldDest == CBI->getSuccessBB() ? NewDest : CBI->getSuccessBB(); - auto FailureBB = OldDest == CBI->getFailureBB() ? NewDest : CBI->getFailureBB(); - B.createCheckedCastBranch(CBI->getLoc(), CBI->isExact(), CBI->getOperand(), - CBI->getCastType(), SuccessBB, FailureBB, - CBI->getTrueBBCount(), CBI->getFalseBBCount()); - CBI->eraseFromParent(); - return; - } - - case TermKind::CheckedCastValueBranchInst: { - auto CBI = cast(T); - assert(OldDest == CBI->getSuccessBB() || - OldDest == CBI->getFailureBB() && "Invalid edge index"); - auto SuccessBB = - OldDest == CBI->getSuccessBB() ? NewDest : CBI->getSuccessBB(); - auto FailureBB = - OldDest == CBI->getFailureBB() ? NewDest : CBI->getFailureBB(); - B.createCheckedCastValueBranch(CBI->getLoc(), CBI->getOperand(), - CBI->getCastType(), SuccessBB, FailureBB); - CBI->eraseFromParent(); - return; - } - - case TermKind::CheckedCastAddrBranchInst: { - auto CBI = cast(T); - assert(OldDest == CBI->getSuccessBB() || OldDest == CBI->getFailureBB() && "Invalid edge index"); - auto SuccessBB = OldDest == CBI->getSuccessBB() ? NewDest : CBI->getSuccessBB(); - auto FailureBB = OldDest == CBI->getFailureBB() ? NewDest : CBI->getFailureBB(); - auto TrueCount = CBI->getTrueBBCount(); - auto FalseCount = CBI->getFalseBBCount(); - B.createCheckedCastAddrBranch(CBI->getLoc(), CBI->getConsumptionKind(), - CBI->getSrc(), CBI->getSourceType(), - CBI->getDest(), CBI->getTargetType(), - SuccessBB, FailureBB, TrueCount, FalseCount); - CBI->eraseFromParent(); - return; - } - - case TermKind::ReturnInst: - case TermKind::ThrowInst: - case TermKind::TryApplyInst: - case TermKind::UnreachableInst: - case TermKind::UnwindInst: - case TermKind::YieldInst: - llvm_unreachable("Branch target cannot be replaced for this terminator instruction!"); - } - llvm_unreachable("Not yet implemented!"); -} - -/// Check if the edge from the terminator is critical. -bool swift::isCriticalEdge(TermInst *T, unsigned EdgeIdx) { - assert(T->getSuccessors().size() > EdgeIdx && "Not enough successors"); - - auto SrcSuccs = T->getSuccessors(); - - if (SrcSuccs.size() <= 1 && - // Also consider non-branch instructions with a single successor for - // critical edges, for example: a switch_enum of a single-case enum. - (isa(T) || isa(T))) - return false; - - SILBasicBlock *DestBB = SrcSuccs[EdgeIdx]; - assert(!DestBB->pred_empty() && "There should be a predecessor"); - if (DestBB->getSinglePredecessorBlock()) - return false; - - return true; -} - -/// Splits the basic block at the iterator with an unconditional branch and -/// updates the dominator tree and loop info. -SILBasicBlock *swift::splitBasicBlockAndBranch(SILBuilder &B, - SILInstruction *SplitBeforeInst, - DominanceInfo *DT, - SILLoopInfo *LI) { - auto *OrigBB = SplitBeforeInst->getParent(); - auto *NewBB = OrigBB->split(SplitBeforeInst->getIterator()); - B.setInsertionPoint(OrigBB); - B.createBranch(SplitBeforeInst->getLoc(), NewBB); - - // Update the dominator tree. - if (DT) { - auto OrigBBDTNode = DT->getNode(OrigBB); - if (OrigBBDTNode) { - // Change the immediate dominators of the children of the block we - // splitted to the splitted block. - SmallVector Adoptees(OrigBBDTNode->begin(), - OrigBBDTNode->end()); - - auto NewBBDTNode = DT->addNewBlock(NewBB, OrigBB); - for (auto *Adoptee : Adoptees) - DT->changeImmediateDominator(Adoptee, NewBBDTNode); - } - } - - // Update loop info. - if (LI) - if (auto *OrigBBLoop = LI->getLoopFor(OrigBB)) { - OrigBBLoop->addBasicBlockToLoop(NewBB, LI->getBase()); - } - - return NewBB; -} - -/// Split every edge between two basic blocks. -void swift::splitEdgesFromTo(SILBasicBlock *From, SILBasicBlock *To, - DominanceInfo *DT, SILLoopInfo *LI) { - for (unsigned EdgeIndex = 0, E = From->getSuccessors().size(); EdgeIndex != E; - ++EdgeIndex) { - SILBasicBlock *SuccBB = From->getSuccessors()[EdgeIndex]; - if (SuccBB != To) - continue; - splitEdge(From->getTerminator(), EdgeIndex, DT, LI); - } -} - -/// Splits the n-th critical edge from the terminator and updates dominance and -/// loop info if set. -/// Returns the newly created basic block on success or nullptr otherwise (if -/// the edge was not critical. -SILBasicBlock *swift::splitCriticalEdge(TermInst *T, unsigned EdgeIdx, - DominanceInfo *DT, SILLoopInfo *LI) { - if (!isCriticalEdge(T, EdgeIdx)) - return nullptr; - - return splitEdge(T, EdgeIdx, DT, LI); -} - -bool swift::splitCriticalEdgesFrom(SILBasicBlock *fromBB, DominanceInfo *DT, - SILLoopInfo *LI) { - bool Changed = false; - for (unsigned idx = 0, e = fromBB->getSuccessors().size(); idx != e; ++idx) { - auto *NewBB = splitCriticalEdge(fromBB->getTerminator(), idx, DT, LI); - Changed |= (NewBB != nullptr); - } - return Changed; -} - -bool swift::hasCriticalEdges(SILFunction &F, bool OnlyNonCondBr) { - for (SILBasicBlock &BB : F) { - // Only consider critical edges for terminators that don't support block - // arguments. - if (OnlyNonCondBr && isa(BB.getTerminator())) - continue; - - if (isa(BB.getTerminator())) - continue; - - for (unsigned Idx = 0, e = BB.getSuccessors().size(); Idx != e; ++Idx) - if (isCriticalEdge(BB.getTerminator(), Idx)) - return true; - } - return false; -} - -/// Split all critical edges in the function updating the dominator tree and -/// loop information (if they are not set to null). -bool swift::splitAllCriticalEdges(SILFunction &F, DominanceInfo *DT, - SILLoopInfo *LI) { - bool Changed = false; - - for (SILBasicBlock &BB : F) { - if (isa(BB.getTerminator())) - continue; - - for (unsigned Idx = 0, e = BB.getSuccessors().size(); Idx != e; ++Idx) { - auto *NewBB = splitCriticalEdge(BB.getTerminator(), Idx, DT, LI); - assert(!NewBB - || isa(BB.getTerminator()) - && "Only cond_br may have a critical edge."); - Changed |= (NewBB != nullptr); - } - } - return Changed; -} - -/// Merge the basic block with its successor if possible. If dominance -/// information or loop info is non null update it. Return true if block was -/// merged. -bool swift::mergeBasicBlockWithSuccessor(SILBasicBlock *BB, DominanceInfo *DT, - SILLoopInfo *LI) { - auto *Branch = dyn_cast(BB->getTerminator()); - if (!Branch) - return false; - - auto *SuccBB = Branch->getDestBB(); - if (BB == SuccBB || !SuccBB->getSinglePredecessorBlock()) - return false; - - if (DT) - if (auto *SuccBBNode = DT->getNode(SuccBB)) { - // Change the immediate dominator for children of the successor to be the - // current block. - auto *BBNode = DT->getNode(BB); - SmallVector Children(SuccBBNode->begin(), - SuccBBNode->end()); - for (auto *ChildNode : Children) - DT->changeImmediateDominator(ChildNode, BBNode); - - DT->eraseNode(SuccBB); - } - - if (LI) - LI->removeBlock(SuccBB); - - mergeBasicBlockWithSingleSuccessor(BB, SuccBB); - - return true; -} - -bool swift::mergeBasicBlocks(SILFunction *F) { - bool merged = false; - for (auto BBIter = F->begin(); BBIter != F->end();) { - if (mergeBasicBlockWithSuccessor(&*BBIter, /*DT*/ nullptr, /*LI*/ nullptr)) { - merged = true; - // Continue to merge the current block without advancing. - continue; - } - ++BBIter; - } - return merged; -} - -/// Splits the critical edges between from and to. This code assumes there is -/// only one edge between the two basic blocks. -SILBasicBlock *swift::splitIfCriticalEdge(SILBasicBlock *From, - SILBasicBlock *To, - DominanceInfo *DT, - SILLoopInfo *LI) { - auto *T = From->getTerminator(); - for (unsigned i = 0, e = T->getSuccessors().size(); i != e; ++i) { - if (T->getSuccessors()[i] == To) - return splitCriticalEdge(T, i, DT, LI); - } - llvm_unreachable("Destination block not found"); -} - -void swift::completeJointPostDominanceSet( - ArrayRef UserBlocks, ArrayRef DefBlocks, - llvm::SmallVectorImpl &Result) { - assert(!UserBlocks.empty() && "Must have at least 1 user block"); - assert(!DefBlocks.empty() && "Must have at least 1 def block"); - - // If we have only one def block and one user block and they are the same - // block, then just return. - if (DefBlocks.size() == 1 && UserBlocks.size() == 1 && - UserBlocks[0] == DefBlocks[0]) { - return; - } - - // Some notes on the algorithm: - // - // 1. Our VisitedBlocks set just states that a value has been added to the - // worklist and should not be added to the worklist. - // 2. Our targets of the CFG block are DefBlockSet. - // 3. We find the missing post-domination blocks by finding successors of - // blocks on our walk that we have not visited by the end of the walk. For - // joint post-dominance to be true, no such successors should exist. - - // Our set of target blocks where we stop walking. - llvm::SmallPtrSet DefBlockSet(DefBlocks.begin(), - DefBlocks.end()); - - // The set of successor blocks of blocks that we visit. Any blocks still in - // this set at the end of the walk act as a post-dominating closure around our - // UserBlock set. - llvm::SmallSetVector MustVisitSuccessorBlocks; - - // Add our user and def blocks to the VisitedBlock set. We never want to find - // these in our worklist. - llvm::SmallPtrSet VisitedBlocks(UserBlocks.begin(), - UserBlocks.end()); - - // Finally setup our worklist by adding our user block predecessors. We only - // add the predecessors to the worklist once. - llvm::SmallVector Worklist; - for (auto *Block : UserBlocks) { - llvm::copy_if(Block->getPredecessorBlocks(), std::back_inserter(Worklist), - [&](SILBasicBlock *PredBlock) -> bool { - return VisitedBlocks.insert(PredBlock).second; - }); - } - - // Then until we reach a fix point. - while (!Worklist.empty()) { - // Grab the next block from the worklist. - auto *Block = Worklist.pop_back_val(); - assert(VisitedBlocks.count(Block) && "All blocks from worklist should be " - "in the visited blocks set."); - - // Since we are visiting this block now, we know that this block can not be - // apart of a the post-dominance closure of our UseBlocks. - MustVisitSuccessorBlocks.remove(Block); - - // Then add each successor block of Block that has not been visited yet to - // the MustVisitSuccessorBlocks set. - for (auto *SuccBlock : Block->getSuccessorBlocks()) { - if (!VisitedBlocks.count(SuccBlock)) { - MustVisitSuccessorBlocks.insert(SuccBlock); - } - } - - // If this is a def block, then do not add its predecessors to the - // worklist. - if (DefBlockSet.count(Block)) - continue; - - // Otherwise add all unvisited predecessors to the worklist. - llvm::copy_if(Block->getPredecessorBlocks(), std::back_inserter(Worklist), - [&](SILBasicBlock *Block) -> bool { - return VisitedBlocks.insert(Block).second; - }); - } - - // Now that we are done, add all remaining must visit blocks to our result - // list. These are the remaining parts of our joint post-dominance closure. - llvm::copy(MustVisitSuccessorBlocks, std::back_inserter(Result)); -} - -bool swift::splitAllCondBrCriticalEdgesWithNonTrivialArgs(SILFunction &Fn, - DominanceInfo *DT, - SILLoopInfo *LI) { - // Find our targets. - llvm::SmallVector, 8> Targets; - for (auto &Block : Fn) { - auto *CBI = dyn_cast(Block.getTerminator()); - if (!CBI) - continue; - - // See if our true index is a critical edge. If so, add block to the list - // and continue. If the false edge is also critical, we will handle it at - // the same time. - if (isCriticalEdge(CBI, CondBranchInst::TrueIdx)) { - Targets.emplace_back(&Block, CondBranchInst::TrueIdx); - } - - if (!isCriticalEdge(CBI, CondBranchInst::FalseIdx)) { - continue; - } - - Targets.emplace_back(&Block, CondBranchInst::FalseIdx); - } - - if (Targets.empty()) - return false; - - for (auto P : Targets) { - SILBasicBlock *Block = P.first; - unsigned Index = P.second; - auto *Result = splitCriticalEdge(Block->getTerminator(), Index, DT, LI); - (void)Result; - assert(Result); - } - - return true; -} - -bool swift::removeUnreachableBlocks(SILFunction &Fn) { - // All reachable blocks, but does not include the entry block. - llvm::SmallPtrSet Visited; - - // Walk over the CFG, starting at the entry block, until all reachable blocks are visited. - llvm::SmallVector Worklist(1, Fn.getEntryBlock()); - while (!Worklist.empty()) { - SILBasicBlock *BB = Worklist.pop_back_val(); - for (auto &Succ : BB->getSuccessors()) { - if (Visited.insert(Succ).second) - Worklist.push_back(Succ); - } - } - - // Remove the blocks we never reached. Exclude the entry block from the iteration because it's - // not included in the Visited set. - bool Changed = false; - for (auto It = std::next(Fn.begin()), End = Fn.end(); It != End; ) { - auto *BB = &*It++; - if (!Visited.count(BB)) { - removeDeadBlock(BB); - Changed = true; - } - } - return Changed; -} diff --git a/lib/SILOptimizer/Utils/CFGOptUtils.cpp b/lib/SILOptimizer/Utils/CFGOptUtils.cpp new file mode 100644 index 00000000000..b310323cc27 --- /dev/null +++ b/lib/SILOptimizer/Utils/CFGOptUtils.cpp @@ -0,0 +1,826 @@ +//===--- CFGOptUtils.cpp - SIL CFG edge utilities -------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "swift/Demangling/ManglingMacros.h" +#include "swift/SIL/BasicBlockUtils.h" +#include "swift/SIL/Dominance.h" +#include "swift/SIL/LoopInfo.h" +#include "swift/SIL/SILArgument.h" +#include "swift/SIL/SILBuilder.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "llvm/ADT/TinyPtrVector.h" + +using namespace swift; + +/// Adds a new argument to an edge between a branch and a destination +/// block. +/// +/// \param branch The terminator to add the argument to. +/// \param dest The destination block of the edge. +/// \param Val The value to the arguments of the branch. +/// \return The created branch. The old branch is deleted. +/// The argument is appended at the end of the argument tuple. +TermInst *swift::addNewEdgeValueToBranch(TermInst *branch, SILBasicBlock *dest, + SILValue val) { + SILBuilderWithScope builder(branch); + TermInst *newBr = nullptr; + + if (auto *cbi = dyn_cast(branch)) { + SmallVector trueArgs; + SmallVector falseArgs; + + for (auto arg : cbi->getTrueArgs()) + trueArgs.push_back(arg); + + for (auto arg : cbi->getFalseArgs()) + falseArgs.push_back(arg); + + if (dest == cbi->getTrueBB()) { + trueArgs.push_back(val); + assert(trueArgs.size() == dest->getNumArguments()); + } + if (dest == cbi->getFalseBB()) { + falseArgs.push_back(val); + assert(falseArgs.size() == dest->getNumArguments()); + } + + newBr = builder.createCondBranch( + cbi->getLoc(), cbi->getCondition(), cbi->getTrueBB(), trueArgs, + cbi->getFalseBB(), falseArgs, cbi->getTrueBBCount(), + cbi->getFalseBBCount()); + } else if (auto *bi = dyn_cast(branch)) { + SmallVector args; + + for (auto arg : bi->getArgs()) + args.push_back(arg); + + args.push_back(val); + assert(args.size() == dest->getNumArguments()); + newBr = builder.createBranch(bi->getLoc(), bi->getDestBB(), args); + } else { + // At the moment we can only add arguments to br and cond_br. + llvm_unreachable("Can't add argument to terminator"); + } + + branch->dropAllReferences(); + branch->eraseFromParent(); + + return newBr; +} + +static void +deleteTriviallyDeadOperandsOfDeadArgument(MutableArrayRef termOperands, + unsigned deadArgIndex) { + Operand &op = termOperands[deadArgIndex]; + auto *i = op.get()->getDefiningInstruction(); + if (!i) + return; + op.set(SILUndef::get(op.get()->getType(), *i->getFunction())); + recursivelyDeleteTriviallyDeadInstructions(i); +} + +// Our implementation assumes that our caller is attempting to remove a dead +// SILPhiArgument from a SILBasicBlock and has already RAUWed the argument. +TermInst *swift::deleteEdgeValue(TermInst *branch, SILBasicBlock *destBlock, + size_t argIndex) { + if (auto *cbi = dyn_cast(branch)) { + SmallVector trueArgs; + SmallVector falseArgs; + + llvm::copy(cbi->getTrueArgs(), std::back_inserter(trueArgs)); + llvm::copy(cbi->getFalseArgs(), std::back_inserter(falseArgs)); + + if (destBlock == cbi->getTrueBB()) { + deleteTriviallyDeadOperandsOfDeadArgument(cbi->getTrueOperands(), + argIndex); + trueArgs.erase(trueArgs.begin() + argIndex); + } + + if (destBlock == cbi->getFalseBB()) { + deleteTriviallyDeadOperandsOfDeadArgument(cbi->getFalseOperands(), + argIndex); + falseArgs.erase(falseArgs.begin() + argIndex); + } + + SILBuilderWithScope builder(cbi); + auto *result = builder.createCondBranch( + cbi->getLoc(), cbi->getCondition(), cbi->getTrueBB(), trueArgs, + cbi->getFalseBB(), falseArgs, cbi->getTrueBBCount(), + cbi->getFalseBBCount()); + branch->eraseFromParent(); + return result; + } + + if (auto *bi = dyn_cast(branch)) { + SmallVector args; + llvm::copy(bi->getArgs(), std::back_inserter(args)); + + deleteTriviallyDeadOperandsOfDeadArgument(bi->getAllOperands(), argIndex); + args.erase(args.begin() + argIndex); + auto *result = SILBuilderWithScope(bi).createBranch(bi->getLoc(), + bi->getDestBB(), args); + branch->eraseFromParent(); + return result; + } + + llvm_unreachable("unsupported terminator"); +} + +void swift::erasePhiArgument(SILBasicBlock *block, unsigned argIndex) { + assert(block->getArgument(argIndex)->isPhiArgument() + && "Only should be used on phi arguments"); + block->eraseArgument(argIndex); + + // Determine the set of predecessors in case any predecessor has + // two edges to this block (e.g. a conditional branch where both + // sides reach this block). + // + // NOTE: This needs to be a SmallSetVector since we need both uniqueness /and/ + // insertion order. Otherwise non-determinism can result. + SmallSetVector predBlocks; + + for (auto *pred : block->getPredecessorBlocks()) + predBlocks.insert(pred); + + for (auto *pred : predBlocks) + deleteEdgeValue(pred->getTerminator(), block, argIndex); +} + +/// Changes the edge value between a branch and destination basic block +/// at the specified index. Changes all edges from \p branch to \p dest to carry +/// the value. +/// +/// \param branch The branch to modify. +/// \param dest The destination of the edge. +/// \param idx The index of the argument to modify. +/// \param Val The new value to use. +/// \return The new branch. Deletes the old one. +/// Changes the edge value between a branch and destination basic block at the +/// specified index. +TermInst *swift::changeEdgeValue(TermInst *branch, SILBasicBlock *dest, + size_t idx, SILValue Val) { + SILBuilderWithScope builder(branch); + + if (auto *cbi = dyn_cast(branch)) { + SmallVector trueArgs; + SmallVector falseArgs; + + OperandValueArrayRef oldTrueArgs = cbi->getTrueArgs(); + bool branchOnTrue = cbi->getTrueBB() == dest; + assert((!branchOnTrue || idx < oldTrueArgs.size()) && "Not enough edges"); + + // Copy the edge values overwriting the edge at idx. + for (unsigned i = 0, e = oldTrueArgs.size(); i != e; ++i) { + if (branchOnTrue && idx == i) + trueArgs.push_back(Val); + else + trueArgs.push_back(oldTrueArgs[i]); + } + assert(trueArgs.size() == cbi->getTrueBB()->getNumArguments() + && "Destination block's number of arguments must match"); + + OperandValueArrayRef oldFalseArgs = cbi->getFalseArgs(); + bool branchOnFalse = cbi->getFalseBB() == dest; + assert((!branchOnFalse || idx < oldFalseArgs.size()) && "Not enough edges"); + + // Copy the edge values overwriting the edge at idx. + for (unsigned i = 0, e = oldFalseArgs.size(); i != e; ++i) { + if (branchOnFalse && idx == i) + falseArgs.push_back(Val); + else + falseArgs.push_back(oldFalseArgs[i]); + } + assert(falseArgs.size() == cbi->getFalseBB()->getNumArguments() + && "Destination block's number of arguments must match"); + + cbi = builder.createCondBranch( + cbi->getLoc(), cbi->getCondition(), cbi->getTrueBB(), trueArgs, + cbi->getFalseBB(), falseArgs, cbi->getTrueBBCount(), + cbi->getFalseBBCount()); + branch->dropAllReferences(); + branch->eraseFromParent(); + return cbi; + } + + if (auto *bi = dyn_cast(branch)) { + SmallVector args; + + assert(idx < bi->getNumArgs() && "Not enough edges"); + OperandValueArrayRef oldArgs = bi->getArgs(); + + // Copy the edge values overwriting the edge at idx. + for (unsigned i = 0, e = oldArgs.size(); i != e; ++i) { + if (idx == i) + args.push_back(Val); + else + args.push_back(oldArgs[i]); + } + assert(args.size() == dest->getNumArguments()); + + bi = builder.createBranch(bi->getLoc(), bi->getDestBB(), args); + branch->dropAllReferences(); + branch->eraseFromParent(); + return bi; + } + + llvm_unreachable("Unhandled terminator leading to merge block"); +} + +template +SILBasicBlock *replaceSwitchDest(SwitchEnumTy *sTy, + SmallVectorImpl &cases, + unsigned edgeIdx, SILBasicBlock *newDest) { + auto *defaultBB = sTy->hasDefault() ? sTy->getDefaultBB() : nullptr; + for (unsigned i = 0, e = sTy->getNumCases(); i != e; ++i) + if (edgeIdx != i) + cases.push_back(sTy->getCase(i)); + else + cases.push_back(std::make_pair(sTy->getCase(i).first, newDest)); + if (edgeIdx == sTy->getNumCases()) + defaultBB = newDest; + return defaultBB; +} + +template +SILBasicBlock * +replaceSwitchDest(SwitchEnumTy *sTy, SmallVectorImpl &cases, + SILBasicBlock *oldDest, SILBasicBlock *newDest) { + auto *defaultBB = sTy->hasDefault() ? sTy->getDefaultBB() : nullptr; + for (unsigned i = 0, e = sTy->getNumCases(); i != e; ++i) + if (sTy->getCase(i).second != oldDest) + cases.push_back(sTy->getCase(i)); + else + cases.push_back(std::make_pair(sTy->getCase(i).first, newDest)); + if (oldDest == defaultBB) + defaultBB = newDest; + return defaultBB; +} + +/// Replace a branch target. +/// +/// \param T The terminating instruction to modify. +/// \param oldDest The successor block that will be replaced. +/// \param newDest The new target block. +/// \param preserveArgs If set, preserve arguments on the replaced edge. +void swift::replaceBranchTarget(TermInst *t, SILBasicBlock *oldDest, + SILBasicBlock *newDest, bool preserveArgs) { + SILBuilderWithScope builder(t); + + switch (t->getTermKind()) { + // Only Branch and CondBranch may have arguments. + case TermKind::BranchInst: { + auto br = cast(t); + assert(oldDest == br->getDestBB() && "wrong branch target"); + SmallVector args; + if (preserveArgs) { + for (auto arg : br->getArgs()) + args.push_back(arg); + } + builder.createBranch(t->getLoc(), newDest, args); + br->dropAllReferences(); + br->eraseFromParent(); + return; + } + + case TermKind::CondBranchInst: { + auto condBr = cast(t); + SmallVector trueArgs; + if (oldDest == condBr->getFalseBB() || preserveArgs) { + for (auto Arg : condBr->getTrueArgs()) + trueArgs.push_back(Arg); + } + SmallVector falseArgs; + if (oldDest == condBr->getTrueBB() || preserveArgs) { + for (auto arg : condBr->getFalseArgs()) + falseArgs.push_back(arg); + } + SILBasicBlock *trueDest = condBr->getTrueBB(); + SILBasicBlock *falseDest = condBr->getFalseBB(); + if (oldDest == condBr->getTrueBB()) { + trueDest = newDest; + } else { + assert(oldDest == condBr->getFalseBB() && "wrong cond_br target"); + falseDest = newDest; + } + + builder.createCondBranch( + condBr->getLoc(), condBr->getCondition(), trueDest, trueArgs, falseDest, + falseArgs, condBr->getTrueBBCount(), condBr->getFalseBBCount()); + condBr->dropAllReferences(); + condBr->eraseFromParent(); + return; + } + + case TermKind::SwitchValueInst: { + auto sii = cast(t); + SmallVector, 8> cases; + auto *defaultBB = replaceSwitchDest(sii, cases, oldDest, newDest); + builder.createSwitchValue(sii->getLoc(), sii->getOperand(), defaultBB, + cases); + sii->eraseFromParent(); + return; + } + + case TermKind::SwitchEnumInst: { + auto sei = cast(t); + SmallVector, 8> cases; + auto *defaultBB = replaceSwitchDest(sei, cases, oldDest, newDest); + builder.createSwitchEnum(sei->getLoc(), sei->getOperand(), defaultBB, + cases); + sei->eraseFromParent(); + return; + } + + case TermKind::SwitchEnumAddrInst: { + auto sei = cast(t); + SmallVector, 8> cases; + auto *defaultBB = replaceSwitchDest(sei, cases, oldDest, newDest); + builder.createSwitchEnumAddr(sei->getLoc(), sei->getOperand(), defaultBB, + cases); + sei->eraseFromParent(); + return; + } + + case TermKind::DynamicMethodBranchInst: { + auto dmbi = cast(t); + assert(oldDest == dmbi->getHasMethodBB() + || oldDest == dmbi->getNoMethodBB() && "Invalid edge index"); + auto hasMethodBB = + oldDest == dmbi->getHasMethodBB() ? newDest : dmbi->getHasMethodBB(); + auto noMethodBB = + oldDest == dmbi->getNoMethodBB() ? newDest : dmbi->getNoMethodBB(); + builder.createDynamicMethodBranch(dmbi->getLoc(), dmbi->getOperand(), + dmbi->getMember(), hasMethodBB, + noMethodBB); + dmbi->eraseFromParent(); + return; + } + + case TermKind::CheckedCastBranchInst: { + auto cbi = cast(t); + assert(oldDest == cbi->getSuccessBB() + || oldDest == cbi->getFailureBB() && "Invalid edge index"); + auto successBB = + oldDest == cbi->getSuccessBB() ? newDest : cbi->getSuccessBB(); + auto failureBB = + oldDest == cbi->getFailureBB() ? newDest : cbi->getFailureBB(); + builder.createCheckedCastBranch( + cbi->getLoc(), cbi->isExact(), cbi->getOperand(), cbi->getCastType(), + successBB, failureBB, cbi->getTrueBBCount(), cbi->getFalseBBCount()); + cbi->eraseFromParent(); + return; + } + + case TermKind::CheckedCastValueBranchInst: { + auto cbi = cast(t); + assert(oldDest == cbi->getSuccessBB() + || oldDest == cbi->getFailureBB() && "Invalid edge index"); + auto successBB = + oldDest == cbi->getSuccessBB() ? newDest : cbi->getSuccessBB(); + auto failureBB = + oldDest == cbi->getFailureBB() ? newDest : cbi->getFailureBB(); + builder.createCheckedCastValueBranch(cbi->getLoc(), cbi->getOperand(), + cbi->getCastType(), successBB, + failureBB); + cbi->eraseFromParent(); + return; + } + + case TermKind::CheckedCastAddrBranchInst: { + auto cbi = cast(t); + assert(oldDest == cbi->getSuccessBB() + || oldDest == cbi->getFailureBB() && "Invalid edge index"); + auto successBB = + oldDest == cbi->getSuccessBB() ? newDest : cbi->getSuccessBB(); + auto failureBB = + oldDest == cbi->getFailureBB() ? newDest : cbi->getFailureBB(); + auto trueCount = cbi->getTrueBBCount(); + auto falseCount = cbi->getFalseBBCount(); + builder.createCheckedCastAddrBranch( + cbi->getLoc(), cbi->getConsumptionKind(), cbi->getSrc(), + cbi->getSourceType(), cbi->getDest(), cbi->getTargetType(), successBB, + failureBB, trueCount, falseCount); + cbi->eraseFromParent(); + return; + } + + case TermKind::ReturnInst: + case TermKind::ThrowInst: + case TermKind::TryApplyInst: + case TermKind::UnreachableInst: + case TermKind::UnwindInst: + case TermKind::YieldInst: + llvm_unreachable( + "Branch target cannot be replaced for this terminator instruction!"); + } + llvm_unreachable("Not yet implemented!"); +} + +/// Check if the edge from the terminator is critical. +bool swift::isCriticalEdge(TermInst *t, unsigned edgeIdx) { + assert(t->getSuccessors().size() > edgeIdx && "Not enough successors"); + + auto srcSuccs = t->getSuccessors(); + + if (srcSuccs.size() <= 1 && + // Also consider non-branch instructions with a single successor for + // critical edges, for example: a switch_enum of a single-case enum. + (isa(t) || isa(t))) + return false; + + SILBasicBlock *destBB = srcSuccs[edgeIdx]; + assert(!destBB->pred_empty() && "There should be a predecessor"); + if (destBB->getSinglePredecessorBlock()) + return false; + + return true; +} + +/// Splits the basic block at the iterator with an unconditional branch and +/// updates the dominator tree and loop info. +SILBasicBlock *swift::splitBasicBlockAndBranch(SILBuilder &builder, + SILInstruction *splitBeforeInst, + DominanceInfo *domInfo, + SILLoopInfo *loopInfo) { + auto *origBB = splitBeforeInst->getParent(); + auto *newBB = origBB->split(splitBeforeInst->getIterator()); + builder.setInsertionPoint(origBB); + builder.createBranch(splitBeforeInst->getLoc(), newBB); + + // Update the dominator tree. + if (domInfo) { + auto origBBDTNode = domInfo->getNode(origBB); + if (origBBDTNode) { + // Change the immediate dominators of the children of the block we + // splitted to the splitted block. + SmallVector Adoptees(origBBDTNode->begin(), + origBBDTNode->end()); + + auto newBBDTNode = domInfo->addNewBlock(newBB, origBB); + for (auto *adoptee : Adoptees) + domInfo->changeImmediateDominator(adoptee, newBBDTNode); + } + } + + // Update loop info. + if (loopInfo) + if (auto *origBBLoop = loopInfo->getLoopFor(origBB)) { + origBBLoop->addBasicBlockToLoop(newBB, loopInfo->getBase()); + } + + return newBB; +} + +/// Split every edge between two basic blocks. +void swift::splitEdgesFromTo(SILBasicBlock *From, SILBasicBlock *To, + DominanceInfo *domInfo, SILLoopInfo *loopInfo) { + for (unsigned edgeIndex = 0, E = From->getSuccessors().size(); edgeIndex != E; + ++edgeIndex) { + SILBasicBlock *succBB = From->getSuccessors()[edgeIndex]; + if (succBB != To) + continue; + splitEdge(From->getTerminator(), edgeIndex, domInfo, loopInfo); + } +} + +/// Splits the n-th critical edge from the terminator and updates dominance and +/// loop info if set. +/// Returns the newly created basic block on success or nullptr otherwise (if +/// the edge was not critical. +SILBasicBlock *swift::splitCriticalEdge(TermInst *t, unsigned edgeIdx, + DominanceInfo *domInfo, + SILLoopInfo *loopInfo) { + if (!isCriticalEdge(t, edgeIdx)) + return nullptr; + + return splitEdge(t, edgeIdx, domInfo, loopInfo); +} + +bool swift::splitCriticalEdgesFrom(SILBasicBlock *fromBB, + DominanceInfo *domInfo, + SILLoopInfo *loopInfo) { + bool changed = false; + for (unsigned idx = 0, e = fromBB->getSuccessors().size(); idx != e; ++idx) { + auto *newBB = + splitCriticalEdge(fromBB->getTerminator(), idx, domInfo, loopInfo); + changed |= (newBB != nullptr); + } + return changed; +} + +bool swift::hasCriticalEdges(SILFunction &f, bool onlyNonCondBr) { + for (SILBasicBlock &bb : f) { + // Only consider critical edges for terminators that don't support block + // arguments. + if (onlyNonCondBr && isa(bb.getTerminator())) + continue; + + if (isa(bb.getTerminator())) + continue; + + for (unsigned idx = 0, e = bb.getSuccessors().size(); idx != e; ++idx) + if (isCriticalEdge(bb.getTerminator(), idx)) + return true; + } + return false; +} + +/// Split all critical edges in the function updating the dominator tree and +/// loop information (if they are not set to null). +bool swift::splitAllCriticalEdges(SILFunction &f, DominanceInfo *domInfo, + SILLoopInfo *loopInfo) { + bool changed = false; + + for (SILBasicBlock &bb : f) { + if (isa(bb.getTerminator())) + continue; + + for (unsigned idx = 0, e = bb.getSuccessors().size(); idx != e; ++idx) { + auto *newBB = + splitCriticalEdge(bb.getTerminator(), idx, domInfo, loopInfo); + assert(!newBB + || isa(bb.getTerminator()) + && "Only cond_br may have a critical edge."); + changed |= (newBB != nullptr); + } + } + return changed; +} + +/// Merge the basic block with its successor if possible. If dominance +/// information or loop info is non null update it. Return true if block was +/// merged. +bool swift::mergeBasicBlockWithSuccessor(SILBasicBlock *bb, + DominanceInfo *domInfo, + SILLoopInfo *loopInfo) { + auto *branch = dyn_cast(bb->getTerminator()); + if (!branch) + return false; + + auto *succBB = branch->getDestBB(); + if (bb == succBB || !succBB->getSinglePredecessorBlock()) + return false; + + if (domInfo) + if (auto *succBBNode = domInfo->getNode(succBB)) { + // Change the immediate dominator for children of the successor to be the + // current block. + auto *bbNode = domInfo->getNode(bb); + SmallVector Children(succBBNode->begin(), + succBBNode->end()); + for (auto *ChildNode : Children) + domInfo->changeImmediateDominator(ChildNode, bbNode); + + domInfo->eraseNode(succBB); + } + + if (loopInfo) + loopInfo->removeBlock(succBB); + + mergeBasicBlockWithSingleSuccessor(bb, succBB); + + return true; +} + +bool swift::mergeBasicBlocks(SILFunction *f) { + bool merged = false; + for (auto bbIter = f->begin(); bbIter != f->end();) { + if (mergeBasicBlockWithSuccessor(&*bbIter, /*domInfo*/ nullptr, + /*loopInfo*/ nullptr)) { + merged = true; + // Continue to merge the current block without advancing. + continue; + } + ++bbIter; + } + return merged; +} + +/// Splits the critical edges between from and to. This code assumes there is +/// only one edge between the two basic blocks. +SILBasicBlock *swift::splitIfCriticalEdge(SILBasicBlock *from, + SILBasicBlock *to, + DominanceInfo *domInfo, + SILLoopInfo *loopInfo) { + auto *t = from->getTerminator(); + for (unsigned i = 0, e = t->getSuccessors().size(); i != e; ++i) { + if (t->getSuccessors()[i] == to) + return splitCriticalEdge(t, i, domInfo, loopInfo); + } + llvm_unreachable("Destination block not found"); +} + +void swift::completeJointPostDominanceSet( + ArrayRef userBlocks, ArrayRef defBlocks, + llvm::SmallVectorImpl &result) { + assert(!userBlocks.empty() && "Must have at least 1 user block"); + assert(!defBlocks.empty() && "Must have at least 1 def block"); + + // If we have only one def block and one user block and they are the same + // block, then just return. + if (defBlocks.size() == 1 && userBlocks.size() == 1 + && userBlocks[0] == defBlocks[0]) { + return; + } + + // Some notes on the algorithm: + // + // 1. Our VisitedBlocks set just states that a value has been added to the + // worklist and should not be added to the worklist. + // 2. Our targets of the CFG block are DefBlockSet. + // 3. We find the missing post-domination blocks by finding successors of + // blocks on our walk that we have not visited by the end of the walk. For + // joint post-dominance to be true, no such successors should exist. + + // Our set of target blocks where we stop walking. + llvm::SmallPtrSet defBlockSet(defBlocks.begin(), + defBlocks.end()); + + // The set of successor blocks of blocks that we visit. Any blocks still in + // this set at the end of the walk act as a post-dominating closure around our + // userBlock set. + llvm::SmallSetVector mustVisitSuccessorBlocks; + + // Add our user and def blocks to the visitedBlock set. We never want to find + // these in our worklist. + llvm::SmallPtrSet visitedBlocks(userBlocks.begin(), + userBlocks.end()); + + // Finally setup our worklist by adding our user block predecessors. We only + // add the predecessors to the worklist once. + llvm::SmallVector worklist; + for (auto *block : userBlocks) { + llvm::copy_if(block->getPredecessorBlocks(), std::back_inserter(worklist), + [&](SILBasicBlock *predBlock) -> bool { + return visitedBlocks.insert(predBlock).second; + }); + } + + // Then until we reach a fix point. + while (!worklist.empty()) { + // Grab the next block from the worklist. + auto *block = worklist.pop_back_val(); + assert(visitedBlocks.count(block) + && "All blocks from worklist should be " + "in the visited blocks set."); + + // Since we are visiting this block now, we know that this block can not be + // apart of a the post-dominance closure of our UseBlocks. + mustVisitSuccessorBlocks.remove(block); + + // Then add each successor block of block that has not been visited yet to + // the mustVisitSuccessorBlocks set. + for (auto *succBlock : block->getSuccessorBlocks()) { + if (!visitedBlocks.count(succBlock)) { + mustVisitSuccessorBlocks.insert(succBlock); + } + } + + // If this is a def block, then do not add its predecessors to the + // worklist. + if (defBlockSet.count(block)) + continue; + + // Otherwise add all unvisited predecessors to the worklist. + llvm::copy_if(block->getPredecessorBlocks(), std::back_inserter(worklist), + [&](SILBasicBlock *block) -> bool { + return visitedBlocks.insert(block).second; + }); + } + + // Now that we are done, add all remaining must visit blocks to our result + // list. These are the remaining parts of our joint post-dominance closure. + llvm::copy(mustVisitSuccessorBlocks, std::back_inserter(result)); +} + +bool swift::splitAllCondBrCriticalEdgesWithNonTrivialArgs( + SILFunction &fn, DominanceInfo *domInfo, SILLoopInfo *loopInfo) { + // Find our targets. + llvm::SmallVector, 8> targets; + for (auto &block : fn) { + auto *cbi = dyn_cast(block.getTerminator()); + if (!cbi) + continue; + + // See if our true index is a critical edge. If so, add block to the list + // and continue. If the false edge is also critical, we will handle it at + // the same time. + if (isCriticalEdge(cbi, CondBranchInst::TrueIdx)) { + targets.emplace_back(&block, CondBranchInst::TrueIdx); + } + + if (!isCriticalEdge(cbi, CondBranchInst::FalseIdx)) { + continue; + } + + targets.emplace_back(&block, CondBranchInst::FalseIdx); + } + + if (targets.empty()) + return false; + + for (auto p : targets) { + SILBasicBlock *block = p.first; + unsigned index = p.second; + auto *result = + splitCriticalEdge(block->getTerminator(), index, domInfo, loopInfo); + (void)result; + assert(result); + } + + return true; +} + +static bool isSafeNonExitTerminator(TermInst *ti) { + switch (ti->getTermKind()) { + case TermKind::BranchInst: + case TermKind::CondBranchInst: + case TermKind::SwitchValueInst: + case TermKind::SwitchEnumInst: + case TermKind::SwitchEnumAddrInst: + case TermKind::DynamicMethodBranchInst: + case TermKind::CheckedCastBranchInst: + case TermKind::CheckedCastValueBranchInst: + case TermKind::CheckedCastAddrBranchInst: + return true; + case TermKind::UnreachableInst: + case TermKind::ReturnInst: + case TermKind::ThrowInst: + case TermKind::UnwindInst: + return false; + // yield is special because it can do arbitrary, + // potentially-process-terminating things. + case TermKind::YieldInst: + return false; + case TermKind::TryApplyInst: + return true; + } + + llvm_unreachable("Unhandled TermKind in switch."); +} + +static bool isTrapNoReturnFunction(ApplyInst *ai) { + const char *fatalName = MANGLE_AS_STRING( + MANGLE_SYM(s18_fatalErrorMessageyys12StaticStringV_AcCSutF)); + auto *fn = ai->getReferencedFunctionOrNull(); + + // We use endswith here since if we specialize fatal error we will always + // prepend the specialization records to fatalName. + if (!fn || !fn->getName().endswith(fatalName)) + return false; + + return true; +} + +bool swift::findAllNonFailureExitBBs( + SILFunction *f, llvm::TinyPtrVector &bbs) { + for (SILBasicBlock &bb : *f) { + TermInst *ti = bb.getTerminator(); + + // If we know that this terminator is not an exit terminator, continue. + if (isSafeNonExitTerminator(ti)) + continue; + + // A return inst is always a non-failure exit bb. + if (ti->isFunctionExiting()) { + bbs.push_back(&bb); + continue; + } + + // If we don't have an unreachable inst at this point, this is a terminator + // we don't understand. Be conservative and return false. + if (!isa(ti)) + return false; + + // Ok, at this point we know we have a terminator. If it is the only + // instruction in our bb, it is a failure bb. continue... + if (ti == &*bb.begin()) + continue; + + // If the unreachable is preceded by a no-return apply inst, then it is a + // non-failure exit bb. Add it to our list and continue. + auto prevIter = std::prev(SILBasicBlock::iterator(ti)); + if (auto *ai = dyn_cast(&*prevIter)) { + if (ai->isCalleeNoReturn() && !isTrapNoReturnFunction(ai)) { + bbs.push_back(&bb); + continue; + } + } + + // Otherwise, it must be a failure bb where we leak, continue. + continue; + } + + // We understood all terminators, return true. + return true; +} diff --git a/lib/SILOptimizer/Utils/CMakeLists.txt b/lib/SILOptimizer/Utils/CMakeLists.txt index b45f12afffd..36f43361f0a 100644 --- a/lib/SILOptimizer/Utils/CMakeLists.txt +++ b/lib/SILOptimizer/Utils/CMakeLists.txt @@ -1,5 +1,6 @@ silopt_register_sources( - CFG.cpp + BasicBlockOptUtils.cpp + CFGOptUtils.cpp CanonicalizeInstruction.cpp CastOptimizer.cpp CheckedCastBrJumpThreading.cpp @@ -9,8 +10,8 @@ silopt_register_sources( Existential.cpp GenericCloner.cpp Generics.cpp + InstOptUtils.cpp LoadStoreOptUtils.cpp - Local.cpp LoopUtils.cpp OptimizerStatsUtils.cpp PerformanceInlinerUtils.cpp @@ -18,4 +19,5 @@ silopt_register_sources( SILSSAUpdater.cpp SpecializationMangler.cpp StackNesting.cpp + ValueLifetime.cpp ) diff --git a/lib/SILOptimizer/Utils/CastOptimizer.cpp b/lib/SILOptimizer/Utils/CastOptimizer.cpp index da136f54532..8891d3bb643 100644 --- a/lib/SILOptimizer/Utils/CastOptimizer.cpp +++ b/lib/SILOptimizer/Utils/CastOptimizer.cpp @@ -26,15 +26,15 @@ #include "swift/SIL/InstructionUtils.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILBuilder.h" -#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "swift/SIL/SILModule.h" #include "swift/SIL/SILUndef.h" #include "swift/SIL/TypeLowering.h" #include "swift/SILOptimizer/Analysis/ARCAnalysis.h" #include "swift/SILOptimizer/Analysis/Analysis.h" #include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" -#include "swift/SILOptimizer/Utils/CFG.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringSwitch.h" @@ -1215,8 +1215,8 @@ CastOptimizer::optimizeCheckedCastBranchInst(CheckedCastBranchInst *Inst) { if (Inst->isExact()) return nullptr; - // Local helper we use to simplify replacing a checked_cast_branch with an - // optimized checked cast branch. + // InstOptUtils.helper we use to simplify replacing a checked_cast_branch with + // an optimized checked cast branch. auto replaceCastHelper = [](SILBuilderWithScope &B, SILDynamicCastInst dynamicCast, MetatypeInst *mi) -> SILInstruction * { diff --git a/lib/SILOptimizer/Utils/CheckedCastBrJumpThreading.cpp b/lib/SILOptimizer/Utils/CheckedCastBrJumpThreading.cpp index 3f49cae3c1d..390e6e826a6 100644 --- a/lib/SILOptimizer/Utils/CheckedCastBrJumpThreading.cpp +++ b/lib/SILOptimizer/Utils/CheckedCastBrJumpThreading.cpp @@ -11,15 +11,16 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "sil-simplify-cfg" +#include "swift/SIL/InstructionUtils.h" +#include "swift/SIL/SILInstruction.h" +#include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" +#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "swift/SILOptimizer/Utils/SILInliner.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Allocator.h" -#include "swift/SIL/SILInstruction.h" -#include "swift/SIL/InstructionUtils.h" -#include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" -#include "swift/SILOptimizer/Utils/CFG.h" -#include "swift/SILOptimizer/Utils/Local.h" -#include "swift/SILOptimizer/Utils/SILInliner.h" using namespace swift; diff --git a/lib/SILOptimizer/Utils/ConstantFolding.cpp b/lib/SILOptimizer/Utils/ConstantFolding.cpp index 0e101edc22d..dc276b27f4d 100644 --- a/lib/SILOptimizer/Utils/ConstantFolding.cpp +++ b/lib/SILOptimizer/Utils/ConstantFolding.cpp @@ -18,7 +18,7 @@ #include "swift/SIL/PatternMatch.h" #include "swift/SIL/SILBuilder.h" #include "swift/SILOptimizer/Utils/CastOptimizer.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/Statistic.h" @@ -1527,7 +1527,11 @@ static bool constantFoldGlobalStringTablePointerBuiltin(BuiltinInst *bi, bool enableDiagnostics) { // Look through string initializer to extract the string_literal instruction. - SILValue builtinOperand = bi->getOperand(0); + // + // We allow for a single borrow to be stripped here if we are here in + // [ossa]. The begin borrow occurs b/c SILGen treats builtins as having + // arguments with a +0 convention (implying a borrow). + SILValue builtinOperand = stripBorrow(bi->getOperand(0)); SILFunction *caller = bi->getFunction(); FullApplySite stringInitSite = FullApplySite::isa(builtinOperand); diff --git a/lib/SILOptimizer/Utils/Devirtualize.cpp b/lib/SILOptimizer/Utils/Devirtualize.cpp index 4dff796e54c..6957266bc76 100644 --- a/lib/SILOptimizer/Utils/Devirtualize.cpp +++ b/lib/SILOptimizer/Utils/Devirtualize.cpp @@ -11,13 +11,13 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "sil-devirtualize-utility" -#include "swift/SILOptimizer/Analysis/ClassHierarchyAnalysis.h" #include "swift/SILOptimizer/Utils/Devirtualize.h" #include "swift/AST/Decl.h" #include "swift/AST/GenericSignature.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/SubstitutionMap.h" #include "swift/AST/Types.h" +#include "swift/SIL/InstructionUtils.h" #include "swift/SIL/OptimizationRemark.h" #include "swift/SIL/SILDeclRef.h" #include "swift/SIL/SILFunction.h" @@ -25,8 +25,8 @@ #include "swift/SIL/SILModule.h" #include "swift/SIL/SILType.h" #include "swift/SIL/SILValue.h" -#include "swift/SIL/InstructionUtils.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Analysis/ClassHierarchyAnalysis.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/Statistic.h" @@ -40,87 +40,83 @@ STATISTIC(NumWitnessDevirt, "Number of witness_method applies devirtualized"); // Class Method Optimization //===----------------------------------------------------------------------===// -void swift::getAllSubclasses(ClassHierarchyAnalysis *CHA, - ClassDecl *CD, - CanType ClassType, - SILModule &M, - ClassHierarchyAnalysis::ClassList &Subs) { +void swift::getAllSubclasses(ClassHierarchyAnalysis *cha, ClassDecl *cd, + CanType classType, SILModule &module, + ClassHierarchyAnalysis::ClassList &subs) { // Collect the direct and indirect subclasses for the class. // Sort these subclasses in the order they should be tested by the // speculative devirtualization. Different strategies could be used, // E.g. breadth-first, depth-first, etc. // Currently, let's use the breadth-first strategy. // The exact static type of the instance should be tested first. - auto &DirectSubs = CHA->getDirectSubClasses(CD); - auto &IndirectSubs = CHA->getIndirectSubClasses(CD); + auto &directSubs = cha->getDirectSubClasses(cd); + auto &indirectSubs = cha->getIndirectSubClasses(cd); - Subs.append(DirectSubs.begin(), DirectSubs.end()); - Subs.append(IndirectSubs.begin(), IndirectSubs.end()); + subs.append(directSubs.begin(), directSubs.end()); + subs.append(indirectSubs.begin(), indirectSubs.end()); // FIXME: This is wrong -- we could have a non-generic class nested // inside a generic class - if (isa(ClassType)) { + if (isa(classType)) { // Filter out any subclasses that do not inherit from this // specific bound class. - auto RemovedIt = std::remove_if(Subs.begin(), Subs.end(), - [&ClassType](ClassDecl *Sub){ + auto removedIt = + std::remove_if(subs.begin(), subs.end(), [&classType](ClassDecl *sub) { // FIXME: Add support for generic subclasses. - if (Sub->isGenericContext()) + if (sub->isGenericContext()) return false; - auto SubCanTy = Sub->getDeclaredInterfaceType()->getCanonicalType(); + auto subCanTy = sub->getDeclaredInterfaceType()->getCanonicalType(); // Handle the usual case here: the class in question // should be a real subclass of a bound generic class. - return !ClassType->isBindableToSuperclassOf( - SubCanTy); + return !classType->isBindableToSuperclassOf(subCanTy); }); - Subs.erase(RemovedIt, Subs.end()); + subs.erase(removedIt, subs.end()); } } /// Returns true, if a method implementation corresponding to -/// the class_method applied to an instance of the class CD is +/// the class_method applied to an instance of the class cd is /// effectively final, i.e. it is statically known to be not overridden -/// by any subclasses of the class CD. +/// by any subclasses of the class cd. /// -/// \p AI invocation instruction -/// \p ClassType type of the instance -/// \p CD static class of the instance whose method is being invoked -/// \p CHA class hierarchy analysis -static bool isEffectivelyFinalMethod(FullApplySite AI, - CanType ClassType, - ClassDecl *CD, - ClassHierarchyAnalysis *CHA) { - if (CD && CD->isFinal()) +/// \p applySite invocation instruction +/// \p classType type of the instance +/// \p cd static class of the instance whose method is being invoked +/// \p cha class hierarchy analysis +static bool isEffectivelyFinalMethod(FullApplySite applySite, CanType classType, + ClassDecl *cd, + ClassHierarchyAnalysis *cha) { + if (cd && cd->isFinal()) return true; - const DeclContext *DC = AI.getModule().getAssociatedContext(); + const DeclContext *dc = applySite.getModule().getAssociatedContext(); // Without an associated context we cannot perform any // access-based optimizations. - if (!DC) + if (!dc) return false; - auto *CMI = cast(AI.getCallee()); + auto *cmi = cast(applySite.getCallee()); - if (!calleesAreStaticallyKnowable(AI.getModule(), CMI->getMember())) + if (!calleesAreStaticallyKnowable(applySite.getModule(), cmi->getMember())) return false; - auto *Method = CMI->getMember().getAbstractFunctionDecl(); - assert(Method && "Expected abstract function decl!"); - assert(!Method->isFinal() && "Unexpected indirect call to final method!"); + auto *method = cmi->getMember().getAbstractFunctionDecl(); + assert(method && "Expected abstract function decl!"); + assert(!method->isFinal() && "Unexpected indirect call to final method!"); // If this method is not overridden in the module, // there is no other implementation. - if (!Method->isOverridden()) + if (!method->isOverridden()) return true; // Class declaration may be nullptr, e.g. for cases like: // func foo(c: C) {}, where C is a class, but // it does not have a class decl. - if (!CD) + if (!cd) return false; - if (!CHA) + if (!cha) return false; // This is a private or a module internal class. @@ -128,18 +124,18 @@ static bool isEffectivelyFinalMethod(FullApplySite AI, // We can analyze the class hierarchy rooted at it and // eventually devirtualize a method call more efficiently. - ClassHierarchyAnalysis::ClassList Subs; - getAllSubclasses(CHA, CD, ClassType, AI.getModule(), Subs); + ClassHierarchyAnalysis::ClassList subs; + getAllSubclasses(cha, cd, classType, applySite.getModule(), subs); // This is the implementation of the method to be used - // if the exact class of the instance would be CD. - auto *ImplMethod = CD->findImplementingMethod(Method); + // if the exact class of the instance would be cd. + auto *ImplMethod = cd->findImplementingMethod(method); // First, analyze all direct subclasses. - for (auto S : Subs) { + for (auto S : subs) { // Check if the subclass overrides a method and provides // a different implementation. - auto *ImplFD = S->findImplementingMethod(Method); + auto *ImplFD = S->findImplementingMethod(method); if (ImplFD != ImplMethod) return false; } @@ -153,32 +149,32 @@ static bool isEffectivelyFinalMethod(FullApplySite AI, /// - or it is private and has not sub-classes /// - or it is an internal class without sub-classes and /// it is a whole-module compilation. -static bool isKnownFinalClass(ClassDecl *CD, SILModule &M, - ClassHierarchyAnalysis *CHA) { - const DeclContext *DC = M.getAssociatedContext(); +static bool isKnownFinalClass(ClassDecl *cd, SILModule &module, + ClassHierarchyAnalysis *cha) { + const DeclContext *dc = module.getAssociatedContext(); - if (CD->isFinal()) + if (cd->isFinal()) return true; // Without an associated context we cannot perform any // access-based optimizations. - if (!DC) + if (!dc) return false; // Only handle classes defined within the SILModule's associated context. - if (!CD->isChildContextOf(DC)) + if (!cd->isChildContextOf(dc)) return false; - if (!CD->hasAccess()) + if (!cd->hasAccess()) return false; // Only consider 'private' members, unless we are in whole-module compilation. - switch (CD->getEffectiveAccess()) { + switch (cd->getEffectiveAccess()) { case AccessLevel::Open: return false; case AccessLevel::Public: case AccessLevel::Internal: - if (!M.isWholeModule()) + if (!module.isWholeModule()) return false; break; case AccessLevel::FilePrivate: @@ -192,14 +188,14 @@ static bool isKnownFinalClass(ClassDecl *CD, SILModule &M, // - or internal and it is a WMO compilation // then this class can be considered final for the purpose // of devirtualization. - if (CHA) { - if (!CHA->hasKnownDirectSubclasses(CD)) { - switch (CD->getEffectiveAccess()) { + if (cha) { + if (!cha->hasKnownDirectSubclasses(cd)) { + switch (cd->getEffectiveAccess()) { case AccessLevel::Open: return false; case AccessLevel::Public: case AccessLevel::Internal: - if (!M.isWholeModule()) + if (!module.isWholeModule()) return false; break; case AccessLevel::FilePrivate: @@ -214,57 +210,56 @@ static bool isKnownFinalClass(ClassDecl *CD, SILModule &M, return false; } - // Attempt to get the instance for S, whose static type is the same as // its exact dynamic type, returning a null SILValue() if we cannot find it. // The information that a static type is the same as the exact dynamic, // can be derived e.g.: // - from a constructor or // - from a successful outcome of a checked_cast_br [exact] instruction. -SILValue swift::getInstanceWithExactDynamicType(SILValue S, - ClassHierarchyAnalysis *CHA) { - auto *F = S->getFunction(); - auto &M = F->getModule(); +SILValue swift::getInstanceWithExactDynamicType(SILValue instance, + ClassHierarchyAnalysis *cha) { + auto *f = instance->getFunction(); + auto &module = f->getModule(); - while (S) { - S = stripCasts(S); + while (instance) { + instance = stripCasts(instance); - if (isa(S) || isa(S)) { - if (S->getType().getASTType()->hasDynamicSelfType()) + if (isa(instance) || isa(instance)) { + if (instance->getType().getASTType()->hasDynamicSelfType()) return SILValue(); - return S; + return instance; } - auto *Arg = dyn_cast(S); - if (!Arg) + auto *arg = dyn_cast(instance); + if (!arg) break; - auto *SinglePred = Arg->getParent()->getSinglePredecessorBlock(); - if (!SinglePred) { - if (!isa(Arg)) + auto *singlePred = arg->getParent()->getSinglePredecessorBlock(); + if (!singlePred) { + if (!isa(arg)) break; - auto *CD = Arg->getType().getClassOrBoundGenericClass(); + auto *cd = arg->getType().getClassOrBoundGenericClass(); // Check if this class is effectively final. - if (!CD || !isKnownFinalClass(CD, M, CHA)) + if (!cd || !isKnownFinalClass(cd, module, cha)) break; - return Arg; + return arg; } // Traverse the chain of predecessors. - if (isa(SinglePred->getTerminator()) || - isa(SinglePred->getTerminator())) { - S = cast(Arg)->getIncomingPhiValue(SinglePred); + if (isa(singlePred->getTerminator()) + || isa(singlePred->getTerminator())) { + instance = cast(arg)->getIncomingPhiValue(singlePred); continue; } // If it is a BB argument received on a success branch // of a checked_cast_br, then we know its exact type. - auto *CCBI = dyn_cast(SinglePred->getTerminator()); - if (!CCBI) + auto *ccbi = dyn_cast(singlePred->getTerminator()); + if (!ccbi) break; - if (!CCBI->isExact() || CCBI->getSuccessBB() != Arg->getParent()) + if (!ccbi->isExact() || ccbi->getSuccessBB() != arg->getParent()) break; - return S; + return instance; } return SILValue(); @@ -273,117 +268,117 @@ SILValue swift::getInstanceWithExactDynamicType(SILValue S, /// Try to determine the exact dynamic type of an object. /// returns the exact dynamic type of the object, or an empty type if the exact /// type could not be determined. -SILType swift::getExactDynamicType(SILValue S, - ClassHierarchyAnalysis *CHA, - bool ForUnderlyingObject) { - auto *F = S->getFunction(); - auto &M = F->getModule(); +SILType swift::getExactDynamicType(SILValue instance, + ClassHierarchyAnalysis *cha, + bool forUnderlyingObject) { + auto *f = instance->getFunction(); + auto &module = f->getModule(); // Set of values to be checked for their exact types. - SmallVector WorkList; + SmallVector worklist; // The detected type of the underlying object. - SILType ResultType; + SILType resultType; // Set of processed values. - llvm::SmallSet Processed; - WorkList.push_back(S); + llvm::SmallSet processed; + worklist.push_back(instance); - while (!WorkList.empty()) { - auto V = WorkList.pop_back_val(); - if (!V) + while (!worklist.empty()) { + auto v = worklist.pop_back_val(); + if (!v) return SILType(); - if (Processed.count(V)) + if (processed.count(v)) continue; - Processed.insert(V); + processed.insert(v); // For underlying object strip casts and projections. // For the object itself, simply strip casts. - V = ForUnderlyingObject ? getUnderlyingObject(V) : stripCasts(V); + v = forUnderlyingObject ? getUnderlyingObject(v) : stripCasts(v); - if (isa(V) || isa(V)) { - if (ResultType && ResultType != V->getType()) + if (isa(v) || isa(v)) { + if (resultType && resultType != v->getType()) return SILType(); - ResultType = V->getType(); + resultType = v->getType(); continue; } - if (isa(V)) { - if (ResultType && ResultType != V->getType()) + if (isa(v)) { + if (resultType && resultType != v->getType()) return SILType(); - ResultType = V->getType(); + resultType = v->getType(); continue; } - if (isa(V) || isa(V) || isa(V)) { - if (ResultType && ResultType != V->getType()) + if (isa(v) || isa(v) || isa(v)) { + if (resultType && resultType != v->getType()) return SILType(); - ResultType = V->getType(); + resultType = v->getType(); continue; } - if (ForUnderlyingObject) { - if (isa(V)) { - if (ResultType && ResultType != V->getType()) + if (forUnderlyingObject) { + if (isa(v)) { + if (resultType && resultType != v->getType()) return SILType(); - ResultType = V->getType(); + resultType = v->getType(); continue; } } - auto Arg = dyn_cast(V); - if (!Arg) { + auto arg = dyn_cast(v); + if (!arg) { // We don't know what it is. return SILType(); } - if (auto *FArg = dyn_cast(Arg)) { + if (auto *fArg = dyn_cast(arg)) { // Bail on metatypes for now. - if (FArg->getType().is()) { + if (fArg->getType().is()) { return SILType(); } - auto *CD = FArg->getType().getClassOrBoundGenericClass(); + auto *cd = fArg->getType().getClassOrBoundGenericClass(); // If it is not class and it is a trivial type, then it // should be the exact type. - if (!CD && FArg->getType().isTrivial(*F)) { - if (ResultType && ResultType != FArg->getType()) + if (!cd && fArg->getType().isTrivial(*f)) { + if (resultType && resultType != fArg->getType()) return SILType(); - ResultType = FArg->getType(); + resultType = fArg->getType(); continue; } - if (!CD) { + if (!cd) { // It is not a class or a trivial type, so we don't know what it is. return SILType(); } // Check if this class is effectively final. - if (!isKnownFinalClass(CD, M, CHA)) { + if (!isKnownFinalClass(cd, module, cha)) { return SILType(); } - if (ResultType && ResultType != FArg->getType()) + if (resultType && resultType != fArg->getType()) return SILType(); - ResultType = FArg->getType(); + resultType = fArg->getType(); continue; } - auto *SinglePred = Arg->getParent()->getSinglePredecessorBlock(); - if (SinglePred) { + auto *singlePred = arg->getParent()->getSinglePredecessorBlock(); + if (singlePred) { // If it is a BB argument received on a success branch // of a checked_cast_br, then we know its exact type. - auto *CCBI = dyn_cast(SinglePred->getTerminator()); - if (CCBI && CCBI->isExact() && CCBI->getSuccessBB() == Arg->getParent()) { - if (ResultType && ResultType != Arg->getType()) + auto *ccbi = dyn_cast(singlePred->getTerminator()); + if (ccbi && ccbi->isExact() && ccbi->getSuccessBB() == arg->getParent()) { + if (resultType && resultType != arg->getType()) return SILType(); - ResultType = Arg->getType(); + resultType = arg->getType(); continue; } } // It is a BB argument, look through incoming values. If they all have the // same exact type, then we consider it to be the type of the BB argument. - SmallVector IncomingValues; - if (Arg->getSingleTerminatorOperands(IncomingValues)) { - for (auto InValue : IncomingValues) { - WorkList.push_back(InValue); + SmallVector incomingValues; + if (arg->getSingleTerminatorOperands(incomingValues)) { + for (auto inValue : incomingValues) { + worklist.push_back(inValue); } continue; } @@ -392,27 +387,24 @@ SILType swift::getExactDynamicType(SILValue S, return SILType(); } - return ResultType; + return resultType; } - /// Try to determine the exact dynamic type of the underlying object. /// returns the exact dynamic type of a value, or an empty type if the exact /// type could not be determined. SILType -swift::getExactDynamicTypeOfUnderlyingObject(SILValue S, - ClassHierarchyAnalysis *CHA) { - return getExactDynamicType(S, CHA, /* ForUnderlyingObject */ true); +swift::getExactDynamicTypeOfUnderlyingObject(SILValue instance, + ClassHierarchyAnalysis *cha) { + return getExactDynamicType(instance, cha, /* forUnderlyingObject */ true); } // Start with the substitutions from the apply. // Try to propagate them to find out the real substitutions required // to invoke the method. static SubstitutionMap -getSubstitutionsForCallee(SILModule &M, - CanSILFunctionType baseCalleeType, - CanType derivedSelfType, - FullApplySite AI) { +getSubstitutionsForCallee(SILModule &module, CanSILFunctionType baseCalleeType, + CanType derivedSelfType, FullApplySite applySite) { // If the base method is not polymorphic, no substitutions are required, // even if we originally had substitutions for calling the derived method. @@ -439,12 +431,13 @@ getSubstitutionsForCallee(SILModule &M, if (auto metatypeType = derivedClass->getAs()) derivedClass = metatypeType->getInstanceType(); baseSubMap = derivedClass->getContextSubstitutionMap( - M.getSwiftModule(), baseClassDecl); + module.getSwiftModule(), baseClassDecl); } - SubstitutionMap origSubMap = AI.getSubstitutionMap(); + SubstitutionMap origSubMap = applySite.getSubstitutionMap(); - Type calleeSelfType = AI.getOrigCalleeType()->getSelfParameter().getType(); + Type calleeSelfType = + applySite.getOrigCalleeType()->getSelfParameter().getType(); if (auto metatypeType = calleeSelfType->getAs()) calleeSelfType = metatypeType->getInstanceType(); auto *calleeClassDecl = calleeSelfType->getClassOrBoundGenericClass(); @@ -467,264 +460,260 @@ getSubstitutionsForCallee(SILModule &M, baseCalleeSig); } -static ApplyInst *replaceApplyInst(SILBuilder &B, SILLocation Loc, - ApplyInst *OldAI, - SILValue NewFn, - SubstitutionMap NewSubs, - ArrayRef NewArgs, - ArrayRef NewArgBorrows) { - auto *NewAI = B.createApply(Loc, NewFn, NewSubs, NewArgs, - OldAI->isNonThrowing()); +static ApplyInst *replaceApplyInst(SILBuilder &builder, SILLocation loc, + ApplyInst *oldAI, SILValue newFn, + SubstitutionMap newSubs, + ArrayRef newArgs, + ArrayRef newArgBorrows) { + auto *newAI = + builder.createApply(loc, newFn, newSubs, newArgs, oldAI->isNonThrowing()); - if (!NewArgBorrows.empty()) { - for (SILValue Arg : NewArgBorrows) { - B.createEndBorrow(Loc, Arg); + if (!newArgBorrows.empty()) { + for (SILValue arg : newArgBorrows) { + builder.createEndBorrow(loc, arg); } } // Check if any casting is required for the return value. - SILValue ResultValue = - castValueToABICompatibleType(&B, Loc, NewAI, NewAI->getType(), - OldAI->getType()); + SILValue resultValue = castValueToABICompatibleType( + &builder, loc, newAI, newAI->getType(), oldAI->getType()); - OldAI->replaceAllUsesWith(ResultValue); - return NewAI; + oldAI->replaceAllUsesWith(resultValue); + return newAI; } -static TryApplyInst *replaceTryApplyInst(SILBuilder &B, SILLocation Loc, - TryApplyInst *OldTAI, SILValue NewFn, - SubstitutionMap NewSubs, - ArrayRef NewArgs, - SILFunctionConventions Conv, - ArrayRef NewArgBorrows) { - SILBasicBlock *NormalBB = OldTAI->getNormalBB(); - SILBasicBlock *ResultBB = nullptr; +static TryApplyInst *replaceTryApplyInst(SILBuilder &builder, SILLocation loc, + TryApplyInst *oldTAI, SILValue newFn, + SubstitutionMap newSubs, + ArrayRef newArgs, + SILFunctionConventions conv, + ArrayRef newArgBorrows) { + SILBasicBlock *normalBB = oldTAI->getNormalBB(); + SILBasicBlock *resultBB = nullptr; - SILType NewResultTy = Conv.getSILResultType(); + SILType newResultTy = conv.getSILResultType(); // Does the result value need to be casted? - auto OldResultTy = NormalBB->getArgument(0)->getType(); - bool ResultCastRequired = NewResultTy != OldResultTy; + auto oldResultTy = normalBB->getArgument(0)->getType(); + bool resultCastRequired = newResultTy != oldResultTy; // Create a new normal BB only if the result of the new apply differs // in type from the argument of the original normal BB. - if (!ResultCastRequired) { - ResultBB = NormalBB; + if (!resultCastRequired) { + resultBB = normalBB; } else { - ResultBB = B.getFunction().createBasicBlockBefore(NormalBB); - ResultBB->createPhiArgument(NewResultTy, ValueOwnershipKind::Owned); + resultBB = builder.getFunction().createBasicBlockBefore(normalBB); + resultBB->createPhiArgument(newResultTy, ValueOwnershipKind::Owned); } // We can always just use the original error BB because we'll be // deleting the edge to it from the old TAI. - SILBasicBlock *ErrorBB = OldTAI->getErrorBB(); + SILBasicBlock *errorBB = oldTAI->getErrorBB(); // Insert a try_apply here. // Note that this makes this block temporarily double-terminated! // We won't fix that until deleteDevirtualizedApply. - auto NewTAI = B.createTryApply(Loc, NewFn, NewSubs, NewArgs, - ResultBB, ErrorBB); + auto newTAI = + builder.createTryApply(loc, newFn, newSubs, newArgs, resultBB, errorBB); - if (!NewArgBorrows.empty()) { - B.setInsertionPoint(NormalBB->begin()); - for (SILValue Arg : NewArgBorrows) { - B.createEndBorrow(Loc, Arg); + if (!newArgBorrows.empty()) { + builder.setInsertionPoint(normalBB->begin()); + for (SILValue arg : newArgBorrows) { + builder.createEndBorrow(loc, arg); } - B.setInsertionPoint(ErrorBB->begin()); - for (SILValue Arg : NewArgBorrows) { - B.createEndBorrow(Loc, Arg); + builder.setInsertionPoint(errorBB->begin()); + for (SILValue arg : newArgBorrows) { + builder.createEndBorrow(loc, arg); } } - if (ResultCastRequired) { - B.setInsertionPoint(ResultBB); + if (resultCastRequired) { + builder.setInsertionPoint(resultBB); - SILValue ResultValue = ResultBB->getArgument(0); - ResultValue = castValueToABICompatibleType(&B, Loc, ResultValue, - NewResultTy, OldResultTy); - B.createBranch(Loc, NormalBB, { ResultValue }); + SILValue resultValue = resultBB->getArgument(0); + resultValue = castValueToABICompatibleType(&builder, loc, resultValue, + newResultTy, oldResultTy); + builder.createBranch(loc, normalBB, {resultValue}); } - B.setInsertionPoint(NormalBB->begin()); - return NewTAI; + builder.setInsertionPoint(normalBB->begin()); + return newTAI; } -static BeginApplyInst *replaceBeginApplyInst(SILBuilder &B, SILLocation Loc, - BeginApplyInst *OldBAI, - SILValue NewFn, - SubstitutionMap NewSubs, - ArrayRef NewArgs, - ArrayRef NewArgBorrows) { - auto *NewBAI = - B.createBeginApply(Loc, NewFn, NewSubs, NewArgs, OldBAI->isNonThrowing()); +static BeginApplyInst * +replaceBeginApplyInst(SILBuilder &builder, SILLocation loc, + BeginApplyInst *oldBAI, SILValue newFn, + SubstitutionMap newSubs, ArrayRef newArgs, + ArrayRef newArgBorrows) { + auto *newBAI = builder.createBeginApply(loc, newFn, newSubs, newArgs, + oldBAI->isNonThrowing()); // Forward the token. - OldBAI->getTokenResult()->replaceAllUsesWith(NewBAI->getTokenResult()); + oldBAI->getTokenResult()->replaceAllUsesWith(newBAI->getTokenResult()); - auto OldYields = OldBAI->getYieldedValues(); - auto NewYields = NewBAI->getYieldedValues(); - assert(OldYields.size() == NewYields.size()); + auto oldYields = oldBAI->getYieldedValues(); + auto newYields = newBAI->getYieldedValues(); + assert(oldYields.size() == newYields.size()); - for (auto i : indices(OldYields)) { - auto OldYield = OldYields[i]; - auto NewYield = NewYields[i]; - NewYield = castValueToABICompatibleType(&B, Loc, NewYield, - NewYield->getType(), - OldYield->getType()); - OldYield->replaceAllUsesWith(NewYield); + for (auto i : indices(oldYields)) { + auto oldYield = oldYields[i]; + auto newYield = newYields[i]; + newYield = castValueToABICompatibleType( + &builder, loc, newYield, newYield->getType(), oldYield->getType()); + oldYield->replaceAllUsesWith(newYield); } - if (NewArgBorrows.empty()) - return NewBAI; + if (newArgBorrows.empty()) + return newBAI; - SILValue token = NewBAI->getTokenResult(); + SILValue token = newBAI->getTokenResult(); // The token will only be used by end_apply and abort_apply. Use that to // insert the end_borrows we need. for (auto *use : token->getUses()) { - SILBuilderWithScope builder(use->getUser(), B.getBuilderContext()); - for (SILValue borrow : NewArgBorrows) { - builder.createEndBorrow(Loc, borrow); + SILBuilderWithScope borrowBuilder(use->getUser(), + builder.getBuilderContext()); + for (SILValue borrow : newArgBorrows) { + borrowBuilder.createEndBorrow(loc, borrow); } } - return NewBAI; + return newBAI; } -static PartialApplyInst *replacePartialApplyInst(SILBuilder &B, SILLocation Loc, - PartialApplyInst *OldPAI, - SILValue NewFn, - SubstitutionMap NewSubs, - ArrayRef NewArgs) { - auto Convention = - OldPAI->getType().getAs()->getCalleeConvention(); - auto *NewPAI = B.createPartialApply(Loc, NewFn, NewSubs, NewArgs, - Convention); +static PartialApplyInst * +replacePartialApplyInst(SILBuilder &builder, SILLocation loc, + PartialApplyInst *oldPAI, SILValue newFn, + SubstitutionMap newSubs, ArrayRef newArgs) { + auto convention = + oldPAI->getType().getAs()->getCalleeConvention(); + auto *newPAI = + builder.createPartialApply(loc, newFn, newSubs, newArgs, convention); // Check if any casting is required for the partially-applied function. - SILValue ResultValue = castValueToABICompatibleType( - &B, Loc, NewPAI, NewPAI->getType(), OldPAI->getType()); - OldPAI->replaceAllUsesWith(ResultValue); + SILValue resultValue = castValueToABICompatibleType( + &builder, loc, newPAI, newPAI->getType(), oldPAI->getType()); + oldPAI->replaceAllUsesWith(resultValue); - return NewPAI; + return newPAI; } -static ApplySite replaceApplySite(SILBuilder &B, SILLocation Loc, - ApplySite OldAS, SILValue NewFn, - SubstitutionMap NewSubs, - ArrayRef NewArgs, - SILFunctionConventions Conv, - ArrayRef NewArgBorrows) { - switch (OldAS.getKind()) { +static ApplySite replaceApplySite(SILBuilder &builder, SILLocation loc, + ApplySite oldAS, SILValue newFn, + SubstitutionMap newSubs, + ArrayRef newArgs, + SILFunctionConventions conv, + ArrayRef newArgBorrows) { + switch (oldAS.getKind()) { case ApplySiteKind::ApplyInst: { - auto *OldAI = cast(OldAS); - return replaceApplyInst(B, Loc, OldAI, NewFn, NewSubs, NewArgs, NewArgBorrows); + auto *oldAI = cast(oldAS); + return replaceApplyInst(builder, loc, oldAI, newFn, newSubs, newArgs, + newArgBorrows); } case ApplySiteKind::TryApplyInst: { - auto *OldTAI = cast(OldAS); - return replaceTryApplyInst(B, Loc, OldTAI, NewFn, NewSubs, NewArgs, Conv, - NewArgBorrows); + auto *oldTAI = cast(oldAS); + return replaceTryApplyInst(builder, loc, oldTAI, newFn, newSubs, newArgs, + conv, newArgBorrows); } case ApplySiteKind::BeginApplyInst: { - auto *OldBAI = dyn_cast(OldAS); - return replaceBeginApplyInst(B, Loc, OldBAI, NewFn, NewSubs, NewArgs, - NewArgBorrows); + auto *oldBAI = dyn_cast(oldAS); + return replaceBeginApplyInst(builder, loc, oldBAI, newFn, newSubs, newArgs, + newArgBorrows); } case ApplySiteKind::PartialApplyInst: { - assert(NewArgBorrows.empty()); - auto *OldPAI = cast(OldAS); - return replacePartialApplyInst(B, Loc, OldPAI, NewFn, NewSubs, NewArgs); + assert(newArgBorrows.empty()); + auto *oldPAI = cast(oldAS); + return replacePartialApplyInst(builder, loc, oldPAI, newFn, newSubs, + newArgs); } } llvm_unreachable("covered switch"); } /// Delete an apply site that's been successfully devirtualized. -void swift::deleteDevirtualizedApply(ApplySite Old) { - auto *OldApply = Old.getInstruction(); - recursivelyDeleteTriviallyDeadInstructions(OldApply, true); +void swift::deleteDevirtualizedApply(ApplySite old) { + auto *oldApply = old.getInstruction(); + recursivelyDeleteTriviallyDeadInstructions(oldApply, true); } -SILFunction *swift::getTargetClassMethod(SILModule &M, - ClassDecl *CD, - MethodInst *MI) { - assert((isa(MI) || isa(MI)) && - "Only class_method and super_method instructions are supported"); +SILFunction *swift::getTargetClassMethod(SILModule &module, ClassDecl *cd, + MethodInst *mi) { + assert((isa(mi) || isa(mi)) + && "Only class_method and super_method instructions are supported"); - SILDeclRef Member = MI->getMember(); - return M.lookUpFunctionInVTable(CD, Member); + SILDeclRef member = mi->getMember(); + return module.lookUpFunctionInVTable(cd, member); } -CanType swift::getSelfInstanceType(CanType ClassOrMetatypeType) { - if (auto MetaType = dyn_cast(ClassOrMetatypeType)) - ClassOrMetatypeType = MetaType.getInstanceType(); +CanType swift::getSelfInstanceType(CanType classOrMetatypeType) { + if (auto metaType = dyn_cast(classOrMetatypeType)) + classOrMetatypeType = metaType.getInstanceType(); - if (auto SelfType = dyn_cast(ClassOrMetatypeType)) - ClassOrMetatypeType = SelfType.getSelfType(); - - return ClassOrMetatypeType; + if (auto selfType = dyn_cast(classOrMetatypeType)) + classOrMetatypeType = selfType.getSelfType(); + + return classOrMetatypeType; } /// Check if it is possible to devirtualize an Apply instruction /// and a class member obtained using the class_method instruction into /// a direct call to a specific member of a specific class. /// -/// \p AI is the apply to devirtualize. -/// \p CD is the class declaration we are devirtualizing for. +/// \p applySite is the apply to devirtualize. +/// \p cd is the class declaration we are devirtualizing for. /// return true if it is possible to devirtualize, false - otherwise. -bool swift::canDevirtualizeClassMethod(FullApplySite AI, - ClassDecl *CD, - OptRemark::Emitter *ORE, +bool swift::canDevirtualizeClassMethod(FullApplySite applySite, ClassDecl *cd, + OptRemark::Emitter *ore, bool isEffectivelyFinalMethod) { LLVM_DEBUG(llvm::dbgs() << " Trying to devirtualize : " - << *AI.getInstruction()); + << *applySite.getInstruction()); - SILModule &Mod = AI.getModule(); + SILModule &module = applySite.getModule(); - auto *MI = cast(AI.getCallee()); + auto *mi = cast(applySite.getCallee()); // Find the implementation of the member which should be invoked. - auto *F = getTargetClassMethod(Mod, CD, MI); + auto *f = getTargetClassMethod(module, cd, mi); // If we do not find any such function, we have no function to devirtualize // to... so bail. - if (!F) { + if (!f) { LLVM_DEBUG(llvm::dbgs() << " FAIL: Could not find matching VTable " "or vtable method for this class.\n"); return false; } // We need to disable the “effectively final” opt if a function is inlinable - if (isEffectivelyFinalMethod && AI.getFunction()->isSerialized()) { + if (isEffectivelyFinalMethod && applySite.getFunction()->isSerialized()) { LLVM_DEBUG(llvm::dbgs() << " FAIL: Could not optimize function " "because it is an effectively-final inlinable: " - << AI.getFunction()->getName() << "\n"); + << applySite.getFunction()->getName() << "\n"); return false; } // Mandatory inlining does class method devirtualization. I'm not sure if this // is really needed, but some test rely on this. // So even for Onone functions we have to do it if the SILStage is raw. - if (F->getModule().getStage() != SILStage::Raw && !F->shouldOptimize()) { + if (f->getModule().getStage() != SILStage::Raw && !f->shouldOptimize()) { // Do not consider functions that should not be optimized. - LLVM_DEBUG(llvm::dbgs() << " FAIL: Could not optimize function " - << " because it is marked no-opt: " << F->getName() - << "\n"); + LLVM_DEBUG(llvm::dbgs() + << " FAIL: Could not optimize function " + << " because it is marked no-opt: " << f->getName() << "\n"); return false; } - if (AI.getFunction()->isSerialized()) { + if (applySite.getFunction()->isSerialized()) { // function_ref inside fragile function cannot reference a private or // hidden symbol. - if (!F->hasValidLinkageForFragileRef()) + if (!f->hasValidLinkageForFragileRef()) return false; } // devirtualizeClassMethod below does not support this case. It currently // assumes it can try_apply call the target. - if (!F->getLoweredFunctionType()->hasErrorResult() && - isa(AI.getInstruction())) { + if (!f->getLoweredFunctionType()->hasErrorResult() + && isa(applySite.getInstruction())) { LLVM_DEBUG(llvm::dbgs() << " FAIL: Trying to devirtualize a " "try_apply but vtable entry has no error result.\n"); return false; @@ -735,102 +724,100 @@ bool swift::canDevirtualizeClassMethod(FullApplySite AI, /// Devirtualize an apply of a class method. /// -/// \p AI is the apply to devirtualize. +/// \p applySite is the apply to devirtualize. /// \p ClassOrMetatype is a class value or metatype value that is the /// self argument of the apply we will devirtualize. /// return the result value of the new ApplyInst if created one or null. -FullApplySite swift::devirtualizeClassMethod(FullApplySite AI, - SILValue ClassOrMetatype, - ClassDecl *CD, - OptRemark::Emitter *ORE) { +FullApplySite swift::devirtualizeClassMethod(FullApplySite applySite, + SILValue classOrMetatype, + ClassDecl *cd, + OptRemark::Emitter *ore) { LLVM_DEBUG(llvm::dbgs() << " Trying to devirtualize : " - << *AI.getInstruction()); + << *applySite.getInstruction()); - SILModule &Mod = AI.getModule(); - auto *MI = cast(AI.getCallee()); + SILModule &module = applySite.getModule(); + auto *mi = cast(applySite.getCallee()); - auto *F = getTargetClassMethod(Mod, CD, MI); + auto *f = getTargetClassMethod(module, cd, mi); - CanSILFunctionType GenCalleeType = F->getLoweredFunctionType(); + CanSILFunctionType genCalleeType = f->getLoweredFunctionType(); - SubstitutionMap Subs = - getSubstitutionsForCallee(Mod, GenCalleeType, - ClassOrMetatype->getType().getASTType(), - AI); - CanSILFunctionType SubstCalleeType = GenCalleeType; - if (GenCalleeType->isPolymorphic()) - SubstCalleeType = GenCalleeType->substGenericArgs(Mod, Subs); - SILFunctionConventions substConv(SubstCalleeType, Mod); + SubstitutionMap subs = getSubstitutionsForCallee( + module, genCalleeType, classOrMetatype->getType().getASTType(), + applySite); + CanSILFunctionType substCalleeType = genCalleeType; + if (genCalleeType->isPolymorphic()) + substCalleeType = genCalleeType->substGenericArgs(module, subs); + SILFunctionConventions substConv(substCalleeType, module); - SILBuilderWithScope B(AI.getInstruction()); - SILLocation Loc = AI.getLoc(); - auto *FRI = B.createFunctionRefFor(Loc, F); + SILBuilderWithScope builder(applySite.getInstruction()); + SILLocation loc = applySite.getLoc(); + auto *fri = builder.createFunctionRefFor(loc, f); // Create the argument list for the new apply, casting when needed // in order to handle covariant indirect return types and // contravariant argument types. - SmallVector NewArgs; + SmallVector newArgs; // If we have a value that is owned, but that we are going to use in as a // guaranteed argument, we need to borrow/unborrow the argument. Otherwise, we // will introduce new consuming uses. In contrast, if we have an owned value, // we are ok due to the forwarding nature of upcasts. - SmallVector NewArgBorrows; + SmallVector newArgBorrows; - auto IndirectResultArgIter = AI.getIndirectSILResults().begin(); - for (auto ResultTy : substConv.getIndirectSILResultTypes()) { - NewArgs.push_back( - castValueToABICompatibleType(&B, Loc, *IndirectResultArgIter, - IndirectResultArgIter->getType(), ResultTy)); - ++IndirectResultArgIter; + auto indirectResultArgIter = applySite.getIndirectSILResults().begin(); + for (auto resultTy : substConv.getIndirectSILResultTypes()) { + newArgs.push_back(castValueToABICompatibleType( + &builder, loc, *indirectResultArgIter, indirectResultArgIter->getType(), + resultTy)); + ++indirectResultArgIter; } - auto ParamArgIter = AI.getArgumentsWithoutIndirectResults().begin(); + auto paramArgIter = applySite.getArgumentsWithoutIndirectResults().begin(); // Skip the last parameter, which is `self`. Add it below. for (auto param : substConv.getParameters()) { auto paramType = substConv.getSILType(param); - SILValue arg = *ParamArgIter; - if (B.hasOwnership() - && arg->getType().isObject() + SILValue arg = *paramArgIter; + if (builder.hasOwnership() && arg->getType().isObject() && arg.getOwnershipKind() == ValueOwnershipKind::Owned && param.isGuaranteed()) { - SILBuilderWithScope builder(AI.getInstruction(), B); - arg = builder.createBeginBorrow(Loc, arg); - NewArgBorrows.push_back(arg); + SILBuilderWithScope borrowBuilder(applySite.getInstruction(), builder); + arg = borrowBuilder.createBeginBorrow(loc, arg); + newArgBorrows.push_back(arg); } - arg = castValueToABICompatibleType(&B, Loc, arg, ParamArgIter->getType(), - paramType); - NewArgs.push_back(arg); - ++ParamArgIter; + arg = castValueToABICompatibleType(&builder, loc, arg, + paramArgIter->getType(), paramType); + newArgs.push_back(arg); + ++paramArgIter; } - ApplySite NewAS = replaceApplySite(B, Loc, AI, FRI, Subs, NewArgs, substConv, - NewArgBorrows); - FullApplySite NewAI = FullApplySite::isa(NewAS.getInstruction()); - assert(NewAI); + ApplySite newAS = replaceApplySite(builder, loc, applySite, fri, subs, + newArgs, substConv, newArgBorrows); + FullApplySite newAI = FullApplySite::isa(newAS.getInstruction()); + assert(newAI); - LLVM_DEBUG(llvm::dbgs() << " SUCCESS: " << F->getName() << "\n"); - if (ORE) - ORE->emit([&]() { - using namespace OptRemark; - return RemarkPassed("ClassMethodDevirtualized", *AI.getInstruction()) - << "Devirtualized call to class method " << NV("Method", F); - }); + LLVM_DEBUG(llvm::dbgs() << " SUCCESS: " << f->getName() << "\n"); + if (ore) + ore->emit([&]() { + using namespace OptRemark; + return RemarkPassed("ClassMethodDevirtualized", + *applySite.getInstruction()) + << "Devirtualized call to class method " << NV("Method", f); + }); NumClassDevirt++; - return NewAI; + return newAI; } -FullApplySite -swift::tryDevirtualizeClassMethod(FullApplySite AI, SILValue ClassInstance, - ClassDecl *CD, - OptRemark::Emitter *ORE, - bool isEffectivelyFinalMethod) { - if (!canDevirtualizeClassMethod(AI, CD, ORE, isEffectivelyFinalMethod)) +FullApplySite swift::tryDevirtualizeClassMethod(FullApplySite applySite, + SILValue classInstance, + ClassDecl *cd, + OptRemark::Emitter *ore, + bool isEffectivelyFinalMethod) { + if (!canDevirtualizeClassMethod(applySite, cd, ore, isEffectivelyFinalMethod)) return FullApplySite(); - return devirtualizeClassMethod(AI, ClassInstance, CD, ORE); + return devirtualizeClassMethod(applySite, classInstance, cd, ore); } - //===----------------------------------------------------------------------===// // Witness Method Optimization //===----------------------------------------------------------------------===// @@ -944,24 +931,24 @@ getWitnessMethodSubstitutions( } SubstitutionMap -swift::getWitnessMethodSubstitutions(SILModule &Module, ApplySite AI, - SILFunction *F, - ProtocolConformanceRef CRef) { - auto witnessFnTy = F->getLoweredFunctionType(); +swift::getWitnessMethodSubstitutions(SILModule &module, ApplySite applySite, + SILFunction *f, + ProtocolConformanceRef cRef) { + auto witnessFnTy = f->getLoweredFunctionType(); assert(witnessFnTy->getRepresentation() == SILFunctionTypeRepresentation::WitnessMethod); - auto requirementSig = AI.getOrigCalleeType()->getGenericSignature(); + auto requirementSig = applySite.getOrigCalleeType()->getGenericSignature(); auto witnessThunkSig = witnessFnTy->getGenericSignature(); - SubstitutionMap origSubs = AI.getSubstitutionMap(); + SubstitutionMap origSubs = applySite.getSubstitutionMap(); - auto *mod = Module.getSwiftModule(); + auto *mod = module.getSwiftModule(); bool isSelfAbstract = witnessFnTy->getSelfInstanceType()->is(); auto *classWitness = witnessFnTy->getWitnessMethodClass(); - return ::getWitnessMethodSubstitutions(mod, CRef, requirementSig, + return ::getWitnessMethodSubstitutions(mod, cRef, requirementSig, witnessThunkSig, origSubs, isSelfAbstract, classWitness); } @@ -969,97 +956,99 @@ swift::getWitnessMethodSubstitutions(SILModule &Module, ApplySite AI, /// Generate a new apply of a function_ref to replace an apply of a /// witness_method when we've determined the actual function we'll end /// up calling. -static ApplySite -devirtualizeWitnessMethod(ApplySite AI, SILFunction *F, - ProtocolConformanceRef C, OptRemark::Emitter *ORE) { +static ApplySite devirtualizeWitnessMethod(ApplySite applySite, SILFunction *f, + ProtocolConformanceRef cRef, + OptRemark::Emitter *ore) { // We know the witness thunk and the corresponding set of substitutions // required to invoke the protocol method at this point. - auto &Module = AI.getModule(); + auto &module = applySite.getModule(); // Collect all the required substitutions. // // The complete set of substitutions may be different, e.g. because the found - // witness thunk F may have been created by a specialization pass and have + // witness thunk f may have been created by a specialization pass and have // additional generic parameters. - auto SubMap = getWitnessMethodSubstitutions(Module, AI, F, C); + auto subMap = getWitnessMethodSubstitutions(module, applySite, f, cRef); // Figure out the exact bound type of the function to be called by // applying all substitutions. - auto CalleeCanType = F->getLoweredFunctionType(); - auto SubstCalleeCanType = CalleeCanType->substGenericArgs(Module, SubMap); + auto calleeCanType = f->getLoweredFunctionType(); + auto substCalleeCanType = calleeCanType->substGenericArgs(module, subMap); // Collect arguments from the apply instruction. - SmallVector Arguments; - SmallVector BorrowedArgs; + SmallVector arguments; + SmallVector borrowedArgs; // Iterate over the non self arguments and add them to the // new argument list, upcasting when required. - SILBuilderWithScope B(AI.getInstruction()); - SILFunctionConventions substConv(SubstCalleeCanType, Module); - unsigned substArgIdx = AI.getCalleeArgIndexOfFirstAppliedArg(); - for (auto arg : AI.getArguments()) { + SILBuilderWithScope argBuilder(applySite.getInstruction()); + SILFunctionConventions substConv(substCalleeCanType, module); + unsigned substArgIdx = applySite.getCalleeArgIndexOfFirstAppliedArg(); + for (auto arg : applySite.getArguments()) { auto paramInfo = substConv.getSILArgumentConvention(substArgIdx); auto paramType = substConv.getSILArgumentType(substArgIdx++); if (arg->getType() != paramType) { - if (B.hasOwnership() - && AI.getKind() != ApplySiteKind::PartialApplyInst + if (argBuilder.hasOwnership() + && applySite.getKind() != ApplySiteKind::PartialApplyInst && arg->getType().isObject() && arg.getOwnershipKind() == ValueOwnershipKind::Owned && paramInfo.isGuaranteedConvention()) { - SILBuilderWithScope builder(AI.getInstruction(), B); - arg = builder.createBeginBorrow(AI.getLoc(), arg); - BorrowedArgs.push_back(arg); + SILBuilderWithScope borrowBuilder(applySite.getInstruction(), + argBuilder); + arg = borrowBuilder.createBeginBorrow(applySite.getLoc(), arg); + borrowedArgs.push_back(arg); } - arg = castValueToABICompatibleType(&B, AI.getLoc(), arg, + arg = castValueToABICompatibleType(&argBuilder, applySite.getLoc(), arg, arg->getType(), paramType); } - Arguments.push_back(arg); + arguments.push_back(arg); } assert(substArgIdx == substConv.getNumSILArguments()); // Replace old apply instruction by a new apply instruction that invokes // the witness thunk. - SILBuilderWithScope Builder(AI.getInstruction()); - SILLocation Loc = AI.getLoc(); - auto *FRI = Builder.createFunctionRefFor(Loc, F); + SILBuilderWithScope applyBuilder(applySite.getInstruction()); + SILLocation loc = applySite.getLoc(); + auto *fri = applyBuilder.createFunctionRefFor(loc, f); - ApplySite SAI = replaceApplySite(Builder, Loc, AI, FRI, SubMap, Arguments, - substConv, BorrowedArgs); + ApplySite newApplySite = + replaceApplySite(applyBuilder, loc, applySite, fri, subMap, arguments, + substConv, borrowedArgs); - if (ORE) - ORE->emit([&]() { - using namespace OptRemark; - return RemarkPassed("WitnessMethodDevirtualized", *AI.getInstruction()) - << "Devirtualized call to " << NV("Method", F); - }); + if (ore) + ore->emit([&]() { + using namespace OptRemark; + return RemarkPassed("WitnessMethodDevirtualized", + *applySite.getInstruction()) + << "Devirtualized call to " << NV("Method", f); + }); NumWitnessDevirt++; - return SAI; + return newApplySite; } -static bool canDevirtualizeWitnessMethod(ApplySite AI) { - SILFunction *F; - SILWitnessTable *WT; +static bool canDevirtualizeWitnessMethod(ApplySite applySite) { + SILFunction *f; + SILWitnessTable *wt; - auto *WMI = cast(AI.getCallee()); + auto *wmi = cast(applySite.getCallee()); - std::tie(F, WT) = - AI.getModule().lookUpFunctionInWitnessTable(WMI->getConformance(), - WMI->getMember()); + std::tie(f, wt) = applySite.getModule().lookUpFunctionInWitnessTable( + wmi->getConformance(), wmi->getMember()); - if (!F) + if (!f) return false; - if (AI.getFunction()->isSerialized()) { + if (applySite.getFunction()->isSerialized()) { // function_ref inside fragile function cannot reference a private or // hidden symbol. - if (!F->hasValidLinkageForFragileRef()) + if (!f->hasValidLinkageForFragileRef()) return false; } // devirtualizeWitnessMethod below does not support this case. It currently // assumes it can try_apply call the target. - if (!F->getLoweredFunctionType()->hasErrorResult() && - isa(AI.getInstruction())) { + if (!f->getLoweredFunctionType()->hasErrorResult() + && isa(applySite.getInstruction())) { LLVM_DEBUG(llvm::dbgs() << " FAIL: Trying to devirtualize a " "try_apply but wtable entry has no error result.\n"); return false; @@ -1071,21 +1060,20 @@ static bool canDevirtualizeWitnessMethod(ApplySite AI) { /// In the cases where we can statically determine the function that /// we'll call to, replace an apply of a witness_method with an apply /// of a function_ref, returning the new apply. -ApplySite -swift::tryDevirtualizeWitnessMethod(ApplySite AI, OptRemark::Emitter *ORE) { - if (!canDevirtualizeWitnessMethod(AI)) +ApplySite swift::tryDevirtualizeWitnessMethod(ApplySite applySite, + OptRemark::Emitter *ore) { + if (!canDevirtualizeWitnessMethod(applySite)) return ApplySite(); - SILFunction *F; - SILWitnessTable *WT; + SILFunction *f; + SILWitnessTable *wt; - auto *WMI = cast(AI.getCallee()); + auto *wmi = cast(applySite.getCallee()); - std::tie(F, WT) = - AI.getModule().lookUpFunctionInWitnessTable(WMI->getConformance(), - WMI->getMember()); + std::tie(f, wt) = applySite.getModule().lookUpFunctionInWitnessTable( + wmi->getConformance(), wmi->getMember()); - return devirtualizeWitnessMethod(AI, F, WMI->getConformance(), ORE); + return devirtualizeWitnessMethod(applySite, f, wmi->getConformance(), ore); } //===----------------------------------------------------------------------===// @@ -1094,23 +1082,23 @@ swift::tryDevirtualizeWitnessMethod(ApplySite AI, OptRemark::Emitter *ORE) { /// Attempt to devirtualize the given apply if possible, and return a /// new instruction in that case, or nullptr otherwise. -ApplySite swift::tryDevirtualizeApply(ApplySite AI, - ClassHierarchyAnalysis *CHA, - OptRemark::Emitter *ORE) { +ApplySite swift::tryDevirtualizeApply(ApplySite applySite, + ClassHierarchyAnalysis *cha, + OptRemark::Emitter *ore) { LLVM_DEBUG(llvm::dbgs() << " Trying to devirtualize: " - << *AI.getInstruction()); + << *applySite.getInstruction()); // Devirtualize apply instructions that call witness_method instructions: // // %8 = witness_method $Optional, #LogicValue.boolValue!getter.1 // %9 = apply %8(%6#1) : ... // - if (isa(AI.getCallee())) - return tryDevirtualizeWitnessMethod(AI, ORE); + if (isa(applySite.getCallee())) + return tryDevirtualizeWitnessMethod(applySite, ore); // TODO: check if we can also de-virtualize partial applies of class methods. - FullApplySite FAS = FullApplySite::isa(AI.getInstruction()); - if (!FAS) + FullApplySite fas = FullApplySite::isa(applySite.getInstruction()); + if (!fas) return ApplySite(); /// Optimize a class_method and alloc_ref pair into a direct function @@ -1129,48 +1117,49 @@ ApplySite swift::tryDevirtualizeApply(ApplySite AI, /// into /// /// %YY = function_ref @... - if (auto *CMI = dyn_cast(FAS.getCallee())) { - auto Instance = stripUpCasts(CMI->getOperand()); - auto ClassType = getSelfInstanceType(Instance->getType().getASTType()); - auto *CD = ClassType.getClassOrBoundGenericClass(); + if (auto *cmi = dyn_cast(fas.getCallee())) { + auto instance = stripUpCasts(cmi->getOperand()); + auto classType = getSelfInstanceType(instance->getType().getASTType()); + auto *cd = classType.getClassOrBoundGenericClass(); - if (isEffectivelyFinalMethod(FAS, ClassType, CD, CHA)) - return tryDevirtualizeClassMethod(FAS, Instance, CD, ORE, + if (isEffectivelyFinalMethod(fas, classType, cd, cha)) + return tryDevirtualizeClassMethod(fas, instance, cd, ore, true /*isEffectivelyFinalMethod*/); // Try to check if the exact dynamic type of the instance is statically // known. - if (auto Instance = getInstanceWithExactDynamicType(CMI->getOperand(), CHA)) - return tryDevirtualizeClassMethod(FAS, Instance, CD, ORE); + if (auto instance = getInstanceWithExactDynamicType(cmi->getOperand(), cha)) + return tryDevirtualizeClassMethod(fas, instance, cd, ore); - if (auto ExactTy = getExactDynamicType(CMI->getOperand(), CHA)) { - if (ExactTy == CMI->getOperand()->getType()) - return tryDevirtualizeClassMethod(FAS, CMI->getOperand(), CD, ORE); + if (auto exactTy = getExactDynamicType(cmi->getOperand(), cha)) { + if (exactTy == cmi->getOperand()->getType()) + return tryDevirtualizeClassMethod(fas, cmi->getOperand(), cd, ore); } } - if (isa(FAS.getCallee())) { - auto Instance = FAS.getArguments().back(); - auto ClassType = getSelfInstanceType(Instance->getType().getASTType()); - auto *CD = ClassType.getClassOrBoundGenericClass(); + if (isa(fas.getCallee())) { + auto instance = fas.getArguments().back(); + auto classType = getSelfInstanceType(instance->getType().getASTType()); + auto *cd = classType.getClassOrBoundGenericClass(); - return tryDevirtualizeClassMethod(FAS, Instance, CD, ORE); + return tryDevirtualizeClassMethod(fas, instance, cd, ore); } return ApplySite(); } -bool swift::canDevirtualizeApply(FullApplySite AI, ClassHierarchyAnalysis *CHA) { +bool swift::canDevirtualizeApply(FullApplySite applySite, + ClassHierarchyAnalysis *cha) { LLVM_DEBUG(llvm::dbgs() << " Trying to devirtualize: " - << *AI.getInstruction()); + << *applySite.getInstruction()); // Devirtualize apply instructions that call witness_method instructions: // // %8 = witness_method $Optional, #LogicValue.boolValue!getter.1 // %9 = apply %8(%6#1) : ... // - if (isa(AI.getCallee())) - return canDevirtualizeWitnessMethod(AI); + if (isa(applySite.getCallee())) + return canDevirtualizeWitnessMethod(applySite); /// Optimize a class_method and alloc_ref pair into a direct function /// reference: @@ -1188,33 +1177,32 @@ bool swift::canDevirtualizeApply(FullApplySite AI, ClassHierarchyAnalysis *CHA) /// into /// /// %YY = function_ref @... - if (auto *CMI = dyn_cast(AI.getCallee())) { - auto Instance = stripUpCasts(CMI->getOperand()); - auto ClassType = getSelfInstanceType(Instance->getType().getASTType()); - auto *CD = ClassType.getClassOrBoundGenericClass(); + if (auto *cmi = dyn_cast(applySite.getCallee())) { + auto instance = stripUpCasts(cmi->getOperand()); + auto classType = getSelfInstanceType(instance->getType().getASTType()); + auto *cd = classType.getClassOrBoundGenericClass(); - if (isEffectivelyFinalMethod(AI, ClassType, CD, CHA)) - return canDevirtualizeClassMethod(AI, CD, - nullptr /*ORE*/, + if (isEffectivelyFinalMethod(applySite, classType, cd, cha)) + return canDevirtualizeClassMethod(applySite, cd, nullptr /*ore*/, true /*isEffectivelyFinalMethod*/); // Try to check if the exact dynamic type of the instance is statically // known. - if (auto Instance = getInstanceWithExactDynamicType(CMI->getOperand(), CHA)) - return canDevirtualizeClassMethod(AI, CD); + if (auto instance = getInstanceWithExactDynamicType(cmi->getOperand(), cha)) + return canDevirtualizeClassMethod(applySite, cd); - if (auto ExactTy = getExactDynamicType(CMI->getOperand(), CHA)) { - if (ExactTy == CMI->getOperand()->getType()) - return canDevirtualizeClassMethod(AI, CD); + if (auto exactTy = getExactDynamicType(cmi->getOperand(), cha)) { + if (exactTy == cmi->getOperand()->getType()) + return canDevirtualizeClassMethod(applySite, cd); } } - if (isa(AI.getCallee())) { - auto Instance = AI.getArguments().back(); - auto ClassType = getSelfInstanceType(Instance->getType().getASTType()); - auto *CD = ClassType.getClassOrBoundGenericClass(); + if (isa(applySite.getCallee())) { + auto instance = applySite.getArguments().back(); + auto classType = getSelfInstanceType(instance->getType().getASTType()); + auto *cd = classType.getClassOrBoundGenericClass(); - return canDevirtualizeClassMethod(AI, CD); + return canDevirtualizeClassMethod(applySite, cd); } return false; diff --git a/lib/SILOptimizer/Utils/Existential.cpp b/lib/SILOptimizer/Utils/Existential.cpp index 04d10a6990b..07a78d27479 100644 --- a/lib/SILOptimizer/Utils/Existential.cpp +++ b/lib/SILOptimizer/Utils/Existential.cpp @@ -15,8 +15,8 @@ #include "swift/AST/ProtocolConformance.h" #include "swift/SIL/BasicBlockUtils.h" #include "swift/SIL/InstructionUtils.h" -#include "swift/SILOptimizer/Utils/CFG.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/ADT/SmallPtrSet.h" using namespace swift; diff --git a/lib/SILOptimizer/Utils/GenericCloner.cpp b/lib/SILOptimizer/Utils/GenericCloner.cpp index ccee64e9647..f41e67384b1 100644 --- a/lib/SILOptimizer/Utils/GenericCloner.cpp +++ b/lib/SILOptimizer/Utils/GenericCloner.cpp @@ -15,11 +15,11 @@ #include "swift/AST/Type.h" #include "swift/SIL/SILBasicBlock.h" #include "swift/SIL/SILFunction.h" -#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILModule.h" #include "swift/SIL/SILValue.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" diff --git a/lib/SILOptimizer/Utils/InstOptUtils.cpp b/lib/SILOptimizer/Utils/InstOptUtils.cpp new file mode 100644 index 00000000000..7d6e490078d --- /dev/null +++ b/lib/SILOptimizer/Utils/InstOptUtils.cpp @@ -0,0 +1,1577 @@ +//===--- InstOptUtils.cpp - SILOptimizer instruction utilities ------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include "swift/SILOptimizer/Utils/InstOptUtils.h" +#include "swift/AST/GenericSignature.h" +#include "swift/AST/SubstitutionMap.h" +#include "swift/SIL/BasicBlockUtils.h" +#include "swift/SIL/DebugUtils.h" +#include "swift/SIL/DynamicCasts.h" +#include "swift/SIL/InstructionUtils.h" +#include "swift/SIL/SILArgument.h" +#include "swift/SIL/SILBuilder.h" +#include "swift/SIL/SILModule.h" +#include "swift/SIL/SILUndef.h" +#include "swift/SIL/TypeLowering.h" +#include "swift/SILOptimizer/Analysis/ARCAnalysis.h" +#include "swift/SILOptimizer/Analysis/Analysis.h" +#include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Compiler.h" +#include + +using namespace swift; + +static llvm::cl::opt EnableExpandAll("enable-expand-all", + llvm::cl::init(false)); + +/// Creates an increment on \p Ptr before insertion point \p InsertPt that +/// creates a strong_retain if \p Ptr has reference semantics itself or a +/// retain_value if \p Ptr is a non-trivial value without reference-semantics. +NullablePtr +swift::createIncrementBefore(SILValue ptr, SILInstruction *insertPt) { + // Set up the builder we use to insert at our insertion point. + SILBuilder builder(insertPt); + auto loc = RegularLocation::getAutoGeneratedLocation(); + + // If we have a trivial type, just bail, there is no work to do. + if (ptr->getType().isTrivial(builder.getFunction())) + return nullptr; + + // If Ptr is refcounted itself, create the strong_retain and + // return. + if (ptr->getType().isReferenceCounted(builder.getModule())) { + if (ptr->getType().is()) + return builder.createUnownedRetain(loc, ptr, + builder.getDefaultAtomicity()); + else + return builder.createStrongRetain(loc, ptr, + builder.getDefaultAtomicity()); + } + + // Otherwise, create the retain_value. + return builder.createRetainValue(loc, ptr, builder.getDefaultAtomicity()); +} + +/// Creates a decrement on \p ptr before insertion point \p InsertPt that +/// creates a strong_release if \p ptr has reference semantics itself or +/// a release_value if \p ptr is a non-trivial value without +/// reference-semantics. +NullablePtr +swift::createDecrementBefore(SILValue ptr, SILInstruction *insertPt) { + // Setup the builder we will use to insert at our insertion point. + SILBuilder builder(insertPt); + auto loc = RegularLocation::getAutoGeneratedLocation(); + + if (ptr->getType().isTrivial(builder.getFunction())) + return nullptr; + + // If ptr has reference semantics itself, create a strong_release. + if (ptr->getType().isReferenceCounted(builder.getModule())) { + if (ptr->getType().is()) + return builder.createUnownedRelease(loc, ptr, + builder.getDefaultAtomicity()); + else + return builder.createStrongRelease(loc, ptr, + builder.getDefaultAtomicity()); + } + + // Otherwise create a release value. + return builder.createReleaseValue(loc, ptr, builder.getDefaultAtomicity()); +} + +/// Perform a fast local check to see if the instruction is dead. +/// +/// This routine only examines the state of the instruction at hand. +bool swift::isInstructionTriviallyDead(SILInstruction *inst) { + // At Onone, consider all uses, including the debug_info. + // This way, debug_info is preserved at Onone. + if (inst->hasUsesOfAnyResult() + && inst->getFunction()->getEffectiveOptimizationMode() + <= OptimizationMode::NoOptimization) + return false; + + if (!onlyHaveDebugUsesOfAllResults(inst) || isa(inst)) + return false; + + if (auto *bi = dyn_cast(inst)) { + // Although the onFastPath builtin has no side-effects we don't want to + // remove it. + if (bi->getBuiltinInfo().ID == BuiltinValueKind::OnFastPath) + return false; + return !bi->mayHaveSideEffects(); + } + + // condfail instructions that obviously can't fail are dead. + if (auto *cfi = dyn_cast(inst)) + if (auto *ili = dyn_cast(cfi->getOperand())) + if (!ili->getValue()) + return true; + + // mark_uninitialized is never dead. + if (isa(inst)) + return false; + + if (isa(inst) || isa(inst)) + return false; + + // These invalidate enums so "write" memory, but that is not an essential + // operation so we can remove these if they are trivially dead. + if (isa(inst)) + return true; + + if (!inst->mayHaveSideEffects()) + return true; + + return false; +} + +/// Return true if this is a release instruction and the released value +/// is a part of a guaranteed parameter. +bool swift::isIntermediateRelease(SILInstruction *inst, + EpilogueARCFunctionInfo *eafi) { + // Check whether this is a release instruction. + if (!isa(inst) && !isa(inst)) + return false; + + // OK. we have a release instruction. + // Check whether this is a release on part of a guaranteed function argument. + SILValue Op = stripValueProjections(inst->getOperand(0)); + auto *arg = dyn_cast(Op); + if (!arg) + return false; + + // This is a release on a guaranteed parameter. Its not the final release. + if (arg->hasConvention(SILArgumentConvention::Direct_Guaranteed)) + return true; + + // This is a release on an owned parameter and its not the epilogue release. + // Its not the final release. + auto rel = eafi->computeEpilogueARCInstructions( + EpilogueARCContext::EpilogueARCKind::Release, arg); + if (rel.size() && !rel.count(inst)) + return true; + + // Failed to prove anything. + return false; +} + +namespace { +using CallbackTy = llvm::function_ref; +} // end anonymous namespace + +void swift::recursivelyDeleteTriviallyDeadInstructions( + ArrayRef ia, bool force, CallbackTy callback) { + // Delete these instruction and others that become dead after it's deleted. + llvm::SmallPtrSet deadInsts; + for (auto *inst : ia) { + // If the instruction is not dead and force is false, do nothing. + if (force || isInstructionTriviallyDead(inst)) + deadInsts.insert(inst); + } + llvm::SmallPtrSet nextInsts; + while (!deadInsts.empty()) { + for (auto inst : deadInsts) { + // Call the callback before we mutate the to be deleted instruction in any + // way. + callback(inst); + + // Check if any of the operands will become dead as well. + MutableArrayRef operands = inst->getAllOperands(); + for (Operand &operand : operands) { + SILValue operandVal = operand.get(); + if (!operandVal) + continue; + + // Remove the reference from the instruction being deleted to this + // operand. + operand.drop(); + + // If the operand is an instruction that is only used by the instruction + // being deleted, delete it. + if (auto *operandValInst = operandVal->getDefiningInstruction()) + if (!deadInsts.count(operandValInst) + && isInstructionTriviallyDead(operandValInst)) + nextInsts.insert(operandValInst); + } + + // If we have a function ref inst, we need to especially drop its function + // argument so that it gets a proper ref decrement. + auto *fri = dyn_cast(inst); + if (fri && fri->getInitiallyReferencedFunction()) + fri->dropReferencedFunction(); + + auto *dfri = dyn_cast(inst); + if (dfri && dfri->getInitiallyReferencedFunction()) + dfri->dropReferencedFunction(); + + auto *pfri = dyn_cast(inst); + if (pfri && pfri->getInitiallyReferencedFunction()) + pfri->dropReferencedFunction(); + } + + for (auto inst : deadInsts) { + // This will remove this instruction and all its uses. + eraseFromParentWithDebugInsts(inst, callback); + } + + nextInsts.swap(deadInsts); + nextInsts.clear(); + } +} + +/// If the given instruction is dead, delete it along with its dead +/// operands. +/// +/// \param inst The instruction to be deleted. +/// \param force If force is set, don't check if the top level instruction is +/// considered dead - delete it regardless. +void swift::recursivelyDeleteTriviallyDeadInstructions(SILInstruction *inst, + bool force, + CallbackTy callback) { + ArrayRef ai = ArrayRef(inst); + recursivelyDeleteTriviallyDeadInstructions(ai, force, callback); +} + +void swift::eraseUsesOfInstruction(SILInstruction *inst, CallbackTy callback) { + for (auto result : inst->getResults()) { + while (!result->use_empty()) { + auto ui = result->use_begin(); + auto *user = ui->getUser(); + assert(user && "User should never be NULL!"); + + // If the instruction itself has any uses, recursively zap them so that + // nothing uses this instruction. + eraseUsesOfInstruction(user, callback); + + // Walk through the operand list and delete any random instructions that + // will become trivially dead when this instruction is removed. + + for (auto &operand : user->getAllOperands()) { + if (auto *operandI = operand.get()->getDefiningInstruction()) { + // Don't recursively delete the instruction we're working on. + // FIXME: what if we're being recursively invoked? + if (operandI != inst) { + operand.drop(); + recursivelyDeleteTriviallyDeadInstructions(operandI, false, + callback); + } + } + } + callback(user); + user->eraseFromParent(); + } + } +} + +void swift::collectUsesOfValue(SILValue v, + llvm::SmallPtrSetImpl &insts) { + for (auto ui = v->use_begin(), E = v->use_end(); ui != E; ui++) { + auto *user = ui->getUser(); + // Instruction has been processed. + if (!insts.insert(user).second) + continue; + + // Collect the users of this instruction. + for (auto result : user->getResults()) + collectUsesOfValue(result, insts); + } +} + +void swift::eraseUsesOfValue(SILValue v) { + llvm::SmallPtrSet insts; + // Collect the uses. + collectUsesOfValue(v, insts); + // Erase the uses, we can have instructions that become dead because + // of the removal of these instructions, leave to DCE to cleanup. + // Its not safe to do recursively delete here as some of the SILInstruction + // maybe tracked by this set. + for (auto inst : insts) { + inst->replaceAllUsesOfAllResultsWithUndef(); + inst->eraseFromParent(); + } +} + +// Devirtualization of functions with covariant return types produces +// a result that is not an apply, but takes an apply as an +// argument. Attempt to dig the apply out from this result. +FullApplySite swift::findApplyFromDevirtualizedResult(SILValue v) { + if (auto Apply = FullApplySite::isa(v)) + return Apply; + + if (isa(v) || isa(v) || isa(v)) + return findApplyFromDevirtualizedResult( + cast(v)->getOperand(0)); + + return FullApplySite(); +} + +bool swift::mayBindDynamicSelf(SILFunction *F) { + if (!F->hasSelfMetadataParam()) + return false; + + SILValue mdArg = F->getSelfMetadataArgument(); + + for (Operand *mdUse : F->getSelfMetadataArgument()->getUses()) { + SILInstruction *mdUser = mdUse->getUser(); + for (Operand &typeDepOp : mdUser->getTypeDependentOperands()) { + if (typeDepOp.get() == mdArg) + return true; + } + } + return false; +} + +static SILValue skipAddrProjections(SILValue v) { + for (;;) { + switch (v->getKind()) { + case ValueKind::IndexAddrInst: + case ValueKind::IndexRawPointerInst: + case ValueKind::StructElementAddrInst: + case ValueKind::TupleElementAddrInst: + v = cast(v)->getOperand(0); + break; + default: + return v; + } + } + llvm_unreachable("there is no escape from an infinite loop"); +} + +/// Check whether the \p addr is an address of a tail-allocated array element. +bool swift::isAddressOfArrayElement(SILValue addr) { + addr = stripAddressProjections(addr); + if (auto *md = dyn_cast(addr)) + addr = stripAddressProjections(md->getValue()); + + // High-level SIL: check for an get_element_address array semantics call. + if (auto *ptrToAddr = dyn_cast(addr)) + if (auto *sei = dyn_cast(ptrToAddr->getOperand())) { + ArraySemanticsCall call(sei->getOperand()); + if (call && call.getKind() == ArrayCallKind::kGetElementAddress) + return true; + } + + // Check for an tail-address (of an array buffer object). + if (isa(skipAddrProjections(addr))) + return true; + + return false; +} + +/// Find a new position for an ApplyInst's FuncRef so that it dominates its +/// use. Not that FunctionRefInsts may be shared by multiple ApplyInsts. +void swift::placeFuncRef(ApplyInst *ai, DominanceInfo *domInfo) { + FunctionRefInst *funcRef = cast(ai->getCallee()); + SILBasicBlock *domBB = domInfo->findNearestCommonDominator( + ai->getParent(), funcRef->getParent()); + if (domBB == ai->getParent() && domBB != funcRef->getParent()) + // Prefer to place the FuncRef immediately before the call. Since we're + // moving FuncRef up, this must be the only call to it in the block. + funcRef->moveBefore(ai); + else + // Otherwise, conservatively stick it at the beginning of the block. + funcRef->moveBefore(&*domBB->begin()); +} + +/// Add an argument, \p val, to the branch-edge that is pointing into +/// block \p Dest. Return a new instruction and do not erase the old +/// instruction. +TermInst *swift::addArgumentToBranch(SILValue val, SILBasicBlock *dest, + TermInst *branch) { + SILBuilderWithScope builder(branch); + + if (auto *cbi = dyn_cast(branch)) { + SmallVector trueArgs; + SmallVector falseArgs; + + for (auto arg : cbi->getTrueArgs()) + trueArgs.push_back(arg); + + for (auto arg : cbi->getFalseArgs()) + falseArgs.push_back(arg); + + if (dest == cbi->getTrueBB()) { + trueArgs.push_back(val); + assert(trueArgs.size() == dest->getNumArguments()); + } else { + falseArgs.push_back(val); + assert(falseArgs.size() == dest->getNumArguments()); + } + + return builder.createCondBranch( + cbi->getLoc(), cbi->getCondition(), cbi->getTrueBB(), trueArgs, + cbi->getFalseBB(), falseArgs, cbi->getTrueBBCount(), + cbi->getFalseBBCount()); + } + + if (auto *bi = dyn_cast(branch)) { + SmallVector args; + + for (auto arg : bi->getArgs()) + args.push_back(arg); + + args.push_back(val); + assert(args.size() == dest->getNumArguments()); + return builder.createBranch(bi->getLoc(), bi->getDestBB(), args); + } + + llvm_unreachable("unsupported terminator"); +} + +SILLinkage swift::getSpecializedLinkage(SILFunction *f, SILLinkage linkage) { + if (hasPrivateVisibility(linkage) && !f->isSerialized()) { + // Specializations of private symbols should remain so, unless + // they were serialized, which can only happen when specializing + // definitions from a standard library built with -sil-serialize-all. + return SILLinkage::Private; + } + + return SILLinkage::Shared; +} + +/// Cast a value into the expected, ABI compatible type if necessary. +/// This may happen e.g. when: +/// - a type of the return value is a subclass of the expected return type. +/// - actual return type and expected return type differ in optionality. +/// - both types are tuple-types and some of the elements need to be casted. +/// +/// If CheckOnly flag is set, then this function only checks if the +/// required casting is possible. If it is not possible, then None +/// is returned. +/// +/// If CheckOnly is not set, then a casting code is generated and the final +/// casted value is returned. +/// +/// NOTE: We intentionally combine the checking of the cast's handling +/// possibility and the transformation performing the cast in the same function, +/// to avoid any divergence between the check and the implementation in the +/// future. +/// +/// NOTE: The implementation of this function is very closely related to the +/// rules checked by SILVerifier::requireABICompatibleFunctionTypes. +SILValue swift::castValueToABICompatibleType(SILBuilder *builder, + SILLocation loc, SILValue value, + SILType srcTy, SILType destTy) { + + // No cast is required if types are the same. + if (srcTy == destTy) + return value; + + assert(srcTy.isAddress() == destTy.isAddress() + && "Addresses aren't compatible with values"); + + if (srcTy.isAddress() && destTy.isAddress()) { + // Cast between two addresses and that's it. + return builder->createUncheckedAddrCast(loc, value, destTy); + } + + // If both types are classes and dest is the superclass of src, + // simply perform an upcast. + if (destTy.isExactSuperclassOf(srcTy)) { + return builder->createUpcast(loc, value, destTy); + } + + if (srcTy.isHeapObjectReferenceType() && destTy.isHeapObjectReferenceType()) { + return builder->createUncheckedRefCast(loc, value, destTy); + } + + if (auto mt1 = srcTy.getAs()) { + if (auto mt2 = destTy.getAs()) { + if (mt1->getRepresentation() == mt2->getRepresentation()) { + // If builder.Type needs to be casted to A.Type and + // A is a superclass of builder, then it can be done by means + // of a simple upcast. + if (mt2.getInstanceType()->isExactSuperclassOf(mt1.getInstanceType())) { + return builder->createUpcast(loc, value, destTy); + } + + // Cast between two metatypes and that's it. + return builder->createUncheckedBitCast(loc, value, destTy); + } + } + } + + // Check if src and dest types are optional. + auto optionalSrcTy = srcTy.getOptionalObjectType(); + auto optionalDestTy = destTy.getOptionalObjectType(); + + // Both types are optional. + if (optionalDestTy && optionalSrcTy) { + // If both wrapped types are classes and dest is the superclass of src, + // simply perform an upcast. + if (optionalDestTy.isExactSuperclassOf(optionalSrcTy)) { + // Insert upcast. + return builder->createUpcast(loc, value, destTy); + } + + // Unwrap the original optional value. + auto *someDecl = builder->getASTContext().getOptionalSomeDecl(); + auto *noneBB = builder->getFunction().createBasicBlock(); + auto *someBB = builder->getFunction().createBasicBlock(); + auto *curBB = builder->getInsertionPoint()->getParent(); + + auto *contBB = curBB->split(builder->getInsertionPoint()); + contBB->createPhiArgument(destTy, ValueOwnershipKind::Owned); + + SmallVector, 1> caseBBs; + caseBBs.push_back(std::make_pair(someDecl, someBB)); + builder->setInsertionPoint(curBB); + builder->createSwitchEnum(loc, value, noneBB, caseBBs); + + // Handle the Some case. + builder->setInsertionPoint(someBB); + SILValue unwrappedValue = + builder->createUncheckedEnumData(loc, value, someDecl); + // Cast the unwrapped value. + auto castedUnwrappedValue = castValueToABICompatibleType( + builder, loc, unwrappedValue, optionalSrcTy, optionalDestTy); + // Wrap into optional. + auto castedValue = + builder->createOptionalSome(loc, castedUnwrappedValue, destTy); + builder->createBranch(loc, contBB, {castedValue}); + + // Handle the None case. + builder->setInsertionPoint(noneBB); + castedValue = builder->createOptionalNone(loc, destTy); + builder->createBranch(loc, contBB, {castedValue}); + builder->setInsertionPoint(contBB->begin()); + + return contBB->getArgument(0); + } + + // Src is not optional, but dest is optional. + if (!optionalSrcTy && optionalDestTy) { + auto optionalSrcCanTy = + OptionalType::get(srcTy.getASTType())->getCanonicalType(); + auto loweredOptionalSrcType = + SILType::getPrimitiveObjectType(optionalSrcCanTy); + + // Wrap the source value into an optional first. + SILValue wrappedValue = + builder->createOptionalSome(loc, value, loweredOptionalSrcType); + // Cast the wrapped value. + return castValueToABICompatibleType(builder, loc, wrappedValue, + wrappedValue->getType(), destTy); + } + + // Handle tuple types. + // Extract elements, cast each of them, create a new tuple. + if (auto srcTupleTy = srcTy.getAs()) { + SmallVector expectedTuple; + for (unsigned i = 0, e = srcTupleTy->getNumElements(); i < e; i++) { + SILValue element = builder->createTupleExtract(loc, value, i); + // Cast the value if necessary. + element = castValueToABICompatibleType(builder, loc, element, + srcTy.getTupleElementType(i), + destTy.getTupleElementType(i)); + expectedTuple.push_back(element); + } + + return builder->createTuple(loc, destTy, expectedTuple); + } + + // Function types are interchangeable if they're also ABI-compatible. + if (srcTy.is()) { + if (destTy.is()) { + assert(srcTy.getAs()->isNoEscape() + == destTy.getAs()->isNoEscape() + || srcTy.getAs()->getRepresentation() + != SILFunctionType::Representation::Thick + && "Swift thick functions that differ in escapeness are " + "not ABI " + "compatible"); + // Insert convert_function. + return builder->createConvertFunction(loc, value, destTy, + /*WithoutActuallyEscaping=*/false); + } + } + + llvm::errs() << "Source type: " << srcTy << "\n"; + llvm::errs() << "Destination type: " << destTy << "\n"; + llvm_unreachable("Unknown combination of types for casting"); +} + +ProjectBoxInst *swift::getOrCreateProjectBox(AllocBoxInst *abi, + unsigned index) { + SILBasicBlock::iterator iter(abi); + iter++; + assert(iter != abi->getParent()->end() + && "alloc_box cannot be the last instruction of a block"); + SILInstruction *nextInst = &*iter; + if (auto *pbi = dyn_cast(nextInst)) { + if (pbi->getOperand() == abi && pbi->getFieldIndex() == index) + return pbi; + } + + SILBuilder builder(nextInst); + return builder.createProjectBox(abi->getLoc(), abi, index); +} + +// Peek through trivial Enum initialization, typically for pointless +// Optionals. +// +// Given an UncheckedTakeEnumDataAddrInst, check that there are no +// other uses of the Enum value and return the address used to initialized the +// enum's payload: +// +// %stack_adr = alloc_stack +// %data_adr = init_enum_data_addr %stk_adr +// %enum_adr = inject_enum_addr %stack_adr +// %copy_src = unchecked_take_enum_data_addr %enum_adr +// dealloc_stack %stack_adr +// (No other uses of %stack_adr.) +InitEnumDataAddrInst * +swift::findInitAddressForTrivialEnum(UncheckedTakeEnumDataAddrInst *utedai) { + auto *asi = dyn_cast(utedai->getOperand()); + if (!asi) + return nullptr; + + SILInstruction *singleUser = nullptr; + for (auto use : asi->getUses()) { + auto *user = use->getUser(); + if (user == utedai) + continue; + + // As long as there's only one UncheckedTakeEnumDataAddrInst and one + // InitEnumDataAddrInst, we don't care how many InjectEnumAddr and + // DeallocStack users there are. + if (isa(user) || isa(user)) + continue; + + if (singleUser) + return nullptr; + + singleUser = user; + } + if (!singleUser) + return nullptr; + + // Assume, without checking, that the returned InitEnumDataAddr dominates the + // given UncheckedTakeEnumDataAddrInst, because that's how SIL is defined. I + // don't know where this is actually verified. + return dyn_cast(singleUser); +} + +//===----------------------------------------------------------------------===// +// String Concatenation Optimizer +//===----------------------------------------------------------------------===// + +namespace { +/// This is a helper class that performs optimization of string literals +/// concatenation. +class StringConcatenationOptimizer { + /// Apply instruction being optimized. + ApplyInst *ai; + /// Builder to be used for creation of new instructions. + SILBuilder &builder; + /// Left string literal operand of a string concatenation. + StringLiteralInst *sliLeft = nullptr; + /// Right string literal operand of a string concatenation. + StringLiteralInst *sliRight = nullptr; + /// Function used to construct the left string literal. + FunctionRefInst *friLeft = nullptr; + /// Function used to construct the right string literal. + FunctionRefInst *friRight = nullptr; + /// Apply instructions used to construct left string literal. + ApplyInst *aiLeft = nullptr; + /// Apply instructions used to construct right string literal. + ApplyInst *aiRight = nullptr; + /// String literal conversion function to be used. + FunctionRefInst *friConvertFromBuiltin = nullptr; + /// Result type of a function producing the concatenated string literal. + SILValue funcResultType; + + /// Internal helper methods + bool extractStringConcatOperands(); + void adjustEncodings(); + APInt getConcatenatedLength(); + bool isAscii() const; + +public: + StringConcatenationOptimizer(ApplyInst *ai, SILBuilder &builder) + : ai(ai), builder(builder) {} + + /// Tries to optimize a given apply instruction if it is a + /// concatenation of string literals. + /// + /// Returns a new instruction if optimization was possible. + SingleValueInstruction *optimize(); +}; + +} // end anonymous namespace + +/// Checks operands of a string concatenation operation to see if +/// optimization is applicable. +/// +/// Returns false if optimization is not possible. +/// Returns true and initializes internal fields if optimization is possible. +bool StringConcatenationOptimizer::extractStringConcatOperands() { + auto *Fn = ai->getReferencedFunctionOrNull(); + if (!Fn) + return false; + + if (ai->getNumArguments() != 3 || !Fn->hasSemanticsAttr("string.concat")) + return false; + + // Left and right operands of a string concatenation operation. + aiLeft = dyn_cast(ai->getOperand(1)); + aiRight = dyn_cast(ai->getOperand(2)); + + if (!aiLeft || !aiRight) + return false; + + friLeft = dyn_cast(aiLeft->getCallee()); + friRight = dyn_cast(aiRight->getCallee()); + + if (!friLeft || !friRight) + return false; + + auto *friLeftFun = friLeft->getReferencedFunctionOrNull(); + auto *friRightFun = friRight->getReferencedFunctionOrNull(); + + if (friLeftFun->getEffectsKind() >= EffectsKind::ReleaseNone + || friRightFun->getEffectsKind() >= EffectsKind::ReleaseNone) + return false; + + if (!friLeftFun->hasSemanticsAttrs() || !friRightFun->hasSemanticsAttrs()) + return false; + + auto aiLeftOperandsNum = aiLeft->getNumOperands(); + auto aiRightOperandsNum = aiRight->getNumOperands(); + + // makeUTF8 should have following parameters: + // (start: RawPointer, utf8CodeUnitCount: Word, isASCII: Int1) + if (!((friLeftFun->hasSemanticsAttr("string.makeUTF8") + && aiLeftOperandsNum == 5) + || (friRightFun->hasSemanticsAttr("string.makeUTF8") + && aiRightOperandsNum == 5))) + return false; + + sliLeft = dyn_cast(aiLeft->getOperand(1)); + sliRight = dyn_cast(aiRight->getOperand(1)); + + if (!sliLeft || !sliRight) + return false; + + // Only UTF-8 and UTF-16 encoded string literals are supported by this + // optimization. + if (sliLeft->getEncoding() != StringLiteralInst::Encoding::UTF8 + && sliLeft->getEncoding() != StringLiteralInst::Encoding::UTF16) + return false; + + if (sliRight->getEncoding() != StringLiteralInst::Encoding::UTF8 + && sliRight->getEncoding() != StringLiteralInst::Encoding::UTF16) + return false; + + return true; +} + +/// Ensures that both string literals to be concatenated use the same +/// UTF encoding. Converts UTF-8 into UTF-16 if required. +void StringConcatenationOptimizer::adjustEncodings() { + if (sliLeft->getEncoding() == sliRight->getEncoding()) { + friConvertFromBuiltin = friLeft; + if (sliLeft->getEncoding() == StringLiteralInst::Encoding::UTF8) { + funcResultType = aiLeft->getOperand(4); + } else { + funcResultType = aiLeft->getOperand(3); + } + return; + } + + builder.setCurrentDebugScope(ai->getDebugScope()); + + // If one of the string literals is UTF8 and another one is UTF16, + // convert the UTF8-encoded string literal into UTF16-encoding first. + if (sliLeft->getEncoding() == StringLiteralInst::Encoding::UTF8 + && sliRight->getEncoding() == StringLiteralInst::Encoding::UTF16) { + funcResultType = aiRight->getOperand(3); + friConvertFromBuiltin = friRight; + // Convert UTF8 representation into UTF16. + sliLeft = builder.createStringLiteral(ai->getLoc(), sliLeft->getValue(), + StringLiteralInst::Encoding::UTF16); + } + + if (sliRight->getEncoding() == StringLiteralInst::Encoding::UTF8 + && sliLeft->getEncoding() == StringLiteralInst::Encoding::UTF16) { + funcResultType = aiLeft->getOperand(3); + friConvertFromBuiltin = friLeft; + // Convert UTF8 representation into UTF16. + sliRight = builder.createStringLiteral(ai->getLoc(), sliRight->getValue(), + StringLiteralInst::Encoding::UTF16); + } + + // It should be impossible to have two operands with different + // encodings at this point. + assert( + sliLeft->getEncoding() == sliRight->getEncoding() + && "Both operands of string concatenation should have the same encoding"); +} + +/// Computes the length of a concatenated string literal. +APInt StringConcatenationOptimizer::getConcatenatedLength() { + // Real length of string literals computed based on its contents. + // Length is in code units. + auto sliLenLeft = sliLeft->getCodeUnitCount(); + (void)sliLenLeft; + auto sliLenRight = sliRight->getCodeUnitCount(); + (void)sliLenRight; + + // Length of string literals as reported by string.make functions. + auto *lenLeft = dyn_cast(aiLeft->getOperand(2)); + auto *lenRight = dyn_cast(aiRight->getOperand(2)); + + // Real and reported length should be the same. + assert(sliLenLeft == lenLeft->getValue() + && "Size of string literal in @_semantics(string.make) is wrong"); + + assert(sliLenRight == lenRight->getValue() + && "Size of string literal in @_semantics(string.make) is wrong"); + + // Compute length of the concatenated literal. + return lenLeft->getValue() + lenRight->getValue(); +} + +/// Computes the isAscii flag of a concatenated UTF8-encoded string literal. +bool StringConcatenationOptimizer::isAscii() const { + // Add the isASCII argument in case of UTF8. + // IsASCII is true only if IsASCII of both literals is true. + auto *asciiLeft = dyn_cast(aiLeft->getOperand(3)); + auto *asciiRight = dyn_cast(aiRight->getOperand(3)); + auto isAsciiLeft = asciiLeft->getValue() == 1; + auto isAsciiRight = asciiRight->getValue() == 1; + return isAsciiLeft && isAsciiRight; +} + +SingleValueInstruction *StringConcatenationOptimizer::optimize() { + // Bail out if string literals concatenation optimization is + // not possible. + if (!extractStringConcatOperands()) + return nullptr; + + // Perform string literal encodings adjustments if needed. + adjustEncodings(); + + // Arguments of the new StringLiteralInst to be created. + SmallVector arguments; + + // Encoding to be used for the concatenated string literal. + auto encoding = sliLeft->getEncoding(); + + // Create a concatenated string literal. + builder.setCurrentDebugScope(ai->getDebugScope()); + auto lv = sliLeft->getValue(); + auto rv = sliRight->getValue(); + auto *newSLI = + builder.createStringLiteral(ai->getLoc(), lv + Twine(rv), encoding); + arguments.push_back(newSLI); + + // Length of the concatenated literal according to its encoding. + auto *len = builder.createIntegerLiteral( + ai->getLoc(), aiLeft->getOperand(2)->getType(), getConcatenatedLength()); + arguments.push_back(len); + + // isAscii flag for UTF8-encoded string literals. + if (encoding == StringLiteralInst::Encoding::UTF8) { + bool ascii = isAscii(); + auto ilType = aiLeft->getOperand(3)->getType(); + auto *asciiLiteral = + builder.createIntegerLiteral(ai->getLoc(), ilType, intmax_t(ascii)); + arguments.push_back(asciiLiteral); + } + + // Type. + arguments.push_back(funcResultType); + + return builder.createApply(ai->getLoc(), friConvertFromBuiltin, + SubstitutionMap(), arguments); +} + +/// Top level entry point +SingleValueInstruction *swift::tryToConcatenateStrings(ApplyInst *ai, + SILBuilder &builder) { + return StringConcatenationOptimizer(ai, builder).optimize(); +} + +//===----------------------------------------------------------------------===// +// Closure Deletion +//===----------------------------------------------------------------------===// + +/// NOTE: Instructions with transitive ownership kind are assumed to not keep +/// the underlying closure alive as well. This is meant for instructions only +/// with non-transitive users. +static bool useDoesNotKeepClosureAlive(const SILInstruction *inst) { + switch (inst->getKind()) { + case SILInstructionKind::StrongRetainInst: + case SILInstructionKind::StrongReleaseInst: + case SILInstructionKind::DestroyValueInst: + case SILInstructionKind::RetainValueInst: + case SILInstructionKind::ReleaseValueInst: + case SILInstructionKind::DebugValueInst: + case SILInstructionKind::EndBorrowInst: + return true; + default: + return false; + } +} + +static bool useHasTransitiveOwnership(const SILInstruction *inst) { + // convert_escape_to_noescape is used to convert to a @noescape function type. + // It does not change ownership of the function value. + if (isa(inst)) + return true; + + // Look through copy_value, begin_borrow. They are inert for our purposes, but + // we need to look through it. + return isa(inst) || isa(inst); +} + +static SILValue createLifetimeExtendedAllocStack( + SILBuilder &builder, SILLocation loc, SILValue arg, + ArrayRef exitingBlocks, InstModCallbacks callbacks) { + AllocStackInst *asi = nullptr; + { + // Save our insert point and create a new alloc_stack in the initial BB and + // dealloc_stack in all exit blocks. + auto *oldInsertPt = &*builder.getInsertionPoint(); + builder.setInsertionPoint(builder.getFunction().begin()->begin()); + asi = builder.createAllocStack(loc, arg->getType()); + callbacks.createdNewInst(asi); + + for (auto *BB : exitingBlocks) { + builder.setInsertionPoint(BB->getTerminator()); + callbacks.createdNewInst(builder.createDeallocStack(loc, asi)); + } + builder.setInsertionPoint(oldInsertPt); + } + assert(asi != nullptr); + + // Then perform a copy_addr [take] [init] right after the partial_apply from + // the original address argument to the new alloc_stack that we have + // created. + callbacks.createdNewInst( + builder.createCopyAddr(loc, arg, asi, IsTake, IsInitialization)); + + // Return the new alloc_stack inst that has the appropriate live range to + // destroy said values. + return asi; +} + +static bool shouldDestroyPartialApplyCapturedArg(SILValue arg, + SILParameterInfo paramInfo, + const SILFunction &F) { + // If we have a non-trivial type and the argument is passed in @inout, we do + // not need to destroy it here. This is something that is implicit in the + // partial_apply design that will be revisited when partial_apply is + // redesigned. + if (paramInfo.isIndirectMutating()) + return false; + + // If we have a trivial type, we do not need to put in any extra releases. + if (arg->getType().isTrivial(F)) + return false; + + // We handle all other cases. + return true; +} + +// *HEY YOU, YES YOU, PLEASE READ*. Even though a textual partial apply is +// printed with the convention of the closed over function upon it, all +// non-inout arguments to a partial_apply are passed at +1. This includes +// arguments that will eventually be passed as guaranteed or in_guaranteed to +// the closed over function. This is because the partial apply is building up a +// boxed aggregate to send off to the closed over function. Of course when you +// call the function, the proper conventions will be used. +void swift::releasePartialApplyCapturedArg(SILBuilder &builder, SILLocation loc, + SILValue arg, + SILParameterInfo paramInfo, + InstModCallbacks callbacks) { + if (!shouldDestroyPartialApplyCapturedArg(arg, paramInfo, + builder.getFunction())) + return; + + // Otherwise, we need to destroy the argument. If we have an address, we + // insert a destroy_addr and return. Any live range issues must have been + // dealt with by our caller. + if (arg->getType().isAddress()) { + // Then emit the destroy_addr for this arg + SILInstruction *newInst = builder.emitDestroyAddrAndFold(loc, arg); + callbacks.createdNewInst(newInst); + return; + } + + // Otherwise, we have an object. We emit the most optimized form of release + // possible for that value. + + // If we have qualified ownership, we should just emit a destroy value. + if (arg->getFunction()->hasOwnership()) { + callbacks.createdNewInst(builder.createDestroyValue(loc, arg)); + return; + } + + if (arg->getType().hasReferenceSemantics()) { + auto u = builder.emitStrongRelease(loc, arg); + if (u.isNull()) + return; + + if (auto *SRI = u.dyn_cast()) { + callbacks.deleteInst(SRI); + return; + } + + callbacks.createdNewInst(u.get()); + return; + } + + auto u = builder.emitReleaseValue(loc, arg); + if (u.isNull()) + return; + + if (auto *rvi = u.dyn_cast()) { + callbacks.deleteInst(rvi); + return; + } + + callbacks.createdNewInst(u.get()); +} + +/// For each captured argument of pai, decrement the ref count of the captured +/// argument as appropriate at each of the post dominated release locations +/// found by tracker. +static bool releaseCapturedArgsOfDeadPartialApply(PartialApplyInst *pai, + ReleaseTracker &tracker, + InstModCallbacks callbacks) { + SILBuilderWithScope builder(pai); + SILLocation loc = pai->getLoc(); + CanSILFunctionType paiTy = + pai->getCallee()->getType().getAs(); + + ArrayRef params = paiTy->getParameters(); + llvm::SmallVector args; + for (SILValue v : pai->getArguments()) { + // If any of our arguments contain open existentials, bail. We do not + // support this for now so that we can avoid having to re-order stack + // locations (a larger change). + if (v->getType().hasOpenedExistential()) + return false; + args.emplace_back(v); + } + unsigned delta = params.size() - args.size(); + assert(delta <= params.size() + && "Error, more args to partial apply than " + "params in its interface."); + params = params.drop_front(delta); + + llvm::SmallVector exitingBlocks; + pai->getFunction()->findExitingBlocks(exitingBlocks); + + // Go through our argument list and create new alloc_stacks for each + // non-trivial address value. This ensures that the memory location that we + // are cleaning up has the same live range as the partial_apply. Otherwise, we + // may be inserting destroy_addr of alloc_stack that have already been passed + // to a dealloc_stack. + for (unsigned i : reversed(indices(args))) { + SILValue arg = args[i]; + SILParameterInfo paramInfo = params[i]; + + // If we are not going to destroy this partial_apply, continue. + if (!shouldDestroyPartialApplyCapturedArg(arg, paramInfo, + builder.getFunction())) + continue; + + // If we have an object, we will not have live range issues, just continue. + if (arg->getType().isObject()) + continue; + + // Now that we know that we have a non-argument address, perform a take-init + // of arg into a lifetime extended alloc_stack + args[i] = createLifetimeExtendedAllocStack(builder, loc, arg, exitingBlocks, + callbacks); + } + + // Emit a destroy for each captured closure argument at each final release + // point. + for (auto *finalRelease : tracker.getFinalReleases()) { + builder.setInsertionPoint(finalRelease); + builder.setCurrentDebugScope(finalRelease->getDebugScope()); + for (unsigned i : indices(args)) { + SILValue arg = args[i]; + SILParameterInfo param = params[i]; + + releasePartialApplyCapturedArg(builder, loc, arg, param, callbacks); + } + } + + return true; +} + +static bool +deadMarkDependenceUser(SILInstruction *inst, + SmallVectorImpl &deleteInsts) { + if (!isa(inst)) + return false; + deleteInsts.push_back(inst); + for (auto *use : cast(inst)->getUses()) { + if (!deadMarkDependenceUser(use->getUser(), deleteInsts)) + return false; + } + return true; +} + +/// TODO: Generalize this to general objects. +bool swift::tryDeleteDeadClosure(SingleValueInstruction *closure, + InstModCallbacks callbacks) { + auto *pa = dyn_cast(closure); + + // We currently only handle locally identified values that do not escape. We + // also assume that the partial apply does not capture any addresses. + if (!pa && !isa(closure)) + return false; + + // A stack allocated partial apply does not have any release users. Delete it + // if the only users are the dealloc_stack and mark_dependence instructions. + if (pa && pa->isOnStack()) { + SmallVector deleteInsts; + for (auto *use : pa->getUses()) { + if (isa(use->getUser()) + || isa(use->getUser())) + deleteInsts.push_back(use->getUser()); + else if (!deadMarkDependenceUser(use->getUser(), deleteInsts)) + return false; + } + for (auto *inst : reverse(deleteInsts)) + callbacks.deleteInst(inst); + callbacks.deleteInst(pa); + + // Note: the lifetime of the captured arguments is managed outside of the + // trivial closure value i.e: there will already be releases for the + // captured arguments. Releasing captured arguments is not necessary. + return true; + } + + // We only accept a user if it is an ARC object that can be removed if the + // object is dead. This should be expanded in the future. This also ensures + // that we are locally identified and non-escaping since we only allow for + // specific ARC users. + ReleaseTracker tracker(useDoesNotKeepClosureAlive, useHasTransitiveOwnership); + + // Find the ARC users and the final retain, release. + if (!getFinalReleasesForValue(SILValue(closure), tracker)) + return false; + + // If we have a partial_apply, release each captured argument at each one of + // the final release locations of the partial apply. + if (auto *pai = dyn_cast(closure)) { + // If we can not decrement the ref counts of the dead partial apply for any + // reason, bail. + if (!releaseCapturedArgsOfDeadPartialApply(pai, tracker, callbacks)) + return false; + } + + // Then delete all user instructions in reverse so that leaf uses are deleted + // first. + for (auto *user : reverse(tracker.getTrackedUsers())) { + assert(user->getResults().empty() + || useHasTransitiveOwnership(user) + && "We expect only ARC operations without " + "results or a cast from escape to noescape without users"); + callbacks.deleteInst(user); + } + + // Finally delete the closure. + callbacks.deleteInst(closure); + + return true; +} + +bool swift::simplifyUsers(SingleValueInstruction *inst) { + bool changed = false; + + for (auto ui = inst->use_begin(), ue = inst->use_end(); ui != ue;) { + SILInstruction *user = ui->getUser(); + ++ui; + + auto svi = dyn_cast(user); + if (!svi) + continue; + + SILValue S = simplifyInstruction(svi); + if (!S) + continue; + + replaceAllSimplifiedUsesAndErase(svi, S); + changed = true; + } + + return changed; +} + +/// True if a type can be expanded without a significant increase to code size. +bool swift::shouldExpand(SILModule &module, SILType ty) { + // FIXME: Expansion + auto expansion = ResilienceExpansion::Minimal; + + if (module.Types.getTypeLowering(ty, expansion).isAddressOnly()) { + return false; + } + if (EnableExpandAll) { + return true; + } + + unsigned numFields = module.Types.countNumberOfFields(ty, expansion); + return (numFields <= 6); +} + +/// Some support functions for the global-opt and let-properties-opts + +// Encapsulate the state used for recursive analysis of a static +// initializer. Discover all the instruction in a use-def graph and return them +// in topological order. +// +// TODO: We should have a DFS utility for this sort of thing so it isn't +// recursive. +class StaticInitializerAnalysis { + SmallVectorImpl &postOrderInstructions; + llvm::SmallDenseSet visited; + int recursionLevel = 0; + +public: + StaticInitializerAnalysis( + SmallVectorImpl &postOrderInstructions) + : postOrderInstructions(postOrderInstructions) {} + + // Perform a recursive DFS on on the use-def graph rooted at `V`. Insert + // values in the `visited` set in preorder. Insert values in + // `postOrderInstructions` in postorder so that the instructions are + // topologically def-use ordered (in execution order). + bool analyze(SILValue rootValue) { + return recursivelyAnalyzeOperand(rootValue); + } + +protected: + bool recursivelyAnalyzeOperand(SILValue v) { + if (!visited.insert(v).second) + return true; + + if (++recursionLevel > 50) + return false; + + // TODO: For multi-result instructions, we could simply insert all result + // values in the visited set here. + auto *inst = dyn_cast(v); + if (!inst) + return false; + + if (!recursivelyAnalyzeInstruction(inst)) + return false; + + postOrderInstructions.push_back(inst); + --recursionLevel; + return true; + } + + bool recursivelyAnalyzeInstruction(SILInstruction *inst) { + if (auto *si = dyn_cast(inst)) { + // If it is not a struct which is a simple type, bail. + if (!si->getType().isTrivial(*si->getFunction())) + return false; + + return llvm::all_of(si->getAllOperands(), [&](Operand &operand) -> bool { + return recursivelyAnalyzeOperand(operand.get()); + }); + } + if (auto *ti = dyn_cast(inst)) { + // If it is not a tuple which is a simple type, bail. + if (!ti->getType().isTrivial(*ti->getFunction())) + return false; + + return llvm::all_of(ti->getAllOperands(), [&](Operand &operand) -> bool { + return recursivelyAnalyzeOperand(operand.get()); + }); + } + if (auto *bi = dyn_cast(inst)) { + switch (bi->getBuiltinInfo().ID) { + case BuiltinValueKind::FPTrunc: + if (auto *li = dyn_cast(bi->getArguments()[0])) { + return recursivelyAnalyzeOperand(li); + } + return false; + default: + return false; + } + } + return isa(inst) || isa(inst) + || isa(inst); + } +}; + +/// Check if the value of v is computed by means of a simple initialization. +/// Populate `forwardInstructions` with references to all the instructions +/// that participate in the use-def graph required to compute `V`. The +/// instructions will be in def-use topological order. +bool swift::analyzeStaticInitializer( + SILValue v, SmallVectorImpl &forwardInstructions) { + return StaticInitializerAnalysis(forwardInstructions).analyze(v); +} + +/// FIXME: This must be kept in sync with replaceLoadSequence() +/// below. What a horrible design. +bool swift::canReplaceLoadSequence(SILInstruction *inst) { + if (auto *cai = dyn_cast(inst)) + return true; + + if (auto *li = dyn_cast(inst)) + return true; + + if (auto *seai = dyn_cast(inst)) { + for (auto seaiUse : seai->getUses()) { + if (!canReplaceLoadSequence(seaiUse->getUser())) + return false; + } + return true; + } + + if (auto *teai = dyn_cast(inst)) { + for (auto teaiUse : teai->getUses()) { + if (!canReplaceLoadSequence(teaiUse->getUser())) + return false; + } + return true; + } + + if (auto *ba = dyn_cast(inst)) { + for (auto use : ba->getUses()) { + if (!canReplaceLoadSequence(use->getUser())) + return false; + } + return true; + } + + // Incidental uses of an address are meaningless with regard to the loaded + // value. + if (isIncidentalUse(inst) || isa(inst)) + return true; + + return false; +} + +/// Replace load sequence which may contain +/// a chain of struct_element_addr followed by a load. +/// The sequence is traversed inside out, i.e. +/// starting with the innermost struct_element_addr +/// Move into utils. +/// +/// FIXME: this utility does not make sense as an API. How can the caller +/// guarantee that the only uses of `I` are struct_element_addr and +/// tuple_element_addr? +void swift::replaceLoadSequence(SILInstruction *inst, SILValue value) { + if (auto *cai = dyn_cast(inst)) { + SILBuilder builder(cai); + builder.createStore(cai->getLoc(), value, cai->getDest(), + StoreOwnershipQualifier::Unqualified); + return; + } + + if (auto *li = dyn_cast(inst)) { + li->replaceAllUsesWith(value); + return; + } + + if (auto *seai = dyn_cast(inst)) { + SILBuilder builder(seai); + auto *sei = + builder.createStructExtract(seai->getLoc(), value, seai->getField()); + for (auto seaiUse : seai->getUses()) { + replaceLoadSequence(seaiUse->getUser(), sei); + } + return; + } + + if (auto *teai = dyn_cast(inst)) { + SILBuilder builder(teai); + auto *tei = + builder.createTupleExtract(teai->getLoc(), value, teai->getFieldNo()); + for (auto teaiUse : teai->getUses()) { + replaceLoadSequence(teaiUse->getUser(), tei); + } + return; + } + + if (auto *ba = dyn_cast(inst)) { + for (auto use : ba->getUses()) { + replaceLoadSequence(use->getUser(), value); + } + return; + } + + // Incidental uses of an addres are meaningless with regard to the loaded + // value. + if (isIncidentalUse(inst) || isa(inst)) + return; + + llvm_unreachable("Unknown instruction sequence for reading from a global"); +} + +/// Are the callees that could be called through Decl statically +/// knowable based on the Decl and the compilation mode? +bool swift::calleesAreStaticallyKnowable(SILModule &module, SILDeclRef decl) { + if (decl.isForeign) + return false; + + const DeclContext *assocDC = module.getAssociatedContext(); + if (!assocDC) + return false; + + auto *afd = decl.getAbstractFunctionDecl(); + assert(afd && "Expected abstract function decl!"); + + // Only handle members defined within the SILModule's associated context. + if (!afd->isChildContextOf(assocDC)) + return false; + + if (afd->isDynamic()) { + return false; + } + + if (!afd->hasAccess()) + return false; + + // Only consider 'private' members, unless we are in whole-module compilation. + switch (afd->getEffectiveAccess()) { + case AccessLevel::Open: + return false; + case AccessLevel::Public: + if (isa(afd)) { + // Constructors are special: a derived class in another module can + // "override" a constructor if its class is "open", although the + // constructor itself is not open. + auto *nd = afd->getDeclContext()->getSelfNominalTypeDecl(); + if (nd->getEffectiveAccess() == AccessLevel::Open) + return false; + } + LLVM_FALLTHROUGH; + case AccessLevel::Internal: + return module.isWholeModule(); + case AccessLevel::FilePrivate: + case AccessLevel::Private: + return true; + } + + llvm_unreachable("Unhandled access level in switch."); +} + +Optional +swift::findLocalApplySites(FunctionRefBaseInst *fri) { + SmallVector worklist(fri->use_begin(), fri->use_end()); + + Optional f; + f.emplace(); + + // Optimistically state that we have no escapes before our def-use dataflow. + f->escapes = false; + + while (!worklist.empty()) { + auto *op = worklist.pop_back_val(); + auto *user = op->getUser(); + + // If we have a full apply site as our user. + if (auto apply = FullApplySite::isa(user)) { + if (apply.getCallee() == op->get()) { + f->fullApplySites.push_back(apply); + continue; + } + } + + // If we have a partial apply as a user, start tracking it, but also look at + // its users. + if (auto *pai = dyn_cast(user)) { + if (pai->getCallee() == op->get()) { + // Track the partial apply that we saw so we can potentially eliminate + // dead closure arguments. + f->partialApplySites.push_back(pai); + // Look to see if we can find a full application of this partial apply + // as well. + llvm::copy(pai->getUses(), std::back_inserter(worklist)); + continue; + } + } + + // Otherwise, see if we have any function casts to look through... + switch (user->getKind()) { + case SILInstructionKind::ThinToThickFunctionInst: + case SILInstructionKind::ConvertFunctionInst: + case SILInstructionKind::ConvertEscapeToNoEscapeInst: + llvm::copy(cast(user)->getUses(), + std::back_inserter(worklist)); + continue; + + // A partial_apply [stack] marks its captured arguments with + // mark_dependence. + case SILInstructionKind::MarkDependenceInst: + llvm::copy(cast(user)->getUses(), + std::back_inserter(worklist)); + continue; + + // Look through any reference count instructions since these are not + // escapes: + case SILInstructionKind::CopyValueInst: + llvm::copy(cast(user)->getUses(), + std::back_inserter(worklist)); + continue; + case SILInstructionKind::StrongRetainInst: + case SILInstructionKind::StrongReleaseInst: + case SILInstructionKind::RetainValueInst: + case SILInstructionKind::ReleaseValueInst: + case SILInstructionKind::DestroyValueInst: + // A partial_apply [stack] is deallocated with a dealloc_stack. + case SILInstructionKind::DeallocStackInst: + continue; + default: + break; + } + + // But everything else is considered an escape. + f->escapes = true; + } + + // If we did escape and didn't find any apply sites, then we have no + // information for our users that is interesting. + if (f->escapes && f->partialApplySites.empty() && f->fullApplySites.empty()) + return None; + return f; +} + +/// Insert destroys of captured arguments of partial_apply [stack]. +void swift::insertDestroyOfCapturedArguments( + PartialApplyInst *pai, SILBuilder &builder, + llvm::function_ref shouldInsertDestroy) { + assert(pai->isOnStack()); + + ApplySite site(pai); + SILFunctionConventions calleeConv(site.getSubstCalleeType(), + pai->getModule()); + auto loc = RegularLocation::getAutoGeneratedLocation(); + for (auto &arg : pai->getArgumentOperands()) { + if (!shouldInsertDestroy(arg.get())) + continue; + unsigned calleeArgumentIndex = site.getCalleeArgIndex(arg); + assert(calleeArgumentIndex >= calleeConv.getSILArgIndexOfFirstParam()); + auto paramInfo = calleeConv.getParamInfoForSILArg(calleeArgumentIndex); + releasePartialApplyCapturedArg(builder, loc, arg.get(), paramInfo); + } +} diff --git a/lib/SILOptimizer/Utils/LoadStoreOptUtils.cpp b/lib/SILOptimizer/Utils/LoadStoreOptUtils.cpp index a16be4bc5df..93dcad0c477 100644 --- a/lib/SILOptimizer/Utils/LoadStoreOptUtils.cpp +++ b/lib/SILOptimizer/Utils/LoadStoreOptUtils.cpp @@ -13,7 +13,7 @@ #define DEBUG_TYPE "sil-lsbase" #include "swift/SILOptimizer/Utils/LoadStoreOptUtils.h" #include "swift/SIL/InstructionUtils.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "llvm/Support/Debug.h" using namespace swift; diff --git a/lib/SILOptimizer/Utils/Local.cpp b/lib/SILOptimizer/Utils/Local.cpp deleted file mode 100644 index 55852170192..00000000000 --- a/lib/SILOptimizer/Utils/Local.cpp +++ /dev/null @@ -1,1889 +0,0 @@ -//===--- Local.cpp - Functions that perform local SIL transformations. ----===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// - -#include "swift/SILOptimizer/Utils/Local.h" -#include "swift/SILOptimizer/Utils/CFG.h" -#include "swift/SILOptimizer/Analysis/Analysis.h" -#include "swift/SILOptimizer/Analysis/ARCAnalysis.h" -#include "swift/SILOptimizer/Analysis/DominanceAnalysis.h" -#include "swift/AST/GenericSignature.h" -#include "swift/AST/SubstitutionMap.h" -#include "swift/SIL/DynamicCasts.h" -#include "swift/SIL/SILArgument.h" -#include "swift/SIL/SILBuilder.h" -#include "swift/SIL/SILModule.h" -#include "swift/SIL/SILUndef.h" -#include "swift/SIL/TypeLowering.h" -#include "swift/SIL/DebugUtils.h" -#include "swift/SIL/InstructionUtils.h" -#include "swift/SIL/BasicBlockUtils.h" -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/IR/Intrinsics.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/Compiler.h" -#include - -using namespace swift; - -static llvm::cl::opt EnableExpandAll("enable-expand-all", - llvm::cl::init(false)); - -/// Creates an increment on \p Ptr before insertion point \p InsertPt that -/// creates a strong_retain if \p Ptr has reference semantics itself or a -/// retain_value if \p Ptr is a non-trivial value without reference-semantics. -NullablePtr -swift::createIncrementBefore(SILValue Ptr, SILInstruction *InsertPt) { - // Set up the builder we use to insert at our insertion point. - SILBuilder B(InsertPt); - auto Loc = RegularLocation::getAutoGeneratedLocation(); - - // If we have a trivial type, just bail, there is no work to do. - if (Ptr->getType().isTrivial(B.getFunction())) - return nullptr; - - // If Ptr is refcounted itself, create the strong_retain and - // return. - if (Ptr->getType().isReferenceCounted(B.getModule())) { - if (Ptr->getType().is()) - return B.createUnownedRetain(Loc, Ptr, B.getDefaultAtomicity()); - else - return B.createStrongRetain(Loc, Ptr, B.getDefaultAtomicity()); - } - - // Otherwise, create the retain_value. - return B.createRetainValue(Loc, Ptr, B.getDefaultAtomicity()); -} - -/// Creates a decrement on \p Ptr before insertion point \p InsertPt that -/// creates a strong_release if \p Ptr has reference semantics itself or -/// a release_value if \p Ptr is a non-trivial value without reference-semantics. -NullablePtr -swift::createDecrementBefore(SILValue Ptr, SILInstruction *InsertPt) { - // Setup the builder we will use to insert at our insertion point. - SILBuilder B(InsertPt); - auto Loc = RegularLocation::getAutoGeneratedLocation(); - - if (Ptr->getType().isTrivial(B.getFunction())) - return nullptr; - - // If Ptr has reference semantics itself, create a strong_release. - if (Ptr->getType().isReferenceCounted(B.getModule())) { - if (Ptr->getType().is()) - return B.createUnownedRelease(Loc, Ptr, B.getDefaultAtomicity()); - else - return B.createStrongRelease(Loc, Ptr, B.getDefaultAtomicity()); - } - - // Otherwise create a release value. - return B.createReleaseValue(Loc, Ptr, B.getDefaultAtomicity()); -} - -/// Perform a fast local check to see if the instruction is dead. -/// -/// This routine only examines the state of the instruction at hand. -bool -swift::isInstructionTriviallyDead(SILInstruction *I) { - // At Onone, consider all uses, including the debug_info. - // This way, debug_info is preserved at Onone. - if (I->hasUsesOfAnyResult() && - I->getFunction()->getEffectiveOptimizationMode() <= - OptimizationMode::NoOptimization) - return false; - - if (!onlyHaveDebugUsesOfAllResults(I) || isa(I)) - return false; - - if (auto *BI = dyn_cast(I)) { - // Although the onFastPath builtin has no side-effects we don't want to - // remove it. - if (BI->getBuiltinInfo().ID == BuiltinValueKind::OnFastPath) - return false; - return !BI->mayHaveSideEffects(); - } - - // condfail instructions that obviously can't fail are dead. - if (auto *CFI = dyn_cast(I)) - if (auto *ILI = dyn_cast(CFI->getOperand())) - if (!ILI->getValue()) - return true; - - // mark_uninitialized is never dead. - if (isa(I)) - return false; - - if (isa(I) || isa(I)) - return false; - - // These invalidate enums so "write" memory, but that is not an essential - // operation so we can remove these if they are trivially dead. - if (isa(I)) - return true; - - if (!I->mayHaveSideEffects()) - return true; - - return false; -} - -/// Return true if this is a release instruction and the released value -/// is a part of a guaranteed parameter. -bool swift::isIntermediateRelease(SILInstruction *I, - EpilogueARCFunctionInfo *EAFI) { - // Check whether this is a release instruction. - if (!isa(I) && !isa(I)) - return false; - - // OK. we have a release instruction. - // Check whether this is a release on part of a guaranteed function argument. - SILValue Op = stripValueProjections(I->getOperand(0)); - auto *Arg = dyn_cast(Op); - if (!Arg) - return false; - - // This is a release on a guaranteed parameter. Its not the final release. - if (Arg->hasConvention(SILArgumentConvention::Direct_Guaranteed)) - return true; - - // This is a release on an owned parameter and its not the epilogue release. - // Its not the final release. - auto Rel = EAFI->computeEpilogueARCInstructions( - EpilogueARCContext::EpilogueARCKind::Release, Arg); - if (Rel.size() && !Rel.count(I)) - return true; - - // Failed to prove anything. - return false; -} - -namespace { - using CallbackTy = llvm::function_ref; -} // end anonymous namespace - -void swift::recursivelyDeleteTriviallyDeadInstructions( - ArrayRef IA, bool Force, CallbackTy Callback) { - // Delete these instruction and others that become dead after it's deleted. - llvm::SmallPtrSet DeadInsts; - for (auto I : IA) { - // If the instruction is not dead and force is false, do nothing. - if (Force || isInstructionTriviallyDead(I)) - DeadInsts.insert(I); - } - llvm::SmallPtrSet NextInsts; - while (!DeadInsts.empty()) { - for (auto I : DeadInsts) { - // Call the callback before we mutate the to be deleted instruction in any - // way. - Callback(I); - - // Check if any of the operands will become dead as well. - MutableArrayRef Ops = I->getAllOperands(); - for (Operand &Op : Ops) { - SILValue OpVal = Op.get(); - if (!OpVal) - continue; - - // Remove the reference from the instruction being deleted to this - // operand. - Op.drop(); - - // If the operand is an instruction that is only used by the instruction - // being deleted, delete it. - if (auto *OpValInst = OpVal->getDefiningInstruction()) - if (!DeadInsts.count(OpValInst) && - isInstructionTriviallyDead(OpValInst)) - NextInsts.insert(OpValInst); - } - - // If we have a function ref inst, we need to especially drop its function - // argument so that it gets a proper ref decrement. - auto *FRI = dyn_cast(I); - if (FRI && FRI->getInitiallyReferencedFunction()) - FRI->dropReferencedFunction(); - - auto *DFRI = dyn_cast(I); - if (DFRI && DFRI->getInitiallyReferencedFunction()) - DFRI->dropReferencedFunction(); - - auto *PFRI = dyn_cast(I); - if (PFRI && PFRI->getInitiallyReferencedFunction()) - PFRI->dropReferencedFunction(); - } - - for (auto I : DeadInsts) { - // This will remove this instruction and all its uses. - eraseFromParentWithDebugInsts(I, Callback); - } - - NextInsts.swap(DeadInsts); - NextInsts.clear(); - } -} - -/// If the given instruction is dead, delete it along with its dead -/// operands. -/// -/// \param I The instruction to be deleted. -/// \param Force If Force is set, don't check if the top level instruction is -/// considered dead - delete it regardless. -void swift::recursivelyDeleteTriviallyDeadInstructions(SILInstruction *I, - bool Force, - CallbackTy Callback) { - ArrayRef AI = ArrayRef(I); - recursivelyDeleteTriviallyDeadInstructions(AI, Force, Callback); -} - -void swift::eraseUsesOfInstruction(SILInstruction *Inst, - CallbackTy Callback) { - for (auto result : Inst->getResults()) { - while (!result->use_empty()) { - auto UI = result->use_begin(); - auto *User = UI->getUser(); - assert(User && "User should never be NULL!"); - - // If the instruction itself has any uses, recursively zap them so that - // nothing uses this instruction. - eraseUsesOfInstruction(User, Callback); - - // Walk through the operand list and delete any random instructions that - // will become trivially dead when this instruction is removed. - - for (auto &Op : User->getAllOperands()) { - if (auto *OpI = Op.get()->getDefiningInstruction()) { - // Don't recursively delete the instruction we're working on. - // FIXME: what if we're being recursively invoked? - if (OpI != Inst) { - Op.drop(); - recursivelyDeleteTriviallyDeadInstructions(OpI, false, Callback); - } - } - } - Callback(User); - User->eraseFromParent(); - } - } -} - -void swift:: -collectUsesOfValue(SILValue V, llvm::SmallPtrSetImpl &Insts) { - for (auto UI = V->use_begin(), E = V->use_end(); UI != E; UI++) { - auto *User = UI->getUser(); - // Instruction has been processed. - if (!Insts.insert(User).second) - continue; - - // Collect the users of this instruction. - for (auto result : User->getResults()) - collectUsesOfValue(result, Insts); - } -} - -void swift::eraseUsesOfValue(SILValue V) { - llvm::SmallPtrSet Insts; - // Collect the uses. - collectUsesOfValue(V, Insts); - // Erase the uses, we can have instructions that become dead because - // of the removal of these instructions, leave to DCE to cleanup. - // Its not safe to do recursively delete here as some of the SILInstruction - // maybe tracked by this set. - for (auto I : Insts) { - I->replaceAllUsesOfAllResultsWithUndef(); - I->eraseFromParent(); - } -} - -// Devirtualization of functions with covariant return types produces -// a result that is not an apply, but takes an apply as an -// argument. Attempt to dig the apply out from this result. -FullApplySite swift::findApplyFromDevirtualizedResult(SILValue V) { - if (auto Apply = FullApplySite::isa(V)) - return Apply; - - if (isa(V) || isa(V) || isa(V)) - return findApplyFromDevirtualizedResult( - cast(V)->getOperand(0)); - - return FullApplySite(); -} - -bool swift::mayBindDynamicSelf(SILFunction *F) { - if (!F->hasSelfMetadataParam()) - return false; - - SILValue MDArg = F->getSelfMetadataArgument(); - - for (Operand *MDUse : F->getSelfMetadataArgument()->getUses()) { - SILInstruction *MDUser = MDUse->getUser(); - for (Operand &TypeDepOp : MDUser->getTypeDependentOperands()) { - if (TypeDepOp.get() == MDArg) - return true; - } - } - return false; -} - -static SILValue skipAddrProjections(SILValue V) { - for (;;) { - switch (V->getKind()) { - case ValueKind::IndexAddrInst: - case ValueKind::IndexRawPointerInst: - case ValueKind::StructElementAddrInst: - case ValueKind::TupleElementAddrInst: - V = cast(V)->getOperand(0); - break; - default: - return V; - } - } - llvm_unreachable("there is no escape from an infinite loop"); -} - -/// Check whether the \p addr is an address of a tail-allocated array element. -bool swift::isAddressOfArrayElement(SILValue addr) { - addr = stripAddressProjections(addr); - if (auto *MD = dyn_cast(addr)) - addr = stripAddressProjections(MD->getValue()); - - // High-level SIL: check for an get_element_address array semantics call. - if (auto *PtrToAddr = dyn_cast(addr)) - if (auto *SEI = dyn_cast(PtrToAddr->getOperand())) { - ArraySemanticsCall Call(SEI->getOperand()); - if (Call && Call.getKind() == ArrayCallKind::kGetElementAddress) - return true; - } - - // Check for an tail-address (of an array buffer object). - if (isa(skipAddrProjections(addr))) - return true; - - return false; -} - -/// Find a new position for an ApplyInst's FuncRef so that it dominates its -/// use. Not that FunctionRefInsts may be shared by multiple ApplyInsts. -void swift::placeFuncRef(ApplyInst *AI, DominanceInfo *DT) { - FunctionRefInst *FuncRef = cast(AI->getCallee()); - SILBasicBlock *DomBB = - DT->findNearestCommonDominator(AI->getParent(), FuncRef->getParent()); - if (DomBB == AI->getParent() && DomBB != FuncRef->getParent()) - // Prefer to place the FuncRef immediately before the call. Since we're - // moving FuncRef up, this must be the only call to it in the block. - FuncRef->moveBefore(AI); - else - // Otherwise, conservatively stick it at the beginning of the block. - FuncRef->moveBefore(&*DomBB->begin()); -} - -/// Add an argument, \p val, to the branch-edge that is pointing into -/// block \p Dest. Return a new instruction and do not erase the old -/// instruction. -TermInst *swift::addArgumentToBranch(SILValue Val, SILBasicBlock *Dest, - TermInst *Branch) { - SILBuilderWithScope Builder(Branch); - - if (auto *CBI = dyn_cast(Branch)) { - SmallVector TrueArgs; - SmallVector FalseArgs; - - for (auto A : CBI->getTrueArgs()) - TrueArgs.push_back(A); - - for (auto A : CBI->getFalseArgs()) - FalseArgs.push_back(A); - - if (Dest == CBI->getTrueBB()) { - TrueArgs.push_back(Val); - assert(TrueArgs.size() == Dest->getNumArguments()); - } else { - FalseArgs.push_back(Val); - assert(FalseArgs.size() == Dest->getNumArguments()); - } - - return Builder.createCondBranch(CBI->getLoc(), CBI->getCondition(), CBI->getTrueBB(), TrueArgs, CBI->getFalseBB(), FalseArgs, CBI->getTrueBBCount(), CBI->getFalseBBCount()); - } - - if (auto *BI = dyn_cast(Branch)) { - SmallVector Args; - - for (auto A : BI->getArgs()) - Args.push_back(A); - - Args.push_back(Val); - assert(Args.size() == Dest->getNumArguments()); - return Builder.createBranch(BI->getLoc(), BI->getDestBB(), Args); - } - - llvm_unreachable("unsupported terminator"); -} - -SILLinkage swift::getSpecializedLinkage(SILFunction *F, SILLinkage L) { - if (hasPrivateVisibility(L) && - !F->isSerialized()) { - // Specializations of private symbols should remain so, unless - // they were serialized, which can only happen when specializing - // definitions from a standard library built with -sil-serialize-all. - return SILLinkage::Private; - } - - return SILLinkage::Shared; -} - -/// Remove all instructions in the body of \p BB in safe manner by using -/// undef. -void swift::clearBlockBody(SILBasicBlock *BB) { - // Instructions in the dead block may be used by other dead blocks. Replace - // any uses of them with undef values. - while (!BB->empty()) { - // Grab the last instruction in the BB. - auto *Inst = &BB->back(); - - // Replace any still-remaining uses with undef values and erase. - Inst->replaceAllUsesOfAllResultsWithUndef(); - Inst->eraseFromParent(); - } -} - -// Handle the mechanical aspects of removing an unreachable block. -void swift::removeDeadBlock(SILBasicBlock *BB) { - // Clear the body of BB. - clearBlockBody(BB); - - // Now that the BB is empty, eliminate it. - BB->eraseFromParent(); -} - -/// Cast a value into the expected, ABI compatible type if necessary. -/// This may happen e.g. when: -/// - a type of the return value is a subclass of the expected return type. -/// - actual return type and expected return type differ in optionality. -/// - both types are tuple-types and some of the elements need to be casted. -/// -/// If CheckOnly flag is set, then this function only checks if the -/// required casting is possible. If it is not possible, then None -/// is returned. -/// -/// If CheckOnly is not set, then a casting code is generated and the final -/// casted value is returned. -/// -/// NOTE: We intentionally combine the checking of the cast's handling possibility -/// and the transformation performing the cast in the same function, to avoid -/// any divergence between the check and the implementation in the future. -/// -/// NOTE: The implementation of this function is very closely related to the -/// rules checked by SILVerifier::requireABICompatibleFunctionTypes. -SILValue swift::castValueToABICompatibleType(SILBuilder *B, SILLocation Loc, - SILValue Value, - SILType SrcTy, SILType DestTy) { - - // No cast is required if types are the same. - if (SrcTy == DestTy) - return Value; - - assert(SrcTy.isAddress() == DestTy.isAddress() && - "Addresses aren't compatible with values"); - - if (SrcTy.isAddress() && DestTy.isAddress()) { - // Cast between two addresses and that's it. - return B->createUncheckedAddrCast(Loc, Value, DestTy); - } - - // If both types are classes and dest is the superclass of src, - // simply perform an upcast. - if (DestTy.isExactSuperclassOf(SrcTy)) { - return B->createUpcast(Loc, Value, DestTy); - } - - if (SrcTy.isHeapObjectReferenceType() && - DestTy.isHeapObjectReferenceType()) { - return B->createUncheckedRefCast(Loc, Value, DestTy); - } - - if (auto mt1 = SrcTy.getAs()) { - if (auto mt2 = DestTy.getAs()) { - if (mt1->getRepresentation() == mt2->getRepresentation()) { - // If B.Type needs to be casted to A.Type and - // A is a superclass of B, then it can be done by means - // of a simple upcast. - if (mt2.getInstanceType()->isExactSuperclassOf( - mt1.getInstanceType())) { - return B->createUpcast(Loc, Value, DestTy); - } - - // Cast between two metatypes and that's it. - return B->createUncheckedBitCast(Loc, Value, DestTy); - } - } - } - - // Check if src and dest types are optional. - auto OptionalSrcTy = SrcTy.getOptionalObjectType(); - auto OptionalDestTy = DestTy.getOptionalObjectType(); - - // Both types are optional. - if (OptionalDestTy && OptionalSrcTy) { - // If both wrapped types are classes and dest is the superclass of src, - // simply perform an upcast. - if (OptionalDestTy.isExactSuperclassOf(OptionalSrcTy)) { - // Insert upcast. - return B->createUpcast(Loc, Value, DestTy); - } - - // Unwrap the original optional value. - auto *SomeDecl = B->getASTContext().getOptionalSomeDecl(); - auto *NoneBB = B->getFunction().createBasicBlock(); - auto *SomeBB = B->getFunction().createBasicBlock(); - auto *CurBB = B->getInsertionPoint()->getParent(); - - auto *ContBB = CurBB->split(B->getInsertionPoint()); - ContBB->createPhiArgument(DestTy, ValueOwnershipKind::Owned); - - SmallVector, 1> CaseBBs; - CaseBBs.push_back(std::make_pair(SomeDecl, SomeBB)); - B->setInsertionPoint(CurBB); - B->createSwitchEnum(Loc, Value, NoneBB, CaseBBs); - - // Handle the Some case. - B->setInsertionPoint(SomeBB); - SILValue UnwrappedValue = B->createUncheckedEnumData(Loc, Value, - SomeDecl); - // Cast the unwrapped value. - auto CastedUnwrappedValue = - castValueToABICompatibleType(B, Loc, UnwrappedValue, - OptionalSrcTy, - OptionalDestTy); - // Wrap into optional. - auto CastedValue = B->createOptionalSome(Loc, CastedUnwrappedValue, DestTy); - B->createBranch(Loc, ContBB, {CastedValue}); - - // Handle the None case. - B->setInsertionPoint(NoneBB); - CastedValue = B->createOptionalNone(Loc, DestTy); - B->createBranch(Loc, ContBB, {CastedValue}); - B->setInsertionPoint(ContBB->begin()); - - return ContBB->getArgument(0); - } - - // Src is not optional, but dest is optional. - if (!OptionalSrcTy && OptionalDestTy) { - auto OptionalSrcCanTy = OptionalType::get(SrcTy.getASTType()) - ->getCanonicalType(); - auto LoweredOptionalSrcType = SILType::getPrimitiveObjectType( - OptionalSrcCanTy); - - // Wrap the source value into an optional first. - SILValue WrappedValue = B->createOptionalSome(Loc, Value, - LoweredOptionalSrcType); - // Cast the wrapped value. - return castValueToABICompatibleType(B, Loc, WrappedValue, - WrappedValue->getType(), - DestTy); - } - - // Handle tuple types. - // Extract elements, cast each of them, create a new tuple. - if (auto SrcTupleTy = SrcTy.getAs()) { - SmallVector ExpectedTuple; - for (unsigned i = 0, e = SrcTupleTy->getNumElements(); i < e; i++) { - SILValue Element = B->createTupleExtract(Loc, Value, i); - // Cast the value if necessary. - Element = castValueToABICompatibleType(B, Loc, Element, - SrcTy.getTupleElementType(i), - DestTy.getTupleElementType(i)); - ExpectedTuple.push_back(Element); - } - - return B->createTuple(Loc, DestTy, ExpectedTuple); - } - - // Function types are interchangeable if they're also ABI-compatible. - if (SrcTy.is()) { - if (DestTy.is()) { - assert(SrcTy.getAs()->isNoEscape() == - DestTy.getAs()->isNoEscape() || - SrcTy.getAs()->getRepresentation() != - SILFunctionType::Representation::Thick && - "Swift thick functions that differ in escapeness are not ABI " - "compatible"); - // Insert convert_function. - return B->createConvertFunction(Loc, Value, DestTy, - /*WithoutActuallyEscaping=*/false); - } - } - - llvm::errs() << "Source type: " << SrcTy << "\n"; - llvm::errs() << "Destination type: " << DestTy << "\n"; - llvm_unreachable("Unknown combination of types for casting"); -} - -ProjectBoxInst *swift::getOrCreateProjectBox(AllocBoxInst *ABI, unsigned Index){ - SILBasicBlock::iterator Iter(ABI); - Iter++; - assert(Iter != ABI->getParent()->end() && - "alloc_box cannot be the last instruction of a block"); - SILInstruction *NextInst = &*Iter; - if (auto *PBI = dyn_cast(NextInst)) { - if (PBI->getOperand() == ABI && PBI->getFieldIndex() == Index) - return PBI; - } - - SILBuilder B(NextInst); - return B.createProjectBox(ABI->getLoc(), ABI, Index); -} - -// Peek through trivial Enum initialization, typically for pointless -// Optionals. -// -// Given an UncheckedTakeEnumDataAddrInst, check that there are no -// other uses of the Enum value and return the address used to initialized the -// enum's payload: -// -// %stack_adr = alloc_stack -// %data_adr = init_enum_data_addr %stk_adr -// %enum_adr = inject_enum_addr %stack_adr -// %copy_src = unchecked_take_enum_data_addr %enum_adr -// dealloc_stack %stack_adr -// (No other uses of %stack_adr.) -InitEnumDataAddrInst * -swift::findInitAddressForTrivialEnum(UncheckedTakeEnumDataAddrInst *UTEDAI) { - auto *ASI = dyn_cast(UTEDAI->getOperand()); - if (!ASI) - return nullptr; - - SILInstruction *singleUser = nullptr; - for (auto use : ASI->getUses()) { - auto *user = use->getUser(); - if (user == UTEDAI) - continue; - - // As long as there's only one UncheckedTakeEnumDataAddrInst and one - // InitEnumDataAddrInst, we don't care how many InjectEnumAddr and - // DeallocStack users there are. - if (isa(user) || isa(user)) - continue; - - if (singleUser) - return nullptr; - - singleUser = user; - } - if (!singleUser) - return nullptr; - - // Assume, without checking, that the returned InitEnumDataAddr dominates the - // given UncheckedTakeEnumDataAddrInst, because that's how SIL is defined. I - // don't know where this is actually verified. - return dyn_cast(singleUser); -} - -//===----------------------------------------------------------------------===// -// String Concatenation Optimizer -//===----------------------------------------------------------------------===// - -namespace { -/// This is a helper class that performs optimization of string literals -/// concatenation. -class StringConcatenationOptimizer { - /// Apply instruction being optimized. - ApplyInst *AI; - /// Builder to be used for creation of new instructions. - SILBuilder &Builder; - /// Left string literal operand of a string concatenation. - StringLiteralInst *SLILeft = nullptr; - /// Right string literal operand of a string concatenation. - StringLiteralInst *SLIRight = nullptr; - /// Function used to construct the left string literal. - FunctionRefInst *FRILeft = nullptr; - /// Function used to construct the right string literal. - FunctionRefInst *FRIRight = nullptr; - /// Apply instructions used to construct left string literal. - ApplyInst *AILeft = nullptr; - /// Apply instructions used to construct right string literal. - ApplyInst *AIRight = nullptr; - /// String literal conversion function to be used. - FunctionRefInst *FRIConvertFromBuiltin = nullptr; - /// Result type of a function producing the concatenated string literal. - SILValue FuncResultType; - - /// Internal helper methods - bool extractStringConcatOperands(); - void adjustEncodings(); - APInt getConcatenatedLength(); - bool isAscii() const; - -public: - StringConcatenationOptimizer(ApplyInst *AI, SILBuilder &Builder) - : AI(AI), Builder(Builder) {} - - /// Tries to optimize a given apply instruction if it is a - /// concatenation of string literals. - /// - /// Returns a new instruction if optimization was possible. - SingleValueInstruction *optimize(); -}; - -} // end anonymous namespace - -/// Checks operands of a string concatenation operation to see if -/// optimization is applicable. -/// -/// Returns false if optimization is not possible. -/// Returns true and initializes internal fields if optimization is possible. -bool StringConcatenationOptimizer::extractStringConcatOperands() { - auto *Fn = AI->getReferencedFunctionOrNull(); - if (!Fn) - return false; - - if (AI->getNumArguments() != 3 || !Fn->hasSemanticsAttr("string.concat")) - return false; - - // Left and right operands of a string concatenation operation. - AILeft = dyn_cast(AI->getOperand(1)); - AIRight = dyn_cast(AI->getOperand(2)); - - if (!AILeft || !AIRight) - return false; - - FRILeft = dyn_cast(AILeft->getCallee()); - FRIRight = dyn_cast(AIRight->getCallee()); - - if (!FRILeft || !FRIRight) - return false; - - auto *FRILeftFun = FRILeft->getReferencedFunctionOrNull(); - auto *FRIRightFun = FRIRight->getReferencedFunctionOrNull(); - - if (FRILeftFun->getEffectsKind() >= EffectsKind::ReleaseNone || - FRIRightFun->getEffectsKind() >= EffectsKind::ReleaseNone) - return false; - - if (!FRILeftFun->hasSemanticsAttrs() || !FRIRightFun->hasSemanticsAttrs()) - return false; - - auto AILeftOperandsNum = AILeft->getNumOperands(); - auto AIRightOperandsNum = AIRight->getNumOperands(); - - // makeUTF8 should have following parameters: - // (start: RawPointer, utf8CodeUnitCount: Word, isASCII: Int1) - if (!((FRILeftFun->hasSemanticsAttr("string.makeUTF8") && - AILeftOperandsNum == 5) || - (FRIRightFun->hasSemanticsAttr("string.makeUTF8") && - AIRightOperandsNum == 5))) - return false; - - SLILeft = dyn_cast(AILeft->getOperand(1)); - SLIRight = dyn_cast(AIRight->getOperand(1)); - - if (!SLILeft || !SLIRight) - return false; - - // Only UTF-8 and UTF-16 encoded string literals are supported by this - // optimization. - if (SLILeft->getEncoding() != StringLiteralInst::Encoding::UTF8 && - SLILeft->getEncoding() != StringLiteralInst::Encoding::UTF16) - return false; - - if (SLIRight->getEncoding() != StringLiteralInst::Encoding::UTF8 && - SLIRight->getEncoding() != StringLiteralInst::Encoding::UTF16) - return false; - - return true; -} - -/// Ensures that both string literals to be concatenated use the same -/// UTF encoding. Converts UTF-8 into UTF-16 if required. -void StringConcatenationOptimizer::adjustEncodings() { - if (SLILeft->getEncoding() == SLIRight->getEncoding()) { - FRIConvertFromBuiltin = FRILeft; - if (SLILeft->getEncoding() == StringLiteralInst::Encoding::UTF8) { - FuncResultType = AILeft->getOperand(4); - } else { - FuncResultType = AILeft->getOperand(3); - } - return; - } - - Builder.setCurrentDebugScope(AI->getDebugScope()); - - // If one of the string literals is UTF8 and another one is UTF16, - // convert the UTF8-encoded string literal into UTF16-encoding first. - if (SLILeft->getEncoding() == StringLiteralInst::Encoding::UTF8 && - SLIRight->getEncoding() == StringLiteralInst::Encoding::UTF16) { - FuncResultType = AIRight->getOperand(3); - FRIConvertFromBuiltin = FRIRight; - // Convert UTF8 representation into UTF16. - SLILeft = Builder.createStringLiteral(AI->getLoc(), SLILeft->getValue(), - StringLiteralInst::Encoding::UTF16); - } - - if (SLIRight->getEncoding() == StringLiteralInst::Encoding::UTF8 && - SLILeft->getEncoding() == StringLiteralInst::Encoding::UTF16) { - FuncResultType = AILeft->getOperand(3); - FRIConvertFromBuiltin = FRILeft; - // Convert UTF8 representation into UTF16. - SLIRight = Builder.createStringLiteral(AI->getLoc(), SLIRight->getValue(), - StringLiteralInst::Encoding::UTF16); - } - - // It should be impossible to have two operands with different - // encodings at this point. - assert(SLILeft->getEncoding() == SLIRight->getEncoding() && - "Both operands of string concatenation should have the same encoding"); -} - -/// Computes the length of a concatenated string literal. -APInt StringConcatenationOptimizer::getConcatenatedLength() { - // Real length of string literals computed based on its contents. - // Length is in code units. - auto SLILenLeft = SLILeft->getCodeUnitCount(); - (void) SLILenLeft; - auto SLILenRight = SLIRight->getCodeUnitCount(); - (void) SLILenRight; - - // Length of string literals as reported by string.make functions. - auto *LenLeft = dyn_cast(AILeft->getOperand(2)); - auto *LenRight = dyn_cast(AIRight->getOperand(2)); - - // Real and reported length should be the same. - assert(SLILenLeft == LenLeft->getValue() && - "Size of string literal in @_semantics(string.make) is wrong"); - - assert(SLILenRight == LenRight->getValue() && - "Size of string literal in @_semantics(string.make) is wrong"); - - - // Compute length of the concatenated literal. - return LenLeft->getValue() + LenRight->getValue(); -} - -/// Computes the isAscii flag of a concatenated UTF8-encoded string literal. -bool StringConcatenationOptimizer::isAscii() const{ - // Add the isASCII argument in case of UTF8. - // IsASCII is true only if IsASCII of both literals is true. - auto *AsciiLeft = dyn_cast(AILeft->getOperand(3)); - auto *AsciiRight = dyn_cast(AIRight->getOperand(3)); - auto IsAsciiLeft = AsciiLeft->getValue() == 1; - auto IsAsciiRight = AsciiRight->getValue() == 1; - return IsAsciiLeft && IsAsciiRight; -} - -SingleValueInstruction *StringConcatenationOptimizer::optimize() { - // Bail out if string literals concatenation optimization is - // not possible. - if (!extractStringConcatOperands()) - return nullptr; - - // Perform string literal encodings adjustments if needed. - adjustEncodings(); - - // Arguments of the new StringLiteralInst to be created. - SmallVector Arguments; - - // Encoding to be used for the concatenated string literal. - auto Encoding = SLILeft->getEncoding(); - - // Create a concatenated string literal. - Builder.setCurrentDebugScope(AI->getDebugScope()); - auto LV = SLILeft->getValue(); - auto RV = SLIRight->getValue(); - auto *NewSLI = - Builder.createStringLiteral(AI->getLoc(), LV + Twine(RV), Encoding); - Arguments.push_back(NewSLI); - - // Length of the concatenated literal according to its encoding. - auto *Len = Builder.createIntegerLiteral( - AI->getLoc(), AILeft->getOperand(2)->getType(), getConcatenatedLength()); - Arguments.push_back(Len); - - // isAscii flag for UTF8-encoded string literals. - if (Encoding == StringLiteralInst::Encoding::UTF8) { - bool IsAscii = isAscii(); - auto ILType = AILeft->getOperand(3)->getType(); - auto *Ascii = - Builder.createIntegerLiteral(AI->getLoc(), ILType, intmax_t(IsAscii)); - Arguments.push_back(Ascii); - } - - // Type. - Arguments.push_back(FuncResultType); - - return Builder.createApply(AI->getLoc(), FRIConvertFromBuiltin, - SubstitutionMap(), Arguments); -} - -/// Top level entry point -SingleValueInstruction * -swift::tryToConcatenateStrings(ApplyInst *AI, SILBuilder &B) { - return StringConcatenationOptimizer(AI, B).optimize(); -} - -//===----------------------------------------------------------------------===// -// Closure Deletion -//===----------------------------------------------------------------------===// - -/// NOTE: Instructions with transitive ownership kind are assumed to not keep -/// the underlying closure alive as well. This is meant for instructions only -/// with non-transitive users. -static bool useDoesNotKeepClosureAlive(const SILInstruction *I) { - switch (I->getKind()) { - case SILInstructionKind::StrongRetainInst: - case SILInstructionKind::StrongReleaseInst: - case SILInstructionKind::DestroyValueInst: - case SILInstructionKind::RetainValueInst: - case SILInstructionKind::ReleaseValueInst: - case SILInstructionKind::DebugValueInst: - case SILInstructionKind::EndBorrowInst: - return true; - default: - return false; - } -} - -static bool useHasTransitiveOwnership(const SILInstruction *I) { - // convert_escape_to_noescape is used to convert to a @noescape function type. - // It does not change ownership of the function value. - if (isa(I)) - return true; - - // Look through copy_value, begin_borrow. They are inert for our purposes, but - // we need to look through it. - return isa(I) || isa(I); -} - -static SILValue createLifetimeExtendedAllocStack( - SILBuilder &Builder, SILLocation Loc, SILValue Arg, - ArrayRef ExitingBlocks, InstModCallbacks Callbacks) { - AllocStackInst *ASI = nullptr; - { - // Save our insert point and create a new alloc_stack in the initial BB and - // dealloc_stack in all exit blocks. - auto *OldInsertPt = &*Builder.getInsertionPoint(); - Builder.setInsertionPoint(Builder.getFunction().begin()->begin()); - ASI = Builder.createAllocStack(Loc, Arg->getType()); - Callbacks.CreatedNewInst(ASI); - - for (auto *BB : ExitingBlocks) { - Builder.setInsertionPoint(BB->getTerminator()); - Callbacks.CreatedNewInst(Builder.createDeallocStack(Loc, ASI)); - } - Builder.setInsertionPoint(OldInsertPt); - } - assert(ASI != nullptr); - - // Then perform a copy_addr [take] [init] right after the partial_apply from - // the original address argument to the new alloc_stack that we have - // created. - Callbacks.CreatedNewInst( - Builder.createCopyAddr(Loc, Arg, ASI, IsTake, IsInitialization)); - - // Return the new alloc_stack inst that has the appropriate live range to - // destroy said values. - return ASI; -} - -static bool shouldDestroyPartialApplyCapturedArg(SILValue Arg, - SILParameterInfo PInfo, - const SILFunction &F) { - // If we have a non-trivial type and the argument is passed in @inout, we do - // not need to destroy it here. This is something that is implicit in the - // partial_apply design that will be revisited when partial_apply is - // redesigned. - if (PInfo.isIndirectMutating()) - return false; - - // If we have a trivial type, we do not need to put in any extra releases. - if (Arg->getType().isTrivial(F)) - return false; - - // We handle all other cases. - return true; -} - -// *HEY YOU, YES YOU, PLEASE READ*. Even though a textual partial apply is -// printed with the convention of the closed over function upon it, all -// non-inout arguments to a partial_apply are passed at +1. This includes -// arguments that will eventually be passed as guaranteed or in_guaranteed to -// the closed over function. This is because the partial apply is building up a -// boxed aggregate to send off to the closed over function. Of course when you -// call the function, the proper conventions will be used. -void swift::releasePartialApplyCapturedArg(SILBuilder &Builder, SILLocation Loc, - SILValue Arg, SILParameterInfo PInfo, - InstModCallbacks Callbacks) { - if (!shouldDestroyPartialApplyCapturedArg(Arg, PInfo, Builder.getFunction())) - return; - - // Otherwise, we need to destroy the argument. If we have an address, we - // insert a destroy_addr and return. Any live range issues must have been - // dealt with by our caller. - if (Arg->getType().isAddress()) { - // Then emit the destroy_addr for this arg - SILInstruction *NewInst = Builder.emitDestroyAddrAndFold(Loc, Arg); - Callbacks.CreatedNewInst(NewInst); - return; - } - - // Otherwise, we have an object. We emit the most optimized form of release - // possible for that value. - - // If we have qualified ownership, we should just emit a destroy value. - if (Arg->getFunction()->hasOwnership()) { - Callbacks.CreatedNewInst(Builder.createDestroyValue(Loc, Arg)); - return; - } - - if (Arg->getType().hasReferenceSemantics()) { - auto U = Builder.emitStrongRelease(Loc, Arg); - if (U.isNull()) - return; - - if (auto *SRI = U.dyn_cast()) { - Callbacks.DeleteInst(SRI); - return; - } - - Callbacks.CreatedNewInst(U.get()); - return; - } - - auto U = Builder.emitReleaseValue(Loc, Arg); - if (U.isNull()) - return; - - if (auto *RVI = U.dyn_cast()) { - Callbacks.DeleteInst(RVI); - return; - } - - Callbacks.CreatedNewInst(U.get()); -} - -/// For each captured argument of PAI, decrement the ref count of the captured -/// argument as appropriate at each of the post dominated release locations -/// found by Tracker. -static bool releaseCapturedArgsOfDeadPartialApply(PartialApplyInst *PAI, - ReleaseTracker &Tracker, - InstModCallbacks Callbacks) { - SILBuilderWithScope Builder(PAI); - SILLocation Loc = PAI->getLoc(); - CanSILFunctionType PAITy = - PAI->getCallee()->getType().getAs(); - - ArrayRef Params = PAITy->getParameters(); - llvm::SmallVector Args; - for (SILValue v : PAI->getArguments()) { - // If any of our arguments contain open existentials, bail. We do not - // support this for now so that we can avoid having to re-order stack - // locations (a larger change). - if (v->getType().hasOpenedExistential()) - return false; - Args.emplace_back(v); - } - unsigned Delta = Params.size() - Args.size(); - assert(Delta <= Params.size() && "Error, more Args to partial apply than " - "params in its interface."); - Params = Params.drop_front(Delta); - - llvm::SmallVector ExitingBlocks; - PAI->getFunction()->findExitingBlocks(ExitingBlocks); - - // Go through our argument list and create new alloc_stacks for each - // non-trivial address value. This ensures that the memory location that we - // are cleaning up has the same live range as the partial_apply. Otherwise, we - // may be inserting destroy_addr of alloc_stack that have already been passed - // to a dealloc_stack. - for (unsigned i : reversed(indices(Args))) { - SILValue Arg = Args[i]; - SILParameterInfo PInfo = Params[i]; - - // If we are not going to destroy this partial_apply, continue. - if (!shouldDestroyPartialApplyCapturedArg(Arg, PInfo, Builder.getFunction())) - continue; - - // If we have an object, we will not have live range issues, just continue. - if (Arg->getType().isObject()) - continue; - - // Now that we know that we have a non-argument address, perform a take-init - // of Arg into a lifetime extended alloc_stack - Args[i] = createLifetimeExtendedAllocStack(Builder, Loc, Arg, ExitingBlocks, - Callbacks); - } - - // Emit a destroy for each captured closure argument at each final release - // point. - for (auto *FinalRelease : Tracker.getFinalReleases()) { - Builder.setInsertionPoint(FinalRelease); - Builder.setCurrentDebugScope(FinalRelease->getDebugScope()); - for (unsigned i : indices(Args)) { - SILValue Arg = Args[i]; - SILParameterInfo Param = Params[i]; - - releasePartialApplyCapturedArg(Builder, Loc, Arg, Param, Callbacks); - } - } - - return true; -} - -static bool -deadMarkDependenceUser(SILInstruction *Inst, - SmallVectorImpl &DeleteInsts) { - if (!isa(Inst)) - return false; - DeleteInsts.push_back(Inst); - for (auto *Use : cast(Inst)->getUses()) { - if (!deadMarkDependenceUser(Use->getUser(), DeleteInsts)) - return false; - } - return true; -} - -/// TODO: Generalize this to general objects. -bool swift::tryDeleteDeadClosure(SingleValueInstruction *Closure, - InstModCallbacks Callbacks) { - auto *PA = dyn_cast(Closure); - - // We currently only handle locally identified values that do not escape. We - // also assume that the partial apply does not capture any addresses. - if (!PA && !isa(Closure)) - return false; - - // A stack allocated partial apply does not have any release users. Delete it - // if the only users are the dealloc_stack and mark_dependence instructions. - if (PA && PA->isOnStack()) { - SmallVector DeleteInsts; - for (auto *Use : PA->getUses()) { - if (isa(Use->getUser()) || - isa(Use->getUser())) - DeleteInsts.push_back(Use->getUser()); - else if (!deadMarkDependenceUser(Use->getUser(), DeleteInsts)) - return false; - } - for (auto *Inst : reverse(DeleteInsts)) - Callbacks.DeleteInst(Inst); - Callbacks.DeleteInst(PA); - - // Note: the lifetime of the captured arguments is managed outside of the - // trivial closure value i.e: there will already be releases for the - // captured arguments. Releasing captured arguments is not necessary. - return true; - } - - // We only accept a user if it is an ARC object that can be removed if the - // object is dead. This should be expanded in the future. This also ensures - // that we are locally identified and non-escaping since we only allow for - // specific ARC users. - ReleaseTracker Tracker(useDoesNotKeepClosureAlive, useHasTransitiveOwnership); - - // Find the ARC Users and the final retain, release. - if (!getFinalReleasesForValue(SILValue(Closure), Tracker)) - return false; - - // If we have a partial_apply, release each captured argument at each one of - // the final release locations of the partial apply. - if (auto *PAI = dyn_cast(Closure)) { - // If we can not decrement the ref counts of the dead partial apply for any - // reason, bail. - if (!releaseCapturedArgsOfDeadPartialApply(PAI, Tracker, Callbacks)) - return false; - } - - // Then delete all user instructions in reverse so that leaf uses are deleted - // first. - for (auto *User : reverse(Tracker.getTrackedUsers())) { - assert(User->getResults().empty() || - useHasTransitiveOwnership(User) && - "We expect only ARC operations without " - "results or a cast from escape to noescape without users"); - Callbacks.DeleteInst(User); - } - - // Finally delete the closure. - Callbacks.DeleteInst(Closure); - - return true; -} - -//===----------------------------------------------------------------------===// -// Value Lifetime -//===----------------------------------------------------------------------===// - -void ValueLifetimeAnalysis::propagateLiveness() { - assert(LiveBlocks.empty() && "frontier computed twice"); - - auto DefBB = DefValue->getParentBlock(); - llvm::SmallVector Worklist; - int NumUsersBeforeDef = 0; - - // Find the initial set of blocks where the value is live, because - // it is used in those blocks. - for (SILInstruction *User : UserSet) { - SILBasicBlock *UserBlock = User->getParent(); - if (LiveBlocks.insert(UserBlock)) - Worklist.push_back(UserBlock); - - // A user in the DefBB could potentially be located before the DefValue. - if (UserBlock == DefBB) - NumUsersBeforeDef++; - } - // Don't count any users in the DefBB which are actually located _after_ - // the DefValue. - auto InstIter = DefValue->getIterator(); - while (NumUsersBeforeDef > 0 && ++InstIter != DefBB->end()) { - if (UserSet.count(&*InstIter)) - NumUsersBeforeDef--; - } - - // Now propagate liveness backwards until we hit the block that defines the - // value. - while (!Worklist.empty()) { - auto *BB = Worklist.pop_back_val(); - - // Don't go beyond the definition. - if (BB == DefBB && NumUsersBeforeDef == 0) - continue; - - for (SILBasicBlock *Pred : BB->getPredecessorBlocks()) { - // If it's already in the set, then we've already queued and/or - // processed the predecessors. - if (LiveBlocks.insert(Pred)) - Worklist.push_back(Pred); - } - } -} - -SILInstruction *ValueLifetimeAnalysis:: findLastUserInBlock(SILBasicBlock *BB) { - // Walk backwards in BB looking for last use of the value. - for (auto II = BB->rbegin(); II != BB->rend(); ++II) { - assert(DefValue != &*II && "Found def before finding use!"); - - if (UserSet.count(&*II)) - return &*II; - } - llvm_unreachable("Expected to find use of value in block!"); -} - -bool ValueLifetimeAnalysis::computeFrontier(Frontier &Fr, Mode mode, - DeadEndBlocks *DEBlocks) { - assert(!isAliveAtBeginOfBlock(DefValue->getFunction()->getEntryBlock()) && - "Can't compute frontier for def which does not dominate all uses"); - - bool NoCriticalEdges = true; - - // Exit-blocks from the lifetime region. The value is live at the end of - // a predecessor block but not in the frontier block itself. - llvm::SmallSetVector FrontierBlocks; - - // Blocks where the value is live at the end of the block and which have - // a frontier block as successor. - llvm::SmallSetVector LiveOutBlocks; - - /// The lifetime ends if we have a live block and a not-live successor. - for (SILBasicBlock *BB : LiveBlocks) { - if (DEBlocks && DEBlocks->isDeadEnd(BB)) - continue; - - bool LiveInSucc = false; - bool DeadInSucc = false; - for (const SILSuccessor &Succ : BB->getSuccessors()) { - if (isAliveAtBeginOfBlock(Succ)) { - LiveInSucc = true; - } else if (!DEBlocks || !DEBlocks->isDeadEnd(Succ)) { - DeadInSucc = true; - } - } - if (!LiveInSucc) { - // The value is not live in any of the successor blocks. This means the - // block contains a last use of the value. The next instruction after - // the last use is part of the frontier. - SILInstruction *LastUser = findLastUserInBlock(BB); - if (!isa(LastUser)) { - Fr.push_back(&*std::next(LastUser->getIterator())); - continue; - } - // In case the last user is a TermInst we add all successor blocks to the - // frontier (see below). - assert(DeadInSucc && "The final using TermInst must have successors"); - } - if (DeadInSucc) { - if (mode == UsersMustPostDomDef) - return false; - - // The value is not live in some of the successor blocks. - LiveOutBlocks.insert(BB); - for (const SILSuccessor &Succ : BB->getSuccessors()) { - if (!isAliveAtBeginOfBlock(Succ)) { - // It's an "exit" edge from the lifetime region. - FrontierBlocks.insert(Succ); - } - } - } - } - // Handle "exit" edges from the lifetime region. - llvm::SmallPtrSet UnhandledFrontierBlocks; - for (SILBasicBlock *FrontierBB: FrontierBlocks) { - assert(mode != UsersMustPostDomDef); - bool needSplit = false; - // If the value is live only in part of the predecessor blocks we have to - // split those predecessor edges. - for (SILBasicBlock *Pred : FrontierBB->getPredecessorBlocks()) { - if (!LiveOutBlocks.count(Pred)) { - needSplit = true; - break; - } - } - if (needSplit) { - if (mode == DontModifyCFG) - return false; - // We need to split the critical edge to create a frontier instruction. - UnhandledFrontierBlocks.insert(FrontierBB); - } else { - // The first instruction of the exit-block is part of the frontier. - Fr.push_back(&*FrontierBB->begin()); - } - } - // Split critical edges from the lifetime region to not yet handled frontier - // blocks. - for (SILBasicBlock *FrontierPred : LiveOutBlocks) { - assert(mode != UsersMustPostDomDef); - auto *T = FrontierPred->getTerminator(); - // Cache the successor blocks because splitting critical edges invalidates - // the successor list iterator of T. - llvm::SmallVector SuccBlocks; - for (const SILSuccessor &Succ : T->getSuccessors()) - SuccBlocks.push_back(Succ); - - for (unsigned i = 0, e = SuccBlocks.size(); i != e; ++i) { - if (UnhandledFrontierBlocks.count(SuccBlocks[i])) { - assert(mode == AllowToModifyCFG); - assert(isCriticalEdge(T, i) && "actually not a critical edge?"); - SILBasicBlock *NewBlock = splitEdge(T, i); - // The single terminator instruction is part of the frontier. - Fr.push_back(&*NewBlock->begin()); - NoCriticalEdges = false; - } - } - } - return NoCriticalEdges; -} - -bool ValueLifetimeAnalysis::isWithinLifetime(SILInstruction *Inst) { - SILBasicBlock *BB = Inst->getParent(); - // Check if the value is not live anywhere in Inst's block. - if (!LiveBlocks.count(BB)) - return false; - for (const SILSuccessor &Succ : BB->getSuccessors()) { - // If the value is live at the beginning of any successor block it is also - // live at the end of BB and therefore Inst is definitely in the lifetime - // region (Note that we don't check in upward direction against the value's - // definition). - if (isAliveAtBeginOfBlock(Succ)) - return true; - } - // The value is live in the block but not at the end of the block. Check if - // Inst is located before (or at) the last use. - for (auto II = BB->rbegin(); II != BB->rend(); ++II) { - if (UserSet.count(&*II)) { - return true; - } - if (Inst == &*II) - return false; - } - llvm_unreachable("Expected to find use of value in block!"); -} - -// Searches \p BB backwards from the instruction before \p FrontierInst -// to the beginning of the list and returns true if we find a dealloc_ref -// /before/ we find \p DefValue (the instruction that defines our target value). -static bool blockContainsDeallocRef(SILBasicBlock *BB, SILInstruction *DefValue, - SILInstruction *FrontierInst) { - SILBasicBlock::reverse_iterator End = BB->rend(); - SILBasicBlock::reverse_iterator Iter = FrontierInst->getReverseIterator(); - for (++Iter; Iter != End; ++Iter) { - SILInstruction *I = &*Iter; - if (isa(I)) - return true; - if (I == DefValue) - return false; - } - return false; -} - -bool ValueLifetimeAnalysis::containsDeallocRef(const Frontier &Frontier) { - SmallPtrSet FrontierBlocks; - // Search in live blocks where the value is not alive until the end of the - // block, i.e. the live range is terminated by a frontier instruction. - for (SILInstruction *FrontierInst : Frontier) { - SILBasicBlock *BB = FrontierInst->getParent(); - if (blockContainsDeallocRef(BB, DefValue, FrontierInst)) - return true; - FrontierBlocks.insert(BB); - } - // Search in all other live blocks where the value is alive until the end of - // the block. - for (SILBasicBlock *BB : LiveBlocks) { - if (FrontierBlocks.count(BB) == 0) { - if (blockContainsDeallocRef(BB, DefValue, BB->getTerminator())) - return true; - } - } - return false; -} - -void ValueLifetimeAnalysis::dump() const { - llvm::errs() << "lifetime of def: " << *DefValue; - for (SILInstruction *Use : UserSet) { - llvm::errs() << " use: " << *Use; - } - llvm::errs() << " live blocks:"; - for (SILBasicBlock *BB : LiveBlocks) { - llvm::errs() << ' ' << BB->getDebugID(); - } - llvm::errs() << '\n'; -} - -// FIXME: Remove this. SILCloner should not create critical edges. -bool BasicBlockCloner::splitCriticalEdges(DominanceInfo *DT, - SILLoopInfo *LI) { - bool changed = false; - // Remove any critical edges that the EdgeThreadingCloner may have - // accidentally created. - for (unsigned succIdx = 0, succEnd = origBB->getSuccessors().size(); - succIdx != succEnd; ++succIdx) { - if (nullptr != splitCriticalEdge(origBB->getTerminator(), succIdx, DT, LI)) - changed |= true; - } - for (unsigned succIdx = 0, succEnd = getNewBB()->getSuccessors().size(); - succIdx != succEnd; ++succIdx) { - auto *newBB = - splitCriticalEdge(getNewBB()->getTerminator(), succIdx, DT, LI); - changed |= (newBB != nullptr); - } - return changed; -} - -bool swift::simplifyUsers(SingleValueInstruction *I) { - bool Changed = false; - - for (auto UI = I->use_begin(), UE = I->use_end(); UI != UE; ) { - SILInstruction *User = UI->getUser(); - ++UI; - - auto SVI = dyn_cast(User); - if (!SVI) continue; - - SILValue S = simplifyInstruction(SVI); - if (!S) - continue; - - replaceAllSimplifiedUsesAndErase(SVI, S); - Changed = true; - } - - return Changed; -} - -/// True if a type can be expanded without a significant increase to code size. -bool swift::shouldExpand(SILModule &Module, SILType Ty) { - // FIXME: Expansion - auto Expansion = ResilienceExpansion::Minimal; - - if (Module.Types.getTypeLowering(Ty, Expansion).isAddressOnly()) { - return false; - } - if (EnableExpandAll) { - return true; - } - - unsigned NumFields = Module.Types.countNumberOfFields(Ty, Expansion); - return (NumFields <= 6); -} - -/// Some support functions for the global-opt and let-properties-opts - -// Encapsulate the state used for recursive analysis of a static -// initializer. Discover all the instruction in a use-def graph and return them -// in topological order. -// -// TODO: We should have a DFS utility for this sort of thing so it isn't -// recursive. -class StaticInitializerAnalysis { - SmallVectorImpl &postOrderInstructions; - llvm::SmallDenseSet visited; - int recursionLevel = 0; - -public: - StaticInitializerAnalysis( - SmallVectorImpl &postOrderInstructions) - : postOrderInstructions(postOrderInstructions) {} - - // Perform a recursive DFS on on the use-def graph rooted at `V`. Insert - // values in the `visited` set in preorder. Insert values in - // `postOrderInstructions` in postorder so that the instructions are - // topologically def-use ordered (in execution order). - bool analyze(SILValue RootValue) { - return recursivelyAnalyzeOperand(RootValue); - } - -protected: - bool recursivelyAnalyzeOperand(SILValue V) { - if (!visited.insert(V).second) - return true; - - if (++recursionLevel > 50) - return false; - - // TODO: For multi-result instructions, we could simply insert all result - // values in the visited set here. - auto *I = dyn_cast(V); - if (!I) - return false; - - if (!recursivelyAnalyzeInstruction(I)) - return false; - - postOrderInstructions.push_back(I); - --recursionLevel; - return true; - } - - bool recursivelyAnalyzeInstruction(SILInstruction *I) { - if (auto *SI = dyn_cast(I)) { - // If it is not a struct which is a simple type, bail. - if (!SI->getType().isTrivial(*SI->getFunction())) - return false; - - return llvm::all_of(SI->getAllOperands(), [&](Operand &Op) -> bool { - return recursivelyAnalyzeOperand(Op.get()); - }); - } - if (auto *TI = dyn_cast(I)) { - // If it is not a tuple which is a simple type, bail. - if (!TI->getType().isTrivial(*TI->getFunction())) - return false; - - return llvm::all_of(TI->getAllOperands(), [&](Operand &Op) -> bool { - return recursivelyAnalyzeOperand(Op.get()); - }); - } - if (auto *bi = dyn_cast(I)) { - switch (bi->getBuiltinInfo().ID) { - case BuiltinValueKind::FPTrunc: - if (auto *LI = dyn_cast(bi->getArguments()[0])) { - return recursivelyAnalyzeOperand(LI); - } - return false; - default: - return false; - } - } - return isa(I) || isa(I) - || isa(I); - } -}; - -/// Check if the value of V is computed by means of a simple initialization. -/// Populate `forwardInstructions` with references to all the instructions -/// that participate in the use-def graph required to compute `V`. The -/// instructions will be in def-use topological order. -bool swift::analyzeStaticInitializer( - SILValue V, SmallVectorImpl &forwardInstructions) { - return StaticInitializerAnalysis(forwardInstructions).analyze(V); -} - -/// FIXME: This must be kept in sync with replaceLoadSequence() -/// below. What a horrible design. -bool swift::canReplaceLoadSequence(SILInstruction *I) { - if (auto *CAI = dyn_cast(I)) - return true; - - if (auto *LI = dyn_cast(I)) - return true; - - if (auto *SEAI = dyn_cast(I)) { - for (auto SEAIUse : SEAI->getUses()) { - if (!canReplaceLoadSequence(SEAIUse->getUser())) - return false; - } - return true; - } - - if (auto *TEAI = dyn_cast(I)) { - for (auto TEAIUse : TEAI->getUses()) { - if (!canReplaceLoadSequence(TEAIUse->getUser())) - return false; - } - return true; - } - - if (auto *BA = dyn_cast(I)) { - for (auto Use : BA->getUses()) { - if (!canReplaceLoadSequence(Use->getUser())) - return false; - } - return true; - } - - // Incidental uses of an address are meaningless with regard to the loaded - // value. - if (isIncidentalUse(I) || isa(I)) - return true; - - return false; -} - -/// Replace load sequence which may contain -/// a chain of struct_element_addr followed by a load. -/// The sequence is traversed inside out, i.e. -/// starting with the innermost struct_element_addr -/// Move into utils. -/// -/// FIXME: this utility does not make sense as an API. How can the caller -/// guarantee that the only uses of `I` are struct_element_addr and -/// tuple_element_addr? -void swift::replaceLoadSequence(SILInstruction *I, - SILValue Value) { - if (auto *CAI = dyn_cast(I)) { - SILBuilder B(CAI); - B.createStore(CAI->getLoc(), Value, CAI->getDest(), - StoreOwnershipQualifier::Unqualified); - return; - } - - if (auto *LI = dyn_cast(I)) { - LI->replaceAllUsesWith(Value); - return; - } - - if (auto *SEAI = dyn_cast(I)) { - SILBuilder B(SEAI); - auto *SEI = B.createStructExtract(SEAI->getLoc(), Value, SEAI->getField()); - for (auto SEAIUse : SEAI->getUses()) { - replaceLoadSequence(SEAIUse->getUser(), SEI); - } - return; - } - - if (auto *TEAI = dyn_cast(I)) { - SILBuilder B(TEAI); - auto *TEI = B.createTupleExtract(TEAI->getLoc(), Value, TEAI->getFieldNo()); - for (auto TEAIUse : TEAI->getUses()) { - replaceLoadSequence(TEAIUse->getUser(), TEI); - } - return; - } - - if (auto *BA = dyn_cast(I)) { - for (auto Use : BA->getUses()) { - replaceLoadSequence(Use->getUser(), Value); - } - return; - } - - // Incidental uses of an addres are meaningless with regard to the loaded - // value. - if (isIncidentalUse(I) || isa(I)) - return; - - llvm_unreachable("Unknown instruction sequence for reading from a global"); -} - -/// Are the callees that could be called through Decl statically -/// knowable based on the Decl and the compilation mode? -bool swift::calleesAreStaticallyKnowable(SILModule &M, SILDeclRef Decl) { - if (Decl.isForeign) - return false; - - const DeclContext *AssocDC = M.getAssociatedContext(); - if (!AssocDC) - return false; - - auto *AFD = Decl.getAbstractFunctionDecl(); - assert(AFD && "Expected abstract function decl!"); - - // Only handle members defined within the SILModule's associated context. - if (!AFD->isChildContextOf(AssocDC)) - return false; - - if (AFD->isDynamic()) { - return false; - } - - if (!AFD->hasAccess()) - return false; - - // Only consider 'private' members, unless we are in whole-module compilation. - switch (AFD->getEffectiveAccess()) { - case AccessLevel::Open: - return false; - case AccessLevel::Public: - if (isa(AFD)) { - // Constructors are special: a derived class in another module can - // "override" a constructor if its class is "open", although the - // constructor itself is not open. - auto *ND = AFD->getDeclContext()->getSelfNominalTypeDecl(); - if (ND->getEffectiveAccess() == AccessLevel::Open) - return false; - } - LLVM_FALLTHROUGH; - case AccessLevel::Internal: - return M.isWholeModule(); - case AccessLevel::FilePrivate: - case AccessLevel::Private: - return true; - } - - llvm_unreachable("Unhandled access level in switch."); -} - -void StaticInitCloner::add(SILInstruction *InitVal) { - // Don't schedule an instruction twice for cloning. - if (NumOpsToClone.count(InitVal) != 0) - return; - - ArrayRef Ops = InitVal->getAllOperands(); - NumOpsToClone[InitVal] = Ops.size(); - if (Ops.empty()) { - // It's an instruction without operands, e.g. a literal. It's ready to be - // cloned first. - ReadyToClone.push_back(InitVal); - } else { - // Recursively add all operands. - for (const Operand &Op : Ops) { - add(cast(Op.get())); - } - } -} - -SingleValueInstruction * -StaticInitCloner::clone(SingleValueInstruction *InitVal) { - assert(NumOpsToClone.count(InitVal) != 0 && "InitVal was not added"); - // Find the right order to clone: all operands of an instruction must be - // cloned before the instruction itself. - while (!ReadyToClone.empty()) { - SILInstruction *I = ReadyToClone.pop_back_val(); - - // Clone the instruction into the SILGlobalVariable - visit(I); - - // Check if users of I can now be cloned. - for (SILValue result : I->getResults()) { - for (Operand *Use : result->getUses()) { - SILInstruction *User = Use->getUser(); - if (NumOpsToClone.count(User) != 0 && --NumOpsToClone[User] == 0) - ReadyToClone.push_back(User); - } - } - } - return cast(getMappedValue(InitVal)); -} - -Optional -swift::findLocalApplySites(FunctionRefBaseInst *FRI) { - SmallVector worklist(FRI->use_begin(), FRI->use_end()); - - Optional f; - f.emplace(); - - // Optimistically state that we have no escapes before our def-use dataflow. - f->escapes = false; - - while (!worklist.empty()) { - auto *op = worklist.pop_back_val(); - auto *user = op->getUser(); - - // If we have a full apply site as our user. - if (auto apply = FullApplySite::isa(user)) { - if (apply.getCallee() == op->get()) { - f->fullApplySites.push_back(apply); - continue; - } - } - - // If we have a partial apply as a user, start tracking it, but also look at - // its users. - if (auto *pai = dyn_cast(user)) { - if (pai->getCallee() == op->get()) { - // Track the partial apply that we saw so we can potentially eliminate - // dead closure arguments. - f->partialApplySites.push_back(pai); - // Look to see if we can find a full application of this partial apply - // as well. - llvm::copy(pai->getUses(), std::back_inserter(worklist)); - continue; - } - } - - // Otherwise, see if we have any function casts to look through... - switch (user->getKind()) { - case SILInstructionKind::ThinToThickFunctionInst: - case SILInstructionKind::ConvertFunctionInst: - case SILInstructionKind::ConvertEscapeToNoEscapeInst: - llvm::copy(cast(user)->getUses(), - std::back_inserter(worklist)); - continue; - - // A partial_apply [stack] marks its captured arguments with - // mark_dependence. - case SILInstructionKind::MarkDependenceInst: - llvm::copy(cast(user)->getUses(), - std::back_inserter(worklist)); - continue; - - // Look through any reference count instructions since these are not - // escapes: - case SILInstructionKind::CopyValueInst: - llvm::copy(cast(user)->getUses(), - std::back_inserter(worklist)); - continue; - case SILInstructionKind::StrongRetainInst: - case SILInstructionKind::StrongReleaseInst: - case SILInstructionKind::RetainValueInst: - case SILInstructionKind::ReleaseValueInst: - case SILInstructionKind::DestroyValueInst: - // A partial_apply [stack] is deallocated with a dealloc_stack. - case SILInstructionKind::DeallocStackInst: - continue; - default: - break; - } - - // But everything else is considered an escape. - f->escapes = true; - } - - // If we did escape and didn't find any apply sites, then we have no - // information for our users that is interesting. - if (f->escapes && f->partialApplySites.empty() && f->fullApplySites.empty()) - return None; - return f; -} - -/// Insert destroys of captured arguments of partial_apply [stack]. -void swift::insertDestroyOfCapturedArguments( - PartialApplyInst *PAI, SILBuilder &B, - llvm::function_ref shouldInsertDestroy) { - assert(PAI->isOnStack()); - - ApplySite site(PAI); - SILFunctionConventions calleeConv(site.getSubstCalleeType(), - PAI->getModule()); - auto loc = RegularLocation::getAutoGeneratedLocation(); - for (auto &arg : PAI->getArgumentOperands()) { - if (!shouldInsertDestroy(arg.get())) continue; - unsigned calleeArgumentIndex = site.getCalleeArgIndex(arg); - assert(calleeArgumentIndex >= calleeConv.getSILArgIndexOfFirstParam()); - auto paramInfo = calleeConv.getParamInfoForSILArg(calleeArgumentIndex); - releasePartialApplyCapturedArg(B, loc, arg.get(), paramInfo); - } -} diff --git a/lib/SILOptimizer/Utils/LoopUtils.cpp b/lib/SILOptimizer/Utils/LoopUtils.cpp index 0437d5b6d3d..9f0802b62f5 100644 --- a/lib/SILOptimizer/Utils/LoopUtils.cpp +++ b/lib/SILOptimizer/Utils/LoopUtils.cpp @@ -19,7 +19,7 @@ #include "swift/SIL/SILBasicBlock.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILModule.h" -#include "swift/SILOptimizer/Utils/CFG.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" #include "llvm/Support/Debug.h" using namespace swift; diff --git a/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp b/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp index 21e08139fe9..0f0f78d9f7e 100644 --- a/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp +++ b/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp @@ -12,7 +12,7 @@ #include "swift/SILOptimizer/Utils/PerformanceInlinerUtils.h" #include "swift/AST/Module.h" -#include "swift/SILOptimizer/Utils/Local.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" //===----------------------------------------------------------------------===// // ConstantTracker diff --git a/lib/SILOptimizer/Utils/SILInliner.cpp b/lib/SILOptimizer/Utils/SILInliner.cpp index d20ab659b74..8954dcb4f82 100644 --- a/lib/SILOptimizer/Utils/SILInliner.cpp +++ b/lib/SILOptimizer/Utils/SILInliner.cpp @@ -16,7 +16,7 @@ #include "swift/SIL/PrettyStackTrace.h" #include "swift/SIL/SILDebugScope.h" #include "swift/SIL/TypeSubstCloner.h" -#include "swift/SILOptimizer/Utils/CFG.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" #include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Debug.h" diff --git a/lib/SILOptimizer/Utils/SILSSAUpdater.cpp b/lib/SILOptimizer/Utils/SILSSAUpdater.cpp index fb9b17fe7eb..9625114d8fa 100644 --- a/lib/SILOptimizer/Utils/SILSSAUpdater.cpp +++ b/lib/SILOptimizer/Utils/SILSSAUpdater.cpp @@ -10,19 +10,18 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Transforms/Utils/SSAUpdaterImpl.h" +#include "swift/SILOptimizer/Utils/SILSSAUpdater.h" #include "swift/Basic/Malloc.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILBasicBlock.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILModule.h" #include "swift/SIL/SILUndef.h" -#include "swift/SILOptimizer/Utils/CFG.h" -#include "swift/SILOptimizer/Utils/SILSSAUpdater.h" - +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/Utils/SSAUpdaterImpl.h" using namespace swift; diff --git a/lib/SILOptimizer/Utils/ValueLifetime.cpp b/lib/SILOptimizer/Utils/ValueLifetime.cpp new file mode 100644 index 00000000000..8e18a9da9ad --- /dev/null +++ b/lib/SILOptimizer/Utils/ValueLifetime.cpp @@ -0,0 +1,251 @@ +//===--- ValueLifetime.cpp - ValueLifetimeAnalysis ------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include "swift/SILOptimizer/Utils/ValueLifetime.h" +#include "swift/SIL/BasicBlockUtils.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" + +using namespace swift; + +void ValueLifetimeAnalysis::propagateLiveness() { + assert(liveBlocks.empty() && "frontier computed twice"); + + auto defBB = defValue->getParentBlock(); + llvm::SmallVector worklist; + int numUsersBeforeDef = 0; + + // Find the initial set of blocks where the value is live, because + // it is used in those blocks. + for (SILInstruction *user : userSet) { + SILBasicBlock *userBlock = user->getParent(); + if (liveBlocks.insert(userBlock)) + worklist.push_back(userBlock); + + // A user in the defBB could potentially be located before the defValue. + if (userBlock == defBB) + numUsersBeforeDef++; + } + // Don't count any users in the defBB which are actually located _after_ + // the defValue. + auto instIter = defValue->getIterator(); + while (numUsersBeforeDef > 0 && ++instIter != defBB->end()) { + if (userSet.count(&*instIter)) + numUsersBeforeDef--; + } + + // Now propagate liveness backwards until we hit the block that defines the + // value. + while (!worklist.empty()) { + auto *bb = worklist.pop_back_val(); + + // Don't go beyond the definition. + if (bb == defBB && numUsersBeforeDef == 0) + continue; + + for (SILBasicBlock *Pred : bb->getPredecessorBlocks()) { + // If it's already in the set, then we've already queued and/or + // processed the predecessors. + if (liveBlocks.insert(Pred)) + worklist.push_back(Pred); + } + } +} + +SILInstruction *ValueLifetimeAnalysis::findLastUserInBlock(SILBasicBlock *bb) { + // Walk backwards in bb looking for last use of the value. + for (auto ii = bb->rbegin(); ii != bb->rend(); ++ii) { + assert(defValue != &*ii && "Found def before finding use!"); + + if (userSet.count(&*ii)) + return &*ii; + } + llvm_unreachable("Expected to find use of value in block!"); +} + +bool ValueLifetimeAnalysis::computeFrontier(Frontier &frontier, Mode mode, + DeadEndBlocks *deBlocks) { + assert(!isAliveAtBeginOfBlock(defValue->getFunction()->getEntryBlock()) + && "Can't compute frontier for def which does not dominate all uses"); + + bool noCriticalEdges = true; + + // Exit-blocks from the lifetime region. The value is live at the end of + // a predecessor block but not in the frontier block itself. + llvm::SmallSetVector frontierBlocks; + + // Blocks where the value is live at the end of the block and which have + // a frontier block as successor. + llvm::SmallSetVector liveOutBlocks; + + /// The lifetime ends if we have a live block and a not-live successor. + for (SILBasicBlock *bb : liveBlocks) { + if (deBlocks && deBlocks->isDeadEnd(bb)) + continue; + + bool liveInSucc = false; + bool deadInSucc = false; + for (const SILSuccessor &succ : bb->getSuccessors()) { + if (isAliveAtBeginOfBlock(succ)) { + liveInSucc = true; + } else if (!deBlocks || !deBlocks->isDeadEnd(succ)) { + deadInSucc = true; + } + } + if (!liveInSucc) { + // The value is not live in any of the successor blocks. This means the + // block contains a last use of the value. The next instruction after + // the last use is part of the frontier. + SILInstruction *lastUser = findLastUserInBlock(bb); + if (!isa(lastUser)) { + frontier.push_back(&*std::next(lastUser->getIterator())); + continue; + } + // In case the last user is a TermInst we add all successor blocks to the + // frontier (see below). + assert(deadInSucc && "The final using TermInst must have successors"); + } + if (deadInSucc) { + if (mode == UsersMustPostDomDef) + return false; + + // The value is not live in some of the successor blocks. + liveOutBlocks.insert(bb); + for (const SILSuccessor &succ : bb->getSuccessors()) { + if (!isAliveAtBeginOfBlock(succ)) { + // It's an "exit" edge from the lifetime region. + frontierBlocks.insert(succ); + } + } + } + } + // Handle "exit" edges from the lifetime region. + llvm::SmallPtrSet unhandledFrontierBlocks; + for (SILBasicBlock *frontierBB : frontierBlocks) { + assert(mode != UsersMustPostDomDef); + bool needSplit = false; + // If the value is live only in part of the predecessor blocks we have to + // split those predecessor edges. + for (SILBasicBlock *Pred : frontierBB->getPredecessorBlocks()) { + if (!liveOutBlocks.count(Pred)) { + needSplit = true; + break; + } + } + if (needSplit) { + if (mode == DontModifyCFG) + return false; + // We need to split the critical edge to create a frontier instruction. + unhandledFrontierBlocks.insert(frontierBB); + } else { + // The first instruction of the exit-block is part of the frontier. + frontier.push_back(&*frontierBB->begin()); + } + } + // Split critical edges from the lifetime region to not yet handled frontier + // blocks. + for (SILBasicBlock *frontierPred : liveOutBlocks) { + assert(mode != UsersMustPostDomDef); + auto *term = frontierPred->getTerminator(); + // Cache the successor blocks because splitting critical edges invalidates + // the successor list iterator of T. + llvm::SmallVector succBlocks; + for (const SILSuccessor &succ : term->getSuccessors()) + succBlocks.push_back(succ); + + for (unsigned i = 0, e = succBlocks.size(); i != e; ++i) { + if (unhandledFrontierBlocks.count(succBlocks[i])) { + assert(mode == AllowToModifyCFG); + assert(isCriticalEdge(term, i) && "actually not a critical edge?"); + SILBasicBlock *newBlock = splitEdge(term, i); + // The single terminator instruction is part of the frontier. + frontier.push_back(&*newBlock->begin()); + noCriticalEdges = false; + } + } + } + return noCriticalEdges; +} + +bool ValueLifetimeAnalysis::isWithinLifetime(SILInstruction *inst) { + SILBasicBlock *bb = inst->getParent(); + // Check if the value is not live anywhere in inst's block. + if (!liveBlocks.count(bb)) + return false; + for (const SILSuccessor &succ : bb->getSuccessors()) { + // If the value is live at the beginning of any successor block it is also + // live at the end of bb and therefore inst is definitely in the lifetime + // region (Note that we don't check in upward direction against the value's + // definition). + if (isAliveAtBeginOfBlock(succ)) + return true; + } + // The value is live in the block but not at the end of the block. Check if + // inst is located before (or at) the last use. + for (auto ii = bb->rbegin(); ii != bb->rend(); ++ii) { + if (userSet.count(&*ii)) { + return true; + } + if (inst == &*ii) + return false; + } + llvm_unreachable("Expected to find use of value in block!"); +} + +// Searches \p bb backwards from the instruction before \p frontierInst +// to the beginning of the list and returns true if we find a dealloc_ref +// /before/ we find \p defValue (the instruction that defines our target value). +static bool blockContainsDeallocRef(SILBasicBlock *bb, SILInstruction *defValue, + SILInstruction *frontierInst) { + SILBasicBlock::reverse_iterator End = bb->rend(); + SILBasicBlock::reverse_iterator iter = frontierInst->getReverseIterator(); + for (++iter; iter != End; ++iter) { + SILInstruction *inst = &*iter; + if (isa(inst)) + return true; + if (inst == defValue) + return false; + } + return false; +} + +bool ValueLifetimeAnalysis::containsDeallocRef(const Frontier &frontier) { + SmallPtrSet frontierBlocks; + // Search in live blocks where the value is not alive until the end of the + // block, i.e. the live range is terminated by a frontier instruction. + for (SILInstruction *frontierInst : frontier) { + SILBasicBlock *bb = frontierInst->getParent(); + if (blockContainsDeallocRef(bb, defValue, frontierInst)) + return true; + frontierBlocks.insert(bb); + } + // Search in all other live blocks where the value is alive until the end of + // the block. + for (SILBasicBlock *bb : liveBlocks) { + if (frontierBlocks.count(bb) == 0) { + if (blockContainsDeallocRef(bb, defValue, bb->getTerminator())) + return true; + } + } + return false; +} + +void ValueLifetimeAnalysis::dump() const { + llvm::errs() << "lifetime of def: " << *defValue; + for (SILInstruction *Use : userSet) { + llvm::errs() << " use: " << *Use; + } + llvm::errs() << " live blocks:"; + for (SILBasicBlock *bb : liveBlocks) { + llvm::errs() << ' ' << bb->getDebugID(); + } + llvm::errs() << '\n'; +} diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 3b3799ad8e0..1d2ab2765ad 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -2510,15 +2510,19 @@ namespace { auto baseTyUnwrappedName = baseTyUnwrapped->getString(); auto loc = DSCE->getLoc(); auto startLoc = DSCE->getStartLoc(); - - tc.diagnose(loc, swift::diag::optional_ambiguous_case_ref, - baseTyName, baseTyUnwrappedName, memberName.str()); - - tc.diagnose(loc, swift::diag::optional_fixit_ambiguous_case_ref) - .fixItInsert(startLoc, "Optional"); - tc.diagnose(loc, swift::diag::type_fixit_optional_ambiguous_case_ref, + tc.diagnoseWithNotes( + tc.diagnose(loc, swift::diag::optional_ambiguous_case_ref, + baseTyName, baseTyUnwrappedName, memberName.str()), + [&]() { + tc.diagnose(loc, + swift::diag::optional_fixit_ambiguous_case_ref) + .fixItInsert(startLoc, "Optional"); + tc.diagnose( + loc, + swift::diag::type_fixit_optional_ambiguous_case_ref, baseTyUnwrappedName, memberName.str()) - .fixItInsert(startLoc, baseTyUnwrappedName); + .fixItInsert(startLoc, baseTyUnwrappedName); + }); } } } diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 46bb7383c18..e3e1065f919 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -94,18 +94,19 @@ Expr *FailureDiagnostic::findParentExpr(Expr *subExpr) const { return E ? E->getParentMap()[subExpr] : nullptr; } -Expr *FailureDiagnostic::getArgumentExprFor(Expr *anchor) const { - if (auto *UDE = dyn_cast(anchor)) { - if (auto *call = dyn_cast_or_null(findParentExpr(UDE))) - return call->getArg(); - } else if (auto *UME = dyn_cast(anchor)) { - return UME->getArgument(); - } else if (auto *call = dyn_cast(anchor)) { - return call->getArg(); - } else if (auto *SE = dyn_cast(anchor)) { - return SE->getIndex(); - } - return nullptr; +Expr * +FailureDiagnostic::getArgumentListExprFor(ConstraintLocator *locator) const { + auto path = locator->getPath(); + auto iter = path.begin(); + if (!locator->findFirst(iter)) + return nullptr; + + // Form a new locator that ends at the ApplyArgument element, then simplify + // to get the argument list. + auto newPath = ArrayRef(path.begin(), iter + 1); + auto &cs = getConstraintSystem(); + auto argListLoc = cs.getConstraintLocator(locator->getAnchor(), newPath); + return simplifyLocatorToAnchor(argListLoc); } Expr *FailureDiagnostic::getBaseExprFor(Expr *anchor) const { @@ -836,21 +837,18 @@ bool GenericArgumentsMismatchFailure::diagnoseAsError() { } bool LabelingFailure::diagnoseAsError() { - auto &cs = getConstraintSystem(); - auto *anchor = getRawAnchor(); - - auto *argExpr = getArgumentExprFor(anchor); + auto *argExpr = getArgumentListExprFor(getLocator()); if (!argExpr) return false; + auto &cs = getConstraintSystem(); + auto *anchor = getRawAnchor(); return diagnoseArgumentLabelError(cs.getASTContext(), argExpr, CorrectLabels, isa(anchor)); } bool LabelingFailure::diagnoseAsNote() { - auto *anchor = getRawAnchor(); - - auto *argExpr = getArgumentExprFor(anchor); + auto *argExpr = getArgumentListExprFor(getLocator()); if (!argExpr) return false; @@ -4211,7 +4209,8 @@ bool ClosureParamDestructuringFailure::diagnoseAsError() { bool OutOfOrderArgumentFailure::diagnoseAsError() { auto *anchor = getRawAnchor(); - auto *argExpr = isa(anchor) ? anchor : getArgumentExprFor(anchor); + auto *argExpr = isa(anchor) ? anchor + : getArgumentListExprFor(getLocator()); if (!argExpr) return false; @@ -4860,7 +4859,7 @@ bool InvalidTupleSplatWithSingleParameterFailure::diagnoseAsError() { auto *choice = selectedOverload->choice.getDecl(); - auto *argExpr = getArgumentExprFor(getRawAnchor()); + auto *argExpr = getArgumentListExprFor(getLocator()); if (!argExpr) return false; diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index 563cfdfd962..3529e668f41 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -170,9 +170,11 @@ protected: /// `x.foo` or `x[0]` extract and return its base expression. Expr *getBaseExprFor(Expr *anchor) const; - /// \returns An argument expression if given anchor is a call, member - /// reference or subscript, nullptr otherwise. - Expr *getArgumentExprFor(Expr *anchor) const; + /// For a given locator describing an argument application, or a constraint + /// within an argument application, returns the argument list for that + /// application. If the locator is not for an argument application, or + /// the argument list cannot be found, returns \c nullptr. + Expr *getArgumentListExprFor(ConstraintLocator *locator) const; /// \returns The overload choice made by the constraint system for the callee /// of a given locator's anchor, or \c None if no such choice can be found. diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 139cec2159c..23e90aeb35b 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -902,7 +902,7 @@ public: } } - auto *locator = CS.getConstraintLocator(anchor); + auto *locator = CS.getConstraintLocator(Locator); auto *fix = RelabelArguments::create(CS, newLabels, locator); CS.recordFix(fix); // Re-labeling fixes with extraneous labels should take diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp index 72b443aac0f..346e496bb16 100644 --- a/lib/Sema/CodeSynthesis.cpp +++ b/lib/Sema/CodeSynthesis.cpp @@ -692,8 +692,6 @@ createDesignatedInitOverride(ClassDecl *classDecl, ctor->setImplicitlyUnwrappedOptional( superclassCtor->isImplicitlyUnwrappedOptional()); - ctor->setValidationToChecked(); - configureInheritedDesignatedInitAttributes(classDecl, ctor, superclassCtor, ctx); diff --git a/lib/Sema/DerivedConformanceCodable.cpp b/lib/Sema/DerivedConformanceCodable.cpp index 3ebcc03c992..77266d5513c 100644 --- a/lib/Sema/DerivedConformanceCodable.cpp +++ b/lib/Sema/DerivedConformanceCodable.cpp @@ -757,7 +757,6 @@ static FuncDecl *deriveEncodable_encode(DerivedConformance &derived) { encodeDecl->setGenericSignature(conformanceDC->getGenericSignatureOfContext()); encodeDecl->computeType(FunctionType::ExtInfo().withThrows()); - encodeDecl->setValidationToChecked(); encodeDecl->copyFormalAccessFrom(derived.Nominal, /*sourceIsParentContext*/ true); @@ -1038,7 +1037,6 @@ static ValueDecl *deriveDecodable_init(DerivedConformance &derived) { initDecl->setGenericSignature(conformanceDC->getGenericSignatureOfContext()); initDecl->computeType(AnyFunctionType::ExtInfo().withThrows()); - initDecl->setValidationToChecked(); initDecl->copyFormalAccessFrom(derived.Nominal, /*sourceIsParentContext*/ true); diff --git a/lib/Sema/DerivedConformanceCodingKey.cpp b/lib/Sema/DerivedConformanceCodingKey.cpp index 595e0552a7b..dfe00f9906e 100644 --- a/lib/Sema/DerivedConformanceCodingKey.cpp +++ b/lib/Sema/DerivedConformanceCodingKey.cpp @@ -146,7 +146,6 @@ static ValueDecl *deriveInitDecl(DerivedConformance &derived, Type paramType, initDecl->computeType(); initDecl->setAccess(derived.Nominal->getFormalAccess()); - initDecl->setValidationToChecked(); C.addSynthesizedDecl(initDecl); diff --git a/lib/Sema/DerivedConformanceEquatableHashable.cpp b/lib/Sema/DerivedConformanceEquatableHashable.cpp index 566ca9e48dd..ace82f70cdd 100644 --- a/lib/Sema/DerivedConformanceEquatableHashable.cpp +++ b/lib/Sema/DerivedConformanceEquatableHashable.cpp @@ -771,7 +771,6 @@ deriveEquatable_eq( eqDecl->computeType(); eqDecl->copyFormalAccessFrom(derived.Nominal, /*sourceIsParentContext*/ true); - eqDecl->setValidationToChecked(); C.addSynthesizedDecl(eqDecl); @@ -896,7 +895,6 @@ deriveHashable_hashInto( hashDecl->setGenericSignature(parentDC->getGenericSignatureOfContext()); hashDecl->computeType(); hashDecl->copyFormalAccessFrom(derived.Nominal); - hashDecl->setValidationToChecked(); C.addSynthesizedDecl(hashDecl); @@ -1247,14 +1245,12 @@ static ValueDecl *deriveHashable_hashValue(DerivedConformance &derived) { getterDecl->setGenericSignature(parentDC->getGenericSignatureOfContext()); getterDecl->computeType(); - getterDecl->setValidationToChecked(); getterDecl->copyFormalAccessFrom(derived.Nominal, /*sourceIsParentContext*/ true); // Finish creating the property. hashValueDecl->setImplicit(); hashValueDecl->setInterfaceType(intType); - hashValueDecl->setValidationToChecked(); hashValueDecl->setImplInfo(StorageImplInfo::getImmutableComputed()); hashValueDecl->setAccessors(SourceLoc(), {getterDecl}, SourceLoc()); hashValueDecl->copyFormalAccessFrom(derived.Nominal, diff --git a/lib/Sema/DerivedConformanceRawRepresentable.cpp b/lib/Sema/DerivedConformanceRawRepresentable.cpp index dcc35d78eb5..d414743f7a2 100644 --- a/lib/Sema/DerivedConformanceRawRepresentable.cpp +++ b/lib/Sema/DerivedConformanceRawRepresentable.cpp @@ -433,7 +433,6 @@ deriveRawRepresentable_init(DerivedConformance &derived) { initDecl->computeType(); initDecl->copyFormalAccessFrom(enumDecl, /*sourceIsParentContext*/true); - initDecl->setValidationToChecked(); // If the containing module is not resilient, make sure clients can construct // an instance without function call overhead. diff --git a/lib/Sema/DerivedConformances.cpp b/lib/Sema/DerivedConformances.cpp index 937db527e88..320f55c3bac 100644 --- a/lib/Sema/DerivedConformances.cpp +++ b/lib/Sema/DerivedConformances.cpp @@ -316,7 +316,6 @@ DerivedConformance::declareDerivedPropertyGetter(VarDecl *property, getterDecl->computeType(); getterDecl->copyFormalAccessFrom(property); - getterDecl->setValidationToChecked(); C.addSynthesizedDecl(getterDecl); @@ -337,7 +336,6 @@ DerivedConformance::declareDerivedProperty(Identifier name, propDecl->setImplicit(); propDecl->copyFormalAccessFrom(Nominal, /*sourceIsParentContext*/ true); propDecl->setInterfaceType(propertyInterfaceType); - propDecl->setValidationToChecked(); Pattern *propPat = new (C) NamedPattern(propDecl, /*implicit*/ true); propPat->setType(propertyContextType); diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index 1c8bcaa796e..df2da7149f2 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -2140,6 +2140,12 @@ public: } } + // Don't walk into implicit accessors, since eg. an observer's setter + // references the variable, but we don't want to consider it as a real + // "use". + if (isa(D) && D->isImplicit()) + return false; + if (auto *afd = dyn_cast(D)) { // If this is a nested function with a capture list, mark any captured // variables. diff --git a/lib/Sema/TypeCheckCaptures.cpp b/lib/Sema/TypeCheckCaptures.cpp index 048bff537ff..da051ad66fd 100644 --- a/lib/Sema/TypeCheckCaptures.cpp +++ b/lib/Sema/TypeCheckCaptures.cpp @@ -365,6 +365,11 @@ public: return false; } + // Don't walk into local types; we'll walk their initializers when we check + // the local type itself. + if (isa(D)) + return false; + return true; } diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index d4848bace5a..bd01a73fc09 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -869,8 +869,10 @@ static void checkRedeclaration(TypeChecker &tc, ValueDecl *current) { current->getFullName(), otherInit->isMemberwiseInitializer()); } else { - tc.diagnose(current, diag::invalid_redecl, current->getFullName()); - tc.diagnose(other, diag::invalid_redecl_prev, other->getFullName()); + tc.diagnoseWithNotes(tc.diagnose(current, diag::invalid_redecl, + current->getFullName()), [&]() { + tc.diagnose(other, diag::invalid_redecl_prev, other->getFullName()); + }); } markInvalid(); } @@ -1382,40 +1384,37 @@ namespace { /// Given the raw value literal expression for an enum case, produces the /// auto-incremented raw value for the subsequent case, or returns null if /// the value is not auto-incrementable. -static LiteralExpr *getAutomaticRawValueExpr(TypeChecker &TC, - AutomaticEnumValueKind valueKind, +static LiteralExpr *getAutomaticRawValueExpr(AutomaticEnumValueKind valueKind, EnumElementDecl *forElt, LiteralExpr *prevValue) { + auto &Ctx = forElt->getASTContext(); switch (valueKind) { case AutomaticEnumValueKind::None: - TC.diagnose(forElt->getLoc(), - diag::enum_non_integer_convertible_raw_type_no_value); + Ctx.Diags.diagnose(forElt->getLoc(), + diag::enum_non_integer_convertible_raw_type_no_value); return nullptr; case AutomaticEnumValueKind::String: - return new (TC.Context) StringLiteralExpr(forElt->getNameStr(), SourceLoc(), + return new (Ctx) StringLiteralExpr(forElt->getNameStr(), SourceLoc(), /*Implicit=*/true); case AutomaticEnumValueKind::Integer: // If there was no previous value, start from zero. if (!prevValue) { - return new (TC.Context) IntegerLiteralExpr("0", SourceLoc(), + return new (Ctx) IntegerLiteralExpr("0", SourceLoc(), /*Implicit=*/true); } - // If the prevValue is not a well-typed integer, then break. - if (!prevValue->getType()) - return nullptr; if (auto intLit = dyn_cast(prevValue)) { - APInt nextVal = intLit->getValue().sextOrSelf(128) + 1; + APInt nextVal = intLit->getRawValue().sextOrSelf(128) + 1; bool negative = nextVal.slt(0); if (negative) nextVal = -nextVal; llvm::SmallString<10> nextValStr; nextVal.toStringSigned(nextValStr); - auto expr = new (TC.Context) - IntegerLiteralExpr(TC.Context.AllocateCopy(StringRef(nextValStr)), + auto expr = new (Ctx) + IntegerLiteralExpr(Ctx.AllocateCopy(StringRef(nextValStr)), forElt->getLoc(), /*Implicit=*/true); if (negative) expr->setNegative(forElt->getLoc()); @@ -1423,8 +1422,8 @@ static LiteralExpr *getAutomaticRawValueExpr(TypeChecker &TC, return expr; } - TC.diagnose(forElt->getLoc(), - diag::enum_non_integer_raw_value_auto_increment); + Ctx.Diags.diagnose(forElt->getLoc(), + diag::enum_non_integer_raw_value_auto_increment); return nullptr; } @@ -1432,7 +1431,7 @@ static LiteralExpr *getAutomaticRawValueExpr(TypeChecker &TC, } static Optional -computeAutomaticEnumValueKind(TypeChecker &TC, EnumDecl *ED) { +computeAutomaticEnumValueKind(EnumDecl *ED) { Type rawTy = ED->getRawType(); assert(rawTy && "Cannot compute value kind without raw type!"); @@ -1442,7 +1441,7 @@ computeAutomaticEnumValueKind(TypeChecker &TC, EnumDecl *ED) { // Swift enums require that the raw type is convertible from one of the // primitive literal protocols. auto conformsToProtocol = [&](KnownProtocolKind protoKind) { - ProtocolDecl *proto = TC.getProtocol(ED->getLoc(), protoKind); + ProtocolDecl *proto = ED->getASTContext().getProtocol(protoKind); return TypeChecker::conformsToProtocol(rawTy, proto, ED->getDeclContext(), None); }; @@ -1466,22 +1465,19 @@ computeAutomaticEnumValueKind(TypeChecker &TC, EnumDecl *ED) { } } -static void checkEnumRawValues(TypeChecker &TC, EnumDecl *ED) { +llvm::Expected +EnumRawValuesRequest::evaluate(Evaluator &eval, EnumDecl *ED, + TypeResolutionStage stage) const { Type rawTy = ED->getRawType(); if (!rawTy) { - return; + return true; } if (ED->getGenericEnvironmentOfContext() != nullptr) rawTy = ED->mapTypeIntoContext(rawTy); if (rawTy->hasError()) - return; + return true; - // If we don't have a value kind, the decl checker will provide a diagnostic. - auto valueKind = computeAutomaticEnumValueKind(TC, ED); - if (!valueKind.hasValue()) - return; - // Check the raw values of the cases. LiteralExpr *prevValue = nullptr; EnumElementDecl *lastExplicitValueElt = nullptr; @@ -1489,38 +1485,67 @@ static void checkEnumRawValues(TypeChecker &TC, EnumDecl *ED) { // Keep a map we can use to check for duplicate case values. llvm::SmallDenseMap uniqueRawValues; + // Make the raw member accesses explicit. + auto uncheckedRawValueOf = [](EnumElementDecl *EED) -> LiteralExpr * { + return EED->RawValueExpr; + }; + + Optional valueKind; for (auto elt : ED->getAllElements()) { - // Skip if the raw value expr has already been checked. - if (elt->hasRawValueExpr() && elt->getRawValueExpr()->getType()) { - prevValue = elt->getRawValueExpr(); - continue; - } - - // Make sure the element is checked out before we poke at it. - // FIXME: Make isInvalid work with interface types + // If the element has been diagnosed up to now, skip it. (void)elt->getInterfaceType(); if (elt->isInvalid()) continue; - - if (elt->hasRawValueExpr()) { - lastExplicitValueElt = elt; - } else { + + if (uncheckedRawValueOf(elt)) { + if (!uncheckedRawValueOf(elt)->isImplicit()) + lastExplicitValueElt = elt; + } else if (!ED->LazySemanticInfo.hasFixedRawValues()) { + // Try to pull out the automatic enum value kind. If that fails, bail. + if (!valueKind) { + valueKind = computeAutomaticEnumValueKind(ED); + if (!valueKind) { + elt->setInvalid(); + return true; + } + } + // If the enum element has no explicit raw value, try to // autoincrement from the previous value, or start from zero if this // is the first element. - auto nextValue = getAutomaticRawValueExpr(TC, *valueKind, elt, prevValue); + auto nextValue = getAutomaticRawValueExpr(*valueKind, elt, prevValue); if (!nextValue) { elt->setInvalid(); break; } elt->setRawValueExpr(nextValue); } - prevValue = elt->getRawValueExpr(); + prevValue = uncheckedRawValueOf(elt); assert(prevValue && "continued without setting raw value of enum case"); + switch (stage) { + case TypeResolutionStage::Structural: + // We're only interested in computing the complete set of raw values, + // so we can skip type checking. + continue; + default: + // Continue on to type check the raw value. + break; + } + + + { + auto *TC = static_cast(ED->getASTContext().getLazyResolver()); + assert(TC && "Must have a lazy resolver set"); + Expr *exprToCheck = prevValue; + if (TC->typeCheckExpression(exprToCheck, ED, TypeLoc::withoutLoc(rawTy), + CTP_EnumCaseRawValue)) { + TC->checkEnumElementErrorHandling(elt, exprToCheck); + } + } + // If we didn't find a valid initializer (maybe the initial value was // incompatible with the raw value type) mark the entry as being erroneous. - TC.checkRawValueExpr(ED, elt); if (!prevValue->getType() || prevValue->getType()->hasError()) { elt->setInvalid(); continue; @@ -1535,34 +1560,36 @@ static void checkEnumRawValues(TypeChecker &TC, EnumDecl *ED) { continue; // Diagnose the duplicate value. - SourceLoc diagLoc = elt->getRawValueExpr()->isImplicit() - ? elt->getLoc() : elt->getRawValueExpr()->getLoc(); - TC.diagnose(diagLoc, diag::enum_raw_value_not_unique); + auto &Diags = ED->getASTContext().Diags; + SourceLoc diagLoc = uncheckedRawValueOf(elt)->isImplicit() + ? elt->getLoc() : uncheckedRawValueOf(elt)->getLoc(); + Diags.diagnose(diagLoc, diag::enum_raw_value_not_unique); assert(lastExplicitValueElt && "should not be able to have non-unique raw values when " "relying on autoincrement"); if (lastExplicitValueElt != elt && valueKind == AutomaticEnumValueKind::Integer) { - TC.diagnose(lastExplicitValueElt->getRawValueExpr()->getLoc(), - diag::enum_raw_value_incrementing_from_here); + Diags.diagnose(uncheckedRawValueOf(lastExplicitValueElt)->getLoc(), + diag::enum_raw_value_incrementing_from_here); } RawValueSource prevSource = insertIterPair.first->second; auto foundElt = prevSource.sourceElt; - diagLoc = foundElt->getRawValueExpr()->isImplicit() - ? foundElt->getLoc() : foundElt->getRawValueExpr()->getLoc(); - TC.diagnose(diagLoc, diag::enum_raw_value_used_here); + diagLoc = uncheckedRawValueOf(foundElt)->isImplicit() + ? foundElt->getLoc() : uncheckedRawValueOf(foundElt)->getLoc(); + Diags.diagnose(diagLoc, diag::enum_raw_value_used_here); if (foundElt != prevSource.lastExplicitValueElt && valueKind == AutomaticEnumValueKind::Integer) { if (prevSource.lastExplicitValueElt) - TC.diagnose(prevSource.lastExplicitValueElt - ->getRawValueExpr()->getLoc(), - diag::enum_raw_value_incrementing_from_here); + Diags.diagnose(uncheckedRawValueOf(prevSource.lastExplicitValueElt) + ->getLoc(), + diag::enum_raw_value_incrementing_from_here); else - TC.diagnose(ED->getAllElements().front()->getLoc(), - diag::enum_raw_value_incrementing_from_zero); + Diags.diagnose(ED->getAllElements().front()->getLoc(), + diag::enum_raw_value_incrementing_from_zero); } } + return true; } const ConstructorDecl * @@ -2606,7 +2633,7 @@ public: if (auto rawTy = ED->getRawType()) { // The raw type must be one of the blessed literal convertible types. - if (!computeAutomaticEnumValueKind(TC, ED)) { + if (!computeAutomaticEnumValueKind(ED)) { TC.diagnose(ED->getInherited().front().getSourceRange().Start, diag::raw_type_not_literal_convertible, rawTy); @@ -2618,11 +2645,6 @@ public: TC.diagnose(ED->getInherited().front().getSourceRange().Start, diag::empty_enum_raw_type); } - - // ObjC enums have already had their raw values checked, but pure Swift - // enums haven't. - if (!ED->isObjC()) - checkEnumRawValues(TC, ED); } checkExplicitAvailability(ED); @@ -3116,13 +3138,13 @@ public: } } - // Yell if our parent doesn't have a raw type but we have a raw value. - if (EED->hasRawValueExpr() && !ED->hasRawType()) { - TC.diagnose(EED->getRawValueExpr()->getLoc(), - diag::enum_raw_value_without_raw_type); + // Force the raw value expr then yell if our parent doesn't have a raw type. + Expr *RVE = EED->getRawValueExpr(); + if (RVE && !ED->hasRawType()) { + TC.diagnose(RVE->getLoc(), diag::enum_raw_value_without_raw_type); EED->setInvalid(); } - + checkAccessControl(TC, EED); } @@ -3197,13 +3219,6 @@ public: checkInheritanceClause(ED); - // Check the raw values of an enum, since we might synthesize - // RawRepresentable while checking conformances on this extension. - if (auto enumDecl = dyn_cast(nominal)) { - if (enumDecl->hasRawType()) - checkEnumRawValues(TC, enumDecl); - } - // Only generic and protocol types are permitted to have // trailing where clauses. if (auto trailingWhereClause = ED->getTrailingWhereClause()) { @@ -3806,12 +3821,8 @@ void TypeChecker::validateDecl(ValueDecl *D) { // Handling validation failure due to re-entrancy is left // up to the caller, who must call hasInterfaceType() to // check that validateDecl() returned a fully-formed decl. - if (D->hasValidationStarted()) { - // If this isn't reentrant (i.e. D has already been validated), the - // signature better be valid. - assert(D->isBeingValidated() || D->hasInterfaceType()); + if (D->hasValidationStarted() || D->hasInterfaceType()) return; - } // FIXME: It would be nicer if Sema would always synthesize fully-typechecked // declarations, but for now, you can make an imported type conform to a @@ -3825,8 +3836,7 @@ void TypeChecker::validateDecl(ValueDecl *D) { PrettyStackTraceDecl StackTrace("validating", D); FrontendStatsTracer StatsTracer(Context.Stats, "validate-decl", D); - if (hasEnabledForbiddenTypecheckPrefix()) - checkForForbiddenPrefix(D); + checkForForbiddenPrefix(D); // Validate the context. auto dc = D->getDeclContext(); @@ -3854,7 +3864,7 @@ void TypeChecker::validateDecl(ValueDecl *D) { // Validating the parent may have triggered validation of this declaration, // so just return if that was the case. - if (D->hasValidationStarted()) { + if (D->hasValidationStarted() || D->hasInterfaceType()) { assert(D->hasInterfaceType()); return; } @@ -3885,73 +3895,46 @@ void TypeChecker::validateDecl(ValueDecl *D) { case DeclKind::AssociatedType: { auto assocType = cast(D); - - DeclValidationRAII IBV(assocType); - - // Finally, set the interface type. - if (!assocType->hasInterfaceType()) - assocType->computeType(); - + assocType->computeType(); break; } case DeclKind::TypeAlias: { auto typeAlias = cast(D); - - DeclValidationRAII IBV(typeAlias); - - // Finally, set the interface type. - if (!typeAlias->hasInterfaceType()) - typeAlias->computeType(); - + typeAlias->computeType(); break; } - case DeclKind::OpaqueType: { - auto opaque = cast(D); - opaque->setValidationToChecked(); + case DeclKind::OpaqueType: break; - } case DeclKind::Enum: case DeclKind::Struct: - case DeclKind::Class: { + case DeclKind::Class: + case DeclKind::Protocol: { auto nominal = cast(D); nominal->computeType(); - nominal->setValidationToChecked(); if (auto *ED = dyn_cast(nominal)) { // @objc enums use their raw values as the value representation, so we - // need to force the values to be checked. - if (ED->isObjC()) - checkEnumRawValues(*this, ED); + // need to force the values to be checked even in non-primaries. + // + // FIXME: This check can be removed once IRGen can be made tolerant of + // semantic failures post-Sema. + if (ED->isObjC()) { + (void)evaluateOrDefault( + Context.evaluator, + EnumRawValuesRequest{ED, TypeResolutionStage::Interface}, true); + } } break; } - case DeclKind::Protocol: { - auto proto = cast(D); - if (!proto->hasInterfaceType()) - proto->computeType(); - proto->setValidationToChecked(); - - break; - } - - case DeclKind::Param: { - auto *PD = cast(D); - if (!PD->hasInterfaceType()) { - // Can't fallthough because parameter without a type doesn't have - // valid signature, but that shouldn't matter anyway. - return; - } - - auto type = PD->getInterfaceType(); - if (type->hasError()) - PD->markInvalid(); - break; - } + case DeclKind::Param: + // Can't fallthough because parameter without a type doesn't have + // valid signature, but that shouldn't matter anyway. + return; case DeclKind::Var: { auto *VD = cast(D); @@ -3961,11 +3944,7 @@ void TypeChecker::validateDecl(ValueDecl *D) { // have a PatternBindingDecl, for example the iterator in a // 'for ... in ...' loop. if (PBD == nullptr) { - if (!VD->hasInterfaceType()) { - VD->setValidationToChecked(); - VD->markInvalid(); - } - + VD->markInvalid(); break; } @@ -3975,25 +3954,15 @@ void TypeChecker::validateDecl(ValueDecl *D) { if (PBD->isBeingValidated()) return; - if (!VD->hasInterfaceType()) { - // Attempt to infer the type using initializer expressions. - validatePatternBindingEntries(*this, PBD); + // Attempt to infer the type using initializer expressions. + validatePatternBindingEntries(*this, PBD); - auto parentPattern = VD->getParentPattern(); - if (PBD->isInvalid() || !parentPattern->hasType()) { - parentPattern->setType(ErrorType::get(Context)); - setBoundVarsTypeError(parentPattern, Context); - } - - // Should have set a type above. - assert(VD->hasInterfaceType()); + auto parentPattern = VD->getParentPattern(); + if (PBD->isInvalid() || !parentPattern->hasType()) { + parentPattern->setType(ErrorType::get(Context)); + setBoundVarsTypeError(parentPattern, Context); } - // We're not really done with processing the signature yet, but - // @objc checking requires the declaration to call itself validated - // so that it can be considered as a witness. - D->setValidationToChecked(); - if (VD->getOpaqueResultTypeDecl()) { if (auto SF = VD->getInnermostDeclContext()->getParentSourceFile()) { SF->markDeclWithOpaqueResultTypeAsValidated(VD); @@ -4006,7 +3975,6 @@ void TypeChecker::validateDecl(ValueDecl *D) { case DeclKind::Func: case DeclKind::Accessor: { auto *FD = cast(D); - assert(!FD->hasInterfaceType()); // Bail out if we're in a recursive validation situation. if (auto accessor = dyn_cast(FD)) { @@ -4204,22 +4172,12 @@ void TypeChecker::validateDecl(ValueDecl *D) { DeclValidationRAII IBV(EED); if (auto *PL = EED->getParameterList()) { - typeCheckParameterList(PL, - TypeResolution::forInterface( - EED->getParentEnum(), - ED->getGenericSignature()), + auto res = TypeResolution::forInterface(ED, ED->getGenericSignature()); + typeCheckParameterList(PL, res, TypeResolverContext::EnumElementDecl); } - // Now that we have an argument type we can set the element's declared - // type. EED->computeType(); - - if (auto argTy = EED->getArgumentInterfaceType()) { - assert(argTy->isMaterializable()); - (void) argTy; - } - break; } } diff --git a/lib/Sema/TypeCheckDeclOverride.cpp b/lib/Sema/TypeCheckDeclOverride.cpp index b0e8326795b..ab362ae1725 100644 --- a/lib/Sema/TypeCheckDeclOverride.cpp +++ b/lib/Sema/TypeCheckDeclOverride.cpp @@ -1954,3 +1954,22 @@ OverriddenDeclsRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const { return matcher.checkPotentialOverrides(matches, OverrideCheckingAttempt::PerfectMatch); } + +llvm::Expected +IsABICompatibleOverrideRequest::evaluate(Evaluator &evaluator, + ValueDecl *decl) const { + auto base = decl->getOverriddenDecl(); + if (!base) + return false; + + auto baseInterfaceTy = base->getInterfaceType(); + auto derivedInterfaceTy = decl->getInterfaceType(); + + auto selfInterfaceTy = decl->getDeclContext()->getDeclaredInterfaceType(); + + auto overrideInterfaceTy = selfInterfaceTy->adjustSuperclassMemberDeclType( + base, decl, baseInterfaceTy); + + return derivedInterfaceTy->matches(overrideInterfaceTy, + TypeMatchFlags::AllowABICompatible); +} diff --git a/lib/Sema/TypeCheckError.cpp b/lib/Sema/TypeCheckError.cpp index 51f131fe92d..86c207933c5 100644 --- a/lib/Sema/TypeCheckError.cpp +++ b/lib/Sema/TypeCheckError.cpp @@ -1662,11 +1662,9 @@ void TypeChecker::checkInitializerErrorHandling(Initializer *initCtx, /// ensures correctness if those restrictions are ever loosened, /// perhaps accidentally, and (2) allows the verifier to assert that /// all calls have been checked. -void TypeChecker::checkEnumElementErrorHandling(EnumElementDecl *elt) { - if (auto *rawValue = elt->getRawValueExpr()) { - CheckErrorCoverage checker(*this, Context::forEnumElementInitializer(elt)); - rawValue->walk(checker); - } +void TypeChecker::checkEnumElementErrorHandling(EnumElementDecl *elt, Expr *E) { + CheckErrorCoverage checker(*this, Context::forEnumElementInitializer(elt)); + E->walk(checker); } void TypeChecker::checkPropertyWrapperErrorHandling( diff --git a/lib/Sema/TypeCheckPattern.cpp b/lib/Sema/TypeCheckPattern.cpp index 497083195b0..c33fce6d02c 100644 --- a/lib/Sema/TypeCheckPattern.cpp +++ b/lib/Sema/TypeCheckPattern.cpp @@ -21,6 +21,7 @@ #include "swift/Basic/StringExtras.h" #include "swift/AST/ASTWalker.h" #include "swift/AST/ASTVisitor.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/NameLookup.h" #include "swift/AST/ParameterList.h" #include "llvm/Support/SaveAndRestore.h" @@ -1132,6 +1133,18 @@ recur: var->getTypeLoc() = tyLoc; var->getTypeLoc().setType(var->getType()); + // FIXME: Copy pasted from validateDecl(). This needs to be converted to + // use requests. + if (var->getOpaqueResultTypeDecl()) { + if (auto sf = var->getInnermostDeclContext()->getParentSourceFile()) { + sf->markDeclWithOpaqueResultTypeAsValidated(var); + } + } + + // FIXME: Should probably just remove the forbidden prefix stuff, it no + // longer makes a lot of sense in a request-based world. + checkForForbiddenPrefix(var); + // If we are inferring a variable to have type AnyObject.Type, // "()", an uninhabited type, or optional thereof, emit a diagnostic. // In the first 2 cases, the coder probably forgot a cast and expected a diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index f317159db3e..fac4951ea32 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -2472,7 +2472,6 @@ void ConformanceChecker::recordTypeWitness(AssociatedTypeDecl *assocType, DC); aliasDecl->setGenericSignature(DC->getGenericSignatureOfContext()); aliasDecl->setUnderlyingType(type); - aliasDecl->setValidationToChecked(); aliasDecl->computeType(); aliasDecl->setImplicit(); diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index 05d6cd44bd9..129dc6ee5c4 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -1835,20 +1835,6 @@ Stmt *StmtChecker::visitBraceStmt(BraceStmt *BS) { return BS; } -void TypeChecker::checkRawValueExpr(EnumDecl *ED, EnumElementDecl *EED) { - Type rawTy = ED->getRawType(); - Expr *rawValue = EED->getRawValueExpr(); - assert((rawTy && rawValue) && "Cannot check missing raw value!"); - - if (ED->getGenericEnvironmentOfContext() != nullptr) - rawTy = ED->mapTypeIntoContext(rawTy); - - if (typeCheckExpression(rawValue, ED, TypeLoc::withoutLoc(rawTy), - CTP_EnumCaseRawValue)) { - checkEnumElementErrorHandling(EED); - } -} - static Type getFunctionBuilderType(FuncDecl *FD) { Type builderType = FD->getFunctionBuilderType(); diff --git a/lib/Sema/TypeCheckStorage.cpp b/lib/Sema/TypeCheckStorage.cpp index 6ee02d0f289..11668e7dba0 100644 --- a/lib/Sema/TypeCheckStorage.cpp +++ b/lib/Sema/TypeCheckStorage.cpp @@ -659,7 +659,6 @@ static Expr *buildStorageReference(AccessorDecl *accessor, // Otherwise do a self-reference, which is dynamically bogus but // should be statically valid. This should only happen in invalid cases. } else { - assert(storage->isInvalid()); semantics = AccessSemantics::Ordinary; selfAccessKind = SelfAccessorKind::Peer; } @@ -667,7 +666,17 @@ static Expr *buildStorageReference(AccessorDecl *accessor, case TargetImpl::Wrapper: { auto var = cast(accessor->getStorage()); - storage = var->getPropertyWrapperBackingProperty(); + auto *backing = var->getPropertyWrapperBackingProperty(); + + // Error recovery. + if (!backing) { + auto type = storage->getValueInterfaceType(); + if (isLValue) + type = LValueType::get(type); + return new (ctx) ErrorExpr(SourceRange(), type); + } + + storage = backing; // If the outermost property wrapper uses the enclosing self pattern, // record that. @@ -691,7 +700,18 @@ static Expr *buildStorageReference(AccessorDecl *accessor, case TargetImpl::WrapperStorage: { auto var = cast(accessor->getStorage())->getOriginalWrappedProperty(); - storage = var->getPropertyWrapperBackingProperty(); + auto *backing = var->getPropertyWrapperBackingProperty(); + + // Error recovery. + if (!backing) { + auto type = storage->getValueInterfaceType(); + if (isLValue) + type = LValueType::get(type); + return new (ctx) ErrorExpr(SourceRange(), type); + } + + storage = backing; + enclosingSelfAccess = getEnclosingSelfPropertyWrapperAccess(var, /*forProjected=*/true); if (!enclosingSelfAccess) { @@ -976,12 +996,21 @@ void createPropertyStoreOrCallSuperclassSetter(AccessorDecl *accessor, value = synthesizeCopyWithZoneCall(value, property, ctx); } + // Error recovery. + if (value->getType()->hasError()) + return; + Expr *dest = buildStorageReference(accessor, storage, target, /*isLValue=*/true, ctx); // A lazy property setter will store a value of type T into underlying storage // of type T?. auto destType = dest->getType()->getWithoutSpecifierType(); + + // Error recovery. + if (destType->hasError()) + return; + if (!destType->isEqual(value->getType())) { assert(destType->getOptionalObjectType()->isEqual(value->getType())); value = new (ctx) InjectIntoOptionalExpr(value, destType); @@ -1172,17 +1201,25 @@ synthesizeLazyGetterBody(AccessorDecl *Get, VarDecl *VD, VarDecl *Storage, // Take the initializer from the PatternBindingDecl for VD. // TODO: This doesn't work with complicated patterns like: // lazy var (a,b) = foo() - auto *InitValue = VD->getParentInitializer(); auto PBD = VD->getParentPatternBinding(); unsigned entryIndex = PBD->getPatternEntryIndexForVarDecl(VD); - PBD->setInitializerSubsumed(entryIndex); - if (!PBD->isInitializerChecked(entryIndex)) - TC.typeCheckPatternBinding(PBD, entryIndex); + Expr *InitValue; + if (PBD->getPatternList()[entryIndex].getInit()) { + PBD->setInitializerSubsumed(entryIndex); + + if (!PBD->isInitializerChecked(entryIndex)) + TC.typeCheckPatternBinding(PBD, entryIndex); + + InitValue = PBD->getPatternList()[entryIndex].getInit(); + } else { + InitValue = new (Ctx) ErrorExpr(SourceRange(), Tmp2VD->getType()); + } // Recontextualize any closure declcontexts nested in the initializer to // realize that they are in the getter function. Get->getImplicitSelfDecl()->setDeclContext(Get); + InitValue->walk(RecontextualizeClosures(Get)); // Wrap the initializer in a LazyInitializerExpr to avoid walking it twice. @@ -1226,6 +1263,12 @@ synthesizePropertyWrapperGetterBody(AccessorDecl *getter, ASTContext &ctx) { return synthesizeTrivialGetterBody(getter, TargetImpl::Wrapper, ctx); } +static std::pair +synthesizeInvalidAccessor(AccessorDecl *accessor, ASTContext &ctx) { + auto loc = accessor->getLoc(); + return { BraceStmt::create(ctx, loc, ArrayRef(), loc, true), true }; +} + static std::pair synthesizeGetterBody(AccessorDecl *getter, ASTContext &ctx) { auto storage = getter->getStorage(); @@ -1257,7 +1300,7 @@ synthesizeGetterBody(AccessorDecl *getter, ASTContext &ctx) { return synthesizeTrivialGetterBody(getter, ctx); case ReadImplKind::Get: - llvm_unreachable("synthesizing getter that already exists?"); + return synthesizeInvalidAccessor(getter, ctx); case ReadImplKind::Inherited: return synthesizeInheritedGetterBody(getter, ctx); @@ -1490,7 +1533,7 @@ synthesizeSetterBody(AccessorDecl *setter, ASTContext &ctx) { return synthesizeInheritedWithObserversSetterBody(setter, ctx); case WriteImplKind::Set: - llvm_unreachable("synthesizing setter for unknown reason?"); + return synthesizeInvalidAccessor(setter, ctx); case WriteImplKind::MutableAddress: return synthesizeMutableAddressSetterBody(setter, ctx); @@ -1547,7 +1590,7 @@ synthesizeModifyCoroutineBody(AccessorDecl *modify, ASTContext &ctx) { return synthesizeCoroutineAccessorBody(modify, ctx); } -std::pair +static std::pair synthesizeAccessorBody(AbstractFunctionDecl *fn, void *) { auto *accessor = cast(fn); auto &ctx = accessor->getASTContext(); @@ -1555,9 +1598,6 @@ synthesizeAccessorBody(AbstractFunctionDecl *fn, void *) { if (ctx.Stats) ctx.Stats->getFrontendCounters().NumAccessorBodiesSynthesized++; - if (accessor->isInvalid() || ctx.hadError()) - return { nullptr, true }; - switch (accessor->getAccessorKind()) { case AccessorKind::Get: return synthesizeGetterBody(accessor, ctx); diff --git a/lib/Sema/TypeCheckSwitchStmt.cpp b/lib/Sema/TypeCheckSwitchStmt.cpp index 2b818581e11..c9892315820 100644 --- a/lib/Sema/TypeCheckSwitchStmt.cpp +++ b/lib/Sema/TypeCheckSwitchStmt.cpp @@ -23,8 +23,10 @@ #include "swift/Basic/APIntMap.h" #include -#include #include +#include +#include +#include using namespace swift; @@ -115,7 +117,7 @@ namespace { // In type space, we reuse HEAD to help us print meaningful name, e.g., // tuple element name in fixits. - Identifier Head; + DeclName Head; std::forward_list Spaces; size_t computeSize(TypeChecker &TC, const DeclContext *DC, @@ -170,19 +172,18 @@ namespace { llvm_unreachable("unhandled kind"); } - explicit Space(Type T, Identifier NameForPrinting) - : Kind(SpaceKind::Type), TypeAndVal(T), - Head(NameForPrinting), Spaces({}){} + explicit Space(Type T, DeclName NameForPrinting) + : Kind(SpaceKind::Type), TypeAndVal(T), Head(NameForPrinting), + Spaces({}) {} explicit Space(UnknownCase_t, bool allowedButNotRequired) : Kind(SpaceKind::UnknownCase), TypeAndVal(Type(), allowedButNotRequired), Head(Identifier()), Spaces({}) {} - explicit Space(Type T, Identifier H, ArrayRef SP) - : Kind(SpaceKind::Constructor), TypeAndVal(T), Head(H), - Spaces(SP.begin(), SP.end()) {} - explicit Space(Type T, Identifier H, std::forward_list SP) - : Kind(SpaceKind::Constructor), TypeAndVal(T), Head(H), - Spaces(SP) {} + explicit Space(Type T, DeclName H, ArrayRef SP) + : Kind(SpaceKind::Constructor), TypeAndVal(T), Head(H), + Spaces(SP.begin(), SP.end()) {} + explicit Space(Type T, DeclName H, std::forward_list SP) + : Kind(SpaceKind::Constructor), TypeAndVal(T), Head(H), Spaces(SP) {} explicit Space(ArrayRef SP) : Kind(SpaceKind::Disjunct), TypeAndVal(Type()), Head(Identifier()), Spaces(SP.begin(), SP.end()) {} @@ -194,7 +195,7 @@ namespace { : Kind(SpaceKind::Empty), TypeAndVal(Type()), Head(Identifier()), Spaces({}) {} - static Space forType(Type T, Identifier NameForPrinting) { + static Space forType(Type T, DeclName NameForPrinting) { if (T->isStructurallyUninhabited()) return Space(); return Space(T, NameForPrinting); @@ -202,7 +203,7 @@ namespace { static Space forUnknown(bool allowedButNotRequired) { return Space(UnknownCase, allowedButNotRequired); } - static Space forConstructor(Type T, Identifier H, ArrayRef SP) { + static Space forConstructor(Type T, DeclName H, ArrayRef SP) { if (llvm::any_of(SP, std::mem_fn(&Space::isEmpty))) { // A constructor with an unconstructible parameter can never actually // be used. @@ -210,7 +211,7 @@ namespace { } return Space(T, H, SP); } - static Space forConstructor(Type T, Identifier H, + static Space forConstructor(Type T, DeclName H, std::forward_list SP) { // No need to filter SP here; this is only used to copy other // Constructor spaces. @@ -263,7 +264,7 @@ namespace { return TypeAndVal.getPointer(); } - Identifier getHead() const { + DeclName getHead() const { assert(getKind() == SpaceKind::Constructor && "Wrong kind of space tried to access head"); return Head; @@ -272,7 +273,7 @@ namespace { Identifier getPrintingName() const { assert(getKind() == SpaceKind::Type && "Wrong kind of space tried to access printing name"); - return Head; + return Head.getBaseIdentifier(); } const std::forward_list &getSpaces() const { @@ -333,7 +334,7 @@ namespace { return this->isSubspace(or2Space, TC, DC); } - return true; + return false; } PAIRCASE (SpaceKind::Type, SpaceKind::Disjunct): { // (_ : Ty1) <= (S1 | ... | Sn) iff (S1 <= S) || ... || (Sn <= S) @@ -372,10 +373,11 @@ namespace { PAIRCASE (SpaceKind::Constructor, SpaceKind::Constructor): { // Optimization: If the constructor heads don't match, subspace is // impossible. + if (this->Head != other.Head) { return false; } - + // Special Case: Short-circuit comparisons with payload-less // constructors. if (other.getSpaces().empty()) { @@ -557,7 +559,8 @@ namespace { PAIRCASE (SpaceKind::Constructor, SpaceKind::Constructor): { // Optimization: If the heads of the constructors don't match then // the two are disjoint and their difference is the first space. - if (this->Head != other.Head) { + if (this->Head.getBaseIdentifier() != + other.Head.getBaseIdentifier()) { return *this; } @@ -696,19 +699,40 @@ namespace { buffer << (getBoolValue() ? "true" : "false"); break; case SpaceKind::Constructor: { - if (!Head.empty()) { + if (!Head.getBaseIdentifier().empty()) { buffer << "."; - buffer << Head.str(); + buffer << Head.getBaseIdentifier().str(); } if (Spaces.empty()) { return; } + auto args = Head.getArgumentNames().begin(); + auto argEnd = Head.getArgumentNames().end(); + + // FIXME: Clean up code for performance buffer << "("; - interleave(Spaces, [&](const Space ¶m) { - param.show(buffer, forDisplay); - }, [&buffer]() { buffer << ", "; }); + llvm::SmallVector, 4> labelSpaces; + for (auto param : Spaces) { + if (args != argEnd) { + labelSpaces.push_back( + std::pair(*args, param)); + args++; + } else + labelSpaces.push_back( + std::pair(Identifier(), param)); + } + interleave( + labelSpaces, + [&](const std::pair ¶m) { + if (!param.first.empty()) { + buffer << param.first; + buffer << ": "; + } + param.second.show(buffer, forDisplay); + }, + [&buffer]() { buffer << ", "; }); buffer << ")"; } break; @@ -800,7 +824,7 @@ namespace { Space::forType(TTy->getUnderlyingType(), Identifier())); } } - return Space::forConstructor(tp, eed->getName(), + return Space::forConstructor(tp, eed->getFullName(), constElemSpaces); }); @@ -961,7 +985,6 @@ namespace { return; Space projection = projectPattern(TC, caseItem.getPattern()); - bool isRedundant = !projection.isEmpty() && llvm::any_of(spaces, [&](const Space &handled) { return projection.isSubspace(handled, TC, DC); @@ -1414,8 +1437,8 @@ namespace { auto subSpace = projectPattern(TC, OSP->getSubPattern()); // To match patterns like (_, _, ...)?, we must rewrite the underlying // tuple pattern to .some(_, _, ...) first. - if (subSpace.getKind() == SpaceKind::Constructor - && subSpace.getHead().empty()) { + if (subSpace.getKind() == SpaceKind::Constructor && + subSpace.getHead().getBaseIdentifier().empty()) { return Space::forConstructor(item->getType(), name, std::move(subSpace.getSpaces())); } diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 8580d6dd5b0..85659710e95 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -214,22 +214,16 @@ Type TypeResolution::resolveDependentMemberType( ref->setValue(singleType, nullptr); } + auto *concrete = ref->getBoundDecl(); + // If the nested type has been resolved to an associated type, use it. - if (auto assocType = dyn_cast(ref->getBoundDecl())) { + if (auto assocType = dyn_cast(concrete)) { return DependentMemberType::get(baseTy, assocType); } // Otherwise, the nested type comes from a concrete type, // or it's a typealias declared in protocol or protocol extension. // Substitute the base type into it. - auto concrete = ref->getBoundDecl(); - if (!concrete->getInterfaceType()) { - ctx.Diags.diagnose(ref->getIdLoc(), diag::recursive_decl_reference, - concrete->getDescriptiveKind(), concrete->getName()); - concrete->diagnose(diag::kind_declared_here, - DescriptiveDeclKind::Type); - return ErrorType::get(ctx); - } // Make sure that base type didn't get replaced along the way. assert(baseTy->isTypeParameter()); @@ -713,16 +707,6 @@ Type TypeChecker::applyGenericArguments(Type type, } } - // Cannot extend a bound generic type. - if (options.is(TypeResolverContext::ExtensionBinding)) { - if (!options.contains(TypeResolutionFlags::SilenceErrors)) { - diags.diagnose(loc, diag::extension_specialization, - genericDecl->getName()) - .highlight(generic->getSourceRange()); - } - return ErrorType::get(ctx); - } - // FIXME: More principled handling of circularity. if (!genericDecl->getGenericSignature()) { diags.diagnose(loc, diag::recursive_decl_reference, @@ -934,33 +918,6 @@ static Type resolveTypeDecl(TypeDecl *typeDecl, SourceLoc loc, DeclContext *foundDC, TypeResolution resolution, GenericIdentTypeRepr *generic, TypeResolutionOptions options) { - auto fromDC = resolution.getDeclContext(); - assert(fromDC && "No declaration context for type resolution?"); - - ASTContext &ctx = typeDecl->getASTContext(); - auto &diags = ctx.Diags; - - // Hack: Don't validate nested typealiases if we only need the structural - // type. - auto prevalidatingAlias = [](TypeDecl *typeDecl, TypeResolution res) { - return isa(typeDecl) - && !typeDecl->hasInterfaceType() - && typeDecl->getDeclContext()->isTypeContext() - && res.getStage() == TypeResolutionStage::Structural; - }; - - // Don't validate nominal type declarations during extension binding. - if ((!options.is(TypeResolverContext::ExtensionBinding) || - !isa(typeDecl)) && - !prevalidatingAlias(typeDecl, resolution)) { - // If we were not able to validate recursively, bail out. - if (!typeDecl->getInterfaceType()) { - diags.diagnose(loc, diag::recursive_decl_reference, - typeDecl->getDescriptiveKind(), typeDecl->getName()); - typeDecl->diagnose(diag::kind_declared_here, DescriptiveDeclKind::Type); - return ErrorType::get(ctx); - } - } // Resolve the type declaration to a specific type. How this occurs // depends on the current context and where the type was found. @@ -971,11 +928,13 @@ static Type resolveTypeDecl(TypeDecl *typeDecl, SourceLoc loc, !options.is(TypeResolverContext::TypeAliasDecl) && !options.contains(TypeResolutionFlags::AllowUnboundGenerics)) { diagnoseUnboundGenericType(type, loc); - return ErrorType::get(ctx); + return ErrorType::get(typeDecl->getASTContext()); } if (type->hasError() && foundDC && (isa(typeDecl) || isa(typeDecl))) { + auto fromDC = resolution.getDeclContext(); + assert(fromDC && "No declaration context for type resolution?"); maybeDiagnoseBadConformanceRef(fromDC, foundDC->getDeclaredInterfaceType(), loc, typeDecl); } @@ -3477,8 +3436,6 @@ public: T->setInvalid(); } } else if (auto *alias = dyn_cast_or_null(comp->getBoundDecl())) { - if (!alias->hasInterfaceType()) - return; auto type = Type(alias->getDeclaredInterfaceType()->getDesugaredType()); type.findIf([&](Type type) -> bool { if (T->isInvalid()) diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index c430cefb2a0..394bf03a52c 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -732,6 +732,13 @@ public: return Diags.diagnose(std::forward(Args)...); } + void diagnoseWithNotes(InFlightDiagnostic parentDiag, + llvm::function_ref builder) { + CompoundDiagnosticTransaction transaction(Diags); + parentDiag.flush(); + builder(); + } + static Type getArraySliceType(SourceLoc loc, Type elementType); static Type getDictionaryType(SourceLoc loc, Type keyType, Type valueType); static Type getOptionalType(SourceLoc loc, Type elementType); @@ -1016,9 +1023,6 @@ public: Type checkReferenceOwnershipAttr(VarDecl *D, Type interfaceType, ReferenceOwnershipAttr *attr); - /// Check the raw value expression in this enum element. - void checkRawValueExpr(EnumDecl *parent, EnumElementDecl *Elt); - virtual void resolveDeclSignature(ValueDecl *VD) override { validateDecl(VD); } @@ -1898,7 +1902,7 @@ public: void checkTopLevelErrorHandling(TopLevelCodeDecl *D); void checkFunctionErrorHandling(AbstractFunctionDecl *D); void checkInitializerErrorHandling(Initializer *I, Expr *E); - void checkEnumElementErrorHandling(EnumElementDecl *D); + void checkEnumElementErrorHandling(EnumElementDecl *D, Expr *expr); void checkPropertyWrapperErrorHandling(PatternBindingDecl *binding, Expr *expr); diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index a40d53ed54d..b6f9a634511 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -1120,11 +1120,14 @@ static void filterValues(Type expectedTy, ModuleDecl *expectedModule, if (isType != isa(value)) return true; - auto ifaceTy = value->getInterfaceType(); - if (!ifaceTy) - return true; - if (canTy && ifaceTy->getCanonicalType() != canTy) - return true; + + // If we're expecting a type, make sure this decl has the expected type. + if (canTy) { + auto ifaceTy = value->getInterfaceType(); + if (!ifaceTy || !ifaceTy->isEqual(canTy)) + return true; + } + if (value->isStatic() != isStatic) return true; if (value->hasClangNode() != importedFromClang) @@ -2242,8 +2245,6 @@ public: if (!filenameForPrivate.empty()) MF.FilenamesForPrivateValues[value] = filenameForPrivate; } - - decl->setValidationToChecked(); } /// Deserializes decl attribute and attribute-like records from @@ -2294,7 +2295,6 @@ public: auto underlying = MF.getType(underlyingTypeID); alias->setUnderlyingType(underlying); alias->computeType(); - alias->setValidationToChecked(); if (auto accessLevel = getActualAccessLevel(rawAccessLevel)) alias->setAccess(*accessLevel); @@ -3484,6 +3484,11 @@ public: MF.fatal(); theEnum->setAddedImplicitInitializers(); + // @objc enums have all their raw values checked. + if (isObjC) { + theEnum->setHasFixedRawValues(); + } + if (isImplicit) theEnum->setImplicit(); theEnum->setIsObjC(isObjC); diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 30df3fd05eb..45904057c1c 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -3342,7 +3342,7 @@ public: if (elem->getParentEnum()->isObjC()) { // Currently ObjC enums always have integer raw values. rawValueKind = EnumElementRawValueKind::IntegerLiteral; - auto ILE = cast(elem->getRawValueExpr()); + auto ILE = cast(elem->getStructuralRawValueExpr()); RawValueText = ILE->getDigitsText(); isNegative = ILE->isNegative(); isRawValueImplicit = ILE->isImplicit(); diff --git a/lib/Syntax/Syntax.cpp b/lib/Syntax/Syntax.cpp index 57aa313597c..850fb9ecbf0 100644 --- a/lib/Syntax/Syntax.cpp +++ b/lib/Syntax/Syntax.cpp @@ -18,7 +18,7 @@ using namespace swift; using namespace swift::syntax; -RC Syntax::getRaw() const { +const RC &Syntax::getRaw() const { return Data->getRaw(); } diff --git a/lib/TBDGen/CMakeLists.txt b/lib/TBDGen/CMakeLists.txt index 6928dc57a2b..e2a96a306b6 100644 --- a/lib/TBDGen/CMakeLists.txt +++ b/lib/TBDGen/CMakeLists.txt @@ -1,10 +1,8 @@ -add_subdirectory(tapi) - add_swift_host_library(swiftTBDGen STATIC - ${TAPI_SOURCES} TBDGen.cpp LLVM_LINK_COMPONENTS demangle + TextAPI ) target_link_libraries(swiftTBDGen PRIVATE swiftAST diff --git a/lib/TBDGen/TBDGen.cpp b/lib/TBDGen/TBDGen.cpp index 0d40a5a41e4..e549407aaae 100644 --- a/lib/TBDGen/TBDGen.cpp +++ b/lib/TBDGen/TBDGen.cpp @@ -35,19 +35,17 @@ #include "llvm/ADT/StringSet.h" #include "llvm/Support/Error.h" #include "llvm/Support/YAMLTraits.h" +#include "llvm/TextAPI/MachO/InterfaceFile.h" +#include "llvm/TextAPI/MachO/TextAPIReader.h" +#include "llvm/TextAPI/MachO/TextAPIWriter.h" #include "TBDGenVisitor.h" -#include "tapi/Architecture.h" -#include "tapi/InterfaceFile.h" -#include "tapi/Platform.h" -#include "tapi/TextStub_v3.h" -#include "tapi/YAMLReaderWriter.h" using namespace swift; using namespace swift::irgen; using namespace swift::tbdgen; using StringSet = llvm::StringSet<>; -using SymbolKind = tapi::internal::SymbolKind; +using SymbolKind = llvm::MachO::SymbolKind; static bool isGlobalOrStaticVar(VarDecl *VD) { return VD->isStatic() || VD->getDeclContext()->isModuleScopeContext(); @@ -588,14 +586,14 @@ void TBDGenVisitor::addFirstFileSymbols() { /// Converts a version tuple into a packed version, ignoring components beyond /// major, minor, and subminor. -static tapi::internal::PackedVersion +static llvm::MachO::PackedVersion convertToPacked(const version::Version &version) { // FIXME: Warn if version is greater than 3 components? unsigned major = 0, minor = 0, subminor = 0; if (version.size() > 0) major = version[0]; if (version.size() > 1) minor = version[1]; if (version.size() > 2) subminor = version[2]; - return tapi::internal::PackedVersion(major, minor, subminor); + return llvm::MachO::PackedVersion(major, minor, subminor); } static bool isApplicationExtensionSafe(const LangOptions &LangOpts) { @@ -611,8 +609,9 @@ static void enumeratePublicSymbolsAndWrite(ModuleDecl *M, FileUnit *singleFile, const auto &target = ctx.LangOpts.Target; UniversalLinkageInfo linkInfo(target, opts.HasMultipleIGMs, false, isWholeModule); - tapi::internal::InterfaceFile file; - file.setFileType(tapi::internal::FileType::TBD_V3); + + llvm::MachO::InterfaceFile file; + file.setFileType(llvm::MachO::FileType::TBD_V3); file.setApplicationExtensionSafe( isApplicationExtensionSafe(M->getASTContext().LangOpts)); file.setInstallName(opts.InstallName); @@ -620,11 +619,27 @@ static void enumeratePublicSymbolsAndWrite(ModuleDecl *M, FileUnit *singleFile, file.setCompatibilityVersion(convertToPacked(opts.CompatibilityVersion)); file.setTwoLevelNamespace(); file.setSwiftABIVersion(irgen::getSwiftABIVersion()); - file.setPlatform(tapi::internal::mapToSinglePlatform(target)); - auto arch = tapi::internal::getArchType(target.getArchName()); - file.setArch(arch); file.setInstallAPI(opts.IsInstallAPI); + auto getPlatformKind = + [](const llvm::Triple &Target) -> llvm::MachO::PlatformKind { + switch (Target.getOS()) { + default: + return llvm::MachO::PlatformKind::unknown; + case llvm::Triple::MacOSX: + return llvm::MachO::PlatformKind::macOS; + case llvm::Triple::IOS: + return llvm::MachO::PlatformKind::iOS; + case llvm::Triple::TvOS: + return llvm::MachO::PlatformKind::tvOS; + case llvm::Triple::WatchOS: + return llvm::MachO::PlatformKind::watchOS; + } + }; + auto arch = llvm::MachO::getArchitectureFromName(target.getArchName()); + file.addArch(arch); + file.setPlatform(getPlatformKind(target)); + TBDGenVisitor visitor(file, arch, symbols, linkInfo, M, opts); auto visitFile = [&](FileUnit *file) { @@ -651,13 +666,7 @@ static void enumeratePublicSymbolsAndWrite(ModuleDecl *M, FileUnit *singleFile, } if (os) { - tapi::internal::YAMLWriter writer; - writer.add( - llvm::make_unique()); - - assert(writer.canWrite(&file) && - "YAML writer should be able to write TBD v3"); - llvm::cantFail(writer.writeFile(*os, &file), + llvm::cantFail(llvm::MachO::TextAPIWriter::writeToStream(*os, file), "YAML writing should be error-free"); } } diff --git a/lib/TBDGen/TBDGenVisitor.h b/lib/TBDGen/TBDGenVisitor.h index 5453322f810..227fed22400 100644 --- a/lib/TBDGen/TBDGenVisitor.h +++ b/lib/TBDGen/TBDGenVisitor.h @@ -29,8 +29,7 @@ #include "swift/SIL/TypeLowering.h" #include "llvm/ADT/StringSet.h" #include "llvm/ADT/Triple.h" - -#include "tapi/InterfaceFile.h" +#include "llvm/TextAPI/MachO/InterfaceFile.h" using namespace swift::irgen; using StringSet = llvm::StringSet<>; @@ -43,8 +42,8 @@ namespace tbdgen { class TBDGenVisitor : public ASTVisitor { public: - tapi::internal::InterfaceFile &Symbols; - tapi::internal::ArchitectureSet Archs; + llvm::MachO::InterfaceFile &Symbols; + llvm::MachO::ArchitectureSet Archs; StringSet *StringSymbols; const UniversalLinkageInfo &UniversalLinkInfo; @@ -52,8 +51,8 @@ public: const TBDGenOptions &Opts; private: - void addSymbol(StringRef name, tapi::internal::SymbolKind kind = - tapi::internal::SymbolKind::GlobalSymbol); + void addSymbol(StringRef name, llvm::MachO::SymbolKind kind = + llvm::MachO::SymbolKind::GlobalSymbol); void addSymbol(SILDeclRef declRef); @@ -71,8 +70,8 @@ private: void addBaseConformanceDescriptor(BaseConformance conformance); public: - TBDGenVisitor(tapi::internal::InterfaceFile &symbols, - tapi::internal::ArchitectureSet archs, StringSet *stringSymbols, + TBDGenVisitor(llvm::MachO::InterfaceFile &symbols, + llvm::MachO::ArchitectureSet archs, StringSet *stringSymbols, const UniversalLinkageInfo &universalLinkInfo, ModuleDecl *swiftModule, const TBDGenOptions &opts) : Symbols(symbols), Archs(archs), StringSymbols(stringSymbols), diff --git a/lib/TBDGen/tapi/APIVersion.h b/lib/TBDGen/tapi/APIVersion.h deleted file mode 100644 index c789c47f22f..00000000000 --- a/lib/TBDGen/tapi/APIVersion.h +++ /dev/null @@ -1,130 +0,0 @@ -//===-- tapi/APIVersion.h - TAPI API Version Interface ----------*- C++ -*-===*\ -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Access the TAPI API version information and feature availability. -/// \since 1.0 -/// -//===----------------------------------------------------------------------===// -#ifndef TAPI_API_VERSION_H -#define TAPI_API_VERSION_H - -#include "Defines.h" - -/// -/// \defgroup TAPI_API_VERSION API Version and Feature methods -/// \ingroup TAPI_CPP_API -/// -/// @{ -/// - -#define TAPI_API_VERSION_MAJOR 1U -#define TAPI_API_VERSION_MINOR 4U -#define TAPI_API_VERSION_PATCH 0U - -namespace tapi { - -/// -/// Defines a list of TAPI library features. -/// \since 1.0 -/// -enum class Feature : unsigned {}; - -/// -/// Access to API version, feature and ABI related information about the -/// TAPI dynamic library. -/// \since 1.0 -/// -class TAPI_PUBLIC APIVersion { -public: - /// - /// \name API Version Number Methods - /// @{ - /// - - /// - /// Get the major API version number. - /// \return The major API version number as unsigned integer. - /// \since 1.0 - /// - static unsigned getMajor() noexcept; - - /// - /// Get the minor API version number. - /// \return The minor API version number as unsigned integer. - /// \since 1.0 - /// - static unsigned getMinor() noexcept; - - /// - /// Get the patch API version number. - /// \return The patch API version as unsigned integer. - /// \since 1.0 - /// - static unsigned getPatch() noexcept; - - /// - /// Check if the current API version is at least the specified API - /// version or greater. - /// \param[in] major The major API version number to compare against. - /// \param[in] minor The minor API version number to compare against. - /// \param[in] patch The patch API version number to compare against. - /// \return True if the current API version number is at least the specified - /// version or greater. - /// \since 1.0 - /// - static bool isAtLeast(unsigned major, unsigned minor = 0, - unsigned patch = 0) noexcept; - - /// - /// @} - /// - - /// - /// \name Feature Methods - /// @{ - /// - - /// - /// Check if the library supports a particular #Feature. - /// \param[in] feature The #Feature to be queried for. - /// \return True if \a feature is supported. - /// \since 1.0 - /// - static bool hasFeature(Feature feature) noexcept; - - /// - /// @} - /// - - /// - /// \name ABI Methods - /// @{ - /// - - /// - /// Check if the library supports the specified ABI version. - /// \param[in] abiVersion The ABI version to query for. - /// \return True if the library supports the ABI version \a abiVersion. - /// \since 1.0 - /// - static bool hasABI(unsigned abiVersion) noexcept; - - /// - /// @} - /// -}; - -} // end tapi namespace. - -/// -/// @} -/// - -#endif // TAPI_API_VERSION_H diff --git a/lib/TBDGen/tapi/Architecture.cpp b/lib/TBDGen/tapi/Architecture.cpp deleted file mode 100644 index a62b3fdb45f..00000000000 --- a/lib/TBDGen/tapi/Architecture.cpp +++ /dev/null @@ -1,83 +0,0 @@ -//===- tapi/Core/Architecture.cpp - Architecture ----------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Implements the architecture. -/// -//===----------------------------------------------------------------------===// - -#include "Architecture.h" -#include "LLVM.h" -#include "Defines.h" -#include "clang/Basic/Diagnostic.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/BinaryFormat/MachO.h" -#include "llvm/Support/raw_ostream.h" - -using namespace llvm; - -TAPI_NAMESPACE_INTERNAL_BEGIN - -Architecture getArchType(uint32_t CPUType, uint32_t CPUSubType) { -#define ARCHINFO(arch, type, subtype) \ - if (CPUType == (type) && \ - (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) == (subtype)) \ - return Architecture::arch; -#include "Architecture.def" -#undef ARCHINFO - - return Architecture::unknown; -} - -Architecture getArchType(StringRef name) { - return StringSwitch(name) -#define ARCHINFO(arch, type, subtype) .Case(#arch, Architecture::arch) -#include "Architecture.def" -#undef ARCHINFO - .Default(Architecture::unknown); -} - -StringRef getArchName(Architecture arch) { - switch (arch) { -#define ARCHINFO(arch, type, subtype) \ - case Architecture::arch: \ - return #arch; -#include "Architecture.def" -#undef ARCHINFO - case Architecture::unknown: - return "unknown"; - } - llvm_unreachable("unknown architecutre"); -} - -std::pair getCPUType(Architecture arch) { - switch (arch) { -#define ARCHINFO(arch, type, subtype) \ - case Architecture::arch: \ - return std::make_pair(type, subtype); -#include "Architecture.def" -#undef ARCHINFO - case Architecture::unknown: - return std::make_pair(0, 0); - } - llvm_unreachable("unknown architecture"); -} - -raw_ostream &operator<<(raw_ostream &os, Architecture arch) { - os << getArchName(arch); - return os; -} - -const DiagnosticBuilder &operator<<(const DiagnosticBuilder &db, - Architecture arch) { - db.AddString(getArchName(arch)); - return db; -} - -TAPI_NAMESPACE_INTERNAL_END diff --git a/lib/TBDGen/tapi/Architecture.def b/lib/TBDGen/tapi/Architecture.def deleted file mode 100644 index b8ce7bc0f81..00000000000 --- a/lib/TBDGen/tapi/Architecture.def +++ /dev/null @@ -1,71 +0,0 @@ -#include "ArchitectureConfig.h" - -#ifndef ARCHINFO -#define ARCHINFO(arch) -#endif - -/// -/// X86 architectures sorted by cpu type and sub type id. -/// - -#ifdef SUPPORT_ARCH_I386 -ARCHINFO(i386, MachO::CPU_TYPE_I386, MachO::CPU_SUBTYPE_I386_ALL) -#endif - -#ifdef SUPPORT_ARCH_X86_64 -ARCHINFO(x86_64, MachO::CPU_TYPE_X86_64, MachO::CPU_SUBTYPE_X86_64_ALL) -#endif - -#ifdef SUPPORT_ARCH_X86_64H -ARCHINFO(x86_64h, MachO::CPU_TYPE_X86_64, MachO::CPU_SUBTYPE_X86_64_H) -#endif - - -/// -/// ARM architectures sorted by cpu sub type id. -/// - -#ifdef SUPPORT_ARCH_ARMV4T -ARCHINFO(armv4t, MachO::CPU_TYPE_ARM, MachO::CPU_SUBTYPE_ARM_V4T) -#endif - -#ifdef SUPPORT_ARCH_ARMV6 -ARCHINFO(armv6, MachO::CPU_TYPE_ARM, MachO::CPU_SUBTYPE_ARM_V6) -#endif - -#ifdef SUPPORT_ARCH_ARMV5 -ARCHINFO(armv5, MachO::CPU_TYPE_ARM, MachO::CPU_SUBTYPE_ARM_V5TEJ) -#endif - -#ifdef SUPPORT_ARCH_ARMV7 -ARCHINFO(armv7, MachO::CPU_TYPE_ARM, MachO::CPU_SUBTYPE_ARM_V7) -#endif - -#ifdef SUPPORT_ARCH_ARMV7S -ARCHINFO(armv7s, MachO::CPU_TYPE_ARM, MachO::CPU_SUBTYPE_ARM_V7S) -#endif - -#ifdef SUPPORT_ARCH_ARMV7K -ARCHINFO(armv7k, MachO::CPU_TYPE_ARM, MachO::CPU_SUBTYPE_ARM_V7K) -#endif - -#ifdef SUPPORT_ARCH_ARMV6M -ARCHINFO(armv6m, MachO::CPU_TYPE_ARM, MachO::CPU_SUBTYPE_ARM_V6M) -#endif - -#ifdef SUPPORT_ARCH_ARMV7M -ARCHINFO(armv7m, MachO::CPU_TYPE_ARM, MachO::CPU_SUBTYPE_ARM_V7M) -#endif - -#ifdef SUPPORT_ARCH_ARMV7EM -ARCHINFO(armv7em, MachO::CPU_TYPE_ARM, MachO::CPU_SUBTYPE_ARM_V7EM) -#endif - - -/// -/// ARM64 architectures sorted by cpu sub type id. -/// - -#ifdef SUPPORT_ARCH_ARM64 -ARCHINFO(arm64, MachO::CPU_TYPE_ARM64, MachO::CPU_SUBTYPE_ARM64_ALL) -#endif diff --git a/lib/TBDGen/tapi/Architecture.h b/lib/TBDGen/tapi/Architecture.h deleted file mode 100644 index a704bcf67f5..00000000000 --- a/lib/TBDGen/tapi/Architecture.h +++ /dev/null @@ -1,43 +0,0 @@ -//===- tapi/Core/Architecture.h - Architecture ------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Defines architecture enum. -/// -//===----------------------------------------------------------------------===// - -#ifndef TAPI_CORE_ARCHITECTURE_H -#define TAPI_CORE_ARCHITECTURE_H - -#include "LLVM.h" -#include "Defines.h" -#include "llvm/ADT/StringRef.h" - -TAPI_NAMESPACE_INTERNAL_BEGIN - -enum class Architecture : uint8_t { -#define ARCHINFO(arch, type, subtype) arch, -#include "Architecture.def" -#undef ARCHINFO - unknown, // this has to go last. -}; - -Architecture getArchType(uint32_t CPUType, uint32_t CPUSubType); -Architecture getArchType(StringRef name); -StringRef getArchName(Architecture arch); -std::pair getCPUType(Architecture arch); - -raw_ostream &operator<<(raw_ostream &os, Architecture arch); - -const DiagnosticBuilder &operator<<(const DiagnosticBuilder &db, - Architecture arch); - -TAPI_NAMESPACE_INTERNAL_END - -#endif // TAPI_CORE_ARCHITECTURE_H diff --git a/lib/TBDGen/tapi/ArchitectureConfig.h b/lib/TBDGen/tapi/ArchitectureConfig.h deleted file mode 100644 index ef6c7ad3337..00000000000 --- a/lib/TBDGen/tapi/ArchitectureConfig.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef TAPI_CORE_ARCHITECTURE_CONFIG_H -#define TAPI_CORE_ARCHITECTURE_CONFIG_H - -#define SUPPORT_ARCH_I386 1 -#define SUPPORT_ARCH_X86_64 1 -#define SUPPORT_ARCH_X86_64H 1 -#define SUPPORT_ARCH_ARMV4T 1 -#define SUPPORT_ARCH_ARMV6 1 -#define SUPPORT_ARCH_ARMV5 1 -#define SUPPORT_ARCH_ARMV7 1 -#define SUPPORT_ARCH_ARMV7S 1 -#define SUPPORT_ARCH_ARMV7K 1 -#define SUPPORT_ARCH_ARMV6M 1 -#define SUPPORT_ARCH_ARMV7M 1 -#define SUPPORT_ARCH_ARMV7EM 1 -#define SUPPORT_ARCH_ARM64 1 - -#endif // TAPI_CORE_ARCHITECTURE_CONFIG_H diff --git a/lib/TBDGen/tapi/ArchitectureSet.cpp b/lib/TBDGen/tapi/ArchitectureSet.cpp deleted file mode 100644 index 00ecfd1aca2..00000000000 --- a/lib/TBDGen/tapi/ArchitectureSet.cpp +++ /dev/null @@ -1,101 +0,0 @@ -//===- tapi/Core/ArchitectureSet.cpp - Architecture Set -*- C++ -*---------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Implements the architecture set. -/// -//===----------------------------------------------------------------------===// - -#include "ArchitectureSet.h" -#include "LLVM.h" -#include "Defines.h" -#include "clang/Basic/Diagnostic.h" -#include "llvm/Support/raw_ostream.h" -#include - -using namespace llvm; - -TAPI_NAMESPACE_INTERNAL_BEGIN - -bool ArchitectureSet::hasABICompatibleSlice(Architecture arch) const { - uint32_t cpuType; - std::tie(cpuType, std::ignore) = getCPUType(arch); - - for (auto arch2 : *this) { - uint32_t cpuType2; - std::tie(cpuType2, std::ignore) = getCPUType(arch2); - - if (cpuType == cpuType2) - return true; - } - - return false; -} - -Architecture ArchitectureSet::getABICompatibleSlice(Architecture arch) const { - uint32_t cpuType; - std::tie(cpuType, std::ignore) = getCPUType(arch); - - for (auto arch2 : *this) { - uint32_t cpuType2; - std::tie(cpuType2, std::ignore) = getCPUType(arch2); - - if (cpuType == cpuType2) - return arch2; - } - - return Architecture::unknown; -} - -ArchitectureSet::operator std::string() const { - if (empty()) - return "[(empty)]"; - - std::string result; - auto size = count(); - for (auto arch : *this) { - result.append(getArchName(arch)); - size -= 1; - if (size) - result.append(" "); - } - return result; -} - -ArchitectureSet::operator std::vector() const { - std::vector archs; - for (auto arch : *this) { - if (arch == Architecture::unknown) - continue; - archs.emplace_back(arch); - } - return archs; -} - -void ArchitectureSet::print(raw_ostream &os) const { os << std::string(*this); } - -raw_ostream &operator<<(raw_ostream &os, ArchitectureSet set) { - set.print(os); - return os; -} - -const DiagnosticBuilder &operator<<(const DiagnosticBuilder &db, - ArchitectureSet architectureSet) { - db.AddString(std::string(architectureSet)); - return db; -} - -ArchitectureSet mapToArchitectureSet(const std::vector &targets) { - ArchitectureSet result; - for (const auto &target : targets) - result |= getArchType(target.getArchName()); - return result; -} - -TAPI_NAMESPACE_INTERNAL_END diff --git a/lib/TBDGen/tapi/ArchitectureSet.h b/lib/TBDGen/tapi/ArchitectureSet.h deleted file mode 100644 index a261527a700..00000000000 --- a/lib/TBDGen/tapi/ArchitectureSet.h +++ /dev/null @@ -1,198 +0,0 @@ -//===- tapi/Core/ArchitectureSet.h - Architecture Set -----------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Defines the architecture set. -/// -//===----------------------------------------------------------------------===// - -#ifndef TAPI_CORE_ARCHITECTURE_SET_H -#define TAPI_CORE_ARCHITECTURE_SET_H - -#include "Architecture.h" -#include "ArchitectureConfig.h" -#include "LLVM.h" -#include "Defines.h" -#include "llvm/ADT/Triple.h" -#include -#include -#include -#include -#include - -TAPI_NAMESPACE_INTERNAL_BEGIN - -class ArchitectureSet { -private: - using ArchSetType = uint32_t; - - const static ArchSetType _endIndexVal = - std::numeric_limits::max(); - ArchSetType _archSet{0}; - -public: - constexpr ArchitectureSet() = default; - ArchitectureSet(ArchSetType raw) : _archSet(raw) {} - ArchitectureSet(Architecture arch) : ArchitectureSet() { set(arch); } - ArchitectureSet(const std::vector &archs) : ArchitectureSet() { - for (auto arch : archs) { - if (arch == Architecture::unknown) - continue; - set(arch); - } - } - - static ArchitectureSet All() { - return ArchitectureSet(_endIndexVal); - } - - void set(Architecture arch) { - if (arch == Architecture::unknown) - return; - _archSet |= 1U << static_cast(arch); - } - void clear(Architecture arch) { _archSet &= ~(1U << static_cast(arch)); } - bool has(Architecture arch) const { - return _archSet & (1U << static_cast(arch)); - } - bool contains(ArchitectureSet archs) const { - return (_archSet & archs._archSet) == archs._archSet; - } - - size_t count() const { - // popcnt - size_t cnt = 0; - for (unsigned i = 0; i < sizeof(ArchSetType) * 8; ++i) - if (_archSet & (1U << i)) - ++cnt; - return cnt; - } - - bool empty() const { return _archSet == 0; } - - ArchSetType rawValue() const { return _archSet; } - - bool hasX86() const { -#ifdef SUPPORT_ARCH_I386 - if (has(Architecture::i386)) - return true; -#endif - -#ifdef SUPPORT_ARCH_X86_64 - if (has(Architecture::x86_64)) - return true; -#endif - -#ifdef SUPPORT_ARCH_X86_64H - if (has(Architecture::x86_64h)) - return true; -#endif - - return false; - } - - bool hasABICompatibleSlice(Architecture arch) const; - - Architecture getABICompatibleSlice(Architecture arch) const; - - template - class arch_iterator - : public std::iterator { - private: - ArchSetType _index; - Ty *_archSet; - - void findNextSetBit() { - if (_index == _endIndexVal) - return; - - do { - if (*_archSet & (1UL << ++_index)) - return; - } while (_index < sizeof(Ty) * 8); - - _index = _endIndexVal; - } - - public: - arch_iterator(Ty *archSet, ArchSetType index = 0) - : _index(index), _archSet(archSet) { - if (index != _endIndexVal && !(*_archSet & (1UL << index))) - findNextSetBit(); - } - - Architecture operator*() const { return static_cast(_index); } - - arch_iterator &operator++() { - findNextSetBit(); - return *this; - } - - arch_iterator operator++(int) { - auto tmp = *this; - findNextSetBit(); - return tmp; - } - - bool operator==(const arch_iterator &o) const { - return std::tie(_index, _archSet) == std::tie(o._index, o._archSet); - } - - bool operator!=(const arch_iterator &o) const { return !(*this == o); } - }; - - ArchitectureSet operator&(const ArchitectureSet &o) { - return {_archSet & o._archSet}; - } - - ArchitectureSet operator|(const ArchitectureSet &o) { - return {_archSet | o._archSet}; - } - - ArchitectureSet &operator|=(const ArchitectureSet &o) { - _archSet |= o._archSet; - return *this; - } - - bool operator==(const ArchitectureSet &o) const { - return _archSet == o._archSet; - } - - bool operator!=(const ArchitectureSet &o) const { - return _archSet != o._archSet; - } - - bool operator<(const ArchitectureSet &o) const { - return _archSet < o._archSet; - } - - using iterator = arch_iterator; - using const_iterator = arch_iterator; - - iterator begin() { return {&_archSet}; } - iterator end() { return {&_archSet, _endIndexVal}; } - - const_iterator begin() const { return {&_archSet}; } - const_iterator end() const { return {&_archSet, _endIndexVal}; } - - operator std::string() const; - operator std::vector() const; - void print(raw_ostream &os) const; -}; - -ArchitectureSet mapToArchitectureSet(const std::vector &targets); - -raw_ostream &operator<<(raw_ostream &os, ArchitectureSet set); - -const DiagnosticBuilder &operator<<(const DiagnosticBuilder &db, - ArchitectureSet architectureSet); - -TAPI_NAMESPACE_INTERNAL_END - -#endif // TAPI_CORE_ARCHITECTURE_SET_H diff --git a/lib/TBDGen/tapi/ArchitectureSupport.cpp b/lib/TBDGen/tapi/ArchitectureSupport.cpp deleted file mode 100644 index 217797bcb4c..00000000000 --- a/lib/TBDGen/tapi/ArchitectureSupport.cpp +++ /dev/null @@ -1,126 +0,0 @@ -//===- tapi/Core/ArchitectureSupport.cpp - Architecture Support -*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Implements architecture specific helper functions. -/// -//===----------------------------------------------------------------------===// - -#include "ArchitectureSupport.h" -#include "LLVM.h" -#include "clang/Basic/Diagnostic.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/raw_ostream.h" - -using namespace llvm; - -TAPI_NAMESPACE_INTERNAL_BEGIN - -bool PackedVersion::parse32(StringRef str) { - _version = 0; - - if (str.empty()) - return false; - - SmallVector parts; - SplitString(str, parts, "."); - - if (parts.size() > 3) - return false; - - unsigned long long num; - if (getAsUnsignedInteger(parts[0], 10, num)) - return false; - - if (num > UINT16_MAX) - return false; - - _version = num << 16; - - for (unsigned i = 1, shiftNum = 8; i < parts.size(); ++i, shiftNum -= 8) { - if (getAsUnsignedInteger(parts[i], 10, num)) - return false; - - if (num > UINT8_MAX) - return false; - - _version |= (num << shiftNum); - } - - return true; -} - -std::pair PackedVersion::parse64(StringRef str) { - bool truncated = false; - _version = 0; - - if (str.empty()) - return std::make_pair(false, truncated); - - SmallVector parts; - SplitString(str, parts, "."); - - if (parts.size() > 5) - return std::make_pair(false, truncated); - - unsigned long long num; - if (getAsUnsignedInteger(parts[0], 10, num)) - return std::make_pair(false, truncated); - - if (num > 0xFFFFFFULL) - return std::make_pair(false, truncated); - - if (num > 0xFFFFULL) { - num = 0xFFFFULL; - truncated = true; - } - _version = num << 16; - - for (unsigned i = 1, shiftNum = 8; i < parts.size() && i < 3; - ++i, shiftNum -= 8) { - if (getAsUnsignedInteger(parts[i], 10, num)) - return std::make_pair(false, truncated); - - if (num > 0x3FFULL) - return std::make_pair(false, truncated); - - if (num > 0xFFULL) { - num = 0xFFULL; - truncated = true; - } - _version |= (num << shiftNum); - } - - if (parts.size() > 3) - truncated = true; - - return std::make_pair(true, truncated); -} - -void PackedVersion::print(raw_ostream &os) const { - os << format("%d", getMajor()); - if (getMinor() || getSubminor()) - os << format(".%d", getMinor()); - if (getSubminor()) - os << format(".%d", getSubminor()); -} - -const DiagnosticBuilder &operator<<(const DiagnosticBuilder &db, - const PackedVersion &version) { - SmallString<32> string; - raw_svector_ostream os(string); - os << version; - db.AddString(string); - return db; -} - -TAPI_NAMESPACE_INTERNAL_END diff --git a/lib/TBDGen/tapi/ArchitectureSupport.h b/lib/TBDGen/tapi/ArchitectureSupport.h deleted file mode 100644 index 3375089435a..00000000000 --- a/lib/TBDGen/tapi/ArchitectureSupport.h +++ /dev/null @@ -1,93 +0,0 @@ -//===- tapi/Core/ArchitectureSupport.h - Architecture Support ---*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Defines architecture specific enums and helper functions. -/// -//===----------------------------------------------------------------------===// - -#ifndef TAPI_CORE_ARCHITECTURE_SUPPORT_H -#define TAPI_CORE_ARCHITECTURE_SUPPORT_H - -#include "Architecture.h" -#include "LLVM.h" -#include "Defines.h" -#include "LinkerInterfaceFile.h" -#include "PackedVersion32.h" -#include "tapi.h" -#include "llvm/ADT/StringRef.h" -//#include "llvm/Support/VersionTuple.h" -#include "llvm/Support/raw_ostream.h" -#include - -TAPI_NAMESPACE_INTERNAL_BEGIN - -struct PackedVersion { - uint32_t _version{0}; - - constexpr PackedVersion() = default; - constexpr PackedVersion(uint32_t version) : _version(version) {} - PackedVersion(unsigned major, unsigned minor, unsigned subminor) - : _version((major << 16) | ((minor & 0xff) << 8) | (subminor & 0xff)) {} - /*PackedVersion(llvm::VersionTuple version) { - _version = version.getMajor() << 16; - if (auto minor = version.getMinor()) - _version |= (*minor & 0xff) << 8; - if (auto subminor = version.getSubminor()) - _version |= *subminor & 0xff; - }*/ - - bool empty() const { return _version == 0; } - - /// Retrieve the major version number. - unsigned getMajor() const { return _version >> 16; } - - /// Retrieve the minor version number, if provided. - unsigned getMinor() const { return (_version >> 8) & 0xff; } - - /// Retrieve the subminor version number, if provided. - unsigned getSubminor() const { return _version & 0xff; } - - bool parse32(StringRef str); - std::pair parse64(StringRef str); - - bool operator<(const PackedVersion &rhs) const { - return _version < rhs._version; - } - - bool operator<=(const PackedVersion &rhs) const { - return _version <= rhs._version; - } - - bool operator==(const PackedVersion &rhs) const { - return _version == rhs._version; - } - - bool operator!=(const PackedVersion &rhs) const { - return _version != rhs._version; - } - - void print(raw_ostream &os) const; - - operator PackedVersion32() const { - return {getMajor(), getMinor(), getSubminor()}; - } -}; - -inline raw_ostream &operator<<(raw_ostream &os, const PackedVersion &version) { - version.print(os); - return os; -} - -const DiagnosticBuilder &operator<<(const DiagnosticBuilder &db, - const PackedVersion &version); - -TAPI_NAMESPACE_INTERNAL_END - -#endif // TAPI_CORE_ARCHITECTURE_SUPPORT_H diff --git a/lib/TBDGen/tapi/AvailabilityInfo.cpp b/lib/TBDGen/tapi/AvailabilityInfo.cpp deleted file mode 100644 index 54ddf6c5c51..00000000000 --- a/lib/TBDGen/tapi/AvailabilityInfo.cpp +++ /dev/null @@ -1,22 +0,0 @@ -//===- lib/Core/AvailabilityInfo.cpp - Availability Info --------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "AvailabilityInfo.h" -#include "LLVM.h" - -using namespace llvm; - -TAPI_NAMESPACE_INTERNAL_BEGIN - -void AvailabilityInfo::print(raw_ostream &os) const { - os << "i:" << _introduced << " o:" << _obsoleted - << " u:" << static_cast((bool)_unavailable); -} - -TAPI_NAMESPACE_INTERNAL_END diff --git a/lib/TBDGen/tapi/AvailabilityInfo.h b/lib/TBDGen/tapi/AvailabilityInfo.h deleted file mode 100644 index 5685695760a..00000000000 --- a/lib/TBDGen/tapi/AvailabilityInfo.h +++ /dev/null @@ -1,87 +0,0 @@ -//===- tapi/Core/AvailabilityInfo.h - TAPI Availability Info ----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Defines the Availability Info. -/// -//===----------------------------------------------------------------------===// - -#ifndef TAPI_CORE_AVAILABILITY_INFO_H -#define TAPI_CORE_AVAILABILITY_INFO_H - -#include "ArchitectureSupport.h" -#include "LLVM.h" -#include "Defines.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/Support/Error.h" - -TAPI_NAMESPACE_INTERNAL_BEGIN - -struct AvailabilityInfo { - PackedVersion _introduced{0}; - PackedVersion _obsoleted{0}; - bool _unavailable{false}; - - constexpr AvailabilityInfo(bool unavailable = false) - : _unavailable(unavailable) {} - - constexpr AvailabilityInfo(PackedVersion i, PackedVersion o, bool u) - : _introduced(i), _obsoleted(o), _unavailable(u) {} - - bool isDefault() const { return *this == AvailabilityInfo(); } - - llvm::Error merge(const AvailabilityInfo &other) { - if (*this == other || other.isDefault()) - return llvm::Error::success(); - - if (isDefault()) { - *this = other; - return llvm::Error::success(); - } - - return llvm::make_error( - "availabilities do not match", - std::make_error_code(std::errc::not_supported)); - } - - void print(raw_ostream &os) const; - - friend bool operator==(const AvailabilityInfo &lhs, - const AvailabilityInfo &rhs); - friend bool operator!=(const AvailabilityInfo &lhs, - const AvailabilityInfo &rhs); - friend bool operator<(const AvailabilityInfo &lhs, - const AvailabilityInfo &rhs); -}; - -inline bool operator==(const AvailabilityInfo &lhs, - const AvailabilityInfo &rhs) { - return std::tie(lhs._introduced, lhs._obsoleted, lhs._unavailable) == - std::tie(rhs._introduced, rhs._obsoleted, rhs._unavailable); -} - -inline bool operator!=(const AvailabilityInfo &lhs, - const AvailabilityInfo &rhs) { - return !(lhs == rhs); -} - -inline bool operator<(const AvailabilityInfo &lhs, - const AvailabilityInfo &rhs) { - return std::tie(lhs._introduced, lhs._obsoleted, lhs._unavailable) < - std::tie(rhs._introduced, rhs._obsoleted, rhs._unavailable); -} - -inline raw_ostream &operator<<(raw_ostream &os, const AvailabilityInfo &avail) { - avail.print(os); - return os; -} - -TAPI_NAMESPACE_INTERNAL_END - -#endif // TAPI_CORE_AVAILABILITY_INFO_H diff --git a/lib/TBDGen/tapi/CMakeLists.txt b/lib/TBDGen/tapi/CMakeLists.txt deleted file mode 100644 index f858521eeee..00000000000 --- a/lib/TBDGen/tapi/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -set(TAPI_SOURCES - tapi/Architecture.cpp - tapi/ArchitectureSet.cpp - tapi/ArchitectureSupport.cpp - tapi/AvailabilityInfo.cpp - tapi/ExtendedInterfaceFile.cpp - tapi/InterfaceFile.cpp - tapi/InterfaceFileBase.cpp - tapi/Platform.cpp - tapi/Registry.cpp - tapi/TapiError.cpp - tapi/TextStub_v3.cpp - tapi/XPI.cpp - tapi/XPISet.cpp - tapi/YAML.cpp - tapi/YAMLReaderWriter.cpp - PARENT_SCOPE) diff --git a/lib/TBDGen/tapi/CoreSymbol.h b/lib/TBDGen/tapi/CoreSymbol.h deleted file mode 100644 index 149c064654a..00000000000 --- a/lib/TBDGen/tapi/CoreSymbol.h +++ /dev/null @@ -1,86 +0,0 @@ -//===- tapi/Core/Symbol.h - TAPI Symbol -------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// API Symbol -/// -//===----------------------------------------------------------------------===// - -#ifndef TAPI_CORE_SYMBOL_H -#define TAPI_CORE_SYMBOL_H - -#include "ArchitectureSet.h" -#include "LLVM.h" -#include "Defines.h" -#include "Symbol.h" -#include "tapi.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/raw_ostream.h" - -TAPI_NAMESPACE_INTERNAL_BEGIN - -using SymbolFlags = tapi::v1::SymbolFlags; - -enum class SymbolKind : unsigned { - GlobalSymbol, - ObjectiveCClass, - ObjectiveCClassEHType, - ObjectiveCInstanceVariable, -}; - -class Symbol { -public: - constexpr Symbol(SymbolKind kind, StringRef name, - ArchitectureSet architectures, SymbolFlags flags) - : kind(kind), name(name), architectures(architectures), flags(flags) {} - - SymbolKind getKind() const { return kind; } - StringRef getName() const { return name; } - ArchitectureSet getArchitectures() const { return architectures; } - void setArchitectures(ArchitectureSet archs) { architectures |= archs; } - SymbolFlags getFlags() const { return flags; } - - bool isWeakDefined() const { - return (flags & SymbolFlags::WeakDefined) == SymbolFlags::WeakDefined; - } - - bool isWeakReferenced() const { - return (flags & SymbolFlags::WeakReferenced) == SymbolFlags::WeakReferenced; - } - - bool isThreadLocalValue() const { - return (flags & SymbolFlags::ThreadLocalValue) == - SymbolFlags::ThreadLocalValue; - } - - std::string getPrettyName(bool demangle) const; - std::string getAnnotatedName(bool demangle = false) const; - - void print(raw_ostream &os) const; - - /// Print APISymbol in human readable format. - void dump(raw_ostream &os) const; - void dump() const { dump(llvm::errs()); } - -private: - SymbolKind kind; - StringRef name; - ArchitectureSet architectures; - SymbolFlags flags; -}; - -inline raw_ostream &operator<<(raw_ostream &os, const Symbol &symbol) { - symbol.print(os); - return os; -} - -TAPI_NAMESPACE_INTERNAL_END - -#endif // TAPI_CORE_SYMBOL_H diff --git a/lib/TBDGen/tapi/Defines.h b/lib/TBDGen/tapi/Defines.h deleted file mode 100644 index 2a09e105aa3..00000000000 --- a/lib/TBDGen/tapi/Defines.h +++ /dev/null @@ -1,32 +0,0 @@ -//===-- tapi/Defines.h - TAPI C++ Library Defines ---------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// TAPI C++ library defines. -/// \since 1.0 -/// -//===----------------------------------------------------------------------===// -#ifndef TAPI_DEFINES_H -#define TAPI_DEFINES_H - -#define TAPI_INTERNAL tapi::internal -#define TAPI_NAMESPACE_INTERNAL_BEGIN namespace tapi { namespace internal { -#define TAPI_NAMESPACE_INTERNAL_END } } - -#define TAPI_NAMESPACE_V1_BEGIN namespace tapi { inline namespace v1 { -#define TAPI_NAMESPACE_V1_END } } - -#if defined(_WIN32) -#define TAPI_PUBLIC -#else -#define TAPI_PUBLIC __attribute__((visibility ("default"))) -#endif - -#endif // TAPI_DEFINES_H - diff --git a/lib/TBDGen/tapi/ExtendedInterfaceFile.cpp b/lib/TBDGen/tapi/ExtendedInterfaceFile.cpp deleted file mode 100644 index 4a26b77503f..00000000000 --- a/lib/TBDGen/tapi/ExtendedInterfaceFile.cpp +++ /dev/null @@ -1,311 +0,0 @@ -//===- ExtendedInterfaceFile.cpp - Extended Interface File ------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Implements the Extended Interface File -/// -//===----------------------------------------------------------------------===// - -#include "ExtendedInterfaceFile.h" -#include "llvm/Support/ErrorHandling.h" - -using namespace llvm; - -TAPI_NAMESPACE_INTERNAL_BEGIN - -static XPIKind convertSymbolKindToXPIKind(SymbolKind kind) { - switch (kind) { - case SymbolKind::GlobalSymbol: - return XPIKind::GlobalSymbol; - case SymbolKind::ObjectiveCClass: - return XPIKind::ObjectiveCClass; - case SymbolKind::ObjectiveCClassEHType: - return XPIKind::ObjectiveCClassEHType; - case SymbolKind::ObjectiveCInstanceVariable: - return XPIKind::ObjectiveCInstanceVariable; - } - llvm_unreachable("unexpected SymbolKind kind"); -} - -void ExtendedInterfaceFile::addSymbol(XPIKind kind, StringRef name, - ArchitectureSet archs, SymbolFlags flags, - XPIAccess access) { - switch (kind) { - default: - llvm_unreachable("invalid XPI kind"); - case XPIKind::GlobalSymbol: - _symbols->addGlobalSymbol(name, archs, flags, access); - break; - case XPIKind::ObjectiveCClass: - _symbols->addObjCClass(name, archs, access); - break; - case XPIKind::ObjectiveCClassEHType: - _symbols->addObjCClassEHType(name, archs, access); - break; - case XPIKind::ObjectiveCInstanceVariable: - _symbols->addObjCInstanceVariable(name, archs, access); - break; - } -} - -ObjCClass *ExtendedInterfaceFile::addObjCClass(StringRef name, - ArchitectureSet archs, - XPIAccess access, - ObjCClass *superClass) { - return _symbols->addObjCClass(name, archs, access, superClass); -} - -ObjCSelector *ExtendedInterfaceFile::addObjCSelector( - ObjCContainer *container, StringRef name, ArchitectureSet archs, - bool isInstanceMethod, bool isDynamic, XPIAccess access) { - return _symbols->addObjCSelector(container, name, archs, isInstanceMethod, - isDynamic, access); -} - -ObjCCategory *ExtendedInterfaceFile::addObjCCategory(ObjCClass *baseClass, - StringRef name, - ArchitectureSet archs, - XPIAccess access) { - return _symbols->addObjCCategory(baseClass, name, archs, access); -} - -ObjCProtocol *ExtendedInterfaceFile::addObjCProtocol(StringRef name, - ArchitectureSet archs, - XPIAccess access) { - return _symbols->addObjCProtocol(name, archs, access); -} - -void ExtendedInterfaceFile::addUndefinedSymbol(XPIKind kind, StringRef name, - ArchitectureSet archs, - SymbolFlags flags) { - switch (kind) { - default: - llvm_unreachable("invalid XPI kind"); - case XPIKind::GlobalSymbol: - _undefineds->addGlobalSymbol(name, archs, flags, XPIAccess::Exported); - break; - case XPIKind::ObjectiveCClass: - _undefineds->addObjCClass(name, archs, XPIAccess::Exported); - break; - case XPIKind::ObjectiveCClassEHType: - _undefineds->addObjCClassEHType(name, archs, XPIAccess::Exported); - break; - case XPIKind::ObjectiveCInstanceVariable: - _undefineds->addObjCInstanceVariable(name, archs, XPIAccess::Exported); - break; - } -} - -bool ExtendedInterfaceFile::contains(XPIKind kind, StringRef name, - XPI const **result) const { - if (auto *it = _symbols->findSymbol(kind, name)) { - if (result) - *result = it; - return true; - } - - return false; -} - -Expected> -ExtendedInterfaceFile::merge(const ExtendedInterfaceFile *otherInterface, - bool allowArchitectureMerges) const { - // Verify files can be merged. - if (getFileType() != otherInterface->getFileType()) { - return make_error("file types do not match", - inconvertibleErrorCode()); - } - - if (!allowArchitectureMerges) { - if ((getArchitectures() & otherInterface->getArchitectures()) != - Architecture::unknown) { - return make_error("architectures overlap", - inconvertibleErrorCode()); - } - } - - if (getPlatform() != otherInterface->getPlatform()) { - return make_error("platforms do not match", - inconvertibleErrorCode()); - } - - if (getInstallName() != otherInterface->getInstallName()) { - return make_error("install names do not match", - inconvertibleErrorCode()); - } - - if (getCurrentVersion() != otherInterface->getCurrentVersion()) { - return make_error("current versions do not match", - inconvertibleErrorCode()); - } - - if (getCompatibilityVersion() != otherInterface->getCompatibilityVersion()) { - return make_error("compatibility versions do not match", - inconvertibleErrorCode()); - } - - if (getSwiftABIVersion() != otherInterface->getSwiftABIVersion()) { - return make_error("swift ABI versions do not match", - inconvertibleErrorCode()); - } - - if (isTwoLevelNamespace() != otherInterface->isTwoLevelNamespace()) { - return make_error("two level namespace flags do not match", - inconvertibleErrorCode()); - } - - if (isApplicationExtensionSafe() != - otherInterface->isApplicationExtensionSafe()) { - return make_error( - "application extension safe flags do not match", - inconvertibleErrorCode()); - } - - if (isInstallAPI() != otherInterface->isInstallAPI()) { - return make_error("installapi flags do not match", - inconvertibleErrorCode()); - } - - if (getObjCConstraint() != otherInterface->getObjCConstraint()) { - return make_error("installapi flags do not match", - inconvertibleErrorCode()); - } - - if (getParentUmbrella() != otherInterface->getParentUmbrella()) { - return make_error("parent umbrellas do not match", - inconvertibleErrorCode()); - } - - std::unique_ptr interface(new ExtendedInterfaceFile()); - interface->setFileType(getFileType()); - interface->setPath(getPath()); - interface->setPlatform(getPlatform()); - interface->setInstallName(getInstallName()); - interface->setCurrentVersion(getCurrentVersion()); - interface->setCompatibilityVersion(getCompatibilityVersion()); - interface->setSwiftABIVersion(getSwiftABIVersion()); - interface->setTwoLevelNamespace(isTwoLevelNamespace()); - interface->setApplicationExtensionSafe(isApplicationExtensionSafe()); - interface->setInstallAPI(isInstallAPI()); - interface->setObjCConstraint(getObjCConstraint()); - interface->setParentUmbrella(getParentUmbrella()); - - interface->setArchitectures(getArchitectures() | - otherInterface->getArchitectures()); - - for (const auto &lib : allowableClients()) - interface->addAllowableClient(lib.getInstallName(), lib.getArchitectures()); - - for (const auto &lib : otherInterface->allowableClients()) - interface->addAllowableClient(lib.getInstallName(), lib.getArchitectures()); - - for (const auto &lib : reexportedLibraries()) - interface->addReexportedLibrary(lib.getInstallName(), - lib.getArchitectures()); - - for (const auto &lib : otherInterface->reexportedLibraries()) - interface->addReexportedLibrary(lib.getInstallName(), - lib.getArchitectures()); - - for (const auto &uuid : uuids()) - interface->addUUID(uuid.first, uuid.second); - - for (const auto &uuid : otherInterface->uuids()) - interface->addUUID(uuid.first, uuid.second); - - for (const auto *symbol : symbols()) - interface->addSymbol(symbol->getKind(), symbol->getName(), - symbol->getArchitectures(), symbol->getSymbolFlags(), - symbol->getAccess()); - - for (const auto *symbol : otherInterface->symbols()) - interface->addSymbol(symbol->getKind(), symbol->getName(), - symbol->getArchitectures(), symbol->getSymbolFlags(), - symbol->getAccess()); - - for (const auto *symbol : undefineds()) - interface->addUndefinedSymbol(symbol->getKind(), symbol->getName(), - symbol->getArchitectures(), - symbol->getSymbolFlags()); - - for (const auto *symbol : otherInterface->undefineds()) - interface->addUndefinedSymbol(symbol->getKind(), symbol->getName(), - symbol->getArchitectures(), - symbol->getSymbolFlags()); - - return std::move(interface); -} - -bool ExtendedInterfaceFile::removeSymbol(XPIKind kind, StringRef name) { - return _symbols->removeSymbol(kind, name); -} - -bool ExtendedInterfaceFile::removeSymbol(SymbolKind kind, StringRef name) { - return removeSymbol(convertSymbolKindToXPIKind(kind), name); -} - -void ExtendedInterfaceFile::printSymbolsForArch(Architecture arch) const { - std::vector exports; - for (const auto *symbol : this->exports()) { - if (!symbol->getArchitectures().has(arch)) - continue; - - switch (symbol->getKind()) { - case XPIKind::GlobalSymbol: - exports.emplace_back(symbol->getName()); - break; - case XPIKind::ObjectiveCClass: - if (getPlatform() == Platform::macOS && arch == Architecture::i386) { - exports.emplace_back(".objc_class_name_" + symbol->getName().str()); - } else { - exports.emplace_back("_OBJC_CLASS_$_" + symbol->getName().str()); - exports.emplace_back("_OBJC_METACLASS_$_" + symbol->getName().str()); - } - break; - case XPIKind::ObjectiveCClassEHType: - exports.emplace_back("_OBJC_EHTYPE_$_" + symbol->getName().str()); - break; - case XPIKind::ObjectiveCInstanceVariable: - exports.emplace_back("_OBJC_IVAR_$_" + symbol->getName().str()); - break; - default: - llvm_unreachable("Unexpected symbol kind for exported symbols"); - } - } - - sort(exports); - for (auto &symbol : exports) - outs() << symbol << "\n"; -} - -void ExtendedInterfaceFile::printSymbols(ArchitectureSet archs) const { - if (archs.empty()) - archs = getArchitectures(); - - if (getArchitectures().contains(archs)) { - bool firstItr = true; - for (auto arch : getArchitectures()) { - if (!archs.has(arch)) - continue; - - if (firstItr) - firstItr = false; - else - outs() << "\n"; - if (archs.count() > 1) - outs() << getPath() << " (for architecture " << arch << "):\n"; - printSymbolsForArch(arch); - } - } else { - outs() << "file: " << getPath() - << " does not contain architecture: " << archs << "\n"; - } -} - -TAPI_NAMESPACE_INTERNAL_END diff --git a/lib/TBDGen/tapi/ExtendedInterfaceFile.h b/lib/TBDGen/tapi/ExtendedInterfaceFile.h deleted file mode 100644 index a10e184b996..00000000000 --- a/lib/TBDGen/tapi/ExtendedInterfaceFile.h +++ /dev/null @@ -1,102 +0,0 @@ -//===- ExtendedIntefaceFile.h - TAPI Extended Interface File ----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// A generic and abstract interface representation for linkable objects. -/// This could be an MachO executable, bundle, dylib, or text-based stub -/// file. -/// -//===----------------------------------------------------------------------===// - -#ifndef TAPI_CORE_EXTENDED_INTERFACE_FILE_H -#define TAPI_CORE_EXTENDED_INTERFACE_FILE_H - -#include "Architecture.h" -#include "ArchitectureSet.h" -#include "File.h" -#include "InterfaceFile.h" -#include "InterfaceFileBase.h" -#include "STLExtras.h" -#include "XPI.h" -#include "XPISet.h" -#include "Defines.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/iterator.h" -#include "llvm/Support/Error.h" - -TAPI_NAMESPACE_INTERNAL_BEGIN - -class ExtendedInterfaceFile : public InterfaceFileBase { -public: - static bool classof(const File *file) { - return file->kind() == File::Kind::ExtendedInterfaceFile; - } - - ExtendedInterfaceFile() - : InterfaceFileBase(File::Kind::ExtendedInterfaceFile), - _symbols(new XPISet), _undefineds(new XPISet) {} - ExtendedInterfaceFile(std::unique_ptr &&symbols) - : InterfaceFileBase(File::Kind::ExtendedInterfaceFile), - _symbols(std::move(symbols)), _undefineds(new XPISet) {} - - void addSymbol(XPIKind kind, StringRef name, ArchitectureSet archs, - SymbolFlags flags = SymbolFlags::None, - XPIAccess access = XPIAccess::Exported); - - ObjCClass *addObjCClass(StringRef name, ArchitectureSet archs, - XPIAccess access = XPIAccess::Exported, - ObjCClass *superClass = nullptr); - ObjCSelector *addObjCSelector(ObjCContainer *container, StringRef name, - ArchitectureSet archs, - bool isInstanceMethod = false, - bool isDynamic = false, - XPIAccess access = XPIAccess::Exported); - ObjCCategory *addObjCCategory(ObjCClass *baseClass, StringRef name, - ArchitectureSet archs, - XPIAccess access = XPIAccess::Exported); - ObjCProtocol *addObjCProtocol(StringRef name, ArchitectureSet archs, - XPIAccess access = XPIAccess::Exported); - - void addUndefinedSymbol(XPIKind kind, StringRef name, ArchitectureSet archs, - SymbolFlags flags = SymbolFlags::None); - - using const_symbol_range = XPISet::const_symbol_range; - using const_export_range = XPISet::const_export_range; - using const_selector_range = XPISet::const_selector_range; - - const_symbol_range symbols() const { return _symbols->symbols(); } - const_export_range exports() const { return _symbols->exports(); } - const_selector_range selectors() const { return _symbols->selectors(); } - const_symbol_range undefineds() const { return _undefineds->symbols(); } - - const XPISet &getSymbolSet() const { return *_symbols; } - - bool contains(XPIKind kind, StringRef name, - XPI const **result = nullptr) const; - - llvm::Expected> - merge(const ExtendedInterfaceFile *otherInterface, - bool allowArchitectureMerges = false) const; - - bool removeSymbol(XPIKind kind, StringRef name); - bool removeSymbol(SymbolKind kind, StringRef name); - - void printSymbols(ArchitectureSet archs) const; - -private: - void printSymbolsForArch(Architecture arch) const; - -protected: - std::unique_ptr _symbols; - std::unique_ptr _undefineds; -}; - -TAPI_NAMESPACE_INTERNAL_END - -#endif // TAPI_CORE_EXTENDED_INTERFACE_FILE_H diff --git a/lib/TBDGen/tapi/File.h b/lib/TBDGen/tapi/File.h deleted file mode 100644 index 64e7250f3e2..00000000000 --- a/lib/TBDGen/tapi/File.h +++ /dev/null @@ -1,142 +0,0 @@ -//===- tapi/Core/File.h - TAPI File -----------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// TAPI File abstraction. -/// -//===----------------------------------------------------------------------===// - -#ifndef TAPI_CORE_FILE_H -#define TAPI_CORE_FILE_H - -#include "LLVM.h" -#include "Defines.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Path.h" -#include -#include - -TAPI_NAMESPACE_INTERNAL_BEGIN - -// clang-format off -enum FileType : unsigned { - /// Invalid file type. - Invalid = 0U, - - /// TAPI Configuration file. - TAPI_Configuration_V1 = 1U << 0, - - /// MachO Dynamic Library file. - MachO_DynamicLibrary = 1U << 1, - - /// MachO Dynamic Library Stub file. - MachO_DynamicLibrary_Stub = 1U << 2, - - /// MachO Bundle file. - MachO_Bundle = 1U << 3, - - /// Text-based stub file (.tbd) version 1.0 - TBD_V1 = 1U << 4, - - /// Text-based stub file (.tbd) version 2.0 - TBD_V2 = 1U << 5, - - /// Text-based stub file (.tbd) version 3.0 - TBD_V3 = 1U << 6, - - /// JSON Header List - JSON_V1 = 1U << 7, - - /// LD64 re-export file - ReexportFile = 1U << 8, - - /// Text-based API file (.api) version 1.0 - API_V1 = 1U << 9, - - /// Text-based SPI file (.spi) version 1.0 - SPI_V1 = 1U << 10, - - /// SDKDB file (.sdkdb) version 1.0 - SDKDB_V1 = 1U << 11, - - All = ~0U, -}; -// clang-format on - -inline FileType operator&(const FileType lhs, const FileType rhs) { - return static_cast(static_cast(lhs) & - static_cast(rhs)); -} - -inline FileType operator|(const FileType lhs, const FileType rhs) { - return static_cast(static_cast(lhs) | - static_cast(rhs)); -} - -/// Abstract TAPI file. -class File { -public: - enum class Kind : unsigned { - Configuration, - JSONFile, - InterfaceFileBase, - InterfaceFile, - ExtendedInterfaceFile, - SDKDBFile, - }; - - virtual ~File() = default; - - template void setPath(T &&path) { - _path = std::forward(path); - } - const std::string &getPath() const { return _path; } - - llvm::StringRef getFileName() const { - return llvm::sys::path::filename(_path); - } - - void setFileType(FileType type) { _fileType = type; } - FileType getFileType() const { return _fileType; } - - void setMemoryBuffer(std::unique_ptr memBuffer) { - _buffer = std::move(memBuffer); - } - - MemoryBufferRef getMemBufferRef() const { return _buffer->getMemBufferRef(); } - - void addDocument(std::shared_ptr &&document) { - _documents.emplace_back(std::move(document)); - } - - Kind kind() const { return _kind; } - - std::vector> _documents; - -protected: - File(Kind kind) : _kind(kind) {} - void setKind(Kind kind) { _kind = kind; } - - // Manually add the default implementations back in. The implicit ones have - // been removed, because we defined a virtual destructor. - File(File &&) = default; - File &operator=(File &&) = default; - -private: - Kind _kind; - std::string _path; - FileType _fileType = FileType::Invalid; - // The backing store this file was derived from. We use this as context for - // the strings that we reference. - std::unique_ptr _buffer; -}; - -TAPI_NAMESPACE_INTERNAL_END - -#endif // TAPI_CORE_FILE_H diff --git a/lib/TBDGen/tapi/InterfaceFile.cpp b/lib/TBDGen/tapi/InterfaceFile.cpp deleted file mode 100644 index ed0c7b1e8d9..00000000000 --- a/lib/TBDGen/tapi/InterfaceFile.cpp +++ /dev/null @@ -1,429 +0,0 @@ -//===- lib/Core/InterfaceFile.cpp - Interface File --------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Implements the Interface File -/// -//===----------------------------------------------------------------------===// - -#include "InterfaceFile.h" -#include "ExtendedInterfaceFile.h" -#include "TapiError.h" -#include "XPI.h" -#include "llvm/Support/ErrorHandling.h" - -using namespace llvm; - -TAPI_NAMESPACE_INTERNAL_BEGIN - -static SymbolKind convertXPIKindToSymbolKind(XPIKind kind) { - switch (kind) { - default: - llvm_unreachable("unexpected XPI kind"); - case XPIKind::GlobalSymbol: - return SymbolKind::GlobalSymbol; - case XPIKind::ObjectiveCClass: - return SymbolKind::ObjectiveCClass; - case XPIKind::ObjectiveCClassEHType: - return SymbolKind::ObjectiveCClassEHType; - case XPIKind::ObjectiveCInstanceVariable: - return SymbolKind::ObjectiveCInstanceVariable; - } -} - -InterfaceFile::InterfaceFile(ExtendedInterfaceFile &&other) - : InterfaceFileBase(std::forward(other)) { - setKind(File::Kind::InterfaceFile); - for (const auto *symbol : other.exports()) - addSymbolImpl(convertXPIKindToSymbolKind(symbol->getKind()), - symbol->getName(), symbol->getArchitectures(), - symbol->getSymbolFlags()); - - for (const auto *symbol : other.undefineds()) - addUndefinedSymbolImpl(convertXPIKindToSymbolKind(symbol->getKind()), - symbol->getName(), symbol->getArchitectures(), - symbol->getSymbolFlags()); -} - -void InterfaceFile::addSymbolImpl(SymbolKind kind, StringRef name, - ArchitectureSet archs, SymbolFlags flags, - bool copyStrings) { - if (copyStrings) - name = copyString(name); - _symbols.emplace_back(new (allocator) Symbol{kind, name, archs, flags}); -} - -void InterfaceFile::addSymbol(SymbolKind kind, StringRef name, - ArchitectureSet archs, SymbolFlags flags, - bool copyStrings) { - auto it = find_if(_symbols, [kind, name](const Symbol *symbol) { - return (symbol->getKind() == kind) && (symbol->getName() == name); - }); - - if (it != _symbols.end()) { - (*it)->setArchitectures(archs); - return; - } - - addSymbolImpl(kind, name, archs, flags, copyStrings); -} - -void InterfaceFile::addUndefinedSymbolImpl(SymbolKind kind, StringRef name, - ArchitectureSet archs, - SymbolFlags flags, - bool copyStrings) { - if (copyStrings) - name = copyString(name); - _undefineds.emplace_back(new (allocator) Symbol{kind, name, archs, flags}); -} - -void InterfaceFile::addUndefinedSymbol(SymbolKind kind, StringRef name, - ArchitectureSet archs, SymbolFlags flags, - bool copyStrings) { - auto it = find_if(_undefineds, [kind, name](const Symbol *symbol) { - return (symbol->getKind() == kind) && (symbol->getName() == name); - }); - - if (it != _undefineds.end()) { - (*it)->setArchitectures(archs); - return; - } - - addUndefinedSymbolImpl(kind, name, archs, flags, copyStrings); -} - -bool InterfaceFile::contains(SymbolKind kind, StringRef name, - Symbol const **result) const { - auto it = find_if(_symbols, [kind, name](const Symbol *symbol) { - return (symbol->getKind() == kind) && (symbol->getName() == name); - }); - - if (it != _symbols.end()) { - if (result) - *result = *it; - return true; - } - - return false; -} - -Expected> -InterfaceFile::extract(Architecture arch) const { - if (!_architectures.has(arch)) { - return make_error("file doesn't have architecture '" + - getArchName(arch) + "'", - inconvertibleErrorCode()); - } - - std::unique_ptr interface(new InterfaceFile()); - interface->setFileType(getFileType()); - interface->setPath(getPath()); - interface->setPlatform(getPlatform()); - interface->setArch(arch); - interface->setInstallName(getInstallName()); - interface->setCurrentVersion(getCurrentVersion()); - interface->setCompatibilityVersion(getCompatibilityVersion()); - interface->setSwiftABIVersion(getSwiftABIVersion()); - interface->setTwoLevelNamespace(isTwoLevelNamespace()); - interface->setApplicationExtensionSafe(isApplicationExtensionSafe()); - interface->setInstallAPI(isInstallAPI()); - interface->setObjCConstraint(getObjCConstraint()); - interface->setParentUmbrella(getParentUmbrella()); - - for (const auto &lib : allowableClients()) - if (lib.hasArchitecture(arch)) - interface->addAllowableClient(lib.getInstallName(), arch); - - for (const auto &lib : reexportedLibraries()) - if (lib.hasArchitecture(arch)) - interface->addReexportedLibrary(lib.getInstallName(), arch); - - for (const auto &uuid : uuids()) - if (uuid.first == arch) - interface->addUUID(arch, uuid.second); - - for (const auto *symbol : symbols()) - if (symbol->getArchitectures().has(arch)) - interface->addSymbol(symbol->getKind(), symbol->getName(), arch, - symbol->getFlags()); - - for (const auto *symbol : undefineds()) - if (symbol->getArchitectures().has(arch)) - interface->addUndefinedSymbol(symbol->getKind(), symbol->getName(), arch, - symbol->getFlags()); - - return std::move(interface); -} - -Expected> -InterfaceFile::remove(Architecture arch) const { - if (_architectures == arch) - return make_error("cannot remove last architecture slice '" + - getArchName(arch) + "'", - inconvertibleErrorCode()); - - if (!_architectures.has(arch)) - return make_error(TapiErrorCode::NoSuchArchitecture); - - std::unique_ptr interface(new InterfaceFile()); - interface->setFileType(getFileType()); - interface->setPath(getPath()); - interface->setPlatform(getPlatform()); - ArchitectureSet archs = getArchitectures(); - archs.clear(arch); - interface->setArchitectures(archs); - interface->setInstallName(getInstallName()); - interface->setCurrentVersion(getCurrentVersion()); - interface->setCompatibilityVersion(getCompatibilityVersion()); - interface->setSwiftABIVersion(getSwiftABIVersion()); - interface->setTwoLevelNamespace(isTwoLevelNamespace()); - interface->setApplicationExtensionSafe(isApplicationExtensionSafe()); - interface->setInstallAPI(isInstallAPI()); - interface->setObjCConstraint(getObjCConstraint()); - interface->setParentUmbrella(getParentUmbrella()); - - for (const auto &lib : allowableClients()) { - auto archs = lib.getArchitectures(); - archs.clear(arch); - if (archs.empty()) - continue; - interface->addAllowableClient(lib.getInstallName(), archs); - } - - for (const auto &lib : reexportedLibraries()) { - auto archs = lib.getArchitectures(); - archs.clear(arch); - if (archs.empty()) - continue; - interface->addReexportedLibrary(lib.getInstallName(), archs); - } - - for (const auto &uuid : uuids()) - if (uuid.first != arch) - interface->addUUID(uuid.first, uuid.second); - - for (const auto *symbol : symbols()) { - auto archs = symbol->getArchitectures(); - archs.clear(arch); - if (archs.empty()) - continue; - interface->addSymbol(symbol->getKind(), symbol->getName(), archs, - symbol->getFlags()); - } - - for (const auto *symbol : undefineds()) { - auto archs = symbol->getArchitectures(); - archs.clear(arch); - if (archs.empty()) - continue; - interface->addUndefinedSymbol(symbol->getKind(), symbol->getName(), archs, - symbol->getFlags()); - } - - return std::move(interface); -} - -Expected> -InterfaceFile::merge(const InterfaceFile *otherInterface, - bool allowArchitectureMerges) const { - // Verify files can be merged. - if (getFileType() != otherInterface->getFileType()) { - return make_error("file types do not match", - inconvertibleErrorCode()); - } - - if (!allowArchitectureMerges) { - if ((getArchitectures() & otherInterface->getArchitectures()) != - Architecture::unknown) { - return make_error("architectures overlap", - inconvertibleErrorCode()); - } - } - - if (getPlatform() != otherInterface->getPlatform()) { - return make_error("platforms do not match", - inconvertibleErrorCode()); - } - - if (getInstallName() != otherInterface->getInstallName()) { - return make_error("install names do not match", - inconvertibleErrorCode()); - } - - if (getCurrentVersion() != otherInterface->getCurrentVersion()) { - return make_error("current versions do not match", - inconvertibleErrorCode()); - } - - if (getCompatibilityVersion() != otherInterface->getCompatibilityVersion()) { - return make_error("compatibility versions do not match", - inconvertibleErrorCode()); - } - - if ((getSwiftABIVersion() != 0) && - (otherInterface->getSwiftABIVersion() != 0) && - (getSwiftABIVersion() != otherInterface->getSwiftABIVersion())) { - return make_error("swift ABI versions do not match", - inconvertibleErrorCode()); - } - - if (isTwoLevelNamespace() != otherInterface->isTwoLevelNamespace()) { - return make_error("two level namespace flags do not match", - inconvertibleErrorCode()); - } - - if (isApplicationExtensionSafe() != - otherInterface->isApplicationExtensionSafe()) { - return make_error( - "application extension safe flags do not match", - inconvertibleErrorCode()); - } - - if (isInstallAPI() != otherInterface->isInstallAPI()) { - return make_error("installapi flags do not match", - inconvertibleErrorCode()); - } - - if ((getObjCConstraint() != ObjCConstraint::None) && - (otherInterface->getObjCConstraint() != ObjCConstraint::None) && - (getObjCConstraint() != otherInterface->getObjCConstraint())) { - return make_error("installapi flags do not match", - inconvertibleErrorCode()); - } - - if (getParentUmbrella() != otherInterface->getParentUmbrella()) { - return make_error("parent umbrellas do not match", - inconvertibleErrorCode()); - } - - std::unique_ptr interface(new InterfaceFile()); - interface->setFileType(getFileType()); - interface->setPath(getPath()); - interface->setPlatform(getPlatform()); - interface->setInstallName(getInstallName()); - interface->setCurrentVersion(getCurrentVersion()); - interface->setCompatibilityVersion(getCompatibilityVersion()); - - if (getSwiftABIVersion() == 0) - interface->setSwiftABIVersion(otherInterface->getSwiftABIVersion()); - else - interface->setSwiftABIVersion(getSwiftABIVersion()); - - interface->setTwoLevelNamespace(isTwoLevelNamespace()); - interface->setApplicationExtensionSafe(isApplicationExtensionSafe()); - interface->setInstallAPI(isInstallAPI()); - - if (getObjCConstraint() == ObjCConstraint::None) - interface->setObjCConstraint(otherInterface->getObjCConstraint()); - else - interface->setObjCConstraint(getObjCConstraint()); - - interface->setParentUmbrella(getParentUmbrella()); - - interface->setArchitectures(getArchitectures() | - otherInterface->getArchitectures()); - - for (const auto &lib : allowableClients()) - interface->addAllowableClient(lib.getInstallName(), lib.getArchitectures()); - - for (const auto &lib : otherInterface->allowableClients()) - interface->addAllowableClient(lib.getInstallName(), lib.getArchitectures()); - - for (const auto &lib : reexportedLibraries()) - interface->addReexportedLibrary(lib.getInstallName(), - lib.getArchitectures()); - - for (const auto &lib : otherInterface->reexportedLibraries()) - interface->addReexportedLibrary(lib.getInstallName(), - lib.getArchitectures()); - - for (const auto &uuid : uuids()) - interface->addUUID(uuid.first, uuid.second); - - for (const auto &uuid : otherInterface->uuids()) - interface->addUUID(uuid.first, uuid.second); - - for (const auto *symbol : symbols()) - interface->addSymbol(symbol->getKind(), symbol->getName(), - symbol->getArchitectures(), symbol->getFlags()); - - for (const auto *symbol : otherInterface->symbols()) - interface->addSymbol(symbol->getKind(), symbol->getName(), - symbol->getArchitectures(), symbol->getFlags()); - - for (const auto *symbol : undefineds()) - interface->addUndefinedSymbol(symbol->getKind(), symbol->getName(), - symbol->getArchitectures(), - symbol->getFlags()); - - for (const auto *symbol : otherInterface->undefineds()) - interface->addUndefinedSymbol(symbol->getKind(), symbol->getName(), - symbol->getArchitectures(), - symbol->getFlags()); - - return std::move(interface); -} - -void InterfaceFile::printSymbolsForArch(Architecture arch) const { - std::vector exports; - for (const auto *symbol : this->symbols()) { - if (!symbol->getArchitectures().has(arch)) - continue; - - switch (symbol->getKind()) { - case SymbolKind::GlobalSymbol: - exports.emplace_back(symbol->getName()); - break; - case SymbolKind::ObjectiveCClass: - if (getPlatform() == Platform::macOS && arch == Architecture::i386) { - exports.emplace_back(".objc_class_name_" + symbol->getName().str()); - } else { - exports.emplace_back("_OBJC_CLASS_$_" + symbol->getName().str()); - exports.emplace_back("_OBJC_METACLASS_$_" + symbol->getName().str()); - } - break; - case SymbolKind::ObjectiveCClassEHType: - exports.emplace_back("_OBJC_EHTYPE_$_" + symbol->getName().str()); - break; - case SymbolKind::ObjectiveCInstanceVariable: - exports.emplace_back("_OBJC_IVAR_$_" + symbol->getName().str()); - break; - } - } - - sort(exports); - for (const auto &symbol : exports) - outs() << symbol << "\n"; -} - -void InterfaceFile::printSymbols(ArchitectureSet archs) const { - if (archs.empty()) - archs = getArchitectures(); - - if (getArchitectures().contains(archs)) { - bool firstItr = true; - for (auto arch : getArchitectures()) { - if (!archs.has(arch)) - continue; - - if (firstItr) - firstItr = false; - else - outs() << "\n"; - if (archs.count() > 1) - outs() << getPath() << " (for architecture " << arch << "):\n"; - printSymbolsForArch(arch); - } - } else { - outs() << "file: " << getPath() - << " does not contain architecture: " << archs << "\n"; - } -} - -TAPI_NAMESPACE_INTERNAL_END diff --git a/lib/TBDGen/tapi/InterfaceFile.h b/lib/TBDGen/tapi/InterfaceFile.h deleted file mode 100644 index a191a297b7b..00000000000 --- a/lib/TBDGen/tapi/InterfaceFile.h +++ /dev/null @@ -1,106 +0,0 @@ -//===- tapi/Core/IntefaceFile.h - TAPI Interface File --------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// A generic and abstract interface representation for linkable objects. -/// This could be an MachO executable, bundle, dylib, or text-based stub -/// file. -/// -//===----------------------------------------------------------------------===// - -#ifndef TAPI_CORE_INTERFACE_FILE_H -#define TAPI_CORE_INTERFACE_FILE_H - -#include "Architecture.h" -#include "ArchitectureSet.h" -#include "File.h" -#include "InterfaceFileBase.h" -#include "STLExtras.h" -#include "CoreSymbol.h" -#include "Defines.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/iterator.h" -#include "llvm/Support/Allocator.h" -#include "llvm/Support/Error.h" - -namespace llvm { -namespace yaml { -template struct MappingTraits; -} -} // namespace llvm - -TAPI_NAMESPACE_INTERNAL_BEGIN - -class ExtendedInterfaceFile; - -class InterfaceFile : public InterfaceFileBase { -public: - static bool classof(const File *file) { - return file->kind() == File::Kind::InterfaceFile; - } - - InterfaceFile() : InterfaceFileBase(File::Kind::InterfaceFile) {} - InterfaceFile(ExtendedInterfaceFile &&); - - void addSymbol(SymbolKind kind, StringRef name, ArchitectureSet archs, - SymbolFlags flags = SymbolFlags::None, - bool copyStrings = true); - void addUndefinedSymbol(SymbolKind kind, StringRef name, - ArchitectureSet archs, - SymbolFlags flags = SymbolFlags::None, - bool copyStrings = true); - - using SymbolSeq = std::vector; - using const_symbol_iterator = SymbolSeq::const_iterator; - using const_symbol_range = llvm::iterator_range; - - const_symbol_range symbols() const { return _symbols; } - const_symbol_range exports() const { return _symbols; } - const_symbol_range undefineds() const { return _undefineds; } - - bool contains(SymbolKind kind, StringRef name, - Symbol const **result = nullptr) const; - - llvm::Expected> - extract(Architecture arch) const; - llvm::Expected> - remove(Architecture arch) const; - llvm::Expected> - merge(const InterfaceFile *otherInterface, - bool allowArchitectureMerges = false) const; - void printSymbols(ArchitectureSet archs) const; - -private: - void addSymbolImpl(SymbolKind kind, StringRef name, ArchitectureSet archs, - SymbolFlags flags, bool copyStrings = true); - void addUndefinedSymbolImpl(SymbolKind kind, StringRef name, - ArchitectureSet archs, SymbolFlags flags, - bool copyStrings = true); - void printSymbolsForArch(Architecture arch) const; - -protected: - StringRef copyString(StringRef string) { - if (string.empty()) - return {}; - - void *ptr = allocator.Allocate(string.size(), 1); - memcpy(ptr, string.data(), string.size()); - return {reinterpret_cast(ptr), string.size()}; - } - - llvm::BumpPtrAllocator allocator; - SymbolSeq _symbols; - SymbolSeq _undefineds; - - friend struct llvm::yaml::MappingTraits; -}; - -TAPI_NAMESPACE_INTERNAL_END - -#endif // TAPI_CORE_INTERFACE_FILE_H diff --git a/lib/TBDGen/tapi/InterfaceFileBase.cpp b/lib/TBDGen/tapi/InterfaceFileBase.cpp deleted file mode 100644 index 31b4ac70570..00000000000 --- a/lib/TBDGen/tapi/InterfaceFileBase.cpp +++ /dev/null @@ -1,148 +0,0 @@ -//===- lib/Core/InterfaceFileBase.cpp - Interface File Base -----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Implements the Interface File Base -/// -//===----------------------------------------------------------------------===// - -#include "InterfaceFileBase.h" -#include "STLExtras.h" -#include "clang/Basic/Diagnostic.h" -#include -#include - -using namespace llvm; - -TAPI_NAMESPACE_INTERNAL_BEGIN - -raw_ostream &operator<<(raw_ostream &os, const InterfaceFileRef &ref) { - os << ref.getInstallName() << ref.getArchitectures(); - return os; -} - -const DiagnosticBuilder &operator<<(const DiagnosticBuilder &db, - const InterfaceFileRef &ref) { - auto str = ref.getInstallName().str() + " [ " + - std::string(ref.getArchitectures()) + " ]"; - db.AddString(str); - return db; -} - -namespace { -template -typename C::iterator addEntry(C &container, StringRef installName) { - auto it = lower_bound(container, installName, - [](const InterfaceFileRef &lhs, const StringRef &rhs) { - return lhs.getInstallName() < rhs; - }); - if ((it != std::end(container)) && !(installName < it->getInstallName())) - return it; - - return container.emplace(it, installName); -} -} // end anonymous namespace. - -void InterfaceFileBase::addAllowableClient(StringRef installName, - ArchitectureSet archs) { - auto client = addEntry(_allowableClients, installName); - client->setArchitectures(archs); -} - -void InterfaceFileBase::addReexportedLibrary(StringRef installName, - ArchitectureSet archs) { - auto lib = addEntry(_reexportedLibraries, installName); - lib->setArchitectures(archs); -} - -bool InterfaceFileBase::removeReexportedLibrary(StringRef installName) { - auto it = lower_bound(_reexportedLibraries, installName, - [](const InterfaceFileRef &lhs, const StringRef &rhs) { - return lhs.getInstallName() < rhs; - }); - - if ((it == _reexportedLibraries.end()) || - (installName < it->getInstallName())) - return false; - - _reexportedLibraries.erase(it); - return true; -} - -void InterfaceFileBase::addUUID(Architecture arch, StringRef uuid) { - auto it = lower_bound(_uuids, arch, - [](const std::pair &lhs, - Architecture rhs) { return lhs.first < rhs; }); - - if ((it != _uuids.end()) && !(arch < it->first)) { - it->second = uuid; - return; - } - - _uuids.emplace(it, arch, uuid); - return; -} - -void InterfaceFileBase::addUUID(uint8_t uuid[16], Architecture arch) { - std::stringstream stream; - for (unsigned i = 0; i < 16; ++i) { - if (i == 4 || i == 6 || i == 8 || i == 10) - stream << '-'; - stream << std::setfill('0') << std::setw(2) << std::uppercase << std::hex - << static_cast(uuid[i]); - } - addUUID(arch, stream.str()); -} - -bool InterfaceFileBase::convertTo(FileType fileType) { - switch (fileType) { - default: - return false; - case FileType::TBD_V1: - case FileType::TBD_V2: - case FileType::TBD_V3: - case FileType::API_V1: - case FileType::SPI_V1: - break; - } - - if ((fileType == FileType::TBD_V1) && - (!isTwoLevelNamespace() || !isApplicationExtensionSafe())) - return false; - - setFileType(fileType); - - return true; -} - -void InterfaceFileBase::inlineFramework( - std::shared_ptr framework) { - auto addFramework = [&](std::shared_ptr &&framework) { - auto it = - lower_bound(_documents, framework->getInstallName(), - [](std::shared_ptr &lhs, const std::string &rhs) { - return std::static_pointer_cast(lhs) - ->getInstallName() < rhs; - }); - - if ((it != _documents.end()) && - !(framework->getInstallName() < - std::static_pointer_cast(*it)->getInstallName())) - return; - - _documents.emplace(it, std::move(framework)); - }; - for (auto &doc : framework->_documents) - addFramework(std::static_pointer_cast(doc)); - - framework->_documents.clear(); - addFramework(std::move(framework)); -} - -TAPI_NAMESPACE_INTERNAL_END diff --git a/lib/TBDGen/tapi/InterfaceFileBase.h b/lib/TBDGen/tapi/InterfaceFileBase.h deleted file mode 100644 index c7c97b6660b..00000000000 --- a/lib/TBDGen/tapi/InterfaceFileBase.h +++ /dev/null @@ -1,174 +0,0 @@ -//===- tapi/Core/IntefaceFileBase.h - TAPI Interface File Base --*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Abstract base class for interface files. -/// -//===----------------------------------------------------------------------===// - -#ifndef TAPI_CORE_INTERFACE_FILE_BASE_H -#define TAPI_CORE_INTERFACE_FILE_BASE_H - -#include "Architecture.h" -#include "ArchitectureSet.h" -#include "ArchitectureSupport.h" -#include "File.h" -#include "Platform.h" -#include "STLExtras.h" -#include "Defines.h" -#include "llvm/ADT/StringRef.h" - -namespace llvm { -namespace yaml { -template struct MappingTraits; -} -} // namespace llvm - -TAPI_NAMESPACE_INTERNAL_BEGIN - -class InterfaceFileRef { -public: - InterfaceFileRef() = default; - - InterfaceFileRef(StringRef installName) : _installName(installName) {} - - InterfaceFileRef(StringRef installName, ArchitectureSet archs) - : _installName(installName), _architectures(archs) {} - - StringRef getInstallName() const { return _installName; }; - void setArchitectures(ArchitectureSet archs) { _architectures |= archs; } - ArchitectureSet getArchitectures() const { return _architectures; } - bool hasArchitecture(Architecture arch) const { - return _architectures.has(arch); - } - void clearArchitectures() { _architectures = Architecture::unknown; } - - bool operator==(const InterfaceFileRef &o) const { - return std::tie(_installName, _architectures) == - std::tie(o._installName, o._architectures); - } - - bool operator!=(const InterfaceFileRef &o) const { - return std::tie(_installName, _architectures) != - std::tie(o._installName, o._architectures); - } - - bool operator<(const InterfaceFileRef &o) const { - return std::tie(_installName, _architectures) < - std::tie(o._installName, o._architectures); - } - -private: - std::string _installName; - ArchitectureSet _architectures; - - template friend struct llvm::yaml::MappingTraits; -}; - -raw_ostream &operator<<(raw_ostream &os, const InterfaceFileRef &ref); - -const DiagnosticBuilder &operator<<(const DiagnosticBuilder &db, - const InterfaceFileRef &ref); - -class InterfaceFileBase : public File { -public: - static bool classof(const File *file) { - return (file->kind() == File::Kind::InterfaceFileBase) || - (file->kind() == File::Kind::InterfaceFile) || - (file->kind() == File::Kind::ExtendedInterfaceFile); - } - - void setPlatform(Platform platform) { - _platform = platform; - } - Platform getPlatform() const { return _platform; } - - void setArchitectures(ArchitectureSet archs) { _architectures |= archs; } - void setArch(Architecture arch) { _architectures.set(arch); } - ArchitectureSet getArchitectures() const { return _architectures; } - void clearArchitectures() { _architectures = Architecture::unknown; } - - void setInstallName(StringRef installName) { _installName = installName; } - StringRef getInstallName() const { return _installName; } - - void setCurrentVersion(PackedVersion version) { _currentVersion = version; } - PackedVersion getCurrentVersion() const { return _currentVersion; } - - void setCompatibilityVersion(PackedVersion version) { - _compatibilityVersion = version; - } - PackedVersion getCompatibilityVersion() const { - return _compatibilityVersion; - } - - void setSwiftABIVersion(uint8_t version) { _swiftABIVersion = version; } - uint8_t getSwiftABIVersion() const { return _swiftABIVersion; } - - void setTwoLevelNamespace(bool v = true) { _isTwoLevelNamespace = v; } - bool isTwoLevelNamespace() const { return _isTwoLevelNamespace; } - - void setApplicationExtensionSafe(bool v = true) { _isAppExtensionSafe = v; } - bool isApplicationExtensionSafe() const { return _isAppExtensionSafe; } - - void setObjCConstraint(ObjCConstraint constraint) { - _objcConstraint = constraint; - } - ObjCConstraint getObjCConstraint() const { return _objcConstraint; } - - void setInstallAPI(bool v = true) { _isInstallAPI = v; } - bool isInstallAPI() const { return _isInstallAPI; } - - void setParentUmbrella(StringRef parent) { _parentUmbrella = parent; } - StringRef getParentUmbrella() const { return _parentUmbrella; } - - void addAllowableClient(StringRef installName, ArchitectureSet archs); - const std::vector &allowableClients() const { - return _allowableClients; - } - - void addReexportedLibrary(StringRef installName, ArchitectureSet archs); - bool removeReexportedLibrary(StringRef installName); - const std::vector &reexportedLibraries() const { - return _reexportedLibraries; - } - - void addUUID(Architecture arch, StringRef uuid); - void addUUID(uint8_t uuid[16], Architecture arch); - const std::vector> &uuids() const { - return _uuids; - } - void clearUUIDs() { _uuids.clear(); } - - bool convertTo(FileType fileType); - - void inlineFramework(std::shared_ptr framework); - -protected: - InterfaceFileBase(File::Kind kind) : File(kind) {} - InterfaceFileBase(InterfaceFileBase &&) = default; - - Platform _platform = Platform::unknown; - ArchitectureSet _architectures; - std::string _installName; - PackedVersion _currentVersion; - PackedVersion _compatibilityVersion; - uint8_t _swiftABIVersion = 0; - bool _isTwoLevelNamespace = false; - bool _isAppExtensionSafe = false; - bool _isInstallAPI = false; - ObjCConstraint _objcConstraint = ObjCConstraint::None; - std::string _parentUmbrella; - std::vector _allowableClients; - std::vector _reexportedLibraries; - std::vector> _uuids; -}; - -TAPI_NAMESPACE_INTERNAL_END - -#endif // TAPI_CORE_INTERFACE_FILE_BASE_H diff --git a/lib/TBDGen/tapi/LLVM.h b/lib/TBDGen/tapi/LLVM.h deleted file mode 100644 index 3901f53900c..00000000000 --- a/lib/TBDGen/tapi/LLVM.h +++ /dev/null @@ -1,76 +0,0 @@ -//===- tapi/Core/LLVM.h - Import various common LLVM datatypes --*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file forward declares and imports various common LLVM and clang -// datatypes that tapi wants to use unqualified. -// -//===----------------------------------------------------------------------===// - -#ifndef TAPI_CORE_LLVM_H -#define TAPI_CORE_LLVM_H - -#include "llvm/Support/Casting.h" - -namespace llvm { - -// ADT's. -template class ErrorOr; -template class IntrusiveRefCntPtr; -template class SmallPtrSet; -template class SmallString; -template class SmallVector; -template class SmallVectorImpl; -template class ArrayRef; -class raw_ostream; -class StringRef; -class Twine; -class MemoryBuffer; -class MemoryBufferRef; - -} // end namespace llvm. - -namespace clang { - -class DirectoryEntry; -class FileEntry; -class DiagnosticBuilder; - -} // end namespace clang. - -namespace tapi { - -// Casting operators. -using llvm::isa; -using llvm::cast; -using llvm::dyn_cast; -using llvm::dyn_cast_or_null; -using llvm::cast_or_null; - -// ADT's. -using llvm::ArrayRef; -using llvm::ErrorOr; -using llvm::IntrusiveRefCntPtr; -using llvm::SmallPtrSet; -using llvm::SmallString; -using llvm::SmallVector; -using llvm::SmallVectorImpl; -using llvm::raw_ostream; -using llvm::StringRef; -using llvm::Twine; -using llvm::MemoryBuffer; -using llvm::MemoryBufferRef; - -// FileManager -using clang::DirectoryEntry; -using clang::FileEntry; - -using clang::DiagnosticBuilder; -} // end namespace tapi. - -#endif // TAPI_CORE_LLVM_H diff --git a/lib/TBDGen/tapi/LinkerInterfaceFile.h b/lib/TBDGen/tapi/LinkerInterfaceFile.h deleted file mode 100644 index adf26ab88f3..00000000000 --- a/lib/TBDGen/tapi/LinkerInterfaceFile.h +++ /dev/null @@ -1,482 +0,0 @@ -//===-- tapi/LinkerInterfaceFile.h - TAPI File Interface --------*- C++ -*-===*\ -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// API for reading TAPI files. -/// \since 1.0 -/// -//===----------------------------------------------------------------------===// -#ifndef TAPI_LINKER_INTERFACE_FILE_H -#define TAPI_LINKER_INTERFACE_FILE_H - -#include -#include -#include "Defines.h" -#include - -/// -/// \defgroup TAPI_LINKER_INTERFACE_FILE TAPI File APIs -/// \ingroup TAPI_CPP_API -/// -/// @{ -/// - -using cpu_type_t = int; -using cpu_subtype_t = int; - -TAPI_NAMESPACE_V1_BEGIN - -class PackedVersion32; -class Symbol; - -/// -/// Defines a list of supported platforms. -/// \since 1.0 -/// -enum class Platform : unsigned { - /// Unknown platform - /// \since 1.0 - Unknown = 0, - - /// Mac OS X - /// \since 1.0 - OSX = 1, - - /// iOS - /// \since 1.0 - iOS = 2, - - /// watchOS - /// \since 1.0 - watchOS = 3, - - /// tvOS - /// \since 1.0 - tvOS = 4, - - /// bridgeOS - /// \since 1.2 - bridgeOS = 5, -}; - -/// -/// Defines a list of Objective-C constraints. -/// \since 1.0 -/// -enum class ObjCConstraint : unsigned { - /// No constraint. - /// \since 1.0 - None = 0, - - /// Retain/Release. - /// \since 1.0 - Retain_Release = 1, - - /// Retain/Release for Simulator. - /// \since 1.0 - Retain_Release_For_Simulator = 2, - - /// Retain/Release or Garbage Collection. - /// \since 1.0 - Retain_Release_Or_GC = 3, - - /// Garbage Collection. - /// \since 1.0 - GC = 4, -}; - -/// -/// Defines a list of supported file types. -/// \since 1.0 -/// -enum class FileType : unsigned { - /// Unsupported file type. - /// \since 1.0 - Unsupported = 0, - - /// Text-based Dynamic Library Stub File (.tbd) version 1.0 - /// \since 1.0 - TBD_V1 = 1, - - /// Text-based stub file (.tbd) version 2.0 - /// \since 1.0 - TBD_V2 = 2, - - /// Text-based stub file (.tbd) version 3.0 - /// \since 1.3 - TBD_V3 = 3, -}; - -/// -/// Defines the cpu subtype matching mode. -/// \since 1.0 -/// -enum class CpuSubTypeMatching : unsigned { - /// Fall-back to an ABI compatible slice if an exact match cannot be - /// found. - /// \since 1.0 - ABI_Compatible = 0, - - /// Only accept a slice if the sub type matches. - /// \since 1.0 - Exact = 1, -}; - -/// -/// Defines flags that control the parsing of text-based stub files. -/// \since 1.1 -/// -enum ParsingFlags : unsigned { - /// Default flags. - /// \since 1.1 - None = 0, - - /// Only accept a slice if the sub type matches. ABI fall-back mode is - /// the default. - /// \since 1.1 - ExactCpuSubType = 1U << 0, - - /// Disallow weak imported symbols. This adds weak imported symbols to - /// the ignore exports list. - /// \since 1.1 - DisallowWeakImports = 1U << 1, -}; - -inline ParsingFlags operator|(ParsingFlags lhs, ParsingFlags rhs) noexcept { - return static_cast(static_cast(lhs) | - static_cast(rhs)); -} - -inline ParsingFlags operator|=(ParsingFlags &lhs, ParsingFlags rhs) noexcept { - lhs = lhs | rhs; - return lhs; -} - -/// -/// TAPI File APIs -/// \since 1.0 -/// -class TAPI_PUBLIC LinkerInterfaceFile { -public: - /// - /// Returns a list of supported file extensions. - /// - /// \returns a list of supported file extensions. - /// \since 1.0 - /// - static std::vector getSupportedFileExtensions() noexcept; - - /// - /// Indicate if the provided buffer is a supported Text-based Dynamic - /// Library Stub file. - /// - /// Checks if the buffer is a supported format. This doesn't check for - /// malformed buffer content. - /// - /// \param[in] path full path to the file. - /// \param[in] data raw pointer to start of buffer. - /// \param[in] size size of the buffer in bytes. - /// \returns true if the format is supported. - /// \since 1.0 - /// - static bool isSupported(const std::string &path, const uint8_t *data, - size_t size) noexcept; - - /// - /// Check if we should prefer the text-based stub file. - /// - /// \param[in] path full path to the text-based stub file. - /// \returns true if the tex-based stub file should be prefered over any - /// dynamic library. - /// \since 1.0 - /// - static bool shouldPreferTextBasedStubFile(const std::string &path) noexcept; - - /// - /// Check if the text-based stub file and the MachO dynamic library - /// file are in sync. - /// - /// This validates both files against each other and checks if both files are - /// still in sync. - /// - /// \param[in] tbdPath full path to the text-based stub file. - /// \param[in] dylibPath full path to the MachO dynamic library file. - /// \returns true if both files are in sync. - /// \since 1.0 - /// - static bool areEquivalent(const std::string &tbdPath, - const std::string &dylibPath) noexcept; - - /// - /// Create a LinkerInterfaceFile from the provided buffer. - /// - /// Parses the content of the provided buffer with the given constrains for - /// cpu type, cpu sub-type, matching requirement, and minimum deployment - /// version. - /// - /// \param[in] path path to the file (for error message only). - /// \param[in] data raw pointer to start of buffer. - /// \param[in] size size of the buffer in bytes. - /// \param[in] cpuType The cpu type / architecture to check the file for. - /// \param[in] cpuSubType The cpu sub type / sub architecture to check the - /// file for. - /// \param[in] matchingMode Specified the cpu subtype matching mode. - /// \param[in] minOSVersion The minimum OS version / deployment target. - /// \param[out] errorMessage holds an error message when the return value is a - /// nullptr. - /// \return nullptr on error - /// \since 1.0 - /// - static LinkerInterfaceFile * - create(const std::string &path, const uint8_t *data, size_t size, - cpu_type_t cpuType, cpu_subtype_t cpuSubType, - CpuSubTypeMatching matchingMode, PackedVersion32 minOSVersion, - std::string &errorMessage) noexcept; - - /// - /// Create a LinkerInterfaceFile from the provided buffer. - /// - /// Parses the content of the provided buffer with the given constrains for - /// cpu type, cpu sub-type, flags, and minimum deployment version. - /// - /// \param[in] path path to the file (for error message only). - /// \param[in] data raw pointer to start of buffer. - /// \param[in] size size of the buffer in bytes. - /// \param[in] cpuType The cpu type / architecture to check the file for. - /// \param[in] cpuSubType The cpu sub type / sub architecture to check the - /// file for. - /// \param[in] flags Flags that control the parsing behavior. - /// \param[in] minOSVersion The minimum OS version / deployment target. - /// \param[out] errorMessage holds an error message when the return value is a - /// nullptr. - /// \return nullptr on error - /// \since 1.1 - /// - static LinkerInterfaceFile * - create(const std::string &path, const uint8_t *data, size_t size, - cpu_type_t cpuType, cpu_subtype_t cpuSubType, ParsingFlags flags, - PackedVersion32 minOSVersion, std::string &errorMessage) noexcept; - - /// - /// Create a LinkerInterfaceFile from a file. - /// - /// Parses the content of the file with the given constrains for cpu type, - /// cpu sub-type, flags, and minimum deployment version. - /// - /// \param[in] path path to the file. - /// \param[in] cpuType The cpu type / architecture to check the file for. - /// \param[in] cpuSubType The cpu sub type / sub architecture to check the - /// file for. - /// \param[in] flags Flags that control the parsing behavior. - /// \param[in] minOSVersion The minimum OS version / deployment target. - /// \param[out] errorMessage holds an error message when the return value is a - /// nullptr. - /// \return nullptr on error - /// \since 1.3 - /// - static LinkerInterfaceFile * - create(const std::string &path, cpu_type_t cpuType, cpu_subtype_t cpuSubType, - ParsingFlags flags, PackedVersion32 minOSVersion, - std::string &errorMessage) noexcept; - - /// - /// Query the file type. - /// \return Returns the file type this TAPI file represents. - /// \since 1.0 - /// - FileType getFileType() const noexcept; - - /// - /// Query the platform - /// \return Returns the platform supported by the TAPI file. - /// \since 1.0 - /// - Platform getPlatform() const noexcept; - - /// - /// Query the install name. - /// \return Returns the install name of the TAPI file. - /// \since 1.0 - /// - const std::string &getInstallName() const noexcept; - - /// - /// Query the install name is version specifc. - /// \return True if the install name has been adjusted for the provided - /// minimum OS version. - /// \since 1.0 - /// - bool isInstallNameVersionSpecific() const noexcept; - - /// - /// Query the current library version. - /// \return Returns the current library version as 32bit packed version. - /// \since 1.0 - /// - PackedVersion32 getCurrentVersion() const noexcept; - - /// - /// Query the compatibility library version. - /// \return Returns the compatibility library version as 32bit packed version. - /// \since 1.0 - /// - PackedVersion32 getCompatibilityVersion() const noexcept; - - /// - /// Query the Swift ABI version. - /// \return Returns the Swift ABI version as unsigned integer. - /// \since 1.0 - /// - unsigned getSwiftVersion() const noexcept; - - /// - /// Query the Objective-C Constraint. - /// \return Returns the Objetive-C constraint. - /// \since 1.0 - /// - ObjCConstraint getObjCConstraint() const noexcept; - - /// - /// Query if the library has two level namespace. - /// \return Returns true if the library has two level namespace. - /// \since 1.0 - /// - bool hasTwoLevelNamespace() const noexcept; - - /// - /// Query if the library is Applicatiuon Extension Safe. - /// \return Returns true if the library is Application Extension Safe. - /// \since 1.0 - /// - bool isApplicationExtensionSafe() const noexcept; - - /// - /// Query if the library has any allowable clients. - /// \return Return true if there are any allowable clients. - /// \since 1.0 - /// - bool hasAllowableClients() const noexcept; - - /// - /// Query if the library has any re-exported libraries. - /// \return Return true if there are any re-exported libraries. - /// \since 1.0 - /// - bool hasReexportedLibraries() const noexcept; - - /// - /// Query if the library has any weak defined exports. - /// \return Return true if there are any weak defined exports. - /// \since 1.0 - /// - bool hasWeakDefinedExports() const noexcept; - - /// - /// Obtain the name of the parent framework (umbrella framework). - /// \return Returns the name of the parent framework (if it exists), otherwise - /// an empty string. - /// \since 1.0 - /// - const std::string &getParentFrameworkName() const noexcept; - - /// - /// Obtain the list of allowable clients. - /// \return Returns a list of allowable clients. - /// \since 1.0 - /// - const std::vector &allowableClients() const noexcept; - - /// - /// Obtain the list of re-exported libraries. - /// \return Returns a list of re-exported libraries. - /// \since 1.0 - /// - const std::vector &reexportedLibraries() const noexcept; - - /// - /// Obtain a list of all symbols to be ignored. - /// \return Returns a list of all symbols that should be ignored. - /// \since 1.0 - /// - const std::vector &ignoreExports() const noexcept; - - /// - /// Obtain a list of all exported symbols. - /// \return Returns a list of all exported symbols. - /// \since 1.0 - /// - const std::vector &exports() const noexcept; - - /// - /// Obtain a list of all undefined symbols. - /// \return Returns a list of all undefined symbols. - /// \since 1.0 - /// - const std::vector &undefineds() const noexcept; - - /// - /// Obtain a list of all inlined frameworks. - /// \return Returns a list of install names of all inlined frameworks. - /// \since 1.3 - /// - const std::vector &inlinedFrameworkNames() const noexcept; - - /// - /// Create a LinkerInterfaceFile from the specified inlined framework. - /// - /// Creates a LinkerInterfaceFile with the given constrains for cpu type, - /// cpu sub-type, flags, and minimum deployment version. - /// - /// \param[in] installName install name of the inlined framework. - /// \param[in] cpuType The cpu type / architecture to check the file for. - /// \param[in] cpuSubType The cpu sub type / sub architecture to check the - /// file for. - /// \param[in] flags Flags that control the parsing behavior. - /// \param[in] minOSVersion The minimum OS version / deployment target. - /// \param[out] errorMessage holds an error message when the return value is a - /// nullptr. - /// \return nullptr on error - /// \since 1.3 - /// - LinkerInterfaceFile * - getInlinedFramework(const std::string &installName, cpu_type_t cpuType, - cpu_subtype_t cpuSubType, ParsingFlags flags, - PackedVersion32 minOSVersion, - std::string &errorMessage) const noexcept; - - /// - /// Destructor. - /// \since 1.0 - /// - ~LinkerInterfaceFile() noexcept; - - /// - /// Copy constructor (deleted). - /// \since 1.0 - /// - LinkerInterfaceFile(const LinkerInterfaceFile &) noexcept = delete; - LinkerInterfaceFile &operator=(const LinkerInterfaceFile &) noexcept = delete; - - /// - /// Move constructor. - /// \since 1.0 - /// - LinkerInterfaceFile(LinkerInterfaceFile &&) noexcept; - LinkerInterfaceFile &operator=(LinkerInterfaceFile &&) noexcept; - -private: - LinkerInterfaceFile() noexcept; - - class Impl; - std::unique_ptr _pImpl; -}; - -TAPI_NAMESPACE_V1_END - -#endif // TAPI_LINKER_INTERFACE_FILE_H diff --git a/lib/TBDGen/tapi/PackedVersion32.h b/lib/TBDGen/tapi/PackedVersion32.h deleted file mode 100644 index e837291b797..00000000000 --- a/lib/TBDGen/tapi/PackedVersion32.h +++ /dev/null @@ -1,105 +0,0 @@ -//===-- tapi/PackedVersion32.h - TAPI Packed Version 32 ---------*- C++ -*-===*\ -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Defines the packed version number. -/// \since 1.0 -/// -//===----------------------------------------------------------------------===// -#ifndef TAPI_PACKED_VERSION_32_H -#define TAPI_PACKED_VERSION_32_H - -#include "Defines.h" - -/// -/// \defgroup TAPI_PACKED_VERSION_32 Packed Version handling -/// \ingroup TAPI_CPP_API -/// -/// @{ -/// - -TAPI_NAMESPACE_V1_BEGIN - -/// -/// Packed Version Number Encoding. -/// -/// The Mach-O version numbers are commonly encoded as a 32bit value, where the -/// upper 16 bit quantity is used for the major version number and the lower two -/// 8 bit quantities as minor version number and patch version number. -/// -/// \since 1.0 -/// -class TAPI_PUBLIC PackedVersion32 { -private: - uint32_t _version; - -public: - /// - /// Default construct a PackedVersion32. - /// \since 1.0 - /// - PackedVersion32() = default; - - /// - /// Construct a PackedVersion32 with a raw value. - /// \since 1.0 - /// - PackedVersion32(uint32_t rawVersion) : _version(rawVersion) {} - - /// - /// Construct a PackedVersion32 with the provided major, minor, and - /// patch version number. - /// \since 1.0 - /// - PackedVersion32(unsigned major, unsigned minor, unsigned patch) - : _version((major << 16) | ((minor & 0xff) << 8) | (patch & 0xff)) {} - - /// - /// Get the major version number. - /// \return The major version number as unsigned integer. - /// \since 1.0 - /// - unsigned getMajor() const { return _version >> 16; } - - /// - /// Get the minor version number. - /// \return The minor version number as unsigned integer. - /// \since 1.0 - /// - unsigned getMinor() const { return (_version >> 8) & 0xff; } - - /// - /// Get the patch version number. - /// \return The patch version number as unsigned integer. - /// \since 1.0 - /// - unsigned getPatch() const { return _version & 0xff; } - - bool operator<(const PackedVersion32 &rhs) const { - return _version < rhs._version; - } - - bool operator==(const PackedVersion32 &rhs) const { - return _version == rhs._version; - } - - bool operator!=(const PackedVersion32 &rhs) const { - return _version != rhs._version; - } - - operator unsigned() const { return _version; } -}; - -TAPI_NAMESPACE_V1_END - -/// -/// @} -/// - -#endif // TAPI_PACKED_VERSION_32_H diff --git a/lib/TBDGen/tapi/Platform.cpp b/lib/TBDGen/tapi/Platform.cpp deleted file mode 100644 index 2022634e284..00000000000 --- a/lib/TBDGen/tapi/Platform.cpp +++ /dev/null @@ -1,137 +0,0 @@ -//===- tapi/Core/Platform.cpp - Platform ------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Implements platform specific helper functions. -/// -//===----------------------------------------------------------------------===// - -#include "Platform.h" -#include "LLVM.h" -#include "clang/Basic/Diagnostic.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/raw_ostream.h" - -using namespace llvm; - -TAPI_NAMESPACE_INTERNAL_BEGIN - -Platform mapToSim(Platform platform, bool wantSim) { - switch (platform) { - default: - return platform; - case Platform::iOS: - return wantSim ? Platform::iOSSimulator : Platform::iOS; - case Platform::tvOS: - return wantSim ? Platform::tvOSSimulator : Platform::tvOS; - case Platform::watchOS: - return wantSim ? Platform::watchOSSimulator : Platform::watchOS; - } -} - -static Platform mapToPlatform(const Triple &target) { - switch (target.getOS()) { - default: - return Platform::unknown; - case Triple::MacOSX: - return Platform::macOS; - case Triple::IOS: - if (target.isSimulatorEnvironment()) - return Platform::iOSSimulator; - return Platform::iOS; - case Triple::TvOS: - return target.isSimulatorEnvironment() ? Platform::tvOSSimulator - : Platform::tvOS; - case Triple::WatchOS: - return target.isSimulatorEnvironment() ? Platform::watchOSSimulator - : Platform::watchOS; - /*case Triple::BridgeOS: - return Platform::bridgeOS;*/ - } -} - -Platform mapToSinglePlatform(ArrayRef targets) { - auto result = Platform::unknown; - for (const auto &target : targets) { - auto p = mapToPlatform(target); - if (p == Platform::unknown) - return Platform::unknown; - if (result == Platform::unknown) { - result = p; - continue; - } - if (result != p) - return Platform::unknown; - } - return result; -} - -StringRef getPlatformName(Platform platform) { - switch (platform) { - case Platform::unknown: - return "unknown"; - case Platform::macOS: - return "macOS"; - case Platform::iOS: - return "iOS"; - case Platform::iOSSimulator: - return "iOSSimulator"; - case Platform::watchOS: - return "watchOS"; - case Platform::watchOSSimulator: - return "watchOSSimulator"; - case Platform::tvOS: - return "tvOS"; - case Platform::tvOSSimulator: - return "tvOSSimulator"; - case Platform::bridgeOS: - return "bridgeOS"; - } - llvm_unreachable("unknown platform"); -} - -std::string getOSAndEnvironmentName(Platform platform, std::string version) { - switch (platform) { - case Platform::unknown: - return "darwin" + version; - case Platform::macOS: - return "macos" + version; - case Platform::iOS: - return "ios" + version; - case Platform::iOSSimulator: - return "ios" + version + "-simulator"; - case Platform::watchOS: - return "watchos" + version; - case Platform::watchOSSimulator: - return "watchos" + version + "-simulator"; - case Platform::tvOS: - return "tvos" + version; - case Platform::tvOSSimulator: - return "tvos" + version + "-simulator"; - case Platform::bridgeOS: - return "bridgeos" + version; - } - llvm_unreachable("unknown platform"); -} - -raw_ostream &operator<<(raw_ostream &os, Platform platform) { - os << getPlatformName(platform); - return os; -} - -const DiagnosticBuilder &operator<<(const DiagnosticBuilder &db, - Platform platform) { - db.AddString(getPlatformName(platform)); - return db; -} - -TAPI_NAMESPACE_INTERNAL_END diff --git a/lib/TBDGen/tapi/Platform.h b/lib/TBDGen/tapi/Platform.h deleted file mode 100644 index 0c7c1b6588b..00000000000 --- a/lib/TBDGen/tapi/Platform.h +++ /dev/null @@ -1,52 +0,0 @@ -//===- tapi/Core/Platform.h - Platform --------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Defines the platform enum. -/// -//===----------------------------------------------------------------------===// - -#ifndef TAPI_CORE_PLATFORM_H -#define TAPI_CORE_PLATFORM_H - -#include "LLVM.h" -#include "Defines.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Triple.h" -#include - -TAPI_NAMESPACE_INTERNAL_BEGIN - -enum class Platform : uint8_t { - unknown, - macOS, - iOS, - iOSSimulator, - tvOS, - tvOSSimulator, - watchOS, - watchOSSimulator, - bridgeOS, -}; - -Platform mapToSim(Platform platform, bool wantSim); -Platform mapToSinglePlatform(ArrayRef targets); -StringRef getPlatformName(Platform platform); -std::string getOSAndEnvironmentName(Platform platform, - std::string version = ""); - -raw_ostream &operator<<(raw_ostream &os, Platform platform); - -const DiagnosticBuilder &operator<<(const DiagnosticBuilder &db, - Platform platform); - -TAPI_NAMESPACE_INTERNAL_END - -#endif // TAPI_CORE_PLATFORM_H diff --git a/lib/TBDGen/tapi/Registry.cpp b/lib/TBDGen/tapi/Registry.cpp deleted file mode 100644 index 5be845b0940..00000000000 --- a/lib/TBDGen/tapi/Registry.cpp +++ /dev/null @@ -1,186 +0,0 @@ -//===- lib/Core/Registry.cpp - TAPI Registry --------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Implements the TAPI Registry. -/// -//===----------------------------------------------------------------------===// - -#include "Registry.h" -/*#include "tapi/Core/MachODylibReader.h" -#include "tapi/Core/ReexportFileWriter.h" -#include "tapi/Core/TextAPI_v1.h" -#include "tapi/Core/TextStub_v1.h" -#include "tapi/Core/TextStub_v2.h"*/ -#include "TextStub_v3.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/raw_ostream.h" - -using namespace llvm; - -TAPI_NAMESPACE_INTERNAL_BEGIN - -namespace { - -// Diagnostic reader. It can read all the YAML file with !tapi tag and returns -// proper error when started to read the file. -class DiagnosticReader : public Reader { - bool canRead(file_magic fileType, MemoryBufferRef bufferRef, - FileType types = FileType::All) const override; - Expected getFileType(file_magic magic, - MemoryBufferRef bufferRef) const override; - Expected> - readFile(std::unique_ptr memBuffer, ReadFlags readFlags, - ArchitectureSet arches) const override; -}; - -} // namespace - -bool DiagnosticReader::canRead(file_magic fileType, MemoryBufferRef bufferRef, - FileType types) const { - auto str = bufferRef.getBuffer().trim(); - if (!str.startswith("--- !tapi") || !str.endswith("...")) - return false; - - return true; -} - -Expected -DiagnosticReader::getFileType(file_magic magic, - MemoryBufferRef bufferRef) const { - return Invalid; -} - -Expected> -DiagnosticReader::readFile(std::unique_ptr memBuffer, - ReadFlags readFlags, ArchitectureSet arches) const { - auto str = memBuffer->getBuffer().trim(); - auto tag = str.split('\n').first.drop_front(4); - return make_error( - "unsupported tapi file type \'" + tag.str() + "\' in YAML", - std::make_error_code(std::errc::not_supported)); -} - -bool Registry::canRead(MemoryBufferRef memBuffer, FileType types) const { - auto data = memBuffer.getBuffer(); - auto magic = identify_magic(data); - - for (const auto &reader : _readers) { - if (reader->canRead(magic, memBuffer, types)) - return true; - } - - return false; -} - -Expected Registry::getFileType(MemoryBufferRef memBuffer) const { - auto data = memBuffer.getBuffer(); - auto magic = identify_magic(data); - - for (const auto &reader : _readers) { - auto fileType = reader->getFileType(magic, memBuffer); - if (!fileType) - return fileType.takeError(); - if (fileType.get() != FileType::Invalid) - return fileType; - } - - return FileType::Invalid; -} - -bool Registry::canWrite(const File *file) const { - for (const auto &writer : _writers) { - if (writer->canWrite(file)) - return true; - } - - return false; -} - -Expected> -Registry::readFile(std::unique_ptr memBuffer, ReadFlags readFlags, - ArchitectureSet arches) const { - auto data = memBuffer->getBuffer(); - auto fileType = identify_magic(data); - - for (const auto &reader : _readers) { - if (!reader->canRead(fileType, memBuffer->getMemBufferRef())) - continue; - return reader->readFile(std::move(memBuffer), readFlags, arches); - } - - return make_error( - "unsupported file type", std::make_error_code(std::errc::not_supported)); -} - -Error Registry::writeFile(const File *file, const std::string &path) const { - std::error_code ec; - raw_fd_ostream os(path, ec, sys::fs::F_Text); - if (ec) - return errorCodeToError(ec); - auto error = writeFile(os, file); - if (error) - return error; - os.close(); - if (ec) - return errorCodeToError(ec); - return Error::success(); -} - -Error Registry::writeFile(raw_ostream &os, const File *file) const { - for (const auto &writer : _writers) { - if (!writer->canWrite(file)) - continue; - return writer->writeFile(os, file); - } - - return make_error( - "unsupported file type", std::make_error_code(std::errc::not_supported)); -} - -/*void Registry::addBinaryReaders() { - add(std::unique_ptr(new MachODylibReader)); - }*/ - -void Registry::addYAMLReaders() { - auto reader = make_unique(); - /*reader->add( - std::unique_ptr(new stub::v1::YAMLDocumentHandler)); - reader->add( - std::unique_ptr(new stub::v2::YAMLDocumentHandler));*/ - reader->add( - std::unique_ptr(new stub::v3::YAMLDocumentHandler)); -/*reader->add( - std::unique_ptr(new api::v1::YAMLDocumentHandler));*/ - add(std::unique_ptr(std::move(reader))); -} - -void Registry::addYAMLWriters() { - auto writer = make_unique(); - /*writer->add( - std::unique_ptr(new stub::v1::YAMLDocumentHandler)); - writer->add( - std::unique_ptr(new stub::v2::YAMLDocumentHandler));*/ - writer->add( - std::unique_ptr(new stub::v3::YAMLDocumentHandler)); - /*writer->add( - std::unique_ptr(new api::v1::YAMLDocumentHandler));*/ - add(std::unique_ptr(std::move(writer))); -} - -void Registry::addReexportWriters() { - //add(std::unique_ptr(new ReexportFileWriter)); -} - -void Registry::addDiagnosticReader() { - add(make_unique()); -} - -TAPI_NAMESPACE_INTERNAL_END diff --git a/lib/TBDGen/tapi/Registry.h b/lib/TBDGen/tapi/Registry.h deleted file mode 100644 index 068e159a3ac..00000000000 --- a/lib/TBDGen/tapi/Registry.h +++ /dev/null @@ -1,98 +0,0 @@ -//===- tapi/Core/Registry.h - TAPI Registry ---------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// The TAPI registry keeps track of the supported file formats. -/// -//===----------------------------------------------------------------------===// - -#ifndef TAPI_CORE_REGISTRY_H -#define TAPI_CORE_REGISTRY_H - -#include "ArchitectureSet.h" -#include "File.h" -#include "LLVM.h" -#include "Defines.h" -#include "llvm/BinaryFormat/Magic.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/MemoryBuffer.h" - -using llvm::file_magic; -using llvm::Error; -using llvm::Expected; - -TAPI_NAMESPACE_INTERNAL_BEGIN - -class Registry; - -enum class ReadFlags { - Header, - Symbols, - ObjCMetadata, - All, -}; - -/// Abstract Reader class - all readers need to inherit from this class and -/// implement the interface. -class Reader { -public: - virtual ~Reader() = default; - virtual bool canRead(file_magic fileType, MemoryBufferRef bufferRef, - FileType types = FileType::All) const = 0; - virtual Expected getFileType(file_magic magic, - MemoryBufferRef bufferRef) const = 0; - virtual Expected> - readFile(std::unique_ptr memBuffer, ReadFlags readFlags, - ArchitectureSet arches) const = 0; -}; - -/// Abstract Writer class - all writers need to inherit from this class and -/// implement the interface. -class Writer { -public: - virtual ~Writer() = default; - virtual bool canWrite(const File *file) const = 0; - virtual Error writeFile(raw_ostream &os, const File *file) const = 0; -}; - -class Registry { -public: - bool canRead(MemoryBufferRef memBuffer, FileType types = FileType::All) const; - Expected getFileType(MemoryBufferRef memBuffer) const; - bool canWrite(const File *file) const; - - Expected> - readFile(std::unique_ptr memBuffer, - ReadFlags readFlags = ReadFlags::All, - ArchitectureSet arches = ArchitectureSet::All()) const; - Error writeFile(const File *file, const std::string &path) const; - Error writeFile(raw_ostream &os, const File *file) const; - - void add(std::unique_ptr reader) { - _readers.emplace_back(std::move(reader)); - } - - void add(std::unique_ptr writer) { - _writers.emplace_back(std::move(writer)); - } - - void addBinaryReaders(); - void addYAMLReaders(); - void addYAMLWriters(); - void addDiagnosticReader(); - void addReexportWriters(); - -private: - std::vector> _readers; - std::vector> _writers; -}; - -TAPI_NAMESPACE_INTERNAL_END - -#endif // TAPI_CORE_REGISTRY_H diff --git a/lib/TBDGen/tapi/STLExtras.h b/lib/TBDGen/tapi/STLExtras.h deleted file mode 100644 index 4377916dc13..00000000000 --- a/lib/TBDGen/tapi/STLExtras.h +++ /dev/null @@ -1,77 +0,0 @@ -//===- tapi/Core/STLExtras.h - STL Extras -----------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Simplify common uses cases of C++ code. -/// -//===----------------------------------------------------------------------===// - -#ifndef TAPI_CORE_STL_EXTRAS_H -#define TAPI_CORE_STL_EXTRAS_H - -#include "Defines.h" -#include - -TAPI_NAMESPACE_INTERNAL_BEGIN - -template -inline bool is_sorted(const _T &container, _Compare cmp) { - return std::is_sorted(std::begin(container), std::end(container), cmp); -} - -template inline bool is_sorted(const _T &container) { - return std::is_sorted(std::begin(container), std::end(container)); -} - -template -inline void sort(_T &container, _Compare cmp) { - std::sort(std::begin(container), std::end(container), cmp); -} - -template inline void sort(_T &container) { - std::sort(std::begin(container), std::end(container)); -} - -template -inline auto find(_T &container, const _Tp &value) - -> decltype(std::find(std::begin(container), std::end(container), value)) { - return std::find(std::begin(container), std::end(container), value); -} - -template -inline auto find_if(_T &container, _Predicate pred) - -> decltype(std::find_if(std::begin(container), std::end(container), - pred)) { - return std::find_if(std::begin(container), std::end(container), pred); -} - -template -inline auto remove_if(_T &container, _Predicate pred) - -> decltype(std::remove_if(std::begin(container), std::end(container), - pred)) { - return std::remove_if(std::begin(container), std::end(container), pred); -} - -template -inline auto lower_bound(_T &container, const _Tp &value, _Compare cmp) - -> decltype(std::lower_bound(std::begin(container), std::end(container), - value, cmp)) { - return std::lower_bound(std::begin(container), std::end(container), value, - cmp); -} - -template -inline bool equal(const _T1 &container1, const _T2 &container2) { - return std::equal(std::begin(container1), std::end(container1), - std::begin(container2)); -} - -TAPI_NAMESPACE_INTERNAL_END - -#endif // TAPI_CORE_STL_EXTRAS_H diff --git a/lib/TBDGen/tapi/Symbol.h b/lib/TBDGen/tapi/Symbol.h deleted file mode 100644 index 2914dc0a8ca..00000000000 --- a/lib/TBDGen/tapi/Symbol.h +++ /dev/null @@ -1,121 +0,0 @@ -//===-- tapi/Symbol.h - TAPI Symbol -----------------------------*- C++ -*-===*\ -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Defines a symbol. -/// \since 1.0 -/// -//===----------------------------------------------------------------------===// -#ifndef TAPI_SYMBOL_H -#define TAPI_SYMBOL_H - -#include "Defines.h" - -/// -/// \defgroup TAPI_SYMBOL Symbol API -/// \ingroup TAPI_CPP_API -/// -/// @{ -/// - -TAPI_NAMESPACE_V1_BEGIN - -/// -/// Symbol flags. -/// \since 1.0 -/// -enum class SymbolFlags : unsigned { - /// No flags - /// \since 1.0 - None = 0, - - /// Thread-local value symbol - /// \since 1.0 - ThreadLocalValue = 1U << 0, - - /// Weak defined symbol - /// \since 1.0 - WeakDefined = 1U << 1, - - /// Weak referenced symbol - /// \since 1.0 - WeakReferenced = 1U << 2, -}; - -inline SymbolFlags operator&(const SymbolFlags &lhs, - const SymbolFlags &rhs) noexcept { - return static_cast(static_cast(lhs) & - static_cast(rhs)); -} - -/// -/// Provides query methods for symbols. -/// \since 1.0 -/// -class TAPI_PUBLIC Symbol { -public: - template - Symbol(Tp &&name, SymbolFlags flags = SymbolFlags::None) - : _name(std::forward(name)), _flags(flags) {} - - /// - /// Get the symbol name as string. - /// \return A string with the symbol name. - /// \since 1.0 - /// - inline const std::string &getName() const noexcept { return _name; } - - /// - /// Obtain the symbol flags. - /// \return Returns the symbol flags. - /// \since 1.0 - /// - inline SymbolFlags getFlags() const noexcept { return _flags; } - - /// - /// Query if the symbol is thread-local. - /// \return True if the symbol is a thread-local value, false otherwise. - /// \since 1.0 - /// - inline bool isThreadLocalValue() const noexcept { - return (_flags & SymbolFlags::ThreadLocalValue) == - SymbolFlags::ThreadLocalValue; - } - - /// - /// Query if the symbol is weak defined. - /// \return True if the symbol is weak defined, false otherwise. - /// \since 1.0 - /// - inline bool isWeakDefined() const noexcept { - return (_flags & SymbolFlags::WeakDefined) == SymbolFlags::WeakDefined; - } - - /// - /// Query if the symbol is weak referenced. - /// \return True if the symbol is weak referenced, false otherwise. - /// \since 1.0 - /// - inline bool isWeakReferenced() const noexcept { - return (_flags & SymbolFlags::WeakReferenced) == - SymbolFlags::WeakReferenced; - } - -private: - std::string _name; - SymbolFlags _flags; -}; - -TAPI_NAMESPACE_V1_END - -/// -/// @} -/// - -#endif // TAPI_SYMBOL_H diff --git a/lib/TBDGen/tapi/TapiError.cpp b/lib/TBDGen/tapi/TapiError.cpp deleted file mode 100644 index 9bf1bc50839..00000000000 --- a/lib/TBDGen/tapi/TapiError.cpp +++ /dev/null @@ -1,36 +0,0 @@ -//===- lib/Core/TapiError.cpp - Tapi Error ----------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Implements TAPI Error. -/// -//===----------------------------------------------------------------------===// - -#include "TapiError.h" - -using namespace llvm; - -TAPI_NAMESPACE_INTERNAL_BEGIN - -char TapiError::ID = 0; - -void TapiError::log(raw_ostream &os) const { - switch (ec) { - case TapiErrorCode::NoSuchArchitecture: - os << "no such architecture\n"; - return; - } - llvm_unreachable("unhandled TapiErrorCode"); -} - -std::error_code TapiError::convertToErrorCode() const { - llvm_unreachable("convertToErrorCode is not supported."); -} - -TAPI_NAMESPACE_INTERNAL_END diff --git a/lib/TBDGen/tapi/TapiError.h b/lib/TBDGen/tapi/TapiError.h deleted file mode 100644 index 6a663816e0a..00000000000 --- a/lib/TBDGen/tapi/TapiError.h +++ /dev/null @@ -1,41 +0,0 @@ -//===- tapi/Core/TapiError.h - TAPI Error -----------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Define TAPI specific error codes. -/// -//===----------------------------------------------------------------------===// - -#ifndef TAPI_CORE_TAPIERROR_H -#define TAPI_CORE_TAPIERROR_H - -#include "LLVM.h" -#include "Defines.h" -#include "llvm/Support/Error.h" - -TAPI_NAMESPACE_INTERNAL_BEGIN - -enum class TapiErrorCode { - NoSuchArchitecture, -}; - -class TapiError : public llvm::ErrorInfo { -public: - static char ID; - TapiErrorCode ec; - - TapiError(TapiErrorCode ec) : ec(ec) {} - - void log(raw_ostream &os) const override; - std::error_code convertToErrorCode() const override; -}; - -TAPI_NAMESPACE_INTERNAL_END - -#endif // TAPI_CORE_TAPIERROR_H diff --git a/lib/TBDGen/tapi/TextStub_v3.cpp b/lib/TBDGen/tapi/TextStub_v3.cpp deleted file mode 100644 index a1bf4f23010..00000000000 --- a/lib/TBDGen/tapi/TextStub_v3.cpp +++ /dev/null @@ -1,426 +0,0 @@ -//===- tapi/Core/TextStub_v3.cpp - Text Stub v3 -----------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Implements the text stub file (TBD v3) reader/writer. -/// -//===----------------------------------------------------------------------===// - -#include "TextStub_v3.h" -#include "ArchitectureSupport.h" -#include "InterfaceFile.h" -#include "Registry.h" -#include "YAML.h" -#include "YAMLReaderWriter.h" -#include "LinkerInterfaceFile.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/YAMLTraits.h" -#include - -using namespace llvm; -using namespace llvm::yaml; -using namespace TAPI_INTERNAL; - -namespace { - -struct ExportSection { - std::vector archs; - std::vector allowableClients; - std::vector reexportedLibraries; - std::vector symbols; - std::vector classes; - std::vector classEHs; - std::vector ivars; - std::vector weakDefSymbols; - std::vector tlvSymbols; -}; - -struct UndefinedSection { - std::vector archs; - std::vector symbols; - std::vector classes; - std::vector classEHs; - std::vector ivars; - std::vector weakRefSymbols; -}; - - enum Flags : unsigned { - None = 0U, - FlatNamespace = 1U << 0, - NotApplicationExtensionSafe = 1U << 1, - InstallAPI = 1U << 2, - }; - -inline Flags operator|(const Flags a, const Flags b) { - return static_cast(static_cast(a) | - static_cast(b)); -} - -inline Flags operator|=(Flags &a, const Flags b) { - a = static_cast(static_cast(a) | static_cast(b)); - return a; -} - -} // end anonymous namespace. - -LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(Architecture) -LLVM_YAML_IS_SEQUENCE_VECTOR(ExportSection) -LLVM_YAML_IS_SEQUENCE_VECTOR(UndefinedSection) - -namespace llvm { -namespace yaml { - -template <> struct MappingTraits { - static void mapping(IO &io, ExportSection §ion) { - io.mapRequired("archs", section.archs); - io.mapOptional("allowable-clients", section.allowableClients); - io.mapOptional("re-exports", section.reexportedLibraries); - io.mapOptional("symbols", section.symbols); - io.mapOptional("objc-classes", section.classes); - io.mapOptional("objc-eh-types", section.classEHs); - io.mapOptional("objc-ivars", section.ivars); - io.mapOptional("weak-def-symbols", section.weakDefSymbols); - io.mapOptional("thread-local-symbols", section.tlvSymbols); - } -}; - -template <> struct MappingTraits { - static void mapping(IO &io, UndefinedSection §ion) { - io.mapRequired("archs", section.archs); - io.mapOptional("symbols", section.symbols); - io.mapOptional("objc-classes", section.classes); - io.mapOptional("objc-eh-types", section.classEHs); - io.mapOptional("objc-ivars", section.ivars); - io.mapOptional("weak-ref-symbols", section.weakRefSymbols); - } -}; - -template <> struct ScalarBitSetTraits { - static void bitset(IO &io, Flags &flags) { - io.bitSetCase(flags, "flat_namespace", Flags::FlatNamespace); - io.bitSetCase(flags, "not_app_extension_safe", - Flags::NotApplicationExtensionSafe); - io.bitSetCase(flags, "installapi", Flags::InstallAPI); - } -}; - -template <> struct MappingTraits { - struct NormalizedTBD3 { - explicit NormalizedTBD3(IO &io) {} - NormalizedTBD3(IO &io, const InterfaceFile *&file) { - archs = file->getArchitectures(); - uuids = file->uuids(); - platform = file->getPlatform(); - installName = file->getInstallName(); - currentVersion = file->getCurrentVersion(); - compatibilityVersion = file->getCompatibilityVersion(); - swiftABIVersion = file->getSwiftABIVersion(); - objcConstraint = file->getObjCConstraint(); - - flags = Flags::None; - if (!file->isApplicationExtensionSafe()) - flags |= Flags::NotApplicationExtensionSafe; - - if (!file->isTwoLevelNamespace()) - flags |= Flags::FlatNamespace; - - if (file->isInstallAPI()) - flags |= Flags::InstallAPI; - - parentUmbrella = file->getParentUmbrella(); - - std::set archSet; - for (const auto &library : file->allowableClients()) - archSet.insert(library.getArchitectures()); - - for (const auto &library : file->reexportedLibraries()) - archSet.insert(library.getArchitectures()); - - std::map symbolToArchSet; - for (const auto *symbol : file->exports()) { - auto archs = symbol->getArchitectures(); - symbolToArchSet[symbol] = archs; - archSet.insert(archs); - } - - for (auto archs : archSet) { - ExportSection section; - section.archs = archs; - - for (const auto &library : file->allowableClients()) - if (library.getArchitectures() == archs) - section.allowableClients.emplace_back(library.getInstallName()); - - for (const auto &library : file->reexportedLibraries()) - if (library.getArchitectures() == archs) - section.reexportedLibraries.emplace_back(library.getInstallName()); - - for (const auto &symArch : symbolToArchSet) { - if (symArch.second != archs) - continue; - - const auto *symbol = symArch.first; - switch (symbol->getKind()) { - case SymbolKind::GlobalSymbol: - if (symbol->isWeakDefined()) - section.weakDefSymbols.emplace_back(symbol->getName()); - else if (symbol->isThreadLocalValue()) - section.tlvSymbols.emplace_back(symbol->getName()); - else - section.symbols.emplace_back(symbol->getName()); - break; - case SymbolKind::ObjectiveCClass: - section.classes.emplace_back(symbol->getName()); - break; - case SymbolKind::ObjectiveCClassEHType: - section.classEHs.emplace_back(symbol->getName()); - break; - case SymbolKind::ObjectiveCInstanceVariable: - section.ivars.emplace_back(symbol->getName()); - break; - } - } - TAPI_INTERNAL::sort(section.symbols); - TAPI_INTERNAL::sort(section.classes); - TAPI_INTERNAL::sort(section.classEHs); - TAPI_INTERNAL::sort(section.ivars); - TAPI_INTERNAL::sort(section.weakDefSymbols); - TAPI_INTERNAL::sort(section.tlvSymbols); - exports.emplace_back(std::move(section)); - } - - archSet.clear(); - symbolToArchSet.clear(); - - for (const auto *symbol : file->undefineds()) { - auto archs = symbol->getArchitectures(); - symbolToArchSet[symbol] = archs; - archSet.insert(archs); - } - - for (auto archs : archSet) { - UndefinedSection section; - section.archs = archs; - - for (const auto &symArch : symbolToArchSet) { - if (symArch.second != archs) - continue; - - const auto *symbol = symArch.first; - switch (symbol->getKind()) { - case SymbolKind::GlobalSymbol: - if (symbol->isWeakReferenced()) - section.weakRefSymbols.emplace_back(symbol->getName()); - else - section.symbols.emplace_back(symbol->getName()); - break; - case SymbolKind::ObjectiveCClass: - section.classes.emplace_back(symbol->getName()); - break; - case SymbolKind::ObjectiveCClassEHType: - section.classEHs.emplace_back(symbol->getName()); - break; - case SymbolKind::ObjectiveCInstanceVariable: - section.ivars.emplace_back(symbol->getName()); - break; - } - } - TAPI_INTERNAL::sort(section.symbols); - TAPI_INTERNAL::sort(section.classes); - TAPI_INTERNAL::sort(section.classEHs); - TAPI_INTERNAL::sort(section.ivars); - TAPI_INTERNAL::sort(section.weakRefSymbols); - undefineds.emplace_back(std::move(section)); - } - } - - const InterfaceFile *denormalize(IO &io) { - auto ctx = reinterpret_cast(io.getContext()); - assert(ctx); - - auto *file = new InterfaceFile; - file->setPath(ctx->path); - file->setFileType(TAPI_INTERNAL::FileType::TBD_V3); - for (auto &id : uuids) - file->addUUID(id.first, id.second); - file->setArchitectures(archs); - file->setPlatform(mapToSim(platform, file->getArchitectures().hasX86())); - file->setInstallName(installName); - file->setCurrentVersion(currentVersion); - file->setCompatibilityVersion(compatibilityVersion); - file->setSwiftABIVersion(swiftABIVersion); - file->setObjCConstraint(objcConstraint); - file->setParentUmbrella(parentUmbrella); - - file->setTwoLevelNamespace(!(flags & Flags::FlatNamespace)); - file->setApplicationExtensionSafe( - !(flags & Flags::NotApplicationExtensionSafe)); - file->setInstallAPI(flags & Flags::InstallAPI); - - for (const auto §ion : exports) { - for (const auto &client : section.allowableClients) - file->addAllowableClient(client, section.archs); - for (const auto &lib : section.reexportedLibraries) - file->addReexportedLibrary(lib, section.archs); - - // Skip symbols if requested. - if (ctx->readFlags < ReadFlags::Symbols) - continue; - - for (auto &sym : section.symbols) - file->addSymbolImpl(SymbolKind::GlobalSymbol, sym, section.archs, - SymbolFlags::None, - /*copyStrings=*/false); - for (auto &sym : section.classes) - file->addSymbolImpl(SymbolKind::ObjectiveCClass, sym, section.archs, - SymbolFlags::None, - /*copyStrings=*/false); - for (auto &sym : section.classEHs) - file->addSymbolImpl(SymbolKind::ObjectiveCClassEHType, sym, - section.archs, SymbolFlags::None, - /*copyStrings=*/false); - for (auto &sym : section.ivars) - file->addSymbolImpl(SymbolKind::ObjectiveCInstanceVariable, sym, - section.archs, SymbolFlags::None, - /*copyStrings=*/false); - for (auto &sym : section.weakDefSymbols) - file->addSymbolImpl(SymbolKind::GlobalSymbol, sym, section.archs, - SymbolFlags::WeakDefined, - /*copyStrings=*/false); - for (auto &sym : section.tlvSymbols) - file->addSymbolImpl(SymbolKind::GlobalSymbol, sym, section.archs, - SymbolFlags::ThreadLocalValue, - /*copyStrings=*/false); - } - - // Skip symbols if requested. - if (ctx->readFlags < ReadFlags::Symbols) - return file; - - for (const auto §ion : undefineds) { - for (auto &sym : section.symbols) - file->addUndefinedSymbolImpl(SymbolKind::GlobalSymbol, sym, - section.archs, SymbolFlags::None, - /*copyStrings=*/false); - for (auto &sym : section.classes) - file->addUndefinedSymbolImpl(SymbolKind::ObjectiveCClass, sym, - section.archs, SymbolFlags::None, - /*copyStrings=*/false); - for (auto &sym : section.classEHs) - file->addUndefinedSymbolImpl(SymbolKind::ObjectiveCClassEHType, sym, - section.archs, SymbolFlags::None, - /*copyStrings=*/false); - for (auto &sym : section.ivars) - file->addUndefinedSymbolImpl(SymbolKind::ObjectiveCInstanceVariable, - sym, section.archs, SymbolFlags::None, - /*copyStrings=*/false); - for (auto &sym : section.weakRefSymbols) - file->addUndefinedSymbolImpl(SymbolKind::GlobalSymbol, sym, - section.archs, - SymbolFlags::WeakReferenced, - /*copyStrings=*/false); - } - - return file; - } - - std::vector archs; - std::vector uuids; - Platform platform; - StringRef installName; - PackedVersion currentVersion; - PackedVersion compatibilityVersion; - uint8_t swiftABIVersion; - ObjCConstraint objcConstraint; - Flags flags; - StringRef parentUmbrella; - std::vector exports; - std::vector undefineds; - }; - - static void mappingTBD3(IO &io, const InterfaceFile *&file) { - MappingNormalization keys(io, file); - io.mapTag("!tapi-tbd-v3", true); - io.mapRequired("archs", keys->archs); - io.mapOptional("uuids", keys->uuids); - io.mapRequired("platform", keys->platform); - io.mapOptional("flags", keys->flags, Flags::None); - io.mapRequired("install-name", keys->installName); - io.mapOptional("current-version", keys->currentVersion, - PackedVersion(1, 0, 0)); - io.mapOptional("compatibility-version", keys->compatibilityVersion, - PackedVersion(1, 0, 0)); - io.mapOptional("swift-abi-version", keys->swiftABIVersion, (uint8_t)0U); - io.mapOptional("objc-constraint", keys->objcConstraint, - ObjCConstraint::Retain_Release); - io.mapOptional("parent-umbrella", keys->parentUmbrella, StringRef()); - io.mapOptional("exports", keys->exports); - io.mapOptional("undefineds", keys->undefineds); - } -}; - -} // end namespace yaml. -} // end namespace llvm. - -TAPI_NAMESPACE_INTERNAL_BEGIN - -namespace stub { -namespace v3 { - -bool YAMLDocumentHandler::canRead(MemoryBufferRef memBufferRef, - FileType types) const { - if (!(types & FileType::TBD_V3)) - return false; - - auto str = memBufferRef.getBuffer().trim(); - if (!str.startswith("--- !tapi-tbd-v3\n") || !str.endswith("...")) - return false; - - return true; -} - -FileType YAMLDocumentHandler::getFileType(MemoryBufferRef memBufferRef) const { - if (canRead(memBufferRef)) - return FileType::TBD_V3; - - return FileType::Invalid; -} - -bool YAMLDocumentHandler::canWrite(const File *file) const { - auto *interface = dyn_cast(file); - if (interface == nullptr) - return false; - - if (interface->getFileType() != FileType::TBD_V3) - return false; - - return true; -} - -bool YAMLDocumentHandler::handleDocument(IO &io, const File *&file) const { - if (io.outputting() && file->getFileType() != FileType::TBD_V3) - return false; - - if (!io.outputting() && !io.mapTag("!tapi-tbd-v3")) - return false; - - auto *ctx = reinterpret_cast(io.getContext()); - ctx->fileType = FileType::TBD_V3; - - const auto *interface = dyn_cast_or_null(file); - MappingTraits::mappingTBD3(io, interface); - file = interface; - - return true; -} - -} // end namespace v3. -} // end namespace stub. - -TAPI_NAMESPACE_INTERNAL_END diff --git a/lib/TBDGen/tapi/TextStub_v3.h b/lib/TBDGen/tapi/TextStub_v3.h deleted file mode 100644 index 3351c69bb3b..00000000000 --- a/lib/TBDGen/tapi/TextStub_v3.h +++ /dev/null @@ -1,48 +0,0 @@ -//===- tapi/Core/TextStub_v3.h - Text Stub v3 -------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Defines the content of a text stub v3 file. -/// -//===----------------------------------------------------------------------===// - -#ifndef TAPI_CORE_TEXT_STUB_V3_H -#define TAPI_CORE_TEXT_STUB_V3_H - -#include "File.h" -#include "LLVM.h" -#include "Registry.h" -#include "YAMLReaderWriter.h" -#include "Defines.h" - -namespace llvm { -namespace yaml { -class IO; -} // namespace yaml -} // namespace llvm - -TAPI_NAMESPACE_INTERNAL_BEGIN - -namespace stub { -namespace v3 { - -class YAMLDocumentHandler : public DocumentHandler { - bool canRead(MemoryBufferRef memBufferRef, - FileType types = FileType::All) const override; - FileType getFileType(MemoryBufferRef memBufferRef) const override; - bool canWrite(const File *file) const override; - bool handleDocument(llvm::yaml::IO &io, const File *&file) const override; -}; - -} // end namespace v3. -} // end namespace stub. - -TAPI_NAMESPACE_INTERNAL_END - -#endif // TAPI_CORE_TEXT_STUB_V3_H diff --git a/lib/TBDGen/tapi/Version.h b/lib/TBDGen/tapi/Version.h deleted file mode 100644 index e8c48179a37..00000000000 --- a/lib/TBDGen/tapi/Version.h +++ /dev/null @@ -1,104 +0,0 @@ -//===-- tapi/Version.h - TAPI Version Interface -----------------*- C++ -*-===*\ -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Access the TAPI version information. -/// \since 1.0 -/// -//===----------------------------------------------------------------------===// -#ifndef TAPI_VERSION_H -#define TAPI_VERSION_H - -#include -#include "Defines.h" -#define TAPI_VERSION 2.0.0 -#define TAPI_VERSION_MAJOR 2 -#define TAPI_VERSION_MINOR 0 -#define TAPI_VERSION_PATCH 0 - -/// -/// \defgroup TAPI_VERSION Version methods -/// \ingroup TAPI_CPP_API -/// -/// @{ -/// - -namespace tapi { - -/// -/// Access to version related information about the TAPI dynamic library. -/// \since 1.0 -/// -class TAPI_PUBLIC Version { -public: - /// - /// \name Version Number Methods - /// @{ - /// - - /// - /// Get the major version number. - /// \return The major version number as unsigned integer. - /// \since 1.0 - /// - static unsigned getMajor() noexcept; - - /// - /// Get the minor version number. - /// \return The minor version number as unsigned integer. - /// \since 1.0 - /// - static unsigned getMinor() noexcept; - - /// - /// Get the patch version number. - /// \return The patch version as unsigned integer. - /// \since 1.0 - /// - static unsigned getPatch() noexcept; - - /// - /// Get the library version as string. - /// \return A string with the version number. - /// \since 1.0 - /// - static std::string getAsString() noexcept; - - /// - /// Get the full library name and version as string. - /// \return A string with the program name and version number. - /// \since 1.0 - /// - static std::string getFullVersionAsString() noexcept; - - /// - /// Check if the current version is at least the specified version or - /// greater. - /// \param[in] major The major version number to compare against. - /// \param[in] minor The minor version number to compare against. - /// \param[in] patch The patch version number to compare against. - /// \return True if the current version number is at least the specified - /// version or greater. - /// \since 1.0 - /// - static bool isAtLeast(unsigned major, unsigned minor = 0, - unsigned patch = 0) noexcept; - - /// - /// @} - /// -}; - -} // end tapi namespace. - -/// -/// @} -/// - -#endif // TAPI_VERSION_H diff --git a/lib/TBDGen/tapi/XPI.cpp b/lib/TBDGen/tapi/XPI.cpp deleted file mode 100644 index bf31576ce5c..00000000000 --- a/lib/TBDGen/tapi/XPI.cpp +++ /dev/null @@ -1,213 +0,0 @@ -//===- lib/Core/XPI.cpp - TAPI XPI ------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Implements the XPI set -/// -//===----------------------------------------------------------------------===// - -#include "XPI.h" -#include "Defines.h" -#include "llvm/Demangle/Demangle.h" -#include "llvm/Support/raw_ostream.h" -#include - -using namespace llvm; - -TAPI_NAMESPACE_INTERNAL_BEGIN - -bool XPI::isExportedSymbol() const { - switch (getKind()) { - case XPIKind::GlobalSymbol: - case XPIKind::ObjectiveCClass: - case XPIKind::ObjectiveCClassEHType: - case XPIKind::ObjectiveCInstanceVariable: - break; - case XPIKind::ObjCCategory: - case XPIKind::ObjCProtocol: - case XPIKind::ObjCSelector: - return false; - } - - switch (getAccess()) { - case XPIAccess::Exported: - case XPIAccess::Public: - case XPIAccess::Private: - case XPIAccess::Project: - break; - case XPIAccess::Internal: - case XPIAccess::Unknown: - return false; - } - - return isAvailable(); -} - -std::string XPI::getPrettyName(bool demangle) const { - if (!demangle) - return _name; - - if (demangle && _name.startswith("__Z")) { - int status = 0; - char *demangledName = itaniumDemangle(_name.substr(1).str().c_str(), - nullptr, nullptr, &status); - if (status == 0) { - std::string result = demangledName; - free(demangledName); - return result; - } - } - - if (_name[0] == '_') - return _name.substr(1); - - return _name; -} - -std::string XPI::getAnnotatedName(bool demangle) const { - std::string name; - if (isWeakDefined()) - name += "(weak-def) "; - if (isWeakReferenced()) - name += "(weak-ref) "; - if (isThreadLocalValue()) - name += "(tlv) "; - switch (getKind()) { - case XPIKind::GlobalSymbol: - return name + getPrettyName(demangle); - case XPIKind::ObjectiveCClass: - return name + "(ObjC Class) " + _name.str(); - case XPIKind::ObjectiveCClassEHType: - return name + "(ObjC Class EH) " + _name.str(); - case XPIKind::ObjectiveCInstanceVariable: - return name + "(ObjC IVar) " + _name.str(); - case XPIKind::ObjCSelector: { - auto selector = cast(this); - if (selector->isInstanceMethod()) - return name + "(ObjC Instance Method) " + _name.str(); - - return name + "(ObjC Class Method) " + _name.str(); - } - case XPIKind::ObjCCategory: - return name + "(ObjC Category) " + _name.str(); - case XPIKind::ObjCProtocol: - return name + "(ObjC Protocol) " + _name.str(); - } - llvm_unreachable("unknown kind"); -} - -void XPI::print(raw_ostream &os) const { - switch (getAccess()) { - case XPIAccess::Unknown: - os << "(unknown) "; - break; - case XPIAccess::Exported: - os << "(exported) "; - break; - case XPIAccess::Public: - os << "(public) "; - break; - case XPIAccess::Private: - os << "(private) "; - break; - case XPIAccess::Project: - os << "(project) "; - break; - case XPIAccess::Internal: - os << "(internal) "; - break; - } - os << getAnnotatedName(); - for (const auto &avail : _availability) - os << " [" << avail.first << ": " << avail.second << "]"; -} - -GlobalSymbol *GlobalSymbol::create(BumpPtrAllocator &A, StringRef name, - XPIAccess access, SymbolFlags flags) { - return new (A) GlobalSymbol(name, access, flags); -} - -ObjCInstanceVariable *ObjCInstanceVariable::create(BumpPtrAllocator &A, - StringRef name, - XPIAccess access) { - return new (A) ObjCInstanceVariable(name, access); -} - -ObjCProtocol *ObjCProtocol::create(BumpPtrAllocator &A, StringRef name, - XPIAccess access) { - return new (A) ObjCProtocol(name, access); -} - -void ObjCContainer::addSelector(const ObjCSelector *selector) { - auto it = find(_selectors, selector); - if (it != _selectors.end()) - return; - - auto insertAt = - lower_bound(_selectors, selector, - [](const ObjCSelector *selector, const ObjCSelector *value) { - return static_cast(selector->isInstanceMethod()) < - static_cast(value->isInstanceMethod()) || - selector->getName() < value->getName(); - }); - - _selectors.insert(insertAt, selector); -} - -const ObjCSelector *ObjCContainer::findSelector(StringRef name, - bool isInstanceMethod) const { - auto it = find_if(_selectors, - [&name, isInstanceMethod](const ObjCSelector *selector) { - return selector->isInstanceMethod() == isInstanceMethod && - selector->getName() == name; - }); - - if (it != _selectors.end()) - return *it; - - return nullptr; -} - -ObjCClass *ObjCClass::create(BumpPtrAllocator &A, StringRef name, - XPIAccess access) { - return new (A) ObjCClass(name, access); -} - -void ObjCClass::addCategory(const ObjCCategory *category) { - auto it = find(_categories, category); - if (it != _categories.end()) - return; - - auto insertAt = - lower_bound(_categories, category, - [](const ObjCCategory *category, const ObjCCategory *value) { - return category->getName() < value->getName(); - }); - _categories.insert(insertAt, category); -} - -ObjCClassEHType *ObjCClassEHType::create(BumpPtrAllocator &A, StringRef name, - XPIAccess access) { - return new (A) ObjCClassEHType(name, access); -} - -ObjCCategory *ObjCCategory::create(BumpPtrAllocator &A, ObjCClass *baseClass, - StringRef name, XPIAccess access) { - return new (A) ObjCCategory(baseClass, name, access); -} - -ObjCSelector *ObjCSelector::create(BumpPtrAllocator &A, StringRef name, - bool isInstanceMethod, bool isDynamic, - XPIAccess access, - bool isDerivedFromProtocol) { - return new (A) ObjCSelector(name, isInstanceMethod, isDynamic, access, - isDerivedFromProtocol); -} - -TAPI_NAMESPACE_INTERNAL_END diff --git a/lib/TBDGen/tapi/XPI.h b/lib/TBDGen/tapi/XPI.h deleted file mode 100644 index e7a3decc85f..00000000000 --- a/lib/TBDGen/tapi/XPI.h +++ /dev/null @@ -1,381 +0,0 @@ -//===- tapi/Core/XPI.h - TAPI XPI -------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Defines XPI - API, SPI, etc -/// -//===----------------------------------------------------------------------===// - -#ifndef TAPI_CORE_XPI_H -#define TAPI_CORE_XPI_H - -#include "Architecture.h" -#include "ArchitectureSet.h" -#include "AvailabilityInfo.h" -#include "LLVM.h" -#include "STLExtras.h" -#include "Defines.h" -#include "Symbol.h" -#include "clang/Basic/SourceLocation.h" -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/iterator.h" -#include "llvm/Support/Allocator.h" -#include -#include - -TAPI_NAMESPACE_INTERNAL_BEGIN - -class ObjCClass; -class ObjCContainer; -class XPISet; - -using SymbolFlags = tapi::v1::SymbolFlags; - -/// Helper method to create the symbol flags from the XPI flags. -inline SymbolFlags operator|=(SymbolFlags &lhs, - const SymbolFlags &rhs) noexcept { - lhs = static_cast(static_cast(lhs) | - static_cast(rhs)); - return lhs; -} - -/// The different XPI kinds. -enum class XPIKind : unsigned { - GlobalSymbol, - ObjectiveCClass, - ObjectiveCClassEHType, - ObjectiveCInstanceVariable, - ObjCSelector, - ObjCCategory, - ObjCProtocol, -}; - -/// The XPI access permissions/visibility. -enum class XPIAccess : unsigned { - Unknown, - Exported, - Public, - Private, - Project, - Internal, -}; - -class XPI { -protected: - /// Construct an XPI - the constructor should only be called by a - /// sub-class. - XPI(XPIKind kind, StringRef name, XPIAccess access, - SymbolFlags flags = SymbolFlags::None) - : _name(name), _kind(kind), _access(access), _flags(flags) {} - - /// Construct an XPI - the constructor should only be called by a - /// sub-class. - XPI(XPIKind kind, StringRef name, XPIAccess access, Architecture arch, - AvailabilityInfo &info) - : XPI(kind, name, access) { - addAvailabilityInfo(arch, info); - - if (!info._unavailable) - _archs.set(arch); - } - -public: - bool isExportedSymbol() const; - StringRef getName() const { return _name; } - XPIKind getKind() const { return _kind; } - XPIAccess getAccess() const { return _access; } - void setAccess(XPIAccess access) { _access = access; } - bool updateAccess(XPIAccess access) { - if (access == XPIAccess::Unknown) - return true; - - if (getAccess() == XPIAccess::Unknown) { - setAccess(access); - return true; - } - - // XPIAccess Public and Private are for header declaration only. - // It is fine to re-declare the public XPI in the private header again and - // the final XPIAccess type should be public. - if (getAccess() == XPIAccess::Public && access == XPIAccess::Private) - return true; - if (getAccess() == XPIAccess::Private && access == XPIAccess::Public) { - setAccess(access); - return true; - } - - return getAccess() == access; - } - - bool isWeakDefined() const { - return (_flags & SymbolFlags::WeakDefined) == SymbolFlags::WeakDefined; - } - bool isWeakReferenced() const { - return (_flags & SymbolFlags::WeakReferenced) == - SymbolFlags::WeakReferenced; - } - bool isThreadLocalValue() const { - return (_flags & SymbolFlags::ThreadLocalValue) == - SymbolFlags::ThreadLocalValue; - } - - SymbolFlags getSymbolFlags() const { return _flags; } - - void addAvailabilityInfo(Architecture arch, - const AvailabilityInfo info = AvailabilityInfo(), - bool NoOverwrite = false) { - auto it = - find_if(_availability, - [arch](const std::pair &avail) { - return arch == avail.first; - }); - if (it != _availability.end()) { - if (NoOverwrite && !it->second.isDefault()) - it->second = info; - if (!info._unavailable && info._obsoleted.empty()) { - it->second._unavailable = false; - _archs.set(arch); - } - return; - } - - _availability.emplace_back(arch, info); - if (!info._unavailable && info._obsoleted.empty()) - _archs.set(arch); - } - - const llvm::SmallVectorImpl> & - getAvailabilityInfo() const { - return _availability; - } - - llvm::Optional - getAvailabilityInfo(Architecture arch) const { - auto it = - find_if(_availability, - [arch](const std::pair &avail) { - return arch == avail.first; - }); - if (it != _availability.end()) - return it->second; - - return llvm::None; - } - - ArchitectureSet getArchitectures() const { return _archs; } - - bool hasArch(Architecture arch) const { return _archs.has(arch); } - - bool isAvailable() const { return _archs.count() != 0; } - bool isUnavailable() const { return _archs.count() == 0; } - bool isObsolete() const { - for (const auto &avail : _availability) - if (avail.second._obsoleted.empty()) - return false; - return true; - } - std::string getPrettyName(bool demangle = false) const; - std::string getAnnotatedName(bool demangle = false) const; - void print(raw_ostream &os) const; - - bool operator<(const XPI &other) const { - return std::tie(_kind, _name) < std::tie(other._kind, other._name); - } - -private: - llvm::SmallVector, 4> - _availability{}; - StringRef _name; - ArchitectureSet _archs{}; - -protected: - /// The kind of xpi. - XPIKind _kind; - - /// The access permission/visibility of this xpi. - XPIAccess _access; - - /// Hoisted GlobalSymbol flags. - SymbolFlags _flags; -}; - -inline raw_ostream &operator<<(raw_ostream &os, const XPI &xpi) { - xpi.print(os); - return os; -} - -class GlobalSymbol : public XPI { -private: - GlobalSymbol(StringRef name, XPIAccess access, SymbolFlags flags) - : XPI(XPIKind::GlobalSymbol, name, access, flags) {} - -public: - static GlobalSymbol *create(llvm::BumpPtrAllocator &A, StringRef name, - XPIAccess access, - SymbolFlags flags = SymbolFlags::None); - - static bool classof(const XPI *xpi) { - return xpi->getKind() == XPIKind::GlobalSymbol; - } -}; - -class ObjCClassEHType : public XPI { -private: - ObjCClassEHType(StringRef name, XPIAccess access) - : XPI(XPIKind::ObjectiveCClassEHType, name, access) {} - -public: - static ObjCClassEHType *create(llvm::BumpPtrAllocator &A, StringRef name, - XPIAccess access); - - static bool classof(const XPI *xpi) { - return xpi->getKind() == XPIKind::ObjectiveCClassEHType; - } -}; - -class ObjCInstanceVariable : public XPI { -private: - ObjCInstanceVariable(StringRef name, XPIAccess access) - : XPI(XPIKind::ObjectiveCInstanceVariable, name, access) {} - -public: - static ObjCInstanceVariable *create(llvm::BumpPtrAllocator &A, StringRef name, - XPIAccess access); - - static bool classof(const XPI *xpi) { - return xpi->getKind() == XPIKind::ObjectiveCInstanceVariable; - } -}; - -class ObjCSelector : public XPI { -private: - bool _isInstanceMethod; - bool _isDynamic; - bool _isDerivedFromProtocol; - - ObjCSelector(StringRef name, bool isInstanceMethod, bool isDynamic, - XPIAccess access, bool isDerivedFromProtocol) - : XPI(XPIKind::ObjCSelector, name, access), - _isInstanceMethod(isInstanceMethod), _isDynamic(isDynamic), - _isDerivedFromProtocol(isDerivedFromProtocol) {} - -public: - static ObjCSelector *create(llvm::BumpPtrAllocator &A, StringRef name, - bool isInstanceMethod, bool isDynamic, - XPIAccess access, - bool isDerivedFromProtocol = false); - - bool isInstanceMethod() const { return _isInstanceMethod; } - bool isDynamic() const { return _isDynamic; } - bool isDerivedFromProtocol() const { return _isDerivedFromProtocol; } - - static bool classof(const XPI *xpi) { - return xpi->getKind() == XPIKind::ObjCSelector; - } -}; - -class ObjCContainer : public XPI { -public: - ObjCContainer(XPIKind kind, StringRef name, XPIAccess access) - : XPI(kind, name, access) {} - - static bool classof(const XPI *xpi) { - auto K = xpi->getKind(); - return K == XPIKind::ObjCProtocol || K == XPIKind::ObjectiveCClass || - K == XPIKind::ObjCCategory; - } - - void addSelector(const ObjCSelector *selector); - const ObjCSelector *findSelector(StringRef name, - bool isInstanceMethod = false) const; - using const_selector_range = llvm::iterator_range< - SmallVectorImpl::const_iterator>; - const_selector_range selectors() const { return _selectors; } - -private: - llvm::SmallVector _selectors; -}; - -class ObjCProtocol : public ObjCContainer { -private: - ObjCProtocol(StringRef name, XPIAccess access) - : ObjCContainer(XPIKind::ObjCProtocol, name, access) {} - -public: - static ObjCProtocol *create(llvm::BumpPtrAllocator &A, StringRef name, - XPIAccess access); - - static bool classof(const XPI *xpi) { - return xpi->getKind() == XPIKind::ObjCProtocol; - } -}; - -class ObjCCategory : public ObjCContainer { -private: - ObjCCategory(ObjCClass *baseClass, StringRef name, XPIAccess access) - : ObjCContainer(XPIKind::ObjCCategory, name, access), - _baseClass(baseClass) {} - -public: - static ObjCCategory *create(llvm::BumpPtrAllocator &A, ObjCClass *baseClass, - StringRef name, XPIAccess access); - - static bool classof(const XPI *xpi) { - return xpi->getKind() == XPIKind::ObjCCategory; - } - - const ObjCClass *getBaseClass() const { return _baseClass; } - -private: - const ObjCClass *_baseClass; -}; - -class ObjCClass : public ObjCContainer { -private: - ObjCClass(StringRef name, XPIAccess access) - : ObjCContainer(XPIKind::ObjectiveCClass, name, access), - _superClass(nullptr) {} - -public: - static ObjCClass *create(llvm::BumpPtrAllocator &A, StringRef name, - XPIAccess access); - - static bool classof(const XPI *xpi) { - return xpi->getKind() == XPIKind::ObjectiveCClass; - } - - bool updateSuperClass(ObjCClass *superClass) { - if (superClass == nullptr) - return true; - - if (_superClass == nullptr) { - _superClass = superClass; - return true; - } - - return _superClass == superClass; - } - - const ObjCClass *getSuperClass() const { return _superClass; } - - void addCategory(const ObjCCategory *category); - using const_category_range = llvm::iterator_range< - llvm::SmallVectorImpl::const_iterator>; - const_category_range categories() const { return _categories; } - -private: - llvm::SmallVector _categories; - const ObjCClass *_superClass; -}; - -TAPI_NAMESPACE_INTERNAL_END - -#endif // TAPI_CORE_XPI_H diff --git a/lib/TBDGen/tapi/XPISet.cpp b/lib/TBDGen/tapi/XPISet.cpp deleted file mode 100644 index f090d163164..00000000000 --- a/lib/TBDGen/tapi/XPISet.cpp +++ /dev/null @@ -1,483 +0,0 @@ -//===- lib/Core/XPISet.cpp - TAPI XPI Set -----------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Implements the XPI set -/// -//===----------------------------------------------------------------------===// - -#include "XPISet.h" -#include "Defines.h" -#include "clang/Basic/SourceLocation.h" - -using namespace llvm; -using clang::PresumedLoc; - -TAPI_NAMESPACE_INTERNAL_BEGIN - -GlobalSymbol *XPISet::addGlobalSymbol(StringRef name, PresumedLoc /*loc*/, - XPIAccess access, Architecture arch, - const AvailabilityInfo &info, - bool isWeakDefined) { - name = copyString(name); - GlobalSymbol *globalSymbol; - auto result = - _symbols.emplace(std::piecewise_construct, - std::forward_as_tuple(XPIKind::GlobalSymbol, name), - std::forward_as_tuple(nullptr)); - if (result.second) { - globalSymbol = GlobalSymbol::create(allocator, name, access, - isWeakDefined ? SymbolFlags::WeakDefined - : SymbolFlags::None); - result.first->second = globalSymbol; - } else { - globalSymbol = cast(result.first->second); - assert(globalSymbol->isWeakDefined() == isWeakDefined && - "Weak defined not equal"); - } - - auto success = globalSymbol->updateAccess(access); - assert(success && "Access is not equal"); - (void)success; - - globalSymbol->addAvailabilityInfo(arch, info); - - return globalSymbol; -} - -ObjCClass *XPISet::addObjCClass(StringRef name, PresumedLoc /*loc*/, - XPIAccess access, Architecture arch, - const AvailabilityInfo &info, - ObjCClass *superClass) { - name = copyString(name); - ObjCClass *objcClass = nullptr; - auto result = - _symbols.emplace(std::piecewise_construct, - std::forward_as_tuple(XPIKind::ObjectiveCClass, name), - std::forward_as_tuple(nullptr)); - if (result.second) { - objcClass = ObjCClass::create(allocator, name, access); - result.first->second = objcClass; - } else { - objcClass = cast(result.first->second); - } - - auto success = objcClass->updateAccess(access); - assert(success && "Access is not equal"); - (void)success; - success = objcClass->updateSuperClass(superClass); - assert(success && "super class is not equal"); - (void)success; - objcClass->addAvailabilityInfo(arch, info); - - return objcClass; -} - -ObjCClassEHType *XPISet::addObjCClassEHType(StringRef name, - clang::PresumedLoc /*loc*/, - XPIAccess access, Architecture arch, - const AvailabilityInfo &info) { - name = copyString(name); - ObjCClassEHType *objcClassEH = nullptr; - auto result = _symbols.emplace( - std::piecewise_construct, - std::forward_as_tuple(XPIKind::ObjectiveCClassEHType, name), - std::forward_as_tuple(nullptr)); - if (result.second) { - objcClassEH = ObjCClassEHType::create(allocator, name, access); - result.first->second = objcClassEH; - } else { - objcClassEH = cast(result.first->second); - } - - auto success = objcClassEH->updateAccess(access); - assert(success && "Access is not equal"); - (void)success; - objcClassEH->addAvailabilityInfo(arch, info); - - return objcClassEH; -} - -ObjCInstanceVariable * -XPISet::addObjCInstanceVariable(StringRef name, PresumedLoc /*loc*/, - XPIAccess access, Architecture arch, - const AvailabilityInfo &info) { - name = copyString(name); - ObjCInstanceVariable *objcInstanceVariable = nullptr; - auto result = _symbols.emplace( - std::piecewise_construct, - std::forward_as_tuple(XPIKind::ObjectiveCInstanceVariable, name), - std::forward_as_tuple(nullptr)); - - if (result.second) { - objcInstanceVariable = - ObjCInstanceVariable::create(allocator, name, access); - result.first->second = objcInstanceVariable; - } else { - objcInstanceVariable = cast(result.first->second); - } - - auto success = objcInstanceVariable->updateAccess(access); - assert(success && "Access is not equal"); - (void)success; - objcInstanceVariable->addAvailabilityInfo(arch, info); - - return objcInstanceVariable; -} - -ObjCSelector *XPISet::addObjCSelector(ObjCContainer *container, StringRef name, - bool isInstanceMethod, bool isDynamic, - clang::PresumedLoc /*loc*/, - XPIAccess access, Architecture arch, - const AvailabilityInfo &info, - bool isDerivedFromProtocol) { - const auto *objcClass = container; - bool isCategory = false; - if (auto *category = dyn_cast(container)) { - objcClass = category->getBaseClass(); - isCategory = true; - } - - name = copyString(name); - auto result = _selectors.emplace( - std::piecewise_construct, - std::forward_as_tuple(objcClass->getName(), name, isInstanceMethod, - isa(objcClass)), - std::forward_as_tuple(nullptr)); - ObjCSelector *objcSelector = nullptr; - if (result.second) { - objcSelector = - ObjCSelector::create(allocator, name, isInstanceMethod, isDynamic, - access, isDerivedFromProtocol); - result.first->second = objcSelector; - } else { - objcSelector = cast(result.first->second); - } - - auto success = objcSelector->updateAccess(access); - assert(success && "Access is not equal"); - (void)success; - objcSelector->addAvailabilityInfo(arch, info, isCategory); - - // Record a reference in the container (class, category, or protocol). - container->addSelector(objcSelector); - - return objcSelector; -} - -ObjCCategory *XPISet::addObjCCategory(ObjCClass *baseClass, StringRef name, - PresumedLoc /*loc*/, XPIAccess access, - Architecture arch, - const AvailabilityInfo &info) { - name = copyString(name); - ObjCCategory *objcCategory = nullptr; - auto result = - _categories.emplace(std::piecewise_construct, - std::forward_as_tuple(baseClass->getName(), name), - std::forward_as_tuple(nullptr)); - - if (result.second) { - objcCategory = ObjCCategory::create(allocator, baseClass, name, access); - result.first->second = objcCategory; - } else { - objcCategory = cast(result.first->second); - } - - auto success = objcCategory->updateAccess(access); - assert(success && "Access is not equal"); - (void)success; - objcCategory->addAvailabilityInfo(arch, info); - - // Record a reference in the base class. - baseClass->addCategory(objcCategory); - - return objcCategory; -} - -ObjCProtocol *XPISet::addObjCProtocol(StringRef name, PresumedLoc /*loc*/, - XPIAccess access, Architecture arch, - const AvailabilityInfo info) { - name = copyString(name); - ObjCProtocol *objcProtocol = nullptr; - auto result = - _protocols.emplace(std::piecewise_construct, std::forward_as_tuple(name), - std::forward_as_tuple(nullptr)); - - if (result.second) { - objcProtocol = ObjCProtocol::create(allocator, name, access); - result.first->second = objcProtocol; - } else { - objcProtocol = cast(result.first->second); - } - - auto success = objcProtocol->updateAccess(access); - assert(success && "Access is not equal"); - (void)success; - objcProtocol->addAvailabilityInfo(arch, info); - - return objcProtocol; -} - -GlobalSymbol *XPISet::addGlobalSymbol(StringRef name, ArchitectureSet archs, - SymbolFlags flags, XPIAccess access) { - name = copyString(name); - GlobalSymbol *globalSymbol; - auto result = - _symbols.emplace(std::piecewise_construct, - std::forward_as_tuple(XPIKind::GlobalSymbol, name), - std::forward_as_tuple(nullptr)); - if (result.second) { - globalSymbol = GlobalSymbol::create(allocator, name, access, flags); - result.first->second = globalSymbol; - } else { - globalSymbol = cast(result.first->second); - assert(globalSymbol->getSymbolFlags() == flags && "flags are not equal"); - } - - auto success = globalSymbol->updateAccess(access); - assert(success && "Access is not equal"); - (void)success; - - for (auto arch : archs) - globalSymbol->addAvailabilityInfo(arch); - - return globalSymbol; -} - - -ObjCClass *XPISet::addObjCClass(StringRef name, ArchitectureSet archs, - XPIAccess access, ObjCClass *superClass) { - name = copyString(name); - ObjCClass *objcClass = nullptr; - auto result = - _symbols.emplace(std::piecewise_construct, - std::forward_as_tuple(XPIKind::ObjectiveCClass, name), - std::forward_as_tuple(nullptr)); - if (result.second) { - objcClass = ObjCClass::create(allocator, name, access); - result.first->second = objcClass; - } else { - objcClass = cast(result.first->second); - } - - auto success = objcClass->updateAccess(access); - assert(success && "Access is not equal"); - (void)success; - success = objcClass->updateSuperClass(superClass); - assert(success && "super class is not equal"); - (void)success; - - for (auto arch : archs) - objcClass->addAvailabilityInfo(arch); - - return objcClass; -} - -ObjCClassEHType *XPISet::addObjCClassEHType(StringRef name, - ArchitectureSet archs, - XPIAccess access) { - name = copyString(name); - ObjCClassEHType *objCClassEH = nullptr; - auto result = _symbols.emplace( - std::piecewise_construct, - std::forward_as_tuple(XPIKind::ObjectiveCClassEHType, name), - std::forward_as_tuple(nullptr)); - if (result.second) { - objCClassEH = ObjCClassEHType::create(allocator, name, access); - result.first->second = objCClassEH; - } else { - objCClassEH = cast(result.first->second); - } - - auto success = objCClassEH->updateAccess(access); - assert(success && "Access is not equal"); - (void)success; - - for (auto arch : archs) - objCClassEH->addAvailabilityInfo(arch); - - return objCClassEH; -} - -ObjCInstanceVariable *XPISet::addObjCInstanceVariable(StringRef name, - ArchitectureSet archs, - XPIAccess access) { - name = copyString(name); - ObjCInstanceVariable *objcInstanceVariable = nullptr; - auto result = _symbols.emplace( - std::piecewise_construct, - std::forward_as_tuple(XPIKind::ObjectiveCInstanceVariable, name), - std::forward_as_tuple(nullptr)); - - if (result.second) { - objcInstanceVariable = - ObjCInstanceVariable::create(allocator, name, access); - result.first->second = objcInstanceVariable; - } else { - objcInstanceVariable = cast(result.first->second); - } - - auto success = objcInstanceVariable->updateAccess(access); - assert(success && "Access is not equal"); - (void)success; - - for (auto arch : archs) - objcInstanceVariable->addAvailabilityInfo(arch); - - return objcInstanceVariable; -} - -ObjCSelector *XPISet::addObjCSelector(ObjCContainer *container, StringRef name, - ArchitectureSet archs, - bool isInstanceMethod, bool isDynamic, - XPIAccess access) { - const auto *objcClass = container; - if (auto *category = dyn_cast(container)) - objcClass = category->getBaseClass(); - - name = copyString(name); - auto result = _selectors.emplace( - std::piecewise_construct, - std::forward_as_tuple(objcClass->getName(), name, isInstanceMethod, - isa(objcClass)), - std::forward_as_tuple(nullptr)); - ObjCSelector *objcSelector = nullptr; - if (result.second) { - objcSelector = ObjCSelector::create(allocator, name, isInstanceMethod, - isDynamic, access); - result.first->second = objcSelector; - } else { - objcSelector = cast(result.first->second); - } - - auto success = objcSelector->updateAccess(access); - assert(success && "Access is not equal"); - (void)success; - - for (auto arch : archs) - objcSelector->addAvailabilityInfo(arch); - - // Record a reference in the container (class, category, or protocol). - container->addSelector(objcSelector); - - return objcSelector; -} - -ObjCCategory *XPISet::addObjCCategory(ObjCClass *baseClass, StringRef name, - ArchitectureSet archs, XPIAccess access) { - name = copyString(name); - ObjCCategory *objcCategory = nullptr; - auto result = - _categories.emplace(std::piecewise_construct, - std::forward_as_tuple(baseClass->getName(), name), - std::forward_as_tuple(nullptr)); - - if (result.second) { - objcCategory = ObjCCategory::create(allocator, baseClass, name, access); - result.first->second = objcCategory; - } else { - objcCategory = cast(result.first->second); - } - - auto success = objcCategory->updateAccess(access); - assert(success && "Access is not equal"); - (void)success; - - for (auto arch : archs) - objcCategory->addAvailabilityInfo(arch); - - // Record a reference in the base class. - baseClass->addCategory(objcCategory); - - return objcCategory; -} - -ObjCProtocol *XPISet::addObjCProtocol(StringRef name, ArchitectureSet archs, - XPIAccess access) { - name = copyString(name); - ObjCProtocol *objcProtocol = nullptr; - auto result = - _protocols.emplace(std::piecewise_construct, std::forward_as_tuple(name), - std::forward_as_tuple(nullptr)); - - if (result.second) { - objcProtocol = ObjCProtocol::create(allocator, name, access); - result.first->second = objcProtocol; - } else { - objcProtocol = cast(result.first->second); - } - - auto success = objcProtocol->updateAccess(access); - assert(success && "Access is not equal"); - (void)success; - - for (auto arch : archs) - objcProtocol->addAvailabilityInfo(arch); - - return objcProtocol; -} - -const XPI *XPISet::findSymbol(XPIKind kind, StringRef name) const { - assert((kind == XPIKind::GlobalSymbol || kind == XPIKind::ObjectiveCClass || - kind == XPIKind::ObjectiveCClassEHType || - kind == XPIKind::ObjectiveCInstanceVariable) && - "Not a symbol kind"); - auto it = _symbols.find({kind, name}); - if (it != _symbols.end()) - return it->second; - return nullptr; -} - -const XPI *XPISet::findSymbol(const XPI &xpi) const { - return findSymbol(xpi.getKind(), xpi.getName()); -} - -bool XPISet::removeSymbol(XPIKind kind, StringRef name) { - assert((kind == XPIKind::GlobalSymbol || kind == XPIKind::ObjectiveCClass || - kind == XPIKind::ObjectiveCClassEHType || - kind == XPIKind::ObjectiveCInstanceVariable) && - "Not a symbol kind"); - auto it = _symbols.find({kind, name}); - if (it == _symbols.end()) - return false; - - _symbols.erase(it); - return true; -} - -const ObjCSelector *XPISet::findSelector(const SelectorsMapKey &key) const { - auto it = _selectors.find(key); - if (it != _selectors.end()) - return it->second; - - return nullptr; -} - -const ObjCCategory *XPISet::findCategory(const CategoriesMapKey &key) const { - auto it = _categories.find(key); - if (it != _categories.end()) - return it->second; - - return nullptr; -} - -const ObjCCategory *XPISet::findCategory(const ObjCCategory *category) const { - return findCategory(CategoriesMapKey{category->getBaseClass()->getName(), - category->getName()}); -} - -const ObjCProtocol *XPISet::findProtocol(StringRef key) const { - auto it = _protocols.find(key); - if (it != _protocols.end()) - return it->second; - - return nullptr; -} - -TAPI_NAMESPACE_INTERNAL_END diff --git a/lib/TBDGen/tapi/XPISet.h b/lib/TBDGen/tapi/XPISet.h deleted file mode 100644 index 3e155bdb3ec..00000000000 --- a/lib/TBDGen/tapi/XPISet.h +++ /dev/null @@ -1,291 +0,0 @@ -//===- tapi/Core/XPISet.h - TAPI XPI Set ------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Defines the XPI Set - A set of API, SPI, etc -/// -//===----------------------------------------------------------------------===// - -#ifndef TAPI_CORE_XPISET_H -#define TAPI_CORE_XPISET_H - -#include "Architecture.h" -#include "ArchitectureSet.h" -#include "AvailabilityInfo.h" -#include "STLExtras.h" -#include "XPI.h" -#include "Defines.h" -#include "clang/Basic/SourceLocation.h" -#include "llvm/ADT/Hashing.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/iterator.h" -#include "llvm/ADT/iterator_range.h" -#include "llvm/Support/Allocator.h" -#include -#include - -namespace clang { -class PresumedLoc; -} // namespace clang - -TAPI_NAMESPACE_INTERNAL_BEGIN - -class XPISet { -private: - llvm::BumpPtrAllocator allocator; - - StringRef copyString(StringRef string) { - if (string.empty()) - return {}; - - void *ptr = allocator.Allocate(string.size(), 1); - memcpy(ptr, string.data(), string.size()); - return StringRef(reinterpret_cast(ptr), string.size()); - } - -public: - struct SymbolsMapKey { - XPIKind kind; - StringRef name; - - SymbolsMapKey(XPIKind kind, StringRef name) : kind(kind), name(name) {} - }; - - struct SymbolsMapKeyHash { - std::size_t operator()(const SymbolsMapKey &key) const { - return llvm::hash_combine(key.kind, key.name); - } - }; - - struct SymbolsMapKeyEqual { - bool operator()(const SymbolsMapKey &lhs, const SymbolsMapKey &rhs) const { - return std::tie(lhs.kind, lhs.name) == std::tie(rhs.kind, rhs.name); - } - }; - - struct SelectorsMapKey { - StringRef containerName; - StringRef selectorName; - union { - unsigned raw; - struct { - unsigned isInstanceMethod : 1; - unsigned containerIsProtocol : 1; - } bits; - }; - - SelectorsMapKey(StringRef containerName, StringRef selectorName, - bool isInstanceMethod, bool containerIsProtocol) - : containerName(containerName), selectorName(selectorName), raw(0) { - bits.isInstanceMethod = isInstanceMethod; - bits.containerIsProtocol = containerIsProtocol; - } - }; - - struct SelectorsMapKeyHash { - std::size_t operator()(const SelectorsMapKey &key) const { - return llvm::hash_combine(key.containerName, key.selectorName, key.raw); - } - }; - - struct SelectorsMapKeyEqual { - bool operator()(const SelectorsMapKey &lhs, - const SelectorsMapKey &rhs) const { - return std::tie(lhs.containerName, lhs.selectorName, lhs.raw) == - std::tie(rhs.containerName, rhs.selectorName, rhs.raw); - } - }; - - struct CategoriesMapKey { - StringRef containerName; - StringRef categoryName; - - CategoriesMapKey(StringRef containerName, StringRef categoryName) - : containerName(containerName), categoryName(categoryName) {} - }; - - struct CategoriesMapKeyHash { - std::size_t operator()(const CategoriesMapKey &key) const { - return llvm::hash_combine(key.containerName, key.categoryName); - } - }; - - struct CategoriesMapKeyEqual { - bool operator()(const CategoriesMapKey &lhs, - const CategoriesMapKey &rhs) const { - return std::tie(lhs.containerName, lhs.categoryName) == - std::tie(rhs.containerName, rhs.categoryName); - } - }; - - struct ProtocolsMapKeyHash { - std::size_t operator()(const StringRef &key) const { - return llvm::hash_value(key); - } - }; - - struct ProtocolsMapKeyEqual { - bool operator()(const StringRef &lhs, const StringRef &rhs) const { - return lhs == rhs; - } - }; - - using SymbolsMapType = - std::unordered_map; - using SelectorsMapType = - std::unordered_map; - using CategoriesMapType = - std::unordered_map; - using ProtocolsMapType = - std::unordered_map; - SymbolsMapType _symbols; - SelectorsMapType _selectors; - CategoriesMapType _categories; - ProtocolsMapType _protocols; - -public: - XPISet() = default; - - GlobalSymbol *addGlobalSymbol(StringRef name, clang::PresumedLoc loc, - XPIAccess access, Architecture arch, - const AvailabilityInfo &info, - bool isWeakDefined = false); - ObjCClass *addObjCClass(StringRef name, clang::PresumedLoc loc, - XPIAccess access, Architecture arch, - const AvailabilityInfo &info, - ObjCClass *superClass = nullptr); - ObjCClassEHType *addObjCClassEHType(StringRef name, clang::PresumedLoc loc, - XPIAccess access, Architecture arch, - const AvailabilityInfo &info); - ObjCInstanceVariable *addObjCInstanceVariable(StringRef name, - clang::PresumedLoc loc, - XPIAccess access, - Architecture arch, - const AvailabilityInfo &info); - ObjCSelector *addObjCSelector(ObjCContainer *container, StringRef name, - bool isInstanceMethod, bool isDynamic, - clang::PresumedLoc loc, XPIAccess access, - Architecture arch, const AvailabilityInfo &info, - bool isDerivedFromProtocol = false); - ObjCCategory *addObjCCategory(ObjCClass *baseClass, StringRef name, - clang::PresumedLoc loc, XPIAccess access, - Architecture arch, - const AvailabilityInfo &info); - ObjCProtocol *addObjCProtocol(StringRef name, clang::PresumedLoc loc, - XPIAccess access, Architecture arch, - const AvailabilityInfo info); - - GlobalSymbol *addGlobalSymbol(StringRef name, ArchitectureSet archs, - SymbolFlags flags, XPIAccess access); - ObjCClass *addObjCClass(StringRef name, ArchitectureSet archs, - XPIAccess access, ObjCClass *superClass = nullptr); - ObjCClassEHType *addObjCClassEHType(StringRef name, ArchitectureSet archs, - XPIAccess access); - ObjCInstanceVariable *addObjCInstanceVariable(StringRef name, - ArchitectureSet archs, - XPIAccess access); - ObjCSelector *addObjCSelector(ObjCContainer *container, StringRef name, - ArchitectureSet archs, bool isInstanceMethod, - bool isDynamic, XPIAccess access); - ObjCCategory *addObjCCategory(ObjCClass *baseClass, StringRef name, - ArchitectureSet archs, XPIAccess access); - ObjCProtocol *addObjCProtocol(StringRef name, ArchitectureSet archs, - XPIAccess access); - - const XPI *findSymbol(const XPI &) const; - const XPI *findSymbol(XPIKind kind, StringRef name) const; - bool removeSymbol(XPIKind, StringRef name); - const ObjCSelector *findSelector(const SelectorsMapKey &) const; - const ObjCCategory *findCategory(const CategoriesMapKey &) const; - const ObjCCategory *findCategory(const ObjCCategory *) const; - const ObjCProtocol *findProtocol(StringRef) const; - - struct const_symbol_iterator - : public llvm::iterator_adaptor_base< - const_symbol_iterator, SymbolsMapType::const_iterator, - std::forward_iterator_tag, const XPI *, ptrdiff_t, const XPI *, - const XPI *> { - const_symbol_iterator() = default; - - template - const_symbol_iterator(U &&u) - : iterator_adaptor_base(std::forward(u)) {} - - reference operator*() const { return I->second; } - pointer operator->() const { return I->second; } - }; - using const_symbol_range = llvm::iterator_range; - - // Custom iterator to return only exported symbols. - struct const_export_iterator - : public llvm::iterator_adaptor_base< - const_export_iterator, const_symbol_iterator, - std::forward_iterator_tag, const XPI *> { - const_symbol_iterator _end; - - const_export_iterator() = default; - template - const_export_iterator(U &&it, U &&end) - : iterator_adaptor_base(std::forward(it)), - _end(std::forward(end)) { - while (I != _end && !I->isExportedSymbol()) - ++I; - } - - const_export_iterator &operator++() { - do { - ++I; - } while (I != _end && !I->isExportedSymbol()); - return *this; - } - - const_export_iterator operator++(int) { - const_export_iterator tmp(*this); - do { - ++I; - } while (I != _end && !I->isExportedSymbol()); - return tmp; - } - }; - using const_export_range = llvm::iterator_range; - - const_symbol_range symbols() const { - return {_symbols.begin(), _symbols.end()}; - } - - const_export_range exports() const { - return {const_export_iterator(_symbols.begin(), _symbols.end()), - const_export_iterator(_symbols.end(), _symbols.end())}; - } - - using const_selector_range = - llvm::iterator_range; - const_selector_range selectors() const { return _selectors; } - - using const_category_range = - llvm::iterator_range; - const_category_range categories() const { return _categories; } - - using const_protocol_range = - llvm::iterator_range; - const_protocol_range protocols() const { return _protocols; } - - void *Allocate(size_t Size, unsigned Align = 8) { - return allocator.Allocate(Size, Align); - } -}; - -TAPI_NAMESPACE_INTERNAL_END - -#endif // TAPI_CORE_XPISET_H diff --git a/lib/TBDGen/tapi/YAML.cpp b/lib/TBDGen/tapi/YAML.cpp deleted file mode 100644 index e4798afa4db..00000000000 --- a/lib/TBDGen/tapi/YAML.cpp +++ /dev/null @@ -1,207 +0,0 @@ -//===- lib/Core/YAML.cpp - Common YAML Mappings------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Implements common YAML mappings -/// -//===----------------------------------------------------------------------===// - -#include "YAML.h" - -namespace llvm { -namespace yaml { - -using Impl = ScalarTraits; -void ScalarTraits::output(const FlowStringRef &value, void *ctx, - raw_ostream &os) { - Impl::output(value, ctx, os); -} -StringRef ScalarTraits::input(StringRef value, void *ctx, - FlowStringRef &out) { - return Impl::input(value, ctx, out.value); -} -QuotingType ScalarTraits::mustQuote(StringRef name) { - return Impl::mustQuote(name); -} - -using tapi::ObjCConstraint; -void ScalarEnumerationTraits::enumeration( - IO &io, ObjCConstraint &constraint) { - io.enumCase(constraint, "none", ObjCConstraint::None); - io.enumCase(constraint, "retain_release", ObjCConstraint::Retain_Release); - io.enumCase(constraint, "retain_release_for_simulator", - ObjCConstraint::Retain_Release_For_Simulator); - io.enumCase(constraint, "retain_release_or_gc", - ObjCConstraint::Retain_Release_Or_GC); - io.enumCase(constraint, "gc", ObjCConstraint::GC); -} - -using TAPI_INTERNAL::Platform; -void ScalarEnumerationTraits::enumeration(IO &io, - Platform &platform) { - io.enumCase(platform, "unknown", Platform::unknown); - io.enumCase(platform, "macosx", Platform::macOS); - io.enumCase(platform, "ios", Platform::iOS); - io.enumCase(platform, "ios", Platform::iOSSimulator); - - io.enumCase(platform, "watchos", Platform::watchOS); - io.enumCase(platform, "watchos", Platform::watchOSSimulator); - io.enumCase(platform, "tvos", Platform::tvOS); - io.enumCase(platform, "tvos", Platform::tvOSSimulator); - io.enumCase(platform, "bridgeos", Platform::bridgeOS); -} - -using TAPI_INTERNAL::Architecture; -using TAPI_INTERNAL::ArchitectureSet; -void ScalarBitSetTraits::bitset(IO &io, - ArchitectureSet &archs) { -#define ARCHINFO(arch, type, subtype) \ - io.bitSetCase(archs, #arch, 1U << static_cast(Architecture::arch)); -#include "Architecture.def" -#undef ARCHINFO -} - -using TAPI_INTERNAL::getArchType; -void ScalarTraits::output(const Architecture &value, void *, - raw_ostream &os) { - os << value; -} -StringRef ScalarTraits::input(StringRef scalar, void *, - Architecture &value) { - value = getArchType(scalar); - return {}; -} -QuotingType ScalarTraits::mustQuote(StringRef) { - return QuotingType::None; -} - -using TAPI_INTERNAL::PackedVersion; -void ScalarTraits::output(const PackedVersion &value, void *, - raw_ostream &os) { - os << value; -} -StringRef ScalarTraits::input(StringRef scalar, void *, - PackedVersion &value) { - if (!value.parse32(scalar)) - return "invalid packed version string."; - return {}; -} -QuotingType ScalarTraits::mustQuote(StringRef) { - return QuotingType::None; -} - -void ScalarTraits::output(const SwiftVersion &value, void *, - raw_ostream &os) { - switch (value) { - case 1: - os << "1.0"; - break; - case 2: - os << "1.1"; - break; - case 3: - os << "2.0"; - break; - case 4: - os << "3.0"; - break; - default: - os << (unsigned)value; - break; - } -} -StringRef ScalarTraits::input(StringRef scalar, void *, - SwiftVersion &value) { - value = StringSwitch(scalar) - .Case("1.0", 1) - .Case("1.1", 2) - .Case("2.0", 3) - .Case("3.0", 4) - .Default(0); - if (value != SwiftVersion(0)) - return {}; - - if (scalar.getAsInteger(10, value)) - return "invalid Swift ABI version."; - - return StringRef(); -} -QuotingType ScalarTraits::mustQuote(StringRef) { - return QuotingType::None; -} - -using TAPI_INTERNAL::AvailabilityInfo; -void ScalarTraits::output(const AvailabilityInfo &value, - void *, raw_ostream &os) { - if (value._unavailable) { - os << "n/a"; - return; - } - - os << value._introduced; - if (!value._obsoleted.empty()) - os << ".." << value._obsoleted; -} -StringRef ScalarTraits::input(StringRef scalar, void *, - AvailabilityInfo &value) { - if (scalar == "n/a") { - value._unavailable = true; - return {}; - } - - auto split = scalar.split(".."); - auto introduced = split.first.trim(); - auto obsoleted = split.second.trim(); - - if (!value._introduced.parse32(introduced)) - return "invalid packed version string."; - - if (obsoleted.empty()) - return StringRef(); - - if (!value._obsoleted.parse32(obsoleted)) - return "invalid packed version string."; - - return StringRef(); -} -QuotingType ScalarTraits::mustQuote(StringRef) { - return QuotingType::None; -} - -void ScalarTraits::output(const UUID &value, void *, raw_ostream &os) { - os << value.first << ": " << value.second; -} -StringRef ScalarTraits::input(StringRef scalar, void *, UUID &value) { - auto split = scalar.split(':'); - auto arch = split.first.trim(); - auto uuid = split.second.trim(); - if (uuid.empty()) - return "invalid uuid string pair"; - value.first = getArchType(arch); - value.second = uuid; - return {}; -} -QuotingType ScalarTraits::mustQuote(StringRef) { - return QuotingType::Single; -} - -using clang::InputKind; -void ScalarEnumerationTraits::enumeration( - IO &io, InputKind::Language &kind) { - io.enumCase(kind, "c", InputKind::C); - io.enumCase(kind, "cxx", InputKind::CXX); - io.enumCase(kind, "objective-c", InputKind::ObjC); - io.enumCase(kind, "objc", InputKind::ObjC); // to keep old snapshots working. - io.enumCase(kind, "objective-cxx", InputKind::ObjCXX); - io.enumCase(kind, "objcxx", - InputKind::ObjCXX); // to keep old snapshots working. -} - -} // end namespace yaml. -} // end namespace llvm. diff --git a/lib/TBDGen/tapi/YAML.h b/lib/TBDGen/tapi/YAML.h deleted file mode 100644 index 0a0f474c054..00000000000 --- a/lib/TBDGen/tapi/YAML.h +++ /dev/null @@ -1,101 +0,0 @@ -//===- tapi/Core/YAML.h - YAML ----------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Defines common YAML mappings -/// -//===----------------------------------------------------------------------===// - -#ifndef TAPI_CORE_YAML_H -#define TAPI_CORE_YAML_H - -#include "Architecture.h" -#include "ArchitectureSet.h" -#include "ArchitectureSupport.h" -#include "AvailabilityInfo.h" -#include "Platform.h" -#include "YAMLReaderWriter.h" -#include "clang/Frontend/FrontendOptions.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/Support/YAMLTraits.h" - -using UUID = std::pair; - -LLVM_YAML_STRONG_TYPEDEF(llvm::StringRef, FlowStringRef) -LLVM_YAML_STRONG_TYPEDEF(uint8_t, SwiftVersion) -LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(UUID) -LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(FlowStringRef) - -namespace llvm { -namespace yaml { - -template <> struct ScalarTraits { - static void output(const FlowStringRef &value, void *ctx, raw_ostream &os); - static StringRef input(StringRef value, void *ctx, FlowStringRef &out); - static QuotingType mustQuote(StringRef name); -}; - -using tapi::ObjCConstraint; -template <> struct ScalarEnumerationTraits { - static void enumeration(IO &io, ObjCConstraint &constraint); -}; - -using TAPI_INTERNAL::Platform; -template <> struct ScalarEnumerationTraits { - static void enumeration(IO &io, Platform &platform); -}; - -using TAPI_INTERNAL::Architecture; -using TAPI_INTERNAL::ArchitectureSet; -template <> struct ScalarBitSetTraits { - static void bitset(IO &io, ArchitectureSet &archs); -}; - -using TAPI_INTERNAL::getArchType; -template <> struct ScalarTraits { - static void output(const Architecture &value, void *, raw_ostream &os); - static StringRef input(StringRef scalar, void *, Architecture &value); - static QuotingType mustQuote(StringRef); -}; - -using TAPI_INTERNAL::PackedVersion; -template <> struct ScalarTraits { - static void output(const PackedVersion &value, void *, raw_ostream &os); - static StringRef input(StringRef scalar, void *, PackedVersion &value); - static QuotingType mustQuote(StringRef); -}; - -template <> struct ScalarTraits { - static void output(const SwiftVersion &value, void *, raw_ostream &os); - static StringRef input(StringRef scalar, void *, SwiftVersion &value); - static QuotingType mustQuote(StringRef); -}; - -using TAPI_INTERNAL::AvailabilityInfo; -template <> struct ScalarTraits { - static void output(const AvailabilityInfo &value, void *, raw_ostream &os); - static StringRef input(StringRef scalar, void *, AvailabilityInfo &value); - static QuotingType mustQuote(StringRef); -}; - -template <> struct ScalarTraits { - static void output(const UUID &value, void *, raw_ostream &os); - static StringRef input(StringRef scalar, void *, UUID &value); - static QuotingType mustQuote(StringRef); -}; - -using clang::InputKind; -template <> struct ScalarEnumerationTraits { - static void enumeration(IO &io, InputKind::Language &kind); -}; - -} // end namespace yaml. -} // end namespace llvm. - -#endif // TAPI_CORE_YAML_H diff --git a/lib/TBDGen/tapi/YAMLReaderWriter.cpp b/lib/TBDGen/tapi/YAMLReaderWriter.cpp deleted file mode 100644 index 0268f673af1..00000000000 --- a/lib/TBDGen/tapi/YAMLReaderWriter.cpp +++ /dev/null @@ -1,165 +0,0 @@ -//===- tapi/Core/YAMLReaderWriter.cpp - YAML Reader/Writer ------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Implements the YAML reader/writer. -/// -//===----------------------------------------------------------------------===// - -#include "YAMLReaderWriter.h" -#include "Registry.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/Support/SourceMgr.h" -#include "llvm/Support/YAMLTraits.h" -#include "llvm/Support/raw_ostream.h" - -using namespace llvm; -using namespace llvm::yaml; -using namespace tapi::internal; - -namespace llvm { -namespace yaml { - -template <> struct DocumentListTraits> { - static size_t size(IO &io, std::vector &seq) { - return seq.size(); - } - static const File *&element(IO &io, std::vector &seq, - size_t index) { - if (index >= seq.size()) - seq.resize(index + 1); - return seq[index]; - } -}; - -template <> struct MappingTraits { - static void mapping(IO &io, const File *&file) { - auto ctx = reinterpret_cast(io.getContext()); - assert(ctx != nullptr); - ctx->base.handleDocument(io, file); - } -}; -} // namespace yaml -} // namespace llvm - -TAPI_NAMESPACE_INTERNAL_BEGIN - -static void DiagHandler(const SMDiagnostic &diag, void *context) { - auto *file = static_cast(context); - SmallString<1024> message; - raw_svector_ostream s(message); - - SMDiagnostic newdiag(*diag.getSourceMgr(), diag.getLoc(), file->path, - diag.getLineNo(), diag.getColumnNo(), diag.getKind(), - diag.getMessage(), diag.getLineContents(), - diag.getRanges(), diag.getFixIts()); - - newdiag.print(nullptr, s); - file->errorMessage = message.str(); -} - -bool YAMLBase::canRead(MemoryBufferRef memBufferRef, FileType types) const { - for (const auto &handler : _documentHandlers) { - if (handler->canRead(memBufferRef, types)) - return true; - } - return false; -} - -bool YAMLBase::canWrite(const File *file) const { - for (const auto &handler : _documentHandlers) { - if (handler->canWrite(file)) - return true; - } - return false; -} - -FileType YAMLBase::getFileType(MemoryBufferRef bufferRef) const { - for (const auto &handler : _documentHandlers) { - auto fileType = handler->getFileType(bufferRef); - if (fileType != FileType::Invalid) - return fileType; - } - return FileType::Invalid; -} - -bool YAMLBase::handleDocument(IO &io, const File *&file) const { - for (const auto &handler : _documentHandlers) { - if (handler->handleDocument(io, file)) - return true; - } - return false; -} - -bool YAMLReader::canRead(file_magic magic, MemoryBufferRef memBufferRef, - FileType types) const { - return YAMLBase::canRead(memBufferRef, types); -} - -Expected YAMLReader::getFileType(file_magic magic, - MemoryBufferRef memBufferRef) const { - return YAMLBase::getFileType(memBufferRef); -} - -Expected> -YAMLReader::readFile(std::unique_ptr memBuffer, - ReadFlags readFlags, ArchitectureSet arches) const { - // Create YAML Input Reader. - YAMLContext ctx(*this); - ctx.path = memBuffer->getBufferIdentifier(); - ctx.readFlags = readFlags; - llvm::yaml::Input yin(memBuffer->getBuffer(), &ctx, DiagHandler, &ctx); - - // Fill vector with File objects created by parsing yaml. - std::vector files; - yin >> files; - - if (yin.error()) - return make_error("malformed file\n" + ctx.errorMessage, - yin.error()); - - if (files.empty()) - return errorCodeToError(std::make_error_code(std::errc::not_supported)); - - auto *file = const_cast(files.front()); - file->setMemoryBuffer(std::move(memBuffer)); - - for (auto it = std::next(files.begin()); it != files.end(); ++it) { - auto *document = const_cast(*it); - file->addDocument(std::unique_ptr(document)); - } - - return std::unique_ptr(file); -} - -bool YAMLWriter::canWrite(const File *file) const { - return YAMLBase::canWrite(file); -} - -Error YAMLWriter::writeFile(raw_ostream &os, const File *file) const { - if (file == nullptr) - return errorCodeToError(std::make_error_code(std::errc::invalid_argument)); - - YAMLContext ctx(*this); - ctx.path = file->getPath(); - llvm::yaml::Output yout(os, &ctx, /*WrapColumn=*/80); - - std::vector files; - files.emplace_back(file); - - for (auto &it : file->_documents) - files.emplace_back(it.get()); - - // Stream out yaml. - yout << files; - - return Error::success(); -} - -TAPI_NAMESPACE_INTERNAL_END diff --git a/lib/TBDGen/tapi/YAMLReaderWriter.h b/lib/TBDGen/tapi/YAMLReaderWriter.h deleted file mode 100644 index a91db627185..00000000000 --- a/lib/TBDGen/tapi/YAMLReaderWriter.h +++ /dev/null @@ -1,90 +0,0 @@ -//===- tapi/Core/YAMLReaderWriter.h - YAML Reader/Writer --------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Defines the YAML Reader/Writer. -/// -//===----------------------------------------------------------------------===// - -#ifndef TAPI_CORE_YAML_READER_WRITER_H -#define TAPI_CORE_YAML_READER_WRITER_H - -#include "ArchitectureSet.h" -#include "File.h" -#include "LLVM.h" -#include "Registry.h" -#include "Defines.h" -#include "llvm/BinaryFormat/Magic.h" -#include "llvm/Support/Error.h" -#include - -namespace llvm { -namespace yaml { -class IO; -} // namespace yaml -} // namespace llvm - -TAPI_NAMESPACE_INTERNAL_BEGIN - -class YAMLBase; - -struct YAMLContext { - const YAMLBase &base; - std::string path; - std::string errorMessage; - ReadFlags readFlags; - FileType fileType = FileType::Invalid; - - YAMLContext(const YAMLBase &base) : base(base) {} -}; - -class DocumentHandler { -public: - virtual ~DocumentHandler() = default; - virtual bool canRead(MemoryBufferRef memBufferRef, FileType types) const = 0; - virtual FileType getFileType(MemoryBufferRef bufferRef) const = 0; - virtual bool canWrite(const File *file) const = 0; - virtual bool handleDocument(llvm::yaml::IO &io, const File *&file) const = 0; -}; - -class YAMLBase { -public: - bool canRead(MemoryBufferRef memBufferRef, FileType types) const; - FileType getFileType(MemoryBufferRef bufferRef) const; - bool canWrite(const File *file) const; - bool handleDocument(llvm::yaml::IO &io, const File *&file) const; - - void add(std::unique_ptr handler) { - _documentHandlers.emplace_back(std::move(handler)); - } - -private: - std::vector> _documentHandlers; -}; - -class YAMLReader final : public YAMLBase, public Reader { -public: - bool canRead(file_magic magic, MemoryBufferRef memBufferRef, - FileType types) const override; - Expected getFileType(file_magic magic, - MemoryBufferRef bufferRef) const override; - Expected> - readFile(std::unique_ptr memBuffer, ReadFlags readFlags, - ArchitectureSet arches) const override; -}; - -class YAMLWriter final : public YAMLBase, public Writer { -public: - bool canWrite(const File *file) const override; - Error writeFile(raw_ostream &os, const File *file) const override; -}; - -TAPI_NAMESPACE_INTERNAL_END - -#endif // TAPI_CORE_YAML_READER_WRITER_H diff --git a/lib/TBDGen/tapi/tapi.h b/lib/TBDGen/tapi/tapi.h deleted file mode 100644 index 77c8294387d..00000000000 --- a/lib/TBDGen/tapi/tapi.h +++ /dev/null @@ -1,31 +0,0 @@ -//===-- tapi/tapi.h - TAPI C++ Library Interface ----------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// This is the umbrella header for the TAPI C++ Library Interface. -/// \since 1.0 -/// -//===----------------------------------------------------------------------===// -#ifndef TAPI_H -#define TAPI_H - -/// -/// \defgroup TAPI_CPP_API TAPI C++ API -/// -/// The C++ Application Programming Interface (API) for the TAPI library -/// - -#include "APIVersion.h" -#include "Defines.h" -#include "LinkerInterfaceFile.h" -#include "PackedVersion32.h" -#include "Symbol.h" -#include "Version.h" - -#endif // TAPI_H diff --git a/stdlib/public/core/FloatingPointTypes.swift.gyb b/stdlib/public/core/FloatingPointTypes.swift.gyb index 17ea7a538e6..d83e91b1e8d 100644 --- a/stdlib/public/core/FloatingPointTypes.swift.gyb +++ b/stdlib/public/core/FloatingPointTypes.swift.gyb @@ -1263,7 +1263,7 @@ internal struct _${Self}AnyHashableBox: _AnyHashableBox { ${SelfDocComment} @frozen -@available(*, unavailable, message: "Float80 is only available on non-Windows x86 targets.") +@available(*, unavailable, message: "Float80 is not available on target platform.") public struct ${Self} { /// Creates a value initialized to zero. @_transparent diff --git a/stdlib/public/core/SwiftNativeNSArray.swift b/stdlib/public/core/SwiftNativeNSArray.swift index 79ce494d5ae..b54f45386f0 100644 --- a/stdlib/public/core/SwiftNativeNSArray.swift +++ b/stdlib/public/core/SwiftNativeNSArray.swift @@ -254,7 +254,7 @@ extension __SwiftNativeNSArrayWithContiguousStorage: _NSArrayCore { @objc(exchangeObjectAtIndex:withObjectAtIndex:) dynamic internal func exchange(at index: Int, with index2: Int) { - swap(&contents[index], &contents[index2]) + contents.swapAt(index, index2) } @objc(replaceObjectsInRange:withObjects:count:) @@ -263,7 +263,13 @@ extension __SwiftNativeNSArrayWithContiguousStorage: _NSArrayCore { count: Int) { let range = range.location ..< range.location + range.length let buf = UnsafeBufferPointer(start: objects, count: count) - contents.replaceSubrange(range, with: buf) + if range == contents.startIndex.. + using namespace swift; struct OverrideSection { diff --git a/test/CircularReferences/global_typealias.swift b/test/CircularReferences/global_typealias.swift index 3d03d19448e..2b94ca7ce2e 100644 --- a/test/CircularReferences/global_typealias.swift +++ b/test/CircularReferences/global_typealias.swift @@ -1,6 +1,6 @@ // RUN: %target-typecheck-verify-swift -typealias A = B // expected-note{{type declared here}} -typealias C = D -typealias D = (A, Int) // expected-error{{type alias 'A' references itself}} -typealias B = C +typealias A = B // expected-error {{type alias 'A' references itself}} +typealias C = D // expected-note {{through reference here}} +typealias D = (A, Int) // expected-note {{through reference here}} +typealias B = C // expected-note {{through reference here}} diff --git a/test/ClangImporter/CoreGraphics_test.swift b/test/ClangImporter/CoreGraphics_test.swift index dad3bd50cc8..017265f52a2 100644 --- a/test/ClangImporter/CoreGraphics_test.swift +++ b/test/ClangImporter/CoreGraphics_test.swift @@ -115,8 +115,8 @@ public func testRenames(transform: CGAffineTransform, context: CGContext, context.clip(to: rect) context.clip(to: rect, mask: image) -// CHECK: call void @CGContextClipToRect(%struct.CGContext* [[CONTEXT]], %struct.CGRect* byval nonnull align 8 %{{.*}}) -// CHECK: call void @CGContextClipToMask(%struct.CGContext* [[CONTEXT]], %struct.CGRect* byval nonnull align 8 %{{.*}}, %struct.CGImage* %{{.*}}) +// CHECK: call void @CGContextClipToRect(%struct.CGContext* [[CONTEXT]], %struct.CGRect* nonnull byval align 8 %{{.*}}) +// CHECK: call void @CGContextClipToMask(%struct.CGContext* [[CONTEXT]], %struct.CGRect* nonnull byval align 8 %{{.*}}, %struct.CGImage* %{{.*}}) var slice = CGRect.zero var remainder = CGRect.zero @@ -124,7 +124,7 @@ public func testRenames(transform: CGAffineTransform, context: CGContext, from: edge) assert((slice, remainder) == rect.divided(atDistance: CGFloat(2.0), from: edge)) -// CHECK: call void @CGRectDivide(%struct.CGRect* byval nonnull align 8 %{{.*}}, %struct.CGRect* nonnull %{{.*}}, %struct.CGRect* nonnull %{{.*}}, double {{2\.0+.*}}, i32 %{{.*}}) +// CHECK: call void @CGRectDivide(%struct.CGRect* nonnull byval align 8 %{{.*}}, %struct.CGRect* nonnull %{{.*}}, %struct.CGRect* nonnull %{{.*}}, double {{2\.0+.*}}, i32 %{{.*}}) // // CHECK: ret void } diff --git a/test/ClangImporter/objc_ir.swift b/test/ClangImporter/objc_ir.swift index 2aeb4d656dd..a1c86412e33 100644 --- a/test/ClangImporter/objc_ir.swift +++ b/test/ClangImporter/objc_ir.swift @@ -360,10 +360,13 @@ func testBlocksWithGenerics(hba: HasBlockArray) -> Any { // CHECK: attributes [[NOUNWIND]] = { nounwind } // CHECK: ![[SWIFT_NAME_ALIAS_VAR]] = !DILocalVariable(name: "obj", arg: 1, scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[SWIFT_NAME_ALIAS_TYPE:[0-9]+]]) +// CHECK: ![[LET_SWIFT_NAME_ALIAS_TYPE:[0-9]+]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[SWIFT_NAME_ALIAS_TYPE:[0-9]+]]) // CHECK: ![[SWIFT_NAME_ALIAS_TYPE]] = !DIDerivedType(tag: DW_TAG_typedef, name: "$sSo14SwiftNameAliasaD", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: !{{[0-9]+}}) -// CHECK: ![[SWIFT_GENERIC_NAME_ALIAS_VAR]] = !DILocalVariable(name: "generic_obj", arg: 1, scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[SWIFT_GENERIC_NAME_ALIAS_TYPE:[0-9]+]]) +// CHECK: ![[SWIFT_GENERIC_NAME_ALIAS_VAR]] = !DILocalVariable(name: "generic_obj", arg: 1, scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[LET_SWIFT_GENERIC_NAME_ALIAS_TYPE:[0-9]+]]) +// CHECK: ![[LET_SWIFT_GENERIC_NAME_ALIAS_TYPE:[0-9]+]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[SWIFT_GENERIC_NAME_ALIAS_TYPE:[0-9]+]]) // CHECK: ![[SWIFT_GENERIC_NAME_ALIAS_TYPE]] = !DIDerivedType(tag: DW_TAG_typedef, name: "$sSo21SwiftGenericNameAliasaySo8NSNumberCGD", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: !{{[0-9]+}}) -// CHECK: ![[SWIFT_CONSTR_GENERIC_NAME_ALIAS_VAR]] = !DILocalVariable(name: "constr_generic_obj", arg: 1, scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[SWIFT_CONSTR_GENERIC_NAME_ALIAS_TYPE:[0-9]+]]) +// CHECK: ![[SWIFT_CONSTR_GENERIC_NAME_ALIAS_VAR]] = !DILocalVariable(name: "constr_generic_obj", arg: 1, scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[LET_SWIFT_CONSTR_GENERIC_NAME_ALIAS_TYPE:[0-9]+]]) +// CHECK: ![[LET_SWIFT_CONSTR_GENERIC_NAME_ALIAS_TYPE:[0-9]+]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[SWIFT_CONSTR_GENERIC_NAME_ALIAS_TYPE:[0-9]+]]) // CHECK: ![[SWIFT_CONSTR_GENERIC_NAME_ALIAS_TYPE]] = !DIDerivedType(tag: DW_TAG_typedef, name: "$sSo27SwiftConstrGenericNameAliasaySo8NSNumberCGD", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: !{{[0-9]+}}) diff --git a/test/ClangImporter/pch-bridging-header.swift b/test/ClangImporter/pch-bridging-header.swift index d2ab92b7248..a4aacb04907 100644 --- a/test/ClangImporter/pch-bridging-header.swift +++ b/test/ClangImporter/pch-bridging-header.swift @@ -46,6 +46,12 @@ // RUN: not %target-swift-frontend -typecheck %s -import-objc-header %S/Inputs/sdk-bridging-header.h -pch-output-dir %t/no-pch -pch-disable-validation 2>&1 | %FileCheck %s -check-prefix=NO-VALIDATION // NO-VALIDATION: PCH file {{.*}} not found +// Test that -Xcc options are considered in the PCH hash. +// RUN: %target-swift-frontend -emit-pch -pch-output-dir %t/pch-Xcc %S/Inputs/sdk-bridging-header.h +// RUN: %target-swift-frontend -emit-pch -pch-output-dir %t/pch-Xcc %S/Inputs/sdk-bridging-header.h -Xcc -Ifoo +// RUN: %target-swift-frontend -emit-pch -pch-output-dir %t/pch-Xcc %S/Inputs/sdk-bridging-header.h -Xcc -Ibar +// RUN: ls %t/pch-Xcc/*swift*clang*.pch | count 3 + import Foundation let not = MyPredicate.not() diff --git a/test/DebugInfo/DynamicSelf.swift b/test/DebugInfo/DynamicSelf.swift index fb89ac893b2..6d48065b53a 100644 --- a/test/DebugInfo/DynamicSelf.swift +++ b/test/DebugInfo/DynamicSelf.swift @@ -16,7 +16,7 @@ extension C { // CHECK: ![[SELFTY]] = !DIDerivedType(tag: DW_TAG_typedef, // CHECK-SAME: name: "$s11DynamicSelf1CCXDD", // CHECK-SAME: baseType: ![[BASE]]) - let r = self.init(number: 0) + var r = self.init(number: 0) return r } } diff --git a/test/DebugInfo/archetypes2.swift b/test/DebugInfo/archetypes2.swift index 5c10be652ac..124f157cb0d 100644 --- a/test/DebugInfo/archetypes2.swift +++ b/test/DebugInfo/archetypes2.swift @@ -4,9 +4,15 @@ func markUsed(_ t: T) {} class C { // CHECK: ![[A:.*]] = !DICompositeType(tag: DW_TAG_structure_type,{{.*}}identifier: "$sxD" + // CHECK: ![[LET_A:[0-9]+]] = !DIDerivedType(tag: DW_TAG_const_type, + // CHECK-SAME: baseType: ![[A]]) // CHECK: ![[B:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type,{{.*}}identifier: "$sqd__D") - // CHECK: !DILocalVariable(name: "x", arg: 1,{{.*}}line: [[@LINE+2]],{{.*}}type: ![[A]] - // CHECK: !DILocalVariable(name: "y", arg: 2,{{.*}}line: [[@LINE+1]],{{.*}}type: ![[B]]) + // CHECK: !DILocalVariable(name: "x", arg: 1,{{.*}}line: [[@LINE+6]], + // CHECK-SAME: type: ![[LET_A]] + // CHECK: !DILocalVariable(name: "y", arg: 2,{{.*}}line: [[@LINE+4]], + // CHECK-SAME: type: ![[LET_B:[0-9]+]] + // CHECK: ![[LET_B]] = !DIDerivedType(tag: DW_TAG_const_type, + // CHECK-SAME: baseType: ![[B]]) func foo(_ x: A, y :B) { markUsed("hello world") } diff --git a/test/DebugInfo/dbgvalue-insertpt.swift b/test/DebugInfo/dbgvalue-insertpt.swift index 24ecdc834e6..0d670e4bb7d 100644 --- a/test/DebugInfo/dbgvalue-insertpt.swift +++ b/test/DebugInfo/dbgvalue-insertpt.swift @@ -9,10 +9,10 @@ for i in 0 ..< 3 { // CHECK: %[[LD:[0-9]+]] = load i{{32|64}}, i{{32|64}}* // CHECK: br i1 {{%.*}}, label %[[FAIL:.*]], label %[[SUCCESS:.*]], // - // CHECK: ;

{ func bar(_ x : Tuple) -> Tuple { return x } // CHECK: ![[LIST:.*]] = !DICompositeType({{.*}}identifier: "$s4enum4ListOyxGD" -// CHECK: !DILocalVariable(name: "self", arg: 1, {{.*}} line: [[@LINE+4]], type: ![[LIST]], flags: DIFlagArtificial) +// CHECK-DAG: ![[LET_LIST:.*]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[LIST]]) +// CHECK-DAG: !DILocalVariable(name: "self", arg: 1, {{.*}} line: [[@LINE+4]], type: ![[LET_LIST]], flags: DIFlagArtificial) public enum List { indirect case Tail(List, T) case End diff --git a/test/DebugInfo/generic_arg.swift b/test/DebugInfo/generic_arg.swift index 42294c3cdf8..c2e7ffeb06e 100644 --- a/test/DebugInfo/generic_arg.swift +++ b/test/DebugInfo/generic_arg.swift @@ -10,11 +10,13 @@ func foo(_ x: T) -> () { // CHECK-SAME: metadata ![[X1:.*]], metadata !DIExpression(DW_OP_deref)) // CHECK: store %swift.type* %T, %swift.type** %[[T]], // CHECK: store %swift.opaque* %0, %swift.opaque** %[[X]], - // CHECK: ![[TY2:.*]] = !DICompositeType({{.*}}identifier: "$sxD") + // CHECK: ![[TY2:[0-9]+]] = !DICompositeType({{.*}}identifier: "$sxD") // CHECK: ![[T1]] = !DILocalVariable(name: "$\CF\84_0_0", // CHECK-SAME: flags: DIFlagArtificial) // CHECK: ![[X1]] = !DILocalVariable(name: "x", arg: 1, - // CHECK-SAME: line: 3, type: ![[TY2]]) + // CHECK-SAME: line: 3, type: ![[LET_TY2:[0-9]+]]) + // CHECK: ![[LET_TY2]] = !DIDerivedType(tag: DW_TAG_const_type, + // CHECK-SAME: baseType: ![[TY2]]) _blackHole(x) } diff --git a/test/DebugInfo/generic_arg3.swift b/test/DebugInfo/generic_arg3.swift index 11ff6c5f047..4e7a90cc162 100644 --- a/test/DebugInfo/generic_arg3.swift +++ b/test/DebugInfo/generic_arg3.swift @@ -10,7 +10,9 @@ public func f(_ value : Type) // CHECK: store %swift.opaque* %1, %swift.opaque** %[[ALLOCA]], align // No deref here. // CHECK: ![[TY:.*]] = !DICompositeType({{.*}}identifier: "$sxD" + // CHECK: ![[LET_TY:[0-9]+]] = !DIDerivedType(tag: DW_TAG_const_type, + // CHECK-SAME: baseType: ![[TY]]) // CHECK: ![[ARG]] = !DILocalVariable(name: "arg", arg: 1, - // CHECK-SAME: line: [[@LINE+1]], type: ![[TY]]) + // CHECK-SAME: line: [[@LINE+1]], type: ![[LET_TY]]) apply(value) { arg in return arg } } diff --git a/test/DebugInfo/generic_arg5.swift b/test/DebugInfo/generic_arg5.swift index a13246be837..419cd34867e 100644 --- a/test/DebugInfo/generic_arg5.swift +++ b/test/DebugInfo/generic_arg5.swift @@ -12,11 +12,13 @@ public func foo(_ values : [S]) // CHECK-SAME: metadata ![[ARG:[0-9]+]], // CHECK-SAME: metadata !DIExpression(DW_OP_deref)) // CHECK: store %[[TY]]* %1, %[[TY]]** %[[ALLOCA]], align - // CHECK: ![[TYP:.*]] = !DICompositeType({{.*}}, identifier: "$s12generic_arg51SVyxGD") + // CHECK: ![[TYP:[0-9]+]] = !DICompositeType({{.*}}, identifier: "$s12generic_arg51SVyxGD") // The argument is a by-ref struct and thus needs to be dereferenced. // CHECK: ![[ARG]] = !DILocalVariable(name: "arg", arg: 1, - // CHECK-SAME: line: [[@LINE+2]], - // CHECK-SAME: type: ![[TYP]]) + // CHECK-SAME: line: [[@LINE+4]], + // CHECK-SAME: type: ![[LET_TYP:[0-9]+]]) + // CHECK: ![[LET_TYP]] = !DIDerivedType(tag: DW_TAG_const_type, + // CHECK-SAME: baseType: ![[TYP]]) let _ = values.flatMap { arg in return .some(arg) } diff --git a/test/DebugInfo/generic_args.swift b/test/DebugInfo/generic_args.swift index 30fdb4efce6..293e20b93a3 100644 --- a/test/DebugInfo/generic_args.swift +++ b/test/DebugInfo/generic_args.swift @@ -1,4 +1,3 @@ - // RUN: %target-swift-frontend -module-name generic_args -primary-file %s -emit-ir -verify -g -o - | %FileCheck %s -allow-deprecated-dag-overlap func markUsed(_ t: T) {} @@ -13,10 +12,12 @@ class AnotherClass : AProtocol { func f() -> String { return "B" } } -// CHECK-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "$sq_D",{{.*}} -// CHECK-DAG: !DILocalVariable(name: "x", arg: 1,{{.*}} type: ![[T:.*]]) +// CHECK-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "$sq_D", +// CHECK-DAG: !DILocalVariable(name: "x", arg: 1,{{.*}} type: ![[LET_T:.*]]) +// CHECK-DAG: ![[LET_T]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[T:.*]]) // CHECK-DAG: ![[T]] = !DICompositeType(tag: DW_TAG_structure_type, name: "$sxD" -// CHECK-DAG: !DILocalVariable(name: "y", arg: 2,{{.*}} type: ![[Q:.*]]) +// CHECK-DAG: !DILocalVariable(name: "y", arg: 2,{{.*}} type: ![[LET_Q:.*]]) +// CHECK-DAG: ![[LET_Q]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[Q:.*]]) // CHECK-DAG: ![[Q]] = !DICompositeType(tag: DW_TAG_structure_type, name: "$sq_D" func aFunction(_ x: T, _ y: Q, _ z: String) { markUsed("I am in \(z): \(x.f()) \(y.f())") @@ -43,7 +44,8 @@ struct Wrapper { } // CHECK-DAG: ![[FNTY:.*]] = !DICompositeType({{.*}}identifier: "$sxq_Ignr_D" -// CHECK-DAG: !DILocalVariable(name: "f", {{.*}}, line: [[@LINE+1]], type: ![[FNTY]]) +// CHECK-DAG: ![[LET_FNTY:.*]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[FNTY]]) +// CHECK-DAG: !DILocalVariable(name: "f", {{.*}}, line: [[@LINE+1]], type: ![[LET_FNTY]]) func apply (_ x: T, f: (T) -> (U)) -> U { return f(x) } diff --git a/test/DebugInfo/inlined-generics-basic.swift b/test/DebugInfo/inlined-generics-basic.swift index fa6f3ebaa5c..d1f6fbb6869 100644 --- a/test/DebugInfo/inlined-generics-basic.swift +++ b/test/DebugInfo/inlined-generics-basic.swift @@ -83,30 +83,35 @@ public class C { } // IR: ![[BOOL:[0-9]+]] = !DICompositeType({{.*}}name: "Bool" +// IR: ![[LET_BOOL:[0-9]+]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[BOOL]]) // IR: ![[INT:[0-9]+]] = !DICompositeType({{.*}}name: "Int" +// IR: ![[LET_INT:[0-9]+]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[INT]]) // IR: ![[TAU_0_0:[0-9]+]] = {{.*}}DW_TAG_structure_type, name: "$sxD", +// IR: ![[LET_TAU_0_0:[0-9]+]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[TAU_0_0]]) // IR: ![[TAU_1_0:[0-9]+]] = {{.*}}DW_TAG_structure_type, name: "$sqd__D", // IR: ![[MD_1_0]] = !DILocalVariable(name: "$\CF\84_1_0" -// IR: ![[S]] = !DILocalVariable(name: "s", {{.*}} type: ![[TAU_1_0]] -// IR: ![[GS_T]] = !DILocalVariable(name: "t", {{.*}} scope: ![[SP_GS_T:[0-9]+]], {{.*}} type: ![[TAU_1_0]]) +// IR: ![[S]] = !DILocalVariable(name: "s", {{.*}} type: ![[LET_TAU_1_0:[0-9]+]] +// IR: ![[LET_TAU_1_0]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[TAU_1_0]]) +// IR: ![[GS_T]] = !DILocalVariable(name: "t", {{.*}} scope: ![[SP_GS_T:[0-9]+]], {{.*}} type: ![[LET_TAU_1_0]]) // IR: ![[SP_GS_T]] = {{.*}}linkageName: "$s1A1gyyxlFqd___Ti5" -// IR: ![[GS_U]] = !DILocalVariable(name: "u", {{.*}} scope: ![[SP_GS_U:[0-9]+]], {{.*}} type: ![[TAU_1_0]]) +// IR: ![[GS_U]] = !DILocalVariable(name: "u", {{.*}} scope: ![[SP_GS_U:[0-9]+]], {{.*}} type: ![[LET_TAU_1_0]]) // IR: ![[SP_GS_U]] = {{.*}}linkageName: "$s1A1hyyxlFqd___Ti5" -// IR: ![[GR_T]] = !DILocalVariable(name: "t", {{.*}} scope: ![[SP_GR_T:[0-9]+]], {{.*}}type: ![[TAU_0_0]]) +// IR: ![[GR_T]] = !DILocalVariable(name: "t", {{.*}} scope: ![[SP_GR_T:[0-9]+]], {{.*}}type: ![[LET_TAU_0_0]]) // S has the same generic parameter numbering s T and U. // IR: ![[SP_GR_T]] = {{.*}}linkageName: "$s1A1gyyxlF" -// IR: ![[GR_U]] = !DILocalVariable(name: "u", {{.*}} scope: ![[SP_GR_U:[0-9]+]], {{.*}}type: ![[TAU_0_0]]) +// IR: ![[GR_U]] = !DILocalVariable(name: "u", {{.*}} scope: ![[SP_GR_U:[0-9]+]], {{.*}}type: ![[LET_TAU_0_0]]) // IR: ![[SP_GR_U]] = {{.*}}linkageName: "$s1A1hyyxlF" -// IR: ![[GRS_T]] = !DILocalVariable(name: "t", {{.*}} scope: ![[SP_GRS_T:[0-9]+]], {{.*}}type: ![[TUPLE:[0-9]+]] +// IR: ![[GRS_T]] = !DILocalVariable(name: "t", {{.*}} scope: ![[SP_GRS_T:[0-9]+]], {{.*}}type: ![[LET_TUPLE:[0-9]+]] // IR: ![[SP_GRS_T]] = {{.*}}linkageName: "$s1A1gyyxlFx_qd__t_Ti5" +// IR: ![[LET_TUPLE]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[TUPLE:[0-9]+]]) // IR: ![[TUPLE]] = {{.*}}DW_TAG_structure_type, name: "$sx_qd__tD" -// IR: ![[GRS_U]] = !DILocalVariable(name: "u", {{.*}} scope: ![[SP_GRS_U:[0-9]+]], {{.*}}type: ![[TUPLE]] +// IR: ![[GRS_U]] = !DILocalVariable(name: "u", {{.*}} scope: ![[SP_GRS_U:[0-9]+]], {{.*}}type: ![[LET_TUPLE]] // IR: ![[SP_GRS_U]] = {{.*}}linkageName: "$s1A1hyyxlFx_qd__t_Ti5" -// IR-DAG: ![[GI_T]] = !DILocalVariable(name: "t", {{.*}} scope: ![[SP_GI_G:[0-9]+]], {{.*}}type: ![[INT]]) +// IR-DAG: ![[GI_T]] = !DILocalVariable(name: "t", {{.*}} scope: ![[SP_GI_G:[0-9]+]], {{.*}}type: ![[LET_INT]]) // IR-DAG: ![[SP_GI_G]] = {{.*}}linkageName: "$s1A1gyyxlFSi_Tg5" -// IR-DAG: ![[GI_U]] = !DILocalVariable(name: "u", {{.*}} scope: ![[SP_GI_U:[0-9]+]], {{.*}}type: ![[INT]]) +// IR-DAG: ![[GI_U]] = !DILocalVariable(name: "u", {{.*}} scope: ![[SP_GI_U:[0-9]+]], {{.*}}type: ![[LET_INT]]) // IR-DAG: ![[SP_GI_U]] = {{.*}}linkageName: "$s1A1hyyxlFSi_TG5" -// IR-DAG: ![[GB_T]] = !DILocalVariable(name: "t", {{.*}} scope: ![[SP_GB_G:[0-9]+]], {{.*}}type: ![[BOOL]]) +// IR-DAG: ![[GB_T]] = !DILocalVariable(name: "t", {{.*}} scope: ![[SP_GB_G:[0-9]+]], {{.*}}type: ![[LET_BOOL]]) // IR-DAG: ![[SP_GB_G]] = {{.*}}linkageName: "$s1A1gyyxlFSb_Tg5" -// IR-DAG: ![[GB_U]] = !DILocalVariable(name: "u", {{.*}} scope: ![[SP_GB_U:[0-9]+]], {{.*}}type: ![[BOOL]]) +// IR-DAG: ![[GB_U]] = !DILocalVariable(name: "u", {{.*}} scope: ![[SP_GB_U:[0-9]+]], {{.*}}type: ![[LET_BOOL]]) // IR-DAG: ![[SP_GB_U]] = {{.*}}linkageName: "$s1A1hyyxlFSb_TG5" diff --git a/test/DebugInfo/inout.swift b/test/DebugInfo/inout.swift index 77c737ef04e..8ebc2b6d079 100644 --- a/test/DebugInfo/inout.swift +++ b/test/DebugInfo/inout.swift @@ -38,12 +38,13 @@ func modifyFooHeap(_ a: inout Int64, // Inout reference type. // FOO-CHECK: define {{.*}}@"$s5inout9modifyFooyys5Int64Vz_SftF" // FOO-CHECK: call void @llvm.dbg.declare(metadata %Ts5Int64V** % -// FOO-CHECK-SAME: metadata ![[U:[0-9]+]], metadata !DIExpression(DW_OP_deref)) +// FOO-CHECK-SAME: metadata ![[U:[0-9]+]], metadata !DIExpression(DW_OP_deref)) func modifyFoo(_ u: inout Int64, -// FOO-CHECK-DAG: !DILocalVariable(name: "v", arg: 2{{.*}} line: [[@LINE+3]],{{.*}} type: ![[MYFLOAT:[0-9]+]] - // FOO-CHECK-DAG: [[U]] = !DILocalVariable(name: "u", arg: 1{{.*}} line: [[@LINE-2]],{{.*}} type: ![[RINT:[0-9]+]] - // FOO-CHECK-DAG: ![[RINT]] = !DICompositeType({{.*}}identifier: "$ss5Int64VD" - _ v: MyFloat) +// FOO-CHECK-DAG: !DILocalVariable(name: "v", arg: 2{{.*}} line: [[@LINE+3]],{{.*}} type: ![[LET_MYFLOAT:[0-9]+]] +// FOO-CHECK-DAG: [[U]] = !DILocalVariable(name: "u", arg: 1,{{.*}} line: [[@LINE-2]],{{.*}} type: ![[RINT:[0-9]+]] +// FOO-CHECK-DAG: ![[RINT]] = !DICompositeType({{.*}}identifier: "$ss5Int64VD" + _ v: MyFloat) +// FOO-CHECK-DAG: ![[LET_MYFLOAT]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[MYFLOAT:[0-9]+]]) // FOO-CHECK-DAG: ![[MYFLOAT]] = !DIDerivedType(tag: DW_TAG_typedef, name: "$s5inout7MyFloataD",{{.*}} baseType: ![[FLOAT:[0-9]+]] // FOO-CHECK-DAG: ![[FLOAT]] = !DICompositeType({{.*}}identifier: "$sSfD" { diff --git a/test/DebugInfo/linetable-cleanups.swift b/test/DebugInfo/linetable-cleanups.swift index 6410dbf91c1..25e343f2c56 100644 --- a/test/DebugInfo/linetable-cleanups.swift +++ b/test/DebugInfo/linetable-cleanups.swift @@ -19,7 +19,7 @@ func main() { markUsed("Done with the for loop") // CHECK: call {{.*}}void @"$s4main8markUsedyyxlF" // CHECK: br label -// CHECK: { typealias A = A // this is OK now -- the underlying type is the generic parameter 'A' typealias B = B // expected-error {{type alias 'B' references itself}} - // expected-note@-1 {{type declared here}} } // Infinite recursion when using fully-qualified associatedtype name that has not been defined with typealias diff --git a/test/Sema/diag_typealias.swift b/test/Sema/diag_typealias.swift index 0ad55c3870d..ac741594ba0 100644 --- a/test/Sema/diag_typealias.swift +++ b/test/Sema/diag_typealias.swift @@ -3,4 +3,3 @@ struct S {} typealias S = S // expected-error {{type alias 'S' references itself}} -// expected-note@-1{{type declared here}} diff --git a/test/Sema/exhaustive_switch.swift b/test/Sema/exhaustive_switch.swift index 871ca1c43b4..6495685934c 100644 --- a/test/Sema/exhaustive_switch.swift +++ b/test/Sema/exhaustive_switch.swift @@ -1196,13 +1196,13 @@ enum Z { func sr11160_extra() { switch Z.z1(a: 1) { // expected-error {{switch must be exhaustive}} - // expected-note@-1 {{add missing case: '.z1(let a)'}} + // expected-note@-1 {{add missing case: '.z1(a: let a)'}} case .z2(_, _): () case .z3(_): () } switch Z.z1(a: 1) { // expected-error {{switch must be exhaustive}} - // expected-note@-1 {{add missing case: '.z2(let a, let b)'}} + // expected-note@-1 {{add missing case: '.z2(a: let a, b: let b)'}} case .z1(_): () case .z3(_): () } diff --git a/test/Serialization/Inputs/multi-file-subclass-generic-instantiation-extension.swift b/test/Serialization/Inputs/multi-file-subclass-generic-instantiation-extension.swift new file mode 100644 index 00000000000..e8cf56ac25e --- /dev/null +++ b/test/Serialization/Inputs/multi-file-subclass-generic-instantiation-extension.swift @@ -0,0 +1,3 @@ +extension Subclass { + struct MemberTypeFromOtherFile {} +} diff --git a/test/Serialization/Recovery/types-5-to-4.swift b/test/Serialization/Recovery/types-5-to-4.swift index a3116fcfa0c..c5061fd5838 100644 --- a/test/Serialization/Recovery/types-5-to-4.swift +++ b/test/Serialization/Recovery/types-5-to-4.swift @@ -16,8 +16,8 @@ import Lib func requiresConformance(_: B_RequiresConformance) {} func requiresConformance(_: B_RequiresConformance) {} -class Sub: Base {} // expected-error {{cannot inherit from class 'Base' (compiled with Swift 5.1) because it has overridable members that could not be loaded in Swift 4.1.50}} -class Impl: Proto {} // expected-error {{type 'Impl' cannot conform to protocol 'Proto' (compiled with Swift 5.1) because it has requirements that could not be loaded in Swift 4.1.50}} +class Sub: Base {} // expected-error {{cannot inherit from class 'Base' (compiled with Swift 5.1.1) because it has overridable members that could not be loaded in Swift 4.1.50}} +class Impl: Proto {} // expected-error {{type 'Impl' cannot conform to protocol 'Proto' (compiled with Swift 5.1.1) because it has requirements that could not be loaded in Swift 4.1.50}} #else // TEST diff --git a/test/Serialization/multi-file-subclass-generic-instantiation.swift b/test/Serialization/multi-file-subclass-generic-instantiation.swift new file mode 100644 index 00000000000..d425db7d2d9 --- /dev/null +++ b/test/Serialization/multi-file-subclass-generic-instantiation.swift @@ -0,0 +1,8 @@ +// RUN: %empty-directory(%t) + +// RUN: %target-build-swift -emit-module -o %t/Module.swiftmodule %s %S/Inputs/multi-file-subclass-generic-instantiation-extension.swift + +// https://bugs.swift.org/browse/SR-11495 + +class Superclass {} +class Subclass: Superclass {} diff --git a/test/SourceKit/Misc/compiler_version.swift b/test/SourceKit/Misc/compiler_version.swift index cfb1899027f..1db7358ad23 100644 --- a/test/SourceKit/Misc/compiler_version.swift +++ b/test/SourceKit/Misc/compiler_version.swift @@ -2,4 +2,4 @@ // CHECK: key.version_major: 5 // CHECK: key.version_minor: 1 -// CHECK: key.version_patch: 0 +// CHECK: key.version_patch: 1 diff --git a/test/Syntax/Outputs/round_trip_invalid.swift.withkinds b/test/Syntax/Outputs/round_trip_invalid.swift.withkinds index 20da5f46d97..648fe369882 100644 --- a/test/Syntax/Outputs/round_trip_invalid.swift.withkinds +++ b/test/Syntax/Outputs/round_trip_invalid.swift.withkinds @@ -9,7 +9,7 @@ // RUN: %swift-syntax-test -deserialize-raw-tree -input-source-filename %t.dump -output-filename %t // RUN: diff -u %s %t -let strings: [Strin[g]? +let strings: [Strin[g]? // Function body without closing brace token. func foo() { diff --git a/test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds b/test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds index 680d7b2d4ca..9129943fdf3 100644 --- a/test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds +++ b/test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds @@ -142,7 +142,10 @@ typealias G = (a x: = () rethrows -> () typealias I = (A & B<C>) -> C & D typealias J = inout @autoclosure () -> Int -typealias K = (@invalidAttr Int, inout Int, __shared Int, __owned Int) -> () +typealias K = (@invalidAttr Int, inout Int, __shared Int, __owned Int) -> () +typealias L = (inout Int) -> Int +typealias M = (inout arg: Int) -> Int +typealias N = (inout _ arg: @objc Int) -> Int @objc private typealias T<a,b> = Int @objc private typealias T<a,b> diff --git a/test/Syntax/round_trip_misc.swift b/test/Syntax/round_trip_misc.swift index 78b0c0a3ae8..faec3efc360 100644 --- a/test/Syntax/round_trip_misc.swift +++ b/test/Syntax/round_trip_misc.swift @@ -28,6 +28,9 @@ do { do { typealias Alias = A & B & C.D<> } +do { + typealias boo bar = Int +} // Orphan '}' at top level } diff --git a/test/Syntax/round_trip_parse_gen.swift b/test/Syntax/round_trip_parse_gen.swift index 36f0f67b30c..69b03ea130c 100644 --- a/test/Syntax/round_trip_parse_gen.swift +++ b/test/Syntax/round_trip_parse_gen.swift @@ -143,6 +143,9 @@ typealias H = () rethrows -> () typealias I = (A & B) -> C & D typealias J = inout @autoclosure () -> Int typealias K = (@invalidAttr Int, inout Int, __shared Int, __owned Int) -> () +typealias L = (inout Int) -> Int +typealias M = (inout arg: Int) -> Int +typealias N = (inout _ arg: @objc Int) -> Int @objc private typealias T = Int @objc private typealias T diff --git a/test/Syntax/serialize_tupletype.swift.result b/test/Syntax/serialize_tupletype.swift.result index c186b51c93d..fd4b66ff361 100644 --- a/test/Syntax/serialize_tupletype.swift.result +++ b/test/Syntax/serialize_tupletype.swift.result @@ -1,23 +1,23 @@ { - "id": 39, + "id": 23, "kind": "SourceFile", "layout": [ { - "id": 38, + "id": 22, "kind": "CodeBlockItemList", "layout": [ { - "id": 36, + "id": 20, "kind": "CodeBlockItem", "layout": [ { - "id": 35, + "id": 19, "kind": "TypealiasDecl", "layout": [ null, null, { - "id": 33, + "id": 17, "tokenKind": { "kind": "kw_typealias" }, @@ -48,7 +48,7 @@ "presence": "Present" }, { - "id": 34, + "id": 18, "tokenKind": { "kind": "identifier", "text": "x" @@ -64,7 +64,7 @@ }, null, { - "id": 32, + "id": 16, "kind": "TypeInitializerClause", "layout": [ { @@ -82,11 +82,11 @@ "presence": "Present" }, { - "id": 31, + "id": 15, "kind": "TupleType", "layout": [ { - "id": 18, + "id": 2, "tokenKind": { "kind": "l_paren" }, @@ -95,16 +95,16 @@ "presence": "Present" }, { - "id": 29, + "id": 13, "kind": "TupleTypeElementList", "layout": [ { - "id": 24, + "id": 8, "kind": "TupleTypeElement", "layout": [ null, { - "id": 19, + "id": 3, "tokenKind": { "kind": "identifier", "text": "b" @@ -115,7 +115,7 @@ }, null, { - "id": 20, + "id": 4, "tokenKind": { "kind": "colon" }, @@ -129,11 +129,11 @@ "presence": "Present" }, { - "id": 22, + "id": 6, "kind": "SimpleTypeIdentifier", "layout": [ { - "id": 21, + "id": 5, "tokenKind": { "kind": "identifier", "text": "Int" @@ -149,7 +149,7 @@ null, null, { - "id": 23, + "id": 7, "tokenKind": { "kind": "comma" }, @@ -166,12 +166,12 @@ "presence": "Present" }, { - "id": 28, + "id": 12, "kind": "TupleTypeElement", "layout": [ null, { - "id": 25, + "id": 9, "tokenKind": { "kind": "kw__" }, @@ -181,7 +181,7 @@ }, null, { - "id": 20, + "id": 4, "tokenKind": { "kind": "colon" }, @@ -195,11 +195,11 @@ "presence": "Present" }, { - "id": 27, + "id": 11, "kind": "SimpleTypeIdentifier", "layout": [ { - "id": 26, + "id": 10, "tokenKind": { "kind": "identifier", "text": "String" @@ -222,7 +222,7 @@ "presence": "Present" }, { - "id": 30, + "id": 14, "tokenKind": { "kind": "r_paren" }, @@ -249,7 +249,7 @@ "presence": "Present" }, { - "id": 37, + "id": 21, "tokenKind": { "kind": "eof", "text": "" diff --git a/test/Syntax/syntax_diagnostics.swift b/test/Syntax/syntax_diagnostics.swift index e97652902e6..5e49009b1d6 100644 --- a/test/Syntax/syntax_diagnostics.swift +++ b/test/Syntax/syntax_diagnostics.swift @@ -1,3 +1,3 @@ // RUN: %target-swift-frontend -emit-syntax -primary-file %s -verify -typealias Inner: Foo // expected-error{{unknown declaration syntax exists in the source}} expected-error{{expected '=' in type alias declaration}} +typealias Inner: Foo // expected-error{{expected '=' in type alias declaration}} diff --git a/test/TBD/abi-version.swift b/test/TBD/abi-version.swift index 60ec951b802..7795d9d588f 100644 --- a/test/TBD/abi-version.swift +++ b/test/TBD/abi-version.swift @@ -1,3 +1,4 @@ +// REQUIRES: VENDOR=apple // RUN: %empty-directory(%t) // This test ensures that we see the same Swift ABI Version flag in the LLVM IR diff --git a/test/TBD/app-extension.swift b/test/TBD/app-extension.swift index 83067882ae4..3e8708bedae 100644 --- a/test/TBD/app-extension.swift +++ b/test/TBD/app-extension.swift @@ -1,3 +1,4 @@ +// REQUIRES: VENDOR=apple // RUN: %empty-directory(%t) // RUN: %target-swift-frontend -typecheck %s -application-extension -emit-tbd -emit-tbd-path %t/safe.tbd // RUN: %target-swift-frontend -typecheck %s -emit-tbd -emit-tbd-path %t/not-safe.tbd diff --git a/test/TBD/class.swift b/test/TBD/class.swift index 91ac017be58..507412677f7 100644 --- a/test/TBD/class.swift +++ b/test/TBD/class.swift @@ -1,3 +1,4 @@ +// REQUIRES: VENDOR=apple // RUN: %target-swift-frontend -emit-ir -o/dev/null -parse-as-library -module-name test -validate-tbd-against-ir=missing %s // RUN: %target-swift-frontend -enable-library-evolution -emit-ir -o/dev/null -parse-as-library -module-name test -validate-tbd-against-ir=missing %s // RUN: %target-swift-frontend -emit-ir -o/dev/null -parse-as-library -module-name test -validate-tbd-against-ir=missing %s -enable-testing diff --git a/test/TBD/dylib-version.swift b/test/TBD/dylib-version.swift index 4df259ba9a6..eb5fb611a89 100644 --- a/test/TBD/dylib-version.swift +++ b/test/TBD/dylib-version.swift @@ -1,3 +1,4 @@ +// REQUIRES: VENDOR=apple // RUN: %empty-directory(%t) // RUN: %target-swift-frontend -emit-ir -o /dev/null %s -tbd-current-version 2.0.3 -tbd-compatibility-version 1.7 -emit-tbd -emit-tbd-path %t/both_provided.tbd // RUN: %target-swift-frontend -emit-ir -o /dev/null %s -tbd-current-version 2.0 -emit-tbd -emit-tbd-path %t/only_current_provided.tbd diff --git a/test/TBD/enum.swift b/test/TBD/enum.swift index 8e392977d2f..2b9545123f9 100644 --- a/test/TBD/enum.swift +++ b/test/TBD/enum.swift @@ -1,3 +1,4 @@ +// REQUIRES: VENDOR=apple // RUN: %target-swift-frontend -emit-ir -o/dev/null -parse-as-library -module-name test -validate-tbd-against-ir=missing %s // RUN: %target-swift-frontend -enable-library-evolution -emit-ir -o/dev/null -parse-as-library -module-name test -validate-tbd-against-ir=missing %s // RUN: %target-swift-frontend -emit-ir -o/dev/null -parse-as-library -module-name test -validate-tbd-against-ir=missing %s -O @@ -66,4 +67,4 @@ public enum PublicEnumDefaultArgument { internal enum InternalEnumDefaultArgument { case first(_: Int = 123) -} \ No newline at end of file +} diff --git a/test/TBD/function.swift b/test/TBD/function.swift index 9e63cb01b7c..5a04fefd191 100644 --- a/test/TBD/function.swift +++ b/test/TBD/function.swift @@ -1,3 +1,4 @@ +// REQUIRES: VENDOR=apple // RUN: %target-swift-frontend -emit-ir -o/dev/null -parse-as-library -module-name test -validate-tbd-against-ir=all %s // RUN: %target-swift-frontend -emit-ir -o/dev/null -parse-as-library -module-name test -validate-tbd-against-ir=all %s -enable-testing // RUN: %target-swift-frontend -emit-ir -o/dev/null -parse-as-library -module-name test -validate-tbd-against-ir=all %s -O diff --git a/test/TBD/global.swift b/test/TBD/global.swift index f4a33c4cf34..83e1a7a18d8 100644 --- a/test/TBD/global.swift +++ b/test/TBD/global.swift @@ -1,3 +1,4 @@ +// REQUIRES: VENDOR=apple // RUN: %target-swift-frontend -emit-ir -o/dev/null -parse-as-library -module-name test -validate-tbd-against-ir=all %s // RUN: %target-swift-frontend -emit-ir -o/dev/null -parse-as-library -module-name test -validate-tbd-against-ir=all -enable-library-evolution %s // RUN: %target-swift-frontend -emit-ir -o/dev/null -parse-as-library -module-name test -validate-tbd-against-ir=all %s -enable-testing diff --git a/test/TBD/installapi-flag.swift b/test/TBD/installapi-flag.swift index cf6b04e8d71..685b5cfb6d1 100644 --- a/test/TBD/installapi-flag.swift +++ b/test/TBD/installapi-flag.swift @@ -1,3 +1,4 @@ +// REQUIRES: VENDOR=apple // RUN: %empty-directory(%t) // 1. Emit two TBDs, one with -tbd-is-installapi set, and one without diff --git a/test/TBD/main.swift b/test/TBD/main.swift index 02f5c3ccfa5..bb0deb9e6dc 100644 --- a/test/TBD/main.swift +++ b/test/TBD/main.swift @@ -1,3 +1,4 @@ +// REQUIRES: VENDOR=apple // RUN: %target-swift-frontend -emit-ir -o/dev/null -module-name test -validate-tbd-against-ir=all %s // RUN: %target-swift-frontend -emit-ir -o/dev/null -module-name test -validate-tbd-against-ir=all %s -O diff --git a/test/TBD/opaque_result_type.swift b/test/TBD/opaque_result_type.swift index b2e9445abc4..33111ab4835 100644 --- a/test/TBD/opaque_result_type.swift +++ b/test/TBD/opaque_result_type.swift @@ -1,3 +1,4 @@ +// REQUIRES: VENDOR=apple // RUN: %empty-directory(%t) // RUN: %target-swift-frontend -disable-availability-checking -emit-ir -o /dev/null -module-name opaque_result_type -emit-tbd -emit-tbd-path %t/opaque_result_type.tbd %s -validate-tbd-against-ir=missing diff --git a/test/TBD/output-path-deduction.swift b/test/TBD/output-path-deduction.swift index ed8e557f433..597a4a1590c 100644 --- a/test/TBD/output-path-deduction.swift +++ b/test/TBD/output-path-deduction.swift @@ -1,3 +1,4 @@ +// REQUIRES: VENDOR=apple // RUN: %empty-directory(%t) // RUN: cd %t; %target-build-swift -emit-module -emit-tbd %s diff --git a/test/TBD/protocol.swift b/test/TBD/protocol.swift index db56fa69385..8ba2ac64ce8 100644 --- a/test/TBD/protocol.swift +++ b/test/TBD/protocol.swift @@ -1,3 +1,4 @@ +// REQUIRES: VENDOR=apple // RUN: %target-swift-frontend -emit-ir -o/dev/null -parse-as-library -module-name test -validate-tbd-against-ir=missing %s // RUN: %target-swift-frontend -enable-library-evolution -emit-ir -o/dev/null -parse-as-library -module-name test -validate-tbd-against-ir=missing %s // RUN: %target-swift-frontend -emit-ir -o/dev/null -parse-as-library -module-name test -validate-tbd-against-ir=missing %s -enable-testing diff --git a/test/TBD/specialization.swift b/test/TBD/specialization.swift index f26b88872e5..85ca083a4d2 100644 --- a/test/TBD/specialization.swift +++ b/test/TBD/specialization.swift @@ -1,3 +1,4 @@ +// REQUIRES: VENDOR=apple // Validate the the specializations actually exist (if they don't then we're not // validating that they end up with the correct linkages): // RUN: %target-swift-frontend -emit-sil -o- -O -validate-tbd-against-ir=none %s | %FileCheck %s diff --git a/test/TBD/struct.swift b/test/TBD/struct.swift index 36f17a050b8..ef17e423af4 100644 --- a/test/TBD/struct.swift +++ b/test/TBD/struct.swift @@ -1,3 +1,4 @@ +// REQUIRES: VENDOR=apple // RUN: %target-swift-frontend -emit-ir -o/dev/null -parse-as-library -module-name test -validate-tbd-against-ir=all %s // RUN: %target-swift-frontend -emit-ir -o/dev/null -parse-as-library -module-name test -validate-tbd-against-ir=all %s -enable-library-evolution // RUN: %target-swift-frontend -emit-ir -o/dev/null -parse-as-library -module-name test -validate-tbd-against-ir=all %s -enable-testing diff --git a/test/attr/attr_objc.swift b/test/attr/attr_objc.swift index ac143b2aa73..fde589532e0 100644 --- a/test/attr/attr_objc.swift +++ b/test/attr/attr_objc.swift @@ -123,7 +123,7 @@ func subject_genericFunc(t: T) { func subject_instanceFunc() {} } -func subject_funcParam(a: @objc Int) { // expected-error {{attribute can only be applied to declarations, not types}} {{1-1=@objc }} {{27-33=}} +func subject_funcParam(a: @objc Int) { // expected-error {{attribute can only be applied to declarations, not types}} } @objc // expected-error {{'@objc' attribute cannot be applied to this declaration}} {{1-7=}} @@ -849,17 +849,21 @@ class infer_instanceVar1 { var observingAccessorsVar1: Int { // CHECK: @_hasStorage @objc var observingAccessorsVar1: Int { willSet {} - // CHECK-NEXT: {{^}} @objc get + // CHECK-NEXT: {{^}} @objc get { + // CHECK-NEXT: return + // CHECK-NEXT: } didSet {} - // CHECK-NEXT: {{^}} @objc set + // CHECK-NEXT: {{^}} @objc set { } @objc var observingAccessorsVar1_: Int { // CHECK: {{^}} @objc @_hasStorage var observingAccessorsVar1_: Int { willSet {} - // CHECK-NEXT: {{^}} @objc get + // CHECK-NEXT: {{^}} @objc get { + // CHECK-NEXT: return + // CHECK-NEXT: } didSet {} - // CHECK-NEXT: {{^}} @objc set + // CHECK-NEXT: {{^}} @objc set { } diff --git a/test/attr/attributes.swift b/test/attr/attributes.swift index 2eb337ef5e7..5dae546a0a2 100644 --- a/test/attr/attributes.swift +++ b/test/attr/attributes.swift @@ -56,7 +56,7 @@ func zim() {} func zung(_: T) {} @_transparent // expected-error{{'@_transparent' attribute cannot be applied to stored properties}} {{1-15=}} var zippity : Int -func zoom(x: @_transparent () -> ()) { } // expected-error{{attribute can only be applied to declarations, not types}} {{1-1=@_transparent }} {{14-28=}} +func zoom(x: @_transparent () -> ()) { } // expected-error{{attribute can only be applied to declarations, not types}} protocol ProtoWithTransparent { @_transparent// expected-error{{'@_transparent' attribute is not supported on declarations within protocols}} {{3-16=}} func transInProto() diff --git a/test/decl/enum/Inputs/objc_enum_multi_file_helper.swift b/test/decl/enum/Inputs/objc_enum_multi_file_helper.swift index ed20033db32..788936aa40a 100644 --- a/test/decl/enum/Inputs/objc_enum_multi_file_helper.swift +++ b/test/decl/enum/Inputs/objc_enum_multi_file_helper.swift @@ -1,6 +1,6 @@ func useEnum(_ x: TheEnum) { switch x { - case A: + case .A: print("a!") default: break diff --git a/test/decl/enum/objc_enum_multi_file.swift b/test/decl/enum/objc_enum_multi_file.swift index bb763e0d09f..aee48f148a8 100644 --- a/test/decl/enum/objc_enum_multi_file.swift +++ b/test/decl/enum/objc_enum_multi_file.swift @@ -1,8 +1,8 @@ -// RUN: not %target-swift-frontend -module-name main %s -primary-file %S/Inputs/objc_enum_multi_file_helper.swift -typecheck -D NO_RAW_TYPE 2>&1 | %FileCheck -check-prefix=NO_RAW_TYPE %s -// RUN: not %target-swift-frontend -module-name main %s -primary-file %S/Inputs/objc_enum_multi_file_helper.swift -typecheck -D BAD_RAW_TYPE 2>&1 | %FileCheck -check-prefix=BAD_RAW_TYPE %s -// RUN: not %target-swift-frontend -module-name main %s -primary-file %S/Inputs/objc_enum_multi_file_helper.swift -typecheck -D NON_INT_RAW_TYPE 2>&1 | %FileCheck -check-prefix=NON_INT_RAW_TYPE %s -// RUN: not %target-swift-frontend -module-name main %s -primary-file %S/Inputs/objc_enum_multi_file_helper.swift -typecheck -D NO_CASES 2>&1 | %FileCheck -check-prefix=NO_CASES %s -// RUN: not %target-swift-frontend -module-name main %s -primary-file %S/Inputs/objc_enum_multi_file_helper.swift -typecheck -D DUPLICATE_CASES 2>&1 | %FileCheck -check-prefix=DUPLICATE_CASES %s +// RUN: not %target-swift-frontend -module-name main %s -primary-file %S/Inputs/objc_enum_multi_file_helper.swift -emit-ir -D NO_RAW_TYPE 2>&1 | %FileCheck -check-prefix=NO_RAW_TYPE %s +// RUN: not %target-swift-frontend -module-name main %s -primary-file %S/Inputs/objc_enum_multi_file_helper.swift -emit-ir -D BAD_RAW_TYPE 2>&1 | %FileCheck -check-prefix=BAD_RAW_TYPE %s +// RUN: not %target-swift-frontend -module-name main %s -primary-file %S/Inputs/objc_enum_multi_file_helper.swift -emit-ir -D NON_INT_RAW_TYPE 2>&1 | %FileCheck -check-prefix=NON_INT_RAW_TYPE %s +// RUN: not %target-swift-frontend -module-name main %s -primary-file %S/Inputs/objc_enum_multi_file_helper.swift -emit-ir -D NO_CASES 2>&1 | %FileCheck -check-prefix=NO_CASES %s +// RUN: not %target-swift-frontend -module-name main %s -primary-file %S/Inputs/objc_enum_multi_file_helper.swift -emit-ir -D DUPLICATE_CASES 2>&1 | %FileCheck -check-prefix=DUPLICATE_CASES %s // Note that the *other* file is the primary file in this test! #if NO_RAW_TYPE diff --git a/test/decl/func/functions.swift b/test/decl/func/functions.swift index 4ac2fca0fe1..e40866b898b 100644 --- a/test/decl/func/functions.swift +++ b/test/decl/func/functions.swift @@ -129,7 +129,7 @@ func rdar16786220(inout let c: Int) -> () { // expected-warning {{'let' in this c = 42 } -func multipleSpecifiers(a: inout __owned Int) {} // expected-error {{parameter must not have multiple '__owned', 'inout', or '__shared' specifiers}} {{28-34=}} +func multipleSpecifiers(a: inout __owned Int) {} // expected-error {{parameter must not have multiple '__owned', 'inout', or '__shared' specifiers}} {{34-42=}} // ambiguous operator emits same candidate multiple times infix operator !!! diff --git a/test/decl/init/basic_init.swift b/test/decl/init/basic_init.swift index e03115804f5..b45c3116211 100644 --- a/test/decl/init/basic_init.swift +++ b/test/decl/init/basic_init.swift @@ -11,7 +11,6 @@ class C { } typealias t = t // expected-error {{type alias 't' references itself}} -// expected-note@-1{{type declared here}} extension Foo { convenience init() {} // expected-error{{invalid redeclaration of synthesized 'init()'}} diff --git a/test/decl/typealias/generic.swift b/test/decl/typealias/generic.swift index c67e9831154..73bef2c6f4d 100644 --- a/test/decl/typealias/generic.swift +++ b/test/decl/typealias/generic.swift @@ -32,7 +32,7 @@ typealias DS = MyType typealias BadA = MyType // expected-error {{type 'T' constrained to non-protocol, non-class type 'Int'}} -typealias BadB = MyType // expected-error {{associated types must not have a generic parameter list}} +typealias BadB = MyType // expected-error {{'where' clause next to generic parameters is obsolete, must be written following the declaration's type}} {{17-32=}} {{53-53= where T == Int}} // expected-error@-1 {{same-type requirement makes generic parameter 'T' non-generic}} typealias BadC = MyType // expected-error {{definition conflicts with previous value}} @@ -303,9 +303,9 @@ func takesSugaredType2(m: GenericClass.TA) { extension A {} extension A {} // expected-error {{generic type 'A' specialized with too few type parameters (got 1, but expected 2)}} -extension A {} // expected-error {{constrained extension must be declared on the unspecialized generic type 'A' with constraints specified by a 'where' clause}} -extension C {} // expected-error {{constrained extension must be declared on the unspecialized generic type 'C' with constraints specified by a 'where' clause}} -extension C {} // expected-error {{constrained extension must be declared on the unspecialized generic type 'C' with constraints specified by a 'where' clause}} +extension A {} // expected-error {{constrained extension must be declared on the unspecialized generic type 'MyType' with constraints specified by a 'where' clause}} +extension C {} // expected-error {{use of undeclared type 'T'}} +extension C {} // expected-error {{constrained extension must be declared on the unspecialized generic type 'MyType' with constraints specified by a 'where' clause}} protocol ErrorQ { diff --git a/test/decl/typealias/protocol.swift b/test/decl/typealias/protocol.swift index f243926c820..882edcad1be 100644 --- a/test/decl/typealias/protocol.swift +++ b/test/decl/typealias/protocol.swift @@ -145,14 +145,12 @@ protocol P3 { // Test for not crashing on recursive aliases protocol Circular { typealias Y = Self.Y // expected-error {{type alias 'Y' references itself}} - // expected-note@-1 {{type declared here}} typealias Y2 = Y2 // expected-error {{type alias 'Y2' references itself}} - // expected-note@-1 {{type declared here}} - typealias Y3 = Y4 // expected-note {{type declared here}} + typealias Y3 = Y4 // expected-error {{type alias 'Y3' references itself}} - typealias Y4 = Y3 // expected-error {{type alias 'Y3' references itself}} + typealias Y4 = Y3 // expected-note {{through reference here}} } // Qualified and unqualified references to protocol typealiases from concrete type diff --git a/test/expr/unary/keypath/keypath.swift b/test/expr/unary/keypath/keypath.swift index f8d3a8ea929..9310e7a573f 100644 --- a/test/expr/unary/keypath/keypath.swift +++ b/test/expr/unary/keypath/keypath.swift @@ -504,8 +504,11 @@ func testLabeledSubscript() { let k = \AA.[labeled: 0] // TODO: These ought to work without errors. - let _ = \AA.[keyPath: k] // expected-error{{}} - let _ = \AA.[keyPath: \AA.[labeled: 0]] // expected-error{{}} + let _ = \AA.[keyPath: k] // expected-error {{incorrect argument label in call (have 'keyPath:', expected 'labeled:')}} + // expected-error@-1 {{cannot convert value of type 'KeyPath' to expected argument type 'Int'}} + + let _ = \AA.[keyPath: \AA.[labeled: 0]] // expected-error {{incorrect argument label in call (have 'keyPath:', expected 'labeled:')}} + // expected-error@-1 {{cannot convert value of type 'KeyPath' to expected argument type 'Int'}} } func testInvalidKeyPathComponents() { @@ -830,6 +833,34 @@ func test_keypath_inference_with_optionals() { } } +func sr11562() { + struct S1 { + subscript(x x: Int) -> Int { x } + } + + _ = \S1.[5] // expected-error {{missing argument label 'x:' in call}} {{12-12=x: }} + + struct S2 { + subscript(x x: Int) -> Int { x } // expected-note {{incorrect labels for candidate (have: '(_:)', expected: '(x:)')}} + subscript(y y: Int) -> Int { y } // expected-note {{incorrect labels for candidate (have: '(_:)', expected: '(y:)')}} + } + + _ = \S2.[5] // expected-error {{no exact matches in call to subscript}} + + struct S3 { + subscript(x x: Int, y y: Int) -> Int { x } + } + + _ = \S3.[y: 5, x: 5] // expected-error {{argument 'x' must precede argument 'y'}} + + struct S4 { + subscript(x: (Int, Int)) -> Int { x.0 } + } + + _ = \S4.[1, 4] // expected-error {{subscript expects a single parameter of type '(Int, Int)'}} {{12-12=(}} {{16-16=)}} + // expected-error@-1 {{subscript index of type '(Int, Int)' in a key path must be Hashable}} +} + func testSyntaxErrors() { // expected-note{{}} _ = \. ; // expected-error{{expected member name following '.'}} _ = \.a ; diff --git a/test/lit.cfg b/test/lit.cfg index 661ff2c041a..1602e8c98ba 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -499,6 +499,7 @@ for target in config.llvm_code_generators: config.available_features.add("CPU=" + run_cpu) config.available_features.add("OS=" + run_os) config.available_features.add("PTRSIZE=" + run_ptrsize) +config.available_features.add("VENDOR=" + run_vendor) config.available_features.add("SWIFT_VERSION=" + swift_version) diff --git a/test/multifile/synthesized-accessors/invalid/Inputs/library.swift b/test/multifile/synthesized-accessors/invalid/Inputs/library.swift new file mode 100644 index 00000000000..a68cc0b1487 --- /dev/null +++ b/test/multifile/synthesized-accessors/invalid/Inputs/library.swift @@ -0,0 +1,4 @@ +public struct SomeStruct { + var x: InvalidType +} + diff --git a/test/multifile/synthesized-accessors/invalid/main.swift b/test/multifile/synthesized-accessors/invalid/main.swift new file mode 100644 index 00000000000..51bb4f7bbc5 --- /dev/null +++ b/test/multifile/synthesized-accessors/invalid/main.swift @@ -0,0 +1,11 @@ +// RUN: not %target-swift-frontend -emit-silgen %S/Inputs/library.swift -primary-file %S/main.swift + +public func f(x: SomeStruct) {} + +public protocol P { + @_borrowed var x: Int { get set } +} + +public struct HasAccessors : P { + public var x: Int = 123 +} diff --git a/test/reproducible-builds/swiftc-emit-tbd.swift b/test/reproducible-builds/swiftc-emit-tbd.swift index 41621128381..7002d002882 100644 --- a/test/reproducible-builds/swiftc-emit-tbd.swift +++ b/test/reproducible-builds/swiftc-emit-tbd.swift @@ -1,3 +1,4 @@ +// REQUIRES: VENDOR=apple // RUN: %empty-directory(%t) // RUN: %target-build-swift -O -g -module-name foo %s -emit-tbd-path %t/run-1.tbd -force-single-frontend-invocation // RUN: %target-build-swift -O -g -module-name foo %s -emit-tbd-path %t/run-2.tbd -force-single-frontend-invocation diff --git a/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp b/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp index 230f055d450..187755c143c 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp @@ -950,7 +950,6 @@ ASTUnitRef ASTProducer::createASTUnit( if (fileSystem != llvm::vfs::getRealFileSystem()) { CompIns.getSourceMgr().setFileSystem(fileSystem); - Invocation.getClangImporterOptions().ForceUseSwiftVirtualFileSystem = true; } if (CompIns.setup(Invocation)) { diff --git a/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp b/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp index a08b8945ae4..4ab794506e2 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp @@ -200,7 +200,6 @@ static bool swiftCodeCompleteImpl( if (FileSystem != llvm::vfs::getRealFileSystem()) { CI.getSourceMgr().setFileSystem(FileSystem); - Invocation.getClangImporterOptions().ForceUseSwiftVirtualFileSystem = true; } if (CI.setup(Invocation)) { diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt index 8e326d0aea3..10e926b4e67 100644 --- a/tools/driver/CMakeLists.txt +++ b/tools/driver/CMakeLists.txt @@ -34,7 +34,7 @@ add_swift_tool_symlink(swift-indent swift editor-integration) # If building as part of clang, make sure the headers are installed. if(NOT SWIFT_BUILT_STANDALONE) - add_dependencies(swift clang-headers) + add_dependencies(swift clang-resource-headers) endif() add_dependencies(compiler swift) diff --git a/tools/driver/autolink_extract_main.cpp b/tools/driver/autolink_extract_main.cpp index 798c768fa50..f805714c30e 100644 --- a/tools/driver/autolink_extract_main.cpp +++ b/tools/driver/autolink_extract_main.cpp @@ -106,26 +106,38 @@ public: /// Look inside the object file 'ObjectFile' and append any linker flags found in /// its ".swift1_autolink_entries" section to 'LinkerFlags'. -static void +/// Return 'true' if there was an error, and 'false' otherwise. +static bool extractLinkerFlagsFromObjectFile(const llvm::object::ObjectFile *ObjectFile, - std::vector &LinkerFlags) { + std::vector &LinkerFlags, + CompilerInstance &Instance) { // Search for the section we hold autolink entries in for (auto &Section : ObjectFile->sections()) { llvm::StringRef SectionName; Section.getName(SectionName); if (SectionName == ".swift1_autolink_entries") { - llvm::StringRef SectionData; - Section.getContents(SectionData); + llvm::Expected SectionData = Section.getContents(); + if (!SectionData) { + std::string message; + { + llvm::raw_string_ostream os(message); + logAllUnhandledErrors(SectionData.takeError(), os, ""); + } + Instance.getDiags().diagnose(SourceLoc(), diag::error_open_input_file, + ObjectFile->getFileName() , message); + return true; + } // entries are null-terminated, so extract them and push them into // the set. llvm::SmallVector SplitFlags; - SectionData.split(SplitFlags, llvm::StringRef("\0", 1), -1, - /*KeepEmpty=*/false); + SectionData->split(SplitFlags, llvm::StringRef("\0", 1), -1, + /*KeepEmpty=*/false); for (const auto &Flag : SplitFlags) LinkerFlags.push_back(Flag); } } + return false; } /// Look inside the binary 'Bin' and append any linker flags found in its @@ -137,8 +149,7 @@ static bool extractLinkerFlags(const llvm::object::Binary *Bin, StringRef BinaryFileName, std::vector &LinkerFlags) { if (auto *ObjectFile = llvm::dyn_cast(Bin)) { - extractLinkerFlagsFromObjectFile(ObjectFile, LinkerFlags); - return false; + return extractLinkerFlagsFromObjectFile(ObjectFile, LinkerFlags, Instance); } else if (auto *Archive = llvm::dyn_cast(Bin)) { llvm::Error Error = llvm::Error::success(); for (const auto &Child : Archive->children(Error)) { diff --git a/tools/lldb-moduleimport-test/lldb-moduleimport-test.cpp b/tools/lldb-moduleimport-test/lldb-moduleimport-test.cpp index 2a6d99bb167..def4356f271 100644 --- a/tools/lldb-moduleimport-test/lldb-moduleimport-test.cpp +++ b/tools/lldb-moduleimport-test/lldb-moduleimport-test.cpp @@ -173,10 +173,15 @@ collectASTModules(llvm::cl::list &InputNames, (ELF && Name == swift::ELFASTSectionName) || (COFF && Name == swift::COFFASTSectionName)) { uint64_t Size = Section.getSize(); - StringRef ContentsReference; - Section.getContents(ContentsReference); + + llvm::Expected ContentsReference = Section.getContents(); + if (!ContentsReference) { + llvm::errs() << "error: " << name << " " + << errorToErrorCode(OF.takeError()).message() << "\n"; + return false; + } char *Module = Alloc.Allocate(Size); - std::memcpy(Module, (void *)ContentsReference.begin(), Size); + std::memcpy(Module, (void *)ContentsReference->begin(), Size); Modules.push_back({Module, Size}); } } diff --git a/tools/swift-reflection-dump/swift-reflection-dump.cpp b/tools/swift-reflection-dump/swift-reflection-dump.cpp index 4a6802ebae1..a70bd1ac602 100644 --- a/tools/swift-reflection-dump/swift-reflection-dump.cpp +++ b/tools/swift-reflection-dump/swift-reflection-dump.cpp @@ -25,7 +25,9 @@ #include "llvm/Object/ELF.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/MachOUniversal.h" +#include "llvm/Object/RelocationResolver.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Error.h" #if defined(_WIN32) #include @@ -80,169 +82,471 @@ template static T unwrap(llvm::Expected value) { exit(EXIT_FAILURE); } -static void reportError(std::error_code EC) { - assert(EC); - llvm::errs() << "swift-reflection-test error: " << EC.message() << ".\n"; - exit(EXIT_FAILURE); -} - -using NativeReflectionContext = - swift::reflection::ReflectionContext>>; - using ReadBytesResult = swift::remote::MemoryReader::ReadBytesResult; -static uint64_t getSectionAddress(SectionRef S) { - // See COFFObjectFile.cpp for the implementation of - // COFFObjectFile::getSectionAddress. The image base address is added - // to all the addresses of the sections, thus the behavior is slightly different from - // the other platforms. - if (auto C = dyn_cast(S.getObject())) - return S.getAddress() - C->getImageBase(); - return S.getAddress(); -} - -static bool needToRelocate(SectionRef S) { - if (!getSectionAddress(S)) - return false; - - if (auto EO = dyn_cast(S.getObject())) { - static const llvm::StringSet<> ELFSectionsList = { - ".data", ".rodata", "swift5_protocols", "swift5_protocol_conformances", - "swift5_typeref", "swift5_reflstr", "swift5_assocty", "swift5_replace", - "swift5_type_metadata", "swift5_fieldmd", "swift5_capture", "swift5_builtin" - }; - StringRef Name; - if (auto EC = S.getName(Name)) - reportError(EC); - return ELFSectionsList.count(Name); - } - - return true; -} - +// Since ObjectMemoryReader maintains ownership of the ObjectFiles and their +// raw data, we can vend ReadBytesResults with no-op destructors. +static void no_op_destructor(const void*) {} class Image { - const ObjectFile *O; - uint64_t VASize; - - struct RelocatedRegion { - uint64_t Start, Size; - const char *Base; +private: + struct Segment { + uint64_t Addr; + StringRef Contents; }; + const ObjectFile *O; + uint64_t HeaderAddress; + std::vector Segments; + struct DynamicRelocation { + StringRef Symbol; + uint64_t Offset; + }; + llvm::DenseMap DynamicRelocations; + + void scanMachO(const MachOObjectFile *O) { + using namespace llvm::MachO; - std::vector RelocatedRegions; - -public: - explicit Image(const ObjectFile *O) : O(O), VASize(O->getData().size()) { - for (SectionRef S : O->sections()) { - if (!needToRelocate(S)) - continue; - StringRef Content; - auto SectionAddr = getSectionAddress(S); - if (SectionAddr) - VASize = std::max(VASize, SectionAddr + S.getSize()); - - if (auto EC = S.getContents(Content)) - reportError(EC); - - auto PhysOffset = (uintptr_t)Content.data() - (uintptr_t)O->getData().data(); - - if (PhysOffset == SectionAddr) { - continue; - } - - RelocatedRegions.push_back(RelocatedRegion{ - SectionAddr, - Content.size(), - Content.data()}); - } - } - - RemoteAddress getStartAddress() const { - return RemoteAddress((uintptr_t)O->getData().data()); - } - - bool isAddressValid(RemoteAddress Addr, uint64_t Size) const { - auto start = getStartAddress().getAddressData(); - return start <= Addr.getAddressData() - && Addr.getAddressData() + Size <= start + VASize; - } - - ReadBytesResult readBytes(RemoteAddress Addr, uint64_t Size) { - if (!isAddressValid(Addr, Size)) - return ReadBytesResult(nullptr, [](const void *) {}); + HeaderAddress = UINT64_MAX; - auto addrValue = Addr.getAddressData(); - auto base = O->getData().data(); - auto offset = addrValue - (uint64_t)base; - for (auto ®ion : RelocatedRegions) { - if (region.Start <= offset && offset < region.Start + region.Size) { - // Read shouldn't need to straddle section boundaries. - if (offset + Size > region.Start + region.Size) - return ReadBytesResult(nullptr, [](const void *) {}); + // Collect the segment preferred vm mappings. + for (const auto &Load : O->load_commands()) { + if (Load.C.cmd == LC_SEGMENT_64) { + auto Seg = O->getSegment64LoadCommand(Load); + if (Seg.filesize == 0) + continue; + + auto contents = O->getData().slice(Seg.fileoff, + Seg.fileoff + Seg.filesize); + + if (contents.empty() || contents.size() != Seg.filesize) + continue; + + Segments.push_back({Seg.vmaddr, contents}); + HeaderAddress = std::min(HeaderAddress, Seg.vmaddr); + } else if (Load.C.cmd == LC_SEGMENT) { + auto Seg = O->getSegmentLoadCommand(Load); + if (Seg.filesize == 0) + continue; + + auto contents = O->getData().slice(Seg.fileoff, + Seg.fileoff + Seg.filesize); + + if (contents.empty() || contents.size() != Seg.filesize) + continue; + + Segments.push_back({Seg.vmaddr, contents}); + HeaderAddress = std::min(HeaderAddress, (uint64_t)Seg.vmaddr); + } + } + + // Walk through the bindings list to collect all the external references + // in the image. + llvm::Error error = llvm::Error::success(); + auto OO = const_cast(O); - offset -= region.Start; - base = region.Base; + for (auto bind : OO->bindTable(error)) { + if (error) { + llvm::consumeError(std::move(error)); break; } + + // The offset from the symbol is stored at the target address. + uint64_t Offset; + auto OffsetContent = getContentsAtAddress(bind.address(), + O->getBytesInAddress()); + if (OffsetContent.empty()) + continue; + + if (O->getBytesInAddress() == 8) { + memcpy(&Offset, OffsetContent.data(), sizeof(Offset)); + } else if (O->getBytesInAddress() == 4) { + uint32_t OffsetValue; + memcpy(&OffsetValue, OffsetContent.data(), sizeof(OffsetValue)); + Offset = OffsetValue; + } else { + assert(false && "unexpected word size?!"); + } + + DynamicRelocations.insert({bind.address(), {bind.symbolName(), Offset}}); + } + if (error) { + llvm::consumeError(std::move(error)); + } + } + + template + void scanELFType(const ELFObjectFile *O) { + using namespace llvm::ELF; + + HeaderAddress = UINT64_MAX; + + auto phdrs = O->getELFFile()->program_headers(); + if (!phdrs) { + llvm::consumeError(phdrs.takeError()); + } + + for (auto &ph : *phdrs) { + if (ph.p_filesz == 0) + continue; + + auto contents = O->getData().slice(ph.p_offset, + ph.p_offset + ph.p_filesz); + if (contents.empty() || contents.size() != ph.p_filesz) + continue; + + Segments.push_back({ph.p_vaddr, contents}); + HeaderAddress = std::min(HeaderAddress, (uint64_t)ph.p_vaddr); + } + + // Collect the dynamic relocations. + auto resolver = getRelocationResolver(*O); + auto resolverSupports = resolver.first; + auto resolve = resolver.second; + + if (!resolverSupports || !resolve) + return; + + auto machine = O->getELFFile()->getHeader()->e_machine; + auto relativeRelocType = getELFRelativeRelocationType(machine); + + for (auto &S : static_cast(O) + ->dynamic_relocation_sections()) { + bool isRela = O->getSection(S.getRawDataRefImpl())->sh_type + == llvm::ELF::SHT_RELA; + + for (const RelocationRef &R : S.relocations()) { + // `getRelocationResolver` doesn't handle RELATIVE relocations, so we + // have to do that ourselves. + if (isRela && R.getType() == relativeRelocType) { + auto rela = O->getRela(R.getRawDataRefImpl()); + DynamicRelocations.insert({R.getOffset(), + {{}, HeaderAddress + rela->r_addend}}); + continue; + } + + if (!resolverSupports(R.getType())) + continue; + auto symbol = R.getSymbol(); + auto name = symbol->getName(); + if (!name) { + llvm::consumeError(name.takeError()); + continue; + } + uint64_t offset = resolve(R, 0, 0); + DynamicRelocations.insert({R.getOffset(), {*name, offset}}); + } + } + } + + void scanELF(const ELFObjectFileBase *O) { + if (auto le32 = dyn_cast>(O)) { + scanELFType(le32); + } else if (auto be32 = dyn_cast>(O)) { + scanELFType(be32); + } else if (auto le64 = dyn_cast>(O)) { + scanELFType(le64); + } else if (auto be64 = dyn_cast>(O)) { + scanELFType(be64); + } else { + return; } - return ReadBytesResult(base + offset, [](const void *) {}); + // FIXME: ReflectionContext tries to read bits of the ELF structure that + // aren't normally mapped by a phdr. Until that's fixed, + // allow access to the whole file 1:1 in address space that isn't otherwise + // mapped. + Segments.push_back({HeaderAddress, O->getData()}); + } + + void scanCOFF(const COFFObjectFile *O) { + HeaderAddress = O->getImageBase(); + + for (auto SectionRef : O->sections()) { + auto Section = O->getCOFFSection(SectionRef); + + if (Section->SizeOfRawData == 0) + continue; + + auto SectionBase = O->getImageBase() + Section->VirtualAddress; + auto SectionContent = + O->getData().slice(Section->PointerToRawData, + Section->PointerToRawData + Section->SizeOfRawData); + if (SectionContent.empty() + || SectionContent.size() != Section->SizeOfRawData) + continue; + + Segments.push_back({SectionBase, SectionContent}); + } + + // FIXME: We need to map the header at least, but how much of it does + // Windows typically map? + Segments.push_back({HeaderAddress, O->getData()}); + } + +public: + explicit Image(const ObjectFile *O) : O(O) { + // Unfortunately llvm doesn't provide a uniform interface for iterating + // loadable segments or dynamic relocations in executable images yet. + if (auto macho = dyn_cast(O)) { + scanMachO(macho); + } else if (auto elf = dyn_cast(O)) { + scanELF(elf); + } else if (auto coff = dyn_cast(O)) { + scanCOFF(coff); + } else { + fputs("unsupported image format\n", stderr); + abort(); + } + } + + unsigned getBytesInAddress() const { + return O->getBytesInAddress(); + } + + uint64_t getStartAddress() const { + return HeaderAddress; + } + + uint64_t getEndAddress() const { + uint64_t max = 0; + for (auto &Segment : Segments) { + max = std::max(max, Segment.Addr + Segment.Contents.size()); + } + return max; + } + + StringRef getContentsAtAddress(uint64_t Addr, uint64_t Size) const { + for (auto &Segment : Segments) { + auto addrInSegment = Segment.Addr <= Addr + && Addr + Size <= Segment.Addr + Segment.Contents.size(); + + if (!addrInSegment) + continue; + + auto offset = Addr - Segment.Addr; + auto result = Segment.Contents.drop_front(offset); + return result; + } + return {}; + } + + RemoteAbsolutePointer + resolvePointer(uint64_t Addr, uint64_t pointerValue) const { + auto found = DynamicRelocations.find(Addr); + RemoteAbsolutePointer result; + if (found == DynamicRelocations.end()) + result = RemoteAbsolutePointer("", pointerValue); + else + result = RemoteAbsolutePointer(found->second.Symbol, + found->second.Offset); + return result; } }; +/// MemoryReader that reads from the on-disk representation of an executable +/// or dynamic library image. +/// +/// This reader uses a remote addressing scheme where the most significant +/// 16 bits of the address value serve as an index into the array of loaded images, +/// and the low 48 bits correspond to the preferred virtual address mapping of +/// the image. class ObjectMemoryReader : public MemoryReader { - std::vector Images; + struct ImageEntry { + Image TheImage; + uint64_t Slide; + }; + std::vector Images; + + std::pair + decodeImageIndexAndAddress(uint64_t Addr) const { + for (auto &Image : Images) { + if (Image.TheImage.getStartAddress() + Image.Slide <= Addr + && Addr < Image.TheImage.getEndAddress() + Image.Slide) { + return {&Image.TheImage, Addr - Image.Slide}; + } + } + return {nullptr, 0}; + } + + uint64_t + encodeImageIndexAndAddress(const Image *image, uint64_t imageAddr) const { + auto entry = (const ImageEntry*)image; + return imageAddr + entry->Slide; + } + StringRef getContentsAtAddress(uint64_t Addr, uint64_t Size) { + const Image *image; + uint64_t imageAddr; + std::tie(image, imageAddr) = decodeImageIndexAndAddress(Addr); + + if (!image) + return StringRef(); + + return image->getContentsAtAddress(imageAddr, Size); + } + public: explicit ObjectMemoryReader( const std::vector &ObjectFiles) { - for (const ObjectFile *O : ObjectFiles) - Images.emplace_back(O); + if (ObjectFiles.empty()) { + fputs("no object files provided\n", stderr); + abort(); + } + unsigned WordSize = 0; + for (const ObjectFile *O : ObjectFiles) { + // All the object files we look at should share a word size. + if (!WordSize) { + WordSize = O->getBytesInAddress(); + } else if (WordSize != O->getBytesInAddress()) { + fputs("object files must all be for the same architecture\n", stderr); + abort(); + } + Images.push_back({Image(O), 0}); + } + + // If there is more than one image loaded, try to fit them into one address + // space. + if (Images.size() > 1) { + uint64_t NextAddrSpace = 0; + for (auto &Image : Images) { + Image.Slide = NextAddrSpace - Image.TheImage.getStartAddress(); + NextAddrSpace += + Image.TheImage.getEndAddress() - Image.TheImage.getStartAddress(); + NextAddrSpace = (NextAddrSpace + 16383) & ~16383; + } + + if (WordSize < 8 && NextAddrSpace > 0xFFFFFFFFu) { + fputs("object files did not fit in address space", stderr); + abort(); + } + } } - const std::vector &getImages() const { return Images; } + ArrayRef getImages() const { return Images; } bool queryDataLayout(DataLayoutQueryType type, void *inBuffer, void *outBuffer) override { + auto wordSize = Images.front().TheImage.getBytesInAddress(); switch (type) { case DLQ_GetPointerSize: { auto result = static_cast(outBuffer); - *result = sizeof(void *); + *result = wordSize; return true; } case DLQ_GetSizeSize: { auto result = static_cast(outBuffer); - *result = sizeof(size_t); + *result = wordSize; return true; } } return false; } + + RemoteAddress getImageStartAddress(unsigned i) const { + assert(i < Images.size()); + + return RemoteAddress( + encodeImageIndexAndAddress(&Images[i].TheImage, + Images[i].TheImage.getStartAddress())); + } + // TODO: We could consult the dynamic symbol tables of the images to + // implement this. RemoteAddress getSymbolAddress(const std::string &name) override { return RemoteAddress(nullptr); } ReadBytesResult readBytes(RemoteAddress Addr, uint64_t Size) override { - auto I = std::find_if(Images.begin(), Images.end(), [=](const Image &I) { - return I.isAddressValid(Addr, Size); - }); - return I == Images.end() ? ReadBytesResult(nullptr, [](const void *) {}) - : I->readBytes(Addr, Size); + auto addrValue = Addr.getAddressData(); + auto resultBuffer = getContentsAtAddress(addrValue, Size); + return ReadBytesResult(resultBuffer.data(), no_op_destructor); } bool readString(RemoteAddress Addr, std::string &Dest) override { - ReadBytesResult R = readBytes(Addr, 1); - if (!R) + auto addrValue = Addr.getAddressData(); + auto resultBuffer = getContentsAtAddress(addrValue, 1); + if (resultBuffer.empty()) return false; - StringRef Str((const char *)R.get()); - Dest.append(Str.begin(), Str.end()); + + // Make sure there's a null terminator somewhere in the contents. + unsigned i = 0; + for (unsigned e = resultBuffer.size(); i < e; ++i) { + if (resultBuffer[i] == 0) + goto found_terminator; + } + return false; + + found_terminator: + Dest.append(resultBuffer.begin(), resultBuffer.begin() + i); return true; } + + RemoteAbsolutePointer resolvePointer(RemoteAddress Addr, + uint64_t pointerValue) override { + auto addrValue = Addr.getAddressData(); + const Image *image; + uint64_t imageAddr; + std::tie(image, imageAddr) = + decodeImageIndexAndAddress(addrValue); + + if (!image) + return RemoteAbsolutePointer(); + + auto resolved = image->resolvePointer(imageAddr, pointerValue); + + if (resolved && resolved.isResolved()) { + // Mix in the image index again to produce a remote address pointing into + // the same image. + return RemoteAbsolutePointer("", encodeImageIndexAndAddress(image, + resolved.getResolvedAddress().getAddressData())); + } + // If the pointer is relative to an unresolved relocation, leave it as is. + return resolved; + } }; +using ReflectionContextOwner + = std::unique_ptr; + +template +static std::pair +makeReflectionContextForMetadataReader( + std::shared_ptr reader) { + using ReflectionContext = ReflectionContext; + auto context = new ReflectionContext(reader); + auto &builder = context->getBuilder(); + for (unsigned i = 0, e = reader->getImages().size(); i < e; ++i) { + context->addImage(reader->getImageStartAddress(i)); + } + return {ReflectionContextOwner(context, + [](void *x){ delete (ReflectionContext*)x; }), + builder}; +} + + +static std::pair +makeReflectionContextForObjectFiles( + const std::vector &objectFiles) { + auto Reader = std::make_shared(objectFiles); + + uint8_t pointerSize; + Reader->queryDataLayout(DataLayoutQueryType::DLQ_GetPointerSize, + nullptr, &pointerSize); + + switch (pointerSize) { + case 4: + return makeReflectionContextForMetadataReader>> + (std::move(Reader)); + case 8: + return makeReflectionContextForMetadataReader>> + (std::move(Reader)); + default: + fputs("unsupported word size in object file\n", stderr); + abort(); + } +} + static int doDumpReflectionSections(ArrayRef BinaryFilenames, StringRef Arch, ActionType Action, std::ostream &OS) { @@ -271,16 +575,14 @@ static int doDumpReflectionSections(ArrayRef BinaryFilenames, ObjectOwners.push_back(std::move(ObjectOwner)); ObjectFiles.push_back(O); } - - auto Reader = std::make_shared(ObjectFiles); - NativeReflectionContext Context(Reader); - for (const Image &I : Reader->getImages()) - Context.addImage(I.getStartAddress()); + + auto context = makeReflectionContextForObjectFiles(ObjectFiles); + auto &builder = context.second; switch (Action) { case ActionType::DumpReflectionSections: // Dump everything - Context.getBuilder().dumpAllSections(OS); + builder.dumpAllSections(OS); break; case ActionType::DumpTypeLowering: { for (std::string Line; std::getline(std::cin, Line);) { @@ -293,15 +595,14 @@ static int doDumpReflectionSections(ArrayRef BinaryFilenames, Demangle::Demangler Dem; auto Demangled = Dem.demangleType(Line); auto *TypeRef = - swift::Demangle::decodeMangledType(Context.getBuilder(), Demangled); + swift::Demangle::decodeMangledType(builder, Demangled); if (TypeRef == nullptr) { OS << "Invalid typeref: " << Line << "\n"; continue; } TypeRef->dump(OS); - auto *TypeInfo = - Context.getBuilder().getTypeConverter().getTypeInfo(TypeRef); + auto *TypeInfo = builder.getTypeConverter().getTypeInfo(TypeRef); if (TypeInfo == nullptr) { OS << "Invalid lowering\n"; continue; diff --git a/tools/swift-remoteast-test/CMakeLists.txt b/tools/swift-remoteast-test/CMakeLists.txt index 99526a5f32a..54987f792c1 100644 --- a/tools/swift-remoteast-test/CMakeLists.txt +++ b/tools/swift-remoteast-test/CMakeLists.txt @@ -13,6 +13,6 @@ endif() # If building as part of clang, make sure the headers are installed. if(NOT SWIFT_BUILT_STANDALONE) - add_dependencies(swift clang-headers) + add_dependencies(swift clang-resource-headers) endif() diff --git a/unittests/Basic/CMakeLists.txt b/unittests/Basic/CMakeLists.txt index 10a7bdf509f..488dc579d23 100644 --- a/unittests/Basic/CMakeLists.txt +++ b/unittests/Basic/CMakeLists.txt @@ -27,7 +27,7 @@ add_swift_unittest(SwiftBasicTests StringExtrasTest.cpp SuccessorMapTest.cpp ThreadSafeRefCntPointerTest.cpp - TransformArrayRefTest.cpp + TransformRangeTest.cpp TreeScopedHashTableTest.cpp UnicodeTest.cpp ValueEnumeratorTest.cpp diff --git a/unittests/Basic/TransformArrayRefTest.cpp b/unittests/Basic/TransformRangeTest.cpp similarity index 64% rename from unittests/Basic/TransformArrayRefTest.cpp rename to unittests/Basic/TransformRangeTest.cpp index 3234656f4af..25f534ac3dd 100644 --- a/unittests/Basic/TransformArrayRefTest.cpp +++ b/unittests/Basic/TransformRangeTest.cpp @@ -1,8 +1,8 @@ -//===--- TransformArrayRefTest.cpp ----------------------------------------===// +//===--- TransformRangeTest.cpp -------------------------------------------===// // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information @@ -10,20 +10,21 @@ // //===----------------------------------------------------------------------===// -#include "swift/Basic/TransformArrayRef.h" +#include "swift/Basic/STLExtras.h" +#include "llvm/ADT/ArrayRef.h" #include "gtest/gtest.h" using namespace swift; -TEST(TransformArrayRefTest, Empty) { +TEST(TransformRangeTest, Empty) { auto transform = [](int i) -> float { return float(i); }; std::function f(transform); std::vector v1; - auto EmptyArray = makeTransformArrayRef(llvm::ArrayRef(v1), f); + auto EmptyArray = makeTransformRange(llvm::ArrayRef(v1), f); EXPECT_EQ(EmptyArray.empty(), v1.empty()); } -TEST(TransformArrayRefTest, Subscript) { +TEST(TransformRangeTest, Subscript) { auto transform = [](int i) -> float { return float(i); }; std::function f(transform); std::vector v1; @@ -35,7 +36,7 @@ TEST(TransformArrayRefTest, Subscript) { v1.push_back(-5); v1.push_back(-30); - auto Array = makeTransformArrayRef(llvm::ArrayRef(v1), f); + auto Array = makeTransformRange(llvm::ArrayRef(v1), f); EXPECT_EQ(Array.size(), v1.size()); for (unsigned i = 0, e = Array.size(); i != e; ++i) { @@ -43,7 +44,7 @@ TEST(TransformArrayRefTest, Subscript) { } } -TEST(TransformArrayRefTest, Iteration) { +TEST(TransformRangeTest, Iteration) { auto transform = [](int i) -> float { return float(i); }; std::function f(transform); std::vector v1; @@ -55,7 +56,7 @@ TEST(TransformArrayRefTest, Iteration) { v1.push_back(-5); v1.push_back(-30); - auto Array = makeTransformArrayRef(llvm::ArrayRef(v1), f); + auto Array = makeTransformRange(llvm::ArrayRef(v1), f); auto VBegin = v1.begin(); auto VIter = v1.begin(); @@ -83,7 +84,7 @@ TEST(TransformArrayRefTest, Iteration) { } } -TEST(TransformArrayRefTest, Slicing) { +TEST(TransformRangeTest, IterationWithSizelessSubscriptlessRange) { auto transform = [](int i) -> float { return float(i); }; std::function f(transform); std::vector v1; @@ -95,13 +96,30 @@ TEST(TransformArrayRefTest, Slicing) { v1.push_back(-5); v1.push_back(-30); - auto Array = llvm::ArrayRef(v1); - auto TArray = makeTransformArrayRef(Array, f); + auto Array = makeTransformRange(llvm::make_range(v1.begin(), v1.end()), f); - EXPECT_EQ(Array.size(), TArray.size()); - while (!Array.empty()) { - EXPECT_EQ(transform(*Array.begin()), *TArray.begin()); - Array = Array.slice(1); - TArray = TArray.slice(1); + auto VBegin = v1.begin(); + auto VIter = v1.begin(); + auto VEnd = v1.end(); + auto TBegin = Array.begin(); + auto TIter = Array.begin(); + auto TEnd = Array.end(); + + // Forwards. + while (VIter != VEnd) { + EXPECT_NE(TIter, TEnd); + EXPECT_EQ(transform(*VIter), *TIter); + ++VIter; + ++TIter; + } + + // Backwards. + while (VIter != VBegin) { + EXPECT_NE(TIter, TBegin); + + --VIter; + --TIter; + + EXPECT_EQ(transform(*VIter), *TIter); } } diff --git a/unittests/Parse/LexerTests.cpp b/unittests/Parse/LexerTests.cpp index 282295ae76c..5d085155354 100644 --- a/unittests/Parse/LexerTests.cpp +++ b/unittests/Parse/LexerTests.cpp @@ -825,7 +825,9 @@ TEST_F(LexerTest, DiagnoseEmbeddedNulOffset) { // This test requires mmap because llvm::sys::Memory doesn't support protecting // pages to have no permissions. TEST_F(LexerTest, EncodedStringSegmentPastTheEnd) { - size_t PageSize = llvm::sys::Process::getPageSize(); + Expected ExptPageSize = llvm::sys::Process::getPageSize(); + ASSERT_TRUE(bool(ExptPageSize)); + size_t PageSize = *ExptPageSize; void *FirstPage = mmap(/*addr*/nullptr, PageSize * 2, PROT_NONE, MAP_PRIVATE | MAP_ANON, /*fd*/-1, /*offset*/0); diff --git a/utils/build-parser-lib b/utils/build-parser-lib index 616ce76c2d8..7d5c0483506 100755 --- a/utils/build-parser-lib +++ b/utils/build-parser-lib @@ -24,6 +24,7 @@ from __future__ import print_function +import copy import multiprocessing import os import platform @@ -32,6 +33,7 @@ import sys from build_swift import argparse, defaults from swift_build_support.swift_build_support import ( shell, + xcrun, ) from swift_build_support.swift_build_support.SwiftBuildSupport import ( HOME, @@ -43,7 +45,7 @@ from swift_build_support.swift_build_support.toolchain import host_toolchain isDarwin = platform.system() == 'Darwin' class Builder(object): - def __init__(self, toolchain, args, profile_data=None, arch=None, native_build_dir=None): + def __init__(self, toolchain, args, host, arch, profile_data=None, native_build_dir=None): self.toolchain = toolchain self.ninja_path = args.ninja_path self.build_release = args.release @@ -59,6 +61,7 @@ class Builder(object): self.install_destdir = args.install_destdir self.install_prefix = args.install_prefix self.version = args.version + self.host = host self.arch = arch self.native_build_dir = native_build_dir @@ -71,16 +74,84 @@ class Builder(object): def configure(self, enable_debuginfo, instrumentation=None, profile_data=None): cmake_args = [self.toolchain.cmake, '-G', 'Ninja'] cmake_args += ['-DCMAKE_MAKE_PROGRAM='+self.ninja_path] + + isEmbeddedHost = isDarwin and self.host != 'macosx' + host_triple = None + host_sdk = None + llvm_c_flags = "-arch "+self.arch + + if self.host == 'macosx': + deployment_version = '10.12' + host_triple = '%s-apple-macosx%s' % (self.arch, deployment_version) + host_sdk = 'OSX' + cmake_args += ['-DCMAKE_OSX_DEPLOYMENT_TARGET='+deployment_version, '-DSWIFT_DARWIN_DEPLOYMENT_VERSION_OSX='+deployment_version] + + elif self.host == 'linux': + host_triple = '%s-unknown-linux' % (self.arch) + host_sdk = 'LINUX' + + elif self.host == 'iphonesimulator': + deployment_version = '10.0' + host_triple = '%s-apple-ios%s-simulator' % (self.arch, deployment_version) + host_sdk = 'IOS_SIMULATOR' + cmake_args += ['-DCMAKE_OSX_DEPLOYMENT_TARGET='+deployment_version, '-DSWIFT_DARWIN_DEPLOYMENT_VERSION_IOS='+deployment_version] + llvm_c_flags += ' -mios-simulator-version-min='+deployment_version + + elif self.host == 'iphoneos': + deployment_version = '10.0' + host_triple = '%s-apple-ios%s' % (self.arch, deployment_version) + host_sdk = 'IOS' + cmake_args += ['-DCMAKE_OSX_DEPLOYMENT_TARGET='+deployment_version, '-DSWIFT_DARWIN_DEPLOYMENT_VERSION_IOS='+deployment_version] + llvm_c_flags += ' -miphoneos-version-min=='+deployment_version + + elif self.host == 'appletvsimulator': + deployment_version = '10.0' + host_triple = '%s-apple-tvos%s-simulator' % (self.arch, deployment_version) + host_sdk = 'TVOS_SIMULATOR' + cmake_args += ['-DCMAKE_OSX_DEPLOYMENT_TARGET='+deployment_version, '-DSWIFT_DARWIN_DEPLOYMENT_VERSION_TVOS='+deployment_version] + llvm_c_flags += ' -mtvos-simulator-version-min='+deployment_version + + elif self.host == 'appletvos': + deployment_version = '10.0' + host_triple = '%s-apple-tvos%s' % (self.arch, deployment_version) + host_sdk = 'TVOS' + cmake_args += ['-DCMAKE_OSX_DEPLOYMENT_TARGET='+deployment_version, '-DSWIFT_DARWIN_DEPLOYMENT_VERSION_TVOS='+deployment_version] + llvm_c_flags += ' -mtvos-version-min='+deployment_version + + elif self.host == 'watchsimulator': + deployment_version = '3.0' + host_triple = '%s-apple-watchos%s-simulator' % (self.arch, deployment_version) + host_sdk = 'WATCHOS_SIMULATOR' + cmake_args += ['-DCMAKE_OSX_DEPLOYMENT_TARGET='+deployment_version, '-DSWIFT_DARWIN_DEPLOYMENT_VERSION_WATCHOS='+deployment_version] + llvm_c_flags += ' -mwatchos-simulator-version-min='+deployment_version + + elif self.host == 'watchos': + deployment_version = '3.0' + host_triple = '%s-apple-watchos%s' % (self.arch, deployment_version) + host_sdk = 'WATCHOS' + cmake_args += ['-DCMAKE_OSX_DEPLOYMENT_TARGET='+deployment_version, '-DSWIFT_DARWIN_DEPLOYMENT_VERSION_WATCHOS='+deployment_version] + llvm_c_flags += ' -mwatchos-version-min='+deployment_version + + assert host_triple + assert host_sdk + cmake_args += [ + '-DLLVM_HOST_TRIPLE:STRING='+host_triple, + '-DLLVM_TARGET_ARCH='+self.arch, + '-DSWIFT_HOST_VARIANT='+self.host, + '-DSWIFT_HOST_VARIANT_SDK='+host_sdk, + '-DSWIFT_HOST_VARIANT_ARCH='+self.arch, + '-DCMAKE_C_FLAGS='+llvm_c_flags, + '-DCMAKE_CXX_FLAGS='+llvm_c_flags, + ] + if isEmbeddedHost: + cmake_args += [ + '-DCMAKE_OSX_SYSROOT:PATH='+xcrun.sdk_path(self.host), + # For embedded hosts CMake runs the checks and triggers crashes because the test binary was built for embedded host. + '-DHAVE_POSIX_REGEX:BOOL=TRUE', + '-DHAVE_STEADY_CLOCK:BOOL=TRUE', + ] + if isDarwin: - cmake_args += ['-DCMAKE_OSX_DEPLOYMENT_TARGET=10.12', '-DSWIFT_DARWIN_DEPLOYMENT_VERSION_OSX=10.12'] - if self.arch is not None: - cmake_args += [ - '-DLLVM_HOST_TRIPLE:STRING='+self.arch+'-apple-darwin16.0', - '-DSWIFT_HOST_TRIPLE:STRING='+self.arch+'-apple-darwin16.0', - '-DCMAKE_C_FLAGS=-arch '+self.arch, - '-DCMAKE_CXX_FLAGS=-arch '+self.arch, - '-DSWIFT_HOST_VARIANT_ARCH='+self.arch, - ] if self.native_build_dir is not None: cmake_args += [ '-DLLVM_TABLEGEN='+os.path.join(self.native_build_dir, 'bin', 'llvm-tblgen'), @@ -92,7 +163,7 @@ class Builder(object): ] else: dispatch_source_path = os.path.join(SWIFT_SOURCE_ROOT, 'swift-corelibs-libdispatch') - cmake_args += ['-DSWIFT_HOST_VARIANT=linux', '-DSWIFT_HOST_VARIANT_SDK=LINUX', '-DSWIFT_HOST_VARIANT_ARCH=x86_64', + cmake_args += [ '-DSWIFT_PATH_TO_LIBDISPATCH_SOURCE:PATH='+dispatch_source_path, '-DLLVM_ENABLE_LLD=ON'] cmake_args += ['-DLLVM_TARGETS_TO_BUILD=X86'] @@ -190,6 +261,7 @@ def main(): store_path = optbuilder.actions.store_path toolchain = host_toolchain(xcrun_toolchain='default') + default_host = 'macosx' if isDarwin else 'linux' default_architectures = platform.machine() default_profile_input = os.path.join(SWIFT_SOURCE_ROOT, "swift", "utils", "parser-lib", "profile-input.swift") @@ -229,6 +301,10 @@ def main(): option('--build-dir', store_path, default=default_build_dir, help='the path where the build products will be placed. (default = %s)' % default_build_dir) + option('--host', store, + choices=['macosx', 'linux', 'iphonesimulator', 'iphoneos', 'appletvsimulator', 'appletvos', 'watchsimulator', 'watchos'], + default=default_host, + help='host platform to build for (default = %s)' % default_host) option('--architectures', store, default=default_architectures, help='space-separated list of architectures to build for. (default = %s)' % default_architectures) @@ -251,39 +327,73 @@ def main(): if not args.install_destdir: args.install_destdir = os.path.join(args.build_dir, 'install') - if isDarwin: - architectures = args.architectures.split(" ") - architectures = [arch for arch in architectures if arch != platform.machine() and arch != ""] - if platform.machine() in architectures: architectures = [platform.machine()] + architectures + architectures = args.architectures.split(" ") + architectures = [arch for arch in architectures if arch != ""] + if platform.machine() in architectures: + # Make sure the machine architecture is at the front. + architectures.remove(platform.machine()) architectures = [platform.machine()] + architectures + if isDarwin: objroot = args.build_dir dstroot = args.install_destdir symroot = args.install_symroot prefix = args.install_prefix - for arch in architectures: - native = platform.machine() == arch + native_build_dir = None + profile_data = None + dst_dirs = [] + if args.host == 'macosx' and architectures[0] == platform.machine(): + # Build for the native machine. + arch = architectures.pop(0) + tmpargs = copy.copy(args) + tmpargs.build_dir = os.path.join(objroot, arch, "obj") + tmpargs.install_destdir = os.path.join(objroot, arch, "dst") + tmpargs.install_prefix = "/" + + native_build_dir = tmpargs.build_dir + dst_dirs.append(tmpargs.install_destdir) + + if tmpargs.pgo_type: + profile_dir = os.path.join(objroot, platform.machine()+'-profiling') + builder = Builder(toolchain, tmpargs, tmpargs.host, arch) + builder.get_profile_data(profile_dir) + profile_data = os.path.join(profile_dir, "profdata.prof") + + builder = Builder(toolchain, tmpargs, tmpargs.host, arch, profile_data=profile_data) + builder.run() + + else: + tmpargs = copy.copy(args) + if tmpargs.pgo_type: + # Build for the machine and get profile data. + native_build_dir = os.path.join(objroot, platform.machine()+'-profiling') + builder = Builder(toolchain, tmpargs, 'macosx', platform.machine()) + builder.get_profile_data(native_build_dir) + profile_data = os.path.join(native_build_dir, "profdata.prof") + else: + # Build the tablegen binaries so we can use them for the cross-compile build. + native_build_dir = os.path.join(objroot, platform.machine()+'-tblgen') + tmpargs.lto_type = None + builder = Builder(toolchain, tmpargs, 'macosx', platform.machine()) + shell.makedirs(native_build_dir, dry_run=tmpargs.dry_run) + with shell.pushd(native_build_dir, dry_run=tmpargs.dry_run): + builder.configure(enable_debuginfo=False) + builder.build_target(native_build_dir, 'llvm-tblgen') + builder.build_target(native_build_dir, 'clang-tblgen') + + for arch in architectures: args.build_dir = os.path.join(objroot, arch, "obj") args.install_destdir = os.path.join(objroot, arch, "dst") args.install_prefix = "/" - native_build_dir = None if native else os.path.join(objroot, platform.machine(), "obj") + dst_dirs.append(args.install_destdir) - profile_data = None - if args.pgo_type: - profile_dir = os.path.join(objroot, platform.machine()+'-profiling') - if native: - builder = Builder(toolchain, args) - builder.get_profile_data(profile_dir) - profile_data = os.path.join(profile_dir, "profdata.prof") - - builder = Builder(toolchain, args, profile_data=profile_data, arch=arch, native_build_dir=native_build_dir) + builder = Builder(toolchain, args, args.host, arch, profile_data=profile_data, native_build_dir=native_build_dir) builder.run() lipo = os.path.join(SWIFT_SOURCE_ROOT, "swift", "utils", "recursive-lipo") - dst_dirs = [os.path.join(objroot, arch, "dst") for arch in architectures] shell.call([lipo, "-v", "--destination", os.path.join(dstroot, "./"+prefix)] + dst_dirs) if args.install_symroot: @@ -291,7 +401,8 @@ def main(): return 0 - builder = Builder(toolchain, args) + assert args.architectures == platform.machine(), "building for non-machine architecture is not supported for non-darwin host" + builder = Builder(toolchain, args, args.host, args.architectures) builder.run() return 0 diff --git a/utils/build-presets.ini b/utils/build-presets.ini index 7f2ac5c0a2d..0a810e8974a 100644 --- a/utils/build-presets.ini +++ b/utils/build-presets.ini @@ -20,7 +20,7 @@ swift-install-components=compiler;clang-builtin-headers;stdlib;sdk-overlay;parse [preset: mixin_buildbot_install_components_with_clang] swift-install-components=compiler;clang-resource-dir-symlink;stdlib;sdk-overlay;parser-lib;toolchain-tools;license;sourcekit-xpc-service;swift-remote-mirror;swift-remote-mirror-headers -llvm-install-components=llvm-cov;llvm-profdata;IndexStore;clang;clang-headers;compiler-rt;clangd +llvm-install-components=llvm-cov;llvm-profdata;IndexStore;clang;clang-resource-headers;compiler-rt;clangd [preset: mixin_buildbot_trunk_base] # Build standard library and SDK overlay for iOS device and simulator. @@ -716,7 +716,7 @@ swift-enable-ast-verifier=0 #===------------------------------------------------------------------------===# [preset: mixin_linux_install_components_with_clang] swift-install-components=autolink-driver;compiler;clang-resource-dir-symlink;stdlib;swift-remote-mirror;sdk-overlay;parser-lib;toolchain-tools;license;sourcekit-inproc -llvm-install-components=llvm-cov;llvm-profdata;IndexStore;clang;clang-headers;compiler-rt;clangd +llvm-install-components=llvm-cov;llvm-profdata;IndexStore;clang;clang-resource-headers;compiler-rt;clangd [preset: mixin_linux_installation] mixin-preset= diff --git a/utils/build-script b/utils/build-script index 338f229e918..e01a55d23e8 100755 --- a/utils/build-script +++ b/utils/build-script @@ -299,7 +299,6 @@ class BuildScriptInvocation(object): "--swift-build-type", args.swift_build_variant, "--swift-stdlib-build-type", args.swift_stdlib_build_variant, "--lldb-build-type", args.lldb_build_variant, - "--lldb-build-with-xcode", args.lldb_build_with_xcode, "--foundation-build-type", args.foundation_build_variant, "--libdispatch-build-type", args.libdispatch_build_variant, "--libicu-build-type", args.libicu_build_variant, diff --git a/utils/build-script-impl b/utils/build-script-impl index 411889ad728..62c306fe9b1 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -53,9 +53,7 @@ KNOWN_SETTINGS=( ninja-bin "" "the path to Ninja tool" cmark-build-type "Debug" "the CMake build variant for CommonMark (Debug, RelWithDebInfo, Release, MinSizeRel). Defaults to Debug." lldb-extra-cmake-args "" "extra command line args to pass to lldb cmake" - lldb-extra-xcodebuild-args "" "extra command line args to pass to lldb xcodebuild" lldb-test-cc "" "CC to use for building LLDB testsuite test inferiors. Defaults to just-built, in-tree clang. If set to 'host-toolchain', sets it to same as host-cc." - lldb-test-with-curses "" "run test lldb test runner using curses terminal control" lldb-test-swift-only "0" "when running lldb tests, only include Swift-specific tests" lldb-no-debugserver "" "delete debugserver after building it, and don't try to codesign it" lldb-use-system-debugserver "" "don't try to codesign debugserver, and use the system's debugserver instead" @@ -74,7 +72,6 @@ KNOWN_SETTINGS=( swift-stdlib-enable-assertions "1" "enable assertions in Swift" swift-stdlib-use-nonatomic-rc "0" "build the Swift stdlib and overlays with nonatomic reference count operations enabled" lldb-build-type "Debug" "the CMake build variant for LLDB" - lldb-build-with-xcode "0" "Use xcodebuild to build LLDB, instead of CMake" llbuild-build-type "Debug" "the CMake build variant for llbuild" foundation-build-type "Debug" "the build variant for Foundation" libdispatch-build-type "Debug" "the build variant for libdispatch" @@ -1929,64 +1926,6 @@ function set_swiftevolve_build_command() { swiftevolve_build_command=("${stresstester_build_script_helper_command[@]}") } -# Construct the appropriate options to pass to an Xcode -# build of any LLDB target. -function set_lldb_xcodebuild_options() { - llvm_build_dir=$(build_directory ${host} llvm) - cmark_build_dir=$(build_directory ${host} cmark) - lldb_build_dir=$(build_directory ${host} lldb) - swift_build_dir=$(build_directory ${host} swift) - - lldb_xcodebuild_options=( - LLDB_PATH_TO_LLVM_SOURCE="${LLVM_SOURCE_DIR}" - LLDB_PATH_TO_CLANG_SOURCE="${CLANG_SOURCE_DIR}" - LLDB_PATH_TO_SWIFT_SOURCE="${SWIFT_SOURCE_DIR}" - LLDB_PATH_TO_LLVM_BUILD="${llvm_build_dir}" - LLDB_PATH_TO_CLANG_BUILD="${llvm_build_dir}" - LLDB_PATH_TO_SWIFT_BUILD="${swift_build_dir}" - LLDB_IS_BUILDBOT_BUILD="${LLDB_IS_BUILDBOT_BUILD}" - LLDB_BUILD_DATE="\"${LLDB_BUILD_DATE}\"" - SYMROOT="${lldb_build_dir}" - OBJROOT="${lldb_build_dir}" - -UseNewBuildSystem=NO - ${LLDB_EXTRA_XCODEBUILD_ARGS} - MACOSX_DEPLOYMENT_TARGET=10.13 - ) - if [[ "${LLDB_NO_DEBUGSERVER}" ]] ; then - lldb_xcodebuild_options=( - "${lldb_xcodebuild_options[@]}" - DEBUGSERVER_DISABLE_CODESIGN="1" - DEBUGSERVER_DELETE_AFTER_BUILD="1" - ) - fi - if [[ "${LLDB_USE_SYSTEM_DEBUGSERVER}" ]] ; then - lldb_xcodebuild_options=( - "${lldb_xcodebuild_options[@]}" - DEBUGSERVER_USE_FROM_SYSTEM="1" - ) - fi - if [[ "${ENABLE_ASAN}" ]] ; then - lldb_xcodebuild_options=( - "${lldb_xcodebuild_options[@]}" - ENABLE_ADDRESS_SANITIZER="YES" - -enableAddressSanitizer=YES - ) - fi - if [[ "${ENABLE_UBSAN}" ]] ; then - lldb_xcodebuild_options=( - "${lldb_xcodebuild_options[@]}" - ENABLE_UNDEFINED_BEHAVIOR_SANITIZER="YES" - -enableUndefinedBehaviorSanitizer=YES - ) - fi - if [[ "$(true_false ${LLDB_ASSERTIONS})" == "FALSE" ]]; then - lldb_xcodebuild_options=( - "${lldb_xcodebuild_options[@]}" - OTHER_CFLAGS="-DNDEBUG" - ) - fi -} - # # Configure and build each product # @@ -2157,7 +2096,7 @@ for host in "${ALL_HOSTS[@]}"; do if [ "${SKIP_BUILD_LLVM}" ] ; then # We can't skip the build completely because the standalone # build of Swift depend on these for building and testing. - build_targets=(llvm-tblgen clang-headers intrinsics_gen clang-tablegen-targets) + build_targets=(llvm-tblgen clang-resource-headers intrinsics_gen clang-tablegen-targets) # If we are not performing a toolchain only build, then we # also want to include FileCheck and not for testing # purposes. @@ -2309,6 +2248,13 @@ for host in "${ALL_HOSTS[@]}"; do build_tests_this_time=${SWIFT_INCLUDE_TESTS} fi + if [[ $(is_cross_tools_host ${host}) ]] ; then + cmake_options=( + "${cmake_options[@]}" + -DLLVM_TABLEGEN=$(build_directory "${LOCAL_HOST}" llvm)/bin/llvm-tblgen + ) + fi + # Command-line parameters override any autodetection that we # might have done. if [[ "${NATIVE_LLVM_TOOLS_PATH}" ]] ; then @@ -2500,13 +2446,6 @@ for host in "${ALL_HOSTS[@]}"; do "${lldb_cmake_options[@]}" ) - if [ ! -z "${LLDB_EXTRA_CMAKE_ARGS}" ]; then - cmake_options=( - "${cmake_options[@]}" - ${LLDB_EXTRA_CMAKE_ARGS} - ) - fi - # Figure out if we think this is a buildbot build. # This will influence the lldb version line. if [ ! -z "${JENKINS_HOME}" -a ! -z "${JOB_NAME}" -a ! -z "${BUILD_NUMBER}" ]; then @@ -2515,53 +2454,83 @@ for host in "${ALL_HOSTS[@]}"; do LLDB_IS_BUILDBOT_BUILD=0 fi - # Get the build date + # Get the build date. LLDB_BUILD_DATE=$(date +%Y-%m-%d) - using_xcodebuild="FALSE" - if [[ "$(uname -s)" == "Darwin" && "$(true_false ${LLDB_BUILD_WITH_XCODE})" == "TRUE" ]] ; then - using_xcodebuild="TRUE" + # Pick the right cache. + if [[ "$(uname -s)" == "Darwin" ]] ; then + cmake_cache="Apple-lldb-macOS.cmake" + else + cmake_cache="Apple-lldb-Linux.cmake" fi - if [[ "${using_xcodebuild}" == "TRUE" ]] ; then - # Set up flags to pass to xcodebuild - set_lldb_xcodebuild_options - set_lldb_build_mode - with_pushd ${source_dir} \ - call xcodebuild -target desktop -configuration ${LLDB_BUILD_MODE} ${lldb_xcodebuild_options[@]} - continue + # Options to find the just-built libddispatch and Foundation. + if [[ "$(uname -s)" == "Darwin" || "${SKIP_BUILD_FOUNDATION}" ]] ; then + DOTEST_EXTRA="" else - if [[ "$(uname -s)" == "Darwin" ]] ; then - cmake_cache="Apple-lldb-macOS.cmake" - else - cmake_cache="Apple-lldb-linux.cmake" - fi + # This assumes that there are no spaces in any on these paths. + LIBDISPATCH_BUILD_DIR="$(build_directory ${host} libdispatch)" + FOUNDATION_BUILD_DIR=$(build_directory ${host} foundation) + DOTEST_EXTRA="-I${FOUNDATION_BUILD_DIR}" + DOTEST_EXTRA="${DOTEST_EXTRA} -Xcc -F${FOUNDATION_BUILD_DIR}" + DOTEST_EXTRA="${DOTEST_EXTRA} -I${FOUNDATION_BUILD_DIR}/swift" + DOTEST_EXTRA="${DOTEST_EXTRA} -I${LIBDISPATCH_SOURCE_DIR}" + DOTEST_EXTRA="${DOTEST_EXTRA} -L${FOUNDATION_BUILD_DIR}" + DOTEST_EXTRA="${DOTEST_EXTRA} -L${LIBDISPATCH_BUILD_DIR}" + DOTEST_EXTRA="${DOTEST_EXTRA} -L${LIBDISPATCH_BUILD_DIR}/src" + DOTEST_EXTRA="${DOTEST_EXTRA} -Xlinker -rpath -Xlinker ${LIBDISPATCH_BUILD_DIR}/src" + DOTEST_EXTRA="${DOTEST_EXTRA} -Xlinker -rpath -Xlinker ${LIBDISPATCH_BUILD_DIR}" + DOTEST_EXTRA="${DOTEST_EXTRA} -Xlinker -rpath -Xlinker ${FOUNDATION_BUILD_DIR}" + fi - cmake_options=( - "${cmake_options[@]}" - -C${LLDB_SOURCE_DIR}/cmake/caches/${cmake_cache} - -DCMAKE_BUILD_TYPE:STRING="${LLDB_BUILD_TYPE}" - -DLLDB_SWIFTC:PATH="$(build_directory ${LOCAL_HOST} swift)/bin/swiftc" - -DLLDB_SWIFT_LIBS:PATH="$(build_directory ${LOCAL_HOST} swift)/lib/swift" - -DCMAKE_INSTALL_PREFIX:PATH="$(get_host_install_prefix ${host})" - -DLLDB_FRAMEWORK_INSTALL_DIR="$(get_host_install_prefix ${host})../System/Library/PrivateFrameworks" - -DClang_DIR:PATH=${llvm_build_dir}/lib/cmake/clang - -DLLVM_DIR:PATH=${llvm_build_dir}/lib/cmake/llvm - -DLLDB_PATH_TO_CLANG_BUILD:PATH="${llvm_build_dir}" - -DLLDB_PATH_TO_SWIFT_SOURCE:PATH="${SWIFT_SOURCE_DIR}" - -DLLDB_PATH_TO_SWIFT_BUILD:PATH="${swift_build_dir}" - -DLLDB_IS_BUILDBOT_BUILD:BOOL="${LLDB_IS_BUILDBOT_BUILD}" - -DLLDB_BUILD_DATE:STRING="\"${LLDB_BUILD_DATE}\"" - -DLLDB_ALLOW_STATIC_BINDINGS:BOOL=1 - -DLLDB_INCLUDE_TESTS:BOOL=$(false_true ${BUILD_TOOLCHAIN_ONLY}) + # Watchpoint testing is currently disabled: see rdar://38566150. + LLDB_TEST_CATEGORIES="--skip-category=watchpoint" + + # Skip DWO to speed up swift testing. + if [[ "$(true_false ${LLDB_TEST_SWIFT_ONLY})" == "TRUE" ]]; then + LLDB_TEST_CATEGORIES="${LLDB_TEST_CATEGORIES};--skip-category=dwo" + fi + + # Construct dotest arguments. We use semicolons so CMake interprets this as a list. + DOTEST_ARGS="--build-dir;${lldb_build_dir}/lldb-test-build.noindex;${LLDB_TEST_CATEGORIES};-t" + + # Only set the extra arguments if they're not empty. + if [[ -n "${DOTEST_EXTRA}" ]]; then + DOTEST_ARGS="${DOTEST_ARGS};-E;${DOTEST_EXTRA}" + fi + + cmake_options=( + "${cmake_options[@]}" + -C${LLDB_SOURCE_DIR}/cmake/caches/${cmake_cache} + -DCMAKE_BUILD_TYPE:STRING="${LLDB_BUILD_TYPE}" + -DLLDB_SWIFTC:PATH="$(build_directory ${LOCAL_HOST} swift)/bin/swiftc" + -DLLDB_SWIFT_LIBS:PATH="$(build_directory ${LOCAL_HOST} swift)/lib/swift" + -DCMAKE_INSTALL_PREFIX:PATH="$(get_host_install_prefix ${host})" + -DLLDB_FRAMEWORK_INSTALL_DIR="$(get_host_install_prefix ${host})../System/Library/PrivateFrameworks" + -DLLVM_DIR:PATH=${llvm_build_dir}/lib/cmake/llvm + -DClang_DIR:PATH=${llvm_build_dir}/lib/cmake/clang + -DSwift_DIR:PATH=${swift_build_dir}/lib/cmake/swift + -DLLDB_PATH_TO_SWIFT_SOURCE:PATH="${SWIFT_SOURCE_DIR}" + -DLLDB_IS_BUILDBOT_BUILD:BOOL="${LLDB_IS_BUILDBOT_BUILD}" + -DLLDB_BUILD_DATE:STRING="\"${LLDB_BUILD_DATE}\"" + -DLLDB_ALLOW_STATIC_BINDINGS:BOOL=1 + -DLLDB_INCLUDE_TESTS:BOOL=$(false_true ${BUILD_TOOLCHAIN_ONLY}) + -DLLDB_TEST_USER_ARGS="${DOTEST_ARGS}" + ) + + if [[ "$(uname -s)" == "Darwin" && "$(true_false ${LLDB_USE_SYSTEM_DEBUGSERVER})" == "TRUE" ]]; then + cmake_options+=( + -DLLDB_USE_SYSTEM_DEBUGSERVER:BOOL="${LLDB_USE_SYSTEM_DEBUGSERVER}" ) + fi - if [[ "$(uname -s)" == "Darwin" ]] ; then - cmake_options+=( - -DLLDB_CODESIGN_IDENTITY="" - -DLLDB_USE_SYSTEM_DEBUGSERVER:BOOL="${LLDB_USE_SYSTEM_DEBUGSERVER}" - ) - fi + # Add the extra CMake args at the end so they can override + # values set earlier. + if [ ! -z "${LLDB_EXTRA_CMAKE_ARGS}" ]; then + cmake_options=( + "${cmake_options[@]}" + ${LLDB_EXTRA_CMAKE_ARGS} + ) fi ;; llbuild) @@ -2658,7 +2627,7 @@ for host in "${ALL_HOSTS[@]}"; do cmake_options=( ${cmake_options[@]} - -DCMAKE_BUILD_TYPE:STRING="${LIBDISPATCH_BUILD_TYPE}" + -DCMAKE_BUILD_TYPE:STRING="${XCTEST_BUILD_TYPE}" -DCMAKE_C_COMPILER:PATH="${LLVM_BIN}/clang" -DCMAKE_CXX_COMPILER:PATH="${LLVM_BIN}/clang++" -DCMAKE_SWIFT_COMPILER:PATH="$(build_directory_bin ${LOCAL_HOST} swift)/swiftc" @@ -2717,6 +2686,7 @@ for host in "${ALL_HOSTS[@]}"; do LIBDISPATCH_BUILD_ARGS=( -DFOUNDATION_PATH_TO_LIBDISPATCH_SOURCE=${LIBDISPATCH_SOURCE_DIR} -DFOUNDATION_PATH_TO_LIBDISPATCH_BUILD=${LIBDISPATCH_BUILD_DIR} + -Ddispatch_DIR=${LIBDISPATCH_BUILD_DIR}/cmake/modules ) else LIBDISPATCH_BUILD_ARGS=( -DFOUNDATION_ENABLE_LIBDISPATCH=NO ) @@ -3056,181 +3026,43 @@ for host in "${ALL_HOSTS[@]}"; do fi llvm_build_dir=$(build_directory ${host} llvm) lldb_build_dir=$(build_directory ${host} lldb) - swift_build_dir=$(build_directory ${host} swift) - module_cache="${build_dir}/module-cache" - - using_xcodebuild="FALSE" - if [[ "$(uname -s)" == "Darwin" && "$(true_false ${LLDB_BUILD_WITH_XCODE})" == "TRUE" ]] ; then - using_xcodebuild="TRUE" - fi - - - # Run the unittests. - # FIXME: The xcode build project currently doesn't know how to run the lit style tests. - if [[ "$using_xcodebuild" == "TRUE" ]] ; then - set_lldb_xcodebuild_options - set_lldb_build_mode - # Run the LLDB unittests (gtests). - with_pushd ${LLDB_SOURCE_DIR} \ - call xcodebuild -scheme lldb-gtest -configuration ${LLDB_BUILD_MODE} ${lldb_xcodebuild_options[@]} - rc=$? - if [[ "$rc" -ne 0 ]] ; then - >&2 echo "error: LLDB gtests failed" - exit 1 - fi - fi - - # Setup lldb executable path - if [[ "$using_xcodebuild" == "TRUE" ]] ; then - lldb_executable="${lldb_build_dir}"/${LLDB_BUILD_MODE}/lldb - else - lldb_executable="${lldb_build_dir}"/bin/lldb - fi - results_dir="${lldb_build_dir}/test-results" - # Handle test results formatter - if [[ "${LLDB_TEST_WITH_CURSES}" ]]; then - # Setup the curses results formatter. - LLDB_FORMATTER_OPTS="\ - --results-formatter lldbsuite.test_event.formatter.curses.Curses \ - --results-file /dev/stdout" - else - LLDB_FORMATTER_OPTS="\ - --results-formatter lldbsuite.test_event.formatter.xunit.XunitFormatter \ - --results-file ${results_dir}/results.xml \ - -O--xpass=success \ - -O--xfail=success" - # Setup the xUnit results formatter. - if [[ "$(uname -s)" != "Darwin" ]] ; then - # On non-Darwin, we ignore skipped tests entirely - # so that they don't pollute our xUnit results with - # non-actionable content. - LLDB_FORMATTER_OPTS="${LLDB_FORMATTER_OPTS} -O-ndsym -O-rdebugserver -O-rlibc\\\\+\\\\+ -O-rlong.running -O-rbenchmarks -O-rrequires.one?.of.darwin" - fi - fi - - # Optionally specify a test subdirectory and category filters. - # Watchpoint testing is currently disabled: see rdar://38566150. - if [[ "$(true_false ${LLDB_TEST_SWIFT_ONLY})" == "TRUE" ]]; then - LLDB_TEST_SUBDIR_CLAUSE="--test-subdir lang/swift" - LLDB_TEST_CATEGORIES="--skip-category=watchpoint --skip-category=dwo" - else - LLDB_TEST_SUBDIR_CLAUSE="" - LLDB_TEST_CATEGORIES="--skip-category=watchpoint" - fi - - # figure out which C/C++ compiler we should use for building test inferiors. - if [[ "${LLDB_TEST_CC}" == "host-toolchain" ]]; then - # Use the host toolchain: i.e. the toolchain specified by HOST_CC - LLDB_DOTEST_CC_OPTS="-C ${HOST_CC}" - elif [[ -n "${LLDB_TEST_CC}" ]]; then - # Use exactly the compiler path specified by the user. - LLDB_DOTEST_CC_OPTS="-C ${LLDB_TEST_CC}" - else - # Use the clang that was just built in the tree. - LLDB_DOTEST_CC_OPTS="-C $(build_directory $LOCAL_HOST llvm)"/bin/clang - fi - - # If we need to use the system debugserver, do so explicitly. - if [[ "$(uname -s)" == "Darwin" && "${LLDB_USE_SYSTEM_DEBUGSERVER}" ]] ; then - LLDB_TEST_DEBUG_SERVER="--server $(xcode-select -p)/../SharedFrameworks/LLDB.framework/Resources/debugserver --out-of-tree-debugserver" - else - LLDB_TEST_DEBUG_SERVER="" - fi - - # Options to find the just-built libddispatch and Foundation. - if [[ "$(uname -s)" == "Darwin" || "${SKIP_BUILD_FOUNDATION}" ]] ; then - DOTEST_EXTRA="" - else - # This assumes that there are no spaces in any on these paths. - LIBDISPATCH_BUILD_DIR="$(build_directory ${host} libdispatch)" - FOUNDATION_BUILD_DIR=$(build_directory ${host} foundation) - DOTEST_EXTRA="-I${FOUNDATION_BUILD_DIR}" - DOTEST_EXTRA="${DOTEST_EXTRA} -Xcc -F${FOUNDATION_BUILD_DIR}" - DOTEST_EXTRA="${DOTEST_EXTRA} -I${FOUNDATION_BUILD_DIR}/swift" - DOTEST_EXTRA="${DOTEST_EXTRA} -I${LIBDISPATCH_SOURCE_DIR}" - DOTEST_EXTRA="${DOTEST_EXTRA} -L${FOUNDATION_BUILD_DIR}" - DOTEST_EXTRA="${DOTEST_EXTRA} -L${LIBDISPATCH_BUILD_DIR}" - DOTEST_EXTRA="${DOTEST_EXTRA} -L${LIBDISPATCH_BUILD_DIR}/src" - DOTEST_EXTRA="${DOTEST_EXTRA} -Xlinker -rpath -Xlinker ${LIBDISPATCH_BUILD_DIR}/src" - DOTEST_EXTRA="${DOTEST_EXTRA} -Xlinker -rpath -Xlinker ${LIBDISPATCH_BUILD_DIR}" - DOTEST_EXTRA="${DOTEST_EXTRA} -Xlinker -rpath -Xlinker ${FOUNDATION_BUILD_DIR}" - fi call mkdir -p "${results_dir}" - - if [[ "$using_xcodebuild" == "TRUE" ]] ; then - LLDB_DOTEST_CC_OPTS="${LLDB_DOTEST_CC_OPTS} --filecheck $(build_directory $LOCAL_HOST llvm)/bin/FileCheck --dsymutil $(build_directory $LOCAL_HOST llvm)/bin/dsymutil" - fi - - # Prefer to use lldb-dotest, as building it guarantees that we build all - # test dependencies. Ultimately we want to delete as much lldb-specific logic - # from this file as possible and just have a single call to lldb-dotest. + LLVM_LIT_ARG="${LLVM_LIT_ARGS} --xunit-xml-output=${results_dir}/results.xml" if [[ "${ENABLE_ASAN}" ]] ; then # Limit the number of parallel tests LLVM_LIT_ARGS="${LLVM_LIT_ARGS} -j $(sysctl hw.physicalcpu | awk -v N=${BUILD_JOBS} '{ print (N < $2) ? N : $2 }')" fi - if [[ "$(true_false ${LLDB_TEST_SWIFT_ONLY})" == "TRUE" ]]; then - LLVM_LIT_ARGS="${LLVM_LIT_ARGS} --filter=[sS]wift" - fi + if [[ "$(true_false ${LLDB_TEST_SWIFT_ONLY})" == "TRUE" ]]; then + LLVM_LIT_ARGS="${LLVM_LIT_ARGS} --filter=[sS]wift" + fi # Record the times test took and report the slowest. LLVM_LIT_ARGS="${LLVM_LIT_ARGS} -v --time-tests" - if [[ "$using_xcodebuild" == "FALSE" ]] ; then - with_pushd ${lldb_build_dir} \ - call ${NINJA_BIN} -j ${BUILD_JOBS} unittests/LLDBUnitTests - with_pushd ${lldb_build_dir} \ - call ${NINJA_BIN} -j ${BUILD_JOBS} lldb-test-deps - with_pushd ${results_dir} \ - call "${llvm_build_dir}/bin/llvm-lit" \ - "${lldb_build_dir}/lit" \ - ${LLVM_LIT_ARGS} \ - --xunit-xml-output=${results_dir}/results.xml \ - --param dotest-args="--build-dir ${lldb_build_dir}/lldb-test-build.noindex ${LLDB_TEST_SUBDIR_CLAUSE} ${LLDB_TEST_CATEGORIES} -t -E \"${DOTEST_EXTRA}\"" - if [[ -x "${LLDB_TEST_SWIFT_COMPATIBILITY}" ]] ; then - echo "Running LLDB swift compatibility tests against" \ - "${LLDB_TEST_SWIFT_COMPATIBILITY}" - with_pushd ${results_dir} \ - call "${llvm_build_dir}/bin/llvm-lit" \ - "${lldb_build_dir}/lit" \ - ${LLVM_LIT_ARGS} \ - --xunit-xml-output=${results_dir}/results.xml \ - --param dotest-args="--build-dir ${lldb_build_dir}/lldb-test-build.noindex ${LLDB_TEST_SUBDIR_CLAUSE} ${LLDB_TEST_CATEGORIES} -G swift-history --swift-compiler \"${LLDB_TEST_SWIFT_COMPATIBILITY}\" -t -E \"${DOTEST_EXTRA}\"" --filter=compat - fi - else - with_pushd "${results_dir}" \ - call env SWIFTC="$(build_directory $LOCAL_HOST swift)/bin/swiftc" \ - SWIFTLIBS="${swift_build_dir}/lib/swift" \ - "${LLDB_SOURCE_DIR}"/test/dotest.py \ - --executable "${lldb_executable}" \ - ${LLDB_TEST_DEBUG_SERVER} \ - ${LLDB_TEST_SUBDIR_CLAUSE} \ - ${LLDB_TEST_CATEGORIES} \ - ${LLDB_DOTEST_CC_OPTS} \ - ${LLDB_FORMATTER_OPTS} \ - --build-dir "${lldb_build_dir}/lldb-test-build.noindex" \ - -t -E "${DOTEST_EXTRA}" - if [[ -x "${LLDB_TEST_SWIFT_COMPATIBILITY}" ]] ; then - echo "Running LLDB swift compatibility tests against" \ - "${LLDB_TEST_SWIFT_COMPATIBILITY}" - call env SWIFTC="$(build_directory $LOCAL_HOST swift)/bin/swiftc" \ - SWIFTLIBS="${swift_build_dir}/lib/swift" \ - "${LLDB_SOURCE_DIR}"/test/dotest.py \ - --executable "${lldb_executable}" \ - ${LLDB_TEST_DEBUG_SERVER} \ - ${LLDB_TEST_SUBDIR_CLAUSE} \ - ${LLDB_TEST_CATEGORIES} \ - ${LLDB_DOTEST_CC_OPTS} \ - ${LLDB_FORMATTER_OPTS} \ - --build-dir "${lldb_build_dir}/lldb-test-build.noindex" \ - -G swift-history \ - --swift-compiler "${LLDB_TEST_SWIFT_COMPATIBILITY}" \ - -t -E "${DOTEST_EXTRA}" - fi - fi + with_pushd ${lldb_build_dir} \ + call ${NINJA_BIN} -j ${BUILD_JOBS} unittests/LLDBUnitTests + with_pushd ${lldb_build_dir} \ + call ${NINJA_BIN} -j ${BUILD_JOBS} lldb-test-deps + with_pushd ${results_dir} \ + call "${llvm_build_dir}/bin/llvm-lit" \ + "${lldb_build_dir}/lit" \ + ${LLVM_LIT_ARGS} + + if [[ -x "${LLDB_TEST_SWIFT_COMPATIBILITY}" ]] ; then + echo "Running LLDB swift compatibility tests against" \ + "${LLDB_TEST_SWIFT_COMPATIBILITY}" + DOTEST_ARGS="-G swift-history --swift-compiler \"${LLDB_TEST_SWIFT_COMPATIBILITY}\"" + with_pushd ${results_dir} \ + call "${llvm_build_dir}/bin/llvm-lit" \ + "${lldb_build_dir}/lit" \ + ${LLVM_LIT_ARGS} \ + --param dotest-args="${DOTEST_ARGS}" \ + --filter=compat + fi continue ;; llbuild) @@ -3583,25 +3415,6 @@ for host in "${ALL_HOSTS[@]}"; do echo "--install-destdir is required to install products." exit 1 fi - if [[ "$using_xcodebuild" == "TRUE" ]] ; then - case ${host} in - linux-*) - ;; - freebsd-*) - ;; - cygwin-*) - ;; - haiku-*) - ;; - macosx-*) - set_lldb_xcodebuild_options - set_lldb_build_mode - with_pushd ${LLDB_SOURCE_DIR} \ - call xcodebuild -target toolchain -configuration ${LLDB_BUILD_MODE} install ${lldb_xcodebuild_options[@]} DSTROOT="${host_install_destdir}" LLDB_TOOLCHAIN_PREFIX="${TOOLCHAIN_PREFIX}" - continue - ;; - esac - fi ;; swiftpm) if [[ -z "${INSTALL_SWIFTPM}" ]] ; then diff --git a/utils/build-windows.bat b/utils/build-windows.bat index fff2ea45503..df3fc73b1ff 100644 --- a/utils/build-windows.bat +++ b/utils/build-windows.bat @@ -145,7 +145,7 @@ cmake "%source_root%\llvm"^ -DCMAKE_BUILD_TYPE=%CMAKE_BUILD_TYPE%^ -DCMAKE_C_COMPILER=cl^ -DCMAKE_CXX_COMPILER=cl^ - -DCMAKE_INSTALL_PREFIX=%install_directory%^ + -DCMAKE_INSTALL_PREFIX:PATH=%install_directory%^ -DLLVM_DEFAULT_TARGET_TRIPLE=x86_64-unknown-windows-msvc^ -DLLVM_ENABLE_PDB:BOOL=YES^ -DLLVM_ENABLE_ASSERTIONS:BOOL=YES^ @@ -215,27 +215,27 @@ cmake "%source_root%\swift"^ -DCMAKE_BUILD_TYPE=%CMAKE_BUILD_TYPE%^ -DCMAKE_C_COMPILER=cl^ -DCMAKE_CXX_COMPILER=cl^ - -DCMAKE_INSTALL_PREFIX=%install_directory%^ - -DClang_DIR=%build_root%\llvm\lib\cmake\clang^ - -DSWIFT_PATH_TO_CMARK_BUILD=%build_root%\cmark^ - -DSWIFT_PATH_TO_CMARK_SOURCE=%source_root%\cmark^ - -DSWIFT_PATH_TO_LIBDISPATCH_SOURCE=%source_root%\swift-corelibs-libdispatch^ - -DLLVM_DIR=%build_root%\llvm\lib\cmake\llvm^ - -DSWIFT_INCLUDE_DOCS=NO^ - -DSWIFT_WINDOWS_x86_64_ICU_UC_INCLUDE=%source_root%\icu-%icu_version%\include\unicode^ - -DSWIFT_WINDOWS_x86_64_ICU_UC=%source_root%\icu-%icu_version%\lib64\icuuc.lib^ - -DSWIFT_WINDOWS_x86_64_ICU_I18N_INCLUDE=%source_root%\icu-%icu_version%\include^ - -DSWIFT_WINDOWS_x86_64_ICU_I18N=%source_root%\icu-%icu_version%\lib64\icuin.lib^ - -DSWIFT_BUILD_DYNAMIC_STDLIB=YES^ - -DSWIFT_BUILD_DYNAMIC_SDK_OVERLAY=YES^ - -DSWIFT_BUILD_STATIC_STDLIB=NO^ - -DSWIFT_BUILD_STATIC_SDK_OVERLAY=NO^ - -DLLVM_INSTALL_TOOLCHAIN_ONLY=YES^ - -DSWIFT_BUILD_SOURCEKIT=YES^ - -DSWIFT_ENABLE_SOURCEKIT_TESTS=NO^ + -DCMAKE_INSTALL_PREFIX:PATH=%install_directory%^ + -DClang_DIR:PATH=%build_root%\llvm\lib\cmake\clang^ + -DSWIFT_PATH_TO_CMARK_BUILD:PATH=%build_root%\cmark^ + -DSWIFT_PATH_TO_CMARK_SOURCE:PATH=%source_root%\cmark^ + -DSWIFT_PATH_TO_LIBDISPATCH_SOURCE:PATH=%source_root%\swift-corelibs-libdispatch^ + -DLLVM_DIR:PATH=%build_root%\llvm\lib\cmake\llvm^ + -DSWIFT_INCLUDE_DOCS:BOOL=NO^ + -DSWIFT_WINDOWS_x86_64_ICU_UC_INCLUDE:PATH=%source_root%\icu-%icu_version%\include\unicode^ + -DSWIFT_WINDOWS_x86_64_ICU_UC:PATH=%source_root%\icu-%icu_version%\lib64\icuuc.lib^ + -DSWIFT_WINDOWS_x86_64_ICU_I18N_INCLUDE:PATH=%source_root%\icu-%icu_version%\include^ + -DSWIFT_WINDOWS_x86_64_ICU_I18N:PATH=%source_root%\icu-%icu_version%\lib64\icuin.lib^ + -DSWIFT_BUILD_DYNAMIC_STDLIB:BOOL=YES^ + -DSWIFT_BUILD_DYNAMIC_SDK_OVERLAY:BOOL=YES^ + -DSWIFT_BUILD_STATIC_STDLIB:BOOL=NO^ + -DSWIFT_BUILD_STATIC_SDK_OVERLAY:BOOL=NO^ + -DLLVM_INSTALL_TOOLCHAIN_ONLY:BOOL=YES^ + -DSWIFT_BUILD_SOURCEKIT:BOOL=YES^ + -DSWIFT_ENABLE_SOURCEKIT_TESTS:BOOL=NO^ -DSWIFT_INSTALL_COMPONENTS="autolink-driver;compiler;clang-resource-dir-symlink;stdlib;sdk-overlay;editor-integration;tools;sourcekit-inproc;swift-remote-mirror;swift-remote-mirror-headers"^ -DSWIFT_PARALLEL_LINK_JOBS=8^ - -DPYTHON_EXECUTABLE=%PYTHON_HOME%\python.exe^ + -DPYTHON_EXECUTABLE:PATH=%PYTHON_HOME%\python.exe^ -DCMAKE_CXX_FLAGS:STRING="/GS- /Oy"^ -DCMAKE_EXE_LINKER_FLAGS:STRING=/INCREMENTAL:NO^ -DCMAKE_SHARED_LINKER_FLAGS:STRING=/INCREMENTAL:NO %exitOnError% @@ -271,21 +271,17 @@ cmake "%source_root%\lldb"^ -DCMAKE_BUILD_TYPE=%CMAKE_BUILD_TYPE%^ -DCMAKE_C_COMPILER=clang-cl^ -DCMAKE_CXX_COMPILER=clang-cl^ - -DCMAKE_INSTALL_PREFIX=%install_directory%^ - -DLLDB_PATH_TO_CMARK_SOURCE=%source_root%\cmark^ - -DLLDB_PATH_TO_CLANG_SOURCE=%source_root%\clang^ - -DLLDB_PATH_TO_LLVM_SOURCE=%source_root%\llvm^ - -DLLDB_PATH_TO_SWIFT_SOURCE=%source_root%\swift^ - -DLLDB_PATH_TO_CMARK_BUILD=%build_root%\cmark^ - -DLLDB_PATH_TO_CLANG_BUILD=%build_root%\llvm^ - -DLLDB_PATH_TO_LLVM_BUILD=%build_root%\llvm^ - -DLLDB_PATH_TO_SWIFT_BUILD=%build_root%\swift^ - -DLLVM_ENABLE_ASSERTIONS=YES^ - -DLLVM_ALLOW_STATIC_BINDINGS=YES^ - -DPYTHON_HOME=%PYTHON_HOME%^ + -DCMAKE_INSTALL_PREFIX:PATH=%install_directory%^ + -DLLVM_DIR:PATH=%build_root%\llvm\lib\cmake\llvm^ + -DClang_DIR:PATH=%build_root%\llvm\lib\cmake\clang^ + -DSwift_DIR:PATH=%build_root%\swift\lib\cmake\swift^ + -DLLVM_ENABLE_ASSERTIONS:BOOL=YES^ + -DLLDB_ALLOW_STATIC_BINDINGS:BOOL=YES^ + -DPYTHON_HOME:PATH=%PYTHON_HOME%^ -DCMAKE_CXX_FLAGS:STRING="/GS- /Oy"^ -DCMAKE_EXE_LINKER_FLAGS:STRING=/INCREMENTAL:NO^ - -DCMAKE_SHARED_LINKER_FLAGS:STRING=/INCREMENTAL:NO %exitOnError% + -DCMAKE_SHARED_LINKER_FLAGS:STRING=/INCREMENTAL:NO^ + -DLLDB_INCLUDE_TESTS:BOOL=NO %exitOnError% popd @@ -296,7 +292,7 @@ goto :eof endlocal -:build_lldb +:build_libdispatch :: Configures, builds, and installs Dispatch setlocal enableextensions enabledelayedexpansion @@ -308,13 +304,13 @@ cmake "%source_root%\swift-corelibs-libdispatch"^ -DCMAKE_BUILD_TYPE=%CMAKE_BUILD_TYPE%^ -DCMAKE_C_COMPILER=clang-cl^ -DCMAKE_CXX_COMPILER=clang-cl^ - -DCMAKE_SWIFT_COMPILER=%install_directory%\bin\swiftc.exe^ - -DSwift_DIR=%build_root%\swift\lib\cmake\swift^ - -DCMAKE_INSTALL_PREFIX=%install_directory%^ - -DBUILD_SHARED_LIBS=YES^ - -DENABLE_TESTING=NO^ + -DCMAKE_SWIFT_COMPILER:PATH=%install_directory%\bin\swiftc.exe^ + -DSwift_DIR:PATH=%build_root%\swift\lib\cmake\swift^ + -DCMAKE_INSTALL_PREFIX:PATH=%install_directory%^ + -DBUILD_SHARED_LIBS:BOOL=YES^ + -DENABLE_TESTING:BOOL=NO^ -DCMAKE_C_COMPILER_TARGET=x86_64-unknown-windows-msvc^ - -DENABLE_SWIFT=YES^ + -DENABLE_SWIFT:BOOL=YES^ -DCMAKE_CXX_FLAGS:STRING="/GS- /Oy"^ -DCMAKE_EXE_LINKER_FLAGS:STRING=/INCREMENTAL:NO^ -DCMAKE_SHARED_LINKER_FLAGS:STRING=/INCREMENTAL:NO %exitOnError% diff --git a/utils/build_swift/defaults.py b/utils/build_swift/defaults.py index 692999f1250..ffc07325ace 100644 --- a/utils/build_swift/defaults.py +++ b/utils/build_swift/defaults.py @@ -40,7 +40,7 @@ BUILD_VARIANT = 'Debug' CMAKE_GENERATOR = 'Ninja' COMPILER_VENDOR = 'none' -SWIFT_USER_VISIBLE_VERSION = CompilerVersion('5.1') +SWIFT_USER_VISIBLE_VERSION = CompilerVersion('5.1.1') CLANG_USER_VISIBLE_VERSION = CompilerVersion('7.0.0') SWIFT_ANALYZE_CODE_COVERAGE = 'false' diff --git a/utils/dev-scripts/csvcolumn_to_scurve.py b/utils/dev-scripts/csvcolumn_to_scurve.py index 621c7a926ae..8ec698e9d29 100755 --- a/utils/dev-scripts/csvcolumn_to_scurve.py +++ b/utils/dev-scripts/csvcolumn_to_scurve.py @@ -14,7 +14,10 @@ def get_data(input_file, before_column, after_column): for row in csv.DictReader(input_file): before = float(row[before_column]) after = float(row[after_column]) - delta = after / before + if before > 0: + delta = after / before + else: + delta = 1 yield delta def f(input_data): diff --git a/utils/gyb_syntax_support/AttributeNodes.py b/utils/gyb_syntax_support/AttributeNodes.py index c185a1da300..750810beb10 100644 --- a/utils/gyb_syntax_support/AttributeNodes.py +++ b/utils/gyb_syntax_support/AttributeNodes.py @@ -62,6 +62,8 @@ ATTRIBUTE_NODES = [ kind='ImplementsAttributeArguments'), Child('NamedAttributeString', kind='NamedAttributeStringArgument'), + Child('OpaqueReturnTypeOfArguments', + kind='OpaqueReturnTypeOfAttributeArguments'), ], description=''' The arguments of the attribute. In case the attribute \ takes multiple arguments, they are gather in the \ @@ -79,6 +81,7 @@ ATTRIBUTE_NODES = [ # attribute-list -> attribute attribute-list? Node('AttributeList', kind='SyntaxCollection', + omit_when_empty=True, element='Syntax', element_name='Attribute', element_choices=[ 'Attribute', @@ -139,12 +142,15 @@ ATTRIBUTE_NODES = [ ]), ]), Node('DeclName', kind='Syntax', children=[ - Child('DeclBaseName', kind='Syntax', description=''' + Child('DeclBaseName', kind='Token', description=''' The base name of the protocol\'s requirement. ''', - node_choices=[ - Child('Identifier', kind='IdentifierToken'), - Child('Operator', kind='PrefixOperatorToken'), + token_choices=[ + 'IdentifierToken', + 'PrefixOperatorToken', + 'PostfixOperatorToken', + 'SpacedBinaryOperatorToken', + 'UnspacedBinaryOperatorToken', ]), Child('DeclNameArguments', kind='DeclNameArguments', is_optional=True, description=''' @@ -196,5 +202,23 @@ ATTRIBUTE_NODES = [ ]), # objc-selector -> objc-selector-piece objc-selector? - Node('ObjCSelector', kind='SyntaxCollection', element='ObjCSelectorPiece') + Node('ObjCSelector', kind='SyntaxCollection', element='ObjCSelectorPiece'), + + # opaque-return-type-of-attr-arguments -> string-literal ',' + # integer-literal + Node('OpaqueReturnTypeOfAttributeArguments', kind='Syntax', + description=''' + The argument for the `@_opaqueReturnTypeOf` type attribute of the \ + form `, `. + ''', + children=[ + Child('MangledName', kind='StringLiteralToken', description=''' + The mangled name of the opaque function/property which the + the type represents. + '''), + Child('Comma', kind='CommaToken'), + Child('Index', kind='IntegerLiteralToken', description=''' + The index of the return type. + '''), + ]), ] diff --git a/utils/gyb_syntax_support/DeclNodes.py b/utils/gyb_syntax_support/DeclNodes.py index 6741725b510..14111b3b45a 100644 --- a/utils/gyb_syntax_support/DeclNodes.py +++ b/utils/gyb_syntax_support/DeclNodes.py @@ -374,6 +374,7 @@ DECL_NODES = [ # | 'weak' # mutation-modifier -> 'mutating' | 'nonmutating' Node('ModifierList', kind='SyntaxCollection', + omit_when_empty=True, element='DeclModifier', element_name='Modifier'), diff --git a/utils/gyb_syntax_support/NodeSerializationCodes.py b/utils/gyb_syntax_support/NodeSerializationCodes.py index fb9edd7ca3e..0e85d0d5c97 100644 --- a/utils/gyb_syntax_support/NodeSerializationCodes.py +++ b/utils/gyb_syntax_support/NodeSerializationCodes.py @@ -236,6 +236,7 @@ SYNTAX_NODE_SERIALIZATION_CODES = { 'GenericRequirement': 232, 'LayoutRequirement': 233, 'LayoutConstraint': 234, + 'OpaqueReturnTypeOfAttributeArguments': 235, } diff --git a/utils/gyb_syntax_support/SILOnlyNodes.py b/utils/gyb_syntax_support/SILOnlyNodes.py index 799ca5c99ee..5c6fa130e60 100644 --- a/utils/gyb_syntax_support/SILOnlyNodes.py +++ b/utils/gyb_syntax_support/SILOnlyNodes.py @@ -1,3 +1,4 @@ +from Child import Child from Node import Node # noqa: I201 # These nodes are used only in SIL parsing. @@ -6,4 +7,43 @@ SILONLY_NODES = [ # generic-parameter-clause-list Node('GenericParameterClauseList', kind='SyntaxCollection', element='GenericParameterClause'), + + # sil-function-type -> generic-parameter-clause-list function-type + Node('SILFunctionType', kind='Type', + children=[ + Child('GenericParameterClauses', + kind='GenericParameterClauseList', + collection_element_name='GenericParameterClause', + is_optional=True), + Child('Function', kind='FunctionType'), + ]), + + # sil-box-type-field + Node('SILBoxTypeField', kind='Syntax', + children=[ + Child('Specifier', kind='Token', + token_choices=[ + 'LetToken', + 'VarToken', + ]), + Child('Type', kind='Type'), + Child('TrailingComma', kind='CommaToken', is_optional=True), + ]), + Node('SILBoxTypeFieldList', kind='SyntaxCollection', + element='SILBoxTypeField'), + + # sil-box-type -> generic-parameter-clause-list '{' + Node('SILBoxType', kind='Type', + children=[ + Child('GenericParameterClauses', + kind='GenericParameterClauseList', + collection_element_name='GenericParameterClause', + is_optional=True), + Child('LeftBrace', kind='LeftBraceToken'), + Child('Fields', kind='SILBoxTypeFieldList', + collection_element_name='Field'), + Child('RightBrace', kind='RightBraceToken'), + Child('GenericArgumentClause', kind='GenericArgumentClause', + is_optional=True), + ]), ] diff --git a/utils/gyb_syntax_support/__init__.py b/utils/gyb_syntax_support/__init__.py index 0611331faa3..a5d466c8f15 100644 --- a/utils/gyb_syntax_support/__init__.py +++ b/utils/gyb_syntax_support/__init__.py @@ -156,7 +156,7 @@ def create_node_map(): """ Creates a lookup table to find nodes by their kind. """ - return {node.syntax_kind: node for node in SYNTAX_NODES} + return {node.syntax_kind: node for node in SYNTAX_NODES + PARSEONLY_NODES} def is_visitable(node): diff --git a/utils/update_checkout/update-checkout-config.json b/utils/update_checkout/update-checkout-config.json index 610114297c7..ca4c70f4e70 100644 --- a/utils/update_checkout/update-checkout-config.json +++ b/utils/update_checkout/update-checkout-config.json @@ -403,16 +403,17 @@ "sourcekit-lsp": "swift-5.1-branch" } }, - "master-rebranch" : { + "master-20190619" : { "aliases": ["apple/stable/20190619", - "master-rebranch-apple-stable-20190619", - "master-rebranch"], + "master-apple-stable-20190619", + "master-20190619" + ], "repos": { "llvm": "apple/stable/20190619", "clang": "apple/stable/20190619", "compiler-rt": "apple/stable/20190619", - "swift": "master-rebranch", - "lldb": "master-rebranch", + "swift": "master", + "lldb": "stable", "cmark": "master", "llbuild": "master", "swiftpm": "master", @@ -421,7 +422,7 @@ "swift-corelibs-xctest": "master", "swift-corelibs-foundation": "master", "swift-corelibs-libdispatch": "master", - "swift-integration-tests": "master-rebranch", + "swift-integration-tests": "master", "swift-xcode-playground-support": "master", "ninja": "release", "icu": "release-61-1", @@ -429,7 +430,8 @@ "clang-tools-extra": "apple/stable/20190619", "libcxx": "apple/stable/20190619", "indexstore-db": "master", - "sourcekit-lsp": "master" + "sourcekit-lsp": "master", + "swift-format": "master" } }, "stdlib_standalone" : { diff --git a/utils/viewcfg b/utils/viewcfg index db593bb2a6e..9734b24ae7e 100755 --- a/utils/viewcfg +++ b/utils/viewcfg @@ -97,7 +97,7 @@ def main(): cur_block = None sil_block_pattern = re.compile(r'^(\S+)(\(.*\))?: *(\/\/ *Preds:(.*))?$') llvm_block_pattern1 = re.compile(r'^"?([^\s"]+)"?: *; *preds =(.*)?$') - llvm_block_pattern2 = re.compile(r'^;