Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CIR][Codegen][Lowering] Introduce new bitfield layout #487

Merged
merged 33 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
09d6784
[CIR][Codegen] support for packed structures
gitoleg Feb 20, 2024
ea82ef0
adds sentenial
gitoleg Feb 20, 2024
6641ce8
added trivial tests
gitoleg Feb 20, 2024
e7948d2
added one more test
gitoleg Feb 20, 2024
ee347ae
clang format
gitoleg Feb 21, 2024
bc1177d
Merge remote-tracking branch 'upstream/main' into packed-structures
gitoleg Feb 21, 2024
7dc3497
Merge remote-tracking branch 'upstream/main' into packed-structures
gitoleg Feb 22, 2024
d6451db
omg, wip
gitoleg Feb 26, 2024
cd06ee8
looks like something starts to work
gitoleg Feb 27, 2024
27dd7b3
helpers, refactoring
gitoleg Feb 27, 2024
4405c76
refactoring
gitoleg Feb 27, 2024
b2fc073
wip
gitoleg Feb 27, 2024
37fc173
Merge remote-tracking branch 'upstream/main' into new-bitfield-layout
gitoleg Feb 27, 2024
7936c4f
wip
gitoleg Feb 27, 2024
d3586bf
try this one: both intType and ByteArrayType supported
gitoleg Feb 28, 2024
45d43fd
work on tests
gitoleg Feb 28, 2024
8d86d82
fixed all tests
gitoleg Feb 28, 2024
3f2653a
use volatile for lowering
gitoleg Feb 28, 2024
11db130
removed bitfield-ops.c
gitoleg Feb 29, 2024
0c789d0
cleaned the code
gitoleg Feb 29, 2024
55e041f
bug fixed
gitoleg Feb 29, 2024
35c6583
returns the SetBitfield result
gitoleg Feb 29, 2024
6125f95
fixes minor issues
gitoleg Feb 29, 2024
e44431d
clang-format ...
gitoleg Feb 29, 2024
8b0b837
merg
gitoleg Mar 1, 2024
68971d6
clang-format ...
gitoleg Mar 1, 2024
859141d
forgotten return val
gitoleg Mar 1, 2024
8840bb6
Merge remote-tracking branch 'upstream/main' into new-bitfield-layout
gitoleg Mar 7, 2024
2fbbb92
refactoring
gitoleg Mar 11, 2024
4700574
Merge remote-tracking branch 'upstream/main' into new-bitfield-layout
gitoleg Mar 11, 2024
c35d31a
clang-format ...
gitoleg Mar 11, 2024
dbd0a46
minor fix
gitoleg Mar 11, 2024
9097afd
bug fixed
gitoleg Mar 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIRTypes.td
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,18 @@ def CIR_IntType : CIR_Type<"Int", "int",
std::string getAlias() const {
return (isSigned() ? 's' : 'u') + std::to_string(getWidth()) + 'i';
};

/// Returns a minimum bitwidth of cir::IntType
static unsigned minBitwidth() { return 8; }
/// Returns a maximum bitwidth of cir::IntType
static unsigned maxBitwidth() { return 64; }

/// Returns true if cir::IntType can be constructed from the provided bitwidth
static bool isValidBitwidth(unsigned width) {
return width >= minBitwidth()
&& width <= maxBitwidth()
&& llvm::isPowerOf2_32(width);
}
}];
let genVerifyDecl = 1;
}
Expand Down
17 changes: 5 additions & 12 deletions clang/lib/CIR/CodeGen/CIRGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,19 +226,15 @@ static bool isAAPCS(const TargetInfo &TargetInfo) {

Address CIRGenFunction::getAddrOfBitFieldStorage(LValue base,
const FieldDecl *field,
unsigned index,
unsigned size) {
mlir::Type fieldType,
unsigned index) {
if (index == 0)
return base.getAddress();

auto loc = getLoc(field->getLocation());
auto fieldType = builder.getUIntNTy(size);

auto fieldPtr =
mlir::cir::PointerType::get(getBuilder().getContext(), fieldType);
auto sea = getBuilder().createGetMember(loc, fieldPtr, base.getPointer(),
field->getName(), index);

return Address(sea, CharUnits::One());
}

Expand Down Expand Up @@ -268,14 +264,11 @@ LValue CIRGenFunction::buildLValueForBitField(LValue base,
llvm_unreachable("NYI");
}

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);
Address Addr = getAddrOfBitFieldStorage(base, field, info.StorageType, Idx);

