Fix the source line debug information for the Windows platform.
[oota-llvm.git] / lib / CodeGen / DwarfWriter.cpp
index e72ff07a9d704299b36a67d4e0afc11ac0b3cf44..784bf930b584db7690734a66ba13d83a43c8323b 100644 (file)
@@ -296,6 +296,7 @@ public:
     isString,
     isLabel,
     isAsIsLabel,
+    isSectionOffset,
     isDelta,
     isEntry,
     isBlock
@@ -504,6 +505,56 @@ public:
 #endif
 };
 
+//===----------------------------------------------------------------------===//
+/// DIESectionOffset - A section offset DIE.
+//
+class DIESectionOffset : public DIEValue {
+public:
+  const DWLabel Label;
+  const DWLabel Section;
+  bool IsEH : 1;
+  bool UseSet : 1;
+  
+  DIESectionOffset(const DWLabel &Lab, const DWLabel &Sec,
+                   bool isEH = false, bool useSet = true)
+  : DIEValue(isSectionOffset), Label(Lab), Section(Sec),
+                               IsEH(isEH), UseSet(useSet) {}
+
+  // Implement isa/cast/dyncast.
+  static bool classof(const DIESectionOffset *)  { return true; }
+  static bool classof(const DIEValue *D) { return D->Type == isSectionOffset; }
+  
+  /// EmitValue - Emit section offset.
+  ///
+  virtual void EmitValue(DwarfDebug &DD, unsigned Form);
+  
+  /// SizeOf - Determine size of section offset value in bytes.
+  ///
+  virtual unsigned SizeOf(const DwarfDebug &DD, unsigned Form) const;
+  
+  /// Profile - Used to gather unique data for the value folding set.
+  ///
+  static void Profile(FoldingSetNodeID &ID, const DWLabel &Label,
+                                            const DWLabel &Section) {
+    ID.AddInteger(isSectionOffset);
+    Label.Profile(ID);
+    Section.Profile(ID);
+    // IsEH and UseSet are specific to the Label/Section that we will emit
+    // the offset for; so Label/Section are enough for uniqueness.
+  }
+  virtual void Profile(FoldingSetNodeID &ID) { Profile(ID, Label, Section); }
+
+#ifndef NDEBUG
+  virtual void print(std::ostream &O) {
+    O << "Off: ";
+    Label.print(O);
+    O << "-";
+    Section.print(O);
+    O << "-" << IsEH << "-" << UseSet;
+  }
+#endif
+};
+
 //===----------------------------------------------------------------------===//
 /// DIEDelta - A simple label difference DIE.
 /// 
@@ -1275,6 +1326,24 @@ public:
     Die->AddValue(Attribute, Form, Value);
   }
       
+  /// AddSectionOffset - Add a section offset label attribute data and value.
+  ///
+  void AddSectionOffset(DIE *Die, unsigned Attribute, unsigned Form,
+                        const DWLabel &Label, const DWLabel &Section,
+                        bool isEH = false, bool useSet = true) {
+    FoldingSetNodeID ID;
+    DIESectionOffset::Profile(ID, Label, Section);
+    void *Where;
+    DIEValue *Value = ValuesSet.FindNodeOrInsertPos(ID, Where);
+    if (!Value) {
+      Value = new DIESectionOffset(Label, Section, isEH, useSet);
+      ValuesSet.InsertNode(Value, Where);
+      Values.push_back(Value);
+    }
+  
+    Die->AddValue(Attribute, Form, Value);
+  }
+      
   /// AddDelta - Add a label delta attribute data and value.
   ///
   void AddDelta(DIE *Die, unsigned Attribute, unsigned Form,
@@ -1714,11 +1783,8 @@ private:
   CompileUnit *NewCompileUnit(CompileUnitDesc *UnitDesc, unsigned ID) {
     // Construct debug information entry.
     DIE *Die = new DIE(DW_TAG_compile_unit);
-    if (TAI->isAbsoluteDebugSectionOffsets())
-      AddLabel(Die, DW_AT_stmt_list, DW_FORM_data4, DWLabel("section_line", 0));
-    else
-      AddDelta(Die, DW_AT_stmt_list, DW_FORM_data4, DWLabel("section_line", 0),
-               DWLabel("section_line", 0));      
+    AddSectionOffset(Die, DW_AT_stmt_list, DW_FORM_data4,
+              DWLabel("section_line", 0), DWLabel("section_line", 0), false);
     AddString(Die, DW_AT_producer,  DW_FORM_string, UnitDesc->getProducer());
     AddUInt  (Die, DW_AT_language,  DW_FORM_data1,  UnitDesc->getLanguage());
     AddString(Die, DW_AT_name,      DW_FORM_string, UnitDesc->getFileName());
@@ -2720,8 +2786,11 @@ public:
 
     // Emit label for the implicitly defined dbg.stoppoint at the start of
     // the function.
-    const SourceLineInfo &LineInfo = MMI->getSourceLines()[0];
-    Asm->printLabel(LineInfo.getLabelID());
+    const std::vector<SourceLineInfo> &LineInfos = MMI->getSourceLines();
+    if (!LineInfos.empty()) {
+      const SourceLineInfo &LineInfo = LineInfos[0];
+      Asm->printLabel(LineInfo.getLabelID());
+    }
   }
   
   /// EndFunction - Gather and emit post-function debug information.
@@ -2777,11 +2846,23 @@ private:
   };
 
   std::vector<FunctionEHFrameInfo> EHFrames;
