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