| ... | ... | @@ -483,7 +483,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 483 | 483 | |
| 484 | 484 | switch (air_tags[inst]) { |
| 485 | 485 | // zig fmt: off |
| 486 | | .add, .ptr_add => @panic("TODO try self.airBinOp(inst)"), |
| 486 | .add, .ptr_add => try self.airBinOp(inst), |
| 487 | 487 | .addwrap => @panic("TODO try self.airAddWrap(inst)"), |
| 488 | 488 | .add_sat => @panic("TODO try self.airAddSat(inst)"), |
| 489 | 489 | .sub, .ptr_sub => @panic("TODO try self.airBinOp(inst)"), |
| ... | ... | @@ -825,6 +825,21 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 825 | 825 | return self.finishAir(inst, mcv, .{ .none, .none, .none }); |
| 826 | 826 | } |
| 827 | 827 | |
| 828 | fn airBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 829 | const tag = self.air.instructions.items(.tag)[inst]; |
| 830 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 831 | const lhs = try self.resolveInst(bin_op.lhs); |
| 832 | const rhs = try self.resolveInst(bin_op.rhs); |
| 833 | const lhs_ty = self.air.typeOf(bin_op.lhs); |
| 834 | const rhs_ty = self.air.typeOf(bin_op.rhs); |
| 835 | |
| 836 | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 837 | .dead |
| 838 | else |
| 839 | try self.binOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty); |
| 840 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 841 | } |
| 842 | |
| 828 | 843 | fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 829 | 844 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 830 | 845 | const result = try self.resolveInst(ty_op.operand); |
| ... | ... | @@ -1601,7 +1616,7 @@ fn binOp( |
| 1601 | 1616 | ) InnerError!MCValue { |
| 1602 | 1617 | const mod = self.bin_file.options.module.?; |
| 1603 | 1618 | switch (tag) { |
| 1604 | | .cmp_eq => { |
| 1619 | .add, .cmp_eq => { |
| 1605 | 1620 | switch (lhs_ty.zigTypeTag()) { |
| 1606 | 1621 | .Float => return self.fail("TODO binary operations on floats", .{}), |
| 1607 | 1622 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| ... | ... | @@ -1609,14 +1624,37 @@ fn binOp( |
| 1609 | 1624 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 1610 | 1625 | const int_info = lhs_ty.intInfo(self.target.*); |
| 1611 | 1626 | if (int_info.bits <= 64) { |
| 1612 | | // TODO optimize for small (i13) values by putting them inside immediates |
| 1627 | // Only say yes if the operation is |
| 1628 | // commutative, i.e. we can swap both of the |
| 1629 | // operands |
| 1630 | const lhs_immediate_ok = switch (tag) { |
| 1631 | .add => lhs == .immediate and lhs.immediate <= std.math.maxInt(u12), |
| 1632 | .sub, .cmp_eq => false, |
| 1633 | else => unreachable, |
| 1634 | }; |
| 1635 | const rhs_immediate_ok = switch (tag) { |
| 1636 | .add, |
| 1637 | .sub, |
| 1638 | .cmp_eq, |
| 1639 | => rhs == .immediate and rhs.immediate <= std.math.maxInt(u12), |
| 1640 | else => unreachable, |
| 1641 | }; |
| 1613 | 1642 | |
| 1614 | 1643 | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| 1644 | .add => .add, |
| 1615 | 1645 | .cmp_eq => .subcc, |
| 1616 | 1646 | else => unreachable, |
| 1617 | 1647 | }; |
| 1618 | 1648 | |
| 1619 | | return try self.binOpRegister(mir_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); |
| 1649 | if (rhs_immediate_ok) { |
| 1650 | return try self.binOpImmediate(mir_tag, maybe_inst, lhs, rhs, lhs_ty, false); |
| 1651 | } else if (lhs_immediate_ok) { |
| 1652 | // swap lhs and rhs |
| 1653 | return try self.binOpImmediate(mir_tag, maybe_inst, rhs, lhs, rhs_ty, true); |
| 1654 | } else { |
| 1655 | // TODO convert large immediates to register before adding |
| 1656 | return try self.binOpRegister(mir_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); |
| 1657 | } |
| 1620 | 1658 | } else { |
| 1621 | 1659 | return self.fail("TODO binary operations on int with bits > 64", .{}); |
| 1622 | 1660 | } |