| ... | @@ -35,6 +35,7 @@ const RegisterManager = abi.RegisterManager; | ... | @@ -35,6 +35,7 @@ const RegisterManager = abi.RegisterManager; |
| 35 | const RegisterLock = RegisterManager.RegisterLock; | 35 | const RegisterLock = RegisterManager.RegisterLock; |
| 36 | const Register = bits.Register; | 36 | const Register = bits.Register; |
| 37 | const Instruction = bits.Instruction; | 37 | const Instruction = bits.Instruction; |
| | 38 | const Condition = bits.Instruction.Condition; |
| 38 | const callee_preserved_regs = abi.callee_preserved_regs; | 39 | const callee_preserved_regs = abi.callee_preserved_regs; |
| 39 | const c_abi_int_param_regs = abi.c_abi_int_param_regs; | 40 | const c_abi_int_param_regs = abi.c_abi_int_param_regs; |
| 40 | const c_abi_int_return_regs = abi.c_abi_int_return_regs; | 41 | const c_abi_int_return_regs = abi.c_abi_int_return_regs; |
| ... | @@ -90,7 +91,7 @@ register_manager: RegisterManager = .{}, | ... | @@ -90,7 +91,7 @@ register_manager: RegisterManager = .{}, |
| 90 | /// Maps offset to what is stored there. | 91 | /// Maps offset to what is stored there. |
| 91 | stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{}, | 92 | stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{}, |
| 92 | /// Tracks the current instruction allocated to the compare flags | 93 | /// Tracks the current instruction allocated to the compare flags |
| 93 | compare_flags_inst: ?Air.Inst.Index = null, | 94 | condition_flags_inst: ?Air.Inst.Index = null, |
| 94 | | 95 | |
| 95 | /// Offset from the stack base, representing the end of the stack frame. | 96 | /// Offset from the stack base, representing the end of the stack frame. |
| 96 | max_end_stack: u32 = 0, | 97 | max_end_stack: u32 = 0, |
| ... | @@ -161,12 +162,10 @@ const MCValue = union(enum) { | ... | @@ -161,12 +162,10 @@ const MCValue = union(enum) { |
| 161 | /// The value is a pointer to one of the stack variables (payload | 162 | /// The value is a pointer to one of the stack variables (payload |
| 162 | /// is stack offset). | 163 | /// is stack offset). |
| 163 | ptr_stack_offset: u32, | 164 | ptr_stack_offset: u32, |
| 164 | /// The value is in the compare flags assuming an unsigned | 165 | /// The value resides in the N, Z, C, V flags. The value is 1 (if |
| 165 | /// operation, with this operator applied on top of it. | 166 | /// the type is u1) or true (if the type in bool) iff the |
| 166 | compare_flags_unsigned: math.CompareOperator, | 167 | /// specified condition is true. |
| 167 | /// The value is in the compare flags assuming a signed operation, | 168 | condition_flags: Condition, |
| 168 | /// with this operator applied on top of it. | | |
| 169 | compare_flags_signed: math.CompareOperator, | | |
| 170 | | 169 | |
| 171 | fn isMemory(mcv: MCValue) bool { | 170 | fn isMemory(mcv: MCValue) bool { |
| 172 | return switch (mcv) { | 171 | return switch (mcv) { |
| ... | @@ -190,8 +189,7 @@ const MCValue = union(enum) { | ... | @@ -190,8 +189,7 @@ const MCValue = union(enum) { |
| 190 | | 189 | |
| 191 | .immediate, | 190 | .immediate, |
| 192 | .memory, | 191 | .memory, |
| 193 | .compare_flags_unsigned, | 192 | .condition_flags, |
| 194 | .compare_flags_signed, | | |
| 195 | .ptr_stack_offset, | 193 | .ptr_stack_offset, |
| 196 | .undef, | 194 | .undef, |
| 197 | => false, | 195 | => false, |
| ... | @@ -758,10 +756,10 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void { | ... | @@ -758,10 +756,10 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void { |
| 758 | }, | 756 | }, |
| 759 | .register_with_overflow => |rwo| { | 757 | .register_with_overflow => |rwo| { |
| 760 | self.register_manager.freeReg(rwo.reg); | 758 | self.register_manager.freeReg(rwo.reg); |
| 761 | self.compare_flags_inst = null; | 759 | self.condition_flags_inst = null; |
| 762 | }, | 760 | }, |
| 763 | .compare_flags_signed, .compare_flags_unsigned => { | 761 | .condition_flags => { |
| 764 | self.compare_flags_inst = null; | 762 | self.condition_flags_inst = null; |
| 765 | }, | 763 | }, |
| 766 | else => {}, // TODO process stack allocation death | 764 | else => {}, // TODO process stack allocation death |
| 767 | } | 765 | } |
| ... | @@ -911,12 +909,10 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void | ... | @@ -911,12 +909,10 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void |
| 911 | /// Save the current instruction stored in the compare flags if | 909 | /// Save the current instruction stored in the compare flags if |
| 912 | /// occupied | 910 | /// occupied |
| 913 | fn spillCompareFlagsIfOccupied(self: *Self) !void { | 911 | fn spillCompareFlagsIfOccupied(self: *Self) !void { |
| 914 | if (self.compare_flags_inst) |inst_to_save| { | 912 | if (self.condition_flags_inst) |inst_to_save| { |
| 915 | const mcv = self.getResolvedInstValue(inst_to_save); | 913 | const mcv = self.getResolvedInstValue(inst_to_save); |
| 916 | const new_mcv = switch (mcv) { | 914 | const new_mcv = switch (mcv) { |
| 917 | .compare_flags_signed, | 915 | .condition_flags => try self.allocRegOrMem(inst_to_save, true), |
| 918 | .compare_flags_unsigned, | | |
| 919 | => try self.allocRegOrMem(inst_to_save, true), | | |
| 920 | .register_with_overflow => try self.allocRegOrMem(inst_to_save, false), | 916 | .register_with_overflow => try self.allocRegOrMem(inst_to_save, false), |
| 921 | else => unreachable, // mcv doesn't occupy the compare flags | 917 | else => unreachable, // mcv doesn't occupy the compare flags |
| 922 | }; | 918 | }; |
| ... | @@ -927,7 +923,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void { | ... | @@ -927,7 +923,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void { |
| 927 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; | 923 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 928 | try branch.inst_table.put(self.gpa, inst_to_save, new_mcv); | 924 | try branch.inst_table.put(self.gpa, inst_to_save, new_mcv); |
| 929 | | 925 | |
| 930 | self.compare_flags_inst = null; | 926 | self.condition_flags_inst = null; |
| 931 | | 927 | |
| 932 | // TODO consolidate with register manager and spillInstruction | 928 | // TODO consolidate with register manager and spillInstruction |
| 933 | // this call should really belong in the register manager! | 929 | // this call should really belong in the register manager! |
| ... | @@ -1109,32 +1105,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1109,32 +1105,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1109 | switch (operand) { | 1105 | switch (operand) { |
| 1110 | .dead => unreachable, | 1106 | .dead => unreachable, |
| 1111 | .unreach => unreachable, | 1107 | .unreach => unreachable, |
| 1112 | .compare_flags_unsigned => |op| { | 1108 | .condition_flags => |cond| break :result MCValue{ .condition_flags = cond.negate() }, |
| 1113 | const r = MCValue{ | | |
| 1114 | .compare_flags_unsigned = switch (op) { | | |
| 1115 | .gte => .lt, | | |
| 1116 | .gt => .lte, | | |
| 1117 | .neq => .eq, | | |
| 1118 | .lt => .gte, | | |
| 1119 | .lte => .gt, | | |
| 1120 | .eq => .neq, | | |
| 1121 | }, | | |
| 1122 | }; | | |
| 1123 | break :result r; | | |
| 1124 | }, | | |
| 1125 | .compare_flags_signed => |op| { | | |
| 1126 | const r = MCValue{ | | |
| 1127 | .compare_flags_signed = switch (op) { | | |
| 1128 | .gte => .lt, | | |
| 1129 | .gt => .lte, | | |
| 1130 | .neq => .eq, | | |
| 1131 | .lt => .gte, | | |
| 1132 | .lte => .gt, | | |
| 1133 | .eq => .neq, | | |
| 1134 | }, | | |
| 1135 | }; | | |
| 1136 | break :result r; | | |
| 1137 | }, | | |
| 1138 | else => { | 1109 | else => { |
| 1139 | switch (operand_ty.zigTypeTag()) { | 1110 | switch (operand_ty.zigTypeTag()) { |
| 1140 | .Bool => { | 1111 | .Bool => { |
| ... | @@ -1851,7 +1822,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1851,7 +1822,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1851 | const stack_offset = try self.allocMem(inst, tuple_size, tuple_align); | 1822 | const stack_offset = try self.allocMem(inst, tuple_size, tuple_align); |
| 1852 | | 1823 | |
| 1853 | try self.spillCompareFlagsIfOccupied(); | 1824 | try self.spillCompareFlagsIfOccupied(); |
| 1854 | self.compare_flags_inst = null; | 1825 | self.condition_flags_inst = null; |
| 1855 | | 1826 | |
| 1856 | const base_tag: Air.Inst.Tag = switch (tag) { | 1827 | const base_tag: Air.Inst.Tag = switch (tag) { |
| 1857 | .add_with_overflow => .add, | 1828 | .add_with_overflow => .add, |
| ... | @@ -1875,7 +1846,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1875,7 +1846,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1875 | _ = try self.binOp(.cmp_eq, dest, .{ .register = truncated_reg }, Type.usize, Type.usize, null); | 1846 | _ = try self.binOp(.cmp_eq, dest, .{ .register = truncated_reg }, Type.usize, Type.usize, null); |
| 1876 | | 1847 | |
| 1877 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); | 1848 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); |
| 1878 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags_unsigned = .neq }); | 1849 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .condition_flags = .ne }); |
| 1879 | | 1850 | |
| 1880 | break :result MCValue{ .stack_offset = stack_offset }; | 1851 | break :result MCValue{ .stack_offset = stack_offset }; |
| 1881 | }, | 1852 | }, |
| ... | @@ -1907,7 +1878,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1907,7 +1878,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1907 | }; | 1878 | }; |
| 1908 | | 1879 | |
| 1909 | try self.spillCompareFlagsIfOccupied(); | 1880 | try self.spillCompareFlagsIfOccupied(); |
| 1910 | self.compare_flags_inst = inst; | 1881 | self.condition_flags_inst = inst; |
| 1911 | | 1882 | |
| 1912 | const dest = blk: { | 1883 | const dest = blk: { |
| 1913 | if (rhs_immediate_ok) { | 1884 | if (rhs_immediate_ok) { |
| ... | @@ -1966,7 +1937,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1966,7 +1937,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1966 | const stack_offset = try self.allocMem(inst, tuple_size, tuple_align); | 1937 | const stack_offset = try self.allocMem(inst, tuple_size, tuple_align); |
| 1967 | | 1938 | |
| 1968 | try self.spillCompareFlagsIfOccupied(); | 1939 | try self.spillCompareFlagsIfOccupied(); |
| 1969 | self.compare_flags_inst = null; | 1940 | self.condition_flags_inst = null; |
| 1970 | | 1941 | |
| 1971 | const base_tag: Mir.Inst.Tag = switch (int_info.signedness) { | 1942 | const base_tag: Mir.Inst.Tag = switch (int_info.signedness) { |
| 1972 | .signed => .smull, | 1943 | .signed => .smull, |
| ... | @@ -2015,16 +1986,14 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2015,16 +1986,14 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2015 | } | 1986 | } |
| 2016 | | 1987 | |
| 2017 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); | 1988 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); |
| 2018 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ | 1989 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .condition_flags = .ne }); |
| 2019 | .compare_flags_unsigned = .neq, | | |
| 2020 | }); | | |
| 2021 | | 1990 | |
| 2022 | break :result MCValue{ .stack_offset = stack_offset }; | 1991 | break :result MCValue{ .stack_offset = stack_offset }; |
| 2023 | } else if (int_info.bits <= 64) { | 1992 | } else if (int_info.bits <= 64) { |
| 2024 | const stack_offset = try self.allocMem(inst, tuple_size, tuple_align); | 1993 | const stack_offset = try self.allocMem(inst, tuple_size, tuple_align); |
| 2025 | | 1994 | |
| 2026 | try self.spillCompareFlagsIfOccupied(); | 1995 | try self.spillCompareFlagsIfOccupied(); |
| 2027 | self.compare_flags_inst = null; | 1996 | self.condition_flags_inst = null; |
| 2028 | | 1997 | |
| 2029 | // TODO this should really be put in a helper similar to `binOpRegister` | 1998 | // TODO this should really be put in a helper similar to `binOpRegister` |
| 2030 | const lhs_is_register = lhs == .register; | 1999 | const lhs_is_register = lhs == .register; |
| ... | @@ -2194,9 +2163,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2194,9 +2163,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2194 | try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits); | 2163 | try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits); |
| 2195 | | 2164 | |
| 2196 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); | 2165 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); |
| 2197 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ | 2166 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .condition_flags = .ne }); |
| 2198 | .compare_flags_unsigned = .neq, | | |
| 2199 | }); | | |
| 2200 | | 2167 | |
| 2201 | break :result MCValue{ .stack_offset = stack_offset }; | 2168 | break :result MCValue{ .stack_offset = stack_offset }; |
| 2202 | } else return self.fail("TODO implement mul_with_overflow for integers > u64/i64", .{}); | 2169 | } else return self.fail("TODO implement mul_with_overflow for integers > u64/i64", .{}); |
| ... | @@ -2236,7 +2203,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2236,7 +2203,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2236 | defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg); | 2203 | defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg); |
| 2237 | | 2204 | |
| 2238 | try self.spillCompareFlagsIfOccupied(); | 2205 | try self.spillCompareFlagsIfOccupied(); |
| 2239 | self.compare_flags_inst = null; | 2206 | self.condition_flags_inst = null; |
| 2240 | | 2207 | |
| 2241 | // lsl dest, lhs, rhs | 2208 | // lsl dest, lhs, rhs |
| 2242 | const dest = try self.binOp(.shl, lhs, rhs, lhs_ty, rhs_ty, null); | 2209 | const dest = try self.binOp(.shl, lhs, rhs, lhs_ty, rhs_ty, null); |
| ... | @@ -2251,9 +2218,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2251,9 +2218,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2251 | _ = try self.binOp(.cmp_eq, lhs, reconstructed, lhs_ty, lhs_ty, null); | 2218 | _ = try self.binOp(.cmp_eq, lhs, reconstructed, lhs_ty, lhs_ty, null); |
| 2252 | | 2219 | |
| 2253 | try self.genSetStack(lhs_ty, stack_offset, dest); | 2220 | try self.genSetStack(lhs_ty, stack_offset, dest); |
| 2254 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ | 2221 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .condition_flags = .ne }); |
| 2255 | .compare_flags_unsigned = .neq, | | |
| 2256 | }); | | |
| 2257 | | 2222 | |
| 2258 | break :result MCValue{ .stack_offset = stack_offset }; | 2223 | break :result MCValue{ .stack_offset = stack_offset }; |
| 2259 | } else { | 2224 | } else { |
| ... | @@ -2681,8 +2646,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -2681,8 +2646,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 2681 | .undef => unreachable, | 2646 | .undef => unreachable, |
| 2682 | .unreach => unreachable, | 2647 | .unreach => unreachable, |
| 2683 | .dead => unreachable, | 2648 | .dead => unreachable, |
| 2684 | .compare_flags_unsigned, | 2649 | .condition_flags, |
| 2685 | .compare_flags_signed, | | |
| 2686 | .register_with_overflow, | 2650 | .register_with_overflow, |
| 2687 | => unreachable, // cannot hold an address | 2651 | => unreachable, // cannot hold an address |
| 2688 | .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }), | 2652 | .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }), |
| ... | @@ -2694,7 +2658,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -2694,7 +2658,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 2694 | switch (dst_mcv) { | 2658 | switch (dst_mcv) { |
| 2695 | .dead => unreachable, | 2659 | .dead => unreachable, |
| 2696 | .undef => unreachable, | 2660 | .undef => unreachable, |
| 2697 | .compare_flags_signed, .compare_flags_unsigned => unreachable, | 2661 | .condition_flags => unreachable, |
| 2698 | .register => |dst_reg| { | 2662 | .register => |dst_reg| { |
| 2699 | try self.genLdrRegister(dst_reg, addr_reg, elem_ty); | 2663 | try self.genLdrRegister(dst_reg, addr_reg, elem_ty); |
| 2700 | }, | 2664 | }, |
| ... | @@ -2903,8 +2867,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -2903,8 +2867,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2903 | .undef => unreachable, | 2867 | .undef => unreachable, |
| 2904 | .unreach => unreachable, | 2868 | .unreach => unreachable, |
| 2905 | .dead => unreachable, | 2869 | .dead => unreachable, |
| 2906 | .compare_flags_unsigned, | 2870 | .condition_flags, |
| 2907 | .compare_flags_signed, | | |
| 2908 | .register_with_overflow, | 2871 | .register_with_overflow, |
| 2909 | => unreachable, // cannot hold an address | 2872 | => unreachable, // cannot hold an address |
| 2910 | .immediate => |imm| { | 2873 | .immediate => |imm| { |
| ... | @@ -3370,11 +3333,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | ... | @@ -3370,11 +3333,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 3370 | }); | 3333 | }); |
| 3371 | | 3334 | |
| 3372 | try self.spillCompareFlagsIfOccupied(); | 3335 | try self.spillCompareFlagsIfOccupied(); |
| 3373 | self.compare_flags_inst = inst; | 3336 | self.condition_flags_inst = inst; |
| 3374 | | 3337 | |
| 3375 | break :result switch (int_info.signedness) { | 3338 | break :result switch (int_info.signedness) { |
| 3376 | .signed => MCValue{ .compare_flags_signed = op }, | 3339 | .signed => MCValue{ .condition_flags = Condition.fromCompareOperatorSigned(op) }, |
| 3377 | .unsigned => MCValue{ .compare_flags_unsigned = op }, | 3340 | .unsigned => MCValue{ .condition_flags = Condition.fromCompareOperatorUnsigned(op) }, |
| 3378 | }; | 3341 | }; |
| 3379 | } else { | 3342 | } else { |
| 3380 | return self.fail("TODO AArch64 cmp for ints > 64 bits", .{}); | 3343 | return self.fail("TODO AArch64 cmp for ints > 64 bits", .{}); |
| ... | @@ -3434,26 +3397,13 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3434,26 +3397,13 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { |
| 3434 | | 3397 | |
| 3435 | fn condBr(self: *Self, condition: MCValue) !Mir.Inst.Index { | 3398 | fn condBr(self: *Self, condition: MCValue) !Mir.Inst.Index { |
| 3436 | switch (condition) { | 3399 | switch (condition) { |
| 3437 | .compare_flags_signed, | 3400 | .condition_flags => |cond| return try self.addInst(.{ |
| 3438 | .compare_flags_unsigned, | | |
| 3439 | => return try self.addInst(.{ | | |
| 3440 | .tag = .b_cond, | 3401 | .tag = .b_cond, |
| 3441 | .data = .{ | 3402 | .data = .{ |
| 3442 | .inst_cond = .{ | 3403 | .inst_cond = .{ |
| 3443 | .inst = undefined, // populated later through performReloc | 3404 | .inst = undefined, // populated later through performReloc |
| 3444 | .cond = switch (condition) { | 3405 | // Here we map to the opposite condition because the jump is to the false branch. |
| 3445 | .compare_flags_signed => |cmp_op| blk: { | 3406 | .cond = cond.negate(), |
| 3446 | // Here we map to the opposite condition because the jump is to the false branch. | | |
| 3447 | const condition_code = Instruction.Condition.fromCompareOperatorSigned(cmp_op); | | |
| 3448 | break :blk condition_code.negate(); | | |
| 3449 | }, | | |
| 3450 | .compare_flags_unsigned => |cmp_op| blk: { | | |
| 3451 | // Here we map to the opposite condition because the jump is to the false branch. | | |
| 3452 | const condition_code = Instruction.Condition.fromCompareOperatorUnsigned(cmp_op); | | |
| 3453 | break :blk condition_code.negate(); | | |
| 3454 | }, | | |
| 3455 | else => unreachable, | | |
| 3456 | }, | | |
| 3457 | }, | 3407 | }, |
| 3458 | }, | 3408 | }, |
| 3459 | }), | 3409 | }), |
| ... | @@ -3503,7 +3453,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3503,7 +3453,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 3503 | var parent_stack = try self.stack.clone(self.gpa); | 3453 | var parent_stack = try self.stack.clone(self.gpa); |
| 3504 | defer parent_stack.deinit(self.gpa); | 3454 | defer parent_stack.deinit(self.gpa); |
| 3505 | const parent_registers = self.register_manager.registers; | 3455 | const parent_registers = self.register_manager.registers; |
| 3506 | const parent_compare_flags_inst = self.compare_flags_inst; | 3456 | const parent_condition_flags_inst = self.condition_flags_inst; |
| 3507 | | 3457 | |
| 3508 | try self.branch_stack.append(.{}); | 3458 | try self.branch_stack.append(.{}); |
| 3509 | errdefer { | 3459 | errdefer { |
| ... | @@ -3522,7 +3472,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3522,7 +3472,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 3522 | defer saved_then_branch.deinit(self.gpa); | 3472 | defer saved_then_branch.deinit(self.gpa); |
| 3523 | | 3473 | |
| 3524 | self.register_manager.registers = parent_registers; | 3474 | self.register_manager.registers = parent_registers; |
| 3525 | self.compare_flags_inst = parent_compare_flags_inst; | 3475 | self.condition_flags_inst = parent_condition_flags_inst; |
| 3526 | | 3476 | |
| 3527 | self.stack.deinit(self.gpa); | 3477 | self.stack.deinit(self.gpa); |
| 3528 | self.stack = parent_stack; | 3478 | self.stack = parent_stack; |
| ... | @@ -3672,15 +3622,15 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue { | ... | @@ -3672,15 +3622,15 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 3672 | else => return self.fail("TODO implement isErr for {}", .{operand}), | 3622 | else => return self.fail("TODO implement isErr for {}", .{operand}), |
| 3673 | } | 3623 | } |
| 3674 | | 3624 | |
| 3675 | return MCValue{ .compare_flags_unsigned = .gt }; | 3625 | return MCValue{ .condition_flags = .hi }; |
| 3676 | } | 3626 | } |
| 3677 | | 3627 | |
| 3678 | fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue { | 3628 | fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 3679 | const is_err_result = try self.isErr(ty, operand); | 3629 | const is_err_result = try self.isErr(ty, operand); |
| 3680 | switch (is_err_result) { | 3630 | switch (is_err_result) { |
| 3681 | .compare_flags_unsigned => |op| { | 3631 | .condition_flags => |cond| { |
| 3682 | assert(op == .gt); | 3632 | assert(cond == .hi); |
| 3683 | return MCValue{ .compare_flags_unsigned = .lte }; | 3633 | return MCValue{ .condition_flags = cond.negate() }; |
| 3684 | }, | 3634 | }, |
| 3685 | .immediate => |imm| { | 3635 | .immediate => |imm| { |
| 3686 | assert(imm == 0); | 3636 | assert(imm == 0); |
| ... | @@ -3889,7 +3839,7 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { | ... | @@ -3889,7 +3839,7 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { |
| 3889 | block_data.mcv = switch (operand_mcv) { | 3839 | block_data.mcv = switch (operand_mcv) { |
| 3890 | .none, .dead, .unreach => unreachable, | 3840 | .none, .dead, .unreach => unreachable, |
| 3891 | .register, .stack_offset, .memory => operand_mcv, | 3841 | .register, .stack_offset, .memory => operand_mcv, |
| 3892 | .immediate => blk: { | 3842 | .immediate, .condition_flags => blk: { |
| 3893 | const new_mcv = try self.allocRegOrMem(block, true); | 3843 | const new_mcv = try self.allocRegOrMem(block, true); |
| 3894 | try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv); | 3844 | try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv); |
| 3895 | break :blk new_mcv; | 3845 | break :blk new_mcv; |
| ... | @@ -4072,8 +4022,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -4072,8 +4022,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 4072 | else => return self.fail("TODO implement memset", .{}), | 4022 | else => return self.fail("TODO implement memset", .{}), |
| 4073 | } | 4023 | } |
| 4074 | }, | 4024 | }, |
| 4075 | .compare_flags_unsigned, | 4025 | .condition_flags, |
| 4076 | .compare_flags_signed, | | |
| 4077 | .immediate, | 4026 | .immediate, |
| 4078 | .ptr_stack_offset, | 4027 | .ptr_stack_offset, |
| 4079 | => { | 4028 | => { |
| ... | @@ -4235,15 +4184,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -4235,15 +4184,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 4235 | } }, | 4184 | } }, |
| 4236 | }); | 4185 | }); |
| 4237 | }, | 4186 | }, |
| 4238 | .compare_flags_unsigned, | 4187 | .condition_flags => |condition| { |
| 4239 | .compare_flags_signed, | | |
| 4240 | => |op| { | | |
| 4241 | const condition = switch (mcv) { | | |
| 4242 | .compare_flags_unsigned => Instruction.Condition.fromCompareOperatorUnsigned(op), | | |
| 4243 | .compare_flags_signed => Instruction.Condition.fromCompareOperatorSigned(op), | | |
| 4244 | else => unreachable, | | |
| 4245 | }; | | |
| 4246 | | | |
| 4247 | _ = try self.addInst(.{ | 4188 | _ = try self.addInst(.{ |
| 4248 | .tag = .cset, | 4189 | .tag = .cset, |
| 4249 | .data = .{ .r_cond = .{ | 4190 | .data = .{ .r_cond = .{ |