]> git.lizzy.rs Git - rust.git/blob - src/pointer.rs
Merge pull request #1079 from CohenArthur/fmt-master
[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>(
36         fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
37         addr: i64,
38     ) -> Self {
39         let addr = fx.bcx.ins().iconst(fx.pointer_type, addr);
40         Pointer {
41             base: PointerBase::Addr(addr),
42             offset: Offset32::new(0),
43         }
44     }
45
46     pub(crate) fn dangling(align: Align) -> Self {
47         Pointer {
48             base: PointerBase::Dangling(align),
49             offset: Offset32::new(0),
50         }
51     }
52
53     #[cfg(debug_assertions)]
54     pub(crate) fn base_and_offset(self) -> (PointerBase, Offset32) {
55         (self.base, self.offset)
56     }
57
58     pub(crate) fn get_addr<'a, 'tcx>(self, fx: &mut FunctionCx<'a, 'tcx, impl Backend>) -> Value {
59         match self.base {
60             PointerBase::Addr(base_addr) => {
61                 let offset: i64 = self.offset.into();
62                 if offset == 0 {
63                     base_addr
64                 } else {
65                     fx.bcx.ins().iadd_imm(base_addr, offset)
66                 }
67             }
68             PointerBase::Stack(stack_slot) => {
69                 fx.bcx
70                     .ins()
71                     .stack_addr(fx.pointer_type, stack_slot, self.offset)
72             }
73             PointerBase::Dangling(align) => fx
74                 .bcx
75                 .ins()
76                 .iconst(fx.pointer_type, i64::try_from(align.bytes()).unwrap()),
77         }
78     }
79
80     pub(crate) fn offset<'a, 'tcx>(
81         self,
82         fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
83         extra_offset: Offset32,
84     ) -> Self {
85         self.offset_i64(fx, extra_offset.into())
86     }
87
88     pub(crate) fn offset_i64<'a, 'tcx>(
89         self,
90         fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
91         extra_offset: i64,
92     ) -> Self {
93         if let Some(new_offset) = self.offset.try_add_i64(extra_offset) {
94             Pointer {
95                 base: self.base,
96                 offset: new_offset,
97             }
98         } else {
99             let base_offset: i64 = self.offset.into();
100             if let Some(new_offset) = base_offset.checked_add(extra_offset) {
101                 let base_addr = match self.base {
102                     PointerBase::Addr(addr) => addr,
103                     PointerBase::Stack(stack_slot) => {
104                         fx.bcx.ins().stack_addr(fx.pointer_type, stack_slot, 0)
105                     }
106                     PointerBase::Dangling(align) => fx
107                         .bcx
108                         .ins()
109                         .iconst(fx.pointer_type, i64::try_from(align.bytes()).unwrap()),
110                 };
111                 let addr = fx.bcx.ins().iadd_imm(base_addr, new_offset);
112                 Pointer {
113                     base: PointerBase::Addr(addr),
114                     offset: Offset32::new(0),
115                 }
116             } else {
117                 panic!(
118                     "self.offset ({}) + extra_offset ({}) not representable in i64",
119                     base_offset, extra_offset
120                 );
121             }
122         }
123     }
124
125     pub(crate) fn offset_value<'a, 'tcx>(
126         self,
127         fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
128         extra_offset: Value,
129     ) -> Self {
130         match self.base {
131             PointerBase::Addr(addr) => Pointer {
132                 base: PointerBase::Addr(fx.bcx.ins().iadd(addr, extra_offset)),
133                 offset: self.offset,
134             },
135             PointerBase::Stack(stack_slot) => {
136                 let base_addr = fx
137                     .bcx
138                     .ins()
139                     .stack_addr(fx.pointer_type, stack_slot, self.offset);
140                 Pointer {
141                     base: PointerBase::Addr(fx.bcx.ins().iadd(base_addr, extra_offset)),
142                     offset: Offset32::new(0),
143                 }
144             }
145             PointerBase::Dangling(align) => {
146                 let addr = fx
147                     .bcx
148                     .ins()
149                     .iconst(fx.pointer_type, i64::try_from(align.bytes()).unwrap());
150                 Pointer {
151                     base: PointerBase::Addr(fx.bcx.ins().iadd(addr, extra_offset)),
152                     offset: self.offset,
153                 }
154             }
155         }
156     }
157
158     pub(crate) fn load<'a, 'tcx>(
159         self,
160         fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
161         ty: Type,
162         flags: MemFlags,
163     ) -> Value {
164         match self.base {
165             PointerBase::Addr(base_addr) => fx.bcx.ins().load(ty, flags, base_addr, self.offset),
166             PointerBase::Stack(stack_slot) => {
167                 if ty == types::I128 || ty.is_vector() {
168                     // WORKAROUND for stack_load.i128 and stack_load.iXxY not being implemented
169                     let base_addr = fx.bcx.ins().stack_addr(fx.pointer_type, stack_slot, 0);
170                     fx.bcx.ins().load(ty, flags, base_addr, self.offset)
171                 } else {
172                     fx.bcx.ins().stack_load(ty, stack_slot, self.offset)
173                 }
174             }
175             PointerBase::Dangling(_align) => unreachable!(),
176         }
177     }
178
179     pub(crate) fn store<'a, 'tcx>(
180         self,
181         fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
182         value: Value,
183         flags: MemFlags,
184     ) {
185         match self.base {
186             PointerBase::Addr(base_addr) => {
187                 fx.bcx.ins().store(flags, value, base_addr, self.offset);
188             }
189             PointerBase::Stack(stack_slot) => {
190                 let val_ty = fx.bcx.func.dfg.value_type(value);
191                 if val_ty == types::I128 || val_ty.is_vector() {
192                     // WORKAROUND for stack_store.i128 and stack_store.iXxY not being implemented
193                     let base_addr = fx.bcx.ins().stack_addr(fx.pointer_type, stack_slot, 0);
194                     fx.bcx.ins().store(flags, value, base_addr, self.offset);
195                 } else {
196                     fx.bcx.ins().stack_store(value, stack_slot, self.offset);
197                 }
198             }
199             PointerBase::Dangling(_align) => unreachable!(),
200         }
201     }
202 }