| ... | ... | @@ -3068,13 +3068,37 @@ fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void { |
| 3068 | 3068 | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 3069 | 3069 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3070 | 3070 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 3071 | const payload_ty = self.air.typeOf(ty_op.operand); |
| 3072 | if (!payload_ty.hasRuntimeBits()) { |
| 3073 | break :result MCValue{ .immediate = 1 }; |
| 3074 | } |
| 3075 | |
| 3071 | 3076 | const optional_ty = self.air.typeOfIndex(inst); |
| 3077 | const operand = try self.resolveInst(ty_op.operand); |
| 3078 | const operand_lock: ?RegisterLock = switch (operand) { |
| 3079 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 3080 | else => null, |
| 3081 | }; |
| 3082 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); |
| 3072 | 3083 | |
| 3073 | | // Optional with a zero-bit payload type is just a boolean true |
| 3074 | | if (optional_ty.abiSize(self.target.*) == 1) |
| 3075 | | break :result MCValue{ .immediate = 1 }; |
| 3084 | if (optional_ty.isPtrLikeOptional()) { |
| 3085 | // TODO should we check if we can reuse the operand? |
| 3086 | const raw_reg = try self.register_manager.allocReg(inst, gp); |
| 3087 | const reg = self.registerAlias(raw_reg, payload_ty); |
| 3088 | try self.genSetReg(payload_ty, raw_reg, operand); |
| 3089 | break :result MCValue{ .register = reg }; |
| 3090 | } |
| 3076 | 3091 | |
| 3077 | | return self.fail("TODO implement wrap optional for {}", .{self.target.cpu.arch}); |
| 3092 | const optional_abi_size = @intCast(u32, optional_ty.abiSize(self.target.*)); |
| 3093 | const optional_abi_align = optional_ty.abiAlignment(self.target.*); |
| 3094 | const payload_abi_size = @intCast(u32, payload_ty.abiSize(self.target.*)); |
| 3095 | const offset = optional_abi_size - payload_abi_size; |
| 3096 | |
| 3097 | const stack_offset = try self.allocMem(optional_abi_size, optional_abi_align, inst); |
| 3098 | try self.genSetStack(Type.bool, stack_offset, .{ .immediate = 1 }); |
| 3099 | try self.genSetStack(payload_ty, stack_offset - @intCast(u32, offset), operand); |
| 3100 | |
| 3101 | break :result MCValue{ .stack_offset = stack_offset }; |
| 3078 | 3102 | }; |
| 3079 | 3103 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 3080 | 3104 | } |