From 70be308c4315c53d42889d568d5731ba227dcf88 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 1 Nov 2019 22:57:19 -0400 Subject: [PATCH] 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(-) 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(); +}