Subzero, MIPS32: Introduction of floating point registers

This patch introduces floating point registers used for 32-bit
operations, and basic handling of FP values in operands. It is
partial work needed as a base for further work.

R=stichnot@chromium.org

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

Patch from Srdjan Obucina <Srdjan.Obucina@imgtec.com>.
diff --git a/src/IceInstMIPS32.cpp b/src/IceInstMIPS32.cpp
index 0bc97a8..a32afa9 100644
--- a/src/IceInstMIPS32.cpp
+++ b/src/IceInstMIPS32.cpp
@@ -65,16 +65,26 @@
 template <> const char *InstMIPS32La::Opcode = "la";
 // Three-addr ops
 template <> const char *InstMIPS32Add::Opcode = "add";
+template <> const char *InstMIPS32Add_d::Opcode = "add.d";
+template <> const char *InstMIPS32Add_s::Opcode = "add.s";
 template <> const char *InstMIPS32Addu::Opcode = "addu";
 template <> const char *InstMIPS32And::Opcode = "and";
 template <> const char *InstMIPS32Andi::Opcode = "andi";
 template <> const char *InstMIPS32Div::Opcode = "div";
+template <> const char *InstMIPS32Div_d::Opcode = "div.d";
+template <> const char *InstMIPS32Div_s::Opcode = "div.s";
 template <> const char *InstMIPS32Divu::Opcode = "divu";
+template <> const char *InstMIPS32Mfc1::Opcode = "mfc1";
 template <> const char *InstMIPS32Mfhi::Opcode = "mfhi";
 template <> const char *InstMIPS32Mflo::Opcode = "mflo";
+template <> const char *InstMIPS32Mov_d::Opcode = "mov.d";
+template <> const char *InstMIPS32Mov_s::Opcode = "mov.s";
+template <> const char *InstMIPS32Mtc1::Opcode = "mtc1";
 template <> const char *InstMIPS32Mthi::Opcode = "mthi";
 template <> const char *InstMIPS32Mtlo::Opcode = "mtlo";
 template <> const char *InstMIPS32Mul::Opcode = "mul";
+template <> const char *InstMIPS32Mul_d::Opcode = "mul.d";
+template <> const char *InstMIPS32Mul_s::Opcode = "mul.s";
 template <> const char *InstMIPS32Mult::Opcode = "mult";
 template <> const char *InstMIPS32Multu::Opcode = "multu";
 template <> const char *InstMIPS32Or::Opcode = "or";
@@ -90,6 +100,8 @@
 template <> const char *InstMIPS32Srl::Opcode = "srl";
 template <> const char *InstMIPS32Srlv::Opcode = "srlv";
 template <> const char *InstMIPS32Sub::Opcode = "sub";
+template <> const char *InstMIPS32Sub_d::Opcode = "sub.d";
+template <> const char *InstMIPS32Sub_s::Opcode = "sub.s";
 template <> const char *InstMIPS32Subu::Opcode = "subu";
 template <> const char *InstMIPS32Xor::Opcode = "xor";
 template <> const char *InstMIPS32Xori::Opcode = "xori";
@@ -278,6 +290,18 @@
   Inst->getSrc(1)->emit(Func);
 }
 
+void InstMIPS32::emitTwoAddr(const char *Opcode, const InstMIPS32 *Inst,
+                             const Cfg *Func) {
+  if (!BuildDefs::dump())
+    return;
+  Ostream &Str = Func->getContext()->getStrEmit();
+  assert(Inst->getSrcSize() == 1);
+  Str << "\t" << Opcode << "\t";
+  Inst->getDest()->emit(Func);
+  Str << ", ";
+  Inst->getSrc(0)->emit(Func);
+}
+
 void InstMIPS32::emitThreeAddrLoHi(const char *Opcode, const InstMIPS32 *Inst,
                                    const Cfg *Func) {
   if (!BuildDefs::dump())
diff --git a/src/IceInstMIPS32.def b/src/IceInstMIPS32.def
index d84890e..6120a47 100644
--- a/src/IceInstMIPS32.def
+++ b/src/IceInstMIPS32.def
@@ -105,13 +105,45 @@
     ALIASES1(Reg_RA))                                                          \
   X(Reg_LO,       0,   "lo",    0, 0, 0, 0, 0, 0, 0, 0, 0,                     \
     ALIASES2(Reg_LO, Reg_LOHI))                                                \
