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