Skip to content

Commit 6bc7e7e

Browse files
committed
Add experimental _Volatile module providing low-level primitives for MMIO
1 parent 47803aa commit 6bc7e7e

File tree

5 files changed

+329
-0
lines changed

5 files changed

+329
-0
lines changed

stdlib/public/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,8 @@ if(SWIFT_BUILD_STDLIB AND NOT SWIFT_STDLIB_BUILD_ONLY_CORE_MODULES)
256256
if(SWIFT_ENABLE_SYNCHRONIZATION)
257257
add_subdirectory(Synchronization)
258258
endif()
259+
260+
add_subdirectory(Volatile)
259261
endif()
260262

261263
if(SWIFT_BUILD_REMOTE_MIRROR)

stdlib/public/Volatile/CMakeLists.txt

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#===--- CMakeLists.txt ---------------------------------------------------===#
2+
#
3+
# This source file is part of the Swift.org open source project
4+
#
5+
# Copyright (c) 2019 - 2022 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+
add_swift_target_library(swift_Volatile ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} IS_STDLIB
14+
Volatile.swift
15+
16+
SWIFT_COMPILE_FLAGS
17+
${SWIFT_STANDARD_LIBRARY_SWIFT_FLAGS}
18+
-parse-stdlib
19+
LINK_FLAGS "${SWIFT_RUNTIME_SWIFT_LINK_FLAGS}"
20+
21+
INSTALL_IN_COMPONENT stdlib
22+
)
23+
24+
if(SWIFT_SHOULD_BUILD_EMBEDDED_STDLIB)
25+
add_custom_target(embedded-volatile ALL)
26+
foreach(entry ${EMBEDDED_STDLIB_TARGET_TRIPLES})
27+
string(REGEX REPLACE "[ \t]+" ";" list "${entry}")
28+
list(GET list 0 arch)
29+
list(GET list 1 mod)
30+
list(GET list 2 triple)
31+
32+
set(SWIFT_SDK_embedded_ARCH_${arch}_MODULE "${mod}")
33+
set(SWIFT_SDK_embedded_LIB_SUBDIR "embedded")
34+
set(SWIFT_SDK_embedded_ARCH_${arch}_TRIPLE "${triple}")
35+
add_swift_target_library_single(
36+
embedded-volatile-${mod}
37+
swift_Volatile
38+
ONLY_SWIFTMODULE
39+
IS_SDK_OVERLAY IS_FRAGILE
40+
41+
Volatile.swift
42+
43+
SWIFT_COMPILE_FLAGS
44+
-Xcc -D__MACH__ -Xcc -D__APPLE__ -Xcc -ffreestanding -enable-experimental-feature Embedded
45+
-parse-stdlib
46+
C_COMPILE_FLAGS
47+
-D__MACH__ -D__APPLE__ -ffreestanding
48+
MODULE_DIR "${CMAKE_BINARY_DIR}/lib/swift/embedded"
49+
SDK "embedded"
50+
ARCHITECTURE "${arch}"
51+
DEPENDS embedded-stdlib-${mod}
52+
INSTALL_IN_COMPONENT stdlib
53+
)
54+
add_dependencies(embedded-volatile embedded-volatile-${mod})
55+
endforeach()
56+
endif()