-  X(Reg_HI,       0,  "hi",     0, 0, 0, 0, 0, 0, 0, 0, 0,                     \
+  X(Reg_HI,       0,   "hi",    0, 0, 0, 0, 0, 0, 0, 0, 0,                     \
    ALIASES2(Reg_HI, Reg_LOHI))
-//#define X(val, encode, name, scratch, preserved, stackptr, frameptr,
-//          isInt, isI64Pair, isFP32, isFP64, isVec128, alias_init)
-// TODO(reed kotler): List FP registers etc.
-// Be able to grab even registers, and the corresponding odd register
-// for each even register.
+
+#define REGMIPS32_FPR_TABLE                                                    \
+  /* val, encode, name, scratch, preserved, stackptr, frameptr,                \
+     isInt, isI64Pair, isFP32, isFP64, isVec128, alias_init */                 \
+  X(Reg_F0,       0,   "f0",    1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F0))          \
+  X(Reg_F1,       1,   "f1",    1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F1))          \
+  X(Reg_F2,       2,   "f2",    1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F2))          \
+  X(Reg_F3,       3,   "f3",    1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F3))          \
+  X(Reg_F4,       4,   "f4",    1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F4))          \
+  X(Reg_F5,       5,   "f5",    1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F5))          \
+  X(Reg_F6,       6,   "f6",    1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F6))          \
+  X(Reg_F7,       7,   "f7",    1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F7))          \
+  X(Reg_F8,       8,   "f8",    1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F8))          \
+  X(Reg_F9,       9,   "f9",    1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F9))          \
+  X(Reg_F10,      10,  "f10",   1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F10))         \
+  X(Reg_F11,      11,  "f11",   1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F11))         \
+  X(Reg_F12,      12,  "f12",   1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F12))         \
+  X(Reg_F13,      13,  "f13",   1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F13))         \
+  X(Reg_F14,      14,  "f14",   1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F14))         \
+  X(Reg_F15,      15,  "f15",   1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F15))         \
+  X(Reg_F16,      16,  "f16",   1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F16))         \
+  X(Reg_F17,      17,  "f17",   1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F17))         \
+  X(Reg_F18,      18,  "f18",   1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F18))         \
+  X(Reg_F19,      19,  "f19",   1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F19))         \
+  X(Reg_F20,      20,  "f20",   1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F20))         \
+  X(Reg_F21,      21,  "f21",   1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F21))         \
+  X(Reg_F22,      22,  "f22",   1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F22))         \
+  X(Reg_F23,      23,  "f23",   1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F23))         \
+  X(Reg_F24,      24,  "f24",   1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F24))         \
+  X(Reg_F25,      25,  "f25",   1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F25))         \
+  X(Reg_F26,      26,  "f26",   1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F26))         \
+  X(Reg_F27,      27,  "f27",   1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F27))         \
+  X(Reg_F28,      28,  "f28",   1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F28))         \
+  X(Reg_F29,      29,  "f29",   1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F29))         \
+  X(Reg_F30,      30,  "f30",   1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F30))         \
+  X(Reg_F31,      31,  "f31",   1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F31))
+
 //#define X(val, encode, name, scratch, preserved, stackptr, frameptr,
 //          isInt, isI64Pair, isFP32, isFP64, isVec128, alias_init)
 // The following defines a table with the available pairs of consecutive i32
@@ -151,6 +183,42 @@
 //#define X(val, encode, name, scratch, preserved, stackptr, frameptr,
 //          isInt, isI64Pair, isFP32, isFP64, isVec128, alias_init)
 
