authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-10-19 15:24:58+02:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-10-20 16:14:52+02:00
log3800bb538a38bfe92f4c8ee49b468169b6bd273b
tree94a46544d61edbcfba06e64e13976e481c0d0a98
parentea7a60116d2ddb30a1684b67d892cb72f631a9f3
signaturelock-open Commit is signed but in an unrecognized format.

stage2 AArch64: mov mul,div,mod to new allocRegs mechanism


1 files changed, 340 insertions(+), 244 deletions(-)

src/arch/aarch64/CodeGen.zig+340-244
...@@ -1910,168 +1910,6 @@ fn binOp(...@@ -1910,168 +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 .mul => {
1914 switch (lhs_ty.zigTypeTag()) {
1915 .Vector => return self.fail("TODO binary operations on vectors", .{}),
1916 .Int => {
1917 assert(lhs_ty.eql(rhs_ty, mod));
1918 const int_info = lhs_ty.intInfo(self.target.*);
1919 if (int_info.bits <= 64) {
1920 // TODO add optimisations for multiplication
1921 // with immediates, for example a * 2 can be
1922 // lowered to a << 1
1923 return try self.binOpRegister(.mul, lhs, rhs, lhs_ty, rhs_ty, metadata);
1924 } else {
1925 return self.fail("TODO binary operations on int with bits > 64", .{});
1926 }
1927 },
1928 else => unreachable,
1929 }
1930 },
1931 .div_float => {
1932 switch (lhs_ty.zigTypeTag()) {
1933 .Float => return self.fail("TODO div_float", .{}),
1934 .Vector => return self.fail("TODO div_float on vectors", .{}),
1935 else => unreachable,
1936 }
1937 },
1938 .div_trunc, .div_floor, .div_exact => {
1939 switch (lhs_ty.zigTypeTag()) {
1940 .Float => return self.fail("TODO div on floats", .{}),
1941 .Vector => return self.fail("TODO div on vectors", .{}),
1942 .Int => {
1943 assert(lhs_ty.eql(rhs_ty, mod));
1944 const int_info = lhs_ty.intInfo(self.target.*);
1945 if (int_info.bits <= 64) {
1946 switch (int_info.signedness) {
1947 .signed => {
1948 switch (tag) {
1949 .div_trunc, .div_exact => {
1950 // TODO optimize integer division by constants
1951 return try self.binOpRegister(.sdiv, lhs, rhs, lhs_ty, rhs_ty, metadata);
1952 },
1953 .div_floor => return self.fail("TODO div_floor on signed integers", .{}),
1954 else => unreachable,
1955 }
1956 },
1957 .unsigned => {
1958 // TODO optimize integer division by constants
1959 return try self.binOpRegister(.udiv, lhs, rhs, lhs_ty, rhs_ty, metadata);
1960 },
1961 }
1962 } else {
1963 return self.fail("TODO integer division for ints with bits > 64", .{});
1964 }
1965 },
1966 else => unreachable,
1967 }
1968 },
1969 .rem, .mod => {
1970 switch (lhs_ty.zigTypeTag()) {
1971 .Float => return self.fail("TODO rem/mod on floats", .{}),
1972 .Vector => return self.fail("TODO rem/mod on vectors", .{}),
1973 .Int => {
1974 assert(lhs_ty.eql(rhs_ty, mod));
1975 const int_info = lhs_ty.intInfo(self.target.*);
1976 if (int_info.bits <= 64) {
1977 if (int_info.signedness == .signed and tag == .mod) {
1978 return self.fail("TODO mod on signed integers", .{});
1979 } else {
1980 const lhs_is_register = lhs == .register;
1981 const rhs_is_register = rhs == .register;
1982
1983 const lhs_lock: ?RegisterLock = if (lhs_is_register)
1984 self.register_manager.lockReg(lhs.register)
1985 else
1986 null;
1987 defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg);
1988
1989 const rhs_lock: ?RegisterLock = if (rhs_is_register)
1990 self.register_manager.lockReg(rhs.register)
1991 else
1992 null;
1993 defer if (rhs_lock) |reg| self.register_manager.unlockReg(reg);
1994
1995 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
1996
1997 const lhs_reg = if (lhs_is_register) lhs.register else blk: {
1998 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {
1999 break :inst Air.refToIndex(md.lhs).?;
2000 } else null;
2001
2002 const raw_reg = try self.register_manager.allocReg(track_inst, gp);
2003 const reg = self.registerAlias(raw_reg, lhs_ty);
2004
2005 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
2006
2007 break :blk reg;
2008 };
2009 const new_lhs_lock = self.register_manager.lockReg(lhs_reg);
2010 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);
2011
2012 const rhs_reg = if (rhs_is_register) rhs.register else blk: {
2013 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {
2014 break :inst Air.refToIndex(md.rhs).?;
2015 } else null;
2016
2017 const raw_reg = try self.register_manager.allocReg(track_inst, gp);
2018 const reg = self.registerAlias(raw_reg, rhs_ty);
2019
2020 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
2021
2022 break :blk reg;
2023 };
2024 const new_rhs_lock = self.register_manager.lockReg(rhs_reg);
2025 defer if (new_rhs_lock) |reg| self.register_manager.unlockReg(reg);
2026
2027 const dest_regs: [2]Register = blk: {
2028 const raw_regs = try self.register_manager.allocRegs(2, .{ null, null }, gp);
2029 break :blk .{
2030 self.registerAlias(raw_regs[0], lhs_ty),
2031 self.registerAlias(raw_regs[1], lhs_ty),
2032 };
2033 };
2034 const dest_regs_locks = self.register_manager.lockRegsAssumeUnused(2, dest_regs);
2035 defer for (dest_regs_locks) |reg| {
2036 self.register_manager.unlockReg(reg);
2037 };
2038 const quotient_reg = dest_regs[0];
2039 const remainder_reg = dest_regs[1];
2040
2041 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);
2042 if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs);
2043
2044 _ = try self.addInst(.{
2045 .tag = switch (int_info.signedness) {
2046 .signed => .sdiv,
2047 .unsigned => .udiv,
2048 },
2049 .data = .{ .rrr = .{
2050 .rd = quotient_reg,
2051 .rn = lhs_reg,
2052 .rm = rhs_reg,
2053 } },
2054 });
2055
2056 _ = try self.addInst(.{
2057 .tag = .msub,
2058 .data = .{ .rrrr = .{
2059 .rd = remainder_reg,
2060 .rn = quotient_reg,
2061 .rm = rhs_reg,
2062 .ra = lhs_reg,
2063 } },
2064 });
2065
2066 return MCValue{ .register = remainder_reg };
2067 }
2068 } else {
2069 return self.fail("TODO rem/mod for integers with bits > 64", .{});
2070 }
2071 },
2072 else => unreachable,
2073 }
2074 },
2075 .addwrap,1913 .addwrap,
2076 .subwrap,1914 .subwrap,
2077 .mulwrap,1915 .mulwrap,
...@@ -2228,37 +2066,6 @@ fn binOp(...@@ -2228,37 +2066,6 @@ fn binOp(
2228 else => unreachable,2066 else => unreachable,
2229 }2067 }
2230 },2068 },
2231 .ptr_add,
2232 .ptr_sub,
2233 => {
2234 switch (lhs_ty.zigTypeTag()) {
2235 .Pointer => {
2236 const ptr_ty = lhs_ty;
2237 const elem_ty = switch (ptr_ty.ptrSize()) {
2238 .One => ptr_ty.childType().childType(), // ptr to array, so get array element type
2239 else => ptr_ty.childType(),
2240 };
2241 const elem_size = elem_ty.abiSize(self.target.*);
2242
2243 if (elem_size == 1) {
2244 const base_tag: Mir.Inst.Tag = switch (tag) {
2245 .ptr_add => .add_shifted_register,
2246 .ptr_sub => .sub_shifted_register,
2247 else => unreachable,
2248 };
2249
2250 return try self.binOpRegister(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
2251 } else {
2252 // convert the offset into a byte offset by
2253 // multiplying it with elem_size
2254 const offset = try self.binOp(.mul, rhs, .{ .immediate = elem_size }, Type.usize, Type.usize, null);
2255 const addr = try self.binOp(tag, lhs, offset, Type.initTag(.manyptr_u8), Type.usize, null);
2256 return addr;
2257 }
2258 },
2259 else => unreachable,
2260 }
2261 },
2262 else => unreachable,2069 else => unreachable,
2263 }2070 }
2264}2071}
...@@ -2325,6 +2132,288 @@ fn addSub(...@@ -2325,6 +2132,288 @@ fn addSub(
2325 }2132 }
2326}2133}
23272134
2135fn mul(
2136 self: *Self,
2137 lhs_bind: ReadArg.Bind,
2138 rhs_bind: ReadArg.Bind,
2139 lhs_ty: Type,
2140 rhs_ty: Type,
2141 maybe_inst: ?Air.Inst.Index,
2142) InnerError!MCValue {
2143 const mod = self.bin_file.options.module.?;
2144 switch (lhs_ty.zigTypeTag()) {
2145 .Vector => return self.fail("TODO binary operations on vectors", .{}),
2146 .Int => {
2147 assert(lhs_ty.eql(rhs_ty, mod));
2148 const int_info = lhs_ty.intInfo(self.target.*);
2149 if (int_info.bits <= 64) {
2150 // TODO add optimisations for multiplication
2151 // with immediates, for example a * 2 can be
2152 // lowered to a << 1
2153 return try self.binOpRegisterNew(.mul, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst);
2154 } else {
2155 return self.fail("TODO binary operations on int with bits > 64", .{});
2156 }
2157 },
2158 else => unreachable,
2159 }
2160}
2161
2162fn divFloat(
2163 self: *Self,
2164 lhs_bind: ReadArg.Bind,
2165 rhs_bind: ReadArg.Bind,
2166 lhs_ty: Type,
2167 rhs_ty: Type,
2168 maybe_inst: ?Air.Inst.Index,
2169) InnerError!MCValue {
2170 _ = lhs_bind;
2171 _ = rhs_bind;
2172 _ = rhs_ty;
2173 _ = maybe_inst;
2174
2175 switch (lhs_ty.zigTypeTag()) {
2176 .Float => return self.fail("TODO div_float", .{}),
2177 .Vector => return self.fail("TODO div_float on vectors", .{}),
2178 else => unreachable,
2179 }
2180}
2181
2182fn divTrunc(
2183 self: *Self,
2184 lhs_bind: ReadArg.Bind,
2185 rhs_bind: ReadArg.Bind,
2186 lhs_ty: Type,
2187 rhs_ty: Type,
2188 maybe_inst: ?Air.Inst.Index,
2189) InnerError!MCValue {
2190 const mod = self.bin_file.options.module.?;
2191 switch (lhs_ty.zigTypeTag()) {
2192 .Float => return self.fail("TODO div on floats", .{}),
2193 .Vector => return self.fail("TODO div on vectors", .{}),
2194 .Int => {
2195 assert(lhs_ty.eql(rhs_ty, mod));
2196 const int_info = lhs_ty.intInfo(self.target.*);
2197 if (int_info.bits <= 64) {
2198 switch (int_info.signedness) {
2199 .signed => {
2200 // TODO optimize integer division by constants
2201 return try self.binOpRegisterNew(.sdiv, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst);
2202 },
2203 .unsigned => {
2204 // TODO optimize integer division by constants
2205 return try self.binOpRegisterNew(.udiv, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst);
2206 },
2207 }
2208 } else {
2209 return self.fail("TODO integer division for ints with bits > 64", .{});
2210 }
2211 },
2212 else => unreachable,
2213 }
2214}
2215
2216fn divFloor(
2217 self: *Self,
2218 lhs_bind: ReadArg.Bind,
2219 rhs_bind: ReadArg.Bind,
2220 lhs_ty: Type,
2221 rhs_ty: Type,
2222 maybe_inst: ?Air.Inst.Index,
2223) InnerError!MCValue {
2224 const mod = self.bin_file.options.module.?;
2225 switch (lhs_ty.zigTypeTag()) {
2226 .Float => return self.fail("TODO div on floats", .{}),
2227 .Vector => return self.fail("TODO div on vectors", .{}),
2228 .Int => {
2229 assert(lhs_ty.eql(rhs_ty, mod));
2230 const int_info = lhs_ty.intInfo(self.target.*);
2231 if (int_info.bits <= 64) {
2232 switch (int_info.signedness) {
2233 .signed => {
2234 return self.fail("TODO div_floor on signed integers", .{});
2235 },
2236 .unsigned => {
2237 // TODO optimize integer division by constants
2238 return try self.binOpRegisterNew(.udiv, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst);
2239 },
2240 }
2241 } else {
2242 return self.fail("TODO integer division for ints with bits > 64", .{});
2243 }
2244 },
2245 else => unreachable,
2246 }
2247}
2248
2249fn divExact(
2250 self: *Self,
2251 lhs_bind: ReadArg.Bind,
2252 rhs_bind: ReadArg.Bind,
2253 lhs_ty: Type,
2254 rhs_ty: Type,
2255 maybe_inst: ?Air.Inst.Index,
2256) InnerError!MCValue {
2257 const mod = self.bin_file.options.module.?;
2258 switch (lhs_ty.zigTypeTag()) {
2259 .Float => return self.fail("TODO div on floats", .{}),
2260 .Vector => return self.fail("TODO div on vectors", .{}),
2261 .Int => {
2262 assert(lhs_ty.eql(rhs_ty, mod));
2263 const int_info = lhs_ty.intInfo(self.target.*);
2264 if (int_info.bits <= 64) {
2265 switch (int_info.signedness) {
2266 .signed => {
2267 // TODO optimize integer division by constants
2268 return try self.binOpRegisterNew(.sdiv, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst);
2269 },
2270 .unsigned => {
2271 // TODO optimize integer division by constants
2272 return try self.binOpRegisterNew(.udiv, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst);
2273 },
2274 }
2275 } else {
2276 return self.fail("TODO integer division for ints with bits > 64", .{});
2277 }
2278 },
2279 else => unreachable,
2280 }
2281}
2282
2283fn rem(
2284 self: *Self,
2285 lhs_bind: ReadArg.Bind,
2286 rhs_bind: ReadArg.Bind,
2287 lhs_ty: Type,
2288 rhs_ty: Type,
2289 maybe_inst: ?Air.Inst.Index,
2290) InnerError!MCValue {
2291 _ = maybe_inst;
2292
2293 const mod = self.bin_file.options.module.?;
2294 switch (lhs_ty.zigTypeTag()) {
2295 .Float => return self.fail("TODO rem/mod on floats", .{}),
2296 .Vector => return self.fail("TODO rem/mod on vectors", .{}),
2297 .Int => {
2298 assert(lhs_ty.eql(rhs_ty, mod));
2299 const int_info = lhs_ty.intInfo(self.target.*);
2300 if (int_info.bits <= 64) {
2301 var lhs_reg: Register = undefined;
2302 var rhs_reg: Register = undefined;
2303 var quotient_reg: Register = undefined;
2304 var remainder_reg: Register = undefined;
2305
2306 const read_args = [_]ReadArg{
2307 .{ .ty = lhs_ty, .bind = lhs_bind, .class = gp, .reg = &lhs_reg },
2308 .{ .ty = rhs_ty, .bind = rhs_bind, .class = gp, .reg = &rhs_reg },
2309 };
2310 const write_args = [_]WriteArg{
2311 .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &quotient_reg },
2312 .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &remainder_reg },
2313 };
2314 try self.allocRegs(
2315 &read_args,
2316 &write_args,
2317 null,
2318 );
2319
2320 _ = try self.addInst(.{
2321 .tag = switch (int_info.signedness) {
2322 .signed => .sdiv,
2323 .unsigned => .udiv,
2324 },
2325 .data = .{ .rrr = .{
2326 .rd = quotient_reg,
2327 .rn = lhs_reg,
2328 .rm = rhs_reg,
2329 } },
2330 });
2331
2332 _ = try self.addInst(.{
2333 .tag = .msub,
2334 .data = .{ .rrrr = .{
2335 .rd = remainder_reg,
2336 .rn = quotient_reg,
2337 .rm = rhs_reg,
2338 .ra = lhs_reg,
2339 } },
2340 });
2341
2342 return MCValue{ .register = remainder_reg };
2343 } else {
2344 return self.fail("TODO rem/mod for integers with bits > 64", .{});
2345 }
2346 },
2347 else => unreachable,
2348 }
2349}
2350
2351fn modulo(
2352 self: *Self,
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 _ = lhs_bind;
2360 _ = rhs_bind;
2361 _ = rhs_ty;
2362 _ = maybe_inst;
2363
2364 switch (lhs_ty.zigTypeTag()) {
2365 .Float => return self.fail("TODO mod on floats", .{}),
2366 .Vector => return self.fail("TODO mod on vectors", .{}),
2367 .Int => return self.fail("TODO mod on ints", .{}),
2368 else => unreachable,
2369 }
2370}
2371
2372fn ptrArithmetic(
2373 self: *Self,
2374 tag: Air.Inst.Tag,
2375 lhs_bind: ReadArg.Bind,
2376 rhs_bind: ReadArg.Bind,
2377 lhs_ty: Type,
2378 rhs_ty: Type,
2379 maybe_inst: ?Air.Inst.Index,
2380) InnerError!MCValue {
2381 switch (lhs_ty.zigTypeTag()) {
2382 .Pointer => {
2383 const mod = self.bin_file.options.module.?;
2384 assert(rhs_ty.eql(Type.usize, mod));
2385
2386 const ptr_ty = lhs_ty;
2387 const elem_ty = switch (ptr_ty.ptrSize()) {
2388 .One => ptr_ty.childType().childType(), // ptr to array, so get array element type
2389 else => ptr_ty.childType(),
2390 };
2391 const elem_size = elem_ty.abiSize(self.target.*);
2392
2393 const base_tag: Air.Inst.Tag = switch (tag) {
2394 .ptr_add => .add,
2395 .ptr_sub => .sub,
2396 else => unreachable,
2397 };
2398
2399 if (elem_size == 1) {
2400 return try self.addSub(base_tag, lhs_bind, rhs_bind, Type.usize, Type.usize, maybe_inst);
2401 } else {
2402 // convert the offset into a byte offset by
2403 // multiplying it with elem_size
2404 const imm_bind = ReadArg.Bind{ .mcv = .{ .immediate = elem_size } };
2405
2406 const offset = try self.mul(rhs_bind, imm_bind, Type.usize, Type.usize, null);
2407 const offset_bind = ReadArg.Bind{ .mcv = offset };
2408
2409 const addr = try self.addSub(base_tag, lhs_bind, offset_bind, Type.usize, Type.usize, null);
2410 return addr;
2411 }
2412 },
2413 else => unreachable,
2414 }
2415}
2416
2328fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {2417fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
2329 const bin_op = self.air.instructions.items(.data)[inst].bin_op;2418 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
2330 const lhs_ty = self.air.typeOf(bin_op.lhs);2419 const lhs_ty = self.air.typeOf(bin_op.lhs);
...@@ -2338,6 +2427,20 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {...@@ -2338,6 +2427,20 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
2338 .add => try self.addSub(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),2427 .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),2428 .sub => try self.addSub(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
23402429
2430 .mul => try self.mul(lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
2431
2432 .div_float => try self.divFloat(lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
2433
2434 .div_trunc => try self.divTrunc(lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
2435
2436 .div_floor => try self.divFloor(lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
2437
2438 .div_exact => try self.divExact(lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
2439
2440 .rem => try self.rem(lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
2441
2442 .mod => try self.modulo(lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
2443
2341 else => blk: {2444 else => blk: {
2342 const lhs = try self.resolveInst(bin_op.lhs);2445 const lhs = try self.resolveInst(bin_op.lhs);
2343 const rhs = try self.resolveInst(bin_op.rhs);2446 const rhs = try self.resolveInst(bin_op.rhs);
...@@ -2356,19 +2459,15 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {...@@ -2356,19 +2459,15 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
2356fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {2459fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
2357 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;2460 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
2358 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;2461 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
2359 const lhs = try self.resolveInst(bin_op.lhs);
2360 const rhs = try self.resolveInst(bin_op.rhs);
2361 const lhs_ty = self.air.typeOf(bin_op.lhs);2462 const lhs_ty = self.air.typeOf(bin_op.lhs);
2362 const rhs_ty = self.air.typeOf(bin_op.rhs);2463 const rhs_ty = self.air.typeOf(bin_op.rhs);
23632464
2364 const result: MCValue = if (self.liveness.isUnused(inst))2465 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
2365 .dead2466 const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs };
2366 else2467 const rhs_bind: ReadArg.Bind = .{ .inst = bin_op.rhs };
2367 try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{2468
2368 .inst = inst,2469 break :result try self.ptrArithmetic(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst);
2369 .lhs = bin_op.lhs,2470 };
2370 .rhs = bin_op.rhs,
2371 });
2372 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });2471 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2373}2472}
23742473
...@@ -3161,63 +3260,59 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -3161,63 +3260,59 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void {
3161}3260}
31623261
3163fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {3262fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
3164 const is_volatile = false; // TODO
3165 const bin_op = self.air.instructions.items(.data)[inst].bin_op;3263 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
31663264 const slice_ty = self.air.typeOf(bin_op.lhs);
3167 if (!is_volatile and self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });3265 const result: MCValue = if (!slice_ty.isVolatilePtr() and self.liveness.isUnused(inst)) .dead else result: {
3168 const result: MCValue = result: {
3169 const slice_ty = self.air.typeOf(bin_op.lhs);
3170 const elem_ty = slice_ty.childType();
3171 const elem_size = elem_ty.abiSize(self.target.*);
3172 const slice_mcv = try self.resolveInst(bin_op.lhs);
3173
3174 // TODO optimize for the case where the index is a constant,
3175 // i.e. index_mcv == .immediate
3176 const index_mcv = try self.resolveInst(bin_op.rhs);
3177 const index_is_register = index_mcv == .register;
3178
3179 var buf: Type.SlicePtrFieldTypeBuffer = undefined;3266 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
3180 const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf);3267 const ptr_ty = slice_ty.slicePtrFieldType(&buf);
3181
3182 const index_lock: ?RegisterLock = if (index_is_register)
3183 self.register_manager.lockRegAssumeUnused(index_mcv.register)
3184 else
3185 null;
3186 defer if (index_lock) |reg| self.register_manager.unlockReg(reg);
31873268
3269 const slice_mcv = try self.resolveInst(bin_op.lhs);
3188 const base_mcv = slicePtr(slice_mcv);3270 const base_mcv = slicePtr(slice_mcv);
31893271
3190 switch (elem_size) {3272 const base_bind: ReadArg.Bind = .{ .mcv = base_mcv };
3191 else => {3273 const index_bind: ReadArg.Bind = .{ .inst = bin_op.rhs };
3192 const base_reg = switch (base_mcv) {
3193 .register => |r| r,
3194 else => try self.copyToTmpRegister(slice_ptr_field_type, base_mcv),
3195 };
3196 const base_reg_lock = self.register_manager.lockRegAssumeUnused(base_reg);
3197 defer self.register_manager.unlockReg(base_reg_lock);
3198
3199 const dest = try self.allocRegOrMem(elem_ty, true, inst);
3200 const addr = try self.binOp(.ptr_add, base_mcv, index_mcv, slice_ptr_field_type, Type.usize, null);
3201 try self.load(dest, addr, slice_ptr_field_type);
32023274
3203 break :result dest;3275 break :result try self.ptrElemVal(base_bind, index_bind, ptr_ty, inst);
3204 },
3205 }
3206 };3276 };
3207 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });3277 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
3208}3278}
32093279
3280fn ptrElemVal(
3281 self: *Self,
3282 ptr_bind: ReadArg.Bind,
3283 index_bind: ReadArg.Bind,
3284 ptr_ty: Type,
3285 maybe_inst: ?Air.Inst.Index,
3286) !MCValue {
3287 const elem_ty = ptr_ty.childType();
3288 const elem_size = @intCast(u32, elem_ty.abiSize(self.target.*));
3289
3290 // TODO optimize for elem_sizes of 1, 2, 4, 8
3291 switch (elem_size) {
3292 else => {
3293 const addr = try self.ptrArithmetic(.ptr_add, ptr_bind, index_bind, ptr_ty, Type.usize, null);
3294
3295 const dest = try self.allocRegOrMem(elem_ty, true, maybe_inst);
3296 try self.load(dest, addr, ptr_ty);
3297 return dest;
3298 },
3299 }
3300}
3301
3210fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {3302fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {
3211 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;3303 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
3212 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;3304 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
3213 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {3305 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
3214 const slice_mcv = try self.resolveInst(extra.lhs);3306 const slice_mcv = try self.resolveInst(extra.lhs);
3215 const index_mcv = try self.resolveInst(extra.rhs);
3216 const base_mcv = slicePtr(slice_mcv);3307 const base_mcv = slicePtr(slice_mcv);
32173308
3309 const base_bind: ReadArg.Bind = .{ .mcv = base_mcv };
3310 const index_bind: ReadArg.Bind = .{ .inst = extra.rhs };
3311
3218 const slice_ty = self.air.typeOf(extra.lhs);3312 const slice_ty = self.air.typeOf(extra.lhs);
3313 const index_ty = self.air.typeOf(extra.rhs);
32193314
3220 const addr = try self.binOp(.ptr_add, base_mcv, index_mcv, slice_ty, Type.usize, null);3315 const addr = try self.ptrArithmetic(.ptr_add, base_bind, index_bind, slice_ty, index_ty, null);
3221 break :result addr;3316 break :result addr;
3222 };3317 };
3223 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });3318 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
...@@ -3240,12 +3335,13 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -3240,12 +3335,13 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {
3240 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;3335 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
3241 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;3336 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
3242 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {3337 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
3243 const ptr_mcv = try self.resolveInst(extra.lhs);3338 const ptr_bind: ReadArg.Bind = .{ .inst = extra.lhs };
3244 const index_mcv = try self.resolveInst(extra.rhs);3339 const index_bind: ReadArg.Bind = .{ .inst = extra.rhs };
32453340
3246 const ptr_ty = self.air.typeOf(extra.lhs);3341 const ptr_ty = self.air.typeOf(extra.lhs);
3342 const index_ty = self.air.typeOf(extra.rhs);
32473343
3248 const addr = try self.binOp(.ptr_add, ptr_mcv, index_mcv, ptr_ty, Type.usize, null);3344 const addr = try self.ptrArithmetic(.ptr_add, ptr_bind, index_bind, ptr_ty, index_ty, null);
3249 break :result addr;3345 break :result addr;
3250 };3346 };
3251 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });3347 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });