authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2024-01-21 12:17:19+01:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2024-02-04 19:09:30+01:00
log7dfd403da1cd0f25e500ed67b2dfd21c669491fa
tree595bf2aa4854f712f2f41a6b27769c8ff8ee97ad
parent345d6e280de1566000bf58ccd6683541cf601459
signaturebadge-check Signed by SSH key SHA256:ZS52FNyUv2WUXvO4njmVaFVO46RHojFuOrxRc4LuKzg

spirv: air mul_add


2 files changed, 73 insertions(+), 42 deletions(-)

src/codegen/spirv.zig+73-37
......@@ -2160,9 +2160,9 @@ const DeclGen = struct {
21602160 const air_tags = self.air.instructions.items(.tag);
21612161 const maybe_result_id: ?IdRef = switch (air_tags[@intFromEnum(inst)]) {
21622162 // zig fmt: off
2163 .add, .add_wrap => try self.airArithOp(inst, .OpFAdd, .OpIAdd, .OpIAdd),
2164 .sub, .sub_wrap => try self.airArithOp(inst, .OpFSub, .OpISub, .OpISub),
2165 .mul, .mul_wrap => try self.airArithOp(inst, .OpFMul, .OpIMul, .OpIMul),
2163 .add, .add_wrap, .add_optimized => try self.airArithOp(inst, .OpFAdd, .OpIAdd, .OpIAdd),
2164 .sub, .sub_wrap, .sub_optimized => try self.airArithOp(inst, .OpFSub, .OpISub, .OpISub),
2165 .mul, .mul_wrap, .mul_optimized => try self.airArithOp(inst, .OpFMul, .OpIMul, .OpIMul),
21662166
21672167 .div_float,
21682168 .div_float_optimized,
......@@ -2179,6 +2179,8 @@ const DeclGen = struct {
21792179 .sub_with_overflow => try self.airAddSubOverflow(inst, .OpISub, .OpUGreaterThan, .OpSGreaterThan),
21802180 .shl_with_overflow => try self.airShlOverflow(inst),
21812181
2182 .mul_add => try self.airMulAdd(inst),
2183
21822184 .reduce, .reduce_optimized => try self.airReduce(inst),
21832185 .shuffle => try self.airShuffle(inst),
21842186
......@@ -2439,40 +2441,38 @@ const DeclGen = struct {
24392441 switch (info.class) {
24402442 .integer, .bool, .float => return value_id,
24412443 .composite_integer => unreachable, // TODO
2442 .strange_integer => {
2443 switch (info.signedness) {
2444 .unsigned => {
2445 const mask_value = if (info.bits == 64) 0xFFFF_FFFF_FFFF_FFFF else (@as(u64, 1) << @as(u6, @intCast(info.bits))) - 1;
2446 const result_id = self.spv.allocId();
2447 const mask_id = try self.constInt(ty_ref, mask_value);
2448 try self.func.body.emit(self.spv.gpa, .OpBitwiseAnd, .{
2449 .id_result_type = self.typeId(ty_ref),
2450 .id_result = result_id,
2451 .operand_1 = value_id,
2452 .operand_2 = mask_id,
2453 });
2454 return result_id;
2455 },
2456 .signed => {
2457 // Shift left and right so that we can copy the sight bit that way.
2458 const shift_amt_id = try self.constInt(ty_ref, info.backing_bits - info.bits);
2459 const left_id = self.spv.allocId();
2460 try self.func.body.emit(self.spv.gpa, .OpShiftLeftLogical, .{
2461 .id_result_type = self.typeId(ty_ref),
2462 .id_result = left_id,
2463 .base = value_id,
2464 .shift = shift_amt_id,
2465 });
2466 const right_id = self.spv.allocId();
2467 try self.func.body.emit(self.spv.gpa, .OpShiftRightArithmetic, .{
2468 .id_result_type = self.typeId(ty_ref),
2469 .id_result = right_id,
2470 .base = left_id,
2471 .shift = shift_amt_id,
2472 });
2473 return right_id;
2474 },
2475 }
2444 .strange_integer => switch (info.signedness) {
2445 .unsigned => {
2446 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();
2448 const mask_id = try self.constInt(ty_ref, mask_value);
2449 try self.func.body.emit(self.spv.gpa, .OpBitwiseAnd, .{
2450 .id_result_type = self.typeId(ty_ref),
2451 .id_result = result_id,
2452 .operand_1 = value_id,
2453 .operand_2 = mask_id,
2454 });
2455 return result_id;
2456 },
2457 .signed => {
2458 // 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);
2460 const left_id = self.spv.allocId();
2461 try self.func.body.emit(self.spv.gpa, .OpShiftLeftLogical, .{
2462 .id_result_type = self.typeId(ty_ref),
2463 .id_result = left_id,
2464 .base = value_id,
2465 .shift = shift_amt_id,
2466 });
2467 const right_id = self.spv.allocId();
2468 try self.func.body.emit(self.spv.gpa, .OpShiftRightArithmetic, .{
2469 .id_result_type = self.typeId(ty_ref),
2470 .id_result = right_id,
2471 .base = left_id,
2472 .shift = shift_amt_id,
2473 });
2474 return right_id;
2475 },
24762476 },
24772477 }
24782478 }
......@@ -2761,6 +2761,42 @@ const DeclGen = struct {
27612761 );
27622762 }
27632763
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
27642800 fn airReduce(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
27652801 if (self.liveness.isUnused(inst)) return null;
27662802 const mod = self.module;
test/behavior/muladd.zig-5
......@@ -10,7 +10,6 @@ test "@mulAdd" {
1010 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1111 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1212 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1413
1514 try comptime testMulAdd();
1615 try testMulAdd();
......@@ -37,7 +36,6 @@ test "@mulAdd f16" {
3736 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
3837 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
3938 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
40 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
4139 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
4240
4341 try comptime testMulAdd16();
......@@ -111,7 +109,6 @@ test "vector f16" {
111109 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
112110 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
113111 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
114 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
115112
116113 try comptime vector16();
117114 try vector16();
......@@ -136,7 +133,6 @@ test "vector f32" {
136133 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
137134 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
138135 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
139 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
140136
141137 try comptime vector32();
142138 try vector32();
......@@ -161,7 +157,6 @@ test "vector f64" {
161157 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
162158 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
163159 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
164 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
165160
166161 try comptime vector64();
167162 try vector64();