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