1 //! Defines [`Pointer`] which is used to improve the quality of the generated clif ir for pointer 2 //! operations. 3 4 use crate::prelude::*; 5 6 use rustc_target::abi::Align; 7 8 use cranelift_codegen::ir::immediates::Offset32; 9 10 /// A pointer pointing either to a certain address, a certain stack slot or nothing. 11 #[derive(Copy, Clone, Debug)] 12 pub(crate) struct Pointer { 13 base: PointerBase, 14 offset: Offset32, 15 } 16 17 #[derive(Copy, Clone, Debug)] 18 pub(crate) enum PointerBase { 19 Addr(Value), 20 Stack(StackSlot), 21 Dangling(Align), 22 } 23 24 impl Pointer { new(addr: Value) -> Self25 pub(crate) fn new(addr: Value) -> Self { 26 Pointer { base: PointerBase::Addr(addr), offset: Offset32::new(0) } 27 } 28 stack_slot(stack_slot: StackSlot) -> Self29 pub(crate) fn stack_slot(stack_slot: StackSlot) -> Self { 30 Pointer { base: PointerBase::Stack(stack_slot), offset: Offset32::new(0) } 31 } 32 dangling(align: Align) -> Self33 pub(crate) fn dangling(align: Align) -> Self { 34 Pointer { base: PointerBase::Dangling(align), offset: Offset32::new(0) } 35 } 36 debug_base_and_offset(self) -> (PointerBase, Offset32)37 pub(crate) fn debug_base_and_offset(self) -> (PointerBase, Offset32) { 38 (self.base, self.offset) 39 } 40 get_addr(self, fx: &mut FunctionCx<'_, '_, '_>) -> Value41 pub(crate) fn get_addr(self, fx: &mut FunctionCx<'_, '_, '_>) -> Value { 42 match self.base { 43 PointerBase::Addr(base_addr) => { 44 let offset: i64 = self.offset.into(); 45 if offset == 0 { base_addr } else { fx.bcx.ins().iadd_imm(base_addr, offset) } 46 } 47 PointerBase::Stack(stack_slot) => { 48 fx.bcx.ins().stack_addr(fx.pointer_type, stack_slot, self.offset) 49 } 50 PointerBase::Dangling(align) => { 51 fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(align.bytes()).unwrap()) 52 } 53 } 54 } 55 offset(self, fx: &mut FunctionCx<'_, '_, '_>, extra_offset: Offset32) -> Self56 pub(crate) fn offset(self, fx: &mut FunctionCx<'_, '_, '_>, extra_offset: Offset32) -> Self { 57 self.offset_i64(fx, extra_offset.into()) 58 } 59 offset_i64(self, fx: &mut FunctionCx<'_, '_, '_>, extra_offset: i64) -> Self60 pub(crate) fn offset_i64(self, fx: &mut FunctionCx<'_, '_, '_>, extra_offset: i64) -> Self { 61 if let Some(new_offset) = self.offset.try_add_i64(extra_offset) { 62 Pointer { base: self.base, offset: new_offset } 63 } else { 64 let base_offset: i64 = self.offset.into(); 65 if let Some(new_offset) = base_offset.checked_add(extra_offset) { 66 let base_addr = match self.base { 67 PointerBase::Addr(addr) => addr, 68 PointerBase::Stack(stack_slot) => { 69 fx.bcx.ins().stack_addr(fx.pointer_type, stack_slot, 0) 70 } 71 PointerBase::Dangling(align) => { 72 fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(align.bytes()).unwrap()) 73 } 74 }; 75 let addr = fx.bcx.ins().iadd_imm(base_addr, new_offset); 76 Pointer { base: PointerBase::Addr(addr), offset: Offset32::new(0) } 77 } else { 78 panic!( 79 "self.offset ({}) + extra_offset ({}) not representable in i64", 80 base_offset, extra_offset 81 ); 82 } 83 } 84 } 85 offset_value(self, fx: &mut FunctionCx<'_, '_, '_>, extra_offset: Value) -> Self86 pub(crate) fn offset_value(self, fx: &mut FunctionCx<'_, '_, '_>, extra_offset: Value) -> Self { 87 match self.base { 88 PointerBase::Addr(addr) => Pointer { 89 base: PointerBase::Addr(fx.bcx.ins().iadd(addr, extra_offset)), 90 offset: self.offset, 91 }, 92 PointerBase::Stack(stack_slot) => { 93 let base_addr = fx.bcx.ins().stack_addr(fx.pointer_type, stack_slot, self.offset); 94 Pointer { 95 base: PointerBase::Addr(fx.bcx.ins().iadd(base_addr, extra_offset)), 96 offset: Offset32::new(0), 97 } 98 } 99 PointerBase::Dangling(align) => { 100 let addr = 101 fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(align.bytes()).unwrap()); 102 Pointer { 103 base: PointerBase::Addr(fx.bcx.ins().iadd(addr, extra_offset)), 104 offset: self.offset, 105 } 106 } 107 } 108 } 109 load(self, fx: &mut FunctionCx<'_, '_, '_>, ty: Type, flags: MemFlags) -> Value110 pub(crate) fn load(self, fx: &mut FunctionCx<'_, '_, '_>, ty: Type, flags: MemFlags) -> Value { 111 match self.base { 112 PointerBase::Addr(base_addr) => fx.bcx.ins().load(ty, flags, base_addr, self.offset), 113 PointerBase::Stack(stack_slot) => fx.bcx.ins().stack_load(ty, stack_slot, self.offset), 114 PointerBase::Dangling(_align) => unreachable!(), 115 } 116 } 117 store(self, fx: &mut FunctionCx<'_, '_, '_>, value: Value, flags: MemFlags)118 pub(crate) fn store(self, fx: &mut FunctionCx<'_, '_, '_>, value: Value, flags: MemFlags) { 119 match self.base { 120 PointerBase::Addr(base_addr) => { 121 fx.bcx.ins().store(flags, value, base_addr, self.offset); 122 } 123 PointerBase::Stack(stack_slot) => { 124 fx.bcx.ins().stack_store(value, stack_slot, self.offset); 125 } 126 PointerBase::Dangling(_align) => unreachable!(), 127 } 128 } 129 } 130