+#define REGMIPS32_F64PAIR_TABLE                                                \
+  /* val, encode, name, scratch, preserved, stackptr, frameptr,                \
+     isInt, isI64Pair, isFP32, isFP64, isVec128, alias_init */                 \
+  X(Reg_F0F1,   0,  "f0, f1",   1,0,0,0, 0,0,0,1,0,                            \
+    ALIASES3(Reg_F0, Reg_F1, Reg_F0F1))                                        \
+  X(Reg_F2F3,   2,  "f2, f3",   1,0,0,0, 0,0,0,1,0,                            \
+    ALIASES3(Reg_F2, Reg_F3, Reg_F2F3))                                        \
+  X(Reg_F4F5,   4,  "f4, f5",   1,0,0,0, 0,0,0,1,0,                            \
+    ALIASES3(Reg_F4, Reg_F5, Reg_F4F5))                                        \
+  X(Reg_F6F7,   6,  "f6, f7",   1,0,0,0, 0,0,0,1,0,                            \
+    ALIASES3(Reg_F6, Reg_F7, Reg_F6F7))                                        \
+  X(Reg_F8F9,   8,  "f8, f9",   1,0,0,0, 0,0,0,1,0,                            \
+    ALIASES3(Reg_F8, Reg_F9, Reg_F8F9))                                        \
+  X(Reg_F10F11, 10, "f10, f11", 1,0,0,0, 0,0,0,1,0,                            \
+    ALIASES3(Reg_F10, Reg_F11, Reg_F10F11))                                    \
+  X(Reg_F12F13, 12, "f12, f13", 1,0,0,0, 0,0,0,1,0,                            \
+    ALIASES3(Reg_F12, Reg_F13, Reg_F12F13))                                    \
+  X(Reg_F14F15, 14, "f14, f15", 1,0,0,0, 0,0,0,1,0,                            \
+    ALIASES3(Reg_F14, Reg_F15, Reg_F14F15))                                    \
+  X(Reg_F16F17, 16, "f16, f17", 1,0,0,0, 0,0,0,1,0,                            \
+    ALIASES3(Reg_F16, Reg_F17, Reg_F16F17))                                    \
+  X(Reg_F18F19, 18, "f18, f19", 1,0,0,0, 0,0,0,1,0,                            \
+    ALIASES3(Reg_F18, Reg_F19, Reg_F18F19))                                    \
+  X(Reg_F20F21, 20, "f20, f21", 1,0,0,0, 0,0,0,1,0,                            \
+    ALIASES3(Reg_F20, Reg_F21, Reg_F20F21))                                    \
+  X(Reg_F22F23, 22, "f22, f23", 1,0,0,0, 0,0,0,1,0,                            \
+    ALIASES3(Reg_F22, Reg_F23, Reg_F22F23))                                    \
+  X(Reg_F24F25, 24, "f24, f25", 1,0,0,0, 0,0,0,1,0,                            \
+    ALIASES3(Reg_F24, Reg_F25, Reg_F24F25))                                    \
+  X(Reg_F26F27, 26, "f26, f27", 1,0,0,0, 0,0,0,1,0,                            \
+    ALIASES3(Reg_F26, Reg_F27, Reg_F26F27))                                    \
+  X(Reg_F28F29, 28, "f28, f29", 1,0,0,0, 0,0,0,1,0,                            \
+    ALIASES3(Reg_F28, Reg_F29, Reg_F28F29))                                    \
+  X(Reg_F30F31, 30, "f30, f31", 1,0,0,0, 0,0,0,1,0,                            \
+    ALIASES3(Reg_F30, Reg_F31, Reg_F30F31))
+
 // We also provide a combined table, so that there is a namespace where
 // all of the registers are considered and have distinct numberings.
 // This is in contrast to the above, where the "encode" is based on how
