| ... | @@ -1401,7 +1401,8 @@ fn allocRegs( | ... | @@ -1401,7 +1401,8 @@ fn allocRegs( |
| 1401 | for (read_args) |arg, i| { | 1401 | for (read_args) |arg, i| { |
| 1402 | const mcv = try arg.bind.resolveToMcv(self); | 1402 | const mcv = try arg.bind.resolveToMcv(self); |
| 1403 | if (mcv == .register) { | 1403 | if (mcv == .register) { |
| 1404 | arg.reg.* = mcv.register; | 1404 | const raw_reg = mcv.register; |
| | 1405 | arg.reg.* = self.registerAlias(raw_reg, arg.ty); |
| 1405 | } else { | 1406 | } else { |
| 1406 | const track_inst: ?Air.Inst.Index = switch (arg.bind) { | 1407 | const track_inst: ?Air.Inst.Index = switch (arg.bind) { |
| 1407 | .inst => |inst| Air.refToIndex(inst).?, | 1408 | .inst => |inst| Air.refToIndex(inst).?, |
| ... | @@ -1418,7 +1419,8 @@ fn allocRegs( | ... | @@ -1418,7 +1419,8 @@ fn allocRegs( |
| 1418 | const operand_mapping = reuse_metadata.?.operand_mapping; | 1419 | const operand_mapping = reuse_metadata.?.operand_mapping; |
| 1419 | const arg = write_args[0]; | 1420 | const arg = write_args[0]; |
| 1420 | if (arg.bind == .reg) { | 1421 | if (arg.bind == .reg) { |
| 1421 | arg.reg.* = arg.bind.reg; | 1422 | const raw_reg = arg.bind.reg; |
| | 1423 | arg.reg.* = self.registerAlias(raw_reg, arg.ty); |
| 1422 | } else { | 1424 | } else { |
| 1423 | reuse_operand: for (read_args) |read_arg, i| { | 1425 | reuse_operand: for (read_args) |read_arg, i| { |
| 1424 | if (read_arg.bind == .inst) { | 1426 | if (read_arg.bind == .inst) { |
| ... | @@ -1428,7 +1430,8 @@ fn allocRegs( | ... | @@ -1428,7 +1430,8 @@ fn allocRegs( |
| 1428 | std.meta.eql(arg.class, read_arg.class) and | 1430 | std.meta.eql(arg.class, read_arg.class) and |
| 1429 | self.reuseOperand(inst, operand, operand_mapping[i], mcv)) | 1431 | self.reuseOperand(inst, operand, operand_mapping[i], mcv)) |
| 1430 | { | 1432 | { |
| 1431 | arg.reg.* = mcv.register; | 1433 | const raw_reg = mcv.register; |
| | 1434 | arg.reg.* = self.registerAlias(raw_reg, arg.ty); |
| 1432 | write_locks[0] = null; | 1435 | write_locks[0] = null; |
| 1433 | reused_read_arg = i; | 1436 | reused_read_arg = i; |
| 1434 | break :reuse_operand; | 1437 | break :reuse_operand; |
| ... | @@ -1443,7 +1446,8 @@ fn allocRegs( | ... | @@ -1443,7 +1446,8 @@ fn allocRegs( |
| 1443 | } else { | 1446 | } else { |
| 1444 | for (write_args) |arg, i| { | 1447 | for (write_args) |arg, i| { |
| 1445 | if (arg.bind == .reg) { | 1448 | if (arg.bind == .reg) { |
| 1446 | arg.reg.* = arg.bind.reg; | 1449 | const raw_reg = arg.bind.reg; |
| | 1450 | arg.reg.* = self.registerAlias(raw_reg, arg.ty); |
| 1447 | } else { | 1451 | } else { |
| 1448 | const raw_reg = try self.register_manager.allocReg(null, arg.class); | 1452 | const raw_reg = try self.register_manager.allocReg(null, arg.class); |
| 1449 | arg.reg.* = self.registerAlias(raw_reg, arg.ty); | 1453 | arg.reg.* = self.registerAlias(raw_reg, arg.ty); |
| ... | @@ -1887,189 +1891,6 @@ const BinOpMetadata = struct { | ... | @@ -1887,189 +1891,6 @@ const BinOpMetadata = struct { |
| 1887 | rhs: Air.Inst.Ref, | 1891 | rhs: Air.Inst.Ref, |
| 1888 | }; | 1892 | }; |
| 1889 | | 1893 | |
| 1890 | /// For all your binary operation needs, this function will generate | | |
| 1891 | /// the corresponding Mir instruction(s). Returns the location of the | | |
| 1892 | /// result. | | |
| 1893 | /// | | |
| 1894 | /// If the binary operation itself happens to be an Air instruction, | | |
| 1895 | /// pass the corresponding index in the inst parameter. That helps | | |
| 1896 | /// this function do stuff like reusing operands. | | |
| 1897 | /// | | |
| 1898 | /// This function does not do any lowering to Mir itself, but instead | | |
| 1899 | /// looks at the lhs and rhs and determines which kind of lowering | | |
| 1900 | /// would be best suitable and then delegates the lowering to other | | |
| 1901 | /// functions. | | |
| 1902 | fn binOp( | | |
| 1903 | self: *Self, | | |
| 1904 | tag: Air.Inst.Tag, | | |
| 1905 | lhs: MCValue, | | |
| 1906 | rhs: MCValue, | | |
| 1907 | lhs_ty: Type, | | |
| 1908 | rhs_ty: Type, | | |
| 1909 | metadata: ?BinOpMetadata, | | |
| 1910 | ) InnerError!MCValue { | | |
| 1911 | const mod = self.bin_file.options.module.?; | | |
| 1912 | switch (tag) { | | |
| 1913 | .addwrap, | | |
| 1914 | .subwrap, | | |
| 1915 | .mulwrap, | | |
| 1916 | => { | | |
| 1917 | const base_tag: Air.Inst.Tag = switch (tag) { | | |
| 1918 | .addwrap => .add, | | |
| 1919 | .subwrap => .sub, | | |
| 1920 | .mulwrap => .mul, | | |
| 1921 | else => unreachable, | | |
| 1922 | }; | | |
| 1923 | | | |
| 1924 | const lhs_bind = if (metadata) |md| | | |
| 1925 | ReadArg.Bind{ .inst = md.lhs } | | |
| 1926 | else | | |
| 1927 | ReadArg.Bind{ .mcv = lhs }; | | |
| 1928 | const rhs_bind = if (metadata) |md| | | |
| 1929 | ReadArg.Bind{ .inst = md.rhs } | | |
| 1930 | else | | |
| 1931 | ReadArg.Bind{ .mcv = rhs }; | | |
| 1932 | | | |
| 1933 | // Generate an add/sub/mul | | |
| 1934 | const maybe_inst: ?Air.Inst.Index = if (metadata) |md| md.inst else null; | | |
| 1935 | const result = try self.addSub(base_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); | | |
| 1936 | | | |
| 1937 | // Truncate if necessary | | |
| 1938 | switch (lhs_ty.zigTypeTag()) { | | |
| 1939 | .Vector => return self.fail("TODO binary operations on vectors", .{}), | | |
| 1940 | .Int => { | | |
| 1941 | const int_info = lhs_ty.intInfo(self.target.*); | | |
| 1942 | if (int_info.bits <= 64) { | | |
| 1943 | const result_reg = result.register; | | |
| 1944 | try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits); | | |
| 1945 | return result; | | |
| 1946 | } else { | | |
| 1947 | return self.fail("TODO binary operations on integers > u64/i64", .{}); | | |
| 1948 | } | | |
| 1949 | }, | | |
| 1950 | else => unreachable, | | |
| 1951 | } | | |
| 1952 | }, | | |
| 1953 | .bit_and, | | |
| 1954 | .bit_or, | | |
| 1955 | .xor, | | |
| 1956 | => { | | |
| 1957 | switch (lhs_ty.zigTypeTag()) { | | |
| 1958 | .Vector => return self.fail("TODO binary operations on vectors", .{}), | | |
| 1959 | .Int => { | | |
| 1960 | assert(lhs_ty.eql(rhs_ty, mod)); | | |
| 1961 | const int_info = lhs_ty.intInfo(self.target.*); | | |
| 1962 | if (int_info.bits <= 64) { | | |
| 1963 | // TODO implement bitwise operations with immediates | | |
| 1964 | const mir_tag: Mir.Inst.Tag = switch (tag) { | | |
| 1965 | .bit_and => .and_shifted_register, | | |
| 1966 | .bit_or => .orr_shifted_register, | | |
| 1967 | .xor => .eor_shifted_register, | | |
| 1968 | else => unreachable, | | |
| 1969 | }; | | |
| 1970 | | | |
| 1971 | return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata); | | |
| 1972 | } else { | | |
| 1973 | return self.fail("TODO binary operations on int with bits > 64", .{}); | | |
| 1974 | } | | |
| 1975 | }, | | |
| 1976 | else => unreachable, | | |
| 1977 | } | | |
| 1978 | }, | | |
| 1979 | .shl_exact, | | |
| 1980 | .shr_exact, | | |
| 1981 | => { | | |
| 1982 | switch (lhs_ty.zigTypeTag()) { | | |
| 1983 | .Vector => return self.fail("TODO binary operations on vectors", .{}), | | |
| 1984 | .Int => { | | |
| 1985 | const int_info = lhs_ty.intInfo(self.target.*); | | |
| 1986 | if (int_info.bits <= 64) { | | |
| 1987 | const rhs_immediate_ok = rhs == .immediate; | | |
| 1988 | | | |
| 1989 | const mir_tag_register: Mir.Inst.Tag = switch (tag) { | | |
| 1990 | .shl_exact => .lsl_register, | | |
| 1991 | .shr_exact => switch (int_info.signedness) { | | |
| 1992 | .signed => Mir.Inst.Tag.asr_register, | | |
| 1993 | .unsigned => Mir.Inst.Tag.lsr_register, | | |
| 1994 | }, | | |
| 1995 | else => unreachable, | | |
| 1996 | }; | | |
| 1997 | const mir_tag_immediate: Mir.Inst.Tag = switch (tag) { | | |
| 1998 | .shl_exact => .lsl_immediate, | | |
| 1999 | .shr_exact => switch (int_info.signedness) { | | |
| 2000 | .signed => Mir.Inst.Tag.asr_immediate, | | |
| 2001 | .unsigned => Mir.Inst.Tag.lsr_immediate, | | |
| 2002 | }, | | |
| 2003 | else => unreachable, | | |
| 2004 | }; | | |
| 2005 | | | |
| 2006 | if (rhs_immediate_ok) { | | |
| 2007 | return try self.binOpImmediate(mir_tag_immediate, lhs, rhs, lhs_ty, false, metadata); | | |
| 2008 | } else { | | |
| 2009 | return try self.binOpRegister(mir_tag_register, lhs, rhs, lhs_ty, rhs_ty, metadata); | | |
| 2010 | } | | |
| 2011 | } else { | | |
| 2012 | return self.fail("TODO binary operations on int with bits > 64", .{}); | | |
| 2013 | } | | |
| 2014 | }, | | |
| 2015 | else => unreachable, | | |
| 2016 | } | | |
| 2017 | }, | | |
| 2018 | .shl, | | |
| 2019 | .shr, | | |
| 2020 | => { | | |
| 2021 | const base_tag: Air.Inst.Tag = switch (tag) { | | |
| 2022 | .shl => .shl_exact, | | |
| 2023 | .shr => .shr_exact, | | |
| 2024 | else => unreachable, | | |
| 2025 | }; | | |
| 2026 | | | |
| 2027 | // Generate a shl_exact/shr_exact | | |
| 2028 | const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata); | | |
| 2029 | | | |
| 2030 | // Truncate if necessary | | |
| 2031 | switch (tag) { | | |
| 2032 | .shr => return result, | | |
| 2033 | .shl => switch (lhs_ty.zigTypeTag()) { | | |
| 2034 | .Vector => return self.fail("TODO binary operations on vectors", .{}), | | |
| 2035 | .Int => { | | |
| 2036 | const int_info = lhs_ty.intInfo(self.target.*); | | |
| 2037 | if (int_info.bits <= 64) { | | |
| 2038 | const result_reg = result.register; | | |
| 2039 | try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits); | | |
| 2040 | return result; | | |
| 2041 | } else { | | |
| 2042 | return self.fail("TODO binary operations on integers > u64/i64", .{}); | | |
| 2043 | } | | |
| 2044 | }, | | |
| 2045 | else => unreachable, | | |
| 2046 | }, | | |
| 2047 | else => unreachable, | | |
| 2048 | } | | |
| 2049 | }, | | |
| 2050 | .bool_and, | | |
| 2051 | .bool_or, | | |
| 2052 | => { | | |
| 2053 | switch (lhs_ty.zigTypeTag()) { | | |
| 2054 | .Bool => { | | |
| 2055 | assert(lhs != .immediate); // should have been handled by Sema | | |
| 2056 | assert(rhs != .immediate); // should have been handled by Sema | | |
| 2057 | | | |
| 2058 | const mir_tag_register: Mir.Inst.Tag = switch (tag) { | | |
| 2059 | .bool_and => .and_shifted_register, | | |
| 2060 | .bool_or => .orr_shifted_register, | | |
| 2061 | else => unreachable, | | |
| 2062 | }; | | |
| 2063 | | | |
| 2064 | return try self.binOpRegister(mir_tag_register, lhs, rhs, lhs_ty, rhs_ty, metadata); | | |
| 2065 | }, | | |
| 2066 | else => unreachable, | | |
| 2067 | } | | |
| 2068 | }, | | |
| 2069 | else => unreachable, | | |
| 2070 | } | | |
| 2071 | } | | |
| 2072 | | | |
| 2073 | fn addSub( | 1894 | fn addSub( |
| 2074 | self: *Self, | 1895 | self: *Self, |
| 2075 | tag: Air.Inst.Tag, | 1896 | tag: Air.Inst.Tag, |
| ... | @@ -2369,6 +2190,189 @@ fn modulo( | ... | @@ -2369,6 +2190,189 @@ fn modulo( |
| 2369 | } | 2190 | } |
| 2370 | } | 2191 | } |
| 2371 | | 2192 | |
| | 2193 | fn wrappingArithmetic( |
| | 2194 | self: *Self, |
| | 2195 | tag: Air.Inst.Tag, |
| | 2196 | lhs_bind: ReadArg.Bind, |
| | 2197 | rhs_bind: ReadArg.Bind, |
| | 2198 | lhs_ty: Type, |
| | 2199 | rhs_ty: Type, |
| | 2200 | maybe_inst: ?Air.Inst.Index, |
| | 2201 | ) InnerError!MCValue { |
| | 2202 | switch (lhs_ty.zigTypeTag()) { |
| | 2203 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| | 2204 | .Int => { |
| | 2205 | const int_info = lhs_ty.intInfo(self.target.*); |
| | 2206 | if (int_info.bits <= 64) { |
| | 2207 | // Generate an add/sub/mul |
| | 2208 | const result: MCValue = switch (tag) { |
| | 2209 | .addwrap => try self.addSub(.add, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst), |
| | 2210 | .subwrap => try self.addSub(.sub, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst), |
| | 2211 | .mulwrap => try self.mul(lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst), |
| | 2212 | else => unreachable, |
| | 2213 | }; |
| | 2214 | |
| | 2215 | // Truncate if necessary |
| | 2216 | const result_reg = result.register; |
| | 2217 | try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits); |
| | 2218 | return result; |
| | 2219 | } else { |
| | 2220 | return self.fail("TODO binary operations on integers > u64/i64", .{}); |
| | 2221 | } |
| | 2222 | }, |
| | 2223 | else => unreachable, |
| | 2224 | } |
| | 2225 | } |
| | 2226 | |
| | 2227 | fn bitwise( |
| | 2228 | self: *Self, |
| | 2229 | tag: Air.Inst.Tag, |
| | 2230 | lhs_bind: ReadArg.Bind, |
| | 2231 | rhs_bind: ReadArg.Bind, |
| | 2232 | lhs_ty: Type, |
| | 2233 | rhs_ty: Type, |
| | 2234 | maybe_inst: ?Air.Inst.Index, |
| | 2235 | ) InnerError!MCValue { |
| | 2236 | const mod = self.bin_file.options.module.?; |
| | 2237 | switch (lhs_ty.zigTypeTag()) { |
| | 2238 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| | 2239 | .Int => { |
| | 2240 | assert(lhs_ty.eql(rhs_ty, mod)); |
| | 2241 | const int_info = lhs_ty.intInfo(self.target.*); |
| | 2242 | if (int_info.bits <= 64) { |
| | 2243 | // TODO implement bitwise operations with immediates |
| | 2244 | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| | 2245 | .bit_and => .and_shifted_register, |
| | 2246 | .bit_or => .orr_shifted_register, |
| | 2247 | .xor => .eor_shifted_register, |
| | 2248 | else => unreachable, |
| | 2249 | }; |
| | 2250 | |
| | 2251 | return try self.binOpRegisterNew(mir_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); |
| | 2252 | } else { |
| | 2253 | return self.fail("TODO binary operations on int with bits > 64", .{}); |
| | 2254 | } |
| | 2255 | }, |
| | 2256 | else => unreachable, |
| | 2257 | } |
| | 2258 | } |
| | 2259 | |
| | 2260 | fn shiftExact( |
| | 2261 | self: *Self, |
| | 2262 | tag: Air.Inst.Tag, |
| | 2263 | lhs_bind: ReadArg.Bind, |
| | 2264 | rhs_bind: ReadArg.Bind, |
| | 2265 | lhs_ty: Type, |
| | 2266 | rhs_ty: Type, |
| | 2267 | maybe_inst: ?Air.Inst.Index, |
| | 2268 | ) InnerError!MCValue { |
| | 2269 | _ = rhs_ty; |
| | 2270 | |
| | 2271 | switch (lhs_ty.zigTypeTag()) { |
| | 2272 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| | 2273 | .Int => { |
| | 2274 | const int_info = lhs_ty.intInfo(self.target.*); |
| | 2275 | if (int_info.bits <= 64) { |
| | 2276 | const rhs_immediate = try rhs_bind.resolveToImmediate(self); |
| | 2277 | |
| | 2278 | const mir_tag_register: Mir.Inst.Tag = switch (tag) { |
| | 2279 | .shl_exact => .lsl_register, |
| | 2280 | .shr_exact => switch (int_info.signedness) { |
| | 2281 | .signed => Mir.Inst.Tag.asr_register, |
| | 2282 | .unsigned => Mir.Inst.Tag.lsr_register, |
| | 2283 | }, |
| | 2284 | else => unreachable, |
| | 2285 | }; |
| | 2286 | const mir_tag_immediate: Mir.Inst.Tag = switch (tag) { |
| | 2287 | .shl_exact => .lsl_immediate, |
| | 2288 | .shr_exact => switch (int_info.signedness) { |
| | 2289 | .signed => Mir.Inst.Tag.asr_immediate, |
| | 2290 | .unsigned => Mir.Inst.Tag.lsr_immediate, |
| | 2291 | }, |
| | 2292 | else => unreachable, |
| | 2293 | }; |
| | 2294 | |
| | 2295 | if (rhs_immediate) |imm| { |
| | 2296 | return try self.binOpImmediateNew(mir_tag_immediate, lhs_bind, imm, lhs_ty, false, maybe_inst); |
| | 2297 | } else { |
| | 2298 | // We intentionally pass lhs_ty here in order to |
| | 2299 | // prevent using the 32-bit register alias when |
| | 2300 | // lhs_ty is > 32 bits. |
| | 2301 | return try self.binOpRegisterNew(mir_tag_register, lhs_bind, rhs_bind, lhs_ty, lhs_ty, maybe_inst); |
| | 2302 | } |
| | 2303 | } else { |
| | 2304 | return self.fail("TODO binary operations on int with bits > 64", .{}); |
| | 2305 | } |
| | 2306 | }, |
| | 2307 | else => unreachable, |
| | 2308 | } |
| | 2309 | } |
| | 2310 | |
| | 2311 | fn shiftNormal( |
| | 2312 | self: *Self, |
| | 2313 | tag: Air.Inst.Tag, |
| | 2314 | lhs_bind: ReadArg.Bind, |
| | 2315 | rhs_bind: ReadArg.Bind, |
| | 2316 | lhs_ty: Type, |
| | 2317 | rhs_ty: Type, |
| | 2318 | maybe_inst: ?Air.Inst.Index, |
| | 2319 | ) InnerError!MCValue { |
| | 2320 | switch (lhs_ty.zigTypeTag()) { |
| | 2321 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| | 2322 | .Int => { |
| | 2323 | const int_info = lhs_ty.intInfo(self.target.*); |
| | 2324 | if (int_info.bits <= 64) { |
| | 2325 | // Generate a shl_exact/shr_exact |
| | 2326 | const result: MCValue = switch (tag) { |
| | 2327 | .shl => try self.shiftExact(.shl_exact, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst), |
| | 2328 | .shr => try self.shiftExact(.shr_exact, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst), |
| | 2329 | else => unreachable, |
| | 2330 | }; |
| | 2331 | |
| | 2332 | // Truncate if necessary |
| | 2333 | switch (tag) { |
| | 2334 | .shr => return result, |
| | 2335 | .shl => { |
| | 2336 | const result_reg = result.register; |
| | 2337 | try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits); |
| | 2338 | return result; |
| | 2339 | }, |
| | 2340 | else => unreachable, |
| | 2341 | } |
| | 2342 | } else { |
| | 2343 | return self.fail("TODO binary operations on integers > u64/i64", .{}); |
| | 2344 | } |
| | 2345 | }, |
| | 2346 | else => unreachable, |
| | 2347 | } |
| | 2348 | } |
| | 2349 | |
| | 2350 | fn booleanOp( |
| | 2351 | self: *Self, |
| | 2352 | tag: Air.Inst.Tag, |
| | 2353 | lhs_bind: ReadArg.Bind, |
| | 2354 | rhs_bind: ReadArg.Bind, |
| | 2355 | lhs_ty: Type, |
| | 2356 | rhs_ty: Type, |
| | 2357 | maybe_inst: ?Air.Inst.Index, |
| | 2358 | ) InnerError!MCValue { |
| | 2359 | switch (lhs_ty.zigTypeTag()) { |
| | 2360 | .Bool => { |
| | 2361 | assert((try lhs_bind.resolveToImmediate(self)) == null); // should have been handled by Sema |
| | 2362 | assert((try rhs_bind.resolveToImmediate(self)) == null); // should have been handled by Sema |
| | 2363 | |
| | 2364 | const mir_tag_register: Mir.Inst.Tag = switch (tag) { |
| | 2365 | .bool_and => .and_shifted_register, |
| | 2366 | .bool_or => .orr_shifted_register, |
| | 2367 | else => unreachable, |
| | 2368 | }; |
| | 2369 | |
| | 2370 | return try self.binOpRegisterNew(mir_tag_register, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); |
| | 2371 | }, |
| | 2372 | else => unreachable, |
| | 2373 | } |
| | 2374 | } |
| | 2375 | |
| 2372 | fn ptrArithmetic( | 2376 | fn ptrArithmetic( |
| 2373 | self: *Self, | 2377 | self: *Self, |
| 2374 | tag: Air.Inst.Tag, | 2378 | tag: Air.Inst.Tag, |
| ... | @@ -2441,16 +2445,24 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { | ... | @@ -2441,16 +2445,24 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 2441 | | 2445 | |
| 2442 | .mod => try self.modulo(lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), | 2446 | .mod => try self.modulo(lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| 2443 | | 2447 | |
| 2444 | else => blk: { | 2448 | .addwrap => try self.wrappingArithmetic(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| 2445 | const lhs = try self.resolveInst(bin_op.lhs); | 2449 | .subwrap => try self.wrappingArithmetic(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| 2446 | const rhs = try self.resolveInst(bin_op.rhs); | 2450 | .mulwrap => try self.wrappingArithmetic(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| 2447 | | 2451 | |
| 2448 | break :blk try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{ | 2452 | .bit_and => try self.bitwise(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| 2449 | .inst = inst, | 2453 | .bit_or => try self.bitwise(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| 2450 | .lhs = bin_op.lhs, | 2454 | .xor => try self.bitwise(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| 2451 | .rhs = bin_op.rhs, | 2455 | |
| 2452 | }); | 2456 | .shl_exact => try self.shiftExact(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| 2453 | }, | 2457 | .shr_exact => try self.shiftExact(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| | 2458 | |
| | 2459 | .shl => try self.shiftNormal(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| | 2460 | .shr => try self.shiftNormal(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| | 2461 | |
| | 2462 | .bool_and => try self.booleanOp(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| | 2463 | .bool_or => try self.booleanOp(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| | 2464 | |
| | 2465 | else => unreachable, |
| 2454 | }; | 2466 | }; |
| 2455 | }; | 2467 | }; |
| 2456 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 2468 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |