[AVR] IRGen traps on lowering (invalid cast assertion thrown by LLVM)

I created a freshly built compiler with the current trunk (55189bae8e) and tried to compile IR with a stub file a.swift, with the contents...

import Swift

// nothing yet

Then I tried to compile it using much the same command line as the test test/embedded/avr/testStdlibFunctioning.swift but changing the parameter -typecheck to -emit-ir so that IRGen is activated. It traps in IRGen due to LLVM trapping on an invalid cast assertion...

carl@LT1152 bin % ./swiftc -emit-ir -target avr-none-none-elf -enable-experimental-feature Embedded -wmo a.swift
<unknown>:0: warning: no target microcontroller specified on command line, cannot link standard libraries, please pass -mmcu=<mcu name>
Assertion failed: (castIsValid(op, S, Ty) && "Invalid cast!"), function Create, file Instructions.cpp, line 2974.
Please submit a bug report (https://swift.org/contributing/#reporting-bugs) and include the crash backtrace.
Stack dump:
0.	Program arguments: /Users/carl/Documents/Code/swift/build/Ninja-RelWithDebInfoAssert/swift-macosx-arm64/bin/swift-frontend -frontend -emit-ir a.swift -target avr-none-none-elf -disable-objc-interop -color-diagnostics -enable-experimental-feature Embedded -empty-abi-descriptor -resource-dir /Users/carl/Documents/Code/swift/build/Ninja-RelWithDebInfoAssert/swift-macosx-arm64/lib/swift -module-name a -in-process-plugin-server-path /Users/carl/Documents/Code/swift/build/Ninja-RelWithDebInfoAssert/swift-macosx-arm64/lib/swift/host/libSwiftInProcPluginServer.dylib -plugin-path /Users/carl/Documents/Code/swift/build/Ninja-RelWithDebInfoAssert/swift-macosx-arm64/lib/swift/host/plugins -plugin-path /Users/carl/Documents/Code/swift/build/Ninja-RelWithDebInfoAssert/swift-macosx-arm64/local/lib/swift/host/plugins -o -
1.	Swift version 6.2-dev (LLVM 9f6c3d784782c34, Swift 55189bae8e55169)
2.	Compiling with effective version 5.10
3.	While evaluating request IRGenRequest(IR Generation for module a)
4.	While emitting IR SIL function "@swift_once".
 for <<debugloc at "<compiler-generated>":0:0>>Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it):
