https://github.com/Andres-Salamanca updated 
https://github.com/llvm/llvm-project/pull/145971

>From d2e19a9ce2270ae9d764f1e2ba3978aaab2c1e2a Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbari...@gmail.com>
Date: Thu, 26 Jun 2025 15:51:02 -0500
Subject: [PATCH 1/4] Get Lvalue for bit-field

---
 clang/include/clang/CIR/MissingFeatures.h |  1 +
 clang/lib/CIR/CodeGen/CIRGenExpr.cpp      | 47 +++++++++++++++++++++--
 clang/lib/CIR/CodeGen/CIRGenFunction.h    |  4 ++
 clang/lib/CIR/CodeGen/CIRGenValue.h       | 19 +++++++++
 clang/test/CIR/CodeGen/bitfields.c        |  8 ++++
 5 files changed, 75 insertions(+), 4 deletions(-)

diff --git a/clang/include/clang/CIR/MissingFeatures.h 
b/clang/include/clang/CIR/MissingFeatures.h
index 9e8944d1114b8..e136d73daac89 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -200,6 +200,7 @@ struct MissingFeatures {
   static bool fastMathFlags() { return false; }
   static bool fpConstraints() { return false; }
   static bool generateDebugInfo() { return false; }
+  static bool getBitfieldOp() { return false; }
   static bool hip() { return false; }
   static bool implicitConstructorArgs() { return false; }
   static bool incrementProfileCounter() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index 5c6604d784156..a3d24e92c701a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -326,13 +326,47 @@ mlir::Value 
CIRGenFunction::emitStoreThroughBitfieldLValue(RValue src,
   return {};
 }
 
+Address CIRGenFunction::getAddrOfBitFieldStorage(LValue base,
+                                                 const FieldDecl *field,
+                                                 mlir::Type fieldType,
+                                                 unsigned index) {
+  if (index == 0)
+    return base.getAddress();
+  mlir::Location loc = getLoc(field->getLocation());
+  cir::PointerType fieldPtr = cir::PointerType::get(fieldType);
+  cir::GetMemberOp sea = getBuilder().createGetMember(
+      loc, fieldPtr, base.getPointer(), field->getName(), index);
+  return Address(sea, CharUnits::One());
+}
+
+LValue CIRGenFunction::emitLValueForBitField(LValue base,
+                                             const FieldDecl *field) {
+  LValueBaseInfo baseInfo = base.getBaseInfo();
+  const CIRGenRecordLayout &layout =
+      cgm.getTypes().getCIRGenRecordLayout(field->getParent());
+  const CIRGenBitFieldInfo &info = layout.getBitFieldInfo(field);
+  assert(!cir::MissingFeatures::armComputeVolatileBitfields());
+  unsigned idx = layout.getCIRFieldNo(field);
+
+  Address addr = getAddrOfBitFieldStorage(base, field, info.storageType, idx);
+
+  mlir::Location loc = getLoc(field->getLocation());
+  if (addr.getElementType() != info.storageType)
+    addr = builder.createElementBitCast(loc, addr, info.storageType);
+
+  QualType fieldType =
+      field->getType().withCVRQualifiers(base.getVRQualifiers());
+  // TODO(cir): Support TBAA for bit fields.
+  assert(!cir::MissingFeatures::opTBAA());
+  LValueBaseInfo fieldBaseInfo(baseInfo.getAlignmentSource());
+  return LValue::makeBitfield(addr, info, fieldType, fieldBaseInfo);
+}
+
 LValue CIRGenFunction::emitLValueForField(LValue base, const FieldDecl *field) 
{
   LValueBaseInfo baseInfo = base.getBaseInfo();
 
-  if (field->isBitField()) {
-    cgm.errorNYI(field->getSourceRange(), "emitLValueForField: bitfield");
-    return LValue();
-  }
+  if (field->isBitField())
+    return emitLValueForBitField(base, field);
 
   QualType fieldType = field->getType();
   const RecordDecl *rec = field->getParent();
@@ -460,6 +494,11 @@ RValue CIRGenFunction::emitLoadOfLValue(LValue lv, 
SourceLocation loc) {
   assert(!lv.getType()->isFunctionType());
   assert(!(lv.getType()->isConstantMatrixType()) && "not implemented");
 
+  if (lv.isBitField()) {
+    assert(!cir::MissingFeatures::getBitfieldOp());
+    return RValue::getIgnored();
+  }
+
   if (lv.isSimple())
     return RValue::get(emitLoadOfScalar(lv, loc));
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 2e54243f18cff..5139bc8249b3d 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -550,6 +550,9 @@ class CIRGenFunction : public CIRGenTypeCache {
     return it->second;
   }
 
+  Address getAddrOfBitFieldStorage(LValue base, const clang::FieldDecl *field,
+                                   mlir::Type fieldType, unsigned index);
+
   /// Load the value for 'this'. This function is only valid while generating
   /// code for an C++ member function.
   /// FIXME(cir): this should return a mlir::Value!
@@ -964,6 +967,7 @@ class CIRGenFunction : public CIRGenTypeCache {
   /// of the expression.
   /// FIXME: document this function better.
   LValue emitLValue(const clang::Expr *e);
+  LValue emitLValueForBitField(LValue base, const FieldDecl *field);
   LValue emitLValueForField(LValue base, const clang::FieldDecl *field);
 
   /// Like emitLValueForField, excpet that if the Field is a reference, this
diff --git a/clang/lib/CIR/CodeGen/CIRGenValue.h 
b/clang/lib/CIR/CodeGen/CIRGenValue.h
index a5a457ddafa9c..2d6bdb921c9fa 100644
--- a/clang/lib/CIR/CodeGen/CIRGenValue.h
+++ b/clang/lib/CIR/CodeGen/CIRGenValue.h
@@ -19,6 +19,7 @@
 #include "clang/AST/CharUnits.h"
 #include "clang/AST/Type.h"
 
+#include "CIRGenRecordLayout.h"
 #include "mlir/IR/Value.h"
 
 #include "clang/CIR/MissingFeatures.h"
@@ -162,6 +163,7 @@ class LValue {
   mlir::Value vectorIdx; // Index for vector subscript
   mlir::Type elementType;
   LValueBaseInfo baseInfo;
+  const CIRGenBitFieldInfo *bitFieldInfo{nullptr};
 
   void initialize(clang::QualType type, clang::Qualifiers quals,
                   clang::CharUnits alignment, LValueBaseInfo baseInfo) {
@@ -245,6 +247,23 @@ class LValue {
     r.initialize(t, t.getQualifiers(), vecAddress.getAlignment(), baseInfo);
     return r;
   }
+
+  /// Create a new object to represent a bit-field access.
+  ///
+  /// \param Addr - The base address of the bit-field sequence this
+  /// bit-field refers to.
+  /// \param Info - The information describing how to perform the bit-field
+  /// access.
+  static LValue makeBitfield(Address addr, const CIRGenBitFieldInfo &info,
+                             clang::QualType type, LValueBaseInfo baseInfo) {
+    LValue r;
+    r.lvType = BitField;
+    r.v = addr.getPointer();
+    r.elementType = addr.getElementType();
+    r.bitFieldInfo = &info;
+    r.initialize(type, type.getQualifiers(), addr.getAlignment(), baseInfo);
+    return r;
+  }
 };
 
 /// An aggregate value slot.
diff --git a/clang/test/CIR/CodeGen/bitfields.c 
b/clang/test/CIR/CodeGen/bitfields.c
index ff5c6bc1787b4..4cc1fc69ecc5a 100644
--- a/clang/test/CIR/CodeGen/bitfields.c
+++ b/clang/test/CIR/CodeGen/bitfields.c
@@ -76,3 +76,11 @@ void def() {
   T t;
   U u;
 }
+
+// CIR: cir.func {{.*@load_field}}
+// CIR:   [[TMP0:%.*]] = cir.alloca !cir.ptr<!rec_S>, 
!cir.ptr<!cir.ptr<!rec_S>>, ["s", init]
+// CIR:   [[TMP1:%.*]] = cir.load{{.*}} [[TMP0]] : !cir.ptr<!cir.ptr<!rec_S>>, 
!cir.ptr<!rec_S>
+// CIR:   [[TMP2:%.*]] = cir.get_member %2[1] {name = "e"} : !cir.ptr<!rec_S> 
-> !cir.ptr<!u16i>
+int load_field(S* s) {
+  return s->e;
+}

>From a94f579b36df696dded896137c60a1394cf3f6d3 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbari...@gmail.com>
Date: Fri, 27 Jun 2025 16:08:49 -0500
Subject: [PATCH 2/4] [CIR] Upstream get_bitfield operation to load bit-field
 members from structs

---
 .../include/clang/CIR/Dialect/IR/CIRAttrs.td  | 38 +++++++++
 clang/include/clang/CIR/Dialect/IR/CIROps.td  | 79 +++++++++++++++++++
 clang/include/clang/CIR/LoweringHelpers.h     | 14 ++++
 clang/lib/CIR/CodeGen/CIRGenBuilder.h         | 11 +++
 clang/lib/CIR/CodeGen/CIRGenExpr.cpp          | 24 ++++--
 clang/lib/CIR/CodeGen/CIRGenFunction.h        |  2 +
 clang/lib/CIR/CodeGen/CIRGenValue.h           | 15 ++++
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp       |  4 +
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 51 +++++++++++-
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.h   | 10 +++
 clang/lib/CIR/Lowering/LoweringHelpers.cpp    | 38 +++++++++
 clang/test/CIR/CodeGen/bitfields.c            | 29 ++++++-
 clang/test/CIR/CodeGen/bitfields.cpp          | 28 +++++++
 clang/test/CIR/CodeGen/bitfields_be.c         | 29 ++++++-
 14 files changed, 360 insertions(+), 12 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td 
b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 03e970db2847d..683a9194da3b1 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -375,4 +375,42 @@ def CIR_VisibilityAttr : CIR_EnumAttr<CIR_VisibilityKind, 
"visibility"> {
   }];
 }
 
+//===----------------------------------------------------------------------===//
+// BitfieldInfoAttr
+//===----------------------------------------------------------------------===//
+
+def BitfieldInfoAttr : CIR_Attr<"BitfieldInfo", "bitfield_info"> {
+  let summary = "Represents a bit field info";
+  let description = [{
+    Holds the next information about bitfields: name, storage type, a bitfield
+    size and position in the storage, if the bitfield is signed or not.
+  }];
+  let parameters = (ins "mlir::StringAttr":$name,
+                        "mlir::Type":$storageType,
+                        "uint64_t":$size,
+                        "uint64_t":$offset,
+                        "bool":$isSigned);
+
+  let assemblyFormat = [{`<` struct($name,
+                                    $storageType,
+                                    $size,
+                                    $offset,
+                                    $isSigned)
+                         `>`
+                        }];
+
+  let builders = [
+    AttrBuilder<(ins "llvm::StringRef":$name,
+                     "mlir::Type":$storageType,
+                     "uint64_t":$size,
+                     "uint64_t":$offset,
+                     "bool":$isSigned
+                     ), [{
+      return $_get($_ctxt, mlir::StringAttr::get($_ctxt, name), storageType,
+                   size, offset, isSigned);
+    }]>
+  ];
+}
+
+
 #endif // LLVM_CLANG_CIR_DIALECT_IR_CIRATTRS_TD
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index ef77c46b011f7..d81add1a5264c 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -1669,6 +1669,85 @@ def GetGlobalOp : CIR_Op<"get_global",
   }];
 }
 
