[clang] [CIR] Upstream get_bitfield operation to load bit-field members from structs (PR #145971)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Jul 2 13:23:24 PDT 2025
https://github.com/Andres-Salamanca updated https://github.com/llvm/llvm-project/pull/145971
>From f1f1d8c8db9d3c976e2baa50ac70bfa88b905434 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbaritos at gmail.com>
Date: Thu, 26 Jun 2025 15:51:02 -0500
Subject: [PATCH 1/7] 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 c33d68fa5e730..0dd38c2b470f5 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -204,6 +204,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 c2a7315fd101b..8c527ef51344e 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!
@@ -976,6 +979,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 9c05865b565c2783dc50caa53feff8dbda572d22 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbaritos at gmail.com>
Date: Fri, 27 Jun 2025 16:08:49 -0500
Subject: [PATCH 2/7] [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 | 49 ++++++++++++
.../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, 359 insertions(+), 11 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 060fbf7fad068..9726d28d64d8a 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -453,4 +453,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 4afacab80957a..10267a8086ed1 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 17b931a0693aa..e63ab489c73b0 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/CIRTypeInterfaces.h"
#include "clang/CIR/MissingFeatures.h"
@@ -392,6 +393,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 8c527ef51344e..621faa0adec9c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -959,6 +959,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 2d5dcf69c489f..2a54906703011 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 bdc7492d48211..3039314b4cd12 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -1965,6 +1965,7 @@ void ConvertCIRToLLVMPass::runOnOperation() {
CIRToLLVMConstantOpLowering,
CIRToLLVMExpectOpLowering,
CIRToLLVMFuncOpLowering,
+ CIRToLLVMGetBitfieldOpLowering,
CIRToLLVMGetGlobalOpLowering,
CIRToLLVMGetMemberOpLowering,
CIRToLLVMSelectOpLowering,
@@ -2303,6 +2304,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 da3fe4412ec2a..33a0fd3e257ef 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 d52729f8a41e864241b207c10a44fb5ffaff445e Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbaritos at gmail.com>
Date: Fri, 27 Jun 2025 16:22:47 -0500
Subject: [PATCH 3/7] 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 e63ab489c73b0..a84cde8e8bd7b 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -398,7 +398,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 3039314b4cd12..e948f12150afa 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -2346,7 +2346,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 33a0fd3e257ef..d5f132431aba2 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 c310c1f5047ca811601b7847c1251f5b99fce2c1 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbaritos at gmail.com>
Date: Fri, 27 Jun 2025 16:27:40 -0500
Subject: [PATCH 4/7] 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 0dd38c2b470f5..c33d68fa5e730 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -204,7 +204,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; }
>From 5306ed3728a6985cb675fec2eb7b54c1717a65db Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbaritos at gmail.com>
Date: Sat, 28 Jun 2025 18:05:27 -0500
Subject: [PATCH 5/7] Apply reviews
---
.../include/clang/CIR/Dialect/IR/CIRAttrs.td | 29 +++++++++++++++++--
clang/lib/CIR/CodeGen/CIRGenBuilder.h | 3 +-
clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 1 +
clang/test/CIR/CodeGen/bitfields.c | 29 +++++++++++++++++++
4 files changed, 58 insertions(+), 4 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 9726d28d64d8a..6860d82f1d6d7 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -460,8 +460,33 @@ def CIR_VisibilityAttr : CIR_EnumAttr<CIR_VisibilityKind, "visibility"> {
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.
+ Holds the following information about bitfields: name, storage type, size
+ and position in the storage, and signedness.
+ Example:
+ Given the following struct with bitfields:
+ ```c++
+ typedef struct {
+ int a : 4;
+ int b : 27;
+ int c : 17;
+ int d : 2;
+ int e : 15;
+ } S;
+ ```
+
+ The CIR representation of the struct `S` might look like:
+ ```mlir
+ !rec_S = !cir.record<struct "S" packed padded {!u64i, !u16i,
+ !cir.array<!u8i x 2>}>
+ ```
+ And the bitfield info attribute for member `a` would be:
+ ```mlir
+ #bfi_a = #cir.bitfield_info<name = "a", storage_type = !u64i,
+ size = 4, offset = 0, is_signed = true>
+ ```
+
+ This metadata describes that field `a` is stored in a 64-bit integer,
+ is 4 bits wide, starts at offset 0, and is signed.
}];
let parameters = (ins "mlir::StringAttr":$name,
"mlir::Type":$storageType,
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index a84cde8e8bd7b..0b33f6c7d03b7 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -398,9 +398,8 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
mlir::Value addr, mlir::Type storageType,
const CIRGenBitFieldInfo &info,
bool isLvalueVolatile, bool useVolatile) {
- unsigned int offset = useVolatile ? info.volatileOffset : info.offset;
return create<cir::GetBitfieldOp>(loc, resultType, addr, storageType,
- info.name, info.size, offset,
+ info.name, info.size, info.offset,
info.isSigned, isLvalueVolatile);
}
};
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index 1e6ed59251951..f2e63ed0a777e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -360,6 +360,7 @@ LValue CIRGenFunction::emitLValueForBitField(LValue base,
cgm.getTypes().getCIRGenRecordLayout(field->getParent());
const CIRGenBitFieldInfo &info = layout.getBitFieldInfo(field);
assert(!cir::MissingFeatures::armComputeVolatileBitfields());
+ assert(!cir::MissingFeatures::preservedAccessIndexRegion());
unsigned idx = layout.getCIRFieldNo(field);
Address addr = getAddrOfBitFieldStorage(base, field, info.storageType, idx);
diff --git a/clang/test/CIR/CodeGen/bitfields.c b/clang/test/CIR/CodeGen/bitfields.c
index 28ce09e2e2c89..6eb753c5cc3d2 100644
--- a/clang/test/CIR/CodeGen/bitfields.c
+++ b/clang/test/CIR/CodeGen/bitfields.c
@@ -13,6 +13,7 @@ typedef struct {
} A;
// CIR-DAG: !rec_A = !cir.record<struct "A" packed padded {!s8i, !s8i, !s8i, !u16i, !cir.array<!u8i x 3>}>
+// CIR-DAG: #bfi_more_bits = #cir.bitfield_info<name = "more_bits", storageType = !u16i, size = 4, offset = 3, isSigned = false>
// LLVM-DAG: %struct.A = type <{ i8, i8, i8, i16, [3 x i8] }>
// OGCG-DAG: %struct.A = type <{ i8, i8, i8, i16, [3 x i8] }>
@@ -105,3 +106,31 @@ int load_field(S* s) {
// OGCG: [[TMP3:%.*]] = shl i64 [[TMP2]], 15
// OGCG: [[TMP4:%.*]] = ashr i64 [[TMP3]], 47
// OGCG: [[TMP5:%.*]] = trunc i64 [[TMP4]] to i32
+
+unsigned int load_field_unsigned(A* s) {
+ return s->more_bits;
+}
+
+//CIR: cir.func dso_local @load_field_unsigned
+//CIR: [[TMP0:%.*]] = cir.alloca !cir.ptr<!rec_A>, !cir.ptr<!cir.ptr<!rec_A>>, ["s", init] {alignment = 8 : i64}
+//CIR: [[TMP1:%.*]] = cir.load align(8) [[TMP0]] : !cir.ptr<!cir.ptr<!rec_A>>, !cir.ptr<!rec_A>
+//CIR: [[TMP2:%.*]] = cir.get_member [[TMP1]][3] {name = "more_bits"} : !cir.ptr<!rec_A> -> !cir.ptr<!u16i>
+//CIR: [[TMP3:%.*]] = cir.get_bitfield(#bfi_more_bits, [[TMP2]] : !cir.ptr<!u16i>) -> !u32i
+
+//LLVM: define dso_local i32 @load_field_unsigned
+//LLVM: [[TMP0:%.*]] = alloca ptr, i64 1, align 8
+//LLVM: [[TMP1:%.*]] = load ptr, ptr [[TMP0]], align 8
+//LLVM: [[TMP2:%.*]] = getelementptr %struct.A, ptr [[TMP1]], i32 0, i32 3
+//LLVM: [[TMP3:%.*]] = load i16, ptr [[TMP2]], align 2
+//LLVM: [[TMP4:%.*]] = lshr i16 [[TMP3]], 3
+//LLVM: [[TMP5:%.*]] = and i16 [[TMP4]], 15
+//LLVM: [[TMP6:%.*]] = zext i16 [[TMP5]] to i32
+
+//OGCG: define dso_local i32 @load_field_unsigned
+//OGCG: [[TMP0:%.*]] = alloca ptr, align 8
+//OGCG: [[TMP1:%.*]] = load ptr, ptr [[TMP0]], align 8
+//OGCG: [[TMP2:%.*]] = getelementptr inbounds nuw %struct.A, ptr [[TMP1]], i32 0, i32 3
+//OGCG: [[TMP3:%.*]] = load i16, ptr [[TMP2]], align 1
+//OGCG: [[TMP4:%.*]] = lshr i16 [[TMP3]], 3
+//OGCG: [[TMP5:%.*]] = and i16 [[TMP4]], 15
+//OGCG: [[TMP6:%.*]] = zext i16 [[TMP5]] to i32
>From 51a4da212e41d7f034aa72ed5545229f2ca80729 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbaritos at gmail.com>
Date: Tue, 1 Jul 2025 16:09:52 -0500
Subject: [PATCH 6/7] Apply review in docs
---
clang/include/clang/CIR/Dialect/IR/CIRAttrs.td | 2 +-
clang/include/clang/CIR/Dialect/IR/CIROps.td | 6 +++---
clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 6 +++---
3 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 6860d82f1d6d7..75650beec0c6d 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -458,7 +458,7 @@ def CIR_VisibilityAttr : CIR_EnumAttr<CIR_VisibilityKind, "visibility"> {
//===----------------------------------------------------------------------===//
def BitfieldInfoAttr : CIR_Attr<"BitfieldInfo", "bitfield_info"> {
- let summary = "Represents a bit field info";
+ let summary = "Represents info for a bit-field member";
let description = [{
Holds the following information about bitfields: name, storage type, size
and position in the storage, and signedness.
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 10267a8086ed1..187e04bc25f24 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -1674,7 +1674,7 @@ def GetGlobalOp : CIR_Op<"get_global",
//===----------------------------------------------------------------------===//
def GetBitfieldOp : CIR_Op<"get_bitfield"> {
- let summary = "Get a bitfield";
+ let summary = "Get the information for a bitfield member";
let description = [{
The `cir.get_bitfield` operation provides a load-like access to
a bit field of a record.
@@ -1688,8 +1688,8 @@ def GetBitfieldOp : CIR_Op<"get_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
+ different members. The `cir.get_bitfield` operation gets the value
+ of the bitfield.
```C++
typedef struct {
int a : 4;
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index f2e63ed0a777e..68d7f1f5bca48 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -335,9 +335,9 @@ RValue CIRGenFunction::emitLoadOfBitfieldLValue(LValue lv, SourceLocation loc) {
assert(!cir::MissingFeatures::armComputeVolatileBitfields());
- mlir::Value field = builder.createGetBitfield(getLoc(loc), resLTy, ptr.getPointer(),
- ptr.getElementType(), info,
- lv.isVolatile(), false);
+ mlir::Value field = builder.createGetBitfield(
+ getLoc(loc), resLTy, ptr.getPointer(), ptr.getElementType(), info,
+ lv.isVolatile(), false);
assert(!cir::MissingFeatures::opLoadEmitScalarRangeCheck() && "NYI");
return RValue::get(field);
}
>From f16035e643517e14f3054d85410c29d628975908 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbaritos at gmail.com>
Date: Wed, 2 Jul 2025 10:48:58 -0500
Subject: [PATCH 7/7] Replace else-if with type switch
---
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 23 +++++++++++--------
1 file changed, 14 insertions(+), 9 deletions(-)
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index e948f12150afa..891017e1d8256 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -2318,15 +2318,20 @@ mlir::LogicalResult CIRToLLVMGetBitfieldOpLowering::matchAndRewrite(
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::IntegerType intType =
+ TypeSwitch<mlir::Type, mlir::IntegerType>(storageType)
+ .Case<cir::ArrayType>([&](cir::ArrayType atTy) {
+ storageSize = atTy.getSize() * 8;
+ return mlir::IntegerType::get(context, storageSize);
+ })
+ .Case<cir::IntType>([&](cir::IntType intTy) {
+ storageSize = intTy.getWidth();
+ return mlir::IntegerType::get(context, storageSize);
+ })
+ .Default([](mlir::Type) -> mlir::IntegerType {
+ llvm_unreachable(
+ "Either ArrayType or IntType expected for bitfields storage");
+ });
mlir::Value val = rewriter.create<mlir::LLVM::LoadOp>(
op.getLoc(), intType, adaptor.getAddr(), 0, op.getIsVolatile());
More information about the cfe-commits
mailing list