Calendar fails on s390x

Hi there,

Our team has been working on s390x support of swift 4.1. We have encountered a problem with use of Calendar in Foundation. Given the following example No.1,

import Foundation

let c: Calendar? = nil
print(c)

When using swiftc -g <file_name>, it will give seg fault at the print statement.

During debugging, we read the calendar object c by

(lldb) fr v -L c
0x000002aa000061a0: (Foundation.Calendar?) c = some {
0x000002aa000061a0:   _autoupdating = false
0x000002aa000061a8:   _handle = <uninitialized>
}

and we find the size of c by

(lldb) expr MemoryLayout.size(ofValue: c)
(Int) $R0 = 16

and we look into the memory of the calendar object c. It shows

0x2aa000061a0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x02
0x2aa000061a8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00

However, if we manually modify the memory by moving the tag 0x02 to the lower address:

(lldb) memory write 0x000002aa000061a0 0x02

The example will get passed.

We have also tried example No. 2:

import Foundation

func createOptionalNil<T>(_ t: T.Type) -> T? {
  return nil
}

public func isNone<T>(_ t: T?) -> Bool {
  if t == nil {
    return true
  } else {
    return false
  }
}

func testNil() {
  let opt = createOptionalNil(Calendar.self)
  print(opt)
}

testNil()

This example gets passed with no problem. And the memory of object opt reads as

(lldb) fr v -L opt
0x000003fffffff2a8: (Foundation.Calendar?) opt = nil
(lldb) memory read --size 1 --format x --count 16 0x000003fffffff2a8
0x3fffffff2a8: 0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x3fffffff2b0: 0x00 0x00 0x00 0x00 0xf6 0x3d 0x4e 0x2e

As we can see, the tag 0x02 locates at the lowest address which makes it be executed normally.

By assigning the Calendar object with nil in 2 ways results differently, this is confusing us. Any insights or explanations to this? To further fix this, do you guys have any suggestions on what code to look into?

Just a follow up with this thread with a hack. On the following test case:

import Foundation

let c: Calendar? = nil
print(c)

If i made the following changes:

diff --git a/lib/IRGen/EnumPayload.cpp b/lib/IRGen/EnumPayload.cpp
index cadec55..fc3393d 100644
--- a/lib/IRGen/EnumPayload.cpp
+++ b/lib/IRGen/EnumPayload.cpp
@@ -366,6 +367,10 @@ void EnumPayload::store(IRGenFunction &IGF, Address address) const {
       auto &value = PayloadValues[i];
       auto member = IGF.Builder.CreateStructGEP(address, i, offset);
       auto valueToStore = forcePayloadValue(value);
+#if defined(__BIG_ENDIAN__) && defined(__LP64__)
+      if(i==0 && valueToStore->getValueID() == llvm::Value::ConstantIntVal)
+        valueToStore = IGF.Builder.CreateShl(valueToStore,56);
+#endif
       IGF.Builder.CreateStore(valueToStore, member);
       offset += Size(IGF.IGM.DataLayout
                        .getTypeAllocSize(valueToStore->getType()));

The test would get passed without issue. However, this is an only a hacking fix, which later i found it causing regression on other swift validation test. Also this hack doesn't seem scalable and general.

Further, a more abstract test case is

struct MyCal {
        var flag: Bool
        var val: Int64
}

var ca: MyCal? = Optional<MyCal>.none
print(ca)

similar hack can also be applied.