| ... | ... | @@ -2187,6 +2187,7 @@ const DeclGen = struct { |
| 2187 | 2187 | .sub_with_overflow => try self.airAddSubOverflow(inst, .OpISub, .OpUGreaterThan, .OpSGreaterThan), |
| 2188 | 2188 | .shl_with_overflow => try self.airShlOverflow(inst), |
| 2189 | 2189 | |
| 2190 | .reduce, .reduce_optimized => try self.airReduce(inst), |
| 2190 | 2191 | .shuffle => try self.airShuffle(inst), |
| 2191 | 2192 | |
| 2192 | 2193 | .ptr_add => try self.airPtrAdd(inst), |
| ... | ... | @@ -2388,9 +2389,14 @@ const DeclGen = struct { |
| 2388 | 2389 | const lhs_id = try self.resolve(bin_op.lhs); |
| 2389 | 2390 | const rhs_id = try self.resolve(bin_op.rhs); |
| 2390 | 2391 | const result_ty = self.typeOfIndex(inst); |
| 2391 | | const result_ty_ref = try self.resolveType(result_ty, .direct); |
| 2392 | 2392 | |
| 2393 | return try self.minMax(result_ty, op, lhs_id, rhs_id); |
| 2394 | } |
| 2395 | |
| 2396 | fn minMax(self: *DeclGen, result_ty: Type, op: std.math.CompareOperator, lhs_id: IdRef, rhs_id: IdRef) !IdRef { |
| 2397 | const result_ty_ref = try self.resolveType(result_ty, .direct); |
| 2393 | 2398 | const info = try self.arithmeticTypeInfo(result_ty); |
| 2399 | |
| 2394 | 2400 | // TODO: Use fmin for OpenCL |
| 2395 | 2401 | const cmp_id = try self.cmp(op, Type.bool, result_ty, lhs_id, rhs_id); |
| 2396 | 2402 | const selection_id = switch (info.class) { |
| ... | ... | @@ -2758,6 +2764,73 @@ const DeclGen = struct { |
| 2758 | 2764 | ); |
| 2759 | 2765 | } |
| 2760 | 2766 | |
| 2767 | fn airReduce(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2768 | if (self.liveness.isUnused(inst)) return null; |
| 2769 | const mod = self.module; |
| 2770 | const reduce = self.air.instructions.items(.data)[@intFromEnum(inst)].reduce; |
| 2771 | const operand = try self.resolve(reduce.operand); |
| 2772 | const operand_ty = self.typeOf(reduce.operand); |
| 2773 | const scalar_ty = operand_ty.scalarType(mod); |
| 2774 | const scalar_ty_ref = try self.resolveType(scalar_ty, .direct); |
| 2775 | const scalar_ty_id = self.typeId(scalar_ty_ref); |
| 2776 | |
| 2777 | const info = try self.arithmeticTypeInfo(operand_ty); |
| 2778 | |
| 2779 | var result_id = try self.extractField(scalar_ty, operand, 0); |
| 2780 | const len = operand_ty.vectorLen(mod); |
| 2781 | |
| 2782 | switch (reduce.operation) { |
| 2783 | .Min, .Max => |op| { |
| 2784 | const cmp_op: std.math.CompareOperator = if (op == .Max) .gt else .lt; |
| 2785 | for (1..len) |i| { |
| 2786 | const lhs = result_id; |
| 2787 | const rhs = try self.extractField(scalar_ty, operand, @intCast(i)); |
| 2788 | result_id = try self.minMax(scalar_ty, cmp_op, lhs, rhs); |
| 2789 | } |
| 2790 | |
| 2791 | return result_id; |
| 2792 | }, |
| 2793 | else => {}, |
| 2794 | } |
| 2795 | |
| 2796 | const opcode: Opcode = switch (info.class) { |
| 2797 | .bool => switch (reduce.operation) { |
| 2798 | .And => .OpLogicalAnd, |
| 2799 | .Or => .OpLogicalOr, |
| 2800 | .Xor => .OpLogicalNotEqual, |
| 2801 | else => unreachable, |
| 2802 | }, |
| 2803 | .strange_integer, .integer => switch (reduce.operation) { |
| 2804 | .And => .OpBitwiseAnd, |
| 2805 | .Or => .OpBitwiseOr, |
| 2806 | .Xor => .OpBitwiseXor, |
| 2807 | .Add => .OpIAdd, |
| 2808 | .Mul => .OpIMul, |
| 2809 | else => unreachable, |
| 2810 | }, |
| 2811 | .float => switch (reduce.operation) { |
| 2812 | .Add => .OpFAdd, |
| 2813 | .Mul => .OpFMul, |
| 2814 | else => unreachable, |
| 2815 | }, |
| 2816 | .composite_integer => unreachable, // TODO |
| 2817 | }; |
| 2818 | |
| 2819 | for (1..len) |i| { |
| 2820 | const lhs = result_id; |
| 2821 | const rhs = try self.extractField(scalar_ty, operand, @intCast(i)); |
| 2822 | result_id = self.spv.allocId(); |
| 2823 | |
| 2824 | try self.func.body.emitRaw(self.spv.gpa, opcode, 4); |
| 2825 | self.func.body.writeOperand(spec.IdResultType, scalar_ty_id); |
| 2826 | self.func.body.writeOperand(spec.IdResult, result_id); |
| 2827 | self.func.body.writeOperand(spec.IdResultType, lhs); |
| 2828 | self.func.body.writeOperand(spec.IdResultType, rhs); |
| 2829 | } |
| 2830 | |
| 2831 | return result_id; |
| 2832 | } |
| 2833 | |
| 2761 | 2834 | fn airShuffle(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2762 | 2835 | const mod = self.module; |
| 2763 | 2836 | if (self.liveness.isUnused(inst)) return null; |