From 1923647b68f2c88d64af4696f4275f186f7551ca Mon Sep 17 00:00:00 2001 From: gitoleg Date: Mon, 30 Oct 2023 14:31:43 +0300 Subject: [PATCH 01/15] [CIR][CodeGen] Bitfield operations --- .../CIR/Dialect/Builder/CIRBaseBuilder.h | 176 ++++++++++++++++++ .../include/clang/CIR/Dialect/IR/CIRAttrs.td | 29 +++ clang/include/clang/CIR/Dialect/IR/CIROps.td | 101 ++++++++++ clang/lib/CIR/CodeGen/CIRGenBuilder.h | 157 +++------------- clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 147 ++++----------- clang/lib/CIR/CodeGen/CIRGenRecordLayout.h | 3 + .../CIR/CodeGen/CIRRecordLayoutBuilder.cpp | 1 + .../Dialect/Transforms/LoweringPrepare.cpp | 151 +++++++++++++-- 8 files changed, 508 insertions(+), 257 deletions(-) create mode 100644 clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h new file mode 100644 index 000000000000..f92dfea09de4 --- /dev/null +++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h @@ -0,0 +1,176 @@ +//===-- CIRBaseBuilder.h - CIRBuilder implementation -----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_CIRBASEBUILDER_H +#define LLVM_CLANG_LIB_CIRBASEBUILDER_H + +#include "clang/AST/Decl.h" +#include "clang/AST/Type.h" +#include "clang/CIR/Dialect/IR/CIRAttrs.h" +#include "clang/CIR/Dialect/IR/CIRDialect.h" +#include "clang/CIR/Dialect/IR/CIROpsEnums.h" +#include "clang/CIR/Dialect/IR/CIRTypes.h" +#include "clang/CIR/Dialect/IR/FPEnv.h" + +#include "mlir/IR/Attributes.h" +#include "mlir/IR/Builders.h" +#include "mlir/IR/BuiltinAttributes.h" +#include "mlir/IR/BuiltinOps.h" +#include "mlir/IR/BuiltinTypes.h" +#include "mlir/IR/Location.h" +#include "mlir/IR/Types.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/FloatingPointMode.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/Support/ErrorHandling.h" +#include +#include +#include + +namespace cir { + +class CIRBaseBuilderTy : public mlir::OpBuilder { + +public: + CIRBaseBuilderTy(mlir::MLIRContext &C) : mlir::OpBuilder(&C) {} + + + mlir::Value getConstAPInt(mlir::Location loc, mlir::Type typ, + const llvm::APInt &val) { + return create(loc, typ, + getAttr(typ, val)); + } + + + mlir::Value createNot(mlir::Value value) { + return create(value.getLoc(), value.getType(), + mlir::cir::UnaryOpKind::Not, value); + } + + mlir::Value createBinop(mlir::Value lhs, mlir::cir::BinOpKind kind, + const llvm::APInt &rhs) { + return create( + lhs.getLoc(), lhs.getType(), kind, lhs, + getConstAPInt(lhs.getLoc(), lhs.getType(), rhs)); + } + + mlir::Value createBinop(mlir::Value lhs, mlir::cir::BinOpKind kind, + mlir::Value rhs) { + return create(lhs.getLoc(), lhs.getType(), kind, lhs, + rhs); + } + + mlir::Value createShift(mlir::Value lhs, const llvm::APInt &rhs, + bool isShiftLeft) { + return create( + lhs.getLoc(), lhs.getType(), lhs, + getConstAPInt(lhs.getLoc(), lhs.getType(), rhs), isShiftLeft); + } + + mlir::Value createShift(mlir::Value lhs, unsigned bits, bool isShiftLeft) { + auto width = lhs.getType().dyn_cast().getWidth(); + auto shift = llvm::APInt(width, bits); + return createShift(lhs, shift, isShiftLeft); + } + + mlir::Value createShiftLeft(mlir::Value lhs, unsigned bits) { + return createShift(lhs, bits, true); + } + + mlir::Value createShiftRight(mlir::Value lhs, unsigned bits) { + return createShift(lhs, bits, false); + } + + mlir::Value createLowBitsSet(mlir::Location loc, unsigned size, + unsigned bits) { + auto val = llvm::APInt::getLowBitsSet(size, bits); + auto typ = mlir::cir::IntType::get(getContext(), size, false); + return getConstAPInt(loc, typ, val); + } + + mlir::Value createAnd(mlir::Value lhs, llvm::APInt rhs) { + auto val = getConstAPInt(lhs.getLoc(), lhs.getType(), rhs); + return createBinop(lhs, mlir::cir::BinOpKind::And, val); + } + + mlir::Value createAnd(mlir::Value lhs, mlir::Value rhs) { + return createBinop(lhs, mlir::cir::BinOpKind::And, rhs); + } + + mlir::Value createOr(mlir::Value lhs, llvm::APInt rhs) { + auto val = getConstAPInt(lhs.getLoc(), lhs.getType(), rhs); + return createBinop(lhs, mlir::cir::BinOpKind::Or, val); + } + + mlir::Value createOr(mlir::Value lhs, mlir::Value rhs) { + return createBinop(lhs, mlir::cir::BinOpKind::Or, rhs); + } + + //===--------------------------------------------------------------------===// + // Cast/Conversion Operators + //===--------------------------------------------------------------------===// + + mlir::Value createCast(mlir::cir::CastKind kind, mlir::Value src, + mlir::Type newTy) { + if (newTy == src.getType()) + return src; + return create(src.getLoc(), newTy, kind, src); + } + + mlir::Value createIntCast(mlir::Value src, mlir::Type newTy) { + return create(src.getLoc(), newTy, + mlir::cir::CastKind::integral, src); + } + + mlir::Value createIntToPtr(mlir::Value src, mlir::Type newTy) { + return create(src.getLoc(), newTy, + mlir::cir::CastKind::int_to_ptr, src); + } + + mlir::Value createPtrToInt(mlir::Value src, mlir::Type newTy) { + return create(src.getLoc(), newTy, + mlir::cir::CastKind::ptr_to_int, src); + } + + // TODO(cir): the following function was introduced to keep in sync with LLVM + // codegen. CIR does not have "zext" operations. It should eventually be + // renamed or removed. For now, we just add whatever cast is required here. + mlir::Value createZExtOrBitCast(mlir::Location loc, mlir::Value src, + mlir::Type newTy) { + auto srcTy = src.getType(); + + if (srcTy == newTy) + return src; + + if (srcTy.isa() && newTy.isa()) + return createBoolToInt(src, newTy); + + llvm_unreachable("unhandled extension cast"); + } + + mlir::Value createBoolToInt(mlir::Value src, mlir::Type newTy) { + return createCast(mlir::cir::CastKind::bool_to_int, src, newTy); + } + + mlir::Value createBitcast(mlir::Value src, mlir::Type newTy) { + return createCast(mlir::cir::CastKind::bitcast, src, newTy); + } + + mlir::Value createBitcast(mlir::Location loc, mlir::Value src, + mlir::Type newTy) { + if (newTy == src.getType()) + return src; + return create(loc, newTy, mlir::cir::CastKind::bitcast, + src); + } +}; + +} // namespace cir +#endif diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td index c3e551f08632..81cca3023b80 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td @@ -521,4 +521,33 @@ def GlobalCtorAttr : CIR_Attr<"GlobalCtor", "globalCtor"> { ]; let skipDefaultBuilders = 1; } + +def BitfieldInfoAttr : CIR_Attr<"BitfieldInfo", "bitfieldInfo"> { + let parameters = (ins "StringAttr":$name, + "Type":$eltType, + "uint64_t":$storageSize, + "uint64_t":$size, + "uint64_t":$offset, + "bool":$isSigned); + + let assemblyFormat = [{ `<` + `(` `name` `=` $name `)` + `(` `size` $size `)` + `(` `storage` $eltType $storageSize `)` + `(` `offset` $offset `)` + `(` `signed` `=` $isSigned `)` `>` }]; + + let builders = [ + AttrBuilder<(ins "StringRef":$name, + "Type":$eltType, + "uint64_t":$storageSize, + "uint64_t":$size, + "uint64_t":$offset, + "bool":$isSigned + ), [{ + return $_get($_ctxt, StringAttr::get($_ctxt, name), eltType, storageSize, size, offset, isSigned); + }]> + ]; +} + #endif // MLIR_CIR_DIALECT_CIR_ATTRS diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index a1177b11cea5..2e6badea5196 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -1415,6 +1415,107 @@ def VTableAddrPointOp : CIR_Op<"vtable.address_point", let hasVerifier = 1; } +//===----------------------------------------------------------------------===// +// SetBitfieldOp +//===----------------------------------------------------------------------===// + +def SetBitfieldOp : CIR_Op<"set_bitfield"> { + let summary = "Set a bitfield"; + let description = [{ + The `cir.set_bitfield` operation provides a store-like access to + a bit field of a record. + + It expects an address of a storage where to store, a value being stored, + a type of a bitfield, a name of a bit field, a pointer to a storage in the + base record, a size of the storage, a size the bit field, an offset + of the bit field and a sign. Returns a value being stored. + + Example: + ```mlir + // Suppose we have a struct with multiple bitfields stored in + // different storages. The `cir.get_bitfield` operation gets the value + // of the bitfield + + // Sets the bitfield with name a1. + %6 = "cir.set_bitfield"(%5, %3) <{BitfieldInfo = #cir.bitfieldInfo<(name = "a1") (size 4) (storage !u64i 64) (offset 0) (signed = true)>}> : (!cir.ptr, !s32i) -> !s32i + ``` + }]; + + let arguments = (ins + AnyType:$dst, + AnyType:$src, + BitfieldInfoAttr:$BitfieldInfo + ); + + let results = (outs CIR_IntType:$result); + + let builders = [ + OpBuilder<(ins "Type":$type, + "Value":$dst, + "Type":$eltType, + "Value":$src, + "StringRef":$name, + "unsigned":$storageSize, + "unsigned":$size, + "unsigned":$offset, + "bool":$isSigned + ), + [{ + BitfieldInfoAttr info = BitfieldInfoAttr::get($_builder.getContext(), name, eltType, storageSize, size, offset, isSigned); + build($_builder, $_state, type, dst, src, info); + }]> + ]; +} + +//===----------------------------------------------------------------------===// +// 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 size of the storage, a size the bit field, an offset + of the bit field and a sign. + + Example: + ```mlir + // Suppose we have a struct with multiple bitfields stored in + // different storages. The `cir.get_bitfield` operation gets the value + // of the bitfield + + // Get the address of the bitfield with name a1. + %6 = "cir.get_bitfield"(%5) <{BitfieldInfo = #cir.bitfieldInfo<(name = "a1") (size 4) (storage !u64i 64) (offset 0) (signed = true)>}> : (!cir.ptr) -> !s32i + ``` + }]; + + let arguments = (ins + AnyType:$addr, + BitfieldInfoAttr:$BitfieldInfo + ); + + let results = (outs CIR_IntType:$result); + + let builders = [ + OpBuilder<(ins "Type":$type, + "Value":$addr, + "Type":$eltType, + "StringRef":$name, + "unsigned":$storageSize, + "unsigned":$size, + "unsigned":$offset, + "bool":$isSigned + ), + [{ + BitfieldInfoAttr info = BitfieldInfoAttr::get($_builder.getContext(), name, eltType, storageSize, size, offset, isSigned); + build($_builder, $_state, type, addr, info); + }]> + ]; +} + //===----------------------------------------------------------------------===// // GetMemberOp //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h index 8e25c4ac7acb..560a43f3d40f 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h @@ -10,11 +10,13 @@ #define LLVM_CLANG_LIB_CIR_CIRGENBUILDER_H #include "Address.h" +#include "CIRGenRecordLayout.h" #include "CIRGenTypeCache.h" #include "UnimplementedFeatureGuarding.h" #include "clang/AST/Decl.h" #include "clang/AST/Type.h" +#include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h" #include "clang/CIR/Dialect/IR/CIRAttrs.h" #include "clang/CIR/Dialect/IR/CIRDialect.h" #include "clang/CIR/Dialect/IR/CIROpsEnums.h" @@ -42,7 +44,7 @@ namespace cir { class CIRGenFunction; -class CIRGenBuilderTy : public mlir::OpBuilder { +class CIRGenBuilderTy : public CIRBaseBuilderTy { const CIRGenTypeCache &typeCache; bool IsFPConstrained = false; fp::ExceptionBehavior DefaultConstrainedExcept = fp::ebStrict; @@ -53,7 +55,7 @@ class CIRGenBuilderTy : public mlir::OpBuilder { public: CIRGenBuilderTy(mlir::MLIRContext &C, const CIRGenTypeCache &tc) - : mlir::OpBuilder(&C), typeCache(tc) {} + : CIRBaseBuilderTy(C), typeCache(tc) {} std::string getUniqueAnonRecordName() { std::string name = "anon." + std::to_string(anonRecordNames.size()); @@ -468,11 +470,6 @@ class CIRGenBuilderTy : public mlir::OpBuilder { return getConstInt( loc, t, isSigned ? intVal.getSExtValue() : intVal.getZExtValue()); } - mlir::Value getConstAPInt(mlir::Location loc, mlir::Type typ, - const llvm::APInt &val) { - return create(loc, typ, - getAttr(typ, val)); - } mlir::cir::ConstantOp getBool(bool state, mlir::Location loc) { return create(loc, getBoolTy(), getCIRBoolAttr(state)); @@ -622,6 +619,30 @@ class CIRGenBuilderTy : public mlir::OpBuilder { global.getLoc(), getPointerTo(global.getSymType()), global.getName()); } + mlir::Value createGetBitfield(mlir::Location loc, mlir::Type resultType, + mlir::Value addr, mlir::Type eltType, + const CIRGenBitFieldInfo &info, + bool useVolatile) { + auto offset = useVolatile ? info.VolatileOffset : info.Offset; + auto storageSize = + useVolatile ? info.VolatileStorageSize : info.StorageSize; + return create(loc, resultType, addr, eltType, + info.Name, storageSize, info.Size, + offset, info.IsSigned); + } + + mlir::Value createSetBitfield(mlir::Location loc, mlir::Type resultType, + mlir::Value dstAddr, mlir::Type eltType, + mlir::Value src, const CIRGenBitFieldInfo &info, + bool useVolatile) { + auto storageSize = + useVolatile ? info.VolatileStorageSize : info.StorageSize; + auto offset = useVolatile ? info.VolatileOffset : info.Offset; + return create( + loc, resultType, dstAddr, eltType, src, info.Name, storageSize, + info.Size, offset, info.IsSigned); + } + /// Create a pointer to a record member. mlir::Value createGetMember(mlir::Location loc, mlir::Type result, mlir::Value base, llvm::StringRef name, @@ -641,14 +662,6 @@ class CIRGenBuilderTy : public mlir::OpBuilder { addr.getAlignment()); } - mlir::Value createBitcast(mlir::Location loc, mlir::Value src, - mlir::Type newTy) { - if (newTy == src.getType()) - return src; - return create(loc, newTy, mlir::cir::CastKind::bitcast, - src); - } - mlir::Value createLoad(mlir::Location loc, Address addr) { return create(loc, addr.getElementType(), addr.getPointer()); @@ -684,120 +697,6 @@ class CIRGenBuilderTy : public mlir::OpBuilder { auto flag = getBool(val, loc); return create(loc, flag, dst); } - - mlir::Value createNot(mlir::Value value) { - return create(value.getLoc(), value.getType(), - mlir::cir::UnaryOpKind::Not, value); - } - - mlir::Value createBinop(mlir::Value lhs, mlir::cir::BinOpKind kind, - const llvm::APInt &rhs) { - return create( - lhs.getLoc(), lhs.getType(), kind, lhs, - getConstAPInt(lhs.getLoc(), lhs.getType(), rhs)); - } - - mlir::Value createBinop(mlir::Value lhs, mlir::cir::BinOpKind kind, - mlir::Value rhs) { - return create(lhs.getLoc(), lhs.getType(), kind, lhs, - rhs); - } - - mlir::Value createShift(mlir::Value lhs, const llvm::APInt &rhs, - bool isShiftLeft) { - return create( - lhs.getLoc(), lhs.getType(), lhs, - getConstAPInt(lhs.getLoc(), lhs.getType(), rhs), isShiftLeft); - } - - mlir::Value createShift(mlir::Value lhs, unsigned bits, bool isShiftLeft) { - auto width = lhs.getType().dyn_cast().getWidth(); - auto shift = llvm::APInt(width, bits); - return createShift(lhs, shift, isShiftLeft); - } - - mlir::Value createShiftLeft(mlir::Value lhs, unsigned bits) { - return createShift(lhs, bits, true); - } - - mlir::Value createShiftRight(mlir::Value lhs, unsigned bits) { - return createShift(lhs, bits, false); - } - - mlir::Value createLowBitsSet(mlir::Location loc, unsigned size, - unsigned bits) { - auto val = llvm::APInt::getLowBitsSet(size, bits); - auto typ = mlir::cir::IntType::get(getContext(), size, false); - return getConstAPInt(loc, typ, val); - } - - mlir::Value createAnd(mlir::Value lhs, llvm::APInt rhs) { - auto val = getConstAPInt(lhs.getLoc(), lhs.getType(), rhs); - return createBinop(lhs, mlir::cir::BinOpKind::And, val); - } - - mlir::Value createAnd(mlir::Value lhs, mlir::Value rhs) { - return createBinop(lhs, mlir::cir::BinOpKind::And, rhs); - } - - mlir::Value createOr(mlir::Value lhs, llvm::APInt rhs) { - auto val = getConstAPInt(lhs.getLoc(), lhs.getType(), rhs); - return createBinop(lhs, mlir::cir::BinOpKind::Or, val); - } - - mlir::Value createOr(mlir::Value lhs, mlir::Value rhs) { - return createBinop(lhs, mlir::cir::BinOpKind::Or, rhs); - } - - //===--------------------------------------------------------------------===// - // Cast/Conversion Operators - //===--------------------------------------------------------------------===// - - mlir::Value createCast(mlir::cir::CastKind kind, mlir::Value src, - mlir::Type newTy) { - if (newTy == src.getType()) - return src; - return create(src.getLoc(), newTy, kind, src); - } - - mlir::Value createIntCast(mlir::Value src, mlir::Type newTy) { - return create(src.getLoc(), newTy, - mlir::cir::CastKind::integral, src); - } - - mlir::Value createIntToPtr(mlir::Value src, mlir::Type newTy) { - return create(src.getLoc(), newTy, - mlir::cir::CastKind::int_to_ptr, src); - } - - mlir::Value createPtrToInt(mlir::Value src, mlir::Type newTy) { - return create(src.getLoc(), newTy, - mlir::cir::CastKind::ptr_to_int, src); - } - - // TODO(cir): the following function was introduced to keep in sync with LLVM - // codegen. CIR does not have "zext" operations. It should eventually be - // renamed or removed. For now, we just add whatever cast is required here. - mlir::Value createZExtOrBitCast(mlir::Location loc, mlir::Value src, - mlir::Type newTy) { - auto srcTy = src.getType(); - - if (srcTy == newTy) - return src; - - if (srcTy.isa() && newTy.isa()) - return createBoolToInt(src, newTy); - - llvm_unreachable("unhandled extension cast"); - } - - mlir::Value createBoolToInt(mlir::Value src, mlir::Type newTy) { - return createCast(mlir::cir::CastKind::bool_to_int, src, newTy); - } - - mlir::Value createBitcast(mlir::Value src, mlir::Type newTy) { - return createCast(mlir::cir::CastKind::bitcast, src, newTy); - } }; } // namespace cir diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index 0765944d62e1..3d740074bdef 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -218,14 +218,14 @@ static bool isAAPCS(const TargetInfo &TargetInfo) { return TargetInfo.getABI().startswith("aapcs"); } -Address CIRGenFunction::getAddrOfBitFieldStorage(LValue base, +Address CIRGenFunction::getAddrOfBitFieldStorage(LValue base, const FieldDecl *field, unsigned index, unsigned size) { if (index == 0) return base.getAddress(); - auto loc = getLoc(field->getLocation()); + auto loc = getLoc(field->getLocation()); auto fieldType = builder.getUIntNTy(size); auto fieldPtr = @@ -264,7 +264,6 @@ LValue CIRGenFunction::buildLValueForBitField(LValue base, const unsigned SS = useVolatile ? info.VolatileStorageSize : info.StorageSize; Address Addr = getAddrOfBitFieldStorage(base, field, Idx, SS); - // Get the access type. mlir::Type FieldIntTy = builder.getUIntNTy(SS); @@ -274,7 +273,6 @@ LValue CIRGenFunction::buildLValueForBitField(LValue base, QualType fieldType = field->getType().withCVRQualifiers(base.getVRQualifiers()); - assert(!UnimplementedFeature::tbaa() && "NYI TBAA for bit fields"); LValueBaseInfo FieldBaseInfo(BaseInfo.getAlignmentSource()); return LValue::MakeBitfield(Addr, info, fieldType, FieldBaseInfo); @@ -396,7 +394,7 @@ LValue CIRGenFunction::buildLValueForFieldInitialization( auto& layout = CGM.getTypes().getCIRGenRecordLayout(Field->getParent()); unsigned FieldIndex = layout.getCIRFieldNo(Field); - + Address V = buildAddrOfFieldStorage(*this, Base.getAddress(), Field, FieldName, FieldIndex); @@ -605,42 +603,20 @@ RValue CIRGenFunction::buildLoadOfLValue(LValue LV, SourceLocation Loc) { RValue CIRGenFunction::buildLoadOfBitfieldLValue(LValue LV, SourceLocation Loc) { - const CIRGenBitFieldInfo &Info = LV.getBitFieldInfo(); + const CIRGenBitFieldInfo &info = LV.getBitFieldInfo(); // Get the output type. - mlir::Type ResLTy = convertType(LV.getType()); - Address Ptr = LV.getBitFieldAddress(); - mlir::Value Val = builder.createLoad(getLoc(Loc), Ptr); - auto ValWidth = Val.getType().cast().getWidth(); - - bool UseVolatile = LV.isVolatileQualified() && - Info.VolatileStorageSize != 0 && isAAPCS(CGM.getTarget()); - const unsigned Offset = UseVolatile ? Info.VolatileOffset : Info.Offset; - const unsigned StorageSize = - UseVolatile ? Info.VolatileStorageSize : Info.StorageSize; - - if (Info.IsSigned) { - assert(static_cast(Offset + Info.Size) <= StorageSize); - - mlir::Type typ = builder.getSIntNTy(ValWidth); - Val = builder.createIntCast(Val, typ); - - unsigned HighBits = StorageSize - Offset - Info.Size; - if (HighBits) - Val = builder.createShiftLeft(Val, HighBits); - if (Offset + HighBits) - Val = builder.createShiftRight(Val, Offset + HighBits); - } else { - if (Offset) - Val = builder.createShiftRight(Val, Offset); + mlir::Type resLTy = convertType(LV.getType()); + Address ptr = LV.getBitFieldAddress(); - if (static_cast(Offset) + Info.Size < StorageSize) - Val = builder.createAnd(Val, - llvm::APInt::getLowBitsSet(ValWidth, Info.Size)); - } - Val = builder.createIntCast(Val, ResLTy); - assert(!UnimplementedFeature::emitScalarRangeCheck() && "NYI"); - return RValue::get(Val); + bool useVolatile = LV.isVolatileQualified() && + info.VolatileStorageSize != 0 && isAAPCS(CGM.getTarget()); + + auto field = + builder.createGetBitfield(getLoc(Loc), resLTy, ptr.getPointer(), + ptr.getElementType(), info, useVolatile); + assert(!UnimplementedFeature::emitScalarRangeCheck() && "NYI"); + return RValue::get(field); } void CIRGenFunction::buildStoreThroughLValue(RValue Src, LValue Dst) { @@ -665,79 +641,28 @@ void CIRGenFunction::buildStoreThroughLValue(RValue Src, LValue Dst) { void CIRGenFunction::buildStoreThroughBitfieldLValue(RValue Src, LValue Dst, mlir::Value &Result) { - const CIRGenBitFieldInfo &Info = Dst.getBitFieldInfo(); - mlir::Type ResLTy = getTypes().convertTypeForMem(Dst.getType()); - Address Ptr = Dst.getBitFieldAddress(); - - // Get the source value, truncated to the width of the bit-field. - mlir::Value SrcVal = Src.getScalarVal(); - - // Cast the source to the storage type and shift it into place. - SrcVal = builder.createIntCast(SrcVal, Ptr.getElementType()); - auto SrcWidth = SrcVal.getType().cast().getWidth(); - mlir::Value MaskedVal = SrcVal; - - const bool UseVolatile = + // According to the AACPS: + // When a volatile bit-field is written, and its container does not overlap + // with any non-bit-field member, its container must be read exactly once + // and written exactly once using the access width appropriate to the type + // of the container. The two accesses are not atomic. + if (Dst.isVolatileQualified() && isAAPCS(CGM.getTarget()) && + CGM.getCodeGenOpts().ForceAAPCSBitfieldLoad) + llvm_unreachable("volatile bit-field is not implemented for the AACPS"); + + const CIRGenBitFieldInfo &info = Dst.getBitFieldInfo(); + mlir::Type resLTy = getTypes().convertTypeForMem(Dst.getType()); + Address ptr = Dst.getBitFieldAddress(); + + const bool useVolatile = CGM.getCodeGenOpts().AAPCSBitfieldWidth && Dst.isVolatileQualified() && - Info.VolatileStorageSize != 0 && isAAPCS(CGM.getTarget()); - const unsigned StorageSize = - UseVolatile ? Info.VolatileStorageSize : Info.StorageSize; - const unsigned Offset = UseVolatile ? Info.VolatileOffset : Info.Offset; - // See if there are other bits in the bitfield's storage we'll need to load - // and mask together with source before storing. - if (StorageSize != Info.Size) { - assert(StorageSize > Info.Size && "Invalid bitfield size."); - - mlir::Value Val = buildLoadOfScalar(Dst, Dst.getPointer().getLoc()); - - // Mask the source value as needed. - if (!hasBooleanRepresentation(Dst.getType())) - SrcVal = builder.createAnd( - SrcVal, llvm::APInt::getLowBitsSet(SrcWidth, Info.Size)); - - MaskedVal = SrcVal; - if (Offset) - SrcVal = builder.createShiftLeft(SrcVal, Offset); - - // Mask out the original value. - Val = builder.createAnd( - Val, ~llvm::APInt::getBitsSet(SrcWidth, Offset, Offset + Info.Size)); + info.VolatileStorageSize != 0 && isAAPCS(CGM.getTarget()); - // Or together the unchanged values and the source value. - SrcVal = builder.createOr(Val, SrcVal); + mlir::Value dstAddr = Dst.getAddress().getPointer(); - } else { - // According to the AACPS: - // When a volatile bit-field is written, and its container does not overlap - // with any non-bit-field member, its container must be read exactly once - // and written exactly once using the access width appropriate to the type - // of the container. The two accesses are not atomic. - if (Dst.isVolatileQualified() && isAAPCS(CGM.getTarget()) && - CGM.getCodeGenOpts().ForceAAPCSBitfieldLoad) - llvm_unreachable("volatile bit-field is not implemented for the AACPS"); - } - - // Write the new value back out. - // TODO: constant matrix type, volatile, no init, non temporal, TBAA - buildStoreOfScalar(SrcVal, Ptr, Dst.isVolatileQualified(), Dst.getType(), - Dst.getBaseInfo(), false, false); - - // Return the new value of the bit-field. - mlir::Value ResultVal = MaskedVal; - ResultVal = builder.createIntCast(ResultVal, ResLTy); - - // Sign extend the value if needed. - if (Info.IsSigned) { - assert(Info.Size <= StorageSize); - unsigned HighBits = StorageSize - Info.Size; - - if (HighBits) { - ResultVal = builder.createShiftLeft(ResultVal, HighBits); - ResultVal = builder.createShiftRight(ResultVal, HighBits); - } - } - - Result = buildFromMemory(ResultVal, Dst.getType()); + Result = builder.createSetBitfield(dstAddr.getLoc(), resLTy, dstAddr, + ptr.getElementType(), Src.getScalarVal(), + info, useVolatile); } static LValue buildGlobalVarDeclLValue(CIRGenFunction &CGF, const Expr *E, @@ -2453,9 +2378,9 @@ mlir::Value CIRGenFunction::buildLoadOfScalar(Address Addr, bool Volatile, if (isNontemporal) { llvm_unreachable("NYI"); } - - assert(!UnimplementedFeature::tbaa() && "NYI"); - assert(!UnimplementedFeature::emitScalarRangeCheck() && "NYI"); + + assert(!UnimplementedFeature::tbaa() && "NYI"); + assert(!UnimplementedFeature::emitScalarRangeCheck() && "NYI"); return buildFromMemory(Load, Ty); } diff --git a/clang/lib/CIR/CodeGen/CIRGenRecordLayout.h b/clang/lib/CIR/CodeGen/CIRGenRecordLayout.h index 0a686181db61..fc198776511e 100644 --- a/clang/lib/CIR/CodeGen/CIRGenRecordLayout.h +++ b/clang/lib/CIR/CodeGen/CIRGenRecordLayout.h @@ -91,6 +91,9 @@ struct CIRGenBitFieldInfo { /// The offset of the bitfield storage from the start of the struct. clang::CharUnits VolatileStorageOffset; + /// The name of a bitfield + llvm::StringRef Name; + CIRGenBitFieldInfo() : Offset(), Size(), IsSigned(), StorageSize(), VolatileOffset(), VolatileStorageSize() {} diff --git a/clang/lib/CIR/CodeGen/CIRRecordLayoutBuilder.cpp b/clang/lib/CIR/CodeGen/CIRRecordLayoutBuilder.cpp index fb17c7dbc3ff..1e4e26033179 100644 --- a/clang/lib/CIR/CodeGen/CIRRecordLayoutBuilder.cpp +++ b/clang/lib/CIR/CodeGen/CIRRecordLayoutBuilder.cpp @@ -228,6 +228,7 @@ void CIRRecordLowering::setBitFieldInfo(const FieldDecl *FD, Info.Size = FD->getBitWidthValue(astContext); Info.StorageSize = getSizeInBits(StorageType).getQuantity(); Info.StorageOffset = StartOffset; + Info.Name = FD->getName(); if (Info.Size > Info.StorageSize) Info.Size = Info.StorageSize; diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp index 8ec0d76226fb..1593bb046f8f 100644 --- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp +++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp @@ -10,9 +10,11 @@ #include "mlir/Dialect/Func/IR/FuncOps.h" #include "mlir/IR/BuiltinAttributes.h" #include "mlir/IR/Region.h" +#include "mlir/Transforms/DialectConversion.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Mangle.h" #include "clang/Basic/Module.h" +#include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h" #include "clang/CIR/Dialect/IR/CIRDialect.h" #include "clang/CIR/Dialect/Passes.h" #include "clang/CIR/Interfaces/ASTAttrInterfaces.h" @@ -23,8 +25,9 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Path.h" +using cir::CIRBaseBuilderTy; using namespace mlir; -using namespace cir; +using namespace mlir::cir; static SmallString<128> getTransformedFileName(ModuleOp theModule) { SmallString<128> FileName; @@ -47,36 +50,39 @@ static SmallString<128> getTransformedFileName(ModuleOp theModule) { } /// Return the FuncOp called by `callOp`. -static cir::FuncOp getCalledFunction(cir::CallOp callOp) { +static FuncOp getCalledFunction(CallOp callOp) { SymbolRefAttr sym = llvm::dyn_cast_if_present(callOp.getCallableForCallee()); if (!sym) return nullptr; - return dyn_cast_or_null( + return dyn_cast_or_null( SymbolTable::lookupNearestSymbolFrom(callOp, sym)); } namespace { + struct LoweringPreparePass : public LoweringPrepareBase { LoweringPreparePass() = default; void runOnOperation() override; void runOnOp(Operation *op); void lowerGlobalOp(GlobalOp op); + void lowerGetBitfieldOp(GetBitfieldOp op); + void lowerSetBitfieldOp(SetBitfieldOp op); /// Build the function that initializes the specified global - cir::FuncOp buildCXXGlobalVarDeclInitFunc(GlobalOp op); + FuncOp buildCXXGlobalVarDeclInitFunc(GlobalOp op); /// Build a module init function that calls all the dynamic initializers. void buildCXXGlobalInitFunc(); - cir::FuncOp + FuncOp buildRuntimeFunction(mlir::OpBuilder &builder, llvm::StringRef name, mlir::Location loc, mlir::cir::FuncType type, mlir::cir::GlobalLinkageKind linkage = mlir::cir::GlobalLinkageKind::ExternalLinkage); - cir::GlobalOp + GlobalOp buildRuntimeVariable(mlir::OpBuilder &Builder, llvm::StringRef Name, mlir::Location Loc, mlir::Type type, mlir::cir::GlobalLinkageKind Linkage = @@ -98,11 +104,11 @@ struct LoweringPreparePass : public LoweringPrepareBase { }; } // namespace -cir::GlobalOp LoweringPreparePass::buildRuntimeVariable( +GlobalOp LoweringPreparePass::buildRuntimeVariable( mlir::OpBuilder &builder, llvm::StringRef name, mlir::Location loc, mlir::Type type, mlir::cir::GlobalLinkageKind linkage) { - cir::GlobalOp g = - dyn_cast_or_null(SymbolTable::lookupNearestSymbolFrom( + GlobalOp g = + dyn_cast_or_null(SymbolTable::lookupNearestSymbolFrom( theModule, StringAttr::get(theModule->getContext(), name))); if (!g) { g = builder.create(loc, name, type); @@ -114,11 +120,11 @@ cir::GlobalOp LoweringPreparePass::buildRuntimeVariable( return g; } -cir::FuncOp LoweringPreparePass::buildRuntimeFunction( +FuncOp LoweringPreparePass::buildRuntimeFunction( mlir::OpBuilder &builder, llvm::StringRef name, mlir::Location loc, mlir::cir::FuncType type, mlir::cir::GlobalLinkageKind linkage) { - cir::FuncOp f = - dyn_cast_or_null(SymbolTable::lookupNearestSymbolFrom( + FuncOp f = + dyn_cast_or_null(SymbolTable::lookupNearestSymbolFrom( theModule, StringAttr::get(theModule->getContext(), name))); if (!f) { f = builder.create(loc, name, type); @@ -133,7 +139,7 @@ cir::FuncOp LoweringPreparePass::buildRuntimeFunction( return f; } -cir::FuncOp LoweringPreparePass::buildCXXGlobalVarDeclInitFunc(GlobalOp op) { +FuncOp LoweringPreparePass::buildCXXGlobalVarDeclInitFunc(GlobalOp op) { SmallString<256> fnName; { llvm::raw_svector_ostream Out(fnName); @@ -177,7 +183,7 @@ cir::FuncOp LoweringPreparePass::buildCXXGlobalVarDeclInitFunc(GlobalOp op) { break; } assert(dtorCall && "Expected a dtor call"); - cir::FuncOp dtorFunc = getCalledFunction(dtorCall); + FuncOp dtorFunc = getCalledFunction(dtorCall); assert(dtorFunc && mlir::isa(*dtorFunc.getAst()) && "Expected a dtor call"); @@ -297,10 +303,117 @@ void LoweringPreparePass::buildCXXGlobalInitFunc() { builder.create(f.getLoc()); } +void LoweringPreparePass::lowerGetBitfieldOp(GetBitfieldOp op) { + CIRBaseBuilderTy builder(getContext()); + builder.setInsertionPointAfter(op.getOperation()); + + auto info = op.getBitfieldInfo(); + auto size = info.getSize(); + auto storageSize = info.getStorageSize(); + auto offset = info.getOffset(); + auto resultTy = op.getType(); + auto addr = op.getAddr(); + auto loc = addr.getLoc(); + mlir::Value val = + builder.create(loc, info.getEltType(), op.getAddr()); + auto valWidth = val.getType().cast().getWidth(); + + if (info.getIsSigned()) { + assert(static_cast(offset + size) <= storageSize); + mlir::Type typ = + mlir::cir::IntType::get(builder.getContext(), valWidth, true); + + val = builder.createIntCast(val, typ); + + unsigned highBits = storageSize - offset - size; + if (highBits) + val = builder.createShiftLeft(val, highBits); + if (offset + highBits) + val = builder.createShiftRight(val, offset + highBits); + } else { + if (offset) + val = builder.createShiftRight(val, offset); + + if (static_cast(offset) + size < storageSize) + val = builder.createAnd(val, llvm::APInt::getLowBitsSet(valWidth, size)); + } + val = builder.createIntCast(val, resultTy); + + ConversionPatternRewriter rewriter(&getContext()); + rewriter.replaceAllUsesWith(op, val); + op.erase(); +} + +void LoweringPreparePass::lowerSetBitfieldOp(SetBitfieldOp op) { + CIRBaseBuilderTy builder(getContext()); + builder.setInsertionPointAfter(op.getOperation()); + + auto srcVal = op.getSrc(); + auto addr = op.getDst(); + auto info = op.getBitfieldInfo(); + auto size = info.getSize(); + auto storageSize = info.getStorageSize(); + auto offset = info.getOffset(); + auto resultTy = op.getType(); + auto loc = addr.getLoc(); + + // Get the source value, truncated to the width of the bit-field. + srcVal = builder.createIntCast(op.getSrc(), info.getEltType()); + auto srcWidth = srcVal.getType().cast().getWidth(); + + mlir::Value maskedVal = srcVal; + + if (storageSize != size) { + assert(storageSize > size && "Invalid bitfield size."); + + mlir::Value val = + builder.create(loc, info.getEltType(), addr); + + srcVal = + builder.createAnd(srcVal, llvm::APInt::getLowBitsSet(srcWidth, size)); + + maskedVal = srcVal; + if (offset) + srcVal = builder.createShiftLeft(srcVal, offset); + + // Mask out the original value. + val = builder.createAnd(val, + ~llvm::APInt::getBitsSet(srcWidth, offset, offset + size)); + + // Or together the unchanged values and the source value. + srcVal = builder.createOr(val, srcVal); + } + + builder.create(loc, srcVal, addr); + + if (!op->getUses().empty()) { + mlir::Value resultVal = maskedVal; + resultVal = builder.createIntCast(resultVal, resultTy); + + if (info.getIsSigned()) { + assert(size <= storageSize); + unsigned highBits = storageSize - size; + + if (highBits) { + resultVal = builder.createShiftLeft(resultVal, highBits); + resultVal = builder.createShiftRight(resultVal, highBits); + } + } + + ConversionPatternRewriter rewriter(&getContext()); + rewriter.replaceAllUsesWith(op, resultVal); + } + + op.erase(); +} + void LoweringPreparePass::runOnOp(Operation *op) { - if (GlobalOp globalOp = cast(op)) { - lowerGlobalOp(globalOp); - return; + if (auto getGlobal = dyn_cast(op)) { + lowerGlobalOp(getGlobal); + } else if (auto getBitfield = dyn_cast(op)) { + //lowerGetBitfieldOp(getBitfield); + } else if (auto setBitfield = dyn_cast(op)) { + //lowerSetBitfieldOp(setBitfield); } } @@ -315,6 +428,10 @@ void LoweringPreparePass::runOnOperation() { op->walk([&](Operation *op) { if (isa(op)) opsToTransform.push_back(op); + if (isa(op)) + opsToTransform.push_back(op); + if (isa(op)) + opsToTransform.push_back(op); }); for (auto *o : opsToTransform) { From e29967aa658dfa50cd44d6f312306dd021beedd5 Mon Sep 17 00:00:00 2001 From: gitoleg Date: Mon, 30 Oct 2023 15:07:12 +0300 Subject: [PATCH 02/15] minor fix --- clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp index 1593bb046f8f..47df7c452ac0 100644 --- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp +++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp @@ -411,9 +411,9 @@ void LoweringPreparePass::runOnOp(Operation *op) { if (auto getGlobal = dyn_cast(op)) { lowerGlobalOp(getGlobal); } else if (auto getBitfield = dyn_cast(op)) { - //lowerGetBitfieldOp(getBitfield); + lowerGetBitfieldOp(getBitfield); } else if (auto setBitfield = dyn_cast(op)) { - //lowerSetBitfieldOp(setBitfield); + lowerSetBitfieldOp(setBitfield); } } From 468e5fcdef066a0e3bb13441bb5645a66adc25d9 Mon Sep 17 00:00:00 2001 From: gitoleg Date: Mon, 30 Oct 2023 15:13:33 +0300 Subject: [PATCH 03/15] minor fix --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 2e6badea5196..73f8757047b9 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -1433,7 +1433,7 @@ def SetBitfieldOp : CIR_Op<"set_bitfield"> { Example: ```mlir // Suppose we have a struct with multiple bitfields stored in - // different storages. The `cir.get_bitfield` operation gets the value + // different storages. The `cir.set_bitfield` operation sets the value // of the bitfield // Sets the bitfield with name a1. From e311b51ec91c3565188b3a48551be40301b1826d Mon Sep 17 00:00:00 2001 From: gitoleg Date: Thu, 2 Nov 2023 15:18:14 +0300 Subject: [PATCH 04/15] tests added --- .../include/clang/CIR/Dialect/IR/CIRAttrs.td | 23 ++++++--------- clang/include/clang/CIR/Dialect/IR/CIROps.td | 10 +++++-- .../CIR/CodeGen/CIRRecordLayoutBuilder.cpp | 2 +- clang/test/CIR/CodeGen/bitfield-ops.c | 29 +++++++++++++++++++ 4 files changed, 47 insertions(+), 17 deletions(-) create mode 100644 clang/test/CIR/CodeGen/bitfield-ops.c diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td index 81cca3023b80..354284f68f92 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td @@ -522,30 +522,25 @@ def GlobalCtorAttr : CIR_Attr<"GlobalCtor", "globalCtor"> { let skipDefaultBuilders = 1; } -def BitfieldInfoAttr : CIR_Attr<"BitfieldInfo", "bitfieldInfo"> { +def BitfieldInfoAttr : CIR_Attr<"BitfieldInfo", "bitfield_info"> { let parameters = (ins "StringAttr":$name, - "Type":$eltType, - "uint64_t":$storageSize, + "Type":$elt_type, + "uint64_t":$storage_size, "uint64_t":$size, "uint64_t":$offset, - "bool":$isSigned); + "bool":$is_signed); - let assemblyFormat = [{ `<` - `(` `name` `=` $name `)` - `(` `size` $size `)` - `(` `storage` $eltType $storageSize `)` - `(` `offset` $offset `)` - `(` `signed` `=` $isSigned `)` `>` }]; + let assemblyFormat = "`<` struct($name, $elt_type, $storage_size, $size, $offset, $is_signed) `>`"; let builders = [ AttrBuilder<(ins "StringRef":$name, - "Type":$eltType, - "uint64_t":$storageSize, + "Type":$elt_type, + "uint64_t":$storage_size, "uint64_t":$size, "uint64_t":$offset, - "bool":$isSigned + "bool":$is_signed ), [{ - return $_get($_ctxt, StringAttr::get($_ctxt, name), eltType, storageSize, size, offset, isSigned); + return $_get($_ctxt, StringAttr::get($_ctxt, name), elt_type, storage_size, size, offset, is_signed); }]> ]; } diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 73f8757047b9..b9fd98e8fe59 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -1436,8 +1436,8 @@ def SetBitfieldOp : CIR_Op<"set_bitfield"> { // different storages. The `cir.set_bitfield` operation sets the value // of the bitfield - // Sets the bitfield with name a1. - %6 = "cir.set_bitfield"(%5, %3) <{BitfieldInfo = #cir.bitfieldInfo<(name = "a1") (size 4) (storage !u64i 64) (offset 0) (signed = true)>}> : (!cir.ptr, !s32i) -> !s32i + // Sets the bitfield with name a1 + %3 = cir.set_bitfield %1, %2() : (!s32i, !cir.ptr) -> !s32i ``` }]; @@ -1449,6 +1449,9 @@ def SetBitfieldOp : CIR_Op<"set_bitfield"> { let results = (outs CIR_IntType:$result); + let assemblyFormat = [{ $src `,` $dst`(`$BitfieldInfo`)` attr-dict `:` + `(` type($src) `,` type($dst) `)` `->` type($result) }]; + let builders = [ OpBuilder<(ins "Type":$type, "Value":$dst, @@ -1499,6 +1502,9 @@ def GetBitfieldOp : CIR_Op<"get_bitfield"> { let results = (outs CIR_IntType:$result); + let assemblyFormat = [{ $addr`(`$BitfieldInfo`)` attr-dict `:` + type($addr) `->` type($result) }]; + let builders = [ OpBuilder<(ins "Type":$type, "Value":$addr, diff --git a/clang/lib/CIR/CodeGen/CIRRecordLayoutBuilder.cpp b/clang/lib/CIR/CodeGen/CIRRecordLayoutBuilder.cpp index ace19a3e326f..be4c7db760d4 100644 --- a/clang/lib/CIR/CodeGen/CIRRecordLayoutBuilder.cpp +++ b/clang/lib/CIR/CodeGen/CIRRecordLayoutBuilder.cpp @@ -227,7 +227,7 @@ void CIRRecordLowering::setBitFieldInfo(const FieldDecl *FD, (unsigned)(getFieldBitOffset(FD) - astContext.toBits(StartOffset)); Info.Size = FD->getBitWidthValue(astContext); Info.StorageSize = getSizeInBits(StorageType).getQuantity(); - Info.StorageOffset = StartOffset; + Info.StorageOffset = StartOffset; Info.Name = FD->getName(); if (Info.Size > Info.StorageSize) diff --git a/clang/test/CIR/CodeGen/bitfield-ops.c b/clang/test/CIR/CodeGen/bitfield-ops.c new file mode 100644 index 000000000000..e4c4ddd43a79 --- /dev/null +++ b/clang/test/CIR/CodeGen/bitfield-ops.c @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir-enable -emit-cir -mmlir --mlir-print-ir-before=cir-lowering-prepare %s -o %t.cir 2>&1 | FileCheck %s -check-prefix=BEFORE + +typedef struct { + int a : 4; + int b : 27; + int c : 17; + int d : 2; + int e : 15; + unsigned f; // type other than int above, not a bitfield +} S; + +// BEFORE: cir.func {{.*@store_field}} +// BEFORE: [[TMP0:%.*]] = cir.alloca !ty_22S22, cir.ptr , ["s"] +// BEFORE: [[TMP1:%.*]] = cir.const(#cir.int<3> : !s32i) : !s32i +// BEFORE: [[TMP2:%.*]] = cir.get_member [[TMP0]][2] {name = "e"} : !cir.ptr -> !cir.ptr +// BEFORE: [[TMP3:%.*]] = cir.set_bitfield [[TMP1]], [[TMP2]]() : (!s32i, !cir.ptr) -> !s32i +void store_field() { + S s; + s.e = 3; +} + +// BEFORE: cir.func {{.*@load_field}} +// BEFORE: [[TMP0:%.*]] = cir.alloca !cir.ptr, cir.ptr >, ["s", init] +// BEFORE: [[TMP1:%.*]] = cir.load [[TMP0]] : cir.ptr >, !cir.ptr +// BEFORE: [[TMP2:%.*]] = cir.get_member [[TMP1]][1] {name = "d"} : !cir.ptr -> !cir.ptr +// BEFORE: [[TMP3:%.*]] = cir.get_bitfield [[TMP2]]() : !cir.ptr -> !s32i +int load_field(S* s) { + return s->d; +} \ No newline at end of file From 3405bb8876576257d08c60fe8e6c822e0989b724 Mon Sep 17 00:00:00 2001 From: gitoleg Date: Thu, 2 Nov 2023 16:15:45 +0300 Subject: [PATCH 05/15] use alias --- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 4 ++++ clang/test/CIR/CodeGen/bitfield-ops.c | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 35a194df22f1..8eddfaf638e8 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -78,6 +78,10 @@ struct CIROpAsmDialectInterface : public OpAsmDialectInterface { os << (boolAttr.getValue() ? "true" : "false"); return AliasResult::FinalAlias; } + if (auto bitfield = attr.dyn_cast()) { + os << bitfield.getName().str(); + return AliasResult::FinalAlias; + } return AliasResult::NoAlias; } diff --git a/clang/test/CIR/CodeGen/bitfield-ops.c b/clang/test/CIR/CodeGen/bitfield-ops.c index e4c4ddd43a79..50e485f6e36c 100644 --- a/clang/test/CIR/CodeGen/bitfield-ops.c +++ b/clang/test/CIR/CodeGen/bitfield-ops.c @@ -6,14 +6,14 @@ typedef struct { int c : 17; int d : 2; int e : 15; - unsigned f; // type other than int above, not a bitfield + unsigned f; } S; // BEFORE: cir.func {{.*@store_field}} // BEFORE: [[TMP0:%.*]] = cir.alloca !ty_22S22, cir.ptr , ["s"] // BEFORE: [[TMP1:%.*]] = cir.const(#cir.int<3> : !s32i) : !s32i // BEFORE: [[TMP2:%.*]] = cir.get_member [[TMP0]][2] {name = "e"} : !cir.ptr -> !cir.ptr -// BEFORE: [[TMP3:%.*]] = cir.set_bitfield [[TMP1]], [[TMP2]]() : (!s32i, !cir.ptr) -> !s32i +// BEFORE: [[TMP3:%.*]] = cir.set_bitfield [[TMP1]], [[TMP2]](#e) : (!s32i, !cir.ptr) -> !s32i void store_field() { S s; s.e = 3; @@ -23,7 +23,7 @@ void store_field() { // BEFORE: [[TMP0:%.*]] = cir.alloca !cir.ptr, cir.ptr >, ["s", init] // BEFORE: [[TMP1:%.*]] = cir.load [[TMP0]] : cir.ptr >, !cir.ptr // BEFORE: [[TMP2:%.*]] = cir.get_member [[TMP1]][1] {name = "d"} : !cir.ptr -> !cir.ptr -// BEFORE: [[TMP3:%.*]] = cir.get_bitfield [[TMP2]]() : !cir.ptr -> !s32i +// BEFORE: [[TMP3:%.*]] = cir.get_bitfield [[TMP2]](#d) : !cir.ptr -> !s32i int load_field(S* s) { return s->d; } \ No newline at end of file From b387dae47e22af6fbe23ba2ba1702f18e2fbb0e2 Mon Sep 17 00:00:00 2001 From: gitoleg Date: Tue, 7 Nov 2023 09:55:45 +0300 Subject: [PATCH 06/15] fixed examples --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 69 +++++++++++++------- 1 file changed, 44 insertions(+), 25 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index b9fd98e8fe59..704e2ed23bd7 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -1430,41 +1430,51 @@ def SetBitfieldOp : CIR_Op<"set_bitfield"> { base record, a size of the storage, a size the bit field, an offset of the bit field and a sign. Returns a value being stored. - Example: - ```mlir - // Suppose we have a struct with multiple bitfields stored in - // different storages. The `cir.set_bitfield` operation sets the value - // of the bitfield + Example. + Suppose we have a struct with multiple bitfields stored in + different storages. The `cir.set_bitfield` operation sets the value + of the bitfield. + ```C++ + void store_bitfield(S& s) { + s.d = 3; + } + ``` - // Sets the bitfield with name a1 - %3 = cir.set_bitfield %1, %2() : (!s32i, !cir.ptr) -> !s32i + ```mlir + %1 = cir.const(#cir.int<3> : !s32i) : !s32i + %2 = cir.load %0 : cir.ptr >, !cir.ptr + %3 = cir.get_member %2[1] {name = "d"} : !cir.ptr -> !cir.ptr + %4 = cir.set_bitfield %1, %3(#d) : (!s32i, !cir.ptr) -> !s32i ``` }]; let arguments = (ins AnyType:$dst, AnyType:$src, - BitfieldInfoAttr:$BitfieldInfo + BitfieldInfoAttr:$bitfield_info ); let results = (outs CIR_IntType:$result); - let assemblyFormat = [{ $src `,` $dst`(`$BitfieldInfo`)` attr-dict `:` + let assemblyFormat = [{ $src `,` $dst`(`$bitfield_info`)` attr-dict `:` `(` type($src) `,` type($dst) `)` `->` type($result) }]; let builders = [ OpBuilder<(ins "Type":$type, "Value":$dst, - "Type":$eltType, + "Type":$elt_type, "Value":$src, "StringRef":$name, - "unsigned":$storageSize, + "unsigned":$storage_size, "unsigned":$size, "unsigned":$offset, - "bool":$isSigned + "bool":$is_signed ), [{ - BitfieldInfoAttr info = BitfieldInfoAttr::get($_builder.getContext(), name, eltType, storageSize, size, offset, isSigned); + BitfieldInfoAttr info = + BitfieldInfoAttr::get($_builder.getContext(), + name, elt_type, storage_size, + size, offset, is_signed); build($_builder, $_state, type, dst, src, info); }]> ]; @@ -1485,38 +1495,47 @@ def GetBitfieldOp : CIR_Op<"get_bitfield"> { of the bit field and a sign. Example: - ```mlir - // Suppose we have a struct with multiple bitfields stored in - // different storages. The `cir.get_bitfield` operation gets the value - // of the bitfield + Suppose we have a struct with multiple bitfields stored in + different storages. The `cir.get_bitfield` operation gets the value + of the bitfield + ```C++ + int load_bitfield(S& s) { + return s.d; + } + ``` - // Get the address of the bitfield with name a1. - %6 = "cir.get_bitfield"(%5) <{BitfieldInfo = #cir.bitfieldInfo<(name = "a1") (size 4) (storage !u64i 64) (offset 0) (signed = true)>}> : (!cir.ptr) -> !s32i + ```mlir + %2 = cir.load %0 : cir.ptr >, !cir.ptr + %3 = cir.get_member %2[1] {name = "d"} : !cir.ptr -> !cir.ptr + %4 = cir.get_bitfield %3(#d) : !cir.ptr -> !s32i ``` }]; let arguments = (ins AnyType:$addr, - BitfieldInfoAttr:$BitfieldInfo + BitfieldInfoAttr:$bitfield_info ); let results = (outs CIR_IntType:$result); - let assemblyFormat = [{ $addr`(`$BitfieldInfo`)` attr-dict `:` + let assemblyFormat = [{ $addr`(`$bitfield_info`)` attr-dict `:` type($addr) `->` type($result) }]; let builders = [ OpBuilder<(ins "Type":$type, "Value":$addr, - "Type":$eltType, + "Type":$elt_type, "StringRef":$name, - "unsigned":$storageSize, + "unsigned":$storage_size, "unsigned":$size, "unsigned":$offset, - "bool":$isSigned + "bool":$is_signed ), [{ - BitfieldInfoAttr info = BitfieldInfoAttr::get($_builder.getContext(), name, eltType, storageSize, size, offset, isSigned); + BitfieldInfoAttr info = + BitfieldInfoAttr::get($_builder.getContext(), + name, elt_type, storage_size, + size, offset, is_signed); build($_builder, $_state, type, addr, info); }]> ]; From 87264d10bbf416e081bb2586727fa5d11afb3f80 Mon Sep 17 00:00:00 2001 From: gitoleg Date: Tue, 7 Nov 2023 10:46:22 +0300 Subject: [PATCH 07/15] removes storage_size from ops --- clang/include/clang/CIR/Dialect/IR/CIRAttrs.td | 10 ++++------ clang/include/clang/CIR/Dialect/IR/CIROps.td | 10 ++++------ clang/lib/CIR/CodeGen/CIRGenBuilder.h | 8 ++------ clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp | 12 +++++++----- 4 files changed, 17 insertions(+), 23 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td index 354284f68f92..eacb99b5b1df 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td @@ -524,23 +524,21 @@ def GlobalCtorAttr : CIR_Attr<"GlobalCtor", "globalCtor"> { def BitfieldInfoAttr : CIR_Attr<"BitfieldInfo", "bitfield_info"> { let parameters = (ins "StringAttr":$name, - "Type":$elt_type, - "uint64_t":$storage_size, + "Type":$storage_type, "uint64_t":$size, "uint64_t":$offset, "bool":$is_signed); - let assemblyFormat = "`<` struct($name, $elt_type, $storage_size, $size, $offset, $is_signed) `>`"; + let assemblyFormat = "`<` struct($name, $storage_type, $size, $offset, $is_signed) `>`"; let builders = [ AttrBuilder<(ins "StringRef":$name, - "Type":$elt_type, - "uint64_t":$storage_size, + "Type":$storage_type, "uint64_t":$size, "uint64_t":$offset, "bool":$is_signed ), [{ - return $_get($_ctxt, StringAttr::get($_ctxt, name), elt_type, storage_size, size, offset, is_signed); + return $_get($_ctxt, StringAttr::get($_ctxt, name), storage_type, size, offset, is_signed); }]> ]; } diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 704e2ed23bd7..759af0c96743 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -1462,10 +1462,9 @@ def SetBitfieldOp : CIR_Op<"set_bitfield"> { let builders = [ OpBuilder<(ins "Type":$type, "Value":$dst, - "Type":$elt_type, + "Type":$storage_type, "Value":$src, "StringRef":$name, - "unsigned":$storage_size, "unsigned":$size, "unsigned":$offset, "bool":$is_signed @@ -1473,7 +1472,7 @@ def SetBitfieldOp : CIR_Op<"set_bitfield"> { [{ BitfieldInfoAttr info = BitfieldInfoAttr::get($_builder.getContext(), - name, elt_type, storage_size, + name, storage_type, size, offset, is_signed); build($_builder, $_state, type, dst, src, info); }]> @@ -1524,9 +1523,8 @@ def GetBitfieldOp : CIR_Op<"get_bitfield"> { let builders = [ OpBuilder<(ins "Type":$type, "Value":$addr, - "Type":$elt_type, + "Type":$storage_type, "StringRef":$name, - "unsigned":$storage_size, "unsigned":$size, "unsigned":$offset, "bool":$is_signed @@ -1534,7 +1532,7 @@ def GetBitfieldOp : CIR_Op<"get_bitfield"> { [{ BitfieldInfoAttr info = BitfieldInfoAttr::get($_builder.getContext(), - name, elt_type, storage_size, + name, storage_type, size, offset, is_signed); build($_builder, $_state, type, addr, info); }]> diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h index 83b3ef7b77a2..7a4efa51e13d 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h @@ -641,10 +641,8 @@ class CIRGenBuilderTy : public CIRBaseBuilderTy { const CIRGenBitFieldInfo &info, bool useVolatile) { auto offset = useVolatile ? info.VolatileOffset : info.Offset; - auto storageSize = - useVolatile ? info.VolatileStorageSize : info.StorageSize; return create(loc, resultType, addr, eltType, - info.Name, storageSize, info.Size, + info.Name, info.Size, offset, info.IsSigned); } @@ -652,11 +650,9 @@ class CIRGenBuilderTy : public CIRBaseBuilderTy { mlir::Value dstAddr, mlir::Type eltType, mlir::Value src, const CIRGenBitFieldInfo &info, bool useVolatile) { - auto storageSize = - useVolatile ? info.VolatileStorageSize : info.StorageSize; auto offset = useVolatile ? info.VolatileOffset : info.Offset; return create( - loc, resultType, dstAddr, eltType, src, info.Name, storageSize, + loc, resultType, dstAddr, eltType, src, info.Name, info.Size, offset, info.IsSigned); } diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp index 47df7c452ac0..0fe94c091ab3 100644 --- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp +++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp @@ -309,13 +309,14 @@ void LoweringPreparePass::lowerGetBitfieldOp(GetBitfieldOp op) { auto info = op.getBitfieldInfo(); auto size = info.getSize(); - auto storageSize = info.getStorageSize(); + auto storageType = info.getStorageType(); + auto storageSize = storageType.cast().getWidth(); auto offset = info.getOffset(); auto resultTy = op.getType(); auto addr = op.getAddr(); auto loc = addr.getLoc(); mlir::Value val = - builder.create(loc, info.getEltType(), op.getAddr()); + builder.create(loc, storageType, op.getAddr()); auto valWidth = val.getType().cast().getWidth(); if (info.getIsSigned()) { @@ -352,13 +353,14 @@ void LoweringPreparePass::lowerSetBitfieldOp(SetBitfieldOp op) { auto addr = op.getDst(); auto info = op.getBitfieldInfo(); auto size = info.getSize(); - auto storageSize = info.getStorageSize(); + auto storageType = info.getStorageType(); + auto storageSize = storageType.cast().getWidth(); auto offset = info.getOffset(); auto resultTy = op.getType(); auto loc = addr.getLoc(); // Get the source value, truncated to the width of the bit-field. - srcVal = builder.createIntCast(op.getSrc(), info.getEltType()); + srcVal = builder.createIntCast(op.getSrc(), storageType); auto srcWidth = srcVal.getType().cast().getWidth(); mlir::Value maskedVal = srcVal; @@ -367,7 +369,7 @@ void LoweringPreparePass::lowerSetBitfieldOp(SetBitfieldOp op) { assert(storageSize > size && "Invalid bitfield size."); mlir::Value val = - builder.create(loc, info.getEltType(), addr); + builder.create(loc, storageType, addr); srcVal = builder.createAnd(srcVal, llvm::APInt::getLowBitsSet(srcWidth, size)); From aa526cf9faaad8e8ef364a0410cf4e0ab92140f3 Mon Sep 17 00:00:00 2001 From: gitoleg Date: Tue, 7 Nov 2023 11:13:50 +0300 Subject: [PATCH 08/15] fixed description --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 759af0c96743..964ffa29c375 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -1425,8 +1425,8 @@ def SetBitfieldOp : CIR_Op<"set_bitfield"> { The `cir.set_bitfield` operation provides a store-like access to a bit field of a record. - It expects an address of a storage where to store, a value being stored, - a type of a bitfield, a name of a bit field, a pointer to a storage in the + It expects an address of a storage where to store, a type of the storage, + a value being stored, a name of a bit field, a pointer to the storage in the base record, a size of the storage, a size the bit field, an offset of the bit field and a sign. Returns a value being stored. @@ -1490,8 +1490,8 @@ def GetBitfieldOp : CIR_Op<"get_bitfield"> { a bit field of a record. It expects a name if a bit field, a pointer to a storage in the - base record, a size of the storage, a size the bit field, an offset - of the bit field and a sign. + 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. Example: Suppose we have a struct with multiple bitfields stored in From 44d770415edc0463f21e438aadcc5d30e49f1e4e Mon Sep 17 00:00:00 2001 From: gitoleg Date: Tue, 7 Nov 2023 11:19:29 +0300 Subject: [PATCH 09/15] minor changes --- clang/lib/CIR/CodeGen/CIRGenBuilder.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h index 7a4efa51e13d..b15cafd794db 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h @@ -637,22 +637,22 @@ class CIRGenBuilderTy : public CIRBaseBuilderTy { } mlir::Value createGetBitfield(mlir::Location loc, mlir::Type resultType, - mlir::Value addr, mlir::Type eltType, + mlir::Value addr, mlir::Type storageType, const CIRGenBitFieldInfo &info, bool useVolatile) { auto offset = useVolatile ? info.VolatileOffset : info.Offset; - return create(loc, resultType, addr, eltType, + return create(loc, resultType, addr, storageType, info.Name, info.Size, offset, info.IsSigned); } mlir::Value createSetBitfield(mlir::Location loc, mlir::Type resultType, - mlir::Value dstAddr, mlir::Type eltType, + mlir::Value dstAddr, mlir::Type storageType, mlir::Value src, const CIRGenBitFieldInfo &info, bool useVolatile) { auto offset = useVolatile ? info.VolatileOffset : info.Offset; return create( - loc, resultType, dstAddr, eltType, src, info.Name, + loc, resultType, dstAddr, storageType, src, info.Name, info.Size, offset, info.IsSigned); } From f0edec38a8f15f6cd79819acc041531d2987433b Mon Sep 17 00:00:00 2001 From: gitoleg Date: Tue, 7 Nov 2023 16:41:44 +0300 Subject: [PATCH 10/15] don't create ConversionPatternRewriter to replace uses --- clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp index 0fe94c091ab3..92a7137e8e40 100644 --- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp +++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp @@ -10,7 +10,6 @@ #include "mlir/Dialect/Func/IR/FuncOps.h" #include "mlir/IR/BuiltinAttributes.h" #include "mlir/IR/Region.h" -#include "mlir/Transforms/DialectConversion.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Mangle.h" #include "clang/Basic/Module.h" @@ -340,8 +339,7 @@ void LoweringPreparePass::lowerGetBitfieldOp(GetBitfieldOp op) { } val = builder.createIntCast(val, resultTy); - ConversionPatternRewriter rewriter(&getContext()); - rewriter.replaceAllUsesWith(op, val); + op.replaceAllUsesWith(val); op.erase(); } @@ -402,8 +400,7 @@ void LoweringPreparePass::lowerSetBitfieldOp(SetBitfieldOp op) { } } - ConversionPatternRewriter rewriter(&getContext()); - rewriter.replaceAllUsesWith(op, resultVal); + op.replaceAllUsesWith(resultVal); } op.erase(); From adf86b3b9b7282b7fed26ad945ff7768fc58ba1c Mon Sep 17 00:00:00 2001 From: gitoleg Date: Wed, 15 Nov 2023 11:44:54 +0300 Subject: [PATCH 11/15] minor changes after review --- .../include/clang/CIR/Dialect/IR/CIRAttrs.td | 5 ++++ clang/include/clang/CIR/Dialect/IR/CIROps.td | 22 +++++++++++++++ clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 2 +- clang/test/CIR/CodeGen/bitfield-ops.c | 27 ++++++++++--------- 4 files changed, 42 insertions(+), 14 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td index eacb99b5b1df..f385051d254b 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td @@ -523,6 +523,11 @@ def GlobalCtorAttr : CIR_Attr<"GlobalCtor", "globalCtor"> { } 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 "StringAttr":$name, "Type":$storage_type, "uint64_t":$size, diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 964ffa29c375..45661ba85892 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -1435,12 +1435,23 @@ def SetBitfieldOp : CIR_Op<"set_bitfield"> { different storages. The `cir.set_bitfield` operation sets the value of the bitfield. ```C++ + typedef struct { + int a : 4; + int b : 27; + int c : 17; + int d : 2; + int e : 15; + } S; + void store_bitfield(S& s) { s.d = 3; } ``` ```mlir + // 'd' is in the storage with the index 1 + !ty_22S22 = !cir.struct, !cir.int, !cir.int, !cir.int} #cir.record.decl.ast> + %1 = cir.const(#cir.int<3> : !s32i) : !s32i %2 = cir.load %0 : cir.ptr >, !cir.ptr %3 = cir.get_member %2[1] {name = "d"} : !cir.ptr -> !cir.ptr @@ -1498,12 +1509,23 @@ def GetBitfieldOp : CIR_Op<"get_bitfield"> { 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.d; } ``` ```mlir + // 'd' is in the storage with the index 1 + !ty_22S22 = !cir.struct, !cir.int, !cir.int, !cir.int} #cir.record.decl.ast> + %2 = cir.load %0 : cir.ptr >, !cir.ptr %3 = cir.get_member %2[1] {name = "d"} : !cir.ptr -> !cir.ptr %4 = cir.get_bitfield %3(#d) : !cir.ptr -> !s32i diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 8eddfaf638e8..9e11070d9182 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -79,7 +79,7 @@ struct CIROpAsmDialectInterface : public OpAsmDialectInterface { return AliasResult::FinalAlias; } if (auto bitfield = attr.dyn_cast()) { - os << bitfield.getName().str(); + os << "bfi_" << bitfield.getName().str(); return AliasResult::FinalAlias; } diff --git a/clang/test/CIR/CodeGen/bitfield-ops.c b/clang/test/CIR/CodeGen/bitfield-ops.c index 50e485f6e36c..f27934ae7b73 100644 --- a/clang/test/CIR/CodeGen/bitfield-ops.c +++ b/clang/test/CIR/CodeGen/bitfield-ops.c @@ -1,29 +1,30 @@ -// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir-enable -emit-cir -mmlir --mlir-print-ir-before=cir-lowering-prepare %s -o %t.cir 2>&1 | FileCheck %s -check-prefix=BEFORE +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir-enable -emit-cir -mmlir --mlir-print-ir-before=cir-lowering-prepare %s -o - 2>&1 | FileCheck %s +// CHECK: !ty_22S22 = !cir.struct, !cir.int, !cir.int, !cir.int} #cir.record.decl.ast> typedef struct { int a : 4; int b : 27; int c : 17; int d : 2; int e : 15; - unsigned f; -} S; + unsigned f; +} S; -// BEFORE: cir.func {{.*@store_field}} -// BEFORE: [[TMP0:%.*]] = cir.alloca !ty_22S22, cir.ptr , ["s"] -// BEFORE: [[TMP1:%.*]] = cir.const(#cir.int<3> : !s32i) : !s32i -// BEFORE: [[TMP2:%.*]] = cir.get_member [[TMP0]][2] {name = "e"} : !cir.ptr -> !cir.ptr -// BEFORE: [[TMP3:%.*]] = cir.set_bitfield [[TMP1]], [[TMP2]](#e) : (!s32i, !cir.ptr) -> !s32i +// CHECK: cir.func {{.*@store_field}} +// CHECK: [[TMP0:%.*]] = cir.alloca !ty_22S22, cir.ptr , ["s"] +// CHECK: [[TMP1:%.*]] = cir.const(#cir.int<3> : !s32i) : !s32i +// CHECK: [[TMP2:%.*]] = cir.get_member [[TMP0]][2] {name = "e"} : !cir.ptr -> !cir.ptr +// CHECK: [[TMP3:%.*]] = cir.set_bitfield [[TMP1]], [[TMP2]](#bfi_e) : (!s32i, !cir.ptr) -> !s32i void store_field() { S s; s.e = 3; } -// BEFORE: cir.func {{.*@load_field}} -// BEFORE: [[TMP0:%.*]] = cir.alloca !cir.ptr, cir.ptr >, ["s", init] -// BEFORE: [[TMP1:%.*]] = cir.load [[TMP0]] : cir.ptr >, !cir.ptr -// BEFORE: [[TMP2:%.*]] = cir.get_member [[TMP1]][1] {name = "d"} : !cir.ptr -> !cir.ptr -// BEFORE: [[TMP3:%.*]] = cir.get_bitfield [[TMP2]](#d) : !cir.ptr -> !s32i +// CHECK: cir.func {{.*@load_field}} +// CHECK: [[TMP0:%.*]] = cir.alloca !cir.ptr, cir.ptr >, ["s", init] +// CHECK: [[TMP1:%.*]] = cir.load [[TMP0]] : cir.ptr >, !cir.ptr +// CHECK: [[TMP2:%.*]] = cir.get_member [[TMP1]][1] {name = "d"} : !cir.ptr -> !cir.ptr +// CHECK: [[TMP3:%.*]] = cir.get_bitfield [[TMP2]](#bfi_d) : !cir.ptr -> !s32i int load_field(S* s) { return s->d; } \ No newline at end of file From 508610f3e50f04109ffec419f6b57ee4aa020309 Mon Sep 17 00:00:00 2001 From: gitoleg Date: Thu, 16 Nov 2023 11:46:04 +0300 Subject: [PATCH 12/15] a couple of minor changes --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 18 ++++++++++-------- clang/test/CIR/CodeGen/bitfield-ops.c | 3 +++ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 45661ba85892..9c381568332f 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -1450,12 +1450,13 @@ def SetBitfieldOp : CIR_Op<"set_bitfield"> { ```mlir // 'd' is in the storage with the index 1 - !ty_22S22 = !cir.struct, !cir.int, !cir.int, !cir.int} #cir.record.decl.ast> + !struct_type = !cir.struct, !cir.int, !cir.int} #cir.record.decl.ast> + #bfi_d = #cir.bitfield_info %1 = cir.const(#cir.int<3> : !s32i) : !s32i - %2 = cir.load %0 : cir.ptr >, !cir.ptr - %3 = cir.get_member %2[1] {name = "d"} : !cir.ptr -> !cir.ptr - %4 = cir.set_bitfield %1, %3(#d) : (!s32i, !cir.ptr) -> !s32i + %2 = cir.load %0 : cir.ptr >, !cir.ptr + %3 = cir.get_member %2[1] {name = "d"} : !cir.ptr -> !cir.ptr + %4 = cir.set_bitfield %1, %3(#bfi_d) : (!s32i, !cir.ptr) -> !s32i ``` }]; @@ -1524,11 +1525,12 @@ def GetBitfieldOp : CIR_Op<"get_bitfield"> { ```mlir // 'd' is in the storage with the index 1 - !ty_22S22 = !cir.struct, !cir.int, !cir.int, !cir.int} #cir.record.decl.ast> + !struct_type = !cir.struct, !cir.int, !cir.int} #cir.record.decl.ast> + #bfi_d = #cir.bitfield_info - %2 = cir.load %0 : cir.ptr >, !cir.ptr - %3 = cir.get_member %2[1] {name = "d"} : !cir.ptr -> !cir.ptr - %4 = cir.get_bitfield %3(#d) : !cir.ptr -> !s32i + %2 = cir.load %0 : cir.ptr >, !cir.ptr + %3 = cir.get_member %2[1] {name = "d"} : !cir.ptr -> !cir.ptr + %4 = cir.get_bitfield %3(#bfi_d) : !cir.ptr -> !s32i ``` }]; diff --git a/clang/test/CIR/CodeGen/bitfield-ops.c b/clang/test/CIR/CodeGen/bitfield-ops.c index f27934ae7b73..8e296dcf8c05 100644 --- a/clang/test/CIR/CodeGen/bitfield-ops.c +++ b/clang/test/CIR/CodeGen/bitfield-ops.c @@ -10,6 +10,9 @@ typedef struct { unsigned f; } S; +// CHECK: #bfi_d = #cir.bitfield_info +// CHECK: #bfi_e = #cir.bitfield_info + // CHECK: cir.func {{.*@store_field}} // CHECK: [[TMP0:%.*]] = cir.alloca !ty_22S22, cir.ptr , ["s"] // CHECK: [[TMP1:%.*]] = cir.const(#cir.int<3> : !s32i) : !s32i From ca83f19cd9dce5f9756469e79492ec4014e9d4a5 Mon Sep 17 00:00:00 2001 From: gitoleg Date: Mon, 20 Nov 2023 11:09:16 +0300 Subject: [PATCH 13/15] changed asm output --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 8 ++++---- clang/test/CIR/CodeGen/bitfield-ops.c | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index c4e29566408d..9bb066c56620 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -1457,7 +1457,7 @@ def SetBitfieldOp : CIR_Op<"set_bitfield"> { %1 = cir.const(#cir.int<3> : !s32i) : !s32i %2 = cir.load %0 : cir.ptr >, !cir.ptr %3 = cir.get_member %2[1] {name = "d"} : !cir.ptr -> !cir.ptr - %4 = cir.set_bitfield %1, %3(#bfi_d) : (!s32i, !cir.ptr) -> !s32i + %4 = cir.set_bitfield #bfi_d, %3, %1 : (!s32i, !cir.ptr) -> !s32i ``` }]; @@ -1469,7 +1469,7 @@ def SetBitfieldOp : CIR_Op<"set_bitfield"> { let results = (outs CIR_IntType:$result); - let assemblyFormat = [{ $src `,` $dst`(`$bitfield_info`)` attr-dict `:` + let assemblyFormat = [{ $bitfield_info`,` $dst`,` $src attr-dict `:` `(` type($src) `,` type($dst) `)` `->` type($result) }]; let builders = [ @@ -1531,7 +1531,7 @@ def GetBitfieldOp : CIR_Op<"get_bitfield"> { %2 = cir.load %0 : cir.ptr >, !cir.ptr %3 = cir.get_member %2[1] {name = "d"} : !cir.ptr -> !cir.ptr - %4 = cir.get_bitfield %3(#bfi_d) : !cir.ptr -> !s32i + %4 = cir.get_bitfield #bfi_d, %3 : !cir.ptr -> !s32i ``` }]; @@ -1542,7 +1542,7 @@ def GetBitfieldOp : CIR_Op<"get_bitfield"> { let results = (outs CIR_IntType:$result); - let assemblyFormat = [{ $addr`(`$bitfield_info`)` attr-dict `:` + let assemblyFormat = [{ $bitfield_info `,` $addr attr-dict `:` type($addr) `->` type($result) }]; let builders = [ diff --git a/clang/test/CIR/CodeGen/bitfield-ops.c b/clang/test/CIR/CodeGen/bitfield-ops.c index 8e296dcf8c05..fe9748b1683f 100644 --- a/clang/test/CIR/CodeGen/bitfield-ops.c +++ b/clang/test/CIR/CodeGen/bitfield-ops.c @@ -17,7 +17,7 @@ typedef struct { // CHECK: [[TMP0:%.*]] = cir.alloca !ty_22S22, cir.ptr , ["s"] // CHECK: [[TMP1:%.*]] = cir.const(#cir.int<3> : !s32i) : !s32i // CHECK: [[TMP2:%.*]] = cir.get_member [[TMP0]][2] {name = "e"} : !cir.ptr -> !cir.ptr -// CHECK: [[TMP3:%.*]] = cir.set_bitfield [[TMP1]], [[TMP2]](#bfi_e) : (!s32i, !cir.ptr) -> !s32i +// CHECK: [[TMP3:%.*]] = cir.set_bitfield #bfi_e, [[TMP2]], [[TMP1]] : (!s32i, !cir.ptr) -> !s32i void store_field() { S s; s.e = 3; @@ -27,7 +27,7 @@ void store_field() { // CHECK: [[TMP0:%.*]] = cir.alloca !cir.ptr, cir.ptr >, ["s", init] // CHECK: [[TMP1:%.*]] = cir.load [[TMP0]] : cir.ptr >, !cir.ptr // CHECK: [[TMP2:%.*]] = cir.get_member [[TMP1]][1] {name = "d"} : !cir.ptr -> !cir.ptr -// CHECK: [[TMP3:%.*]] = cir.get_bitfield [[TMP2]](#bfi_d) : !cir.ptr -> !s32i +// CHECK: [[TMP3:%.*]] = cir.get_bitfield #bfi_d, [[TMP2]] : !cir.ptr -> !s32i int load_field(S* s) { return s->d; } \ No newline at end of file From c6fe0b1ac1da6b0fd15b171b6d8df51d8f4111e4 Mon Sep 17 00:00:00 2001 From: gitoleg Date: Tue, 21 Nov 2023 10:14:58 +0300 Subject: [PATCH 14/15] fix printing --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 6 +++--- clang/test/CIR/CodeGen/bitfield-ops.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 9bb066c56620..45836ad35578 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -1457,7 +1457,7 @@ def SetBitfieldOp : CIR_Op<"set_bitfield"> { %1 = cir.const(#cir.int<3> : !s32i) : !s32i %2 = cir.load %0 : cir.ptr >, !cir.ptr %3 = cir.get_member %2[1] {name = "d"} : !cir.ptr -> !cir.ptr - %4 = cir.set_bitfield #bfi_d, %3, %1 : (!s32i, !cir.ptr) -> !s32i + %4 = cir.set_bitfield(#bfi_d, %3 : !cir.ptr, %1 : !s32i) -> !s32i ``` }]; @@ -1469,8 +1469,8 @@ def SetBitfieldOp : CIR_Op<"set_bitfield"> { let results = (outs CIR_IntType:$result); - let assemblyFormat = [{ $bitfield_info`,` $dst`,` $src attr-dict `:` - `(` type($src) `,` type($dst) `)` `->` type($result) }]; + let assemblyFormat = [{ `(`$bitfield_info`,` $dst`:`type($dst)`,` + $src`:`type($src) `)` attr-dict `->` type($result) }]; let builders = [ OpBuilder<(ins "Type":$type, diff --git a/clang/test/CIR/CodeGen/bitfield-ops.c b/clang/test/CIR/CodeGen/bitfield-ops.c index fe9748b1683f..7418ed5619ce 100644 --- a/clang/test/CIR/CodeGen/bitfield-ops.c +++ b/clang/test/CIR/CodeGen/bitfield-ops.c @@ -17,7 +17,7 @@ typedef struct { // CHECK: [[TMP0:%.*]] = cir.alloca !ty_22S22, cir.ptr , ["s"] // CHECK: [[TMP1:%.*]] = cir.const(#cir.int<3> : !s32i) : !s32i // CHECK: [[TMP2:%.*]] = cir.get_member [[TMP0]][2] {name = "e"} : !cir.ptr -> !cir.ptr -// CHECK: [[TMP3:%.*]] = cir.set_bitfield #bfi_e, [[TMP2]], [[TMP1]] : (!s32i, !cir.ptr) -> !s32i +// CHECK: [[TMP3:%.*]] = cir.set_bitfield(#bfi_e, [[TMP2]] : !cir.ptr, [[TMP1]] : !s32i) -> !s32i void store_field() { S s; s.e = 3; From d7cf1f5fd93cb806d1d1742a4582966c305a7b03 Mon Sep 17 00:00:00 2001 From: gitoleg Date: Thu, 23 Nov 2023 16:19:37 +0300 Subject: [PATCH 15/15] fixed get_bitfield printing --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 6 +++--- clang/test/CIR/CodeGen/bitfield-ops.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 45836ad35578..15686f3ef2da 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -1531,7 +1531,7 @@ def GetBitfieldOp : CIR_Op<"get_bitfield"> { %2 = cir.load %0 : cir.ptr >, !cir.ptr %3 = cir.get_member %2[1] {name = "d"} : !cir.ptr -> !cir.ptr - %4 = cir.get_bitfield #bfi_d, %3 : !cir.ptr -> !s32i + %4 = cir.get_bitfield(#bfi_d, %3 : !cir.ptr) -> !s32i ``` }]; @@ -1542,8 +1542,8 @@ def GetBitfieldOp : CIR_Op<"get_bitfield"> { let results = (outs CIR_IntType:$result); - let assemblyFormat = [{ $bitfield_info `,` $addr attr-dict `:` - type($addr) `->` type($result) }]; + let assemblyFormat = [{ `(`$bitfield_info `,` $addr attr-dict `:` + type($addr) `)` `->` type($result) }]; let builders = [ OpBuilder<(ins "Type":$type, diff --git a/clang/test/CIR/CodeGen/bitfield-ops.c b/clang/test/CIR/CodeGen/bitfield-ops.c index 7418ed5619ce..5fb5f6824c3e 100644 --- a/clang/test/CIR/CodeGen/bitfield-ops.c +++ b/clang/test/CIR/CodeGen/bitfield-ops.c @@ -27,7 +27,7 @@ void store_field() { // CHECK: [[TMP0:%.*]] = cir.alloca !cir.ptr, cir.ptr >, ["s", init] // CHECK: [[TMP1:%.*]] = cir.load [[TMP0]] : cir.ptr >, !cir.ptr // CHECK: [[TMP2:%.*]] = cir.get_member [[TMP1]][1] {name = "d"} : !cir.ptr -> !cir.ptr -// CHECK: [[TMP3:%.*]] = cir.get_bitfield #bfi_d, [[TMP2]] : !cir.ptr -> !s32i +// CHECK: [[TMP3:%.*]] = cir.get_bitfield(#bfi_d, [[TMP2]] : !cir.ptr) -> !s32i int load_field(S* s) { return s->d; } \ No newline at end of file