From 899fb14c30f34cea811bbf361124b15dc41eea71 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 23 Apr 2016 13:58:30 -0700 Subject: [PATCH] fix handling of slice of zero bits type closes #143 --- src/analyze.cpp | 122 ++++++++++++++++++++++++++++--------------- src/codegen.cpp | 46 +++++++++++----- test/self_hosted.zig | 8 +++ 3 files changed, 121 insertions(+), 55 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index b0efb7bbc1..ae8a4213db 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -494,18 +494,6 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_c buf_appendf(&entry->name, "[]%s", buf_ptr(&child_type->name)); entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(&entry->name)); - TypeTableEntry *pointer_type = get_pointer_to_type(g, child_type, is_const); - - unsigned element_count = 2; - LLVMTypeRef element_types[] = { - pointer_type->type_ref, - g->builtin_types.entry_isize->type_ref, - }; - LLVMStructSetBody(entry->type_ref, element_types, element_count, false); - - slice_type_common_init(g, child_type, is_const, entry); - - LLVMZigDIScope *compile_unit_scope = LLVMZigCompileUnitToScope(g->compile_unit); LLVMZigDIFile *di_file = nullptr; unsigned line = 0; @@ -513,40 +501,90 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_c LLVMZigTag_DW_structure_type(), buf_ptr(&entry->name), compile_unit_scope, di_file, line); - uint64_t ptr_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, pointer_type->type_ref); - uint64_t ptr_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, pointer_type->type_ref); - uint64_t ptr_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, 0); + if (child_type->zero_bits) { + LLVMTypeRef element_types[] = { + g->builtin_types.entry_isize->type_ref, + }; + LLVMStructSetBody(entry->type_ref, element_types, 1, false); - TypeTableEntry *isize_type = g->builtin_types.entry_isize; - uint64_t len_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, isize_type->type_ref); - uint64_t len_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, isize_type->type_ref); - uint64_t len_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, 1); + slice_type_common_init(g, child_type, is_const, entry); - uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref); - uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref); + entry->data.structure.gen_field_count = 1; + entry->data.structure.fields[0].gen_index = -1; + entry->data.structure.fields[1].gen_index = 0; - LLVMZigDIType *di_element_types[] = { - LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type), - "ptr", di_file, line, - ptr_debug_size_in_bits, - ptr_debug_align_in_bits, - ptr_offset_in_bits, - 0, pointer_type->di_type), - LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type), - "len", di_file, line, - len_debug_size_in_bits, - len_debug_align_in_bits, - len_offset_in_bits, - 0, isize_type->di_type), - }; - LLVMZigDIType *replacement_di_type = LLVMZigCreateDebugStructType(g->dbuilder, - compile_unit_scope, - buf_ptr(&entry->name), - di_file, line, debug_size_in_bits, debug_align_in_bits, 0, - nullptr, di_element_types, 2, 0, nullptr, ""); + TypeTableEntry *isize_type = g->builtin_types.entry_isize; + uint64_t len_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, isize_type->type_ref); + uint64_t len_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, isize_type->type_ref); + uint64_t len_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, 0); - LLVMZigReplaceTemporary(g->dbuilder, entry->di_type, replacement_di_type); - entry->di_type = replacement_di_type; + uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref); + uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref); + + LLVMZigDIType *di_element_types[] = { + LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type), + "len", di_file, line, + len_debug_size_in_bits, + len_debug_align_in_bits, + len_offset_in_bits, + 0, isize_type->di_type), + }; + LLVMZigDIType *replacement_di_type = LLVMZigCreateDebugStructType(g->dbuilder, + compile_unit_scope, + buf_ptr(&entry->name), + di_file, line, debug_size_in_bits, debug_align_in_bits, 0, + nullptr, di_element_types, 1, 0, nullptr, ""); + + LLVMZigReplaceTemporary(g->dbuilder, entry->di_type, replacement_di_type); + entry->di_type = replacement_di_type; + } else { + TypeTableEntry *pointer_type = get_pointer_to_type(g, child_type, is_const); + + unsigned element_count = 2; + LLVMTypeRef element_types[] = { + pointer_type->type_ref, + g->builtin_types.entry_isize->type_ref, + }; + LLVMStructSetBody(entry->type_ref, element_types, element_count, false); + + slice_type_common_init(g, child_type, is_const, entry); + + + uint64_t ptr_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, pointer_type->type_ref); + uint64_t ptr_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, pointer_type->type_ref); + uint64_t ptr_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, 0); + + TypeTableEntry *isize_type = g->builtin_types.entry_isize; + uint64_t len_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, isize_type->type_ref); + uint64_t len_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, isize_type->type_ref); + uint64_t len_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, 1); + + uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref); + uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref); + + LLVMZigDIType *di_element_types[] = { + LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type), + "ptr", di_file, line, + ptr_debug_size_in_bits, + ptr_debug_align_in_bits, + ptr_offset_in_bits, + 0, pointer_type->di_type), + LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type), + "len", di_file, line, + len_debug_size_in_bits, + len_debug_align_in_bits, + len_offset_in_bits, + 0, isize_type->di_type), + }; + LLVMZigDIType *replacement_di_type = LLVMZigCreateDebugStructType(g->dbuilder, + compile_unit_scope, + buf_ptr(&entry->name), + di_file, line, debug_size_in_bits, debug_align_in_bits, 0, + nullptr, di_element_types, 2, 0, nullptr, ""); + + LLVMZigReplaceTemporary(g->dbuilder, entry->di_type, replacement_di_type); + entry->di_type = replacement_di_type; + } entry->data.structure.complete = true; diff --git a/src/codegen.cpp b/src/codegen.cpp index 9422aeaa05..394ab398bb 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -714,11 +714,15 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) { add_debug_source_node(g, node); - LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, 0, ""); - LLVMValueRef expr_bitcast = LLVMBuildBitCast(g->builder, expr_val, pointer_type->type_ref, ""); - LLVMBuildStore(g->builder, expr_bitcast, ptr_ptr); + int ptr_index = wanted_type->data.structure.fields[0].gen_index; + if (ptr_index >= 0) { + LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, ptr_index, ""); + LLVMValueRef expr_bitcast = LLVMBuildBitCast(g->builder, expr_val, pointer_type->type_ref, ""); + LLVMBuildStore(g->builder, expr_bitcast, ptr_ptr); + } - LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, 1, ""); + int len_index = wanted_type->data.structure.fields[1].gen_index; + LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, len_index, ""); LLVMValueRef len_val = LLVMConstInt(g->builtin_types.entry_isize->type_ref, actual_type->data.array.len, false); LLVMBuildStore(g->builder, len_val, len_ptr); @@ -884,7 +888,9 @@ static LLVMValueRef gen_array_elem_ptr(CodeGen *g, AstNode *source_node, LLVMVal assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind); add_debug_source_node(g, source_node); - LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, 0, ""); + int ptr_index = array_type->data.structure.fields[0].gen_index; + assert(ptr_index >= 0); + LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, ptr_index, ""); LLVMValueRef ptr = LLVMBuildLoad(g->builder, ptr_ptr, ""); return LLVMBuildInBoundsGEP(g->builder, ptr, &subscript_value, 1, ""); } else { @@ -1002,18 +1008,25 @@ static LLVMValueRef gen_slice_expr(CodeGen *g, AstNode *node) { end_val = gen_expr(g, node->data.slice_expr.end); } else { add_debug_source_node(g, node); - LLVMValueRef src_len_ptr = LLVMBuildStructGEP(g->builder, array_ptr, 1, ""); + int len_index = array_type->data.structure.fields[1].gen_index; + assert(len_index >= 0); + LLVMValueRef src_len_ptr = LLVMBuildStructGEP(g->builder, array_ptr, len_index, ""); end_val = LLVMBuildLoad(g->builder, src_len_ptr, ""); } + int ptr_index = array_type->data.structure.fields[0].gen_index; + assert(ptr_index >= 0); + int len_index = array_type->data.structure.fields[1].gen_index; + assert(len_index >= 0); + add_debug_source_node(g, node); - LLVMValueRef src_ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, 0, ""); + LLVMValueRef src_ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, ptr_index, ""); LLVMValueRef src_ptr = LLVMBuildLoad(g->builder, src_ptr_ptr, ""); - LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 0, ""); - LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr, &start_val, 1, ""); + LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, ptr_index, ""); + LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr, &start_val, len_index, ""); LLVMBuildStore(g->builder, slice_start_ptr, ptr_field_ptr); - LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 1, ""); + LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, len_index, ""); LLVMValueRef len_value = LLVMBuildSub(g->builder, end_val, start_val, ""); LLVMBuildStore(g->builder, len_value, len_field_ptr); @@ -2419,7 +2432,9 @@ static LLVMValueRef gen_for_expr(CodeGen *g, AstNode *node) { TypeTableEntry *child_ptr_type = array_type->data.structure.fields[0].type_entry; assert(child_ptr_type->id == TypeTableEntryIdPointer); child_type = child_ptr_type->data.pointer.child_type; - LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, array_val, 1, ""); + int len_index = array_type->data.structure.fields[1].gen_index; + assert(len_index >= 0); + LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, array_val, len_index, ""); len_val = LLVMBuildLoad(g->builder, len_field_ptr, ""); } else { zig_unreachable(); @@ -2537,14 +2552,19 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa LLVMValueRef ptr_val = LLVMBuildArrayAlloca(g->builder, child_type->type_ref, size_val, ""); + int ptr_index = var_type->data.structure.fields[0].gen_index; + assert(ptr_index >= 0); + int len_index = var_type->data.structure.fields[1].gen_index; + assert(len_index >= 0); + // store the freshly allocated pointer in the unknown size array struct LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, - variable->value_ref, 0, ""); + variable->value_ref, ptr_index, ""); LLVMBuildStore(g->builder, ptr_val, ptr_field_ptr); // store the size in the len field LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, - variable->value_ref, 1, ""); + variable->value_ref, len_index, ""); LLVMBuildStore(g->builder, size_val, len_field_ptr); // don't clobber what we just did with debug initialization diff --git a/test/self_hosted.zig b/test/self_hosted.zig index 29a04efba7..ae47716a12 100644 --- a/test/self_hosted.zig +++ b/test/self_hosted.zig @@ -1314,3 +1314,11 @@ fn test_return_empty_struct_from_fn() -> EmptyStruct2 { fn test_return_empty_struct_from_fn_noeval() -> EmptyStruct2 { EmptyStruct2 {} } + +#attribute("test") +fn pass_slice_of_empty_struct_to_fn() { + assert(test_pass_slice_of_empty_struct_to_fn([]EmptyStruct2{ EmptyStruct2{} }) == 1); +} +fn test_pass_slice_of_empty_struct_to_fn(slice: []EmptyStruct2) -> isize { + slice.len +}