[SubZero] Handle relocatable constants for MIPS

The patch generates HI/LO modifiers for relocatable constants.

R=stichnot@chromium.org

Review URL: https://codereview.chromium.org/2420033002 .

Patch from Jaydeep Patil <jaydeep.patil@imgtec.com>.
diff --git a/src/IceInstMIPS32.h b/src/IceInstMIPS32.h
index e3f1e82..2e367e9 100644
--- a/src/IceInstMIPS32.h
+++ b/src/IceInstMIPS32.h
@@ -983,14 +983,21 @@
 
 public:
   static InstMIPS32Imm16 *create(Cfg *Func, Variable *Dest, Operand *Source,
-                                 uint32_t Imm) {
+                                 uint32_t Imm, RelocOp Reloc = RO_No) {
     return new (Func->allocate<InstMIPS32Imm16>())
-        InstMIPS32Imm16(Func, Dest, Source, Imm);
+        InstMIPS32Imm16(Func, Dest, Source, Imm, Reloc);
   }
 
-  static InstMIPS32Imm16 *create(Cfg *Func, Variable *Dest, uint32_t Imm) {
+  static InstMIPS32Imm16 *create(Cfg *Func, Variable *Dest, uint32_t Imm,
+                                 RelocOp Reloc = RO_No) {
     return new (Func->allocate<InstMIPS32Imm16>())
-        InstMIPS32Imm16(Func, Dest, Imm);
+        InstMIPS32Imm16(Func, Dest, Imm, Reloc);
+  }
+
+  static InstMIPS32Imm16 *create(Cfg *Func, Variable *Dest, Operand *Src0,
+                                 Operand *Src1, RelocOp Reloc) {
+    return new (Func->allocate<InstMIPS32Imm16>())
+        InstMIPS32Imm16(Func, Dest, Src0, Src1, Reloc);
   }
 
   void emit(const Cfg *Func) const override {
@@ -1004,10 +1011,18 @@
       getSrc(0)->emit(Func);
     }
     Str << ", ";
-    if (Signed)
-      Str << (int32_t)Imm;
-    else
-      Str << Imm;
+    if (Reloc == RO_No) {
+      if (Signed)
+        Str << (int32_t)Imm;
+      else
+        Str << Imm;
+    } else {
+      auto *CR = llvm::dyn_cast<ConstantRelocatable>(getSrc(1));
+      emitRelocOp(Str, Reloc);
+      Str << "(";
+      CR->emitWithoutPrefix(Func->getTarget());
+      Str << ")";
+    }
   }
 
   void emitIAS(const Cfg *Func) const override {
@@ -1022,27 +1037,45 @@
     Str << " ";
     dumpDest(Func);
     Str << ", ";
-    dumpSources(Func);
-    Str << ", ";
-    if (Signed)
-      Str << (int32_t)Imm;
-    else
-      Str << Imm;
+    if (Reloc == RO_No) {
+      dumpSources(Func);
+      Str << ", ";
+      if (Signed)
+        Str << (int32_t)Imm;
+      else
+        Str << Imm;
+    } else {
+      getSrc(0)->dump(Func);
+      Str << ",";
+      emitRelocOp(Str, Reloc);
+      Str << "(";
+      getSrc(1)->dump(Func);
+      Str << ")";
+    }
   }
 
   static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
 
 private:
-  InstMIPS32Imm16(Cfg *Func, Variable *Dest, Operand *Source, uint32_t Imm)
-      : InstMIPS32(Func, K, 1, Dest), Imm(Imm) {
+  InstMIPS32Imm16(Cfg *Func, Variable *Dest, Operand *Source, uint32_t Imm,
+                  RelocOp Reloc = RO_No)
+      : InstMIPS32(Func, K, 1, Dest), Reloc(Reloc), Imm(Imm) {
     addSource(Source);
   }
 
-  InstMIPS32Imm16(Cfg *Func, Variable *Dest, uint32_t Imm)
-      : InstMIPS32(Func, K, 0, Dest), Imm(Imm) {}
+  InstMIPS32Imm16(Cfg *Func, Variable *Dest, uint32_t Imm,
+                  RelocOp Reloc = RO_No)
+      : InstMIPS32(Func, K, 0, Dest), Reloc(Reloc), Imm(Imm) {}
+
+  InstMIPS32Imm16(Cfg *Func, Variable *Dest, Operand *Src0, Operand *Src1,
+                  RelocOp Reloc = RO_No)
+      : InstMIPS32(Func, K, 1, Dest), Reloc(Reloc), Imm(0) {
+    addSource(Src0);
+    addSource(Src1);
+  }
 
   static const char *Opcode;
-
+  const RelocOp Reloc;
   const uint32_t Imm;
 };
 
