| author | |
| committer | |
| log | 12d5efcbe621b98b5a99c5f84a9d5b605e4acc40 |
| tree | 9188b875170a4c23511213f8002fe48908ea3729 |
| parent | 1c33ea2c35e9260babedb116ad527256e0a4ef5e |
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 extra | 346 | /// 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 the | 349 | /// 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, | ||
| 556 | 559 | ||
| 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 | }; |
| 787 | 790 | ||
| 791 | pub const Select = struct { | ||
| 792 | pred: Inst.Ref, | ||
| 793 | a: Inst.Ref, | ||
| 794 | b: Inst.Ref, | ||
| 795 | }; | ||
| 796 | |||
| 788 | pub const VectorCmp = struct { | 797 | pub 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( |
| 14804 | 14804 | ||
| 14805 | fn zirSelect(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 14805 | fn 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 | } |
| 14810 | 14907 | ||
| 14811 | fn zirAtomicLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 14908 | fn 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 | } |
| 3748 | 3749 | ||
| 3750 | fn 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 | |||
| 3749 | fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { | 3757 | fn 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 | } |
| 4325 | 4326 | ||
| 4327 | fn 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 | |||
| 4326 | fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { | 4334 | fn 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 | } |
| 2398 | 2399 | ||
| 2400 | fn 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 | |||
| 2399 | fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { | 2407 | fn 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 | } |
| 3267 | 3268 | ||
| 3269 | fn 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 | |||
| 3268 | fn airShuffle(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 3279 | fn 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 = {} }; |
| 3270 | 3281 |
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 | } |
| 5680 | 5681 | ||
| 5682 | fn 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 | |||
| 5681 | fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { | 5689 | fn 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 | } |
| 3796 | 3797 | ||
| 3798 | fn 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 | |||
| 3797 | fn airShuffle(f: *Function, inst: Air.Inst.Index) !CValue { | 3813 | fn 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; |
| 3799 | 3815 |
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 | } |
| 6357 | 6358 | ||
| 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; |
| 6360 | 6373 |
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 | } |
| 398 | 399 | ||
| 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; |
| 401 | 414 |
test/behavior/select.zig+23-17| ... | @@ -4,23 +4,29 @@ const mem = std.mem; | ... | @@ -4,23 +4,29 @@ const mem = std.mem; |
| 4 | const expect = std.testing.expect; | 4 | const expect = std.testing.expect; |
| 5 | 5 | ||
| 6 | test "@select" { | 6 | test "@select" { |
| 7 | if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO | 7 | 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 | ||
| 8 | 12 | ||
| 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 }; | 17 | fn 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); | ||
| 16 | 26 | ||
| 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 | } |