diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2019-11-05 13:39:56 -0500 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2019-11-05 13:40:57 -0500 |
| commit | cb8af1c6d48d5fdb26484a070b8af069c4152049 (patch) | |
| tree | 0c3baee6423b40eda3ba57e9d41041f6c9fbd3b8 /src/ir.cpp | |
| parent | a26e9fa7238e972301f761db80434fa0205d1016 (diff) | |
| parent | 9a08de93b64a332af9f581ef15b208e153fa19f0 (diff) | |
| download | zig-cb8af1c6d48d5fdb26484a070b8af069c4152049.tar.gz zig-cb8af1c6d48d5fdb26484a070b8af069c4152049.zip | |
Merge branch 'vector-element-access'
This introduces the concept of vector index being part of a pointer
type. This avoids vectors having well-defined in-memory layout, and
allows vectors of any integer bit width to work the same way.
When a vector is indexed with a scalar, this is vector element access,
which this branch implements. When a vector is indexed with a vector,
this is gather/scatter, which is not implemented in this branch.
closes #3575
closes #3580
Diffstat (limited to 'src/ir.cpp')
| -rw-r--r-- | src/ir.cpp | 121 |
1 files changed, 111 insertions, 10 deletions
diff --git a/src/ir.cpp b/src/ir.cpp index d5633b0538..d4687e5adb 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; } @@ -1083,6 +1087,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; @@ -1627,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<IrInstructionVectorStoreElem>( + &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) { @@ -3419,6 +3444,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; @@ -12908,18 +12948,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 +12989,36 @@ 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) { + 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 vector element index of type '%s'", buf_ptr(&ptr_type->name))); + 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); @@ -16085,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; @@ -17488,6 +17568,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 +17595,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))) @@ -17551,7 +17640,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct return ira->codegen->invalid_instruction; if (array_ptr_val->special == ConstValSpecialUndef && elem_ptr_instruction->init_array_type != nullptr) { - if (array_type->id == ZigTypeIdArray) { + if (array_type->id == ZigTypeIdArray || array_type->id == ZigTypeIdVector) { array_ptr_val->data.x_array.special = ConstArraySpecialNone; array_ptr_val->data.x_array.data.s_none.elements = create_const_vals(array_type->data.array.len); array_ptr_val->special = ConstValSpecialStatic; @@ -17720,7 +17809,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct zig_panic("TODO elem ptr on a slice has a null pointer"); } return result; - } else if (array_type->id == ZigTypeIdArray) { + } else if (array_type->id == ZigTypeIdArray || array_type->id == ZigTypeIdVector) { IrInstruction *result; if (orig_array_ptr_val->data.x_ptr.mut == ConstPtrMutInfer) { result = ir_build_elem_ptr(&ira->new_irb, elem_ptr_instruction->base.scope, @@ -17742,6 +17831,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)) { @@ -26004,6 +26101,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction case IrInstructionIdFrameSizeGen: case IrInstructionIdAwaitGen: case IrInstructionIdSplatGen: + case IrInstructionIdVectorExtractElem: + case IrInstructionIdVectorStoreElem: zig_unreachable(); case IrInstructionIdReturn: @@ -26387,6 +26486,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdDeclVarSrc: case IrInstructionIdDeclVarGen: case IrInstructionIdStorePtr: + case IrInstructionIdVectorStoreElem: case IrInstructionIdCallSrc: case IrInstructionIdCallGen: case IrInstructionIdReturn: @@ -26539,6 +26639,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdAllocaSrc: case IrInstructionIdAllocaGen: case IrInstructionIdSpillEnd: + case IrInstructionIdVectorExtractElem: return false; case IrInstructionIdAsm: |
