[Sparc] Add support for 13-bit PIC
Summary: When compiling with -fpic, in contrast to -fPIC, use only the
immediate field to index into the GOT. This saves space if the GOT is
known to be small. The linker will warn if the GOT is too large for
this method.
Reviewers: jyknight, venkatra
Reviewed By: jyknight
Subscribers: brad, fedor.sergeev, jrtc27, llvm-commits
Differential Revision: https://reviews.llvm.org/D47136
llvm-svn: 334383
diff --git a/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp b/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
index 35d92a9..c7a5a1e 100644
--- a/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
+++ b/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
@@ -885,9 +885,17 @@
const MCExpr *Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None,
getContext());
- if (isCall && getContext().getObjectFileInfo()->isPositionIndependent())
- Res = SparcMCExpr::create(SparcMCExpr::VK_Sparc_WPLT30, Res,
- getContext());
+ SparcMCExpr::VariantKind Kind = SparcMCExpr::VK_Sparc_13;
+
+ if (getContext().getObjectFileInfo()->isPositionIndependent()) {
+ if (isCall)
+ Kind = SparcMCExpr::VK_Sparc_WPLT30;
+ else
+ Kind = SparcMCExpr::VK_Sparc_GOT13;
+ }
+
+ Res = SparcMCExpr::create(Kind, Res, getContext());
+
Op = SparcOperand::CreateImm(Res, S, E);
}
break;
diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp b/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
index 4b6c1de..5f5e2ef 100644
--- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
+++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
@@ -54,6 +54,10 @@
case Sparc::fixup_sparc_hi22:
return (Value >> 10) & 0x3fffff;
+ case Sparc::fixup_sparc_got13:
+ case Sparc::fixup_sparc_13:
+ return Value & 0x1fff;
+
case Sparc::fixup_sparc_pc10:
case Sparc::fixup_sparc_got10:
case Sparc::fixup_sparc_tls_gd_lo10:
@@ -120,6 +124,7 @@
{ "fixup_sparc_br19", 13, 19, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_sparc_br16_2", 10, 2, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_sparc_br16_14", 18, 14, MCFixupKindInfo::FKF_IsPCRel },
+ { "fixup_sparc_13", 19, 13, 0 },
{ "fixup_sparc_hi22", 10, 22, 0 },
{ "fixup_sparc_lo10", 22, 10, 0 },
{ "fixup_sparc_h44", 10, 22, 0 },
@@ -131,6 +136,7 @@
{ "fixup_sparc_pc10", 22, 10, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_sparc_got22", 10, 22, 0 },
{ "fixup_sparc_got10", 22, 10, 0 },
+ { "fixup_sparc_got13", 19, 13, 0 },
{ "fixup_sparc_wplt30", 2, 30, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_sparc_tls_gd_hi22", 10, 22, 0 },
{ "fixup_sparc_tls_gd_lo10", 22, 10, 0 },
@@ -159,6 +165,7 @@
{ "fixup_sparc_br19", 0, 19, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_sparc_br16_2", 20, 2, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_sparc_br16_14", 0, 14, MCFixupKindInfo::FKF_IsPCRel },
+ { "fixup_sparc_13", 0, 13, 0 },
{ "fixup_sparc_hi22", 0, 22, 0 },
{ "fixup_sparc_lo10", 0, 10, 0 },
{ "fixup_sparc_h44", 0, 22, 0 },
@@ -170,6 +177,7 @@
{ "fixup_sparc_pc10", 0, 10, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_sparc_got22", 0, 22, 0 },
{ "fixup_sparc_got10", 0, 10, 0 },
+ { "fixup_sparc_got13", 0, 13, 0 },
{ "fixup_sparc_wplt30", 0, 30, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_sparc_tls_gd_hi22", 0, 22, 0 },
{ "fixup_sparc_tls_gd_lo10", 0, 10, 0 },
diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp b/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp
index 173ef86..5a73094 100644
--- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp
+++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp
@@ -79,6 +79,7 @@
case FK_Data_8: return ((Fixup.getOffset() % 8)
? ELF::R_SPARC_UA64
: ELF::R_SPARC_64);
+ case Sparc::fixup_sparc_13: return ELF::R_SPARC_13;
case Sparc::fixup_sparc_hi22: return ELF::R_SPARC_HI22;
case Sparc::fixup_sparc_lo10: return ELF::R_SPARC_LO10;
case Sparc::fixup_sparc_h44: return ELF::R_SPARC_H44;
@@ -88,6 +89,7 @@
case Sparc::fixup_sparc_hm: return ELF::R_SPARC_HM10;
case Sparc::fixup_sparc_got22: return ELF::R_SPARC_GOT22;
case Sparc::fixup_sparc_got10: return ELF::R_SPARC_GOT10;
+ case Sparc::fixup_sparc_got13: return ELF::R_SPARC_GOT13;
case Sparc::fixup_sparc_tls_gd_hi22: return ELF::R_SPARC_TLS_GD_HI22;
case Sparc::fixup_sparc_tls_gd_lo10: return ELF::R_SPARC_TLS_GD_LO10;
case Sparc::fixup_sparc_tls_gd_add: return ELF::R_SPARC_TLS_GD_ADD;
diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h b/llvm/lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h
index 8d79396..99aa63f 100644
--- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h
+++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h
@@ -30,6 +30,9 @@
fixup_sparc_br16_2,
fixup_sparc_br16_14,
+ /// fixup_sparc_13 - 13-bit fixup
+ fixup_sparc_13,
+
/// fixup_sparc_hi22 - 22-bit fixup corresponding to %hi(foo)
/// for sethi
fixup_sparc_hi22,
@@ -64,6 +67,9 @@
/// fixup_sparc_got10 - 10-bit fixup corresponding to %got10(foo)
fixup_sparc_got10,
+ /// fixup_sparc_got13 - 13-bit fixup corresponding to %got13(foo)
+ fixup_sparc_got13,
+
/// fixup_sparc_wplt30
fixup_sparc_wplt30,
diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp b/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp
index 2b80293..f736a37 100644
--- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp
+++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp
@@ -58,6 +58,8 @@
// FIXME: use %got22/%got10, if system assembler supports them.
case VK_Sparc_GOT22: OS << "%hi("; break;
case VK_Sparc_GOT10: OS << "%lo("; break;
+ case VK_Sparc_GOT13: closeParen = false; break;
+ case VK_Sparc_13: closeParen = false; break;
case VK_Sparc_WPLT30: closeParen = false; break;
case VK_Sparc_R_DISP32: OS << "%r_disp32("; break;
case VK_Sparc_TLS_GD_HI22: OS << "%tgd_hi22("; break;
@@ -96,6 +98,7 @@
.Case("pc10", VK_Sparc_PC10)
.Case("got22", VK_Sparc_GOT22)
.Case("got10", VK_Sparc_GOT10)
+ .Case("got13", VK_Sparc_GOT13)
.Case("r_disp32", VK_Sparc_R_DISP32)
.Case("tgd_hi22", VK_Sparc_TLS_GD_HI22)
.Case("tgd_lo10", VK_Sparc_TLS_GD_LO10)
@@ -132,6 +135,8 @@
case VK_Sparc_PC10: return Sparc::fixup_sparc_pc10;
case VK_Sparc_GOT22: return Sparc::fixup_sparc_got22;
case VK_Sparc_GOT10: return Sparc::fixup_sparc_got10;
+ case VK_Sparc_GOT13: return Sparc::fixup_sparc_got13;
+ case VK_Sparc_13: return Sparc::fixup_sparc_13;
case VK_Sparc_WPLT30: return Sparc::fixup_sparc_wplt30;
case VK_Sparc_TLS_GD_HI22: return Sparc::fixup_sparc_tls_gd_hi22;
case VK_Sparc_TLS_GD_LO10: return Sparc::fixup_sparc_tls_gd_lo10;
diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h b/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h
index 13f0819..cf2db06 100644
--- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h
+++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h
@@ -36,6 +36,8 @@
VK_Sparc_PC10,
VK_Sparc_GOT22,
VK_Sparc_GOT10,
+ VK_Sparc_GOT13,
+ VK_Sparc_13,
VK_Sparc_WPLT30,
VK_Sparc_R_DISP32,
VK_Sparc_TLS_GD_HI22,
diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
index 34e0297f..14a99c0 100644
--- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp
+++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
@@ -1980,11 +1980,22 @@
// Handle PIC mode first. SPARC needs a got load for every variable!
if (isPositionIndependent()) {
- // This is the pic32 code model, the GOT is known to be smaller than 4GB.
- SDValue HiLo = makeHiLoPair(Op, SparcMCExpr::VK_Sparc_GOT22,
- SparcMCExpr::VK_Sparc_GOT10, DAG);
+ const Module *M = DAG.getMachineFunction().getFunction().getParent();
+ PICLevel::Level picLevel = M->getPICLevel();
+ SDValue Idx;
+
+ if (picLevel == PICLevel::SmallPIC) {
+ // This is the pic13 code model, the GOT is known to be smaller than 8KiB.
+ Idx = DAG.getNode(SPISD::Lo, DL, Op.getValueType(),
+ withTargetFlags(Op, SparcMCExpr::VK_Sparc_GOT13, DAG));
+ } else {
+ // This is the pic32 code model, the GOT is known to be smaller than 4GB.
+ Idx = makeHiLoPair(Op, SparcMCExpr::VK_Sparc_GOT22,
+ SparcMCExpr::VK_Sparc_GOT10, DAG);
+ }
+
SDValue GlobalBase = DAG.getNode(SPISD::GLOBAL_BASE_REG, DL, VT);
- SDValue AbsAddr = DAG.getNode(ISD::ADD, DL, VT, GlobalBase, HiLo);
+ SDValue AbsAddr = DAG.getNode(ISD::ADD, DL, VT, GlobalBase, Idx);
// GLOBAL_BASE_REG codegen'ed with call. Inform MFI that this
// function has calls.
MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
diff --git a/llvm/test/CodeGen/SPARC/pic.ll b/llvm/test/CodeGen/SPARC/pic.ll
new file mode 100644
index 0000000..4edbffc
--- /dev/null
+++ b/llvm/test/CodeGen/SPARC/pic.ll
@@ -0,0 +1,14 @@
+; RUN: llc < %s -relocation-model=pic -mtriple=sparc | FileCheck %s
+
+@value = external global i32
+
+define i32 @test() nounwind {
+; CHECK: ld [%i0+value], %i0
+entry:
+ %0 = load i32, i32* @value
+ ret i32 %0
+}
+
+!llvm.module.flags = !{!0}
+
+!0 = !{i32 7, !"PIC Level", i32 1}
diff --git a/llvm/test/MC/Sparc/sparc-pic.s b/llvm/test/MC/Sparc/sparc-pic.s
index f51e1e9..a16ed80 100644
--- a/llvm/test/MC/Sparc/sparc-pic.s
+++ b/llvm/test/MC/Sparc/sparc-pic.s
@@ -15,6 +15,7 @@
! PIC-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_GOT22 .LC0 0x0
! PIC-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_GOT10 .LC0 0x0
! PIC-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_WPLT30 bar 0x0
+! PIC: 0x{{[0-9,A-F]+}} R_SPARC_GOT13 value 0x0
! PIC: ]
! NOPIC: Relocations [
@@ -30,6 +31,7 @@
! NOPIC-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_HI22 .rodata 0x0
! NOPIC-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_LO10 .rodata 0x0
! NOPIC-NEXT: 0x{{[0-9,A-F]+}} R_SPARC_WDISP30 bar 0x0
+! NOPIC: 0x{{[0-9,A-F]+}} R_SPARC_13 value 0x0
! NOPIC: ]
.section ".rodata"
@@ -78,3 +80,24 @@
AGlobalVar:
.xword 0 ! 0x0
.size AGlobalVar, 8
+
+ .section ".text"
+ .text
+ .globl pic13
+ .align 4
+ .type pic13,@function
+pic13:
+ save %sp, -128, %sp
+.Ltmp0:
+ call .Ltmp1
+.Ltmp2:
+ sethi %hi(_GLOBAL_OFFSET_TABLE_+(.Ltmp2-.Ltmp0)), %i0
+.Ltmp1:
+ or %i0, %lo(_GLOBAL_OFFSET_TABLE_+(.Ltmp1-.Ltmp0)), %i0
+ add %i0, %o7, %i0
+ ldx [%i0+value], %i0
+ ld [%i0], %i0
+ ret
+ restore
+.Lfunc_end0:
+ .size pic13, .Lfunc_end0-pic13
diff --git a/llvm/test/MC/Sparc/sparc-relocations.s b/llvm/test/MC/Sparc/sparc-relocations.s
index 58ad37e..18fc123 100644
--- a/llvm/test/MC/Sparc/sparc-relocations.s
+++ b/llvm/test/MC/Sparc/sparc-relocations.s
@@ -11,6 +11,7 @@
! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_L44 sym
! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_HH22 sym
! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_HM10 sym
+ ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_13 sym
! CHECK-ELF: ]
! CHECK: call foo ! encoding: [0b01AAAAAA,A,A,A]
@@ -44,3 +45,7 @@
! CHECK: or %g1, %hm(sym), %g3 ! encoding: [0x86,0x10,0b011000AA,A]
! CHECK-NEXT: ! fixup A - offset: 0, value: %hm(sym), kind: fixup_sparc_hm
or %g1, %hm(sym), %g3
+
+ ! CHECK: or %g1, sym, %g3 ! encoding: [0x86,0x10,0b011AAAAA,A]
+ ! CHECK-NEXT: ! fixup A - offset: 0, value: sym, kind: fixup_sparc_13
+ or %g1, sym, %g3