Skip to content

Commit 85fde8b

Browse files
committed
Add support for Linux s390x. LLVM's Swift calling convention support is used to ensure correct operations of C++ code in the runtime. This patch also includes some (incomplete) changes to enum handling to make enums work in most common cases.
1 parent bb3486d commit 85fde8b

File tree

32 files changed

+189
-49
lines changed

32 files changed

+189
-49
lines changed

CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,8 @@ else()
439439
set(SWIFT_HOST_VARIANT_ARCH_default "powerpc64")
440440
elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc64le")
441441
set(SWIFT_HOST_VARIANT_ARCH_default "powerpc64le")
442+
elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "s390x")
443+
set(SWIFT_HOST_VARIANT_ARCH_default "s390x")
442444
# FIXME: Only matches v6l/v7l - by far the most common variants
443445
elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "armv6l")
444446
set(SWIFT_HOST_VARIANT_ARCH_default "armv6")
@@ -507,6 +509,8 @@ if("${SWIFT_HOST_VARIANT_SDK}" STREQUAL "LINUX")
507509
set(SWIFT_HOST_TRIPLE "aarch64-unknown-linux-gnu")
508510
elseif("${SWIFT_HOST_VARIANT_ARCH}" MATCHES "(powerpc64|powerpc64le)")
509511
set(SWIFT_HOST_TRIPLE "${SWIFT_HOST_VARIANT_ARCH}-unknown-linux-gnu")
512+
elseif("${SWIFT_HOST_VARIANT_ARCH}" MATCHES "s390x")
513+
set(SWIFT_HOST_TRIPLE "s390x-unknown-linux-gnu")
510514
elseif("${SWIFT_HOST_VARIANT_ARCH}" MATCHES "(armv6|armv7)")
511515
set(SWIFT_HOST_TRIPLE "${SWIFT_HOST_VARIANT_ARCH}-unknown-linux-gnueabihf")
512516
else()

cmake/modules/SwiftSetIfArchBitness.cmake

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ function(set_if_arch_bitness var_name)
1616
"${SIA_ARCH}" STREQUAL "arm64" OR
1717
"${SIA_ARCH}" STREQUAL "aarch64" OR
1818
"${SIA_ARCH}" STREQUAL "powerpc64" OR
19-
"${SIA_ARCH}" STREQUAL "powerpc64le")
19+
"${SIA_ARCH}" STREQUAL "powerpc64le" OR
20+
"${SIA_ARCH}" STREQUAL "s390x")
2021
set("${var_name}" "${SIA_CASE_64_BIT}" PARENT_SCOPE)
2122
else()
2223
message(FATAL_ERROR "Unknown architecture: ${SIA_ARCH}")

include/swift/ABI/System.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,9 @@
9797
// Heap objects are pointer-aligned, so the low three bits are unused.
9898
#define SWIFT_ABI_POWERPC64_SWIFT_SPARE_BITS_MASK 0x0000000000000007ULL
9999

100+
/*********************************** s390x ************************************/
101+
102+
// Top byte of pointers is unused, and heap objects are eight-byte aligned.
103+
#define SWIFT_ABI_S390X_SWIFT_SPARE_BITS_MASK 0x0000000000000007ULL
104+
100105
#endif /* SWIFT_ABI_SYSTEM_H */

include/swift/Runtime/Config.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,12 @@
3333
/// Does the current Swift platform use LLVM's intrinsic "swiftcall"
3434
/// calling convention for Swift functions?
3535
#ifndef SWIFT_USE_SWIFTCALL
36+
#ifdef __s390x__
37+
#define SWIFT_USE_SWIFTCALL 1
38+
#else
3639
#define SWIFT_USE_SWIFTCALL 0
3740
#endif
41+
#endif
3842

3943
/// Does the current Swift platform allow information other than the
4044
/// class pointer to be stored in the isa field? If so, when deriving

include/swift/Runtime/HeapObject.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,10 +157,12 @@ using BoxPair = TwoWordPair<HeapObject *, OpaqueValue *>;
157157
/// The heap object has an initial retain count of 1, and its metadata is set
158158
/// such that destroying the heap object destroys the contained value.
159159
SWIFT_RUNTIME_EXPORT
160-
extern "C" BoxPair::Return swift_allocBox(Metadata const *type);
160+
extern "C" BoxPair::Return swift_allocBox(Metadata const *type)
161+
SWIFT_CC(swift);
161162

