mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Access scopes for enforcing exclusivity are currently the only
exception to our ability to canonicalize OSSA lifetime purely based on
the SSA value's known uses. This is because access scopes have
semantics relative to object deinitializers.
In general, deinitializers are asynchronous with respect to code that
is unrelated to the object's uses. Ignoring exclusivity, the optimizer
may always destroy objects as early as it wants, as long as the object
won't be used again. The optimizer may also extend the lifetime
(although in the future this lifetime extension should be limited by
"synchronization points").
The optimizer's freedom is however limited by exclusivity
enforcement. Optimization may never introduce new exclusivity
violations. Destroying an object within an access scope is an
exclusivity violation if the deinitializer accesses the same variable.
To handle this, OSSA canonicalization must detect access scopes that
overlap with the end of the pruned extended lifetime. Essentially:
%def
begin_access // access scope unrelated to def
use %def // pruned liveness ends here
end_access
destroy %def
Support for access scopes composes cleanly with the existing algorithm
without adding significant cost in the usual case. Overlapping access
scopes are unusual. A single CFG walk within the original extended
lifetime is normally sufficient. Only the blocks that are not already
LiveOut in the pruned liveness need to be visited. During this walk,
local overlapping access are detected by scanning for end_access
instructions after the last use point. Global overlapping accesses are
detected by checking NonLocalAccessBlockAnalysis. This avoids scanning
instructions in the common case. NonLocalAccessBlockAnalysis is a
trivial analysis that caches the rare occurence of nonlocal access
scopes. The analysis itself is a single linear scan over the
instruction stream. This analysis can be preserved across most
transformations and I expect it to be used to speed up other
optimizations related to access marker.
When an overlapping access is detected, pruned liveness is simply
extended to include the end_access as a new use point. Extending the
lifetime is iterative, but with each iteration, blocks that are now
marked LiveOut no longer need to be visited. Furthermore, interleaved
accessed scopes are not expected to happen in practice.
132 lines
4.0 KiB
C++
132 lines
4.0 KiB
C++
//===--- Compiler.h - Compiler specific definitions -------------*- C++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_BASIC_COMPILER_H
|
|
#define SWIFT_BASIC_COMPILER_H
|
|
|
|
#if defined(_MSC_VER) && !defined(__clang__)
|
|
#define SWIFT_COMPILER_IS_MSVC 1
|
|
#else
|
|
#define SWIFT_COMPILER_IS_MSVC 0
|
|
#endif
|
|
|
|
// Workaround non-clang compilers
|
|
#ifndef __has_builtin
|
|
#define __has_builtin(x) 0
|
|
#endif
|
|
#ifndef __has_attribute
|
|
#define __has_attribute(x) 0
|
|
#endif
|
|
|
|
// __builtin_assume() is an optimization hint.
|
|
#if __has_builtin(__builtin_assume)
|
|
#define SWIFT_ASSUME(x) __builtin_assume(x)
|
|
#else
|
|
#define SWIFT_ASSUME(x)
|
|
#endif
|
|
|
|
/// Attributes.
|
|
|
|
#if __has_attribute(constructor)
|
|
#define SWIFT_CONSTRUCTOR __attribute__((constructor))
|
|
#else
|
|
#define SWIFT_CONSTRUCTOR
|
|
#endif
|
|
|
|
/// \macro SWIFT_GNUC_PREREQ
|
|
/// Extend the default __GNUC_PREREQ even if glibc's features.h isn't
|
|
/// available.
|
|
#ifndef SWIFT_GNUC_PREREQ
|
|
# if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
|
|
# define SWIFT_GNUC_PREREQ(maj, min, patch) \
|
|
((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) + __GNUC_PATCHLEVEL__ >= \
|
|
((maj) << 20) + ((min) << 10) + (patch))
|
|
# elif defined(__GNUC__) && defined(__GNUC_MINOR__)
|
|
# define SWIFT_GNUC_PREREQ(maj, min, patch) \
|
|
((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) >= ((maj) << 20) + ((min) << 10))
|
|
# else
|
|
# define SWIFT_GNUC_PREREQ(maj, min, patch) 0
|
|
# endif
|
|
#endif
|
|
|
|
|
|
/// SWIFT_ATTRIBUTE_NOINLINE - On compilers where we have a directive to do so,
|
|
/// mark a method "not for inlining".
|
|
#if __has_attribute(noinline) || SWIFT_GNUC_PREREQ(3, 4, 0)
|
|
#define SWIFT_ATTRIBUTE_NOINLINE __attribute__((noinline))
|
|
#elif defined(_MSC_VER)
|
|
#define SWIFT_ATTRIBUTE_NOINLINE __declspec(noinline)
|
|
#else
|
|
#define SWIFT_ATTRIBUTE_NOINLINE
|
|
#endif
|
|
|
|
/// SWIFT_ATTRIBUTE_ALWAYS_INLINE - On compilers where we have a directive to do
|
|
/// so, mark a method "always inline" because it is performance sensitive. GCC
|
|
/// 3.4 supported this but is buggy in various cases and produces unimplemented
|
|
/// errors, just use it in GCC 4.0 and later.
|
|
#if __has_attribute(always_inline) || SWIFT_GNUC_PREREQ(4, 0, 0)
|
|
#define SWIFT_ATTRIBUTE_ALWAYS_INLINE __attribute__((always_inline))
|
|
#elif defined(_MSC_VER)
|
|
#define SWIFT_ATTRIBUTE_ALWAYS_INLINE __forceinline
|
|
#else
|
|
#define SWIFT_ATTRIBUTE_ALWAYS_INLINE
|
|
#endif
|
|
|
|
#ifdef __GNUC__
|
|
#define SWIFT_ATTRIBUTE_NORETURN __attribute__((noreturn))
|
|
#elif defined(_MSC_VER)
|
|
#define SWIFT_ATTRIBUTE_NORETURN __declspec(noreturn)
|
|
#else
|
|
#define SWIFT_ATTRIBUTE_NORETURN
|
|
#endif
|
|
|
|
#ifndef SWIFT_BUG_REPORT_URL
|
|
#define SWIFT_BUG_REPORT_URL "https://swift.org/contributing/#reporting-bugs"
|
|
#endif
|
|
|
|
#define SWIFT_BUG_REPORT_MESSAGE_BASE \
|
|
"submit a bug report (" SWIFT_BUG_REPORT_URL \
|
|
") and include the project"
|
|
|
|
#define SWIFT_BUG_REPORT_MESSAGE \
|
|
"please " SWIFT_BUG_REPORT_MESSAGE_BASE
|
|
|
|
#define SWIFT_CRASH_BUG_REPORT_MESSAGE \
|
|
"Please " SWIFT_BUG_REPORT_MESSAGE_BASE " and the crash backtrace."
|
|
|
|
// Conditionally exclude declarations or statements that are only needed for
|
|
// assertions from release builds (NDEBUG) without cluttering the surrounding
|
|
// code by #ifdefs.
|
|
//
|
|
// struct DoThings {
|
|
// SWIFT_ASSERT_ONLY_DECL(unsigned verifyCount = 0);
|
|
// DoThings() {
|
|
// SWIFT_ASSERT_ONLY(verifyCount = getNumberOfThingsToDo());
|
|
// }
|
|
// void doThings() {
|
|
// do {
|
|
// // ... do each thing
|
|
// SWIFT_ASSERT_ONLY(--verifyCount);
|
|
// } while (!done());
|
|
// assert(verifyCount == 0 && "did not do everything");
|
|
// }
|
|
// };
|
|
#ifdef NDEBUG
|
|
#define SWIFT_ASSERT_ONLY_DECL(...)
|
|
#define SWIFT_ASSERT_ONLY(...) do { } while (false)
|
|
#else
|
|
#define SWIFT_ASSERT_ONLY_DECL(X...) X
|
|
#define SWIFT_ASSERT_ONLY(X...) do { X; } while (false)
|
|
#endif
|
|
|
|
#endif // SWIFT_BASIC_COMPILER_H
|