[clang] [CIR] Upstream get_bitfield operation to load bit-field members from structs (PR #145971)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 27 14:23:06 PDT 2025
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 <andrealebarbaritos at gmail.com>
Date: Thu, 26 Jun 2025 15:51:02 -0500
Subject: [PATCH 1/3] 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 <andrealebarbaritos at gmail.com>
Date: Fri, 27 Jun 2025 16:08:49 -0500
Subject: [PATCH 2/3] [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 <andrealebarbaritos at gmail.com>
Date: Fri, 27 Jun 2025 16:22:47 -0500
Subject: [PATCH 3/3] 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);
}
More information about the cfe-commits
mailing list