summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp80
-rw-r--r--llvm/test/MC/Mips/macro-dla-bad.s21
-rw-r--r--llvm/test/MC/Mips/macro-dla-pic.s50
3 files changed, 151 insertions, 0 deletions
diff --git a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
index c60899a0fae..69b1ba1528d 100644
--- a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
+++ b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
@@ -2789,6 +2789,7 @@ bool MipsAsmParser::loadAndAddSymbolAddress(const MCExpr *SymExpr,
bool Is32BitSym, SMLoc IDLoc,
MCStreamer &Out,
const MCSubtargetInfo *STI) {
+ // FIXME: These expansions do not respect -mxgot.
MipsTargetStreamer &TOut = getTargetStreamer();
bool UseSrcReg = SrcReg != Mips::NoRegister;
warnIfNoMacro(IDLoc);
@@ -2869,6 +2870,85 @@ bool MipsAsmParser::loadAndAddSymbolAddress(const MCExpr *SymExpr,
return false;
}
+ if (inPicMode() && ABI.ArePtrs64bit()) {
+ 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_GOT_DISP.
+ if ((DstReg == Mips::T9 || DstReg == Mips::T9_64) && !UseSrcReg &&
+ Res.getConstant() == 0 &&
+ !(Res.getSymA()->getSymbol().isInSection() ||
+ Res.getSymA()->getSymbol().isTemporary() ||
+ (Res.getSymA()->getSymbol().isELF() &&
+ cast<MCSymbolELF>(Res.getSymA()->getSymbol()).getBinding() ==
+ ELF::STB_LOCAL))) {
+ const MCExpr *CallExpr =
+ MipsMCExpr::create(MipsMCExpr::MEK_GOT_CALL, SymExpr, getContext());
+ TOut.emitRRX(Mips::LD, DstReg, ABI.GetGlobalPtr(),
+ MCOperand::createExpr(CallExpr), IDLoc, STI);
+ return false;
+ }
+
+ // The remaining cases are:
+ // Small offset: ld $tmp, %got_disp(symbol)($gp)
+ // >daddiu $tmp, $tmp, offset
+ // >daddu $rd, $tmp, $rs
+ // The daddiu'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_DISP,
+ Res.getSymA(),
+ getContext());
+ const MCExpr *LoExpr = nullptr;
+ if (Res.getConstant() != 0) {
+ // Symbols fully resolve with just the %got_disp(symbol) but we
+ // must still account for any offset to the symbol for
+ // expressions like symbol+8.
+ LoExpr = MCConstantExpr::create(Res.getConstant(), getContext());
+
+ // FIXME: Offsets greater than 16 bits are not yet implemented.
+ // FIXME: The correct range is a 32-bit sign-extended number.
+ if (Res.getConstant() < -0x8000 || Res.getConstant() > 0x7fff) {
+ Error(IDLoc, "macro instruction uses large offset, which is not "
+ "currently supported");
+ return true;
+ }
+ }
+
+ 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::LD, TmpReg, ABI.GetGlobalPtr(),
+ MCOperand::createExpr(GotExpr), IDLoc, STI);
+
+ if (LoExpr)
+ TOut.emitRRX(Mips::DADDiu, TmpReg, TmpReg, MCOperand::createExpr(LoExpr),
+ IDLoc, STI);
+
+ if (UseSrcReg)
+ TOut.emitRRR(Mips::DADDu, DstReg, TmpReg, SrcReg, IDLoc, STI);
+
+ return false;
+ }
+
const MipsMCExpr *HiExpr =
MipsMCExpr::create(MipsMCExpr::MEK_HI, SymExpr, getContext());
const MipsMCExpr *LoExpr =
diff --git a/llvm/test/MC/Mips/macro-dla-bad.s b/llvm/test/MC/Mips/macro-dla-bad.s
new file mode 100644
index 00000000000..cd377f4557c
--- /dev/null
+++ b/llvm/test/MC/Mips/macro-dla-bad.s
@@ -0,0 +1,21 @@
+# RUN: not llvm-mc %s -arch=mips64 -mcpu=mips3 -target-abi n64 2>&1 | \
+# RUN: FileCheck %s
+
+ .text
+ .option pic2
+ dla $5, symbol+0x8000
+ # CHECK: :[[@LINE-1]]:3: error: macro instruction uses large offset, which is not currently supported
+ dla $5, symbol-0x8001
+ # CHECK: :[[@LINE-1]]:3: error: macro instruction uses large offset, which is not currently supported
+ dla $5, symbol+0x8000($6)
+ # CHECK: :[[@LINE-1]]:3: error: macro instruction uses large offset, which is not currently supported
+ dla $5, symbol-0x8001($6)
+ # CHECK: :[[@LINE-1]]:3: error: macro instruction uses large offset, which is not currently supported
+ dla $25, symbol+0x8000
+ # CHECK: :[[@LINE-1]]:3: error: macro instruction uses large offset, which is not currently supported
+ dla $25, symbol-0x8001
+ # CHECK: :[[@LINE-1]]:3: error: macro instruction uses large offset, which is not currently supported
+ dla $25, symbol+0x8000($6)
+ # CHECK: :[[@LINE-1]]:3: error: macro instruction uses large offset, which is not currently supported
+ dla $25, symbol-0x8001($6)
+ # CHECK: :[[@LINE-1]]:3: error: macro instruction uses large offset, which is not currently supported
diff --git a/llvm/test/MC/Mips/macro-dla-pic.s b/llvm/test/MC/Mips/macro-dla-pic.s
new file mode 100644
index 00000000000..ed5aa202618
--- /dev/null
+++ b/llvm/test/MC/Mips/macro-dla-pic.s
@@ -0,0 +1,50 @@
+# RUN: llvm-mc %s -triple=mips64-unknown-linux -show-encoding -mcpu=mips3 | \
+# RUN: FileCheck %s
+
+.option pic2
+dla $5, symbol # CHECK: ld $5, %got_disp(symbol)($gp) # encoding: [0xdf,0x85,A,A]
+ # CHECK: # fixup A - offset: 0, value: %got_disp(symbol), kind: fixup_Mips_GOT_DISP
+dla $5, symbol($6) # CHECK: ld $5, %got_disp(symbol)($gp) # encoding: [0xdf,0x85,A,A]
+ # CHECK: # fixup A - offset: 0, value: %got_disp(symbol), kind: fixup_Mips_GOT_DISP
+ # CHECK: daddu $5, $5, $6 # encoding: [0x00,0xa6,0x28,0x2d]
+dla $6, symbol($6) # CHECK: ld $1, %got_disp(symbol)($gp) # encoding: [0xdf,0x81,A,A]
+ # CHECK: # fixup A - offset: 0, value: %got_disp(symbol), kind: fixup_Mips_GOT_DISP
+ # CHECK: daddu $6, $1, $6 # encoding: [0x00,0x26,0x30,0x2d]
+dla $5, symbol+8 # CHECK: ld $5, %got_disp(symbol)($gp) # encoding: [0xdf,0x85,A,A]
+ # CHECK: # fixup A - offset: 0, value: %got_disp(symbol), kind: fixup_Mips_GOT_DISP
+ # CHECK: daddiu $5, $5, 8 # encoding: [0x64,0xa5,0x00,0x08]
+dla $5, symbol+8($6) # CHECK: ld $5, %got_disp(symbol)($gp) # encoding: [0xdf,0x85,A,A]
+ # CHECK: # fixup A - offset: 0, value: %got_disp(symbol), kind: fixup_Mips_GOT_DISP
+ # CHECK: daddiu $5, $5, 8 # encoding: [0x64,0xa5,0x00,0x08]
+ # CHECK: daddu $5, $5, $6 # encoding: [0x00,0xa6,0x28,0x2d]
+dla $6, symbol+8($6) # CHECK: ld $1, %got_disp(symbol)($gp) # encoding: [0xdf,0x81,A,A]
+ # CHECK: # fixup A - offset: 0, value: %got_disp(symbol), kind: fixup_Mips_GOT_DISP
+ # CHECK: daddiu $1, $1, 8 # encoding: [0x64,0x21,0x00,0x08]
+ # CHECK: daddu $6, $1, $6 # encoding: [0x00,0x26,0x30,0x2d]
+dla $5, 1f # CHECK: ld $5, %got_disp(.Ltmp0)($gp) # encoding: [0xdf,0x85,A,A]
+ # CHECK: # fixup A - offset: 0, value: %got_disp(.Ltmp0), kind: fixup_Mips_GOT_DISP
+1:
+
+# PIC expansions involving $25 are special.
+dla $25, symbol # CHECK: ld $25, %call16(symbol)($gp) # encoding: [0xdf,0x99,A,A]
+ # CHECK: # fixup A - offset: 0, value: %call16(symbol), kind: fixup_Mips_CALL16
+dla $25, symbol($6) # CHECK: ld $25, %got_disp(symbol)($gp) # encoding: [0xdf,0x99,A,A]
+ # CHECK: # fixup A - offset: 0, value: %got_disp(symbol), kind: fixup_Mips_GOT_DISP
+ # CHECK: daddu $25, $25, $6 # encoding: [0x03,0x26,0xc8,0x2d]
+dla $25, symbol($25) # CHECK: ld $1, %got_disp(symbol)($gp) # encoding: [0xdf,0x81,A,A]
+ # CHECK: # fixup A - offset: 0, value: %got_disp(symbol), kind: fixup_Mips_GOT_DISP
+ # CHECK: daddu $25, $1, $25 # encoding: [0x00,0x39,0xc8,0x2d]
+dla $25, symbol+8 # CHECK: ld $25, %got_disp(symbol)($gp) # encoding: [0xdf,0x99,A,A]
+ # CHECK: # fixup A - offset: 0, value: %got_disp(symbol), kind: fixup_Mips_GOT_DISP
+ # CHECK: daddiu $25, $25, 8 # encoding: [0x67,0x39,0x00,0x08]
+dla $25, symbol+8($6) # CHECK: ld $25, %got_disp(symbol)($gp) # encoding: [0xdf,0x99,A,A]
+ # CHECK: # fixup A - offset: 0, value: %got_disp(symbol), kind: fixup_Mips_GOT_DISP
+ # CHECK: daddiu $25, $25, 8 # encoding: [0x67,0x39,0x00,0x08]
+ # CHECK: daddu $25, $25, $6 # encoding: [0x03,0x26,0xc8,0x2d]
+dla $25, symbol+8($25)# CHECK: ld $1, %got_disp(symbol)($gp) # encoding: [0xdf,0x81,A,A]
+ # CHECK: # fixup A - offset: 0, value: %got_disp(symbol), kind: fixup_Mips_GOT_DISP
+ # CHECK: daddiu $1, $1, 8 # encoding: [0x64,0x21,0x00,0x08]
+ # CHECK: daddu $25, $1, $25 # encoding: [0x00,0x39,0xc8,0x2d]
+dla $25, 1f # CHECK: ld $25, %got_disp(.Ltmp1)($gp) # encoding: [0xdf,0x99,A,A]
+ # CHECK: # fixup A - offset: 0, value: %got_disp(.Ltmp1), kind: fixup_Mips_GOT_DISP
+1:
OpenPOWER on IntegriCloud