0  swift-frontend           0x0000000106932f90 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) + 56
1  swift-frontend           0x00000001069314b4 llvm::sys::RunSignalHandlers() + 112
2  swift-frontend           0x0000000106933608 SignalHandler(int) + 332
3  libsystem_platform.dylib 0x000000019e0db584 _sigtramp + 56
4  libsystem_pthread.dylib  0x000000019e0aac20 pthread_kill + 288
5  libsystem_c.dylib        0x000000019dfb7a20 abort + 180
6  libsystem_c.dylib        0x000000019dfb6d10 err + 0
7  swift-frontend           0x000000010850701c llvm::CastInst::CreateZExtOrBitCast(llvm::Value*, llvm::Type*, llvm::Twine const&, llvm::InsertPosition) (.cold.1) + 0
8  swift-frontend           0x0000000106760edc llvm::CastInst::Create(llvm::Instruction::CastOps, llvm::Value*, llvm::Type*, llvm::Twine const&, llvm::InsertPosition) + 772
9  swift-frontend           0x0000000100ae3474 llvm::IRBuilderBase::CreateBitCast(llvm::Value*, llvm::Type*, llvm::Twine const&) + 124
10 swift-frontend           0x0000000100affc2c swift::irgen::IRGenFunction::coerceValue(llvm::Value*, llvm::Type*, llvm::DataLayout const&) + 180
11 swift-frontend           0x0000000100b0898c swift::irgen::emitForeignParameter(swift::irgen::IRGenFunction&, swift::irgen::Explosion&, swift::irgen::ForeignFunctionInfo, unsigned int, swift::SILType, swift::irgen::LoadableTypeInfo const&, swift::irgen::Explosion&, bool) + 764
12 swift-frontend           0x0000000100ce2890 (anonymous namespace)::IRGenSILFunction::emitSILFunction() + 4072
13 swift-frontend           0x0000000100ce1324 swift::irgen::IRGenModule::emitSILFunction(swift::SILFunction*) + 1816
14 swift-frontend           0x0000000100b61a5c swift::irgen::IRGenerator::emitGlobalTopLevel(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>>> const&) + 752
15 swift-frontend           0x0000000100c786b0 swift::IRGenRequest::evaluate(swift::Evaluator&, swift::IRGenDescriptor) const + 2212
16 swift-frontend           0x0000000100ce0784 swift::GeneratedModule swift::SimpleRequest<swift::IRGenRequest, swift::GeneratedModule (swift::IRGenDescriptor), (swift::RequestFlags)17>::callDerived<0ul>(swift::Evaluator&, std::__1::integer_sequence<unsigned long, 0ul>) const + 176
17 swift-frontend           0x0000000100c818fc swift::IRGenRequest::OutputType swift::Evaluator::getResultUncached<swift::IRGenRequest, swift::IRGenRequest::OutputType swift::evaluateOrFatal<swift::IRGenRequest>(swift::Evaluator&, swift::IRGenRequest)::'lambda'()>(swift::IRGenRequest const&, swift::IRGenRequest::OutputType swift::evaluateOrFatal<swift::IRGenRequest>(swift::Evaluator&, swift::IRGenRequest)::'lambda'()) + 196
18 swift-frontend           0x0000000100c79768 swift::performIRGeneration(swift::ModuleDecl*, swift::IRGenOptions const&, swift::TBDGenOptions const&, std::__1::unique_ptr<swift::SILModule, std::__1::default_delete<swift::SILModule>>, llvm::StringRef, swift::PrimarySpecificPaths const&, llvm::ArrayRef<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>>, llvm::GlobalVariable**) + 1420
19 swift-frontend           0x00000001007254d0 generateIR(swift::IRGenOptions const&, swift::TBDGenOptions const&, std::__1::unique_ptr<swift::SILModule, std::__1::default_delete<swift::SILModule>>, swift::PrimarySpecificPaths const&, llvm::StringRef, llvm::PointerUnion<swift::ModuleDecl*, swift::SourceFile*>, llvm::GlobalVariable*&, llvm::ArrayRef<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>>) + 272
20 swift-frontend           0x0000000100721b04 performCompileStepsPostSILGen(swift::CompilerInstance&, std::__1::unique_ptr<swift::SILModule, std::__1::default_delete<swift::SILModule>>, llvm::PointerUnion<swift::ModuleDecl*, swift::SourceFile*>, swift::PrimarySpecificPaths const&, int&, swift::FrontendObserver*) + 1336
21 swift-frontend           0x00000001007212b8 swift::performCompileStepsPostSema(swift::CompilerInstance&, int&, swift::FrontendObserver*) + 768
22 swift-frontend           0x000000010072db3c withSemanticAnalysis(swift::CompilerInstance&, swift::FrontendObserver*, llvm::function_ref<bool (swift::CompilerInstance&)>, bool) + 160
23 swift-frontend           0x0000000100722c08 performCompile(swift::CompilerInstance&, int&, swift::FrontendObserver*) + 700
24 swift-frontend           0x0000000100722464 swift::performFrontend(llvm::ArrayRef<char const*>, char const*, void*, swift::FrontendObserver*) + 2180
25 swift-frontend           0x00000001004d7384 swift::mainEntry(int, char const**) + 3104
26 dyld                     0x000000019dd220e0 start + 2360


I expected errors like this to occur when we started to emit IR because I had a lot of similar issues over the years with my own forks. It's always issues related to address space on AVR.

