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