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 #3580master
commit
cb8af1c6d4
|
@ -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;
|
||||
|
@ -2414,6 +2426,7 @@ enum IrInstructionId {
|
|||
IrInstructionIdLoadPtr,
|
||||
IrInstructionIdLoadPtrGen,
|
||||
IrInstructionIdStorePtr,
|
||||
IrInstructionIdVectorStoreElem,
|
||||
IrInstructionIdFieldPtr,
|
||||
IrInstructionIdStructFieldPtr,
|
||||
IrInstructionIdUnionFieldPtr,
|
||||
|
@ -2563,6 +2576,7 @@ enum IrInstructionId {
|
|||
IrInstructionIdResume,
|
||||
IrInstructionIdSpillBegin,
|
||||
IrInstructionIdSpillEnd,
|
||||
IrInstructionIdVectorExtractElem,
|
||||
};
|
||||
|
||||
struct IrInstruction {
|
||||
|
@ -2757,6 +2771,14 @@ struct IrInstructionStorePtr {
|
|||
IrInstruction *value;
|
||||
};
|
||||
|
||||
struct IrInstructionVectorStoreElem {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *vector_ptr;
|
||||
IrInstruction *index;
|
||||
IrInstruction *value;
|
||||
};
|
||||
|
||||
struct IrInstructionFieldPtr {
|
||||
IrInstruction base;
|
||||
|
||||
|
@ -3890,6 +3912,13 @@ struct IrInstructionSpillEnd {
|
|||
IrInstructionSpillBegin *begin;
|
||||
};
|
||||
|
||||
struct IrInstructionVectorExtractElem {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *vector;
|
||||
IrInstruction *index;
|
||||
};
|
||||
|
||||
enum ResultLocId {
|
||||
ResultLocIdInvalid,
|
||||
ResultLocIdNone,
|
||||
|
|
|
@ -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 ") %s%s%s%s",
|
||||
star_str,
|
||||
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_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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
@ -1635,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);
|
||||
|
@ -1695,11 +1711,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 +2444,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 +3414,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;
|
||||
|
@ -3408,6 +3425,14 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI
|
|||
ZigType *ptr_type = instruction->ptr->value.type;
|
||||
assert(ptr_type->id == ZigTypeIdPointer);
|
||||
|
||||
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, "");
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -3619,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);
|
||||
|
@ -3636,7 +3674,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;
|
||||
}
|
||||
|
||||
|
@ -3645,7 +3683,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);
|
||||
|
||||
|
@ -3657,6 +3694,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;
|
||||
|
@ -3696,12 +3734,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;
|
||||
|
@ -3729,6 +3769,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 +3959,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 +4313,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 +4726,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 +5081,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, "");
|
||||
|
@ -5973,6 +6015,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;
|
||||
|
@ -6093,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:
|
||||
|
@ -6233,6 +6285,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();
|
||||
}
|
||||
|
|
121
src/ir.cpp
121
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:
|
||||
|
|
|
@ -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:
|
||||
|
@ -370,6 +372,8 @@ const char* ir_instruction_type_str(IrInstructionId id) {
|
|||
return "SpillBegin";
|
||||
case IrInstructionIdSpillEnd:
|
||||
return "SpillEnd";
|
||||
case IrInstructionIdVectorExtractElem:
|
||||
return "VectorExtractElem";
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
@ -788,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);
|
||||
|
@ -1969,6 +1982,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) {
|
||||
|
@ -2037,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;
|
||||
|
@ -2466,6 +2490,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");
|
||||
}
|
||||
|
|
|
@ -24,6 +24,38 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
|||
"tmp.zig:4:20: note: referenced here",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
"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 };
|
||||
\\
|
||||
\\ 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{
|
||||
|
|
|
@ -159,3 +159,94 @@ 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();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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 "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();
|
||||
}
|
||||
|
||||
test "initialize vector which is a struct field" {
|
||||
const Vec4Obj = struct {
|
||||
data: @Vector(4, f32),
|
||||
};
|
||||
|
||||
const S = struct {
|
||||
fn doTheTest() void {
|
||||
var foo = Vec4Obj{
|
||||
.data = [_]f32{ 1, 2, 3, 4 },
|
||||
};
|
||||
}
|
||||
};
|
||||
S.doTheTest();
|
||||
comptime S.doTheTest();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue