Commit 55e54d98c4

Andrew Kelley <andrew@ziglang.org>
2019-11-01 23:13:37
runtime load vector element with comptime index
1 parent a26e9fa
Changed files (6)
src/all_types.hpp
@@ -1183,13 +1183,22 @@ struct FnTypeId {
 uint32_t fn_type_id_hash(FnTypeId*);
 bool fn_type_id_eql(FnTypeId *a, FnTypeId *b);
 
+static const uint32_t VECTOR_INDEX_NONE = UINT32_MAX;
+static const uint32_t VECTOR_INDEX_RUNTIME = UINT32_MAX - 1;
+
 struct ZigTypePointer {
     ZigType *child_type;
     ZigType *slice_parent;
+
     PtrLen ptr_len;
     uint32_t explicit_alignment; // 0 means use ABI alignment
+
     uint32_t bit_offset_in_host;
-    uint32_t host_int_bytes; // size of host integer. 0 means no host integer; this field is aligned
+    // size of host integer. 0 means no host integer; this field is aligned
+    // when vector_index != VECTOR_INDEX_NONE this is the len of the containing vector
+    uint32_t host_int_bytes;
+
+    uint32_t vector_index; // see the VECTOR_INDEX_* constants
     bool is_const;
     bool is_volatile;
     bool allow_zero;
@@ -1732,8 +1741,11 @@ struct TypeId {
             ZigType *child_type;
             PtrLen ptr_len;
             uint32_t alignment;
+
             uint32_t bit_offset_in_host;
             uint32_t host_int_bytes;
+
+            uint32_t vector_index;
             bool is_const;
             bool is_volatile;
             bool allow_zero;
src/analyze.cpp
@@ -480,9 +480,10 @@ ZigType *get_fn_frame_type(CodeGen *g, ZigFn *fn) {
     return entry;
 }
 
-ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const,
+ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type, bool is_const,
         bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment,
-        uint32_t bit_offset_in_host, uint32_t host_int_bytes, bool allow_zero)
+        uint32_t bit_offset_in_host, uint32_t host_int_bytes, bool allow_zero,
+        uint32_t vector_index)
 {
     assert(ptr_len != PtrLenC || allow_zero);
     assert(!type_is_invalid(child_type));
@@ -494,7 +495,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
             byte_alignment = 0;
     }
 
-    if (host_int_bytes != 0) {
+    if (host_int_bytes != 0 && vector_index == VECTOR_INDEX_NONE) {
         uint32_t child_type_bits = type_size_bits(g, child_type);
         if (host_int_bytes * 8 == child_type_bits) {
             assert(bit_offset_in_host == 0);
@@ -504,7 +505,9 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
 
     TypeId type_id = {};
     ZigType **parent_pointer = nullptr;
-    if (host_int_bytes != 0 || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle || allow_zero) {
+    if (host_int_bytes != 0 || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle ||
+        allow_zero || vector_index != VECTOR_INDEX_NONE)
+    {
         type_id.id = ZigTypeIdPointer;
         type_id.data.pointer.child_type = child_type;
         type_id.data.pointer.is_const = is_const;
@@ -514,6 +517,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
         type_id.data.pointer.host_int_bytes = host_int_bytes;
         type_id.data.pointer.ptr_len = ptr_len;
         type_id.data.pointer.allow_zero = allow_zero;
+        type_id.data.pointer.vector_index = vector_index;
 
         auto existing_entry = g->type_table.maybe_get(type_id);
         if (existing_entry)
@@ -540,19 +544,36 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
         allow_zero_str = allow_zero ? "allowzero " : "";
     }
     buf_resize(&entry->name, 0);
-    if (host_int_bytes == 0 && byte_alignment == 0) {
+    if (host_int_bytes == 0 && byte_alignment == 0 && vector_index == VECTOR_INDEX_NONE) {
         buf_appendf(&entry->name, "%s%s%s%s%s",
                 star_str, const_str, volatile_str, allow_zero_str, buf_ptr(&child_type->name));
-    } else if (host_int_bytes == 0) {
+    } else if (host_int_bytes == 0 && vector_index == VECTOR_INDEX_NONE) {
         buf_appendf(&entry->name, "%salign(%" PRIu32 ") %s%s%s%s", star_str, byte_alignment,
                 const_str, volatile_str, allow_zero_str, buf_ptr(&child_type->name));
     } else if (byte_alignment == 0) {
-        buf_appendf(&entry->name, "%salign(:%" PRIu32 ":%" PRIu32 ") %s%s%s%s", star_str,
-                bit_offset_in_host, host_int_bytes, const_str, volatile_str, allow_zero_str,
+        assert(vector_index == VECTOR_INDEX_NONE);
+        buf_appendf(&entry->name, "%salign(:%" PRIu32 ":%" PRIu32 ":%" PRIu32 ") %s%s%s%s",
+                star_str,
+                bit_offset_in_host, host_int_bytes, vector_index,
+                const_str, volatile_str, allow_zero_str,
+                buf_ptr(&child_type->name));
+    } else if (vector_index == VECTOR_INDEX_NONE) {
+        buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ") %s%s%s%s",
+                star_str, byte_alignment,
+                bit_offset_in_host, host_int_bytes,
+                const_str, volatile_str, allow_zero_str,
+                buf_ptr(&child_type->name));
+    } else if (vector_index == VECTOR_INDEX_RUNTIME) {
+        buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ":?) %s%s%s%s",
+                star_str, byte_alignment,
+                bit_offset_in_host, host_int_bytes,
+                const_str, volatile_str, allow_zero_str,
                 buf_ptr(&child_type->name));
     } else {
-        buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ") %s%s%s%s", star_str, byte_alignment,
-                bit_offset_in_host, host_int_bytes, const_str, volatile_str, allow_zero_str,
+        buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ":%" PRIu32 ") %s%s%s%s",
+                star_str, byte_alignment,
+                bit_offset_in_host, host_int_bytes, vector_index,
+                const_str, volatile_str, allow_zero_str,
                 buf_ptr(&child_type->name));
     }
 
@@ -581,6 +602,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
     entry->data.pointer.bit_offset_in_host = bit_offset_in_host;
     entry->data.pointer.host_int_bytes = host_int_bytes;
     entry->data.pointer.allow_zero = allow_zero;
+    entry->data.pointer.vector_index = vector_index;
 
     if (parent_pointer) {
         *parent_pointer = entry;
@@ -590,8 +612,17 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
     return entry;
 }
 
+ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const,
+        bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment,
+        uint32_t bit_offset_in_host, uint32_t host_int_bytes, bool allow_zero)
+{
+    return get_pointer_to_type_extra2(g, child_type, is_const, is_volatile, ptr_len,
+            byte_alignment, bit_offset_in_host, host_int_bytes, allow_zero, VECTOR_INDEX_NONE);
+}
+
 ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const) {
-    return get_pointer_to_type_extra(g, child_type, is_const, false, PtrLenSingle, 0, 0, 0, false);
+    return get_pointer_to_type_extra2(g, child_type, is_const, false, PtrLenSingle, 0, 0, 0, false,
+            VECTOR_INDEX_NONE);
 }
 
 ZigType *get_optional_type(CodeGen *g, ZigType *child_type) {
@@ -6910,6 +6941,7 @@ uint32_t type_id_hash(TypeId x) {
                 (x.data.pointer.allow_zero ? (uint32_t)3324284834 : (uint32_t)3584904923) +
                 (((uint32_t)x.data.pointer.alignment) ^ (uint32_t)0x777fbe0e) +
                 (((uint32_t)x.data.pointer.bit_offset_in_host) ^ (uint32_t)2639019452) +
+                (((uint32_t)x.data.pointer.vector_index) ^ (uint32_t)0x19199716) +
                 (((uint32_t)x.data.pointer.host_int_bytes) ^ (uint32_t)529908881);
         case ZigTypeIdArray:
             return hash_ptr(x.data.array.child_type) +
@@ -6962,6 +6994,7 @@ bool type_id_eql(TypeId a, TypeId b) {
                 a.data.pointer.allow_zero == b.data.pointer.allow_zero &&
                 a.data.pointer.alignment == b.data.pointer.alignment &&
                 a.data.pointer.bit_offset_in_host == b.data.pointer.bit_offset_in_host &&
+                a.data.pointer.vector_index == b.data.pointer.vector_index &&
                 a.data.pointer.host_int_bytes == b.data.pointer.host_int_bytes;
         case ZigTypeIdArray:
             return a.data.array.child_type == b.data.array.child_type &&
@@ -8266,11 +8299,21 @@ static void resolve_llvm_types_pointer(CodeGen *g, ZigType *type, ResolveStatus
 
     if (type->data.pointer.is_const || type->data.pointer.is_volatile ||
         type->data.pointer.explicit_alignment != 0 || type->data.pointer.ptr_len != PtrLenSingle ||
-        type->data.pointer.bit_offset_in_host != 0 || type->data.pointer.allow_zero)
+        type->data.pointer.bit_offset_in_host != 0 || type->data.pointer.allow_zero ||
+        type->data.pointer.vector_index != VECTOR_INDEX_NONE)
     {
         assertNoError(type_resolve(g, elem_type, ResolveStatusLLVMFwdDecl));
-        ZigType *peer_type = get_pointer_to_type_extra(g, elem_type, false, false,
-                PtrLenSingle, 0, 0, type->data.pointer.host_int_bytes, false);
+        ZigType *peer_type;
+        if (type->data.pointer.vector_index == VECTOR_INDEX_NONE) {
+            peer_type = get_pointer_to_type_extra2(g, elem_type, false, false,
+                PtrLenSingle, 0, 0, type->data.pointer.host_int_bytes, false,
+                VECTOR_INDEX_NONE);
+        } else {
+            uint32_t host_vec_len = type->data.pointer.host_int_bytes;
+            ZigType *host_vec_type = get_vector_type(g, host_vec_len, elem_type);
+            peer_type = get_pointer_to_type_extra2(g, host_vec_type, false, false,
+                PtrLenSingle, 0, 0, 0, false, VECTOR_INDEX_NONE);
+        }
         type->llvm_type = get_llvm_type(g, peer_type);
         type->llvm_di_type = get_llvm_di_type(g, peer_type);
         assertNoError(type_resolve(g, elem_type, wanted_resolve_status));
src/analyze.hpp
@@ -17,10 +17,14 @@ ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, const AstNode *node,
 ZigType *new_type_table_entry(ZigTypeId id);
 ZigType *get_fn_frame_type(CodeGen *g, ZigFn *fn);
 ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const);
-ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const,
-        bool is_volatile, PtrLen ptr_len,
+ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type,
+        bool is_const, bool is_volatile, PtrLen ptr_len,
         uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count,
         bool allow_zero);
+ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type,
+        bool is_const, bool is_volatile, PtrLen ptr_len,
+        uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count,
+        bool allow_zero, uint32_t vector_index);
 uint64_t type_size(CodeGen *g, ZigType *type_entry);
 uint64_t type_size_bits(CodeGen *g, ZigType *type_entry);
 ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits);
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, "");
src/ir.cpp
@@ -12908,18 +12908,18 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
         ResultLoc *result_loc)
 {
     Error err;
-    ZigType *type_entry = ptr->value.type;
-    if (type_is_invalid(type_entry))
+    ZigType *ptr_type = ptr->value.type;
+    if (type_is_invalid(ptr_type))
         return ira->codegen->invalid_instruction;
 
-    if (type_entry->id != ZigTypeIdPointer) {
+    if (ptr_type->id != ZigTypeIdPointer) {
         ir_add_error_node(ira, source_instruction->source_node,
             buf_sprintf("attempt to dereference non-pointer type '%s'",
-                buf_ptr(&type_entry->name)));
+                buf_ptr(&ptr_type->name)));
         return ira->codegen->invalid_instruction;
     }
 
