| author | |
| committer | |
| log | 55e54d98c47a0f1fb951f2011c6fc221af68d537 |
| tree | 031f12e33101d46cfd00849f811d1097d3300d3b |
| parent | a26e9fa7238e972301f761db80434fa0205d1016 |
| signature |
6 files changed, 163 insertions(+), 38 deletions(-)
src/all_types.hpp+13-1| ... | ... | @@ -1183,13 +1183,22 @@ struct FnTypeId { |
| 1183 | 1183 | uint32_t fn_type_id_hash(FnTypeId*); |
| 1184 | 1184 | bool fn_type_id_eql(FnTypeId *a, FnTypeId *b); |
| 1185 | 1185 | |
| 1186 | static const uint32_t VECTOR_INDEX_NONE = UINT32_MAX; | |
| 1187 | static const uint32_t VECTOR_INDEX_RUNTIME = UINT32_MAX - 1; | |
| 1188 | ||
| 1186 | 1189 | struct ZigTypePointer { |
| 1187 | 1190 | ZigType *child_type; |
| 1188 | 1191 | ZigType *slice_parent; |
| 1192 | ||
| 1189 | 1193 | PtrLen ptr_len; |
| 1190 | 1194 | uint32_t explicit_alignment; // 0 means use ABI alignment |
| 1195 | ||
| 1191 | 1196 | uint32_t bit_offset_in_host; |
| 1192 | uint32_t host_int_bytes; // size of host integer. 0 means no host integer; this field is aligned | |
| 1197 | // size of host integer. 0 means no host integer; this field is aligned | |
| 1198 | // when vector_index != VECTOR_INDEX_NONE this is the len of the containing vector | |
| 1199 | uint32_t host_int_bytes; | |
| 1200 | ||
| 1201 | uint32_t vector_index; // see the VECTOR_INDEX_* constants | |
| 1193 | 1202 | bool is_const; |
| 1194 | 1203 | bool is_volatile; |
| 1195 | 1204 | bool allow_zero; |
| ... | ... | @@ -1732,8 +1741,11 @@ struct TypeId { |
| 1732 | 1741 | ZigType *child_type; |
| 1733 | 1742 | PtrLen ptr_len; |
| 1734 | 1743 | uint32_t alignment; |
| 1744 | ||
| 1735 | 1745 | uint32_t bit_offset_in_host; |
| 1736 | 1746 | uint32_t host_int_bytes; |
| 1747 | ||
| 1748 | uint32_t vector_index; | |
| 1737 | 1749 | bool is_const; |
| 1738 | 1750 | bool is_volatile; |
| 1739 | 1751 | bool allow_zero; |
src/analyze.cpp+57-14| ... | ... | @@ -480,9 +480,10 @@ ZigType *get_fn_frame_type(CodeGen *g, ZigFn *fn) { |
| 480 | 480 | return entry; |
| 481 | 481 | } |
| 482 | 482 | |
| 483 | ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const, | |
| 483 | ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type, bool is_const, | |
| 484 | 484 | bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, |
| 485 | uint32_t bit_offset_in_host, uint32_t host_int_bytes, bool allow_zero) | |
| 485 | uint32_t bit_offset_in_host, uint32_t host_int_bytes, bool allow_zero, | |
| 486 | uint32_t vector_index) | |
| 486 | 487 | { |
| 487 | 488 | assert(ptr_len != PtrLenC || allow_zero); |
| 488 | 489 | assert(!type_is_invalid(child_type)); |
| ... | ... | @@ -494,7 +495,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons |
| 494 | 495 | byte_alignment = 0; |
| 495 | 496 | } |
| 496 | 497 | |
| 497 | if (host_int_bytes != 0) { | |
| 498 | if (host_int_bytes != 0 && vector_index == VECTOR_INDEX_NONE) { | |
| 498 | 499 | uint32_t child_type_bits = type_size_bits(g, child_type); |
| 499 | 500 | if (host_int_bytes * 8 == child_type_bits) { |
| 500 | 501 | assert(bit_offset_in_host == 0); |
| ... | ... | @@ -504,7 +505,9 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons |
| 504 | 505 | |
| 505 | 506 | TypeId type_id = {}; |
| 506 | 507 | ZigType **parent_pointer = nullptr; |
| 507 | if (host_int_bytes != 0 || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle || allow_zero) { | |
| 508 | if (host_int_bytes != 0 || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle || | |
| 509 | allow_zero || vector_index != VECTOR_INDEX_NONE) | |
| 510 | { | |
| 508 | 511 | type_id.id = ZigTypeIdPointer; |
| 509 | 512 | type_id.data.pointer.child_type = child_type; |
| 510 | 513 | type_id.data.pointer.is_const = is_const; |
| ... | ... | @@ -514,6 +517,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons |
| 514 | 517 | type_id.data.pointer.host_int_bytes = host_int_bytes; |
| 515 | 518 | type_id.data.pointer.ptr_len = ptr_len; |
| 516 | 519 | type_id.data.pointer.allow_zero = allow_zero; |
| 520 | type_id.data.pointer.vector_index = vector_index; | |
| 517 | 521 | |
| 518 | 522 | auto existing_entry = g->type_table.maybe_get(type_id); |
| 519 | 523 | if (existing_entry) |
| ... | ... | @@ -540,19 +544,36 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons |
| 540 | 544 | allow_zero_str = allow_zero ? "allowzero " : ""; |
| 541 | 545 | } |
| 542 | 546 | buf_resize(&entry->name, 0); |
| 543 | if (host_int_bytes == 0 && byte_alignment == 0) { | |
| 547 | if (host_int_bytes == 0 && byte_alignment == 0 && vector_index == VECTOR_INDEX_NONE) { | |
| 544 | 548 | buf_appendf(&entry->name, "%s%s%s%s%s", |
| 545 | 549 | star_str, const_str, volatile_str, allow_zero_str, buf_ptr(&child_type->name)); |
| 546 | } else if (host_int_bytes == 0) { | |
| 550 | } else if (host_int_bytes == 0 && vector_index == VECTOR_INDEX_NONE) { | |
| 547 | 551 | buf_appendf(&entry->name, "%salign(%" PRIu32 ") %s%s%s%s", star_str, byte_alignment, |
| 548 | 552 | const_str, volatile_str, allow_zero_str, buf_ptr(&child_type->name)); |
| 549 | 553 | } else if (byte_alignment == 0) { |
| 550 | buf_appendf(&entry->name, "%salign(:%" PRIu32 ":%" PRIu32 ") %s%s%s%s", star_str, | |
| 551 | bit_offset_in_host, host_int_bytes, const_str, volatile_str, allow_zero_str, | |
| 554 | assert(vector_index == VECTOR_INDEX_NONE); | |
| 555 | buf_appendf(&entry->name, "%salign(:%" PRIu32 ":%" PRIu32 ":%" PRIu32 ") %s%s%s%s", | |
| 556 | star_str, | |
| 557 | bit_offset_in_host, host_int_bytes, vector_index, | |
| 558 | const_str, volatile_str, allow_zero_str, | |
| 559 | buf_ptr(&child_type->name)); | |
| 560 | } else if (vector_index == VECTOR_INDEX_NONE) { | |
| 561 | buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ") %s%s%s%s", | |
| 562 | star_str, byte_alignment, | |
| 563 | bit_offset_in_host, host_int_bytes, | |
| 564 | const_str, volatile_str, allow_zero_str, | |
| 565 | buf_ptr(&child_type->name)); | |
| 566 | } else if (vector_index == VECTOR_INDEX_RUNTIME) { | |
| 567 | buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ":?) %s%s%s%s", | |
| 568 | star_str, byte_alignment, | |
| 569 | bit_offset_in_host, host_int_bytes, | |
| 570 | const_str, volatile_str, allow_zero_str, | |
| 552 | 571 | buf_ptr(&child_type->name)); |
| 553 | 572 | } else { |
| 554 | buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ") %s%s%s%s", star_str, byte_alignment, | |
| 555 | bit_offset_in_host, host_int_bytes, const_str, volatile_str, allow_zero_str, | |
| 573 | buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ":%" PRIu32 ") %s%s%s%s", | |
| 574 | star_str, byte_alignment, | |
| 575 | bit_offset_in_host, host_int_bytes, vector_index, | |
| 576 | const_str, volatile_str, allow_zero_str, | |
| 556 | 577 | buf_ptr(&child_type->name)); |
| 557 | 578 | } |
| 558 | 579 | |
| ... | ... | @@ -581,6 +602,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons |
| 581 | 602 | entry->data.pointer.bit_offset_in_host = bit_offset_in_host; |
| 582 | 603 | entry->data.pointer.host_int_bytes = host_int_bytes; |
| 583 | 604 | entry->data.pointer.allow_zero = allow_zero; |
| 605 | entry->data.pointer.vector_index = vector_index; | |
| 584 | 606 | |
| 585 | 607 | if (parent_pointer) { |
| 586 | 608 | *parent_pointer = entry; |
| ... | ... | @@ -590,8 +612,17 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons |
| 590 | 612 | return entry; |
| 591 | 613 | } |
| 592 | 614 | |
| 615 | ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const, | |
| 616 | bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, | |
| 617 | uint32_t bit_offset_in_host, uint32_t host_int_bytes, bool allow_zero) | |
| 618 | { | |
| 619 | return get_pointer_to_type_extra2(g, child_type, is_const, is_volatile, ptr_len, | |
| 620 | byte_alignment, bit_offset_in_host, host_int_bytes, allow_zero, VECTOR_INDEX_NONE); | |
| 621 | } | |
| 622 | ||
| 593 | 623 | ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const) { |
| 594 | return get_pointer_to_type_extra(g, child_type, is_const, false, PtrLenSingle, 0, 0, 0, false); | |
| 624 | return get_pointer_to_type_extra2(g, child_type, is_const, false, PtrLenSingle, 0, 0, 0, false, | |
| 625 | VECTOR_INDEX_NONE); | |
| 595 | 626 | } |
| 596 | 627 | |
| 597 | 628 | ZigType *get_optional_type(CodeGen *g, ZigType *child_type) { |
| ... | ... | @@ -6910,6 +6941,7 @@ uint32_t type_id_hash(TypeId x) { |
| 6910 | 6941 | (x.data.pointer.allow_zero ? (uint32_t)3324284834 : (uint32_t)3584904923) + |
| 6911 | 6942 | (((uint32_t)x.data.pointer.alignment) ^ (uint32_t)0x777fbe0e) + |
| 6912 | 6943 | (((uint32_t)x.data.pointer.bit_offset_in_host) ^ (uint32_t)2639019452) + |
| 6944 | (((uint32_t)x.data.pointer.vector_index) ^ (uint32_t)0x19199716) + | |
| 6913 | 6945 | (((uint32_t)x.data.pointer.host_int_bytes) ^ (uint32_t)529908881); |
| 6914 | 6946 | case ZigTypeIdArray: |
| 6915 | 6947 | return hash_ptr(x.data.array.child_type) + |
| ... | ... | @@ -6962,6 +6994,7 @@ bool type_id_eql(TypeId a, TypeId b) { |
| 6962 | 6994 | a.data.pointer.allow_zero == b.data.pointer.allow_zero && |
| 6963 | 6995 | a.data.pointer.alignment == b.data.pointer.alignment && |
| 6964 | 6996 | a.data.pointer.bit_offset_in_host == b.data.pointer.bit_offset_in_host && |
| 6997 | a.data.pointer.vector_index == b.data.pointer.vector_index && | |
| 6965 | 6998 | a.data.pointer.host_int_bytes == b.data.pointer.host_int_bytes; |
| 6966 | 6999 | case ZigTypeIdArray: |
| 6967 | 7000 | return a.data.array.child_type == b.data.array.child_type && |
| ... | ... | @@ -8266,11 +8299,21 @@ static void resolve_llvm_types_pointer(CodeGen *g, ZigType *type, ResolveStatus |
| 8266 | 8299 | |
| 8267 | 8300 | if (type->data.pointer.is_const || type->data.pointer.is_volatile || |
| 8268 | 8301 | type->data.pointer.explicit_alignment != 0 || type->data.pointer.ptr_len != PtrLenSingle || |
| 8269 | type->data.pointer.bit_offset_in_host != 0 || type->data.pointer.allow_zero) | |
| 8302 | type->data.pointer.bit_offset_in_host != 0 || type->data.pointer.allow_zero || | |
| 8303 | type->data.pointer.vector_index != VECTOR_INDEX_NONE) | |
| 8270 | 8304 | { |
| 8271 | 8305 | assertNoError(type_resolve(g, elem_type, ResolveStatusLLVMFwdDecl)); |
| 8272 | ZigType *peer_type = get_pointer_to_type_extra(g, elem_type, false, false, | |
| 8273 | PtrLenSingle, 0, 0, type->data.pointer.host_int_bytes, false); | |
| 8306 | ZigType *peer_type; | |
| 8307 | if (type->data.pointer.vector_index == VECTOR_INDEX_NONE) { | |
| 8308 | peer_type = get_pointer_to_type_extra2(g, elem_type, false, false, | |
| 8309 | PtrLenSingle, 0, 0, type->data.pointer.host_int_bytes, false, | |
| 8310 | VECTOR_INDEX_NONE); | |
| 8311 | } else { | |
| 8312 | uint32_t host_vec_len = type->data.pointer.host_int_bytes; | |
| 8313 | ZigType *host_vec_type = get_vector_type(g, host_vec_len, elem_type); | |
| 8314 | peer_type = get_pointer_to_type_extra2(g, host_vec_type, false, false, | |
| 8315 | PtrLenSingle, 0, 0, 0, false, VECTOR_INDEX_NONE); | |
| 8316 | } | |
| 8274 | 8317 | type->llvm_type = get_llvm_type(g, peer_type); |
| 8275 | 8318 | type->llvm_di_type = get_llvm_di_type(g, peer_type); |
| 8276 | 8319 | assertNoError(type_resolve(g, elem_type, wanted_resolve_status)); |
src/analyze.hpp+6-2| ... | ... | @@ -17,10 +17,14 @@ ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, const AstNode *node, |
| 17 | 17 | ZigType *new_type_table_entry(ZigTypeId id); |
| 18 | 18 | ZigType *get_fn_frame_type(CodeGen *g, ZigFn *fn); |
| 19 | 19 | ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const); |
| 20 | ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const, | |
| 21 | bool is_volatile, PtrLen ptr_len, | |
| 20 | ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, | |
| 21 | bool is_const, bool is_volatile, PtrLen ptr_len, | |
| 22 | 22 | uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count, |
| 23 | 23 | bool allow_zero); |
| 24 | ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type, | |
| 25 | bool is_const, bool is_volatile, PtrLen ptr_len, | |
| 26 | uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count, | |
| 27 | bool allow_zero, uint32_t vector_index); | |
| 24 | 28 | uint64_t type_size(CodeGen *g, ZigType *type_entry); |
| 25 | 29 | uint64_t type_size_bits(CodeGen *g, ZigType *type_entry); |
| 26 | 30 | ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits); |
src/codegen.cpp+30-13| ... | ... | @@ -838,6 +838,11 @@ static LLVMValueRef get_handle_value(CodeGen *g, LLVMValueRef ptr, ZigType *type |
| 838 | 838 | } |
| 839 | 839 | } |
| 840 | 840 | |
| 841 | static void ir_assert(bool ok, IrInstruction *source_instruction) { | |
| 842 | if (ok) return; | |
| 843 | src_assert(ok, source_instruction->source_node); | |
| 844 | } | |
| 845 | ||
| 841 | 846 | static bool ir_want_fast_math(CodeGen *g, IrInstruction *instruction) { |
| 842 | 847 | // TODO memoize |
| 843 | 848 | Scope *scope = instruction->scope; |
| ... | ... | @@ -1695,11 +1700,11 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) { |
| 1695 | 1700 | } |
| 1696 | 1701 | if (instruction->spill != nullptr) { |
| 1697 | 1702 | ZigType *ptr_type = instruction->spill->value.type; |
| 1698 | src_assert(ptr_type->id == ZigTypeIdPointer, instruction->source_node); | |
| 1703 | ir_assert(ptr_type->id == ZigTypeIdPointer, instruction); | |
| 1699 | 1704 | return get_handle_value(g, ir_llvm_value(g, instruction->spill), |
| 1700 | 1705 | ptr_type->data.pointer.child_type, instruction->spill->value.type); |
| 1701 | 1706 | } |
| 1702 | src_assert(instruction->value.special != ConstValSpecialRuntime, instruction->source_node); | |
| 1707 | ir_assert(instruction->value.special != ConstValSpecialRuntime, instruction); | |
| 1703 | 1708 | assert(instruction->value.type); |
| 1704 | 1709 | render_const_val(g, &instruction->value, ""); |
| 1705 | 1710 | // we might have to do some pointer casting here due to the way union |
| ... | ... | @@ -2428,8 +2433,7 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns |
| 2428 | 2433 | return nullptr; |
| 2429 | 2434 | } |
| 2430 | 2435 | assert(g->cur_ret_ptr); |
| 2431 | src_assert(instruction->operand->value.special != ConstValSpecialRuntime, | |
| 2432 | instruction->base.source_node); | |
| 2436 | ir_assert(instruction->operand->value.special != ConstValSpecialRuntime, &instruction->base); | |
| 2433 | 2437 | LLVMValueRef value = ir_llvm_value(g, instruction->operand); |
| 2434 | 2438 | ZigType *return_type = instruction->operand->value.type; |
| 2435 | 2439 | gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value); |
| ... | ... | @@ -3399,7 +3403,9 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, IrI |
| 3399 | 3403 | return nullptr; |
| 3400 | 3404 | } |
| 3401 | 3405 | |
| 3402 | static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrInstructionLoadPtrGen *instruction) { | |
| 3406 | static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, | |
| 3407 | IrInstructionLoadPtrGen *instruction) | |
| 3408 | { | |
| 3403 | 3409 | ZigType *child_type = instruction->base.value.type; |
| 3404 | 3410 | if (!type_has_bits(child_type)) |
| 3405 | 3411 | return nullptr; |
| ... | ... | @@ -3409,6 +3415,15 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI |
| 3409 | 3415 | assert(ptr_type->id == ZigTypeIdPointer); |
| 3410 | 3416 | |
| 3411 | 3417 | uint32_t host_int_bytes = ptr_type->data.pointer.host_int_bytes; |
| 3418 | ||
| 3419 | ir_assert(ptr_type->data.pointer.vector_index != VECTOR_INDEX_RUNTIME, &instruction->base); | |
| 3420 | if (ptr_type->data.pointer.vector_index != VECTOR_INDEX_NONE) { | |
| 3421 | LLVMValueRef index_val = LLVMConstInt(LLVMInt32Type(), | |
| 3422 | ptr_type->data.pointer.vector_index, false); | |
| 3423 | LLVMValueRef loaded_vector = LLVMBuildLoad(g->builder, ptr, ""); | |
| 3424 | return LLVMBuildExtractElement(g->builder, loaded_vector, index_val, ""); | |
| 3425 | } | |
| 3426 | ||
| 3412 | 3427 | if (host_int_bytes == 0) |
| 3413 | 3428 | return get_handle_value(g, ptr, child_type, ptr_type); |
| 3414 | 3429 | |
| ... | ... | @@ -3636,7 +3651,7 @@ static LLVMValueRef ir_render_return_ptr(CodeGen *g, IrExecutable *executable, |
| 3636 | 3651 | { |
| 3637 | 3652 | if (!type_has_bits(instruction->base.value.type)) |
| 3638 | 3653 | return nullptr; |
| 3639 | src_assert(g->cur_ret_ptr != nullptr, instruction->base.source_node); | |
| 3654 | ir_assert(g->cur_ret_ptr != nullptr, &instruction->base); | |
| 3640 | 3655 | return g->cur_ret_ptr; |
| 3641 | 3656 | } |
| 3642 | 3657 | |
| ... | ... | @@ -3729,6 +3744,8 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI |
| 3729 | 3744 | LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, (unsigned)ptr_index, ""); |
| 3730 | 3745 | LLVMValueRef ptr = gen_load_untyped(g, ptr_ptr, 0, false, ""); |
| 3731 | 3746 | return LLVMBuildInBoundsGEP(g->builder, ptr, &subscript_value, 1, ""); |
| 3747 | } else if (array_type->id == ZigTypeIdVector) { | |
| 3748 | return array_ptr_ptr; | |
| 3732 | 3749 | } else { |
| 3733 | 3750 | zig_unreachable(); |
| 3734 | 3751 | } |
| ... | ... | @@ -3917,9 +3934,9 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3917 | 3934 | if (instruction->modifier == CallModifierAsync) { |
| 3918 | 3935 | frame_result_loc = result_loc; |
| 3919 | 3936 | } else { |
| 3920 | src_assert(instruction->frame_result_loc != nullptr, instruction->base.source_node); | |
| 3937 | ir_assert(instruction->frame_result_loc != nullptr, &instruction->base); | |
| 3921 | 3938 | frame_result_loc_uncasted = ir_llvm_value(g, instruction->frame_result_loc); |
| 3922 | src_assert(instruction->fn_entry != nullptr, instruction->base.source_node); | |
| 3939 | ir_assert(instruction->fn_entry != nullptr, &instruction->base); | |
| 3923 | 3940 | frame_result_loc = LLVMBuildBitCast(g->builder, frame_result_loc_uncasted, |
| 3924 | 3941 | LLVMPointerType(get_llvm_type(g, instruction->fn_entry->frame_type), 0), ""); |
| 3925 | 3942 | } |
| ... | ... | @@ -4271,10 +4288,10 @@ static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executa |
| 4271 | 4288 | if ((err = type_resolve(g, struct_type, ResolveStatusLLVMFull))) |
| 4272 | 4289 | codegen_report_errors_and_exit(g); |
| 4273 | 4290 | |
| 4274 | src_assert(field->gen_index != SIZE_MAX, instruction->base.source_node); | |
| 4291 | ir_assert(field->gen_index != SIZE_MAX, &instruction->base); | |
| 4275 | 4292 | LLVMValueRef field_ptr_val = LLVMBuildStructGEP(g->builder, struct_ptr, (unsigned)field->gen_index, ""); |
| 4276 | 4293 | ZigType *res_type = instruction->base.value.type; |
| 4277 | src_assert(res_type->id == ZigTypeIdPointer, instruction->base.source_node); | |
| 4294 | ir_assert(res_type->id == ZigTypeIdPointer, &instruction->base); | |
| 4278 | 4295 | if (res_type->data.pointer.host_int_bytes != 0) { |
| 4279 | 4296 | // We generate packed structs with get_llvm_type_of_n_bytes, which is |
| 4280 | 4297 | // u8 for 1 byte or [n]u8 for multiple bytes. But the pointer to the type |
| ... | ... | @@ -4684,7 +4701,7 @@ static LLVMValueRef ir_render_shuffle_vector(CodeGen *g, IrExecutable *executabl |
| 4684 | 4701 | |
| 4685 | 4702 | static LLVMValueRef ir_render_splat(CodeGen *g, IrExecutable *executable, IrInstructionSplatGen *instruction) { |
| 4686 | 4703 | ZigType *result_type = instruction->base.value.type; |
| 4687 | src_assert(result_type->id == ZigTypeIdVector, instruction->base.source_node); | |
| 4704 | ir_assert(result_type->id == ZigTypeIdVector, &instruction->base); | |
| 4688 | 4705 | uint32_t len = result_type->data.vector.len; |
| 4689 | 4706 | LLVMTypeRef op_llvm_type = LLVMVectorType(get_llvm_type(g, instruction->scalar->value.type), 1); |
| 4690 | 4707 | LLVMTypeRef mask_llvm_type = LLVMVectorType(LLVMInt32Type(), len); |
| ... | ... | @@ -5039,8 +5056,8 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrIn |
| 5039 | 5056 | } |
| 5040 | 5057 | |
| 5041 | 5058 | LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); |
| 5042 | src_assert(result_loc != nullptr, instruction->base.source_node); | |
| 5043 | src_assert(type_has_bits(child_type), instruction->base.source_node); | |
| 5059 | ir_assert(result_loc != nullptr, &instruction->base); | |
| 5060 | ir_assert(type_has_bits(child_type), &instruction->base); | |
| 5044 | 5061 | |
| 5045 | 5062 | LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, ""); |
| 5046 | 5063 | LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, result_loc, maybe_child_index, ""); |
src/ir.cpp+40-8| ... | ... | @@ -12908,18 +12908,18 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc |
| 12908 | 12908 | ResultLoc *result_loc) |
| 12909 | 12909 | { |
| 12910 | 12910 | Error err; |
| 12911 | ZigType *type_entry = ptr->value.type; | |
| 12912 | if (type_is_invalid(type_entry)) | |
| 12911 | ZigType *ptr_type = ptr->value.type; | |
| 12912 | if (type_is_invalid(ptr_type)) | |
| 12913 | 12913 | return ira->codegen->invalid_instruction; |
| 12914 | 12914 | |
| 12915 | if (type_entry->id != ZigTypeIdPointer) { | |
| 12915 | if (ptr_type->id != ZigTypeIdPointer) { | |
| 12916 | 12916 | ir_add_error_node(ira, source_instruction->source_node, |
| 12917 | 12917 | buf_sprintf("attempt to dereference non-pointer type '%s'", |
| 12918 | buf_ptr(&type_entry->name))); | |
| 12918 | buf_ptr(&ptr_type->name))); | |
| 12919 | 12919 | return ira->codegen->invalid_instruction; |
| 12920 | 12920 | } |
| 12921 | 12921 | |
| 12922 | ZigType *child_type = type_entry->data.pointer.child_type; | |
| 12922 | ZigType *child_type = ptr_type->data.pointer.child_type; | |
| 12923 | 12923 | // if the child type has one possible value, the deref is comptime |
| 12924 | 12924 | switch (type_has_one_possible_value(ira->codegen, child_type)) { |
| 12925 | 12925 | case OnePossibleValueInvalid: |
| ... | ... | @@ -12949,14 +12949,29 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc |
| 12949 | 12949 | } |
| 12950 | 12950 | } |
| 12951 | 12951 | } |
| 12952 | ||
| 12952 | 12953 | // if the instruction is a const ref instruction we can skip it |
| 12953 | 12954 | if (ptr->id == IrInstructionIdRef) { |
| 12954 | 12955 | IrInstructionRef *ref_inst = reinterpret_cast<IrInstructionRef *>(ptr); |
| 12955 | 12956 | return ref_inst->value; |
| 12956 | 12957 | } |
| 12957 | 12958 | |
| 12959 | // If the instruction is a element pointer instruction to a vector, we emit | |
| 12960 | // vector element extract instruction rather than load pointer. If the | |
| 12961 | // pointer type has non-VECTOR_INDEX_RUNTIME value, it would have been | |
| 12962 | // possible to implement this in the codegen for IrInstructionLoadPtrGen. | |
| 12963 | // However if it has VECTOR_INDEX_RUNTIME then we must emit a compile error | |
| 12964 | // if the vector index cannot be determined right here, right now, because | |
| 12965 | // the type information does not contain enough information to actually | |
| 12966 | // perform a dereference. | |
| 12967 | if (ptr_type->data.pointer.vector_index == VECTOR_INDEX_RUNTIME) { | |
| 12968 | ir_add_error(ira, ptr, | |
| 12969 | buf_sprintf("unable to determine element index in order to dereference vector pointer")); | |
| 12970 | return ira->codegen->invalid_instruction; | |
| 12971 | } | |
| 12972 | ||
| 12958 | 12973 | IrInstruction *result_loc_inst; |
| 12959 | if (type_entry->data.pointer.host_int_bytes != 0 && handle_is_ptr(child_type)) { | |
| 12974 | if (ptr_type->data.pointer.host_int_bytes != 0 && handle_is_ptr(child_type)) { | |
| 12960 | 12975 | if (result_loc == nullptr) result_loc = no_result_loc(); |
| 12961 | 12976 | result_loc_inst = ir_resolve_result(ira, source_instruction, result_loc, child_type, nullptr, |
| 12962 | 12977 | true, false, true); |
| ... | ... | @@ -17488,6 +17503,9 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct |
| 17488 | 17503 | return ir_get_const_ptr(ira, &elem_ptr_instruction->base, &ira->codegen->const_void_val, |
| 17489 | 17504 | ira->codegen->builtin_types.entry_void, ConstPtrMutComptimeConst, is_const, is_volatile, 0); |
| 17490 | 17505 | } |
| 17506 | } else if (array_type->id == ZigTypeIdVector) { | |
| 17507 | // This depends on whether the element index is comptime, so it is computed later. | |
| 17508 | return_type = nullptr; | |
| 17491 | 17509 | } else { |
| 17492 | 17510 | ir_add_error_node(ira, elem_ptr_instruction->base.source_node, |
| 17493 | 17511 | buf_sprintf("array access of non-array type '%s'", buf_ptr(&array_type->name))); |
| ... | ... | @@ -17512,8 +17530,14 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct |
| 17512 | 17530 | } |
| 17513 | 17531 | safety_check_on = false; |
| 17514 | 17532 | } |
| 17515 | ||
| 17516 | if (return_type->data.pointer.explicit_alignment != 0) { | |
| 17533 | if (array_type->id == ZigTypeIdVector) { | |
| 17534 | ZigType *elem_type = array_type->data.vector.elem_type; | |
| 17535 | uint32_t host_vec_len = array_type->data.vector.len; | |
| 17536 | return_type = get_pointer_to_type_extra2(ira->codegen, elem_type, | |
| 17537 | ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, | |
| 17538 | elem_ptr_instruction->ptr_len, | |
| 17539 | get_ptr_align(ira->codegen, ptr_type), 0, host_vec_len, false, (uint32_t)index); | |
| 17540 | } else if (return_type->data.pointer.explicit_alignment != 0) { | |
| 17517 | 17541 | // figure out the largest alignment possible |
| 17518 | 17542 | |
| 17519 | 17543 | if ((err = type_resolve(ira->codegen, return_type->data.pointer.child_type, ResolveStatusSizeKnown))) |
| ... | ... | @@ -17742,6 +17766,14 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct |
| 17742 | 17766 | } |
| 17743 | 17767 | } |
| 17744 | 17768 | } |
| 17769 | } else if (array_type->id == ZigTypeIdVector) { | |
| 17770 | // runtime known element index | |
| 17771 | ZigType *elem_type = array_type->data.vector.elem_type; | |
| 17772 | uint32_t host_vec_len = array_type->data.vector.len; | |
| 17773 | return_type = get_pointer_to_type_extra2(ira->codegen, elem_type, | |
| 17774 | ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, | |
| 17775 | elem_ptr_instruction->ptr_len, | |
| 17776 | get_ptr_align(ira->codegen, ptr_type), 0, host_vec_len, false, VECTOR_INDEX_RUNTIME); | |
| 17745 | 17777 | } else { |
| 17746 | 17778 | // runtime known element index |
| 17747 | 17779 | switch (type_requires_comptime(ira->codegen, return_type)) { |
test/stage1/behavior/vector.zig+17| ... | ... | @@ -159,3 +159,20 @@ test "vector @splat" { |
| 159 | 159 | S.doTheTest(); |
| 160 | 160 | comptime S.doTheTest(); |
| 161 | 161 | } |
| 162 | ||
| 163 | test "load vector elements via comptime index" { | |
| 164 | const S = struct { | |
| 165 | fn doTheTest() void { | |
| 166 | var v: @Vector(4, i32) = [_]i32{ 1, 2, 3, undefined }; | |
| 167 | expect(v[0] == 1); | |
| 168 | expect(v[1] == 2); | |
| 169 | expect(loadv(&v[2]) == 3); | |
| 170 | } | |
| 171 | fn loadv(ptr: var) i32 { | |
| 172 | return ptr.*; | |
| 173 | } | |
| 174 | }; | |
| 175 | ||
| 176 | S.doTheTest(); | |
| 177 | //comptime S.doTheTest(); | |
| 178 | } |