| author | |
| committer | |
| log | cb8af1c6d48d5fdb26484a070b8af069c4152049 |
| tree | 0c3baee6423b40eda3ba57e9d41041f6c9fbd3b8 |
| parent | a26e9fa7238e972301f761db80434fa0205d1016 |
| parent | 9a08de93b64a332af9f581ef15b208e153fa19f0 |
| signature |
This introduces the concept of vector index being part of a pointer
type. This avoids vectors having well-defined in-memory layout, and
allows vectors of any integer bit width to work the same way.
When a vector is indexed with a scalar, this is vector element access,
which this branch implements. When a vector is indexed with a vector,
this is gather/scatter, which is not implemented in this branch.
closes #3575
closes #35808 files changed, 422 insertions(+), 41 deletions(-)
src/all_types.hpp+30-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; |
| ... | ... | @@ -2414,6 +2426,7 @@ enum IrInstructionId { |
| 2414 | 2426 | IrInstructionIdLoadPtr, |
| 2415 | 2427 | IrInstructionIdLoadPtrGen, |
| 2416 | 2428 | IrInstructionIdStorePtr, |
| 2429 | IrInstructionIdVectorStoreElem, | |
| 2417 | 2430 | IrInstructionIdFieldPtr, |
| 2418 | 2431 | IrInstructionIdStructFieldPtr, |
| 2419 | 2432 | IrInstructionIdUnionFieldPtr, |
| ... | ... | @@ -2563,6 +2576,7 @@ enum IrInstructionId { |
| 2563 | 2576 | IrInstructionIdResume, |
| 2564 | 2577 | IrInstructionIdSpillBegin, |
| 2565 | 2578 | IrInstructionIdSpillEnd, |
| 2579 | IrInstructionIdVectorExtractElem, | |
| 2566 | 2580 | }; |
| 2567 | 2581 | |
| 2568 | 2582 | struct IrInstruction { |
| ... | ... | @@ -2757,6 +2771,14 @@ struct IrInstructionStorePtr { |
| 2757 | 2771 | IrInstruction *value; |
| 2758 | 2772 | }; |
| 2759 | 2773 | |
| 2774 | struct IrInstructionVectorStoreElem { | |
| 2775 | IrInstruction base; | |
| 2776 | ||
| 2777 | IrInstruction *vector_ptr; | |
| 2778 | IrInstruction *index; | |
| 2779 | IrInstruction *value; | |
| 2780 | }; | |
| 2781 | ||
| 2760 | 2782 | struct IrInstructionFieldPtr { |
| 2761 | 2783 | IrInstruction base; |
| 2762 | 2784 | |
| ... | ... | @@ -3890,6 +3912,13 @@ struct IrInstructionSpillEnd { |
| 3890 | 3912 | IrInstructionSpillBegin *begin; |
| 3891 | 3913 | }; |
| 3892 | 3914 | |
| 3915 | struct IrInstructionVectorExtractElem { | |
| 3916 | IrInstruction base; | |
| 3917 | ||
| 3918 | IrInstruction *vector; | |
| 3919 | IrInstruction *index; | |
| 3920 | }; | |
| 3921 | ||
| 3893 | 3922 | enum ResultLocId { |
| 3894 | 3923 | ResultLocIdInvalid, |
| 3895 | 3924 | ResultLocIdNone, |
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 ") %s%s%s%s", | |
| 556 | star_str, | |
| 557 | bit_offset_in_host, host_int_bytes, | |
| 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+68-14| ... | ... | @@ -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; |
| ... | ... | @@ -1635,6 +1640,17 @@ static void gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_type, |
| 1635 | 1640 | return; |
| 1636 | 1641 | } |
| 1637 | 1642 | |
| 1643 | assert(ptr_type->data.pointer.vector_index != VECTOR_INDEX_RUNTIME); | |
| 1644 | if (ptr_type->data.pointer.vector_index != VECTOR_INDEX_NONE) { | |
| 1645 | LLVMValueRef index_val = LLVMConstInt(LLVMInt32Type(), | |
| 1646 | ptr_type->data.pointer.vector_index, false); | |
| 1647 | LLVMValueRef loaded_vector = gen_load(g, ptr, ptr_type, ""); | |
| 1648 | LLVMValueRef new_vector = LLVMBuildInsertElement(g->builder, loaded_vector, value, | |
| 1649 | index_val, ""); | |
| 1650 | gen_store(g, new_vector, ptr, ptr_type); | |
| 1651 | return; | |
| 1652 | } | |
| 1653 | ||
| 1638 | 1654 | uint32_t host_int_bytes = ptr_type->data.pointer.host_int_bytes; |
| 1639 | 1655 | if (host_int_bytes == 0) { |
| 1640 | 1656 | gen_store(g, value, ptr, ptr_type); |
| ... | ... | @@ -1695,11 +1711,11 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) { |
| 1695 | 1711 | } |
| 1696 | 1712 | if (instruction->spill != nullptr) { |
| 1697 | 1713 | ZigType *ptr_type = instruction->spill->value.type; |
| 1698 | src_assert(ptr_type->id == ZigTypeIdPointer, instruction->source_node); | |
| 1714 | ir_assert(ptr_type->id == ZigTypeIdPointer, instruction); | |
| 1699 | 1715 | return get_handle_value(g, ir_llvm_value(g, instruction->spill), |
| 1700 | 1716 | ptr_type->data.pointer.child_type, instruction->spill->value.type); |
| 1701 | 1717 | } |
| 1702 | src_assert(instruction->value.special != ConstValSpecialRuntime, instruction->source_node); | |
| 1718 | ir_assert(instruction->value.special != ConstValSpecialRuntime, instruction); | |
| 1703 | 1719 | assert(instruction->value.type); |
| 1704 | 1720 | render_const_val(g, &instruction->value, ""); |
| 1705 | 1721 | // we might have to do some pointer casting here due to the way union |
| ... | ... | @@ -2428,8 +2444,7 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns |
| 2428 | 2444 | return nullptr; |
| 2429 | 2445 | } |
| 2430 | 2446 | assert(g->cur_ret_ptr); |
| 2431 | src_assert(instruction->operand->value.special != ConstValSpecialRuntime, | |
| 2432 | instruction->base.source_node); | |
| 2447 | ir_assert(instruction->operand->value.special != ConstValSpecialRuntime, &instruction->base); | |
| 2433 | 2448 | LLVMValueRef value = ir_llvm_value(g, instruction->operand); |
| 2434 | 2449 | ZigType *return_type = instruction->operand->value.type; |
| 2435 | 2450 | gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value); |
| ... | ... | @@ -3399,7 +3414,9 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, IrI |
| 3399 | 3414 | return nullptr; |
| 3400 | 3415 | } |
| 3401 | 3416 | |
| 3402 | static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrInstructionLoadPtrGen *instruction) { | |
| 3417 | static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, | |
| 3418 | IrInstructionLoadPtrGen *instruction) | |
| 3419 | { | |
| 3403 | 3420 | ZigType *child_type = instruction->base.value.type; |
| 3404 | 3421 | if (!type_has_bits(child_type)) |
| 3405 | 3422 | return nullptr; |
| ... | ... | @@ -3408,6 +3425,14 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI |
| 3408 | 3425 | ZigType *ptr_type = instruction->ptr->value.type; |
| 3409 | 3426 | assert(ptr_type->id == ZigTypeIdPointer); |
| 3410 | 3427 | |
| 3428 | ir_assert(ptr_type->data.pointer.vector_index != VECTOR_INDEX_RUNTIME, &instruction->base); | |
| 3429 | if (ptr_type->data.pointer.vector_index != VECTOR_INDEX_NONE) { | |
| 3430 | LLVMValueRef index_val = LLVMConstInt(LLVMInt32Type(), | |
| 3431 | ptr_type->data.pointer.vector_index, false); | |
| 3432 | LLVMValueRef loaded_vector = LLVMBuildLoad(g->builder, ptr, ""); | |
| 3433 | return LLVMBuildExtractElement(g->builder, loaded_vector, index_val, ""); | |
| 3434 | } | |
| 3435 | ||
| 3411 | 3436 | uint32_t host_int_bytes = ptr_type->data.pointer.host_int_bytes; |
| 3412 | 3437 | if (host_int_bytes == 0) |
| 3413 | 3438 | return get_handle_value(g, ptr, child_type, ptr_type); |
| ... | ... | @@ -3619,6 +3644,19 @@ static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, Ir |
| 3619 | 3644 | return nullptr; |
| 3620 | 3645 | } |
| 3621 | 3646 | |
| 3647 | static LLVMValueRef ir_render_vector_store_elem(CodeGen *g, IrExecutable *executable, | |
| 3648 | IrInstructionVectorStoreElem *instruction) | |
| 3649 | { | |
| 3650 | LLVMValueRef vector_ptr = ir_llvm_value(g, instruction->vector_ptr); | |
| 3651 | LLVMValueRef index = ir_llvm_value(g, instruction->index); | |
| 3652 | LLVMValueRef value = ir_llvm_value(g, instruction->value); | |
| 3653 | ||
| 3654 | LLVMValueRef loaded_vector = gen_load(g, vector_ptr, instruction->vector_ptr->value.type, ""); | |
| 3655 | LLVMValueRef modified_vector = LLVMBuildInsertElement(g->builder, loaded_vector, value, index, ""); | |
| 3656 | gen_store(g, modified_vector, vector_ptr, instruction->vector_ptr->value.type); | |
| 3657 | return nullptr; | |
| 3658 | } | |
| 3659 | ||
| 3622 | 3660 | static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrInstructionVarPtr *instruction) { |
| 3623 | 3661 | if (instruction->base.value.special != ConstValSpecialRuntime) |
| 3624 | 3662 | return ir_llvm_value(g, &instruction->base); |
| ... | ... | @@ -3636,7 +3674,7 @@ static LLVMValueRef ir_render_return_ptr(CodeGen *g, IrExecutable *executable, |
| 3636 | 3674 | { |
| 3637 | 3675 | if (!type_has_bits(instruction->base.value.type)) |
| 3638 | 3676 | return nullptr; |
| 3639 | src_assert(g->cur_ret_ptr != nullptr, instruction->base.source_node); | |
| 3677 | ir_assert(g->cur_ret_ptr != nullptr, &instruction->base); | |
| 3640 | 3678 | return g->cur_ret_ptr; |
| 3641 | 3679 | } |
| 3642 | 3680 | |
| ... | ... | @@ -3645,7 +3683,6 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI |
| 3645 | 3683 | ZigType *array_ptr_type = instruction->array_ptr->value.type; |
| 3646 | 3684 | assert(array_ptr_type->id == ZigTypeIdPointer); |
| 3647 | 3685 | ZigType *array_type = array_ptr_type->data.pointer.child_type; |
| 3648 | LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type); | |
| 3649 | 3686 | LLVMValueRef subscript_value = ir_llvm_value(g, instruction->elem_index); |
| 3650 | 3687 | assert(subscript_value); |
| 3651 | 3688 | |
| ... | ... | @@ -3657,6 +3694,7 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI |
| 3657 | 3694 | if (array_type->id == ZigTypeIdArray || |
| 3658 | 3695 | (array_type->id == ZigTypeIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle)) |
| 3659 | 3696 | { |
| 3697 | LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type); | |
| 3660 | 3698 | if (array_type->id == ZigTypeIdPointer) { |
| 3661 | 3699 | assert(array_type->data.pointer.child_type->id == ZigTypeIdArray); |
| 3662 | 3700 | array_type = array_type->data.pointer.child_type; |
| ... | ... | @@ -3696,12 +3734,14 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI |
| 3696 | 3734 | }; |
| 3697 | 3735 | return LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, ""); |
| 3698 | 3736 | } else if (array_type->id == ZigTypeIdPointer) { |
| 3737 | LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type); | |
| 3699 | 3738 | assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind); |
| 3700 | 3739 | LLVMValueRef indices[] = { |
| 3701 | 3740 | subscript_value |
| 3702 | 3741 | }; |
| 3703 | 3742 | return LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 1, ""); |
| 3704 | 3743 | } else if (array_type->id == ZigTypeIdStruct) { |
| 3744 | LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type); | |
| 3705 | 3745 | assert(array_type->data.structure.is_slice); |
| 3706 | 3746 | |
| 3707 | 3747 | ZigType *ptr_type = instruction->base.value.type; |
| ... | ... | @@ -3729,6 +3769,8 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI |
| 3729 | 3769 | LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, (unsigned)ptr_index, ""); |
| 3730 | 3770 | LLVMValueRef ptr = gen_load_untyped(g, ptr_ptr, 0, false, ""); |
| 3731 | 3771 | return LLVMBuildInBoundsGEP(g->builder, ptr, &subscript_value, 1, ""); |
| 3772 | } else if (array_type->id == ZigTypeIdVector) { | |
| 3773 | return array_ptr_ptr; | |
| 3732 | 3774 | } else { |
| 3733 | 3775 | zig_unreachable(); |
| 3734 | 3776 | } |
| ... | ... | @@ -3917,9 +3959,9 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3917 | 3959 | if (instruction->modifier == CallModifierAsync) { |
| 3918 | 3960 | frame_result_loc = result_loc; |
| 3919 | 3961 | } else { |
| 3920 | src_assert(instruction->frame_result_loc != nullptr, instruction->base.source_node); | |
| 3962 | ir_assert(instruction->frame_result_loc != nullptr, &instruction->base); | |
| 3921 | 3963 | frame_result_loc_uncasted = ir_llvm_value(g, instruction->frame_result_loc); |
| 3922 | src_assert(instruction->fn_entry != nullptr, instruction->base.source_node); | |
| 3964 | ir_assert(instruction->fn_entry != nullptr, &instruction->base); | |
| 3923 | 3965 | frame_result_loc = LLVMBuildBitCast(g->builder, frame_result_loc_uncasted, |
| 3924 | 3966 | LLVMPointerType(get_llvm_type(g, instruction->fn_entry->frame_type), 0), ""); |
| 3925 | 3967 | } |
| ... | ... | @@ -4271,10 +4313,10 @@ static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executa |
| 4271 | 4313 | if ((err = type_resolve(g, struct_type, ResolveStatusLLVMFull))) |
| 4272 | 4314 | codegen_report_errors_and_exit(g); |
| 4273 | 4315 | |
| 4274 | src_assert(field->gen_index != SIZE_MAX, instruction->base.source_node); | |
| 4316 | ir_assert(field->gen_index != SIZE_MAX, &instruction->base); | |
| 4275 | 4317 | LLVMValueRef field_ptr_val = LLVMBuildStructGEP(g->builder, struct_ptr, (unsigned)field->gen_index, ""); |
| 4276 | 4318 | ZigType *res_type = instruction->base.value.type; |
| 4277 | src_assert(res_type->id == ZigTypeIdPointer, instruction->base.source_node); | |
| 4319 | ir_assert(res_type->id == ZigTypeIdPointer, &instruction->base); | |
| 4278 | 4320 | if (res_type->data.pointer.host_int_bytes != 0) { |
| 4279 | 4321 | // We generate packed structs with get_llvm_type_of_n_bytes, which is |
| 4280 | 4322 | // u8 for 1 byte or [n]u8 for multiple bytes. But the pointer to the type |
| ... | ... | @@ -4684,7 +4726,7 @@ static LLVMValueRef ir_render_shuffle_vector(CodeGen *g, IrExecutable *executabl |
| 4684 | 4726 | |
| 4685 | 4727 | static LLVMValueRef ir_render_splat(CodeGen *g, IrExecutable *executable, IrInstructionSplatGen *instruction) { |
| 4686 | 4728 | ZigType *result_type = instruction->base.value.type; |
| 4687 | src_assert(result_type->id == ZigTypeIdVector, instruction->base.source_node); | |
| 4729 | ir_assert(result_type->id == ZigTypeIdVector, &instruction->base); | |
| 4688 | 4730 | uint32_t len = result_type->data.vector.len; |
| 4689 | 4731 | LLVMTypeRef op_llvm_type = LLVMVectorType(get_llvm_type(g, instruction->scalar->value.type), 1); |
| 4690 | 4732 | LLVMTypeRef mask_llvm_type = LLVMVectorType(LLVMInt32Type(), len); |
| ... | ... | @@ -5039,8 +5081,8 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrIn |
| 5039 | 5081 | } |
| 5040 | 5082 | |
| 5041 | 5083 | 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); | |
| 5084 | ir_assert(result_loc != nullptr, &instruction->base); | |
| 5085 | ir_assert(type_has_bits(child_type), &instruction->base); | |
| 5044 | 5086 | |
| 5045 | 5087 | LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, ""); |
| 5046 | 5088 | LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, result_loc, maybe_child_index, ""); |
| ... | ... | @@ -5973,6 +6015,14 @@ static LLVMValueRef ir_render_spill_end(CodeGen *g, IrExecutable *executable, Ir |
| 5973 | 6015 | zig_unreachable(); |
| 5974 | 6016 | } |
| 5975 | 6017 | |
| 6018 | static LLVMValueRef ir_render_vector_extract_elem(CodeGen *g, IrExecutable *executable, | |
| 6019 | IrInstructionVectorExtractElem *instruction) | |
| 6020 | { | |
| 6021 | LLVMValueRef vector = ir_llvm_value(g, instruction->vector); | |
| 6022 | LLVMValueRef index = ir_llvm_value(g, instruction->index); | |
| 6023 | return LLVMBuildExtractElement(g->builder, vector, index, ""); | |
| 6024 | } | |
| 6025 | ||
| 5976 | 6026 | static void set_debug_location(CodeGen *g, IrInstruction *instruction) { |
| 5977 | 6027 | AstNode *source_node = instruction->source_node; |
| 5978 | 6028 | Scope *scope = instruction->scope; |
| ... | ... | @@ -6093,6 +6143,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 6093 | 6143 | return ir_render_load_ptr(g, executable, (IrInstructionLoadPtrGen *)instruction); |
| 6094 | 6144 | case IrInstructionIdStorePtr: |
| 6095 | 6145 | return ir_render_store_ptr(g, executable, (IrInstructionStorePtr *)instruction); |
| 6146 | case IrInstructionIdVectorStoreElem: | |
| 6147 | return ir_render_vector_store_elem(g, executable, (IrInstructionVectorStoreElem *)instruction); | |
| 6096 | 6148 | case IrInstructionIdVarPtr: |
| 6097 | 6149 | return ir_render_var_ptr(g, executable, (IrInstructionVarPtr *)instruction); |
| 6098 | 6150 | case IrInstructionIdReturnPtr: |
| ... | ... | @@ -6233,6 +6285,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 6233 | 6285 | return ir_render_shuffle_vector(g, executable, (IrInstructionShuffleVector *) instruction); |
| 6234 | 6286 | case IrInstructionIdSplatGen: |
| 6235 | 6287 | return ir_render_splat(g, executable, (IrInstructionSplatGen *) instruction); |
| 6288 | case IrInstructionIdVectorExtractElem: | |
| 6289 | return ir_render_vector_extract_elem(g, executable, (IrInstructionVectorExtractElem *) instruction); | |
| 6236 | 6290 | } |
| 6237 | 6291 | zig_unreachable(); |
| 6238 | 6292 | } |
src/ir.cpp+111-10| ... | ... | @@ -491,6 +491,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionStorePtr *) { |
| 491 | 491 | return IrInstructionIdStorePtr; |
| 492 | 492 | } |
| 493 | 493 | |
| 494 | static constexpr IrInstructionId ir_instruction_id(IrInstructionVectorStoreElem *) { | |
| 495 | return IrInstructionIdVectorStoreElem; | |
| 496 | } | |
| 497 | ||
| 494 | 498 | static constexpr IrInstructionId ir_instruction_id(IrInstructionFieldPtr *) { |
| 495 | 499 | return IrInstructionIdFieldPtr; |
| 496 | 500 | } |
| ... | ... | @@ -1083,6 +1087,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSpillEnd *) { |
| 1083 | 1087 | return IrInstructionIdSpillEnd; |
| 1084 | 1088 | } |
| 1085 | 1089 | |
| 1090 | static constexpr IrInstructionId ir_instruction_id(IrInstructionVectorExtractElem *) { | |
| 1091 | return IrInstructionIdVectorExtractElem; | |
| 1092 | } | |
| 1093 | ||
| 1086 | 1094 | template<typename T> |
| 1087 | 1095 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 1088 | 1096 | const char *name = nullptr; |
| ... | ... | @@ -1627,6 +1635,23 @@ static IrInstructionStorePtr *ir_build_store_ptr(IrBuilder *irb, Scope *scope, A |
| 1627 | 1635 | return instruction; |
| 1628 | 1636 | } |
| 1629 | 1637 | |
| 1638 | static IrInstruction *ir_build_vector_store_elem(IrAnalyze *ira, IrInstruction *source_instruction, | |
| 1639 | IrInstruction *vector_ptr, IrInstruction *index, IrInstruction *value) | |
| 1640 | { | |
| 1641 | IrInstructionVectorStoreElem *inst = ir_build_instruction<IrInstructionVectorStoreElem>( | |
| 1642 | &ira->new_irb, source_instruction->scope, source_instruction->source_node); | |
| 1643 | inst->base.value.type = ira->codegen->builtin_types.entry_void; | |
| 1644 | inst->vector_ptr = vector_ptr; | |
| 1645 | inst->index = index; | |
| 1646 | inst->value = value; | |
| 1647 | ||
| 1648 | ir_ref_instruction(vector_ptr, ira->new_irb.current_basic_block); | |
| 1649 | ir_ref_instruction(index, ira->new_irb.current_basic_block); | |
| 1650 | ir_ref_instruction(value, ira->new_irb.current_basic_block); | |
| 1651 | ||
| 1652 | return &inst->base; | |
| 1653 | } | |
| 1654 | ||
| 1630 | 1655 | static IrInstruction *ir_build_var_decl_src(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 1631 | 1656 | ZigVar *var, IrInstruction *align_value, IrInstruction *ptr) |
| 1632 | 1657 | { |
| ... | ... | @@ -3419,6 +3444,21 @@ static IrInstruction *ir_build_spill_end(IrBuilder *irb, Scope *scope, AstNode * |
| 3419 | 3444 | return &instruction->base; |
| 3420 | 3445 | } |
| 3421 | 3446 | |
| 3447 | static IrInstruction *ir_build_vector_extract_elem(IrAnalyze *ira, IrInstruction *source_instruction, | |
| 3448 | IrInstruction *vector, IrInstruction *index) | |
| 3449 | { | |
| 3450 | IrInstructionVectorExtractElem *instruction = ir_build_instruction<IrInstructionVectorExtractElem>( | |
| 3451 | &ira->new_irb, source_instruction->scope, source_instruction->source_node); | |
| 3452 | instruction->base.value.type = vector->value.type->data.vector.elem_type; | |
| 3453 | instruction->vector = vector; | |
| 3454 | instruction->index = index; | |
| 3455 | ||
| 3456 | ir_ref_instruction(vector, ira->new_irb.current_basic_block); | |
| 3457 | ir_ref_instruction(index, ira->new_irb.current_basic_block); | |
| 3458 | ||
| 3459 | return &instruction->base; | |
| 3460 | } | |
| 3461 | ||
| 3422 | 3462 | static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { |
| 3423 | 3463 | results[ReturnKindUnconditional] = 0; |
| 3424 | 3464 | results[ReturnKindError] = 0; |
| ... | ... | @@ -12908,18 +12948,18 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc |
| 12908 | 12948 | ResultLoc *result_loc) |
| 12909 | 12949 | { |
| 12910 | 12950 | Error err; |
| 12911 | ZigType *type_entry = ptr->value.type; | |
| 12912 | if (type_is_invalid(type_entry)) | |
| 12951 | ZigType *ptr_type = ptr->value.type; | |
| 12952 | if (type_is_invalid(ptr_type)) | |
| 12913 | 12953 | return ira->codegen->invalid_instruction; |
| 12914 | 12954 | |
| 12915 | if (type_entry->id != ZigTypeIdPointer) { | |
| 12955 | if (ptr_type->id != ZigTypeIdPointer) { | |
| 12916 | 12956 | ir_add_error_node(ira, source_instruction->source_node, |
| 12917 | 12957 | buf_sprintf("attempt to dereference non-pointer type '%s'", |
| 12918 | buf_ptr(&type_entry->name))); | |
| 12958 | buf_ptr(&ptr_type->name))); | |
| 12919 | 12959 | return ira->codegen->invalid_instruction; |
| 12920 | 12960 | } |
| 12921 | 12961 | |
| 12922 | ZigType *child_type = type_entry->data.pointer.child_type; | |
| 12962 | ZigType *child_type = ptr_type->data.pointer.child_type; | |
| 12923 | 12963 | // if the child type has one possible value, the deref is comptime |
| 12924 | 12964 | switch (type_has_one_possible_value(ira->codegen, child_type)) { |
| 12925 | 12965 | case OnePossibleValueInvalid: |
| ... | ... | @@ -12949,14 +12989,36 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc |
| 12949 | 12989 | } |
| 12950 | 12990 | } |
| 12951 | 12991 | } |
| 12992 | ||
| 12952 | 12993 | // if the instruction is a const ref instruction we can skip it |
| 12953 | 12994 | if (ptr->id == IrInstructionIdRef) { |
| 12954 | 12995 | IrInstructionRef *ref_inst = reinterpret_cast<IrInstructionRef *>(ptr); |
| 12955 | 12996 | return ref_inst->value; |
| 12956 | 12997 | } |
| 12957 | 12998 | |
| 12999 | // If the instruction is a element pointer instruction to a vector, we emit | |
| 13000 | // vector element extract instruction rather than load pointer. If the | |
| 13001 | // pointer type has non-VECTOR_INDEX_RUNTIME value, it would have been | |
| 13002 | // possible to implement this in the codegen for IrInstructionLoadPtrGen. | |
| 13003 | // However if it has VECTOR_INDEX_RUNTIME then we must emit a compile error | |
| 13004 | // if the vector index cannot be determined right here, right now, because | |
| 13005 | // the type information does not contain enough information to actually | |
| 13006 | // perform a dereference. | |
| 13007 | if (ptr_type->data.pointer.vector_index == VECTOR_INDEX_RUNTIME) { | |
| 13008 | if (ptr->id == IrInstructionIdElemPtr) { | |
| 13009 | IrInstructionElemPtr *elem_ptr = (IrInstructionElemPtr *)ptr; | |
| 13010 | IrInstruction *vector_loaded = ir_get_deref(ira, elem_ptr->array_ptr, | |
| 13011 | elem_ptr->array_ptr, nullptr); | |
| 13012 | IrInstruction *elem_index = elem_ptr->elem_index; | |
| 13013 | return ir_build_vector_extract_elem(ira, source_instruction, vector_loaded, elem_index); | |
| 13014 | } | |
| 13015 | ir_add_error(ira, ptr, | |
| 13016 | buf_sprintf("unable to determine vector element index of type '%s'", buf_ptr(&ptr_type->name))); | |
| 13017 | return ira->codegen->invalid_instruction; | |
| 13018 | } | |
| 13019 | ||
| 12958 | 13020 | IrInstruction *result_loc_inst; |
| 12959 | if (type_entry->data.pointer.host_int_bytes != 0 && handle_is_ptr(child_type)) { | |
| 13021 | if (ptr_type->data.pointer.host_int_bytes != 0 && handle_is_ptr(child_type)) { | |
| 12960 | 13022 | if (result_loc == nullptr) result_loc = no_result_loc(); |
| 12961 | 13023 | result_loc_inst = ir_resolve_result(ira, source_instruction, result_loc, child_type, nullptr, |
| 12962 | 13024 | true, false, true); |
| ... | ... | @@ -16085,6 +16147,24 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source |
| 16085 | 16147 | mark_comptime_value_escape(ira, source_instr, &value->value); |
| 16086 | 16148 | } |
| 16087 | 16149 | |
| 16150 | // If this is a store to a pointer with a runtime-known vector index, | |
| 16151 | // we have to figure out the IrInstruction which represents the index and | |
| 16152 | // emit a IrInstructionVectorStoreElem, or emit a compile error | |
| 16153 | // explaining why it is impossible for this store to work. Which is that | |
| 16154 | // the pointer address is of the vector; without the element index being known | |
| 16155 | // we cannot properly perform the insertion. | |
| 16156 | if (ptr->value.type->data.pointer.vector_index == VECTOR_INDEX_RUNTIME) { | |
| 16157 | if (ptr->id == IrInstructionIdElemPtr) { | |
| 16158 | IrInstructionElemPtr *elem_ptr = (IrInstructionElemPtr *)ptr; | |
| 16159 | return ir_build_vector_store_elem(ira, source_instr, elem_ptr->array_ptr, | |
| 16160 | elem_ptr->elem_index, value); | |
| 16161 | } | |
| 16162 | ir_add_error(ira, ptr, | |
| 16163 | buf_sprintf("unable to determine vector element index of type '%s'", | |
| 16164 | buf_ptr(&ptr->value.type->name))); | |
| 16165 | return ira->codegen->invalid_instruction; | |
| 16166 | } | |
| 16167 | ||
| 16088 | 16168 | IrInstructionStorePtr *store_ptr = ir_build_store_ptr(&ira->new_irb, source_instr->scope, |
| 16089 | 16169 | source_instr->source_node, ptr, value); |
| 16090 | 16170 | return &store_ptr->base; |
| ... | ... | @@ -17488,6 +17568,9 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct |
| 17488 | 17568 | return ir_get_const_ptr(ira, &elem_ptr_instruction->base, &ira->codegen->const_void_val, |
| 17489 | 17569 | ira->codegen->builtin_types.entry_void, ConstPtrMutComptimeConst, is_const, is_volatile, 0); |
| 17490 | 17570 | } |
| 17571 | } else if (array_type->id == ZigTypeIdVector) { | |
| 17572 | // This depends on whether the element index is comptime, so it is computed later. | |
| 17573 | return_type = nullptr; | |
| 17491 | 17574 | } else { |
| 17492 | 17575 | ir_add_error_node(ira, elem_ptr_instruction->base.source_node, |
| 17493 | 17576 | buf_sprintf("array access of non-array type '%s'", buf_ptr(&array_type->name))); |
| ... | ... | @@ -17512,8 +17595,14 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct |
| 17512 | 17595 | } |
| 17513 | 17596 | safety_check_on = false; |
| 17514 | 17597 | } |
| 17515 | ||
| 17516 | if (return_type->data.pointer.explicit_alignment != 0) { | |
| 17598 | if (array_type->id == ZigTypeIdVector) { | |
| 17599 | ZigType *elem_type = array_type->data.vector.elem_type; | |
| 17600 | uint32_t host_vec_len = array_type->data.vector.len; | |
| 17601 | return_type = get_pointer_to_type_extra2(ira->codegen, elem_type, | |
| 17602 | ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, | |
| 17603 | elem_ptr_instruction->ptr_len, | |
| 17604 | get_ptr_align(ira->codegen, ptr_type), 0, host_vec_len, false, (uint32_t)index); | |
| 17605 | } else if (return_type->data.pointer.explicit_alignment != 0) { | |
| 17517 | 17606 | // figure out the largest alignment possible |
| 17518 | 17607 | |
| 17519 | 17608 | if ((err = type_resolve(ira->codegen, return_type->data.pointer.child_type, ResolveStatusSizeKnown))) |
| ... | ... | @@ -17551,7 +17640,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct |
| 17551 | 17640 | return ira->codegen->invalid_instruction; |
| 17552 | 17641 | |
| 17553 | 17642 | if (array_ptr_val->special == ConstValSpecialUndef && elem_ptr_instruction->init_array_type != nullptr) { |
| 17554 | if (array_type->id == ZigTypeIdArray) { | |
| 17643 | if (array_type->id == ZigTypeIdArray || array_type->id == ZigTypeIdVector) { | |
| 17555 | 17644 | array_ptr_val->data.x_array.special = ConstArraySpecialNone; |
| 17556 | 17645 | array_ptr_val->data.x_array.data.s_none.elements = create_const_vals(array_type->data.array.len); |
| 17557 | 17646 | array_ptr_val->special = ConstValSpecialStatic; |
| ... | ... | @@ -17720,7 +17809,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct |
| 17720 | 17809 | zig_panic("TODO elem ptr on a slice has a null pointer"); |
| 17721 | 17810 | } |
| 17722 | 17811 | return result; |
| 17723 | } else if (array_type->id == ZigTypeIdArray) { | |
| 17812 | } else if (array_type->id == ZigTypeIdArray || array_type->id == ZigTypeIdVector) { | |
| 17724 | 17813 | IrInstruction *result; |
| 17725 | 17814 | if (orig_array_ptr_val->data.x_ptr.mut == ConstPtrMutInfer) { |
| 17726 | 17815 | result = ir_build_elem_ptr(&ira->new_irb, elem_ptr_instruction->base.scope, |
| ... | ... | @@ -17742,6 +17831,14 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct |
| 17742 | 17831 | } |
| 17743 | 17832 | } |
| 17744 | 17833 | } |
| 17834 | } else if (array_type->id == ZigTypeIdVector) { | |
| 17835 | // runtime known element index | |
| 17836 | ZigType *elem_type = array_type->data.vector.elem_type; | |
| 17837 | uint32_t host_vec_len = array_type->data.vector.len; | |
| 17838 | return_type = get_pointer_to_type_extra2(ira->codegen, elem_type, | |
| 17839 | ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, | |
| 17840 | elem_ptr_instruction->ptr_len, | |
| 17841 | get_ptr_align(ira->codegen, ptr_type), 0, host_vec_len, false, VECTOR_INDEX_RUNTIME); | |
| 17745 | 17842 | } else { |
| 17746 | 17843 | // runtime known element index |
| 17747 | 17844 | switch (type_requires_comptime(ira->codegen, return_type)) { |
| ... | ... | @@ -26004,6 +26101,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction |
| 26004 | 26101 | case IrInstructionIdFrameSizeGen: |
| 26005 | 26102 | case IrInstructionIdAwaitGen: |
| 26006 | 26103 | case IrInstructionIdSplatGen: |
| 26104 | case IrInstructionIdVectorExtractElem: | |
| 26105 | case IrInstructionIdVectorStoreElem: | |
| 26007 | 26106 | zig_unreachable(); |
| 26008 | 26107 | |
| 26009 | 26108 | case IrInstructionIdReturn: |
| ... | ... | @@ -26387,6 +26486,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 26387 | 26486 | case IrInstructionIdDeclVarSrc: |
| 26388 | 26487 | case IrInstructionIdDeclVarGen: |
| 26389 | 26488 | case IrInstructionIdStorePtr: |
| 26489 | case IrInstructionIdVectorStoreElem: | |
| 26390 | 26490 | case IrInstructionIdCallSrc: |
| 26391 | 26491 | case IrInstructionIdCallGen: |
| 26392 | 26492 | case IrInstructionIdReturn: |
| ... | ... | @@ -26539,6 +26639,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 26539 | 26639 | case IrInstructionIdAllocaSrc: |
| 26540 | 26640 | case IrInstructionIdAllocaGen: |
| 26541 | 26641 | case IrInstructionIdSpillEnd: |
| 26642 | case IrInstructionIdVectorExtractElem: | |
| 26542 | 26643 | return false; |
| 26543 | 26644 | |
| 26544 | 26645 | case IrInstructionIdAsm: |
src/ir_print.cpp+27| ... | ... | @@ -78,6 +78,8 @@ const char* ir_instruction_type_str(IrInstructionId id) { |
| 78 | 78 | return "LoadPtrGen"; |
| 79 | 79 | case IrInstructionIdStorePtr: |
| 80 | 80 | return "StorePtr"; |
| 81 | case IrInstructionIdVectorStoreElem: | |
| 82 | return "VectorStoreElem"; | |
| 81 | 83 | case IrInstructionIdFieldPtr: |
| 82 | 84 | return "FieldPtr"; |
| 83 | 85 | case IrInstructionIdStructFieldPtr: |
| ... | ... | @@ -370,6 +372,8 @@ const char* ir_instruction_type_str(IrInstructionId id) { |
| 370 | 372 | return "SpillBegin"; |
| 371 | 373 | case IrInstructionIdSpillEnd: |
| 372 | 374 | return "SpillEnd"; |
| 375 | case IrInstructionIdVectorExtractElem: | |
| 376 | return "VectorExtractElem"; | |
| 373 | 377 | } |
| 374 | 378 | zig_unreachable(); |
| 375 | 379 | } |
| ... | ... | @@ -788,6 +792,15 @@ static void ir_print_store_ptr(IrPrint *irp, IrInstructionStorePtr *instruction) |
| 788 | 792 | ir_print_other_instruction(irp, instruction->value); |
| 789 | 793 | } |
| 790 | 794 | |
| 795 | static void ir_print_vector_store_elem(IrPrint *irp, IrInstructionVectorStoreElem *instruction) { | |
| 796 | fprintf(irp->f, "vector_ptr="); | |
| 797 | ir_print_var_instruction(irp, instruction->vector_ptr); | |
| 798 | fprintf(irp->f, ",index="); | |
| 799 | ir_print_var_instruction(irp, instruction->index); | |
| 800 | fprintf(irp->f, ",value="); | |
| 801 | ir_print_other_instruction(irp, instruction->value); | |
| 802 | } | |
| 803 | ||
| 791 | 804 | static void ir_print_typeof(IrPrint *irp, IrInstructionTypeOf *instruction) { |
| 792 | 805 | fprintf(irp->f, "@typeOf("); |
| 793 | 806 | ir_print_other_instruction(irp, instruction->value); |
| ... | ... | @@ -1969,6 +1982,14 @@ static void ir_print_spill_end(IrPrint *irp, IrInstructionSpillEnd *instruction) |
| 1969 | 1982 | fprintf(irp->f, ")"); |
| 1970 | 1983 | } |
| 1971 | 1984 | |
| 1985 | static void ir_print_vector_extract_elem(IrPrint *irp, IrInstructionVectorExtractElem *instruction) { | |
| 1986 | fprintf(irp->f, "@vectorExtractElem("); | |
| 1987 | ir_print_other_instruction(irp, instruction->vector); | |
| 1988 | fprintf(irp->f, ","); | |
| 1989 | ir_print_other_instruction(irp, instruction->index); | |
| 1990 | fprintf(irp->f, ")"); | |
| 1991 | } | |
| 1992 | ||
| 1972 | 1993 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction, bool trailing) { |
| 1973 | 1994 | ir_print_prefix(irp, instruction, trailing); |
| 1974 | 1995 | switch (instruction->id) { |
| ... | ... | @@ -2037,6 +2058,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction, bool |
| 2037 | 2058 | case IrInstructionIdStorePtr: |
| 2038 | 2059 | ir_print_store_ptr(irp, (IrInstructionStorePtr *)instruction); |
| 2039 | 2060 | break; |
| 2061 | case IrInstructionIdVectorStoreElem: | |
| 2062 | ir_print_vector_store_elem(irp, (IrInstructionVectorStoreElem *)instruction); | |
| 2063 | break; | |
| 2040 | 2064 | case IrInstructionIdTypeOf: |
| 2041 | 2065 | ir_print_typeof(irp, (IrInstructionTypeOf *)instruction); |
| 2042 | 2066 | break; |
| ... | ... | @@ -2466,6 +2490,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction, bool |
| 2466 | 2490 | case IrInstructionIdSpillEnd: |
| 2467 | 2491 | ir_print_spill_end(irp, (IrInstructionSpillEnd *)instruction); |
| 2468 | 2492 | break; |
| 2493 | case IrInstructionIdVectorExtractElem: | |
| 2494 | ir_print_vector_extract_elem(irp, (IrInstructionVectorExtractElem *)instruction); | |
| 2495 | break; | |
| 2469 | 2496 | } |
| 2470 | 2497 | fprintf(irp->f, "\n"); |
| 2471 | 2498 | } |
test/compile_errors.zig+32| ... | ... | @@ -24,6 +24,38 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 24 | 24 | "tmp.zig:4:20: note: referenced here", |
| 25 | 25 | ); |
| 26 | 26 | |
| 27 | cases.add( | |
| 28 | "store vector pointer with unknown runtime index", | |
| 29 | \\export fn entry() void { | |
| 30 | \\ var v: @Vector(4, i32) = [_]i32{ 1, 5, 3, undefined }; | |
| 31 | \\ | |
| 32 | \\ var i: u32 = 0; | |
| 33 | \\ storev(&v[i], 42); | |
| 34 | \\} | |
| 35 | \\ | |
| 36 | \\fn storev(ptr: var, val: i32) void { | |
| 37 | \\ ptr.* = val; | |
| 38 | \\} | |
| 39 | , | |
| 40 | "tmp.zig:9:8: error: unable to determine vector element index of type '*align(16:0:4:?) i32", | |
| 41 | ); | |
| 42 | ||
| 43 | cases.add( | |
| 44 | "load vector pointer with unknown runtime index", | |
| 45 | \\export fn entry() void { | |
| 46 | \\ var v: @Vector(4, i32) = [_]i32{ 1, 5, 3, undefined }; | |
| 47 | \\ | |
| 48 | \\ var i: u32 = 0; | |
| 49 | \\ var x = loadv(&v[i]); | |
| 50 | \\} | |
| 51 | \\ | |
| 52 | \\fn loadv(ptr: var) i32 { | |
| 53 | \\ return ptr.*; | |
| 54 | \\} | |
| 55 | , | |
| 56 | "tmp.zig:9:12: error: unable to determine vector element index of type '*align(16:0:4:?) i32", | |
| 57 | ); | |
| 58 | ||
| 27 | 59 | cases.add( |
| 28 | 60 | "using an unknown len ptr type instead of array", |
| 29 | 61 | \\const resolutions = [*][*]const u8{ |
test/stage1/behavior/vector.zig+91| ... | ... | @@ -159,3 +159,94 @@ 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 | } | |
| 179 | ||
| 180 | test "store vector elements via comptime index" { | |
| 181 | const S = struct { | |
| 182 | fn doTheTest() void { | |
| 183 | var v: @Vector(4, i32) = [_]i32{ 1, 5, 3, undefined }; | |
| 184 | ||
| 185 | v[2] = 42; | |
| 186 | expect(v[1] == 5); | |
| 187 | v[3] = -364; | |
| 188 | expect(v[2] == 42); | |
| 189 | expect(-364 == v[3]); | |
| 190 | ||
| 191 | storev(&v[0], 100); | |
| 192 | expect(v[0] == 100); | |
| 193 | } | |
| 194 | fn storev(ptr: var, x: i32) void { | |
| 195 | ptr.* = x; | |
| 196 | } | |
| 197 | }; | |
| 198 | ||
| 199 | S.doTheTest(); | |
| 200 | comptime S.doTheTest(); | |
| 201 | } | |
| 202 | ||
| 203 | test "load vector elements via runtime index" { | |
| 204 | const S = struct { | |
| 205 | fn doTheTest() void { | |
| 206 | var v: @Vector(4, i32) = [_]i32{ 1, 2, 3, undefined }; | |
| 207 | var i: u32 = 0; | |
| 208 | expect(v[i] == 1); | |
| 209 | i += 1; | |
| 210 | expect(v[i] == 2); | |
| 211 | i += 1; | |
| 212 | expect(v[i] == 3); | |
| 213 | } | |
| 214 | }; | |
| 215 | ||
| 216 | S.doTheTest(); | |
| 217 | comptime S.doTheTest(); | |
| 218 | } | |
| 219 | ||
| 220 | test "store vector elements via runtime index" { | |
| 221 | const S = struct { | |
| 222 | fn doTheTest() void { | |
| 223 | var v: @Vector(4, i32) = [_]i32{ 1, 5, 3, undefined }; | |
| 224 | var i: u32 = 2; | |
| 225 | v[i] = 1; | |
| 226 | expect(v[1] == 5); | |
| 227 | expect(v[2] == 1); | |
| 228 | i += 1; | |
| 229 | v[i] = -364; | |
| 230 | expect(-364 == v[3]); | |
| 231 | } | |
| 232 | }; | |
| 233 | ||
| 234 | S.doTheTest(); | |
| 235 | comptime S.doTheTest(); | |
| 236 | } | |
| 237 | ||
| 238 | test "initialize vector which is a struct field" { | |
| 239 | const Vec4Obj = struct { | |
| 240 | data: @Vector(4, f32), | |
| 241 | }; | |
| 242 | ||
| 243 | const S = struct { | |
| 244 | fn doTheTest() void { | |
| 245 | var foo = Vec4Obj{ | |
| 246 | .data = [_]f32{ 1, 2, 3, 4 }, | |
| 247 | }; | |
| 248 | } | |
| 249 | }; | |
| 250 | S.doTheTest(); | |
| 251 | comptime S.doTheTest(); | |
| 252 | } |