| ... | @@ -2160,9 +2160,9 @@ const DeclGen = struct { | ... | @@ -2160,9 +2160,9 @@ const DeclGen = struct { |
| 2160 | const air_tags = self.air.instructions.items(.tag); | 2160 | const air_tags = self.air.instructions.items(.tag); |
| 2161 | const maybe_result_id: ?IdRef = switch (air_tags[@intFromEnum(inst)]) { | 2161 | const maybe_result_id: ?IdRef = switch (air_tags[@intFromEnum(inst)]) { |
| 2162 | // zig fmt: off | 2162 | // zig fmt: off |
| 2163 | .add, .add_wrap => try self.airArithOp(inst, .OpFAdd, .OpIAdd, .OpIAdd), | 2163 | .add, .add_wrap, .add_optimized => try self.airArithOp(inst, .OpFAdd, .OpIAdd, .OpIAdd), |
| 2164 | .sub, .sub_wrap => try self.airArithOp(inst, .OpFSub, .OpISub, .OpISub), | 2164 | .sub, .sub_wrap, .sub_optimized => try self.airArithOp(inst, .OpFSub, .OpISub, .OpISub), |
| 2165 | .mul, .mul_wrap => try self.airArithOp(inst, .OpFMul, .OpIMul, .OpIMul), | 2165 | .mul, .mul_wrap, .mul_optimized => try self.airArithOp(inst, .OpFMul, .OpIMul, .OpIMul), |
| 2166 | | 2166 | |
| 2167 | .div_float, | 2167 | .div_float, |
| 2168 | .div_float_optimized, | 2168 | .div_float_optimized, |
| ... | @@ -2179,6 +2179,8 @@ const DeclGen = struct { | ... | @@ -2179,6 +2179,8 @@ const DeclGen = struct { |
| 2179 | .sub_with_overflow => try self.airAddSubOverflow(inst, .OpISub, .OpUGreaterThan, .OpSGreaterThan), | 2179 | .sub_with_overflow => try self.airAddSubOverflow(inst, .OpISub, .OpUGreaterThan, .OpSGreaterThan), |
| 2180 | .shl_with_overflow => try self.airShlOverflow(inst), | 2180 | .shl_with_overflow => try self.airShlOverflow(inst), |
| 2181 | | 2181 | |
| | 2182 | .mul_add => try self.airMulAdd(inst), |
| | 2183 | |
| 2182 | .reduce, .reduce_optimized => try self.airReduce(inst), | 2184 | .reduce, .reduce_optimized => try self.airReduce(inst), |
| 2183 | .shuffle => try self.airShuffle(inst), | 2185 | .shuffle => try self.airShuffle(inst), |
| 2184 | | 2186 | |
| ... | @@ -2439,40 +2441,38 @@ const DeclGen = struct { | ... | @@ -2439,40 +2441,38 @@ const DeclGen = struct { |
| 2439 | switch (info.class) { | 2441 | switch (info.class) { |
| 2440 | .integer, .bool, .float => return value_id, | 2442 | .integer, .bool, .float => return value_id, |
| 2441 | .composite_integer => unreachable, // TODO | 2443 | .composite_integer => unreachable, // TODO |
| 2442 | .strange_integer => { | 2444 | .strange_integer => switch (info.signedness) { |
| 2443 | switch (info.signedness) { | 2445 | .unsigned => { |
| 2444 | .unsigned => { | 2446 | const mask_value = if (info.bits == 64) 0xFFFF_FFFF_FFFF_FFFF else (@as(u64, 1) << @as(u6, @intCast(info.bits))) - 1; |
| 2445 | const mask_value = if (info.bits == 64) 0xFFFF_FFFF_FFFF_FFFF else (@as(u64, 1) << @as(u6, @intCast(info.bits))) - 1; | 2447 | const result_id = self.spv.allocId(); |
| 2446 | const result_id = self.spv.allocId(); | 2448 | const mask_id = try self.constInt(ty_ref, mask_value); |
| 2447 | const mask_id = try self.constInt(ty_ref, mask_value); | 2449 | try self.func.body.emit(self.spv.gpa, .OpBitwiseAnd, .{ |
| 2448 | try self.func.body.emit(self.spv.gpa, .OpBitwiseAnd, .{ | 2450 | .id_result_type = self.typeId(ty_ref), |
| 2449 | .id_result_type = self.typeId(ty_ref), | 2451 | .id_result = result_id, |
| 2450 | .id_result = result_id, | 2452 | .operand_1 = value_id, |
| 2451 | .operand_1 = value_id, | 2453 | .operand_2 = mask_id, |
| 2452 | .operand_2 = mask_id, | 2454 | }); |
| 2453 | }); | 2455 | return result_id; |
| 2454 | return result_id; | 2456 | }, |
| 2455 | }, | 2457 | .signed => { |
| 2456 | .signed => { | 2458 | // Shift left and right so that we can copy the sight bit that way. |
| 2457 | // Shift left and right so that we can copy the sight bit that way. | 2459 | const shift_amt_id = try self.constInt(ty_ref, info.backing_bits - info.bits); |
| 2458 | const shift_amt_id = try self.constInt(ty_ref, info.backing_bits - info.bits); | 2460 | const left_id = self.spv.allocId(); |
| 2459 | const left_id = self.spv.allocId(); | 2461 | try self.func.body.emit(self.spv.gpa, .OpShiftLeftLogical, .{ |
| 2460 | try self.func.body.emit(self.spv.gpa, .OpShiftLeftLogical, .{ | 2462 | .id_result_type = self.typeId(ty_ref), |
| 2461 | .id_result_type = self.typeId(ty_ref), | 2463 | .id_result = left_id, |
| 2462 | .id_result = left_id, | 2464 | .base = value_id, |
| 2463 | .base = value_id, | 2465 | .shift = shift_amt_id, |
| 2464 | .shift = shift_amt_id, | 2466 | }); |
| 2465 | }); | 2467 | const right_id = self.spv.allocId(); |
| 2466 | const right_id = self.spv.allocId(); | 2468 | try self.func.body.emit(self.spv.gpa, .OpShiftRightArithmetic, .{ |
| 2467 | try self.func.body.emit(self.spv.gpa, .OpShiftRightArithmetic, .{ | 2469 | .id_result_type = self.typeId(ty_ref), |
| 2468 | .id_result_type = self.typeId(ty_ref), | 2470 | .id_result = right_id, |
| 2469 | .id_result = right_id, | 2471 | .base = left_id, |
| 2470 | .base = left_id, | 2472 | .shift = shift_amt_id, |
| 2471 | .shift = shift_amt_id, | 2473 | }); |
| 2472 | }); | 2474 | return right_id; |
| 2473 | return right_id; | 2475 | }, |
| 2474 | }, | | |
| 2475 | } | | |
| 2476 | }, | 2476 | }, |
| 2477 | } | 2477 | } |
| 2478 | } | 2478 | } |
| ... | @@ -2761,6 +2761,42 @@ const DeclGen = struct { | ... | @@ -2761,6 +2761,42 @@ const DeclGen = struct { |
| 2761 | ); | 2761 | ); |
| 2762 | } | 2762 | } |
| 2763 | | 2763 | |
| | 2764 | fn airMulAdd(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| | 2765 | if (self.liveness.isUnused(inst)) return null; |
| | 2766 | |
| | 2767 | const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; |
| | 2768 | const extra = self.air.extraData(Air.Bin, pl_op.payload).data; |
| | 2769 | |
| | 2770 | const mulend1 = try self.resolve(extra.lhs); |
| | 2771 | const mulend2 = try self.resolve(extra.rhs); |
| | 2772 | const addend = try self.resolve(pl_op.operand); |
| | 2773 | |
| | 2774 | const ty = self.typeOfIndex(inst); |
| | 2775 | |
| | 2776 | const info = self.arithmeticTypeInfo(ty); |
| | 2777 | assert(info.class == .float); // .mul_add is only emitted for floats |
| | 2778 | |
| | 2779 | var wip = try self.elementWise(ty); |
| | 2780 | defer wip.deinit(); |
| | 2781 | for (0..wip.results.len) |i| { |
| | 2782 | const mul_result = self.spv.allocId(); |
| | 2783 | try self.func.body.emit(self.spv.gpa, .OpFMul, .{ |
| | 2784 | .id_result_type = wip.scalar_ty_id, |
| | 2785 | .id_result = mul_result, |
| | 2786 | .operand_1 = try wip.elementAt(ty, mulend1, i), |
| | 2787 | .operand_2 = try wip.elementAt(ty, mulend2, i), |
| | 2788 | }); |
| | 2789 | |
| | 2790 | try self.func.body.emit(self.spv.gpa, .OpFAdd, .{ |
| | 2791 | .id_result_type = wip.scalar_ty_id, |
| | 2792 | .id_result = wip.allocId(i), |
| | 2793 | .operand_1 = mul_result, |
| | 2794 | .operand_2 = try wip.elementAt(ty, addend, i), |
| | 2795 | }); |
| | 2796 | } |
| | 2797 | return try wip.finalize(); |
| | 2798 | } |
| | 2799 | |
| 2764 | fn airReduce(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 2800 | fn airReduce(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2765 | if (self.liveness.isUnused(inst)) return null; | 2801 | if (self.liveness.isUnused(inst)) return null; |
| 2766 | const mod = self.module; | 2802 | const mod = self.module; |