authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-11 13:48:28-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-03-11 13:48:28-05:00
log4c1cc4d8d91af459e5ac1e20b744c7dc9b5b8da3
tree8ee7c3b7f2b4c66e9ed8599b9c5164b78d1cc43c
parent5fbae9cd6fe7a53d85ad6dd20cab75f7b835f0ad
parent03b8206f27485f871fc489f884ffbc276d61877c
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11120 from Vexu/stage2

Stage2: make std.rand tests pass

16 files changed, 447 insertions(+), 44 deletions(-)

lib/std/rand.zig+5-1
...@@ -7,6 +7,7 @@...@@ -7,6 +7,7 @@
7//! TODO(tiehuis): Benchmark these against other reference implementations.7//! TODO(tiehuis): Benchmark these against other reference implementations.
88
9const std = @import("std.zig");9const std = @import("std.zig");
10const builtin = @import("builtin");
10const assert = std.debug.assert;11const assert = std.debug.assert;
11const expect = std.testing.expect;12const expect = std.testing.expect;
12const expectEqual = std.testing.expectEqual;13const expectEqual = std.testing.expectEqual;
...@@ -30,7 +31,10 @@ pub const Sfc64 = @import("rand/Sfc64.zig");...@@ -30,7 +31,10 @@ pub const Sfc64 = @import("rand/Sfc64.zig");
3031
31pub const Random = struct {32pub const Random = struct {
32 ptr: *anyopaque,33 ptr: *anyopaque,
33 fillFn: fn (ptr: *anyopaque, buf: []u8) void,34 fillFn: if (builtin.zig_backend == .stage1)
35 fn (ptr: *anyopaque, buf: []u8) void
36 else
37 *const fn (ptr: *anyopaque, buf: []u8) void,
3438
35 pub fn init(pointer: anytype, comptime fillFn: fn (ptr: @TypeOf(pointer), buf: []u8) void) Random {39 pub fn init(pointer: anytype, comptime fillFn: fn (ptr: @TypeOf(pointer), buf: []u8) void) Random {
36 const Ptr = @TypeOf(pointer);40 const Ptr = @TypeOf(pointer);
src/Air.zig+12
...@@ -520,6 +520,9 @@ pub const Inst = struct {...@@ -520,6 +520,9 @@ pub const Inst = struct {
520 /// equal to the scalar value.520 /// equal to the scalar value.
521 /// Uses the `ty_op` field.521 /// Uses the `ty_op` field.
522 splat,522 splat,
523 /// Constructs a vector by selecting elements from `a` and `b` based on `mask`.
524 /// Uses the `ty_pl` field with payload `Shuffle`.
525 shuffle,
523526
524 /// Given dest ptr, value, and len, set all elements at dest to value.527 /// Given dest ptr, value, and len, set all elements at dest to value.
525 /// Result type is always void.528 /// Result type is always void.
...@@ -740,6 +743,14 @@ pub const FieldParentPtr = struct {...@@ -740,6 +743,14 @@ pub const FieldParentPtr = struct {
740 field_index: u32,743 field_index: u32,
741};744};
742745
746pub const Shuffle = struct {
747 a: Inst.Ref,
748 b: Inst.Ref,
749 // index to air_values
750 mask: u32,
751 mask_len: u32,
752};
753
743/// Trailing:754/// Trailing:
744/// 0. `Inst.Ref` for every outputs_len755/// 0. `Inst.Ref` for every outputs_len
745/// 1. `Inst.Ref` for every inputs_len756/// 1. `Inst.Ref` for every inputs_len
...@@ -897,6 +908,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -897,6 +908,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
897 .cmpxchg_weak,908 .cmpxchg_weak,
898 .cmpxchg_strong,909 .cmpxchg_strong,
899 .slice,910 .slice,
911 .shuffle,
900 .aggregate_init,912 .aggregate_init,
901 .union_init,913 .union_init,
902 .field_parent_ptr,914 .field_parent_ptr,
src/Liveness.zig+4
...@@ -422,6 +422,10 @@ fn analyzeInst(...@@ -422,6 +422,10 @@ fn analyzeInst(
422 }422 }
423 return extra_tombs.finish();423 return extra_tombs.finish();
424 },424 },
425 .shuffle => {
426 const extra = a.air.extraData(Air.Shuffle, inst_datas[inst].ty_pl.payload).data;
427 return trackOperands(a, new_set, inst, main_tomb, .{ extra.a, extra.b, .none });
428 },
425 .aggregate_init => {429 .aggregate_init => {
426 const ty_pl = inst_datas[inst].ty_pl;430 const ty_pl = inst_datas[inst].ty_pl;
427 const aggregate_ty = a.air.getRefType(ty_pl.ty);431 const aggregate_ty = a.air.getRefType(ty_pl.ty);
src/Sema.zig+228-19
...@@ -4618,7 +4618,7 @@ fn analyzeCall(...@@ -4618,7 +4618,7 @@ fn analyzeCall(
4618 },4618 },
4619 else => {},4619 else => {},
4620 }4620 }
4621 should_memoize = should_memoize and !arg_val.isComptimeMutablePtr();4621 should_memoize = should_memoize and !arg_val.canMutateComptimeVarState();
4622 memoized_call_key.args[arg_i] = .{4622 memoized_call_key.args[arg_i] = .{
4623 .ty = param_ty,4623 .ty = param_ty,
4624 .val = arg_val,4624 .val = arg_val,
...@@ -4644,7 +4644,7 @@ fn analyzeCall(...@@ -4644,7 +4644,7 @@ fn analyzeCall(
4644 },4644 },
4645 else => {},4645 else => {},
4646 }4646 }
4647 should_memoize = should_memoize and !arg_val.isComptimeMutablePtr();4647 should_memoize = should_memoize and !arg_val.canMutateComptimeVarState();
4648 memoized_call_key.args[arg_i] = .{4648 memoized_call_key.args[arg_i] = .{
4649 .ty = sema.typeOf(uncasted_arg),4649 .ty = sema.typeOf(uncasted_arg),
4650 .val = arg_val,4650 .val = arg_val,
...@@ -5923,6 +5923,10 @@ fn funcCommon(...@@ -5923,6 +5923,10 @@ fn funcCommon(
5923 break :ret_ty ret_ty;5923 break :ret_ty ret_ty;
5924 } else |err| break :err err;5924 } else |err| break :err err;
5925 } else |err| break :err err;5925 } else |err| break :err err;
5926 // Check for generic params.
5927 for (block.params.items) |param| {
5928 if (param.ty.tag() == .generic_poison) is_generic = true;
5929 }
5926 };5930 };
5927 switch (err) {5931 switch (err) {
5928 error.GenericPoison => {5932 error.GenericPoison => {
...@@ -6111,6 +6115,13 @@ fn zirParam(...@@ -6111,6 +6115,13 @@ fn zirParam(
61116115
6112 if (sema.resolveBody(block, body, inst)) |param_ty_inst| {6116 if (sema.resolveBody(block, body, inst)) |param_ty_inst| {
6113 if (sema.analyzeAsType(block, src, param_ty_inst)) |param_ty| {6117 if (sema.analyzeAsType(block, src, param_ty_inst)) |param_ty| {
6118 if (param_ty.zigTypeTag() == .Fn and param_ty.fnInfo().is_generic) {
6119 // zirFunc will not emit error.GenericPoison to build a
6120 // partial type for generic functions but we still need to
6121 // detect if a function parameter is a generic function
6122 // to force the parent function to also be generic.
6123 break :err error.GenericPoison;
6124 }
6114 break :param_ty param_ty;6125 break :param_ty param_ty;
6115 } else |err| break :err err;6126 } else |err| break :err err;
6116 } else |err| break :err err;6127 } else |err| break :err err;
...@@ -8048,7 +8059,6 @@ fn zirBitwise(...@@ -8048,7 +8059,6 @@ fn zirBitwise(
8048 rhs_ty.arrayLen(),8059 rhs_ty.arrayLen(),
8049 });8060 });
8050 }8061 }
8051 return sema.fail(block, src, "TODO implement support for vectors in zirBitwise", .{});
8052 } else if (lhs_ty.zigTypeTag() == .Vector or rhs_ty.zigTypeTag() == .Vector) {8062 } else if (lhs_ty.zigTypeTag() == .Vector or rhs_ty.zigTypeTag() == .Vector) {
8053 return sema.fail(block, src, "mixed scalar and vector operands to binary expression: '{}' and '{}'", .{8063 return sema.fail(block, src, "mixed scalar and vector operands to binary expression: '{}' and '{}'", .{
8054 lhs_ty,8064 lhs_ty,
...@@ -8064,6 +8074,9 @@ fn zirBitwise(...@@ -8064,6 +8074,9 @@ fn zirBitwise(
80648074
8065 if (try sema.resolveMaybeUndefVal(block, lhs_src, casted_lhs)) |lhs_val| {8075 if (try sema.resolveMaybeUndefVal(block, lhs_src, casted_lhs)) |lhs_val| {
8066 if (try sema.resolveMaybeUndefVal(block, rhs_src, casted_rhs)) |rhs_val| {8076 if (try sema.resolveMaybeUndefVal(block, rhs_src, casted_rhs)) |rhs_val| {
8077 if (resolved_type.zigTypeTag() == .Vector) {
8078 return sema.fail(block, src, "TODO implement zirBitwise for vectors at comptime", .{});
8079 }
8067 const result_val = switch (air_tag) {8080 const result_val = switch (air_tag) {
8068 .bit_and => try lhs_val.bitwiseAnd(rhs_val, sema.arena),8081 .bit_and => try lhs_val.bitwiseAnd(rhs_val, sema.arena),
8069 .bit_or => try lhs_val.bitwiseOr(rhs_val, sema.arena),8082 .bit_or => try lhs_val.bitwiseOr(rhs_val, sema.arena),
...@@ -10965,6 +10978,7 @@ fn zirTypeofBuiltin(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr...@@ -10965,6 +10978,7 @@ fn zirTypeofBuiltin(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
1096510978
10966 const operand = try sema.resolveBody(&child_block, body, inst);10979 const operand = try sema.resolveBody(&child_block, body, inst);
10967 const operand_ty = sema.typeOf(operand);10980 const operand_ty = sema.typeOf(operand);
10981 if (operand_ty.tag() == .generic_poison) return error.GenericPoison;
10968 return sema.addType(operand_ty);10982 return sema.addType(operand_ty);
10969}10983}
1097010984
...@@ -10973,19 +10987,21 @@ fn zirTypeofLog2IntType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil...@@ -10973,19 +10987,21 @@ fn zirTypeofLog2IntType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil
10973 const src = inst_data.src();10987 const src = inst_data.src();
10974 const operand = sema.resolveInst(inst_data.operand);10988 const operand = sema.resolveInst(inst_data.operand);
10975 const operand_ty = sema.typeOf(operand);10989 const operand_ty = sema.typeOf(operand);
10976 return sema.log2IntType(block, operand_ty, src);10990 const res_ty = try sema.log2IntType(block, operand_ty, src);
10991 return sema.addType(res_ty);
10977}10992}
1097810993
10979fn zirLog2IntType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {10994fn zirLog2IntType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
10980 const inst_data = sema.code.instructions.items(.data)[inst].un_node;10995 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
10981 const src = inst_data.src();10996 const src = inst_data.src();
10982 const operand = try sema.resolveType(block, src, inst_data.operand);10997 const operand = try sema.resolveType(block, src, inst_data.operand);
10983 return sema.log2IntType(block, operand, src);10998 const res_ty = try sema.log2IntType(block, operand, src);
10999 return sema.addType(res_ty);
10984}11000}
1098511001
10986fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) CompileError!Air.Inst.Ref {11002fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) CompileError!Type {
10987 switch (operand.zigTypeTag()) {11003 switch (operand.zigTypeTag()) {
10988 .ComptimeInt => return Air.Inst.Ref.comptime_int_type,11004 .ComptimeInt => return Type.@"comptime_int",
10989 .Int => {11005 .Int => {
10990 const bits = operand.bitSize(sema.mod.getTarget());11006 const bits = operand.bitSize(sema.mod.getTarget());
10991 const count = if (bits == 0)11007 const count = if (bits == 0)
...@@ -10998,16 +11014,24 @@ fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) Compi...@@ -10998,16 +11014,24 @@ fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) Compi
10998 }11014 }
10999 break :blk count;11015 break :blk count;
11000 };11016 };
11001 const res = try Module.makeIntType(sema.arena, .unsigned, count);11017 return Module.makeIntType(sema.arena, .unsigned, count);
11002 return sema.addType(res);
11003 },11018 },
11004 else => return sema.fail(11019 .Vector => {
11005 block,11020 const elem_ty = operand.elemType2();
11006 src,11021 const log2_elem_ty = try sema.log2IntType(block, elem_ty, src);
11007 "bit shifting operation expected integer type, found '{}'",11022 return Type.Tag.vector.create(sema.arena, .{
11008 .{operand},11023 .len = operand.arrayLen(),
11009 ),11024 .elem_type = log2_elem_ty,
11025 });
11026 },
11027 else => {},
11010 }11028 }
11029 return sema.fail(
11030 block,
11031 src,
11032 "bit shifting operation expected integer type, found '{}'",
11033 .{operand},
11034 );
11011}11035}
1101211036
11013fn zirTypeofPeer(11037fn zirTypeofPeer(
...@@ -11044,6 +11068,7 @@ fn zirTypeofPeer(...@@ -11044,6 +11068,7 @@ fn zirTypeofPeer(
1104411068
11045 for (args) |arg_ref, i| {11069 for (args) |arg_ref, i| {
11046 inst_list[i] = sema.resolveInst(arg_ref);11070 inst_list[i] = sema.resolveInst(arg_ref);
11071 if (sema.typeOf(inst_list[i]).tag() == .generic_poison) return error.GenericPoison;
11047 }11072 }
1104811073
11049 const result_type = try sema.resolvePeerTypes(block, src, inst_list, .{ .typeof_builtin_call_node_offset = extra.data.src_node });11074 const result_type = try sema.resolvePeerTypes(block, src, inst_list, .{ .typeof_builtin_call_node_offset = extra.data.src_node });
...@@ -13427,8 +13452,193 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -13427,8 +13452,193 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
1342713452
13428fn zirShuffle(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {13453fn zirShuffle(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
13429 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;13454 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
13430 const src = inst_data.src();13455 const extra = sema.code.extraData(Zir.Inst.Shuffle, inst_data.payload_index).data;
13431 return sema.fail(block, src, "TODO: Sema.zirShuffle", .{});13456 const elem_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
13457 const mask_src: LazySrcLoc = .{ .node_offset_builtin_call_arg3 = inst_data.src_node };
13458
13459 const elem_ty = try sema.resolveType(block, elem_ty_src, extra.elem_type);
13460 try sema.checkVectorElemType(block, elem_ty_src, elem_ty);
13461 var a = sema.resolveInst(extra.a);
13462 var b = sema.resolveInst(extra.b);
13463 var mask = sema.resolveInst(extra.mask);
13464 var mask_ty = sema.typeOf(mask);
13465
13466 const mask_len = switch (sema.typeOf(mask).zigTypeTag()) {
13467 .Array, .Vector => sema.typeOf(mask).arrayLen(),
13468 else => return sema.fail(block, mask_src, "expected vector or array, found {}", .{sema.typeOf(mask)}),
13469 };
13470 mask_ty = try Type.Tag.vector.create(sema.arena, .{
13471 .len = mask_len,
13472 .elem_type = Type.@"i32",
13473 });
13474 mask = try sema.coerce(block, mask_ty, mask, mask_src);
13475 const mask_val = try sema.resolveConstMaybeUndefVal(block, mask_src, mask);
13476 return sema.analyzeShuffle(block, inst_data.src_node, elem_ty, a, b, mask_val, @intCast(u32, mask_len));
13477}
13478
13479fn analyzeShuffle(
13480 sema: *Sema,
13481 block: *Block,
13482 src_node: i32,
13483 elem_ty: Type,
13484 a_arg: Air.Inst.Ref,
13485 b_arg: Air.Inst.Ref,
13486 mask: Value,
13487 mask_len: u32,
13488) CompileError!Air.Inst.Ref {
13489 const a_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = src_node };
13490 const b_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = src_node };
13491 const mask_src: LazySrcLoc = .{ .node_offset_builtin_call_arg3 = src_node };
13492 var a = a_arg;
13493 var b = b_arg;
13494
13495 const res_ty = try Type.Tag.vector.create(sema.arena, .{
13496 .len = mask_len,
13497 .elem_type = elem_ty,
13498 });
13499
13500 var maybe_a_len = switch (sema.typeOf(a).zigTypeTag()) {
13501 .Array, .Vector => sema.typeOf(a).arrayLen(),
13502 .Undefined => null,
13503 else => return sema.fail(block, a_src, "expected vector or array with element type {}, found {}", .{
13504 elem_ty,
13505 sema.typeOf(a),
13506 }),
13507 };
13508 var maybe_b_len = switch (sema.typeOf(b).zigTypeTag()) {
13509 .Array, .Vector => sema.typeOf(b).arrayLen(),
13510 .Undefined => null,
13511 else => return sema.fail(block, b_src, "expected vector or array with element type {}, found {}", .{
13512 elem_ty,
13513 sema.typeOf(b),
13514 }),
13515 };
13516 if (maybe_a_len == null and maybe_b_len == null) {
13517 return sema.addConstUndef(res_ty);
13518 }
13519 const a_len = maybe_a_len orelse maybe_b_len.?;
13520 const b_len = maybe_b_len orelse a_len;
13521
13522 const a_ty = try Type.Tag.vector.create(sema.arena, .{
13523 .len = a_len,
13524 .elem_type = elem_ty,
13525 });
13526 const b_ty = try Type.Tag.vector.create(sema.arena, .{
13527 .len = b_len,
13528 .elem_type = elem_ty,
13529 });
13530
13531 if (maybe_a_len == null) a = try sema.addConstUndef(a_ty);
13532 if (maybe_b_len == null) b = try sema.addConstUndef(b_ty);
13533
13534 const operand_info = [2]std.meta.Tuple(&.{ u64, LazySrcLoc, Type }){
13535 .{ a_len, a_src, a_ty },
13536 .{ b_len, b_src, b_ty },
13537 };
13538
13539 var i: usize = 0;
13540 while (i < mask_len) : (i += 1) {
13541 var buf: Value.ElemValueBuffer = undefined;
13542 const elem = mask.elemValueBuffer(i, &buf);
13543 if (elem.isUndef()) continue;
13544 const int = elem.toSignedInt();
13545 var unsigned: u32 = undefined;
13546 var chosen: u32 = undefined;
13547 if (int >= 0) {
13548 unsigned = @intCast(u32, int);
13549 chosen = 0;
13550 } else {
13551 unsigned = @intCast(u32, ~int);
13552 chosen = 1;
13553 }
13554 if (unsigned >= operand_info[chosen][0]) {
13555 const msg = msg: {
13556 const msg = try sema.errMsg(block, mask_src, "mask index {d} has out-of-bounds selection", .{i});
13557 errdefer msg.destroy(sema.gpa);
13558
13559 try sema.errNote(block, operand_info[chosen][1], msg, "selected index {d} out of bounds of {}", .{
13560 unsigned,
13561 operand_info[chosen][2],
13562 });
13563
13564 if (chosen == 1) {
13565 try sema.errNote(block, b_src, msg, "selections from the second vector are specified with negative numbers", .{});
13566 }
13567
13568 break :msg msg;
13569 };
13570 return sema.failWithOwnedErrorMsg(block, msg);
13571 }
13572 }
13573
13574 if (try sema.resolveMaybeUndefVal(block, a_src, a)) |a_val| {
13575 if (try sema.resolveMaybeUndefVal(block, b_src, b)) |b_val| {
13576 const values = try sema.arena.alloc(Value, mask_len);
13577
13578 i = 0;
13579 while (i < mask_len) : (i += 1) {
13580 var buf: Value.ElemValueBuffer = undefined;
13581 const mask_elem_val = mask.elemValueBuffer(i, &buf);
13582 if (mask_elem_val.isUndef()) {
13583 values[i] = Value.undef;
13584 continue;
13585 }
13586 const int = mask_elem_val.toSignedInt();
13587 const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int);
13588 if (int >= 0) {
13589 values[i] = try a_val.elemValue(sema.arena, unsigned);
13590 } else {
13591 values[i] = try b_val.elemValue(sema.arena, unsigned);
13592 }
13593 }
13594 const res_val = try Value.Tag.array.create(sema.arena, values);
13595 return sema.addConstant(res_ty, res_val);
13596 }
13597 }
13598
13599 // All static analysis passed, and not comptime.
13600 // For runtime codegen, vectors a and b must be the same length. Here we
13601 // recursively @shuffle the smaller vector to append undefined elements
13602 // to it up to the length of the longer vector. This recursion terminates
13603 // in 1 call because these calls to analyzeShuffle guarantee a_len == b_len.
13604 if (a_len != b_len) {
13605 const min_len = std.math.min(a_len, b_len);
13606 const max_src = if (a_len > b_len) a_src else b_src;
13607 const max_len = try sema.usizeCast(block, max_src, std.math.max(a_len, b_len));
13608
13609 const expand_mask_values = try sema.arena.alloc(Value, max_len);
13610 i = 0;
13611 while (i < min_len) : (i += 1) {
13612 expand_mask_values[i] = try Value.Tag.int_u64.create(sema.arena, i);
13613 }
13614 while (i < max_len) : (i += 1) {
13615 expand_mask_values[i] = Value.negative_one;
13616 }
13617 const expand_mask = try Value.Tag.array.create(sema.arena, expand_mask_values);
13618
13619 if (a_len < b_len) {
13620 const undef = try sema.addConstUndef(a_ty);
13621 a = try sema.analyzeShuffle(block, src_node, elem_ty, a, undef, expand_mask, @intCast(u32, max_len));
13622 } else {
13623 const undef = try sema.addConstUndef(b_ty);
13624 b = try sema.analyzeShuffle(block, src_node, elem_ty, b, undef, expand_mask, @intCast(u32, max_len));
13625 }
13626 }
13627
13628 const mask_index = @intCast(u32, sema.air_values.items.len);
13629 try sema.air_values.append(sema.gpa, mask);
13630 return block.addInst(.{
13631 .tag = .shuffle,
13632 .data = .{ .ty_pl = .{
13633 .ty = try sema.addType(res_ty),
13634 .payload = try block.sema.addExtra(Air.Shuffle{
13635 .a = a,
13636 .b = b,
13637 .mask = mask_index,
13638 .mask_len = mask_len,
13639 }),
13640 } },
13641 });
13432}13642}
1343313643
13434fn zirSelect(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {13644fn zirSelect(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -15663,8 +15873,7 @@ fn elemPtr(...@@ -15663,8 +15873,7 @@ fn elemPtr(
15663 },15873 },
15664 }15874 }
15665 },15875 },
15666 .Array => return sema.elemPtrArray(block, array_ptr_src, array_ptr, elem_index, elem_index_src),15876 .Array, .Vector => return sema.elemPtrArray(block, array_ptr_src, array_ptr, elem_index, elem_index_src),
15667 .Vector => return sema.fail(block, src, "TODO implement Sema for elemPtr for vector", .{}),
15668 .Struct => {15877 .Struct => {
15669 // Tuple field access.15878 // Tuple field access.
15670 const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index);15879 const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index);
src/arch/aarch64/CodeGen.zig+7
...@@ -637,6 +637,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -637,6 +637,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
637 .tag_name => try self.airTagName(inst),637 .tag_name => try self.airTagName(inst),
638 .error_name => try self.airErrorName(inst),638 .error_name => try self.airErrorName(inst),
639 .splat => try self.airSplat(inst),639 .splat => try self.airSplat(inst),
640 .shuffle => try self.airShuffle(inst),
640 .aggregate_init => try self.airAggregateInit(inst),641 .aggregate_init => try self.airAggregateInit(inst),
641 .union_init => try self.airUnionInit(inst),642 .union_init => try self.airUnionInit(inst),
642 .prefetch => try self.airPrefetch(inst),643 .prefetch => try self.airPrefetch(inst),
...@@ -3633,6 +3634,12 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {...@@ -3633,6 +3634,12 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {
3633 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });3634 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3634}3635}
36353636
3637fn airShuffle(self: *Self, inst: Air.Inst.Index) !void {
3638 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3639 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airShuffle for {}", .{self.target.cpu.arch});
3640 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3641}
3642
3636fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {3643fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
3637 const vector_ty = self.air.typeOfIndex(inst);3644 const vector_ty = self.air.typeOfIndex(inst);
3638 const len = vector_ty.vectorLen();3645 const len = vector_ty.vectorLen();
src/arch/arm/CodeGen.zig+7
...@@ -636,6 +636,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -636,6 +636,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
636 .tag_name => try self.airTagName(inst),636 .tag_name => try self.airTagName(inst),
637 .error_name => try self.airErrorName(inst),637 .error_name => try self.airErrorName(inst),
638 .splat => try self.airSplat(inst),638 .splat => try self.airSplat(inst),
639 .shuffle => try self.airShuffle(inst),
639 .aggregate_init => try self.airAggregateInit(inst),640 .aggregate_init => try self.airAggregateInit(inst),
640 .union_init => try self.airUnionInit(inst),641 .union_init => try self.airUnionInit(inst),
641 .prefetch => try self.airPrefetch(inst),642 .prefetch => try self.airPrefetch(inst),
...@@ -4094,6 +4095,12 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {...@@ -4094,6 +4095,12 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {
4094 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });4095 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
4095}4096}
40964097
4098fn airShuffle(self: *Self, inst: Air.Inst.Index) !void {
4099 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
4100 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airShuffle for arm", .{});
4101 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
4102}
4103
4097fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {4104fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
4098 const vector_ty = self.air.typeOfIndex(inst);4105 const vector_ty = self.air.typeOfIndex(inst);
4099 const len = vector_ty.vectorLen();4106 const len = vector_ty.vectorLen();
src/arch/riscv64/CodeGen.zig+7
...@@ -603,6 +603,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -603,6 +603,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
603 .tag_name => try self.airTagName(inst),603 .tag_name => try self.airTagName(inst),
604 .error_name => try self.airErrorName(inst),604 .error_name => try self.airErrorName(inst),
605 .splat => try self.airSplat(inst),605 .splat => try self.airSplat(inst),
606 .shuffle => try self.airShuffle(inst),
606 .aggregate_init => try self.airAggregateInit(inst),607 .aggregate_init => try self.airAggregateInit(inst),
607 .union_init => try self.airUnionInit(inst),608 .union_init => try self.airUnionInit(inst),
608 .prefetch => try self.airPrefetch(inst),609 .prefetch => try self.airPrefetch(inst),
...@@ -2181,6 +2182,12 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {...@@ -2181,6 +2182,12 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {
2181 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });2182 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
2182}2183}
21832184
2185fn airShuffle(self: *Self, inst: Air.Inst.Index) !void {
2186 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2187 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airShuffle for riscv64", .{});
2188 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
2189}
2190
2184fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {2191fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
2185 const vector_ty = self.air.typeOfIndex(inst);2192 const vector_ty = self.air.typeOfIndex(inst);
2186 const len = vector_ty.vectorLen();2193 const len = vector_ty.vectorLen();
src/arch/wasm/CodeGen.zig+12
...@@ -1255,6 +1255,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1255,6 +1255,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1255 .ret_ptr => self.airRetPtr(inst),1255 .ret_ptr => self.airRetPtr(inst),
1256 .ret_load => self.airRetLoad(inst),1256 .ret_load => self.airRetLoad(inst),
1257 .splat => self.airSplat(inst),1257 .splat => self.airSplat(inst),
1258 .shuffle => self.airShuffle(inst),
1258 .aggregate_init => self.airAggregateInit(inst),1259 .aggregate_init => self.airAggregateInit(inst),
1259 .union_init => self.airUnionInit(inst),1260 .union_init => self.airUnionInit(inst),
1260 .prefetch => self.airPrefetch(inst),1261 .prefetch => self.airPrefetch(inst),
...@@ -2985,6 +2986,17 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2985,6 +2986,17 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2985 return self.fail("TODO: Implement wasm airSplat", .{});2986 return self.fail("TODO: Implement wasm airSplat", .{});
2986}2987}
29872988
2989fn airShuffle(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2990 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
2991
2992 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2993 const operand = try self.resolveInst(ty_op.operand);
2994
2995 _ = ty_op;
2996 _ = operand;
2997 return self.fail("TODO: Implement wasm airShuffle", .{});
2998}
2999
2988fn airAggregateInit(self: *Self, inst: Air.Inst.Index) InnerError!WValue {3000fn airAggregateInit(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2989 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };3001 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
29903002
src/arch/x86_64/CodeGen.zig+7
...@@ -720,6 +720,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -720,6 +720,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
720 .tag_name => try self.airTagName(inst),720 .tag_name => try self.airTagName(inst),
721 .error_name => try self.airErrorName(inst),721 .error_name => try self.airErrorName(inst),
722 .splat => try self.airSplat(inst),722 .splat => try self.airSplat(inst),
723 .shuffle => try self.airShuffle(inst),
723 .aggregate_init => try self.airAggregateInit(inst),724 .aggregate_init => try self.airAggregateInit(inst),
724 .union_init => try self.airUnionInit(inst),725 .union_init => try self.airUnionInit(inst),
725 .prefetch => try self.airPrefetch(inst),726 .prefetch => try self.airPrefetch(inst),
...@@ -5535,6 +5536,12 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {...@@ -5535,6 +5536,12 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {
5535 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });5536 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
5536}5537}
55375538
5539fn airShuffle(self: *Self, inst: Air.Inst.Index) !void {
5540 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
5541 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airShuffle for x86_64", .{});
5542 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
5543}
5544
5538fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {5545fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
5539 const vector_ty = self.air.typeOfIndex(inst);5546 const vector_ty = self.air.typeOfIndex(inst);
5540 const len = vector_ty.vectorLen();5547 const len = vector_ty.vectorLen();
src/codegen/c.zig+16
...@@ -1716,6 +1716,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -1716,6 +1716,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
1716 .tag_name => try airTagName(f, inst),1716 .tag_name => try airTagName(f, inst),
1717 .error_name => try airErrorName(f, inst),1717 .error_name => try airErrorName(f, inst),
1718 .splat => try airSplat(f, inst),1718 .splat => try airSplat(f, inst),
1719 .shuffle => try airShuffle(f, inst),
1719 .aggregate_init => try airAggregateInit(f, inst),1720 .aggregate_init => try airAggregateInit(f, inst),
1720 .union_init => try airUnionInit(f, inst),1721 .union_init => try airUnionInit(f, inst),
1721 .prefetch => try airPrefetch(f, inst),1722 .prefetch => try airPrefetch(f, inst),
...@@ -3557,6 +3558,21 @@ fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3557,6 +3558,21 @@ fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue {
3557 return f.fail("TODO: C backend: implement airSplat", .{});3558 return f.fail("TODO: C backend: implement airSplat", .{});
3558}3559}
35593560
3561fn airShuffle(f: *Function, inst: Air.Inst.Index) !CValue {
3562 if (f.liveness.isUnused(inst)) return CValue.none;
3563
3564 const inst_ty = f.air.typeOfIndex(inst);
3565 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
3566 const operand = try f.resolveInst(ty_op.operand);
3567 const writer = f.object.writer();
3568 const local = try f.allocLocal(inst_ty, .Const);
3569 try writer.writeAll(" = ");
3570
3571 _ = operand;
3572 _ = local;
3573 return f.fail("TODO: C backend: implement airShuffle", .{});
3574}
3575
3560fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {3576fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
3561 if (f.liveness.isUnused(inst)) return CValue.none;3577 if (f.liveness.isUnused(inst)) return CValue.none;
35623578
src/codegen/llvm.zig+38
...@@ -3204,6 +3204,7 @@ pub const FuncGen = struct {...@@ -3204,6 +3204,7 @@ pub const FuncGen = struct {
3204 .tag_name => try self.airTagName(inst),3204 .tag_name => try self.airTagName(inst),
3205 .error_name => try self.airErrorName(inst),3205 .error_name => try self.airErrorName(inst),
3206 .splat => try self.airSplat(inst),3206 .splat => try self.airSplat(inst),
3207 .shuffle => try self.airShuffle(inst),
3207 .aggregate_init => try self.airAggregateInit(inst),3208 .aggregate_init => try self.airAggregateInit(inst),
3208 .union_init => try self.airUnionInit(inst),3209 .union_init => try self.airUnionInit(inst),
3209 .prefetch => try self.airPrefetch(inst),3210 .prefetch => try self.airPrefetch(inst),
...@@ -5850,6 +5851,43 @@ pub const FuncGen = struct {...@@ -5850,6 +5851,43 @@ pub const FuncGen = struct {
5850 return self.builder.buildShuffleVector(op_vector, undef_vector, mask_llvm_ty.constNull(), "");5851 return self.builder.buildShuffleVector(op_vector, undef_vector, mask_llvm_ty.constNull(), "");
5851 }5852 }
58525853
5854 fn airShuffle(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
5855 if (self.liveness.isUnused(inst)) return null;
5856
5857 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
5858 const extra = self.air.extraData(Air.Shuffle, ty_pl.payload).data;
5859 const a = try self.resolveInst(extra.a);
5860 const b = try self.resolveInst(extra.b);
5861 const mask = self.air.values[extra.mask];
5862 const mask_len = extra.mask_len;
5863 const a_len = self.air.typeOf(extra.a).vectorLen();
5864
5865 // LLVM uses integers larger than the length of the first array to
5866 // index into the second array. This was deemed unnecessarily fragile
5867 // when changing code, so Zig uses negative numbers to index the
5868 // second vector. These start at -1 and go down, and are easiest to use
5869 // with the ~ operator. Here we convert between the two formats.
5870 const values = try self.gpa.alloc(*const llvm.Value, mask_len);
5871 defer self.gpa.free(values);
5872
5873 const llvm_i32 = self.context.intType(32);
5874
5875 for (values) |*val, i| {
5876 var buf: Value.ElemValueBuffer = undefined;
5877 const elem = mask.elemValueBuffer(i, &buf);
5878 if (elem.isUndef()) {
5879 val.* = llvm_i32.getUndef();
5880 } else {
5881 const int = elem.toSignedInt();
5882 const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int + a_len);
5883 val.* = llvm_i32.constInt(unsigned, .False);
5884 }
5885 }
5886
5887 const llvm_mask_value = llvm.constVector(values.ptr, mask_len);
5888 return self.builder.buildShuffleVector(a, b, llvm_mask_value, "");
5889 }
5890
5853 fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {5891 fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
5854 if (self.liveness.isUnused(inst)) return null;5892 if (self.liveness.isUnused(inst)) return null;
58555893
src/print_air.zig+11
...@@ -258,6 +258,7 @@ const Writer = struct {...@@ -258,6 +258,7 @@ const Writer = struct {
258 .wasm_memory_size => try w.writeWasmMemorySize(s, inst),258 .wasm_memory_size => try w.writeWasmMemorySize(s, inst),
259 .wasm_memory_grow => try w.writeWasmMemoryGrow(s, inst),259 .wasm_memory_grow => try w.writeWasmMemoryGrow(s, inst),
260 .mul_add => try w.writeMulAdd(s, inst),260 .mul_add => try w.writeMulAdd(s, inst),
261 .shuffle => try w.writeShuffle(s, inst),
261262
262 .add_with_overflow,263 .add_with_overflow,
263 .sub_with_overflow,264 .sub_with_overflow,
...@@ -375,6 +376,16 @@ const Writer = struct {...@@ -375,6 +376,16 @@ const Writer = struct {
375 try w.writeOperand(s, inst, 2, pl_op.operand);376 try w.writeOperand(s, inst, 2, pl_op.operand);
376 }377 }
377378
379 fn writeShuffle(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
380 const pl_op = w.air.instructions.items(.data)[inst].pl_op;
381 const extra = w.air.extraData(Air.Shuffle, pl_op.payload).data;
382
383 try w.writeOperand(s, inst, 0, extra.a);
384 try s.writeAll(", ");
385 try w.writeOperand(s, inst, 1, extra.b);
386 try s.print(", mask {d}, len {d}", .{ extra.mask, extra.mask_len });
387 }
388
378 fn writeFence(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {389 fn writeFence(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
379 const atomic_order = w.air.instructions.items(.data)[inst].fence;390 const atomic_order = w.air.instructions.items(.data)[inst].fence;
380391
src/value.zig+43
...@@ -1157,6 +1157,7 @@ pub const Value = extern union {...@@ -1157,6 +1157,7 @@ pub const Value = extern union {
1157 ) Allocator.Error!Value {1157 ) Allocator.Error!Value {
1158 switch (ty.zigTypeTag()) {1158 switch (ty.zigTypeTag()) {
1159 .Int => {1159 .Int => {
1160 if (buffer.len == 0) return Value.zero;
1160 const int_info = ty.intInfo(target);1161 const int_info = ty.intInfo(target);
1161 const endian = target.cpu.arch.endian();1162 const endian = target.cpu.arch.endian();
1162 const Limb = std.math.big.Limb;1163 const Limb = std.math.big.Limb;
...@@ -1819,7 +1820,22 @@ pub const Value = extern union {...@@ -1819,7 +1820,22 @@ pub const Value = extern union {
1819 }1820 }
18201821
1821 /// Asserts the value is comparable.1822 /// Asserts the value is comparable.
1823 /// For vectors this is only valid with op == .eq.
1822 pub fn compareWithZero(lhs: Value, op: std.math.CompareOperator) bool {1824 pub fn compareWithZero(lhs: Value, op: std.math.CompareOperator) bool {
1825 switch (lhs.tag()) {
1826 .repeated => {
1827 assert(op == .eq);
1828 return lhs.castTag(.repeated).?.data.compareWithZero(.eq);
1829 },
1830 .array => {
1831 assert(op == .eq);
1832 for (lhs.cast(Payload.Array).?.data) |elem_val| {
1833 if (!elem_val.compareWithZero(.eq)) return false;
1834 }
1835 return true;
1836 },
1837 else => {},
1838 }
1823 return orderAgainstZero(lhs).compare(op);1839 return orderAgainstZero(lhs).compare(op);
1824 }1840 }
18251841
...@@ -2170,6 +2186,33 @@ pub const Value = extern union {...@@ -2170,6 +2186,33 @@ pub const Value = extern union {
2170 };2186 };
2171 }2187 }
21722188
2189 pub fn canMutateComptimeVarState(val: Value) bool {
2190 if (val.isComptimeMutablePtr()) return true;
2191 switch (val.tag()) {
2192 .repeated => return val.castTag(.repeated).?.data.canMutateComptimeVarState(),
2193 .array => {
2194 const elems = val.cast(Payload.Array).?.data;
2195 for (elems) |elem| {
2196 if (elem.canMutateComptimeVarState()) return true;
2197 }
2198 return false;
2199 },
2200 .eu_payload => return val.castTag(.eu_payload).?.data.canMutateComptimeVarState(),
2201 .eu_payload_ptr => return val.castTag(.eu_payload_ptr).?.data.canMutateComptimeVarState(),
2202 .opt_payload => return val.castTag(.opt_payload).?.data.canMutateComptimeVarState(),
2203 .opt_payload_ptr => return val.castTag(.opt_payload_ptr).?.data.canMutateComptimeVarState(),
2204 .@"struct" => {
2205 const fields = val.cast(Payload.Struct).?.data;
2206 for (fields) |field| {
2207 if (field.canMutateComptimeVarState()) return true;
2208 }
2209 return false;
2210 },
2211 .@"union" => return val.cast(Payload.Union).?.data.val.canMutateComptimeVarState(),
2212 else => return false,
2213 }
2214 }
2215
2173 /// Gets the decl referenced by this pointer. If the pointer does not point2216 /// Gets the decl referenced by this pointer. If the pointer does not point
2174 /// to a decl, or if it points to some part of a decl (like field_ptr or element_ptr),2217 /// to a decl, or if it points to some part of a decl (like field_ptr or element_ptr),
2175 /// this function returns null.2218 /// this function returns null.
test/behavior.zig+1-1
...@@ -151,6 +151,7 @@ test {...@@ -151,6 +151,7 @@ test {
151 _ = @import("behavior/bugs/2114.zig");151 _ = @import("behavior/bugs/2114.zig");
152 _ = @import("behavior/bugs/3779.zig");152 _ = @import("behavior/bugs/3779.zig");
153 _ = @import("behavior/bugs/10147.zig");153 _ = @import("behavior/bugs/10147.zig");
154 _ = @import("behavior/shuffle.zig");
154 _ = @import("behavior/union_with_members.zig");155 _ = @import("behavior/union_with_members.zig");
155156
156 if (builtin.zig_backend == .stage1) {157 if (builtin.zig_backend == .stage1) {
...@@ -169,7 +170,6 @@ test {...@@ -169,7 +170,6 @@ test {
169 _ = @import("behavior/bugs/7027.zig");170 _ = @import("behavior/bugs/7027.zig");
170 _ = @import("behavior/const_slice_child.zig");171 _ = @import("behavior/const_slice_child.zig");
171 _ = @import("behavior/select.zig");172 _ = @import("behavior/select.zig");
172 _ = @import("behavior/shuffle.zig");
173 _ = @import("behavior/struct_contains_slice_of_itself.zig");173 _ = @import("behavior/struct_contains_slice_of_itself.zig");
174 _ = @import("behavior/typename.zig");174 _ = @import("behavior/typename.zig");
175 _ = @import("behavior/vector.zig");175 _ = @import("behavior/vector.zig");
test/behavior/generics.zig+13
...@@ -230,3 +230,16 @@ fn GenNode(comptime T: type) type {...@@ -230,3 +230,16 @@ fn GenNode(comptime T: type) type {
230 }230 }
231 };231 };
232}232}
233
234test "function parameter is generic" {
235 const S = struct {
236 pub fn init(pointer: anytype, comptime fillFn: fn (ptr: *@TypeOf(pointer)) void) void {
237 _ = fillFn;
238 }
239 pub fn fill(self: *u32) void {
240 _ = self;
241 }
242 };
243 var rng: u32 = 2;
244 S.init(rng, S.fill);
245}
test/behavior/shuffle.zig+36-23
...@@ -4,12 +4,12 @@ const mem = std.mem;...@@ -4,12 +4,12 @@ const mem = std.mem;
4const expect = std.testing.expect;4const expect = std.testing.expect;
5const Vector = std.meta.Vector;5const Vector = std.meta.Vector;
66
7test "@shuffle" {7test "@shuffle int" {
8 const S = struct {8 const S = struct {
9 fn doTheTest() !void {9 fn doTheTest() !void {
10 var v: Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 };10 var v: Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 };
11 var x: Vector(4, i32) = [4]i32{ 1, 2147483647, 3, 4 };11 var x: Vector(4, i32) = [4]i32{ 1, 2147483647, 3, 4 };
12 const mask: Vector(4, i32) = [4]i32{ 0, ~@as(i32, 2), 3, ~@as(i32, 3) };12 const mask = [4]i32{ 0, ~@as(i32, 2), 3, ~@as(i32, 3) };
13 var res = @shuffle(i32, v, x, mask);13 var res = @shuffle(i32, v, x, mask);
14 try expect(mem.eql(i32, &@as([4]i32, res), &[4]i32{ 2147483647, 3, 40, 4 }));14 try expect(mem.eql(i32, &@as([4]i32, res), &[4]i32{ 2147483647, 3, 40, 4 }));
1515
...@@ -18,40 +18,53 @@ test "@shuffle" {...@@ -18,40 +18,53 @@ test "@shuffle" {
18 try expect(mem.eql(i32, &@as([4]i32, res), &[4]i32{ 2147483647, 3, 40, 4 }));18 try expect(mem.eql(i32, &@as([4]i32, res), &[4]i32{ 2147483647, 3, 40, 4 }));
1919
20 // Undefined20 // Undefined
21 const mask2: Vector(4, i32) = [4]i32{ 3, 1, 2, 0 };21 const mask2 = [4]i32{ 3, 1, 2, 0 };
22 res = @shuffle(i32, v, undefined, mask2);22 res = @shuffle(i32, v, undefined, mask2);
23 try expect(mem.eql(i32, &@as([4]i32, res), &[4]i32{ 40, -2, 30, 2147483647 }));23 try expect(mem.eql(i32, &@as([4]i32, res), &[4]i32{ 40, -2, 30, 2147483647 }));
2424
25 // Upcasting of b25 // Upcasting of b
26 var v2: Vector(2, i32) = [2]i32{ 2147483647, undefined };26 var v2: Vector(2, i32) = [2]i32{ 2147483647, undefined };
27 const mask3: Vector(4, i32) = [4]i32{ ~@as(i32, 0), 2, ~@as(i32, 0), 3 };27 const mask3 = [4]i32{ ~@as(i32, 0), 2, ~@as(i32, 0), 3 };
28 res = @shuffle(i32, x, v2, mask3);28 res = @shuffle(i32, x, v2, mask3);
29 try expect(mem.eql(i32, &@as([4]i32, res), &[4]i32{ 2147483647, 3, 2147483647, 4 }));29 try expect(mem.eql(i32, &@as([4]i32, res), &[4]i32{ 2147483647, 3, 2147483647, 4 }));
3030
31 // Upcasting of a31 // Upcasting of a
32 var v3: Vector(2, i32) = [2]i32{ 2147483647, -2 };32 var v3: Vector(2, i32) = [2]i32{ 2147483647, -2 };
33 const mask4: Vector(4, i32) = [4]i32{ 0, ~@as(i32, 2), 1, ~@as(i32, 3) };33 const mask4 = [4]i32{ 0, ~@as(i32, 2), 1, ~@as(i32, 3) };
34 res = @shuffle(i32, v3, x, mask4);34 res = @shuffle(i32, v3, x, mask4);
35 try expect(mem.eql(i32, &@as([4]i32, res), &[4]i32{ 2147483647, 3, -2, 4 }));35 try expect(mem.eql(i32, &@as([4]i32, res), &[4]i32{ 2147483647, 3, -2, 4 }));
36 }
37 };
38 try S.doTheTest();
39 comptime try S.doTheTest();
40}
3641
37 // bool42test "@shuffle bool" {
38 {43 const S = struct {
39 var x2: Vector(4, bool) = [4]bool{ false, true, false, true };44 fn doTheTest() !void {
40 var v4: Vector(2, bool) = [2]bool{ true, false };45 var x: Vector(4, bool) = [4]bool{ false, true, false, true };
41 const mask5: Vector(4, i32) = [4]i32{ 0, ~@as(i32, 1), 1, 2 };46 var v: Vector(2, bool) = [2]bool{ true, false };
42 var res2 = @shuffle(bool, x2, v4, mask5);47 const mask = [4]i32{ 0, ~@as(i32, 1), 1, 2 };
43 try expect(mem.eql(bool, &@as([4]bool, res2), &[4]bool{ false, false, true, false }));48 var res = @shuffle(bool, x, v, mask);
44 }49 try expect(mem.eql(bool, &@as([4]bool, res), &[4]bool{ false, false, true, false }));
4550 }
46 // TODO re-enable when LLVM codegen is fixed51 };
47 // https://github.com/ziglang/zig/issues/324652 if (builtin.zig_backend == .stage1) try S.doTheTest();
48 if (false) {53 comptime try S.doTheTest();
49 var x2: Vector(3, bool) = [3]bool{ false, true, false };54}
50 var v4: Vector(2, bool) = [2]bool{ true, false };55
51 const mask5: Vector(4, i32) = [4]i32{ 0, ~@as(i32, 1), 1, 2 };56test "@shuffle bool" {
52 var res2 = @shuffle(bool, x2, v4, mask5);57 // TODO re-enable when LLVM codegen is fixed
53 try expect(mem.eql(bool, &@as([4]bool, res2), &[4]bool{ false, false, true, false }));58 // https://github.com/ziglang/zig/issues/3246
54 }59 if (true) return error.SkipZigTest;
60
61 const S = struct {
62 fn doTheTest() !void {
63 var x: Vector(3, bool) = [3]bool{ false, true, false };
64 var v: Vector(2, bool) = [2]bool{ true, false };
65 const mask: Vector(4, i32) = [4]i32{ 0, ~@as(i32, 1), 1, 2 };
66 var res = @shuffle(bool, x, v, mask);
67 try expect(mem.eql(bool, &@as([4]bool, res), &[4]bool{ false, false, true, false }));
55 }68 }
56 };69 };
57 try S.doTheTest();70 try S.doTheTest();