@@ -159,7 +227,9 @@
   /* val, encode, name, scratch, preserved, stackptr, frameptr, isInt,         \
      isFP32, isFP64, isVec128, alias_init */                                   \
   REGMIPS32_GPR_TABLE                                                          \
-  REGMIPS32_I64PAIR_TABLE
+  REGMIPS32_FPR_TABLE                                                          \
+  REGMIPS32_I64PAIR_TABLE                                                      \
+  REGMIPS32_F64PAIR_TABLE
 
 //#define X(val, encode, name, scratch, preserved, stackptr, frameptr,
 //          isInt, isI64Pair, isFP32, isFP64, isVec128, alias_init)
@@ -167,8 +237,12 @@
   /* val, init */                                                              \
   X(Reg_GPR_First, = Reg_ZERO)                                                 \
   X(Reg_GPR_Last,  = Reg_HI)                                                   \
+  X(Reg_FPR_First, = Reg_F0)                                                   \
+  X(Reg_FPR_Last,  = Reg_F31)                                                  \
   X(Reg_I64PAIR_First, = Reg_V0V1)                                             \
   X(Reg_I64PAIR_Last, = Reg_LOHI)                                              \
+  X(Reg_F64PAIR_First, = Reg_F0F1)                                             \
+  X(Reg_F64PAIR_Last, = Reg_F30F31)                                            \
 //define X(val, init)
 
 #define ICEINSTMIPS32COND_TABLE                                                \
diff --git a/src/IceInstMIPS32.h b/src/IceInstMIPS32.h
index 71c1e4b..37a2f04 100644
--- a/src/IceInstMIPS32.h
+++ b/src/IceInstMIPS32.h
@@ -119,6 +119,8 @@
   enum InstKindMIPS32 {
     k__Start = Inst::Target,
     Add,
+    Add_d,
+    Add_s,
     Addiu,
     Addu,
     And,
@@ -126,16 +128,24 @@
     Br,
     Call,
     Div,
+    Div_d,
+    Div_s,
     Divu,
     La,
     Label,
     Lui,
+    Mfc1,
     Mfhi,
     Mflo,
     Mov, // actually a pseudo op for addi rd, rs, 0
+    Mov_d,
+    Mov_s,
+    Mtc1,
     Mthi,
     Mtlo,
     Mul,
+    Mul_d,
+    Mul_s,
     Mult,
     Multu,
     Or,
@@ -152,6 +162,8 @@
     Srl,
     Srlv,
     Sub,
+    Sub_d,
+    Sub_s,
     Subu,
     Xor,
     Xori
@@ -175,6 +187,8 @@
                                   const Cfg *Func);
   static void emitUnaryopGPRTLoHi(const char *Opcode, const InstMIPS32 *Inst,
                                   const Cfg *Func);
+  static void emitTwoAddr(const char *Opcode, const InstMIPS32 *Inst,
+                          const Cfg *Func);
   static void emitThreeAddr(const char *Opcode, const InstMIPS32 *Inst,
                             const Cfg *Func);
   static void emitThreeAddrLoHi(const char *Opcode, const InstMIPS32 *Inst,
@@ -259,6 +273,143 @@
   static const char *Opcode;
 };
 
+/// Instructions of the form opcode reg, reg.
+template <InstMIPS32::InstKindMIPS32 K>
+class InstMIPS32TwoAddrFPR : public InstMIPS32 {
+  InstMIPS32TwoAddrFPR() = delete;
+  InstMIPS32TwoAddrFPR(const InstMIPS32TwoAddrFPR &) = delete;
+  InstMIPS32TwoAddrFPR &operator=(const InstMIPS32TwoAddrFPR &) = delete;
+
+public:
+  static InstMIPS32TwoAddrFPR *create(Cfg *Func, Variable *Dest,
+                                      Variable *Src0) {
+    return new (Func->allocate<InstMIPS32TwoAddrFPR>())
+        InstMIPS32TwoAddrFPR(Func, Dest, Src0);
+  }
+  void emit(const Cfg *Func) const override {
+    if (!BuildDefs::dump())
+      return;
+    emitTwoAddr(Opcode, this, Func);
+  }
+  void emitIAS(const Cfg *Func) const override {
+    (void)Func;
+    llvm_unreachable("Not yet implemented");
+  }
+
+  void dump(const Cfg *Func) const override {
+    if (!BuildDefs::dump())
+      return;
+    Ostream &Str = Func->getContext()->getStrDump();
+    dumpDest(Func);
+    Str << " = ";
+    dumpOpcode(Str, Opcode, getDest()->getType());
+    Str << " ";
+    dumpSources(Func);
+  }
+  static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
+
+private:
+  InstMIPS32TwoAddrFPR(Cfg *Func, Variable *Dest, Variable *Src0)
+      : InstMIPS32(Func, K, 1, Dest) {
+    addSource(Src0);
+  }
+
+  static const char *Opcode;
+};
+
+/// Instructions of the form opcode reg, reg.
+template <InstMIPS32::InstKindMIPS32 K>
+class InstMIPS32TwoAddrGPR : public InstMIPS32 {
+  InstMIPS32TwoAddrGPR() = delete;
+  InstMIPS32TwoAddrGPR(const InstMIPS32TwoAddrGPR &) = delete;
+  InstMIPS32TwoAddrGPR &operator=(const InstMIPS32TwoAddrGPR &) = delete;
+
+public:
+  static InstMIPS32TwoAddrGPR *create(Cfg *Func, Variable *Dest,
+                                      Variable *Src0) {
+    return new (Func->allocate<InstMIPS32TwoAddrGPR>())
+        InstMIPS32TwoAddrGPR(Func, Dest, Src0);
+  }
+  void emit(const Cfg *Func) const override {
+    if (!BuildDefs::dump())
+      return;
+    emitTwoAddr(Opcode, this, Func);
+  }
+  void emitIAS(const Cfg *Func) const override {
+    (void)Func;
+    llvm_unreachable("Not yet implemented");
+  }
+
+  void dump(const Cfg *Func) const override {
+    if (!BuildDefs::dump())
+      return;
+    Ostream &Str = Func->getContext()->getStrDump();
+    dumpDest(Func);
+    Str << " = ";
+    dumpOpcode(Str, Opcode, getDest()->getType());
+    Str << " ";
+    dumpSources(Func);
+  }
+  static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
+
+private:
+  InstMIPS32TwoAddrGPR(Cfg *Func, Variable *Dest, Variable *Src0)
+      : InstMIPS32(Func, K, 1, Dest) {
+    addSource(Src0);
+  }
+
+  static const char *Opcode;
+};
+
+/// Instructions of the form x := y op z. May have the side-effect of setting
+/// status flags.
+template <InstMIPS32::InstKindMIPS32 K>
+class InstMIPS32ThreeAddrFPR : public InstMIPS32 {
+  InstMIPS32ThreeAddrFPR() = delete;
+  InstMIPS32ThreeAddrFPR(const InstMIPS32ThreeAddrFPR &) = delete;
+  InstMIPS32ThreeAddrFPR &operator=(const InstMIPS32ThreeAddrFPR &) = delete;
+
+public:
+  /// Create an ordinary binary-op instruction like add, and sub. Dest and Src1
+  /// must be registers.
+  static InstMIPS32ThreeAddrFPR *create(Cfg *Func, Variable *Dest,
+                                        Variable *Src0, Variable *Src1) {
+    return new (Func->allocate<InstMIPS32ThreeAddrFPR>())
+        InstMIPS32ThreeAddrFPR(Func, Dest, Src0, Src1);
+  }
+  void emit(const Cfg *Func) const override {
+    if (!BuildDefs::dump())
+      return;
+    emitThreeAddr(Opcode, this, Func);
+  }
+  void emitIAS(const Cfg *Func) const override {
+    (void)Func;
+    llvm_unreachable("Not yet implemented");
+  }
+
+  void dump(const Cfg *Func) const override {
+    if (!BuildDefs::dump())
+      return;
+    Ostream &Str = Func->getContext()->getStrDump();
+    dumpDest(Func);
+    Str << " = ";
+    dumpOpcode(Str, Opcode, getDest()->getType());
+    Str << " ";
+    dumpSources(Func);
+  }
+  static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
+
+private:
+  InstMIPS32ThreeAddrFPR(Cfg *Func, Variable *Dest, Variable *Src0,
+                         Variable *Src1)
+      : InstMIPS32(Func, K, 2, Dest) {
+    addSource(Src0);
+    addSource(Src1);
+  }
+
+  static const char *Opcode;
+};
+
 /// Instructions of the form x := y op z. May have the side-effect of setting
 /// status flags.
 template <InstMIPS32::InstKindMIPS32 K>
