[llvm] [IR] Implementation and lowering of bitinsert and bitextract (PR #200605)

Pedro Vicente via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 10 06:05:38 PDT 2026


https://github.com/pedroMVicente updated https://github.com/llvm/llvm-project/pull/200605

>From d160053ddbec320957cec8eeb28e7c2b7795ca5a Mon Sep 17 00:00:00 2001
From: Guilherme Lopes <guilhermeglopes at tecnico.ulisboa.pt>
Date: Fri, 29 May 2026 15:23:12 +0100
Subject: [PATCH 1/9] [IR] Implementation and lowering of bitinsert and
 bitextract

This commit implements bitinsert and bitextract instructions to
manipulate Byte types. These were lowered to SDAG and GlobalISel,
and tests for IR and X86 were added.

Co-authored-by: Pedro Vicente <pedro.costa.vicente at tecnico.ulisboa.pt>
---
 llvm/docs/LangRef.rst                         | 82 +++++++++++++++++++
 llvm/include/llvm-c/Core.h                    | 12 +++
 .../llvm/Analysis/InstSimplifyFolder.h        | 12 +++
 llvm/include/llvm/Analysis/TargetFolder.h     | 10 +++
 llvm/include/llvm/AsmParser/LLParser.h        |  2 +
 llvm/include/llvm/AsmParser/LLToken.h         |  2 +
 llvm/include/llvm/Bitcode/LLVMBitCodes.h      |  2 +
 .../llvm/CodeGen/GlobalISel/IRTranslator.h    |  3 +
 llvm/include/llvm/IR/ConstantFolder.h         | 10 +++
 llvm/include/llvm/IR/IRBuilder.h              | 14 ++++
 llvm/include/llvm/IR/IRBuilderFolder.h        |  6 ++
 llvm/include/llvm/IR/InstVisitor.h            |  2 +
 llvm/include/llvm/IR/Instruction.def          |  4 +-
 llvm/include/llvm/IR/Instructions.h           | 81 ++++++++++++++++++
 llvm/include/llvm/IR/NoFolder.h               | 10 +++
 llvm/lib/AsmParser/LLLexer.cpp                |  2 +
 llvm/lib/AsmParser/LLParser.cpp               | 49 +++++++++++
 llvm/lib/Bitcode/Reader/BitcodeReader.cpp     | 39 +++++++++
 llvm/lib/Bitcode/Writer/BitcodeWriter.cpp     | 12 +++
 llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp  | 70 ++++++++++++++++
 .../SelectionDAG/SelectionDAGBuilder.cpp      | 67 +++++++++++++++
 .../SelectionDAG/SelectionDAGBuilder.h        |  3 +
 llvm/lib/CodeGen/TargetLoweringBase.cpp       |  2 +
 llvm/lib/IR/AsmWriter.cpp                     |  4 +-
 llvm/lib/IR/Core.cpp                          | 14 ++++
 llvm/lib/IR/Instruction.cpp                   |  2 +
 llvm/lib/IR/Instructions.cpp                  | 57 +++++++++++++
 llvm/lib/IR/Verifier.cpp                      | 19 +++++
 llvm/test/Assembler/bitextract-invalid-1.ll   |  6 ++
 llvm/test/Assembler/bitinsert-bitextract.ll   | 15 ++++
 llvm/test/Assembler/bitinsert-invalid-1.ll    |  6 ++
 .../X86/GlobalISel/bitinsert-bitextract.ll    | 32 ++++++++
 .../CodeGen/X86/bitinsert-bitextract-x86.ll   | 42 ++++++++++
 .../bitinsert-bitextract-runtime.ll           | 29 +++++++
 .../Verifier/bitextract-invalid-verifier.ll   |  8 ++
 llvm/tools/llvm-c-test/echo.cpp               | 14 ++++
 36 files changed, 741 insertions(+), 3 deletions(-)
 create mode 100644 llvm/test/Assembler/bitextract-invalid-1.ll
 create mode 100644 llvm/test/Assembler/bitinsert-bitextract.ll
 create mode 100644 llvm/test/Assembler/bitinsert-invalid-1.ll
 create mode 100644 llvm/test/CodeGen/X86/GlobalISel/bitinsert-bitextract.ll
 create mode 100644 llvm/test/CodeGen/X86/bitinsert-bitextract-x86.ll
 create mode 100644 llvm/test/ExecutionEngine/bitinsert-bitextract-runtime.ll
 create mode 100644 llvm/test/Verifier/bitextract-invalid-verifier.ll

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 81694139fcea2..d671e8f343c65 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -10596,6 +10596,88 @@ Example:
 
 .. _binaryops:
 
+Byte Operations
+-----------------
+
+Instructions for bit manipulation for bytes.
+
+.. _i_bitextract:
+
+'``bitextract``' Instruction
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Syntax:
+"""""""
+
+::
+
+      <result> = bitextract <ty>, <tx> <source>, i32 <offset>
+
+Overview:
+"""""""""
+
+The '``bitextract``' extracts a value from a byte.
+
+Arguments:
+""""""""""
+The '``bitextract``' instruction takes any first-class type ty (the
+return type), a Byte value source, and an offset.
+
+Semantics:
+""""""""""
+
+The '``bitextract``' instruction returns a value of the specified type.
+The returned value is first extracted from the source, starting at the
+bit specified by the offset, and then bitcasted to the return type.
+If the range offset+ty.bitwidth exceeds the source width, it returns
+poison.
+
+Example:
+""""""""
+
+.. code-block:: text
+
+      %result = bitextract i8, b32 %src, i32 24 ; Extract the last 8 bits from %src and return an 8-bit integer
+
+.. _i_bitinsert:
+
+'``bitinsert``' Instruction
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Syntax:
+"""""""
+
+::
+
+      <result> = bitinsert <tx> <base>, <ty> <val>, i32 <offset>
+
+Overview:
+"""""""""
+
+This instruction '``bitinsert``' inserts a value into a specific
+position within a byte.
+
+Arguments:
+""""""""""
+The first argument (base) of '``bitinsert``' must be of a byte type.
+The second operand (val) must be an arbitrary type.
+
+Semantics:
+""""""""""
+
+The returned value is of the same byte type as the first argument.
+It returns the first argument where the bits in the range
+[offset, offset + ty.bitlength - 1] have been replaced with val. 
+If the range (offset + ty.bitwidth) is greater than the bitwidth of
+the first argument, it returns poison.
+
+Example:
+""""""""
+
+.. code-block:: text
+
+      %result = bitinsert b32 %x, i8 %y, i32 3 ; Inserts the %y bits into %x with an offset of 3
+
 Binary Operations
 -----------------
 
diff --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h
index 86f636c636783..6aae7fc30dab6 100644
--- a/llvm/include/llvm-c/Core.h
+++ b/llvm/include/llvm-c/Core.h
@@ -133,6 +133,8 @@ typedef enum {
   LLVMExtractValue   = 53,
   LLVMInsertValue    = 54,
   LLVMFreeze         = 68,
+  LLVMBitInsert      = 72,
+  LLVMBitExtract     = 73,
 
   /* Atomic operators */
   LLVMFence          = 55,
@@ -5142,6 +5144,16 @@ LLVM_C_ABI LLVMValueRef LLVMBuildInsertValue(LLVMBuilderRef,
                                              unsigned Index, const char *Name);
 LLVM_C_ABI LLVMValueRef LLVMBuildFreeze(LLVMBuilderRef, LLVMValueRef Val,
                                         const char *Name);
+LLVM_C_ABI LLVMValueRef LLVMBuildBitExtract(LLVMBuilderRef,
+                                            LLVMTypeRef Type,
+                                            LLVMValueRef Src,
+                                            LLVMValueRef Offset,
+                                            const char *Name);
+LLVM_C_ABI LLVMValueRef LLVMBuildBitInsert(LLVMBuilderRef,
+                                           LLVMValueRef Base,
+                                           LLVMValueRef Val,
+                                           LLVMValueRef Offset,
+                                           const char *Name);
 
 LLVM_C_ABI LLVMValueRef LLVMBuildIsNull(LLVMBuilderRef, LLVMValueRef Val,
                                         const char *Name);
diff --git a/llvm/include/llvm/Analysis/InstSimplifyFolder.h b/llvm/include/llvm/Analysis/InstSimplifyFolder.h
index b0b8dde3b2967..d79c619114a72 100644
--- a/llvm/include/llvm/Analysis/InstSimplifyFolder.h
+++ b/llvm/include/llvm/Analysis/InstSimplifyFolder.h
@@ -115,6 +115,18 @@ class LLVM_ABI InstSimplifyFolder final : public IRBuilderFolder {
     return simplifyShuffleVectorInst(V1, V2, Mask, RetTy, SQ);
   }
 
+  Value *FoldBitInsert(Value *Base, Value *Val,
+                       Value *Offset) const override {
+    // TODO
+    return nullptr;
+  }
+
+  Value *FoldBitExtract(Type *Ty, Value *Src,
+                        Value *Offset) const override {
+    // TODO
+    return nullptr;
+  }
+
   Value *FoldCast(Instruction::CastOps Op, Value *V,
                   Type *DestTy) const override {
     return simplifyCastInst(Op, V, DestTy, SQ);
diff --git a/llvm/include/llvm/Analysis/TargetFolder.h b/llvm/include/llvm/Analysis/TargetFolder.h
index 596e3600f7306..dd8264c34e58e 100644
--- a/llvm/include/llvm/Analysis/TargetFolder.h
+++ b/llvm/include/llvm/Analysis/TargetFolder.h
@@ -184,6 +184,16 @@ class LLVM_ABI TargetFolder final : public IRBuilderFolder {
     return nullptr;
   }
 
+  Value *FoldBitInsert(Value *Base, Value *Val,
+                       Value *Offset) const override {
+    return nullptr;
+  }
+
+  Value *FoldBitExtract(Type *Ty, Value *Src,
+                        Value *Offset) const override {
+    return nullptr;
+  }
+
   Value *FoldCast(Instruction::CastOps Op, Value *V,
                   Type *DestTy) const override {
     if (auto *C = dyn_cast<Constant>(V))
diff --git a/llvm/include/llvm/AsmParser/LLParser.h b/llvm/include/llvm/AsmParser/LLParser.h
index 938a45951e074..0e7c073a47277 100644
--- a/llvm/include/llvm/AsmParser/LLParser.h
+++ b/llvm/include/llvm/AsmParser/LLParser.h
@@ -684,6 +684,8 @@ namespace llvm {
     bool parseExtractElement(Instruction *&Inst, PerFunctionState &PFS);
     bool parseInsertElement(Instruction *&Inst, PerFunctionState &PFS);
     bool parseShuffleVector(Instruction *&Inst, PerFunctionState &PFS);
+    bool parseBitExtract(Instruction *&Inst, PerFunctionState &PFS);
+    bool parseBitInsert(Instruction *&Inst, PerFunctionState &PFS);
     int parsePHI(Instruction *&Inst, PerFunctionState &PFS);
     bool parseLandingPad(Instruction *&Inst, PerFunctionState &PFS);
     bool parseCall(Instruction *&Inst, PerFunctionState &PFS,
diff --git a/llvm/include/llvm/AsmParser/LLToken.h b/llvm/include/llvm/AsmParser/LLToken.h
index a9864cfbcab25..eb2e3c97a43ce 100644
--- a/llvm/include/llvm/AsmParser/LLToken.h
+++ b/llvm/include/llvm/AsmParser/LLToken.h
@@ -380,6 +380,8 @@ enum Kind {
   kw_dso_local_equivalent,
   kw_no_cfi,
   kw_ptrauth,
+  kw_bitinsert,
+  kw_bitextract,
 
   kw_freeze,
 
diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
index 95787c595dff7..d5691877b20d2 100644
--- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h
+++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
@@ -703,6 +703,8 @@ enum FunctionCodes {
   FUNC_CODE_DEBUG_RECORD_LABEL = 65, // [DILocation, DILabel]
   FUNC_CODE_DEBUG_RECORD_DECLARE_VALUE =
       66, // [DILocation, DILocalVariable, DIExpression, ValueAsMetadata]
+  FUNC_CODE_INST_BITINSERT = 67, // BITINSERT: [val, val ,val]
+  FUNC_CODE_INST_BITEXTRACT = 68, // BITEXTRACT: [val, val, val]
 };
 
 enum UseListCodes {
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h b/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h
index 7815ad686cbaa..9622a3a158b7f 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h
@@ -569,6 +569,9 @@ class IRTranslator : public MachineFunctionPass {
   bool translateFence(const User &U, MachineIRBuilder &MIRBuilder);
   bool translateFreeze(const User &U, MachineIRBuilder &MIRBuilder);
 
+  bool translateBitExtract(const User &U, MachineIRBuilder &MIRBuilder);
+  bool translateBitInsert(const User &U, MachineIRBuilder &MIRBuilder);
+
   // Stubs to keep the compiler happy while we implement the rest of the
   // translation.
   bool translateResume(const User &U, MachineIRBuilder &MIRBuilder) {
diff --git a/llvm/include/llvm/IR/ConstantFolder.h b/llvm/include/llvm/IR/ConstantFolder.h
index 384773027fb65..8bb5b8f45a314 100644
--- a/llvm/include/llvm/IR/ConstantFolder.h
+++ b/llvm/include/llvm/IR/ConstantFolder.h
@@ -172,6 +172,16 @@ class LLVM_ABI ConstantFolder final : public IRBuilderFolder {
     return nullptr;
   }
 
+  Value *FoldBitInsert(Value *Base, Value *Val,
+                       Value *Offset) const override {
+    return nullptr;
+  }
+
+  Value *FoldBitExtract(Type *Ty, Value *Src,
+                        Value *Offset) const override {
+    return nullptr;
+  }
+
   Value *FoldCast(Instruction::CastOps Op, Value *V,
                   Type *DestTy) const override {
     if (auto *C = dyn_cast<Constant>(V)) {
diff --git a/llvm/include/llvm/IR/IRBuilder.h b/llvm/include/llvm/IR/IRBuilder.h
index a10a59a9ae9e7..cdd0dc9e1a5d9 100644
--- a/llvm/include/llvm/IR/IRBuilder.h
+++ b/llvm/include/llvm/IR/IRBuilder.h
@@ -2694,6 +2694,20 @@ class IRBuilderBase {
     return Insert(new FreezeInst(V), Name);
   }
 
+  Value *CreateBitInsert(Value *Base, Value *Val, Value *Offset,
+                         const Twine &Name = "") {
+    if (Value *V = Folder.FoldBitInsert(Base, Val, Offset))
+      return V;
+    return Insert(BitInsertInst::Create(Base, Val, Offset), Name);
+  }
+
+  Value *CreateBitExtract(Type *Ty, Value *Src, Value *Offset,
+                          const Twine &Name = "") {
+    if (Value *V = Folder.FoldBitExtract(Ty, Src, Offset))
+      return V;
+    return Insert(BitExtractInst::Create(Ty, Src, Offset), Name);
+  }
+
   //===--------------------------------------------------------------------===//
   // Utility creation methods
   //===--------------------------------------------------------------------===//
diff --git a/llvm/include/llvm/IR/IRBuilderFolder.h b/llvm/include/llvm/IR/IRBuilderFolder.h
index 3cf3bcd3d9522..6db2424155128 100644
--- a/llvm/include/llvm/IR/IRBuilderFolder.h
+++ b/llvm/include/llvm/IR/IRBuilderFolder.h
@@ -80,6 +80,12 @@ class LLVM_ABI IRBuilderFolder {
   FoldBinaryIntrinsic(Intrinsic::ID ID, Value *LHS, Value *RHS, Type *Ty,
                       FastMathFlags FMF = FastMathFlags()) const = 0;
 
+  virtual Value *FoldBitInsert(Value *Base, Value *Val,
+                               Value *Offset) const = 0;
+
+  virtual Value *FoldBitExtract(Type *Ty, Value *Src,
+                                Value *Offset) const = 0;
+
   //===--------------------------------------------------------------------===//
   // Cast/Conversion Operators
   //===--------------------------------------------------------------------===//
diff --git a/llvm/include/llvm/IR/InstVisitor.h b/llvm/include/llvm/IR/InstVisitor.h
index 45b2e59510b67..0f5f2ab6c1317 100644
--- a/llvm/include/llvm/IR/InstVisitor.h
+++ b/llvm/include/llvm/IR/InstVisitor.h
@@ -199,6 +199,8 @@ class InstVisitor {
   RetTy visitCleanupPadInst(CleanupPadInst &I) { DELEGATE(FuncletPadInst); }
   RetTy visitCatchPadInst(CatchPadInst &I)     { DELEGATE(FuncletPadInst); }
   RetTy visitFreezeInst(FreezeInst &I)         { DELEGATE(Instruction); }
+  RetTy visitBitInsertInst(BitInsertInst &I)   { DELEGATE(Instruction); }
+  RetTy visitBitExtractInst(BitExtractInst &I) { DELEGATE(Instruction); }
 
   RetTy visitMemSetInst(MemSetInst &I)            { DELEGATE(MemIntrinsic); }
   RetTy visitMemSetPatternInst(MemSetPatternInst &I) {
diff --git a/llvm/include/llvm/IR/Instruction.def b/llvm/include/llvm/IR/Instruction.def
index 949a9d0beecb4..dc4c3c795fad7 100644
--- a/llvm/include/llvm/IR/Instruction.def
+++ b/llvm/include/llvm/IR/Instruction.def
@@ -220,7 +220,9 @@ 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)
+HANDLE_OTHER_INST(70, BitInsert, BitInsertInst) // BitInsert Instruction.
+HANDLE_OTHER_INST(71, BitExtract, BitExtractInst) // BitExtract Instruction
+  LAST_OTHER_INST(71)
 
 #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 365a4eee54eb6..400d996710b44 100644
--- a/llvm/include/llvm/IR/Instructions.h
+++ b/llvm/include/llvm/IR/Instructions.h
@@ -5415,6 +5415,87 @@ class FreezeInst : public UnaryInstruction {
   }
 };
 
+//===----------------------------------------------------------------------===//
+//                              BitInsert Class
+//===----------------------------------------------------------------------===//
+class BitInsertInst : public Instruction {
+  constexpr static IntrusiveOperandsAllocMarker AllocMarker{3};
+  LLVM_ABI explicit BitInsertInst(Value *Base, Value *Val, Value *Offset,
+                                  const Twine &NameStr = "",
+                                  InsertPosition InsertBefore = nullptr);
+
+protected:
+  // Note: Instruction needs to be a friend here to call cloneImpl.
+  friend class Instruction;
+  /// Clone an identical FreezeInst
+  LLVM_ABI BitInsertInst *cloneImpl() const;
+
+public:
+  static BitInsertInst *Create(Value *Base, Value *Val, Value *Offset,
+                               const Twine &NameStr = "",
+                               InsertPosition InsertBefore = nullptr) {
+    return new (AllocMarker)
+        BitInsertInst(Base, Val, Offset, NameStr, InsertBefore);
+  }
+  /// Transparently provide more efficient getOperand methods.
+  DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
+  /// Return true if an bitinsert instruction can be
+  /// formed with the specified operands.
+  LLVM_ABI static bool isValidOperands(const Value *Base, const Value *Val,
+                                       const Value *Offset);
+  // Methods for support type inquiry through isa, cast, and dyn_cast:
+  static inline bool classof(const Instruction *I) {
+    return I->getOpcode() == BitInsert;
+  }
+  static inline bool classof(const Value *V) {
+    return isa<Instruction>(V) && classof(cast<Instruction>(V));
+  }
+};
+template <>
+struct OperandTraits<BitInsertInst>
+    : public FixedNumOperandTraits<BitInsertInst, 3> {};
+DEFINE_TRANSPARENT_OPERAND_ACCESSORS(BitInsertInst, Value)
+
+//===----------------------------------------------------------------------===//
+//                              BitExtract Class
+//===----------------------------------------------------------------------===//
+class BitExtractInst : public Instruction {
+  constexpr static IntrusiveOperandsAllocMarker AllocMarker{2};
+  LLVM_ABI BitExtractInst(Type *Ty, Value *Src, Value *Offset,
+                          const Twine &NameStr = "",
+                          InsertPosition InsertBefore = nullptr);
+
+protected:
+  // Note: Instruction needs to be a friend here to call cloneImpl.
+  friend class Instruction;
+  /// Clone an identical FreezeInst
+  LLVM_ABI BitExtractInst *cloneImpl() const;
+
+public:
+  static BitExtractInst *Create(Type *Ty, Value *Src, Value *Offset,
+                                const Twine &NameStr = "",
+                                InsertPosition InsertBefore = nullptr) {
+    return new (AllocMarker)
+        BitExtractInst(Ty, Src, Offset, NameStr, InsertBefore);
+  }
+  /// Transparently provide more efficient getOperand methods.
+  DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
+  /// Return true if an bitextract instruction can be
+  /// formed with the specified operands.
+  LLVM_ABI static bool isValidOperands(const Type *Ty, const Value *Val,
+                                       const Value *Offset);
+  // Methods for support type inquiry through isa, cast, and dyn_cast:
+  static inline bool classof(const Instruction *I) {
+    return I->getOpcode() == BitExtract;
+  }
+  static inline bool classof(const Value *V) {
+    return isa<Instruction>(V) && classof(cast<Instruction>(V));
+  }
+};
+template <>
+struct OperandTraits<BitExtractInst>
+    : public FixedNumOperandTraits<BitExtractInst, 2> {};
+DEFINE_TRANSPARENT_OPERAND_ACCESSORS(BitExtractInst, Value)
 } // end namespace llvm
 
 #endif // LLVM_IR_INSTRUCTIONS_H
diff --git a/llvm/include/llvm/IR/NoFolder.h b/llvm/include/llvm/IR/NoFolder.h
index a8dbbf5eeb1c2..24b7856bc55df 100644
--- a/llvm/include/llvm/IR/NoFolder.h
+++ b/llvm/include/llvm/IR/NoFolder.h
@@ -109,6 +109,16 @@ class LLVM_ABI NoFolder final : public IRBuilderFolder {
     return nullptr;
   }
 
+  Value *FoldBitInsert(Value *Base, Value *Val,
+                      Value *Offset) const override {
+    return nullptr;
+  }
+  
+  Value *FoldBitExtract(Type *Ty, Value *Src,
+                        Value *Offset) const override {
+    return nullptr;
+  }
+
   Value *FoldCast(Instruction::CastOps Op, Value *V,
                   Type *DestTy) const override {
     return nullptr;
diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp
index e7d7cc4ba88ea..26d04800aef36 100644
--- a/llvm/lib/AsmParser/LLLexer.cpp
+++ b/llvm/lib/AsmParser/LLLexer.cpp
@@ -996,6 +996,8 @@ lltok::Kind LLLexer::LexIdentifier() {
   INSTKEYWORD(cleanuppad,   CleanupPad);
 
   INSTKEYWORD(freeze,       Freeze);
+  INSTKEYWORD(bitinsert,    BitInsert);
+  INSTKEYWORD(bitextract,   BitExtract);
 
 #undef INSTKEYWORD
 
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index 990febaacbe48..eb6da0bbe256f 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -4736,6 +4736,12 @@ bool LLParser::parseValID(ValID &ID, PerFunctionState *PFS, Type *ExpectedTy) {
         return true;
     }
 
+    if (Opc == Instruction::BitExtract) {
+      if (parseType(Ty) ||
+          parseToken(lltok::comma, "expected comma after bitextract's type"))
+        return true;
+    }
+
     if (parseGlobalValueVector(Elts) ||
         parseToken(lltok::rparen, "expected ')' in constantexpr"))
       return true;
@@ -7721,6 +7727,10 @@ int LLParser::parseInstruction(Instruction *&Inst, BasicBlock *BB,
     return parseLandingPad(Inst, PFS);
   case lltok::kw_freeze:
     return parseFreeze(Inst, PFS);
+  case lltok::kw_bitinsert:
+    return parseBitInsert(Inst, PFS);
+  case lltok::kw_bitextract:
+    return parseBitExtract(Inst, PFS);
   // Call.
   case lltok::kw_call:
     return parseCall(Inst, PFS, CallInst::TCK_None);
@@ -8538,6 +8548,45 @@ bool LLParser::parseInsertElement(Instruction *&Inst, PerFunctionState &PFS) {
   return false;
 }
 
+// parseBitExtract
+// ::= 'bitextract' Type ',' TypeAndValue ',' TypeAndValue
+bool LLParser::parseBitExtract(Instruction *&Inst, PerFunctionState &PFS) {
+  LocTy Loc;
+  Type *Ty = nullptr;
+  Value *Op0, *Op1;
+  if (parseType(Ty, Loc) ||
+      parseToken(lltok::comma, "expected ',' after bitextract type") ||
+      parseTypeAndValue(Op0, Loc, PFS) ||
+      parseToken(lltok::comma, "expected ',' after bitextract source value") ||
+      parseTypeAndValue(Op1, PFS))
+    return true;
+
+  if (!BitExtractInst::isValidOperands(Ty, Op0, Op1))
+    return error(Loc, "invalid bitextract operands");
+
+  Inst = BitExtractInst::Create(Ty, Op0, Op1);
+  return false;
+}
+
+// parseBitInsert
+// ::= 'bitinsert' TypeAndValue ',' TypeAndValue ',' TypeAndValue
+bool LLParser::parseBitInsert(Instruction *&Inst, PerFunctionState &PFS) {
+  LocTy Loc;
+  Value *Op0, *Op1, *Op2;
+  if (parseTypeAndValue(Op0, Loc, PFS) ||
+      parseToken(lltok::comma, "expected ',' after bitinsert source value") ||
+      parseTypeAndValue(Op1, PFS) ||
+      parseToken(lltok::comma, "expected ',' after bitinsert insert value") ||
+      parseTypeAndValue(Op2, PFS))
+    return true;
+
+  if (!BitInsertInst::isValidOperands(Op0, Op1, Op2))
+    return error(Loc, "invalid bitinsert operands");
+
+  Inst = BitInsertInst::Create(Op0, Op1, Op2);
+  return false;
+}
+
 /// parseShuffleVector
 ///   ::= 'shufflevector' TypeAndValue ',' TypeAndValue ',' TypeAndValue
 bool LLParser::parseShuffleVector(Instruction *&Inst, PerFunctionState &PFS) {
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index 3e863f4786e1a..ef28f922a3b45 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -1837,6 +1837,14 @@ Expected<Value *> BitcodeReader::materializeValue(unsigned StartValID,
         I = new ShuffleVectorInst(Ops[0], Ops[1], Ops[2], "constexpr",
                                   InsertBB);
         break;
+      case Instruction::BitExtract:
+        I = BitExtractInst::Create(BC->getType(), Ops[0], Ops[1],
+                                   "constexpr", InsertBB);
+        break;
+      case Instruction::BitInsert:
+        I = BitInsertInst::Create(Ops[0], Ops[1], Ops[2], "constexpr",
+                                  InsertBB);
+        break;
       default:
         llvm_unreachable("Unhandled bitcode constant");
       }
@@ -5546,6 +5554,37 @@ Error BitcodeReader::parseFunctionBody(Function *F) {
       break;
     }
 
+    case bitc::FUNC_CODE_INST_BITINSERT: { // BITINSERT: [ty, opval, opval, opval]
+      unsigned OpNum = 0;
+      Value *Base, *Val, *Offset;
+      unsigned BaseTypeID, ValTypeID, OffsetTypeID;
+      if (getValueTypePair(Record, OpNum, NextValueNo, Base, BaseTypeID, CurBB) ||
+          getValueTypePair(Record, OpNum, NextValueNo, Val, ValTypeID, CurBB) ||
+          getValueTypePair(Record, OpNum, NextValueNo, Offset, OffsetTypeID,
+                           CurBB))
+        return error("Invalid bitinsert record");
+      I = BitInsertInst::Create(Base, Val, Offset);
+      ResTypeID = BaseTypeID;
+      InstructionList.push_back(I);
+      break;
+    }
+
+    case bitc::FUNC_CODE_INST_BITEXTRACT: { // BITEXTRACT: [ty, opval, opval]
+      unsigned OpNum = 0;
+      unsigned TypeID = Record[OpNum++];
+      Type *ResTy = getTypeByID(TypeID);
+      Value *Src, *Offset;
+      unsigned SrcTypeID, OffsetTypeID;
+      if (getValueTypePair(Record, OpNum, NextValueNo, Src, SrcTypeID, CurBB) ||
+          getValueTypePair(Record, OpNum, NextValueNo, Offset, OffsetTypeID,
+                           CurBB))
+        return error("Invalid bitextract record");
+      I = BitExtractInst::Create(ResTy, Src, Offset);
+      ResTypeID = TypeID;
+      InstructionList.push_back(I);
+      break;
+    }
+
     case bitc::FUNC_CODE_INST_SHUFFLEVEC: {// SHUFFLEVEC: [opval,ty,opval,opval]
       unsigned OpNum = 0;
       Value *Vec1, *Vec2, *Mask;
diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index ed7f95701ea65..55f2d7f1c0f06 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -3289,6 +3289,18 @@ void ModuleBitcodeWriter::writeInstruction(const Instruction &I,
     pushValue(I.getOperand(1), InstID, Vals);
     pushValueAndType(I.getOperand(2), InstID, Vals);
     break;
+  case Instruction::BitExtract:
+    Code = bitc::FUNC_CODE_INST_BITEXTRACT;
+    Vals.push_back(VE.getTypeID(I.getType()));
+    pushValueAndType(I.getOperand(0), InstID, Vals);
+    pushValue(I.getOperand(1), InstID, Vals);
+    break;
+  case Instruction::BitInsert:
+    Code = bitc::FUNC_CODE_INST_BITINSERT;
+    pushValueAndType(I.getOperand(0), InstID, Vals);
+    pushValueAndType(I.getOperand(1), InstID, Vals);
+    pushValue(I.getOperand(2), InstID, Vals);
+    break;
   case Instruction::ShuffleVector:
     Code = bitc::FUNC_CODE_INST_SHUFFLEVEC;
     pushValueAndType(I.getOperand(0), InstID, Vals);
diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
index 8c8e08865744a..204b1dc4424fe 100644
--- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
@@ -3524,6 +3524,76 @@ bool IRTranslator::translateShuffleVector(const User &U,
   return true;
 }
 
+bool IRTranslator::translateBitInsert(const User &U,
+                                      MachineIRBuilder &MIRBuilder) {
+  Register Res    = getOrCreateVReg(U);
+  Register Base   = getOrCreateVReg(*U.getOperand(0));
+  Register Val    = getOrCreateVReg(*U.getOperand(1));
+  Register Offset = getOrCreateVReg(*U.getOperand(2));
+  MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
+  LLT BaseTy = MRI.getType(Base);
+  LLT ValTy  = MRI.getType(Val);
+
+  // Convert Offset to BaseTy
+  Register LegalOffset = MIRBuilder.buildZExtOrTrunc(BaseTy, Offset).getReg(0);
+
+  // RotateAmount = Offset + width(Val)
+  unsigned ValBitWidth = ValTy.getSizeInBits();
+  Register ValWidth = MIRBuilder.buildConstant(BaseTy, ValBitWidth).getReg(0);
+  Register RotateAmount = MIRBuilder.buildAdd(BaseTy, LegalOffset, ValWidth).getReg(0);
+
+  Register RotatedBase = MIRBuilder.buildRotateLeft(BaseTy, Base, RotateAmount).getReg(0);
+
+  // Truncate or extend Val to BaseTy so only the inserted bit range remains.
+  Register ExtVal = MIRBuilder.buildZExtOrTrunc(BaseTy, Val).getReg(0);
+
+  // Clear the low ValBitWidth bits of the rotated base and insert Val there.
+  unsigned BaseBitWidth = BaseTy.getSizeInBits();
+  APInt ClearMask =
+      APInt::getHighBitsSet(BaseBitWidth, BaseBitWidth - ValBitWidth);
+  Register MaskConst = MIRBuilder.buildConstant(BaseTy, ClearMask).getReg(0);
+  Register ClearedBase =
+      MIRBuilder.buildAnd(BaseTy, RotatedBase, MaskConst).getReg(0);
+  Register Inserted = MIRBuilder.buildOr(BaseTy, ClearedBase, ExtVal).getReg(0);
+
+  // Restore bit positions
+  MIRBuilder.buildRotateRight(Res, Inserted, RotateAmount);
+  return true;
+}
+
+bool IRTranslator::translateBitExtract(const User &U,
+                                       MachineIRBuilder &MIRBuilder) {
+  Register Res    = getOrCreateVReg(U);
+  Register Src    = getOrCreateVReg(*U.getOperand(0));
+  Register Offset = getOrCreateVReg(*U.getOperand(1));
+  MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
+  LLT SrcTy = MRI.getType(Src);
+  LLT ResTy = MRI.getType(Res);
+
+  if (ResTy.getSizeInBits() > SrcTy.getSizeInBits())
+    llvm_unreachable(
+        "bitextract result wider than source should be rejected by verifier");
+
+  // Convert Offset to SrcTy
+  Register LegalOffset = MIRBuilder.buildZExtOrTrunc(SrcTy, Offset).getReg(0);
+
+  // RotateAmount = Offset + width
+  unsigned ResultBitWidth = ResTy.getSizeInBits();
+  Register ResultWidth = MIRBuilder.buildConstant(SrcTy, ResultBitWidth).getReg(0);
+  Register RotateAmount = MIRBuilder.buildAdd(SrcTy, LegalOffset, ResultWidth).getReg(0);
+
+  // Rotate left by (Offset + ResultWidth)
+  Register Rotated = MIRBuilder.buildRotateLeft(SrcTy, Src, RotateAmount).getReg(0);
+
+  // Truncating to ResTy discards the high bits for free
+  if (SrcTy == ResTy)
+    MIRBuilder.buildCopy(Res, Rotated);
+  else
+    MIRBuilder.buildTrunc(Res, Rotated);
+
+  return true;
+}
+
 bool IRTranslator::translatePHI(const User &U, MachineIRBuilder &MIRBuilder) {
   const PHINode &PI = cast<PHINode>(U);
 
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 579bff7d3ab60..124633e362dfb 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -4151,6 +4151,73 @@ void SelectionDAGBuilder::visitInsertElement(const User &I) {
                            InVec, InVal, InIdx));
 }
 
+void SelectionDAGBuilder::visitBitInsert(const User &I) {
+  SDValue Base   = getValue(I.getOperand(0));
+  SDValue Val    = getValue(I.getOperand(1));
+  SDValue Offset = getValue(I.getOperand(2));
+  EVT BaseVT = Base.getValueType();
+  EVT ValVT  = Val.getValueType();
+  const TargetLowering &TLI = DAG.getTargetLoweringInfo();
+  SDLoc dl = getCurSDLoc();
+
+  SDValue LegalOffset = DAG.getZExtOrTrunc(Offset, dl, BaseVT);
+
+  unsigned ValBitWidth = ValVT.getScalarSizeInBits();
+  SDValue ValWidth = DAG.getConstant(ValBitWidth, dl, BaseVT);
+  SDValue RotateAmount = DAG.getNode(ISD::ADD, dl, BaseVT, LegalOffset, ValWidth);
+
+  // Legalize rotate amount to the target's shift amount type
+  EVT ShiftAmtTy = TLI.getShiftAmountTy(BaseVT, DAG.getDataLayout());
+  SDValue LegalRotateAmount = DAG.getZExtOrTrunc(RotateAmount, dl, ShiftAmtTy);
+
+  SDValue RotatedBase = DAG.getNode(ISD::ROTL, dl, BaseVT, Base, LegalRotateAmount);
+
+  unsigned BaseBitWidth = BaseVT.getScalarSizeInBits();
+  APInt ClearMask = APInt::getHighBitsSet(BaseBitWidth, BaseBitWidth - ValBitWidth);
+  SDValue ClearedBase = DAG.getNode(ISD::AND, dl, BaseVT, RotatedBase,
+                                    DAG.getConstant(ClearMask, dl, BaseVT));
+
+  SDValue ExtVal  = DAG.getZExtOrTrunc(Val, dl, BaseVT);
+  SDValue Inserted = DAG.getNode(ISD::OR, dl, BaseVT, ClearedBase, ExtVal);
+
+  SDValue Result = DAG.getNode(ISD::ROTR, dl, BaseVT, Inserted, LegalRotateAmount);
+  setValue(&I, Result);
+}
+
+void SelectionDAGBuilder::visitBitExtract(const User &I) {
+  SDValue Src    = getValue(I.getOperand(0));
+  SDValue Offset = getValue(I.getOperand(1));
+  EVT SrcVT    = Src.getValueType();
+  const TargetLowering &TLI = DAG.getTargetLoweringInfo();
+  EVT ResultVT = TLI.getValueType(DAG.getDataLayout(), I.getType());
+  SDLoc dl = getCurSDLoc();
+
+  // The verifier guarantees the result type is not wider than the source
+  // type, so reject any widening case here. getZExtOrTrunc handles the
+  // equal-width and narrower cases.
+  if (ResultVT.getSizeInBits() > SrcVT.getSizeInBits())
+    llvm_unreachable(
+        "bitextract result wider than source should be rejected by verifier");
+
+  // Convert offset to SrcVT
+  SDValue LegalOffset = DAG.getZExtOrTrunc(Offset, dl, SrcVT);
+
+  // RotateAmount = Offset + width(Result), computed in SrcVT
+  unsigned ResultBitWidth = ResultVT.getScalarSizeInBits();
+  SDValue ResultWidth = DAG.getConstant(ResultBitWidth, dl, SrcVT);
+  SDValue RotateAmount = DAG.getNode(ISD::ADD, dl, SrcVT, LegalOffset, ResultWidth);
+
+  // Legalize rotate amount to the target's shift amount type
+  EVT ShiftAmtTy = TLI.getShiftAmountTy(SrcVT, DAG.getDataLayout());
+  SDValue LegalRotateAmount = DAG.getZExtOrTrunc(RotateAmount, dl, ShiftAmtTy);
+
+  // Rotate left by (Offset + ResultWidth) — brings target field to bit 0
+  SDValue Rotated = DAG.getNode(ISD::ROTL, dl, SrcVT, Src, LegalRotateAmount);
+
+  // Truncating to ResultVT discards the high bits for free
+  setValue(&I, DAG.getZExtOrTrunc(Rotated, dl, ResultVT));
+}
+
 void SelectionDAGBuilder::visitExtractElement(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 21aac333a73cd..eab52ff3f24b5 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
@@ -615,6 +615,9 @@ class SelectionDAGBuilder {
   void visitGetElementPtr(const User &I);
   void visitSelect(const User &I);
 
+  void visitBitInsert(const User &I);
+  void visitBitExtract(const User &I);
+
   void visitAlloca(const AllocaInst &I);
   void visitLoad(const LoadInst &I);
   void visitStore(const StoreInst &I);
diff --git a/llvm/lib/CodeGen/TargetLoweringBase.cpp b/llvm/lib/CodeGen/TargetLoweringBase.cpp
index 1f4842fb3df15..701c2b58014bc 100644
--- a/llvm/lib/CodeGen/TargetLoweringBase.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringBase.cpp
@@ -2299,6 +2299,8 @@ int TargetLoweringBase::InstructionOpcodeToISD(unsigned Opcode) const {
   case InsertValue:    return ISD::MERGE_VALUES;
   case LandingPad:     return 0;
   case Freeze:         return ISD::FREEZE;
+  case BitInsert:      return 0;
+  case BitExtract:     return 0;
   }
 
   llvm_unreachable("Unknown instruction type encountered!");
diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp
index 106fd6541360c..334204ea7fabb 100644
--- a/llvm/lib/IR/AsmWriter.cpp
+++ b/llvm/lib/IR/AsmWriter.cpp
@@ -4790,9 +4790,9 @@ void AssemblyWriter::printInstruction(const Instruction &I) {
       Out << ' ';
       TypePrinter.print(GEP->getSourceElementType(), Out);
       Out << ',';
-    } else if (const auto *LI = dyn_cast<LoadInst>(&I)) {
+    } else if (isa<BitExtractInst>(I) || isa<LoadInst>(I)) {
       Out << ' ';
-      TypePrinter.print(LI->getType(), Out);
+      TypePrinter.print(I.getType(), Out);
       Out << ',';
     }
 
diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp
index 5e6b03d01b6ba..67572f436330c 100644
--- a/llvm/lib/IR/Core.cpp
+++ b/llvm/lib/IR/Core.cpp
@@ -4497,6 +4497,20 @@ LLVMValueRef LLVMBuildFreeze(LLVMBuilderRef B, LLVMValueRef Val,
   return wrap(unwrap(B)->CreateFreeze(unwrap(Val), Name));
 }
 
+LLVMValueRef LLVMBuildBitInsert(LLVMBuilderRef B, LLVMValueRef Base,
+                                    LLVMValueRef Val, LLVMValueRef Offset,
+                                    const char *Name) {
+  return wrap(unwrap(B)->CreateBitInsert(unwrap(Base), unwrap(Val),
+                                             unwrap(Offset), Name));
+}
+
+LLVMValueRef LLVMBuildBitExtract(LLVMBuilderRef B, LLVMTypeRef Ty,
+                                    LLVMValueRef Src, LLVMValueRef Offset,
+                                    const char *Name) {
+  return wrap(unwrap(B)->CreateBitExtract(unwrap(Ty), unwrap(Src),
+                                             unwrap(Offset), Name));
+}
+
 LLVMValueRef LLVMBuildIsNull(LLVMBuilderRef B, LLVMValueRef Val,
                              const char *Name) {
   return wrap(unwrap(B)->CreateIsNull(unwrap(Val), Name));
diff --git a/llvm/lib/IR/Instruction.cpp b/llvm/lib/IR/Instruction.cpp
index ac209ffa72aae..fc1e2885253f5 100644
--- a/llvm/lib/IR/Instruction.cpp
+++ b/llvm/lib/IR/Instruction.cpp
@@ -889,6 +889,8 @@ const char *Instruction::getOpcodeName(unsigned OpCode) {
   case LandingPad:     return "landingpad";
   case CleanupPad:     return "cleanuppad";
   case Freeze:         return "freeze";
+  case BitInsert:      return "bitinsert";
+  case BitExtract:     return "bitextract";
 
   default: return "<Invalid operator> ";
   }
diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp
index 088f85c4851cd..d5b028726dffc 100644
--- a/llvm/lib/IR/Instructions.cpp
+++ b/llvm/lib/IR/Instructions.cpp
@@ -2599,6 +2599,55 @@ Type *ExtractValueInst::getIndexedType(Type *Agg,
   return Agg;
 }
 
+//===----------------------------------------------------------------------===//
+//                             BitInsert Class
+//===----------------------------------------------------------------------===//
+BitInsertInst::BitInsertInst(Value *Base, Value *Val, Value *Offset,
+                             const Twine &Name, InsertPosition InsertBef)
+    : Instruction(Base->getType(), BitInsert, AllocMarker, InsertBef) {
+  assert(isValidOperands(Base, Val, Offset) &&
+         "Invalid bitinsert instruction operands!");
+  Op<0>() = Base;
+  Op<1>() = Val;
+  Op<2>() = Offset;
+  setName(Name);
+}
+
+bool BitInsertInst::isValidOperands(const Value *Base, const Value *Val,
+                                    const Value *Offset) {
+  if (!Base->getType()->isByteTy())
+    return false; // First operand of bitinsert must be byte type.
+  if (!Val->getType()->isFirstClassType())
+    return false; // Second operand of bitinsert must be a first-class type.
+  if (!Offset->getType()->isIntegerTy(32))
+    return false; // Third operand of bitinsert must be i32.
+  return true;
+}
+
+//===----------------------------------------------------------------------===//
+//                             BitExtract Class
+//===----------------------------------------------------------------------===//
+BitExtractInst::BitExtractInst(Type *Ty, Value *Src, Value *Offset,
+                               const Twine &Name, InsertPosition InsertBef)
+    : Instruction(Ty, BitExtract, AllocMarker, InsertBef) {
+  assert(isValidOperands(Ty, Src, Offset) &&
+         "Invalid bitextract instruction operands!");
+  Op<0>() = Src;
+  Op<1>() = Offset;
+  setName(Name);
+}
+
+bool BitExtractInst::isValidOperands(const Type *Ty, const Value *Src,
+                                     const Value *Offset) {
+  if (!Ty->isFirstClassType())
+    return false; // First operand of bitextract must be a first-class type.
+  if (!Src->getType()->isByteTy())
+    return false; // Second operand of bitextract must be a byte type.
+  if (!Offset->getType()->isIntegerTy(32))
+    return false; // Third operand of bitextract must be i32.
+  return true;
+}
+
 //===----------------------------------------------------------------------===//
 //                             UnaryOperator Class
 //===----------------------------------------------------------------------===//
@@ -4533,6 +4582,14 @@ InsertElementInst *InsertElementInst::cloneImpl() const {
   return InsertElementInst::Create(getOperand(0), getOperand(1), getOperand(2));
 }
 
+BitInsertInst *BitInsertInst::cloneImpl() const {
+  return BitInsertInst::Create(getOperand(0), getOperand(1), getOperand(2));
+}
+
+BitExtractInst *BitExtractInst::cloneImpl() const {
+  return BitExtractInst::Create(getType(), getOperand(0), getOperand(1));
+}
+
 ShuffleVectorInst *ShuffleVectorInst::cloneImpl() const {
   return new ShuffleVectorInst(getOperand(0), getOperand(1), getShuffleMask());
 }
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 9c6c5f245ff0b..122de2cd22fdf 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -595,6 +595,8 @@ class Verifier : public InstVisitor<Verifier>, VerifierSupport {
   void visitExtractElementInst(ExtractElementInst &EI);
   void visitInsertElementInst(InsertElementInst &EI);
   void visitShuffleVectorInst(ShuffleVectorInst &EI);
+  void visitBitInsertInst(BitInsertInst &EI);
+  void visitBitExtractInst(BitExtractInst &EI);
   void visitVAArgInst(VAArgInst &VAA) { visitInstruction(VAA); }
   void visitCallInst(CallInst &CI);
   void visitInvokeInst(InvokeInst &II);
@@ -4502,6 +4504,23 @@ void Verifier::visitShuffleVectorInst(ShuffleVectorInst &SV) {
   visitInstruction(SV);
 }
 
+void Verifier::visitBitInsertInst(BitInsertInst &IE) {
+  Check(BitInsertInst::isValidOperands(IE.getOperand(0), IE.getOperand(1),
+                                       IE.getOperand(2)),
+        "Invalid bitinsert operands!", &IE);
+  visitInstruction(IE);
+}
+
+void Verifier::visitBitExtractInst(BitExtractInst &IE) {
+  Check(BitExtractInst::isValidOperands(IE.getType(), IE.getOperand(0),
+                                        IE.getOperand(1)),
+        "Invalid bitextract operands!", &IE);
+  Check(IE.getType()->getPrimitiveSizeInBits() <=
+            IE.getOperand(0)->getType()->getPrimitiveSizeInBits(),
+        "bitextract result type cannot be wider than source type!", &IE);
+  visitInstruction(IE);
+}
+
 void Verifier::visitGetElementPtrInst(GetElementPtrInst &GEP) {
   if (auto *MD = mdconst::extract_or_null<ConstantInt>(
           GEP.getModule()->getModuleFlag("require-logical-pointer")))
diff --git a/llvm/test/Assembler/bitextract-invalid-1.ll b/llvm/test/Assembler/bitextract-invalid-1.ll
new file mode 100644
index 0000000000000..c746b0d9bafe1
--- /dev/null
+++ b/llvm/test/Assembler/bitextract-invalid-1.ll
@@ -0,0 +1,6 @@
+; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s
+; CHECK: invalid bitextract operands
+define i8 @invalid(i32 %src) {
+  %r = bitextract i8, i32 %src, i32 0
+  ret i8 %r
+}
diff --git a/llvm/test/Assembler/bitinsert-bitextract.ll b/llvm/test/Assembler/bitinsert-bitextract.ll
new file mode 100644
index 0000000000000..237a25f0c2744
--- /dev/null
+++ b/llvm/test/Assembler/bitinsert-bitextract.ll
@@ -0,0 +1,15 @@
+; RUN: llvm-as < %s | llvm-dis | FileCheck %s
+
+; CHECK-LABEL: test_bitextract
+; CHECK: bitextract i8, b32 %{{.*}}, i32 24
+define i8 @test_bitextract(b32 %src) {
+  %result = bitextract i8, b32 %src, i32 24
+  ret i8 %result
+}
+
+; CHECK-LABEL: test_bitinsert
+; CHECK: bitinsert b32 %{{.*}}, i8 %{{.*}}, i32 3
+define b32 @test_bitinsert(b32 %base, i8 %val) {
+  %result = bitinsert b32 %base, i8 %val, i32 3
+  ret b32 %result
+}
diff --git a/llvm/test/Assembler/bitinsert-invalid-1.ll b/llvm/test/Assembler/bitinsert-invalid-1.ll
new file mode 100644
index 0000000000000..acec42649ccda
--- /dev/null
+++ b/llvm/test/Assembler/bitinsert-invalid-1.ll
@@ -0,0 +1,6 @@
+; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s
+; CHECK: invalid bitinsert operands
+define i32 @invalid(i32 %base, i8 %val) {
+  %r = bitinsert i32 %base, i8 %val, i32 0
+  ret i32 %r
+}
diff --git a/llvm/test/CodeGen/X86/GlobalISel/bitinsert-bitextract.ll b/llvm/test/CodeGen/X86/GlobalISel/bitinsert-bitextract.ll
new file mode 100644
index 0000000000000..699852b890f45
--- /dev/null
+++ b/llvm/test/CodeGen/X86/GlobalISel/bitinsert-bitextract.ll
@@ -0,0 +1,32 @@
+; RUN: llc -mtriple=x86_64-unknown-linux-gnu -global-isel -stop-after=irtranslator < %s | FileCheck %s
+
+define i16 @test_bitextract(b32 %src, i32 %off) {
+; CHECK-LABEL: name: test_bitextract
+; CHECK: [[SRC:%[0-9]+]]:_(s32) = COPY $edi
+; CHECK: [[WIDTH:%[0-9]+]]:_(s32) = G_CONSTANT i32 16
+; CHECK: [[ADD:%[0-9]+]]:_(s32) = G_ADD %{{[0-9]+}}, [[WIDTH]]
+; CHECK: [[ROTL:%[0-9]+]]:_(s32) = G_ROTL [[SRC]], [[ADD]](s32)
+; CHECK: [[RES:%[0-9]+]]:_(s16) = G_TRUNC [[ROTL]](s32)
+; CHECK: $ax = COPY [[RES]](s16)
+; CHECK: RET 0, implicit $ax
+  %result = bitextract i16, b32 %src, i32 %off
+  ret i16 %result
+}
+
+define b32 @test_bitinsert(b32 %base, i16 %val, i32 %off) {
+; CHECK-LABEL: name: test_bitinsert
+; CHECK: [[BASE:%[0-9]+]]:_(s32) = COPY $edi
+; CHECK: [[VAL:%[0-9]+]]:_(s16) = G_TRUNC %{{[0-9]+}}(s32)
+; CHECK: [[WIDTH:%[0-9]+]]:_(s32) = G_CONSTANT i32 16
+; CHECK: [[ADD:%[0-9]+]]:_(s32) = G_ADD %{{[0-9]+}}, [[WIDTH]]
+; CHECK: [[ROTL:%[0-9]+]]:_(s32) = G_ROTL [[BASE]], [[ADD]](s32)
+; CHECK: [[EXT_VAL:%[0-9]+]]:_(s32) = G_ZEXT [[VAL]](s16)
+; CHECK: [[MASK:%[0-9]+]]:_(s32) = G_CONSTANT i32 -65536
+; CHECK: [[AND:%[0-9]+]]:_(s32) = G_AND [[ROTL]], [[MASK]]
+; CHECK: [[OR:%[0-9]+]]:_(s32) = G_OR [[AND]], [[EXT_VAL]]
+; CHECK: [[ROTR:%[0-9]+]]:_(s32) = G_ROTR [[OR]], [[ADD]](s32)
+; CHECK: $eax = COPY [[ROTR]](s32)
+; CHECK: RET 0, implicit $eax
+  %result = bitinsert b32 %base, i16 %val, i32 %off
+  ret b32 %result
+}
diff --git a/llvm/test/CodeGen/X86/bitinsert-bitextract-x86.ll b/llvm/test/CodeGen/X86/bitinsert-bitextract-x86.ll
new file mode 100644
index 0000000000000..412ebb70e6bd9
--- /dev/null
+++ b/llvm/test/CodeGen/X86/bitinsert-bitextract-x86.ll
@@ -0,0 +1,42 @@
+; RUN: llc -mtriple=x86_64-unknown-linux-gnu < %s | FileCheck %s
+
+define i16 @test_bitextract_var(b32 %src, i32 %off) {
+; CHECK-LABEL: test_bitextract_var:
+; CHECK:       movl %edi, %eax
+; CHECK:       leal 16(%rsi), %ecx
+; CHECK:       roll %cl, %eax
+; CHECK:       retq
+  %result = bitextract i16, b32 %src, i32 %off
+  ret i16 %result
+}
+
+define i16 @test_bitextract_const(b32 %src) {
+; CHECK-LABEL: test_bitextract_const:
+; CHECK:       movl %edi, %eax
+; CHECK:       shrl $8, %eax
+; CHECK:       retq
+  %result = bitextract i16, b32 %src, i32 8
+  ret i16 %result
+}
+
+define i8 @test_bitextract_narrow(b64 %src) {
+; CHECK-LABEL: test_bitextract_narrow:
+; CHECK:       movq %rdi, %rax
+; CHECK:       shrq $56, %rax
+; CHECK:       retq
+  %result = bitextract i8, b64 %src, i32 0
+  ret i8 %result
+}
+
+define b32 @test_bitinsert_var(b32 %base, i16 %val, i32 %off) {
+; CHECK-LABEL: test_bitinsert_var:
+; CHECK:       leal 16(%rdx), %ecx
+; CHECK:       roll %cl, %edi
+; CHECK:       andl $-65536, %edi
+; CHECK:       movzwl %si, %eax
+; CHECK:       orl %edi, %eax
+; CHECK:       rorl %cl, %eax
+; CHECK:       retq
+  %result = bitinsert b32 %base, i16 %val, i32 %off
+  ret b32 %result
+}
diff --git a/llvm/test/ExecutionEngine/bitinsert-bitextract-runtime.ll b/llvm/test/ExecutionEngine/bitinsert-bitextract-runtime.ll
new file mode 100644
index 0000000000000..4853669cd21dc
--- /dev/null
+++ b/llvm/test/ExecutionEngine/bitinsert-bitextract-runtime.ll
@@ -0,0 +1,29 @@
+; RUN: %lli %s | FileCheck %s
+; CHECK: extract=0x3456 insert=0x12beef78
+
+ at .str = private unnamed_addr constant [30 x i8] c"extract=0x%04x insert=0x%08x\0A\00", align 1
+
+declare i32 @printf(ptr, ...)
+
+define i16 @test_bitextract_var(b32 %src, i32 %off) noinline {
+  %result = bitextract i16, b32 %src, i32 %off
+  ret i16 %result
+}
+
+define b32 @test_bitinsert_var(b32 %base, i16 %val, i32 %off) noinline {
+  %result = bitinsert b32 %base, i16 %val, i32 %off
+  ret b32 %result
+}
+
+define i32 @main() {
+  ; Test values: 305419896 is 0x12345678, 48879 is 0xBEEF
+  %extract = call i16 @test_bitextract_var(b32 305419896, i32 8)
+  %insert = call b32 @test_bitinsert_var(b32 305419896, i16 48879, i32 8)
+  
+  %extract32 = zext i16 %extract to i32
+  %insert32 = bitcast b32 %insert to i32
+  
+  %fmt = getelementptr inbounds [30 x i8], ptr @.str, i64 0, i64 0
+  %call = call i32 (ptr, ...) @printf(ptr %fmt, i32 %extract32, i32 %insert32)
+  ret i32 0
+}
diff --git a/llvm/test/Verifier/bitextract-invalid-verifier.ll b/llvm/test/Verifier/bitextract-invalid-verifier.ll
new file mode 100644
index 0000000000000..9a1d30672089c
--- /dev/null
+++ b/llvm/test/Verifier/bitextract-invalid-verifier.ll
@@ -0,0 +1,8 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: not llvm-as %s 2>&1 | FileCheck %s
+; CHECK: bitextract result type cannot be wider than source type!
+
+define i64 @invalid(b32 %src) {
+  %r = bitextract i64, b32 %src, i32 0
+  ret i64 %r
+}
diff --git a/llvm/tools/llvm-c-test/echo.cpp b/llvm/tools/llvm-c-test/echo.cpp
index 5ed1eaa459d88..c15a013ab80e0 100644
--- a/llvm/tools/llvm-c-test/echo.cpp
+++ b/llvm/tools/llvm-c-test/echo.cpp
@@ -1002,6 +1002,20 @@ struct FunCloner {
         Dst = LLVMBuildFreeze(Builder, Arg, Name);
         break;
       }
+      case LLVMBitInsert: {
+        LLVMValueRef Base = CloneValue(LLVMGetOperand(Src, 0));
+        LLVMValueRef Val = CloneValue(LLVMGetOperand(Src, 1));
+        LLVMValueRef Offset = CloneValue(LLVMGetOperand(Src, 2));
+        Dst = LLVMBuildBitInsert(Builder, Base, Val, Offset, Name);
+        break;
+      }
+      case LLVMBitExtract: {
+        LLVMTypeRef Type = CloneType(LLVMTypeOf(Src));
+        LLVMValueRef SrcV = CloneValue(LLVMGetOperand(Src, 0));
+        LLVMValueRef Offset = CloneValue(LLVMGetOperand(Src, 1));
+        Dst = LLVMBuildBitExtract(Builder, Type, SrcV, Offset, Name);
+        break;
+      }
       case LLVMFence: {
         LLVMAtomicOrdering Ordering = LLVMGetOrdering(Src);
         Dst = LLVMBuildFenceSyncScope(Builder, Ordering,

>From 8cd10b1666588acd6f06bd776e376a1519227aa5 Mon Sep 17 00:00:00 2001
From: Pedro Vicente <pedro.costa.vicente at tecnico.ulisboa.pt>
Date: Sat, 30 May 2026 16:53:31 +0100
Subject: [PATCH 2/9] [IR] Implementation and lowering of bitinsert and
 bitextract This commit implements bitinsert and bitextract instructions to
 manipulate Byte types. These were lowered to SDAG and GlobalISel, and tests
 for IR and X86 were added.

Co-authored-by: Guilherme Lopes <guilhermeglopes at tecnico.ulisboa.pt>
---
 llvm/docs/LangRef.rst                         | 82 +++++++++++++++++++
 llvm/include/llvm-c/Core.h                    | 12 +++
 .../llvm/Analysis/InstSimplifyFolder.h        | 12 +++
 llvm/include/llvm/Analysis/TargetFolder.h     | 10 +++
 llvm/include/llvm/AsmParser/LLParser.h        |  2 +
 llvm/include/llvm/AsmParser/LLToken.h         |  2 +
 llvm/include/llvm/Bitcode/LLVMBitCodes.h      |  2 +
 .../llvm/CodeGen/GlobalISel/IRTranslator.h    |  3 +
 llvm/include/llvm/IR/ConstantFolder.h         | 10 +++
 llvm/include/llvm/IR/IRBuilder.h              | 14 ++++
 llvm/include/llvm/IR/IRBuilderFolder.h        |  6 ++
 llvm/include/llvm/IR/InstVisitor.h            |  2 +
 llvm/include/llvm/IR/Instruction.def          |  4 +-
 llvm/include/llvm/IR/Instructions.h           | 81 ++++++++++++++++++
 llvm/include/llvm/IR/NoFolder.h               | 10 +++
 llvm/lib/AsmParser/LLLexer.cpp                |  2 +
 llvm/lib/AsmParser/LLParser.cpp               | 49 +++++++++++
 llvm/lib/Bitcode/Reader/BitcodeReader.cpp     | 39 +++++++++
 llvm/lib/Bitcode/Writer/BitcodeWriter.cpp     | 12 +++
 llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp  | 70 ++++++++++++++++
 .../SelectionDAG/SelectionDAGBuilder.cpp      | 67 +++++++++++++++
 .../SelectionDAG/SelectionDAGBuilder.h        |  3 +
 llvm/lib/CodeGen/TargetLoweringBase.cpp       |  2 +
 llvm/lib/IR/AsmWriter.cpp                     |  4 +-
 llvm/lib/IR/Core.cpp                          | 14 ++++
 llvm/lib/IR/Instruction.cpp                   |  2 +
 llvm/lib/IR/Instructions.cpp                  | 57 +++++++++++++
 llvm/lib/IR/Verifier.cpp                      | 19 +++++
 llvm/test/Assembler/bitextract-invalid-1.ll   |  6 ++
 llvm/test/Assembler/bitinsert-bitextract.ll   | 15 ++++
 llvm/test/Assembler/bitinsert-invalid-1.ll    |  6 ++
 .../X86/GlobalISel/bitinsert-bitextract.ll    | 32 ++++++++
 .../CodeGen/X86/bitinsert-bitextract-x86.ll   | 42 ++++++++++
 .../bitinsert-bitextract-runtime.ll           | 29 +++++++
 .../Verifier/bitextract-invalid-verifier.ll   |  8 ++
 llvm/tools/llvm-c-test/echo.cpp               | 14 ++++
 36 files changed, 741 insertions(+), 3 deletions(-)
 create mode 100644 llvm/test/Assembler/bitextract-invalid-1.ll
 create mode 100644 llvm/test/Assembler/bitinsert-bitextract.ll
 create mode 100644 llvm/test/Assembler/bitinsert-invalid-1.ll
 create mode 100644 llvm/test/CodeGen/X86/GlobalISel/bitinsert-bitextract.ll
 create mode 100644 llvm/test/CodeGen/X86/bitinsert-bitextract-x86.ll
 create mode 100644 llvm/test/ExecutionEngine/bitinsert-bitextract-runtime.ll
 create mode 100644 llvm/test/Verifier/bitextract-invalid-verifier.ll

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 81694139fcea2..75a2f100c5536 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -11517,6 +11517,88 @@ Example:
       <result> = xor i32 4, 8            ; yields i32:result = 12
       <result> = xor i32 %V, -1          ; yields i32:result = ~%V
 
+Byte Operations
+-----------------
+
+Instructions for bit manipulation for bytes.
+
+.. _i_bitextract:
+
+'``bitextract``' Instruction
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Syntax:
+"""""""
+
+::
+
+      <result> = bitextract <ty>, <tx> <source>, i32 <offset>
+
+Overview:
+"""""""""
+
+The '``bitextract``' extracts a value from a byte.
+
+Arguments:
+""""""""""
+The '``bitextract``' instruction takes any first-class type ty (the
+return type), a Byte value source, and an offset.
+
+Semantics:
+""""""""""
+
+The '``bitextract``' instruction returns a value of the specified type.
+The returned value is first extracted from the source, starting at the
+bit specified by the offset, and then bitcasted to the return type.
+If the range offset+ty.bitwidth exceeds the source width, it returns
+poison. Bit 0 is the most significant bit.
+
+Example:
+""""""""
+
+.. code-block:: text
+
+      %result = bitextract i8, b32 %src, i32 24 ; Extract the last 8 bits from %src and return an 8-bit integer
+
+.. _i_bitinsert:
+
+'``bitinsert``' Instruction
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Syntax:
+"""""""
+
+::
+
+      <result> = bitinsert <tx> <base>, <ty> <val>, i32 <offset>
+
+Overview:
+"""""""""
+
+This instruction '``bitinsert``' inserts a value into a specific
+position within a byte.
+
+Arguments:
+""""""""""
+The first argument (base) of '``bitinsert``' must be of a byte type.
+The second operand (val) must be an arbitrary type.
+
+Semantics:
+""""""""""
+
+The returned value is of the same byte type as the first argument.
+It returns the first argument where the bits in the range
+[offset, offset + ty.bitlength - 1] have been replaced with val.
+If the range (offset + ty.bitwidth) is greater than the bitwidth of
+the first argument, it returns poison. Bit 0 is the most significant bit.
+
+Example:
+""""""""
+
+.. code-block:: text
+
+      %result = bitinsert b32 %x, i8 %y, i32 3 ; Inserts the %y bits into %x with an offset of 3
+
 Vector Operations
 -----------------
 
diff --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h
index 86f636c636783..6aae7fc30dab6 100644
--- a/llvm/include/llvm-c/Core.h
+++ b/llvm/include/llvm-c/Core.h
@@ -133,6 +133,8 @@ typedef enum {
   LLVMExtractValue   = 53,
   LLVMInsertValue    = 54,
   LLVMFreeze         = 68,
+  LLVMBitInsert      = 72,
+  LLVMBitExtract     = 73,
 
   /* Atomic operators */
   LLVMFence          = 55,
@@ -5142,6 +5144,16 @@ LLVM_C_ABI LLVMValueRef LLVMBuildInsertValue(LLVMBuilderRef,
                                              unsigned Index, const char *Name);
 LLVM_C_ABI LLVMValueRef LLVMBuildFreeze(LLVMBuilderRef, LLVMValueRef Val,
                                         const char *Name);
+LLVM_C_ABI LLVMValueRef LLVMBuildBitExtract(LLVMBuilderRef,
+                                            LLVMTypeRef Type,
+                                            LLVMValueRef Src,
+                                            LLVMValueRef Offset,
+                                            const char *Name);
+LLVM_C_ABI LLVMValueRef LLVMBuildBitInsert(LLVMBuilderRef,
+                                           LLVMValueRef Base,
+                                           LLVMValueRef Val,
+                                           LLVMValueRef Offset,
+                                           const char *Name);
 
 LLVM_C_ABI LLVMValueRef LLVMBuildIsNull(LLVMBuilderRef, LLVMValueRef Val,
                                         const char *Name);
diff --git a/llvm/include/llvm/Analysis/InstSimplifyFolder.h b/llvm/include/llvm/Analysis/InstSimplifyFolder.h
index b0b8dde3b2967..d79c619114a72 100644
--- a/llvm/include/llvm/Analysis/InstSimplifyFolder.h
+++ b/llvm/include/llvm/Analysis/InstSimplifyFolder.h
@@ -115,6 +115,18 @@ class LLVM_ABI InstSimplifyFolder final : public IRBuilderFolder {
     return simplifyShuffleVectorInst(V1, V2, Mask, RetTy, SQ);
   }
 
+  Value *FoldBitInsert(Value *Base, Value *Val,
+                       Value *Offset) const override {
+    // TODO
+    return nullptr;
+  }
+
+  Value *FoldBitExtract(Type *Ty, Value *Src,
+                        Value *Offset) const override {
+    // TODO
+    return nullptr;
+  }
+
   Value *FoldCast(Instruction::CastOps Op, Value *V,
                   Type *DestTy) const override {
     return simplifyCastInst(Op, V, DestTy, SQ);
diff --git a/llvm/include/llvm/Analysis/TargetFolder.h b/llvm/include/llvm/Analysis/TargetFolder.h
index 596e3600f7306..dd8264c34e58e 100644
--- a/llvm/include/llvm/Analysis/TargetFolder.h
+++ b/llvm/include/llvm/Analysis/TargetFolder.h
@@ -184,6 +184,16 @@ class LLVM_ABI TargetFolder final : public IRBuilderFolder {
     return nullptr;
   }
 
+  Value *FoldBitInsert(Value *Base, Value *Val,
+                       Value *Offset) const override {
+    return nullptr;
+  }
+
+  Value *FoldBitExtract(Type *Ty, Value *Src,
+                        Value *Offset) const override {
+    return nullptr;
+  }
+
   Value *FoldCast(Instruction::CastOps Op, Value *V,
                   Type *DestTy) const override {
     if (auto *C = dyn_cast<Constant>(V))
diff --git a/llvm/include/llvm/AsmParser/LLParser.h b/llvm/include/llvm/AsmParser/LLParser.h
index 938a45951e074..0e7c073a47277 100644
--- a/llvm/include/llvm/AsmParser/LLParser.h
+++ b/llvm/include/llvm/AsmParser/LLParser.h
@@ -684,6 +684,8 @@ namespace llvm {
     bool parseExtractElement(Instruction *&Inst, PerFunctionState &PFS);
     bool parseInsertElement(Instruction *&Inst, PerFunctionState &PFS);
     bool parseShuffleVector(Instruction *&Inst, PerFunctionState &PFS);
+    bool parseBitExtract(Instruction *&Inst, PerFunctionState &PFS);
+    bool parseBitInsert(Instruction *&Inst, PerFunctionState &PFS);
     int parsePHI(Instruction *&Inst, PerFunctionState &PFS);
     bool parseLandingPad(Instruction *&Inst, PerFunctionState &PFS);
     bool parseCall(Instruction *&Inst, PerFunctionState &PFS,
diff --git a/llvm/include/llvm/AsmParser/LLToken.h b/llvm/include/llvm/AsmParser/LLToken.h
index a9864cfbcab25..eb2e3c97a43ce 100644
--- a/llvm/include/llvm/AsmParser/LLToken.h
+++ b/llvm/include/llvm/AsmParser/LLToken.h
@@ -380,6 +380,8 @@ enum Kind {
   kw_dso_local_equivalent,
   kw_no_cfi,
   kw_ptrauth,
+  kw_bitinsert,
+  kw_bitextract,
 
   kw_freeze,
 
diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
index 95787c595dff7..d5691877b20d2 100644
--- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h
+++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
@@ -703,6 +703,8 @@ enum FunctionCodes {
   FUNC_CODE_DEBUG_RECORD_LABEL = 65, // [DILocation, DILabel]
   FUNC_CODE_DEBUG_RECORD_DECLARE_VALUE =
       66, // [DILocation, DILocalVariable, DIExpression, ValueAsMetadata]
+  FUNC_CODE_INST_BITINSERT = 67, // BITINSERT: [val, val ,val]
+  FUNC_CODE_INST_BITEXTRACT = 68, // BITEXTRACT: [val, val, val]
 };
 
 enum UseListCodes {
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h b/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h
index 7815ad686cbaa..9622a3a158b7f 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h
@@ -569,6 +569,9 @@ class IRTranslator : public MachineFunctionPass {
   bool translateFence(const User &U, MachineIRBuilder &MIRBuilder);
   bool translateFreeze(const User &U, MachineIRBuilder &MIRBuilder);
 
+  bool translateBitExtract(const User &U, MachineIRBuilder &MIRBuilder);
+  bool translateBitInsert(const User &U, MachineIRBuilder &MIRBuilder);
+
   // Stubs to keep the compiler happy while we implement the rest of the
   // translation.
   bool translateResume(const User &U, MachineIRBuilder &MIRBuilder) {
diff --git a/llvm/include/llvm/IR/ConstantFolder.h b/llvm/include/llvm/IR/ConstantFolder.h
index 384773027fb65..8bb5b8f45a314 100644
--- a/llvm/include/llvm/IR/ConstantFolder.h
+++ b/llvm/include/llvm/IR/ConstantFolder.h
@@ -172,6 +172,16 @@ class LLVM_ABI ConstantFolder final : public IRBuilderFolder {
     return nullptr;
   }
 
+  Value *FoldBitInsert(Value *Base, Value *Val,
+                       Value *Offset) const override {
+    return nullptr;
+  }
+
+  Value *FoldBitExtract(Type *Ty, Value *Src,
+                        Value *Offset) const override {
+    return nullptr;
+  }
+
   Value *FoldCast(Instruction::CastOps Op, Value *V,
                   Type *DestTy) const override {
     if (auto *C = dyn_cast<Constant>(V)) {
diff --git a/llvm/include/llvm/IR/IRBuilder.h b/llvm/include/llvm/IR/IRBuilder.h
index a10a59a9ae9e7..cdd0dc9e1a5d9 100644
--- a/llvm/include/llvm/IR/IRBuilder.h
+++ b/llvm/include/llvm/IR/IRBuilder.h
@@ -2694,6 +2694,20 @@ class IRBuilderBase {
     return Insert(new FreezeInst(V), Name);
   }
 
+  Value *CreateBitInsert(Value *Base, Value *Val, Value *Offset,
+                         const Twine &Name = "") {
+    if (Value *V = Folder.FoldBitInsert(Base, Val, Offset))
+      return V;
+    return Insert(BitInsertInst::Create(Base, Val, Offset), Name);
+  }
+
+  Value *CreateBitExtract(Type *Ty, Value *Src, Value *Offset,
+                          const Twine &Name = "") {
+    if (Value *V = Folder.FoldBitExtract(Ty, Src, Offset))
+      return V;
+    return Insert(BitExtractInst::Create(Ty, Src, Offset), Name);
+  }
+
   //===--------------------------------------------------------------------===//
   // Utility creation methods
   //===--------------------------------------------------------------------===//
diff --git a/llvm/include/llvm/IR/IRBuilderFolder.h b/llvm/include/llvm/IR/IRBuilderFolder.h
index 3cf3bcd3d9522..6db2424155128 100644
--- a/llvm/include/llvm/IR/IRBuilderFolder.h
+++ b/llvm/include/llvm/IR/IRBuilderFolder.h
@@ -80,6 +80,12 @@ class LLVM_ABI IRBuilderFolder {
   FoldBinaryIntrinsic(Intrinsic::ID ID, Value *LHS, Value *RHS, Type *Ty,
                       FastMathFlags FMF = FastMathFlags()) const = 0;
 
+  virtual Value *FoldBitInsert(Value *Base, Value *Val,
+                               Value *Offset) const = 0;
+
+  virtual Value *FoldBitExtract(Type *Ty, Value *Src,
+                                Value *Offset) const = 0;
+
   //===--------------------------------------------------------------------===//
   // Cast/Conversion Operators
   //===--------------------------------------------------------------------===//
diff --git a/llvm/include/llvm/IR/InstVisitor.h b/llvm/include/llvm/IR/InstVisitor.h
index 45b2e59510b67..0f5f2ab6c1317 100644
--- a/llvm/include/llvm/IR/InstVisitor.h
+++ b/llvm/include/llvm/IR/InstVisitor.h
@@ -199,6 +199,8 @@ class InstVisitor {
   RetTy visitCleanupPadInst(CleanupPadInst &I) { DELEGATE(FuncletPadInst); }
   RetTy visitCatchPadInst(CatchPadInst &I)     { DELEGATE(FuncletPadInst); }
   RetTy visitFreezeInst(FreezeInst &I)         { DELEGATE(Instruction); }
+  RetTy visitBitInsertInst(BitInsertInst &I)   { DELEGATE(Instruction); }
+  RetTy visitBitExtractInst(BitExtractInst &I) { DELEGATE(Instruction); }
 
   RetTy visitMemSetInst(MemSetInst &I)            { DELEGATE(MemIntrinsic); }
   RetTy visitMemSetPatternInst(MemSetPatternInst &I) {
diff --git a/llvm/include/llvm/IR/Instruction.def b/llvm/include/llvm/IR/Instruction.def
index 949a9d0beecb4..dc4c3c795fad7 100644
--- a/llvm/include/llvm/IR/Instruction.def
+++ b/llvm/include/llvm/IR/Instruction.def
@@ -220,7 +220,9 @@ 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)
+HANDLE_OTHER_INST(70, BitInsert, BitInsertInst) // BitInsert Instruction.
+HANDLE_OTHER_INST(71, BitExtract, BitExtractInst) // BitExtract Instruction
+  LAST_OTHER_INST(71)
 
 #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 365a4eee54eb6..400d996710b44 100644
--- a/llvm/include/llvm/IR/Instructions.h
+++ b/llvm/include/llvm/IR/Instructions.h
@@ -5415,6 +5415,87 @@ class FreezeInst : public UnaryInstruction {
   }
 };
 
+//===----------------------------------------------------------------------===//
+//                              BitInsert Class
+//===----------------------------------------------------------------------===//
+class BitInsertInst : public Instruction {
+  constexpr static IntrusiveOperandsAllocMarker AllocMarker{3};
+  LLVM_ABI explicit BitInsertInst(Value *Base, Value *Val, Value *Offset,
+                                  const Twine &NameStr = "",
+                                  InsertPosition InsertBefore = nullptr);
+
+protected:
+  // Note: Instruction needs to be a friend here to call cloneImpl.
+  friend class Instruction;
+  /// Clone an identical FreezeInst
+  LLVM_ABI BitInsertInst *cloneImpl() const;
+
+public:
+  static BitInsertInst *Create(Value *Base, Value *Val, Value *Offset,
+                               const Twine &NameStr = "",
+                               InsertPosition InsertBefore = nullptr) {
+    return new (AllocMarker)
+        BitInsertInst(Base, Val, Offset, NameStr, InsertBefore);
+  }
+  /// Transparently provide more efficient getOperand methods.
+  DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
+  /// Return true if an bitinsert instruction can be
+  /// formed with the specified operands.
+  LLVM_ABI static bool isValidOperands(const Value *Base, const Value *Val,
+                                       const Value *Offset);
+  // Methods for support type inquiry through isa, cast, and dyn_cast:
+  static inline bool classof(const Instruction *I) {
+    return I->getOpcode() == BitInsert;
+  }
+  static inline bool classof(const Value *V) {
+    return isa<Instruction>(V) && classof(cast<Instruction>(V));
+  }
+};
+template <>
+struct OperandTraits<BitInsertInst>
+    : public FixedNumOperandTraits<BitInsertInst, 3> {};
+DEFINE_TRANSPARENT_OPERAND_ACCESSORS(BitInsertInst, Value)
+
+//===----------------------------------------------------------------------===//
+//                              BitExtract Class
+//===----------------------------------------------------------------------===//
+class BitExtractInst : public Instruction {
+  constexpr static IntrusiveOperandsAllocMarker AllocMarker{2};
+  LLVM_ABI BitExtractInst(Type *Ty, Value *Src, Value *Offset,
+                          const Twine &NameStr = "",
+                          InsertPosition InsertBefore = nullptr);
+
+protected:
+  // Note: Instruction needs to be a friend here to call cloneImpl.
+  friend class Instruction;
+  /// Clone an identical FreezeInst
+  LLVM_ABI BitExtractInst *cloneImpl() const;
+
+public:
+  static BitExtractInst *Create(Type *Ty, Value *Src, Value *Offset,
+                                const Twine &NameStr = "",
+                                InsertPosition InsertBefore = nullptr) {
+    return new (AllocMarker)
+        BitExtractInst(Ty, Src, Offset, NameStr, InsertBefore);
+  }
+  /// Transparently provide more efficient getOperand methods.
+  DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
+  /// Return true if an bitextract instruction can be
+  /// formed with the specified operands.
+  LLVM_ABI static bool isValidOperands(const Type *Ty, const Value *Val,
+                                       const Value *Offset);
+  // Methods for support type inquiry through isa, cast, and dyn_cast:
+  static inline bool classof(const Instruction *I) {
+    return I->getOpcode() == BitExtract;
+  }
+  static inline bool classof(const Value *V) {
+    return isa<Instruction>(V) && classof(cast<Instruction>(V));
+  }
+};
+template <>
+struct OperandTraits<BitExtractInst>
+    : public FixedNumOperandTraits<BitExtractInst, 2> {};
+DEFINE_TRANSPARENT_OPERAND_ACCESSORS(BitExtractInst, Value)
 } // end namespace llvm
 
 #endif // LLVM_IR_INSTRUCTIONS_H
diff --git a/llvm/include/llvm/IR/NoFolder.h b/llvm/include/llvm/IR/NoFolder.h
index a8dbbf5eeb1c2..24b7856bc55df 100644
--- a/llvm/include/llvm/IR/NoFolder.h
+++ b/llvm/include/llvm/IR/NoFolder.h
@@ -109,6 +109,16 @@ class LLVM_ABI NoFolder final : public IRBuilderFolder {
     return nullptr;
   }
 
+  Value *FoldBitInsert(Value *Base, Value *Val,
+                      Value *Offset) const override {
+    return nullptr;
+  }
+  
+  Value *FoldBitExtract(Type *Ty, Value *Src,
+                        Value *Offset) const override {
+    return nullptr;
+  }
+
   Value *FoldCast(Instruction::CastOps Op, Value *V,
                   Type *DestTy) const override {
     return nullptr;
diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp
index e7d7cc4ba88ea..26d04800aef36 100644
--- a/llvm/lib/AsmParser/LLLexer.cpp
+++ b/llvm/lib/AsmParser/LLLexer.cpp
@@ -996,6 +996,8 @@ lltok::Kind LLLexer::LexIdentifier() {
   INSTKEYWORD(cleanuppad,   CleanupPad);
 
   INSTKEYWORD(freeze,       Freeze);
+  INSTKEYWORD(bitinsert,    BitInsert);
+  INSTKEYWORD(bitextract,   BitExtract);
 
 #undef INSTKEYWORD
 
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index 990febaacbe48..eb6da0bbe256f 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -4736,6 +4736,12 @@ bool LLParser::parseValID(ValID &ID, PerFunctionState *PFS, Type *ExpectedTy) {
         return true;
     }
 
+    if (Opc == Instruction::BitExtract) {
+      if (parseType(Ty) ||
+          parseToken(lltok::comma, "expected comma after bitextract's type"))
+        return true;
+    }
+
     if (parseGlobalValueVector(Elts) ||
         parseToken(lltok::rparen, "expected ')' in constantexpr"))
       return true;
@@ -7721,6 +7727,10 @@ int LLParser::parseInstruction(Instruction *&Inst, BasicBlock *BB,
     return parseLandingPad(Inst, PFS);
   case lltok::kw_freeze:
     return parseFreeze(Inst, PFS);
+  case lltok::kw_bitinsert:
+    return parseBitInsert(Inst, PFS);
+  case lltok::kw_bitextract:
+    return parseBitExtract(Inst, PFS);
   // Call.
   case lltok::kw_call:
     return parseCall(Inst, PFS, CallInst::TCK_None);
@@ -8538,6 +8548,45 @@ bool LLParser::parseInsertElement(Instruction *&Inst, PerFunctionState &PFS) {
   return false;
 }
 
+// parseBitExtract
+// ::= 'bitextract' Type ',' TypeAndValue ',' TypeAndValue
+bool LLParser::parseBitExtract(Instruction *&Inst, PerFunctionState &PFS) {
+  LocTy Loc;
+  Type *Ty = nullptr;
+  Value *Op0, *Op1;
+  if (parseType(Ty, Loc) ||
+      parseToken(lltok::comma, "expected ',' after bitextract type") ||
+      parseTypeAndValue(Op0, Loc, PFS) ||
+      parseToken(lltok::comma, "expected ',' after bitextract source value") ||
+      parseTypeAndValue(Op1, PFS))
+    return true;
+
+  if (!BitExtractInst::isValidOperands(Ty, Op0, Op1))
+    return error(Loc, "invalid bitextract operands");
+
+  Inst = BitExtractInst::Create(Ty, Op0, Op1);
+  return false;
+}
+
+// parseBitInsert
+// ::= 'bitinsert' TypeAndValue ',' TypeAndValue ',' TypeAndValue
+bool LLParser::parseBitInsert(Instruction *&Inst, PerFunctionState &PFS) {
+  LocTy Loc;
+  Value *Op0, *Op1, *Op2;
+  if (parseTypeAndValue(Op0, Loc, PFS) ||
+      parseToken(lltok::comma, "expected ',' after bitinsert source value") ||
+      parseTypeAndValue(Op1, PFS) ||
+      parseToken(lltok::comma, "expected ',' after bitinsert insert value") ||
+      parseTypeAndValue(Op2, PFS))
+    return true;
+
+  if (!BitInsertInst::isValidOperands(Op0, Op1, Op2))
+    return error(Loc, "invalid bitinsert operands");
+
+  Inst = BitInsertInst::Create(Op0, Op1, Op2);
+  return false;
+}
+
 /// parseShuffleVector
 ///   ::= 'shufflevector' TypeAndValue ',' TypeAndValue ',' TypeAndValue
 bool LLParser::parseShuffleVector(Instruction *&Inst, PerFunctionState &PFS) {
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index 3e863f4786e1a..ef28f922a3b45 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -1837,6 +1837,14 @@ Expected<Value *> BitcodeReader::materializeValue(unsigned StartValID,
         I = new ShuffleVectorInst(Ops[0], Ops[1], Ops[2], "constexpr",
                                   InsertBB);
         break;
+      case Instruction::BitExtract:
+        I = BitExtractInst::Create(BC->getType(), Ops[0], Ops[1],
+                                   "constexpr", InsertBB);
+        break;
+      case Instruction::BitInsert:
+        I = BitInsertInst::Create(Ops[0], Ops[1], Ops[2], "constexpr",
+                                  InsertBB);
+        break;
       default:
         llvm_unreachable("Unhandled bitcode constant");
       }
@@ -5546,6 +5554,37 @@ Error BitcodeReader::parseFunctionBody(Function *F) {
       break;
     }
 
+    case bitc::FUNC_CODE_INST_BITINSERT: { // BITINSERT: [ty, opval, opval, opval]
+      unsigned OpNum = 0;
+      Value *Base, *Val, *Offset;
+      unsigned BaseTypeID, ValTypeID, OffsetTypeID;
+      if (getValueTypePair(Record, OpNum, NextValueNo, Base, BaseTypeID, CurBB) ||
+          getValueTypePair(Record, OpNum, NextValueNo, Val, ValTypeID, CurBB) ||
+          getValueTypePair(Record, OpNum, NextValueNo, Offset, OffsetTypeID,
+                           CurBB))
+        return error("Invalid bitinsert record");
+      I = BitInsertInst::Create(Base, Val, Offset);
+      ResTypeID = BaseTypeID;
+      InstructionList.push_back(I);
+      break;
+    }
+
+    case bitc::FUNC_CODE_INST_BITEXTRACT: { // BITEXTRACT: [ty, opval, opval]
+      unsigned OpNum = 0;
+      unsigned TypeID = Record[OpNum++];
+      Type *ResTy = getTypeByID(TypeID);
+      Value *Src, *Offset;
+      unsigned SrcTypeID, OffsetTypeID;
+      if (getValueTypePair(Record, OpNum, NextValueNo, Src, SrcTypeID, CurBB) ||
+          getValueTypePair(Record, OpNum, NextValueNo, Offset, OffsetTypeID,
+                           CurBB))
+        return error("Invalid bitextract record");
+      I = BitExtractInst::Create(ResTy, Src, Offset);
+      ResTypeID = TypeID;
+      InstructionList.push_back(I);
+      break;
+    }
+
     case bitc::FUNC_CODE_INST_SHUFFLEVEC: {// SHUFFLEVEC: [opval,ty,opval,opval]
       unsigned OpNum = 0;
       Value *Vec1, *Vec2, *Mask;
diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index ed7f95701ea65..55f2d7f1c0f06 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -3289,6 +3289,18 @@ void ModuleBitcodeWriter::writeInstruction(const Instruction &I,
     pushValue(I.getOperand(1), InstID, Vals);
     pushValueAndType(I.getOperand(2), InstID, Vals);
     break;
+  case Instruction::BitExtract:
+    Code = bitc::FUNC_CODE_INST_BITEXTRACT;
+    Vals.push_back(VE.getTypeID(I.getType()));
+    pushValueAndType(I.getOperand(0), InstID, Vals);
+    pushValue(I.getOperand(1), InstID, Vals);
+    break;
+  case Instruction::BitInsert:
+    Code = bitc::FUNC_CODE_INST_BITINSERT;
+    pushValueAndType(I.getOperand(0), InstID, Vals);
+    pushValueAndType(I.getOperand(1), InstID, Vals);
+    pushValue(I.getOperand(2), InstID, Vals);
+    break;
   case Instruction::ShuffleVector:
     Code = bitc::FUNC_CODE_INST_SHUFFLEVEC;
     pushValueAndType(I.getOperand(0), InstID, Vals);
diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
index 8c8e08865744a..204b1dc4424fe 100644
--- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
@@ -3524,6 +3524,76 @@ bool IRTranslator::translateShuffleVector(const User &U,
   return true;
 }
 
+bool IRTranslator::translateBitInsert(const User &U,
+                                      MachineIRBuilder &MIRBuilder) {
+  Register Res    = getOrCreateVReg(U);
+  Register Base   = getOrCreateVReg(*U.getOperand(0));
+  Register Val    = getOrCreateVReg(*U.getOperand(1));
+  Register Offset = getOrCreateVReg(*U.getOperand(2));
+  MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
+  LLT BaseTy = MRI.getType(Base);
+  LLT ValTy  = MRI.getType(Val);
+
+  // Convert Offset to BaseTy
+  Register LegalOffset = MIRBuilder.buildZExtOrTrunc(BaseTy, Offset).getReg(0);
+
+  // RotateAmount = Offset + width(Val)
+  unsigned ValBitWidth = ValTy.getSizeInBits();
+  Register ValWidth = MIRBuilder.buildConstant(BaseTy, ValBitWidth).getReg(0);
+  Register RotateAmount = MIRBuilder.buildAdd(BaseTy, LegalOffset, ValWidth).getReg(0);
+
+  Register RotatedBase = MIRBuilder.buildRotateLeft(BaseTy, Base, RotateAmount).getReg(0);
+
+  // Truncate or extend Val to BaseTy so only the inserted bit range remains.
+  Register ExtVal = MIRBuilder.buildZExtOrTrunc(BaseTy, Val).getReg(0);
+
+  // Clear the low ValBitWidth bits of the rotated base and insert Val there.
+  unsigned BaseBitWidth = BaseTy.getSizeInBits();
+  APInt ClearMask =
+      APInt::getHighBitsSet(BaseBitWidth, BaseBitWidth - ValBitWidth);
+  Register MaskConst = MIRBuilder.buildConstant(BaseTy, ClearMask).getReg(0);
+  Register ClearedBase =
+      MIRBuilder.buildAnd(BaseTy, RotatedBase, MaskConst).getReg(0);
+  Register Inserted = MIRBuilder.buildOr(BaseTy, ClearedBase, ExtVal).getReg(0);
+
+  // Restore bit positions
+  MIRBuilder.buildRotateRight(Res, Inserted, RotateAmount);
+  return true;
+}
+
+bool IRTranslator::translateBitExtract(const User &U,
+                                       MachineIRBuilder &MIRBuilder) {
+  Register Res    = getOrCreateVReg(U);
+  Register Src    = getOrCreateVReg(*U.getOperand(0));
+  Register Offset = getOrCreateVReg(*U.getOperand(1));
+  MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
+  LLT SrcTy = MRI.getType(Src);
+  LLT ResTy = MRI.getType(Res);
+
+  if (ResTy.getSizeInBits() > SrcTy.getSizeInBits())
+    llvm_unreachable(
+        "bitextract result wider than source should be rejected by verifier");
+
+  // Convert Offset to SrcTy
+  Register LegalOffset = MIRBuilder.buildZExtOrTrunc(SrcTy, Offset).getReg(0);
+
+  // RotateAmount = Offset + width
+  unsigned ResultBitWidth = ResTy.getSizeInBits();
+  Register ResultWidth = MIRBuilder.buildConstant(SrcTy, ResultBitWidth).getReg(0);
+  Register RotateAmount = MIRBuilder.buildAdd(SrcTy, LegalOffset, ResultWidth).getReg(0);
+
+  // Rotate left by (Offset + ResultWidth)
+  Register Rotated = MIRBuilder.buildRotateLeft(SrcTy, Src, RotateAmount).getReg(0);
+
+  // Truncating to ResTy discards the high bits for free
+  if (SrcTy == ResTy)
+    MIRBuilder.buildCopy(Res, Rotated);
+  else
+    MIRBuilder.buildTrunc(Res, Rotated);
+
+  return true;
+}
+
 bool IRTranslator::translatePHI(const User &U, MachineIRBuilder &MIRBuilder) {
   const PHINode &PI = cast<PHINode>(U);
 
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 579bff7d3ab60..124633e362dfb 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -4151,6 +4151,73 @@ void SelectionDAGBuilder::visitInsertElement(const User &I) {
                            InVec, InVal, InIdx));
 }
 
+void SelectionDAGBuilder::visitBitInsert(const User &I) {
+  SDValue Base   = getValue(I.getOperand(0));
+  SDValue Val    = getValue(I.getOperand(1));
+  SDValue Offset = getValue(I.getOperand(2));
+  EVT BaseVT = Base.getValueType();
+  EVT ValVT  = Val.getValueType();
+  const TargetLowering &TLI = DAG.getTargetLoweringInfo();
+  SDLoc dl = getCurSDLoc();
+
+  SDValue LegalOffset = DAG.getZExtOrTrunc(Offset, dl, BaseVT);
+
+  unsigned ValBitWidth = ValVT.getScalarSizeInBits();
+  SDValue ValWidth = DAG.getConstant(ValBitWidth, dl, BaseVT);
+  SDValue RotateAmount = DAG.getNode(ISD::ADD, dl, BaseVT, LegalOffset, ValWidth);
+
+  // Legalize rotate amount to the target's shift amount type
+  EVT ShiftAmtTy = TLI.getShiftAmountTy(BaseVT, DAG.getDataLayout());
+  SDValue LegalRotateAmount = DAG.getZExtOrTrunc(RotateAmount, dl, ShiftAmtTy);
+
+  SDValue RotatedBase = DAG.getNode(ISD::ROTL, dl, BaseVT, Base, LegalRotateAmount);
+
+  unsigned BaseBitWidth = BaseVT.getScalarSizeInBits();
+  APInt ClearMask = APInt::getHighBitsSet(BaseBitWidth, BaseBitWidth - ValBitWidth);
+  SDValue ClearedBase = DAG.getNode(ISD::AND, dl, BaseVT, RotatedBase,
+                                    DAG.getConstant(ClearMask, dl, BaseVT));
+
+  SDValue ExtVal  = DAG.getZExtOrTrunc(Val, dl, BaseVT);
+  SDValue Inserted = DAG.getNode(ISD::OR, dl, BaseVT, ClearedBase, ExtVal);
+
+  SDValue Result = DAG.getNode(ISD::ROTR, dl, BaseVT, Inserted, LegalRotateAmount);
+  setValue(&I, Result);
+}
+
+void SelectionDAGBuilder::visitBitExtract(const User &I) {
+  SDValue Src    = getValue(I.getOperand(0));
+  SDValue Offset = getValue(I.getOperand(1));
+  EVT SrcVT    = Src.getValueType();
+  const TargetLowering &TLI = DAG.getTargetLoweringInfo();
+  EVT ResultVT = TLI.getValueType(DAG.getDataLayout(), I.getType());
+  SDLoc dl = getCurSDLoc();
+
+  // The verifier guarantees the result type is not wider than the source
+  // type, so reject any widening case here. getZExtOrTrunc handles the
+  // equal-width and narrower cases.
+  if (ResultVT.getSizeInBits() > SrcVT.getSizeInBits())
+    llvm_unreachable(
+        "bitextract result wider than source should be rejected by verifier");
+
+  // Convert offset to SrcVT
+  SDValue LegalOffset = DAG.getZExtOrTrunc(Offset, dl, SrcVT);
+
+  // RotateAmount = Offset + width(Result), computed in SrcVT
+  unsigned ResultBitWidth = ResultVT.getScalarSizeInBits();
+  SDValue ResultWidth = DAG.getConstant(ResultBitWidth, dl, SrcVT);
+  SDValue RotateAmount = DAG.getNode(ISD::ADD, dl, SrcVT, LegalOffset, ResultWidth);
+
+  // Legalize rotate amount to the target's shift amount type
+  EVT ShiftAmtTy = TLI.getShiftAmountTy(SrcVT, DAG.getDataLayout());
+  SDValue LegalRotateAmount = DAG.getZExtOrTrunc(RotateAmount, dl, ShiftAmtTy);
+
+  // Rotate left by (Offset + ResultWidth) — brings target field to bit 0
+  SDValue Rotated = DAG.getNode(ISD::ROTL, dl, SrcVT, Src, LegalRotateAmount);
+
+  // Truncating to ResultVT discards the high bits for free
+  setValue(&I, DAG.getZExtOrTrunc(Rotated, dl, ResultVT));
+}
+
 void SelectionDAGBuilder::visitExtractElement(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 21aac333a73cd..eab52ff3f24b5 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
@@ -615,6 +615,9 @@ class SelectionDAGBuilder {
   void visitGetElementPtr(const User &I);
   void visitSelect(const User &I);
 
+  void visitBitInsert(const User &I);
+  void visitBitExtract(const User &I);
+
   void visitAlloca(const AllocaInst &I);
   void visitLoad(const LoadInst &I);
   void visitStore(const StoreInst &I);
diff --git a/llvm/lib/CodeGen/TargetLoweringBase.cpp b/llvm/lib/CodeGen/TargetLoweringBase.cpp
index 1f4842fb3df15..701c2b58014bc 100644
--- a/llvm/lib/CodeGen/TargetLoweringBase.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringBase.cpp
@@ -2299,6 +2299,8 @@ int TargetLoweringBase::InstructionOpcodeToISD(unsigned Opcode) const {
   case InsertValue:    return ISD::MERGE_VALUES;
   case LandingPad:     return 0;
   case Freeze:         return ISD::FREEZE;
+  case BitInsert:      return 0;
+  case BitExtract:     return 0;
   }
 
   llvm_unreachable("Unknown instruction type encountered!");
diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp
index 106fd6541360c..334204ea7fabb 100644
--- a/llvm/lib/IR/AsmWriter.cpp
+++ b/llvm/lib/IR/AsmWriter.cpp
@@ -4790,9 +4790,9 @@ void AssemblyWriter::printInstruction(const Instruction &I) {
       Out << ' ';
       TypePrinter.print(GEP->getSourceElementType(), Out);
       Out << ',';
-    } else if (const auto *LI = dyn_cast<LoadInst>(&I)) {
+    } else if (isa<BitExtractInst>(I) || isa<LoadInst>(I)) {
       Out << ' ';
-      TypePrinter.print(LI->getType(), Out);
+      TypePrinter.print(I.getType(), Out);
       Out << ',';
     }
 
diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp
index 5e6b03d01b6ba..67572f436330c 100644
--- a/llvm/lib/IR/Core.cpp
+++ b/llvm/lib/IR/Core.cpp
@@ -4497,6 +4497,20 @@ LLVMValueRef LLVMBuildFreeze(LLVMBuilderRef B, LLVMValueRef Val,
   return wrap(unwrap(B)->CreateFreeze(unwrap(Val), Name));
 }
 
+LLVMValueRef LLVMBuildBitInsert(LLVMBuilderRef B, LLVMValueRef Base,
+                                    LLVMValueRef Val, LLVMValueRef Offset,
+                                    const char *Name) {
+  return wrap(unwrap(B)->CreateBitInsert(unwrap(Base), unwrap(Val),
+                                             unwrap(Offset), Name));
+}
+
+LLVMValueRef LLVMBuildBitExtract(LLVMBuilderRef B, LLVMTypeRef Ty,
+                                    LLVMValueRef Src, LLVMValueRef Offset,
+                                    const char *Name) {
+  return wrap(unwrap(B)->CreateBitExtract(unwrap(Ty), unwrap(Src),
+                                             unwrap(Offset), Name));
+}
+
 LLVMValueRef LLVMBuildIsNull(LLVMBuilderRef B, LLVMValueRef Val,
                              const char *Name) {
   return wrap(unwrap(B)->CreateIsNull(unwrap(Val), Name));
diff --git a/llvm/lib/IR/Instruction.cpp b/llvm/lib/IR/Instruction.cpp
index ac209ffa72aae..fc1e2885253f5 100644
--- a/llvm/lib/IR/Instruction.cpp
+++ b/llvm/lib/IR/Instruction.cpp
@@ -889,6 +889,8 @@ const char *Instruction::getOpcodeName(unsigned OpCode) {
   case LandingPad:     return "landingpad";
   case CleanupPad:     return "cleanuppad";
   case Freeze:         return "freeze";
+  case BitInsert:      return "bitinsert";
+  case BitExtract:     return "bitextract";
 
   default: return "<Invalid operator> ";
   }
diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp
index 088f85c4851cd..d5b028726dffc 100644
--- a/llvm/lib/IR/Instructions.cpp
+++ b/llvm/lib/IR/Instructions.cpp
@@ -2599,6 +2599,55 @@ Type *ExtractValueInst::getIndexedType(Type *Agg,
   return Agg;
 }
 
+//===----------------------------------------------------------------------===//
+//                             BitInsert Class
+//===----------------------------------------------------------------------===//
+BitInsertInst::BitInsertInst(Value *Base, Value *Val, Value *Offset,
+                             const Twine &Name, InsertPosition InsertBef)
+    : Instruction(Base->getType(), BitInsert, AllocMarker, InsertBef) {
+  assert(isValidOperands(Base, Val, Offset) &&
+         "Invalid bitinsert instruction operands!");
+  Op<0>() = Base;
+  Op<1>() = Val;
+  Op<2>() = Offset;
+  setName(Name);
+}
+
+bool BitInsertInst::isValidOperands(const Value *Base, const Value *Val,
+                                    const Value *Offset) {
+  if (!Base->getType()->isByteTy())
+    return false; // First operand of bitinsert must be byte type.
+  if (!Val->getType()->isFirstClassType())
+    return false; // Second operand of bitinsert must be a first-class type.
+  if (!Offset->getType()->isIntegerTy(32))
+    return false; // Third operand of bitinsert must be i32.
+  return true;
+}
+
+//===----------------------------------------------------------------------===//
+//                             BitExtract Class
+//===----------------------------------------------------------------------===//
+BitExtractInst::BitExtractInst(Type *Ty, Value *Src, Value *Offset,
+                               const Twine &Name, InsertPosition InsertBef)
+    : Instruction(Ty, BitExtract, AllocMarker, InsertBef) {
+  assert(isValidOperands(Ty, Src, Offset) &&
+         "Invalid bitextract instruction operands!");
+  Op<0>() = Src;
+  Op<1>() = Offset;
+  setName(Name);
+}
+
+bool BitExtractInst::isValidOperands(const Type *Ty, const Value *Src,
+                                     const Value *Offset) {
+  if (!Ty->isFirstClassType())
+    return false; // First operand of bitextract must be a first-class type.
+  if (!Src->getType()->isByteTy())
+    return false; // Second operand of bitextract must be a byte type.
+  if (!Offset->getType()->isIntegerTy(32))
+    return false; // Third operand of bitextract must be i32.
+  return true;
+}
+
 //===----------------------------------------------------------------------===//
 //                             UnaryOperator Class
 //===----------------------------------------------------------------------===//
@@ -4533,6 +4582,14 @@ InsertElementInst *InsertElementInst::cloneImpl() const {
   return InsertElementInst::Create(getOperand(0), getOperand(1), getOperand(2));
 }
 
+BitInsertInst *BitInsertInst::cloneImpl() const {
+  return BitInsertInst::Create(getOperand(0), getOperand(1), getOperand(2));
+}
+
+BitExtractInst *BitExtractInst::cloneImpl() const {
+  return BitExtractInst::Create(getType(), getOperand(0), getOperand(1));
+}
+
 ShuffleVectorInst *ShuffleVectorInst::cloneImpl() const {
   return new ShuffleVectorInst(getOperand(0), getOperand(1), getShuffleMask());
 }
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 9c6c5f245ff0b..122de2cd22fdf 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -595,6 +595,8 @@ class Verifier : public InstVisitor<Verifier>, VerifierSupport {
   void visitExtractElementInst(ExtractElementInst &EI);
   void visitInsertElementInst(InsertElementInst &EI);
   void visitShuffleVectorInst(ShuffleVectorInst &EI);
+  void visitBitInsertInst(BitInsertInst &EI);
+  void visitBitExtractInst(BitExtractInst &EI);
   void visitVAArgInst(VAArgInst &VAA) { visitInstruction(VAA); }
   void visitCallInst(CallInst &CI);
   void visitInvokeInst(InvokeInst &II);
@@ -4502,6 +4504,23 @@ void Verifier::visitShuffleVectorInst(ShuffleVectorInst &SV) {
   visitInstruction(SV);
 }
 
+void Verifier::visitBitInsertInst(BitInsertInst &IE) {
+  Check(BitInsertInst::isValidOperands(IE.getOperand(0), IE.getOperand(1),
+                                       IE.getOperand(2)),
+        "Invalid bitinsert operands!", &IE);
+  visitInstruction(IE);
+}
+
+void Verifier::visitBitExtractInst(BitExtractInst &IE) {
+  Check(BitExtractInst::isValidOperands(IE.getType(), IE.getOperand(0),
+                                        IE.getOperand(1)),
+        "Invalid bitextract operands!", &IE);
+  Check(IE.getType()->getPrimitiveSizeInBits() <=
+            IE.getOperand(0)->getType()->getPrimitiveSizeInBits(),
+        "bitextract result type cannot be wider than source type!", &IE);
+  visitInstruction(IE);
+}
+
 void Verifier::visitGetElementPtrInst(GetElementPtrInst &GEP) {
   if (auto *MD = mdconst::extract_or_null<ConstantInt>(
           GEP.getModule()->getModuleFlag("require-logical-pointer")))
diff --git a/llvm/test/Assembler/bitextract-invalid-1.ll b/llvm/test/Assembler/bitextract-invalid-1.ll
new file mode 100644
index 0000000000000..c746b0d9bafe1
--- /dev/null
+++ b/llvm/test/Assembler/bitextract-invalid-1.ll
@@ -0,0 +1,6 @@
+; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s
+; CHECK: invalid bitextract operands
+define i8 @invalid(i32 %src) {
+  %r = bitextract i8, i32 %src, i32 0
+  ret i8 %r
+}
diff --git a/llvm/test/Assembler/bitinsert-bitextract.ll b/llvm/test/Assembler/bitinsert-bitextract.ll
new file mode 100644
index 0000000000000..237a25f0c2744
--- /dev/null
+++ b/llvm/test/Assembler/bitinsert-bitextract.ll
@@ -0,0 +1,15 @@
+; RUN: llvm-as < %s | llvm-dis | FileCheck %s
+
+; CHECK-LABEL: test_bitextract
+; CHECK: bitextract i8, b32 %{{.*}}, i32 24
+define i8 @test_bitextract(b32 %src) {
+  %result = bitextract i8, b32 %src, i32 24
+  ret i8 %result
+}
+
+; CHECK-LABEL: test_bitinsert
+; CHECK: bitinsert b32 %{{.*}}, i8 %{{.*}}, i32 3
+define b32 @test_bitinsert(b32 %base, i8 %val) {
+  %result = bitinsert b32 %base, i8 %val, i32 3
+  ret b32 %result
+}
diff --git a/llvm/test/Assembler/bitinsert-invalid-1.ll b/llvm/test/Assembler/bitinsert-invalid-1.ll
new file mode 100644
index 0000000000000..acec42649ccda
--- /dev/null
+++ b/llvm/test/Assembler/bitinsert-invalid-1.ll
@@ -0,0 +1,6 @@
+; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s
+; CHECK: invalid bitinsert operands
+define i32 @invalid(i32 %base, i8 %val) {
+  %r = bitinsert i32 %base, i8 %val, i32 0
+  ret i32 %r
+}
diff --git a/llvm/test/CodeGen/X86/GlobalISel/bitinsert-bitextract.ll b/llvm/test/CodeGen/X86/GlobalISel/bitinsert-bitextract.ll
new file mode 100644
index 0000000000000..699852b890f45
--- /dev/null
+++ b/llvm/test/CodeGen/X86/GlobalISel/bitinsert-bitextract.ll
@@ -0,0 +1,32 @@
+; RUN: llc -mtriple=x86_64-unknown-linux-gnu -global-isel -stop-after=irtranslator < %s | FileCheck %s
+
+define i16 @test_bitextract(b32 %src, i32 %off) {
+; CHECK-LABEL: name: test_bitextract
+; CHECK: [[SRC:%[0-9]+]]:_(s32) = COPY $edi
+; CHECK: [[WIDTH:%[0-9]+]]:_(s32) = G_CONSTANT i32 16
+; CHECK: [[ADD:%[0-9]+]]:_(s32) = G_ADD %{{[0-9]+}}, [[WIDTH]]
+; CHECK: [[ROTL:%[0-9]+]]:_(s32) = G_ROTL [[SRC]], [[ADD]](s32)
+; CHECK: [[RES:%[0-9]+]]:_(s16) = G_TRUNC [[ROTL]](s32)
+; CHECK: $ax = COPY [[RES]](s16)
+; CHECK: RET 0, implicit $ax
+  %result = bitextract i16, b32 %src, i32 %off
+  ret i16 %result
+}
+
+define b32 @test_bitinsert(b32 %base, i16 %val, i32 %off) {
+; CHECK-LABEL: name: test_bitinsert
+; CHECK: [[BASE:%[0-9]+]]:_(s32) = COPY $edi
+; CHECK: [[VAL:%[0-9]+]]:_(s16) = G_TRUNC %{{[0-9]+}}(s32)
+; CHECK: [[WIDTH:%[0-9]+]]:_(s32) = G_CONSTANT i32 16
+; CHECK: [[ADD:%[0-9]+]]:_(s32) = G_ADD %{{[0-9]+}}, [[WIDTH]]
+; CHECK: [[ROTL:%[0-9]+]]:_(s32) = G_ROTL [[BASE]], [[ADD]](s32)
+; CHECK: [[EXT_VAL:%[0-9]+]]:_(s32) = G_ZEXT [[VAL]](s16)
+; CHECK: [[MASK:%[0-9]+]]:_(s32) = G_CONSTANT i32 -65536
+; CHECK: [[AND:%[0-9]+]]:_(s32) = G_AND [[ROTL]], [[MASK]]
+; CHECK: [[OR:%[0-9]+]]:_(s32) = G_OR [[AND]], [[EXT_VAL]]
+; CHECK: [[ROTR:%[0-9]+]]:_(s32) = G_ROTR [[OR]], [[ADD]](s32)
+; CHECK: $eax = COPY [[ROTR]](s32)
+; CHECK: RET 0, implicit $eax
+  %result = bitinsert b32 %base, i16 %val, i32 %off
+  ret b32 %result
+}
diff --git a/llvm/test/CodeGen/X86/bitinsert-bitextract-x86.ll b/llvm/test/CodeGen/X86/bitinsert-bitextract-x86.ll
new file mode 100644
index 0000000000000..412ebb70e6bd9
--- /dev/null
+++ b/llvm/test/CodeGen/X86/bitinsert-bitextract-x86.ll
@@ -0,0 +1,42 @@
+; RUN: llc -mtriple=x86_64-unknown-linux-gnu < %s | FileCheck %s
+
+define i16 @test_bitextract_var(b32 %src, i32 %off) {
+; CHECK-LABEL: test_bitextract_var:
+; CHECK:       movl %edi, %eax
+; CHECK:       leal 16(%rsi), %ecx
+; CHECK:       roll %cl, %eax
+; CHECK:       retq
+  %result = bitextract i16, b32 %src, i32 %off
+  ret i16 %result
+}
+
+define i16 @test_bitextract_const(b32 %src) {
+; CHECK-LABEL: test_bitextract_const:
+; CHECK:       movl %edi, %eax
+; CHECK:       shrl $8, %eax
+; CHECK:       retq
+  %result = bitextract i16, b32 %src, i32 8
+  ret i16 %result
+}
+
+define i8 @test_bitextract_narrow(b64 %src) {
+; CHECK-LABEL: test_bitextract_narrow:
+; CHECK:       movq %rdi, %rax
+; CHECK:       shrq $56, %rax
+; CHECK:       retq
+  %result = bitextract i8, b64 %src, i32 0
+  ret i8 %result
+}
+
+define b32 @test_bitinsert_var(b32 %base, i16 %val, i32 %off) {
+; CHECK-LABEL: test_bitinsert_var:
+; CHECK:       leal 16(%rdx), %ecx
+; CHECK:       roll %cl, %edi
+; CHECK:       andl $-65536, %edi
+; CHECK:       movzwl %si, %eax
+; CHECK:       orl %edi, %eax
+; CHECK:       rorl %cl, %eax
+; CHECK:       retq
+  %result = bitinsert b32 %base, i16 %val, i32 %off
+  ret b32 %result
+}
diff --git a/llvm/test/ExecutionEngine/bitinsert-bitextract-runtime.ll b/llvm/test/ExecutionEngine/bitinsert-bitextract-runtime.ll
new file mode 100644
index 0000000000000..4853669cd21dc
--- /dev/null
+++ b/llvm/test/ExecutionEngine/bitinsert-bitextract-runtime.ll
@@ -0,0 +1,29 @@
+; RUN: %lli %s | FileCheck %s
+; CHECK: extract=0x3456 insert=0x12beef78
+
+ at .str = private unnamed_addr constant [30 x i8] c"extract=0x%04x insert=0x%08x\0A\00", align 1
+
+declare i32 @printf(ptr, ...)
+
+define i16 @test_bitextract_var(b32 %src, i32 %off) noinline {
+  %result = bitextract i16, b32 %src, i32 %off
+  ret i16 %result
+}
+
+define b32 @test_bitinsert_var(b32 %base, i16 %val, i32 %off) noinline {
+  %result = bitinsert b32 %base, i16 %val, i32 %off
+  ret b32 %result
+}
+
+define i32 @main() {
+  ; Test values: 305419896 is 0x12345678, 48879 is 0xBEEF
+  %extract = call i16 @test_bitextract_var(b32 305419896, i32 8)
+  %insert = call b32 @test_bitinsert_var(b32 305419896, i16 48879, i32 8)
+  
+  %extract32 = zext i16 %extract to i32
+  %insert32 = bitcast b32 %insert to i32
+  
+  %fmt = getelementptr inbounds [30 x i8], ptr @.str, i64 0, i64 0
+  %call = call i32 (ptr, ...) @printf(ptr %fmt, i32 %extract32, i32 %insert32)
+  ret i32 0
+}
diff --git a/llvm/test/Verifier/bitextract-invalid-verifier.ll b/llvm/test/Verifier/bitextract-invalid-verifier.ll
new file mode 100644
index 0000000000000..9a1d30672089c
--- /dev/null
+++ b/llvm/test/Verifier/bitextract-invalid-verifier.ll
@@ -0,0 +1,8 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: not llvm-as %s 2>&1 | FileCheck %s
+; CHECK: bitextract result type cannot be wider than source type!
+
+define i64 @invalid(b32 %src) {
+  %r = bitextract i64, b32 %src, i32 0
+  ret i64 %r
+}
diff --git a/llvm/tools/llvm-c-test/echo.cpp b/llvm/tools/llvm-c-test/echo.cpp
index 5ed1eaa459d88..c15a013ab80e0 100644
--- a/llvm/tools/llvm-c-test/echo.cpp
+++ b/llvm/tools/llvm-c-test/echo.cpp
@@ -1002,6 +1002,20 @@ struct FunCloner {
         Dst = LLVMBuildFreeze(Builder, Arg, Name);
         break;
       }
+      case LLVMBitInsert: {
+        LLVMValueRef Base = CloneValue(LLVMGetOperand(Src, 0));
+        LLVMValueRef Val = CloneValue(LLVMGetOperand(Src, 1));
+        LLVMValueRef Offset = CloneValue(LLVMGetOperand(Src, 2));
+        Dst = LLVMBuildBitInsert(Builder, Base, Val, Offset, Name);
+        break;
+      }
+      case LLVMBitExtract: {
+        LLVMTypeRef Type = CloneType(LLVMTypeOf(Src));
+        LLVMValueRef SrcV = CloneValue(LLVMGetOperand(Src, 0));
+        LLVMValueRef Offset = CloneValue(LLVMGetOperand(Src, 1));
+        Dst = LLVMBuildBitExtract(Builder, Type, SrcV, Offset, Name);
+        break;
+      }
       case LLVMFence: {
         LLVMAtomicOrdering Ordering = LLVMGetOrdering(Src);
         Dst = LLVMBuildFenceSyncScope(Builder, Ordering,

>From ad44a63c473441b59e34c442a3956bb4598ef84b Mon Sep 17 00:00:00 2001
From: Pedro Vicente <pedro.costa.vicente at tecnico.ulisboa.pt>
Date: Wed, 3 Jun 2026 16:28:38 +0100
Subject: [PATCH 3/9] update langref

---
 llvm/docs/LangRef.rst | 86 +------------------------------------------
 1 file changed, 2 insertions(+), 84 deletions(-)

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 4323405ecbde8..7c1dec4663d4a 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -10596,88 +10596,6 @@ Example:
 
 .. _binaryops:
 
-Byte Operations
------------------
-
-Instructions for bit manipulation for bytes.
-
-.. _i_bitextract:
-
-'``bitextract``' Instruction
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Syntax:
-"""""""
-
-::
-
-      <result> = bitextract <ty>, <tx> <source>, i32 <offset>
-
-Overview:
-"""""""""
-
-The '``bitextract``' extracts a value from a byte.
-
-Arguments:
-""""""""""
-The '``bitextract``' instruction takes any first-class type ty (the
-return type), a Byte value source, and an offset.
-
-Semantics:
-""""""""""
-
-The '``bitextract``' instruction returns a value of the specified type.
-The returned value is first extracted from the source, starting at the
-bit specified by the offset, and then bitcasted to the return type.
-If the range offset+ty.bitwidth exceeds the source width, it returns
-poison.
-
-Example:
-""""""""
-
-.. code-block:: text
-
-      %result = bitextract i8, b32 %src, i32 24 ; Extract the last 8 bits from %src and return an 8-bit integer
-
-.. _i_bitinsert:
-
-'``bitinsert``' Instruction
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Syntax:
-"""""""
-
-::
-
-      <result> = bitinsert <tx> <base>, <ty> <val>, i32 <offset>
-
-Overview:
-"""""""""
-
-This instruction '``bitinsert``' inserts a value into a specific
-position within a byte.
-
-Arguments:
-""""""""""
-The first argument (base) of '``bitinsert``' must be of a byte type.
-The second operand (val) must be an arbitrary type.
-
-Semantics:
-""""""""""
-
-The returned value is of the same byte type as the first argument.
-It returns the first argument where the bits in the range
-[offset, offset + ty.bitlength - 1] have been replaced with val. 
-If the range (offset + ty.bitwidth) is greater than the bitwidth of
-the first argument, it returns poison.
-
-Example:
-""""""""
-
-.. code-block:: text
-
-      %result = bitinsert b32 %x, i8 %y, i32 3 ; Inserts the %y bits into %x with an offset of 3
-
 Binary Operations
 -----------------
 
@@ -11619,7 +11537,7 @@ Syntax:
 Overview:
 """""""""
 
-The '``bitextract``' extracts a value from a byte.
+The '``bitextract``' extracts a value from a byte type.
 
 Arguments:
 """"""""""
@@ -11658,7 +11576,7 @@ Overview:
 """""""""
 
 This instruction '``bitinsert``' inserts a value into a specific
-position within a byte.
+position within a byte type.
 
 Arguments:
 """"""""""

>From ccb30029a25867ef19ab8ee33107dc0b8eb99c3a Mon Sep 17 00:00:00 2001
From: Pedro Vicente <pedro.costa.vicente at tecnico.ulisboa.pt>
Date: Wed, 3 Jun 2026 20:32:46 +0100
Subject: [PATCH 4/9] tests fixed

---
 .../Inputs/reference_default_vocab_print.txt  |  2 +
 .../Inputs/reference_wtd1_vocab_print.txt     |  2 +
 .../Inputs/reference_wtd2_vocab_print.txt     |  2 +
 .../Inputs/reference_wtd3_vocab_print.txt     |  2 +
 llvm/test/Analysis/IR2Vec/vocab-test.ll       |  4 +-
 llvm/test/Bitcode/bitinsert-bitextract.ll     | 14 +++
 llvm/test/tools/llvm-ir2vec/entities.ll       | 90 ++++++++++---------
 llvm/test/tools/llvm-ir2vec/triplets.ll       | 76 ++++++++--------
 llvm/unittests/Analysis/IR2VecTest.cpp        | 31 ++++---
 9 files changed, 125 insertions(+), 98 deletions(-)
 create mode 100644 llvm/test/Analysis/IR2Vec/Inputs/reference_wtd3_vocab_print.txt
 create mode 100644 llvm/test/Bitcode/bitinsert-bitextract.ll

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 cc36415abb00b..86e63affc15fb 100644
--- a/llvm/test/Analysis/IR2Vec/Inputs/reference_default_vocab_print.txt
+++ b/llvm/test/Analysis/IR2Vec/Inputs/reference_default_vocab_print.txt
@@ -67,6 +67,8 @@ Key: ExtractValue:  [ 127.00  128.00 ]
 Key: InsertValue:  [ 129.00  130.00 ]
 Key: LandingPad:  [ 131.00  132.00 ]
 Key: Freeze:  [ 133.00  134.00 ]
+Key: BitInsert:  [ 0.00  0.00 ]
+Key: BitExtract:  [ 0.00  0.00 ]
 Key: FloatTy:  [ 0.50  1.00 ]
 Key: VoidTy:  [ 1.50  2.00 ]
 Key: LabelTy:  [ 2.50  3.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 8d837e9502739..248199f666967 100644
--- a/llvm/test/Analysis/IR2Vec/Inputs/reference_wtd1_vocab_print.txt
+++ b/llvm/test/Analysis/IR2Vec/Inputs/reference_wtd1_vocab_print.txt
@@ -67,6 +67,8 @@ Key: ExtractValue:  [ 63.50  64.00 ]
 Key: InsertValue:  [ 64.50  65.00 ]
 Key: LandingPad:  [ 65.50  66.00 ]
 Key: Freeze:  [ 66.50  67.00 ]
+Key: BitInsert:  [ 0.00  0.00 ]
+Key: BitExtract:  [ 0.00  0.00 ]
 Key: FloatTy:  [ 0.50  1.00 ]
 Key: VoidTy:  [ 1.50  2.00 ]
 Key: LabelTy:  [ 2.50  3.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 3d31b9d9db315..913d6d16d1d91 100644
--- a/llvm/test/Analysis/IR2Vec/Inputs/reference_wtd2_vocab_print.txt
+++ b/llvm/test/Analysis/IR2Vec/Inputs/reference_wtd2_vocab_print.txt
@@ -67,6 +67,8 @@ Key: ExtractValue:  [ 12.70  12.80 ]
 Key: InsertValue:  [ 12.90  13.00 ]
 Key: LandingPad:  [ 13.10  13.20 ]
 Key: Freeze:  [ 13.30  13.40 ]
+Key: BitInsert:  [ 0.00  0.00 ]
+Key: BitExtract:  [ 0.00  0.00 ]
 Key: FloatTy:  [ 0.00  0.00 ]
 Key: VoidTy:  [ 0.00  0.00 ]
 Key: LabelTy:  [ 0.00  0.00 ]
diff --git a/llvm/test/Analysis/IR2Vec/Inputs/reference_wtd3_vocab_print.txt b/llvm/test/Analysis/IR2Vec/Inputs/reference_wtd3_vocab_print.txt
new file mode 100644
index 0000000000000..c00453b3a9781
--- /dev/null
+++ b/llvm/test/Analysis/IR2Vec/Inputs/reference_wtd3_vocab_print.txt
@@ -0,0 +1,2 @@
+Command 'opt' not found, but can be installed with:
+sudo apt install llvm
diff --git a/llvm/test/Analysis/IR2Vec/vocab-test.ll b/llvm/test/Analysis/IR2Vec/vocab-test.ll
index ff6b4e7ad131f..8ed46a82bdcde 100644
--- a/llvm/test/Analysis/IR2Vec/vocab-test.ll
+++ b/llvm/test/Analysis/IR2Vec/vocab-test.ll
@@ -1,5 +1,5 @@
 ; REQUIRES: x86_64-linux
-; RUN: opt -passes='print<ir2vec-vocab>' -S -o /dev/null -ir2vec-vocab-path=%S/Inputs/dummy_2D_vocab.json %s 2> %t1.log 
+; RUN: opt -passes='print<ir2vec-vocab>' -S -o /dev/null -ir2vec-vocab-path=%S/Inputs/dummy_2D_vocab.json %s 2> %t1.log
 ; RUN: diff %S/Inputs/reference_default_vocab_print.txt %t1.log
 
 ; RUN: opt -passes='print<ir2vec-vocab>' -o /dev/null -ir2vec-vocab-path=%S/Inputs/dummy_2D_vocab.json -ir2vec-opc-weight=0.5 -ir2vec-type-weight=0.5 -ir2vec-arg-weight=0.5 %s 2> %t2.log
@@ -7,7 +7,7 @@
 
 ; RUN: opt -passes='print<ir2vec-vocab>' -o /dev/null -ir2vec-vocab-path=%S/Inputs/dummy_2D_vocab.json -ir2vec-opc-weight=0.1 -ir2vec-type-weight=0 -ir2vec-arg-weight=0 %s 2> %t3.log
 ; RUN: diff %S/Inputs/reference_wtd2_vocab_print.txt %t3.log
- 
+
 define dso_local void @test() {
   entry:
     ret void
diff --git a/llvm/test/Bitcode/bitinsert-bitextract.ll b/llvm/test/Bitcode/bitinsert-bitextract.ll
new file mode 100644
index 0000000000000..1624b3355a379
--- /dev/null
+++ b/llvm/test/Bitcode/bitinsert-bitextract.ll
@@ -0,0 +1,14 @@
+; RUN: llvm-as %s -o - -f | llvm-dis | FileCheck %s
+; RUN: llvm-as %s -o - -f | verify-uselistorder
+
+define b32 @test_bitinsert(b32 %x, i8 %y) {
+; CHECK: %r = bitinsert b32 %x, i8 %y, i32 3
+  %r = bitinsert b32 %x, i8 %y, i32 3
+  ret b32 %r
+}
+
+define i8 @test_bitextract(b32 %src) {
+; CHECK: %r = bitextract i8, b32 %src, i32 24
+  %r = bitextract i8, b32 %src, i32 24
+  ret i8 %r
+}
\ No newline at end of file
diff --git a/llvm/test/tools/llvm-ir2vec/entities.ll b/llvm/test/tools/llvm-ir2vec/entities.ll
index 002614164c128..953fb3616f0cf 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: 112
+CHECK: 114
 CHECK-NEXT: Ret	0
 CHECK-NEXT: UncondBr	1
 CHECK-NEXT: CondBr	2
@@ -70,46 +70,48 @@ 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
+CHECK-NEXT: BitInsert	69
+CHECK-NEXT: BitExtract	70
+CHECK-NEXT: FloatTy	71
+CHECK-NEXT: VoidTy	72
+CHECK-NEXT: LabelTy	73
+CHECK-NEXT: MetadataTy	74
+CHECK-NEXT: VectorTy	75
+CHECK-NEXT: TokenTy	76
+CHECK-NEXT: IntegerTy	77
+CHECK-NEXT: ByteTy	78
+CHECK-NEXT: FunctionTy	79
+CHECK-NEXT: PointerTy	80
+CHECK-NEXT: StructTy	81
+CHECK-NEXT: ArrayTy	82
+CHECK-NEXT: UnknownTy	83
+CHECK-NEXT: Function	84
+CHECK-NEXT: Pointer	85
+CHECK-NEXT: Constant	86
+CHECK-NEXT: Variable	87
+CHECK-NEXT: FCMP_false	88
+CHECK-NEXT: FCMP_oeq	89
+CHECK-NEXT: FCMP_ogt	90
+CHECK-NEXT: FCMP_oge	91
+CHECK-NEXT: FCMP_olt	92
+CHECK-NEXT: FCMP_ole	93
+CHECK-NEXT: FCMP_one	94
+CHECK-NEXT: FCMP_ord	95
+CHECK-NEXT: FCMP_uno	96
+CHECK-NEXT: FCMP_ueq	97
+CHECK-NEXT: FCMP_ugt	98
+CHECK-NEXT: FCMP_uge	99
+CHECK-NEXT: FCMP_ult	100
+CHECK-NEXT: FCMP_ule	101
+CHECK-NEXT: FCMP_une	102
+CHECK-NEXT: FCMP_true	103
+CHECK-NEXT: ICMP_eq	104
+CHECK-NEXT: ICMP_ne	105
+CHECK-NEXT: ICMP_ugt	106
+CHECK-NEXT: ICMP_uge	107
+CHECK-NEXT: ICMP_ult	108
+CHECK-NEXT: ICMP_ule	109
+CHECK-NEXT: ICMP_sgt	110
+CHECK-NEXT: ICMP_sge	111
+CHECK-NEXT: ICMP_slt	112
+CHECK-NEXT: ICMP_sle	113
diff --git a/llvm/test/tools/llvm-ir2vec/triplets.ll b/llvm/test/tools/llvm-ir2vec/triplets.ll
index 45a158c926900..329299cc4ec91 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: 13	75	0
-; TRIPLETS-NEXT: 13	85	2
-; TRIPLETS-NEXT: 13	85	3
-; TRIPLETS-NEXT: 13	0	1
-; TRIPLETS-NEXT: 0	70	0
-; TRIPLETS-NEXT: 0	85	2
-; TRIPLETS-NEXT: 17	75	0
-; TRIPLETS-NEXT: 17	85	2
-; TRIPLETS-NEXT: 17	85	3
-; TRIPLETS-NEXT: 17	0	1
-; TRIPLETS-NEXT: 0	70	0
-; TRIPLETS-NEXT: 0	85	2
-; TRIPLETS-NEXT: 31	78	0
-; TRIPLETS-NEXT: 31	84	2
-; TRIPLETS-NEXT: 31	31	1
-; TRIPLETS-NEXT: 31	78	0
-; TRIPLETS-NEXT: 31	84	2
-; TRIPLETS-NEXT: 31	33	1
-; TRIPLETS-NEXT: 33	70	0
-; TRIPLETS-NEXT: 33	85	2
-; TRIPLETS-NEXT: 33	83	3
-; TRIPLETS-NEXT: 33	33	1
-; TRIPLETS-NEXT: 33	70	0
-; TRIPLETS-NEXT: 33	85	2
-; TRIPLETS-NEXT: 33	83	3
-; TRIPLETS-NEXT: 33	32	1
-; TRIPLETS-NEXT: 32	75	0
-; TRIPLETS-NEXT: 32	83	2
-; TRIPLETS-NEXT: 32	32	1
-; TRIPLETS-NEXT: 32	75	0
-; TRIPLETS-NEXT: 32	83	2
-; TRIPLETS-NEXT: 32	13	1
-; TRIPLETS-NEXT: 13	75	0
-; TRIPLETS-NEXT: 13	85	2
-; TRIPLETS-NEXT: 13	85	3
-; TRIPLETS-NEXT: 13	0	1
-; TRIPLETS-NEXT: 0	70	0
-; TRIPLETS-NEXT: 0	85	2
+; TRIPLETS-NEXT: 13 77 0
+; TRIPLETS-NEXT: 13 87 2
+; TRIPLETS-NEXT: 13 87 3
+; TRIPLETS-NEXT: 13 0 1
+; TRIPLETS-NEXT: 0 72 0
+; TRIPLETS-NEXT: 0 87 2
+; TRIPLETS-NEXT: 17 77 0
+; TRIPLETS-NEXT: 17 87 2
+; TRIPLETS-NEXT: 17 87 3
+; TRIPLETS-NEXT: 17 0 1
+; TRIPLETS-NEXT: 0 72 0
+; TRIPLETS-NEXT: 0 87 2
+; TRIPLETS-NEXT: 31 80 0
+; TRIPLETS-NEXT: 31 86 2
+; TRIPLETS-NEXT: 31 31 1
+; TRIPLETS-NEXT: 31 80 0
+; TRIPLETS-NEXT: 31 86 2
+; TRIPLETS-NEXT: 31 33 1
+; TRIPLETS-NEXT: 33 72 0
+; TRIPLETS-NEXT: 33 87 2
+; TRIPLETS-NEXT: 33 85 3
+; TRIPLETS-NEXT: 33 33 1
+; TRIPLETS-NEXT: 33 72 0
+; TRIPLETS-NEXT: 33 87 2
+; TRIPLETS-NEXT: 33 85 3
+; TRIPLETS-NEXT: 33 32 1
+; TRIPLETS-NEXT: 32 77 0
+; TRIPLETS-NEXT: 32 85 2
+; TRIPLETS-NEXT: 32 32 1
+; TRIPLETS-NEXT: 32 77 0
+; TRIPLETS-NEXT: 32 85 2
+; TRIPLETS-NEXT: 32 13 1
+; TRIPLETS-NEXT: 13 77 0
+; TRIPLETS-NEXT: 13 87 2
+; TRIPLETS-NEXT: 13 87 3
+; TRIPLETS-NEXT: 13 0 1
+; TRIPLETS-NEXT: 0 72 0
+; TRIPLETS-NEXT: 0 87 2
diff --git a/llvm/unittests/Analysis/IR2VecTest.cpp b/llvm/unittests/Analysis/IR2VecTest.cpp
index fe67442da0f90..db2708ecb5bcd 100644
--- a/llvm/unittests/Analysis/IR2VecTest.cpp
+++ b/llvm/unittests/Analysis/IR2VecTest.cpp
@@ -363,8 +363,9 @@ TEST_F(IR2VecTestFixture, GetInstVec_Symbolic) {
   EXPECT_EQ(AddEmb.size(), 2u);
   EXPECT_EQ(RetEmb.size(), 2u);
 
-  EXPECT_TRUE(AddEmb.approximatelyEquals(Embedding(2, 26.1)));
-  EXPECT_TRUE(RetEmb.approximatelyEquals(Embedding(2, 15.8)));
+  EXPECT_TRUE(AddEmb.approximatelyEquals(Embedding(2, 26.7)));
+  EXPECT_TRUE(RetEmb.approximatelyEquals(Embedding(2, 16.2)));
+
 }
 
 TEST_F(IR2VecTestFixture, GetInstVec_FlowAware) {
@@ -376,8 +377,10 @@ TEST_F(IR2VecTestFixture, GetInstVec_FlowAware) {
   EXPECT_EQ(AddEmb.size(), 2u);
   EXPECT_EQ(RetEmb.size(), 2u);
 
-  EXPECT_TRUE(AddEmb.approximatelyEquals(Embedding(2, 26.1)));
-  EXPECT_TRUE(RetEmb.approximatelyEquals(Embedding(2, 33.3)));
+  llvm::errs() << "Add[0]=" << AddEmb[0] << " Ret[0]=" << RetEmb[0] << "\n";
+
+  EXPECT_TRUE(AddEmb.approximatelyEquals(Embedding(2, 26.7)));
+  EXPECT_TRUE(RetEmb.approximatelyEquals(Embedding(2, 34.1)));
 }
 
 TEST_F(IR2VecTestFixture, GetBBVector_Symbolic) {
@@ -387,9 +390,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: {26.1, 26.1} + {15.8, 15.8} =
-  // {41.9, 41.9}
-  EXPECT_TRUE(BBVec.approximatelyEquals(Embedding(2, 41.9)));
+  // BB vector should be sum of add and ret: {26.7, 26.7} + {16.2, 16.2} =
+  // {42.9, 42.9}
+  EXPECT_TRUE(BBVec.approximatelyEquals(Embedding(2, 42.9)));
 }
 
 TEST_F(IR2VecTestFixture, GetBBVector_FlowAware) {
@@ -399,9 +402,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: {26.1, 26.1} + {33.3, 33.3} =
-  // {59.4, 59.4}
-  EXPECT_TRUE(BBVec.approximatelyEquals(Embedding(2, 59.4)));
+  // BB vector should be sum of add and ret: {26.7, 26.7} + {34.1, 34.1} =
+  // {60.8, 60.8}
+  EXPECT_TRUE(BBVec.approximatelyEquals(Embedding(2, 60.8)));
 }
 
 TEST_F(IR2VecTestFixture, GetFunctionVector_Symbolic) {
@@ -412,8 +415,8 @@ TEST_F(IR2VecTestFixture, GetFunctionVector_Symbolic) {
 
   EXPECT_EQ(FuncVec.size(), 2u);
 
-  // Function vector should match BB vector (only one BB): {41.9, 41.9}
-  EXPECT_TRUE(FuncVec.approximatelyEquals(Embedding(2, 41.9)));
+  // Function vector should match BB vector (only one BB): {42.9, 42.9}
+  EXPECT_TRUE(FuncVec.approximatelyEquals(Embedding(2, 42.9)));
 }
 
 TEST_F(IR2VecTestFixture, GetFunctionVector_FlowAware) {
@@ -423,8 +426,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): {59.4, 59.4}
-  EXPECT_TRUE(FuncVec.approximatelyEquals(Embedding(2, 59.4)));
+  // Function vector should match BB vector (only one BB): {60.8, 60.8}
+  EXPECT_TRUE(FuncVec.approximatelyEquals(Embedding(2, 60.8)));
 }
 
 TEST_F(IR2VecTestFixture, MultipleComputeEmbeddingsConsistency_Symbolic) {

>From d43aabb8fefadb18e2fe7cb356994fe4feadcaa9 Mon Sep 17 00:00:00 2001
From: Pedro Vicente <pedro.costa.vicente at tecnico.ulisboa.pt>
Date: Wed, 3 Jun 2026 20:48:36 +0100
Subject: [PATCH 5/9] formatted

---
 .../llvm/Analysis/InstSimplifyFolder.h        |  6 ++---
 llvm/include/llvm/Analysis/TargetFolder.h     |  6 ++---
 llvm/include/llvm/Bitcode/LLVMBitCodes.h      |  2 +-
 llvm/include/llvm/IR/ConstantFolder.h         |  6 ++---
 llvm/include/llvm/IR/IRBuilderFolder.h        |  3 +--
 llvm/include/llvm/IR/InstVisitor.h            |  2 +-
 llvm/include/llvm/IR/NoFolder.h               |  8 +++---
 llvm/lib/AsmParser/LLLexer.cpp                |  4 +--
 llvm/lib/Bitcode/Reader/BitcodeReader.cpp     | 10 ++++---
 llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp  | 27 +++++++++++--------
 .../SelectionDAG/SelectionDAGBuilder.cpp      | 27 +++++++++++--------
 llvm/lib/CodeGen/TargetLoweringBase.cpp       |  6 +++--
 llvm/lib/IR/Core.cpp                          | 12 ++++-----
 llvm/lib/IR/Instruction.cpp                   |  6 +++--
 14 files changed, 66 insertions(+), 59 deletions(-)

diff --git a/llvm/include/llvm/Analysis/InstSimplifyFolder.h b/llvm/include/llvm/Analysis/InstSimplifyFolder.h
index d79c619114a72..4390c55780533 100644
--- a/llvm/include/llvm/Analysis/InstSimplifyFolder.h
+++ b/llvm/include/llvm/Analysis/InstSimplifyFolder.h
@@ -115,14 +115,12 @@ class LLVM_ABI InstSimplifyFolder final : public IRBuilderFolder {
     return simplifyShuffleVectorInst(V1, V2, Mask, RetTy, SQ);
   }
 
-  Value *FoldBitInsert(Value *Base, Value *Val,
-                       Value *Offset) const override {
+  Value *FoldBitInsert(Value *Base, Value *Val, Value *Offset) const override {
     // TODO
     return nullptr;
   }
 
-  Value *FoldBitExtract(Type *Ty, Value *Src,
-                        Value *Offset) const override {
+  Value *FoldBitExtract(Type *Ty, Value *Src, Value *Offset) const override {
     // TODO
     return nullptr;
   }
diff --git a/llvm/include/llvm/Analysis/TargetFolder.h b/llvm/include/llvm/Analysis/TargetFolder.h
index dd8264c34e58e..4396dbd5f61d8 100644
--- a/llvm/include/llvm/Analysis/TargetFolder.h
+++ b/llvm/include/llvm/Analysis/TargetFolder.h
@@ -184,13 +184,11 @@ class LLVM_ABI TargetFolder final : public IRBuilderFolder {
     return nullptr;
   }
 
-  Value *FoldBitInsert(Value *Base, Value *Val,
-                       Value *Offset) const override {
+  Value *FoldBitInsert(Value *Base, Value *Val, Value *Offset) const override {
     return nullptr;
   }
 
-  Value *FoldBitExtract(Type *Ty, Value *Src,
-                        Value *Offset) const override {
+  Value *FoldBitExtract(Type *Ty, Value *Src, Value *Offset) const override {
     return nullptr;
   }
 
diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
index d5691877b20d2..d088c9515c950 100644
--- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h
+++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
@@ -703,7 +703,7 @@ enum FunctionCodes {
   FUNC_CODE_DEBUG_RECORD_LABEL = 65, // [DILocation, DILabel]
   FUNC_CODE_DEBUG_RECORD_DECLARE_VALUE =
       66, // [DILocation, DILocalVariable, DIExpression, ValueAsMetadata]
-  FUNC_CODE_INST_BITINSERT = 67, // BITINSERT: [val, val ,val]
+  FUNC_CODE_INST_BITINSERT = 67,  // BITINSERT: [val, val ,val]
   FUNC_CODE_INST_BITEXTRACT = 68, // BITEXTRACT: [val, val, val]
 };
 
diff --git a/llvm/include/llvm/IR/ConstantFolder.h b/llvm/include/llvm/IR/ConstantFolder.h
index 8bb5b8f45a314..e31de22c7129c 100644
--- a/llvm/include/llvm/IR/ConstantFolder.h
+++ b/llvm/include/llvm/IR/ConstantFolder.h
@@ -172,13 +172,11 @@ class LLVM_ABI ConstantFolder final : public IRBuilderFolder {
     return nullptr;
   }
 
-  Value *FoldBitInsert(Value *Base, Value *Val,
-                       Value *Offset) const override {
+  Value *FoldBitInsert(Value *Base, Value *Val, Value *Offset) const override {
     return nullptr;
   }
 
-  Value *FoldBitExtract(Type *Ty, Value *Src,
-                        Value *Offset) const override {
+  Value *FoldBitExtract(Type *Ty, Value *Src, Value *Offset) const override {
     return nullptr;
   }
 
diff --git a/llvm/include/llvm/IR/IRBuilderFolder.h b/llvm/include/llvm/IR/IRBuilderFolder.h
index 6db2424155128..98f0e72da40fc 100644
--- a/llvm/include/llvm/IR/IRBuilderFolder.h
+++ b/llvm/include/llvm/IR/IRBuilderFolder.h
@@ -83,8 +83,7 @@ class LLVM_ABI IRBuilderFolder {
   virtual Value *FoldBitInsert(Value *Base, Value *Val,
                                Value *Offset) const = 0;
 
-  virtual Value *FoldBitExtract(Type *Ty, Value *Src,
-                                Value *Offset) const = 0;
+  virtual Value *FoldBitExtract(Type *Ty, Value *Src, Value *Offset) const = 0;
 
   //===--------------------------------------------------------------------===//
   // Cast/Conversion Operators
diff --git a/llvm/include/llvm/IR/InstVisitor.h b/llvm/include/llvm/IR/InstVisitor.h
index 0f5f2ab6c1317..e40f0f611ea8e 100644
--- a/llvm/include/llvm/IR/InstVisitor.h
+++ b/llvm/include/llvm/IR/InstVisitor.h
@@ -199,7 +199,7 @@ class InstVisitor {
   RetTy visitCleanupPadInst(CleanupPadInst &I) { DELEGATE(FuncletPadInst); }
   RetTy visitCatchPadInst(CatchPadInst &I)     { DELEGATE(FuncletPadInst); }
   RetTy visitFreezeInst(FreezeInst &I)         { DELEGATE(Instruction); }
-  RetTy visitBitInsertInst(BitInsertInst &I)   { DELEGATE(Instruction); }
+  RetTy visitBitInsertInst(BitInsertInst &I) { DELEGATE(Instruction); }
   RetTy visitBitExtractInst(BitExtractInst &I) { DELEGATE(Instruction); }
 
   RetTy visitMemSetInst(MemSetInst &I)            { DELEGATE(MemIntrinsic); }
diff --git a/llvm/include/llvm/IR/NoFolder.h b/llvm/include/llvm/IR/NoFolder.h
index 24b7856bc55df..80ce1fe8cb7f1 100644
--- a/llvm/include/llvm/IR/NoFolder.h
+++ b/llvm/include/llvm/IR/NoFolder.h
@@ -109,13 +109,11 @@ class LLVM_ABI NoFolder final : public IRBuilderFolder {
     return nullptr;
   }
 
-  Value *FoldBitInsert(Value *Base, Value *Val,
-                      Value *Offset) const override {
+  Value *FoldBitInsert(Value *Base, Value *Val, Value *Offset) const override {
     return nullptr;
   }
-  
-  Value *FoldBitExtract(Type *Ty, Value *Src,
-                        Value *Offset) const override {
+
+  Value *FoldBitExtract(Type *Ty, Value *Src, Value *Offset) const override {
     return nullptr;
   }
 
diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp
index 26d04800aef36..d16dd78174289 100644
--- a/llvm/lib/AsmParser/LLLexer.cpp
+++ b/llvm/lib/AsmParser/LLLexer.cpp
@@ -996,8 +996,8 @@ lltok::Kind LLLexer::LexIdentifier() {
   INSTKEYWORD(cleanuppad,   CleanupPad);
 
   INSTKEYWORD(freeze,       Freeze);
-  INSTKEYWORD(bitinsert,    BitInsert);
-  INSTKEYWORD(bitextract,   BitExtract);
+  INSTKEYWORD(bitinsert, BitInsert);
+  INSTKEYWORD(bitextract, BitExtract);
 
 #undef INSTKEYWORD
 
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index ef28f922a3b45..14f0cd8ac62ff 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -1838,8 +1838,8 @@ Expected<Value *> BitcodeReader::materializeValue(unsigned StartValID,
                                   InsertBB);
         break;
       case Instruction::BitExtract:
-        I = BitExtractInst::Create(BC->getType(), Ops[0], Ops[1],
-                                   "constexpr", InsertBB);
+        I = BitExtractInst::Create(BC->getType(), Ops[0], Ops[1], "constexpr",
+                                   InsertBB);
         break;
       case Instruction::BitInsert:
         I = BitInsertInst::Create(Ops[0], Ops[1], Ops[2], "constexpr",
@@ -5554,11 +5554,13 @@ Error BitcodeReader::parseFunctionBody(Function *F) {
       break;
     }
 
-    case bitc::FUNC_CODE_INST_BITINSERT: { // BITINSERT: [ty, opval, opval, opval]
+    case bitc::FUNC_CODE_INST_BITINSERT: { // BITINSERT: [ty, opval, opval,
+                                           // opval]
       unsigned OpNum = 0;
       Value *Base, *Val, *Offset;
       unsigned BaseTypeID, ValTypeID, OffsetTypeID;
-      if (getValueTypePair(Record, OpNum, NextValueNo, Base, BaseTypeID, CurBB) ||
+      if (getValueTypePair(Record, OpNum, NextValueNo, Base, BaseTypeID,
+                           CurBB) ||
           getValueTypePair(Record, OpNum, NextValueNo, Val, ValTypeID, CurBB) ||
           getValueTypePair(Record, OpNum, NextValueNo, Offset, OffsetTypeID,
                            CurBB))
diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
index 204b1dc4424fe..afec0d5916e5b 100644
--- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
@@ -3526,13 +3526,13 @@ bool IRTranslator::translateShuffleVector(const User &U,
 
 bool IRTranslator::translateBitInsert(const User &U,
                                       MachineIRBuilder &MIRBuilder) {
-  Register Res    = getOrCreateVReg(U);
-  Register Base   = getOrCreateVReg(*U.getOperand(0));
-  Register Val    = getOrCreateVReg(*U.getOperand(1));
+  Register Res = getOrCreateVReg(U);
+  Register Base = getOrCreateVReg(*U.getOperand(0));
+  Register Val = getOrCreateVReg(*U.getOperand(1));
   Register Offset = getOrCreateVReg(*U.getOperand(2));
   MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
   LLT BaseTy = MRI.getType(Base);
-  LLT ValTy  = MRI.getType(Val);
+  LLT ValTy = MRI.getType(Val);
 
   // Convert Offset to BaseTy
   Register LegalOffset = MIRBuilder.buildZExtOrTrunc(BaseTy, Offset).getReg(0);
@@ -3540,9 +3540,11 @@ bool IRTranslator::translateBitInsert(const User &U,
   // RotateAmount = Offset + width(Val)
   unsigned ValBitWidth = ValTy.getSizeInBits();
   Register ValWidth = MIRBuilder.buildConstant(BaseTy, ValBitWidth).getReg(0);
-  Register RotateAmount = MIRBuilder.buildAdd(BaseTy, LegalOffset, ValWidth).getReg(0);
+  Register RotateAmount =
+      MIRBuilder.buildAdd(BaseTy, LegalOffset, ValWidth).getReg(0);
 
-  Register RotatedBase = MIRBuilder.buildRotateLeft(BaseTy, Base, RotateAmount).getReg(0);
+  Register RotatedBase =
+      MIRBuilder.buildRotateLeft(BaseTy, Base, RotateAmount).getReg(0);
 
   // Truncate or extend Val to BaseTy so only the inserted bit range remains.
   Register ExtVal = MIRBuilder.buildZExtOrTrunc(BaseTy, Val).getReg(0);
@@ -3563,8 +3565,8 @@ bool IRTranslator::translateBitInsert(const User &U,
 
 bool IRTranslator::translateBitExtract(const User &U,
                                        MachineIRBuilder &MIRBuilder) {
-  Register Res    = getOrCreateVReg(U);
-  Register Src    = getOrCreateVReg(*U.getOperand(0));
+  Register Res = getOrCreateVReg(U);
+  Register Src = getOrCreateVReg(*U.getOperand(0));
   Register Offset = getOrCreateVReg(*U.getOperand(1));
   MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
   LLT SrcTy = MRI.getType(Src);
@@ -3579,11 +3581,14 @@ bool IRTranslator::translateBitExtract(const User &U,
 
   // RotateAmount = Offset + width
   unsigned ResultBitWidth = ResTy.getSizeInBits();
-  Register ResultWidth = MIRBuilder.buildConstant(SrcTy, ResultBitWidth).getReg(0);
-  Register RotateAmount = MIRBuilder.buildAdd(SrcTy, LegalOffset, ResultWidth).getReg(0);
+  Register ResultWidth =
+      MIRBuilder.buildConstant(SrcTy, ResultBitWidth).getReg(0);
+  Register RotateAmount =
+      MIRBuilder.buildAdd(SrcTy, LegalOffset, ResultWidth).getReg(0);
 
   // Rotate left by (Offset + ResultWidth)
-  Register Rotated = MIRBuilder.buildRotateLeft(SrcTy, Src, RotateAmount).getReg(0);
+  Register Rotated =
+      MIRBuilder.buildRotateLeft(SrcTy, Src, RotateAmount).getReg(0);
 
   // Truncating to ResTy discards the high bits for free
   if (SrcTy == ResTy)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 124633e362dfb..32f7abe0fd852 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -4152,11 +4152,11 @@ void SelectionDAGBuilder::visitInsertElement(const User &I) {
 }
 
 void SelectionDAGBuilder::visitBitInsert(const User &I) {
-  SDValue Base   = getValue(I.getOperand(0));
-  SDValue Val    = getValue(I.getOperand(1));
+  SDValue Base = getValue(I.getOperand(0));
+  SDValue Val = getValue(I.getOperand(1));
   SDValue Offset = getValue(I.getOperand(2));
   EVT BaseVT = Base.getValueType();
-  EVT ValVT  = Val.getValueType();
+  EVT ValVT = Val.getValueType();
   const TargetLowering &TLI = DAG.getTargetLoweringInfo();
   SDLoc dl = getCurSDLoc();
 
@@ -4164,30 +4164,34 @@ void SelectionDAGBuilder::visitBitInsert(const User &I) {
 
   unsigned ValBitWidth = ValVT.getScalarSizeInBits();
   SDValue ValWidth = DAG.getConstant(ValBitWidth, dl, BaseVT);
-  SDValue RotateAmount = DAG.getNode(ISD::ADD, dl, BaseVT, LegalOffset, ValWidth);
+  SDValue RotateAmount =
+      DAG.getNode(ISD::ADD, dl, BaseVT, LegalOffset, ValWidth);
 
   // Legalize rotate amount to the target's shift amount type
   EVT ShiftAmtTy = TLI.getShiftAmountTy(BaseVT, DAG.getDataLayout());
   SDValue LegalRotateAmount = DAG.getZExtOrTrunc(RotateAmount, dl, ShiftAmtTy);
 
-  SDValue RotatedBase = DAG.getNode(ISD::ROTL, dl, BaseVT, Base, LegalRotateAmount);
+  SDValue RotatedBase =
+      DAG.getNode(ISD::ROTL, dl, BaseVT, Base, LegalRotateAmount);
 
   unsigned BaseBitWidth = BaseVT.getScalarSizeInBits();
-  APInt ClearMask = APInt::getHighBitsSet(BaseBitWidth, BaseBitWidth - ValBitWidth);
+  APInt ClearMask =
+      APInt::getHighBitsSet(BaseBitWidth, BaseBitWidth - ValBitWidth);
   SDValue ClearedBase = DAG.getNode(ISD::AND, dl, BaseVT, RotatedBase,
                                     DAG.getConstant(ClearMask, dl, BaseVT));
 
-  SDValue ExtVal  = DAG.getZExtOrTrunc(Val, dl, BaseVT);
+  SDValue ExtVal = DAG.getZExtOrTrunc(Val, dl, BaseVT);
   SDValue Inserted = DAG.getNode(ISD::OR, dl, BaseVT, ClearedBase, ExtVal);
 
-  SDValue Result = DAG.getNode(ISD::ROTR, dl, BaseVT, Inserted, LegalRotateAmount);
+  SDValue Result =
+      DAG.getNode(ISD::ROTR, dl, BaseVT, Inserted, LegalRotateAmount);
   setValue(&I, Result);
 }
 
 void SelectionDAGBuilder::visitBitExtract(const User &I) {
-  SDValue Src    = getValue(I.getOperand(0));
+  SDValue Src = getValue(I.getOperand(0));
   SDValue Offset = getValue(I.getOperand(1));
-  EVT SrcVT    = Src.getValueType();
+  EVT SrcVT = Src.getValueType();
   const TargetLowering &TLI = DAG.getTargetLoweringInfo();
   EVT ResultVT = TLI.getValueType(DAG.getDataLayout(), I.getType());
   SDLoc dl = getCurSDLoc();
@@ -4205,7 +4209,8 @@ void SelectionDAGBuilder::visitBitExtract(const User &I) {
   // RotateAmount = Offset + width(Result), computed in SrcVT
   unsigned ResultBitWidth = ResultVT.getScalarSizeInBits();
   SDValue ResultWidth = DAG.getConstant(ResultBitWidth, dl, SrcVT);
-  SDValue RotateAmount = DAG.getNode(ISD::ADD, dl, SrcVT, LegalOffset, ResultWidth);
+  SDValue RotateAmount =
+      DAG.getNode(ISD::ADD, dl, SrcVT, LegalOffset, ResultWidth);
 
   // Legalize rotate amount to the target's shift amount type
   EVT ShiftAmtTy = TLI.getShiftAmountTy(SrcVT, DAG.getDataLayout());
diff --git a/llvm/lib/CodeGen/TargetLoweringBase.cpp b/llvm/lib/CodeGen/TargetLoweringBase.cpp
index 701c2b58014bc..116f02b02fd2e 100644
--- a/llvm/lib/CodeGen/TargetLoweringBase.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringBase.cpp
@@ -2299,8 +2299,10 @@ int TargetLoweringBase::InstructionOpcodeToISD(unsigned Opcode) const {
   case InsertValue:    return ISD::MERGE_VALUES;
   case LandingPad:     return 0;
   case Freeze:         return ISD::FREEZE;
-  case BitInsert:      return 0;
-  case BitExtract:     return 0;
+  case BitInsert:
+    return 0;
+  case BitExtract:
+    return 0;
   }
 
   llvm_unreachable("Unknown instruction type encountered!");
diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp
index 67572f436330c..fbd76d018a8d0 100644
--- a/llvm/lib/IR/Core.cpp
+++ b/llvm/lib/IR/Core.cpp
@@ -4498,17 +4498,17 @@ LLVMValueRef LLVMBuildFreeze(LLVMBuilderRef B, LLVMValueRef Val,
 }
 
 LLVMValueRef LLVMBuildBitInsert(LLVMBuilderRef B, LLVMValueRef Base,
-                                    LLVMValueRef Val, LLVMValueRef Offset,
-                                    const char *Name) {
+                                LLVMValueRef Val, LLVMValueRef Offset,
+                                const char *Name) {
   return wrap(unwrap(B)->CreateBitInsert(unwrap(Base), unwrap(Val),
-                                             unwrap(Offset), Name));
+                                         unwrap(Offset), Name));
 }
 
 LLVMValueRef LLVMBuildBitExtract(LLVMBuilderRef B, LLVMTypeRef Ty,
-                                    LLVMValueRef Src, LLVMValueRef Offset,
-                                    const char *Name) {
+                                 LLVMValueRef Src, LLVMValueRef Offset,
+                                 const char *Name) {
   return wrap(unwrap(B)->CreateBitExtract(unwrap(Ty), unwrap(Src),
-                                             unwrap(Offset), Name));
+                                          unwrap(Offset), Name));
 }
 
 LLVMValueRef LLVMBuildIsNull(LLVMBuilderRef B, LLVMValueRef Val,
diff --git a/llvm/lib/IR/Instruction.cpp b/llvm/lib/IR/Instruction.cpp
index fc1e2885253f5..bb2ebad37b137 100644
--- a/llvm/lib/IR/Instruction.cpp
+++ b/llvm/lib/IR/Instruction.cpp
@@ -889,8 +889,10 @@ const char *Instruction::getOpcodeName(unsigned OpCode) {
   case LandingPad:     return "landingpad";
   case CleanupPad:     return "cleanuppad";
   case Freeze:         return "freeze";
-  case BitInsert:      return "bitinsert";
-  case BitExtract:     return "bitextract";
+  case BitInsert:
+    return "bitinsert";
+  case BitExtract:
+    return "bitextract";
 
   default: return "<Invalid operator> ";
   }

>From 9e7f6d3f7bdde4d84a79d8b088bed419a0c5cd50 Mon Sep 17 00:00:00 2001
From: Pedro Vicente <pedro.costa.vicente at tecnico.ulisboa.pt>
Date: Wed, 3 Jun 2026 21:13:59 +0100
Subject: [PATCH 6/9] remove useless file

---
 llvm/test/Analysis/IR2Vec/Inputs/reference_wtd3_vocab_print.txt | 2 --
 1 file changed, 2 deletions(-)
 delete mode 100644 llvm/test/Analysis/IR2Vec/Inputs/reference_wtd3_vocab_print.txt

diff --git a/llvm/test/Analysis/IR2Vec/Inputs/reference_wtd3_vocab_print.txt b/llvm/test/Analysis/IR2Vec/Inputs/reference_wtd3_vocab_print.txt
deleted file mode 100644
index c00453b3a9781..0000000000000
--- a/llvm/test/Analysis/IR2Vec/Inputs/reference_wtd3_vocab_print.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Command 'opt' not found, but can be installed with:
-sudo apt install llvm

>From 3584bec393f7ca7fc487def31bd27e5b69df5079 Mon Sep 17 00:00:00 2001
From: Pedro Vicente <pedro.costa.vicente at tecnico.ulisboa.pt>
Date: Wed, 10 Jun 2026 13:28:00 +0100
Subject: [PATCH 7/9] change bit 0 to be LSB

---
 llvm/docs/LangRef.rst                                  |  4 ++--
 llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp           |  6 +++---
 llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp  |  8 ++++----
 .../CodeGen/X86/GlobalISel/bitinsert-bitextract.ll     |  6 +++---
 llvm/test/CodeGen/X86/bitinsert-bitextract-x86.ll      | 10 +++++-----
 .../ExecutionEngine/bitinsert-bitextract-runtime.ll    |  6 +++---
 6 files changed, 20 insertions(+), 20 deletions(-)

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 7c1dec4663d4a..d05ca1f472b6a 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -11551,7 +11551,7 @@ The '``bitextract``' instruction returns a value of the specified type.
 The returned value is first extracted from the source, starting at the
 bit specified by the offset, and then bitcasted to the return type.
 If the range offset+ty.bitwidth exceeds the source width, it returns
-poison. Bit 0 is the most significant bit.
+poison. Bit 0 is the least significant bit.
 
 Example:
 """"""""
@@ -11590,7 +11590,7 @@ The returned value is of the same byte type as the first argument.
 It returns the first argument where the bits in the range
 [offset, offset + ty.bitlength - 1] have been replaced with val.
 If the range (offset + ty.bitwidth) is greater than the bitwidth of
-the first argument, it returns poison. Bit 0 is the most significant bit.
+the first argument, it returns poison. Bit 0 is the least significant bit.
 
 Example:
 """"""""
diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
index afec0d5916e5b..cc472f1b614b6 100644
--- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
@@ -3544,7 +3544,7 @@ bool IRTranslator::translateBitInsert(const User &U,
       MIRBuilder.buildAdd(BaseTy, LegalOffset, ValWidth).getReg(0);
 
   Register RotatedBase =
-      MIRBuilder.buildRotateLeft(BaseTy, Base, RotateAmount).getReg(0);
+      MIRBuilder.buildRotateRight(BaseTy, Base, RotateAmount).getReg(0);
 
   // Truncate or extend Val to BaseTy so only the inserted bit range remains.
   Register ExtVal = MIRBuilder.buildZExtOrTrunc(BaseTy, Val).getReg(0);
@@ -3559,7 +3559,7 @@ bool IRTranslator::translateBitInsert(const User &U,
   Register Inserted = MIRBuilder.buildOr(BaseTy, ClearedBase, ExtVal).getReg(0);
 
   // Restore bit positions
-  MIRBuilder.buildRotateRight(Res, Inserted, RotateAmount);
+  MIRBuilder.buildRotateLeft(Res, Inserted, RotateAmount);
   return true;
 }
 
@@ -3588,7 +3588,7 @@ bool IRTranslator::translateBitExtract(const User &U,
 
   // Rotate left by (Offset + ResultWidth)
   Register Rotated =
-      MIRBuilder.buildRotateLeft(SrcTy, Src, RotateAmount).getReg(0);
+      MIRBuilder.buildRotateRight(SrcTy, Src, RotateAmount).getReg(0);
 
   // Truncating to ResTy discards the high bits for free
   if (SrcTy == ResTy)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 32f7abe0fd852..50ad14a08f408 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -4172,7 +4172,7 @@ void SelectionDAGBuilder::visitBitInsert(const User &I) {
   SDValue LegalRotateAmount = DAG.getZExtOrTrunc(RotateAmount, dl, ShiftAmtTy);
 
   SDValue RotatedBase =
-      DAG.getNode(ISD::ROTL, dl, BaseVT, Base, LegalRotateAmount);
+      DAG.getNode(ISD::ROTR, dl, BaseVT, Base, LegalRotateAmount);
 
   unsigned BaseBitWidth = BaseVT.getScalarSizeInBits();
   APInt ClearMask =
@@ -4184,7 +4184,7 @@ void SelectionDAGBuilder::visitBitInsert(const User &I) {
   SDValue Inserted = DAG.getNode(ISD::OR, dl, BaseVT, ClearedBase, ExtVal);
 
   SDValue Result =
-      DAG.getNode(ISD::ROTR, dl, BaseVT, Inserted, LegalRotateAmount);
+      DAG.getNode(ISD::ROTL, dl, BaseVT, Inserted, LegalRotateAmount);
   setValue(&I, Result);
 }
 
@@ -4216,8 +4216,8 @@ void SelectionDAGBuilder::visitBitExtract(const User &I) {
   EVT ShiftAmtTy = TLI.getShiftAmountTy(SrcVT, DAG.getDataLayout());
   SDValue LegalRotateAmount = DAG.getZExtOrTrunc(RotateAmount, dl, ShiftAmtTy);
 
-  // Rotate left by (Offset + ResultWidth) — brings target field to bit 0
-  SDValue Rotated = DAG.getNode(ISD::ROTL, dl, SrcVT, Src, LegalRotateAmount);
+  // Rotate left by (Offset + ResultWidth) - brings target field to bit 0
+  SDValue Rotated = DAG.getNode(ISD::ROTR, dl, SrcVT, Src, LegalRotateAmount);
 
   // Truncating to ResultVT discards the high bits for free
   setValue(&I, DAG.getZExtOrTrunc(Rotated, dl, ResultVT));
diff --git a/llvm/test/CodeGen/X86/GlobalISel/bitinsert-bitextract.ll b/llvm/test/CodeGen/X86/GlobalISel/bitinsert-bitextract.ll
index 699852b890f45..6969b90995b24 100644
--- a/llvm/test/CodeGen/X86/GlobalISel/bitinsert-bitextract.ll
+++ b/llvm/test/CodeGen/X86/GlobalISel/bitinsert-bitextract.ll
@@ -5,7 +5,7 @@ define i16 @test_bitextract(b32 %src, i32 %off) {
 ; CHECK: [[SRC:%[0-9]+]]:_(s32) = COPY $edi
 ; CHECK: [[WIDTH:%[0-9]+]]:_(s32) = G_CONSTANT i32 16
 ; CHECK: [[ADD:%[0-9]+]]:_(s32) = G_ADD %{{[0-9]+}}, [[WIDTH]]
-; CHECK: [[ROTL:%[0-9]+]]:_(s32) = G_ROTL [[SRC]], [[ADD]](s32)
+; CHECK: [[ROTL:%[0-9]+]]:_(s32) = G_ROTR [[SRC]], [[ADD]](s32)
 ; CHECK: [[RES:%[0-9]+]]:_(s16) = G_TRUNC [[ROTL]](s32)
 ; CHECK: $ax = COPY [[RES]](s16)
 ; CHECK: RET 0, implicit $ax
@@ -19,12 +19,12 @@ define b32 @test_bitinsert(b32 %base, i16 %val, i32 %off) {
 ; CHECK: [[VAL:%[0-9]+]]:_(s16) = G_TRUNC %{{[0-9]+}}(s32)
 ; CHECK: [[WIDTH:%[0-9]+]]:_(s32) = G_CONSTANT i32 16
 ; CHECK: [[ADD:%[0-9]+]]:_(s32) = G_ADD %{{[0-9]+}}, [[WIDTH]]
-; CHECK: [[ROTL:%[0-9]+]]:_(s32) = G_ROTL [[BASE]], [[ADD]](s32)
+; CHECK: [[ROTL:%[0-9]+]]:_(s32) = G_ROTR [[BASE]], [[ADD]](s32)
 ; CHECK: [[EXT_VAL:%[0-9]+]]:_(s32) = G_ZEXT [[VAL]](s16)
 ; CHECK: [[MASK:%[0-9]+]]:_(s32) = G_CONSTANT i32 -65536
 ; CHECK: [[AND:%[0-9]+]]:_(s32) = G_AND [[ROTL]], [[MASK]]
 ; CHECK: [[OR:%[0-9]+]]:_(s32) = G_OR [[AND]], [[EXT_VAL]]
-; CHECK: [[ROTR:%[0-9]+]]:_(s32) = G_ROTR [[OR]], [[ADD]](s32)
+; CHECK: [[ROTR:%[0-9]+]]:_(s32) = G_ROTL [[OR]], [[ADD]](s32)
 ; CHECK: $eax = COPY [[ROTR]](s32)
 ; CHECK: RET 0, implicit $eax
   %result = bitinsert b32 %base, i16 %val, i32 %off
diff --git a/llvm/test/CodeGen/X86/bitinsert-bitextract-x86.ll b/llvm/test/CodeGen/X86/bitinsert-bitextract-x86.ll
index 412ebb70e6bd9..0a9b8ab1fdf45 100644
--- a/llvm/test/CodeGen/X86/bitinsert-bitextract-x86.ll
+++ b/llvm/test/CodeGen/X86/bitinsert-bitextract-x86.ll
@@ -4,7 +4,7 @@ define i16 @test_bitextract_var(b32 %src, i32 %off) {
 ; CHECK-LABEL: test_bitextract_var:
 ; CHECK:       movl %edi, %eax
 ; CHECK:       leal 16(%rsi), %ecx
-; CHECK:       roll %cl, %eax
+; CHECK:       rorl %cl, %eax
 ; CHECK:       retq
   %result = bitextract i16, b32 %src, i32 %off
   ret i16 %result
@@ -13,7 +13,7 @@ define i16 @test_bitextract_var(b32 %src, i32 %off) {
 define i16 @test_bitextract_const(b32 %src) {
 ; CHECK-LABEL: test_bitextract_const:
 ; CHECK:       movl %edi, %eax
-; CHECK:       shrl $8, %eax
+; CHECK:       rorl $24, %eax
 ; CHECK:       retq
   %result = bitextract i16, b32 %src, i32 8
   ret i16 %result
@@ -22,7 +22,7 @@ define i16 @test_bitextract_const(b32 %src) {
 define i8 @test_bitextract_narrow(b64 %src) {
 ; CHECK-LABEL: test_bitextract_narrow:
 ; CHECK:       movq %rdi, %rax
-; CHECK:       shrq $56, %rax
+; CHECK:       shrl $8, %eax
 ; CHECK:       retq
   %result = bitextract i8, b64 %src, i32 0
   ret i8 %result
@@ -31,11 +31,11 @@ define i8 @test_bitextract_narrow(b64 %src) {
 define b32 @test_bitinsert_var(b32 %base, i16 %val, i32 %off) {
 ; CHECK-LABEL: test_bitinsert_var:
 ; CHECK:       leal 16(%rdx), %ecx
-; CHECK:       roll %cl, %edi
+; CHECK:       rorl %cl, %edi
 ; CHECK:       andl $-65536, %edi
 ; CHECK:       movzwl %si, %eax
 ; CHECK:       orl %edi, %eax
-; CHECK:       rorl %cl, %eax
+; CHECK:       roll %cl, %eax
 ; CHECK:       retq
   %result = bitinsert b32 %base, i16 %val, i32 %off
   ret b32 %result
diff --git a/llvm/test/ExecutionEngine/bitinsert-bitextract-runtime.ll b/llvm/test/ExecutionEngine/bitinsert-bitextract-runtime.ll
index 4853669cd21dc..20662f7cfc1de 100644
--- a/llvm/test/ExecutionEngine/bitinsert-bitextract-runtime.ll
+++ b/llvm/test/ExecutionEngine/bitinsert-bitextract-runtime.ll
@@ -1,5 +1,5 @@
 ; RUN: %lli %s | FileCheck %s
-; CHECK: extract=0x3456 insert=0x12beef78
+; CHECK: extract=0x7812 insert=0xef3456be
 
 @.str = private unnamed_addr constant [30 x i8] c"extract=0x%04x insert=0x%08x\0A\00", align 1
 
@@ -19,10 +19,10 @@ define i32 @main() {
   ; Test values: 305419896 is 0x12345678, 48879 is 0xBEEF
   %extract = call i16 @test_bitextract_var(b32 305419896, i32 8)
   %insert = call b32 @test_bitinsert_var(b32 305419896, i16 48879, i32 8)
-  
+
   %extract32 = zext i16 %extract to i32
   %insert32 = bitcast b32 %insert to i32
-  
+
   %fmt = getelementptr inbounds [30 x i8], ptr @.str, i64 0, i64 0
   %call = call i32 (ptr, ...) @printf(ptr %fmt, i32 %extract32, i32 %insert32)
   ret i32 0

>From 066f6d0bf3a63e4c8cec0b367b77f0fc4e899cb1 Mon Sep 17 00:00:00 2001
From: Pedro Vicente <pedro.costa.vicente at tecnico.ulisboa.pt>
Date: Wed, 10 Jun 2026 13:56:58 +0100
Subject: [PATCH 8/9] Update verifier in order to known the size of pointers

---
 llvm/lib/IR/Verifier.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 122de2cd22fdf..204ed64301e97 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -4515,8 +4515,8 @@ void Verifier::visitBitExtractInst(BitExtractInst &IE) {
   Check(BitExtractInst::isValidOperands(IE.getType(), IE.getOperand(0),
                                         IE.getOperand(1)),
         "Invalid bitextract operands!", &IE);
-  Check(IE.getType()->getPrimitiveSizeInBits() <=
-            IE.getOperand(0)->getType()->getPrimitiveSizeInBits(),
+   Check(DL.getTypeSizeInBits(IE.getType()) <=
+            DL.getTypeSizeInBits(IE.getOperand(0)->getType()),
         "bitextract result type cannot be wider than source type!", &IE);
   visitInstruction(IE);
 }

>From eef74892c21e7d7da8466a796636de9f207cde54 Mon Sep 17 00:00:00 2001
From: Pedro Vicente <pedro.costa.vicente at tecnico.ulisboa.pt>
Date: Wed, 10 Jun 2026 14:05:11 +0100
Subject: [PATCH 9/9] remove line at IR2VecTest.cpp

---
 llvm/unittests/Analysis/IR2VecTest.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/llvm/unittests/Analysis/IR2VecTest.cpp b/llvm/unittests/Analysis/IR2VecTest.cpp
index db2708ecb5bcd..2de8eaa692da6 100644
--- a/llvm/unittests/Analysis/IR2VecTest.cpp
+++ b/llvm/unittests/Analysis/IR2VecTest.cpp
@@ -365,7 +365,6 @@ TEST_F(IR2VecTestFixture, GetInstVec_Symbolic) {
 
   EXPECT_TRUE(AddEmb.approximatelyEquals(Embedding(2, 26.7)));
   EXPECT_TRUE(RetEmb.approximatelyEquals(Embedding(2, 16.2)));
-
 }
 
 TEST_F(IR2VecTestFixture, GetInstVec_FlowAware) {



More information about the llvm-commits mailing list