+//===----------------------------------------------------------------------===//
+// GetBitfieldOp
+//===----------------------------------------------------------------------===//
+
+def GetBitfieldOp : CIR_Op<"get_bitfield"> {
+  let summary = "Get a bitfield";
+  let description = [{
+    The `cir.get_bitfield` operation provides a load-like access to
+    a bit field of a record.
+
+    It expects a name if a bit field, a pointer to a storage in the
+    base record, a type of the storage, a name of the bitfield,
+    a size the bit field, an offset of the bit field and a sign.
+
+    A unit attribute `volatile` can be used to indicate a volatile load of the
+    bitfield.
+
+    Example:
+    Suppose we have a struct with multiple bitfields stored in
+    different storages. The `cir.get_bitfield` operation gets the value
+    of the bitfield
+    ```C++
+    typedef struct {
+      int a : 4;
+      int b : 27;
+      int c : 17;
+      int d : 2;
+      int e : 15;
+    } S;
+
+    int load_bitfield(S& s) {
+      return s.e;
+    }
+    ```
+
+    ```mlir
+    // 'e' is in the storage with the index 1
+    !cir.record<struct "S" packed padded {!u64i, !u16i, !cir.array<!u8i x 2>}>
+    #bfi_e = #cir.bitfield_info<name = "e", storage_type = !u16i, size = 15,
+                                offset = 0, is_signed = true>
+
+    %2 = cir.load %0 : !cir.ptr<!cir.ptr<!record_type>>, !cir.ptr<!record_type>
+    %3 = cir.get_member %2[1] {name = "e"} : !cir.ptr<!record_type>
+                                                             -> !cir.ptr<!u16i>
+    %4 = cir.get_bitfield(#bfi_e, %3 : !cir.ptr<!u16i>) -> !s32i
+    ```
+    }];
+
+  let arguments = (ins
+    Arg<CIR_PointerType, "the address to load from", [MemRead]>:$addr,
+    BitfieldInfoAttr:$bitfield_info,
+    UnitAttr:$is_volatile
+    );
+
+  let results = (outs CIR_IntType:$result);
+
+  let assemblyFormat = [{ `(`$bitfield_info `,` $addr attr-dict `:`
+   qualified(type($addr)) `)` `->` type($result) }];
+
+  let builders = [
+    OpBuilder<(ins "mlir::Type":$type,
+                   "mlir::Value":$addr,
+                   "mlir::Type":$storage_type,
+                   "llvm::StringRef":$name,
+                   "unsigned":$size,
+                   "unsigned":$offset,
+                   "bool":$is_signed,
+                   "bool":$is_volatile
+                   ),
+   [{
+      BitfieldInfoAttr info =
+        BitfieldInfoAttr::get($_builder.getContext(),
+                              name, storage_type,
+                              size, offset, is_signed);
+      build($_builder, $_state, type, addr, info, is_volatile);
+    }]>
+  ];
+}
+
 
