Debug failed verifier pass

Hi, rather a basic question I’m afraid!

I am getting a failed Verifier pass. Is there an easy way to breakpoint/dump where in the IR the verifier errors are coming from? I might have been staring at the screen too long and I’m missing the obvious…

Function return type does not match operand type of return inst!
  ret void
 i8Function return type does not match operand type of return inst!
  ret void
 i8Function return type does not match operand type of return inst!
  ret void
 i8Function return type does not match operand type of return inst!
  ret void
 i8Function return type does not match operand type of return inst!
  ret void
 i8Function return type does not match operand type of return inst!
  ret void
 i8<unknown>:0: error: fatal error encountered during compilation; please submit a bug report (https://swift.org/contributing/#reporting-bugs)
<unknown>:0: note: Broken module found, compilation aborted!
Process 16388 stopped
* thread #3, stop reason = signal SIGABRT
    frame #0: 0x00007ff80b7e2ffe libsystem_kernel.dylib`__pthread_kill + 10
libsystem_kernel.dylib`:
->  0x7ff80b7e2ffe <+10>: jae    0x7ff80b7e3008            ; <+20>
    0x7ff80b7e3000 <+12>: movq   %rax, %rdi
    0x7ff80b7e3003 <+15>: jmp    0x7ff80b7dd1b5            ; cerror_nocancel
    0x7ff80b7e3008 <+20>: retq   
Target 0: (swift-frontend) stopped.
(lldb) bt
* thread #3, stop reason = signal SIGABRT
  * frame #0: 0x00007ff80b7e2ffe libsystem_kernel.dylib`__pthread_kill + 10
    frame #1: 0x00007ff80b8191ff libsystem_pthread.dylib`pthread_kill + 263
    frame #2: 0x00007ff80b764d24 libsystem_c.dylib`abort + 123
    frame #3: 0x00000001000f055d swift-frontend`swift::performFrontend(this=0x000000033a113058, reason="Broken module found, compilation aborted!", shouldCrash=true)::$_34::operator()(char const*, bool) const at FrontendTool.cpp:2042:7
    frame #4: 0x00000001000f0198 swift-frontend`swift::performFrontend(this=0x000000033a113058, rawCallback=0x000000033a113058, reason="Broken module found, compilation aborted!", shouldCrash=true)::$_2::operator()(void*, char const*, bool) const at FrontendTool.cpp:2048:9
    frame #5: 0x00000001000f014c swift-frontend`swift::performFrontend(rawCallback=0x000000033a113058, reason="Broken module found, compilation aborted!", shouldCrash=true)::$_2::__invoke(void*, char const*, bool) at FrontendTool.cpp:2045:7
    frame #6: 0x000000010d385909 swift-frontend`llvm::report_fatal_error(Reason=0x000000033b11a148, GenCrashDiag=true) at ErrorHandling.cpp:104:5
    frame #7: 0x000000010d385855 swift-frontend`llvm::report_fatal_error(Reason="Broken module found, compilation aborted!", GenCrashDiag=true) at ErrorHandling.cpp:83:3
    frame #8: 0x000000010cec8934 swift-frontend`llvm::VerifierPass::run(this=0x00006000000288c8, M=0x000000017c6b1030, AM=0x000000033b11a6b8) at Verifier.cpp:6661:5
    frame #9: 0x0000000100be2f97 swift-frontend`llvm::detail::PassModel<llvm::Module, llvm::VerifierPass, llvm::PreservedAnalyses, llvm::AnalysisManager<llvm::Module> >::run(this=0x00006000000288c0, IR=0x000000017c6b1030, AM=0x000000033b11a6b8) at PassManagerInternal.h:88:17
    frame #10: 0x000000010ce506ad swift-frontend`llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module> >::run(this=0x000000033b11a4c8, IR=0x000000017c6b1030, AM=0x000000033b11a6b8) at PassManager.h:522:21
    frame #11: 0x0000000100bb31b7 swift-frontend`performOptimizationsUsingNewPassManger(Opts=0x000000017b01b240, Module=0x000000017c6b1030, TargetMachine=0x0000000180328000) at IRGen.cpp:575:14
    frame #12: 0x0000000100bb1e86 swift-frontend`swift::performLLVMOptimizations(Opts=0x000000017b01b240, Module=0x000000017c6b1030, TargetMachine=0x0000000180328000) at IRGen.cpp:602:5
    frame #13: 0x0000000100bb37da swift-frontend`swift::performLLVM(Opts=0x000000017b01b240, Diags=0x000000017b01b8c0, DiagMutex=0x000000033a110cc8, HashGlobal=0x0000000000000000, Module=0x000000017c6b1030, TargetMachine=0x0000000180328000, OutputFilename=(Data = "bin/timers.bc\xff\xff\xff", Length = 13), Stats=0x0000000000000000) at IRGen.cpp:787:3
    frame #14: 0x0000000100c15d5f swift-frontend`(anonymous namespace)::LLVMCodeGenThreads::Thread::run(this=0x00006000021518c8) at IRGen.cpp:1458:9
    frame #15: 0x0000000100c15a9d swift-frontend`(anonymous namespace)::LLVMCodeGenThreads::runThread(arg=0x00006000021518c8) at IRGen.cpp:1487:13
    frame #16: 0x00007ff80b8194e1 libsystem_pthread.dylib`_pthread_start + 125
    frame #17: 0x00007ff80b814f6b libsystem_pthread.dylib`thread_start + 15
(lldb) fr 8
invalid command 'frame 8'.
(lldb) fr s 8
frame #8: 0x000000010cec8934 swift-frontend`llvm::VerifierPass::run(this=0x00006000000288c8, M=0x000000017c6b1030, AM=0x000000033b11a6b8) at Verifier.cpp:6661:5
   6658	PreservedAnalyses VerifierPass::run(Module &M, ModuleAnalysisManager &AM) {
   6659	  auto Res = AM.getResult<VerifierAnalysis>(M);
   6660	  if (FatalErrors && (Res.IRBroken || Res.DebugInfoBroken))
-> 6661	    report_fatal_error("Broken module found, compilation aborted!");
   6662	
   6663	  return PreservedAnalyses::all();
   6664	}

(I think the cause of it might be me implementing a bad merge/cherry pick on the Clang ABI code stuff in TargetInfo.cpp)

I would insert F->dump() into Verifier::visitReturnInst under the failing condition, like this:

void Verifier::visitReturnInst(ReturnInst &RI) {
  Function *F = RI.getParent()->getParent();
  unsigned N = RI.getNumOperands();
  if (F->getReturnType()->isVoidTy())
    Check(N == 0,
          "Found return instr that returns non-void in Function of void "
          "return type!",
          &RI, F->getReturnType());
  else {
    if (N != 1 || F->getReturnType() != RI.getOperand(0)->getType())
      F->dump();
    Check(N == 1 && F->getReturnType() == RI.getOperand(0)->getType(),
          "Function return type does not match operand "
          "type of return inst!",
          &RI, F->getReturnType());
  }

  // Check to make sure that the return value has necessary properties for
  // terminators...
  visitTerminator(RI);
}
1 Like

Or less verbose, just add F->getName() to the end of the Check(), so that it is printed after the error message.

1 Like

Another approach I took, since I’m already debugging it in lldb, I put a breakpoint at line 244 of Verifier.cpp

Broken = true;

…which seems to be the only place Broken is set to true. That got me to the problem in a debug session.

Thanks so much for the help, guys. I really needed some nudges in the right direction!

The faulty BB is…

; Function Attrs: minsize optsize
define linkonce_odr hidden i8 @"$s3AVR8sleepCpu12microsecondsys6UInt32V_tFyycfU_To"() addrspace(1) #0 {
  call swiftcc addrspace(1) void @"$s3AVR8sleepCpu12microsecondsys6UInt32V_tFyycfU_"() #4
  ret void
}

