Commit 9c550721e4

Ali Chraghi <alichraghi@proton.me>
2023-05-15 01:32:11
spirv: lower float_to_int and int_to_float
1 parent 2ce9122
Changed files (5)
src/codegen/spirv.zig
@@ -568,6 +568,28 @@ pub const DeclGen = struct {
             try self.addBytes(std.mem.asBytes(&int_bits)[0..@intCast(usize, len)]);
         }
 
+        fn addFloat(self: *@This(), ty: Type, val: Value) !void {
+            const target = self.dg.getTarget();
+            const len = ty.abiSize(target);
+
+            // TODO: Swap endianess if the compiler is big endian.
+            switch (ty.floatBits(target)) {
+                16 => {
+                    const float_bits = val.toFloat(f16);
+                    try self.addBytes(std.mem.asBytes(&float_bits)[0..@intCast(usize, len)]);
+                },
+                32 => {
+                    const float_bits = val.toFloat(f32);
+                    try self.addBytes(std.mem.asBytes(&float_bits)[0..@intCast(usize, len)]);
+                },
+                64 => {
+                    const float_bits = val.toFloat(f64);
+                    try self.addBytes(std.mem.asBytes(&float_bits)[0..@intCast(usize, len)]);
+                },
+                else => unreachable,
+            }
+        }
+
         fn addDeclRef(self: *@This(), ty: Type, decl_index: Decl.Index) !void {
             const dg = self.dg;
 
@@ -618,6 +640,7 @@ pub const DeclGen = struct {
 
             switch (ty.zigTypeTag()) {
                 .Int => try self.addInt(ty, val),
+                .Float => try self.addFloat(ty, val),
                 .Bool => try self.addConstBool(val.toBool()),
                 .Array => switch (val.tag()) {
                     .aggregate => {
@@ -1690,6 +1713,8 @@ pub const DeclGen = struct {
 
             .bitcast         => try self.airBitcast(inst),
             .intcast, .trunc => try self.airIntcast(inst),
+            .int_to_float    => try self.airIntToFloat(inst),
+            .float_to_int    => try self.airFloatToInt(inst),
             .not             => try self.airNot(inst),
 
             .slice_ptr      => try self.airSliceField(inst, 0),
@@ -2095,6 +2120,57 @@ pub const DeclGen = struct {
         return result_id;
     }
 
+    fn airIntToFloat(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
+        if (self.liveness.isUnused(inst)) return null;
+
+        const ty_op = self.air.instructions.items(.data)[inst].ty_op;
+        const operand_ty = self.air.typeOf(ty_op.operand);
+        const operand_id = try self.resolve(ty_op.operand);
+        const operand_info = try self.arithmeticTypeInfo(operand_ty);
+        const dest_ty = self.air.typeOfIndex(inst);
+        const dest_ty_id = try self.resolveTypeId(dest_ty);
+
+        const result_id = self.spv.allocId();
+        switch (operand_info.signedness) {
+            .signed => try self.func.body.emit(self.spv.gpa, .OpConvertSToF, .{
+                .id_result_type = dest_ty_id,
+                .id_result = result_id,
+                .signed_value = operand_id,
+            }),
+            .unsigned => try self.func.body.emit(self.spv.gpa, .OpConvertUToF, .{
+                .id_result_type = dest_ty_id,
+                .id_result = result_id,
+                .unsigned_value = operand_id,
+            }),
+        }
+        return result_id;
+    }
+
+    fn airFloatToInt(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
+        if (self.liveness.isUnused(inst)) return null;
+
+        const ty_op = self.air.instructions.items(.data)[inst].ty_op;
+        const operand_id = try self.resolve(ty_op.operand);
+        const dest_ty = self.air.typeOfIndex(inst);
+        const dest_info = try self.arithmeticTypeInfo(dest_ty);
+        const dest_ty_id = try self.resolveTypeId(dest_ty);
+
+        const result_id = self.spv.allocId();
+        switch (dest_info.signedness) {
+            .signed => try self.func.body.emit(self.spv.gpa, .OpConvertFToS, .{
+                .id_result_type = dest_ty_id,
+                .id_result = result_id,
+                .float_value = operand_id,
+            }),
+            .unsigned => try self.func.body.emit(self.spv.gpa, .OpConvertFToU, .{
+                .id_result_type = dest_ty_id,
+                .id_result = result_id,
+                .float_value = operand_id,
+            }),
+        }
+        return result_id;
+    }
+
     fn airNot(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
         if (self.liveness.isUnused(inst)) return null;
         const ty_op = self.air.instructions.items(.data)[inst].ty_op;
test/behavior/cast.zig
@@ -97,7 +97,6 @@ test "@intToFloat" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
 
     const S = struct {
         fn doTheTest() !void {
@@ -156,7 +155,6 @@ test "@floatToInt" {
     if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
 
     try testFloatToInts();
     comptime try testFloatToInts();
@@ -208,16 +206,12 @@ test "implicitly cast indirect pointer to maybe-indirect pointer" {
 }
 
 test "@intCast comptime_int" {
-    if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
-
     const result = @intCast(i32, 1234);
     try expect(@TypeOf(result) == i32);
     try expect(result == 1234);
 }
 
 test "@floatCast comptime_int and comptime_float" {
-    if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
-
     {
         const result = @floatCast(f16, 1234);
         try expect(@TypeOf(result) == f16);
test/behavior/error.zig
@@ -916,6 +916,7 @@ test "optional error set return type" {
 test "try used in recursive function with inferred error set" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
 
     const Value = union(enum) {
         values: []const @This(),
test/behavior/maximum_minimum.zig
@@ -106,6 +106,7 @@ test "@min/max for floats" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
 
     const S = struct {
         fn doTheTest(comptime T: type) !void {
test/behavior/slice.zig
@@ -186,6 +186,8 @@ test "slicing zero length array" {
 
 test "slicing pointer by length" {
     if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
+    if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
+
     const array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };
     const ptr: [*]const u8 = @ptrCast([*]const u8, &array);
     const slice = ptr[1..][0..5];