//===----------------------------------------------------------------------===//
 // GetMemberOp
 
//===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/LoweringHelpers.h 
b/clang/include/clang/CIR/LoweringHelpers.h
index 3077010ee5ffe..66e99c7e84416 100644
--- a/clang/include/clang/CIR/LoweringHelpers.h
+++ b/clang/include/clang/CIR/LoweringHelpers.h
@@ -37,4 +37,18 @@ std::optional<mlir::Attribute>
 lowerConstArrayAttr(cir::ConstArrayAttr constArr,
                     const mlir::TypeConverter *converter);
 
+mlir::Value getConstAPInt(mlir::OpBuilder &bld, mlir::Location loc,
+                          mlir::Type typ, const llvm::APInt &val);
+
+mlir::Value getConst(mlir::OpBuilder &bld, mlir::Location loc, mlir::Type typ,
+                     unsigned val);
+
+mlir::Value createShL(mlir::OpBuilder &bld, mlir::Value lhs, unsigned rhs);
+
+mlir::Value createAShR(mlir::OpBuilder &bld, mlir::Value lhs, unsigned rhs);
+
+mlir::Value createAnd(mlir::OpBuilder &bld, mlir::Value lhs,
+                      const llvm::APInt &rhs);
+
+mlir::Value createLShR(mlir::OpBuilder &bld, mlir::Value lhs, unsigned rhs);
 #endif
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h 
b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index ac62ea7c6aa16..7258aad9b70d8 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -10,6 +10,7 @@
 #define LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENBUILDER_H
 
 #include "Address.h"
+#include "CIRGenRecordLayout.h"
 #include "CIRGenTypeCache.h"
 #include "clang/CIR/Interfaces/CIRFPTypeInterface.h"
 #include "clang/CIR/MissingFeatures.h"
@@ -405,6 +406,16 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
 
     return createGlobal(module, loc, uniqueName, type, linkage);
   }
+
+  mlir::Value createGetBitfield(mlir::Location loc, mlir::Type resultType,
+                                mlir::Value addr, mlir::Type storageType,
+                                const CIRGenBitFieldInfo &info,
+                                bool isLvalueVolatile, bool useVolatile) {
+    auto offset = useVolatile ? info.volatileOffset : info.offset;
+    return create<cir::GetBitfieldOp>(loc, resultType, addr, storageType,
+                                      info.name, info.size, offset,
+                                      info.isSigned, isLvalueVolatile);
+  }
 };
 
 } // namespace clang::CIRGen
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index a3d24e92c701a..cd20eec934d03 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -326,12 +326,26 @@ mlir::Value 
CIRGenFunction::emitStoreThroughBitfieldLValue(RValue src,
   return {};
 }
 
+RValue CIRGenFunction::emitLoadOfBitfieldLValue(LValue lv, SourceLocation loc) 
{
+  const CIRGenBitFieldInfo &info = lv.getBitFieldInfo();
+
+  // Get the output type.
+  mlir::Type resLTy = convertType(lv.getType());
+  Address ptr = lv.getBitFieldAddress();
+
+  assert(!cir::MissingFeatures::armComputeVolatileBitfields());
+
+  auto field = builder.createGetBitfield(getLoc(loc), resLTy, ptr.getPointer(),
+                                         ptr.getElementType(), info,
+                                         lv.isVolatile(), false);
+  assert(!cir::MissingFeatures::opLoadEmitScalarRangeCheck() && "NYI");
+  return RValue::get(field);
+}
+
 Address CIRGenFunction::getAddrOfBitFieldStorage(LValue base,
                                                  const FieldDecl *field,
                                                  mlir::Type fieldType,
                                                  unsigned index) {
-  if (index == 0)
-    return base.getAddress();
   mlir::Location loc = getLoc(field->getLocation());
   cir::PointerType fieldPtr = cir::PointerType::get(fieldType);
   cir::GetMemberOp sea = getBuilder().createGetMember(
@@ -494,10 +508,8 @@ RValue CIRGenFunction::emitLoadOfLValue(LValue lv, 
SourceLocation loc) {
   assert(!lv.getType()->isFunctionType());
   assert(!(lv.getType()->isConstantMatrixType()) && "not implemented");
 
-  if (lv.isBitField()) {
-    assert(!cir::MissingFeatures::getBitfieldOp());
-    return RValue::getIgnored();
-  }
+  if (lv.isBitField())
+    return emitLoadOfBitfieldLValue(lv, loc);
 
   if (lv.isSimple())
     return RValue::get(emitLoadOfScalar(lv, loc));
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 5139bc8249b3d..8e4bb900bdd2a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -947,6 +947,8 @@ class CIRGenFunction : public CIRGenTypeCache {
   /// ignoring the result.
   void emitIgnoredExpr(const clang::Expr *e);
 
+  RValue emitLoadOfBitfieldLValue(LValue lv, SourceLocation loc);
+
   /// Given an expression that represents a value lvalue, this method emits
   /// the address of the lvalue, then loads the result as an rvalue,
   /// returning the rvalue.
diff --git a/clang/lib/CIR/CodeGen/CIRGenValue.h 
b/clang/lib/CIR/CodeGen/CIRGenValue.h
index 2d6bdb921c9fa..e1b0f805a7b21 100644
--- a/clang/lib/CIR/CodeGen/CIRGenValue.h
+++ b/clang/lib/CIR/CodeGen/CIRGenValue.h
@@ -248,6 +248,21 @@ class LValue {
     return r;
   }
 
+  // bitfield lvalue
+  Address getBitFieldAddress() const {
+    return Address(getBitFieldPointer(), elementType, getAlignment());
+  }
+
+  mlir::Value getBitFieldPointer() const {
+    assert(isBitField());
+    return v;
+  }
+
+  const CIRGenBitFieldInfo &getBitFieldInfo() const {
+    assert(isBitField());
+    return *bitFieldInfo;
+  }
+
   /// Create a new object to represent a bit-field access.
   ///
   /// \param Addr - The base address of the bit-field sequence this
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp 
b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 17157561357f9..eec66f4633ec3 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -65,6 +65,10 @@ struct CIROpAsmDialectInterface : public 
OpAsmDialectInterface {
       os << (boolAttr.getValue() ? "true" : "false");
       return AliasResult::FinalAlias;
     }
+    if (auto bitfield = mlir::dyn_cast<cir::BitfieldInfoAttr>(attr)) {
+      os << "bfi_" << bitfield.getName().str();
+      return AliasResult::FinalAlias;
+    }
     return AliasResult::NoAlias;
   }
 };
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 1c13c88902d9a..c867518199b03 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -1922,7 +1922,8 @@ void ConvertCIRToLLVMPass::runOnOperation() {
                CIRToLLVMVecTernaryOpLowering,
                CIRToLLVMComplexCreateOpLowering,
                CIRToLLVMComplexRealOpLowering,
-               CIRToLLVMComplexImagOpLowering
+               CIRToLLVMComplexImagOpLowering,
+               CIRToLLVMGetBitfieldOpLowering
       // clang-format on
       >(converter, patterns.getContext());
 
@@ -2244,6 +2245,54 @@ mlir::LogicalResult 
CIRToLLVMComplexImagOpLowering::matchAndRewrite(
   return mlir::success();
 }
 
+mlir::LogicalResult CIRToLLVMGetBitfieldOpLowering::matchAndRewrite(
+    cir::GetBitfieldOp op, OpAdaptor adaptor,
+    mlir::ConversionPatternRewriter &rewriter) const {
+
+  mlir::OpBuilder::InsertionGuard guard(rewriter);
+  rewriter.setInsertionPoint(op);
+
+  cir::BitfieldInfoAttr info = op.getBitfieldInfo();
+  uint64_t size = info.getSize();
+  uint64_t offset = info.getOffset();
+  mlir::Type storageType = info.getStorageType();
+  mlir::MLIRContext *context = storageType.getContext();
+  unsigned storageSize = 0;
+
+  if (auto arTy = mlir::dyn_cast<cir::ArrayType>(storageType))
+    storageSize = arTy.getSize() * 8;
+  else if (auto intTy = mlir::dyn_cast<cir::IntType>(storageType))
+    storageSize = intTy.getWidth();
+  else
+    llvm_unreachable(
+        "Either ArrayType or IntType expected for bitfields storage");
+
+  mlir::IntegerType intType = mlir::IntegerType::get(context, storageSize);
+
+  mlir::Value val = rewriter.create<mlir::LLVM::LoadOp>(
+      op.getLoc(), intType, adaptor.getAddr(), 0, op.getIsVolatile());
+  val = rewriter.create<mlir::LLVM::BitcastOp>(op.getLoc(), intType, val);
+
+  if (info.getIsSigned()) {
+    assert(static_cast<unsigned>(offset + size) <= storageSize);
+    unsigned highBits = storageSize - offset - size;
+    val = createShL(rewriter, val, highBits);
+    val = createAShR(rewriter, val, offset + highBits);
+  } else {
+    val = createLShR(rewriter, val, offset);
+
+    if (static_cast<unsigned>(offset) + size < storageSize)
+      val = createAnd(rewriter, val,
+                      llvm::APInt::getLowBitsSet(storageSize, size));
+  }
+
+  mlir::Type resTy = getTypeConverter()->convertType(op.getType());
+  auto newOp = createIntCast(
+      rewriter, val, mlir::cast<mlir::IntegerType>(resTy), info.getIsSigned());
+  rewriter.replaceOp(op, newOp);
+  return mlir::success();
+}
+
 std::unique_ptr<mlir::Pass> createConvertCIRToLLVMPass() {
   return std::make_unique<ConvertCIRToLLVMPass>();
 }
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
index 8502cb1ae5d9f..1c3622172f836 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
@@ -463,6 +463,16 @@ class CIRToLLVMComplexImagOpLowering
                   mlir::ConversionPatternRewriter &) const override;
 };
 
+class CIRToLLVMGetBitfieldOpLowering
+    : public mlir::OpConversionPattern<cir::GetBitfieldOp> {
+public:
+  using mlir::OpConversionPattern<cir::GetBitfieldOp>::OpConversionPattern;
+
+  mlir::LogicalResult
+  matchAndRewrite(cir::GetBitfieldOp op, OpAdaptor,
+                  mlir::ConversionPatternRewriter &) const override;
+};
+
 } // namespace direct
 } // namespace cir
 
