Index: lib/Target/Mips/AsmParser/MipsAsmParser.cpp =================================================================== --- lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -1101,6 +1101,105 @@ "nop instruction"); } + if ((Inst.getOpcode() == Mips::JAL || Inst.getOpcode() == Mips::JAL_MM) && + inPicMode()) { + MCOperand JalOpnd = Inst.getOperand(0); + const MCSymbolRefExpr *JalSymExpr = + cast(JalOpnd.getExpr()); + const MCSymbol &JalSym = JalSymExpr->getSymbol(); + + if (JalSym.isInSection()) { + if (isABI_O32()) { + // If it's a local symbol and the O32 ABI is being used, we expand to: + // lw   $25, 0($gp) + // R_MIPS_GOT16 .text / R_MICROMIPS_GOT16 label + // addiu $25, $25, 0 + // R_MIPS_LO16 .text / R_MICROMIPS_LO16 label + // jalr $25 + MCInst LwInst; + LwInst.setOpcode(Mips::LW); + LwInst.addOperand(MCOperand::CreateReg(Mips::T9)); + LwInst.addOperand(MCOperand::CreateReg(Mips::GP)); + if (inMicroMipsMode()) { + const MCSymbolRefExpr *Got16RelocSymExpr = MCSymbolRefExpr::Create( + JalSym.getName(), MCSymbolRefExpr::VK_Mips_GOT, getContext()); + LwInst.addOperand(MCOperand::CreateExpr(Got16RelocSymExpr)); + } else { + const MCSymbolRefExpr *Got16RelocSymExpr = MCSymbolRefExpr::Create( + ".text", MCSymbolRefExpr::VK_Mips_GOT, getContext()); + LwInst.addOperand(MCOperand::CreateExpr(Got16RelocSymExpr)); + } + Instructions.push_back(LwInst); + + MCInst AddiuInst; + AddiuInst.setOpcode(Mips::ADDiu); + AddiuInst.addOperand(MCOperand::CreateReg(Mips::T9)); + AddiuInst.addOperand(MCOperand::CreateReg(Mips::T9)); + if (inMicroMipsMode()) { + const MCSymbolRefExpr *Lo16RelocSymExpr = MCSymbolRefExpr::Create( + JalSym.getName(), MCSymbolRefExpr::VK_Mips_ABS_LO, getContext()); + AddiuInst.addOperand(MCOperand::CreateExpr(Lo16RelocSymExpr)); + } else { + const MCSymbolRefExpr *Lo16RelocSymExpr = MCSymbolRefExpr::Create( + ".text", MCSymbolRefExpr::VK_Mips_ABS_LO, getContext()); + AddiuInst.addOperand(MCOperand::CreateExpr(Lo16RelocSymExpr)); + } + 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   $25, 0($gp) + // R_MIPS_GOT_DISP .text / R_MICROMIPS_GOT_DISP label + // jalr $25 + MCInst LwInst; + LwInst.setOpcode(Mips::LW); + LwInst.addOperand(MCOperand::CreateReg(Mips::T9)); + LwInst.addOperand(MCOperand::CreateReg(Mips::GP)); + if (inMicroMipsMode()) { + const MCSymbolRefExpr *GotDispRelocSymExpr = MCSymbolRefExpr::Create( + JalSym.getName(), MCSymbolRefExpr::VK_Mips_GOT_DISP, + getContext()); + LwInst.addOperand(MCOperand::CreateExpr(GotDispRelocSymExpr)); + } else { + const MCSymbolRefExpr *GotDispRelocSymExpr = MCSymbolRefExpr::Create( + ".text", MCSymbolRefExpr::VK_Mips_GOT_DISP, getContext()); + LwInst.addOperand(MCOperand::CreateExpr(GotDispRelocSymExpr)); + } + Instructions.push_back(LwInst); + } + } else { + // If it's an external/weak symbol, we expand to: + // lw $25, 0($gp) + // R_MIPS_CALL16 label / R_MICROMIPS_CALL16 label + // jalr $25 + MCInst LwInst; + LwInst.setOpcode(Mips::LW); + LwInst.addOperand(MCOperand::CreateReg(Mips::T9)); + LwInst.addOperand(MCOperand::CreateReg(Mips::GP)); + const MCSymbolRefExpr *Call16RelocSymExpr = MCSymbolRefExpr::Create( + JalSym.getName(), MCSymbolRefExpr::VK_Mips_GOT_CALL, getContext()); + LwInst.addOperand(MCOperand::CreateExpr(Call16RelocSymExpr)); + Instructions.push_back(LwInst); + } + + MCInst JalrInst; + if (inMicroMipsMode()) + JalrInst.setOpcode(Mips::JALR_MM); + else + JalrInst.setOpcode(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. Note that in GAS, the symbol used + // for the relocation is ".text" only if we're jumping to a local symbol + // and we're using the N32/N64 ABIs, otherwise it's the actual symbol that + // we're jumping to. + + Inst = JalrInst; + } + if (MCID.hasDelaySlot() && AssemblerOptions.back()->isReorder()) { // If this instruction has a delay slot and .set reorder is active, // emit a NOP after it. Index: test/MC/Mips/expansion-jal-sym-pic-noreorder.s =================================================================== --- /dev/null +++ test/MC/Mips/expansion-jal-sym-pic-noreorder.s @@ -0,0 +1,96 @@ +# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -relocation-model=pic -filetype=obj -o -|\ +# RUN: llvm-objdump -d -r -arch=mips - | \ +# RUN: FileCheck %s -check-prefix=O32 + +# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -mattr=micromips -relocation-model=pic -filetype=obj -o -|\ +# RUN: llvm-objdump -d -r -arch=mips -mattr=micromips - | \ +# RUN: FileCheck %s -check-prefix=O32-MICROMIPS + +# RUN: llvm-mc %s -arch=mips -mcpu=mips64 -mattr=-n64,+n32 -relocation-model=pic -filetype=obj -o -|\ +# RUN: llvm-objdump -d -r -arch=mips - | \ +# RUN: FileCheck %s -check-prefix=N32-N64 + +# RUN: llvm-mc %s -arch=mips -mcpu=mips64 -relocation-model=pic -filetype=obj -o -|\ +# RUN: llvm-objdump -d -r -arch=mips - | \ +# RUN: FileCheck %s -check-prefix=N32-N64 + +# RUN: llvm-mc %s -arch=mips -mcpu=mips64 -mattr=-n64,+n32 -mattr=micromips -relocation-model=pic -filetype=obj -o -|\ +# RUN: llvm-objdump -d -r -arch=mips -mattr=micromips - | \ +# RUN: FileCheck %s -check-prefix=N32-N64-MICROMIPS + +# RUN: llvm-mc %s -arch=mips -mcpu=mips64 -mattr=micromips -relocation-model=pic -filetype=obj -o -|\ +# RUN: llvm-objdump -d -r -arch=mips -mattr=micromips - | \ +# RUN: FileCheck %s -check-prefix=N32-N64-MICROMIPS + + .text + .weak weak_label + + .ent local_label +local_label: + .frame $sp, 0, $ra + .set noreorder + + jal local_label + nop + jal weak_label + nop + jal external_label + nop + + .end local_label + +# O32: 8f 99 00 00 lw $25, 0($gp) +# O32: R_MIPS_GOT16 .text +# O32: 27 39 00 00 addiu $25, $25, 0 +# O32: R_MIPS_LO16 .text +# O32: 03 20 f8 09 jalr $25 +# O32: 00 00 00 00 nop +# O32: 8f 99 00 00 lw $25, 0($gp) +# O32: R_MIPS_CALL16 weak_label +# O32: 03 20 f8 09 jalr $25 +# O32: 00 00 00 00 nop +# O32: 8f 99 00 00 lw $25, 0($gp) +# O32: R_MIPS_CALL16 external_label +# O32: 03 20 f8 09 jalr $25 +# O32: 00 00 00 00 nop + +# O32-MICROMIPS: ff 3c 00 00 lw $25, 0($gp) +# O32-MICROMIPS: R_MICROMIPS_GOT16 local_label +# O32-MICROMIPS: 33 39 00 00 addiu $25, $25, 0 +# O32-MICROMIPS: R_MICROMIPS_LO16 local_label +# O32-MICROMIPS: 03 f9 0f 3c jalr $ra, $25 +# O32-MICROMIPS: 00 00 00 00 sll $zero, $zero, 0 +# O32-MICROMIPS: ff 3c 00 00 lw $25, 0($gp) +# O32-MICROMIPS: R_MICROMIPS_CALL16 weak_label +# O32-MICROMIPS: 03 f9 0f 3c jalr $ra, $25 +# O32-MICROMIPS: 00 00 00 00 sll $zero, $zero, 0 +# O32-MICROMIPS: ff 3c 00 00 lw $25, 0($gp) +# O32-MICROMIPS: R_MICROMIPS_CALL16 external_label +# O32-MICROMIPS: 03 f9 0f 3c jalr $ra, $25 +# O32-MICROMIPS: 00 00 00 00 sll $zero, $zero, 0 + +# N32-N64: 8f 99 00 00 lw $25, 0($gp) +# N32-N64: R_MIPS_GOT_DISP .text +# N32-N64: 03 20 f8 09 jalr $25 +# N32-N64: 00 00 00 00 nop +# N32-N64: 8f 99 00 00 lw $25, 0($gp) +# N32-N64: R_MIPS_CALL16 weak_label +# N32-N64: 03 20 f8 09 jalr $25 +# N32-N64: 00 00 00 00 nop +# N32-N64: 8f 99 00 00 lw $25, 0($gp) +# N32-N64: R_MIPS_CALL16 external_label +# N32-N64: 03 20 f8 09 jalr $25 +# N32-N64: 00 00 00 00 nop + +# N32-N64-MICROMIPS: ff 3c 00 00 lw $25, 0($gp) +# N32-N64-MICROMIPS: R_MICROMIPS_GOT_DISP local_label +# N32-N64-MICROMIPS: 03 f9 0f 3c jalr $ra, $25 +# N32-N64-MICROMIPS: 00 00 00 00 sll $zero, $zero, 0 +# N32-N64-MICROMIPS: ff 3c 00 00 lw $25, 0($gp) +# N32-N64-MICROMIPS: R_MICROMIPS_CALL16 weak_label +# N32-N64-MICROMIPS: 03 f9 0f 3c jalr $ra, $25 +# N32-N64-MICROMIPS: 00 00 00 00 sll $zero, $zero, 0 +# N32-N64-MICROMIPS: ff 3c 00 00 lw $25, 0($gp) +# N32-N64-MICROMIPS: R_MICROMIPS_CALL16 external_label +# N32-N64-MICROMIPS: 03 f9 0f 3c jalr $ra, $25 +# N32-N64-MICROMIPS: 00 00 00 00 sll $zero, $zero, 0 Index: test/MC/Mips/expansion-jal-sym-pic-reorder.s =================================================================== --- /dev/null +++ test/MC/Mips/expansion-jal-sym-pic-reorder.s @@ -0,0 +1,93 @@ +# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -relocation-model=pic -filetype=obj -o -|\ +# RUN: llvm-objdump -d -r -arch=mips - | \ +# RUN: FileCheck %s -check-prefix=O32 + +# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -mattr=micromips -relocation-model=pic -filetype=obj -o -|\ +# RUN: llvm-objdump -d -r -arch=mips -mattr=micromips - | \ +# RUN: FileCheck %s -check-prefix=O32-MICROMIPS + +# RUN: llvm-mc %s -arch=mips -mcpu=mips64 -mattr=-n64,+n32 -relocation-model=pic -filetype=obj -o -|\ +# RUN: llvm-objdump -d -r -arch=mips - | \ +# RUN: FileCheck %s -check-prefix=N32-N64 + +# RUN: llvm-mc %s -arch=mips -mcpu=mips64 -relocation-model=pic -filetype=obj -o -|\ +# RUN: llvm-objdump -d -r -arch=mips - | \ +# RUN: FileCheck %s -check-prefix=N32-N64 + +# RUN: llvm-mc %s -arch=mips -mcpu=mips64 -mattr=-n64,+n32 -mattr=micromips -relocation-model=pic -filetype=obj -o -|\ +# RUN: llvm-objdump -d -r -arch=mips -mattr=micromips - | \ +# RUN: FileCheck %s -check-prefix=N32-N64-MICROMIPS + +# RUN: llvm-mc %s -arch=mips -mcpu=mips64 -mattr=micromips -relocation-model=pic -filetype=obj -o -|\ +# RUN: llvm-objdump -d -r -arch=mips -mattr=micromips - | \ +# RUN: FileCheck %s -check-prefix=N32-N64-MICROMIPS + + .text + .weak weak_label + + .ent local_label +local_label: + .frame $sp, 0, $ra + .set reorder + + jal local_label + jal weak_label + jal external_label + + .end local_label + +# O32: 8f 99 00 00 lw $25, 0($gp) +# O32: R_MIPS_GOT16 .text +# O32: 27 39 00 00 addiu $25, $25, 0 +# O32: R_MIPS_LO16 .text +# O32: 03 20 f8 09 jalr $25 +# O32: 00 00 00 00 nop +# O32: 8f 99 00 00 lw $25, 0($gp) +# O32: R_MIPS_CALL16 weak_label +# O32: 03 20 f8 09 jalr $25 +# O32: 00 00 00 00 nop +# O32: 8f 99 00 00 lw $25, 0($gp) +# O32: R_MIPS_CALL16 external_label +# O32: 03 20 f8 09 jalr $25 +# O32: 00 00 00 00 nop + +# O32-MICROMIPS: ff 3c 00 00 lw $25, 0($gp) +# O32-MICROMIPS: R_MICROMIPS_GOT16 local_label +# O32-MICROMIPS: 33 39 00 00 addiu $25, $25, 0 +# O32-MICROMIPS: R_MICROMIPS_LO16 local_label +# O32-MICROMIPS: 03 f9 0f 3c jalr $ra, $25 +# O32-MICROMIPS: 00 00 00 00 sll $zero, $zero, 0 +# O32-MICROMIPS: ff 3c 00 00 lw $25, 0($gp) +# O32-MICROMIPS: R_MICROMIPS_CALL16 weak_label +# O32-MICROMIPS: 03 f9 0f 3c jalr $ra, $25 +# O32-MICROMIPS: 00 00 00 00 sll $zero, $zero, 0 +# O32-MICROMIPS: ff 3c 00 00 lw $25, 0($gp) +# O32-MICROMIPS: R_MICROMIPS_CALL16 external_label +# O32-MICROMIPS: 03 f9 0f 3c jalr $ra, $25 +# O32-MICROMIPS: 00 00 00 00 sll $zero, $zero, 0 + +# N32-N64: 8f 99 00 00 lw $25, 0($gp) +# N32-N64: R_MIPS_GOT_DISP .text +# N32-N64: 03 20 f8 09 jalr $25 +# N32-N64: 00 00 00 00 nop +# N32-N64: 8f 99 00 00 lw $25, 0($gp) +# N32-N64: R_MIPS_CALL16 weak_label +# N32-N64: 03 20 f8 09 jalr $25 +# N32-N64: 00 00 00 00 nop +# N32-N64: 8f 99 00 00 lw $25, 0($gp) +# N32-N64: R_MIPS_CALL16 external_label +# N32-N64: 03 20 f8 09 jalr $25 +# N32-N64: 00 00 00 00 nop + +# N32-N64-MICROMIPS: ff 3c 00 00 lw $25, 0($gp) +# N32-N64-MICROMIPS: R_MICROMIPS_GOT_DISP local_label +# N32-N64-MICROMIPS: 03 f9 0f 3c jalr $ra, $25 +# N32-N64-MICROMIPS: 00 00 00 00 sll $zero, $zero, 0 +# N32-N64-MICROMIPS: ff 3c 00 00 lw $25, 0($gp) +# N32-N64-MICROMIPS: R_MICROMIPS_CALL16 weak_label +# N32-N64-MICROMIPS: 03 f9 0f 3c jalr $ra, $25 +# N32-N64-MICROMIPS: 00 00 00 00 sll $zero, $zero, 0 +# N32-N64-MICROMIPS: ff 3c 00 00 lw $25, 0($gp) +# N32-N64-MICROMIPS: R_MICROMIPS_CALL16 external_label +# N32-N64-MICROMIPS: 03 f9 0f 3c jalr $ra, $25 +# N32-N64-MICROMIPS: 00 00 00 00 sll $zero, $zero, 0