-    
-  /// shouldEmit - Flag to indicate if debug information should be emitted.
-  ///
-  bool shouldEmit;
-  
+
+  /// shouldEmitTable - Per-function flag to indicate if EH tables should
+  /// be emitted.
+  bool shouldEmitTable;
+
+  /// shouldEmitMoves - Per-function flag to indicate if frame moves info
+  /// should be emitted.
+  bool shouldEmitMoves;
+
+  /// shouldEmitTableModule - Per-module flag to indicate if EH tables
+  /// should be emitted.
+  bool shouldEmitTableModule;
+
+  /// shouldEmitFrameModule - Per-module flag to indicate if frame moves 
+  /// should be emitted.
+  bool shouldEmitMovesModule;
+
   /// EmitCommonEHFrame - Emit the common eh unwind frame.
   ///
   void EmitCommonEHFrame(const Function *Personality, unsigned Index) {
@@ -2798,7 +2879,7 @@ private:
 
     // Define base labels.
     EmitLabel("eh_frame_common", Index);
-    
+
     // Define the eh frame length.
     EmitDifference("eh_frame_common_end", Index,
                    "eh_frame_common_begin", Index, true);
@@ -2810,50 +2891,50 @@ private:
     Asm->EOL("CIE Identifier Tag");
     Asm->EmitInt8(DW_CIE_VERSION);
     Asm->EOL("CIE Version");
-    
+
     // The personality presence indicates that language specific information
     // will show up in the eh frame.
     Asm->EmitString(Personality ? "zPLR" : "zR");
     Asm->EOL("CIE Augmentation");
-    
+
     // Round out reader.
     Asm->EmitULEB128Bytes(1);
     Asm->EOL("CIE Code Alignment Factor");
     Asm->EmitSLEB128Bytes(stackGrowth);
-    Asm->EOL("CIE Data Alignment Factor");   
+    Asm->EOL("CIE Data Alignment Factor");
     Asm->EmitInt8(RI->getDwarfRegNum(RI->getRARegister(), true));
-    Asm->EOL("CIE RA Column");
-    
+    Asm->EOL("CIE Return Address Column");
+
     // If there is a personality, we need to indicate the functions location.
     if (Personality) {
       Asm->EmitULEB128Bytes(7);
       Asm->EOL("Augmentation Size");
 
-      if (TAI->getNeedsIndirectEncoding())
+      if (TAI->getNeedsIndirectEncoding()) {
         Asm->EmitInt8(DW_EH_PE_pcrel | DW_EH_PE_sdata4 | DW_EH_PE_indirect);
-      else
+        Asm->EOL("Personality (pcrel sdata4 indirect)");
+      } else {
         Asm->EmitInt8(DW_EH_PE_pcrel | DW_EH_PE_sdata4);
+        Asm->EOL("Personality (pcrel sdata4)");
+      }
 
-      Asm->EOL("Personality (pcrel sdata4 indirect)");
-      
-      PrintRelDirective(TAI->getShortenEHDataOn64Bit());
+      PrintRelDirective(true);
       O << TAI->getPersonalityPrefix();
       Asm->EmitExternalGlobal((const GlobalVariable *)(Personality));
       O << TAI->getPersonalitySuffix();
-      if (!TAI->getShortenEHDataOn64Bit()) {
+      if (strcmp(TAI->getPersonalitySuffix(), "+4@GOTPCREL"))
         O << "-" << TAI->getPCSymbol();
-      }
       Asm->EOL("Personality");
 
-      Asm->EmitULEB128Bytes(DW_EH_PE_pcrel);
-      Asm->EOL("LSDA Encoding (pcrel)");
-      Asm->EmitULEB128Bytes(DW_EH_PE_pcrel);
-      Asm->EOL("FDE Encoding (pcrel)");
+      Asm->EmitInt8(DW_EH_PE_pcrel | DW_EH_PE_sdata4);
+      Asm->EOL("LSDA Encoding (pcrel sdata4)");
+      Asm->EmitInt8(DW_EH_PE_pcrel | DW_EH_PE_sdata4);
+      Asm->EOL("FDE Encoding (pcrel sdata4)");
    } else {
       Asm->EmitULEB128Bytes(1);
       Asm->EOL("Augmentation Size");
-      Asm->EmitULEB128Bytes(DW_EH_PE_pcrel);
-      Asm->EOL("FDE Encoding (pcrel)");
+      Asm->EmitInt8(DW_EH_PE_pcrel | DW_EH_PE_sdata4);
+      Asm->EOL("FDE Encoding (pcrel sdata4)");
     }
 
     // Indicate locations of general callee saved registers in frame.
@@ -2861,12 +2942,16 @@ private:
     RI->getInitialFrameState(Moves);
     EmitFrameMoves(NULL, 0, Moves, true);
 
-    Asm->EmitAlignment(2, 0, 0, false);
+    // On Darwin the linker honors the alignment of eh_frame, which means it
+    // must be 8-byte on 64-bit targets to match what gcc does.  Otherwise
+    // you get holes which confuse readers of eh_frame.
+    Asm->EmitAlignment(TD->getPointerSize() == sizeof(int32_t) ? 2 : 3, 
+                       0, 0, false);
     EmitLabel("eh_frame_common_end", Index);
-    
+
     Asm->EOL();
   }
