| ... | ... | @@ -3,6 +3,7 @@ const builtin = @import("builtin"); |
| 3 | 3 | const Allocator = std.mem.Allocator; |
| 4 | 4 | const assert = std.debug.assert; |
| 5 | 5 | const testing = std.testing; |
| 6 | const math = std.math; |
| 6 | 7 | const mem = std.mem; |
| 7 | 8 | const log = std.log.scoped(.codegen); |
| 8 | 9 | |
| ... | ... | @@ -3258,32 +3259,35 @@ fn intByteSwap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3258 | 3259 | return cg.intShr(ty, intrin_ret, .{ .imm32 = 64 - ty.bits }); |
| 3259 | 3260 | }, |
| 3260 | 3261 | 65...128 => { |
| 3261 | | const tmp = try cg.allocStack(Type.u128); |
| 3262 | const result = try cg.allocStack(Type.u128); |
| 3262 | 3263 | |
| 3263 | | const low = try cg.load(operand, Type.u64, 0); |
| 3264 | | const high = try cg.load(operand, Type.u64, 8); |
| 3264 | try cg.emitWValue(result); |
| 3265 | 3265 | |
| 3266 | const low = try cg.load(operand, Type.u64, 0); |
| 3266 | 3267 | const swap_low = try cg.callIntrinsic( |
| 3267 | 3268 | .__bswapdi2, |
| 3268 | 3269 | &.{.u64_type}, |
| 3269 | 3270 | Type.u64, |
| 3270 | 3271 | &.{low}, |
| 3271 | 3272 | ); |
| 3273 | try cg.store(.stack, swap_low, Type.u64, result.offset() + 8); |
| 3274 | |
| 3275 | try cg.emitWValue(result); |
| 3276 | |
| 3277 | const high = try cg.load(operand, Type.u64, 8); |
| 3272 | 3278 | const swap_high = try cg.callIntrinsic( |
| 3273 | 3279 | .__bswapdi2, |
| 3274 | 3280 | &.{.u64_type}, |
| 3275 | 3281 | Type.u64, |
| 3276 | 3282 | &.{high}, |
| 3277 | 3283 | ); |
| 3278 | | |
| 3279 | | try cg.store(tmp, swap_low, Type.u64, tmp.offset() + 8); |
| 3280 | | try cg.store(tmp, swap_high, Type.u64, tmp.offset()); |
| 3284 | try cg.store(.stack, swap_high, Type.u64, result.offset()); |
| 3281 | 3285 | |
| 3282 | 3286 | if (ty.bits < 128) { |
| 3283 | 3287 | const shift_ty: IntType = .{ .is_signed = ty.is_signed, .bits = 128 }; |
| 3284 | | return cg.intShr(shift_ty, tmp, .{ .imm32 = 128 - ty.bits }); |
| 3288 | return cg.intShr(shift_ty, result, .{ .imm32 = 128 - ty.bits }); |
| 3285 | 3289 | } else { |
| 3286 | | return tmp; |
| 3290 | return result; |
| 3287 | 3291 | } |
| 3288 | 3292 | }, |
| 3289 | 3293 | else => { |
| ... | ... | @@ -3360,14 +3364,14 @@ fn intWrap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3360 | 3364 | |
| 3361 | 3365 | const result = try cg.allocInt(ty); |
| 3362 | 3366 | |
| 3363 | | const copy_len = (ty.bits / 64) * 8; |
| 3364 | | try cg.memcpy(result, operand, .{ .imm32 = copy_len }); |
| 3367 | const used_len = (math.divCeil(u16, ty.bits, 64) catch unreachable) * 8; |
| 3365 | 3368 | |
| 3366 | 3369 | if (ty.bits % 64 != 0) { |
| 3370 | try cg.memcpy(result, operand, .{ .imm32 = used_len - 8 }); |
| 3367 | 3371 | const pad = 64 - ty.bits % 64; |
| 3368 | 3372 | |
| 3369 | 3373 | try cg.emitWValue(result); |
| 3370 | | _ = try cg.load(operand, Type.u64, copy_len); |
| 3374 | _ = try cg.load(operand, Type.u64, used_len - 8); |
| 3371 | 3375 | if (ty.is_signed) { |
| 3372 | 3376 | try cg.addImm64(pad); |
| 3373 | 3377 | try cg.addTag(.i64_shl); |
| ... | ... | @@ -3377,20 +3381,22 @@ fn intWrap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3377 | 3381 | try cg.addImm64(~@as(u64, 0) >> @intCast(pad)); |
| 3378 | 3382 | try cg.addTag(.i64_and); |
| 3379 | 3383 | } |
| 3380 | | try cg.store(.stack, .stack, Type.u64, result.offset() + copy_len); |
| 3384 | try cg.store(.stack, .stack, Type.u64, result.offset() + used_len - 8); |
| 3385 | } else { |
| 3386 | try cg.memcpy(result, operand, .{ .imm32 = used_len }); |
| 3381 | 3387 | } |
| 3382 | 3388 | |
| 3383 | 3389 | const full_len = @divExact(bits, 8); |
| 3384 | | if (copy_len + 16 == full_len) { // last limb needs sign extended |
| 3390 | if (used_len + 8 == full_len) { // last limb needs sign extended |
| 3385 | 3391 | try cg.emitWValue(result); |
| 3386 | 3392 | if (ty.is_signed) { |
| 3387 | | _ = try cg.load(result, Type.u64, copy_len); |
| 3393 | _ = try cg.load(result, Type.u64, used_len - 8); |
| 3388 | 3394 | try cg.addImm64(63); |
| 3389 | 3395 | try cg.addTag(.i64_shr_s); |
| 3390 | 3396 | } else { |
| 3391 | 3397 | try cg.addImm64(0); |
| 3392 | 3398 | } |
| 3393 | | try cg.store(.stack, .stack, Type.u64, result.offset() + copy_len + 8); |
| 3399 | try cg.store(.stack, .stack, Type.u64, result.offset() + used_len); |
| 3394 | 3400 | } |
| 3395 | 3401 | |
| 3396 | 3402 | return result; |
| ... | ... | @@ -3424,17 +3430,17 @@ fn intMaxValue(cg: *CodeGen, int_ty: IntType) InnerError!WValue { |
| 3424 | 3430 | } else { |
| 3425 | 3431 | const result = try cg.allocInt(int_ty); |
| 3426 | 3432 | const full_len = @divExact(cg.intBackingBits(int_ty.bits), 8); |
| 3427 | | const normal_len = (int_ty.bits / 64) * 8; |
| 3433 | const used_len = (math.divCeil(u16, int_ty.bits, 64) catch unreachable) * 8; |
| 3428 | 3434 | |
| 3429 | | try cg.memset(Type.u8, result, .{ .imm32 = normal_len }, .{ .imm32 = 0xFF }); |
| 3435 | try cg.memset(Type.u8, result, .{ .imm32 = used_len - 8 }, .{ .imm32 = 0xFF }); |
| 3430 | 3436 | |
| 3431 | 3437 | if (int_ty.is_signed) { |
| 3432 | | try cg.store(result, .{ .imm64 = (~@as(u64, 0) >> @intCast((normal_len + 8) * 8 - int_ty.bits)) >> 1 }, Type.u64, normal_len); |
| 3438 | try cg.store(result, .{ .imm64 = (~@as(u64, 0) >> @intCast(used_len * 8 - int_ty.bits)) >> 1 }, Type.u64, used_len - 8); |
| 3433 | 3439 | } else { |
| 3434 | | try cg.store(result, .{ .imm64 = ~@as(u64, 0) >> @intCast((normal_len + 8) * 8 - int_ty.bits) }, Type.u64, normal_len); |
| 3440 | try cg.store(result, .{ .imm64 = ~@as(u64, 0) >> @intCast(used_len * 8 - int_ty.bits) }, Type.u64, used_len - 8); |
| 3435 | 3441 | } |
| 3436 | 3442 | |
| 3437 | | if (normal_len + 16 == full_len) { |
| 3443 | if (used_len + 8 == full_len) { |
| 3438 | 3444 | try cg.store(result, .{ .imm64 = 0 }, Type.u64, full_len - 8); |
| 3439 | 3445 | } |
| 3440 | 3446 | |
| ... | ... | @@ -3458,12 +3464,12 @@ fn intMinValue(cg: *CodeGen, int_ty: IntType) InnerError!WValue { |
| 3458 | 3464 | } else { |
| 3459 | 3465 | const result = try cg.allocInt(int_ty); |
| 3460 | 3466 | const full_len = @divExact(cg.intBackingBits(int_ty.bits), 8); |
| 3461 | | const normal_len = (int_ty.bits / 64) * 8; |
| 3467 | const used_len = (math.divCeil(u16, int_ty.bits, 64) catch unreachable) * 8; |
| 3462 | 3468 | |
| 3463 | | try cg.memset(Type.u8, result, .{ .imm32 = normal_len }, .{ .imm32 = 0 }); |
| 3464 | | try cg.store(result, .{ .imm64 = ~@as(u64, 0) << @intCast(int_ty.bits - normal_len * 8 - 1) }, Type.u64, normal_len); |
| 3469 | try cg.memset(Type.u8, result, .{ .imm32 = used_len - 8 }, .{ .imm32 = 0 }); |
| 3470 | try cg.store(result, .{ .imm64 = ~@as(u64, 0) << @intCast(int_ty.bits - (used_len - 8) * 8 - 1) }, Type.u64, used_len - 8); |
| 3465 | 3471 | |
| 3466 | | if (normal_len + 16 == full_len) { |
| 3472 | if (used_len + 8 == full_len) { |
| 3467 | 3473 | try cg.store(result, .{ .imm64 = ~@as(u64, 0) }, Type.u64, full_len - 8); |
| 3468 | 3474 | } |
| 3469 | 3475 | |
| ... | ... | @@ -4505,7 +4511,7 @@ fn floatFromInt(cg: *CodeGen, dest_ty: FloatType, src_ty: IntType, operand: WVal |
| 4505 | 4511 | }, |
| 4506 | 4512 | else => { |
| 4507 | 4513 | const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floateihf else .__floatuneihf; |
| 4508 | | return cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type }, Type.f16, &.{ operand, .{ .imm32 = src_ty.bits }}); |
| 4514 | return cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type }, Type.f16, &.{ operand, .{ .imm32 = src_ty.bits } }); |
| 4509 | 4515 | }, |
| 4510 | 4516 | }, |
| 4511 | 4517 | .f32 => switch (src_ty.bits) { |
| ... | ... | @@ -4526,7 +4532,7 @@ fn floatFromInt(cg: *CodeGen, dest_ty: FloatType, src_ty: IntType, operand: WVal |
| 4526 | 4532 | }, |
| 4527 | 4533 | else => { |
| 4528 | 4534 | const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floateisf else .__floatuneisf; |
| 4529 | | return cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type }, Type.f32, &.{ operand, .{ .imm32 = src_ty.bits }}); |
| 4535 | return cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type }, Type.f32, &.{ operand, .{ .imm32 = src_ty.bits } }); |
| 4530 | 4536 | }, |
| 4531 | 4537 | }, |
| 4532 | 4538 | .f64 => switch (src_ty.bits) { |
| ... | ... | @@ -4547,7 +4553,7 @@ fn floatFromInt(cg: *CodeGen, dest_ty: FloatType, src_ty: IntType, operand: WVal |
| 4547 | 4553 | }, |
| 4548 | 4554 | else => { |
| 4549 | 4555 | const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floateidf else .__floatuneidf; |
| 4550 | | return cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type }, Type.f64, &.{ operand, .{ .imm32 = src_ty.bits }}); |
| 4556 | return cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type }, Type.f64, &.{ operand, .{ .imm32 = src_ty.bits } }); |
| 4551 | 4557 | }, |
| 4552 | 4558 | }, |
| 4553 | 4559 | .f80 => switch (src_ty.bits) { |
| ... | ... | @@ -4566,7 +4572,7 @@ fn floatFromInt(cg: *CodeGen, dest_ty: FloatType, src_ty: IntType, operand: WVal |
| 4566 | 4572 | }, |
| 4567 | 4573 | else => { |
| 4568 | 4574 | const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floateixf else .__floatuneixf; |
| 4569 | | return cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type }, Type.f80, &.{ operand, .{ .imm32 = src_ty.bits }}); |
| 4575 | return cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type }, Type.f80, &.{ operand, .{ .imm32 = src_ty.bits } }); |
| 4570 | 4576 | }, |
| 4571 | 4577 | }, |
| 4572 | 4578 | .f128 => switch (src_ty.bits) { |
| ... | ... | @@ -4585,7 +4591,7 @@ fn floatFromInt(cg: *CodeGen, dest_ty: FloatType, src_ty: IntType, operand: WVal |
| 4585 | 4591 | }, |
| 4586 | 4592 | else => { |
| 4587 | 4593 | const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floateitf else .__floatuneitf; |
| 4588 | | return cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type }, Type.f128, &.{ operand, .{ .imm32 = src_ty.bits }}); |
| 4594 | return cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type }, Type.f128, &.{ operand, .{ .imm32 = src_ty.bits } }); |
| 4589 | 4595 | }, |
| 4590 | 4596 | }, |
| 4591 | 4597 | } |