Index: lib/Target/Mips/AsmParser/MipsAsmParser.cpp =================================================================== --- lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -1376,6 +1376,114 @@ } } + if ((Inst.getOpcode() == Mips::JAL || Inst.getOpcode() == Mips::JAL_MM) && + inPicMode()) { + const MCSymbol *JalSym; + int64_t JalOffset = 0; + + // Calculate JalOffset. If it doesn't exist, it has the value 0. + // FIXME: Use JalOffset later on. + if (const MCBinaryExpr *BExpr = + dyn_cast(Inst.getOperand(0).getExpr())) { + if (BExpr->getOpcode() == MCBinaryExpr::Add) { + // jal sym+offset + JalSym = &(cast(BExpr->getLHS())->getSymbol()); + JalOffset = cast(BExpr->getRHS())->getValue(); + } else if (BExpr->getOpcode() == MCBinaryExpr::Sub) { + // jal sym-offset + JalSym = &(cast(BExpr->getLHS())->getSymbol()); + JalOffset = cast(BExpr->getRHS())->getValue(); + } else { + return Error(IDLoc, "invalid operation for offset"); + } + } else if (const MCSymbolRefExpr *SRExpr = + dyn_cast(Inst.getOperand(0).getExpr())) { + // jal sym with no offset + JalSym = &(SRExpr->getSymbol()); + } else { + return Error(IDLoc, "invalid operand"); + } + + // 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 + MCInst LwInst; + LwInst.setOpcode(Mips::LW); + LwInst.addOperand(MCOperand::CreateReg(Mips::T9)); + LwInst.addOperand(MCOperand::CreateReg(Mips::GP)); + + // Create the R_(MICRO)MIPS_GOT16 relocation. + const MCSymbolRefExpr *Got16RelocSymExpr = MCSymbolRefExpr::Create( + JalSym, 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)); + + // Create the R_(MICRO)MIPS_LO16 relocation. + const MCSymbolRefExpr *Lo16RelocSymExpr = MCSymbolRefExpr::Create( + JalSym, 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/ld   $25, 0($gp) + // R_(MICRO)MIPS_GOT_DISP label + // jalr $25 + MCInst LoadInst; + LoadInst.setOpcode(isABI_N64() ? Mips::LD : Mips::LW); + LoadInst.addOperand(MCOperand::CreateReg(Mips::T9)); + LoadInst.addOperand(MCOperand::CreateReg(Mips::GP)); + + // Create the R_(MICRO)MIPS_GOT_DISP relocation. + const MCSymbolRefExpr *GotDispRelocSymExpr = MCSymbolRefExpr::Create( + JalSym, MCSymbolRefExpr::VK_Mips_GOT_DISP, getContext()); + LoadInst.addOperand(MCOperand::CreateExpr(GotDispRelocSymExpr)); + + 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 + MCInst LoadInst; + LoadInst.setOpcode(isABI_N64() ? Mips::LD : Mips::LW); + LoadInst.addOperand(MCOperand::CreateReg(Mips::T9)); + LoadInst.addOperand(MCOperand::CreateReg(Mips::GP)); + + // Create the R_(MICRO)MIPS_CALL16 relocation. + const MCSymbolRefExpr *Call16RelocSymExpr = MCSymbolRefExpr::Create( + JalSym, MCSymbolRefExpr::VK_Mips_GOT_CALL, getContext()); + LoadInst.addOperand(MCOperand::CreateExpr(Call16RelocSymExpr)); + + 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.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.s =================================================================== --- /dev/null +++ test/MC/Mips/expansion-jal-sym-pic.s @@ -0,0 +1,177 @@ +# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -show-encoding |\ +# RUN: FileCheck %s -check-prefix=ALL -check-prefix=NORMAL -check-prefix=O32 + +# RUN: llvm-mc %s -arch=mips -mcpu=mips64 -target-abi n32 -show-encoding |\ +# RUN: FileCheck %s -check-prefix=ALL -check-prefix=NORMAL -check-prefix=N32 + +# RUN: llvm-mc %s -arch=mips64 -mcpu=mips64 -target-abi n64 -show-encoding |\ +# RUN: FileCheck %s -check-prefix=ALL -check-prefix=NORMAL -check-prefix=N64 + +# RUN: llvm-mc %s -arch=mips -mcpu=mips32 -mattr=micromips -show-encoding |\ +# RUN: FileCheck %s -check-prefix=ALL -check-prefix=MICROMIPS -check-prefix=O32-MICROMIPS + +# RUN: llvm-mc %s -arch=mips -mcpu=mips64 -target-abi n32 -mattr=micromips -show-encoding |\ +# RUN: FileCheck %s -check-prefix=ALL -check-prefix=MICROMIPS -check-prefix=N32-MICROMIPS + +# RUN: llvm-mc %s -arch=mips64 -mcpu=mips64 -target-abi n64 -mattr=micromips -show-encoding |\ +# RUN: FileCheck %s -check-prefix=ALL -check-prefix=MICROMIPS -check-prefix=N64-MICROMIPS + + .weak weak_label + + .text + .option pic2 + + .ent local_label +local_label: + .frame $sp, 0, $ra + .set noreorder + + jal local_label + nop + + jal weak_label + nop + + jal global_label + nop + + jal .text + nop + + # local labels ($temp symbols) + jal 1f + nop + + .end local_label + +1: + nop + add $8, $8, $8 + nop + +# Expanding "jal local_label": +# O32: lw $25, %got(local_label)($gp) # encoding: [0x8f,0x99,A,A] +# O32: # fixup A - offset: 0, value: local_label@GOT, kind: fixup_Mips_GOT_Local +# O32: addiu $25, $25, %lo(local_label) # encoding: [0x27,0x39,A,A] +# O32: # fixup A - offset: 0, value: local_label@ABS_LO, kind: fixup_Mips_LO16 + +# N32: lw $25, %got_disp(local_label)($gp) # encoding: [0x8f,0x99,A,A] +# N32: # fixup A - offset: 0, value: local_label@GOT_DISP, kind: fixup_Mips_GOT_DISP + +# N64: ld $25, %got_disp(local_label)($gp) # encoding: [0xdf,0x99,A,A] +# N64: # fixup A - offset: 0, value: local_label@GOT_DISP, kind: fixup_Mips_GOT_DISP + +# O32-MICROMIPS: lw $25, %got(local_label)($gp) # encoding: [0xff,0x3c,A,A] +# O32-MICROMIPS: # fixup A - offset: 0, value: local_label@GOT, kind: fixup_MICROMIPS_GOT16 +# O32-MICROMIPS: addiu $25, $25, %lo(local_label) # encoding: [0x33,0x39,A,A] +# O32-MICROMIPS: # fixup A - offset: 0, value: local_label@ABS_LO, kind: fixup_MICROMIPS_LO16 + +# N32-MICROMIPS: lw $25, %got_disp(local_label)($gp) # encoding: [0xff,0x3c,A,A] +# N32-MICROMIPS: # fixup A - offset: 0, value: local_label@GOT_DISP, kind: fixup_MICROMIPS_GOT_DISP + +# N64-MICROMIPS: ld $25, %got_disp(local_label)($gp) # encoding: [0xdf,0x99,A,A] +# N64-MICROMIPS: # fixup A - offset: 0, value: local_label@GOT_DISP, kind: fixup_MICROMIPS_GOT_DISP + +# NORMAL: jalr $25 # encoding: [0x03,0x20,0xf8,0x09] +# MICROMIPS: jalr $ra, $25 # encoding: [0x03,0xf9,0x0f,0x3c] +# ALL: nop # encoding: [0x00,0x00,0x00,0x00] + + +# Expanding "jal weak_label": +# O32: lw $25, %call16(weak_label)($gp) # encoding: [0x8f,0x99,A,A] +# O32: # fixup A - offset: 0, value: weak_label@GOT_CALL, kind: fixup_Mips_CALL16 + +# N32: lw $25, %call16(weak_label)($gp) # encoding: [0x8f,0x99,A,A] +# N32: # fixup A - offset: 0, value: weak_label@GOT_CALL, kind: fixup_Mips_CALL16 + +# N64: ld $25, %call16(weak_label)($gp) # encoding: [0xdf,0x99,A,A] +# N64: # fixup A - offset: 0, value: weak_label@GOT_CALL, kind: fixup_Mips_CALL16 + +# O32-MICROMIPS: lw $25, %call16(weak_label)($gp) # encoding: [0xff,0x3c,A,A] +# O32-MICROMIPS: # fixup A - offset: 0, value: weak_label@GOT_CALL, kind: fixup_MICROMIPS_CALL16 + +# N32-MICROMIPS: lw $25, %call16(weak_label)($gp) # encoding: [0xff,0x3c,A,A] +# N32-MICROMIPS: # fixup A - offset: 0, value: weak_label@GOT_CALL, kind: fixup_MICROMIPS_CALL16 + +# N64-MICROMIPS: ld $25, %call16(weak_label)($gp) # encoding: [0xdf,0x99,A,A] +# N64-MICROMIPS: # fixup A - offset: 0, value: weak_label@GOT_CALL, kind: fixup_MICROMIPS_CALL16 + +# NORMAL: jalr $25 # encoding: [0x03,0x20,0xf8,0x09] +# MICROMIPS: jalr $ra, $25 # encoding: [0x03,0xf9,0x0f,0x3c] +# ALL: nop # encoding: [0x00,0x00,0x00,0x00] + + +# Expanding "jal global_label": +# O32: lw $25, %call16(global_label)($gp) # encoding: [0x8f,0x99,A,A] +# O32: # fixup A - offset: 0, value: global_label@GOT_CALL, kind: fixup_Mips_CALL16 + +# N32: lw $25, %call16(global_label)($gp) # encoding: [0x8f,0x99,A,A] +# N32: # fixup A - offset: 0, value: global_label@GOT_CALL, kind: fixup_Mips_CALL16 + +# N64: ld $25, %call16(global_label)($gp) # encoding: [0xdf,0x99,A,A] +# N64: # fixup A - offset: 0, value: global_label@GOT_CALL, kind: fixup_Mips_CALL16 + +# O32-MICROMIPS: lw $25, %call16(global_label)($gp) # encoding: [0xff,0x3c,A,A] +# O32-MICROMIPS: # fixup A - offset: 0, value: global_label@GOT_CALL, kind: fixup_MICROMIPS_CALL16 + +# N32-MICROMIPS: lw $25, %call16(global_label)($gp) # encoding: [0xff,0x3c,A,A] +# N32-MICROMIPS: # fixup A - offset: 0, value: global_label@GOT_CALL, kind: fixup_MICROMIPS_CALL16 + +# N64-MICROMIPS: ld $25, %call16(global_label)($gp) # encoding: [0xdf,0x99,A,A] +# N64-MICROMIPS: # fixup A - offset: 0, value: global_label@GOT_CALL, kind: fixup_MICROMIPS_CALL16 + +# NORMAL: jalr $25 # encoding: [0x03,0x20,0xf8,0x09] +# MICROMIPS: jalr $ra, $25 # encoding: [0x03,0xf9,0x0f,0x3c] +# ALL: nop # encoding: [0x00,0x00,0x00,0x00] + + +# Expanding "jal .text": +# O32-FIXME: lw $25, %call16(.text)($gp) # encoding: [0x8f,0x99,A,A] +# O32-FIXME: # fixup A - offset: 0, value: .text@GOT_CALL, kind: fixup_Mips_CALL16 + +# N32-FIXME: lw $25, %call16(.text)($gp) # encoding: [0x8f,0x99,A,A] +# N32-FIXME: # fixup A - offset: 0, value: .text@GOT_CALL, kind: fixup_Mips_CALL16 + +# N64-FIXME: ld $25, %call16(.text)($gp) # encoding: [0xdf,0x99,A,A] +# N64-FIXME: # fixup A - offset: 0, value: .text@GOT_CALL, kind: fixup_Mips_CALL16 + +# O32-MICROMIPS-FIXME: lw $25, %call16(.text)($gp) # encoding: [0xff,0x3c,A,A] +# O32-MICROMIPS-FIXME: # fixup A - offset: 0, value: .text@GOT_CALL, kind: fixup_MICROMIPS_CALL16 + +# N32-MICROMIPS-FIXME: lw $25, %call16(.text)($gp) # encoding: [0xff,0x3c,A,A] +# N32-MICROMIPS-FIXME: # fixup A - offset: 0, value: .text@GOT_CALL, kind: fixup_MICROMIPS_CALL16 + +# N64-MICROMIPS-FIXME: ld $25, %call16(.text)($gp) # encoding: [0xdf,0x99,A,A] +# N64-MICROMIPS-FIXME: # fixup A - offset: 0, value: .text@GOT_CALL, kind: fixup_MICROMIPS_CALL16 + +# NORMAL: jalr $25 # encoding: [0x03,0x20,0xf8,0x09] +# MICROMIPS: jalr $ra, $25 # encoding: [0x03,0xf9,0x0f,0x3c] +# ALL: nop # encoding: [0x00,0x00,0x00,0x00] + + +# Expanding "jal 1f": +# O32: lw $25, %got($tmp0)($gp) # encoding: [0x8f,0x99,A,A] +# O32: # fixup A - offset: 0, value: ($tmp0)@GOT, kind: fixup_Mips_GOT_Local +# O32: addiu $25, $25, %lo($tmp0) # encoding: [0x27,0x39,A,A] +# O32: # fixup A - offset: 0, value: ($tmp0)@ABS_LO, kind: fixup_Mips_LO16 + +# N32: lw $25, %got_disp($tmp0)($gp) # encoding: [0x8f,0x99,A,A] +# N32: # fixup A - offset: 0, value: ($tmp0)@GOT_DISP, kind: fixup_Mips_GOT_DISP + +# N64: ld $25, %got_disp($tmp0)($gp) # encoding: [0xdf,0x99,A,A] +# N64: # fixup A - offset: 0, value: ($tmp0)@GOT_DISP, kind: fixup_Mips_GOT_DISP + +# O32-MICROMIPS: lw $25, %got($tmp0)($gp) # encoding: [0xff,0x3c,A,A] +# O32-MICROMIPS: # fixup A - offset: 0, value: ($tmp0)@GOT, kind: fixup_MICROMIPS_GOT16 +# O32-MICROMIPS: addiu $25, $25, %lo($tmp0) # encoding: [0x33,0x39,A,A] +# O32-MICROMIPS: # fixup A - offset: 0, value: ($tmp0)@ABS_LO, kind: fixup_MICROMIPS_LO16 + +# N32-MICROMIPS: lw $25, %got_disp($tmp0)($gp) # encoding: [0xff,0x3c,A,A] +# N32-MICROMIPS: # fixup A - offset: 0, value: ($tmp0)@GOT_DISP, kind: fixup_MICROMIPS_GOT_DISP + +# N64-MICROMIPS: ld $25, %got_disp($tmp0)($gp) # encoding: [0xdf,0x99,A,A] +# N64-MICROMIPS: # fixup A - offset: 0, value: ($tmp0)@GOT_DISP, kind: fixup_MICROMIPS_GOT_DISP + +# NORMAL: jalr $25 # encoding: [0x03,0x20,0xf8,0x09] +# MICROMIPS: jalr $ra, $25 # encoding: [0x03,0xf9,0x0f,0x3c] +# ALL: nop # encoding: [0x00,0x00,0x00,0x00]