| ... | @@ -586,7 +586,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -586,7 +586,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 586 | .is_err_ptr => @panic("TODO try self.airIsErrPtr(inst)"), | 586 | .is_err_ptr => @panic("TODO try self.airIsErrPtr(inst)"), |
| 587 | .load => try self.airLoad(inst), | 587 | .load => try self.airLoad(inst), |
| 588 | .loop => try self.airLoop(inst), | 588 | .loop => try self.airLoop(inst), |
| 589 | .not => @panic("TODO try self.airNot(inst)"), | 589 | .not => try self.airNot(inst), |
| 590 | .ptrtoint => @panic("TODO try self.airPtrToInt(inst)"), | 590 | .ptrtoint => @panic("TODO try self.airPtrToInt(inst)"), |
| 591 | .ret => try self.airRet(inst), | 591 | .ret => try self.airRet(inst), |
| 592 | .ret_load => try self.airRetLoad(inst), | 592 | .ret_load => try self.airRetLoad(inst), |
| ... | @@ -1507,6 +1507,126 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1507,6 +1507,126 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void { |
| 1507 | return self.finishAirBookkeeping(); | 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 | fn airRet(self: *Self, inst: Air.Inst.Index) !void { | 1630 | fn airRet(self: *Self, inst: Air.Inst.Index) !void { |
| 1511 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 1631 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 1512 | const operand = try self.resolveInst(un_op); | 1632 | const operand = try self.resolveInst(un_op); |