SingleEnumTagPayload Value Witness Handling

windows
(Saleem Abdulrasool) #1

I was looking at what it would take to fix SR-10192. This is the only bug that is preventing release mode builds for Foundation on Windows. Investigating it, it turns out that it is a bug in the optimization pipeline. I've managed to create a reduced test case for this:

module CoreFoundation {
  header "CoreFoundation.h"
  export *
}
typedef struct CFURLSessionInfo {
  int value;
} CFURLSessionInfo;

typedef struct CFURLSessionEasyCode {
  int value;
} CFURLSessionEasyCode;

import CoreFoundation

extension CFURLSessionInfo : Equatable {
  public static func ==(lhs: CFURLSessionInfo, rhs: CFURLSessionInfo) -> Bool {
    return lhs.value == rhs.value
  }
}

extension CFURLSessionEasyCode : Equatable {
  public static func ==(lhs: CFURLSessionEasyCode, rhs: CFURLSessionEasyCode) -> Bool {
    return lhs.value == rhs.value
  }
}

When building this, there are two symbols of interest:

  • $sSo16CFURLSessionInfoVwst
  • $sSo20CFURLSessionEasyCodeVwst

When building without optimizations both functions are emitted just fine. We attach COMDATs to both of the definitions and everything is fine. However, when building with optimizations, the pipeline "optimizes" and merges the function bodies. The result is that we get this following definition:

define linkonce_odr hidden void @"$sSo20CFURLSessionEasyCodeVwst"(%swift.opaque* noalias, i32, i32, %swift.type*) #6 {
  tail call void @"$sSo16CFURLSessionInfoVwst"(%swift.opaque* noalias %0, i32 %1, i32 %2, %swift.type* %3) #6
  ret void
}

The important thing to note here that is that the definition here does not contain a COMDAT even though the store SingleEnumTagPayload value witness is supposed to. I can't seem to figure out where the body is getting deduplicated and the function replaced. The result of this is that we end up with multiple definitions of this function which is unacceptable on PE/COFF (ELF and MachO get away with it due to the weak linkage semantics).

From the debug logging of the LLVM Merge Functions pass, it doesn't seem to be in the Swift Merge Functions pass.

CC: @Joe_Groff @John_McCall @Erik_Eckstein

(Saleem Abdulrasool) #2

CC: @vedantk

Vedant, I'm pretty sure that this is a bug in the LLVM Merge Functions IPO. When it creates the new function for the thunk, that will loose the COMDAT.