[llvm-branch-commits] [llvm] 75f50e1 - Adding PoisonValue for representing poison value explicitly in IR

Zhengyang Liu via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Nov 25 16:48:56 PST 2020


Author: Zhengyang Liu
Date: 2020-11-25T17:33:51-07:00
New Revision: 75f50e15bf8fff6fba1d4678adedd33ef6a945e5

URL: https://github.com/llvm/llvm-project/commit/75f50e15bf8fff6fba1d4678adedd33ef6a945e5
DIFF: https://github.com/llvm/llvm-project/commit/75f50e15bf8fff6fba1d4678adedd33ef6a945e5.diff

LOG: Adding PoisonValue for representing poison value explicitly in IR

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

Added: 
    llvm/test/CodeGen/X86/poison-ops.ll

Modified: 
    llvm/bindings/ocaml/llvm/llvm.ml
    llvm/bindings/ocaml/llvm/llvm.mli
    llvm/bindings/ocaml/llvm/llvm_ocaml.c
    llvm/include/llvm-c/Core.h
    llvm/include/llvm/Bitcode/LLVMBitCodes.h
    llvm/include/llvm/IR/Constants.h
    llvm/include/llvm/IR/PatternMatch.h
    llvm/include/llvm/IR/Value.def
    llvm/lib/AsmParser/LLLexer.cpp
    llvm/lib/AsmParser/LLParser.cpp
    llvm/lib/AsmParser/LLParser.h
    llvm/lib/AsmParser/LLToken.h
    llvm/lib/Bitcode/Reader/BitcodeReader.cpp
    llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
    llvm/lib/IR/AsmWriter.cpp
    llvm/lib/IR/Constants.cpp
    llvm/lib/IR/Core.cpp
    llvm/lib/IR/LLVMContextImpl.h
    llvm/test/Bindings/OCaml/core.ml
    llvm/test/Bitcode/compatibility.ll
    llvm/tools/llvm-c-test/echo.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/bindings/ocaml/llvm/llvm.ml b/llvm/bindings/ocaml/llvm/llvm.ml
index fdef6eb176d6..723ac66ffd05 100644
--- a/llvm/bindings/ocaml/llvm/llvm.ml
+++ b/llvm/bindings/ocaml/llvm/llvm.ml
@@ -314,6 +314,7 @@ module ValueKind = struct
   | GlobalIFunc
   | GlobalVariable
   | UndefValue
+  | PoisonValue
   | Instruction of Opcode.t
 end
 
@@ -547,8 +548,10 @@ external const_null : lltype -> llvalue = "LLVMConstNull"
 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
index 04e27438a479..ba9e6c1f2120 100644
--- a/llvm/bindings/ocaml/llvm/llvm.mli
+++ b/llvm/bindings/ocaml/llvm/llvm.mli
@@ -347,6 +347,7 @@ module ValueKind : sig
   | GlobalIFunc
   | GlobalVariable
   | UndefValue
+  | PoisonValue
   | Instruction of Opcode.t
 end
 
@@ -842,6 +843,10 @@ val const_pointer_null : lltype -> llvalue
     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 @@ 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

diff  --git a/llvm/bindings/ocaml/llvm/llvm_ocaml.c b/llvm/bindings/ocaml/llvm/llvm_ocaml.c
index 1552abf29c03..5845783278d9 100644
--- a/llvm/bindings/ocaml/llvm/llvm_ocaml.c
+++ b/llvm/bindings/ocaml/llvm/llvm_ocaml.c
@@ -627,6 +627,7 @@ enum ValueKind {
   GlobalIFunc,
   GlobalVariable,
   UndefValue,
+  PoisonValue,
   Instruction
 };
 
@@ -669,6 +670,7 @@ CAMLprim value llvm_classify_value(LLVMValueRef Val) {
   DEFINE_CASE(Val, MDNode);
   DEFINE_CASE(Val, MDString);
   DEFINE_CASE(Val, UndefValue);
+  DEFINE_CASE(Val, PoisonValue);
   failwith("Unknown Value class");
 }
 
