[llvm] [IR] Add initial support for the byte type (PR #178666)

Pedro Lobo via llvm-commits llvm-commits at lists.llvm.org
Sun Mar 8 04:40:41 PDT 2026


https://github.com/pedroclobo updated https://github.com/llvm/llvm-project/pull/178666

>From b144d04beda91d51675c438a7fa59d6de3857c7f Mon Sep 17 00:00:00 2001
From: George Mitenkov <georgemitenk0v at gmail.com>
Date: Thu, 22 Jul 2021 14:29:05 +0300
Subject: [PATCH 1/6] [IR] Introduce the byte type

- Adds the byte type
- Extends the `bitcast` instruction to accept byte operands
- Fixes `IR2Vec` tests
---
 llvm/include/llvm-c/Core.h                    |  93 +++++
 llvm/include/llvm/Analysis/IR2Vec.h           |   8 +-
 llvm/include/llvm/Bitcode/LLVMBitCodes.h      |   4 +
 llvm/include/llvm/IR/Constants.h              | 248 +++++++++++-
 llvm/include/llvm/IR/DataLayout.h             |  19 +
 llvm/include/llvm/IR/DerivedTypes.h           |  56 +++
 llvm/include/llvm/IR/IRBuilder.h              |  24 ++
 llvm/include/llvm/IR/Type.h                   |  30 +-
 llvm/include/llvm/IR/Value.def                |   1 +
 llvm/lib/AsmParser/LLLexer.cpp                |  35 +-
 llvm/lib/AsmParser/LLParser.cpp               |  21 +-
 llvm/lib/Bitcode/Reader/BitcodeReader.cpp     |  54 ++-
 llvm/lib/Bitcode/Writer/BitcodeWriter.cpp     |  29 +-
 llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp    |  87 ++++-
 .../SelectionDAG/FunctionLoweringInfo.cpp     |   2 +-
 .../SelectionDAG/SelectionDAGBuilder.cpp      |   3 +
 llvm/lib/CodeGen/ValueTypes.cpp               |   4 +
 llvm/lib/IR/AsmWriter.cpp                     |  26 +-
 llvm/lib/IR/Attributes.cpp                    |   4 +-
 llvm/lib/IR/Constants.cpp                     | 357 +++++++++++++++++-
 llvm/lib/IR/Core.cpp                          |  78 ++++
 llvm/lib/IR/DataLayout.cpp                    |  37 ++
 llvm/lib/IR/Instructions.cpp                  |  16 +-
 llvm/lib/IR/Intrinsics.cpp                    |   3 +
 llvm/lib/IR/LLVMContextImpl.cpp               |   7 +-
 llvm/lib/IR/LLVMContextImpl.h                 |  11 +
 llvm/lib/IR/Type.cpp                          |  54 ++-
 llvm/lib/IR/Verifier.cpp                      |  10 +-
 .../DirectX/DXILWriter/DXILBitcodeWriter.cpp  |  19 +
 .../Hexagon/HexagonTargetObjectFile.cpp       |   1 +
 .../Inputs/reference_default_vocab_print.txt  |   1 +
 .../Inputs/reference_wtd1_vocab_print.txt     |   1 +
 .../Inputs/reference_wtd2_vocab_print.txt     |   1 +
 .../Assembler/2008-02-18-IntPointerCrash.ll   |   2 +-
 llvm/test/Assembler/byte-invalid-cast-1.ll    |   7 +
 llvm/test/Assembler/byte-invalid-cast-2.ll    |   7 +
 llvm/test/Assembler/byte-invalid-cast-3.ll    |   7 +
 llvm/test/Assembler/byte-invalid-cast-4.ll    |   7 +
 llvm/test/Assembler/byte-invalid-cast-5.ll    |   7 +
 llvm/test/Assembler/byte-invalid-cast-6.ll    |   7 +
 llvm/test/Assembler/byte-invalid-cast-7.ll    |   7 +
 llvm/test/Assembler/byte-invalid-cast-8.ll    |   7 +
 llvm/test/Assembler/byte-invalid-cmp.ll       |   7 +
 llvm/test/Assembler/byte.ll                   | 102 +++++
 llvm/test/Assembler/invalid-inttype.ll        |   2 +-
 llvm/test/Bindings/llvm-c/byte.ll             |  11 +
 llvm/test/Bindings/llvm-c/echo.ll             |   1 +
 llvm/test/Bitcode/compatibility.ll            |   2 +
 llvm/test/CodeGen/X86/byte-constants.ll       |  63 ++++
 llvm/test/Verifier/atomics.ll                 |   4 +-
 llvm/test/tools/llvm-ir2vec/entities.ll       |  73 ++--
 llvm/test/tools/llvm-ir2vec/triplets.ll       |  38 +-
 llvm/tools/llvm-c-test/echo.cpp               |   2 +
 llvm/unittests/Analysis/IR2VecTest.cpp        |  29 +-
 54 files changed, 1585 insertions(+), 151 deletions(-)
 create mode 100644 llvm/test/Assembler/byte-invalid-cast-1.ll
 create mode 100644 llvm/test/Assembler/byte-invalid-cast-2.ll
 create mode 100644 llvm/test/Assembler/byte-invalid-cast-3.ll
 create mode 100644 llvm/test/Assembler/byte-invalid-cast-4.ll
 create mode 100644 llvm/test/Assembler/byte-invalid-cast-5.ll
 create mode 100644 llvm/test/Assembler/byte-invalid-cast-6.ll
 create mode 100644 llvm/test/Assembler/byte-invalid-cast-7.ll
 create mode 100644 llvm/test/Assembler/byte-invalid-cast-8.ll
 create mode 100644 llvm/test/Assembler/byte-invalid-cmp.ll
 create mode 100644 llvm/test/Assembler/byte.ll
 create mode 100644 llvm/test/Bindings/llvm-c/byte.ll
 create mode 100644 llvm/test/CodeGen/X86/byte-constants.ll

diff --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h
index 2bd971983e287..23f94408b86b5 100644
--- a/llvm/include/llvm-c/Core.h
+++ b/llvm/include/llvm-c/Core.h
@@ -169,6 +169,7 @@ typedef enum {
   LLVMBFloatTypeKind = 18,         /**< 16 bit brain floating point type */
   LLVMX86_AMXTypeKind = 19,        /**< X86 AMX */
   LLVMTargetExtTypeKind = 20,      /**< Target extension type */
+  LLVMByteTypeKind = 21,           /**< Arbitrary bit width bytes */
 } LLVMTypeKind;
 
 typedef enum {
@@ -278,6 +279,7 @@ typedef enum {
   LLVMConstantDataArrayValueKind,
   LLVMConstantDataVectorValueKind,
   LLVMConstantIntValueKind,
+  LLVMConstantByteValueKind,
   LLVMConstantFPValueKind,
   LLVMConstantPointerNullValueKind,
   LLVMConstantTokenNoneValueKind,
@@ -1311,6 +1313,7 @@ LLVM_C_ABI void LLVMSetModuleInlineAsm(LLVMModuleRef M, const char *Asm);
  *
  *   types:
  *     integer type
+ *     byte type
  *     real type
  *     function type
  *     sequence types:
@@ -1362,6 +1365,40 @@ LLVM_C_ABI void LLVMDumpType(LLVMTypeRef Val);
  */
 LLVM_C_ABI char *LLVMPrintTypeToString(LLVMTypeRef Val);
 
+/**
+ * @}
+ */
+
+/**
+ * @defgroup LLVMCCoreTypeByte Byte Types
+ *
+ * Functions in this section operate on byte types.
+ *
+ * @{
+ */
+
+/**
+ * Obtain a byte type from a context with specified bit width.
+ */
+LLVMTypeRef LLVMByte8TypeInContext(LLVMContextRef C);
+LLVMTypeRef LLVMByte16TypeInContext(LLVMContextRef C);
+LLVMTypeRef LLVMByte32TypeInContext(LLVMContextRef C);
+LLVMTypeRef LLVMByte64TypeInContext(LLVMContextRef C);
+LLVMTypeRef LLVMByte128TypeInContext(LLVMContextRef C);
+LLVMTypeRef LLVMByteTypeInContext(LLVMContextRef C, unsigned NumBits);
+
+/**
+ * Obtain a byte type from the global context with a specified bit
+ * width.
+ */
+LLVMTypeRef LLVMByte8Type(void);
+LLVMTypeRef LLVMByte16Type(void);
+LLVMTypeRef LLVMByte32Type(void);
+LLVMTypeRef LLVMByte64Type(void);
+LLVMTypeRef LLVMByte128Type(void);
+LLVMTypeRef LLVMByteType(unsigned NumBits);
+unsigned LLVMGetByteTypeWidth(LLVMTypeRef ByteTy);
+
 /**
  * @defgroup LLVMCCoreTypeInt Integer Types
  *
@@ -1978,6 +2015,7 @@ LLVM_C_ABI unsigned LLVMGetTargetExtTypeIntParam(LLVMTypeRef TargetExtTy,
       macro(ConstantExpr)                   \
       macro(ConstantFP)                     \
       macro(ConstantInt)                    \
+      macro(ConstantByte)                   \
       macro(ConstantPointerNull)            \
       macro(ConstantStruct)                 \
       macro(ConstantTokenNone)              \
@@ -2389,6 +2427,47 @@ LLVM_C_ABI LLVMValueRef LLVMConstIntOfStringAndSize(LLVMTypeRef IntTy,
                                                     unsigned SLen,
                                                     uint8_t Radix);
 
+/**
+ * Obtain a constant value for a byte type.
+ *
+ * The returned value corresponds to a llvm::ConstantByte.
+ *
+ * @see llvm::ConstantByte::get()
+ *
+ * @param ByteTy Byte type to obtain value of.
+ * @param N The value the returned instance should refer to.
+ */
+LLVMValueRef LLVMConstByte(LLVMTypeRef ByteTy, unsigned long long N);
+
+/**
+ * Obtain a constant value for a byte of arbitrary precision.
+ *
+ * @see llvm::ConstantByte::get()
+ */
+LLVMValueRef LLVMConstByteOfArbitraryPrecision(LLVMTypeRef ByteTy,
+                                               unsigned NumWords,
+                                               const uint64_t Words[]);
+
+/**
+ * Obtain a constant value for a byte parsed from a string.
+ *
+ * A similar API, LLVMConstByteOfStringAndSize is also available. If the
+ * string's length is available, it is preferred to call that function
+ * instead.
+ *
+ * @see llvm::ConstantByte::get()
+ */
+LLVMValueRef LLVMConstByteOfString(LLVMTypeRef ByteTy, const char *Text,
+                                   uint8_t Radix);
+
+/**
+ * Obtain a constant value for a byte parsed from a string with specified
+ * length.
+ * @see llvm::ConstantByte::get()
+ */
+LLVMValueRef LLVMConstByteOfStringAndSize(LLVMTypeRef ByteTy, const char *Text,
+                                          unsigned SLen, uint8_t Radix);
+
 /**
  * Obtain a constant value referring to a double floating point value.
  */
@@ -2433,6 +2512,20 @@ LLVMConstIntGetZExtValue(LLVMValueRef ConstantVal);
  */
 LLVM_C_ABI long long LLVMConstIntGetSExtValue(LLVMValueRef ConstantVal);
 
+/**
+ * Obtain the zero extended value for a byte constant value.
+ *
+ * @see llvm::ConstantByte::getZExtValue()
+ */
+unsigned long long LLVMConstByteGetZExtValue(LLVMValueRef ConstantVal);
+
+/**
+ * Obtain the sign extended value for a byte constant value.
+ *
+ * @see llvm::ConstantByte::getSExtValue()
+ */
+long long LLVMConstByteGetSExtValue(LLVMValueRef ConstantVal);
+
 /**
  * Obtain the double value for an floating point constant value.
  * losesInfo indicates if some precision was lost in the conversion.
diff --git a/llvm/include/llvm/Analysis/IR2Vec.h b/llvm/include/llvm/Analysis/IR2Vec.h
index fdaed0f0901a9..e795e3b86f20f 100644
--- a/llvm/include/llvm/Analysis/IR2Vec.h
+++ b/llvm/include/llvm/Analysis/IR2Vec.h
@@ -286,6 +286,7 @@ class Vocabulary {
     VectorTy,
     TokenTy,
     IntegerTy,
+    ByteTy,
     FunctionTy,
     PointerTy,
     StructTy,
@@ -459,9 +460,9 @@ class Vocabulary {
 
   /// String mappings for CanonicalTypeID values
   static constexpr StringLiteral CanonicalTypeNames[] = {
-      "FloatTy",   "VoidTy",   "LabelTy",   "MetadataTy",
-      "VectorTy",  "TokenTy",  "IntegerTy", "FunctionTy",
-      "PointerTy", "StructTy", "ArrayTy",   "UnknownTy"};
+      "FloatTy",  "VoidTy",    "LabelTy",  "MetadataTy", "VectorTy",
+      "TokenTy",  "IntegerTy", "ByteTy",   "FunctionTy", "PointerTy",
+      "StructTy", "ArrayTy",   "UnknownTy"};
   static_assert(std::size(CanonicalTypeNames) ==
                     static_cast<unsigned>(CanonicalTypeID::MaxCanonicalType),
                 "CanonicalTypeNames array size must match MaxCanonicalType");
@@ -489,6 +490,7 @@ class Vocabulary {
       CanonicalTypeID::VectorTy,   // X86_AMXTyID
       CanonicalTypeID::TokenTy,    // TokenTyID
       CanonicalTypeID::IntegerTy,  // IntegerTyID
+      CanonicalTypeID::ByteTy,     // ByteTyID
       CanonicalTypeID::FunctionTy, // FunctionTyID
       CanonicalTypeID::PointerTy,  // PointerTyID
       CanonicalTypeID::StructTy,   // StructTyID
diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
index 20d19f21a64ce..592bdf3a34949 100644
--- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h
+++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
@@ -177,6 +177,8 @@ enum TypeCodes {
   TYPE_CODE_OPAQUE_POINTER = 25, // OPAQUE_POINTER: [addrspace]
 
   TYPE_CODE_TARGET_TYPE = 26, // TARGET_TYPE
+
+  TYPE_CODE_BYTE = 27, // BYTE: [width]
 };
 
 enum OperandBundleTagCode {
@@ -440,6 +442,8 @@ enum ConstantsCodes {
   CST_CODE_PTRAUTH = 33,              // [ptr, key, disc, addrdisc]
   CST_CODE_PTRAUTH2 = 34,             // [ptr, key, disc, addrdisc,
                                       //  deactivation_symbol]
+  CST_CODE_BYTE = 35,                 // BYTE:          [intval]
+  CST_CODE_WIDE_BYTE = 36,            // WIDE_BYTE:     [n x intval]
 };
 
 /// 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 f35b249e9686d..e754ffb580359 100644
--- a/llvm/include/llvm/IR/Constants.h
+++ b/llvm/include/llvm/IR/Constants.h
@@ -276,6 +276,199 @@ class ConstantInt final : public ConstantData {
   }
 };
 
+//===----------------------------------------------------------------------===//
+/// Class for constant bytes.
+class ConstantByte final : public ConstantData {
+  friend class Constant;
+  friend class ConstantVector;
+
+  APInt Val;
+
+  ConstantByte(Type *Ty, const APInt &V);
+
+  void destroyConstantImpl();
+
+  /// Return a ConstantByte with the specified value and an implied Type. The
+  /// type is the vector type whose byte element type corresponds to the bit
+  /// width of the value.
+  static ConstantByte *get(LLVMContext &Context, ElementCount EC,
+                           const APInt &V);
+
+public:
+  ConstantByte(const ConstantByte &) = delete;
+
+  LLVM_ABI static ConstantByte *getTrue(LLVMContext &Context);
+  LLVM_ABI static ConstantByte *getFalse(LLVMContext &Context);
+  LLVM_ABI static ConstantByte *getBool(LLVMContext &Context, bool V);
+  LLVM_ABI static Constant *getTrue(Type *Ty);
+  LLVM_ABI static Constant *getFalse(Type *Ty);
+  LLVM_ABI static Constant *getBool(Type *Ty, bool V);
+
+  /// If Ty is a vector type, return a Constant with a splat of the given
+  /// value. Otherwise return a ConstantByte for the given value.
+  /// \param ImplicitTrunc Whether to allow implicit truncation of the value.
+  LLVM_ABI static Constant *get(Type *Ty, uint64_t V, bool isSigned = false,
+                                bool ImplicitTrunc = false);
+
+  /// Return a ConstantByte with the specified byte value for the specified
+  /// type. If the type is wider than 64 bits, the value will be zero-extended
+  /// to fit the type, unless IsSigned is true, in which case the value will
+  /// be interpreted as a 64-bit signed byte and sign-extended to fit
+  /// the type.
+  /// \param ImplicitTrunc Whether to allow implicit truncation of the value.
+  LLVM_ABI static ConstantByte *get(ByteType *Ty, uint64_t V,
+                                    bool isSigned = false,
+                                    bool ImplicitTrunc = false);
+
+  /// Return a ConstantByte with the specified value for the specified type. The
+  /// value V will be canonicalized to an unsigned APInt. Accessing it with
+  /// either getSExtValue() or getZExtValue() will yield a correctly sized and
+  /// signed value for the type Ty.
+  /// Get a ConstantByte for a specific signed value.
+  /// \param ImplicitTrunc Whether to allow implicit truncation of the value.
+  static ConstantByte *getSigned(ByteType *Ty, int64_t V,
+                                 bool ImplicitTrunc = false) {
+    return get(Ty, V, /*IsSigned=*/true, ImplicitTrunc);
+  }
+  static Constant *getSigned(Type *Ty, int64_t V, bool ImplicitTrunc = false) {
+    return get(Ty, V, /*IsSigned=*/true, ImplicitTrunc);
+  }
+
+  /// Return a ConstantByte with the specified value and an implied Type. The
+  /// type is the byte type that corresponds to the bit width of the value.
+  LLVM_ABI static ConstantByte *get(LLVMContext &Context, const APInt &V);
+
+  /// Return a ConstantByte constructed from the string strStart with the given
+  /// radix.
+  LLVM_ABI static ConstantByte *get(ByteType *Ty, StringRef Str, uint8_t Radix);
+
+  /// If Ty is a vector type, return a Constant with a splat of the given
+  /// value. Otherwise return a ConstantByte for the given value.
+  LLVM_ABI static Constant *get(Type *Ty, const APInt &V);
+
+  /// Return the constant as an APInt value reference. This allows clients to
+  /// obtain a full-precision copy of the value.
+  /// Return the constant's value.
+  inline const APInt &getValue() const { return Val; }
+
+  /// getBitWidth - Return the scalar bitwidth of this constant.
+  unsigned getBitWidth() const { return Val.getBitWidth(); }
+
+  /// Return the constant as a 64-bit byte value after it
+  /// has been zero extended as appropriate for the type of this constant. Note
+  /// that this method can assert if the value does not fit in 64 bits.
+  /// Return the zero extended value.
+  inline uint64_t getZExtValue() const { return Val.getZExtValue(); }
+
+  /// Return the constant as a 64-bit byte value after it has been sign
+  /// extended as appropriate for the type of this constant. Note that
+  /// this method can assert if the value does not fit in 64 bits.
+  /// Return the sign extended value.
+  inline int64_t getSExtValue() const { return Val.getSExtValue(); }
+
+  /// Return the constant as an llvm::MaybeAlign.
+  /// Note that this method can assert if the value does not fit in 64 bits or
+  /// is not a power of two.
+  inline MaybeAlign getMaybeAlignValue() const {
+    return MaybeAlign(getZExtValue());
+  }
+
+  /// Return the constant as an llvm::Align, interpreting `0` as `Align(1)`.
+  /// Note that this method can assert if the value does not fit in 64 bits or
+  /// is not a power of two.
+  inline Align getAlignValue() const {
+    return getMaybeAlignValue().valueOrOne();
+  }
+
+  /// A helper method that can be used to determine if the constant contained
+  /// within is equal to a constant.  This only works for very small values,
+  /// because this is all that can be represented with all types.
+  /// Determine if this constant's value is same as an unsigned char.
+  bool equalsByte(uint64_t V) const { return Val == V; }
+
+  /// Variant of the getType() method to always return a ByteType, which
+  /// reduces the amount of casting needed in parts of the compiler.
+  inline ByteType *getByteType() const {
+    return cast<ByteType>(Value::getType());
+  }
+
+  /// This static method returns true if the type Ty is big enough to
+  /// represent the value V. This can be used to avoid having the get method
+  /// assert when V is larger than Ty can represent. Note that there are two
+  /// versions of this method, one for unsigned and one for signed integers.
+  /// Although ConstantByte canonicalizes everything to an unsigned integer,
+  /// the signed version avoids callers having to convert a signed quantity
+  /// to the appropriate unsigned type before calling the method.
+  /// @returns true if V is a valid value for type Ty
+  /// Determine if the value is in range for the given type.
+  LLVM_ABI static bool isValueValidForType(Type *Ty, uint64_t V);
+  LLVM_ABI static bool isValueValidForType(Type *Ty, int64_t V);
+
+  bool isNegative() const { return Val.isNegative(); }
+
+  /// This is just a convenience method to make client code smaller for a
+  /// common code. It also correctly performs the comparison without the
+  /// potential for an assertion from getZExtValue().
+  bool isZero() const { return Val.isZero(); }
+
+  /// This is just a convenience method to make client code smaller for a
+  /// common case. It also correctly performs the comparison without the
+  /// potential for an assertion from getZExtValue().
+  /// Determine if the value is one.
+  bool isOne() const { return Val.isOne(); }
+
+  /// This function will return true iff every bit in this constant is set
+  /// to true.
+  /// @returns true iff this constant's bits are all set to true.
+  /// Determine if the value is all ones.
+  bool isMinusOne() const { return Val.isAllOnes(); }
+
+  /// This function will return true iff this constant represents the largest
+  /// value that may be represented by the constant's type.
+  /// @returns true iff this is the largest value that may be represented
+  /// by this type.
+  /// Determine if the value is maximal.
+  bool isMaxValue(bool IsSigned) const {
+    if (IsSigned)
+      return Val.isMaxSignedValue();
+    else
+      return Val.isMaxValue();
+  }
+
+  /// This function will return true iff this constant represents the smallest
+  /// value that may be represented by this constant's type.
+  /// @returns true if this is the smallest value that may be represented by
+  /// this type.
+  /// Determine if the value is minimal.
+  bool isMinValue(bool IsSigned) const {
+    if (IsSigned)
+      return Val.isMinSignedValue();
+    else
+      return Val.isMinValue();
+  }
+
+  /// This function will return true iff this constant represents a value with
+  /// active bits bigger than 64 bits or a value greater than the given uint64_t
+  /// value.
+  /// @returns true iff this constant is greater or equal to the given number.
+  /// Determine if the value is greater or equal to the given number.
+  bool uge(uint64_t Num) const { return Val.uge(Num); }
+
+  /// getLimitedValue - If the value is smaller than the specified limit,
+  /// return it, otherwise return the limit value.  This causes the value
+  /// to saturate to the limit.
+  /// @returns the min of the value of the constant and the specified value
+  /// Get the constant's value with a saturation limit
+  uint64_t getLimitedValue(uint64_t Limit = ~0ULL) const {
+    return Val.getLimitedValue(Limit);
+  }
+
+  /// Methods to support type inquiry through isa, cast, and dyn_cast.
+  static bool classof(const Value *V) {
+    return V->getValueID() == ConstantByteVal;
+  }
+};
+
 //===----------------------------------------------------------------------===//
 /// ConstantFP - Floating Point Values [float, double]
 ///
