Skip to content

Commit 0bb8845

Browse files
committed
Add a runtime interface for working with Builtin.IntegerLiteral values.
1 parent 4381735 commit 0bb8845

File tree

7 files changed

+184
-0
lines changed

7 files changed

+184
-0
lines changed

include/swift/ABI/MetadataValues.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1674,6 +1674,40 @@ class MetadataRequest : public FlagSet<size_t> {
16741674
}
16751675
};
16761676

1677+
/// Flags for Builtin.IntegerLiteral values.
1678+
class IntegerLiteralFlags {
1679+
public:
1680+
enum : size_t {
1681+
IsNegativeFlag = 0x1,
1682+
1683+
// Save some space for other flags.
1684+
1685+
BitWidthShift = 8,
1686+
};
1687+
1688+
private:
1689+
size_t Data;
1690+
1691+
explicit IntegerLiteralFlags(size_t data) : Data(data) {}
1692+
1693+
public:
1694+
constexpr IntegerLiteralFlags(size_t bitWidth, bool isNegative)
1695+
: Data((bitWidth << BitWidthShift)
1696+
| (isNegative ? IsNegativeFlag : 0)) {}
1697+
1698+
/// Return true if the value is negative.
1699+
bool isNegative() const { return Data & IsNegativeFlag; }
1700+
1701+
/// Return the minimum number of bits necessary to store the value in
1702+
/// two's complement, including a leading sign bit.
1703+
unsigned getBitWidth() const { return Data >> BitWidthShift; }
1704+
1705+
size_t getOpaqueValue() const { return Data; }
1706+
static IntegerLiteralFlags getFromOpaqueValue(size_t value) {
1707+
return IntegerLiteralFlags(value);
1708+
}
1709+
};
1710+
16771711
} // end namespace swift
16781712

16791713
#endif /* SWIFT_ABI_METADATAVALUES_H */

include/swift/Runtime/Numeric.h

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
//===--- Numeric.h - Swift Language ABI numerics support --------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// Swift runtime support for numeric operations.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_RUNTIME_NUMERIC_H
18+
#define SWIFT_RUNTIME_NUMERIC_H
19+
20+
#include "swift/ABI/MetadataValues.h"
21+
#include "swift/Runtime/Config.h"
22+
#include "swift/Basic/LLVM.h"
23+
#include "llvm/ADT/ArrayRef.h"
24+
25+
namespace swift {
26+
27+
/// A constant integer literal. The format is designed to optimize the
28+
/// checked-truncation operation typically performed by conformances to the
29+
/// ExpressibleByBuiltinIntegerLiteral protocol.
30+
class IntegerLiteral {
31+
public:
32+
using SignedChunk = intptr_t;
33+
using UnsignedChunk = uintptr_t;
34+
enum : size_t { BitsPerChunk = sizeof(SignedChunk) * 8 };
35+
36+
private:
37+
const UnsignedChunk *Data;
38+
IntegerLiteralFlags Flags;
39+
40+
public:
41+
constexpr IntegerLiteral(const UnsignedChunk *data, IntegerLiteralFlags flags)
42+
: Data(data), Flags(flags) {}
43+
44+
/// Return the chunks of data making up this value, arranged starting from
45+
/// the least-significant chunk. The value is sign-extended to fill the
46+
/// final chunk.
47+
ArrayRef<UnsignedChunk> getData() const {
48+
return ArrayRef<UnsignedChunk>(Data,
49+
(Flags.getBitWidth() + BitsPerChunk - 1) / BitsPerChunk);
50+
}
51+
52+
/// The flags for this value.
53+
IntegerLiteralFlags getFlags() const { return Flags; }
54+
55+
/// Whether this value is negative.
56+
bool isNegative() const { return Flags.isNegative(); }
57+
58+
/// The minimum number of bits necessary to store this value.
59+
/// Because this always includes the sign bit, it is never zero.
60+
size_t getBitWidth() const { return Flags.getBitWidth(); }
61+
};
62+
63+
SWIFT_RUNTIME_EXPORT SWIFT_CC(swift)
64+
float swift_intToFloat32(IntegerLiteral value);
65+
66+
SWIFT_RUNTIME_EXPORT SWIFT_CC(swift)
67+
double swift_intToFloat64(IntegerLiteral value);
68+
69+
// TODO: Float16 instead of just truncating from float?
70+
// TODO: Float80 on x86?
71+
// TODO: Float128 on targets that provide it?
72+
73+
}
74+
75+
#endif

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1247,6 +1247,16 @@ FUNCTION(VerifyTypeLayoutAttribute, _swift_debug_verifyTypeLayoutAttribute,
12471247
ARGS(TypeMetadataPtrTy, Int8PtrTy, Int8PtrTy, SizeTy, Int8PtrTy),
12481248
ATTRS(NoUnwind))
12491249

