]> git.lizzy.rs Git - rust.git/blob - src/pointer.rs
Use dynamic dispatch for the inner Module
[rust.git] / src / pointer.rs
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 {
25     pub(crate) fn new(addr: Value) -> Self {
26         Pointer {
27             base: PointerBase::Addr(addr),
28             offset: Offset32::new(0),
29         }
30     }
31
32     pub(crate) fn stack_slot(stack_slot: StackSlot) -> Self {
33         Pointer {
34             base: PointerBase::Stack(stack_slot),
35             offset: Offset32::new(0),
36         }
37     }
38
39     pub(crate) fn const_addr(fx: &mut FunctionCx<'_, '_, '_>, addr: i64) -> Self {
40         let addr = fx.bcx.ins().iconst(fx.pointer_type, addr);
41         Pointer {
42             base: PointerBase::Addr(addr),
43             offset: Offset32::new(0),
44         }
45     }
46
47     pub(crate) fn dangling(align: Align) -> Self {
48         Pointer {
49             base: PointerBase::Dangling(align),
50             offset: Offset32::new(0),
51         }
52     }
53
54     #[cfg(debug_assertions)]
55     pub(crate) fn base_and_offset(self) -> (PointerBase, Offset32) {
56         (self.base, self.offset)
57     }
58
59     pub(crate) fn get_addr(self, fx: &mut FunctionCx<'_, '_, '_>) -> Value {
60         match self.base {
61             PointerBase::Addr(base_addr) => {
62                 let offset: i64 = self.offset.into();
63                 if offset == 0 {
64                     base_addr
65                 } else {
66                     fx.bcx.ins().iadd_imm(base_addr, offset)
67                 }
68             }
69             PointerBase::Stack(stack_slot) => {
70                 fx.bcx
71                     .ins()
72                     .stack_addr(fx.pointer_type, stack_slot, self.offset)
73             }
74             PointerBase::Dangling(align) => fx
75                 .bcx
76                 .ins()
77                 .iconst(fx.pointer_type, i64::try_from(align.bytes()).unwrap()),
78         }
79     }
80
81     pub(crate) fn offset(self, fx: &mut FunctionCx<'_, '_, '_>, extra_offset: Offset32) -> Self {
82         self.offset_i64(fx, extra_offset.into())
83     }
84
85     pub(crate) fn offset_i64(self, fx: &mut FunctionCx<'_, '_, '_>, extra_offset: i64) -> Self {
86         if let Some(new_offset) = self.offset.try_add_i64(extra_offset) {
87             Pointer {
88                 base: self.base,
89                 offset: new_offset,
90             }
91         } else {
92             let base_offset: i64 = self.offset.into();
93             if let Some(new_offset) = base_offset.checked_add(extra_offset) {
94                 let base_addr = match self.base {
95                     PointerBase::Addr(addr) => addr,
96                     PointerBase::Stack(stack_slot) => {
97                         fx.bcx.ins().stack_addr(fx.pointer_type, stack_slot, 0)
98                     }
99                     PointerBase::Dangling(align) => fx
100                         .bcx
101                         .ins()
102                         .iconst(fx.pointer_type, i64::try_from(align.bytes()).unwrap()),
103                 };
104                 let addr = fx.bcx.ins().iadd_imm(base_addr, new_offset);
105                 Pointer {
106                     base: PointerBase::Addr(addr),
107                     offset: Offset32::new(0),
108                 }
109             } else {
110                 panic!(
111                     "self.offset ({}) + extra_offset ({}) not representable in i64",
112                     base_offset, extra_offset
113                 );
114             }
115         }
116     }
117
118     pub(crate) fn offset_value(self, fx: &mut FunctionCx<'_, '_, '_>, extra_offset: Value) -> Self {
119         match self.base {
120             PointerBase::Addr(addr) => Pointer {
121                 base: PointerBase::Addr(fx.bcx.ins().iadd(addr, extra_offset)),
122                 offset: self.offset,
123             },
124             PointerBase::Stack(stack_slot) => {
125                 let base_addr = fx
126                     .bcx
127                     .ins()
128                     .stack_addr(fx.pointer_type, stack_slot, self.offset);
129                 Pointer {
130                     base: PointerBase::Addr(fx.bcx.ins().iadd(base_addr, extra_offset)),
131                     offset: Offset32::new(0),
132                 }
133             }
134             PointerBase::Dangling(align) => {
135                 let addr = fx
136                     .bcx
137                     .ins()
138                     .iconst(fx.pointer_type, i64::try_from(align.bytes()).unwrap());
139                 Pointer {
140                     base: PointerBase::Addr(fx.bcx.ins().iadd(addr, extra_offset)),
141                     offset: self.offset,
142                 }
143             }
144         }
145     }
146
147     pub(crate) fn load(self, fx: &mut FunctionCx<'_, '_, '_>, ty: Type, flags: MemFlags) -> Value {
148         match self.base {
149             PointerBase::Addr(base_addr) => fx.bcx.ins().load(ty, flags, base_addr, self.offset),
150             PointerBase::Stack(stack_slot) => fx.bcx.ins().stack_load(ty, stack_slot, self.offset),
151             PointerBase::Dangling(_align) => unreachable!(),
152         }
153     }
154
155     pub(crate) fn store(self, fx: &mut FunctionCx<'_, '_, '_>, value: Value, flags: MemFlags) {
156         match self.base {
157             PointerBase::Addr(base_addr) => {
158                 fx.bcx.ins().store(flags, value, base_addr, self.offset);
159             }
160             PointerBase::Stack(stack_slot) => {
161                 fx.bcx.ins().stack_store(value, stack_slot, self.offset);
162             }
163             PointerBase::Dangling(_align) => unreachable!(),
164         }
165     }
166 }