@@ -498,19 +649,29 @@
 };
 
 using InstMIPS32Add = InstMIPS32ThreeAddrGPR<InstMIPS32::Add>;
+using InstMIPS32Add_d = InstMIPS32ThreeAddrFPR<InstMIPS32::Add_d>;
+using InstMIPS32Add_s = InstMIPS32ThreeAddrFPR<InstMIPS32::Add_s>;
 using InstMIPS32Addu = InstMIPS32ThreeAddrGPR<InstMIPS32::Addu>;
 using InstMIPS32Addiu = InstMIPS32Imm16<InstMIPS32::Addiu, true>;
 using InstMIPS32And = InstMIPS32ThreeAddrGPR<InstMIPS32::And>;
 using InstMIPS32Andi = InstMIPS32Imm16<InstMIPS32::Andi>;
 using InstMIPS32Div = InstMIPS32ThreeAddrGPR<InstMIPS32::Div>;
+using InstMIPS32Div_d = InstMIPS32ThreeAddrFPR<InstMIPS32::Div_d>;
+using InstMIPS32Div_s = InstMIPS32ThreeAddrFPR<InstMIPS32::Div_s>;
 using InstMIPS32Divu = InstMIPS32ThreeAddrGPR<InstMIPS32::Divu>;
 using InstMIPS32Lui = InstMIPS32Imm16<InstMIPS32::Lui>;
 using InstMIPS32La = InstMIPS32UnaryopGPR<InstMIPS32::La>;
+using InstMIPS32Mfc1 = InstMIPS32TwoAddrGPR<InstMIPS32::Mfc1>;
 using InstMIPS32Mfhi = InstMIPS32UnaryopGPR<InstMIPS32::Mfhi>;
 using InstMIPS32Mflo = InstMIPS32UnaryopGPR<InstMIPS32::Mflo>;
+using InstMIPS32Mov_d = InstMIPS32TwoAddrFPR<InstMIPS32::Mov_d>;
+using InstMIPS32Mov_s = InstMIPS32TwoAddrFPR<InstMIPS32::Mov_s>;
+using InstMIPS32Mtc1 = InstMIPS32TwoAddrGPR<InstMIPS32::Mtc1>;
 using InstMIPS32Mthi = InstMIPS32UnaryopGPR<InstMIPS32::Mthi>;
 using InstMIPS32Mtlo = InstMIPS32UnaryopGPR<InstMIPS32::Mtlo>;
 using InstMIPS32Mul = InstMIPS32ThreeAddrGPR<InstMIPS32::Mul>;
+using InstMIPS32Mul_d = InstMIPS32ThreeAddrFPR<InstMIPS32::Mul_d>;
+using InstMIPS32Mul_s = InstMIPS32ThreeAddrFPR<InstMIPS32::Mul_s>;
 using InstMIPS32Mult = InstMIPS32ThreeAddrGPR<InstMIPS32::Mult>;
 using InstMIPS32Multu = InstMIPS32ThreeAddrGPR<InstMIPS32::Multu>;
 using InstMIPS32Or = InstMIPS32ThreeAddrGPR<InstMIPS32::Or>;
