Skip to content

Commit

Permalink
Add support for Linux s390x. LLVM's Swift calling convention support …
Browse files Browse the repository at this point in the history
…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.
  • Loading branch information
bryanpkc committed May 25, 2016
1 parent bb3486d commit 85fde8b
Show file tree
Hide file tree
Showing 32 changed files with 189 additions and 49 deletions.
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,8 @@ else()
set(SWIFT_HOST_VARIANT_ARCH_default "powerpc64")
elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc64le")
set(SWIFT_HOST_VARIANT_ARCH_default "powerpc64le")
elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "s390x")
set(SWIFT_HOST_VARIANT_ARCH_default "s390x")
# FIXME: Only matches v6l/v7l - by far the most common variants
elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "armv6l")
set(SWIFT_HOST_VARIANT_ARCH_default "armv6")
Expand Down Expand Up @@ -507,6 +509,8 @@ if("${SWIFT_HOST_VARIANT_SDK}" STREQUAL "LINUX")
set(SWIFT_HOST_TRIPLE "aarch64-unknown-linux-gnu")
elseif("${SWIFT_HOST_VARIANT_ARCH}" MATCHES "(powerpc64|powerpc64le)")
set(SWIFT_HOST_TRIPLE "${SWIFT_HOST_VARIANT_ARCH}-unknown-linux-gnu")
elseif("${SWIFT_HOST_VARIANT_ARCH}" MATCHES "s390x")
set(SWIFT_HOST_TRIPLE "s390x-unknown-linux-gnu")
elseif("${SWIFT_HOST_VARIANT_ARCH}" MATCHES "(armv6|armv7)")
set(SWIFT_HOST_TRIPLE "${SWIFT_HOST_VARIANT_ARCH}-unknown-linux-gnueabihf")
else()
Expand Down
3 changes: 2 additions & 1 deletion cmake/modules/SwiftSetIfArchBitness.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ function(set_if_arch_bitness var_name)
"${SIA_ARCH}" STREQUAL "arm64" OR
"${SIA_ARCH}" STREQUAL "aarch64" OR
"${SIA_ARCH}" STREQUAL "powerpc64" OR
"${SIA_ARCH}" STREQUAL "powerpc64le")
"${SIA_ARCH}" STREQUAL "powerpc64le" OR
"${SIA_ARCH}" STREQUAL "s390x")
set("${var_name}" "${SIA_CASE_64_BIT}" PARENT_SCOPE)
else()
message(FATAL_ERROR "Unknown architecture: ${SIA_ARCH}")
Expand Down
5 changes: 5 additions & 0 deletions include/swift/ABI/System.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,9 @@
// Heap objects are pointer-aligned, so the low three bits are unused.
#define SWIFT_ABI_POWERPC64_SWIFT_SPARE_BITS_MASK 0x0000000000000007ULL

/*********************************** s390x ************************************/

// Top byte of pointers is unused, and heap objects are eight-byte aligned.
#define SWIFT_ABI_S390X_SWIFT_SPARE_BITS_MASK 0x0000000000000007ULL

#endif /* SWIFT_ABI_SYSTEM_H */
4 changes: 4 additions & 0 deletions include/swift/Runtime/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,12 @@
/// Does the current Swift platform use LLVM's intrinsic "swiftcall"
/// calling convention for Swift functions?
#ifndef SWIFT_USE_SWIFTCALL
#ifdef __s390x__
#define SWIFT_USE_SWIFTCALL 1
#else
#define SWIFT_USE_SWIFTCALL 0
#endif
#endif

/// Does the current Swift platform allow information other than the
/// class pointer to be stored in the isa field? If so, when deriving
Expand Down
6 changes: 4 additions & 2 deletions include/swift/Runtime/HeapObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,12 @@ using BoxPair = TwoWordPair<HeapObject *, OpaqueValue *>;
/// The heap object has an initial retain count of 1, and its metadata is set
/// such that destroying the heap object destroys the contained value.
SWIFT_RUNTIME_EXPORT
extern "C" BoxPair::Return swift_allocBox(Metadata const *type);
extern "C" BoxPair::Return swift_allocBox(Metadata const *type)
SWIFT_CC(swift);

SWIFT_RUNTIME_EXPORT
extern "C" BoxPair::Return (*_swift_allocBox)(Metadata const *type);
extern "C" BoxPair::Return (*_swift_allocBox)(Metadata const *type)
SWIFT_CC(swift);


// Allocate plain old memory. This is the generalized entry point
Expand Down
11 changes: 11 additions & 0 deletions include/swift/Runtime/Metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -1046,6 +1046,17 @@ static const uintptr_t ObjCReservedBitsMask =
static const unsigned ObjCReservedLowBits =
SWIFT_ABI_DEFAULT_OBJC_NUM_RESERVED_LOW_BITS;

