| ... | @@ -102,9 +102,12 @@ air_bookkeeping: @TypeOf(air_bookkeeping_init) = air_bookkeeping_init, | ... | @@ -102,9 +102,12 @@ air_bookkeeping: @TypeOf(air_bookkeeping_init) = air_bookkeeping_init, |
| 102 | const air_bookkeeping_init = if (std.debug.runtime_safety) @as(usize, 0) else {}; | 102 | const air_bookkeeping_init = if (std.debug.runtime_safety) @as(usize, 0) else {}; |
| 103 | | 103 | |
| 104 | const MCValue = union(enum) { | 104 | const MCValue = union(enum) { |
| 105 | /// No runtime bits. `void` types, empty structs, u0, enums with 1 tag, etc. | 105 | /// No runtime bits. `void` types, empty structs, u0, enums with 1 |
| 106 | /// TODO Look into deleting this tag and using `dead` instead, since every use | 106 | /// tag, etc. |
| 107 | /// of MCValue.none should be instead looking at the type and noticing it is 0 bits. | 107 | /// |
| | 108 | /// TODO Look into deleting this tag and using `dead` instead, |
| | 109 | /// since every use of MCValue.none should be instead looking at |
| | 110 | /// the type and noticing it is 0 bits. |
| 108 | none, | 111 | none, |
| 109 | /// Control flow will not allow this value to be observed. | 112 | /// Control flow will not allow this value to be observed. |
| 110 | unreach, | 113 | unreach, |
| ... | @@ -113,28 +116,56 @@ const MCValue = union(enum) { | ... | @@ -113,28 +116,56 @@ const MCValue = union(enum) { |
| 113 | /// The value is undefined. | 116 | /// The value is undefined. |
| 114 | undef, | 117 | undef, |
| 115 | /// A pointer-sized integer that fits in a register. | 118 | /// A pointer-sized integer that fits in a register. |
| 116 | /// If the type is a pointer, this is the pointer address in virtual address space. | 119 | /// |
| | 120 | /// If the type is a pointer, this is the pointer address in |
| | 121 | /// virtual address space. |
| 117 | immediate: u64, | 122 | immediate: u64, |
| 118 | /// The value is in a target-specific register. | 123 | /// The value is in a target-specific register. |
| 119 | register: Register, | 124 | register: Register, |
| | 125 | /// The value is a tuple { wrapped: u32, overflow: u1 } where |
| | 126 | /// wrapped is stored in the register and the overflow bit is |
| | 127 | /// stored in the C flag of the CPSR. |
| | 128 | /// |
| | 129 | /// This MCValue is only generated by a add_with_overflow or |
| | 130 | /// sub_with_overflow instruction operating on u32. |
| | 131 | register_c_flag: Register, |
| | 132 | /// The value is a tuple { wrapped: i32, overflow: u1 } where |
| | 133 | /// wrapped is stored in the register and the overflow bit is |
| | 134 | /// stored in the V flag of the CPSR. |
| | 135 | /// |
| | 136 | /// This MCValue is only generated by a add_with_overflow or |
| | 137 | /// sub_with_overflow instruction operating on i32. |
| | 138 | register_v_flag: Register, |
| 120 | /// The value is in memory at a hard-coded address. | 139 | /// The value is in memory at a hard-coded address. |
| 121 | /// If the type is a pointer, it means the pointer address is at this memory location. | 140 | /// |
| | 141 | /// If the type is a pointer, it means the pointer address is at |
| | 142 | /// this memory location. |
| 122 | memory: u64, | 143 | memory: u64, |
| 123 | /// The value is in memory referenced indirectly via a GOT entry index. | 144 | /// The value is in memory referenced indirectly via a GOT entry |
| 124 | /// If the type is a pointer, it means the pointer is referenced indirectly via GOT. | 145 | /// index. |
| 125 | /// When lowered, linker will emit relocations of type ARM64_RELOC_GOT_LOAD_PAGE21 and ARM64_RELOC_GOT_LOAD_PAGEOFF12. | 146 | /// |
| | 147 | /// If the type is a pointer, it means the pointer is referenced |
| | 148 | /// indirectly via GOT. When lowered, linker will emit |
| | 149 | /// relocations of type ARM64_RELOC_GOT_LOAD_PAGE21 and |
| | 150 | /// ARM64_RELOC_GOT_LOAD_PAGEOFF12. |
| 126 | got_load: u32, | 151 | got_load: u32, |
| 127 | /// The value is in memory referenced directly via symbol index. | 152 | /// The value is in memory referenced directly via symbol index. |
| 128 | /// If the type is a pointer, it means the pointer is referenced directly via symbol index. | 153 | /// |
| 129 | /// When lowered, linker will emit a relocation of type ARM64_RELOC_PAGE21 and ARM64_RELOC_PAGEOFF12. | 154 | /// If the type is a pointer, it means the pointer is referenced |
| | 155 | /// directly via symbol index. When lowered, linker will emit a |
| | 156 | /// relocation of type ARM64_RELOC_PAGE21 and |
| | 157 | /// ARM64_RELOC_PAGEOFF12. |
| 130 | direct_load: u32, | 158 | direct_load: u32, |
| 131 | /// The value is one of the stack variables. | 159 | /// The value is one of the stack variables. |
| 132 | /// If the type is a pointer, it means the pointer address is in the stack at this offset. | 160 | /// |
| | 161 | /// If the type is a pointer, it means the pointer address is in |
| | 162 | /// the stack at this offset. |
| 133 | stack_offset: u32, | 163 | stack_offset: u32, |
| 134 | /// The value is a pointer to one of the stack variables (payload is stack offset). | 164 | /// The value is a pointer to one of the stack variables (payload |
| | 165 | /// is stack offset). |
| 135 | ptr_stack_offset: u32, | 166 | ptr_stack_offset: u32, |
| 136 | /// The value is in the compare flags assuming an unsigned operation, | 167 | /// The value is in the compare flags assuming an unsigned |
| 137 | /// with this operator applied on top of it. | 168 | /// operation, with this operator applied on top of it. |
| 138 | compare_flags_unsigned: math.CompareOperator, | 169 | compare_flags_unsigned: math.CompareOperator, |
| 139 | /// The value is in the compare flags assuming a signed operation, | 170 | /// The value is in the compare flags assuming a signed operation, |
| 140 | /// with this operator applied on top of it. | 171 | /// with this operator applied on top of it. |
| ... | @@ -716,8 +747,13 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void { | ... | @@ -716,8 +747,13 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void { |
| 716 | branch.inst_table.putAssumeCapacity(inst, .dead); | 747 | branch.inst_table.putAssumeCapacity(inst, .dead); |
| 717 | switch (prev_value) { | 748 | switch (prev_value) { |
| 718 | .register => |reg| { | 749 | .register => |reg| { |
| 719 | const canon_reg = toCanonicalReg(reg); | 750 | self.register_manager.freeReg(reg); |
| 720 | self.register_manager.freeReg(canon_reg); | 751 | }, |
| | 752 | .register_c_flag, |
| | 753 | .register_v_flag, |
| | 754 | => |reg| { |
| | 755 | self.register_manager.freeReg(reg); |
| | 756 | self.compare_flags_inst = null; |
| 721 | }, | 757 | }, |
| 722 | .compare_flags_signed, .compare_flags_unsigned => { | 758 | .compare_flags_signed, .compare_flags_unsigned => { |
| 723 | self.compare_flags_inst = null; | 759 | self.compare_flags_inst = null; |
| ... | @@ -857,7 +893,13 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void | ... | @@ -857,7 +893,13 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void |
| 857 | const stack_mcv = try self.allocRegOrMem(inst, false); | 893 | const stack_mcv = try self.allocRegOrMem(inst, false); |
| 858 | log.debug("spilling {d} to stack mcv {any}", .{ inst, stack_mcv }); | 894 | log.debug("spilling {d} to stack mcv {any}", .{ inst, stack_mcv }); |
| 859 | const reg_mcv = self.getResolvedInstValue(inst); | 895 | const reg_mcv = self.getResolvedInstValue(inst); |
| 860 | assert(reg == toCanonicalReg(reg_mcv.register)); | 896 | switch (reg_mcv) { |
| | 897 | .register, |
| | 898 | .register_c_flag, |
| | 899 | .register_v_flag, |
| | 900 | => |r| assert(reg.id() == r.id()), |
| | 901 | else => unreachable, // not a register |
| | 902 | } |
| 861 | 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]; |
| 862 | try branch.inst_table.put(self.gpa, inst, stack_mcv); | 904 | try branch.inst_table.put(self.gpa, inst, stack_mcv); |
| 863 | try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv); | 905 | try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv); |
| ... | @@ -868,7 +910,14 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void | ... | @@ -868,7 +910,14 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void |
| 868 | fn spillCompareFlagsIfOccupied(self: *Self) !void { | 910 | fn spillCompareFlagsIfOccupied(self: *Self) !void { |
| 869 | if (self.compare_flags_inst) |inst_to_save| { | 911 | if (self.compare_flags_inst) |inst_to_save| { |
| 870 | const mcv = self.getResolvedInstValue(inst_to_save); | 912 | const mcv = self.getResolvedInstValue(inst_to_save); |
| 871 | assert(mcv == .compare_flags_signed or mcv == .compare_flags_unsigned); | 913 | switch (mcv) { |
| | 914 | .compare_flags_signed, |
| | 915 | .compare_flags_unsigned, |
| | 916 | .register_c_flag, |
| | 917 | .register_v_flag, |
| | 918 | => {}, |
| | 919 | else => unreachable, // mcv doesn't occupy the compare flags |
| | 920 | } |
| 872 | | 921 | |
| 873 | const new_mcv = try self.allocRegOrMem(inst_to_save, true); | 922 | const new_mcv = try self.allocRegOrMem(inst_to_save, true); |
| 874 | try self.setRegOrMem(self.air.typeOfIndex(inst_to_save), new_mcv, mcv); | 923 | try self.setRegOrMem(self.air.typeOfIndex(inst_to_save), new_mcv, mcv); |
| ... | @@ -1269,7 +1318,9 @@ fn binOpRegister( | ... | @@ -1269,7 +1318,9 @@ fn binOpRegister( |
| 1269 | | 1318 | |
| 1270 | const mir_data: Mir.Inst.Data = switch (mir_tag) { | 1319 | const mir_data: Mir.Inst.Data = switch (mir_tag) { |
| 1271 | .add_shifted_register, | 1320 | .add_shifted_register, |
| | 1321 | .adds_shifted_register, |
| 1272 | .sub_shifted_register, | 1322 | .sub_shifted_register, |
| | 1323 | .subs_shifted_register, |
| 1273 | => .{ .rrr_imm6_shift = .{ | 1324 | => .{ .rrr_imm6_shift = .{ |
| 1274 | .rd = dest_reg, | 1325 | .rd = dest_reg, |
| 1275 | .rn = lhs_reg, | 1326 | .rn = lhs_reg, |
| ... | @@ -1384,7 +1435,9 @@ fn binOpImmediate( | ... | @@ -1384,7 +1435,9 @@ fn binOpImmediate( |
| 1384 | | 1435 | |
| 1385 | const mir_data: Mir.Inst.Data = switch (mir_tag) { | 1436 | const mir_data: Mir.Inst.Data = switch (mir_tag) { |
| 1386 | .add_immediate, | 1437 | .add_immediate, |
| | 1438 | .adds_immediate, |
| 1387 | .sub_immediate, | 1439 | .sub_immediate, |
| | 1440 | .subs_immediate, |
| 1388 | => .{ .rr_imm12_sh = .{ | 1441 | => .{ .rr_imm12_sh = .{ |
| 1389 | .rd = dest_reg, | 1442 | .rd = dest_reg, |
| 1390 | .rn = lhs_reg, | 1443 | .rn = lhs_reg, |
| ... | @@ -1774,7 +1827,52 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1774,7 +1827,52 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1774 | | 1827 | |
| 1775 | break :result MCValue{ .stack_offset = stack_offset }; | 1828 | break :result MCValue{ .stack_offset = stack_offset }; |
| 1776 | }, | 1829 | }, |
| 1777 | 32, 64 => return self.fail("TODO overflow operations on integers u32/i32 and u64/i64", .{}), | 1830 | 32, 64 => { |
| | 1831 | // Only say yes if the operation is |
| | 1832 | // commutative, i.e. we can swap both of the |
| | 1833 | // operands |
| | 1834 | const lhs_immediate_ok = switch (tag) { |
| | 1835 | .add_with_overflow => lhs == .immediate and lhs.immediate <= std.math.maxInt(u12), |
| | 1836 | .sub_with_overflow => false, |
| | 1837 | else => unreachable, |
| | 1838 | }; |
| | 1839 | const rhs_immediate_ok = switch (tag) { |
| | 1840 | .add_with_overflow, |
| | 1841 | .sub_with_overflow, |
| | 1842 | => rhs == .immediate and rhs.immediate <= std.math.maxInt(u12), |
| | 1843 | else => unreachable, |
| | 1844 | }; |
| | 1845 | |
| | 1846 | const mir_tag_register: Mir.Inst.Tag = switch (tag) { |
| | 1847 | .add_with_overflow => .adds_shifted_register, |
| | 1848 | .sub_with_overflow => .subs_shifted_register, |
| | 1849 | else => unreachable, |
| | 1850 | }; |
| | 1851 | const mir_tag_immediate: Mir.Inst.Tag = switch (tag) { |
| | 1852 | .add_with_overflow => .adds_immediate, |
| | 1853 | .sub_with_overflow => .subs_immediate, |
| | 1854 | else => unreachable, |
| | 1855 | }; |
| | 1856 | |
| | 1857 | try self.spillCompareFlagsIfOccupied(); |
| | 1858 | self.compare_flags_inst = inst; |
| | 1859 | |
| | 1860 | const dest = blk: { |
| | 1861 | if (rhs_immediate_ok) { |
| | 1862 | break :blk try self.binOpImmediate(mir_tag_immediate, null, lhs, rhs, lhs_ty, false); |
| | 1863 | } else if (lhs_immediate_ok) { |
| | 1864 | // swap lhs and rhs |
| | 1865 | break :blk try self.binOpImmediate(mir_tag_immediate, null, rhs, lhs, rhs_ty, true); |
| | 1866 | } else { |
| | 1867 | break :blk try self.binOpRegister(mir_tag_register, null, lhs, rhs, lhs_ty, rhs_ty); |
| | 1868 | } |
| | 1869 | }; |
| | 1870 | |
| | 1871 | switch (int_info.signedness) { |
| | 1872 | .unsigned => break :result MCValue{ .register_c_flag = dest.register }, |
| | 1873 | .signed => break :result MCValue{ .register_v_flag = dest.register }, |
| | 1874 | } |
| | 1875 | }, |
| 1778 | else => return self.fail("TODO overflow operations on integers > u32/i32", .{}), | 1876 | else => return self.fail("TODO overflow operations on integers > u32/i32", .{}), |
| 1779 | } | 1877 | } |
| 1780 | }, | 1878 | }, |
| ... | @@ -2148,8 +2246,11 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -2148,8 +2246,11 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 2148 | .undef => unreachable, | 2246 | .undef => unreachable, |
| 2149 | .unreach => unreachable, | 2247 | .unreach => unreachable, |
| 2150 | .dead => unreachable, | 2248 | .dead => unreachable, |
| 2151 | .compare_flags_unsigned => unreachable, | 2249 | .compare_flags_unsigned, |
| 2152 | .compare_flags_signed => unreachable, | 2250 | .compare_flags_signed, |
| | 2251 | .register_c_flag, |
| | 2252 | .register_v_flag, |
| | 2253 | => unreachable, // cannot hold an address |
| 2153 | .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }), | 2254 | .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }), |
| 2154 | .ptr_stack_offset => |off| try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }), | 2255 | .ptr_stack_offset => |off| try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }), |
| 2155 | .register => |addr_reg| { | 2256 | .register => |addr_reg| { |
| ... | @@ -2366,8 +2467,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -2366,8 +2467,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2366 | .undef => unreachable, | 2467 | .undef => unreachable, |
| 2367 | .unreach => unreachable, | 2468 | .unreach => unreachable, |
| 2368 | .dead => unreachable, | 2469 | .dead => unreachable, |
| 2369 | .compare_flags_unsigned => unreachable, | 2470 | .compare_flags_unsigned, |
| 2370 | .compare_flags_signed => unreachable, | 2471 | .compare_flags_signed, |
| | 2472 | .register_c_flag, |
| | 2473 | .register_v_flag, |
| | 2474 | => unreachable, // cannot hold an address |
| 2371 | .immediate => |imm| { | 2475 | .immediate => |imm| { |
| 2372 | try self.setRegOrMem(value_ty, .{ .memory = imm }, value); | 2476 | try self.setRegOrMem(value_ty, .{ .memory = imm }, value); |
| 2373 | }, | 2477 | }, |
| ... | @@ -2487,6 +2591,40 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2487,6 +2591,40 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2487 | .memory => |addr| { | 2591 | .memory => |addr| { |
| 2488 | break :result MCValue{ .memory = addr + struct_field_offset }; | 2592 | break :result MCValue{ .memory = addr + struct_field_offset }; |
| 2489 | }, | 2593 | }, |
| | 2594 | .register_c_flag, |
| | 2595 | .register_v_flag, |
| | 2596 | => |reg| { |
| | 2597 | switch (index) { |
| | 2598 | 0 => { |
| | 2599 | // get wrapped value: return register |
| | 2600 | break :result MCValue{ .register = reg }; |
| | 2601 | }, |
| | 2602 | 1 => { |
| | 2603 | // TODO return special MCValue condition flags |
| | 2604 | // get overflow bit: set register to C flag |
| | 2605 | // resp. V flag |
| | 2606 | const raw_dest_reg = try self.register_manager.allocReg(null); |
| | 2607 | const dest_reg = raw_dest_reg.to32(); |
| | 2608 | |
| | 2609 | // C flag: cset reg, cs |
| | 2610 | // V flag: cset reg, vs |
| | 2611 | _ = try self.addInst(.{ |
| | 2612 | .tag = .cset, |
| | 2613 | .data = .{ .r_cond = .{ |
| | 2614 | .rd = dest_reg, |
| | 2615 | .cond = switch (mcv) { |
| | 2616 | .register_c_flag => .cs, |
| | 2617 | .register_v_flag => .vs, |
| | 2618 | else => unreachable, |
| | 2619 | }, |
| | 2620 | } }, |
| | 2621 | }); |
| | 2622 | |
| | 2623 | break :result MCValue{ .register = dest_reg }; |
| | 2624 | }, |
| | 2625 | else => unreachable, |
| | 2626 | } |
| | 2627 | }, |
| 2490 | else => return self.fail("TODO implement codegen struct_field_val for {}", .{mcv}), | 2628 | else => return self.fail("TODO implement codegen struct_field_val for {}", .{mcv}), |
| 2491 | } | 2629 | } |
| 2492 | }; | 2630 | }; |
| ... | @@ -2531,7 +2669,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2531,7 +2669,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 2531 | | 2669 | |
| 2532 | switch (mcv) { | 2670 | switch (mcv) { |
| 2533 | .register => |reg| { | 2671 | .register => |reg| { |
| 2534 | self.register_manager.getRegAssumeFree(toCanonicalReg(reg), inst); | 2672 | self.register_manager.getRegAssumeFree(reg, inst); |
| 2535 | }, | 2673 | }, |
| 2536 | else => {}, | 2674 | else => {}, |
| 2537 | } | 2675 | } |
| ... | @@ -2596,15 +2734,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. | ... | @@ -2596,15 +2734,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 2596 | | 2734 | |
| 2597 | switch (mc_arg) { | 2735 | switch (mc_arg) { |
| 2598 | .none => continue, | 2736 | .none => continue, |
| 2599 | .undef => unreachable, | | |
| 2600 | .immediate => unreachable, | | |
| 2601 | .unreach => unreachable, | | |
| 2602 | .dead => unreachable, | | |
| 2603 | .memory => unreachable, | | |
| 2604 | .compare_flags_signed => unreachable, | | |
| 2605 | .compare_flags_unsigned => unreachable, | | |
| 2606 | .got_load => unreachable, | | |
| 2607 | .direct_load => unreachable, | | |
| 2608 | .register => |reg| { | 2737 | .register => |reg| { |
| 2609 | try self.register_manager.getReg(reg, null); | 2738 | try self.register_manager.getReg(reg, null); |
| 2610 | try self.genSetReg(arg_ty, reg, arg_mcv); | 2739 | try self.genSetReg(arg_ty, reg, arg_mcv); |
| ... | @@ -2615,6 +2744,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. | ... | @@ -2615,6 +2744,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 2615 | .ptr_stack_offset => { | 2744 | .ptr_stack_offset => { |
| 2616 | return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{}); | 2745 | return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{}); |
| 2617 | }, | 2746 | }, |
| | 2747 | else => unreachable, |
| 2618 | } | 2748 | } |
| 2619 | } | 2749 | } |
| 2620 | | 2750 | |
| ... | @@ -3518,6 +3648,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -3518,6 +3648,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 3518 | else => return self.fail("TODO implement storing other types abi_size={}", .{abi_size}), | 3648 | else => return self.fail("TODO implement storing other types abi_size={}", .{abi_size}), |
| 3519 | } | 3649 | } |
| 3520 | }, | 3650 | }, |
| | 3651 | .register_c_flag, |
| | 3652 | .register_v_flag, |
| | 3653 | => { |
| | 3654 | return self.fail("TODO implement genSetStack {}", .{mcv}); |
| | 3655 | }, |
| 3521 | .got_load, | 3656 | .got_load, |
| 3522 | .direct_load, | 3657 | .direct_load, |
| 3523 | .memory, | 3658 | .memory, |
| ... | @@ -3635,7 +3770,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -3635,7 +3770,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 3635 | .tag = .cset, | 3770 | .tag = .cset, |
| 3636 | .data = .{ .r_cond = .{ | 3771 | .data = .{ .r_cond = .{ |
| 3637 | .rd = reg, | 3772 | .rd = reg, |
| 3638 | .cond = condition.negate(), | 3773 | .cond = condition, |
| 3639 | } }, | 3774 | } }, |
| 3640 | }); | 3775 | }); |
| 3641 | }, | 3776 | }, |
| ... | @@ -3678,6 +3813,9 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -3678,6 +3813,9 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 3678 | .data = .{ .rr = .{ .rd = reg, .rn = src_reg } }, | 3813 | .data = .{ .rr = .{ .rd = reg, .rn = src_reg } }, |
| 3679 | }); | 3814 | }); |
| 3680 | }, | 3815 | }, |
| | 3816 | .register_c_flag, |
| | 3817 | .register_v_flag, |
| | 3818 | => unreachable, // doesn't fit into a register |
| 3681 | .got_load, | 3819 | .got_load, |
| 3682 | .direct_load, | 3820 | .direct_load, |
| 3683 | => |sym_index| { | 3821 | => |sym_index| { |
| ... | @@ -4279,8 +4417,3 @@ fn registerAlias(reg: Register, size_bytes: u64) Register { | ... | @@ -4279,8 +4417,3 @@ fn registerAlias(reg: Register, size_bytes: u64) Register { |
| 4279 | unreachable; // TODO handle floating-point registers | 4417 | unreachable; // TODO handle floating-point registers |
| 4280 | } | 4418 | } |
| 4281 | } | 4419 | } |
| 4282 | | | |
| 4283 | /// Resolves any aliased registers to the 64-bit wide ones. | | |
| 4284 | fn toCanonicalReg(reg: Register) Register { | | |
| 4285 | return reg.to64(); | | |
| 4286 | } | | |