summaryrefslogtreecommitdiffstats
path: root/llvm
diff options
context:
space:
mode:
authorDaniel Sanders <daniel.sanders@imgtec.com>2016-06-03 09:53:06 +0000
committerDaniel Sanders <daniel.sanders@imgtec.com>2016-06-03 09:53:06 +0000
commit6ba3dd6b719ec740dd54b324bbab40ff25a21642 (patch)
tree37a0953a3558db176da2f05605b9efdcb3a7469f /llvm
parent5bc39ab5925f7b6e312f22481c679d93238824b8 (diff)
downloadbcm5719-llvm-6ba3dd6b719ec740dd54b324bbab40ff25a21642.tar.gz
bcm5719-llvm-6ba3dd6b719ec740dd54b324bbab40ff25a21642.zip
[mips] Implement 'la' macro in PIC mode for O32.
Summary: N32 support will follow in a later patch since the symbol version of 'la' incorrectly believes N32 to have 64-bit pointers and rejects it early. This fixes the three incorrectly expanded 'la' macros found in bionic. Reviewers: sdardis Subscribers: dsanders, llvm-commits, sdardis Differential Revision: http://reviews.llvm.org/D20820 llvm-svn: 271644
Diffstat (limited to 'llvm')
-rw-r--r--llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp84
-rw-r--r--llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp29
-rw-r--r--llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp4
-rw-r--r--llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.h1
-rw-r--r--llvm/test/CodeGen/Mips/hf1_body.ll2
-rw-r--r--llvm/test/MC/Mips/macro-la-pic.s54
6 files changed, 138 insertions, 36 deletions
diff --git a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
index 7c77d31aae9..94f09a95d36 100644
--- a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
+++ b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
@@ -2376,15 +2376,85 @@ bool MipsAsmParser::loadAndAddSymbolAddress(const MCExpr *SymExpr,
MCStreamer &Out,
const MCSubtargetInfo *STI) {
MipsTargetStreamer &TOut = getTargetStreamer();
+ bool UseSrcReg = SrcReg != Mips::NoRegister;
warnIfNoMacro(IDLoc);
- const MCExpr *Symbol = cast<MCExpr>(SymExpr);
+ if (inPicMode() && ABI.IsO32()) {
+ MCValue Res;
+ if (!SymExpr->evaluateAsRelocatable(Res, nullptr, nullptr)) {
+ Error(IDLoc, "expected relocatable expression");
+ return true;
+ }
+ if (Res.getSymB() != nullptr) {
+ Error(IDLoc, "expected relocatable expression with only one symbol");
+ return true;
+ }
+
+ // The case where the result register is $25 is somewhat special. If the
+ // symbol in the final relocation is external and not modified with a
+ // constant then we must use R_MIPS_CALL16 instead of R_MIPS_GOT16.
+ if ((DstReg == Mips::T9 || DstReg == Mips::T9_64) && !UseSrcReg &&
+ Res.getConstant() == 0 && !Res.getSymA()->getSymbol().isInSection() &&
+ !Res.getSymA()->getSymbol().isTemporary()) {
+ const MCExpr *CallExpr =
+ MipsMCExpr::create(MipsMCExpr::MEK_GOT_CALL, SymExpr, getContext());
+ TOut.emitRRX(Mips::LW, DstReg, ABI.GetGlobalPtr(),
+ MCOperand::createExpr(CallExpr), IDLoc, STI);
+ return false;
+ }
+
+ // The remaining cases are:
+ // External GOT: lw $tmp, %got(symbol+offset)($gp)
+ // >addiu $tmp, $tmp, %lo(offset)
+ // >addiu $rd, $tmp, $rs
+ // Local GOT: lw $tmp, %got(symbol+offset)($gp)
+ // addiu $tmp, $tmp, %lo(symbol+offset)($gp)
+ // >addiu $rd, $tmp, $rs
+ // The addiu's marked with a '>' may be omitted if they are redundant. If
+ // this happens then the last instruction must use $rd as the result
+ // register.
+ const MipsMCExpr *GotExpr =
+ MipsMCExpr::create(MipsMCExpr::MEK_GOT, SymExpr, getContext());
+ const MCExpr *LoExpr = nullptr;
+ if (Res.getSymA()->getSymbol().isInSection() ||
+ Res.getSymA()->getSymbol().isTemporary())
+ LoExpr = MipsMCExpr::create(MipsMCExpr::MEK_LO, SymExpr, getContext());
+ else if (Res.getConstant() != 0) {
+ // External symbols fully resolve the symbol with just the %got(symbol)
+ // but we must still account for any offset to the symbol for expressions
+ // like symbol+8.
+ LoExpr = MCConstantExpr::create(Res.getConstant(), getContext());
+ }
+
+ unsigned TmpReg = DstReg;
+ if (UseSrcReg &&
+ getContext().getRegisterInfo()->isSuperOrSubRegisterEq(DstReg,
+ SrcReg)) {
+ // If $rs is the same as $rd, we need to use AT.
+ // If it is not available we exit.
+ unsigned ATReg = getATReg(IDLoc);
+ if (!ATReg)
+ return true;
+ TmpReg = ATReg;
+ }
+
+ TOut.emitRRX(Mips::LW, TmpReg, ABI.GetGlobalPtr(),
+ MCOperand::createExpr(GotExpr), IDLoc, STI);
+
+ if (LoExpr)
+ TOut.emitRRX(Mips::ADDiu, TmpReg, TmpReg, MCOperand::createExpr(LoExpr),
+ IDLoc, STI);
+
+ if (UseSrcReg)
+ TOut.emitRRR(Mips::ADDu, DstReg, TmpReg, SrcReg, IDLoc, STI);
+
+ return false;
+ }
+
const MipsMCExpr *HiExpr =
- MipsMCExpr::create(MipsMCExpr::MEK_HI, Symbol, getContext());
+ MipsMCExpr::create(MipsMCExpr::MEK_HI, SymExpr, getContext());
const MipsMCExpr *LoExpr =
- MipsMCExpr::create(MipsMCExpr::MEK_LO, Symbol, getContext());
-
- bool UseSrcReg = SrcReg != Mips::NoRegister;
+ MipsMCExpr::create(MipsMCExpr::MEK_LO, SymExpr, getContext());
// This is the 64-bit symbol address expansion.
if (ABI.ArePtrs64bit() && isGP64bit()) {
@@ -2395,9 +2465,9 @@ bool MipsAsmParser::loadAndAddSymbolAddress(const MCExpr *SymExpr,
return true;
const MipsMCExpr *HighestExpr =
- MipsMCExpr::create(MipsMCExpr::MEK_HIGHEST, Symbol, getContext());
+ MipsMCExpr::create(MipsMCExpr::MEK_HIGHEST, SymExpr, getContext());
const MipsMCExpr *HigherExpr =
- MipsMCExpr::create(MipsMCExpr::MEK_HIGHER, Symbol, getContext());
+ MipsMCExpr::create(MipsMCExpr::MEK_HIGHER, SymExpr, getContext());
if (UseSrcReg &&
getContext().getRegisterInfo()->isSuperOrSubRegisterEq(DstReg,
diff --git a/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp b/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp
index eae5ebee2ef..08a12010489 100644
--- a/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp
+++ b/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp
@@ -122,33 +122,6 @@ void MipsInstPrinter::printInst(const MCInst *MI, raw_ostream &O,
}
}
-static void printExpr(const MCExpr *Expr, const MCAsmInfo *MAI,
- raw_ostream &OS) {
- int Offset = 0;
- const MCSymbolRefExpr *SRE;
-
- if (const MCBinaryExpr *BE = dyn_cast<MCBinaryExpr>(Expr)) {
- SRE = dyn_cast<MCSymbolRefExpr>(BE->getLHS());
- const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(BE->getRHS());
- assert(SRE && CE && "Binary expression must be sym+const.");
- Offset = CE->getValue();
- } else if (const MipsMCExpr *ME = dyn_cast<MipsMCExpr>(Expr)) {
- ME->print(OS, MAI);
- return;
- } else
- SRE = cast<MCSymbolRefExpr>(Expr);
-
- assert(SRE->getKind() == MCSymbolRefExpr::VK_None && "Invalid kind!");
-
- SRE->getSymbol().print(OS, MAI);
-
- if (Offset) {
- if (Offset > 0)
- OS << '+';
- OS << Offset;
- }
-}
-
void MipsInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
const MCOperand &Op = MI->getOperand(OpNo);
@@ -163,7 +136,7 @@ void MipsInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
}
assert(Op.isExpr() && "unknown operand kind in printOperand");
- printExpr(Op.getExpr(), &MAI, O);
+ Op.getExpr()->print(O, &MAI, true);
}
template <unsigned Bits, unsigned Offset>
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp
index 5fda05a5b4e..97b24ede0cd 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp
@@ -102,6 +102,10 @@ unsigned MipsABIInfo::GetBasePtr() const {
return ArePtrs64bit() ? Mips::S7_64 : Mips::S7;
}
+unsigned MipsABIInfo::GetGlobalPtr() const {
+ return ArePtrs64bit() ? Mips::GP_64 : Mips::GP;
+}
+
unsigned MipsABIInfo::GetNullPtr() const {
return ArePtrs64bit() ? Mips::ZERO_64 : Mips::ZERO;
}
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.h
index 31e6a3ed5ac..06d1251e6d4 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.h
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.h
@@ -66,6 +66,7 @@ public:
unsigned GetStackPtr() const;
unsigned GetFramePtr() const;
unsigned GetBasePtr() const;
+ unsigned GetGlobalPtr() const;
unsigned GetNullPtr() const;
unsigned GetZeroReg() const;
unsigned GetPtrAdduOp() const;
diff --git a/llvm/test/CodeGen/Mips/hf1_body.ll b/llvm/test/CodeGen/Mips/hf1_body.ll
index 260f6c30184..f6102bdd788 100644
--- a/llvm/test/CodeGen/Mips/hf1_body.ll
+++ b/llvm/test/CodeGen/Mips/hf1_body.ll
@@ -23,7 +23,7 @@ entry:
; ALL: .set reorder
; ALL: .reloc 0, R_MIPS_NONE, v_sf
; GAS: la $25, $__fn_local_v_sf
-; IAS: lui $25, %hi($$__fn_local_v_sf)
+; IAS: lw $25, %got($$__fn_local_v_sf)($gp)
; IAS: addiu $25, $25, %lo($$__fn_local_v_sf)
; ALL: mfc1 $4, $f12
; ALL: jr $25
diff --git a/llvm/test/MC/Mips/macro-la-pic.s b/llvm/test/MC/Mips/macro-la-pic.s
new file mode 100644
index 00000000000..5516518ba61
--- /dev/null
+++ b/llvm/test/MC/Mips/macro-la-pic.s
@@ -0,0 +1,54 @@
+# RUN: llvm-mc %s -triple=mips-unknown-linux -show-encoding -mcpu=mips32r2 | \
+# RUN: FileCheck %s
+# RUN: llvm-mc %s -triple=mips-unknown-linux -show-encoding -mcpu=mips32r6 | \
+# RUN: FileCheck %s
+# N32 should be acceptable too but it currently errors out.
+# N64 should be acceptable too but we cannot convert la to dla yet.
+
+.option pic2
+la $5, symbol # CHECK: lw $5, %got(symbol)($gp) # encoding: [0x8f,0x85,A,A]
+ # CHECK: # fixup A - offset: 0, value: %got(symbol), kind: fixup_Mips_GOT
+la $5, symbol($6) # CHECK: lw $5, %got(symbol)($gp) # encoding: [0x8f,0x85,A,A]
+ # CHECK: # fixup A - offset: 0, value: %got(symbol), kind: fixup_Mips_GOT
+ # CHECK: addu $5, $5, $6 # encoding: [0x00,0xa6,0x28,0x21]
+la $6, symbol($6) # CHECK: lw $1, %got(symbol)($gp) # encoding: [0x8f,0x81,A,A]
+ # CHECK: # fixup A - offset: 0, value: %got(symbol), kind: fixup_Mips_GOT
+ # CHECK: addu $6, $1, $6 # encoding: [0x00,0x26,0x30,0x21]
+la $5, symbol+8 # CHECK: lw $5, %got(symbol+8)($gp) # encoding: [0x8f,0x85,A,A]
+ # CHECK: # fixup A - offset: 0, value: %got(symbol+8), kind: fixup_Mips_GOT
+la $5, symbol+8($6) # CHECK: lw $5, %got(symbol+8)($gp) # encoding: [0x8f,0x85,A,A]
+ # CHECK: # fixup A - offset: 0, value: %got(symbol+8), kind: fixup_Mips_GOT
+ # CHECK: addu $5, $5, $6 # encoding: [0x00,0xa6,0x28,0x21]
+la $6, symbol+8($6) # CHECK: lw $1, %got(symbol+8)($gp) # encoding: [0x8f,0x81,A,A]
+ # CHECK: # fixup A - offset: 0, value: %got(symbol+8), kind: fixup_Mips_GOT
+ # CHECK: addiu $1, $1, 8 # encoding: [0x24,0x21,0x00,0x08]
+ # CHECK: addu $6, $1, $6 # encoding: [0x00,0x26,0x30,0x21]
+la $5, 1f # CHECK: lw $5, %got($tmp0)($gp) # encoding: [0x8f,0x85,A,A]
+ # CHECK: # fixup A - offset: 0, value: %got($tmp0), kind: fixup_Mips_GOT
+ # CHECK: addiu $5, $5, %lo($tmp0) # encoding: [0x24,0xa5,A,A]
+ # CHECK: # fixup A - offset: 0, value: %lo($tmp0), kind: fixup_Mips_LO16
+1:
+
+# PIC expansions involving $25 are special.
+la $25, symbol # CHECK: lw $25, %call16(symbol)($gp) # encoding: [0x8f,0x99,A,A]
+ # CHECK: # fixup A - offset: 0, value: %call16(symbol), kind: fixup_Mips_CALL16
+la $25, symbol($6) # CHECK: lw $25, %got(symbol)($gp) # encoding: [0x8f,0x99,A,A]
+ # CHECK: # fixup A - offset: 0, value: %got(symbol), kind: fixup_Mips_GOT
+ # CHECK: addu $25, $25, $6 # encoding: [0x03,0x26,0xc8,0x21]
+la $25, symbol($25) # CHECK: lw $1, %got(symbol)($gp) # encoding: [0x8f,0x81,A,A]
+ # CHECK: # fixup A - offset: 0, value: %got(symbol), kind: fixup_Mips_GOT
+ # CHECK: addu $25, $1, $25 # encoding: [0x00,0x39,0xc8,0x21]
+la $25, symbol+8 # CHECK: lw $25, %got(symbol+8)($gp) # encoding: [0x8f,0x99,A,A]
+ # CHECK: # fixup A - offset: 0, value: %got(symbol+8), kind: fixup_Mips_GOT
+la $25, symbol+8($6) # CHECK: lw $25, %got(symbol+8)($gp) # encoding: [0x8f,0x99,A,A]
+ # CHECK: # fixup A - offset: 0, value: %got(symbol+8), kind: fixup_Mips_GOT
+ # CHECK: addu $25, $25, $6 # encoding: [0x03,0x26,0xc8,0x21]
+la $25, symbol+8($25) # CHECK: lw $1, %got(symbol+8)($gp) # encoding: [0x8f,0x81,A,A]
+ # CHECK: # fixup A - offset: 0, value: %got(symbol+8), kind: fixup_Mips_GOT
+ # CHECK: addiu $1, $1, 8 # encoding: [0x24,0x21,0x00,0x08]
+ # CHECK: addu $25, $1, $25 # encoding: [0x00,0x39,0xc8,0x21]
+la $25, 1f # CHECK: lw $25, %got($tmp1)($gp) # encoding: [0x8f,0x99,A,A]
+ # CHECK: # fixup A - offset: 0, value: %got($tmp1), kind: fixup_Mips_GOT
+ # CHECK: addiu $25, $25, %lo($tmp1) # encoding: [0x27,0x39,A,A]
+ # CHECK: # fixup A - offset: 0, value: %lo($tmp1), kind: fixup_Mips_LO16
+1:
OpenPOWER on IntegriCloud