stdlib/public/Volatile/Volatile.swift

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2020 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+
import Swift
14+
15+
/// A pointer for accessing "volatile" memory, e.g. memory-mapped I/O registers.
16+
///
17+
/// Do not use for inter-thread synchronization. This is only meaningful for
18+
/// low-level operations on special memory addresses performed from OS kernels,
19+
/// embedded firmware, and similar environments.
20+
///
21+
/// The semantics of volatile load and volatile store operations match the LLVM
22+
/// volatile semantics. Notably, a volatile operation cannot be added, removed,
23+
/// or reordered with other volatile operations by the compiler. They may be
24+
/// reordered with non-volatile operations. For details, see
25+
/// <https://llvm.org/docs/LangRef.html#volatile-memory-accesses>.
26+
public struct UnsafeVolatilePointer<Pointee> {
27+
public var _rawPointer: Builtin.RawPointer
28+
public init(bitPattern: UInt) {
29+
_rawPointer = UnsafeRawPointer(bitPattern: bitPattern)!._rawValue
30+
}
31+
}
32+
33+
extension UnsafeVolatilePointer where Pointee == UInt8 {
34+
/// Perform an 8-bit volatile load operation from the target pointer.
35+
///
36+
/// Do not use for inter-thread synchronization.
37+
@_transparent
38+
public func load() -> Pointee {
39+
UInt8(Builtin.atomicload_monotonic_volatile_Int8(_rawPointer))
40+
}
41+
42+
/// Perform an 8-bit volatile store operation on the target pointer.
43+
///
44+
/// Do not use for inter-thread synchronization.
45+
@_transparent
46+
public func store(_ value: Pointee) {
47+
Builtin.atomicstore_monotonic_volatile_Int8(_rawPointer, value._value)
48+
}
49+
}
50+
51+
extension UnsafeVolatilePointer where Pointee == UInt16 {
52+
/// Perform a 16-bit volatile load operation from the target pointer.
53+
///
54+
/// Do not use for inter-thread synchronization.
55+
@_transparent
56+
public func load() -> Pointee {
57+
UInt16(Builtin.atomicload_monotonic_volatile_Int16(_rawPointer))
58+
}
59+
60+
/// Perform a 16-bit volatile store operation on the target pointer.
61+
///
62+
/// Do not use for inter-thread synchronization.
63+
@_transparent
64+
public func store(_ value: Pointee) {
65+
Builtin.atomicstore_monotonic_volatile_Int16(_rawPointer, value._value)
66+
}
67+
}
68+
69+
extension UnsafeVolatilePointer where Pointee == UInt32 {
70+
/// Perform a 32-bit volatile load operation from the target pointer.
71+
///
72+
/// Do not use for inter-thread synchronization.
73+
@_transparent
74+
public func load() -> Pointee {
75+
UInt32(Builtin.atomicload_monotonic_volatile_Int32(_rawPointer))
76+
}
77+
78+
/// Perform a 32-bit volatile store operation on the target pointer.
79+
///
80+
/// Do not use for inter-thread synchronization.
81+
@_transparent
82+
public func store(_ value: Pointee) {
83+
Builtin.atomicstore_monotonic_volatile_Int32(_rawPointer, value._value)
84+
}
85+
}
86+
87+
extension UnsafeVolatilePointer where Pointee == UInt64 {
88+
/// Perform a 64-bit volatile load operation from the target pointer.
89+
///
90+
/// Do not use for inter-thread synchronization.
91+
@_transparent
92+
public func load() -> Pointee {
93+
UInt64(Builtin.atomicload_monotonic_volatile_Int64(_rawPointer))
94+
}
95+
96+
/// Perform a 64-bit volatile store operation on the target pointer.
97+
///
98+
/// Do not use for inter-thread synchronization.
99+
@_transparent
100+
public func store(_ value: Pointee) {
101+
Builtin.atomicstore_monotonic_volatile_Int64(_rawPointer, value._value)
102+
}
103+
}
104+
105+
106+
107+
extension UnsafeMutablePointer where Pointee == UInt8 {
108+
/// Perform a 8-bit volatile load operation from the target pointer.
109+
///
110+
/// Do not use for inter-thread synchronization.
111+
@_transparent
112+
public func volatileLoad() -> Pointee {
113+
UnsafeVolatilePointer(bitPattern: UInt(bitPattern: self)).load()
114+
}
115+
116+
/// Perform a 8-bit volatile store operation on the target pointer.
117+
///
118+
/// Do not use for inter-thread synchronization.
119+
@_transparent
120+
public func volatileStore(_ value: Pointee) {
121+
UnsafeVolatilePointer(bitPattern: UInt(bitPattern: self)).store(value)
122+
}
123+
}
124+
125+
extension UnsafeMutablePointer where Pointee == UInt16 {
126+
/// Perform a 16-bit volatile load operation from the target pointer.
127+
///
128+
/// Do not use for inter-thread synchronization.
129+
@_transparent
130+
public func volatileLoad() -> Pointee {
131+
UnsafeVolatilePointer(bitPattern: UInt(bitPattern: self)).load()
132+
}
133+
134+
/// Perform a 16-bit volatile store operation on the target pointer.
135+
///
136+
/// Do not use for inter-thread synchronization.
137+
@_transparent
138+
public func volatileStore(_ value: Pointee) {
139+
UnsafeVolatilePointer(bitPattern: UInt(bitPattern: self)).store(value)
140+
}
141+
}
142+
143+
extension UnsafeMutablePointer where Pointee == UInt32 {
144+
/// Perform a 32-bit volatile load operation from the target pointer.
145+
///
146+
/// Do not use for inter-thread synchronization.
147+
@_transparent
148+
public func volatileLoad() -> Pointee {
149+
UnsafeVolatilePointer(bitPattern: UInt(bitPattern: self)).load()
150+
}
151+
152+
/// Perform a 32-bit volatile store operation on the target pointer.
153+
///
154+
/// Do not use for inter-thread synchronization.
155+
@_transparent
156+
public func volatileStore(_ value: Pointee) {
157+
UnsafeVolatilePointer(bitPattern: UInt(bitPattern: self)).store(value)
158+
}
159+
}
160+
161+
extension UnsafeMutablePointer where Pointee == UInt64 {
162+
/// Perform a 64-bit volatile load operation from the target pointer.
163+
///
164+
/// Do not use for inter-thread synchronization.
165+
@_transparent
166+
public func volatileLoad() -> Pointee {
167+
UnsafeVolatilePointer(bitPattern: UInt(bitPattern: self)).load()
168+
}
169+
170+
/// Perform a 64-bit volatile store operation on the target pointer.
171+
///
172+
/// Do not use for inter-thread synchronization.
173+
@_transparent
174+
public func volatileStore(_ value: Pointee) {
175+
UnsafeVolatilePointer(bitPattern: UInt(bitPattern: self)).store(value)
176+
}
177+
}

