authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-08-26 19:27:20+02:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-09-09 19:17:17+02:00
log481bd4761ac9826336d13553e249989f509ba172
tree381f11455715b4939c72d28a9c3611c906f7efd3
parent95b8a5f157aa7552e3f125e56968b889e254497a
signaturelock-open Commit is signed but in an unrecognized format.

stage2 ARM: remove remaining uses of binOp{Register,Immediate}


1 files changed, 61 insertions(+), 251 deletions(-)

src/arch/arm/CodeGen.zig+61-251
...@@ -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 {
1264fn minMax(1264fn 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;
12831284
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,
12971294 &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,
13001297 .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);
13091300
1310 // lhs == reg should have been checked by airMinMax1301 // lhs == reg should have been checked by airMinMax
1311 //1302 //
...@@ -1369,15 +1360,17 @@ fn minMax(...@@ -1369,15 +1360,17 @@ fn minMax(
1369fn airMinMax(self: *Self, inst: Air.Inst.Index) !void {1360fn 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);
13761365
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;
13791372
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 {
15381531
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);
15431536
1544 // Only say yes if the operation is1537 // Only say yes if the operation is
1545 // commutative, i.e. we can swap both of the1538 // commutative, i.e. we can swap both of the
1546 // operands1539 // 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 };
15581551
...@@ -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 {
15671560
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 rhs1565 // 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 };
15781571
...@@ -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);
16061599
...@@ -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 };
16271620
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 };
16621655
1663 // TODO extract umull etc. to binOpTwoRegister1656 var lhs_reg: Register = undefined;
1664 // once MCValue.rr is implemented1657 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;
16671660 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);
16981661
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 );
17021676
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}
29352909
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 Mir2913/// 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.
2944fn 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.
3032fn 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
3102fn binOpRegisterNew(2914fn 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}
31692981
3170/// TODO2982/// 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
3171fn binOpImmediateNew(2987fn 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}
32303046
3231const BinOpMetadata = struct {
3232 inst: Air.Inst.Index,
3233 lhs: Air.Inst.Ref,
3234 rhs: Air.Inst.Ref,
3235};
3236
3237fn addSub(3047fn addSub(
3238 self: *Self,3048 self: *Self,
3239 tag: Air.Inst.Tag,3049 tag: Air.Inst.Tag,