blob: e378588d0120b65aa995310c9e292d1d27191ad1 [file] [log] [blame]
//===--- ValueWitness.h - Enumeration of value witnesses --------*- 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 the list of witnesses required to attest that a
// type is a value type.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_IRGEN_VALUEWITNESS_H
#define SWIFT_IRGEN_VALUEWITNESS_H
namespace swift {
namespace irgen {
/// The members required to attest that a type is a value type.
///
/// Logically, there are three basic data operations we must support
/// on arbitrary types:
/// - initializing an object by copying another
/// - changing an object to be a copy of another
/// - destroying an object
///
/// As an optimization to permit efficient transfers of data, the
/// "copy" operations each have an analogous "take" operation which
/// implicitly destroys the source object.
///
/// Therefore there are five basic data operations:
/// initWithCopy(T*, T*)
/// initWithTake(T*, T*)
/// assignWithCopy(T*, T*)
/// assignWithTake(T*, T*)
/// destroy(T*)
///
/// As a further optimization, for every T*, there is a related
/// operation which replaces that T* with a B*, combinatorially. This
/// makes 18 operations, except that some of these operations are
/// fairly unlikely and so do not merit optimized entries, due to
/// the common code patterns of the two use cases:
/// - Existential code usually doesn't work directly with T*s
/// because pointers into existential objects are not generally
/// reliable.
/// - Generic code works with T*s a fair amount, but it usually
/// doesn't have to deal with B*s after initialization
/// because initialization returns a reliable pointer.
/// This leads us to the following conclusions:
// - Operations to copy a B* to a T* are very unlikely
/// to be used (-4 operations).
/// - Assignments involving two B*s are only likely in
/// existential code, where we won't have the right
/// typing guarantees to use them (-2 operations).
/// Furthermore, take-initializing a buffer from a buffer is just a
/// memcpy of the buffer (-1), and take-assigning a buffer from a
/// buffer is just a destroy and a memcpy (-1).
///
/// This leaves us with 12 data operations, to which we add the
/// meta-operation 'sizeAndAlign' for a total of 13.
enum class ValueWitness : unsigned {
#define WANT_ALL_VALUE_WITNESSES
#define VALUE_WITNESS(lowerId, upperId) upperId,
#define BEGIN_VALUE_WITNESS_RANGE(rangeId, upperId) First_##rangeId = upperId,
#define END_VALUE_WITNESS_RANGE(rangeId, upperId) Last_##rangeId = upperId,
#include "swift/ABI/ValueWitness.def"
};
enum {
NumRequiredValueWitnesses
= unsigned(ValueWitness::Last_RequiredValueWitness) + 1,
NumRequiredValueWitnessFunctions
= unsigned(ValueWitness::Last_RequiredValueWitnessFunction) + 1,
MaxNumValueWitnesses
= unsigned(ValueWitness::Last_ValueWitness) + 1,
MaxNumTypeLayoutWitnesses
= unsigned(ValueWitness::Last_TypeLayoutWitness)
- unsigned(ValueWitness::First_TypeLayoutWitness)
+ 1,
};
static inline bool isValueWitnessFunction(ValueWitness witness) {
#define WANT_ALL_VALUE_WITNESSES 1
#define FUNCTION_VALUE_WITNESS(name, Name, ret, args) \
if (witness == ValueWitness::Name) \
return true;
#define DATA_VALUE_WITNESS(name, Name, ty)
#include "swift/ABI/ValueWitness.def"
return false;
}
const char *getValueWitnessName(ValueWitness witness);
} // end namespace irgen
} // end namespace swift
#endif