#elif defined(__s390x__)

static const uintptr_t LeastValidPointerValue =
SWIFT_ABI_DEFAULT_LEAST_VALID_POINTER;
static const uintptr_t SwiftSpareBitsMask =
SWIFT_ABI_S390X_SWIFT_SPARE_BITS_MASK;
static const uintptr_t ObjCReservedBitsMask =
SWIFT_ABI_DEFAULT_OBJC_RESERVED_BITS_MASK;
static const unsigned ObjCReservedLowBits =
SWIFT_ABI_DEFAULT_OBJC_NUM_RESERVED_LOW_BITS;

#else

static const uintptr_t LeastValidPointerValue =
Expand Down
9 changes: 8 additions & 1 deletion lib/Basic/LangOptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ static const StringRef SupportedConditionalCompilationArches[] = {
"i386",
"x86_64",
"powerpc64",
"powerpc64le"
"powerpc64le",
"s390x"
};

static const StringRef SupportedConditionalCompilationEndianness[] = {
Expand Down Expand Up @@ -154,6 +155,9 @@ std::pair<bool, bool> LangOptions::setTarget(llvm::Triple triple) {
case llvm::Triple::ArchType::x86_64:
addPlatformConditionValue("arch", "x86_64");
break;
case llvm::Triple::ArchType::systemz:
addPlatformConditionValue("arch", "s390x");
break;
default:
UnsupportedArch = true;
}
Expand Down Expand Up @@ -182,6 +186,9 @@ std::pair<bool, bool> LangOptions::setTarget(llvm::Triple triple) {
case llvm::Triple::ArchType::x86_64:
addPlatformConditionValue("_endian", "little");
break;
case llvm::Triple::ArchType::systemz:
addPlatformConditionValue("_endian", "big");
break;
default:
llvm_unreachable("undefined architecture endianness");
}
Expand Down
11 changes: 11 additions & 0 deletions lib/IRGen/SwiftTargetInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,13 @@ static void configurePowerPC64(IRGenModule &IGM, const llvm::Triple &triple,
SWIFT_ABI_POWERPC64_SWIFT_SPARE_BITS_MASK);
}

/// Configures target-specific information for SystemZ platforms.
static void configureSystemZ(IRGenModule &IGM, const llvm::Triple &triple,
SwiftTargetInfo &target) {
setToMask(target.PointerSpareBits, 64,
SWIFT_ABI_S390X_SWIFT_SPARE_BITS_MASK);
}

