diff options
author | Anders Carlsson <andersca@mac.com> | 2009-07-27 01:23:51 +0000 |
---|---|---|
committer | Anders Carlsson <andersca@mac.com> | 2009-07-27 01:23:51 +0000 |
commit | d24393bbc18fe8d30273e832fb9617604cb20493 (patch) | |
tree | 9ce3621c2c30e9d8094bf8d063ca07634c2285ac /lib/CodeGen/CGExprConstant.cpp | |
parent | 2d3c191e1d5545e1724ee6e0550c70eef54beff2 (diff) |
More work on bitfield support in the new constant struct builder.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@77177 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/CGExprConstant.cpp')
-rw-r--r-- | lib/CodeGen/CGExprConstant.cpp | 81 |
1 files changed, 79 insertions, 2 deletions
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index db34fdee0c..97e420b70d 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -119,6 +119,82 @@ class VISIBILITY_HIDDEN ConstStructBuilder { return true; } + bool AppendBitField(const FieldDecl *Field, uint64_t FieldOffset, + const Expr *InitExpr) { + llvm::ConstantInt *CI = + cast_or_null<llvm::ConstantInt>(CGM.EmitConstantExpr(InitExpr, + Field->getType(), + CGF)); + // FIXME: Can this ever happen? + if (!CI) + return false; + + if (FieldOffset > NextFieldOffsetInBytes * 8) { + // FIXME: Add padding. + return false; + } + + uint64_t FieldSize = + Field->getBitWidth()->EvaluateAsInt(CGM.getContext()).getZExtValue(); + + llvm::APInt FieldValue = CI->getValue(); + + // Promote the size of FieldValue if necessary + // FIXME: This should never occur, but currently it can because initializer + // constants are cast to bool, and because clang is not enforcing bitfield + // width limits. + if (FieldSize > FieldValue.getBitWidth()) + FieldValue.zext(FieldSize); + + // Truncate the size of FieldValue to the bit field size. + if (FieldSize < FieldValue.getBitWidth()) + FieldValue.trunc(FieldSize); + + if (FieldOffset < NextFieldOffsetInBytes * 8) { + // FIXME: Part of the bitfield should go into the previous byte. + return false; + } + + while (FieldValue.getBitWidth() > 8) { + llvm::APInt Tmp; + + if (CGM.getTargetData().isBigEndian()) { + // We want the low bits. + Tmp = FieldValue.getLoBits(8); + } else { + // We want the high bits. + Tmp = FieldValue.getHiBits(8); + } + + Tmp.trunc(8); + Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp)); + NextFieldOffsetInBytes++; + + FieldValue.trunc(FieldValue.getBitWidth() - 8); + } + + assert(FieldValue.getBitWidth() > 0 && + "Should have at least one bit left!"); + assert(FieldValue.getBitWidth() <= 8 && + "Should not have more than a byte left!"); + + if (FieldValue.getBitWidth() < 8) { + if (CGM.getTargetData().isBigEndian()) { + unsigned BitWidth = FieldValue.getBitWidth(); + + FieldValue.zext(8); + FieldValue = FieldValue << (8 - BitWidth); + } else + FieldValue.zext(8); + } + + // Append the last element. + Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(), + FieldValue)); + NextFieldOffsetInBytes++; + return true; + } + void AppendPadding(uint64_t NumBytes) { if (!NumBytes) return; @@ -158,8 +234,9 @@ class VISIBILITY_HIDDEN ConstStructBuilder { if (!Field->getIdentifier()) continue; - // FIXME: Bitfield support. - return false; + if (!AppendBitField(*Field, Layout.getFieldOffset(FieldNo), + ILE->getInit(ElementNo))) + return false; } else { if (!AppendField(*Field, Layout.getFieldOffset(FieldNo), ILE->getInit(ElementNo))) |