Skip to content

Commit 30c01a9

Browse files
committed
Possible spelling: Relaxed.sum/product.
1 parent 9a23fdf commit 30c01a9

File tree

7 files changed

+126
-66
lines changed

7 files changed

+126
-66
lines changed

Sources/ComplexModule/Complex+AlgebraicField.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,4 +123,17 @@ extension Complex: AlgebraicField {
123123
}
124124
return nil
125125
}
126+
127+
@inlinable
128+
public static func _relaxedAdd(_ a: Self, _ b: Self) -> Self {
129+
Complex(Relaxed.sum(a.x, b.x), Relaxed.sum(a.y, b.y))
130+
}
131+
132+
@inlinable
133+
public static func _relaxedMul(_ a: Self, _ b: Self) -> Self {
134+
Complex(
135+
Relaxed.sum(Relaxed.product(a.x, b.x), -Relaxed.product(a.y, b.y)),
136+
Relaxed.sum(Relaxed.product(a.x, b.y), Relaxed.product(a.y, b.x))
137+
)
138+
}
126139
}

Sources/ComplexModule/Complex+ElementaryFunctions.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ extension Complex: ElementaryFunctions {
119119
}
120120
// Special cases out of the way, evaluate as discussed above.
121121
return Complex(
122-
RealType._mulAdd(.cos(z.y), .expMinusOne(z.x), .cosMinusOne(z.y)),
122+
Relaxed.multiplyAdd(.cos(z.y), .expMinusOne(z.x), .cosMinusOne(z.y)),
123123
.exp(z.x) * .sin(z.y)
124124
)
125125
}
@@ -300,7 +300,7 @@ extension Complex: ElementaryFunctions {
300300
// We are not trying for sub-ulp accuracy, just a good relative error
301301
// bound, so for our purposes it suffices to have log u dominate the
302302
// result:
303-
if u >= 1 || u >= RealType._mulAdd(u,u,v*v) {
303+
if u >= 1 || u >= Relaxed.multiplyAdd(u, u, v*v) {
304304
let r = v / u
305305
return Complex(.log(u) + .log(onePlus: r*r)/2, θ)
306306
}

Sources/RealModule/AlgebraicField.swift

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,12 @@ public protocol AlgebraicField: SignedNumeric {
8989
/// }
9090
/// ```
9191
var reciprocal: Self? { get }
92+
93+
/// a + b, with the optimizer licensed to reassociate and form FMAs.
94+
static func _relaxedAdd(_ a: Self, _ b: Self) -> Self
95+
96+
/// a * b, with the optimizer licensed to reassociate and form FMAs.
97+
static func _relaxedMul(_ a: Self, _ b: Self) -> Self
9298
}
9399

94100
extension AlgebraicField {
@@ -99,12 +105,27 @@ extension AlgebraicField {
99105
return result
100106
}
101107

102-
/// Implementations should be *conservative* with the reciprocal property;
103-
/// it is OK to return `nil` even in cases where a reciprocal could be
104-
/// represented. For this reason, a default implementation that simply
105-
/// always returns `nil` is correct, but conforming types should provide
106-
/// a better implementation if possible.
108+
// Implementations should be *conservative* with the reciprocal property;
109+
// it is OK to return `nil` even in cases where a reciprocal could be
110+
// represented. For this reason, a default implementation that simply
111+
// always returns `nil` is correct, but conforming types should provide
112+
// a better implementation if possible.
113+
@_transparent
107114
public var reciprocal: Self? {
108115
return nil
109116
}
117+
118+
// It's always OK to simply fall back on normal arithmetic, and for any
119+
// field with exact arithmetic, this is the correct definition.
120+
@_transparent
121+
public static func _relaxedAdd(_ a: Self, _ b: Self) -> Self {
122+
a + b
123+
}
124+
125+
// It's always OK to simply fall back on normal arithmetic, and for any
126+
// field with exact arithmetic, this is the correct definition.
127+
@_transparent
128+
public static func _relaxedMul(_ a: Self, _ b: Self) -> Self {
129+
a * b
130+
}
110131
}

Sources/RealModule/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ add_library(RealModule
1717
Float16+Real.swift
1818
Float80+Real.swift
1919
Real.swift
20-
RealFunctions.swift)
20+
RealFunctions.swift
21+
RelaxedArithmetic.swift)
2122
set_target_properties(RealModule PROPERTIES
2223
INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY})
2324
target_link_libraries(RealModule PUBLIC

Sources/RealModule/Real.swift

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -88,16 +88,6 @@ extension Real {
8888
a*b + c
8989
}
9090

91-
@_transparent
92-
public static func _relaxedAdd(_ a: Self, _ b: Self) -> Self {
93-
a + b
94-
}
95-
96-
@_transparent
97-
public static func _relaxedMul(_ a: Self, _ b: Self) -> Self {
98-
a * b
99-
}
100-
10191
@_transparent
10292
public static func sqrt(_ x: Self) -> Self {
10393
return x.squareRoot()

Sources/RealModule/RealFunctions.swift

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -80,52 +80,4 @@ public protocol RealFunctions: ElementaryFunctions {
8080
/// a*b + c, computed _either_ with an FMA or with separate multiply and add,
8181
/// whichever is fastest on the compilation target.
8282
static func _mulAdd(_ a: Self, _ b: Self, _ c: Self) -> Self
83-
84-
/// a + b, with the optimizer licensed to reassociate and form FMAs.
85-
///
86-
/// Floating-point addition is not an associative operation, so the Swift
87-
/// compiler does not have any flexibility in how it evaluates an expression
88-
/// like:
89-
/// ```
90-
/// func sum(array: [Float]) -> Float {
91-
/// array.reduce(0, +)
92-
/// }
93-
/// ```
94-
/// Using `_relaxedAdd` instead of `+` permits the compiler to reorder the
95-
/// terms in the summation, which unlocks loop unrolling and vectorization.
96-
/// In a benchmark, simply using `_relaxedAdd` provides about an 8x speedup
97-
/// for release builds, without any unsafe flags or other optimizations.
98-
/// Further improvement should be possible by improving LLVM optimizations
99-
/// or adding attributes to license more aggressive unrolling and taking
100-
/// advantage of vector ISA extensions for swift.
101-
///
102-
/// If a type or toolchain does not support reassociation for optimization
103-
/// purposes, this operation decays to a normal addition; it is a license
104-
/// for the compiler to optimize, not a guarantee that any change occurs.
105-
static func _relaxedAdd(_ a: Self, _ b: Self) -> Self
106-
107-
/// a * b, with the optimizer licensed to reassociate and form FMAs.
108-
///
109-
/// Floating-point addition and multiplication are not associative operations,
110-
/// so the Swift compiler does not have any flexibility in how it evaluates
111-
/// an expression
112-
/// like:
113-
/// ```
114-
/// func sumOfSquares(array: [Float]) -> Float {
115-
/// array.reduce(0) { $0 + $1*$1 }
116-
/// }
117-
/// ```
118-
/// Using `_relaxedAdd` and `_relaxedMul` instead of `+` and `*` permits the
119-
/// compiler to reorder the terms in the summation, which unlocks loop
120-
/// unrolling and vectorization, and form fused multiply-adds, which allows
121-
/// us to achieve twice the throughput on some hardware.
122-
///
123-
/// If you want to license FMA formation, but _not_ reassociation (desirable
124-
/// for some numerics tasks), use `_mulAdd(a, b, c)` instead.
125-
///
126-
/// If a type or toolchain does not support reassociation for optimization
127-
/// purposes, this operation decays to a normal multiplication; it is a
128-
/// license for the compiler to optimize, not a guarantee that any change
129-
/// occurs.
130-
static func _relaxedMul(_ a: Self, _ b: Self) -> Self
13183
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
//===--- RelaxedArithmetic.swift ------------------------------*- swift -*-===//
2+
//
3+
// This source file is part of the Swift Numerics open source project
4+
//
5+
// Copyright (c) 2021 Apple Inc. and the Swift Numerics 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+
//
10+
//===----------------------------------------------------------------------===//
11+
12+
import _NumericsShims
13+
14+
/// A namespace for "relaxed arithmetic" operations for types conforming to
15+
/// `AlgebraicField`.
16+
public enum Relaxed { }
17+
18+
extension Relaxed {
19+
/// a+b with the optimizer licensed to reassociate expressions and form FMAs.
20+
///
21+
/// Floating-point addition is not an associative operation, so the Swift
22+
/// compiler does not have any flexibility in how it evaluates an expression
23+
/// like:
24+
/// ```
25+
/// func sum(array: [Float]) -> Float {
26+
/// array.reduce(0, +)
27+
/// }
28+
/// ```
29+
/// Using `Relaxed.sum` instead of `+` permits the compiler to reorder the
30+
/// terms in the summation, which unlocks loop unrolling and vectorization.
31+
/// In a benchmark, simply using `Relaxed.sum` provides about an 8x speedup
32+
/// for release builds, without any unsafe flags or other optimizations.
33+
/// Further improvement should be possible by improving LLVM optimizations
34+
/// or adding attributes to license more aggressive unrolling and taking
35+
/// advantage of vector ISA extensions for swift.
36+
///
37+
/// If you want to compute `a-b` with relaxed semantics, use
38+
/// `Relaxed.sum(a, -b)`.
39+
///
40+
/// If a type or toolchain does not support reassociation for optimization
41+
/// purposes, this operation decays to a normal addition; it is a license
42+
/// for the compiler to optimize, not a guarantee that any change occurs.
43+
@_transparent
44+
public static func sum<T: AlgebraicField>(_ a: T, _ b: T) -> T {
45+
T._relaxedAdd(a, b)
46+
}
47+
48+
/// a*b with the optimizer licensed to reassociate expressions and form FMAs.
49+
///
50+
/// Floating-point addition and multiplication are not associative operations,
51+
/// so the Swift compiler does not have any flexibility in how it evaluates
52+
/// an expression
53+
/// like:
54+
/// ```
55+
/// func sumOfSquares(array: [Float]) -> Float {
56+
/// array.reduce(0) { $0 + $1*$1 }
57+
/// }
58+
/// ```
59+
/// Using `Relaxed.sum` and `Relaxed.product` instead of `+` and `*` permits
60+
/// the compiler to reorder the terms in the summation, which unlocks loop
61+
/// unrolling and vectorization, and form fused multiply-adds, which allows
62+
/// us to achieve twice the throughput on some hardware.
63+
///
64+
/// If a type or toolchain does not support reassociation for optimization
65+
/// purposes, this operation decays to a normal multiplication; it is a
66+
/// license for the compiler to optimize, not a guarantee that any change
67+
/// occurs.
68+
@_transparent
69+
public static func product<T: AlgebraicField>(_ a: T, _ b: T) -> T {
70+
T._relaxedMul(a, b)
71+
}
72+
}
73+
74+
extension Relaxed {
75+
/// a*b + c, computed _either_ with an FMA or with separate multiply and add,
76+
/// whichever is fastest according to the optimizer's heuristics.
77+
@_transparent
78+
public static func multiplyAdd<T: RealFunctions>(
79+
_ a: T, _ b: T, _ c: T
80+
) -> T {
81+
T._mulAdd(a, b, c)
82+
}
83+
}

0 commit comments

Comments
 (0)