mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
And add builtins for the added runtime functions (assign-take, assign-copy). rdar://27412867 SR-3376
220 lines
7.1 KiB
C++
220 lines
7.1 KiB
C++
//===------------- Array.cpp - Swift Array Operations Support -------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Implementations of the array runtime functions.
|
|
//
|
|
// arrayInitWithCopy(T *dest, T *src, size_t count, M* self)
|
|
// arrayInitWithTake(NoAlias|FrontToBack|BackToFront)(T *dest, T *src,
|
|
// size_t count, M* self)
|
|
// arrayAssignWithCopy(NoAlias|FrontToBack|BackToFront)(T *dest, T *src,
|
|
// size_t count, M* self)
|
|
// arrayAssignWithTake(T *dest, T *src, size_t count, M* self)
|
|
// arrayDestroy(T *dst, size_t count, M* self)
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "swift/Runtime/Config.h"
|
|
#include "swift/Runtime/HeapObject.h"
|
|
#include "swift/Runtime/Metadata.h"
|
|
|
|
using namespace swift;
|
|
|
|
namespace {
|
|
enum class ArrayCopy : unsigned {
|
|
NoAlias = 0,
|
|
FrontToBack = 1,
|
|
BackToFront = 2
|
|
};
|
|
|
|
enum class ArraySource {
|
|
Copy,
|
|
Take
|
|
};
|
|
|
|
enum class ArrayDest {
|
|
Init,
|
|
Assign
|
|
};
|
|
} // end anonymous namespace.
|
|
|
|
static void array_pod_copy(ArrayCopy copyKind, OpaqueValue *dest,
|
|
OpaqueValue *src, size_t stride, size_t count) {
|
|
if (copyKind == ArrayCopy::NoAlias) {
|
|
memcpy(dest, src, stride * count);
|
|
return;
|
|
}
|
|
|
|
assert(copyKind == ArrayCopy::FrontToBack ||
|
|
copyKind == ArrayCopy::BackToFront);
|
|
memmove(dest, src, stride * count);
|
|
}
|
|
|
|
namespace {
|
|
typedef OpaqueValue *(*const WitnessFunction)(OpaqueValue *, OpaqueValue *,
|
|
const Metadata *);
|
|
}
|
|
|
|
template <ArrayDest destOp, ArraySource srcOp>
|
|
static WitnessFunction get_witness_function(const ValueWitnessTable *wtable) {
|
|
if (destOp == ArrayDest::Init) {
|
|
if (srcOp == ArraySource::Copy)
|
|
return wtable->initializeWithCopy;
|
|
else {
|
|
assert(srcOp == ArraySource::Take);
|
|
return wtable->initializeWithTake;
|
|
}
|
|
} else {
|
|
assert(destOp == ArrayDest::Assign);
|
|
if (srcOp == ArraySource::Copy) {
|
|
return wtable->assignWithCopy;
|
|
} else {
|
|
assert(srcOp == ArraySource::Take);
|
|
return wtable->assignWithTake;
|
|
}
|
|
}
|
|
}
|
|
template <ArrayDest destOp, ArraySource srcOp, ArrayCopy copyKind>
|
|
static void array_copy_operation(OpaqueValue *dest, OpaqueValue *src,
|
|
size_t count, const Metadata *self) {
|
|
if (count == 0)
|
|
return;
|
|
|
|
auto wtable = self->getValueWitnesses();
|
|
auto stride = wtable->getStride();
|
|
|
|
// If we are doing a copy we need PODness for a memcpy.
|
|
if (srcOp == ArraySource::Copy) {
|
|
auto isPOD = wtable->isPOD();
|
|
if (isPOD) {
|
|
array_pod_copy(copyKind, dest, src, stride, count);
|
|
return;
|
|
}
|
|
} else {
|
|
// Otherwise, we are doing a take and need bitwise takability for a copy.
|
|
assert(srcOp == ArraySource::Take);
|
|
auto isBitwiseTakable = wtable->isBitwiseTakable();
|
|
if (isBitwiseTakable && (destOp == ArrayDest::Init || wtable->isPOD())) {
|
|
array_pod_copy(copyKind, dest, src, stride, count);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Call the witness to do the copy.
|
|
if (copyKind == ArrayCopy::NoAlias || copyKind == ArrayCopy::FrontToBack) {
|
|
auto copy = get_witness_function<destOp, srcOp>(wtable);
|
|
for (size_t i = 0; i < count; ++i) {
|
|
auto offset = i * stride;
|
|
auto *from = reinterpret_cast<OpaqueValue *>((char *)src + offset);
|
|
auto *to = reinterpret_cast<OpaqueValue *>((char *)dest + offset);
|
|
copy(to, from, self);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Back-to-front copy.
|
|
assert(copyKind == ArrayCopy::BackToFront);
|
|
assert(count != 0);
|
|
|
|
auto copy = get_witness_function<destOp, srcOp>(wtable);
|
|
size_t i = count;
|
|
do {
|
|
auto offset = --i * stride;
|
|
auto *from = reinterpret_cast<OpaqueValue *>((char *)src + offset);
|
|
auto *to = reinterpret_cast<OpaqueValue *>((char *)dest + offset);
|
|
copy(to, from, self);
|
|
} while (i != 0);
|
|
}
|
|
|
|
SWIFT_CC(c)
|
|
SWIFT_RUNTIME_EXPORT
|
|
void swift_arrayInitWithCopy(OpaqueValue *dest, OpaqueValue *src, size_t count,
|
|
const Metadata *self) {
|
|
array_copy_operation<ArrayDest::Init, ArraySource::Copy, ArrayCopy::NoAlias>(
|
|
dest, src, count, self);
|
|
}
|
|
|
|
SWIFT_CC(c)
|
|
SWIFT_RUNTIME_EXPORT
|
|
void swift_arrayInitWithTakeNoAlias(OpaqueValue *dest, OpaqueValue *src,
|
|
size_t count, const Metadata *self) {
|
|
array_copy_operation<ArrayDest::Init, ArraySource::Take, ArrayCopy::NoAlias>(
|
|
dest, src, count, self);
|
|
}
|
|
|
|
SWIFT_CC(c)
|
|
SWIFT_RUNTIME_EXPORT
|
|
void swift_arrayInitWithTakeFrontToBack(OpaqueValue *dest, OpaqueValue *src,
|
|
size_t count, const Metadata *self) {
|
|
array_copy_operation<ArrayDest::Init, ArraySource::Take,
|
|
ArrayCopy::FrontToBack>(dest, src, count, self);
|
|
}
|
|
|
|
SWIFT_CC(c)
|
|
SWIFT_RUNTIME_EXPORT
|
|
void swift_arrayInitWithTakeBackToFront(OpaqueValue *dest, OpaqueValue *src,
|
|
size_t count, const Metadata *self) {
|
|
array_copy_operation<ArrayDest::Init, ArraySource::Take,
|
|
ArrayCopy::BackToFront>(dest, src, count, self);
|
|
}
|
|
|
|
SWIFT_CC(c)
|
|
SWIFT_RUNTIME_EXPORT
|
|
void swift_arrayAssignWithCopyNoAlias(OpaqueValue *dest, OpaqueValue *src,
|
|
size_t count, const Metadata *self) {
|
|
array_copy_operation<ArrayDest::Assign, ArraySource::Copy,
|
|
ArrayCopy::NoAlias>(dest, src, count, self);
|
|
}
|
|
|
|
SWIFT_CC(c)
|
|
SWIFT_RUNTIME_EXPORT
|
|
void swift_arrayAssignWithCopyFrontToBack(OpaqueValue *dest, OpaqueValue *src,
|
|
size_t count, const Metadata *self) {
|
|
array_copy_operation<ArrayDest::Assign, ArraySource::Copy,
|
|
ArrayCopy::FrontToBack>(dest, src, count, self);
|
|
}
|
|
|
|
SWIFT_CC(c)
|
|
SWIFT_RUNTIME_EXPORT
|
|
void swift_arrayAssignWithCopyBackToFront(OpaqueValue *dest, OpaqueValue *src,
|
|
size_t count, const Metadata *self) {
|
|
array_copy_operation<ArrayDest::Assign, ArraySource::Copy,
|
|
ArrayCopy::BackToFront>(dest, src, count, self);
|
|
}
|
|
|
|
SWIFT_CC(c)
|
|
SWIFT_RUNTIME_EXPORT
|
|
void swift_arrayAssignWithTake(OpaqueValue *dest, OpaqueValue *src,
|
|
size_t count, const Metadata *self) {
|
|
array_copy_operation<ArrayDest::Assign, ArraySource::Take,
|
|
ArrayCopy::NoAlias>(dest, src, count, self);
|
|
}
|
|
|
|
SWIFT_CC(c)
|
|
SWIFT_RUNTIME_EXPORT
|
|
void swift_arrayDestroy(OpaqueValue *begin, size_t count, const Metadata *self) {
|
|
if (count == 0)
|
|
return;
|
|
|
|
auto wtable = self->getValueWitnesses();
|
|
|
|
// Nothing to do if the type is POD.
|
|
if (wtable->isPOD())
|
|
return;
|
|
|
|
auto stride = wtable->getStride();
|
|
for (size_t i = 0; i < count; ++i) {
|
|
auto offset = i * stride;
|
|
auto *obj = reinterpret_cast<OpaqueValue *>((char *)begin + offset);
|
|
wtable->destroy(obj, self);
|
|
}
|
|
}
|