Properly handle Mips MC relocations and lower cpload and cprestore macros to MCInsts.

Patch by Jack Carter.

llvm-svn: 144139
diff --git a/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp b/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp
index 53282ab..4a815f3 100644
--- a/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp
+++ b/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp
@@ -13,8 +13,10 @@
 
 #define DEBUG_TYPE "asm-printer"
 #include "MipsInstPrinter.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/MC/MCExpr.h"
 #include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCSymbol.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/raw_ostream.h"
 using namespace llvm;
@@ -74,6 +76,52 @@
   printAnnotation(O, Annot);
 }
 
+static void printExpr(const MCExpr *Expr, raw_ostream &OS) {
+  int Offset = 0;
+  const MCSymbolRefExpr *SRE;
+
+  if (const MCBinaryExpr *BE = dyn_cast<MCBinaryExpr>(Expr)) {
+    SRE = dyn_cast<MCSymbolRefExpr>(BE->getLHS());
+    const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(BE->getRHS());
+    assert(SRE && CE && "Binary expression must be sym+const.");
+    Offset = CE->getValue();
+  }
+  else if (!(SRE = dyn_cast<MCSymbolRefExpr>(Expr)))
+    assert(false && "Unexpected MCExpr type.");
+
+  MCSymbolRefExpr::VariantKind Kind = SRE->getKind();
+
+  switch (Kind) {
+  default: assert(0 && "Invalid kind!");
+  case MCSymbolRefExpr::VK_None:     break;
+  case MCSymbolRefExpr::VK_Mips_GPREL:    OS << "%gp_rel("; break;
+  case MCSymbolRefExpr::VK_Mips_GOT_CALL: OS << "%call16("; break;
+  case MCSymbolRefExpr::VK_Mips_GOT:      OS << "%got(";    break;
+  case MCSymbolRefExpr::VK_Mips_ABS_HI:   OS << "%hi(";     break;
+  case MCSymbolRefExpr::VK_Mips_ABS_LO:   OS << "%lo(";     break;
+  case MCSymbolRefExpr::VK_Mips_TLSGD:    OS << "%tlsgd(";  break;
+  case MCSymbolRefExpr::VK_Mips_GOTTPREL: OS << "%gottprel("; break;
+  case MCSymbolRefExpr::VK_Mips_TPREL_HI: OS << "%tprel_hi("; break;
+  case MCSymbolRefExpr::VK_Mips_TPREL_LO: OS << "%tprel_lo("; break;
+  case MCSymbolRefExpr::VK_Mips_GPOFF_HI: OS << "%hi(%neg(%gp_rel("; break;
+  case MCSymbolRefExpr::VK_Mips_GPOFF_LO: OS << "%lo(%neg(%gp_rel("; break;
+  case MCSymbolRefExpr::VK_Mips_GOT_DISP: OS << "%got_disp("; break;
+  case MCSymbolRefExpr::VK_Mips_GOT_PAGE: OS << "%got_page("; break;
+  case MCSymbolRefExpr::VK_Mips_GOT_OFST: OS << "%got_ofst("; break;
+  }
+
+  OS << SRE->getSymbol();
+
+  if (Offset) {
+    if (Offset > 0)
+      OS << '+';
+    OS << Offset;
+  }
+
+  if (Kind != MCSymbolRefExpr::VK_None)
+    OS << ')';
+}
+
 void MipsInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
                                    raw_ostream &O) {
   const MCOperand &Op = MI->getOperand(OpNo);
@@ -88,7 +136,7 @@
   }
   
   assert(Op.isExpr() && "unknown operand kind in printOperand");
-  O << *Op.getExpr();
+  printExpr(Op.getExpr(), O);
 }
 
 void MipsInstPrinter::printUnsignedImm(const MCInst *MI, int opNum,