Add a few Subzero intrinsics (not the atomic ones yet).

Handle:
* mem{cpy,move,set} (without optimizations for known lengths)
* nacl.read.tp
* setjmp, longjmp
* trap

Mostly see if the dispatching/organization is okay.

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

Review URL: https://codereview.chromium.org/321993002
diff --git a/src/IceGlobalContext.h b/src/IceGlobalContext.h
index 088421f..c46d7d45 100644
--- a/src/IceGlobalContext.h
+++ b/src/IceGlobalContext.h
@@ -20,6 +20,7 @@
 #include "llvm/Support/raw_ostream.h"
 
 #include "IceDefs.h"
+#include "IceIntrinsics.h"
 #include "IceTypes.h"
 
 namespace Ice {
@@ -88,6 +89,8 @@
   // Allocate data of type T using the global allocator.
   template <typename T> T *allocate() { return Allocator.Allocate<T>(); }
 
+  const Intrinsics &getIntrinsicsInfo() const { return IntrinsicsInfo; }
+
 private:
   Ostream StrDump; // Stream for dumping / diagnostics
   Ostream StrEmit; // Stream for code emission
@@ -95,6 +98,7 @@
   llvm::BumpPtrAllocator Allocator;
   VerboseMask VMask;
   llvm::OwningPtr<class ConstantPool> ConstPool;
+  Intrinsics IntrinsicsInfo;
   const TargetArch Arch;
   const OptLevel Opt;
   const IceString TestPrefix;
diff --git a/src/IceInst.h b/src/IceInst.h
index a465eda..0397e02 100644
--- a/src/IceInst.h
+++ b/src/IceInst.h
@@ -18,6 +18,7 @@
 
 #include "IceDefs.h"
 #include "IceInst.def"
+#include "IceIntrinsics.h"
 #include "IceTypes.h"
 
 // TODO: The Cfg structure, and instructions in particular, need to be
@@ -42,6 +43,7 @@
     Cast,
     Fcmp,
     Icmp,
+    IntrinsicCall,
     Load,
     Phi,
     Ret,
@@ -286,8 +288,13 @@
 public:
   static InstCall *create(Cfg *Func, SizeT NumArgs, Variable *Dest,
                           Operand *CallTarget) {
+    // Set HasSideEffects to true so that the call instruction can't be
+    // dead-code eliminated. IntrinsicCalls can override this if the
+    // particular intrinsic is deletable and has no side-effects.
+    const bool HasSideEffects = true;
+    const InstKind Kind = Inst::Call;
     return new (Func->allocateInst<InstCall>())
-        InstCall(Func, NumArgs, Dest, CallTarget);
+        InstCall(Func, NumArgs, Dest, CallTarget, HasSideEffects, Kind);
   }
   void addArg(Operand *Arg) { addSource(Arg); }
   Operand *getCallTarget() const { return getSrc(0); }
@@ -296,18 +303,18 @@
   virtual void dump(const Cfg *Func) const;
   static bool classof(const Inst *Inst) { return Inst->getKind() == Call; }
 
-private:
-  InstCall(Cfg *Func, SizeT NumArgs, Variable *Dest, Operand *CallTarget)
-      : Inst(Func, Inst::Call, NumArgs + 1, Dest) {
-    // Set HasSideEffects so that the call instruction can't be
-    // dead-code eliminated.  Don't set this for a deletable intrinsic
-    // call.
-    HasSideEffects = true;
+protected:
+  InstCall(Cfg *Func, SizeT NumArgs, Variable *Dest, Operand *CallTarget,
+           bool HasSideEff, InstKind Kind)
+      : Inst(Func, Kind, NumArgs + 1, Dest) {
+    HasSideEffects = HasSideEff;
     addSource(CallTarget);
   }
+  virtual ~InstCall() {}
+
+private:
   InstCall(const InstCall &) LLVM_DELETED_FUNCTION;
   InstCall &operator=(const InstCall &) LLVM_DELETED_FUNCTION;
-  virtual ~InstCall() {}
 };
 
 // Cast instruction (a.k.a. conversion operation).
@@ -395,6 +402,34 @@
   const ICond Condition;
 };
 
+// Call to an intrinsic function.  The call target is captured as getSrc(0),
+// and arg I is captured as getSrc(I+1).
+class InstIntrinsicCall : public InstCall {
+public:
+  static InstIntrinsicCall *create(Cfg *Func, SizeT NumArgs, Variable *Dest,
+                                   Operand *CallTarget,
+                                   const Intrinsics::IntrinsicInfo &Info) {
+    return new (Func->allocateInst<InstIntrinsicCall>())
+        InstIntrinsicCall(Func, NumArgs, Dest, CallTarget, Info);
+  }
+  static bool classof(const Inst *Inst) {
+    return Inst->getKind() == IntrinsicCall;
+  }
+
+  Intrinsics::IntrinsicInfo getIntrinsicInfo() const { return Info; }
+
+private:
+  InstIntrinsicCall(Cfg *Func, SizeT NumArgs, Variable *Dest,
+                    Operand *CallTarget, const Intrinsics::IntrinsicInfo &Info)
+      : InstCall(Func, NumArgs, Dest, CallTarget, Info.HasSideEffects,
+                 Inst::IntrinsicCall),
+        Info(Info) {}
+  InstIntrinsicCall(const InstIntrinsicCall &) LLVM_DELETED_FUNCTION;
+  InstIntrinsicCall &operator=(const InstIntrinsicCall &) LLVM_DELETED_FUNCTION;
+  virtual ~InstIntrinsicCall() {}
+  const Intrinsics::IntrinsicInfo Info;
+};
+
 // Load instruction.  The source address is captured in getSrc(0).
 class InstLoad : public Inst {
 public:
diff --git a/src/IceInstX8632.cpp b/src/IceInstX8632.cpp
index 17e5712..6477683 100644
--- a/src/IceInstX8632.cpp
+++ b/src/IceInstX8632.cpp
@@ -50,6 +50,15 @@
 const size_t TypeX8632AttributesSize =
     llvm::array_lengthof(TypeX8632Attributes);
 
+const char *InstX8632SegmentRegNames[] = {
+#define X(val, name)                                                           \
+  name,
+    SEG_REGX8632_TABLE
+#undef X
+};
+const size_t InstX8632SegmentRegNamesSize =
+    llvm::array_lengthof(InstX8632SegmentRegNames);
+
 } // end of anonymous namespace
 
 const char *InstX8632::getWidthString(Type Ty) {
@@ -58,9 +67,9 @@
 
 OperandX8632Mem::OperandX8632Mem(Cfg *Func, Type Ty, Variable *Base,
                                  Constant *Offset, Variable *Index,
-                                 uint32_t Shift)
+                                 uint16_t Shift, SegmentRegisters SegmentReg)
     : OperandX8632(kMem, Ty), Base(Base), Offset(Offset), Index(Index),
