implement the null function for the Mips32 subzero compiler

BUG= https://code.google.com/p/nativeclient/issues/detail?id=4167
R=jvoung@chromium.org

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

Patch from Reed Kotler <reed.kotler@imgtec.com>.
diff --git a/Makefile.standalone b/Makefile.standalone
index b4c33b7..83eddac 100644
--- a/Makefile.standalone
+++ b/Makefile.standalone
@@ -189,6 +189,7 @@
 	IceGlobalInits.cpp \
 	IceInst.cpp \
 	IceInstARM32.cpp \
+	IceInstMIPS32.cpp \
 	IceInstX8632.cpp \
 	IceIntrinsics.cpp \
 	IceLiveness.cpp \
diff --git a/pydir/run-pnacl-sz.py b/pydir/run-pnacl-sz.py
index 787910c..72b6a0b 100755
--- a/pydir/run-pnacl-sz.py
+++ b/pydir/run-pnacl-sz.py
@@ -15,14 +15,18 @@
   # TODO(stichnot): -triple=i686-nacl should be used for a
   # sandboxing test.  This means there should be an args.sandbox
   # argument that also gets passed through to pnacl-sz.
+  # TODO(reed kotler). Need to find out exactly we need to
+  # add here for Mips32.
   flags = { 'x8632': ['-triple=i686'],
-            'arm32': ['-triple=armv7a', '-mcpu=cortex-a9', '-mattr=+neon'] }
+            'arm32': ['-triple=armv7a', '-mcpu=cortex-a9', '-mattr=+neon'],
+            'mips32': ['-triple=mipsel-none-nacl' ] }
   return flags[target]
 
 
 def TargetDisassemblerFlags(target):
   flags = { 'x8632': ['-Mintel'],
-            'arm32': [] }
+            'arm32': [],
+            'mips32':[] }
   return flags[target]
 
 
