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, @@ -1550,6 +1551,7 @@ macro(Function) \ macro(GlobalVariable) \ macro(UndefValue) \ + macro(PoisonValue) \ macro(Instruction) \ macro(UnaryOperator) \ macro(BinaryOperator) \ @@ -1683,6 +1685,11 @@ */ LLVMBool LLVMIsUndef(LLVMValueRef Val); +/** + * Determine whether a value instance is poisonous. + */ +LLVMBool LLVMIsPoison(LLVMValueRef Val); + /** * Convert value instances between types. * @@ -1841,6 +1848,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 @@ -374,6 +374,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 @@ -1344,6 +1344,50 @@ } }; +//===----------------------------------------------------------------------===// +/// 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 ConstantData { + friend class Constant; + + explicit PoisonValue(Type *T) : ConstantData(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; + + /// Return the number of elements in the array, vector, or struct. + unsigned getNumElements() const; + + /// Methods for support type inquiry through isa, cast, and dyn_cast: + static bool classof(const Value *V) { + return V->getValueID() == PoisonValueVal; + } +}; + } // end namespace llvm #endif // LLVM_IR_CONSTANTS_H 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 @@ -73,6 +73,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 @@ -3221,6 +3221,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; @@ -5400,6 +5401,12 @@ 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"); 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 @@ -2406,6 +2406,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 @@ -2408,6 +2408,8 @@ Code = bitc::CST_CODE_NULL; } else if (isa(C)) { Code = bitc::CST_CODE_UNDEF; + } else if (isa(C)) { + Code = bitc::CST_CODE_POISON; } else if (const ConstantInt *IV = dyn_cast(C)) { if (IV->getBitWidth() <= 64) { uint64_t V = IV->getSExtValue(); diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp --- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp +++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -1546,8 +1546,9 @@ MachineIRBuilder &MIRBuilder, unsigned Opcode) { - // If the source is undef, then just emit a nop. - if (isa(CI.getArgOperand(1))) + // If the source is undef or poison, then just emit a nop. + if (isa(CI.getArgOperand(1)) || + isa(CI.getArgOperand(1))) return true; SmallVector SrcRegs; @@ -1831,7 +1832,7 @@ assert(DI.getVariable() && "Missing variable"); const Value *Address = DI.getAddress(); - if (!Address || isa(Address)) { + if (!Address || isa(Address) || isa(Address)) { LLVM_DEBUG(dbgs() << "Dropping debug info for " << DI << "\n"); return true; } @@ -2739,6 +2740,8 @@ EntryBuilder->buildFConstant(Reg, *CF); else if (isa(C)) EntryBuilder->buildUndef(Reg); + else if (isa(C)) + EntryBuilder->buildUndef(Reg); else if (isa(C)) EntryBuilder->buildConstant(Reg, 0); else if (auto GV = dyn_cast(&C)) diff --git a/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp b/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp --- a/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp @@ -459,6 +459,10 @@ Reg = createResultReg(TLI.getRegClassFor(VT)); BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(TargetOpcode::IMPLICIT_DEF), Reg); + } else if (isa(V)) { + Reg = createResultReg(TLI.getRegClassFor(VT)); + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, + TII.get(TargetOpcode::IMPLICIT_DEF), Reg); } return Reg; } @@ -1386,7 +1390,7 @@ } const Value *Address = DI->getAddress(); - if (!Address || isa(Address)) { + if (!Address || isa(Address) || isa(Address)) { LLVM_DEBUG(dbgs() << "Dropping debug info for " << *DI << " (bad/undef address)\n"); return true; diff --git a/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp b/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp --- a/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp @@ -449,7 +449,7 @@ LiveOutInfo &DestLOI = LiveOutRegInfo[DestReg]; Value *V = PN->getIncomingValue(0); - if (isa(V) || isa(V)) { + if (isa(V) || isa(V) || isa(V)) { DestLOI.NumSignBits = 1; DestLOI.Known = KnownBits(BitWidth); return; @@ -482,7 +482,7 @@ for (unsigned i = 1, e = PN->getNumIncomingValues(); i != e; ++i) { Value *V = PN->getIncomingValue(i); - if (isa(V) || isa(V)) { + if (isa(V) || isa(V) || isa(V)) { DestLOI.NumSignBits = 1; DestLOI.Known = KnownBits(BitWidth); return; diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -1262,7 +1262,7 @@ const TargetLowering &TLI = DAG.getTargetLoweringInfo(); SDDbgValue *SDV; if (isa(V) || isa(V) || isa(V) || - isa(V)) { + isa(V) || isa(V)) { SDV = DAG.getConstantDbgValue(Var, Expr, V, dl, SDNodeOrder); DAG.AddDbgValue(SDV, nullptr, false); return true; @@ -1449,6 +1449,9 @@ if (isa(C) && !V->getType()->isAggregateType()) return DAG.getUNDEF(VT); + if (isa(C) && !V->getType()->isAggregateType()) + return DAG.getUNDEF(VT); + if (const ConstantExpr *CE = dyn_cast(C)) { visit(CE->getOpcode(), *CE); SDValue N1 = NodeMap[V]; @@ -1489,7 +1492,9 @@ } if (C->getType()->isStructTy() || C->getType()->isArrayTy()) { - assert((isa(C) || isa(C)) && + assert((isa(C) || + isa(C) || + isa(C)) && "Unknown struct or array constant!"); SmallVector ValueVTs; @@ -1502,6 +1507,8 @@ EVT EltVT = ValueVTs[i]; if (isa(C)) Constants[i] = DAG.getUNDEF(EltVT); + else if (isa(C)) + Constants[i] = DAG.getUNDEF(EltVT); else if (EltVT.isFloatingPoint()) Constants[i] = DAG.getConstantFP(0, getCurSDLoc(), EltVT); else @@ -3615,8 +3622,8 @@ const Value *Op1 = I.getOperand(1); Type *AggTy = I.getType(); Type *ValTy = Op1->getType(); - bool IntoUndef = isa(Op0); - bool FromUndef = isa(Op1); + bool IntoUndefOrPoison = isa(Op0) || isa(Op0); + bool FromUndefOrPoison = isa(Op1) || isa(Op1); unsigned LinearIndex = ComputeLinearIndex(AggTy, Indices); @@ -3640,18 +3647,18 @@ unsigned i = 0; // Copy the beginning value(s) from the original aggregate. for (; i != LinearIndex; ++i) - Values[i] = IntoUndef ? DAG.getUNDEF(AggValueVTs[i]) : + Values[i] = IntoUndefOrPoison ? DAG.getUNDEF(AggValueVTs[i]) : SDValue(Agg.getNode(), Agg.getResNo() + i); // Copy values from the inserted value(s). if (NumValValues) { SDValue Val = getValue(Op1); for (; i != LinearIndex + NumValValues; ++i) - Values[i] = FromUndef ? DAG.getUNDEF(AggValueVTs[i]) : + Values[i] = FromUndefOrPoison ? DAG.getUNDEF(AggValueVTs[i]) : SDValue(Val.getNode(), Val.getResNo() + i - LinearIndex); } // Copy remaining value(s) from the original aggregate. for (; i != NumAggValues; ++i) - Values[i] = IntoUndef ? DAG.getUNDEF(AggValueVTs[i]) : + Values[i] = IntoUndefOrPoison ? DAG.getUNDEF(AggValueVTs[i]) : SDValue(Agg.getNode(), Agg.getResNo() + i); setValue(&I, DAG.getNode(ISD::MERGE_VALUES, getCurSDLoc(), @@ -3668,7 +3675,7 @@ const Value *Op0 = I.getOperand(0); Type *AggTy = Op0->getType(); Type *ValTy = I.getType(); - bool OutOfUndef = isa(Op0); + bool OutOfUndefOrPoison = isa(Op0) || isa(Op0); unsigned LinearIndex = ComputeLinearIndex(AggTy, Indices); @@ -3690,7 +3697,7 @@ // Copy out the selected value(s). for (unsigned i = LinearIndex; i != LinearIndex + NumValValues; ++i) Values[i - LinearIndex] = - OutOfUndef ? + OutOfUndefOrPoison ? DAG.getUNDEF(Agg.getNode()->getValueType(Agg.getResNo() + i)) : SDValue(Agg.getNode(), Agg.getResNo() + i); @@ -5827,9 +5834,9 @@ assert(Variable && "Missing variable"); LLVM_DEBUG(dbgs() << "SelectionDAG visiting debug intrinsic: " << DI << "\n"); - // Check if address has undef value. + // Check if address has undef or poison value. const Value *Address = DI.getVariableLocation(); - if (!Address || isa(Address) || + if (!Address || isa(Address) || isa(Address) || (Address->use_empty() && !isa(Address))) { LLVM_DEBUG(dbgs() << "Dropping debug info for " << DI << " (bad/undef/unused-arg address)\n"); 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 @@ -1554,6 +1554,11 @@ return; } + if (isa(CV)) { + Out << "poison"; + return; + } + if (const ConstantExpr *CE = dyn_cast(CV)) { Out << CE->getOpcodeName(); WriteOptimizationInfo(Out, CE); 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 @@ -1076,6 +1076,42 @@ 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); +} + +unsigned PoisonValue::getNumElements() const { + Type *Ty = getType(); + if (auto *AT = dyn_cast(Ty)) + return AT->getNumElements(); + if (auto *VT = dyn_cast(Ty)) + return cast(VT)->getNumElements(); + return Ty->getStructNumElements(); +} + //===----------------------------------------------------------------------===// // ConstantXXX Classes //===----------------------------------------------------------------------===// @@ -1686,6 +1722,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 @@ -1034,6 +1034,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)); } @@ -1048,6 +1052,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 @@ -1360,6 +1360,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 }> @@ -1073,6 +1073,8 @@ resume i32 undef ; CHECK: resume i32 undef + resume i32 poison + ; CHECK: resume i32 poison unreachable ; CHECK: unreachable @@ -1352,6 +1354,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);