[mips] Reduce code duplication in the `loadAndAddSymbolAddress`. NFC

llvm-svn: 372218
This commit is contained in:
Simon Atanasyan 2019-09-18 12:24:23 +00:00
parent 4b8b7f249c
commit 59d0cc82b5
1 changed files with 57 additions and 106 deletions

View File

@ -2877,7 +2877,7 @@ bool MipsAsmParser::loadAndAddSymbolAddress(const MCExpr *SymExpr,
SrcReg != Mips::ZERO_64;
warnIfNoMacro(IDLoc);
if (inPicMode() && ABI.IsO32()) {
if (inPicMode()) {
MCValue Res;
if (!SymExpr->evaluateAsRelocatable(Res, nullptr, nullptr)) {
Error(IDLoc, "expected relocatable expression");
@ -2888,6 +2888,7 @@ bool MipsAsmParser::loadAndAddSymbolAddress(const MCExpr *SymExpr,
return true;
}
bool IsPtr64 = ABI.ArePtrs64bit();
bool IsLocalSym =
Res.getSymA()->getSymbol().isInSection() ||
Res.getSymA()->getSymbol().isTemporary() ||
@ -2897,117 +2898,66 @@ bool MipsAsmParser::loadAndAddSymbolAddress(const MCExpr *SymExpr,
// 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.
// constant then we must use R_MIPS_CALL16 instead of R_MIPS_GOT16
// or R_MIPS_CALL16 instead of R_MIPS_GOT_DISP in 64-bit case.
if ((DstReg == Mips::T9 || DstReg == Mips::T9_64) && !UseSrcReg &&
Res.getConstant() == 0 && !IsLocalSym) {
const MCExpr *CallExpr =
MipsMCExpr::create(MipsMCExpr::MEK_GOT_CALL, SymExpr, getContext());
TOut.emitRRX(Mips::LW, DstReg, GPReg, MCOperand::createExpr(CallExpr),
IDLoc, STI);
TOut.emitRRX(IsPtr64 ? Mips::LD : Mips::LW, DstReg, GPReg,
MCOperand::createExpr(CallExpr), IDLoc, STI);
return false;
}
// The remaining cases are:
// External GOT: lw $tmp, %got(symbol)($gp)
// >addiu $tmp, $tmp, 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 = nullptr;
const MCExpr *LoExpr = nullptr;
if (IsLocalSym) {
GotExpr = MipsMCExpr::create(MipsMCExpr::MEK_GOT, SymExpr, getContext());
LoExpr = MipsMCExpr::create(MipsMCExpr::MEK_LO, SymExpr, getContext());
} else {
// 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.
GotExpr =
MipsMCExpr::create(MipsMCExpr::MEK_GOT, Res.getSymA(), getContext());
if (Res.getConstant() != 0)
if (IsPtr64) {
// 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.
GotExpr = MipsMCExpr::create(MipsMCExpr::MEK_GOT_DISP, Res.getSymA(),
getContext());
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());
}
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, GPReg, 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;
}
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, GPReg, 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;
// 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;
}
}
} else {
// The remaining cases are:
// External GOT: lw $tmp, %got(symbol)($gp)
// >addiu $tmp, $tmp, 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.
if (IsLocalSym) {
GotExpr =
MipsMCExpr::create(MipsMCExpr::MEK_GOT, SymExpr, getContext());
LoExpr = MipsMCExpr::create(MipsMCExpr::MEK_LO, SymExpr, getContext());
} else {
// 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.
GotExpr = MipsMCExpr::create(MipsMCExpr::MEK_GOT, Res.getSymA(),
getContext());
if (Res.getConstant() != 0)
LoExpr = MCConstantExpr::create(Res.getConstant(), getContext());
}
}
@ -3023,15 +2973,16 @@ bool MipsAsmParser::loadAndAddSymbolAddress(const MCExpr *SymExpr,
TmpReg = ATReg;
}
TOut.emitRRX(Mips::LD, TmpReg, GPReg, MCOperand::createExpr(GotExpr), IDLoc,
STI);
TOut.emitRRX(IsPtr64 ? Mips::LD : Mips::LW, TmpReg, GPReg,
MCOperand::createExpr(GotExpr), IDLoc, STI);
if (LoExpr)
TOut.emitRRX(Mips::DADDiu, TmpReg, TmpReg, MCOperand::createExpr(LoExpr),
IDLoc, STI);
TOut.emitRRX(IsPtr64 ? Mips::DADDiu : Mips::ADDiu, TmpReg, TmpReg,
MCOperand::createExpr(LoExpr), IDLoc, STI);
if (UseSrcReg)
TOut.emitRRR(Mips::DADDu, DstReg, TmpReg, SrcReg, IDLoc, STI);
TOut.emitRRR(IsPtr64 ? Mips::DADDu : Mips::ADDu, DstReg, TmpReg, SrcReg,
IDLoc, STI);
return false;
}