| ... | @@ -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), |
| 2207 | | 2208 | |
| ... | @@ -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 | } | | |
| 3180 | | 3180 | |
| 3181 | // TODO: Some more cases are missing here | 3181 | const result_id = blk: { |
| 3182 | // See fn bitCast in llvm.zig | 3182 | if (src_ty_ref == dst_ty_ref) { |
| | 3183 | break :blk src_id; |
| | 3184 | } |
| 3183 | | 3185 | |
| 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 | } | | |
| 3193 | | 3188 | |
| 3194 | // We can only use OpBitcast for specific conversions: between numerical types, and | 3189 | 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 | } |
| 3199 | | 3212 | |
| 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 | }; |
| 3209 | | 3225 | |
| 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 | } |
| 3211 | | 3234 | |
| 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 | } |
| 3222 | | 3237 | |
| 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 | } |
| 3342 | | 3357 | |
| | 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; |
| 3345 | | 3376 | |