| //! Defines [`Pointer`] which is used to improve the quality of the generated clif ir for pointer | |
| //! operations. | |
| use cranelift_codegen::ir::immediates::Offset32; | |
| use rustc_abi::Align; | |
| use crate::prelude::*; | |
| /// A pointer pointing either to a certain address, a certain stack slot or nothing. | |
| #[derive(Copy, Clone, Debug)] | |
| pub(crate) struct Pointer { | |
| base: PointerBase, | |
| offset: Offset32, | |
| } | |
| #[derive(Copy, Clone, Debug)] | |
| pub(crate) enum PointerBase { | |
| Addr(Value), | |
| Stack(StackSlot), | |
| Dangling(Align), | |
| } | |
| impl Pointer { | |
| pub(crate) fn new(addr: Value) -> Self { | |
| Pointer { base: PointerBase::Addr(addr), offset: Offset32::new(0) } | |
| } | |
| pub(crate) fn stack_slot(stack_slot: StackSlot) -> Self { | |
| Pointer { base: PointerBase::Stack(stack_slot), offset: Offset32::new(0) } | |
| } | |
| pub(crate) fn dangling(align: Align) -> Self { | |
| Pointer { base: PointerBase::Dangling(align), offset: Offset32::new(0) } | |
| } | |
| pub(crate) fn debug_base_and_offset(self) -> (PointerBase, Offset32) { | |
| (self.base, self.offset) | |
| } | |
| pub(crate) fn get_addr(self, fx: &mut FunctionCx<'_, '_, '_>) -> Value { | |
| match self.base { | |
| PointerBase::Addr(base_addr) => { | |
| let offset: i64 = self.offset.into(); | |
| if offset == 0 { base_addr } else { fx.bcx.ins().iadd_imm(base_addr, offset) } | |
| } | |
| PointerBase::Stack(stack_slot) => { | |
| fx.bcx.ins().stack_addr(fx.pointer_type, stack_slot, self.offset) | |
| } | |
| PointerBase::Dangling(align) => { | |
| fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(align.bytes()).unwrap()) | |
| } | |
| } | |
| } | |
| pub(crate) fn offset(self, fx: &mut FunctionCx<'_, '_, '_>, extra_offset: Offset32) -> Self { | |
| self.offset_i64(fx, extra_offset.into()) | |
| } | |
| pub(crate) fn offset_i64(self, fx: &mut FunctionCx<'_, '_, '_>, extra_offset: i64) -> Self { | |
| if let Some(new_offset) = self.offset.try_add_i64(extra_offset) { | |
| Pointer { base: self.base, offset: new_offset } | |
| } else { | |
| let base_offset: i64 = self.offset.into(); | |
| if let Some(new_offset) = base_offset.checked_add(extra_offset) { | |
| let base_addr = match self.base { | |
| PointerBase::Addr(addr) => addr, | |
| PointerBase::Stack(stack_slot) => { | |
| fx.bcx.ins().stack_addr(fx.pointer_type, stack_slot, 0) | |
| } | |
| PointerBase::Dangling(align) => { | |
| fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(align.bytes()).unwrap()) | |
| } | |
| }; | |
| let addr = fx.bcx.ins().iadd_imm(base_addr, new_offset); | |
| Pointer { base: PointerBase::Addr(addr), offset: Offset32::new(0) } | |
| } else { | |
| panic!( | |
| "self.offset ({}) + extra_offset ({}) not representable in i64", | |
| base_offset, extra_offset | |
| ); | |
| } | |
| } | |
| } | |
| pub(crate) fn offset_value(self, fx: &mut FunctionCx<'_, '_, '_>, extra_offset: Value) -> Self { | |
| match self.base { | |
| PointerBase::Addr(addr) => Pointer { | |
| base: PointerBase::Addr(fx.bcx.ins().iadd(addr, extra_offset)), | |
| offset: self.offset, | |
| }, | |
| PointerBase::Stack(stack_slot) => { | |
| let base_addr = fx.bcx.ins().stack_addr(fx.pointer_type, stack_slot, self.offset); | |
| Pointer { | |
| base: PointerBase::Addr(fx.bcx.ins().iadd(base_addr, extra_offset)), | |
| offset: Offset32::new(0), | |
| } | |
| } | |
| PointerBase::Dangling(align) => { | |
| let addr = | |
| fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(align.bytes()).unwrap()); | |
| Pointer { | |
| base: PointerBase::Addr(fx.bcx.ins().iadd(addr, extra_offset)), | |
| offset: self.offset, | |
| } | |
| } | |
| } | |
| } | |
| pub(crate) fn load(self, fx: &mut FunctionCx<'_, '_, '_>, ty: Type, flags: MemFlags) -> Value { | |
| match self.base { | |
| PointerBase::Addr(base_addr) => fx.bcx.ins().load(ty, flags, base_addr, self.offset), | |
| PointerBase::Stack(stack_slot) => fx.bcx.ins().stack_load(ty, stack_slot, self.offset), | |
| PointerBase::Dangling(_align) => unreachable!(), | |
| } | |
| } | |
| pub(crate) fn store(self, fx: &mut FunctionCx<'_, '_, '_>, value: Value, flags: MemFlags) { | |
| match self.base { | |
| PointerBase::Addr(base_addr) => { | |
| fx.bcx.ins().store(flags, value, base_addr, self.offset); | |
| } | |
| PointerBase::Stack(stack_slot) => { | |
| fx.bcx.ins().stack_store(value, stack_slot, self.offset); | |
| } | |
| PointerBase::Dangling(_align) => unreachable!(), | |
| } | |
| } | |
| } |