mirror of
https://github.com/ziglang/zig.git
synced 2025-12-16 11:13:08 +00:00
runtime load vector element with comptime index
This commit is contained in:
parent
a26e9fa723
commit
55e54d98c4
@ -1183,13 +1183,22 @@ struct FnTypeId {
|
|||||||
uint32_t fn_type_id_hash(FnTypeId*);
|
uint32_t fn_type_id_hash(FnTypeId*);
|
||||||
bool fn_type_id_eql(FnTypeId *a, FnTypeId *b);
|
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 {
|
struct ZigTypePointer {
|
||||||
ZigType *child_type;
|
ZigType *child_type;
|
||||||
ZigType *slice_parent;
|
ZigType *slice_parent;
|
||||||
|
|
||||||
PtrLen ptr_len;
|
PtrLen ptr_len;
|
||||||
uint32_t explicit_alignment; // 0 means use ABI alignment
|
uint32_t explicit_alignment; // 0 means use ABI alignment
|
||||||
|
|
||||||
uint32_t bit_offset_in_host;
|
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_const;
|
||||||
bool is_volatile;
|
bool is_volatile;
|
||||||
bool allow_zero;
|
bool allow_zero;
|
||||||
@ -1732,8 +1741,11 @@ struct TypeId {
|
|||||||
ZigType *child_type;
|
ZigType *child_type;
|
||||||
PtrLen ptr_len;
|
PtrLen ptr_len;
|
||||||
uint32_t alignment;
|
uint32_t alignment;
|
||||||
|
|
||||||
uint32_t bit_offset_in_host;
|
uint32_t bit_offset_in_host;
|
||||||
uint32_t host_int_bytes;
|
uint32_t host_int_bytes;
|
||||||
|
|
||||||
|
uint32_t vector_index;
|
||||||
bool is_const;
|
bool is_const;
|
||||||
bool is_volatile;
|
bool is_volatile;
|
||||||
bool allow_zero;
|
bool allow_zero;
|
||||||
|
|||||||
@ -480,9 +480,10 @@ ZigType *get_fn_frame_type(CodeGen *g, ZigFn *fn) {
|
|||||||
return entry;
|
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,
|
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(ptr_len != PtrLenC || allow_zero);
|
||||||
assert(!type_is_invalid(child_type));
|
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;
|
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);
|
uint32_t child_type_bits = type_size_bits(g, child_type);
|
||||||
if (host_int_bytes * 8 == child_type_bits) {
|
if (host_int_bytes * 8 == child_type_bits) {
|
||||||
assert(bit_offset_in_host == 0);
|
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 = {};
|
TypeId type_id = {};
|
||||||
ZigType **parent_pointer = nullptr;
|
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.id = ZigTypeIdPointer;
|
||||||
type_id.data.pointer.child_type = child_type;
|
type_id.data.pointer.child_type = child_type;
|
||||||
type_id.data.pointer.is_const = is_const;
|
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.host_int_bytes = host_int_bytes;
|
||||||
type_id.data.pointer.ptr_len = ptr_len;
|
type_id.data.pointer.ptr_len = ptr_len;
|
||||||
type_id.data.pointer.allow_zero = allow_zero;
|
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);
|
auto existing_entry = g->type_table.maybe_get(type_id);
|
||||||
if (existing_entry)
|
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 " : "";
|
allow_zero_str = allow_zero ? "allowzero " : "";
|
||||||
}
|
}
|
||||||
buf_resize(&entry->name, 0);
|
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",
|
buf_appendf(&entry->name, "%s%s%s%s%s",
|
||||||
star_str, const_str, volatile_str, allow_zero_str, buf_ptr(&child_type->name));
|
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,
|
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));
|
const_str, volatile_str, allow_zero_str, buf_ptr(&child_type->name));
|
||||||
} else if (byte_alignment == 0) {
|
} else if (byte_alignment == 0) {
|
||||||
buf_appendf(&entry->name, "%salign(:%" PRIu32 ":%" PRIu32 ") %s%s%s%s", star_str,
|
assert(vector_index == VECTOR_INDEX_NONE);
|
||||||
bit_offset_in_host, host_int_bytes, const_str, volatile_str, allow_zero_str,
|
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));
|
buf_ptr(&child_type->name));
|
||||||
} else {
|
} else {
|
||||||
buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ") %s%s%s%s", star_str, byte_alignment,
|
buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ":%" PRIu32 ") %s%s%s%s",
|
||||||
bit_offset_in_host, host_int_bytes, const_str, volatile_str, allow_zero_str,
|
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));
|
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.bit_offset_in_host = bit_offset_in_host;
|
||||||
entry->data.pointer.host_int_bytes = host_int_bytes;
|
entry->data.pointer.host_int_bytes = host_int_bytes;
|
||||||
entry->data.pointer.allow_zero = allow_zero;
|
entry->data.pointer.allow_zero = allow_zero;
|
||||||
|
entry->data.pointer.vector_index = vector_index;
|
||||||
|
|
||||||
if (parent_pointer) {
|
if (parent_pointer) {
|
||||||
*parent_pointer = entry;
|
*parent_pointer = entry;
|
||||||
@ -590,8 +612,17 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
|
|||||||
return entry;
|
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) {
|
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) {
|
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) +
|
(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.alignment) ^ (uint32_t)0x777fbe0e) +
|
||||||
(((uint32_t)x.data.pointer.bit_offset_in_host) ^ (uint32_t)2639019452) +
|
(((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);
|
(((uint32_t)x.data.pointer.host_int_bytes) ^ (uint32_t)529908881);
|
||||||
case ZigTypeIdArray:
|
case ZigTypeIdArray:
|
||||||
return hash_ptr(x.data.array.child_type) +
|
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.allow_zero == b.data.pointer.allow_zero &&
|
||||||
a.data.pointer.alignment == b.data.pointer.alignment &&
|
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.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;
|
a.data.pointer.host_int_bytes == b.data.pointer.host_int_bytes;
|
||||||
case ZigTypeIdArray:
|
case ZigTypeIdArray:
|
||||||
return a.data.array.child_type == b.data.array.child_type &&
|
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 ||
|
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.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));
|
assertNoError(type_resolve(g, elem_type, ResolveStatusLLVMFwdDecl));
|
||||||
ZigType *peer_type = get_pointer_to_type_extra(g, elem_type, false, false,
|
ZigType *peer_type;
|
||||||
PtrLenSingle, 0, 0, type->data.pointer.host_int_bytes, false);
|
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_type = get_llvm_type(g, peer_type);
|
||||||
type->llvm_di_type = get_llvm_di_type(g, peer_type);
|
type->llvm_di_type = get_llvm_di_type(g, peer_type);
|
||||||
assertNoError(type_resolve(g, elem_type, wanted_resolve_status));
|
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 *new_type_table_entry(ZigTypeId id);
|
||||||
ZigType *get_fn_frame_type(CodeGen *g, ZigFn *fn);
|
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(CodeGen *g, ZigType *child_type, bool is_const);
|
||||||
ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const,
|
ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type,
|
||||||
bool is_volatile, PtrLen ptr_len,
|
bool is_const, bool is_volatile, PtrLen ptr_len,
|
||||||
uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count,
|
uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count,
|
||||||
bool allow_zero);
|
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(CodeGen *g, ZigType *type_entry);
|
||||||
uint64_t type_size_bits(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);
|
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) {
|
static bool ir_want_fast_math(CodeGen *g, IrInstruction *instruction) {
|
||||||
// TODO memoize
|
// TODO memoize
|
||||||
Scope *scope = instruction->scope;
|
Scope *scope = instruction->scope;
|
||||||
@ -1695,11 +1700,11 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) {
|
|||||||
}
|
}
|
||||||
if (instruction->spill != nullptr) {
|
if (instruction->spill != nullptr) {
|
||||||
ZigType *ptr_type = instruction->spill->value.type;
|
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),
|
return get_handle_value(g, ir_llvm_value(g, instruction->spill),
|
||||||
ptr_type->data.pointer.child_type, instruction->spill->value.type);
|
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);
|
assert(instruction->value.type);
|
||||||
render_const_val(g, &instruction->value, "");
|
render_const_val(g, &instruction->value, "");
|
||||||
// we might have to do some pointer casting here due to the way union
|
// 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;
|
return nullptr;
|
||||||
}
|
}
|
||||||
assert(g->cur_ret_ptr);
|
assert(g->cur_ret_ptr);
|
||||||
src_assert(instruction->operand->value.special != ConstValSpecialRuntime,
|
ir_assert(instruction->operand->value.special != ConstValSpecialRuntime, &instruction->base);
|
||||||
instruction->base.source_node);
|
|
||||||
LLVMValueRef value = ir_llvm_value(g, instruction->operand);
|
LLVMValueRef value = ir_llvm_value(g, instruction->operand);
|
||||||
ZigType *return_type = instruction->operand->value.type;
|
ZigType *return_type = instruction->operand->value.type;
|
||||||
gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value);
|
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;
|
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;
|
ZigType *child_type = instruction->base.value.type;
|
||||||
if (!type_has_bits(child_type))
|
if (!type_has_bits(child_type))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -3409,6 +3415,15 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI
|
|||||||
assert(ptr_type->id == ZigTypeIdPointer);
|
assert(ptr_type->id == ZigTypeIdPointer);
|
||||||
|
|
||||||
uint32_t host_int_bytes = ptr_type->data.pointer.host_int_bytes;
|
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)
|
if (host_int_bytes == 0)
|
||||||
return get_handle_value(g, ptr, child_type, ptr_type);
|
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))
|
if (!type_has_bits(instruction->base.value.type))
|
||||||
return nullptr;
|
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;
|
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_ptr = LLVMBuildStructGEP(g->builder, array_ptr, (unsigned)ptr_index, "");
|
||||||
LLVMValueRef ptr = gen_load_untyped(g, ptr_ptr, 0, false, "");
|
LLVMValueRef ptr = gen_load_untyped(g, ptr_ptr, 0, false, "");
|
||||||
return LLVMBuildInBoundsGEP(g->builder, ptr, &subscript_value, 1, "");
|
return LLVMBuildInBoundsGEP(g->builder, ptr, &subscript_value, 1, "");
|
||||||
|
} else if (array_type->id == ZigTypeIdVector) {
|
||||||
|
return array_ptr_ptr;
|
||||||
} else {
|
} else {
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
}
|
}
|
||||||
@ -3917,9 +3934,9 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
|
|||||||
if (instruction->modifier == CallModifierAsync) {
|
if (instruction->modifier == CallModifierAsync) {
|
||||||
frame_result_loc = result_loc;
|
frame_result_loc = result_loc;
|
||||||
} else {
|
} 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);
|
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,
|
frame_result_loc = LLVMBuildBitCast(g->builder, frame_result_loc_uncasted,
|
||||||
LLVMPointerType(get_llvm_type(g, instruction->fn_entry->frame_type), 0), "");
|
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)))
|
if ((err = type_resolve(g, struct_type, ResolveStatusLLVMFull)))
|
||||||
codegen_report_errors_and_exit(g);
|
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, "");
|
LLVMValueRef field_ptr_val = LLVMBuildStructGEP(g->builder, struct_ptr, (unsigned)field->gen_index, "");
|
||||||
ZigType *res_type = instruction->base.value.type;
|
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) {
|
if (res_type->data.pointer.host_int_bytes != 0) {
|
||||||
// We generate packed structs with get_llvm_type_of_n_bytes, which is
|
// 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
|
// 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) {
|
static LLVMValueRef ir_render_splat(CodeGen *g, IrExecutable *executable, IrInstructionSplatGen *instruction) {
|
||||||
ZigType *result_type = instruction->base.value.type;
|
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;
|
uint32_t len = result_type->data.vector.len;
|
||||||
LLVMTypeRef op_llvm_type = LLVMVectorType(get_llvm_type(g, instruction->scalar->value.type), 1);
|
LLVMTypeRef op_llvm_type = LLVMVectorType(get_llvm_type(g, instruction->scalar->value.type), 1);
|
||||||
LLVMTypeRef mask_llvm_type = LLVMVectorType(LLVMInt32Type(), len);
|
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);
|
LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc);
|
||||||
src_assert(result_loc != nullptr, instruction->base.source_node);
|
ir_assert(result_loc != nullptr, &instruction->base);
|
||||||
src_assert(type_has_bits(child_type), instruction->base.source_node);
|
ir_assert(type_has_bits(child_type), &instruction->base);
|
||||||
|
|
||||||
LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, "");
|
LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, "");
|
||||||
LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, result_loc, maybe_child_index, "");
|
LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, result_loc, maybe_child_index, "");
|
||||||
|
|||||||
48
src/ir.cpp
48
src/ir.cpp
@ -12908,18 +12908,18 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
|
|||||||
ResultLoc *result_loc)
|
ResultLoc *result_loc)
|
||||||
{
|
{
|
||||||
Error err;
|
Error err;
|
||||||
ZigType *type_entry = ptr->value.type;
|
ZigType *ptr_type = ptr->value.type;
|
||||||
if (type_is_invalid(type_entry))
|
if (type_is_invalid(ptr_type))
|
||||||
return ira->codegen->invalid_instruction;
|
return ira->codegen->invalid_instruction;
|
||||||
|
|
||||||
if (type_entry->id != ZigTypeIdPointer) {
|
if (ptr_type->id != ZigTypeIdPointer) {
|
||||||
ir_add_error_node(ira, source_instruction->source_node,
|
ir_add_error_node(ira, source_instruction->source_node,
|
||||||
buf_sprintf("attempt to dereference non-pointer type '%s'",
|
buf_sprintf("attempt to dereference non-pointer type '%s'",
|
||||||
buf_ptr(&type_entry->name)));
|
buf_ptr(&ptr_type->name)));
|
||||||
return ira->codegen->invalid_instruction;
|
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
|
// if the child type has one possible value, the deref is comptime
|
||||||
switch (type_has_one_possible_value(ira->codegen, child_type)) {
|
switch (type_has_one_possible_value(ira->codegen, child_type)) {
|
||||||
case OnePossibleValueInvalid:
|
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 the instruction is a const ref instruction we can skip it
|
||||||
if (ptr->id == IrInstructionIdRef) {
|
if (ptr->id == IrInstructionIdRef) {
|
||||||
IrInstructionRef *ref_inst = reinterpret_cast<IrInstructionRef *>(ptr);
|
IrInstructionRef *ref_inst = reinterpret_cast<IrInstructionRef *>(ptr);
|
||||||
return ref_inst->value;
|
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;
|
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();
|
if (result_loc == nullptr) result_loc = no_result_loc();
|
||||||
result_loc_inst = ir_resolve_result(ira, source_instruction, result_loc, child_type, nullptr,
|
result_loc_inst = ir_resolve_result(ira, source_instruction, result_loc, child_type, nullptr,
|
||||||
true, false, true);
|
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,
|
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);
|
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 {
|
} else {
|
||||||
ir_add_error_node(ira, elem_ptr_instruction->base.source_node,
|
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)));
|
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;
|
safety_check_on = false;
|
||||||
}
|
}
|
||||||
|
if (array_type->id == ZigTypeIdVector) {
|
||||||
if (return_type->data.pointer.explicit_alignment != 0) {
|
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
|
// figure out the largest alignment possible
|
||||||
|
|
||||||
if ((err = type_resolve(ira->codegen, return_type->data.pointer.child_type, ResolveStatusSizeKnown)))
|
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 {
|
} else {
|
||||||
// runtime known element index
|
// runtime known element index
|
||||||
switch (type_requires_comptime(ira->codegen, return_type)) {
|
switch (type_requires_comptime(ira->codegen, return_type)) {
|
||||||
|
|||||||
@ -159,3 +159,20 @@ test "vector @splat" {
|
|||||||
S.doTheTest();
|
S.doTheTest();
|
||||||
comptime 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();
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user