[llvm-commits] [PATCH 5/5] Initial MCJIT PPC64 support

Will Schmidt will_schmidt at vnet.ibm.com
Wed Sep 5 12:12:05 PDT 2012


On Wed, 2012-09-05 at 13:01 -0300, Adhemerval Zanella wrote:
> This patch adds initial PPC64 JIT support. For this patch, I focused
> on existent
> testcases.

>  Currently, TOC accesses and function calls (internal and external)
> are working.

Please identify the specific testcases.

>  I'm still working on function calls through function pointers and
> also on remaining testcases.

> Please review.

I think may be appropriate to break this up into a few smaller pieces
for easier consumption.   I have no actual issues with the patch code
changes/content, but I'm easy. :-)  (I'll leave code issues for those
more familiar with the LLVM internals).   Cosmetic/potential
break-out/other comments in-line below. 

Thanks, 
-Will

> 
> -- 
> Adhemerval Zanella Netto
>   Software Engineer
>   Linux Technology Center Brazil
>   Toolchain / GLIBC on Power Architecture
>   azanella at linux.vnet.ibm.com / azanella at br.ibm.com
>   +55 61 8642-9890
> 
> 
> 
> 
> 
> 
> 
> 
> differences
> between files
> attachment
> (05-ppc64-mcjit.patch)
> 
> Index: lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
> ===================================================================
> --- lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp     (revision
> 163212)
> +++ lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp     (working copy)
> @@ -194,7 +194,7 @@
>    if (!Addr)
>      report_fatal_error("Unable to allocate memory for common
> symbols!");
>    uint64_t Offset = 0;
> -  Sections.push_back(SectionEntry(Addr, TotalSize, TotalSize, 0));
> +  Sections.push_back(SectionEntry(StringRef(), Addr, TotalSize,
> TotalSize, 0));
>    memset(Addr, 0, TotalSize);
> 
>    DEBUG(dbgs() << "emitCommonSection SectionID: " << SectionID
> @@ -237,10 +237,12 @@
>    bool IsVirtual;
>    bool IsZeroInit;
>    uint64_t DataSize;
> +  StringRef Name;
>    Check(Section.isRequiredForExecution(IsRequired));
>    Check(Section.isVirtual(IsVirtual));
>    Check(Section.isZeroInit(IsZeroInit));
>    Check(Section.getSize(DataSize));
> +  Check(Section.getName(Name));
> 
>    unsigned Allocate;
>    unsigned SectionID = Sections.size();
> @@ -268,6 +270,7 @@
>        memcpy(Addr, pData, DataSize);
> 
>      DEBUG(dbgs() << "emitSection SectionID: " << SectionID
> +                << " Name: " << Name
>                   << " obj addr: " << format("%p", pData)
>                   << " new addr: " << format("%p", Addr)
>                   << " DataSize: " << DataSize
> @@ -283,6 +286,7 @@
>      Allocate = 0;
>      Addr = 0;
>      DEBUG(dbgs() << "emitSection SectionID: " << SectionID
> +                << " Name: " << Name
>                   << " obj addr: " << format("%p", data.data())
>                   << " new addr: 0"
>                   << " DataSize: " << DataSize
> @@ -291,7 +295,8 @@
>                   << "\n");
>    }
> 
> -  Sections.push_back(SectionEntry(Addr, Allocate,
> DataSize,(uintptr_t)pData));
> +  Sections.push_back(SectionEntry(Name, Addr, Allocate, DataSize,
> +                                 (uintptr_t)pData));
>    return SectionID;
>  }

^^ Can the above bits be broken out into an "add 'name' field to
section" patch?

> 
> @@ -357,6 +362,19 @@

^^ 'svn diff -x -p' should include the function name as part of the
diff, will help provide context.
RuntimeDyldImpl::createStubFunction() in this case. 

>      StubAddr++;
>      *StubAddr = NopInstr;
>      return Addr;
> +  } else if (Arch == Triple::ppc64) {
> +    uint32_t *StubAddr = (uint32_t*)Addr;
> +    *StubAddr     = 0x3D800000; // lis   r12, highest(addr)
> +    *(StubAddr+1) = 0x618C0000; // ori   r12, higher(addr)
> +    *(StubAddr+2) = 0x798C07C6; // sldi  r12, r12, 32
> +    *(StubAddr+3) = 0x658C0000; // oris  r12, r12, h(addr)
> +    *(StubAddr+4) = 0x618C0000; // ori   r12, r12, l(addr)
> +    *(StubAddr+5) = 0xE96C0000; // ld    r11, 0(r12)
> +    *(StubAddr+6) = 0xE84C0008; // ld    r2,  0(r12)
> +    *(StubAddr+7) = 0x7D6903A6; // mtctr r11
> +    *(StubAddr+8) = 0xE96C0010; // ld    r11, 16(r2)
> +    *(StubAddr+9) = 0x4E800420; // bctr
> +    return Addr;

^ may be worth adding a comment to clarify to the reader what this stub
is doing.  i.e.  "update R11 to point to the TOC (?)".

>    }
>    return Addr;
>  }
> Index: lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
> ===================================================================
> --- lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp  (revision
> 163212)
> +++ lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp  (working copy)
> @@ -27,6 +27,14 @@
> 
>  namespace {
> 
> +static inline
> +error_code Check(error_code Err) {
> +  if (Err) {
> +    report_fatal_error(Err.message());
> +  }
> +  return Err;
> +}
> +
>  template<support::endianness target_endianness, bool is64Bits>
>  class DyldELFObject : public ELFObjectFile<target_endianness,
> is64Bits> {
>    LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits)
> @@ -344,6 +352,182 @@
>     }
>  }
> 
> +// Return the .TOC. section address to R_PPC64_TOC relocations.
> +uint64_t RuntimeDyldELF::findPPC64TOC() const
> +{
> +  // The TOC consists of sections .got, .toc, .tocbss, .plt in that
> +  // order. The TOC starts where the first of these sections starts.
> +  SectionList::const_iterator it = Sections.begin();
> +  for (; it != Sections.end(); ++it) {
> +    if ((*it).Name == ".got")
> +      break;
> +    if ((*it).Name == ".toc")
> +      break;
> +    if ((*it).Name == ".tocbss")
> +      break;
> +    if ((*it).Name == ".plt")
> +      break;
> +  }
> +  if (it == Sections.end()) {
> +    // This may happen for
> +    // * references to TOC base base (sym at toc, .odp relocation)
> without
> +    // a .toc directive.
> +    // In this case looks just use the first section (which is
> usually
> +    // the .odp) since the code won't reference the .toc base 

s/looks/lets/


> +    // directly.
> +    it = Sections.begin();
> +  }
> +  assert (it != Sections.end());
> +  // The TOC base is the first address in the TOC plus 0x8000
> +  return (*it).LoadAddress + 0x8000;

The above is per the ppc64-elf-linux ABI.   Wouldn't hurt to complete
the paragraph with "thus permitting a full 64 Kbyte TOC.", and possibly
lead-in with "Per the ppc64-elf-linux ABI, The TOC base is ..."


> +}
> +
> +// Returns the sections and offset associate with the ODP entry
> referenced
> +// by \a Symbol.