-  
+
   /// EmitEHFrame - Emit function exception frame information.
   ///
   void EmitEHFrame(const FunctionEHFrameInfo &EHFrameInfo) {
@@ -2890,8 +2975,11 @@ private:
 
     // If there are no calls then you can't unwind.  This may mean we can
     // omit the EH Frame, but some environments do not handle weak absolute
-    // symbols.
+    // symbols.  
+    // If UnwindTablesMandatory is set we cannot do this optimization; the
+    // unwind info is to be available for non-EH uses.
     if (!EHFrameInfo.hasCalls &&
+        !UnwindTablesMandatory &&
         ((linkage != Function::WeakLinkage && 
           linkage != Function::LinkOnceLinkage) ||
          !TAI->getWeakDefDirective() ||
@@ -2918,36 +3006,37 @@ private:
                         true, true, false);
       Asm->EOL("FDE CIE offset");
 
-      EmitReference("eh_func_begin", EHFrameInfo.Number, true);
+      EmitReference("eh_func_begin", EHFrameInfo.Number, true, true);
       Asm->EOL("FDE initial location");
       EmitDifference("eh_func_end", EHFrameInfo.Number,
-                     "eh_func_begin", EHFrameInfo.Number);
+                     "eh_func_begin", EHFrameInfo.Number, true);
       Asm->EOL("FDE address range");
-      
+
       // If there is a personality and landing pads then point to the language
       // specific data area in the exception table.
       if (EHFrameInfo.PersonalityIndex) {
-        Asm->EmitULEB128Bytes(TAI->getShortenEHDataOn64Bit() ? 8 : 4);
+        Asm->EmitULEB128Bytes(4);
         Asm->EOL("Augmentation size");
-        
-        if (EHFrameInfo.hasLandingPads) {
-          EmitReference("exception", EHFrameInfo.Number, true);
-        } else if (TD->getPointerSize() == 8) {
-          Asm->EmitInt64((int)0);
-        } else {
+
+        if (EHFrameInfo.hasLandingPads)
+          EmitReference("exception", EHFrameInfo.Number, true, true);
+        else
           Asm->EmitInt32((int)0);
-        }
         Asm->EOL("Language Specific Data Area");
       } else {
         Asm->EmitULEB128Bytes(0);
         Asm->EOL("Augmentation size");
       }
-      
+
       // Indicate locations of function specific  callee saved registers in
       // frame.
       EmitFrameMoves("eh_func_begin", EHFrameInfo.Number, EHFrameInfo.Moves, true);
       
-      Asm->EmitAlignment(2, 0, 0, false);
+      // On Darwin the linker honors the alignment of eh_frame, which means it
+      // must be 8-byte on 64-bit targets to match what gcc does.  Otherwise
+      // you get holes which confuse readers of eh_frame.
+      Asm->EmitAlignment(TD->getPointerSize() == sizeof(int32_t) ? 2 : 3, 
+                         0, 0, false);
       EmitLabel("eh_frame_end", EHFrameInfo.Number);
     
       // If the function is marked used, this table should be also.  We cannot 
@@ -3045,9 +3134,6 @@ private:
   };
 
   void EmitExceptionTable() {
-    // Map all labels and get rid of any dead landing pads.
-    MMI->TidyLandingPads();
-
     const std::vector<GlobalVariable *> &TypeInfos = MMI->getTypeInfos();
     const std::vector<unsigned> &FilterIds = MMI->getFilterIds();
     const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads();
@@ -3244,13 +3330,20 @@ private:
     }
 
     // Final tallies.