162163
SWIFT_RUNTIME_EXPORT
163-
extern "C" BoxPair::Return (*_swift_allocBox)(Metadata const *type);
164+
extern "C" BoxPair::Return (*_swift_allocBox)(Metadata const *type)
165+
SWIFT_CC(swift);
164166

165167

166168
// Allocate plain old memory. This is the generalized entry point

include/swift/Runtime/Metadata.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,6 +1046,17 @@ static const uintptr_t ObjCReservedBitsMask =
10461046
static const unsigned ObjCReservedLowBits =
10471047
SWIFT_ABI_DEFAULT_OBJC_NUM_RESERVED_LOW_BITS;
10481048

1049+
#elif defined(__s390x__)
1050+
1051+
static const uintptr_t LeastValidPointerValue =
1052+
SWIFT_ABI_DEFAULT_LEAST_VALID_POINTER;
1053+
static const uintptr_t SwiftSpareBitsMask =
1054+
SWIFT_ABI_S390X_SWIFT_SPARE_BITS_MASK;
1055+
static const uintptr_t ObjCReservedBitsMask =
1056+
SWIFT_ABI_DEFAULT_OBJC_RESERVED_BITS_MASK;
1057+
static const unsigned ObjCReservedLowBits =
1058+
SWIFT_ABI_DEFAULT_OBJC_NUM_RESERVED_LOW_BITS;
1059+
10491060
#else
10501061

10511062
static const uintptr_t LeastValidPointerValue =

lib/Basic/LangOptions.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ static const StringRef SupportedConditionalCompilationArches[] = {
4040
"i386",
4141
"x86_64",
4242
"powerpc64",
43-
"powerpc64le"
43+
"powerpc64le",
44+
"s390x"
4445
};
4546

4647
static const StringRef SupportedConditionalCompilationEndianness[] = {
@@ -154,6 +155,9 @@ std::pair<bool, bool> LangOptions::setTarget(llvm::Triple triple) {
154155
case llvm::Triple::ArchType::x86_64:
155156
addPlatformConditionValue("arch", "x86_64");
156157
break;
158+
case llvm::Triple::ArchType::systemz:
159+
addPlatformConditionValue("arch", "s390x");
160+
break;
157161
default:
158162
UnsupportedArch = true;
159163
}
@@ -182,6 +186,9 @@ std::pair<bool, bool> LangOptions::setTarget(llvm::Triple triple) {
182186
case llvm::Triple::ArchType::x86_64:
183187
addPlatformConditionValue("_endian", "little");
184188
break;
189+
case llvm::Triple::ArchType::systemz:
190+
addPlatformConditionValue("_endian", "big");
191+
break;
185192
default:
186193
llvm_unreachable("undefined architecture endianness");
187194
}

lib/IRGen/SwiftTargetInfo.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,13 @@ static void configurePowerPC64(IRGenModule &IGM, const llvm::Triple &triple,
103103
SWIFT_ABI_POWERPC64_SWIFT_SPARE_BITS_MASK);
104104
}
105105

