[llvm-commits] [RFC] PPC64 TOC and MCJIT support

Adhemerval Zanella azanella at linux.vnet.ibm.com
Mon Aug 6 11:11:57 PDT 2012


Although the patch is still WIP and requires a lot of work, I'd appreciate some
advices and feedback for my modifications. As I stated em previous emails, although
llvm generates working code for PPC32, it lacks some functionality for PPC64,
mainly the TOC usage for PIC and PIE generation.

This patch is based on previous email and feedback I got to add support for TOC
and the PPC64 relocation needed for both JIT and assembly. Currently the assembly
generated creates the @toc relocation correctly instead of @ha/@lo, that works
on mostly cases, but are not full PIC and PIE.

The testcase result remains the same, so next step I add PPC64 toc testcase 
to fully test the TOC code generation.

---

Index: include/llvm/Object/ELF.h
===================================================================
--- include/llvm/Object/ELF.h	(revision 161325)
+++ include/llvm/Object/ELF.h	(working copy)
@@ -2015,6 +2015,8 @@
       return "ELF32-arm";
     case ELF::EM_HEXAGON:
       return "ELF32-hexagon";
+    case ELF::EM_PPC:
+      return "ELF32-ppc";
     default:
       return "ELF32-unknown";
     }
@@ -2024,6 +2026,8 @@
       return "ELF64-i386";
     case ELF::EM_X86_64:
       return "ELF64-x86-64";
+    case ELF::EM_PPC64:
+      return "ELF64-ppc64";
     default:
       return "ELF64-unknown";
     }
@@ -2044,6 +2048,10 @@
     return Triple::arm;
   case ELF::EM_HEXAGON:
     return Triple::hexagon;
+  case ELF::EM_PPC:
+    return Triple::ppc;
+  case ELF::EM_PPC64:
+    return Triple::ppc64;
   default:
     return Triple::UnknownArch;
   }
Index: include/llvm/Support/ELF.h
===================================================================
--- include/llvm/Support/ELF.h	(revision 161325)
+++ include/llvm/Support/ELF.h	(working copy)
@@ -441,6 +441,7 @@
   R_MICROBLAZE_COPY           = 21
 };
 
+// ELF Relocation types for PPC32
 enum {
   R_PPC_NONE                  = 0,      /* No relocation. */
   R_PPC_ADDR32                = 1,
@@ -459,6 +460,19 @@
   R_PPC_REL32                 = 26
 };
 
+// ELF Relocation types for PPC64
+enum {
+  R_PPC64_ADDR16_LO           = 4,
+  R_PPC64_ADDR16_HA           = 6,
+  R_PPC64_ADDR14              = 7,
+  R_PPC64_REL24               = 10,
+  R_PPC64_ADDR64              = 38,
+  R_PPC64_TOC16_LO            = 48,
+  R_PPC64_TOC16_HI            = 49,
+  R_PPC64_TOC16_HA            = 50,
+  R_PPC64_TOC16_DS            = 63
+};
+
 // ARM Specific e_flags
 enum { EF_ARM_EABIMASK = 0xFF000000U };
 
Index: lib/Target/PowerPC/PPCCodeEmitter.cpp
===================================================================
--- lib/Target/PowerPC/PPCCodeEmitter.cpp	(revision 161325)
+++ lib/Target/PowerPC/PPCCodeEmitter.cpp	(working copy)
@@ -66,8 +66,12 @@
 
     unsigned getHA16Encoding(const MachineInstr &MI, unsigned OpNo) const;
     unsigned getLO16Encoding(const MachineInstr &MI, unsigned OpNo) const;
+    unsigned getTOCHA16Encoding(const MachineInstr &MI, unsigned OpNo) const;
+    unsigned getTOCLO16Encoding(const MachineInstr &MI, unsigned OpNo) const;
     unsigned getMemRIEncoding(const MachineInstr &MI, unsigned OpNo) const;
+    unsigned getMemRITOCEncoding(const MachineInstr &MI, unsigned OpNo) const;
     unsigned getMemRIXEncoding(const MachineInstr &MI, unsigned OpNo) const;
+    unsigned getMemRIXTOCEncoding(const MachineInstr &MI, unsigned OpNo) const;
 
     const char *getPassName() const { return "PowerPC Machine Code Emitter"; }
 
@@ -211,6 +215,24 @@
   return 0;
 }
 
