GCCで8bit長・16bit長のビットフィールドが正しく扱われない(STRICT_ALGINMENTな環境でもアライン無視する、volatile付けると領域破壊を起こす)問題を修正した。
BTSには投げたけれど、多分無視されるのでここにパッチを置いておく(gcc-4_6-branch/trunkにて動作確認)。
I fixed the problem around handling bit-field (GCC generates wrong code when using 8bit or 16bit width of bit-field.)
Patch is here (also posted to BTS.)
diff --git a/gcc/expr.c b/gcc/expr.c
index a4cfee0..a2823a2 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -4689,7 +4689,7 @@ expand_assignment (tree to, tree from, bool nontemporal)
use BLKmode for it instead. */
if (MEM_P (to_rtx))
{
- if (volatilep && flag_strict_volatile_bitfields > 0)
+ if (STRICT_ALIGNMENT || (volatilep && flag_strict_volatile_bitfields > 0))
to_rtx = adjust_address (to_rtx, mode1, 0);
else if (GET_MODE (to_rtx) == VOIDmode)
to_rtx = adjust_address (to_rtx, BLKmode, 0);
@@ -6345,7 +6345,9 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
store it as a bit field. */
|| (mode != BLKmode
&& ((((MEM_ALIGN (target) < GET_MODE_ALIGNMENT (mode))
- || bitpos % GET_MODE_ALIGNMENT (mode))
+ || bitpos % GET_MODE_ALIGNMENT (mode)
+ || (TREE_THIS_VOLATILE (type)
+ && flag_strict_volatile_bitfields > 0))
&& SLOW_UNALIGNED_ACCESS (mode, MEM_ALIGN (target)))
|| (bitpos % BITS_PER_UNIT != 0)))
/* If the RHS and field are a constant size and the size of the
@@ -6510,8 +6512,8 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
mode = DECL_MODE (field);
else if (DECL_MODE (field) == BLKmode)
blkmode_bitfield = true;
- else if (TREE_THIS_VOLATILE (exp)
- && flag_strict_volatile_bitfields > 0)
+ else if (STRICT_ALIGNMENT || (TREE_THIS_VOLATILE (exp)
+ && flag_strict_volatile_bitfields > 0))
/* Volatile bitfields should be accessed in the mode of the
field's type, not the mode computed based on the bit
size. */
@@ -9624,7 +9626,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
use BLKmode for it instead. */
if (MEM_P (op0))
{
- if (volatilep && flag_strict_volatile_bitfields > 0)
+ if (STRICT_ALIGNMENT || (volatilep && flag_strict_volatile_bitfields > 0))
op0 = adjust_address (op0, mode1, 0);
else if (GET_MODE (op0) == VOIDmode)
op0 = adjust_address (op0, BLKmode, 0);
diff --git a/gcc/stor-layout.c b/gcc/stor-layout.c
index 359541e..7ebba2f 100644
--- a/gcc/stor-layout.c
+++ b/gcc/stor-layout.c
@@ -626,6 +626,7 @@ layout_decl (tree decl, unsigned int known_align)
if (TYPE_SIZE (type) != 0
&& TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
&& GET_MODE_CLASS (TYPE_MODE (type)) == MODE_INT
+ && !STRICT_ALIGNMENT
&& !(TREE_THIS_VOLATILE (decl)
&& flag_strict_volatile_bitfields > 0))
{