diff --git a/clang/lib/CIR/Lowering/LoweringHelpers.cpp 
b/clang/lib/CIR/Lowering/LoweringHelpers.cpp
index b4ae9f1909f41..b288ef91af776 100644
--- a/clang/lib/CIR/Lowering/LoweringHelpers.cpp
+++ b/clang/lib/CIR/Lowering/LoweringHelpers.cpp
@@ -11,6 +11,7 @@
 
//===----------------------------------------------------------------------===//
 
 #include "clang/CIR/LoweringHelpers.h"
+#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
 #include "clang/CIR/MissingFeatures.h"
 
 mlir::DenseElementsAttr
@@ -144,3 +145,40 @@ lowerConstArrayAttr(cir::ConstArrayAttr constArr,
 
   return std::nullopt;
 }
+
+mlir::Value getConstAPInt(mlir::OpBuilder &bld, mlir::Location loc,
+                          mlir::Type typ, const llvm::APInt &val) {
+  return bld.create<mlir::LLVM::ConstantOp>(loc, typ, val);
+}
+
+mlir::Value getConst(mlir::OpBuilder &bld, mlir::Location loc, mlir::Type typ,
+                     unsigned val) {
+  return bld.create<mlir::LLVM::ConstantOp>(loc, typ, val);
+}
+
+mlir::Value createShL(mlir::OpBuilder &bld, mlir::Value lhs, unsigned rhs) {
+  if (!rhs)
+    return lhs;
+  auto rhsVal = getConst(bld, lhs.getLoc(), lhs.getType(), rhs);
+  return bld.create<mlir::LLVM::ShlOp>(lhs.getLoc(), lhs, rhsVal);
+}
+
+mlir::Value createAShR(mlir::OpBuilder &bld, mlir::Value lhs, unsigned rhs) {
+  if (!rhs)
+    return lhs;
+  auto rhsVal = getConst(bld, lhs.getLoc(), lhs.getType(), rhs);
+  return bld.create<mlir::LLVM::AShrOp>(lhs.getLoc(), lhs, rhsVal);
+}
+
+mlir::Value createAnd(mlir::OpBuilder &bld, mlir::Value lhs,
+                      const llvm::APInt &rhs) {
+  auto rhsVal = getConstAPInt(bld, lhs.getLoc(), lhs.getType(), rhs);
+  return bld.create<mlir::LLVM::AndOp>(lhs.getLoc(), lhs, rhsVal);
+}
+
+mlir::Value createLShR(mlir::OpBuilder &bld, mlir::Value lhs, unsigned rhs) {
+  if (!rhs)
+    return lhs;
+  auto rhsVal = getConst(bld, lhs.getLoc(), lhs.getType(), rhs);
+  return bld.create<mlir::LLVM::LShrOp>(lhs.getLoc(), lhs, rhsVal);
+}
diff --git a/clang/test/CIR/CodeGen/bitfields.c 
b/clang/test/CIR/CodeGen/bitfields.c
index 4cc1fc69ecc5a..28ce09e2e2c89 100644
--- a/clang/test/CIR/CodeGen/bitfields.c
+++ b/clang/test/CIR/CodeGen/bitfields.c
@@ -34,6 +34,7 @@ typedef struct {
   int e : 15;
   unsigned f; // type other than int above, not a bitfield
 } S;