s/associate/associated/
\a  ??


> +void RuntimeDyldELF::findOPDEntrySection(ObjectImage &Obj,
> +                                         ObjSectionToIDMap
> &LocalSections,
> +                                         RelocationValueRef &Rel)
> +{
> +  // Get the ELF symbol value (st_value) to compare with Relocation
> offset in
> +  // .opd entries
> +  
> +  error_code err;
> +  for (section_iterator si = Obj.begin_sections(),
> +     se = Obj.end_sections(); si != se; si.increment(err)) {
> +    StringRef SectionName;
> +    Check(si->getName(SectionName));
> +    if (SectionName != ".opd")
> +      continue;
> +
> +    for (relocation_iterator i = si->begin_relocations(),
> +         e = si->end_relocations(); i != e;) {
> +      Check(err);
> +
> +      // The R_PPC64_ADDR64 relocation indicates the first field
> +      // of a .opd entry
> +      uint64_t TypeFunc;
> +      Check(i->getType(TypeFunc));
> +      if (TypeFunc != ELF::R_PPC64_ADDR64) {
> +        i.increment(err);
> +        continue;
> +      }
> +
> +      SymbolRef TargetSymbol;
> +      Check(i->getSymbol(TargetSymbol));
> +      uint64_t TargetSymbolOffset;
> +      Check(i->getOffset(TargetSymbolOffset));
> +      int64_t TargetAdditionalInfo;
> +      Check(i->getAdditionalInfo(TargetAdditionalInfo));
> +
> +      i = i.increment(err);
> +      if (i == e)
> +        break;
> +      Check(err);
> +
> +      // Just check if following relocation is a R_PPC64_TOC
> +      uint64_t TypeTOC;
> +      Check(i->getType(TypeTOC));
> +      if (TypeTOC != ELF::R_PPC64_TOC)
> +        continue;
> +
> +      // Finally compares the Symbol value and the target symbol
> offset
> +      // to check if this .opd entry refers to the symbol the
> relocation
> +      // points to.
> +      if (Rel.Addend != (intptr_t)TargetSymbolOffset)
> +        continue;
> +
> +      section_iterator tsi(Obj.end_sections());
> +      Check(TargetSymbol.getSection(tsi));
> +      Rel.SectionID = findOrEmitSection(Obj, (*tsi), true,
> LocalSections);
> +      Rel.Addend = (intptr_t)TargetAdditionalInfo;
> +      return;
> +    }
> +  }
> +  llvm_unreachable("Attempting to get address of ODP entry!");
> +}
> +
> +
> +static inline
> +uint16_t ppc_lo (uint64_t value)
> +{
> +  return value & 0xffff;
> +}
> +
> +static inline
> +uint16_t ppc_hi (uint64_t value)
> +{
> +  return (value >> 16) & 0xffff;
> +}
> +
> +static inline
> +uint16_t ppc_higher (uint64_t value)
> +{
> +  return (value >> 32) & 0xffff;
> +}
> +
> +static inline
> +uint16_t ppc_highest (uint64_t value)
> +{
> +  return (value >> 48) & 0xffff;
> +}
> +
> +void RuntimeDyldELF::resolvePPC64Relocation(uint8_t *LocalAddress,
> +                                           uint64_t FinalAddress,
> +                                           uint64_t Value,
> +                                           uint32_t Type,
> +                                           int64_t Addend) {
> +  uint64_t* RelocAddr = (uint64_t*)LocalAddress;
> +  switch (Type) {
> +  default:
> +    llvm_unreachable("Relocation type not implemented yet!");
> +  break;
> +  case ELF::R_PPC64_ADDR16_LO :
> +    *((uint16_t*)RelocAddr+1) = ppc_lo (Value + Addend);
> +    break;
> +  case ELF::R_PPC64_ADDR16_HI :
> +    *((uint16_t*)RelocAddr+1) = ppc_hi (Value + Addend);
> +    break;
> +  case ELF::R_PPC64_ADDR16_HIGHER :
> +    *((uint16_t*)RelocAddr+1) = ppc_higher (Value + Addend);
> +    break;
> +  case ELF::R_PPC64_ADDR16_HIGHEST :
> +    *((uint16_t*)RelocAddr+1) = ppc_highest (Value + Addend);
> +    break;
> +  case ELF::R_PPC64_ADDR14 :
> +    {
> +      assert(((Value + Addend) & 3) == 0);
> +      uint16_t *insn = ((uint16_t*)RelocAddr+1);
> +      *insn = (*insn & 3) | ((Value + Addend) & 0xfffc);
> +    } break;
> +  case ELF::R_PPC64_REL24 :
> +    {
> +      int32_t delta = static_cast<int32_t>(Value - FinalAddress +
> Addend);
> +      if (SignExtend32<24>(delta) != delta)
> +        llvm_unreachable("Relocation R_PPC64_REL24 overflow");
> +      // Generates a 'bl <address>' instruction
> +      *(uint32_t*)(RelocAddr) = 0x48000001 | (delta & 0x03FFFFFC);
> +    } break;
> +  case ELF::R_PPC64_ADDR64 :
> +    *RelocAddr = Value + Addend;
> +    break;
> +  case ELF::R_PPC64_TOC :
> +    *RelocAddr = findPPC64TOC();
> +    break;
> +  case ELF::R_PPC64_TOC16 :
> +    {
> +      uint64_t TOCStart = findPPC64TOC();
> +      Value = ppc_lo((Value + Addend) - TOCStart);
> +      *((uint16_t*)RelocAddr+1) = ppc_lo (Value);
> +    } break;
> +  case ELF::R_PPC64_TOC16_DS :
> +    {
> +      uint64_t TOCStart = findPPC64TOC();
> +      Value = ((Value + Addend) - TOCStart);
> +      *((uint16_t*)RelocAddr+1) = ppc_lo (Value);
> +    } break;
> +  }
> +}
> +

