| author | |
| committer | |
| log | 899fb14c30f34cea811bbf361124b15dc41eea71 |
| tree | 78e32bfb606dd9bae9fba0865837a0bbc7eaa11f |
| parent | 55b28ab0301237b8c9e39db4160036a42544f836 |
closes #1433 files changed, 125 insertions(+), 59 deletions(-)
src/analyze.cpp+84-46| ... | ... | @@ -494,18 +494,6 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_c |
| 494 | 494 | buf_appendf(&entry->name, "[]%s", buf_ptr(&child_type->name)); |
| 495 | 495 | entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(&entry->name)); |
| 496 | 496 | |
| 497 | TypeTableEntry *pointer_type = get_pointer_to_type(g, child_type, is_const); | |
| 498 | ||
| 499 | unsigned element_count = 2; | |
| 500 | LLVMTypeRef element_types[] = { | |
| 501 | pointer_type->type_ref, | |
| 502 | g->builtin_types.entry_isize->type_ref, | |
| 503 | }; | |
| 504 | LLVMStructSetBody(entry->type_ref, element_types, element_count, false); | |
| 505 | ||
| 506 | slice_type_common_init(g, child_type, is_const, entry); | |
| 507 | ||
| 508 | ||
| 509 | 497 | LLVMZigDIScope *compile_unit_scope = LLVMZigCompileUnitToScope(g->compile_unit); |
| 510 | 498 | LLVMZigDIFile *di_file = nullptr; |
| 511 | 499 | unsigned line = 0; |
| ... | ... | @@ -513,40 +501,90 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_c |
| 513 | 501 | LLVMZigTag_DW_structure_type(), buf_ptr(&entry->name), |
| 514 | 502 | compile_unit_scope, di_file, line); |
| 515 | 503 | |
| 516 | uint64_t ptr_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, pointer_type->type_ref); | |
| 517 | uint64_t ptr_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, pointer_type->type_ref); | |
| 518 | uint64_t ptr_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, 0); | |
| 519 | ||
| 520 | TypeTableEntry *isize_type = g->builtin_types.entry_isize; | |
| 521 | uint64_t len_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, isize_type->type_ref); | |
| 522 | uint64_t len_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, isize_type->type_ref); | |
| 523 | uint64_t len_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, 1); | |
| 524 | ||
| 525 | uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref); | |
| 526 | uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref); | |
| 527 | ||
| 528 | LLVMZigDIType *di_element_types[] = { | |
| 529 | LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type), | |
| 530 | "ptr", di_file, line, | |
| 531 | ptr_debug_size_in_bits, | |
| 532 | ptr_debug_align_in_bits, | |
| 533 | ptr_offset_in_bits, | |
| 534 | 0, pointer_type->di_type), | |
| 535 | LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type), | |
| 536 | "len", di_file, line, | |
| 537 | len_debug_size_in_bits, | |
| 538 | len_debug_align_in_bits, | |
| 539 | len_offset_in_bits, | |
| 540 | 0, isize_type->di_type), | |
| 541 | }; | |
| 542 | LLVMZigDIType *replacement_di_type = LLVMZigCreateDebugStructType(g->dbuilder, | |
| 543 | compile_unit_scope, | |
| 544 | buf_ptr(&entry->name), | |
| 545 | di_file, line, debug_size_in_bits, debug_align_in_bits, 0, | |
| 546 | nullptr, di_element_types, 2, 0, nullptr, ""); | |
| 547 | ||
| 548 | LLVMZigReplaceTemporary(g->dbuilder, entry->di_type, replacement_di_type); | |
| 549 | entry->di_type = replacement_di_type; | |
| 504 | if (child_type->zero_bits) { | |
| 505 | LLVMTypeRef element_types[] = { | |
| 506 | g->builtin_types.entry_isize->type_ref, | |
| 507 | }; | |
| 508 | LLVMStructSetBody(entry->type_ref, element_types, 1, false); | |
| 509 | ||
| 510 | slice_type_common_init(g, child_type, is_const, entry); | |
| 511 | ||
| 512 | entry->data.structure.gen_field_count = 1; | |
| 513 | entry->data.structure.fields[0].gen_index = -1; | |
| 514 | entry->data.structure.fields[1].gen_index = 0; | |
| 515 | ||
| 516 | TypeTableEntry *isize_type = g->builtin_types.entry_isize; | |
| 517 | uint64_t len_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, isize_type->type_ref); | |
| 518 | uint64_t len_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, isize_type->type_ref); | |
| 519 | uint64_t len_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, 0); | |
| 520 | ||
| 521 | uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref); | |
| 522 | uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref); | |
| 523 | ||
| 524 | LLVMZigDIType *di_element_types[] = { | |
| 525 | LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type), | |
| 526 | "len", di_file, line, | |
| 527 | len_debug_size_in_bits, | |
| 528 | len_debug_align_in_bits, | |
| 529 | len_offset_in_bits, | |
| 530 | 0, isize_type->di_type), | |
| 531 | }; | |
| 532 | LLVMZigDIType *replacement_di_type = LLVMZigCreateDebugStructType(g->dbuilder, | |
| 533 | compile_unit_scope, | |
| 534 | buf_ptr(&entry->name), | |
| 535 | di_file, line, debug_size_in_bits, debug_align_in_bits, 0, | |
| 536 | nullptr, di_element_types, 1, 0, nullptr, ""); | |
| 537 | ||
| 538 | LLVMZigReplaceTemporary(g->dbuilder, entry->di_type, replacement_di_type); | |
| 539 | entry->di_type = replacement_di_type; | |
| 540 | } else { | |
| 541 | TypeTableEntry *pointer_type = get_pointer_to_type(g, child_type, is_const); | |
| 542 | ||
| 543 | unsigned element_count = 2; | |
| 544 | LLVMTypeRef element_types[] = { | |
| 545 | pointer_type->type_ref, | |
| 546 | g->builtin_types.entry_isize->type_ref, | |
| 547 | }; | |
| 548 | LLVMStructSetBody(entry->type_ref, element_types, element_count, false); | |
| 549 | ||
| 550 | slice_type_common_init(g, child_type, is_const, entry); | |
| 551 | ||
| 552 | ||
| 553 | uint64_t ptr_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, pointer_type->type_ref); | |
| 554 | uint64_t ptr_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, pointer_type->type_ref); | |
| 555 | uint64_t ptr_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, 0); | |
| 556 | ||
| 557 | TypeTableEntry *isize_type = g->builtin_types.entry_isize; | |
| 558 | uint64_t len_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, isize_type->type_ref); | |
| 559 | uint64_t len_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, isize_type->type_ref); | |
| 560 | uint64_t len_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, 1); | |
| 561 | ||
| 562 | uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref); | |
| 563 | uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref); | |
| 564 | ||
| 565 | LLVMZigDIType *di_element_types[] = { | |
| 566 | LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type), | |
| 567 | "ptr", di_file, line, | |
| 568 | ptr_debug_size_in_bits, | |
| 569 | ptr_debug_align_in_bits, | |
| 570 | ptr_offset_in_bits, | |
| 571 | 0, pointer_type->di_type), | |
| 572 | LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type), | |
| 573 | "len", di_file, line, | |
| 574 | len_debug_size_in_bits, | |
| 575 | len_debug_align_in_bits, | |
| 576 | len_offset_in_bits, | |
| 577 | 0, isize_type->di_type), | |
| 578 | }; | |
| 579 | LLVMZigDIType *replacement_di_type = LLVMZigCreateDebugStructType(g->dbuilder, | |
| 580 | compile_unit_scope, | |
| 581 | buf_ptr(&entry->name), | |
| 582 | di_file, line, debug_size_in_bits, debug_align_in_bits, 0, | |
| 583 | nullptr, di_element_types, 2, 0, nullptr, ""); | |
| 584 | ||
| 585 | LLVMZigReplaceTemporary(g->dbuilder, entry->di_type, replacement_di_type); | |
| 586 | entry->di_type = replacement_di_type; | |
| 587 | } | |
| 550 | 588 | |
| 551 | 589 | |
| 552 | 590 | entry->data.structure.complete = true; |
src/codegen.cpp+33-13| ... | ... | @@ -714,11 +714,15 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) { |
| 714 | 714 | |
| 715 | 715 | add_debug_source_node(g, node); |
| 716 | 716 | |
| 717 | LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, 0, ""); | |
| 718 | LLVMValueRef expr_bitcast = LLVMBuildBitCast(g->builder, expr_val, pointer_type->type_ref, ""); | |
| 719 | LLVMBuildStore(g->builder, expr_bitcast, ptr_ptr); | |
| 717 | int ptr_index = wanted_type->data.structure.fields[0].gen_index; | |
| 718 | if (ptr_index >= 0) { | |
| 719 | LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, ptr_index, ""); | |
| 720 | LLVMValueRef expr_bitcast = LLVMBuildBitCast(g->builder, expr_val, pointer_type->type_ref, ""); | |
| 721 | LLVMBuildStore(g->builder, expr_bitcast, ptr_ptr); | |
| 722 | } | |
| 720 | 723 | |
| 721 | LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, 1, ""); | |
| 724 | int len_index = wanted_type->data.structure.fields[1].gen_index; | |
| 725 | LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, len_index, ""); | |
| 722 | 726 | LLVMValueRef len_val = LLVMConstInt(g->builtin_types.entry_isize->type_ref, |
| 723 | 727 | actual_type->data.array.len, false); |
| 724 | 728 | LLVMBuildStore(g->builder, len_val, len_ptr); |
| ... | ... | @@ -884,7 +888,9 @@ static LLVMValueRef gen_array_elem_ptr(CodeGen *g, AstNode *source_node, LLVMVal |
| 884 | 888 | assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind); |
| 885 | 889 | |
| 886 | 890 | add_debug_source_node(g, source_node); |
| 887 | LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, 0, ""); | |
| 891 | int ptr_index = array_type->data.structure.fields[0].gen_index; | |
| 892 | assert(ptr_index >= 0); | |
| 893 | LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, ptr_index, ""); | |
| 888 | 894 | LLVMValueRef ptr = LLVMBuildLoad(g->builder, ptr_ptr, ""); |
| 889 | 895 | return LLVMBuildInBoundsGEP(g->builder, ptr, &subscript_value, 1, ""); |
| 890 | 896 | } else { |
| ... | ... | @@ -1002,18 +1008,25 @@ static LLVMValueRef gen_slice_expr(CodeGen *g, AstNode *node) { |
| 1002 | 1008 | end_val = gen_expr(g, node->data.slice_expr.end); |
| 1003 | 1009 | } else { |
| 1004 | 1010 | add_debug_source_node(g, node); |
| 1005 | LLVMValueRef src_len_ptr = LLVMBuildStructGEP(g->builder, array_ptr, 1, ""); | |
| 1011 | int len_index = array_type->data.structure.fields[1].gen_index; | |
| 1012 | assert(len_index >= 0); | |
| 1013 | LLVMValueRef src_len_ptr = LLVMBuildStructGEP(g->builder, array_ptr, len_index, ""); | |
| 1006 | 1014 | end_val = LLVMBuildLoad(g->builder, src_len_ptr, ""); |
| 1007 | 1015 | } |
| 1008 | 1016 | |
| 1017 | int ptr_index = array_type->data.structure.fields[0].gen_index; | |
| 1018 | assert(ptr_index >= 0); | |
| 1019 | int len_index = array_type->data.structure.fields[1].gen_index; | |
| 1020 | assert(len_index >= 0); | |
| 1021 | ||
| 1009 | 1022 | add_debug_source_node(g, node); |
| 1010 | LLVMValueRef src_ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, 0, ""); | |
| 1023 | LLVMValueRef src_ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, ptr_index, ""); | |
| 1011 | 1024 | LLVMValueRef src_ptr = LLVMBuildLoad(g->builder, src_ptr_ptr, ""); |
| 1012 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 0, ""); | |
| 1013 | LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr, &start_val, 1, ""); | |
| 1025 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, ptr_index, ""); | |
| 1026 | LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr, &start_val, len_index, ""); | |
| 1014 | 1027 | LLVMBuildStore(g->builder, slice_start_ptr, ptr_field_ptr); |
| 1015 | 1028 | |
| 1016 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 1, ""); | |
| 1029 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, len_index, ""); | |
| 1017 | 1030 | LLVMValueRef len_value = LLVMBuildSub(g->builder, end_val, start_val, ""); |
| 1018 | 1031 | LLVMBuildStore(g->builder, len_value, len_field_ptr); |
| 1019 | 1032 | |
| ... | ... | @@ -2419,7 +2432,9 @@ static LLVMValueRef gen_for_expr(CodeGen *g, AstNode *node) { |
| 2419 | 2432 | TypeTableEntry *child_ptr_type = array_type->data.structure.fields[0].type_entry; |
| 2420 | 2433 | assert(child_ptr_type->id == TypeTableEntryIdPointer); |
| 2421 | 2434 | child_type = child_ptr_type->data.pointer.child_type; |
| 2422 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, array_val, 1, ""); | |
| 2435 | int len_index = array_type->data.structure.fields[1].gen_index; | |
| 2436 | assert(len_index >= 0); | |
| 2437 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, array_val, len_index, ""); | |
| 2423 | 2438 | len_val = LLVMBuildLoad(g->builder, len_field_ptr, ""); |
| 2424 | 2439 | } else { |
| 2425 | 2440 | zig_unreachable(); |
| ... | ... | @@ -2537,14 +2552,19 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa |
| 2537 | 2552 | LLVMValueRef ptr_val = LLVMBuildArrayAlloca(g->builder, child_type->type_ref, |
| 2538 | 2553 | size_val, ""); |
| 2539 | 2554 | |
| 2555 | int ptr_index = var_type->data.structure.fields[0].gen_index; | |
| 2556 | assert(ptr_index >= 0); | |
| 2557 | int len_index = var_type->data.structure.fields[1].gen_index; | |
| 2558 | assert(len_index >= 0); | |
| 2559 | ||
| 2540 | 2560 | // store the freshly allocated pointer in the unknown size array struct |
| 2541 | 2561 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, |
| 2542 | variable->value_ref, 0, ""); | |
| 2562 | variable->value_ref, ptr_index, ""); | |
| 2543 | 2563 | LLVMBuildStore(g->builder, ptr_val, ptr_field_ptr); |
| 2544 | 2564 | |
| 2545 | 2565 | // store the size in the len field |
| 2546 | 2566 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, |
| 2547 | variable->value_ref, 1, ""); | |
| 2567 | variable->value_ref, len_index, ""); | |
| 2548 | 2568 | LLVMBuildStore(g->builder, size_val, len_field_ptr); |
| 2549 | 2569 | |
| 2550 | 2570 | // don't clobber what we just did with debug initialization |
test/self_hosted.zig+8| ... | ... | @@ -1314,3 +1314,11 @@ fn test_return_empty_struct_from_fn() -> EmptyStruct2 { |
| 1314 | 1314 | fn test_return_empty_struct_from_fn_noeval() -> EmptyStruct2 { |
| 1315 | 1315 | EmptyStruct2 {} |
| 1316 | 1316 | } |
| 1317 | ||
| 1318 | #attribute("test") | |
| 1319 | fn pass_slice_of_empty_struct_to_fn() { | |
| 1320 | assert(test_pass_slice_of_empty_struct_to_fn([]EmptyStruct2{ EmptyStruct2{} }) == 1); | |
| 1321 | } | |
| 1322 | fn test_pass_slice_of_empty_struct_to_fn(slice: []EmptyStruct2) -> isize { | |
| 1323 | slice.len | |
| 1324 | } |