| ... | ... | @@ -508,7 +508,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 508 | 508 | .sub, .ptr_sub => try self.airBinOp(inst), |
| 509 | 509 | .subwrap => try self.airSubWrap(inst), |
| 510 | 510 | .sub_sat => try self.airSubSat(inst), |
| 511 | | .mul => try self.airMul(inst), |
| 511 | .mul => try self.airBinOp(inst), |
| 512 | 512 | .mulwrap => try self.airMulWrap(inst), |
| 513 | 513 | .mul_sat => try self.airMulSat(inst), |
| 514 | 514 | .rem => try self.airRem(inst), |
| ... | ... | @@ -979,12 +979,6 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { |
| 979 | 979 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 980 | 980 | } |
| 981 | 981 | |
| 982 | | fn airMul(self: *Self, inst: Air.Inst.Index) !void { |
| 983 | | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 984 | | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else try self.genMul(inst, bin_op.lhs, bin_op.rhs); |
| 985 | | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 986 | | } |
| 987 | | |
| 988 | 982 | fn airMulWrap(self: *Self, inst: Air.Inst.Index) !void { |
| 989 | 983 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 990 | 984 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement mulwrap for {}", .{self.target.cpu.arch}); |
| ... | ... | @@ -1252,7 +1246,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1252 | 1246 | |
| 1253 | 1247 | const slice_ty = self.air.typeOf(bin_op.lhs); |
| 1254 | 1248 | const elem_ty = slice_ty.childType(); |
| 1255 | | const elem_size = elem_ty.abiSize(self.target.*); |
| 1249 | const elem_size = @intCast(u32, elem_ty.abiSize(self.target.*)); |
| 1256 | 1250 | |
| 1257 | 1251 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 1258 | 1252 | const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf); |
| ... | ... | @@ -1307,7 +1301,14 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1307 | 1301 | else => { |
| 1308 | 1302 | const dst_mcv = try self.allocRegOrMem(inst, true); |
| 1309 | 1303 | |
| 1310 | | const offset_mcv = try self.genMulConstant(bin_op.rhs, @intCast(u32, elem_size)); |
| 1304 | const offset_mcv = try self.binOp( |
| 1305 | .mul, |
| 1306 | null, |
| 1307 | index_mcv, |
| 1308 | .{ .immediate = elem_size }, |
| 1309 | Type.usize, |
| 1310 | Type.usize, |
| 1311 | ); |
| 1311 | 1312 | assert(offset_mcv == .register); // result of multiplication should always be register |
| 1312 | 1313 | self.register_manager.freezeRegs(&.{offset_mcv.register}); |
| 1313 | 1314 | |
| ... | ... | @@ -1768,6 +1769,7 @@ fn binOpRegister( |
| 1768 | 1769 | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| 1769 | 1770 | .add, .ptr_add => .add, |
| 1770 | 1771 | .sub, .ptr_sub => .sub, |
| 1772 | .mul => .mul, |
| 1771 | 1773 | else => unreachable, |
| 1772 | 1774 | }; |
| 1773 | 1775 | const mir_data: Mir.Inst.Data = switch (tag) { |
| ... | ... | @@ -1780,6 +1782,11 @@ fn binOpRegister( |
| 1780 | 1782 | .rn = lhs_reg, |
| 1781 | 1783 | .op = Instruction.Operand.reg(rhs_reg, Instruction.Operand.Shift.none), |
| 1782 | 1784 | } }, |
| 1785 | .mul => .{ .rrr = .{ |
| 1786 | .rd = dest_reg, |
| 1787 | .rn = lhs_reg, |
| 1788 | .rm = rhs_reg, |
| 1789 | } }, |
| 1783 | 1790 | else => unreachable, |
| 1784 | 1791 | }; |
| 1785 | 1792 | |
| ... | ... | @@ -1938,6 +1945,25 @@ fn binOp( |
| 1938 | 1945 | else => unreachable, |
| 1939 | 1946 | } |
| 1940 | 1947 | }, |
| 1948 | .mul => { |
| 1949 | switch (lhs_ty.zigTypeTag()) { |
| 1950 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 1951 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 1952 | .Int => { |
| 1953 | assert(lhs_ty.eql(rhs_ty)); |
| 1954 | const int_info = lhs_ty.intInfo(self.target.*); |
| 1955 | if (int_info.bits <= 32) { |
| 1956 | // TODO add optimisations for multiplication |
| 1957 | // with immediates, for example a * 2 can be |
| 1958 | // lowered to a << 1 |
| 1959 | return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); |
| 1960 | } else { |
| 1961 | return self.fail("TODO ARM binary operations on integers > u32/i32", .{}); |
| 1962 | } |
| 1963 | }, |
| 1964 | else => unreachable, |
| 1965 | } |
| 1966 | }, |
| 1941 | 1967 | .ptr_add, |
| 1942 | 1968 | .ptr_sub, |
| 1943 | 1969 | => { |
| ... | ... | @@ -2219,132 +2245,6 @@ fn genBinOpCode( |
| 2219 | 2245 | } |
| 2220 | 2246 | } |
| 2221 | 2247 | |
| 2222 | | fn genMul(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref) !MCValue { |
| 2223 | | const lhs = try self.resolveInst(op_lhs); |
| 2224 | | const rhs = try self.resolveInst(op_rhs); |
| 2225 | | |
| 2226 | | const lhs_is_register = lhs == .register; |
| 2227 | | const rhs_is_register = rhs == .register; |
| 2228 | | const reuse_lhs = lhs_is_register and self.reuseOperand(inst, op_lhs, 0, lhs); |
| 2229 | | const reuse_rhs = !reuse_lhs and rhs_is_register and self.reuseOperand(inst, op_rhs, 1, rhs); |
| 2230 | | |
| 2231 | | if (lhs_is_register) self.register_manager.freezeRegs(&.{lhs.register}); |
| 2232 | | defer if (lhs_is_register) self.register_manager.unfreezeRegs(&.{lhs.register}); |
| 2233 | | if (rhs_is_register) self.register_manager.freezeRegs(&.{rhs.register}); |
| 2234 | | defer if (rhs_is_register) self.register_manager.unfreezeRegs(&.{rhs.register}); |
| 2235 | | |
| 2236 | | // Destination must be a register |
| 2237 | | // LHS must be a register |
| 2238 | | // RHS must be a register |
| 2239 | | var dst_mcv: MCValue = undefined; |
| 2240 | | var lhs_mcv: MCValue = lhs; |
| 2241 | | var rhs_mcv: MCValue = rhs; |
| 2242 | | |
| 2243 | | // Allocate registers for operands and/or destination |
| 2244 | | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 2245 | | if (reuse_lhs) { |
| 2246 | | // Allocate 0 or 1 registers |
| 2247 | | if (!rhs_is_register) { |
| 2248 | | rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_rhs).?) }; |
| 2249 | | branch.inst_table.putAssumeCapacity(Air.refToIndex(op_rhs).?, rhs_mcv); |
| 2250 | | } |
| 2251 | | dst_mcv = lhs; |
| 2252 | | } else if (reuse_rhs) { |
| 2253 | | // Allocate 0 or 1 registers |
| 2254 | | if (!lhs_is_register) { |
| 2255 | | lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_lhs).?) }; |
| 2256 | | branch.inst_table.putAssumeCapacity(Air.refToIndex(op_lhs).?, lhs_mcv); |
| 2257 | | } |
| 2258 | | dst_mcv = rhs; |
| 2259 | | } else { |
| 2260 | | // Allocate 1 or 2 registers |
| 2261 | | if (lhs_is_register and rhs_is_register) { |
| 2262 | | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) }; |
| 2263 | | } else if (lhs_is_register) { |
| 2264 | | // Move RHS to register |
| 2265 | | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) }; |
| 2266 | | rhs_mcv = dst_mcv; |
| 2267 | | } else if (rhs_is_register) { |
| 2268 | | // Move LHS to register |
| 2269 | | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) }; |
| 2270 | | lhs_mcv = dst_mcv; |
| 2271 | | } else { |
| 2272 | | // Move LHS and RHS to register |
| 2273 | | const regs = try self.register_manager.allocRegs(2, .{ inst, Air.refToIndex(op_rhs).? }); |
| 2274 | | lhs_mcv = MCValue{ .register = regs[0] }; |
| 2275 | | rhs_mcv = MCValue{ .register = regs[1] }; |
| 2276 | | dst_mcv = lhs_mcv; |
| 2277 | | |
| 2278 | | branch.inst_table.putAssumeCapacity(Air.refToIndex(op_rhs).?, rhs_mcv); |
| 2279 | | } |
| 2280 | | } |
| 2281 | | |
| 2282 | | // Move the operands to the newly allocated registers |
| 2283 | | if (!lhs_is_register) { |
| 2284 | | try self.genSetReg(self.air.typeOf(op_lhs), lhs_mcv.register, lhs); |
| 2285 | | } |
| 2286 | | if (!rhs_is_register) { |
| 2287 | | try self.genSetReg(self.air.typeOf(op_rhs), rhs_mcv.register, rhs); |
| 2288 | | } |
| 2289 | | |
| 2290 | | _ = try self.addInst(.{ |
| 2291 | | .tag = .mul, |
| 2292 | | .data = .{ .rrr = .{ |
| 2293 | | .rd = dst_mcv.register, |
| 2294 | | .rn = lhs_mcv.register, |
| 2295 | | .rm = rhs_mcv.register, |
| 2296 | | } }, |
| 2297 | | }); |
| 2298 | | return dst_mcv; |
| 2299 | | } |
| 2300 | | |
| 2301 | | fn genMulConstant(self: *Self, op: Air.Inst.Ref, imm: u32) !MCValue { |
| 2302 | | const lhs = try self.resolveInst(op); |
| 2303 | | const rhs = MCValue{ .immediate = imm }; |
| 2304 | | |
| 2305 | | const lhs_is_register = lhs == .register; |
| 2306 | | |
| 2307 | | if (lhs_is_register) self.register_manager.freezeRegs(&.{lhs.register}); |
| 2308 | | defer if (lhs_is_register) self.register_manager.unfreezeRegs(&.{lhs.register}); |
| 2309 | | |
| 2310 | | // Destination must be a register |
| 2311 | | // LHS must be a register |
| 2312 | | // RHS must be a register |
| 2313 | | var dst_mcv: MCValue = undefined; |
| 2314 | | var lhs_mcv: MCValue = lhs; |
| 2315 | | var rhs_mcv: MCValue = rhs; |
| 2316 | | |
| 2317 | | // Allocate registers for operands and/or destination |
| 2318 | | // Allocate 1 or 2 registers |
| 2319 | | if (lhs_is_register) { |
| 2320 | | // Move RHS to register |
| 2321 | | dst_mcv = MCValue{ .register = try self.register_manager.allocReg(null) }; |
| 2322 | | rhs_mcv = dst_mcv; |
| 2323 | | } else { |
| 2324 | | // Move LHS and RHS to register |
| 2325 | | const regs = try self.register_manager.allocRegs(2, .{ null, null }); |
| 2326 | | lhs_mcv = MCValue{ .register = regs[0] }; |
| 2327 | | rhs_mcv = MCValue{ .register = regs[1] }; |
| 2328 | | dst_mcv = lhs_mcv; |
| 2329 | | } |
| 2330 | | |
| 2331 | | // Move the operands to the newly allocated registers |
| 2332 | | if (!lhs_is_register) { |
| 2333 | | try self.genSetReg(self.air.typeOf(op), lhs_mcv.register, lhs); |
| 2334 | | } |
| 2335 | | try self.genSetReg(Type.initTag(.usize), rhs_mcv.register, rhs); |
| 2336 | | |
| 2337 | | _ = try self.addInst(.{ |
| 2338 | | .tag = .mul, |
| 2339 | | .data = .{ .rrr = .{ |
| 2340 | | .rd = dst_mcv.register, |
| 2341 | | .rn = lhs_mcv.register, |
| 2342 | | .rm = rhs_mcv.register, |
| 2343 | | } }, |
| 2344 | | }); |
| 2345 | | return dst_mcv; |
| 2346 | | } |
| 2347 | | |
| 2348 | 2248 | fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, abi_size: u32) !void { |
| 2349 | 2249 | switch (abi_size) { |
| 2350 | 2250 | 1, 3, 4 => { |