[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
This commit is contained in:
Daniel Sanders 2016-06-03 09:53:06 +00:00
parent 5bc39ab592
commit 6ba3dd6b71
6 changed files with 139 additions and 37 deletions

View File

@ -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);
const MipsMCExpr *HiExpr =
MipsMCExpr::create(MipsMCExpr::MEK_HI, Symbol, getContext());
const MipsMCExpr *LoExpr =
MipsMCExpr::create(MipsMCExpr::MEK_LO, Symbol, getContext());
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;
}
bool UseSrcReg = SrcReg != Mips::NoRegister;
// 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, SymExpr, getContext());
const MipsMCExpr *LoExpr =
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,

View File

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

View File

@ -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;
}

View File

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

View File

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

View File

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