-      Shift(Shift) {
+      Shift(Shift), SegmentReg(SegmentReg) {
   assert(Shift <= 3);
   Vars = NULL;
   NumVars = 0;
@@ -148,6 +157,9 @@
   addSource(Src1);
 }
 
+InstX8632UD2::InstX8632UD2(Cfg *Func)
+    : InstX8632(Func, InstX8632::UD2, 0, NULL) {}
+
 InstX8632Test::InstX8632Test(Cfg *Func, Operand *Src1, Operand *Src2)
     : InstX8632(Func, InstX8632::Test, 2, NULL) {
   addSource(Src1);
@@ -525,6 +537,17 @@
   dumpSources(Func);
 }
 
+void InstX8632UD2::emit(const Cfg *Func) const {
+  Ostream &Str = Func->getContext()->getStrEmit();
+  assert(getSrcSize() == 0);
+  Str << "\tud2\n";
+}
+
+void InstX8632UD2::dump(const Cfg *Func) const {
+  Ostream &Str = Func->getContext()->getStrDump();
+  Str << "ud2\n";
+}
+
 void InstX8632Test::emit(const Cfg *Func) const {
   Ostream &Str = Func->getContext()->getStrEmit();
   assert(getSrcSize() == 2);
@@ -758,6 +781,11 @@
 void OperandX8632Mem::emit(const Cfg *Func) const {
   Ostream &Str = Func->getContext()->getStrEmit();
   Str << TypeX8632Attributes[getType()].WidthString << " ";
+  if (SegmentReg != DefaultSegment) {
+    assert(SegmentReg >= 0 &&
+           static_cast<size_t>(SegmentReg) < InstX8632SegmentRegNamesSize);
+    Str << InstX8632SegmentRegNames[SegmentReg] << ":";
+  }
   // TODO: The following is an almost verbatim paste of dump().
   bool Dumped = false;
   Str << "[";
@@ -782,11 +810,14 @@
     OffsetIsZero = (CI->getValue() == 0);
     OffsetIsNegative = (static_cast<int64_t>(CI->getValue()) < 0);
   }
-  if (!OffsetIsZero) { // Suppress if Offset is known to be 0
-    if (Dumped) {
+  if (Dumped) {
+    if (!OffsetIsZero) {     // Suppress if Offset is known to be 0
       if (!OffsetIsNegative) // Suppress if Offset is known to be negative
         Str << "+";
+      Offset->emit(Func);
     }
+  } else {
+    // There is only the offset.
     Offset->emit(Func);
   }
   Str << "]";
@@ -794,6 +825,11 @@
 
 void OperandX8632Mem::dump(const Cfg *Func) const {
   Ostream &Str = Func->getContext()->getStrDump();
+  if (SegmentReg != DefaultSegment) {
+    assert(SegmentReg >= 0 &&
+           static_cast<size_t>(SegmentReg) < InstX8632SegmentRegNamesSize);
+    Str << InstX8632SegmentRegNames[SegmentReg] << ":";
+  }
   bool Dumped = false;
   Str << "[";
   if (Base) {
@@ -817,11 +853,14 @@
     OffsetIsZero = (CI->getValue() == 0);
     OffsetIsNegative = (static_cast<int64_t>(CI->getValue()) < 0);
   }
-  if (!OffsetIsZero) { // Suppress if Offset is known to be 0
-    if (Dumped) {
+  if (Dumped) {
+    if (!OffsetIsZero) {     // Suppress if Offset is known to be 0
       if (!OffsetIsNegative) // Suppress if Offset is known to be negative
         Str << "+";
+      Offset->dump(Func);
     }
+  } else {
+    // There is only the offset.
     Offset->dump(Func);
   }
   Str << "]";
diff --git a/src/IceInstX8632.def b/src/IceInstX8632.def
index d5e99c3..47650e1 100644
--- a/src/IceInstX8632.def
+++ b/src/IceInstX8632.def
@@ -38,6 +38,16 @@
 //#define X(val, init, name, name16, name8, scratch, preserved, stackptr,
 //          frameptr, isI8, isInt, isFP)
 
+// X86 segment registers.
+#define SEG_REGX8632_TABLE  \
+  /* enum value, name */    \
+  X(SegReg_CS, "cs")        \
+  X(SegReg_DS, "ds")        \
+  X(SegReg_ES, "es")        \
+  X(SegReg_SS, "ss")        \
+  X(SegReg_FS, "fs")        \
+  X(SegReg_GS, "gs")        \
+//#define X(val, name)
 
 #define ICEINSTX8632BR_TABLE   \
   /* enum value, dump, emit */ \
diff --git a/src/IceInstX8632.h b/src/IceInstX8632.h
index 8a6f14a..7e6e199 100644
--- a/src/IceInstX8632.h
+++ b/src/IceInstX8632.h
@@ -52,16 +52,26 @@
 // value for the index register.
 class OperandX8632Mem : public OperandX8632 {
 public:
+  enum SegmentRegisters {
+    DefaultSegment = -1,
+#define X(val, name)                                                           \
+    val,
+      SEG_REGX8632_TABLE
+#undef X
+        SegReg_NUM
+  };
   static OperandX8632Mem *create(Cfg *Func, Type Ty, Variable *Base,
                                  Constant *Offset, Variable *Index = NULL,
-                                 uint32_t Shift = 0) {
+                                 uint16_t Shift = 0,
+                                 SegmentRegisters SegmentReg = DefaultSegment) {
     return new (Func->allocate<OperandX8632Mem>())
-        OperandX8632Mem(Func, Ty, Base, Offset, Index, Shift);
+        OperandX8632Mem(Func, Ty, Base, Offset, Index, Shift, SegmentReg);
   }
   Variable *getBase() const { return Base; }
   Constant *getOffset() const { return Offset; }
   Variable *getIndex() const { return Index; }
-  uint32_t getShift() const { return Shift; }
+  uint16_t getShift() const { return Shift; }
+  SegmentRegisters getSegmentRegister() const { return SegmentReg; }
   virtual void emit(const Cfg *Func) const;
   virtual void dump(const Cfg *Func) const;
 
@@ -71,14 +81,15 @@
 
 private:
   OperandX8632Mem(Cfg *Func, Type Ty, Variable *Base, Constant *Offset,
-                  Variable *Index, uint32_t Shift);
+                  Variable *Index, uint16_t Shift, SegmentRegisters SegmentReg);
   OperandX8632Mem(const OperandX8632Mem &) LLVM_DELETED_FUNCTION;
   OperandX8632Mem &operator=(const OperandX8632Mem &) LLVM_DELETED_FUNCTION;
   virtual ~OperandX8632Mem() {}
   Variable *Base;
   Constant *Offset;
   Variable *Index;
-  uint32_t Shift;
+  uint16_t Shift;
+  SegmentRegisters SegmentReg : 16;
 };
 
 // VariableSplit is a way to treat an f64 memory location as a pair
@@ -160,6 +171,7 @@
     Subss,
     Test,
     Ucomiss,
+    UD2,
     Xor
   };
   static const char *getWidthString(Type Ty);
@@ -531,6 +543,23 @@
   virtual ~InstX8632Ucomiss() {}
 };
 
+// UD2 instruction.
+class InstX8632UD2 : public InstX8632 {
+public:
+  static InstX8632UD2 *create(Cfg *Func) {
+    return new (Func->allocate<InstX8632UD2>()) InstX8632UD2(Func);
+  }
+  virtual void emit(const Cfg *Func) const;
+  virtual void dump(const Cfg *Func) const;
+  static bool classof(const Inst *Inst) { return isClassof(Inst, UD2); }
+
+private:
+  InstX8632UD2(Cfg *Func);
+  InstX8632UD2(const InstX8632UD2 &) LLVM_DELETED_FUNCTION;
+  InstX8632UD2 &operator=(const InstX8632UD2 &) LLVM_DELETED_FUNCTION;
+  virtual ~InstX8632UD2() {}
+};
+
 // Test instruction.
 class InstX8632Test : public InstX8632 {
 public:
diff --git a/src/IceIntrinsics.cpp b/src/IceIntrinsics.cpp
new file mode 100644
index 0000000..dbf79cf
--- /dev/null
+++ b/src/IceIntrinsics.cpp
@@ -0,0 +1,202 @@
+//===- subzero/src/IceIntrinsics.cpp - Functions related to intrinsics ----===//
+//
+//                        The Subzero Code Generator
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Intrinsics utilities for matching and
+// then dispatching by name.
+//
+//===----------------------------------------------------------------------===//
+
+#include "IceCfg.h"
+#include "IceCfgNode.h"
+#include "IceIntrinsics.h"
+#include "IceLiveness.h"
+#include "IceOperand.h"
+
+#include <utility>
+
+namespace Ice {
+
+namespace {
+
+const struct IceIntrinsicsEntry_ {
+  Intrinsics::FullIntrinsicInfo Info;
+  const char *IntrinsicName;
+} IceIntrinsicsTable[] = {
+#define AtomicCmpxchgInit(Overload, NameSuffix)                                \
+  {                                                                            \
+    {                                                                          \
+      { Intrinsics::AtomicCmpxchg, true },                                     \
+      { Overload, IceType_i32, Overload, Overload, IceType_i32, IceType_i32 }, \
+      6                                                                        \
+    }                                                                          \
+    , "nacl.atomic.cmpxchg." NameSuffix                                        \
+  }
+    AtomicCmpxchgInit(IceType_i8, "i8"),
+    AtomicCmpxchgInit(IceType_i16, "i16"),
+    AtomicCmpxchgInit(IceType_i32, "i32"),
+    AtomicCmpxchgInit(IceType_i64, "i64"),
+#undef AtomicCmpxchgInit
+    { { { Intrinsics::AtomicFence, true }, { IceType_void, IceType_i32 }, 2 },
+      "nacl.atomic.fence" },
+    { { { Intrinsics::AtomicFenceAll, true }, { IceType_void }, 1 },
+      "nacl.atomic.fence.all" },
+    { { { Intrinsics::AtomicIsLockFree, true },
+        { IceType_i1, IceType_i32, IceType_i32 }, 3 },
+      "nacl.atomic.is.lock.free" },
+
+#define AtomicLoadInit(Overload, NameSuffix)                                   \
+  {                                                                            \
+    {                                                                          \
+      { Intrinsics::AtomicLoad, true }                                         \
+      , { Overload, IceType_i32, IceType_i32 }, 3                              \
+    }                                                                          \
+    , "nacl.atomic.load." NameSuffix                                           \
+  }
+    AtomicLoadInit(IceType_i8, "i8"),
+    AtomicLoadInit(IceType_i16, "i16"),
+    AtomicLoadInit(IceType_i32, "i32"),
+    AtomicLoadInit(IceType_i64, "i64"),
+#undef AtomicLoadInit
+
+#define AtomicRMWInit(Overload, NameSuffix)                                    \
+  {                                                                            \
+    {                                                                          \
+      { Intrinsics::AtomicRMW, true }                                          \
+      , { Overload, IceType_i32, IceType_i32, Overload, IceType_i32 }, 5       \
+    }                                                                          \
+    , "nacl.atomic.rmw." NameSuffix                                            \
+  }
+    AtomicRMWInit(IceType_i8, "i8"),
+    AtomicRMWInit(IceType_i16, "i16"),
+    AtomicRMWInit(IceType_i32, "i32"),
+    AtomicRMWInit(IceType_i64, "i64"),
+#undef AtomicRMWInit
+
+#define AtomicStoreInit(Overload, NameSuffix)                                  \
+  {                                                                            \
+    {                                                                          \
+      { Intrinsics::AtomicStore, true }                                        \
+      , { IceType_void, Overload, IceType_i32, IceType_i32 }, 5                \
+    }                                                                          \
+    , "nacl.atomic.store." NameSuffix                                          \
+  }
+    AtomicStoreInit(IceType_i8, "i8"),
+    AtomicStoreInit(IceType_i16, "i16"),
+    AtomicStoreInit(IceType_i32, "i32"),
+    AtomicStoreInit(IceType_i64, "i64"),
+#undef AtomicStoreInit
+
+#define BswapInit(Overload, NameSuffix)                                        \
+  {                                                                            \
+    {                                                                          \
+      { Intrinsics::Bswap, false }                                             \
+      , { Overload, Overload }, 2                                              \
+    }                                                                          \
+    , "bswap." NameSuffix                                                      \
+  }
+    BswapInit(IceType_i16, "i16"),
+    BswapInit(IceType_i32, "i32"),
+    BswapInit(IceType_i64, "i64"),
+#undef BswapInit
+
+#define CtlzInit(Overload, NameSuffix)                                         \
+  {                                                                            \
+    {                                                                          \
+      { Intrinsics::Ctlz, false }                                              \
+      , { Overload, Overload, IceType_i1 }, 3                                  \
+    }                                                                          \
+    , "ctlz." NameSuffix                                                       \
+  }
+    CtlzInit(IceType_i32, "i32"),
+    CtlzInit(IceType_i64, "i64"),
+#undef CtlzInit
+
+#define CtpopInit(Overload, NameSuffix)                                        \
+  {                                                                            \
+    {                                                                          \
+      { Intrinsics::Ctpop, false }                                             \
+      , { Overload, Overload }, 2                                              \
+    }                                                                          \
+    , "ctpop." NameSuffix                                                      \
+  }
+    CtpopInit(IceType_i32, "i32"),
+    CtpopInit(IceType_i64, "i64"),
+#undef CtpopInit
+
+#define CttzInit(Overload, NameSuffix)                                         \
+  {                                                                            \
+    {                                                                          \
+      { Intrinsics::Cttz, false }                                              \
+      , { Overload, Overload, IceType_i1 }, 3                                  \
+    }                                                                          \
+    , "cttz." NameSuffix                                                       \
+  }
+    CttzInit(IceType_i32, "i32"),
+    CttzInit(IceType_i64, "i64"),
+#undef CttzInit
+    { { { Intrinsics::Longjmp, true },
+        { IceType_void, IceType_i32, IceType_i32 }, 3 },
+      "nacl.longjmp" },
+    { { { Intrinsics::Memcpy, true }, { IceType_void, IceType_i32, IceType_i32,
+                                        IceType_i32,  IceType_i32, IceType_i1 },
+        6 },
+      "memcpy.p0i8.p0i8.i32" },
+    { { { Intrinsics::Memmove, true },
+        { IceType_void, IceType_i32, IceType_i32,
+          IceType_i32,  IceType_i32, IceType_i1 },
+        6 },
+      "memmove.p0i8.p0i8.i32" },
+    { { { Intrinsics::Memset, true }, { IceType_void, IceType_i32, IceType_i8,
+                                        IceType_i32,  IceType_i32, IceType_i1 },
+        6 },
+      "memset.p0i8.i32" },
+    { { { Intrinsics::NaClReadTP, false }, { IceType_i32 }, 1 },
+      "nacl.read.tp" },
+    { { { Intrinsics::Setjmp, true }, { IceType_i32, IceType_i32 }, 2 },
+      "nacl.setjmp" },
+
+#define SqrtInit(Overload, NameSuffix)                                         \
+  {                                                                            \
+    {                                                                          \
+      { Intrinsics::Sqrt, false }                                              \
+      , { Overload, Overload }, 2                                              \
+    }                                                                          \
+    , "sqrt." NameSuffix                                                       \
+  }
+    SqrtInit(IceType_f32, "f32"),
+    SqrtInit(IceType_f64, "f64"),
+#undef SqrtInit
+    { { { Intrinsics::Stacksave, true }, { IceType_i32 }, 1 }, "stacksave" },
+    { { { Intrinsics::Stackrestore, true }, { IceType_void, IceType_i32 }, 2 },
+      "stackrestore" },
+    { { { Intrinsics::Trap, true }, { IceType_void }, 1 }, "trap" }
+  };
+const size_t IceIntrinsicsTableSize = llvm::array_lengthof(IceIntrinsicsTable);
+
+} // end of namespace
+
+Intrinsics::Intrinsics() {
+  for (size_t I = 0; I < IceIntrinsicsTableSize; ++I) {
+    const struct IceIntrinsicsEntry_ &Entry = IceIntrinsicsTable[I];
+    assert(Entry.Info.NumTypes <= kMaxIntrinsicParameters);
+    map.insert(std::make_pair(IceString(Entry.IntrinsicName), Entry.Info));
+  }
+}
+
+Intrinsics::~Intrinsics() {}
+
+const Intrinsics::FullIntrinsicInfo *
+Intrinsics::find(const IceString &Name) const {
+  IntrinsicMap::const_iterator it = map.find(Name);
+  if (it == map.end())
+    return NULL;
+  return &it->second;
+}
+
+} // end of namespace Ice
diff --git a/src/IceIntrinsics.h b/src/IceIntrinsics.h
new file mode 100644
index 0000000..4f9f7de
--- /dev/null
+++ b/src/IceIntrinsics.h
@@ -0,0 +1,94 @@
+//===- subzero/src/IceIntrinsics.h - List of Ice Intrinsics -----*- C++ -*-===//
+//
+//                        The Subzero Code Generator
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the kinds of intrinsics supported by PNaCl.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SUBZERO_SRC_ICEINTRINSICS_H
+#define SUBZERO_SRC_ICEINTRINSICS_H
+
+#include "IceDefs.h"
+
+namespace Ice {
+
+static const size_t kMaxIntrinsicParameters = 6;
+
+class Intrinsics {
+public:
+  Intrinsics();
+  ~Intrinsics();
+
+  // Some intrinsics allow overloading by type. This enum collapses all
+  // overloads into a single ID, but the type can still be recovered by the
+  // type of the intrinsic function call's return value and parameters.
+  enum IntrinsicID {
+    UnknownIntrinsic = 0,
+    // Arbitrary (alphabetical) order.
+    AtomicCmpxchg,
+    AtomicFence,
+    AtomicFenceAll,
+    AtomicIsLockFree,
+    AtomicLoad,
+    AtomicRMW,
+    AtomicStore,
+    Bswap,
+    Ctlz,
+    Ctpop,
+    Cttz,
+    Longjmp,
+    Memcpy,
+    Memmove,
+    Memset,
+    NaClReadTP,
+    Setjmp,
+    Sqrt,
+    Stacksave,
+    Stackrestore,
+    Trap
+  };
+
+  // Basic attributes related to each intrinsic, that are relevant to
+  // code generation. We will want to have more attributes (e.g., Setjmp
+  // returns twice and which affects stack coloring) once the lowering
+  // cares about such attributes. Perhaps the attributes representation
+  // can be shared with general function calls, though most functions
+  // will be opaque.
+  struct IntrinsicInfo {
+    IntrinsicID ID : 31;
+    bool HasSideEffects : 1;
+  };
+
+  // The complete set of information about an intrinsic.
+  struct FullIntrinsicInfo {
+    struct IntrinsicInfo Info; // Information that CodeGen would care about.
+
+    // Sanity check during parsing.
+    Type Signature[kMaxIntrinsicParameters];
+    uint8_t NumTypes;
+  };
+
+  // Find the information about a given intrinsic, based on function name.
+  // The function name is expected to have the common "llvm." prefix
+  // stripped. If found, returns a reference to a FullIntrinsicInfo entry
+  // (valid for the lifetime of the map). Otherwise returns null.
+  const FullIntrinsicInfo *find(const IceString &Name) const;
+
+private:
+  // TODO(jvoung): May want to switch to something like LLVM's StringMap.
+  typedef std::map<IceString, FullIntrinsicInfo> IntrinsicMap;
+  IntrinsicMap map;
+
+  Intrinsics(const Intrinsics &) LLVM_DELETED_FUNCTION;
+  Intrinsics &operator=(const Intrinsics &) LLVM_DELETED_FUNCTION;
+};
+
+} // end of namespace Ice
+
+#endif // SUBZERO_SRC_ICEINTRINSICS_H
diff --git a/src/IceTargetLowering.cpp b/src/IceTargetLowering.cpp
index 72a3e8c..877f717 100644
--- a/src/IceTargetLowering.cpp
+++ b/src/IceTargetLowering.cpp
@@ -116,6 +116,9 @@
   case Inst::Icmp:
     lowerIcmp(llvm::dyn_cast<InstIcmp>(Inst));
     break;
+  case Inst::IntrinsicCall:
+    lowerIntrinsicCall(llvm::dyn_cast<InstIntrinsicCall>(Inst));
+    break;
   case Inst::Load:
     lowerLoad(llvm::dyn_cast<InstLoad>(Inst));
     break;
diff --git a/src/IceTargetLowering.h b/src/IceTargetLowering.h
index 7f798a8..dbb9a42 100644
--- a/src/IceTargetLowering.h
+++ b/src/IceTargetLowering.h
@@ -167,6 +167,7 @@
   virtual void lowerCast(const InstCast *Inst) = 0;
   virtual void lowerFcmp(const InstFcmp *Inst) = 0;
   virtual void lowerIcmp(const InstIcmp *Inst) = 0;
+  virtual void lowerIntrinsicCall(const InstIntrinsicCall *Inst) = 0;
   virtual void lowerLoad(const InstLoad *Inst) = 0;
   virtual void lowerPhi(const InstPhi *Inst) = 0;
   virtual void lowerRet(const InstRet *Inst) = 0;
diff --git a/src/IceTargetLoweringX8632.cpp b/src/IceTargetLoweringX8632.cpp
index 0edcab5..449e413 100644
--- a/src/IceTargetLoweringX8632.cpp
+++ b/src/IceTargetLoweringX8632.cpp
@@ -431,6 +431,9 @@
   InArgsSizeBytes += typeWidthInBytesOnStack(Ty);
 }
 
+// static
+Type TargetX8632::stackSlotType() { return IceType_i32; }
+
 void TargetX8632::addProlog(CfgNode *Node) {
   // If SimpleCoalescing is false, each variable without a register
   // gets its own unique stack slot, which leads to large stack
@@ -760,7 +763,7 @@
   if (OperandX8632Mem *Mem = llvm::dyn_cast<OperandX8632Mem>(Operand)) {
     return OperandX8632Mem::create(Func, IceType_i32, Mem->getBase(),
                                    Mem->getOffset(), Mem->getIndex(),
-                                   Mem->getShift());
+                                   Mem->getShift(), Mem->getSegmentRegister());
   }
   llvm_unreachable("Unsupported operand type");
   return NULL;
@@ -790,7 +793,8 @@
                                    SymOffset->getName());
     }
     return OperandX8632Mem::create(Func, IceType_i32, Mem->getBase(), Offset,
-                                   Mem->getIndex(), Mem->getShift());
+                                   Mem->getIndex(), Mem->getShift(),
+                                   Mem->getSegmentRegister());
   }
   llvm_unreachable("Unsupported operand type");
   return NULL;
