| ... | @@ -1264,11 +1264,11 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1264,11 +1264,11 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1264 | fn minMax( | 1264 | fn minMax( |
| 1265 | self: *Self, | 1265 | self: *Self, |
| 1266 | tag: Air.Inst.Tag, | 1266 | tag: Air.Inst.Tag, |
| 1267 | maybe_inst: ?Air.Inst.Index, | 1267 | lhs_bind: ReadArg.Bind, |
| 1268 | lhs: MCValue, | 1268 | rhs_bind: ReadArg.Bind, |
| 1269 | rhs: MCValue, | | |
| 1270 | lhs_ty: Type, | 1269 | lhs_ty: Type, |
| 1271 | rhs_ty: Type, | 1270 | rhs_ty: Type, |
| | 1271 | maybe_inst: ?Air.Inst.Index, |
| 1272 | ) !MCValue { | 1272 | ) !MCValue { |
| 1273 | switch (lhs_ty.zigTypeTag()) { | 1273 | switch (lhs_ty.zigTypeTag()) { |
| 1274 | .Float => return self.fail("TODO ARM min/max on floats", .{}), | 1274 | .Float => return self.fail("TODO ARM min/max on floats", .{}), |
| ... | @@ -1278,34 +1278,25 @@ fn minMax( | ... | @@ -1278,34 +1278,25 @@ fn minMax( |
| 1278 | assert(lhs_ty.eql(rhs_ty, mod)); | 1278 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 1279 | const int_info = lhs_ty.intInfo(self.target.*); | 1279 | const int_info = lhs_ty.intInfo(self.target.*); |
| 1280 | if (int_info.bits <= 32) { | 1280 | if (int_info.bits <= 32) { |
| 1281 | const lhs_is_register = lhs == .register; | 1281 | var lhs_reg: Register = undefined; |
| 1282 | const rhs_is_register = rhs == .register; | 1282 | var rhs_reg: Register = undefined; |
| | 1283 | var dest_reg: Register = undefined; |
| 1283 | | 1284 | |
| 1284 | const lhs_reg = switch (lhs) { | 1285 | const read_args = [_]ReadArg{ |
| 1285 | .register => |r| r, | 1286 | .{ .ty = lhs_ty, .bind = lhs_bind, .class = gp, .reg = &lhs_reg }, |
| 1286 | else => try self.copyToTmpRegister(lhs_ty, lhs), | 1287 | .{ .ty = rhs_ty, .bind = rhs_bind, .class = gp, .reg = &rhs_reg }, |
| 1287 | }; | 1288 | }; |
| 1288 | const lhs_reg_lock = self.register_manager.lockReg(lhs_reg); | 1289 | const write_args = [_]WriteArg{ |
| 1289 | defer if (lhs_reg_lock) |reg| self.register_manager.unlockReg(reg); | 1290 | .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &dest_reg }, |
| 1290 | | | |
| 1291 | const rhs_reg = switch (rhs) { | | |
| 1292 | .register => |r| r, | | |
| 1293 | else => try self.copyToTmpRegister(rhs_ty, rhs), | | |
| 1294 | }; | 1291 | }; |
| 1295 | const rhs_reg_lock = self.register_manager.lockReg(rhs_reg); | 1292 | try self.allocRegs( |
| 1296 | defer if (rhs_reg_lock) |reg| self.register_manager.unlockReg(reg); | 1293 | &read_args, |
| 1297 | | 1294 | &write_args, |
| 1298 | const dest_reg = if (maybe_inst) |inst| blk: { | 1295 | if (maybe_inst) |inst| .{ |
| 1299 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1296 | .corresponding_inst = inst, |
| 1300 | | 1297 | .operand_mapping = &.{ 0, 1 }, |
| 1301 | if (lhs_is_register and self.reuseOperand(inst, bin_op.lhs, 0, lhs)) { | 1298 | } else null, |
| 1302 | break :blk lhs_reg; | 1299 | ); |
| 1303 | } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) { | | |
| 1304 | break :blk rhs_reg; | | |
| 1305 | } else { | | |
| 1306 | break :blk try self.register_manager.allocReg(inst, gp); | | |
| 1307 | } | | |
| 1308 | } else try self.register_manager.allocReg(null, gp); | | |
| 1309 | | 1300 | |
| 1310 | // lhs == reg should have been checked by airMinMax | 1301 | // lhs == reg should have been checked by airMinMax |
| 1311 | // | 1302 | // |
| ... | @@ -1369,15 +1360,17 @@ fn minMax( | ... | @@ -1369,15 +1360,17 @@ fn minMax( |
| 1369 | fn airMinMax(self: *Self, inst: Air.Inst.Index) !void { | 1360 | fn airMinMax(self: *Self, inst: Air.Inst.Index) !void { |
| 1370 | const tag = self.air.instructions.items(.tag)[inst]; | 1361 | const tag = self.air.instructions.items(.tag)[inst]; |
| 1371 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1362 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1372 | const lhs = try self.resolveInst(bin_op.lhs); | | |
| 1373 | const rhs = try self.resolveInst(bin_op.rhs); | | |
| 1374 | const lhs_ty = self.air.typeOf(bin_op.lhs); | 1363 | const lhs_ty = self.air.typeOf(bin_op.lhs); |
| 1375 | const rhs_ty = self.air.typeOf(bin_op.rhs); | 1364 | const rhs_ty = self.air.typeOf(bin_op.rhs); |
| 1376 | | 1365 | |
| 1377 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 1366 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| | 1367 | const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs }; |
| | 1368 | const rhs_bind: ReadArg.Bind = .{ .inst = bin_op.rhs }; |
| | 1369 | |
| | 1370 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1378 | if (bin_op.lhs == bin_op.rhs) break :result lhs; | 1371 | if (bin_op.lhs == bin_op.rhs) break :result lhs; |
| 1379 | | 1372 | |
| 1380 | break :result try self.minMax(tag, inst, lhs, rhs, lhs_ty, rhs_ty); | 1373 | break :result try self.minMax(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst); |
| 1381 | }; | 1374 | }; |
| 1382 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1375 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1383 | } | 1376 | } |
| ... | @@ -1538,21 +1531,21 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1538,21 +1531,21 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1538 | | 1531 | |
| 1539 | break :result MCValue{ .stack_offset = stack_offset }; | 1532 | break :result MCValue{ .stack_offset = stack_offset }; |
| 1540 | } else if (int_info.bits == 32) { | 1533 | } else if (int_info.bits == 32) { |
| 1541 | const lhs = try self.resolveInst(extra.lhs); | 1534 | const lhs_immediate = try lhs_bind.resolveToImmediate(self); |
| 1542 | const rhs = try self.resolveInst(extra.rhs); | 1535 | const rhs_immediate = try rhs_bind.resolveToImmediate(self); |
| 1543 | | 1536 | |
| 1544 | // Only say yes if the operation is | 1537 | // Only say yes if the operation is |
| 1545 | // commutative, i.e. we can swap both of the | 1538 | // commutative, i.e. we can swap both of the |
| 1546 | // operands | 1539 | // operands |
| 1547 | const lhs_immediate_ok = switch (tag) { | 1540 | const lhs_immediate_ok = switch (tag) { |
| 1548 | .add_with_overflow => lhs == .immediate and Instruction.Operand.fromU32(lhs.immediate) != null, | 1541 | .add_with_overflow => if (lhs_immediate) |imm| Instruction.Operand.fromU32(imm) != null else false, |
| 1549 | .sub_with_overflow => false, | 1542 | .sub_with_overflow => false, |
| 1550 | else => unreachable, | 1543 | else => unreachable, |
| 1551 | }; | 1544 | }; |
| 1552 | const rhs_immediate_ok = switch (tag) { | 1545 | const rhs_immediate_ok = switch (tag) { |
| 1553 | .add_with_overflow, | 1546 | .add_with_overflow, |
| 1554 | .sub_with_overflow, | 1547 | .sub_with_overflow, |
| 1555 | => rhs == .immediate and Instruction.Operand.fromU32(rhs.immediate) != null, | 1548 | => if (rhs_immediate) |imm| Instruction.Operand.fromU32(imm) != null else false, |
| 1556 | else => unreachable, | 1549 | else => unreachable, |
| 1557 | }; | 1550 | }; |
| 1558 | | 1551 | |
| ... | @@ -1567,12 +1560,12 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1567,12 +1560,12 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1567 | | 1560 | |
| 1568 | const dest = blk: { | 1561 | const dest = blk: { |
| 1569 | if (rhs_immediate_ok) { | 1562 | if (rhs_immediate_ok) { |
| 1570 | break :blk try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, null); | 1563 | break :blk try self.binOpImmediateNew(mir_tag, lhs_bind, rhs_immediate.?, lhs_ty, false, null); |
| 1571 | } else if (lhs_immediate_ok) { | 1564 | } else if (lhs_immediate_ok) { |
| 1572 | // swap lhs and rhs | 1565 | // swap lhs and rhs |
| 1573 | break :blk try self.binOpImmediate(mir_tag, rhs, lhs, rhs_ty, true, null); | 1566 | break :blk try self.binOpImmediateNew(mir_tag, rhs_bind, lhs_immediate.?, rhs_ty, true, null); |
| 1574 | } else { | 1567 | } else { |
| 1575 | break :blk try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, null); | 1568 | break :blk try self.binOpRegisterNew(mir_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, null); |
| 1576 | } | 1569 | } |
| 1577 | }; | 1570 | }; |
| 1578 | | 1571 | |
| ... | @@ -1599,8 +1592,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1599,8 +1592,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1599 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; | 1592 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1600 | if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none }); | 1593 | if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none }); |
| 1601 | const result: MCValue = result: { | 1594 | const result: MCValue = result: { |
| 1602 | const lhs = try self.resolveInst(extra.lhs); | 1595 | const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs }; |
| 1603 | const rhs = try self.resolveInst(extra.rhs); | 1596 | const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs }; |
| 1604 | const lhs_ty = self.air.typeOf(extra.lhs); | 1597 | const lhs_ty = self.air.typeOf(extra.lhs); |
| 1605 | const rhs_ty = self.air.typeOf(extra.rhs); | 1598 | const rhs_ty = self.air.typeOf(extra.rhs); |
| 1606 | | 1599 | |
| ... | @@ -1625,7 +1618,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1625,7 +1618,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1625 | .unsigned => .mul, | 1618 | .unsigned => .mul, |
| 1626 | }; | 1619 | }; |
| 1627 | | 1620 | |
| 1628 | const dest = try self.binOpRegister(base_tag, lhs, rhs, lhs_ty, rhs_ty, null); | 1621 | const dest = try self.binOpRegisterNew(base_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, null); |
| 1629 | const dest_reg = dest.register; | 1622 | const dest_reg = dest.register; |
| 1630 | const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg); | 1623 | const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg); |
| 1631 | defer self.register_manager.unlockReg(dest_reg_lock); | 1624 | defer self.register_manager.unlockReg(dest_reg_lock); |
| ... | @@ -1660,45 +1653,26 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1660,45 +1653,26 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1660 | .unsigned => .umull, | 1653 | .unsigned => .umull, |
| 1661 | }; | 1654 | }; |
| 1662 | | 1655 | |
| 1663 | // TODO extract umull etc. to binOpTwoRegister | 1656 | var lhs_reg: Register = undefined; |
| 1664 | // once MCValue.rr is implemented | 1657 | var rhs_reg: Register = undefined; |
| 1665 | const lhs_is_register = lhs == .register; | 1658 | var rdhi: Register = undefined; |
| 1666 | const rhs_is_register = rhs == .register; | 1659 | var rdlo: Register = undefined; |
| 1667 | | 1660 | var truncated_reg: Register = undefined; |
| 1668 | const lhs_lock: ?RegisterLock = if (lhs_is_register) | | |
| 1669 | self.register_manager.lockReg(lhs.register) | | |
| 1670 | else | | |
| 1671 | null; | | |
| 1672 | defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg); | | |
| 1673 | | | |
| 1674 | const lhs_reg = if (lhs_is_register) | | |
| 1675 | lhs.register | | |
| 1676 | else | | |
| 1677 | try self.register_manager.allocReg(null, gp); | | |
| 1678 | const new_lhs_lock = self.register_manager.lockReg(lhs_reg); | | |
| 1679 | defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg); | | |
| 1680 | | | |
| 1681 | const rhs_reg = if (rhs_is_register) | | |
| 1682 | rhs.register | | |
| 1683 | else | | |
| 1684 | try self.register_manager.allocReg(null, gp); | | |
| 1685 | const new_rhs_lock = self.register_manager.lockReg(rhs_reg); | | |
| 1686 | defer if (new_rhs_lock) |reg| self.register_manager.unlockReg(reg); | | |
| 1687 | | | |
| 1688 | const dest_regs = try self.register_manager.allocRegs(2, .{ null, null }, gp); | | |
| 1689 | const dest_regs_locks = self.register_manager.lockRegsAssumeUnused(2, dest_regs); | | |
| 1690 | defer for (dest_regs_locks) |reg| { | | |
| 1691 | self.register_manager.unlockReg(reg); | | |
| 1692 | }; | | |
| 1693 | const rdlo = dest_regs[0]; | | |
| 1694 | const rdhi = dest_regs[1]; | | |
| 1695 | | | |
| 1696 | if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs); | | |
| 1697 | if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs); | | |
| 1698 | | 1661 | |
| 1699 | const truncated_reg = try self.register_manager.allocReg(null, gp); | 1662 | const read_args = [_]ReadArg{ |
| 1700 | const truncated_reg_lock = self.register_manager.lockRegAssumeUnused(truncated_reg); | 1663 | .{ .ty = lhs_ty, .bind = lhs_bind, .class = gp, .reg = &lhs_reg }, |
| 1701 | defer self.register_manager.unlockReg(truncated_reg_lock); | 1664 | .{ .ty = rhs_ty, .bind = rhs_bind, .class = gp, .reg = &rhs_reg }, |
| | 1665 | }; |
| | 1666 | const write_args = [_]WriteArg{ |
| | 1667 | .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &rdhi }, |
| | 1668 | .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &rdlo }, |
| | 1669 | .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &truncated_reg }, |
| | 1670 | }; |
| | 1671 | try self.allocRegs( |
| | 1672 | &read_args, |
| | 1673 | &write_args, |
| | 1674 | null, |
| | 1675 | ); |
| 1702 | | 1676 | |
| 1703 | _ = try self.addInst(.{ | 1677 | _ = try self.addInst(.{ |
| 1704 | .tag = base_tag, | 1678 | .tag = base_tag, |
| ... | @@ -2933,172 +2907,10 @@ fn allocRegs( | ... | @@ -2933,172 +2907,10 @@ fn allocRegs( |
| 2933 | } | 2907 | } |
| 2934 | } | 2908 | } |
| 2935 | | 2909 | |
| 2936 | /// Don't call this function directly. Use binOp instead. | 2910 | /// Wrapper around allocRegs and addInst tailored for specific Mir |
| | 2911 | /// instructions which are binary operations acting on two registers |
| 2937 | /// | 2912 | /// |
| 2938 | /// Calling this function signals an intention to generate a Mir | 2913 | /// Returns the destination register |
| 2939 | /// instruction of the form | | |
| 2940 | /// | | |
| 2941 | /// op dest, lhs, rhs | | |
| 2942 | /// | | |
| 2943 | /// Asserts that generating an instruction of that form is possible. | | |
| 2944 | fn binOpRegister( | | |
| 2945 | self: *Self, | | |
| 2946 | mir_tag: Mir.Inst.Tag, | | |
| 2947 | lhs: MCValue, | | |
| 2948 | rhs: MCValue, | | |
| 2949 | lhs_ty: Type, | | |
| 2950 | rhs_ty: Type, | | |
| 2951 | metadata: ?BinOpMetadata, | | |
| 2952 | ) !MCValue { | | |
| 2953 | var lhs_reg: Register = undefined; | | |
| 2954 | var rhs_reg: Register = undefined; | | |
| 2955 | var dest_reg: Register = undefined; | | |
| 2956 | | | |
| 2957 | const lhs_bind = if (metadata) |md| | | |
| 2958 | ReadArg.Bind{ .inst = md.lhs } | | |
| 2959 | else | | |
| 2960 | ReadArg.Bind{ .mcv = lhs }; | | |
| 2961 | const rhs_bind = if (metadata) |md| | | |
| 2962 | ReadArg.Bind{ .inst = md.rhs } | | |
| 2963 | else | | |
| 2964 | ReadArg.Bind{ .mcv = rhs }; | | |
| 2965 | const read_args = [_]ReadArg{ | | |
| 2966 | .{ .ty = lhs_ty, .bind = lhs_bind, .class = gp, .reg = &lhs_reg }, | | |
| 2967 | .{ .ty = rhs_ty, .bind = rhs_bind, .class = gp, .reg = &rhs_reg }, | | |
| 2968 | }; | | |
| 2969 | const write_args = [_]WriteArg{ | | |
| 2970 | .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &dest_reg }, | | |
| 2971 | }; | | |
| 2972 | try self.allocRegs( | | |
| 2973 | &read_args, | | |
| 2974 | &write_args, | | |
| 2975 | if (metadata) |md| .{ | | |
| 2976 | .corresponding_inst = md.inst, | | |
| 2977 | .operand_mapping = &.{ 0, 1 }, | | |
| 2978 | } else null, | | |
| 2979 | ); | | |
| 2980 | | | |
| 2981 | const mir_data: Mir.Inst.Data = switch (mir_tag) { | | |
| 2982 | .add, | | |
| 2983 | .adds, | | |
| 2984 | .sub, | | |
| 2985 | .subs, | | |
| 2986 | .@"and", | | |
| 2987 | .orr, | | |
| 2988 | .eor, | | |
| 2989 | => .{ .rr_op = .{ | | |
| 2990 | .rd = dest_reg, | | |
| 2991 | .rn = lhs_reg, | | |
| 2992 | .op = Instruction.Operand.reg(rhs_reg, Instruction.Operand.Shift.none), | | |
| 2993 | } }, | | |
| 2994 | .lsl, | | |
| 2995 | .asr, | | |
| 2996 | .lsr, | | |
| 2997 | => .{ .rr_shift = .{ | | |
| 2998 | .rd = dest_reg, | | |
| 2999 | .rm = lhs_reg, | | |
| 3000 | .shift_amount = Instruction.ShiftAmount.reg(rhs_reg), | | |
| 3001 | } }, | | |
| 3002 | .mul, | | |
| 3003 | .smulbb, | | |
| 3004 | => .{ .rrr = .{ | | |
| 3005 | .rd = dest_reg, | | |
| 3006 | .rn = lhs_reg, | | |
| 3007 | .rm = rhs_reg, | | |
| 3008 | } }, | | |
| 3009 | else => unreachable, | | |
| 3010 | }; | | |
| 3011 | | | |
| 3012 | _ = try self.addInst(.{ | | |
| 3013 | .tag = mir_tag, | | |
| 3014 | .data = mir_data, | | |
| 3015 | }); | | |
| 3016 | | | |
| 3017 | return MCValue{ .register = dest_reg }; | | |
| 3018 | } | | |
| 3019 | | | |
| 3020 | /// Don't call this function directly. Use binOp instead. | | |
| 3021 | /// | | |
| 3022 | /// Calling this function signals an intention to generate a Mir | | |
| 3023 | /// instruction of the form | | |
| 3024 | /// | | |
| 3025 | /// op dest, lhs, #rhs_imm | | |
| 3026 | /// | | |
| 3027 | /// Set lhs_and_rhs_swapped to true iff inst.bin_op.lhs corresponds to | | |
| 3028 | /// rhs and vice versa. This parameter is only used when maybe_inst != | | |
| 3029 | /// null. | | |
| 3030 | /// | | |
| 3031 | /// Asserts that generating an instruction of that form is possible. | | |
| 3032 | fn binOpImmediate( | | |
| 3033 | self: *Self, | | |
| 3034 | mir_tag: Mir.Inst.Tag, | | |
| 3035 | lhs: MCValue, | | |
| 3036 | rhs: MCValue, | | |
| 3037 | lhs_ty: Type, | | |
| 3038 | lhs_and_rhs_swapped: bool, | | |
| 3039 | metadata: ?BinOpMetadata, | | |
| 3040 | ) !MCValue { | | |
| 3041 | var lhs_reg: Register = undefined; | | |
| 3042 | var dest_reg: Register = undefined; | | |
| 3043 | | | |
| 3044 | const lhs_bind = blk: { | | |
| 3045 | if (metadata) |md| { | | |
| 3046 | const inst = if (lhs_and_rhs_swapped) md.rhs else md.lhs; | | |
| 3047 | break :blk ReadArg.Bind{ .inst = inst }; | | |
| 3048 | } else { | | |
| 3049 | break :blk ReadArg.Bind{ .mcv = lhs }; | | |
| 3050 | } | | |
| 3051 | }; | | |
| 3052 | | | |
| 3053 | const read_args = [_]ReadArg{ | | |
| 3054 | .{ .ty = lhs_ty, .bind = lhs_bind, .class = gp, .reg = &lhs_reg }, | | |
| 3055 | }; | | |
| 3056 | const write_args = [_]WriteArg{ | | |
| 3057 | .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &dest_reg }, | | |
| 3058 | }; | | |
| 3059 | const operand_mapping: []const Liveness.OperandInt = if (lhs_and_rhs_swapped) &.{1} else &.{0}; | | |
| 3060 | try self.allocRegs( | | |
| 3061 | &read_args, | | |
| 3062 | &write_args, | | |
| 3063 | if (metadata) |md| .{ | | |
| 3064 | .corresponding_inst = md.inst, | | |
| 3065 | .operand_mapping = operand_mapping, | | |
| 3066 | } else null, | | |
| 3067 | ); | | |
| 3068 | | | |
| 3069 | const mir_data: Mir.Inst.Data = switch (mir_tag) { | | |
| 3070 | .add, | | |
| 3071 | .adds, | | |
| 3072 | .sub, | | |
| 3073 | .subs, | | |
| 3074 | .@"and", | | |
| 3075 | .orr, | | |
| 3076 | .eor, | | |
| 3077 | => .{ .rr_op = .{ | | |
| 3078 | .rd = dest_reg, | | |
| 3079 | .rn = lhs_reg, | | |
| 3080 | .op = Instruction.Operand.fromU32(rhs.immediate).?, | | |
| 3081 | } }, | | |
| 3082 | .lsl, | | |
| 3083 | .asr, | | |
| 3084 | .lsr, | | |
| 3085 | => .{ .rr_shift = .{ | | |
| 3086 | .rd = dest_reg, | | |
| 3087 | .rm = lhs_reg, | | |
| 3088 | .shift_amount = Instruction.ShiftAmount.imm(@intCast(u5, rhs.immediate)), | | |
| 3089 | } }, | | |
| 3090 | else => unreachable, | | |
| 3091 | }; | | |
| 3092 | | | |
| 3093 | _ = try self.addInst(.{ | | |
| 3094 | .tag = mir_tag, | | |
| 3095 | .data = mir_data, | | |
| 3096 | }); | | |
| 3097 | | | |
| 3098 | return MCValue{ .register = dest_reg }; | | |
| 3099 | } | | |
| 3100 | | | |
| 3101 | /// TODO | | |
| 3102 | fn binOpRegisterNew( | 2914 | fn binOpRegisterNew( |
| 3103 | self: *Self, | 2915 | self: *Self, |
| 3104 | mir_tag: Mir.Inst.Tag, | 2916 | mir_tag: Mir.Inst.Tag, |
| ... | @@ -3167,7 +2979,11 @@ fn binOpRegisterNew( | ... | @@ -3167,7 +2979,11 @@ fn binOpRegisterNew( |
| 3167 | return MCValue{ .register = dest_reg }; | 2979 | return MCValue{ .register = dest_reg }; |
| 3168 | } | 2980 | } |
| 3169 | | 2981 | |
| 3170 | /// TODO | 2982 | /// Wrapper around allocRegs and addInst tailored for specific Mir |
| | 2983 | /// instructions which are binary operations acting on a register and |
| | 2984 | /// an immediate |
| | 2985 | /// |
| | 2986 | /// Returns the destination register |
| 3171 | fn binOpImmediateNew( | 2987 | fn binOpImmediateNew( |
| 3172 | self: *Self, | 2988 | self: *Self, |
| 3173 | mir_tag: Mir.Inst.Tag, | 2989 | mir_tag: Mir.Inst.Tag, |
| ... | @@ -3228,12 +3044,6 @@ fn binOpImmediateNew( | ... | @@ -3228,12 +3044,6 @@ fn binOpImmediateNew( |
| 3228 | return MCValue{ .register = dest_reg }; | 3044 | return MCValue{ .register = dest_reg }; |
| 3229 | } | 3045 | } |
| 3230 | | 3046 | |
| 3231 | const BinOpMetadata = struct { | | |
| 3232 | inst: Air.Inst.Index, | | |
| 3233 | lhs: Air.Inst.Ref, | | |
| 3234 | rhs: Air.Inst.Ref, | | |
| 3235 | }; | | |
| 3236 | | | |
| 3237 | fn addSub( | 3047 | fn addSub( |
| 3238 | self: *Self, | 3048 | self: *Self, |
| 3239 | tag: Air.Inst.Tag, | 3049 | tag: Air.Inst.Tag, |