| 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,6 +2426,7 @@ enum IrInstructionId { |
| 2426 | IrInstructionIdLoadPtr, | 2426 | IrInstructionIdLoadPtr, |
| 2427 | IrInstructionIdLoadPtrGen, | 2427 | IrInstructionIdLoadPtrGen, |
| 2428 | IrInstructionIdStorePtr, | 2428 | IrInstructionIdStorePtr, |
| 2429 | IrInstructionIdVectorStoreElem, | ||
| 2429 | IrInstructionIdFieldPtr, | 2430 | IrInstructionIdFieldPtr, |
| 2430 | IrInstructionIdStructFieldPtr, | 2431 | IrInstructionIdStructFieldPtr, |
| 2431 | IrInstructionIdUnionFieldPtr, | 2432 | IrInstructionIdUnionFieldPtr, |
| ... | @@ -2770,6 +2771,14 @@ struct IrInstructionStorePtr { | ... | @@ -2770,6 +2771,14 @@ struct IrInstructionStorePtr { |
| 2770 | IrInstruction *value; | 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 | struct IrInstructionFieldPtr { | 2782 | struct IrInstructionFieldPtr { |
| 2774 | IrInstruction base; | 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,6 +3644,19 @@ static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, Ir |
| 3644 | return nullptr; | 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 | static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrInstructionVarPtr *instruction) { | 3660 | static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrInstructionVarPtr *instruction) { |
| 3648 | if (instruction->base.value.special != ConstValSpecialRuntime) | 3661 | if (instruction->base.value.special != ConstValSpecialRuntime) |
| 3649 | return ir_llvm_value(g, &instruction->base); | 3662 | return ir_llvm_value(g, &instruction->base); |
| ... | @@ -6130,6 +6143,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, | ... | @@ -6130,6 +6143,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 6130 | return ir_render_load_ptr(g, executable, (IrInstructionLoadPtrGen *)instruction); | 6143 | return ir_render_load_ptr(g, executable, (IrInstructionLoadPtrGen *)instruction); |
| 6131 | case IrInstructionIdStorePtr: | 6144 | case IrInstructionIdStorePtr: |
| 6132 | return ir_render_store_ptr(g, executable, (IrInstructionStorePtr *)instruction); | 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 | case IrInstructionIdVarPtr: | 6148 | case IrInstructionIdVarPtr: |
| 6134 | return ir_render_var_ptr(g, executable, (IrInstructionVarPtr *)instruction); | 6149 | return ir_render_var_ptr(g, executable, (IrInstructionVarPtr *)instruction); |
| 6135 | case IrInstructionIdReturnPtr: | 6150 | case IrInstructionIdReturnPtr: |
src/ir.cpp+41| ... | @@ -491,6 +491,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionStorePtr *) { | ... | @@ -491,6 +491,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionStorePtr *) { |
| 491 | return IrInstructionIdStorePtr; | 491 | return IrInstructionIdStorePtr; |
| 492 | } | 492 | } |
| 493 | 493 | ||
| 494 | static constexpr IrInstructionId ir_instruction_id(IrInstructionVectorStoreElem *) { | ||
| 495 | return IrInstructionIdVectorStoreElem; | ||
| 496 | } | ||
| 497 | |||
| 494 | static constexpr IrInstructionId ir_instruction_id(IrInstructionFieldPtr *) { | 498 | static constexpr IrInstructionId ir_instruction_id(IrInstructionFieldPtr *) { |
| 495 | return IrInstructionIdFieldPtr; | 499 | return IrInstructionIdFieldPtr; |
| 496 | } | 500 | } |
| ... | @@ -1631,6 +1635,23 @@ static IrInstructionStorePtr *ir_build_store_ptr(IrBuilder *irb, Scope *scope, A | ... | @@ -1631,6 +1635,23 @@ static IrInstructionStorePtr *ir_build_store_ptr(IrBuilder *irb, Scope *scope, A |
| 1631 | return instruction; | 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 | static IrInstruction *ir_build_var_decl_src(IrBuilder *irb, Scope *scope, AstNode *source_node, | 1655 | static IrInstruction *ir_build_var_decl_src(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 1635 | ZigVar *var, IrInstruction *align_value, IrInstruction *ptr) | 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,6 +16147,24 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source |
| 16126 | mark_comptime_value_escape(ira, source_instr, &value->value); | 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 | IrInstructionStorePtr *store_ptr = ir_build_store_ptr(&ira->new_irb, source_instr->scope, | 16168 | IrInstructionStorePtr *store_ptr = ir_build_store_ptr(&ira->new_irb, source_instr->scope, |
| 16130 | source_instr->source_node, ptr, value); | 16169 | source_instr->source_node, ptr, value); |
| 16131 | return &store_ptr->base; | 16170 | return &store_ptr->base; |
| ... | @@ -26063,6 +26102,7 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction | ... | @@ -26063,6 +26102,7 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction |
| 26063 | case IrInstructionIdAwaitGen: | 26102 | case IrInstructionIdAwaitGen: |
| 26064 | case IrInstructionIdSplatGen: | 26103 | case IrInstructionIdSplatGen: |
| 26065 | case IrInstructionIdVectorExtractElem: | 26104 | case IrInstructionIdVectorExtractElem: |
| 26105 | case IrInstructionIdVectorStoreElem: | ||
| 26066 | zig_unreachable(); | 26106 | zig_unreachable(); |
| 26067 | 26107 | ||
| 26068 | case IrInstructionIdReturn: | 26108 | case IrInstructionIdReturn: |
| ... | @@ -26446,6 +26486,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -26446,6 +26486,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 26446 | case IrInstructionIdDeclVarSrc: | 26486 | case IrInstructionIdDeclVarSrc: |
| 26447 | case IrInstructionIdDeclVarGen: | 26487 | case IrInstructionIdDeclVarGen: |
| 26448 | case IrInstructionIdStorePtr: | 26488 | case IrInstructionIdStorePtr: |
| 26489 | case IrInstructionIdVectorStoreElem: | ||
| 26449 | case IrInstructionIdCallSrc: | 26490 | case IrInstructionIdCallSrc: |
| 26450 | case IrInstructionIdCallGen: | 26491 | case IrInstructionIdCallGen: |
| 26451 | case IrInstructionIdReturn: | 26492 | case IrInstructionIdReturn: |
src/ir_print.cpp+14| ... | @@ -78,6 +78,8 @@ const char* ir_instruction_type_str(IrInstructionId id) { | ... | @@ -78,6 +78,8 @@ const char* ir_instruction_type_str(IrInstructionId id) { |
| 78 | return "LoadPtrGen"; | 78 | return "LoadPtrGen"; |
| 79 | case IrInstructionIdStorePtr: | 79 | case IrInstructionIdStorePtr: |
| 80 | return "StorePtr"; | 80 | return "StorePtr"; |
| 81 | case IrInstructionIdVectorStoreElem: | ||
| 82 | return "VectorStoreElem"; | ||
| 81 | case IrInstructionIdFieldPtr: | 83 | case IrInstructionIdFieldPtr: |
| 82 | return "FieldPtr"; | 84 | return "FieldPtr"; |
| 83 | case IrInstructionIdStructFieldPtr: | 85 | case IrInstructionIdStructFieldPtr: |
| ... | @@ -790,6 +792,15 @@ static void ir_print_store_ptr(IrPrint *irp, IrInstructionStorePtr *instruction) | ... | @@ -790,6 +792,15 @@ static void ir_print_store_ptr(IrPrint *irp, IrInstructionStorePtr *instruction) |
| 790 | ir_print_other_instruction(irp, instruction->value); | 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 | static void ir_print_typeof(IrPrint *irp, IrInstructionTypeOf *instruction) { | 804 | static void ir_print_typeof(IrPrint *irp, IrInstructionTypeOf *instruction) { |
| 794 | fprintf(irp->f, "@typeOf("); | 805 | fprintf(irp->f, "@typeOf("); |
| 795 | ir_print_other_instruction(irp, instruction->value); | 806 | ir_print_other_instruction(irp, instruction->value); |
| ... | @@ -2047,6 +2058,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction, bool | ... | @@ -2047,6 +2058,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction, bool |
| 2047 | case IrInstructionIdStorePtr: | 2058 | case IrInstructionIdStorePtr: |
| 2048 | ir_print_store_ptr(irp, (IrInstructionStorePtr *)instruction); | 2059 | ir_print_store_ptr(irp, (IrInstructionStorePtr *)instruction); |
| 2049 | break; | 2060 | break; |
| 2061 | case IrInstructionIdVectorStoreElem: | ||
| 2062 | ir_print_vector_store_elem(irp, (IrInstructionVectorStoreElem *)instruction); | ||
| 2063 | break; | ||
| 2050 | case IrInstructionIdTypeOf: | 2064 | case IrInstructionIdTypeOf: |
| 2051 | ir_print_typeof(irp, (IrInstructionTypeOf *)instruction); | 2065 | ir_print_typeof(irp, (IrInstructionTypeOf *)instruction); |
| 2052 | break; | 2066 | break; |
test/compile_errors.zig+17| ... | @@ -26,6 +26,23 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -26,6 +26,23 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 26 | 26 | ||
| 27 | cases.add( | 27 | cases.add( |
| 28 | "dereference vector pointer with unknown runtime index", | 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 | \\export fn entry() void { | 46 | \\export fn entry() void { |
| 30 | \\ var v: @Vector(4, i32) = [_]i32{ 1, 5, 3, undefined }; | 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,3 +216,21 @@ test "load vector elements via runtime index" { |
| 216 | S.doTheTest(); | 216 | S.doTheTest(); |
| 217 | comptime S.doTheTest(); | 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 | } |