[PATCH] D147506: [DebugLine] save one debug line entry for empty prologue

ChenZheng via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 26 07:53:33 PDT 2023


shchenz added a comment.

  Like maybe recordSourceLine raises a flag and beginInstruction checks the flag, and if the flag is raised, it calls Asm.OutStreamer->emitDwarfLocDirective and lowers the flag. Then any redundant line directives aren't emitted, they are just overwritten.

Hi @dblaikie Sorry, I don't quite understand the method you suggested. Could you please share more details? And I am also sorry for the long comment...

I also tried a way in `recordSourceLine()` (See the code snippet at last), it can handle empty prologue case, but it can not handle non-empty prologue case now and I can not find a better way to fix this.

The truncated input for non-empty prologue case:

  ; Function Attrs: noinline nounwind optnone uwtable
  define dso_local signext i32 @main() #0 !dbg !10 {
  entry:
    %retval = alloca i32, align 4  ;; prologue
    store i32 0, ptr %retval, align 4 ;;prologue
    ret i32 0, !dbg !15
  }



  main:                                   # @main
  .Lfunc_begin0:
  	.file	0 "empty_prologue" "1.c" md5 0xd1035b543709f23158df094b6d49742b
  	.cfi_startproc
  # %bb.0:                                # %entry
  	li 3, 0
  	stw 3, -12(1)
  .Ltmp0:
  	.loc	0 2 0                           # 1.c:2:0     ######now the first line entry of the file is put after prologue instructions.
  	.loc	0 3 3 prologue_end              # 1.c:3:3
  	li 3, 0
  	blr

