Loads the stack top value into the next available register, if it isn't already one; spilling if there are no registers available. Optionally the caller may specify a specific destination register. When a named register is requested and it's not at the top of the stack a move from register to register might happen, in which case the source register will be freed.
(
&mut self,
masm: &mut M,
named: Option<Reg>,
)
| 231 | /// stack a move from register to register might happen, in which case |
| 232 | /// the source register will be freed. |
| 233 | pub fn pop_to_reg<M: MacroAssembler>( |
| 234 | &mut self, |
| 235 | masm: &mut M, |
| 236 | named: Option<Reg>, |
| 237 | ) -> Result<TypedReg> { |
| 238 | let typed_reg = if let Some(dst) = named { |
| 239 | self.stack.pop_named_reg(dst) |
| 240 | } else { |
| 241 | self.stack.pop_reg() |
| 242 | }; |
| 243 | |
| 244 | if let Some(dst) = typed_reg { |
| 245 | return Ok(dst); |
| 246 | } |
| 247 | |
| 248 | let val = self.stack.pop().expect("a value at stack top"); |
| 249 | let reg = if let Some(r) = named { |
| 250 | self.reg(r, masm)? |
| 251 | } else { |
| 252 | self.reg_for_type(val.ty(), masm)? |
| 253 | }; |
| 254 | |
| 255 | if val.is_mem() { |
| 256 | let mem = val.unwrap_mem(); |
| 257 | let curr_offset = masm.sp_offset()?.as_u32(); |
| 258 | let slot_offset = mem.slot.offset.as_u32(); |
| 259 | ensure!( |
| 260 | curr_offset == slot_offset, |
| 261 | CodeGenError::invalid_sp_offset(), |
| 262 | ); |
| 263 | masm.pop(writable!(reg), val.ty().try_into()?)?; |
| 264 | } else { |
| 265 | self.move_val_to_reg(&val, reg, masm)?; |
| 266 | // Free the source value if it is a register. |
| 267 | if val.is_reg() { |
| 268 | self.free_reg(val.unwrap_reg()); |
| 269 | } |
| 270 | } |
| 271 | |
| 272 | Ok(TypedReg::new(val.ty(), reg)) |
| 273 | } |
| 274 | |
| 275 | /// Pops the value stack top and stores it at the specified address. |
| 276 | pub fn pop_to_addr<M: MacroAssembler>(&mut self, masm: &mut M, addr: M::Address) -> Result<()> { |
no test coverage detected