mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 14:23:09 +00:00
Sema: use runtime_value instead of creating allocs
This commit is contained in:
parent
398a3aae40
commit
d03c47bf85
76
src/Sema.zig
76
src/Sema.zig
@ -1827,6 +1827,22 @@ fn resolveMaybeUndefValAllowVariables(
|
||||
block: *Block,
|
||||
src: LazySrcLoc,
|
||||
inst: Air.Inst.Ref,
|
||||
) CompileError!?Value {
|
||||
var make_runtime = false;
|
||||
if (try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(block, src, inst, &make_runtime)) |val| {
|
||||
if (make_runtime) return null;
|
||||
return val;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Returns all Value tags including `variable`, `undef` and `runtime_value`.
|
||||
fn resolveMaybeUndefValAllowVariablesMaybeRuntime(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
src: LazySrcLoc,
|
||||
inst: Air.Inst.Ref,
|
||||
make_runtime: *bool,
|
||||
) CompileError!?Value {
|
||||
// First section of indexes correspond to a set number of constant values.
|
||||
var i: usize = @enumToInt(inst);
|
||||
@ -1843,7 +1859,7 @@ fn resolveMaybeUndefValAllowVariables(
|
||||
.constant => {
|
||||
const ty_pl = sema.air_instructions.items(.data)[i].ty_pl;
|
||||
const val = sema.air_values.items[ty_pl.payload];
|
||||
if (val.tag() == .runtime_int) return null;
|
||||
if (val.tag() == .runtime_value) make_runtime.* = true;
|
||||
return val;
|
||||
},
|
||||
.const_ty => {
|
||||
@ -3896,6 +3912,7 @@ fn validateUnionInit(
|
||||
var first_block_index = block.instructions.items.len;
|
||||
var block_index = block.instructions.items.len - 1;
|
||||
var init_val: ?Value = null;
|
||||
var make_runtime = false;
|
||||
while (block_index > 0) : (block_index -= 1) {
|
||||
const store_inst = block.instructions.items[block_index];
|
||||
if (store_inst == field_ptr_air_inst) break;
|
||||
@ -3920,7 +3937,7 @@ fn validateUnionInit(
|
||||
} else {
|
||||
first_block_index = @min(first_block_index, block_index);
|
||||
}
|
||||
init_val = try sema.resolveMaybeUndefValAllowVariables(block, init_src, bin_op.rhs);
|
||||
init_val = try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(block, init_src, bin_op.rhs, &make_runtime);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -3933,10 +3950,11 @@ fn validateUnionInit(
|
||||
// instead a single `store` to the result ptr with a comptime union value.
|
||||
block.instructions.shrinkRetainingCapacity(first_block_index);
|
||||
|
||||
const union_val = try Value.Tag.@"union".create(sema.arena, .{
|
||||
var union_val = try Value.Tag.@"union".create(sema.arena, .{
|
||||
.tag = tag_val,
|
||||
.val = val,
|
||||
});
|
||||
if (make_runtime) union_val = try Value.Tag.runtime_value.create(sema.arena, union_val);
|
||||
const union_init = try sema.addConstant(union_ty, union_val);
|
||||
try sema.storePtr2(block, init_src, union_ptr, init_src, union_init, init_src, .store);
|
||||
return;
|
||||
@ -4054,6 +4072,7 @@ fn validateStructInit(
|
||||
|
||||
var struct_is_comptime = true;
|
||||
var first_block_index = block.instructions.items.len;
|
||||
var make_runtime = false;
|
||||
|
||||
const air_tags = sema.air_instructions.items(.tag);
|
||||
const air_datas = sema.air_instructions.items(.data);
|
||||
@ -4130,7 +4149,7 @@ fn validateStructInit(
|
||||
} else {
|
||||
first_block_index = @min(first_block_index, block_index);
|
||||
}
|
||||
if (try sema.resolveMaybeUndefValAllowVariables(block, field_src, bin_op.rhs)) |val| {
|
||||
if (try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(block, field_src, bin_op.rhs, &make_runtime)) |val| {
|
||||
field_values[i] = val;
|
||||
} else {
|
||||
struct_is_comptime = false;
|
||||
@ -4185,7 +4204,8 @@ fn validateStructInit(
|
||||
// instead a single `store` to the struct_ptr with a comptime struct value.
|
||||
|
||||
block.instructions.shrinkRetainingCapacity(first_block_index);
|
||||
const struct_val = try Value.Tag.aggregate.create(sema.arena, field_values);
|
||||
var struct_val = try Value.Tag.aggregate.create(sema.arena, field_values);
|
||||
if (make_runtime) struct_val = try Value.Tag.runtime_value.create(sema.arena, struct_val);
|
||||
const struct_init = try sema.addConstant(struct_ty, struct_val);
|
||||
try sema.storePtr2(block, init_src, struct_ptr, init_src, struct_init, init_src, .store);
|
||||
return;
|
||||
@ -4265,6 +4285,7 @@ fn zirValidateArrayInit(
|
||||
|
||||
var array_is_comptime = true;
|
||||
var first_block_index = block.instructions.items.len;
|
||||
var make_runtime = false;
|
||||
|
||||
// Collect the comptime element values in case the array literal ends up
|
||||
// being comptime-known.
|
||||
@ -4326,7 +4347,7 @@ fn zirValidateArrayInit(
|
||||
array_is_comptime = false;
|
||||
continue;
|
||||
}
|
||||
if (try sema.resolveMaybeUndefValAllowVariables(block, elem_src, bin_op.rhs)) |val| {
|
||||
if (try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(block, elem_src, bin_op.rhs, &make_runtime)) |val| {
|
||||
element_vals[i] = val;
|
||||
} else {
|
||||
array_is_comptime = false;
|
||||
@ -4352,7 +4373,7 @@ fn zirValidateArrayInit(
|
||||
array_is_comptime = false;
|
||||
continue;
|
||||
}
|
||||
if (try sema.resolveMaybeUndefValAllowVariables(block, elem_src, bin_op.rhs)) |val| {
|
||||
if (try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(block, elem_src, bin_op.rhs, &make_runtime)) |val| {
|
||||
element_vals[i] = val;
|
||||
} else {
|
||||
array_is_comptime = false;
|
||||
@ -4383,7 +4404,8 @@ fn zirValidateArrayInit(
|
||||
|
||||
block.instructions.shrinkRetainingCapacity(first_block_index);
|
||||
|
||||
const array_val = try Value.Tag.aggregate.create(sema.arena, element_vals);
|
||||
var array_val = try Value.Tag.aggregate.create(sema.arena, element_vals);
|
||||
if (make_runtime) array_val = try Value.Tag.runtime_value.create(sema.arena, array_val);
|
||||
const array_init = try sema.addConstant(array_ty, array_val);
|
||||
try sema.storePtr2(block, init_src, array_ptr, init_src, array_init, init_src, .store);
|
||||
}
|
||||
@ -6635,20 +6657,14 @@ fn analyzeInlineCallArg(
|
||||
.ty = param_ty,
|
||||
.val = arg_val,
|
||||
};
|
||||
} else if (((try sema.resolveMaybeUndefVal(arg_block, arg_src, casted_arg)) == null) or
|
||||
try sema.typeRequiresComptime(param_ty) or zir_tags[inst] == .param_comptime)
|
||||
{
|
||||
} else if (zir_tags[inst] == .param_comptime or try sema.typeRequiresComptime(param_ty)) {
|
||||
try sema.inst_map.putNoClobber(sema.gpa, inst, casted_arg);
|
||||
} else {
|
||||
} else if (try sema.resolveMaybeUndefVal(arg_block, arg_src, casted_arg)) |val| {
|
||||
// We have a comptime value but we need a runtime value to preserve inlining semantics,
|
||||
const ptr_type = try Type.ptr(sema.arena, sema.mod, .{
|
||||
.pointee_type = param_ty,
|
||||
.@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local),
|
||||
});
|
||||
const alloc = try arg_block.addTy(.alloc, ptr_type);
|
||||
_ = try arg_block.addBinOp(.store, alloc, casted_arg);
|
||||
const loaded = try arg_block.addTyOp(.load, param_ty, alloc);
|
||||
try sema.inst_map.putNoClobber(sema.gpa, inst, loaded);
|
||||
const wrapped = try sema.addConstant(param_ty, try Value.Tag.runtime_value.create(sema.arena, val));
|
||||
try sema.inst_map.putNoClobber(sema.gpa, inst, wrapped);
|
||||
} else {
|
||||
try sema.inst_map.putNoClobber(sema.gpa, inst, casted_arg);
|
||||
}
|
||||
|
||||
arg_i.* += 1;
|
||||
@ -6685,20 +6701,14 @@ fn analyzeInlineCallArg(
|
||||
.ty = sema.typeOf(uncasted_arg),
|
||||
.val = arg_val,
|
||||
};
|
||||
} else if ((try sema.resolveMaybeUndefVal(arg_block, arg_src, uncasted_arg)) == null or
|
||||
try sema.typeRequiresComptime(param_ty) or zir_tags[inst] == .param_anytype_comptime)
|
||||
{
|
||||
} else if (zir_tags[inst] == .param_anytype_comptime or try sema.typeRequiresComptime(param_ty)) {
|
||||
try sema.inst_map.putNoClobber(sema.gpa, inst, uncasted_arg);
|
||||
} else {
|
||||
} else if (try sema.resolveMaybeUndefVal(arg_block, arg_src, uncasted_arg)) |val| {
|
||||
// We have a comptime value but we need a runtime value to preserve inlining semantics,
|
||||
const ptr_type = try Type.ptr(sema.arena, sema.mod, .{
|
||||
.pointee_type = param_ty,
|
||||
.@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local),
|
||||
});
|
||||
const alloc = try arg_block.addTy(.alloc, ptr_type);
|
||||
_ = try arg_block.addBinOp(.store, alloc, uncasted_arg);
|
||||
const loaded = try arg_block.addTyOp(.load, param_ty, alloc);
|
||||
try sema.inst_map.putNoClobber(sema.gpa, inst, loaded);
|
||||
const wrapped = try sema.addConstant(param_ty, try Value.Tag.runtime_value.create(sema.arena, val));
|
||||
try sema.inst_map.putNoClobber(sema.gpa, inst, wrapped);
|
||||
} else {
|
||||
try sema.inst_map.putNoClobber(sema.gpa, inst, uncasted_arg);
|
||||
}
|
||||
|
||||
arg_i.* += 1;
|
||||
@ -14826,7 +14836,7 @@ fn zirBuiltinSrc(
|
||||
// fn_name: [:0]const u8,
|
||||
field_values[1] = func_name_val;
|
||||
// line: u32
|
||||
field_values[2] = try Value.Tag.runtime_int.create(sema.arena, extra.line + 1);
|
||||
field_values[2] = try Value.Tag.runtime_value.create(sema.arena, try Value.Tag.int_u64.create(sema.arena, extra.line + 1));
|
||||
// column: u32,
|
||||
field_values[3] = try Value.Tag.int_u64.create(sema.arena, extra.column + 1);
|
||||
|
||||
|
||||
@ -477,6 +477,6 @@ pub fn print(
|
||||
},
|
||||
.generic_poison_type => return writer.writeAll("(generic poison type)"),
|
||||
.generic_poison => return writer.writeAll("(generic poison)"),
|
||||
.runtime_int => return writer.writeAll("[runtime value]"),
|
||||
.runtime_value => return writer.writeAll("[runtime value]"),
|
||||
};
|
||||
}
|
||||
|
||||
@ -5401,7 +5401,11 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
|
||||
}
|
||||
}
|
||||
|
||||
fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
|
||||
fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {
|
||||
var typed_value = arg_tv;
|
||||
if (typed_value.val.castTag(.runtime_value)) |rt| {
|
||||
typed_value.val = rt.data;
|
||||
}
|
||||
log.debug("genTypedValue: ty = {}, val = {}", .{ typed_value.ty.fmtDebug(), typed_value.val.fmtDebug() });
|
||||
if (typed_value.val.isUndef())
|
||||
return MCValue{ .undef = {} };
|
||||
|
||||
@ -6047,7 +6047,11 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
|
||||
}
|
||||
}
|
||||
|
||||
fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
|
||||
fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {
|
||||
var typed_value = arg_tv;
|
||||
if (typed_value.val.castTag(.runtime_value)) |rt| {
|
||||
typed_value.val = rt.data;
|
||||
}
|
||||
log.debug("genTypedValue: ty = {}, val = {}", .{ typed_value.ty.fmtDebug(), typed_value.val.fmtDebug() });
|
||||
if (typed_value.val.isUndef())
|
||||
return MCValue{ .undef = {} };
|
||||
|
||||
@ -2582,7 +2582,11 @@ fn toTwosComplement(value: anytype, bits: u7) std.meta.Int(.unsigned, @typeInfo(
|
||||
return @intCast(WantedT, result);
|
||||
}
|
||||
|
||||
fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {
|
||||
fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
|
||||
var val = arg_val;
|
||||
if (val.castTag(.runtime_value)) |rt| {
|
||||
val = rt.data;
|
||||
}
|
||||
if (val.isUndefDeep()) return func.emitUndefined(ty);
|
||||
if (val.castTag(.decl_ref)) |decl_ref| {
|
||||
const decl_index = decl_ref.data;
|
||||
|
||||
@ -6960,7 +6960,11 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
|
||||
}
|
||||
}
|
||||
|
||||
fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
|
||||
fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {
|
||||
var typed_value = arg_tv;
|
||||
if (typed_value.val.castTag(.runtime_value)) |rt| {
|
||||
typed_value.val = rt.data;
|
||||
}
|
||||
log.debug("genTypedValue: ty = {}, val = {}", .{ typed_value.ty.fmtDebug(), typed_value.val.fmtDebug() });
|
||||
if (typed_value.val.isUndef())
|
||||
return MCValue{ .undef = {} };
|
||||
|
||||
@ -149,7 +149,7 @@ fn writeFloat(comptime F: type, f: F, target: Target, endian: std.builtin.Endian
|
||||
pub fn generateSymbol(
|
||||
bin_file: *link.File,
|
||||
src_loc: Module.SrcLoc,
|
||||
typed_value: TypedValue,
|
||||
arg_tv: TypedValue,
|
||||
code: *std.ArrayList(u8),
|
||||
debug_output: DebugInfoOutput,
|
||||
reloc_info: RelocInfo,
|
||||
@ -157,6 +157,11 @@ pub fn generateSymbol(
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
var typed_value = arg_tv;
|
||||
if (arg_tv.val.castTag(.runtime_value)) |rt| {
|
||||
typed_value.val = rt.data;
|
||||
}
|
||||
|
||||
const target = bin_file.options.target;
|
||||
const endian = target.cpu.arch.endian();
|
||||
|
||||
|
||||
@ -555,9 +555,13 @@ pub const DeclGen = struct {
|
||||
dg: *DeclGen,
|
||||
writer: anytype,
|
||||
ty: Type,
|
||||
val: Value,
|
||||
arg_val: Value,
|
||||
location: ValueRenderLocation,
|
||||
) error{ OutOfMemory, AnalysisFail }!void {
|
||||
var val = arg_val;
|
||||
if (val.castTag(.runtime_value)) |rt| {
|
||||
val = rt.data;
|
||||
}
|
||||
const target = dg.module.getTarget();
|
||||
if (val.isUndefDeep()) {
|
||||
switch (ty.zigTypeTag()) {
|
||||
|
||||
@ -3187,7 +3187,11 @@ pub const DeclGen = struct {
|
||||
return llvm_elem_ty;
|
||||
}
|
||||
|
||||
fn lowerValue(dg: *DeclGen, tv: TypedValue) Error!*llvm.Value {
|
||||
fn lowerValue(dg: *DeclGen, arg_tv: TypedValue) Error!*llvm.Value {
|
||||
var tv = arg_tv;
|
||||
if (tv.val.castTag(.runtime_value)) |rt| {
|
||||
tv.val = rt.data;
|
||||
}
|
||||
if (tv.val.isUndef()) {
|
||||
const llvm_type = try dg.lowerType(tv.ty);
|
||||
return llvm_type.getUndef();
|
||||
|
||||
@ -111,10 +111,12 @@ pub const Value = extern union {
|
||||
int_i64,
|
||||
int_big_positive,
|
||||
int_big_negative,
|
||||
runtime_int,
|
||||
function,
|
||||
extern_fn,
|
||||
variable,
|
||||
/// A wrapper for values which are comptime-known but should
|
||||
/// semantically be runtime-known.
|
||||
runtime_value,
|
||||
/// Represents a pointer to a Decl.
|
||||
/// When machine codegen backend sees this, it must set the Decl's `alive` field to true.
|
||||
decl_ref,
|
||||
@ -282,6 +284,7 @@ pub const Value = extern union {
|
||||
.eu_payload,
|
||||
.opt_payload,
|
||||
.empty_array_sentinel,
|
||||
.runtime_value,
|
||||
=> Payload.SubValue,
|
||||
|
||||
.eu_payload_ptr,
|
||||
@ -305,7 +308,6 @@ pub const Value = extern union {
|
||||
.int_type => Payload.IntType,
|
||||
.int_u64 => Payload.U64,
|
||||
.int_i64 => Payload.I64,
|
||||
.runtime_int => Payload.U64,
|
||||
.function => Payload.Function,
|
||||
.variable => Payload.Variable,
|
||||
.decl_ref_mut => Payload.DeclRefMut,
|
||||
@ -485,7 +487,6 @@ pub const Value = extern union {
|
||||
},
|
||||
.int_type => return self.copyPayloadShallow(arena, Payload.IntType),
|
||||
.int_u64 => return self.copyPayloadShallow(arena, Payload.U64),
|
||||
.runtime_int => return self.copyPayloadShallow(arena, Payload.U64),
|
||||
.int_i64 => return self.copyPayloadShallow(arena, Payload.I64),
|
||||
.int_big_positive, .int_big_negative => {
|
||||
const old_payload = self.cast(Payload.BigInt).?;
|
||||
@ -567,6 +568,7 @@ pub const Value = extern union {
|
||||
.eu_payload,
|
||||
.opt_payload,
|
||||
.empty_array_sentinel,
|
||||
.runtime_value,
|
||||
=> {
|
||||
const payload = self.cast(Payload.SubValue).?;
|
||||
const new_payload = try arena.create(Payload.SubValue);
|
||||
@ -765,7 +767,7 @@ pub const Value = extern union {
|
||||
.int_i64 => return std.fmt.formatIntValue(val.castTag(.int_i64).?.data, "", options, out_stream),
|
||||
.int_big_positive => return out_stream.print("{}", .{val.castTag(.int_big_positive).?.asBigInt()}),
|
||||
.int_big_negative => return out_stream.print("{}", .{val.castTag(.int_big_negative).?.asBigInt()}),
|
||||
.runtime_int => return out_stream.writeAll("[runtime value]"),
|
||||
.runtime_value => return out_stream.writeAll("[runtime value]"),
|
||||
.function => return out_stream.print("(function decl={d})", .{val.castTag(.function).?.data.owner_decl}),
|
||||
.extern_fn => return out_stream.writeAll("(extern function)"),
|
||||
.variable => return out_stream.writeAll("(variable)"),
|
||||
@ -1081,8 +1083,6 @@ pub const Value = extern union {
|
||||
.int_big_positive => return val.castTag(.int_big_positive).?.asBigInt(),
|
||||
.int_big_negative => return val.castTag(.int_big_negative).?.asBigInt(),
|
||||
|
||||
.runtime_int => return BigIntMutable.init(&space.limbs, val.castTag(.runtime_int).?.data).toConst(),
|
||||
|
||||
.undef => unreachable,
|
||||
|
||||
.lazy_align => {
|
||||
@ -1138,8 +1138,6 @@ pub const Value = extern union {
|
||||
.int_big_positive => return val.castTag(.int_big_positive).?.asBigInt().to(u64) catch null,
|
||||
.int_big_negative => return val.castTag(.int_big_negative).?.asBigInt().to(u64) catch null,
|
||||
|
||||
.runtime_int => return val.castTag(.runtime_int).?.data,
|
||||
|
||||
.undef => unreachable,
|
||||
|
||||
.lazy_align => {
|
||||
@ -2357,6 +2355,8 @@ pub const Value = extern union {
|
||||
const zig_ty_tag = ty.zigTypeTag();
|
||||
std.hash.autoHash(hasher, zig_ty_tag);
|
||||
if (val.isUndef()) return;
|
||||
// The value is runtime-known and shouldn't affect the hash.
|
||||
if (val.tag() == .runtime_value) return;
|
||||
|
||||
switch (zig_ty_tag) {
|
||||
.BoundFn => unreachable, // TODO remove this from the language
|
||||
@ -2632,9 +2632,6 @@ pub const Value = extern union {
|
||||
.lazy_size,
|
||||
=> return hashInt(ptr_val, hasher, target),
|
||||
|
||||
// The value is runtime-known and shouldn't affect the hash.
|
||||
.runtime_int => {},
|
||||
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ inline fn setLimits(min: ?u32, max: ?u32) !void {
|
||||
test {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
|
||||
var x: u32 = 42;
|
||||
try setLimits(x, null);
|
||||
|
||||
@ -1135,3 +1135,40 @@ test "array of vectors is copied" {
|
||||
points2[0..points.len].* = points;
|
||||
try std.testing.expectEqual(points2[6], Vec3{ -345, -311, 381 });
|
||||
}
|
||||
|
||||
test "byte vector initialized in inline function" {
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
|
||||
const S = struct {
|
||||
inline fn boolx4(e0: bool, e1: bool, e2: bool, e3: bool) @Vector(4, bool) {
|
||||
return .{ e0, e1, e2, e3 };
|
||||
}
|
||||
|
||||
fn all(vb: @Vector(4, bool)) bool {
|
||||
return @reduce(.And, vb);
|
||||
}
|
||||
};
|
||||
|
||||
try expect(S.all(S.boolx4(true, true, true, true)));
|
||||
}
|
||||
|
||||
test "byte vector initialized in inline function" {
|
||||
// TODO https://github.com/ziglang/zig/issues/13279
|
||||
if (true) return error.SkipZigTest;
|
||||
|
||||
const S = struct {
|
||||
fn boolx4(e0: bool, e1: bool, e2: bool, e3: bool) @Vector(4, bool) {
|
||||
return .{ e0, e1, e2, e3 };
|
||||
}
|
||||
|
||||
fn all(vb: @Vector(4, bool)) bool {
|
||||
return @reduce(.And, vb);
|
||||
}
|
||||
};
|
||||
|
||||
try expect(S.all(S.boolx4(true, true, true, true)));
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user