diff --git a/docs/ABI/Mangling.rst b/docs/ABI/Mangling.rst
index ee99f99911ba0..a65799b8c53cd 100644
--- a/docs/ABI/Mangling.rst
+++ b/docs/ABI/Mangling.rst
@@ -1047,3 +1047,63 @@ Some kinds need arguments, which precede ``Tf``.
If the first character of the string literal is a digit ``[0-9]`` or an
underscore ``_``, the identifier for the string literal is prefixed with an
additional underscore ``_``.
+
+Conventions for foreign symbols
+-------------------------------
+
+Swift interoperates with multiple other languages - C, C++, Objective-C, and
+Objective-C++. Each of these languages defines their own mangling conventions,
+so Swift must take care to follow them. However, these conventions do not cover
+Swift-specific symbols like Swift type metadata for foreign types, so Swift uses
+its own mangling scheme for those symbols.
+
+Importing C and C++ structs
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Types imported from C and C++ are imported as if they are located in the ``__C``
+module, regardless of the actual Clang module that they are coming from. This
+can be observed when mangling a Swift function that accepts a C/C++ struct as a
+parameter:
+
+C++ module ``CxxStructModule``:
+
+.. code-block:: c++
+
+ struct CxxStruct {};
+
+ inline void cxxFunction(CxxStruct s) {}
+
+Swift module ``main`` that imports ``CxxStructModule``:
+
+.. code-block:: swift
+
+ import CxxStructModule
+
+ public func swiftFunction(_ s: CxxStruct) {}
+
+Resulting symbols (showing only Itanium-mangled C++ symbols for brevity):
+
+.. code::
+
+ _Z11cxxFunction9CxxStruct // -> cxxFunction(CxxStruct)
+ s4main13swiftFunctionyySo9CxxStructVF // -> main.swiftFunction(__C.CxxStruct) -> ()
+
+The reason for ignoring the Clang module and always putting C and C++ types into
+``__C`` at the Swift ABI level is that the Clang module is not a part of the C
+or C++ ABI. When owners of C and C++ Clang modules decide what changes are
+ABI-compatible or not, they will likely take into account C and C++ ABI, but not
+the Swift ABI. Therefore, Swift ABI can only encode information about a C or C++
+type that the C and C++ ABI already encodes in order to remain compatible with
+future versions of libraries that evolve according to C and C++ ABI
+compatibility principles.
+
+The C/C++ compiler does not generate Swift metadata symbols and value witness
+tables for C and C++ types. To make a foreign type usable in Swift in the same
+way as a native type, the Swift compiler must generate these symbols.
+Specifically, each Swift module that uses a given C or C++ type generates the
+necessary Swift symbols. For the example above the Swift compiler will generate following
+nominal type descriptor symbol for ``CxxStruct`` while compiling the ``main`` module:
+
+.. code::
+
+ sSo9CxxStructVMn // -> nominal type descriptor for __C.CxxStruct
diff --git a/docs/ContinuousIntegration.md b/docs/ContinuousIntegration.md
index 27685776f6b2d..e83a28a47d0d4 100644
--- a/docs/ContinuousIntegration.md
+++ b/docs/ContinuousIntegration.md
@@ -106,9 +106,11 @@ macOS platform | @swift-ci Please smoke benchmark | S
Linux platform | @swift-ci Please test Linux platform | Swift Test Linux Platform (smoke test)
Swift Test Linux Platform
Linux platform | @swift-ci Please clean test Linux platform | Swift Test Linux Platform (smoke test)
Swift Test Linux Platform
macOS platform | @swift-ci Please ASAN test | Swift ASAN Test OS X Platform
-Ubuntu 20.04 | @swift-ci Please test Ubuntu 20.04 platform | Swift Test Ubuntu 20.04 Platform
-CentOS 8 | @swift-ci Please test CentOS 8 platform | Swift Test CentOS 8 Platform
-Amazon Linux 2 | @swift-ci Please test Amazon Linux 2 platform | Swift Test Amazon Linux 2 Platform
+Ubuntu 18.04 | @swift-ci Please test Ubuntu 18.04 platform | Swift Test Ubuntu 18.04 Platform
+Ubuntu 20.04 | @swift-ci Please test Ubuntu 20.04 platform | Swift Test Ubuntu 20.04 Platform
+CentOS 7 | @swift-ci Please test CentOS 7 platform | Swift Test CentOS 7 Platform
+CentOS 8 | @swift-ci Please test CentOS 8 platform | Swift Test CentOS 8 Platform
+Amazon Linux 2 | @swift-ci Please test Amazon Linux 2 platform | Swift Test Amazon Linux 2 Platform
The core principles of validation testing is that:
diff --git a/docs/DifferentiableProgramming.md b/docs/DifferentiableProgramming.md
index 0e1196f138cca..26d2e99fca2fb 100644
--- a/docs/DifferentiableProgramming.md
+++ b/docs/DifferentiableProgramming.md
@@ -893,8 +893,15 @@ extension Perceptron {
### `@differentiable` function types
-A subtype of normal function types with a different runtime representation,
-which stores metadata that allows their values to be differentiated anywhere.
+Differentiable functions are first-class values, identified by a
+`@differentiable` attribute in the function type. A `@differentiable` function
+type is a subtype of its corresponding normal function type (i.e. without a
+`@differentiable` attribute) with an extended ABI, which stores metadata that
+allows their values to be differentiated anywhere the function is passed. A
+`@differentiable(linear)` function type is a subtype of its corresponding
+`@differentiable` function type. A normal function can be implicitly converted
+to a `@differentiable` or `@differentiable(linear)` function with appropriate
+compile-time checks.
```swift
func addOne(_ x: Float) -> Float { x + 1 }
@@ -920,8 +927,9 @@ func _(_ x: Float) -> (value: Float,
### Differential operators
-Standard library differentiation APIs that take `@differentiable` functions and
-return derivative functions or compute derivative values.
+Differential operators are APIs defined in the standard library that take
+`@differentiable` functions and return derivative functions or compute
+derivative values.
```swift
// In the standard library:
@@ -2318,7 +2326,7 @@ As shown in the
subsection, a `@differentiable` function value's runtime representation contains
the original function along with extra information that allows the function to
be differentiated (or transposed, if it is `@differentiable(linear)`). A
-@differentiable or `@differentiable(linear)` function value can be called like a
+`@differentiable` or `@differentiable(linear)` function value can be called like a
non-`@differentiable` function. A `@differentiable(linear)` function value can
be implicitly converted to a `@differentiable` one, which can be implicitly
converted to a non-`@differentiable` one.
diff --git a/docs/README.md b/docs/README.md
index 1492d1ef48430..b3e2c3f976d4d 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -105,7 +105,7 @@ documentation, please create a thread on the Swift forums under the
- [RequestEvaluator.md](/docs/RequestEvaluator.md):
Describes the request evaluator architecture, which is used for
lazy type-checking and efficient caching.
- - [Literal.md](/docs/Literal.md):
+ - [Literals.md](/docs/Literals.md):
Describes type-checking and inference specifically for literals.
- [Serialization.rst](/docs/Serialization.rst):
Gives an overview of the LLVM bitcode format used for swiftmodules.
@@ -117,7 +117,7 @@ documentation, please create a thread on the Swift forums under the
Provides an overview of the implementation of SIL in the compiler.
- [OptimizerDesign.md](/docs/OptimizerDesign.md):
Describes the design of the optimizer pipeline.
- - [HighLevelSILOptimizations.rst](docs/HighLevelSILOptimizations.rst):
+ - [HighLevelSILOptimizations.rst](/docs/HighLevelSILOptimizations.rst):
Describes how the optimizer understands the semantics of high-level
operations on currency data types and optimizes accordingly.
Includes a thorough discussion of the `@_semantics` attribute.
diff --git a/include/swift/AST/DiagnosticEngine.h b/include/swift/AST/DiagnosticEngine.h
index ef9160641981e..ee3c776cd9db6 100644
--- a/include/swift/AST/DiagnosticEngine.h
+++ b/include/swift/AST/DiagnosticEngine.h
@@ -24,6 +24,8 @@
#include "swift/AST/TypeLoc.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Allocator.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/VersionTuple.h"
namespace swift {
@@ -742,8 +744,26 @@ namespace swift {
void setLocalization(std::string locale, std::string path) {
assert(!locale.empty());
assert(!path.empty());
- localization =
- std::make_unique(locale, path);
+ llvm::SmallString<128> filePath(path);
+ llvm::sys::path::append(filePath, locale);
+ llvm::sys::path::replace_extension(filePath, ".db");
+
+ // If the serialized diagnostics file not available,
+ // fallback to the `YAML` file.
+ if (llvm::sys::fs::exists(filePath)) {
+ if (auto file = llvm::MemoryBuffer::getFile(filePath)) {
+ localization = std::make_unique(
+ std::move(file.get()));
+ }
+ } else {
+ llvm::sys::path::replace_extension(filePath, ".yaml");
+ // In case of missing localization files, we should fallback to messages
+ // from `.def` files.
+ if (llvm::sys::fs::exists(filePath)) {
+ localization =
+ std::make_unique(filePath.str());
+ }
+ }
}
void ignoreDiagnostic(DiagID id) {
diff --git a/include/swift/AST/DiagnosticsCommon.def b/include/swift/AST/DiagnosticsCommon.def
index 788fb0e09f767..cdeef09e3058e 100644
--- a/include/swift/AST/DiagnosticsCommon.def
+++ b/include/swift/AST/DiagnosticsCommon.def
@@ -178,5 +178,12 @@ WARNING(cross_imported_by_both_modules, none,
"please report this bug to the maintainers of these modules",
(Identifier, Identifier, Identifier))
+//------------------------------------------------------------------------------
+// MARK: dependencies scanner diagnostics
+//------------------------------------------------------------------------------
+
+ERROR(scanner_find_cycle, none,
+ "dependency scanner detected dependency cycle: '%0'", (StringRef))
+
#define UNDEFINE_DIAGNOSTIC_MACROS
#include "DefineDiagnosticMacros.h"
diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def
index 0c8d0df993b8c..8eaafddc06e5a 100644
--- a/include/swift/AST/DiagnosticsSema.def
+++ b/include/swift/AST/DiagnosticsSema.def
@@ -88,6 +88,13 @@ ERROR(could_not_find_subscript_member_did_you_mean,none,
"did you mean to use the subscript operator?",
(Type))
+ERROR(could_not_find_subscript_member_tuple, none,
+ "cannot access element using subscript for tuple type %0; "
+ "use '.' notation instead", (Type))
+ERROR(could_not_find_subscript_member_tuple_did_you_mean_use_dot, none,
+ "cannot access element using subscript for tuple type %0; "
+ "did you mean to use '.%1'?", (Type, StringRef))
+
ERROR(could_not_find_enum_case,none,
"enum type %0 has no case %1; did you mean %2?",
(Type, DeclNameRef, DeclName))
@@ -2835,7 +2842,8 @@ NOTE(codable_extraneous_codingkey_case_here,none,
NOTE(codable_non_conforming_property_here,none,
"cannot automatically synthesize %0 because %1 does not conform to %0", (Type, TypeLoc))
NOTE(codable_non_decoded_property_here,none,
- "cannot automatically synthesize %0 because %1 does not have a matching CodingKey and does not have a default value", (Type, Identifier))
+ "cannot automatically synthesize %0 because %1 does not have a matching "
+ "CodingKey and does not have a default value", (Type, Identifier))
NOTE(codable_codingkeys_type_is_not_an_enum_here,none,
"cannot automatically synthesize %0 because 'CodingKeys' is not an enum", (Type))
NOTE(codable_codingkeys_type_does_not_conform_here,none,
@@ -4064,10 +4072,13 @@ ERROR(throw_in_nonexhaustive_catch,none,
"error is not handled because the enclosing catch is not exhaustive", ())
ERROR(throwing_call_in_illegal_context,none,
- "call can throw, but errors cannot be thrown out of %0",
- (StringRef))
+ "call can throw, but errors cannot be thrown out of "
+ "%select{<>|a default argument|a property initializer|a global variable initializer|an enum case raw value|a catch pattern|a catch guard expression|a defer body}0",
+ (unsigned))
ERROR(throw_in_illegal_context,none,
- "errors cannot be thrown out of %0", (StringRef))
+ "errors cannot be thrown out of "
+ "%select{<>|a default argument|a property initializer|a global variable initializer|an enum case raw value|a catch pattern|a catch guard expression|a defer body}0",
+ (unsigned))
ERROR(throwing_operator_without_try,none,
"operator can throw but expression is not marked with 'try'", ())
@@ -4716,6 +4727,11 @@ ERROR(availability_decl_unavailable, none,
"%select{ in %3|}2%select{|: %4}4",
(unsigned, DeclName, bool, StringRef, StringRef))
+WARNING(availability_decl_unavailable_warn, none,
+ "%select{getter for |setter for |}0%1 is unavailable"
+ "%select{ in %3|}2%select{|: %4}4",
+ (unsigned, DeclName, bool, StringRef, StringRef))
+
#define REPLACEMENT_DECL_KIND_SELECT "select{| instance method| property}"
ERROR(availability_decl_unavailable_rename, none,
"%select{getter for |setter for |}0%1 has been "
@@ -4723,6 +4739,12 @@ ERROR(availability_decl_unavailable_rename, none,
"'%4'%select{|: %5}5",
(unsigned, DeclName, bool, unsigned, StringRef, StringRef))
+WARNING(availability_decl_unavailable_rename_warn, none,
+ "%select{getter for |setter for |}0%1 has been "
+ "%select{renamed to|replaced by}2%" REPLACEMENT_DECL_KIND_SELECT "3 "
+ "'%4'%select{|: %5}5",
+ (unsigned, DeclName, bool, unsigned, StringRef, StringRef))
+
NOTE(availability_marked_unavailable, none,
"%select{getter for |setter for |}0%1 has been explicitly marked "
"unavailable here", (unsigned, DeclName))
diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h
index a62c045674a18..a75d9d56b39e4 100644
--- a/include/swift/AST/Expr.h
+++ b/include/swift/AST/Expr.h
@@ -861,9 +861,6 @@ class StringLiteralExpr : public LiteralExpr {
/// A UTF-8 string.
UTF8,
- /// A UTF-16 string.
- UTF16,
-
/// A single UnicodeScalar, passed as an integer.
OneUnicodeScalar
};
@@ -5259,6 +5256,7 @@ class KeyPathExpr : public Expr {
OptionalWrap,
Identity,
TupleElement,
+ DictionaryKey,
};
private:
@@ -5367,6 +5365,16 @@ class KeyPathExpr : public Expr {
propertyType,
loc);
}
+
+ /// Create a component for a dictionary key (#keyPath only).
+ static Component forDictionaryKey(DeclNameRef UnresolvedName,
+ Type valueType,
+ SourceLoc loc) {
+ return Component(nullptr, UnresolvedName, nullptr, {}, {},
+ Kind::DictionaryKey,
+ valueType,
+ loc);
+ }
/// Create a component for a subscript.
static Component forSubscript(ASTContext &ctx,
@@ -5457,6 +5465,7 @@ class KeyPathExpr : public Expr {
case Kind::Property:
case Kind::Identity:
case Kind::TupleElement:
+ case Kind::DictionaryKey:
return true;
case Kind::UnresolvedSubscript:
@@ -5481,6 +5490,7 @@ class KeyPathExpr : public Expr {
case Kind::Property:
case Kind::Identity:
case Kind::TupleElement:
+ case Kind::DictionaryKey:
return nullptr;
}
llvm_unreachable("unhandled kind");
@@ -5500,6 +5510,7 @@ class KeyPathExpr : public Expr {
case Kind::Property:
case Kind::Identity:
case Kind::TupleElement:
+ case Kind::DictionaryKey:
llvm_unreachable("no subscript labels for this kind");
}
llvm_unreachable("unhandled kind");
@@ -5522,6 +5533,7 @@ class KeyPathExpr : public Expr {
case Kind::Property:
case Kind::Identity:
case Kind::TupleElement:
+ case Kind::DictionaryKey:
return {};
}
llvm_unreachable("unhandled kind");
@@ -5533,6 +5545,7 @@ class KeyPathExpr : public Expr {
DeclNameRef getUnresolvedDeclName() const {
switch (getKind()) {
case Kind::UnresolvedProperty:
+ case Kind::DictionaryKey:
return Decl.UnresolvedName;
case Kind::Invalid:
@@ -5563,6 +5576,7 @@ class KeyPathExpr : public Expr {
case Kind::OptionalForce:
case Kind::Identity:
case Kind::TupleElement:
+ case Kind::DictionaryKey:
llvm_unreachable("no decl ref for this kind");
}
llvm_unreachable("unhandled kind");
@@ -5582,6 +5596,7 @@ class KeyPathExpr : public Expr {
case Kind::Identity:
case Kind::Property:
case Kind::Subscript:
+ case Kind::DictionaryKey:
llvm_unreachable("no field number for this kind");
}
llvm_unreachable("unhandled kind");
diff --git a/include/swift/AST/GenericSignatureBuilder.h b/include/swift/AST/GenericSignatureBuilder.h
index 1cf1d535d5f4a..e91543b476539 100644
--- a/include/swift/AST/GenericSignatureBuilder.h
+++ b/include/swift/AST/GenericSignatureBuilder.h
@@ -751,7 +751,7 @@ class GenericSignatureBuilder {
/// \param resolutionKind How to perform the resolution.
///
/// \param wantExactPotentialArchetype Whether to return the precise
- /// potential archetype described by the type (vs. just the equivalance
+ /// potential archetype described by the type (vs. just the equivalence
/// class and resolved type).
ResolvedType maybeResolveEquivalenceClass(
Type type,
diff --git a/include/swift/AST/IRGenOptions.h b/include/swift/AST/IRGenOptions.h
index d03c1310cf8e8..3d1facf4e6a60 100644
--- a/include/swift/AST/IRGenOptions.h
+++ b/include/swift/AST/IRGenOptions.h
@@ -139,6 +139,12 @@ struct PointerAuthOptions : clang::PointerAuthOptions {
PointerAuthSchema ResilientClassStubInitCallbacks;
};
+enum class JITDebugArtifact : unsigned {
+ None, ///< None
+ LLVMIR, ///< LLVM IR
+ Object, ///< Object File
+};
+
/// The set of options supported by IR generation.
class IRGenOptions {
public:
@@ -326,6 +332,8 @@ class IRGenOptions {
Optional AutolinkRuntimeCompatibilityLibraryVersion;
Optional AutolinkRuntimeCompatibilityDynamicReplacementLibraryVersion;
+ JITDebugArtifact DumpJIT = JITDebugArtifact::None;
+
IRGenOptions()
: DWARFVersion(2), OutputKind(IRGenOutputKind::LLVMAssembly),
Verify(true), OptMode(OptimizationMode::NotSet),
diff --git a/include/swift/AST/LocalizationFormat.h b/include/swift/AST/LocalizationFormat.h
index a4205bb85be72..efd3d5345467f 100644
--- a/include/swift/AST/LocalizationFormat.h
+++ b/include/swift/AST/LocalizationFormat.h
@@ -1,5 +1,4 @@
-//===--- LocalizationFormat.h - YAML format for Diagnostic Messages ---*-
-// C++ -*-===//
+//===--- LocalizationFormat.h - Format for Diagnostic Messages --*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
@@ -18,16 +17,127 @@
#ifndef SWIFT_LOCALIZATIONFORMAT_H
#define SWIFT_LOCALIZATIONFORMAT_H
+#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Bitstream/BitstreamReader.h"
+#include "llvm/Support/EndianStream.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/OnDiskHashTable.h"
#include "llvm/Support/YAMLParser.h"
#include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/raw_ostream.h"
+#include
+#include
#include
#include
+#include
+#include
namespace swift {
enum class DiagID : uint32_t;
namespace diag {
+
+using namespace llvm::support;
+
+class LocalizationWriterInfo {
+public:
+ using key_type = uint32_t;
+ using key_type_ref = const uint32_t &;
+ using data_type = std::string;
+ using data_type_ref = llvm::StringRef;
+ using hash_value_type = uint32_t;
+ using offset_type = uint32_t;
+
+ hash_value_type ComputeHash(key_type_ref key) { return llvm::hash_code(key); }
+
+ std::pair EmitKeyDataLength(llvm::raw_ostream &out,
+ key_type_ref key,
+ data_type_ref data) {
+ offset_type dataLength = static_cast(data.size());
+ endian::write(out, dataLength, little);
+ // No need to write the key length; it's constant.
+ return {sizeof(key_type), dataLength};
+ }
+
+ void EmitKey(llvm::raw_ostream &out, key_type_ref key, unsigned len) {
+ assert(len == sizeof(key_type));
+ endian::write(out, key, little);
+ }
+
+ void EmitData(llvm::raw_ostream &out, key_type_ref key, data_type_ref data,
+ unsigned len) {
+ out << data;
+ }
+};
+
+class LocalizationReaderInfo {
+public:
+ using internal_key_type = uint32_t;
+ using external_key_type = swift::DiagID;
+ using data_type = llvm::StringRef;
+ using hash_value_type = uint32_t;
+ using offset_type = uint32_t;
+
+ internal_key_type GetInternalKey(external_key_type key) {
+ return static_cast(key);
+ }
+
+ external_key_type GetExternalKey(internal_key_type key) {
+ return static_cast(key);
+ }
+
+ static bool EqualKey(internal_key_type lhs, internal_key_type rhs) {
+ return lhs == rhs;
+ }
+
+ hash_value_type ComputeHash(internal_key_type key) {
+ return llvm::hash_code(key);
+ }
+
+ static std::pair
+ ReadKeyDataLength(const unsigned char *&data) {
+ offset_type dataLength =
+ endian::readNext(data);
+ return {sizeof(uint32_t), dataLength};
+ }
+
+ internal_key_type ReadKey(const unsigned char *data, offset_type length) {
+ return endian::readNext(data);
+ }
+
+ data_type ReadData(internal_key_type Key, const unsigned char *data,
+ offset_type length) {
+ return data_type((const char *)data, length);
+ }
+};
+
+class SerializedLocalizationWriter {
+ using offset_type = LocalizationWriterInfo::offset_type;
+ llvm::OnDiskChainedHashTableGenerator generator;
+
+public:
+ /// Enqueue the given diagnostic to be included in a serialized translations
+ /// file.
+ ///
+ /// \param id The identifier associated with the given diagnostic message e.g.
+ /// 'cannot_convert_argument'.
+ /// \param translation The localized diagnostic message for the given
+ /// identifier.
+ void insert(swift::DiagID id, llvm::StringRef translation);
+
+ /// Write out previously inserted diagnostic translations into the given
+ /// location.
+ ///
+ /// \param filePath The location of the serialized diagnostics file. It's
+ /// supposed to be a file with '.db' postfix.
+ /// \returns true if all diagnostic
+ /// messages have been successfully serialized, false otherwise.
+ bool emit(llvm::StringRef filePath);
+};
+
class LocalizationProducer {
public:
/// If the message isn't available/localized in the current `yaml` file,
@@ -41,9 +151,33 @@ class LocalizationProducer {
};
class YAMLLocalizationProducer final : public LocalizationProducer {
-public:
std::vector diagnostics;
- explicit YAMLLocalizationProducer(std::string locale, std::string path);
+
+public:
+ /// The diagnostics IDs that are no longer available in `.def`
+ std::vector unknownIDs;
+ explicit YAMLLocalizationProducer(llvm::StringRef filePath);
+ llvm::StringRef getMessageOr(swift::DiagID id,
+ llvm::StringRef defaultMessage) const override;
+
+ /// Iterate over all of the available (non-empty) translations
+ /// maintained by this producer, callback gets each translation
+ /// with its unique identifier.
+ void forEachAvailable(
+ llvm::function_ref callback) const;
+};
+
+class SerializedLocalizationProducer final : public LocalizationProducer {
+ using SerializedLocalizationTable =
+ llvm::OnDiskIterableChainedHashTable;
+ using offset_type = LocalizationReaderInfo::offset_type;
+ std::unique_ptr Buffer;
+ std::unique_ptr SerializedTable;
+
+public:
+ explicit SerializedLocalizationProducer(
+ std::unique_ptr buffer);
+
llvm::StringRef getMessageOr(swift::DiagID id,
llvm::StringRef defaultMessage) const override;
};
@@ -55,12 +189,23 @@ class LocalizationInput : public llvm::yaml::Input {
template
friend typename std::enable_if::value,
void>::type
- readYAML(llvm::yaml::IO &io, T &Seq, bool, Context &Ctx);
+ readYAML(llvm::yaml::IO &io, T &Seq, T &unknownIDs, bool, Context &Ctx);
template
friend typename std::enable_if::value,
LocalizationInput &>::type
operator>>(LocalizationInput &yin, T &diagnostics);
+
+public:
+ /// A vector that keeps track of the diagnostics IDs that are available in
+ /// YAML and not available in `.def` files.
+ std::vector unknownIDs;
+
+ /// A diagnostic ID might be present in YAML and not in `.def` file, if that's
+ /// the case the `id` won't have a `DiagID` value.
+ /// If the `id` is available in `.def` file this method will return the `id`'s
+ /// value, otherwise this method won't return a value.
+ static llvm::Optional readID(llvm::yaml::IO &io);
};
} // namespace diag
diff --git a/include/swift/AST/NameLookup.h b/include/swift/AST/NameLookup.h
index 57e6c63740d5c..ea847ce01c1ba 100644
--- a/include/swift/AST/NameLookup.h
+++ b/include/swift/AST/NameLookup.h
@@ -512,14 +512,6 @@ void recordLookupOfTopLevelName(DeclContext *topLevelContext, DeclName name,
} // end namespace namelookup
-/// Retrieve the set of nominal type declarations that are directly
-/// referenced in the given \c typeRepr, looking through typealiases.
-///
-/// \param dc The \c DeclContext from which to perform lookup.
-TinyPtrVector
-getDirectlyReferencedNominalTypeDecls(ASTContext &ctx, TypeRepr *typeRepr,
- DeclContext *dc, bool &anyObject);
-
/// Retrieve the set of nominal type declarations that are directly
/// "inherited" by the given declaration at a particular position in the
/// list of "inherited" types.
diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h
index 5fd6baee95994..90e0e814d0f32 100644
--- a/include/swift/Basic/LangOptions.h
+++ b/include/swift/Basic/LangOptions.h
@@ -390,6 +390,12 @@ namespace swift {
/// Load swiftmodule files in memory as volatile and avoid mmap.
bool EnableVolatileModules = false;
+ /// Allow deserializing implementation only dependencies. This should only
+ /// be set true by lldb and other tooling, so that deserilization
+ /// recovery issues won't bring down the debugger.
+ /// TODO: remove this when @_implementationOnly modules are robust enough.
+ bool AllowDeserializingImplementationOnly = false;
+
/// Sets the target we are building for and updates platform conditions
/// to match.
///
diff --git a/include/swift/Basic/Unicode.h b/include/swift/Basic/Unicode.h
index ff2163eb0f374..4b1108af7fac1 100644
--- a/include/swift/Basic/Unicode.h
+++ b/include/swift/Basic/Unicode.h
@@ -68,10 +68,6 @@ bool isSingleUnicodeScalar(StringRef S);
unsigned extractFirstUnicodeScalar(StringRef S);
-/// Get the length of the UTF8 string transcoded into UTF16.
-/// Returns the number of code units in UTF16 representation
-uint64_t getUTF16Length(StringRef Str);
-
} // end namespace unicode
} // end namespace swift
diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td
index 76cd3658ee615..5bd693d2ffe7d 100644
--- a/include/swift/Option/FrontendOptions.td
+++ b/include/swift/Option/FrontendOptions.td
@@ -329,6 +329,9 @@ def disable_llvm_verify : Flag<["-"], "disable-llvm-verify">,
def disable_llvm_value_names : Flag<["-"], "disable-llvm-value-names">,
HelpText<"Don't add names to local values in LLVM IR">;
+def dump_jit : JoinedOrSeparate<["-"], "dump-jit">,
+ HelpText<"Dump JIT contents">;
+
def enable_llvm_value_names : Flag<["-"], "enable-llvm-value-names">,
HelpText<"Add names to local values in LLVM IR">;
diff --git a/include/swift/Runtime/ObjCBridge.h b/include/swift/Runtime/ObjCBridge.h
index 33e5022463434..a24fb03feeb9d 100644
--- a/include/swift/Runtime/ObjCBridge.h
+++ b/include/swift/Runtime/ObjCBridge.h
@@ -68,6 +68,9 @@ OBJC_EXPORT Class objc_readClassPair(Class cls,
const struct objc_image_info *info)
__OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0);
+// Magic symbol whose _address_ is the runtime's isa mask.
+OBJC_EXPORT const struct { char c; } objc_absolute_packed_isa_class_mask;
+
namespace swift {
diff --git a/include/swift/SIL/SILFunction.h b/include/swift/SIL/SILFunction.h
index ae3f940d21ad4..8125736fc391f 100644
--- a/include/swift/SIL/SILFunction.h
+++ b/include/swift/SIL/SILFunction.h
@@ -274,6 +274,9 @@ class SILFunction
/// that it may have unboxed capture (i.e. @inout_aliasable parameters).
unsigned IsWithoutActuallyEscapingThunk : 1;
+ /// True if this function is an async function.
+ unsigned IsAsync : 1;
+
/// If != OptimizationMode::NotSet, the optimization mode specified with an
/// function attribute.
unsigned OptMode : NumOptimizationModeBits;
@@ -501,6 +504,10 @@ class SILFunction
IsWithoutActuallyEscapingThunk = val;
}
+ bool isAsync() const { return IsAsync; }
+
+ void setAsync(bool val = true) { IsAsync = val; }
+
/// Returns the calling convention used by this entry point.
SILFunctionTypeRepresentation getRepresentation() const {
return getLoweredFunctionType()->getRepresentation();
diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h
index dd9e3731b9ac9..d504f37085831 100644
--- a/include/swift/SIL/SILInstruction.h
+++ b/include/swift/SIL/SILInstruction.h
@@ -3307,7 +3307,6 @@ class StringLiteralInst final
enum class Encoding {
Bytes,
UTF8,
- UTF16,
/// UTF-8 encoding of an Objective-C selector.
ObjCSelector,
};
diff --git a/include/swift/SIL/SILValue.h b/include/swift/SIL/SILValue.h
index 37064391dd50a..751484a90e175 100644
--- a/include/swift/SIL/SILValue.h
+++ b/include/swift/SIL/SILValue.h
@@ -41,6 +41,7 @@ class SILLocation;
class DeadEndBlocks;
class ValueBaseUseIterator;
class ValueUseIterator;
+class SILValue;
/// An enumeration which contains values for all the concrete ValueBase
/// subclasses.
@@ -188,6 +189,12 @@ struct ValueOwnershipKind {
return merge(other).hasValue();
}
+ /// Returns isCompatibleWith(other.getOwnershipKind()).
+ ///
+ /// Definition is inline after SILValue is defined to work around circular
+ /// dependencies.
+ bool isCompatibleWith(SILValue other) const;
+
template
static Optional merge(RangeTy &&r) {
auto initial = Optional(ValueOwnershipKind::None);
@@ -440,6 +447,10 @@ class SILValue {
void verifyOwnership(DeadEndBlocks *DEBlocks = nullptr) const;
};
+inline bool ValueOwnershipKind::isCompatibleWith(SILValue other) const {
+ return isCompatibleWith(other.getOwnershipKind());
+}
+
/// A map from a ValueOwnershipKind that an operand can accept to a
/// UseLifetimeConstraint that describes the effect that the operand's use has
/// on the underlying value. If a ValueOwnershipKind is not in this map then
diff --git a/include/swift/SILOptimizer/Utils/SILSSAUpdater.h b/include/swift/SILOptimizer/Utils/SILSSAUpdater.h
index f222f2309cc79..6cac152cd8ce4 100644
--- a/include/swift/SILOptimizer/Utils/SILSSAUpdater.h
+++ b/include/swift/SILOptimizer/Utils/SILSSAUpdater.h
@@ -18,9 +18,14 @@
#include "swift/SIL/SILValue.h"
namespace llvm {
- template class SSAUpdaterTraits;
- template class SmallVectorImpl;
-}
+
+template
+class SSAUpdaterTraits;
+
+template
+class SmallVectorImpl;
+
+} // namespace llvm
namespace swift {
@@ -31,7 +36,7 @@ class SILUndef;
/// Independent utility that canonicalizes BB arguments by reusing structurally
/// equivalent arguments and replacing the original arguments with casts.
-SILValue replaceBBArgWithCast(SILPhiArgument *Arg);
+SILValue replaceBBArgWithCast(SILPhiArgument *arg);
/// This class updates SSA for a set of SIL instructions defined in multiple
/// blocks.
@@ -40,16 +45,16 @@ class SILSSAUpdater {
// A map of basic block to available phi value.
using AvailableValsTy = llvm::DenseMap;
- std::unique_ptr AV;
+ std::unique_ptr blockToAvailableValueMap;
- SILType ValType;
+ SILType type;
// The SSAUpdaterTraits specialization uses this sentinel to mark 'new' phi
// nodes (all the incoming edge arguments have this sentinel set).
- std::unique_ptr PHISentinel;
+ std::unique_ptr phiSentinel;
// If not null updated with inserted 'phi' nodes (SILArgument).
- SmallVectorImpl *InsertedPHIs;
+ SmallVectorImpl *insertedPhis;
// Not copyable.
void operator=(const SILSSAUpdater &) = delete;
@@ -57,21 +62,21 @@ class SILSSAUpdater {
public:
explicit SILSSAUpdater(
- SmallVectorImpl *InsertedPHIs = nullptr);
+ SmallVectorImpl *insertedPhis = nullptr);
~SILSSAUpdater();
- void setInsertedPhis(SmallVectorImpl *insertedPhis) {
- InsertedPHIs = insertedPhis;
+ void setInsertedPhis(SmallVectorImpl *inputInsertedPhis) {
+ insertedPhis = inputInsertedPhis;
}
/// Initialize for a use of a value of type.
- void Initialize(SILType T);
+ void initialize(SILType type);
- bool HasValueForBlock(SILBasicBlock *BB) const;
- void AddAvailableValue(SILBasicBlock *BB, SILValue V);
+ bool hasValueForBlock(SILBasicBlock *block) const;
+ void addAvailableValue(SILBasicBlock *block, SILValue value);
/// Construct SSA for a value that is live at the *end* of a basic block.
- SILValue GetValueAtEndOfBlock(SILBasicBlock *BB);
+ SILValue getValueAtEndOfBlock(SILBasicBlock *block);
/// Construct SSA for a value that is live in the middle of a block.
/// This handles the case where the use is before a definition of the value.
@@ -85,15 +90,15 @@ class SILSSAUpdater {
///
/// In this case we need to insert a 'PHI' node at the beginning of BB2
/// merging val_1 and val_2.
- SILValue GetValueInMiddleOfBlock(SILBasicBlock *BB);
+ SILValue getValueInMiddleOfBlock(SILBasicBlock *block);
- void RewriteUse(Operand &Op);
+ void rewriteUse(Operand &operand);
- void *allocate(unsigned Size, unsigned Align) const;
- static void deallocateSentinel(SILUndef *U);
-private:
+ void *allocate(unsigned size, unsigned align) const;
+ static void deallocateSentinel(SILUndef *undef);
- SILValue GetValueAtEndOfBlockInternal(SILBasicBlock *BB);
+private:
+ SILValue getValueAtEndOfBlockInternal(SILBasicBlock *block);
};
/// Utility to wrap 'Operand's to deal with invalidation of
@@ -112,15 +117,15 @@ class SILSSAUpdater {
/// identify the use allowing us to reconstruct the use after the branch has
/// been changed.
class UseWrapper {
- Operand *U;
- SILBasicBlock *Parent;
+ Operand *wrappedUse;
+ SILBasicBlock *parent;
enum {
kRegularUse,
kBranchUse,
kCondBranchUseTrue,
kCondBranchUseFalse
- } Type;
- unsigned Idx;
+ } type;
+ unsigned index;
public:
@@ -131,7 +136,7 @@ class UseWrapper {
/// (ValueUseIterator) become invalid as they point to freed operands.
/// Instead we store the branch's parent and the idx so that we can
/// reconstruct the use.
- UseWrapper(Operand *Use);
+ UseWrapper(Operand *use);
Operand *getOperand();
diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp
index 94e6654c5562b..532790cc94f3b 100644
--- a/lib/AST/ASTDumper.cpp
+++ b/lib/AST/ASTDumper.cpp
@@ -368,7 +368,6 @@ static StringRef
getStringLiteralExprEncodingString(StringLiteralExpr::Encoding value) {
switch (value) {
case StringLiteralExpr::UTF8: return "utf8";
- case StringLiteralExpr::UTF16: return "utf16";
case StringLiteralExpr::OneUnicodeScalar: return "unicodeScalar";
}
@@ -2829,6 +2828,11 @@ class PrintExpr : public ExprVisitor {
PrintWithColorRAII(OS, DiscriminatorColor)
<< "#" << component.getTupleIndex();
break;
+ case KeyPathExpr::Component::Kind::DictionaryKey:
+ PrintWithColorRAII(OS, ASTNodeColor) << "dict_key";
+ PrintWithColorRAII(OS, IdentifierColor)
+ << " key='" << component.getUnresolvedDeclName() << "'";
+ break;
}
PrintWithColorRAII(OS, TypeColor)
<< " type='" << GetTypeOfKeyPathComponent(E, i) << "'";
diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp
index 6c6726c2c0225..3641f7c807627 100644
--- a/lib/AST/ASTWalker.cpp
+++ b/lib/AST/ASTWalker.cpp
@@ -1133,6 +1133,7 @@ class Traversal : public ASTVisitor parents;
for (unsigned i : range(equivClass->derivedSameTypeComponents.size())) {
parents.push_back(i);
diff --git a/lib/AST/LocalizationFormat.cpp b/lib/AST/LocalizationFormat.cpp
index f0af4a133288a..5bc4f46cf5e64 100644
--- a/lib/AST/LocalizationFormat.cpp
+++ b/lib/AST/LocalizationFormat.cpp
@@ -1,5 +1,4 @@
-//===--- LocalizationFormat.cpp - YAML format for Diagnostic Messages ---*-
-// C++ -*-===//
+//===-- LocalizationFormat.cpp - Format for Diagnostic Messages -*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
@@ -16,26 +15,27 @@
//===----------------------------------------------------------------------===//
#include "swift/AST/LocalizationFormat.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Bitstream/BitstreamReader.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/YAMLParser.h"
#include "llvm/Support/YAMLTraits.h"
+#include
#include
+#include
#include
namespace {
+
enum LocalDiagID : uint32_t {
#define DIAG(KIND, ID, Options, Text, Signature) ID,
#include "swift/AST/DiagnosticsAll.def"
NumDiags
};
-struct DiagnosticNode {
- uint32_t id;
- std::string msg;
-};
} // namespace
namespace llvm {
@@ -46,15 +46,10 @@ template <> struct ScalarEnumerationTraits {
#define DIAG(KIND, ID, Options, Text, Signature) \
io.enumCase(value, #ID, LocalDiagID::ID);
#include "swift/AST/DiagnosticsAll.def"
- }
-};
-
-template <> struct MappingTraits {
- static void mapping(IO &io, DiagnosticNode &node) {
- LocalDiagID diagID;
- io.mapRequired("id", diagID);
- io.mapRequired("msg", node.msg);
- node.id = static_cast(diagID);
+ // Ignore diagnostic IDs that are available in the YAML file and not
+ // available in the `.def` file.
+ if (io.matchEnumFallback())
+ value = LocalDiagID::NumDiags;
}
};
@@ -64,18 +59,58 @@ template <> struct MappingTraits {
namespace swift {
namespace diag {
-YAMLLocalizationProducer::YAMLLocalizationProducer(std::string locale,
- std::string path) {
- llvm::SmallString<128> DiagnosticsFilePath(path);
- llvm::sys::path::append(DiagnosticsFilePath, locale);
- llvm::sys::path::replace_extension(DiagnosticsFilePath, ".yaml");
- auto FileBufOrErr = llvm::MemoryBuffer::getFileOrSTDIN(DiagnosticsFilePath);
- // Absence of localizations shouldn't crash the compiler.
- if (!FileBufOrErr)
- return;
+void SerializedLocalizationWriter::insert(swift::DiagID id,
+ llvm::StringRef translation) {
+ generator.insert(static_cast(id), translation);
+}
+
+bool SerializedLocalizationWriter::emit(llvm::StringRef filePath) {
+ assert(llvm::sys::path::extension(filePath) == ".db");
+ std::error_code error;
+ llvm::raw_fd_ostream OS(filePath, error, llvm::sys::fs::F_None);
+ if (OS.has_error()) {
+ return true;
+ }
+
+ offset_type offset;
+ {
+ llvm::support::endian::write(OS, 0, llvm::support::little);
+ offset = generator.Emit(OS);
+ }
+ OS.seek(0);
+ llvm::support::endian::write(OS, offset, llvm::support::little);
+ OS.close();
+
+ return OS.has_error();
+}
+
+SerializedLocalizationProducer::SerializedLocalizationProducer(
+ std::unique_ptr buffer)
+ : Buffer(std::move(buffer)) {
+ auto base =
+ reinterpret_cast(Buffer.get()->getBufferStart());
+ auto tableOffset = endian::read(base, little);
+ SerializedTable.reset(SerializedLocalizationTable::Create(
+ base + tableOffset, base + sizeof(offset_type), base));
+}
+
+llvm::StringRef SerializedLocalizationProducer::getMessageOr(
+ swift::DiagID id, llvm::StringRef defaultMessage) const {
+ auto value = SerializedTable.get()->find(id);
+ llvm::StringRef diagnosticMessage((const char *)value.getDataPtr(),
+ value.getDataLen());
+ if (diagnosticMessage.empty())
+ return defaultMessage;
+
+ return diagnosticMessage;
+}
+
+YAMLLocalizationProducer::YAMLLocalizationProducer(llvm::StringRef filePath) {
+ auto FileBufOrErr = llvm::MemoryBuffer::getFileOrSTDIN(filePath);
llvm::MemoryBuffer *document = FileBufOrErr->get();
diag::LocalizationInput yin(document->getBuffer());
yin >> diagnostics;
+ unknownIDs = std::move(yin.unknownIDs);
}
llvm::StringRef
@@ -89,24 +124,54 @@ YAMLLocalizationProducer::getMessageOr(swift::DiagID id,
return diagnosticMessage;
}
+void YAMLLocalizationProducer::forEachAvailable(
+ llvm::function_ref callback) const {
+ for (uint32_t i = 0, n = diagnostics.size(); i != n; ++i) {
+ auto translation = diagnostics[i];
+ if (!translation.empty())
+ callback(static_cast(i), translation);
+ }
+}
+
+llvm::Optional LocalizationInput::readID(llvm::yaml::IO &io) {
+ LocalDiagID diagID;
+ io.mapRequired("id", diagID);
+ if (diagID == LocalDiagID::NumDiags)
+ return llvm::None;
+ return static_cast(diagID);
+}
+
template
typename std::enable_if::value, void>::type
-readYAML(llvm::yaml::IO &io, T &Seq, bool, Context &Ctx) {
+readYAML(llvm::yaml::IO &io, T &Seq, T &unknownIDs, bool, Context &Ctx) {
unsigned count = io.beginSequence();
- if (count)
+ if (count) {
Seq.resize(LocalDiagID::NumDiags);
+ }
+
for (unsigned i = 0; i < count; ++i) {
void *SaveInfo;
if (io.preflightElement(i, SaveInfo)) {
- DiagnosticNode current;
- yamlize(io, current, true, Ctx);
+ io.beginMapping();
+
+ // If the current diagnostic ID is available in YAML and in `.def`, add it
+ // to the diagnostics array. Otherwise, re-parse the current diagnnostic
+ // id as a string and store it in `unknownIDs` array.
+ if (auto id = LocalizationInput::readID(io)) {
+ // YAML file isn't guaranteed to have diagnostics in order of their
+ // declaration in `.def` files, to accommodate that we need to leave
+ // holes in diagnostic array for diagnostics which haven't yet been
+ // localized and for the ones that have `id` indicates their position.
+ io.mapRequired("msg", Seq[*id]);
+ } else {
+ std::string unknownID, message;
+ // Read "raw" id since it doesn't exist in `.def` file.
+ io.mapRequired("id", unknownID);
+ io.mapRequired("msg", message);
+ unknownIDs.push_back(unknownID);
+ }
+ io.endMapping();
io.postflightElement(SaveInfo);
- // YAML file isn't guaranteed to have diagnostics in order of their
- // declaration in `.def` files, to accommodate that we need to leave
- // holes in diagnostic array for diagnostics which haven't yet been
- // localized and for the ones that have `DiagnosticNode::id`
- // indicates their position.
- Seq[static_cast(current.id)] = std::move(current.msg);
}
}
io.endSequence();
@@ -120,7 +185,7 @@ operator>>(LocalizationInput &yin, T &diagnostics) {
if (yin.setCurrentDocument()) {
// If YAML file's format doesn't match the current format in
// DiagnosticMessageFormat, will throw an error.
- readYAML(yin, diagnostics, true, Ctx);
+ readYAML(yin, diagnostics, yin.unknownIDs, true, Ctx);
}
return yin;
}
diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp
index df94b8ea9a972..fdbfb119ebddb 100644
--- a/lib/AST/NameLookup.cpp
+++ b/lib/AST/NameLookup.cpp
@@ -861,13 +861,18 @@ SelfBounds SelfBoundsFromWhereClauseRequest::evaluate(
continue;
// Resolve the right-hand side.
- if (auto *const typeRepr = req.getConstraintRepr()) {
- const auto rhsNominals = getDirectlyReferencedNominalTypeDecls(
- ctx, typeRepr, lookupDC, result.anyObject);
-
- result.decls.insert(result.decls.end(), rhsNominals.begin(),
- rhsNominals.end());
+ DirectlyReferencedTypeDecls rhsDecls;
+ if (auto typeRepr = req.getConstraintRepr()) {
+ rhsDecls = directReferencesForTypeRepr(evaluator, ctx, typeRepr, lookupDC);
}
+
+ SmallVector modulesFound;
+ auto rhsNominals = resolveTypeDeclsToNominal(evaluator, ctx, rhsDecls,
+ modulesFound,
+ result.anyObject);
+ result.decls.insert(result.decls.end(),
+ rhsNominals.begin(),
+ rhsNominals.end());
}
return result;
@@ -2134,17 +2139,6 @@ static DirectlyReferencedTypeDecls directReferencesForType(Type type) {
return { };
}
-TinyPtrVector swift::getDirectlyReferencedNominalTypeDecls(
- ASTContext &ctx, TypeRepr *typeRepr, DeclContext *dc, bool &anyObject) {
- const auto referenced =
- directReferencesForTypeRepr(ctx.evaluator, ctx, typeRepr, dc);
-
- // Resolve those type declarations to nominal type declarations.
- SmallVector modulesFound;
- return resolveTypeDeclsToNominal(ctx.evaluator, ctx, referenced, modulesFound,
- anyObject);
-}
-
DirectlyReferencedTypeDecls InheritedDeclsReferencedRequest::evaluate(
Evaluator &evaluator,
llvm::PointerUnion decl,
@@ -2266,10 +2260,16 @@ ExtendedNominalRequest::evaluate(Evaluator &evaluator,
// We must've seen 'extension { ... }' during parsing.
return nullptr;
+ ASTContext &ctx = ext->getASTContext();
+ DirectlyReferencedTypeDecls referenced =
+ directReferencesForTypeRepr(evaluator, ctx, typeRepr, ext->getParent());
+
// Resolve those type declarations to nominal type declarations.
+ SmallVector modulesFound;
bool anyObject = false;
- const auto nominalTypes = getDirectlyReferencedNominalTypeDecls(
- ext->getASTContext(), typeRepr, ext->getParent(), anyObject);
+ auto nominalTypes
+ = resolveTypeDeclsToNominal(evaluator, ctx, referenced, modulesFound,
+ anyObject);
// If there is more than 1 element, we will emit a warning or an error
// elsewhere, so don't handle that case here.
diff --git a/lib/Basic/Unicode.cpp b/lib/Basic/Unicode.cpp
index a299c457a7805..e7479be57820f 100644
--- a/lib/Basic/Unicode.cpp
+++ b/lib/Basic/Unicode.cpp
@@ -123,22 +123,3 @@ unsigned swift::unicode::extractFirstUnicodeScalar(StringRef S) {
(void)Result;
return Scalar;
}
-
-uint64_t swift::unicode::getUTF16Length(StringRef Str) {
- uint64_t Length;
- // Transcode the string to UTF-16 to get its length.
- SmallVector buffer(Str.size() + 1); // +1 for ending nulls.
- const llvm::UTF8 *fromPtr = (const llvm::UTF8 *) Str.data();
- llvm::UTF16 *toPtr = &buffer[0];
- llvm::ConversionResult Result =
- ConvertUTF8toUTF16(&fromPtr, fromPtr + Str.size(),
- &toPtr, toPtr + Str.size(),
- llvm::strictConversion);
- assert(Result == llvm::conversionOK &&
- "UTF-8 encoded string cannot be converted into UTF-16 encoding");
- (void)Result;
-
- // The length of the transcoded string in UTF-16 code points.
- Length = toPtr - &buffer[0];
- return Length;
-}
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index bdb3437ee50e2..f9c3828c19c67 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -1448,9 +1448,23 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args,
if (Args.hasArg(OPT_disable_concrete_type_metadata_mangled_name_accessors))
Opts.DisableConcreteTypeMetadataMangledNameAccessors = true;
- if (Args.hasArg(OPT_use_jit))
+ if (Args.hasArg(OPT_use_jit)) {
Opts.UseJIT = true;
-
+ if (const Arg *A = Args.getLastArg(OPT_dump_jit)) {
+ llvm::Optional artifact =
+ llvm::StringSwitch>(A->getValue())
+ .Case("llvm-ir", JITDebugArtifact::LLVMIR)
+ .Case("object", JITDebugArtifact::Object)
+ .Default(None);
+ if (!artifact) {
+ Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value,
+ A->getOption().getName(), A->getValue());
+ return true;
+ }
+ Opts.DumpJIT = *artifact;
+ }
+ }
+
for (const Arg *A : Args.filtered(OPT_verify_type_layout)) {
Opts.VerifyTypeLayoutNames.push_back(A->getValue());
}
diff --git a/lib/FrontendTool/ScanDependencies.cpp b/lib/FrontendTool/ScanDependencies.cpp
index e68955216b343..6a90ae8231c86 100644
--- a/lib/FrontendTool/ScanDependencies.cpp
+++ b/lib/FrontendTool/ScanDependencies.cpp
@@ -470,6 +470,57 @@ static void writeJSON(llvm::raw_ostream &out,
}
}
+static bool diagnoseCycle(CompilerInstance &instance,
+ ModuleDependenciesCache &cache,
+ ModuleDependencyID mainId,
+ InterfaceSubContextDelegate &astDelegate) {
+ llvm::SetVector,
+ std::set> openSet;
+ llvm::SetVector,
+ std::set> closeSet;
+ // Start from the main module.
+ openSet.insert(mainId);
+ while(!openSet.empty()) {
+ auto &lastOpen = openSet.back();
+ auto beforeSize = openSet.size();
+ for (auto dep: resolveDirectDependencies(instance, lastOpen, cache,
+ astDelegate)) {
+ if (closeSet.count(dep))
+ continue;
+ if (openSet.insert(dep)) {
+ break;
+ } else {
+ // Find a cycle, diagnose.
+ auto startIt = std::find(openSet.begin(), openSet.end(), dep);
+ assert(startIt != openSet.end());
+ llvm::SmallString<64> buffer;
+ for (auto it = startIt; it != openSet.end(); ++ it) {
+ buffer.append(it->first);
+ buffer.append(it->second == ModuleDependenciesKind::Swift?
+ ".swiftmodule": ".pcm");
+ buffer.append(" -> ");
+ }
+ buffer.append(startIt->first);
+ buffer.append(startIt->second == ModuleDependenciesKind::Swift?
+ ".swiftmodule": ".pcm");
+ instance.getASTContext().Diags.diagnose(SourceLoc(),
+ diag::scanner_find_cycle,
+ buffer.str());
+ return true;
+ }
+ }
+ // No new node added. We can close this node
+ if (openSet.size() == beforeSize) {
+ closeSet.insert(openSet.back());
+ openSet.pop_back();
+ } else {
+ assert(openSet.size() == beforeSize + 1);
+ }
+ }
+ assert(openSet.empty());
+ return false;
+}
+
bool swift::scanDependencies(CompilerInstance &instance) {
ASTContext &Context = instance.getASTContext();
ModuleDecl *mainModule = instance.getMainModule();
@@ -592,6 +643,10 @@ bool swift::scanDependencies(CompilerInstance &instance) {
allModules.insert(id);
});
+ // Dignose cycle in dependency graph.
+ if (diagnoseCycle(instance, cache, /*MainModule*/allModules.front(), ASTDelegate))
+ return true;
+
// Write out the JSON description.
writeJSON(out, instance, cache, ASTDelegate, allModules.getArrayRef());
diff --git a/lib/IDE/SourceEntityWalker.cpp b/lib/IDE/SourceEntityWalker.cpp
index a7a3f7d0ea4de..6f6f08e9daf27 100644
--- a/lib/IDE/SourceEntityWalker.cpp
+++ b/lib/IDE/SourceEntityWalker.cpp
@@ -412,6 +412,7 @@ std::pair SemaAnnotator::walkToExprPre(Expr *E) {
case KeyPathExpr::Component::Kind::OptionalWrap:
case KeyPathExpr::Component::Kind::OptionalForce:
case KeyPathExpr::Component::Kind::Identity:
+ case KeyPathExpr::Component::Kind::DictionaryKey:
break;
}
}
@@ -684,7 +685,7 @@ bool SemaAnnotator::
passReference(ValueDecl *D, Type Ty, DeclNameLoc Loc, ReferenceMetaData Data) {
SourceManager &SM = D->getASTContext().SourceMgr;
SourceLoc BaseStart = Loc.getBaseNameLoc(), BaseEnd = BaseStart;
- if (SM.extractText({BaseStart, 1}) == "`")
+ if (BaseStart.isValid() && SM.extractText({BaseStart, 1}) == "`")
BaseEnd = Lexer::getLocForEndOfToken(SM, BaseStart.getAdvancedLoc(1));
return passReference(D, Ty, BaseStart, {BaseStart, BaseEnd}, Data);
}
diff --git a/lib/IRGen/GenCast.cpp b/lib/IRGen/GenCast.cpp
index 5054b5344303f..90ff58b9bfa15 100644
--- a/lib/IRGen/GenCast.cpp
+++ b/lib/IRGen/GenCast.cpp
@@ -357,7 +357,7 @@ llvm::Value *irgen::emitReferenceToObjCProtocol(IRGenFunction &IGF,
/// The function's output type is (value, witnessTable...)
///
/// The value is NULL if the cast failed.
-static llvm::Function *
+static llvm::Constant *
emitExistentialScalarCastFn(IRGenModule &IGM,
unsigned numProtocols,
CheckedCastMode mode,
@@ -385,13 +385,7 @@ emitExistentialScalarCastFn(IRGenModule &IGM,
}
}
- // See if we already defined this function.
-
- if (auto fn = IGM.Module.getFunction(name))
- return fn;
-
// Build the function type.
-
llvm::SmallVector argTys;
llvm::SmallVector returnTys;
argTys.push_back(IGM.Int8PtrTy);
@@ -405,84 +399,77 @@ emitExistentialScalarCastFn(IRGenModule &IGM,
}
llvm::Type *returnTy = llvm::StructType::get(IGM.getLLVMContext(), returnTys);
-
- auto fnTy = llvm::FunctionType::get(returnTy, argTys, /*vararg*/ false);
- auto fn = llvm::Function::Create(fnTy, llvm::GlobalValue::PrivateLinkage,
- llvm::Twine(name), IGM.getModule());
- fn->setAttributes(IGM.constructInitialAttributes());
-
- IRGenFunction IGF(IGM, fn);
- if (IGM.DebugInfo)
- IGM.DebugInfo->emitArtificialFunction(IGF, fn);
- Explosion args = IGF.collectParameters();
-
- auto value = args.claimNext();
- auto ref = args.claimNext();
- auto failBB = IGF.createBasicBlock("fail");
- auto conformsToProtocol = IGM.getConformsToProtocolFn();
-
- Explosion rets;
- rets.add(value);
-
- // Check the class constraint if necessary.
- if (checkSuperclassConstraint) {
- auto superclassMetadata = args.claimNext();
- auto castFn = IGF.IGM.getDynamicCastMetatypeFn();
- auto castResult = IGF.Builder.CreateCall(castFn, {ref,
- superclassMetadata});
-
- auto cc = cast(castFn)->getCallingConv();
-
- // FIXME: Eventually, we may want to throw.
- castResult->setCallingConv(cc);
- castResult->setDoesNotThrow();
- auto isClass = IGF.Builder.CreateICmpNE(
- castResult,
- llvm::ConstantPointerNull::get(IGF.IGM.TypeMetadataPtrTy));
+ return IGM.getOrCreateHelperFunction(name, returnTy, argTys,
+ [&](IRGenFunction &IGF) {
+ Explosion args = IGF.collectParameters();
+
+ auto value = args.claimNext();
+ auto ref = args.claimNext();
+ auto failBB = IGF.createBasicBlock("fail");
+ auto conformsToProtocol = IGM.getConformsToProtocolFn();
+
+ Explosion rets;
+ rets.add(value);
+
+ // Check the class constraint if necessary.
+ if (checkSuperclassConstraint) {
+ auto superclassMetadata = args.claimNext();
+ auto castFn = IGF.IGM.getDynamicCastMetatypeFn();
+ auto castResult = IGF.Builder.CreateCall(castFn, {ref,
+ superclassMetadata});
+
+ auto cc = cast(castFn)->getCallingConv();
+
+ // FIXME: Eventually, we may want to throw.
+ castResult->setCallingConv(cc);
+ castResult->setDoesNotThrow();
+
+ auto isClass = IGF.Builder.CreateICmpNE(
+ castResult,
+ llvm::ConstantPointerNull::get(IGF.IGM.TypeMetadataPtrTy));
+
+ auto contBB = IGF.createBasicBlock("cont");
+ IGF.Builder.CreateCondBr(isClass, contBB, failBB);
+ IGF.Builder.emitBlock(contBB);
+ } else if (checkClassConstraint) {
+ auto isClass = IGF.Builder.CreateCall(IGM.getIsClassTypeFn(), ref);
+ auto contBB = IGF.createBasicBlock("cont");
+ IGF.Builder.CreateCondBr(isClass, contBB, failBB);
+ IGF.Builder.emitBlock(contBB);
+ }
- auto contBB = IGF.createBasicBlock("cont");
- IGF.Builder.CreateCondBr(isClass, contBB, failBB);
- IGF.Builder.emitBlock(contBB);
- } else if (checkClassConstraint) {
- auto isClass = IGF.Builder.CreateCall(IGM.getIsClassTypeFn(), ref);
- auto contBB = IGF.createBasicBlock("cont");
- IGF.Builder.CreateCondBr(isClass, contBB, failBB);
- IGF.Builder.emitBlock(contBB);
- }
+ // Look up each protocol conformance we want.
+ for (unsigned i = 0; i < numProtocols; ++i) {
+ auto proto = args.claimNext();
+ auto witness = IGF.Builder.CreateCall(conformsToProtocol, {ref, proto});
+ auto isNull = IGF.Builder.CreateICmpEQ(witness,
+ llvm::ConstantPointerNull::get(IGM.WitnessTablePtrTy));
+ auto contBB = IGF.createBasicBlock("cont");
+ IGF.Builder.CreateCondBr(isNull, failBB, contBB);
+
+ IGF.Builder.emitBlock(contBB);
+ rets.add(witness);
+ }
- // Look up each protocol conformance we want.
- for (unsigned i = 0; i < numProtocols; ++i) {
- auto proto = args.claimNext();
- auto witness = IGF.Builder.CreateCall(conformsToProtocol, {ref, proto});
- auto isNull = IGF.Builder.CreateICmpEQ(witness,
- llvm::ConstantPointerNull::get(IGM.WitnessTablePtrTy));
- auto contBB = IGF.createBasicBlock("cont");
- IGF.Builder.CreateCondBr(isNull, failBB, contBB);
+ // If we succeeded, return the witnesses.
+ IGF.emitScalarReturn(returnTy, rets);
- IGF.Builder.emitBlock(contBB);
- rets.add(witness);
- }
-
- // If we succeeded, return the witnesses.
- IGF.emitScalarReturn(returnTy, rets);
-
- // If we failed, return nil or trap.
- IGF.Builder.emitBlock(failBB);
- switch (mode) {
- case CheckedCastMode::Conditional: {
- auto null = llvm::ConstantStruct::getNullValue(returnTy);
- IGF.Builder.CreateRet(null);
- break;
- }
+ // If we failed, return nil or trap.
+ IGF.Builder.emitBlock(failBB);
+ switch (mode) {
+ case CheckedCastMode::Conditional: {
+ auto null = llvm::ConstantStruct::getNullValue(returnTy);
+ IGF.Builder.CreateRet(null);
+ break;
+ }
- case CheckedCastMode::Unconditional: {
- IGF.emitTrap("type cast failed", /*EmitUnreachable=*/true);
- break;
- }
- }
-
- return fn;
+ case CheckedCastMode::Unconditional: {
+ IGF.emitTrap("type cast failed", /*EmitUnreachable=*/true);
+ break;
+ }
+ }
+ });
}
llvm::Value *irgen::emitMetatypeToAnyObjectDowncast(IRGenFunction &IGF,
diff --git a/lib/IRGen/GenClass.cpp b/lib/IRGen/GenClass.cpp
index 912f0e3ad6131..94ab37632feba 100644
--- a/lib/IRGen/GenClass.cpp
+++ b/lib/IRGen/GenClass.cpp
@@ -1284,7 +1284,7 @@ namespace {
// };
assert(fields.getNextOffsetFromGlobal() == size);
- return buildGlobalVariable(fields, "_CATEGORY_");
+ return buildGlobalVariable(fields, "_CATEGORY_", /*const*/ true);
}
llvm::Constant *emitProtocol() {
@@ -1336,7 +1336,7 @@ namespace {
// };
assert(fields.getNextOffsetFromGlobal() == size);
- return buildGlobalVariable(fields, "_PROTOCOL_");
+ return buildGlobalVariable(fields, "_PROTOCOL_", /*const*/ true);
}
void emitRODataFields(ConstantStructBuilder &b,
@@ -1439,7 +1439,7 @@ namespace {
emitRODataFields(fields, forMeta, hasUpdater);
auto dataSuffix = forMeta ? "_METACLASS_DATA_" : "_DATA_";
- return buildGlobalVariable(fields, dataSuffix);
+ return buildGlobalVariable(fields, dataSuffix, /*const*/ true);
}
private:
@@ -1673,7 +1673,8 @@ namespace {
return null();
}
- return buildGlobalVariable(array, "_PROTOCOL_METHOD_TYPES_");
+ return buildGlobalVariable(array, "_PROTOCOL_METHOD_TYPES_",
+ /*const*/ true);
}
void buildExtMethodTypes(ConstantArrayBuilder &array,
@@ -1698,6 +1699,7 @@ namespace {
llvm::Constant *buildMethodList(ArrayRef methods,
StringRef name) {
return buildOptionalList(methods, 3 * IGM.getPointerSize(), name,
+ /*isConst*/ false,
[&](ConstantArrayBuilder &descriptors,
MethodDescriptor descriptor) {
buildMethod(descriptors, descriptor);
@@ -1723,6 +1725,7 @@ namespace {
chooseNamePrefix("_PROTOCOLS_",
"_CATEGORY_PROTOCOLS_",
"_PROTOCOL_PROTOCOLS_"),
+ /*isConst*/ true,
[&](ConstantArrayBuilder &descriptors,
ProtocolDecl *protocol) {
buildProtocol(descriptors, protocol);
@@ -1836,6 +1839,7 @@ namespace {
llvm::Constant *buildIvarList() {
Size eltSize = 3 * IGM.getPointerSize() + Size(8);
return buildOptionalList(Ivars, eltSize, "_IVARS_",
+ /*constant*/ true,
[&](ConstantArrayBuilder &descriptors,
VarDecl *ivar) {
buildIvar(descriptors, ivar);
@@ -1971,6 +1975,7 @@ namespace {
StringRef namePrefix) {
Size eltSize = 2 * IGM.getPointerSize();
return buildOptionalList(properties, eltSize, namePrefix,
+ /*constant*/ true,
[&](ConstantArrayBuilder &descriptors,
VarDecl *property) {
buildProperty(descriptors, property);
@@ -1989,6 +1994,7 @@ namespace {
llvm::Constant *buildOptionalList(const C &objects,
Size optionalEltSize,
StringRef nameBase,
+ bool isConst,
Fn &&buildElement) {
if (objects.empty())
return null();
@@ -2027,7 +2033,7 @@ namespace {
fields.fillPlaceholderWithInt(countPosition, countType, count);
- return buildGlobalVariable(fields, nameBase);
+ return buildGlobalVariable(fields, nameBase, isConst);
}
/// Get the name of the class or protocol to mangle into the ObjC symbol
@@ -2047,7 +2053,8 @@ namespace {
/// Build a private global variable as a structure containing the
/// given fields.
template
- llvm::Constant *buildGlobalVariable(B &fields, StringRef nameBase) {
+ llvm::Constant *buildGlobalVariable(B &fields, StringRef nameBase,
+ bool isConst) {
llvm::SmallString<64> nameBuffer;
auto var =
fields.finishAndCreateGlobal(Twine(nameBase)
@@ -2061,7 +2068,8 @@ namespace {
switch (IGM.TargetInfo.OutputObjectFormat) {
case llvm::Triple::MachO:
- var->setSection("__DATA, __objc_const");
+ var->setSection(isConst ? "__DATA, __objc_const"
+ : "__DATA, __objc_data");
break;
case llvm::Triple::XCOFF:
case llvm::Triple::COFF:
diff --git a/lib/IRGen/GenConstant.cpp b/lib/IRGen/GenConstant.cpp
index 071d49f82603b..0d6e021e8327f 100644
--- a/lib/IRGen/GenConstant.cpp
+++ b/lib/IRGen/GenConstant.cpp
@@ -102,14 +102,6 @@ llvm::Constant *irgen::emitAddrOfConstantString(IRGenModule &IGM,
case StringLiteralInst::Encoding::UTF8:
return IGM.getAddrOfGlobalString(SLI->getValue());
- case StringLiteralInst::Encoding::UTF16: {
- // This is always a GEP of a GlobalVariable with a nul terminator.
- auto addr = IGM.getAddrOfGlobalUTF16String(SLI->getValue());
-
- // Cast to Builtin.RawPointer.
- return llvm::ConstantExpr::getBitCast(addr, IGM.Int8PtrTy);
- }
-
case StringLiteralInst::Encoding::ObjCSelector:
llvm_unreachable("cannot get the address of an Objective-C selector");
}
diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp
index 81fd8183d7aec..c207e75ad800f 100644
--- a/lib/IRGen/GenDecl.cpp
+++ b/lib/IRGen/GenDecl.cpp
@@ -4860,6 +4860,7 @@ static llvm::Function *shouldDefineHelper(IRGenModule &IGM,
if (!def) return nullptr;
if (!def->empty()) return nullptr;
+ def->setAttributes(IGM.constructInitialAttributes());
ApplyIRLinkage(IRLinkage::InternalLinkOnceODR).to(def);
def->setDoesNotThrow();
def->setCallingConv(IGM.DefaultCC);
diff --git a/lib/IRGen/GenKeyPath.cpp b/lib/IRGen/GenKeyPath.cpp
index 41128f62b8620..6cfc8d962c9b9 100644
--- a/lib/IRGen/GenKeyPath.cpp
+++ b/lib/IRGen/GenKeyPath.cpp
@@ -277,6 +277,7 @@ getLayoutFunctionForComputedComponent(IRGenModule &IGM,
auto layoutFn = llvm::Function::Create(fnTy,
llvm::GlobalValue::PrivateLinkage, "keypath_get_arg_layout", IGM.getModule());
+ layoutFn->setAttributes(IGM.constructInitialAttributes());
{
IRGenFunction IGF(IGM, layoutFn);
@@ -378,6 +379,7 @@ getWitnessTableForComputedComponent(IRGenModule &IGM,
auto destroyFn = llvm::Function::Create(destroyType,
llvm::GlobalValue::PrivateLinkage, "keypath_destroy", IGM.getModule());
destroy = destroyFn;
+ destroyFn->setAttributes(IGM.constructInitialAttributes());
IRGenFunction IGF(IGM, destroyFn);
if (IGM.DebugInfo)
@@ -426,6 +428,7 @@ getWitnessTableForComputedComponent(IRGenModule &IGM,
auto copyFn = llvm::Function::Create(copyType,
llvm::GlobalValue::PrivateLinkage, "keypath_copy", IGM.getModule());
copy = copyFn;
+ copyFn->setAttributes(IGM.constructInitialAttributes());
IRGenFunction IGF(IGM, copyFn);
if (IGM.DebugInfo)
@@ -538,6 +541,7 @@ getInitializerForComputedComponent(IRGenModule &IGM,
auto initFn = llvm::Function::Create(fnTy,
llvm::GlobalValue::PrivateLinkage, "keypath_arg_init", IGM.getModule());
+ initFn->setAttributes(IGM.constructInitialAttributes());
{
IRGenFunction IGF(IGM, initFn);
@@ -945,23 +949,16 @@ emitKeyPathComponent(IRGenModule &IGM,
// Note that we'd need to do this anyway in JIT mode because we would
// need to unique the selector at runtime anyway.
auto selectorName = IGM.getObjCSelectorName(declRef);
- llvm::Type *fnParams[] = {IGM.Int8PtrTy};
- auto fnTy = llvm::FunctionType::get(IGM.Int8PtrTy, fnParams, false);
SmallString<32> fnName;
fnName.append("keypath_get_selector_");
fnName.append(selectorName);
- auto fn = cast(
- IGM.Module.getOrInsertFunction(fnName, fnTy).getCallee());
- if (fn->empty()) {
- fn->setLinkage(llvm::Function::PrivateLinkage);
- IRGenFunction subIGF(IGM, fn);
- if (IGM.DebugInfo)
- IGM.DebugInfo->emitArtificialFunction(subIGF, fn);
-
+ auto fn = IGM.getOrCreateHelperFunction(fnName, IGM.Int8PtrTy,
+ {IGM.Int8PtrTy},
+ [&selectorName](IRGenFunction &subIGF) {
auto selectorValue = subIGF.emitObjCSelectorRefLoad(selectorName);
subIGF.Builder.CreateRet(selectorValue);
- }
-
+ });
+
idValue = fn;
idResolution = KeyPathComponentHeader::FunctionCall;
} else {
diff --git a/lib/IRGen/GenOpaque.cpp b/lib/IRGen/GenOpaque.cpp
index a6a328f273aa4..a01ff1ad59adc 100644
--- a/lib/IRGen/GenOpaque.cpp
+++ b/lib/IRGen/GenOpaque.cpp
@@ -1354,6 +1354,7 @@ irgen::getOrCreateGetExtraInhabitantTagFunction(IRGenModule &IGM,
auto fn = llvm::Function::Create(fnTy, llvm::Function::PrivateLinkage,
"__swift_get_extra_inhabitant_index",
&IGM.Module);
+ fn->setAttributes(IGM.constructInitialAttributes());
fn->setCallingConv(IGM.SwiftCC);
IRGenFunction IGF(IGM, fn);
auto parameters = IGF.collectParameters();
@@ -1427,8 +1428,9 @@ irgen::getOrCreateStoreExtraInhabitantTagFunction(IRGenModule &IGM,
// TODO: use a meaningful mangled name and internal/shared linkage.
auto fn = llvm::Function::Create(fnTy, llvm::Function::PrivateLinkage,
- "__swift_get_extra_inhabitant_index",
+ "__swift_store_extra_inhabitant_index",
&IGM.Module);
+ fn->setAttributes(IGM.constructInitialAttributes());
fn->setCallingConv(IGM.SwiftCC);
IRGenFunction IGF(IGM, fn);
auto parameters = IGF.collectParameters();
diff --git a/lib/IRGen/GenStruct.cpp b/lib/IRGen/GenStruct.cpp
index b8c647fbefc6d..3f1961f80664b 100644
--- a/lib/IRGen/GenStruct.cpp
+++ b/lib/IRGen/GenStruct.cpp
@@ -53,6 +53,7 @@ enum class StructTypeInfoKind {
LoadableStructTypeInfo,
FixedStructTypeInfo,
LoadableClangRecordTypeInfo,
+ AddressOnlyClangRecordTypeInfo,
NonFixedStructTypeInfo,
ResilientStructTypeInfo
};
@@ -83,6 +84,12 @@ namespace {
/// A field-info implementation for fields of Clang types.
class ClangFieldInfo : public RecordField {
public:
+ ClangFieldInfo(VarDecl *swiftField, const ElementLayout &layout,
+ const TypeInfo &typeInfo)
+ : RecordField(typeInfo), Field(swiftField) {
+ completeFrom(layout);
+ }
+
ClangFieldInfo(VarDecl *swiftField, const ElementLayout &layout,
unsigned explosionBegin, unsigned explosionEnd)
: RecordField(layout, explosionBegin, explosionEnd),
@@ -290,7 +297,7 @@ namespace {
}
}
};
-
+
/// A type implementation for loadable record types imported from Clang.
class LoadableClangRecordTypeInfo final :
public StructTypeInfoBase {
+ const clang::RecordDecl *ClangDecl;
+
+ public:
+ AddressOnlyClangRecordTypeInfo(ArrayRef fields,
+ llvm::Type *storageType, Size size,
+ Alignment align,
+ const clang::RecordDecl *clangDecl)
+ : StructTypeInfoBase(StructTypeInfoKind::AddressOnlyClangRecordTypeInfo,
+ fields, storageType, size,
+ // We can't assume any spare bits in a C++ type
+ // with user-defined special member functions.
+ SpareBitVector(llvm::Optional{
+ llvm::APInt(size.getValueInBits(), 0)}),
+ align, IsPOD, IsNotBitwiseTakable, IsFixedSize),
+ ClangDecl(clangDecl) {
+ (void)ClangDecl;
+ }
+
+ TypeLayoutEntry *buildTypeLayoutEntry(IRGenModule &IGM,
+ SILType T) const override {
+ return IGM.typeLayoutCache.getOrCreateScalarEntry(*this, T);
+ }
+
+ void initializeFromParams(IRGenFunction &IGF, Explosion ¶ms,
+ Address addr, SILType T,
+ bool isOutlined) const override {
+ llvm_unreachable("Address-only C++ types must be created by C++ special "
+ "member functions.");
+ }
+
+ llvm::NoneType getNonFixedOffsets(IRGenFunction &IGF) const { return None; }
+ llvm::NoneType getNonFixedOffsets(IRGenFunction &IGF, SILType T) const {
+ return None;
+ }
+ MemberAccessStrategy
+ getNonFixedFieldAccessStrategy(IRGenModule &IGM, SILType T,
+ const ClangFieldInfo &field) const {
+ llvm_unreachable("non-fixed field in Clang type?");
+ }
+ };
+
/// A type implementation for loadable struct types.
class LoadableStructTypeInfo final
: public StructTypeInfoBase {
@@ -680,6 +731,10 @@ class ClangRecordLowering {
const TypeInfo *createTypeInfo(llvm::StructType *llvmType) {
llvmType->setBody(LLVMFields, /*packed*/ true);
+ if (SwiftType.getStructOrBoundGenericStruct()->isCxxNonTrivial()) {
+ return AddressOnlyClangRecordTypeInfo::create(
+ FieldInfos, llvmType, TotalStride, TotalAlignment, ClangDecl);
+ }
return LoadableClangRecordTypeInfo::create(FieldInfos, NextExplosionIndex,
llvmType, TotalStride,
std::move(SpareBits), TotalAlignment,
@@ -773,7 +828,7 @@ class ClangRecordLowering {
// If we have a Swift import of this type, use our lowered information.
if (swiftField) {
- auto &fieldTI = cast(IGM.getTypeInfo(
+ auto &fieldTI = cast(IGM.getTypeInfo(
SwiftType.getFieldType(swiftField, IGM.getSILModule(),
IGM.getMaximalTypeExpansionContext())));
addField(swiftField, offset, fieldTI);
@@ -812,7 +867,7 @@ class ClangRecordLowering {
/// Add storage for an (optional) Swift field at the given offset.
void addField(VarDecl *swiftField, Size offset,
- const LoadableTypeInfo &fieldType) {
+ const FixedTypeInfo &fieldType) {
assert(offset >= NextOffset && "adding fields out of order");
// Add a padding field if required.
@@ -823,8 +878,11 @@ class ClangRecordLowering {
}
/// Add information to track a value field at the current offset.
- void addFieldInfo(VarDecl *swiftField, const LoadableTypeInfo &fieldType) {
- unsigned explosionSize = fieldType.getExplosionSize();
+ void addFieldInfo(VarDecl *swiftField, const FixedTypeInfo &fieldType) {
+ bool isLoadableField = isa(fieldType);
+ unsigned explosionSize = 0;
+ if (isLoadableField)
+ explosionSize = cast(fieldType).getExplosionSize();
unsigned explosionBegin = NextExplosionIndex;
NextExplosionIndex += explosionSize;
unsigned explosionEnd = NextExplosionIndex;
@@ -838,9 +896,12 @@ class ClangRecordLowering {
layout.completeFixed(fieldType.isPOD(ResilienceExpansion::Maximal),
NextOffset, LLVMFields.size());
- FieldInfos.push_back(
- ClangFieldInfo(swiftField, layout, explosionBegin, explosionEnd));
-
+ if (isLoadableField)
+ FieldInfos.push_back(
+ ClangFieldInfo(swiftField, layout, explosionBegin, explosionEnd));
+ else
+ FieldInfos.push_back(ClangFieldInfo(swiftField, layout, fieldType));
+
if (!isEmpty) {
LLVMFields.push_back(fieldType.getStorageType());
NextOffset += fieldType.getFixedSize();
@@ -862,22 +923,26 @@ class ClangRecordLowering {
/// A convenient macro for delegating an operation to all of the
/// various struct implementations.
-#define FOR_STRUCT_IMPL(IGF, type, op, ...) do { \
- auto &structTI = IGF.getTypeInfo(type); \
- switch (getStructTypeInfoKind(structTI)) { \
- case StructTypeInfoKind::LoadableClangRecordTypeInfo: \
- return structTI.as().op(IGF, __VA_ARGS__); \
- case StructTypeInfoKind::LoadableStructTypeInfo: \
- return structTI.as().op(IGF, __VA_ARGS__); \
- case StructTypeInfoKind::FixedStructTypeInfo: \
- return structTI.as().op(IGF, __VA_ARGS__); \
- case StructTypeInfoKind::NonFixedStructTypeInfo: \
- return structTI.as().op(IGF, __VA_ARGS__); \
- case StructTypeInfoKind::ResilientStructTypeInfo: \
- llvm_unreachable("resilient structs are opaque"); \
- } \
- llvm_unreachable("bad struct type info kind!"); \
-} while (0)
+#define FOR_STRUCT_IMPL(IGF, type, op, ...) \
+ do { \
+ auto &structTI = IGF.getTypeInfo(type); \
+ switch (getStructTypeInfoKind(structTI)) { \
+ case StructTypeInfoKind::LoadableClangRecordTypeInfo: \
+ return structTI.as().op(IGF, __VA_ARGS__); \
+ case StructTypeInfoKind::AddressOnlyClangRecordTypeInfo: \
+ return structTI.as().op(IGF, \
+ __VA_ARGS__); \
+ case StructTypeInfoKind::LoadableStructTypeInfo: \
+ return structTI.as().op(IGF, __VA_ARGS__); \
+ case StructTypeInfoKind::FixedStructTypeInfo: \
+ return structTI.as().op(IGF, __VA_ARGS__); \
+ case StructTypeInfoKind::NonFixedStructTypeInfo: \
+ return structTI.as().op(IGF, __VA_ARGS__); \
+ case StructTypeInfoKind::ResilientStructTypeInfo: \
+ llvm_unreachable("resilient structs are opaque"); \
+ } \
+ llvm_unreachable("bad struct type info kind!"); \
+ } while (0)
Address irgen::projectPhysicalStructMemberAddress(IRGenFunction &IGF,
Address base,
diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp
index a3f83a2e9edd5..91eefd6d832dc 100644
--- a/lib/IRGen/IRGenModule.cpp
+++ b/lib/IRGen/IRGenModule.cpp
@@ -1418,6 +1418,7 @@ void IRGenModule::emitAutolinkInfo() {
llvm::Function::Create(llvm::FunctionType::get(VoidTy, false),
llvm::GlobalValue::ExternalLinkage, buf,
&Module);
+ ForceImportThunk->setAttributes(constructInitialAttributes());
ApplyIRLinkage(IRLinkage::ExternalExport).to(ForceImportThunk);
if (Triple.supportsCOMDAT())
if (auto *GO = cast(ForceImportThunk))
diff --git a/lib/IRGen/MetadataRequest.cpp b/lib/IRGen/MetadataRequest.cpp
index 7dfd2be9b2f44..5a794512e3ff1 100644
--- a/lib/IRGen/MetadataRequest.cpp
+++ b/lib/IRGen/MetadataRequest.cpp
@@ -2256,66 +2256,57 @@ MetadataResponse irgen::emitGenericTypeMetadataAccessFunction(
// Factor out the buffer shuffling for metadata accessors that take their
// arguments directly, so that the accessor function itself only needs to
// materialize the nominal type descriptor and call this thunk.
- auto thunkFn = cast(
- IGM.getModule()
- ->getOrInsertFunction("__swift_instantiateGenericMetadata",
- IGM.TypeMetadataResponseTy,
- IGM.SizeTy, // request
- IGM.Int8PtrTy, // arg 0
- IGM.Int8PtrTy, // arg 1
- IGM.Int8PtrTy, // arg 2
- IGM.TypeContextDescriptorPtrTy) // type context descriptor
- .getCallee()
- ->stripPointerCasts());
-
- if (thunkFn->empty()) {
- ApplyIRLinkage(IRLinkage::InternalLinkOnceODR)
- .to(thunkFn);
- thunkFn->setDoesNotAccessMemory();
- thunkFn->setDoesNotThrow();
- thunkFn->setCallingConv(IGM.SwiftCC);
- thunkFn->addAttribute(llvm::AttributeList::FunctionIndex,
- llvm::Attribute::NoInline);
- IGM.setHasNoFramePointer(thunkFn);
-
- [&IGM, thunkFn]{
- IRGenFunction subIGF(IGM, thunkFn);
-
- auto params = subIGF.collectParameters();
- auto request = params.claimNext();
- auto arg0 = params.claimNext();
- auto arg1 = params.claimNext();
- auto arg2 = params.claimNext();
- auto descriptor = params.claimNext();
-
- // Allocate a buffer with enough storage for the arguments.
- auto argsBufferTy =
- llvm::ArrayType::get(IGM.Int8PtrTy,
- NumDirectGenericTypeMetadataAccessFunctionArgs);
- auto argsBuffer = subIGF.createAlloca(argsBufferTy,
- IGM.getPointerAlignment(),
- "generic.arguments");
- subIGF.Builder.CreateLifetimeStart(argsBuffer,
- IGM.getPointerSize() * NumDirectGenericTypeMetadataAccessFunctionArgs);
-
- auto arg0Buf = subIGF.Builder.CreateConstInBoundsGEP2_32(argsBufferTy,
- argsBuffer.getAddress(), 0, 0);
- subIGF.Builder.CreateStore(arg0, arg0Buf, IGM.getPointerAlignment());
- auto arg1Buf = subIGF.Builder.CreateConstInBoundsGEP2_32(argsBufferTy,
- argsBuffer.getAddress(), 0, 1);
- subIGF.Builder.CreateStore(arg1, arg1Buf, IGM.getPointerAlignment());
- auto arg2Buf = subIGF.Builder.CreateConstInBoundsGEP2_32(argsBufferTy,
- argsBuffer.getAddress(), 0, 2);
- subIGF.Builder.CreateStore(arg2, arg2Buf, IGM.getPointerAlignment());
-
- // Make the call.
- auto argsAddr = subIGF.Builder.CreateBitCast(argsBuffer.getAddress(),
- IGM.Int8PtrTy);
- auto result = subIGF.Builder.CreateCall(IGM.getGetGenericMetadataFn(),
- {request, argsAddr, descriptor});
- subIGF.Builder.CreateRet(result);
- }();
- }
+ auto generateThunkFn = [&IGM](IRGenFunction &subIGF) {
+ subIGF.CurFn->setDoesNotAccessMemory();
+ subIGF.CurFn->setCallingConv(IGM.SwiftCC);
+ IGM.setHasNoFramePointer(subIGF.CurFn);
+
+ auto params = subIGF.collectParameters();
+ auto request = params.claimNext();
+ auto arg0 = params.claimNext();
+ auto arg1 = params.claimNext();
+ auto arg2 = params.claimNext();
+ auto descriptor = params.claimNext();
+
+ // Allocate a buffer with enough storage for the arguments.
+ auto argsBufferTy =
+ llvm::ArrayType::get(IGM.Int8PtrTy,
+ NumDirectGenericTypeMetadataAccessFunctionArgs);
+ auto argsBuffer = subIGF.createAlloca(argsBufferTy,
+ IGM.getPointerAlignment(),
+ "generic.arguments");
+ subIGF.Builder.CreateLifetimeStart(argsBuffer,
+ IGM.getPointerSize() * NumDirectGenericTypeMetadataAccessFunctionArgs);
+
+ auto arg0Buf = subIGF.Builder.CreateConstInBoundsGEP2_32(argsBufferTy,
+ argsBuffer.getAddress(), 0, 0);
+ subIGF.Builder.CreateStore(arg0, arg0Buf, IGM.getPointerAlignment());
+ auto arg1Buf = subIGF.Builder.CreateConstInBoundsGEP2_32(argsBufferTy,
+ argsBuffer.getAddress(), 0, 1);
+ subIGF.Builder.CreateStore(arg1, arg1Buf, IGM.getPointerAlignment());
+ auto arg2Buf = subIGF.Builder.CreateConstInBoundsGEP2_32(argsBufferTy,
+ argsBuffer.getAddress(), 0, 2);
+ subIGF.Builder.CreateStore(arg2, arg2Buf, IGM.getPointerAlignment());
+
+ // Make the call.
+ auto argsAddr = subIGF.Builder.CreateBitCast(argsBuffer.getAddress(),
+ IGM.Int8PtrTy);
+ auto result = subIGF.Builder.CreateCall(IGM.getGetGenericMetadataFn(),
+ {request, argsAddr, descriptor});
+ subIGF.Builder.CreateRet(result);
+ };
+ auto thunkFn = IGM.getOrCreateHelperFunction(
+ "__swift_instantiateGenericMetadata",
+ IGM.TypeMetadataResponseTy,
+ {
+ IGM.SizeTy, // request
+ IGM.Int8PtrTy, // arg 0
+ IGM.Int8PtrTy, // arg 1
+ IGM.Int8PtrTy, // arg 2
+ IGM.TypeContextDescriptorPtrTy // type context descriptor
+ },
+ generateThunkFn,
+ /*noinline*/true);
// Call out to the helper.
auto arg0 = numArguments >= 1
@@ -2805,136 +2796,127 @@ emitMetadataAccessByMangledName(IRGenFunction &IGF, CanType type,
request.isStaticallyAbstract()
? "__swift_instantiateConcreteTypeFromMangledNameAbstract"
: "__swift_instantiateConcreteTypeFromMangledName";
- auto instantiationFn = cast(
- IGM.getModule()
- ->getOrInsertFunction(instantiationFnName, IGF.IGM.TypeMetadataPtrTy,
- cache->getType())
- .getCallee()
- ->stripPointerCasts());
- if (instantiationFn->empty()) {
- ApplyIRLinkage(IRLinkage::InternalLinkOnceODR)
- .to(instantiationFn);
- instantiationFn->setDoesNotAccessMemory();
- instantiationFn->setDoesNotThrow();
- instantiationFn->addAttribute(llvm::AttributeList::FunctionIndex,
- llvm::Attribute::NoInline);
- IGM.setHasNoFramePointer(instantiationFn);
-
- [&IGM, instantiationFn, request]{
- IRGenFunction subIGF(IGM, instantiationFn);
-
- auto params = subIGF.collectParameters();
- auto cache = params.claimNext();
-
- // Load the existing cache value.
- // Conceptually, this needs to establish memory ordering with the
- // store we do later in the function: if the metadata value is
- // non-null, we must be able to see any stores performed by the
- // initialization of the metadata. However, any attempt to read
- // from the metadata will be address-dependent on the loaded
- // metadata pointer, which is sufficient to provide adequate
- // memory ordering guarantees on all the platforms we care about:
- // ARM has special rules about address dependencies, and x86's
- // memory ordering is strong enough to guarantee the visibility
- // even without the address dependency.
- //
- // And we do not need to worry about the compiler because the
- // address dependency naturally forces an order to the memory
- // accesses.
- //
- // Therefore, we can perform a completely naked load here.
- // FIXME: Technically should be "consume", but that introduces barriers
- // in the current LLVM ARM backend.
- auto cacheWordAddr = subIGF.Builder.CreateBitCast(cache,
- IGM.Int64Ty->getPointerTo());
- auto load = subIGF.Builder.CreateLoad(cacheWordAddr, Alignment(8));
- // Make this barrier explicit when building for TSan to avoid false positives.
- if (IGM.IRGen.Opts.Sanitizers & SanitizerKind::Thread)
- load->setOrdering(llvm::AtomicOrdering::Acquire);
- else
- load->setOrdering(llvm::AtomicOrdering::Monotonic);
-
- // Compare the load result to see if it's negative.
- auto isUnfilledBB = subIGF.createBasicBlock("");
- auto contBB = subIGF.createBasicBlock("");
- llvm::Value *comparison = subIGF.Builder.CreateICmpSLT(load,
- llvm::ConstantInt::get(IGM.Int64Ty, 0));
- comparison = subIGF.Builder.CreateExpect(comparison,
- llvm::ConstantInt::get(IGM.Int1Ty, 0));
- subIGF.Builder.CreateCondBr(comparison, isUnfilledBB, contBB);
- auto loadBB = subIGF.Builder.GetInsertBlock();
-
- // If the load is negative, emit the call to instantiate the type
- // metadata.
- subIGF.Builder.SetInsertPoint(&subIGF.CurFn->back());
- subIGF.Builder.emitBlock(isUnfilledBB);
-
- // Break up the loaded value into size and relative address to the
- // string.
- auto size = subIGF.Builder.CreateAShr(load, 32);
- size = subIGF.Builder.CreateTruncOrBitCast(size, IGM.SizeTy);
- size = subIGF.Builder.CreateNeg(size);
-
- auto stringAddrOffset = subIGF.Builder.CreateTrunc(load,
- IGM.Int32Ty);
- stringAddrOffset = subIGF.Builder.CreateSExtOrBitCast(stringAddrOffset,
- IGM.SizeTy);
- auto stringAddrBase = subIGF.Builder.CreatePtrToInt(cache, IGM.SizeTy);
- if (IGM.getModule()->getDataLayout().isBigEndian()) {
- stringAddrBase = subIGF.Builder.CreateAdd(stringAddrBase,
- llvm::ConstantInt::get(IGM.SizeTy, 4));
- }
- auto stringAddr = subIGF.Builder.CreateAdd(stringAddrBase,
- stringAddrOffset);
- stringAddr = subIGF.Builder.CreateIntToPtr(stringAddr, IGM.Int8PtrTy);
-
- llvm::CallInst *call;
- if (request.isStaticallyAbstract()) {
- call = subIGF.Builder.CreateCall(
- IGM.getGetTypeByMangledNameInContextInMetadataStateFn(),
- {llvm::ConstantInt::get(IGM.SizeTy, (size_t)MetadataState::Abstract),
- stringAddr, size,
- // TODO: Use mangled name lookup in generic
- // contexts?
- llvm::ConstantPointerNull::get(IGM.TypeContextDescriptorPtrTy),
- llvm::ConstantPointerNull::get(IGM.Int8PtrPtrTy)});
- } else {
- call = subIGF.Builder.CreateCall(
- IGM.getGetTypeByMangledNameInContextFn(),
- {stringAddr, size,
- // TODO: Use mangled name lookup in generic
- // contexts?
- llvm::ConstantPointerNull::get(IGM.TypeContextDescriptorPtrTy),
- llvm::ConstantPointerNull::get(IGM.Int8PtrPtrTy)});
- }
- call->setDoesNotThrow();
- call->setDoesNotAccessMemory();
- call->setCallingConv(IGM.SwiftCC);
-
- // Store the result back to the cache. Metadata instantatiation should
- // already have emitted the necessary barriers to publish the instantiated
- // metadata to other threads, so we only need to expose the pointer.
- // Worst case, another thread might race with us and reinstantiate the
- // exact same metadata pointer.
- auto resultWord = subIGF.Builder.CreatePtrToInt(call, IGM.SizeTy);
- resultWord = subIGF.Builder.CreateZExtOrBitCast(resultWord, IGM.Int64Ty);
- auto store = subIGF.Builder.CreateStore(resultWord, cacheWordAddr,
- Alignment(8));
- store->setOrdering(llvm::AtomicOrdering::Monotonic);
- subIGF.Builder.CreateBr(contBB);
-
- subIGF.Builder.SetInsertPoint(loadBB);
- subIGF.Builder.emitBlock(contBB);
- auto phi = subIGF.Builder.CreatePHI(IGM.Int64Ty, 2);
- phi->addIncoming(load, loadBB);
- phi->addIncoming(resultWord, isUnfilledBB);
-
- auto resultAddr = subIGF.Builder.CreateTruncOrBitCast(phi, IGM.SizeTy);
- resultAddr = subIGF.Builder.CreateIntToPtr(resultAddr,
- IGM.TypeMetadataPtrTy);
- subIGF.Builder.CreateRet(resultAddr);
- }();
- }
+ auto generateInstantiationFn = [&IGM, request](IRGenFunction &subIGF) {
+ subIGF.CurFn->setDoesNotAccessMemory();
+ IGM.setHasNoFramePointer(subIGF.CurFn);
+
+ auto params = subIGF.collectParameters();
+ auto cache = params.claimNext();
+
+ // Load the existing cache value.
+ // Conceptually, this needs to establish memory ordering with the
+ // store we do later in the function: if the metadata value is
+ // non-null, we must be able to see any stores performed by the
+ // initialization of the metadata. However, any attempt to read
+ // from the metadata will be address-dependent on the loaded
+ // metadata pointer, which is sufficient to provide adequate
+ // memory ordering guarantees on all the platforms we care about:
+ // ARM has special rules about address dependencies, and x86's
+ // memory ordering is strong enough to guarantee the visibility
+ // even without the address dependency.
+ //
+ // And we do not need to worry about the compiler because the
+ // address dependency naturally forces an order to the memory
+ // accesses.
+ //
+ // Therefore, we can perform a completely naked load here.
+ // FIXME: Technically should be "consume", but that introduces barriers
+ // in the current LLVM ARM backend.
+ auto cacheWordAddr = subIGF.Builder.CreateBitCast(cache,
+ IGM.Int64Ty->getPointerTo());
+ auto load = subIGF.Builder.CreateLoad(cacheWordAddr, Alignment(8));
+ // Make this barrier explicit when building for TSan to avoid false positives.
+ if (IGM.IRGen.Opts.Sanitizers & SanitizerKind::Thread)
+ load->setOrdering(llvm::AtomicOrdering::Acquire);
+ else
+ load->setOrdering(llvm::AtomicOrdering::Monotonic);
+
+ // Compare the load result to see if it's negative.
+ auto isUnfilledBB = subIGF.createBasicBlock("");
+ auto contBB = subIGF.createBasicBlock("");
+ llvm::Value *comparison = subIGF.Builder.CreateICmpSLT(load,
+ llvm::ConstantInt::get(IGM.Int64Ty, 0));
+ comparison = subIGF.Builder.CreateExpect(comparison,
+ llvm::ConstantInt::get(IGM.Int1Ty, 0));
+ subIGF.Builder.CreateCondBr(comparison, isUnfilledBB, contBB);
+ auto loadBB = subIGF.Builder.GetInsertBlock();
+
+ // If the load is negative, emit the call to instantiate the type
+ // metadata.
+ subIGF.Builder.SetInsertPoint(&subIGF.CurFn->back());
+ subIGF.Builder.emitBlock(isUnfilledBB);
+
+ // Break up the loaded value into size and relative address to the
+ // string.
+ auto size = subIGF.Builder.CreateAShr(load, 32);
+ size = subIGF.Builder.CreateTruncOrBitCast(size, IGM.SizeTy);
+ size = subIGF.Builder.CreateNeg(size);
+
+ auto stringAddrOffset = subIGF.Builder.CreateTrunc(load,
+ IGM.Int32Ty);
+ stringAddrOffset = subIGF.Builder.CreateSExtOrBitCast(stringAddrOffset,
+ IGM.SizeTy);
+ auto stringAddrBase = subIGF.Builder.CreatePtrToInt(cache, IGM.SizeTy);
+ if (IGM.getModule()->getDataLayout().isBigEndian()) {
+ stringAddrBase = subIGF.Builder.CreateAdd(stringAddrBase,
+ llvm::ConstantInt::get(IGM.SizeTy, 4));
+ }
+ auto stringAddr = subIGF.Builder.CreateAdd(stringAddrBase,
+ stringAddrOffset);
+ stringAddr = subIGF.Builder.CreateIntToPtr(stringAddr, IGM.Int8PtrTy);
+
+ llvm::CallInst *call;
+ if (request.isStaticallyAbstract()) {
+ call = subIGF.Builder.CreateCall(
+ IGM.getGetTypeByMangledNameInContextInMetadataStateFn(),
+ {llvm::ConstantInt::get(IGM.SizeTy, (size_t)MetadataState::Abstract),
+ stringAddr, size,
+ // TODO: Use mangled name lookup in generic
+ // contexts?
+ llvm::ConstantPointerNull::get(IGM.TypeContextDescriptorPtrTy),
+ llvm::ConstantPointerNull::get(IGM.Int8PtrPtrTy)});
+ } else {
+ call = subIGF.Builder.CreateCall(
+ IGM.getGetTypeByMangledNameInContextFn(),
+ {stringAddr, size,
+ // TODO: Use mangled name lookup in generic
+ // contexts?
+ llvm::ConstantPointerNull::get(IGM.TypeContextDescriptorPtrTy),
+ llvm::ConstantPointerNull::get(IGM.Int8PtrPtrTy)});
+ }
+ call->setDoesNotThrow();
+ call->setDoesNotAccessMemory();
+ call->setCallingConv(IGM.SwiftCC);
+
+ // Store the result back to the cache. Metadata instantatiation should
+ // already have emitted the necessary barriers to publish the instantiated
+ // metadata to other threads, so we only need to expose the pointer.
+ // Worst case, another thread might race with us and reinstantiate the
+ // exact same metadata pointer.
+ auto resultWord = subIGF.Builder.CreatePtrToInt(call, IGM.SizeTy);
+ resultWord = subIGF.Builder.CreateZExtOrBitCast(resultWord, IGM.Int64Ty);
+ auto store = subIGF.Builder.CreateStore(resultWord, cacheWordAddr,
+ Alignment(8));
+ store->setOrdering(llvm::AtomicOrdering::Monotonic);
+ subIGF.Builder.CreateBr(contBB);
+
+ subIGF.Builder.SetInsertPoint(loadBB);
+ subIGF.Builder.emitBlock(contBB);
+ auto phi = subIGF.Builder.CreatePHI(IGM.Int64Ty, 2);
+ phi->addIncoming(load, loadBB);
+ phi->addIncoming(resultWord, isUnfilledBB);
+
+ auto resultAddr = subIGF.Builder.CreateTruncOrBitCast(phi, IGM.SizeTy);
+ resultAddr = subIGF.Builder.CreateIntToPtr(resultAddr,
+ IGM.TypeMetadataPtrTy);
+ subIGF.Builder.CreateRet(resultAddr);
+ };
+ auto instantiationFn =
+ IGM.getOrCreateHelperFunction(instantiationFnName,
+ IGF.IGM.TypeMetadataPtrTy,
+ cache->getType(),
+ generateInstantiationFn,
+ /*noinline*/true);
auto call = IGF.Builder.CreateCall(instantiationFn, cache);
call->setDoesNotThrow();
diff --git a/lib/Immediate/Immediate.cpp b/lib/Immediate/Immediate.cpp
index 5ac87f6f42397..b49156177b8f1 100644
--- a/lib/Immediate/Immediate.cpp
+++ b/lib/Immediate/Immediate.cpp
@@ -30,6 +30,7 @@
#include "swift/SILOptimizer/PassManager/Passes.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Config/config.h"
+#include "llvm/ExecutionEngine/Orc/DebugUtils.h"
#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
#include "llvm/IR/LLVMContext.h"
@@ -75,6 +76,18 @@ static void *loadRuntimeLib(StringRef sharedLibName,
return nullptr;
}
+static void DumpLLVMIR(const llvm::Module &M) {
+ std::string path = (M.getName() + ".ll").str();
+ for (size_t count = 0; llvm::sys::fs::exists(path); )
+ path = (M.getName() + llvm::utostr(count++) + ".ll").str();
+
+ std::error_code error;
+ llvm::raw_fd_ostream stream(path, error);
+ if (error)
+ return;
+ M.print(stream, /*AssemblyAnnotationWriter=*/nullptr);
+}
+
void *swift::immediate::loadSwiftRuntime(ArrayRef
runtimeLibPaths) {
#if defined(_WIN32)
@@ -290,6 +303,18 @@ int swift::RunImmediately(CompilerInstance &CI,
}
auto Module = GenModule.getModule();
+
+ switch (IRGenOpts.DumpJIT) {
+ case JITDebugArtifact::None:
+ break;
+ case JITDebugArtifact::LLVMIR:
+ DumpLLVMIR(*Module);
+ break;
+ case JITDebugArtifact::Object:
+ JIT->getObjTransformLayer().setTransform(llvm::orc::DumpObjects());
+ break;
+ }
+
{
// Get a generator for the process symbols and attach it to the main
// JITDylib.
diff --git a/lib/LLVMPasses/LLVMMergeFunctions.cpp b/lib/LLVMPasses/LLVMMergeFunctions.cpp
index da76bba87217f..51db1af2f4892 100644
--- a/lib/LLVMPasses/LLVMMergeFunctions.cpp
+++ b/lib/LLVMPasses/LLVMMergeFunctions.cpp
@@ -222,12 +222,6 @@ class SwiftMergeFunctions : public ModulePass {
bool runOnModule(Module &M) override;
private:
- enum {
- /// The maximum number of parameters added to a merged functions. This
- /// roughly corresponds to the number of differing constants.
- maxAddedParams = 4
- };
-
struct FunctionEntry;
/// Describes the set of functions which are considered as "equivalent" (i.e.
@@ -359,7 +353,7 @@ class SwiftMergeFunctions : public ModulePass {
}
};
- using ParamInfos = SmallVector;
+ using ParamInfos = SmallVector;
GlobalNumberState GlobalNumbers;
@@ -398,14 +392,15 @@ class SwiftMergeFunctions : public ModulePass {
FunctionInfo removeFuncWithMostParams(FunctionInfos &FInfos);
- bool deriveParams(ParamInfos &Params, FunctionInfos &FInfos);
+ bool deriveParams(ParamInfos &Params, FunctionInfos &FInfos,
+ unsigned maxParams);
bool numOperandsDiffer(FunctionInfos &FInfos);
bool constsDiffer(const FunctionInfos &FInfos, unsigned OpIdx);
bool tryMapToParameter(FunctionInfos &FInfos, unsigned OpIdx,
- ParamInfos &Params);
+ ParamInfos &Params, unsigned maxParams);
void mergeWithParams(const FunctionInfos &FInfos, ParamInfos &Params);
@@ -524,17 +519,9 @@ static bool mayMergeCallsToFunction(Function &F) {
return true;
}
-/// Returns true if function \p F is eligible for merging.
-static bool isEligibleFunction(Function *F) {
- if (F->isDeclaration())
- return false;
-
- if (F->hasAvailableExternallyLinkage())
- return false;
-
- if (F->getFunctionType()->isVarArg())
- return false;
-
+/// Returns the benefit, which is approximately the size of the function.
+/// Return 0, if the function should not be merged.
+static unsigned getBenefit(Function *F) {
unsigned Benefit = 0;
// We don't want to merge very small functions, because the overhead of
@@ -545,7 +532,7 @@ static bool isEligibleFunction(Function *F) {
if (CallBase *CB = dyn_cast(&I)) {
Function *Callee = CB->getCalledFunction();
if (Callee && !mayMergeCallsToFunction(*Callee))
- return false;
+ return 0;
if (!Callee || !Callee->isIntrinsic()) {
Benefit += 5;
continue;
@@ -554,6 +541,21 @@ static bool isEligibleFunction(Function *F) {
Benefit += 1;
}
}
+ return Benefit;
+}
+
+/// Returns true if function \p F is eligible for merging.
+static bool isEligibleFunction(Function *F) {
+ if (F->isDeclaration())
+ return false;
+
+ if (F->hasAvailableExternallyLinkage())
+ return false;
+
+ if (F->getFunctionType()->isVarArg())
+ return false;
+
+ unsigned Benefit = getBenefit(F);
if (Benefit < FunctionMergeThreshold)
return false;
@@ -723,12 +725,17 @@ bool SwiftMergeFunctions::tryMergeEquivalenceClass(FunctionEntry *FirstInClass)
bool Changed = false;
int Try = 0;
+ unsigned Benefit = getBenefit(FirstInClass->F);
+
+ // The bigger the function, the more parameters are allowed.
+ unsigned maxParams = std::max(4u, Benefit / 100);
+
// We need multiple tries if there are some functions in FInfos which differ
// too much from the first function in FInfos. But we limit the number of
// tries to a small number, because this is quadratic.
while (FInfos.size() >= 2 && Try++ < 4) {
ParamInfos Params;
- bool Merged = deriveParams(Params, FInfos);
+ bool Merged = deriveParams(Params, FInfos, maxParams);
if (Merged) {
mergeWithParams(FInfos, Params);
Changed = true;
@@ -767,7 +774,8 @@ removeFuncWithMostParams(FunctionInfos &FInfos) {
/// Returns true on success, i.e. the functions in \p FInfos can be merged with
/// the parameters returned in \p Params.
bool SwiftMergeFunctions::deriveParams(ParamInfos &Params,
- FunctionInfos &FInfos) {
+ FunctionInfos &FInfos,
+ unsigned maxParams) {
for (FunctionInfo &FI : FInfos)
FI.init();
@@ -796,7 +804,7 @@ bool SwiftMergeFunctions::deriveParams(ParamInfos &Params,
if (constsDiffer(FInfos, OpIdx)) {
// This instruction has operands which differ in at least some
// functions. So we need to parameterize it.
- if (!tryMapToParameter(FInfos, OpIdx, Params)) {
+ if (!tryMapToParameter(FInfos, OpIdx, Params, maxParams)) {
// We ran out of parameters.
return false;
}
@@ -845,7 +853,8 @@ bool SwiftMergeFunctions::constsDiffer(const FunctionInfos &FInfos,
/// Returns true if a parameter could be created or found without exceeding the
/// maximum number of parameters.
bool SwiftMergeFunctions::tryMapToParameter(FunctionInfos &FInfos,
- unsigned OpIdx, ParamInfos &Params) {
+ unsigned OpIdx, ParamInfos &Params,
+ unsigned maxParams) {
ParamInfo *Matching = nullptr;
// Try to find an existing parameter which exactly matches the differing
// operands of the current instruction.
@@ -858,7 +867,7 @@ bool SwiftMergeFunctions::tryMapToParameter(FunctionInfos &FInfos,
if (!Matching) {
// We need a new parameter.
// Check if we are within the limit.
- if (Params.size() >= maxAddedParams)
+ if (Params.size() >= maxParams)
return false;
Params.resize(Params.size() + 1);
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 1009646c1c40e..d7f77869d6723 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -397,7 +397,7 @@ ParserResult Parser::parseExprSequenceElement(Diag<> message,
SourceLoc awaitLoc = consumeToken(tok::kw___await);
ParserResult sub = parseExprUnary(message, isExprBasic);
if (!sub.hasCodeCompletion() && !sub.isNull()) {
- ElementContext.setCreateSyntax(SyntaxKind::TryExpr);
+ ElementContext.setCreateSyntax(SyntaxKind::AwaitExpr);
sub = makeParserResult(new (Context) AwaitExpr(awaitLoc, sub.get()));
}
diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp
index 443f572c04acb..aefea2401c15a 100644
--- a/lib/Parse/ParseType.cpp
+++ b/lib/Parse/ParseType.cpp
@@ -465,10 +465,10 @@ ParserResult Parser::parseType(Diag<> MessageID,
ParsedFunctionTypeSyntaxBuilder Builder(*SyntaxContext);
Builder.useReturnType(std::move(*SyntaxContext->popIf()));
Builder.useArrow(SyntaxContext->popToken());
- if (asyncLoc.isValid())
- Builder.useAsyncKeyword(SyntaxContext->popToken());
if (throwsLoc.isValid())
Builder.useThrowsOrRethrowsKeyword(SyntaxContext->popToken());
+ if (asyncLoc.isValid())
+ Builder.useAsyncKeyword(SyntaxContext->popToken());
auto InputNode(std::move(*SyntaxContext->popIf()));
if (auto TupleTypeNode = InputNode.getAs()) {
diff --git a/lib/SIL/IR/SILFunction.cpp b/lib/SIL/IR/SILFunction.cpp
index 8e0d770d82310..0a39386e3f35c 100644
--- a/lib/SIL/IR/SILFunction.cpp
+++ b/lib/SIL/IR/SILFunction.cpp
@@ -110,7 +110,7 @@ SILFunction::SILFunction(SILModule &Module, SILLinkage Linkage, StringRef Name,
ExactSelfClass(isExactSelfClass),
Inlined(false), Zombie(false), HasOwnership(true),
WasDeserializedCanonical(false), IsWithoutActuallyEscapingThunk(false),
- OptMode(unsigned(OptimizationMode::NotSet)),
+ IsAsync(false), OptMode(unsigned(OptimizationMode::NotSet)),
EffectsKindAttr(unsigned(E)) {
assert(!Transparent || !IsDynamicReplaceable);
validateSubclassScope(classSubclassScope, isThunk, nullptr);
diff --git a/lib/SIL/IR/SILFunctionBuilder.cpp b/lib/SIL/IR/SILFunctionBuilder.cpp
index b56d34ea74d00..c28ba05090b1b 100644
--- a/lib/SIL/IR/SILFunctionBuilder.cpp
+++ b/lib/SIL/IR/SILFunctionBuilder.cpp
@@ -217,6 +217,10 @@ SILFunction *SILFunctionBuilder::getOrCreateFunction(
}
addFunctionAttributes(F, decl->getAttrs(), mod, getOrCreateDeclaration,
constant);
+
+ if (auto *funcDecl = dyn_cast(decl)) {
+ F->setAsync(funcDecl->hasAsync());
+ }
}
return F;
diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp
index e165434668d42..60f7584418787 100644
--- a/lib/SIL/IR/SILFunctionType.cpp
+++ b/lib/SIL/IR/SILFunctionType.cpp
@@ -242,12 +242,14 @@ IndexSubset *SILFunctionType::getDifferentiabilityResultIndices() {
// 2. `@noDerivative`: neither a differentiability parameter nor a
// differentiability result.
// However, there is no way to represent an `inout` parameter that:
- // 3. Is a differentiability parameter but not a differentiability result.
- // 4. Is a differentiability result but not a differentiability parameter.
+ // 3. Is a differentiability result but not a differentiability parameter.
+ // 4. Is a differentiability parameter but not a differentiability result.
+ // This case is not currently expressible and does not yet have clear use
+ // cases, so supporting it is a non-goal.
//
// See TF-1305 for solution ideas. For now, `@noDerivative` `inout`
// parameters are not treated as differentiability results, unless the
- // original function has no formal results, which case all `inout`
+ // original function has no formal results, in which case all `inout`
// parameters are treated as differentiability results.
if (getResults().empty() ||
inoutParamAndIndex.value().getDifferentiability() !=
diff --git a/lib/SIL/IR/SILGlobalVariable.cpp b/lib/SIL/IR/SILGlobalVariable.cpp
index bad50c8437f93..609a8318b153d 100644
--- a/lib/SIL/IR/SILGlobalVariable.cpp
+++ b/lib/SIL/IR/SILGlobalVariable.cpp
@@ -157,7 +157,6 @@ bool SILGlobalVariable::isValidStaticInitializerInst(const SILInstruction *I,
switch (cast(I)->getEncoding()) {
case StringLiteralInst::Encoding::Bytes:
case StringLiteralInst::Encoding::UTF8:
- case StringLiteralInst::Encoding::UTF16:
return true;
case StringLiteralInst::Encoding::ObjCSelector:
// Objective-C selector string literals cannot be used in static
diff --git a/lib/SIL/IR/SILInstructions.cpp b/lib/SIL/IR/SILInstructions.cpp
index 85e21ea609f21..1faa9ec6ae6a1 100644
--- a/lib/SIL/IR/SILInstructions.cpp
+++ b/lib/SIL/IR/SILInstructions.cpp
@@ -1043,9 +1043,6 @@ CondFailInst *CondFailInst::create(SILDebugLocation DebugLoc, SILValue Operand,
}
uint64_t StringLiteralInst::getCodeUnitCount() {
- auto E = unsigned(Encoding::UTF16);
- if (SILInstruction::Bits.StringLiteralInst.TheEncoding == E)
- return unicode::getUTF16Length(getValue());
return SILInstruction::Bits.StringLiteralInst.Length;
}
diff --git a/lib/SIL/IR/SILPrinter.cpp b/lib/SIL/IR/SILPrinter.cpp
index b1d92dd8ee5a4..bb84c23ef1e4c 100644
--- a/lib/SIL/IR/SILPrinter.cpp
+++ b/lib/SIL/IR/SILPrinter.cpp
@@ -1339,7 +1339,6 @@ class SILPrinter : public SILInstructionVisitor {
switch (kind) {
case StringLiteralInst::Encoding::Bytes: return "bytes ";
case StringLiteralInst::Encoding::UTF8: return "utf8 ";
- case StringLiteralInst::Encoding::UTF16: return "utf16 ";
case StringLiteralInst::Encoding::ObjCSelector: return "objc_selector ";
}
llvm_unreachable("bad string literal encoding");
@@ -2599,6 +2598,9 @@ void SILFunction::print(SILPrintContext &PrintCtx) const {
if (isWithoutActuallyEscapingThunk())
OS << "[without_actually_escaping] ";
+ if (isAsync())
+ OS << "[async] ";
+
switch (getSpecialPurpose()) {
case SILFunction::Purpose::None:
break;
diff --git a/lib/SIL/Parser/ParseSIL.cpp b/lib/SIL/Parser/ParseSIL.cpp
index 1cb9139437f49..57a637eed8c1b 100644
--- a/lib/SIL/Parser/ParseSIL.cpp
+++ b/lib/SIL/Parser/ParseSIL.cpp
@@ -918,6 +918,7 @@ static bool parseDeclSILOptional(bool *isTransparent,
bool *isWeakImported,
AvailabilityContext *availability,
bool *isWithoutActuallyEscapingThunk,
+ bool *isAsync,
SmallVectorImpl *Semantics,
SmallVectorImpl *SpecAttrs,
ValueDecl **ClangDecl,
@@ -956,6 +957,8 @@ static bool parseDeclSILOptional(bool *isTransparent,
else if (isWithoutActuallyEscapingThunk
&& SP.P.Tok.getText() == "without_actually_escaping")
*isWithoutActuallyEscapingThunk = true;
+ else if (isAsync && SP.P.Tok.getText() == "async")
+ *isAsync = true;
else if (specialPurpose && SP.P.Tok.getText() == "global_init")
*specialPurpose = SILFunction::Purpose::GlobalInit;
else if (specialPurpose && SP.P.Tok.getText() == "lazy_getter")
@@ -2615,8 +2618,6 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
StringLiteralInst::Encoding encoding;
if (P.Tok.getText() == "utf8") {
encoding = StringLiteralInst::Encoding::UTF8;
- } else if (P.Tok.getText() == "utf16") {
- encoding = StringLiteralInst::Encoding::UTF16;
} else if (P.Tok.getText() == "objc_selector") {
encoding = StringLiteralInst::Encoding::ObjCSelector;
} else if (P.Tok.getText() == "bytes") {
@@ -5682,6 +5683,7 @@ bool SILParserState::parseDeclSIL(Parser &P) {
bool isWeakImported = false;
AvailabilityContext availability = AvailabilityContext::alwaysAvailable();
bool isWithoutActuallyEscapingThunk = false;
+ bool isAsync = false;
Inline_t inlineStrategy = InlineDefault;
OptimizationMode optimizationMode = OptimizationMode::NotSet;
SmallVector Semantics;
@@ -5696,8 +5698,8 @@ bool SILParserState::parseDeclSIL(Parser &P) {
&isThunk, &isDynamic, &isExactSelfClass, &DynamicallyReplacedFunction,
&objCReplacementFor, &specialPurpose, &inlineStrategy,
&optimizationMode, nullptr, &isWeakImported, &availability,
- &isWithoutActuallyEscapingThunk, &Semantics,
- &SpecAttrs, &ClangDecl, &MRK, FunctionState, M) ||
+ &isWithoutActuallyEscapingThunk, &isAsync, &Semantics, &SpecAttrs,
+ &ClangDecl, &MRK, FunctionState, M) ||
P.parseToken(tok::at_sign, diag::expected_sil_function_name) ||
P.parseIdentifier(FnName, FnNameLoc, diag::expected_sil_function_name) ||
P.parseToken(tok::colon, diag::expected_sil_type))
@@ -5735,6 +5737,7 @@ bool SILParserState::parseDeclSIL(Parser &P) {
FunctionState.F->setAvailabilityForLinkage(availability);
FunctionState.F->setWithoutActuallyEscapingThunk(
isWithoutActuallyEscapingThunk);
+ FunctionState.F->setAsync(isAsync);
FunctionState.F->setInlineStrategy(inlineStrategy);
FunctionState.F->setOptimizationMode(optimizationMode);
FunctionState.F->setEffectsKind(MRK);
@@ -5920,10 +5923,9 @@ bool SILParserState::parseSILGlobal(Parser &P) {
SILParser State(P);
if (parseSILLinkage(GlobalLinkage, P) ||
parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr, nullptr,
- nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr, nullptr,
- &isLet, nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr, nullptr, State, M) ||
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, &isLet, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, State, M) ||
P.parseToken(tok::at_sign, diag::expected_sil_value_name) ||
P.parseIdentifier(GlobalName, NameLoc, diag::expected_sil_value_name) ||
P.parseToken(tok::colon, diag::expected_sil_type))
@@ -5972,7 +5974,7 @@ bool SILParserState::parseSILProperty(Parser &P) {
if (parseDeclSILOptional(nullptr, &Serialized, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr, nullptr, nullptr, SP, M))
+ nullptr, nullptr, nullptr, nullptr, SP, M))
return true;
ValueDecl *VD;
@@ -6042,8 +6044,7 @@ bool SILParserState::parseSILVTable(Parser &P) {
if (parseDeclSILOptional(nullptr, &Serialized, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr, nullptr, nullptr,
- VTableState, M))
+ nullptr, nullptr, nullptr, nullptr, VTableState, M))
return true;
// Parse the class name.
@@ -6582,8 +6583,7 @@ bool SILParserState::parseSILWitnessTable(Parser &P) {
if (parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr, nullptr, nullptr,
- WitnessState, M))
+ nullptr, nullptr, nullptr, nullptr, WitnessState, M))
return true;
Scope S(&P, ScopeKind::TopLevel);
diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp
index c8c80a3f1d3f3..bffecc2c2c187 100644
--- a/lib/SILGen/SILGenApply.cpp
+++ b/lib/SILGen/SILGenApply.cpp
@@ -1628,11 +1628,6 @@ static PreparedArguments emitStringLiteral(SILGenFunction &SGF, Expr *E,
Length = Str.size();
break;
- case StringLiteralExpr::UTF16: {
- instEncoding = StringLiteralInst::Encoding::UTF16;
- Length = unicode::getUTF16Length(Str);
- break;
- }
case StringLiteralExpr::OneUnicodeScalar: {
SILType Int32Ty = SILType::getBuiltinIntegerType(32, SGF.getASTContext());
SILValue UnicodeScalarValue =
@@ -1674,11 +1669,6 @@ static PreparedArguments emitStringLiteral(SILGenFunction &SGF, Expr *E,
ArrayRef Elts;
ArrayRef TypeElts;
switch (instEncoding) {
- case StringLiteralInst::Encoding::UTF16:
- Elts = llvm::makeArrayRef(EltsArray).slice(0, 2);
- TypeElts = llvm::makeArrayRef(TypeEltsArray).slice(0, 2);
- break;
-
case StringLiteralInst::Encoding::UTF8:
Elts = EltsArray;
TypeElts = TypeEltsArray;
diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp
index 6b524fe06a9d2..cb8273d129e1e 100644
--- a/lib/SILGen/SILGenExpr.cpp
+++ b/lib/SILGen/SILGenExpr.cpp
@@ -3734,6 +3734,11 @@ RValue RValueEmitter::visitKeyPathExpr(KeyPathExpr *E, SGFContext C) {
case KeyPathExpr::Component::Kind::UnresolvedProperty:
case KeyPathExpr::Component::Kind::UnresolvedSubscript:
llvm_unreachable("not resolved");
+ break;
+
+ case KeyPathExpr::Component::Kind::DictionaryKey:
+ llvm_unreachable("DictionaryKey only valid in #keyPath");
+ break;
}
}
diff --git a/lib/SILOptimizer/ARC/RefCountState.cpp b/lib/SILOptimizer/ARC/RefCountState.cpp
index eabe4d5ed7958..e0c43fed19040 100644
--- a/lib/SILOptimizer/ARC/RefCountState.cpp
+++ b/lib/SILOptimizer/ARC/RefCountState.cpp
@@ -365,6 +365,14 @@ bool BottomUpRefCountState::handlePotentialGuaranteedUser(
if (!mayGuaranteedUseValue(PotentialGuaranteedUser, getRCRoot(), AA))
return false;
+ // If we can prove that the pointer we are tracking cannot be decremented,
+ // return. On return, BottomUpRefCountState::handlePotentialUser can correctly
+ // handle transition of refcount state. It transitions from a Decrement
+ // refcount state to a MighBeUsed refcount state
+ if (!mayDecrementRefCount(PotentialGuaranteedUser, getRCRoot(), AA)) {
+ return false;
+ }
+
// Instructions that we do not recognize (and thus will not move) and that
// *must* use RCIdentity, implies we are always known safe as long as meet
// over all path constraints are satisfied.
@@ -816,6 +824,13 @@ bool TopDownRefCountState::handlePotentialGuaranteedUser(
if (!mayGuaranteedUseValue(PotentialGuaranteedUser, getRCRoot(), AA))
return false;
+ // If we can prove that the pointer we are tracking cannot be decremented,
+ // return. On return, TopDownRefCountState::handlePotentialUser can correctly
+ // handle transition of refcount state.
+ if (!mayDecrementRefCount(PotentialGuaranteedUser, getRCRoot(), AA)) {
+ return false;
+ }
+
// Otherwise, update our step given that we have a potential decrement.
return handleGuaranteedUser(PotentialGuaranteedUser, getRCRoot(),
SetFactory, AA);
diff --git a/lib/SILOptimizer/Differentiation/PullbackCloner.cpp b/lib/SILOptimizer/Differentiation/PullbackCloner.cpp
index 0438285ed07aa..aa40f16f53d91 100644
--- a/lib/SILOptimizer/Differentiation/PullbackCloner.cpp
+++ b/lib/SILOptimizer/Differentiation/PullbackCloner.cpp
@@ -650,6 +650,19 @@ class PullbackCloner::Implementation final
return alloc;
}
+ //--------------------------------------------------------------------------//
+ // Optional differentiation
+ //--------------------------------------------------------------------------//
+
+ /// Given a `wrappedAdjoint` value of type `T.TangentVector`, creates an
+ /// `Optional.TangentVector` value from it and adds it to the adjoint value
+ /// of `optionalValue`.
+ ///
+ /// `wrappedAdjoint` may be an object or address value, both cases are
+ /// handled.
+ void accumulateAdjointForOptional(SILBasicBlock *bb, SILValue optionalValue,
+ SILValue wrappedAdjoint);
+
//--------------------------------------------------------------------------//
// Array literal initialization differentiation
//--------------------------------------------------------------------------//
@@ -1503,6 +1516,30 @@ class PullbackCloner::Implementation final
}
}
+ /// Handle `unchecked_take_enum_data_addr` instruction.
+ /// Currently, only `Optional`-typed operands are supported.
+ /// Original: y = unchecked_take_enum_data_addr x : $*Enum, #Enum.Case
+ /// Adjoint: adj[x] += $Enum.TangentVector(adj[y])
+ void
+ visitUncheckedTakeEnumDataAddrInst(UncheckedTakeEnumDataAddrInst *utedai) {
+ auto *bb = utedai->getParent();
+ auto adjBuf = getAdjointBuffer(bb, utedai);
+ auto enumTy = utedai->getOperand()->getType();
+ auto *optionalEnumDecl = getASTContext().getOptionalDecl();
+ // Only `Optional`-typed operands are supported for now. Diagnose all other
+ // enum operand types.
+ if (enumTy.getASTType().getEnumOrBoundGenericEnum() != optionalEnumDecl) {
+ LLVM_DEBUG(getADDebugStream()
+ << "Unhandled instruction in PullbackCloner: " << *utedai);
+ getContext().emitNondifferentiabilityError(
+ utedai, getInvoker(),
+ diag::autodiff_expression_not_differentiable_note);
+ errorOccurred = true;
+ return;
+ }
+ accumulateAdjointForOptional(bb, utedai->getOperand(), adjBuf);
+ }
+
#define NOT_DIFFERENTIABLE(INST, DIAG) void visit##INST##Inst(INST##Inst *inst);
#undef NOT_DIFFERENTIABLE
@@ -1639,11 +1676,16 @@ bool PullbackCloner::Implementation::run() {
// Diagnose active enum values. Differentiation of enum values requires
// special adjoint value handling and is not yet supported. Diagnose
// only the first active enum value to prevent too many diagnostics.
- if (type.getEnumOrBoundGenericEnum()) {
- getContext().emitNondifferentiabilityError(
- v, getInvoker(), diag::autodiff_enums_unsupported);
- errorOccurred = true;
- return true;
+ //
+ // Do not diagnose `Optional`-typed values, which will have special-case
+ // differentiation support.
+ if (auto *enumDecl = type.getEnumOrBoundGenericEnum()) {
+ if (enumDecl != getContext().getASTContext().getOptionalDecl()) {
+ getContext().emitNondifferentiabilityError(
+ v, getInvoker(), diag::autodiff_enums_unsupported);
+ errorOccurred = true;
+ return true;
+ }
}
// Diagnose unsupported stored property projections.
if (auto *inst = dyn_cast(v)) {
@@ -1972,6 +2014,103 @@ void PullbackCloner::Implementation::emitZeroDerivativesForNonvariedResult(
<< pullback);
}
+void PullbackCloner::Implementation::accumulateAdjointForOptional(
+ SILBasicBlock *bb, SILValue optionalValue, SILValue wrappedAdjoint) {
+ auto pbLoc = getPullback().getLocation();
+ // Handle `switch_enum` on `Optional`.
+ auto *optionalEnumDecl = getASTContext().getOptionalDecl();
+ auto optionalTy = optionalValue->getType();
+ assert(optionalTy.getASTType().getEnumOrBoundGenericEnum() ==
+ optionalEnumDecl);
+ // `Optional`
+ optionalTy = remapType(optionalTy);
+ // `T`
+ auto wrappedType = optionalTy.getOptionalObjectType();
+ // `T.TangentVector`
+ auto wrappedTanType = remapType(wrappedAdjoint->getType());
+ // `Optional`
+ auto optionalOfWrappedTanType = SILType::getOptionalType(wrappedTanType);
+ // `Optional.TangentVector`
+ auto optionalTanTy = getRemappedTangentType(optionalTy);
+ auto *optionalTanDecl = optionalTanTy.getNominalOrBoundGenericNominal();
+ // Look up the `Optional.TangentVector.init` declaration.
+ auto initLookup =
+ optionalTanDecl->lookupDirect(DeclBaseName::createConstructor());
+ ConstructorDecl *constructorDecl = nullptr;
+ for (auto *candidate : initLookup) {
+ auto candidateModule = candidate->getModuleContext();
+ if (candidateModule->getName() ==
+ builder.getASTContext().Id_Differentiation ||
+ candidateModule->isStdlibModule()) {
+ assert(!constructorDecl && "Multiple `Optional.TangentVector.init`s");
+ constructorDecl = cast(candidate);
+#ifdef NDEBUG
+ break;
+#endif
+ }
+ }
+ assert(constructorDecl && "No `Optional.TangentVector.init`");
+
+ // Allocate a local buffer for the `Optional` adjoint value.
+ auto *optTanAdjBuf = builder.createAllocStack(pbLoc, optionalTanTy);
+ // Find `Optional.some` EnumElementDecl.
+ auto someEltDecl = builder.getASTContext().getOptionalSomeDecl();
+
+ // Initialize an `Optional` buffer from `wrappedAdjoint` as
+ // the input for `Optional.TangentVector.init`.
+ auto *optArgBuf = builder.createAllocStack(pbLoc, optionalOfWrappedTanType);
+ if (optionalOfWrappedTanType.isLoadableOrOpaque(builder.getFunction())) {
+ // %enum = enum $Optional, #Optional.some!enumelt,
+ // %wrappedAdjoint : $T
+ auto *enumInst = builder.createEnum(pbLoc, wrappedAdjoint, someEltDecl,
+ optionalOfWrappedTanType);
+ // store %enum to %optArgBuf
+ builder.emitStoreValueOperation(pbLoc, enumInst, optArgBuf,
+ StoreOwnershipQualifier::Init);
+ } else {
+ // %enumAddr = init_enum_data_addr %optArgBuf $Optional,
+ // #Optional.some!enumelt
+ auto *enumAddr = builder.createInitEnumDataAddr(
+ pbLoc, optArgBuf, someEltDecl, wrappedTanType.getAddressType());
+ // copy_addr %wrappedAdjoint to [initialization] %enumAddr
+ builder.createCopyAddr(pbLoc, wrappedAdjoint, enumAddr, IsNotTake,
+ IsInitialization);
+ // inject_enum_addr %optArgBuf : $*Optional,
+ // #Optional.some!enumelt
+ builder.createInjectEnumAddr(pbLoc, optArgBuf, someEltDecl);
+ }
+
+ // Apply `Optional.TangentVector.init`.
+ SILOptFunctionBuilder fb(getContext().getTransform());
+ // %init_fn = function_ref @Optional.TangentVector.init
+ auto *initFn = fb.getOrCreateFunction(pbLoc, SILDeclRef(constructorDecl),
+ NotForDefinition);
+ auto *initFnRef = builder.createFunctionRef(pbLoc, initFn);
+ auto *diffProto =
+ builder.getASTContext().getProtocol(KnownProtocolKind::Differentiable);
+ auto *swiftModule = getModule().getSwiftModule();
+ auto diffConf =
+ swiftModule->lookupConformance(wrappedType.getASTType(), diffProto);
+ assert(!diffConf.isInvalid() && "Missing conformance to `Differentiable`");
+ auto subMap = SubstitutionMap::get(
+ initFn->getLoweredFunctionType()->getSubstGenericSignature(),
+ ArrayRef(wrappedType.getASTType()), {diffConf});
+ // %metatype = metatype $Optional.TangentVector.Type
+ auto metatypeType = CanMetatypeType::get(optionalTanTy.getASTType(),
+ MetatypeRepresentation::Thin);
+ auto metatypeSILType = SILType::getPrimitiveObjectType(metatypeType);
+ auto metatype = builder.createMetatype(pbLoc, metatypeSILType);
+ // apply %init_fn(%optTanAdjBuf, %optArgBuf, %metatype)
+ builder.createApply(pbLoc, initFnRef, subMap,
+ {optTanAdjBuf, optArgBuf, metatype});
+ builder.createDeallocStack(pbLoc, optArgBuf);
+
+ // Accumulate adjoint for the incoming `Optional` value.
+ addToAdjointBuffer(bb, optionalValue, optTanAdjBuf, pbLoc);
+ builder.emitDestroyAddr(pbLoc, optTanAdjBuf);
+ builder.createDeallocStack(pbLoc, optTanAdjBuf);
+}
+
SILBasicBlock *PullbackCloner::Implementation::buildPullbackSuccessor(
SILBasicBlock *origBB, SILBasicBlock *origPredBB,
SmallDenseMap &pullbackTrampolineBlockMap) {
@@ -2110,18 +2249,65 @@ void PullbackCloner::Implementation::visitSILBasicBlock(SILBasicBlock *bb) {
// Get predecessor terminator operands.
SmallVector, 4> incomingValues;
bbArg->getSingleTerminatorOperands(incomingValues);
- // Materialize adjoint value of active basic block argument, create a
- // copy, and set copy as adjoint value of incoming values.
- auto bbArgAdj = getAdjointValue(bb, bbArg);
- auto concreteBBArgAdj = materializeAdjointDirect(bbArgAdj, pbLoc);
- auto concreteBBArgAdjCopy =
- builder.emitCopyValueOperation(pbLoc, concreteBBArgAdj);
- for (auto pair : incomingValues) {
- auto *predBB = std::get<0>(pair);
- auto incomingValue = std::get<1>(pair);
- blockTemporaries[getPullbackBlock(predBB)].insert(concreteBBArgAdjCopy);
- setAdjointValue(predBB, incomingValue,
- makeConcreteAdjointValue(concreteBBArgAdjCopy));
+
+ // Returns true if the given terminator instruction is a `switch_enum` on
+ // an `Optional`-typed value. `switch_enum` instructions require
+ // special-case adjoint value propagation for the operand.
+ auto isSwitchEnumInstOnOptional =
+ [&ctx = getASTContext()](TermInst *termInst) {
+ if (!termInst)
+ return false;
+ if (auto *sei = dyn_cast(termInst)) {
+ auto *optionalEnumDecl = ctx.getOptionalDecl();
+ auto operandTy = sei->getOperand()->getType();
+ return operandTy.getASTType().getEnumOrBoundGenericEnum() ==
+ optionalEnumDecl;
+ }
+ return false;
+ };
+
+ // Check the tangent value category of the active basic block argument.
+ switch (getTangentValueCategory(bbArg)) {
+ // If argument has a loadable tangent value category: materialize adjoint
+ // value of the argument, create a copy, and set the copy as the adjoint
+ // value of incoming values.
+ case SILValueCategory::Object: {
+ auto bbArgAdj = getAdjointValue(bb, bbArg);
+ auto concreteBBArgAdj = materializeAdjointDirect(bbArgAdj, pbLoc);
+ auto concreteBBArgAdjCopy =
+ builder.emitCopyValueOperation(pbLoc, concreteBBArgAdj);
+ for (auto pair : incomingValues) {
+ auto *predBB = std::get<0>(pair);
+ auto incomingValue = std::get<1>(pair);
+ // Handle `switch_enum` on `Optional`.
+ auto termInst = bbArg->getSingleTerminator();
+ if (isSwitchEnumInstOnOptional(termInst)) {
+ accumulateAdjointForOptional(bb, incomingValue, concreteBBArgAdjCopy);
+ } else {
+ blockTemporaries[getPullbackBlock(predBB)].insert(concreteBBArgAdjCopy);
+ setAdjointValue(predBB, incomingValue,
+ makeConcreteAdjointValue(concreteBBArgAdjCopy));
+ }
+ }
+ break;
+ }
+ // If argument has an address tangent value category: materialize adjoint
+ // value of the argument, create a copy, and set the copy as the adjoint
+ // value of incoming values.
+ case SILValueCategory::Address: {
+ auto bbArgAdjBuf = getAdjointBuffer(bb, bbArg);
+ for (auto pair : incomingValues) {
+ auto *predBB = std::get<0>(pair);
+ auto incomingValue = std::get<1>(pair);
+ // Handle `switch_enum` on `Optional`.
+ auto termInst = bbArg->getSingleTerminator();
+ if (isSwitchEnumInstOnOptional(termInst))
+ accumulateAdjointForOptional(bb, incomingValue, bbArgAdjBuf);
+ else
+ addToAdjointBuffer(predBB, incomingValue, bbArgAdjBuf, pbLoc);
+ }
+ break;
+ }
}
}
@@ -2657,7 +2843,7 @@ void PullbackCloner::Implementation::accumulateIndirect(SILValue resultAddress,
CanMetatypeType::get(adjointASTTy, MetatypeRepresentation::Thick);
auto metatypeSILType = SILType::getPrimitiveObjectType(metatypeType);
auto metatype = builder.createMetatype(loc, metatypeSILType);
- // %2 = apply $0(%result, %new, %old, %1)
+ // %2 = apply %0(%result, %new, %old, %1)
builder.createApply(loc, witnessMethod, subMap,
{resultAddress, rhsAddress, lhsAddress, metatype},
/*isNonThrowing*/ false);
diff --git a/lib/SILOptimizer/LoopTransforms/ArrayPropertyOpt.cpp b/lib/SILOptimizer/LoopTransforms/ArrayPropertyOpt.cpp
index b734d134cf29e..76a30bfaca3d2 100644
--- a/lib/SILOptimizer/LoopTransforms/ArrayPropertyOpt.cpp
+++ b/lib/SILOptimizer/LoopTransforms/ArrayPropertyOpt.cpp
@@ -519,13 +519,13 @@ class RegionCloner : public SILCloner {
return;
// Update SSA form.
- SSAUp.Initialize(V->getType());
- SSAUp.AddAvailableValue(OrigBB, V);
+ SSAUp.initialize(V->getType());
+ SSAUp.addAvailableValue(OrigBB, V);
SILValue NewVal = getMappedValue(V);
- SSAUp.AddAvailableValue(getOpBasicBlock(OrigBB), NewVal);
+ SSAUp.addAvailableValue(getOpBasicBlock(OrigBB), NewVal);
for (auto U : UseList) {
Operand *Use = U;
- SSAUp.RewriteUse(*Use);
+ SSAUp.rewriteUse(*Use);
}
}
diff --git a/lib/SILOptimizer/LoopTransforms/LICM.cpp b/lib/SILOptimizer/LoopTransforms/LICM.cpp
index 79e5bd6d96b8e..e4be5ac35f5fa 100644
--- a/lib/SILOptimizer/LoopTransforms/LICM.cpp
+++ b/lib/SILOptimizer/LoopTransforms/LICM.cpp
@@ -1062,8 +1062,8 @@ void LoopTreeOptimization::hoistLoadsAndStores(SILValue addr, SILLoop *loop, Ins
LLVM_DEBUG(llvm::dbgs() << "Creating preload " << *initialLoad);
SILSSAUpdater ssaUpdater;
- ssaUpdater.Initialize(initialLoad->getType());
- ssaUpdater.AddAvailableValue(preheader, initialLoad);
+ ssaUpdater.initialize(initialLoad->getType());
+ ssaUpdater.addAvailableValue(preheader, initialLoad);
// Set all stored values as available values in the ssaUpdater.
// If there are multiple stores in a block, only the last one counts.
@@ -1078,7 +1078,7 @@ void LoopTreeOptimization::hoistLoadsAndStores(SILValue addr, SILLoop *loop, Ins
if (isLoadFromAddr(dyn_cast(SI->getSrc()), addr))
return;
- ssaUpdater.AddAvailableValue(SI->getParent(), SI->getSrc());
+ ssaUpdater.addAvailableValue(SI->getParent(), SI->getSrc());
}
}
@@ -1099,7 +1099,7 @@ void LoopTreeOptimization::hoistLoadsAndStores(SILValue addr, SILLoop *loop, Ins
// If we didn't see a store in this block yet, get the current value from
// the ssaUpdater.
if (!currentVal)
- currentVal = ssaUpdater.GetValueInMiddleOfBlock(block);
+ currentVal = ssaUpdater.getValueInMiddleOfBlock(block);
SILValue projectedValue = projectLoadValue(LI->getOperand(), addr,
currentVal, LI);
LLVM_DEBUG(llvm::dbgs() << "Replacing stored load " << *LI << " with "
@@ -1117,8 +1117,8 @@ void LoopTreeOptimization::hoistLoadsAndStores(SILValue addr, SILLoop *loop, Ins
"should have split critical edges");
SILBuilder B(succ->begin());
auto *SI = B.createStore(loc.getValue(),
- ssaUpdater.GetValueInMiddleOfBlock(succ),
- addr, StoreOwnershipQualifier::Unqualified);
+ ssaUpdater.getValueInMiddleOfBlock(succ), addr,
+ StoreOwnershipQualifier::Unqualified);
(void)SI;
LLVM_DEBUG(llvm::dbgs() << "Creating loop-exit store " << *SI);
}
diff --git a/lib/SILOptimizer/LoopTransforms/LoopRotate.cpp b/lib/SILOptimizer/LoopTransforms/LoopRotate.cpp
index ea9521f061b2f..fff3b201dc415 100644
--- a/lib/SILOptimizer/LoopTransforms/LoopRotate.cpp
+++ b/lib/SILOptimizer/LoopTransforms/LoopRotate.cpp
@@ -131,9 +131,9 @@ static void updateSSAForUseOfValue(
assert(Res->getType() == MappedValue->getType() && "The types must match");
insertedPhis.clear();
- updater.Initialize(Res->getType());
- updater.AddAvailableValue(Header, Res);
- updater.AddAvailableValue(EntryCheckBlock, MappedValue);
+ 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
@@ -155,7 +155,7 @@ static void updateSSAForUseOfValue(
assert(user->getParent() != EntryCheckBlock
&& "The entry check block should dominate the header");
- updater.RewriteUse(*use);
+ updater.rewriteUse(*use);
}
// Canonicalize inserted phis to avoid extra BB Args.
for (SILPhiArgument *arg : insertedPhis) {
diff --git a/lib/SILOptimizer/LoopTransforms/LoopUnroll.cpp b/lib/SILOptimizer/LoopTransforms/LoopUnroll.cpp
index 752e74ecc7001..967bfdbf4d468 100644
--- a/lib/SILOptimizer/LoopTransforms/LoopUnroll.cpp
+++ b/lib/SILOptimizer/LoopTransforms/LoopUnroll.cpp
@@ -334,13 +334,13 @@ updateSSA(SILModule &M, SILLoop *Loop,
if (!Loop->contains(Use->getUser()->getParent()))
UseList.push_back(UseWrapper(Use));
// Update SSA of use with the available values.
- SSAUp.Initialize(OrigValue->getType());
- SSAUp.AddAvailableValue(OrigValue->getParentBlock(), OrigValue);
+ SSAUp.initialize(OrigValue->getType());
+ SSAUp.addAvailableValue(OrigValue->getParentBlock(), OrigValue);
for (auto NewValue : MapEntry.second)
- SSAUp.AddAvailableValue(NewValue->getParentBlock(), NewValue);
+ SSAUp.addAvailableValue(NewValue->getParentBlock(), NewValue);
for (auto U : UseList) {
Operand *Use = U;
- SSAUp.RewriteUse(*Use);
+ SSAUp.rewriteUse(*Use);
}
}
}
diff --git a/lib/SILOptimizer/Mandatory/ClosureLifetimeFixup.cpp b/lib/SILOptimizer/Mandatory/ClosureLifetimeFixup.cpp
index 093cb4482e6b1..ff14e4a0f05ea 100644
--- a/lib/SILOptimizer/Mandatory/ClosureLifetimeFixup.cpp
+++ b/lib/SILOptimizer/Mandatory/ClosureLifetimeFixup.cpp
@@ -244,7 +244,7 @@ static void extendLifetimeToEndOfFunction(SILFunction &fn,
// lifetime respecting loops.
SmallVector insertedPhis;
SILSSAUpdater updater(&insertedPhis);
- updater.Initialize(optionalEscapingClosureTy);
+ updater.initialize(optionalEscapingClosureTy);
// Create an Optional<() -> ()>.none in the entry block of the function and
// add it as an available value to the SSAUpdater.
@@ -256,7 +256,7 @@ static void extendLifetimeToEndOfFunction(SILFunction &fn,
SILBuilderWithScope b(fn.getEntryBlock()->begin());
return b.createOptionalNone(loc, optionalEscapingClosureTy);
}();
- updater.AddAvailableValue(fn.getEntryBlock(), entryBlockOptionalNone);
+ updater.addAvailableValue(fn.getEntryBlock(), entryBlockOptionalNone);
// Create a copy of the convert_escape_to_no_escape and add it as an available
// value to the SSA updater.
@@ -270,7 +270,7 @@ static void extendLifetimeToEndOfFunction(SILFunction &fn,
cvt->setLifetimeGuaranteed();
cvt->setOperand(innerCVI);
SILBuilderWithScope b(std::next(cvt->getIterator()));
- updater.AddAvailableValue(
+ updater.addAvailableValue(
cvt->getParent(),
b.createOptionalSome(loc, innerCVI, optionalEscapingClosureTy));
return innerCVI;
@@ -284,13 +284,13 @@ static void extendLifetimeToEndOfFunction(SILFunction &fn,
{
// Before the copy value, insert an extra destroy_value to handle
// loops. Since we used our enum value this is safe.
- SILValue v = updater.GetValueInMiddleOfBlock(cvi->getParent());
+ SILValue v = updater.getValueInMiddleOfBlock(cvi->getParent());
SILBuilderWithScope(cvi).createDestroyValue(loc, v);
}
for (auto *block : exitingBlocks) {
auto *safeDestructionPt = getDeinitSafeClosureDestructionPoint(block);
- SILValue v = updater.GetValueAtEndOfBlock(block);
+ SILValue v = updater.getValueAtEndOfBlock(block);
SILBuilderWithScope(safeDestructionPt).createDestroyValue(loc, v);
}
@@ -849,7 +849,7 @@ static bool fixupCopyBlockWithoutEscaping(CopyBlockWithoutEscapingInst *cb,
SmallVector insertedPhis;
SILSSAUpdater updater(&insertedPhis);
- updater.Initialize(optionalEscapingClosureTy);
+ updater.initialize(optionalEscapingClosureTy);
// Create the Optional.none as the beginning available value.
SILValue entryBlockOptionalNone;
@@ -857,7 +857,7 @@ static bool fixupCopyBlockWithoutEscaping(CopyBlockWithoutEscapingInst *cb,
SILBuilderWithScope b(fn.getEntryBlock()->begin());
entryBlockOptionalNone =
b.createOptionalNone(autoGenLoc, optionalEscapingClosureTy);
- updater.AddAvailableValue(fn.getEntryBlock(), entryBlockOptionalNone);
+ updater.addAvailableValue(fn.getEntryBlock(), entryBlockOptionalNone);
}
assert(entryBlockOptionalNone);
@@ -872,7 +872,7 @@ static bool fixupCopyBlockWithoutEscaping(CopyBlockWithoutEscapingInst *cb,
// operand consumed at +1, so we don't need a copy) to it.
auto *result = b.createOptionalSome(autoGenLoc, sentinelClosure,
optionalEscapingClosureTy);
- updater.AddAvailableValue(result->getParent(), result);
+ updater.addAvailableValue(result->getParent(), result);
return result;
}();
@@ -881,14 +881,14 @@ static bool fixupCopyBlockWithoutEscaping(CopyBlockWithoutEscapingInst *cb,
if (singleDestroy) {
SILBuilderWithScope b(std::next(singleDestroy->getIterator()));
auto *result = b.createOptionalNone(autoGenLoc, optionalEscapingClosureTy);
- updater.AddAvailableValue(result->getParent(), result);
+ updater.addAvailableValue(result->getParent(), result);
}
// Now that we have all of our available values, insert a destroy_value before
// the initial Optional.some value using the SSA updater to ensure that we
// handle loops correctly.
{
- SILValue v = updater.GetValueInMiddleOfBlock(initialValue->getParent());
+ SILValue v = updater.getValueInMiddleOfBlock(initialValue->getParent());
SILBuilderWithScope(initialValue).createDestroyValue(autoGenLoc, v);
}
@@ -896,7 +896,7 @@ static bool fixupCopyBlockWithoutEscaping(CopyBlockWithoutEscapingInst *cb,
// lifetime end points. This ensures we do not expand our lifetime too much.
if (singleDestroy) {
SILBuilderWithScope b(std::next(singleDestroy->getIterator()));
- SILValue v = updater.GetValueInMiddleOfBlock(singleDestroy->getParent());
+ SILValue v = updater.getValueInMiddleOfBlock(singleDestroy->getParent());
SILValue isEscaping =
b.createIsEscapingClosure(loc, v, IsEscapingClosureInst::ObjCEscaping);
b.createCondFail(loc, isEscaping, "non-escaping closure has escaped");
@@ -911,7 +911,7 @@ static bool fixupCopyBlockWithoutEscaping(CopyBlockWithoutEscapingInst *cb,
for (auto *block : exitingBlocks) {
auto *safeDestructionPt = getDeinitSafeClosureDestructionPoint(block);
- SILValue v = updater.GetValueAtEndOfBlock(block);
+ SILValue v = updater.getValueAtEndOfBlock(block);
SILBuilderWithScope(safeDestructionPt).createDestroyValue(autoGenLoc, v);
}
}
diff --git a/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp b/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp
index 5d4d4f889cb6c..1b7a6c384fc80 100644
--- a/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp
+++ b/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp
@@ -686,7 +686,7 @@ AvailableValueAggregator::aggregateFullyAvailableValue(SILType loadTy,
// have multiple insertion points if we are storing exactly the same value
// implying that we can just copy firstVal at each insertion point.
SILSSAUpdater updater(&insertedPhiNodes);
- updater.Initialize(loadTy);
+ updater.initialize(loadTy);
Optional singularValue;
for (auto *insertPt : insertPts) {
@@ -707,7 +707,7 @@ AvailableValueAggregator::aggregateFullyAvailableValue(SILType loadTy,
}
// And then put the value into the SSA updater.
- updater.AddAvailableValue(insertPt->getParent(), eltVal);
+ updater.addAvailableValue(insertPt->getParent(), eltVal);
}
// If we only are tracking a singular value, we do not need to construct
@@ -727,7 +727,7 @@ AvailableValueAggregator::aggregateFullyAvailableValue(SILType loadTy,
}
// Finally, grab the value from the SSA updater.
- SILValue result = updater.GetValueInMiddleOfBlock(B.getInsertionBB());
+ SILValue result = updater.getValueInMiddleOfBlock(B.getInsertionBB());
assert(result.getOwnershipKind().isCompatibleWith(ValueOwnershipKind::Owned));
if (isTake() || !B.hasOwnership()) {
return result;
@@ -863,7 +863,7 @@ SILValue AvailableValueAggregator::handlePrimitiveValue(SILType loadTy,
// never have the same value along all paths unless we have a trivial value
// meaning the SSA updater given a non-trivial value must /always/ be used.
SILSSAUpdater updater(&insertedPhiNodes);
- updater.Initialize(loadTy);
+ updater.initialize(loadTy);
Optional singularValue;
for (auto *i : insertPts) {
@@ -881,7 +881,7 @@ SILValue AvailableValueAggregator::handlePrimitiveValue(SILType loadTy,
singularValue = SILValue();
}
- updater.AddAvailableValue(i->getParent(), eltVal);
+ updater.addAvailableValue(i->getParent(), eltVal);
}
SILBasicBlock *insertBlock = B.getInsertionBB();
@@ -902,7 +902,7 @@ SILValue AvailableValueAggregator::handlePrimitiveValue(SILType loadTy,
}
// Finally, grab the value from the SSA updater.
- SILValue eltVal = updater.GetValueInMiddleOfBlock(insertBlock);
+ SILValue eltVal = updater.getValueInMiddleOfBlock(insertBlock);
assert(!B.hasOwnership() ||
eltVal.getOwnershipKind().isCompatibleWith(ValueOwnershipKind::Owned));
assert(eltVal->getType() == loadTy && "Subelement types mismatch");
diff --git a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp
index 9cde36a2239f4..6483b47a12a6f 100644
--- a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp
+++ b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp
@@ -12,6 +12,7 @@
#define DEBUG_TYPE "allocbox-to-stack"
#include "swift/AST/DiagnosticsSIL.h"
+#include "swift/Basic/BlotMapVector.h"
#include "swift/SIL/ApplySite.h"
#include "swift/SIL/Dominance.h"
#include "swift/SIL/SILArgument.h"
@@ -43,6 +44,10 @@ static llvm::cl::opt MaxLocalApplyRecurDepth(
"max-local-apply-recur-depth", llvm::cl::init(4),
llvm::cl::desc("Max recursive depth for analyzing local functions"));
+static llvm::cl::opt AllocBoxToStackAnalyzeApply(
+ "allocbox-to-stack-analyze-apply", llvm::cl::init(true),
+ llvm::cl::desc("Analyze functions into while alloc_box is passed"));
+
//===-----------------------------------------------------------------------===//
// SIL Utilities for alloc_box Promotion
//===----------------------------------------------------------------------===//
@@ -319,6 +324,10 @@ static bool checkLocalApplyBody(Operand *O,
// AllocBoxToStack opt. We don't want to increase code size, so this is
// restricted only for private local functions currently.
static bool isOptimizableApplySite(ApplySite Apply) {
+ if (!AllocBoxToStackAnalyzeApply) {
+ // turned off explicitly
+ return false;
+ }
auto callee = Apply.getReferencedFunctionOrNull();
if (!callee) {
return false;
@@ -978,8 +987,7 @@ specializeApplySite(SILOptFunctionBuilder &FuncBuilder, ApplySite Apply,
}
static void rewriteApplySites(AllocBoxToStackState &pass) {
- llvm::DenseMap IndexMap;
- llvm::SmallVector AppliesToSpecialize;
+ swift::SmallBlotMapVector AppliesToSpecialize;
ArgIndexList Indices;
// Build a map from the ApplySite to the indices of the operands
@@ -993,17 +1001,26 @@ static void rewriteApplySites(AllocBoxToStackState &pass) {
Indices.clear();
Indices.push_back(CalleeArgIndexNumber);
- auto iterAndSuccess = IndexMap.try_emplace(Apply, Indices);
// AllocBoxStack opt promotes boxes passed to a chain of applies when it is
// safe to do so. All such applies have to be specialized to take pointer
// arguments instead of box arguments. This has to be done in dfs order.
- // Since PromotedOperands is already populated in dfs order by
- // `recursivelyFindBoxOperandsPromotableToAddress`. Build
- // `AppliesToSpecialize` in the same order.
- if (iterAndSuccess.second) {
- AppliesToSpecialize.push_back(Apply);
- } else {
- iterAndSuccess.first->second.push_back(CalleeArgIndexNumber);
+
+ // PromotedOperands is already populated in dfs order by
+ // `recursivelyFindBoxOperandsPromotableToAddress` w.r.t a single alloc_box.
+ // AppliesToSpecialize is then populated in the order of PromotedOperands.
+ // If multiple alloc_boxes are passed to the same apply instruction, then
+ // the apply instruction can appear multiple times in AppliesToSpecialize.
+ // Only its last appearance is maintained and previous appearances are
+ // blotted.
+ auto iterAndSuccess =
+ AppliesToSpecialize.insert(std::make_pair(Apply, Indices));
+ if (!iterAndSuccess.second) {
+ // Blot the previously inserted apply and insert at the end with updated
+ // indices
+ auto OldIndices = iterAndSuccess.first->getValue().second;
+ OldIndices.push_back(CalleeArgIndexNumber);
+ AppliesToSpecialize.erase(iterAndSuccess.first);
+ AppliesToSpecialize.insert(std::make_pair(Apply, OldIndices));
}
}
@@ -1011,11 +1028,12 @@ static void rewriteApplySites(AllocBoxToStackState &pass) {
// operands that we will not need, and remove the existing
// ApplySite.
SILOptFunctionBuilder FuncBuilder(*pass.T);
- for (auto &Apply : AppliesToSpecialize) {
- auto It = IndexMap.find(Apply);
- assert(It != IndexMap.end());
- auto &Indices = It->second;
-
+ for (auto &It : AppliesToSpecialize) {
+ if (!It.hasValue()) {
+ continue;
+ }
+ auto Apply = It.getValue().first;
+ auto Indices = It.getValue().second;
// Sort the indices and unique them.
sortUnique(Indices);
diff --git a/lib/SILOptimizer/Transforms/DeadObjectElimination.cpp b/lib/SILOptimizer/Transforms/DeadObjectElimination.cpp
index fff5fafdde1f7..a040d1166d176 100644
--- a/lib/SILOptimizer/Transforms/DeadObjectElimination.cpp
+++ b/lib/SILOptimizer/Transforms/DeadObjectElimination.cpp
@@ -535,10 +535,10 @@ static void insertReleases(ArrayRef Stores,
assert(!Stores.empty());
SILValue StVal = Stores.front()->getSrc();
- SSAUp.Initialize(StVal->getType());
+ SSAUp.initialize(StVal->getType());
for (auto *Store : Stores)
- SSAUp.AddAvailableValue(Store->getParent(), Store->getSrc());
+ SSAUp.addAvailableValue(Store->getParent(), Store->getSrc());
SILLocation Loc = Stores[0]->getLoc();
for (auto *RelPoint : ReleasePoints) {
@@ -547,7 +547,7 @@ static void insertReleases(ArrayRef Stores,
// the right thing for local uses. We have already ensured a single store
// per block, and all release points occur after all stores. Therefore we
// can simply ask SSAUpdater for the reaching store.
- SILValue RelVal = SSAUp.GetValueAtEndOfBlock(RelPoint->getParent());
+ SILValue RelVal = SSAUp.getValueAtEndOfBlock(RelPoint->getParent());
if (StVal->getType().isReferenceCounted(RelPoint->getModule()))
B.createStrongRelease(Loc, RelVal, B.getDefaultAtomicity());
else
diff --git a/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp b/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp
index 06968a86b32a5..373d62d92c976 100644
--- a/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp
+++ b/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp
@@ -1337,14 +1337,14 @@ SILValue RLEContext::computePredecessorLocationValue(SILBasicBlock *BB,
// Finally, collect all the values for the SILArgument, materialize it using
// the SSAUpdater.
- Updater.Initialize(
+ Updater.initialize(
L.getType(&BB->getModule(), TypeExpansionContext(*BB->getParent()))
.getObjectType());
for (auto V : Values) {
- Updater.AddAvailableValue(V.first, V.second);
+ Updater.addAvailableValue(V.first, V.second);
}
- return Updater.GetValueInMiddleOfBlock(BB);
+ return Updater.getValueInMiddleOfBlock(BB);
}
bool RLEContext::collectLocationValues(SILBasicBlock *BB, LSLocation &L,
diff --git a/lib/SILOptimizer/Utils/BasicBlockOptUtils.cpp b/lib/SILOptimizer/Utils/BasicBlockOptUtils.cpp
index a70372768b507..6b5a52240da00 100644
--- a/lib/SILOptimizer/Utils/BasicBlockOptUtils.cpp
+++ b/lib/SILOptimizer/Utils/BasicBlockOptUtils.cpp
@@ -107,9 +107,9 @@ void BasicBlockCloner::updateSSAAfterCloning() {
for (auto *use : inst->getUses())
useList.push_back(UseWrapper(use));
- ssaUpdater.Initialize(inst->getType());
- ssaUpdater.AddAvailableValue(origBB, inst);
- ssaUpdater.AddAvailableValue(getNewBB(), newResult);
+ ssaUpdater.initialize(inst->getType());
+ ssaUpdater.addAvailableValue(origBB, inst);
+ ssaUpdater.addAvailableValue(getNewBB(), newResult);
if (useList.empty())
continue;
@@ -124,7 +124,7 @@ void BasicBlockCloner::updateSSAAfterCloning() {
if (user->getParent() == origBB)
continue;
- ssaUpdater.RewriteUse(*use);
+ ssaUpdater.rewriteUse(*use);
}
}
}
diff --git a/lib/SILOptimizer/Utils/SILSSAUpdater.cpp b/lib/SILOptimizer/Utils/SILSSAUpdater.cpp
index ba37d210559d3..92dec29e38461 100644
--- a/lib/SILOptimizer/Utils/SILSSAUpdater.cpp
+++ b/lib/SILOptimizer/Utils/SILSSAUpdater.cpp
@@ -25,71 +25,75 @@
using namespace swift;
-void *SILSSAUpdater::allocate(unsigned Size, unsigned Align) const {
- return AlignedAlloc(Size, Align);
+void *SILSSAUpdater::allocate(unsigned size, unsigned align) const {
+ return AlignedAlloc(size, align);
}
-void SILSSAUpdater::deallocateSentinel(SILUndef *D) {
- AlignedFree(D);
+void SILSSAUpdater::deallocateSentinel(SILUndef *undef) {
+ AlignedFree(undef);
}
-SILSSAUpdater::SILSSAUpdater(SmallVectorImpl *PHIs)
- : AV(nullptr), PHISentinel(nullptr, deallocateSentinel),
- InsertedPHIs(PHIs) {}
+SILSSAUpdater::SILSSAUpdater(SmallVectorImpl *phis)
+ : blockToAvailableValueMap(nullptr),
+ phiSentinel(nullptr, deallocateSentinel), insertedPhis(phis) {}
SILSSAUpdater::~SILSSAUpdater() = default;
-void SILSSAUpdater::Initialize(SILType Ty) {
- ValType = Ty;
+void SILSSAUpdater::initialize(SILType inputType) {
+ type = inputType;
- PHISentinel = std::unique_ptr(
- SILUndef::getSentinelValue(Ty, this), SILSSAUpdater::deallocateSentinel);
+ phiSentinel = std::unique_ptr(
+ SILUndef::getSentinelValue(inputType, this),
+ SILSSAUpdater::deallocateSentinel);
- if (!AV)
- AV.reset(new AvailableValsTy());
+ if (!blockToAvailableValueMap)
+ blockToAvailableValueMap.reset(new AvailableValsTy());
else
- AV->clear();
+ blockToAvailableValueMap->clear();
}
-bool SILSSAUpdater::HasValueForBlock(SILBasicBlock *BB) const {
- return AV->count(BB);
+bool SILSSAUpdater::hasValueForBlock(SILBasicBlock *block) const {
+ return blockToAvailableValueMap->count(block);
}
/// Indicate that a rewritten value is available in the specified block with the
/// specified value.
-void SILSSAUpdater::AddAvailableValue(SILBasicBlock *BB, SILValue V) {
- (*AV)[BB] = V;
+void SILSSAUpdater::addAvailableValue(SILBasicBlock *block, SILValue value) {
+ (*blockToAvailableValueMap)[block] = value;
}
/// Construct SSA form, materializing a value that is live at the end of the
/// specified block.
-SILValue SILSSAUpdater::GetValueAtEndOfBlock(SILBasicBlock *BB) {
- return GetValueAtEndOfBlockInternal(BB);
+SILValue SILSSAUpdater::getValueAtEndOfBlock(SILBasicBlock *block) {
+ return getValueAtEndOfBlockInternal(block);
}
/// Are all available values identicalTo each other.
-static bool areIdentical(llvm::DenseMap &Avails) {
- if (auto *First = dyn_cast(Avails.begin()->second)) {
- for (auto Avail : Avails) {
- auto *Inst = dyn_cast(Avail.second);
- if (!Inst)
+static bool
+areIdentical(llvm::DenseMap &availableValues) {
+ if (auto *firstInst =
+ dyn_cast(availableValues.begin()->second)) {
+ for (auto value : availableValues) {
+ auto *svi = dyn_cast(value.second);
+ if (!svi)
return false;
- if (!Inst->isIdenticalTo(First))
+ if (!svi->isIdenticalTo(firstInst))
return false;
}
return true;
}
- auto *MVIR = dyn_cast(Avails.begin()->second);
- if (!MVIR)
+ auto *mvir =
+ dyn_cast(availableValues.begin()->second);
+ if (!mvir)
return false;
- for (auto Avail : Avails) {
- auto *Result = dyn_cast(Avail.second);
- if (!Result)
+ for (auto value : availableValues) {
+ auto *result = dyn_cast(value.second);
+ if (!result)
return false;
- if (!Result->getParent()->isIdenticalTo(MVIR->getParent()) ||
- Result->getIndex() != MVIR->getIndex()) {
+ if (!result->getParent()->isIdenticalTo(mvir->getParent()) ||
+ result->getIndex() != mvir->getIndex()) {
return false;
}
}
@@ -98,65 +102,61 @@ static bool areIdentical(llvm::DenseMap &Avails) {
/// This should be called in top-down order of each def that needs its uses
/// rewrited. The order that we visit uses for a given def is irrelevant.
-void SILSSAUpdater::RewriteUse(Operand &Op) {
+void SILSSAUpdater::rewriteUse(Operand &use) {
// Replicate function_refs to their uses. SILGen can't build phi nodes for
// them and it would not make much sense anyways.
- if (auto *FR = dyn_cast(Op.get())) {
- assert(areIdentical(*AV) &&
+ if (auto *fri = dyn_cast(use.get())) {
+ assert(areIdentical(*blockToAvailableValueMap) &&
"The function_refs need to have the same value");
- SILInstruction *User = Op.getUser();
- auto *NewFR = cast(FR->clone(User));
- Op.set(NewFR);
+ SILInstruction *user = use.getUser();
+ use.set(cast(fri->clone(user)));
return;
- } else if (auto *FR = dyn_cast(Op.get())) {
- assert(areIdentical(*AV) &&
+ } else if (auto *pdfri =
+ dyn_cast(use.get())) {
+ assert(areIdentical(*blockToAvailableValueMap) &&
"The function_refs need to have the same value");
- SILInstruction *User = Op.getUser();
- auto *NewFR = cast(FR->clone(User));
- Op.set(NewFR);
+ SILInstruction *user = use.getUser();
+ use.set(cast(pdfri->clone(user)));
return;
- } else if (auto *FR = dyn_cast(Op.get())) {
- assert(areIdentical(*AV) &&
+ } else if (auto *dfri = dyn_cast(use.get())) {
+ assert(areIdentical(*blockToAvailableValueMap) &&
"The function_refs need to have the same value");
- SILInstruction *User = Op.getUser();
- auto *NewFR = cast(FR->clone(User));
- Op.set(NewFR);
+ SILInstruction *user = use.getUser();
+ use.set(cast(dfri->clone(user)));
return;
- } else if (auto *IL = dyn_cast(Op.get()))
- if (areIdentical(*AV)) {
+ } else if (auto *ili = dyn_cast(use.get()))
+ if (areIdentical(*blockToAvailableValueMap)) {
// Some llvm intrinsics don't like phi nodes as their constant inputs (e.g
// ctlz).
- SILInstruction *User = Op.getUser();
- auto *NewIL = cast(IL->clone(User));
- Op.set(NewIL);
+ SILInstruction *user = use.getUser();
+ use.set(cast(ili->clone(user)));
return;
}
// Again we need to be careful here, because ssa construction (with the
// existing representation) can change the operand from under us.
- UseWrapper UW(&Op);
+ UseWrapper useWrapper(&use);
- SILInstruction *User = Op.getUser();
- SILValue NewVal = GetValueInMiddleOfBlock(User->getParent());
- assert(NewVal && "Need a valid value");
- ((Operand *)UW)->set((SILValue)NewVal);
+ SILInstruction *user = use.getUser();
+ SILValue newVal = getValueInMiddleOfBlock(user->getParent());
+ assert(newVal && "Need a valid value");
+ static_cast(useWrapper)->set(newVal);
}
-
/// Get the edge values from the terminator to the destination basic block.
-static OperandValueArrayRef getEdgeValuesForTerminator(TermInst *TI,
- SILBasicBlock *ToBB) {
- if (auto *BrInst = dyn_cast(TI)) {
- assert(BrInst->getDestBB() == ToBB &&
+static OperandValueArrayRef getEdgeValuesForTerminator(TermInst *ti,
+ SILBasicBlock *toBlock) {
+ if (auto *br = dyn_cast(ti)) {
+ assert(br->getDestBB() == toBlock &&
"Incoming edge block and phi block mismatch");
- return BrInst->getArgs();
+ return br->getArgs();
}
- if (auto *CondBrInst = dyn_cast(TI)) {
- bool IsTrueEdge = CondBrInst->getTrueBB() == ToBB;
- assert(((IsTrueEdge && CondBrInst->getTrueBB() == ToBB) ||
- CondBrInst->getFalseBB() == ToBB) &&
+ if (auto *cbi = dyn_cast(ti)) {
+ bool isTrueEdge = cbi->getTrueBB() == toBlock;
+ assert(((isTrueEdge && cbi->getTrueBB() == toBlock) ||
+ cbi->getFalseBB() == toBlock) &&
"Incoming edge block and phi block mismatch");
- return IsTrueEdge ? CondBrInst->getTrueArgs() : CondBrInst->getFalseArgs();
+ return isTrueEdge ? cbi->getTrueArgs() : cbi->getFalseArgs();
}
// We need a predecessor who is capable of holding outgoing branch
@@ -167,211 +167,219 @@ static OperandValueArrayRef getEdgeValuesForTerminator(TermInst *TI,
/// Check that the argument has the same incoming edge values as the value
/// map.
static bool
-isEquivalentPHI(SILPhiArgument *PHI,
- llvm::SmallDenseMap &ValueMap) {
- SILBasicBlock *PhiBB = PHI->getParent();
- size_t Idx = PHI->getIndex();
- for (auto *PredBB : PhiBB->getPredecessorBlocks()) {
- auto DesiredVal = ValueMap[PredBB];
- OperandValueArrayRef EdgeValues =
- getEdgeValuesForTerminator(PredBB->getTerminator(), PhiBB);
- if (EdgeValues[Idx] != DesiredVal)
+isEquivalentPHI(SILPhiArgument *phi,
+ llvm::SmallDenseMap &valueMap) {
+ SILBasicBlock *phiBlock = phi->getParent();
+ size_t phiArgEdgeIndex = phi->getIndex();
+ for (auto *predBlock : phiBlock->getPredecessorBlocks()) {
+ auto desiredVal = valueMap[predBlock];
+ OperandValueArrayRef edgeValues =
+ getEdgeValuesForTerminator(predBlock->getTerminator(), phiBlock);
+ if (edgeValues[phiArgEdgeIndex] != desiredVal)
return false;
}
return true;
}
-SILValue SILSSAUpdater::GetValueInMiddleOfBlock(SILBasicBlock *BB) {
+SILValue SILSSAUpdater::getValueInMiddleOfBlock(SILBasicBlock *block) {
// If this basic block does not define a value we can just use the value
// live at the end of the block.
- if (!HasValueForBlock(BB))
- return GetValueAtEndOfBlock(BB);
+ if (!hasValueForBlock(block))
+ return getValueAtEndOfBlock(block);
/// Otherwise, we have to build SSA for the value defined in this block and
/// this block's predecessors.
- SILValue SingularValue;
- SmallVector, 4> PredVals;
- bool FirstPred = true;
+ SILValue singularValue;
+ SmallVector, 4> predVals;
+ bool firstPred = true;
// SSAUpdater can modify TerminatorInst and therefore invalidate the
// predecessor iterator. Find all the predecessors before the SSA update.
- SmallVector Preds;
- for (auto *PredBB : BB->getPredecessorBlocks()) {
- Preds.push_back(PredBB);
+ SmallVector preds;
+ for (auto *predBlock : block->getPredecessorBlocks()) {
+ preds.push_back(predBlock);
}
- for (auto *PredBB : Preds) {
- SILValue PredVal = GetValueAtEndOfBlock(PredBB);
- PredVals.push_back(std::make_pair(PredBB, PredVal));
- if (FirstPred) {
- SingularValue = PredVal;
- FirstPred = false;
- } else if (SingularValue != PredVal)
- SingularValue = SILValue();
+ for (auto *predBlock : preds) {
+ SILValue predVal = getValueAtEndOfBlock(predBlock);
+ predVals.push_back(std::make_pair(predBlock, predVal));
+ if (firstPred) {
+ singularValue = predVal;
+ firstPred = false;
+ } else if (singularValue != predVal)
+ singularValue = SILValue();
}
// Return undef for blocks without predecessor.
- if (PredVals.empty())
- return SILUndef::get(ValType, *BB->getParent());
+ if (predVals.empty())
+ return SILUndef::get(type, *block->getParent());
- if (SingularValue)
- return SingularValue;
+ if (singularValue)
+ return singularValue;
// Check if we already have an equivalent phi.
- if (!BB->getArguments().empty()) {
- llvm::SmallDenseMap ValueMap(PredVals.begin(),
- PredVals.end());
- for (auto *Arg : BB->getSILPhiArguments())
- if (isEquivalentPHI(Arg, ValueMap))
- return Arg;
-
+ if (!block->getArguments().empty()) {
+ llvm::SmallDenseMap valueMap(predVals.begin(),
+ predVals.end());
+ for (auto *arg : block->getSILPhiArguments())
+ if (isEquivalentPHI(arg, valueMap))
+ return arg;
}
// Create a new phi node.
- SILPhiArgument *PHI =
- BB->createPhiArgument(ValType, ValueOwnershipKind::Owned);
- for (auto &EV : PredVals)
- addNewEdgeValueToBranch(EV.first->getTerminator(), BB, EV.second);
+ SILPhiArgument *phiArg =
+ block->createPhiArgument(type, ValueOwnershipKind::Owned);
+ for (auto &pair : predVals)
+ addNewEdgeValueToBranch(pair.first->getTerminator(), block, pair.second);
- if (InsertedPHIs)
- InsertedPHIs->push_back(PHI);
+ if (insertedPhis)
+ insertedPhis->push_back(phiArg);
- return PHI;
+ return phiArg;
}
-/// SSAUpdaterTraits - Traits for the SSAUpdaterImpl
-/// template, specialized for MachineSSAUpdater.
namespace llvm {
-template<>
+
+/// Traits for the SSAUpdaterImpl specialized for SIL and the SILSSAUpdater.
+template <>
class SSAUpdaterTraits {
public:
- typedef SILBasicBlock BlkT;
- typedef SILValue ValT;
- typedef SILPhiArgument PhiT;
+ using BlkT = SILBasicBlock;
+ using ValT = SILValue;
+ using PhiT = SILPhiArgument;
- typedef SILBasicBlock::succ_iterator BlkSucc_iterator;
- static BlkSucc_iterator BlkSucc_begin(BlkT *BB) { return BB->succ_begin(); }
- static BlkSucc_iterator BlkSucc_end(BlkT *BB) { return BB->succ_end(); }
+ using BlkSucc_iterator = SILBasicBlock::succ_iterator;
+ static BlkSucc_iterator BlkSucc_begin(BlkT *block) {
+ return block->succ_begin();
+ }
+ static BlkSucc_iterator BlkSucc_end(BlkT *block) { return block->succ_end(); }
/// Iterator for PHI operands.
class PHI_iterator {
private:
- SILBasicBlock::pred_iterator PredIt;
- SILBasicBlock *BB;
- size_t Idx;
+ SILBasicBlock::pred_iterator predBlockIter;
+ SILBasicBlock *phiBlock;
+ size_t phiArgEdgeIndex;
public:
- explicit PHI_iterator(SILPhiArgument *P) // begin iterator
- : PredIt(P->getParent()->pred_begin()),
- BB(P->getParent()),
- Idx(P->getIndex()) {}
- PHI_iterator(SILPhiArgument *P, bool) // end iterator
- : PredIt(P->getParent()->pred_end()),
- BB(P->getParent()),
- Idx(P->getIndex()) {}
-
- PHI_iterator &operator++() { ++PredIt; return *this; }
- bool operator==(const PHI_iterator& x) const { return PredIt == x.PredIt; }
+ explicit PHI_iterator(SILPhiArgument *phiArg) // begin iterator
+ : predBlockIter(phiArg->getParent()->pred_begin()),
+ phiBlock(phiArg->getParent()), phiArgEdgeIndex(phiArg->getIndex()) {}
+ PHI_iterator(SILPhiArgument *phiArg, bool) // end iterator
+ : predBlockIter(phiArg->getParent()->pred_end()),
+ phiBlock(phiArg->getParent()), phiArgEdgeIndex(phiArg->getIndex()) {}
+
+ PHI_iterator &operator++() {
+ ++predBlockIter;
+ return *this;
+ }
+
+ bool operator==(const PHI_iterator &x) const {
+ return predBlockIter == x.predBlockIter;
+ }
+
bool operator!=(const PHI_iterator& x) const { return !operator==(x); }
- SILValue getValueForBlock(size_t Idx, SILBasicBlock *BB, TermInst *TI) {
- OperandValueArrayRef Args = getEdgeValuesForTerminator(TI, BB);
- assert(Idx < Args.size() && "Not enough values on incoming edge");
- return Args[Idx];
+ SILValue getValueForBlock(size_t inputArgIndex, SILBasicBlock *block,
+ TermInst *ti) {
+ OperandValueArrayRef args = getEdgeValuesForTerminator(ti, block);
+ assert(inputArgIndex < args.size() &&
+ "Not enough values on incoming edge");
+ return args[inputArgIndex];
}
SILValue getIncomingValue() {
- return getValueForBlock(Idx, BB, (*PredIt)->getTerminator());
+ return getValueForBlock(phiArgEdgeIndex, phiBlock,
+ (*predBlockIter)->getTerminator());
}
- SILBasicBlock *getIncomingBlock() {
- return *PredIt;
- }
+ SILBasicBlock *getIncomingBlock() { return *predBlockIter; }
};
- static inline PHI_iterator PHI_begin(PhiT *PHI) { return PHI_iterator(PHI); }
- static inline PHI_iterator PHI_end(PhiT *PHI) {
- return PHI_iterator(PHI, true);
+ static inline PHI_iterator PHI_begin(PhiT *phi) { return PHI_iterator(phi); }
+ static inline PHI_iterator PHI_end(PhiT *phi) {
+ return PHI_iterator(phi, true);
}
/// Put the predecessors of BB into the Preds vector.
- static void FindPredecessorBlocks(SILBasicBlock *BB,
- SmallVectorImpl *Preds){
- for (SILBasicBlock::pred_iterator PI = BB->pred_begin(), E = BB->pred_end();
- PI != E; ++PI)
- Preds->push_back(*PI);
+ static void
+ FindPredecessorBlocks(SILBasicBlock *block,
+ SmallVectorImpl *predBlocks) {
+ llvm::copy(block->getPredecessorBlocks(), std::back_inserter(*predBlocks));
}
- static SILValue GetUndefVal(SILBasicBlock *BB,
- SILSSAUpdater *Updater) {
- return SILUndef::get(Updater->ValType, *BB->getParent());
+ static SILValue GetUndefVal(SILBasicBlock *block, SILSSAUpdater *ssaUpdater) {
+ return SILUndef::get(ssaUpdater->type, *block->getParent());
}
/// Add an Argument to the basic block.
- static SILValue CreateEmptyPHI(SILBasicBlock *BB, unsigned NumPreds,
- SILSSAUpdater *Updater) {
+ static SILValue CreateEmptyPHI(SILBasicBlock *block, unsigned numPreds,
+ SILSSAUpdater *ssaUpdater) {
// Add the argument to the block.
- SILValue PHI(
- BB->createPhiArgument(Updater->ValType, ValueOwnershipKind::Owned));
+ SILValue phi(
+ block->createPhiArgument(ssaUpdater->type, ValueOwnershipKind::Owned));
// Mark all predecessor blocks with the sentinel undef value.
- SmallVector Preds(BB->pred_begin(), BB->pred_end());
- for (auto *PredBB: Preds) {
- TermInst *TI = PredBB->getTerminator();
- addNewEdgeValueToBranch(TI, BB, Updater->PHISentinel.get());
+ SmallVector predBlockList(
+ block->getPredecessorBlocks());
+
+ for (auto *predBlock : predBlockList) {
+ TermInst *ti = predBlock->getTerminator();
+ addNewEdgeValueToBranch(ti, block, ssaUpdater->phiSentinel.get());
}
- return PHI;
+
+ return phi;
}
- /// Add the specified value as an operand of the PHI for the specified
- /// predecessor block.
- static void AddPHIOperand(SILPhiArgument *PHI, SILValue Val,
- SILBasicBlock *Pred) {
- auto *PHIBB = PHI->getParent();
- size_t PhiIdx = PHI->getIndex();
- auto *TI = Pred->getTerminator();
- changeEdgeValue(TI, PHIBB, PhiIdx, Val);
+ /// Add \p value as an operand of the phi argument \p phi for the specified
+ /// predecessor block \p predBlock.
+ static void AddPHIOperand(SILPhiArgument *phi, SILValue value,
+ SILBasicBlock *predBlock) {
+ auto *phiBlock = phi->getParent();
+ size_t phiArgIndex = phi->getIndex();
+ auto *ti = predBlock->getTerminator();
+ changeEdgeValue(ti, phiBlock, phiArgIndex, value);
}
- /// InstrIsPHI - Check if an instruction is a PHI.
- ///
- static SILPhiArgument *InstrIsPHI(ValueBase *I) {
- auto *Res = dyn_cast(I);
- return Res;
+ /// Check if an instruction is a PHI.
+ static SILPhiArgument *InstrIsPHI(ValueBase *valueBase) {
+ return dyn_cast(valueBase);
}
- /// ValueIsPHI - Check if the instruction that defines the specified register
- /// is a PHI instruction.
- static SILPhiArgument *ValueIsPHI(SILValue V, SILSSAUpdater *Updater) {
- return InstrIsPHI(V);
+ /// Check if the instruction that defines the specified SILValue is a PHI
+ /// instruction.
+ static SILPhiArgument *ValueIsPHI(SILValue value, SILSSAUpdater *) {
+ return InstrIsPHI(value);
}
/// Like ValueIsPHI but also check if the PHI has no source
/// operands, i.e., it was just added.
- static SILPhiArgument *ValueIsNewPHI(SILValue Val, SILSSAUpdater *Updater) {
- SILPhiArgument *PHI = ValueIsPHI(Val, Updater);
- if (PHI) {
- auto *PhiBB = PHI->getParent();
- size_t PhiIdx = PHI->getIndex();
-
- // If all predecessor edges are 'not set' this is a new phi.
- for (auto *PredBB : PhiBB->getPredecessorBlocks()) {
- OperandValueArrayRef Edges =
- getEdgeValuesForTerminator(PredBB->getTerminator(), PhiBB);
-
- assert(PhiIdx < Edges.size() && "Not enough edges!");
-
- SILValue V = Edges[PhiIdx];
- // Check for the 'not set' sentinel.
- if (V != Updater->PHISentinel.get())
- return nullptr;
- }
- return PHI;
+ static SILPhiArgument *ValueIsNewPHI(SILValue value,
+ SILSSAUpdater *ssaUpdater) {
+ SILPhiArgument *phiArg = ValueIsPHI(value, ssaUpdater);
+ if (!phiArg) {
+ return nullptr;
}
- return nullptr;
+
+ auto *phiBlock = phiArg->getParent();
+ size_t phiArgEdgeIndex = phiArg->getIndex();
+
+ // If all predecessor edges are 'not set' this is a new phi.
+ for (auto *predBlock : phiBlock->getPredecessorBlocks()) {
+ OperandValueArrayRef edgeValues =
+ getEdgeValuesForTerminator(predBlock->getTerminator(), phiBlock);
+
+ assert(phiArgEdgeIndex < edgeValues.size() && "Not enough edges!");
+
+ SILValue edgeValue = edgeValues[phiArgEdgeIndex];
+ // Check for the 'not set' sentinel.
+ if (edgeValue != ssaUpdater->phiSentinel.get())
+ return nullptr;
+ }
+ return phiArg;
}
- static SILValue GetPHIValue(SILPhiArgument *PHI) { return PHI; }
+ static SILValue GetPHIValue(SILPhiArgument *phi) { return phi; }
};
} // namespace llvm
@@ -379,14 +387,15 @@ class SSAUpdaterTraits {
/// Check to see if AvailableVals has an entry for the specified BB and if so,
/// return it. If not, construct SSA form by first calculating the required
/// placement of PHIs and then inserting new PHIs where needed.
-SILValue SILSSAUpdater::GetValueAtEndOfBlockInternal(SILBasicBlock *BB){
- AvailableValsTy &AvailableVals = *AV;
- auto AI = AvailableVals.find(BB);
- if (AI != AvailableVals.end())
- return AI->second;
-
- llvm::SSAUpdaterImpl Impl(this, &AvailableVals, InsertedPHIs);
- return Impl.GetValue(BB);
+SILValue SILSSAUpdater::getValueAtEndOfBlockInternal(SILBasicBlock *block) {
+ AvailableValsTy &availableValues = *blockToAvailableValueMap;
+ auto iter = availableValues.find(block);
+ if (iter != availableValues.end())
+ return iter->second;
+
+ llvm::SSAUpdaterImpl impl(this, &availableValues,
+ insertedPhis);
+ return impl.GetValue(block);
}
/// Construct a use wrapper. For branches we store information so that we
@@ -395,67 +404,70 @@ SILValue SILSSAUpdater::GetValueAtEndOfBlockInternal(SILBasicBlock *BB){
/// When a branch is modified existing pointers to the operand
/// (ValueUseIterator) become invalid as they point to freed operands. Instead
/// we store the branch's parent and the idx so that we can reconstruct the use.
-UseWrapper::UseWrapper(Operand *Use) {
- U = nullptr;
- Type = kRegularUse;
+UseWrapper::UseWrapper(Operand *inputUse) {
+ wrappedUse = nullptr;
+ type = kRegularUse;
- SILInstruction *User = Use->getUser();
+ SILInstruction *user = inputUse->getUser();
// Direct branch user.
- if (auto *Br = dyn_cast(User)) {
- auto Opds = User->getAllOperands();
- for (unsigned i = 0, e = Opds.size(); i != e; ++i) {
- if (Use == &Opds[i]) {
- Idx = i;
- Type = kBranchUse;
- Parent = Br->getParent();
+ if (auto *br = dyn_cast(user)) {
+ for (auto pair : llvm::enumerate(user->getAllOperands())) {
+ if (inputUse == &pair.value()) {
+ index = pair.index();
+ type = kBranchUse;
+ parent = br->getParent();
return;
}
}
}
// Conditional branch user.
- if (auto *Br = dyn_cast(User)) {
- auto Opds = User->getAllOperands();
- auto NumTrueArgs = Br->getTrueArgs().size();
- for (unsigned i = 0, e = Opds.size(); i != e; ++i) {
- if (Use == &Opds[i]) {
+ if (auto *cbi = dyn_cast(user)) {
+ auto operands = user->getAllOperands();
+ auto numTrueArgs = cbi->getTrueArgs().size();
+ for (auto pair : llvm::enumerate(operands)) {
+ if (inputUse == &pair.value()) {
+ unsigned i = pair.index();
// We treat the condition as part of the true args.
- if (i < NumTrueArgs + 1) {
- Idx = i;
- Type = kCondBranchUseTrue;
+ if (i < numTrueArgs + 1) {
+ index = i;
+ type = kCondBranchUseTrue;
} else {
- Idx = i - NumTrueArgs - 1;
- Type = kCondBranchUseFalse;
+ index = i - numTrueArgs - 1;
+ type = kCondBranchUseFalse;
}
- Parent = Br->getParent();
+ parent = cbi->getParent();
return;
}
}
}
- U = Use;
+ wrappedUse = inputUse;
}
/// Return the operand we wrap. Reconstructing branch operands.
Operand *UseWrapper::getOperand() {
- switch (Type) {
+ switch (type) {
case kRegularUse:
- return U;
+ return wrappedUse;
case kBranchUse: {
- auto *Br = cast(Parent->getTerminator());
- assert(Idx < Br->getNumArgs());
- return &Br->getAllOperands()[Idx];
+ auto *br = cast(parent->getTerminator());
+ assert(index < br->getNumArgs());
+ return &br->getAllOperands()[index];
}
case kCondBranchUseTrue:
case kCondBranchUseFalse: {
- auto *Br = cast(Parent->getTerminator());
- unsigned IdxToUse =
- Type == kCondBranchUseTrue ? Idx : Br->getTrueArgs().size() + 1 + Idx;
- assert(IdxToUse < Br->getAllOperands().size());
- return &Br->getAllOperands()[IdxToUse];
+ auto *cbi = cast(parent->getTerminator());
+ auto indexToUse = [&]() -> unsigned {
+ if (type == kCondBranchUseTrue)
+ return index;
+ return cbi->getTrueArgs().size() + 1 + index;
+ }();
+ assert(indexToUse < cbi->getAllOperands().size());
+ return &cbi->getAllOperands()[indexToUse];
}
}
@@ -470,12 +482,12 @@ Operand *UseWrapper::getOperand() {
/// ArgValues are the values feeding the specified Argument from each
/// predecessor. They must be listed in order of Arg->getParent()->getPreds().
static StructInst *
-replaceBBArgWithStruct(SILPhiArgument *Arg,
- SmallVectorImpl &ArgValues) {
+replaceBBArgWithStruct(SILPhiArgument *phiArg,
+ SmallVectorImpl &argValues) {
- SILBasicBlock *PhiBB = Arg->getParent();
- auto *FirstSI = dyn_cast(ArgValues[0]);
- if (!FirstSI)
+ SILBasicBlock *phiBlock = phiArg->getParent();
+ auto *firstSI = dyn_cast(argValues[0]);
+ if (!firstSI)
return nullptr;
// Collect the BBArg index of each struct oper.
@@ -483,42 +495,45 @@ replaceBBArgWithStruct(SILPhiArgument *Arg,
// struct(A, B)
// br (B, A)
// : ArgIdxForOper => {1, 0}
- SmallVector ArgIdxForOper;
- for (unsigned OperIdx : indices(FirstSI->getElements())) {
- bool FoundMatchingArgIdx = false;
- for (unsigned ArgIdx : indices(PhiBB->getArguments())) {
- SmallVectorImpl::const_iterator AVIter = ArgValues.begin();
- bool TryNextArgIdx = false;
- for (SILBasicBlock *PredBB : PhiBB->getPredecessorBlocks()) {
+ SmallVector argIdxForOper;
+ for (unsigned operIdx : indices(firstSI->getElements())) {
+ bool foundMatchingArgIdx = false;
+ for (unsigned argIdx : indices(phiBlock->getArguments())) {
+ auto avIter = argValues.begin();
+ bool tryNextArgIdx = false;
+ for (SILBasicBlock *predBlock : phiBlock->getPredecessorBlocks()) {
// All argument values must be StructInst.
- auto *PredSI = dyn_cast(*AVIter++);
- if (!PredSI)
+ auto *predSI = dyn_cast(*avIter++);
+ if (!predSI)
return nullptr;
- OperandValueArrayRef EdgeValues =
- getEdgeValuesForTerminator(PredBB->getTerminator(), PhiBB);
- if (EdgeValues[ArgIdx] != PredSI->getElements()[OperIdx]) {
- TryNextArgIdx = true;
+ OperandValueArrayRef edgeValues =
+ getEdgeValuesForTerminator(predBlock->getTerminator(), phiBlock);
+ if (edgeValues[argIdx] != predSI->getElements()[operIdx]) {
+ tryNextArgIdx = true;
break;
}
}
- if (!TryNextArgIdx) {
- assert(AVIter == ArgValues.end() && "# ArgValues does not match # BB preds");
- FoundMatchingArgIdx = true;
- ArgIdxForOper.push_back(ArgIdx);
+ if (!tryNextArgIdx) {
+ assert(avIter == argValues.end() &&
+ "# ArgValues does not match # BB preds");
+ foundMatchingArgIdx = true;
+ argIdxForOper.push_back(argIdx);
break;
}
}
- if (!FoundMatchingArgIdx)
+ if (!foundMatchingArgIdx)
return nullptr;
}
- SmallVector StructArgs;
- for (auto ArgIdx : ArgIdxForOper)
- StructArgs.push_back(PhiBB->getArgument(ArgIdx));
+ SmallVector structArgs;
+ for (auto argIdx : argIdxForOper)
+ structArgs.push_back(phiBlock->getArgument(argIdx));
- SILBuilder Builder(PhiBB, PhiBB->begin());
- return Builder.createStruct(cast(ArgValues[0])->getLoc(),
- Arg->getType(), StructArgs);
+ // TODO: We probably want to use a SILBuilderWithScope here. What should we
+ // use?
+ SILBuilder builder(phiBlock, phiBlock->begin());
+ return builder.createStruct(cast(argValues[0])->getLoc(),
+ phiArg->getType(), structArgs);
}
/// Canonicalize BB arguments, replacing argument-of-casts with
@@ -527,10 +542,10 @@ replaceBBArgWithStruct(SILPhiArgument *Arg,
/// detection like induction variable analysis to succeed.
///
/// If Arg is replaced, return the cast instruction. Otherwise return nullptr.
-SILValue swift::replaceBBArgWithCast(SILPhiArgument *Arg) {
- SmallVector ArgValues;
- Arg->getIncomingPhiValues(ArgValues);
- if (isa(ArgValues[0]))
- return replaceBBArgWithStruct(Arg, ArgValues);
+SILValue swift::replaceBBArgWithCast(SILPhiArgument *arg) {
+ SmallVector argValues;
+ arg->getIncomingPhiValues(argValues);
+ if (isa(argValues[0]))
+ return replaceBBArgWithStruct(arg, argValues);
return nullptr;
}
diff --git a/lib/SILOptimizer/Utils/SpecializationMangler.cpp b/lib/SILOptimizer/Utils/SpecializationMangler.cpp
index 9807b43eb5f6d..3a37e3f3430ba 100644
--- a/lib/SILOptimizer/Utils/SpecializationMangler.cpp
+++ b/lib/SILOptimizer/Utils/SpecializationMangler.cpp
@@ -243,7 +243,6 @@ FunctionSignatureSpecializationMangler::mangleConstantProp(LiteralInst *LI) {
switch (SLI->getEncoding()) {
case StringLiteralInst::Encoding::Bytes: ArgOpBuffer << 'B'; break;
case StringLiteralInst::Encoding::UTF8: ArgOpBuffer << 'b'; break;
- case StringLiteralInst::Encoding::UTF16: ArgOpBuffer << 'w'; break;
case StringLiteralInst::Encoding::ObjCSelector: ArgOpBuffer << 'c'; break;
}
break;
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt
index 887ece0e2a85c..3beec6900ad47 100644
--- a/lib/Sema/CMakeLists.txt
+++ b/lib/Sema/CMakeLists.txt
@@ -59,7 +59,7 @@ add_swift_host_library(swiftSema STATIC
TypeCheckDeclObjC.cpp
TypeCheckDeclOverride.cpp
TypeCheckDeclPrimary.cpp
- TypeCheckError.cpp
+ TypeCheckEffects.cpp
TypeCheckExpr.cpp
TypeCheckExprObjC.cpp
TypeCheckGeneric.cpp
diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp
index ab6e244606004..96cf2965568c7 100644
--- a/lib/Sema/CSApply.cpp
+++ b/lib/Sema/CSApply.cpp
@@ -237,6 +237,9 @@ static bool buildObjCKeyPathString(KeyPathExpr *E,
// Don't bother building the key path string if the key path didn't even
// resolve.
return false;
+ case KeyPathExpr::Component::Kind::DictionaryKey:
+ llvm_unreachable("DictionaryKey only valid in #keyPath expressions.");
+ return false;
}
}
@@ -2696,7 +2699,7 @@ namespace {
// then we're in an ambiguity tolerant mode used for diagnostic
// generation. Just leave this as an unresolved member reference.
Type resultTy = simplifyType(cs.getType(expr));
- if (resultTy->getRValueType()->is()) {
+ if (resultTy->hasUnresolvedType()) {
cs.setType(expr, resultTy);
return expr;
}
@@ -4700,6 +4703,10 @@ namespace {
case KeyPathExpr::Component::Kind::OptionalWrap:
case KeyPathExpr::Component::Kind::TupleElement:
llvm_unreachable("already resolved");
+ break;
+ case KeyPathExpr::Component::Kind::DictionaryKey:
+ llvm_unreachable("DictionaryKey only valid in #keyPath");
+ break;
}
// Update "componentTy" with the result type of the last component.
@@ -5472,124 +5479,6 @@ static bool hasCurriedSelf(ConstraintSystem &cs, ConcreteDeclRef callee,
return false;
}
-/// Attach a Fix-It to the given diagnostic to give the trailing closure
-/// argument a label.
-static void labelTrailingClosureArgument(
- ASTContext &ctx, Expr *fn, Expr *arg, Identifier paramName,
- Expr *trailingClosure, InFlightDiagnostic &diag) {
- // Dig out source locations.
- SourceLoc existingRParenLoc;
- SourceLoc leadingCommaLoc;
- if (auto tupleExpr = dyn_cast(arg)) {
- existingRParenLoc = tupleExpr->getRParenLoc();
- assert(tupleExpr->getNumElements() >= 2 && "Should be a ParenExpr?");
- leadingCommaLoc = Lexer::getLocForEndOfToken(
- ctx.SourceMgr,
- tupleExpr->getElements()[tupleExpr->getNumElements()-2]->getEndLoc());
- } else {
- auto parenExpr = cast(arg);
- existingRParenLoc = parenExpr->getRParenLoc();
- }
-
- // Figure out the text to be inserted before the trailing closure.
- SmallString<16> insertionText;
- SourceLoc insertionLoc;
- if (leadingCommaLoc.isValid()) {
- insertionText += ", ";
- assert(existingRParenLoc.isValid());
- insertionLoc = leadingCommaLoc;
- } else if (existingRParenLoc.isInvalid()) {
- insertionText += "(";
- insertionLoc = Lexer::getLocForEndOfToken(
- ctx.SourceMgr, fn->getEndLoc());
- } else {
- insertionLoc = existingRParenLoc;
- }
-
- // Add the label, if there is one.
- if (!paramName.empty()) {
- insertionText += paramName.str();
- insertionText += ": ";
- }
-
- // If there is an existing right parentheses, remove it while we
- // insert the new text.
- if (existingRParenLoc.isValid()) {
- SourceLoc afterExistingRParenLoc = Lexer::getLocForEndOfToken(
- ctx.SourceMgr, existingRParenLoc);
- diag.fixItReplaceChars(
- insertionLoc, afterExistingRParenLoc, insertionText);
- } else {
- // Insert the appropriate prefix.
- diag.fixItInsert(insertionLoc, insertionText);
- }
-
- // Insert a right parenthesis after the closing '}' of the trailing closure;
- SourceLoc newRParenLoc = Lexer::getLocForEndOfToken(
- ctx.SourceMgr, trailingClosure->getEndLoc());
- diag.fixItInsert(newRParenLoc, ")");
-}
-
-/// Find the trailing closure argument of a tuple or parenthesized expression.
-///
-/// Due to a quirk of the backward scan that could allow reordering of
-/// arguments in the presence of a trailing closure, it might not be the last
-/// argument in the tuple.
-static Expr *findTrailingClosureArgument(Expr *arg) {
- if (auto parenExpr = dyn_cast(arg)) {
- return parenExpr->getSubExpr();
- }
-
- auto tupleExpr = cast(arg);
- SourceLoc endLoc = tupleExpr->getEndLoc();
- for (Expr *elt : llvm::reverse(tupleExpr->getElements())) {
- if (elt->getEndLoc() == endLoc)
- return elt;
- }
-
- return tupleExpr->getElements().back();
-}
-
-/// Find the index of the parameter that binds the given argument.
-static unsigned findParamBindingArgument(
- ArrayRef