aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tcc.h2
-rw-r--r--tccgen.c36
-rw-r--r--tests/tcctest.c7
3 files changed, 38 insertions, 7 deletions
diff --git a/tcc.h b/tcc.h
index 7630f4c..9b65e6d 100644
--- a/tcc.h
+++ b/tcc.h
@@ -379,7 +379,7 @@ typedef struct SValue {
struct Attribute {
unsigned
func_call : 3, /* calling convention (0..5), see below */
- aligned : 5, /* alignement (0..16) */
+ aligned : 5, /* alignment as log2+1 (0 == unspecified) */
packed : 1,
func_export : 1,
func_import : 1,
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;
}
diff --git a/tests/tcctest.c b/tests/tcctest.c
index 9fcd7a4..68f8db6 100644
--- a/tests/tcctest.c
+++ b/tests/tcctest.c
@@ -1048,6 +1048,11 @@ int pad1;
a copy of it).
struct aligntest7 altest7[2] __attribute__((aligned(16)));*/
+struct aligntest8
+{
+ int i;
+} __attribute__((aligned(4096)));
+
struct Large {
unsigned long flags;
union {
@@ -1129,6 +1134,8 @@ void struct_test()
sizeof(struct aligntest6), __alignof__(struct aligntest6));
printf("aligntest7 sizeof=%d alignof=%d\n",
sizeof(struct aligntest7), __alignof__(struct aligntest7));
+ printf("aligntest8 sizeof=%d alignof=%d\n",
+ sizeof(struct aligntest8), __alignof__(struct aligntest8));
printf("altest5 sizeof=%d alignof=%d\n",
sizeof(altest5), __alignof__(altest5));
printf("altest6 sizeof=%d alignof=%d\n",