auto loc = getLoc(field->getLocation());
if (Addr.getElementType() != FieldIntTy)
Addr = builder.createElementBitCast(loc, Addr, FieldIntTy);
if (Addr.getElementType() != info.StorageType)
Addr = builder.createElementBitCast(loc, Addr, info.StorageType);

QualType fieldType =
field->getType().withCVRQualifiers(base.getVRQualifiers());
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/CIR/CodeGen/CIRGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -1468,7 +1468,7 @@ class CIRGenFunction : public CIRGenTypeCache {
}

Address getAddrOfBitFieldStorage(LValue base, const clang::FieldDecl *field,
unsigned index, unsigned size);
mlir::Type fieldType, unsigned index);

/// Given an opaque value expression, return its LValue mapping if it exists,
/// otherwise create one.
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenRecordLayout.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ struct CIRGenBitFieldInfo {
/// The name of a bitfield
llvm::StringRef Name;

// The actual storage type for the bitfield
mlir::Type StorageType;

CIRGenBitFieldInfo()
: Offset(), Size(), IsSigned(), StorageSize(), VolatileOffset(),
VolatileStorageSize() {}
Expand Down
24 changes: 17 additions & 7 deletions clang/lib/CIR/CodeGen/CIRRecordLayoutBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,20 @@ struct CIRRecordLowering final {
numberOfChars.getQuantity());
}

// This is different from LLVM traditional codegen because CIRGen uses arrays
// of bytes instead of arbitrary-sized integers. This is important for packed
// structures support.
mlir::Type getBitfieldStorageType(unsigned numBits) {
unsigned alignedBits = llvm::alignTo(numBits, astContext.getCharWidth());
if (mlir::cir::IntType::isValidBitwidth(alignedBits)) {
return builder.getUIntNTy(alignedBits);
} else {
mlir::Type type = getCharType();
return mlir::cir::ArrayType::get(type.getContext(), type,
bcardosolopes marked this conversation as resolved.
Show resolved Hide resolved
alignedBits / astContext.getCharWidth());
}
}