+// CIR-DAG:  #bfi_c = #cir.bitfield_info<name = "c", storageType = !u64i, size 
= 17, offset = 32, isSigned = true>
 // CIR-DAG:  !rec_S = !cir.record<struct "S" {!u64i, !u16i, !u32i}>
 // LLVM-DAG: %struct.S = type { i64, i16, i32 }
 // OGCG-DAG: %struct.S = type { i64, i16, i32 }
@@ -77,10 +78,30 @@ void def() {
   U u;
 }
 
+int load_field(S* s) {
+  return s->c;
+}
+
 // CIR: cir.func {{.*@load_field}}
 // CIR:   [[TMP0:%.*]] = cir.alloca !cir.ptr<!rec_S>, 
!cir.ptr<!cir.ptr<!rec_S>>, ["s", init]
 // CIR:   [[TMP1:%.*]] = cir.load{{.*}} [[TMP0]] : !cir.ptr<!cir.ptr<!rec_S>>, 
!cir.ptr<!rec_S>
-// CIR:   [[TMP2:%.*]] = cir.get_member %2[1] {name = "e"} : !cir.ptr<!rec_S> 
-> !cir.ptr<!u16i>
-int load_field(S* s) {
-  return s->e;
-}
+// CIR:   [[TMP2:%.*]] = cir.get_member [[TMP1]][0] {name = "c"} : 
!cir.ptr<!rec_S> -> !cir.ptr<!u64i>
+// CIR:   [[TMP3:%.*]] = cir.get_bitfield(#bfi_c, [[TMP2]] : !cir.ptr<!u64i>) 
-> !s32i
+
+// LLVM: define dso_local i32 @load_field
+// LLVM:   [[TMP0:%.*]] = alloca ptr, i64 1, align 8
+// LLVM:   [[TMP1:%.*]] = alloca i32, i64 1, align 4
+// LLVM:   [[TMP2:%.*]] = load ptr, ptr [[TMP0]], align 8
+// LLVM:   [[TMP3:%.*]] = getelementptr %struct.S, ptr [[TMP2]], i32 0, i32 0
+// LLVM:   [[TMP4:%.*]] = load i64, ptr [[TMP3]], align 8
+// LLVM:   [[TMP5:%.*]] = shl i64 [[TMP4]], 15
+// LLVM:   [[TMP6:%.*]] = ashr i64 [[TMP5]], 47
+// LLVM:   [[TMP7:%.*]] = trunc i64 [[TMP6]] to i32
+
+// OGCG: define dso_local i32 @load_field
+// OGCG:  [[TMP0:%.*]] = alloca ptr, align 8
+// OGCG:  [[TMP1:%.*]] = load ptr, ptr [[TMP0]], align 8
+// OGCG:  [[TMP2:%.*]] = load i64, ptr [[TMP1]], align 4
+// OGCG:  [[TMP3:%.*]] = shl i64 [[TMP2]], 15
+// OGCG:  [[TMP4:%.*]] = ashr i64 [[TMP3]], 47
+// OGCG:  [[TMP5:%.*]] = trunc i64 [[TMP4]] to i32
diff --git a/clang/test/CIR/CodeGen/bitfields.cpp 
b/clang/test/CIR/CodeGen/bitfields.cpp
index 762d249884741..a4d58b5cadcec 100644
--- a/clang/test/CIR/CodeGen/bitfields.cpp
+++ b/clang/test/CIR/CodeGen/bitfields.cpp
@@ -14,6 +14,7 @@ typedef struct {
   unsigned f; // type other than int above, not a bitfield
 } S;
 // CIR-DAG:  !rec_S = !cir.record<struct "S" {!u64i, !u16i, !u32i}>
+// CIR-DAG:  #bfi_c = #cir.bitfield_info<name = "c", storageType = !u64i, size 
= 17, offset = 32, isSigned = true>
 // LLVM-DAG: %struct.S = type { i64, i16, i32 }
 // OGCG-DAG: %struct.S = type { i64, i16, i32 }
 
@@ -30,3 +31,30 @@ void def() {
   S s;
   T t;
 }
