authorgravatar for john.schmidt.h@gmail.comJohn Schmidt <john.schmidt.h@gmail.com> 2022-03-23 21:41:35+01:00
committergravatar for john.schmidt.h@gmail.comJohn Schmidt <john.schmidt.h@gmail.com> 2022-03-25 16:13:54+01:00
log12d5efcbe621b98b5a99c5f84a9d5b605e4acc40
tree9188b875170a4c23511213f8002fe48908ea3729
parent1c33ea2c35e9260babedb116ad527256e0a4ef5e

stage2: implement `@select`


12 files changed, 222 insertions(+), 20 deletions(-)

src/Air.zig+11-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 `ty_pl` field with payload `Select`.
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.
...@@ -785,6 +788,12 @@ pub const Shuffle = struct {...@@ -785,6 +788,12 @@ pub const Shuffle = struct {
785 mask_len: u32,788 mask_len: u32,
786};789};
787790
791pub const Select = struct {
792 pred: Inst.Ref,
793 a: Inst.Ref,
794 b: Inst.Ref,
795};
796
788pub const VectorCmp = struct {797pub const VectorCmp = struct {
789 lhs: Inst.Ref,798 lhs: Inst.Ref,
790 rhs: Inst.Ref,799 rhs: Inst.Ref,
...@@ -956,6 +965,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -956,6 +965,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
956 .cmpxchg_weak,965 .cmpxchg_weak,
957 .cmpxchg_strong,966 .cmpxchg_strong,
958 .slice,967 .slice,
968 .select,
959 .shuffle,969 .shuffle,
960 .aggregate_init,970 .aggregate_init,
961 .union_init,971 .union_init,
src/Liveness.zig+4
...@@ -433,6 +433,10 @@ fn analyzeInst(...@@ -433,6 +433,10 @@ fn analyzeInst(
433 }433 }
434 return extra_tombs.finish();434 return extra_tombs.finish();
435 },435 },
436 .select => {
437 const extra = a.air.extraData(Air.Select, inst_datas[inst].ty_pl.payload).data;
438 return trackOperands(a, new_set, inst, main_tomb, .{ extra.pred, extra.a, extra.b });
439 },
436 .shuffle => {440 .shuffle => {
437 const extra = a.air.extraData(Air.Shuffle, inst_datas[inst].ty_pl.payload).data;441 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 });442 return trackOperands(a, new_set, inst, main_tomb, .{ extra.a, extra.b, .none });
src/Sema.zig+99-2
...@@ -14804,8 +14804,105 @@ fn analyzeShuffle(...@@ -14804,8 +14804,105 @@ fn analyzeShuffle(
1480414804
14805fn zirSelect(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {14805fn zirSelect(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
14806 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;14806 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
14807 const src = inst_data.src();14807 const extra = sema.code.extraData(Zir.Inst.Select, inst_data.payload_index).data;
14808 return sema.fail(block, src, "TODO: Sema.zirSelect", .{});14808
14809 const elem_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
14810 const pred_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
14811 const a_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
14812 const b_src: LazySrcLoc = .{ .node_offset_builtin_call_arg3 = inst_data.src_node };
14813
14814 const elem_ty = try sema.resolveType(block, elem_ty_src, extra.elem_type);
14815 try sema.checkVectorElemType(block, elem_ty_src, elem_ty);
14816 const pred = sema.resolveInst(extra.pred);
14817 const a = sema.resolveInst(extra.a);
14818 const b = sema.resolveInst(extra.b);
14819 const target = sema.mod.getTarget();
14820
14821 const pred_ty = sema.typeOf(pred);
14822 switch (try pred_ty.zigTypeTagOrPoison()) {
14823 .Vector => {
14824 const scalar_ty = pred_ty.childType();
14825 if (!scalar_ty.eql(Type.bool, target)) {
14826 const bool_vec_ty = try Type.vector(sema.arena, pred_ty.vectorLen(), Type.bool);
14827 return sema.fail(block, pred_src, "Expected '{}', found '{}'", .{ bool_vec_ty.fmt(target), pred_ty.fmt(target) });
14828 }
14829 },
14830 else => return sema.fail(block, pred_src, "Expected vector type, found '{}'", .{pred_ty.fmt(target)}),
14831 }
14832
14833 const vec_len = pred_ty.vectorLen();
14834 const vec_ty = try Type.vector(sema.arena, vec_len, elem_ty);
14835
14836 const a_ty = sema.typeOf(a);
14837 if (!a_ty.eql(vec_ty, target)) {
14838 return sema.fail(block, a_src, "Expected '{}', found '{}'", .{ vec_ty.fmt(target), a_ty.fmt(target) });
14839 }
14840
14841 const b_ty = sema.typeOf(b);
14842 if (!b_ty.eql(vec_ty, target)) {
14843 return sema.fail(block, b_src, "Expected '{}', found '{}'", .{ vec_ty.fmt(target), b_ty.fmt(target) });
14844 }
14845
14846 const maybe_pred = try sema.resolveMaybeUndefVal(block, pred_src, pred);
14847 const maybe_a = try sema.resolveMaybeUndefVal(block, a_src, a);
14848 const maybe_b = try sema.resolveMaybeUndefVal(block, b_src, b);
14849
14850 const runtime_src = if (maybe_pred) |pred_val| rs: {
14851 if (pred_val.isUndef()) return sema.addConstUndef(vec_ty);
14852
14853 if (maybe_a) |a_val| {
14854 if (a_val.isUndef()) return sema.addConstUndef(vec_ty);
14855
14856 if (maybe_b) |b_val| {
14857 if (b_val.isUndef()) return sema.addConstUndef(vec_ty);
14858
14859 var buf: Value.ElemValueBuffer = undefined;
14860 const elems = try sema.gpa.alloc(Value, vec_len);
14861 for (elems) |*elem, i| {
14862 const pred_elem_val = pred_val.elemValueBuffer(i, &buf);
14863 const should_choose_a = pred_elem_val.toBool();
14864 if (should_choose_a) {
14865 elem.* = a_val.elemValueBuffer(i, &buf);
14866 } else {
14867 elem.* = b_val.elemValueBuffer(i, &buf);
14868 }
14869 }
14870
14871 return sema.addConstant(
14872 vec_ty,
14873 try Value.Tag.aggregate.create(sema.arena, elems),
14874 );
14875 } else {
14876 break :rs b_src;
14877 }
14878 } else {
14879 if (maybe_b) |b_val| {
14880 if (b_val.isUndef()) return sema.addConstUndef(vec_ty);
14881 }
14882 break :rs a_src;
14883 }
14884 } else rs: {
14885 if (maybe_a) |a_val| {
14886 if (a_val.isUndef()) return sema.addConstUndef(vec_ty);
14887 }
14888 if (maybe_b) |b_val| {
14889 if (b_val.isUndef()) return sema.addConstUndef(vec_ty);
14890 }
14891 break :rs pred_src;
14892 };
14893
14894 try sema.requireRuntimeBlock(block, runtime_src);
14895 return block.addInst(.{
14896 .tag = .select,
14897 .data = .{ .ty_pl = .{
14898 .ty = try block.sema.addType(vec_ty),
14899 .payload = try block.sema.addExtra(Air.Select{
14900 .pred = pred,
14901 .a = a,
14902 .b = b,
14903 }),
14904 } },
14905 });
14809}14906}
1481014907
14811fn zirAtomicLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {14908fn zirAtomicLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
src/arch/aarch64/CodeGen.zig+8
...@@ -640,6 +640,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -640,6 +640,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
640 .tag_name => try self.airTagName(inst),640 .tag_name => try self.airTagName(inst),
641 .error_name => try self.airErrorName(inst),641 .error_name => try self.airErrorName(inst),
642 .splat => try self.airSplat(inst),642 .splat => try self.airSplat(inst),
643 .select => try self.airSelect(inst),
643 .shuffle => try self.airShuffle(inst),644 .shuffle => try self.airShuffle(inst),
644 .reduce => try self.airReduce(inst),645 .reduce => try self.airReduce(inst),
645 .aggregate_init => try self.airAggregateInit(inst),646 .aggregate_init => try self.airAggregateInit(inst),
...@@ -3746,6 +3747,13 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {...@@ -3746,6 +3747,13 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {
3746 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });3747 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3747}3748}
37483749
3750fn airSelect(self: *Self, inst: Air.Inst.Index) !void {
3751 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
3752 const extra = self.air.extraData(Air.Select, ty_pl.payload).data;
3753 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airSelect for {}", .{self.target.cpu.arch});
3754 return self.finishAir(inst, result, .{ extra.pred, extra.a, extra.b });
3755}
3756
3749fn airShuffle(self: *Self, inst: Air.Inst.Index) !void {3757fn airShuffle(self: *Self, inst: Air.Inst.Index) !void {
3750 const ty_op = self.air.instructions.items(.data)[inst].ty_op;3758 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3751 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airShuffle for {}", .{self.target.cpu.arch});3759 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 ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
4329 const extra = self.air.extraData(Air.Select, ty_pl.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, .{ extra.pred, extra.a, extra.b });
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 ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
2402 const extra = self.air.extraData(Air.Select, ty_pl.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, .{ extra.pred, extra.a, extra.b });
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 ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
3273 const ty = try self.resolveInst(ty_pl.ty);
3274
3275 _ = ty;
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
...@@ -721,6 +721,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -721,6 +721,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
721 .tag_name => try self.airTagName(inst),721 .tag_name => try self.airTagName(inst),
722 .error_name => try self.airErrorName(inst),722 .error_name => try self.airErrorName(inst),
723 .splat => try self.airSplat(inst),723 .splat => try self.airSplat(inst),
724 .select => try self.airSelect(inst),
724 .shuffle => try self.airShuffle(inst),725 .shuffle => try self.airShuffle(inst),
725 .reduce => try self.airReduce(inst),726 .reduce => try self.airReduce(inst),
726 .aggregate_init => try self.airAggregateInit(inst),727 .aggregate_init => try self.airAggregateInit(inst),
...@@ -5678,6 +5679,13 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {...@@ -5678,6 +5679,13 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {
5678 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });5679 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
5679}5680}
56805681
5682fn airSelect(self: *Self, inst: Air.Inst.Index) !void {
5683 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
5684 const extra = self.air.extraData(Air.Select, ty_pl.payload).data;
5685 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airSelect for x86_64", .{});
5686 return self.finishAir(inst, result, .{ extra.pred, extra.a, extra.b });
5687}
5688
5681fn airShuffle(self: *Self, inst: Air.Inst.Index) !void {5689fn airShuffle(self: *Self, inst: Air.Inst.Index) !void {
5682 const ty_op = self.air.instructions.items(.data)[inst].ty_op;5690 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
5683 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airShuffle for x86_64", .{});5691 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 ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
6363 const extra = self.air.extraData(Air.Select, ty_pl.payload).data;
6364 const pred = try self.resolveInst(extra.pred);
6365 const a = try self.resolveInst(extra.a);
6366 const b = try self.resolveInst(extra.b);
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+13
...@@ -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,18 @@ const Writer = struct {...@@ -396,6 +397,18 @@ 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 ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
402 const extra = w.air.extraData(Air.Select, ty_pl.payload).data;
403
404 try s.print("{}, ", .{w.air.getRefType(ty_pl.ty).fmtDebug()});
405 try w.writeOperand(s, inst, 0, extra.pred);
406 try s.writeAll(", ");
407 try w.writeOperand(s, inst, 1, extra.a);
408 try s.writeAll(", ");
409 try w.writeOperand(s, inst, 2, extra.b);
410 }
411
399 fn writeReduce(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {412 fn writeReduce(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
400 const reduce = w.air.instructions.items(.data)[inst].reduce;413 const reduce = w.air.instructions.items(.data)[inst].reduce;
401414
test/behavior/select.zig+23-17
...@@ -4,23 +4,29 @@ const mem = std.mem;...@@ -4,23 +4,29 @@ const mem = std.mem;
4const expect = std.testing.expect;4const expect = std.testing.expect;
55
6test "@select" {6test "@select" {
7 if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO7 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
812
9 const S = struct {13 try doTheTest();
10 fn doTheTest() !void {14 comptime try doTheTest();
11 var a: @Vector(4, bool) = [4]bool{ true, false, true, false };15}
12 var b: @Vector(4, i32) = [4]i32{ -1, 4, 999, -31 };16
13 var c: @Vector(4, i32) = [4]i32{ -5, 1, 0, 1234 };17fn doTheTest() !void {
14 var abc = @select(i32, a, b, c);18 var a = @Vector(4, bool){ true, false, true, false };
15 try expect(mem.eql(i32, &@as([4]i32, abc), &[4]i32{ -1, 1, 999, 1234 }));19 var b = @Vector(4, i32){ -1, 4, 999, -31 };
20 var c = @Vector(4, i32){ -5, 1, 0, 1234 };
21 var abc = @select(i32, a, b, c);
22 try expect(abc[0] == -1);
23 try expect(abc[1] == 1);
24 try expect(abc[2] == 999);
25 try expect(abc[3] == 1234);
1626
17 var x: @Vector(4, bool) = [4]bool{ false, false, false, true };27 var x = @Vector(4, bool){ false, false, false, true };
18 var y: @Vector(4, f32) = [4]f32{ 0.001, 33.4, 836, -3381.233 };28 var y = @Vector(4, f32){ 0.001, 33.4, 836, -3381.233 };
19 var z: @Vector(4, f32) = [4]f32{ 0.0, 312.1, -145.9, 9993.55 };29 var z = @Vector(4, f32){ 0.0, 312.1, -145.9, 9993.55 };
20 var xyz = @select(f32, x, y, z);30 var xyz = @select(f32, x, y, z);
21 try expect(mem.eql(f32, &@as([4]f32, xyz), &[4]f32{ 0.0, 312.1, -145.9, -3381.233 }));31 try expect(mem.eql(f32, &@as([4]f32, xyz), &[4]f32{ 0.0, 312.1, -145.9, -3381.233 }));
22 }
23 };
24 try S.doTheTest();
25 comptime try S.doTheTest();
26}32}