Start incorporating the ARM integrated assembler.

Extends the ARM32 assembler to be able to generate a trivial function
footprint using the -filetype=iasm option.

Also does a couple of cleanups:

1) Move UnimplementedError macro to common location so that it can be
used by everyone.

2) Add a GlobalContext argument to the assembler, so that it can
look at flags etc.

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

Review URL: https://codereview.chromium.org/1397933002 .
diff --git a/src/DartARM32/assembler_arm.cc b/src/DartARM32/assembler_arm.cc
index 5c0a90e..fee25dc 100644
--- a/src/DartARM32/assembler_arm.cc
+++ b/src/DartARM32/assembler_arm.cc
@@ -1433,9 +1433,12 @@
 }
 
 
+#if 0
+// Moved to: ARM32::AssemblerARM32.
 void Assembler::bkpt(uint16_t imm16) {
   Emit(BkptEncoding(imm16));
 }
+#endif
 
 
 void Assembler::b(Label* label, Condition cond) {
@@ -1447,7 +1450,8 @@
   EmitBranch(cond, label, true);
 }
 
-
+#if 0
+// Moved to: ARM32::AssemblerARM32.
 void Assembler::bx(Register rm, Condition cond) {
   ASSERT(rm != kNoRegister);
   ASSERT(cond != kNoCondition);
@@ -1456,6 +1460,7 @@
                      (static_cast<int32_t>(rm) << kRmShift);
   Emit(encoding);
 }
+#endif
 
 
 void Assembler::blx(Register rm, Condition cond) {
@@ -2314,7 +2319,10 @@
   label->BindTo(bound_pc);
 }
 
-
+#if 0
+// Moved to: ARM32::AssemblerARM32 as method bind(Label* Label)
+// Note: Most of this code isn't needed because instruction selection has
+// already been handler
 void Assembler::BindARMv7(Label* label) {
   ASSERT(!label->IsBound());
   intptr_t bound_pc = buffer_.Size();
@@ -2381,6 +2389,7 @@
   }
   label->BindTo(bound_pc);
 }
