blob: 0889ba3c462ffdad3dff45c12d1fdfc7897fc177 [file] [log] [blame]
//===-- LayoutConstraint.h - Layout constraints types and APIs --*- 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
//
//===----------------------------------------------------------------------===//
//
// This file defines types and APIs for layout constraints.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_LAYOUT_CONSTRAINT_H
#define SWIFT_LAYOUT_CONSTRAINT_H
#include "swift/AST/TypeAlignments.h"
#include "swift/Basic/Debug.h"
#include "swift/Basic/SourceLoc.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/StringRef.h"
#include "swift/AST/PrintOptions.h"
namespace swift {
enum class AllocationArena;
class ASTContext;
class ASTPrinter;
/// Describes a layout constraint information.
enum class LayoutConstraintKind : uint8_t {
// It is not a known layout constraint.
UnknownLayout,
// It is a layout constraint representing a trivial type of a known size.
TrivialOfExactSize,
// It is a layout constraint representing a trivial type of a size known to
// be no larger than a given size.
TrivialOfAtMostSize,
// It is a layout constraint representing a trivial type of an unknown size.
Trivial,
// It is a layout constraint representing a reference counted class instance.
Class,
// It is a layout constraint representing a reference counted native class
// instance.
NativeClass,
// It is a layout constraint representing a reference counted object.
RefCountedObject,
// It is a layout constraint representing a native reference counted object.
NativeRefCountedObject,
LastLayout = NativeRefCountedObject,
};
/// This is a class representing the layout constraint.
class LayoutConstraintInfo : public llvm::FoldingSetNode {
friend class LayoutConstraint;
// Alignment of the layout in bytes.
const unsigned Alignment : 16;
// Size of the layout in bits.
const unsigned SizeInBits : 24;
// Kind of the layout.
const LayoutConstraintKind Kind;
LayoutConstraintInfo()
: Alignment(0), SizeInBits(0), Kind(LayoutConstraintKind::UnknownLayout) {
}
LayoutConstraintInfo(const LayoutConstraintInfo &Layout)
: Alignment(Layout.Alignment), SizeInBits(Layout.SizeInBits),
Kind(Layout.Kind) {
}
LayoutConstraintInfo(LayoutConstraintKind Kind)
: Alignment(0), SizeInBits(0), Kind(Kind) {
assert(!isKnownSizeTrivial() && "Size in bits should be specified");
}
LayoutConstraintInfo(LayoutConstraintKind Kind, unsigned SizeInBits,
unsigned Alignment)
: Alignment(Alignment), SizeInBits(SizeInBits), Kind(Kind) {
assert(
isTrivial() &&
"Size in bits should be specified only for trivial layout constraints");
}
public:
LayoutConstraintKind getKind() const { return Kind; }
bool isKnownLayout() const {
return isKnownLayout(Kind);
}
bool isFixedSizeTrivial() const {
return isFixedSizeTrivial(Kind);
}
bool isKnownSizeTrivial() const {
return isKnownSizeTrivial(Kind);
}
bool isAddressOnlyTrivial() const {
return isAddressOnlyTrivial(Kind);
}
bool isTrivial() const {
return isTrivial(Kind);
}
bool isRefCountedObject() const {
return isRefCountedObject(Kind);
}
bool isNativeRefCountedObject() const {
return isNativeRefCountedObject(Kind);
}
bool isClass() const {
return isClass(Kind);
}
bool isNativeClass() const {
return isNativeClass(Kind);
}
bool isRefCounted() const {
return isRefCounted(Kind);
}
bool isNativeRefCounted() const {
return isNativeRefCounted(Kind);
}
unsigned getTrivialSizeInBytes() const {
assert(isKnownSizeTrivial());
return (SizeInBits + 7) / 8;
}
unsigned getMaxTrivialSizeInBytes() const {
assert(isKnownSizeTrivial());
return (SizeInBits + 7) / 8;
}
unsigned getTrivialSizeInBits() const {
assert(isKnownSizeTrivial());
return SizeInBits;
}
unsigned getMaxTrivialSizeInBits() const {
assert(isKnownSizeTrivial());
return SizeInBits;
}
unsigned getAlignmentInBits() const {
return Alignment;
}
unsigned getAlignmentInBytes() const {
assert(isKnownSizeTrivial());
if (Alignment)
return Alignment;
// There is no explicitly defined alignment. Try to come up with a
// reasonable one.
// If the size is a power of 2, use it also for the default alignment.
auto SizeInBytes = getTrivialSizeInBytes();
if (llvm::isPowerOf2_32(SizeInBytes))
return SizeInBytes * 8;
// Otherwise assume the alignment of 8 bytes.
return 8*8;
}
operator bool() const {
return isKnownLayout();
}
bool operator==(const LayoutConstraintInfo &rhs) const {
return getKind() == rhs.getKind() && SizeInBits == rhs.SizeInBits &&
Alignment == rhs.Alignment;
}
bool operator!=(LayoutConstraintInfo rhs) const { return !(*this == rhs); }
void print(raw_ostream &OS, const PrintOptions &PO = PrintOptions()) const;
void print(ASTPrinter &Printer, const PrintOptions &PO) const;
/// Return the layout constraint as a string, for use in diagnostics only.
std::string getString(const PrintOptions &PO = PrintOptions()) const;
/// Return the name of this layout constraint.
StringRef getName() const;
/// Return the name of a layout constraint with a given kind.
static StringRef getName(LayoutConstraintKind Kind);
static bool isKnownLayout(LayoutConstraintKind Kind);
static bool isFixedSizeTrivial(LayoutConstraintKind Kind);
static bool isKnownSizeTrivial(LayoutConstraintKind Kind);
static bool isAddressOnlyTrivial(LayoutConstraintKind Kind);
static bool isTrivial(LayoutConstraintKind Kind);
static bool isRefCountedObject(LayoutConstraintKind Kind);
static bool isNativeRefCountedObject(LayoutConstraintKind Kind);
static bool isAnyRefCountedObject(LayoutConstraintKind Kind);
static bool isClass(LayoutConstraintKind Kind);
static bool isNativeClass(LayoutConstraintKind Kind);
static bool isRefCounted(LayoutConstraintKind Kind);
static bool isNativeRefCounted(LayoutConstraintKind Kind);
/// Uniquing for the LayoutConstraintInfo.
void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, Kind, SizeInBits, Alignment);
}
static void Profile(llvm::FoldingSetNodeID &ID,
LayoutConstraintKind Kind,
unsigned SizeInBits,
unsigned Alignment);
private:
// Make vanilla new/delete illegal for LayoutConstraintInfo.
void *operator new(size_t Bytes) throw() = delete;
void operator delete(void *Data) throw() = delete;
public:
// Only allow allocation of LayoutConstraintInfo using the allocator in
// ASTContext or by doing a placement new.
void *operator new(size_t bytes, const ASTContext &ctx,
AllocationArena arena, unsigned alignment = 8);
void *operator new(size_t Bytes, void *Mem) throw() { return Mem; }
// Representation of the non-parameterized layouts.
static LayoutConstraintInfo UnknownLayoutConstraintInfo;
static LayoutConstraintInfo RefCountedObjectConstraintInfo;
static LayoutConstraintInfo NativeRefCountedObjectConstraintInfo;
static LayoutConstraintInfo ClassConstraintInfo;
static LayoutConstraintInfo NativeClassConstraintInfo;
static LayoutConstraintInfo TrivialConstraintInfo;
};
/// A wrapper class containing a reference to the actual LayoutConstraintInfo
/// object.
class LayoutConstraint {
LayoutConstraintInfo *Ptr;
public:
/*implicit*/ LayoutConstraint(LayoutConstraintInfo *P = 0) : Ptr(P) {}
static LayoutConstraint getLayoutConstraint(const LayoutConstraint &Layout,
ASTContext &C);
static LayoutConstraint getLayoutConstraint(LayoutConstraintKind Kind,
ASTContext &C);
static LayoutConstraint getLayoutConstraint(LayoutConstraintKind Kind);
static LayoutConstraint getLayoutConstraint(LayoutConstraintKind Kind,
unsigned SizeInBits,
unsigned Alignment,
ASTContext &C);
static LayoutConstraint getUnknownLayout();
LayoutConstraintInfo *getPointer() const { return Ptr; }
bool isNull() const { return Ptr == 0; }
LayoutConstraintInfo *operator->() const { return Ptr; }
/// Merge these two constraints and return a more specific one
/// or fail if they're incompatible and return an unknown constraint.
LayoutConstraint merge(LayoutConstraint Other);
explicit operator bool() const { return Ptr != 0; }
SWIFT_DEBUG_DUMP;
void dump(raw_ostream &os, unsigned indent = 0) const;
void print(raw_ostream &OS, const PrintOptions &PO = PrintOptions()) const;
void print(ASTPrinter &Printer, const PrintOptions &PO) const;
/// Return the layout constraint as a string, for use in diagnostics only.
std::string getString(const PrintOptions &PO = PrintOptions()) const;
friend llvm::hash_code hash_value(const LayoutConstraint &layout) {
return hash_value(layout.getPointer());
}
bool operator==(LayoutConstraint rhs) const {
if (isNull() && rhs.isNull())
return true;
return *getPointer() == *rhs.getPointer();
}
bool operator!=(LayoutConstraint rhs) const {
return !(*this == rhs);
}
};
// Permit direct uses of isa/cast/dyn_cast on LayoutConstraint.
template <class X> inline bool isa(LayoutConstraint LC) {
return isa<X>(LC.getPointer());
}
template <class X> inline X cast_or_null(LayoutConstraint LC) {
return cast_or_null<X>(LC.getPointer());
}
template <class X> inline X dyn_cast(LayoutConstraint LC) {
return dyn_cast<X>(LC.getPointer());
}
template <class X> inline X dyn_cast_or_null(LayoutConstraint LC) {
return dyn_cast_or_null<X>(LC.getPointer());
}
/// LayoutConstraintLoc - Provides source location information for a
/// parsed layout constraint.
struct LayoutConstraintLoc {
private:
LayoutConstraint Layout;
SourceLoc Loc;
public:
LayoutConstraintLoc(LayoutConstraint Layout, SourceLoc Loc)
: Layout(Layout), Loc(Loc) {}
bool isError() const;
// FIXME: We generally shouldn't need to build LayoutConstraintLoc without
// a location.
static LayoutConstraintLoc withoutLoc(LayoutConstraint Layout) {
return LayoutConstraintLoc(Layout, SourceLoc());
}
/// Get the representative location of this type, for diagnostic
/// purposes.
SourceLoc getLoc() const { return Loc; }
SourceRange getSourceRange() const;
bool hasLocation() const { return Loc.isValid(); }
LayoutConstraint getLayoutConstraint() const { return Layout; }
void setLayoutConstraint(LayoutConstraint value) {
Layout = value;
}
bool isNull() const { return Layout.isNull(); }
LayoutConstraintLoc clone(ASTContext &ctx) const { return *this; }
};
/// Checks if ID is a name of a layout constraint and returns this
/// constraint. If ID does not match any known layout constraint names,
/// returns UnknownLayout.
LayoutConstraint getLayoutConstraint(Identifier ID, ASTContext &Ctx);
} // end namespace swift
LLVM_DECLARE_TYPE_ALIGNMENT(swift::LayoutConstraintInfo, swift::TypeAlignInBits)
namespace llvm {
static inline raw_ostream &
operator<<(raw_ostream &OS, swift::LayoutConstraint LC) {
LC->print(OS);
return OS;
}
// A LayoutConstraint casts like a LayoutConstraintInfo*.
template <> struct simplify_type<const ::swift::LayoutConstraint> {
typedef ::swift::LayoutConstraintInfo *SimpleType;
static SimpleType getSimplifiedValue(const ::swift::LayoutConstraint &Val) {
return Val.getPointer();
}
};
template <>
struct simplify_type<::swift::LayoutConstraint>
: public simplify_type<const ::swift::LayoutConstraint> {};
// LayoutConstraint hashes just like pointers.
template <> struct DenseMapInfo<swift::LayoutConstraint> {
static swift::LayoutConstraint getEmptyKey() {
return llvm::DenseMapInfo<swift::LayoutConstraintInfo *>::getEmptyKey();
}
static swift::LayoutConstraint getTombstoneKey() {
return llvm::DenseMapInfo<swift::LayoutConstraintInfo *>::getTombstoneKey();
}
static unsigned getHashValue(swift::LayoutConstraint Val) {
return DenseMapInfo<swift::LayoutConstraintInfo *>::getHashValue(
Val.getPointer());
}
static bool isEqual(swift::LayoutConstraint LHS,
swift::LayoutConstraint RHS) {
return LHS.getPointer() == RHS.getPointer();
}
};
// A LayoutConstraint is "pointer like".
template <> struct PointerLikeTypeTraits<swift::LayoutConstraint> {
public:
static inline void *getAsVoidPointer(swift::LayoutConstraint I) {
return (void *)I.getPointer();
}
static inline swift::LayoutConstraint getFromVoidPointer(void *P) {
return (swift::LayoutConstraintInfo *)P;
}
enum { NumLowBitsAvailable = swift::TypeAlignInBits };
};
} // end namespace llvm
#endif