Add support for undef values in ICE IR. Undef values represent an
arbitrary bit pattern and are lowered to a zero constant.

IceOperand.h: Introduce a new ConstantUndef subclass of
Constant. Add a getConstantZero() method.

IceGlobalContext.h / IceGlobalContext.cpp: Implement pooling for
ConstantUndefs.

IceTargetLoweringX8632.cpp: Legalize ConstantUndefs to constant
zeros.

llvm2ice.cpp: Translate LLVM Undefs into ConstantUndefs.

undef.ll: Test that undef values are recognized and legalized to
zero.

BUG=none
R=jvoung@chromium.org, stichnot@chromium.org

Review URL: https://codereview.chromium.org/339783002
diff --git a/src/IceGlobalContext.cpp b/src/IceGlobalContext.cpp
index c3060c3..7e89a41 100644
--- a/src/IceGlobalContext.cpp
+++ b/src/IceGlobalContext.cpp
@@ -74,6 +74,29 @@
   uint32_t NextPoolID;
 };
 
+// UndefPool maps ICE types to the corresponding ConstantUndef values.
+class UndefPool {
+  UndefPool(const UndefPool &) LLVM_DELETED_FUNCTION;
+  UndefPool &operator=(const UndefPool &) LLVM_DELETED_FUNCTION;
+
+public:
+  UndefPool() : NextPoolID(0) {}
+
+  ConstantUndef *getOrAdd(GlobalContext *Ctx, Type Ty) {
+    ContainerType::iterator I = Pool.find(Ty);
+    if (I != Pool.end())
+      return I->second;
+    ConstantUndef *Undef = ConstantUndef::create(Ctx, Ty, NextPoolID++);
+    Pool[Ty] = Undef;
+    return Undef;
+  }
+
+private:
+  uint32_t NextPoolID;
+  typedef std::map<Type, ConstantUndef *> ContainerType;
+  ContainerType Pool;
+};
+
 // The global constant pool bundles individual pools of each type of
 // interest.
 class ConstantPool {
@@ -86,6 +109,7 @@
   TypePool<double, ConstantDouble, true> Doubles;
   TypePool<uint64_t, ConstantInteger> Integers;
   TypePool<RelocatableTuple, ConstantRelocatable> Relocatables;
+  UndefPool Undefs;
 };
 
 GlobalContext::GlobalContext(llvm::raw_ostream *OsDump,
@@ -192,6 +216,29 @@
       this, Ty, RelocatableTuple(Offset, Name, SuppressMangling));
 }
 