The issue is for assembly code generation, we must emit the `.loc` once the `recordSourceLine()` is called, we can not delay it otherwise the `.loc` will be emitted in the wrong place like above case shows. `AsmPrinter::emitFunctionBody()` emits one instruction in each iteration while it iterates the instructions in a BB. The debug handler `DwarfDebug::beginInstruction()` must keep pace with `AsmPrinter::emitFunctionBody()`. Otherwise the `.loc` can not be emitted in the right place. I thought we can not change how we write the assembly file, it has to be written line by line, right?

  diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
  index 98f24599970d..cd4dd504e1e8 100644
  --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
  +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
  @@ -2048,7 +2048,7 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) {
       if ((LastAsmLine == 0 && DL.getLine() != 0) || Flags) {
         // Reinstate the source location but not marked as a statement.
         const MDNode *Scope = DL.getScope();
  -      recordSourceLine(DL.getLine(), DL.getCol(), Scope, Flags);
  +      recordSourceLine(DL.getLine(), DL.getCol(), Scope, Flags, MI);
       }
       return;
     }
  @@ -2079,7 +2079,7 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) {
           Scope = PrevInstLoc.getScope();
           Column = PrevInstLoc.getCol();
         }
  -      recordSourceLine(/*Line=*/0, Column, Scope, /*Flags=*/0);
  +      recordSourceLine(/*Line=*/0, Column, Scope, /*Flags=*/0, MI);
       }
       return;
     }
  @@ -2091,7 +2091,7 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) {
       return;
     if (DL == PrologEndLoc) {
       Flags |= DWARF2_FLAG_PROLOGUE_END | DWARF2_FLAG_IS_STMT;
  -    PrologEndLoc = DebugLoc();
  +    //PrologEndLoc = DebugLoc();
     }
     // If the line changed, we call that a new statement; unless we went to
     // line 0 and came back, in which case it is not a new statement.
  @@ -2100,7 +2100,7 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) {
       Flags |= DWARF2_FLAG_IS_STMT;
  
     const MDNode *Scope = DL.getScope();
  -  recordSourceLine(DL.getLine(), DL.getCol(), Scope, Flags);
  +  recordSourceLine(DL.getLine(), DL.getCol(), Scope, Flags, MI);
  
     // If we're not at line 0, remember this location.
     if (DL.getLine())
  @@ -2128,28 +2128,6 @@ static DebugLoc findPrologueEndLoc(const MachineFunction *MF) {
     return LineZeroLoc;
   }
  
  -/// Register a source line with debug info. Returns the  unique label that was
  -/// emitted and which provides correspondence to the source line list.
  -static void recordSourceLine(AsmPrinter &Asm, unsigned Line, unsigned Col,
  -                             const MDNode *S, unsigned Flags, unsigned CUID,
  -                             uint16_t DwarfVersion,
  -                             ArrayRef<std::unique_ptr<DwarfCompileUnit>> DCUs) {
  -  StringRef Fn;
  -  unsigned FileNo = 1;
  -  unsigned Discriminator = 0;
  -  if (auto *Scope = cast_or_null<DIScope>(S)) {
  -    Fn = Scope->getFilename();
  -    if (Line != 0 && DwarfVersion >= 4)
  -      if (auto *LBF = dyn_cast<DILexicalBlockFile>(Scope))
  -        Discriminator = LBF->getDiscriminator();
  -
  -    FileNo = static_cast<DwarfCompileUnit &>(*DCUs[CUID])
  -                 .getOrCreateSourceID(Scope->getFile());
  -  }
  -  Asm.OutStreamer->emitDwarfLocDirective(FileNo, Line, Col, Flags, 0,
  -                                         Discriminator, Fn);
  -}
  -
   DebugLoc DwarfDebug::emitInitialLocDirective(const MachineFunction &MF,
                                                unsigned CUID) {
     // Get beginning of function.
  @@ -2161,8 +2139,7 @@ DebugLoc DwarfDebug::emitInitialLocDirective(const MachineFunction &MF,
       // We'd like to list the prologue as "not statements" but GDB behaves
       // poorly if we do that. Revisit this with caution/GDB (7.5+) testing.
       const DISubprogram *SP = PrologEndLoc->getInlinedAtScope()->getSubprogram();
  -    ::recordSourceLine(*Asm, SP->getScopeLine(), 0, SP, DWARF2_FLAG_IS_STMT,
  -                       CUID, getDwarfVersion(), getUnits());
  +    recordSourceLine(SP->getScopeLine(), 0, SP, DWARF2_FLAG_IS_STMT);
       return PrologEndLoc;
     }
     return DebugLoc();
  @@ -2308,13 +2285,64 @@ void DwarfDebug::endFunctionImpl(const MachineFunction *MF) {
     CurFn = nullptr;
   }
  
  -// Register a source line with debug info. Returns the  unique label that was
  +// Register a source line with debug info. Returns the unique label that was
   // emitted and which provides correspondence to the source line list.
   void DwarfDebug::recordSourceLine(unsigned Line, unsigned Col, const MDNode *S,
  -                                  unsigned Flags) {
  -  ::recordSourceLine(*Asm, Line, Col, S, Flags,
  -                     Asm->OutStreamer->getContext().getDwarfCompileUnitID(),
  -                     getDwarfVersion(), getUnits());
  +                                  unsigned Flags, const MachineInstr *MI) {
  +
  +  auto EmitLoc = [&](unsigned Line, unsigned Col, const MDNode *S,
  +                     unsigned Flags) {
  +    StringRef Fn;
  +    unsigned FileNo = 1;
  +    unsigned Discriminator = 0;
  +    ArrayRef<std::unique_ptr<DwarfCompileUnit>> DCUs = getUnits();
  +    unsigned CUID = Asm->OutStreamer->getContext().getDwarfCompileUnitID();
  +
  +    if (auto *Scope = cast_or_null<DIScope>(S)) {
  +      Fn = Scope->getFilename();
  +      if (Line != 0 && getDwarfVersion() >= 4)
  +        if (auto *LBF = dyn_cast<DILexicalBlockFile>(Scope))
  +          Discriminator = LBF->getDiscriminator();
  +
  +      FileNo = static_cast<DwarfCompileUnit &>(*DCUs[CUID])
  +                   .getOrCreateSourceID(Scope->getFile());
  +    }
  +    Asm->OutStreamer->emitDwarfLocDirective(FileNo, Line, Col, Flags, 0,
  +                                            Discriminator, Fn);
  +  };
  +
  +  // Before handling instructions, multiple debug lines may be recorded and
  +  // these debug lines may have same addresses, for example the prologue is
  +  // empty. Ignore these lines for now until we know what the prologue looks
  +  // like.
  +  if (!PrevInstLoc && !MI)
  +    return;
  +
  +  // If the function's first instruction does not have debug loc info, prologue
  +  // is not empty. Generate the line for the function start first before
  +  // generating prologue end line.
  +  if (!PrevInstLoc && MI && PrologEndLoc) {
  +    const MachineInstr *FirstInstr =
  +        [](const MachineInstr *MI) -> const MachineInstr * {
  +      for (auto &BB : *MI->getParent()->getParent()) {
  +        for (auto &I : BB) {
  +          if (!I.isMetaInstruction())
  +            return &I;
  +        }
  +      }
  +      return nullptr;
  +    }(MI);
  +
  +    if (FirstInstr && FirstInstr != MI) {
  +      // FirstInstr must be in prologue.
  +      const DISubprogram *SP =
  +          PrologEndLoc->getInlinedAtScope()->getSubprogram();
  +      EmitLoc(SP->getScopeLine(), 0, SP, DWARF2_FLAG_IS_STMT);
  +    }
  +    PrologEndLoc = DebugLoc();
  +  }
  +
  +  EmitLoc(Line, Col, S, Flags);
   }
  
   //===----------------------------------------------------------------------===//
  diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
  index 0e71c216e958..fdac1134abe7 100644
  --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
  +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
  @@ -606,7 +606,7 @@ private:
     /// label that was emitted and which provides correspondence to the
     /// source line list.
     void recordSourceLine(unsigned Line, unsigned Col, const MDNode *Scope,
  -                        unsigned Flags);
  +                        unsigned Flags, const MachineInstr *MI = nullptr);
  
     /// Populate LexicalScope entries with variables' info.
     void collectEntityInfo(DwarfCompileUnit &TheCU, const DISubprogram *SP,


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D147506/new/

https://reviews.llvm.org/D147506



More information about the llvm-commits mailing list