| ... | @@ -451,9 +451,7 @@ fn gen(self: *Self) !void { | ... | @@ -451,9 +451,7 @@ fn gen(self: *Self) !void { |
| 451 | // The address of where to store the return value is in | 451 | // The address of where to store the return value is in |
| 452 | // r0. As this register might get overwritten along the | 452 | // r0. As this register might get overwritten along the |
| 453 | // way, save the address to the stack. | 453 | // way, save the address to the stack. |
| 454 | const stack_offset = mem.alignForwardGeneric(u32, self.next_stack_offset, 4) + 4; | 454 | const stack_offset = try self.allocMem(4, 4, null); |
| 455 | self.next_stack_offset = stack_offset; | | |
| 456 | self.max_end_stack = @maximum(self.max_end_stack, self.next_stack_offset); | | |
| 457 | | 455 | |
| 458 | try self.genSetStack(Type.usize, stack_offset, MCValue{ .register = .r0 }); | 456 | try self.genSetStack(Type.usize, stack_offset, MCValue{ .register = .r0 }); |
| 459 | self.ret_mcv = MCValue{ .stack_offset = stack_offset }; | 457 | self.ret_mcv = MCValue{ .stack_offset = stack_offset }; |
| ... | @@ -893,17 +891,30 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { | ... | @@ -893,17 +891,30 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { |
| 893 | try table.ensureUnusedCapacity(self.gpa, additional_count); | 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 | if (abi_align > self.stack_align) | 903 | if (abi_align > self.stack_align) |
| 898 | self.stack_align = abi_align; | 904 | self.stack_align = abi_align; |
| | 905 | |
| 899 | // TODO find a free slot instead of always appending | 906 | // TODO find a free slot instead of always appending |
| 900 | const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align) + abi_size; | 907 | const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align) + abi_size; |
| 901 | self.next_stack_offset = offset; | 908 | self.next_stack_offset = offset; |
| 902 | self.max_end_stack = @maximum(self.max_end_stack, self.next_stack_offset); | 909 | self.max_end_stack = @maximum(self.max_end_stack, self.next_stack_offset); |
| 903 | try self.stack.putNoClobber(self.gpa, offset, .{ | 910 | |
| 904 | .inst = inst, | 911 | if (maybe_inst) |inst| { |
| 905 | .size = abi_size, | 912 | try self.stack.putNoClobber(self.gpa, offset, .{ |
| 906 | }); | 913 | .inst = inst, |
| | 914 | .size = abi_size, |
| | 915 | }); |
| | 916 | } |
| | 917 | |
| 907 | return offset; | 918 | return offset; |
| 908 | } | 919 | } |
| 909 | | 920 | |
| ... | @@ -925,7 +936,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { | ... | @@ -925,7 +936,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { |
| 925 | }; | 936 | }; |
| 926 | // TODO swap this for inst.ty.ptrAlign | 937 | // TODO swap this for inst.ty.ptrAlign |
| 927 | const abi_align = elem_ty.abiAlignment(self.target.*); | 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 | fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { | 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,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 | return MCValue{ .stack_offset = stack_offset }; | 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,29 +1193,32 @@ fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 1182 | fn airNot(self: *Self, inst: Air.Inst.Index) !void { | 1193 | fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1183 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 1194 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1184 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 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 | const operand_ty = self.air.typeOf(ty_op.operand); | 1197 | const operand_ty = self.air.typeOf(ty_op.operand); |
| 1187 | switch (operand) { | 1198 | switch (try operand_bind.resolveToMcv(self)) { |
| 1188 | .dead => unreachable, | 1199 | .dead => unreachable, |
| 1189 | .unreach => unreachable, | 1200 | .unreach => unreachable, |
| 1190 | .cpsr_flags => |cond| break :result MCValue{ .cpsr_flags = cond.negate() }, | 1201 | .cpsr_flags => |cond| break :result MCValue{ .cpsr_flags = cond.negate() }, |
| 1191 | else => { | 1202 | else => { |
| 1192 | switch (operand_ty.zigTypeTag()) { | 1203 | switch (operand_ty.zigTypeTag()) { |
| 1193 | .Bool => { | 1204 | .Bool => { |
| 1194 | const op_reg = switch (operand) { | 1205 | var op_reg: Register = undefined; |
| 1195 | .register => |r| r, | 1206 | var dest_reg: Register = undefined; |
| 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 | | 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 | _ = try self.addInst(.{ | 1223 | _ = try self.addInst(.{ |
| 1210 | .tag = .eor, | 1224 | .tag = .eor, |
| ... | @@ -1221,20 +1235,23 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1221,20 +1235,23 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1221 | .Int => { | 1235 | .Int => { |
| 1222 | const int_info = operand_ty.intInfo(self.target.*); | 1236 | const int_info = operand_ty.intInfo(self.target.*); |
| 1223 | if (int_info.bits <= 32) { | 1237 | if (int_info.bits <= 32) { |
| 1224 | const op_reg = switch (operand) { | 1238 | var op_reg: Register = undefined; |
| 1225 | .register => |r| r, | 1239 | var dest_reg: Register = undefined; |
| 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 | } | | |
| 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 | _ = try self.addInst(.{ | 1256 | _ = try self.addInst(.{ |
| 1240 | .tag = .mvn, | 1257 | .tag = .mvn, |
| ... | @@ -1384,7 +1401,7 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1384,7 +1401,7 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1384 | const len = try self.resolveInst(bin_op.rhs); | 1401 | const len = try self.resolveInst(bin_op.rhs); |
| 1385 | const len_ty = self.air.typeOf(bin_op.rhs); | 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 | try self.genSetStack(ptr_ty, stack_offset, ptr); | 1405 | try self.genSetStack(ptr_ty, stack_offset, ptr); |
| 1389 | try self.genSetStack(len_ty, stack_offset - 4, len); | 1406 | try self.genSetStack(len_ty, stack_offset - 4, len); |
| 1390 | break :result MCValue{ .stack_offset = stack_offset }; | 1407 | break :result MCValue{ .stack_offset = stack_offset }; |
| ... | @@ -1496,7 +1513,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1496,7 +1513,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1496 | assert(lhs_ty.eql(rhs_ty, mod)); | 1513 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 1497 | const int_info = lhs_ty.intInfo(self.target.*); | 1514 | const int_info = lhs_ty.intInfo(self.target.*); |
| 1498 | if (int_info.bits < 32) { | 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 | try self.spillCompareFlagsIfOccupied(); | 1518 | try self.spillCompareFlagsIfOccupied(); |
| 1502 | | 1519 | |
| ... | @@ -1609,7 +1626,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1609,7 +1626,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1609 | assert(lhs_ty.eql(rhs_ty, mod)); | 1626 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 1610 | const int_info = lhs_ty.intInfo(self.target.*); | 1627 | const int_info = lhs_ty.intInfo(self.target.*); |
| 1611 | if (int_info.bits <= 16) { | 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 | try self.spillCompareFlagsIfOccupied(); | 1631 | try self.spillCompareFlagsIfOccupied(); |
| 1615 | | 1632 | |
| ... | @@ -1644,7 +1661,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1644,7 +1661,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1644 | | 1661 | |
| 1645 | break :result MCValue{ .stack_offset = stack_offset }; | 1662 | break :result MCValue{ .stack_offset = stack_offset }; |
| 1646 | } else if (int_info.bits <= 32) { | 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 | try self.spillCompareFlagsIfOccupied(); | 1666 | try self.spillCompareFlagsIfOccupied(); |
| 1650 | | 1667 | |
| ... | @@ -1769,7 +1786,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1769,7 +1786,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1769 | .Int => { | 1786 | .Int => { |
| 1770 | const int_info = lhs_ty.intInfo(self.target.*); | 1787 | const int_info = lhs_ty.intInfo(self.target.*); |
| 1771 | if (int_info.bits <= 32) { | 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 | try self.spillCompareFlagsIfOccupied(); | 1791 | try self.spillCompareFlagsIfOccupied(); |
| 1775 | | 1792 | |
| ... | @@ -1926,19 +1943,57 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1926,19 +1943,57 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 1926 | } | 1943 | } |
| 1927 | | 1944 | |
| 1928 | /// Given an error union, returns the error | 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 | const err_ty = error_union_ty.errorUnionSet(); | 1952 | const err_ty = error_union_ty.errorUnionSet(); |
| 1931 | const payload_ty = error_union_ty.errorUnionPayload(); | 1953 | const payload_ty = error_union_ty.errorUnionPayload(); |
| 1932 | if (err_ty.errorSetIsEmpty()) { | 1954 | if (err_ty.errorSetIsEmpty()) { |
| 1933 | return MCValue{ .immediate = 0 }; | 1955 | return MCValue{ .immediate = 0 }; |
| 1934 | } | 1956 | } |
| 1935 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 1957 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { |
| 1936 | return error_union_mcv; | 1958 | return try error_union_bind.resolveToMcv(self); |
| 1937 | } | 1959 | } |
| 1938 | | 1960 | |
| 1939 | const err_offset = @intCast(u32, errUnionErrorOffset(payload_ty, self.target.*)); | 1961 | const err_offset = @intCast(u32, errUnionErrorOffset(payload_ty, self.target.*)); |
| 1940 | switch (error_union_mcv) { | 1962 | switch (try error_union_bind.resolveToMcv(self)) { |
| 1941 | .register => return self.fail("TODO errUnionErr for registers", .{}), | 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 | .stack_argument_offset => |off| { | 1997 | .stack_argument_offset => |off| { |
| 1943 | return MCValue{ .stack_argument_offset = off + err_offset }; | 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,27 +2010,66 @@ fn errUnionErr(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCV |
| 1955 | fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { | 2010 | fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { |
| 1956 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2011 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1957 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2012 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| | 2013 | const error_union_bind: ReadArg.Bind = .{ .inst = ty_op.operand }; |
| 1958 | const error_union_ty = self.air.typeOf(ty_op.operand); | 2014 | const error_union_ty = self.air.typeOf(ty_op.operand); |
| 1959 | const mcv = try self.resolveInst(ty_op.operand); | 2015 | |
| 1960 | break :result try self.errUnionErr(mcv, error_union_ty); | 2016 | break :result try self.errUnionErr(error_union_bind, error_union_ty, inst); |
| 1961 | }; | 2017 | }; |
| 1962 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 2018 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1963 | } | 2019 | } |
| 1964 | | 2020 | |
| 1965 | /// Given an error union, returns the payload | 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 | const err_ty = error_union_ty.errorUnionSet(); | 2028 | const err_ty = error_union_ty.errorUnionSet(); |
| 1968 | const payload_ty = error_union_ty.errorUnionPayload(); | 2029 | const payload_ty = error_union_ty.errorUnionPayload(); |
| 1969 | if (err_ty.errorSetIsEmpty()) { | 2030 | if (err_ty.errorSetIsEmpty()) { |
| 1970 | return error_union_mcv; | 2031 | return try error_union_bind.resolveToMcv(self); |
| 1971 | } | 2032 | } |
| 1972 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 2033 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { |
| 1973 | return MCValue.none; | 2034 | return MCValue.none; |
| 1974 | } | 2035 | } |
| 1975 | | 2036 | |
| 1976 | const payload_offset = @intCast(u32, errUnionPayloadOffset(payload_ty, self.target.*)); | 2037 | const payload_offset = @intCast(u32, errUnionPayloadOffset(payload_ty, self.target.*)); |
| 1977 | switch (error_union_mcv) { | 2038 | switch (try error_union_bind.resolveToMcv(self)) { |
| 1978 | .register => return self.fail("TODO errUnionPayload for registers", .{}), | 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 | .stack_argument_offset => |off| { | 2073 | .stack_argument_offset => |off| { |
| 1980 | return MCValue{ .stack_argument_offset = off + payload_offset }; | 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,9 +2086,10 @@ fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) |
| 1992 | fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void { | 2086 | fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 1993 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2087 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1994 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2088 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| | 2089 | const error_union_bind: ReadArg.Bind = .{ .inst = ty_op.operand }; |
| 1995 | const error_union_ty = self.air.typeOf(ty_op.operand); | 2090 | const error_union_ty = self.air.typeOf(ty_op.operand); |
| 1996 | const error_union = try self.resolveInst(ty_op.operand); | 2091 | |
| 1997 | break :result try self.errUnionPayload(error_union, error_union_ty); | 2092 | break :result try self.errUnionPayload(error_union_bind, error_union_ty, inst); |
| 1998 | }; | 2093 | }; |
| 1999 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 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,17 +2133,18 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 2038 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2133 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2039 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2134 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2040 | const error_union_ty = self.air.getRefType(ty_op.ty); | 2135 | const error_union_ty = self.air.getRefType(ty_op.ty); |
| | 2136 | const error_ty = error_union_ty.errorUnionSet(); |
| 2041 | const payload_ty = error_union_ty.errorUnionPayload(); | 2137 | const payload_ty = error_union_ty.errorUnionPayload(); |
| 2042 | const operand = try self.resolveInst(ty_op.operand); | 2138 | const operand = try self.resolveInst(ty_op.operand); |
| 2043 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) break :result operand; | 2139 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) break :result operand; |
| 2044 | | 2140 | |
| 2045 | const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*)); | 2141 | const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*)); |
| 2046 | const abi_align = error_union_ty.abiAlignment(self.target.*); | 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 | const payload_off = errUnionPayloadOffset(payload_ty, self.target.*); | 2144 | const payload_off = errUnionPayloadOffset(payload_ty, self.target.*); |
| 2049 | const err_off = errUnionErrorOffset(payload_ty, self.target.*); | 2145 | const err_off = errUnionErrorOffset(payload_ty, self.target.*); |
| 2050 | try self.genSetStack(payload_ty, stack_offset - @intCast(u32, payload_off), operand); | 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 | break :result MCValue{ .stack_offset = stack_offset }; | 2149 | break :result MCValue{ .stack_offset = stack_offset }; |
| 2054 | }; | 2150 | }; |
| ... | @@ -2060,16 +2156,17 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2060,16 +2156,17 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 2060 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2156 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2061 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2157 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2062 | const error_union_ty = self.air.getRefType(ty_op.ty); | 2158 | const error_union_ty = self.air.getRefType(ty_op.ty); |
| | 2159 | const error_ty = error_union_ty.errorUnionSet(); |
| 2063 | const payload_ty = error_union_ty.errorUnionPayload(); | 2160 | const payload_ty = error_union_ty.errorUnionPayload(); |
| 2064 | const operand = try self.resolveInst(ty_op.operand); | 2161 | const operand = try self.resolveInst(ty_op.operand); |
| 2065 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) break :result operand; | 2162 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) break :result operand; |
| 2066 | | 2163 | |
| 2067 | const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*)); | 2164 | const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*)); |
| 2068 | const abi_align = error_union_ty.abiAlignment(self.target.*); | 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 | const payload_off = errUnionPayloadOffset(payload_ty, self.target.*); | 2167 | const payload_off = errUnionPayloadOffset(payload_ty, self.target.*); |
| 2071 | const err_off = errUnionErrorOffset(payload_ty, self.target.*); | 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 | try self.genSetStack(payload_ty, stack_offset - @intCast(u32, payload_off), .undef); | 2170 | try self.genSetStack(payload_ty, stack_offset - @intCast(u32, payload_off), .undef); |
| 2074 | | 2171 | |
| 2075 | break :result MCValue{ .stack_offset = stack_offset }; | 2172 | break :result MCValue{ .stack_offset = stack_offset }; |
| ... | @@ -2108,7 +2205,6 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2108,7 +2205,6 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { |
| 2108 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2205 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2109 | const mcv = try self.resolveInst(ty_op.operand); | 2206 | const mcv = try self.resolveInst(ty_op.operand); |
| 2110 | switch (mcv) { | 2207 | switch (mcv) { |
| 2111 | .dead, .unreach => unreachable, | | |
| 2112 | .register => unreachable, // a slice doesn't fit in one register | 2208 | .register => unreachable, // a slice doesn't fit in one register |
| 2113 | .stack_argument_offset => |off| { | 2209 | .stack_argument_offset => |off| { |
| 2114 | break :result MCValue{ .stack_argument_offset = off + 4 }; | 2210 | break :result MCValue{ .stack_argument_offset = off + 4 }; |
| ... | @@ -2119,7 +2215,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2119,7 +2215,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { |
| 2119 | .memory => |addr| { | 2215 | .memory => |addr| { |
| 2120 | break :result MCValue{ .memory = addr + 4 }; | 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 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 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,7 +2230,12 @@ fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2134 | .ptr_stack_offset => |off| { | 2230 | .ptr_stack_offset => |off| { |
| 2135 | break :result MCValue{ .ptr_stack_offset = off - 4 }; | 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 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 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,7 +2250,13 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2149 | .ptr_stack_offset => |off| { | 2250 | .ptr_stack_offset => |off| { |
| 2150 | break :result MCValue{ .ptr_stack_offset = off }; | 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 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 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,7 +3998,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 3891 | .register => |reg| blk: { | 3998 | .register => |reg| blk: { |
| 3892 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); | 3999 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); |
| 3893 | const abi_align = ty.abiAlignment(self.target.*); | 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 | try self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); | 4002 | try self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); |
| 3896 | | 4003 | |
| 3897 | break :blk MCValue{ .stack_offset = stack_offset }; | 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,7 +4085,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 3978 | const ret_ty = fn_ty.fnReturnType(); | 4085 | const ret_ty = fn_ty.fnReturnType(); |
| 3979 | const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*)); | 4086 | const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*)); |
| 3980 | const ret_abi_align = @intCast(u32, ret_ty.abiAlignment(self.target.*)); | 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 | var ptr_ty_payload: Type.Payload.ElemType = .{ | 4090 | var ptr_ty_payload: Type.Payload.ElemType = .{ |
| 3984 | .base = .{ .tag = .single_mut_pointer }, | 4091 | .base = .{ .tag = .single_mut_pointer }, |
| ... | @@ -4166,14 +4273,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4166,14 +4273,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 4166 | const abi_size = @intCast(u32, ret_ty.abiSize(self.target.*)); | 4273 | const abi_size = @intCast(u32, ret_ty.abiSize(self.target.*)); |
| 4167 | const abi_align = ret_ty.abiAlignment(self.target.*); | 4274 | const abi_align = ret_ty.abiAlignment(self.target.*); |
| 4168 | | 4275 | |
| 4169 | // This is essentially allocMem without the | 4276 | const offset = try self.allocMem(abi_size, abi_align, null); |
| 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); | | |
| 4177 | | 4277 | |
| 4178 | const tmp_mcv = MCValue{ .stack_offset = offset }; | 4278 | const tmp_mcv = MCValue{ .stack_offset = offset }; |
| 4179 | try self.load(tmp_mcv, ptr, ptr_ty); | 4279 | try self.load(tmp_mcv, ptr, ptr_ty); |
| ... | @@ -4545,20 +4645,28 @@ fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue { | ... | @@ -4545,20 +4645,28 @@ fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 4545 | return MCValue{ .cpsr_flags = .ne }; | 4645 | return MCValue{ .cpsr_flags = .ne }; |
| 4546 | } | 4646 | } |
| 4547 | | 4647 | |
| 4548 | fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue { | 4648 | fn isErr( |
| 4549 | const error_type = ty.errorUnionSet(); | 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 | if (error_type.errorSetIsEmpty()) { | 4655 | if (error_type.errorSetIsEmpty()) { |
| 4552 | return MCValue{ .immediate = 0 }; // always false | 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 | _ = try self.cmp(.{ .mcv = error_mcv }, .{ .mcv = .{ .immediate = 0 } }, error_type, .neq); | 4660 | _ = try self.cmp(.{ .mcv = error_mcv }, .{ .mcv = .{ .immediate = 0 } }, error_type, .neq); |
| 4557 | return MCValue{ .cpsr_flags = .hi }; | 4661 | return MCValue{ .cpsr_flags = .hi }; |
| 4558 | } | 4662 | } |
| 4559 | | 4663 | |
| 4560 | fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue { | 4664 | fn isNonErr( |
| 4561 | const is_err_result = try self.isErr(ty, operand); | 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 | switch (is_err_result) { | 4670 | switch (is_err_result) { |
| 4563 | .cpsr_flags => |cond| { | 4671 | .cpsr_flags => |cond| { |
| 4564 | assert(cond == .hi); | 4672 | assert(cond == .hi); |
| ... | @@ -4637,9 +4745,10 @@ fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4637,9 +4745,10 @@ fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4637 | fn airIsErr(self: *Self, inst: Air.Inst.Index) !void { | 4745 | fn airIsErr(self: *Self, inst: Air.Inst.Index) !void { |
| 4638 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 4746 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4639 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 4747 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4640 | const operand = try self.resolveInst(un_op); | 4748 | const error_union_bind: ReadArg.Bind = .{ .inst = un_op }; |
| 4641 | const ty = self.air.typeOf(un_op); | 4749 | const error_union_ty = self.air.typeOf(un_op); |
| 4642 | break :result try self.isErr(ty, operand); | 4750 | |
| | 4751 | break :result try self.isErr(error_union_bind, error_union_ty); |
| 4643 | }; | 4752 | }; |
| 4644 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 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,7 +4767,7 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4658 | } | 4767 | } |
| 4659 | }; | 4768 | }; |
| 4660 | try self.load(operand, operand_ptr, ptr_ty); | 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 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 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,9 +4775,10 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4666 | fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void { | 4775 | fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void { |
| 4667 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 4776 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4668 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 4777 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4669 | const operand = try self.resolveInst(un_op); | 4778 | const error_union_bind: ReadArg.Bind = .{ .inst = un_op }; |
| 4670 | const ty = self.air.typeOf(un_op); | 4779 | const error_union_ty = self.air.typeOf(un_op); |
| 4671 | break :result try self.isNonErr(ty, operand); | 4780 | |
| | 4781 | break :result try self.isNonErr(error_union_bind, error_union_ty); |
| 4672 | }; | 4782 | }; |
| 4673 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 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,7 +4797,7 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4687 | } | 4797 | } |
| 4688 | }; | 4798 | }; |
| 4689 | try self.load(operand, operand_ptr, ptr_ty); | 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 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 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,7 +5730,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 5620 | const array_ty = ptr_ty.childType(); | 5730 | const array_ty = ptr_ty.childType(); |
| 5621 | const array_len = @intCast(u32, array_ty.arrayLen()); | 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 | try self.genSetStack(ptr_ty, stack_offset, ptr); | 5734 | try self.genSetStack(ptr_ty, stack_offset, ptr); |
| 5625 | try self.genSetStack(Type.initTag(.usize), stack_offset - 4, .{ .immediate = array_len }); | 5735 | try self.genSetStack(Type.initTag(.usize), stack_offset - 4, .{ .immediate = array_len }); |
| 5626 | break :result MCValue{ .stack_offset = stack_offset }; | 5736 | break :result MCValue{ .stack_offset = stack_offset }; |
| ... | @@ -5774,15 +5884,24 @@ fn airTry(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5774,15 +5884,24 @@ fn airTry(self: *Self, inst: Air.Inst.Index) !void { |
| 5774 | const extra = self.air.extraData(Air.Try, pl_op.payload); | 5884 | const extra = self.air.extraData(Air.Try, pl_op.payload); |
| 5775 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; | 5885 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; |
| 5776 | const result: MCValue = result: { | 5886 | const result: MCValue = result: { |
| | 5887 | const error_union_bind: ReadArg.Bind = .{ .inst = pl_op.operand }; |
| 5777 | const error_union_ty = self.air.typeOf(pl_op.operand); | 5888 | const error_union_ty = self.air.typeOf(pl_op.operand); |
| 5778 | const error_union = try self.resolveInst(pl_op.operand); | 5889 | const error_union_size = @intCast(u32, error_union_ty.abiSize(self.target.*)); |
| 5779 | const is_err_result = try self.isErr(error_union_ty, error_union); | 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 | const reloc = try self.condBr(is_err_result); | 5899 | const reloc = try self.condBr(is_err_result); |
| 5781 | | 5900 | |
| 5782 | try self.genBody(body); | 5901 | try self.genBody(body); |
| 5783 | | | |
| 5784 | try self.performReloc(reloc); | 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 | return self.finishAir(inst, result, .{ pl_op.operand, .none, .none }); | 5906 | return self.finishAir(inst, result, .{ pl_op.operand, .none, .none }); |
| 5788 | } | 5907 | } |