@@ -588,10 +781,10 @@ class ConstantPointerNull final : public ConstantData {
 
 //===----------------------------------------------------------------------===//
 /// ConstantDataSequential - A vector or array constant whose element type is a
-/// simple 1/2/4/8-byte integer or half/bfloat/float/double, and whose elements
-/// are just simple data values (i.e. ConstantInt/ConstantFP).  This Constant
-/// node has no operands because it stores all of the elements of the constant
-/// as densely packed data, instead of as Value*'s.
+/// simple 1/2/4/8-byte integer/byte or half/bfloat/float/double, and whose
+/// elements are just simple data values (i.e. ConstantInt/ConstantByte/
+/// ConstantFP).  This Constant node has no operands because it stores all of
+/// the elements of the constant as densely packed data, instead of as Value*'s.
 ///
 /// This is the common base class of ConstantDataArray and ConstantDataVector.
 ///
@@ -661,7 +854,8 @@ class ConstantDataSequential : public ConstantData {
   /// The size of the elements is known to be a multiple of one byte.
   LLVM_ABI uint64_t getElementByteSize() const;
 
-  /// This method returns true if this is an array of \p CharSize integers.
+  /// This method returns true if this is an array of \p CharSize integers or
+  /// bytes.
   LLVM_ABI bool isString(unsigned CharSize = 8) const;
 
   /// This method returns true if the array "isString", ends with a null byte,
@@ -699,8 +893,8 @@ class ConstantDataSequential : public ConstantData {
 };
 
 //===----------------------------------------------------------------------===//
-/// An array constant whose element type is a simple 1/2/4/8-byte integer or
-/// float/double, and whose elements are just simple data values
+/// An array constant whose element type is a simple 1/2/4/8-byte integer, bytes
+//  or float/double, and whose elements are just simple data values
 /// (i.e. ConstantInt/ConstantFP). This Constant node has no operands because it
 /// stores all of the elements of the constant as densely packed data, instead
 /// of as Value*'s.
@@ -733,9 +927,9 @@ class ConstantDataArray final : public ConstantDataSequential {
   /// getRaw() constructor - Return a constant with array type with an element
   /// count and element type matching the NumElements and ElementTy parameters
   /// passed in. Note that this can return a ConstantAggregateZero object.
-  /// ElementTy must be one of i8/i16/i32/i64/half/bfloat/float/double. Data is
-  /// the buffer containing the elements. Be careful to make sure Data uses the
-  /// right endianness, the buffer will be used as-is.
+  /// ElementTy must be one of i8/i16/i32/i64/b8/b16/b32/b64/half/bfloat/float/
+  ///  double. Data is the buffer containing the elements. Be careful to make
+  /// sure Data uses the right endianness, the buffer will be used as-is.
   static Constant *getRaw(StringRef Data, uint64_t NumElements,
                           Type *ElementTy) {
     Type *Ty = ArrayType::get(ElementTy, NumElements);
@@ -752,13 +946,25 @@ class ConstantDataArray final : public ConstantDataSequential {
   LLVM_ABI static Constant *getFP(Type *ElementType, ArrayRef<uint32_t> Elts);
   LLVM_ABI static Constant *getFP(Type *ElementType, ArrayRef<uint64_t> Elts);
 
+  /// getByte() constructors - Return a constant of array type with a byte
+  /// element type taken from argument `ElementType', and count taken from
+  /// argument `Elts'.  The amount of bits of the contained type must match the
+  /// number of bits of the type contained in the passed in ArrayRef.
+  /// Note that this can return a ConstantAggregateZero object.
+  LLVM_ABI static Constant *getByte(Type *ElementType, ArrayRef<uint8_t> Elts);
+  LLVM_ABI static Constant *getByte(Type *ElementType, ArrayRef<uint16_t> Elts);
+  LLVM_ABI static Constant *getByte(Type *ElementType, ArrayRef<uint32_t> Elts);
+  LLVM_ABI static Constant *getByte(Type *ElementType, ArrayRef<uint64_t> Elts);
+
   /// This method constructs a CDS and initializes it with a text string.
   /// The default behavior (AddNull==true) causes a null terminator to
   /// be placed at the end of the array (increasing the length of the string by
   /// one more than the StringRef would normally indicate.  Pass AddNull=false
   /// to disable this behavior.
-  LLVM_ABI static Constant *
-  getString(LLVMContext &Context, StringRef Initializer, bool AddNull = true);
+  LLVM_ABI static Constant *getString(LLVMContext &Context,
+                                      StringRef Initializer,
+                                      bool AddNull = true,
+                                      bool ByteString = false);
 
   /// Specialize the getType() method to always return an ArrayType,
   /// which reduces the amount of casting needed in parts of the compiler.
@@ -805,15 +1011,24 @@ class ConstantDataVector final : public ConstantDataSequential {
   /// getRaw() constructor - Return a constant with vector type with an element
   /// count and element type matching the NumElements and ElementTy parameters
   /// passed in. Note that this can return a ConstantAggregateZero object.
-  /// ElementTy must be one of i8/i16/i32/i64/half/bfloat/float/double. Data is
-  /// the buffer containing the elements. Be careful to make sure Data uses the
-  /// right endianness, the buffer will be used as-is.
+  /// ElementTy must be one of i8/i16/i32/i64/b8/b16/b32/b64/half/bfloat/float/
+  /// double. Data is the buffer containing the elements. Be careful to make
+  /// sure Data uses the right endianness, the buffer will be used as-is.
   static Constant *getRaw(StringRef Data, uint64_t NumElements,
                           Type *ElementTy) {
     Type *Ty = VectorType::get(ElementTy, ElementCount::getFixed(NumElements));
     return getImpl(Data, Ty);
   }
 
+  /// getByte() constructors - Return a constant of vector type with a byte
+  /// element type taken from argument `ElementType', and count taken from
+  /// argument `Elts'.  The amount of bits of the contained type must match the
+  /// number of bits of the type contained in the passed in ArrayRef.
+  LLVM_ABI static Constant *getByte(Type *ElementType, ArrayRef<uint8_t> Elts);
+  LLVM_ABI static Constant *getByte(Type *ElementType, ArrayRef<uint16_t> Elts);
+  LLVM_ABI static Constant *getByte(Type *ElementType, ArrayRef<uint32_t> Elts);
+  LLVM_ABI static Constant *getByte(Type *ElementType, ArrayRef<uint64_t> Elts);
+
   /// getFP() constructors - Return a constant of vector type with a float
   /// element type taken from argument `ElementType', and count taken from
   /// argument `Elts'.  The amount of bits of the contained type must match the
@@ -826,7 +1041,8 @@ class ConstantDataVector final : public ConstantDataSequential {
 
   /// Return a ConstantVector with the specified constant in each element.
   /// The specified constant has to be a of a compatible type (i8/i16/
-  /// i32/i64/half/bfloat/float/double) and must be a ConstantFP or ConstantInt.
+  /// i32/i64/b8/b16/b32/b64/half/bfloat/float/double) and must be a ConstantFP,
+  /// ConstantByte or ConstantInt.
   LLVM_ABI static Constant *getSplat(unsigned NumElts, Constant *Elt);
 
   /// Returns true if this is a splat constant, meaning that all elements have
diff --git a/llvm/include/llvm/IR/DataLayout.h b/llvm/include/llvm/IR/DataLayout.h
index 4d695e1e5c566..bc54269e5e762 100644
--- a/llvm/include/llvm/IR/DataLayout.h
+++ b/llvm/include/llvm/IR/DataLayout.h
@@ -637,6 +637,11 @@ class DataLayout {
   /// This is always at least as good as the ABI alignment.
   LLVM_ABI Align getPrefTypeAlign(Type *Ty) const;
 
+  /// Returns a byte type with size at least as big as that of a
+  /// pointer in the given address space.
+  LLVM_ABI ByteType *getBytePtrType(LLVMContext &C,
+                                    unsigned AddressSpace = 0) const;
+
   /// Returns an integer type with size at least as big as that of a
   /// pointer in the given address space.
   LLVM_ABI IntegerType *getIntPtrType(LLVMContext &C,
@@ -646,6 +651,18 @@ class DataLayout {
   /// big as that of a pointer of the given pointer (vector of pointer) type.
   LLVM_ABI Type *getIntPtrType(Type *) const;
 
+  /// Returns an integer (vector of integer) type with size at least as
+  /// big as that of a byte of the given byte (vector of byte) type.
+  LLVM_ABI Type *getIntByteType(Type *) const;
+
+  /// Returns a byte (vector of byte) type with size at least as big as that of
+  /// a pointer of the given pointer (vector of pointer) type.
+  LLVM_ABI Type *getBytePtrType(Type *) const;
+
+  /// Returns a byte (vector of byte) type with size at least as big as that of
+  /// an integer of the given integer (vector of integer) type.
+  LLVM_ABI Type *getByteIntType(Type *) const;
+
   /// Returns the smallest integer type with size at least as big as
   /// Width bits.
   LLVM_ABI Type *getSmallestLegalIntType(LLVMContext &C,
@@ -784,6 +801,8 @@ inline TypeSize DataLayout::getTypeSizeInBits(Type *Ty) const {
   case Type::StructTyID:
     // Get the layout annotation... which is lazily created on demand.
     return getStructLayout(cast<StructType>(Ty))->getSizeInBits();
+  case Type::ByteTyID:
+    return TypeSize::getFixed(Ty->getByteBitWidth());
   case Type::IntegerTyID:
     return TypeSize::getFixed(Ty->getIntegerBitWidth());
   case Type::HalfTyID:
diff --git a/llvm/include/llvm/IR/DerivedTypes.h b/llvm/include/llvm/IR/DerivedTypes.h
index b22177c9e6c2d..876c4c8c871ce 100644
--- a/llvm/include/llvm/IR/DerivedTypes.h
+++ b/llvm/include/llvm/IR/DerivedTypes.h
@@ -100,6 +100,62 @@ unsigned Type::getIntegerBitWidth() const {
   return cast<IntegerType>(this)->getBitWidth();
 }
 
+/// Class to represent byte types. Note that this class is also used to
+/// represent the built-in byte types: Byte8Ty, Byte16Ty, Byte32Ty and
+/// Byte64Ty.
+/// Byte representation type
+class ByteType : public Type {
+  friend class LLVMContextImpl;
+
+protected:
+  explicit ByteType(LLVMContext &C, unsigned NumBits) : Type(C, ByteTyID) {
+    setSubclassData(NumBits);
+  }
+
+public:
+  /// This enum is just used to hold constants we need for ByteType.
+  enum {
+    MIN_BYTE_BITS = 1, ///< Minimum number of bits that can be specified
+    MAX_BYTE_BITS =
+        (1 << 23) ///< Maximum number of bits that can be specified
+                  ///< Note that bit width is stored in the Type classes
+                  ///< SubclassData field which has 24 bits. SelectionDAG type
+                  ///< legalization can require a power of 2 ByteType, so limit
+                  ///< to the largest representable power of 2, 8388608.
+  };
+
+  /// This static method is the primary way of constructing a ByteType.
+  /// If a ByteType with the same NumBits value was previously instantiated,
+  /// that instance will be returned. Otherwise a new one will be created. Only
+  /// one instance with a given NumBits value is ever created.
+  /// Get or create a ByteType instance.
+  LLVM_ABI static ByteType *get(LLVMContext &C, unsigned NumBits);
+
+  /// Returns type twice as wide the input type.
+  ByteType *getExtendedType() const {
+    return Type::getByteNTy(getContext(), 2 * getScalarSizeInBits());
+  }
+
+  /// Get the number of bits in this ByteType
+  unsigned getBitWidth() const { return getSubclassData(); }
+
+  /// Return a bitmask with ones set for all of the bits. This is 0xFF for i8,
+  /// 0xFFFF for i16, etc.
+  uint64_t getBitMask() const { return ~uint64_t(0UL) >> (64 - getBitWidth()); }
+
+  /// For example, this is 0xFF for an 8 bit byte, 0xFFFF for b16, etc.
+  /// @returns a bit mask with ones set for all the bits of this type.
+  /// Get a bit mask for this type.
+  LLVM_ABI APInt getMask() const;
+
+  /// Methods for support type inquiry through isa, cast, and dyn_cast.
+  static bool classof(const Type *T) { return T->getTypeID() == ByteTyID; }
+};
+
+unsigned Type::getByteBitWidth() const {
+  return cast<ByteType>(this)->getBitWidth();
+}
+
 /// Class to represent function types
 ///
 class FunctionType : public Type {
diff --git a/llvm/include/llvm/IR/IRBuilder.h b/llvm/include/llvm/IR/IRBuilder.h
index 2d6bafdec2c16..ddf0538e0a30e 100644
--- a/llvm/include/llvm/IR/IRBuilder.h
+++ b/llvm/include/llvm/IR/IRBuilder.h
@@ -543,6 +543,24 @@ class IRBuilderBase {
   // Type creation methods
   //===--------------------------------------------------------------------===//
 
+  /// Fetch the type representing an 8-bit byte.
+  ByteType *getByte8Ty() { return Type::getByte8Ty(Context); }
+
+  /// Fetch the type representing a 16-bit byte.
+  ByteType *getByte16Ty() { return Type::getByte16Ty(Context); }
+
+  /// Fetch the type representing a 32-bit byte.
+  ByteType *getByte32Ty() { return Type::getByte32Ty(Context); }
+
+  /// Fetch the type representing a 64-bit byte.
+  ByteType *getByte64Ty() { return Type::getByte64Ty(Context); }
+
+  /// Fetch the type representing a 128-bit byte.
+  ByteType *getByte128Ty() { return Type::getByte128Ty(Context); }
+
+  /// Fetch the type representing an N-bit byte.
+  ByteType *getByteNTy(unsigned N) { return Type::getByteNTy(Context, N); }
+
   /// Fetch the type representing a single bit
   IntegerType *getInt1Ty() {
     return Type::getInt1Ty(Context);
@@ -606,6 +624,12 @@ class IRBuilderBase {
     return PointerType::get(Context, AddrSpace);
   }
 
+  /// Fetch the type of a byte with size at least as big as that of a
+  /// pointer in the given address space.
+  ByteType *getBytePtrTy(const DataLayout &DL, unsigned AddrSpace = 0) {
+    return DL.getBytePtrType(Context, AddrSpace);
+  }
+
   /// Fetch the type of an integer with size at least as big as that of a
   /// pointer in the given address space.
   IntegerType *getIntPtrTy(const DataLayout &DL, unsigned AddrSpace = 0) {
diff --git a/llvm/include/llvm/IR/Type.h b/llvm/include/llvm/IR/Type.h
index 44db4ef163a64..56417ee14796f 100644
--- a/llvm/include/llvm/IR/Type.h
+++ b/llvm/include/llvm/IR/Type.h
@@ -26,6 +26,7 @@
 
 namespace llvm {
 
+class ByteType;
 class IntegerType;
 struct fltSemantics;
 class LLVMContext;
@@ -68,6 +69,7 @@ class Type {
 
     // Derived types... see DerivedTypes.h file.
     IntegerTyID,        ///< Arbitrary bit width integers
+    ByteTyID,           ///< Arbitrary bit width bytes
     FunctionTyID,       ///< Functions
     PointerTyID,        ///< Pointers
     StructTyID,         ///< Structures
@@ -236,6 +238,21 @@ class Type {
   /// Returns true if this is 'token' or a token-like target type.s
   LLVM_ABI bool isTokenLikeTy() const;
 
+  /// True if this is an instance of ByteType.
+  bool isByteTy() const { return getTypeID() == ByteTyID; }
+
+  /// Return true if this is a ByteType of the given width.
+  LLVM_ABI bool isByteTy(unsigned BitWidth) const;
+
+  /// Return true if this is a byte type or a vector of byte types.
+  bool isByteOrByteVectorTy() const { return getScalarType()->isByteTy(); }
+
+  /// Return true if this is a byte type or a vector of byte types of
+  /// the given width.
+  bool isByteOrByteVectorTy(unsigned BitWidth) const {
+    return getScalarType()->isByteTy(BitWidth);
+  }
+
   /// True if this is an instance of IntegerType.
   bool isIntegerTy() const { return getTypeID() == IntegerTyID; }
 
@@ -295,7 +312,7 @@ class Type {
   /// includes all first-class types except struct and array types.
   bool isSingleValueType() const {
     return isFloatingPointTy() || isIntegerTy() || isPointerTy() ||
-           isVectorTy() || isX86_AMXTy() || isTargetExtTy();
+           isVectorTy() || isX86_AMXTy() || isTargetExtTy() || isByteTy();
   }
 
   /// Return true if the type is an aggregate type. This means it is valid as
@@ -311,7 +328,8 @@ class Type {
   bool isSized(SmallPtrSetImpl<Type*> *Visited = nullptr) const {
     // If it's a primitive, it is always sized.
     if (getTypeID() == IntegerTyID || isFloatingPointTy() ||
-        getTypeID() == PointerTyID || getTypeID() == X86_AMXTyID)
+        getTypeID() == PointerTyID || getTypeID() == X86_AMXTyID ||
+        getTypeID() == ByteTyID)
       return true;
     // If it is not something that can have a size (e.g. a function or label),
     // it doesn't have a size.
@@ -394,6 +412,7 @@ class Type {
   // methods should not be added here.
 
   LLVM_ABI inline unsigned getIntegerBitWidth() const;
+  LLVM_ABI inline unsigned getByteBitWidth() const;
 
   LLVM_ABI inline Type *getFunctionParamType(unsigned i) const;
   LLVM_ABI inline unsigned getFunctionNumParams() const;
@@ -451,6 +470,13 @@ class Type {
   LLVM_ABI static Type *getPPC_FP128Ty(LLVMContext &C);
   LLVM_ABI static Type *getX86_AMXTy(LLVMContext &C);
   LLVM_ABI static Type *getTokenTy(LLVMContext &C);
+  LLVM_ABI static ByteType *getByteNTy(LLVMContext &C, unsigned N);
+  LLVM_ABI static ByteType *getByte1Ty(LLVMContext &C);
+  LLVM_ABI static ByteType *getByte8Ty(LLVMContext &C);
+  LLVM_ABI static ByteType *getByte16Ty(LLVMContext &C);
+  LLVM_ABI static ByteType *getByte32Ty(LLVMContext &C);
+  LLVM_ABI static ByteType *getByte64Ty(LLVMContext &C);
+  LLVM_ABI static ByteType *getByte128Ty(LLVMContext &C);
   LLVM_ABI static IntegerType *getIntNTy(LLVMContext &C, unsigned N);
   LLVM_ABI static IntegerType *getInt1Ty(LLVMContext &C);
   LLVM_ABI static IntegerType *getInt8Ty(LLVMContext &C);
diff --git a/llvm/include/llvm/IR/Value.def b/llvm/include/llvm/IR/Value.def
index 34b8d4967b28a..96160fbe3bcb4 100644
--- a/llvm/include/llvm/IR/Value.def
+++ b/llvm/include/llvm/IR/Value.def
@@ -82,6 +82,7 @@ HANDLE_CONSTANT(ConstantAggregateZero)
 HANDLE_CONSTANT(ConstantDataArray)
 HANDLE_CONSTANT(ConstantDataVector)
 HANDLE_CONSTANT(ConstantInt)
+HANDLE_CONSTANT(ConstantByte)
 HANDLE_CONSTANT(ConstantFP)
 HANDLE_CONSTANT(ConstantTargetNone)
 HANDLE_CONSTANT(ConstantPointerNull)
diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp
index 4e7e31da09a52..9cbb5d3c8c8e6 100644
--- a/llvm/lib/AsmParser/LLLexer.cpp
+++ b/llvm/lib/AsmParser/LLLexer.cpp
@@ -487,20 +487,26 @@ lltok::Kind LLLexer::LexHash() {
   return lltok::hash;
 }
 
-/// Lex a label, integer type, keyword, or hexadecimal integer constant.
+/// Lex a label, integer or byte types, keyword, or hexadecimal integer
+/// constant.
 ///    Label           [-a-zA-Z$._0-9]+:
+///    ByteType        b[0-9]+
 ///    IntegerType     i[0-9]+
 ///    Keyword         sdiv, float, ...
 ///    HexIntConstant  [us]0x[0-9A-Fa-f]+
 lltok::Kind LLLexer::LexIdentifier() {
   const char *StartChar = CurPtr;
-  const char *IntEnd = CurPtr[-1] == 'i' ? nullptr : StartChar;
+  const char IntOrByteIdentifier = CurPtr[-1];
+  const char *IntOrByteEnd =
+      (IntOrByteIdentifier == 'i' || IntOrByteIdentifier == 'b') ? nullptr
+                                                                 : StartChar;
   const char *KeywordEnd = nullptr;
 
   for (; isLabelChar(*CurPtr); ++CurPtr) {
-    // If we decide this is an integer, remember the end of the sequence.
-    if (!IntEnd && !isdigit(static_cast<unsigned char>(*CurPtr)))
-      IntEnd = CurPtr;
+    // If we decide this is a byte or an integer, remember the end of the
+    // sequence.
+    if (!IntOrByteEnd && !isdigit(static_cast<unsigned char>(*CurPtr)))
+      IntOrByteEnd = CurPtr;
     if (!KeywordEnd && !isalnum(static_cast<unsigned char>(*CurPtr)) &&
         *CurPtr != '_')
       KeywordEnd = CurPtr;
@@ -513,18 +519,23 @@ lltok::Kind LLLexer::LexIdentifier() {
     return lltok::LabelStr;
   }
 
-  // Otherwise, this wasn't a label.  If this was valid as an integer type,
-  // return it.
-  if (!IntEnd) IntEnd = CurPtr;
-  if (IntEnd != StartChar) {
-    CurPtr = IntEnd;
+  // Otherwise, this wasn't a label. If this was valid as a byte or an integer
+  // type, return it.
+  if (!IntOrByteEnd)
+    IntOrByteEnd = CurPtr;
+  if (IntOrByteEnd != StartChar) {
+    CurPtr = IntOrByteEnd;
     uint64_t NumBits = atoull(StartChar, CurPtr);
     if (NumBits < IntegerType::MIN_INT_BITS ||
         NumBits > IntegerType::MAX_INT_BITS) {
-      LexError("bitwidth for integer type out of range");
+      LexError("bitwidth for integer or byte type out of range");
       return lltok::Error;
     }
-    TyVal = IntegerType::get(Context, NumBits);
+    if (IntOrByteIdentifier == 'i')
+      TyVal = IntegerType::get(Context, NumBits);
+    else
+      TyVal = ByteType::get(Context, NumBits);
+
     return lltok::Type;
   }
 
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index 068b52fcf0995..1965efd37b968 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -4041,12 +4041,13 @@ bool LLParser::parseValID(ValID &ID, PerFunctionState *PFS, Type *ExpectedTy) {
     if (Elts.empty())
       return error(ID.Loc, "constant vector must not be empty");
 
-    if (!Elts[0]->getType()->isIntegerTy() &&
+    if (!Elts[0]->getType()->isIntegerTy() && !Elts[0]->getType()->isByteTy() &&
         !Elts[0]->getType()->isFloatingPointTy() &&
         !Elts[0]->getType()->isPointerTy())
       return error(
           FirstEltLoc,
-          "vector elements must have integer, pointer or floating point type");
+          "vector elements must have integer, byte, pointer or floating point "
+          "type");
 
     // Verify that all the vector elements have the same type.
     for (unsigned i = 1, e = Elts.size(); i != e; ++i)
@@ -4093,15 +4094,16 @@ bool LLParser::parseValID(ValID &ID, PerFunctionState *PFS, Type *ExpectedTy) {
     ID.Kind = ValID::t_Constant;
     return false;
   }
-  case lltok::kw_c:  // c "foo"
+  case lltok::kw_c: { // c "foo"
     Lex.Lex();
-    ID.ConstantVal = ConstantDataArray::getString(Context, Lex.getStrVal(),
-                                                  false);
+    ArrayType *ATy = static_cast<ArrayType *>(ExpectedTy);
+    ID.ConstantVal = ConstantDataArray::getString(
+        Context, Lex.getStrVal(), false, ATy->getElementType()->isByteTy());
     if (parseToken(lltok::StringConstant, "expected string"))
       return true;
     ID.Kind = ValID::t_Constant;
     return false;
-
+  }
   case lltok::kw_asm: {
     // ValID ::= 'asm' SideEffect? AlignStack? IntelDialect? STRINGCONSTANT ','
     //             STRINGCONSTANT
@@ -6552,10 +6554,11 @@ bool LLParser::convertValIDToValue(Type *Ty, ValID &ID, Value *&V,
       V = NoCFIValue::get(cast<GlobalValue>(V));
     return V == nullptr;
   case ValID::t_APSInt:
-    if (!Ty->isIntegerTy())
-      return error(ID.Loc, "integer constant must have integer type");
+    if (!Ty->isIntegerTy() && !Ty->isByteTy())
+      return error(ID.Loc, "integer/byte constant must have integer/byte type");
     ID.APSIntVal = ID.APSIntVal.extOrTrunc(Ty->getPrimitiveSizeInBits());
-    V = ConstantInt::get(Context, ID.APSIntVal);
+    Ty->isIntegerTy() ? V = ConstantInt::get(Context, ID.APSIntVal)
+                      : V = ConstantByte::get(Context, ID.APSIntVal);
     return false;
   case ValID::t_APFloat:
     if (!Ty->isFloatingPointTy() ||
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index 036f3c2964997..550972a252e90 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -2621,6 +2621,17 @@ Error BitcodeReader::parseTypeTableBody() {
     case bitc::TYPE_CODE_TOKEN:     // TOKEN
       ResultTy = Type::getTokenTy(Context);
       break;
+    case bitc::TYPE_CODE_BYTE: { // BYTE: [width]
+      if (Record.empty())
+        return error("Invalid record");
+
+      uint64_t NumBits = Record[0];
+      if (NumBits < ByteType::MIN_BYTE_BITS ||
+          NumBits > ByteType::MAX_BYTE_BITS)
+        return error("Bitwidth for byte type out of range");
+      ResultTy = ByteType::get(Context, NumBits);
+      break;
+    }
     case bitc::TYPE_CODE_INTEGER: { // INTEGER: [width]
       if (Record.empty())
         return error("Invalid integer record");
@@ -3319,6 +3330,20 @@ Error BitcodeReader::parseConstants() {
       V = ConstantInt::get(CurTy, VInt);
       break;
     }
+    case bitc::CST_CODE_BYTE: // BYTE: [byteval]
+      if (!CurTy->isByteOrByteVectorTy() || Record.empty())
+        return error("Invalid byte const record");
+      V = ConstantByte::get(CurTy, decodeSignRotatedValue(Record[0]));
+      break;
+    case bitc::CST_CODE_WIDE_BYTE: { // WIDE_BYTE: [n x byteval]
+      if (!CurTy->isByteOrByteVectorTy() || Record.empty())
+        return error("Invalid wide byte const record");
+
+      auto *ScalarTy = cast<ByteType>(CurTy->getScalarType());
+      APInt VByte = readWideAPInt(Record, ScalarTy->getBitWidth());
+      V = ConstantByte::get(CurTy, VByte);
+      break;
+    }
     case bitc::CST_CODE_FLOAT: {    // FLOAT: [fpval]
       if (Record.empty())
         return error("Invalid float const record");
@@ -3381,8 +3406,9 @@ Error BitcodeReader::parseConstants() {
         return error("Invalid string record");
 
       SmallString<16> Elts(Record.begin(), Record.end());
-      V = ConstantDataArray::getString(Context, Elts,
-                                       BitCode == bitc::CST_CODE_CSTRING);
+      V = ConstantDataArray::getString(
+          Context, Elts, BitCode == bitc::CST_CODE_CSTRING,
+          cast<ArrayType>(CurTy)->getElementType()->isByteTy());
       break;
     }
     case bitc::CST_CODE_DATA: {// DATA: [n x value]
@@ -3418,6 +3444,30 @@ Error BitcodeReader::parseConstants() {
           V = ConstantDataVector::get(Context, Elts);
         else
           V = ConstantDataArray::get(Context, Elts);
+      } else if (EltTy->isByteTy(8)) {
+        SmallVector<uint8_t, 16> Elts(Record.begin(), Record.end());
+        if (isa<VectorType>(CurTy))
+          V = ConstantDataVector::getByte(EltTy, Elts);
+        else
+          V = ConstantDataArray::getByte(EltTy, Elts);
+      } else if (EltTy->isByteTy(16)) {
+        SmallVector<uint16_t, 16> Elts(Record.begin(), Record.end());
+        if (isa<VectorType>(CurTy))
+          V = ConstantDataVector::getByte(EltTy, Elts);
+        else
+          V = ConstantDataArray::getByte(EltTy, Elts);
+      } else if (EltTy->isByteTy(32)) {
+        SmallVector<uint32_t, 16> Elts(Record.begin(), Record.end());
+        if (isa<VectorType>(CurTy))
+          V = ConstantDataVector::getByte(EltTy, Elts);
+        else
+          V = ConstantDataArray::getByte(EltTy, Elts);
+      } else if (EltTy->isByteTy(64)) {
+        SmallVector<uint64_t, 16> Elts(Record.begin(), Record.end());
+        if (isa<VectorType>(CurTy))
+          V = ConstantDataVector::getByte(EltTy, Elts);
+        else
+          V = ConstantDataArray::getByte(EltTy, Elts);
       } else if (EltTy->isHalfTy()) {
         SmallVector<uint16_t, 16> Elts(Record.begin(), Record.end());
         if (isa<VectorType>(CurTy))
diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index 8bc98c92bc698..1e9058b9939b7 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -136,6 +136,7 @@ enum {
   // CONSTANTS_BLOCK abbrev id's.
   CONSTANTS_SETTYPE_ABBREV = bitc::FIRST_APPLICATION_ABBREV,
   CONSTANTS_INTEGER_ABBREV,
+  CONSTANTS_BYTE_ABBREV,
   CONSTANTS_CE_CAST_Abbrev,
   CONSTANTS_NULL_Abbrev,
 
@@ -1169,6 +1170,11 @@ void ModuleBitcodeWriter::writeTypeTable() {
       break;
     case Type::X86_AMXTyID:   Code = bitc::TYPE_CODE_X86_AMX;   break;
     case Type::TokenTyID:     Code = bitc::TYPE_CODE_TOKEN;     break;
+    case Type::ByteTyID:
+      // BYTE: [width]
+      Code = bitc::TYPE_CODE_BYTE;
+      TypeVals.push_back(T->getByteBitWidth());
+      break;
     case Type::IntegerTyID:
       // INTEGER: [width]
       Code = bitc::TYPE_CODE_INTEGER;
@@ -2863,6 +2869,16 @@ void ModuleBitcodeWriter::writeConstants(unsigned FirstVal, unsigned LastVal,
         emitWideAPInt(Record, IV->getValue());
         Code = bitc::CST_CODE_WIDE_INTEGER;
       }
+    } else if (const ConstantByte *BV = dyn_cast<ConstantByte>(C)) {
+      if (BV->getBitWidth() <= 64) {
+        uint64_t V = BV->getSExtValue();
+        emitSignedInt64(Record, V);
+        Code = bitc::CST_CODE_BYTE;
+        AbbrevToUse = CONSTANTS_BYTE_ABBREV;
+      } else { // Wide bytes, > 64 bits in size.
+        emitWideAPInt(Record, BV->getValue());
+        Code = bitc::CST_CODE_WIDE_BYTE;
+      }
     } else if (const ConstantFP *CFP = dyn_cast<ConstantFP>(C)) {
       Code = bitc::CST_CODE_FLOAT;
       Type *Ty = CFP->getType()->getScalarType();
@@ -2912,10 +2928,10 @@ void ModuleBitcodeWriter::writeConstants(unsigned FirstVal, unsigned LastVal,
       else if (isCStr7)
         AbbrevToUse = CString7Abbrev;
     } else if (const ConstantDataSequential *CDS =
-                  dyn_cast<ConstantDataSequential>(C)) {
+                   dyn_cast<ConstantDataSequential>(C)) {
       Code = bitc::CST_CODE_DATA;
       Type *EltTy = CDS->getElementType();
-      if (isa<IntegerType>(EltTy)) {
+      if (isa<IntegerType>(EltTy) || isa<ByteType>(EltTy)) {
         for (uint64_t i = 0, e = CDS->getNumElements(); i != e; ++i)
           Record.push_back(CDS->getElementAsInteger(i));
       } else {
@@ -3959,6 +3975,15 @@ void ModuleBitcodeWriter::writeBlockInfo() {
       llvm_unreachable("Unexpected abbrev ordering!");
   }
 
+  { // BYTE abbrev for CONSTANTS_BLOCK.
+    auto Abbv = std::make_shared<BitCodeAbbrev>();
+    Abbv->Add(BitCodeAbbrevOp(bitc::CST_CODE_BYTE));
+    Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));
+    if (Stream.EmitBlockInfoAbbrev(bitc::CONSTANTS_BLOCK_ID, Abbv) !=
+        CONSTANTS_BYTE_ABBREV)
+      llvm_unreachable("Unexpected abbrev ordering!");
+  }
+
   { // CE_CAST abbrev for CONSTANTS_BLOCK.
     auto Abbv = std::make_shared<BitCodeAbbrev>();
     Abbv->Add(BitCodeAbbrevOp(bitc::CST_CODE_CE_CAST));
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 420f09c514d63..4be7c59ce67f4 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -3708,6 +3708,9 @@ const MCExpr *AsmPrinter::lowerConstant(const Constant *CV,
   if (const ConstantInt *CI = dyn_cast<ConstantInt>(CV))
     return MCConstantExpr::create(CI->getZExtValue(), Ctx);
 
+  if (const ConstantByte *CB = dyn_cast<ConstantByte>(CV))
+    return MCConstantExpr::create(CB->getZExtValue(), Ctx);
+
   if (const ConstantPtrAuth *CPA = dyn_cast<ConstantPtrAuth>(CV))
     return lowerConstantPtrAuth(*CPA);
 
@@ -3963,7 +3966,8 @@ static void emitGlobalConstantDataSequential(
 
   // Otherwise, emit the values in successive locations.
   uint64_t ElementByteSize = CDS->getElementByteSize();
-  if (isa<IntegerType>(CDS->getElementType())) {
+  if (isa<IntegerType>(CDS->getElementType()) ||
+      isa<ByteType>(CDS->getElementType())) {
     for (uint64_t I = 0, E = CDS->getNumElements(); I != E; ++I) {
       emitGlobalAliasInline(AP, ElementByteSize * I, AliasList);
       if (AP.isVerbose())
@@ -4127,6 +4131,66 @@ static void emitGlobalConstantFP(const ConstantFP *CFP, AsmPrinter &AP) {
   emitGlobalConstantFP(CFP->getValueAPF(), CFP->getType(), AP);
 }
 
+static void emitGlobalConstantLargeByte(const ConstantByte *CB,
+                                        AsmPrinter &AP) {
+  const DataLayout &DL = AP.getDataLayout();
+  unsigned BitWidth = CB->getBitWidth();
+
+  // Copy the value as we may massage the layout for constants whose bit width
+  // is not a multiple of 64-bits.
+  APInt Realigned(CB->getValue());
+  uint64_t ExtraBits = 0;
+  unsigned ExtraBitsSize = BitWidth & 63;
+
+  if (ExtraBitsSize) {
+    // The bit width of the data is not a multiple of 64-bits.
+    // The extra bits are expected to be at the end of the chunk of the memory.
+    // Little endian:
+    // * Nothing to be done, just record the extra bits to emit.
+    // Big endian:
+    // * Record the extra bits to emit.
+    // * Realign the raw data to emit the chunks of 64-bits.
+    if (DL.isBigEndian()) {
+      // Basically the structure of the raw data is a chunk of 64-bits cells:
+      //    0        1         BitWidth / 64
+      // [chunk1][chunk2] ... [chunkN].
+      // The most significant chunk is chunkN and it should be emitted first.
+      // However, due to the alignment issue chunkN contains useless bits.
+      // Realign the chunks so that they contain only useful information:
+      // ExtraBits     0       1       (BitWidth / 64) - 1
+      //       chu[nk1 chu][nk2 chu] ... [nkN-1 chunkN]
+      ExtraBitsSize = alignTo(ExtraBitsSize, 8);
+      ExtraBits =
+          Realigned.getRawData()[0] & (((uint64_t)-1) >> (64 - ExtraBitsSize));
+      if (BitWidth >= 64)
+        Realigned.lshrInPlace(ExtraBitsSize);
+    } else
+      ExtraBits = Realigned.getRawData()[BitWidth / 64];
+  }
+
+  // We don't expect assemblers to support byte data directives
+  // for more than 64 bits, so we emit the data in at most 64-bit
+  // quantities at a time.
+  const uint64_t *RawData = Realigned.getRawData();
+  for (unsigned i = 0, e = BitWidth / 64; i != e; ++i) {
+    uint64_t Val = DL.isBigEndian() ? RawData[e - i - 1] : RawData[i];
+    AP.OutStreamer->emitIntValue(Val, 8);
+  }
+
+  if (ExtraBitsSize) {
+    // Emit the extra bits after the 64-bits chunks.
+
+    // Emit a directive that fills the expected size.
+    uint64_t Size = AP.getDataLayout().getTypeStoreSize(CB->getType());
+    Size -= (BitWidth / 64) * 8;
+    assert(Size && Size * 8 >= ExtraBitsSize &&
+           (ExtraBits & (((uint64_t)-1) >> (64 - ExtraBitsSize))) ==
+               ExtraBits &&
+           "Directive too small for extra bits.");
+    AP.OutStreamer->emitIntValue(ExtraBits, Size);
+  }
+}
+
 static void emitGlobalConstantLargeInt(const ConstantInt *CI, AsmPrinter &AP) {
   const DataLayout &DL = AP.getDataLayout();
   unsigned BitWidth = CI->getBitWidth();
@@ -4330,6 +4394,27 @@ static void emitGlobalConstantImpl(const DataLayout &DL, const Constant *CV,
     return;
   }
 
+  if (const ConstantByte *CB = dyn_cast<ConstantByte>(CV)) {
+    if (isa<VectorType>(CV->getType()))
+      return emitGlobalConstantVector(DL, CV, AP, AliasList);
+
+    const uint64_t StoreSize = DL.getTypeStoreSize(CV->getType());
+    if (StoreSize <= 8) {
+      if (AP.isVerbose())
+        AP.OutStreamer->getCommentOS()
+            << format("0x%" PRIx64 "\n", CB->getZExtValue());
+      AP.OutStreamer->emitIntValue(CB->getZExtValue(), StoreSize);
+    } else {
+      emitGlobalConstantLargeByte(CB, AP);
+    }
+
+    // Emit tail padding if needed
+    if (Size != StoreSize)
+      AP.OutStreamer->emitZeros(Size - StoreSize);
+
+    return;
+  }
+
   if (const ConstantFP *CFP = dyn_cast<ConstantFP>(CV)) {
     if (isa<VectorType>(CV->getType()))
       return emitGlobalConstantVector(DL, CV, AP, AliasList);
diff --git a/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp b/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
index 7eacdc0bd7bc4..d71ed4d4cb4ca 100644
--- a/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
@@ -479,7 +479,7 @@ void FunctionLoweringInfo::ComputePHILiveOutRegInfo(const PHINode *PN) {
     LiveOutInfo &DestLOI = LiveOutRegInfo[DestReg];
 
     Value *V = PN->getIncomingValue(0);
-    if (isa<UndefValue>(V) || isa<ConstantExpr>(V)) {
+    if (isa<UndefValue>(V) || isa<ConstantExpr>(V) || isa<ConstantByte>(V)) {
       DestLOI.NumSignBits = 1;
       DestLOI.Known = KnownBits(BitWidth);
       continue;
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 63c9d193421ea..2cbf2ae8105b7 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -1865,6 +1865,9 @@ SDValue SelectionDAGBuilder::getValueImpl(const Value *V) {
       return DAG.getConstant(*CI, DL, VT);
     }
 
+    if (const ConstantByte *CB = dyn_cast<ConstantByte>(C))
+      return DAG.getConstant(CB->getValue(), getCurSDLoc(), VT);
+
     if (const GlobalValue *GV = dyn_cast<GlobalValue>(C))
       return DAG.getGlobalAddress(GV, getCurSDLoc(), VT);
 
diff --git a/llvm/lib/CodeGen/ValueTypes.cpp b/llvm/lib/CodeGen/ValueTypes.cpp
index 0743c92c5b95b..e74068e22f4cd 100644
--- a/llvm/lib/CodeGen/ValueTypes.cpp
+++ b/llvm/lib/CodeGen/ValueTypes.cpp
@@ -254,6 +254,8 @@ MVT MVT::getVT(Type *Ty, bool HandleUnknown){
     llvm_unreachable("Unknown type!");
   case Type::VoidTyID:
     return MVT::isVoid;
+  case Type::ByteTyID:
+    return getIntegerVT(cast<ByteType>(Ty)->getBitWidth());
   case Type::IntegerTyID:
     return getIntegerVT(cast<IntegerType>(Ty)->getBitWidth());
   case Type::HalfTyID:      return MVT(MVT::f16);
@@ -304,6 +306,8 @@ EVT EVT::getEVT(Type *Ty, bool HandleUnknown){
     return MVT::getVT(Ty, HandleUnknown);
   case Type::TokenTyID:
     return MVT::Untyped;
+  case Type::ByteTyID:
+    return getIntegerVT(Ty->getContext(), cast<ByteType>(Ty)->getBitWidth());
   case Type::IntegerTyID:
     return getIntegerVT(Ty->getContext(), cast<IntegerType>(Ty)->getBitWidth());
   case Type::FixedVectorTyID:
diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp
index 82e4de6d07441..6a90f6748161a 100644
--- a/llvm/lib/IR/AsmWriter.cpp
+++ b/llvm/lib/IR/AsmWriter.cpp
@@ -669,6 +669,9 @@ void TypePrinting::print(Type *Ty, raw_ostream &OS) {
     return;
   case Type::X86_AMXTyID:   OS << "x86_amx"; return;
   case Type::TokenTyID:     OS << "token"; return;
+  case Type::ByteTyID:
+    OS << 'b' << Ty->getByteBitWidth();
+    return;
   case Type::IntegerTyID:
     OS << 'i' << cast<IntegerType>(Ty)->getBitWidth();
     return;
@@ -1648,6 +1651,23 @@ static void writeConstantInternal(raw_ostream &Out, const Constant *CV,
     return;
   }
 
+  if (const auto *CB = dyn_cast<ConstantByte>(CV)) {
+    Type *Ty = CB->getType();
+
+    if (Ty->isVectorTy()) {
+      Out << "splat (";
+      WriterCtx.TypePrinter->print(Ty->getScalarType(), Out);
+      Out << " ";
+    }
+
+    Out << CB->getValue();
+
+    if (Ty->isVectorTy())
+      Out << ")";
+
+    return;
+  }
+
   if (const auto *CFP = dyn_cast<ConstantFP>(CV)) {
     Type *Ty = CFP->getType();
 
@@ -1773,7 +1793,8 @@ static void writeConstantInternal(raw_ostream &Out, const Constant *CV,
     // TODO: Remove this block when the UseConstant{Int,FP}ForFixedLengthSplat
     // options are removed.
     if (auto *SplatVal = CV->getSplatValue()) {
-      if (isa<ConstantInt>(SplatVal) || isa<ConstantFP>(SplatVal)) {
+      if (isa<ConstantInt>(SplatVal) || isa<ConstantFP>(SplatVal) ||
+          isa<ConstantByte>(SplatVal)) {
         Out << "splat (";
         writeAsOperandInternal(Out, SplatVal, WriterCtx, /*PrintType=*/true);
         Out << ')';
@@ -1820,7 +1841,8 @@ static void writeConstantInternal(raw_ostream &Out, const Constant *CV,
     // options are removed.
     if (CE->getOpcode() == Instruction::ShuffleVector) {
       if (auto *SplatVal = CE->getSplatValue()) {
-        if (isa<ConstantInt>(SplatVal) || isa<ConstantFP>(SplatVal)) {
+        if (isa<ConstantInt>(SplatVal) || isa<ConstantFP>(SplatVal) ||
+            isa<ConstantByte>(SplatVal)) {
           Out << "splat (";
           writeAsOperandInternal(Out, SplatVal, WriterCtx, /*PrintType=*/true);
           Out << ')';
diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp
index 726a3d8dd906f..265d7eed21a6c 100644
--- a/llvm/lib/IR/Attributes.cpp
+++ b/llvm/lib/IR/Attributes.cpp
@@ -2451,8 +2451,8 @@ AttributeMask AttributeFuncs::typeIncompatible(Type *Ty, AttributeSet AS,
                                                AttributeSafetyKind ASK) {
   AttributeMask Incompatible;
 
-  if (!Ty->isIntegerTy()) {
-    // Attributes that only apply to integers.
+  if (!Ty->isIntegerTy() && !Ty->isByteTy()) {
+    // Attributes that only apply to integers and bytes.
     if (ASK & ASK_SAFE_TO_DROP)
       Incompatible.addAttribute(Attribute::AllocAlign);
     if (ASK & ASK_UNSAFE_TO_DROP)
diff --git a/llvm/lib/IR/Constants.cpp b/llvm/lib/IR/Constants.cpp
index 76152fe91a532..256b8cadfc210 100644
--- a/llvm/lib/IR/Constants.cpp
+++ b/llvm/lib/IR/Constants.cpp
@@ -39,12 +39,18 @@ using namespace PatternMatch;
 static cl::opt<bool> UseConstantIntForFixedLengthSplat(
     "use-constant-int-for-fixed-length-splat", cl::init(false), cl::Hidden,
     cl::desc("Use ConstantInt's native fixed-length vector splat support."));
+static cl::opt<bool> UseConstantByteForFixedLengthSplat(
+    "use-constant-byte-for-fixed-length-splat", cl::init(false), cl::Hidden,
+    cl::desc("Use ConstantByte's native fixed-length vector splat support."));
 static cl::opt<bool> UseConstantFPForFixedLengthSplat(
     "use-constant-fp-for-fixed-length-splat", cl::init(false), cl::Hidden,
     cl::desc("Use ConstantFP's native fixed-length vector splat support."));
 static cl::opt<bool> UseConstantIntForScalableSplat(
     "use-constant-int-for-scalable-splat", cl::init(false), cl::Hidden,
     cl::desc("Use ConstantInt's native scalable vector splat support."));
+static cl::opt<bool> UseConstantByteForScalableSplat(
+    "use-constant-byte-for-scalable-splat", cl::init(false), cl::Hidden,
+    cl::desc("Use ConstantByte's native scalable vector splat support."));
 static cl::opt<bool> UseConstantFPForScalableSplat(
     "use-constant-fp-for-scalable-splat", cl::init(false), cl::Hidden,
     cl::desc("Use ConstantFP's native scalable vector splat support."));
@@ -92,6 +98,10 @@ bool Constant::isNullValue() const {
   if (const ConstantInt *CI = dyn_cast<ConstantInt>(this))
     return CI->isZero();
 
+  // 0 is null.
+  if (const ConstantByte *CB = dyn_cast<ConstantByte>(this))
+    return CB->isZero();
+
   // +0.0 is null.
   if (const ConstantFP *CFP = dyn_cast<ConstantFP>(this))
     // ppc_fp128 determine isZero using high order double only
@@ -109,6 +119,10 @@ bool Constant::isAllOnesValue() const {
   if (const ConstantInt *CI = dyn_cast<ConstantInt>(this))
     return CI->isMinusOne();
 
+  // Check for MaxValue bytes
+  if (const ConstantByte *CB = dyn_cast<ConstantByte>(this))
+    return CB->isMinusOne();
+
   // Check for FP which are bitcasted from -1 integers
   if (const ConstantFP *CFP = dyn_cast<ConstantFP>(this))
     return CFP->getValueAPF().bitcastToAPInt().isAllOnes();
@@ -126,6 +140,10 @@ bool Constant::isOneValue() const {
   if (const ConstantInt *CI = dyn_cast<ConstantInt>(this))
     return CI->isOne();
 
+  // Check for 1 bytes
+  if (const ConstantByte *CB = dyn_cast<ConstantByte>(this))
+    return CB->isOne();
+
   // Check for FP which are bitcasted from 1 integers
   if (const ConstantFP *CFP = dyn_cast<ConstantFP>(this))
     return CFP->getValueAPF().bitcastToAPInt().isOne();
@@ -143,6 +161,10 @@ bool Constant::isNotOneValue() const {
   if (const ConstantInt *CI = dyn_cast<ConstantInt>(this))
     return !CI->isOneValue();
 
+  // Check for 1 bytes
+  if (const ConstantByte *CB = dyn_cast<ConstantByte>(this))
+    return !CB->isOneValue();
+
   // Check for FP which are bitcasted from 1 integers
   if (const ConstantFP *CFP = dyn_cast<ConstantFP>(this))
     return !CFP->getValueAPF().bitcastToAPInt().isOne();
@@ -389,6 +411,8 @@ bool Constant::containsConstantExpression() const {
 /// Constructor to create a '0' constant of arbitrary type.
 Constant *Constant::getNullValue(Type *Ty) {
   switch (Ty->getTypeID()) {
+  case Type::ByteTyID:
+    return ConstantByte::get(Ty, 0);
   case Type::IntegerTyID:
     return ConstantInt::get(Ty, 0);
   case Type::HalfTyID:
@@ -427,6 +451,10 @@ Constant *Constant::getIntegerValue(Type *Ty, const APInt &V) {
   if (PointerType *PTy = dyn_cast<PointerType>(ScalarTy))
     C = ConstantExpr::getIntToPtr(C, PTy);
 
+  // Convert an integer to a byte, if necessary.
+  if (ByteType *BTy = dyn_cast<ByteType>(ScalarTy))
+    C = ConstantExpr::getBitCast(C, BTy);
+
   // Broadcast a scalar to a vector, if necessary.
   if (VectorType *VTy = dyn_cast<VectorType>(Ty))
     C = ConstantVector::getSplat(VTy->getElementCount(), C);
@@ -444,6 +472,10 @@ Constant *Constant::getAllOnesValue(Type *Ty) {
     return ConstantFP::get(Ty->getContext(), FL);
   }
 
+  if (ByteType *BTy = dyn_cast<ByteType>(Ty))
+    return ConstantByte::get(Ty->getContext(),
+                             APInt::getAllOnes(BTy->getBitWidth()));
+
   VectorType *VTy = cast<VectorType>(Ty);
   return ConstantVector::getSplat(VTy->getElementCount(),
                                   getAllOnesValue(VTy->getElementType()));
@@ -468,6 +500,13 @@ Constant *Constant::getAggregateElement(unsigned Elt) const {
                ? ConstantInt::get(getContext(), CI->getValue())
                : nullptr;
 
+  if (const auto *CB = dyn_cast<ConstantByte>(this))
+    return Elt < cast<VectorType>(getType())
+                       ->getElementCount()
+                       .getKnownMinValue()
+               ? ConstantByte::get(getContext(), CB->getValue())
+               : nullptr;
+
   if (const auto *CFP = dyn_cast<ConstantFP>(this))
     return Elt < cast<VectorType>(getType())
                        ->getElementCount()
@@ -548,6 +587,9 @@ void llvm::deleteConstant(Constant *C) {
   case Constant::ConstantIntVal:
     delete static_cast<ConstantInt *>(C);
     break;
+  case Constant::ConstantByteVal:
+    delete static_cast<ConstantByte *>(C);
+    break;
   case Constant::ConstantFPVal:
     delete static_cast<ConstantFP *>(C);
     break;
@@ -752,7 +794,7 @@ static bool constantIsDead(const Constant *C, bool RemoveDeadUsers) {
     ReplaceableMetadataImpl::SalvageDebugInfo(*C);
     const_cast<Constant *>(C)->destroyConstant();
   }
-  
+
   return true;
 }
 
@@ -999,6 +1041,131 @@ void ConstantInt::destroyConstantImpl() {
   llvm_unreachable("You can't ConstantInt->destroyConstantImpl()!");
 }
 
+//===----------------------------------------------------------------------===//
+//                               ConstantByte
+//===----------------------------------------------------------------------===//
+
+ConstantByte::ConstantByte(Type *Ty, const APInt &V)
+    : ConstantData(Ty, ConstantByteVal), Val(V) {
+  assert(V.getBitWidth() ==
+             cast<ByteType>(Ty->getScalarType())->getBitWidth() &&
+         "Invalid constant for type");
+}
+
+ConstantByte *ConstantByte::getTrue(LLVMContext &Context) {
+  LLVMContextImpl *pImpl = Context.pImpl;
+  if (!pImpl->TheTrueByteVal)
+    pImpl->TheTrueByteVal = ConstantByte::get(Type::getByte1Ty(Context), 1);
+  return pImpl->TheTrueByteVal;
+}
+
+ConstantByte *ConstantByte::getFalse(LLVMContext &Context) {
+  LLVMContextImpl *pImpl = Context.pImpl;
+  if (!pImpl->TheFalseByteVal)
+    pImpl->TheFalseByteVal = ConstantByte::get(Type::getByte1Ty(Context), 0);
+  return pImpl->TheFalseByteVal;
+}
+
+ConstantByte *ConstantByte::getBool(LLVMContext &Context, bool V) {
+  return V ? getTrue(Context) : getFalse(Context);
+}
+
+Constant *ConstantByte::getTrue(Type *Ty) {
+  assert(Ty->isByteOrByteVectorTy(1) && "Type not i1 or vector of i1.");
+  ConstantByte *TrueC = ConstantByte::getTrue(Ty->getContext());
+  if (auto *VTy = dyn_cast<VectorType>(Ty))
+    return ConstantVector::getSplat(VTy->getElementCount(), TrueC);
+  return TrueC;
+}
+
+Constant *ConstantByte::getFalse(Type *Ty) {
+  assert(Ty->isByteOrByteVectorTy(1) && "Type not i1 or vector of i1.");
+  ConstantByte *FalseC = ConstantByte::getFalse(Ty->getContext());
+  if (auto *VTy = dyn_cast<VectorType>(Ty))
+    return ConstantVector::getSplat(VTy->getElementCount(), FalseC);
+  return FalseC;
+}
+
+Constant *ConstantByte::getBool(Type *Ty, bool V) {
+  return V ? getTrue(Ty) : getFalse(Ty);
+}
+
+// Get a ConstantByte from an APInt.
+ConstantByte *ConstantByte::get(LLVMContext &Context, const APInt &V) {
+  // get an existing value or the insertion position
+  LLVMContextImpl *pImpl = Context.pImpl;
+  std::unique_ptr<ConstantByte> &Slot =
+      V.isZero()  ? pImpl->ByteZeroConstants[V.getBitWidth()]
+      : V.isOne() ? pImpl->ByteOneConstants[V.getBitWidth()]
+                  : pImpl->ByteConstants[V];
+  if (!Slot) {
+    // Get the corresponding byte type for the bit width of the value.
+    ByteType *BTy = ByteType::get(Context, V.getBitWidth());
+    Slot.reset(new ConstantByte(BTy, V));
+  }
+  assert(Slot->getType() == ByteType::get(Context, V.getBitWidth()));
+  return Slot.get();
+}
+
+// Get a ConstantByte vector with each lane set to the same APInt.
+ConstantByte *ConstantByte::get(LLVMContext &Context, ElementCount EC,
+                                const APInt &V) {
+  // Get an existing value or the insertion position.
+  std::unique_ptr<ConstantByte> &Slot =
+      Context.pImpl->ByteSplatConstants[std::make_pair(EC, V)];
+  if (!Slot) {
+    ByteType *BTy = ByteType::get(Context, V.getBitWidth());
+    VectorType *VTy = VectorType::get(BTy, EC);
+    Slot.reset(new ConstantByte(VTy, V));
+  }
+
+#ifndef NDEBUG
+  ByteType *BTy = ByteType::get(Context, V.getBitWidth());
+  VectorType *VTy = VectorType::get(BTy, EC);
+  assert(Slot->getType() == VTy);
+#endif
+  return Slot.get();
+}
+
+Constant *ConstantByte::get(Type *Ty, uint64_t V, bool isSigned,
+                            bool ImplicitTrunc) {
+  Constant *C =
+      get(cast<ByteType>(Ty->getScalarType()), V, isSigned, ImplicitTrunc);
+
+  // For vectors, broadcast the value.
+  if (VectorType *VTy = dyn_cast<VectorType>(Ty))
+    return ConstantVector::getSplat(VTy->getElementCount(), C);
+
+  return C;
+}
+
+ConstantByte *ConstantByte::get(ByteType *Ty, uint64_t V, bool isSigned,
+                                bool ImplicitTrunc) {
+  return get(Ty->getContext(),
+             APInt(Ty->getBitWidth(), V, isSigned, ImplicitTrunc));
+}
+
+Constant *ConstantByte::get(Type *Ty, const APInt &V) {
+  ConstantByte *C = get(Ty->getContext(), V);
+  assert(C->getType() == Ty->getScalarType() &&
+         "ConstantByte type doesn't match the type implied by its value!");
+
+  // For vectors, broadcast the value.
+  if (VectorType *VTy = dyn_cast<VectorType>(Ty))
+    return ConstantVector::getSplat(VTy->getElementCount(), C);
+
+  return C;
+}
+
+ConstantByte *ConstantByte::get(ByteType *Ty, StringRef Str, uint8_t radix) {
+  return get(Ty->getContext(), APInt(Ty->getBitWidth(), Str, radix));
+}
+
+/// Remove the constant from the constant table.
+void ConstantByte::destroyConstantImpl() {
+  llvm_unreachable("You can't ConstantByte->destroyConstantImpl()!");
+}
+
 //===----------------------------------------------------------------------===//
 //                                ConstantFP
 //===----------------------------------------------------------------------===//
@@ -1269,6 +1436,19 @@ static Constant *getIntSequenceIfElementsMatch(ArrayRef<Constant *> V) {
   return SequentialTy::get(V[0]->getContext(), Elts);
 }
 
+template <typename SequentialTy, typename ElementTy>
+static Constant *getByteSequenceIfElementsMatch(ArrayRef<Constant *> V) {
+  assert(!V.empty() && "Cannot get empty byte sequence.");
+
+  SmallVector<ElementTy, 16> Elts;
+  for (Constant *C : V)
+    if (auto *CI = dyn_cast<ConstantByte>(C))
+      Elts.push_back(CI->getZExtValue());
+    else
+      return nullptr;
+  return SequentialTy::getByte(V[0]->getType(), Elts);
+}
+
 template <typename SequentialTy, typename ElementTy>
 static Constant *getFPSequenceIfElementsMatch(ArrayRef<Constant *> V) {
   assert(!V.empty() && "Cannot get empty FP sequence.");
@@ -1297,6 +1477,15 @@ static Constant *getSequenceIfElementsMatch(Constant *C,
       return getIntSequenceIfElementsMatch<SequenceTy, uint32_t>(V);
     else if (CI->getType()->isIntegerTy(64))
       return getIntSequenceIfElementsMatch<SequenceTy, uint64_t>(V);
+  } else if (ConstantByte *CB = dyn_cast<ConstantByte>(C)) {
+    if (CB->getType()->isByteTy(8))
+      return getByteSequenceIfElementsMatch<SequenceTy, uint8_t>(V);
+    else if (CB->getType()->isByteTy(16))
+      return getByteSequenceIfElementsMatch<SequenceTy, uint16_t>(V);
+    else if (CB->getType()->isByteTy(32))
+      return getByteSequenceIfElementsMatch<SequenceTy, uint32_t>(V);
+    else if (CB->getType()->isByteTy(64))
+      return getByteSequenceIfElementsMatch<SequenceTy, uint64_t>(V);
   } else if (ConstantFP *CFP = dyn_cast<ConstantFP>(C)) {
     if (CFP->getType()->isHalfTy() || CFP->getType()->isBFloatTy())
       return getFPSequenceIfElementsMatch<SequenceTy, uint16_t>(V);
@@ -1362,8 +1551,9 @@ Constant *ConstantArray::getImpl(ArrayType *Ty, ArrayRef<Constant*> V) {
   if (C->isNullValue() && rangeOnlyContains(V.begin(), V.end(), C))
     return ConstantAggregateZero::get(Ty);
 
-  // Check to see if all of the elements are ConstantFP or ConstantInt and if
-  // the element type is compatible with ConstantDataVector.  If so, use it.
+  // Check to see if all of the elements are ConstantFP or ConstantInt or
+  // ConstantByte and if the element type is compatible with ConstantDataVector.
+  // If so, use it.
   if (ConstantDataSequential::isElementTypeCompatible(C->getType()))
     return getSequenceIfElementsMatch<ConstantDataArray>(C, V);
 
@@ -1460,11 +1650,13 @@ Constant *ConstantVector::getImpl(ArrayRef<Constant*> V) {
   bool isPoison = isa<PoisonValue>(C);
   bool isSplatFP = UseConstantFPForFixedLengthSplat && isa<ConstantFP>(C);
   bool isSplatInt = UseConstantIntForFixedLengthSplat && isa<ConstantInt>(C);
+  bool isSplatByte = UseConstantByteForFixedLengthSplat && isa<ConstantByte>(C);
 
-  if (isZero || isUndef || isSplatFP || isSplatInt) {
+  if (isZero || isUndef || isSplatFP || isSplatInt || isSplatByte) {
     for (unsigned i = 1, e = V.size(); i != e; ++i)
       if (V[i] != C) {
-        isZero = isUndef = isPoison = isSplatFP = isSplatInt = false;
+        isZero = isUndef = isPoison = isSplatFP = isSplatInt = isSplatByte =
+            false;
         break;
       }
   }
@@ -1481,6 +1673,9 @@ Constant *ConstantVector::getImpl(ArrayRef<Constant*> V) {
   if (isSplatInt)
     return ConstantInt::get(C->getContext(), T->getElementCount(),
                             cast<ConstantInt>(C)->getValue());
+  if (isSplatByte)
+    return ConstantByte::get(C->getContext(), T->getElementCount(),
+                             cast<ConstantByte>(C)->getValue());
 
   // Check to see if all of the elements are ConstantFP or ConstantInt and if
   // the element type is compatible with ConstantDataVector.  If so, use it.
@@ -1499,6 +1694,9 @@ Constant *ConstantVector::getSplat(ElementCount EC, Constant *V) {
       if (UseConstantIntForFixedLengthSplat && isa<ConstantInt>(V))
         return ConstantInt::get(V->getContext(), EC,
                                 cast<ConstantInt>(V)->getValue());
+      if (UseConstantByteForFixedLengthSplat && isa<ConstantByte>(V))
+        return ConstantByte::get(V->getContext(), EC,
+                                 cast<ConstantByte>(V)->getValue());
       if (UseConstantFPForFixedLengthSplat && isa<ConstantFP>(V))
         return ConstantFP::get(V->getContext(), EC,
                                cast<ConstantFP>(V)->getValue());
@@ -1506,7 +1704,7 @@ Constant *ConstantVector::getSplat(ElementCount EC, Constant *V) {
 
     // If this splat is compatible with ConstantDataVector, use it instead of
     // ConstantVector.
-    if ((isa<ConstantFP>(V) || isa<ConstantInt>(V)) &&
+    if ((isa<ConstantFP>(V) || isa<ConstantInt>(V) || isa<ConstantByte>(V)) &&
         ConstantDataSequential::isElementTypeCompatible(V->getType()))
       return ConstantDataVector::getSplat(EC.getKnownMinValue(), V);
 
@@ -1519,6 +1717,9 @@ Constant *ConstantVector::getSplat(ElementCount EC, Constant *V) {
     if (UseConstantIntForScalableSplat && isa<ConstantInt>(V))
       return ConstantInt::get(V->getContext(), EC,
                               cast<ConstantInt>(V)->getValue());
+    if (UseConstantByteForScalableSplat && isa<ConstantByte>(V))
+      return ConstantByte::get(V->getContext(), EC,
+                               cast<ConstantByte>(V)->getValue());
     if (UseConstantFPForScalableSplat && isa<ConstantFP>(V))
       return ConstantFP::get(V->getContext(), EC,
                              cast<ConstantFP>(V)->getValue());
@@ -1634,6 +1835,10 @@ bool ConstantInt::isValueValidForType(Type *Ty, int64_t Val) {
   return isIntN(NumBits, Val);
 }
 
+bool ConstantByte::isValueValidForType(Type *Ty, uint64_t Val) {
+  return isUIntN(Ty->getByteBitWidth(), Val);
+}
+
 bool ConstantFP::isValueValidForType(Type *Ty, const APFloat& Val) {
   // convert modifies in place, so make a copy.
   APFloat Val2 = APFloat(Val);
@@ -1739,6 +1944,8 @@ Constant *Constant::getSplatValue(bool AllowPoison) const {
     return getNullValue(cast<VectorType>(getType())->getElementType());
   if (auto *CI = dyn_cast<ConstantInt>(this))
     return ConstantInt::get(getContext(), CI->getValue());
+  if (auto *CB = dyn_cast<ConstantByte>(this))
+    return ConstantByte::get(getContext(), CB->getValue());
   if (auto *CFP = dyn_cast<ConstantFP>(this))
     return ConstantFP::get(getContext(), CFP->getValue());
   if (const ConstantDataVector *CV = dyn_cast<ConstantDataVector>(this))
@@ -1798,6 +2005,8 @@ Constant *ConstantVector::getSplatValue(bool AllowPoison) const {
 const APInt &Constant::getUniqueInteger() const {
   if (const ConstantInt *CI = dyn_cast<ConstantInt>(this))
     return CI->getValue();
+  if (const ConstantByte *CB = dyn_cast<ConstantByte>(this))
+    return CB->getValue();
   // Scalable vectors can use a ConstantExpr to build a splat.
   if (isa<ConstantExpr>(this))
     return cast<ConstantInt>(this->getSplatValue())->getValue();
@@ -1821,6 +2030,10 @@ ConstantRange Constant::toConstantRange() const {
           getSplatValue(/*AllowPoison=*/true)))
     return ConstantRange(CI->getValue());
 
+  if (auto *CB =
+          dyn_cast_or_null<ConstantByte>(getSplatValue(/*AllowPoison=*/true)))
+    return ConstantRange(CB->getValue());
+
   if (auto *CDV = dyn_cast<ConstantDataVector>(this)) {
     ConstantRange CR = ConstantRange::getEmpty(BitWidth);
     for (unsigned I = 0, E = CDV->getNumElements(); I < E; ++I)
@@ -1837,7 +2050,8 @@ ConstantRange Constant::toConstantRange() const {
       if (isa<PoisonValue>(Elem))
         continue;
       auto *CI = dyn_cast<ConstantInt>(Elem);
-      if (!CI)
+      auto *CB = dyn_cast<ConstantByte>(Elem);
+      if (!CI && !CB)
         return ConstantRange::getFull(BitWidth);
       CR = CR.unionWith(CI->getValue());
     }
@@ -2884,6 +3098,17 @@ bool ConstantDataSequential::isElementTypeCompatible(Type *Ty) {
     default: break;
     }
   }
+  if (auto *IT = dyn_cast<ByteType>(Ty)) {
+    switch (IT->getBitWidth()) {
+    case 8:
+    case 16:
+    case 32:
+    case 64:
+      return true;
+    default:
+      break;
+    }
+  }
   return false;
 }
 
@@ -3016,17 +3241,54 @@ Constant *ConstantDataArray::getFP(Type *ElementType, ArrayRef<uint64_t> Elts) {
   return getImpl(StringRef(Data, Elts.size() * 8), Ty);
 }
 
-Constant *ConstantDataArray::getString(LLVMContext &Context,
-                                       StringRef Str, bool AddNull) {
+/// getByte() constructors - Return a constant of array type with a byte
+/// element type taken from argument `ElementType', and count taken from
+/// argument `Elts'.  The amount of bits of the contained type must match the
+/// number of bits of the type contained in the passed in ArrayRef.
+/// Note that this can return a ConstantAggregateZero object.
+Constant *ConstantDataArray::getByte(Type *ElementType,
+                                     ArrayRef<uint8_t> Elts) {
+  assert(ElementType->isByteTy(8) && "Element type is not a 8-bit byte type");
+  Type *Ty = ArrayType::get(ElementType, Elts.size());
+  const char *Data = reinterpret_cast<const char *>(Elts.data());
+  return getImpl(StringRef(Data, Elts.size() * 1), Ty);
+}
+Constant *ConstantDataArray::getByte(Type *ElementType,
+                                     ArrayRef<uint16_t> Elts) {
+  assert(ElementType->isByteTy(16) && "Element type is not a 16-bit byte type");
+  Type *Ty = ArrayType::get(ElementType, Elts.size());
+  const char *Data = reinterpret_cast<const char *>(Elts.data());
+  return getImpl(StringRef(Data, Elts.size() * 2), Ty);
+}
+Constant *ConstantDataArray::getByte(Type *ElementType,
+                                     ArrayRef<uint32_t> Elts) {
+  assert(ElementType->isByteTy(32) && "Element type is not a 32-bit byte type");
+  Type *Ty = ArrayType::get(ElementType, Elts.size());
+  const char *Data = reinterpret_cast<const char *>(Elts.data());
+  return getImpl(StringRef(Data, Elts.size() * 4), Ty);
+}
+Constant *ConstantDataArray::getByte(Type *ElementType,
+                                     ArrayRef<uint64_t> Elts) {
+  assert(ElementType->isByteTy(64) && "Element type is not a 64-bit byte type");
+  Type *Ty = ArrayType::get(ElementType, Elts.size());
+  const char *Data = reinterpret_cast<const char *>(Elts.data());
+  return getImpl(StringRef(Data, Elts.size() * 8), Ty);
+}
+
+Constant *ConstantDataArray::getString(LLVMContext &Context, StringRef Str,
+                                       bool AddNull, bool ByteString) {
   if (!AddNull) {
     const uint8_t *Data = Str.bytes_begin();
-    return get(Context, ArrayRef(Data, Str.size()));
+    return ByteString
+               ? getByte(Type::getByte8Ty(Context), ArrayRef(Data, Str.size()))
+               : get(Context, ArrayRef(Data, Str.size()));
   }
 
   SmallVector<uint8_t, 64> ElementVals;
   ElementVals.append(Str.begin(), Str.end());
   ElementVals.push_back(0);
-  return get(Context, ElementVals);
+  return ByteString ? getByte(Type::getByte8Ty(Context), ElementVals)
+                    : get(Context, ElementVals);
 }
 
 /// get() constructors - Return a constant with vector type with an element
@@ -3063,6 +3325,40 @@ Constant *ConstantDataVector::get(LLVMContext &Context, ArrayRef<double> Elts) {
   return getImpl(StringRef(Data, Elts.size() * 8), Ty);
 }
 
+/// getByte() constructors - Return a constant of vector type with a byte
+/// element type taken from argument `ElementType', and count taken from
+/// argument `Elts'.  The amount of bits of the contained type must match the
+/// number of bits of the type contained in the passed in ArrayRef.
+/// Note that this can return a ConstantAggregateZero object.
+Constant *ConstantDataVector::getByte(Type *ElementType,
+                                      ArrayRef<uint8_t> Elts) {
+  assert(ElementType->isByteTy(8) && "Element type is not a 8-bit byte");
+  auto *Ty = FixedVectorType::get(ElementType, Elts.size());
+  const char *Data = reinterpret_cast<const char *>(Elts.data());
+  return getImpl(StringRef(Data, Elts.size() * 1), Ty);
+}
+Constant *ConstantDataVector::getByte(Type *ElementType,
+                                      ArrayRef<uint16_t> Elts) {
+  assert(ElementType->isByteTy(16) && "Element type is not a 16-bit byte");
+  auto *Ty = FixedVectorType::get(ElementType, Elts.size());
+  const char *Data = reinterpret_cast<const char *>(Elts.data());
+  return getImpl(StringRef(Data, Elts.size() * 2), Ty);
+}
+Constant *ConstantDataVector::getByte(Type *ElementType,
+                                      ArrayRef<uint32_t> Elts) {
+  assert(ElementType->isByteTy(32) && "Element type is not a 32-bit byte");
+  auto *Ty = FixedVectorType::get(ElementType, Elts.size());
+  const char *Data = reinterpret_cast<const char *>(Elts.data());
+  return getImpl(StringRef(Data, Elts.size() * 4), Ty);
+}
+Constant *ConstantDataVector::getByte(Type *ElementType,
+                                      ArrayRef<uint64_t> Elts) {
+  assert(ElementType->isByteTy(64) && "Element type is not a 64-bit byte");
+  auto *Ty = FixedVectorType::get(ElementType, Elts.size());
+  const char *Data = reinterpret_cast<const char *>(Elts.data());
+  return getImpl(StringRef(Data, Elts.size() * 8), Ty);
+}
+
 /// getFP() constructors - Return a constant of vector type with a float
 /// element type taken from argument `ElementType', and count taken from
 /// argument `Elts'.  The amount of bits of the contained type must match the
@@ -3114,6 +3410,24 @@ Constant *ConstantDataVector::getSplat(unsigned NumElts, Constant *V) {
     return get(V->getContext(), Elts);
   }
 
+  if (ConstantByte *CB = dyn_cast<ConstantByte>(V)) {
+    if (CB->getType()->isByteTy(8)) {
+      SmallVector<uint8_t, 16> Elts(NumElts, CB->getZExtValue());
+      return getByte(V->getType(), Elts);
+    }
+    if (CB->getType()->isByteTy(16)) {
+      SmallVector<uint16_t, 16> Elts(NumElts, CB->getZExtValue());
+      return getByte(V->getType(), Elts);
+    }
+    if (CB->getType()->isByteTy(32)) {
+      SmallVector<uint32_t, 16> Elts(NumElts, CB->getZExtValue());
+      return getByte(V->getType(), Elts);
+    }
+    assert(CB->getType()->isByteTy(64) && "Unsupported ConstantData type");
+    SmallVector<uint64_t, 16> Elts(NumElts, CB->getZExtValue());
+    return getByte(V->getType(), Elts);
+  }
+
   if (ConstantFP *CFP = dyn_cast<ConstantFP>(V)) {
     if (CFP->getType()->isHalfTy()) {
       SmallVector<uint16_t, 16> Elts(
@@ -3140,13 +3454,14 @@ Constant *ConstantDataVector::getSplat(unsigned NumElts, Constant *V) {
 }
 
 uint64_t ConstantDataSequential::getElementAsInteger(uint64_t Elt) const {
-  assert(isa<IntegerType>(getElementType()) &&
-         "Accessor can only be used when element is an integer");
+  assert(
+      (isa<IntegerType>(getElementType()) || isa<ByteType>(getElementType())) &&
+      "Accessor can only be used when element is an integer or byte");
   const char *EltPtr = getElementPointer(Elt);
 
   // The data is stored in host byte order, make sure to cast back to the right
   // type to load with the right endianness.
-  switch (getElementType()->getIntegerBitWidth()) {
+  switch (getElementType()->getScalarSizeInBits()) {
   default: llvm_unreachable("Invalid bitwidth for CDS");
   case 8:
     return *reinterpret_cast<const uint8_t *>(EltPtr);
@@ -3160,13 +3475,14 @@ uint64_t ConstantDataSequential::getElementAsInteger(uint64_t Elt) const {
 }
 
 APInt ConstantDataSequential::getElementAsAPInt(uint64_t Elt) const {
-  assert(isa<IntegerType>(getElementType()) &&
-         "Accessor can only be used when element is an integer");
+  assert(
+      (isa<IntegerType>(getElementType()) || isa<ByteType>(getElementType())) &&
+      "Accessor can only be used when element is an integer or byte");
   const char *EltPtr = getElementPointer(Elt);
 
   // The data is stored in host byte order, make sure to cast back to the right
   // type to load with the right endianness.
-  switch (getElementType()->getIntegerBitWidth()) {
+  switch (getElementType()->getScalarSizeInBits()) {
   default: llvm_unreachable("Invalid bitwidth for CDS");
   case 8: {
     auto EltVal = *reinterpret_cast<const uint8_t *>(EltPtr);
@@ -3229,11 +3545,16 @@ Constant *ConstantDataSequential::getElementAsConstant(uint64_t Elt) const {
       getElementType()->isFloatTy() || getElementType()->isDoubleTy())
     return ConstantFP::get(getContext(), getElementAsAPFloat(Elt));
 
+  if (getElementType()->isByteTy())
+    return ConstantByte::get(getElementType(), getElementAsInteger(Elt));
+
   return ConstantInt::get(getElementType(), getElementAsInteger(Elt));
 }
 
 bool ConstantDataSequential::isString(unsigned CharSize) const {
-  return isa<ArrayType>(getType()) && getElementType()->isIntegerTy(CharSize);
+  return isa<ArrayType>(getType()) &&
+         (getElementType()->isIntegerTy(CharSize) ||
+          getElementType()->isByteTy(CharSize));
 }
 
 bool ConstantDataSequential::isCString() const {
diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp
index d31322a3013b6..0fd832ac5c99e 100644
--- a/llvm/lib/IR/Core.cpp
+++ b/llvm/lib/IR/Core.cpp
@@ -605,6 +605,8 @@ LLVMTypeKind LLVMGetTypeKind(LLVMTypeRef Ty) {
     return LLVMLabelTypeKind;
   case Type::MetadataTyID:
     return LLVMMetadataTypeKind;
+  case Type::ByteTyID:
+    return LLVMByteTypeKind;
   case Type::IntegerTyID:
     return LLVMIntegerTypeKind;
   case Type::FunctionTyID:
@@ -656,6 +658,50 @@ char *LLVMPrintTypeToString(LLVMTypeRef Ty) {
   return strdup(buf.c_str());
 }
 
+/*--.. Operations on byte types ............................................--*/
+
+LLVMTypeRef LLVMByte8TypeInContext(LLVMContextRef C) {
+  return (LLVMTypeRef)Type::getByte8Ty(*unwrap(C));
+}
+LLVMTypeRef LLVMByte16TypeInContext(LLVMContextRef C) {
+  return (LLVMTypeRef)Type::getByte16Ty(*unwrap(C));
+}
+LLVMTypeRef LLVMByte32TypeInContext(LLVMContextRef C) {
+  return (LLVMTypeRef)Type::getByte32Ty(*unwrap(C));
+}
+LLVMTypeRef LLVMByte64TypeInContext(LLVMContextRef C) {
+  return (LLVMTypeRef)Type::getByte64Ty(*unwrap(C));
+}
+LLVMTypeRef LLVMByte128TypeInContext(LLVMContextRef C) {
+  return (LLVMTypeRef)Type::getByte128Ty(*unwrap(C));
+}
+LLVMTypeRef LLVMByteTypeInContext(LLVMContextRef C, unsigned NumBits) {
+  return wrap(ByteType::get(*unwrap(C), NumBits));
+}
+
+LLVMTypeRef LLVMByte8Type(void) {
+  return LLVMByte8TypeInContext(getGlobalContextForCAPI());
+}
+LLVMTypeRef LLVMByte16Type(void) {
+  return LLVMByte16TypeInContext(getGlobalContextForCAPI());
+}
+LLVMTypeRef LLVMByte32Type(void) {
+  return LLVMByte32TypeInContext(getGlobalContextForCAPI());
+}
+LLVMTypeRef LLVMByte64Type(void) {
+  return LLVMByte64TypeInContext(getGlobalContextForCAPI());
+}
+LLVMTypeRef LLVMByte128Type(void) {
+  return LLVMByte128TypeInContext(getGlobalContextForCAPI());
+}
+LLVMTypeRef LLVMByteType(unsigned NumBits) {
+  return LLVMByteTypeInContext(getGlobalContextForCAPI(), NumBits);
+}
+
+unsigned LLVMGetByteTypeWidth(LLVMTypeRef ByteTy) {
+  return unwrap<ByteType>(ByteTy)->getBitWidth();
+}
+
 /*--.. Operations on integer types .........................................--*/
 
 LLVMTypeRef LLVMInt1TypeInContext(LLVMContextRef C)  {
@@ -1556,6 +1602,30 @@ LLVMValueRef LLVMConstIntOfStringAndSize(LLVMTypeRef IntTy, const char Str[],
                                Radix));
 }
 
+LLVMValueRef LLVMConstByte(LLVMTypeRef ByteTy, unsigned long long N) {
+  return wrap(ConstantByte::get(unwrap<ByteType>(ByteTy), N));
+}
+
+LLVMValueRef LLVMConstByteOfArbitraryPrecision(LLVMTypeRef ByteTy,
+                                               unsigned NumWords,
+                                               const uint64_t Words[]) {
+  ByteType *Ty = unwrap<ByteType>(ByteTy);
+  return wrap(ConstantByte::get(
+      Ty->getContext(), APInt(Ty->getBitWidth(), ArrayRef(Words, NumWords))));
+}
+
+LLVMValueRef LLVMConstByteOfString(LLVMTypeRef ByteTy, const char Str[],
+                                   uint8_t Radix) {
+  return wrap(
+      ConstantByte::get(unwrap<ByteType>(ByteTy), StringRef(Str), Radix));
+}
+
+LLVMValueRef LLVMConstByteOfStringAndSize(LLVMTypeRef ByteTy, const char Str[],
+                                          unsigned SLen, uint8_t Radix) {
+  return wrap(
+      ConstantByte::get(unwrap<ByteType>(ByteTy), StringRef(Str, SLen), Radix));
+}
+
 LLVMValueRef LLVMConstReal(LLVMTypeRef RealTy, double N) {
   return wrap(ConstantFP::get(unwrap(RealTy), N));
 }
@@ -1585,6 +1655,14 @@ long long LLVMConstIntGetSExtValue(LLVMValueRef ConstantVal) {
   return unwrap<ConstantInt>(ConstantVal)->getSExtValue();
 }
 
+unsigned long long LLVMConstByteGetZExtValue(LLVMValueRef ConstantVal) {
+  return unwrap<ConstantByte>(ConstantVal)->getZExtValue();
+}
+
+long long LLVMConstByteGetSExtValue(LLVMValueRef ConstantVal) {
+  return unwrap<ConstantByte>(ConstantVal)->getSExtValue();
+}
+
 double LLVMConstRealGetDouble(LLVMValueRef ConstantVal, LLVMBool *LosesInfo) {
   ConstantFP *cFP = unwrap<ConstantFP>(ConstantVal) ;
   Type *Ty = cFP->getType();
diff --git a/llvm/lib/IR/DataLayout.cpp b/llvm/lib/IR/DataLayout.cpp
index 05aa6c29c0e50..f7361f337af0d 100644
--- a/llvm/lib/IR/DataLayout.cpp
+++ b/llvm/lib/IR/DataLayout.cpp
@@ -872,6 +872,9 @@ Align DataLayout::getAlignment(Type *Ty, bool abi_or_pref) const {
     const Align Align = abi_or_pref ? StructABIAlignment : StructPrefAlignment;
     return std::max(Align, Layout->getAlignment());
   }
+  case Type::ByteTyID:
+    // The byte type has the same alignment as the equally sized integer type.
+    return getIntegerAlignment(Ty->getByteBitWidth(), abi_or_pref);
   case Type::IntegerTyID:
     return getIntegerAlignment(Ty->getIntegerBitWidth(), abi_or_pref);
   case Type::HalfTyID:
@@ -983,6 +986,40 @@ Type *DataLayout::getIntPtrType(Type *Ty) const {
   return IntTy;
 }
 
+Type *DataLayout::getIntByteType(Type *Ty) const {
+  assert(Ty->isByteOrByteVectorTy() && "Expected a byte or byte vector type.");
+  unsigned NumBits = Ty->getScalarSizeInBits();
+  IntegerType *IntTy = IntegerType::get(Ty->getContext(), NumBits);
+  if (VectorType *VecTy = dyn_cast<VectorType>(Ty))
+    return VectorType::get(IntTy, VecTy);
+  return IntTy;
+}
+
+ByteType *DataLayout::getBytePtrType(LLVMContext &C,
+                                     unsigned AddressSpace) const {
+  return ByteType::get(C, getPointerSizeInBits(AddressSpace));
+}
+
+Type *DataLayout::getBytePtrType(Type *Ty) const {
+  assert(Ty->isPtrOrPtrVectorTy() &&
+         "Expected a pointer or pointer vector type.");
+  unsigned NumBits = getPointerTypeSizeInBits(Ty);
+  ByteType *ByteTy = ByteType::get(Ty->getContext(), NumBits);
+  if (VectorType *VecTy = dyn_cast<VectorType>(Ty))
+    return VectorType::get(ByteTy, VecTy);
+  return ByteTy;
+}
+
+Type *DataLayout::getByteIntType(Type *Ty) const {
+  assert(!Ty->isPtrOrPtrVectorTy() &&
+         "Expected a non-pointer or non-pointer vector type.");
+  unsigned NumBits = Ty->getScalarSizeInBits();
+  ByteType *ByteTy = ByteType::get(Ty->getContext(), NumBits);
+  if (VectorType *VecTy = dyn_cast<VectorType>(Ty))
+    return VectorType::get(ByteTy, VecTy);
+  return ByteTy;
+}
+
 Type *DataLayout::getSmallestLegalIntType(LLVMContext &C, unsigned Width) const {
   for (unsigned LegalIntWidth : LegalIntWidths)
     if (Width <= LegalIntWidth)
diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp
index be307cf08ccc5..8fcdd6e4e2d47 100644
--- a/llvm/lib/IR/Instructions.cpp
+++ b/llvm/lib/IR/Instructions.cpp
@@ -3237,7 +3237,16 @@ CastInst::getCastOpcode(
       DestTy->getPrimitiveSizeInBits().getFixedValue(); // 0 for ptr
 
   // Run through the possibilities ...
-  if (DestTy->isIntegerTy()) {                      // Casting to integral
+  if (DestTy->isByteTy()) {     // Casting to byte
+    if (SrcTy->isIntegerTy()) { // Casting from integral
+      assert(DestBits == SrcBits && "Illegal cast from integer to byte type");
+      return BitCast;
+    } else if (SrcTy->isPointerTy()) { // Casting from pointer
+      assert(DestBits == SrcBits && "Illegal cast from pointer to byte type");
+      return BitCast;
+    }
+    llvm_unreachable("Illegal cast to byte type");
+  } else if (DestTy->isIntegerTy()) {               // Casting to integral
     if (SrcTy->isIntegerTy()) {                     // Casting from integral
       if (DestBits < SrcBits)
         return Trunc;                               // int -> smaller int
@@ -3369,7 +3378,10 @@ CastInst::castIsValid(Instruction::CastOps op, Type *SrcTy, Type *DstTy) {
     PointerType *DstPtrTy = dyn_cast<PointerType>(DstTy->getScalarType());
 
     // BitCast implies a no-op cast of type only. No bits change.
-    // However, you can't cast pointers to anything but pointers.
+    // However, you can't cast pointers to anything but pointers/bytes.
+    if ((SrcPtrTy && DstTy->isByteOrByteVectorTy()) ||
+        (SrcTy->isByteOrByteVectorTy() && DstPtrTy))
+      return true;
     if (!SrcPtrTy != !DstPtrTy)
       return false;
 
diff --git a/llvm/lib/IR/Intrinsics.cpp b/llvm/lib/IR/Intrinsics.cpp
index f46d3e5063e43..49a0816eeb345 100644
--- a/llvm/lib/IR/Intrinsics.cpp
+++ b/llvm/lib/IR/Intrinsics.cpp
@@ -147,6 +147,9 @@ static std::string getMangledTypeStr(Type *Ty, bool &HasUnnamedType) {
     case Type::IntegerTyID:
       Result += "i" + utostr(cast<IntegerType>(Ty)->getBitWidth());
       break;
+    case Type::ByteTyID:
+      Result += "b" + utostr(cast<IntegerType>(Ty)->getBitWidth());
+      break;
     }
   }
   return Result;
diff --git a/llvm/lib/IR/LLVMContextImpl.cpp b/llvm/lib/IR/LLVMContextImpl.cpp
index 8f79398b086eb..9bb14178234db 100644
--- a/llvm/lib/IR/LLVMContextImpl.cpp
+++ b/llvm/lib/IR/LLVMContextImpl.cpp
@@ -37,7 +37,8 @@ LLVMContextImpl::LLVMContextImpl(LLVMContext &C)
       X86_FP80Ty(C, Type::X86_FP80TyID), FP128Ty(C, Type::FP128TyID),
       PPC_FP128Ty(C, Type::PPC_FP128TyID), X86_AMXTy(C, Type::X86_AMXTyID),
       Int1Ty(C, 1), Int8Ty(C, 8), Int16Ty(C, 16), Int32Ty(C, 32),
-      Int64Ty(C, 64), Int128Ty(C, 128) {}
+      Int64Ty(C, 64), Int128Ty(C, 128), Byte1Ty(C, 1), Byte8Ty(C, 8),
+      Byte16Ty(C, 16), Byte32Ty(C, 32), Byte64Ty(C, 64), Byte128Ty(C, 128) {}
 
 LLVMContextImpl::~LLVMContextImpl() {
 #ifndef NDEBUG
@@ -119,6 +120,10 @@ LLVMContextImpl::~LLVMContextImpl() {
   IntOneConstants.clear();
   IntConstants.clear();
   IntSplatConstants.clear();
+  ByteZeroConstants.clear();
+  ByteOneConstants.clear();
+  ByteConstants.clear();
+  ByteSplatConstants.clear();
   FPConstants.clear();
   FPSplatConstants.clear();
   CDSConstants.clear();
diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h
index 2c9921df0422e..85aaecede4795 100644
--- a/llvm/lib/IR/LLVMContextImpl.h
+++ b/llvm/lib/IR/LLVMContextImpl.h
@@ -1674,6 +1674,12 @@ class LLVMContextImpl {
   DenseMap<std::pair<ElementCount, APInt>, std::unique_ptr<ConstantInt>>
       IntSplatConstants;
 
+  DenseMap<unsigned, std::unique_ptr<ConstantByte>> ByteZeroConstants;
+  DenseMap<unsigned, std::unique_ptr<ConstantByte>> ByteOneConstants;
+  DenseMap<APInt, std::unique_ptr<ConstantByte>> ByteConstants;
+  DenseMap<std::pair<ElementCount, APInt>, std::unique_ptr<ConstantByte>>
+      ByteSplatConstants;
+
   DenseMap<APFloat, std::unique_ptr<ConstantFP>> FPConstants;
   DenseMap<std::pair<ElementCount, APFloat>, std::unique_ptr<ConstantFP>>
       FPSplatConstants;
@@ -1743,11 +1749,15 @@ class LLVMContextImpl {
   ConstantInt *TheTrueVal = nullptr;
   ConstantInt *TheFalseVal = nullptr;
 
+  ConstantByte *TheTrueByteVal = nullptr;
+  ConstantByte *TheFalseByteVal = nullptr;
+
   // Basic type instances.
   Type VoidTy, LabelTy, HalfTy, BFloatTy, FloatTy, DoubleTy, MetadataTy,
       TokenTy;
   Type X86_FP80Ty, FP128Ty, PPC_FP128Ty, X86_AMXTy;
   IntegerType Int1Ty, Int8Ty, Int16Ty, Int32Ty, Int64Ty, Int128Ty;
+  ByteType Byte1Ty, Byte8Ty, Byte16Ty, Byte32Ty, Byte64Ty, Byte128Ty;
 
   std::unique_ptr<ConstantTokenNone> TheNoneToken;
 
@@ -1756,6 +1766,7 @@ class LLVMContextImpl {
   SpecificBumpPtrAllocator<ConstantRangeAttributeImpl>
       ConstantRangeAttributeAlloc;
 
+  DenseMap<unsigned, ByteType *> ByteTypes;
   DenseMap<unsigned, IntegerType *> IntegerTypes;
 
   using FunctionTypeSet = DenseSet<FunctionType *, FunctionTypeKeyInfo>;
diff --git a/llvm/lib/IR/Type.cpp b/llvm/lib/IR/Type.cpp
index 299d07b81837b..585c9c45c3524 100644
--- a/llvm/lib/IR/Type.cpp
+++ b/llvm/lib/IR/Type.cpp
@@ -54,6 +54,10 @@ Type *Type::getPrimitiveType(LLVMContext &C, TypeID IDNumber) {
   }
 }
 
+bool Type::isByteTy(unsigned BitWidth) const {
+  return isByteTy() && cast<ByteType>(this)->getBitWidth() == BitWidth;
+}
+
 bool Type::isIntegerTy(unsigned Bitwidth) const {
   return isIntegerTy() && cast<IntegerType>(this)->getBitWidth() == Bitwidth;
 }
@@ -212,6 +216,8 @@ TypeSize Type::getPrimitiveSizeInBits() const {
     return TypeSize::getFixed(128);
   case Type::X86_AMXTyID:
     return TypeSize::getFixed(8192);
+  case Type::ByteTyID:
+    return TypeSize::getFixed(cast<ByteType>(this)->getBitWidth());
   case Type::IntegerTyID:
     return TypeSize::getFixed(cast<IntegerType>(this)->getBitWidth());
   case Type::FixedVectorTyID:
@@ -290,6 +296,17 @@ Type *Type::getFP128Ty(LLVMContext &C) { return &C.pImpl->FP128Ty; }
 Type *Type::getPPC_FP128Ty(LLVMContext &C) { return &C.pImpl->PPC_FP128Ty; }
 Type *Type::getX86_AMXTy(LLVMContext &C) { return &C.pImpl->X86_AMXTy; }
 
+ByteType *Type::getByte1Ty(LLVMContext &C) { return &C.pImpl->Byte1Ty; }
+ByteType *Type::getByte8Ty(LLVMContext &C) { return &C.pImpl->Byte8Ty; }
+ByteType *Type::getByte16Ty(LLVMContext &C) { return &C.pImpl->Byte16Ty; }
+ByteType *Type::getByte32Ty(LLVMContext &C) { return &C.pImpl->Byte32Ty; }
+ByteType *Type::getByte64Ty(LLVMContext &C) { return &C.pImpl->Byte64Ty; }
+ByteType *Type::getByte128Ty(LLVMContext &C) { return &C.pImpl->Byte128Ty; }
+
+ByteType *Type::getByteNTy(LLVMContext &C, unsigned N) {
+  return ByteType::get(C, N);
+}
+
 IntegerType *Type::getInt1Ty(LLVMContext &C) { return &C.pImpl->Int1Ty; }
 IntegerType *Type::getInt8Ty(LLVMContext &C) { return &C.pImpl->Int8Ty; }
 IntegerType *Type::getInt16Ty(LLVMContext &C) { return &C.pImpl->Int16Ty; }
@@ -341,6 +358,40 @@ IntegerType *IntegerType::get(LLVMContext &C, unsigned NumBits) {
 
 APInt IntegerType::getMask() const { return APInt::getAllOnes(getBitWidth()); }
 
+//===----------------------------------------------------------------------===//
+//                       ByteType Implementation
+//===----------------------------------------------------------------------===//
+
+ByteType *ByteType::get(LLVMContext &C, unsigned NumBits) {
+  assert(NumBits >= MIN_BYTE_BITS && "bitwidth too small");
+  assert(NumBits <= MAX_BYTE_BITS && "bitwidth too large");
+
+  // Check for the built-in byte types
+  switch (NumBits) {
+  case 8:
+    return cast<ByteType>(Type::getByte8Ty(C));
+  case 16:
+    return cast<ByteType>(Type::getByte16Ty(C));
+  case 32:
+    return cast<ByteType>(Type::getByte32Ty(C));
+  case 64:
+    return cast<ByteType>(Type::getByte64Ty(C));
+  case 128:
+    return cast<ByteType>(Type::getByte128Ty(C));
+  default:
+    break;
+  }
+
+  ByteType *&Entry = C.pImpl->ByteTypes[NumBits];
+
+  if (!Entry)
+    Entry = new (C.pImpl->Alloc) ByteType(C, NumBits);
+
+  return Entry;
+}
+
+APInt ByteType::getMask() const { return APInt::getAllOnes(getBitWidth()); }
+
 //===----------------------------------------------------------------------===//
 //                       FunctionType Implementation
 //===----------------------------------------------------------------------===//
@@ -788,7 +839,8 @@ VectorType *VectorType::get(Type *ElementType, ElementCount EC) {
 
 bool VectorType::isValidElementType(Type *ElemTy) {
   if (ElemTy->isIntegerTy() || ElemTy->isFloatingPointTy() ||
-      ElemTy->isPointerTy() || ElemTy->getTypeID() == TypedPointerTyID)
+      ElemTy->isPointerTy() || ElemTy->getTypeID() == TypedPointerTyID ||
+      ElemTy->isByteTy())
     return true;
   if (auto *TTy = dyn_cast<TargetExtType>(ElemTy))
     return TTy->hasProperty(TargetExtType::CanBeVectorElement);
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 3d44d1317ecc7..a9962aed295b0 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -4619,9 +4619,10 @@ void Verifier::visitLoadInst(LoadInst &LI) {
               LI.getOrdering() != AtomicOrdering::AcquireRelease,
           "Load cannot have Release ordering", &LI);
     Check(ElTy->getScalarType()->isIntOrPtrTy() ||
+              ElTy->getScalarType()->isByteTy() ||
               ElTy->getScalarType()->isFloatingPointTy(),
-          "atomic load operand must have integer, pointer, floating point, "
-          "or vector type!",
+          "atomic load operand must have integer, byte, pointer, floating "
+          "point, or vector type!",
           ElTy, &LI);
 
     checkAtomicMemAccessSize(ElTy, &LI);
@@ -4647,9 +4648,10 @@ void Verifier::visitStoreInst(StoreInst &SI) {
               SI.getOrdering() != AtomicOrdering::AcquireRelease,
           "Store cannot have Acquire ordering", &SI);
     Check(ElTy->getScalarType()->isIntOrPtrTy() ||
+              ElTy->getScalarType()->isByteTy() ||
               ElTy->getScalarType()->isFloatingPointTy(),
-          "atomic store operand must have integer, pointer, floating point, "
-          "or vector type!",
+          "atomic store operand must have integer, byte, pointer, floating "
+          "point, or vector type!",
           ElTy, &SI);
     checkAtomicMemAccessSize(ElTy, &SI);
   } else {
diff --git a/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp b/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp
index 48a9085820471..7feaf5a7bb68e 100644
--- a/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp
+++ b/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp
@@ -77,6 +77,7 @@ class DXILBitcodeWriter {
     // CONSTANTS_BLOCK abbrev id's.
     CONSTANTS_SETTYPE_ABBREV = bitc::FIRST_APPLICATION_ABBREV,
     CONSTANTS_INTEGER_ABBREV,
+    CONSTANTS_BYTE_ABBREV,
     CONSTANTS_CE_CAST_Abbrev,
     CONSTANTS_NULL_Abbrev,
 
@@ -2014,6 +2015,24 @@ void DXILBitcodeWriter::writeConstants(unsigned FirstVal, unsigned LastVal,
         }
         Code = bitc::CST_CODE_WIDE_INTEGER;
       }
+    } else if (const ConstantByte *BV = dyn_cast<ConstantByte>(C)) {
+      if (BV->getBitWidth() <= 64) {
+        uint64_t V = BV->getZExtValue();
+        emitSignedInt64(Record, V);
+        Code = bitc::CST_CODE_BYTE;
+        AbbrevToUse = CONSTANTS_BYTE_ABBREV;
+      } else { // Wide bytes, > 64 bits in size.
+        // We have an arbitrary precision byte value to write whose
+        // bit width is > 64. However, in canonical unsigned integer
+        // format it is likely that the high bits are going to be zero.
+        // So, we only write the number of active words.
+        unsigned NWords = BV->getValue().getActiveWords();
+        const uint64_t *RawWords = BV->getValue().getRawData();
+        for (unsigned i = 0; i != NWords; ++i) {
+          emitSignedInt64(Record, RawWords[i]);
+        }
+        Code = bitc::CST_CODE_WIDE_BYTE;
+      }
     } else if (const ConstantFP *CFP = dyn_cast<ConstantFP>(C)) {
       Code = bitc::CST_CODE_FLOAT;
       Type *Ty = CFP->getType();
diff --git a/llvm/lib/Target/Hexagon/HexagonTargetObjectFile.cpp b/llvm/lib/Target/Hexagon/HexagonTargetObjectFile.cpp
index 0c1b0aea41f41..0212dffa38645 100644
--- a/llvm/lib/Target/Hexagon/HexagonTargetObjectFile.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonTargetObjectFile.cpp
@@ -316,6 +316,7 @@ unsigned HexagonTargetObjectFile::getSmallestAddressableSize(const Type *Ty,
   case Type::HalfTyID:
   case Type::FloatTyID:
   case Type::DoubleTyID:
+  case Type::ByteTyID:
   case Type::IntegerTyID: {
     const DataLayout &DL = GV->getDataLayout();
     // It is unfortunate that DL's function take non-const Type*.
diff --git a/llvm/test/Analysis/IR2Vec/Inputs/reference_default_vocab_print.txt b/llvm/test/Analysis/IR2Vec/Inputs/reference_default_vocab_print.txt
index d62b0dd157b0b..12d1567466b1b 100644
--- a/llvm/test/Analysis/IR2Vec/Inputs/reference_default_vocab_print.txt
+++ b/llvm/test/Analysis/IR2Vec/Inputs/reference_default_vocab_print.txt
@@ -73,6 +73,7 @@ Key: MetadataTy:  [ 3.50  4.00 ]
 Key: VectorTy:  [ 11.50  12.00 ]
 Key: TokenTy:  [ 5.50  6.00 ]
 Key: IntegerTy:  [ 6.50  7.00 ]
+Key: ByteTy:  [ 0.00  0.00 ]
 Key: FunctionTy:  [ 7.50  8.00 ]
 Key: PointerTy:  [ 8.50  9.00 ]
 Key: StructTy:  [ 9.50  10.00 ]
diff --git a/llvm/test/Analysis/IR2Vec/Inputs/reference_wtd1_vocab_print.txt b/llvm/test/Analysis/IR2Vec/Inputs/reference_wtd1_vocab_print.txt
index e443adb17ac78..cb775622dc722 100644
--- a/llvm/test/Analysis/IR2Vec/Inputs/reference_wtd1_vocab_print.txt
+++ b/llvm/test/Analysis/IR2Vec/Inputs/reference_wtd1_vocab_print.txt
@@ -73,6 +73,7 @@ Key: MetadataTy:  [ 3.50  4.00 ]
 Key: VectorTy:  [ 11.50  12.00 ]
 Key: TokenTy:  [ 5.50  6.00 ]
 Key: IntegerTy:  [ 6.50  7.00 ]
+Key: ByteTy:  [ 0.00  0.00 ]
 Key: FunctionTy:  [ 7.50  8.00 ]
 Key: PointerTy:  [ 8.50  9.00 ]
 Key: StructTy:  [ 9.50  10.00 ]
diff --git a/llvm/test/Analysis/IR2Vec/Inputs/reference_wtd2_vocab_print.txt b/llvm/test/Analysis/IR2Vec/Inputs/reference_wtd2_vocab_print.txt
index 7fb6043552f7b..cafc8eb1b7e23 100644
--- a/llvm/test/Analysis/IR2Vec/Inputs/reference_wtd2_vocab_print.txt
+++ b/llvm/test/Analysis/IR2Vec/Inputs/reference_wtd2_vocab_print.txt
@@ -73,6 +73,7 @@ Key: MetadataTy:  [ 0.00  0.00 ]
 Key: VectorTy:  [ 0.00  0.00 ]
 Key: TokenTy:  [ 0.00  0.00 ]
 Key: IntegerTy:  [ 0.00  0.00 ]
+Key: ByteTy:  [ 0.00  0.00 ]
 Key: FunctionTy:  [ 0.00  0.00 ]
 Key: PointerTy:  [ 0.00  0.00 ]
 Key: StructTy:  [ 0.00  0.00 ]
diff --git a/llvm/test/Assembler/2008-02-18-IntPointerCrash.ll b/llvm/test/Assembler/2008-02-18-IntPointerCrash.ll
index 0d8fbc08917a0..82818adfec309 100644
--- a/llvm/test/Assembler/2008-02-18-IntPointerCrash.ll
+++ b/llvm/test/Assembler/2008-02-18-IntPointerCrash.ll
@@ -1,7 +1,7 @@
 ; RUN: not llvm-as %s 2>&1 | FileCheck %s
 ; PR2060
 
-; CHECK: integer constant must have integer type
+; CHECK: integer/byte constant must have integer/byte type
 
 define ptr @foo() {
        ret ptr 0
diff --git a/llvm/test/Assembler/byte-invalid-cast-1.ll b/llvm/test/Assembler/byte-invalid-cast-1.ll
new file mode 100644
index 0000000000000..793a8c25ea3f1
--- /dev/null
+++ b/llvm/test/Assembler/byte-invalid-cast-1.ll
@@ -0,0 +1,7 @@
+; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s
+
+; CHECK: invalid cast opcode for cast from 'b8' to 'i32'
+define void @invalid_zext(b8 %b) {
+  %t = zext b8 %b to i32
+  ret void
+}
diff --git a/llvm/test/Assembler/byte-invalid-cast-2.ll b/llvm/test/Assembler/byte-invalid-cast-2.ll
new file mode 100644
index 0000000000000..fa2cee7f11005
--- /dev/null
+++ b/llvm/test/Assembler/byte-invalid-cast-2.ll
@@ -0,0 +1,7 @@
+; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s
+
+; CHECK: invalid cast opcode for cast from 'b8' to 'i32'
+define void @invalid_sext(b8 %b) {
+  %t = sext b8 %b to i32
+  ret void
+}
diff --git a/llvm/test/Assembler/byte-invalid-cast-3.ll b/llvm/test/Assembler/byte-invalid-cast-3.ll
new file mode 100644
index 0000000000000..ec78843d70862
--- /dev/null
+++ b/llvm/test/Assembler/byte-invalid-cast-3.ll
@@ -0,0 +1,7 @@
+; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s
+
+; CHECK: invalid cast opcode for cast from 'b32' to 'b8'
+define void @invalid_trunc(b32 %b) {
+  %t = trunc b32 %b to b8
+  ret void
+}
diff --git a/llvm/test/Assembler/byte-invalid-cast-4.ll b/llvm/test/Assembler/byte-invalid-cast-4.ll
new file mode 100644
index 0000000000000..878cdd8e27425
--- /dev/null
+++ b/llvm/test/Assembler/byte-invalid-cast-4.ll
@@ -0,0 +1,7 @@
+; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s
+
+; CHECK: invalid cast opcode for cast from 'i8' to 'b32'
+define void @invalid_zext(i8 %v) {
+  %t = zext i8 %v to b32
+  ret void
+}
diff --git a/llvm/test/Assembler/byte-invalid-cast-5.ll b/llvm/test/Assembler/byte-invalid-cast-5.ll
new file mode 100644
index 0000000000000..bb569ff9c6064
--- /dev/null
+++ b/llvm/test/Assembler/byte-invalid-cast-5.ll
@@ -0,0 +1,7 @@
+; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s
+
+; CHECK: invalid cast opcode for cast from 'i8' to 'b32'
+define void @invalid_sext(i8 %v) {
+  %t = sext i8 %v to b32
+  ret void
+}
diff --git a/llvm/test/Assembler/byte-invalid-cast-6.ll b/llvm/test/Assembler/byte-invalid-cast-6.ll
new file mode 100644
index 0000000000000..fcfb00383ce3e
--- /dev/null
+++ b/llvm/test/Assembler/byte-invalid-cast-6.ll
@@ -0,0 +1,7 @@
+; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s
+
+; CHECK: invalid cast opcode for cast from 'i32' to 'b8'
+define void @invalid_trunc(i32 %v) {
+  %t = trunc i32 %v to b8
+  ret void
+}
diff --git a/llvm/test/Assembler/byte-invalid-cast-7.ll b/llvm/test/Assembler/byte-invalid-cast-7.ll
new file mode 100644
index 0000000000000..edad062e0cbcd
--- /dev/null
+++ b/llvm/test/Assembler/byte-invalid-cast-7.ll
@@ -0,0 +1,7 @@
+; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s
+
+; CHECK: invalid cast opcode for cast from 'b32' to 'i8'
+define void @invalid_trunc(b32 %b) {
+  %t = trunc b32 %b to i8
+  ret void
+}
diff --git a/llvm/test/Assembler/byte-invalid-cast-8.ll b/llvm/test/Assembler/byte-invalid-cast-8.ll
new file mode 100644
index 0000000000000..2d92841c870ce
--- /dev/null
+++ b/llvm/test/Assembler/byte-invalid-cast-8.ll
@@ -0,0 +1,7 @@
+; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s
+
+; CHECK: invalid operand type for instruction
+define void @invalid_lshr(b32 %b) {
+  %t = lshr b32 %b, 8
+  ret void
+}
diff --git a/llvm/test/Assembler/byte-invalid-cmp.ll b/llvm/test/Assembler/byte-invalid-cmp.ll
new file mode 100644
index 0000000000000..8206b037ea911
--- /dev/null
+++ b/llvm/test/Assembler/byte-invalid-cmp.ll
@@ -0,0 +1,7 @@
+; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s
+
+; CHECK: icmp requires integer operands
+define void @byte_compare(b8 %b1, b8 %b2) {
+  %cmp = icmp eq b8 %b1, %b2
+  ret void
+}
diff --git a/llvm/test/Assembler/byte.ll b/llvm/test/Assembler/byte.ll
new file mode 100644
index 0000000000000..2a896337a3f02
--- /dev/null
+++ b/llvm/test/Assembler/byte.ll
@@ -0,0 +1,102 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt < %s -S | FileCheck %s
+
+; CHECK: common global [32 x b8] zeroinitializer
+; CHECK: constant [1 x b8] zeroinitializer
+; CHECK: constant [15 x b8] c"Hello, World!\0A\00"
+; CHECK: constant [15 x b8] c"Hello, World!\0A\00"
+ at a = common global [32 x b8] zeroinitializer, align 1
+ at b = constant [1 x b8] zeroinitializer
+ at c = constant [15 x b8] [b8 72, b8 101, b8 108, b8 108, b8 111, b8 44, b8 32,  b8 87, b8 111, b8 114, b8 108, b8 100, b8 33,  b8 10, b8 0]
+ at d = constant [15 x b8] c"Hello, World!\0A\00"
+
+define void @bytes(b1 %a, b3 %b, b5 %c, b8 %d, b16 %e, b32 %f, b64 %g, b128 %h, <8 x b5> %i, <2 x b64> %j) {
+; CHECK-LABEL: define void @bytes(
+; CHECK-SAME: b1 [[A:%.*]], b3 [[B:%.*]], b5 [[C:%.*]], b8 [[D:%.*]], b16 [[E:%.*]], b32 [[F:%.*]], b64 [[G:%.*]], b128 [[H:%.*]], <8 x b5> [[I:%.*]], <2 x b64> [[J:%.*]]) {
+; CHECK-NEXT:    ret void
+;
+  ret void
+}
+
+define void @byte_alloca() {
+; CHECK-LABEL: define void @byte_alloca() {
+; CHECK-NEXT:    [[B1:%.*]] = alloca b8, align 1
+; CHECK-NEXT:    [[B8:%.*]] = alloca b64, align 8
+; CHECK-NEXT:    [[V:%.*]] = alloca <4 x b64>, align 32
+; CHECK-NEXT:    [[A:%.*]] = alloca [4 x b64], align 8
+; CHECK-NEXT:    ret void
+;
+  %b1 = alloca b8
+  %b8 = alloca b64
+  %v  = alloca <4 x b64>
+  %a  = alloca [4 x b64]
+  ret void
+}
+
+define void @byte_load_store(ptr %ptr) {
+; CHECK-LABEL: define void @byte_load_store(
+; CHECK-SAME: ptr [[PTR:%.*]]) {
+; CHECK-NEXT:    [[B:%.*]] = load b8, ptr [[PTR]], align 1
+; CHECK-NEXT:    store b8 [[B]], ptr [[PTR]], align 1
+; CHECK-NEXT:    store b8 0, ptr [[PTR]], align 1
+; CHECK-NEXT:    [[V:%.*]] = load <4 x b64>, ptr [[PTR]], align 32
+; CHECK-NEXT:    store <4 x b64> [[V]], ptr [[PTR]], align 32
+; CHECK-NEXT:    store <4 x b64> <b64 0, b64 1, b64 2, b64 3>, ptr [[PTR]], align 32
+; CHECK-NEXT:    [[A:%.*]] = load [4 x b8], ptr [[PTR]], align 1
+; CHECK-NEXT:    store [4 x b8] [[A]], ptr [[PTR]], align 1
+; CHECK-NEXT:    store [4 x b8] c"\00\01\02\03", ptr [[PTR]], align 1
+; CHECK-NEXT:    ret void
+;
+  %b = load b8, ptr %ptr
+  store b8 %b, ptr %ptr
+  store b8 0, ptr %ptr
+  %v = load <4 x b64>, ptr %ptr
+  store <4 x b64> %v, ptr %ptr
+  store <4 x b64> <b64 0, b64 1, b64 2, b64 3>, ptr %ptr
+  %a = load [4 x b8], ptr %ptr
+  store [4 x b8] %a, ptr %ptr
+  store [4 x b8] [b8 0, b8 1, b8 2, b8 3], ptr %ptr
+  ret void
+}
+
+define void @bitcasts(i64 %i, b64 %b, ptr %p) {
+; CHECK-LABEL: define void @bitcasts(
+; CHECK-SAME: i64 [[I:%.*]], b64 [[B:%.*]], ptr [[P:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = bitcast ptr [[P]] to b64
+; CHECK-NEXT:    [[TMP2:%.*]] = bitcast i64 [[I]] to b64
+; CHECK-NEXT:    [[TMP3:%.*]] = bitcast b64 [[B]] to <8 x b8>
+; CHECK-NEXT:    [[TMP4:%.*]] = bitcast b64 [[B]] to i64
+; CHECK-NEXT:    [[TMP5:%.*]] = bitcast b64 [[B]] to ptr
+; CHECK-NEXT:    [[TMP6:%.*]] = bitcast <8 x b8> [[TMP3]] to <2 x b32>
+; CHECK-NEXT:    [[TMP7:%.*]] = bitcast <2 x b32> [[TMP6]] to b64
+; CHECK-NEXT:    [[TMP8:%.*]] = bitcast <2 x b32> splat (b32 1) to b64
+; CHECK-NEXT:    [[TMP9:%.*]] = bitcast <8 x b8> [[TMP3]] to <4 x i16>
+; CHECK-NEXT:    [[TMP10:%.*]] = bitcast <2 x b32> [[TMP6]] to ptr
+; CHECK-NEXT:    ret void
+;
+  %1 = bitcast ptr %p to b64
+  %2 = bitcast i64 %i to b64
+  %3 = bitcast b64 %b to <8 x b8>
+  %4 = bitcast b64 %b to i64
+  %5 = bitcast b64 %b to ptr
+  %6 = bitcast <8 x b8> %3 to <2 x b32>
+  %7 = bitcast <2 x b32> %6 to b64
+  %8 = bitcast <2 x b32> <b32 1, b32 1> to b64
+  %9 = bitcast <8 x b8> %3 to <4 x i16>
+  %10 = bitcast <2 x b32> %6 to ptr
+  ret void
+}
+
+define void @freeze(b3 %t, b64 %b, <4 x b64> %v) {
+; CHECK-LABEL: define void @freeze(
+; CHECK-SAME: b3 [[T:%.*]], b64 [[B:%.*]], <4 x b64> [[V:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = freeze b3 [[T]]
+; CHECK-NEXT:    [[TMP2:%.*]] = freeze b64 [[B]]
+; CHECK-NEXT:    [[TMP3:%.*]] = freeze <4 x b64> [[V]]
+; CHECK-NEXT:    ret void
+;
+  %1 = freeze b3 %t
+  %2 = freeze b64 %b
+  %3 = freeze <4 x b64> %v
+  ret void
+}
diff --git a/llvm/test/Assembler/invalid-inttype.ll b/llvm/test/Assembler/invalid-inttype.ll
index 9e3c31148af2d..ef050d599875e 100644
--- a/llvm/test/Assembler/invalid-inttype.ll
+++ b/llvm/test/Assembler/invalid-inttype.ll
@@ -1,5 +1,5 @@
 ; RUN: not llvm-as --disable-output %s 2>&1 | FileCheck -DFILE=%s %s
 
 ; i8388609 is the smallest integer type that can't be represented in LLVM IR
-; CHECK: [[FILE]]:[[@LINE+1]]:21: error: bitwidth for integer type out of range
+; CHECK: [[FILE]]:[[@LINE+1]]:21: error: bitwidth for integer or byte type out of range
 @i2 = common global i8388609 0, align 4
diff --git a/llvm/test/Bindings/llvm-c/byte.ll b/llvm/test/Bindings/llvm-c/byte.ll
new file mode 100644
index 0000000000000..93b9819c3c9b9
--- /dev/null
+++ b/llvm/test/Bindings/llvm-c/byte.ll
@@ -0,0 +1,11 @@
+; RUN: llvm-as < %s | llvm-dis > %t.orig
+; RUN: llvm-as < %s | llvm-c-test --echo > %t.echo
+; RUN: diff -w %t.orig %t.echo
+
+define void @foo(b8 %a, b16 %b, b64 %c) {
+  %1 = alloca b16, align 2
+  store b16 %b, ptr %1, align 2
+  %2 = load b16, ptr %1, align 2
+  %3 = bitcast b16 %2 to <2 x b8>
+  ret void
+}
diff --git a/llvm/test/Bindings/llvm-c/echo.ll b/llvm/test/Bindings/llvm-c/echo.ll
index ab1771d1f879f..0202990018045 100644
--- a/llvm/test/Bindings/llvm-c/echo.ll
+++ b/llvm/test/Bindings/llvm-c/echo.ll
@@ -72,6 +72,7 @@ define void @types() {
   %10 = alloca ptr addrspace(5), align 8
   %11 = alloca <5 x ptr>, align 64
   %12 = alloca <1 x i64>, align 8
+  %13 = alloca b8, align 1
   ret void
 }
 
diff --git a/llvm/test/Bitcode/compatibility.ll b/llvm/test/Bitcode/compatibility.ll
index 53cbe2d6ffd37..1510d6275c56f 100644
--- a/llvm/test/Bitcode/compatibility.ll
+++ b/llvm/test/Bitcode/compatibility.ll
@@ -1270,6 +1270,8 @@ define void @typesystem() {
   ; CHECK: %t9 = alloca <4 x i32>
   %t10 = alloca <vscale x 4 x i32>
   ; CHECK: %t10 = alloca <vscale x 4 x i32>
+  %t11 = alloca b8
+  ; CHECK: %t11 = alloca b8
 
   ret void
 }
diff --git a/llvm/test/CodeGen/X86/byte-constants.ll b/llvm/test/CodeGen/X86/byte-constants.ll
new file mode 100644
index 0000000000000..77b77fc3e50e9
--- /dev/null
+++ b/llvm/test/CodeGen/X86/byte-constants.ll
@@ -0,0 +1,63 @@
+; RUN: llc < %s | FileCheck %s
+
+; CHECK:	.globl x
+; CHECK: x:
+; CHECK: .quad	10
+
+ at x = global b64 bitcast (i64 10 to b64)
+
+; CHECK:	.globl b
+; CHECK: b:
+; CHECK: .byte	1
+
+ at b = global b1 1
+
+; CHECK:	.globl f
+; CHECK: f:
+; CHECK: .byte	31
+
+ at f = global b5 31
+
+; CHECK:	.globl r
+; CHECK: r:
+; CHECK: .long	42
+
+ at r = global b32 42
+
+; CHECK:	.globl w
+; CHECK: w:
+; CHECK: .quad	-1
+; CHECK: .quad	-1
+
+ at w = global b128 -1
+
+; CHECK:	.globl uw
+; CHECK: uw:
+; CHECK: .quad	-1
+; CHECK: .quad	-1
+; CHECK: .quad	-1
+; CHECK: .quad	-1
+
+ at uw = global b256 -1
+
+; CHECK:	.globl v
+; CHECK: v:
+; CHECK: .byte	1
+; CHECK: .byte	2
+; CHECK: .byte	3
+; CHECK: .byte	4
+
+ at v = global <4 x b8> <b8 1, b8 2, b8 3, b8 4>
+
+; CHECK:	.globl uv
+; CHECK: uv:
+; CHECK: .quad	-1
+; CHECK: .quad	-1
+; CHECK: .quad	-1
+; CHECK: .quad	-1
+; CHECK: .quad	-1
+; CHECK: .quad	-1
+; CHECK: .quad	-1
+; CHECK: .quad	-1
+
+ at uv = global <4 x b128> <b128 -1, b128 -1, b128 -1, b128 -1>
diff --git a/llvm/test/Verifier/atomics.ll b/llvm/test/Verifier/atomics.ll
index 17bf5a0528d73..2b1f971e6e91f 100644
--- a/llvm/test/Verifier/atomics.ll
+++ b/llvm/test/Verifier/atomics.ll
@@ -1,6 +1,6 @@
 ; RUN: not opt -passes=verify < %s 2>&1 | FileCheck %s
-; CHECK: atomic store operand must have integer, pointer, floating point, or vector type!
-; CHECK: atomic load operand must have integer, pointer, floating point, or vector type!
+; CHECK: atomic store operand must have integer, byte, pointer, floating point, or vector type!
+; CHECK: atomic load operand must have integer, byte, pointer, floating point, or vector type!
 
 %ty = type { i32 };
 
diff --git a/llvm/test/tools/llvm-ir2vec/entities.ll b/llvm/test/tools/llvm-ir2vec/entities.ll
index 8dbce57302f6f..58c2d74036783 100644
--- a/llvm/test/tools/llvm-ir2vec/entities.ll
+++ b/llvm/test/tools/llvm-ir2vec/entities.ll
@@ -1,6 +1,6 @@
 ; RUN: llvm-ir2vec entities | FileCheck %s
 
-CHECK: 110
+CHECK: 111
 CHECK-NEXT: Ret     0
 CHECK-NEXT: Br      1
 CHECK-NEXT: Switch  2
@@ -76,38 +76,39 @@ CHECK-NEXT: MetadataTy      71
 CHECK-NEXT: VectorTy        72
 CHECK-NEXT: TokenTy 73
 CHECK-NEXT: IntegerTy       74
-CHECK-NEXT: FunctionTy      75
-CHECK-NEXT: PointerTy       76
-CHECK-NEXT: StructTy        77
-CHECK-NEXT: ArrayTy 78
-CHECK-NEXT: UnknownTy       79
-CHECK-NEXT: Function        80
-CHECK-NEXT: Pointer 81
-CHECK-NEXT: Constant        82
-CHECK-NEXT: Variable        83
-CHECK-NEXT: FCMP_false   84
-CHECK-NEXT: FCMP_oeq     85
-CHECK-NEXT: FCMP_ogt     86
-CHECK-NEXT: FCMP_oge     87
-CHECK-NEXT: FCMP_olt     88
-CHECK-NEXT: FCMP_ole     89
-CHECK-NEXT: FCMP_one     90
-CHECK-NEXT: FCMP_ord     91
-CHECK-NEXT: FCMP_uno     92
-CHECK-NEXT: FCMP_ueq     93
-CHECK-NEXT: FCMP_ugt     94
-CHECK-NEXT: FCMP_uge     95
-CHECK-NEXT: FCMP_ult     96
-CHECK-NEXT: FCMP_ule     97
-CHECK-NEXT: FCMP_une     98
-CHECK-NEXT: FCMP_true    99
-CHECK-NEXT: ICMP_eq      100
-CHECK-NEXT: ICMP_ne      101
-CHECK-NEXT: ICMP_ugt     102
-CHECK-NEXT: ICMP_uge     103
-CHECK-NEXT: ICMP_ult     104
-CHECK-NEXT: ICMP_ule     105
-CHECK-NEXT: ICMP_sgt     106
-CHECK-NEXT: ICMP_sge     107
-CHECK-NEXT: ICMP_slt     108
-CHECK-NEXT: ICMP_sle     109
+CHECK-NEXT: ByteTy  75
+CHECK-NEXT: FunctionTy      76
+CHECK-NEXT: PointerTy       77
+CHECK-NEXT: StructTy        78
+CHECK-NEXT: ArrayTy 79
+CHECK-NEXT: UnknownTy       80
+CHECK-NEXT: Function        81
+CHECK-NEXT: Pointer 82
+CHECK-NEXT: Constant        83
+CHECK-NEXT: Variable        84
+CHECK-NEXT: FCMP_false   85
+CHECK-NEXT: FCMP_oeq     86
+CHECK-NEXT: FCMP_ogt     87
+CHECK-NEXT: FCMP_oge     88
+CHECK-NEXT: FCMP_olt     89
+CHECK-NEXT: FCMP_ole     90
+CHECK-NEXT: FCMP_one     91
+CHECK-NEXT: FCMP_ord     92
+CHECK-NEXT: FCMP_uno     93
+CHECK-NEXT: FCMP_ueq     94
+CHECK-NEXT: FCMP_ugt     95
+CHECK-NEXT: FCMP_uge     96
+CHECK-NEXT: FCMP_ult     97
+CHECK-NEXT: FCMP_ule     98
+CHECK-NEXT: FCMP_une     99
+CHECK-NEXT: FCMP_true    100
+CHECK-NEXT: ICMP_eq      101
+CHECK-NEXT: ICMP_ne      102
+CHECK-NEXT: ICMP_ugt     103
+CHECK-NEXT: ICMP_uge     104
+CHECK-NEXT: ICMP_ult     105
+CHECK-NEXT: ICMP_ule     106
+CHECK-NEXT: ICMP_sgt     107
+CHECK-NEXT: ICMP_sge     108
+CHECK-NEXT: ICMP_slt     109
+CHECK-NEXT: ICMP_sle     110
diff --git a/llvm/test/tools/llvm-ir2vec/triplets.ll b/llvm/test/tools/llvm-ir2vec/triplets.ll
index 7b476f60a07b3..1a7220cc9c3c5 100644
--- a/llvm/test/tools/llvm-ir2vec/triplets.ll
+++ b/llvm/test/tools/llvm-ir2vec/triplets.ll
@@ -26,40 +26,40 @@ entry:
 
 ; TRIPLETS: MAX_RELATION=3
 ; TRIPLETS-NEXT: 12      74      0
-; TRIPLETS-NEXT: 12      83      2
-; TRIPLETS-NEXT: 12      83      3
+; TRIPLETS-NEXT: 12      84      2
+; TRIPLETS-NEXT: 12      84      3
 ; TRIPLETS-NEXT: 12      0       1
 ; TRIPLETS-NEXT: 0       69      0
-; TRIPLETS-NEXT: 0       83      2
+; TRIPLETS-NEXT: 0       84      2
 ; TRIPLETS-NEXT: 16      74      0
-; TRIPLETS-NEXT: 16      83      2
-; TRIPLETS-NEXT: 16      83      3
+; TRIPLETS-NEXT: 16      84      2
+; TRIPLETS-NEXT: 16      84      3
 ; TRIPLETS-NEXT: 16      0       1
 ; TRIPLETS-NEXT: 0       69      0
-; TRIPLETS-NEXT: 0       83      2
-; TRIPLETS-NEXT: 30      76      0
-; TRIPLETS-NEXT: 30      82      2
+; TRIPLETS-NEXT: 0       84      2
+; TRIPLETS-NEXT: 30      77      0
+; TRIPLETS-NEXT: 30      83      2
 ; TRIPLETS-NEXT: 30      30      1
-; TRIPLETS-NEXT: 30      76      0
-; TRIPLETS-NEXT: 30      82      2
+; TRIPLETS-NEXT: 30      77      0
+; TRIPLETS-NEXT: 30      83      2
 ; TRIPLETS-NEXT: 30      32      1
 ; TRIPLETS-NEXT: 32      69      0
-; TRIPLETS-NEXT: 32      83      2
-; TRIPLETS-NEXT: 32      81      3
+; TRIPLETS-NEXT: 32      84      2
+; TRIPLETS-NEXT: 32      82      3
 ; TRIPLETS-NEXT: 32      32      1
 ; TRIPLETS-NEXT: 32      69      0
-; TRIPLETS-NEXT: 32      83      2
-; TRIPLETS-NEXT: 32      81      3
+; TRIPLETS-NEXT: 32      84      2
+; TRIPLETS-NEXT: 32      82      3
 ; TRIPLETS-NEXT: 32      31      1
 ; TRIPLETS-NEXT: 31      74      0
-; TRIPLETS-NEXT: 31      81      2
+; TRIPLETS-NEXT: 31      82      2
 ; TRIPLETS-NEXT: 31      31      1
 ; TRIPLETS-NEXT: 31      74      0
-; TRIPLETS-NEXT: 31      81      2
+; TRIPLETS-NEXT: 31      82      2
 ; TRIPLETS-NEXT: 31      12      1
 ; TRIPLETS-NEXT: 12      74      0
-; TRIPLETS-NEXT: 12      83      2
-; TRIPLETS-NEXT: 12      83      3
+; TRIPLETS-NEXT: 12      84      2
+; TRIPLETS-NEXT: 12      84      3
 ; TRIPLETS-NEXT: 12      0       1
 ; TRIPLETS-NEXT: 0       69      0
-; TRIPLETS-NEXT: 0       83      2
\ No newline at end of file
+; TRIPLETS-NEXT: 0       84      2
\ No newline at end of file
diff --git a/llvm/tools/llvm-c-test/echo.cpp b/llvm/tools/llvm-c-test/echo.cpp
index bd640cd8d85ec..e5add4430e5a5 100644
--- a/llvm/tools/llvm-c-test/echo.cpp
+++ b/llvm/tools/llvm-c-test/echo.cpp
@@ -89,6 +89,8 @@ struct TypeCloner {
         return LLVMPPCFP128TypeInContext(Ctx);
       case LLVMLabelTypeKind:
         return LLVMLabelTypeInContext(Ctx);
+      case LLVMByteTypeKind:
+        return LLVMByteTypeInContext(Ctx, LLVMGetByteTypeWidth(Src));
       case LLVMIntegerTypeKind:
         return LLVMIntTypeInContext(Ctx, LLVMGetIntTypeWidth(Src));
       case LLVMFunctionTypeKind: {
diff --git a/llvm/unittests/Analysis/IR2VecTest.cpp b/llvm/unittests/Analysis/IR2VecTest.cpp
index e085568a135fe..a095761bc246a 100644
--- a/llvm/unittests/Analysis/IR2VecTest.cpp
+++ b/llvm/unittests/Analysis/IR2VecTest.cpp
@@ -333,8 +333,8 @@ TEST_F(IR2VecTestFixture, GetInstVec_Symbolic) {
   EXPECT_EQ(AddEmb.size(), 2u);
   EXPECT_EQ(RetEmb.size(), 2u);
 
-  EXPECT_TRUE(AddEmb.approximatelyEquals(Embedding(2, 25.5)));
-  EXPECT_TRUE(RetEmb.approximatelyEquals(Embedding(2, 15.5)));
+  EXPECT_TRUE(AddEmb.approximatelyEquals(Embedding(2, 25.7)));
+  EXPECT_TRUE(RetEmb.approximatelyEquals(Embedding(2, 15.6)));
 }
 
 TEST_F(IR2VecTestFixture, GetInstVec_FlowAware) {
@@ -346,8 +346,8 @@ TEST_F(IR2VecTestFixture, GetInstVec_FlowAware) {
   EXPECT_EQ(AddEmb.size(), 2u);
   EXPECT_EQ(RetEmb.size(), 2u);
 
-  EXPECT_TRUE(AddEmb.approximatelyEquals(Embedding(2, 25.5)));
-  EXPECT_TRUE(RetEmb.approximatelyEquals(Embedding(2, 32.6)));
+  EXPECT_TRUE(AddEmb.approximatelyEquals(Embedding(2, 25.7)));
+  EXPECT_TRUE(RetEmb.approximatelyEquals(Embedding(2, 32.8)));
 }
 
 TEST_F(IR2VecTestFixture, GetBBVector_Symbolic) {
@@ -357,9 +357,9 @@ TEST_F(IR2VecTestFixture, GetBBVector_Symbolic) {
   const auto &BBVec = Emb->getBBVector(*BB);
 
   EXPECT_EQ(BBVec.size(), 2u);
-  // BB vector should be sum of add and ret: {25.5, 25.5} + {15.5, 15.5} =
-  // {41.0, 41.0}
-  EXPECT_TRUE(BBVec.approximatelyEquals(Embedding(2, 41.0)));
+  // BB vector should be sum of add and ret: {25.7, 25.7} + {15.6, 15.6} =
+  // {41.3, 41.3}
+  EXPECT_TRUE(BBVec.approximatelyEquals(Embedding(2, 41.3)));
 }
 
 TEST_F(IR2VecTestFixture, GetBBVector_FlowAware) {
@@ -369,9 +369,9 @@ TEST_F(IR2VecTestFixture, GetBBVector_FlowAware) {
   const auto &BBVec = Emb->getBBVector(*BB);
 
   EXPECT_EQ(BBVec.size(), 2u);
-  // BB vector should be sum of add and ret: {25.5, 25.5} + {32.6, 32.6} =
-  // {58.1, 58.1}
-  EXPECT_TRUE(BBVec.approximatelyEquals(Embedding(2, 58.1)));
+  // BB vector should be sum of add and ret: {25.7, 25.7} + {32.8, 32.8} =
+  // {58.5, 58.5}
+  EXPECT_TRUE(BBVec.approximatelyEquals(Embedding(2, 58.5)));
 }
 
 TEST_F(IR2VecTestFixture, GetFunctionVector_Symbolic) {
@@ -382,8 +382,8 @@ TEST_F(IR2VecTestFixture, GetFunctionVector_Symbolic) {
 
   EXPECT_EQ(FuncVec.size(), 2u);
 
-  // Function vector should match BB vector (only one BB): {41.0, 41.0}
-  EXPECT_TRUE(FuncVec.approximatelyEquals(Embedding(2, 41.0)));
+  // Function vector should match BB vector (only one BB): {41.3, 41.3}
+  EXPECT_TRUE(FuncVec.approximatelyEquals(Embedding(2, 41.3)));
 }
 
 TEST_F(IR2VecTestFixture, GetFunctionVector_FlowAware) {
@@ -393,8 +393,8 @@ TEST_F(IR2VecTestFixture, GetFunctionVector_FlowAware) {
   const auto &FuncVec = Emb->getFunctionVector();
 
   EXPECT_EQ(FuncVec.size(), 2u);
-  // Function vector should match BB vector (only one BB): {58.1, 58.1}
-  EXPECT_TRUE(FuncVec.approximatelyEquals(Embedding(2, 58.1)));
+  // Function vector should match BB vector (only one BB): {58.5, 58.5}
+  EXPECT_TRUE(FuncVec.approximatelyEquals(Embedding(2, 58.5)));
 }
 
 TEST_F(IR2VecTestFixture, MultipleComputeEmbeddingsConsistency_Symbolic) {
@@ -450,6 +450,7 @@ static constexpr unsigned MaxPredicateKinds = Vocabulary::MaxPredicateKinds;
 // names and their canonical string keys.
 #define IR2VEC_HANDLE_TYPE_BIMAP(X)                                            \
   X(VoidTyID, VoidTy, "VoidTy")                                                \
+  X(ByteTyID, ByteTy, "ByteTy")                                                \
   X(IntegerTyID, IntegerTy, "IntegerTy")                                       \
   X(FloatTyID, FloatTy, "FloatTy")                                             \
   X(PointerTyID, PointerTy, "PointerTy")                                       \

>From cfad6d59c5ab11397a5279325c53f5d5beb8dd9a Mon Sep 17 00:00:00 2001
From: Pedro Lobo <pedro.lobo at tecnico.ulisboa.pt>
Date: Wed, 28 Jan 2026 19:34:19 +0000
Subject: [PATCH 2/6] [LangRef] Add section on the byte type

---
 llvm/docs/Frontend/PerformanceTips.rst | 13 ++++
 llvm/docs/LangRef.rst                  | 95 ++++++++++++++++++++++++--
 2 files changed, 103 insertions(+), 5 deletions(-)

diff --git a/llvm/docs/Frontend/PerformanceTips.rst b/llvm/docs/Frontend/PerformanceTips.rst
index b81df707a31a6..a11c8e3a16857 100644
--- a/llvm/docs/Frontend/PerformanceTips.rst
+++ b/llvm/docs/Frontend/PerformanceTips.rst
@@ -95,6 +95,19 @@ For example, when working with boolean values, store them by zero-extending
 If you do use loads/stores on non-byte-sized types, make sure that you *always*
 use those types. For example, do not first store ``i8`` and then load ``i1``.
 
+Use byte types when manipulating raw memory
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The byte type represents raw memory values in SSA registers. Loads and stores of
+byte types should be used when performing raw memory copies (such as ``memmove``
+and ``memcpy``). Using integer types to represent raw memory introduces type
+punning, which discards the provenance of pointers being copied.
+
+Use a byte type if a value may hold either a pointer or any other type at run
+time (and you don't know which one), or if the value may contain uninitialized
+data. For instance, if a union may hold a pointer or another type, use byte
+types to load and store the value. Otherwise, use the specific type.
+
 Prefer zext over sext when legal
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 38f2ad8c166fd..bee9e88a64324 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -787,8 +787,8 @@ be performed as loads and stores of the correct type since stores of other
 types may not propagate the external data.
 Therefore it is not legal to convert an existing load/store (or a
 ``llvm.memcpy`` / ``llvm.memmove`` intrinsic) of pointer types with external
-state to a load/store of an integer type with the same bitwidth, as that may drop
-the external state.
+state to a load/store of an integer or byte type with the same bitwidth, as that
+may drop the external state.
 
 
 .. _globalvars:
@@ -4432,6 +4432,54 @@ Examples:
 | ``i1942652``   | a really big integer of over 1 million bits.   |
 +----------------+------------------------------------------------+
 
+.. _t_byte:
+
+Byte Type
+"""""""""
+
+:Overview:
+
+The byte type represents raw memory data in SSA registers. It should be used
+when it cannot be determined whether a value holds a pointer or another type at
+run time, or if the value contains uninitialized data. Frontends are expected to
+use a byte type when:
+
+#. Lowering memory operations like `memcpy` and `memmove` to load/store pairs
+   without knowing the underlying type being copied.
+
+#. Working with union types that can hold a pointer alongside a non-pointer
+   type.
+
+#. Working with possibly uninitialized data.
+
+Otherwise, when known, the specific specific type should be used. Each bit can
+be:
+
+* An integer bit (0 or 1)
+* Part of a pointer value
+* ``poison``
+
+Any bit width from 1 bit to 2\ :sup:`23`\ (about 8 million) can be specified.
+
+:Syntax:
+
+::
+
+      bN
+
+The number of bits the byte occupies is specified by the ``N`` value.
+
+Examples:
+*********
+
++----------------+------------------------------------------------+
+| ``b1``         | a single-bit byte value.                       |
++----------------+------------------------------------------------+
+| ``b32``        | a 32-bit byte value.                           |
++----------------+------------------------------------------------+
+| ``b128``       | a 128-bit byte value.                          |
++----------------+------------------------------------------------+
+
 .. _t_floating:
 
 Floating-Point Types
@@ -4865,6 +4913,10 @@ Simple Constants
     Note that hexadecimal integers are sign extended from the number
     of active bits, i.e., the bit width minus the number of leading
     zeros. So '``s0x0001``' of type '``i16``' will be -1, not 1.
+**Byte constants**
+    Byte constants are used to initialize global variables of the :ref:`byte
+    <t_byte>` type. These are strictly equivalent to integer constants:
+    ``store b8 42, ptr %p`` is equivalent to ``store i8 42, ptr %p``.
 **Floating-point constants**
     Floating-point constants use standard decimal notation (e.g.
     123.421), exponential notation (e.g., 1.23421e+2), or a more precise
@@ -12998,15 +13050,35 @@ is always a *no-op cast* because no bits change with this
 conversion. The conversion is done as if the ``value`` had been stored
 to memory and read back as type ``ty2``. Pointer (or vector of
 pointers) types may only be converted to other pointer (or vector of
-pointers) types with the same address space through this instruction.
-To convert pointers to other types, use the :ref:`inttoptr <i_inttoptr>`
-or :ref:`ptrtoint <i_ptrtoint>` instructions first.
+pointers) types with the same address space or byte (or vector of bytes) types
+through this instruction. To convert pointers to other types, use the
+:ref:`inttoptr <i_inttoptr>` or :ref:`ptrtoint <i_ptrtoint>` instructions first.
 
 There is a caveat for bitcasts involving vector types in relation to
 endianness. For example ``bitcast <2 x i8> <value> to i16`` puts element zero
 of the vector in the least significant bits of the i16 for little-endian while
 element zero ends up in the most significant bits for big-endian.
 
+If ``value`` is of the :ref:`byte type <t_byte>`:
+
+* If ``value`` contains at least one ``poison`` bit, the cast result is
+``poison``.
+
+* If ``value`` is any mix of (non-``poison``) pointer and non-pointer bits:
+
+    * If ``ty2`` is a non-pointer type, the provenance of the pointer bits is
+    stripped without being exposed, similarly to the
+    :ref:`ptrtoaddr <i_ptrtoaddr>` instruction.
+
+    * If ``ty2`` is a pointer type, then if all bits of ``value`` are from the
+    same pointer and are correctly ordered (there were no pointer bit swaps),
+    the cast result is that pointer. If ``value`` is a mix of bits from
+    different pointers or a mix of pointer and non-pointer bits, the result is a
+    pointer without provenance. This pointer cannot be dereferenced, but can be
+    used in comparisons or :ref:`getelementptr <i_getelementptr>` instructions.
+
+* Otherwise, the cast is a *no-op*.
+
 Example:
 """"""""
 
@@ -13017,6 +13089,15 @@ Example:
       %Z = bitcast <2 x i32> %V to i64; ; yields i64: %V (depends on endianness)
       %Z = bitcast <2 x i32*> %V to <2 x i64*> ; yields <2 x i64*>
 
+      ; considering %bi to hold an integer and %bp to hold a pointer,
+      %a = bitcast b64 %bi to i64       ; returns an integer, no-op cast
+      %b = bitcast b64 %bp to i64       ; reinterprets the pointer as an integer, returning its address without exposing provenance
+      %c = bitcast b64 %bp to ptr       ; returns a pointer, no-op cast
+      %d = bitcast b64 %bi to ptr       ; reinterprets the integer as a pointer, returning a pointer with no provenance
+
+      %e = bitcast <2 x b32> %v to i64  ; reinterprets the raw bytes as an integer
+      %f = bitcast <2 x b32> %v to ptr  ; reinterprets the raw bytes as a pointer
+
 .. _i_addrspacecast:
 
 '``addrspacecast .. to``' Instruction
@@ -13448,6 +13529,7 @@ instructions may yield different values.
 While ``undef`` and ``poison`` pointers can be frozen, the result is a
 non-dereferenceable pointer. See the
 :ref:`Pointer Aliasing Rules <pointeraliasing>` section for more information.
+Values of the :ref:`byte type <t_byte>` are frozen on a per-bit basis.
 If an aggregate value or vector is frozen, the operand is frozen element-wise.
 The padding of an aggregate isn't considered, since it isn't visible
 without storing it into memory and loading it with a different type.
@@ -13476,6 +13558,9 @@ Example:
       %d = extractelement <2 x i32> %v.fr, i32 0 ; not undef
       %add.f = add i32 %d, %d                    ; even number
 
+      %l = load b32, ptr %p                      ; may be unitialized
+      %f = freeze b32 %l                         ; freezes on a per-bit basis
+
       ; branching on frozen value
       %poison = add nsw i1 %k, undef   ; poison
       %c = freeze i1 %poison

>From edabd49dafb4ac28888622c3ae3ce51823196b22 Mon Sep 17 00:00:00 2001
From: Pedro Lobo <pedro.lobo at tecnico.ulisboa.pt>
Date: Mon, 9 Feb 2026 23:28:09 +0000
Subject: [PATCH 3/6] fix docs

---
 llvm/docs/LangRef.rst | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index bee9e88a64324..4699553faa6a5 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -13062,20 +13062,21 @@ element zero ends up in the most significant bits for big-endian.
 If ``value`` is of the :ref:`byte type <t_byte>`:
 
 * If ``value`` contains at least one ``poison`` bit, the cast result is
-``poison``.
+  ``poison``.
 
 * If ``value`` is any mix of (non-``poison``) pointer and non-pointer bits:
 
     * If ``ty2`` is a non-pointer type, the provenance of the pointer bits is
-    stripped without being exposed, similarly to the
-    :ref:`ptrtoaddr <i_ptrtoaddr>` instruction.
+      stripped without being exposed, similarly to the
+      :ref:`ptrtoaddr <i_ptrtoaddr>` instruction.
 
     * If ``ty2`` is a pointer type, then if all bits of ``value`` are from the
-    same pointer and are correctly ordered (there were no pointer bit swaps),
-    the cast result is that pointer. If ``value`` is a mix of bits from
-    different pointers or a mix of pointer and non-pointer bits, the result is a
-    pointer without provenance. This pointer cannot be dereferenced, but can be
-    used in comparisons or :ref:`getelementptr <i_getelementptr>` instructions.
+      same pointer and are correctly ordered (there were no pointer bit swaps),
+      the cast result is that pointer. If ``value`` is a mix of bits from
+      different pointers or a mix of pointer and non-pointer bits, the result is
+      a pointer without provenance. This pointer cannot be dereferenced, but can
+      be used in comparisons or :ref:`getelementptr <i_getelementptr>`
+      instructions.
 
 * Otherwise, the cast is a *no-op*.
 

>From f0dd5350794eb2849e1ea0f4ef5a803e667fa976 Mon Sep 17 00:00:00 2001
From: Pedro Lobo <pedro.lobo at tecnico.ulisboa.pt>
Date: Sat, 14 Feb 2026 17:30:03 +0000
Subject: [PATCH 4/6] address review comments

---
 llvm/docs/LangRef.rst               | 22 ++++++++----
 llvm/include/llvm-c/Core.h          | 46 ++++++------------------
 llvm/include/llvm/IR/Constants.h    | 42 ----------------------
 llvm/include/llvm/IR/DataLayout.h   | 16 +++------
 llvm/include/llvm/IR/DerivedTypes.h |  5 +--
 llvm/include/llvm/IR/Type.h         | 11 ++++++
 llvm/lib/AsmParser/LLParser.cpp     |  2 +-
 llvm/lib/IR/Attributes.cpp          |  8 +++--
 llvm/lib/IR/Constants.cpp           | 54 ++---------------------------
 llvm/lib/IR/DataLayout.cpp          | 19 ----------
 llvm/lib/IR/Type.cpp                | 19 ++++++++++
 llvm/test/Assembler/byte.ll         |  3 +-
 12 files changed, 72 insertions(+), 175 deletions(-)

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 4699553faa6a5..9e40655606d27 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -13037,10 +13037,10 @@ The '``bitcast``' instruction takes a value to cast, which must be a
 non-aggregate first class value, and a type to cast it to, which must
 also be a non-aggregate :ref:`first class <t_firstclass>` type. The
 bit sizes of ``value`` and the destination type, ``ty2``, must be
-identical. If the source type is a pointer, the destination type must
-also be a pointer of the same size. This instruction supports bitwise
-conversion of vectors to integers and to vectors of other types (as
-long as they have the same size).
+identical. If the source type is a pointer, the destination type must also be a
+pointer or a byte (vector of bytes) of the same size. This instruction supports
+bitwise conversion of vectors to integers and to vectors of other types (as long
+as they have the same size).
 
 Semantics:
 """"""""""
@@ -13062,7 +13062,14 @@ element zero ends up in the most significant bits for big-endian.
 If ``value`` is of the :ref:`byte type <t_byte>`:
 
 * If ``value`` contains at least one ``poison`` bit, the cast result is
-  ``poison``.
+
+    * ``poison``, if ``ty2`` is a scalar type.
+
+    * a vector where only the lanes containing at least one ``poison`` bit are
+      ``poison``, if ``ty2`` is a vector type. The values of the remaining
+      non-``poison`` lanes are given by bitcasting the bits of ``value``
+      corresponding to each lane (according to the target's endianness) to the
+      lane element type.
 
 * If ``value`` is any mix of (non-``poison``) pointer and non-pointer bits:
 
@@ -13072,7 +13079,8 @@ If ``value`` is of the :ref:`byte type <t_byte>`:
 
     * If ``ty2`` is a pointer type, then if all bits of ``value`` are from the
       same pointer and are correctly ordered (there were no pointer bit swaps),
-      the cast result is that pointer. If ``value`` is a mix of bits from
+      the cast result is that pointer. If all the bits are from the same pointer
+      and these are not correctly ordered, or if ``value`` is a mix of bits from
       different pointers or a mix of pointer and non-pointer bits, the result is
       a pointer without provenance. This pointer cannot be dereferenced, but can
       be used in comparisons or :ref:`getelementptr <i_getelementptr>`
@@ -13099,6 +13107,8 @@ Example:
       %e = bitcast <2 x b32> %v to i64  ; reinterprets the raw bytes as an integer
       %f = bitcast <2 x b32> %v to ptr  ; reinterprets the raw bytes as a pointer
 
+      %g = bitcast <2 x b32> %v to <4 x i16> ; reinterprets the raw bytes as integers
+
 .. _i_addrspacecast:
 
 '``addrspacecast .. to``' Instruction
diff --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h
index 23f94408b86b5..cf64668fbbbdd 100644
--- a/llvm/include/llvm-c/Core.h
+++ b/llvm/include/llvm-c/Core.h
@@ -1380,24 +1380,9 @@ LLVM_C_ABI char *LLVMPrintTypeToString(LLVMTypeRef Val);
 /**
  * Obtain a byte type from a context with specified bit width.
  */
-LLVMTypeRef LLVMByte8TypeInContext(LLVMContextRef C);
-LLVMTypeRef LLVMByte16TypeInContext(LLVMContextRef C);
-LLVMTypeRef LLVMByte32TypeInContext(LLVMContextRef C);
-LLVMTypeRef LLVMByte64TypeInContext(LLVMContextRef C);
-LLVMTypeRef LLVMByte128TypeInContext(LLVMContextRef C);
-LLVMTypeRef LLVMByteTypeInContext(LLVMContextRef C, unsigned NumBits);
-
-/**
- * Obtain a byte type from the global context with a specified bit
- * width.
- */
-LLVMTypeRef LLVMByte8Type(void);
-LLVMTypeRef LLVMByte16Type(void);
-LLVMTypeRef LLVMByte32Type(void);
-LLVMTypeRef LLVMByte64Type(void);
-LLVMTypeRef LLVMByte128Type(void);
-LLVMTypeRef LLVMByteType(unsigned NumBits);
-unsigned LLVMGetByteTypeWidth(LLVMTypeRef ByteTy);
+LLVM_C_ABI LLVMTypeRef LLVMByteTypeInContext(LLVMContextRef C,
+                                             unsigned NumBits);
+LLVM_C_ABI unsigned LLVMGetByteTypeWidth(LLVMTypeRef ByteTy);
 
 /**
  * @defgroup LLVMCCoreTypeInt Integer Types
@@ -2437,36 +2422,25 @@ LLVM_C_ABI LLVMValueRef LLVMConstIntOfStringAndSize(LLVMTypeRef IntTy,
  * @param ByteTy Byte type to obtain value of.
  * @param N The value the returned instance should refer to.
  */
-LLVMValueRef LLVMConstByte(LLVMTypeRef ByteTy, unsigned long long N);
+LLVM_C_ABI LLVMValueRef LLVMConstByte(LLVMTypeRef ByteTy, unsigned long long N);
 
 /**
  * Obtain a constant value for a byte of arbitrary precision.
  *
  * @see llvm::ConstantByte::get()
  */
-LLVMValueRef LLVMConstByteOfArbitraryPrecision(LLVMTypeRef ByteTy,
-                                               unsigned NumWords,
-                                               const uint64_t Words[]);
-
-/**
- * Obtain a constant value for a byte parsed from a string.
- *
- * A similar API, LLVMConstByteOfStringAndSize is also available. If the
- * string's length is available, it is preferred to call that function
- * instead.
- *
- * @see llvm::ConstantByte::get()
- */
-LLVMValueRef LLVMConstByteOfString(LLVMTypeRef ByteTy, const char *Text,
-                                   uint8_t Radix);
+LLVM_C_ABI LLVMValueRef LLVMConstByteOfArbitraryPrecision(
+    LLVMTypeRef ByteTy, unsigned NumWords, const uint64_t Words[]);
 
 /**
  * Obtain a constant value for a byte parsed from a string with specified
  * length.
  * @see llvm::ConstantByte::get()
  */
-LLVMValueRef LLVMConstByteOfStringAndSize(LLVMTypeRef ByteTy, const char *Text,
-                                          unsigned SLen, uint8_t Radix);
+LLVM_C_ABI LLVMValueRef LLVMConstByteOfStringAndSize(LLVMTypeRef ByteTy,
+                                                     const char *Text,
+                                                     unsigned SLen,
+                                                     uint8_t Radix);
 
 /**
  * Obtain a constant value referring to a double floating point value.
diff --git a/llvm/include/llvm/IR/Constants.h b/llvm/include/llvm/IR/Constants.h
index e754ffb580359..ddb00b35c20ba 100644
--- a/llvm/include/llvm/IR/Constants.h
+++ b/llvm/include/llvm/IR/Constants.h
@@ -297,13 +297,6 @@ class ConstantByte final : public ConstantData {
 public:
   ConstantByte(const ConstantByte &) = delete;
 
-  LLVM_ABI static ConstantByte *getTrue(LLVMContext &Context);
-  LLVM_ABI static ConstantByte *getFalse(LLVMContext &Context);
-  LLVM_ABI static ConstantByte *getBool(LLVMContext &Context, bool V);
-  LLVM_ABI static Constant *getTrue(Type *Ty);
-  LLVM_ABI static Constant *getFalse(Type *Ty);
-  LLVM_ABI static Constant *getBool(Type *Ty, bool V);
-
   /// If Ty is a vector type, return a Constant with a splat of the given
   /// value. Otherwise return a ConstantByte for the given value.
   /// \param ImplicitTrunc Whether to allow implicit truncation of the value.
@@ -366,20 +359,6 @@ class ConstantByte final : public ConstantData {
   /// Return the sign extended value.
   inline int64_t getSExtValue() const { return Val.getSExtValue(); }
 
-  /// Return the constant as an llvm::MaybeAlign.
-  /// Note that this method can assert if the value does not fit in 64 bits or
-  /// is not a power of two.
-  inline MaybeAlign getMaybeAlignValue() const {
-    return MaybeAlign(getZExtValue());
-  }
-
-  /// Return the constant as an llvm::Align, interpreting `0` as `Align(1)`.
-  /// Note that this method can assert if the value does not fit in 64 bits or
-  /// is not a power of two.
-  inline Align getAlignValue() const {
-    return getMaybeAlignValue().valueOrOne();
-  }
-
   /// A helper method that can be used to determine if the constant contained
   /// within is equal to a constant.  This only works for very small values,
   /// because this is all that can be represented with all types.
@@ -392,18 +371,6 @@ class ConstantByte final : public ConstantData {
     return cast<ByteType>(Value::getType());
   }
 
-  /// This static method returns true if the type Ty is big enough to
-  /// represent the value V. This can be used to avoid having the get method
-  /// assert when V is larger than Ty can represent. Note that there are two
-  /// versions of this method, one for unsigned and one for signed integers.
-  /// Although ConstantByte canonicalizes everything to an unsigned integer,
-  /// the signed version avoids callers having to convert a signed quantity
-  /// to the appropriate unsigned type before calling the method.
-  /// @returns true if V is a valid value for type Ty
-  /// Determine if the value is in range for the given type.
-  LLVM_ABI static bool isValueValidForType(Type *Ty, uint64_t V);
-  LLVM_ABI static bool isValueValidForType(Type *Ty, int64_t V);
-
   bool isNegative() const { return Val.isNegative(); }
 
   /// This is just a convenience method to make client code smaller for a
@@ -454,15 +421,6 @@ class ConstantByte final : public ConstantData {
   /// Determine if the value is greater or equal to the given number.
   bool uge(uint64_t Num) const { return Val.uge(Num); }
 
-  /// getLimitedValue - If the value is smaller than the specified limit,
-  /// return it, otherwise return the limit value.  This causes the value
-  /// to saturate to the limit.
-  /// @returns the min of the value of the constant and the specified value
-  /// Get the constant's value with a saturation limit
-  uint64_t getLimitedValue(uint64_t Limit = ~0ULL) const {
-    return Val.getLimitedValue(Limit);
-  }
-
   /// Methods to support type inquiry through isa, cast, and dyn_cast.
   static bool classof(const Value *V) {
     return V->getValueID() == ConstantByteVal;
diff --git a/llvm/include/llvm/IR/DataLayout.h b/llvm/include/llvm/IR/DataLayout.h
index bc54269e5e762..4b63233025c3c 100644
--- a/llvm/include/llvm/IR/DataLayout.h
+++ b/llvm/include/llvm/IR/DataLayout.h
@@ -637,8 +637,8 @@ class DataLayout {
   /// This is always at least as good as the ABI alignment.
   LLVM_ABI Align getPrefTypeAlign(Type *Ty) const;
 
-  /// Returns a byte type with size at least as big as that of a
-  /// pointer in the given address space.
+  /// Returns a byte type with the same size of a pointer in the given address
+  /// space.
   LLVM_ABI ByteType *getBytePtrType(LLVMContext &C,
                                     unsigned AddressSpace = 0) const;
 
@@ -651,18 +651,10 @@ class DataLayout {
   /// big as that of a pointer of the given pointer (vector of pointer) type.
   LLVM_ABI Type *getIntPtrType(Type *) const;
 
-  /// Returns an integer (vector of integer) type with size at least as
-  /// big as that of a byte of the given byte (vector of byte) type.
-  LLVM_ABI Type *getIntByteType(Type *) const;
-
-  /// Returns a byte (vector of byte) type with size at least as big as that of
-  /// a pointer of the given pointer (vector of pointer) type.
+  /// Returns a byte (vector of byte) type with the same size of a pointer of
+  /// the given pointer (vector of pointer) type.
   LLVM_ABI Type *getBytePtrType(Type *) const;
 
-  /// Returns a byte (vector of byte) type with size at least as big as that of
-  /// an integer of the given integer (vector of integer) type.
-  LLVM_ABI Type *getByteIntType(Type *) const;
-
   /// Returns the smallest integer type with size at least as big as
   /// Width bits.
   LLVM_ABI Type *getSmallestLegalIntType(LLVMContext &C,
diff --git a/llvm/include/llvm/IR/DerivedTypes.h b/llvm/include/llvm/IR/DerivedTypes.h
index 876c4c8c871ce..23ef199362f5a 100644
--- a/llvm/include/llvm/IR/DerivedTypes.h
+++ b/llvm/include/llvm/IR/DerivedTypes.h
@@ -100,10 +100,7 @@ unsigned Type::getIntegerBitWidth() const {
   return cast<IntegerType>(this)->getBitWidth();
 }
 
-/// Class to represent byte types. Note that this class is also used to
-/// represent the built-in byte types: Byte8Ty, Byte16Ty, Byte32Ty and
-/// Byte64Ty.
-/// Byte representation type
+/// Class to represent byte types.
 class ByteType : public Type {
   friend class LLVMContextImpl;
 
diff --git a/llvm/include/llvm/IR/Type.h b/llvm/include/llvm/IR/Type.h
index 56417ee14796f..7a21d68e94e0a 100644
--- a/llvm/include/llvm/IR/Type.h
+++ b/llvm/include/llvm/IR/Type.h
@@ -501,6 +501,17 @@ class Type {
   LLVM_ABI static Type *getFloatingPointTy(LLVMContext &C,
                                            const fltSemantics &S);
 
+  //===--------------------------------------------------------------------===//
+  // Convenience methods for getting byte/integer types.
+  //
+  /// Returns an integer (vector of integer) type with the same size of a byte
+  /// of the given byte (vector of byte) type.
+  LLVM_ABI static Type *getIntByteType(Type *);
+
+  /// Returns a byte (vector of byte) type with the same size of an integer of
+  /// the given integer (vector of integer) type.
+  LLVM_ABI static Type *getByteIntType(Type *);
+
   //===--------------------------------------------------------------------===//
   // Convenience methods for getting pointer types.
   //
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index 1965efd37b968..3f9c389f3bc2a 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -4096,7 +4096,7 @@ bool LLParser::parseValID(ValID &ID, PerFunctionState *PFS, Type *ExpectedTy) {
   }
   case lltok::kw_c: { // c "foo"
     Lex.Lex();
-    ArrayType *ATy = static_cast<ArrayType *>(ExpectedTy);
+    ArrayType *ATy = cast<ArrayType>(ExpectedTy);
     ID.ConstantVal = ConstantDataArray::getString(
         Context, Lex.getStrVal(), false, ATy->getElementType()->isByteTy());
     if (parseToken(lltok::StringConstant, "expected string"))
diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp
index 265d7eed21a6c..6045a80d762c7 100644
--- a/llvm/lib/IR/Attributes.cpp
+++ b/llvm/lib/IR/Attributes.cpp
@@ -2451,10 +2451,14 @@ AttributeMask AttributeFuncs::typeIncompatible(Type *Ty, AttributeSet AS,
                                                AttributeSafetyKind ASK) {
   AttributeMask Incompatible;
 
-  if (!Ty->isIntegerTy() && !Ty->isByteTy()) {
-    // Attributes that only apply to integers and bytes.
+  if (!Ty->isIntegerTy()) {
+    // Attributes that only apply to integers.
     if (ASK & ASK_SAFE_TO_DROP)
       Incompatible.addAttribute(Attribute::AllocAlign);
+  }
+
+  if (!Ty->isIntegerTy() && !Ty->isByteTy()) {
+    // Attributes that only apply to integers and bytes.
     if (ASK & ASK_UNSAFE_TO_DROP)
       Incompatible.addAttribute(Attribute::SExt).addAttribute(Attribute::ZExt);
   }
diff --git a/llvm/lib/IR/Constants.cpp b/llvm/lib/IR/Constants.cpp
index 256b8cadfc210..80d5664702de4 100644
--- a/llvm/lib/IR/Constants.cpp
+++ b/llvm/lib/IR/Constants.cpp
@@ -39,18 +39,12 @@ using namespace PatternMatch;
 static cl::opt<bool> UseConstantIntForFixedLengthSplat(
     "use-constant-int-for-fixed-length-splat", cl::init(false), cl::Hidden,
     cl::desc("Use ConstantInt's native fixed-length vector splat support."));
-static cl::opt<bool> UseConstantByteForFixedLengthSplat(
-    "use-constant-byte-for-fixed-length-splat", cl::init(false), cl::Hidden,
-    cl::desc("Use ConstantByte's native fixed-length vector splat support."));
 static cl::opt<bool> UseConstantFPForFixedLengthSplat(
     "use-constant-fp-for-fixed-length-splat", cl::init(false), cl::Hidden,
     cl::desc("Use ConstantFP's native fixed-length vector splat support."));
 static cl::opt<bool> UseConstantIntForScalableSplat(
     "use-constant-int-for-scalable-splat", cl::init(false), cl::Hidden,
     cl::desc("Use ConstantInt's native scalable vector splat support."));
-static cl::opt<bool> UseConstantByteForScalableSplat(
-    "use-constant-byte-for-scalable-splat", cl::init(false), cl::Hidden,
-    cl::desc("Use ConstantByte's native scalable vector splat support."));
 static cl::opt<bool> UseConstantFPForScalableSplat(
     "use-constant-fp-for-scalable-splat", cl::init(false), cl::Hidden,
     cl::desc("Use ConstantFP's native scalable vector splat support."));
@@ -1052,44 +1046,6 @@ ConstantByte::ConstantByte(Type *Ty, const APInt &V)
          "Invalid constant for type");
 }
 
-ConstantByte *ConstantByte::getTrue(LLVMContext &Context) {
-  LLVMContextImpl *pImpl = Context.pImpl;
-  if (!pImpl->TheTrueByteVal)
-    pImpl->TheTrueByteVal = ConstantByte::get(Type::getByte1Ty(Context), 1);
-  return pImpl->TheTrueByteVal;
-}
-
-ConstantByte *ConstantByte::getFalse(LLVMContext &Context) {
-  LLVMContextImpl *pImpl = Context.pImpl;
-  if (!pImpl->TheFalseByteVal)
-    pImpl->TheFalseByteVal = ConstantByte::get(Type::getByte1Ty(Context), 0);
-  return pImpl->TheFalseByteVal;
-}
-
-ConstantByte *ConstantByte::getBool(LLVMContext &Context, bool V) {
-  return V ? getTrue(Context) : getFalse(Context);
-}
-
-Constant *ConstantByte::getTrue(Type *Ty) {
-  assert(Ty->isByteOrByteVectorTy(1) && "Type not i1 or vector of i1.");
-  ConstantByte *TrueC = ConstantByte::getTrue(Ty->getContext());
-  if (auto *VTy = dyn_cast<VectorType>(Ty))
-    return ConstantVector::getSplat(VTy->getElementCount(), TrueC);
-  return TrueC;
-}
-
-Constant *ConstantByte::getFalse(Type *Ty) {
-  assert(Ty->isByteOrByteVectorTy(1) && "Type not i1 or vector of i1.");
-  ConstantByte *FalseC = ConstantByte::getFalse(Ty->getContext());
-  if (auto *VTy = dyn_cast<VectorType>(Ty))
-    return ConstantVector::getSplat(VTy->getElementCount(), FalseC);
-  return FalseC;
-}
-
-Constant *ConstantByte::getBool(Type *Ty, bool V) {
-  return V ? getTrue(Ty) : getFalse(Ty);
-}
-
 // Get a ConstantByte from an APInt.
 ConstantByte *ConstantByte::get(LLVMContext &Context, const APInt &V) {
   // get an existing value or the insertion position
@@ -1650,7 +1606,7 @@ Constant *ConstantVector::getImpl(ArrayRef<Constant*> V) {
   bool isPoison = isa<PoisonValue>(C);
   bool isSplatFP = UseConstantFPForFixedLengthSplat && isa<ConstantFP>(C);
   bool isSplatInt = UseConstantIntForFixedLengthSplat && isa<ConstantInt>(C);
-  bool isSplatByte = UseConstantByteForFixedLengthSplat && isa<ConstantByte>(C);
+  bool isSplatByte = isa<ConstantByte>(C);
 
   if (isZero || isUndef || isSplatFP || isSplatInt || isSplatByte) {
     for (unsigned i = 1, e = V.size(); i != e; ++i)
@@ -1694,7 +1650,7 @@ Constant *ConstantVector::getSplat(ElementCount EC, Constant *V) {
       if (UseConstantIntForFixedLengthSplat && isa<ConstantInt>(V))
         return ConstantInt::get(V->getContext(), EC,
                                 cast<ConstantInt>(V)->getValue());
-      if (UseConstantByteForFixedLengthSplat && isa<ConstantByte>(V))
+      if (isa<ConstantByte>(V))
         return ConstantByte::get(V->getContext(), EC,
                                  cast<ConstantByte>(V)->getValue());
       if (UseConstantFPForFixedLengthSplat && isa<ConstantFP>(V))
@@ -1717,7 +1673,7 @@ Constant *ConstantVector::getSplat(ElementCount EC, Constant *V) {
     if (UseConstantIntForScalableSplat && isa<ConstantInt>(V))
       return ConstantInt::get(V->getContext(), EC,
                               cast<ConstantInt>(V)->getValue());
-    if (UseConstantByteForScalableSplat && isa<ConstantByte>(V))
+    if (isa<ConstantByte>(V))
       return ConstantByte::get(V->getContext(), EC,
                                cast<ConstantByte>(V)->getValue());
     if (UseConstantFPForScalableSplat && isa<ConstantFP>(V))
@@ -1835,10 +1791,6 @@ bool ConstantInt::isValueValidForType(Type *Ty, int64_t Val) {
   return isIntN(NumBits, Val);
 }
 
-bool ConstantByte::isValueValidForType(Type *Ty, uint64_t Val) {
-  return isUIntN(Ty->getByteBitWidth(), Val);
-}
-
 bool ConstantFP::isValueValidForType(Type *Ty, const APFloat& Val) {
   // convert modifies in place, so make a copy.
   APFloat Val2 = APFloat(Val);
diff --git a/llvm/lib/IR/DataLayout.cpp b/llvm/lib/IR/DataLayout.cpp
index f7361f337af0d..c15eaca3b868c 100644
--- a/llvm/lib/IR/DataLayout.cpp
+++ b/llvm/lib/IR/DataLayout.cpp
@@ -986,15 +986,6 @@ Type *DataLayout::getIntPtrType(Type *Ty) const {
   return IntTy;
 }
 
-Type *DataLayout::getIntByteType(Type *Ty) const {
-  assert(Ty->isByteOrByteVectorTy() && "Expected a byte or byte vector type.");
-  unsigned NumBits = Ty->getScalarSizeInBits();
-  IntegerType *IntTy = IntegerType::get(Ty->getContext(), NumBits);
-  if (VectorType *VecTy = dyn_cast<VectorType>(Ty))
-    return VectorType::get(IntTy, VecTy);
-  return IntTy;
-}
-
 ByteType *DataLayout::getBytePtrType(LLVMContext &C,
                                      unsigned AddressSpace) const {
   return ByteType::get(C, getPointerSizeInBits(AddressSpace));
@@ -1010,16 +1001,6 @@ Type *DataLayout::getBytePtrType(Type *Ty) const {
   return ByteTy;
 }
 
-Type *DataLayout::getByteIntType(Type *Ty) const {
-  assert(!Ty->isPtrOrPtrVectorTy() &&
-         "Expected a non-pointer or non-pointer vector type.");
-  unsigned NumBits = Ty->getScalarSizeInBits();
-  ByteType *ByteTy = ByteType::get(Ty->getContext(), NumBits);
-  if (VectorType *VecTy = dyn_cast<VectorType>(Ty))
-    return VectorType::get(ByteTy, VecTy);
-  return ByteTy;
-}
-
 Type *DataLayout::getSmallestLegalIntType(LLVMContext &C, unsigned Width) const {
   for (unsigned LegalIntWidth : LegalIntWidths)
     if (Width <= LegalIntWidth)
diff --git a/llvm/lib/IR/Type.cpp b/llvm/lib/IR/Type.cpp
index 585c9c45c3524..5c4fe00581d0d 100644
--- a/llvm/lib/IR/Type.cpp
+++ b/llvm/lib/IR/Type.cpp
@@ -318,6 +318,25 @@ IntegerType *Type::getIntNTy(LLVMContext &C, unsigned N) {
   return IntegerType::get(C, N);
 }
 
+Type *Type::getIntByteType(Type *Ty) {
+  assert(Ty->isByteOrByteVectorTy() && "Expected a byte or byte vector type.");
+  unsigned NumBits = Ty->getScalarSizeInBits();
+  IntegerType *IntTy = IntegerType::get(Ty->getContext(), NumBits);
+  if (VectorType *VecTy = dyn_cast<VectorType>(Ty))
+    return VectorType::get(IntTy, VecTy);
+  return IntTy;
+}
+
+Type *Type::getByteIntType(Type *Ty) {
+  assert(!Ty->isPtrOrPtrVectorTy() &&
+         "Expected a non-pointer or non-pointer vector type.");
+  unsigned NumBits = Ty->getScalarSizeInBits();
+  ByteType *ByteTy = ByteType::get(Ty->getContext(), NumBits);
+  if (VectorType *VecTy = dyn_cast<VectorType>(Ty))
+    return VectorType::get(ByteTy, VecTy);
+  return ByteTy;
+}
+
 Type *Type::getWasm_ExternrefTy(LLVMContext &C) {
   // opaque pointer in addrspace(10)
   return PointerType::get(C, 10);
diff --git a/llvm/test/Assembler/byte.ll b/llvm/test/Assembler/byte.ll
index 2a896337a3f02..1a02d0fab5df3 100644
--- a/llvm/test/Assembler/byte.ll
+++ b/llvm/test/Assembler/byte.ll
@@ -1,5 +1,4 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
-; RUN: opt < %s -S | FileCheck %s
+; RUN: llvm-as < %s | llvm-dis | FileCheck %s
 
 ; CHECK: common global [32 x b8] zeroinitializer
 ; CHECK: constant [1 x b8] zeroinitializer

>From 076b1685166fc1b80fc7825d654dd9cbae878591 Mon Sep 17 00:00:00 2001
From: Pedro Lobo <pedro.lobo at tecnico.ulisboa.pt>
Date: Sat, 21 Feb 2026 12:02:23 +0000
Subject: [PATCH 5/6] address review comments

---
 llvm/docs/LangRef.rst                         |  6 +-
 llvm/include/llvm-c/Core.h                    |  2 +-
 llvm/include/llvm/IR/Constants.h              | 13 ---
 llvm/include/llvm/IR/DerivedTypes.h           |  9 ---
 llvm/include/llvm/IR/Type.h                   |  4 +-
 llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp    | 81 ++++---------------
 llvm/lib/IR/Core.cpp                          | 32 +-------
 llvm/lib/IR/Intrinsics.cpp                    |  2 +-
 llvm/lib/IR/Type.cpp                          | 14 ++--
 .../DirectX/DXILWriter/DXILBitcodeWriter.cpp  | 19 -----
 llvm/test/Assembler/byte-invalid-cast-1.ll    |  7 --
 llvm/test/Assembler/byte-invalid-cast-2.ll    |  7 --
 llvm/test/Assembler/byte-invalid-cast-3.ll    |  7 --
 llvm/test/Assembler/byte-invalid-cast-4.ll    |  7 --
 llvm/test/Assembler/byte-invalid-cast-5.ll    |  7 --
 llvm/test/Assembler/byte-invalid-cast-6.ll    |  7 --
 llvm/test/Assembler/byte-invalid-cast-7.ll    |  7 --
 llvm/test/Assembler/byte-invalid-cast-8.ll    |  7 --
 llvm/test/Assembler/byte-invalid-cmp.ll       |  7 --
 llvm/test/Assembler/byte-invalid.ll           | 73 +++++++++++++++++
 20 files changed, 106 insertions(+), 212 deletions(-)
 delete mode 100644 llvm/test/Assembler/byte-invalid-cast-1.ll
 delete mode 100644 llvm/test/Assembler/byte-invalid-cast-2.ll
 delete mode 100644 llvm/test/Assembler/byte-invalid-cast-3.ll
 delete mode 100644 llvm/test/Assembler/byte-invalid-cast-4.ll
 delete mode 100644 llvm/test/Assembler/byte-invalid-cast-5.ll
 delete mode 100644 llvm/test/Assembler/byte-invalid-cast-6.ll
 delete mode 100644 llvm/test/Assembler/byte-invalid-cast-7.ll
 delete mode 100644 llvm/test/Assembler/byte-invalid-cast-8.ll
 delete mode 100644 llvm/test/Assembler/byte-invalid-cmp.ll
 create mode 100644 llvm/test/Assembler/byte-invalid.ll

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 9e40655606d27..0fa8c76aa2966 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -4441,8 +4441,8 @@ Byte Type
 
 The byte type represents raw memory data in SSA registers. It should be used
 when it cannot be determined whether a value holds a pointer or another type at
-run time, or if the value contains uninitialized data. Frontends are expected to
-use a byte type when:
+run time, or if the value contains uninitialized or poison data. Frontends are
+expected to use a byte type when:
 
 #. Lowering memory operations like `memcpy` and `memmove` to load/store pairs
    without knowing the underlying type being copied.
@@ -11781,6 +11781,8 @@ If the value being loaded is of aggregate type, the bytes that correspond to
 padding may be accessed but are ignored, because it is impossible to observe
 padding from the loaded aggregate value.
 If ``<pointer>`` is not a well-defined value, the behavior is undefined.
+The behavior of loading a value of a type that differs from the type used to
+store it is described in the :ref:`bitcast <i_bitcast>` section.
 
 Examples:
 """""""""
diff --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h
index cf64668fbbbdd..08a92f1dff2d6 100644
--- a/llvm/include/llvm-c/Core.h
+++ b/llvm/include/llvm-c/Core.h
@@ -2439,7 +2439,7 @@ LLVM_C_ABI LLVMValueRef LLVMConstByteOfArbitraryPrecision(
  */
 LLVM_C_ABI LLVMValueRef LLVMConstByteOfStringAndSize(LLVMTypeRef ByteTy,
                                                      const char *Text,
-                                                     unsigned SLen,
+                                                     size_t SLen,
                                                      uint8_t Radix);
 
 /**
diff --git a/llvm/include/llvm/IR/Constants.h b/llvm/include/llvm/IR/Constants.h
index ddb00b35c20ba..da5bf684557d7 100644
--- a/llvm/include/llvm/IR/Constants.h
+++ b/llvm/include/llvm/IR/Constants.h
@@ -359,12 +359,6 @@ class ConstantByte final : public ConstantData {
   /// Return the sign extended value.
   inline int64_t getSExtValue() const { return Val.getSExtValue(); }
 
-  /// A helper method that can be used to determine if the constant contained
-  /// within is equal to a constant.  This only works for very small values,
-  /// because this is all that can be represented with all types.
-  /// Determine if this constant's value is same as an unsigned char.
-  bool equalsByte(uint64_t V) const { return Val == V; }
-
   /// Variant of the getType() method to always return a ByteType, which
   /// reduces the amount of casting needed in parts of the compiler.
   inline ByteType *getByteType() const {
@@ -414,13 +408,6 @@ class ConstantByte final : public ConstantData {
       return Val.isMinValue();
   }
 
-  /// This function will return true iff this constant represents a value with
-  /// active bits bigger than 64 bits or a value greater than the given uint64_t
-  /// value.
-  /// @returns true iff this constant is greater or equal to the given number.
-  /// Determine if the value is greater or equal to the given number.
-  bool uge(uint64_t Num) const { return Val.uge(Num); }
-
   /// Methods to support type inquiry through isa, cast, and dyn_cast.
   static bool classof(const Value *V) {
     return V->getValueID() == ConstantByteVal;
diff --git a/llvm/include/llvm/IR/DerivedTypes.h b/llvm/include/llvm/IR/DerivedTypes.h
index 23ef199362f5a..c272f091e31a4 100644
--- a/llvm/include/llvm/IR/DerivedTypes.h
+++ b/llvm/include/llvm/IR/DerivedTypes.h
@@ -128,18 +128,9 @@ class ByteType : public Type {
   /// Get or create a ByteType instance.
   LLVM_ABI static ByteType *get(LLVMContext &C, unsigned NumBits);
 
-  /// Returns type twice as wide the input type.
-  ByteType *getExtendedType() const {
-    return Type::getByteNTy(getContext(), 2 * getScalarSizeInBits());
-  }
-
   /// Get the number of bits in this ByteType
   unsigned getBitWidth() const { return getSubclassData(); }
 
-  /// Return a bitmask with ones set for all of the bits. This is 0xFF for i8,
-  /// 0xFFFF for i16, etc.
-  uint64_t getBitMask() const { return ~uint64_t(0UL) >> (64 - getBitWidth()); }
-
   /// For example, this is 0xFF for an 8 bit byte, 0xFFFF for b16, etc.
   /// @returns a bit mask with ones set for all the bits of this type.
   /// Get a bit mask for this type.
diff --git a/llvm/include/llvm/IR/Type.h b/llvm/include/llvm/IR/Type.h
index 7a21d68e94e0a..4217d797cdf28 100644
--- a/llvm/include/llvm/IR/Type.h
+++ b/llvm/include/llvm/IR/Type.h
@@ -506,11 +506,11 @@ class Type {
   //
   /// Returns an integer (vector of integer) type with the same size of a byte
   /// of the given byte (vector of byte) type.
-  LLVM_ABI static Type *getIntByteType(Type *);
+  LLVM_ABI static Type *getIntFromByteType(Type *);
 
   /// Returns a byte (vector of byte) type with the same size of an integer of
   /// the given integer (vector of integer) type.
-  LLVM_ABI static Type *getByteIntType(Type *);
+  LLVM_ABI static Type *getByteFromIntType(Type *);
 
   //===--------------------------------------------------------------------===//
   // Convenience methods for getting pointer types.
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 4be7c59ce67f4..f9e2319543b22 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -4131,14 +4131,15 @@ static void emitGlobalConstantFP(const ConstantFP *CFP, AsmPrinter &AP) {
   emitGlobalConstantFP(CFP->getValueAPF(), CFP->getType(), AP);
 }
 
-static void emitGlobalConstantLargeByte(const ConstantByte *CB,
-                                        AsmPrinter &AP) {
+static void emitGlobalConstantLargeAPInt(const APInt &Val,
+                                         uint64_t TypeStoreSize,
+                                         AsmPrinter &AP) {
   const DataLayout &DL = AP.getDataLayout();
-  unsigned BitWidth = CB->getBitWidth();
+  unsigned BitWidth = Val.getBitWidth();
 
   // Copy the value as we may massage the layout for constants whose bit width
   // is not a multiple of 64-bits.
-  APInt Realigned(CB->getValue());
+  APInt Realigned(Val);
   uint64_t ExtraBits = 0;
   unsigned ExtraBitsSize = BitWidth & 63;
 
@@ -4168,21 +4169,20 @@ static void emitGlobalConstantLargeByte(const ConstantByte *CB,
       ExtraBits = Realigned.getRawData()[BitWidth / 64];
   }
 
-  // We don't expect assemblers to support byte data directives
+  // We don't expect assemblers to support data directives
   // for more than 64 bits, so we emit the data in at most 64-bit
   // quantities at a time.
   const uint64_t *RawData = Realigned.getRawData();
   for (unsigned i = 0, e = BitWidth / 64; i != e; ++i) {
-    uint64_t Val = DL.isBigEndian() ? RawData[e - i - 1] : RawData[i];
-    AP.OutStreamer->emitIntValue(Val, 8);
+    uint64_t ChunkVal = DL.isBigEndian() ? RawData[e - i - 1] : RawData[i];
+    AP.OutStreamer->emitIntValue(ChunkVal, 8);
   }
 
   if (ExtraBitsSize) {
     // Emit the extra bits after the 64-bits chunks.
 
     // Emit a directive that fills the expected size.
-    uint64_t Size = AP.getDataLayout().getTypeStoreSize(CB->getType());
-    Size -= (BitWidth / 64) * 8;
+    uint64_t Size = TypeStoreSize - (BitWidth / 64) * 8;
     assert(Size && Size * 8 >= ExtraBitsSize &&
            (ExtraBits & (((uint64_t)-1) >> (64 - ExtraBitsSize))) ==
                ExtraBits &&
@@ -4191,62 +4191,15 @@ static void emitGlobalConstantLargeByte(const ConstantByte *CB,
   }
 }
 
-static void emitGlobalConstantLargeInt(const ConstantInt *CI, AsmPrinter &AP) {
-  const DataLayout &DL = AP.getDataLayout();
-  unsigned BitWidth = CI->getBitWidth();
-
-  // Copy the value as we may massage the layout for constants whose bit width
-  // is not a multiple of 64-bits.
-  APInt Realigned(CI->getValue());
-  uint64_t ExtraBits = 0;
-  unsigned ExtraBitsSize = BitWidth & 63;
-
-  if (ExtraBitsSize) {
-    // The bit width of the data is not a multiple of 64-bits.
-    // The extra bits are expected to be at the end of the chunk of the memory.
-    // Little endian:
-    // * Nothing to be done, just record the extra bits to emit.
-    // Big endian:
-    // * Record the extra bits to emit.
-    // * Realign the raw data to emit the chunks of 64-bits.
-    if (DL.isBigEndian()) {
-      // Basically the structure of the raw data is a chunk of 64-bits cells:
-      //    0        1         BitWidth / 64
-      // [chunk1][chunk2] ... [chunkN].
-      // The most significant chunk is chunkN and it should be emitted first.
-      // However, due to the alignment issue chunkN contains useless bits.
-      // Realign the chunks so that they contain only useful information:
-      // ExtraBits     0       1       (BitWidth / 64) - 1
-      //       chu[nk1 chu][nk2 chu] ... [nkN-1 chunkN]
-      ExtraBitsSize = alignTo(ExtraBitsSize, 8);
-      ExtraBits = Realigned.getRawData()[0] &
-        (((uint64_t)-1) >> (64 - ExtraBitsSize));
-      if (BitWidth >= 64)
-        Realigned.lshrInPlace(ExtraBitsSize);
-    } else
-      ExtraBits = Realigned.getRawData()[BitWidth / 64];
-  }
-
-  // We don't expect assemblers to support integer data directives
-  // for more than 64 bits, so we emit the data in at most 64-bit
-  // quantities at a time.
-  const uint64_t *RawData = Realigned.getRawData();
-  for (unsigned i = 0, e = BitWidth / 64; i != e; ++i) {
-    uint64_t Val = DL.isBigEndian() ? RawData[e - i - 1] : RawData[i];
-    AP.OutStreamer->emitIntValue(Val, 8);
-  }
-
-  if (ExtraBitsSize) {
-    // Emit the extra bits after the 64-bits chunks.
+static void emitGlobalConstantLargeByte(const ConstantByte *CB,
+                                        AsmPrinter &AP) {
+  emitGlobalConstantLargeAPInt(
+      CB->getValue(), AP.getDataLayout().getTypeStoreSize(CB->getType()), AP);
+}
 
-    // Emit a directive that fills the expected size.
-    uint64_t Size = AP.getDataLayout().getTypeStoreSize(CI->getType());
-    Size -= (BitWidth / 64) * 8;
-    assert(Size && Size * 8 >= ExtraBitsSize &&
-           (ExtraBits & (((uint64_t)-1) >> (64 - ExtraBitsSize)))
-           == ExtraBits && "Directive too small for extra bits.");
-    AP.OutStreamer->emitIntValue(ExtraBits, Size);
-  }
+static void emitGlobalConstantLargeInt(const ConstantInt *CI, AsmPrinter &AP) {
+  emitGlobalConstantLargeAPInt(
+      CI->getValue(), AP.getDataLayout().getTypeStoreSize(CI->getType()), AP);
 }
 
 /// Transform a not absolute MCExpr containing a reference to a GOT
diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp
index 0fd832ac5c99e..3a63176ca49df 100644
--- a/llvm/lib/IR/Core.cpp
+++ b/llvm/lib/IR/Core.cpp
@@ -660,40 +660,10 @@ char *LLVMPrintTypeToString(LLVMTypeRef Ty) {
 
 /*--.. Operations on byte types ............................................--*/
 
-LLVMTypeRef LLVMByte8TypeInContext(LLVMContextRef C) {
-  return (LLVMTypeRef)Type::getByte8Ty(*unwrap(C));
-}
-LLVMTypeRef LLVMByte16TypeInContext(LLVMContextRef C) {
-  return (LLVMTypeRef)Type::getByte16Ty(*unwrap(C));
-}
-LLVMTypeRef LLVMByte32TypeInContext(LLVMContextRef C) {
-  return (LLVMTypeRef)Type::getByte32Ty(*unwrap(C));
-}
-LLVMTypeRef LLVMByte64TypeInContext(LLVMContextRef C) {
-  return (LLVMTypeRef)Type::getByte64Ty(*unwrap(C));
-}
-LLVMTypeRef LLVMByte128TypeInContext(LLVMContextRef C) {
-  return (LLVMTypeRef)Type::getByte128Ty(*unwrap(C));
-}
 LLVMTypeRef LLVMByteTypeInContext(LLVMContextRef C, unsigned NumBits) {
   return wrap(ByteType::get(*unwrap(C), NumBits));
 }
 
-LLVMTypeRef LLVMByte8Type(void) {
-  return LLVMByte8TypeInContext(getGlobalContextForCAPI());
-}
-LLVMTypeRef LLVMByte16Type(void) {
-  return LLVMByte16TypeInContext(getGlobalContextForCAPI());
-}
-LLVMTypeRef LLVMByte32Type(void) {
-  return LLVMByte32TypeInContext(getGlobalContextForCAPI());
-}
-LLVMTypeRef LLVMByte64Type(void) {
-  return LLVMByte64TypeInContext(getGlobalContextForCAPI());
-}
-LLVMTypeRef LLVMByte128Type(void) {
-  return LLVMByte128TypeInContext(getGlobalContextForCAPI());
-}
 LLVMTypeRef LLVMByteType(unsigned NumBits) {
   return LLVMByteTypeInContext(getGlobalContextForCAPI(), NumBits);
 }
@@ -1621,7 +1591,7 @@ LLVMValueRef LLVMConstByteOfString(LLVMTypeRef ByteTy, const char Str[],
 }
 
 LLVMValueRef LLVMConstByteOfStringAndSize(LLVMTypeRef ByteTy, const char Str[],
-                                          unsigned SLen, uint8_t Radix) {
+                                          size_t SLen, uint8_t Radix) {
   return wrap(
       ConstantByte::get(unwrap<ByteType>(ByteTy), StringRef(Str, SLen), Radix));
 }
diff --git a/llvm/lib/IR/Intrinsics.cpp b/llvm/lib/IR/Intrinsics.cpp
index 49a0816eeb345..94e251d228d54 100644
--- a/llvm/lib/IR/Intrinsics.cpp
+++ b/llvm/lib/IR/Intrinsics.cpp
@@ -148,7 +148,7 @@ static std::string getMangledTypeStr(Type *Ty, bool &HasUnnamedType) {
       Result += "i" + utostr(cast<IntegerType>(Ty)->getBitWidth());
       break;
     case Type::ByteTyID:
-      Result += "b" + utostr(cast<IntegerType>(Ty)->getBitWidth());
+      Result += "b" + utostr(cast<ByteType>(Ty)->getBitWidth());
       break;
     }
   }
diff --git a/llvm/lib/IR/Type.cpp b/llvm/lib/IR/Type.cpp
index 5c4fe00581d0d..498e78d4b0cc8 100644
--- a/llvm/lib/IR/Type.cpp
+++ b/llvm/lib/IR/Type.cpp
@@ -318,7 +318,7 @@ IntegerType *Type::getIntNTy(LLVMContext &C, unsigned N) {
   return IntegerType::get(C, N);
 }
 
-Type *Type::getIntByteType(Type *Ty) {
+Type *Type::getIntFromByteType(Type *Ty) {
   assert(Ty->isByteOrByteVectorTy() && "Expected a byte or byte vector type.");
   unsigned NumBits = Ty->getScalarSizeInBits();
   IntegerType *IntTy = IntegerType::get(Ty->getContext(), NumBits);
@@ -327,7 +327,7 @@ Type *Type::getIntByteType(Type *Ty) {
   return IntTy;
 }
 
-Type *Type::getByteIntType(Type *Ty) {
+Type *Type::getByteFromIntType(Type *Ty) {
   assert(!Ty->isPtrOrPtrVectorTy() &&
          "Expected a non-pointer or non-pointer vector type.");
   unsigned NumBits = Ty->getScalarSizeInBits();
@@ -388,15 +388,15 @@ ByteType *ByteType::get(LLVMContext &C, unsigned NumBits) {
   // Check for the built-in byte types
   switch (NumBits) {
   case 8:
-    return cast<ByteType>(Type::getByte8Ty(C));
+    return Type::getByte8Ty(C);
   case 16:
-    return cast<ByteType>(Type::getByte16Ty(C));
+    return Type::getByte16Ty(C);
   case 32:
-    return cast<ByteType>(Type::getByte32Ty(C));
+    return Type::getByte32Ty(C);
   case 64:
-    return cast<ByteType>(Type::getByte64Ty(C));
+    return Type::getByte64Ty(C);
   case 128:
-    return cast<ByteType>(Type::getByte128Ty(C));
+    return Type::getByte128Ty(C);
   default:
     break;
   }
diff --git a/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp b/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp
index 7feaf5a7bb68e..48a9085820471 100644
--- a/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp
+++ b/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp
@@ -77,7 +77,6 @@ class DXILBitcodeWriter {
     // CONSTANTS_BLOCK abbrev id's.
     CONSTANTS_SETTYPE_ABBREV = bitc::FIRST_APPLICATION_ABBREV,
     CONSTANTS_INTEGER_ABBREV,
-    CONSTANTS_BYTE_ABBREV,
     CONSTANTS_CE_CAST_Abbrev,
     CONSTANTS_NULL_Abbrev,
 
@@ -2015,24 +2014,6 @@ void DXILBitcodeWriter::writeConstants(unsigned FirstVal, unsigned LastVal,
         }
         Code = bitc::CST_CODE_WIDE_INTEGER;
       }
-    } else if (const ConstantByte *BV = dyn_cast<ConstantByte>(C)) {
-      if (BV->getBitWidth() <= 64) {
-        uint64_t V = BV->getZExtValue();
-        emitSignedInt64(Record, V);
-        Code = bitc::CST_CODE_BYTE;
-        AbbrevToUse = CONSTANTS_BYTE_ABBREV;
-      } else { // Wide bytes, > 64 bits in size.
-        // We have an arbitrary precision byte value to write whose
-        // bit width is > 64. However, in canonical unsigned integer
-        // format it is likely that the high bits are going to be zero.
-        // So, we only write the number of active words.
-        unsigned NWords = BV->getValue().getActiveWords();
-        const uint64_t *RawWords = BV->getValue().getRawData();
-        for (unsigned i = 0; i != NWords; ++i) {
-          emitSignedInt64(Record, RawWords[i]);
-        }
-        Code = bitc::CST_CODE_WIDE_BYTE;
-      }
     } else if (const ConstantFP *CFP = dyn_cast<ConstantFP>(C)) {
       Code = bitc::CST_CODE_FLOAT;
       Type *Ty = CFP->getType();
diff --git a/llvm/test/Assembler/byte-invalid-cast-1.ll b/llvm/test/Assembler/byte-invalid-cast-1.ll
deleted file mode 100644
index 793a8c25ea3f1..0000000000000
--- a/llvm/test/Assembler/byte-invalid-cast-1.ll
+++ /dev/null
@@ -1,7 +0,0 @@
-; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s
-
-; CHECK: invalid cast opcode for cast from 'b8' to 'i32'
-define void @invalid_zext(b8 %b) {
-  %t = zext b8 %b to i32
-  ret void
-}
diff --git a/llvm/test/Assembler/byte-invalid-cast-2.ll b/llvm/test/Assembler/byte-invalid-cast-2.ll
deleted file mode 100644
index fa2cee7f11005..0000000000000
--- a/llvm/test/Assembler/byte-invalid-cast-2.ll
+++ /dev/null
@@ -1,7 +0,0 @@
-; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s
-
-; CHECK: invalid cast opcode for cast from 'b8' to 'i32'
-define void @invalid_sext(b8 %b) {
-  %t = sext b8 %b to i32
-  ret void
-}
diff --git a/llvm/test/Assembler/byte-invalid-cast-3.ll b/llvm/test/Assembler/byte-invalid-cast-3.ll
deleted file mode 100644
index ec78843d70862..0000000000000
--- a/llvm/test/Assembler/byte-invalid-cast-3.ll
+++ /dev/null
@@ -1,7 +0,0 @@
-; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s
-
-; CHECK: invalid cast opcode for cast from 'b32' to 'b8'
-define void @invalid_trunc(b32 %b) {
-  %t = trunc b32 %b to b8
-  ret void
-}
diff --git a/llvm/test/Assembler/byte-invalid-cast-4.ll b/llvm/test/Assembler/byte-invalid-cast-4.ll
deleted file mode 100644
index 878cdd8e27425..0000000000000
--- a/llvm/test/Assembler/byte-invalid-cast-4.ll
+++ /dev/null
@@ -1,7 +0,0 @@
-; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s
-
-; CHECK: invalid cast opcode for cast from 'i8' to 'b32'
-define void @invalid_zext(i8 %v) {
-  %t = zext i8 %v to b32
-  ret void
-}
diff --git a/llvm/test/Assembler/byte-invalid-cast-5.ll b/llvm/test/Assembler/byte-invalid-cast-5.ll
deleted file mode 100644
index bb569ff9c6064..0000000000000
--- a/llvm/test/Assembler/byte-invalid-cast-5.ll
+++ /dev/null
@@ -1,7 +0,0 @@
-; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s
-
-; CHECK: invalid cast opcode for cast from 'i8' to 'b32'
-define void @invalid_sext(i8 %v) {
-  %t = sext i8 %v to b32
-  ret void
-}
diff --git a/llvm/test/Assembler/byte-invalid-cast-6.ll b/llvm/test/Assembler/byte-invalid-cast-6.ll
deleted file mode 100644
index fcfb00383ce3e..0000000000000
--- a/llvm/test/Assembler/byte-invalid-cast-6.ll
+++ /dev/null
@@ -1,7 +0,0 @@
-; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s
-
-; CHECK: invalid cast opcode for cast from 'i32' to 'b8'
-define void @invalid_trunc(i32 %v) {
-  %t = trunc i32 %v to b8
-  ret void
-}
diff --git a/llvm/test/Assembler/byte-invalid-cast-7.ll b/llvm/test/Assembler/byte-invalid-cast-7.ll
deleted file mode 100644
index edad062e0cbcd..0000000000000
--- a/llvm/test/Assembler/byte-invalid-cast-7.ll
+++ /dev/null
@@ -1,7 +0,0 @@
-; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s
-
-; CHECK: invalid cast opcode for cast from 'b32' to 'i8'
-define void @invalid_trunc(b32 %b) {
-  %t = trunc b32 %b to i8
-  ret void
-}
diff --git a/llvm/test/Assembler/byte-invalid-cast-8.ll b/llvm/test/Assembler/byte-invalid-cast-8.ll
deleted file mode 100644
index 2d92841c870ce..0000000000000
--- a/llvm/test/Assembler/byte-invalid-cast-8.ll
+++ /dev/null
@@ -1,7 +0,0 @@
-; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s
-
-; CHECK: invalid operand type for instruction
-define void @invalid_lshr(b32 %b) {
-  %t = lshr b32 %b, 8
-  ret void
-}
diff --git a/llvm/test/Assembler/byte-invalid-cmp.ll b/llvm/test/Assembler/byte-invalid-cmp.ll
deleted file mode 100644
index 8206b037ea911..0000000000000
--- a/llvm/test/Assembler/byte-invalid-cmp.ll
+++ /dev/null
@@ -1,7 +0,0 @@
-; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s
-
-; CHECK: icmp requires integer operands
-define void @byte_compare(b8 %b1, b8 %b2) {
-  %cmp = icmp eq b8 %b1, %b2
-  ret void
-}
diff --git a/llvm/test/Assembler/byte-invalid.ll b/llvm/test/Assembler/byte-invalid.ll
new file mode 100644
index 0000000000000..3cbecf25abacb
--- /dev/null
+++ b/llvm/test/Assembler/byte-invalid.ll
@@ -0,0 +1,73 @@
+; RUN: split-file %s %t
+; RUN: not llvm-as -disable-output %t/zext-byte-to-int.ll   2>&1 | FileCheck %t/zext-byte-to-int.ll
+; RUN: not llvm-as -disable-output %t/sext-byte-to-int.ll   2>&1 | FileCheck %t/sext-byte-to-int.ll
+; RUN: not llvm-as -disable-output %t/trunc-byte-to-byte.ll 2>&1 | FileCheck %t/trunc-byte-to-byte.ll
+; RUN: not llvm-as -disable-output %t/zext-int-to-byte.ll   2>&1 | FileCheck %t/zext-int-to-byte.ll
+; RUN: not llvm-as -disable-output %t/sext-int-to-byte.ll   2>&1 | FileCheck %t/sext-int-to-byte.ll
+; RUN: not llvm-as -disable-output %t/trunc-int-to-byte.ll  2>&1 | FileCheck %t/trunc-int-to-byte.ll
+; RUN: not llvm-as -disable-output %t/trunc-byte-to-int.ll  2>&1 | FileCheck %t/trunc-byte-to-int.ll
+; RUN: not llvm-as -disable-output %t/lshr-byte.ll          2>&1 | FileCheck %t/lshr-byte.ll
+; RUN: not llvm-as -disable-output %t/icmp-byte.ll          2>&1 | FileCheck %t/icmp-byte.ll
+
+;--- zext-byte-to-int.ll
+; CHECK: invalid cast opcode for cast from 'b8' to 'i32'
+define void @test(b8 %b) {
+  %t = zext b8 %b to i32
+  ret void
+}
+
+;--- sext-byte-to-int.ll
+; CHECK: invalid cast opcode for cast from 'b8' to 'i32'
+define void @test(b8 %b) {
+  %t = sext b8 %b to i32
+  ret void
+}
+
+;--- trunc-byte-to-byte.ll
+; CHECK: invalid cast opcode for cast from 'b32' to 'b8'
+define void @test(b32 %b) {
+  %t = trunc b32 %b to b8
+  ret void
+}
+
+;--- zext-int-to-byte.ll
+; CHECK: invalid cast opcode for cast from 'i8' to 'b32'
+define void @test(i8 %v) {
+  %t = zext i8 %v to b32
+  ret void
+}
+
+;--- sext-int-to-byte.ll
+; CHECK: invalid cast opcode for cast from 'i8' to 'b32'
+define void @test(i8 %v) {
+  %t = sext i8 %v to b32
+  ret void
+}
+
+;--- trunc-int-to-byte.ll
+; CHECK: invalid cast opcode for cast from 'i32' to 'b8'
+define void @test(i32 %v) {
+  %t = trunc i32 %v to b8
+  ret void
+}
+
+;--- trunc-byte-to-int.ll
+; CHECK: invalid cast opcode for cast from 'b32' to 'i8'
+define void @test(b32 %b) {
+  %t = trunc b32 %b to i8
+  ret void
+}
+
+;--- lshr-byte.ll
+; CHECK: invalid operand type for instruction
+define void @test(b32 %b) {
+  %t = lshr b32 %b, 8
+  ret void
+}
+
+;--- icmp-byte.ll
+; CHECK: icmp requires integer operands
+define void @test(b8 %b1, b8 %b2) {
+  %cmp = icmp eq b8 %b1, %b2
+  ret void
+}

>From 086b350a431efd80bc5ac2fcfb7440aea8b751d9 Mon Sep 17 00:00:00 2001
From: Pedro Lobo <pedro.lobo at tecnico.ulisboa.pt>
Date: Sun, 8 Mar 2026 11:12:16 +0000
Subject: [PATCH 6/6] address review comments

---
 llvm/docs/LangRef.rst                         | 45 +++++++++----------
 llvm/include/llvm-c/Core.h                    |  5 ++-
 llvm/include/llvm/IR/Constants.h              |  2 +-
 .../SelectionDAG/FunctionLoweringInfo.cpp     |  2 +-
 llvm/lib/IR/Core.cpp                          |  4 --
 5 files changed, 27 insertions(+), 31 deletions(-)

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 0fa8c76aa2966..3211ade27d494 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -4452,8 +4452,7 @@ expected to use a byte type when:
 
 #. Working with possibly uninitialized data.
 
-Otherwise, when known, the specific specific type should be used. Each bit can
-be:
+Otherwise, when known, the specific type should be used. Each bit can be:
 
 * An integer bit (0 or 1)
 * Part of a pointer value
@@ -13063,32 +13062,32 @@ element zero ends up in the most significant bits for big-endian.
 
 If ``value`` is of the :ref:`byte type <t_byte>`:
 
-* If ``value`` contains at least one ``poison`` bit, the cast result is
+* If ``ty2`` is a scalar type:
 
-    * ``poison``, if ``ty2`` is a scalar type.
+    * If ``ty2`` is a byte type, the original bits are unchanged.
 
-    * a vector where only the lanes containing at least one ``poison`` bit are
-      ``poison``, if ``ty2`` is a vector type. The values of the remaining
-      non-``poison`` lanes are given by bitcasting the bits of ``value``
-      corresponding to each lane (according to the target's endianness) to the
-      lane element type.
+    * If ``ty2`` is a pointer type:
 
-* If ``value`` is any mix of (non-``poison``) pointer and non-pointer bits:
+        * If at least one bit of ``value`` is ``poison``, the result is
+          ``poison``.
 
-    * If ``ty2`` is a non-pointer type, the provenance of the pointer bits is
-      stripped without being exposed, similarly to the
-      :ref:`ptrtoaddr <i_ptrtoaddr>` instruction.
+        * If all bits of ``value`` are from the same pointer and are correctly
+          ordered (there were no pointer bit swaps), the result is that pointer.
 
-    * If ``ty2`` is a pointer type, then if all bits of ``value`` are from the
-      same pointer and are correctly ordered (there were no pointer bit swaps),
-      the cast result is that pointer. If all the bits are from the same pointer
-      and these are not correctly ordered, or if ``value`` is a mix of bits from
-      different pointers or a mix of pointer and non-pointer bits, the result is
-      a pointer without provenance. This pointer cannot be dereferenced, but can
-      be used in comparisons or :ref:`getelementptr <i_getelementptr>`
-      instructions.
+        * Otherwise, the result is a pointer with the address given by the
+          integer value of the input, and without provenance.
 
-* Otherwise, the cast is a *no-op*.
+    * If ``ty2`` is an integer or floating-point type:
+
+        * If at least one bit of ``value`` is ``poison``, the result is
+          ``poison``.
+
+        * Otherwise, the result is the value encoded by the input bits with
+          their provenance stripped without being exposed.
+
+* If ``ty2`` is a vector type, the input bits get sliced into chunks
+  corresponding to lanes of the output. Each lane is then converted using the
+  rules for scalar types above.
 
 Example:
 """"""""
@@ -13571,7 +13570,7 @@ Example:
       %d = extractelement <2 x i32> %v.fr, i32 0 ; not undef
       %add.f = add i32 %d, %d                    ; even number
 
-      %l = load b32, ptr %p                      ; may be unitialized
+      %l = load b32, ptr %p                      ; may be uninitialized
       %f = freeze b32 %l                         ; freezes on a per-bit basis
 
       ; branching on frozen value
diff --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h
index 08a92f1dff2d6..c0dfefbfff5a8 100644
--- a/llvm/include/llvm-c/Core.h
+++ b/llvm/include/llvm-c/Core.h
@@ -2491,14 +2491,15 @@ LLVM_C_ABI long long LLVMConstIntGetSExtValue(LLVMValueRef ConstantVal);
  *
  * @see llvm::ConstantByte::getZExtValue()
  */
-unsigned long long LLVMConstByteGetZExtValue(LLVMValueRef ConstantVal);
+LLVM_C_ABI unsigned long long
+LLVMConstByteGetZExtValue(LLVMValueRef ConstantVal);
 
 /**
  * Obtain the sign extended value for a byte constant value.
  *
  * @see llvm::ConstantByte::getSExtValue()
  */
-long long LLVMConstByteGetSExtValue(LLVMValueRef ConstantVal);
+LLVM_C_ABI long long LLVMConstByteGetSExtValue(LLVMValueRef ConstantVal);
 
 /**
  * Obtain the double value for an floating point constant value.
diff --git a/llvm/include/llvm/IR/Constants.h b/llvm/include/llvm/IR/Constants.h
index da5bf684557d7..5d68c0985c752 100644
--- a/llvm/include/llvm/IR/Constants.h
+++ b/llvm/include/llvm/IR/Constants.h
@@ -839,7 +839,7 @@ class ConstantDataSequential : public ConstantData {
 
 //===----------------------------------------------------------------------===//
 /// An array constant whose element type is a simple 1/2/4/8-byte integer, bytes
-//  or float/double, and whose elements are just simple data values
+///  or float/double, and whose elements are just simple data values
 /// (i.e. ConstantInt/ConstantFP). This Constant node has no operands because it
 /// stores all of the elements of the constant as densely packed data, instead
 /// of as Value*'s.
diff --git a/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp b/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
index d71ed4d4cb4ca..7eacdc0bd7bc4 100644
--- a/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
@@ -479,7 +479,7 @@ void FunctionLoweringInfo::ComputePHILiveOutRegInfo(const PHINode *PN) {
     LiveOutInfo &DestLOI = LiveOutRegInfo[DestReg];
 
     Value *V = PN->getIncomingValue(0);
-    if (isa<UndefValue>(V) || isa<ConstantExpr>(V) || isa<ConstantByte>(V)) {
+    if (isa<UndefValue>(V) || isa<ConstantExpr>(V)) {
       DestLOI.NumSignBits = 1;
       DestLOI.Known = KnownBits(BitWidth);
       continue;
diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp
index 3a63176ca49df..1777b1f389334 100644
--- a/llvm/lib/IR/Core.cpp
+++ b/llvm/lib/IR/Core.cpp
@@ -664,10 +664,6 @@ LLVMTypeRef LLVMByteTypeInContext(LLVMContextRef C, unsigned NumBits) {
   return wrap(ByteType::get(*unwrap(C), NumBits));
 }
 
-LLVMTypeRef LLVMByteType(unsigned NumBits) {
-  return LLVMByteTypeInContext(getGlobalContextForCAPI(), NumBits);
-}
-
 unsigned LLVMGetByteTypeWidth(LLVMTypeRef ByteTy) {
   return unwrap<ByteType>(ByteTy)->getBitWidth();
 }



More information about the llvm-commits mailing list