diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index d6791074c7d7..840ed4314f6d 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -14,11 +14,13 @@ #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "clang/AST/AST.h" +#include "clang/Basic/TargetInfo.h" #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" #include "llvm/Function.h" #include "llvm/GlobalVariable.h" #include "llvm/Support/MathExtras.h" +#include "llvm/Target/TargetData.h" using namespace clang; using namespace CodeGen; @@ -175,6 +177,11 @@ RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV, V = LV.isBitfieldSigned() ? Builder.CreateAShr(V, ShAmt, "tmp") : Builder.CreateLShr(V, ShAmt, "tmp"); + + // The bitfield type and the normal type differ when the storage sizes + // differ (currently just _Bool). + V = Builder.CreateIntCast(V, ConvertType(ExprType), false, "tmp"); + return RValue::get(V); } @@ -280,13 +287,18 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, unsigned short StartBit = Dst.getBitfieldStartBit(); unsigned short BitfieldSize = Dst.getBitfieldSize(); llvm::Value *Ptr = Dst.getBitfieldAddr(); - const llvm::Type *EltTy = - cast(Ptr->getType())->getElementType(); - unsigned EltTySize = EltTy->getPrimitiveSizeInBits(); llvm::Value *NewVal = Src.getScalarVal(); llvm::Value *OldVal = Builder.CreateLoad(Ptr, "tmp"); + // The bitfield type and the normal type differ when the storage sizes + // differ (currently just _Bool). + const llvm::Type *EltTy = OldVal->getType(); + unsigned EltTySize = CGM.getTargetData().getABITypeSizeInBits(EltTy); + + NewVal = Builder.CreateIntCast(NewVal, EltTy, false, "tmp"); + + // Move the bits into the appropriate location llvm::Value *ShAmt = llvm::ConstantInt::get(EltTy, StartBit); NewVal = Builder.CreateShl(NewVal, ShAmt, "tmp"); @@ -531,7 +543,11 @@ LValue CodeGenFunction::EmitLValueForField(llvm::Value* BaseValue, if (!Field->isBitField()) { V = Builder.CreateStructGEP(BaseValue, idx, "tmp"); } else { - const llvm::Type *FieldTy = ConvertType(Field->getType()); + // FIXME: CodeGenTypes should expose a method to get the appropriate + // type for FieldTy (the appropriate type is ABI-dependent). + unsigned EltTySize = + CGM.getTargetData().getABITypeSizeInBits(ConvertType(Field->getType())); + const llvm::Type *FieldTy = llvm::IntegerType::get(EltTySize); const llvm::PointerType *BaseTy = cast(BaseValue->getType()); unsigned AS = BaseTy->getAddressSpace(); diff --git a/clang/test/CodeGen/bool-bitfield.c b/clang/test/CodeGen/bool-bitfield.c new file mode 100644 index 000000000000..09298ed53b90 --- /dev/null +++ b/clang/test/CodeGen/bool-bitfield.c @@ -0,0 +1,54 @@ +// RUN: clang -emit-llvm %s + +// From GCC PR19331 +struct SysParams +{ + unsigned short tag; + unsigned short version; + unsigned int seqnum; + int contrast; + int igain_1, igain_2; + int oattn_1, oattn_2; + int max_out_vltg_1, max_out_vltg_2; + int max_mains_current; + int meters_mode; + int input_select; + _Bool input_parallelch2:1; + _Bool cliplmt_ch1:1; + _Bool cliplmt_ch2:1; + _Bool gate_ch1:1; + _Bool gate_ch2:1; + _Bool mute_ch1:1; + _Bool mute_ch2:1; + _Bool brownout:1; + _Bool power_on:1; + _Bool pwrup_mute:1; + _Bool keylock:1; + _Bool dsp_ch1:1; + _Bool dsp_ch2:1; + int dsp_preset; + long unlock_code; +}; +extern struct SysParams params; + +void foo(void *); +void kcmd_setParams(void) +{ + struct { + unsigned char igain_1; + unsigned char igain_2; + unsigned char max_out_vltg_1; + unsigned char max_out_vltg_2; + unsigned char max_imains; + unsigned char cliplmt_ch1:1; + unsigned char cliplmt_ch2:1; + unsigned char gate_ch1:1; + unsigned char gate_ch2:1; + } msg; + foo(&msg); + params.cliplmt_ch1 = msg.cliplmt_ch1; + params.cliplmt_ch2 = msg.cliplmt_ch2; + params.gate_ch1 = msg.gate_ch1; + params.gate_ch2 = msg.gate_ch2; +} +