Skip to content

Commit 471e568

Browse files
authored
[CIR][CIRGen] CIR generation for bitfields. Fixes llvm#13 (llvm#233)
This PR introduces bitfelds support. This now works: ``` #include <stdio.h> typedef struct { int a1 : 4; int a2 : 28; int a3 : 16; int a4 : 3; int a5 : 17; int a6 : 25; } A; void init(A* a) { a->a1 = 1; a->a2 = 321; a->a3 = 15; a->a4 = -2; a->a5 = -123; a->a6 = 1234; } void print(A* a) { printf("%d %d %d %d %d %d\n", a->a1, a->a2, a->a3, a->a4, a->a5, a->a6 ); } int main() { A a; init(&a); print(&a); return 0; } ``` the output is: `1 321 15 -2 -123 1234`
1 parent 470aba9 commit 471e568

File tree

10 files changed

+561
-85
lines changed

10 files changed

+561
-85
lines changed

clang/lib/CIR/CodeGen/CIRGenBuilder.h

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,11 @@ class CIRGenBuilderTy : public mlir::OpBuilder {
460460
return getConstInt(
461461
loc, t, isSigned ? intVal.getSExtValue() : intVal.getZExtValue());
462462
}
463+
mlir::Value getConstAPInt(mlir::Location loc, mlir::Type typ,
464+
const llvm::APInt &val) {
465+
return create<mlir::cir::ConstantOp>(loc, typ,
466+
getAttr<mlir::cir::IntAttr>(typ, val));
467+
}
463468
mlir::cir::ConstantOp getBool(bool state, mlir::Location loc) {
464469
return create<mlir::cir::ConstantOp>(loc, getBoolTy(),
465470
getCIRBoolAttr(state));
@@ -677,6 +682,65 @@ class CIRGenBuilderTy : public mlir::OpBuilder {
677682
mlir::cir::UnaryOpKind::Not, value);
678683
}
679684

685+
mlir::Value createBinop(mlir::Value lhs, mlir::cir::BinOpKind kind,
686+
const llvm::APInt &rhs) {
687+
return create<mlir::cir::BinOp>(
688+
lhs.getLoc(), lhs.getType(), kind, lhs,
689+
getConstAPInt(lhs.getLoc(), lhs.getType(), rhs));
690+
}
691+
692+
mlir::Value createBinop(mlir::Value lhs, mlir::cir::BinOpKind kind,
693+
mlir::Value rhs) {
694+
return create<mlir::cir::BinOp>(lhs.getLoc(), lhs.getType(), kind, lhs,
695+
rhs);
696+
}
697+
698+
mlir::Value createShift(mlir::Value lhs, const llvm::APInt &rhs,
699+
bool isShiftLeft) {
700+
return create<mlir::cir::ShiftOp>(
701+
lhs.getLoc(), lhs.getType(), lhs,
702+
getConstAPInt(lhs.getLoc(), lhs.getType(), rhs), isShiftLeft);
703+
}
704+
705+
mlir::Value createShift(mlir::Value lhs, unsigned bits, bool isShiftLeft) {
706+
auto width = lhs.getType().dyn_cast<mlir::cir::IntType>().getWidth();
707+
auto shift = llvm::APInt(width, bits);
708+
return createShift(lhs, shift, isShiftLeft);
709+
}
710+
711+
mlir::Value createShiftLeft(mlir::Value lhs, unsigned bits) {
712+
return createShift(lhs, bits, true);
713+
}
714+
715+
mlir::Value createShiftRight(mlir::Value lhs, unsigned bits) {
716+
return createShift(lhs, bits, false);
717+
}
718+
719+
mlir::Value createLowBitsSet(mlir::Location loc, unsigned size,
720+
unsigned bits) {
721+
auto val = llvm::APInt::getLowBitsSet(size, bits);
722+
auto typ = mlir::cir::IntType::get(getContext(), size, false);
723+
return getConstAPInt(loc, typ, val);
724+
}
725+
726+
mlir::Value createAnd(mlir::Value lhs, llvm::APInt rhs) {
727+
auto val = getConstAPInt(lhs.getLoc(), lhs.getType(), rhs);
728+
return createBinop(lhs, mlir::cir::BinOpKind::And, val);
729+
}
730+
731+
mlir::Value createAnd(mlir::Value lhs, mlir::Value rhs) {
732+
return createBinop(lhs, mlir::cir::BinOpKind::And, rhs);
733+
}
734+
735+
mlir::Value createOr(mlir::Value lhs, llvm::APInt rhs) {
736+
auto val = getConstAPInt(lhs.getLoc(), lhs.getType(), rhs);
737+
return createBinop(lhs, mlir::cir::BinOpKind::Or, val);
738+
}
739+
740+
mlir::Value createOr(mlir::Value lhs, mlir::Value rhs) {
741+
return createBinop(lhs, mlir::cir::BinOpKind::Or, rhs);
742+
}
743+
680744
//===--------------------------------------------------------------------===//
681745
// Cast/Conversion Operators
682746
//===--------------------------------------------------------------------===//
@@ -727,6 +791,5 @@ class CIRGenBuilderTy : public mlir::OpBuilder {
727791
return createCast(mlir::cir::CastKind::bitcast, src, newTy);
728792
}
729793
};
730-
731794
} // namespace cir
732795
#endif