+
+int load_field(S* s) {
+  return s->c;
+}
+// CIR: cir.func dso_local @_Z10load_field
+// CIR:   [[TMP0:%.*]] = cir.alloca !cir.ptr<!rec_S>, 
!cir.ptr<!cir.ptr<!rec_S>>, ["s", init]
+// CIR:   [[TMP1:%.*]] = cir.load{{.*}} [[TMP0]] : !cir.ptr<!cir.ptr<!rec_S>>, 
!cir.ptr<!rec_S>
+// CIR:   [[TMP2:%.*]] = cir.get_member [[TMP1]][0] {name = "c"} : 
!cir.ptr<!rec_S> -> !cir.ptr<!u64i>
+// CIR:   [[TMP3:%.*]] = cir.get_bitfield(#bfi_c, [[TMP2]] : !cir.ptr<!u64i>) 
-> !s32i
+
+// LLVM: define dso_local i32 @_Z10load_fieldP1S
+// LLVM:   [[TMP0:%.*]] = alloca ptr, i64 1, align 8
+// LLVM:   [[TMP1:%.*]] = alloca i32, i64 1, align 4
+// LLVM:   [[TMP2:%.*]] = load ptr, ptr [[TMP0]], align 8
+// LLVM:   [[TMP3:%.*]] = getelementptr %struct.S, ptr [[TMP2]], i32 0, i32 0
+// LLVM:   [[TMP4:%.*]] = load i64, ptr [[TMP3]], align 8
+// LLVM:   [[TMP5:%.*]] = shl i64 [[TMP4]], 15
+// LLVM:   [[TMP6:%.*]] = ashr i64 [[TMP5]], 47
+// LLVM:   [[TMP7:%.*]] = trunc i64 [[TMP6]] to i32
+
+// OGCG: define dso_local noundef i32 @_Z10load_fieldP1S
+// OGCG:  [[TMP0:%.*]] = alloca ptr, align 8
+// OGCG:  [[TMP1:%.*]] = load ptr, ptr [[TMP0]], align 8
+// OGCG:  [[TMP2:%.*]] = load i64, ptr [[TMP1]], align 4
+// OGCG:  [[TMP3:%.*]] = shl i64 [[TMP2]], 15
+// OGCG:  [[TMP4:%.*]] = ashr i64 [[TMP3]], 47
+// OGCG:  [[TMP5:%.*]] = trunc i64 [[TMP4]] to i32
diff --git a/clang/test/CIR/CodeGen/bitfields_be.c 
b/clang/test/CIR/CodeGen/bitfields_be.c
index 149e9c9ac33ff..e839bc2b9698d 100644
--- a/clang/test/CIR/CodeGen/bitfields_be.c
+++ b/clang/test/CIR/CodeGen/bitfields_be.c
@@ -10,8 +10,35 @@ typedef struct {
     int b : 11;
     int c : 17;
 } S;
-S s;
 
 // CIR:  !rec_S = !cir.record<struct "S" {!u32i}>
 // LLVM: %struct.S = type { i32 }
 // OGCG: %struct.S = type { i32 }
+void def() {
+  S s;
+}
+int init(S* s) {
+  return s->c;
+}
+
+//CIR: cir.func dso_local @init
+//CIR:   [[TMP0:%.*]] = cir.alloca !cir.ptr<!rec_S>, 
!cir.ptr<!cir.ptr<!rec_S>>, ["s", init] {alignment = 8 : i64}
+//CIR:   [[TMP1:%.*]] = cir.load align(8) [[TMP0]] : 
!cir.ptr<!cir.ptr<!rec_S>>, !cir.ptr<!rec_S>
+//CIR:   [[TMP2:%.*]] = cir.get_member [[TMP1]][0] {name = "c"} : 
!cir.ptr<!rec_S> -> !cir.ptr<!u32i>
+//CIR:   [[TMP3:%.*]] = cir.get_bitfield(#bfi_c, [[TMP2]] : !cir.ptr<!u32i>) 
-> !s32i
+
+//LLVM: define dso_local i32 @init(ptr %0) {
+//LLVM:   [[TMP0:%.*]] = alloca ptr, i64 1, align 8
+//LLVM:   [[TMP1:%.*]] = alloca i32, i64 1, align 4
+//LLVM:   [[TMP2:%.*]] = load ptr, ptr [[TMP0]], align 8
+//LLVM:   [[TMP3:%.*]] = getelementptr %struct.S, ptr [[TMP2]], i32 0, i32 0
+//LLVM:   [[TMP4:%.*]] = load i32, ptr [[TMP3]], align 4
+//LLVM:   [[TMP5:%.*]] = shl i32 [[TMP4]], 15
+//LLVM:   [[TMP6:%.*]] = ashr i32 [[TMP5]], 15
+
+//OGCG: define dso_local i32 @init
+//OGCG:   [[TMP0:%.*]] = alloca ptr, align 8
+//OGCG:   [[TMP1:%.*]] = load ptr, ptr [[TMP0]], align 8
+//OGCG:   [[TMP2:%.*]] = load i32, ptr [[TMP1]], align 4
+//OGCG:   [[TMP3:%.*]] = shl i32 [[TMP2]], 15
+//OGCG:   [[TMP4:%.*]] = ashr i32 [[TMP3]], 15

>From 1f3479e6c4eb00dfa29c1a17ddfe1acc3acd46c0 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbari...@gmail.com>
Date: Fri, 27 Jun 2025 16:22:47 -0500
Subject: [PATCH 3/4] Remove auto

---
 clang/lib/CIR/CodeGen/CIRGenBuilder.h               | 2 +-
 clang/lib/CIR/CodeGen/CIRGenExpr.cpp                | 2 +-
 clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 2 +-
 clang/lib/CIR/Lowering/LoweringHelpers.cpp          | 8 ++++----
 4 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h 
b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index 7258aad9b70d8..6e52adb6bbaba 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -411,7 +411,7 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
                                 mlir::Value addr, mlir::Type storageType,
                                 const CIRGenBitFieldInfo &info,
                                 bool isLvalueVolatile, bool useVolatile) {
-    auto offset = useVolatile ? info.volatileOffset : info.offset;
+    unsigned int offset = useVolatile ? info.volatileOffset : info.offset;
     return create<cir::GetBitfieldOp>(loc, resultType, addr, storageType,
                                       info.name, info.size, offset,
                                       info.isSigned, isLvalueVolatile);
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index cd20eec934d03..1e6ed59251951 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -335,7 +335,7 @@ RValue CIRGenFunction::emitLoadOfBitfieldLValue(LValue lv, 
SourceLocation loc) {
 
   assert(!cir::MissingFeatures::armComputeVolatileBitfields());
 
-  auto field = builder.createGetBitfield(getLoc(loc), resLTy, ptr.getPointer(),
+  mlir::Value field = builder.createGetBitfield(getLoc(loc), resLTy, 
ptr.getPointer(),
                                          ptr.getElementType(), info,
                                          lv.isVolatile(), false);
   assert(!cir::MissingFeatures::opLoadEmitScalarRangeCheck() && "NYI");
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index c867518199b03..3166d686d8658 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -2287,7 +2287,7 @@ mlir::LogicalResult 
CIRToLLVMGetBitfieldOpLowering::matchAndRewrite(
   }
 
   mlir::Type resTy = getTypeConverter()->convertType(op.getType());
-  auto newOp = createIntCast(
+  mlir::Value newOp = createIntCast(
       rewriter, val, mlir::cast<mlir::IntegerType>(resTy), info.getIsSigned());
   rewriter.replaceOp(op, newOp);
   return mlir::success();
diff --git a/clang/lib/CIR/Lowering/LoweringHelpers.cpp 
b/clang/lib/CIR/Lowering/LoweringHelpers.cpp
index b288ef91af776..6e44de885ffb9 100644
--- a/clang/lib/CIR/Lowering/LoweringHelpers.cpp
+++ b/clang/lib/CIR/Lowering/LoweringHelpers.cpp
@@ -159,26 +159,26 @@ mlir::Value getConst(mlir::OpBuilder &bld, mlir::Location 
loc, mlir::Type typ,
 mlir::Value createShL(mlir::OpBuilder &bld, mlir::Value lhs, unsigned rhs) {
   if (!rhs)
     return lhs;
-  auto rhsVal = getConst(bld, lhs.getLoc(), lhs.getType(), rhs);
+  mlir::Value rhsVal = getConst(bld, lhs.getLoc(), lhs.getType(), rhs);
   return bld.create<mlir::LLVM::ShlOp>(lhs.getLoc(), lhs, rhsVal);
 }
 
 mlir::Value createAShR(mlir::OpBuilder &bld, mlir::Value lhs, unsigned rhs) {
   if (!rhs)
     return lhs;
-  auto rhsVal = getConst(bld, lhs.getLoc(), lhs.getType(), rhs);
+  mlir::Value rhsVal = getConst(bld, lhs.getLoc(), lhs.getType(), rhs);
   return bld.create<mlir::LLVM::AShrOp>(lhs.getLoc(), lhs, rhsVal);
 }
 
 mlir::Value createAnd(mlir::OpBuilder &bld, mlir::Value lhs,
                       const llvm::APInt &rhs) {
-  auto rhsVal = getConstAPInt(bld, lhs.getLoc(), lhs.getType(), rhs);
+  mlir::Value rhsVal = getConstAPInt(bld, lhs.getLoc(), lhs.getType(), rhs);
   return bld.create<mlir::LLVM::AndOp>(lhs.getLoc(), lhs, rhsVal);
 }
 
 mlir::Value createLShR(mlir::OpBuilder &bld, mlir::Value lhs, unsigned rhs) {
   if (!rhs)
     return lhs;
-  auto rhsVal = getConst(bld, lhs.getLoc(), lhs.getType(), rhs);
+  mlir::Value rhsVal = getConst(bld, lhs.getLoc(), lhs.getType(), rhs);
   return bld.create<mlir::LLVM::LShrOp>(lhs.getLoc(), lhs, rhsVal);
 }

>From 24d67033cd221a06247d14b55a3d78f3f97c36d4 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbari...@gmail.com>
Date: Fri, 27 Jun 2025 16:27:40 -0500
Subject: [PATCH 4/4] Remove getBitfieldOp missing feature

---
 clang/include/clang/CIR/MissingFeatures.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/clang/include/clang/CIR/MissingFeatures.h 
b/clang/include/clang/CIR/MissingFeatures.h
index e136d73daac89..9e8944d1114b8 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -200,7 +200,6 @@ struct MissingFeatures {
   static bool fastMathFlags() { return false; }
   static bool fpConstraints() { return false; }
   static bool generateDebugInfo() { return false; }
-  static bool getBitfieldOp() { return false; }
   static bool hip() { return false; }
   static bool implicitConstructorArgs() { return false; }
   static bool incrementProfileCounter() { return false; }

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to