mirror of
https://github.com/ziglang/zig.git
synced 2025-02-10 22:50:18 +00:00
introduce vector type for SIMD
See #903 * create with `@Vector(len, ElemType)` * only wrapping addition is implemented This feature is far from complete; this is only the beginning.
This commit is contained in:
parent
169a789b34
commit
545064c1d9
@ -1531,6 +1531,29 @@ test "array initialization with function calls" {
|
||||
{#code_end#}
|
||||
{#see_also|for|Slices#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|Vectors#}
|
||||
<p>
|
||||
A vector is a group of {#link|Integers#}, {#link|Floats#}, or {#link|Pointers#} which are operated on
|
||||
in parallel using a single instruction ({#link|SIMD#}). Vector types are created with the builtin
|
||||
function {#link|@Vector#}.
|
||||
</p>
|
||||
<p>
|
||||
TODO talk about C ABI interop
|
||||
</p>
|
||||
{#header_open|SIMD#}
|
||||
<p>
|
||||
TODO Zig's SIMD abilities are just beginning to be fleshed out. Here are some talking points to update the
|
||||
docs with:
|
||||
* What kind of operations can you do? All the operations on integers and floats? What about mixing scalar and vector?
|
||||
* How to convert to/from vectors/arrays
|
||||
* How to access individual elements from vectors, how to loop over the elements
|
||||
* "shuffle"
|
||||
* Advice on writing high perf software, how to abstract the best way
|
||||
</p>
|
||||
{#header_close#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|Pointers#}
|
||||
<p>
|
||||
Zig has two kinds of pointers:
|
||||
@ -6607,6 +6630,17 @@ pub const TypeInfo = union(TypeId) {
|
||||
expression passed as an argument. The expression is evaluated.
|
||||
</p>
|
||||
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@Vector#}
|
||||
<pre>{#syntax#}@Vector(comptime len: u32, comptime ElemType: type) type{#endsyntax#}</pre>
|
||||
<p>
|
||||
This function returns a vector type for {#link|SIMD#}.
|
||||
</p>
|
||||
<p>
|
||||
{#syntax#}ElemType{#endsyntax#} must be an {#link|integer|Integers#}, a {#link|float|Floats#}, or a
|
||||
{#link|pointer|Pointers#}.
|
||||
</p>
|
||||
{#header_close#}
|
||||
{#header_close#}
|
||||
|
||||
|
@ -44,6 +44,7 @@ pub const Type = struct {
|
||||
Id.ArgTuple => @fieldParentPtr(ArgTuple, "base", base).destroy(comp),
|
||||
Id.Opaque => @fieldParentPtr(Opaque, "base", base).destroy(comp),
|
||||
Id.Promise => @fieldParentPtr(Promise, "base", base).destroy(comp),
|
||||
Id.Vector => @fieldParentPtr(Vector, "base", base).destroy(comp),
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,6 +78,7 @@ pub const Type = struct {
|
||||
Id.ArgTuple => unreachable,
|
||||
Id.Opaque => return @fieldParentPtr(Opaque, "base", base).getLlvmType(allocator, llvm_context),
|
||||
Id.Promise => return @fieldParentPtr(Promise, "base", base).getLlvmType(allocator, llvm_context),
|
||||
Id.Vector => return @fieldParentPtr(Vector, "base", base).getLlvmType(allocator, llvm_context),
|
||||
}
|
||||
}
|
||||
|
||||
@ -103,6 +105,7 @@ pub const Type = struct {
|
||||
Id.Enum,
|
||||
Id.Fn,
|
||||
Id.Promise,
|
||||
Id.Vector,
|
||||
=> return false,
|
||||
|
||||
Id.Struct => @panic("TODO"),
|
||||
@ -135,6 +138,7 @@ pub const Type = struct {
|
||||
Id.Float,
|
||||
Id.Fn,
|
||||
Id.Promise,
|
||||
Id.Vector,
|
||||
=> return true,
|
||||
|
||||
Id.Pointer => {
|
||||
@ -902,6 +906,18 @@ pub const Type = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub const Vector = struct {
|
||||
base: Type,
|
||||
|
||||
pub fn destroy(self: *Vector, comp: *Compilation) void {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Vector, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
|
||||
pub const ComptimeFloat = struct {
|
||||
base: Type,
|
||||
|
||||
|
@ -252,6 +252,10 @@ struct ConstArgTuple {
|
||||
size_t end_index;
|
||||
};
|
||||
|
||||
struct ConstVector {
|
||||
ConstExprValue *elements;
|
||||
};
|
||||
|
||||
enum ConstValSpecial {
|
||||
ConstValSpecialRuntime,
|
||||
ConstValSpecialStatic,
|
||||
@ -318,6 +322,7 @@ struct ConstExprValue {
|
||||
ConstPtrValue x_ptr;
|
||||
ImportTableEntry *x_import;
|
||||
ConstArgTuple x_arg_tuple;
|
||||
ConstVector x_vector;
|
||||
|
||||
// populated if special == ConstValSpecialRuntime
|
||||
RuntimeHintErrorUnion rh_error_union;
|
||||
@ -1210,6 +1215,12 @@ struct ZigTypePromise {
|
||||
ZigType *result_type;
|
||||
};
|
||||
|
||||
struct ZigTypeVector {
|
||||
// The type must be a pointer, integer, or float
|
||||
ZigType *elem_type;
|
||||
uint32_t len;
|
||||
};
|
||||
|
||||
enum ZigTypeId {
|
||||
ZigTypeIdInvalid,
|
||||
ZigTypeIdMetaType,
|
||||
@ -1236,6 +1247,7 @@ enum ZigTypeId {
|
||||
ZigTypeIdArgTuple,
|
||||
ZigTypeIdOpaque,
|
||||
ZigTypeIdPromise,
|
||||
ZigTypeIdVector,
|
||||
};
|
||||
|
||||
struct ZigType {
|
||||
@ -1262,6 +1274,7 @@ struct ZigType {
|
||||
ZigTypeFn fn;
|
||||
ZigTypeBoundFn bound_fn;
|
||||
ZigTypePromise promise;
|
||||
ZigTypeVector vector;
|
||||
} data;
|
||||
|
||||
// use these fields to make sure we don't duplicate type table entries for the same type
|
||||
@ -1415,6 +1428,7 @@ enum BuiltinFnId {
|
||||
BuiltinFnIdEnumToInt,
|
||||
BuiltinFnIdIntToEnum,
|
||||
BuiltinFnIdIntType,
|
||||
BuiltinFnIdVectorType,
|
||||
BuiltinFnIdSetCold,
|
||||
BuiltinFnIdSetRuntimeSafety,
|
||||
BuiltinFnIdSetFloatMode,
|
||||
@ -1505,6 +1519,10 @@ struct TypeId {
|
||||
ZigType *err_set_type;
|
||||
ZigType *payload_type;
|
||||
} error_union;
|
||||
struct {
|
||||
ZigType *elem_type;
|
||||
uint32_t len;
|
||||
} vector;
|
||||
} data;
|
||||
};
|
||||
|
||||
@ -2139,6 +2157,7 @@ enum IrInstructionId {
|
||||
IrInstructionIdFloatToInt,
|
||||
IrInstructionIdBoolToInt,
|
||||
IrInstructionIdIntType,
|
||||
IrInstructionIdVectorType,
|
||||
IrInstructionIdBoolNot,
|
||||
IrInstructionIdMemset,
|
||||
IrInstructionIdMemcpy,
|
||||
@ -2807,6 +2826,13 @@ struct IrInstructionIntType {
|
||||
IrInstruction *bit_count;
|
||||
};
|
||||
|
||||
struct IrInstructionVectorType {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *len;
|
||||
IrInstruction *elem_type;
|
||||
};
|
||||
|
||||
struct IrInstructionBoolNot {
|
||||
IrInstruction base;
|
||||
|
||||
|
@ -250,6 +250,7 @@ AstNode *type_decl_node(ZigType *type_entry) {
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdPromise:
|
||||
case ZigTypeIdVector:
|
||||
return nullptr;
|
||||
}
|
||||
zig_unreachable();
|
||||
@ -311,6 +312,7 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) {
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdPromise:
|
||||
case ZigTypeIdVector:
|
||||
return true;
|
||||
}
|
||||
zig_unreachable();
|
||||
@ -1055,11 +1057,7 @@ bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id) {
|
||||
}
|
||||
if (g->zig_target.arch.arch == ZigLLVM_x86_64) {
|
||||
X64CABIClass abi_class = type_c_abi_x86_64_class(g, fn_type_id->return_type);
|
||||
if (abi_class == X64CABIClass_MEMORY) {
|
||||
return true;
|
||||
}
|
||||
zig_panic("TODO implement C ABI for x86_64 return types. type '%s'\nSee https://github.com/ziglang/zig/issues/1481",
|
||||
buf_ptr(&fn_type_id->return_type->name));
|
||||
return abi_class == X64CABIClass_MEMORY;
|
||||
} else if (target_is_arm(&g->zig_target)) {
|
||||
return type_size(g, fn_type_id->return_type) > 16;
|
||||
}
|
||||
@ -1424,6 +1422,7 @@ static bool type_allowed_in_packed_struct(ZigType *type_entry) {
|
||||
case ZigTypeIdPointer:
|
||||
case ZigTypeIdArray:
|
||||
case ZigTypeIdFn:
|
||||
case ZigTypeIdVector:
|
||||
return true;
|
||||
case ZigTypeIdStruct:
|
||||
return type_entry->data.structure.layout == ContainerLayoutPacked;
|
||||
@ -1472,6 +1471,8 @@ static bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) {
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
case ZigTypeIdVector:
|
||||
return type_allowed_in_extern(g, type_entry->data.vector.elem_type);
|
||||
case ZigTypeIdFloat:
|
||||
return true;
|
||||
case ZigTypeIdArray:
|
||||
@ -1625,6 +1626,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
|
||||
case ZigTypeIdUnion:
|
||||
case ZigTypeIdFn:
|
||||
case ZigTypeIdPromise:
|
||||
case ZigTypeIdVector:
|
||||
switch (type_requires_comptime(g, type_entry)) {
|
||||
case ReqCompTimeNo:
|
||||
break;
|
||||
@ -1720,6 +1722,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
|
||||
case ZigTypeIdUnion:
|
||||
case ZigTypeIdFn:
|
||||
case ZigTypeIdPromise:
|
||||
case ZigTypeIdVector:
|
||||
switch (type_requires_comptime(g, fn_type_id.return_type)) {
|
||||
case ReqCompTimeInvalid:
|
||||
return g->builtin_types.entry_invalid;
|
||||
@ -3577,6 +3580,7 @@ ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry
|
||||
case ZigTypeIdFn:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdPromise:
|
||||
case ZigTypeIdVector:
|
||||
return type_entry;
|
||||
}
|
||||
zig_unreachable();
|
||||
@ -3943,6 +3947,7 @@ static bool is_container(ZigType *type_entry) {
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdOpaque:
|
||||
case ZigTypeIdPromise:
|
||||
case ZigTypeIdVector:
|
||||
return false;
|
||||
}
|
||||
zig_unreachable();
|
||||
@ -4002,6 +4007,7 @@ void resolve_container_type(CodeGen *g, ZigType *type_entry) {
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdOpaque:
|
||||
case ZigTypeIdPromise:
|
||||
case ZigTypeIdVector:
|
||||
zig_unreachable();
|
||||
}
|
||||
}
|
||||
@ -4451,6 +4457,34 @@ ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) {
|
||||
return new_entry;
|
||||
}
|
||||
|
||||
ZigType *get_vector_type(CodeGen *g, uint32_t len, ZigType *elem_type) {
|
||||
TypeId type_id = {};
|
||||
type_id.id = ZigTypeIdVector;
|
||||
type_id.data.vector.len = len;
|
||||
type_id.data.vector.elem_type = elem_type;
|
||||
|
||||
{
|
||||
auto entry = g->type_table.maybe_get(type_id);
|
||||
if (entry)
|
||||
return entry->value;
|
||||
}
|
||||
|
||||
ZigType *entry = new_type_table_entry(ZigTypeIdVector);
|
||||
entry->zero_bits = (len == 0) || !type_has_bits(elem_type);
|
||||
entry->type_ref = entry->zero_bits ? LLVMVoidType() : LLVMVectorType(elem_type->type_ref, len);
|
||||
entry->data.vector.len = len;
|
||||
entry->data.vector.elem_type = elem_type;
|
||||
|
||||
buf_resize(&entry->name, 0);
|
||||
buf_appendf(&entry->name, "@Vector(%u, %s)", len, buf_ptr(&elem_type->name));
|
||||
|
||||
entry->di_type = ZigLLVMDIBuilderCreateVectorType(g->dbuilder, len,
|
||||
LLVMABIAlignmentOfType(g->target_data_ref, entry->type_ref), elem_type->di_type);
|
||||
|
||||
g->type_table.put(type_id, entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
ZigType **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type) {
|
||||
return &g->builtin_types.entry_c_int[c_int_type];
|
||||
}
|
||||
@ -4482,6 +4516,7 @@ bool handle_is_ptr(ZigType *type_entry) {
|
||||
case ZigTypeIdFn:
|
||||
case ZigTypeIdEnum:
|
||||
case ZigTypeIdPromise:
|
||||
case ZigTypeIdVector:
|
||||
return false;
|
||||
case ZigTypeIdArray:
|
||||
case ZigTypeIdStruct:
|
||||
@ -4914,6 +4949,9 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
|
||||
return hash_const_val_error_set(const_val);
|
||||
case ZigTypeIdNamespace:
|
||||
return hash_ptr(const_val->data.x_import);
|
||||
case ZigTypeIdVector:
|
||||
// TODO better hashing algorithm
|
||||
return 3647867726;
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdInvalid:
|
||||
case ZigTypeIdUnreachable:
|
||||
@ -4966,6 +5004,7 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) {
|
||||
case ZigTypeIdBool:
|
||||
case ZigTypeIdUnreachable:
|
||||
case ZigTypeIdInt:
|
||||
case ZigTypeIdVector:
|
||||
case ZigTypeIdFloat:
|
||||
case ZigTypeIdComptimeFloat:
|
||||
case ZigTypeIdComptimeInt:
|
||||
@ -5049,6 +5088,7 @@ static bool return_type_is_cacheable(ZigType *return_type) {
|
||||
case ZigTypeIdErrorSet:
|
||||
case ZigTypeIdEnum:
|
||||
case ZigTypeIdPointer:
|
||||
case ZigTypeIdVector:
|
||||
return true;
|
||||
|
||||
case ZigTypeIdArray:
|
||||
@ -5201,6 +5241,7 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) {
|
||||
case ZigTypeIdErrorSet:
|
||||
case ZigTypeIdEnum:
|
||||
case ZigTypeIdInt:
|
||||
case ZigTypeIdVector:
|
||||
return type_has_bits(type_entry) ? OnePossibleValueNo : OnePossibleValueYes;
|
||||
case ZigTypeIdPointer:
|
||||
return type_has_one_possible_value(g, type_entry->data.pointer.child_type);
|
||||
@ -5251,6 +5292,7 @@ ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) {
|
||||
case ZigTypeIdErrorSet:
|
||||
case ZigTypeIdBool:
|
||||
case ZigTypeIdInt:
|
||||
case ZigTypeIdVector:
|
||||
case ZigTypeIdFloat:
|
||||
case ZigTypeIdVoid:
|
||||
case ZigTypeIdUnreachable:
|
||||
@ -5777,7 +5819,7 @@ bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) {
|
||||
ConstExprValue *a_elems = a->data.x_array.data.s_none.elements;
|
||||
ConstExprValue *b_elems = b->data.x_array.data.s_none.elements;
|
||||
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
for (size_t i = 0; i < len; i += 1) {
|
||||
if (!const_values_equal(g, &a_elems[i], &b_elems[i]))
|
||||
return false;
|
||||
}
|
||||
@ -5811,6 +5853,20 @@ bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) {
|
||||
case ZigTypeIdArgTuple:
|
||||
return a->data.x_arg_tuple.start_index == b->data.x_arg_tuple.start_index &&
|
||||
a->data.x_arg_tuple.end_index == b->data.x_arg_tuple.end_index;
|
||||
case ZigTypeIdVector: {
|
||||
assert(a->type->data.vector.len == b->type->data.vector.len);
|
||||
|
||||
size_t len = a->type->data.vector.len;
|
||||
ConstExprValue *a_elems = a->data.x_vector.elements;
|
||||
ConstExprValue *b_elems = b->data.x_vector.elements;
|
||||
|
||||
for (size_t i = 0; i < len; i += 1) {
|
||||
if (!const_values_equal(g, &a_elems[i], &b_elems[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdInvalid:
|
||||
case ZigTypeIdUnreachable:
|
||||
@ -6042,6 +6098,18 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
|
||||
}
|
||||
}
|
||||
zig_unreachable();
|
||||
case ZigTypeIdVector: {
|
||||
buf_appendf(buf, "%s{", buf_ptr(&type_entry->name));
|
||||
uint64_t len = type_entry->data.vector.len;
|
||||
for (uint32_t i = 0; i < len; i += 1) {
|
||||
if (i != 0)
|
||||
buf_appendf(buf, ",");
|
||||
ConstExprValue *child_value = &const_val->data.x_vector.elements[i];
|
||||
render_const_value(g, buf, child_value);
|
||||
}
|
||||
buf_appendf(buf, "}");
|
||||
return;
|
||||
}
|
||||
case ZigTypeIdNull:
|
||||
{
|
||||
buf_appendf(buf, "null");
|
||||
@ -6200,6 +6268,8 @@ uint32_t type_id_hash(TypeId x) {
|
||||
case ZigTypeIdInt:
|
||||
return (x.data.integer.is_signed ? (uint32_t)2652528194 : (uint32_t)163929201) +
|
||||
(((uint32_t)x.data.integer.bit_count) ^ (uint32_t)2998081557);
|
||||
case ZigTypeIdVector:
|
||||
return hash_ptr(x.data.vector.elem_type) * (x.data.vector.len * 526582681);
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
@ -6248,6 +6318,9 @@ bool type_id_eql(TypeId a, TypeId b) {
|
||||
case ZigTypeIdInt:
|
||||
return a.data.integer.is_signed == b.data.integer.is_signed &&
|
||||
a.data.integer.bit_count == b.data.integer.bit_count;
|
||||
case ZigTypeIdVector:
|
||||
return a.data.vector.elem_type == b.data.vector.elem_type &&
|
||||
a.data.vector.len == b.data.vector.len;
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
@ -6382,6 +6455,7 @@ static const ZigTypeId all_type_ids[] = {
|
||||
ZigTypeIdArgTuple,
|
||||
ZigTypeIdOpaque,
|
||||
ZigTypeIdPromise,
|
||||
ZigTypeIdVector,
|
||||
};
|
||||
|
||||
ZigTypeId type_id_at_index(size_t index) {
|
||||
@ -6447,6 +6521,8 @@ size_t type_id_index(ZigType *entry) {
|
||||
return 22;
|
||||
case ZigTypeIdPromise:
|
||||
return 23;
|
||||
case ZigTypeIdVector:
|
||||
return 24;
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
@ -6503,6 +6579,8 @@ const char *type_id_name(ZigTypeId id) {
|
||||
return "Opaque";
|
||||
case ZigTypeIdPromise:
|
||||
return "Promise";
|
||||
case ZigTypeIdVector:
|
||||
return "Vector";
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
@ -6658,6 +6736,7 @@ X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty) {
|
||||
case ZigTypeIdBool:
|
||||
return X64CABIClass_INTEGER;
|
||||
case ZigTypeIdFloat:
|
||||
case ZigTypeIdVector:
|
||||
return X64CABIClass_SSE;
|
||||
case ZigTypeIdStruct: {
|
||||
// "If the size of an object is larger than four eightbytes, or it contains unaligned
|
||||
|
@ -20,6 +20,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
|
||||
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);
|
||||
ZigType *get_vector_type(CodeGen *g, uint32_t len, ZigType *elem_type);
|
||||
ZigType **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type);
|
||||
ZigType *get_c_int_type(CodeGen *g, CIntType c_int_type);
|
||||
ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id);
|
||||
|
@ -1980,7 +1980,7 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
|
||||
break;
|
||||
}
|
||||
|
||||
if (type_is_c_abi_int(g, ty) || ty->id == ZigTypeIdFloat ||
|
||||
if (type_is_c_abi_int(g, ty) || ty->id == ZigTypeIdFloat || ty->id == ZigTypeIdVector ||
|
||||
ty->id == ZigTypeIdInt // TODO investigate if we need to change this
|
||||
) {
|
||||
switch (fn_walk->id) {
|
||||
@ -2660,6 +2660,27 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
|
||||
} else {
|
||||
return LLVMBuildNUWAdd(g->builder, op1_value, op2_value, "");
|
||||
}
|
||||
} else if (type_entry->id == ZigTypeIdVector) {
|
||||
ZigType *elem_type = type_entry->data.vector.elem_type;
|
||||
if (elem_type->id == ZigTypeIdFloat) {
|
||||
ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base));
|
||||
return LLVMBuildFAdd(g->builder, op1_value, op2_value, "");
|
||||
} else if (elem_type->id == ZigTypeIdPointer) {
|
||||
zig_panic("TODO codegen for pointers in vectors");
|
||||
} else if (elem_type->id == ZigTypeIdInt) {
|
||||
bool is_wrapping = (op_id == IrBinOpAddWrap);
|
||||
if (is_wrapping) {
|
||||
return LLVMBuildAdd(g->builder, op1_value, op2_value, "");
|
||||
} else if (want_runtime_safety) {
|
||||
zig_panic("TODO runtime safety for vector integer addition");
|
||||
} else if (elem_type->data.integral.is_signed) {
|
||||
return LLVMBuildNSWAdd(g->builder, op1_value, op2_value, "");
|
||||
} else {
|
||||
return LLVMBuildNUWAdd(g->builder, op1_value, op2_value, "");
|
||||
}
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
@ -5211,6 +5232,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
|
||||
case IrInstructionIdCUndef:
|
||||
case IrInstructionIdEmbedFile:
|
||||
case IrInstructionIdIntType:
|
||||
case IrInstructionIdVectorType:
|
||||
case IrInstructionIdMemberCount:
|
||||
case IrInstructionIdMemberType:
|
||||
case IrInstructionIdMemberName:
|
||||
@ -5620,6 +5642,8 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
|
||||
}
|
||||
case ZigTypeIdArray:
|
||||
zig_panic("TODO bit pack an array");
|
||||
case ZigTypeIdVector:
|
||||
zig_panic("TODO bit pack a vector");
|
||||
case ZigTypeIdUnion:
|
||||
zig_panic("TODO bit pack a union");
|
||||
case ZigTypeIdStruct:
|
||||
@ -5992,6 +6016,14 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
|
||||
}
|
||||
}
|
||||
}
|
||||
case ZigTypeIdVector: {
|
||||
uint32_t len = type_entry->data.vector.len;
|
||||
LLVMValueRef *values = allocate<LLVMValueRef>(len);
|
||||
for (uint32_t i = 0; i < len; i += 1) {
|
||||
values[i] = gen_const_val(g, &const_val->data.x_vector.elements[i], "");
|
||||
}
|
||||
return LLVMConstVector(values, len);
|
||||
}
|
||||
case ZigTypeIdUnion:
|
||||
{
|
||||
LLVMTypeRef union_type_ref = type_entry->data.unionation.union_type_ref;
|
||||
@ -6927,6 +6959,7 @@ static void define_builtin_fns(CodeGen *g) {
|
||||
create_builtin_fn(g, BuiltinFnIdCompileErr, "compileError", 1);
|
||||
create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX);
|
||||
create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int
|
||||
create_builtin_fn(g, BuiltinFnIdVectorType, "Vector", 2);
|
||||
create_builtin_fn(g, BuiltinFnIdSetCold, "setCold", 1);
|
||||
create_builtin_fn(g, BuiltinFnIdSetRuntimeSafety, "setRuntimeSafety", 1);
|
||||
create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 1);
|
||||
@ -7152,6 +7185,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
|
||||
" ArgTuple: void,\n"
|
||||
" Opaque: void,\n"
|
||||
" Promise: Promise,\n"
|
||||
" Vector: Vector,\n"
|
||||
"\n\n"
|
||||
" pub const Int = struct {\n"
|
||||
" is_signed: bool,\n"
|
||||
@ -7270,6 +7304,11 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
|
||||
" child: ?type,\n"
|
||||
" };\n"
|
||||
"\n"
|
||||
" pub const Vector = struct {\n"
|
||||
" len: u32,\n"
|
||||
" child: type,\n"
|
||||
" };\n"
|
||||
"\n"
|
||||
" pub const Definition = struct {\n"
|
||||
" name: []const u8,\n"
|
||||
" is_pub: bool,\n"
|
||||
@ -7841,6 +7880,9 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, ZigType *type_e
|
||||
case ZigTypeIdArray:
|
||||
prepend_c_type_to_decl_list(g, gen_h, type_entry->data.array.child_type);
|
||||
return;
|
||||
case ZigTypeIdVector:
|
||||
prepend_c_type_to_decl_list(g, gen_h, type_entry->data.vector.elem_type);
|
||||
return;
|
||||
case ZigTypeIdOptional:
|
||||
prepend_c_type_to_decl_list(g, gen_h, type_entry->data.maybe.child_type);
|
||||
return;
|
||||
@ -7972,6 +8014,8 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu
|
||||
buf_appendf(out_buf, "%s", buf_ptr(child_buf));
|
||||
return;
|
||||
}
|
||||
case ZigTypeIdVector:
|
||||
zig_panic("TODO implement get_c_type for vector types");
|
||||
case ZigTypeIdErrorUnion:
|
||||
case ZigTypeIdErrorSet:
|
||||
case ZigTypeIdFn:
|
||||
@ -8137,6 +8181,7 @@ static void gen_h_file(CodeGen *g) {
|
||||
case ZigTypeIdOptional:
|
||||
case ZigTypeIdFn:
|
||||
case ZigTypeIdPromise:
|
||||
case ZigTypeIdVector:
|
||||
zig_unreachable();
|
||||
case ZigTypeIdEnum:
|
||||
if (type_entry->data.enumeration.layout == ContainerLayoutExtern) {
|
||||
|
213
src/ir.cpp
213
src/ir.cpp
@ -587,6 +587,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionIntType *) {
|
||||
return IrInstructionIdIntType;
|
||||
}
|
||||
|
||||
static constexpr IrInstructionId ir_instruction_id(IrInstructionVectorType *) {
|
||||
return IrInstructionIdVectorType;
|
||||
}
|
||||
|
||||
static constexpr IrInstructionId ir_instruction_id(IrInstructionBoolNot *) {
|
||||
return IrInstructionIdBoolNot;
|
||||
}
|
||||
@ -1953,6 +1957,19 @@ static IrInstruction *ir_build_int_type(IrBuilder *irb, Scope *scope, AstNode *s
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_vector_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *len,
|
||||
IrInstruction *elem_type)
|
||||
{
|
||||
IrInstructionVectorType *instruction = ir_build_instruction<IrInstructionVectorType>(irb, scope, source_node);
|
||||
instruction->len = len;
|
||||
instruction->elem_type = elem_type;
|
||||
|
||||
ir_ref_instruction(len, irb->current_basic_block);
|
||||
ir_ref_instruction(elem_type, irb->current_basic_block);
|
||||
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_bool_not(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) {
|
||||
IrInstructionBoolNot *instruction = ir_build_instruction<IrInstructionBoolNot>(irb, scope, source_node);
|
||||
instruction->value = value;
|
||||
@ -4230,6 +4247,21 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
|
||||
IrInstruction *int_type = ir_build_int_type(irb, scope, node, arg0_value, arg1_value);
|
||||
return ir_lval_wrap(irb, scope, int_type, lval);
|
||||
}
|
||||
case BuiltinFnIdVectorType:
|
||||
{
|
||||
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
|
||||
IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
|
||||
if (arg0_value == irb->codegen->invalid_instruction)
|
||||
return arg0_value;
|
||||
|
||||
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
|
||||
IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
|
||||
if (arg1_value == irb->codegen->invalid_instruction)
|
||||
return arg1_value;
|
||||
|
||||
IrInstruction *vector_type = ir_build_vector_type(irb, scope, node, arg0_value, arg1_value);
|
||||
return ir_lval_wrap(irb, scope, vector_type, lval);
|
||||
}
|
||||
case BuiltinFnIdMemcpy:
|
||||
{
|
||||
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
|
||||
@ -11617,6 +11649,7 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
|
||||
case ZigTypeIdComptimeInt:
|
||||
case ZigTypeIdInt:
|
||||
case ZigTypeIdFloat:
|
||||
case ZigTypeIdVector:
|
||||
operator_allowed = true;
|
||||
break;
|
||||
|
||||
@ -12032,6 +12065,48 @@ static IrInstruction *ir_analyze_bit_shift(IrAnalyze *ira, IrInstructionBinOp *b
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool ok_float_op(IrBinOp op) {
|
||||
switch (op) {
|
||||
case IrBinOpInvalid:
|
||||
zig_unreachable();
|
||||
case IrBinOpAdd:
|
||||
case IrBinOpSub:
|
||||
case IrBinOpMult:
|
||||
case IrBinOpDivUnspecified:
|
||||
case IrBinOpDivTrunc:
|
||||
case IrBinOpDivFloor:
|
||||
case IrBinOpDivExact:
|
||||
case IrBinOpRemRem:
|
||||
case IrBinOpRemMod:
|
||||
return true;
|
||||
|
||||
case IrBinOpBoolOr:
|
||||
case IrBinOpBoolAnd:
|
||||
case IrBinOpCmpEq:
|
||||
case IrBinOpCmpNotEq:
|
||||
case IrBinOpCmpLessThan:
|
||||
case IrBinOpCmpGreaterThan:
|
||||
case IrBinOpCmpLessOrEq:
|
||||
case IrBinOpCmpGreaterOrEq:
|
||||
case IrBinOpBinOr:
|
||||
case IrBinOpBinXor:
|
||||
case IrBinOpBinAnd:
|
||||
case IrBinOpBitShiftLeftLossy:
|
||||
case IrBinOpBitShiftLeftExact:
|
||||
case IrBinOpBitShiftRightLossy:
|
||||
case IrBinOpBitShiftRightExact:
|
||||
case IrBinOpAddWrap:
|
||||
case IrBinOpSubWrap:
|
||||
case IrBinOpMultWrap:
|
||||
case IrBinOpRemUnspecified:
|
||||
case IrBinOpArrayCat:
|
||||
case IrBinOpArrayMult:
|
||||
case IrBinOpMergeErrorSets:
|
||||
return false;
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp *instruction) {
|
||||
IrInstruction *op1 = instruction->op1->child;
|
||||
if (type_is_invalid(op1->value.type))
|
||||
@ -12169,21 +12244,20 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
|
||||
op_id = IrBinOpRemRem;
|
||||
}
|
||||
|
||||
bool ok = false;
|
||||
if (is_int) {
|
||||
// int
|
||||
} else if (is_float &&
|
||||
(op_id == IrBinOpAdd ||
|
||||
op_id == IrBinOpSub ||
|
||||
op_id == IrBinOpMult ||
|
||||
op_id == IrBinOpDivUnspecified ||
|
||||
op_id == IrBinOpDivTrunc ||
|
||||
op_id == IrBinOpDivFloor ||
|
||||
op_id == IrBinOpDivExact ||
|
||||
op_id == IrBinOpRemRem ||
|
||||
op_id == IrBinOpRemMod))
|
||||
{
|
||||
// float
|
||||
} else {
|
||||
ok = true;
|
||||
} else if (is_float && ok_float_op(op_id)) {
|
||||
ok = true;
|
||||
} else if (resolved_type->id == ZigTypeIdVector) {
|
||||
ZigType *elem_type = resolved_type->data.vector.elem_type;
|
||||
if (elem_type->id == ZigTypeIdInt || elem_type->id == ZigTypeIdComptimeInt) {
|
||||
ok = true;
|
||||
} else if ((elem_type->id == ZigTypeIdFloat || elem_type->id == ZigTypeIdComptimeFloat) && ok_float_op(op_id)) {
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
AstNode *source_node = instruction->base.source_node;
|
||||
ir_add_error_node(ira, source_node,
|
||||
buf_sprintf("invalid operands to binary expression: '%s' and '%s'",
|
||||
@ -12817,6 +12891,7 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
|
||||
case ZigTypeIdPointer:
|
||||
case ZigTypeIdArray:
|
||||
case ZigTypeIdBool:
|
||||
case ZigTypeIdVector:
|
||||
break;
|
||||
case ZigTypeIdMetaType:
|
||||
case ZigTypeIdVoid:
|
||||
@ -12851,6 +12926,7 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
|
||||
case ZigTypeIdOptional:
|
||||
case ZigTypeIdErrorUnion:
|
||||
case ZigTypeIdErrorSet:
|
||||
case ZigTypeIdVector:
|
||||
zig_panic("TODO export const value of type %s", buf_ptr(&target->value.type->name));
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBoundFn:
|
||||
@ -14009,6 +14085,7 @@ static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_
|
||||
case ZigTypeIdVoid:
|
||||
case ZigTypeIdBool:
|
||||
case ZigTypeIdInt:
|
||||
case ZigTypeIdVector:
|
||||
case ZigTypeIdFloat:
|
||||
case ZigTypeIdPointer:
|
||||
case ZigTypeIdArray:
|
||||
@ -15383,37 +15460,7 @@ static IrInstruction *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructio
|
||||
ZigType *type_entry = expr_value->value.type;
|
||||
if (type_is_invalid(type_entry))
|
||||
return ira->codegen->invalid_instruction;
|
||||
switch (type_entry->id) {
|
||||
case ZigTypeIdInvalid:
|
||||
zig_unreachable(); // handled above
|
||||
case ZigTypeIdComptimeFloat:
|
||||
case ZigTypeIdComptimeInt:
|
||||
case ZigTypeIdUndefined:
|
||||
case ZigTypeIdNull:
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdMetaType:
|
||||
case ZigTypeIdVoid:
|
||||
case ZigTypeIdBool:
|
||||
case ZigTypeIdUnreachable:
|
||||
case ZigTypeIdInt:
|
||||
case ZigTypeIdFloat:
|
||||
case ZigTypeIdPointer:
|
||||
case ZigTypeIdArray:
|
||||
case ZigTypeIdStruct:
|
||||
case ZigTypeIdOptional:
|
||||
case ZigTypeIdErrorUnion:
|
||||
case ZigTypeIdErrorSet:
|
||||
case ZigTypeIdEnum:
|
||||
case ZigTypeIdUnion:
|
||||
case ZigTypeIdFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdOpaque:
|
||||
case ZigTypeIdPromise:
|
||||
return ir_const_type(ira, &typeof_instruction->base, type_entry);
|
||||
}
|
||||
|
||||
zig_unreachable();
|
||||
return ir_const_type(ira, &typeof_instruction->base, type_entry);
|
||||
}
|
||||
|
||||
static IrInstruction *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira,
|
||||
@ -15652,6 +15699,7 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira,
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdPromise:
|
||||
case ZigTypeIdVector:
|
||||
{
|
||||
if ((err = type_resolve(ira->codegen, child_type, ResolveStatusZeroBitsKnown)))
|
||||
return ira->codegen->invalid_instruction;
|
||||
@ -15772,6 +15820,7 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira,
|
||||
case ZigTypeIdNamespace:
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdPromise:
|
||||
case ZigTypeIdVector:
|
||||
{
|
||||
if ((err = ensure_complete_type(ira->codegen, child_type)))
|
||||
return ira->codegen->invalid_instruction;
|
||||
@ -15838,6 +15887,7 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira,
|
||||
case ZigTypeIdUnion:
|
||||
case ZigTypeIdFn:
|
||||
case ZigTypeIdPromise:
|
||||
case ZigTypeIdVector:
|
||||
{
|
||||
uint64_t size_in_bytes = type_size(ira->codegen, type_entry);
|
||||
return ir_const_unsigned(ira, &size_of_instruction->base, size_in_bytes);
|
||||
@ -16307,6 +16357,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
|
||||
case ZigTypeIdBoundFn:
|
||||
case ZigTypeIdArgTuple:
|
||||
case ZigTypeIdOpaque:
|
||||
case ZigTypeIdVector:
|
||||
ir_add_error(ira, &switch_target_instruction->base,
|
||||
buf_sprintf("invalid switch target type '%s'", buf_ptr(&target_type->name)));
|
||||
return ira->codegen->invalid_instruction;
|
||||
@ -17496,6 +17547,27 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE
|
||||
|
||||
break;
|
||||
}
|
||||
case ZigTypeIdVector: {
|
||||
result = create_const_vals(1);
|
||||
result->special = ConstValSpecialStatic;
|
||||
result->type = ir_type_info_get_type(ira, "Vector", nullptr);
|
||||
|
||||
ConstExprValue *fields = create_const_vals(2);
|
||||
result->data.x_struct.fields = fields;
|
||||
|
||||
// len: usize
|
||||
ensure_field_index(result->type, "len", 0);
|
||||
fields[0].special = ConstValSpecialStatic;
|
||||
fields[0].type = ira->codegen->builtin_types.entry_u32;
|
||||
bigint_init_unsigned(&fields[0].data.x_bigint, type_entry->data.vector.len);
|
||||
// child: type
|
||||
ensure_field_index(result->type, "child", 1);
|
||||
fields[1].special = ConstValSpecialStatic;
|
||||
fields[1].type = ira->codegen->builtin_types.entry_type;
|
||||
fields[1].data.x_type = type_entry->data.vector.elem_type;
|
||||
|
||||
break;
|
||||
}
|
||||
case ZigTypeIdOptional:
|
||||
{
|
||||
result = create_const_vals(1);
|
||||
@ -18671,6 +18743,30 @@ static IrInstruction *ir_analyze_instruction_int_type(IrAnalyze *ira, IrInstruct
|
||||
return ir_const_type(ira, &instruction->base, get_int_type(ira->codegen, is_signed, (uint32_t)bit_count));
|
||||
}
|
||||
|
||||
static IrInstruction *ir_analyze_instruction_vector_type(IrAnalyze *ira, IrInstructionVectorType *instruction) {
|
||||
uint64_t len;
|
||||
if (!ir_resolve_unsigned(ira, instruction->len->child, ira->codegen->builtin_types.entry_u32, &len))
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
ZigType *elem_type = ir_resolve_type(ira, instruction->elem_type->child);
|
||||
if (type_is_invalid(elem_type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
if (elem_type->id != ZigTypeIdInt &&
|
||||
elem_type->id != ZigTypeIdFloat &&
|
||||
get_codegen_ptr_type(elem_type) == nullptr)
|
||||
{
|
||||
ir_add_error(ira, instruction->elem_type,
|
||||
buf_sprintf("vector element type must be integer, float, or pointer; '%s' is invalid",
|
||||
buf_ptr(&elem_type->name)));
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
ZigType *vector_type = get_vector_type(ira->codegen, len, elem_type);
|
||||
|
||||
return ir_const_type(ira, &instruction->base, vector_type);
|
||||
}
|
||||
|
||||
static IrInstruction *ir_analyze_instruction_bool_not(IrAnalyze *ira, IrInstructionBoolNot *instruction) {
|
||||
IrInstruction *value = instruction->value->child;
|
||||
if (type_is_invalid(value->value.type))
|
||||
@ -19474,6 +19570,7 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct
|
||||
case ZigTypeIdEnum:
|
||||
case ZigTypeIdUnion:
|
||||
case ZigTypeIdFn:
|
||||
case ZigTypeIdVector:
|
||||
{
|
||||
uint64_t align_in_bytes = get_abi_alignment(ira->codegen, type_entry);
|
||||
return ir_const_unsigned(ira, &instruction->base, align_in_bytes);
|
||||
@ -20311,6 +20408,15 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
|
||||
}
|
||||
}
|
||||
return;
|
||||
case ZigTypeIdVector: {
|
||||
size_t buf_i = 0;
|
||||
for (uint32_t elem_i = 0; elem_i < val->type->data.vector.len; elem_i += 1) {
|
||||
ConstExprValue *elem = &val->data.x_vector.elements[elem_i];
|
||||
buf_write_value_bytes(codegen, &buf[buf_i], elem);
|
||||
buf_i += type_size(codegen, elem->type);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case ZigTypeIdStruct:
|
||||
zig_panic("TODO buf_write_value_bytes struct type");
|
||||
case ZigTypeIdOptional:
|
||||
@ -20387,6 +20493,20 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
case ZigTypeIdVector: {
|
||||
uint64_t elem_size = type_size(codegen, val->type->data.vector.elem_type);
|
||||
uint32_t len = val->type->data.vector.len;
|
||||
|
||||
val->data.x_vector.elements = create_const_vals(len);
|
||||
for (uint32_t i = 0; i < len; i += 1) {
|
||||
ConstExprValue *elem = &val->data.x_vector.elements[i];
|
||||
elem->special = ConstValSpecialStatic;
|
||||
elem->type = val->type->data.vector.elem_type;
|
||||
if ((err = buf_read_value_bytes(ira, codegen, source_node, buf + (elem_size * i), elem)))
|
||||
return err;
|
||||
}
|
||||
return ErrorNone;
|
||||
}
|
||||
case ZigTypeIdEnum:
|
||||
switch (val->type->data.enumeration.layout) {
|
||||
case ContainerLayoutAuto:
|
||||
@ -21633,6 +21753,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
|
||||
return ir_analyze_instruction_bool_to_int(ira, (IrInstructionBoolToInt *)instruction);
|
||||
case IrInstructionIdIntType:
|
||||
return ir_analyze_instruction_int_type(ira, (IrInstructionIntType *)instruction);
|
||||
case IrInstructionIdVectorType:
|
||||
return ir_analyze_instruction_vector_type(ira, (IrInstructionVectorType *)instruction);
|
||||
case IrInstructionIdBoolNot:
|
||||
return ir_analyze_instruction_bool_not(ira, (IrInstructionBoolNot *)instruction);
|
||||
case IrInstructionIdMemset:
|
||||
@ -21943,6 +22065,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
|
||||
case IrInstructionIdEmbedFile:
|
||||
case IrInstructionIdTruncate:
|
||||
case IrInstructionIdIntType:
|
||||
case IrInstructionIdVectorType:
|
||||
case IrInstructionIdBoolNot:
|
||||
case IrInstructionIdSlice:
|
||||
case IrInstructionIdMemberCount:
|
||||
|
@ -719,6 +719,14 @@ static void ir_print_int_type(IrPrint *irp, IrInstructionIntType *instruction) {
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_vector_type(IrPrint *irp, IrInstructionVectorType *instruction) {
|
||||
fprintf(irp->f, "@Vector(");
|
||||
ir_print_other_instruction(irp, instruction->len);
|
||||
fprintf(irp->f, ", ");
|
||||
ir_print_other_instruction(irp, instruction->elem_type);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_bool_not(IrPrint *irp, IrInstructionBoolNot *instruction) {
|
||||
fprintf(irp->f, "! ");
|
||||
ir_print_other_instruction(irp, instruction->value);
|
||||
@ -1577,6 +1585,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
case IrInstructionIdIntType:
|
||||
ir_print_int_type(irp, (IrInstructionIntType *)instruction);
|
||||
break;
|
||||
case IrInstructionIdVectorType:
|
||||
ir_print_vector_type(irp, (IrInstructionVectorType *)instruction);
|
||||
break;
|
||||
case IrInstructionIdBoolNot:
|
||||
ir_print_bool_not(irp, (IrInstructionBoolNot *)instruction);
|
||||
break;
|
||||
|
@ -263,6 +263,19 @@ ZigLLVMDIType *ZigLLVMCreateDebugBasicType(ZigLLVMDIBuilder *dibuilder, const ch
|
||||
return reinterpret_cast<ZigLLVMDIType*>(di_type);
|
||||
}
|
||||
|
||||
struct ZigLLVMDIType *ZigLLVMDIBuilderCreateVectorType(struct ZigLLVMDIBuilder *dibuilder,
|
||||
uint64_t Size, uint32_t AlignInBits, struct ZigLLVMDIType *Ty)
|
||||
{
|
||||
SmallVector<Metadata *, 1> subrange;
|
||||
subrange.push_back(reinterpret_cast<DIBuilder*>(dibuilder)->getOrCreateSubrange(0, Size));
|
||||
DIType *di_type = reinterpret_cast<DIBuilder*>(dibuilder)->createVectorType(
|
||||
Size,
|
||||
AlignInBits,
|
||||
reinterpret_cast<DIType*>(Ty),
|
||||
reinterpret_cast<DIBuilder*>(dibuilder)->getOrCreateArray(subrange));
|
||||
return reinterpret_cast<ZigLLVMDIType*>(di_type);
|
||||
}
|
||||
|
||||
ZigLLVMDIType *ZigLLVMCreateDebugArrayType(ZigLLVMDIBuilder *dibuilder, uint64_t size_in_bits,
|
||||
uint64_t align_in_bits, ZigLLVMDIType *elem_type, int elem_count)
|
||||
{
|
||||
|
@ -191,6 +191,9 @@ ZIG_EXTERN_C struct ZigLLVMDISubprogram *ZigLLVMCreateFunction(struct ZigLLVMDIB
|
||||
unsigned lineno, struct ZigLLVMDIType *fn_di_type, bool is_local_to_unit, bool is_definition,
|
||||
unsigned scope_line, unsigned flags, bool is_optimized, struct ZigLLVMDISubprogram *decl_subprogram);
|
||||
|
||||
ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMDIBuilderCreateVectorType(struct ZigLLVMDIBuilder *dibuilder,
|
||||
uint64_t Size, uint32_t AlignInBits, struct ZigLLVMDIType *Ty);
|
||||
|
||||
ZIG_EXTERN_C void ZigLLVMFnSetSubprogram(LLVMValueRef fn, struct ZigLLVMDISubprogram *subprogram);
|
||||
|
||||
ZIG_EXTERN_C void ZigLLVMDIBuilderFinalize(struct ZigLLVMDIBuilder *dibuilder);
|
||||
|
@ -508,6 +508,7 @@ pub fn autoHash(key: var, comptime rng: *std.rand.Random, comptime HashInt: type
|
||||
|
||||
builtin.TypeId.Optional => @compileError("TODO auto hash for optionals"),
|
||||
builtin.TypeId.Array => @compileError("TODO auto hash for arrays"),
|
||||
builtin.TypeId.Vector => @compileError("TODO auto hash for vectors"),
|
||||
builtin.TypeId.Struct => @compileError("TODO auto hash for structs"),
|
||||
builtin.TypeId.Union => @compileError("TODO auto hash for unions"),
|
||||
builtin.TypeId.ErrorUnion => @compileError("TODO auto hash for unions"),
|
||||
@ -555,5 +556,6 @@ pub fn autoEql(a: var, b: @typeOf(a)) bool {
|
||||
builtin.TypeId.Struct => @compileError("TODO auto eql for structs"),
|
||||
builtin.TypeId.Union => @compileError("TODO auto eql for unions"),
|
||||
builtin.TypeId.ErrorUnion => @compileError("TODO auto eql for unions"),
|
||||
builtin.TypeId.Vector => @compileError("TODO auto eql for vectors"),
|
||||
}
|
||||
}
|
||||
|
@ -171,11 +171,11 @@ fn testUnion() void {
|
||||
assertOrPanic(TypeId(typeinfo_info) == TypeId.Union);
|
||||
assertOrPanic(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto);
|
||||
assertOrPanic(typeinfo_info.Union.tag_type.? == TypeId);
|
||||
assertOrPanic(typeinfo_info.Union.fields.len == 24);
|
||||
assertOrPanic(typeinfo_info.Union.fields.len == 25);
|
||||
assertOrPanic(typeinfo_info.Union.fields[4].enum_field != null);
|
||||
assertOrPanic(typeinfo_info.Union.fields[4].enum_field.?.value == 4);
|
||||
assertOrPanic(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int));
|
||||
assertOrPanic(typeinfo_info.Union.defs.len == 20);
|
||||
assertOrPanic(typeinfo_info.Union.defs.len == 21);
|
||||
|
||||
const TestNoTagUnion = union {
|
||||
Foo: void,
|
||||
@ -262,3 +262,15 @@ test "typeInfo with comptime parameter in struct fn def" {
|
||||
};
|
||||
comptime var info = @typeInfo(S);
|
||||
}
|
||||
|
||||
test "type info: vectors" {
|
||||
testVector();
|
||||
comptime testVector();
|
||||
}
|
||||
|
||||
fn testVector() void {
|
||||
const vec_info = @typeInfo(@Vector(4, i32));
|
||||
assertOrPanic(TypeId(vec_info) == TypeId.Vector);
|
||||
assertOrPanic(vec_info.Vector.len == 4);
|
||||
assertOrPanic(vec_info.Vector.child == i32);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user