diff --git a/src/IceTargetLoweringMIPS32.cpp b/src/IceTargetLoweringMIPS32.cpp
index 624c4a5..b7d36a6 100644
--- a/src/IceTargetLoweringMIPS32.cpp
+++ b/src/IceTargetLoweringMIPS32.cpp
@@ -4961,10 +4961,10 @@
         return From;
     }
     if (auto *C = llvm::dyn_cast<ConstantRelocatable>(From)) {
-      (void)C;
-      // TODO(reed kotler): complete this case for proper implementation
       Variable *Reg = makeReg(Ty, RegNum);
-      Context.insert<InstFakeDef>(Reg);
+      Variable *TReg = makeReg(Ty, RegNum);
+      _lui(TReg, C, RO_Hi);
+      _addiu(Reg, TReg, C, RO_Lo);
       return Reg;
     } else if (auto *C32 = llvm::dyn_cast<ConstantInteger32>(From)) {
       const uint32_t Value = C32->getValue();
diff --git a/src/IceTargetLoweringMIPS32.h b/src/IceTargetLoweringMIPS32.h
index 6a50b96..09b981b 100644
--- a/src/IceTargetLoweringMIPS32.h
+++ b/src/IceTargetLoweringMIPS32.h
@@ -216,6 +216,10 @@
     Context.insert<InstMIPS32Addiu>(Dest, Src, Imm);
   }
 
+  void _addiu(Variable *Dest, Variable *Src0, Operand *Src1, RelocOp Reloc) {
+    Context.insert<InstMIPS32Addiu>(Dest, Src0, Src1, Reloc);
+  }
+
   void _c_eq_d(Variable *Src0, Variable *Src1) {
     Context.insert<InstMIPS32C_eq_d>(Src0, Src1);
   }
diff --git a/tests_lit/llvm2ice_tests/arith.ll b/tests_lit/llvm2ice_tests/arith.ll
index cf8644b..659b30c 100644
--- a/tests_lit/llvm2ice_tests/arith.ll
+++ b/tests_lit/llvm2ice_tests/arith.ll
@@ -276,6 +276,11 @@
 ; CHECK-LABEL: ShlReloc
 ; CHECK: shl {{.*}},cl
 
+; MIPS32-LABEL: ShlReloc
+; MIPS32: lui [[REG:.*]],{{.*}} R_MIPS_HI16 G
+; MIPS32: addiu [[REG]],[[REG]],{{.*}} R_MIPS_LO16 G
+; MIPS32: sllv {{.*}},{{.*}},[[REG]]
+
 define internal i32 @LshrReloc(i32 %a) {
 entry:
   %opnd = ptrtoint [4 x i8]* @G to i32
@@ -285,6 +290,11 @@
 ; CHECK-LABEL: LshrReloc
 ; CHECK: shr {{.*}},cl
 
+; MIPS32-LABEL: LshrReloc
+; MIPS32: lui [[REG:.*]],{{.*}} R_MIPS_HI16 G
+; MIPS32: addiu [[REG]],[[REG]],{{.*}} R_MIPS_LO16 G
+; MIPS32: srlv {{.*}},{{.*}},[[REG]]
+
 define internal i32 @AshrReloc(i32 %a) {
 entry:
   %opnd = ptrtoint [4 x i8]* @G to i32
@@ -293,3 +303,8 @@
 }
 ; CHECK-LABEL: AshrReloc
 ; CHECK: sar {{.*}},cl
+
+; MIPS32-LABEL: AshrReloc
+; MIPS32: lui [[REG:.*]],{{.*}} R_MIPS_HI16 G
+; MIPS32: addiu [[REG]],[[REG]],{{.*}} R_MIPS_LO16 G
+; MIPS32: srav {{.*}},{{.*}},[[REG]]