| ... | @@ -1582,7 +1582,7 @@ fn binOpImmediateNew( | ... | @@ -1582,7 +1582,7 @@ fn binOpImmediateNew( |
| 1582 | self: *Self, | 1582 | self: *Self, |
| 1583 | mir_tag: Mir.Inst.Tag, | 1583 | mir_tag: Mir.Inst.Tag, |
| 1584 | lhs_bind: ReadArg.Bind, | 1584 | lhs_bind: ReadArg.Bind, |
| 1585 | rhs_immediate: u32, | 1585 | rhs_immediate: u64, |
| 1586 | lhs_ty: Type, | 1586 | lhs_ty: Type, |
| 1587 | lhs_and_rhs_swapped: bool, | 1587 | lhs_and_rhs_swapped: bool, |
| 1588 | maybe_inst: ?Air.Inst.Index, | 1588 | maybe_inst: ?Air.Inst.Index, |
| ... | @@ -1910,57 +1910,6 @@ fn binOp( | ... | @@ -1910,57 +1910,6 @@ fn binOp( |
| 1910 | ) InnerError!MCValue { | 1910 | ) InnerError!MCValue { |
| 1911 | const mod = self.bin_file.options.module.?; | 1911 | const mod = self.bin_file.options.module.?; |
| 1912 | switch (tag) { | 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 | .mul => { | 1913 | .mul => { |
| 1965 | switch (lhs_ty.zigTypeTag()) { | 1914 | switch (lhs_ty.zigTypeTag()) { |
| 1966 | .Vector => return self.fail("TODO binary operations on vectors", .{}), | 1915 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| ... | @@ -2134,8 +2083,18 @@ fn binOp( | ... | @@ -2134,8 +2083,18 @@ fn binOp( |
| 2134 | else => unreachable, | 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 | // Generate an add/sub/mul | 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 | // Truncate if necessary | 2099 | // Truncate if necessary |
| 2141 | switch (lhs_ty.zigTypeTag()) { | 2100 | switch (lhs_ty.zigTypeTag()) { |
| ... | @@ -2304,21 +2263,93 @@ fn binOp( | ... | @@ -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 | fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { | 2328 | fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 2308 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 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 | const lhs_ty = self.air.typeOf(bin_op.lhs); | 2330 | const lhs_ty = self.air.typeOf(bin_op.lhs); |
| 2312 | const rhs_ty = self.air.typeOf(bin_op.rhs); | 2331 | const rhs_ty = self.air.typeOf(bin_op.rhs); |
| 2313 | | 2332 | |
| 2314 | const result: MCValue = if (self.liveness.isUnused(inst)) | 2333 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2315 | .dead | 2334 | const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs }; |
| 2316 | else | 2335 | const rhs_bind: ReadArg.Bind = .{ .inst = bin_op.rhs }; |
| 2317 | try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{ | 2336 | |
| 2318 | .inst = inst, | 2337 | break :result switch (tag) { |
| 2319 | .lhs = bin_op.lhs, | 2338 | .add => try self.addSub(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| 2320 | .rhs = bin_op.rhs, | 2339 | .sub => try self.addSub(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| 2321 | }); | 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 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 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,8 +2395,8 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2364 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 2395 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2365 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; | 2396 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2366 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2397 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2367 | const lhs = try self.resolveInst(extra.lhs); | 2398 | const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs }; |
| 2368 | const rhs = try self.resolveInst(extra.rhs); | 2399 | const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs }; |
| 2369 | const lhs_ty = self.air.typeOf(extra.lhs); | 2400 | const lhs_ty = self.air.typeOf(extra.lhs); |
| 2370 | const rhs_ty = self.air.typeOf(extra.rhs); | 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,7 +2423,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2392 | .sub_with_overflow => .sub, | 2423 | .sub_with_overflow => .sub, |
| 2393 | else => unreachable, | 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 | const dest_reg = dest.register; | 2427 | const dest_reg = dest.register; |
| 2397 | const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg); | 2428 | const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg); |
| 2398 | defer self.register_manager.unlockReg(dest_reg_lock); | 2429 | defer self.register_manager.unlockReg(dest_reg_lock); |
| ... | @@ -2422,18 +2453,21 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2422,18 +2453,21 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2422 | break :result MCValue{ .stack_offset = stack_offset }; | 2453 | break :result MCValue{ .stack_offset = stack_offset }; |
| 2423 | }, | 2454 | }, |
| 2424 | 32, 64 => { | 2455 | 32, 64 => { |
| | 2456 | const lhs_immediate = try lhs_bind.resolveToImmediate(self); |
| | 2457 | const rhs_immediate = try rhs_bind.resolveToImmediate(self); |
| | 2458 | |
| 2425 | // Only say yes if the operation is | 2459 | // Only say yes if the operation is |
| 2426 | // commutative, i.e. we can swap both of the | 2460 | // commutative, i.e. we can swap both of the |
| 2427 | // operands | 2461 | // operands |
| 2428 | const lhs_immediate_ok = switch (tag) { | 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 | .sub_with_overflow => false, | 2464 | .sub_with_overflow => false, |
| 2431 | else => unreachable, | 2465 | else => unreachable, |
| 2432 | }; | 2466 | }; |
| 2433 | const rhs_immediate_ok = switch (tag) { | 2467 | const rhs_immediate_ok = switch (tag) { |
| 2434 | .add_with_overflow, | 2468 | .add_with_overflow, |
| 2435 | .sub_with_overflow, | 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 | else => unreachable, | 2471 | else => unreachable, |
| 2438 | }; | 2472 | }; |
| 2439 | | 2473 | |
| ... | @@ -2453,12 +2487,12 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2453,12 +2487,12 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2453 | | 2487 | |
| 2454 | const dest = blk: { | 2488 | const dest = blk: { |
| 2455 | if (rhs_immediate_ok) { | 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 | } else if (lhs_immediate_ok) { | 2491 | } else if (lhs_immediate_ok) { |
| 2458 | // swap lhs and rhs | 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 | } else { | 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,26 +3684,10 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde |
| 3650 | break :result MCValue{ .ptr_stack_offset = off - struct_field_offset }; | 3684 | break :result MCValue{ .ptr_stack_offset = off - struct_field_offset }; |
| 3651 | }, | 3685 | }, |
| 3652 | else => { | 3686 | else => { |
| 3653 | const offset_reg = try self.copyToTmpRegister(ptr_ty, .{ | 3687 | const lhs_bind: ReadArg.Bind = .{ .mcv = mcv }; |
| 3654 | .immediate = struct_field_offset, | 3688 | const rhs_bind: ReadArg.Bind = .{ .mcv = .{ .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); | | |
| 3662 | | 3689 | |
| 3663 | const dest = try self.binOp( | 3690 | break :result try self.addSub(.add, lhs_bind, rhs_bind, Type.usize, Type.usize, null); |
| 3664 | .add, | | |
| 3665 | .{ .register = addr_reg }, | | |
| 3666 | .{ .register = offset_reg }, | | |
| 3667 | Type.usize, | | |
| 3668 | Type.usize, | | |
| 3669 | null, | | |
| 3670 | ); | | |
| 3671 | | | |
| 3672 | break :result dest; | | |
| 3673 | }, | 3691 | }, |
| 3674 | } | 3692 | } |
| 3675 | }; | 3693 | }; |