stage2 ARM: change binOp lowering mechanism to use Mir tags

The Air -> Mir correspondence is not 1:1, so this better represents
what Mir insruction we actually want to generate.
This commit is contained in:
joachimschmidt557 2022-03-27 15:06:37 +02:00
parent 8b5d5f44e2
commit e2e69803dc
No known key found for this signature in database
GPG Key ID: E0B575BE2884ACC5

View File

@ -1196,7 +1196,7 @@ fn minMax(
// register. // register.
assert(lhs_reg != rhs_reg); // see note above assert(lhs_reg != rhs_reg); // see note above
_ = try self.binOpRegister(.cmp_eq, null, .{ .register = lhs_reg }, .{ .register = rhs_reg }, lhs_ty, rhs_ty); _ = try self.binOpRegister(.cmp, null, .{ .register = lhs_reg }, .{ .register = rhs_reg }, lhs_ty, rhs_ty);
const cond_choose_lhs: Condition = switch (tag) { const cond_choose_lhs: Condition = switch (tag) {
.max => switch (int_info.signedness) { .max => switch (int_info.signedness) {
@ -2067,7 +2067,7 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {
/// Asserts that generating an instruction of that form is possible. /// Asserts that generating an instruction of that form is possible.
fn binOpRegister( fn binOpRegister(
self: *Self, self: *Self,
tag: Air.Inst.Tag, mir_tag: Mir.Inst.Tag,
maybe_inst: ?Air.Inst.Index, maybe_inst: ?Air.Inst.Index,
lhs: MCValue, lhs: MCValue,
rhs: MCValue, rhs: MCValue,
@ -2112,8 +2112,8 @@ fn binOpRegister(
}; };
defer self.register_manager.unfreezeRegs(&.{rhs_reg}); defer self.register_manager.unfreezeRegs(&.{rhs_reg});
const dest_reg = switch (tag) { const dest_reg = switch (mir_tag) {
.cmp_eq => .r0, // cmp has no destination regardless .cmp => .r0, // cmp has no destination regardless
else => if (maybe_inst) |inst| blk: { else => if (maybe_inst) |inst| blk: {
const bin_op = self.air.instructions.items(.data)[inst].bin_op; const bin_op = self.air.instructions.items(.data)[inst].bin_op;
@ -2130,41 +2130,21 @@ fn binOpRegister(
if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs); if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);
if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs); if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs);
const mir_tag: Mir.Inst.Tag = switch (tag) { const mir_data: Mir.Inst.Data = switch (mir_tag) {
.add => .add,
.sub => .sub,
.cmp_eq => .cmp,
.mul => .mul,
.bit_and,
.bool_and,
=> .@"and",
.bit_or,
.bool_or,
=> .orr,
.shl_exact => .lsl,
.shr_exact => switch (lhs_ty.intInfo(self.target.*).signedness) {
.signed => Mir.Inst.Tag.asr,
.unsigned => Mir.Inst.Tag.lsr,
},
.xor => .eor,
else => unreachable,
};
const mir_data: Mir.Inst.Data = switch (tag) {
.add, .add,
.sub, .sub,
.cmp_eq, .cmp,
.bit_and, .@"and",
.bool_and, .orr,
.bit_or, .eor,
.bool_or,
.xor,
=> .{ .rr_op = .{ => .{ .rr_op = .{
.rd = dest_reg, .rd = dest_reg,
.rn = lhs_reg, .rn = lhs_reg,
.op = Instruction.Operand.reg(rhs_reg, Instruction.Operand.Shift.none), .op = Instruction.Operand.reg(rhs_reg, Instruction.Operand.Shift.none),
} }, } },
.shl_exact, .lsl,
.shr_exact, .asr,
.lsr,
=> .{ .rr_shift = .{ => .{ .rr_shift = .{
.rd = dest_reg, .rd = dest_reg,
.rm = lhs_reg, .rm = lhs_reg,
@ -2200,7 +2180,7 @@ fn binOpRegister(
/// Asserts that generating an instruction of that form is possible. /// Asserts that generating an instruction of that form is possible.
fn binOpImmediate( fn binOpImmediate(
self: *Self, self: *Self,
tag: Air.Inst.Tag, mir_tag: Mir.Inst.Tag,
maybe_inst: ?Air.Inst.Index, maybe_inst: ?Air.Inst.Index,
lhs: MCValue, lhs: MCValue,
rhs: MCValue, rhs: MCValue,
@ -2230,8 +2210,8 @@ fn binOpImmediate(
}; };
defer self.register_manager.unfreezeRegs(&.{lhs_reg}); defer self.register_manager.unfreezeRegs(&.{lhs_reg});
const dest_reg = switch (tag) { const dest_reg = switch (mir_tag) {
.cmp_eq => .r0, // cmp has no destination reg .cmp => .r0, // cmp has no destination reg
else => if (maybe_inst) |inst| blk: { else => if (maybe_inst) |inst| blk: {
const bin_op = self.air.instructions.items(.data)[inst].bin_op; const bin_op = self.air.instructions.items(.data)[inst].bin_op;
@ -2250,40 +2230,21 @@ fn binOpImmediate(
if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs); if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);
const mir_tag: Mir.Inst.Tag = switch (tag) { const mir_data: Mir.Inst.Data = switch (mir_tag) {
.add => .add,
.sub => .sub,
.cmp_eq => .cmp,
.bit_and,
.bool_and,
=> .@"and",
.bit_or,
.bool_or,
=> .orr,
.shl_exact => .lsl,
.shr_exact => switch (lhs_ty.intInfo(self.target.*).signedness) {
.signed => Mir.Inst.Tag.asr,
.unsigned => Mir.Inst.Tag.lsr,
},
.xor => .eor,
else => unreachable,
};
const mir_data: Mir.Inst.Data = switch (tag) {
.add, .add,
.sub, .sub,
.cmp_eq, .cmp,
.bit_and, .@"and",
.bool_and, .orr,
.bit_or, .eor,
.bool_or,
.xor,
=> .{ .rr_op = .{ => .{ .rr_op = .{
.rd = dest_reg, .rd = dest_reg,
.rn = lhs_reg, .rn = lhs_reg,
.op = Instruction.Operand.fromU32(rhs.immediate).?, .op = Instruction.Operand.fromU32(rhs.immediate).?,
} }, } },
.shl_exact, .lsl,
.shr_exact, .asr,
.lsr,
=> .{ .rr_shift = .{ => .{ .rr_shift = .{
.rd = dest_reg, .rd = dest_reg,
.rm = lhs_reg, .rm = lhs_reg,
@ -2352,13 +2313,20 @@ fn binOp(
else => unreachable, else => unreachable,
}; };
const mir_tag: Mir.Inst.Tag = switch (tag) {
.add => .add,
.sub => .sub,
.cmp_eq => .cmp,
else => unreachable,
};
if (rhs_immediate_ok) { if (rhs_immediate_ok) {
return try self.binOpImmediate(tag, maybe_inst, lhs, rhs, lhs_ty, false); return try self.binOpImmediate(mir_tag, maybe_inst, lhs, rhs, lhs_ty, false);
} else if (lhs_immediate_ok) { } else if (lhs_immediate_ok) {
// swap lhs and rhs // swap lhs and rhs
return try self.binOpImmediate(tag, maybe_inst, rhs, lhs, rhs_ty, true); return try self.binOpImmediate(mir_tag, maybe_inst, rhs, lhs, rhs_ty, true);
} else { } else {
return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); return try self.binOpRegister(mir_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
} }
} else { } else {
return self.fail("TODO ARM binary operations on integers > u32/i32", .{}); return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
@ -2378,7 +2346,7 @@ fn binOp(
// TODO add optimisations for multiplication // TODO add optimisations for multiplication
// with immediates, for example a * 2 can be // with immediates, for example a * 2 can be
// lowered to a << 1 // lowered to a << 1
return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); return try self.binOpRegister(.mul, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
} else { } else {
return self.fail("TODO ARM binary operations on integers > u32/i32", .{}); return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
} }
@ -2432,13 +2400,20 @@ fn binOp(
const lhs_immediate_ok = lhs == .immediate and Instruction.Operand.fromU32(lhs.immediate) != null; const lhs_immediate_ok = lhs == .immediate and Instruction.Operand.fromU32(lhs.immediate) != null;
const rhs_immediate_ok = rhs == .immediate and Instruction.Operand.fromU32(rhs.immediate) != null; const rhs_immediate_ok = rhs == .immediate and Instruction.Operand.fromU32(rhs.immediate) != null;
const mir_tag: Mir.Inst.Tag = switch (tag) {
.bit_and => .@"and",
.bit_or => .orr,
.xor => .eor,
else => unreachable,
};
if (rhs_immediate_ok) { if (rhs_immediate_ok) {
return try self.binOpImmediate(tag, maybe_inst, lhs, rhs, lhs_ty, false); return try self.binOpImmediate(mir_tag, maybe_inst, lhs, rhs, lhs_ty, false);
} else if (lhs_immediate_ok) { } else if (lhs_immediate_ok) {
// swap lhs and rhs // swap lhs and rhs
return try self.binOpImmediate(tag, maybe_inst, rhs, lhs, rhs_ty, true); return try self.binOpImmediate(mir_tag, maybe_inst, rhs, lhs, rhs_ty, true);
} else { } else {
return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); return try self.binOpRegister(mir_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
} }
} else { } else {
return self.fail("TODO ARM binary operations on integers > u32/i32", .{}); return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
@ -2457,10 +2432,19 @@ fn binOp(
if (int_info.bits <= 32) { if (int_info.bits <= 32) {
const rhs_immediate_ok = rhs == .immediate; const rhs_immediate_ok = rhs == .immediate;
const mir_tag: Mir.Inst.Tag = switch (tag) {
.shl_exact => .lsl,
.shr_exact => switch (lhs_ty.intInfo(self.target.*).signedness) {
.signed => Mir.Inst.Tag.asr,
.unsigned => Mir.Inst.Tag.lsr,
},
else => unreachable,
};
if (rhs_immediate_ok) { if (rhs_immediate_ok) {
return try self.binOpImmediate(tag, maybe_inst, lhs, rhs, lhs_ty, false); return try self.binOpImmediate(mir_tag, maybe_inst, lhs, rhs, lhs_ty, false);
} else { } else {
return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); return try self.binOpRegister(mir_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
} }
} else { } else {
return self.fail("TODO ARM binary operations on integers > u32/i32", .{}); return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
@ -2512,13 +2496,19 @@ fn binOp(
const lhs_immediate_ok = lhs == .immediate; const lhs_immediate_ok = lhs == .immediate;
const rhs_immediate_ok = rhs == .immediate; const rhs_immediate_ok = rhs == .immediate;
const mir_tag: Mir.Inst.Tag = switch (tag) {
.bool_and => .@"and",
.bool_or => .orr,
else => unreachable,
};
if (rhs_immediate_ok) { if (rhs_immediate_ok) {
return try self.binOpImmediate(tag, maybe_inst, lhs, rhs, lhs_ty, false); return try self.binOpImmediate(mir_tag, maybe_inst, lhs, rhs, lhs_ty, false);
} else if (lhs_immediate_ok) { } else if (lhs_immediate_ok) {
// swap lhs and rhs // swap lhs and rhs
return try self.binOpImmediate(tag, maybe_inst, rhs, lhs, rhs_ty, true); return try self.binOpImmediate(mir_tag, maybe_inst, rhs, lhs, rhs_ty, true);
} else { } else {
return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); return try self.binOpRegister(mir_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
} }
}, },
else => unreachable, else => unreachable,
@ -2537,7 +2527,7 @@ fn binOp(
const elem_size = @intCast(u32, elem_ty.abiSize(self.target.*)); const elem_size = @intCast(u32, elem_ty.abiSize(self.target.*));
if (elem_size == 1) { if (elem_size == 1) {
const base_tag: Air.Inst.Tag = switch (tag) { const base_tag: Mir.Inst.Tag = switch (tag) {
.ptr_add => .add, .ptr_add => .add,
.ptr_sub => .sub, .ptr_sub => .sub,
else => unreachable, else => unreachable,