@@ -1774,6 +1778,91 @@
   Context.insert(Label);
 }
 
+void TargetX8632::lowerIntrinsicCall(const InstIntrinsicCall *Instr) {
+  switch (Instr->getIntrinsicInfo().ID) {
+  case Intrinsics::AtomicCmpxchg:
+  case Intrinsics::AtomicFence:
+  case Intrinsics::AtomicFenceAll:
+  case Intrinsics::AtomicIsLockFree:
+  case Intrinsics::AtomicLoad:
+  case Intrinsics::AtomicRMW:
+  case Intrinsics::AtomicStore:
+  case Intrinsics::Bswap:
+  case Intrinsics::Ctlz:
+  case Intrinsics::Ctpop:
+  case Intrinsics::Cttz:
+    Func->setError("Unhandled intrinsic");
+    return;
+  case Intrinsics::Longjmp: {
+    InstCall *Call = makeHelperCall("longjmp", NULL, 2);
+    Call->addArg(Instr->getArg(0));
+    Call->addArg(Instr->getArg(1));
+    lowerCall(Call);
+    break;
+  }
+  case Intrinsics::Memcpy: {
+    // In the future, we could potentially emit an inline memcpy/memset, etc.
+    // for intrinsic calls w/ a known length.
+    InstCall *Call = makeHelperCall("memcpy", NULL, 3);
+    Call->addArg(Instr->getArg(0));
+    Call->addArg(Instr->getArg(1));
+    Call->addArg(Instr->getArg(2));
+    lowerCall(Call);
+    break;
+  }
+  case Intrinsics::Memmove: {
+    InstCall *Call = makeHelperCall("memmove", NULL, 3);
+    Call->addArg(Instr->getArg(0));
+    Call->addArg(Instr->getArg(1));
+    Call->addArg(Instr->getArg(2));
+    lowerCall(Call);
+    break;
+  }
+  case Intrinsics::Memset: {
+    // The value operand needs to be extended to a stack slot size
+    // because we "push" only works for a specific operand size.
+    Operand *ValOp = Instr->getArg(1);
+    assert(ValOp->getType() == IceType_i8);
+    Variable *ValExt = makeReg(stackSlotType());
+    _movzx(ValExt, ValOp);
+    InstCall *Call = makeHelperCall("memset", NULL, 3);
+    Call->addArg(Instr->getArg(0));
+    Call->addArg(ValExt);
+    Call->addArg(Instr->getArg(2));
+    lowerCall(Call);
+    break;
+  }
+  case Intrinsics::NaClReadTP: {
+    Constant *Zero = Ctx->getConstantInt(IceType_i32, 0);
+    Operand *Src = OperandX8632Mem::create(Func, IceType_i32, NULL, Zero, NULL,
+                                           0, OperandX8632Mem::SegReg_GS);
+    Variable *Dest = Instr->getDest();
+    Variable *T = NULL;
+    _mov(T, Src);
+    _mov(Dest, T);
+    break;
+  }
+  case Intrinsics::Setjmp: {
+    InstCall *Call = makeHelperCall("setjmp", Instr->getDest(), 1);
+    Call->addArg(Instr->getArg(0));
+    lowerCall(Call);
+    break;
+  }
+  case Intrinsics::Sqrt:
+  case Intrinsics::Stacksave:
+  case Intrinsics::Stackrestore:
+    Func->setError("Unhandled intrinsic");
+    return;
+  case Intrinsics::Trap:
+    _ud2();
+    break;
+  case Intrinsics::UnknownIntrinsic:
+    Func->setError("Should not be lowering UnknownIntrinsic");
+    return;
+  }
+  return;
+}
+
 namespace {
 
 bool isAdd(const Inst *Inst) {
@@ -1784,7 +1873,7 @@
   return false;
 }
 
-void computeAddressOpt(Variable *&Base, Variable *&Index, int32_t &Shift,
+void computeAddressOpt(Variable *&Base, Variable *&Index, uint16_t &Shift,
                        int32_t &Offset) {
   (void)Offset; // TODO: pattern-match for non-zero offsets.
   if (Base == NULL)
@@ -1965,14 +2054,20 @@
   Variable *Dest = Inst->getDest();
   Operand *Addr = Inst->getSrc(0);
   Variable *Index = NULL;
-  int32_t Shift = 0;
+  uint16_t Shift = 0;
   int32_t Offset = 0; // TODO: make Constant
+  // Vanilla ICE load instructions should not use the segment registers,
+  // and computeAddressOpt only works at the level of Variables and Constants,
+  // not other OperandX8632Mem, so there should be no mention of segment
+  // registers there either.
+  const OperandX8632Mem::SegmentRegisters SegmentReg =
+      OperandX8632Mem::DefaultSegment;
   Variable *Base = llvm::dyn_cast<Variable>(Addr);
   computeAddressOpt(Base, Index, Shift, Offset);
   if (Base && Addr != Base) {
     Constant *OffsetOp = Ctx->getConstantInt(IceType_i32, Offset);
     Addr = OperandX8632Mem::create(Func, Dest->getType(), Base, OffsetOp, Index,
-                                   Shift);
+                                   Shift, SegmentReg);
     Inst->setDeleted();
     Context.insert(InstLoad::create(Func, Dest, Addr));
   }
@@ -2081,14 +2176,20 @@
   Operand *Data = Inst->getData();
   Operand *Addr = Inst->getAddr();
   Variable *Index = NULL;
-  int32_t Shift = 0;
+  uint16_t Shift = 0;
   int32_t Offset = 0; // TODO: make Constant
   Variable *Base = llvm::dyn_cast<Variable>(Addr);
+  // Vanilla ICE store instructions should not use the segment registers,
+  // and computeAddressOpt only works at the level of Variables and Constants,
+  // not other OperandX8632Mem, so there should be no mention of segment
+  // registers there either.
+  const OperandX8632Mem::SegmentRegisters SegmentReg =
+      OperandX8632Mem::DefaultSegment;
   computeAddressOpt(Base, Index, Shift, Offset);
   if (Base && Addr != Base) {
     Constant *OffsetOp = Ctx->getConstantInt(IceType_i32, Offset);
     Addr = OperandX8632Mem::create(Func, Data->getType(), Base, OffsetOp, Index,
-                                   Shift);
+                                   Shift, SegmentReg);
     Inst->setDeleted();
     Context.insert(InstStore::create(Func, Data, Addr));
   }
@@ -2147,9 +2248,9 @@
       RegIndex = legalizeToVar(Index, true);
     }
     if (Base != RegBase || Index != RegIndex) {
-      From =
-          OperandX8632Mem::create(Func, Mem->getType(), RegBase,
-                                  Mem->getOffset(), RegIndex, Mem->getShift());
+      From = OperandX8632Mem::create(
+          Func, Mem->getType(), RegBase, Mem->getOffset(), RegIndex,
+          Mem->getShift(), Mem->getSegmentRegister());
     }
 
     if (!(Allowed & Legal_Mem)) {
diff --git a/src/IceTargetLoweringX8632.h b/src/IceTargetLoweringX8632.h
index 3ca9ca3..7902136 100644
--- a/src/IceTargetLoweringX8632.h
+++ b/src/IceTargetLoweringX8632.h
@@ -83,6 +83,7 @@
   virtual void lowerCast(const InstCast *Inst);
   virtual void lowerFcmp(const InstFcmp *Inst);
   virtual void lowerIcmp(const InstIcmp *Inst);
+  virtual void lowerIntrinsicCall(const InstIntrinsicCall *Inst);
   virtual void lowerLoad(const InstLoad *Inst);
   virtual void lowerPhi(const InstPhi *Inst);
   virtual void lowerRet(const InstRet *Inst);
@@ -123,6 +124,7 @@
     InstCall *Call = InstCall::create(Func, MaxSrcs, Dest, CallTarget);
     return Call;
   }
