| ... | ... | @@ -2515,63 +2515,96 @@ fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 2515 | 2515 | const src_ty = self.typeOf(ty_op.operand); |
| 2516 | 2516 | const src_bits = src_ty.floatBits(self.target.*); |
| 2517 | 2517 | |
| 2518 | | const src_mcv = try self.resolveInst(ty_op.operand); |
| 2519 | | const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| 2520 | | src_mcv |
| 2521 | | else |
| 2522 | | try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv); |
| 2523 | | const dst_reg = dst_mcv.getReg().?.to128(); |
| 2524 | | const dst_lock = self.register_manager.lockReg(dst_reg); |
| 2525 | | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 2518 | const result = result: { |
| 2519 | if (switch (dst_bits) { |
| 2520 | 16 => switch (src_bits) { |
| 2521 | 32 => !self.hasFeature(.f16c), |
| 2522 | 64, 80, 128 => true, |
| 2523 | else => unreachable, |
| 2524 | }, |
| 2525 | 32 => switch (src_bits) { |
| 2526 | 64 => false, |
| 2527 | 80, 128 => true, |
| 2528 | else => unreachable, |
| 2529 | }, |
| 2530 | 64 => switch (src_bits) { |
| 2531 | 80, 128 => true, |
| 2532 | else => unreachable, |
| 2533 | }, |
| 2534 | 80 => switch (dst_bits) { |
| 2535 | 128 => true, |
| 2536 | else => unreachable, |
| 2537 | }, |
| 2538 | else => unreachable, |
| 2539 | }) { |
| 2540 | var callee: ["__trunc?f?f2".len]u8 = undefined; |
| 2541 | break :result try self.genCall(.{ .lib = .{ |
| 2542 | .return_type = self.floatCompilerRtAbiType(dst_ty, src_ty).toIntern(), |
| 2543 | .param_types = &.{self.floatCompilerRtAbiType(src_ty, dst_ty).toIntern()}, |
| 2544 | .callee = std.fmt.bufPrint(&callee, "__trunc{c}f{c}f2", .{ |
| 2545 | floatCompilerRtAbiName(src_bits), |
| 2546 | floatCompilerRtAbiName(dst_bits), |
| 2547 | }) catch unreachable, |
| 2548 | } }, &.{ty_op.operand}); |
| 2549 | } |
| 2550 | |
| 2551 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 2552 | const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| 2553 | src_mcv |
| 2554 | else |
| 2555 | try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv); |
| 2556 | const dst_reg = dst_mcv.getReg().?.to128(); |
| 2557 | const dst_lock = self.register_manager.lockReg(dst_reg); |
| 2558 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 2526 | 2559 | |
| 2527 | | if (dst_bits == 16 and self.hasFeature(.f16c)) { |
| 2528 | | switch (src_bits) { |
| 2529 | | 32 => { |
| 2530 | | const mat_src_reg = if (src_mcv.isRegister()) |
| 2560 | if (dst_bits == 16) { |
| 2561 | assert(self.hasFeature(.f16c)); |
| 2562 | switch (src_bits) { |
| 2563 | 32 => { |
| 2564 | const mat_src_reg = if (src_mcv.isRegister()) |
| 2565 | src_mcv.getReg().? |
| 2566 | else |
| 2567 | try self.copyToTmpRegister(src_ty, src_mcv); |
| 2568 | try self.asmRegisterRegisterImmediate( |
| 2569 | .{ .v_, .cvtps2ph }, |
| 2570 | dst_reg, |
| 2571 | mat_src_reg.to128(), |
| 2572 | Immediate.u(0b1_00), |
| 2573 | ); |
| 2574 | }, |
| 2575 | else => unreachable, |
| 2576 | } |
| 2577 | } else { |
| 2578 | assert(src_bits == 64 and dst_bits == 32); |
| 2579 | if (self.hasFeature(.avx)) if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory( |
| 2580 | .{ .v_ss, .cvtsd2 }, |
| 2581 | dst_reg, |
| 2582 | dst_reg, |
| 2583 | src_mcv.mem(.qword), |
| 2584 | ) else try self.asmRegisterRegisterRegister( |
| 2585 | .{ .v_ss, .cvtsd2 }, |
| 2586 | dst_reg, |
| 2587 | dst_reg, |
| 2588 | (if (src_mcv.isRegister()) |
| 2531 | 2589 | src_mcv.getReg().? |
| 2532 | 2590 | else |
| 2533 | | try self.copyToTmpRegister(src_ty, src_mcv); |
| 2534 | | try self.asmRegisterRegisterImmediate( |
| 2535 | | .{ .v_, .cvtps2ph }, |
| 2536 | | dst_reg, |
| 2537 | | mat_src_reg.to128(), |
| 2538 | | Immediate.u(0b1_00), |
| 2539 | | ); |
| 2540 | | }, |
| 2541 | | else => return self.fail("TODO implement airFptrunc from {} to {}", .{ |
| 2542 | | src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?), |
| 2543 | | }), |
| 2591 | try self.copyToTmpRegister(src_ty, src_mcv)).to128(), |
| 2592 | ) else if (src_mcv.isMemory()) try self.asmRegisterMemory( |
| 2593 | .{ ._ss, .cvtsd2 }, |
| 2594 | dst_reg, |
| 2595 | src_mcv.mem(.qword), |
| 2596 | ) else try self.asmRegisterRegister( |
| 2597 | .{ ._ss, .cvtsd2 }, |
| 2598 | dst_reg, |
| 2599 | (if (src_mcv.isRegister()) |
| 2600 | src_mcv.getReg().? |
| 2601 | else |
| 2602 | try self.copyToTmpRegister(src_ty, src_mcv)).to128(), |
| 2603 | ); |
| 2544 | 2604 | } |
| 2545 | | } else if (src_bits == 64 and dst_bits == 32) { |
| 2546 | | if (self.hasFeature(.avx)) if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory( |
| 2547 | | .{ .v_ss, .cvtsd2 }, |
| 2548 | | dst_reg, |
| 2549 | | dst_reg, |
| 2550 | | src_mcv.mem(.qword), |
| 2551 | | ) else try self.asmRegisterRegisterRegister( |
| 2552 | | .{ .v_ss, .cvtsd2 }, |
| 2553 | | dst_reg, |
| 2554 | | dst_reg, |
| 2555 | | (if (src_mcv.isRegister()) |
| 2556 | | src_mcv.getReg().? |
| 2557 | | else |
| 2558 | | try self.copyToTmpRegister(src_ty, src_mcv)).to128(), |
| 2559 | | ) else if (src_mcv.isMemory()) try self.asmRegisterMemory( |
| 2560 | | .{ ._ss, .cvtsd2 }, |
| 2561 | | dst_reg, |
| 2562 | | src_mcv.mem(.qword), |
| 2563 | | ) else try self.asmRegisterRegister( |
| 2564 | | .{ ._ss, .cvtsd2 }, |
| 2565 | | dst_reg, |
| 2566 | | (if (src_mcv.isRegister()) |
| 2567 | | src_mcv.getReg().? |
| 2568 | | else |
| 2569 | | try self.copyToTmpRegister(src_ty, src_mcv)).to128(), |
| 2570 | | ); |
| 2571 | | } else return self.fail("TODO implement airFptrunc from {} to {}", .{ |
| 2572 | | src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?), |
| 2573 | | }); |
| 2574 | | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 2605 | break :result dst_mcv; |
| 2606 | }; |
| 2607 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 2575 | 2608 | } |
| 2576 | 2609 | |
| 2577 | 2610 | fn airFpext(self: *Self, inst: Air.Inst.Index) !void { |
| ... | ... | @@ -2581,58 +2614,96 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void { |
| 2581 | 2614 | const src_ty = self.typeOf(ty_op.operand); |
| 2582 | 2615 | const src_bits = src_ty.floatBits(self.target.*); |
| 2583 | 2616 | |
| 2584 | | const src_mcv = try self.resolveInst(ty_op.operand); |
| 2585 | | const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| 2586 | | src_mcv |
| 2587 | | else |
| 2588 | | try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv); |
| 2589 | | const dst_reg = dst_mcv.getReg().?.to128(); |
| 2590 | | const dst_lock = self.register_manager.lockReg(dst_reg); |
| 2591 | | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 2617 | const result = result: { |
| 2618 | if (switch (src_bits) { |
| 2619 | 16 => switch (dst_bits) { |
| 2620 | 32, 64 => !self.hasFeature(.f16c), |
| 2621 | 80, 128 => true, |
| 2622 | else => unreachable, |
| 2623 | }, |
| 2624 | 32 => switch (dst_bits) { |
| 2625 | 64 => false, |
| 2626 | 80, 128 => true, |
| 2627 | else => unreachable, |
| 2628 | }, |
| 2629 | 64 => switch (dst_bits) { |
| 2630 | 80, 128 => true, |
| 2631 | else => unreachable, |
| 2632 | }, |
| 2633 | 80 => switch (dst_bits) { |
| 2634 | 128 => true, |
| 2635 | else => unreachable, |
| 2636 | }, |
| 2637 | else => unreachable, |
| 2638 | }) { |
| 2639 | var callee: ["__extend?f?f2".len]u8 = undefined; |
| 2640 | break :result try self.genCall(.{ .lib = .{ |
| 2641 | .return_type = self.floatCompilerRtAbiType(dst_ty, src_ty).toIntern(), |
| 2642 | .param_types = &.{self.floatCompilerRtAbiType(src_ty, dst_ty).toIntern()}, |
| 2643 | .callee = std.fmt.bufPrint(&callee, "__extend{c}f{c}f2", .{ |
| 2644 | floatCompilerRtAbiName(src_bits), |
| 2645 | floatCompilerRtAbiName(dst_bits), |
| 2646 | }) catch unreachable, |
| 2647 | } }, &.{ty_op.operand}); |
| 2648 | } |
| 2592 | 2649 | |
| 2593 | | if (src_bits == 16 and self.hasFeature(.f16c)) { |
| 2594 | | const mat_src_reg = if (src_mcv.isRegister()) |
| 2595 | | src_mcv.getReg().? |
| 2650 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 2651 | const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| 2652 | src_mcv |
| 2596 | 2653 | else |
| 2597 | | try self.copyToTmpRegister(src_ty, src_mcv); |
| 2598 | | try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg, mat_src_reg.to128()); |
| 2599 | | switch (dst_bits) { |
| 2600 | | 32 => {}, |
| 2601 | | 64 => try self.asmRegisterRegisterRegister(.{ .v_sd, .cvtss2 }, dst_reg, dst_reg, dst_reg), |
| 2602 | | else => return self.fail("TODO implement airFpext from {} to {}", .{ |
| 2603 | | src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?), |
| 2604 | | }), |
| 2605 | | } |
| 2606 | | } else if (src_bits == 32 and dst_bits == 64) { |
| 2607 | | if (self.hasFeature(.avx)) if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory( |
| 2608 | | .{ .v_sd, .cvtss2 }, |
| 2609 | | dst_reg, |
| 2610 | | dst_reg, |
| 2611 | | src_mcv.mem(.dword), |
| 2612 | | ) else try self.asmRegisterRegisterRegister( |
| 2613 | | .{ .v_sd, .cvtss2 }, |
| 2614 | | dst_reg, |
| 2615 | | dst_reg, |
| 2616 | | (if (src_mcv.isRegister()) |
| 2617 | | src_mcv.getReg().? |
| 2618 | | else |
| 2619 | | try self.copyToTmpRegister(src_ty, src_mcv)).to128(), |
| 2620 | | ) else if (src_mcv.isMemory()) try self.asmRegisterMemory( |
| 2621 | | .{ ._sd, .cvtss2 }, |
| 2622 | | dst_reg, |
| 2623 | | src_mcv.mem(.dword), |
| 2624 | | ) else try self.asmRegisterRegister( |
| 2625 | | .{ ._sd, .cvtss2 }, |
| 2626 | | dst_reg, |
| 2627 | | (if (src_mcv.isRegister()) |
| 2654 | try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv); |
| 2655 | const dst_reg = dst_mcv.getReg().?.to128(); |
| 2656 | const dst_lock = self.register_manager.lockReg(dst_reg); |
| 2657 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 2658 | |
| 2659 | if (src_bits == 16) { |
| 2660 | assert(self.hasFeature(.f16c)); |
| 2661 | const mat_src_reg = if (src_mcv.isRegister()) |
| 2628 | 2662 | src_mcv.getReg().? |
| 2629 | 2663 | else |
| 2630 | | try self.copyToTmpRegister(src_ty, src_mcv)).to128(), |
| 2631 | | ); |
| 2632 | | } else return self.fail("TODO implement airFpext from {} to {}", .{ |
| 2633 | | src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?), |
| 2634 | | }); |
| 2635 | | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 2664 | try self.copyToTmpRegister(src_ty, src_mcv); |
| 2665 | try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg, mat_src_reg.to128()); |
| 2666 | switch (dst_bits) { |
| 2667 | 32 => {}, |
| 2668 | 64 => try self.asmRegisterRegisterRegister( |
| 2669 | .{ .v_sd, .cvtss2 }, |
| 2670 | dst_reg, |
| 2671 | dst_reg, |
| 2672 | dst_reg, |
| 2673 | ), |
| 2674 | else => unreachable, |
| 2675 | } |
| 2676 | } else { |
| 2677 | assert(src_bits == 32 and dst_bits == 64); |
| 2678 | if (self.hasFeature(.avx)) if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory( |
| 2679 | .{ .v_sd, .cvtss2 }, |
| 2680 | dst_reg, |
| 2681 | dst_reg, |
| 2682 | src_mcv.mem(.dword), |
| 2683 | ) else try self.asmRegisterRegisterRegister( |
| 2684 | .{ .v_sd, .cvtss2 }, |
| 2685 | dst_reg, |
| 2686 | dst_reg, |
| 2687 | (if (src_mcv.isRegister()) |
| 2688 | src_mcv.getReg().? |
| 2689 | else |
| 2690 | try self.copyToTmpRegister(src_ty, src_mcv)).to128(), |
| 2691 | ) else if (src_mcv.isMemory()) try self.asmRegisterMemory( |
| 2692 | .{ ._sd, .cvtss2 }, |
| 2693 | dst_reg, |
| 2694 | src_mcv.mem(.dword), |
| 2695 | ) else try self.asmRegisterRegister( |
| 2696 | .{ ._sd, .cvtss2 }, |
| 2697 | dst_reg, |
| 2698 | (if (src_mcv.isRegister()) |
| 2699 | src_mcv.getReg().? |
| 2700 | else |
| 2701 | try self.copyToTmpRegister(src_ty, src_mcv)).to128(), |
| 2702 | ); |
| 2703 | } |
| 2704 | break :result dst_mcv; |
| 2705 | }; |
| 2706 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 2636 | 2707 | } |
| 2637 | 2708 | |
| 2638 | 2709 | fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| ... | ... | @@ -8358,26 +8429,64 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 8358 | 8429 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 8359 | 8430 | const ty = self.typeOf(bin_op.lhs); |
| 8360 | 8431 | |
| 8361 | | try self.spillEflagsIfOccupied(); |
| 8362 | | self.eflags_inst = inst; |
| 8432 | const result: Condition = result: { |
| 8433 | switch (ty.zigTypeTag(mod)) { |
| 8434 | .Float => { |
| 8435 | const float_bits = ty.floatBits(self.target.*); |
| 8436 | if (switch (float_bits) { |
| 8437 | 16 => !self.hasFeature(.f16c), |
| 8438 | 32, 64 => false, |
| 8439 | 80, 128 => true, |
| 8440 | else => unreachable, |
| 8441 | }) { |
| 8442 | var callee: ["__???f2".len]u8 = undefined; |
| 8443 | const ret = try self.genCall(.{ .lib = .{ |
| 8444 | .return_type = .i32_type, |
| 8445 | .param_types = &.{ ty.toIntern(), ty.toIntern() }, |
| 8446 | .callee = std.fmt.bufPrint(&callee, "__{s}{c}f2", .{ |
| 8447 | switch (op) { |
| 8448 | .eq => "eq", |
| 8449 | .neq => "ne", |
| 8450 | .lt => "lt", |
| 8451 | .lte => "le", |
| 8452 | .gt => "gt", |
| 8453 | .gte => "ge", |
| 8454 | }, |
| 8455 | floatCompilerRtAbiName(float_bits), |
| 8456 | }) catch unreachable, |
| 8457 | } }, &.{ bin_op.lhs, bin_op.rhs }); |
| 8458 | try self.genBinOpMir(.{ ._, .@"test" }, Type.i32, ret, ret); |
| 8459 | break :result switch (op) { |
| 8460 | .eq => .e, |
| 8461 | .neq => .ne, |
| 8462 | .lt => .l, |
| 8463 | .lte => .le, |
| 8464 | .gt => .g, |
| 8465 | .gte => .ge, |
| 8466 | }; |
| 8467 | } |
| 8468 | }, |
| 8469 | else => {}, |
| 8470 | } |
| 8363 | 8471 | |
| 8364 | | const lhs_mcv = try self.resolveInst(bin_op.lhs); |
| 8365 | | const lhs_lock = switch (lhs_mcv) { |
| 8366 | | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 8367 | | else => null, |
| 8368 | | }; |
| 8369 | | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 8472 | try self.spillEflagsIfOccupied(); |
| 8370 | 8473 | |
| 8371 | | const rhs_mcv = try self.resolveInst(bin_op.rhs); |
| 8372 | | const rhs_lock = switch (rhs_mcv) { |
| 8373 | | .register => |reg| self.register_manager.lockReg(reg), |
| 8374 | | else => null, |
| 8375 | | }; |
| 8376 | | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 8474 | const lhs_mcv = try self.resolveInst(bin_op.lhs); |
| 8475 | const lhs_lock = switch (lhs_mcv) { |
| 8476 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 8477 | else => null, |
| 8478 | }; |
| 8479 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 8377 | 8480 | |
| 8378 | | const result = MCValue{ |
| 8379 | | .eflags = switch (ty.zigTypeTag(mod)) { |
| 8380 | | else => result: { |
| 8481 | const rhs_mcv = try self.resolveInst(bin_op.rhs); |
| 8482 | const rhs_lock = switch (rhs_mcv) { |
| 8483 | .register => |reg| self.register_manager.lockReg(reg), |
| 8484 | else => null, |
| 8485 | }; |
| 8486 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 8487 | |
| 8488 | switch (ty.zigTypeTag(mod)) { |
| 8489 | else => { |
| 8381 | 8490 | const abi_size: u16 = @intCast(ty.abiSize(mod)); |
| 8382 | 8491 | const may_flip: enum { |
| 8383 | 8492 | may_flip, |
| ... | ... | @@ -8479,7 +8588,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 8479 | 8588 | }, |
| 8480 | 8589 | ); |
| 8481 | 8590 | }, |
| 8482 | | .Float => result: { |
| 8591 | .Float => { |
| 8483 | 8592 | const flipped = switch (op) { |
| 8484 | 8593 | .lt, .lte => true, |
| 8485 | 8594 | .eq, .gte, .gt, .neq => false, |
| ... | ... | @@ -8495,7 +8604,8 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 8495 | 8604 | const src_mcv = if (flipped) lhs_mcv else rhs_mcv; |
| 8496 | 8605 | |
| 8497 | 8606 | switch (ty.floatBits(self.target.*)) { |
| 8498 | | 16 => if (self.hasFeature(.f16c)) { |
| 8607 | 16 => { |
| 8608 | assert(self.hasFeature(.f16c)); |
| 8499 | 8609 | const tmp1_reg = (try self.register_manager.allocReg(null, sse)).to128(); |
| 8500 | 8610 | const tmp1_mcv = MCValue{ .register = tmp1_reg }; |
| 8501 | 8611 | const tmp1_lock = self.register_manager.lockRegAssumeUnused(tmp1_reg); |
| ... | ... | @@ -8524,9 +8634,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 8524 | 8634 | try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, tmp1_reg, tmp1_reg); |
| 8525 | 8635 | try self.asmRegisterRegister(.{ .v_, .movshdup }, tmp2_reg, tmp1_reg); |
| 8526 | 8636 | try self.genBinOpMir(.{ ._ss, .ucomi }, ty, tmp1_mcv, tmp2_mcv); |
| 8527 | | } else return self.fail("TODO implement airCmp for {}", .{ |
| 8528 | | ty.fmt(mod), |
| 8529 | | }), |
| 8637 | }, |
| 8530 | 8638 | 32 => try self.genBinOpMir( |
| 8531 | 8639 | .{ ._ss, .ucomi }, |
| 8532 | 8640 | ty, |
| ... | ... | @@ -8539,9 +8647,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 8539 | 8647 | .{ .register = dst_reg }, |
| 8540 | 8648 | src_mcv, |
| 8541 | 8649 | ), |
| 8542 | | else => return self.fail("TODO implement airCmp for {}", .{ |
| 8543 | | ty.fmt(mod), |
| 8544 | | }), |
| 8650 | else => unreachable, |
| 8545 | 8651 | } |
| 8546 | 8652 | |
| 8547 | 8653 | break :result switch (if (flipped) op.reverse() else op) { |
| ... | ... | @@ -8552,9 +8658,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 8552 | 8658 | .neq => .nz_or_p, |
| 8553 | 8659 | }; |
| 8554 | 8660 | }, |
| 8555 | | }, |
| 8661 | } |
| 8556 | 8662 | }; |
| 8557 | | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 8663 | |
| 8664 | self.eflags_inst = inst; |
| 8665 | return self.finishAir(inst, .{ .eflags = result }, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 8558 | 8666 | } |
| 8559 | 8667 | |
| 8560 | 8668 | fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void { |
| ... | ... | @@ -8572,7 +8680,6 @@ fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void { |
| 8572 | 8680 | try self.genLazySymbolRef(.lea, addr_reg, link.File.LazySymbol.initDecl(.const_data, null, mod)); |
| 8573 | 8681 | |
| 8574 | 8682 | try self.spillEflagsIfOccupied(); |
| 8575 | | self.eflags_inst = inst; |
| 8576 | 8683 | |
| 8577 | 8684 | const op_ty = self.typeOf(un_op); |
| 8578 | 8685 | const op_abi_size: u32 = @intCast(op_ty.abiSize(mod)); |
| ... | ... | @@ -8586,8 +8693,9 @@ fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void { |
| 8586 | 8693 | registerAlias(dst_reg, op_abi_size), |
| 8587 | 8694 | Memory.sib(Memory.PtrSize.fromSize(op_abi_size), .{ .base = .{ .reg = addr_reg } }), |
| 8588 | 8695 | ); |
| 8589 | | const result = MCValue{ .eflags = .b }; |
| 8590 | | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 8696 | |
| 8697 | self.eflags_inst = inst; |
| 8698 | return self.finishAir(inst, .{ .eflags = .b }, .{ un_op, .none, .none }); |
| 8591 | 8699 | } |
| 8592 | 8700 | |
| 8593 | 8701 | fn airTry(self: *Self, inst: Air.Inst.Index) !void { |
| ... | ... | @@ -8777,7 +8885,6 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC |
| 8777 | 8885 | } |
| 8778 | 8886 | |
| 8779 | 8887 | try self.spillEflagsIfOccupied(); |
| 8780 | | self.eflags_inst = inst; |
| 8781 | 8888 | |
| 8782 | 8889 | const pl_ty = opt_ty.optionalChild(mod); |
| 8783 | 8890 | |
| ... | ... | @@ -8786,6 +8893,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC |
| 8786 | 8893 | else |
| 8787 | 8894 | .{ .off = @intCast(pl_ty.abiSize(mod)), .ty = Type.bool }; |
| 8788 | 8895 | |
| 8896 | self.eflags_inst = inst; |
| 8789 | 8897 | switch (opt_mcv) { |
| 8790 | 8898 | .none, |
| 8791 | 8899 | .unreach, |
| ... | ... | @@ -8867,7 +8975,6 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC |
| 8867 | 8975 | fn isNullPtr(self: *Self, inst: Air.Inst.Index, ptr_ty: Type, ptr_mcv: MCValue) !MCValue { |
| 8868 | 8976 | const mod = self.bin_file.options.module.?; |
| 8869 | 8977 | try self.spillEflagsIfOccupied(); |
| 8870 | | self.eflags_inst = inst; |
| 8871 | 8978 | |
| 8872 | 8979 | const opt_ty = ptr_ty.childType(mod); |
| 8873 | 8980 | const pl_ty = opt_ty.optionalChild(mod); |
| ... | ... | @@ -8893,6 +9000,8 @@ fn isNullPtr(self: *Self, inst: Air.Inst.Index, ptr_ty: Type, ptr_mcv: MCValue) |
| 8893 | 9000 | }), |
| 8894 | 9001 | Immediate.u(0), |
| 8895 | 9002 | ); |
| 9003 | |
| 9004 | self.eflags_inst = inst; |
| 8896 | 9005 | return .{ .eflags = .e }; |
| 8897 | 9006 | } |
| 8898 | 9007 | |
| ... | ... | @@ -8905,9 +9014,6 @@ fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, ty: Type, operand: MCValue) ! |
| 8905 | 9014 | } |
| 8906 | 9015 | |
| 8907 | 9016 | try self.spillEflagsIfOccupied(); |
| 8908 | | if (maybe_inst) |inst| { |
| 8909 | | self.eflags_inst = inst; |
| 8910 | | } |
| 8911 | 9017 | |
| 8912 | 9018 | const err_off = errUnionErrorOffset(ty.errorUnionPayload(mod), mod); |
| 8913 | 9019 | switch (operand) { |
| ... | ... | @@ -8945,6 +9051,7 @@ fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, ty: Type, operand: MCValue) ! |
| 8945 | 9051 | else => return self.fail("TODO implement isErr for {}", .{operand}), |
| 8946 | 9052 | } |
| 8947 | 9053 | |
| 9054 | if (maybe_inst) |inst| self.eflags_inst = inst; |
| 8948 | 9055 | return MCValue{ .eflags = .a }; |
| 8949 | 9056 | } |
| 8950 | 9057 | |
| ... | ... | @@ -10526,106 +10633,150 @@ fn airFloatFromInt(self: *Self, inst: Air.Inst.Index) !void { |
| 10526 | 10633 | const mod = self.bin_file.options.module.?; |
| 10527 | 10634 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 10528 | 10635 | |
| 10636 | const dst_ty = self.typeOfIndex(inst); |
| 10637 | const dst_bits = dst_ty.floatBits(self.target.*); |
| 10638 | |
| 10529 | 10639 | const src_ty = self.typeOf(ty_op.operand); |
| 10530 | 10640 | const src_bits: u32 = @intCast(src_ty.bitSize(mod)); |
| 10531 | 10641 | const src_signedness = |
| 10532 | 10642 | if (src_ty.isAbiInt(mod)) src_ty.intInfo(mod).signedness else .unsigned; |
| 10533 | | const dst_ty = self.typeOfIndex(inst); |
| 10534 | | |
| 10535 | 10643 | const src_size = math.divCeil(u32, @max(switch (src_signedness) { |
| 10536 | 10644 | .signed => src_bits, |
| 10537 | 10645 | .unsigned => src_bits + 1, |
| 10538 | 10646 | }, 32), 8) catch unreachable; |
| 10539 | | if (src_size > 8) return self.fail("TODO implement airFloatFromInt from {} to {}", .{ |
| 10540 | | src_ty.fmt(mod), dst_ty.fmt(mod), |
| 10541 | | }); |
| 10542 | 10647 | |
| 10543 | | const src_mcv = try self.resolveInst(ty_op.operand); |
| 10544 | | const src_reg = if (src_mcv.isRegister()) |
| 10545 | | src_mcv.getReg().? |
| 10546 | | else |
| 10547 | | try self.copyToTmpRegister(src_ty, src_mcv); |
| 10548 | | const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); |
| 10549 | | defer self.register_manager.unlockReg(src_lock); |
| 10648 | const result = result: { |
| 10649 | if (switch (dst_bits) { |
| 10650 | 16, 80, 128 => true, |
| 10651 | 32, 64 => src_size > 8 and src_size < 16, |
| 10652 | else => unreachable, |
| 10653 | }) { |
| 10654 | var callee: ["__floatun?i?f".len]u8 = undefined; |
| 10655 | break :result try self.genCall(.{ .lib = .{ |
| 10656 | .return_type = dst_ty.toIntern(), |
| 10657 | .param_types = &.{src_ty.toIntern()}, |
| 10658 | .callee = std.fmt.bufPrint(&callee, "__float{s}{c}i{c}f", .{ |
| 10659 | switch (src_signedness) { |
| 10660 | .signed => "", |
| 10661 | .unsigned => "un", |
| 10662 | }, |
| 10663 | intCompilerRtAbiName(src_bits), |
| 10664 | floatCompilerRtAbiName(dst_bits), |
| 10665 | }) catch unreachable, |
| 10666 | } }, &.{ty_op.operand}); |
| 10667 | } |
| 10550 | 10668 | |
| 10551 | | if (src_bits < src_size * 8) try self.truncateRegister(src_ty, src_reg); |
| 10669 | if (src_size > 8) return self.fail("TODO implement airFloatFromInt from {} to {}", .{ |
| 10670 | src_ty.fmt(mod), dst_ty.fmt(mod), |
| 10671 | }); |
| 10552 | 10672 | |
| 10553 | | const dst_reg = try self.register_manager.allocReg(inst, regClassForType(dst_ty, mod)); |
| 10554 | | const dst_mcv = MCValue{ .register = dst_reg }; |
| 10555 | | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 10556 | | defer self.register_manager.unlockReg(dst_lock); |
| 10673 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 10674 | const src_reg = if (src_mcv.isRegister()) |
| 10675 | src_mcv.getReg().? |
| 10676 | else |
| 10677 | try self.copyToTmpRegister(src_ty, src_mcv); |
| 10678 | const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); |
| 10679 | defer self.register_manager.unlockReg(src_lock); |
| 10557 | 10680 | |
| 10558 | | const mir_tag = @as(?Mir.Inst.FixedTag, switch (dst_ty.zigTypeTag(mod)) { |
| 10559 | | .Float => switch (dst_ty.floatBits(self.target.*)) { |
| 10560 | | 32 => if (self.hasFeature(.avx)) .{ .v_ss, .cvtsi2 } else .{ ._ss, .cvtsi2 }, |
| 10561 | | 64 => if (self.hasFeature(.avx)) .{ .v_sd, .cvtsi2 } else .{ ._sd, .cvtsi2 }, |
| 10562 | | 16, 80, 128 => null, |
| 10563 | | else => unreachable, |
| 10564 | | }, |
| 10565 | | else => null, |
| 10566 | | }) orelse return self.fail("TODO implement airFloatFromInt from {} to {}", .{ |
| 10567 | | src_ty.fmt(mod), dst_ty.fmt(mod), |
| 10568 | | }); |
| 10569 | | const dst_alias = dst_reg.to128(); |
| 10570 | | const src_alias = registerAlias(src_reg, src_size); |
| 10571 | | switch (mir_tag[0]) { |
| 10572 | | .v_ss, .v_sd => try self.asmRegisterRegisterRegister(mir_tag, dst_alias, dst_alias, src_alias), |
| 10573 | | else => try self.asmRegisterRegister(mir_tag, dst_alias, src_alias), |
| 10574 | | } |
| 10681 | if (src_bits < src_size * 8) try self.truncateRegister(src_ty, src_reg); |
| 10575 | 10682 | |
| 10576 | | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 10683 | const dst_reg = try self.register_manager.allocReg(inst, regClassForType(dst_ty, mod)); |
| 10684 | const dst_mcv = MCValue{ .register = dst_reg }; |
| 10685 | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 10686 | defer self.register_manager.unlockReg(dst_lock); |
| 10687 | |
| 10688 | const mir_tag = @as(?Mir.Inst.FixedTag, switch (dst_ty.zigTypeTag(mod)) { |
| 10689 | .Float => switch (dst_ty.floatBits(self.target.*)) { |
| 10690 | 32 => if (self.hasFeature(.avx)) .{ .v_ss, .cvtsi2 } else .{ ._ss, .cvtsi2 }, |
| 10691 | 64 => if (self.hasFeature(.avx)) .{ .v_sd, .cvtsi2 } else .{ ._sd, .cvtsi2 }, |
| 10692 | 16, 80, 128 => null, |
| 10693 | else => unreachable, |
| 10694 | }, |
| 10695 | else => null, |
| 10696 | }) orelse return self.fail("TODO implement airFloatFromInt from {} to {}", .{ |
| 10697 | src_ty.fmt(mod), dst_ty.fmt(mod), |
| 10698 | }); |
| 10699 | const dst_alias = dst_reg.to128(); |
| 10700 | const src_alias = registerAlias(src_reg, src_size); |
| 10701 | switch (mir_tag[0]) { |
| 10702 | .v_ss, .v_sd => try self.asmRegisterRegisterRegister(mir_tag, dst_alias, dst_alias, src_alias), |
| 10703 | else => try self.asmRegisterRegister(mir_tag, dst_alias, src_alias), |
| 10704 | } |
| 10705 | |
| 10706 | break :result dst_mcv; |
| 10707 | }; |
| 10708 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 10577 | 10709 | } |
| 10578 | 10710 | |
| 10579 | 10711 | fn airIntFromFloat(self: *Self, inst: Air.Inst.Index) !void { |
| 10580 | 10712 | const mod = self.bin_file.options.module.?; |
| 10581 | 10713 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 10582 | 10714 | |
| 10583 | | const src_ty = self.typeOf(ty_op.operand); |
| 10584 | 10715 | const dst_ty = self.typeOfIndex(inst); |
| 10585 | 10716 | const dst_bits: u32 = @intCast(dst_ty.bitSize(mod)); |
| 10586 | 10717 | const dst_signedness = |
| 10587 | 10718 | if (dst_ty.isAbiInt(mod)) dst_ty.intInfo(mod).signedness else .unsigned; |
| 10588 | | |
| 10589 | 10719 | const dst_size = math.divCeil(u32, @max(switch (dst_signedness) { |
| 10590 | 10720 | .signed => dst_bits, |
| 10591 | 10721 | .unsigned => dst_bits + 1, |
| 10592 | 10722 | }, 32), 8) catch unreachable; |
| 10593 | | if (dst_size > 8) return self.fail("TODO implement airIntFromFloat from {} to {}", .{ |
| 10594 | | src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?), |
| 10595 | | }); |
| 10596 | 10723 | |
| 10597 | | const src_mcv = try self.resolveInst(ty_op.operand); |
| 10598 | | const src_reg = if (src_mcv.isRegister()) |
| 10599 | | src_mcv.getReg().? |
| 10600 | | else |
| 10601 | | try self.copyToTmpRegister(src_ty, src_mcv); |
| 10602 | | const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); |
| 10603 | | defer self.register_manager.unlockReg(src_lock); |
| 10724 | const src_ty = self.typeOf(ty_op.operand); |
| 10725 | const src_bits = src_ty.floatBits(self.target.*); |
| 10604 | 10726 | |
| 10605 | | const dst_reg = try self.register_manager.allocReg(inst, regClassForType(dst_ty, mod)); |
| 10606 | | const dst_mcv = MCValue{ .register = dst_reg }; |
| 10607 | | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 10608 | | defer self.register_manager.unlockReg(dst_lock); |
| 10727 | const result = result: { |
| 10728 | if (switch (src_bits) { |
| 10729 | 16, 80, 128 => true, |
| 10730 | 32, 64 => dst_size > 8 and dst_size < 16, |
| 10731 | else => unreachable, |
| 10732 | }) { |
| 10733 | var callee: ["__fixuns?f?i".len]u8 = undefined; |
| 10734 | break :result try self.genCall(.{ .lib = .{ |
| 10735 | .return_type = dst_ty.toIntern(), |
| 10736 | .param_types = &.{src_ty.toIntern()}, |
| 10737 | .callee = std.fmt.bufPrint(&callee, "__fix{s}{c}f{c}i", .{ |
| 10738 | switch (dst_signedness) { |
| 10739 | .signed => "", |
| 10740 | .unsigned => "uns", |
| 10741 | }, |
| 10742 | floatCompilerRtAbiName(src_bits), |
| 10743 | intCompilerRtAbiName(dst_bits), |
| 10744 | }) catch unreachable, |
| 10745 | } }, &.{ty_op.operand}); |
| 10746 | } |
| 10609 | 10747 | |
| 10610 | | try self.asmRegisterRegister( |
| 10611 | | @as(?Mir.Inst.FixedTag, switch (src_ty.zigTypeTag(mod)) { |
| 10612 | | .Float => switch (src_ty.floatBits(self.target.*)) { |
| 10748 | if (dst_size > 8) return self.fail("TODO implement airIntFromFloat from {} to {}", .{ |
| 10749 | src_ty.fmt(mod), dst_ty.fmt(mod), |
| 10750 | }); |
| 10751 | |
| 10752 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 10753 | const src_reg = if (src_mcv.isRegister()) |
| 10754 | src_mcv.getReg().? |
| 10755 | else |
| 10756 | try self.copyToTmpRegister(src_ty, src_mcv); |
| 10757 | const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); |
| 10758 | defer self.register_manager.unlockReg(src_lock); |
| 10759 | |
| 10760 | const dst_reg = try self.register_manager.allocReg(inst, regClassForType(dst_ty, mod)); |
| 10761 | const dst_mcv = MCValue{ .register = dst_reg }; |
| 10762 | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 10763 | defer self.register_manager.unlockReg(dst_lock); |
| 10764 | |
| 10765 | try self.asmRegisterRegister( |
| 10766 | switch (src_bits) { |
| 10613 | 10767 | 32 => if (self.hasFeature(.avx)) .{ .v_, .cvttss2si } else .{ ._, .cvttss2si }, |
| 10614 | 10768 | 64 => if (self.hasFeature(.avx)) .{ .v_, .cvttsd2si } else .{ ._, .cvttsd2si }, |
| 10615 | | 16, 80, 128 => null, |
| 10616 | 10769 | else => unreachable, |
| 10617 | 10770 | }, |
| 10618 | | else => null, |
| 10619 | | }) orelse return self.fail("TODO implement airIntFromFloat from {} to {}", .{ |
| 10620 | | src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?), |
| 10621 | | }), |
| 10622 | | registerAlias(dst_reg, dst_size), |
| 10623 | | src_reg.to128(), |
| 10624 | | ); |
| 10771 | registerAlias(dst_reg, dst_size), |
| 10772 | src_reg.to128(), |
| 10773 | ); |
| 10625 | 10774 | |
| 10626 | | if (dst_bits < dst_size * 8) try self.truncateRegister(dst_ty, dst_reg); |
| 10775 | if (dst_bits < dst_size * 8) try self.truncateRegister(dst_ty, dst_reg); |
| 10627 | 10776 | |
| 10628 | | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 10777 | break :result dst_mcv; |
| 10778 | }; |
| 10779 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 10629 | 10780 | } |
| 10630 | 10781 | |
| 10631 | 10782 | fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void { |
| ... | ... | @@ -12276,3 +12427,30 @@ fn typeOfIndex(self: *Self, inst: Air.Inst.Index) Type { |
| 12276 | 12427 | const mod = self.bin_file.options.module.?; |
| 12277 | 12428 | return self.air.typeOfIndex(inst, &mod.intern_pool); |
| 12278 | 12429 | } |
| 12430 | |
| 12431 | fn intCompilerRtAbiName(int_bits: u32) u8 { |
| 12432 | return switch (int_bits) { |
| 12433 | 1...32 => 's', |
| 12434 | 33...64 => 'd', |
| 12435 | 65...128 => 't', |
| 12436 | else => unreachable, |
| 12437 | }; |
| 12438 | } |
| 12439 | |
| 12440 | fn floatCompilerRtAbiName(float_bits: u32) u8 { |
| 12441 | return switch (float_bits) { |
| 12442 | 16 => 'h', |
| 12443 | 32 => 's', |
| 12444 | 64 => 'd', |
| 12445 | 80 => 'x', |
| 12446 | 128 => 't', |
| 12447 | else => unreachable, |
| 12448 | }; |
| 12449 | } |
| 12450 | |
| 12451 | fn floatCompilerRtAbiType(self: *Self, ty: Type, other_ty: Type) Type { |
| 12452 | if (ty.toIntern() == .f16_type and |
| 12453 | (other_ty.toIntern() == .f32_type or other_ty.toIntern() == .f64_type) and |
| 12454 | self.target.isDarwin()) return Type.u16; |
| 12455 | return ty; |
| 12456 | } |