authorgravatar for koachan@protonmail.comKoakuma <koachan@protonmail.com> 2022-05-27 19:53:16+07:00
committergravatar for koachan@protonmail.comKoakuma <koachan@protonmail.com> 2022-06-06 20:34:53+07:00
log3d662cfaf4579cb01546c3e5123eece70fd60b9a
tree3e955cef4d2ea1f023b667cdf786872f9d0571a9
parent093332c02ed828c6c24d6c7e113ae2804ba7e6f3

stage2: sparc64: Implement airAddSubOverflow


3 files changed, 143 insertions(+), 9 deletions(-)

src/arch/sparc64/CodeGen.zig+141-9
......@@ -123,6 +123,16 @@ const MCValue = union(enum) {
123123 immediate: u64,
124124 /// The value is in a target-specific register.
125125 register: Register,
126 /// The value is a tuple { wrapped, overflow } where
127 /// wrapped is stored in the register and the overflow bit is
128 /// stored in the C (signed) or V (unsigned) flag of the CCR.
129 ///
130 /// This MCValue is only generated by a add_with_overflow or
131 /// sub_with_overflow instruction operating on 32- or 64-bit values.
132 register_with_overflow: struct {
133 reg: Register,
134 flag: struct { cond: Instruction.ICondition, ccr: Instruction.CCR },
135 },
126136 /// The value is in memory at a hard-coded address.
127137 /// If the type is a pointer, it means the pointer address is at this memory location.
128138 memory: u64,
......@@ -525,8 +535,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
525535 .trunc_float,
526536 => @panic("TODO try self.airUnaryMath(inst)"),
527537
528 .add_with_overflow => @panic("TODO try self.airAddWithOverflow(inst)"),
529 .sub_with_overflow => @panic("TODO try self.airSubWithOverflow(inst)"),
538 .add_with_overflow => try self.airAddSubWithOverflow(inst),
539 .sub_with_overflow => try self.airAddSubWithOverflow(inst),
530540 .mul_with_overflow => @panic("TODO try self.airMulWithOverflow(inst)"),
531541 .shl_with_overflow => @panic("TODO try self.airShlWithOverflow(inst)"),
532542
......@@ -684,6 +694,88 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
684694 }
685695}
686696
697fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
698 const tag = self.air.instructions.items(.tag)[inst];
699 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
700 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
701 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
702 const lhs = try self.resolveInst(extra.lhs);
703 const rhs = try self.resolveInst(extra.rhs);
704 const lhs_ty = self.air.typeOf(extra.lhs);
705 const rhs_ty = self.air.typeOf(extra.rhs);
706
707 switch (lhs_ty.zigTypeTag()) {
708 .Vector => return self.fail("TODO implement add_with_overflow/sub_with_overflow for vectors", .{}),
709 .Int => {
710 const mod = self.bin_file.options.module.?;
711 assert(lhs_ty.eql(rhs_ty, mod));
712 const int_info = lhs_ty.intInfo(self.target.*);
713 switch (int_info.bits) {
714 32, 64 => {
715 // Only say yes if the operation is
716 // commutative, i.e. we can swap both of the
717 // operands
718 const lhs_immediate_ok = switch (tag) {
719 .add_with_overflow => lhs == .immediate and lhs.immediate <= std.math.maxInt(u12),
720 .sub_with_overflow => false,
721 else => unreachable,
722 };
723 const rhs_immediate_ok = switch (tag) {
724 .add_with_overflow,
725 .sub_with_overflow,
726 => rhs == .immediate and rhs.immediate <= std.math.maxInt(u12),
727 else => unreachable,
728 };
729
730 const mir_tag: Mir.Inst.Tag = switch (tag) {
731 .add_with_overflow => .addcc,
732 .sub_with_overflow => .subcc,
733 else => unreachable,
734 };
735
736 try self.spillCompareFlagsIfOccupied();
737 self.compare_flags_inst = inst;
738
739 const dest = blk: {
740 if (rhs_immediate_ok) {
741 break :blk try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, null);
742 } else if (lhs_immediate_ok) {
743 // swap lhs and rhs
744 break :blk try self.binOpImmediate(mir_tag, rhs, lhs, rhs_ty, true, null);
745 } else {
746 break :blk try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, null);
747 }
748 };
749
750 const cond = switch (int_info.signedness) {
751 .unsigned => switch (tag) {
752 .add_with_overflow => Instruction.ICondition.cs,
753 .sub_with_overflow => Instruction.ICondition.cc,
754 else => unreachable,
755 },
756 .signed => Instruction.ICondition.vs,
757 };
758
759 const ccr = switch (int_info.bits) {
760 32 => Instruction.CCR.icc,
761 64 => Instruction.CCR.xcc,
762 else => unreachable,
763 };
764
765 break :result MCValue{ .register_with_overflow = .{
766 .reg = dest.register,
767 .flag = .{ .cond = cond, .ccr = ccr },
768 } };
769 },
770 else => return self.fail("TODO overflow operations on other integer sizes", .{}),
771 }
772 },
773 else => unreachable,
774 }
775 };
776 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
777}
778
687779fn airAlloc(self: *Self, inst: Air.Inst.Index) !void {
688780 const stack_offset = try self.allocMemPtr(inst);
689781 return self.finishAir(inst, .{ .ptr_stack_offset = stack_offset }, .{ .none, .none, .none });
......@@ -955,13 +1047,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
9551047
9561048 switch (mc_arg) {
9571049 .none => continue,
958 .undef => unreachable,
959 .immediate => unreachable,
960 .unreach => unreachable,
961 .dead => unreachable,
962 .memory => unreachable,
963 .compare_flags_signed => unreachable,
964 .compare_flags_unsigned => unreachable,
9651050 .register => |reg| {
9661051 try self.register_manager.getReg(reg, null);
9671052 try self.genSetReg(arg_ty, reg, arg_mcv);
......@@ -972,6 +1057,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
9721057 .ptr_stack_offset => {
9731058 return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{});
9741059 },
1060 else => unreachable,
9751061 }
9761062 }
9771063
......@@ -1894,6 +1980,7 @@ fn binOpImmediate(
18941980
18951981 const mir_data: Mir.Inst.Data = switch (mir_tag) {
18961982 .add,
1983 .addcc,
18971984 .mulx,
18981985 .subcc,
18991986 => .{
......@@ -2010,6 +2097,7 @@ fn binOpRegister(
20102097
20112098 const mir_data: Mir.Inst.Data = switch (mir_tag) {
20122099 .add,
2100 .addcc,
20132101 .mulx,
20142102 .subcc,
20152103 => .{
......@@ -2473,6 +2561,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
24732561 },
24742562 });
24752563 },
2564 .register_with_overflow => unreachable,
24762565 .memory => |addr| {
24772566 // The value is in memory at a hard-coded address.
24782567 // If the type is a pointer, it means the pointer address is at this memory location.
......@@ -2519,6 +2608,47 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
25192608 return self.fail("TODO larger stack offsets", .{});
25202609 return self.genStore(reg, .sp, i13, simm13, abi_size);
25212610 },
2611 .register_with_overflow => |rwo| {
2612 const reg_lock = self.register_manager.lockReg(rwo.reg);
2613 defer if (reg_lock) |locked_reg| self.register_manager.unlockReg(locked_reg);
2614
2615 const wrapped_ty = ty.structFieldType(0);
2616 try self.genSetStack(wrapped_ty, stack_offset, .{ .register = rwo.reg });
2617
2618 const overflow_bit_ty = ty.structFieldType(1);
2619 const overflow_bit_offset = @intCast(u32, ty.structFieldOffset(1, self.target.*));
2620 const cond_reg = try self.register_manager.allocReg(null, gp);
2621
2622 // TODO handle floating point CCRs
2623 assert(rwo.flag.ccr == .xcc or rwo.flag.ccr == .icc);
2624
2625 _ = try self.addInst(.{
2626 .tag = .mov,
2627 .data = .{
2628 .arithmetic_2op = .{
2629 .is_imm = false,
2630 .rs1 = cond_reg,
2631 .rs2_or_imm = .{ .rs2 = .g0 },
2632 },
2633 },
2634 });
2635
2636 _ = try self.addInst(.{
2637 .tag = .movcc,
2638 .data = .{
2639 .conditional_move = .{
2640 .ccr = rwo.flag.ccr,
2641 .cond = .{ .icond = rwo.flag.cond },
2642 .is_imm = true,
2643 .rd = cond_reg,
2644 .rs2_or_imm = .{ .imm = 1 },
2645 },
2646 },
2647 });
2648 try self.genSetStack(overflow_bit_ty, stack_offset - overflow_bit_offset, .{
2649 .register = cond_reg,
2650 });
2651 },
25222652 .memory, .stack_offset => {
25232653 switch (mcv) {
25242654 .stack_offset => |off| {
......@@ -2760,6 +2890,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
27602890 .dead => unreachable,
27612891 .compare_flags_unsigned,
27622892 .compare_flags_signed,
2893 .register_with_overflow,
27632894 => unreachable, // cannot hold an address
27642895 .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }),
27652896 .ptr_stack_offset => |off| try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }),
......@@ -3100,6 +3231,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
31003231 .dead => unreachable,
31013232 .compare_flags_unsigned,
31023233 .compare_flags_signed,
3234 .register_with_overflow,
31033235 => unreachable, // cannot hold an address
31043236 .immediate => |imm| {
31053237 try self.setRegOrMem(value_ty, .{ .memory = imm }, value);
src/arch/sparc64/Emit.zig+1
......@@ -79,6 +79,7 @@ pub fn emitMir(
7979 .dbg_epilogue_begin => try emit.mirDebugEpilogueBegin(),
8080
8181 .add => try emit.mirArithmetic3Op(inst),
82 .addcc => @panic("TODO implement sparc64 addcc"),
8283
8384 .bpr => try emit.mirConditionalBranch(inst),
8485 .bpcc => try emit.mirConditionalBranch(inst),
src/arch/sparc64/Mir.zig+1
......@@ -42,6 +42,7 @@ pub const Inst = struct {
4242 /// This uses the arithmetic_3op field.
4343 // TODO add other operations.
4444 add,
45 addcc,
4546
4647 /// A.3 Branch on Integer Register with Prediction (BPr)
4748 /// This uses the branch_predict_reg field.