| ... | ... | @@ -128,18 +128,11 @@ const MCValue = union(enum) { |
| 128 | 128 | register: Register, |
| 129 | 129 | /// The value is a tuple { wrapped: u32, overflow: u1 } where |
| 130 | 130 | /// wrapped is stored in the register and the overflow bit is |
| 131 | | /// stored in the C flag of the CPSR. |
| 131 | /// stored in the C (signed) or V (unsigned) flag of the CPSR. |
| 132 | 132 | /// |
| 133 | 133 | /// This MCValue is only generated by a add_with_overflow or |
| 134 | | /// sub_with_overflow instruction operating on u32. |
| 135 | | register_c_flag: Register, |
| 136 | | /// The value is a tuple { wrapped: i32, overflow: u1 } where |
| 137 | | /// wrapped is stored in the register and the overflow bit is |
| 138 | | /// stored in the V flag of the CPSR. |
| 139 | | /// |
| 140 | | /// This MCValue is only generated by a add_with_overflow or |
| 141 | | /// sub_with_overflow instruction operating on i32. |
| 142 | | register_v_flag: Register, |
| 134 | /// sub_with_overflow instruction operating on 32- or 64-bit values. |
| 135 | register_with_overflow: struct { reg: Register, flag: bits.Instruction.Condition }, |
| 143 | 136 | /// The value is in memory at a hard-coded address. |
| 144 | 137 | /// |
| 145 | 138 | /// If the type is a pointer, it means the pointer address is at |
| ... | ... | @@ -760,10 +753,8 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void { |
| 760 | 753 | .register => |reg| { |
| 761 | 754 | self.register_manager.freeReg(reg); |
| 762 | 755 | }, |
| 763 | | .register_c_flag, |
| 764 | | .register_v_flag, |
| 765 | | => |reg| { |
| 766 | | self.register_manager.freeReg(reg); |
| 756 | .register_with_overflow => |rwo| { |
| 757 | self.register_manager.freeReg(rwo.reg); |
| 767 | 758 | self.compare_flags_inst = null; |
| 768 | 759 | }, |
| 769 | 760 | .compare_flags_signed, .compare_flags_unsigned => { |
| ... | ... | @@ -905,10 +896,8 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void |
| 905 | 896 | log.debug("spilling {d} to stack mcv {any}", .{ inst, stack_mcv }); |
| 906 | 897 | const reg_mcv = self.getResolvedInstValue(inst); |
| 907 | 898 | switch (reg_mcv) { |
| 908 | | .register, |
| 909 | | .register_c_flag, |
| 910 | | .register_v_flag, |
| 911 | | => |r| assert(reg.id() == r.id()), |
| 899 | .register => |r| assert(reg.id() == r.id()), |
| 900 | .register_with_overflow => |rwo| assert(rwo.reg.id() == reg.id()), |
| 912 | 901 | else => unreachable, // not a register |
| 913 | 902 | } |
| 914 | 903 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| ... | ... | @@ -925,9 +914,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void { |
| 925 | 914 | .compare_flags_signed, |
| 926 | 915 | .compare_flags_unsigned, |
| 927 | 916 | => try self.allocRegOrMem(inst_to_save, true), |
| 928 | | .register_c_flag, |
| 929 | | .register_v_flag, |
| 930 | | => try self.allocRegOrMem(inst_to_save, false), |
| 917 | .register_with_overflow => try self.allocRegOrMem(inst_to_save, false), |
| 931 | 918 | else => unreachable, // mcv doesn't occupy the compare flags |
| 932 | 919 | }; |
| 933 | 920 | |
| ... | ... | @@ -942,9 +929,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void { |
| 942 | 929 | // TODO consolidate with register manager and spillInstruction |
| 943 | 930 | // this call should really belong in the register manager! |
| 944 | 931 | switch (mcv) { |
| 945 | | .register_c_flag, |
| 946 | | .register_v_flag, |
| 947 | | => |reg| self.register_manager.freeReg(reg), |
| 932 | .register_with_overflow => |rwo| self.register_manager.freeReg(rwo.reg), |
| 948 | 933 | else => {}, |
| 949 | 934 | } |
| 950 | 935 | } |
| ... | ... | @@ -1932,14 +1917,18 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1932 | 1917 | } |
| 1933 | 1918 | }; |
| 1934 | 1919 | |
| 1935 | | if (tag == .sub_with_overflow) { |
| 1936 | | break :result MCValue{ .register_v_flag = dest.register }; |
| 1937 | | } |
| 1938 | | |
| 1939 | | switch (int_info.signedness) { |
| 1940 | | .unsigned => break :result MCValue{ .register_c_flag = dest.register }, |
| 1941 | | .signed => break :result MCValue{ .register_v_flag = dest.register }, |
| 1942 | | } |
| 1920 | const flag: bits.Instruction.Condition = switch (int_info.signedness) { |
| 1921 | .unsigned => switch (tag) { |
| 1922 | .add_with_overflow => bits.Instruction.Condition.cs, |
| 1923 | .sub_with_overflow => bits.Instruction.Condition.cc, |
| 1924 | else => unreachable, |
| 1925 | }, |
| 1926 | .signed => .vs, |
| 1927 | }; |
| 1928 | break :result MCValue{ .register_with_overflow = .{ |
| 1929 | .reg = dest.register, |
| 1930 | .flag = flag, |
| 1931 | } }; |
| 1943 | 1932 | }, |
| 1944 | 1933 | else => return self.fail("TODO overflow operations on integers > u32/i32", .{}), |
| 1945 | 1934 | } |
| ... | ... | @@ -2648,8 +2637,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 2648 | 2637 | .dead => unreachable, |
| 2649 | 2638 | .compare_flags_unsigned, |
| 2650 | 2639 | .compare_flags_signed, |
| 2651 | | .register_c_flag, |
| 2652 | | .register_v_flag, |
| 2640 | .register_with_overflow, |
| 2653 | 2641 | => unreachable, // cannot hold an address |
| 2654 | 2642 | .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }), |
| 2655 | 2643 | .ptr_stack_offset => |off| try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }), |
| ... | ... | @@ -2871,8 +2859,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2871 | 2859 | .dead => unreachable, |
| 2872 | 2860 | .compare_flags_unsigned, |
| 2873 | 2861 | .compare_flags_signed, |
| 2874 | | .register_c_flag, |
| 2875 | | .register_v_flag, |
| 2862 | .register_with_overflow, |
| 2876 | 2863 | => unreachable, // cannot hold an address |
| 2877 | 2864 | .immediate => |imm| { |
| 2878 | 2865 | try self.setRegOrMem(value_ty, .{ .memory = imm }, value); |
| ... | ... | @@ -2993,13 +2980,11 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2993 | 2980 | .memory => |addr| { |
| 2994 | 2981 | break :result MCValue{ .memory = addr + struct_field_offset }; |
| 2995 | 2982 | }, |
| 2996 | | .register_c_flag, |
| 2997 | | .register_v_flag, |
| 2998 | | => |reg| { |
| 2983 | .register_with_overflow => |rwo| { |
| 2999 | 2984 | switch (index) { |
| 3000 | 2985 | 0 => { |
| 3001 | 2986 | // get wrapped value: return register |
| 3002 | | break :result MCValue{ .register = reg }; |
| 2987 | break :result MCValue{ .register = rwo.reg }; |
| 3003 | 2988 | }, |
| 3004 | 2989 | 1 => { |
| 3005 | 2990 | // TODO return special MCValue condition flags |
| ... | ... | @@ -3008,17 +2993,11 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 3008 | 2993 | const raw_dest_reg = try self.register_manager.allocReg(null, gp); |
| 3009 | 2994 | const dest_reg = raw_dest_reg.to32(); |
| 3010 | 2995 | |
| 3011 | | // C flag: cset reg, cs |
| 3012 | | // V flag: cset reg, vs |
| 3013 | 2996 | _ = try self.addInst(.{ |
| 3014 | 2997 | .tag = .cset, |
| 3015 | 2998 | .data = .{ .r_cond = .{ |
| 3016 | 2999 | .rd = dest_reg, |
| 3017 | | .cond = switch (mcv) { |
| 3018 | | .register_c_flag => .cs, |
| 3019 | | .register_v_flag => .vs, |
| 3020 | | else => unreachable, |
| 3021 | | }, |
| 3000 | .cond = rwo.flag, |
| 3022 | 3001 | } }, |
| 3023 | 3002 | }); |
| 3024 | 3003 | |
| ... | ... | @@ -4073,14 +4052,12 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 4073 | 4052 | else => return self.fail("TODO implement storing other types abi_size={}", .{abi_size}), |
| 4074 | 4053 | } |
| 4075 | 4054 | }, |
| 4076 | | .register_c_flag, |
| 4077 | | .register_v_flag, |
| 4078 | | => |reg| { |
| 4079 | | const reg_lock = self.register_manager.lockReg(reg); |
| 4055 | .register_with_overflow => |rwo| { |
| 4056 | const reg_lock = self.register_manager.lockReg(rwo.reg); |
| 4080 | 4057 | defer if (reg_lock) |locked_reg| self.register_manager.unlockReg(locked_reg); |
| 4081 | 4058 | |
| 4082 | 4059 | const wrapped_ty = ty.structFieldType(0); |
| 4083 | | try self.genSetStack(wrapped_ty, stack_offset, .{ .register = reg }); |
| 4060 | try self.genSetStack(wrapped_ty, stack_offset, .{ .register = rwo.reg }); |
| 4084 | 4061 | |
| 4085 | 4062 | const overflow_bit_ty = ty.structFieldType(1); |
| 4086 | 4063 | const overflow_bit_offset = @intCast(u32, ty.structFieldOffset(1, self.target.*)); |
| ... | ... | @@ -4090,17 +4067,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 4090 | 4067 | @intCast(u32, overflow_bit_ty.abiSize(self.target.*)), |
| 4091 | 4068 | ); |
| 4092 | 4069 | |
| 4093 | | // C flag: cset reg, cs |
| 4094 | | // V flag: cset reg, vs |
| 4095 | 4070 | _ = try self.addInst(.{ |
| 4096 | 4071 | .tag = .cset, |
| 4097 | 4072 | .data = .{ .r_cond = .{ |
| 4098 | 4073 | .rd = cond_reg, |
| 4099 | | .cond = switch (mcv) { |
| 4100 | | .register_c_flag => .cs, |
| 4101 | | .register_v_flag => .vs, |
| 4102 | | else => unreachable, |
| 4103 | | }, |
| 4074 | .cond = rwo.flag, |
| 4104 | 4075 | } }, |
| 4105 | 4076 | }); |
| 4106 | 4077 | |
| ... | ... | @@ -4270,9 +4241,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 4270 | 4241 | .data = .{ .rr = .{ .rd = reg, .rn = src_reg } }, |
| 4271 | 4242 | }); |
| 4272 | 4243 | }, |
| 4273 | | .register_c_flag, |
| 4274 | | .register_v_flag, |
| 4275 | | => unreachable, // doesn't fit into a register |
| 4244 | .register_with_overflow => unreachable, // doesn't fit into a register |
| 4276 | 4245 | .got_load, |
| 4277 | 4246 | .direct_load, |
| 4278 | 4247 | => |sym_index| { |