| ... | @@ -508,7 +508,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -508,7 +508,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 508 | .sub, .ptr_sub => try self.airBinOp(inst), | 508 | .sub, .ptr_sub => try self.airBinOp(inst), |
| 509 | .subwrap => try self.airSubWrap(inst), | 509 | .subwrap => try self.airSubWrap(inst), |
| 510 | .sub_sat => try self.airSubSat(inst), | 510 | .sub_sat => try self.airSubSat(inst), |
| 511 | .mul => try self.airMul(inst), | 511 | .mul => try self.airBinOp(inst), |
| 512 | .mulwrap => try self.airMulWrap(inst), | 512 | .mulwrap => try self.airMulWrap(inst), |
| 513 | .mul_sat => try self.airMulSat(inst), | 513 | .mul_sat => try self.airMulSat(inst), |
| 514 | .rem => try self.airRem(inst), | 514 | .rem => try self.airRem(inst), |
| ... | @@ -979,12 +979,6 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -979,12 +979,6 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { |
| 979 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 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 | fn airMulWrap(self: *Self, inst: Air.Inst.Index) !void { | 982 | fn airMulWrap(self: *Self, inst: Air.Inst.Index) !void { |
| 989 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 983 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 990 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement mulwrap for {}", .{self.target.cpu.arch}); | 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,7 +1246,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1252 | | 1246 | |
| 1253 | const slice_ty = self.air.typeOf(bin_op.lhs); | 1247 | const slice_ty = self.air.typeOf(bin_op.lhs); |
| 1254 | const elem_ty = slice_ty.childType(); | 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 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 1251 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 1258 | const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf); | 1252 | const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf); |
| ... | @@ -1307,7 +1301,14 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1307,7 +1301,14 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1307 | else => { | 1301 | else => { |
| 1308 | const dst_mcv = try self.allocRegOrMem(inst, true); | 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 | assert(offset_mcv == .register); // result of multiplication should always be register | 1312 | assert(offset_mcv == .register); // result of multiplication should always be register |
| 1312 | self.register_manager.freezeRegs(&.{offset_mcv.register}); | 1313 | self.register_manager.freezeRegs(&.{offset_mcv.register}); |
| 1313 | | 1314 | |
| ... | @@ -1768,6 +1769,7 @@ fn binOpRegister( | ... | @@ -1768,6 +1769,7 @@ fn binOpRegister( |
| 1768 | const mir_tag: Mir.Inst.Tag = switch (tag) { | 1769 | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| 1769 | .add, .ptr_add => .add, | 1770 | .add, .ptr_add => .add, |
| 1770 | .sub, .ptr_sub => .sub, | 1771 | .sub, .ptr_sub => .sub, |
| | 1772 | .mul => .mul, |
| 1771 | else => unreachable, | 1773 | else => unreachable, |
| 1772 | }; | 1774 | }; |
| 1773 | const mir_data: Mir.Inst.Data = switch (tag) { | 1775 | const mir_data: Mir.Inst.Data = switch (tag) { |
| ... | @@ -1780,6 +1782,11 @@ fn binOpRegister( | ... | @@ -1780,6 +1782,11 @@ fn binOpRegister( |
| 1780 | .rn = lhs_reg, | 1782 | .rn = lhs_reg, |
| 1781 | .op = Instruction.Operand.reg(rhs_reg, Instruction.Operand.Shift.none), | 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 | else => unreachable, | 1790 | else => unreachable, |
| 1784 | }; | 1791 | }; |
| 1785 | | 1792 | |
| ... | @@ -1938,6 +1945,25 @@ fn binOp( | ... | @@ -1938,6 +1945,25 @@ fn binOp( |
| 1938 | else => unreachable, | 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 | .ptr_add, | 1967 | .ptr_add, |
| 1942 | .ptr_sub, | 1968 | .ptr_sub, |
| 1943 | => { | 1969 | => { |
| ... | @@ -2219,132 +2245,6 @@ fn genBinOpCode( | ... | @@ -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 | fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, abi_size: u32) !void { | 2248 | fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, abi_size: u32) !void { |
| 2349 | switch (abi_size) { | 2249 | switch (abi_size) { |
| 2350 | 1, 3, 4 => { | 2250 | 1, 3, 4 => { |