+Constant *GlobalContext::getConstantUndef(Type Ty) {
+  return ConstPool->Undefs.getOrAdd(this, Ty);
+}
+
+Constant *GlobalContext::getConstantZero(Type Ty) {
+  switch (Ty) {
+  case IceType_i1:
+  case IceType_i8:
+  case IceType_i16:
+  case IceType_i32:
+  case IceType_i64:
+    return getConstantInt(Ty, 0);
+  case IceType_f32:
+    return getConstantFloat(0);
+  case IceType_f64:
+    return getConstantDouble(0);
+  case IceType_void:
+  case IceType_NUM:
+    break;
+  }
+  llvm_unreachable("Unknown type");
+}
+
 ConstantList GlobalContext::getConstantPool(Type Ty) const {
   switch (Ty) {
   case IceType_i1:
diff --git a/src/IceGlobalContext.h b/src/IceGlobalContext.h
index beb5bc0..088421f 100644
--- a/src/IceGlobalContext.h
+++ b/src/IceGlobalContext.h
@@ -77,6 +77,10 @@
   // Returns a symbolic constant.
   Constant *getConstantSym(Type Ty, int64_t Offset, const IceString &Name = "",
                            bool SuppressMangling = false);
+  // Returns an undef.
+  Constant *getConstantUndef(Type Ty);
+  // Returns a zero value.
+  Constant *getConstantZero(Type Ty);
   // getConstantPool() returns a copy of the constant pool for
   // constants of a given type.
   ConstantList getConstantPool(Type Ty) const;
diff --git a/src/IceOperand.h b/src/IceOperand.h
index 54ac48b..00febc4 100644
--- a/src/IceOperand.h
+++ b/src/IceOperand.h
@@ -31,6 +31,7 @@
     kConstFloat,
     kConstDouble,
     kConstRelocatable,
+    kConstUndef,
     kConst_Num,
     kVariable,
     // Target-specific operand classes use kTarget as the starting
@@ -206,6 +207,40 @@
   bool SuppressMangling;
 };
 
+// ConstantUndef represents an unspecified bit pattern. Although it is
+// legal to lower ConstantUndef to any value, backends should try to
+// make code generation deterministic by lowering ConstantUndefs to 0.
+class ConstantUndef : public Constant {
+public:
+  static ConstantUndef *create(GlobalContext *Ctx, Type Ty,
+                               uint32_t PoolEntryID) {
+    return new (Ctx->allocate<ConstantUndef>()) ConstantUndef(Ty, PoolEntryID);
+  }
+
+  using Constant::emit;
+  virtual void emit(GlobalContext *Ctx) const {
+    Ostream &Str = Ctx->getStrEmit();
+    Str << "undef";
+  }
+
+  using Constant::dump;
+  virtual void dump(GlobalContext *Ctx) const {
+    Ostream &Str = Ctx->getStrEmit();
+    Str << "undef";
+  }
+
+  static bool classof(const Operand *Operand) {
+    return Operand->getKind() == kConstUndef;
+  }
+
+private:
+  ConstantUndef(Type Ty, uint32_t PoolEntryID)
+      : Constant(kConstUndef, Ty, PoolEntryID) {}
+  ConstantUndef(const ConstantUndef &) LLVM_DELETED_FUNCTION;
+  ConstantUndef &operator=(const ConstantUndef &) LLVM_DELETED_FUNCTION;
+  virtual ~ConstantUndef() {}
+};
+
 // RegWeight is a wrapper for a uint32_t weight value, with a
 // special value that represents infinite weight, and an addWeight()
 // method that ensures that W+infinity=infinity.
diff --git a/src/IceTargetLoweringX8632.cpp b/src/IceTargetLoweringX8632.cpp
index dbfe60f..6a09276 100644
--- a/src/IceTargetLoweringX8632.cpp
+++ b/src/IceTargetLoweringX8632.cpp
@@ -2160,6 +2160,20 @@
     return From;
   }
   if (llvm::isa<Constant>(From)) {
+    if (llvm::isa<ConstantUndef>(From)) {
+      // Lower undefs to zero.  Another option is to lower undefs to an
+      // uninitialized register; however, using an uninitialized register
+      // results in less predictable code.
+      //
+      // If in the future the implementation is changed to lower undef
+      // values to uninitialized registers, a FakeDef will be needed:
+      //     Context.insert(InstFakeDef::create(Func, Reg));
+      // This is in order to ensure that the live range of Reg is not
+      // overestimated.  If the constant being lowered is a 64 bit value,
+      // then the result should be split and the lo and hi components will
+      // need to go in uninitialized registers.
+      From = Ctx->getConstantZero(From->getType());
+    }
     if (!(Allowed & Legal_Imm)) {
       Variable *Reg = makeReg(From->getType(), RegNum);
       _mov(Reg, From);
diff --git a/src/llvm2ice.cpp b/src/llvm2ice.cpp
index 374d753..bce8c94 100644
--- a/src/llvm2ice.cpp
+++ b/src/llvm2ice.cpp
@@ -117,6 +117,8 @@
         return Ctx->getConstantDouble(CFP->getValueAPF().convertToDouble());
       llvm_unreachable("Unexpected floating point type");
       return NULL;
+    } else if (const UndefValue *CU = dyn_cast<UndefValue>(Const)) {
+      return Ctx->getConstantUndef(convertType(CU->getType()));
     } else {
       llvm_unreachable("Unhandled constant type");
       return NULL;
diff --git a/tests_lit/llvm2ice_tests/undef.ll b/tests_lit/llvm2ice_tests/undef.ll
new file mode 100644
index 0000000..2df08ea
--- /dev/null
+++ b/tests_lit/llvm2ice_tests/undef.ll
@@ -0,0 +1,37 @@
+; This test checks that undef values are represented as zero.
+
+; RUN: %llvm2ice --verbose none %s | FileCheck  %s
+; RUN: %llvm2ice -O2 --verbose none %s | FileCheck  %s
+; RUN: %llvm2ice --verbose none %s | FileCheck --check-prefix=ERRORS %s
+; RUN: %llvm2iceinsts %s | %szdiff %s | FileCheck --check-prefix=DUMP %s
+; RUN: %llvm2iceinsts --pnacl %s | %szdiff %s \
+; RUN:                           | FileCheck --check-prefix=DUMP %s
+
+define i32 @undefi32() {
+entry:
+; CHECK-LABEL: undefi32:
+  ret i32 undef
+; CHECK: mov eax, 0
+; CHECK: ret
+}
+
+define i64 @undefi64() {
+entry:
+; CHECK-LABEL: undefi64:
+  ret i64 undef
+; CHECK-DAG: mov eax, 0
+; CHECK-DAG: mov edx, 0
+; CHECK: ret
+}
+
+define float @undeffloat() {
+entry:
+; CHECK-LABEL: undeffloat:
+  ret float undef
+; CHECK-NOT: sub esp
+; CHECK: fld
+; CHECK: ret
+}
+
+; ERRORS-NOT: ICE translation error
+; DUMP-NOT: SZ