Behold, more work on relocations.  Things are looking pretty good now.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@30240 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/llvm/CodeGen/MachOWriter.h b/include/llvm/CodeGen/MachOWriter.h
index bb20f7b..a5e3520 100644
--- a/include/llvm/CodeGen/MachOWriter.h
+++ b/include/llvm/CodeGen/MachOWriter.h
@@ -344,6 +344,10 @@
       /// SectionData - The actual data for this section which we are building
       /// up for emission to the file.
       DataBuffer SectionData;
+
+      /// RelocBuffer - A buffer to hold the mach-o relocations before we write
+      /// them out at the appropriate location in the file.
+      DataBuffer RelocBuffer;
       
       /// Relocations - The relocations that we have encountered so far in this 
       /// section that we will need to convert to MachORelocation entries when
@@ -421,7 +425,7 @@
       }
 
       MachOSection(const std::string &seg, const std::string &sect)
-        : sectname(sect), segname(seg), addr(0), size(0), offset(0), align(0),
+        : sectname(sect), segname(seg), addr(0), size(0), offset(0), align(2),
           reloff(0), nreloc(0), flags(0), reserved1(0), reserved2(0),
           reserved3(0) { }
     };
@@ -449,10 +453,13 @@
       SN->flags = MachOSection::S_REGULAR | Flags;
       return *SN;
     }
-    MachOSection &getTextSection() {
-      return getSection("__TEXT", "__text", 
-                        MachOSection::S_ATTR_PURE_INSTRUCTIONS |
-                        MachOSection::S_ATTR_SOME_INSTRUCTIONS);
+    MachOSection &getTextSection(bool isCode = true) {
+      if (isCode)
+        return getSection("__TEXT", "__text", 
+                          MachOSection::S_ATTR_PURE_INSTRUCTIONS |
+                          MachOSection::S_ATTR_SOME_INSTRUCTIONS);
+      else
+        return getSection("__TEXT", "__text");
     }
     MachOSection &getBSSSection() {
       return getSection("__DATA", "__bss", MachOSection::S_ZEROFILL);
@@ -479,6 +486,12 @@
       }
       return getSection("__TEXT", "__const");
     }
+    MachOSection &getJumpTableSection() {
+      if (TM.getRelocationModel() == Reloc::PIC_)
+        return getTextSection(false);
+      else
+        return getSection("__TEXT", "__const");
+    }
     
     /// MachOSymTab - This struct contains information about the offsets and 
     /// size of symbol table information.
@@ -563,10 +576,6 @@
     /// local symbols first in the list).
     std::vector<MachOSym> SymbolTable;
     
-    /// RelocBuffer - A buffer to hold the mach-o relocations before we write
-    /// them out at the appropriate location in the file.
-    DataBuffer RelocBuffer;
-    
     /// SymT - A buffer to hold the symbol table before we write it out at the
     /// appropriate location in the file.
     DataBuffer SymT;
@@ -666,15 +675,31 @@
         outbyte(Output, 0);
       
     }
+    void fixhalf(DataBuffer &Output, unsigned short X, unsigned Offset) {
+      unsigned char *P = &Output[Offset];
+      P[0] = (X >> (isLittleEndian ?  0 : 8)) & 255;
+      P[1] = (X >> (isLittleEndian ?  8 : 0)) & 255;
+    }
+    void fixword(DataBuffer &Output, unsigned X, unsigned Offset) {
+      unsigned char *P = &Output[Offset];
+      P[0] = (X >> (isLittleEndian ?  0 : 24)) & 255;
+      P[1] = (X >> (isLittleEndian ?  8 : 16)) & 255;
+      P[2] = (X >> (isLittleEndian ? 16 :  8)) & 255;
+      P[3] = (X >> (isLittleEndian ? 24 :  0)) & 255;
+    }
+
   private:
     void AddSymbolToSection(MachOSection &MOS, GlobalVariable *GV);
     void EmitGlobal(GlobalVariable *GV);
     void EmitHeaderAndLoadCommands();
     void EmitSections();
     void BufferSymbolAndStringTable();
+    void CalculateRelocations(MachOSection &MOS, unsigned RelOffset);
 
