]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_cranelift/src/pointer.rs
Auto merge of #83271 - SparrowLii:simd_neg, r=Amanieu
[rust.git] / compiler / rustc_codegen_cranelift / 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 { base: PointerBase::Addr(addr), offset: Offset32::new(0) }
27     }
28
29     pub(crate) fn stack_slot(stack_slot: StackSlot) -> Self {
30         Pointer { base: PointerBase::Stack(stack_slot), offset: Offset32::new(0) }
31     }
32
33     pub(crate) fn const_addr(fx: &mut FunctionCx<'_, '_, '_>, addr: i64) -> Self {
34         let addr = fx.bcx.ins().iconst(fx.pointer_type, addr);
35         Pointer { base: PointerBase::Addr(addr), offset: Offset32::new(0) }
36     }
37
38     pub(crate) fn dangling(align: Align) -> Self {
39         Pointer { base: PointerBase::Dangling(align), offset: Offset32::new(0) }
40     }
41
42     #[cfg(debug_assertions)]
43     pub(crate) fn base_and_offset(self) -> (PointerBase, Offset32) {
44         (self.base, self.offset)
45     }
46
47     pub(crate) fn get_addr(self, fx: &mut FunctionCx<'_, '_, '_>) -> Value {
48         match self.base {
49             PointerBase::Addr(base_addr) => {
50                 let offset: i64 = self.offset.into();
51                 if offset == 0 { base_addr } else { fx.bcx.ins().iadd_imm(base_addr, offset) }
52             }
53             PointerBase::Stack(stack_slot) => {
54                 fx.bcx.ins().stack_addr(fx.pointer_type, stack_slot, self.offset)
55             }
56             PointerBase::Dangling(align) => {
57                 fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(align.bytes()).unwrap())
58             }
59         }
60     }
61
62     pub(crate) fn offset(self, fx: &mut FunctionCx<'_, '_, '_>, extra_offset: Offset32) -> Self {
63         self.offset_i64(fx, extra_offset.into())
64     }
65
66     pub(crate) fn offset_i64(self, fx: &mut FunctionCx<'_, '_, '_>, extra_offset: i64) -> Self {
67         if let Some(new_offset) = self.offset.try_add_i64(extra_offset) {
68             Pointer { base: self.base, offset: new_offset }
69         } else {
70             let base_offset: i64 = self.offset.into();
71             if let Some(new_offset) = base_offset.checked_add(extra_offset) {
72                 let base_addr = match self.base {
73                     PointerBase::Addr(addr) => addr,
74                     PointerBase::Stack(stack_slot) => {
75                         fx.bcx.ins().stack_addr(fx.pointer_type, stack_slot, 0)
76                     }
77                     PointerBase::Dangling(align) => {
78                         fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(align.bytes()).unwrap())
79                     }
80                 };
81                 let addr = fx.bcx.ins().iadd_imm(base_addr, new_offset);
82                 Pointer { base: PointerBase::Addr(addr), offset: Offset32::new(0) }
83             } else {
84                 panic!(
85                     "self.offset ({}) + extra_offset ({}) not representable in i64",
86                     base_offset, extra_offset
87                 );
88             }
89         }
90     }
91
92     pub(crate) fn offset_value(self, fx: &mut FunctionCx<'_, '_, '_>, extra_offset: Value) -> Self {
93         match self.base {
94             PointerBase::Addr(addr) => Pointer {
95                 base: PointerBase::Addr(fx.bcx.ins().iadd(addr, extra_offset)),
96                 offset: self.offset,
97             },
98             PointerBase::Stack(stack_slot) => {
99                 let base_addr = fx.bcx.ins().stack_addr(fx.pointer_type, stack_slot, self.offset);
100                 Pointer {
101                     base: PointerBase::Addr(fx.bcx.ins().iadd(base_addr, extra_offset)),
102                     offset: Offset32::new(0),
103                 }
104             }
105             PointerBase::Dangling(align) => {
106                 let addr =
107                     fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(align.bytes()).unwrap());
108                 Pointer {
109                     base: PointerBase::Addr(fx.bcx.ins().iadd(addr, extra_offset)),
110                     offset: self.offset,
111                 }
112             }
113         }
114     }
115
116     pub(crate) fn load(self, fx: &mut FunctionCx<'_, '_, '_>, ty: Type, flags: MemFlags) -> Value {
117         match self.base {
118             PointerBase::Addr(base_addr) => fx.bcx.ins().load(ty, flags, base_addr, self.offset),
119             PointerBase::Stack(stack_slot) => fx.bcx.ins().stack_load(ty, stack_slot, self.offset),
120             PointerBase::Dangling(_align) => unreachable!(),
121         }
122     }
123
124     pub(crate) fn store(self, fx: &mut FunctionCx<'_, '_, '_>, value: Value, flags: MemFlags) {
125         match self.base {
126             PointerBase::Addr(base_addr) => {
127                 fx.bcx.ins().store(flags, value, base_addr, self.offset);
128             }
129             PointerBase::Stack(stack_slot) => {
130                 fx.bcx.ins().stack_store(value, stack_slot, self.offset);
131             }
132             PointerBase::Dangling(_align) => unreachable!(),
133         }
134     }
135 }