authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-10-20 12:43:41+02:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-10-20 16:14:52+02:00
logdd62d5941ea77f2ae226b28b0da71abeb92f6140
tree794fae2ef3cb26f08f131f01423af33ca99d992e
parent3800bb538a38bfe92f4c8ee49b468169b6bd273b
signaturelock-open Commit is signed but in an unrecognized format.

stage2 AArch64: move remaining operations out of binOp


1 files changed, 208 insertions(+), 196 deletions(-)

src/arch/aarch64/CodeGen.zig+208-196
...@@ -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) and1430 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};
18891893
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.
1902fn 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
2073fn addSub(1894fn 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}
23712192
2193fn 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
2227fn 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
2260fn 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
2311fn 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
2350fn 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
2372fn ptrArithmetic(2376fn 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 {
24412445
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),
24432447
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),
24472451
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 });