-    unsigned SizeSites = CallSites.size() * (sizeof(int32_t) + // Site start.
-                                             sizeof(int32_t) + // Site length.
-                                             sizeof(int32_t)); // Landing pad.
+
+    // Call sites.
+    const unsigned SiteStartSize  = sizeof(int32_t); // DW_EH_PE_udata4
+    const unsigned SiteLengthSize = sizeof(int32_t); // DW_EH_PE_udata4
+    const unsigned LandingPadSize = sizeof(int32_t); // DW_EH_PE_udata4
+    unsigned SizeSites = CallSites.size() * (SiteStartSize +
+                                             SiteLengthSize +
+                                             LandingPadSize);
     for (unsigned i = 0, e = CallSites.size(); i < e; ++i)
       SizeSites += Asm->SizeULEB128(CallSites[i].Action);
 
-    unsigned SizeTypes = TypeInfos.size() * TD->getPointerSize();
+    // Type infos.
+    const unsigned TypeInfoSize = TD->getPointerSize(); // DW_EH_PE_absptr
+    unsigned SizeTypes = TypeInfos.size() * TypeInfoSize;
 
     unsigned TypeOffset = sizeof(int8_t) + // Call site format
                           Asm->SizeULEB128(SizeSites) + // Call-site table length
@@ -3300,27 +3393,22 @@ private:
       }
 
       EmitSectionOffset(BeginTag, "eh_func_begin", BeginNumber, SubprogramCount,
-                        TAI->getShortenEHDataOn64Bit(), true);
+                        true, true);
       Asm->EOL("Region start");
 
       if (!S.EndLabel) {
         EmitDifference("eh_func_end", SubprogramCount, BeginTag, BeginNumber,
-                       TAI->getShortenEHDataOn64Bit());
+                       true);
       } else {
-        EmitDifference("label", S.EndLabel, BeginTag, BeginNumber, 
-                       TAI->getShortenEHDataOn64Bit());
+        EmitDifference("label", S.EndLabel, BeginTag, BeginNumber, true);
       }
       Asm->EOL("Region length");
 
-      if (!S.PadLabel) {
-        if (TD->getPointerSize() == sizeof(int32_t) || TAI->getShortenEHDataOn64Bit())
-          Asm->EmitInt32(0);
-        else
-          Asm->EmitInt64(0);
-      } else {
+      if (!S.PadLabel)
+        Asm->EmitInt32(0);
+      else
         EmitSectionOffset("label", "eh_func_begin", S.PadLabel, SubprogramCount,
-                          TAI->getShortenEHDataOn64Bit(), true);
-      }
+                          true, true);
       Asm->EOL("Landing pad");
 
       Asm->EmitULEB128Bytes(S.Action);
@@ -3367,7 +3455,10 @@ public:
   //
   DwarfException(std::ostream &OS, AsmPrinter *A, const TargetAsmInfo *T)
   : Dwarf(OS, A, T, "eh")
-  , shouldEmit(false)
+  , shouldEmitTable(false)
+  , shouldEmitMoves(false)
+  , shouldEmitTableModule(false)
+  , shouldEmitMovesModule(false)
   {}
   
   virtual ~DwarfException() {}