-    virtual void GetTargetRelocation(MachOSection &MOS, MachineRelocation &MR, 
-                                     uint64_t Addr) = 0;
+    virtual MachineRelocation GetJTRelocation(unsigned Offset,
+                                              MachineBasicBlock *MBB) = 0;
+    virtual void GetTargetRelocation(MachineRelocation &MR, MachOSection &MOS,
+                                     unsigned ToIndex) = 0;
   };
 }
 
diff --git a/lib/CodeGen/MachOWriter.cpp b/lib/CodeGen/MachOWriter.cpp
index 5ffd978..be21f5c 100644
--- a/lib/CodeGen/MachOWriter.cpp
+++ b/lib/CodeGen/MachOWriter.cpp
@@ -25,6 +25,7 @@
 #include "llvm/Module.h"
 #include "llvm/CodeGen/MachineCodeEmitter.h"
 #include "llvm/CodeGen/MachineConstantPool.h"
+#include "llvm/CodeGen/MachineJumpTableInfo.h"
 #include "llvm/CodeGen/MachOWriter.h"
 #include "llvm/ExecutionEngine/ExecutionEngine.h"
 #include "llvm/Target/TargetJITInfo.h"
@@ -50,6 +51,14 @@
     /// Relocations - These are the relocations that the function needs, as
     /// emitted.
     std::vector<MachineRelocation> Relocations;
+    
+    /// CPLocations - This is a map of constant pool indices to offsets from the
+    /// start of the section for that constant pool index.
+    std::vector<intptr_t> CPLocations;
+
+    /// JTLocations - This is a map of jump table indices to offsets from the
+    /// start of the section for that jump table index.
+    std::vector<intptr_t> JTLocations;
 
     /// MBBLocations - This vector is a mapping from MBB ID's to their address.
     /// It is filled in by the StartMachineBasicBlock callback and queried by
@@ -66,19 +75,22 @@
       Relocations.push_back(MR);
     }
     
-    virtual void StartMachineBasicBlock(MachineBasicBlock *MBB) {
-      if (MBBLocations.size() <= (unsigned)MBB->getNumber())
-        MBBLocations.resize((MBB->getNumber()+1)*2);
-      MBBLocations[MBB->getNumber()] = getCurrentPCValue();
-    }
-
+    void emitConstantPool(MachineConstantPool *MCP);
+    void emitJumpTables(MachineJumpTableInfo *MJTI);
+    
     virtual intptr_t getConstantPoolEntryAddress(unsigned Index) const {
       assert(0 && "CP not implementated yet!");
       return 0;
     }
     virtual intptr_t getJumpTableEntryAddress(unsigned Index) const {
-      assert(0 && "JT not implementated yet!");
-      return 0;
+      assert(JTLocations.size() > Index && "JT not emitted!");
+      return JTLocations[Index];
+    }
+
+    virtual void StartMachineBasicBlock(MachineBasicBlock *MBB) {
+      if (MBBLocations.size() <= (unsigned)MBB->getNumber())
+        MBBLocations.resize((MBB->getNumber()+1)*2);
+      MBBLocations[MBB->getNumber()] = getCurrentPCOffset();
     }
 
     virtual intptr_t getMachineBasicBlockAddress(MachineBasicBlock *MBB) const {
@@ -119,7 +131,9 @@
   // Upgrade the section alignment if required.
   if (MOS->align < Align) MOS->align = Align;
 
-  // Make sure we only relocate to this function's MBBs.
+  // Clear per-function data structures.
+  CPLocations.clear();
+  JTLocations.clear();
   MBBLocations.clear();
 }
 
@@ -132,26 +146,31 @@
   const GlobalValue *FuncV = F.getFunction();
   MachOSym FnSym(FuncV, MOW.Mang->getValueName(FuncV), MOS->Index);
 
-  // FIXME: emit constant pool to appropriate section(s)
-  // FIXME: emit jump table to appropriate section
+  // Emit constant pool to appropriate section(s)
+  emitConstantPool(F.getConstantPool());
+
+  // Emit jump tables to appropriate section
+  emitJumpTables(F.getJumpTableInfo());
   
-  // Resolve the function's relocations either to concrete pointers in the case
-  // of branches from one block to another, or to target relocation entries.
+  // If we have emitted any relocations to function-specific objects such as 
+  // basic blocks, constant pools entries, or jump tables, record their
+  // addresses now so that we can rewrite them with the correct addresses
+  // later.
   for (unsigned i = 0, e = Relocations.size(); i != e; ++i) {
     MachineRelocation &MR = Relocations[i];
+    intptr_t Addr;
     if (MR.isBasicBlock()) {
-      void *MBBAddr = (void *)getMachineBasicBlockAddress(MR.getBasicBlock());
-      MR.setResultPointer(MBBAddr);
-      MOW.TM.getJITInfo()->relocate(BufferBegin, &MR, 1, 0);
-    } else if (MR.isConstantPoolIndex() || MR.isJumpTableIndex()) {
-      // Get the address of the index.
-      uint64_t Addr = 0;
-      // Generate the relocation(s) for the index.
-      MOW.GetTargetRelocation(*MOS, MR, Addr);
-    } else {
-      // Handle other types later once we've finalized the sections in the file.
-      MOS->Relocations.push_back(MR);
+      Addr = getMachineBasicBlockAddress(MR.getBasicBlock());
+      MR.setResultPointer((void *)Addr);
+    } else if (MR.isConstantPoolIndex()) {
+      Addr = getConstantPoolEntryAddress(MR.getConstantPoolIndex());
+      MR.setResultPointer((void *)Addr);
+    } else if (MR.isJumpTableIndex()) {
+      // FIXME: handle PIC codegen
+      Addr = getJumpTableEntryAddress(MR.getJumpTableIndex());
+      MR.setResultPointer((void *)Addr);
     }
+    MOS->Relocations.push_back(MR);
   }
   Relocations.clear();
   
@@ -160,6 +179,42 @@
   return false;
 }
 
+/// emitConstantPool - For each constant pool entry, figure out which section
+/// the constant should live in, allocate space for it, and emit it to the 
+/// Section data buffer.
+void MachOCodeEmitter::emitConstantPool(MachineConstantPool *MCP) {
+}
+
+/// emitJumpTables - Emit all the jump tables for a given jump table info
+/// record to the appropriate section.
+void MachOCodeEmitter::emitJumpTables(MachineJumpTableInfo *MJTI) {
+  const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();
+  if (JT.empty()) return;
+
+  bool isPIC = MOW.TM.getRelocationModel() == Reloc::PIC_;
+  assert(!isPIC && "PIC codegen not yet handled for mach-o jump tables!");
+
+  MachOWriter::MachOSection &Sec = MOW.getJumpTableSection();
+
+  for (unsigned i = 0, e = JT.size(); i != e; ++i) {
+    // For each jump table, record its offset from the start of the section,
+    // reserve space for the relocations to the MBBs, and add the relocations.
+    const std::vector<MachineBasicBlock*> &MBBs = JT[i].MBBs;
+    JTLocations.push_back(Sec.SectionData.size());
+    for (unsigned mi = 0, me = MBBs.size(); mi != me; ++mi) {
+      MachineRelocation MR(MOW.GetJTRelocation(Sec.SectionData.size(),
+                                               MBBs[mi]));
+      MR.setResultPointer((void *)JTLocations[i]);
+      Sec.Relocations.push_back(MR);
+      MOW.outaddr(Sec.SectionData, 0);
+    }
+  }
+  // FIXME: it really seems like keeping these in sync is redundant, someone
+  // should do something about that (never access section size directly, only
+  // look at buffer size).
+  Sec.size = Sec.SectionData.size();
+}
+
 //===----------------------------------------------------------------------===//
 //                          MachOWriter Implementation
 //===----------------------------------------------------------------------===//
@@ -294,12 +349,9 @@
   // Emit the header and load commands.
   EmitHeaderAndLoadCommands();
 
-  // Emit the text and data sections.
+  // Emit the various sections and their relocation info.
   EmitSections();
 
-  // Emit the relocation entry data for each section.
-  O.write((char*)&RelocBuffer[0], RelocBuffer.size());
-
   // Write the symbol table and the string table to the end of the file.
   O.write((char*)&SymT[0], SymT.size());
   O.write((char*)&StrT[0], StrT.size());
