1 //! Defines [`Pointer`] which is used to improve the quality of the generated clif ir for pointer
6 use rustc_target::abi::Align;
8 use cranelift_codegen::ir::immediates::Offset32;
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 {
17 #[derive(Copy, Clone, Debug)]
18 pub(crate) enum PointerBase {
25 pub(crate) fn new(addr: Value) -> Self {
27 base: PointerBase::Addr(addr),
28 offset: Offset32::new(0),
32 pub(crate) fn stack_slot(stack_slot: StackSlot) -> Self {
34 base: PointerBase::Stack(stack_slot),
35 offset: Offset32::new(0),
39 pub(crate) fn const_addr<'a, 'tcx>(
40 fx: &mut FunctionCx<'a, 'tcx, impl Module>,
43 let addr = fx.bcx.ins().iconst(fx.pointer_type, addr);
45 base: PointerBase::Addr(addr),
46 offset: Offset32::new(0),
50 pub(crate) fn dangling(align: Align) -> Self {
52 base: PointerBase::Dangling(align),
53 offset: Offset32::new(0),
57 #[cfg(debug_assertions)]
58 pub(crate) fn base_and_offset(self) -> (PointerBase, Offset32) {
59 (self.base, self.offset)
62 pub(crate) fn get_addr<'a, 'tcx>(self, fx: &mut FunctionCx<'a, 'tcx, impl Module>) -> Value {
64 PointerBase::Addr(base_addr) => {
65 let offset: i64 = self.offset.into();
69 fx.bcx.ins().iadd_imm(base_addr, offset)
72 PointerBase::Stack(stack_slot) => {
75 .stack_addr(fx.pointer_type, stack_slot, self.offset)
77 PointerBase::Dangling(align) => fx
80 .iconst(fx.pointer_type, i64::try_from(align.bytes()).unwrap()),
84 pub(crate) fn offset<'a, 'tcx>(
86 fx: &mut FunctionCx<'a, 'tcx, impl Module>,
87 extra_offset: Offset32,
89 self.offset_i64(fx, extra_offset.into())
92 pub(crate) fn offset_i64<'a, 'tcx>(
94 fx: &mut FunctionCx<'a, 'tcx, impl Module>,
97 if let Some(new_offset) = self.offset.try_add_i64(extra_offset) {
103 let base_offset: i64 = self.offset.into();
104 if let Some(new_offset) = base_offset.checked_add(extra_offset) {
105 let base_addr = match self.base {
106 PointerBase::Addr(addr) => addr,
107 PointerBase::Stack(stack_slot) => {
108 fx.bcx.ins().stack_addr(fx.pointer_type, stack_slot, 0)
110 PointerBase::Dangling(align) => fx
113 .iconst(fx.pointer_type, i64::try_from(align.bytes()).unwrap()),
115 let addr = fx.bcx.ins().iadd_imm(base_addr, new_offset);
117 base: PointerBase::Addr(addr),
118 offset: Offset32::new(0),
122 "self.offset ({}) + extra_offset ({}) not representable in i64",
123 base_offset, extra_offset
129 pub(crate) fn offset_value<'a, 'tcx>(
131 fx: &mut FunctionCx<'a, 'tcx, impl Module>,
135 PointerBase::Addr(addr) => Pointer {
136 base: PointerBase::Addr(fx.bcx.ins().iadd(addr, extra_offset)),
139 PointerBase::Stack(stack_slot) => {
143 .stack_addr(fx.pointer_type, stack_slot, self.offset);
145 base: PointerBase::Addr(fx.bcx.ins().iadd(base_addr, extra_offset)),
146 offset: Offset32::new(0),
149 PointerBase::Dangling(align) => {
153 .iconst(fx.pointer_type, i64::try_from(align.bytes()).unwrap());
155 base: PointerBase::Addr(fx.bcx.ins().iadd(addr, extra_offset)),
162 pub(crate) fn load<'a, 'tcx>(
164 fx: &mut FunctionCx<'a, 'tcx, impl Module>,
169 PointerBase::Addr(base_addr) => fx.bcx.ins().load(ty, flags, base_addr, self.offset),
170 PointerBase::Stack(stack_slot) => {
171 fx.bcx.ins().stack_load(ty, stack_slot, self.offset)
173 PointerBase::Dangling(_align) => unreachable!(),
177 pub(crate) fn store<'a, 'tcx>(
179 fx: &mut FunctionCx<'a, 'tcx, impl Module>,
184 PointerBase::Addr(base_addr) => {
185 fx.bcx.ins().store(flags, value, base_addr, self.offset);
187 PointerBase::Stack(stack_slot) => {
188 fx.bcx.ins().stack_store(value, stack_slot, self.offset);
190 PointerBase::Dangling(_align) => unreachable!(),