| ... | ... | @@ -4229,41 +4229,166 @@ 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 | |
| 4232 | 4256 | fn airIntToFloat(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| 4233 | 4257 | if (self.liveness.isUnused(inst)) |
| 4234 | 4258 | return null; |
| 4235 | 4259 | |
| 4260 | const target = self.dg.module.getTarget(); |
| 4236 | 4261 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 4237 | | const operand = try self.resolveInst(ty_op.operand); |
| 4238 | | const operand_ty = self.air.typeOf(ty_op.operand); |
| 4239 | | const operand_scalar_ty = operand_ty.scalarType(); |
| 4262 | |
| 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 | } |
| 4283 | |
| 4240 | 4284 | const dest_ty = self.air.typeOfIndex(inst); |
| 4285 | const dest_scalar_ty = dest_ty.scalarType(); |
| 4241 | 4286 | const dest_llvm_ty = try self.dg.llvmType(dest_ty); |
| 4242 | 4287 | |
| 4243 | | if (operand_scalar_ty.isSignedInt()) { |
| 4244 | | return self.builder.buildSIToFP(operand, dest_llvm_ty, ""); |
| 4245 | | } else { |
| 4246 | | return self.builder.buildUIToFP(operand, dest_llvm_ty, ""); |
| 4288 | if (intrinsicsAllowed(dest_scalar_ty, target)) { |
| 4289 | if (operand_scalar_ty.isSignedInt()) { |
| 4290 | return self.builder.buildSIToFP(operand, dest_llvm_ty, ""); |
| 4291 | } else { |
| 4292 | return self.builder.buildUIToFP(operand, dest_llvm_ty, ""); |
| 4293 | } |
| 4247 | 4294 | } |
| 4295 | |
| 4296 | const operand_bits = @intCast(u16, operand_scalar_ty.bitSize(target)); |
| 4297 | const compiler_rt_operand_abbrev = compilerRtIntAbbrev(operand_bits); |
| 4298 | |
| 4299 | const dest_bits = dest_scalar_ty.floatBits(target); |
| 4300 | const compiler_rt_dest_abbrev = compilerRtFloatAbbrev(dest_bits); |
| 4301 | |
| 4302 | 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}; |
| 4316 | const libc_fn = self.getLibcFunction(fn_name, &param_types, dest_llvm_ty); |
| 4317 | const params = [1]*const llvm.Value{operand}; |
| 4318 | |
| 4319 | return self.builder.buildCall(libc_fn, &params, params.len, .C, .Auto, ""); |
| 4248 | 4320 | } |
| 4249 | 4321 | |
| 4250 | 4322 | fn airFloatToInt(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| 4251 | 4323 | if (self.liveness.isUnused(inst)) |
| 4252 | 4324 | return null; |
| 4253 | 4325 | |
| 4326 | const target = self.dg.module.getTarget(); |
| 4254 | 4327 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 4328 | |
| 4255 | 4329 | const operand = try self.resolveInst(ty_op.operand); |
| 4256 | | const dest_ty = self.air.typeOfIndex(inst); |
| 4257 | | const dest_scalar_ty = dest_ty.scalarType(); |
| 4330 | const operand_ty = self.air.typeOf(ty_op.operand); |
| 4331 | const operand_scalar_ty = operand_ty.scalarType(); |
| 4332 | |
| 4333 | var dest_ty = self.air.typeOfIndex(inst); |
| 4334 | var dest_scalar_ty = dest_ty.scalarType(); |
| 4335 | |
| 4336 | if (intrinsicsAllowed(operand_scalar_ty, target)) { |
| 4337 | // TODO set fast math flag |
| 4338 | const dest_llvm_ty = try self.dg.llvmType(dest_ty); |
| 4339 | if (dest_scalar_ty.isSignedInt()) { |
| 4340 | return self.builder.buildFPToSI(operand, dest_llvm_ty, ""); |
| 4341 | } else { |
| 4342 | return self.builder.buildFPToUI(operand, dest_llvm_ty, ""); |
| 4343 | } |
| 4344 | } |
| 4345 | |
| 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 | |
| 4258 | 4358 | const dest_llvm_ty = try self.dg.llvmType(dest_ty); |
| 4259 | 4359 | |
| 4260 | | // TODO set fast math flag |
| 4360 | const operand_bits = operand_scalar_ty.floatBits(target); |
| 4361 | const compiler_rt_operand_abbrev = compilerRtFloatAbbrev(operand_bits); |
| 4261 | 4362 | |
| 4262 | | if (dest_scalar_ty.isSignedInt()) { |
| 4263 | | return self.builder.buildFPToSI(operand, dest_llvm_ty, ""); |
| 4264 | | } else { |
| 4265 | | return self.builder.buildFPToUI(operand, dest_llvm_ty, ""); |
| 4363 | const dest_bits = @intCast(u16, dest_scalar_ty.bitSize(target)); |
| 4364 | const compiler_rt_dest_abbrev = compilerRtIntAbbrev(dest_bits); |
| 4365 | |
| 4366 | 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; |
| 4377 | |
| 4378 | const operand_llvm_ty = try self.dg.llvmType(operand_ty); |
| 4379 | const param_types = [1]*const llvm.Type{operand_llvm_ty}; |
| 4380 | const libc_fn = self.getLibcFunction(fn_name, &param_types, dest_llvm_ty); |
| 4381 | const params = [1]*const llvm.Value{operand}; |
| 4382 | |
| 4383 | const result = self.builder.buildCall(libc_fn, &params, params.len, .C, .Auto, ""); |
| 4384 | |
| 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, ""); |
| 4266 | 4389 | } |
| 4390 | |
| 4391 | return result; |
| 4267 | 4392 | } |
| 4268 | 4393 | |
| 4269 | 4394 | fn airSliceField(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*const llvm.Value { |
| ... | ... | @@ -5615,6 +5740,16 @@ pub const FuncGen = struct { |
| 5615 | 5740 | }; |
| 5616 | 5741 | } |
| 5617 | 5742 | |
| 5743 | fn compilerRtIntAbbrev(bits: u16) []const u8 { |
| 5744 | return switch (bits) { |
| 5745 | 16 => "h", |
| 5746 | 32 => "s", |
| 5747 | 64 => "d", |
| 5748 | 128 => "t", |
| 5749 | else => "o", // Non-standard |
| 5750 | }; |
| 5751 | } |
| 5752 | |
| 5618 | 5753 | /// Creates a floating point comparison by lowering to the appropriate |
| 5619 | 5754 | /// hardware instruction or softfloat routine for the target |
| 5620 | 5755 | fn buildFloatCmp( |