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

Pedro Lobo via llvm-commits llvm-commits at lists.llvm.org
Sat Jan 31 12:18:48 PST 2026


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

>From afeb5bf065719aa67db1cb57aa56d1bfc9d37e31 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 01/15] [IR] Introduce the byte type

- Adds the byte type
- Extends the `bitcast` instruction to accept the byte type as a destination type
- 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                |  37 +-
 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    |   6 +-
 .../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                  |  26 +-
 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 +
 .../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-cmp.ll       |   7 +
 llvm/test/Assembler/byte.ll                   |  79 ++++
 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/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 +-
 51 files changed, 1423 insertions(+), 150 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-cmp.ll
 create mode 100644 llvm/test/Assembler/byte.ll
 create mode 100644 llvm/test/Bindings/llvm-c/byte.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..e728e76fcc058 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");
@@ -488,6 +489,7 @@ class Vocabulary {
       CanonicalTypeID::MetadataTy, // MetadataTyID
       CanonicalTypeID::VectorTy,   // X86_AMXTyID
       CanonicalTypeID::TokenTy,    // TokenTyID
+      CanonicalTypeID::ByteTy,     // ByteTyID
       CanonicalTypeID::IntegerTy,  // IntegerTyID
       CanonicalTypeID::FunctionTy, // FunctionTyID
       CanonicalTypeID::PointerTy,  // PointerTyID
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..53d1b1ca9b059 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 an 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..7c1fcb90952ec 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 an ByteType.
+  /// If an 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 an 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..1640de3b9fbd8 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;
@@ -67,6 +68,7 @@ class Type {
     TokenTyID,     ///< Tokens
 
     // Derived types... see DerivedTypes.h file.
+    ByteTyID,           ///< Arbitrary bit width bytes
     IntegerTyID,        ///< Arbitrary bit width integers
     FunctionTyID,       ///< Functions
     PointerTyID,        ///< Pointers
@@ -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 an 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..e5de7daa78aa0 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,25 @@ 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..c0b284ec865f6 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())
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..9f7342a7bc83b 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;
@@ -999,6 +1041,133 @@ 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) {
+  // TODO: Avoid implicit trunc?
+  // See https://github.com/llvm/llvm-project/issues/112510.
+  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 +1438,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 int 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 +1479,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 +1553,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 +1652,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 +1675,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 +1696,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 +1706,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 +1719,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 +1837,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 +1946,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 +2007,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 +2032,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 +2052,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 +3100,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 +3243,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 +3327,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 +3412,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 +3456,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 +3477,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 +3547,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..c57e56cf5c095 100644
--- a/llvm/lib/IR/Instructions.cpp
+++ b/llvm/lib/IR/Instructions.cpp
@@ -3183,6 +3183,9 @@ bool CastInst::isBitCastable(Type *SrcTy, Type *DestTy) {
   if (SrcBits != DestBits)
     return false;
 
+  if (SrcTy->isByteOrByteVectorTy() && !DestTy->isByteOrByteVectorTy())
+    return false;
+
   return true;
 }
 
@@ -3237,7 +3240,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
@@ -3368,8 +3380,14 @@ CastInst::castIsValid(Instruction::CastOps op, Type *SrcTy, Type *DstTy) {
     PointerType *SrcPtrTy = dyn_cast<PointerType>(SrcTy->getScalarType());
     PointerType *DstPtrTy = dyn_cast<PointerType>(DstTy->getScalarType());
 
+    // Bytes can only be cast to bytes.
+    if (SrcTy->isByteOrByteVectorTy() && !DstTy->isByteOrByteVectorTy())
+      return false;
+
     // 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())
+      return true;
     if (!SrcPtrTy != !DstPtrTy)
       return false;
 
@@ -3382,6 +3400,10 @@ CastInst::castIsValid(Instruction::CastOps op, Type *SrcTy, Type *DstTy) {
     if (SrcPtrTy->getAddressSpace() != DstPtrTy->getAddressSpace())
       return false;
 
+    // Integers can be cast to bytes of the same size.
+    if (SrcTy->isIntOrIntVectorTy() && DstTy->isByteOrByteVectorTy())
+      return SrcScalarBitSize == DstScalarBitSize;
+
     // A vector of pointers must have the same number of elements.
     if (SrcIsVec && DstIsVec)
       return SrcEC == DstEC;
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..0d87385b44d8f 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, V);
+        }
+        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/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..edad062e0cbcd
--- /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 'i8'
+define void @invalid_trunc(b32 %b) {
+  %t = trunc b32 %b to i8
+  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..d1e90960d4a02
--- /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 'b8' to 'i8'
+define void @invalid_bitcast(b8 %b) {
+  %t = bitcast b8 %b to i8
+  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..d62d6cd9b5fc3
--- /dev/null
+++ b/llvm/test/Assembler/byte.ll
@@ -0,0 +1,79 @@
+; RUN: llvm-as < %s | llvm-dis | 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 <8 x b8> [[TMP3]] to <2 x b32>
+; CHECK-NEXT:    [[TMP5:%.*]] = bitcast <2 x b32> [[TMP4]] to b64
+; CHECK-NEXT:    [[TMP6:%.*]] = bitcast <2 x b32> splat (b32 1) to b64
+; 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 <8 x b8> %3 to <2 x b32>
+  %5 = bitcast <2 x b32> %4 to b64
+  %6 = bitcast <2 x b32> <b32 1, b32 1> to b64
+  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/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 dd7f2c053c57c9a9c76d21d18480fd914a31969a Mon Sep 17 00:00:00 2001
From: George Mitenkov <georgemitenk0v at gmail.com>
Date: Fri, 23 Jul 2021 11:20:49 +0300
Subject: [PATCH 02/15] [IR] Introduce the `bytecast` instruction

- Adds the `bytecast` instruction
- Fixes IR2Vec and IRNormalizer tests
---
 llvm/include/llvm-c/Core.h                    |   5 +
 llvm/include/llvm/AsmParser/LLToken.h         |   1 +
 llvm/include/llvm/Bitcode/LLVMBitCodes.h      |   1 +
 .../llvm/CodeGen/GlobalISel/IRTranslator.h    |   3 +
 llvm/include/llvm/IR/Constants.h              |   2 +
 llvm/include/llvm/IR/IRBuilder.h              |  46 +++++++
 llvm/include/llvm/IR/InstVisitor.h            |   1 +
 llvm/include/llvm/IR/Instruction.def          |  45 +++----
 llvm/include/llvm/IR/Instructions.h           |  32 +++++
 llvm/lib/AsmParser/LLLexer.cpp                |   1 +
 llvm/lib/AsmParser/LLParser.cpp               |   5 +-
 llvm/lib/Bitcode/Reader/BitcodeReader.cpp     |   3 +
 llvm/lib/Bitcode/Writer/BitcodeWriter.cpp     |   3 +
 .../SelectionDAG/SelectionDAGBuilder.cpp      |  21 +++
 .../SelectionDAG/SelectionDAGBuilder.h        |   1 +
 llvm/lib/CodeGen/TargetLoweringBase.cpp       |   3 +
 llvm/lib/IR/Constants.cpp                     |  13 ++
 llvm/lib/IR/Core.cpp                          |   5 +
 llvm/lib/IR/Instruction.cpp                   |   3 +
 llvm/lib/IR/Instructions.cpp                  |  88 +++++++++----
 llvm/lib/IR/Verifier.cpp                      |   8 ++
 .../Inputs/reference_default_vocab_print.txt  |   1 +
 .../Inputs/reference_wtd1_vocab_print.txt     |   1 +
 .../Inputs/reference_wtd2_vocab_print.txt     |   1 +
 llvm/test/Assembler/byte-invalid-cast-10.ll   |   7 +
 llvm/test/Assembler/byte-invalid-cast-8.ll    |   7 +
 llvm/test/Assembler/byte-invalid-cast-9.ll    |   7 +
 llvm/test/Assembler/byte.ll                   |  48 +++++++
 llvm/test/Bindings/llvm-c/byte.ll             |   1 +
 llvm/test/Bitcode/compatibility.ll            |   4 +
 .../regression-convergence-tokens.ll          |   6 +-
 .../IRNormalizer/regression-infinite-loop.ll  |  44 +++----
 .../IRNormalizer/reordering-basic.ll          |  14 +-
 .../Transforms/IRNormalizer/reordering.ll     |   8 +-
 llvm/test/tools/llvm-ir2vec/entities.ll       | 123 +++++++++---------
 llvm/test/tools/llvm-ir2vec/triplets.ll       |  58 ++++-----
 llvm/tools/llvm-c-test/echo.cpp               |   5 +
 llvm/unittests/Analysis/IR2VecTest.cpp        |  28 ++--
 38 files changed, 465 insertions(+), 188 deletions(-)
 create mode 100644 llvm/test/Assembler/byte-invalid-cast-10.ll
 create mode 100644 llvm/test/Assembler/byte-invalid-cast-8.ll
 create mode 100644 llvm/test/Assembler/byte-invalid-cast-9.ll

diff --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h
index 23f94408b86b5..1c19194021c11 100644
--- a/llvm/include/llvm-c/Core.h
+++ b/llvm/include/llvm-c/Core.h
@@ -58,6 +58,7 @@ LLVM_C_EXTERN_C_BEGIN
 
 /// External users depend on the following values being stable. It is not safe
 /// to reorder them.
+// clang-format off
 typedef enum {
   /* Terminator Instructions */
   LLVMRet            = 1,
@@ -115,6 +116,7 @@ typedef enum {
   LLVMIntToPtr       = 40,
   LLVMBitCast        = 41,
   LLVMAddrSpaceCast  = 60,
+  LLVMByteCast       = 70,
 
   /* Other Operators */
   LLVMICmp           = 42,
@@ -146,6 +148,7 @@ typedef enum {
   LLVMCleanupPad     = 64,
   LLVMCatchSwitch    = 65
 } LLVMOpcode;
+// clang-format on
 
 typedef enum {
   LLVMVoidTypeKind = 0,     /**< type with no size */
@@ -5043,6 +5046,8 @@ LLVM_C_ABI LLVMValueRef LLVMBuildIntToPtr(LLVMBuilderRef, LLVMValueRef Val,
                                           LLVMTypeRef DestTy, const char *Name);
 LLVM_C_ABI LLVMValueRef LLVMBuildBitCast(LLVMBuilderRef, LLVMValueRef Val,
                                          LLVMTypeRef DestTy, const char *Name);
+LLVM_C_ABI LLVMValueRef LLVMBuildByteCast(LLVMBuilderRef, LLVMValueRef Val,
+                                          LLVMTypeRef DestTy, const char *Name);
 LLVM_C_ABI LLVMValueRef LLVMBuildAddrSpaceCast(LLVMBuilderRef, LLVMValueRef Val,
                                                LLVMTypeRef DestTy,
                                                const char *Name);
diff --git a/llvm/include/llvm/AsmParser/LLToken.h b/llvm/include/llvm/AsmParser/LLToken.h
index 24f84cfa09e34..377eb68596002 100644
--- a/llvm/include/llvm/AsmParser/LLToken.h
+++ b/llvm/include/llvm/AsmParser/LLToken.h
@@ -328,6 +328,7 @@ enum Kind {
   kw_ptrtoint,
   kw_bitcast,
   kw_addrspacecast,
+  kw_bytecast,
   kw_select,
   kw_va_arg,
 
diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
index 592bdf3a34949..be6a71c35900b 100644
--- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h
+++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
@@ -465,6 +465,7 @@ enum CastOpcodes {
   CAST_BITCAST = 11,
   CAST_ADDRSPACECAST = 12,
   CAST_PTRTOADDR = 13,
+  CAST_BYTECAST = 14
 };
 
 /// UnaryOpcodes - These are values used in the bitcode files to encode which
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h b/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h
index 3828d859212cb..14cc9ec0f3d8d 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h
@@ -585,6 +585,9 @@ class IRTranslator : public MachineFunctionPass {
   bool translateAddrSpaceCast(const User &U, MachineIRBuilder &MIRBuilder) {
     return translateCast(TargetOpcode::G_ADDRSPACE_CAST, U, MIRBuilder);
   }
+  bool translateByteCast(const User &U, MachineIRBuilder &MIRBuilder) {
+    return false;
+  }
   bool translateCleanupPad(const User &U, MachineIRBuilder &MIRBuilder) {
     return false;
   }
diff --git a/llvm/include/llvm/IR/Constants.h b/llvm/include/llvm/IR/Constants.h
index 53d1b1ca9b059..9c00b55140fc6 100644
--- a/llvm/include/llvm/IR/Constants.h
+++ b/llvm/include/llvm/IR/Constants.h
@@ -1394,6 +1394,8 @@ class ConstantExpr : public Constant {
                                        bool OnlyIfReduced = false);
   LLVM_ABI static Constant *getAddrSpaceCast(Constant *C, Type *Ty,
                                              bool OnlyIfReduced = false);
+  LLVM_ABI static Constant *getByteCast(Constant *C, Type *Ty,
+                                        bool OnlyIfReduced = false);
 
   static Constant *getNSWNeg(Constant *C) { return getNeg(C, /*HasNSW=*/true); }
 
diff --git a/llvm/include/llvm/IR/IRBuilder.h b/llvm/include/llvm/IR/IRBuilder.h
index ddf0538e0a30e..f005b0fc75ee3 100644
--- a/llvm/include/llvm/IR/IRBuilder.h
+++ b/llvm/include/llvm/IR/IRBuilder.h
@@ -2204,6 +2204,45 @@ class IRBuilderBase {
     return CreateCast(Instruction::AddrSpaceCast, V, DestTy, Name);
   }
 
+  Value *CreateByteCast(Value *V, Type *DestTy, const Twine &Name = "") {
+    if (Value *Folded = Folder.FoldCast(Instruction::ByteCast, V, DestTy))
+      return Folded;
+    Instruction *I = CastInst::Create(Instruction::ByteCast, V, DestTy);
+    return Insert(I, Name);
+  }
+
+  Value *CreateByteCastToInt(Value *V, const Twine &Name = "") {
+    if (auto *VTy = dyn_cast<VectorType>(V->getType())) {
+      unsigned NumEls = VTy->getElementCount().getKnownMinValue();
+      unsigned BitWidth = VTy->getElementType()->getPrimitiveSizeInBits();
+
+      Type *DestElTy = getIntNTy(BitWidth);
+      VectorType *DestTy =
+          VectorType::get(DestElTy, NumEls, VTy->isScalableTy());
+
+      return CreateByteCast(V, DestTy, Name);
+    }
+
+    Type *DestTy = getIntNTy(V->getType()->getByteBitWidth());
+    return CreateByteCast(V, DestTy, Name);
+  }
+
+  Value *CreateByteCastToPtr(Value *V, unsigned AddrSpace = 0,
+                             const Twine &Name = "") {
+    if (auto *VTy = dyn_cast<VectorType>(V->getType())) {
+      unsigned NumEls = VTy->getElementCount().getKnownMinValue();
+
+      Type *DestElTy = getPtrTy(AddrSpace);
+      VectorType *DestTy =
+          VectorType::get(DestElTy, NumEls, VTy->isScalableTy());
+
+      return CreateByteCast(V, DestTy, Name);
+    }
+
+    Type *DestTy = getPtrTy(AddrSpace);
+    return CreateByteCast(V, DestTy, Name);
+  }
+
   Value *CreateZExtOrBitCast(Value *V, Type *DestTy, const Twine &Name = "") {
     Instruction::CastOps CastOp =
         V->getType()->getScalarSizeInBits() == DestTy->getScalarSizeInBits()
@@ -2228,6 +2267,13 @@ class IRBuilderBase {
     return CreateCast(CastOp, V, DestTy, Name);
   }
 
+  Value *CreateBitOrByteCast(Value *V, Type *DestTy, const Twine &Name = "") {
+    Instruction::CastOps CastOp = V->getType()->isByteOrByteVectorTy()
+                                      ? Instruction::ByteCast
+                                      : Instruction::BitCast;
+    return CreateCast(CastOp, V, DestTy, Name);
+  }
+
   Value *CreateCast(Instruction::CastOps Op, Value *V, Type *DestTy,
                     const Twine &Name = "", MDNode *FPMathTag = nullptr,
                     FMFSource FMFSource = {}) {
diff --git a/llvm/include/llvm/IR/InstVisitor.h b/llvm/include/llvm/IR/InstVisitor.h
index 8e4dc647e5230..ff3eff9506f95 100644
--- a/llvm/include/llvm/IR/InstVisitor.h
+++ b/llvm/include/llvm/IR/InstVisitor.h
@@ -187,6 +187,7 @@ class InstVisitor {
   RetTy visitIntToPtrInst(IntToPtrInst &I)        { DELEGATE(CastInst);}
   RetTy visitBitCastInst(BitCastInst &I)          { DELEGATE(CastInst);}
   RetTy visitAddrSpaceCastInst(AddrSpaceCastInst &I) { DELEGATE(CastInst);}
+  RetTy visitByteCastInst(ByteCastInst &I) { DELEGATE(CastInst); }
   RetTy visitSelectInst(SelectInst &I)            { DELEGATE(Instruction);}
   RetTy visitVAArgInst(VAArgInst   &I)            { DELEGATE(UnaryInstruction);}
   RetTy visitExtractElementInst(ExtractElementInst &I) { DELEGATE(Instruction);}
diff --git a/llvm/include/llvm/IR/Instruction.def b/llvm/include/llvm/IR/Instruction.def
index face6a93ec7d5..bc0f22892e13f 100644
--- a/llvm/include/llvm/IR/Instruction.def
+++ b/llvm/include/llvm/IR/Instruction.def
@@ -195,31 +195,32 @@ HANDLE_CAST_INST(48, PtrToAddr, PtrToAddrInst) // Pointer -> Address
 HANDLE_CAST_INST(49, IntToPtr, IntToPtrInst)  // Integer -> Pointer
 HANDLE_CAST_INST(50, BitCast , BitCastInst )  // Type cast
 HANDLE_CAST_INST(51, AddrSpaceCast, AddrSpaceCastInst)  // addrspace cast
-  LAST_CAST_INST(51)
+HANDLE_CAST_INST(52, ByteCast , ByteCastInst )  // Byte cast
+  LAST_CAST_INST(52)
 
- FIRST_FUNCLETPAD_INST(52)
-HANDLE_FUNCLETPAD_INST(52, CleanupPad, CleanupPadInst)
-HANDLE_FUNCLETPAD_INST(53, CatchPad  , CatchPadInst)
-  LAST_FUNCLETPAD_INST(53)
+ FIRST_FUNCLETPAD_INST(53)
+HANDLE_FUNCLETPAD_INST(53, CleanupPad, CleanupPadInst)
+HANDLE_FUNCLETPAD_INST(54, CatchPad  , CatchPadInst)
+  LAST_FUNCLETPAD_INST(54)
 
 // Other operators...
- FIRST_OTHER_INST(54)
-HANDLE_OTHER_INST(54, ICmp   , ICmpInst   )  // Integer comparison instruction
-HANDLE_OTHER_INST(55, FCmp   , FCmpInst   )  // Floating point comparison instr.
-HANDLE_OTHER_INST(56, PHI    , PHINode    )  // PHI node instruction
-HANDLE_OTHER_INST(57, Call   , CallInst   )  // Call a function
-HANDLE_OTHER_INST(58, Select , SelectInst )  // select instruction
-HANDLE_USER_INST (59, UserOp1, Instruction)  // May be used internally in a pass
-HANDLE_USER_INST (60, UserOp2, Instruction)  // Internal to passes only
-HANDLE_OTHER_INST(61, VAArg  , VAArgInst  )  // vaarg instruction
-HANDLE_OTHER_INST(62, ExtractElement, ExtractElementInst)// extract from vector
-HANDLE_OTHER_INST(63, InsertElement, InsertElementInst)  // insert into vector
-HANDLE_OTHER_INST(64, ShuffleVector, ShuffleVectorInst)  // shuffle two vectors.
-HANDLE_OTHER_INST(65, ExtractValue, ExtractValueInst)// extract from aggregate
-HANDLE_OTHER_INST(66, InsertValue, InsertValueInst)  // insert into aggregate
-HANDLE_OTHER_INST(67, LandingPad, LandingPadInst)  // Landing pad instruction.
-HANDLE_OTHER_INST(68, Freeze, FreezeInst) // Freeze instruction.
-  LAST_OTHER_INST(68)
+ FIRST_OTHER_INST(55)
+HANDLE_OTHER_INST(55, ICmp   , ICmpInst   )  // Integer comparison instruction
+HANDLE_OTHER_INST(56, FCmp   , FCmpInst   )  // Floating point comparison instr.
+HANDLE_OTHER_INST(57, PHI    , PHINode    )  // PHI node instruction
+HANDLE_OTHER_INST(58, Call   , CallInst   )  // Call a function
+HANDLE_OTHER_INST(59, Select , SelectInst )  // select instruction
+HANDLE_USER_INST (60, UserOp1, Instruction)  // May be used internally in a pass
+HANDLE_USER_INST (61, UserOp2, Instruction)  // Internal to passes only
+HANDLE_OTHER_INST(62, VAArg  , VAArgInst  )  // vaarg instruction
+HANDLE_OTHER_INST(63, ExtractElement, ExtractElementInst)// extract from vector
+HANDLE_OTHER_INST(64, InsertElement, InsertElementInst)  // insert into vector
+HANDLE_OTHER_INST(65, ShuffleVector, ShuffleVectorInst)  // shuffle two vectors.
+HANDLE_OTHER_INST(66, ExtractValue, ExtractValueInst)// extract from aggregate
+HANDLE_OTHER_INST(67, InsertValue, InsertValueInst)  // insert into aggregate
+HANDLE_OTHER_INST(68, LandingPad, LandingPadInst)  // Landing pad instruction.
+HANDLE_OTHER_INST(69, Freeze, FreezeInst) // Freeze instruction.
+  LAST_OTHER_INST(69)
 
 #undef  FIRST_TERM_INST
 #undef HANDLE_TERM_INST
diff --git a/llvm/include/llvm/IR/Instructions.h b/llvm/include/llvm/IR/Instructions.h
index d4ea74c05ae62..e1009322c61c3 100644
--- a/llvm/include/llvm/IR/Instructions.h
+++ b/llvm/include/llvm/IR/Instructions.h
@@ -5198,6 +5198,38 @@ inline void setAtomicSyncScopeID(Instruction *I, SyncScope::ID SSID) {
     llvm_unreachable("unhandled atomic operation");
 }
 
+//===----------------------------------------------------------------------===//
+//                             ByteCastInst Class
+//===----------------------------------------------------------------------===//
+
+/// This class represents a cast for byte types.
+class ByteCastInst : public CastInst {
+protected:
+  // Note: Instruction needs to be a friend here to call cloneImpl.
+  friend class Instruction;
+
+  /// Clone an identical ByteCastInst.
+  LLVM_ABI ByteCastInst *cloneImpl() const;
+
+public:
+  /// Constructor with insert-before-instruction semantics
+  LLVM_ABI
+  ByteCastInst(Value *S,                  ///< The value to be casted
+               Type *Ty,                  ///< The type to casted to
+               const Twine &NameStr = "", ///< A name for the new instruction
+               InsertPosition InsertBefore =
+                   nullptr ///< Where to insert the new instruction
+  );
+
+  // Methods for support type inquiry through isa, cast, and dyn_cast:
+  static bool classof(const Instruction *I) {
+    return I->getOpcode() == ByteCast;
+  }
+  static bool classof(const Value *V) {
+    return isa<Instruction>(V) && classof(cast<Instruction>(V));
+  }
+};
+
 //===----------------------------------------------------------------------===//
 //                              FreezeInst Class
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp
index e5de7daa78aa0..828cd20104284 100644
--- a/llvm/lib/AsmParser/LLLexer.cpp
+++ b/llvm/lib/AsmParser/LLLexer.cpp
@@ -953,6 +953,7 @@ lltok::Kind LLLexer::LexIdentifier() {
   INSTKEYWORD(ptrtoint,    PtrToInt);
   INSTKEYWORD(bitcast,     BitCast);
   INSTKEYWORD(addrspacecast, AddrSpaceCast);
+  INSTKEYWORD(bytecast, ByteCast);
   INSTKEYWORD(select,      Select);
   INSTKEYWORD(va_arg,      VAArg);
   INSTKEYWORD(ret,         Ret);
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index 1965efd37b968..9ce92d042e712 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -4345,6 +4345,7 @@ bool LLParser::parseValID(ValID &ID, PerFunctionState *PFS, Type *ExpectedTy) {
 
   case lltok::kw_trunc:
   case lltok::kw_bitcast:
+  case lltok::kw_bytecast:
   case lltok::kw_addrspacecast:
   case lltok::kw_inttoptr:
   case lltok::kw_ptrtoaddr:
@@ -7448,6 +7449,7 @@ int LLParser::parseInstruction(Instruction *&Inst, BasicBlock *BB,
   case lltok::kw_inttoptr:
   case lltok::kw_ptrtoaddr:
   case lltok::kw_ptrtoint:
+  case lltok::kw_bytecast:
     return parseCast(Inst, PFS, KeywordVal);
   case lltok::kw_fptrunc:
   case lltok::kw_fpext: {
@@ -8033,7 +8035,8 @@ bool LLParser::parseUnaryOp(Instruction *&Inst, PerFunctionState &PFS,
     return true;
 
   bool Valid = IsFP ? LHS->getType()->isFPOrFPVectorTy()
-                    : LHS->getType()->isIntOrIntVectorTy();
+                    : (LHS->getType()->isIntOrIntVectorTy() ||
+                       LHS->getType()->isByteOrByteVectorTy());
 
   if (!Valid)
     return error(Loc, "invalid operand type for instruction");
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index 550972a252e90..5569ddb965673 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -1272,6 +1272,7 @@ static GlobalVariable::UnnamedAddr getDecodedUnnamedAddrType(unsigned Val) {
   }
 }
 
+// clang-format off
 static int getDecodedCastOpcode(unsigned Val) {
   switch (Val) {
   default: return -1;
@@ -1288,9 +1289,11 @@ static int getDecodedCastOpcode(unsigned Val) {
   case bitc::CAST_PTRTOINT: return Instruction::PtrToInt;
   case bitc::CAST_INTTOPTR: return Instruction::IntToPtr;
   case bitc::CAST_BITCAST : return Instruction::BitCast;
+  case bitc::CAST_BYTECAST: return Instruction::ByteCast;
   case bitc::CAST_ADDRSPACECAST: return Instruction::AddrSpaceCast;
   }
 }
+// clang-format on
 
 static int getDecodedUnaryOpcode(unsigned Val, Type *Ty) {
   bool IsFP = Ty->isFPOrFPVectorTy();
diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index 1e9058b9939b7..4a3d19cdc5adb 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -639,6 +639,7 @@ class IndexBitcodeWriter : public BitcodeWriterBase {
 
 } // end anonymous namespace
 
+// clang-format off
 static unsigned getEncodedCastOpcode(unsigned Opcode) {
   switch (Opcode) {
   default: llvm_unreachable("Unknown cast instruction!");
@@ -655,9 +656,11 @@ static unsigned getEncodedCastOpcode(unsigned Opcode) {
   case Instruction::PtrToInt: return bitc::CAST_PTRTOINT;
   case Instruction::IntToPtr: return bitc::CAST_INTTOPTR;
   case Instruction::BitCast : return bitc::CAST_BITCAST;
+  case Instruction::ByteCast: return bitc::CAST_BYTECAST;
   case Instruction::AddrSpaceCast: return bitc::CAST_ADDRSPACECAST;
   }
 }
+// clang-format on
 
 static unsigned getEncodedUnaryOpcode(unsigned Opcode) {
   switch (Opcode) {
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 2cbf2ae8105b7..5d97b7e73c673 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -4132,6 +4132,27 @@ void SelectionDAGBuilder::visitAddrSpaceCast(const User &I) {
   setValue(&I, N);
 }
 
+void SelectionDAGBuilder::visitByteCast(const User &I) {
+  SDValue N = getValue(I.getOperand(0));
+  SDLoc dl = getCurSDLoc();
+  EVT DestVT = DAG.getTargetLoweringInfo().getValueType(DAG.getDataLayout(),
+                                                        I.getType());
+
+  if (DestVT != N.getValueType())
+    // Convert vector types.
+    setValue(&I, DAG.getNode(ISD::BITCAST, dl, DestVT, N));
+  // Check if the original LLVM IR Operand was a ConstantByte, because
+  // getValue() might fold any kind of constant expression to an byte constant
+  // and that is not what we are looking for. Only recognize a bytecast of a
+  // genuine constant byte as an opaque constant.
+  else if (ConstantByte *C = dyn_cast<ConstantByte>(I.getOperand(0)))
+    setValue(&I, DAG.getConstant(C->getValue(), dl, DestVT, /*isTarget=*/false,
+                                 /*isOpaque*/ true));
+  else
+    // No-op cast.
+    setValue(&I, N);
+}
+
 void SelectionDAGBuilder::visitInsertElement(const User &I) {
   const TargetLowering &TLI = DAG.getTargetLoweringInfo();
   SDValue InVec = getValue(I.getOperand(0));
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
index f8aecea25b3d6..ab8368e705e8b 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
@@ -602,6 +602,7 @@ class SelectionDAGBuilder {
   void visitIntToPtr(const User &I);
   void visitBitCast(const User &I);
   void visitAddrSpaceCast(const User &I);
+  void visitByteCast(const User &I);
 
   void visitExtractElement(const User &I);
   void visitInsertElement(const User &I);
diff --git a/llvm/lib/CodeGen/TargetLoweringBase.cpp b/llvm/lib/CodeGen/TargetLoweringBase.cpp
index 922b3fa40518d..839e3c962b053 100644
--- a/llvm/lib/CodeGen/TargetLoweringBase.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringBase.cpp
@@ -2163,6 +2163,7 @@ unsigned TargetLoweringBase::getMaxStoresPerMemmove(bool OptSize) const {
 //  TargetTransformInfo Helpers
 //===----------------------------------------------------------------------===//
 
+// clang-format off
 int TargetLoweringBase::InstructionOpcodeToISD(unsigned Opcode) const {
   enum InstructionOpcodes {
 #define HANDLE_INST(NUM, OPCODE, CLASS) OPCODE = NUM,
@@ -2222,6 +2223,7 @@ int TargetLoweringBase::InstructionOpcodeToISD(unsigned Opcode) const {
   case PtrToInt:       return ISD::BITCAST;
   case IntToPtr:       return ISD::BITCAST;
   case BitCast:        return ISD::BITCAST;
+  case ByteCast:       return ISD::BITCAST;
   case AddrSpaceCast:  return ISD::ADDRSPACECAST;
   case ICmp:           return ISD::SETCC;
   case FCmp:           return ISD::SETCC;
@@ -2242,6 +2244,7 @@ int TargetLoweringBase::InstructionOpcodeToISD(unsigned Opcode) const {
 
   llvm_unreachable("Unknown instruction type encountered!");
 }
+// clang-format on
 
 int TargetLoweringBase::IntrinsicIDToISD(Intrinsic::ID ID) const {
   switch (ID) {
diff --git a/llvm/lib/IR/Constants.cpp b/llvm/lib/IR/Constants.cpp
index 9f7342a7bc83b..06f312434003f 100644
--- a/llvm/lib/IR/Constants.cpp
+++ b/llvm/lib/IR/Constants.cpp
@@ -1795,6 +1795,7 @@ Constant *ConstantExpr::getWithOperands(ArrayRef<Constant *> Ops, Type *Ty,
   case Instruction::PtrToInt:
   case Instruction::IntToPtr:
   case Instruction::BitCast:
+  case Instruction::ByteCast:
   case Instruction::AddrSpaceCast:
     return ConstantExpr::getCast(getOpcode(), Ops[0], Ty, OnlyIfReduced);
   case Instruction::InsertElement:
@@ -2478,6 +2479,8 @@ Constant *ConstantExpr::getCast(unsigned oc, Constant *C, Type *Ty,
     return getIntToPtr(C, Ty, OnlyIfReduced);
   case Instruction::BitCast:
     return getBitCast(C, Ty, OnlyIfReduced);
+  case Instruction::ByteCast:
+    return getByteCast(C, Ty, OnlyIfReduced);
   case Instruction::AddrSpaceCast:
     return getAddrSpaceCast(C, Ty, OnlyIfReduced);
   }
@@ -2583,6 +2586,13 @@ Constant *ConstantExpr::getBitCast(Constant *C, Type *DstTy,
   return getFoldedCast(Instruction::BitCast, C, DstTy, OnlyIfReduced);
 }
 
+Constant *ConstantExpr::getByteCast(Constant *C, Type *DstTy,
+                                    bool OnlyIfReduced) {
+  assert(CastInst::castIsValid(Instruction::ByteCast, C, DstTy) &&
+         "Invalid constantexpr bitcast!");
+  return getFoldedCast(Instruction::ByteCast, C, DstTy, OnlyIfReduced);
+}
+
 Constant *ConstantExpr::getAddrSpaceCast(Constant *C, Type *DstTy,
                                          bool OnlyIfReduced) {
   assert(CastInst::castIsValid(Instruction::AddrSpaceCast, C, DstTy) &&
@@ -2702,6 +2712,7 @@ bool ConstantExpr::isDesirableCastOp(unsigned Opcode) {
   case Instruction::PtrToInt:
   case Instruction::IntToPtr:
   case Instruction::BitCast:
+  case Instruction::ByteCast:
   case Instruction::AddrSpaceCast:
     return true;
   default:
@@ -2725,6 +2736,7 @@ bool ConstantExpr::isSupportedCastOp(unsigned Opcode) {
   case Instruction::PtrToInt:
   case Instruction::IntToPtr:
   case Instruction::BitCast:
+  case Instruction::ByteCast:
   case Instruction::AddrSpaceCast:
     return true;
   default:
@@ -3777,6 +3789,7 @@ Instruction *ConstantExpr::getAsInstruction() const {
   case Instruction::PtrToInt:
   case Instruction::IntToPtr:
   case Instruction::BitCast:
+  case Instruction::ByteCast:
   case Instruction::AddrSpaceCast:
     return CastInst::Create((Instruction::CastOps)getOpcode(), Ops[0],
                             getType(), "");
diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp
index 0fd832ac5c99e..d1414469091ed 100644
--- a/llvm/lib/IR/Core.cpp
+++ b/llvm/lib/IR/Core.cpp
@@ -4351,6 +4351,11 @@ LLVMValueRef LLVMBuildAddrSpaceCast(LLVMBuilderRef B, LLVMValueRef Val,
   return wrap(unwrap(B)->CreateAddrSpaceCast(unwrap(Val), unwrap(DestTy), Name));
 }
 
+LLVMValueRef LLVMBuildByteCast(LLVMBuilderRef B, LLVMValueRef Val,
+                               LLVMTypeRef DestTy, const char *Name) {
+  return wrap(unwrap(B)->CreateByteCast(unwrap(Val), unwrap(DestTy), Name));
+}
+
 LLVMValueRef LLVMBuildZExtOrBitCast(LLVMBuilderRef B, LLVMValueRef Val,
                                     LLVMTypeRef DestTy, const char *Name) {
   return wrap(unwrap(B)->CreateZExtOrBitCast(unwrap(Val), unwrap(DestTy),
diff --git a/llvm/lib/IR/Instruction.cpp b/llvm/lib/IR/Instruction.cpp
index 3c35c656dca84..1a88891e2634d 100644
--- a/llvm/lib/IR/Instruction.cpp
+++ b/llvm/lib/IR/Instruction.cpp
@@ -791,6 +791,7 @@ void Instruction::andIRFlags(const Value *V) {
       DestICmp->setSameSign(DestICmp->hasSameSign() && SrcICmp->hasSameSign());
 }
 
+// clang-format off
 const char *Instruction::getOpcodeName(unsigned OpCode) {
   switch (OpCode) {
   // Terminators
@@ -853,6 +854,7 @@ const char *Instruction::getOpcodeName(unsigned OpCode) {
   case PtrToInt:      return "ptrtoint";
   case BitCast:       return "bitcast";
   case AddrSpaceCast: return "addrspacecast";
+  case ByteCast:      return "bytecast";
 
   // Other instructions...
   case ICmp:           return "icmp";
@@ -876,6 +878,7 @@ const char *Instruction::getOpcodeName(unsigned OpCode) {
   default: return "<Invalid operator> ";
   }
 }
+// clang-format on
 
 /// This must be kept in sync with FunctionComparator::cmpOperations in
 /// lib/Transforms/Utils/FunctionComparator.cpp.
diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp
index c57e56cf5c095..b61cf86e6834b 100644
--- a/llvm/lib/IR/Instructions.cpp
+++ b/llvm/lib/IR/Instructions.cpp
@@ -2791,6 +2791,7 @@ bool CastInst::isNoopCast(Instruction::CastOps Opcode,
     case Instruction::SIToFP:
     case Instruction::FPToUI:
     case Instruction::FPToSI:
+    case Instruction::ByteCast:
     case Instruction::AddrSpaceCast:
       // TODO: Target informations may give a more accurate answer here.
       return false;
@@ -2822,7 +2823,7 @@ unsigned CastInst::isEliminableCastPair(Instruction::CastOps firstOp,
                                         Instruction::CastOps secondOp,
                                         Type *SrcTy, Type *MidTy, Type *DstTy,
                                         const DataLayout *DL) {
-  // Define the 144 possibilities for these two cast instructions. The values
+  // Define the 225 possibilities for these two cast instructions. The values
   // in this matrix determine what to do in a given situation and select the
   // case in the switch below.  The rows correspond to firstOp, the columns
   // correspond to secondOp.  In looking at the table below, keep in mind
@@ -2845,6 +2846,7 @@ unsigned CastInst::isEliminableCastPair(Instruction::CastOps firstOp,
   // INTTOPTR     n/a      Integral   Unsigned     Pointer      n/a
   // BITCAST       =       FirstClass   n/a       FirstClass    n/a
   // ADDRSPCST    n/a      Pointer      n/a        Pointer      n/a
+  // BYTECAST      =       Byte       Unsigned    FirstClass    n/a
   //
   // NOTE: some transforms are safe, but we consider them to be non-profitable.
   // For example, we could merge "fptoui double to i32" + "zext i32 to i64",
@@ -2857,25 +2859,26 @@ unsigned CastInst::isEliminableCastPair(Instruction::CastOps firstOp,
     Instruction::CastOpsEnd - Instruction::CastOpsBegin;
   // clang-format off
   static const uint8_t CastResults[numCastOps][numCastOps] = {
-    // T        F  F  U  S  F  F  P  P  I  B  A  -+
-    // R  Z  S  P  P  I  I  T  P  2  2  N  T  S   |
-    // U  E  E  2  2  2  2  R  E  I  A  T  C  C   +- secondOp
-    // N  X  X  U  S  F  F  N  X  N  D  2  V  V   |
-    // C  T  T  I  I  P  P  C  T  T  R  P  T  T  -+
-    {  1, 0, 0,99,99, 0, 0,99,99,99,99, 0, 3, 0}, // Trunc         -+
-    {  8, 1, 9,99,99, 2,17,99,99,99,99, 2, 3, 0}, // ZExt           |
-    {  8, 0, 1,99,99, 0, 2,99,99,99,99, 0, 3, 0}, // SExt           |
-    {  0, 0, 0,99,99, 0, 0,99,99,99,99, 0, 3, 0}, // FPToUI         |
-    {  0, 0, 0,99,99, 0, 0,99,99,99,99, 0, 3, 0}, // FPToSI         |
-    { 99,99,99, 0, 0,99,99, 0, 0,99,99,99, 4, 0}, // UIToFP         +- firstOp
-    { 99,99,99, 0, 0,99,99, 0, 0,99,99,99, 4, 0}, // SIToFP         |
-    { 99,99,99, 0, 0,99,99, 0, 0,99,99,99, 4, 0}, // FPTrunc        |
-    { 99,99,99, 2, 2,99,99, 8, 2,99,99,99, 4, 0}, // FPExt          |
-    {  1, 0, 0,99,99, 0, 0,99,99,99,99, 7, 3, 0}, // PtrToInt       |
-    {  0, 0, 0,99,99, 0, 0,99,99,99,99, 0, 3, 0}, // PtrToAddr      |
-    { 99,99,99,99,99,99,99,99,99,11,11,99,15, 0}, // IntToPtr       |
-    {  5, 5, 5, 0, 0, 5, 5, 0, 0,16,16, 5, 1,14}, // BitCast        |
-    {  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,13,12}, // AddrSpaceCast -+
+    // T        F  F  U  S  F  F  P  P  I  B  A  B -+
+    // R  Z  S  P  P  I  I  T  P  2  2  N  T  S  Y  |
+    // U  E  E  2  2  2  2  R  E  I  A  T  C  C  T  +- secondOp
+    // N  X  X  U  S  F  F  N  X  N  D  2  V  V  C  |
+    // C  T  T  I  I  P  P  C  T  T  R  P  T  T  T -+
+    {  1, 0, 0,99,99, 0, 0,99,99,99,99, 0, 3, 0, 0}, // Trunc         -+
+    {  8, 1, 9,99,99, 2,17,99,99,99,99, 2, 3, 0, 0}, // ZExt           |
+    {  8, 0, 1,99,99, 0, 2,99,99,99,99, 0, 3, 0, 0}, // SExt           |
+    {  0, 0, 0,99,99, 0, 0,99,99,99,99, 0, 3, 0, 0}, // FPToUI         |
+    {  0, 0, 0,99,99, 0, 0,99,99,99,99, 0, 3, 0, 0}, // FPToSI         |
+    { 99,99,99, 0, 0,99,99, 0, 0,99,99,99, 4, 0, 0}, // UIToFP         +- firstOp
+    { 99,99,99, 0, 0,99,99, 0, 0,99,99,99, 4, 0, 0}, // SIToFP         |
+    { 99,99,99, 0, 0,99,99, 0, 0,99,99,99, 4, 0, 0}, // FPTrunc        |
+    { 99,99,99, 2, 2,99,99, 8, 2,99,99,99, 4, 0, 0}, // FPExt          |
+    {  1, 0, 0,99,99, 0, 0,99,99,99,99, 7, 3, 0, 0}, // PtrToInt       |
+    {  0, 0, 0,99,99, 0, 0,99,99,99,99, 0, 3, 0, 0}, // PtrToAddr      |
+    { 99,99,99,99,99,99,99,99,99,11,11,99,15, 0, 0}, // IntToPtr       |
+    {  5, 5, 5, 0, 0, 5, 5, 0, 0,16,16, 5, 1,14, 0}, // BitCast        |
+    {  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,13,12, 0}, // AddrSpaceCast -+
+    {  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,99}, // ByteCast -+
   };
   // clang-format on
 
@@ -3056,6 +3059,8 @@ CastInst *CastInst::Create(Instruction::CastOps op, Value *S, Type *Ty,
     return new BitCastInst(S, Ty, Name, InsertBefore);
   case AddrSpaceCast:
     return new AddrSpaceCastInst(S, Ty, Name, InsertBefore);
+  case ByteCast:
+    return new ByteCastInst(S, Ty, Name, InsertBefore);
   default:
     llvm_unreachable("Invalid opcode provided");
   }
@@ -3249,8 +3254,12 @@ CastInst::getCastOpcode(
       return BitCast;
     }
     llvm_unreachable("Illegal cast to byte type");
-  } else if (DestTy->isIntegerTy()) {               // Casting to integral
-    if (SrcTy->isIntegerTy()) {                     // Casting from integral
+  } else if (DestTy->isIntegerTy()) {
+    if (SrcTy->isByteTy()) { // Casting from byte
+      assert(DestBits == SrcBits &&
+             "Casting byte to integer of different width");
+      return ByteCast;
+    } else if (SrcTy->isIntegerTy()) { // Casting from integral
       if (DestBits < SrcBits)
         return Trunc;                               // int -> smaller int
       else if (DestBits > SrcBits) {                // its an extension
@@ -3261,7 +3270,7 @@ CastInst::getCastOpcode(
       } else {
         return BitCast;                             // Same size, No-op cast
       }
-    } else if (SrcTy->isFloatingPointTy()) {        // Casting from floating pt
+    } else if (SrcTy->isFloatingPointTy()) { // Casting from floating pt
       if (DestIsSigned)
         return FPToSI;                              // FP -> sint
       else
@@ -3289,12 +3298,16 @@ CastInst::getCastOpcode(
       } else  {
         return BitCast;                             // same size, no-op cast
       }
+    } else if (SrcTy->isByteTy()) {
+      assert(DestBits == SrcBits &&
+             "Casting byte to floating point of different width");
+      return ByteCast;
     } else if (SrcTy->isVectorTy()) {
       assert(DestBits == SrcBits &&
              "Casting vector to floating point of different width");
       return BitCast;                             // same size, no-op cast
     }
-    llvm_unreachable("Casting pointer or non-first class to float");
+    llvm_unreachable("Casting pointer or non-first class to float or byte");
   } else if (DestTy->isVectorTy()) {
     assert(DestBits == SrcBits &&
            "Illegal cast to vector (wrong type or size)");
@@ -3306,8 +3319,11 @@ CastInst::getCastOpcode(
       return BitCast;                               // ptr -> ptr
     } else if (SrcTy->isIntegerTy()) {
       return IntToPtr;                              // int -> ptr
+    } else if (SrcTy->isByteTy()) {
+      assert(SrcBits <= 64 && "Casting byte to pointer of greater width");
+      return ByteCast; // byte -> ptr
     }
-    llvm_unreachable("Casting pointer to other than pointer or int");
+    llvm_unreachable("Casting pointer to other than pointer, int or byte");
   }
   llvm_unreachable("Casting to type that is not first-class");
 }
@@ -3414,6 +3430,18 @@ CastInst::castIsValid(Instruction::CastOps op, Type *SrcTy, Type *DstTy) {
 
     return true;
   }
+  case Instruction::ByteCast: {
+    if (!SrcTy->isByteOrByteVectorTy())
+      return false;
+    if (DstTy->isByteOrByteVectorTy())
+      return false;
+
+    PointerType *DstPtrTy = dyn_cast<PointerType>(DstTy->getScalarType());
+    if (!DstPtrTy)
+      return SrcTy->getPrimitiveSizeInBits() == DstTy->getPrimitiveSizeInBits();
+
+    return true;
+  }
   case Instruction::AddrSpaceCast: {
     PointerType *SrcPtrTy = dyn_cast<PointerType>(SrcTy->getScalarType());
     if (!SrcPtrTy)
@@ -3515,6 +3543,12 @@ AddrSpaceCastInst::AddrSpaceCastInst(Value *S, Type *Ty, const Twine &Name,
   assert(castIsValid(getOpcode(), S, Ty) && "Illegal AddrSpaceCast");
 }
 
+ByteCastInst::ByteCastInst(Value *S, Type *Ty, const Twine &Name,
+                           InsertPosition InsertBefore)
+    : CastInst(Ty, ByteCast, S, Name, InsertBefore) {
+  assert(castIsValid(getOpcode(), S, Ty) && "Illegal ByteCast");
+}
+
 //===----------------------------------------------------------------------===//
 //                               CmpInst Classes
 //===----------------------------------------------------------------------===//
@@ -4476,6 +4510,10 @@ AddrSpaceCastInst *AddrSpaceCastInst::cloneImpl() const {
   return new AddrSpaceCastInst(getOperand(0), getType());
 }
 
+ByteCastInst *ByteCastInst::cloneImpl() const {
+  return new ByteCastInst(getOperand(0), getType());
+}
+
 CallInst *CallInst::cloneImpl() const {
   if (hasOperandBundles()) {
     IntrusiveOperandsAndDescriptorAllocMarker AllocMarker{
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index a9962aed295b0..a7f1dd006768e 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -579,6 +579,7 @@ class Verifier : public InstVisitor<Verifier>, VerifierSupport {
   void visitPtrToIntInst(PtrToIntInst &I);
   void visitBitCastInst(BitCastInst &I);
   void visitAddrSpaceCastInst(AddrSpaceCastInst &I);
+  void visitByteCastInst(ByteCastInst &I);
   void visitPHINode(PHINode &PN);
   void visitCallBase(CallBase &Call);
   void visitUnaryOperator(UnaryOperator &U);
@@ -3811,6 +3812,13 @@ void Verifier::visitAddrSpaceCastInst(AddrSpaceCastInst &I) {
   visitInstruction(I);
 }
 
+void Verifier::visitByteCastInst(ByteCastInst &I) {
+  Check(CastInst::castIsValid(Instruction::ByteCast, I.getOperand(0),
+                              I.getType()),
+        "Invalid bytecast", &I);
+  visitInstruction(I);
+}
+
 /// visitPHINode - Ensure that a PHI node is well formed.
 ///
 void Verifier::visitPHINode(PHINode &PN) {
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 12d1567466b1b..cec613f2a5c5c 100644
--- a/llvm/test/Analysis/IR2Vec/Inputs/reference_default_vocab_print.txt
+++ b/llvm/test/Analysis/IR2Vec/Inputs/reference_default_vocab_print.txt
@@ -49,6 +49,7 @@ Key: PtrToAddr:  [ 135.00  136.00 ]
 Key: IntToPtr:  [ 95.00  96.00 ]
 Key: BitCast:  [ 97.00  98.00 ]
 Key: AddrSpaceCast:  [ 99.00  100.00 ]
+Key: ByteCast:  [ 0.00  0.00 ]
 Key: CleanupPad:  [ 101.00  102.00 ]
 Key: CatchPad:  [ 103.00  104.00 ]
 Key: ICmp:  [ 105.00  106.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 cb775622dc722..c49a11caa3fa0 100644
--- a/llvm/test/Analysis/IR2Vec/Inputs/reference_wtd1_vocab_print.txt
+++ b/llvm/test/Analysis/IR2Vec/Inputs/reference_wtd1_vocab_print.txt
@@ -49,6 +49,7 @@ Key: PtrToAddr:  [ 67.50  68.00 ]
 Key: IntToPtr:  [ 47.50  48.00 ]
 Key: BitCast:  [ 48.50  49.00 ]
 Key: AddrSpaceCast:  [ 49.50  50.00 ]
+Key: ByteCast:  [ 0.00  0.00 ]
 Key: CleanupPad:  [ 50.50  51.00 ]
 Key: CatchPad:  [ 51.50  52.00 ]
 Key: ICmp:  [ 52.50  53.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 cafc8eb1b7e23..632f1440dde61 100644
--- a/llvm/test/Analysis/IR2Vec/Inputs/reference_wtd2_vocab_print.txt
+++ b/llvm/test/Analysis/IR2Vec/Inputs/reference_wtd2_vocab_print.txt
@@ -49,6 +49,7 @@ Key: PtrToAddr:  [ 13.50  13.60 ]
 Key: IntToPtr:  [ 9.50  9.60 ]
 Key: BitCast:  [ 9.70  9.80 ]
 Key: AddrSpaceCast:  [ 9.90  10.00 ]
+Key: ByteCast:  [ 0.00  0.00 ]
 Key: CleanupPad:  [ 10.10  10.20 ]
 Key: CatchPad:  [ 10.30  10.40 ]
 Key: ICmp:  [ 10.50  10.60 ]
diff --git a/llvm/test/Assembler/byte-invalid-cast-10.ll b/llvm/test/Assembler/byte-invalid-cast-10.ll
new file mode 100644
index 0000000000000..9daadb4eed49e
--- /dev/null
+++ b/llvm/test/Assembler/byte-invalid-cast-10.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 'b8'
+define void @invalid_bytcast(b8 %b) {
+  %t = bytecast b8 %b to b8
+  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..904fa3de2a9f5
--- /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 cast opcode for cast from 'i8' to 'b8'
+define void @invalid_bytcast(i8 %b) {
+  %t = bytecast i8 %b to b8
+  ret void
+}
diff --git a/llvm/test/Assembler/byte-invalid-cast-9.ll b/llvm/test/Assembler/byte-invalid-cast-9.ll
new file mode 100644
index 0000000000000..cbe36638884ba
--- /dev/null
+++ b/llvm/test/Assembler/byte-invalid-cast-9.ll
@@ -0,0 +1,7 @@
+; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s
+
+; CHECK: invalid cast opcode for cast from '<4 x b32>' to '<6 x i16>'
+define void @invalid_bytcast(<4 x b32> %b) {
+  %t = bytecast <4 x b32> %b to <6 x i16>
+  ret void
+}
diff --git a/llvm/test/Assembler/byte.ll b/llvm/test/Assembler/byte.ll
index d62d6cd9b5fc3..671d2ca0ecb8c 100644
--- a/llvm/test/Assembler/byte.ll
+++ b/llvm/test/Assembler/byte.ll
@@ -77,3 +77,51 @@ define void @bitcasts(i64 %i, b64 %b, ptr %p) {
   %6 = bitcast <2 x b32> <b32 1, b32 1> to b64
   ret void
 }
+
+define void @bytecasts(b8 %b1, b16 %b2, b32 %b3, b64 %b4, b128 %b5) {
+; CHECK-LABEL: define void @bytecasts(
+; CHECK-SAME: b8 [[B1:%.*]], b16 [[B2:%.*]], b32 [[B3:%.*]], b64 [[B4:%.*]], b128 [[B5:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = bytecast b8 [[B1]] to i8
+; CHECK-NEXT:    [[TMP2:%.*]] = bytecast b16 [[B2]] to i16
+; CHECK-NEXT:    [[TMP3:%.*]] = bytecast b32 [[B3]] to i32
+; CHECK-NEXT:    [[TMP4:%.*]] = bytecast b64 [[B4]] to i64
+; CHECK-NEXT:    [[TMP5:%.*]] = bytecast b64 [[B4]] to ptr
+; CHECK-NEXT:    [[TMP6:%.*]] = bytecast b16 [[B2]] to half
+; CHECK-NEXT:    [[TMP7:%.*]] = bytecast b32 [[B3]] to float
+; CHECK-NEXT:    [[TMP8:%.*]] = bytecast b64 [[B4]] to double
+; CHECK-NEXT:    ret void
+;
+  %1 = bytecast b8 %b1 to i8
+  %2 = bytecast b16 %b2 to i16
+  %3 = bytecast b32 %b3 to i32
+  %4 = bytecast b64 %b4 to i64
+  %5 = bytecast b64 %b4 to ptr
+  %6 = bytecast b16 %b2 to half
+  %7 = bytecast b32 %b3 to float
+  %8 = bytecast b64 %b4 to double
+  ret void
+}
+
+define void @vector_bytecasts(<2 x b64> %b1, <2 x b128> %b2, b64 %b3) {
+; CHECK-LABEL: define void @vector_bytecasts(
+; CHECK-SAME: <2 x b64> [[B1:%.*]], <2 x b128> [[B2:%.*]], b64 [[B3:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = bytecast <2 x b64> [[B1]] to <2 x i64>
+; CHECK-NEXT:    [[TMP2:%.*]] = bytecast <2 x b64> [[B1]] to <2 x double>
+; CHECK-NEXT:    [[TMP3:%.*]] = bytecast <2 x b64> [[B1]] to <2 x ptr>
+; CHECK-NEXT:    [[TMP4:%.*]] = bytecast b64 [[B3]] to <2 x i32>
+; CHECK-NEXT:    [[TMP5:%.*]] = bytecast b64 [[B3]] to <1 x ptr>
+; CHECK-NEXT:    [[TMP6:%.*]] = bytecast <2 x b64> [[B1]] to i128
+; CHECK-NEXT:    [[TMP7:%.*]] = bytecast <2 x b64> [[B1]] to <4 x i32>
+; CHECK-NEXT:    [[TMP8:%.*]] = bytecast <2 x b128> [[B2]] to <4 x ptr>
+; CHECK-NEXT:    ret void
+;
+  %1 = bytecast <2 x b64> %b1 to <2 x i64>
+  %2 = bytecast <2 x b64> %b1 to <2 x double>
+  %3 = bytecast <2 x b64> %b1 to <2 x ptr>
+  %4 = bytecast b64 %b3 to <2 x i32>
+  %5 = bytecast b64 %b3 to <1 x ptr>
+  %6 = bytecast <2 x b64> %b1 to i128
+  %7 = bytecast <2 x b64> %b1 to <4 x i32>
+  %8 = bytecast <2 x b128> %b2 to <4 x ptr>
+  ret void
+}
diff --git a/llvm/test/Bindings/llvm-c/byte.ll b/llvm/test/Bindings/llvm-c/byte.ll
index 93b9819c3c9b9..ac7217fb0ab54 100644
--- a/llvm/test/Bindings/llvm-c/byte.ll
+++ b/llvm/test/Bindings/llvm-c/byte.ll
@@ -7,5 +7,6 @@ define void @foo(b8 %a, b16 %b, b64 %c) {
   store b16 %b, ptr %1, align 2
   %2 = load b16, ptr %1, align 2
   %3 = bitcast b16 %2 to <2 x b8>
+  %4 = bytecast <2 x b8> %3 to <2 x i8>
   ret void
 }
diff --git a/llvm/test/Bitcode/compatibility.ll b/llvm/test/Bitcode/compatibility.ll
index 1510d6275c56f..0a93de3a3e81a 100644
--- a/llvm/test/Bitcode/compatibility.ll
+++ b/llvm/test/Bitcode/compatibility.ll
@@ -1646,6 +1646,10 @@ define void @instructions.conversions() {
   ; CHECK: bitcast i32 0 to i32
   addrspacecast ptr null to ptr addrspace(1)
   ; CHECK: addrspacecast ptr null to ptr addrspace(1)
+  %im = bitcast i32 0 to b32
+  ; CHECK: bitcast i32 0 to b32
+  bytecast b32 %im to i32
+  ; CHECK: bytecast b32 %{{.*}} to i32
 
   ret void
 }
diff --git a/llvm/test/Transforms/IRNormalizer/regression-convergence-tokens.ll b/llvm/test/Transforms/IRNormalizer/regression-convergence-tokens.ll
index 0c2db4a2862b2..2db29cdc1db2a 100644
--- a/llvm/test/Transforms/IRNormalizer/regression-convergence-tokens.ll
+++ b/llvm/test/Transforms/IRNormalizer/regression-convergence-tokens.ll
@@ -7,9 +7,9 @@ define i32 @nested(i32 %src) #0 {
 ; CHECK-SAME: i32 [[A0:%.*]]) #[[ATTR0:[0-9]+]] {
 ; CHECK-NEXT:  [[BB15160:.*:]]
 ; CHECK-NEXT:    [[T1:%.*]] = call token @llvm.experimental.convergence.entry()
-; CHECK-NEXT:    %"vl14659llvm.experimental.convergence.anchor()" = call token @llvm.experimental.convergence.anchor()
-; CHECK-NEXT:    %"op15516(vl14659)" = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[A0]]) [ "convergencectrl"(token %"vl14659llvm.experimental.convergence.anchor()") ]
-; CHECK-NEXT:    ret i32 %"op15516(vl14659)"
+; CHECK-NEXT:    %"vl55087llvm.experimental.convergence.anchor()" = call token @llvm.experimental.convergence.anchor()
+; CHECK-NEXT:    %"op11958(vl55087)" = call i32 @llvm.amdgcn.readfirstlane.i32(i32 [[A0]]) [ "convergencectrl"(token %"vl55087llvm.experimental.convergence.anchor()") ]
+; CHECK-NEXT:    ret i32 %"op11958(vl55087)"
 ;
   %t1 = call token @llvm.experimental.convergence.entry()
   %t2 = call token @llvm.experimental.convergence.anchor()
diff --git a/llvm/test/Transforms/IRNormalizer/regression-infinite-loop.ll b/llvm/test/Transforms/IRNormalizer/regression-infinite-loop.ll
index b9be105bcda48..686fc46e6db2b 100644
--- a/llvm/test/Transforms/IRNormalizer/regression-infinite-loop.ll
+++ b/llvm/test/Transforms/IRNormalizer/regression-infinite-loop.ll
@@ -8,18 +8,18 @@ define void @test(ptr, i32) {
 ; CHECK-NEXT:    %"vl72693([[A1]], 1)" = add i32 [[A1]], 1
 ; CHECK-NEXT:    br label %[[BB16110:.*]]
 ; CHECK:       [[BB16110]]:
-; CHECK-NEXT:    %"op81283(op18080, vl72693)" = phi i32 [ %"op18080(op10412, op18131)", %[[BB16110]] ], [ %"vl72693([[A1]], 1)", %[[BB76951]] ]
-; CHECK-NEXT:    %"op81283(op18131, vl72693)" = phi i32 [ %"op18131(op81283)70", %[[BB16110]] ], [ %"vl72693([[A1]], 1)", %[[BB76951]] ]
-; CHECK-NEXT:    %"op13219(op81283)" = mul i32 %"op81283(op18080, vl72693)", undef
-; CHECK-NEXT:    %"op16562(op13219)" = xor i32 -1, %"op13219(op81283)"
-; CHECK-NEXT:    %"op12556(op16562, op81283)" = add i32 %"op16562(op13219)", %"op81283(op18080, vl72693)"
-; CHECK-NEXT:    %"op18131(op81283)" = add i32 -1, %"op81283(op18131, vl72693)"
-; CHECK-NEXT:    %"op18080(op12556, op18131)" = add i32 %"op12556(op16562, op81283)", %"op18131(op81283)"
-; CHECK-NEXT:    %"op17720(op13219, op18080)" = mul i32 %"op13219(op81283)", %"op18080(op12556, op18131)"
-; CHECK-NEXT:    %"op16562(op17720)" = xor i32 -1, %"op17720(op13219, op18080)"
-; CHECK-NEXT:    %"op17430(op16562, op18080)" = add i32 %"op16562(op17720)", %"op18080(op12556, op18131)"
+; CHECK-NEXT:    %"op26813(op18080, vl72693)" = phi i32 [ %"op18080(op10412, op11773)", %[[BB16110]] ], [ %"vl72693([[A1]], 1)", %[[BB76951]] ]
+; CHECK-NEXT:    %"op26813(op11773, vl72693)" = phi i32 [ %"op11773(op26813)70", %[[BB16110]] ], [ %"vl72693([[A1]], 1)", %[[BB76951]] ]
+; CHECK-NEXT:    %"op71272(op26813)" = mul i32 %"op26813(op18080, vl72693)", undef
+; CHECK-NEXT:    %"op16562(op71272)" = xor i32 -1, %"op71272(op26813)"
+; CHECK-NEXT:    %"op75661(op16562, op26813)" = add i32 %"op16562(op71272)", %"op26813(op18080, vl72693)"
+; CHECK-NEXT:    %"op11773(op26813)" = add i32 -1, %"op26813(op11773, vl72693)"
+; CHECK-NEXT:    %"op18080(op11773, op75661)" = add i32 %"op11773(op26813)", %"op75661(op16562, op26813)"
+; CHECK-NEXT:    %"op17720(op18080, op71272)" = mul i32 %"op18080(op11773, op75661)", %"op71272(op26813)"
+; CHECK-NEXT:    %"op16562(op17720)" = xor i32 -1, %"op17720(op18080, op71272)"
+; CHECK-NEXT:    %"op17430(op16562, op18080)" = add i32 %"op16562(op17720)", %"op18080(op11773, op75661)"
 ; CHECK-NEXT:    %"op10412(op17430)" = add i32 %"op17430(op16562, op18080)", undef
-; CHECK-NEXT:    %"op17720(op10412, op17720)" = mul i32 %"op10412(op17430)", %"op17720(op13219, op18080)"
+; CHECK-NEXT:    %"op17720(op10412, op17720)" = mul i32 %"op10412(op17430)", %"op17720(op18080, op71272)"
 ; CHECK-NEXT:    %"op16562(op17720)1" = xor i32 -1, %"op17720(op10412, op17720)"
 ; CHECK-NEXT:    %"op17430(op10412, op16562)" = add i32 %"op10412(op17430)", %"op16562(op17720)1"
 ; CHECK-NEXT:    %"op10412(op17430)2" = add i32 %"op17430(op10412, op16562)", undef
@@ -45,11 +45,11 @@ define void @test(ptr, i32) {
 ; CHECK-NEXT:    %"op17720(op10412, op17720)21" = mul i32 %"op10412(op17430)20", %"op17720(op10412, op17720)17"
 ; CHECK-NEXT:    %"op16562(op17720)22" = xor i32 -1, %"op17720(op10412, op17720)21"
 ; CHECK-NEXT:    %"op17430(op10412, op16562)23" = add i32 %"op10412(op17430)20", %"op16562(op17720)22"
-; CHECK-NEXT:    %"op18131(op81283)24" = add i32 -9, %"op81283(op18131, vl72693)"
-; CHECK-NEXT:    %"op18080(op17430, op18131)" = add i32 %"op17430(op10412, op16562)23", %"op18131(op81283)24"
-; CHECK-NEXT:    %"op17720(op17720, op18080)" = mul i32 %"op17720(op10412, op17720)21", %"op18080(op17430, op18131)"
+; CHECK-NEXT:    %"op11773(op26813)24" = add i32 -9, %"op26813(op11773, vl72693)"
+; CHECK-NEXT:    %"op18080(op11773, op17430)" = add i32 %"op11773(op26813)24", %"op17430(op10412, op16562)23"
+; CHECK-NEXT:    %"op17720(op17720, op18080)" = mul i32 %"op17720(op10412, op17720)21", %"op18080(op11773, op17430)"
 ; CHECK-NEXT:    %"op16562(op17720)25" = xor i32 -1, %"op17720(op17720, op18080)"
-; CHECK-NEXT:    %"op17430(op16562, op18080)26" = add i32 %"op16562(op17720)25", %"op18080(op17430, op18131)"
+; CHECK-NEXT:    %"op17430(op16562, op18080)26" = add i32 %"op16562(op17720)25", %"op18080(op11773, op17430)"
 ; CHECK-NEXT:    %"op10412(op17430)27" = add i32 %"op17430(op16562, op18080)26", undef
 ; CHECK-NEXT:    %"op17720(op10412, op17720)28" = mul i32 %"op10412(op17430)27", %"op17720(op17720, op18080)"
 ; CHECK-NEXT:    %"op16562(op17720)29" = xor i32 -1, %"op17720(op10412, op17720)28"
@@ -66,11 +66,11 @@ define void @test(ptr, i32) {
 ; CHECK-NEXT:    %"op17720(op10412, op17720)40" = mul i32 %"op10412(op17430)39", %"op17720(op10412, op17720)36"
 ; CHECK-NEXT:    %"op16562(op17720)41" = xor i32 -1, %"op17720(op10412, op17720)40"
 ; CHECK-NEXT:    %"op17430(op10412, op16562)42" = add i32 %"op10412(op17430)39", %"op16562(op17720)41"
-; CHECK-NEXT:    %"op18131(op81283)43" = add i32 -14, %"op81283(op18131, vl72693)"
-; CHECK-NEXT:    %"op18080(op17430, op18131)44" = add i32 %"op17430(op10412, op16562)42", %"op18131(op81283)43"
-; CHECK-NEXT:    %"op17720(op17720, op18080)45" = mul i32 %"op17720(op10412, op17720)40", %"op18080(op17430, op18131)44"
+; CHECK-NEXT:    %"op11773(op26813)43" = add i32 -14, %"op26813(op11773, vl72693)"
+; CHECK-NEXT:    %"op18080(op11773, op17430)44" = add i32 %"op11773(op26813)43", %"op17430(op10412, op16562)42"
+; CHECK-NEXT:    %"op17720(op17720, op18080)45" = mul i32 %"op17720(op10412, op17720)40", %"op18080(op11773, op17430)44"
 ; CHECK-NEXT:    %"op16562(op17720)46" = xor i32 -1, %"op17720(op17720, op18080)45"
-; CHECK-NEXT:    %"op17430(op16562, op18080)47" = add i32 %"op16562(op17720)46", %"op18080(op17430, op18131)44"
+; CHECK-NEXT:    %"op17430(op16562, op18080)47" = add i32 %"op16562(op17720)46", %"op18080(op11773, op17430)44"
 ; CHECK-NEXT:    %"op10412(op17430)48" = add i32 %"op17430(op16562, op18080)47", undef
 ; CHECK-NEXT:    %"op17720(op10412, op17720)49" = mul i32 %"op10412(op17430)48", %"op17720(op17720, op18080)45"
 ; CHECK-NEXT:    %"op16562(op17720)50" = xor i32 -1, %"op17720(op10412, op17720)49"
@@ -93,9 +93,9 @@ define void @test(ptr, i32) {
 ; CHECK-NEXT:    %"op17430(op10412, op16562)67" = add i32 %"op10412(op17430)64", %"op16562(op17720)66"
 ; CHECK-NEXT:    %"op10412(op17430)68" = add i32 %"op17430(op10412, op16562)67", undef
 ; CHECK-NEXT:    %"op10412(op10412)69" = add i32 %"op10412(op17430)68", undef
-; CHECK-NEXT:    %"op18131(op81283)70" = add i32 -21, %"op81283(op18131, vl72693)"
-; CHECK-NEXT:    %"op18080(op10412, op18131)" = add i32 %"op10412(op10412)69", %"op18131(op81283)70"
-; CHECK-NEXT:    store i32 %"op18080(op10412, op18131)", ptr [[A0]], align 4
+; CHECK-NEXT:    %"op11773(op26813)70" = add i32 -21, %"op26813(op11773, vl72693)"
+; CHECK-NEXT:    %"op18080(op10412, op11773)" = add i32 %"op10412(op10412)69", %"op11773(op26813)70"
+; CHECK-NEXT:    store i32 %"op18080(op10412, op11773)", ptr [[A0]], align 4
 ; CHECK-NEXT:    br label %[[BB16110]]
 ;
 bb:
diff --git a/llvm/test/Transforms/IRNormalizer/reordering-basic.ll b/llvm/test/Transforms/IRNormalizer/reordering-basic.ll
index 06e67e0feb7e4..87cd59f5c8c70 100644
--- a/llvm/test/Transforms/IRNormalizer/reordering-basic.ll
+++ b/llvm/test/Transforms/IRNormalizer/reordering-basic.ll
@@ -28,16 +28,16 @@ define double @baz(double %x) {
 ; CHECK-SAME: double [[A0:%.*]]) {
 ; CHECK-NEXT:  [[BB76951:.*:]]
 ; CHECK-NEXT:    [[IFCOND:%.*]] = fcmp one double [[A0]], 0.000000e+00
-; CHECK-NEXT:    br i1 [[IFCOND]], label %[[BB47054:.*]], label %[[BB470541:.*]]
-; CHECK:       [[BB47054]]:
-; CHECK-NEXT:    %"vl16994bir()" = call double @bir()
+; CHECK-NEXT:    br i1 [[IFCOND]], label %[[BB57091:.*]], label %[[BB570911:.*]]
+; CHECK:       [[BB57091]]:
+; CHECK-NEXT:    %"vl12417bir()" = call double @bir()
 ; CHECK-NEXT:    br label %[[BB17254:.*]]
-; CHECK:       [[BB470541]]:
-; CHECK-NEXT:    %"vl88592bar()" = call double @bar()
+; CHECK:       [[BB570911]]:
+; CHECK-NEXT:    %"vl26594bar()" = call double @bar()
 ; CHECK-NEXT:    br label %[[BB17254]]
 ; CHECK:       [[BB17254]]:
-; CHECK-NEXT:    %"op16411(vl16994, vl88592)" = phi double [ %"vl16994bir()", %[[BB47054]] ], [ %"vl88592bar()", %[[BB470541]] ]
-; CHECK-NEXT:    ret double %"op16411(vl16994, vl88592)"
+; CHECK-NEXT:    %"op24395(vl12417, vl26594)" = phi double [ %"vl12417bir()", %[[BB57091]] ], [ %"vl26594bar()", %[[BB570911]] ]
+; CHECK-NEXT:    ret double %"op24395(vl12417, vl26594)"
 ;
 entry:
   %ifcond = fcmp one double %x, 0.000000e+00
diff --git a/llvm/test/Transforms/IRNormalizer/reordering.ll b/llvm/test/Transforms/IRNormalizer/reordering.ll
index a3dbcb5494875..80ab28db62ba0 100644
--- a/llvm/test/Transforms/IRNormalizer/reordering.ll
+++ b/llvm/test/Transforms/IRNormalizer/reordering.ll
@@ -23,7 +23,7 @@ declare void @effecting()
 ; Place dead instruction(s) before the terminator
 define void @call_effecting() {
 ; CHECK-LABEL: define void @call_effecting() {
-; CHECK-NEXT:  bb14885:
+; CHECK-NEXT:  bb72598:
 ; CHECK-NEXT:    call void @effecting()
 ; CHECK-NEXT:    [[TMP0:%.*]] = add i32 0, 1
 ; CHECK-NEXT:    ret void
@@ -51,7 +51,7 @@ exit:
 
 define void @dont_move_above_alloca() {
 ; CHECK-LABEL: define void @dont_move_above_alloca() {
-; CHECK-NEXT:  bb14885:
+; CHECK-NEXT:  bb72598:
 ; CHECK-NEXT:    [[TMP0:%.*]] = alloca i32, align 4
 ; CHECK-NEXT:    call void @effecting()
 ; CHECK-NEXT:    ret void
@@ -65,7 +65,7 @@ declare void @effecting1()
 
 define void @dont_reorder_effecting() {
 ; CHECK-LABEL: define void @dont_reorder_effecting() {
-; CHECK-NEXT:  bb45003:
+; CHECK-NEXT:  bb86996:
 ; CHECK-NEXT:    call void @effecting()
 ; CHECK-NEXT:    call void @effecting1()
 ; CHECK-NEXT:    ret void
@@ -79,7 +79,7 @@ declare void @effecting2(i32)
 
 define void @dont_reorder_effecting1() {
 ; CHECK-LABEL: define void @dont_reorder_effecting1() {
-; CHECK-NEXT:  bb45003:
+; CHECK-NEXT:  bb86996:
 ; CHECK-NEXT:    [[ONE:%.*]] = add i32 1, 1
 ; CHECK-NEXT:    call void @effecting2(i32 [[ONE]])
 ; CHECK-NEXT:    [[TWO:%.*]] = add i32 2, 2
diff --git a/llvm/test/tools/llvm-ir2vec/entities.ll b/llvm/test/tools/llvm-ir2vec/entities.ll
index 58c2d74036783..c2d416a1f8b7c 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: 111
+CHECK: 112
 CHECK-NEXT: Ret     0
 CHECK-NEXT: Br      1
 CHECK-NEXT: Switch  2
@@ -52,63 +52,64 @@ CHECK-NEXT: PtrToAddr	47
 CHECK-NEXT: IntToPtr        48
 CHECK-NEXT: BitCast 49
 CHECK-NEXT: AddrSpaceCast   50
-CHECK-NEXT: CleanupPad      51
-CHECK-NEXT: CatchPad        52
-CHECK-NEXT: ICmp    53
-CHECK-NEXT: FCmp    54
-CHECK-NEXT: PHI     55
-CHECK-NEXT: Call    56
-CHECK-NEXT: Select  57
-CHECK-NEXT: UserOp1 58
-CHECK-NEXT: UserOp2 59
-CHECK-NEXT: VAArg   60
-CHECK-NEXT: ExtractElement  61
-CHECK-NEXT: InsertElement   62
-CHECK-NEXT: ShuffleVector   63
-CHECK-NEXT: ExtractValue    64
-CHECK-NEXT: InsertValue     65
-CHECK-NEXT: LandingPad      66
-CHECK-NEXT: Freeze  67
-CHECK-NEXT: FloatTy 68
-CHECK-NEXT: VoidTy  69
-CHECK-NEXT: LabelTy 70
-CHECK-NEXT: MetadataTy      71
-CHECK-NEXT: VectorTy        72
-CHECK-NEXT: TokenTy 73
-CHECK-NEXT: IntegerTy       74
-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
+CHECK-NEXT: ByteCast        51
+CHECK-NEXT: CleanupPad      52
+CHECK-NEXT: CatchPad        53
+CHECK-NEXT: ICmp    54
+CHECK-NEXT: FCmp    55
+CHECK-NEXT: PHI     56
+CHECK-NEXT: Call    57
+CHECK-NEXT: Select  58
+CHECK-NEXT: UserOp1 59
+CHECK-NEXT: UserOp2 60
+CHECK-NEXT: VAArg   61
+CHECK-NEXT: ExtractElement  62
+CHECK-NEXT: InsertElement   63
+CHECK-NEXT: ShuffleVector   64
+CHECK-NEXT: ExtractValue    65
+CHECK-NEXT: InsertValue     66
+CHECK-NEXT: LandingPad      67
+CHECK-NEXT: Freeze  68
+CHECK-NEXT: FloatTy 69
+CHECK-NEXT: VoidTy  70
+CHECK-NEXT: LabelTy 71
+CHECK-NEXT: MetadataTy      72
+CHECK-NEXT: VectorTy        73
+CHECK-NEXT: TokenTy 74
+CHECK-NEXT: IntegerTy       75
+CHECK-NEXT: ByteTy  76
+CHECK-NEXT: FunctionTy      77
+CHECK-NEXT: PointerTy       78
+CHECK-NEXT: StructTy        79
+CHECK-NEXT: ArrayTy 80
+CHECK-NEXT: UnknownTy       81
+CHECK-NEXT: Function        82
+CHECK-NEXT: Pointer 83
+CHECK-NEXT: Constant        84
+CHECK-NEXT: Variable        85
+CHECK-NEXT: FCMP_false   86
+CHECK-NEXT: FCMP_oeq     87
+CHECK-NEXT: FCMP_ogt     88
+CHECK-NEXT: FCMP_oge     89
+CHECK-NEXT: FCMP_olt     90
+CHECK-NEXT: FCMP_ole     91
+CHECK-NEXT: FCMP_one     92
+CHECK-NEXT: FCMP_ord     93
+CHECK-NEXT: FCMP_uno     94
+CHECK-NEXT: FCMP_ueq     95
+CHECK-NEXT: FCMP_ugt     96
+CHECK-NEXT: FCMP_uge     97
+CHECK-NEXT: FCMP_ult     98
+CHECK-NEXT: FCMP_ule     99
+CHECK-NEXT: FCMP_une     100
+CHECK-NEXT: FCMP_true    101
+CHECK-NEXT: ICMP_eq      102
+CHECK-NEXT: ICMP_ne      103
+CHECK-NEXT: ICMP_ugt     104
+CHECK-NEXT: ICMP_uge     105
+CHECK-NEXT: ICMP_ult     106
+CHECK-NEXT: ICMP_ule     107
+CHECK-NEXT: ICMP_sgt     108
+CHECK-NEXT: ICMP_sge     109
+CHECK-NEXT: ICMP_slt     110
+CHECK-NEXT: ICMP_sle     111
diff --git a/llvm/test/tools/llvm-ir2vec/triplets.ll b/llvm/test/tools/llvm-ir2vec/triplets.ll
index 1a7220cc9c3c5..c34370a37e595 100644
--- a/llvm/test/tools/llvm-ir2vec/triplets.ll
+++ b/llvm/test/tools/llvm-ir2vec/triplets.ll
@@ -25,41 +25,41 @@ entry:
 }
 
 ; TRIPLETS: MAX_RELATION=3
-; TRIPLETS-NEXT: 12      74      0
-; TRIPLETS-NEXT: 12      84      2
-; TRIPLETS-NEXT: 12      84      3
+; TRIPLETS-NEXT: 12      75      0
+; TRIPLETS-NEXT: 12      85      2
+; TRIPLETS-NEXT: 12      85      3
 ; TRIPLETS-NEXT: 12      0       1
-; TRIPLETS-NEXT: 0       69      0
-; TRIPLETS-NEXT: 0       84      2
-; TRIPLETS-NEXT: 16      74      0
-; TRIPLETS-NEXT: 16      84      2
-; TRIPLETS-NEXT: 16      84      3
+; TRIPLETS-NEXT: 0       70      0
+; TRIPLETS-NEXT: 0       85      2
+; TRIPLETS-NEXT: 16      75      0
+; TRIPLETS-NEXT: 16      85      2
+; TRIPLETS-NEXT: 16      85      3
 ; TRIPLETS-NEXT: 16      0       1
-; TRIPLETS-NEXT: 0       69      0
-; TRIPLETS-NEXT: 0       84      2
-; TRIPLETS-NEXT: 30      77      0
-; TRIPLETS-NEXT: 30      83      2
+; TRIPLETS-NEXT: 0       70      0
+; TRIPLETS-NEXT: 0       85      2
+; TRIPLETS-NEXT: 30      78      0
+; TRIPLETS-NEXT: 30      84      2
 ; TRIPLETS-NEXT: 30      30      1
-; TRIPLETS-NEXT: 30      77      0
-; TRIPLETS-NEXT: 30      83      2
+; TRIPLETS-NEXT: 30      78      0
+; TRIPLETS-NEXT: 30      84      2
 ; TRIPLETS-NEXT: 30      32      1
-; TRIPLETS-NEXT: 32      69      0
-; TRIPLETS-NEXT: 32      84      2
-; TRIPLETS-NEXT: 32      82      3
+; TRIPLETS-NEXT: 32      70      0
+; TRIPLETS-NEXT: 32      85      2
+; TRIPLETS-NEXT: 32      83      3
 ; TRIPLETS-NEXT: 32      32      1
-; TRIPLETS-NEXT: 32      69      0
-; TRIPLETS-NEXT: 32      84      2
-; TRIPLETS-NEXT: 32      82      3
+; TRIPLETS-NEXT: 32      70      0
+; TRIPLETS-NEXT: 32      85      2
+; TRIPLETS-NEXT: 32      83      3
 ; TRIPLETS-NEXT: 32      31      1
-; TRIPLETS-NEXT: 31      74      0
-; TRIPLETS-NEXT: 31      82      2
+; TRIPLETS-NEXT: 31      75      0
+; TRIPLETS-NEXT: 31      83      2
 ; TRIPLETS-NEXT: 31      31      1
-; TRIPLETS-NEXT: 31      74      0
-; TRIPLETS-NEXT: 31      82      2
+; TRIPLETS-NEXT: 31      75      0
+; TRIPLETS-NEXT: 31      83      2
 ; TRIPLETS-NEXT: 31      12      1
-; TRIPLETS-NEXT: 12      74      0
-; TRIPLETS-NEXT: 12      84      2
-; TRIPLETS-NEXT: 12      84      3
+; TRIPLETS-NEXT: 12      75      0
+; TRIPLETS-NEXT: 12      85      2
+; TRIPLETS-NEXT: 12      85      3
 ; TRIPLETS-NEXT: 12      0       1
-; TRIPLETS-NEXT: 0       69      0
-; TRIPLETS-NEXT: 0       84      2
\ No newline at end of file
+; TRIPLETS-NEXT: 0       70      0
+; TRIPLETS-NEXT: 0       85      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 e5add4430e5a5..9b629f9913ddd 100644
--- a/llvm/tools/llvm-c-test/echo.cpp
+++ b/llvm/tools/llvm-c-test/echo.cpp
@@ -823,6 +823,11 @@ struct FunCloner {
         Dst = LLVMBuildBitCast(Builder, V, CloneType(Src), Name);
         break;
       }
+      case LLVMByteCast: {
+        LLVMValueRef V = CloneValue(LLVMGetOperand(Src, 0));
+        Dst = LLVMBuildByteCast(Builder, V, CloneType(Src), Name);
+        break;
+      }
       case LLVMICmp: {
         LLVMIntPredicate Pred = LLVMGetICmpPredicate(Src);
         LLVMBool IsSameSign = LLVMGetICmpSameSign(Src);
diff --git a/llvm/unittests/Analysis/IR2VecTest.cpp b/llvm/unittests/Analysis/IR2VecTest.cpp
index a095761bc246a..d1a14cda168e9 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.7)));
-  EXPECT_TRUE(RetEmb.approximatelyEquals(Embedding(2, 15.6)));
+  EXPECT_TRUE(AddEmb.approximatelyEquals(Embedding(2, 26.0)));
+  EXPECT_TRUE(RetEmb.approximatelyEquals(Embedding(2, 15.8)));
 }
 
 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.7)));
-  EXPECT_TRUE(RetEmb.approximatelyEquals(Embedding(2, 32.8)));
+  EXPECT_TRUE(AddEmb.approximatelyEquals(Embedding(2, 26.0)));
+  EXPECT_TRUE(RetEmb.approximatelyEquals(Embedding(2, 33.2)));
 }
 
 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.7, 25.7} + {15.6, 15.6} =
-  // {41.3, 41.3}
-  EXPECT_TRUE(BBVec.approximatelyEquals(Embedding(2, 41.3)));
+  // BB vector should be sum of add and ret: {26.0, 26.0} + {15.8, 15.8} =
+  // {41.8, 41.8}
+  EXPECT_TRUE(BBVec.approximatelyEquals(Embedding(2, 41.8)));
 }
 
 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.7, 25.7} + {32.8, 32.8} =
-  // {58.5, 58.5}
-  EXPECT_TRUE(BBVec.approximatelyEquals(Embedding(2, 58.5)));
+  // BB vector should be sum of add and ret: {26.0, 26.0} + {33.2, 33.2} =
+  // {59.2, 59.2}
+  EXPECT_TRUE(BBVec.approximatelyEquals(Embedding(2, 59.2)));
 }
 
 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.3, 41.3}
-  EXPECT_TRUE(FuncVec.approximatelyEquals(Embedding(2, 41.3)));
+  // Function vector should match BB vector (only one BB): {41.8, 41.8}
+  EXPECT_TRUE(FuncVec.approximatelyEquals(Embedding(2, 41.8)));
 }
 
 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.5, 58.5}
-  EXPECT_TRUE(FuncVec.approximatelyEquals(Embedding(2, 58.5)));
+  // Function vector should match BB vector (only one BB): {59.2, 59.2}
+  EXPECT_TRUE(FuncVec.approximatelyEquals(Embedding(2, 59.2)));
 }
 
 TEST_F(IR2VecTestFixture, MultipleComputeEmbeddingsConsistency_Symbolic) {

>From 802a679dfb05ab3c4923fa14d2ae8d1dcbaba3e8 Mon Sep 17 00:00:00 2001
From: Pedro Lobo <pedro.lobo at tecnico.ulisboa.pt>
Date: Fri, 21 Feb 2025 12:14:12 +0000
Subject: [PATCH 03/15] [IR] Support bytes operands in the `trunc` instruction

---
 llvm/lib/IR/Instructions.cpp |  3 ++-
 llvm/lib/IR/Verifier.cpp     |  9 +++++++--
 llvm/test/Assembler/byte.ll  | 16 ++++++++++++++++
 3 files changed, 25 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp
index b61cf86e6834b..fce3934c10a1a 100644
--- a/llvm/lib/IR/Instructions.cpp
+++ b/llvm/lib/IR/Instructions.cpp
@@ -3361,7 +3361,8 @@ CastInst::castIsValid(Instruction::CastOps op, Type *SrcTy, Type *DstTy) {
   switch (op) {
   default: return false; // This is an input error
   case Instruction::Trunc:
-    return SrcTy->isIntOrIntVectorTy() && DstTy->isIntOrIntVectorTy() &&
+    return ((SrcTy->isIntOrIntVectorTy() && DstTy->isIntOrIntVectorTy()) ||
+            (SrcTy->isByteOrByteVectorTy() && DstTy->isByteOrByteVectorTy())) &&
            SrcEC == DstEC && SrcScalarBitSize > DstScalarBitSize;
   case Instruction::ZExt:
     return SrcTy->isIntOrIntVectorTy() && DstTy->isIntOrIntVectorTy() &&
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index a7f1dd006768e..6581466357385 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -3556,8 +3556,13 @@ void Verifier::visitTruncInst(TruncInst &I) {
   unsigned SrcBitSize = SrcTy->getScalarSizeInBits();
   unsigned DestBitSize = DestTy->getScalarSizeInBits();
 
-  Check(SrcTy->isIntOrIntVectorTy(), "Trunc only operates on integer", &I);
-  Check(DestTy->isIntOrIntVectorTy(), "Trunc only produces integer", &I);
+  Check(SrcTy->isIntOrIntVectorTy() || SrcTy->isByteOrByteVectorTy(),
+        "Trunc only operates on integer or byte", &I);
+  Check(DestTy->isIntOrIntVectorTy() || DestTy->isByteOrByteVectorTy(),
+        "Trunc only produces integer or byte", &I);
+  Check(SrcTy->isIntOrIntVectorTy() == DestTy->isIntOrIntVectorTy() &&
+            SrcTy->isByteOrByteVectorTy() == DestTy->isByteOrByteVectorTy(),
+        "Trunc only operates on operands of the same base type", &I);
   Check(SrcTy->isVectorTy() == DestTy->isVectorTy(),
         "trunc source and destination must both be a vector or neither", &I);
   Check(SrcBitSize > DestBitSize, "DestTy too big for Trunc", &I);
diff --git a/llvm/test/Assembler/byte.ll b/llvm/test/Assembler/byte.ll
index 671d2ca0ecb8c..5e1fd41254f31 100644
--- a/llvm/test/Assembler/byte.ll
+++ b/llvm/test/Assembler/byte.ll
@@ -125,3 +125,19 @@ define void @vector_bytecasts(<2 x b64> %b1, <2 x b128> %b2, b64 %b3) {
   %8 = bytecast <2 x b128> %b2 to <4 x ptr>
   ret void
 }
+
+define void @trunc(b16 %b, <2 x b16> %v) {
+; CHECK-LABEL: define void @trunc(
+; CHECK-SAME: b16 [[B:%.*]], <2 x b16> [[V:%.*]]) {
+; CHECK-NEXT:    [[T1:%.*]] = trunc b16 [[B]] to b8
+; CHECK-NEXT:    [[T2:%.*]] = trunc <2 x b16> [[V]] to <2 x b8>
+; CHECK-NEXT:    [[T3:%.*]] = trunc b16 0 to b8
+; CHECK-NEXT:    [[T4:%.*]] = trunc <2 x b16> zeroinitializer to <2 x b8>
+; CHECK-NEXT:    ret void
+;
+  %t1 = trunc b16 %b to b8
+  %t2 = trunc <2 x b16> %v to <2 x b8>
+  %t3 = trunc b16 0 to b8
+  %t4 = trunc <2 x b16> <b16 0, b16 0> to <2 x b8>
+  ret void
+}

>From fe0b5b64b9caece908d580b2f3068e11cb58d1d8 Mon Sep 17 00:00:00 2001
From: Pedro Lobo <pedro.lobo at tecnico.ulisboa.pt>
Date: Tue, 27 Jan 2026 23:01:47 +0000
Subject: [PATCH 04/15] [IR] Support bytes operands in the `lshr` instruction

---
 llvm/include/llvm/IR/IRBuilder.h            | 10 ++++++++--
 llvm/lib/AsmParser/LLParser.cpp             |  4 +++-
 llvm/lib/Bitcode/Reader/BitcodeReader.cpp   |  4 ++--
 llvm/lib/IR/Instructions.cpp                |  8 +++++++-
 llvm/lib/IR/Verifier.cpp                    |  8 +++++++-
 llvm/test/Assembler/byte-invalid-cast-11.ll |  7 +++++++
 llvm/test/Assembler/byte-invalid-cast-12.ll |  7 +++++++
 llvm/test/Assembler/byte.ll                 | 16 ++++++++++++++++
 8 files changed, 57 insertions(+), 7 deletions(-)
 create mode 100644 llvm/test/Assembler/byte-invalid-cast-11.ll
 create mode 100644 llvm/test/Assembler/byte-invalid-cast-12.ll

diff --git a/llvm/include/llvm/IR/IRBuilder.h b/llvm/include/llvm/IR/IRBuilder.h
index f005b0fc75ee3..1482035c02de8 100644
--- a/llvm/include/llvm/IR/IRBuilder.h
+++ b/llvm/include/llvm/IR/IRBuilder.h
@@ -1545,12 +1545,18 @@ class IRBuilderBase {
 
   Value *CreateLShr(Value *LHS, const APInt &RHS, const Twine &Name = "",
                     bool isExact = false) {
-    return CreateLShr(LHS, ConstantInt::get(LHS->getType(), RHS), Name,isExact);
+    Constant *RHSC = LHS->getType()->isByteTy()
+                         ? ConstantByte::get(LHS->getType(), RHS)
+                         : ConstantInt::get(LHS->getType(), RHS);
+    return CreateLShr(LHS, RHSC, Name, isExact);
   }
 
   Value *CreateLShr(Value *LHS, uint64_t RHS, const Twine &Name = "",
                     bool isExact = false) {
-    return CreateLShr(LHS, ConstantInt::get(LHS->getType(), RHS), Name,isExact);
+    Constant *RHSC = LHS->getType()->isByteTy()
+                         ? ConstantByte::get(LHS->getType(), RHS)
+                         : ConstantInt::get(LHS->getType(), RHS);
+    return CreateLShr(LHS, RHSC, Name, isExact);
   }
 
   Value *CreateAShr(Value *LHS, Value *RHS, const Twine &Name = "",
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index 9ce92d042e712..2e22dc9997f7b 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -8166,7 +8166,9 @@ bool LLParser::parseArithmetic(Instruction *&Inst, PerFunctionState &PFS,
     return true;
 
   bool Valid = IsFP ? LHS->getType()->isFPOrFPVectorTy()
-                    : LHS->getType()->isIntOrIntVectorTy();
+                    : (LHS->getType()->isIntOrIntVectorTy() ||
+                       (LHS->getType()->isByteOrByteVectorTy() &&
+                        Opc == Instruction::LShr));
 
   if (!Valid)
     return error(Loc, "invalid operand type for instruction");
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index 5569ddb965673..1ef53c7432ff8 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -1311,8 +1311,8 @@ static int getDecodedUnaryOpcode(unsigned Val, Type *Ty) {
 
 static int getDecodedBinaryOpcode(unsigned Val, Type *Ty) {
   bool IsFP = Ty->isFPOrFPVectorTy();
-  // BinOps are only valid for int/fp or vector of int/fp types
-  if (!IsFP && !Ty->isIntOrIntVectorTy())
+  // BinOps are only valid for int/fp/byte or vector of int/fp/byte types
+  if (!IsFP && !Ty->isIntOrIntVectorTy() && !Ty->isByteOrByteVectorTy())
     return -1;
 
   switch (Val) {
diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp
index fce3934c10a1a..332f2b4b20057 100644
--- a/llvm/lib/IR/Instructions.cpp
+++ b/llvm/lib/IR/Instructions.cpp
@@ -2678,8 +2678,14 @@ void BinaryOperator::AssertOK() {
     assert(getType()->isFPOrFPVectorTy() &&
            "Incorrect operand type (not floating point) for FREM");
     break;
-  case Shl:
   case LShr:
+    assert(getType() == LHS->getType() &&
+           "Lshr operation should return same type as operands!");
+    assert((getType()->isIntOrIntVectorTy() ||
+            getType()->isByteOrByteVectorTy()) &&
+           "Tried to create a lshr operation on a non-integral/byte type!");
+    break;
+  case Shl:
   case AShr:
     assert(getType() == LHS->getType() &&
            "Shift operation should return same type as operands!");
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 6581466357385..bb6fdad4482e7 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -4381,8 +4381,14 @@ void Verifier::visitBinaryOperator(BinaryOperator &B) {
     Check(B.getType() == B.getOperand(0)->getType(),
           "Logical operators must have same type for operands and result!", &B);
     break;
-  case Instruction::Shl:
   case Instruction::LShr:
+    Check(B.getType()->isIntOrIntVectorTy() ||
+              B.getType()->isByteOrByteVectorTy(),
+          "Lshr only work with integral/byte types!", &B);
+    Check(B.getType() == B.getOperand(0)->getType(),
+          "Lshr return type must be same as operands!", &B);
+    break;
+  case Instruction::Shl:
   case Instruction::AShr:
     Check(B.getType()->isIntOrIntVectorTy(),
           "Shifts only work with integral types!", &B);
diff --git a/llvm/test/Assembler/byte-invalid-cast-11.ll b/llvm/test/Assembler/byte-invalid-cast-11.ll
new file mode 100644
index 0000000000000..47d8f7d6e4aab
--- /dev/null
+++ b/llvm/test/Assembler/byte-invalid-cast-11.ll
@@ -0,0 +1,7 @@
+; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s
+
+; CHECK: error: invalid operand type for instruction
+define void @invalid_shift(b32 %b) {
+  %s = shl b32 %b, 8
+  ret void
+}
diff --git a/llvm/test/Assembler/byte-invalid-cast-12.ll b/llvm/test/Assembler/byte-invalid-cast-12.ll
new file mode 100644
index 0000000000000..f1fc7d3341410
--- /dev/null
+++ b/llvm/test/Assembler/byte-invalid-cast-12.ll
@@ -0,0 +1,7 @@
+; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s
+
+; CHECK: error: invalid operand type for instruction
+define void @invalid_shift(b32 %b) {
+  %s = ashr b32 %b, 8
+  ret void
+}
diff --git a/llvm/test/Assembler/byte.ll b/llvm/test/Assembler/byte.ll
index 5e1fd41254f31..7ba2d3152fd61 100644
--- a/llvm/test/Assembler/byte.ll
+++ b/llvm/test/Assembler/byte.ll
@@ -141,3 +141,19 @@ define void @trunc(b16 %b, <2 x b16> %v) {
   %t4 = trunc <2 x b16> <b16 0, b16 0> to <2 x b8>
   ret void
 }
+
+define void @lshr(b64 %b, <4 x b64> %v) {
+; CHECK-LABEL: define void @lshr(
+; CHECK-SAME: b64 [[B:%.*]], <4 x b64> [[V:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = lshr b64 [[B]], 32
+; CHECK-NEXT:    [[TMP2:%.*]] = lshr <4 x b64> [[V]], splat (b64 8)
+; CHECK-NEXT:    [[TMP3:%.*]] = lshr b64 64, 32
+; CHECK-NEXT:    [[TMP4:%.*]] = lshr <4 x b64> zeroinitializer, splat (b64 8)
+; CHECK-NEXT:    ret void
+;
+  %1 = lshr b64 %b, 32
+  %2 = lshr <4 x b64> %v, <b64 8, b64 8, b64 8, b64 8>
+  %3 = lshr b64 64, 32
+  %4 = lshr <4 x b64> <b64 0, b64 0, b64 0, b64 0>, <b64 8, b64 8, b64 8, b64 8>
+  ret void
+}

>From cbc81c4e862fc7ebeaaf15fde67afe813202ca90 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 05/15] [LangRef] Add section on the byte type

---
 llvm/docs/LangRef.rst | 104 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 100 insertions(+), 4 deletions(-)

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 38f2ad8c166fd..b5d5c1639deb8 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -4432,6 +4432,40 @@ 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. 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 +4899,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
@@ -11005,7 +11043,7 @@ Arguments:
 """"""""""
 
 Both arguments to the '``lshr``' instruction must be the same
-:ref:`integer <t_integer>` or :ref:`vector <t_vector>` of integer type.
+:ref:`integer <t_integer>`, :ref:`byte <t_byte>`, or :ref:`vector <t_vector>` of integer or byte type.
 '``op2``' is treated as an unsigned value.
 
 Semantics:
@@ -11032,6 +11070,8 @@ Example:
       <result> = lshr i8 -2, 1   ; yields i8:result = 0x7F
       <result> = lshr i32 1, 32  ; undefined
       <result> = lshr <2 x i32> < i32 -2, i32 4>, < i32 1, i32 2>   ; yields: result=<2 x i32> < i32 0x7FFFFFFF, i32 1>
+      <result> = lshr b32 4, 1   ; yields b32:result = 2
+      <result> = lshr <2 x b32> < b32 -2, b32 4>, < b32 1, b32 2>   ; yields: result=<2 x b32> < b32 0x7FFFFFFF, b32 1>
 
 .. _i_ashr:
 
@@ -12390,8 +12430,8 @@ Arguments:
 """"""""""
 
 The '``trunc``' instruction takes a value to trunc, and a type to trunc
-it to. Both types must be of :ref:`integer <t_integer>` types, or vectors
-of the same number of integers. The bit size of the ``value`` must be
+it to. Both types must be of :ref:`integer <t_integer>` or :ref:`byte <t_byte>` types, or vectors
+of the same number of integers or bytes. The bit size of the ``value`` must be
 larger than the bit size of the destination type, ``ty2``. Equal sized
 types are not allowed.
 
@@ -12417,6 +12457,8 @@ Example:
       %Y = trunc i32 123 to i1                        ; yields i1:true
       %Z = trunc i32 122 to i1                        ; yields i1:false
       %W = trunc <2 x i16> <i16 8, i16 7> to <2 x i8> ; yields <i8 8, i8 7>
+      %X = trunc b32 257 to b8                        ; yields b8:1
+      %W = trunc <2 x b16> <b16 8, b16 7> to <2 x b8> ; yields <b8 8, b8 7>
 
 .. _i_zext:
 
@@ -12998,7 +13040,7 @@ 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.
+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.
 
@@ -13017,6 +13059,60 @@ 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*>
 
+.. _i_bytecast:
+
+'``bytecast .. to``' Instruction
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Syntax:
+"""""""
+
+::
+
+    <result> = bytecast <ty> <value> to <ty2>             ; yields ty2
+
+Overview:
+"""""""""
+
+The '``bytecast``' instruction converts ``value``, of the byte type, to type
+``ty2`` performing type punning.
+
+Arguments:
+""""""""""
+
+The '``bytecast``' instruction takes a value to cast, which must be of the
+:ref:`byte type <t_byte>`, and a type to cast it to, which must be a
+non-aggregate :ref:`first class <t_firstclass>` type. The bit sizes of ``value``
+and the destination type, ``ty2``, must be identical. This instruction supports
+conversions from vectors of bytes to vector of other types (as long as they
+have the same size).
+
+Semantics:
+""""""""""
+
+The '``bytecast``' instruction converts the ``value`` of the :ref:`byte type
+<t_byte>` to type ``ty2``. If ``value`` holds a pointer and type ``ty2`` is not
+a pointer type, the address of the pointer is extracted without exposing its
+provenance, similarly to the :ref:`ptrtoaddr <i_ptrtoaddr>` instruction. If
+``value`` holds a non-pointer value and type ``ty2`` is a pointer type, the cast
+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:
+""""""""
+
+.. code-block:: text
+
+    ; considering %bi to hold an integer and %bp to hold a pointer,
+    %a = bytecast b64 %bi to i64       ; returns an integer, no-op cast
+    %b = bytecast b64 %bp to i64       ; reinterprets the pointer as an integer, returning its address without exposing provenance
+    %c = bytecast b64 %bp to ptr       ; returns a pointer, no-op cast
+    %d = bytecast b64 %bi to ptr       ; reinterprets the integer as a pointer, returning a pointer with no provenance
+
+    %e = bytecast <2 x b32> %v to i64  ; reinterprets the raw bytes as an integer
+    %f = bytecast <2 x b32> %v to ptr  ; reinterprets the raw bytes as a pointer
+
 .. _i_addrspacecast:
 
 '``addrspacecast .. to``' Instruction

>From 313cab865991b644bd0d55e86751095cbdfaa1c5 Mon Sep 17 00:00:00 2001
From: Pedro Lobo <pedro.lobo at tecnico.ulisboa.pt>
Date: Thu, 29 Jan 2026 14:56:54 +0000
Subject: [PATCH 06/15] fix langref

---
 llvm/docs/LangRef.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index b5d5c1639deb8..9f4cdbba54ad7 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -13062,7 +13062,7 @@ Example:
 .. _i_bytecast:
 
 '``bytecast .. to``' Instruction
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Syntax:
 """""""

>From b15a56f8ab9ec31a413851c5aee3c430ea021368 Mon Sep 17 00:00:00 2001
From: Pedro Lobo <pedro.lobo at tecnico.ulisboa.pt>
Date: Thu, 29 Jan 2026 18:33:22 +0000
Subject: [PATCH 07/15] fix CI

---
 llvm/include/llvm/SandboxIR/Instruction.h                | 2 ++
 llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp | 2 +-
 llvm/lib/Target/Hexagon/HexagonTargetObjectFile.cpp      | 1 +
 llvm/lib/Transforms/Scalar/LowerMatrixIntrinsics.cpp     | 1 +
 4 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/llvm/include/llvm/SandboxIR/Instruction.h b/llvm/include/llvm/SandboxIR/Instruction.h
index 95e59a49125c5..13c3deb96f1cc 100644
--- a/llvm/include/llvm/SandboxIR/Instruction.h
+++ b/llvm/include/llvm/SandboxIR/Instruction.h
@@ -2365,6 +2365,8 @@ class CastInst : public UnaryInstruction {
       return Opcode::FPTrunc;
     case llvm::Instruction::BitCast:
       return Opcode::BitCast;
+    case llvm::Instruction::ByteCast:
+      llvm_unreachable("Not implemented!");
     case llvm::Instruction::AddrSpaceCast:
       return Opcode::AddrSpaceCast;
     case llvm::Instruction::CastOpsEnd:
diff --git a/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp b/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp
index 0d87385b44d8f..7feaf5a7bb68e 100644
--- a/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp
+++ b/llvm/lib/Target/DirectX/DXILWriter/DXILBitcodeWriter.cpp
@@ -2029,7 +2029,7 @@ void DXILBitcodeWriter::writeConstants(unsigned FirstVal, unsigned LastVal,
         unsigned NWords = BV->getValue().getActiveWords();
         const uint64_t *RawWords = BV->getValue().getRawData();
         for (unsigned i = 0; i != NWords; ++i) {
-          emitSignedInt64(Record, V);
+          emitSignedInt64(Record, RawWords[i]);
         }
         Code = bitc::CST_CODE_WIDE_BYTE;
       }
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/lib/Transforms/Scalar/LowerMatrixIntrinsics.cpp b/llvm/lib/Transforms/Scalar/LowerMatrixIntrinsics.cpp
index 5d558c2f7a341..5dab775143bc6 100644
--- a/llvm/lib/Transforms/Scalar/LowerMatrixIntrinsics.cpp
+++ b/llvm/lib/Transforms/Scalar/LowerMatrixIntrinsics.cpp
@@ -273,6 +273,7 @@ static bool isShapePreserving(Value *V) {
     case CastInst::PtrToInt:
     case CastInst::IntToPtr:
       return false;
+    case CastInst::ByteCast:
     case CastInst::BitCast: {
       if (auto *SrcVTy = dyn_cast<FixedVectorType>(Cast->getSrcTy()))
         if (auto *DestVTy = dyn_cast<FixedVectorType>(Cast->getDestTy()))

>From 7a49e831de01d7b992ff20f1353edf2871b23d8e Mon Sep 17 00:00:00 2001
From: Pedro Lobo <pedro.lobo at tecnico.ulisboa.pt>
Date: Thu, 29 Jan 2026 19:34:46 +0000
Subject: [PATCH 08/15] add codegen test for byte constants

---
 llvm/lib/IR/Constants.cpp               |  7 +++++--
 llvm/test/CodeGen/X86/byte-constants.ll | 21 +++++++++++++++++++++
 2 files changed, 26 insertions(+), 2 deletions(-)
 create mode 100644 llvm/test/CodeGen/X86/byte-constants.ll

diff --git a/llvm/lib/IR/Constants.cpp b/llvm/lib/IR/Constants.cpp
index 06f312434003f..f388069596679 100644
--- a/llvm/lib/IR/Constants.cpp
+++ b/llvm/lib/IR/Constants.cpp
@@ -2524,8 +2524,11 @@ Constant *ConstantExpr::getTrunc(Constant *C, Type *Ty, bool OnlyIfReduced) {
   bool toVec = isa<VectorType>(Ty);
 #endif
   assert((fromVec == toVec) && "Cannot convert from scalar to/from vector");
-  assert(C->getType()->isIntOrIntVectorTy() && "Trunc operand must be integer");
-  assert(Ty->isIntOrIntVectorTy() && "Trunc produces only integral");
+  assert((C->getType()->isIntOrIntVectorTy() ||
+          C->getType()->isByteOrByteVectorTy()) &&
+         "Trunc operand must be integer or byte");
+  assert((Ty->isIntOrIntVectorTy() || Ty->isByteOrByteVectorTy()) &&
+         "Trunc produces only integral or byte");
   assert(C->getType()->getScalarSizeInBits() > Ty->getScalarSizeInBits()&&
          "SrcTy must be larger than DestTy for Trunc!");
 
diff --git a/llvm/test/CodeGen/X86/byte-constants.ll b/llvm/test/CodeGen/X86/byte-constants.ll
new file mode 100644
index 0000000000000..9077a6426c0a5
--- /dev/null
+++ b/llvm/test/CodeGen/X86/byte-constants.ll
@@ -0,0 +1,21 @@
+; RUN: llc < %s | FileCheck %s
+
+%union.x = type { b32 }
+
+; CHECK:	.globl r
+; CHECK: r:
+; CHECK: .long	42
+
+ at r = global %union.x { b32 42 }, align 4
+
+; CHECK:	.globl x
+; CHECK: x:
+; CHECK: .quad	10
+
+ at x = global b64 bitcast (i64 10 to b64)
+
+; CHECK:	.globl y
+; CHECK: y:
+; CHECK: .byte	12
+
+ at y = global b8 trunc (b32 12 to b8)

>From c76bb74951970e2c7a5845571a4d76a5c4b7f7ad Mon Sep 17 00:00:00 2001
From: Pedro Lobo <pedro.lobo at tecnico.ulisboa.pt>
Date: Thu, 29 Jan 2026 22:04:26 +0000
Subject: [PATCH 09/15] address reviews

---
 llvm/docs/LangRef.rst                          | 18 +++++++++++-------
 llvm/include/llvm/IR/Constants.h               |  2 +-
 llvm/include/llvm/IR/DerivedTypes.h            |  6 +++---
 llvm/include/llvm/IR/IRBuilder.h               | 16 ----------------
 llvm/include/llvm/IR/Type.h                    |  2 +-
 .../SelectionDAG/SelectionDAGBuilder.cpp       |  2 +-
 6 files changed, 17 insertions(+), 29 deletions(-)

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 9f4cdbba54ad7..ba2a87926bf7b 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -13091,13 +13091,17 @@ Semantics:
 """"""""""
 
 The '``bytecast``' instruction converts the ``value`` of the :ref:`byte type
-<t_byte>` to type ``ty2``. If ``value`` holds a pointer and type ``ty2`` is not
-a pointer type, the address of the pointer is extracted without exposing its
-provenance, similarly to the :ref:`ptrtoaddr <i_ptrtoaddr>` instruction. If
-``value`` holds a non-pointer value and type ``ty2`` is a pointer type, the cast
-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*.
+<t_byte>` to type ``ty2``. If ``value`` holds a mix of pointer and non-pointer
+bits and type ``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 ``value`` holds bits from different pointers, or
+a mix of pointer and non-pointer bits, and type ``ty2`` is a pointer type, the
+cast result is a pointer without provenance. This pointer cannot be
+dereferenced, but can be used in comparisons or :ref:`getelementptr
+<i_getelementptr>` instructions. If any of the bits of ``value`` is ``poison``,
+the cast result is also ``poison``. Casting a mix of pointer and non-pointer
+bits to a non-pointer type strips the pointer's provenance. Otherwise, the cast
+is a *no-op*.
 
 Example:
 """"""""
diff --git a/llvm/include/llvm/IR/Constants.h b/llvm/include/llvm/IR/Constants.h
index 9c00b55140fc6..e40cbb4e2bd42 100644
--- a/llvm/include/llvm/IR/Constants.h
+++ b/llvm/include/llvm/IR/Constants.h
@@ -386,7 +386,7 @@ class ConstantByte final : public ConstantData {
   /// 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 an ByteType, which
+  /// 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());
diff --git a/llvm/include/llvm/IR/DerivedTypes.h b/llvm/include/llvm/IR/DerivedTypes.h
index 7c1fcb90952ec..876c4c8c871ce 100644
--- a/llvm/include/llvm/IR/DerivedTypes.h
+++ b/llvm/include/llvm/IR/DerivedTypes.h
@@ -124,11 +124,11 @@ class ByteType : public Type {
                   ///< to the largest representable power of 2, 8388608.
   };
 
-  /// This static method is the primary way of constructing an ByteType.
-  /// If an ByteType with the same NumBits value was previously instantiated,
+  /// 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 an ByteType instance.
+  /// Get or create a ByteType instance.
   LLVM_ABI static ByteType *get(LLVMContext &C, unsigned NumBits);
 
   /// Returns type twice as wide the input type.
diff --git a/llvm/include/llvm/IR/IRBuilder.h b/llvm/include/llvm/IR/IRBuilder.h
index 1482035c02de8..3f326239808f7 100644
--- a/llvm/include/llvm/IR/IRBuilder.h
+++ b/llvm/include/llvm/IR/IRBuilder.h
@@ -2233,22 +2233,6 @@ class IRBuilderBase {
     return CreateByteCast(V, DestTy, Name);
   }
 
-  Value *CreateByteCastToPtr(Value *V, unsigned AddrSpace = 0,
-                             const Twine &Name = "") {
-    if (auto *VTy = dyn_cast<VectorType>(V->getType())) {
-      unsigned NumEls = VTy->getElementCount().getKnownMinValue();
-
-      Type *DestElTy = getPtrTy(AddrSpace);
-      VectorType *DestTy =
-          VectorType::get(DestElTy, NumEls, VTy->isScalableTy());
-
-      return CreateByteCast(V, DestTy, Name);
-    }
-
-    Type *DestTy = getPtrTy(AddrSpace);
-    return CreateByteCast(V, DestTy, Name);
-  }
-
   Value *CreateZExtOrBitCast(Value *V, Type *DestTy, const Twine &Name = "") {
     Instruction::CastOps CastOp =
         V->getType()->getScalarSizeInBits() == DestTy->getScalarSizeInBits()
diff --git a/llvm/include/llvm/IR/Type.h b/llvm/include/llvm/IR/Type.h
index 1640de3b9fbd8..98d432ca243f3 100644
--- a/llvm/include/llvm/IR/Type.h
+++ b/llvm/include/llvm/IR/Type.h
@@ -241,7 +241,7 @@ class Type {
   /// True if this is an instance of ByteType.
   bool isByteTy() const { return getTypeID() == ByteTyID; }
 
-  /// Return true if this is an ByteType of the given width.
+  /// 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.
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 5d97b7e73c673..b10e69909d76f 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -4142,7 +4142,7 @@ void SelectionDAGBuilder::visitByteCast(const User &I) {
     // Convert vector types.
     setValue(&I, DAG.getNode(ISD::BITCAST, dl, DestVT, N));
   // Check if the original LLVM IR Operand was a ConstantByte, because
-  // getValue() might fold any kind of constant expression to an byte constant
+  // getValue() might fold any kind of constant expression to a byte constant
   // and that is not what we are looking for. Only recognize a bytecast of a
   // genuine constant byte as an opaque constant.
   else if (ConstantByte *C = dyn_cast<ConstantByte>(I.getOperand(0)))

>From bddbfc0d76d3731a412fd9f37b39b4205b6e48bb Mon Sep 17 00:00:00 2001
From: Pedro Lobo <pedro.lobo at tecnico.ulisboa.pt>
Date: Fri, 30 Jan 2026 19:44:37 +0000
Subject: [PATCH 10/15] add wide bytes and vectors to codegen test

---
 llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 81 ++++++++++++++++++++++
 llvm/test/CodeGen/X86/byte-constants.ll    | 58 ++++++++++++++--
 2 files changed, 134 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index c0b284ec865f6..715b3c353eeba 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -4131,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 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.
+
+    // 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();
@@ -4334,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/test/CodeGen/X86/byte-constants.ll b/llvm/test/CodeGen/X86/byte-constants.ll
index 9077a6426c0a5..5b6cd7ae1f166 100644
--- a/llvm/test/CodeGen/X86/byte-constants.ll
+++ b/llvm/test/CodeGen/X86/byte-constants.ll
@@ -1,12 +1,10 @@
 ; RUN: llc < %s | FileCheck %s
 
-%union.x = type { b32 }
-
 ; CHECK:	.globl r
 ; CHECK: r:
 ; CHECK: .long	42
 
- at r = global %union.x { b32 42 }, align 4
+ at r = global b32 42
 
 ; CHECK:	.globl x
 ; CHECK: x:
@@ -16,6 +14,56 @@
 
 ; CHECK:	.globl y
 ; CHECK: y:
-; CHECK: .byte	12
+; CHECK: .byte	4
+
+ at y = global b8 trunc (b32 4 to b8)
+
+; 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 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 y = global b8 trunc (b32 12 to b8)
+ at uv = global <4 x b128> <b128 -1, b128 -1, b128 -1, b128 -1>

>From 18dd04961c4e2f8d63641abd95e548520a82ad6b Mon Sep 17 00:00:00 2001
From: Pedro Lobo <pedro.lobo at tecnico.ulisboa.pt>
Date: Fri, 30 Jan 2026 20:00:29 +0000
Subject: [PATCH 11/15] update langref

---
 llvm/docs/LangRef.rst | 23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index ba2a87926bf7b..7886713836602 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -13091,17 +13091,18 @@ Semantics:
 """"""""""
 
 The '``bytecast``' instruction converts the ``value`` of the :ref:`byte type
-<t_byte>` to type ``ty2``. If ``value`` holds a mix of pointer and non-pointer
-bits and type ``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 ``value`` holds bits from different pointers, or
-a mix of pointer and non-pointer bits, and type ``ty2`` is a pointer type, the
-cast result is a pointer without provenance. This pointer cannot be
-dereferenced, but can be used in comparisons or :ref:`getelementptr
-<i_getelementptr>` instructions. If any of the bits of ``value`` is ``poison``,
-the cast result is also ``poison``. Casting a mix of pointer and non-pointer
-bits to a non-pointer type strips the pointer's provenance. Otherwise, the cast
-is a *no-op*.
+<t_byte>` to type ``ty2``. If ``value`` contains at least one ``poison`` bit,
+the cast result is ``poison``. Otherwise, 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, the cast 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:
 """"""""

>From 14dceb6c38f7c6d89a29933e2b058b17711ef14d Mon Sep 17 00:00:00 2001
From: Pedro Lobo <pedro.lobo at tecnico.ulisboa.pt>
Date: Fri, 30 Jan 2026 20:03:31 +0000
Subject: [PATCH 12/15] ir builder review

---
 llvm/include/llvm/IR/IRBuilder.h | 15 +++++----------
 1 file changed, 5 insertions(+), 10 deletions(-)

diff --git a/llvm/include/llvm/IR/IRBuilder.h b/llvm/include/llvm/IR/IRBuilder.h
index 3f326239808f7..48d82b09f222a 100644
--- a/llvm/include/llvm/IR/IRBuilder.h
+++ b/llvm/include/llvm/IR/IRBuilder.h
@@ -2219,13 +2219,7 @@ class IRBuilderBase {
 
   Value *CreateByteCastToInt(Value *V, const Twine &Name = "") {
     if (auto *VTy = dyn_cast<VectorType>(V->getType())) {
-      unsigned NumEls = VTy->getElementCount().getKnownMinValue();
-      unsigned BitWidth = VTy->getElementType()->getPrimitiveSizeInBits();
-
-      Type *DestElTy = getIntNTy(BitWidth);
-      VectorType *DestTy =
-          VectorType::get(DestElTy, NumEls, VTy->isScalableTy());
-
+      VectorType *DestTy = VectorType::getInteger(VTy);
       return CreateByteCast(V, DestTy, Name);
     }
 
@@ -2258,9 +2252,10 @@ class IRBuilderBase {
   }
 
   Value *CreateBitOrByteCast(Value *V, Type *DestTy, const Twine &Name = "") {
-    Instruction::CastOps CastOp = V->getType()->isByteOrByteVectorTy()
-                                      ? Instruction::ByteCast
-                                      : Instruction::BitCast;
+    Instruction::CastOps CastOp =
+        V->getType()->isByteOrByteVectorTy() && !DestTy->isByteOrByteVectorTy()
+            ? Instruction::ByteCast
+            : Instruction::BitCast;
     return CreateCast(CastOp, V, DestTy, Name);
   }
 

>From 358734298206bbf480314ae39a031fcbe3e30842 Mon Sep 17 00:00:00 2001
From: Pedro Lobo <pedro.lobo at tecnico.ulisboa.pt>
Date: Fri, 30 Jan 2026 21:42:52 +0000
Subject: [PATCH 13/15] update langref

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

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 7886713836602..119a81cd0c6f9 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -13098,9 +13098,11 @@ the cast result is ``poison``. Otherwise, if ``value`` is any mix of
 * 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, the cast result is a pointer without provenance.
-  This pointer cannot be dereferenced, but can be used in comparisons or
-  :ref:`getelementptr <i_getelementptr>` instructions.
+* If ``ty2`` is a pointer type, then if all bits of ``value`` are from the same
+  pointer, 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 84e24c4dd85d972945338d32f187b525eb5de871 Mon Sep 17 00:00:00 2001
From: Pedro Lobo <pedro.lobo at tecnico.ulisboa.pt>
Date: Sat, 31 Jan 2026 19:26:05 +0000
Subject: [PATCH 14/15] update docs

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

diff --git a/llvm/docs/Frontend/PerformanceTips.rst b/llvm/docs/Frontend/PerformanceTips.rst
index b81df707a31a6..5a32499cd5700 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). 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 119a81cd0c6f9..e46442f58450b 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -4439,7 +4439,9 @@ Byte Type
 
 :Overview:
 
-The byte type represents raw memory data in SSA registers. Each bit can be:
+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. Otherwise, the specific type should be used. Each bit can be:
 
 * An integer bit (0 or 1)
 * Part of a pointer value
@@ -13109,7 +13111,7 @@ Otherwise, the cast is a *no-op*.
 Example:
 """"""""
 
-.. code-block:: text
+.. code-block:: llvm
 
     ; considering %bi to hold an integer and %bp to hold a pointer,
     %a = bytecast b64 %bi to i64       ; returns an integer, no-op cast

>From f0f6c95c4e7017ce2cd606f94bba5970707761cd Mon Sep 17 00:00:00 2001
From: Pedro Lobo <pedro.lobo at tecnico.ulisboa.pt>
Date: Sat, 31 Jan 2026 20:15:57 +0000
Subject: [PATCH 15/15] fix IR2Vec type order

---
 llvm/include/llvm/Analysis/IR2Vec.h | 2 +-
 llvm/include/llvm/IR/Type.h         | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/include/llvm/Analysis/IR2Vec.h b/llvm/include/llvm/Analysis/IR2Vec.h
index e728e76fcc058..e795e3b86f20f 100644
--- a/llvm/include/llvm/Analysis/IR2Vec.h
+++ b/llvm/include/llvm/Analysis/IR2Vec.h
@@ -489,8 +489,8 @@ class Vocabulary {
       CanonicalTypeID::MetadataTy, // MetadataTyID
       CanonicalTypeID::VectorTy,   // X86_AMXTyID
       CanonicalTypeID::TokenTy,    // TokenTyID
-      CanonicalTypeID::ByteTy,     // ByteTyID
       CanonicalTypeID::IntegerTy,  // IntegerTyID
+      CanonicalTypeID::ByteTy,     // ByteTyID
       CanonicalTypeID::FunctionTy, // FunctionTyID
       CanonicalTypeID::PointerTy,  // PointerTyID
       CanonicalTypeID::StructTy,   // StructTyID
diff --git a/llvm/include/llvm/IR/Type.h b/llvm/include/llvm/IR/Type.h
index 98d432ca243f3..56417ee14796f 100644
--- a/llvm/include/llvm/IR/Type.h
+++ b/llvm/include/llvm/IR/Type.h
@@ -68,8 +68,8 @@ class Type {
     TokenTyID,     ///< Tokens
 
     // Derived types... see DerivedTypes.h file.
-    ByteTyID,           ///< Arbitrary bit width bytes
     IntegerTyID,        ///< Arbitrary bit width integers
+    ByteTyID,           ///< Arbitrary bit width bytes
     FunctionTyID,       ///< Functions
     PointerTyID,        ///< Pointers
     StructTyID,         ///< Structures



More information about the llvm-commits mailing list