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