]> git.lizzy.rs Git - rust.git/blob - src/pointer.rs
Merge pull request #839 from bjorn3/fold_offset_into_load_store
[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 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 get_addr<'a, 'tcx>(self, fx: &mut FunctionCx<'a, 'tcx, impl Backend>) -> Value {
41         match self.base {
42             PointerBase::Addr(base_addr) => {
43                 let offset: i64 = self.offset.into();
44                 if offset == 0 {
45                     base_addr
46                 } else {
47                     fx.bcx.ins().iadd_imm(base_addr, offset)
48                 }
49             }
50             PointerBase::Stack(stack_slot) => fx.bcx.ins().stack_addr(fx.pointer_type, stack_slot, self.offset),
51         }
52     }
53
54     pub fn try_get_addr_and_offset(self) -> Option<(Value, Offset32)> {
55         match self.base {
56             PointerBase::Addr(addr) => Some((addr, self.offset)),
57             PointerBase::Stack(_) => None,
58         }
59     }
60
61     pub fn offset<'a, 'tcx>(
62         self,
63         fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
64         extra_offset: Offset32,
65     ) -> Self {
66         self.offset_i64(fx, extra_offset.into())
67     }
68
69     pub fn offset_i64<'a, 'tcx>(
70         self,
71         fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
72         extra_offset: i64,
73     ) -> Self {
74         if let Some(new_offset) = self.offset.try_add_i64(extra_offset) {
75             Pointer {
76                 base: self.base,
77                 offset: new_offset,
78             }
79         } else {
80             let base_offset: i64 = self.offset.into();
81             if let Some(new_offset) = base_offset.checked_add(extra_offset){
82                 let base_addr = match self.base {
83                     PointerBase::Addr(addr) => addr,
84                     PointerBase::Stack(stack_slot) => fx.bcx.ins().stack_addr(fx.pointer_type, stack_slot, 0),
85                 };
86                 let addr = fx.bcx.ins().iadd_imm(base_addr, new_offset);
87                 Pointer {
88                     base: PointerBase::Addr(addr),
89                     offset: Offset32::new(0),
90                 }
91             } else {
92                 panic!("self.offset ({}) + extra_offset ({}) not representable in i64", base_offset, extra_offset);
93             }
94         }
95     }
96
97     pub fn offset_value<'a, 'tcx>(
98         self,
99         fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
100         extra_offset: Value,
101     ) -> Self {
102         match self.base {
103             PointerBase::Addr(addr) => Pointer {
104                 base: PointerBase::Addr(fx.bcx.ins().iadd(addr, extra_offset)),
105                 offset: self.offset,
106             },
107             PointerBase::Stack(stack_slot) => {
108                 let base_addr = fx.bcx.ins().stack_addr(fx.pointer_type, stack_slot, self.offset);
109                 Pointer {
110                     base: PointerBase::Addr(fx.bcx.ins().iadd(base_addr, extra_offset)),
111                     offset: Offset32::new(0),
112                 }
113             }
114         }
115     }
116
117     pub fn load<'a, 'tcx>(
118         self,
119         fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
120         ty: Type,
121         flags: MemFlags,
122     ) -> Value {
123         match self.base {
124             PointerBase::Addr(base_addr) => fx.bcx.ins().load(ty, flags, base_addr, self.offset),
125             PointerBase::Stack(stack_slot) => if ty == types::I128 {
126                 // WORKAROUND for stack_load.i128 not being implemented
127                 let base_addr = fx.bcx.ins().stack_addr(fx.pointer_type, stack_slot, 0);
128                 fx.bcx.ins().load(ty, flags, base_addr, self.offset)
129             } else {
130                 fx.bcx.ins().stack_load(ty, stack_slot, self.offset)
131             }
132         }
133     }
134
135     pub fn store<'a, 'tcx>(
136         self,
137         fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
138         value: Value,
139         flags: MemFlags,
140     ) {
141         match self.base {
142             PointerBase::Addr(base_addr) => {
143                 fx.bcx.ins().store(flags, value, base_addr, self.offset);
144             }
145             PointerBase::Stack(stack_slot) => if fx.bcx.func.dfg.value_type(value) == types::I128 {
146                 // WORKAROUND for stack_load.i128 not being implemented
147                 let base_addr = fx.bcx.ins().stack_addr(fx.pointer_type, stack_slot, 0);
148                 fx.bcx.ins().store(flags, value, base_addr, self.offset);
149             } else {
150                 fx.bcx.ins().stack_store(value, stack_slot, self.offset);
151             }
152         }
153     }
154 }