authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2024-01-21 01:41:41+01:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2024-02-04 19:09:29+01:00
log345d6e280de1566000bf58ccd6683541cf601459
tree3a9eb6b2ec7d9809f812c63b27e79dd9b350992b
parent77ef78a0ef00392c4e157ebc170d6c4d98f586fb
signaturebadge-check Signed by SSH key SHA256:ZS52FNyUv2WUXvO4njmVaFVO46RHojFuOrxRc4LuKzg

spirv: air int_from_bool


3 files changed, 67 insertions(+), 39 deletions(-)

src/codegen/spirv.zig+67-36
...@@ -2202,6 +2202,7 @@ const DeclGen = struct {...@@ -2202,6 +2202,7 @@ const DeclGen = struct {
2202 .int_from_ptr => try self.airIntFromPtr(inst),2202 .int_from_ptr => try self.airIntFromPtr(inst),
2203 .float_from_int => try self.airFloatFromInt(inst),2203 .float_from_int => try self.airFloatFromInt(inst),
2204 .int_from_float => try self.airIntFromFloat(inst),2204 .int_from_float => try self.airIntFromFloat(inst),
2205 .int_from_bool => try self.airIntFromBool(inst),
2205 .fpext, .fptrunc => try self.airFloatCast(inst),2206 .fpext, .fptrunc => try self.airFloatCast(inst),
2206 .not => try self.airNot(inst),2207 .not => try self.airNot(inst),
22072208
...@@ -3174,50 +3175,64 @@ const DeclGen = struct {...@@ -3174,50 +3175,64 @@ const DeclGen = struct {
3174 const mod = self.module;3175 const mod = self.module;
3175 const src_ty_ref = try self.resolveType(src_ty, .direct);3176 const src_ty_ref = try self.resolveType(src_ty, .direct);
3176 const dst_ty_ref = try self.resolveType(dst_ty, .direct);3177 const dst_ty_ref = try self.resolveType(dst_ty, .direct);
3177 if (src_ty_ref == dst_ty_ref) {3178 const src_key = self.spv.cache.lookup(src_ty_ref);
3178 return src_id;3179 const dst_key = self.spv.cache.lookup(dst_ty_ref);
3179 }
31803180
3181 // TODO: Some more cases are missing here3181 const result_id = blk: {
3182 // See fn bitCast in llvm.zig3182 if (src_ty_ref == dst_ty_ref) {
3183 break :blk src_id;
3184 }
31833185
3184 if (src_ty.zigTypeTag(mod) == .Int and dst_ty.isPtrAtRuntime(mod)) {3186 // TODO: Some more cases are missing here
3185 const result_id = self.spv.allocId();3187 // See fn bitCast in llvm.zig
3186 try self.func.body.emit(self.spv.gpa, .OpConvertUToPtr, .{
3187 .id_result_type = self.typeId(dst_ty_ref),
3188 .id_result = result_id,
3189 .integer_value = src_id,
3190 });
3191 return result_id;
3192 }
31933188
3194 // We can only use OpBitcast for specific conversions: between numerical types, and3189 if (src_ty.zigTypeTag(mod) == .Int and dst_ty.isPtrAtRuntime(mod)) {
3195 // between pointers. If the resolved spir-v types fall into this category then emit OpBitcast,3190 const result_id = self.spv.allocId();
3196 // otherwise use a temporary and perform a pointer cast.3191 try self.func.body.emit(self.spv.gpa, .OpConvertUToPtr, .{
3197 const src_key = self.spv.cache.lookup(src_ty_ref);3192 .id_result_type = self.typeId(dst_ty_ref),
3198 const dst_key = self.spv.cache.lookup(dst_ty_ref);3193 .id_result = result_id,
3194 .integer_value = src_id,
3195 });
3196 break :blk result_id;
3197 }
3198
3199 // We can only use OpBitcast for specific conversions: between numerical types, and
3200 // between pointers. If the resolved spir-v types fall into this category then emit OpBitcast,
3201 // otherwise use a temporary and perform a pointer cast.
3202 if ((src_key.isNumericalType() and dst_key.isNumericalType()) or (src_key == .ptr_type and dst_key == .ptr_type)) {
3203 const result_id = self.spv.allocId();
3204 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{
3205 .id_result_type = self.typeId(dst_ty_ref),
3206 .id_result = result_id,
3207 .operand = src_id,
3208 });
3209
3210 break :blk result_id;
3211 }
31993212
3200 if ((src_key.isNumericalType() and dst_key.isNumericalType()) or (src_key == .ptr_type and dst_key == .ptr_type)) {3213 const dst_ptr_ty_ref = try self.ptrType(dst_ty, .Function);
3201 const result_id = self.spv.allocId();3214
3215 const tmp_id = try self.alloc(src_ty, .{ .storage_class = .Function });
3216 try self.store(src_ty, tmp_id, src_id, .{});
3217 const casted_ptr_id = self.spv.allocId();
3202 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{3218 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{
3203 .id_result_type = self.typeId(dst_ty_ref),3219 .id_result_type = self.typeId(dst_ptr_ty_ref),
3204 .id_result = result_id,3220 .id_result = casted_ptr_id,
3205 .operand = src_id,3221 .operand = tmp_id,
3206 });3222 });
3207 return result_id;3223 break :blk try self.load(dst_ty, casted_ptr_id, .{});
3208 }3224 };
32093225
3210 const dst_ptr_ty_ref = try self.ptrType(dst_ty, .Function);3226 // Because strange integers use sign-extended representation, we may need to normalize
3227 // the result here.
3228 // TODO: This detail could cause stuff like @as(*const i1, @ptrCast(&@as(u1, 1))) to break
3229 // should we change the representation of strange integers?
3230 if (dst_ty.zigTypeTag(mod) == .Int) {
3231 const info = self.arithmeticTypeInfo(dst_ty);
3232 return try self.normalize(dst_ty_ref, result_id, info);
3233 }
32113234
3212 const tmp_id = try self.alloc(src_ty, .{ .storage_class = .Function });3235 return result_id;
3213 try self.store(src_ty, tmp_id, src_id, .{});
3214 const casted_ptr_id = self.spv.allocId();
3215 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{
3216 .id_result_type = self.typeId(dst_ptr_ty_ref),
3217 .id_result = casted_ptr_id,
3218 .operand = tmp_id,
3219 });
3220 return try self.load(dst_ty, casted_ptr_id, .{});
3221 }3236 }
32223237
3223 fn airBitCast(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {3238 fn airBitCast(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
...@@ -3340,6 +3355,22 @@ const DeclGen = struct {...@@ -3340,6 +3355,22 @@ const DeclGen = struct {
3340 return result_id;3355 return result_id;
3341 }3356 }
33423357
3358 fn airIntFromBool(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
3359 if (self.liveness.isUnused(inst)) return null;
3360
3361 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
3362 const operand_id = try self.resolve(un_op);
3363 const result_ty = self.typeOfIndex(inst);
3364
3365 var wip = try self.elementWise(result_ty);
3366 defer wip.deinit();
3367 for (wip.results, 0..) |*result_id, i| {
3368 const elem_id = try wip.elementAt(Type.bool, operand_id, i);
3369 result_id.* = try self.intFromBool(wip.scalar_ty_ref, elem_id);
3370 }
3371 return try wip.finalize();
3372 }
3373
3343 fn airFloatCast(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {3374 fn airFloatCast(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
3344 if (self.liveness.isUnused(inst)) return null;3375 if (self.liveness.isUnused(inst)) return null;
33453376
test/behavior/bool.zig-2
...@@ -9,8 +9,6 @@ test "bool literals" {...@@ -9,8 +9,6 @@ test "bool literals" {
9}9}
1010
11test "cast bool to int" {11test "cast bool to int" {
12 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
13
14 const t = true;12 const t = true;
15 const f = false;13 const f = false;
16 try expectEqual(@as(u32, 1), @intFromBool(t));14 try expectEqual(@as(u32, 1), @intFromBool(t));
test/behavior/cast.zig-1
...@@ -2430,7 +2430,6 @@ test "@intFromBool on vector" {...@@ -2430,7 +2430,6 @@ test "@intFromBool on vector" {
2430 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO2430 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2431 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2431 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2432 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2432 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2433 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
24342433
2435 const S = struct {2434 const S = struct {
2436 fn doTheTest() !void {2435 fn doTheTest() !void {