// Gets the llvm Basesubobject type from a CXXRecordDecl.
mlir::Type getStorageType(const CXXRecordDecl *RD) {
return cirGenTypes.getCIRGenRecordLayout(RD).getBaseSubobjectCIRType();
Expand Down Expand Up @@ -228,6 +242,7 @@ void CIRRecordLowering::setBitFieldInfo(const FieldDecl *FD,
Info.Size = FD->getBitWidthValue(astContext);
Info.StorageSize = getSizeInBits(StorageType).getQuantity();
Info.StorageOffset = StartOffset;
Info.StorageType = StorageType;
Info.Name = FD->getName();

if (Info.Size > Info.StorageSize)
Expand Down Expand Up @@ -502,12 +517,6 @@ void CIRRecordLowering::accumulateBitFields(
auto IsBetterAsSingleFieldRun = [&](uint64_t OffsetInRecord,
uint64_t StartBitOffset,
uint64_t nextTail = 0) {
if (OffsetInRecord >= 64 ||
(nextTail > StartBitOffset &&
nextTail - StartBitOffset >= 64)) { // See IntType::verify
return true;
}

if (!cirGenTypes.getModule().getCodeGenOpts().FineGrainedBitfieldAccesses)
return false;
llvm_unreachable("NYI");
Expand Down Expand Up @@ -567,7 +576,8 @@ void CIRRecordLowering::accumulateBitFields(
}

// We've hit a break-point in the run and need to emit a storage field.
auto Type = getUIntNType(Tail - StartBitOffset);
auto Type = getBitfieldStorageType(Tail - StartBitOffset);

// Add the storage member to the record and set the bitfield info for all of
// the bitfields in the run. Bitfields get the offset of their storage but
// come afterward and remain there after a stable sort.
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/CIR/Dialect/IR/CIRTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -642,8 +642,9 @@ mlir::LogicalResult
IntType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
unsigned width, bool isSigned) {

if (width < 8 || width > 64) {
emitError() << "IntType only supports widths from 8 up to 64";
if (width < IntType::minBitwidth() || width > IntType::maxBitwidth()) {
emitError() << "IntType only supports widths from "
<< IntType::minBitwidth() << "up to " << IntType::maxBitwidth();
return mlir::failure();
}
if (width % 8 != 0) {
Expand Down
112 changes: 1 addition & 111 deletions clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,6 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> {

void runOnOp(Operation *op);
void lowerGlobalOp(GlobalOp op);
void lowerGetBitfieldOp(GetBitfieldOp op);
void lowerSetBitfieldOp(SetBitfieldOp op);
void lowerStdFindOp(StdFindOp op);
void lowerIterBeginOp(IterBeginOp op);
void lowerIterEndOp(IterEndOp op);
Expand Down Expand Up @@ -303,109 +301,6 @@ void LoweringPreparePass::buildCXXGlobalInitFunc() {
builder.create<ReturnOp>(f.getLoc());
}

void LoweringPreparePass::lowerGetBitfieldOp(GetBitfieldOp op) {
CIRBaseBuilderTy builder(getContext());
builder.setInsertionPointAfter(op.getOperation());

auto info = op.getBitfieldInfo();
auto size = info.getSize();
auto storageType = info.getStorageType();
auto storageSize = storageType.cast<IntType>().getWidth();
auto offset = info.getOffset();
auto resultTy = op.getType();
auto addr = op.getAddr();
auto loc = addr.getLoc();
mlir::Value val = builder.create<mlir::cir::LoadOp>(
loc, storageType, op.getAddr(), /* deref */ false, op.getIsVolatile());
auto valWidth = val.getType().cast<IntType>().getWidth();

if (info.getIsSigned()) {
assert(static_cast<unsigned>(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<unsigned>(offset) + size < storageSize)
val = builder.createAnd(val, llvm::APInt::getLowBitsSet(valWidth, size));
}
val = builder.createIntCast(val, resultTy);

op.replaceAllUsesWith(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 storageType = info.getStorageType();
auto storageSize = storageType.cast<IntType>().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(), storageType);
auto srcWidth = srcVal.getType().cast<IntType>().getWidth();

mlir::Value maskedVal = srcVal;

if (storageSize != size) {
assert(storageSize > size && "Invalid bitfield size.");

mlir::Value val = builder.create<mlir::cir::LoadOp>(loc, storageType, 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<mlir::cir::StoreOp>(loc, srcVal, addr, op.getIsVolatile());

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);
}
}

op.replaceAllUsesWith(resultVal);
}

op.erase();
}

void LoweringPreparePass::lowerStdFindOp(StdFindOp op) {
CIRBaseBuilderTy builder(getContext());
builder.setInsertionPointAfter(op.getOperation());
Expand Down Expand Up @@ -442,10 +337,6 @@ void LoweringPreparePass::lowerIterEndOp(IterEndOp op) {
void LoweringPreparePass::runOnOp(Operation *op) {
if (auto getGlobal = dyn_cast<GlobalOp>(op)) {
lowerGlobalOp(getGlobal);
} else if (auto getBitfield = dyn_cast<GetBitfieldOp>(op)) {
lowerGetBitfieldOp(getBitfield);
} else if (auto setBitfield = dyn_cast<SetBitfieldOp>(op)) {
lowerSetBitfieldOp(setBitfield);
} else if (auto stdFind = dyn_cast<StdFindOp>(op)) {
lowerStdFindOp(stdFind);
} else if (auto iterBegin = dyn_cast<IterBeginOp>(op)) {
Expand All @@ -464,8 +355,7 @@ void LoweringPreparePass::runOnOperation() {

SmallVector<Operation *> opsToTransform;
op->walk([&](Operation *op) {
if (isa<GlobalOp, GetBitfieldOp, SetBitfieldOp, StdFindOp, IterBeginOp,
IterEndOp>(op))
if (isa<GlobalOp, StdFindOp, IterBeginOp, IterEndOp>(op))
opsToTransform.push_back(op);
});

Expand Down
Loading
Loading