Running in a debug build of swift, I found the assertions occurs in this IRGen...

(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = hit program assert
    frame #0: 0x000000019e072a60 libsystem_kernel.dylib`__pthread_kill + 8
    frame #1: 0x000000019e0aac20 libsystem_pthread.dylib`pthread_kill + 288
    frame #2: 0x000000019dfb7a20 libsystem_c.dylib`abort + 180
    frame #3: 0x000000019dfb6d10 libsystem_c.dylib`__assert_rtn + 284
    frame #4: 0x000000010a3f0db0 swift-frontend`llvm::CastInst::Create(llvm::Instruction::CastOps, llvm::Value*, llvm::Type*, llvm::Twine const&, llvm::InsertPosition) (.cold.1) at Instructions.cpp:2974:3 [opt]
    frame #5: 0x0000000108d5ac70 swift-frontend`llvm::CastInst::Create(op=BitCast, S=0x000060000283bb28, Ty=0x00000001261a4800, Name=0x000000016fdf2630, InsertBefore=<unavailable>) at Instructions.cpp:2974:3 [opt]
    frame #6: 0x0000000100a85adc swift-frontend`llvm::IRBuilderBase::CreateCast(this=0x000000016fdf3c10, Op=BitCast, V=0x000060000283bb28, DestTy=0x00000001261a4800, Name=0x000000016fdf2a28) at IRBuilder.h:2172:19
    frame #7: 0x0000000100a85988 swift-frontend`llvm::IRBuilderBase::CreateBitCast(this=0x000000016fdf3c10, V=0x000060000283bb28, DestTy=0x00000001261a4800, Name=0x000000016fdf2a28) at IRBuilder.h:2134:12
  * frame #8: 0x0000000100ace8fc swift-frontend`swift::irgen::IRGenFunction::coerceValue(this=0x000000016fdf3c08, value=0x000060000283bb28, toTy=0x00000001261a4800, DL=0x000000016fdf4c90) at GenCall.cpp:5447:22
    frame #9: 0x0000000100adb010 swift-frontend`emitDirectForeignParameter(IGF=0x000000016fdf3c08, in=0x000000016fdf39c0, AI=0x000000016fdf3070, out=0x000000016fdf3438, paramType=SILType @ 0x000000016fdf2f90, paramTI=0x0000000122971bb0) at GenCall.cpp:4705:21
    frame #10: 0x0000000100adac38 swift-frontend`swift::irgen::emitForeignParameter(IGF=0x000000016fdf3c08, params=0x000000016fdf39c0, foreignInfo=ForeignFunctionInfo @ 0x000000016fdf30d0, foreignParamIndex=1, paramTy=SILType @ 0x000000016fdf3110, paramTI=0x0000000122971bb0, paramExplosion=0x000000016fdf3438, isOutlined=false) at GenCall.cpp:4772:5
    frame #11: 0x000000010102656c swift-frontend`emitEntryPointArgumentsCOrObjC(IGF=0x000000016fdf3c08, entry=0x00000001261a1670, params=0x000000016fdf39c0, funcTy=swift::CanSILFunctionType @ 0x000000016fdf3428) at IRGenSIL.cpp:2444:5
    frame #12: 0x000000010101ae1c swift-frontend`(anonymous namespace)::IRGenSILFunction::emitSILFunction(this=0x000000016fdf3c08) at IRGenSIL.cpp:2676:5
    frame #13: 0x000000010101a308 swift-frontend`swift::irgen::IRGenModule::emitSILFunction(this=0x000000016fdf4c68, f=0x00000001261a1420) at IRGenSIL.cpp:2573:30
    frame #14: 0x0000000100c83cd0 swift-frontend`swift::irgen::IRGenerator::emitGlobalTopLevel(this=0x000000016fdf7078, linkerDirectives=size=0) at GenDecl.cpp:1222:10
    frame #15: 0x0000000100f187d8 swift-frontend`swift::IRGenRequest::evaluate(this=0x000000016fdf7c50, evaluator=0x0000000126008880, desc=IRGenDescriptor @ 0x000000016fdf78c0) const at IRGen.cpp:1259:11
    frame #16: 0x0000000101018e54 swift-frontend`swift::GeneratedModule swift::SimpleRequest<swift::IRGenRequest, swift::GeneratedModule (swift::IRGenDescriptor), (swift::RequestFlags)17>::callDerived<0ul>(this=0x000000016fdf7c50, evaluator=0x0000000126008880, (null)=std::__1::index_sequence<0UL> @ 0x000000016fdf78b7) const at SimpleRequest.h:287:24
    frame #17: 0x0000000101018d60 swift-frontend`swift::SimpleRequest<swift::IRGenRequest, swift::GeneratedModule (swift::IRGenDescriptor), (swift::RequestFlags)17>::evaluateRequest(request=0x000000016fdf7c50, evaluator=0x0000000126008880) at SimpleRequest.h:311:20
    frame #18: 0x0000000100f45c80 swift-frontend`swift::IRGenRequest::OutputType swift::Evaluator::getResultUncached<swift::IRGenRequest, swift::IRGenRequest::OutputType swift::evaluateOrFatal<swift::IRGenRequest>(swift::Evaluator&, swift::IRGenRequest)::'lambda'()>(this=0x0000000126008880, request=0x000000016fdf7c50, defaultValueFn=(unnamed class) @ 0x000000016fdf7a6f) at Evaluator.h:347:19
    frame #19: 0x0000000100f45b7c swift-frontend`swift::IRGenRequest::OutputType swift::Evaluator::operator()<swift::IRGenRequest, swift::IRGenRequest::OutputType swift::evaluateOrFatal<swift::IRGenRequest>(swift::Evaluator&, swift::IRGenRequest)::'lambda'(), (void*)0>(this=0x0000000126008880, request=0x000000016fdf7c50, defaultValueFn=(unnamed class) @ 0x000000016fdf7ac7) at Evaluator.h:235:12
    frame #20: 0x0000000100f1a808 swift-frontend`swift::IRGenRequest::OutputType swift::evaluateOrFatal<swift::IRGenRequest>(eval=0x0000000126008880, req=IRGenRequest @ 0x000000016fdf7c50) at Evaluator.h:448:10
    frame #21: 0x0000000100f19c48 swift-frontend`swift::performIRGeneration(M=0x00000001260cea00, Opts=0x00000001248376e0, TBDOpts=0x0000000124837bc8, SILMod=nullptr, ModuleName=(Data = "-", Length = 1), PSPs=0x000000016fdf8950, parallelOutputFilenames=(Data = "-", Length = 1), outModuleHash=0x000000016fdf8158) at IRGen.cpp:1673:10
    frame #22: 0x00000001003d28c4 swift-frontend`generateIR(IRGenOpts=0x00000001248376e0, TBDOpts=0x0000000124837bc8, SM=nullptr, PSPs=0x000000016fdf8950, OutputFilename=(Data = "-", Length = 1), MSF=swift::ModuleOrSourceFile @ 0x000000016fdf7fd0, HashGlobal=0x000000016fdf8158, parallelOutputFilenames=(Data = "-", Length = 1)) at FrontendTool.cpp:1426:12
    frame #23: 0x00000001003cd540 swift-frontend`performCompileStepsPostSILGen(Instance=0x0000000124836400, SM=nullptr, MSF=swift::ModuleOrSourceFile @ 0x000000016fdf82b0, PSPs=0x000000016fdf8950, ReturnValue=0x000000016fdf9cfc, observer=0x0000000000000000) at FrontendTool.cpp:1782:7
    frame #24: 0x00000001003cc73c swift-frontend`swift::performCompileStepsPostSema(Instance=0x0000000124836400, ReturnValue=0x000000016fdf9cfc, observer=0x0000000000000000) at FrontendTool.cpp:732:12
    frame #25: 0x00000001003eefac swift-frontend`performAction(swift::CompilerInstance&, int&, swift::FrontendObserver*)::$_27::operator()(this=0x000000016fdf9760, Instance=0x0000000124836400) const at FrontendTool.cpp:1296:18
    frame #26: 0x00000001003eef10 swift-frontend`bool llvm::function_ref<bool (swift::CompilerInstance&)>::callback_fn<performAction(swift::CompilerInstance&, int&, swift::FrontendObserver*)::$_27>(callable=6171891552, params=0x0000000124836400) at STLFunctionalExtras.h:45:12
    frame #27: 0x00000001003ee2a8 swift-frontend`llvm::function_ref<bool (swift::CompilerInstance&)>::operator()(this=0x000000016fdf9698, params=0x0000000124836400) const at STLFunctionalExtras.h:68:12
    frame #28: 0x00000001003ed180 swift-frontend`withSemanticAnalysis(Instance=0x0000000124836400, observer=0x0000000000000000, cont=function_ref<bool (swift::CompilerInstance &)> @ 0x000000016fdf9698, runDespiteErrors=false) at FrontendTool.cpp:1155:10
    frame #29: 0x00000001003e7888 swift-frontend`performAction(Instance=0x0000000124836400, ReturnValue=0x000000016fdf9cfc, observer=0x0000000000000000) at FrontendTool.cpp:1292:12
    frame #30: 0x00000001003cebac swift-frontend`performCompile(Instance=0x0000000124836400, ReturnValue=0x000000016fdf9cfc, observer=0x0000000000000000) at FrontendTool.cpp:1368:19
    frame #31: 0x00000001003cdfe4 swift-frontend`swift::performFrontend(Args=ArrayRef<const char *> @ 0x000000016fdf9ef0, Argv0="/Users/carl/Documents/Code/swift/build/Ninja-RelWithDebInfoAssert+swift-DebugAssert/swift-macosx-arm64/bin/swift-frontend", MainAddr=0x000000010003720c, observer=0x0000000000000000) at FrontendTool.cpp:2078:19
    frame #32: 0x0000000100038830 swift-frontend`run_driver(ExecName=(Data = "swift-frontend", Length = 14), argv=ArrayRef<const char *> @ 0x000000016fdfc720, originalArgv=const llvm::ArrayRef<const char *> @ 0x000000016fdfc710) at driver.cpp:296:14
    frame #33: 0x00000001000376d0 swift-frontend`swift::mainEntry(argc_=8, argv_=0x000000016fdff388) at driver.cpp:530:10
    frame #34: 0x0000000100036e54 swift-frontend`main(argc_=8, argv_=0x000000016fdff388) at driver.cpp:20:10
    frame #35: 0x000000019dd220e0 dyld`start + 2360

The failing cast is in IRGenFunction::coerceValue...

(lldb) fr s 8
frame #8: 0x0000000100ace8fc swift-frontend`swift::irgen::IRGenFunction::coerceValue(this=0x000000016fdf3c08, value=0x000060000283bb28, toTy=0x00000001261a4800, DL=0x000000016fdf4c90) at GenCall.cpp:5447:22
   5444	  // Use the pointer/pointer and pointer/int casts if we can.
   5445	  if (toTy->isPointerTy()) {
   5446	    if (fromTy->isPointerTy())
-> 5447	      return Builder.CreateBitCast(value, toTy);
   5448	    if (fromTy == IGM.IntPtrTy)
   5449	      return Builder.CreateIntToPtr(value, toTy);
   5450	  } else if (fromTy->isPointerTy()) {
(lldb) e toTy->dump()
ptr
(lldb) e value->dump()
ptr addrspace(1) %1

LLVM refuses to coerce a ptr addrspace(1) %1 Value to ptr type.

Moving up to frame 13 emitSILFunction to get a bit of context, the code being called is...

frame #13: 0x000000010101a308 swift-frontend`swift::irgen::IRGenModule::emitSILFunction(this=0x000000016fdf4c68, f=0x00000001261a1420) at IRGenSIL.cpp:2573:30
   2570	    noteUseOfMetadataByCXXInterop(IRGen, f, TypeExpansionContext(*f));
   2571	
   2572	  PrettyStackTraceSILFunction stackTrace("emitting IR", f);
-> 2573	  IRGenSILFunction(*this, f).emitSILFunction();
   2574	}
   2575	
   2576	void IRGenSILFunction::emitSILFunction() {

And the SIL function in question is something like a thunk related to swift_once...

(lldb) e f->dump()
// swift_once
sil [thunk] @swift_once : $@convention(c) (UnsafeMutablePointer<Int>, @convention(c) (UnsafeMutableRawPointer) -> (), UnsafeMutableRawPointer) -> () {
[%0: read v**.c*.v**, write v**.c*.v**, copy v**.c*.v**, destroy v**.c*.v**]
[%2: read v**.c*.v**, write v**.c*.v**, copy v**.c*.v**, destroy v**.c*.v**]
[global: read,write,copy,destroy,allocate,deinit_barrier]
// %0                                             // user: %4
// %1                                             // user: %4
// %2                                             // user: %4
bb0(%0 : $UnsafeMutablePointer<Int>, %1 : $@convention(c) (UnsafeMutableRawPointer) -> (), %2 : $UnsafeMutableRawPointer):
  // function_ref swift_once(predicate:fn:context:)
  %3 = function_ref @$es10swift_once9predicate2fn7contextySpySiG_ySvXCSvtF : $@convention(thin) (UnsafeMutablePointer<Int>, @convention(c) (UnsafeMutableRawPointer) -> (), UnsafeMutableRawPointer) -> () // user: %4
  %4 = apply %3(%0, %1, %2) : $@convention(thin) (UnsafeMutablePointer<Int>, @convention(c) (UnsafeMutableRawPointer) -> (), UnsafeMutableRawPointer) -> () // user: %5
  return %4                                       // id: %5
} // end sil function 'swift_once'

For reference, I assume (although I haven't made 100% sure) that this comes from this swift in the embedded swift runtime (in stdlib/public/core/EmbeddedRuntime.swift)...

// Once

@_cdecl("swift_once")
public func swift_once(predicate: UnsafeMutablePointer<Int>, fn: (@convention(c) (UnsafeMutableRawPointer)->()), context: UnsafeMutableRawPointer) {
  let checkedLoadAcquire = { predicate in
    let value = loadAcquire(predicate)
    assert(value == -1 || value == 0 || value == 1)
    return value
  }

  if checkedLoadAcquire(predicate) < 0 { return }

  let won = compareExchangeRelaxed(predicate, expectedOldValue: 0, desiredNewValue: 1)
  if won {
    fn(context)
    storeRelease(predicate, newValue: -1)
    return
  }

  // TODO: This should really use an OS provided lock
  while checkedLoadAcquire(predicate) >= 0 {
    // spin
  }
}

I feel like this is going to need me to write a compiler patch :slight_smile: happy to do so... if people can give me some pointers what's the best approach, what's most likely to get PR approval, what's the nicest/most friendly way to do this? If no one has input I'll just poke through the code then "hit something with a hammer until it works". :slight_smile:

All help gratefully received!

Carl

1 Like

Update: I raised a PR to fix this: [AVR] Fix broken IRGen emission due to not respecting LLVM program address space in the Datalayout by carlos4242 · Pull Request #78399 · swiftlang/swift · GitHub

It does work, but I'm not confident that it is the minimum required. We might want to trim it down. Although arguably these may all be changes we end up making in the longer run, so it might be harmless to add them now.

1 Like

This seems to have become a bit lost/ignored in the last month so I closed the PR and opened it again! [AVR] Added test for basic IRGen function. by carlos4242 · Pull Request #78810 · swiftlang/swift · GitHub