@@ -526,6 +687,8 @@
 using InstMIPS32Srl = InstMIPS32Imm16<InstMIPS32::Srl>;
 using InstMIPS32Srlv = InstMIPS32ThreeAddrGPR<InstMIPS32::Srlv>;
 using InstMIPS32Sub = InstMIPS32ThreeAddrGPR<InstMIPS32::Sub>;
+using InstMIPS32Sub_d = InstMIPS32ThreeAddrFPR<InstMIPS32::Sub_d>;
+using InstMIPS32Sub_s = InstMIPS32ThreeAddrFPR<InstMIPS32::Sub_s>;
 using InstMIPS32Subu = InstMIPS32ThreeAddrGPR<InstMIPS32::Subu>;
 using InstMIPS32Ori = InstMIPS32Imm16<InstMIPS32::Ori>;
 using InstMIPS32Xor = InstMIPS32ThreeAddrGPR<InstMIPS32::Xor>;
diff --git a/src/IceRegistersMIPS32.h b/src/IceRegistersMIPS32.h
index 4e14387..f6ea38e 100644
--- a/src/IceRegistersMIPS32.h
+++ b/src/IceRegistersMIPS32.h
@@ -24,8 +24,8 @@
 namespace MIPS32 {
 namespace RegMIPS32 {
 
-/// An enum of every register. The enum value may not match the encoding
-/// used to binary encode register operands in instructions.
+/// An enum of every register. The enum value may not match the encoding used to
+/// binary encode register operands in instructions.
 enum AllRegisters {
 #define X(val, encode, name, scratch, preserved, stackptr, frameptr, isInt,    \
           isI64Pair, isFP32, isFP64, isVec128, alias_init)                     \
@@ -38,8 +38,8 @@
 #undef X
 };
 
-/// An enum of GPR Registers. The enum value does match the encoding used
-/// to binary encode register operands in instructions.
+/// An enum of GPR Registers. The enum value does match the encoding used to
+/// binary encode register operands in instructions.
 enum GPRRegister {
 #define X(val, encode, name, scratch, preserved, stackptr, frameptr, isInt,    \
           isI64Pair, isFP32, isFP64, isVec128, alias_init)                     \
@@ -50,6 +50,18 @@
       Encoded_Not_GPR = -1
 };
 
+/// An enum of FPR Registers. The enum value does match the encoding used to
+/// binary encode register operands in instructions.
+enum FPRRegister {
+#define X(val, encode, name, scratch, preserved, stackptr, frameptr, isInt,    \
+          isI64Pair, isFP32, isFP64, isVec128, alias_init)                     \
+                                                                               \
+  Encoded_##val = encode,
+  REGMIPS32_FPR_TABLE
+#undef X
+      Encoded_Not_FPR = -1
+};
+
 // TODO(jvoung): Floating point and vector registers...
 // Need to model overlap and difference in encoding too.
 
@@ -59,6 +71,22 @@
   return GPRRegister(RegNum - Reg_GPR_First);
 }
 
+static inline bool isGPRReg(RegNumT RegNum) {
+  return (int(Reg_GPR_First) <= int(RegNum)) &&
+         (unsigned(RegNum) <= Reg_GPR_Last);
+}
+
+static inline FPRRegister getEncodedFPR(RegNumT RegNum) {
+  assert(int(Reg_FPR_First) <= int(RegNum));
+  assert(unsigned(RegNum) <= Reg_FPR_Last);
+  return FPRRegister(RegNum - Reg_FPR_First);
+}
+
+static inline bool isFPRReg(RegNumT RegNum) {
+  return (int(Reg_FPR_First) <= int(RegNum)) &&
+         (unsigned(RegNum) <= Reg_FPR_Last);
+}
+
 const char *getRegName(RegNumT RegNum);
 
 } // end of namespace RegMIPS32
