From: Lauro Ramos Venancio Date: Tue, 22 Jan 2008 20:17:04 +0000 (+0000) Subject: Implement bitfield read. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3b8c22d93da1432b2d4cea779d14912645c93866;p=clang Implement bitfield read. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@46257 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/CodeGen/CGExpr.cpp b/CodeGen/CGExpr.cpp index 1bbf2c1f81..9e907216ee 100644 --- a/CodeGen/CGExpr.cpp +++ b/CodeGen/CGExpr.cpp @@ -132,13 +132,37 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, QualType ExprType) { // shuffle the input or extract/insert them as appropriate. if (LV.isOCUVectorElt()) return EmitLoadOfOCUElementLValue(LV, ExprType); - - assert(0 && "Bitfield ref not impl!"); + + if (LV.isBitfield()) + return EmitLoadOfBitfieldLValue(LV, ExprType); + + assert(0 && "Unknown LValue type!"); //an invalid RValue, but the assert will //ensure that this point is never reached return RValue(); } +RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV, + QualType ExprType) { + llvm::Value *Ptr = LV.getBitfieldAddr(); + const llvm::Type *EltTy = + cast(Ptr->getType())->getElementType(); + unsigned EltTySize = EltTy->getPrimitiveSizeInBits(); + unsigned short BitfieldSize = LV.getBitfieldSize(); + unsigned short EndBit = LV.getBitfieldStartBit() + BitfieldSize; + + llvm::Value *V = Builder.CreateLoad(Ptr, "tmp"); + + llvm::Value *ShAmt = llvm::ConstantInt::get(EltTy, EltTySize - EndBit); + V = Builder.CreateShl(V, ShAmt, "tmp"); + + ShAmt = llvm::ConstantInt::get(EltTy, EltTySize - BitfieldSize); + V = LV.isBitfieldSigned() ? + Builder.CreateAShr(V, ShAmt, "tmp") : + Builder.CreateLShr(V, ShAmt, "tmp"); + return RValue::get(V); +} + // If this is a reference to a subset of the elements of a vector, either // shuffle the input or extract/insert them as appropriate. RValue CodeGenFunction::EmitLoadOfOCUElementLValue(LValue LV, @@ -409,15 +433,13 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) { FieldDecl *Field = E->getMemberDecl(); - assert (!Field->isBitField() && "Bit-field access is not yet implmented"); - unsigned idx = CGM.getTypes().getLLVMFieldNo(Field); llvm::Value *Idxs[2] = { llvm::Constant::getNullValue(llvm::Type::Int32Ty), llvm::ConstantInt::get(llvm::Type::Int32Ty, idx) }; llvm::Value *V = Builder.CreateGEP(BaseValue,Idxs, Idxs + 2, "tmp"); // Match union field type. - if (isUnion) { + if (isUnion || Field->isBitField()) { const llvm::Type * FieldTy = ConvertType(Field->getType()); const llvm::PointerType * BaseTy = cast(BaseValue->getType()); @@ -428,10 +450,14 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) { "tmp"); } } - return LValue::MakeAddr(V); - - // FIXME: If record field does not have one to one match with llvm::StructType - // field then apply appropriate masks to select only member field bits. + + if (Field->isBitField()) { + CodeGenTypes::BitFieldInfo bitFieldInfo = + CGM.getTypes().getBitFieldInfo(Field); + return LValue::MakeBitfield(V, bitFieldInfo.Begin, bitFieldInfo.Size, + Field->getType()->isSignedIntegerType()); + } else + return LValue::MakeAddr(V); } //===--------------------------------------------------------------------===// diff --git a/CodeGen/CodeGenFunction.h b/CodeGen/CodeGenFunction.h index 55a02a89b9..d56e438df8 100644 --- a/CodeGen/CodeGenFunction.h +++ b/CodeGen/CodeGenFunction.h @@ -159,6 +159,11 @@ class LValue { union { llvm::Value *VectorIdx; // Index into a vector subscript: V[i] unsigned VectorElts; // Encoded OCUVector element subset: V.xyx + struct { + unsigned short StartBit; + unsigned short Size; + bool IsSigned; + } BitfieldData; // BitField start bit and size }; public: bool isSimple() const { return LVType == Simple; } @@ -177,8 +182,21 @@ public: assert(isOCUVectorElt()); return VectorElts; } - - + // bitfield lvalue + llvm::Value *getBitfieldAddr() const { assert(isBitfield()); return V; } + unsigned short getBitfieldStartBit() const { + assert(isBitfield()); + return BitfieldData.StartBit; + } + unsigned short getBitfieldSize() const { + assert(isBitfield()); + return BitfieldData.Size; + } + bool isBitfieldSigned() const { + assert(isBitfield()); + return BitfieldData.IsSigned; + } + static LValue MakeAddr(llvm::Value *V) { LValue R; R.LVType = Simple; @@ -201,6 +219,17 @@ public: R.VectorElts = Elements; return R; } + + static LValue MakeBitfield(llvm::Value *V, unsigned short StartBit, + unsigned short Size, bool IsSigned) { + LValue R; + R.LVType = BitField; + R.V = V; + R.BitfieldData.StartBit = StartBit; + R.BitfieldData.Size = Size; + R.BitfieldData.IsSigned = IsSigned; + return R; + } }; /// CodeGenFunction - This class organizes the per-function state that is used @@ -364,6 +393,7 @@ public: /// rvalue, returning the rvalue. RValue EmitLoadOfLValue(LValue V, QualType LVType); RValue EmitLoadOfOCUElementLValue(LValue V, QualType LVType); + RValue EmitLoadOfBitfieldLValue(LValue LV, QualType ExprType); /// EmitStoreThroughLValue - Store the specified rvalue into the specified diff --git a/CodeGen/CodeGenTypes.h b/CodeGen/CodeGenTypes.h index db3ba9c2af..5ae49553ab 100644 --- a/CodeGen/CodeGenTypes.h +++ b/CodeGen/CodeGenTypes.h @@ -76,14 +76,17 @@ class CodeGenTypes { /// field no. This info is populated by record organizer. llvm::DenseMap FieldInfo; +public: class BitFieldInfo { public: - explicit BitFieldInfo(unsigned B, unsigned S) + explicit BitFieldInfo(unsigned short B, unsigned short S) : Begin(B), Size(S) {} - unsigned Begin; - unsigned Size; + unsigned short Begin; + unsigned short Size; }; + +private: llvm::DenseMap BitFields; /// RecordTypesToResolve - This keeps track of record types that are not diff --git a/test/CodeGen/bitfield.c b/test/CodeGen/bitfield.c new file mode 100644 index 0000000000..51987655fd --- /dev/null +++ b/test/CodeGen/bitfield.c @@ -0,0 +1,13 @@ +// RUN: clang %s -emit-llvm > %t1 +// RUN: grep "shl i32 %tmp, 19" %t1 && +// RUN: grep "ashr i32 %tmp1, 19" %t1 && +// RUN: grep "shl i16 %tmp4, 1" %t1 && +// RUN: grep "lshr i16 %tmp5, 9" %t1 +// Test bitfield access + + +struct STestB1 { int a:13; char b; unsigned short c:7;} stb1; + +int f() { + return stb1.a + stb1.b + stb1.c; +}