106+
/// Configures target-specific information for SystemZ platforms.
107+
static void configureSystemZ(IRGenModule &IGM, const llvm::Triple &triple,
108+
SwiftTargetInfo &target) {
109+
setToMask(target.PointerSpareBits, 64,
110+
SWIFT_ABI_S390X_SWIFT_SPARE_BITS_MASK);
111+
}
112+
106113
/// Configure a default target.
107114
SwiftTargetInfo::SwiftTargetInfo(
108115
llvm::Triple::ObjectFormatType outputObjectFormat,
@@ -154,6 +161,10 @@ SwiftTargetInfo SwiftTargetInfo::get(IRGenModule &IGM) {
154161
configurePowerPC64(IGM, triple, target);
155162
break;
156163

164+
case llvm::Triple::systemz:
165+
configureSystemZ(IGM, triple, target);
166+
break;
167+
157168
default:
158169
// FIXME: Complain here? Default target info is unlikely to be correct.
159170
break;

stdlib/private/SwiftPrivate/PRNG.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public func rand64() -> UInt64 {
2929
public func randInt() -> Int {
3030
#if arch(i386) || arch(arm)
3131
return Int(Int32(bitPattern: rand32()))
32-
#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le)
32+
#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) || arch(s390x)
3333
return Int(Int64(bitPattern: rand64()))
3434
#else
3535
fatalError("unimplemented")

stdlib/public/core/Builtin.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,19 @@ internal var _objectPointerLowSpareBitShift: UInt {
394394
internal var _objCTaggedPointerBits: UInt {
395395
@inline(__always) get { return 0 }
396396
}
397+
#elseif arch(s390x)
398+
internal var _objectPointerSpareBits: UInt {
399+
@inline(__always) get { return 0x0000_0000_0000_0007 }
400+
}
401+
internal var _objectPointerIsObjCBit: UInt {
402+
@inline(__always) get { return 0x0000_0000_0000_0002 }
403+
}
404+
internal var _objectPointerLowSpareBitShift: UInt {
405+
@inline(__always) get { return 0 }
406+
}
407+
internal var _objCTaggedPointerBits: UInt {
408+
@inline(__always) get { return 0 }
409+
}
397410
#endif
398411

399412
/// Extract the raw bits of `x`.

stdlib/public/core/FixedPoint.swift.gyb

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -265,25 +265,21 @@ public struct ${Self}
265265
/// byte order if necessary.
266266
@_transparent public
267267
init(bigEndian value: ${Self}) {
268-
#if arch(i386) || arch(x86_64) || arch(arm) || arch(arm64) || arch(powerpc64le)
269-
self = ${Self}(Builtin.int_bswap_${BuiltinName}(value._value) )
270-
#elseif arch(powerpc64)
268+
#if _endian(big)
271269
self = value
272270
#else
273-
_UnsupportedArchitectureError()
271+
self = ${Self}(Builtin.int_bswap_${BuiltinName}(value._value) )
274272
#endif
275273
}
276274

277275
/// Creates an integer from its little-endian representation, changing the
278276
/// byte order if necessary.
279277
@_transparent public
280278
init(littleEndian value: ${Self}) {
281-
#if arch(i386) || arch(x86_64) || arch(arm) || arch(arm64) || arch(powerpc64le)
279+
#if _endian(little)
282280
self = value
283-
#elseif arch(powerpc64)
284-
self = ${Self}(Builtin.int_bswap_${BuiltinName}(value._value) )
285281
#else
286-
_UnsupportedArchitectureError()
282+
self = ${Self}(Builtin.int_bswap_${BuiltinName}(value._value) )
287283
#endif
288284
}
289285
% end
@@ -303,23 +299,19 @@ public struct ${Self}
303299
/// Returns the big-endian representation of the integer, changing the
304300
/// byte order if necessary.
305301
public var bigEndian: ${Self} {
306-
#if arch(i386) || arch(x86_64) || arch(arm) || arch(arm64) || arch(powerpc64le)
307-
return ${Self}(Builtin.int_bswap_${BuiltinName}(_value))
308-
#elseif arch(powerpc64)
302+
#if _endian(big)
309303
return self
310304
#else
311-
_UnsupportedArchitectureError()
305+
return ${Self}(Builtin.int_bswap_${BuiltinName}(_value))
312306
#endif
313307
}
314308
/// Returns the little-endian representation of the integer, changing the
315309
/// byte order if necessary.
316310
public var littleEndian: ${Self} {
317-
#if arch(i386) || arch(x86_64) || arch(arm) || arch(arm64) || arch(powerpc64le)
311+
#if _endian(little)
318312
return self
319-
#elseif arch(powerpc64)
320-
return ${Self}(Builtin.int_bswap_${BuiltinName}(_value))
321313
#else
322-
_UnsupportedArchitectureError()
314+
return ${Self}(Builtin.int_bswap_${BuiltinName}(_value))
323315
#endif
324316
}
325317
% end

stdlib/public/core/Hashing.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ public // @testable
111111
func _mixUInt(_ value: UInt) -> UInt {
112112
#if arch(i386) || arch(arm)
113113
return UInt(_mixUInt32(UInt32(value)))
114-
#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le)
114+
#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) || arch(s390x)
115115
return UInt(_mixUInt64(UInt64(value)))
116116
#endif
117117
}
@@ -121,7 +121,7 @@ public // @testable
121121
func _mixInt(_ value: Int) -> Int {
122122
#if arch(i386) || arch(arm)
123123
return Int(_mixInt32(Int32(value)))
124-
#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le)
124+
#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) || arch(s390x)
125125
return Int(_mixInt64(Int64(value)))
126126
#endif
127127
}

stdlib/public/core/Runtime.swift.gyb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ func _stdlib_atomicCompareExchangeStrongInt(
190190
object: UnsafeMutablePointer(target),
191191
expected: UnsafeMutablePointer(expected),
192192
desired: UInt32(bitPattern: Int32(desired)))
193-
#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le)
193+
#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) || arch(s390x)
194194
return _stdlib_atomicCompareExchangeStrongUInt64(
195195
object: UnsafeMutablePointer(target),
196196
expected: UnsafeMutablePointer(expected),
@@ -205,7 +205,7 @@ func _swift_stdlib_atomicStoreInt(
205205
return _swift_stdlib_atomicStoreUInt32(
206206
object: UnsafeMutablePointer(target),
207207
desired: UInt32(bitPattern: Int32(desired)))
208-
#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le)
208+
#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) || arch(s390x)
209209
return _swift_stdlib_atomicStoreUInt64(
210210
object: UnsafeMutablePointer(target),
211211
desired: UInt64(bitPattern: Int64(desired)))
@@ -219,7 +219,7 @@ public func _swift_stdlib_atomicLoadInt(
219219
return Int(Int32(bitPattern:
220220
_swift_stdlib_atomicLoadUInt32(
221221
object: UnsafeMutablePointer(target))))
222-
#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le)
222+
#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) || arch(s390x)
223223
return Int(Int64(bitPattern:
224224
_swift_stdlib_atomicLoadUInt64(
225225
object: UnsafeMutablePointer(target))))
@@ -259,7 +259,7 @@ public func _swift_stdlib_atomicFetch${operation}Int(
259259
_swift_stdlib_atomicFetch${operation}UInt32(
260260
object: UnsafeMutablePointer(target),
261261
operand: UInt32(bitPattern: Int32(operand)))))
262-
#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le)
262+
#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) || arch(s390x)
263263
return Int(Int64(bitPattern:
264264
_swift_stdlib_atomicFetch${operation}UInt64(
265265
object: UnsafeMutablePointer(target),

stdlib/public/runtime/Enum.cpp

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -154,12 +154,16 @@ swift::swift_getEnumCaseSinglePayload(const OpaqueValue *value,
154154
auto *valueAddr = reinterpret_cast<const uint8_t*>(value);
155155
auto *extraTagBitAddr = valueAddr + payloadSize;
156156
unsigned extraTagBits = 0;
157-
// FIXME: endianness
158157
unsigned numBytes = getNumTagBytes(payloadSize,
159158
emptyCases-payloadNumExtraInhabitants,
160159
1 /*payload case*/);
161160

161+
#if defined(__BIG_ENDIAN__)
162+
small_memcpy(reinterpret_cast<uint8_t*>(&extraTagBits) + 4 - numBytes,
163+
extraTagBitAddr, numBytes);
164+
#else
162165
small_memcpy(&extraTagBits, extraTagBitAddr, numBytes);
166+
#endif
163167

164168
// If the extra tag bits are zero, we have a valid payload or
165169
// extra inhabitant (checked below). If nonzero, form the case index from
@@ -170,10 +174,15 @@ swift::swift_getEnumCaseSinglePayload(const OpaqueValue *value,
170174

171175
// In practice we should need no more than four bytes from the payload
172176
// area.
173-
// FIXME: endianness.
174177
unsigned caseIndexFromValue = 0;
178+
#if defined(__BIG_ENDIAN__)
179+
unsigned numPayloadTagBytes = std::min(size_t(4), payloadSize);
180+
memcpy(reinterpret_cast<uint8_t*>(&caseIndexFromValue) + 4 -
181+
numPayloadTagBytes, valueAddr, numPayloadTagBytes);
182+
#else
175183
memcpy(&caseIndexFromValue, valueAddr,
176184
std::min(size_t(4), payloadSize));
185+
#endif
177186
return (caseIndexFromExtraTagBits | caseIndexFromValue)
178187
+ payloadNumExtraInhabitants;
179188
}
@@ -247,11 +256,22 @@ swift::swift_storeEnumTagSinglePayload(OpaqueValue *value,
247256
}
248257

249258
// Store into the value.
250-
// FIXME: endianness.
259+
#if defined(__BIG_ENDIAN__)
260+
unsigned numPayloadTagBytes = std::min(size_t(4), payloadSize);
261+
memcpy(valueAddr,
262+
reinterpret_cast<uint8_t*>(&payloadIndex) + 4 - numPayloadTagBytes,
263+
numPayloadTagBytes);
264+
if (payloadSize > 4)
265+
memset(valueAddr + 4, 0, payloadSize - 4);
266+
memcpy(extraTagBitAddr,
267+
reinterpret_cast<uint8_t*>(&extraTagIndex) + 4 - numExtraTagBytes,
268+
numExtraTagBytes);
269+
#else
251270
memcpy(valueAddr, &payloadIndex, std::min(size_t(4), payloadSize));
252271
if (payloadSize > 4)
253272
memset(valueAddr + 4, 0, payloadSize - 4);
254273
memcpy(extraTagBitAddr, &extraTagIndex, numExtraTagBytes);
274+
#endif
255275
}
256276

257277
void
@@ -312,17 +332,29 @@ static void storeMultiPayloadTag(OpaqueValue *value,
312332
MultiPayloadLayout layout,
313333
unsigned tag) {
314334
auto tagBytes = reinterpret_cast<char *>(value) + layout.payloadSize;
335+
#if defined(__BIG_ENDIAN__)
336+
small_memcpy(tagBytes,
337+
reinterpret_cast<char *>(&tag) + 4 - layout.numTagBytes,
338+
layout.numTagBytes);
339+
#else
315340
small_memcpy(tagBytes, &tag, layout.numTagBytes);
341+
#endif
316342
}
317343

318344
static void storeMultiPayloadValue(OpaqueValue *value,
319345
MultiPayloadLayout layout,
320346
unsigned payloadValue) {
321347
auto bytes = reinterpret_cast<char *>(value);
322-
348+
#if defined(__BIG_ENDIAN__)
349+
unsigned numPayloadValueBytes =
350+
std::min(layout.payloadSize, sizeof(payloadValue));
351+
memcpy(bytes,
352+
reinterpret_cast<char *>(&payloadValue) + 4 - numPayloadValueBytes,
353+
numPayloadValueBytes);
354+
#else
323355
memcpy(bytes, &payloadValue,
324356
std::min(layout.payloadSize, sizeof(payloadValue)));
325-
357+
#endif
326358
// If the payload is larger than the value, zero out the rest.
327359
if (layout.payloadSize > sizeof(payloadValue))
328360
memset(bytes + sizeof(payloadValue), 0,
@@ -334,7 +366,12 @@ static unsigned loadMultiPayloadTag(const OpaqueValue *value,
334366
auto tagBytes = reinterpret_cast<const char *>(value) + layout.payloadSize;
335367

336368
unsigned tag = 0;
369+
#if defined(__BIG_ENDIAN__)
370+
small_memcpy(reinterpret_cast<char *>(&tag) + 4 - layout.numTagBytes,
371+
tagBytes, layout.numTagBytes);
372+
#else
337373
small_memcpy(&tag, tagBytes, layout.numTagBytes);
374+
#endif
338375

339376
return tag;
340377
}
@@ -343,8 +380,15 @@ static unsigned loadMultiPayloadValue(const OpaqueValue *value,
343380
MultiPayloadLayout layout) {
344381
auto bytes = reinterpret_cast<const char *>(value);
345382
unsigned payloadValue = 0;
383+
#if defined(__BIG_ENDIAN__)
384+
unsigned numPayloadValueBytes =
385+
std::min(layout.payloadSize, sizeof(payloadValue));
386+
memcpy(reinterpret_cast<char *>(&payloadValue) + 4 - numPayloadValueBytes,
387+
bytes, numPayloadValueBytes);
388+
#else
346389
memcpy(&payloadValue, bytes,
347390
std::min(layout.payloadSize, sizeof(payloadValue)));
391+
#endif
348392
return payloadValue;
349393
}
350394

0 commit comments

Comments
 (0)