Skip to content

Commit 50df679

Browse files
Merge pull request #3 from SomeRandomiOSDev/LinuxSupport
Added support for Linux
2 parents 5f87bfc + 58e5599 commit 50df679

File tree

12 files changed

+690
-10
lines changed

12 files changed

+690
-10
lines changed

.github/workflows/swift.yml

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,28 @@
1-
name: Swift
1+
name: Test
22

3-
on: [push]
3+
on: [push, pull_request]
44

55
jobs:
66
build:
7-
8-
runs-on: macOS-latest
9-
7+
strategy:
8+
matrix:
9+
os: [macOS-latest, ubuntu-latest]
10+
swift: ["5.1"]
11+
runs-on: ${{ matrix.os }}
12+
env:
13+
SWIFT_VERSION: ${{ matrix.swift }}
14+
SWIFT_EXEC: .swiftenv/shims/swift
1015
steps:
1116
- uses: actions/checkout@v2
17+
- name: Install Swift
18+
run: |
19+
git clone https://github.com/kylef/swiftenv.git ~/.swiftenv
20+
~/.swiftenv/bin/swiftenv install $SWIFT_VERSION --skip-existing
21+
~/.swiftenv/bin/swiftenv rehash
1222
- name: Build
13-
run: swift build -v
14-
- name: Run Tests
15-
run: swift test -v
23+
run: |
24+
~/$SWIFT_EXEC --version
25+
~/$SWIFT_EXEC build -v
26+
- name: Test
27+
run: |
28+
~/$SWIFT_EXEC test -v

.swiftlint.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ opt_in_rules:
5757

5858
reporter: "xcode"
5959

60+
excluded:
61+
- Tests/LinuxMain.swift
62+
- Tests/HalfTests/XCTestManifests.swift
63+
- Tests/CHalfTests/XCTestManifests.swift
64+
6065
identifier_name:
6166
excluded:
6267
- pi

ATTRIBUTIONS

Lines changed: 317 additions & 0 deletions
Large diffs are not rendered by default.

Half.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ Pod::Spec.new do |s|
1919
s.source = { :git => "https://github.com/SomeRandomiOSDev/Half.git", :tag => s.version.to_s }
2020
s.source_files = 'Sources/**/*.{swift,h,c}'
2121
s.frameworks = 'Foundation'
22-
s.swift_versions = ['4.0', '4.2', '5.0']
22+
s.swift_versions = ['5.0']
2323
s.cocoapods_version = '>= 1.7.3'
2424

2525
end

Half.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@
9191

9292
/* Begin PBXFileReference section */
9393
DD6F08D124008A7400749359 /* codecov.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = codecov.yml; sourceTree = "<group>"; };
94+
DDB1DF3F240A25D900C20FED /* fp_extend.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = fp_extend.cpp; sourceTree = "<group>"; };
95+
DDB1DF40240A25D900C20FED /* fp_trunc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = fp_trunc.cpp; sourceTree = "<group>"; };
9496
DDB8120223F587890079FEB5 /* CHalfTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CHalfTests.swift; sourceTree = "<group>"; };
9597
DDFEEC3323EF13900096015C /* Half.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Half.framework; sourceTree = BUILT_PRODUCTS_DIR; };
9698
DDFEEC3723EF13900096015C /* Half-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "Half-Info.plist"; path = "Plists/Half-Info.plist"; sourceTree = "<group>"; };
@@ -292,6 +294,8 @@
292294
isa = PBXGroup;
293295
children = (
294296
DDFEED8223F345690096015C /* half.c */,
297+
DDB1DF3F240A25D900C20FED /* fp_extend.cpp */,
298+
DDB1DF40240A25D900C20FED /* fp_trunc.cpp */,
295299
);
296300
path = src;
297301
sourceTree = "<group>";

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,5 @@ let package = Package(
2323
.testTarget(name: "HalfTests", dependencies: ["Half"])
2424
],
2525

