Skip to content

Add a runtime interface for working with Builtin.IntegerLiteral values #20177

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 31, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions include/swift/ABI/MetadataValues.h
Original file line number Diff line number Diff line change
Expand Up @@ -1674,6 +1674,40 @@ class MetadataRequest : public FlagSet<size_t> {
}
};

/// Flags for Builtin.IntegerLiteral values.
class IntegerLiteralFlags {
public:
enum : size_t {
IsNegativeFlag = 0x1,

// Save some space for other flags.

BitWidthShift = 8,
};

private:
size_t Data;

explicit IntegerLiteralFlags(size_t data) : Data(data) {}

public:
constexpr IntegerLiteralFlags(size_t bitWidth, bool isNegative)
: Data((bitWidth << BitWidthShift)
| (isNegative ? IsNegativeFlag : 0)) {}

/// Return true if the value is negative.
bool isNegative() const { return Data & IsNegativeFlag; }

/// Return the minimum number of bits necessary to store the value in
/// two's complement, including a leading sign bit.
unsigned getBitWidth() const { return Data >> BitWidthShift; }

size_t getOpaqueValue() const { return Data; }
static IntegerLiteralFlags getFromOpaqueValue(size_t value) {
return IntegerLiteralFlags(value);
}
};

} // end namespace swift

#endif /* SWIFT_ABI_METADATAVALUES_H */
75 changes: 75 additions & 0 deletions include/swift/Runtime/Numeric.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//===--- Numeric.h - Swift Language ABI numerics support --------*- 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
//
//===----------------------------------------------------------------------===//
//
// Swift runtime support for numeric operations.
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_RUNTIME_NUMERIC_H
#define SWIFT_RUNTIME_NUMERIC_H

#include "swift/ABI/MetadataValues.h"
#include "swift/Runtime/Config.h"
#include "swift/Basic/LLVM.h"
#include "llvm/ADT/ArrayRef.h"

namespace swift {

/// A constant integer literal. The format is designed to optimize the
/// checked-truncation operation typically performed by conformances to the
/// ExpressibleByBuiltinIntegerLiteral protocol.
class IntegerLiteral {
public:
using SignedChunk = intptr_t;
using UnsignedChunk = uintptr_t;
enum : size_t { BitsPerChunk = sizeof(SignedChunk) * 8 };

private:
const UnsignedChunk *Data;
IntegerLiteralFlags Flags;

public:
constexpr IntegerLiteral(const UnsignedChunk *data, IntegerLiteralFlags flags)
: Data(data), Flags(flags) {}

/// Return the chunks of data making up this value, arranged starting from
/// the least-significant chunk. The value is sign-extended to fill the
/// final chunk.
ArrayRef<UnsignedChunk> getData() const {
return ArrayRef<UnsignedChunk>(Data,
(Flags.getBitWidth() + BitsPerChunk - 1) / BitsPerChunk);
}

/// The flags for this value.
IntegerLiteralFlags getFlags() const { return Flags; }

/// Whether this value is negative.
bool isNegative() const { return Flags.isNegative(); }

/// The minimum number of bits necessary to store this value.
/// Because this always includes the sign bit, it is never zero.
size_t getBitWidth() const { return Flags.getBitWidth(); }
};

SWIFT_RUNTIME_EXPORT SWIFT_CC(swift)
float swift_intToFloat32(IntegerLiteral value);

SWIFT_RUNTIME_EXPORT SWIFT_CC(swift)
double swift_intToFloat64(IntegerLiteral value);

// TODO: Float16 instead of just truncating from float?
// TODO: Float80 on x86?
// TODO: Float128 on targets that provide it?

}

#endif
10 changes: 10 additions & 0 deletions include/swift/Runtime/RuntimeFunctions.def
Original file line number Diff line number Diff line change
Expand Up @@ -1247,6 +1247,16 @@ FUNCTION(VerifyTypeLayoutAttribute, _swift_debug_verifyTypeLayoutAttribute,
ARGS(TypeMetadataPtrTy, Int8PtrTy, Int8PtrTy, SizeTy, Int8PtrTy),
ATTRS(NoUnwind))

// float swift_intToFloat32(const size_t *data, IntegerLiteralFlags flags);
FUNCTION(IntToFloat32, swift_intToFloat32, SwiftCC,
RETURNS(FloatTy),
ARGS(SizeTy->getPointerTo(), SizeTy),
ATTRS(NoUnwind, ReadOnly))
FUNCTION(IntToFloat64, swift_intToFloat64, SwiftCC,
RETURNS(DoubleTy),
ARGS(SizeTy->getPointerTo(), SizeTy),
ATTRS(NoUnwind, ReadOnly))

#undef RETURNS
#undef ARGS
#undef ATTRS
Expand Down
3 changes: 3 additions & 0 deletions lib/IRGen/IRGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,9 @@ IRGenModule::IRGenModule(IRGenerator &irgen,
Int8PtrPtrTy = Int8PtrTy->getPointerTo(0);
SizeTy = DataLayout.getIntPtrType(getLLVMContext(), /*addrspace*/ 0);

FloatTy = llvm::Type::getFloatTy(getLLVMContext());
DoubleTy = llvm::Type::getDoubleTy(getLLVMContext());

auto CI = static_cast<ClangImporter*>(&*Context.getClangModuleLoader());
assert(CI && "no clang module loader");
auto &clangASTContext = CI->getClangASTContext();
Expand Down
2 changes: 2 additions & 0 deletions lib/IRGen/IRGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,8 @@ class IRGenModule {
llvm::StructType *OpenedErrorTripleTy; /// { %swift.opaque*, %swift.type*, i8** }
llvm::PointerType *OpenedErrorTriplePtrTy; /// { %swift.opaque*, %swift.type*, i8** }*
llvm::PointerType *WitnessTablePtrPtrTy; /// i8***
llvm::Type *FloatTy;
llvm::Type *DoubleTy;

llvm::GlobalVariable *TheTrivialPropertyDescriptor = nullptr;

Expand Down
1 change: 1 addition & 0 deletions stdlib/public/runtime/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ set(swift_runtime_sources
MetadataLookup.cpp
MutexPThread.cpp
MutexWin32.cpp
Numeric.cpp
Once.cpp
Portability.cpp
ProtocolConformance.cpp
Expand Down
59 changes: 59 additions & 0 deletions stdlib/public/runtime/Numeric.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
//===--- Numeric.cpp - Swift Language ABI numerics 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 numeric-support ABI functions.
//
//===----------------------------------------------------------------------===//

#include "swift/Runtime/Numeric.h"

using namespace swift;

/// Convert an integer literal to the floating-point type T.
template <class T>
static T convert(IntegerLiteral value) {
using SignedChunk = IntegerLiteral::SignedChunk;
using UnsignedChunk = IntegerLiteral::UnsignedChunk;

auto data = value.getData();
assert(!data.empty() && "always require at least one chunk");

// The single-word case is the easiest.
if (data.size() == 1) {
return T(SignedChunk(data[0]));
}

// In two's complement, only the topmost chunk is really signed;
// everything else is added to that as an unsigned value.
static_assert(IntegerLiteral::BitsPerChunk == 32 ||
IntegerLiteral::BitsPerChunk == 64,
"expected either 32-bit or 64-bit chunking");
T chunkFactor = (IntegerLiteral::BitsPerChunk == 32 ? 0x1p32 : 0x1p64);

T result = UnsignedChunk(data[0]);
T scale = chunkFactor;
for (size_t i = 1, e = data.size() - 1; i != e; ++i) {
result += UnsignedChunk(data[i]) * scale;
scale *= chunkFactor;
}
result += SignedChunk(data.back()) * scale;

return result;
}

float swift::swift_intToFloat32(IntegerLiteral value) {
return convert<float>(value);
}

double swift::swift_intToFloat64(IntegerLiteral value) {
return convert<double>(value);
}