| ... | @@ -1040,6 +1040,7 @@ fn binOpRegister( | ... | @@ -1040,6 +1040,7 @@ fn binOpRegister( |
| 1040 | const mir_tag: Mir.Inst.Tag = switch (tag) { | 1040 | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| 1041 | .add, .ptr_add => .add_shifted_register, | 1041 | .add, .ptr_add => .add_shifted_register, |
| 1042 | .sub, .ptr_sub => .sub_shifted_register, | 1042 | .sub, .ptr_sub => .sub_shifted_register, |
| | 1043 | .mul => .mul, |
| 1043 | .xor => .eor_shifted_register, | 1044 | .xor => .eor_shifted_register, |
| 1044 | else => unreachable, | 1045 | else => unreachable, |
| 1045 | }; | 1046 | }; |
| ... | @@ -1055,6 +1056,11 @@ fn binOpRegister( | ... | @@ -1055,6 +1056,11 @@ fn binOpRegister( |
| 1055 | .imm6 = 0, | 1056 | .imm6 = 0, |
| 1056 | .shift = .lsl, | 1057 | .shift = .lsl, |
| 1057 | } }, | 1058 | } }, |
| | 1059 | .mul => .{ .rrr = .{ |
| | 1060 | .rd = dest_reg, |
| | 1061 | .rn = lhs_reg, |
| | 1062 | .rm = rhs_reg, |
| | 1063 | } }, |
| 1058 | .xor => .{ .rrr_imm6_logical_shift = .{ | 1064 | .xor => .{ .rrr_imm6_logical_shift = .{ |
| 1059 | .rd = dest_reg, | 1065 | .rd = dest_reg, |
| 1060 | .rn = lhs_reg, | 1066 | .rn = lhs_reg, |
| ... | @@ -1221,6 +1227,24 @@ fn binOp( | ... | @@ -1221,6 +1227,24 @@ fn binOp( |
| 1221 | else => unreachable, | 1227 | else => unreachable, |
| 1222 | } | 1228 | } |
| 1223 | }, | 1229 | }, |
| | 1230 | .mul => { |
| | 1231 | switch (lhs_ty.zigTypeTag()) { |
| | 1232 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| | 1233 | .Int => { |
| | 1234 | assert(lhs_ty.eql(rhs_ty)); |
| | 1235 | const int_info = lhs_ty.intInfo(self.target.*); |
| | 1236 | if (int_info.bits <= 64) { |
| | 1237 | // TODO add optimisations for multiplication |
| | 1238 | // with immediates, for example a * 2 can be |
| | 1239 | // lowered to a << 1 |
| | 1240 | return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); |
| | 1241 | } else { |
| | 1242 | return self.fail("TODO ARM binary operations on integers > u32/i32", .{}); |
| | 1243 | } |
| | 1244 | }, |
| | 1245 | else => unreachable, |
| | 1246 | } |
| | 1247 | }, |
| 1224 | // Bitwise operations on integers | 1248 | // Bitwise operations on integers |
| 1225 | .xor => { | 1249 | .xor => { |
| 1226 | switch (lhs_ty.zigTypeTag()) { | 1250 | switch (lhs_ty.zigTypeTag()) { |
| ... | @@ -1544,88 +1568,37 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1544,88 +1568,37 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1544 | }; | 1568 | }; |
| 1545 | self.register_manager.freezeRegs(&.{base_mcv.register}); | 1569 | self.register_manager.freezeRegs(&.{base_mcv.register}); |
| 1546 | | 1570 | |
| 1547 | // TODO implement optimized ldr for airSliceElemVal | 1571 | switch (elem_size) { |
| 1548 | const dst_mcv = try self.allocRegOrMem(inst, true); | 1572 | else => { |
| | 1573 | const dst_mcv = try self.allocRegOrMem(inst, true); |
| 1549 | | 1574 | |
| 1550 | const offset_mcv = try self.genMulConstant(bin_op.rhs, @intCast(u32, elem_size)); | 1575 | const offset_mcv = try self.binOp( |
| 1551 | assert(offset_mcv == .register); // result of multiplication should always be register | 1576 | .mul, |
| 1552 | self.register_manager.freezeRegs(&.{offset_mcv.register}); | 1577 | null, |
| | 1578 | index_mcv, |
| | 1579 | .{ .immediate = elem_size }, |
| | 1580 | Type.usize, |
| | 1581 | Type.usize, |
| | 1582 | ); |
| | 1583 | assert(offset_mcv == .register); // result of multiplication should always be register |
| | 1584 | self.register_manager.freezeRegs(&.{offset_mcv.register}); |
| 1553 | | 1585 | |
| 1554 | const addr_reg = try self.register_manager.allocReg(null); | 1586 | const addr_mcv = try self.binOp(.add, null, base_mcv, offset_mcv, Type.usize, Type.usize); |
| 1555 | self.register_manager.freezeRegs(&.{addr_reg}); | | |
| 1556 | defer self.register_manager.unfreezeRegs(&.{addr_reg}); | | |
| 1557 | | 1587 | |
| 1558 | _ = try self.addInst(.{ | 1588 | // At this point in time, neither the base register |
| 1559 | .tag = .add_shifted_register, | 1589 | // nor the offset register contains any valuable data |
| 1560 | .data = .{ .rrr_imm6_shift = .{ | 1590 | // anymore. |
| 1561 | .rd = addr_reg, | 1591 | self.register_manager.unfreezeRegs(&.{ base_mcv.register, offset_mcv.register }); |
| 1562 | .rn = base_mcv.register, | | |
| 1563 | .rm = offset_mcv.register, | | |
| 1564 | .imm6 = 0, | | |
| 1565 | .shift = .lsl, | | |
| 1566 | } }, | | |
| 1567 | }); | | |
| 1568 | | 1592 | |
| 1569 | // At this point in time, neither the base register | 1593 | try self.load(dst_mcv, addr_mcv, slice_ptr_field_type); |
| 1570 | // nor the offset register contains any valuable data | | |
| 1571 | // anymore. | | |
| 1572 | self.register_manager.unfreezeRegs(&.{ base_mcv.register, offset_mcv.register }); | | |
| 1573 | | 1594 | |
| 1574 | try self.load(dst_mcv, .{ .register = addr_reg }, slice_ptr_field_type); | 1595 | break :result dst_mcv; |
| 1575 | | 1596 | }, |
| 1576 | break :result dst_mcv; | 1597 | } |
| 1577 | }; | 1598 | }; |
| 1578 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1599 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1579 | } | 1600 | } |
| 1580 | | 1601 | |
| 1581 | fn genMulConstant(self: *Self, op: Air.Inst.Ref, imm: u32) !MCValue { | | |
| 1582 | const lhs = try self.resolveInst(op); | | |
| 1583 | const rhs = MCValue{ .immediate = imm }; | | |
| 1584 | | | |
| 1585 | const lhs_is_register = lhs == .register; | | |
| 1586 | | | |
| 1587 | if (lhs_is_register) self.register_manager.freezeRegs(&.{lhs.register}); | | |
| 1588 | defer if (lhs_is_register) self.register_manager.unfreezeRegs(&.{lhs.register}); | | |
| 1589 | | | |
| 1590 | // Destination must be a register | | |
| 1591 | // LHS must be a register | | |
| 1592 | // RHS must be a register | | |
| 1593 | var dst_mcv: MCValue = undefined; | | |
| 1594 | var lhs_mcv: MCValue = lhs; | | |
| 1595 | var rhs_mcv: MCValue = rhs; | | |
| 1596 | | | |
| 1597 | // Allocate registers for operands and/or destination | | |
| 1598 | // Allocate 1 or 2 registers | | |
| 1599 | if (lhs_is_register) { | | |
| 1600 | // Move RHS to register | | |
| 1601 | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(null) }; | | |
| 1602 | rhs_mcv = dst_mcv; | | |
| 1603 | } else { | | |
| 1604 | // Move LHS and RHS to register | | |
| 1605 | const regs = try self.register_manager.allocRegs(2, .{ null, null }); | | |
| 1606 | lhs_mcv = MCValue{ .register = regs[0] }; | | |
| 1607 | rhs_mcv = MCValue{ .register = regs[1] }; | | |
| 1608 | dst_mcv = lhs_mcv; | | |
| 1609 | } | | |
| 1610 | | | |
| 1611 | // Move the operands to the newly allocated registers | | |
| 1612 | if (!lhs_is_register) { | | |
| 1613 | try self.genSetReg(self.air.typeOf(op), lhs_mcv.register, lhs); | | |
| 1614 | } | | |
| 1615 | try self.genSetReg(Type.initTag(.usize), rhs_mcv.register, rhs); | | |
| 1616 | | | |
| 1617 | _ = try self.addInst(.{ | | |
| 1618 | .tag = .mul, | | |
| 1619 | .data = .{ .rrr = .{ | | |
| 1620 | .rd = dst_mcv.register, | | |
| 1621 | .rn = lhs_mcv.register, | | |
| 1622 | .rm = rhs_mcv.register, | | |
| 1623 | } }, | | |
| 1624 | }); | | |
| 1625 | | | |
| 1626 | return dst_mcv; | | |
| 1627 | } | | |
| 1628 | | | |
| 1629 | fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void { | 1602 | fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1630 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 1603 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1631 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; | 1604 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |