]> git.lizzy.rs Git - rust.git/blob - src/pointer.rs
Introduce PointerBase::Dangling
[rust.git] / src / pointer.rs
1 use crate::prelude::*;
2
3 use rustc_target::abi::Align;
4
5 use cranelift_codegen::ir::immediates::Offset32;
6
7 #[derive(Copy, Clone, Debug)]
8 pub(crate) struct Pointer {
9     base: PointerBase,
10     offset: Offset32,
11 }
12
13 #[derive(Copy, Clone, Debug)]
14 pub(crate) enum PointerBase {
15     Addr(Value),
16     Stack(StackSlot),
17     Dangling(Align),
18 }
19
20 impl Pointer {
21     pub(crate) fn new(addr: Value) -> Self {
22         Pointer {
23             base: PointerBase::Addr(addr),
24             offset: Offset32::new(0),
25         }
26     }
27
28     pub(crate) fn stack_slot(stack_slot: StackSlot) -> Self {
29         Pointer {
30             base: PointerBase::Stack(stack_slot),
31             offset: Offset32::new(0),
32         }
33     }
34
35     pub(crate) fn const_addr<'a, 'tcx>(fx: &mut FunctionCx<'a, 'tcx, impl Backend>, addr: i64) -> Self {
36         let addr = fx.bcx.ins().iconst(fx.pointer_type, addr);
37         Pointer {
38             base: PointerBase::Addr(addr),
39             offset: Offset32::new(0),
40         }
41     }
42
43     pub(crate) fn dangling(align: Align) -> Self {
44         Pointer {
45             base: PointerBase::Dangling(align),
46             offset: Offset32::new(0),
47         }
48     }
49
50     #[cfg(debug_assertions)]
51     pub(crate) fn base_and_offset(self) -> (PointerBase, Offset32) {
52         (self.base, self.offset)
53     }
54
55     pub(crate) fn get_addr<'a, 'tcx>(self, fx: &mut FunctionCx<'a, 'tcx, impl Backend>) -> Value {
56         match self.base {
57             PointerBase::Addr(base_addr) => {
58                 let offset: i64 = self.offset.into();
59                 if offset == 0 {
60                     base_addr
61                 } else {
62                     fx.bcx.ins().iadd_imm(base_addr, offset)
63                 }
64             }
65             PointerBase::Stack(stack_slot) => fx.bcx.ins().stack_addr(fx.pointer_type, stack_slot, self.offset),
66             PointerBase::Dangling(align) => {
67                 fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(align.bytes()).unwrap())
68             }
69         }
70     }
71
72     pub(crate) fn offset<'a, 'tcx>(
73         self,
74         fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
75         extra_offset: Offset32,
76     ) -> Self {
77         self.offset_i64(fx, extra_offset.into())
78     }
79
80     pub(crate) fn offset_i64<'a, 'tcx>(
81         self,
82         fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
83         extra_offset: i64,
84     ) -> Self {
85         if let Some(new_offset) = self.offset.try_add_i64(extra_offset) {
86             Pointer {
87                 base: self.base,
88                 offset: new_offset,
89             }
90         } else {
91             let base_offset: i64 = self.offset.into();
92             if let Some(new_offset) = base_offset.checked_add(extra_offset){
93                 let base_addr = match self.base {
94                     PointerBase::Addr(addr) => addr,
95                     PointerBase::Stack(stack_slot) => fx.bcx.ins().stack_addr(fx.pointer_type, stack_slot, 0),
96                     PointerBase::Dangling(align) => fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(align.bytes()).unwrap()),
97                 };
98                 let addr = fx.bcx.ins().iadd_imm(base_addr, new_offset);
99                 Pointer {
100                     base: PointerBase::Addr(addr),
101                     offset: Offset32::new(0),
102                 }
103             } else {
104                 panic!("self.offset ({}) + extra_offset ({}) not representable in i64", base_offset, extra_offset);
105             }
106         }
107     }
108
109     pub(crate) fn offset_value<'a, 'tcx>(
110         self,
111         fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
112         extra_offset: Value,
113     ) -> Self {
114         match self.base {
115             PointerBase::Addr(addr) => Pointer {
116                 base: PointerBase::Addr(fx.bcx.ins().iadd(addr, extra_offset)),
117                 offset: self.offset,
118             },
119             PointerBase::Stack(stack_slot) => {
120                 let base_addr = fx.bcx.ins().stack_addr(fx.pointer_type, stack_slot, self.offset);
121                 Pointer {
122                     base: PointerBase::Addr(fx.bcx.ins().iadd(base_addr, extra_offset)),
123                     offset: Offset32::new(0),
124                 }
125             }
126             PointerBase::Dangling(align) => {
127                 let addr = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(align.bytes()).unwrap());
128                 Pointer {
129                     base: PointerBase::Addr(fx.bcx.ins().iadd(addr, extra_offset)),
130                     offset: self.offset,
131                 }
132             }
133         }
134     }
135
136     pub(crate) fn load<'a, 'tcx>(
137         self,
138         fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
139         ty: Type,
140         flags: MemFlags,
141     ) -> Value {
142         match self.base {
143             PointerBase::Addr(base_addr) => fx.bcx.ins().load(ty, flags, base_addr, self.offset),
144             PointerBase::Stack(stack_slot) => if ty == types::I128 || ty.is_vector() {
145                 // WORKAROUND for stack_load.i128 and stack_load.iXxY not being implemented
146                 let base_addr = fx.bcx.ins().stack_addr(fx.pointer_type, stack_slot, 0);
147                 fx.bcx.ins().load(ty, flags, base_addr, self.offset)
148             } else {
149                 fx.bcx.ins().stack_load(ty, stack_slot, self.offset)
150             }
151             PointerBase::Dangling(_align) => unreachable!(),
152         }
153     }
154
155     pub(crate) fn store<'a, 'tcx>(
156         self,
157         fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
158         value: Value,
159         flags: MemFlags,
160     ) {
161         match self.base {
162             PointerBase::Addr(base_addr) => {
163                 fx.bcx.ins().store(flags, value, base_addr, self.offset);
164             }
165             PointerBase::Stack(stack_slot) => {
166                 let val_ty = fx.bcx.func.dfg.value_type(value);
167                 if val_ty == types::I128 || val_ty.is_vector() {
168                     // WORKAROUND for stack_store.i128 and stack_store.iXxY not being implemented
169                     let base_addr = fx.bcx.ins().stack_addr(fx.pointer_type, stack_slot, 0);
170                     fx.bcx.ins().store(flags, value, base_addr, self.offset);
171                 } else {
172                     fx.bcx.ins().stack_store(value, stack_slot, self.offset);
173                 }
174             }
175             PointerBase::Dangling(_align) => unreachable!(),
176         }
177     }
178 }