diff --git a/llvm/bindings/ocaml/llvm/llvm.ml b/llvm/bindings/ocaml/llvm/llvm.ml --- a/llvm/bindings/ocaml/llvm/llvm.ml +++ b/llvm/bindings/ocaml/llvm/llvm.ml @@ -314,6 +314,7 @@ | GlobalIFunc | GlobalVariable | UndefValue + | PoisonValue | Instruction of Opcode.t end @@ -547,8 +548,10 @@ 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 .........................................--*) diff --git a/llvm/bindings/ocaml/llvm/llvm.mli b/llvm/bindings/ocaml/llvm/llvm.mli --- a/llvm/bindings/ocaml/llvm/llvm.mli +++ b/llvm/bindings/ocaml/llvm/llvm.mli @@ -347,6 +347,7 @@ | GlobalIFunc | GlobalVariable | UndefValue + | PoisonValue | Instruction of Opcode.t end @@ -842,6 +843,10 @@ 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 @@ -850,6 +855,10 @@ otherwise. Similar to [llvm::isa]. *) val is_undef : llvalue -> bool +(** [is_poison v] returns [true] if the value [v] is a poison value, [false] + otherwise. Similar to [llvm::isa]. *) +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 diff --git a/llvm/bindings/ocaml/llvm/llvm_ocaml.c b/llvm/bindings/ocaml/llvm/llvm_ocaml.c --- a/llvm/bindings/ocaml/llvm/llvm_ocaml.c +++ b/llvm/bindings/ocaml/llvm/llvm_ocaml.c @@ -627,6 +627,7 @@ GlobalIFunc, GlobalVariable, UndefValue, + PoisonValue, Instruction }; @@ -669,6 +670,7 @@ DEFINE_CASE(Val, MDNode); DEFINE_CASE(Val, MDString); DEFINE_CASE(Val, UndefValue); + DEFINE_CASE(Val, PoisonValue); failwith("Unknown Value class"); } @@ -762,6 +764,11 @@ 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) ? diff --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h --- a/llvm/include/llvm-c/Core.h +++ b/llvm/include/llvm-c/Core.h @@ -269,6 +269,7 @@ LLVMConstantVectorValueKind, LLVMUndefValueValueKind, + LLVMPoisonValueValueKind, LLVMConstantAggregateZeroValueKind, LLVMConstantDataArrayValueKind, LLVMConstantDataVectorValueKind, @@ -1562,6 +1563,7 @@ macro(Function) \ macro(GlobalVariable) \ macro(UndefValue) \ + macro(PoisonValue) \ macro(Instruction) \ macro(UnaryOperator) \ macro(BinaryOperator) \ @@ -1695,6 +1697,11 @@ */ LLVMBool LLVMIsUndef(LLVMValueRef Val); +/** + * Determine whether a value instance is poisonous. + */ +LLVMBool LLVMIsPoison(LLVMValueRef Val); + /** * Convert value instances between types. * @@ -1853,6 +1860,13 @@ */ 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. * diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h --- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -375,6 +375,7 @@ // 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 diff --git a/llvm/include/llvm/IR/Constants.h b/llvm/include/llvm/IR/Constants.h --- a/llvm/include/llvm/IR/Constants.h +++ b/llvm/include/llvm/IR/Constants.h @@ -1348,13 +1348,16 @@ /// 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; @@ -1381,7 +1384,49 @@ /// 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; } }; diff --git a/llvm/include/llvm/IR/PatternMatch.h b/llvm/include/llvm/IR/PatternMatch.h --- a/llvm/include/llvm/IR/PatternMatch.h +++ b/llvm/include/llvm/IR/PatternMatch.h @@ -96,6 +96,9 @@ /// Match an arbitrary undef constant. inline class_match m_Undef() { return class_match(); } +/// Match an arbitrary poison constant. +inline class_match m_Poison() { return class_match(); } + /// Match an arbitrary Constant and ignore it. inline class_match m_Constant() { return class_match(); } diff --git a/llvm/include/llvm/IR/Value.def b/llvm/include/llvm/IR/Value.def --- a/llvm/include/llvm/IR/Value.def +++ b/llvm/include/llvm/IR/Value.def @@ -88,6 +88,7 @@ // ConstantData. HANDLE_CONSTANT(UndefValue) +HANDLE_CONSTANT(PoisonValue) HANDLE_CONSTANT(ConstantAggregateZero) HANDLE_CONSTANT(ConstantDataArray) HANDLE_CONSTANT(ConstantDataVector) diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp --- a/llvm/lib/AsmParser/LLLexer.cpp +++ b/llvm/lib/AsmParser/LLLexer.cpp @@ -531,6 +531,7 @@ KEYWORD(undef); KEYWORD(null); KEYWORD(none); + KEYWORD(poison); KEYWORD(to); KEYWORD(caller); KEYWORD(within); diff --git a/llvm/lib/AsmParser/LLParser.h b/llvm/lib/AsmParser/LLParser.h --- a/llvm/lib/AsmParser/LLParser.h +++ b/llvm/lib/AsmParser/LLParser.h @@ -46,7 +46,7 @@ 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. diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -3273,6 +3273,7 @@ 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; @@ -5536,10 +5537,15 @@ 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: diff --git a/llvm/lib/AsmParser/LLToken.h b/llvm/lib/AsmParser/LLToken.h --- a/llvm/lib/AsmParser/LLToken.h +++ b/llvm/lib/AsmParser/LLToken.h @@ -74,6 +74,7 @@ kw_localexec, kw_zeroinitializer, kw_undef, + kw_poison, kw_null, kw_none, kw_to, diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -2410,6 +2410,9 @@ 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"); diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -2425,6 +2425,8 @@ unsigned AbbrevToUse = 0; if (C->isNullValue()) { Code = bitc::CST_CODE_NULL; + } else if (isa(C)) { + Code = bitc::CST_CODE_POISON; } else if (isa(C)) { Code = bitc::CST_CODE_UNDEF; } else if (const ConstantInt *IV = dyn_cast(C)) { diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -1568,6 +1568,11 @@ return; } + if (isa(CV)) { + Out << "poison"; + return; + } + if (isa(CV)) { Out << "undef"; return; diff --git a/llvm/lib/IR/Constants.cpp b/llvm/lib/IR/Constants.cpp --- a/llvm/lib/IR/Constants.cpp +++ b/llvm/lib/IR/Constants.cpp @@ -1089,6 +1089,32 @@ return Ty->getStructNumElements(); } +//===----------------------------------------------------------------------===// +// PoisonValue Implementation +//===----------------------------------------------------------------------===// + +PoisonValue *PoisonValue::getSequentialElement() const { + if (ArrayType *ATy = dyn_cast(getType())) + return PoisonValue::get(ATy->getElementType()); + return PoisonValue::get(cast(getType())->getElementType()); +} + +PoisonValue *PoisonValue::getStructElement(unsigned Elt) const { + return PoisonValue::get(getType()->getStructElementType(Elt)); +} + +PoisonValue *PoisonValue::getElementValue(Constant *C) const { + if (isa(getType()) || isa(getType())) + return getSequentialElement(); + return getStructElement(cast(C)->getZExtValue()); +} + +PoisonValue *PoisonValue::getElementValue(unsigned Idx) const { + if (isa(getType()) || isa(getType())) + return getSequentialElement(); + return getStructElement(Idx); +} + //===----------------------------------------------------------------------===// // ConstantXXX Classes //===----------------------------------------------------------------------===// @@ -1699,6 +1725,20 @@ getContext().pImpl->UVConstants.erase(getType()); } +PoisonValue *PoisonValue::get(Type *Ty) { + std::unique_ptr &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); diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp --- a/llvm/lib/IR/Core.cpp +++ b/llvm/lib/IR/Core.cpp @@ -1046,6 +1046,10 @@ return wrap(UndefValue::get(unwrap(Ty))); } +LLVMValueRef LLVMGetPoison(LLVMTypeRef Ty) { + return wrap(PoisonValue::get(unwrap(Ty))); +} + LLVMBool LLVMIsConstant(LLVMValueRef Ty) { return isa(unwrap(Ty)); } @@ -1060,6 +1064,10 @@ return isa(unwrap(Val)); } +LLVMBool LLVMIsPoison(LLVMValueRef Val) { + return isa(unwrap(Val)); +} + LLVMValueRef LLVMConstPointerNull(LLVMTypeRef Ty) { return wrap(ConstantPointerNull::get(unwrap(Ty))); } diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h --- a/llvm/lib/IR/LLVMContextImpl.h +++ b/llvm/lib/IR/LLVMContextImpl.h @@ -1376,6 +1376,8 @@ DenseMap> UVConstants; + DenseMap> PVConstants; + StringMap> CDSConstants; DenseMap, BlockAddress *> diff --git a/llvm/test/Bindings/OCaml/core.ml b/llvm/test/Bindings/OCaml/core.ml --- a/llvm/test/Bindings/OCaml/core.ml +++ b/llvm/test/Bindings/OCaml/core.ml @@ -262,6 +262,14 @@ 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 diff --git a/llvm/test/Bitcode/compatibility.ll b/llvm/test/Bitcode/compatibility.ll --- a/llvm/test/Bitcode/compatibility.ll +++ b/llvm/test/Bitcode/compatibility.ll @@ -41,10 +41,10 @@ ; 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 }> @@ -1075,6 +1075,8 @@ resume i32 undef ; CHECK: resume i32 undef + resume i32 poison + ; CHECK: resume i32 poison unreachable ; CHECK: unreachable @@ -1354,6 +1356,14 @@ ; 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 diff --git a/llvm/test/CodeGen/X86/poison-ops.ll b/llvm/test/CodeGen/X86/poison-ops.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/X86/poison-ops.ll @@ -0,0 +1,458 @@ +; 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 +} + diff --git a/llvm/tools/llvm-c-test/echo.cpp b/llvm/tools/llvm-c-test/echo.cpp --- a/llvm/tools/llvm-c-test/echo.cpp +++ b/llvm/tools/llvm-c-test/echo.cpp @@ -344,6 +344,12 @@ 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);