| author | |
| committer | |
| log | cbaa10fc3bcd2d5f8d48b9038e840ae508fe2822 |
| tree | d5dbbb0d4edee73b54dbd03802ab6885d5699a99 |
| parent | 70be308c4315c53d42889d568d5731ba227dcf88 |
| signature |
6 files changed, 114 insertions(+), 0 deletions(-)
src/all_types.hpp+9| ... | ... | @@ -2426,6 +2426,7 @@ enum IrInstructionId { |
| 2426 | 2426 | IrInstructionIdLoadPtr, |
| 2427 | 2427 | IrInstructionIdLoadPtrGen, |
| 2428 | 2428 | IrInstructionIdStorePtr, |
| 2429 | IrInstructionIdVectorStoreElem, | |
| 2429 | 2430 | IrInstructionIdFieldPtr, |
| 2430 | 2431 | IrInstructionIdStructFieldPtr, |
| 2431 | 2432 | IrInstructionIdUnionFieldPtr, |
| ... | ... | @@ -2770,6 +2771,14 @@ struct IrInstructionStorePtr { |
| 2770 | 2771 | IrInstruction *value; |
| 2771 | 2772 | }; |
| 2772 | 2773 | |
| 2774 | struct IrInstructionVectorStoreElem { | |
| 2775 | IrInstruction base; | |
| 2776 | ||
| 2777 | IrInstruction *vector_ptr; | |
| 2778 | IrInstruction *index; | |
| 2779 | IrInstruction *value; | |
| 2780 | }; | |
| 2781 | ||
| 2773 | 2782 | struct IrInstructionFieldPtr { |
| 2774 | 2783 | IrInstruction base; |
| 2775 | 2784 |
src/codegen.cpp+15| ... | ... | @@ -3644,6 +3644,19 @@ static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, Ir |
| 3644 | 3644 | return nullptr; |
| 3645 | 3645 | } |
| 3646 | 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 | ||
| 3647 | 3660 | static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrInstructionVarPtr *instruction) { |
| 3648 | 3661 | if (instruction->base.value.special != ConstValSpecialRuntime) |
| 3649 | 3662 | return ir_llvm_value(g, &instruction->base); |
| ... | ... | @@ -6130,6 +6143,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 6130 | 6143 | return ir_render_load_ptr(g, executable, (IrInstructionLoadPtrGen *)instruction); |
| 6131 | 6144 | case IrInstructionIdStorePtr: |
| 6132 | 6145 | return ir_render_store_ptr(g, executable, (IrInstructionStorePtr *)instruction); |
| 6146 | case IrInstructionIdVectorStoreElem: | |
| 6147 | return ir_render_vector_store_elem(g, executable, (IrInstructionVectorStoreElem *)instruction); | |
| 6133 | 6148 | case IrInstructionIdVarPtr: |
| 6134 | 6149 | return ir_render_var_ptr(g, executable, (IrInstructionVarPtr *)instruction); |
| 6135 | 6150 | case IrInstructionIdReturnPtr: |
src/ir.cpp+41| ... | ... | @@ -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 | } |
| ... | ... | @@ -1631,6 +1635,23 @@ static IrInstructionStorePtr *ir_build_store_ptr(IrBuilder *irb, Scope *scope, A |
| 1631 | 1635 | return instruction; |
| 1632 | 1636 | } |
| 1633 | 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 | ||
| 1634 | 1655 | static IrInstruction *ir_build_var_decl_src(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 1635 | 1656 | ZigVar *var, IrInstruction *align_value, IrInstruction *ptr) |
| 1636 | 1657 | { |
| ... | ... | @@ -16126,6 +16147,24 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source |
| 16126 | 16147 | mark_comptime_value_escape(ira, source_instr, &value->value); |
| 16127 | 16148 | } |
| 16128 | 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 | ||
| 16129 | 16168 | IrInstructionStorePtr *store_ptr = ir_build_store_ptr(&ira->new_irb, source_instr->scope, |
| 16130 | 16169 | source_instr->source_node, ptr, value); |
| 16131 | 16170 | return &store_ptr->base; |
| ... | ... | @@ -26063,6 +26102,7 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction |
| 26063 | 26102 | case IrInstructionIdAwaitGen: |
| 26064 | 26103 | case IrInstructionIdSplatGen: |
| 26065 | 26104 | case IrInstructionIdVectorExtractElem: |
| 26105 | case IrInstructionIdVectorStoreElem: | |
| 26066 | 26106 | zig_unreachable(); |
| 26067 | 26107 | |
| 26068 | 26108 | case IrInstructionIdReturn: |
| ... | ... | @@ -26446,6 +26486,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 26446 | 26486 | case IrInstructionIdDeclVarSrc: |
| 26447 | 26487 | case IrInstructionIdDeclVarGen: |
| 26448 | 26488 | case IrInstructionIdStorePtr: |
| 26489 | case IrInstructionIdVectorStoreElem: | |
| 26449 | 26490 | case IrInstructionIdCallSrc: |
| 26450 | 26491 | case IrInstructionIdCallGen: |
| 26451 | 26492 | case IrInstructionIdReturn: |
src/ir_print.cpp+14| ... | ... | @@ -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: |
| ... | ... | @@ -790,6 +792,15 @@ static void ir_print_store_ptr(IrPrint *irp, IrInstructionStorePtr *instruction) |
| 790 | 792 | ir_print_other_instruction(irp, instruction->value); |
| 791 | 793 | } |
| 792 | 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 | ||
| 793 | 804 | static void ir_print_typeof(IrPrint *irp, IrInstructionTypeOf *instruction) { |
| 794 | 805 | fprintf(irp->f, "@typeOf("); |
| 795 | 806 | ir_print_other_instruction(irp, instruction->value); |
| ... | ... | @@ -2047,6 +2058,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction, bool |
| 2047 | 2058 | case IrInstructionIdStorePtr: |
| 2048 | 2059 | ir_print_store_ptr(irp, (IrInstructionStorePtr *)instruction); |
| 2049 | 2060 | break; |
| 2061 | case IrInstructionIdVectorStoreElem: | |
| 2062 | ir_print_vector_store_elem(irp, (IrInstructionVectorStoreElem *)instruction); | |
| 2063 | break; | |
| 2050 | 2064 | case IrInstructionIdTypeOf: |
| 2051 | 2065 | ir_print_typeof(irp, (IrInstructionTypeOf *)instruction); |
| 2052 | 2066 | break; |
test/compile_errors.zig+17| ... | ... | @@ -26,6 +26,23 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 26 | 26 | |
| 27 | 27 | cases.add( |
| 28 | 28 | "dereference vector pointer with unknown runtime index", |
| 29 | "store vector pointer with unknown runtime index", | |
| 30 | \\export fn entry() void { | |
| 31 | \\ var v: @Vector(4, i32) = [_]i32{ 1, 5, 3, undefined }; | |
| 32 | \\ | |
| 33 | \\ var i: u32 = 0; | |
| 34 | \\ storev(&v[i], 42); | |
| 35 | \\} | |
| 36 | \\ | |
| 37 | \\fn storev(ptr: var, val: i32) void { | |
| 38 | \\ ptr.* = val; | |
| 39 | \\} | |
| 40 | , | |
| 41 | "tmp.zig:9:8: error: unable to determine vector element index of type '*align(16:0:4:?) i32", | |
| 42 | ); | |
| 43 | ||
| 44 | cases.add( | |
| 45 | "load vector pointer with unknown runtime index", | |
| 29 | 46 | \\export fn entry() void { |
| 30 | 47 | \\ var v: @Vector(4, i32) = [_]i32{ 1, 5, 3, undefined }; |
| 31 | 48 | \\ |
test/stage1/behavior/vector.zig+18| ... | ... | @@ -216,3 +216,21 @@ test "load vector elements via runtime index" { |
| 216 | 216 | S.doTheTest(); |
| 217 | 217 | comptime S.doTheTest(); |
| 218 | 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 | } |