How to track LLVM verifyFunction error "Expected Without Forward Ads!"?

I am developing a compiler for a new language in LLVM and am encountering a problem when creating debugging information.

I have not yet found a lot of documentation on how to actually generate debugging information using DIBuilder , so this is very possible. t doing something is terribly wrong.

I mainly look at the Kaleidoscope , as it is the only one I found that uses debugging information. I have yet to hack Clang to see how they use it, but I would like to hear from someone who has it.

I was able to compile and run my language with more complex examples, but I started using some basics to add debugging support. Here is a simple script I'm trying to compile:

double my_main()
{
    return 0.0;
}

Here is my conclusion from verifyFunction, verifyModule and module reset.

Edit: Mark in edit below. I indicate that the dump after the call to complete, which correctly removes the temporary.

Failed To Verify Function: my_main error: Expected no forward declarations!
!8 = <temporary!> !{}

Failed To Verify Module: test.str error: Expected no forward declarations!
!8 = <temporary!> !{}

; ModuleID = 'test.str'

define double @my_main() !dbg !6 {
entry:
  br label %block, !dbg !10

block:                                            ; preds = %entry
  ret double 0.000000e+00, !dbg !10
}

!llvm.module.flags = !{!0, !1}
!llvm.dbg.cu = !{!2}

!0 = !{i32 2, !"Debug Info Version", i32 3}
!1 = !{i32 2, !"Dwarf Version", i32 2}
!2 = distinct !DICompileUnit(language: DW_LANG_C, file: !3, producer: "Test Compiler", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !4, subprograms: !5)
!3 = !DIFile(filename: "test.str", directory: ".")
!4 = !{}
!5 = !{!6}
!6 = distinct !DISubprogram(name: "my_main", scope: !3, file: !3, line: 10, type: !7, isLocal: false, isDefinition: true, scopeLine: 10, isOptimized: false, variables: !4)
!7 = !DISubroutineType(types: !8)
!8 = !{!9}
!9 = !DIBasicType(name: "double", size: 64, align: 8, encoding: DW_ATE_float)
!10 = !DILocation(line: 9, column: 11, scope: !6)

A search for the error message in the LLVM code base shows the source in Verifier.cpp:

void Verifier::visitMDNode(const MDNode &MD) {
  // Only visit each node once.  Metadata can be mutually recursive, so this
  // avoids infinite recursion here, as well as being an optimization.
  if (!MDNodes.insert(&MD).second)
    return;

  switch (MD.getMetadataID()) {
  default:
    llvm_unreachable("Invalid MDNode subclass");
  case Metadata::MDTupleKind:
    break;
#define HANDLE_SPECIALIZED_MDNODE_LEAF(CLASS)                                  \
  case Metadata::CLASS##Kind:                                                  \
    visit##CLASS(cast<CLASS>(MD));                                             \
    break;
#include "llvm/IR/Metadata.def"
  }

  for (unsigned i = 0, e = MD.getNumOperands(); i != e; ++i) {
    Metadata *Op = MD.getOperand(i);
    if (!Op)
      continue;
    Assert(!isa<LocalAsMetadata>(Op), "Invalid operand for global metadata!",
           &MD, Op);
    if (auto *N = dyn_cast<MDNode>(Op)) {
      visitMDNode(*N);
      continue;
    }
    if (auto *V = dyn_cast<ValueAsMetadata>(Op)) {
      visitValueAsMetadata(*V, nullptr);
      continue;
    }
  }

  // Check these last, so we diagnose problems in operands first.
  Assert(!MD.isTemporary(), "Expected no forward declarations!", &MD);
  Assert(MD.isResolved(), "All nodes should be resolved!", &MD);
}

I assume that I have some metadata that is still considered "temporary", but I would like to know how to track what creates them.

I create my types in the same way as in the example:

