[mips][microMIPS] Add R_MICROMIPS_PC26_S1 relocation

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

llvm-svn: 266985
diff --git a/llvm/include/llvm/Support/ELFRelocs/Mips.def b/llvm/include/llvm/Support/ELFRelocs/Mips.def
index 77e7f8e..7246489 100644
--- a/llvm/include/llvm/Support/ELFRelocs/Mips.def
+++ b/llvm/include/llvm/Support/ELFRelocs/Mips.def
@@ -109,7 +109,7 @@
 ELF_RELOC(R_MICROMIPS_GPREL7_S2,        172)
 ELF_RELOC(R_MICROMIPS_PC23_S2,          173)
 ELF_RELOC(R_MICROMIPS_PC21_S2,          174)
-ELF_RELOC(R_MICROMIPS_PC26_S2,          175)
+ELF_RELOC(R_MICROMIPS_PC26_S1,          175)
 ELF_RELOC(R_MICROMIPS_PC18_S3,          176)
 ELF_RELOC(R_MICROMIPS_PC19_S2,          177)
 ELF_RELOC(R_MIPS_NUM,                218)
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
index 2681e47e..014db54 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
@@ -160,6 +160,16 @@
       return 0;
     }
     break;
+  case Mips::fixup_MICROMIPS_PC26_S1:
+    // Forcing a signed division because Value can be negative.
+    Value = (int64_t)Value / 2;
+    // We now check if Value can be encoded as a 26-bit signed immediate.
+    if (!isInt<26>(Value) && Ctx) {
+      Ctx->reportFatalError(Fixup.getLoc(), "out of range PC26 fixup");
+      return 0;
+    }
+    break;
+
   }
 
   return Value;
@@ -311,6 +321,7 @@
     { "fixup_MICROMIPS_PC7_S1",  0,      7,   MCFixupKindInfo::FKF_IsPCRel },
     { "fixup_MICROMIPS_PC10_S1", 0,     10,   MCFixupKindInfo::FKF_IsPCRel },
     { "fixup_MICROMIPS_PC16_S1", 0,     16,   MCFixupKindInfo::FKF_IsPCRel },
+    { "fixup_MICROMIPS_PC26_S1", 0,     26,   MCFixupKindInfo::FKF_IsPCRel },
     { "fixup_MICROMIPS_CALL16",  0,     16,   0 },
     { "fixup_MICROMIPS_GOT_DISP",        0,     16,   0 },
     { "fixup_MICROMIPS_GOT_PAGE",        0,     16,   0 },
@@ -377,6 +388,7 @@
     { "fixup_MICROMIPS_PC7_S1",  9,      7,   MCFixupKindInfo::FKF_IsPCRel },
     { "fixup_MICROMIPS_PC10_S1", 6,     10,   MCFixupKindInfo::FKF_IsPCRel },
     { "fixup_MICROMIPS_PC16_S1",16,     16,   MCFixupKindInfo::FKF_IsPCRel },
+    { "fixup_MICROMIPS_PC26_S1", 6,     26,   MCFixupKindInfo::FKF_IsPCRel },
     { "fixup_MICROMIPS_CALL16", 16,     16,   0 },
     { "fixup_MICROMIPS_GOT_DISP",        16,     16,   0 },
     { "fixup_MICROMIPS_GOT_PAGE",        16,     16,   0 },
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp
index 5721e72..6cc526f 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp
@@ -89,6 +89,8 @@
       return ELF::R_MICROMIPS_PC10_S1;
     case Mips::fixup_MICROMIPS_PC16_S1:
       return ELF::R_MICROMIPS_PC16_S1;
+    case Mips::fixup_MICROMIPS_PC26_S1:
+      return ELF::R_MICROMIPS_PC26_S1;
     case Mips::fixup_MIPS_PC19_S2:
       return ELF::R_MIPS_PC19_S2;
     case Mips::fixup_MIPS_PC18_S3:
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h
index 3652f4b..7a09fe2 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h
@@ -170,6 +170,9 @@
     // resulting in - R_MICROMIPS_PC16_S1
     fixup_MICROMIPS_PC16_S1,
 
+    // resulting in - R_MICROMIPS_PC26_S1
+    fixup_MICROMIPS_PC26_S1,
+
     // resulting in - R_MICROMIPS_CALL16
     fixup_MICROMIPS_CALL16,
 
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp
index 2ab4b99..b0a4157 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp
@@ -356,7 +356,13 @@
   if (MO.isImm())
     return MO.getImm() >> 1;
 
