r215614 - CodeGen: When bitfields fall on natural boundaries, split them up

Justin Bogner mail at justinbogner.com
Wed Aug 13 19:42:10 PDT 2014


Author: bogner
Date: Wed Aug 13 21:42:10 2014
New Revision: 215614

URL: http://llvm.org/viewvc/llvm-project?rev=215614&view=rev
Log:
CodeGen: When bitfields fall on natural boundaries, split them up

Currently when laying out bitfields that don't need any padding, we
represent them as a wide enough int to contain all of the bits. This
can be hard on the backend since we'll do things like represent stores
to a few bits as loading an i144, masking it with a large constant,
and storing it back.

This turns up in less pathological cases where we load and mask 64 bit
word on a 32 bit platform when we actually only need to access 32 bits.
This leads to bad code being generated in most of our 32 bit backends.

In practice, there are often natural breaks in bitfields, and it's a
fairly simple and effective heuristic to split these fields into legal
integer sized chunks when it will be equivalent (ie, it won't force us
to add any extra padding).

Added:
    cfe/trunk/test/CodeGen/bitfield-machinewords.c
Modified:
    cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.cpp

Modified: cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.cpp?rev=215614&r1=215613&r2=215614&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.cpp Wed Aug 13 21:42:10 2014
@@ -377,6 +377,10 @@ CGRecordLowering::accumulateBitFields(Re
     }
     return;
   }
+
+  llvm::Type *WordType =
+      DataLayout.getLargestLegalIntType(Types.getLLVMContext());
+  uint64_t WordSize = WordType ? DataLayout.getTypeSizeInBits(WordType) : 0;
   for (;;) {
     // Check to see if we need to start a new run.
     if (Run == FieldEnd) {
@@ -392,9 +396,12 @@ CGRecordLowering::accumulateBitFields(Re
       ++Field;
       continue;
     }
-    // Add bitfields to the run as long as they qualify.
+    // Add bitfields to the run as long as they qualify. If we end up on a word
+    // boundary we insert a break since it's equivalent and very wide types are
+    // harder to optimize with.
     if (Field != FieldEnd && Field->getBitWidthValue(Context) != 0 &&
-        Tail == getFieldBitOffset(*Field)) {
+        Tail == getFieldBitOffset(*Field) &&
+        WordSize != Tail - StartBitOffset) {
       Tail += Field->getBitWidthValue(Context);
       ++Field;
       continue;

Added: cfe/trunk/test/CodeGen/bitfield-machinewords.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/bitfield-machinewords.c?rev=215614&view=auto
==============================================================================
--- cfe/trunk/test/CodeGen/bitfield-machinewords.c (added)
+++ cfe/trunk/test/CodeGen/bitfield-machinewords.c Wed Aug 13 21:42:10 2014
@@ -0,0 +1,79 @@
+// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o - | FileCheck %s -check-prefix=CHECK32
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -emit-llvm -o - | FileCheck %s -check-prefix=CHECK64
+
+typedef unsigned long long uint64_t;
+
+struct thirty_two_bit_fields {
+  unsigned int ttbf1 : 32;
+  unsigned int ttbf2 : 32;
+  unsigned int ttbf3 : 32;
+  unsigned int ttbf4 : 32;
+};
+void ttbf(struct thirty_two_bit_fields *x) {}
+// CHECK32: %struct.thirty_two_bit_fields = type { i32, i32, i32, i32 }
+// CHECK64: %struct.thirty_two_bit_fields = type { i64, i64 }
+
+struct thirty_two_in_sixty_four {
+  uint64_t ttisf1 : 32;
+  uint64_t ttisf2 : 32;
+  uint64_t ttisf3 : 32;
+  uint64_t ttisf4 : 32;
+};
+void ttisf(struct thirty_two_in_sixty_four *x) {}
+// CHECK32: %struct.thirty_two_in_sixty_four = type { i32, i32, i32, i32 }
+// CHECK64: %struct.thirty_two_in_sixty_four = type { i64, i64 }
+
+struct everything_fits {
+  unsigned int ef1 : 2;
+  unsigned int ef2 : 29;
+  unsigned int ef3 : 1;
+
+  unsigned int ef4 : 16;
+  unsigned int ef5 : 16;
+
+  unsigned int ef6 : 7;
+  unsigned int ef7 : 25;
+};
+void ef(struct everything_fits *x) {}
+// CHECK32: %struct.everything_fits = type { i32, i32, i32 }
+// CHECK64: %struct.everything_fits = type <{ i64, i32 }>
+
+struct not_lined_up {
+  uint64_t nlu1 : 31;
+  uint64_t nlu2 : 2;
+  uint64_t nlu3 : 32;
+  uint64_t nlu4 : 31;
+};
+void nlu(struct not_lined_up *x) {}
+// CHECK32: %struct.not_lined_up = type { i96 }
+// CHECK64: %struct.not_lined_up = type { i40, i64 }
+
+struct padding_between_words {
+  unsigned int pbw1 : 16;
+  unsigned int pbw2 : 14;
+
+  unsigned int pbw3 : 12;
+  unsigned int pbw4 : 16;
+
+  unsigned int pbw5 : 8;
+  unsigned int pbw6 : 10;
+
+  unsigned int pbw7 : 20;
+  unsigned int pbw8 : 10;
+};
+void pbw(struct padding_between_words *x) {}
+// CHECK32: %struct.padding_between_words = type { i32, i32, i24, i32 }
+// CHECK64: %struct.padding_between_words = type { i32, i32, i24, i32 }
+
+struct unaligned_are_coalesced {
+  uint64_t uac1 : 16;
+  uint64_t uac2 : 32;
+  uint64_t uac3 : 16;
+  uint64_t uac4 : 48;
+  uint64_t uac5 : 64;
+  uint64_t uac6 : 16;
+  uint64_t uac7 : 32;
+};
+void uac(struct unaligned_are_coalesced *x) {}
+// CHECK32: %struct.unaligned_are_coalesced = type { i112, i112 }
+// CHECK64: %struct.unaligned_are_coalesced = type { i64, i48, i64, i48 }





More information about the cfe-commits mailing list