aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/CGExprConstant.cpp
diff options
context:
space:
mode:
authorAnders Carlsson <andersca@mac.com>2009-07-27 02:56:37 +0000
committerAnders Carlsson <andersca@mac.com>2009-07-27 02:56:37 +0000
commit7a86d4b8a4fe34bb8a9e3bc94f839a4a657856b8 (patch)
tree842e5f7f6f68f8d0b9038b9f8ff0c8eac50e77aa /lib/CodeGen/CGExprConstant.cpp
parentd24393bbc18fe8d30273e832fb9617604cb20493 (diff)
More work on the constant struct builder, fix a couple of thinkos and add support for inserting part of a bitfield in the previous byte.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@77180 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/CGExprConstant.cpp')
-rw-r--r--lib/CodeGen/CGExprConstant.cpp68
1 files changed, 59 insertions, 9 deletions
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index 97e420b70d..b335e90faf 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -130,8 +130,12 @@ class VISIBILITY_HIDDEN ConstStructBuilder {
return false;
if (FieldOffset > NextFieldOffsetInBytes * 8) {
- // FIXME: Add padding.
- return false;
+ // We need to add padding.
+ uint64_t NumBytes =
+ llvm::RoundUpToAlignment(FieldOffset -
+ NextFieldOffsetInBytes * 8, 8) / 8;
+
+ AppendPadding(NumBytes);
}
uint64_t FieldSize =
@@ -151,22 +155,68 @@ class VISIBILITY_HIDDEN ConstStructBuilder {
FieldValue.trunc(FieldSize);
if (FieldOffset < NextFieldOffsetInBytes * 8) {
- // FIXME: Part of the bitfield should go into the previous byte.
- return false;
+ // Either part of the field or the entire field can go into the previous
+ // byte.
+ assert(!Elements.empty() && "Elements can't be empty!");
+
+ unsigned BitsInPreviousByte =
+ NextFieldOffsetInBytes * 8 - FieldOffset;
+
+ bool FitsCompletelyInPreviousByte =
+ BitsInPreviousByte >= FieldValue.getBitWidth();
+
+ llvm::APInt Tmp = FieldValue;
+
+ if (!FitsCompletelyInPreviousByte) {
+ unsigned NewFieldWidth = FieldSize - BitsInPreviousByte;
+
+ if (CGM.getTargetData().isBigEndian()) {
+ Tmp = Tmp.lshr(NewFieldWidth);
+ Tmp.trunc(BitsInPreviousByte);
+
+ // We want the remaining high bits.
+ FieldValue.trunc(NewFieldWidth);
+ } else {
+ Tmp.trunc(BitsInPreviousByte);
+
+ // We want the remaining low bits.
+ FieldValue = FieldValue.lshr(BitsInPreviousByte);
+ FieldValue.trunc(NewFieldWidth);
+ }
+ }
+
+ Tmp.zext(8);
+ if (CGM.getTargetData().isBigEndian()) {
+ if (FitsCompletelyInPreviousByte)
+ Tmp = Tmp.shl(BitsInPreviousByte - FieldValue.getBitWidth());
+ } else {
+ Tmp = Tmp.shl(8 - BitsInPreviousByte);
+ }
+
+ // Or in the bits that go into the previous byte.
+ Tmp |= cast<llvm::ConstantInt>(Elements.back())->getValue();
+ Elements.back() = llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp);
+
+ if (FitsCompletelyInPreviousByte)
+ return true;
}
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 = FieldValue;
+ Tmp = Tmp.lshr(Tmp.getBitWidth() - 8);
+ Tmp.trunc(8);
+ } else {
+ // We want the low bits.
+ Tmp = FieldValue;
+ Tmp.trunc(8);
+
+ FieldValue = FieldValue.lshr(8);
}
- Tmp.trunc(8);
Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp));
NextFieldOffsetInBytes++;