// here dbuilder is a DIBuilder* and alignment is coming from 
// my Module getDataLayout().getABITypeAlignment(t);
// where t is Type::getDoubleTy(context.getLLVMContext());
// the context object is my own type
dbuilder->createBasicType("double", 64, alignment, dwarf::DW_ATE_float);

My logic for creating a debug function uses this type, among other things, in another call from the example:

// the argument is of type: SmallVector<Metadata *, 8> returnPlusParams;
dbuilder->createSubroutineType(dbuilder->getOrCreateTypeArray(returnPlusParams));

IRBuilder AST:

_mBuilder->SetCurrentDebugLocation(DebugLoc::get(node->line, node->column, currentDebugScope()));

SourceLevelDebugging, ++ API LLVM , -.

- - - , .


: IR

Clang :

clang -cc1 hello_llvm.c -emit-llvm

: , .

:

double main() {
  return 0.0;
}

:

; ModuleID = 'hello_llvm.c'
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-darwin15.0.0"

; Function Attrs: nounwind
define double @main() #0 {
entry:
  ret double 0.000000e+00
}

attributes #0 = { nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-features"="+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }

!llvm.ident = !{!0}

!0 = !{!"clang version 3.8.0 (http://llvm.org/git/clang.git 80803f026ba7160f7cfa122c7ef829ab42abc3bf) (http://llvm.org/git/llvm.git 1bb03c5884405c428c3ab54631c0528b6cedeb54)"}

, main int. int, alloca:

; ModuleID = 'hello_llvm.c'
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-darwin15.0.0"

; Function Attrs: nounwind
define i32 @main() #0 {
entry:
  %retval = alloca i32, align 4
  store i32 0, i32* %retval, align 4
  ret i32 0
}

attributes #0 = { nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-features"="+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }

!llvm.ident = !{!0}

!0 = !{!"clang version 3.8.0 (http://llvm.org/git/clang.git 80803f026ba7160f7cfa122c7ef829ab42abc3bf) (http://llvm.org/git/llvm.git 1bb03c5884405c428c3ab54631c0528b6cedeb54)"}

. double , int . my_main main argv/argc .


2: ""

IR, verifyModule finalize. -, .

. , .

Failed To Verify Module: test.str error: Expected no forward declarations!
!8 = <temporary!> !{}

; ModuleID = 'test.str'

define i32 @my_main() !dbg !4 {
entry:
  br label %block, !dbg !9

block:                                            ; preds = %entry
  ret i32 0, !dbg !9
}

!llvm.module.flags = !{!0, !1}
!llvm.dbg.cu = !{!2}

!0 = !{i32 2, !"Debug Info Version", i32 3}
!1 = !{i32 2, !"Dwarf Version", i32 2}
!2 = distinct !DICompileUnit(language: DW_LANG_C, file: !3, producer: "Test Compiler", isOptimized: false, runtimeVersion: 0, emissionKind: 1)
!3 = !DIFile(filename: "test.str", directory: ".")
!4 = distinct !DISubprogram(name: "my_main", scope: !3, file: !3, line: 10, type: !5, isLocal: false, isDefinition: true, scopeLine: 10, isOptimized: false, variables: !8)
!5 = !DISubroutineType(types: !6)
!6 = !{!7}
!7 = !DIBasicType(name: "int32", size: 32, align: 4, encoding: DW_ATE_signed)
!8 = <temporary!> !{}
!9 = !DILocation(line: 9, column: 11, scope: !4)

, , ...

-, , ? ? ?

+4
2

, , , verifyFunction, verifyModule .

CODEGENOPT(VerifyModule      , 1, 1) ///< Control whether the module should be run
                                     ///< through the LLVM Verifier.

, , , verifyModule. ", Clang " .

- .

+1

, IRBuilder DIBuilder. , llvm::ExecutionEngine::getFunctionAddress ( ) DIBuilder (llvm::DIBuilder::finalize()). , dbuilder->finalize() llvm:: Module (, ).

+1

Source: https://habr.com/ru/post/1619595/


All Articles