authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-26 00:33:22-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-03-26 00:33:22-04:00
log88e98a0611b9fb41c1da026febac2467548bb129
tree038ccb88c632580be1898a536aa2433077c2e6d0
parentbae35bdf2d8919b60dee9a0af3afbdd93dd72b59
parentcd46daf7d047eeceb7690e2739af5952d60c3884
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11289 from schmee/stage2-select

stage2: implement `@select`

12 files changed, 239 insertions(+), 23 deletions(-)

src/Air.zig+8-1
...@@ -344,7 +344,7 @@ pub const Inst = struct {...@@ -344,7 +344,7 @@ pub const Inst = struct {
344 /// to the storage for the variable. The local may be a const or a var.344 /// to the storage for the variable. The local may be a const or a var.
345 /// Result type is always void.345 /// Result type is always void.
346 /// Uses `pl_op`. The payload index is the variable name. It points to the extra346 /// Uses `pl_op`. The payload index is the variable name. It points to the extra
347 /// array, reinterpreting the bytes there as a null-terminated string. 347 /// array, reinterpreting the bytes there as a null-terminated string.
348 dbg_var_ptr,348 dbg_var_ptr,
349 /// Same as `dbg_var_ptr` except the local is a const, not a var, and the349 /// Same as `dbg_var_ptr` except the local is a const, not a var, and the
350 /// operand is the local's value.350 /// operand is the local's value.
...@@ -553,6 +553,9 @@ pub const Inst = struct {...@@ -553,6 +553,9 @@ pub const Inst = struct {
553 /// Constructs a vector by selecting elements from `a` and `b` based on `mask`.553 /// Constructs a vector by selecting elements from `a` and `b` based on `mask`.
554 /// Uses the `ty_pl` field with payload `Shuffle`.554 /// Uses the `ty_pl` field with payload `Shuffle`.
555 shuffle,555 shuffle,
556 /// Constructs a vector element-wise from `a` or `b` based on `pred`.
557 /// Uses the `pl_op` field with `pred` as operand, and payload `Bin`.
558 select,
556559
557 /// Given dest ptr, value, and len, set all elements at dest to value.560 /// Given dest ptr, value, and len, set all elements at dest to value.
558 /// Result type is always void.561 /// Result type is always void.
...@@ -1067,6 +1070,10 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -1067,6 +1070,10 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
1067 .reduce => return air.typeOf(datas[inst].reduce.operand).childType(),1070 .reduce => return air.typeOf(datas[inst].reduce.operand).childType(),
10681071
1069 .mul_add => return air.typeOf(datas[inst].pl_op.operand),1072 .mul_add => return air.typeOf(datas[inst].pl_op.operand),
1073 .select => {
1074 const extra = air.extraData(Air.Bin, datas[inst].pl_op.payload).data;
1075 return air.typeOf(extra.lhs);
1076 },
10701077
1071 .add_with_overflow,1078 .add_with_overflow,
1072 .sub_with_overflow,1079 .sub_with_overflow,
src/Liveness.zig+5
...@@ -433,6 +433,11 @@ fn analyzeInst(...@@ -433,6 +433,11 @@ fn analyzeInst(
433 }433 }
434 return extra_tombs.finish();434 return extra_tombs.finish();
435 },435 },
436 .select => {
437 const pl_op = inst_datas[inst].pl_op;
438 const extra = a.air.extraData(Air.Bin, pl_op.payload).data;
439 return trackOperands(a, new_set, inst, main_tomb, .{ pl_op.operand, extra.lhs, extra.rhs });
440 },
436 .shuffle => {441 .shuffle => {
437 const extra = a.air.extraData(Air.Shuffle, inst_datas[inst].ty_pl.payload).data;442 const extra = a.air.extraData(Air.Shuffle, inst_datas[inst].ty_pl.payload).data;
438 return trackOperands(a, new_set, inst, main_tomb, .{ extra.a, extra.b, .none });443 return trackOperands(a, new_set, inst, main_tomb, .{ extra.a, extra.b, .none });
src/Sema.zig+85-2
...@@ -14890,8 +14890,91 @@ fn analyzeShuffle(...@@ -14890,8 +14890,91 @@ fn analyzeShuffle(
1489014890
14891fn zirSelect(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {14891fn zirSelect(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
14892 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;14892 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
14893 const src = inst_data.src();14893 const extra = sema.code.extraData(Zir.Inst.Select, inst_data.payload_index).data;
14894 return sema.fail(block, src, "TODO: Sema.zirSelect", .{});14894 const target = sema.mod.getTarget();
14895
14896 const elem_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
14897 const pred_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
14898 const a_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
14899 const b_src: LazySrcLoc = .{ .node_offset_builtin_call_arg3 = inst_data.src_node };
14900
14901 const elem_ty = try sema.resolveType(block, elem_ty_src, extra.elem_type);
14902 try sema.checkVectorElemType(block, elem_ty_src, elem_ty);
14903 const pred_uncoerced = sema.resolveInst(extra.pred);
14904 const pred_ty = sema.typeOf(pred_uncoerced);
14905
14906 const vec_len_u64 = switch (try pred_ty.zigTypeTagOrPoison()) {
14907 .Vector, .Array => pred_ty.arrayLen(),
14908 else => return sema.fail(block, pred_src, "expected vector or array, found '{}'", .{pred_ty.fmt(target)}),
14909 };
14910 const vec_len = try sema.usizeCast(block, pred_src, vec_len_u64);
14911
14912 const bool_vec_ty = try Type.vector(sema.arena, vec_len, Type.bool);
14913 const pred = try sema.coerce(block, bool_vec_ty, pred_uncoerced, pred_src);
14914
14915 const vec_ty = try Type.vector(sema.arena, vec_len, elem_ty);
14916 const a = try sema.coerce(block, vec_ty, sema.resolveInst(extra.a), a_src);
14917 const b = try sema.coerce(block, vec_ty, sema.resolveInst(extra.b), b_src);
14918
14919 const maybe_pred = try sema.resolveMaybeUndefVal(block, pred_src, pred);
14920 const maybe_a = try sema.resolveMaybeUndefVal(block, a_src, a);
14921 const maybe_b = try sema.resolveMaybeUndefVal(block, b_src, b);
14922
14923 const runtime_src = if (maybe_pred) |pred_val| rs: {
14924 if (pred_val.isUndef()) return sema.addConstUndef(vec_ty);
14925
14926 if (maybe_a) |a_val| {
14927 if (a_val.isUndef()) return sema.addConstUndef(vec_ty);
14928
14929 if (maybe_b) |b_val| {
14930 if (b_val.isUndef()) return sema.addConstUndef(vec_ty);
14931
14932 var buf: Value.ElemValueBuffer = undefined;
14933 const elems = try sema.gpa.alloc(Value, vec_len);
14934 for (elems) |*elem, i| {
14935 const pred_elem_val = pred_val.elemValueBuffer(i, &buf);
14936 const should_choose_a = pred_elem_val.toBool();
14937 if (should_choose_a) {
14938 elem.* = a_val.elemValueBuffer(i, &buf);
14939 } else {
14940 elem.* = b_val.elemValueBuffer(i, &buf);
14941 }
14942 }
14943
14944 return sema.addConstant(
14945 vec_ty,
14946 try Value.Tag.aggregate.create(sema.arena, elems),
14947 );
14948 } else {
14949 break :rs b_src;
14950 }
14951 } else {
14952 if (maybe_b) |b_val| {
14953 if (b_val.isUndef()) return sema.addConstUndef(vec_ty);
14954 }
14955 break :rs a_src;
14956 }
14957 } else rs: {
14958 if (maybe_a) |a_val| {
14959 if (a_val.isUndef()) return sema.addConstUndef(vec_ty);
14960 }
14961 if (maybe_b) |b_val| {
14962 if (b_val.isUndef()) return sema.addConstUndef(vec_ty);
14963 }
14964 break :rs pred_src;
14965 };
14966
14967 try sema.requireRuntimeBlock(block, runtime_src);
14968 return block.addInst(.{
14969 .tag = .select,
14970 .data = .{ .pl_op = .{
14971 .operand = pred,
14972 .payload = try block.sema.addExtra(Air.Bin{
14973 .lhs = a,
14974 .rhs = b,
14975 }),
14976 } },
14977 });
14895}14978}
1489614979
14897fn zirAtomicLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {14980fn zirAtomicLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
src/arch/aarch64/CodeGen.zig+8
...@@ -633,6 +633,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -633,6 +633,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
633 .tag_name => try self.airTagName(inst),633 .tag_name => try self.airTagName(inst),
634 .error_name => try self.airErrorName(inst),634 .error_name => try self.airErrorName(inst),
635 .splat => try self.airSplat(inst),635 .splat => try self.airSplat(inst),
636 .select => try self.airSelect(inst),
636 .shuffle => try self.airShuffle(inst),637 .shuffle => try self.airShuffle(inst),
637 .reduce => try self.airReduce(inst),638 .reduce => try self.airReduce(inst),
638 .aggregate_init => try self.airAggregateInit(inst),639 .aggregate_init => try self.airAggregateInit(inst),
...@@ -3666,6 +3667,13 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {...@@ -3666,6 +3667,13 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {
3666 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });3667 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3667}3668}
36683669
3670fn airSelect(self: *Self, inst: Air.Inst.Index) !void {
3671 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
3672 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
3673 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airSelect for {}", .{self.target.cpu.arch});
3674 return self.finishAir(inst, result, .{ pl_op.operand, extra.lhs, extra.rhs });
3675}
3676
3669fn airShuffle(self: *Self, inst: Air.Inst.Index) !void {3677fn airShuffle(self: *Self, inst: Air.Inst.Index) !void {
3670 const ty_op = self.air.instructions.items(.data)[inst].ty_op;3678 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3671 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airShuffle for {}", .{self.target.cpu.arch});3679 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airShuffle for {}", .{self.target.cpu.arch});
src/arch/arm/CodeGen.zig+8
...@@ -630,6 +630,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -630,6 +630,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
630 .tag_name => try self.airTagName(inst),630 .tag_name => try self.airTagName(inst),
631 .error_name => try self.airErrorName(inst),631 .error_name => try self.airErrorName(inst),
632 .splat => try self.airSplat(inst),632 .splat => try self.airSplat(inst),
633 .select => try self.airSelect(inst),
633 .shuffle => try self.airShuffle(inst),634 .shuffle => try self.airShuffle(inst),
634 .reduce => try self.airReduce(inst),635 .reduce => try self.airReduce(inst),
635 .aggregate_init => try self.airAggregateInit(inst),636 .aggregate_init => try self.airAggregateInit(inst),
...@@ -4323,6 +4324,13 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {...@@ -4323,6 +4324,13 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {
4323 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });4324 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
4324}4325}
43254326
4327fn airSelect(self: *Self, inst: Air.Inst.Index) !void {
4328 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
4329 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
4330 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airSelect for arm", .{});
4331 return self.finishAir(inst, result, .{ pl_op.operand, extra.lhs, extra.rhs });
4332}
4333
4326fn airShuffle(self: *Self, inst: Air.Inst.Index) !void {4334fn airShuffle(self: *Self, inst: Air.Inst.Index) !void {
4327 const ty_op = self.air.instructions.items(.data)[inst].ty_op;4335 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
4328 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airShuffle for arm", .{});4336 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airShuffle for arm", .{});
src/arch/riscv64/CodeGen.zig+8
...@@ -600,6 +600,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -600,6 +600,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
600 .tag_name => try self.airTagName(inst),600 .tag_name => try self.airTagName(inst),
601 .error_name => try self.airErrorName(inst),601 .error_name => try self.airErrorName(inst),
602 .splat => try self.airSplat(inst),602 .splat => try self.airSplat(inst),
603 .select => try self.airSelect(inst),
603 .shuffle => try self.airShuffle(inst),604 .shuffle => try self.airShuffle(inst),
604 .reduce => try self.airReduce(inst),605 .reduce => try self.airReduce(inst),
605 .aggregate_init => try self.airAggregateInit(inst),606 .aggregate_init => try self.airAggregateInit(inst),
...@@ -2396,6 +2397,13 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {...@@ -2396,6 +2397,13 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {
2396 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });2397 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
2397}2398}
23982399
2400fn airSelect(self: *Self, inst: Air.Inst.Index) !void {
2401 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
2402 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
2403 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airSelect for riscv64", .{});
2404 return self.finishAir(inst, result, .{ pl_op.operand, extra.lhs, extra.rhs });
2405}
2406
2399fn airShuffle(self: *Self, inst: Air.Inst.Index) !void {2407fn airShuffle(self: *Self, inst: Air.Inst.Index) !void {
2400 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2408 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2401 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airShuffle for riscv64", .{});2409 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airShuffle for riscv64", .{});
src/arch/wasm/CodeGen.zig+11
...@@ -1371,6 +1371,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1371,6 +1371,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1371 .ret_ptr => self.airRetPtr(inst),1371 .ret_ptr => self.airRetPtr(inst),
1372 .ret_load => self.airRetLoad(inst),1372 .ret_load => self.airRetLoad(inst),
1373 .splat => self.airSplat(inst),1373 .splat => self.airSplat(inst),
1374 .select => self.airSelect(inst),
1374 .shuffle => self.airShuffle(inst),1375 .shuffle => self.airShuffle(inst),
1375 .reduce => self.airReduce(inst),1376 .reduce => self.airReduce(inst),
1376 .aggregate_init => self.airAggregateInit(inst),1377 .aggregate_init => self.airAggregateInit(inst),
...@@ -3265,6 +3266,16 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3265,6 +3266,16 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3265 return self.fail("TODO: Implement wasm airSplat", .{});3266 return self.fail("TODO: Implement wasm airSplat", .{});
3266}3267}
32673268
3269fn airSelect(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3270 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
3271
3272 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
3273 const operand = try self.resolveInst(pl_op.operand);
3274
3275 _ = operand;
3276 return self.fail("TODO: Implement wasm airSelect", .{});
3277}
3278
3268fn airShuffle(self: *Self, inst: Air.Inst.Index) InnerError!WValue {3279fn airShuffle(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3269 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };3280 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
32703281
src/arch/x86_64/CodeGen.zig+8
...@@ -714,6 +714,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -714,6 +714,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
714 .tag_name => try self.airTagName(inst),714 .tag_name => try self.airTagName(inst),
715 .error_name => try self.airErrorName(inst),715 .error_name => try self.airErrorName(inst),
716 .splat => try self.airSplat(inst),716 .splat => try self.airSplat(inst),
717 .select => try self.airSelect(inst),
717 .shuffle => try self.airShuffle(inst),718 .shuffle => try self.airShuffle(inst),
718 .reduce => try self.airReduce(inst),719 .reduce => try self.airReduce(inst),
719 .aggregate_init => try self.airAggregateInit(inst),720 .aggregate_init => try self.airAggregateInit(inst),
...@@ -5624,6 +5625,13 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {...@@ -5624,6 +5625,13 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {
5624 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });5625 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
5625}5626}
56265627
5628fn airSelect(self: *Self, inst: Air.Inst.Index) !void {
5629 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
5630 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
5631 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airSelect for x86_64", .{});
5632 return self.finishAir(inst, result, .{ pl_op.operand, extra.lhs, extra.rhs });
5633}
5634
5627fn airShuffle(self: *Self, inst: Air.Inst.Index) !void {5635fn airShuffle(self: *Self, inst: Air.Inst.Index) !void {
5628 const ty_op = self.air.instructions.items(.data)[inst].ty_op;5636 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
5629 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airShuffle for x86_64", .{});5637 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airShuffle for x86_64", .{});
src/codegen/c.zig+16
...@@ -1825,6 +1825,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -1825,6 +1825,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
1825 .tag_name => try airTagName(f, inst),1825 .tag_name => try airTagName(f, inst),
1826 .error_name => try airErrorName(f, inst),1826 .error_name => try airErrorName(f, inst),
1827 .splat => try airSplat(f, inst),1827 .splat => try airSplat(f, inst),
1828 .select => try airSelect(f, inst),
1828 .shuffle => try airShuffle(f, inst),1829 .shuffle => try airShuffle(f, inst),
1829 .reduce => try airReduce(f, inst),1830 .reduce => try airReduce(f, inst),
1830 .aggregate_init => try airAggregateInit(f, inst),1831 .aggregate_init => try airAggregateInit(f, inst),
...@@ -3794,6 +3795,21 @@ fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3794,6 +3795,21 @@ fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue {
3794 return f.fail("TODO: C backend: implement airSplat", .{});3795 return f.fail("TODO: C backend: implement airSplat", .{});
3795}3796}
37963797
3798fn airSelect(f: *Function, inst: Air.Inst.Index) !CValue {
3799 if (f.liveness.isUnused(inst)) return CValue.none;
3800
3801 const inst_ty = f.air.typeOfIndex(inst);
3802 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
3803
3804 const writer = f.object.writer();
3805 const local = try f.allocLocal(inst_ty, .Const);
3806 try writer.writeAll(" = ");
3807
3808 _ = local;
3809 _ = ty_pl;
3810 return f.fail("TODO: C backend: implement airSelect", .{});
3811}
3812
3797fn airShuffle(f: *Function, inst: Air.Inst.Index) !CValue {3813fn airShuffle(f: *Function, inst: Air.Inst.Index) !CValue {
3798 if (f.liveness.isUnused(inst)) return CValue.none;3814 if (f.liveness.isUnused(inst)) return CValue.none;
37993815
src/codegen/llvm.zig+13
...@@ -3444,6 +3444,7 @@ pub const FuncGen = struct {...@@ -3444,6 +3444,7 @@ pub const FuncGen = struct {
3444 .tag_name => try self.airTagName(inst),3444 .tag_name => try self.airTagName(inst),
3445 .error_name => try self.airErrorName(inst),3445 .error_name => try self.airErrorName(inst),
3446 .splat => try self.airSplat(inst),3446 .splat => try self.airSplat(inst),
3447 .select => try self.airSelect(inst),
3447 .shuffle => try self.airShuffle(inst),3448 .shuffle => try self.airShuffle(inst),
3448 .reduce => try self.airReduce(inst),3449 .reduce => try self.airReduce(inst),
3449 .aggregate_init => try self.airAggregateInit(inst),3450 .aggregate_init => try self.airAggregateInit(inst),
...@@ -6355,6 +6356,18 @@ pub const FuncGen = struct {...@@ -6355,6 +6356,18 @@ pub const FuncGen = struct {
6355 return self.builder.buildShuffleVector(op_vector, undef_vector, mask_llvm_ty.constNull(), "");6356 return self.builder.buildShuffleVector(op_vector, undef_vector, mask_llvm_ty.constNull(), "");
6356 }6357 }
63576358
6359 fn airSelect(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
6360 if (self.liveness.isUnused(inst)) return null;
6361
6362 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
6363 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
6364 const pred = try self.resolveInst(pl_op.operand);
6365 const a = try self.resolveInst(extra.lhs);
6366 const b = try self.resolveInst(extra.rhs);
6367
6368 return self.builder.buildSelect(pred, a, b, "");
6369 }
6370
6358 fn airShuffle(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {6371 fn airShuffle(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
6359 if (self.liveness.isUnused(inst)) return null;6372 if (self.liveness.isUnused(inst)) return null;
63606373
src/print_air.zig+14
...@@ -264,6 +264,7 @@ const Writer = struct {...@@ -264,6 +264,7 @@ const Writer = struct {
264 .wasm_memory_size => try w.writeWasmMemorySize(s, inst),264 .wasm_memory_size => try w.writeWasmMemorySize(s, inst),
265 .wasm_memory_grow => try w.writeWasmMemoryGrow(s, inst),265 .wasm_memory_grow => try w.writeWasmMemoryGrow(s, inst),
266 .mul_add => try w.writeMulAdd(s, inst),266 .mul_add => try w.writeMulAdd(s, inst),
267 .select => try w.writeSelect(s, inst),
267 .shuffle => try w.writeShuffle(s, inst),268 .shuffle => try w.writeShuffle(s, inst),
268 .reduce => try w.writeReduce(s, inst),269 .reduce => try w.writeReduce(s, inst),
269 .cmp_vector => try w.writeCmpVector(s, inst),270 .cmp_vector => try w.writeCmpVector(s, inst),
...@@ -396,6 +397,19 @@ const Writer = struct {...@@ -396,6 +397,19 @@ const Writer = struct {
396 try s.print(", mask {d}, len {d}", .{ extra.mask, extra.mask_len });397 try s.print(", mask {d}, len {d}", .{ extra.mask, extra.mask_len });
397 }398 }
398399
400 fn writeSelect(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
401 const pl_op = w.air.instructions.items(.data)[inst].pl_op;
402 const extra = w.air.extraData(Air.Bin, pl_op.payload).data;
403
404 const elem_ty = w.air.typeOfIndex(inst).childType();
405 try s.print("{}, ", .{elem_ty.fmtDebug()});
406 try w.writeOperand(s, inst, 0, pl_op.operand);
407 try s.writeAll(", ");
408 try w.writeOperand(s, inst, 1, extra.lhs);
409 try s.writeAll(", ");
410 try w.writeOperand(s, inst, 2, extra.rhs);
411 }
412
399 fn writeReduce(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {413 fn writeReduce(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
400 const reduce = w.air.instructions.items(.data)[inst].reduce;414 const reduce = w.air.instructions.items(.data)[inst].reduce;
401415
test/behavior/select.zig+55-20
...@@ -3,24 +3,59 @@ const builtin = @import("builtin");...@@ -3,24 +3,59 @@ const builtin = @import("builtin");
3const mem = std.mem;3const mem = std.mem;
4const expect = std.testing.expect;4const expect = std.testing.expect;
55
6test "@select" {6test "@select vectors" {
7 if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO7 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
88 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
9 const S = struct {9 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
10 fn doTheTest() !void {10 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11 var a: @Vector(4, bool) = [4]bool{ true, false, true, false };11 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12 var b: @Vector(4, i32) = [4]i32{ -1, 4, 999, -31 };12
13 var c: @Vector(4, i32) = [4]i32{ -5, 1, 0, 1234 };13 comptime try selectVectors();
14 var abc = @select(i32, a, b, c);14 try selectVectors();
15 try expect(mem.eql(i32, &@as([4]i32, abc), &[4]i32{ -1, 1, 999, 1234 }));15}
1616
17 var x: @Vector(4, bool) = [4]bool{ false, false, false, true };17fn selectVectors() !void {
18 var y: @Vector(4, f32) = [4]f32{ 0.001, 33.4, 836, -3381.233 };18 var a = @Vector(4, bool){ true, false, true, false };
19 var z: @Vector(4, f32) = [4]f32{ 0.0, 312.1, -145.9, 9993.55 };19 var b = @Vector(4, i32){ -1, 4, 999, -31 };
20 var xyz = @select(f32, x, y, z);20 var c = @Vector(4, i32){ -5, 1, 0, 1234 };
21 try expect(mem.eql(f32, &@as([4]f32, xyz), &[4]f32{ 0.0, 312.1, -145.9, -3381.233 }));21 var abc = @select(i32, a, b, c);
22 }22 try expect(abc[0] == -1);
23 };23 try expect(abc[1] == 1);
24 try S.doTheTest();24 try expect(abc[2] == 999);
25 comptime try S.doTheTest();25 try expect(abc[3] == 1234);
26
27 var x = @Vector(4, bool){ false, false, false, true };
28 var y = @Vector(4, f32){ 0.001, 33.4, 836, -3381.233 };
29 var z = @Vector(4, f32){ 0.0, 312.1, -145.9, 9993.55 };
30 var xyz = @select(f32, x, y, z);
31 try expect(mem.eql(f32, &@as([4]f32, xyz), &[4]f32{ 0.0, 312.1, -145.9, -3381.233 }));
32}
33
34test "@select arrays" {
35 if (builtin.zig_backend == .stage1) return error.SkipZigTest; // TODO
36 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
37 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
38 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
39 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
40 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
41
42 comptime try selectArrays();
43 try selectArrays();
44}
45
46fn selectArrays() !void {
47 var a = [4]bool{ false, true, false, true };
48 var b = [4]usize{ 0, 1, 2, 3 };
49 var c = [4]usize{ 4, 5, 6, 7 };
50 var abc = @select(usize, a, b, c);
51 try expect(abc[0] == 4);
52 try expect(abc[1] == 1);
53 try expect(abc[2] == 6);
54 try expect(abc[3] == 3);
55
56 var x = [4]bool{ false, false, false, true };
57 var y = [4]f32{ 0.001, 33.4, 836, -3381.233 };
58 var z = [4]f32{ 0.0, 312.1, -145.9, 9993.55 };
59 var xyz = @select(f32, x, y, z);
60 try expect(mem.eql(f32, &@as([4]f32, xyz), &[4]f32{ 0.0, 312.1, -145.9, -3381.233 }));
26}61}