From 55e54d98c47a0f1fb951f2011c6fc221af68d537 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 1 Nov 2019 18:13:37 -0400 Subject: runtime load vector element with comptime index --- src/codegen.cpp | 43 ++++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index a172ca39a7..d05919cb95 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -838,6 +838,11 @@ static LLVMValueRef get_handle_value(CodeGen *g, LLVMValueRef ptr, ZigType *type } } +static void ir_assert(bool ok, IrInstruction *source_instruction) { + if (ok) return; + src_assert(ok, source_instruction->source_node); +} + static bool ir_want_fast_math(CodeGen *g, IrInstruction *instruction) { // TODO memoize Scope *scope = instruction->scope; @@ -1695,11 +1700,11 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) { } if (instruction->spill != nullptr) { ZigType *ptr_type = instruction->spill->value.type; - src_assert(ptr_type->id == ZigTypeIdPointer, instruction->source_node); + ir_assert(ptr_type->id == ZigTypeIdPointer, instruction); return get_handle_value(g, ir_llvm_value(g, instruction->spill), ptr_type->data.pointer.child_type, instruction->spill->value.type); } - src_assert(instruction->value.special != ConstValSpecialRuntime, instruction->source_node); + ir_assert(instruction->value.special != ConstValSpecialRuntime, instruction); assert(instruction->value.type); render_const_val(g, &instruction->value, ""); // 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 return nullptr; } assert(g->cur_ret_ptr); - src_assert(instruction->operand->value.special != ConstValSpecialRuntime, - instruction->base.source_node); + ir_assert(instruction->operand->value.special != ConstValSpecialRuntime, &instruction->base); LLVMValueRef value = ir_llvm_value(g, instruction->operand); ZigType *return_type = instruction->operand->value.type; 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 return nullptr; } -static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrInstructionLoadPtrGen *instruction) { +static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, + IrInstructionLoadPtrGen *instruction) +{ ZigType *child_type = instruction->base.value.type; if (!type_has_bits(child_type)) return nullptr; @@ -3409,6 +3415,15 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI assert(ptr_type->id == ZigTypeIdPointer); uint32_t host_int_bytes = ptr_type->data.pointer.host_int_bytes; + + ir_assert(ptr_type->data.pointer.vector_index != VECTOR_INDEX_RUNTIME, &instruction->base); + if (ptr_type->data.pointer.vector_index != VECTOR_INDEX_NONE) { + LLVMValueRef index_val = LLVMConstInt(LLVMInt32Type(), + ptr_type->data.pointer.vector_index, false); + LLVMValueRef loaded_vector = LLVMBuildLoad(g->builder, ptr, ""); + return LLVMBuildExtractElement(g->builder, loaded_vector, index_val, ""); + } + if (host_int_bytes == 0) return get_handle_value(g, ptr, child_type, ptr_type); @@ -3636,7 +3651,7 @@ static LLVMValueRef ir_render_return_ptr(CodeGen *g, IrExecutable *executable, { if (!type_has_bits(instruction->base.value.type)) return nullptr; - src_assert(g->cur_ret_ptr != nullptr, instruction->base.source_node); + ir_assert(g->cur_ret_ptr != nullptr, &instruction->base); return g->cur_ret_ptr; } @@ -3729,6 +3744,8 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, (unsigned)ptr_index, ""); LLVMValueRef ptr = gen_load_untyped(g, ptr_ptr, 0, false, ""); return LLVMBuildInBoundsGEP(g->builder, ptr, &subscript_value, 1, ""); + } else if (array_type->id == ZigTypeIdVector) { + return array_ptr_ptr; } else { zig_unreachable(); } @@ -3917,9 +3934,9 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr if (instruction->modifier == CallModifierAsync) { frame_result_loc = result_loc; } else { - src_assert(instruction->frame_result_loc != nullptr, instruction->base.source_node); + ir_assert(instruction->frame_result_loc != nullptr, &instruction->base); frame_result_loc_uncasted = ir_llvm_value(g, instruction->frame_result_loc); - src_assert(instruction->fn_entry != nullptr, instruction->base.source_node); + ir_assert(instruction->fn_entry != nullptr, &instruction->base); frame_result_loc = LLVMBuildBitCast(g->builder, frame_result_loc_uncasted, LLVMPointerType(get_llvm_type(g, instruction->fn_entry->frame_type), 0), ""); } @@ -4271,10 +4288,10 @@ static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executa if ((err = type_resolve(g, struct_type, ResolveStatusLLVMFull))) codegen_report_errors_and_exit(g); - src_assert(field->gen_index != SIZE_MAX, instruction->base.source_node); + ir_assert(field->gen_index != SIZE_MAX, &instruction->base); LLVMValueRef field_ptr_val = LLVMBuildStructGEP(g->builder, struct_ptr, (unsigned)field->gen_index, ""); ZigType *res_type = instruction->base.value.type; - src_assert(res_type->id == ZigTypeIdPointer, instruction->base.source_node); + ir_assert(res_type->id == ZigTypeIdPointer, &instruction->base); if (res_type->data.pointer.host_int_bytes != 0) { // We generate packed structs with get_llvm_type_of_n_bytes, which is // 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 static LLVMValueRef ir_render_splat(CodeGen *g, IrExecutable *executable, IrInstructionSplatGen *instruction) { ZigType *result_type = instruction->base.value.type; - src_assert(result_type->id == ZigTypeIdVector, instruction->base.source_node); + ir_assert(result_type->id == ZigTypeIdVector, &instruction->base); uint32_t len = result_type->data.vector.len; LLVMTypeRef op_llvm_type = LLVMVectorType(get_llvm_type(g, instruction->scalar->value.type), 1); LLVMTypeRef mask_llvm_type = LLVMVectorType(LLVMInt32Type(), len); @@ -5039,8 +5056,8 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrIn } LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); - src_assert(result_loc != nullptr, instruction->base.source_node); - src_assert(type_has_bits(child_type), instruction->base.source_node); + ir_assert(result_loc != nullptr, &instruction->base); + ir_assert(type_has_bits(child_type), &instruction->base); LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, ""); LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, result_loc, maybe_child_index, ""); -- cgit v1.2.3 From 76d188551eb3f742c2feb086c8c51c6b0815184d Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 1 Nov 2019 18:50:33 -0400 Subject: implement store of vector element with comptime index --- src/codegen.cpp | 18 +++++++++++++++--- test/stage1/behavior/vector.zig | 23 +++++++++++++++++++++++ 2 files changed, 38 insertions(+), 3 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index d05919cb95..30d11c9f05 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1640,6 +1640,17 @@ static void gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_type, return; } + assert(ptr_type->data.pointer.vector_index != VECTOR_INDEX_RUNTIME); + if (ptr_type->data.pointer.vector_index != VECTOR_INDEX_NONE) { + LLVMValueRef index_val = LLVMConstInt(LLVMInt32Type(), + ptr_type->data.pointer.vector_index, false); + LLVMValueRef loaded_vector = gen_load(g, ptr, ptr_type, ""); + LLVMValueRef new_vector = LLVMBuildInsertElement(g->builder, loaded_vector, value, + index_val, ""); + gen_store(g, new_vector, ptr, ptr_type); + return; + } + uint32_t host_int_bytes = ptr_type->data.pointer.host_int_bytes; if (host_int_bytes == 0) { gen_store(g, value, ptr, ptr_type); @@ -3414,8 +3425,6 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, ZigType *ptr_type = instruction->ptr->value.type; assert(ptr_type->id == ZigTypeIdPointer); - uint32_t host_int_bytes = ptr_type->data.pointer.host_int_bytes; - ir_assert(ptr_type->data.pointer.vector_index != VECTOR_INDEX_RUNTIME, &instruction->base); if (ptr_type->data.pointer.vector_index != VECTOR_INDEX_NONE) { LLVMValueRef index_val = LLVMConstInt(LLVMInt32Type(), @@ -3424,6 +3433,7 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, return LLVMBuildExtractElement(g->builder, loaded_vector, index_val, ""); } + uint32_t host_int_bytes = ptr_type->data.pointer.host_int_bytes; if (host_int_bytes == 0) return get_handle_value(g, ptr, child_type, ptr_type); @@ -3660,7 +3670,6 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI ZigType *array_ptr_type = instruction->array_ptr->value.type; assert(array_ptr_type->id == ZigTypeIdPointer); ZigType *array_type = array_ptr_type->data.pointer.child_type; - LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type); LLVMValueRef subscript_value = ir_llvm_value(g, instruction->elem_index); assert(subscript_value); @@ -3672,6 +3681,7 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI if (array_type->id == ZigTypeIdArray || (array_type->id == ZigTypeIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle)) { + LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type); if (array_type->id == ZigTypeIdPointer) { assert(array_type->data.pointer.child_type->id == ZigTypeIdArray); array_type = array_type->data.pointer.child_type; @@ -3711,12 +3721,14 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI }; return LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, ""); } else if (array_type->id == ZigTypeIdPointer) { + LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type); assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind); LLVMValueRef indices[] = { subscript_value }; return LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 1, ""); } else if (array_type->id == ZigTypeIdStruct) { + LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type); assert(array_type->data.structure.is_slice); ZigType *ptr_type = instruction->base.value.type; diff --git a/test/stage1/behavior/vector.zig b/test/stage1/behavior/vector.zig index 21c5670be3..a75e6d9443 100644 --- a/test/stage1/behavior/vector.zig +++ b/test/stage1/behavior/vector.zig @@ -176,3 +176,26 @@ test "load vector elements via comptime index" { S.doTheTest(); comptime S.doTheTest(); } + +test "store vector elements via comptime index" { + const S = struct { + fn doTheTest() void { + var v: @Vector(4, i32) = [_]i32{ 1, 5, 3, undefined }; + + v[2] = 42; + expect(v[1] == 5); + v[3] = -364; + expect(v[2] == 42); + expect(-364 == v[3]); + + storev(&v[0], 100); + expect(v[0] == 100); + } + fn storev(ptr: var, x: i32) void { + ptr.* = x; + } + }; + + S.doTheTest(); + comptime S.doTheTest(); +} -- cgit v1.2.3 From 70be308c4315c53d42889d568d5731ba227dcf88 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 1 Nov 2019 22:57:19 -0400 Subject: implement loading vector elements via runtime index --- src/all_types.hpp | 8 ++++++++ src/codegen.cpp | 10 ++++++++++ src/ir.cpp | 30 +++++++++++++++++++++++++++++- src/ir_print.cpp | 13 +++++++++++++ test/compile_errors.zig | 16 ++++++++++++++++ test/stage1/behavior/vector.zig | 17 +++++++++++++++++ 6 files changed, 93 insertions(+), 1 deletion(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index ed6d05ac40..591838ce84 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2575,6 +2575,7 @@ enum IrInstructionId { IrInstructionIdResume, IrInstructionIdSpillBegin, IrInstructionIdSpillEnd, + IrInstructionIdVectorExtractElem, }; struct IrInstruction { @@ -3902,6 +3903,13 @@ struct IrInstructionSpillEnd { IrInstructionSpillBegin *begin; }; +struct IrInstructionVectorExtractElem { + IrInstruction base; + + IrInstruction *vector; + IrInstruction *index; +}; + enum ResultLocId { ResultLocIdInvalid, ResultLocIdNone, diff --git a/src/codegen.cpp b/src/codegen.cpp index 30d11c9f05..0c67a9954a 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -6002,6 +6002,14 @@ static LLVMValueRef ir_render_spill_end(CodeGen *g, IrExecutable *executable, Ir zig_unreachable(); } +static LLVMValueRef ir_render_vector_extract_elem(CodeGen *g, IrExecutable *executable, + IrInstructionVectorExtractElem *instruction) +{ + LLVMValueRef vector = ir_llvm_value(g, instruction->vector); + LLVMValueRef index = ir_llvm_value(g, instruction->index); + return LLVMBuildExtractElement(g->builder, vector, index, ""); +} + static void set_debug_location(CodeGen *g, IrInstruction *instruction) { AstNode *source_node = instruction->source_node; Scope *scope = instruction->scope; @@ -6262,6 +6270,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_shuffle_vector(g, executable, (IrInstructionShuffleVector *) instruction); case IrInstructionIdSplatGen: return ir_render_splat(g, executable, (IrInstructionSplatGen *) instruction); + case IrInstructionIdVectorExtractElem: + return ir_render_vector_extract_elem(g, executable, (IrInstructionVectorExtractElem *) instruction); } zig_unreachable(); } diff --git a/src/ir.cpp b/src/ir.cpp index f0f6c0ea7e..8592d033bc 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1083,6 +1083,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSpillEnd *) { return IrInstructionIdSpillEnd; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionVectorExtractElem *) { + return IrInstructionIdVectorExtractElem; +} + template static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { const char *name = nullptr; @@ -3419,6 +3423,21 @@ static IrInstruction *ir_build_spill_end(IrBuilder *irb, Scope *scope, AstNode * return &instruction->base; } +static IrInstruction *ir_build_vector_extract_elem(IrAnalyze *ira, IrInstruction *source_instruction, + IrInstruction *vector, IrInstruction *index) +{ + IrInstructionVectorExtractElem *instruction = ir_build_instruction( + &ira->new_irb, source_instruction->scope, source_instruction->source_node); + instruction->base.value.type = vector->value.type->data.vector.elem_type; + instruction->vector = vector; + instruction->index = index; + + ir_ref_instruction(vector, ira->new_irb.current_basic_block); + ir_ref_instruction(index, ira->new_irb.current_basic_block); + + return &instruction->base; +} + static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { results[ReturnKindUnconditional] = 0; results[ReturnKindError] = 0; @@ -12965,8 +12984,15 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc // the type information does not contain enough information to actually // perform a dereference. if (ptr_type->data.pointer.vector_index == VECTOR_INDEX_RUNTIME) { + if (ptr->id == IrInstructionIdElemPtr) { + IrInstructionElemPtr *elem_ptr = (IrInstructionElemPtr *)ptr; + IrInstruction *vector_loaded = ir_get_deref(ira, elem_ptr->array_ptr, + elem_ptr->array_ptr, nullptr); + IrInstruction *elem_index = elem_ptr->elem_index; + return ir_build_vector_extract_elem(ira, source_instruction, vector_loaded, elem_index); + } ir_add_error(ira, ptr, - buf_sprintf("unable to determine element index in order to dereference vector pointer")); + buf_sprintf("unable to determine vector element index of type '%s'", buf_ptr(&ptr_type->name))); return ira->codegen->invalid_instruction; } @@ -26036,6 +26062,7 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction case IrInstructionIdFrameSizeGen: case IrInstructionIdAwaitGen: case IrInstructionIdSplatGen: + case IrInstructionIdVectorExtractElem: zig_unreachable(); case IrInstructionIdReturn: @@ -26571,6 +26598,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdAllocaSrc: case IrInstructionIdAllocaGen: case IrInstructionIdSpillEnd: + case IrInstructionIdVectorExtractElem: return false; case IrInstructionIdAsm: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index d3c77f3638..edff281e31 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -370,6 +370,8 @@ const char* ir_instruction_type_str(IrInstructionId id) { return "SpillBegin"; case IrInstructionIdSpillEnd: return "SpillEnd"; + case IrInstructionIdVectorExtractElem: + return "VectorExtractElem"; } zig_unreachable(); } @@ -1969,6 +1971,14 @@ static void ir_print_spill_end(IrPrint *irp, IrInstructionSpillEnd *instruction) fprintf(irp->f, ")"); } +static void ir_print_vector_extract_elem(IrPrint *irp, IrInstructionVectorExtractElem *instruction) { + fprintf(irp->f, "@vectorExtractElem("); + ir_print_other_instruction(irp, instruction->vector); + fprintf(irp->f, ","); + ir_print_other_instruction(irp, instruction->index); + fprintf(irp->f, ")"); +} + static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction, bool trailing) { ir_print_prefix(irp, instruction, trailing); switch (instruction->id) { @@ -2466,6 +2476,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction, bool case IrInstructionIdSpillEnd: ir_print_spill_end(irp, (IrInstructionSpillEnd *)instruction); break; + case IrInstructionIdVectorExtractElem: + ir_print_vector_extract_elem(irp, (IrInstructionVectorExtractElem *)instruction); + break; } fprintf(irp->f, "\n"); } diff --git a/test/compile_errors.zig b/test/compile_errors.zig index a9d93dd882..d0199ecfc5 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -24,6 +24,22 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:4:20: note: referenced here", ); + cases.add( + "dereference vector pointer with unknown runtime index", + \\export fn entry() void { + \\ var v: @Vector(4, i32) = [_]i32{ 1, 5, 3, undefined }; + \\ + \\ var i: u32 = 0; + \\ var x = loadv(&v[i]); + \\} + \\ + \\fn loadv(ptr: var) i32 { + \\ return ptr.*; + \\} + , + "tmp.zig:9:12: error: unable to determine vector element index of type '*align(16:0:4:?) i32", + ); + cases.add( "using an unknown len ptr type instead of array", \\const resolutions = [*][*]const u8{ diff --git a/test/stage1/behavior/vector.zig b/test/stage1/behavior/vector.zig index a75e6d9443..9959d346ce 100644 --- a/test/stage1/behavior/vector.zig +++ b/test/stage1/behavior/vector.zig @@ -199,3 +199,20 @@ test "store vector elements via comptime index" { S.doTheTest(); comptime S.doTheTest(); } + +test "load vector elements via runtime index" { + const S = struct { + fn doTheTest() void { + var v: @Vector(4, i32) = [_]i32{ 1, 2, 3, undefined }; + var i: u32 = 0; + expect(v[i] == 1); + i += 1; + expect(v[i] == 2); + i += 1; + expect(v[i] == 3); + } + }; + + S.doTheTest(); + comptime S.doTheTest(); +} -- cgit v1.2.3 From cbaa10fc3bcd2d5f8d48b9038e840ae508fe2822 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 1 Nov 2019 23:16:49 -0400 Subject: implement storing vector elements via runtime index --- src/all_types.hpp | 9 +++++++++ src/codegen.cpp | 15 +++++++++++++++ src/ir.cpp | 41 +++++++++++++++++++++++++++++++++++++++++ src/ir_print.cpp | 14 ++++++++++++++ test/compile_errors.zig | 17 +++++++++++++++++ test/stage1/behavior/vector.zig | 18 ++++++++++++++++++ 6 files changed, 114 insertions(+) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 591838ce84..42f14539f3 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2426,6 +2426,7 @@ enum IrInstructionId { IrInstructionIdLoadPtr, IrInstructionIdLoadPtrGen, IrInstructionIdStorePtr, + IrInstructionIdVectorStoreElem, IrInstructionIdFieldPtr, IrInstructionIdStructFieldPtr, IrInstructionIdUnionFieldPtr, @@ -2770,6 +2771,14 @@ struct IrInstructionStorePtr { IrInstruction *value; }; +struct IrInstructionVectorStoreElem { + IrInstruction base; + + IrInstruction *vector_ptr; + IrInstruction *index; + IrInstruction *value; +}; + struct IrInstructionFieldPtr { IrInstruction base; diff --git a/src/codegen.cpp b/src/codegen.cpp index 0c67a9954a..154c21893a 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3644,6 +3644,19 @@ static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, Ir return nullptr; } +static LLVMValueRef ir_render_vector_store_elem(CodeGen *g, IrExecutable *executable, + IrInstructionVectorStoreElem *instruction) +{ + LLVMValueRef vector_ptr = ir_llvm_value(g, instruction->vector_ptr); + LLVMValueRef index = ir_llvm_value(g, instruction->index); + LLVMValueRef value = ir_llvm_value(g, instruction->value); + + LLVMValueRef loaded_vector = gen_load(g, vector_ptr, instruction->vector_ptr->value.type, ""); + LLVMValueRef modified_vector = LLVMBuildInsertElement(g->builder, loaded_vector, value, index, ""); + gen_store(g, modified_vector, vector_ptr, instruction->vector_ptr->value.type); + return nullptr; +} + static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrInstructionVarPtr *instruction) { if (instruction->base.value.special != ConstValSpecialRuntime) return ir_llvm_value(g, &instruction->base); @@ -6130,6 +6143,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_load_ptr(g, executable, (IrInstructionLoadPtrGen *)instruction); case IrInstructionIdStorePtr: return ir_render_store_ptr(g, executable, (IrInstructionStorePtr *)instruction); + case IrInstructionIdVectorStoreElem: + return ir_render_vector_store_elem(g, executable, (IrInstructionVectorStoreElem *)instruction); case IrInstructionIdVarPtr: return ir_render_var_ptr(g, executable, (IrInstructionVarPtr *)instruction); case IrInstructionIdReturnPtr: diff --git a/src/ir.cpp b/src/ir.cpp index 8592d033bc..0c75fe7c19 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -491,6 +491,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionStorePtr *) { return IrInstructionIdStorePtr; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionVectorStoreElem *) { + return IrInstructionIdVectorStoreElem; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionFieldPtr *) { return IrInstructionIdFieldPtr; } @@ -1631,6 +1635,23 @@ static IrInstructionStorePtr *ir_build_store_ptr(IrBuilder *irb, Scope *scope, A return instruction; } +static IrInstruction *ir_build_vector_store_elem(IrAnalyze *ira, IrInstruction *source_instruction, + IrInstruction *vector_ptr, IrInstruction *index, IrInstruction *value) +{ + IrInstructionVectorStoreElem *inst = ir_build_instruction( + &ira->new_irb, source_instruction->scope, source_instruction->source_node); + inst->base.value.type = ira->codegen->builtin_types.entry_void; + inst->vector_ptr = vector_ptr; + inst->index = index; + inst->value = value; + + ir_ref_instruction(vector_ptr, ira->new_irb.current_basic_block); + ir_ref_instruction(index, ira->new_irb.current_basic_block); + ir_ref_instruction(value, ira->new_irb.current_basic_block); + + return &inst->base; +} + static IrInstruction *ir_build_var_decl_src(IrBuilder *irb, Scope *scope, AstNode *source_node, ZigVar *var, IrInstruction *align_value, IrInstruction *ptr) { @@ -16126,6 +16147,24 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source mark_comptime_value_escape(ira, source_instr, &value->value); } + // If this is a store to a pointer with a runtime-known vector index, + // we have to figure out the IrInstruction which represents the index and + // emit a IrInstructionVectorStoreElem, or emit a compile error + // explaining why it is impossible for this store to work. Which is that + // the pointer address is of the vector; without the element index being known + // we cannot properly perform the insertion. + if (ptr->value.type->data.pointer.vector_index == VECTOR_INDEX_RUNTIME) { + if (ptr->id == IrInstructionIdElemPtr) { + IrInstructionElemPtr *elem_ptr = (IrInstructionElemPtr *)ptr; + return ir_build_vector_store_elem(ira, source_instr, elem_ptr->array_ptr, + elem_ptr->elem_index, value); + } + ir_add_error(ira, ptr, + buf_sprintf("unable to determine vector element index of type '%s'", + buf_ptr(&ptr->value.type->name))); + return ira->codegen->invalid_instruction; + } + IrInstructionStorePtr *store_ptr = ir_build_store_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node, ptr, value); return &store_ptr->base; @@ -26063,6 +26102,7 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction case IrInstructionIdAwaitGen: case IrInstructionIdSplatGen: case IrInstructionIdVectorExtractElem: + case IrInstructionIdVectorStoreElem: zig_unreachable(); case IrInstructionIdReturn: @@ -26446,6 +26486,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdDeclVarSrc: case IrInstructionIdDeclVarGen: case IrInstructionIdStorePtr: + case IrInstructionIdVectorStoreElem: case IrInstructionIdCallSrc: case IrInstructionIdCallGen: case IrInstructionIdReturn: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index edff281e31..aa53b11e03 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -78,6 +78,8 @@ const char* ir_instruction_type_str(IrInstructionId id) { return "LoadPtrGen"; case IrInstructionIdStorePtr: return "StorePtr"; + case IrInstructionIdVectorStoreElem: + return "VectorStoreElem"; case IrInstructionIdFieldPtr: return "FieldPtr"; case IrInstructionIdStructFieldPtr: @@ -790,6 +792,15 @@ static void ir_print_store_ptr(IrPrint *irp, IrInstructionStorePtr *instruction) ir_print_other_instruction(irp, instruction->value); } +static void ir_print_vector_store_elem(IrPrint *irp, IrInstructionVectorStoreElem *instruction) { + fprintf(irp->f, "vector_ptr="); + ir_print_var_instruction(irp, instruction->vector_ptr); + fprintf(irp->f, ",index="); + ir_print_var_instruction(irp, instruction->index); + fprintf(irp->f, ",value="); + ir_print_other_instruction(irp, instruction->value); +} + static void ir_print_typeof(IrPrint *irp, IrInstructionTypeOf *instruction) { fprintf(irp->f, "@typeOf("); ir_print_other_instruction(irp, instruction->value); @@ -2047,6 +2058,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction, bool case IrInstructionIdStorePtr: ir_print_store_ptr(irp, (IrInstructionStorePtr *)instruction); break; + case IrInstructionIdVectorStoreElem: + ir_print_vector_store_elem(irp, (IrInstructionVectorStoreElem *)instruction); + break; case IrInstructionIdTypeOf: ir_print_typeof(irp, (IrInstructionTypeOf *)instruction); break; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index d0199ecfc5..73208287c8 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -26,6 +26,23 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { cases.add( "dereference vector pointer with unknown runtime index", + "store vector pointer with unknown runtime index", + \\export fn entry() void { + \\ var v: @Vector(4, i32) = [_]i32{ 1, 5, 3, undefined }; + \\ + \\ var i: u32 = 0; + \\ storev(&v[i], 42); + \\} + \\ + \\fn storev(ptr: var, val: i32) void { + \\ ptr.* = val; + \\} + , + "tmp.zig:9:8: error: unable to determine vector element index of type '*align(16:0:4:?) i32", + ); + + cases.add( + "load vector pointer with unknown runtime index", \\export fn entry() void { \\ var v: @Vector(4, i32) = [_]i32{ 1, 5, 3, undefined }; \\ diff --git a/test/stage1/behavior/vector.zig b/test/stage1/behavior/vector.zig index 9959d346ce..d7dc7b5763 100644 --- a/test/stage1/behavior/vector.zig +++ b/test/stage1/behavior/vector.zig @@ -216,3 +216,21 @@ test "load vector elements via runtime index" { S.doTheTest(); comptime S.doTheTest(); } + +test "store vector elements via runtime index" { + const S = struct { + fn doTheTest() void { + var v: @Vector(4, i32) = [_]i32{ 1, 5, 3, undefined }; + var i: u32 = 2; + v[i] = 1; + expect(v[1] == 5); + expect(v[2] == 1); + i += 1; + v[i] = -364; + expect(-364 == v[3]); + } + }; + + S.doTheTest(); + comptime S.doTheTest(); +} -- cgit v1.2.3