@@ -73,7 +77,7 @@
                            choices=['obj', 'asm', 'iasm'],
                            help='Output file type.  Default %(default)s.')
     argparser.add_argument('--target', default='x8632', dest='target',
-                           choices=['x8632','arm32'],
+                           choices=['x8632','arm32','mips32'],
                            help='Target architecture.  Default %(default)s.')
     argparser.add_argument('--echo-cmd', required=False,
                            action='store_true',
diff --git a/src/IceAssemblerMIPS32.h b/src/IceAssemblerMIPS32.h
index b088d56..06b1487 100644
--- a/src/IceAssemblerMIPS32.h
+++ b/src/IceAssemblerMIPS32.h
@@ -49,10 +49,12 @@
 
   SizeT getBundleAlignLog2Bytes() const override { return 4; }
 
-  const char *getNonExecPadDirective() const override { return ".TBD"; }
+  const char *getNonExecPadDirective() const override { return ".p2alignl"; }
 
   llvm::ArrayRef<uint8_t> getNonExecBundlePadding() const override {
-    llvm::report_fatal_error("Not yet implemented.");
+    // TODO(reed kotler) . Find out what this should be.
+    static const uint8_t Padding[] = {0xE7, 0xFE, 0xDE, 0xF0};
+    return llvm::ArrayRef<uint8_t>(Padding, 4);
   }
 
   void padWithNop(intptr_t Padding) override {
diff --git a/src/IceInstMIPS32.cpp b/src/IceInstMIPS32.cpp
new file mode 100644
index 0000000..af6aaf1
--- /dev/null
+++ b/src/IceInstMIPS32.cpp
@@ -0,0 +1,62 @@
+//===- subzero/src/IceInstMips32.cpp - Mips32 instruction implementation --===//
+//
+//                        The Subzero Code Generator
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+/// This file implements the InstMips32 and OperandMips32 classes,
+/// primarily the constructors and the dump()/emit() methods.
+///
+//===----------------------------------------------------------------------===//
+
+#include "IceAssemblerMIPS32.h"
+#include "IceCfg.h"
+#include "IceCfgNode.h"
+#include "IceInst.h"
+#include "IceInstMIPS32.h"
+#include "IceOperand.h"
+#include "IceRegistersMIPS32.h"
+#include "IceTargetLoweringMIPS32.h"
+
+namespace Ice {
+
+
+InstMIPS32Ret::InstMIPS32Ret(Cfg *Func, Variable *RA, Variable *Source)
+    : InstMIPS32(Func, InstMIPS32::Ret, Source ? 2 : 1, nullptr) {
+  addSource(RA);
+  if (Source)
+    addSource(Source);
+}
+
+void InstMIPS32Ret::emit(const Cfg *Func) const {
+  if (!ALLOW_DUMP)
+    return;
+  assert(getSrcSize() > 0);
+  Variable *RA = llvm::cast<Variable>(getSrc(0));
+  assert(RA->hasReg());
+  assert(RA->getRegNum() == RegMIPS32::Reg_RA);
+  Ostream &Str = Func->getContext()->getStrEmit();
+  Str << "\t"
+      << "jr $ra"
+      << "\t";
+  RA->emit(Func);
+}
+
+void InstMIPS32Ret::emitIAS(const Cfg *Func) const {
+  (void)Func;
+  llvm_unreachable("Not yet implemented");
+}
+
+void InstMIPS32Ret::dump(const Cfg *Func) const {
+  if (!ALLOW_DUMP)
+    return;
+  Ostream &Str = Func->getContext()->getStrDump();
+  Type Ty = (getSrcSize() == 1 ? IceType_void : getSrc(0)->getType());
+  Str << "ret." << Ty << " ";
+  dumpSources(Func);
+}
+}
diff --git a/src/IceInstMIPS32.def b/src/IceInstMIPS32.def
index 3b6f387..351ecce 100644
--- a/src/IceInstMIPS32.def
+++ b/src/IceInstMIPS32.def
@@ -15,7 +15,7 @@
 #define SUBZERO_SRC_ICEINSTMIPS32_DEF
 
 // NOTE: PC and SP are not considered isInt, to avoid register allocating.
-// TODO (reed kotler). This needs to be scrubbed and is a placeholder to get
+// TODO(reed kotler). This needs to be scrubbed and is a placeholder to get
 // the Mips skeleton in.
 //
 #define REGMIPS32_GPR_TABLE                                                    \
diff --git a/src/IceInstMIPS32.h b/src/IceInstMIPS32.h
index 17c2583..d608a1c 100644
--- a/src/IceInstMIPS32.h
+++ b/src/IceInstMIPS32.h
@@ -18,11 +18,64 @@
 #define SUBZERO_SRC_ICEINSTMIPS32_H
 
 #include "IceDefs.h"
+#include "IceInst.h"
+#include "IceInstMIPS32.def"
+#include "IceOperand.h"
 
 namespace Ice {
 
 class TargetMIPS32;
-// Fill this in.
+
+/// Base class for Mips instructions.
+class InstMIPS32 : public InstTarget {
+  InstMIPS32() = delete;
+  InstMIPS32(const InstMIPS32 &) = delete;
+  InstMIPS32 &operator=(const InstMIPS32 &) = delete;
+
+public:
+  enum InstKindMIPS32 { k__Start = Inst::Target, Ret };
+
+  static const char *getWidthString(Type Ty);
+
+  void dump(const Cfg *Func) const override;
+
+protected:
+  InstMIPS32(Cfg *Func, InstKindMIPS32 Kind, SizeT Maxsrcs, Variable *Dest)
+      : InstTarget(Func, static_cast<InstKind>(Kind), Maxsrcs, Dest) {}
+  ~InstMIPS32() override {}
+  static bool isClassof(const Inst *Inst, InstKindMIPS32 MyKind) {
+    return Inst->getKind() == static_cast<InstKind>(MyKind);
+  }
+};
+
+/// Ret pseudo-instruction.  This is actually a "jr" instruction with
+/// an "ra" register operand, but epilogue lowering will search for a Ret
+/// instead of a generic "jr". This instruction also takes a Source
+/// operand (for non-void returning functions) for liveness analysis, though
+/// a FakeUse before the ret would do just as well.
+/// TODO(reed kotler): This needs was take from the ARM port and needs to be
+/// scrubbed in the future.
+class InstMIPS32Ret : public InstMIPS32 {
+
+  InstMIPS32Ret() = delete;
+  InstMIPS32Ret(const InstMIPS32Ret &) = delete;
+  InstMIPS32Ret &operator=(const InstMIPS32Ret &) = delete;
+
+public:
+  static InstMIPS32Ret *create(Cfg *Func, Variable *RA,
+                               Variable *Source = nullptr) {
+    return new (Func->allocate<InstMIPS32Ret>())
+        InstMIPS32Ret(Func, RA, Source);
+  }
+  void emit(const Cfg *Func) const override;
+  void emitIAS(const Cfg *Func) const override;
+  void dump(const Cfg *Func) const override;
+  static bool classof(const Inst *Inst) { return isClassof(Inst, Ret); }
+
+private:
+  InstMIPS32Ret(Cfg *Func, Variable *RA, Variable *Source);
+  ~InstMIPS32Ret() override {}
+};
 
 } // end of namespace Ice
 
diff --git a/src/IceTargetLoweringMIPS32.cpp b/src/IceTargetLoweringMIPS32.cpp
index 6c0793f..a7e85a8 100644
--- a/src/IceTargetLoweringMIPS32.cpp
+++ b/src/IceTargetLoweringMIPS32.cpp
@@ -31,6 +31,17 @@
 
 namespace Ice {
 
+namespace {
+void UnimplementedError(const ClFlags &Flags) {
+  if (!Flags.getSkipUnimplemented()) {
+    // Use llvm_unreachable instead of report_fatal_error, which gives better
+    // stack traces.
+    llvm_unreachable("Not yet implemented");
+    abort();
+  }
+}
+} // end of anonymous namespace
+
 TargetMIPS32::TargetMIPS32(Cfg *Func) : TargetLowering(Func) {
   // TODO: Don't initialize IntegerRegisters and friends every time.
   // Instead, initialize in some sort of static initializer for the
@@ -205,7 +216,8 @@
 bool TargetMIPS32::doBranchOpt(Inst *I, const CfgNode *NextNode) {
   (void)I;
   (void)NextNode;
-  llvm::report_fatal_error("Not yet implemented");
+  UnimplementedError(Func->getContext()->getFlags());
+  return false;
 }
 
 IceString TargetMIPS32::RegNames[] = {
@@ -247,23 +259,25 @@
   Ostream &Str = Ctx->getStrEmit();
   (void)Var;
   (void)Str;
-  llvm::report_fatal_error("emitVariable: Not yet implemented");
+  UnimplementedError(Func->getContext()->getFlags());
 }
 
 void TargetMIPS32::lowerArguments() {
-  llvm::report_fatal_error("lowerArguments: Not yet implemented");
+  VarList &Args = Func->getArgs();
+  if (Args.size() > 0)
+    UnimplementedError(Func->getContext()->getFlags());
 }
 
 Type TargetMIPS32::stackSlotType() { return IceType_i32; }
 
 void TargetMIPS32::addProlog(CfgNode *Node) {
   (void)Node;
-  llvm::report_fatal_error("addProlog: Not yet implemented");
+  UnimplementedError(Func->getContext()->getFlags());
 }
 
 void TargetMIPS32::addEpilog(CfgNode *Node) {
   (void)Node;
-  llvm::report_fatal_error("addEpilog: Not yet implemented");
+  UnimplementedError(Func->getContext()->getFlags());
 }
 
 llvm::SmallBitVector TargetMIPS32::getRegisterSet(RegSetMask Include,
@@ -305,84 +319,84 @@
   // restriction can be relaxed in some cases.
   NeedsStackAlignment = true;
   (void)Inst;
-  llvm::report_fatal_error("Not yet implemented");
+  UnimplementedError(Func->getContext()->getFlags());
 }
 
 void TargetMIPS32::lowerArithmetic(const InstArithmetic *Inst) {
   switch (Inst->getOp()) {
   case InstArithmetic::_num:
-    llvm_unreachable("Unknown arithmetic operator");
+    UnimplementedError(Func->getContext()->getFlags());
     break;
   case InstArithmetic::Add:
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     break;
   case InstArithmetic::And:
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     break;
   case InstArithmetic::Or:
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     break;
   case InstArithmetic::Xor:
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     break;
   case InstArithmetic::Sub:
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     break;
   case InstArithmetic::Mul:
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     break;
   case InstArithmetic::Shl:
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     break;
   case InstArithmetic::Lshr:
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     break;
   case InstArithmetic::Ashr:
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     break;
   case InstArithmetic::Udiv:
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     break;
   case InstArithmetic::Sdiv:
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     break;
   case InstArithmetic::Urem:
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     break;
   case InstArithmetic::Srem:
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     break;
   case InstArithmetic::Fadd:
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     break;
   case InstArithmetic::Fsub:
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     break;
   case InstArithmetic::Fmul:
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     break;
   case InstArithmetic::Fdiv:
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     break;
   case InstArithmetic::Frem:
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     break;
   }
 }
 
 void TargetMIPS32::lowerAssign(const InstAssign *Inst) {
   (void)Inst;
-  llvm::report_fatal_error("Not yet implemented");
+  UnimplementedError(Func->getContext()->getFlags());
 }
 
 void TargetMIPS32::lowerBr(const InstBr *Inst) {
   (void)Inst;
-  llvm::report_fatal_error("Not yet implemented");
+  UnimplementedError(Func->getContext()->getFlags());
 }
 
 void TargetMIPS32::lowerCall(const InstCall *Inst) {
   (void)Inst;
-  llvm::report_fatal_error("Not yet implemented");
+  UnimplementedError(Func->getContext()->getFlags());
 }
 
 void TargetMIPS32::lowerCast(const InstCast *Inst) {
@@ -392,39 +406,39 @@
     Func->setError("Cast type not supported");
     return;
   case InstCast::Sext: {
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     break;
   }
   case InstCast::Zext: {
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     break;
   }
   case InstCast::Trunc: {
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     break;
   }
   case InstCast::Fptrunc:
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     break;
   case InstCast::Fpext: {
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     break;
   }
   case InstCast::Fptosi:
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     break;
   case InstCast::Fptoui:
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     break;
   case InstCast::Sitofp:
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     break;
   case InstCast::Uitofp: {
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     break;
   }
   case InstCast::Bitcast: {
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     break;
   }
   }
@@ -432,72 +446,72 @@
 
 void TargetMIPS32::lowerExtractElement(const InstExtractElement *Inst) {
   (void)Inst;
-  llvm::report_fatal_error("Not yet implemented");
+  UnimplementedError(Func->getContext()->getFlags());
 }
 
 void TargetMIPS32::lowerFcmp(const InstFcmp *Inst) {
   (void)Inst;
-  llvm::report_fatal_error("Not yet implemented");
+  UnimplementedError(Func->getContext()->getFlags());
 }
 
 void TargetMIPS32::lowerIcmp(const InstIcmp *Inst) {
   (void)Inst;
-  llvm::report_fatal_error("Not yet implemented");
+  UnimplementedError(Func->getContext()->getFlags());
 }
 
 void TargetMIPS32::lowerInsertElement(const InstInsertElement *Inst) {
   (void)Inst;
-  llvm::report_fatal_error("Not yet implemented");
+  UnimplementedError(Func->getContext()->getFlags());
 }
 
 void TargetMIPS32::lowerIntrinsicCall(const InstIntrinsicCall *Instr) {
   switch (Intrinsics::IntrinsicID ID = Instr->getIntrinsicInfo().ID) {
   case Intrinsics::AtomicCmpxchg: {
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     return;
   }
   case Intrinsics::AtomicFence:
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     return;
   case Intrinsics::AtomicFenceAll:
     // NOTE: FenceAll should prevent and load/store from being moved
     // across the fence (both atomic and non-atomic). The InstMIPS32Mfence
     // instruction is currently marked coarsely as "HasSideEffects".
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     return;
   case Intrinsics::AtomicIsLockFree: {
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     return;
   }
   case Intrinsics::AtomicLoad: {
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     return;
   }
   case Intrinsics::AtomicRMW:
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     return;
   case Intrinsics::AtomicStore: {
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     return;
   }
   case Intrinsics::Bswap: {
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     return;
   }
   case Intrinsics::Ctpop: {
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     return;
   }
   case Intrinsics::Ctlz: {
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     return;
   }
   case Intrinsics::Cttz: {
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     return;
   }
   case Intrinsics::Fabs: {
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     return;
   }
   case Intrinsics::Longjmp: {
@@ -542,7 +556,7 @@
   }
   case Intrinsics::NaClReadTP: {
     if (Ctx->getFlags().getUseSandboxing()) {
-      llvm::report_fatal_error("Not yet implemented");
+      UnimplementedError(Func->getContext()->getFlags());
     } else {
       InstCall *Call = makeHelperCall(H_call_read_tp, Instr->getDest(), 0);
       lowerCall(Call);
@@ -556,19 +570,19 @@
     return;
   }
   case Intrinsics::Sqrt: {
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     return;
   }
   case Intrinsics::Stacksave: {
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     return;
   }
   case Intrinsics::Stackrestore: {
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     return;
   }
   case Intrinsics::Trap:
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
     return;
   case Intrinsics::UnknownIntrinsic:
     Func->setError("Should not be lowering UnknownIntrinsic");
@@ -579,17 +593,17 @@
 
 void TargetMIPS32::lowerLoad(const InstLoad *Inst) {
   (void)Inst;
-  llvm::report_fatal_error("Not yet implemented");
+  UnimplementedError(Func->getContext()->getFlags());
 }
 
 void TargetMIPS32::doAddressOptLoad() {
-  llvm::report_fatal_error("Not yet implemented");
+  UnimplementedError(Func->getContext()->getFlags());
 }
 
 void TargetMIPS32::randomlyInsertNop(float Probability) {
   RandomNumberGeneratorWrapper RNG(Ctx->getRNG());
   if (RNG.getTrueWithProbability(Probability)) {
-    llvm::report_fatal_error("Not yet implemented");
+    UnimplementedError(Func->getContext()->getFlags());
   }
 }
 
@@ -598,31 +612,33 @@
 }
 
 void TargetMIPS32::lowerRet(const InstRet *Inst) {
-  (void)Inst;
-  llvm::report_fatal_error("Not yet implemented");
+  Variable *Reg = nullptr;
+  if (Inst->hasRetValue())
+    UnimplementedError(Func->getContext()->getFlags());
+  _ret(getPhysicalRegister(RegMIPS32::Reg_RA), Reg);
 }
 
 void TargetMIPS32::lowerSelect(const InstSelect *Inst) {
   (void)Inst;
-  llvm::report_fatal_error("Not yet implemented");
+  UnimplementedError(Func->getContext()->getFlags());
 }
 
 void TargetMIPS32::lowerStore(const InstStore *Inst) {
   (void)Inst;
-  llvm::report_fatal_error("Not yet implemented");
+  UnimplementedError(Func->getContext()->getFlags());
 }
 
 void TargetMIPS32::doAddressOptStore() {
-  llvm::report_fatal_error("Not yet implemented");
+  UnimplementedError(Func->getContext()->getFlags());
 }
 
 void TargetMIPS32::lowerSwitch(const InstSwitch *Inst) {
   (void)Inst;
-  llvm::report_fatal_error("Not yet implemented");
+  UnimplementedError(Func->getContext()->getFlags());
 }
 
 void TargetMIPS32::lowerUnreachable(const InstUnreachable * /*Inst*/) {
-  llvm_unreachable("Not yet implemented");
+  UnimplementedError(Func->getContext()->getFlags());
 }
 
 // Turn an i64 Phi instruction into a pair of i32 Phi instructions, to
@@ -630,7 +646,7 @@
 // turned into zeroes, since loOperand() and hiOperand() don't expect
 // Undef input.
 void TargetMIPS32::prelowerPhis() {
-  llvm::report_fatal_error("Not yet implemented");
+  UnimplementedError(Func->getContext()->getFlags());
 }
 
 // Lower the pre-ordered list of assignments into mov instructions.
@@ -639,7 +655,7 @@
                                        const AssignList &Assignments) {
   (void)Node;
   (void)Assignments;
-  llvm::report_fatal_error("Not yet implemented");
+  UnimplementedError(Func->getContext()->getFlags());
 }
 
 void TargetMIPS32::postLower() {
@@ -647,7 +663,7 @@
     return;
   // Find two-address non-SSA instructions where Dest==Src0, and set
   // the DestNonKillable flag to keep liveness analysis consistent.
-  llvm::report_fatal_error("Not yet implemented");
+  UnimplementedError(Func->getContext()->getFlags());
 }
 
 void TargetMIPS32::makeRandomRegisterPermutation(
@@ -655,7 +671,7 @@
     const llvm::SmallBitVector &ExcludeRegisters) const {
   (void)Permutation;
   (void)ExcludeRegisters;
-  llvm::report_fatal_error("Not yet implemented");
+  UnimplementedError(Func->getContext()->getFlags());
 }
 
 /* TODO(jvoung): avoid duplicate symbols with multiple targets.
@@ -694,7 +710,7 @@
 void TargetDataMIPS32::lowerConstants() {
   if (Ctx->getFlags().getDisableTranslation())
     return;
-  llvm::report_fatal_error("Not yet implemented");
+  UnimplementedError(Ctx->getFlags());
 }
 
 TargetHeaderMIPS32::TargetHeaderMIPS32(GlobalContext *Ctx)
diff --git a/src/IceTargetLoweringMIPS32.h b/src/IceTargetLoweringMIPS32.h
index f872af0..a72c8db 100644
--- a/src/IceTargetLoweringMIPS32.h
+++ b/src/IceTargetLoweringMIPS32.h
@@ -76,6 +76,9 @@
     (void)C;
     llvm::report_fatal_error("Not yet implemented");
   }
+  void _ret(Variable *RA, Variable *Src0 = nullptr) {
+    Context.insert(InstMIPS32Ret::create(Func, RA, Src0));
+  }
 
   void lowerArguments() override;
   void addProlog(CfgNode *Node) override;
diff --git a/tests_lit/llvm2ice_tests/function_aligned.ll b/tests_lit/llvm2ice_tests/function_aligned.ll
index 23d2ca7..03da464 100644
--- a/tests_lit/llvm2ice_tests/function_aligned.ll
+++ b/tests_lit/llvm2ice_tests/function_aligned.ll
@@ -13,6 +13,11 @@
 ; RUN:   --disassemble --target arm32 -i %s --args -O2 --skip-unimplemented \
 ; RUN:   | %if --need=target_ARM32 --need=allow_dump \
 ; RUN:   --command FileCheck --check-prefix ARM32 %s
+; RUN: %if --need=target_MIPS32 --need=allow_dump \
+; RUN:   --command %p2i --filetype=asm --assemble \
+; RUN:   --disassemble --target mips32 -i %s --args -O2 --skip-unimplemented \
+; RUN:   | %if --need=target_MIPS32 --need=allow_dump \
+; RUN:   --command FileCheck --check-prefix MIPS32 %s
 
 define void @foo() {
   ret void
@@ -25,6 +30,10 @@
 ; ARM32-NEXT: 4: e7fedef0 udf
 ; ARM32-NEXT: 8: e7fedef0 udf
 ; ARM32-NEXT: c: e7fedef0 udf
+; MIPS32-LABEL: foo
+; MIPS32: 4: {{.*}} jr ra
+; MIPS32-NEXT: 8: {{.*}} nop
+; MIPS32-NEXT: c: e7fedef0
 
 define void @bar() {
   ret void
@@ -33,3 +42,6 @@
 ; CHECK-NEXT: 20: {{.*}} ret
 ; ARM32-LABEL: bar
 ; ARM32-NEXT: 10: {{.*}} bx lr
+; MIPS32-LABEL: bar
+; MIPS32: 14: {{.*}} jr ra
+; MIPS32-NEXT: 18: {{.*}} nop