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
signature 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 {
12641264fn minMax(
12651265 self: *Self,
12661266 tag: Air.Inst.Tag,
1267 maybe_inst: ?Air.Inst.Index,
1268 lhs: MCValue,
1269 rhs: MCValue,
1267 lhs_bind: ReadArg.Bind,
1268 rhs_bind: ReadArg.Bind,
12701269 lhs_ty: Type,
12711270 rhs_ty: Type,
1271 maybe_inst: ?Air.Inst.Index,
12721272) !MCValue {
12731273 switch (lhs_ty.zigTypeTag()) {
12741274 .Float => return self.fail("TODO ARM min/max on floats", .{}),
......@@ -1278,34 +1278,25 @@ fn minMax(
12781278 assert(lhs_ty.eql(rhs_ty, mod));
12791279 const int_info = lhs_ty.intInfo(self.target.*);
12801280 if (int_info.bits <= 32) {
1281 const lhs_is_register = lhs == .register;
1282 const rhs_is_register = rhs == .register;
1281 var lhs_reg: Register = undefined;
1282 var rhs_reg: Register = undefined;
1283 var dest_reg: Register = undefined;
12831284
1284 const lhs_reg = switch (lhs) {
1285 .register => |r| r,
1286 else => try self.copyToTmpRegister(lhs_ty, lhs),
1285 const read_args = [_]ReadArg{
1286 .{ .ty = lhs_ty, .bind = lhs_bind, .class = gp, .reg = &lhs_reg },
1287 .{ .ty = rhs_ty, .bind = rhs_bind, .class = gp, .reg = &rhs_reg },
12871288 };
1288 const lhs_reg_lock = self.register_manager.lockReg(lhs_reg);
1289 defer if (lhs_reg_lock) |reg| self.register_manager.unlockReg(reg);
1290
1291 const rhs_reg = switch (rhs) {
1292 .register => |r| r,
1293 else => try self.copyToTmpRegister(rhs_ty, rhs),
1289 const write_args = [_]WriteArg{
1290 .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &dest_reg },
12941291 };
1295 const rhs_reg_lock = self.register_manager.lockReg(rhs_reg);
1296 defer if (rhs_reg_lock) |reg| self.register_manager.unlockReg(reg);
1297
1298 const dest_reg = if (maybe_inst) |inst| blk: {
1299 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1300
1301 if (lhs_is_register and self.reuseOperand(inst, bin_op.lhs, 0, lhs)) {
1302 break :blk lhs_reg;
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);
1292 try self.allocRegs(
1293 &read_args,
1294 &write_args,
1295 if (maybe_inst) |inst| .{
1296 .corresponding_inst = inst,
1297 .operand_mapping = &.{ 0, 1 },
1298 } else null,
1299 );
13091300
13101301 // lhs == reg should have been checked by airMinMax
13111302 //
......@@ -1369,15 +1360,17 @@ fn minMax(
13691360fn airMinMax(self: *Self, inst: Air.Inst.Index) !void {
13701361 const tag = self.air.instructions.items(.tag)[inst];
13711362 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);
13741363 const lhs_ty = self.air.typeOf(bin_op.lhs);
13751364 const rhs_ty = self.air.typeOf(bin_op.rhs);
13761365
13771366 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);
13781371 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);
13811374 };
13821375 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
13831376}
......@@ -1538,21 +1531,21 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
15381531
15391532 break :result MCValue{ .stack_offset = stack_offset };
15401533 } else if (int_info.bits == 32) {
1541 const lhs = try self.resolveInst(extra.lhs);
1542 const rhs = try self.resolveInst(extra.rhs);
1534 const lhs_immediate = try lhs_bind.resolveToImmediate(self);
1535 const rhs_immediate = try rhs_bind.resolveToImmediate(self);
15431536
15441537 // Only say yes if the operation is
15451538 // commutative, i.e. we can swap both of the
15461539 // operands
15471540 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,
15491542 .sub_with_overflow => false,
15501543 else => unreachable,
15511544 };
15521545 const rhs_immediate_ok = switch (tag) {
15531546 .add_with_overflow,
15541547 .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,
15561549 else => unreachable,
15571550 };
15581551
......@@ -1567,12 +1560,12 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
15671560
15681561 const dest = blk: {
15691562 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);
15711564 } else if (lhs_immediate_ok) {
15721565 // 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);
15741567 } 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);
15761569 }
15771570 };
15781571
......@@ -1599,8 +1592,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
15991592 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
16001593 if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none });
16011594 const result: MCValue = result: {
1602 const lhs = try self.resolveInst(extra.lhs);
1603 const rhs = try self.resolveInst(extra.rhs);
1595 const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs };
1596 const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs };
16041597 const lhs_ty = self.air.typeOf(extra.lhs);
16051598 const rhs_ty = self.air.typeOf(extra.rhs);
16061599
......@@ -1625,7 +1618,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
16251618 .unsigned => .mul,
16261619 };
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);
16291622 const dest_reg = dest.register;
16301623 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);
16311624 defer self.register_manager.unlockReg(dest_reg_lock);
......@@ -1660,45 +1653,26 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
16601653 .unsigned => .umull,
16611654 };
16621655
1663 // TODO extract umull etc. to binOpTwoRegister
1664 // once MCValue.rr is implemented
1665 const lhs_is_register = lhs == .register;
1666 const rhs_is_register = rhs == .register;
1667
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);
1656 var lhs_reg: Register = undefined;
1657 var rhs_reg: Register = undefined;
1658 var rdhi: Register = undefined;
1659 var rdlo: Register = undefined;
1660 var truncated_reg: Register = undefined;
16981661
1699 const truncated_reg = try self.register_manager.allocReg(null, gp);
1700 const truncated_reg_lock = self.register_manager.lockRegAssumeUnused(truncated_reg);
1701 defer self.register_manager.unlockReg(truncated_reg_lock);
1662 const read_args = [_]ReadArg{
1663 .{ .ty = lhs_ty, .bind = lhs_bind, .class = gp, .reg = &lhs_reg },
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
17031677 _ = try self.addInst(.{
17041678 .tag = base_tag,
......@@ -2933,172 +2907,10 @@ fn allocRegs(
29332907 }
29342908}
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
29372912///
2938/// Calling this function signals an intention to generate a Mir
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
2913/// Returns the destination register
31022914fn binOpRegisterNew(
31032915 self: *Self,
31042916 mir_tag: Mir.Inst.Tag,
......@@ -3167,7 +2979,11 @@ fn binOpRegisterNew(
31672979 return MCValue{ .register = dest_reg };
31682980}
31692981
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
31712987fn binOpImmediateNew(
31722988 self: *Self,
31732989 mir_tag: Mir.Inst.Tag,
......@@ -3228,12 +3044,6 @@ fn binOpImmediateNew(
32283044 return MCValue{ .register = dest_reg };
32293045}
32303046
3231const BinOpMetadata = struct {
3232 inst: Air.Inst.Index,
3233 lhs: Air.Inst.Ref,
3234 rhs: Air.Inst.Ref,
3235};
3236
32373047fn addSub(
32383048 self: *Self,
32393049 tag: Air.Inst.Tag,