@@ -3387,48 +3478,61 @@ public:
   /// EndModule - Emit all exception information that should come after the
   /// content.
   void EndModule() {
-    if (!shouldEmit) return;
-
-    const std::vector<Function *> Personalities = MMI->getPersonalities();
-    for (unsigned i =0; i < Personalities.size(); ++i)
-      EmitCommonEHFrame(Personalities[i], i);
-
-    for (std::vector<FunctionEHFrameInfo>::iterator I = EHFrames.begin(),
-           E = EHFrames.end(); I != E; ++I)
-      EmitEHFrame(*I);
+    if (shouldEmitMovesModule || shouldEmitTableModule) {
+      const std::vector<Function *> Personalities = MMI->getPersonalities();
+      for (unsigned i =0; i < Personalities.size(); ++i)
+        EmitCommonEHFrame(Personalities[i], i);
+
+      for (std::vector<FunctionEHFrameInfo>::iterator I = EHFrames.begin(),
+             E = EHFrames.end(); I != E; ++I)
+        EmitEHFrame(*I);
+    }
   }
 
   /// BeginFunction - Gather pre-function exception information.  Assumes being 
   /// emitted immediately after the function entry point.
   void BeginFunction(MachineFunction *MF) {
     this->MF = MF;
-    
-    if (MMI &&
-        ExceptionHandling &&
-        TAI->doesSupportExceptionHandling()) {
-      shouldEmit = true;
-      // Assumes in correct section after the entry point.
-      EmitLabel("eh_func_begin", ++SubprogramCount);
+    shouldEmitTable = shouldEmitMoves = false;
+    if (MMI && TAI->doesSupportExceptionHandling()) {
+
+      // Map all labels and get rid of any dead landing pads.
+      MMI->TidyLandingPads();
+      // If any landing pads survive, we need an EH table.
+      if (MMI->getLandingPads().size())
+        shouldEmitTable = true;
+
+      // See if we need frame move info.
+      if (MMI->hasDebugInfo() || 
+          !MF->getFunction()->doesNotThrow() ||
+          UnwindTablesMandatory)
+        shouldEmitMoves = true;
+
+      if (shouldEmitMoves || shouldEmitTable)
+        // Assumes in correct section after the entry point.
+        EmitLabel("eh_func_begin", ++SubprogramCount);
     }
+    shouldEmitTableModule |= shouldEmitTable;
+    shouldEmitMovesModule |= shouldEmitMoves;
   }
 
   /// EndFunction - Gather and emit post-function exception information.
   ///
   void EndFunction() {
-    if (!shouldEmit) return;
-
-    EmitLabel("eh_func_end", SubprogramCount);
-    EmitExceptionTable();
+    if (shouldEmitMoves || shouldEmitTable) {
+      EmitLabel("eh_func_end", SubprogramCount);
+      EmitExceptionTable();
 
-    // Save EH frame information
-    EHFrames.
-      push_back(FunctionEHFrameInfo(getAsm()->getCurrentFunctionEHName(MF),
+      // Save EH frame information
+      EHFrames.
+        push_back(FunctionEHFrameInfo(getAsm()->getCurrentFunctionEHName(MF),
                                     SubprogramCount,
                                     MMI->getPersonalityIndex(),
                                     MF->getFrameInfo()->hasCalls(),
                                     !MMI->getLandingPads().empty(),
                                     MMI->getFrameMoves(),
                                     MF->getFunction()));
+      }
   }
 };
 
@@ -3577,6 +3681,23 @@ unsigned DIEObjectLabel::SizeOf(const DwarfDebug &DD, unsigned Form) const {
     
 //===----------------------------------------------------------------------===//
 
+/// EmitValue - Emit delta value.
+///
+void DIESectionOffset::EmitValue(DwarfDebug &DD, unsigned Form) {
+  bool IsSmall = Form == DW_FORM_data4;
+  DD.EmitSectionOffset(Label.Tag, Section.Tag,
+                       Label.Number, Section.Number, IsSmall, IsEH, UseSet);
+}
+
+/// SizeOf - Determine size of delta value in bytes.
+///
+unsigned DIESectionOffset::SizeOf(const DwarfDebug &DD, unsigned Form) const {
+  if (Form == DW_FORM_data4) return 4;
+  return DD.getTargetData()->getPointerSize();
+}
+    
+//===----------------------------------------------------------------------===//
+
 /// EmitValue - Emit delta value.
 ///
 void DIEDelta::EmitValue(DwarfDebug &DD, unsigned Form) {