[llvm] r245305 - [mips] Expand JAL instructions when PIC is enabled.

Daniel Sanders via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 18 09:18:09 PDT 2015


Author: dsanders
Date: Tue Aug 18 11:18:09 2015
New Revision: 245305

URL: http://llvm.org/viewvc/llvm-project?rev=245305&view=rev
Log:
[mips] Expand JAL instructions when PIC is enabled.

Summary: This is the correct way to handle JAL instructions when PIC is enabled.

Patch by Toma Tabacu

Reviewers: seanbruno, tomatabacu

Subscribers: brooks, seanbruno, emaste, llvm-commits

Differential Revision: http://reviews.llvm.org/D6231

Added:
    llvm/trunk/test/MC/Mips/expansion-jal-sym-pic.s
Modified:
    llvm/trunk/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
    llvm/trunk/test/ExecutionEngine/RuntimeDyld/Mips/ELF_Mips64r2N64_PIC_relocations.s
    llvm/trunk/test/MC/Mips/set-nomacro.s

Modified: llvm/trunk/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Mips/AsmParser/MipsAsmParser.cpp?rev=245305&r1=245304&r2=245305&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Mips/AsmParser/MipsAsmParser.cpp (original)
+++ llvm/trunk/lib/Target/Mips/AsmParser/MipsAsmParser.cpp Tue Aug 18 11:18:09 2015
@@ -1318,6 +1318,44 @@ static bool hasShortDelaySlot(unsigned O
   }
 }
 
+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(M
     }
   }
 
+  // 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.

Modified: llvm/trunk/test/ExecutionEngine/RuntimeDyld/Mips/ELF_Mips64r2N64_PIC_relocations.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ExecutionEngine/RuntimeDyld/Mips/ELF_Mips64r2N64_PIC_relocations.s?rev=245305&r1=245304&r2=245305&view=diff
==============================================================================
--- llvm/trunk/test/ExecutionEngine/RuntimeDyld/Mips/ELF_Mips64r2N64_PIC_relocations.s (original)
+++ llvm/trunk/test/ExecutionEngine/RuntimeDyld/Mips/ELF_Mips64r2N64_PIC_relocations.s Tue Aug 18 11:18:09 2015
@@ -41,7 +41,9 @@ bar:
 # Test R_MIPS_26 relocation.
 # rtdyld-check:  decode_operand(insn1, 0)[25:0] = foo
 insn1:
+	.option pic0
 	jal   foo
+	.option pic2
 	nop
 
 # Test R_MIPS_PC16 relocation.

Added: llvm/trunk/test/MC/Mips/expansion-jal-sym-pic.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/Mips/expansion-jal-sym-pic.s?rev=245305&view=auto
==============================================================================
--- llvm/trunk/test/MC/Mips/expansion-jal-sym-pic.s (added)
+++ llvm/trunk/test/MC/Mips/expansion-jal-sym-pic.s Tue Aug 18 11:18:09 2015
@@ -0,0 +1,183 @@
+# 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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]
+
+
+# FIXME: The .text section MCSymbol isn't created when printing assembly. However,
+# it is created when generating an ELF object file.
+# Expanding "jal .text":
+# O32-FIXME: lw    $25, %got(.text)($gp)           # encoding: [0x8f,0x99,A,A]
+# O32-FIXME:                                       #   fixup A - offset: 0, value: .text at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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]

Modified: llvm/trunk/test/MC/Mips/set-nomacro.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/Mips/set-nomacro.s?rev=245305&r1=245304&r2=245305&view=diff
==============================================================================
--- llvm/trunk/test/MC/Mips/set-nomacro.s (original)
+++ llvm/trunk/test/MC/Mips/set-nomacro.s Tue Aug 18 11:18:09 2015
@@ -67,6 +67,11 @@
   ulw $8, 2($9)
   ulw $8, 0x8000($9)
 
+  jal foo
+  .option pic2
+  jal foo
+  .option pic0
+
   add $4, $5, $6
 
   .set noreorder
@@ -187,5 +192,12 @@
   ulw $8, 0x8000($9)
 # 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




More information about the llvm-commits mailing list