1250+
// float swift_intToFloat32(const size_t *data, IntegerLiteralFlags flags);
1251+
FUNCTION(IntToFloat32, swift_intToFloat32, SwiftCC,
1252+
RETURNS(FloatTy),
1253+
ARGS(SizeTy->getPointerTo(), SizeTy),
1254+
ATTRS(NoUnwind, ReadOnly))
1255+
FUNCTION(IntToFloat64, swift_intToFloat64, SwiftCC,
1256+
RETURNS(DoubleTy),
1257+
ARGS(SizeTy->getPointerTo(), SizeTy),
1258+
ATTRS(NoUnwind, ReadOnly))
1259+
12501260
#undef RETURNS
12511261
#undef ARGS
12521262
#undef ATTRS

lib/IRGen/IRGenModule.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,9 @@ IRGenModule::IRGenModule(IRGenerator &irgen,
167167
Int8PtrPtrTy = Int8PtrTy->getPointerTo(0);
168168
SizeTy = DataLayout.getIntPtrType(getLLVMContext(), /*addrspace*/ 0);
169169

170+
FloatTy = llvm::Type::getFloatTy(getLLVMContext());
171+
DoubleTy = llvm::Type::getDoubleTy(getLLVMContext());
172+
170173
auto CI = static_cast<ClangImporter*>(&*Context.getClangModuleLoader());
171174
assert(CI && "no clang module loader");
172175
auto &clangASTContext = CI->getClangASTContext();

lib/IRGen/IRGenModule.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,8 @@ class IRGenModule {
636636
llvm::StructType *OpenedErrorTripleTy; /// { %swift.opaque*, %swift.type*, i8** }
637637
llvm::PointerType *OpenedErrorTriplePtrTy; /// { %swift.opaque*, %swift.type*, i8** }*
638638
llvm::PointerType *WitnessTablePtrPtrTy; /// i8***
639+
llvm::Type *FloatTy;
640+
llvm::Type *DoubleTy;
639641

640642
llvm::GlobalVariable *TheTrivialPropertyDescriptor = nullptr;
641643

stdlib/public/runtime/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ set(swift_runtime_sources
6262
MetadataLookup.cpp
6363
MutexPThread.cpp
6464
MutexWin32.cpp
65+
Numeric.cpp
6566
Once.cpp
6667
Portability.cpp
6768
ProtocolConformance.cpp

stdlib/public/runtime/Numeric.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
//===--- Numeric.cpp - Swift Language ABI numerics support ----------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// Implementations of the numeric-support ABI functions.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#include "swift/Runtime/Numeric.h"
18+
19+
using namespace swift;
20+
21+
/// Convert an integer literal to the floating-point type T.
22+
template <class T>
23+
static T convert(IntegerLiteral value) {
24+
using SignedChunk = IntegerLiteral::SignedChunk;
25+
using UnsignedChunk = IntegerLiteral::UnsignedChunk;
26+
27+
auto data = value.getData();
28+
assert(!data.empty() && "always require at least one chunk");
29+
30+
// The single-word case is the easiest.
31+
if (data.size() == 1) {
32+
return T(SignedChunk(data[0]));
33+
}
34+
35+
// In two's complement, only the topmost chunk is really signed;
36+
// everything else is added to that as an unsigned value.
37+
static_assert(IntegerLiteral::BitsPerChunk == 32 ||
38+
IntegerLiteral::BitsPerChunk == 64,
39+
"expected either 32-bit or 64-bit chunking");
40+
T chunkFactor = (IntegerLiteral::BitsPerChunk == 32 ? 0x1p32 : 0x1p64);
41+
42+
T result = UnsignedChunk(data[0]);
43+
T scale = chunkFactor;
44+
for (size_t i = 1, e = data.size() - 1; i != e; ++i) {
45+
result += UnsignedChunk(data[i]) * scale;
46+
scale *= chunkFactor;
47+
}
48+
result += SignedChunk(data.back()) * scale;
49+
50+
return result;
51+
}
52+
53+
float swift::swift_intToFloat32(IntegerLiteral value) {
54+
return convert<float>(value);
55+
}
56+
57+
double swift::swift_intToFloat64(IntegerLiteral value) {
58+
return convert<double>(value);
59+
}

0 commit comments

Comments
 (0)