>  void RuntimeDyldELF::resolveRelocation(uint8_t *LocalAddress,
>                                         uint64_t FinalAddress,
>                                         uint64_t Value,
> @@ -369,6 +553,8 @@
>      resolveMIPSRelocation(LocalAddress, (uint32_t)(FinalAddress &
> 0xffffffffL),
>                            (uint32_t)(Value & 0xffffffffL), Type,
>                            (uint32_t)(Addend & 0xffffffffL));
> +  case Triple::ppc64:
> +    resolvePPC64Relocation(LocalAddress, FinalAddress, Value, Type,
> Addend);
>      break;
>    default: llvm_unreachable("Unsupported CPU type!");
>    }
> @@ -394,6 +580,8 @@
>    RelocationValueRef Value;
>    // First search for the symbol in the local symbol table
>    SymbolTableMap::const_iterator lsi =
> Symbols.find(TargetName.data());
> +  SymbolRef::Type SymType;
> +  Symbol.getType(SymType);
>    if (lsi != Symbols.end()) {
>      Value.SectionID = lsi->second.first;
>      Value.Addend = lsi->second.second;
> @@ -405,8 +593,6 @@
>        Value.SectionID = gsi->second.first;
>        Value.Addend = gsi->second.second;
>      } else {
> -      SymbolRef::Type SymType;
> -      Symbol.getType(SymType);
>        switch (SymType) {
>          case SymbolRef::ST_Debug: {
>            // TODO: Now ELF SymbolRef::ST_Debug = STT_SECTION, it's
> not obviously
> @@ -514,6 +700,85 @@
>                          Section.StubOffset, RelType, 0);
>        Section.StubOffset += getMaxStubSize();
>      }
> +  } else if (Arch == Triple::ppc64) {
> +    if (RelType == ELF::R_PPC64_REL24) {
> +      // A PPC branch relocation will need a stub function if the
> target is
> +      // an external symbol (Symbol::ST_Unknown) or if the target
> address
> +      // is not within the signed 24-bits branch address.
> +      SectionEntry &Section = Sections[Rel.SectionID];
> +      uint8_t *Target = Section.Address + Rel.Offset;
> +      if (SymType != SymbolRef::ST_Unknown) {
> +        // A function call may points to the .opd entry, so the final
> symbol value
> +        // in calculated based in the relocation values in .opd
> section.
> +        findOPDEntrySection(Obj, ObjSectionToID, Value);
> +        uint8_t *RelocTarget = Sections[Value.SectionID].Address +
> Value.Addend;
> +        int32_t delta = static_cast<int32_t>(Target - RelocTarget);
> +        // If it is within 24-bits branch range, just set the branch
> target
> +        if (SignExtend32<24>(delta) == delta) {
> +          RelocationEntry RE(Rel.SectionID, Rel.Offset, RelType,
> Value.Addend);
> +          if (Value.SymbolName)
> +            addRelocationForSymbol(RE, Value.SymbolName);
> +          else
> +            addRelocationForSection(RE, Value.SectionID);
> +        }
> +      } else {
> +        // It is an external symbol (SymbolRef::ST_Unknown) or within
> a range
> +        // larger than 24-bits.
> +        StubMap::const_iterator i = Stubs.find(Value);
> +        if (i != Stubs.end()) {
> +          // Symbol function stub already created, just relocate to
> it
> +          resolveRelocation(Target, (uint64_t)Target,
> (uint64_t)Section.Address
> +                            + i->second, RelType, 0);
> +          DEBUG(dbgs() << " Stub function found\n");
> +        } else {
> +          // Create a new stub function.
> +          DEBUG(dbgs() << " Create a new stub function\n");
> +          Stubs[Value] = Section.StubOffset;
> +          uint8_t *StubTargetAddr =
> createStubFunction(Section.Address +
> +
> Section.StubOffset);
> +          RelocationEntry RE(Rel.SectionID, StubTargetAddr -
> Section.Address,
> +                             ELF::R_PPC64_ADDR64, Value.Addend);
> +
> +          // Generates the 64-bits address loads as exemplified in
> section
> +          // 4.5.1 in PPC64 ELF ABI.

> +          RelocationEntry REhst(Rel.SectionID,
> +                                StubTargetAddr - Section.Address,
> +                                ELF::R_PPC64_ADDR16_HIGHEST,
> Value.Addend);
> +          RelocationEntry REhr(Rel.SectionID,
> +                               StubTargetAddr - Section.Address + 4,
> +                               ELF::R_PPC64_ADDR16_HIGHER,
> Value.Addend);
> +          RelocationEntry REh(Rel.SectionID,
> +                               StubTargetAddr - Section.Address + 12,
> +                               ELF::R_PPC64_ADDR16_HI, Value.Addend);
> +          RelocationEntry REl(Rel.SectionID,
> +                               StubTargetAddr - Section.Address + 16,
> +                               ELF::R_PPC64_ADDR16_LO, Value.Addend);
> +
> +          if (Value.SymbolName) {
> +            addRelocationForSymbol(REhst, Value.SymbolName);
> +            addRelocationForSymbol(REhr,  Value.SymbolName);
> +            addRelocationForSymbol(REh,   Value.SymbolName);
> +            addRelocationForSymbol(REl,   Value.SymbolName);
> +          } else {
> +            addRelocationForSection(REhst, Value.SectionID);
> +            addRelocationForSection(REhr,  Value.SectionID);
> +            addRelocationForSection(REh,   Value.SectionID);
> +            addRelocationForSection(REl,   Value.SectionID);
> +          }
> +
> +          resolveRelocation(Target, (uint64_t)Target,
> (uint64_t)Section.Address
> +                            + Section.StubOffset, RelType, 0);
> +          Section.StubOffset += getMaxStubSize();
> +        }
> +      }
> +    } else {
> +      RelocationEntry RE(Rel.SectionID, Rel.Offset, RelType,
> Value.Addend);
> +      // Extra check to avoid relocation creation against .TOC.
> symbol
> +      if (Value.SymbolName && TargetName != ".TOC.")
> +        addRelocationForSymbol(RE, Value.SymbolName);
> +      else
> +        addRelocationForSection(RE, Value.SectionID);
> +    }
>    } else {
>      RelocationEntry RE(Rel.SectionID, Rel.Offset, RelType,
> Value.Addend);
>      if (Value.SymbolName)

^ Per amount of content, I'd try to break out the relocation code into a
separate patch.  (ppc_hi(), ppc_lo(),... resolveRelocation()...  )   

Fully understanding that it's all intermixed, and probably painful to
do..   :-o :-) 