@@ -370,6 +422,7 @@
          E = SectionList.end(); I != E; ++I) {
     I->addr = currentAddr;
     I->offset = currentAddr + SEG.fileoff;
+
     // FIXME: do we need to do something with alignment here?
     currentAddr += I->size;
   }
@@ -380,14 +433,8 @@
   for (std::list<MachOSection>::iterator I = SectionList.begin(),
          E = SectionList.end(); I != E; ++I) {
     // calculate the relocation info for this section command
-    // FIXME: this could get complicated calculating the address argument, we 
-    // should probably split this out into its own function.
-    for (unsigned i = 0, e = I->Relocations.size(); i != e; ++i)
-      GetTargetRelocation(*I, I->Relocations[i], 0);
-    if (I->nreloc != 0) {
-      I->reloff = currentAddr;
-      currentAddr += I->nreloc * 8;
-    }
+    CalculateRelocations(*I, currentAddr);
+    currentAddr += I->nreloc * 8;
     
     // write the finalized section command to the output buffer
     outstring(FH, I->sectname, 16);
@@ -449,9 +496,13 @@
 /// commands, emit the data for each section to the file.
 void MachOWriter::EmitSections() {
   for (std::list<MachOSection>::iterator I = SectionList.begin(),
-         E = SectionList.end(); I != E; ++I) {
+         E = SectionList.end(); I != E; ++I)
+    // Emit the contents of each section
     O.write((char*)&I->SectionData[0], I->size);
-  }
+  for (std::list<MachOSection>::iterator I = SectionList.begin(),
+         E = SectionList.end(); I != E; ++I)
+    // Emit the relocation entry data for each section.
+    O.write((char*)&I->RelocBuffer[0], I->RelocBuffer.size());
 }
 
 /// PartitionByLocal - Simple boolean predicate that returns true if Sym is
@@ -526,6 +577,23 @@
   }
 }
 
+/// CalculateRelocations - For each MachineRelocation in the current section,
+/// calculate the index of the section containing the object to be relocated,
+/// and the offset into that section.  From this information, create the
+/// appropriate target-specific MachORelocation type and add buffer it to be
+/// written out after we are finished writing out sections.
+void MachOWriter::CalculateRelocations(MachOSection &MOS, unsigned RelOffset) {
+  for (unsigned i = 0, e = MOS.Relocations.size(); i != e; ++i) {
+    // FIXME: calculate the correct offset and section index for relocated
+    // object.
+    // FIXME: somehow convey the fact that the relocation might be external
+    // to the relocating code.
+    GetTargetRelocation(MOS.Relocations[i], MOS, MOS.Index);
+  }
+  if (MOS.nreloc != 0)
+    MOS.reloff = RelOffset;
+}
+
 MachOSym::MachOSym(const GlobalValue *gv, std::string name, uint8_t sect) :
   GV(gv), GVName(name), n_strx(0), n_type(sect == NO_SECT ? N_UNDF : N_SECT), 
   n_sect(sect), n_desc(0), n_value(0) {
diff --git a/lib/ExecutionEngine/JIT/JITEmitter.cpp b/lib/ExecutionEngine/JIT/JITEmitter.cpp
index e266c75..91ae641 100644
--- a/lib/ExecutionEngine/JIT/JITEmitter.cpp
+++ b/lib/ExecutionEngine/JIT/JITEmitter.cpp
@@ -673,7 +673,7 @@
     ///
     void *ConstantPoolBase;
 
-    /// ConstantPool - The constant pool for the current function.
+    /// JumpTable - The jump tables for the current function.
     ///
     MachineJumpTableInfo *JumpTable;
     
diff --git a/lib/Target/PowerPC/PPCMachOWriter.cpp b/lib/Target/PowerPC/PPCMachOWriter.cpp
index f82ee34..8d6de73 100644
--- a/lib/Target/PowerPC/PPCMachOWriter.cpp
+++ b/lib/Target/PowerPC/PPCMachOWriter.cpp
@@ -31,9 +31,15 @@
       Header.cpusubtype = MachOHeader::CPU_SUBTYPE_POWERPC_ALL;
     }
 