diff --git a/src/IceTargetLoweringMIPS32.h b/src/IceTargetLoweringMIPS32.h
index d1908fa..aca82cd 100644
--- a/src/IceTargetLoweringMIPS32.h
+++ b/src/IceTargetLoweringMIPS32.h
@@ -177,6 +177,14 @@
     Context.insert<InstMIPS32Ret>(RA, Src0);
   }
 
+  void _add_d(Variable *Dest, Variable *Src0, Variable *Src1) {
+    Context.insert<InstMIPS32Add_d>(Dest, Src0, Src1);
+  }
+
+  void _add_s(Variable *Dest, Variable *Src0, Variable *Src1) {
+    Context.insert<InstMIPS32Add_s>(Dest, Src0, Src1);
+  }
+
   void _addiu(Variable *Dest, Variable *Src, uint32_t Imm) {
     Context.insert<InstMIPS32Addiu>(Dest, Src, Imm);
   }
@@ -185,6 +193,14 @@
     Context.insert<InstMIPS32Div>(Dest, Src0, Src1);
   }
 
+  void _div_d(Variable *Dest, Variable *Src0, Variable *Src1) {
+    Context.insert<InstMIPS32Div_d>(Dest, Src0, Src1);
+  }
+
+  void _div_s(Variable *Dest, Variable *Src0, Variable *Src1) {
+    Context.insert<InstMIPS32Div_s>(Dest, Src0, Src1);
+  }
+
   void _divu(Variable *Dest, Variable *Src0, Variable *Src1) {
     Context.insert<InstMIPS32Divu>(Dest, Src0, Src1);
   }
@@ -209,6 +225,18 @@
     }
   }
 
+  void _mov_d(Variable *Dest, Variable *Src) {
+    Context.insert<InstMIPS32Mov_d>(Dest, Src);
+  }
+
+  void _mov_s(Variable *Dest, Variable *Src) {
+    Context.insert<InstMIPS32Mov_s>(Dest, Src);
+  }
+
+  void _mfc1(Variable *Dest, Variable *Src) {
+    Context.insert<InstMIPS32Mfc1>(Dest, Src);
+  }
+
   void _mfhi(Variable *Dest, Operand *Src) {
     Context.insert<InstMIPS32Mfhi>(Dest, Src);
   }
@@ -217,6 +245,10 @@
     Context.insert<InstMIPS32Mflo>(Dest, Src);
   }
 
+  void _mtc1(Variable *Dest, Variable *Src) {
+    Context.insert<InstMIPS32Mtc1>(Dest, Src);
+  }
+
   void _mthi(Variable *Dest, Operand *Src) {
     Context.insert<InstMIPS32Mthi>(Dest, Src);
   }
@@ -229,6 +261,14 @@
     Context.insert<InstMIPS32Mul>(Dest, Src0, Src1);
   }
 
+  void _mul_d(Variable *Dest, Variable *Src0, Variable *Src1) {
+    Context.insert<InstMIPS32Mul_d>(Dest, Src0, Src1);
+  }
+
+  void _mul_s(Variable *Dest, Variable *Src0, Variable *Src1) {
+    Context.insert<InstMIPS32Mul_s>(Dest, Src0, Src1);
+  }
+
   void _mult(Variable *Dest, Variable *Src0, Variable *Src1) {
     Context.insert<InstMIPS32Mult>(Dest, Src0, Src1);
   }
@@ -289,6 +329,14 @@
     Context.insert<InstMIPS32Sub>(Dest, Src0, Src1);
   }
 
+  void _sub_d(Variable *Dest, Variable *Src0, Variable *Src1) {
+    Context.insert<InstMIPS32Sub_d>(Dest, Src0, Src1);
+  }
+
+  void _sub_s(Variable *Dest, Variable *Src0, Variable *Src1) {
+    Context.insert<InstMIPS32Sub_s>(Dest, Src0, Src1);
+  }
+
   void _subu(Variable *Dest, Variable *Src0, Variable *Src1) {
     Context.insert<InstMIPS32Subu>(Dest, Src0, Src1);
   }