-    ZigType *child_type = type_entry->data.pointer.child_type;
+    ZigType *child_type = ptr_type->data.pointer.child_type;
     // if the child type has one possible value, the deref is comptime
     switch (type_has_one_possible_value(ira->codegen, child_type)) {
         case OnePossibleValueInvalid:
@@ -12949,14 +12949,29 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
             }
         }
     }
+
     // if the instruction is a const ref instruction we can skip it
     if (ptr->id == IrInstructionIdRef) {
         IrInstructionRef *ref_inst = reinterpret_cast<IrInstructionRef *>(ptr);
         return ref_inst->value;
     }
 
+    // If the instruction is a element pointer instruction to a vector, we emit
+    // vector element extract instruction rather than load pointer. If the
+    // pointer type has non-VECTOR_INDEX_RUNTIME value, it would have been
+    // possible to implement this in the codegen for IrInstructionLoadPtrGen.
+    // However if it has VECTOR_INDEX_RUNTIME then we must emit a compile error
+    // if the vector index cannot be determined right here, right now, because
+    // the type information does not contain enough information to actually
+    // perform a dereference.
+    if (ptr_type->data.pointer.vector_index == VECTOR_INDEX_RUNTIME) {
+        ir_add_error(ira, ptr,
+            buf_sprintf("unable to determine element index in order to dereference vector pointer"));
+        return ira->codegen->invalid_instruction;
+    }
+
     IrInstruction *result_loc_inst;
