Define ConstantData::PoisonValue.
Add support for poison value to LLLexer/LLParser/BitcodeReader/BitcodeWriter.
Add support for poison value to llvm-c interface.
Add support for poison value to OCaml binding.
Add m_Poison in PatternMatch.
Differential Revision: https://reviews.llvm.org/D71126
| GlobalIFunc
| GlobalVariable
| UndefValue
+ | PoisonValue
| Instruction of Opcode.t
end
external const_all_ones : (*int|vec*)lltype -> llvalue = "LLVMConstAllOnes"
external const_pointer_null : lltype -> llvalue = "LLVMConstPointerNull"
external undef : lltype -> llvalue = "LLVMGetUndef"
+external poison : lltype -> llvalue = "LLVMGetPoison"
external is_null : llvalue -> bool = "llvm_is_null"
external is_undef : llvalue -> bool = "llvm_is_undef"
+external is_poison : llvalue -> bool = "llvm_is_poison"
external constexpr_opcode : llvalue -> Opcode.t = "llvm_constexpr_get_opcode"
(*--... Operations on instructions .........................................--*)
| GlobalIFunc
| GlobalVariable
| UndefValue
+ | PoisonValue
| Instruction of Opcode.t
end
See the method [llvm::UndefValue::get]. *)
val undef : lltype -> llvalue
+(** [poison ty] returns the poison value of the type [ty].
+ See the method [llvm::PoisonValue::get]. *)
+val poison : lltype -> llvalue
+
(** [is_null v] returns [true] if the value [v] is the null (zero) value.
See the method [llvm::Constant::isNullValue]. *)
val is_null : llvalue -> bool
otherwise. Similar to [llvm::isa<UndefValue>]. *)
val is_undef : llvalue -> bool
+(** [is_poison v] returns [true] if the value [v] is a poison value, [false]
+ otherwise. Similar to [llvm::isa<PoisonValue>]. *)
+val is_poison : llvalue -> bool
+
(** [constexpr_opcode v] returns an [Opcode.t] corresponding to constexpr
value [v], or [Opcode.Invalid] if [v] is not a constexpr. *)
val constexpr_opcode : llvalue -> Opcode.t
GlobalIFunc,
GlobalVariable,
UndefValue,
+ PoisonValue,
Instruction
};
DEFINE_CASE(Val, MDNode);
DEFINE_CASE(Val, MDString);
DEFINE_CASE(Val, UndefValue);
+ DEFINE_CASE(Val, PoisonValue);
failwith("Unknown Value class");
}
return Val_bool(LLVMIsUndef(Val));
}
+/* llvalue -> bool */
+CAMLprim value llvm_is_poison(LLVMValueRef Val) {
+ return Val_bool(LLVMIsPoison(Val));
+}
+
/* llvalue -> Opcode.t */
CAMLprim value llvm_constexpr_get_opcode(LLVMValueRef Val) {
return LLVMIsAConstantExpr(Val) ?
LLVMConstantVectorValueKind,
LLVMUndefValueValueKind,
+ LLVMPoisonValueValueKind,
LLVMConstantAggregateZeroValueKind,
LLVMConstantDataArrayValueKind,
LLVMConstantDataVectorValueKind,
macro(Function) \
macro(GlobalVariable) \
macro(UndefValue) \
+ macro(PoisonValue) \
macro(Instruction) \
macro(UnaryOperator) \
macro(BinaryOperator) \
LLVMBool LLVMIsUndef(LLVMValueRef Val);
/**
+ * Determine whether a value instance is poisonous.
+ */
+LLVMBool LLVMIsPoison(LLVMValueRef Val);
+
+/**
* Convert value instances between types.
*
* Internally, an LLVMValueRef is "pinned" to a specific type. This
LLVMValueRef LLVMGetUndef(LLVMTypeRef Ty);
/**
+ * Obtain a constant value referring to a poison value of a type.
+ *
+ * @see llvm::PoisonValue::get()
+ */
+LLVMValueRef LLVMGetPoison(LLVMTypeRef Ty);
+
+/**
* Determine whether a value instance is null.
*
* @see llvm::Constant::isNullValue()
// asmdialect,asmstr,conststr]
CST_CODE_CE_GEP_WITH_INRANGE_INDEX = 24, // [opty, flags, n x operands]
CST_CODE_CE_UNOP = 25, // CE_UNOP: [opcode, opval]
+ CST_CODE_POISON = 26, // POISON
};
/// CastOpcodes - These are values used in the bitcode files to encode which
/// can appear to have different bit patterns at each use. See
/// LangRef.html#undefvalues for details.
///
-class UndefValue final : public ConstantData {
+class UndefValue : public ConstantData {
friend class Constant;
explicit UndefValue(Type *T) : ConstantData(T, UndefValueVal) {}
void destroyConstantImpl();
+protected:
+ explicit UndefValue(Type *T, ValueTy vty) : ConstantData(T, vty) {}
+
public:
UndefValue(const UndefValue &) = delete;
/// Methods for support type inquiry through isa, cast, and dyn_cast:
static bool classof(const Value *V) {
- return V->getValueID() == UndefValueVal;
+ return V->getValueID() == UndefValueVal ||
+ V->getValueID() == PoisonValueVal;
+ }
+};
+
+//===----------------------------------------------------------------------===//
+/// In order to facilitate speculative execution, many instructions do not
+/// invoke immediate undefined behavior when provided with illegal operands,
+/// and return a poison value instead.
+///
+/// see LangRef.html#poisonvalues for details.
+///
+class PoisonValue final : public UndefValue {
+ friend class Constant;
+
+ explicit PoisonValue(Type *T) : UndefValue(T, PoisonValueVal) {}
+
+ void destroyConstantImpl();
+
+public:
+ PoisonValue(const PoisonValue &) = delete;
+
+ /// Static factory methods - Return an 'poison' object of the specified type.
+ static PoisonValue *get(Type *T);
+
+ /// If this poison has array or vector type, return a poison with the right
+ /// element type.
+ PoisonValue *getSequentialElement() const;
+
+ /// If this poison has struct type, return a poison with the right element
+ /// type for the specified element.
+ PoisonValue *getStructElement(unsigned Elt) const;
+
+ /// Return an poison of the right value for the specified GEP index if we can,
+ /// otherwise return null (e.g. if C is a ConstantExpr).
+ PoisonValue *getElementValue(Constant *C) const;
+
+ /// Return an poison of the right value for the specified GEP index.
+ PoisonValue *getElementValue(unsigned Idx) const;
+
+ /// Methods for support type inquiry through isa, cast, and dyn_cast:
+ static bool classof(const Value *V) {
+ return V->getValueID() == PoisonValueVal;
}
};
/// Match an arbitrary undef constant.
inline class_match<UndefValue> m_Undef() { return class_match<UndefValue>(); }
+/// Match an arbitrary poison constant.
+inline class_match<PoisonValue> m_Poison() { return class_match<PoisonValue>(); }
+
/// Match an arbitrary Constant and ignore it.
inline class_match<Constant> m_Constant() { return class_match<Constant>(); }
// ConstantData.
HANDLE_CONSTANT(UndefValue)
+HANDLE_CONSTANT(PoisonValue)
HANDLE_CONSTANT(ConstantAggregateZero)
HANDLE_CONSTANT(ConstantDataArray)
HANDLE_CONSTANT(ConstantDataVector)
KEYWORD(undef);
KEYWORD(null);
KEYWORD(none);
+ KEYWORD(poison);
KEYWORD(to);
KEYWORD(caller);
KEYWORD(within);
break;
case lltok::kw_null: ID.Kind = ValID::t_Null; break;
case lltok::kw_undef: ID.Kind = ValID::t_Undef; break;
+ case lltok::kw_poison: ID.Kind = ValID::t_Poison; break;
case lltok::kw_zeroinitializer: ID.Kind = ValID::t_Zero; break;
case lltok::kw_none: ID.Kind = ValID::t_None; break;
return error(ID.Loc, "invalid type for none constant");
V = Constant::getNullValue(Ty);
return false;
+ case ValID::t_Poison:
+ // FIXME: LabelTy should not be a first-class type.
+ if (!Ty->isFirstClassType() || Ty->isLabelTy())
+ return error(ID.Loc, "invalid type for poison constant");
+ V = PoisonValue::get(Ty);
+ return false;
case ValID::t_Constant:
if (ID.ConstantVal->getType() != Ty)
return error(ID.Loc, "constant expression type mismatch");
-
V = ID.ConstantVal;
return false;
case ValID::t_ConstantStruct:
t_LocalID, t_GlobalID, // ID in UIntVal.
t_LocalName, t_GlobalName, // Name in StrVal.
t_APSInt, t_APFloat, // Value in APSIntVal/APFloatVal.
- t_Null, t_Undef, t_Zero, t_None, // No value.
+ t_Null, t_Undef, t_Zero, t_None, t_Poison, // No value.
t_EmptyArray, // No value: []
t_Constant, // Value in ConstantVal.
t_InlineAsm, // Value in FTy/StrVal/StrVal2/UIntVal.
kw_localexec,
kw_zeroinitializer,
kw_undef,
+ kw_poison,
kw_null,
kw_none,
kw_to,
case bitc::CST_CODE_UNDEF: // UNDEF
V = UndefValue::get(CurTy);
break;
+ case bitc::CST_CODE_POISON: // POISON
+ V = PoisonValue::get(CurTy);
+ break;
case bitc::CST_CODE_SETTYPE: // SETTYPE: [typeid]
if (Record.empty())
return error("Invalid record");
unsigned AbbrevToUse = 0;
if (C->isNullValue()) {
Code = bitc::CST_CODE_NULL;
+ } else if (isa<PoisonValue>(C)) {
+ Code = bitc::CST_CODE_POISON;
} else if (isa<UndefValue>(C)) {
Code = bitc::CST_CODE_UNDEF;
} else if (const ConstantInt *IV = dyn_cast<ConstantInt>(C)) {
return;
}
+ if (isa<PoisonValue>(CV)) {
+ Out << "poison";
+ return;
+ }
+
if (isa<UndefValue>(CV)) {
Out << "undef";
return;
}
//===----------------------------------------------------------------------===//
+// PoisonValue Implementation
+//===----------------------------------------------------------------------===//
+
+PoisonValue *PoisonValue::getSequentialElement() const {
+ if (ArrayType *ATy = dyn_cast<ArrayType>(getType()))
+ return PoisonValue::get(ATy->getElementType());
+ return PoisonValue::get(cast<VectorType>(getType())->getElementType());
+}
+
+PoisonValue *PoisonValue::getStructElement(unsigned Elt) const {
+ return PoisonValue::get(getType()->getStructElementType(Elt));
+}
+
+PoisonValue *PoisonValue::getElementValue(Constant *C) const {
+ if (isa<ArrayType>(getType()) || isa<VectorType>(getType()))
+ return getSequentialElement();
+ return getStructElement(cast<ConstantInt>(C)->getZExtValue());
+}
+
+PoisonValue *PoisonValue::getElementValue(unsigned Idx) const {
+ if (isa<ArrayType>(getType()) || isa<VectorType>(getType()))
+ return getSequentialElement();
+ return getStructElement(Idx);
+}
+
+//===----------------------------------------------------------------------===//
// ConstantXXX Classes
//===----------------------------------------------------------------------===//
getContext().pImpl->UVConstants.erase(getType());
}
+PoisonValue *PoisonValue::get(Type *Ty) {
+ std::unique_ptr<PoisonValue> &Entry = Ty->getContext().pImpl->PVConstants[Ty];
+ if (!Entry)
+ Entry.reset(new PoisonValue(Ty));
+
+ return Entry.get();
+}
+
+/// Remove the constant from the constant table.
+void PoisonValue::destroyConstantImpl() {
+ // Free the constant and any dangling references to it.
+ getContext().pImpl->PVConstants.erase(getType());
+}
+
BlockAddress *BlockAddress::get(BasicBlock *BB) {
assert(BB->getParent() && "Block must have a parent");
return get(BB->getParent(), BB);
return wrap(UndefValue::get(unwrap(Ty)));
}
+LLVMValueRef LLVMGetPoison(LLVMTypeRef Ty) {
+ return wrap(PoisonValue::get(unwrap(Ty)));
+}
+
LLVMBool LLVMIsConstant(LLVMValueRef Ty) {
return isa<Constant>(unwrap(Ty));
}
return isa<UndefValue>(unwrap(Val));
}
+LLVMBool LLVMIsPoison(LLVMValueRef Val) {
+ return isa<PoisonValue>(unwrap(Val));
+}
+
LLVMValueRef LLVMConstPointerNull(LLVMTypeRef Ty) {
return wrap(ConstantPointerNull::get(unwrap<PointerType>(Ty)));
}
DenseMap<Type *, std::unique_ptr<UndefValue>> UVConstants;
+ DenseMap<Type *, std::unique_ptr<PoisonValue>> PVConstants;
+
StringMap<std::unique_ptr<ConstantDataSequential>> CDSConstants;
DenseMap<std::pair<const Function *, const BasicBlock *>, BlockAddress *>
insist (i1_type = type_of c);
insist (is_undef c);
+ (* CHECK: const_poison{{.*}}poison
+ *)
+ group "poison";
+ let c = poison i1_type in
+ ignore (define_global "const_poison" c m);
+ insist (i1_type = type_of c);
+ insist (is_poison c);
+
group "constant arithmetic";
(* CHECK: @const_neg = global i64 sub
* CHECK: @const_nsw_neg = global i64 sub nsw
; CHECK: @const.float = constant double 0.0
@const.null = constant i8* null
; CHECK: @const.null = constant i8* null
-%const.struct.type = type { i32, i8 }
+%const.struct.type = type { i32, i8, i64 }
%const.struct.type.packed = type <{ i32, i8 }>
-@const.struct = constant %const.struct.type { i32 -1, i8 undef }
-; CHECK: @const.struct = constant %const.struct.type { i32 -1, i8 undef }
+@const.struct = constant %const.struct.type { i32 -1, i8 undef, i64 poison }
+; CHECK: @const.struct = constant %const.struct.type { i32 -1, i8 undef, i64 poison }
@const.struct.packed = constant %const.struct.type.packed <{ i32 -1, i8 1 }>
; CHECK: @const.struct.packed = constant %const.struct.type.packed <{ i32 -1, i8 1 }>
resume i32 undef
; CHECK: resume i32 undef
+ resume i32 poison
+ ; CHECK: resume i32 poison
unreachable
; CHECK: unreachable
; CHECK: fptoui float undef to i32
fptosi float undef to i32
; CHECK: fptosi float undef to i32
+ fptrunc float poison to half
+ ; CHECK: fptrunc float poison to half
+ fpext half poison to float
+ ; CHECK: fpext half poison to float
+ fptoui float poison to i32
+ ; CHECK: fptoui float poison to i32
+ fptosi float poison to i32
+ ; CHECK: fptosi float poison to i32
uitofp i32 1 to float
; CHECK: uitofp i32 1 to float
sitofp i32 -1 to float
--- /dev/null
+; NOTE: This test case is borrowed from undef-ops.ll
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown | FileCheck %s
+
+define i32 @add_poison_rhs(i32 %x) {
+; CHECK-LABEL: add_poison_rhs:
+; CHECK: # %bb.0:
+; CHECK-NEXT: retq
+ %r = add i32 %x, poison
+ ret i32 %r
+}
+
+define <4 x i32> @add_poison_rhs_vec(<4 x i32> %x) {
+; CHECK-LABEL: add_poison_rhs_vec:
+; CHECK: # %bb.0:
+; CHECK-NEXT: retq
+ %r = add <4 x i32> %x, poison
+ ret <4 x i32> %r
+}
+
+define i32 @add_poison_lhs(i32 %x) {
+; CHECK-LABEL: add_poison_lhs:
+; CHECK: # %bb.0:
+; CHECK-NEXT: retq
+ %r = add i32 poison, %x
+ ret i32 %r
+}
+
+define <4 x i32> @add_poison_lhs_vec(<4 x i32> %x) {
+; CHECK-LABEL: add_poison_lhs_vec:
+; CHECK: # %bb.0:
+; CHECK-NEXT: retq
+ %r = add <4 x i32> poison, %x
+ ret <4 x i32> %r
+}
+
+define i32 @sub_poison_rhs(i32 %x) {
+; CHECK-LABEL: sub_poison_rhs:
+; CHECK: # %bb.0:
+; CHECK-NEXT: retq
+ %r = sub i32 %x, poison
+ ret i32 %r
+}
+
+define <4 x i32> @sub_poison_rhs_vec(<4 x i32> %x) {
+; CHECK-LABEL: sub_poison_rhs_vec:
+; CHECK: # %bb.0:
+; CHECK-NEXT: retq
+ %r = sub <4 x i32> %x, poison
+ ret <4 x i32> %r
+}
+
+define i32 @sub_poison_lhs(i32 %x) {
+; CHECK-LABEL: sub_poison_lhs:
+; CHECK: # %bb.0:
+; CHECK-NEXT: retq
+ %r = sub i32 poison, %x
+ ret i32 %r
+}
+
+define <4 x i32> @sub_poison_lhs_vec(<4 x i32> %x) {
+; CHECK-LABEL: sub_poison_lhs_vec:
+; CHECK: # %bb.0:
+; CHECK-NEXT: retq
+ %r = sub <4 x i32> poison, %x
+ ret <4 x i32> %r
+}
+
+define i32 @mul_poison_rhs(i32 %x) {
+; CHECK-LABEL: mul_poison_rhs:
+; CHECK: # %bb.0:
+; CHECK-NEXT: xorl %eax, %eax
+; CHECK-NEXT: retq
+ %r = mul i32 %x, poison
+ ret i32 %r
+}
+
+define <4 x i32> @mul_poison_rhs_vec(<4 x i32> %x) {
+; CHECK-LABEL: mul_poison_rhs_vec:
+; CHECK: # %bb.0:
+; CHECK-NEXT: xorps %xmm0, %xmm0
+; CHECK-NEXT: retq
+ %r = mul <4 x i32> %x, poison
+ ret <4 x i32> %r
+}
+
+define i32 @mul_poison_lhs(i32 %x) {
+; CHECK-LABEL: mul_poison_lhs:
+; CHECK: # %bb.0:
+; CHECK-NEXT: xorl %eax, %eax
+; CHECK-NEXT: retq
+ %r = mul i32 poison, %x
+ ret i32 %r
+}
+
+define <4 x i32> @mul_poison_lhs_vec(<4 x i32> %x) {
+; CHECK-LABEL: mul_poison_lhs_vec:
+; CHECK: # %bb.0:
+; CHECK-NEXT: xorps %xmm0, %xmm0
+; CHECK-NEXT: retq
+ %r = mul <4 x i32> poison, %x
+ ret <4 x i32> %r
+}
+
+define i32 @sdiv_poison_rhs(i32 %x) {
+; CHECK-LABEL: sdiv_poison_rhs:
+; CHECK: # %bb.0:
+; CHECK-NEXT: retq
+ %r = sdiv i32 %x, poison
+ ret i32 %r
+}
+
+define <4 x i32> @sdiv_poison_rhs_vec(<4 x i32> %x) {
+; CHECK-LABEL: sdiv_poison_rhs_vec:
+; CHECK: # %bb.0:
+; CHECK-NEXT: retq
+ %r = sdiv <4 x i32> %x, poison
+ ret <4 x i32> %r
+}
+
+define i32 @sdiv_poison_lhs(i32 %x) {
+; CHECK-LABEL: sdiv_poison_lhs:
+; CHECK: # %bb.0:
+; CHECK-NEXT: xorl %eax, %eax
+; CHECK-NEXT: retq
+ %r = sdiv i32 poison, %x
+ ret i32 %r
+}
+
+define <4 x i32> @sdiv_poison_lhs_vec(<4 x i32> %x) {
+; CHECK-LABEL: sdiv_poison_lhs_vec:
+; CHECK: # %bb.0:
+; CHECK-NEXT: xorps %xmm0, %xmm0
+; CHECK-NEXT: retq
+ %r = sdiv <4 x i32> poison, %x
+ ret <4 x i32> %r
+}
+
+define i32 @udiv_poison_rhs(i32 %x) {
+; CHECK-LABEL: udiv_poison_rhs:
+; CHECK: # %bb.0:
+; CHECK-NEXT: retq
+ %r = udiv i32 %x, poison
+ ret i32 %r
+}
+
+define <4 x i32> @udiv_poison_rhs_vec(<4 x i32> %x) {
+; CHECK-LABEL: udiv_poison_rhs_vec:
+; CHECK: # %bb.0:
+; CHECK-NEXT: retq
+ %r = udiv <4 x i32> %x, poison
+ ret <4 x i32> %r
+}
+
+define i32 @udiv_poison_lhs(i32 %x) {
+; CHECK-LABEL: udiv_poison_lhs:
+; CHECK: # %bb.0:
+; CHECK-NEXT: xorl %eax, %eax
+; CHECK-NEXT: retq
+ %r = udiv i32 poison, %x
+ ret i32 %r
+}
+
+define <4 x i32> @udiv_poison_lhs_vec(<4 x i32> %x) {
+; CHECK-LABEL: udiv_poison_lhs_vec:
+; CHECK: # %bb.0:
+; CHECK-NEXT: xorps %xmm0, %xmm0
+; CHECK-NEXT: retq
+ %r = udiv <4 x i32> poison, %x
+ ret <4 x i32> %r
+}
+
+define i32 @srem_poison_rhs(i32 %x) {
+; CHECK-LABEL: srem_poison_rhs:
+; CHECK: # %bb.0:
+; CHECK-NEXT: retq
+ %r = srem i32 %x, poison
+ ret i32 %r
+}
+
+define <4 x i32> @srem_poison_rhs_vec(<4 x i32> %x) {
+; CHECK-LABEL: srem_poison_rhs_vec:
+; CHECK: # %bb.0:
+; CHECK-NEXT: retq
+ %r = srem <4 x i32> %x, poison
+ ret <4 x i32> %r
+}
+
+define i32 @srem_poison_lhs(i32 %x) {
+; CHECK-LABEL: srem_poison_lhs:
+; CHECK: # %bb.0:
+; CHECK-NEXT: xorl %eax, %eax
+; CHECK-NEXT: retq
+ %r = srem i32 poison, %x
+ ret i32 %r
+}
+
+define <4 x i32> @srem_poison_lhs_vec(<4 x i32> %x) {
+; CHECK-LABEL: srem_poison_lhs_vec:
+; CHECK: # %bb.0:
+; CHECK-NEXT: xorps %xmm0, %xmm0
+; CHECK-NEXT: retq
+ %r = srem <4 x i32> poison, %x
+ ret <4 x i32> %r
+}
+
+define i32 @urem_poison_rhs(i32 %x) {
+; CHECK-LABEL: urem_poison_rhs:
+; CHECK: # %bb.0:
+; CHECK-NEXT: retq
+ %r = urem i32 %x, poison
+ ret i32 %r
+}
+
+define <4 x i32> @urem_poison_rhs_vec(<4 x i32> %x) {
+; CHECK-LABEL: urem_poison_rhs_vec:
+; CHECK: # %bb.0:
+; CHECK-NEXT: retq
+ %r = urem <4 x i32> %x, poison
+ ret <4 x i32> %r
+}
+
+define i32 @urem_poison_lhs(i32 %x) {
+; CHECK-LABEL: urem_poison_lhs:
+; CHECK: # %bb.0:
+; CHECK-NEXT: xorl %eax, %eax
+; CHECK-NEXT: retq
+ %r = urem i32 poison, %x
+ ret i32 %r
+}
+
+define <4 x i32> @urem_poison_lhs_vec(<4 x i32> %x) {
+; CHECK-LABEL: urem_poison_lhs_vec:
+; CHECK: # %bb.0:
+; CHECK-NEXT: xorps %xmm0, %xmm0
+; CHECK-NEXT: retq
+ %r = urem <4 x i32> poison, %x
+ ret <4 x i32> %r
+}
+
+define i32 @ashr_poison_rhs(i32 %x) {
+; CHECK-LABEL: ashr_poison_rhs:
+; CHECK: # %bb.0:
+; CHECK-NEXT: retq
+ %r = ashr i32 %x, poison
+ ret i32 %r
+}
+
+define <4 x i32> @ashr_poison_rhs_vec(<4 x i32> %x) {
+; CHECK-LABEL: ashr_poison_rhs_vec:
+; CHECK: # %bb.0:
+; CHECK-NEXT: retq
+ %r = ashr <4 x i32> %x, poison
+ ret <4 x i32> %r
+}
+
+define i32 @ashr_poison_lhs(i32 %x) {
+; CHECK-LABEL: ashr_poison_lhs:
+; CHECK: # %bb.0:
+; CHECK-NEXT: xorl %eax, %eax
+; CHECK-NEXT: retq
+ %r = ashr i32 poison, %x
+ ret i32 %r
+}
+
+define <4 x i32> @ashr_poison_lhs_vec(<4 x i32> %x) {
+; CHECK-LABEL: ashr_poison_lhs_vec:
+; CHECK: # %bb.0:
+; CHECK-NEXT: xorps %xmm0, %xmm0
+; CHECK-NEXT: retq
+ %r = ashr <4 x i32> poison, %x
+ ret <4 x i32> %r
+}
+
+define i32 @lshr_poison_rhs(i32 %x) {
+; CHECK-LABEL: lshr_poison_rhs:
+; CHECK: # %bb.0:
+; CHECK-NEXT: retq
+ %r = lshr i32 %x, poison
+ ret i32 %r
+}
+
+define <4 x i32> @lshr_poison_rhs_vec(<4 x i32> %x) {
+; CHECK-LABEL: lshr_poison_rhs_vec:
+; CHECK: # %bb.0:
+; CHECK-NEXT: retq
+ %r = lshr <4 x i32> %x, poison
+ ret <4 x i32> %r
+}
+
+define i32 @lshr_poison_lhs(i32 %x) {
+; CHECK-LABEL: lshr_poison_lhs:
+; CHECK: # %bb.0:
+; CHECK-NEXT: xorl %eax, %eax
+; CHECK-NEXT: retq
+ %r = lshr i32 poison, %x
+ ret i32 %r
+}
+
+define <4 x i32> @lshr_poison_lhs_vec(<4 x i32> %x) {
+; CHECK-LABEL: lshr_poison_lhs_vec:
+; CHECK: # %bb.0:
+; CHECK-NEXT: xorps %xmm0, %xmm0
+; CHECK-NEXT: retq
+ %r = lshr <4 x i32> poison, %x
+ ret <4 x i32> %r
+}
+
+define i32 @shl_poison_rhs(i32 %x) {
+; CHECK-LABEL: shl_poison_rhs:
+; CHECK: # %bb.0:
+; CHECK-NEXT: retq
+ %r = shl i32 %x, poison
+ ret i32 %r
+}
+
+define <4 x i32> @shl_poison_rhs_vec(<4 x i32> %x) {
+; CHECK-LABEL: shl_poison_rhs_vec:
+; CHECK: # %bb.0:
+; CHECK-NEXT: retq
+ %r = shl <4 x i32> %x, poison
+ ret <4 x i32> %r
+}
+
+define i32 @shl_poison_lhs(i32 %x) {
+; CHECK-LABEL: shl_poison_lhs:
+; CHECK: # %bb.0:
+; CHECK-NEXT: xorl %eax, %eax
+; CHECK-NEXT: retq
+ %r = shl i32 poison, %x
+ ret i32 %r
+}
+
+define <4 x i32> @shl_poison_lhs_vec(<4 x i32> %x) {
+; CHECK-LABEL: shl_poison_lhs_vec:
+; CHECK: # %bb.0:
+; CHECK-NEXT: xorps %xmm0, %xmm0
+; CHECK-NEXT: retq
+ %r = shl <4 x i32> poison, %x
+ ret <4 x i32> %r
+}
+
+define i32 @and_poison_rhs(i32 %x) {
+; CHECK-LABEL: and_poison_rhs:
+; CHECK: # %bb.0:
+; CHECK-NEXT: xorl %eax, %eax
+; CHECK-NEXT: retq
+ %r = and i32 %x, poison
+ ret i32 %r
+}
+
+define <4 x i32> @and_poison_rhs_vec(<4 x i32> %x) {
+; CHECK-LABEL: and_poison_rhs_vec:
+; CHECK: # %bb.0:
+; CHECK-NEXT: xorps %xmm0, %xmm0
+; CHECK-NEXT: retq
+ %r = and <4 x i32> %x, poison
+ ret <4 x i32> %r
+}
+
+define i32 @and_poison_lhs(i32 %x) {
+; CHECK-LABEL: and_poison_lhs:
+; CHECK: # %bb.0:
+; CHECK-NEXT: xorl %eax, %eax
+; CHECK-NEXT: retq
+ %r = and i32 poison, %x
+ ret i32 %r
+}
+
+define <4 x i32> @and_poison_lhs_vec(<4 x i32> %x) {
+; CHECK-LABEL: and_poison_lhs_vec:
+; CHECK: # %bb.0:
+; CHECK-NEXT: xorps %xmm0, %xmm0
+; CHECK-NEXT: retq
+ %r = and <4 x i32> poison, %x
+ ret <4 x i32> %r
+}
+
+define i32 @or_poison_rhs(i32 %x) {
+; CHECK-LABEL: or_poison_rhs:
+; CHECK: # %bb.0:
+; CHECK-NEXT: movl $-1, %eax
+; CHECK-NEXT: retq
+ %r = or i32 %x, poison
+ ret i32 %r
+}
+
+define <4 x i32> @or_poison_rhs_vec(<4 x i32> %x) {
+; CHECK-LABEL: or_poison_rhs_vec:
+; CHECK: # %bb.0:
+; CHECK-NEXT: pcmpeqd %xmm0, %xmm0
+; CHECK-NEXT: retq
+ %r = or <4 x i32> %x, poison
+ ret <4 x i32> %r
+}
+
+define i32 @or_poison_lhs(i32 %x) {
+; CHECK-LABEL: or_poison_lhs:
+; CHECK: # %bb.0:
+; CHECK-NEXT: movl $-1, %eax
+; CHECK-NEXT: retq
+ %r = or i32 poison, %x
+ ret i32 %r
+}
+
+define <4 x i32> @or_poison_lhs_vec(<4 x i32> %x) {
+; CHECK-LABEL: or_poison_lhs_vec:
+; CHECK: # %bb.0:
+; CHECK-NEXT: pcmpeqd %xmm0, %xmm0
+; CHECK-NEXT: retq
+ %r = or <4 x i32> poison, %x
+ ret <4 x i32> %r
+}
+
+define i32 @xor_poison_rhs(i32 %x) {
+; CHECK-LABEL: xor_poison_rhs:
+; CHECK: # %bb.0:
+; CHECK-NEXT: retq
+ %r = xor i32 %x, poison
+ ret i32 %r
+}
+
+define <4 x i32> @xor_poison_rhs_vec(<4 x i32> %x) {
+; CHECK-LABEL: xor_poison_rhs_vec:
+; CHECK: # %bb.0:
+; CHECK-NEXT: retq
+ %r = xor <4 x i32> %x, poison
+ ret <4 x i32> %r
+}
+
+define i32 @xor_poison_lhs(i32 %x) {
+; CHECK-LABEL: xor_poison_lhs:
+; CHECK: # %bb.0:
+; CHECK-NEXT: retq
+ %r = xor i32 poison, %x
+ ret i32 %r
+}
+
+define <4 x i32> @xor_poison_lhs_vec(<4 x i32> %x) {
+; CHECK-LABEL: xor_poison_lhs_vec:
+; CHECK: # %bb.0:
+; CHECK-NEXT: retq
+ %r = xor <4 x i32> poison, %x
+ ret <4 x i32> %r
+}
+
+; This would crash because the shift amount is an i8 operand,
+; but the result of the shift is i32. We can't just propagate
+; the existing poison as the result.
+
+define i1 @poison_operand_size_not_same_as_result() {
+; CHECK-LABEL: poison_operand_size_not_same_as_result:
+; CHECK: # %bb.0:
+; CHECK-NEXT: retq
+ %sh = shl i32 7, poison
+ %cmp = icmp eq i32 0, %sh
+ ret i1 %cmp
+}
+
return LLVMGetUndef(TypeCloner(M).Clone(Cst));
}
+ // Try poison
+ if (LLVMIsPoison(Cst)) {
+ check_value_kind(Cst, LLVMPoisonValueValueKind);
+ return LLVMGetPoison(TypeCloner(M).Clone(Cst));
+ }
+
// Try null
if (LLVMIsNull(Cst)) {
check_value_kind(Cst, LLVMConstantTokenNoneValueKind);