clang/lib/CIR/CodeGen/CIRGenExpr.cpp

Lines changed: 217 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "clang/AST/GlobalDecl.h"
2222
#include "clang/Basic/Builtins.h"
2323
#include "clang/CIR/Dialect/IR/CIRDialect.h"
24+
#include "clang/CIR/Dialect/IR/CIROpsEnums.h"
2425
#include "clang/CIR/Dialect/IR/CIRTypes.h"
2526
#include "llvm/Support/Casting.h"
2627
#include "llvm/Support/ErrorHandling.h"
@@ -126,6 +127,7 @@ static Address buildPointerWithAlignment(const Expr *E,
126127
if (PtrTy->getPointeeType()->isVoidType())
127128
break;
128129
assert(!UnimplementedFeature::tbaa());
130+
129131
LValueBaseInfo InnerBaseInfo;
130132
Address Addr = CGF.buildPointerWithAlignment(
131133
CE->getSubExpr(), &InnerBaseInfo, IsKnownNonNull);
@@ -209,13 +211,78 @@ static Address buildPointerWithAlignment(const Expr *E,
209211
return Address(CGF.buildScalarExpr(E), Align);
210212
}
211213

214+
/// Helper method to check if the underlying ABI is AAPCS
215+
static bool isAAPCS(const TargetInfo &TargetInfo) {
216+
return TargetInfo.getABI().startswith("aapcs");
217+
}
218+
219+
Address CIRGenFunction::getAddrOfField(LValue base, const FieldDecl *field,
220+
unsigned index) {
221+
if (index == 0)
222+
return base.getAddress();
223+
224+
auto loc = getLoc(field->getLocation());
225+
auto fieldType = convertType(field->getType());
226+
auto fieldPtr =
227+
mlir::cir::PointerType::get(getBuilder().getContext(), fieldType);
228+
auto sea = getBuilder().createGetMember(
229+
loc, fieldPtr, base.getPointer(), field->getName(), index);
230+
231+
return Address(sea, CharUnits::One());
232+
}
233+
234+
static bool useVolatileForBitField(const CIRGenModule &cgm, LValue base,
235+
const CIRGenBitFieldInfo &info,
236+
const FieldDecl *field) {
237+
return isAAPCS(cgm.getTarget()) && cgm.getCodeGenOpts().AAPCSBitfieldWidth &&
238+
info.VolatileStorageSize != 0 &&
239+
field->getType()
240+
.withCVRQualifiers(base.getVRQualifiers())
241+
.isVolatileQualified();
242+
}
243+
244+
LValue CIRGenFunction::buildLValueForBitField(LValue base,
245+
const FieldDecl *field) {
246+
247+
LValueBaseInfo BaseInfo = base.getBaseInfo();
248+
const RecordDecl *rec = field->getParent();
249+
auto &layout = CGM.getTypes().getCIRGenRecordLayout(field->getParent());
250+
auto &info = layout.getBitFieldInfo(field);
251+
auto useVolatile = useVolatileForBitField(CGM, base, info, field);
252+
unsigned Idx = layout.getCIRFieldNo(field);
253+
254+
if (useVolatile ||
255+
(IsInPreservedAIRegion ||
256+
(getDebugInfo() && rec->hasAttr<BPFPreserveAccessIndexAttr>()))) {
257+
llvm_unreachable("NYI");
258+
}
259+
260+
Address Addr = getAddrOfField(base, field, Idx);
261+
262+
const unsigned SS = useVolatile ? info.VolatileStorageSize : info.StorageSize;
263+
264+
// Get the access type.
265+
mlir::Type FieldIntTy = builder.getUIntNTy(SS);
266+
267+
auto loc = getLoc(field->getLocation());
268+
if (Addr.getElementType() != FieldIntTy)
269+
Addr = builder.createElementBitCast(loc, Addr, FieldIntTy);
270+
271+
QualType fieldType =
272+
field->getType().withCVRQualifiers(base.getVRQualifiers());
273+
274+
assert(!UnimplementedFeature::tbaa() && "NYI TBAA for bit fields");
275+
LValueBaseInfo FieldBaseInfo(BaseInfo.getAlignmentSource());
276+
return LValue::MakeBitfield(Addr, info, fieldType, FieldBaseInfo);
277+
}
278+
212279
LValue CIRGenFunction::buildLValueForField(LValue base,
213280
const FieldDecl *field) {
281+
214282
LValueBaseInfo BaseInfo = base.getBaseInfo();
215283

216-
if (field->isBitField()) {
217-
llvm_unreachable("NYI");
218-
}
284+
if (field->isBitField())
285+
return buildLValueForBitField(base, field);
219286

220287
// Fields of may-alias structures are may-alais themselves.
221288
// FIXME: this hould get propagated down through anonymous structs and unions.
@@ -518,12 +585,55 @@ void CIRGenFunction::buildStoreOfScalar(mlir::Value value, LValue lvalue,
518585
/// method emits the address of the lvalue, then loads the result as an rvalue,
519586
/// returning the rvalue.
520587
RValue CIRGenFunction::buildLoadOfLValue(LValue LV, SourceLocation Loc) {
521-
assert(LV.isSimple() && "not implemented");
522588
assert(!LV.getType()->isFunctionType());
523589
assert(!(LV.getType()->isConstantMatrixType()) && "not implemented");
524590

525-
// Everything needs a load.
526-
return RValue::get(buildLoadOfScalar(LV, Loc));
591+
if (LV.isBitField())
592+
return buildLoadOfBitfieldLValue(LV, Loc);
593+
594+
if (LV.isSimple())
595+
return RValue::get(buildLoadOfScalar(LV, Loc));
596+
llvm_unreachable("NYI");
597+
}
598+
599+
RValue CIRGenFunction::buildLoadOfBitfieldLValue(LValue LV,
600+
SourceLocation Loc) {
601+
const CIRGenBitFieldInfo &Info = LV.getBitFieldInfo();
602+
603+
// Get the output type.
604+
mlir::Type ResLTy = convertType(LV.getType());
605+
Address Ptr = LV.getBitFieldAddress();
606+
mlir::Value Val = builder.createLoad(getLoc(Loc), Ptr);
607+
auto ValWidth = Val.getType().cast<IntType>().getWidth();
608+
609+
bool UseVolatile = LV.isVolatileQualified() &&
610+
Info.VolatileStorageSize != 0 && isAAPCS(CGM.getTarget());
611+
const unsigned Offset = UseVolatile ? Info.VolatileOffset : Info.Offset;
612+
const unsigned StorageSize =
613+
UseVolatile ? Info.VolatileStorageSize : Info.StorageSize;
614+
615+
if (Info.IsSigned) {
616+
assert(static_cast<unsigned>(Offset + Info.Size) <= StorageSize);
617+
618+
mlir::Type typ = builder.getSIntNTy(ValWidth);
619+
Val = builder.createIntCast(Val, typ);
620+
621+
unsigned HighBits = StorageSize - Offset - Info.Size;
622+
if (HighBits)
623+
Val = builder.createShiftLeft(Val, HighBits);
624+
if (Offset + HighBits)
625+
Val = builder.createShiftRight(Val, Offset + HighBits);
626+
} else {
627+
if (Offset)
628+
Val = builder.createShiftRight(Val, Offset);
629+
630+
if (static_cast<unsigned>(Offset) + Info.Size < StorageSize)
631+
Val = builder.createAnd(Val,
632+
llvm::APInt::getLowBitsSet(ValWidth, Info.Size));
633+
}
634+
Val = builder.createIntCast(Val, ResLTy);
635+
assert(!UnimplementedFeature::emitScalarRangeCheck() && "NYI");
636+
return RValue::get(Val);
527637
}
528638

529639
void CIRGenFunction::buildStoreThroughLValue(RValue Src, LValue Dst) {
@@ -546,6 +656,81 @@ void CIRGenFunction::buildStoreThroughLValue(RValue Src, LValue Dst) {
546656
buildStoreOfScalar(Src.getScalarVal(), Dst);
547657
}
548658

659+
void CIRGenFunction::buildStoreThroughBitfieldLValue(RValue Src, LValue Dst,
660+
mlir::Value &Result) {
661+
const CIRGenBitFieldInfo &Info = Dst.getBitFieldInfo();
662+
mlir::Type ResLTy = getTypes().convertTypeForMem(Dst.getType());
663+
Address Ptr = Dst.getBitFieldAddress();
664+
665+
// Get the source value, truncated to the width of the bit-field.
666+
mlir::Value SrcVal = Src.getScalarVal();
667+
668+
// Cast the source to the storage type and shift it into place.
669+
SrcVal = builder.createIntCast(SrcVal, Ptr.getElementType());
670+
auto SrcWidth = SrcVal.getType().cast<IntType>().getWidth();
671+
mlir::Value MaskedVal = SrcVal;
672+
673+
const bool UseVolatile =
674+
CGM.getCodeGenOpts().AAPCSBitfieldWidth && Dst.isVolatileQualified() &&
675+
Info.VolatileStorageSize != 0 && isAAPCS(CGM.getTarget());
676+
const unsigned StorageSize =
677+
UseVolatile ? Info.VolatileStorageSize : Info.StorageSize;
678+
const unsigned Offset = UseVolatile ? Info.VolatileOffset : Info.Offset;
679+
// See if there are other bits in the bitfield's storage we'll need to load
680+
// and mask together with source before storing.
681+
if (StorageSize != Info.Size) {
682+
assert(StorageSize > Info.Size && "Invalid bitfield size.");
683+
684+
mlir::Value Val = buildLoadOfScalar(Dst, Dst.getPointer().getLoc());
685+
686+
// Mask the source value as needed.
687+
if (!hasBooleanRepresentation(Dst.getType()))
688+
SrcVal = builder.createAnd(
689+
SrcVal, llvm::APInt::getLowBitsSet(SrcWidth, Info.Size));
690+
691+
MaskedVal = SrcVal;
692+
if (Offset)
693+
SrcVal = builder.createShiftLeft(SrcVal, Offset);
694+
695+
// Mask out the original value.
696+
Val = builder.createAnd(
697+
Val, ~llvm::APInt::getBitsSet(SrcWidth, Offset, Offset + Info.Size));
698+
699+
// Or together the unchanged values and the source value.
700+
SrcVal = builder.createOr(Val, SrcVal);
701+
702+
} else {
703+
// According to the AACPS:
704+
// When a volatile bit-field is written, and its container does not overlap
705+
// with any non-bit-field member, its container must be read exactly once
706+
// and written exactly once using the access width appropriate to the type
707+
// of the container. The two accesses are not atomic.
708+
llvm_unreachable("volatile bit-field is not implemented for the AACPS");
709+
}
710+
711+
// Write the new value back out.
712+
// TODO: constant matrix type, volatile, no init, non temporal, TBAA
713+
buildStoreOfScalar(SrcVal, Ptr, Dst.isVolatileQualified(), Dst.getType(),
714+
Dst.getBaseInfo(), false, false);
715+
716+
// Return the new value of the bit-field.
717+
mlir::Value ResultVal = MaskedVal;
718+
ResultVal = builder.createIntCast(ResultVal, ResLTy);
719+
720+
// Sign extend the value if needed.
721+
if (Info.IsSigned) {
722+
assert(Info.Size <= StorageSize);
723+
unsigned HighBits = StorageSize - Info.Size;
724+
725+
if (HighBits) {
726+
ResultVal = builder.createShiftLeft(ResultVal, HighBits);
727+
ResultVal = builder.createShiftRight(ResultVal, HighBits);
728+
}
729+
}
730+
731+
Result = buildFromMemory(ResultVal, Dst.getType());
732+
}
733+
549734
static LValue buildGlobalVarDeclLValue(CIRGenFunction &CGF, const Expr *E,
550735
const VarDecl *VD) {
551736
QualType T = E->getType();
@@ -769,7 +954,13 @@ LValue CIRGenFunction::buildBinaryOperatorLValue(const BinaryOperator *E) {
769954
LValue LV = buildLValue(E->getLHS());
770955

771956
SourceLocRAIIObject Loc{*this, getLoc(E->getSourceRange())};
772-
buildStoreThroughLValue(RV, LV);
957+
if (LV.isBitField()) {
958+
mlir::Value result;
959+
buildStoreThroughBitfieldLValue(RV, LV, result);
960+
} else {
961+
buildStoreThroughLValue(RV, LV);
962+
}
963+
773964
assert(!getContext().getLangOpts().OpenMP &&
774965
"last priv cond not implemented");
775966
return LV;
@@ -2203,6 +2394,13 @@ mlir::Value CIRGenFunction::buildAlloca(StringRef name, QualType ty,
22032394

22042395
mlir::Value CIRGenFunction::buildLoadOfScalar(LValue lvalue,
22052396
SourceLocation Loc) {
2397+
return buildLoadOfScalar(lvalue.getAddress(), lvalue.isVolatile(),
2398+
lvalue.getType(), getLoc(Loc), lvalue.getBaseInfo(),
2399+
lvalue.isNontemporal());
2400+
}
2401+
2402+
mlir::Value CIRGenFunction::buildLoadOfScalar(LValue lvalue,
2403+
mlir::Location Loc) {
22062404
return buildLoadOfScalar(lvalue.getAddress(), lvalue.isVolatile(),
22072405
lvalue.getType(), Loc, lvalue.getBaseInfo(),
22082406
lvalue.isNontemporal());
@@ -2220,6 +2418,14 @@ mlir::Value CIRGenFunction::buildLoadOfScalar(Address Addr, bool Volatile,
22202418
QualType Ty, SourceLocation Loc,
22212419
LValueBaseInfo BaseInfo,
22222420
bool isNontemporal) {
2421+
return buildLoadOfScalar(Addr, Volatile, Ty, getLoc(Loc), BaseInfo,
2422+
isNontemporal);
2423+
}
2424+
2425+
mlir::Value CIRGenFunction::buildLoadOfScalar(Address Addr, bool Volatile,
2426+
QualType Ty, mlir::Location Loc,
2427+
LValueBaseInfo BaseInfo,
2428+
bool isNontemporal) {
22232429
if (!CGM.getCodeGenOpts().PreserveVec3Type) {
22242430
if (Ty->isVectorType()) {
22252431
llvm_unreachable("NYI");
@@ -2233,15 +2439,14 @@ mlir::Value CIRGenFunction::buildLoadOfScalar(Address Addr, bool Volatile,
22332439
}
22342440

22352441
mlir::cir::LoadOp Load = builder.create<mlir::cir::LoadOp>(
2236-
getLoc(Loc), Addr.getElementType(), Addr.getPointer());
2442+
Loc, Addr.getElementType(), Addr.getPointer());
22372443

22382444
if (isNontemporal) {
22392445
llvm_unreachable("NYI");
22402446
}
2241-
2242-
// TODO: TBAA
2243-
2244-
// TODO: buildScalarRangeCheck
2447+
2448+
assert(!UnimplementedFeature::tbaa() && "NYI");
2449+
assert(!UnimplementedFeature::emitScalarRangeCheck() && "NYI");
22452450

22462451
return buildFromMemory(Load, Ty);
22472452
}

0 commit comments

Comments
 (0)