/// Configure a default target.
SwiftTargetInfo::SwiftTargetInfo(
llvm::Triple::ObjectFormatType outputObjectFormat,
Expand Down Expand Up @@ -154,6 +161,10 @@ SwiftTargetInfo SwiftTargetInfo::get(IRGenModule &IGM) {
configurePowerPC64(IGM, triple, target);
break;

case llvm::Triple::systemz:
configureSystemZ(IGM, triple, target);
break;

default:
// FIXME: Complain here? Default target info is unlikely to be correct.
break;
Expand Down
2 changes: 1 addition & 1 deletion stdlib/private/SwiftPrivate/PRNG.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public func rand64() -> UInt64 {
public func randInt() -> Int {
#if arch(i386) || arch(arm)
return Int(Int32(bitPattern: rand32()))
#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le)
#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) || arch(s390x)
return Int(Int64(bitPattern: rand64()))
#else
fatalError("unimplemented")
Expand Down
13 changes: 13 additions & 0 deletions stdlib/public/core/Builtin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,19 @@ internal var _objectPointerLowSpareBitShift: UInt {
internal var _objCTaggedPointerBits: UInt {
@inline(__always) get { return 0 }
}
#elseif arch(s390x)
internal var _objectPointerSpareBits: UInt {
@inline(__always) get { return 0x0000_0000_0000_0007 }
}
internal var _objectPointerIsObjCBit: UInt {
@inline(__always) get { return 0x0000_0000_0000_0002 }
}
internal var _objectPointerLowSpareBitShift: UInt {
@inline(__always) get { return 0 }
}
internal var _objCTaggedPointerBits: UInt {
@inline(__always) get { return 0 }
}
#endif

/// Extract the raw bits of `x`.
Expand Down
24 changes: 8 additions & 16 deletions stdlib/public/core/FixedPoint.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -265,25 +265,21 @@ public struct ${Self}
/// byte order if necessary.
@_transparent public
init(bigEndian value: ${Self}) {
#if arch(i386) || arch(x86_64) || arch(arm) || arch(arm64) || arch(powerpc64le)
self = ${Self}(Builtin.int_bswap_${BuiltinName}(value._value) )
#elseif arch(powerpc64)
#if _endian(big)
self = value
#else
_UnsupportedArchitectureError()
self = ${Self}(Builtin.int_bswap_${BuiltinName}(value._value) )
#endif
}

/// Creates an integer from its little-endian representation, changing the
/// byte order if necessary.
@_transparent public
init(littleEndian value: ${Self}) {
#if arch(i386) || arch(x86_64) || arch(arm) || arch(arm64) || arch(powerpc64le)
#if _endian(little)
self = value
#elseif arch(powerpc64)
self = ${Self}(Builtin.int_bswap_${BuiltinName}(value._value) )
#else
_UnsupportedArchitectureError()
self = ${Self}(Builtin.int_bswap_${BuiltinName}(value._value) )
#endif
}
% end
Expand All @@ -303,23 +299,19 @@ public struct ${Self}
/// Returns the big-endian representation of the integer, changing the
/// byte order if necessary.
public var bigEndian: ${Self} {
#if arch(i386) || arch(x86_64) || arch(arm) || arch(arm64) || arch(powerpc64le)
return ${Self}(Builtin.int_bswap_${BuiltinName}(_value))
#elseif arch(powerpc64)
#if _endian(big)
return self
#else
_UnsupportedArchitectureError()
return ${Self}(Builtin.int_bswap_${BuiltinName}(_value))
#endif
}
/// Returns the little-endian representation of the integer, changing the
/// byte order if necessary.
public var littleEndian: ${Self} {
#if arch(i386) || arch(x86_64) || arch(arm) || arch(arm64) || arch(powerpc64le)
#if _endian(little)
return self
#elseif arch(powerpc64)
return ${Self}(Builtin.int_bswap_${BuiltinName}(_value))
#else
_UnsupportedArchitectureError()
return ${Self}(Builtin.int_bswap_${BuiltinName}(_value))
#endif
}
% end
Expand Down
4 changes: 2 additions & 2 deletions stdlib/public/core/Hashing.swift
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public // @testable
func _mixUInt(_ value: UInt) -> UInt {
#if arch(i386) || arch(arm)
return UInt(_mixUInt32(UInt32(value)))
#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le)
#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) || arch(s390x)
return UInt(_mixUInt64(UInt64(value)))
#endif
}
Expand All @@ -121,7 +121,7 @@ public // @testable
func _mixInt(_ value: Int) -> Int {
#if arch(i386) || arch(arm)
return Int(_mixInt32(Int32(value)))
#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le)
#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) || arch(s390x)
return Int(_mixInt64(Int64(value)))
#endif
}
Expand Down
8 changes: 4 additions & 4 deletions stdlib/public/core/Runtime.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ func _stdlib_atomicCompareExchangeStrongInt(
object: UnsafeMutablePointer(target),
expected: UnsafeMutablePointer(expected),
desired: UInt32(bitPattern: Int32(desired)))
#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le)
#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) || arch(s390x)
return _stdlib_atomicCompareExchangeStrongUInt64(
object: UnsafeMutablePointer(target),
expected: UnsafeMutablePointer(expected),
Expand All @@ -205,7 +205,7 @@ func _swift_stdlib_atomicStoreInt(
return _swift_stdlib_atomicStoreUInt32(
object: UnsafeMutablePointer(target),
desired: UInt32(bitPattern: Int32(desired)))
#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le)
#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) || arch(s390x)
return _swift_stdlib_atomicStoreUInt64(
object: UnsafeMutablePointer(target),
desired: UInt64(bitPattern: Int64(desired)))
Expand All @@ -219,7 +219,7 @@ public func _swift_stdlib_atomicLoadInt(
return Int(Int32(bitPattern:
_swift_stdlib_atomicLoadUInt32(
object: UnsafeMutablePointer(target))))
#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le)
#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) || arch(s390x)
return Int(Int64(bitPattern:
_swift_stdlib_atomicLoadUInt64(
object: UnsafeMutablePointer(target))))
Expand Down Expand Up @@ -259,7 +259,7 @@ public func _swift_stdlib_atomicFetch${operation}Int(
_swift_stdlib_atomicFetch${operation}UInt32(
object: UnsafeMutablePointer(target),
operand: UInt32(bitPattern: Int32(operand)))))
#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le)
#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) || arch(s390x)
return Int(Int64(bitPattern:
_swift_stdlib_atomicFetch${operation}UInt64(
object: UnsafeMutablePointer(target),
Expand Down
54 changes: 49 additions & 5 deletions stdlib/public/runtime/Enum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,16 @@ swift::swift_getEnumCaseSinglePayload(const OpaqueValue *value,
auto *valueAddr = reinterpret_cast<const uint8_t*>(value);
auto *extraTagBitAddr = valueAddr + payloadSize;
unsigned extraTagBits = 0;
// FIXME: endianness
unsigned numBytes = getNumTagBytes(payloadSize,
emptyCases-payloadNumExtraInhabitants,
1 /*payload case*/);

#if defined(__BIG_ENDIAN__)
small_memcpy(reinterpret_cast<uint8_t*>(&extraTagBits) + 4 - numBytes,
extraTagBitAddr, numBytes);
#else
small_memcpy(&extraTagBits, extraTagBitAddr, numBytes);
#endif

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

// In practice we should need no more than four bytes from the payload
// area.
// FIXME: endianness.
unsigned caseIndexFromValue = 0;
#if defined(__BIG_ENDIAN__)
unsigned numPayloadTagBytes = std::min(size_t(4), payloadSize);
memcpy(reinterpret_cast<uint8_t*>(&caseIndexFromValue) + 4 -
numPayloadTagBytes, valueAddr, numPayloadTagBytes);
#else
memcpy(&caseIndexFromValue, valueAddr,
std::min(size_t(4), payloadSize));
#endif
return (caseIndexFromExtraTagBits | caseIndexFromValue)
+ payloadNumExtraInhabitants;
}
Expand Down Expand Up @@ -247,11 +256,22 @@ swift::swift_storeEnumTagSinglePayload(OpaqueValue *value,
}

// Store into the value.
// FIXME: endianness.
#if defined(__BIG_ENDIAN__)
unsigned numPayloadTagBytes = std::min(size_t(4), payloadSize);
memcpy(valueAddr,
reinterpret_cast<uint8_t*>(&payloadIndex) + 4 - numPayloadTagBytes,
numPayloadTagBytes);
if (payloadSize > 4)
memset(valueAddr + 4, 0, payloadSize - 4);
memcpy(extraTagBitAddr,
reinterpret_cast<uint8_t*>(&extraTagIndex) + 4 - numExtraTagBytes,
numExtraTagBytes);
#else
memcpy(valueAddr, &payloadIndex, std::min(size_t(4), payloadSize));
if (payloadSize > 4)
memset(valueAddr + 4, 0, payloadSize - 4);
memcpy(extraTagBitAddr, &extraTagIndex, numExtraTagBytes);
#endif
}

void
Expand Down Expand Up @@ -312,17 +332,29 @@ static void storeMultiPayloadTag(OpaqueValue *value,
MultiPayloadLayout layout,
unsigned tag) {
auto tagBytes = reinterpret_cast<char *>(value) + layout.payloadSize;
#if defined(__BIG_ENDIAN__)
small_memcpy(tagBytes,
reinterpret_cast<char *>(&tag) + 4 - layout.numTagBytes,
layout.numTagBytes);
#else
small_memcpy(tagBytes, &tag, layout.numTagBytes);
#endif
}

static void storeMultiPayloadValue(OpaqueValue *value,
MultiPayloadLayout layout,
unsigned payloadValue) {
auto bytes = reinterpret_cast<char *>(value);

#if defined(__BIG_ENDIAN__)
unsigned numPayloadValueBytes =
std::min(layout.payloadSize, sizeof(payloadValue));
memcpy(bytes,
reinterpret_cast<char *>(&payloadValue) + 4 - numPayloadValueBytes,
numPayloadValueBytes);
#else
memcpy(bytes, &payloadValue,
std::min(layout.payloadSize, sizeof(payloadValue)));
#endif
// If the payload is larger than the value, zero out the rest.
if (layout.payloadSize > sizeof(payloadValue))
memset(bytes + sizeof(payloadValue), 0,
Expand All @@ -334,7 +366,12 @@ static unsigned loadMultiPayloadTag(const OpaqueValue *value,
auto tagBytes = reinterpret_cast<const char *>(value) + layout.payloadSize;

unsigned tag = 0;
#if defined(__BIG_ENDIAN__)
small_memcpy(reinterpret_cast<char *>(&tag) + 4 - layout.numTagBytes,
tagBytes, layout.numTagBytes);
#else
small_memcpy(&tag, tagBytes, layout.numTagBytes);
#endif

return tag;
}
Expand All @@ -343,8 +380,15 @@ static unsigned loadMultiPayloadValue(const OpaqueValue *value,
MultiPayloadLayout layout) {
auto bytes = reinterpret_cast<const char *>(value);
unsigned payloadValue = 0;
#if defined(__BIG_ENDIAN__)
unsigned numPayloadValueBytes =
std::min(layout.payloadSize, sizeof(payloadValue));
memcpy(reinterpret_cast<char *>(&payloadValue) + 4 - numPayloadValueBytes,
bytes, numPayloadValueBytes);
#else
memcpy(&payloadValue, bytes,
std::min(layout.payloadSize, sizeof(payloadValue)));
#endif
return payloadValue;
}

Expand Down
Loading

0 comments on commit 85fde8b

Please sign in to comment.