| ... | @@ -402,8 +402,8 @@ fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 { | ... | @@ -402,8 +402,8 @@ fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 { |
| 402 | fn asmSetccRegister(self: *Self, reg: Register, cc: bits.Condition) !void { | 402 | fn asmSetccRegister(self: *Self, reg: Register, cc: bits.Condition) !void { |
| 403 | _ = try self.addInst(.{ | 403 | _ = try self.addInst(.{ |
| 404 | .tag = .setcc, | 404 | .tag = .setcc, |
| 405 | .ops = .r_c, | 405 | .ops = .r_cc, |
| 406 | .data = .{ .r_c = .{ | 406 | .data = .{ .r_cc = .{ |
| 407 | .r1 = reg, | 407 | .r1 = reg, |
| 408 | .cc = cc, | 408 | .cc = cc, |
| 409 | } }, | 409 | } }, |
| ... | @@ -413,8 +413,8 @@ fn asmSetccRegister(self: *Self, reg: Register, cc: bits.Condition) !void { | ... | @@ -413,8 +413,8 @@ fn asmSetccRegister(self: *Self, reg: Register, cc: bits.Condition) !void { |
| 413 | fn asmCmovccRegisterRegister(self: *Self, reg1: Register, reg2: Register, cc: bits.Condition) !void { | 413 | fn asmCmovccRegisterRegister(self: *Self, reg1: Register, reg2: Register, cc: bits.Condition) !void { |
| 414 | _ = try self.addInst(.{ | 414 | _ = try self.addInst(.{ |
| 415 | .tag = .cmovcc, | 415 | .tag = .cmovcc, |
| 416 | .ops = .rr_c, | 416 | .ops = .rr_cc, |
| 417 | .data = .{ .rr_c = .{ | 417 | .data = .{ .rr_cc = .{ |
| 418 | .r1 = reg1, | 418 | .r1 = reg1, |
| 419 | .r2 = reg2, | 419 | .r2 = reg2, |
| 420 | .cc = cc, | 420 | .cc = cc, |
| ... | @@ -422,6 +422,26 @@ fn asmCmovccRegisterRegister(self: *Self, reg1: Register, reg2: Register, cc: bi | ... | @@ -422,6 +422,26 @@ fn asmCmovccRegisterRegister(self: *Self, reg1: Register, reg2: Register, cc: bi |
| 422 | }); | 422 | }); |
| 423 | } | 423 | } |
| 424 | | 424 | |
| | 425 | fn asmCmovccRegisterMemory(self: *Self, reg: Register, m: Memory, cc: bits.Condition) !void { |
| | 426 | _ = try self.addInst(.{ |
| | 427 | .tag = .cmovcc, |
| | 428 | .ops = switch (m) { |
| | 429 | .sib => .rm_sib_cc, |
| | 430 | .rip => .rm_rip_cc, |
| | 431 | else => unreachable, |
| | 432 | }, |
| | 433 | .data = .{ .rx_cc = .{ |
| | 434 | .r1 = reg, |
| | 435 | .cc = cc, |
| | 436 | .payload = switch (m) { |
| | 437 | .sib => try self.addExtra(Mir.MemorySib.encode(m)), |
| | 438 | .rip => try self.addExtra(Mir.MemoryRip.encode(m)), |
| | 439 | else => unreachable, |
| | 440 | }, |
| | 441 | } }, |
| | 442 | }); |
| | 443 | } |
| | 444 | |
| 425 | fn asmJmpReloc(self: *Self, target: Mir.Inst.Index) !Mir.Inst.Index { | 445 | fn asmJmpReloc(self: *Self, target: Mir.Inst.Index) !Mir.Inst.Index { |
| 426 | return self.addInst(.{ | 446 | return self.addInst(.{ |
| 427 | .tag = .jmp_reloc, | 447 | .tag = .jmp_reloc, |
| ... | @@ -793,18 +813,20 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -793,18 +813,20 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 793 | | 813 | |
| 794 | switch (air_tags[inst]) { | 814 | switch (air_tags[inst]) { |
| 795 | // zig fmt: off | 815 | // zig fmt: off |
| 796 | .add => try self.airBinOp(inst, .add), | 816 | .add, |
| 797 | .addwrap => try self.airBinOp(inst, .addwrap), | 817 | .addwrap, |
| 798 | .sub => try self.airBinOp(inst, .sub), | 818 | .sub, |
| 799 | .subwrap => try self.airBinOp(inst, .subwrap), | 819 | .subwrap, |
| 800 | .bool_and => try self.airBinOp(inst, .bool_and), | 820 | .bool_and, |
| 801 | .bool_or => try self.airBinOp(inst, .bool_or), | 821 | .bool_or, |
| 802 | .bit_and => try self.airBinOp(inst, .bit_and), | 822 | .bit_and, |
| 803 | .bit_or => try self.airBinOp(inst, .bit_or), | 823 | .bit_or, |
| 804 | .xor => try self.airBinOp(inst, .xor), | 824 | .xor, |
| 805 | | 825 | .min, |
| 806 | .ptr_add => try self.airPtrArithmetic(inst, .ptr_add), | 826 | .max, |
| 807 | .ptr_sub => try self.airPtrArithmetic(inst, .ptr_sub), | 827 | => |tag| try self.airBinOp(inst, tag), |
| | 828 | |
| | 829 | .ptr_add, .ptr_sub => |tag| try self.airPtrArithmetic(inst, tag), |
| 808 | | 830 | |
| 809 | .shr, .shr_exact => try self.airShlShrBinOp(inst), | 831 | .shr, .shr_exact => try self.airShlShrBinOp(inst), |
| 810 | .shl, .shl_exact => try self.airShlShrBinOp(inst), | 832 | .shl, .shl_exact => try self.airShlShrBinOp(inst), |
| ... | @@ -818,8 +840,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -818,8 +840,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 818 | .sub_sat => try self.airSubSat(inst), | 840 | .sub_sat => try self.airSubSat(inst), |
| 819 | .mul_sat => try self.airMulSat(inst), | 841 | .mul_sat => try self.airMulSat(inst), |
| 820 | .shl_sat => try self.airShlSat(inst), | 842 | .shl_sat => try self.airShlSat(inst), |
| 821 | .min => try self.airMin(inst), | | |
| 822 | .max => try self.airMax(inst), | | |
| 823 | .slice => try self.airSlice(inst), | 843 | .slice => try self.airSlice(inst), |
| 824 | | 844 | |
| 825 | .sqrt, | 845 | .sqrt, |
| ... | @@ -1466,61 +1486,6 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1466,61 +1486,6 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1466 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 1486 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1467 | } | 1487 | } |
| 1468 | | 1488 | |
| 1469 | fn airMin(self: *Self, inst: Air.Inst.Index) !void { | | |
| 1470 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | | |
| 1471 | if (self.liveness.isUnused(inst)) { | | |
| 1472 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); | | |
| 1473 | } | | |
| 1474 | | | |
| 1475 | const ty = self.air.typeOfIndex(inst); | | |
| 1476 | if (ty.zigTypeTag() != .Int) { | | |
| 1477 | return self.fail("TODO implement min for type {}", .{ty.fmtDebug()}); | | |
| 1478 | } | | |
| 1479 | const signedness = ty.intInfo(self.target.*).signedness; | | |
| 1480 | const result: MCValue = result: { | | |
| 1481 | // TODO improve by checking if any operand can be reused. | | |
| 1482 | // TODO audit register allocation | | |
| 1483 | const lhs = try self.resolveInst(bin_op.lhs); | | |
| 1484 | const lhs_lock: ?RegisterLock = switch (lhs) { | | |
| 1485 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | | |
| 1486 | else => null, | | |
| 1487 | }; | | |
| 1488 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); | | |
| 1489 | | | |
| 1490 | const lhs_reg = try self.copyToTmpRegister(ty, lhs); | | |
| 1491 | const lhs_reg_lock = self.register_manager.lockRegAssumeUnused(lhs_reg); | | |
| 1492 | defer self.register_manager.unlockReg(lhs_reg_lock); | | |
| 1493 | | | |
| 1494 | const rhs_mcv = try self.limitImmediateType(bin_op.rhs, i32); | | |
| 1495 | const rhs_lock: ?RegisterLock = switch (rhs_mcv) { | | |
| 1496 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | | |
| 1497 | else => null, | | |
| 1498 | }; | | |
| 1499 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); | | |
| 1500 | | | |
| 1501 | try self.genBinOpMir(.cmp, ty, .{ .register = lhs_reg }, rhs_mcv); | | |
| 1502 | | | |
| 1503 | const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ty, rhs_mcv); | | |
| 1504 | const cc: Condition = switch (signedness) { | | |
| 1505 | .unsigned => .b, | | |
| 1506 | .signed => .l, | | |
| 1507 | }; | | |
| 1508 | try self.asmCmovccRegisterRegister(dst_mcv.register, lhs_reg, cc); | | |
| 1509 | | | |
| 1510 | break :result dst_mcv; | | |
| 1511 | }; | | |
| 1512 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | | |
| 1513 | } | | |
| 1514 | | | |
| 1515 | fn airMax(self: *Self, inst: Air.Inst.Index) !void { | | |
| 1516 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | | |
| 1517 | const result: MCValue = if (self.liveness.isUnused(inst)) | | |
| 1518 | .dead | | |
| 1519 | else | | |
| 1520 | return self.fail("TODO implement max for {}", .{self.target.cpu.arch}); | | |
| 1521 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | | |
| 1522 | } | | |
| 1523 | | | |
| 1524 | fn airSlice(self: *Self, inst: Air.Inst.Index) !void { | 1489 | fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1525 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 1490 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1526 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 1491 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| ... | @@ -1545,11 +1510,10 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1545,11 +1510,10 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1545 | fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { | 1510 | fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 1546 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1511 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1547 | | 1512 | |
| 1548 | if (self.liveness.isUnused(inst)) { | 1513 | const result = if (self.liveness.isUnused(inst)) |
| 1549 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); | 1514 | .dead |
| 1550 | } | 1515 | else |
| 1551 | | 1516 | try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs); |
| 1552 | const result = try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs); | | |
| 1553 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1517 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1554 | } | 1518 | } |
| 1555 | | 1519 | |
| ... | @@ -1557,11 +1521,10 @@ fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void | ... | @@ -1557,11 +1521,10 @@ fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void |
| 1557 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 1521 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1558 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 1522 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1559 | | 1523 | |
| 1560 | if (self.liveness.isUnused(inst)) { | 1524 | const result = if (self.liveness.isUnused(inst)) |
| 1561 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); | 1525 | .dead |
| 1562 | } | 1526 | else |
| 1563 | | 1527 | try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs); |
| 1564 | const result = try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs); | | |
| 1565 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1528 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1566 | } | 1529 | } |
| 1567 | | 1530 | |
| ... | @@ -3486,10 +3449,10 @@ fn genBinOp( | ... | @@ -3486,10 +3449,10 @@ fn genBinOp( |
| 3486 | const lhs_ty = self.air.typeOf(lhs_air); | 3449 | const lhs_ty = self.air.typeOf(lhs_air); |
| 3487 | const rhs_ty = self.air.typeOf(rhs_air); | 3450 | const rhs_ty = self.air.typeOf(rhs_air); |
| 3488 | if (lhs_ty.zigTypeTag() == .Vector) { | 3451 | if (lhs_ty.zigTypeTag() == .Vector) { |
| 3489 | return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmtDebug()}); | 3452 | return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmt(self.bin_file.options.module.?)}); |
| 3490 | } | 3453 | } |
| 3491 | if (lhs_ty.abiSize(self.target.*) > 8) { | 3454 | if (lhs_ty.abiSize(self.target.*) > 8) { |
| 3492 | return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmtDebug()}); | 3455 | return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmt(self.bin_file.options.module.?)}); |
| 3493 | } | 3456 | } |
| 3494 | | 3457 | |
| 3495 | const is_commutative: bool = switch (tag) { | 3458 | const is_commutative: bool = switch (tag) { |
| ... | @@ -3500,6 +3463,8 @@ fn genBinOp( | ... | @@ -3500,6 +3463,8 @@ fn genBinOp( |
| 3500 | .bool_and, | 3463 | .bool_and, |
| 3501 | .bit_and, | 3464 | .bit_and, |
| 3502 | .xor, | 3465 | .xor, |
| | 3466 | .min, |
| | 3467 | .max, |
| 3503 | => true, | 3468 | => true, |
| 3504 | | 3469 | |
| 3505 | else => false, | 3470 | else => false, |
| ... | @@ -3520,10 +3485,10 @@ fn genBinOp( | ... | @@ -3520,10 +3485,10 @@ fn genBinOp( |
| 3520 | var flipped: bool = false; | 3485 | var flipped: bool = false; |
| 3521 | const dst_mcv: MCValue = blk: { | 3486 | const dst_mcv: MCValue = blk: { |
| 3522 | if (maybe_inst) |inst| { | 3487 | if (maybe_inst) |inst| { |
| 3523 | if (self.reuseOperand(inst, lhs_air, 0, lhs) and lhs.isRegister()) { | 3488 | if (lhs.isRegister() and self.reuseOperand(inst, lhs_air, 0, lhs)) { |
| 3524 | break :blk lhs; | 3489 | break :blk lhs; |
| 3525 | } | 3490 | } |
| 3526 | if (is_commutative and self.reuseOperand(inst, rhs_air, 1, rhs) and rhs.isRegister()) { | 3491 | if (rhs.isRegister() and is_commutative and self.reuseOperand(inst, rhs_air, 1, rhs)) { |
| 3527 | flipped = true; | 3492 | flipped = true; |
| 3528 | break :blk rhs; | 3493 | break :blk rhs; |
| 3529 | } | 3494 | } |
| ... | @@ -3580,6 +3545,58 @@ fn genBinOp( | ... | @@ -3580,6 +3545,58 @@ fn genBinOp( |
| 3580 | | 3545 | |
| 3581 | .xor => try self.genBinOpMir(.xor, lhs_ty, dst_mcv, src_mcv), | 3546 | .xor => try self.genBinOpMir(.xor, lhs_ty, dst_mcv, src_mcv), |
| 3582 | | 3547 | |
| | 3548 | .min, |
| | 3549 | .max, |
| | 3550 | => { |
| | 3551 | if (!lhs_ty.isAbiInt() or !rhs_ty.isAbiInt()) { |
| | 3552 | return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?) }); |
| | 3553 | } |
| | 3554 | |
| | 3555 | const mat_src_mcv = switch (src_mcv) { |
| | 3556 | .immediate => MCValue{ .register = try self.copyToTmpRegister(rhs_ty, src_mcv) }, |
| | 3557 | else => src_mcv, |
| | 3558 | }; |
| | 3559 | const mat_mcv_lock = switch (mat_src_mcv) { |
| | 3560 | .register => |reg| self.register_manager.lockReg(reg), |
| | 3561 | else => null, |
| | 3562 | }; |
| | 3563 | defer if (mat_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| | 3564 | |
| | 3565 | try self.genBinOpMir(.cmp, lhs_ty, dst_mcv, mat_src_mcv); |
| | 3566 | |
| | 3567 | const int_info = lhs_ty.intInfo(self.target.*); |
| | 3568 | const cc: Condition = switch (int_info.signedness) { |
| | 3569 | .unsigned => switch (tag) { |
| | 3570 | .min => .a, |
| | 3571 | .max => .b, |
| | 3572 | else => unreachable, |
| | 3573 | }, |
| | 3574 | .signed => switch (tag) { |
| | 3575 | .min => .g, |
| | 3576 | .max => .l, |
| | 3577 | else => unreachable, |
| | 3578 | }, |
| | 3579 | }; |
| | 3580 | |
| | 3581 | const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*)); |
| | 3582 | switch (dst_mcv) { |
| | 3583 | .register => |dst_reg| switch (mat_src_mcv) { |
| | 3584 | .register => |src_reg| try self.asmCmovccRegisterRegister( |
| | 3585 | registerAlias(dst_reg, abi_size), |
| | 3586 | registerAlias(src_reg, abi_size), |
| | 3587 | cc, |
| | 3588 | ), |
| | 3589 | .stack_offset => |off| try self.asmCmovccRegisterMemory( |
| | 3590 | registerAlias(dst_reg, abi_size), |
| | 3591 | Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .rbp, .disp = -off }), |
| | 3592 | cc, |
| | 3593 | ), |
| | 3594 | else => unreachable, |
| | 3595 | }, |
| | 3596 | else => unreachable, |
| | 3597 | } |
| | 3598 | }, |
| | 3599 | |
| 3583 | else => unreachable, | 3600 | else => unreachable, |
| 3584 | } | 3601 | } |
| 3585 | return dst_mcv; | 3602 | return dst_mcv; |
| ... | @@ -3660,13 +3677,10 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu | ... | @@ -3660,13 +3677,10 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu |
| 3660 | Immediate.s(small), | 3677 | Immediate.s(small), |
| 3661 | ); | 3678 | ); |
| 3662 | } else { | 3679 | } else { |
| 3663 | const tmp_reg = try self.register_manager.allocReg(null, gp); | | |
| 3664 | const tmp_alias = registerAlias(tmp_reg, abi_size); | | |
| 3665 | try self.asmRegisterImmediate(.mov, tmp_alias, Immediate.u(imm)); | | |
| 3666 | try self.asmRegisterRegister( | 3680 | try self.asmRegisterRegister( |
| 3667 | mir_tag, | 3681 | mir_tag, |
| 3668 | registerAlias(dst_reg, abi_size), | 3682 | registerAlias(dst_reg, abi_size), |
| 3669 | tmp_alias, | 3683 | registerAlias(try self.copyToTmpRegister(dst_ty, src_mcv), abi_size), |
| 3670 | ); | 3684 | ); |
| 3671 | } | 3685 | } |
| 3672 | }, | 3686 | }, |