| ... | ... | @@ -4229,61 +4229,20 @@ pub const FuncGen = struct { |
| 4229 | 4229 | return self.builder.buildInsertValue(partial, len, 1, ""); |
| 4230 | 4230 | } |
| 4231 | 4231 | |
| 4232 | | inline fn isPowerOfTwo(bits: u64) bool { |
| 4233 | | return bits != 0 and ((bits & (~bits + 1)) == bits); |
| 4234 | | } |
| 4235 | | |
| 4236 | | fn intTypeFromBitsAndSignRounded(self: *FuncGen, bits: u16, signed: bool) error{OutOfMemory}!Type { |
| 4237 | | const next_pow_two = math.log2_int_ceil(u16, bits); |
| 4238 | | const rounded_bits = @as(u32, 1) << next_pow_two; |
| 4239 | | return switch (rounded_bits) { |
| 4240 | | 8, 16, 32 => if (signed) Type.initTag(.i32) else Type.initTag(.u32), |
| 4241 | | 64 => if (signed) Type.initTag(.i64) else Type.initTag(.u64), |
| 4242 | | 128 => if (signed) Type.initTag(.i128) else Type.initTag(.u128), |
| 4243 | | else => |big| if (signed) |
| 4244 | | Type.Tag.int_signed.create( |
| 4245 | | self.dg.object.type_map_arena.allocator(), |
| 4246 | | @intCast(u16, big), |
| 4247 | | ) |
| 4248 | | else |
| 4249 | | Type.Tag.int_unsigned.create( |
| 4250 | | self.dg.object.type_map_arena.allocator(), |
| 4251 | | @intCast(u16, big), |
| 4252 | | ), |
| 4253 | | }; |
| 4254 | | } |
| 4255 | | |
| 4256 | 4232 | fn airIntToFloat(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| 4257 | 4233 | if (self.liveness.isUnused(inst)) |
| 4258 | 4234 | return null; |
| 4259 | 4235 | |
| 4260 | | const target = self.dg.module.getTarget(); |
| 4261 | 4236 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 4262 | 4237 | |
| 4263 | | var operand = try self.resolveInst(ty_op.operand); |
| 4264 | | var operand_ty = self.air.typeOf(ty_op.operand); |
| 4265 | | var operand_scalar_ty = operand_ty.scalarType(); |
| 4266 | | |
| 4267 | | { |
| 4268 | | const operand_bits = @intCast(u16, operand_scalar_ty.bitSize(target)); |
| 4269 | | const is_signed = operand_scalar_ty.isSignedInt(); |
| 4270 | | |
| 4271 | | if (!isPowerOfTwo(operand_bits) or operand_bits < 32) { |
| 4272 | | const wider_ty = try self.intTypeFromBitsAndSignRounded(operand_bits, is_signed); |
| 4273 | | const wider_llvm_ty = try self.dg.llvmType(wider_ty); |
| 4274 | | if (is_signed) { |
| 4275 | | operand = self.builder.buildSExt(operand, wider_llvm_ty, ""); |
| 4276 | | } else { |
| 4277 | | operand = self.builder.buildZExt(operand, wider_llvm_ty, ""); |
| 4278 | | } |
| 4279 | | operand_ty = wider_ty; |
| 4280 | | operand_scalar_ty = operand_ty.scalarType(); |
| 4281 | | } |
| 4282 | | } |
| 4238 | const operand = try self.resolveInst(ty_op.operand); |
| 4239 | const operand_ty = self.air.typeOf(ty_op.operand); |
| 4240 | const operand_scalar_ty = operand_ty.scalarType(); |
| 4283 | 4241 | |
| 4284 | 4242 | const dest_ty = self.air.typeOfIndex(inst); |
| 4285 | 4243 | const dest_scalar_ty = dest_ty.scalarType(); |
| 4286 | 4244 | const dest_llvm_ty = try self.dg.llvmType(dest_ty); |
| 4245 | const target = self.dg.module.getTarget(); |
| 4287 | 4246 | |
| 4288 | 4247 | if (intrinsicsAllowed(dest_scalar_ty, target)) { |
| 4289 | 4248 | if (operand_scalar_ty.isSignedInt()) { |
| ... | ... | @@ -4294,27 +4253,28 @@ pub const FuncGen = struct { |
| 4294 | 4253 | } |
| 4295 | 4254 | |
| 4296 | 4255 | const operand_bits = @intCast(u16, operand_scalar_ty.bitSize(target)); |
| 4297 | | const compiler_rt_operand_abbrev = compilerRtIntAbbrev(operand_bits); |
| 4298 | | |
| 4256 | const rt_int_bits = compilerRtIntBits(operand_bits); |
| 4257 | const rt_int_ty = self.context.intType(rt_int_bits); |
| 4258 | const extended = e: { |
| 4259 | if (operand_scalar_ty.isSignedInt()) { |
| 4260 | break :e self.builder.buildSExtOrBitCast(operand, rt_int_ty, ""); |
| 4261 | } else { |
| 4262 | break :e self.builder.buildZExtOrBitCast(operand, rt_int_ty, ""); |
| 4263 | } |
| 4264 | }; |
| 4299 | 4265 | const dest_bits = dest_scalar_ty.floatBits(target); |
| 4266 | const compiler_rt_operand_abbrev = compilerRtIntAbbrev(rt_int_bits); |
| 4300 | 4267 | const compiler_rt_dest_abbrev = compilerRtFloatAbbrev(dest_bits); |
| 4301 | | |
| 4268 | const sign_prefix = if (operand_scalar_ty.isSignedInt()) "" else "un"; |
| 4302 | 4269 | var fn_name_buf: [64]u8 = undefined; |
| 4303 | | const fn_name = if (operand_scalar_ty.isSignedInt()) |
| 4304 | | std.fmt.bufPrintZ(&fn_name_buf, "__float{s}i{s}f", .{ |
| 4305 | | compiler_rt_operand_abbrev, |
| 4306 | | compiler_rt_dest_abbrev, |
| 4307 | | }) catch unreachable |
| 4308 | | else |
| 4309 | | std.fmt.bufPrintZ(&fn_name_buf, "__floatun{s}i{s}f", .{ |
| 4310 | | compiler_rt_operand_abbrev, |
| 4311 | | compiler_rt_dest_abbrev, |
| 4312 | | }) catch unreachable; |
| 4313 | | |
| 4314 | | const operand_llvm_ty = try self.dg.llvmType(operand_ty); |
| 4315 | | const param_types = [1]*const llvm.Type{operand_llvm_ty}; |
| 4270 | const fn_name = std.fmt.bufPrintZ(&fn_name_buf, "__float{s}{s}i{s}f", .{ |
| 4271 | sign_prefix, |
| 4272 | compiler_rt_operand_abbrev, |
| 4273 | compiler_rt_dest_abbrev, |
| 4274 | }) catch unreachable; |
| 4275 | const param_types = [1]*const llvm.Type{rt_int_ty}; |
| 4316 | 4276 | const libc_fn = self.getLibcFunction(fn_name, &param_types, dest_llvm_ty); |
| 4317 | | const params = [1]*const llvm.Value{operand}; |
| 4277 | const params = [1]*const llvm.Value{extended}; |
| 4318 | 4278 | |
| 4319 | 4279 | return self.builder.buildCall(libc_fn, &params, params.len, .C, .Auto, ""); |
| 4320 | 4280 | } |
| ... | ... | @@ -4330,12 +4290,12 @@ pub const FuncGen = struct { |
| 4330 | 4290 | const operand_ty = self.air.typeOf(ty_op.operand); |
| 4331 | 4291 | const operand_scalar_ty = operand_ty.scalarType(); |
| 4332 | 4292 | |
| 4333 | | var dest_ty = self.air.typeOfIndex(inst); |
| 4334 | | var dest_scalar_ty = dest_ty.scalarType(); |
| 4293 | const dest_ty = self.air.typeOfIndex(inst); |
| 4294 | const dest_scalar_ty = dest_ty.scalarType(); |
| 4295 | const dest_llvm_ty = try self.dg.llvmType(dest_ty); |
| 4335 | 4296 | |
| 4336 | 4297 | if (intrinsicsAllowed(operand_scalar_ty, target)) { |
| 4337 | 4298 | // TODO set fast math flag |
| 4338 | | const dest_llvm_ty = try self.dg.llvmType(dest_ty); |
| 4339 | 4299 | if (dest_scalar_ty.isSignedInt()) { |
| 4340 | 4300 | return self.builder.buildFPToSI(operand, dest_llvm_ty, ""); |
| 4341 | 4301 | } else { |
| ... | ... | @@ -4343,52 +4303,34 @@ pub const FuncGen = struct { |
| 4343 | 4303 | } |
| 4344 | 4304 | } |
| 4345 | 4305 | |
| 4346 | | const needs_truncating = blk: { |
| 4347 | | const dest_bits = @intCast(u16, dest_scalar_ty.bitSize(target)); |
| 4348 | | |
| 4349 | | if (!isPowerOfTwo(dest_bits) or dest_bits < 32) { |
| 4350 | | dest_ty = try self.intTypeFromBitsAndSignRounded(dest_bits, dest_scalar_ty.isSignedInt()); |
| 4351 | | dest_scalar_ty = dest_ty.scalarType(); |
| 4352 | | break :blk true; |
| 4353 | | } |
| 4354 | | |
| 4355 | | break :blk false; |
| 4356 | | }; |
| 4357 | | |
| 4358 | | const dest_llvm_ty = try self.dg.llvmType(dest_ty); |
| 4306 | const rt_int_bits = compilerRtIntBits(@intCast(u16, dest_scalar_ty.bitSize(target))); |
| 4307 | const libc_ret_ty = self.context.intType(rt_int_bits); |
| 4359 | 4308 | |
| 4360 | 4309 | const operand_bits = operand_scalar_ty.floatBits(target); |
| 4361 | 4310 | const compiler_rt_operand_abbrev = compilerRtFloatAbbrev(operand_bits); |
| 4362 | 4311 | |
| 4363 | | const dest_bits = @intCast(u16, dest_scalar_ty.bitSize(target)); |
| 4364 | | const compiler_rt_dest_abbrev = compilerRtIntAbbrev(dest_bits); |
| 4312 | const compiler_rt_dest_abbrev = compilerRtIntAbbrev(rt_int_bits); |
| 4313 | const sign_prefix = if (dest_scalar_ty.isSignedInt()) "" else "un"; |
| 4365 | 4314 | |
| 4366 | 4315 | var fn_name_buf: [64]u8 = undefined; |
| 4367 | | const fn_name = if (dest_scalar_ty.isSignedInt()) |
| 4368 | | std.fmt.bufPrintZ(&fn_name_buf, "__fix{s}f{s}i", .{ |
| 4369 | | compiler_rt_operand_abbrev, |
| 4370 | | compiler_rt_dest_abbrev, |
| 4371 | | }) catch unreachable |
| 4372 | | else |
| 4373 | | std.fmt.bufPrintZ(&fn_name_buf, "__fixun{s}f{s}i", .{ |
| 4374 | | compiler_rt_operand_abbrev, |
| 4375 | | compiler_rt_dest_abbrev, |
| 4376 | | }) catch unreachable; |
| 4316 | const fn_name = std.fmt.bufPrintZ(&fn_name_buf, "__fix{s}{s}f{s}i", .{ |
| 4317 | sign_prefix, |
| 4318 | compiler_rt_operand_abbrev, |
| 4319 | compiler_rt_dest_abbrev, |
| 4320 | }) catch unreachable; |
| 4377 | 4321 | |
| 4378 | 4322 | const operand_llvm_ty = try self.dg.llvmType(operand_ty); |
| 4379 | 4323 | const param_types = [1]*const llvm.Type{operand_llvm_ty}; |
| 4380 | | const libc_fn = self.getLibcFunction(fn_name, &param_types, dest_llvm_ty); |
| 4324 | const libc_fn = self.getLibcFunction(fn_name, &param_types, libc_ret_ty); |
| 4381 | 4325 | const params = [1]*const llvm.Value{operand}; |
| 4382 | 4326 | |
| 4383 | 4327 | const result = self.builder.buildCall(libc_fn, &params, params.len, .C, .Auto, ""); |
| 4384 | 4328 | |
| 4385 | | if (needs_truncating) { |
| 4386 | | const requested_ty = self.air.typeOfIndex(inst); |
| 4387 | | const requested_llvm_ty = try self.dg.llvmType(requested_ty); |
| 4388 | | return self.builder.buildTrunc(result, requested_llvm_ty, ""); |
| 4329 | if (libc_ret_ty == dest_llvm_ty) { |
| 4330 | return result; |
| 4389 | 4331 | } |
| 4390 | 4332 | |
| 4391 | | return result; |
| 4333 | return self.builder.buildTrunc(result, dest_llvm_ty, ""); |
| 4392 | 4334 | } |
| 4393 | 4335 | |
| 4394 | 4336 | fn airSliceField(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*const llvm.Value { |
| ... | ... | @@ -8448,3 +8390,12 @@ fn needDbgVarWorkaround(dg: *DeclGen, ty: Type) bool { |
| 8448 | 8390 | } |
| 8449 | 8391 | return false; |
| 8450 | 8392 | } |
| 8393 | |
| 8394 | fn compilerRtIntBits(bits: u16) u16 { |
| 8395 | inline for (.{ 8, 16, 32, 64, 128 }) |b| { |
| 8396 | if (bits <= b) { |
| 8397 | return b; |
| 8398 | } |
| 8399 | } |
| 8400 | return bits; |
| 8401 | } |