+unsigned PPCCodeEmitter::getTOCHA16Encoding(const MachineInstr &MI,
+                                         unsigned OpNo) const {
+  const MachineOperand &MO = MI.getOperand(OpNo);
+  if (MO.isReg() || MO.isImm()) return getMachineOpValue(MI, MO);
+
+  MCE.addRelocation(GetRelocation(MO, PPC::reloc_toc_high));
+  return 0;
+}
+
+unsigned PPCCodeEmitter::getTOCLO16Encoding(const MachineInstr &MI,
+                                         unsigned OpNo) const {
+  const MachineOperand &MO = MI.getOperand(OpNo);
+  if (MO.isReg() || MO.isImm()) return getMachineOpValue(MI, MO);
+  
+  MCE.addRelocation(GetRelocation(MO, PPC::reloc_toc_low));
+  return 0;
+}
+
 unsigned PPCCodeEmitter::getMemRIEncoding(const MachineInstr &MI,
                                           unsigned OpNo) const {
   // Encode (imm, reg) as a memri, which has the low 16-bits as the
@@ -227,6 +249,21 @@
   return RegBits;
 }
 
+unsigned PPCCodeEmitter::getMemRITOCEncoding(const MachineInstr &MI,
+                                             unsigned OpNo) const {
+  // Encode (imm, reg) as TOC base memri, which might generated a TOC relocation
+  assert(MI.getOperand(OpNo+1).isReg());
+  unsigned RegBits = getMachineOpValue(MI, MI.getOperand(OpNo+1)) << 14;
+  
+  const MachineOperand &MO = MI.getOperand(OpNo);
+  if (MO.isImm())
+    return (getMachineOpValue(MI, MO) & 0xFFFF) | RegBits;
+  
+  // Add a fixup for the displacement field.
+  MCE.addRelocation(GetRelocation(MO, PPC::reloc_toc_low));
+  return RegBits;
+}
+
 unsigned PPCCodeEmitter::getMemRIXEncoding(const MachineInstr &MI,
                                            unsigned OpNo) const {
   // Encode (imm, reg) as a memrix, which has the low 14-bits as the
@@ -242,6 +279,20 @@
   return RegBits;
 }
 
+unsigned PPCCodeEmitter::getMemRIXTOCEncoding(const MachineInstr &MI,
+                                              unsigned OpNo) const {
+  // Encode (imm, reg) as a memrix, which has the low 14-bits as the
+  // displacement and the next 5 bits as the register #.
+  assert(MI.getOperand(OpNo+1).isReg());
+  unsigned RegBits = getMachineOpValue(MI, MI.getOperand(OpNo+1)) << 14;
+  
+  const MachineOperand &MO = MI.getOperand(OpNo);
+  if (MO.isImm())
+    return (getMachineOpValue(MI, MO) & 0x3FFF) | RegBits;
+  
+  MCE.addRelocation(GetRelocation(MO, PPC::reloc_toc_low_ix));
+  return RegBits;
+}
 
 unsigned PPCCodeEmitter::getMachineOpValue(const MachineInstr &MI,
                                            const MachineOperand &MO) const {
Index: lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp
===================================================================
--- lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp	(revision 161325)
+++ lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp	(working copy)
@@ -43,10 +43,18 @@
                            SmallVectorImpl<MCFixup> &Fixups) const;
   unsigned getLO16Encoding(const MCInst &MI, unsigned OpNo,
                            SmallVectorImpl<MCFixup> &Fixups) const;
+  unsigned getTOCHA16Encoding(const MCInst &MI, unsigned OpNo,
+                              SmallVectorImpl<MCFixup> &Fixups) const;
+  unsigned getTOCLO16Encoding(const MCInst &MI, unsigned OpNo,
+                              SmallVectorImpl<MCFixup> &Fixups) const;
   unsigned getMemRIEncoding(const MCInst &MI, unsigned OpNo,
                             SmallVectorImpl<MCFixup> &Fixups) const;
+  unsigned getMemRITOCEncoding(const MCInst &MI, unsigned OpNo,
+                               SmallVectorImpl<MCFixup> &Fixups) const;
   unsigned getMemRIXEncoding(const MCInst &MI, unsigned OpNo,
                              SmallVectorImpl<MCFixup> &Fixups) const;
+  unsigned getMemRIXTOCEncoding(const MCInst &MI, unsigned OpNo,
+                                SmallVectorImpl<MCFixup> &Fixups) const;
   unsigned get_crbitm_encoding(const MCInst &MI, unsigned OpNo,
                                SmallVectorImpl<MCFixup> &Fixups) const;
 
@@ -128,6 +136,26 @@
   return 0;
 }
 
