authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-04-25 21:04:39+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-05 21:43:35+02:00
logf267e7a8b45d343eb1c3cf5f0662746912af8c99
tree406157432c21e05edeca95b40a651feeb0334f3b
parentc2d2307d09017e97a9e9ce59d29754ff2becdd54

stage2 AArch64: implement {add,sub}_with_overflow for all ints < 64


3 files changed, 193 insertions(+), 40 deletions(-)

src/arch/aarch64/CodeGen.zig+172-39
...@@ -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,
102const air_bookkeeping_init = if (std.debug.runtime_safety) @as(usize, 0) else {};102const air_bookkeeping_init = if (std.debug.runtime_safety) @as(usize, 0) else {};
103103
104const MCValue = union(enum) {104const 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 use106 /// 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
868fn spillCompareFlagsIfOccupied(self: *Self) !void {910fn 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 }
872921
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(
12691318
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(
13841435
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 {
17741827
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 {
25312669
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.
25962734
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 }
26202750
...@@ -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 registers4417 unreachable; // TODO handle floating-point registers
4280 }4418 }
4281}4419}
4282
4283/// Resolves any aliased registers to the 64-bit wide ones.
4284fn toCanonicalReg(reg: Register) Register {
4285 return reg.to64();
4286}
src/arch/aarch64/Emit.zig+13-1
...@@ -77,8 +77,10 @@ pub fn emitMir(...@@ -77,8 +77,10 @@ pub fn emitMir(
77 const inst = @intCast(u32, index);77 const inst = @intCast(u32, index);
78 switch (tag) {78 switch (tag) {
79 .add_immediate => try emit.mirAddSubtractImmediate(inst),79 .add_immediate => try emit.mirAddSubtractImmediate(inst),
80 .adds_immediate => try emit.mirAddSubtractImmediate(inst),
80 .cmp_immediate => try emit.mirAddSubtractImmediate(inst),81 .cmp_immediate => try emit.mirAddSubtractImmediate(inst),
81 .sub_immediate => try emit.mirAddSubtractImmediate(inst),82 .sub_immediate => try emit.mirAddSubtractImmediate(inst),
83 .subs_immediate => try emit.mirAddSubtractImmediate(inst),
8284
83 .asr_register => try emit.mirShiftRegister(inst),85 .asr_register => try emit.mirShiftRegister(inst),
84 .lsl_register => try emit.mirShiftRegister(inst),86 .lsl_register => try emit.mirShiftRegister(inst),
...@@ -106,8 +108,10 @@ pub fn emitMir(...@@ -106,8 +108,10 @@ pub fn emitMir(
106 .eor_immediate => try emit.mirLogicalImmediate(inst),108 .eor_immediate => try emit.mirLogicalImmediate(inst),
107109
108 .add_shifted_register => try emit.mirAddSubtractShiftedRegister(inst),110 .add_shifted_register => try emit.mirAddSubtractShiftedRegister(inst),
111 .adds_shifted_register => try emit.mirAddSubtractShiftedRegister(inst),
109 .cmp_shifted_register => try emit.mirAddSubtractShiftedRegister(inst),112 .cmp_shifted_register => try emit.mirAddSubtractShiftedRegister(inst),
110 .sub_shifted_register => try emit.mirAddSubtractShiftedRegister(inst),113 .sub_shifted_register => try emit.mirAddSubtractShiftedRegister(inst),
114 .subs_shifted_register => try emit.mirAddSubtractShiftedRegister(inst),
111115
112 .cset => try emit.mirConditionalSelect(inst),116 .cset => try emit.mirConditionalSelect(inst),
113117
...@@ -454,7 +458,9 @@ fn mirAddSubtractImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -454,7 +458,9 @@ fn mirAddSubtractImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {
454 const tag = emit.mir.instructions.items(.tag)[inst];458 const tag = emit.mir.instructions.items(.tag)[inst];
455 switch (tag) {459 switch (tag) {
456 .add_immediate,460 .add_immediate,
461 .adds_immediate,
457 .sub_immediate,462 .sub_immediate,
463 .subs_immediate,
458 => {464 => {
459 const rr_imm12_sh = emit.mir.instructions.items(.data)[inst].rr_imm12_sh;465 const rr_imm12_sh = emit.mir.instructions.items(.data)[inst].rr_imm12_sh;
460 const rd = rr_imm12_sh.rd;466 const rd = rr_imm12_sh.rd;
...@@ -464,7 +470,9 @@ fn mirAddSubtractImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -464,7 +470,9 @@ fn mirAddSubtractImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {
464470
465 switch (tag) {471 switch (tag) {
466 .add_immediate => try emit.writeInstruction(Instruction.add(rd, rn, imm12, sh)),472 .add_immediate => try emit.writeInstruction(Instruction.add(rd, rn, imm12, sh)),
473 .adds_immediate => try emit.writeInstruction(Instruction.adds(rd, rn, imm12, sh)),
467 .sub_immediate => try emit.writeInstruction(Instruction.sub(rd, rn, imm12, sh)),474 .sub_immediate => try emit.writeInstruction(Instruction.sub(rd, rn, imm12, sh)),
475 .subs_immediate => try emit.writeInstruction(Instruction.subs(rd, rn, imm12, sh)),
468 else => unreachable,476 else => unreachable,
469 }477 }
470 },478 },
...@@ -674,7 +682,9 @@ fn mirAddSubtractShiftedRegister(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -674,7 +682,9 @@ fn mirAddSubtractShiftedRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
674 const tag = emit.mir.instructions.items(.tag)[inst];682 const tag = emit.mir.instructions.items(.tag)[inst];
675 switch (tag) {683 switch (tag) {
676 .add_shifted_register,684 .add_shifted_register,
685 .adds_shifted_register,
677 .sub_shifted_register,686 .sub_shifted_register,
687 .subs_shifted_register,
678 => {688 => {
679 const rrr_imm6_shift = emit.mir.instructions.items(.data)[inst].rrr_imm6_shift;689 const rrr_imm6_shift = emit.mir.instructions.items(.data)[inst].rrr_imm6_shift;
680 const rd = rrr_imm6_shift.rd;690 const rd = rrr_imm6_shift.rd;
...@@ -685,7 +695,9 @@ fn mirAddSubtractShiftedRegister(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -685,7 +695,9 @@ fn mirAddSubtractShiftedRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
685695
686 switch (tag) {696 switch (tag) {
687 .add_shifted_register => try emit.writeInstruction(Instruction.addShiftedRegister(rd, rn, rm, shift, imm6)),697 .add_shifted_register => try emit.writeInstruction(Instruction.addShiftedRegister(rd, rn, rm, shift, imm6)),
698 .adds_shifted_register => try emit.writeInstruction(Instruction.addsShiftedRegister(rd, rn, rm, shift, imm6)),
688 .sub_shifted_register => try emit.writeInstruction(Instruction.subShiftedRegister(rd, rn, rm, shift, imm6)),699 .sub_shifted_register => try emit.writeInstruction(Instruction.subShiftedRegister(rd, rn, rm, shift, imm6)),
700 .subs_shifted_register => try emit.writeInstruction(Instruction.subsShiftedRegister(rd, rn, rm, shift, imm6)),
689 else => unreachable,701 else => unreachable,
690 }702 }
691 },703 },
...@@ -717,7 +729,7 @@ fn mirConditionalSelect(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -717,7 +729,7 @@ fn mirConditionalSelect(emit: *Emit, inst: Mir.Inst.Index) !void {
717 64 => .xzr,729 64 => .xzr,
718 else => unreachable,730 else => unreachable,
719 };731 };
720 try emit.writeInstruction(Instruction.csinc(r_cond.rd, zr, zr, r_cond.cond));732 try emit.writeInstruction(Instruction.csinc(r_cond.rd, zr, zr, r_cond.cond.negate()));
721 },733 },
722 else => unreachable,734 else => unreachable,
723 }735 }
src/arch/aarch64/Mir.zig+8
...@@ -26,8 +26,12 @@ pub const Inst = struct {...@@ -26,8 +26,12 @@ pub const Inst = struct {
26 pub const Tag = enum(u16) {26 pub const Tag = enum(u16) {
27 /// Add (immediate)27 /// Add (immediate)
28 add_immediate,28 add_immediate,
29 /// Add, update condition flags (immediate)
30 adds_immediate,
29 /// Add (shifted register)31 /// Add (shifted register)
30 add_shifted_register,32 add_shifted_register,
33 /// Add, update condition flags (shifted register)
34 adds_shifted_register,
31 /// Bitwise AND (shifted register)35 /// Bitwise AND (shifted register)
32 and_shifted_register,36 and_shifted_register,
33 /// Arithmetic Shift Right (immediate)37 /// Arithmetic Shift Right (immediate)
...@@ -170,8 +174,12 @@ pub const Inst = struct {...@@ -170,8 +174,12 @@ pub const Inst = struct {
170 strh_register,174 strh_register,
171 /// Subtract (immediate)175 /// Subtract (immediate)
172 sub_immediate,176 sub_immediate,
177 /// Subtract, update condition flags (immediate)
178 subs_immediate,
173 /// Subtract (shifted register)179 /// Subtract (shifted register)
174 sub_shifted_register,180 sub_shifted_register,
181 /// Subtract, update condition flags (shifted register)
182 subs_shifted_register,
175 /// Supervisor Call183 /// Supervisor Call
176 svc,184 svc,
177 /// Unsigned bitfield extract185 /// Unsigned bitfield extract