Crash during MergeFunctions pass


I seem to be getting a crash in the MergeFunctions pass during codegen...

(lldb) bt
* thread #2, stop reason = hit program assert
    frame #0: 0x00007ff80b8e314a libsystem_kernel.dylib`__pthread_kill + 10
    frame #1: 0x00007ff80b91bebd libsystem_pthread.dylib`pthread_kill + 262
    frame #2: 0x00007ff80b841a39 libsystem_c.dylib`abort + 126
    frame #3: 0x00007ff80b840d1c libsystem_c.dylib`__assert_rtn + 314
    frame #4: 0x000000010ba20349 swift-frontend`llvm::ConstantExpr::getBitCast(C=0x0000600001247c08, DstTy=0x00007fc51f839a00, OnlyIfReduced=false) at Constants.cpp:2215:3
    frame #5: 0x00000001064cdc67 swift-frontend`(anonymous namespace)::MergeFunctions::replaceDirectCallers(this=0x0000000327373db8, Old=0x000060000125dc88, New=0x0000600001247c08) at MergeFunctions.cpp:444:26
    frame #6: 0x00000001064cb457 swift-frontend`(anonymous namespace)::MergeFunctions::mergeTwoFunctions(this=0x0000000327373db8, F=0x0000600001247c08, G=0x000060000125dc88) at MergeFunctions.cpp:834:9
  * frame #7: 0x00000001064c8dce swift-frontend`(anonymous namespace)::MergeFunctions::insert(this=0x0000000327373db8, NewFunction=0x000060000125dc88) at MergeFunctions.cpp:919:3
    frame #8: 0x00000001064c752b swift-frontend`(anonymous namespace)::MergeFunctions::runOnModule(this=0x0000000327373db8, M=0x00007fc53f705cf0) at MergeFunctions.cpp:428:20
    frame #9: 0x00000001064c6f28 swift-frontend`llvm::MergeFunctionsPass::run(this=0x0000600003e7c8d8, M=0x00007fc53f705cf0, AM=0x0000000327374450) at MergeFunctions.cpp:300:11
    frame #10: 0x00000001060538f4 swift-frontend`llvm::detail::PassModel<llvm::Module, llvm::MergeFunctionsPass, llvm::PreservedAnalyses, llvm::AnalysisManager<llvm::Module>>::run(this=0x0000600003e7c8d0, IR=0x00007fc53f705cf0, AM=0x0000000327374450) at PassManagerInternal.h:89:17
    frame #11: 0x000000010bc5df77 swift-frontend`llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(this=0x0000000327374370, IR=0x00007fc53f705cf0, AM=0x0000000327374450) at PassManager.h:517:40
    frame #12: 0x000000010102b042 swift-frontend`swift::performLLVMOptimizations(Opts=0x00007fc53f80f1f8, Module=0x00007fc53f705cf0, TargetMachine=0x00007fc520058000, out=0x00007fc51f72b9f8) at IRGen.cpp:420:7
    frame #13: 0x000000010102c058 swift-frontend`swift::performLLVM(Opts=0x00007fc53f80f1f8, Diags=0x00007fc53f80fa70, DiagMutex=0x0000000326b6c830, HashGlobal=0x0000000000000000, Module=0x00007fc53f705cf0, TargetMachine=0x00007fc520058000, OutputFilename=(Data = "bin/Embedded/serials.bc", Length = 23), Backend=0x0000600003e6c020, Stats=0x0000000000000000) at IRGen.cpp:610:3
    frame #14: 0x0000000101042a8f swift-frontend`(anonymous namespace)::LLVMCodeGenThreads::Thread::run(this=0x0000600001fb8820) at IRGen.cpp:1290:9
    frame #15: 0x00000001010427bd swift-frontend`(anonymous namespace)::LLVMCodeGenThreads::runThread(arg=0x0000600001fb8820) at IRGen.cpp:1320:13
    frame #16: 0x00007ff80b91c18b libsystem_pthread.dylib`_pthread_start + 99
    frame #17: 0x00007ff80b917ae3 libsystem_pthread.dylib`thread_start + 15

This seems to be where a function call is being replaced at the call site.