+#endif
 
 
 void Assembler::Bind(Label* label) {
diff --git a/src/DartARM32/assembler_arm.h b/src/DartARM32/assembler_arm.h
index c686d60..7893d6f 100644
--- a/src/DartARM32/assembler_arm.h
+++ b/src/DartARM32/assembler_arm.h
@@ -27,7 +27,8 @@
 class RuntimeEntry;
 class StubEntry;
 
-
+#if 0
+// Moved to: ARM32::AssemblerARM32.
 // Instruction encoding bits.
 enum {
   H   = 1 << 5,   // halfword (or byte)
@@ -68,7 +69,7 @@
   B26 = 1 << 26,
   B27 = 1 << 27,
 };
-
+#endif
 
 class Label : public ValueObject {
  public:
@@ -532,6 +533,8 @@
   void clrex();
   void nop(Condition cond = AL);
 
+#if 0
+  // Moved to: ARM32::AssemblerARM32.
   // Note that gdb sets breakpoints using the undefined instruction 0xe7f001f0.
   void bkpt(uint16_t imm16);
 
@@ -540,6 +543,7 @@
     return (AL << kConditionShift) | B24 | B21 |
            ((imm16 >> 4) << 8) | B6 | B5 | B4 | (imm16 & 0xf);
   }
+#endif
 
   static uword GetBreakInstructionFiller() {
     return BkptEncoding(0);
@@ -660,7 +664,10 @@
   // Branch instructions.
   void b(Label* label, Condition cond = AL);
   void bl(Label* label, Condition cond = AL);
+#if 0
+  // Moved to: ARM32::AssemblerARM32.
   void bx(Register rm, Condition cond = AL);
+#endif
   void blx(Register rm, Condition cond = AL);
 
   void Branch(const StubEntry& stub_entry,
diff --git a/src/IceAssembler.cpp b/src/IceAssembler.cpp
index 9c77dce..7eb8b61 100644
--- a/src/IceAssembler.cpp
+++ b/src/IceAssembler.cpp
@@ -119,7 +119,7 @@
                          Buffer.size());
 }
 
-void Assembler::emitIASBytes(GlobalContext *Ctx) const {
+void Assembler::emitIASBytes() const {
   Ostream &Str = Ctx->getStrEmit();
   intptr_t EndPosition = Buffer.size();
   intptr_t CurPosition = 0;
diff --git a/src/IceAssembler.h b/src/IceAssembler.h
index 8247e66..2f5a505 100644
--- a/src/IceAssembler.h
+++ b/src/IceAssembler.h
@@ -64,17 +64,20 @@
     return Position - kWordSize;
   }
 
+  void setPosition(intptr_t NewValue) { Position = NewValue; }
+
   bool isBound() const { return Position < 0; }
   bool isLinked() const { return Position > 0; }
+
   virtual bool isUnused() const { return Position == 0; }
 
-protected:
   void bindTo(intptr_t position) {
     assert(!isBound());
     Position = -position - kWordSize;
     assert(isBound());
   }
 
+protected:
   void linkTo(intptr_t position) {
     assert(!isBound());
     Position = position + kWordSize;
@@ -83,7 +86,6 @@
 
   intptr_t Position = 0;
 
-private:
   // TODO(jvoung): why are labels offset by this?
   static constexpr uint32_t kWordSize = sizeof(uint32_t);
 };
@@ -272,7 +274,7 @@
     return Buffer.createFixup(Kind, Value);
   }
 
-  void emitIASBytes(GlobalContext *Ctx) const;
+  void emitIASBytes() const;
   bool getInternal() const { return IsInternal; }
   void setInternal(bool Internal) { IsInternal = Internal; }
   const IceString &getFunctionName() { return FunctionName; }
@@ -286,8 +288,8 @@
   AssemblerKind getKind() const { return Kind; }
 
 protected:
-  explicit Assembler(AssemblerKind Kind)
-      : Kind(Kind), Allocator(), Buffer(*this) {}
+  explicit Assembler(AssemblerKind Kind, GlobalContext *Ctx)
+      : Kind(Kind), Allocator(), Ctx(Ctx), Buffer(*this) {}
 
 private:
   const AssemblerKind Kind;
@@ -305,6 +307,7 @@
   bool Preliminary = false;
 
 protected:
+  GlobalContext *Ctx;
   // Buffer's constructor uses the Allocator, so it needs to appear after it.
   // TODO(jpp): dependencies on construction order are a nice way of shooting
   // yourself in the foot. Fix this.
diff --git a/src/IceAssemblerARM32.cpp b/src/IceAssemblerARM32.cpp
new file mode 100644
index 0000000..ab22450
--- /dev/null
+++ b/src/IceAssemblerARM32.cpp
@@ -0,0 +1,75 @@
+//===- subzero/src/IceAssemblerARM32.cpp - Assembler for ARM32 --*- C++ -*-===//
+//
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// Modified by the Subzero authors.
+//
+//===----------------------------------------------------------------------===//
+//
+//                        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 Assembler class for ARM32.
+///
+//===----------------------------------------------------------------------===//
+
+#include "IceAssemblerARM32.h"
+
+namespace Ice {
+
+Label *ARM32::AssemblerARM32::getOrCreateLabel(SizeT Number,
+                                               LabelVector &Labels) {
+  Label *L = nullptr;
+  if (Number == Labels.size()) {
+    L = new (this->allocate<Label>()) Label();
+    Labels.push_back(L);
+    return L;
+  }
+  if (Number > Labels.size()) {
+    Labels.resize(Number + 1);
+  }
+  L = Labels[Number];
+  if (!L) {
+    L = new (this->allocate<Label>()) Label();
+    Labels[Number] = L;
+  }
+  return L;
+}
+
+void ARM32::AssemblerARM32::bind(Label *label) {
+  intptr_t bound = Buffer.size();
+  assert(!label->isBound()); // Labels can only be bound once.
+  while (label->isLinked()) {
+    intptr_t position = label->getLinkPosition();
+    intptr_t next = Buffer.load<int32_t>(position);
+    Buffer.store<int32_t>(position, bound - (position + 4));
+    label->setPosition(next);
+  }
+  // TODO(kschimpf) Decide if we have near jumps.
+  label->bindTo(bound);
+}
+
+void ARM32::AssemblerARM32::bkpt(uint16_t imm16) {
+  AssemblerBuffer::EnsureCapacity ensured(&Buffer);
+  emitInt32(BkptEncoding(imm16));
+}
+
+void ARM32::AssemblerARM32::bx(RegARM32::GPRRegister rm, CondARM32::Cond cond) {
+  // cccc000100101111111111110001mmmm where mmmm=rm and cccc=Cond.
+  assert(rm != RegARM32::Encoded_Not_GPR);
+  assert(cond != CondARM32::kNone);
+  AssemblerBuffer::EnsureCapacity ensured(&Buffer);
+  int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | B24 |
+                     B21 | (0xfff << 8) | B4 |
+                     (static_cast<int32_t>(rm) << kRmShift);
+  emitInt32(encoding);
+}
+
+} // end of namespace Ice
diff --git a/src/IceAssemblerARM32.h b/src/IceAssemblerARM32.h
index 2a42826..2b6bbb1 100644
--- a/src/IceAssemblerARM32.h
+++ b/src/IceAssemblerARM32.h
@@ -24,8 +24,11 @@
 #define SUBZERO_SRC_ICEASSEMBLERARM32_H
 
 #include "IceAssembler.h"
+#include "IceConditionCodesARM32.h"
 #include "IceDefs.h"
 #include "IceFixups.h"
+#include "IceRegistersARM32.h"
+#include "IceTargetLowering.h"
 
 namespace Ice {
 namespace ARM32 {
@@ -35,15 +38,24 @@
   AssemblerARM32 &operator=(const AssemblerARM32 &) = delete;
 
 public:
-  explicit AssemblerARM32(bool use_far_branches = false)
-      : Assembler(Asm_ARM32) {
-    // This mode is only needed and implemented for MIPS and ARM.
-    assert(!use_far_branches);
+  explicit AssemblerARM32(GlobalContext *Ctx, bool use_far_branches = false)
+      : Assembler(Asm_ARM32, Ctx) {
+    // TODO(kschimpf): Add mode if needed when branches are handled.
     (void)use_far_branches;
   }
   ~AssemblerARM32() override = default;
 
-  void alignFunction() override { llvm_unreachable("Not yet implemented."); }
+  void alignFunction() override {
+    const SizeT Align = 1 << getBundleAlignLog2Bytes();
+    SizeT BytesNeeded = Utils::OffsetToAlignment(Buffer.getPosition(), Align);
+    constexpr SizeT InstSize = sizeof(int32_t);
+    assert(BytesNeeded % InstSize == 0);
+    while (BytesNeeded > 0) {
+      // TODO(kschimpf) Should this be NOP or some other instruction?
+      bkpt(0);
+      BytesNeeded -= InstSize;
+    }
+  }
 
   SizeT getBundleAlignLog2Bytes() const override { return 4; }
 
@@ -67,18 +79,173 @@
   }
 
   void bindCfgNodeLabel(SizeT NodeNumber) override {
-    (void)NodeNumber;
-    llvm_unreachable("Not yet implemented.");
+    assert(!getPreliminary());
+    Label *L = getOrCreateCfgNodeLabel(NodeNumber);
+    this->bind(L);
   }
 
   bool fixupIsPCRel(FixupKind Kind) const override {
     (void)Kind;
     llvm_unreachable("Not yet implemented.");
   }
+  void bind(Label *label);
+
+  void bkpt(uint16_t imm16);
+
+  void bx(RegARM32::GPRRegister rm, CondARM32::Cond cond = CondARM32::AL);
 
   static bool classof(const Assembler *Asm) {
     return Asm->getKind() == Asm_ARM32;
   }
+
+private:
+  // Instruction encoding bits.
+
+  // halfword (or byte)
+  static constexpr uint32_t H = 1 << 5;
+  // load (or store)
+  static constexpr uint32_t L = 1 << 20;
+  // set condition code (or leave unchanged)
+  static constexpr uint32_t S = 1 << 20;
+  // writeback base register (or leave unchanged)
+  static constexpr uint32_t W = 1 << 21;
+  // accumulate in multiply instruction (or not)
+  static constexpr uint32_t A = 1 << 21;
+  // unsigned byte (or word)
+  static constexpr uint32_t B = 1 << 22;
+  // high/lo bit of start of s/d register range
+  static constexpr uint32_t D = 1 << 22;
+  // long (or short)
+  static constexpr uint32_t N = 1 << 22;
+  // positive (or negative) offset/index
+  static constexpr uint32_t U = 1 << 23;
+  // offset/pre-indexed addressing (or post-indexed addressing)
+  static constexpr uint32_t P = 1 << 24;
+  // immediate shifter operand (or not)
+  static constexpr uint32_t I = 1 << 25;
+
+  // The following define individual bits.
+  static constexpr uint32_t B0 = 1;
+  static constexpr uint32_t B1 = 1 << 1;
+  static constexpr uint32_t B2 = 1 << 2;
+  static constexpr uint32_t B3 = 1 << 3;
+  static constexpr uint32_t B4 = 1 << 4;
+  static constexpr uint32_t B5 = 1 << 5;
+  static constexpr uint32_t B6 = 1 << 6;
+  static constexpr uint32_t B7 = 1 << 7;
+  static constexpr uint32_t B8 = 1 << 8;
+  static constexpr uint32_t B9 = 1 << 9;
+  static constexpr uint32_t B10 = 1 << 10;
+  static constexpr uint32_t B11 = 1 << 11;
+  static constexpr uint32_t B12 = 1 << 12;
+  static constexpr uint32_t B16 = 1 << 16;
+  static constexpr uint32_t B17 = 1 << 17;
+  static constexpr uint32_t B18 = 1 << 18;
+  static constexpr uint32_t B19 = 1 << 19;
+  static constexpr uint32_t B20 = 1 << 20;
+  static constexpr uint32_t B21 = 1 << 21;
+  static constexpr uint32_t B22 = 1 << 22;
+  static constexpr uint32_t B23 = 1 << 23;
+  static constexpr uint32_t B24 = 1 << 24;
+  static constexpr uint32_t B25 = 1 << 25;
+  static constexpr uint32_t B26 = 1 << 26;
+  static constexpr uint32_t B27 = 1 << 27;
+
+  // Constants used for the decoding or encoding of the individual fields of
+  // instructions. Based on section A5.1 from the "ARM Architecture Reference
+  // Manual, ARMv7-A and ARMv7-R edition". See:
+  // http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0406c
+  static constexpr uint32_t kConditionShift = 28;
+  static constexpr uint32_t kConditionBits = 4;
+  static constexpr uint32_t kTypeShift = 25;
+  static constexpr uint32_t kTypeBits = 3;
+  static constexpr uint32_t kLinkShift = 24;
+  static constexpr uint32_t kLinkBits = 1;
+  static constexpr uint32_t kUShift = 23;
+  static constexpr uint32_t kUBits = 1;
+  static constexpr uint32_t kOpcodeShift = 21;
+  static constexpr uint32_t kOpcodeBits = 4;
+  static constexpr uint32_t kSShift = 20;
+  static constexpr uint32_t kSBits = 1;
+  static constexpr uint32_t kRnShift = 16;
+  static constexpr uint32_t kRnBits = 4;
+  static constexpr uint32_t kRdShift = 12;
+  static constexpr uint32_t kRdBits = 4;
+  static constexpr uint32_t kRsShift = 8;
+  static constexpr uint32_t kRsBits = 4;
+  static constexpr uint32_t kRmShift = 0;
+  static constexpr uint32_t kRmBits = 4;
+
+  // Immediate instruction fields encoding.
+  static constexpr uint32_t kRotateShift = 8;
+  static constexpr uint32_t kRotateBits = 4;
+  static constexpr uint32_t kImmed8Shift = 0;
+  static constexpr uint32_t kImmed8Bits = 8;
+
+  // Shift instruction register fields encodings.
+  static constexpr uint32_t kShiftImmShift = 7;
+  static constexpr uint32_t kShiftRegisterShift = 8;
+  static constexpr uint32_t kShiftImmBits = 5;
+  static constexpr uint32_t kShiftShift = 5;
+  static constexpr uint32_t kShiftBits = 2;
+
+  // Load/store instruction offset field encoding.
+  static constexpr uint32_t kOffset12Shift = 0;
+  static constexpr uint32_t kOffset12Bits = 12;
+  static constexpr uint32_t kOffset12Mask = 0x00000fff;
+
+  // Mul instruction register field encodings.
+  static constexpr uint32_t kMulRdShift = 16;
+  static constexpr uint32_t kMulRdBits = 4;
+  static constexpr uint32_t kMulRnShift = 12;
+  static constexpr uint32_t kMulRnBits = 4;
+
+  // Div instruction register field encodings.
+  static constexpr uint32_t kDivRdShift = 16;
+  static constexpr uint32_t kDivRdBits = 4;
+  static constexpr uint32_t kDivRmShift = 8;
+  static constexpr uint32_t kDivRmBints = 4;
+  static constexpr uint32_t kDivRnShift = 0;
+  static constexpr uint32_t kDivRnBits = 4;
+
+  // ldrex/strex register field encodings.
+  static constexpr uint32_t kLdExRnShift = 16;
+  static constexpr uint32_t kLdExRtShift = 12;
+  static constexpr uint32_t kStrExRnShift = 16;
+  static constexpr uint32_t kStrExRdShift = 12;
+  static constexpr uint32_t kStrExRtShift = 0;
+
+  // MRC instruction offset field encoding.
+  static constexpr uint32_t kCRmShift = 0;
+  static constexpr uint32_t kCRmBits = 4;
+  static constexpr uint32_t kOpc2Shift = 5;
+  static constexpr uint32_t kOpc2Bits = 3;
+  static constexpr uint32_t kCoprocShift = 8;
+  static constexpr uint32_t kCoprocBits = 4;
+  static constexpr uint32_t kCRnShift = 16;
+  static constexpr uint32_t kCRnBits = 4;
+  static constexpr uint32_t kOpc1Shift = 21;
+  static constexpr uint32_t kOpc1Bits = 3;
+
+  static constexpr uint32_t kBranchOffsetMask = 0x00ffffff;
+
+  // A vector of pool-allocated x86 labels for CFG nodes.
+  using LabelVector = std::vector<Label *>;
+  LabelVector CfgNodeLabels;
+
+  Label *getOrCreateLabel(SizeT Number, LabelVector &Labels);
+  Label *getOrCreateCfgNodeLabel(SizeT NodeNumber) {
+    return getOrCreateLabel(NodeNumber, CfgNodeLabels);
+  }
+
+  void emitInt32(int32_t Value) { Buffer.emit<int32_t>(Value); }
+
+  static int32_t BkptEncoding(uint16_t imm16) {
+    // bkpt requires that the cond field is AL.
+    // cccc00010010iiiiiiiiiiii0111iiii where cccc=AL and i in imm16
+    return (CondARM32::AL << kConditionShift) | B24 | B21 |
+           ((imm16 >> 4) << 8) | B6 | B5 | B4 | (imm16 & 0xf);
+  }
 };
 
 } // end of namespace ARM32
diff --git a/src/IceAssemblerMIPS32.h b/src/IceAssemblerMIPS32.h
index 9af1151..9f6ba42 100644
--- a/src/IceAssemblerMIPS32.h
+++ b/src/IceAssemblerMIPS32.h
@@ -35,8 +35,8 @@
   AssemblerMIPS32 &operator=(const AssemblerMIPS32 &) = delete;
 
 public:
-  explicit AssemblerMIPS32(bool use_far_branches = false)
-      : Assembler(Asm_MIPS32) {
+  explicit AssemblerMIPS32(GlobalContext *Ctx, bool use_far_branches = false)
+      : Assembler(Asm_MIPS32, Ctx) {
     // This mode is only needed and implemented for MIPS32 and ARM.
     assert(!use_far_branches);
     (void)use_far_branches;
diff --git a/src/IceAssemblerX8632.h b/src/IceAssemblerX8632.h
index fb9eedf..3672ecd 100644
--- a/src/IceAssemblerX8632.h
+++ b/src/IceAssemblerX8632.h
@@ -45,8 +45,8 @@
   AssemblerX8632 &operator=(const AssemblerX8632 &) = delete;
 
 public:
-  explicit AssemblerX8632(bool use_far_branches = false)
-      : X86Internal::AssemblerX86Base<TargetX8632>(Asm_X8632,
+  explicit AssemblerX8632(GlobalContext *Ctx, bool use_far_branches = false)
+      : X86Internal::AssemblerX86Base<TargetX8632>(Asm_X8632, Ctx,
                                                    use_far_branches) {}
   ~AssemblerX8632() override = default;
 
diff --git a/src/IceAssemblerX8664.h b/src/IceAssemblerX8664.h
index 5666810..43b50be 100644
--- a/src/IceAssemblerX8664.h
+++ b/src/IceAssemblerX8664.h
@@ -45,8 +45,8 @@
   AssemblerX8664 &operator=(const AssemblerX8664 &) = delete;
 
 public:
-  explicit AssemblerX8664(bool use_far_branches = false)
-      : X86Internal::AssemblerX86Base<TargetX8664>(Asm_X8664,
+  explicit AssemblerX8664(GlobalContext *Ctx, bool use_far_branches = false)
+      : X86Internal::AssemblerX86Base<TargetX8664>(Asm_X8664, Ctx,
                                                    use_far_branches) {}
   ~AssemblerX8664() override = default;
 
diff --git a/src/IceAssemblerX86Base.h b/src/IceAssemblerX86Base.h
index f9de5a5..6b8f3c1 100644
--- a/src/IceAssemblerX86Base.h
+++ b/src/IceAssemblerX86Base.h
@@ -115,8 +115,9 @@
   AssemblerX86Base &operator=(const AssemblerX86Base &) = delete;
 
 protected:
-  AssemblerX86Base(AssemblerKind Kind, bool use_far_branches)
-      : Assembler(Kind) {
+  AssemblerX86Base(AssemblerKind Kind, GlobalContext *Ctx,
+                   bool use_far_branches)
+      : Assembler(Kind, Ctx) {
     // This mode is only needed and implemented for MIPS and ARM.
     assert(!use_far_branches);
     (void)use_far_branches;
diff --git a/src/IceGlobalContext.cpp b/src/IceGlobalContext.cpp
index 24002d6..7b54feb 100644
--- a/src/IceGlobalContext.cpp
+++ b/src/IceGlobalContext.cpp
@@ -519,7 +519,7 @@
         case FT_Iasm: {
           OstreamLocker L(this);
           Cfg::emitTextHeader(MangledName, this, Asm.get());
-          Asm->emitIASBytes(this);
+          Asm->emitIASBytes();
         } break;
         case FT_Asm:
           llvm::report_fatal_error("Unexpected FT_Asm");
diff --git a/src/IceInstARM32.cpp b/src/IceInstARM32.cpp
index b07b283..b45d2f1 100644
--- a/src/IceInstARM32.cpp
+++ b/src/IceInstARM32.cpp
@@ -969,8 +969,8 @@
 }
 
 void InstARM32Ret::emitIAS(const Cfg *Func) const {
-  (void)Func;
-  llvm_unreachable("Not yet implemented");
+  ARM32::AssemblerARM32 *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
+  Asm->bx(RegARM32::Encoded_Reg_lr);
 }
 
 void InstARM32Ret::dump(const Cfg *Func) const {
diff --git a/src/IceTargetLowering.cpp b/src/IceTargetLowering.cpp
index 9a8a02a..8d67e8b 100644
--- a/src/IceTargetLowering.cpp
+++ b/src/IceTargetLowering.cpp
@@ -113,7 +113,7 @@
                                                            Cfg *Func) {
 #define SUBZERO_TARGET(X)                                                      \
   if (Target == Target_##X)                                                    \
-    return std::unique_ptr<Assembler>(new X::Assembler##X());
+    return std::unique_ptr<Assembler>(new X::Assembler##X(Func->getContext()));
 #include "llvm/Config/SZTargets.def"
 
   Func->setError("Unsupported target assembler");
diff --git a/src/IceTargetLowering.h b/src/IceTargetLowering.h
index 32fdc44..ee0de8f 100644
--- a/src/IceTargetLowering.h
+++ b/src/IceTargetLowering.h
@@ -28,6 +28,18 @@
 
 namespace Ice {
 
+// UnimplementedError is defined as a macro so that we can get actual line
+// numbers.
+#define UnimplementedError(Flags)                                              \
+  do {                                                                         \
+    if (!static_cast<const ClFlags &>(Flags).getSkipUnimplemented()) {         \
+      /* Use llvm_unreachable instead of report_fatal_error, which gives       \
+         better stack traces. */                                               \
+      llvm_unreachable("Not yet implemented");                                 \
+      abort();                                                                 \
+    }                                                                          \
+  } while (0)
+
 /// LoweringContext makes it easy to iterate through non-deleted instructions in
 /// a node, and insert new (lowered) instructions at the current point. Along
 /// with the instruction list container and associated iterators, it holds the
diff --git a/src/IceTargetLoweringARM32.cpp b/src/IceTargetLoweringARM32.cpp
index 2674190..2615b36 100644
--- a/src/IceTargetLoweringARM32.cpp
+++ b/src/IceTargetLoweringARM32.cpp
@@ -37,18 +37,6 @@
 
 namespace {
 
-// UnimplementedError is defined as a macro so that we can get actual line
-// numbers.
-#define UnimplementedError(Flags)                                              \
-  do {                                                                         \
-    if (!static_cast<const ClFlags &>(Flags).getSkipUnimplemented()) {         \
-      /* Use llvm_unreachable instead of report_fatal_error, which gives       \
-         better stack traces. */                                               \
-      llvm_unreachable("Not yet implemented");                                 \
-      abort();                                                                 \
-    }                                                                          \
-  } while (0)
-
 // The following table summarizes the logic for lowering the icmp instruction
 // for i32 and narrower types. Each icmp condition has a clear mapping to an
 // ARM32 conditional move instruction.
@@ -3871,16 +3859,13 @@
   case FT_Elf:
     UnimplementedError(Ctx->getFlags());
     break;
-  case FT_Asm: {
+  case FT_Asm:
+  case FT_Iasm: {
     OstreamLocker L(Ctx);
     emitConstantPool<float>(Ctx);
     emitConstantPool<double>(Ctx);
     break;
   }
-  case FT_Iasm: {
-    UnimplementedError(Ctx->getFlags());
-    break;
-  }
   }
 }
 
@@ -3895,7 +3880,7 @@
     // Already emitted from Cfg
     break;
   case FT_Iasm: {
-    UnimplementedError(Ctx->getFlags());
+    // TODO(kschimpf): Fill this in when we get more information.
     break;
   }
   }
diff --git a/src/IceTargetLoweringMIPS32.cpp b/src/IceTargetLoweringMIPS32.cpp
index 98a698c..7cc65cf 100644
--- a/src/IceTargetLoweringMIPS32.cpp
+++ b/src/IceTargetLoweringMIPS32.cpp
@@ -31,17 +31,6 @@
 
 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 class.