@@ -762,6 +764,11 @@ CAMLprim value llvm_is_undef(LLVMValueRef Val) {
   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
index e95038724276..1803c38b445d 100644
--- a/llvm/include/llvm-c/Core.h
+++ b/llvm/include/llvm-c/Core.h
@@ -269,6 +269,7 @@ typedef enum {
   LLVMConstantVectorValueKind,
 
   LLVMUndefValueValueKind,
+  LLVMPoisonValueValueKind,
   LLVMConstantAggregateZeroValueKind,
   LLVMConstantDataArrayValueKind,
   LLVMConstantDataVectorValueKind,
@@ -1562,6 +1563,7 @@ LLVMTypeRef LLVMX86MMXType(void);
           macro(Function)                   \
           macro(GlobalVariable)             \
       macro(UndefValue)                     \
+      macro(PoisonValue)                    \
     macro(Instruction)                      \
       macro(UnaryOperator)                  \
       macro(BinaryOperator)                 \
@@ -1695,6 +1697,11 @@ LLVMBool LLVMIsConstant(LLVMValueRef Val);
  */
 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 LLVMConstAllOnes(LLVMTypeRef Ty);
  */
 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
index 8abb20ced0c3..80fa4ac97d0d 100644
--- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h
+++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
@@ -375,6 +375,7 @@ enum ConstantsCodes {
                                  //                 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
index 88684dc8fafe..3fbbf53c29b4 100644
--- a/llvm/include/llvm/IR/Constants.h
+++ b/llvm/include/llvm/IR/Constants.h
@@ -1348,13 +1348,16 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ConstantExpr, Constant)
 /// can appear to have 
diff erent 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 @@ class UndefValue final : public ConstantData {
 
   /// 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
index c78ea48b4378..c25573b9f8a6 100644
--- a/llvm/include/llvm/IR/PatternMatch.h
+++ b/llvm/include/llvm/IR/PatternMatch.h
@@ -96,6 +96,9 @@ inline class_match<ConstantInt> m_ConstantInt() {
 /// 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>(); }
 

diff  --git a/llvm/include/llvm/IR/Value.def b/llvm/include/llvm/IR/Value.def
index 0a14b94a501d..0a0125d319c3 100644
--- a/llvm/include/llvm/IR/Value.def
+++ b/llvm/include/llvm/IR/Value.def
@@ -88,6 +88,7 @@ HANDLE_CONSTANT(ConstantVector)
 
 // 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
index b7e3a12cebf6..baabd553fbdf 100644
--- a/llvm/lib/AsmParser/LLLexer.cpp
+++ b/llvm/lib/AsmParser/LLLexer.cpp
@@ -531,6 +531,7 @@ lltok::Kind LLLexer::LexIdentifier() {
   KEYWORD(undef);
   KEYWORD(null);
   KEYWORD(none);
+  KEYWORD(poison);
   KEYWORD(to);
   KEYWORD(caller);
   KEYWORD(within);

diff  --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index 42403f7d6c46..675151e6e147 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -3273,6 +3273,7 @@ bool LLParser::parseValID(ValID &ID, PerFunctionState *PFS) {
     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 @@ bool LLParser::convertValIDToValue(Type *Ty, ValID &ID, Value *&V,
       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/LLParser.h b/llvm/lib/AsmParser/LLParser.h
index d86921ebd25e..aa79823ce986 100644
--- a/llvm/lib/AsmParser/LLParser.h
+++ b/llvm/lib/AsmParser/LLParser.h
@@ -46,7 +46,7 @@ namespace llvm {
       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/LLToken.h b/llvm/lib/AsmParser/LLToken.h
index c2b33355024d..7dd0fdab2cbf 100644
--- a/llvm/lib/AsmParser/LLToken.h
+++ b/llvm/lib/AsmParser/LLToken.h
@@ -74,6 +74,7 @@ enum Kind {
   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
index a39d7a2365ae..57c20d9502a9 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -2410,6 +2410,9 @@ Error BitcodeReader::parseConstants() {
     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
index 2a921a7e2928..5c13738fad61 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -2425,6 +2425,8 @@ void ModuleBitcodeWriter::writeConstants(unsigned FirstVal, unsigned LastVal,
     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)) {

diff  --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp
index 75c25cde623c..88331bf2ba16 100644
--- a/llvm/lib/IR/AsmWriter.cpp
+++ b/llvm/lib/IR/AsmWriter.cpp
@@ -1568,6 +1568,11 @@ static void WriteConstantInternal(raw_ostream &Out, const Constant *CV,
     return;
   }
 
+  if (isa<PoisonValue>(CV)) {
+    Out << "poison";
+    return;
+  }
+
   if (isa<UndefValue>(CV)) {
     Out << "undef";
     return;

diff  --git a/llvm/lib/IR/Constants.cpp b/llvm/lib/IR/Constants.cpp
index b87fc2484d22..f731021492bf 100644
--- a/llvm/lib/IR/Constants.cpp
+++ b/llvm/lib/IR/Constants.cpp
@@ -1089,6 +1089,32 @@ unsigned UndefValue::getNumElements() const {
   return Ty->getStructNumElements();
 }
 
+//===----------------------------------------------------------------------===//
+//                         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
 //===----------------------------------------------------------------------===//
@@ -1699,6 +1725,20 @@ void UndefValue::destroyConstantImpl() {
   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);

diff  --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp
index 28ada52ab911..ea90a33f1629 100644
--- a/llvm/lib/IR/Core.cpp
+++ b/llvm/lib/IR/Core.cpp
@@ -1046,6 +1046,10 @@ LLVMValueRef LLVMGetUndef(LLVMTypeRef Ty) {
   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));
 }
@@ -1060,6 +1064,10 @@ LLVMBool LLVMIsUndef(LLVMValueRef Val) {
   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)));
 }

diff  --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h
index 8f1b2de1e61b..1f7f04589404 100644
--- a/llvm/lib/IR/LLVMContextImpl.h
+++ b/llvm/lib/IR/LLVMContextImpl.h
@@ -1376,6 +1376,8 @@ class LLVMContextImpl {
 
   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 *>

diff  --git a/llvm/test/Bindings/OCaml/core.ml b/llvm/test/Bindings/OCaml/core.ml
index 86f865267cfa..c1bf8f908751 100644
--- a/llvm/test/Bindings/OCaml/core.ml
+++ b/llvm/test/Bindings/OCaml/core.ml
@@ -262,6 +262,14 @@ let test_constants () =
   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
index 73d7dc73a26e..993d5715721e 100644
--- a/llvm/test/Bitcode/compatibility.ll
+++ b/llvm/test/Bitcode/compatibility.ll
@@ -41,10 +41,10 @@ $comdat.samesize = comdat samesize
 ; 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 }>
- at const.struct = constant %const.struct.type { i32 -1, i8 undef }
-; CHECK: @const.struct = constant %const.struct.type { i32 -1, i8 undef }
+ at 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 @@ exc:
 
   resume i32 undef
   ; CHECK: resume i32 undef
+  resume i32 poison
+  ; CHECK: resume i32 poison
   unreachable
   ; CHECK: unreachable
 
@@ -1354,6 +1356,14 @@ define void @instructions.conversions() {
   ; 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
index 000000000000..3cd2ceb125ce
--- /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
index 47dddd32b6a9..44eb7da73f2e 100644
--- a/llvm/tools/llvm-c-test/echo.cpp
+++ b/llvm/tools/llvm-c-test/echo.cpp
@@ -344,6 +344,12 @@ static LLVMValueRef clone_constant_impl(LLVMValueRef Cst, LLVMModuleRef M) {
     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);


        


More information about the llvm-branch-commits mailing list