-    if (type_entry->data.pointer.host_int_bytes != 0 && handle_is_ptr(child_type)) {
+    if (ptr_type->data.pointer.host_int_bytes != 0 && handle_is_ptr(child_type)) {
         if (result_loc == nullptr) result_loc = no_result_loc();
         result_loc_inst = ir_resolve_result(ira, source_instruction, result_loc, child_type, nullptr,
                 true, false, true);
@@ -17488,6 +17503,9 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
             return ir_get_const_ptr(ira, &elem_ptr_instruction->base, &ira->codegen->const_void_val,
                     ira->codegen->builtin_types.entry_void, ConstPtrMutComptimeConst, is_const, is_volatile, 0);
         }
+    } else if (array_type->id == ZigTypeIdVector) {
+        // This depends on whether the element index is comptime, so it is computed later.
+        return_type = nullptr;
     } else {
         ir_add_error_node(ira, elem_ptr_instruction->base.source_node,
                 buf_sprintf("array access of non-array type '%s'", buf_ptr(&array_type->name)));
@@ -17512,8 +17530,14 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
             }
             safety_check_on = false;
         }
-
-        if (return_type->data.pointer.explicit_alignment != 0) {
+        if (array_type->id == ZigTypeIdVector) {
+            ZigType *elem_type = array_type->data.vector.elem_type;
+            uint32_t host_vec_len = array_type->data.vector.len;
+            return_type = get_pointer_to_type_extra2(ira->codegen, elem_type,
+                ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
+                elem_ptr_instruction->ptr_len,
+                get_ptr_align(ira->codegen, ptr_type), 0, host_vec_len, false, (uint32_t)index);
+        } else if (return_type->data.pointer.explicit_alignment != 0) {
             // figure out the largest alignment possible
 
             if ((err = type_resolve(ira->codegen, return_type->data.pointer.child_type, ResolveStatusSizeKnown)))
@@ -17742,6 +17766,14 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
                 }
             }
         }
+    } else if (array_type->id == ZigTypeIdVector) {
+        // runtime known element index
+        ZigType *elem_type = array_type->data.vector.elem_type;
+        uint32_t host_vec_len = array_type->data.vector.len;
+        return_type = get_pointer_to_type_extra2(ira->codegen, elem_type,
+            ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
+            elem_ptr_instruction->ptr_len,
+            get_ptr_align(ira->codegen, ptr_type), 0, host_vec_len, false, VECTOR_INDEX_RUNTIME);
     } else {
         // runtime known element index
         switch (type_requires_comptime(ira->codegen, return_type)) {
test/stage1/behavior/vector.zig
@@ -159,3 +159,20 @@ test "vector @splat" {
     S.doTheTest();
     comptime S.doTheTest();
 }
+
+test "load vector elements via comptime index" {
+    const S = struct {
+        fn doTheTest() void {
+            var v: @Vector(4, i32) = [_]i32{ 1, 2, 3, undefined };
+            expect(v[0] == 1);
+            expect(v[1] == 2);
+            expect(loadv(&v[2]) == 3);
+        }
+        fn loadv(ptr: var) i32 {
+            return ptr.*;
+        }
+    };
+
+    S.doTheTest();
+    //comptime S.doTheTest();
+}