+  static Type stackSlotType();
 
   // The following are helpers that insert lowered x86 instructions
   // with minimal syntactic overhead, so that the lowering code can
@@ -246,6 +248,7 @@
   void _ucomiss(Operand *Src0, Operand *Src1) {
     Context.insert(InstX8632Ucomiss::create(Func, Src0, Src1));
   }
+  void _ud2() { Context.insert(InstX8632UD2::create(Func)); }
   void _xor(Variable *Dest, Operand *Src0) {
     Context.insert(InstX8632Xor::create(Func, Dest, Src0));
   }
diff --git a/src/llvm2ice.cpp b/src/llvm2ice.cpp
index bce8c94..2b323f7 100644
--- a/src/llvm2ice.cpp
+++ b/src/llvm2ice.cpp
@@ -528,11 +528,37 @@
     unsigned NumArgs = Inst->getNumArgOperands();
     // Note: Subzero doesn't (yet) do anything special with the Tail
     // flag in the bitcode, i.e. CallInst::isTailCall().
-    Ice::InstCall *NewInst =
-        Ice::InstCall::create(Func, NumArgs, Dest, CallTarget);
+    Ice::InstCall *NewInst = NULL;
+    const Ice::Intrinsics::FullIntrinsicInfo *Info = NULL;
+
+    if (Ice::ConstantRelocatable *Target =
+            llvm::dyn_cast<Ice::ConstantRelocatable>(CallTarget)) {
+      // Check if this direct call is to an Intrinsic (starts with "llvm.")
+      static const char LLVMPrefix[] = "llvm.";
+      const size_t LLVMPrefixLen = strlen(LLVMPrefix);
+      Ice::IceString Name = Target->getName();
+      if (Name.substr(0, LLVMPrefixLen) == LLVMPrefix) {
+        Ice::IceString NameSuffix = Name.substr(LLVMPrefixLen);
+        Info = Ctx->getIntrinsicsInfo().find(NameSuffix);
+        if (!Info) {
+          report_fatal_error(std::string("Invalid PNaCl intrinsic call: ") +
+                             LLVMObjectAsString(Inst));
+        }
+        NewInst = Ice::InstIntrinsicCall::create(Func, NumArgs, Dest,
+                                                 CallTarget, Info->Info);
+      }
+    }
+
+    // Not an intrinsic call.
+    if (NewInst == NULL) {
+      NewInst = Ice::InstCall::create(Func, NumArgs, Dest, CallTarget);
+    }
     for (unsigned i = 0; i < NumArgs; ++i) {
       NewInst->addArg(convertOperand(Inst, i));
     }
