authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-02-19 09:20:58+01:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-02-19 12:06:34+01:00
logc29bf2f51ae64456edd92bc6e37a6a8d8c7ba44e
treed7d98e7ffd7bada42a6fbb7d255baf4e6f9a4673
parent3b1762bb4769fdbe9d345218f0412595fa1d6e43
signature Commit is signed but in an unrecognized format.

stage2 ARM: move shl, shr to binOp lowering mechanism


1 files changed, 88 insertions(+), 225 deletions(-)

src/arch/arm/CodeGen.zig+88-225
......@@ -513,7 +513,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
513513 .mul_sat => try self.airMulSat(inst),
514514 .rem => try self.airRem(inst),
515515 .mod => try self.airMod(inst),
516 .shl, .shl_exact => try self.airShl(inst),
516 .shl, .shl_exact => try self.airBinOp(inst),
517517 .shl_sat => try self.airShlSat(inst),
518518 .min => try self.airMin(inst),
519519 .max => try self.airMax(inst),
......@@ -553,7 +553,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
553553 .bit_and => try self.airBinOp(inst),
554554 .bit_or => try self.airBinOp(inst),
555555 .xor => try self.airBinOp(inst),
556 .shr, .shr_exact => try self.airShr(inst),
556 .shr, .shr_exact => try self.airBinOp(inst),
557557
558558 .alloc => try self.airAlloc(inst),
559559 .ret_ptr => try self.airRetPtr(inst),
......@@ -1091,24 +1091,12 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void {
10911091 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
10921092}
10931093
1094fn airShl(self: *Self, inst: Air.Inst.Index) !void {
1095 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1096 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else try self.genBinOp(inst, bin_op.lhs, bin_op.rhs, .shl);
1097 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1098}
1099
11001094fn airShlSat(self: *Self, inst: Air.Inst.Index) !void {
11011095 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
11021096 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement shl_sat for {}", .{self.target.cpu.arch});
11031097 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
11041098}
11051099
1106fn airShr(self: *Self, inst: Air.Inst.Index) !void {
1107 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1108 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else try self.genBinOp(inst, bin_op.lhs, bin_op.rhs, .shr);
1109 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1110}
1111
11121100fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {
11131101 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
11141102 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement .optional_payload for {}", .{self.target.cpu.arch});
......@@ -1820,6 +1808,15 @@ fn binOpRegister(
18201808 .bit_or,
18211809 .bool_or,
18221810 => .orr,
1811 .shl,
1812 .shl_exact,
1813 => .lsl,
1814 .shr,
1815 .shr_exact,
1816 => switch (lhs_ty.intInfo(self.target.*).signedness) {
1817 .signed => Mir.Inst.Tag.asr,
1818 .unsigned => Mir.Inst.Tag.lsr,
1819 },
18231820 .xor => .eor,
18241821 else => unreachable,
18251822 };
......@@ -1838,6 +1835,15 @@ fn binOpRegister(
18381835 .rn = lhs_reg,
18391836 .op = Instruction.Operand.reg(rhs_reg, Instruction.Operand.Shift.none),
18401837 } },
1838 .shl,
1839 .shl_exact,
1840 .shr,
1841 .shr_exact,
1842 => .{ .rr_shift = .{
1843 .rd = dest_reg,
1844 .rm = lhs_reg,
1845 .shift_amount = Instruction.ShiftAmount.reg(rhs_reg),
1846 } },
18411847 .mul => .{ .rrr = .{
18421848 .rd = dest_reg,
18431849 .rn = lhs_reg,
......@@ -1924,6 +1930,15 @@ fn binOpImmediate(
19241930 .bit_or,
19251931 .bool_or,
19261932 => .orr,
1933 .shl,
1934 .shl_exact,
1935 => .lsl,
1936 .shr,
1937 .shr_exact,
1938 => switch (lhs_ty.intInfo(self.target.*).signedness) {
1939 .signed => Mir.Inst.Tag.asr,
1940 .unsigned => Mir.Inst.Tag.lsr,
1941 },
19271942 .xor => .eor,
19281943 else => unreachable,
19291944 };
......@@ -1940,6 +1955,15 @@ fn binOpImmediate(
19401955 .rn = lhs_reg,
19411956 .op = Instruction.Operand.fromU32(rhs.immediate).?,
19421957 } },
1958 .shl,
1959 .shl_exact,
1960 .shr,
1961 .shr_exact,
1962 => .{ .rr_shift = .{
1963 .rd = dest_reg,
1964 .rm = lhs_reg,
1965 .shift_amount = Instruction.ShiftAmount.imm(@intCast(u5, rhs.immediate)),
1966 } },
19431967 else => unreachable,
19441968 };
19451969
......@@ -2060,6 +2084,28 @@ fn binOp(
20602084 else => unreachable,
20612085 }
20622086 },
2087 .shl,
2088 .shr,
2089 => {
2090 switch (lhs_ty.zigTypeTag()) {
2091 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
2092 .Int => {
2093 const int_info = lhs_ty.intInfo(self.target.*);
2094 if (int_info.bits <= 32) {
2095 const rhs_immediate_ok = rhs == .immediate;
2096
2097 if (rhs_immediate_ok) {
2098 return try self.binOpImmediate(tag, maybe_inst, lhs, rhs, lhs_ty, false);
2099 } else {
2100 return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
2101 }
2102 } else {
2103 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
2104 }
2105 },
2106 else => unreachable,
2107 }
2108 },
20632109 .bool_and,
20642110 .bool_or,
20652111 => {
......@@ -2129,212 +2175,6 @@ fn armOperandShouldBeRegister(self: *Self, mcv: MCValue) !bool {
21292175 };
21302176}
21312177
2132fn genBinOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref, op: Air.Inst.Tag) !MCValue {
2133 // In the case of bitshifts, the type of rhs is different
2134 // from the resulting type
2135 const ty = self.air.typeOf(op_lhs);
2136
2137 switch (ty.zigTypeTag()) {
2138 .Int => {
2139 const int_info = ty.intInfo(self.target.*);
2140 return self.genBinIntOp(inst, op_lhs, op_rhs, op, int_info.bits, int_info.signedness);
2141 },
2142 else => unreachable,
2143 }
2144}
2145
2146fn genBinIntOp(
2147 self: *Self,
2148 inst: Air.Inst.Index,
2149 op_lhs: Air.Inst.Ref,
2150 op_rhs: Air.Inst.Ref,
2151 op: Air.Inst.Tag,
2152 bits: u16,
2153 signedness: std.builtin.Signedness,
2154) !MCValue {
2155 if (bits > 32) {
2156 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
2157 }
2158
2159 const lhs = try self.resolveInst(op_lhs);
2160 const rhs = try self.resolveInst(op_rhs);
2161
2162 const lhs_is_register = lhs == .register;
2163 const rhs_is_register = rhs == .register;
2164 const lhs_should_be_register = switch (op) {
2165 .shr, .shl => true,
2166 else => try self.armOperandShouldBeRegister(lhs),
2167 };
2168 const rhs_should_be_register = try self.armOperandShouldBeRegister(rhs);
2169 const reuse_lhs = lhs_is_register and self.reuseOperand(inst, op_lhs, 0, lhs);
2170 const reuse_rhs = !reuse_lhs and rhs_is_register and self.reuseOperand(inst, op_rhs, 1, rhs);
2171 const can_swap_lhs_and_rhs = switch (op) {
2172 .shr, .shl => false,
2173 else => true,
2174 };
2175
2176 if (lhs_is_register) self.register_manager.freezeRegs(&.{lhs.register});
2177 defer if (lhs_is_register) self.register_manager.unfreezeRegs(&.{lhs.register});
2178 if (rhs_is_register) self.register_manager.freezeRegs(&.{rhs.register});
2179 defer if (rhs_is_register) self.register_manager.unfreezeRegs(&.{rhs.register});
2180
2181 // Destination must be a register
2182 var dst_mcv: MCValue = undefined;
2183 var lhs_mcv = lhs;
2184 var rhs_mcv = rhs;
2185 var swap_lhs_and_rhs = false;
2186
2187 // Allocate registers for operands and/or destination
2188 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
2189 if (reuse_lhs) {
2190 // Allocate 0 or 1 registers
2191 if (!rhs_is_register and rhs_should_be_register) {
2192 rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_rhs).?) };
2193 branch.inst_table.putAssumeCapacity(Air.refToIndex(op_rhs).?, rhs_mcv);
2194 }
2195 dst_mcv = lhs;
2196 } else if (reuse_rhs and can_swap_lhs_and_rhs) {
2197 // Allocate 0 or 1 registers
2198 if (!lhs_is_register and lhs_should_be_register) {
2199 lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_lhs).?) };
2200 branch.inst_table.putAssumeCapacity(Air.refToIndex(op_lhs).?, lhs_mcv);
2201 }
2202 dst_mcv = rhs;
2203
2204 swap_lhs_and_rhs = true;
2205 } else {
2206 // Allocate 1 or 2 registers
2207 if (lhs_should_be_register and rhs_should_be_register) {
2208 if (lhs_is_register and rhs_is_register) {
2209 dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) };
2210 } else if (lhs_is_register) {
2211 // Move RHS to register
2212 dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) };
2213 rhs_mcv = dst_mcv;
2214 } else if (rhs_is_register) {
2215 // Move LHS to register
2216 dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) };
2217 lhs_mcv = dst_mcv;
2218 } else {
2219 // Move LHS and RHS to register
2220 const regs = try self.register_manager.allocRegs(2, .{ inst, Air.refToIndex(op_rhs).? });
2221 lhs_mcv = MCValue{ .register = regs[0] };
2222 rhs_mcv = MCValue{ .register = regs[1] };
2223 dst_mcv = lhs_mcv;
2224
2225 branch.inst_table.putAssumeCapacity(Air.refToIndex(op_rhs).?, rhs_mcv);
2226 }
2227 } else if (lhs_should_be_register) {
2228 // RHS is immediate
2229 if (lhs_is_register) {
2230 dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) };
2231 } else {
2232 dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) };
2233 lhs_mcv = dst_mcv;
2234 }
2235 } else if (rhs_should_be_register and can_swap_lhs_and_rhs) {
2236 // LHS is immediate
2237 if (rhs_is_register) {
2238 dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) };
2239 } else {
2240 dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) };
2241 rhs_mcv = dst_mcv;
2242 }
2243
2244 swap_lhs_and_rhs = true;
2245 } else unreachable; // binary operation on two immediates
2246 }
2247
2248 // Move the operands to the newly allocated registers
2249 if (lhs_mcv == .register and !lhs_is_register) {
2250 try self.genSetReg(self.air.typeOf(op_lhs), lhs_mcv.register, lhs);
2251 }
2252 if (rhs_mcv == .register and !rhs_is_register) {
2253 try self.genSetReg(self.air.typeOf(op_rhs), rhs_mcv.register, rhs);
2254 }
2255
2256 try self.genBinOpCode(
2257 dst_mcv.register,
2258 lhs_mcv,
2259 rhs_mcv,
2260 swap_lhs_and_rhs,
2261 op,
2262 signedness,
2263 );
2264 return dst_mcv;
2265}
2266
2267fn genBinOpCode(
2268 self: *Self,
2269 dst_reg: Register,
2270 lhs_mcv: MCValue,
2271 rhs_mcv: MCValue,
2272 swap_lhs_and_rhs: bool,
2273 op: Air.Inst.Tag,
2274 signedness: std.builtin.Signedness,
2275) !void {
2276 assert(lhs_mcv == .register or rhs_mcv == .register);
2277
2278 const op1 = if (swap_lhs_and_rhs) rhs_mcv.register else lhs_mcv.register;
2279 const op2 = if (swap_lhs_and_rhs) lhs_mcv else rhs_mcv;
2280
2281 const operand = switch (op2) {
2282 .none => unreachable,
2283 .undef => unreachable,
2284 .dead, .unreach => unreachable,
2285 .compare_flags_unsigned => unreachable,
2286 .compare_flags_signed => unreachable,
2287 .ptr_stack_offset => unreachable,
2288 .ptr_embedded_in_code => unreachable,
2289 .immediate => |imm| Instruction.Operand.fromU32(@intCast(u32, imm)).?,
2290 .register => |reg| Instruction.Operand.reg(reg, Instruction.Operand.Shift.none),
2291 .stack_offset,
2292 .stack_argument_offset,
2293 .embedded_in_code,
2294 .memory,
2295 => unreachable,
2296 };
2297
2298 switch (op) {
2299 .cmp_eq => {
2300 _ = try self.addInst(.{
2301 .tag = .cmp,
2302 .data = .{ .rr_op = .{
2303 .rd = .r0,
2304 .rn = op1,
2305 .op = operand,
2306 } },
2307 });
2308 },
2309 .shl, .shr => {
2310 assert(!swap_lhs_and_rhs);
2311 const shift_amount = switch (operand) {
2312 .register => |reg_op| Instruction.ShiftAmount.reg(@intToEnum(Register, reg_op.rm)),
2313 .immediate => |imm_op| Instruction.ShiftAmount.imm(@intCast(u5, imm_op.imm)),
2314 };
2315
2316 const tag: Mir.Inst.Tag = switch (op) {
2317 .shl => .lsl,
2318 .shr => switch (signedness) {
2319 .signed => Mir.Inst.Tag.asr,
2320 .unsigned => Mir.Inst.Tag.lsr,
2321 },
2322 else => unreachable,
2323 };
2324
2325 _ = try self.addInst(.{
2326 .tag = tag,
2327 .data = .{ .rr_shift = .{
2328 .rd = dst_reg,
2329 .rm = op1,
2330 .shift_amount = shift_amount,
2331 } },
2332 });
2333 },
2334 else => unreachable, // not a binary instruction
2335 }
2336}
2337
23382178fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, abi_size: u32) !void {
23392179 switch (abi_size) {
23402180 1, 3, 4 => {
......@@ -2769,9 +2609,18 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
27692609 branch.inst_table.putAssumeCapacity(Air.refToIndex(bin_op.rhs).?, rhs);
27702610 }
27712611
2772 // The destination register is not present in the cmp instruction
2773 // The signedness of the integer does not matter for the cmp instruction
2774 try self.genBinOpCode(undefined, lhs_mcv, rhs_mcv, false, .cmp_eq, undefined);
2612 _ = try self.addInst(.{
2613 .tag = .cmp,
2614 .data = .{ .rr_op = .{
2615 .rd = undefined,
2616 .rn = lhs_mcv.register,
2617 .op = switch (rhs_mcv) {
2618 .immediate => |imm| Instruction.Operand.fromU32(@intCast(u32, imm)).?,
2619 .register => |reg| Instruction.Operand.reg(reg, Instruction.Operand.Shift.none),
2620 else => unreachable,
2621 },
2622 } },
2623 });
27752624
27762625 break :result switch (signedness) {
27772626 .signed => MCValue{ .compare_flags_signed = op },
......@@ -3003,7 +2852,14 @@ fn isNull(self: *Self, ty: Type, operand: MCValue) !MCValue {
30032852 else => .{ .register = try self.copyToTmpRegister(ty, operand) },
30042853 };
30052854
3006 try self.genBinOpCode(undefined, reg_mcv, .{ .immediate = 0 }, false, .cmp_eq, undefined);
2855 _ = try self.addInst(.{
2856 .tag = .cmp,
2857 .data = .{ .rr_op = .{
2858 .rd = undefined,
2859 .rn = reg_mcv.register,
2860 .op = Instruction.Operand.fromU32(0).?,
2861 } },
2862 });
30072863
30082864 return MCValue{ .compare_flags_unsigned = .eq };
30092865 } else {
......@@ -3033,7 +2889,14 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
30332889 else => .{ .register = try self.copyToTmpRegister(error_type, operand) },
30342890 };
30352891
3036 try self.genBinOpCode(undefined, reg_mcv, .{ .immediate = 0 }, false, .cmp_eq, undefined);
2892 _ = try self.addInst(.{
2893 .tag = .cmp,
2894 .data = .{ .rr_op = .{
2895 .rd = undefined,
2896 .rn = reg_mcv.register,
2897 .op = Instruction.Operand.fromU32(0).?,
2898 } },
2899 });
30372900
30382901 return MCValue{ .compare_flags_unsigned = .gt };
30392902 } else {