…which is fairly obviously wrong. Now I’ve just got to work out how Swift is creating this IR. Pretty weird.


I’m compiling for AVR and I think it might be because I changed the AVRABIInfo to inherit from SwiftABIInfo instead of DefaultABIInfo.

To be honest I don’t really understand what this part of clang is for?

I’m a bit naive about this, but I thought all the ABI implementation was basically handled by llvm? …The swift frontend creates IR for the functions it wants to output, then the usual llvm magic of tablegen, ISel lowering, instruction selection, machine instruction selection, etc etc. …decides exactly how the ABI is implemented, what goes into what register, etc.? Isn’t that most of the point of the design of llvm?!


The llvm-project branch I was using is based on swift/release/5.8 with just that one AVRABIInfo change.

(For interest only, my swift code is based on normal swift release/5.8 with a load of my own patches on top to add features we need for our microcontrollers and to make it work with AVR and our modified standard library variant.)

I’m not familiar with swift fork (and I couldn’t find clang sources in there), but in the upstream llvm-project you’re not supposed to inherit AVRTargetCodeGenInfo from SwiftABIInfo. Instead, you should initialize member SwiftInfo, like this:

Short answer: source code → llvm IR translation is lossy, which makes it impossible to correctly implement all the ABI nuances at later stages.

I think that’s how it’s done in modern branches, like swift/release/5.9. Unfortunately I’ve got issues with the swift 5.9 compiler that mean I can’t upgrade to it yet, our release is based on swift 5.8, which uses llvm-project branch swift/release/5.8, which is basically llvm and clang from last year. It looks like they did a nice overhaul of the SwiftABIInfo to use composition instead of inheritcance (a much better design!) … but unfortunately I’m currently still stuck with the old last year llvm/clang structure for now, which means my AVRABIInfo has to decide whether to inherit from SwiftABIInfo or not.

Thinking about it, I might just revert my commit and go with just plain swift/release/5.8 llvm-project then see what results I get.


The last time I did this, I had some trouble compiling my standard library and it looked like swift was making the assumption that the ABI Info for the architecture you specify in your target triple must inherit from SwiftABIInfo, if that happens again with AVR, I’ll debug into it and see if there’s another approach.

Pretty simple issue in the end… in clang/lib/CodeGen/TargetInfo.cpp I had garbled the classifyReturnType function in AVRABIInfo so it was always returning ABIArgInfo::getDirect() and I had lost this crucial bit of code (among others)…

    if (RetTy->isVoidType())
      return ABIArgInfo::getIgnore();

…the next bit I’m slightly hazy on. Swift reads C header files using a subsystem called the “clang importer” that seems to use clang code under the hood. I think that was using my slightly mangled clang code to interpret the C header files and creating incorrect IR, which then failed the Verifier pass.

Anyway, problem solved! Thanks so much for your help!