| ... | ... | @@ -586,7 +586,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 586 | 586 | .is_err_ptr => @panic("TODO try self.airIsErrPtr(inst)"), |
| 587 | 587 | .load => try self.airLoad(inst), |
| 588 | 588 | .loop => try self.airLoop(inst), |
| 589 | | .not => @panic("TODO try self.airNot(inst)"), |
| 589 | .not => try self.airNot(inst), |
| 590 | 590 | .ptrtoint => @panic("TODO try self.airPtrToInt(inst)"), |
| 591 | 591 | .ret => try self.airRet(inst), |
| 592 | 592 | .ret_load => try self.airRetLoad(inst), |
| ... | ... | @@ -1507,6 +1507,126 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void { |
| 1507 | 1507 | return self.finishAirBookkeeping(); |
| 1508 | 1508 | } |
| 1509 | 1509 | |
| 1510 | fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1511 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1512 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1513 | const operand = try self.resolveInst(ty_op.operand); |
| 1514 | const operand_ty = self.air.typeOf(ty_op.operand); |
| 1515 | switch (operand) { |
| 1516 | .dead => unreachable, |
| 1517 | .unreach => unreachable, |
| 1518 | .compare_flags_unsigned => |op| { |
| 1519 | const r = MCValue{ |
| 1520 | .compare_flags_unsigned = .{ |
| 1521 | .cmp = switch (op.cmp) { |
| 1522 | .gte => .lt, |
| 1523 | .gt => .lte, |
| 1524 | .neq => .eq, |
| 1525 | .lt => .gte, |
| 1526 | .lte => .gt, |
| 1527 | .eq => .neq, |
| 1528 | }, |
| 1529 | .ccr = op.ccr, |
| 1530 | }, |
| 1531 | }; |
| 1532 | break :result r; |
| 1533 | }, |
| 1534 | .compare_flags_signed => |op| { |
| 1535 | const r = MCValue{ |
| 1536 | .compare_flags_signed = .{ |
| 1537 | .cmp = switch (op.cmp) { |
| 1538 | .gte => .lt, |
| 1539 | .gt => .lte, |
| 1540 | .neq => .eq, |
| 1541 | .lt => .gte, |
| 1542 | .lte => .gt, |
| 1543 | .eq => .neq, |
| 1544 | }, |
| 1545 | .ccr = op.ccr, |
| 1546 | }, |
| 1547 | }; |
| 1548 | break :result r; |
| 1549 | }, |
| 1550 | else => { |
| 1551 | switch (operand_ty.zigTypeTag()) { |
| 1552 | .Bool => { |
| 1553 | // TODO convert this to mvn + and |
| 1554 | const op_reg = switch (operand) { |
| 1555 | .register => |r| r, |
| 1556 | else => try self.copyToTmpRegister(operand_ty, operand), |
| 1557 | }; |
| 1558 | const reg_lock = self.register_manager.lockRegAssumeUnused(op_reg); |
| 1559 | defer self.register_manager.unlockReg(reg_lock); |
| 1560 | |
| 1561 | const dest_reg = blk: { |
| 1562 | if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) { |
| 1563 | break :blk op_reg; |
| 1564 | } |
| 1565 | |
| 1566 | const reg = try self.register_manager.allocReg(null, gp); |
| 1567 | break :blk reg; |
| 1568 | }; |
| 1569 | |
| 1570 | _ = try self.addInst(.{ |
| 1571 | .tag = .xor, |
| 1572 | .data = .{ |
| 1573 | .arithmetic_3op = .{ |
| 1574 | .is_imm = true, |
| 1575 | .rd = dest_reg, |
| 1576 | .rs1 = op_reg, |
| 1577 | .rs2_or_imm = .{ .imm = 1 }, |
| 1578 | }, |
| 1579 | }, |
| 1580 | }); |
| 1581 | |
| 1582 | break :result MCValue{ .register = dest_reg }; |
| 1583 | }, |
| 1584 | .Vector => return self.fail("TODO bitwise not for vectors", .{}), |
| 1585 | .Int => { |
| 1586 | const int_info = operand_ty.intInfo(self.target.*); |
| 1587 | if (int_info.bits <= 64) { |
| 1588 | const op_reg = switch (operand) { |
| 1589 | .register => |r| r, |
| 1590 | else => try self.copyToTmpRegister(operand_ty, operand), |
| 1591 | }; |
| 1592 | const reg_lock = self.register_manager.lockRegAssumeUnused(op_reg); |
| 1593 | defer self.register_manager.unlockReg(reg_lock); |
| 1594 | |
| 1595 | const dest_reg = blk: { |
| 1596 | if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) { |
| 1597 | break :blk op_reg; |
| 1598 | } |
| 1599 | |
| 1600 | const reg = try self.register_manager.allocReg(null, gp); |
| 1601 | break :blk reg; |
| 1602 | }; |
| 1603 | |
| 1604 | _ = try self.addInst(.{ |
| 1605 | .tag = .not, |
| 1606 | .data = .{ |
| 1607 | .arithmetic_2op = .{ |
| 1608 | .is_imm = false, |
| 1609 | .rs1 = dest_reg, |
| 1610 | .rs2_or_imm = .{ .rs2 = op_reg }, |
| 1611 | }, |
| 1612 | }, |
| 1613 | }); |
| 1614 | |
| 1615 | try self.truncRegister(dest_reg, dest_reg, int_info.signedness, int_info.bits); |
| 1616 | |
| 1617 | break :result MCValue{ .register = dest_reg }; |
| 1618 | } else { |
| 1619 | return self.fail("TODO AArch64 not on integers > u64/i64", .{}); |
| 1620 | } |
| 1621 | }, |
| 1622 | else => unreachable, |
| 1623 | } |
| 1624 | }, |
| 1625 | } |
| 1626 | }; |
| 1627 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1628 | } |
| 1629 | |
| 1510 | 1630 | fn airRet(self: *Self, inst: Air.Inst.Index) !void { |
| 1511 | 1631 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 1512 | 1632 | const operand = try self.resolveInst(un_op); |