diff options
Diffstat (limited to 'llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp')
| -rw-r--r-- | llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp index 54649fa7080..45115ee0e1b 100644 --- a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -1318,6 +1318,44 @@ static bool hasShortDelaySlot(unsigned Opcode) { } } +static const MCSymbol *getSingleMCSymbol(const MCExpr *Expr) { + if (const MCSymbolRefExpr *SRExpr = dyn_cast<MCSymbolRefExpr>(Expr)) { + return &SRExpr->getSymbol(); + } + + if (const MCBinaryExpr *BExpr = dyn_cast<MCBinaryExpr>(Expr)) { + const MCSymbol *LHSSym = getSingleMCSymbol(BExpr->getLHS()); + const MCSymbol *RHSSym = getSingleMCSymbol(BExpr->getRHS()); + + if (LHSSym) + return LHSSym; + + if (RHSSym) + return RHSSym; + + return nullptr; + } + + if (const MCUnaryExpr *UExpr = dyn_cast<MCUnaryExpr>(Expr)) + return getSingleMCSymbol(UExpr->getSubExpr()); + + return nullptr; +} + +static unsigned countMCSymbolRefExpr(const MCExpr *Expr) { + if (isa<MCSymbolRefExpr>(Expr)) + return 1; + + if (const MCBinaryExpr *BExpr = dyn_cast<MCBinaryExpr>(Expr)) + return countMCSymbolRefExpr(BExpr->getLHS()) + + countMCSymbolRefExpr(BExpr->getRHS()); + + if (const MCUnaryExpr *UExpr = dyn_cast<MCUnaryExpr>(Expr)) + return countMCSymbolRefExpr(UExpr->getSubExpr()); + + return 0; +} + bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions) { const MCInstrDesc &MCID = getInstDesc(Inst.getOpcode()); @@ -1468,6 +1506,94 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, } } + // This expansion is not in a function called by expandInstruction() because + // the pseudo-instruction doesn't have a distinct opcode. + if ((Inst.getOpcode() == Mips::JAL || Inst.getOpcode() == Mips::JAL_MM) && + inPicMode()) { + warnIfNoMacro(IDLoc); + + const MCExpr *JalExpr = Inst.getOperand(0).getExpr(); + + // We can do this expansion if there's only 1 symbol in the argument + // expression. + if (countMCSymbolRefExpr(JalExpr) > 1) + return Error(IDLoc, "jal doesn't support multiple symbols in PIC mode"); + + // FIXME: This is checking the expression can be handled by the later stages + // of the assembler. We ought to leave it to those later stages but + // we can't do that until we stop evaluateRelocExpr() rewriting the + // expressions into non-equivalent forms. + const MCSymbol *JalSym = getSingleMCSymbol(JalExpr); + + // FIXME: Add support for label+offset operands (currently causes an error). + // FIXME: Add support for forward-declared local symbols. + // FIXME: Add expansion for when the LargeGOT option is enabled. + if (JalSym->isInSection() || JalSym->isTemporary()) { + if (isABI_O32()) { + // If it's a local symbol and the O32 ABI is being used, we expand to: + // lw $25, 0($gp) + // R_(MICRO)MIPS_GOT16 label + // addiu $25, $25, 0 + // R_(MICRO)MIPS_LO16 label + // jalr $25 + const MCExpr *Got16RelocExpr = evaluateRelocExpr(JalExpr, "got"); + const MCExpr *Lo16RelocExpr = evaluateRelocExpr(JalExpr, "lo"); + + MCInst LwInst; + LwInst.setOpcode(Mips::LW); + LwInst.addOperand(MCOperand::createReg(Mips::T9)); + LwInst.addOperand(MCOperand::createReg(Mips::GP)); + LwInst.addOperand(MCOperand::createExpr(Got16RelocExpr)); + Instructions.push_back(LwInst); + + MCInst AddiuInst; + AddiuInst.setOpcode(Mips::ADDiu); + AddiuInst.addOperand(MCOperand::createReg(Mips::T9)); + AddiuInst.addOperand(MCOperand::createReg(Mips::T9)); + AddiuInst.addOperand(MCOperand::createExpr(Lo16RelocExpr)); + Instructions.push_back(AddiuInst); + } else if (isABI_N32() || isABI_N64()) { + // If it's a local symbol and the N32/N64 ABIs are being used, + // we expand to: + // lw/ld $25, 0($gp) + // R_(MICRO)MIPS_GOT_DISP label + // jalr $25 + const MCExpr *GotDispRelocExpr = evaluateRelocExpr(JalExpr, "got_disp"); + + MCInst LoadInst; + LoadInst.setOpcode(ABI.ArePtrs64bit() ? Mips::LD : Mips::LW); + LoadInst.addOperand(MCOperand::createReg(Mips::T9)); + LoadInst.addOperand(MCOperand::createReg(Mips::GP)); + LoadInst.addOperand(MCOperand::createExpr(GotDispRelocExpr)); + Instructions.push_back(LoadInst); + } + } else { + // If it's an external/weak symbol, we expand to: + // lw/ld $25, 0($gp) + // R_(MICRO)MIPS_CALL16 label + // jalr $25 + const MCExpr *Call16RelocExpr = evaluateRelocExpr(JalExpr, "call16"); + + MCInst LoadInst; + LoadInst.setOpcode(ABI.ArePtrs64bit() ? Mips::LD : Mips::LW); + LoadInst.addOperand(MCOperand::createReg(Mips::T9)); + LoadInst.addOperand(MCOperand::createReg(Mips::GP)); + LoadInst.addOperand(MCOperand::createExpr(Call16RelocExpr)); + Instructions.push_back(LoadInst); + } + + MCInst JalrInst; + JalrInst.setOpcode(inMicroMipsMode() ? Mips::JALR_MM : Mips::JALR); + JalrInst.addOperand(MCOperand::createReg(Mips::RA)); + JalrInst.addOperand(MCOperand::createReg(Mips::T9)); + + // FIXME: Add an R_(MICRO)MIPS_JALR relocation after the JALR. + // This relocation is supposed to be an optimization hint for the linker + // and is not necessary for correctness. + + Inst = JalrInst; + } + if (MCID.mayLoad() || MCID.mayStore()) { // Check the offset of memory operand, if it is a symbol // reference or immediate we may have to expand instructions. |

