Commit 70be308c43

Andrew Kelley <andrew@ziglang.org>
2019-11-02 03:57:19
implement loading vector elements via runtime index
1 parent 76d1885
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,
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();
 }
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<typename T>
 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<IrInstructionVectorExtractElem>(
+            &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:
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");
 }
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();
+}
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{