| ... | @@ -4229,41 +4229,166 @@ pub const FuncGen = struct { | ... | @@ -4229,41 +4229,166 @@ pub const FuncGen = struct { |
| 4229 | return self.builder.buildInsertValue(partial, len, 1, ""); | 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 | fn airIntToFloat(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | 4256 | fn airIntToFloat(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| 4233 | if (self.liveness.isUnused(inst)) | 4257 | if (self.liveness.isUnused(inst)) |
| 4234 | return null; | 4258 | return null; |
| 4235 | | 4259 | |
| | 4260 | const target = self.dg.module.getTarget(); |
| 4236 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 4261 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 4237 | const operand = try self.resolveInst(ty_op.operand); | 4262 | |
| 4238 | const operand_ty = self.air.typeOf(ty_op.operand); | 4263 | var operand = try self.resolveInst(ty_op.operand); |
| 4239 | const operand_scalar_ty = operand_ty.scalarType(); | 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 | const dest_ty = self.air.typeOfIndex(inst); | 4284 | const dest_ty = self.air.typeOfIndex(inst); |
| | 4285 | const dest_scalar_ty = dest_ty.scalarType(); |
| 4241 | const dest_llvm_ty = try self.dg.llvmType(dest_ty); | 4286 | const dest_llvm_ty = try self.dg.llvmType(dest_ty); |
| 4242 | | 4287 | |
| 4243 | if (operand_scalar_ty.isSignedInt()) { | 4288 | if (intrinsicsAllowed(dest_scalar_ty, target)) { |
| 4244 | return self.builder.buildSIToFP(operand, dest_llvm_ty, ""); | 4289 | if (operand_scalar_ty.isSignedInt()) { |
| 4245 | } else { | 4290 | return self.builder.buildSIToFP(operand, dest_llvm_ty, ""); |
| 4246 | return self.builder.buildUIToFP(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 | fn airFloatToInt(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | 4322 | fn airFloatToInt(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| 4251 | if (self.liveness.isUnused(inst)) | 4323 | if (self.liveness.isUnused(inst)) |
| 4252 | return null; | 4324 | return null; |
| 4253 | | 4325 | |
| | 4326 | const target = self.dg.module.getTarget(); |
| 4254 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 4327 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| | 4328 | |
| 4255 | const operand = try self.resolveInst(ty_op.operand); | 4329 | const operand = try self.resolveInst(ty_op.operand); |
| 4256 | const dest_ty = self.air.typeOfIndex(inst); | 4330 | const operand_ty = self.air.typeOf(ty_op.operand); |
| 4257 | const dest_scalar_ty = dest_ty.scalarType(); | 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 | const dest_llvm_ty = try self.dg.llvmType(dest_ty); | 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()) { | 4363 | const dest_bits = @intCast(u16, dest_scalar_ty.bitSize(target)); |
| 4263 | return self.builder.buildFPToSI(operand, dest_llvm_ty, ""); | 4364 | const compiler_rt_dest_abbrev = compilerRtIntAbbrev(dest_bits); |
| 4264 | } else { | 4365 | |
| 4265 | return self.builder.buildFPToUI(operand, dest_llvm_ty, ""); | 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 | fn airSliceField(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*const llvm.Value { | 4394 | fn airSliceField(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*const llvm.Value { |
| ... | @@ -5615,6 +5740,16 @@ pub const FuncGen = struct { | ... | @@ -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 | /// Creates a floating point comparison by lowering to the appropriate | 5753 | /// Creates a floating point comparison by lowering to the appropriate |
| 5619 | /// hardware instruction or softfloat routine for the target | 5754 | /// hardware instruction or softfloat routine for the target |
| 5620 | fn buildFloatCmp( | 5755 | fn buildFloatCmp( |