| ... | ... | @@ -451,9 +451,7 @@ fn gen(self: *Self) !void { |
| 451 | 451 | // The address of where to store the return value is in |
| 452 | 452 | // r0. As this register might get overwritten along the |
| 453 | 453 | // way, save the address to the stack. |
| 454 | | const stack_offset = mem.alignForwardGeneric(u32, self.next_stack_offset, 4) + 4; |
| 455 | | self.next_stack_offset = stack_offset; |
| 456 | | self.max_end_stack = @maximum(self.max_end_stack, self.next_stack_offset); |
| 454 | const stack_offset = try self.allocMem(4, 4, null); |
| 457 | 455 | |
| 458 | 456 | try self.genSetStack(Type.usize, stack_offset, MCValue{ .register = .r0 }); |
| 459 | 457 | self.ret_mcv = MCValue{ .stack_offset = stack_offset }; |
| ... | ... | @@ -893,17 +891,30 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { |
| 893 | 891 | try table.ensureUnusedCapacity(self.gpa, additional_count); |
| 894 | 892 | } |
| 895 | 893 | |
| 896 | | fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u32 { |
| 894 | fn allocMem( |
| 895 | self: *Self, |
| 896 | abi_size: u32, |
| 897 | abi_align: u32, |
| 898 | maybe_inst: ?Air.Inst.Index, |
| 899 | ) !u32 { |
| 900 | assert(abi_size > 0); |
| 901 | assert(abi_align > 0); |
| 902 | |
| 897 | 903 | if (abi_align > self.stack_align) |
| 898 | 904 | self.stack_align = abi_align; |
| 905 | |
| 899 | 906 | // TODO find a free slot instead of always appending |
| 900 | 907 | const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align) + abi_size; |
| 901 | 908 | self.next_stack_offset = offset; |
| 902 | 909 | self.max_end_stack = @maximum(self.max_end_stack, self.next_stack_offset); |
| 903 | | try self.stack.putNoClobber(self.gpa, offset, .{ |
| 904 | | .inst = inst, |
| 905 | | .size = abi_size, |
| 906 | | }); |
| 910 | |
| 911 | if (maybe_inst) |inst| { |
| 912 | try self.stack.putNoClobber(self.gpa, offset, .{ |
| 913 | .inst = inst, |
| 914 | .size = abi_size, |
| 915 | }); |
| 916 | } |
| 917 | |
| 907 | 918 | return offset; |
| 908 | 919 | } |
| 909 | 920 | |
| ... | ... | @@ -925,7 +936,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { |
| 925 | 936 | }; |
| 926 | 937 | // TODO swap this for inst.ty.ptrAlign |
| 927 | 938 | const abi_align = elem_ty.abiAlignment(self.target.*); |
| 928 | | return self.allocMem(inst, abi_size, abi_align); |
| 939 | return self.allocMem(abi_size, abi_align, inst); |
| 929 | 940 | } |
| 930 | 941 | |
| 931 | 942 | fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { |
| ... | ... | @@ -948,7 +959,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { |
| 948 | 959 | } |
| 949 | 960 | } |
| 950 | 961 | } |
| 951 | | const stack_offset = try self.allocMem(inst, abi_size, abi_align); |
| 962 | const stack_offset = try self.allocMem(abi_size, abi_align, inst); |
| 952 | 963 | return MCValue{ .stack_offset = stack_offset }; |
| 953 | 964 | } |
| 954 | 965 | |
| ... | ... | @@ -1182,29 +1193,32 @@ fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 1182 | 1193 | fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1183 | 1194 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1184 | 1195 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1185 | | const operand = try self.resolveInst(ty_op.operand); |
| 1196 | const operand_bind: ReadArg.Bind = .{ .inst = ty_op.operand }; |
| 1186 | 1197 | const operand_ty = self.air.typeOf(ty_op.operand); |
| 1187 | | switch (operand) { |
| 1198 | switch (try operand_bind.resolveToMcv(self)) { |
| 1188 | 1199 | .dead => unreachable, |
| 1189 | 1200 | .unreach => unreachable, |
| 1190 | 1201 | .cpsr_flags => |cond| break :result MCValue{ .cpsr_flags = cond.negate() }, |
| 1191 | 1202 | else => { |
| 1192 | 1203 | switch (operand_ty.zigTypeTag()) { |
| 1193 | 1204 | .Bool => { |
| 1194 | | const op_reg = switch (operand) { |
| 1195 | | .register => |r| r, |
| 1196 | | else => try self.copyToTmpRegister(operand_ty, operand), |
| 1197 | | }; |
| 1198 | | const op_reg_lock = self.register_manager.lockRegAssumeUnused(op_reg); |
| 1199 | | defer self.register_manager.unlockReg(op_reg_lock); |
| 1200 | | |
| 1201 | | const dest_reg = blk: { |
| 1202 | | if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) { |
| 1203 | | break :blk op_reg; |
| 1204 | | } |
| 1205 | var op_reg: Register = undefined; |
| 1206 | var dest_reg: Register = undefined; |
| 1205 | 1207 | |
| 1206 | | break :blk try self.register_manager.allocReg(null, gp); |
| 1208 | const read_args = [_]ReadArg{ |
| 1209 | .{ .ty = operand_ty, .bind = operand_bind, .class = gp, .reg = &op_reg }, |
| 1210 | }; |
| 1211 | const write_args = [_]WriteArg{ |
| 1212 | .{ .ty = operand_ty, .bind = .none, .class = gp, .reg = &dest_reg }, |
| 1207 | 1213 | }; |
| 1214 | try self.allocRegs( |
| 1215 | &read_args, |
| 1216 | &write_args, |
| 1217 | ReuseMetadata{ |
| 1218 | .corresponding_inst = inst, |
| 1219 | .operand_mapping = &.{0}, |
| 1220 | }, |
| 1221 | ); |
| 1208 | 1222 | |
| 1209 | 1223 | _ = try self.addInst(.{ |
| 1210 | 1224 | .tag = .eor, |
| ... | ... | @@ -1221,20 +1235,23 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1221 | 1235 | .Int => { |
| 1222 | 1236 | const int_info = operand_ty.intInfo(self.target.*); |
| 1223 | 1237 | if (int_info.bits <= 32) { |
| 1224 | | const op_reg = switch (operand) { |
| 1225 | | .register => |r| r, |
| 1226 | | else => try self.copyToTmpRegister(operand_ty, operand), |
| 1227 | | }; |
| 1228 | | const op_reg_lock = self.register_manager.lockRegAssumeUnused(op_reg); |
| 1229 | | defer self.register_manager.unlockReg(op_reg_lock); |
| 1230 | | |
| 1231 | | const dest_reg = blk: { |
| 1232 | | if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) { |
| 1233 | | break :blk op_reg; |
| 1234 | | } |
| 1238 | var op_reg: Register = undefined; |
| 1239 | var dest_reg: Register = undefined; |
| 1235 | 1240 | |
| 1236 | | break :blk try self.register_manager.allocReg(null, gp); |
| 1241 | const read_args = [_]ReadArg{ |
| 1242 | .{ .ty = operand_ty, .bind = operand_bind, .class = gp, .reg = &op_reg }, |
| 1243 | }; |
| 1244 | const write_args = [_]WriteArg{ |
| 1245 | .{ .ty = operand_ty, .bind = .none, .class = gp, .reg = &dest_reg }, |
| 1237 | 1246 | }; |
| 1247 | try self.allocRegs( |
| 1248 | &read_args, |
| 1249 | &write_args, |
| 1250 | ReuseMetadata{ |
| 1251 | .corresponding_inst = inst, |
| 1252 | .operand_mapping = &.{0}, |
| 1253 | }, |
| 1254 | ); |
| 1238 | 1255 | |
| 1239 | 1256 | _ = try self.addInst(.{ |
| 1240 | 1257 | .tag = .mvn, |
| ... | ... | @@ -1384,7 +1401,7 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1384 | 1401 | const len = try self.resolveInst(bin_op.rhs); |
| 1385 | 1402 | const len_ty = self.air.typeOf(bin_op.rhs); |
| 1386 | 1403 | |
| 1387 | | const stack_offset = try self.allocMem(inst, 8, 4); |
| 1404 | const stack_offset = try self.allocMem(8, 4, inst); |
| 1388 | 1405 | try self.genSetStack(ptr_ty, stack_offset, ptr); |
| 1389 | 1406 | try self.genSetStack(len_ty, stack_offset - 4, len); |
| 1390 | 1407 | break :result MCValue{ .stack_offset = stack_offset }; |
| ... | ... | @@ -1496,7 +1513,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1496 | 1513 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 1497 | 1514 | const int_info = lhs_ty.intInfo(self.target.*); |
| 1498 | 1515 | if (int_info.bits < 32) { |
| 1499 | | const stack_offset = try self.allocMem(inst, tuple_size, tuple_align); |
| 1516 | const stack_offset = try self.allocMem(tuple_size, tuple_align, inst); |
| 1500 | 1517 | |
| 1501 | 1518 | try self.spillCompareFlagsIfOccupied(); |
| 1502 | 1519 | |
| ... | ... | @@ -1609,7 +1626,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1609 | 1626 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 1610 | 1627 | const int_info = lhs_ty.intInfo(self.target.*); |
| 1611 | 1628 | if (int_info.bits <= 16) { |
| 1612 | | const stack_offset = try self.allocMem(inst, tuple_size, tuple_align); |
| 1629 | const stack_offset = try self.allocMem(tuple_size, tuple_align, inst); |
| 1613 | 1630 | |
| 1614 | 1631 | try self.spillCompareFlagsIfOccupied(); |
| 1615 | 1632 | |
| ... | ... | @@ -1644,7 +1661,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1644 | 1661 | |
| 1645 | 1662 | break :result MCValue{ .stack_offset = stack_offset }; |
| 1646 | 1663 | } else if (int_info.bits <= 32) { |
| 1647 | | const stack_offset = try self.allocMem(inst, tuple_size, tuple_align); |
| 1664 | const stack_offset = try self.allocMem(tuple_size, tuple_align, inst); |
| 1648 | 1665 | |
| 1649 | 1666 | try self.spillCompareFlagsIfOccupied(); |
| 1650 | 1667 | |
| ... | ... | @@ -1769,7 +1786,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1769 | 1786 | .Int => { |
| 1770 | 1787 | const int_info = lhs_ty.intInfo(self.target.*); |
| 1771 | 1788 | if (int_info.bits <= 32) { |
| 1772 | | const stack_offset = try self.allocMem(inst, tuple_size, tuple_align); |
| 1789 | const stack_offset = try self.allocMem(tuple_size, tuple_align, inst); |
| 1773 | 1790 | |
| 1774 | 1791 | try self.spillCompareFlagsIfOccupied(); |
| 1775 | 1792 | |
| ... | ... | @@ -1926,19 +1943,57 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 1926 | 1943 | } |
| 1927 | 1944 | |
| 1928 | 1945 | /// Given an error union, returns the error |
| 1929 | | fn errUnionErr(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCValue { |
| 1946 | fn errUnionErr( |
| 1947 | self: *Self, |
| 1948 | error_union_bind: ReadArg.Bind, |
| 1949 | error_union_ty: Type, |
| 1950 | maybe_inst: ?Air.Inst.Index, |
| 1951 | ) !MCValue { |
| 1930 | 1952 | const err_ty = error_union_ty.errorUnionSet(); |
| 1931 | 1953 | const payload_ty = error_union_ty.errorUnionPayload(); |
| 1932 | 1954 | if (err_ty.errorSetIsEmpty()) { |
| 1933 | 1955 | return MCValue{ .immediate = 0 }; |
| 1934 | 1956 | } |
| 1935 | 1957 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { |
| 1936 | | return error_union_mcv; |
| 1958 | return try error_union_bind.resolveToMcv(self); |
| 1937 | 1959 | } |
| 1938 | 1960 | |
| 1939 | 1961 | const err_offset = @intCast(u32, errUnionErrorOffset(payload_ty, self.target.*)); |
| 1940 | | switch (error_union_mcv) { |
| 1941 | | .register => return self.fail("TODO errUnionErr for registers", .{}), |
| 1962 | switch (try error_union_bind.resolveToMcv(self)) { |
| 1963 | .register => { |
| 1964 | var operand_reg: Register = undefined; |
| 1965 | var dest_reg: Register = undefined; |
| 1966 | |
| 1967 | const read_args = [_]ReadArg{ |
| 1968 | .{ .ty = error_union_ty, .bind = error_union_bind, .class = gp, .reg = &operand_reg }, |
| 1969 | }; |
| 1970 | const write_args = [_]WriteArg{ |
| 1971 | .{ .ty = err_ty, .bind = .none, .class = gp, .reg = &dest_reg }, |
| 1972 | }; |
| 1973 | try self.allocRegs( |
| 1974 | &read_args, |
| 1975 | &write_args, |
| 1976 | if (maybe_inst) |inst| .{ |
| 1977 | .corresponding_inst = inst, |
| 1978 | .operand_mapping = &.{0}, |
| 1979 | } else null, |
| 1980 | ); |
| 1981 | |
| 1982 | const err_bit_offset = err_offset * 8; |
| 1983 | const err_bit_size = @intCast(u32, err_ty.abiSize(self.target.*)) * 8; |
| 1984 | |
| 1985 | _ = try self.addInst(.{ |
| 1986 | .tag = .ubfx, // errors are unsigned integers |
| 1987 | .data = .{ .rr_lsb_width = .{ |
| 1988 | .rd = dest_reg, |
| 1989 | .rn = operand_reg, |
| 1990 | .lsb = @intCast(u5, err_bit_offset), |
| 1991 | .width = @intCast(u6, err_bit_size), |
| 1992 | } }, |
| 1993 | }); |
| 1994 | |
| 1995 | return MCValue{ .register = dest_reg }; |
| 1996 | }, |
| 1942 | 1997 | .stack_argument_offset => |off| { |
| 1943 | 1998 | return MCValue{ .stack_argument_offset = off + err_offset }; |
| 1944 | 1999 | }, |
| ... | ... | @@ -1955,27 +2010,66 @@ fn errUnionErr(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCV |
| 1955 | 2010 | fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { |
| 1956 | 2011 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1957 | 2012 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2013 | const error_union_bind: ReadArg.Bind = .{ .inst = ty_op.operand }; |
| 1958 | 2014 | const error_union_ty = self.air.typeOf(ty_op.operand); |
| 1959 | | const mcv = try self.resolveInst(ty_op.operand); |
| 1960 | | break :result try self.errUnionErr(mcv, error_union_ty); |
| 2015 | |
| 2016 | break :result try self.errUnionErr(error_union_bind, error_union_ty, inst); |
| 1961 | 2017 | }; |
| 1962 | 2018 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1963 | 2019 | } |
| 1964 | 2020 | |
| 1965 | 2021 | /// Given an error union, returns the payload |
| 1966 | | fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCValue { |
| 2022 | fn errUnionPayload( |
| 2023 | self: *Self, |
| 2024 | error_union_bind: ReadArg.Bind, |
| 2025 | error_union_ty: Type, |
| 2026 | maybe_inst: ?Air.Inst.Index, |
| 2027 | ) !MCValue { |
| 1967 | 2028 | const err_ty = error_union_ty.errorUnionSet(); |
| 1968 | 2029 | const payload_ty = error_union_ty.errorUnionPayload(); |
| 1969 | 2030 | if (err_ty.errorSetIsEmpty()) { |
| 1970 | | return error_union_mcv; |
| 2031 | return try error_union_bind.resolveToMcv(self); |
| 1971 | 2032 | } |
| 1972 | 2033 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { |
| 1973 | 2034 | return MCValue.none; |
| 1974 | 2035 | } |
| 1975 | 2036 | |
| 1976 | 2037 | const payload_offset = @intCast(u32, errUnionPayloadOffset(payload_ty, self.target.*)); |
| 1977 | | switch (error_union_mcv) { |
| 1978 | | .register => return self.fail("TODO errUnionPayload for registers", .{}), |
| 2038 | switch (try error_union_bind.resolveToMcv(self)) { |
| 2039 | .register => { |
| 2040 | var operand_reg: Register = undefined; |
| 2041 | var dest_reg: Register = undefined; |
| 2042 | |
| 2043 | const read_args = [_]ReadArg{ |
| 2044 | .{ .ty = error_union_ty, .bind = error_union_bind, .class = gp, .reg = &operand_reg }, |
| 2045 | }; |
| 2046 | const write_args = [_]WriteArg{ |
| 2047 | .{ .ty = err_ty, .bind = .none, .class = gp, .reg = &dest_reg }, |
| 2048 | }; |
| 2049 | try self.allocRegs( |
| 2050 | &read_args, |
| 2051 | &write_args, |
| 2052 | if (maybe_inst) |inst| .{ |
| 2053 | .corresponding_inst = inst, |
| 2054 | .operand_mapping = &.{0}, |
| 2055 | } else null, |
| 2056 | ); |
| 2057 | |
| 2058 | const payload_bit_offset = payload_offset * 8; |
| 2059 | const payload_bit_size = @intCast(u32, payload_ty.abiSize(self.target.*)) * 8; |
| 2060 | |
| 2061 | _ = try self.addInst(.{ |
| 2062 | .tag = if (payload_ty.isSignedInt()) Mir.Inst.Tag.sbfx else .ubfx, |
| 2063 | .data = .{ .rr_lsb_width = .{ |
| 2064 | .rd = dest_reg, |
| 2065 | .rn = operand_reg, |
| 2066 | .lsb = @intCast(u5, payload_bit_offset), |
| 2067 | .width = @intCast(u6, payload_bit_size), |
| 2068 | } }, |
| 2069 | }); |
| 2070 | |
| 2071 | return MCValue{ .register = dest_reg }; |
| 2072 | }, |
| 1979 | 2073 | .stack_argument_offset => |off| { |
| 1980 | 2074 | return MCValue{ .stack_argument_offset = off + payload_offset }; |
| 1981 | 2075 | }, |
| ... | ... | @@ -1992,9 +2086,10 @@ fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) |
| 1992 | 2086 | fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 1993 | 2087 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1994 | 2088 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2089 | const error_union_bind: ReadArg.Bind = .{ .inst = ty_op.operand }; |
| 1995 | 2090 | const error_union_ty = self.air.typeOf(ty_op.operand); |
| 1996 | | const error_union = try self.resolveInst(ty_op.operand); |
| 1997 | | break :result try self.errUnionPayload(error_union, error_union_ty); |
| 2091 | |
| 2092 | break :result try self.errUnionPayload(error_union_bind, error_union_ty, inst); |
| 1998 | 2093 | }; |
| 1999 | 2094 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 2000 | 2095 | } |
| ... | ... | @@ -2038,17 +2133,18 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 2038 | 2133 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2039 | 2134 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2040 | 2135 | const error_union_ty = self.air.getRefType(ty_op.ty); |
| 2136 | const error_ty = error_union_ty.errorUnionSet(); |
| 2041 | 2137 | const payload_ty = error_union_ty.errorUnionPayload(); |
| 2042 | 2138 | const operand = try self.resolveInst(ty_op.operand); |
| 2043 | 2139 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) break :result operand; |
| 2044 | 2140 | |
| 2045 | 2141 | const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*)); |
| 2046 | 2142 | const abi_align = error_union_ty.abiAlignment(self.target.*); |
| 2047 | | const stack_offset = @intCast(u32, try self.allocMem(inst, abi_size, abi_align)); |
| 2143 | const stack_offset = @intCast(u32, try self.allocMem(abi_size, abi_align, inst)); |
| 2048 | 2144 | const payload_off = errUnionPayloadOffset(payload_ty, self.target.*); |
| 2049 | 2145 | const err_off = errUnionErrorOffset(payload_ty, self.target.*); |
| 2050 | 2146 | try self.genSetStack(payload_ty, stack_offset - @intCast(u32, payload_off), operand); |
| 2051 | | try self.genSetStack(Type.anyerror, stack_offset - @intCast(u32, err_off), .{ .immediate = 0 }); |
| 2147 | try self.genSetStack(error_ty, stack_offset - @intCast(u32, err_off), .{ .immediate = 0 }); |
| 2052 | 2148 | |
| 2053 | 2149 | break :result MCValue{ .stack_offset = stack_offset }; |
| 2054 | 2150 | }; |
| ... | ... | @@ -2060,16 +2156,17 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 2060 | 2156 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2061 | 2157 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2062 | 2158 | const error_union_ty = self.air.getRefType(ty_op.ty); |
| 2159 | const error_ty = error_union_ty.errorUnionSet(); |
| 2063 | 2160 | const payload_ty = error_union_ty.errorUnionPayload(); |
| 2064 | 2161 | const operand = try self.resolveInst(ty_op.operand); |
| 2065 | 2162 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) break :result operand; |
| 2066 | 2163 | |
| 2067 | 2164 | const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*)); |
| 2068 | 2165 | const abi_align = error_union_ty.abiAlignment(self.target.*); |
| 2069 | | const stack_offset = @intCast(u32, try self.allocMem(inst, abi_size, abi_align)); |
| 2166 | const stack_offset = @intCast(u32, try self.allocMem(abi_size, abi_align, inst)); |
| 2070 | 2167 | const payload_off = errUnionPayloadOffset(payload_ty, self.target.*); |
| 2071 | 2168 | const err_off = errUnionErrorOffset(payload_ty, self.target.*); |
| 2072 | | try self.genSetStack(Type.anyerror, stack_offset - @intCast(u32, err_off), operand); |
| 2169 | try self.genSetStack(error_ty, stack_offset - @intCast(u32, err_off), operand); |
| 2073 | 2170 | try self.genSetStack(payload_ty, stack_offset - @intCast(u32, payload_off), .undef); |
| 2074 | 2171 | |
| 2075 | 2172 | break :result MCValue{ .stack_offset = stack_offset }; |
| ... | ... | @@ -2108,7 +2205,6 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { |
| 2108 | 2205 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2109 | 2206 | const mcv = try self.resolveInst(ty_op.operand); |
| 2110 | 2207 | switch (mcv) { |
| 2111 | | .dead, .unreach => unreachable, |
| 2112 | 2208 | .register => unreachable, // a slice doesn't fit in one register |
| 2113 | 2209 | .stack_argument_offset => |off| { |
| 2114 | 2210 | break :result MCValue{ .stack_argument_offset = off + 4 }; |
| ... | ... | @@ -2119,7 +2215,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { |
| 2119 | 2215 | .memory => |addr| { |
| 2120 | 2216 | break :result MCValue{ .memory = addr + 4 }; |
| 2121 | 2217 | }, |
| 2122 | | else => return self.fail("TODO implement slice_len for {}", .{mcv}), |
| 2218 | else => unreachable, // invalid MCValue for a slice |
| 2123 | 2219 | } |
| 2124 | 2220 | }; |
| 2125 | 2221 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| ... | ... | @@ -2134,7 +2230,12 @@ fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2134 | 2230 | .ptr_stack_offset => |off| { |
| 2135 | 2231 | break :result MCValue{ .ptr_stack_offset = off - 4 }; |
| 2136 | 2232 | }, |
| 2137 | | else => return self.fail("TODO implement ptr_slice_len_ptr for {}", .{mcv}), |
| 2233 | else => { |
| 2234 | const lhs_bind: ReadArg.Bind = .{ .mcv = mcv }; |
| 2235 | const rhs_bind: ReadArg.Bind = .{ .mcv = .{ .immediate = 4 } }; |
| 2236 | |
| 2237 | break :result try self.addSub(.add, lhs_bind, rhs_bind, Type.usize, Type.usize, null); |
| 2238 | }, |
| 2138 | 2239 | } |
| 2139 | 2240 | }; |
| 2140 | 2241 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| ... | ... | @@ -2149,7 +2250,13 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2149 | 2250 | .ptr_stack_offset => |off| { |
| 2150 | 2251 | break :result MCValue{ .ptr_stack_offset = off }; |
| 2151 | 2252 | }, |
| 2152 | | else => return self.fail("TODO implement ptr_slice_ptr_ptr for {}", .{mcv}), |
| 2253 | else => { |
| 2254 | if (self.reuseOperand(inst, ty_op.operand, 0, mcv)) { |
| 2255 | break :result mcv; |
| 2256 | } else { |
| 2257 | break :result MCValue{ .register = try self.copyToTmpRegister(Type.usize, mcv) }; |
| 2258 | } |
| 2259 | }, |
| 2153 | 2260 | } |
| 2154 | 2261 | }; |
| 2155 | 2262 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| ... | ... | @@ -3891,7 +3998,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 3891 | 3998 | .register => |reg| blk: { |
| 3892 | 3999 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); |
| 3893 | 4000 | const abi_align = ty.abiAlignment(self.target.*); |
| 3894 | | const stack_offset = try self.allocMem(inst, abi_size, abi_align); |
| 4001 | const stack_offset = try self.allocMem(abi_size, abi_align, inst); |
| 3895 | 4002 | try self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); |
| 3896 | 4003 | |
| 3897 | 4004 | break :blk MCValue{ .stack_offset = stack_offset }; |
| ... | ... | @@ -3978,7 +4085,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 3978 | 4085 | const ret_ty = fn_ty.fnReturnType(); |
| 3979 | 4086 | const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*)); |
| 3980 | 4087 | const ret_abi_align = @intCast(u32, ret_ty.abiAlignment(self.target.*)); |
| 3981 | | const stack_offset = try self.allocMem(inst, ret_abi_size, ret_abi_align); |
| 4088 | const stack_offset = try self.allocMem(ret_abi_size, ret_abi_align, inst); |
| 3982 | 4089 | |
| 3983 | 4090 | var ptr_ty_payload: Type.Payload.ElemType = .{ |
| 3984 | 4091 | .base = .{ .tag = .single_mut_pointer }, |
| ... | ... | @@ -4166,14 +4273,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 4166 | 4273 | const abi_size = @intCast(u32, ret_ty.abiSize(self.target.*)); |
| 4167 | 4274 | const abi_align = ret_ty.abiAlignment(self.target.*); |
| 4168 | 4275 | |
| 4169 | | // This is essentially allocMem without the |
| 4170 | | // instruction tracking |
| 4171 | | if (abi_align > self.stack_align) |
| 4172 | | self.stack_align = abi_align; |
| 4173 | | // TODO find a free slot instead of always appending |
| 4174 | | const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align) + abi_size; |
| 4175 | | self.next_stack_offset = offset; |
| 4176 | | self.max_end_stack = @maximum(self.max_end_stack, self.next_stack_offset); |
| 4276 | const offset = try self.allocMem(abi_size, abi_align, null); |
| 4177 | 4277 | |
| 4178 | 4278 | const tmp_mcv = MCValue{ .stack_offset = offset }; |
| 4179 | 4279 | try self.load(tmp_mcv, ptr, ptr_ty); |
| ... | ... | @@ -4545,20 +4645,28 @@ fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 4545 | 4645 | return MCValue{ .cpsr_flags = .ne }; |
| 4546 | 4646 | } |
| 4547 | 4647 | |
| 4548 | | fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 4549 | | const error_type = ty.errorUnionSet(); |
| 4648 | fn isErr( |
| 4649 | self: *Self, |
| 4650 | error_union_bind: ReadArg.Bind, |
| 4651 | error_union_ty: Type, |
| 4652 | ) !MCValue { |
| 4653 | const error_type = error_union_ty.errorUnionSet(); |
| 4550 | 4654 | |
| 4551 | 4655 | if (error_type.errorSetIsEmpty()) { |
| 4552 | 4656 | return MCValue{ .immediate = 0 }; // always false |
| 4553 | 4657 | } |
| 4554 | 4658 | |
| 4555 | | const error_mcv = try self.errUnionErr(operand, ty); |
| 4659 | const error_mcv = try self.errUnionErr(error_union_bind, error_union_ty, null); |
| 4556 | 4660 | _ = try self.cmp(.{ .mcv = error_mcv }, .{ .mcv = .{ .immediate = 0 } }, error_type, .neq); |
| 4557 | 4661 | return MCValue{ .cpsr_flags = .hi }; |
| 4558 | 4662 | } |
| 4559 | 4663 | |
| 4560 | | fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 4561 | | const is_err_result = try self.isErr(ty, operand); |
| 4664 | fn isNonErr( |
| 4665 | self: *Self, |
| 4666 | error_union_bind: ReadArg.Bind, |
| 4667 | error_union_ty: Type, |
| 4668 | ) !MCValue { |
| 4669 | const is_err_result = try self.isErr(error_union_bind, error_union_ty); |
| 4562 | 4670 | switch (is_err_result) { |
| 4563 | 4671 | .cpsr_flags => |cond| { |
| 4564 | 4672 | assert(cond == .hi); |
| ... | ... | @@ -4637,9 +4745,10 @@ fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4637 | 4745 | fn airIsErr(self: *Self, inst: Air.Inst.Index) !void { |
| 4638 | 4746 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4639 | 4747 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4640 | | const operand = try self.resolveInst(un_op); |
| 4641 | | const ty = self.air.typeOf(un_op); |
| 4642 | | break :result try self.isErr(ty, operand); |
| 4748 | const error_union_bind: ReadArg.Bind = .{ .inst = un_op }; |
| 4749 | const error_union_ty = self.air.typeOf(un_op); |
| 4750 | |
| 4751 | break :result try self.isErr(error_union_bind, error_union_ty); |
| 4643 | 4752 | }; |
| 4644 | 4753 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 4645 | 4754 | } |
| ... | ... | @@ -4658,7 +4767,7 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4658 | 4767 | } |
| 4659 | 4768 | }; |
| 4660 | 4769 | try self.load(operand, operand_ptr, ptr_ty); |
| 4661 | | break :result try self.isErr(ptr_ty.elemType(), operand); |
| 4770 | break :result try self.isErr(.{ .mcv = operand }, ptr_ty.elemType()); |
| 4662 | 4771 | }; |
| 4663 | 4772 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 4664 | 4773 | } |
| ... | ... | @@ -4666,9 +4775,10 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4666 | 4775 | fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void { |
| 4667 | 4776 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4668 | 4777 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4669 | | const operand = try self.resolveInst(un_op); |
| 4670 | | const ty = self.air.typeOf(un_op); |
| 4671 | | break :result try self.isNonErr(ty, operand); |
| 4778 | const error_union_bind: ReadArg.Bind = .{ .inst = un_op }; |
| 4779 | const error_union_ty = self.air.typeOf(un_op); |
| 4780 | |
| 4781 | break :result try self.isNonErr(error_union_bind, error_union_ty); |
| 4672 | 4782 | }; |
| 4673 | 4783 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 4674 | 4784 | } |
| ... | ... | @@ -4687,7 +4797,7 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4687 | 4797 | } |
| 4688 | 4798 | }; |
| 4689 | 4799 | try self.load(operand, operand_ptr, ptr_ty); |
| 4690 | | break :result try self.isNonErr(ptr_ty.elemType(), operand); |
| 4800 | break :result try self.isNonErr(.{ .mcv = operand }, ptr_ty.elemType()); |
| 4691 | 4801 | }; |
| 4692 | 4802 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 4693 | 4803 | } |
| ... | ... | @@ -5620,7 +5730,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 5620 | 5730 | const array_ty = ptr_ty.childType(); |
| 5621 | 5731 | const array_len = @intCast(u32, array_ty.arrayLen()); |
| 5622 | 5732 | |
| 5623 | | const stack_offset = try self.allocMem(inst, 8, 8); |
| 5733 | const stack_offset = try self.allocMem(8, 8, inst); |
| 5624 | 5734 | try self.genSetStack(ptr_ty, stack_offset, ptr); |
| 5625 | 5735 | try self.genSetStack(Type.initTag(.usize), stack_offset - 4, .{ .immediate = array_len }); |
| 5626 | 5736 | break :result MCValue{ .stack_offset = stack_offset }; |
| ... | ... | @@ -5774,15 +5884,24 @@ fn airTry(self: *Self, inst: Air.Inst.Index) !void { |
| 5774 | 5884 | const extra = self.air.extraData(Air.Try, pl_op.payload); |
| 5775 | 5885 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; |
| 5776 | 5886 | const result: MCValue = result: { |
| 5887 | const error_union_bind: ReadArg.Bind = .{ .inst = pl_op.operand }; |
| 5777 | 5888 | const error_union_ty = self.air.typeOf(pl_op.operand); |
| 5778 | | const error_union = try self.resolveInst(pl_op.operand); |
| 5779 | | const is_err_result = try self.isErr(error_union_ty, error_union); |
| 5889 | const error_union_size = @intCast(u32, error_union_ty.abiSize(self.target.*)); |
| 5890 | const error_union_align = error_union_ty.abiAlignment(self.target.*); |
| 5891 | |
| 5892 | // The error union will die in the body. However, we need the |
| 5893 | // error union after the body in order to extract the payload |
| 5894 | // of the error union, so we create a copy of it |
| 5895 | const error_union_copy = try self.allocMem(error_union_size, error_union_align, null); |
| 5896 | try self.genSetStack(error_union_ty, error_union_copy, try error_union_bind.resolveToMcv(self)); |
| 5897 | |
| 5898 | const is_err_result = try self.isErr(error_union_bind, error_union_ty); |
| 5780 | 5899 | const reloc = try self.condBr(is_err_result); |
| 5781 | 5900 | |
| 5782 | 5901 | try self.genBody(body); |
| 5783 | | |
| 5784 | 5902 | try self.performReloc(reloc); |
| 5785 | | break :result try self.errUnionPayload(error_union, error_union_ty); |
| 5903 | |
| 5904 | break :result try self.errUnionPayload(.{ .mcv = .{ .stack_offset = error_union_copy } }, error_union_ty, null); |
| 5786 | 5905 | }; |
| 5787 | 5906 | return self.finishAir(inst, result, .{ pl_op.operand, .none, .none }); |
| 5788 | 5907 | } |