| ... | ... | @@ -1582,7 +1582,7 @@ fn binOpImmediateNew( |
| 1582 | 1582 | self: *Self, |
| 1583 | 1583 | mir_tag: Mir.Inst.Tag, |
| 1584 | 1584 | lhs_bind: ReadArg.Bind, |
| 1585 | | rhs_immediate: u32, |
| 1585 | rhs_immediate: u64, |
| 1586 | 1586 | lhs_ty: Type, |
| 1587 | 1587 | lhs_and_rhs_swapped: bool, |
| 1588 | 1588 | maybe_inst: ?Air.Inst.Index, |
| ... | ... | @@ -1910,57 +1910,6 @@ fn binOp( |
| 1910 | 1910 | ) InnerError!MCValue { |
| 1911 | 1911 | const mod = self.bin_file.options.module.?; |
| 1912 | 1912 | switch (tag) { |
| 1913 | | .add, |
| 1914 | | .sub, |
| 1915 | | => { |
| 1916 | | switch (lhs_ty.zigTypeTag()) { |
| 1917 | | .Float => return self.fail("TODO binary operations on floats", .{}), |
| 1918 | | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 1919 | | .Int => { |
| 1920 | | assert(lhs_ty.eql(rhs_ty, mod)); |
| 1921 | | const int_info = lhs_ty.intInfo(self.target.*); |
| 1922 | | if (int_info.bits <= 64) { |
| 1923 | | // Only say yes if the operation is |
| 1924 | | // commutative, i.e. we can swap both of the |
| 1925 | | // operands |
| 1926 | | const lhs_immediate_ok = switch (tag) { |
| 1927 | | .add => lhs == .immediate and lhs.immediate <= std.math.maxInt(u12), |
| 1928 | | .sub => false, |
| 1929 | | else => unreachable, |
| 1930 | | }; |
| 1931 | | const rhs_immediate_ok = switch (tag) { |
| 1932 | | .add, |
| 1933 | | .sub, |
| 1934 | | => rhs == .immediate and rhs.immediate <= std.math.maxInt(u12), |
| 1935 | | else => unreachable, |
| 1936 | | }; |
| 1937 | | |
| 1938 | | const mir_tag_register: Mir.Inst.Tag = switch (tag) { |
| 1939 | | .add => .add_shifted_register, |
| 1940 | | .sub => .sub_shifted_register, |
| 1941 | | else => unreachable, |
| 1942 | | }; |
| 1943 | | const mir_tag_immediate: Mir.Inst.Tag = switch (tag) { |
| 1944 | | .add => .add_immediate, |
| 1945 | | .sub => .sub_immediate, |
| 1946 | | else => unreachable, |
| 1947 | | }; |
| 1948 | | |
| 1949 | | if (rhs_immediate_ok) { |
| 1950 | | return try self.binOpImmediate(mir_tag_immediate, lhs, rhs, lhs_ty, false, metadata); |
| 1951 | | } else if (lhs_immediate_ok) { |
| 1952 | | // swap lhs and rhs |
| 1953 | | return try self.binOpImmediate(mir_tag_immediate, rhs, lhs, rhs_ty, true, metadata); |
| 1954 | | } else { |
| 1955 | | return try self.binOpRegister(mir_tag_register, lhs, rhs, lhs_ty, rhs_ty, metadata); |
| 1956 | | } |
| 1957 | | } else { |
| 1958 | | return self.fail("TODO binary operations on int with bits > 64", .{}); |
| 1959 | | } |
| 1960 | | }, |
| 1961 | | else => unreachable, |
| 1962 | | } |
| 1963 | | }, |
| 1964 | 1913 | .mul => { |
| 1965 | 1914 | switch (lhs_ty.zigTypeTag()) { |
| 1966 | 1915 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| ... | ... | @@ -2134,8 +2083,18 @@ fn binOp( |
| 2134 | 2083 | else => unreachable, |
| 2135 | 2084 | }; |
| 2136 | 2085 | |
| 2086 | const lhs_bind = if (metadata) |md| |
| 2087 | ReadArg.Bind{ .inst = md.lhs } |
| 2088 | else |
| 2089 | ReadArg.Bind{ .mcv = lhs }; |
| 2090 | const rhs_bind = if (metadata) |md| |
| 2091 | ReadArg.Bind{ .inst = md.rhs } |
| 2092 | else |
| 2093 | ReadArg.Bind{ .mcv = rhs }; |
| 2094 | |
| 2137 | 2095 | // Generate an add/sub/mul |
| 2138 | | const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata); |
| 2096 | const maybe_inst: ?Air.Inst.Index = if (metadata) |md| md.inst else null; |
| 2097 | const result = try self.addSub(base_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); |
| 2139 | 2098 | |
| 2140 | 2099 | // Truncate if necessary |
| 2141 | 2100 | switch (lhs_ty.zigTypeTag()) { |
| ... | ... | @@ -2304,21 +2263,93 @@ fn binOp( |
| 2304 | 2263 | } |
| 2305 | 2264 | } |
| 2306 | 2265 | |
| 2266 | fn addSub( |
| 2267 | self: *Self, |
| 2268 | tag: Air.Inst.Tag, |
| 2269 | lhs_bind: ReadArg.Bind, |
| 2270 | rhs_bind: ReadArg.Bind, |
| 2271 | lhs_ty: Type, |
| 2272 | rhs_ty: Type, |
| 2273 | maybe_inst: ?Air.Inst.Index, |
| 2274 | ) InnerError!MCValue { |
| 2275 | const mod = self.bin_file.options.module.?; |
| 2276 | switch (lhs_ty.zigTypeTag()) { |
| 2277 | .Float => return self.fail("TODO binary operations on floats", .{}), |
| 2278 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 2279 | .Int => { |
| 2280 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 2281 | const int_info = lhs_ty.intInfo(self.target.*); |
| 2282 | if (int_info.bits <= 64) { |
| 2283 | const lhs_immediate = try lhs_bind.resolveToImmediate(self); |
| 2284 | const rhs_immediate = try rhs_bind.resolveToImmediate(self); |
| 2285 | |
| 2286 | // Only say yes if the operation is |
| 2287 | // commutative, i.e. we can swap both of the |
| 2288 | // operands |
| 2289 | const lhs_immediate_ok = switch (tag) { |
| 2290 | .add => if (lhs_immediate) |imm| imm <= std.math.maxInt(u12) else false, |
| 2291 | .sub => false, |
| 2292 | else => unreachable, |
| 2293 | }; |
| 2294 | const rhs_immediate_ok = switch (tag) { |
| 2295 | .add, |
| 2296 | .sub, |
| 2297 | => if (rhs_immediate) |imm| imm <= std.math.maxInt(u12) else false, |
| 2298 | else => unreachable, |
| 2299 | }; |
| 2300 | |
| 2301 | const mir_tag_register: Mir.Inst.Tag = switch (tag) { |
| 2302 | .add => .add_shifted_register, |
| 2303 | .sub => .sub_shifted_register, |
| 2304 | else => unreachable, |
| 2305 | }; |
| 2306 | const mir_tag_immediate: Mir.Inst.Tag = switch (tag) { |
| 2307 | .add => .add_immediate, |
| 2308 | .sub => .sub_immediate, |
| 2309 | else => unreachable, |
| 2310 | }; |
| 2311 | |
| 2312 | if (rhs_immediate_ok) { |
| 2313 | return try self.binOpImmediateNew(mir_tag_immediate, lhs_bind, rhs_immediate.?, lhs_ty, false, maybe_inst); |
| 2314 | } else if (lhs_immediate_ok) { |
| 2315 | // swap lhs and rhs |
| 2316 | return try self.binOpImmediateNew(mir_tag_immediate, rhs_bind, lhs_immediate.?, rhs_ty, true, maybe_inst); |
| 2317 | } else { |
| 2318 | return try self.binOpRegisterNew(mir_tag_register, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); |
| 2319 | } |
| 2320 | } else { |
| 2321 | return self.fail("TODO binary operations on int with bits > 64", .{}); |
| 2322 | } |
| 2323 | }, |
| 2324 | else => unreachable, |
| 2325 | } |
| 2326 | } |
| 2327 | |
| 2307 | 2328 | fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 2308 | 2329 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2309 | | const lhs = try self.resolveInst(bin_op.lhs); |
| 2310 | | const rhs = try self.resolveInst(bin_op.rhs); |
| 2311 | 2330 | const lhs_ty = self.air.typeOf(bin_op.lhs); |
| 2312 | 2331 | const rhs_ty = self.air.typeOf(bin_op.rhs); |
| 2313 | 2332 | |
| 2314 | | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 2315 | | .dead |
| 2316 | | else |
| 2317 | | try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{ |
| 2318 | | .inst = inst, |
| 2319 | | .lhs = bin_op.lhs, |
| 2320 | | .rhs = bin_op.rhs, |
| 2321 | | }); |
| 2333 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2334 | const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs }; |
| 2335 | const rhs_bind: ReadArg.Bind = .{ .inst = bin_op.rhs }; |
| 2336 | |
| 2337 | break :result switch (tag) { |
| 2338 | .add => try self.addSub(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| 2339 | .sub => try self.addSub(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| 2340 | |
| 2341 | else => blk: { |
| 2342 | const lhs = try self.resolveInst(bin_op.lhs); |
| 2343 | const rhs = try self.resolveInst(bin_op.rhs); |
| 2344 | |
| 2345 | break :blk try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{ |
| 2346 | .inst = inst, |
| 2347 | .lhs = bin_op.lhs, |
| 2348 | .rhs = bin_op.rhs, |
| 2349 | }); |
| 2350 | }, |
| 2351 | }; |
| 2352 | }; |
| 2322 | 2353 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2323 | 2354 | } |
| 2324 | 2355 | |
| ... | ... | @@ -2364,8 +2395,8 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2364 | 2395 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2365 | 2396 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2366 | 2397 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2367 | | const lhs = try self.resolveInst(extra.lhs); |
| 2368 | | const rhs = try self.resolveInst(extra.rhs); |
| 2398 | const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs }; |
| 2399 | const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs }; |
| 2369 | 2400 | const lhs_ty = self.air.typeOf(extra.lhs); |
| 2370 | 2401 | const rhs_ty = self.air.typeOf(extra.rhs); |
| 2371 | 2402 | |
| ... | ... | @@ -2392,7 +2423,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2392 | 2423 | .sub_with_overflow => .sub, |
| 2393 | 2424 | else => unreachable, |
| 2394 | 2425 | }; |
| 2395 | | const dest = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, null); |
| 2426 | const dest = try self.addSub(base_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, null); |
| 2396 | 2427 | const dest_reg = dest.register; |
| 2397 | 2428 | const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg); |
| 2398 | 2429 | defer self.register_manager.unlockReg(dest_reg_lock); |
| ... | ... | @@ -2422,18 +2453,21 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2422 | 2453 | break :result MCValue{ .stack_offset = stack_offset }; |
| 2423 | 2454 | }, |
| 2424 | 2455 | 32, 64 => { |
| 2456 | const lhs_immediate = try lhs_bind.resolveToImmediate(self); |
| 2457 | const rhs_immediate = try rhs_bind.resolveToImmediate(self); |
| 2458 | |
| 2425 | 2459 | // Only say yes if the operation is |
| 2426 | 2460 | // commutative, i.e. we can swap both of the |
| 2427 | 2461 | // operands |
| 2428 | 2462 | const lhs_immediate_ok = switch (tag) { |
| 2429 | | .add_with_overflow => lhs == .immediate and lhs.immediate <= std.math.maxInt(u12), |
| 2463 | .add_with_overflow => if (lhs_immediate) |imm| imm <= std.math.maxInt(u12) else false, |
| 2430 | 2464 | .sub_with_overflow => false, |
| 2431 | 2465 | else => unreachable, |
| 2432 | 2466 | }; |
| 2433 | 2467 | const rhs_immediate_ok = switch (tag) { |
| 2434 | 2468 | .add_with_overflow, |
| 2435 | 2469 | .sub_with_overflow, |
| 2436 | | => rhs == .immediate and rhs.immediate <= std.math.maxInt(u12), |
| 2470 | => if (rhs_immediate) |imm| imm <= std.math.maxInt(u12) else false, |
| 2437 | 2471 | else => unreachable, |
| 2438 | 2472 | }; |
| 2439 | 2473 | |
| ... | ... | @@ -2453,12 +2487,12 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2453 | 2487 | |
| 2454 | 2488 | const dest = blk: { |
| 2455 | 2489 | if (rhs_immediate_ok) { |
| 2456 | | break :blk try self.binOpImmediate(mir_tag_immediate, lhs, rhs, lhs_ty, false, null); |
| 2490 | break :blk try self.binOpImmediateNew(mir_tag_immediate, lhs_bind, rhs_immediate.?, lhs_ty, false, null); |
| 2457 | 2491 | } else if (lhs_immediate_ok) { |
| 2458 | 2492 | // swap lhs and rhs |
| 2459 | | break :blk try self.binOpImmediate(mir_tag_immediate, rhs, lhs, rhs_ty, true, null); |
| 2493 | break :blk try self.binOpImmediateNew(mir_tag_immediate, rhs_bind, lhs_immediate.?, rhs_ty, true, null); |
| 2460 | 2494 | } else { |
| 2461 | | break :blk try self.binOpRegister(mir_tag_register, lhs, rhs, lhs_ty, rhs_ty, null); |
| 2495 | break :blk try self.binOpRegisterNew(mir_tag_register, lhs_bind, rhs_bind, lhs_ty, rhs_ty, null); |
| 2462 | 2496 | } |
| 2463 | 2497 | }; |
| 2464 | 2498 | |
| ... | ... | @@ -3650,26 +3684,10 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde |
| 3650 | 3684 | break :result MCValue{ .ptr_stack_offset = off - struct_field_offset }; |
| 3651 | 3685 | }, |
| 3652 | 3686 | else => { |
| 3653 | | const offset_reg = try self.copyToTmpRegister(ptr_ty, .{ |
| 3654 | | .immediate = struct_field_offset, |
| 3655 | | }); |
| 3656 | | const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg); |
| 3657 | | defer self.register_manager.unlockReg(offset_reg_lock); |
| 3658 | | |
| 3659 | | const addr_reg = try self.copyToTmpRegister(ptr_ty, mcv); |
| 3660 | | const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| 3661 | | defer self.register_manager.unlockReg(addr_reg_lock); |
| 3687 | const lhs_bind: ReadArg.Bind = .{ .mcv = mcv }; |
| 3688 | const rhs_bind: ReadArg.Bind = .{ .mcv = .{ .immediate = struct_field_offset } }; |
| 3662 | 3689 | |
| 3663 | | const dest = try self.binOp( |
| 3664 | | .add, |
| 3665 | | .{ .register = addr_reg }, |
| 3666 | | .{ .register = offset_reg }, |
| 3667 | | Type.usize, |
| 3668 | | Type.usize, |
| 3669 | | null, |
| 3670 | | ); |
| 3671 | | |
| 3672 | | break :result dest; |
| 3690 | break :result try self.addSub(.add, lhs_bind, rhs_bind, Type.usize, Type.usize, null); |
| 3673 | 3691 | }, |
| 3674 | 3692 | } |
| 3675 | 3693 | }; |