authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-09-01 16:51:42+02:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-09-09 19:17:18+02:00
log25729d6155682933d7ab3aa30c7e060519b2f4e1
tree5085d441184d2f62fb22ae73ee9b72edba36d74e
parent261fec8036e1e5518951d91c5fc27b53c1a511d8
signature Commit is signed but in an unrecognized format.

stage2 ARM: fix multiple uses of reuseOperand

- add missing checks whether destination fits into the operand - remove reuseOperand invocations from airIsNullPtr and similar functions as we need to load the operands into temporary locations

1 files changed, 120 insertions(+), 141 deletions(-)

src/arch/arm/CodeGen.zig+120-141
...@@ -936,35 +936,34 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {...@@ -936,35 +936,34 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {
936 };936 };
937 // TODO swap this for inst.ty.ptrAlign937 // TODO swap this for inst.ty.ptrAlign
938 const abi_align = elem_ty.abiAlignment(self.target.*);938 const abi_align = elem_ty.abiAlignment(self.target.*);
939
939 return self.allocMem(abi_size, abi_align, inst);940 return self.allocMem(abi_size, abi_align, inst);
940}941}
941942
942fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {943fn allocRegOrMem(self: *Self, elem_ty: Type, reg_ok: bool, maybe_inst: ?Air.Inst.Index) !MCValue {
943 const elem_ty = self.air.typeOfIndex(inst);
944 const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) orelse {944 const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) orelse {
945 const mod = self.bin_file.options.module.?;945 const mod = self.bin_file.options.module.?;
946 return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)});946 return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)});
947 };947 };
948 const abi_align = elem_ty.abiAlignment(self.target.*);948 const abi_align = elem_ty.abiAlignment(self.target.*);
949 if (abi_align > self.stack_align)
950 self.stack_align = abi_align;
951949
952 if (reg_ok) {950 if (reg_ok) {
953 // Make sure the type can fit in a register before we try to allocate one.951 // Make sure the type can fit in a register before we try to allocate one.
954 const ptr_bits = self.target.cpu.arch.ptrBitWidth();952 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
955 const ptr_bytes: u64 = @divExact(ptr_bits, 8);953 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
956 if (abi_size <= ptr_bytes) {954 if (abi_size <= ptr_bytes) {
957 if (self.register_manager.tryAllocReg(inst, gp)) |reg| {955 if (self.register_manager.tryAllocReg(maybe_inst, gp)) |reg| {
958 return MCValue{ .register = reg };956 return MCValue{ .register = reg };
959 }957 }
960 }958 }
961 }959 }
962 const stack_offset = try self.allocMem(abi_size, abi_align, inst);960
961 const stack_offset = try self.allocMem(abi_size, abi_align, maybe_inst);
963 return MCValue{ .stack_offset = stack_offset };962 return MCValue{ .stack_offset = stack_offset };
964}963}
965964
966pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void {965pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void {
967 const stack_mcv = try self.allocRegOrMem(inst, false);966 const stack_mcv = try self.allocRegOrMem(self.air.typeOfIndex(inst), false, inst);
968 log.debug("spilling {} (%{d}) to stack mcv {any}", .{ reg, inst, stack_mcv });967 log.debug("spilling {} (%{d}) to stack mcv {any}", .{ reg, inst, stack_mcv });
969968
970 const reg_mcv = self.getResolvedInstValue(inst);969 const reg_mcv = self.getResolvedInstValue(inst);
...@@ -985,12 +984,13 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void...@@ -985,12 +984,13 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
985/// occupied984/// occupied
986fn spillCompareFlagsIfOccupied(self: *Self) !void {985fn spillCompareFlagsIfOccupied(self: *Self) !void {
987 if (self.cpsr_flags_inst) |inst_to_save| {986 if (self.cpsr_flags_inst) |inst_to_save| {
987 const ty = self.air.typeOfIndex(inst_to_save);
988 const mcv = self.getResolvedInstValue(inst_to_save);988 const mcv = self.getResolvedInstValue(inst_to_save);
989 const new_mcv = switch (mcv) {989 const new_mcv = switch (mcv) {
990 .cpsr_flags => try self.allocRegOrMem(inst_to_save, true),990 .cpsr_flags => try self.allocRegOrMem(ty, true, inst_to_save),
991 .register_c_flag,991 .register_c_flag,
992 .register_v_flag,992 .register_v_flag,
993 => try self.allocRegOrMem(inst_to_save, false),993 => try self.allocRegOrMem(ty, false, inst_to_save),
994 else => unreachable, // mcv doesn't occupy the compare flags994 else => unreachable, // mcv doesn't occupy the compare flags
995 };995 };
996996
...@@ -1121,10 +1121,11 @@ fn truncRegister(...@@ -1121,10 +1121,11 @@ fn truncRegister(
1121 });1121 });
1122}1122}
11231123
1124/// Asserts that both operand_ty and dest_ty are integer types
1124fn trunc(1125fn trunc(
1125 self: *Self,1126 self: *Self,
1126 maybe_inst: ?Air.Inst.Index,1127 maybe_inst: ?Air.Inst.Index,
1127 operand: MCValue,1128 operand_bind: ReadArg.Bind,
1128 operand_ty: Type,1129 operand_ty: Type,
1129 dest_ty: Type,1130 dest_ty: Type,
1130) !MCValue {1131) !MCValue {
...@@ -1132,39 +1133,38 @@ fn trunc(...@@ -1132,39 +1133,38 @@ fn trunc(
1132 const info_b = dest_ty.intInfo(self.target.*);1133 const info_b = dest_ty.intInfo(self.target.*);
11331134
1134 if (info_b.bits <= 32) {1135 if (info_b.bits <= 32) {
1135 const operand_reg = switch (operand) {1136 if (info_a.bits > 32) {
1136 .register => |r| r,1137 return self.fail("TODO load least significant word into register", .{});
1137 else => operand_reg: {1138 }
1138 if (info_a.bits <= 32) {
1139 break :operand_reg try self.copyToTmpRegister(operand_ty, operand);
1140 } else {
1141 return self.fail("TODO load least significant word into register", .{});
1142 }
1143 },
1144 };
1145 const operand_reg_lock = self.register_manager.lockReg(operand_reg);
1146 defer if (operand_reg_lock) |reg| self.register_manager.unlockReg(reg);
11471139
1148 const dest_reg = if (maybe_inst) |inst| blk: {1140 var operand_reg: Register = undefined;
1149 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1141 var dest_reg: Register = undefined;
11501142
1151 if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) {1143 const read_args = [_]ReadArg{
1152 break :blk operand_reg;1144 .{ .ty = operand_ty, .bind = operand_bind, .class = gp, .reg = &operand_reg },
1153 } else {1145 };
1154 break :blk try self.register_manager.allocReg(inst, gp);1146 const write_args = [_]WriteArg{
1155 }1147 .{ .ty = dest_ty, .bind = .none, .class = gp, .reg = &dest_reg },
1156 } else try self.register_manager.allocReg(null, gp);1148 };
1149 try self.allocRegs(
1150 &read_args,
1151 &write_args,
1152 if (maybe_inst) |inst| .{
1153 .corresponding_inst = inst,
1154 .operand_mapping = &.{0},
1155 } else null,
1156 );
11571157
1158 switch (info_b.bits) {1158 switch (info_b.bits) {
1159 32 => {1159 32 => {
1160 try self.genSetReg(operand_ty, dest_reg, .{ .register = operand_reg });1160 try self.genSetReg(operand_ty, dest_reg, .{ .register = operand_reg });
1161 return MCValue{ .register = dest_reg };
1162 },1161 },
1163 else => {1162 else => {
1164 try self.truncRegister(operand_reg, dest_reg, info_b.signedness, info_b.bits);1163 try self.truncRegister(operand_reg, dest_reg, info_b.signedness, info_b.bits);
1165 return MCValue{ .register = dest_reg };
1166 },1164 },
1167 }1165 }
1166
1167 return MCValue{ .register = dest_reg };
1168 } else {1168 } else {
1169 return self.fail("TODO: truncate to ints > 32 bits", .{});1169 return self.fail("TODO: truncate to ints > 32 bits", .{});
1170 }1170 }
...@@ -1172,12 +1172,12 @@ fn trunc(...@@ -1172,12 +1172,12 @@ fn trunc(
11721172
1173fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {1173fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
1174 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1174 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1175 const operand = try self.resolveInst(ty_op.operand);1175 const operand_bind: ReadArg.Bind = .{ .inst = ty_op.operand };
1176 const operand_ty = self.air.typeOf(ty_op.operand);1176 const operand_ty = self.air.typeOf(ty_op.operand);
1177 const dest_ty = self.air.typeOfIndex(inst);1177 const dest_ty = self.air.typeOfIndex(inst);
11781178
1179 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: {1179 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: {
1180 break :blk try self.trunc(inst, operand, operand_ty, dest_ty);1180 break :blk try self.trunc(inst, operand_bind, operand_ty, dest_ty);
1181 };1181 };
11821182
1183 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1183 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
...@@ -2334,7 +2334,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2334,7 +2334,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
2334 break :result dst_mcv;2334 break :result dst_mcv;
2335 },2335 },
2336 else => {2336 else => {
2337 const dest = try self.allocRegOrMem(inst, true);2337 const dest = try self.allocRegOrMem(self.air.typeOfIndex(inst), true, inst);
23382338
2339 const base_bind: ReadArg.Bind = .{ .mcv = base_mcv };2339 const base_bind: ReadArg.Bind = .{ .mcv = base_mcv };
2340 const index_bind: ReadArg.Bind = .{ .mcv = index_mcv };2340 const index_bind: ReadArg.Bind = .{ .mcv = index_mcv };
...@@ -2583,16 +2583,18 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -2583,16 +2583,18 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
2583 if (self.liveness.isUnused(inst) and !is_volatile)2583 if (self.liveness.isUnused(inst) and !is_volatile)
2584 break :result MCValue.dead;2584 break :result MCValue.dead;
25852585
2586 const dst_mcv: MCValue = blk: {2586 const dest_mcv: MCValue = blk: {
2587 if (self.reuseOperand(inst, ty_op.operand, 0, ptr)) {2587 const ptr_fits_dest = elem_ty.abiSize(self.target.*) <= 4;
2588 if (ptr_fits_dest and self.reuseOperand(inst, ty_op.operand, 0, ptr)) {
2588 // The MCValue that holds the pointer can be re-used as the value.2589 // The MCValue that holds the pointer can be re-used as the value.
2589 break :blk ptr;2590 break :blk ptr;
2590 } else {2591 } else {
2591 break :blk try self.allocRegOrMem(inst, true);2592 break :blk try self.allocRegOrMem(elem_ty, true, inst);
2592 }2593 }
2593 };2594 };
2594 try self.load(dst_mcv, ptr, self.air.typeOf(ty_op.operand));2595 try self.load(dest_mcv, ptr, self.air.typeOf(ty_op.operand));
2595 break :result dst_mcv;2596
2597 break :result dest_mcv;
2596 };2598 };
2597 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });2599 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
2598}2600}
...@@ -4615,81 +4617,39 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -4615,81 +4617,39 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
4615 return self.finishAir(inst, .unreach, .{ .none, .none, .none });4617 return self.finishAir(inst, .unreach, .{ .none, .none, .none });
4616}4618}
46174619
4618fn isNull(self: *Self, ty: Type, operand: MCValue) !MCValue {4620fn isNull(
4619 if (ty.isPtrLikeOptional()) {4621 self: *Self,
4620 assert(ty.abiSize(self.target.*) == 4);4622 operand_bind: ReadArg.Bind,
46214623 operand_ty: Type,
4622 const reg_mcv: MCValue = switch (operand) {4624) !MCValue {
4623 .register => operand,4625 if (operand_ty.isPtrLikeOptional()) {
4624 else => .{ .register = try self.copyToTmpRegister(ty, operand) },4626 assert(operand_ty.abiSize(self.target.*) == 4);
4625 };
4626
4627 _ = try self.addInst(.{
4628 .tag = .cmp,
4629 .data = .{ .r_op_cmp = .{
4630 .rn = reg_mcv.register,
4631 .op = Instruction.Operand.fromU32(0).?,
4632 } },
4633 });
46344627
4635 return MCValue{ .cpsr_flags = .eq };4628 const imm_bind: ReadArg.Bind = .{ .mcv = .{ .immediate = 0 } };
4629 return self.cmp(operand_bind, imm_bind, Type.usize, .eq);
4636 } else {4630 } else {
4637 return self.fail("TODO implement non-pointer optionals", .{});4631 return self.fail("TODO implement non-pointer optionals", .{});
4638 }4632 }
4639}4633}
46404634
4641fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue {4635fn isNonNull(
4642 const is_null_result = try self.isNull(ty, operand);
4643 assert(is_null_result.cpsr_flags == .eq);
4644
4645 return MCValue{ .cpsr_flags = .ne };
4646}
4647
4648fn isErr(
4649 self: *Self,4636 self: *Self,
4650 error_union_bind: ReadArg.Bind,4637 operand_bind: ReadArg.Bind,
4651 error_union_ty: Type,4638 operand_ty: Type,
4652) !MCValue {4639) !MCValue {
4653 const error_type = error_union_ty.errorUnionSet();4640 const is_null_result = try self.isNull(operand_bind, operand_ty);
46544641 assert(is_null_result.cpsr_flags == .eq);
4655 if (error_type.errorSetIsEmpty()) {
4656 return MCValue{ .immediate = 0 }; // always false
4657 }
4658
4659 const error_mcv = try self.errUnionErr(error_union_bind, error_union_ty, null);
4660 _ = try self.cmp(.{ .mcv = error_mcv }, .{ .mcv = .{ .immediate = 0 } }, error_type, .neq);
4661 return MCValue{ .cpsr_flags = .hi };
4662}
46634642
4664fn isNonErr(4643 return MCValue{ .cpsr_flags = .ne };
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);
4670 switch (is_err_result) {
4671 .cpsr_flags => |cond| {
4672 assert(cond == .hi);
4673 return MCValue{ .cpsr_flags = cond.negate() };
4674 },
4675 .immediate => |imm| {
4676 assert(imm == 0);
4677 return MCValue{ .immediate = 1 };
4678 },
4679 else => unreachable,
4680 }
4681}4644}
46824645
4683fn airIsNull(self: *Self, inst: Air.Inst.Index) !void {4646fn airIsNull(self: *Self, inst: Air.Inst.Index) !void {
4684 const un_op = self.air.instructions.items(.data)[inst].un_op;4647 const un_op = self.air.instructions.items(.data)[inst].un_op;
4685
4686 try self.spillCompareFlagsIfOccupied();
4687 self.cpsr_flags_inst = inst;
4688
4689 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {4648 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
4690 const operand = try self.resolveInst(un_op);4649 const operand_bind: ReadArg.Bind = .{ .inst = un_op };
4691 const ty = self.air.typeOf(un_op);4650 const operand_ty = self.air.typeOf(un_op);
4692 break :result try self.isNull(ty, operand);4651
4652 break :result try self.isNull(operand_bind, operand_ty);
4693 };4653 };
4694 return self.finishAir(inst, result, .{ un_op, .none, .none });4654 return self.finishAir(inst, result, .{ un_op, .none, .none });
4695}4655}
...@@ -4699,16 +4659,12 @@ fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -4699,16 +4659,12 @@ fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void {
4699 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {4659 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
4700 const operand_ptr = try self.resolveInst(un_op);4660 const operand_ptr = try self.resolveInst(un_op);
4701 const ptr_ty = self.air.typeOf(un_op);4661 const ptr_ty = self.air.typeOf(un_op);
4702 const operand: MCValue = blk: {4662 const elem_ty = ptr_ty.elemType();
4703 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {4663
4704 // The MCValue that holds the pointer can be re-used as the value.4664 const operand = try self.allocRegOrMem(elem_ty, true, null);
4705 break :blk operand_ptr;
4706 } else {
4707 break :blk try self.allocRegOrMem(inst, true);
4708 }
4709 };
4710 try self.load(operand, operand_ptr, ptr_ty);4665 try self.load(operand, operand_ptr, ptr_ty);
4711 break :result try self.isNull(ptr_ty.elemType(), operand);4666
4667 break :result try self.isNull(.{ .mcv = operand }, elem_ty);
4712 };4668 };
4713 return self.finishAir(inst, result, .{ un_op, .none, .none });4669 return self.finishAir(inst, result, .{ un_op, .none, .none });
4714}4670}
...@@ -4716,9 +4672,10 @@ fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -4716,9 +4672,10 @@ fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void {
4716fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void {4672fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void {
4717 const un_op = self.air.instructions.items(.data)[inst].un_op;4673 const un_op = self.air.instructions.items(.data)[inst].un_op;
4718 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {4674 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
4719 const operand = try self.resolveInst(un_op);4675 const operand_bind: ReadArg.Bind = .{ .inst = un_op };
4720 const ty = self.air.typeOf(un_op);4676 const operand_ty = self.air.typeOf(un_op);
4721 break :result try self.isNonNull(ty, operand);4677
4678 break :result try self.isNonNull(operand_bind, operand_ty);
4722 };4679 };
4723 return self.finishAir(inst, result, .{ un_op, .none, .none });4680 return self.finishAir(inst, result, .{ un_op, .none, .none });
4724}4681}
...@@ -4728,20 +4685,50 @@ fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -4728,20 +4685,50 @@ fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void {
4728 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {4685 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
4729 const operand_ptr = try self.resolveInst(un_op);4686 const operand_ptr = try self.resolveInst(un_op);
4730 const ptr_ty = self.air.typeOf(un_op);4687 const ptr_ty = self.air.typeOf(un_op);
4731 const operand: MCValue = blk: {4688 const elem_ty = ptr_ty.elemType();
4732 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {4689
4733 // The MCValue that holds the pointer can be re-used as the value.4690 const operand = try self.allocRegOrMem(elem_ty, true, null);
4734 break :blk operand_ptr;
4735 } else {
4736 break :blk try self.allocRegOrMem(inst, true);
4737 }
4738 };
4739 try self.load(operand, operand_ptr, ptr_ty);4691 try self.load(operand, operand_ptr, ptr_ty);
4740 break :result try self.isNonNull(ptr_ty.elemType(), operand);4692
4693 break :result try self.isNonNull(.{ .mcv = operand }, elem_ty);
4741 };4694 };
4742 return self.finishAir(inst, result, .{ un_op, .none, .none });4695 return self.finishAir(inst, result, .{ un_op, .none, .none });
4743}4696}
47444697
4698fn isErr(
4699 self: *Self,
4700 error_union_bind: ReadArg.Bind,
4701 error_union_ty: Type,
4702) !MCValue {
4703 const error_type = error_union_ty.errorUnionSet();
4704
4705 if (error_type.errorSetIsEmpty()) {
4706 return MCValue{ .immediate = 0 }; // always false
4707 }
4708
4709 const error_mcv = try self.errUnionErr(error_union_bind, error_union_ty, null);
4710 return try self.cmp(.{ .mcv = error_mcv }, .{ .mcv = .{ .immediate = 0 } }, error_type, .gt);
4711}
4712
4713fn isNonErr(
4714 self: *Self,
4715 error_union_bind: ReadArg.Bind,
4716 error_union_ty: Type,
4717) !MCValue {
4718 const is_err_result = try self.isErr(error_union_bind, error_union_ty);
4719 switch (is_err_result) {
4720 .cpsr_flags => |cond| {
4721 assert(cond == .hi);
4722 return MCValue{ .cpsr_flags = cond.negate() };
4723 },
4724 .immediate => |imm| {
4725 assert(imm == 0);
4726 return MCValue{ .immediate = 1 };
4727 },
4728 else => unreachable,
4729 }
4730}
4731
4745fn airIsErr(self: *Self, inst: Air.Inst.Index) !void {4732fn airIsErr(self: *Self, inst: Air.Inst.Index) !void {
4746 const un_op = self.air.instructions.items(.data)[inst].un_op;4733 const un_op = self.air.instructions.items(.data)[inst].un_op;
4747 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {4734 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
...@@ -4758,16 +4745,12 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -4758,16 +4745,12 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void {
4758 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {4745 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
4759 const operand_ptr = try self.resolveInst(un_op);4746 const operand_ptr = try self.resolveInst(un_op);
4760 const ptr_ty = self.air.typeOf(un_op);4747 const ptr_ty = self.air.typeOf(un_op);
4761 const operand: MCValue = blk: {4748 const elem_ty = ptr_ty.elemType();
4762 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {4749
4763 // The MCValue that holds the pointer can be re-used as the value.4750 const operand = try self.allocRegOrMem(elem_ty, true, null);
4764 break :blk operand_ptr;
4765 } else {
4766 break :blk try self.allocRegOrMem(inst, true);
4767 }
4768 };
4769 try self.load(operand, operand_ptr, ptr_ty);4751 try self.load(operand, operand_ptr, ptr_ty);
4770 break :result try self.isErr(.{ .mcv = operand }, ptr_ty.elemType());4752
4753 break :result try self.isErr(.{ .mcv = operand }, elem_ty);
4771 };4754 };
4772 return self.finishAir(inst, result, .{ un_op, .none, .none });4755 return self.finishAir(inst, result, .{ un_op, .none, .none });
4773}4756}
...@@ -4788,16 +4771,12 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -4788,16 +4771,12 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void {
4788 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {4771 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
4789 const operand_ptr = try self.resolveInst(un_op);4772 const operand_ptr = try self.resolveInst(un_op);
4790 const ptr_ty = self.air.typeOf(un_op);4773 const ptr_ty = self.air.typeOf(un_op);
4791 const operand: MCValue = blk: {4774 const elem_ty = ptr_ty.elemType();
4792 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {4775
4793 // The MCValue that holds the pointer can be re-used as the value.4776 const operand = try self.allocRegOrMem(elem_ty, true, null);
4794 break :blk operand_ptr;
4795 } else {
4796 break :blk try self.allocRegOrMem(inst, true);
4797 }
4798 };
4799 try self.load(operand, operand_ptr, ptr_ty);4777 try self.load(operand, operand_ptr, ptr_ty);
4800 break :result try self.isNonErr(.{ .mcv = operand }, ptr_ty.elemType());4778
4779 break :result try self.isNonErr(.{ .mcv = operand }, elem_ty);
4801 };4780 };
4802 return self.finishAir(inst, result, .{ un_op, .none, .none });4781 return self.finishAir(inst, result, .{ un_op, .none, .none });
4803}4782}
...@@ -5010,7 +4989,7 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {...@@ -5010,7 +4989,7 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
5010 .none, .dead, .unreach => unreachable,4989 .none, .dead, .unreach => unreachable,
5011 .register, .stack_offset, .memory => operand_mcv,4990 .register, .stack_offset, .memory => operand_mcv,
5012 .immediate, .stack_argument_offset, .cpsr_flags => blk: {4991 .immediate, .stack_argument_offset, .cpsr_flags => blk: {
5013 const new_mcv = try self.allocRegOrMem(block, true);4992 const new_mcv = try self.allocRegOrMem(self.air.typeOfIndex(block), true, block);
5014 try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv);4993 try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv);
5015 break :blk new_mcv;4994 break :blk new_mcv;
5016 },4995 },