test/Volatile/volatile-ir.swift

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-emit-ir %s -module-name main -parse-as-library -Onone | %FileCheck %s
3+
// RUN: %target-swift-emit-ir %s -module-name main -parse-as-library -O | %FileCheck %s
4+
// RUN: %target-swift-emit-ir %s -module-name main -parse-as-library -Osize | %FileCheck %s
5+
6+
import _Volatile
7+
8+
public func test_uint8() -> UInt8 {
9+
let p = UnsafeVolatilePointer<UInt8>(bitPattern: 0xf000baaa)
10+
p.store(42)
11+
return p.load()
12+
}
13+
14+
// CHECK: define {{.*}}i8 @"$s4main10test_uint8s5UInt8VyF"()
15+
// CHECK: store atomic volatile i8 42, ptr %3 monotonic, align 1
16+
// CHECK: [[RET:%.*]] = load atomic volatile i8, ptr %4 monotonic, align 1
17+
// CHECK: ret i8 [[RET]]
18+
// CHECK: }
19+
20+
public func test_uint16() -> UInt16 {
21+
let p = UnsafeVolatilePointer<UInt16>(bitPattern: 0xf000baaa)
22+
p.store(42)
23+
return p.load()
24+
}
25+
26+
// CHECK: define {{.*}}i16 @"$s4main11test_uint16s6UInt16VyF"()
27+
// CHECK: store atomic volatile i16 42, ptr %3 monotonic, align 2
28+
// CHECK: [[RET:%.*]] = load atomic volatile i16, ptr %4 monotonic, align 2
29+
// CHECK: ret i16 [[RET]]
30+
// CHECK: }
31+
32+
public func test_uint32() -> UInt32 {
33+
let p = UnsafeVolatilePointer<UInt32>(bitPattern: 0xf000baaa)
34+
p.store(42)
35+
return p.load()
36+
}
37+
38+
// CHECK: define {{.*}}i32 @"$s4main11test_uint32s6UInt32VyF"()
39+
// CHECK: store atomic volatile i32 42, ptr %3 monotonic, align 4
40+
// CHECK: [[RET:%.*]] = load atomic volatile i32, ptr %4 monotonic, align 4
41+
// CHECK: ret i32 [[RET]]
42+
// CHECK: }
43+
44+
public func test_uint64() -> UInt64 {
45+
let p = UnsafeVolatilePointer<UInt64>(bitPattern: 0xf000baaa)
46+
p.store(42)
47+
return p.load()
48+
}
49+
50+
// CHECK: define {{.*}}i64 @"$s4main11test_uint64s6UInt64VyF"()
51+
// CHECK: store atomic volatile i64 42, ptr %3 monotonic, align 8
52+
// CHECK: [[RET:%.*]] = load atomic volatile i64, ptr %4 monotonic, align 8
53+
// CHECK: ret i64 [[RET]]
54+
// CHECK: }
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-emit-ir %s -module-name main -parse-as-library -Onone | %FileCheck %s
3+
// RUN: %target-swift-emit-ir %s -module-name main -parse-as-library -O | %FileCheck %s
4+
// RUN: %target-swift-emit-ir %s -module-name main -parse-as-library -Osize | %FileCheck %s
5+
6+
import _Volatile
7+
8+
public func test_volatilepointer() -> UInt8 {
9+
let p = UnsafeVolatilePointer<UInt8>(bitPattern: 0xf000baaa)
10+
p.store(42)
11+
let a = p.load()
12+
let b = p.load()
13+
let c = p.load()
14+
return c
15+
}
16+
17+
// CHECK: define {{.*}}i8 @"$s4main20test_volatilepointers5UInt8VyF"()
18+
// CHECK: store atomic volatile i8 42, ptr {{.*}} monotonic, align 1
19+
// CHECK: load atomic volatile i8, ptr {{.*}} monotonic, align 1
20+
// CHECK: load atomic volatile i8, ptr {{.*}} monotonic, align 1
21+
// CHECK: [[RET:%.*]] = load atomic volatile i8, ptr {{.*}} monotonic, align 1
22+
// CHECK: ret i8 [[RET]]
23+
// CHECK: }
24+
25+
public func test_unsafepointer() -> UInt8 {
26+
let p = UnsafeMutablePointer<UInt8>(bitPattern: 0xf000baaa)!
27+
p.volatileStore(42)
28+
let a = p.volatileLoad()
29+
let b = p.volatileLoad()
30+
let c = p.volatileLoad()
31+
return c
32+
}
33+
34+
// CHECK: define {{.*}}i8 @"$s4main18test_unsafepointers5UInt8VyF"()
35+
// CHECK: store atomic volatile i8 42, ptr {{.*}} monotonic, align 1
36+
// CHECK: load atomic volatile i8, ptr {{.*}} monotonic, align 1
37+
// CHECK: load atomic volatile i8, ptr {{.*}} monotonic, align 1
38+
// CHECK: [[RET:%.*]] = load atomic volatile i8, ptr {{.*}} monotonic, align 1
39+
// CHECK: ret i8 [[RET]]
40+
// CHECK: }

0 commit comments

Comments
 (0)