+static entity_t *pack_bitfield_members(il_size_t *struct_offset,
+ il_alignment_t *struct_alignment,
+ bool packed, entity_t *first)
+{
+ il_size_t offset = *struct_offset;
+ il_alignment_t alignment = *struct_alignment;
+ size_t bit_offset = 0;
+
+ entity_t *member;
+ for (member = first; member != NULL; member = member->base.next) {
+ if (member->kind != ENTITY_COMPOUND_MEMBER)
+ continue;
+ if (!member->compound_member.bitfield)
+ break;
+
+ type_t *const base_type = skip_typeref(member->declaration.type);
+ il_alignment_t base_alignment = get_type_alignment_compound(base_type);
+ il_alignment_t alignment_mask = base_alignment-1;
+ alignment = MAX(alignment, base_alignment);
+
+ size_t bit_size = member->compound_member.bit_size;
+ if (!packed) {
+ bit_offset += (offset & alignment_mask) * BITS_PER_BYTE;
+ offset &= ~alignment_mask;
+ size_t base_size = get_type_size(base_type) * BITS_PER_BYTE;
+
+ if (bit_offset + bit_size > base_size || bit_size == 0) {
+ offset += (bit_offset+BITS_PER_BYTE-1) / BITS_PER_BYTE;
+ offset = (offset + base_alignment-1) & ~alignment_mask;
+ bit_offset = 0;
+ }
+ }
+
+ if (byte_order_big_endian) {
+ size_t base_size = get_type_size(base_type) * BITS_PER_BYTE;
+ member->compound_member.offset = offset & ~alignment_mask;
+ member->compound_member.bit_offset = base_size - bit_offset - bit_size;
+ } else {
+ member->compound_member.offset = offset;
+ member->compound_member.bit_offset = bit_offset;
+ }
+
+ bit_offset += bit_size;
+ offset += bit_offset / BITS_PER_BYTE;
+ bit_offset %= BITS_PER_BYTE;
+ }
+
+ if (bit_offset > 0)
+ offset += 1;
+
+ *struct_offset = offset;
+ *struct_alignment = alignment;
+ return member;
+}
+
+void layout_struct_type(compound_type_t *type)
+{
+ assert(type->compound != NULL);
+
+ compound_t *compound = type->compound;
+ if (!compound->complete)
+ return;
+ if (type->compound->layouted)
+ return;
+ compound->layouted = true;
+
+ il_size_t offset = 0;
+ il_alignment_t alignment = compound->alignment;
+ bool need_pad = false;
+
+ entity_t *entry = compound->members.entities;
+ while (entry != NULL) {
+ if (entry->kind != ENTITY_COMPOUND_MEMBER)
+ goto next;
+
+ type_t *const m_type = skip_typeref(entry->declaration.type);
+ if (!is_type_valid(m_type))
+ goto next;
+
+ if (entry->compound_member.bitfield) {
+ entry = pack_bitfield_members(&offset, &alignment,
+ compound->packed, entry);
+ continue;
+ }
+
+ il_alignment_t m_alignment = get_type_alignment_compound(m_type);
+ alignment = MAX(alignment, m_alignment);
+
+ if (!compound->packed) {
+ il_size_t const new_offset = round_up2(offset, m_alignment);
+ if (new_offset > offset) {
+ need_pad = true;
+ offset = new_offset;
+ }
+ }
+
+ entry->compound_member.offset = offset;
+ offset += get_type_size(m_type);
+
+next:
+ entry = entry->base.next;
+ }
+
+ if (!compound->packed) {
+ il_size_t const new_offset = round_up2(offset, alignment);
+ if (new_offset > offset) {
+ need_pad = true;
+ offset = new_offset;
+ }
+ }
+
+ position_t const *const pos = &compound->base.pos;
+ if (need_pad) {
+ warningf(WARN_PADDED, pos, "'%T' needs padding", type);
+ } else if (compound->packed) {
+ warningf(WARN_PACKED, pos, "superfluous packed attribute on '%T'", type);
+ }
+
+ compound->size = offset;
+ compound->alignment = alignment;
+}
+
+void layout_union_type(compound_type_t *type)
+{
+ assert(type->compound != NULL);
+
+ compound_t *compound = type->compound;
+ if (! compound->complete)
+ return;
+ if (compound->layouted)
+ return;
+ compound->layouted = true;
+
+ il_size_t size = 0;
+ il_alignment_t alignment = compound->alignment;
+
+ entity_t *entry = compound->members.entities;
+ for (; entry != NULL; entry = entry->base.next) {
+ if (entry->kind != ENTITY_COMPOUND_MEMBER)
+ continue;
+
+ type_t *m_type = skip_typeref(entry->declaration.type);
+ if (! is_type_valid(skip_typeref(m_type)))
+ continue;
+
+ entry->compound_member.offset = 0;
+ il_size_t m_size = get_type_size(m_type);
+ size = MAX(size, m_size);
+ il_alignment_t m_alignment = get_type_alignment_compound(m_type);
+ alignment = MAX(alignment, m_alignment);
+ }
+ size = round_up2(size, alignment);
+
+ compound->size = size;
+ compound->alignment = alignment;
+}
+
+function_parameter_t *allocate_parameter(type_t *const type)
+{
+ function_parameter_t *const param = obstack_alloc(&type_obst, sizeof(*param));
+ memset(param, 0, sizeof(*param));
+ param->type = type;
+ return param;
+}
+
+type_t *make_function_2_type(type_t *return_type, type_t *argument_type1,
+ type_t *argument_type2, decl_modifiers_t modifiers)
+{
+ function_parameter_t *const parameter2 = allocate_parameter(argument_type2);
+ function_parameter_t *const parameter1 = allocate_parameter(argument_type1);
+ parameter1->next = parameter2;
+
+ type_t *type = allocate_type_zero(TYPE_FUNCTION);
+ type->function.return_type = return_type;
+ type->function.parameters = parameter1;
+ type->function.modifiers |= modifiers;
+ type->function.linkage = LINKAGE_C;
+
+ return identify_new_type(type);
+}
+
+type_t *make_function_1_type(type_t *return_type, type_t *argument_type,
+ decl_modifiers_t modifiers)
+{
+ function_parameter_t *const parameter = allocate_parameter(argument_type);
+
+ type_t *type = allocate_type_zero(TYPE_FUNCTION);
+ type->function.return_type = return_type;
+ type->function.parameters = parameter;
+ type->function.modifiers |= modifiers;
+ type->function.linkage = LINKAGE_C;
+
+ return identify_new_type(type);
+}
+
+type_t *make_function_1_type_variadic(type_t *return_type,
+ type_t *argument_type,
+ decl_modifiers_t modifiers)
+{
+ function_parameter_t *const parameter = allocate_parameter(argument_type);
+
+ type_t *type = allocate_type_zero(TYPE_FUNCTION);
+ type->function.return_type = return_type;
+ type->function.parameters = parameter;
+ type->function.variadic = true;
+ type->function.modifiers |= modifiers;
+ type->function.linkage = LINKAGE_C;
+
+ return identify_new_type(type);
+}
+
+type_t *make_function_0_type(type_t *return_type, decl_modifiers_t modifiers)
+{
+ type_t *type = allocate_type_zero(TYPE_FUNCTION);
+ type->function.return_type = return_type;
+ type->function.parameters = NULL;
+ type->function.modifiers |= modifiers;
+ type->function.linkage = LINKAGE_C;
+
+ return identify_new_type(type);
+}
+
+type_t *make_function_type(type_t *return_type, int n_types,
+ type_t *const *argument_types,
+ decl_modifiers_t modifiers)
+{
+ type_t *type = allocate_type_zero(TYPE_FUNCTION);
+ type->function.return_type = return_type;
+ type->function.modifiers |= modifiers;
+ type->function.linkage = LINKAGE_C;
+
+ function_parameter_t **anchor = &type->function.parameters;
+ for (int i = 0; i < n_types; ++i) {
+ function_parameter_t *parameter = allocate_parameter(argument_types[i]);
+ *anchor = parameter;
+ anchor = ¶meter->next;
+ }
+
+ return identify_new_type(type);
+}
+