26-
swiftLanguageVersions: [.version("4"), .version("4.2"), .version("5")]
26+
swiftLanguageVersions: [.version("5")]
2727
)

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Half
55
[![CocoaPods Compatible](https://img.shields.io/cocoapods/v/Half.svg)](https://cocoapods.org/pods/Half)
66
[![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
77
[![Platform](https://img.shields.io/cocoapods/p/Half.svg)](https://cocoapods.org/pods/Half)
8+
![Linux](https://img.shields.io/badge/platform-linux-lightgrey)
89
[![Build](https://travis-ci.com/SomeRandomiOSDev/Half.svg?branch=master)](https://travis-ci.com/SomeRandomiOSDev/Half)
910
[![Code Coverage](https://codecov.io/gh/SomeRandomiOSDev/Half/branch/master/graph/badge.svg)](https://codecov.io/gh/SomeRandomiOSDev/Half)
1011
[![Codacy](https://api.codacy.com/project/badge/Grade/8ad52c117e4a46d9aa4699d22fc0bf49)](https://app.codacy.com/app/SomeRandomiOSDev/Half?utm_source=github.com&utm_medium=referral&utm_content=SomeRandomiOSDev/Half&utm_campaign=Badge_Grade_Dashboard)

Sources/CHalf/src/fp_extend.cpp

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
#if defined(__linux__)
2+
#include <limits.h>
3+
#include <stdint.h>
4+
5+
typedef uint16_t src_t;
6+
typedef uint16_t src_rep_t;
7+
#define SRC_REP_C UINT16_C
8+
static const int srcSigBits = 10;
9+
#define src_rep_t_clz __builtin_clz
10+
11+
typedef float dst_t;
12+
typedef uint32_t dst_rep_t;
13+
#define DST_REP_C UINT32_C
14+
static const int dstSigBits = 23;
15+
16+
// End of specialization parameters. Two helper routines for conversion to and
17+
// from the representation of floating-point data as integer values follow.
18+
19+
static __inline src_rep_t srcToRep(src_t x) {
20+
const union { src_t f; src_rep_t i; } rep = {.f = x};
21+
return rep.i;
22+
}
23+
24+
static __inline dst_t dstFromRep(dst_rep_t x) {
25+
const union { dst_t f; dst_rep_t i; } rep = {.i = x};
26+
return rep.f;
27+
}
28+
// End helper routines. Conversion implementation follows.
29+
30+
static __inline dst_t __extendXfYf2__(src_t a) {
31+
// Various constants whose values follow from the type parameters.
32+
// Any reasonable optimizer will fold and propagate all of these.
33+
const int srcBits = sizeof(src_t)*CHAR_BIT;
34+
const int srcExpBits = srcBits - srcSigBits - 1;
35+
const int srcInfExp = (1 << srcExpBits) - 1;
36+
const int srcExpBias = srcInfExp >> 1;
37+
38+
const src_rep_t srcMinNormal = SRC_REP_C(1) << srcSigBits;
39+
const src_rep_t srcInfinity = (src_rep_t)srcInfExp << srcSigBits;
40+
const src_rep_t srcSignMask = SRC_REP_C(1) << (srcSigBits + srcExpBits);
41+
const src_rep_t srcAbsMask = srcSignMask - 1;
42+
const src_rep_t srcQNaN = SRC_REP_C(1) << (srcSigBits - 1);
43+
const src_rep_t srcNaNCode = srcQNaN - 1;
44+
45+
const int dstBits = sizeof(dst_t)*CHAR_BIT;
46+
const int dstExpBits = dstBits - dstSigBits - 1;
47+
const int dstInfExp = (1 << dstExpBits) - 1;
48+
const int dstExpBias = dstInfExp >> 1;
49+
50+
const dst_rep_t dstMinNormal = DST_REP_C(1) << dstSigBits;
51+
52+
// Break a into a sign and representation of the absolute value
53+
const src_rep_t aRep = srcToRep(a);
54+
const src_rep_t aAbs = aRep & srcAbsMask;
55+
const src_rep_t sign = aRep & srcSignMask;
56+
dst_rep_t absResult;
57+
58+
// If sizeof(src_rep_t) < sizeof(int), the subtraction result is promoted
59+
// to (signed) int. To avoid that, explicitly cast to src_rep_t.
60+
if ((src_rep_t)(aAbs - srcMinNormal) < srcInfinity - srcMinNormal) {
61+
// a is a normal number.
62+
// Extend to the destination type by shifting the significand and
63+
// exponent into the proper position and rebiasing the exponent.
64+
absResult = (dst_rep_t)aAbs << (dstSigBits - srcSigBits);
65+
absResult += (dst_rep_t)(dstExpBias - srcExpBias) << dstSigBits;
66+
}
67+
68+
else if (aAbs >= srcInfinity) {
69+
// a is NaN or infinity.
70+
// Conjure the result by beginning with infinity, then setting the qNaN
71+
// bit (if needed) and right-aligning the rest of the trailing NaN
72+
// payload field.
73+
absResult = (dst_rep_t)dstInfExp << dstSigBits;
74+
absResult |= (dst_rep_t)(aAbs & srcQNaN) << (dstSigBits - srcSigBits);
75+
absResult |= (dst_rep_t)(aAbs & srcNaNCode) << (dstSigBits - srcSigBits);
76+
}
77+
78+
else if (aAbs) {
79+
// a is denormal.
80+
// renormalize the significand and clear the leading bit, then insert
81+
// the correct adjusted exponent in the destination type.
82+
const int scale = src_rep_t_clz(aAbs) - src_rep_t_clz(srcMinNormal);
83+
absResult = (dst_rep_t)aAbs << (dstSigBits - srcSigBits + scale);
84+
absResult ^= dstMinNormal;
85+
const int resultExponent = dstExpBias - srcExpBias - scale + 1;
86+
absResult |= (dst_rep_t)resultExponent << dstSigBits;
87+
}
88+
89+
else {
90+
// a is zero.
91+
absResult = 0;
92+
}
93+
94+
// Apply the signbit to (dst_t)abs(a).
95+
const dst_rep_t result = absResult | (dst_rep_t)sign << (dstBits - srcBits);
96+
return dstFromRep(result);
97+
}
98+
// Use a forwarding definition and noinline to implement a poor man's alias,
99+
// as there isn't a good cross-platform way of defining one.
100+
__attribute__((noinline)) float __extendhfsf2(uint16_t a) {
101+
return __extendXfYf2__(a);
102+
}
103+
104+
extern "C" float __gnu_h2f_ieee(uint16_t a) {
105+
return __extendhfsf2(a);
106+
}
107+
#endif // #if defined(__linux__)

Sources/CHalf/src/fp_trunc.cpp

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
#if defined(__linux__)
2+
#include <limits.h>
3+
#include <stdint.h>
4+
5+
typedef float src_t;
6+
typedef uint32_t src_rep_t;
7+
#define SRC_REP_C UINT32_C
8+
static const int srcSigBits = 23;
9+
10+
typedef uint16_t dst_t;
11+
typedef uint16_t dst_rep_t;
12+
#define DST_REP_C UINT16_C
13+
static const int dstSigBits = 10;
14+
15+
// End of specialization parameters. Two helper routines for conversion to and
16+
// from the representation of floating-point data as integer values follow.
17+
18+
static __inline src_rep_t srcToRep(src_t x) {
19+
const union { src_t f; src_rep_t i; } rep = {.f = x};
20+
return rep.i;
21+
}
22+
23+
static __inline dst_t dstFromRep(dst_rep_t x) {
24+
const union { dst_t f; dst_rep_t i; } rep = {.i = x};
25+
return rep.f;
26+
}
27+
28+
static __inline dst_t __truncXfYf2__(src_t a) {
29+
// Various constants whose values follow from the type parameters.
30+
// Any reasonable optimizer will fold and propagate all of these.
31+
const int srcBits = sizeof(src_t)*CHAR_BIT;
32+
const int srcExpBits = srcBits - srcSigBits - 1;
33+
const int srcInfExp = (1 << srcExpBits) - 1;
34+
const int srcExpBias = srcInfExp >> 1;
35+
36+
const src_rep_t srcMinNormal = SRC_REP_C(1) << srcSigBits;
37+
const src_rep_t srcSignificandMask = srcMinNormal - 1;
38+
const src_rep_t srcInfinity = (src_rep_t)srcInfExp << srcSigBits;
39+
const src_rep_t srcSignMask = SRC_REP_C(1) << (srcSigBits + srcExpBits);
40+
const src_rep_t srcAbsMask = srcSignMask - 1;
41+
const src_rep_t roundMask = (SRC_REP_C(1) << (srcSigBits - dstSigBits)) - 1;
42+
const src_rep_t halfway = SRC_REP_C(1) << (srcSigBits - dstSigBits - 1);
43+
const src_rep_t srcQNaN = SRC_REP_C(1) << (srcSigBits - 1);
44+
const src_rep_t srcNaNCode = srcQNaN - 1;
45+
46+
const int dstBits = sizeof(dst_t)*CHAR_BIT;
47+
const int dstExpBits = dstBits - dstSigBits - 1;
48+
const int dstInfExp = (1 << dstExpBits) - 1;
49+
const int dstExpBias = dstInfExp >> 1;
50+
const int underflowExponent = srcExpBias + 1 - dstExpBias;
51+
const int overflowExponent = srcExpBias + dstInfExp - dstExpBias;
52+
const src_rep_t underflow = (src_rep_t)underflowExponent << srcSigBits;
53+
const src_rep_t overflow = (src_rep_t)overflowExponent << srcSigBits;
54+
55+
const dst_rep_t dstQNaN = DST_REP_C(1) << (dstSigBits - 1);
56+
const dst_rep_t dstNaNCode = dstQNaN - 1;
57+
58+
// Break a into a sign and representation of the absolute value
59+
const src_rep_t aRep = srcToRep(a);
60+
const src_rep_t aAbs = aRep & srcAbsMask;
61+
const src_rep_t sign = aRep & srcSignMask;
62+
dst_rep_t absResult;
63+
64+
if (aAbs - underflow < aAbs - overflow) {
65+
// The exponent of a is within the range of normal numbers in the
66+
// destination format. We can convert by simply right-shifting with
67+
// rounding and adjusting the exponent.
68+
absResult = aAbs >> (srcSigBits - dstSigBits);
69+
absResult -= (dst_rep_t)(srcExpBias - dstExpBias) << dstSigBits;
70+
71+
const src_rep_t roundBits = aAbs & roundMask;
72+
// Round to nearest
73+
if (roundBits > halfway)
74+
absResult++;
75+
// Ties to even
76+
else if (roundBits == halfway)
77+
absResult += absResult & 1;
78+
}
79+
else if (aAbs > srcInfinity) {
80+
// a is NaN.
81+
// Conjure the result by beginning with infinity, setting the qNaN
82+
// bit and inserting the (truncated) trailing NaN field.
83+
absResult = (dst_rep_t)dstInfExp << dstSigBits;
84+
absResult |= dstQNaN;
85+
absResult |= ((aAbs & srcNaNCode) >> (srcSigBits - dstSigBits)) & dstNaNCode;
86+
}
87+
else if (aAbs >= overflow) {
88+
// a overflows to infinity.
89+
absResult = (dst_rep_t)dstInfExp << dstSigBits;
90+
}
91+
else {
92+
// a underflows on conversion to the destination type or is an exact
93+
// zero. The result may be a denormal or zero. Extract the exponent
94+
// to get the shift amount for the denormalization.
95+
const int aExp = aAbs >> srcSigBits;
96+
const int shift = srcExpBias - dstExpBias - aExp + 1;
97+
98+
const src_rep_t significand = (aRep & srcSignificandMask) | srcMinNormal;
99+
100+
// Right shift by the denormalization amount with sticky.
101+
if (shift > srcSigBits) {
102+
absResult = 0;
103+
} else {
104+
const bool sticky = significand << (srcBits - shift);
105+
src_rep_t denormalizedSignificand = significand >> shift | sticky;
106+
absResult = denormalizedSignificand >> (srcSigBits - dstSigBits);
107+
const src_rep_t roundBits = denormalizedSignificand & roundMask;
108+
// Round to nearest
109+
if (roundBits > halfway)
110+
absResult++;
111+
// Ties to even
112+
else if (roundBits == halfway)
113+
absResult += absResult & 1;
114+
}
115+
}
116+
117+
// Apply the signbit to (dst_t)abs(a).
118+
const dst_rep_t result = absResult | sign >> (srcBits - dstBits);
119+
return dstFromRep(result);
120+
}
121+
122+
// Use a forwarding definition and noinline to implement a poor man's alias,
123+
// as there isn't a good cross-platform way of defining one.
124+
__attribute__((noinline)) uint16_t __truncsfhf2(float a) {
125+
return __truncXfYf2__(a);
126+
}
127+
128+
extern "C" uint16_t __truncdfhf2(double a) {
129+
return __truncsfhf2((double)a);
130+
}
131+
132+
extern "C" uint16_t __gnu_f2h_ieee(float a) {
133+
return __truncsfhf2(a);
134+
}
135+
#endif // #if defined(__linux__)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#if !canImport(ObjectiveC)
2+
import XCTest
3+
4+
extension TestCHalf {
5+
// DO NOT MODIFY: This is autogenerated, use:
6+
// `swift test --generate-linuxmain`
7+
// to regenerate.
8+
static let __allTests__TestCHalf = [
9+
("testArithmeticFunctions", testArithmeticFunctions),
10+
("testConstructorFunctions", testConstructorFunctions),
11+
("testConvertingToFromRawValue", testConvertingToFromRawValue),
12+
("testConvertToFromPrimitiveValues", testConvertToFromPrimitiveValues),
13+
("testLogicFunctions", testLogicFunctions),
14+
("testMiscellaneousFunctions", testMiscellaneousFunctions),
15+
]
16+
}
17+
18+
public func __allTests() -> [XCTestCaseEntry] {
19+
return [
20+
testCase(TestCHalf.__allTests__TestCHalf),
21+
]
22+
}
23+
#endif

0 commit comments

Comments
 (0)