• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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