| ... | @@ -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 | } |
| 2327 | | 2134 | |
| | 2135 | fn 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 | |
| | 2162 | fn 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 | |
| | 2182 | fn 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 | |
| | 2216 | fn 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 | |
| | 2249 | fn 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 | |
| | 2283 | fn 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 | |
| | 2351 | fn 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 | |
| | 2372 | fn 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 | |
| 2328 | fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { | 2417 | fn 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), |
| 2340 | | 2429 | |
| | 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 { |
| 2356 | fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { | 2459 | fn 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); |
| 2363 | | 2464 | |
| 2364 | const result: MCValue = if (self.liveness.isUnused(inst)) | 2465 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2365 | .dead | 2466 | const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs }; |
| 2366 | else | 2467 | 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 | } |
| 2374 | | 2473 | |
| ... | @@ -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 | } |
| 3162 | | 3261 | |
| 3163 | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { | 3262 | fn 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; |
| 3166 | | 3264 | 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); | | |
| 3187 | | 3268 | |
| | 3269 | const slice_mcv = try self.resolveInst(bin_op.lhs); |
| 3188 | const base_mcv = slicePtr(slice_mcv); | 3270 | const base_mcv = slicePtr(slice_mcv); |
| 3189 | | 3271 | |
| 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); | | |
| 3202 | | 3274 | |
| 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 | } |
| 3209 | | 3279 | |
| | 3280 | fn 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 | |
| 3210 | fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void { | 3302 | fn 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); |
| 3217 | | 3308 | |
| | 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); |
| 3219 | | 3314 | |
| 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 }; |
| 3245 | | 3340 | |
| 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); |
| 3247 | | 3343 | |
| 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 }); |