+unsigned PPCMCCodeEmitter::getTOCHA16Encoding(const MCInst &MI, unsigned OpNo,
+                                       SmallVectorImpl<MCFixup> &Fixups) const {
+  const MCOperand &MO = MI.getOperand(OpNo);
+  if (MO.isReg() || MO.isImm()) return getMachineOpValue(MI, MO, Fixups);
+  
+  Fixups.push_back(MCFixup::Create(0, MO.getExpr(),
+                                   (MCFixupKind)PPC::fixup_ppc_toc_ha16));
+  return 0;
+}
+
+unsigned PPCMCCodeEmitter::getTOCLO16Encoding(const MCInst &MI, unsigned OpNo,
+                                       SmallVectorImpl<MCFixup> &Fixups) const {
+  const MCOperand &MO = MI.getOperand(OpNo);
+  if (MO.isReg() || MO.isImm()) return getMachineOpValue(MI, MO, Fixups);
+  
+  Fixups.push_back(MCFixup::Create(0, MO.getExpr(),
+                                   (MCFixupKind)PPC::fixup_ppc_toc_lo16));
+  return 0;
+}
+
 unsigned PPCMCCodeEmitter::getMemRIEncoding(const MCInst &MI, unsigned OpNo,
                                             SmallVectorImpl<MCFixup> &Fixups) const {
   // Encode (imm, reg) as a memri, which has the low 16-bits as the
@@ -145,6 +173,21 @@
   return RegBits;
 }
 
+unsigned PPCMCCodeEmitter::getMemRITOCEncoding(const MCInst &MI, unsigned OpNo,
+                                               SmallVectorImpl<MCFixup> &Fixups) const {
+  // Encode (imm, reg) as TOC base memri, which might generated a TOC relocation
+  assert(MI.getOperand(OpNo+1).isReg());
+  unsigned RegBits = getMachineOpValue(MI, MI.getOperand(OpNo+1), Fixups) << 14;
+  
+  const MCOperand &MO = MI.getOperand(OpNo);
+  if (MO.isImm())
+    return (getMachineOpValue(MI, MO, Fixups) & 0xFFFF) | RegBits;
+  
+  // Add a fixup for the displacement field.
+  Fixups.push_back(MCFixup::Create(0, MO.getExpr(),
+                                   (MCFixupKind)PPC::fixup_ppc_toc_lo16));
+  return RegBits;
+}
 
 unsigned PPCMCCodeEmitter::getMemRIXEncoding(const MCInst &MI, unsigned OpNo,
                                        SmallVectorImpl<MCFixup> &Fixups) const {
@@ -163,7 +206,23 @@
   return RegBits;
 }
 
+unsigned PPCMCCodeEmitter::getMemRIXTOCEncoding(const MCInst &MI, unsigned OpNo,
+                                           SmallVectorImpl<MCFixup> &Fixups) const {
+  // Encode (imm, reg) as TOC base memri, which might generated a TOC relocation
+  assert(MI.getOperand(OpNo+1).isReg());
+  unsigned RegBits = getMachineOpValue(MI, MI.getOperand(OpNo+1), Fixups) << 14;
+  
+  const MCOperand &MO = MI.getOperand(OpNo);
+  if (MO.isImm())
+    return (getMachineOpValue(MI, MO, Fixups) & 0x3FFF) | RegBits;
+  
+  // Add a fixup for the displacement field.
+  Fixups.push_back(MCFixup::Create(0, MO.getExpr(),
+                                   (MCFixupKind)PPC::fixup_ppc_toc_lo14));
+  return RegBits;
+}
 
+
 unsigned PPCMCCodeEmitter::
 get_crbitm_encoding(const MCInst &MI, unsigned OpNo,
                     SmallVectorImpl<MCFixup> &Fixups) const {
Index: lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp
===================================================================
--- lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp	(revision 161325)
+++ lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp	(working copy)
@@ -29,7 +29,11 @@
   case FK_Data_1:
   case FK_Data_2:
   case FK_Data_4:
+  case FK_Data_8:
     return Value;
+  case PPC::fixup_ppc_lo14:
+  case PPC::fixup_ppc_toc_lo14:
+    return (Value & 0xffff) >> 2;
   case PPC::fixup_ppc_brcond14:
     return Value & 0x3ffc;
   case PPC::fixup_ppc_br24:
@@ -41,6 +45,7 @@
   case PPC::fixup_ppc_ha16:
     return ((Value >> 16) + ((Value & 0x8000) ? 1 : 0)) & 0xffff;
   case PPC::fixup_ppc_lo16:
+  case PPC::fixup_ppc_toc_lo16:
     return Value & 0xffff;
   }
 }
@@ -72,7 +77,9 @@
       { "fixup_ppc_brcond14",    16,     14,   MCFixupKindInfo::FKF_IsPCRel },
       { "fixup_ppc_lo16",        16,     16,   0 },
       { "fixup_ppc_ha16",        16,     16,   0 },
-      { "fixup_ppc_lo14",        16,     14,   0 }
+      { "fixup_ppc_lo14",        16,     14,   0 },
+      { "fixup_ppc_toc_lo16",    16,     16,   0 },
+      { "fixup_ppc_toc_ha16",    16,     16,   0 }
     };
 
     if (Kind < FirstTargetFixupKind)
Index: lib/Target/PowerPC/MCTargetDesc/PPCFixupKinds.h
===================================================================
--- lib/Target/PowerPC/MCTargetDesc/PPCFixupKinds.h	(revision 161325)
+++ lib/Target/PowerPC/MCTargetDesc/PPCFixupKinds.h	(working copy)
@@ -34,6 +34,16 @@
   /// fixup_ppc_lo14 - A 14-bit fixup corresponding to lo16(_foo) for instrs
   /// like 'std'.
   fixup_ppc_lo14,
+
+  /// fixup_ppc_toc_ha16 - A 16-bit fixup based on TOC value to ha16(symbol)
+  fixup_ppc_toc_ha16,
+
+  /// fixup_ppc_toc_lo16 - A 16-bit fixup based on TOC value to lo16(symbol)
+  fixup_ppc_toc_lo16,
+
+  /// fixup_ppc_toc_lo14 - A 14-bit fixup based on TOC value to lo16(symbol)
+  /// with implicity 2 zero bits
+  fixup_ppc_toc_lo14,
   
   // Marker
   LastTargetFixupKind,
Index: lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp
===================================================================
--- lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp	(revision 161325)
+++ lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp	(working copy)
@@ -72,6 +72,15 @@
     case PPC::fixup_ppc_lo14:
       Type = ELF::R_PPC_ADDR14;
       break;
+    case PPC::fixup_ppc_toc_lo16:
+      Type = ELF::R_PPC64_TOC16_LO;
+      break;
+    case PPC::fixup_ppc_toc_lo14:
+      Type = ELF::R_PPC64_TOC16_DS;
+      break;
+    case FK_Data_8:
+      Type = ELF::R_PPC64_ADDR64;
+      break;
     case FK_Data_4:
       Type = ELF::R_PPC_ADDR32;
       break;
Index: lib/Target/PowerPC/PPCRelocations.h
===================================================================
--- lib/Target/PowerPC/PPCRelocations.h	(revision 161325)
+++ lib/Target/PowerPC/PPCRelocations.h	(working copy)
@@ -48,7 +48,21 @@
       
       // reloc_absolute_low_ix - Absolute relocation for the 64-bit load/store
       // instruction which have two implicit zero bits.
-      reloc_absolute_low_ix
+      reloc_absolute_low_ix,
+
+      // reloc_toc_high - TOC relative relocation for 64-bit loadhi instruction
+      // Add the high 16-bits of the relative TOC address into the low 16-bits
+      // of the instruction
+      reloc_toc_high,
+
+      // reloc_toc_low - TOC relative relocation for 64-bit la instruction
+      // Add the high 16-bits of the relative TOC address into the low 16-bits
+      // of the instruction
+      reloc_toc_low,
+
+      // reloc_toc_low_ix - TOC relative relocation for 64-bit load/store
+      // instruction which have two implicet zero bits.
+      reloc_toc_low_ix
     };
   }
 }
Index: lib/Target/PowerPC/PPCInstr64Bit.td
===================================================================
--- lib/Target/PowerPC/PPCInstr64Bit.td	(revision 161325)
+++ lib/Target/PowerPC/PPCInstr64Bit.td	(working copy)
@@ -23,12 +23,22 @@
 }
 def symbolHi64 : Operand<i64> {
   let PrintMethod = "printSymbolHi";
-  let EncoderMethod = "getHA16Encoding";
+  let EncoderMethod = "getTOCHA16Encoding";
 }
 def symbolLo64 : Operand<i64> {
   let PrintMethod = "printSymbolLo";
-  let EncoderMethod = "getLO16Encoding";
+  let EncoderMethod = "getTOCLO16Encoding";
 }
+def memrtoci : Operand<iPTR> {   // memrtoci is toc based imm access
+  let PrintMethod = "printMemRegImm";
+  let MIOperandInfo = (ops i32imm:$imm, ptr_rc:$reg);
+  let EncoderMethod = "getMemRITOCEncoding";
+}
+def memrtocix : Operand<iPTR> {   // memrtoci is toc based imm with shifted 2 bits.
+  let PrintMethod = "printMemRegImmShifted";
+  let MIOperandInfo = (ops i32imm:$imm, ptr_rc:$reg);
+  let EncoderMethod = "getMemRIXTOCEncoding";
+}
 
 //===----------------------------------------------------------------------===//
 // 64-bit transformation functions.
@@ -271,7 +281,7 @@
             PPC970_DGroup_First, PPC970_Unit_FXU;
 
 let Defs = [X1], Uses = [X1] in
-def DYNALLOC8 : Pseudo<(outs G8RC:$result), (ins G8RC:$negsize, memri:$fpsi),"",
+def DYNALLOC8 : Pseudo<(outs G8RC:$result), (ins G8RC:$negsize, memrtoci:$fpsi),"",
                        [(set G8RC:$result,
                              (PPCdynalloc G8RC:$negsize, iaddr:$fpsi))]>;
 
@@ -516,11 +526,11 @@
 
 // Sign extending loads.
 let canFoldAsLoad = 1, PPC970_Unit = 2 in {
-def LHA8: DForm_1<42, (outs G8RC:$rD), (ins memri:$src),
+def LHA8: DForm_1<42, (outs G8RC:$rD), (ins memrtoci:$src),
                   "lha $rD, $src", LdStLHA,
                   [(set G8RC:$rD, (sextloadi16 iaddr:$src))]>,
                   PPC970_DGroup_Cracked;
-def LWA  : DSForm_1<58, 2, (outs G8RC:$rD), (ins memrix:$src),
+def LWA  : DSForm_1<58, 2, (outs G8RC:$rD), (ins memrtocix:$src),
                     "lwa $rD, $src", LdStLWA,
                     [(set G8RC:$rD, (sextloadi32 ixaddr:$src))]>, isPPC64,
                     PPC970_DGroup_Cracked;
@@ -556,13 +566,13 @@
 
 // Zero extending loads.
 let canFoldAsLoad = 1, PPC970_Unit = 2 in {
-def LBZ8 : DForm_1<34, (outs G8RC:$rD), (ins memri:$src),
+def LBZ8 : DForm_1<34, (outs G8RC:$rD), (ins memrtoci:$src),
                   "lbz $rD, $src", LdStLoad,
                   [(set G8RC:$rD, (zextloadi8 iaddr:$src))]>;
-def LHZ8 : DForm_1<40, (outs G8RC:$rD), (ins memri:$src),
+def LHZ8 : DForm_1<40, (outs G8RC:$rD), (ins memrtoci:$src),
                   "lhz $rD, $src", LdStLoad,
                   [(set G8RC:$rD, (zextloadi16 iaddr:$src))]>;
-def LWZ8 : DForm_1<32, (outs G8RC:$rD), (ins memri:$src),
+def LWZ8 : DForm_1<32, (outs G8RC:$rD), (ins memrtoci:$src),
                   "lwz $rD, $src", LdStLoad,
                   [(set G8RC:$rD, (zextloadi32 iaddr:$src))]>, isPPC64;
 
@@ -579,15 +589,15 @@
                    
 // Update forms.
 let mayLoad = 1 in {
-def LBZU8 : DForm_1<35, (outs G8RC:$rD, ptr_rc:$ea_result), (ins memri:$addr),
+def LBZU8 : DForm_1<35, (outs G8RC:$rD, ptr_rc:$ea_result), (ins memrtoci:$addr),
                     "lbzu $rD, $addr", LdStLoad,
                     []>, RegConstraint<"$addr.reg = $ea_result">,
                     NoEncode<"$ea_result">;
-def LHZU8 : DForm_1<41, (outs G8RC:$rD, ptr_rc:$ea_result), (ins memri:$addr),
+def LHZU8 : DForm_1<41, (outs G8RC:$rD, ptr_rc:$ea_result), (ins memrtoci:$addr),
                     "lhzu $rD, $addr", LdStLoad,
                     []>, RegConstraint<"$addr.reg = $ea_result">,
                     NoEncode<"$ea_result">;
-def LWZU8 : DForm_1<33, (outs G8RC:$rD, ptr_rc:$ea_result), (ins memri:$addr),
+def LWZU8 : DForm_1<33, (outs G8RC:$rD, ptr_rc:$ea_result), (ins memrtoci:$addr),
                     "lwzu $rD, $addr", LdStLoad,
                     []>, RegConstraint<"$addr.reg = $ea_result">,
                     NoEncode<"$ea_result">;
@@ -613,13 +623,21 @@
 
 // Full 8-byte loads.
 let canFoldAsLoad = 1, PPC970_Unit = 2 in {
-def LD   : DSForm_1<58, 0, (outs G8RC:$rD), (ins memrix:$src),
+def LD   : DSForm_1<58, 0, (outs G8RC:$rD), (ins memrtocix:$src),
                     "ld $rD, $src", LdStLD,
                     [(set G8RC:$rD, (load ixaddr:$src))]>, isPPC64;
 def LDtoc: Pseudo<(outs G8RC:$rD), (ins tocentry:$disp, G8RC:$reg),
                   "",
                   [(set G8RC:$rD,
                      (PPCtoc_entry tglobaladdr:$disp, G8RC:$reg))]>, isPPC64;
+def LDtocJTI: Pseudo<(outs G8RC:$rD), (ins tocentry:$disp, G8RC:$reg),
+                  "",
+                  [(set G8RC:$rD,
+                     (PPCtoc_entry tjumptable:$disp, G8RC:$reg))]>, isPPC64;
+def LDtocCPT: Pseudo<(outs G8RC:$rD), (ins tocentry:$disp, G8RC:$reg),
+                  "",
+                  [(set G8RC:$rD,
+                     (PPCtoc_entry tconstpool:$disp, G8RC:$reg))]>, isPPC64;
 
 let hasSideEffects = 1 in { 
 let RST = 2, DS_RA = 0 in // FIXME: Should be a pseudo.
@@ -637,7 +655,7 @@
                    [(set G8RC:$rD, (load xaddr:$src))]>, isPPC64;
                    
 let mayLoad = 1 in
-def LDU  : DSForm_1<58, 1, (outs G8RC:$rD, ptr_rc:$ea_result), (ins memrix:$addr),
+def LDU  : DSForm_1<58, 1, (outs G8RC:$rD, ptr_rc:$ea_result), (ins memrtocix:$addr),
                     "ldu $rD, $addr", LdStLD,
                     []>, RegConstraint<"$addr.reg = $ea_result">, isPPC64,
                     NoEncode<"$ea_result">;
@@ -656,13 +674,13 @@
 
 let PPC970_Unit = 2 in {
 // Truncating stores.                       
-def STB8 : DForm_1<38, (outs), (ins G8RC:$rS, memri:$src),
+def STB8 : DForm_1<38, (outs), (ins G8RC:$rS, memrtoci:$src),
                    "stb $rS, $src", LdStStore,
                    [(truncstorei8 G8RC:$rS, iaddr:$src)]>;
-def STH8 : DForm_1<44, (outs), (ins G8RC:$rS, memri:$src),
+def STH8 : DForm_1<44, (outs), (ins G8RC:$rS, memrtoci:$src),
                    "sth $rS, $src", LdStStore,
                    [(truncstorei16 G8RC:$rS, iaddr:$src)]>;
-def STW8 : DForm_1<36, (outs), (ins G8RC:$rS, memri:$src),
+def STW8 : DForm_1<36, (outs), (ins G8RC:$rS, memrtoci:$src),
                    "stw $rS, $src", LdStStore,
                    [(truncstorei32 G8RC:$rS, iaddr:$src)]>;
 def STBX8 : XForm_8<31, 215, (outs), (ins G8RC:$rS, memrr:$dst),
@@ -678,7 +696,7 @@
                    [(truncstorei32 G8RC:$rS, xaddr:$dst)]>,
                    PPC970_DGroup_Cracked;
 // Normal 8-byte stores.
-def STD  : DSForm_1<62, 0, (outs), (ins G8RC:$rS, memrix:$dst),
+def STD  : DSForm_1<62, 0, (outs), (ins G8RC:$rS, memrtocix:$dst),
                     "std $rS, $dst", LdStSTD,
                     [(store G8RC:$rS, ixaddr:$dst)]>, isPPC64;
 def STDX  : XForm_8<31, 149, (outs), (ins G8RC:$rS, memrr:$dst),
@@ -757,7 +775,7 @@
                     PPC970_DGroup_Cracked, isPPC64;
 
 // STD_32/STDX_32 - Just like STD/STDX, but uses a '32-bit' input register.
-def STD_32  : DSForm_1<62, 0, (outs), (ins GPRC:$rT, memrix:$dst),
+def STD_32  : DSForm_1<62, 0, (outs), (ins GPRC:$rT, memrtocix:$dst),
                        "std $rT, $dst", LdStSTD,
                        [(PPCstd_32  GPRC:$rT, ixaddr:$dst)]>, isPPC64;
 def STDX_32  : XForm_8<31, 149, (outs), (ins GPRC:$rT, memrr:$dst),
Index: lib/Target/PowerPC/PPCISelLowering.cpp
===================================================================
--- lib/Target/PowerPC/PPCISelLowering.cpp	(revision 161325)
+++ lib/Target/PowerPC/PPCISelLowering.cpp	(working copy)
@@ -106,7 +106,7 @@
   // from FP_ROUND:  that rounds to nearest, this rounds to zero.
   setOperationAction(ISD::FP_ROUND_INREG, MVT::ppcf128, Custom);
 
-  // We do not currently implment this libm ops for PowerPC.
+  // We do not currently implement this libm ops for PowerPC.
   setOperationAction(ISD::FFLOOR, MVT::ppcf128, Expand);
   setOperationAction(ISD::FCEIL,  MVT::ppcf128, Expand);
   setOperationAction(ISD::FTRUNC, MVT::ppcf128, Expand);
@@ -1204,6 +1204,14 @@
   ConstantPoolSDNode *CP = cast<ConstantPoolSDNode>(Op);
   const Constant *C = CP->getConstVal();
 
+  // 64-bit SVR4 ABI code is always position-independent.
+  // The actual address of the GlobalValue is stored in the TOC.
+  if (PPCSubTarget.isSVR4ABI() && PPCSubTarget.isPPC64()) {
+    SDValue GA = DAG.getTargetConstantPool(C, PtrVT, CP->getAlignment(), 0);
+    return DAG.getNode(PPCISD::TOC_ENTRY, CP->getDebugLoc(), MVT::i64, GA,
+                       DAG.getRegister(PPC::X2, MVT::i64));
+  }
+
   unsigned MOHiFlag, MOLoFlag;
   bool isPIC = GetLabelAccessInfo(DAG.getTarget(), MOHiFlag, MOLoFlag);
   SDValue CPIHi =
@@ -1217,6 +1225,14 @@
   EVT PtrVT = Op.getValueType();
   JumpTableSDNode *JT = cast<JumpTableSDNode>(Op);
 
+  // 64-bit SVR4 ABI code is always position-independent.
+  // The actual address of the GlobalValue is stored in the TOC.
+  if (PPCSubTarget.isSVR4ABI() && PPCSubTarget.isPPC64()) {
+    SDValue GA = DAG.getTargetJumpTable(JT->getIndex(), PtrVT);
+    return DAG.getNode(PPCISD::TOC_ENTRY, JT->getDebugLoc(), MVT::i64, GA,
+                       DAG.getRegister(PPC::X2, MVT::i64));
+  }
+
   unsigned MOHiFlag, MOLoFlag;
   bool isPIC = GetLabelAccessInfo(DAG.getTarget(), MOHiFlag, MOLoFlag);
   SDValue JTIHi = DAG.getTargetJumpTable(JT->getIndex(), PtrVT, MOHiFlag);
Index: lib/Target/PowerPC/PPCAsmPrinter.cpp
===================================================================
--- lib/Target/PowerPC/PPCAsmPrinter.cpp	(revision 161325)
+++ lib/Target/PowerPC/PPCAsmPrinter.cpp	(working copy)
@@ -345,6 +345,29 @@
     OutStreamer.EmitLabel(PICBase);
     return;
   }
+  case PPC::LDtocJTI:
+  case PPC::LDtocCPT: {
+    // Transform %X3 = LDtoc <ga:@min1>, %X2
+    LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, Subtarget.isDarwin());
+
+    // Change the opcode to LD, and the global address operand to be a
+    // reference to the TOC entry we will synthesize later.
+    TmpInst.setOpcode(PPC::LD);
+    const MachineOperand &MO = MI->getOperand(1);
+    assert(MO.isCPI() || MO.isJTI());
+
+    // Map symbol -> label of TOC entry
+    MCSymbol *&TOCEntry = TOC[GetCPISymbol(MO.getIndex())];
+    if (TOCEntry == 0)
+      TOCEntry = GetTempSymbol("C", TOCLabelID++);
+    
+    const MCExpr *Exp =
+      MCSymbolRefExpr::Create(TOCEntry, MCSymbolRefExpr::VK_PPC_TOC,
+			      OutContext);
+    TmpInst.getOperand(1) = MCOperand::CreateExpr(Exp);
+    OutStreamer.EmitInstruction(TmpInst);
+    return;
+  }
   case PPC::LDtoc: {
     // Transform %X3 = LDtoc <ga:@min1>, %X2
     LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, Subtarget.isDarwin());
@@ -423,7 +446,7 @@
 
   bool isPPC64 = TD->getPointerSizeInBits() == 64;
 
-  if (isPPC64 && !TOC.empty()) {
+  if (isPPC64 && !TOC.empty() && OutStreamer.hasRawTextSupport()) {
     const MCSectionELF *Section = OutStreamer.getContext().getELFSection(".toc",
         ELF::SHT_PROGBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC,
         SectionKind::getReadOnly());
Index: lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
===================================================================
--- lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp	(revision 161325)
+++ lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp	(working copy)
@@ -306,6 +306,85 @@
   }
 }
 
+
+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_ha (uint64_t value)
+{
+  return ppc_hi (value) + 0x8000;
+}
+
+static inline
+uint64_t ppc_bit_insert (uint64_t var, uint64_t val, uint64_t mask)
+{
+  return (var & ~mask) | (val & mask);
+}
+
+void RuntimeDyldELF::resolvePPC64Relocation(uint8_t *LocalAddress,
+					    uint64_t FinalAddress,
+					    uint64_t Value,
+					    uint32_t Type,
+					    int64_t Addend) {
+  switch (Type) {
+  default:
+    llvm_unreachable("Relocation type not implemented yet!");
+  break;
+  case ELF::R_PPC64_ADDR16_LO :
+    *(uint16_t*)(LocalAddress) = ppc_lo (Value);
+    break;
+  case ELF::R_PPC64_ADDR16_HA :
+    *(uint16_t*)(LocalAddress) = ppc_ha (Value);
+    break;
+  case ELF::R_PPC64_ADDR14 :
+    {
+      if (((Value + 0x8000) >= 0x10000) || ((Value & 3) != 0))
+	llvm_unreachable("Relocation R_PPC64_ADDR14 overflow");
+      int64_t insn = *(int64_t*)(LocalAddress);
+      // Performs (insn & FFFFFFFFFFFF0003) | (Value & 0xFFFC)
+      // On branch, bit 62 and 63 are ignoned
+      insn = ppc_bit_insert (insn, Value, 0xFFFC);
+      insn &= ~(1 << 21);
+      // insn & (0x14 << 21) checks is 'a' bit in branch is set
+      // 0 means no hint is given
+      if ((insn & (0x14 << 21)) == (0x04 << 21))
+	// Sets the branch is very likely to be taken
+	insn |= 0x02 << 21;
+      else if ((insn & (0x14 << 21)) == (0x10 << 21))
+	// Sets the branch is very likely to not be taken
+	insn |= 0x08 << 21;
+      *(int64_t*)(LocalAddress) = insn;
+    } break;
+  case ELF::R_PPC64_REL24 :
+    {
+      int32_t delta = static_cast<int32_t>(FinalAddress - Value);
+      if (delta << 6 >> 6 != delta)
+	llvm_unreachable("Relocation R_PPC64_REL24 overflow");
+      uint32_t *Target = (uint32_t*)(LocalAddress);
+      *Target = (*Target & 0xFC000003) | (delta & 0x3FFFFFC);
+    } break;
+  case ELF::R_PPC64_ADDR64 :
+    *(uint64_t*)(LocalAddress) = Value;
+    break;
+  case ELF::R_PPC64_TOC16_LO:
+    // TODO
+    break;
+  case ELF::R_PPC64_TOC16_DS:
+    // TODO
+    break;
+  }
+}
+
 void RuntimeDyldELF::resolveRelocation(uint8_t *LocalAddress,
                                        uint64_t FinalAddress,
                                        uint64_t Value,
@@ -326,6 +405,9 @@
                          (uint32_t)(Value & 0xffffffffL), Type,
                          (uint32_t)(Addend & 0xffffffffL));
     break;
+  case Triple::ppc64:
+    resolvePPC64Relocation(LocalAddress, FinalAddress, Value, Type, Addend);
+    break;
   default: llvm_unreachable("Unsupported CPU type!");
   }
 }
@@ -350,6 +432,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;
@@ -361,8 +445,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
@@ -423,6 +505,17 @@
                         Section.StubOffset, RelType, 0);
       Section.StubOffset += getMaxStubSize();
     }
+  } else if (Arch == Triple::ppc64) {
+    if (RelType == ELF::R_PPC64_TOC16_LO) {
+      // This is a TOC based relocation - the final relocation values is based
+      // on Value minus TOC for the section.
+    } else {
+      RelocationEntry RE(Rel.SectionID, Rel.Offset, RelType, Value.Addend);
+      if (Value.SymbolName && (SymType == SymbolRef::ST_Function))
+        addRelocationForSymbol(RE, Value.SymbolName);
+      else
+        addRelocationForSection(RE, Value.SectionID);
+    }
   } else {
     RelocationEntry RE(Rel.SectionID, Rel.Offset, RelType, Value.Addend);
     if (Value.SymbolName)
Index: lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h
===================================================================
--- lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h	(revision 161325)
+++ lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h	(working copy)
@@ -42,6 +42,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,

-- 
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




More information about the llvm-commits mailing list