The function call being replaced is a call to this function...
define protected void @"$s3AVR5print_10addNewlineys12StaticStringV_SbtF"(i16 %0, i16 %1, i8 %2, i1 %3) local_unnamed_addr addrspace(1) #0

With a call to this function...
define internal void @"$s3AVR5print7message10addNewlineys12StaticStringV_SbtFTm"(i16 %0, i16 %1, i8 %2, i1 %3) local_unnamed_addr addrspace(0) #0

(note the addrspace)

I might have got those the wrong way around as I'm not familiar with the optimisation pass code. But the point is the function address space on AVR should always be addrspace(1) so the llvm cast fails. I was trying to investigate how s3AVR5print7message10addNewlineys12StaticStringV_SbtFTm came to be created with the wrong address space on our platform.

Swift-demangle makes it appear maybe that it's a function that is synthesised somewhere in IRGen, perhaps as part of the function merging?...
$s3AVR5print7message10addNewlineys12StaticStringV_SbtFTm ---> merged AVR.print(message: Swift.StaticString, addNewline: Swift.Bool) -> ()

(the word "merged" makes me think that)

I'm pretty adept at fixing these issues now once I can find out where the code has been emitted. Can someone please possibly point me at the bit that creates these functions as part of the optimiser pass? Then I'll make sure they respect the llvm data layout for function address spaces as a point bug fix.


Update: I wasn't clear headed or reading this correctly. This is after Swift has handed over to LLVM for "code emission"(?) I don't know what the right term is. But basically it's the (usually multithreaded) bit when the compiler passes to LLVM to optimise the IR and then lower into real machine code stuff. This is LLVM optimisation that's crashing. So I might need to talk to LLVM.

That said, I don't think LLVM ever could/should allow a call from a function in one data space to a call to a function in another data space.

And we somehow have this IR created from the front end (I think?) before it's sent to LLVM for optimisation/lowering...

; Function Attrs: minsize nounwind optsize
define protected void @"$s3AVR5print_10addNewlineys12StaticStringV_SbtF"(i16 %0, i16 %1, i8 %2, i1 %3) local_unnamed_addr addrspace(1) #0 {
  tail call addrspace(0) void @"$s3AVR5print7message10addNewlineys12StaticStringV_SbtFTm"(i16 %0, i16 %1, i8 %2, i1 %3) #0
  ret void

; Function Attrs: minsize nounwind optsize
define internal void @"$s3AVR5print7message10addNewlineys12StaticStringV_SbtFTm"(i16 %0, i16 %1, i8 %2, i1 %3) local_unnamed_addr addrspace(0) #0 {
  %5 = and i8 %2, 1
  %6 = icmp eq i8 %5, 0
  br i1 %6, label %7, label %11

7:                                                ; preds = %4
  %8 = icmp eq i16 %0, 0
  br i1 %8, label %19, label %9, !prof !8

9:                                                ; preds = %7
  %10 = inttoptr i16 %0 to ptr
  tail call addrspace(1) void @_sendStaticString(i16 %1, ptr nonnull %10, i1 zeroext %3) #11
  br label %14

11:                                               ; preds = %4
  %12 = and i16 %0, -2048
  %13 = icmp eq i16 %12, -10240
  br i1 %13, label %18, label %15, !prof !9

14:                                               ; preds = %9, %15
  ret void

15:                                               ; preds = %11
  %16 = zext i16 %0 to i32
  %17 = tail call addrspace(1) ptr @_intToString(i32 %16) #11
  tail call addrspace(1) void @_sendBuffer(i16 1000, ptr %17, i1 zeroext %3, i1 zeroext true) #11
  br label %14

18:                                               ; preds = %11
  tail call addrspace(0) void asm sideeffect "", "n"(i32 0) #11
  tail call addrspace(1) void @llvm.trap()

19:                                               ; preds = %7
  tail call addrspace(0) void asm sideeffect "", "n"(i32 2) #11
  tail call addrspace(1) void @llvm.trap()

So the "bottom" function somehow ended up with address space 0, which should be impossible on AVR (the AVR LLVM data layout is e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8).

So I'm still feeling that something on the front end is creating a function in address space 0? Perhaps somewhere in IRGen?