authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-03-27 21:30:16+02:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-04-01 22:02:55+02:00
log7285f0557cbc26893a7a64f345432ad01981180c
tree0a91ec54a79841c02074b21b0be0c9fad7f66e26
parente2e69803dc16efe11a6d42c6c49853e16a41fd0c
signaturelock-open Commit is signed but in an unrecognized format.

stage2 ARM: implement add/sub_with_overflow for u32/i32


3 files changed, 202 insertions(+), 34 deletions(-)

src/arch/arm/CodeGen.zig+194-34
...@@ -105,9 +105,12 @@ air_bookkeeping: @TypeOf(air_bookkeeping_init) = air_bookkeeping_init,...@@ -105,9 +105,12 @@ air_bookkeeping: @TypeOf(air_bookkeeping_init) = air_bookkeeping_init,
105const air_bookkeeping_init = if (std.debug.runtime_safety) @as(usize, 0) else {};105const air_bookkeeping_init = if (std.debug.runtime_safety) @as(usize, 0) else {};
106106
107const MCValue = union(enum) {107const MCValue = union(enum) {
108 /// No runtime bits. `void` types, empty structs, u0, enums with 1 tag, etc.108 /// No runtime bits. `void` types, empty structs, u0, enums with 1
109 /// TODO Look into deleting this tag and using `dead` instead, since every use109 /// tag, etc.
110 /// of MCValue.none should be instead looking at the type and noticing it is 0 bits.110 ///
111 /// TODO Look into deleting this tag and using `dead` instead,
112 /// since every use of MCValue.none should be instead looking at
113 /// the type and noticing it is 0 bits.
111 none,114 none,
112 /// Control flow will not allow this value to be observed.115 /// Control flow will not allow this value to be observed.
113 unreach,116 unreach,
...@@ -116,20 +119,41 @@ const MCValue = union(enum) {...@@ -116,20 +119,41 @@ const MCValue = union(enum) {
116 /// The value is undefined.119 /// The value is undefined.
117 undef,120 undef,
118 /// A pointer-sized integer that fits in a register.121 /// A pointer-sized integer that fits in a register.
119 /// If the type is a pointer, this is the pointer address in virtual address space.122 ///
123 /// If the type is a pointer, this is the pointer address in
124 /// virtual address space.
120 immediate: u32,125 immediate: u32,
121 /// The value is in a target-specific register.126 /// The value is in a target-specific register.
122 register: Register,127 register: Register,
128 /// The value is a tuple { wrapped: u32, overflow: u1 } where
129 /// wrapped is stored in the register and the overflow bit is
130 /// stored in the C flag of the CPSR.
131 ///
132 /// This MCValue is only generated by a add_with_overflow or
133 /// sub_with_overflow instruction operating on u32.
134 register_c_flag: Register,
135 /// The value is a tuple { wrapped: i32, overflow: u1 } where
136 /// wrapped is stored in the register and the overflow bit is
137 /// stored in the V flag of the CPSR.
138 ///
139 /// This MCValue is only generated by a add_with_overflow or
140 /// sub_with_overflow instruction operating on i32.
141 register_v_flag: Register,
123 /// The value is in memory at a hard-coded address.142 /// The value is in memory at a hard-coded address.
124 /// If the type is a pointer, it means the pointer address is at this memory location.143 ///
144 /// If the type is a pointer, it means the pointer address is at
145 /// this memory location.
125 memory: u64,146 memory: u64,
126 /// The value is one of the stack variables.147 /// The value is one of the stack variables.
127 /// If the type is a pointer, it means the pointer address is in the stack at this offset.148 ///
149 /// If the type is a pointer, it means the pointer address is in
150 /// the stack at this offset.
128 stack_offset: u32,151 stack_offset: u32,
129 /// The value is a pointer to one of the stack variables (payload is stack offset).152 /// The value is a pointer to one of the stack variables (payload
153 /// is stack offset).
130 ptr_stack_offset: u32,154 ptr_stack_offset: u32,
131 /// The value is in the compare flags assuming an unsigned operation,155 /// The value is in the compare flags assuming an unsigned
132 /// with this operator applied on top of it.156 /// operation, with this operator applied on top of it.
133 compare_flags_unsigned: math.CompareOperator,157 compare_flags_unsigned: math.CompareOperator,
134 /// The value is in the compare flags assuming a signed operation,158 /// The value is in the compare flags assuming a signed operation,
135 /// with this operator applied on top of it.159 /// with this operator applied on top of it.
...@@ -554,8 +578,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -554,8 +578,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
554 .trunc_float,578 .trunc_float,
555 => try self.airUnaryMath(inst),579 => try self.airUnaryMath(inst),
556580
557 .add_with_overflow => try self.airAddWithOverflow(inst),581 .add_with_overflow => try self.airOverflow(inst),
558 .sub_with_overflow => try self.airSubWithOverflow(inst),582 .sub_with_overflow => try self.airOverflow(inst),
559 .mul_with_overflow => try self.airMulWithOverflow(inst),583 .mul_with_overflow => try self.airMulWithOverflow(inst),
560 .shl_with_overflow => try self.airShlWithOverflow(inst),584 .shl_with_overflow => try self.airShlWithOverflow(inst),
561585
...@@ -726,6 +750,12 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void {...@@ -726,6 +750,12 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void {
726 .register => |reg| {750 .register => |reg| {
727 self.register_manager.freeReg(reg);751 self.register_manager.freeReg(reg);
728 },752 },
753 .register_c_flag,
754 .register_v_flag,
755 => |reg| {
756 self.register_manager.freeReg(reg);
757 self.compare_flags_inst = null;
758 },
729 .compare_flags_signed, .compare_flags_unsigned => {759 .compare_flags_signed, .compare_flags_unsigned => {
730 self.compare_flags_inst = null;760 self.compare_flags_inst = null;
731 },761 },
...@@ -841,8 +871,16 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {...@@ -841,8 +871,16 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
841pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void {871pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void {
842 const stack_mcv = try self.allocRegOrMem(inst, false);872 const stack_mcv = try self.allocRegOrMem(inst, false);
843 log.debug("spilling {} (%{d}) to stack mcv {any}", .{ reg, inst, stack_mcv });873 log.debug("spilling {} (%{d}) to stack mcv {any}", .{ reg, inst, stack_mcv });
874
844 const reg_mcv = self.getResolvedInstValue(inst);875 const reg_mcv = self.getResolvedInstValue(inst);
845 assert(reg == reg_mcv.register);876 switch (reg_mcv) {
877 .register,
878 .register_c_flag,
879 .register_v_flag,
880 => |r| assert(r == reg),
881 else => unreachable, // not a register
882 }
883
846 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];884 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
847 try branch.inst_table.put(self.gpa, inst, stack_mcv);885 try branch.inst_table.put(self.gpa, inst, stack_mcv);
848 try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv);886 try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv);
...@@ -853,7 +891,14 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void...@@ -853,7 +891,14 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
853fn spillCompareFlagsIfOccupied(self: *Self) !void {891fn spillCompareFlagsIfOccupied(self: *Self) !void {
854 if (self.compare_flags_inst) |inst_to_save| {892 if (self.compare_flags_inst) |inst_to_save| {
855 const mcv = self.getResolvedInstValue(inst_to_save);893 const mcv = self.getResolvedInstValue(inst_to_save);
856 assert(mcv == .compare_flags_signed or mcv == .compare_flags_unsigned);894 switch (mcv) {
895 .compare_flags_signed,
896 .compare_flags_unsigned,
897 .register_c_flag,
898 .register_v_flag,
899 => {},
900 else => unreachable, // mcv doesn't occupy the compare flags
901 }
857902
858 const new_mcv = try self.allocRegOrMem(inst_to_save, true);903 const new_mcv = try self.allocRegOrMem(inst_to_save, true);
859 try self.setRegOrMem(self.air.typeOfIndex(inst_to_save), new_mcv, mcv);904 try self.setRegOrMem(self.air.typeOfIndex(inst_to_save), new_mcv, mcv);
...@@ -1268,7 +1313,7 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -1268,7 +1313,7 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
1268 const len = try self.resolveInst(bin_op.rhs);1313 const len = try self.resolveInst(bin_op.rhs);
1269 const len_ty = self.air.typeOf(bin_op.rhs);1314 const len_ty = self.air.typeOf(bin_op.rhs);
12701315
1271 const stack_offset = try self.allocMem(inst, 8, 8);1316 const stack_offset = try self.allocMem(inst, 8, 4);
1272 try self.genSetStack(ptr_ty, stack_offset, ptr);1317 try self.genSetStack(ptr_ty, stack_offset, ptr);
1273 try self.genSetStack(len_ty, stack_offset - 4, len);1318 try self.genSetStack(len_ty, stack_offset - 4, len);
1274 break :result MCValue{ .stack_offset = stack_offset };1319 break :result MCValue{ .stack_offset = stack_offset };
...@@ -1306,14 +1351,71 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -1306,14 +1351,71 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
1306 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1351 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1307}1352}
13081353
1309fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {1354fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
1310 _ = inst;1355 const tag = self.air.instructions.items(.tag)[inst];
1311 return self.fail("TODO implement airAddWithOverflow for {}", .{self.target.cpu.arch});1356 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1312}1357 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
1358 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1359 const lhs = try self.resolveInst(extra.lhs);
1360 const rhs = try self.resolveInst(extra.rhs);
1361 const lhs_ty = self.air.typeOf(extra.lhs);
1362 const rhs_ty = self.air.typeOf(extra.rhs);
1363
1364 switch (lhs_ty.zigTypeTag()) {
1365 .Vector => return self.fail("TODO implement add_with_overflow/sub_with_overflow for vectors", .{}),
1366 .Int => {
1367 assert(lhs_ty.eql(rhs_ty, self.target.*));
1368 const int_info = lhs_ty.intInfo(self.target.*);
1369 if (int_info.bits < 32) {
1370 return self.fail("TODO ARM overflow operations on integers < u32/i32", .{});
1371 } else if (int_info.bits == 32) {
1372 // Only say yes if the operation is
1373 // commutative, i.e. we can swap both of the
1374 // operands
1375 const lhs_immediate_ok = switch (tag) {
1376 .add_with_overflow => lhs == .immediate and Instruction.Operand.fromU32(lhs.immediate) != null,
1377 .sub_with_overflow => false,
1378 else => unreachable,
1379 };
1380 const rhs_immediate_ok = switch (tag) {
1381 .add_with_overflow,
1382 .sub_with_overflow,
1383 => rhs == .immediate and Instruction.Operand.fromU32(rhs.immediate) != null,
1384 else => unreachable,
1385 };
13131386
1314fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {1387 const mir_tag: Mir.Inst.Tag = switch (tag) {
1315 _ = inst;1388 .add_with_overflow => .adds,
1316 return self.fail("TODO implement airSubWithOverflow for {}", .{self.target.cpu.arch});1389 .sub_with_overflow => .subs,
1390 else => unreachable,
1391 };
1392
1393 try self.spillCompareFlagsIfOccupied();
1394 self.compare_flags_inst = inst;
1395
1396 const dest = blk: {
1397 if (rhs_immediate_ok) {
1398 break :blk try self.binOpImmediate(mir_tag, null, lhs, rhs, lhs_ty, false);
1399 } else if (lhs_immediate_ok) {
1400 // swap lhs and rhs
1401 break :blk try self.binOpImmediate(mir_tag, null, rhs, lhs, rhs_ty, true);
1402 } else {
1403 break :blk try self.binOpRegister(mir_tag, null, lhs, rhs, lhs_ty, rhs_ty);
1404 }
1405 };
1406
1407 switch (int_info.signedness) {
1408 .unsigned => break :result MCValue{ .register_c_flag = dest.register },
1409 .signed => break :result MCValue{ .register_v_flag = dest.register },
1410 }
1411 } else {
1412 return self.fail("TODO ARM overflow operations on integers > u32/i32", .{});
1413 }
1414 },
1415 else => unreachable,
1416 }
1417 };
1418 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
1317}1419}
13181420
1319fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {1421fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
...@@ -1424,7 +1526,6 @@ fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type)...@@ -1424,7 +1526,6 @@ fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type)
1424 const eu_align = @intCast(u32, error_union_ty.abiAlignment(self.target.*));1526 const eu_align = @intCast(u32, error_union_ty.abiAlignment(self.target.*));
1425 const offset = std.mem.alignForwardGeneric(u32, error_size, eu_align);1527 const offset = std.mem.alignForwardGeneric(u32, error_size, eu_align);
14261528
1427 // TODO optimization for small error unions: put into register
1428 switch (error_union_mcv) {1529 switch (error_union_mcv) {
1429 .register => return self.fail("TODO errUnionPayload for registers", .{}),1530 .register => return self.fail("TODO errUnionPayload for registers", .{}),
1430 .stack_argument_offset => |off| {1531 .stack_argument_offset => |off| {
...@@ -1791,8 +1892,11 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -1791,8 +1892,11 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
1791 .undef => unreachable,1892 .undef => unreachable,
1792 .unreach => unreachable,1893 .unreach => unreachable,
1793 .dead => unreachable,1894 .dead => unreachable,
1794 .compare_flags_unsigned => unreachable,1895 .compare_flags_unsigned,
1795 .compare_flags_signed => unreachable,1896 .compare_flags_signed,
1897 .register_c_flag,
1898 .register_v_flag,
1899 => unreachable, // cannot hold an address
1796 .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }),1900 .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }),
1797 .ptr_stack_offset => |off| try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }),1901 .ptr_stack_offset => |off| try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }),
1798 .register => |reg| {1902 .register => |reg| {
...@@ -1887,8 +1991,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -1887,8 +1991,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
1887 .undef => unreachable,1991 .undef => unreachable,
1888 .unreach => unreachable,1992 .unreach => unreachable,
1889 .dead => unreachable,1993 .dead => unreachable,
1890 .compare_flags_unsigned => unreachable,1994 .compare_flags_unsigned,
1891 .compare_flags_signed => unreachable,1995 .compare_flags_signed,
1996 .register_c_flag,
1997 .register_v_flag,
1998 => unreachable, // cannot hold an address
1892 .immediate => |imm| {1999 .immediate => |imm| {
1893 try self.setRegOrMem(value_ty, .{ .memory = imm }, value);2000 try self.setRegOrMem(value_ty, .{ .memory = imm }, value);
1894 },2001 },
...@@ -2043,6 +2150,50 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2043,6 +2150,50 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
2043 .memory => |addr| {2150 .memory => |addr| {
2044 break :result MCValue{ .memory = addr + struct_field_offset };2151 break :result MCValue{ .memory = addr + struct_field_offset };
2045 },2152 },
2153 .register_c_flag,
2154 .register_v_flag,
2155 => |reg| {
2156 switch (index) {
2157 0 => {
2158 // get wrapped value: return register
2159 break :result MCValue{ .register = reg };
2160 },
2161 1 => {
2162 // get overflow bit: set register to C flag
2163 // resp. V flag
2164 const dest_reg = try self.register_manager.allocReg(null);
2165
2166 // mov reg, #0
2167 _ = try self.addInst(.{
2168 .tag = .mov,
2169 .data = .{ .rr_op = .{
2170 .rd = dest_reg,
2171 .rn = .r0,
2172 .op = Instruction.Operand.fromU32(0).?,
2173 } },
2174 });
2175
2176 // C flag: movcs reg, #1
2177 // V flag: movvs reg, #1
2178 _ = try self.addInst(.{
2179 .tag = .mov,
2180 .cond = switch (mcv) {
2181 .register_c_flag => .cs,
2182 .register_v_flag => .vs,
2183 else => unreachable,
2184 },
2185 .data = .{ .rr_op = .{
2186 .rd = dest_reg,
2187 .rn = .r0,
2188 .op = Instruction.Operand.fromU32(1).?,
2189 } },
2190 });
2191
2192 break :result MCValue{ .register = dest_reg };
2193 },
2194 else => unreachable,
2195 }
2196 },
2046 else => return self.fail("TODO implement codegen struct_field_val for {}", .{mcv}),2197 else => return self.fail("TODO implement codegen struct_field_val for {}", .{mcv}),
2047 }2198 }
2048 };2199 };
...@@ -2132,7 +2283,9 @@ fn binOpRegister(...@@ -2132,7 +2283,9 @@ fn binOpRegister(
21322283
2133 const mir_data: Mir.Inst.Data = switch (mir_tag) {2284 const mir_data: Mir.Inst.Data = switch (mir_tag) {
2134 .add,2285 .add,
2286 .adds,
2135 .sub,2287 .sub,
2288 .subs,
2136 .cmp,2289 .cmp,
2137 .@"and",2290 .@"and",
2138 .orr,2291 .orr,
...@@ -2232,7 +2385,9 @@ fn binOpImmediate(...@@ -2232,7 +2385,9 @@ fn binOpImmediate(
22322385
2233 const mir_data: Mir.Inst.Data = switch (mir_tag) {2386 const mir_data: Mir.Inst.Data = switch (mir_tag) {
2234 .add,2387 .add,
2388 .adds,
2235 .sub,2389 .sub,
2390 .subs,
2236 .cmp,2391 .cmp,
2237 .@"and",2392 .@"and",
2238 .orr,2393 .orr,
...@@ -2814,14 +2969,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -2814,14 +2969,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
28142969
2815 switch (mc_arg) {2970 switch (mc_arg) {
2816 .none => continue,2971 .none => continue,
2817 .undef => unreachable,
2818 .immediate => unreachable,
2819 .unreach => unreachable,
2820 .dead => unreachable,
2821 .memory => unreachable,
2822 .compare_flags_signed => unreachable,
2823 .compare_flags_unsigned => unreachable,
2824 .ptr_stack_offset => unreachable,
2825 .register => |reg| {2972 .register => |reg| {
2826 try self.register_manager.getReg(reg, null);2973 try self.register_manager.getReg(reg, null);
2827 try self.genSetReg(arg_ty, reg, arg_mcv);2974 try self.genSetReg(arg_ty, reg, arg_mcv);
...@@ -2832,6 +2979,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -2832,6 +2979,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
2832 info.stack_byte_count - offset,2979 info.stack_byte_count - offset,
2833 arg_mcv,2980 arg_mcv,
2834 ),2981 ),
2982 else => unreachable,
2835 }2983 }
2836 }2984 }
28372985
...@@ -3774,6 +3922,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -3774,6 +3922,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
3774 else => return self.fail("TODO implement storing other types abi_size={}", .{abi_size}),3922 else => return self.fail("TODO implement storing other types abi_size={}", .{abi_size}),
3775 }3923 }
3776 },3924 },
3925 .register_c_flag,
3926 .register_v_flag,
3927 => {
3928 return self.fail("TODO implement genSetStack {}", .{mcv});
3929 },
3777 .memory,3930 .memory,
3778 .stack_argument_offset,3931 .stack_argument_offset,
3779 .stack_offset,3932 .stack_offset,
...@@ -4015,6 +4168,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -4015,6 +4168,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
4015 } },4168 } },
4016 });4169 });
4017 },4170 },
4171 .register_c_flag => unreachable, // doesn't fit into a register
4172 .register_v_flag => unreachable, // doesn't fit into a register
4018 .memory => |addr| {4173 .memory => |addr| {
4019 // The value is in memory at a hard-coded address.4174 // The value is in memory at a hard-coded address.
4020 // If the type is a pointer, it means the pointer address is at this memory location.4175 // If the type is a pointer, it means the pointer address is at this memory location.
...@@ -4149,6 +4304,11 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I...@@ -4149,6 +4304,11 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
4149 else => return self.fail("TODO implement storing other types abi_size={}", .{abi_size}),4304 else => return self.fail("TODO implement storing other types abi_size={}", .{abi_size}),
4150 }4305 }
4151 },4306 },
4307 .register_c_flag,
4308 .register_v_flag,
4309 => {
4310 return self.fail("TODO implement genSetStack {}", .{mcv});
4311 },
4152 .stack_offset,4312 .stack_offset,
4153 .memory,4313 .memory,
4154 .stack_argument_offset,4314 .stack_argument_offset,
src/arch/arm/Emit.zig+4
...@@ -79,6 +79,7 @@ pub fn emitMir(...@@ -79,6 +79,7 @@ pub fn emitMir(
79 const inst = @intCast(u32, index);79 const inst = @intCast(u32, index);
80 switch (tag) {80 switch (tag) {
81 .add => try emit.mirDataProcessing(inst),81 .add => try emit.mirDataProcessing(inst),
82 .adds => try emit.mirDataProcessing(inst),
82 .@"and" => try emit.mirDataProcessing(inst),83 .@"and" => try emit.mirDataProcessing(inst),
83 .cmp => try emit.mirDataProcessing(inst),84 .cmp => try emit.mirDataProcessing(inst),
84 .eor => try emit.mirDataProcessing(inst),85 .eor => try emit.mirDataProcessing(inst),
...@@ -87,6 +88,7 @@ pub fn emitMir(...@@ -87,6 +88,7 @@ pub fn emitMir(
87 .orr => try emit.mirDataProcessing(inst),88 .orr => try emit.mirDataProcessing(inst),
88 .rsb => try emit.mirDataProcessing(inst),89 .rsb => try emit.mirDataProcessing(inst),
89 .sub => try emit.mirDataProcessing(inst),90 .sub => try emit.mirDataProcessing(inst),
91 .subs => try emit.mirDataProcessing(inst),
9092
91 .asr => try emit.mirShift(inst),93 .asr => try emit.mirShift(inst),
92 .lsl => try emit.mirShift(inst),94 .lsl => try emit.mirShift(inst),
...@@ -474,6 +476,7 @@ fn mirDataProcessing(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -474,6 +476,7 @@ fn mirDataProcessing(emit: *Emit, inst: Mir.Inst.Index) !void {
474476
475 switch (tag) {477 switch (tag) {
476 .add => try emit.writeInstruction(Instruction.add(cond, rr_op.rd, rr_op.rn, rr_op.op)),478 .add => try emit.writeInstruction(Instruction.add(cond, rr_op.rd, rr_op.rn, rr_op.op)),
479 .adds => try emit.writeInstruction(Instruction.adds(cond, rr_op.rd, rr_op.rn, rr_op.op)),
477 .@"and" => try emit.writeInstruction(Instruction.@"and"(cond, rr_op.rd, rr_op.rn, rr_op.op)),480 .@"and" => try emit.writeInstruction(Instruction.@"and"(cond, rr_op.rd, rr_op.rn, rr_op.op)),
478 .cmp => try emit.writeInstruction(Instruction.cmp(cond, rr_op.rn, rr_op.op)),481 .cmp => try emit.writeInstruction(Instruction.cmp(cond, rr_op.rn, rr_op.op)),
479 .eor => try emit.writeInstruction(Instruction.eor(cond, rr_op.rd, rr_op.rn, rr_op.op)),482 .eor => try emit.writeInstruction(Instruction.eor(cond, rr_op.rd, rr_op.rn, rr_op.op)),
...@@ -482,6 +485,7 @@ fn mirDataProcessing(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -482,6 +485,7 @@ fn mirDataProcessing(emit: *Emit, inst: Mir.Inst.Index) !void {
482 .orr => try emit.writeInstruction(Instruction.orr(cond, rr_op.rd, rr_op.rn, rr_op.op)),485 .orr => try emit.writeInstruction(Instruction.orr(cond, rr_op.rd, rr_op.rn, rr_op.op)),
483 .rsb => try emit.writeInstruction(Instruction.rsb(cond, rr_op.rd, rr_op.rn, rr_op.op)),486 .rsb => try emit.writeInstruction(Instruction.rsb(cond, rr_op.rd, rr_op.rn, rr_op.op)),
484 .sub => try emit.writeInstruction(Instruction.sub(cond, rr_op.rd, rr_op.rn, rr_op.op)),487 .sub => try emit.writeInstruction(Instruction.sub(cond, rr_op.rd, rr_op.rn, rr_op.op)),
488 .subs => try emit.writeInstruction(Instruction.sub(cond, rr_op.rd, rr_op.rn, rr_op.op)),
485 else => unreachable,489 else => unreachable,
486 }490 }
487}491}
src/arch/arm/Mir.zig+4
...@@ -28,6 +28,8 @@ pub const Inst = struct {...@@ -28,6 +28,8 @@ pub const Inst = struct {
28 pub const Tag = enum(u16) {28 pub const Tag = enum(u16) {
29 /// Add29 /// Add
30 add,30 add,
31 /// Add, update condition flags
32 adds,
31 /// Bitwise AND33 /// Bitwise AND
32 @"and",34 @"and",
33 /// Arithmetic Shift Right35 /// Arithmetic Shift Right
...@@ -108,6 +110,8 @@ pub const Inst = struct {...@@ -108,6 +110,8 @@ pub const Inst = struct {
108 strh,110 strh,
109 /// Subtract111 /// Subtract
110 sub,112 sub,
113 /// Subtract, update condition flags
114 subs,
111 /// Supervisor Call115 /// Supervisor Call
112 svc,116 svc,
113 /// Unsigned Bit Field Extract117 /// Unsigned Bit Field Extract