-  // TODO: Push 26 PC fixup.
+  assert(MO.isExpr() &&
+         "getBranchTarget26OpValueMM expects only expressions or immediates");
+
+  const MCExpr *FixupExpression = MCBinaryExpr::createAdd(
+      MO.getExpr(), MCConstantExpr::create(-4, Ctx), Ctx);
+  Fixups.push_back(MCFixup::create(0, FixupExpression,
+                                   MCFixupKind(Mips::fixup_MICROMIPS_PC26_S1)));
   return 0;
 }
 
diff --git a/llvm/test/MC/Mips/micromips32r6/relocations.s b/llvm/test/MC/Mips/micromips32r6/relocations.s
new file mode 100644
index 0000000..14baa6b
--- /dev/null
+++ b/llvm/test/MC/Mips/micromips32r6/relocations.s
@@ -0,0 +1,24 @@
+# RUN: llvm-mc %s -triple=mips-unknown-linux -show-encoding -mcpu=mips32r6 \
+# RUN:   -mattr=micromips | FileCheck %s -check-prefix=CHECK-FIXUP
+# RUN: llvm-mc %s -filetype=obj -triple=mips-unknown-linux -mcpu=mips32r6 \
+# RUN:   -mattr=micromips | llvm-readobj -r | FileCheck %s -check-prefix=CHECK-ELF
+#------------------------------------------------------------------------------
+# Check that the assembler can handle the documented syntax for fixups.
+#------------------------------------------------------------------------------
+# CHECK-FIXUP: balc  bar        # encoding: [0b101101AA,A,A,A]
+# CHECK-FIXUP:                  #   fixup A - offset: 0,
+# CHECK-FIXUP:                      value: bar-4, kind: fixup_MICROMIPS_PC26_S1
+# CHECK-FIXUP: bc    bar        # encoding: [0b100101AA,A,A,A]
+# CHECK-FIXUP:                  #   fixup A - offset: 0,
+# CHECK-FIXUP:                      value: bar-4, kind: fixup_MICROMIPS_PC26_S1
+#------------------------------------------------------------------------------
+# Check that the appropriate relocations were created.
+#------------------------------------------------------------------------------
+# CHECK-ELF: Relocations [
+# CHECK-ELF:     0x0 R_MICROMIPS_PC26_S1 bar 0x0
+# CHECK-ELF:     0x4 R_MICROMIPS_PC26_S1 bar 0x0
+# CHECK-ELF: ]
+
+  balc  bar
+  bc    bar
+
diff --git a/llvm/test/MC/Mips/micromips64r6/relocations.s b/llvm/test/MC/Mips/micromips64r6/relocations.s
new file mode 100644
index 0000000..b9e7243
--- /dev/null
+++ b/llvm/test/MC/Mips/micromips64r6/relocations.s
@@ -0,0 +1,23 @@
+# RUN: llvm-mc %s -triple=mips-unknown-linux -show-encoding -mcpu=mips64r6 \
+# RUN:   -mattr=micromips | FileCheck %s -check-prefix=CHECK-FIXUP
+# RUN: llvm-mc %s -filetype=obj -triple=mips-unknown-linux -mcpu=mips64r6 \
+# RUN:   -mattr=micromips | llvm-readobj -r | FileCheck %s -check-prefix=CHECK-ELF
+#------------------------------------------------------------------------------
+# Check that the assembler can handle the documented syntax for fixups.
+#------------------------------------------------------------------------------
+# CHECK-FIXUP: balc  bar        # encoding: [0b101101AA,A,A,A]
+# CHECK-FIXUP:                  #   fixup A - offset: 0,
+# CHECK-FIXUP:                      value: bar-4, kind: fixup_MICROMIPS_PC26_S1
+# CHECK-FIXUP: bc    bar        # encoding: [0b100101AA,A,A,A]
+# CHECK-FIXUP:                  #   fixup A - offset: 0,
+# CHECK-FIXUP:                      value: bar-4, kind: fixup_MICROMIPS_PC26_S1
+#------------------------------------------------------------------------------
+# Check that the appropriate relocations were created.
+#------------------------------------------------------------------------------
+# CHECK-ELF: Relocations [
+# CHECK-ELF:     0x0 R_MICROMIPS_PC26_S1 bar 0x0
+# CHECK-ELF:     0x4 R_MICROMIPS_PC26_S1 bar 0x0
+# CHECK-ELF: ]
+
+  balc  bar
+  bc    bar