| ... | @@ -4229,61 +4229,20 @@ pub const FuncGen = struct { | ... | @@ -4229,61 +4229,20 @@ 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 | | | |
| 4256 | fn airIntToFloat(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | 4232 | fn airIntToFloat(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| 4257 | if (self.liveness.isUnused(inst)) | 4233 | if (self.liveness.isUnused(inst)) |
| 4258 | return null; | 4234 | return null; |
| 4259 | | 4235 | |
| 4260 | const target = self.dg.module.getTarget(); | | |
| 4261 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 4236 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 4262 | | 4237 | |
| 4263 | var operand = try self.resolveInst(ty_op.operand); | 4238 | const operand = try self.resolveInst(ty_op.operand); |
| 4264 | var operand_ty = self.air.typeOf(ty_op.operand); | 4239 | const operand_ty = self.air.typeOf(ty_op.operand); |
| 4265 | var operand_scalar_ty = operand_ty.scalarType(); | 4240 | const 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 | | 4241 | |
| 4284 | const dest_ty = self.air.typeOfIndex(inst); | 4242 | const dest_ty = self.air.typeOfIndex(inst); |
| 4285 | const dest_scalar_ty = dest_ty.scalarType(); | 4243 | const dest_scalar_ty = dest_ty.scalarType(); |
| 4286 | const dest_llvm_ty = try self.dg.llvmType(dest_ty); | 4244 | const dest_llvm_ty = try self.dg.llvmType(dest_ty); |
| | 4245 | const target = self.dg.module.getTarget(); |
| 4287 | | 4246 | |
| 4288 | if (intrinsicsAllowed(dest_scalar_ty, target)) { | 4247 | if (intrinsicsAllowed(dest_scalar_ty, target)) { |
| 4289 | if (operand_scalar_ty.isSignedInt()) { | 4248 | if (operand_scalar_ty.isSignedInt()) { |
| ... | @@ -4294,27 +4253,28 @@ pub const FuncGen = struct { | ... | @@ -4294,27 +4253,28 @@ pub const FuncGen = struct { |
| 4294 | } | 4253 | } |
| 4295 | | 4254 | |
| 4296 | const operand_bits = @intCast(u16, operand_scalar_ty.bitSize(target)); | 4255 | const operand_bits = @intCast(u16, operand_scalar_ty.bitSize(target)); |
| 4297 | const compiler_rt_operand_abbrev = compilerRtIntAbbrev(operand_bits); | 4256 | const rt_int_bits = compilerRtIntBits(operand_bits); |
| 4298 | | 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 | const dest_bits = dest_scalar_ty.floatBits(target); | 4265 | const dest_bits = dest_scalar_ty.floatBits(target); |
| | 4266 | const compiler_rt_operand_abbrev = compilerRtIntAbbrev(rt_int_bits); |
| 4300 | const compiler_rt_dest_abbrev = compilerRtFloatAbbrev(dest_bits); | 4267 | const compiler_rt_dest_abbrev = compilerRtFloatAbbrev(dest_bits); |
| 4301 | | 4268 | const sign_prefix = if (operand_scalar_ty.isSignedInt()) "" else "un"; |
| 4302 | var fn_name_buf: [64]u8 = undefined; | 4269 | var fn_name_buf: [64]u8 = undefined; |
| 4303 | const fn_name = if (operand_scalar_ty.isSignedInt()) | 4270 | const fn_name = std.fmt.bufPrintZ(&fn_name_buf, "__float{s}{s}i{s}f", .{ |
| 4304 | std.fmt.bufPrintZ(&fn_name_buf, "__float{s}i{s}f", .{ | 4271 | sign_prefix, |
| 4305 | compiler_rt_operand_abbrev, | 4272 | compiler_rt_operand_abbrev, |
| 4306 | compiler_rt_dest_abbrev, | 4273 | compiler_rt_dest_abbrev, |
| 4307 | }) catch unreachable | 4274 | }) catch unreachable; |
| 4308 | else | 4275 | const param_types = [1]*const llvm.Type{rt_int_ty}; |
| 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); | 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 | return self.builder.buildCall(libc_fn, &params, params.len, .C, .Auto, ""); | 4279 | return self.builder.buildCall(libc_fn, &params, params.len, .C, .Auto, ""); |
| 4320 | } | 4280 | } |
| ... | @@ -4330,12 +4290,12 @@ pub const FuncGen = struct { | ... | @@ -4330,12 +4290,12 @@ pub const FuncGen = struct { |
| 4330 | const operand_ty = self.air.typeOf(ty_op.operand); | 4290 | const operand_ty = self.air.typeOf(ty_op.operand); |
| 4331 | const operand_scalar_ty = operand_ty.scalarType(); | 4291 | const operand_scalar_ty = operand_ty.scalarType(); |
| 4332 | | 4292 | |
| 4333 | var dest_ty = self.air.typeOfIndex(inst); | 4293 | const dest_ty = self.air.typeOfIndex(inst); |
| 4334 | var dest_scalar_ty = dest_ty.scalarType(); | 4294 | const dest_scalar_ty = dest_ty.scalarType(); |
| | 4295 | const dest_llvm_ty = try self.dg.llvmType(dest_ty); |
| 4335 | | 4296 | |
| 4336 | if (intrinsicsAllowed(operand_scalar_ty, target)) { | 4297 | if (intrinsicsAllowed(operand_scalar_ty, target)) { |
| 4337 | // TODO set fast math flag | 4298 | // TODO set fast math flag |
| 4338 | const dest_llvm_ty = try self.dg.llvmType(dest_ty); | | |
| 4339 | if (dest_scalar_ty.isSignedInt()) { | 4299 | if (dest_scalar_ty.isSignedInt()) { |
| 4340 | return self.builder.buildFPToSI(operand, dest_llvm_ty, ""); | 4300 | return self.builder.buildFPToSI(operand, dest_llvm_ty, ""); |
| 4341 | } else { | 4301 | } else { |
| ... | @@ -4343,52 +4303,34 @@ pub const FuncGen = struct { | ... | @@ -4343,52 +4303,34 @@ pub const FuncGen = struct { |
| 4343 | } | 4303 | } |
| 4344 | } | 4304 | } |
| 4345 | | 4305 | |
| 4346 | const needs_truncating = blk: { | 4306 | const rt_int_bits = compilerRtIntBits(@intCast(u16, dest_scalar_ty.bitSize(target))); |
| 4347 | const dest_bits = @intCast(u16, dest_scalar_ty.bitSize(target)); | 4307 | const libc_ret_ty = self.context.intType(rt_int_bits); |
| 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); | | |
| 4359 | | 4308 | |
| 4360 | const operand_bits = operand_scalar_ty.floatBits(target); | 4309 | const operand_bits = operand_scalar_ty.floatBits(target); |
| 4361 | const compiler_rt_operand_abbrev = compilerRtFloatAbbrev(operand_bits); | 4310 | const compiler_rt_operand_abbrev = compilerRtFloatAbbrev(operand_bits); |
| 4362 | | 4311 | |
| 4363 | const dest_bits = @intCast(u16, dest_scalar_ty.bitSize(target)); | 4312 | const compiler_rt_dest_abbrev = compilerRtIntAbbrev(rt_int_bits); |
| 4364 | const compiler_rt_dest_abbrev = compilerRtIntAbbrev(dest_bits); | 4313 | const sign_prefix = if (dest_scalar_ty.isSignedInt()) "" else "un"; |
| 4365 | | 4314 | |
| 4366 | var fn_name_buf: [64]u8 = undefined; | 4315 | var fn_name_buf: [64]u8 = undefined; |
| 4367 | const fn_name = if (dest_scalar_ty.isSignedInt()) | 4316 | const fn_name = std.fmt.bufPrintZ(&fn_name_buf, "__fix{s}{s}f{s}i", .{ |
| 4368 | std.fmt.bufPrintZ(&fn_name_buf, "__fix{s}f{s}i", .{ | 4317 | sign_prefix, |
| 4369 | compiler_rt_operand_abbrev, | 4318 | compiler_rt_operand_abbrev, |
| 4370 | compiler_rt_dest_abbrev, | 4319 | compiler_rt_dest_abbrev, |
| 4371 | }) catch unreachable | 4320 | }) 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 | | 4321 | |
| 4378 | const operand_llvm_ty = try self.dg.llvmType(operand_ty); | 4322 | const operand_llvm_ty = try self.dg.llvmType(operand_ty); |
| 4379 | const param_types = [1]*const llvm.Type{operand_llvm_ty}; | 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 | const params = [1]*const llvm.Value{operand}; | 4325 | const params = [1]*const llvm.Value{operand}; |
| 4382 | | 4326 | |
| 4383 | const result = self.builder.buildCall(libc_fn, &params, params.len, .C, .Auto, ""); | 4327 | const result = self.builder.buildCall(libc_fn, &params, params.len, .C, .Auto, ""); |
| 4384 | | 4328 | |
| 4385 | if (needs_truncating) { | 4329 | if (libc_ret_ty == dest_llvm_ty) { |
| 4386 | const requested_ty = self.air.typeOfIndex(inst); | 4330 | return result; |
| 4387 | const requested_llvm_ty = try self.dg.llvmType(requested_ty); | | |
| 4388 | return self.builder.buildTrunc(result, requested_llvm_ty, ""); | | |
| 4389 | } | 4331 | } |
| 4390 | | 4332 | |
| 4391 | return result; | 4333 | return self.builder.buildTrunc(result, dest_llvm_ty, ""); |
| 4392 | } | 4334 | } |
| 4393 | | 4335 | |
| 4394 | fn airSliceField(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*const llvm.Value { | 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,3 +8390,12 @@ fn needDbgVarWorkaround(dg: *DeclGen, ty: Type) bool { |
| 8448 | } | 8390 | } |
| 8449 | return false; | 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 | } |