mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Although I don't plan to bring over new assertions wholesale into the current qualification branch, it's entirely possible that various minor changes in main will use the new assertions; having this basic support in the release branch will simplify that. (This is why I'm adding the includes as a separate pass from rewriting the individual assertions)
413 lines
16 KiB
C++
413 lines
16 KiB
C++
//===--- LayoutConstraint.cpp - Layout constraints types and APIs ---------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements APIs for layout constraints.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "swift/AST/ASTContext.h"
|
|
#include "swift/AST/Decl.h"
|
|
#include "swift/AST/Types.h"
|
|
#include "swift/Basic/Assertions.h"
|
|
|
|
namespace swift {
|
|
|
|
/// This helper function is typically used by the parser to
|
|
/// map a type name to a corresponding layout constraint if possible.
|
|
LayoutConstraint getLayoutConstraint(Identifier ID, ASTContext &Ctx) {
|
|
if (ID == Ctx.Id_TrivialLayout)
|
|
return LayoutConstraint::getLayoutConstraint(
|
|
LayoutConstraintKind::TrivialOfExactSize, 0, 0, Ctx);
|
|
|
|
if (ID == Ctx.Id_TrivialAtMostLayout)
|
|
return LayoutConstraint::getLayoutConstraint(
|
|
LayoutConstraintKind::TrivialOfAtMostSize, 0, 0, Ctx);
|
|
|
|
if (ID == Ctx.Id_RefCountedObjectLayout)
|
|
return LayoutConstraint::getLayoutConstraint(
|
|
LayoutConstraintKind::RefCountedObject, Ctx);
|
|
|
|
if (ID == Ctx.Id_NativeRefCountedObjectLayout)
|
|
return LayoutConstraint::getLayoutConstraint(
|
|
LayoutConstraintKind::NativeRefCountedObject, Ctx);
|
|
|
|
if (ID == Ctx.Id_ClassLayout)
|
|
return LayoutConstraint::getLayoutConstraint(
|
|
LayoutConstraintKind::Class, Ctx);
|
|
|
|
if (ID == Ctx.Id_NativeClassLayout)
|
|
return LayoutConstraint::getLayoutConstraint(
|
|
LayoutConstraintKind::NativeClass, Ctx);
|
|
|
|
if (ID == Ctx.Id_BridgeObjectLayout)
|
|
return LayoutConstraint::getLayoutConstraint(
|
|
LayoutConstraintKind::BridgeObject, Ctx);
|
|
|
|
if (ID == Ctx.Id_TrivialStrideLayout)
|
|
return LayoutConstraint::getLayoutConstraint(
|
|
LayoutConstraintKind::TrivialStride, 0, 0, Ctx);
|
|
|
|
return LayoutConstraint::getLayoutConstraint(
|
|
LayoutConstraintKind::UnknownLayout, Ctx);
|
|
}
|
|
|
|
StringRef LayoutConstraintInfo::getName(bool internalName) const {
|
|
return getName(getKind(), internalName);
|
|
}
|
|
|
|
StringRef LayoutConstraintInfo::getName(LayoutConstraintKind Kind, bool internalName) {
|
|
switch (Kind) {
|
|
case LayoutConstraintKind::UnknownLayout:
|
|
return "_UnknownLayout";
|
|
case LayoutConstraintKind::Class:
|
|
return internalName ? "_Class" : "AnyObject";
|
|
case LayoutConstraintKind::NativeClass:
|
|
return "_NativeClass";
|
|
case LayoutConstraintKind::RefCountedObject:
|
|
return "_RefCountedObject";
|
|
case LayoutConstraintKind::NativeRefCountedObject:
|
|
return "_NativeRefCountedObject";
|
|
case LayoutConstraintKind::Trivial:
|
|
return "_Trivial";
|
|
case LayoutConstraintKind::TrivialOfAtMostSize:
|
|
return "_TrivialAtMost";
|
|
case LayoutConstraintKind::TrivialOfExactSize:
|
|
return "_Trivial";
|
|
case LayoutConstraintKind::BridgeObject:
|
|
return "_BridgeObject";
|
|
case LayoutConstraintKind::TrivialStride:
|
|
return "_TrivialStride";
|
|
}
|
|
|
|
llvm_unreachable("Unhandled LayoutConstraintKind in switch.");
|
|
}
|
|
|
|
/// Uniquing for the LayoutConstraintInfo.
|
|
void LayoutConstraintInfo::Profile(llvm::FoldingSetNodeID &ID,
|
|
LayoutConstraintKind Kind,
|
|
unsigned SizeInBits,
|
|
unsigned Alignment) {
|
|
ID.AddInteger((unsigned)Kind);
|
|
ID.AddInteger(SizeInBits);
|
|
ID.AddInteger(Alignment);
|
|
}
|
|
|
|
bool LayoutConstraintInfo::isKnownLayout(LayoutConstraintKind Kind) {
|
|
return Kind != LayoutConstraintKind::UnknownLayout;
|
|
}
|
|
|
|
bool LayoutConstraintInfo::isFixedSizeTrivial(LayoutConstraintKind Kind) {
|
|
return Kind == LayoutConstraintKind::TrivialOfExactSize;
|
|
}
|
|
|
|
bool LayoutConstraintInfo::isKnownSizeTrivial(LayoutConstraintKind Kind) {
|
|
return Kind > LayoutConstraintKind::UnknownLayout &&
|
|
Kind < LayoutConstraintKind::Trivial;
|
|
}
|
|
|
|
bool LayoutConstraintInfo::isAddressOnlyTrivial(LayoutConstraintKind Kind) {
|
|
return Kind == LayoutConstraintKind::Trivial;
|
|
}
|
|
|
|
bool LayoutConstraintInfo::isTrivial(LayoutConstraintKind Kind) {
|
|
return (Kind > LayoutConstraintKind::UnknownLayout &&
|
|
Kind <= LayoutConstraintKind::Trivial) ||
|
|
Kind == LayoutConstraintKind::TrivialStride;
|
|
}
|
|
|
|
bool LayoutConstraintInfo::isRefCountedObject(LayoutConstraintKind Kind) {
|
|
return Kind == LayoutConstraintKind::RefCountedObject;
|
|
}
|
|
|
|
bool LayoutConstraintInfo::isNativeRefCountedObject(LayoutConstraintKind Kind) {
|
|
return Kind == LayoutConstraintKind::NativeRefCountedObject;
|
|
}
|
|
|
|
bool LayoutConstraintInfo::isAnyRefCountedObject(LayoutConstraintKind Kind) {
|
|
return isRefCountedObject(Kind) || isNativeRefCountedObject(Kind);
|
|
}
|
|
|
|
bool LayoutConstraintInfo::isClass(LayoutConstraintKind Kind) {
|
|
return Kind == LayoutConstraintKind::Class ||
|
|
Kind == LayoutConstraintKind::NativeClass;
|
|
}
|
|
|
|
bool LayoutConstraintInfo::isNativeClass(LayoutConstraintKind Kind) {
|
|
return Kind == LayoutConstraintKind::NativeClass;
|
|
}
|
|
|
|
bool LayoutConstraintInfo::isRefCounted(LayoutConstraintKind Kind) {
|
|
return isAnyRefCountedObject(Kind) || isClass(Kind) || isBridgeObject(Kind);
|
|
}
|
|
|
|
bool LayoutConstraintInfo::isNativeRefCounted(LayoutConstraintKind Kind) {
|
|
return Kind == LayoutConstraintKind::NativeRefCountedObject ||
|
|
Kind == LayoutConstraintKind::NativeClass;
|
|
}
|
|
|
|
bool LayoutConstraintInfo::isBridgeObject(LayoutConstraintKind Kind) {
|
|
return Kind == LayoutConstraintKind::BridgeObject;
|
|
}
|
|
|
|
bool LayoutConstraintInfo::isTrivialStride(LayoutConstraintKind Kind) {
|
|
return Kind == LayoutConstraintKind::TrivialStride;
|
|
}
|
|
|
|
SourceRange LayoutConstraintLoc::getSourceRange() const { return getLoc(); }
|
|
|
|
#define MERGE_LOOKUP(lhs, rhs) \
|
|
mergeTable[int(lhs)][int(rhs)]
|
|
|
|
// Shortcut for spelling the whole enumerator.
|
|
#define E(X) LayoutConstraintKind::X
|
|
#define MERGE_CONFLICT LayoutConstraintKind::UnknownLayout
|
|
|
|
/// This is a 2-D table defining the merging rules for layout constraints.
|
|
/// It is indexed by means of LayoutConstraintKind.
|
|
/// mergeTable[i][j] tells the kind of a layout constraint is the result
|
|
/// of merging layout constraints of kinds 'i' and 'j'.
|
|
///
|
|
/// Some of the properties of the merge table, where C is any type of layout
|
|
/// constraint:
|
|
/// UnknownLayout x C -> C
|
|
/// C x UnknownLayout -> C
|
|
/// C x C -> C
|
|
/// mergeTable[i][j] == mergeTable[j][i], i.e. the table is symmetric.
|
|
/// mergeTable[i][j] == UnknownLayout if merging layout constraints of kinds i
|
|
/// and j would result in a conflict.
|
|
static LayoutConstraintKind mergeTable[unsigned(E(LastLayout)) +
|
|
1][unsigned(E(LastLayout)) + 1] = {
|
|
// Initialize the row for UnknownLayout.
|
|
{E(/* UnknownLayout */ UnknownLayout),
|
|
E(/* TrivialOfExactSize */ TrivialOfExactSize),
|
|
E(/* TrivialOfAtMostSize */ TrivialOfAtMostSize), E(/* Trivial */ Trivial),
|
|
E(/* Class */ Class), E(/* NativeClass */ NativeClass),
|
|
E(/* RefCountedObject*/ RefCountedObject),
|
|
E(/* NativeRefCountedObject */ NativeRefCountedObject), MERGE_CONFLICT,
|
|
MERGE_CONFLICT},
|
|
|
|
// Initialize the row for TrivialOfExactSize.
|
|
{E(/* UnknownLayout */ TrivialOfExactSize),
|
|
E(/* TrivialOfExactSize */ TrivialOfExactSize), MERGE_CONFLICT,
|
|
E(/* Trivial */ TrivialOfExactSize), MERGE_CONFLICT, MERGE_CONFLICT,
|
|
MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT},
|
|
|
|
// Initialize the row for TrivialOfAtMostSize.
|
|
{E(/* UnknownLayout */ TrivialOfAtMostSize), MERGE_CONFLICT,
|
|
E(/* TrivialOfAtMostSize */ TrivialOfAtMostSize),
|
|
E(/* Trivial */ TrivialOfAtMostSize), MERGE_CONFLICT, MERGE_CONFLICT,
|
|
MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT},
|
|
|
|
// Initialize the row for Trivial.
|
|
{E(/* UnknownLayout */ Trivial),
|
|
E(/* TrivialOfExactSize */ TrivialOfExactSize),
|
|
E(/* TrivialOfAtMostSize */ TrivialOfAtMostSize), E(/* Trivial */ Trivial),
|
|
MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT,
|
|
MERGE_CONFLICT, MERGE_CONFLICT},
|
|
|
|
// Initialize the row for Class.
|
|
{E(/* UnknownLayout*/ Class), MERGE_CONFLICT, MERGE_CONFLICT,
|
|
MERGE_CONFLICT, E(/* Class */ Class), E(/* NativeClass */ NativeClass),
|
|
E(/* RefCountedObject */ Class),
|
|
E(/* NativeRefCountedObject */ NativeClass), MERGE_CONFLICT,
|
|
MERGE_CONFLICT},
|
|
|
|
// Initialize the row for NativeClass.
|
|
{E(/* UnknownLayout */ NativeClass), MERGE_CONFLICT, MERGE_CONFLICT,
|
|
MERGE_CONFLICT, E(/* Class */ NativeClass),
|
|
E(/* NativeClass */ NativeClass), E(/* RefCountedObject */ NativeClass),
|
|
E(/* NativeRefCountedObject */ NativeClass), MERGE_CONFLICT,
|
|
MERGE_CONFLICT},
|
|
|
|
// Initialize the row for RefCountedObject.
|
|
{E(/* UnknownLayout */ RefCountedObject), MERGE_CONFLICT, MERGE_CONFLICT,
|
|
MERGE_CONFLICT, E(/* Class */ Class), E(/* NativeClass */ NativeClass),
|
|
E(/* RefCountedObject */ RefCountedObject),
|
|
E(/* NativeRefCountedObject */ NativeRefCountedObject), MERGE_CONFLICT,
|
|
MERGE_CONFLICT},
|
|
|
|
// Initialize the row for NativeRefCountedObject.
|
|
{E(/* UnknownLayout */ NativeRefCountedObject), MERGE_CONFLICT,
|
|
MERGE_CONFLICT, MERGE_CONFLICT, E(/* Class */ NativeClass),
|
|
E(/* NativeClass */ NativeClass),
|
|
E(/* RefCountedObject */ NativeRefCountedObject),
|
|
E(/* NativeRefCountedObject*/ NativeRefCountedObject), MERGE_CONFLICT,
|
|
MERGE_CONFLICT},
|
|
|
|
{E(BridgeObject), MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT,
|
|
MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT,
|
|
E(/*BridgeObject*/ BridgeObject), MERGE_CONFLICT},
|
|
|
|
{E(TrivialStride), MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT,
|
|
MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT, MERGE_CONFLICT,
|
|
MERGE_CONFLICT, E(/*TrivialStride*/ TrivialStride)},
|
|
};
|
|
|
|
#undef E
|
|
|
|
// Fixed-size trivial constraint can be combined with AtMostSize trivial
|
|
// constraint into a fixed-size trivial constraint, if
|
|
// fixed_size_layout.size <= at_most_size_layout.size and
|
|
// their alignment requirements are not contradicting.
|
|
//
|
|
// Only merges if LHS would become the result of the merge.
|
|
static LayoutConstraint
|
|
mergeKnownSizeTrivialConstraints(LayoutConstraint LHS, LayoutConstraint RHS) {
|
|
assert(LHS->isKnownSizeTrivial() && RHS->isKnownSizeTrivial());
|
|
|
|
// LHS should be fixed-size.
|
|
if (!LHS->isFixedSizeTrivial())
|
|
return LayoutConstraint::getUnknownLayout();
|
|
|
|
// RHS should be at-most-size.
|
|
if (RHS->isFixedSizeTrivial())
|
|
return LayoutConstraint::getUnknownLayout();
|
|
|
|
// Check that sizes are compatible, i.e.
|
|
// fixed_size_layout.size <= at_most_size_layout.size
|
|
if (LHS->getMaxTrivialSizeInBits() > RHS->getMaxTrivialSizeInBits())
|
|
return LayoutConstraint::getUnknownLayout();
|
|
|
|
// Check alignments
|
|
|
|
// Quick exit if at_most_size_layout does not care about the alignment.
|
|
if (!RHS->getAlignmentInBits())
|
|
return LHS;
|
|
|
|
// Check if fixed_size_layout.alignment is a multiple of
|
|
// at_most_size_layout.alignment.
|
|
if (LHS->getAlignmentInBits() &&
|
|
LHS->getAlignmentInBits() % RHS->getAlignmentInBits() == 0)
|
|
return LHS;
|
|
|
|
return LayoutConstraint::getUnknownLayout();
|
|
}
|
|
|
|
LayoutConstraint
|
|
LayoutConstraint::merge(LayoutConstraint Other) {
|
|
auto Self = *this;
|
|
|
|
// If both constraints are the same, they are always equal.
|
|
if (Self == Other)
|
|
return Self;
|
|
|
|
// TrivialOfExactSize and TrivialOfAtMostSize are a special case,
|
|
// because not only their kind, but their parameters need to be compared as
|
|
// well.
|
|
if (Self->isKnownSizeTrivial() && Other->isKnownSizeTrivial()) {
|
|
// If we got here, it means that the Self == Other check above has failed.
|
|
// And that could only happen if either the kinds are different or
|
|
// size/alignment parameters are different.
|
|
|
|
// Try to merge fixed-size constraint with an at-most-size constraint,
|
|
// if possible.
|
|
LayoutConstraint MergedKnownSizeTrivial;
|
|
MergedKnownSizeTrivial = mergeKnownSizeTrivialConstraints(Self, Other);
|
|
if (MergedKnownSizeTrivial->isKnownLayout())
|
|
return MergedKnownSizeTrivial;
|
|
|
|
MergedKnownSizeTrivial = mergeKnownSizeTrivialConstraints(Other, Self);
|
|
if (MergedKnownSizeTrivial->isKnownLayout())
|
|
return MergedKnownSizeTrivial;
|
|
|
|
return LayoutConstraint::getUnknownLayout();
|
|
}
|
|
|
|
// Lookup in the mergeTable if this combination of layouts can be merged.
|
|
auto mergeKind = MERGE_LOOKUP(Self->getKind(), Other->getKind());
|
|
// The merge table should be symmetric.
|
|
assert(mergeKind == MERGE_LOOKUP(Other->getKind(), Self->getKind()));
|
|
|
|
// Merge is not possible, report a conflict.
|
|
if (mergeKind == LayoutConstraintKind::UnknownLayout)
|
|
return LayoutConstraint::getUnknownLayout();
|
|
|
|
if (Self->getKind() == mergeKind)
|
|
return Self;
|
|
|
|
if (Other->getKind() == mergeKind)
|
|
return Other;
|
|
|
|
// The result of the merge is not equal to any of the input constraints, e.g.
|
|
// Class x NativeRefCountedObject -> NativeClass.
|
|
return LayoutConstraint::getLayoutConstraint(mergeKind);
|
|
}
|
|
|
|
LayoutConstraint
|
|
LayoutConstraint::getLayoutConstraint(LayoutConstraintKind Kind) {
|
|
assert(!LayoutConstraintInfo::isKnownSizeTrivial(Kind));
|
|
assert(!LayoutConstraintInfo::isTrivialStride(Kind));
|
|
switch(Kind) {
|
|
case LayoutConstraintKind::Trivial:
|
|
return LayoutConstraint(&LayoutConstraintInfo::TrivialConstraintInfo);
|
|
case LayoutConstraintKind::NativeClass:
|
|
return LayoutConstraint(&LayoutConstraintInfo::NativeClassConstraintInfo);
|
|
case LayoutConstraintKind::Class:
|
|
return LayoutConstraint(&LayoutConstraintInfo::ClassConstraintInfo);
|
|
case LayoutConstraintKind::NativeRefCountedObject:
|
|
return LayoutConstraint(
|
|
&LayoutConstraintInfo::NativeRefCountedObjectConstraintInfo);
|
|
case LayoutConstraintKind::RefCountedObject:
|
|
return LayoutConstraint(
|
|
&LayoutConstraintInfo::RefCountedObjectConstraintInfo);
|
|
case LayoutConstraintKind::UnknownLayout:
|
|
return LayoutConstraint(&LayoutConstraintInfo::UnknownLayoutConstraintInfo);
|
|
case LayoutConstraintKind::BridgeObject:
|
|
return LayoutConstraint(&LayoutConstraintInfo::BridgeObjectConstraintInfo);
|
|
case LayoutConstraintKind::TrivialOfAtMostSize:
|
|
case LayoutConstraintKind::TrivialOfExactSize:
|
|
case LayoutConstraintKind::TrivialStride:
|
|
llvm_unreachable("Wrong layout constraint kind");
|
|
}
|
|
llvm_unreachable("unhandled kind");
|
|
}
|
|
|
|
LayoutConstraint LayoutConstraint::getUnknownLayout() {
|
|
return LayoutConstraint(&LayoutConstraintInfo::UnknownLayoutConstraintInfo);
|
|
}
|
|
|
|
LayoutConstraintInfo LayoutConstraintInfo::UnknownLayoutConstraintInfo;
|
|
|
|
LayoutConstraintInfo LayoutConstraintInfo::RefCountedObjectConstraintInfo(
|
|
LayoutConstraintKind::RefCountedObject);
|
|
|
|
LayoutConstraintInfo LayoutConstraintInfo::NativeRefCountedObjectConstraintInfo(
|
|
LayoutConstraintKind::NativeRefCountedObject);
|
|
|
|
LayoutConstraintInfo LayoutConstraintInfo::ClassConstraintInfo(
|
|
LayoutConstraintKind::Class);
|
|
|
|
LayoutConstraintInfo LayoutConstraintInfo::NativeClassConstraintInfo(
|
|
LayoutConstraintKind::NativeClass);
|
|
|
|
LayoutConstraintInfo LayoutConstraintInfo::TrivialConstraintInfo(
|
|
LayoutConstraintKind::Trivial);
|
|
|
|
LayoutConstraintInfo LayoutConstraintInfo::BridgeObjectConstraintInfo(
|
|
LayoutConstraintKind::BridgeObject);
|
|
|
|
int LayoutConstraint::compare(LayoutConstraint rhs) const {
|
|
if (Ptr->getKind() != rhs->getKind())
|
|
return int(rhs->getKind()) - int(Ptr->getKind());
|
|
|
|
if (Ptr->SizeInBits != rhs->SizeInBits)
|
|
return int(rhs->SizeInBits) - int(Ptr->SizeInBits);
|
|
|
|
if (Ptr->Alignment != rhs->Alignment)
|
|
return int(rhs->Alignment) - int(Ptr->Alignment);
|
|
|
|
assert(*this == rhs);
|
|
return 0;
|
|
}
|
|
|
|
} // end namespace swift
|