> Index: lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
> ===================================================================
> --- lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h   (revision
> 163212)
> +++ lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h   (working copy)
> @@ -41,6 +41,9 @@
>  /// linker.
>  class SectionEntry {
>  public:
> +  /// Name - section name.
> +  StringRef Name;
> +
>    /// Address - address in the linker's memory where the section
> resides.
>    uint8_t *Address;
> 
> @@ -61,9 +64,9 @@
>    /// for calculating relocations in some object formats (like
> MachO).
>    uintptr_t ObjAddress;
> 
> -  SectionEntry(uint8_t *address, size_t size, uintptr_t stubOffset,
> -               uintptr_t objAddress)
> -    : Address(address), Size(size), LoadAddress((uintptr_t)address),
> +  SectionEntry(StringRef name, uint8_t *address, size_t size,
> +              uintptr_t stubOffset, uintptr_t objAddress)
> +    : Name(name), Address(address), Size(size),
> LoadAddress((uintptr_t)address),
>        StubOffset(stubOffset), ObjAddress(objAddress) {}
>  };


^ this would fit into the "add 'name' field" break-out patch. 



> 
> @@ -163,6 +166,8 @@
>        return 8; // 32-bit instruction and 32-bit address
>      else if (Arch == Triple::mipsel)
>        return 16;
> +    else if (Arch == Triple::ppc64)
> +      return 40;
>      else
>        return 0;
>    }
> Index: lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h
> ===================================================================
> --- lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h    (revision
> 163212)
> +++ lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h    (working copy)
> @@ -48,6 +48,12 @@
>                               uint32_t Type,
>                               int32_t Addend);
> 
> +  void resolvePPC64Relocation(uint8_t *LocalAddress,
> +                              uint64_t FinalAddress,
> +                              uint64_t Value,
> +                              uint32_t Type,
> +                              int64_t Addend);
> +
>    virtual void resolveRelocation(uint8_t *LocalAddress,
>                                   uint64_t FinalAddress,
>                                   uint64_t Value,
> @@ -63,6 +69,11 @@
>    virtual ObjectImage *createObjectImage(const MemoryBuffer
> *InputBuffer);
>    virtual void handleObjectLoaded(ObjectImage *Obj);
> 
> +  uint64_t findPPC64TOC() const;
> +  void findOPDEntrySection(ObjectImage &Obj,
> +                           ObjSectionToIDMap &LocalSections,
> +                           RelocationValueRef &Rel);
> +
>  public:
>    RuntimeDyldELF(RTDyldMemoryManager *mm)
>        : RuntimeDyldImpl(mm), LoadedObject(0) {}
> 
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
> 
> 




More information about the llvm-commits mailing list