aboutsummaryrefslogtreecommitdiff
path: root/tccgen.c
diff options
context:
space:
mode:
authorMichael Matz <matz@suse.de>2016-10-09 02:41:34 +0200
committerMichael Matz <matz@suse.de>2016-12-15 17:49:56 +0100
commit8859dc9e6d56e1d0f1d4eb4302a360899ec17c7d (patch)
treea600c602f6298f1f4094373180078135c5cb4d6e /tccgen.c
parentd815a0f658273d2226f0d89601fd477969f60d68 (diff)
downloadtinycc-8859dc9e6d56e1d0f1d4eb4302a360899ec17c7d.tar.gz
tinycc-8859dc9e6d56e1d0f1d4eb4302a360899ec17c7d.tar.bz2
Support large alignment requests
The linux kernel has some structures that are page aligned, i.e. 4096. Instead of enlarging the bit fields to specify this, use the fact that alignment is always power of two, and store only the log2 minus 1 of it. The 5 bits are enough to specify an alignment of 1 << 30.
Diffstat (limited to 'tccgen.c')
-rw-r--r--tccgen.c36
1 files changed, 30 insertions, 6 deletions
diff --git a/tccgen.c b/tccgen.c
index 6ea62e2..75959ad 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -3062,6 +3062,24 @@ ST_FUNC void parse_mult_str (CString *astr, const char *msg)
cstr_ccat(astr, '\0');
}
+/* If I is >= 1 and a power of two, returns log2(i)+1.
+ If I is 0 returns 0. */
+static int exact_log2p1(int i)
+{
+ int ret;
+ if (!i)
+ return 0;
+ for (ret = 1; i >= 1 << 8; ret += 8)
+ i >>= 8;
+ if (i >= 1 << 4)
+ ret += 4, i >>= 4;
+ if (i >= 1 << 2)
+ ret += 2, i >>= 2;
+ if (i >= 1 << 1)
+ ret++;
+ return ret;
+}
+
/* Parse GNUC __attribute__ extension. Currently, the following
extensions are recognized:
- aligned(n) : set data/function alignment.
@@ -3131,7 +3149,9 @@ static void parse_attribute(AttributeDef *ad)
} else {
n = MAX_ALIGN;
}
- ad->a.aligned = n;
+ ad->a.aligned = exact_log2p1(n);
+ if (n != 1 << (ad->a.aligned - 1))
+ tcc_error("alignment of %d is larger than implemented", n);
break;
case TOK_PACKED1:
case TOK_PACKED2:
@@ -3270,7 +3290,7 @@ static void struct_layout(CType *type, AttributeDef *ad)
int pcc = !tcc_state->ms_bitfields;
Sym *f;
if (ad->a.aligned)
- maxalign = ad->a.aligned;
+ maxalign = 1 << (ad->a.aligned - 1);
else
maxalign = 1;
offset = 0;
@@ -3293,6 +3313,8 @@ static void struct_layout(CType *type, AttributeDef *ad)
align = f->r;
} else if (ad->a.packed || f->r == 1) {
align = 1;
+ /* Packed fields or packed records don't let the base type
+ influence the records type alignment. */
typealign = 1;
} else {
align = typealign;
@@ -3587,8 +3609,9 @@ static void struct_decl(CType *type, AttributeDef *ad, int u)
/* Only remember non-default alignment. */
alignoverride = 0;
if (ad1.a.aligned) {
- if (align < ad1.a.aligned)
- alignoverride = ad1.a.aligned;
+ int speca = 1 << (ad1.a.aligned - 1);
+ if (align < speca)
+ alignoverride = speca;
} else if (ad1.a.packed || ad->a.packed) {
alignoverride = 1;
} else if (*tcc_state->pack_stack_ptr) {
@@ -6594,8 +6617,9 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
* pointed_size(&flexible_array->type);
/* take into account specified alignment if bigger */
if (ad->a.aligned) {
- if (ad->a.aligned > align)
- align = ad->a.aligned;
+ int speca = 1 << (ad->a.aligned - 1);
+ if (speca > align)
+ align = speca;
} else if (ad->a.packed) {
align = 1;
}