-    virtual void GetTargetRelocation(MachOSection &MOS, MachineRelocation &MR,
-                                     uint64_t Addr);
+    virtual void GetTargetRelocation(MachineRelocation &MR, MachOSection &MOS,
+                                     unsigned ToIndex);
+    virtual MachineRelocation GetJTRelocation(unsigned Offset,
+                                              MachineBasicBlock *MBB);
     
+    virtual const char *getPassName() const {
+      return "PowerPC Mach-O Writer";
+    }
+
     // Constants for the relocation r_type field.
     // see <mach-o/ppc/reloc.h>
     enum { PPC_RELOC_VANILLA, // generic relocation
@@ -53,73 +59,93 @@
 ///
 void llvm::addPPCMachOObjectWriterPass(FunctionPassManager &FPM,
                                        std::ostream &O, PPCTargetMachine &TM) {
-  PPCMachOWriter *EW = new PPCMachOWriter(O, TM);
-  FPM.add(EW);
-  FPM.add(createPPCCodeEmitterPass(TM, EW->getMachineCodeEmitter()));
+  PPCMachOWriter *MOW = new PPCMachOWriter(O, TM);
+  FPM.add(MOW);
+  FPM.add(createPPCCodeEmitterPass(TM, MOW->getMachineCodeEmitter()));
 }
 
 /// GetTargetRelocation - For the MachineRelocation MR, convert it to one or
 /// more PowerPC MachORelocation(s), add the new relocations to the
 /// MachOSection, and rewrite the instruction at the section offset if required 
 /// by that relocation type.
-void PPCMachOWriter::GetTargetRelocation(MachOSection &MOS,
-                                         MachineRelocation &MR,
-                                         uint64_t Addr) {
+void PPCMachOWriter::GetTargetRelocation(MachineRelocation &MR,
+                                         MachOSection &MOS,
+                                         unsigned ToIndex) {
+  uint64_t Addr = 0;
+  
   // Keep track of whether or not this is an externally defined relocation.
-  uint32_t index = MOS.Index;
   bool     isExtern = false;
   
-  // Get the address of the instruction to rewrite
-  unsigned char *RelocPos = &MOS.SectionData[0] + MR.getMachineCodeOffset();
-  
   // Get the address of whatever it is we're relocating, if possible.
-  if (MR.isGlobalValue()) {
-    // determine whether or not its external and then figure out what section
-    // we put it in if it's a locally defined symbol.
-  } else if (MR.isString()) {
-    // lookup in global values?
-  } else {
-    assert((MR.isConstantPoolIndex() || MR.isJumpTableIndex()) &&
-           "Unhandled MachineRelocation type!");
-  }
-  
+  if (!isExtern)
+    Addr = (uintptr_t)MR.getResultPointer();
+    
   switch ((PPC::RelocationType)MR.getRelocationType()) {
   default: assert(0 && "Unknown PPC relocation type!");
-  case PPC::reloc_pcrel_bx:
-  case PPC::reloc_pcrel_bcx:
   case PPC::reloc_absolute_low_ix:
     assert(0 && "Unhandled PPC relocation type!");
     break;
+  case PPC::reloc_vanilla:
+    {
+      // FIXME: need to handle 64 bit vanilla relocs
+      MachORelocation VANILLA(MR.getMachineCodeOffset(), ToIndex, false, 2, 
+                              isExtern, PPC_RELOC_VANILLA);
+      outword(MOS.RelocBuffer, VANILLA.r_address);
+      outword(MOS.RelocBuffer, VANILLA.getPackedFields());
+    }
+    MOS.nreloc += 1;
+    fixword(MOS.SectionData, Addr, MR.getMachineCodeOffset());
+    break;
+  case PPC::reloc_pcrel_bx:
+    Addr -= MR.getMachineCodeOffset();
+    Addr >>= 2;
+    Addr & 0xFFFFFF;
+    Addr <<= 2;
+    Addr |= (MOS.SectionData[MR.getMachineCodeOffset()] << 24);
+    fixword(MOS.SectionData, Addr, MR.getMachineCodeOffset());
+    break;
+  case PPC::reloc_pcrel_bcx:
+    Addr -= MR.getMachineCodeOffset();
+    Addr &= 0xFFFC;
+    fixhalf(MOS.SectionData, Addr, MR.getMachineCodeOffset() + 2);
+    break;
   case PPC::reloc_absolute_high:
     {
-      MachORelocation HA16(MR.getMachineCodeOffset(), index, false, 2, isExtern, 
-                           PPC_RELOC_HA16);
+      MachORelocation HA16(MR.getMachineCodeOffset(), ToIndex, false, 2,
+                           isExtern, PPC_RELOC_HA16);
       MachORelocation PAIR(Addr & 0xFFFF, 0xFFFFFF, false, 2, isExtern,
                            PPC_RELOC_PAIR);
-      outword(RelocBuffer, HA16.r_address);
-      outword(RelocBuffer, HA16.getPackedFields());
-      outword(RelocBuffer, PAIR.r_address);
-      outword(RelocBuffer, PAIR.getPackedFields());
+      outword(MOS.RelocBuffer, HA16.r_address);
+      outword(MOS.RelocBuffer, HA16.getPackedFields());
+      outword(MOS.RelocBuffer, PAIR.r_address);
+      outword(MOS.RelocBuffer, PAIR.getPackedFields());
     }
+    printf("ha16: %x\n", (unsigned)Addr);
     MOS.nreloc += 2;
     Addr += 0x8000;
-    *(unsigned *)RelocPos &= 0xFFFF0000;
-    *(unsigned *)RelocPos |= ((Addr >> 16) & 0xFFFF);
+    fixhalf(MOS.SectionData, Addr >> 16, MR.getMachineCodeOffset() + 2);
     break;
   case PPC::reloc_absolute_low:
     {
-      MachORelocation LO16(MR.getMachineCodeOffset(), index, false, 2, isExtern, 
-                           PPC_RELOC_LO16);
+      MachORelocation LO16(MR.getMachineCodeOffset(), ToIndex, false, 2,
+                           isExtern, PPC_RELOC_LO16);
       MachORelocation PAIR(Addr >> 16, 0xFFFFFF, false, 2, isExtern,
                            PPC_RELOC_PAIR);
-      outword(RelocBuffer, LO16.r_address);
-      outword(RelocBuffer, LO16.getPackedFields());
-      outword(RelocBuffer, PAIR.r_address);
-      outword(RelocBuffer, PAIR.getPackedFields());
+      outword(MOS.RelocBuffer, LO16.r_address);
+      outword(MOS.RelocBuffer, LO16.getPackedFields());
+      outword(MOS.RelocBuffer, PAIR.r_address);
+      outword(MOS.RelocBuffer, PAIR.getPackedFields());
     }
+    printf("lo16: %x\n", (unsigned)Addr);
     MOS.nreloc += 2;
-    *(unsigned *)RelocPos &= 0xFFFF0000;
-    *(unsigned *)RelocPos |= (Addr & 0xFFFF);
+    fixhalf(MOS.SectionData, Addr, MR.getMachineCodeOffset() + 2);
     break;
   }
 }
+
+MachineRelocation PPCMachOWriter::GetJTRelocation(unsigned Offset,
+                                                  MachineBasicBlock *MBB) {
+  // FIXME: do something about PIC
+  return MachineRelocation::getBB(Offset, PPC::reloc_vanilla, MBB);
+}
+
diff --git a/lib/Target/PowerPC/PPCRelocations.h b/lib/Target/PowerPC/PPCRelocations.h
index 21c688d..261622f 100644
--- a/lib/Target/PowerPC/PPCRelocations.h
+++ b/lib/Target/PowerPC/PPCRelocations.h
@@ -25,6 +25,10 @@
 namespace llvm {
   namespace PPC {
     enum RelocationType {
+      // reloc_vanilla - A standard relocation, where the address of the
+      // relocated object completely overwrites the address of the relocation.
+      reloc_vanilla,
+    
       // reloc_pcrel_bx - PC relative relocation, for the b or bl instructions.
       reloc_pcrel_bx,