Index: lib/Target/Mips/AsmParser/MipsAsmParser.cpp =================================================================== --- lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -1416,6 +1416,104 @@ } } + // This expansion is not in a function called by expandInstruction() because + // it doesn't have its own opcode. + if ((Inst.getOpcode() == Mips::JAL || Inst.getOpcode() == Mips::JAL_MM) && + inPicMode()) { + warnIfNoMacro(IDLoc); + + const MCExpr *JalExpr = Inst.getOperand(0).getExpr(); + const MCSymbol *JalSym; + + // Get JalSym. + if (const MCBinaryExpr *BExpr = + dyn_cast(Inst.getOperand(0).getExpr())) { + + if (isa(BExpr->getLHS())) + JalSym = &(cast(BExpr->getLHS())->getSymbol()); + else if (isa(BExpr->getRHS())) + JalSym = &(cast(BExpr->getRHS())->getSymbol()); + else + JalSym = nullptr; + + } else if (const MCSymbolRefExpr *SRExpr = + dyn_cast(Inst.getOperand(0).getExpr())) { + JalSym = &(SRExpr->getSymbol()); + } else + JalSym = nullptr; + + // 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 MCExpr *Got16RelocExpr = evaluateRelocExpr(JalExpr, "got"); + 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)); + + // Create the R_(MICRO)MIPS_LO16 relocation. + const MCExpr *Lo16RelocExpr = evaluateRelocExpr(JalExpr, "lo"); + 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 + 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 MCExpr *GotDispRelocExpr = evaluateRelocExpr(JalExpr, "got_disp"); + 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 + 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 MCExpr *Call16RelocExpr = evaluateRelocExpr(JalExpr, "call16"); + 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. Index: test/MC/Mips/expansion-jal-sym-pic.s =================================================================== --- /dev/null +++ test/MC/Mips/expansion-jal-sym-pic.s @@ -0,0 +1,181 @@ +# 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 ($tmp 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, %got(.text)($gp) # encoding: [0x8f,0x99,A,A] +# O32-FIXME: # fixup A - offset: 0, value: .text@GOT, kind: fixup_Mips_GOT_Local +# O32-FIXME: addiu $25, $25, %lo(.text) # encoding: [0x27,0x39,A,A] +# O32-FIXME: # fixup A - offset: 0, value: .text@ABS_LO, kind: fixup_Mips_LO16 + +# N32-FIXME: lw $25, %got_disp(.text)($gp) # encoding: [0x8f,0x99,A,A] +# N32-FIXME: # fixup A - offset: 0, value: .text@GOT_DISP, kind: fixup_Mips_GOT_DISP + +# N64-FIXME: ld $25, %got_disp(.text)($gp) # encoding: [0xdf,0x99,A,A] +# N64-FIXME: # fixup A - offset: 0, value: .text@GOT_DISP, kind: fixup_Mips_GOT_DISP + +# O32-MICROMIPS-FIXME: lw $25, %got(.text)($gp) # encoding: [0xff,0x3c,A,A] +# O32-MICROMIPS-FIXME: # fixup A - offset: 0, value: .text@GOT, kind: fixup_MICROMIPS_GOT16 +# O32-MICROMIPS-FIXME: addiu $25, $25, %lo(.text) # encoding: [0x33,0x39,A,A] +# O32-MICROMIPS-FIXME: # fixup A - offset: 0, value: .text@ABS_LO, kind: fixup_MICROMIPS_LO16 + +# N32-MICROMIPS-FIXME: lw $25, %got_disp(.text)($gp) # encoding: [0xff,0x3c,A,A] +# N32-MICROMIPS-FIXME: # fixup A - offset: 0, value: .text@GOT_DISP, kind: fixup_MICROMIPS_GOT_DISP + +# N64-MICROMIPS-FIXME: ld $25, %got_disp(.text)($gp) # encoding: [0xdf,0x99,A,A] +# N64-MICROMIPS-FIXME: # fixup A - offset: 0, value: .text@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 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] Index: test/MC/Mips/set-nomacro.s =================================================================== --- test/MC/Mips/set-nomacro.s +++ test/MC/Mips/set-nomacro.s @@ -20,6 +20,11 @@ beq $2, 0, 1332 beq $2, 1, 1332 + jal foo + .option pic2 + jal foo + .option pic0 + add $4, $5, $6 .set noreorder @@ -56,5 +61,12 @@ beq $2, 1, 1332 # CHECK: [[@LINE-1]]:3: warning: macro instruction expanded into multiple instructions + jal foo +# CHECK-NOT: [[@LINE-1]]:3: warning: macro instruction expanded into multiple instructions + .option pic2 + jal foo +# CHECK: [[@LINE-1]]:3: warning: macro instruction expanded into multiple instructions + .option pic0 + add $4, $5, $6 # CHECK-NOT: [[@LINE-1]]:3: warning: macro instruction expanded into multiple instructions