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