diff options
| author | Ginger Bill <bill@gingerbill.org> | 2016-11-16 12:36:02 +0000 |
|---|---|---|
| committer | Ginger Bill <bill@gingerbill.org> | 2016-11-16 12:36:02 +0000 |
| commit | e2d98324bae3c8e5f5e41d0fad9b67bfe2d345d1 (patch) | |
| tree | 3a8223c461bbb0c04d2fb72ce773002ff3b184b4 /src | |
| parent | 0cab083b8fb31f33e96b68f3699ba5a83dbd3353 (diff) | |
Fix alignment issues with vectors, unions, and raw_unions
Diffstat (limited to 'src')
| -rw-r--r-- | src/checker/checker.cpp | 6 | ||||
| -rw-r--r-- | src/checker/expr.cpp | 10 | ||||
| -rw-r--r-- | src/checker/types.cpp | 33 | ||||
| -rw-r--r-- | src/ssa.cpp | 74 | ||||
| -rw-r--r-- | src/ssa_print.cpp | 44 |
5 files changed, 117 insertions, 50 deletions
diff --git a/src/checker/checker.cpp b/src/checker/checker.cpp index a2eb0c2b1..218cfbd4b 100644 --- a/src/checker/checker.cpp +++ b/src/checker/checker.cpp @@ -520,6 +520,9 @@ void init_universal_scope(void) { entity->Builtin.id = id; add_global_entity(entity); } + + t_u8_ptr = make_type_pointer(a, t_u8); + t_int_ptr = make_type_pointer(a, t_int); } @@ -920,9 +923,6 @@ Map<Entity *> generate_minimum_dependency_map(CheckerInfo *info, Entity *start) void init_preload_types(Checker *c) { PROF_PROC(); - if (t_u8_ptr == NULL) { - t_u8_ptr = make_type_pointer(c->allocator, t_u8); - } if (t_type_info == NULL) { Entity *e = current_scope_lookup_entity(c->global_scope, make_string("Type_Info")); diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp index c42040ad5..b0b7a0f9c 100644 --- a/src/checker/expr.cpp +++ b/src/checker/expr.cpp @@ -820,10 +820,13 @@ Type *check_get_params(Checker *c, Scope *scope, AstNodeArray params, b32 *is_va } } - if (is_variadic && params.count > 0) { + variable_count = variable_index; + + if (is_variadic) { + GB_ASSERT(params.count > 0); // NOTE(bill): Change last variadic parameter to be a slice // Custom Calling convention for variadic parameters - Entity *end = variables[params.count-1]; + Entity *end = variables[variable_count-1]; end->type = make_type_slice(c->allocator, end->type); } @@ -3458,6 +3461,7 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode defer (gb_string_free(proc_str)); error(ast_node_token(call), err_fmt, proc_str, param_count); operand->mode = Addressing_Invalid; + return; } GB_ASSERT(proc_type->Proc.params != NULL); @@ -3467,7 +3471,6 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode Type *arg_type = sig_params[operand_index]->type; Operand o = operands[operand_index]; if (variadic) { - o = operands[operand_index]; } check_assignment(c, &o, arg_type, make_string("argument"), true); @@ -3476,6 +3479,7 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode if (variadic) { b32 variadic_expand = false; Type *slice = sig_params[param_count]->type; + GB_ASSERT(is_type_slice(slice)); Type *elem = base_type(slice)->Slice.elem; Type *t = elem; for (; operand_index < operands.count; operand_index++) { diff --git a/src/checker/types.cpp b/src/checker/types.cpp index ba1ace5ff..98b5f297f 100644 --- a/src/checker/types.cpp +++ b/src/checker/types.cpp @@ -364,7 +364,8 @@ gb_global Type *t_byte = &basic_type_aliases[0]; gb_global Type *t_rune = &basic_type_aliases[1]; -gb_global Type *t_u8_ptr = NULL; +gb_global Type *t_u8_ptr = NULL; +gb_global Type *t_int_ptr = NULL; gb_global Type *t_type_info = NULL; gb_global Type *t_type_info_ptr = NULL; @@ -908,25 +909,26 @@ Selection lookup_field(gbAllocator a, Type *type_, String field_name, b32 is_typ sel.entity = make_entity_constant(a, NULL, make_token_ident(count_str), t_int, make_exact_value_integer(type->Vector.count)); return sel; } + if (type->Vector.count <= 4 && !is_type_boolean(type->Vector.elem)) { // HACK(bill): Memory leak switch (type->Vector.count) { - #define _VECTOR_FIELD(_name, length) \ - case (length): \ + #define _VECTOR_FIELD_CASE(_length, _name) \ + case (_length): \ if (field_name == _name) { \ - selection_add_index(&sel, (length)-1); \ - sel.entity = make_entity_field(a, NULL, make_token_ident(make_string(_name)), type->Vector.elem, false, (length)-1); \ + selection_add_index(&sel, (_length)-1); \ + sel.entity = make_entity_vector_elem(a, NULL, make_token_ident(make_string(_name)), type->Vector.elem, (_length)-1); \ return sel; \ } \ /*fallthrough*/ - _VECTOR_FIELD("w", 4); - _VECTOR_FIELD("z", 3); - _VECTOR_FIELD("y", 2); - _VECTOR_FIELD("x", 1); - case 0: break; + _VECTOR_FIELD_CASE(4, "w"); + _VECTOR_FIELD_CASE(3, "z"); + _VECTOR_FIELD_CASE(2, "y"); + _VECTOR_FIELD_CASE(1, "x"); + default: break; - #undef _VECTOR_FIELD + #undef _VECTOR_FIELD_CASE } } @@ -1057,10 +1059,9 @@ i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t) { return type_align_of(s, allocator, t->Array.elem); case Type_Vector: { i64 size = type_size_of(s, allocator, t->Vector.elem); - size *= t->Vector.count; - size = prev_pow2(size); - // TODO(bill): Type_Vector type_align_of - return gb_clamp(size, 1, s.max_align); + i64 count = gb_max(prev_pow2(size), 1); + i64 total = size * count; + return gb_clamp(total, 1, s.max_align); } break; case Type_Tuple: { @@ -1097,7 +1098,7 @@ i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t) { } break; case TypeRecord_Union: { - i64 max = s.word_size; + i64 max = 1; for (isize i = 1; i < t->Record.field_count; i++) { // NOTE(bill): field zero is null i64 align = type_align_of(s, allocator, t->Record.fields[i]->type); diff --git a/src/ssa.cpp b/src/ssa.cpp index 060be979c..a20756e7d 100644 --- a/src/ssa.cpp +++ b/src/ssa.cpp @@ -128,6 +128,8 @@ struct ssaProcedure { SSA_INSTR_KIND(StructElementPtr), \ SSA_INSTR_KIND(ArrayExtractValue), \ SSA_INSTR_KIND(StructExtractValue), \ + SSA_INSTR_KIND(UnionTagPtr), \ + SSA_INSTR_KIND(UnionTagValue), \ SSA_INSTR_KIND(Conv), \ SSA_INSTR_KIND(Jump), \ SSA_INSTR_KIND(If), \ @@ -234,6 +236,14 @@ struct ssaInstr { i32 index; } StructExtractValue; struct { + ssaValue *address; + Type *type; // ^int + } UnionTagPtr; + struct { + ssaValue *address; + Type *type; // int + } UnionTagValue; + struct { ssaValue *value; ssaValue *elem; i32 index; @@ -559,6 +569,10 @@ Type *ssa_instr_type(ssaInstr *instr) { return instr->ArrayExtractValue.result_type; case ssaInstr_StructExtractValue: return instr->StructExtractValue.result_type; + case ssaInstr_UnionTagPtr: + return instr->UnionTagPtr.type; + case ssaInstr_UnionTagValue: + return instr->UnionTagValue.type; case ssaInstr_BinaryOp: return instr->BinaryOp.type; case ssaInstr_Conv: @@ -870,6 +884,23 @@ ssaValue *ssa_make_instr_struct_extract_value(ssaProcedure *p, ssaValue *address return v; } +ssaValue *ssa_make_instr_union_tag_ptr(ssaProcedure *p, ssaValue *address) { + ssaValue *v = ssa_alloc_instr(p, ssaInstr_UnionTagPtr); + ssaInstr *i = &v->Instr; + i->UnionTagPtr.address = address; + i->UnionTagPtr.type = t_int_ptr; + return v; +} + +ssaValue *ssa_make_instr_union_tag_value(ssaProcedure *p, ssaValue *address) { + ssaValue *v = ssa_alloc_instr(p, ssaInstr_UnionTagValue); + ssaInstr *i = &v->Instr; + i->UnionTagValue.address = address; + i->UnionTagValue.type = t_int_ptr; + return v; +} + + ssaValue *ssa_make_instr_binary_op(ssaProcedure *p, TokenKind op, ssaValue *left, ssaValue *right, Type *type) { ssaValue *v = ssa_alloc_instr(p, ssaInstr_BinaryOp); ssaInstr *i = &v->Instr; @@ -1535,6 +1566,20 @@ ssaValue *ssa_emit_array_ep(ssaProcedure *proc, ssaValue *s, i32 index) { return ssa_emit_array_ep(proc, s, ssa_make_const_i32(proc->module->allocator, index)); } +ssaValue *ssa_emit_union_tag_ptr(ssaProcedure *proc, ssaValue *u) { + Type *t = ssa_type(u); + GB_ASSERT(is_type_pointer(t) && + is_type_union(type_deref(t))); + return ssa_emit(proc, ssa_make_instr_union_tag_ptr(proc, u)); +} + +ssaValue *ssa_emit_union_tag_value(ssaProcedure *proc, ssaValue *u) { + Type *t = ssa_type(u); + GB_ASSERT(is_type_union(t)); + return ssa_emit(proc, ssa_make_instr_union_tag_value(proc, u)); +} + + ssaValue *ssa_emit_struct_ep(ssaProcedure *proc, ssaValue *s, i32 index) { gbAllocator a = proc->module->allocator; @@ -1571,15 +1616,6 @@ ssaValue *ssa_emit_struct_ep(ssaProcedure *proc, ssaValue *s, i32 index) { case 0: result_type = make_type_pointer(a, t->Maybe.elem); break; case 1: result_type = make_type_pointer(a, t_bool); break; } - } else if (is_type_union(t)) { - switch (index) { - case 1: result_type = make_type_pointer(a, t_int); break; - - case 0: - default: - GB_PANIC("TODO(bill): struct_gep 0 for unions"); - break; - } } else { GB_PANIC("TODO(bill): struct_gep type: %s, %d", type_to_string(ssa_type(s)), index); } @@ -1634,15 +1670,6 @@ ssaValue *ssa_emit_struct_ev(ssaProcedure *proc, ssaValue *s, i32 index) { case 0: result_type = t->Maybe.elem; break; case 1: result_type = t_bool; break; } - } else if (is_type_union(t)) { - switch (index) { - case 1: result_type = t_int; break; - - case 0: - default: - GB_PANIC("TODO(bill): struct_gep 0 for unions"); - break; - } } else { GB_PANIC("TODO(bill): struct_ev type: %s, %d", type_to_string(ssa_type(s)), index); } @@ -1718,8 +1745,9 @@ ssaValue *ssa_emit_deep_field_ev(ssaProcedure *proc, Type *type, ssaValue *e, Se if (is_type_raw_union(type)) { + GB_PANIC("TODO(bill): IS THIS EVEN CORRECT?"); type = type->Record.fields[index]->type; - e = ssa_emit_conv(proc, e, make_type_pointer(proc->module->allocator, type)); + e = ssa_emit_conv(proc, e, type); } else { e = ssa_emit_struct_ev(proc, e, index); } @@ -1990,7 +2018,7 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t) { gbAllocator allocator = proc->module->allocator; ssaValue *parent = ssa_add_local_generated(proc, t); ssaValue *tag = ssa_make_const_int(allocator, i); - ssa_emit_store(proc, ssa_emit_struct_ep(proc, parent, 1), tag); + ssa_emit_store(proc, ssa_emit_union_tag_ptr(proc, parent), tag); ssaValue *data = ssa_emit_conv(proc, parent, t_rawptr); @@ -2189,7 +2217,7 @@ ssaValue *ssa_emit_union_cast(ssaProcedure *proc, ssaValue *value, Type *tuple) Type *dst_ptr = tuple->Tuple.variables[0]->type; Type *dst = type_deref(dst_ptr); - ssaValue *tag = ssa_emit_load(proc, ssa_emit_struct_ep(proc, value, 1)); + ssaValue *tag = ssa_emit_load(proc, ssa_emit_union_tag_ptr(proc, value)); ssaValue *dst_tag = NULL; for (isize i = 1; i < src->Record.field_count; i++) { Entity *f = src->Record.fields[i]; @@ -2222,7 +2250,7 @@ ssaValue *ssa_emit_union_cast(ssaProcedure *proc, ssaValue *value, Type *tuple) Type *dst = tuple->Tuple.variables[0]->type; Type *dst_ptr = make_type_pointer(a, dst); - ssaValue *tag = ssa_emit_struct_ev(proc, value, 1); + ssaValue *tag = ssa_emit_union_tag_value(proc, value); ssaValue *dst_tag = NULL; for (isize i = 1; i < src->Record.field_count; i++) { Entity *f = src->Record.fields[i]; @@ -4228,7 +4256,7 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { GB_ASSERT(is_type_union(union_type)); ssa_emit_comment(proc, make_string("get union's tag")); - ssaValue *tag_index = ssa_emit_struct_ep(proc, parent, 1); + ssaValue *tag_index = ssa_emit_union_tag_ptr(proc, parent); tag_index = ssa_emit_load(proc, tag_index); ssaValue *data = ssa_emit_conv(proc, parent, t_rawptr); diff --git a/src/ssa_print.cpp b/src/ssa_print.cpp index 3c75d8212..e02c58513 100644 --- a/src/ssa_print.cpp +++ b/src/ssa_print.cpp @@ -212,12 +212,19 @@ void ssa_print_type(ssaFileBuffer *f, ssaModule *m, Type *t) { } break; case TypeRecord_Union: { - i64 size_of_union = type_size_of(s, heap_allocator(), t) - s.word_size; - ssa_fprintf(f, "{[%lld x i8], i%lld}", size_of_union, word_bits); + // NOTE(bill): The zero size array is used to fix the alignment used in a structure as + // LLVM takes the first element's alignment as the entire alignment (like C) + i64 size_of_union = type_size_of(s, heap_allocator(), t) - s.word_size; + i64 align_of_union = type_align_of(s, heap_allocator(), t); + ssa_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8], i%lld}", align_of_union, size_of_union, word_bits); + } break; + case TypeRecord_RawUnion: { + // NOTE(bill): The zero size array is used to fix the alignment used in a structure as + // LLVM takes the first element's alignment as the entire alignment (like C) + i64 size_of_union = type_size_of(s, heap_allocator(), t); + i64 align_of_union = type_align_of(s, heap_allocator(), t); + ssa_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8]}", align_of_union, size_of_union); } break; - case TypeRecord_RawUnion: - ssa_fprintf(f, "[%lld x i8]", type_size_of(s, heap_allocator(), t)); - break; case TypeRecord_Enum: ssa_print_type(f, m, t->Record.enum_base); break; @@ -748,6 +755,33 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) { ssa_fprintf(f, ", %d\n", instr->StructExtractValue.index); } break; + case ssaInstr_UnionTagPtr: { + Type *et = ssa_type(instr->UnionTagPtr.address); + ssa_fprintf(f, "%%%d = getelementptr inbounds ", value->index); + + ssa_print_type(f, m, type_deref(et)); + ssa_fprintf(f, ", "); + ssa_print_type(f, m, et); + ssa_fprintf(f, " "); + ssa_print_value(f, m, instr->UnionTagPtr.address, et); + ssa_fprintf(f, ", "); + ssa_print_type(f, m, t_int); + ssa_fprintf(f, " 0, "); + ssa_print_type(f, m, t_i32); + ssa_fprintf(f, " %d", 2); + ssa_fprintf(f, "\n"); + } break; + + case ssaInstr_UnionTagValue: { + Type *et = ssa_type(instr->UnionTagValue.address); + ssa_fprintf(f, "%%%d = extractvalue ", value->index); + + ssa_print_type(f, m, et); + ssa_fprintf(f, " "); + ssa_print_value(f, m, instr->UnionTagValue.address, et); + ssa_fprintf(f, ", %d\n", 2); + } break; + case ssaInstr_Jump: {; ssa_fprintf(f, "br label %%"); ssa_print_block_name(f, instr->Jump.block); |