+    if (Info) {
+      validateIntrinsicCall(NewInst, Info);
+    }
     return NewInst;
   }
 
@@ -559,6 +585,31 @@
     return Node;
   }
 
+  void validateIntrinsicCall(const Ice::InstCall *Call,
+                             const Ice::Intrinsics::FullIntrinsicInfo *I) {
+    assert(I->NumTypes >= 1);
+    if (I->Signature[0] == Ice::IceType_void) {
+      if (Call->getDest() != NULL) {
+        report_fatal_error(
+            "Return value for intrinsic func w/ void return type.");
+      }
+    } else {
+      if (I->Signature[0] != Call->getDest()->getType()) {
+        report_fatal_error("Mismatched return types.");
+      }
+    }
+    if (Call->getNumArgs() + 1 != I->NumTypes) {
+      std::cerr << "Call->getNumArgs() " << (int)Call->getNumArgs()
+                << " I->NumTypes " << (int)I->NumTypes << "\n";
+      report_fatal_error("Mismatched # of args.");
+    }
+    for (size_t i = 1; i < I->NumTypes; ++i) {
+      if (Call->getArg(i - 1)->getType() != I->Signature[i]) {
+        report_fatal_error("Mismatched argument type.");
+      }
+    }
+  }
+
 private:
   // Data
   Ice::GlobalContext *Ctx;