]>
Commit | Line | Data |
---|---|---|
29967ef6 XL |
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 { | |
6a06907d | 26 | Pointer { base: PointerBase::Addr(addr), offset: Offset32::new(0) } |
29967ef6 XL |
27 | } |
28 | ||
29 | pub(crate) fn stack_slot(stack_slot: StackSlot) -> Self { | |
6a06907d | 30 | Pointer { base: PointerBase::Stack(stack_slot), offset: Offset32::new(0) } |
29967ef6 XL |
31 | } |
32 | ||
6a06907d | 33 | pub(crate) fn const_addr(fx: &mut FunctionCx<'_, '_, '_>, addr: i64) -> Self { |
29967ef6 | 34 | let addr = fx.bcx.ins().iconst(fx.pointer_type, addr); |
6a06907d | 35 | Pointer { base: PointerBase::Addr(addr), offset: Offset32::new(0) } |
29967ef6 XL |
36 | } |
37 | ||
38 | pub(crate) fn dangling(align: Align) -> Self { | |
6a06907d | 39 | Pointer { base: PointerBase::Dangling(align), offset: Offset32::new(0) } |
29967ef6 XL |
40 | } |
41 | ||
cdc7bbd5 | 42 | pub(crate) fn debug_base_and_offset(self) -> (PointerBase, Offset32) { |
29967ef6 XL |
43 | (self.base, self.offset) |
44 | } | |
45 | ||
6a06907d | 46 | pub(crate) fn get_addr(self, fx: &mut FunctionCx<'_, '_, '_>) -> Value { |
29967ef6 XL |
47 | match self.base { |
48 | PointerBase::Addr(base_addr) => { | |
49 | let offset: i64 = self.offset.into(); | |
6a06907d | 50 | if offset == 0 { base_addr } else { fx.bcx.ins().iadd_imm(base_addr, offset) } |
29967ef6 XL |
51 | } |
52 | PointerBase::Stack(stack_slot) => { | |
6a06907d XL |
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()) | |
29967ef6 | 57 | } |
29967ef6 XL |
58 | } |
59 | } | |
60 | ||
6a06907d | 61 | pub(crate) fn offset(self, fx: &mut FunctionCx<'_, '_, '_>, extra_offset: Offset32) -> Self { |
29967ef6 XL |
62 | self.offset_i64(fx, extra_offset.into()) |
63 | } | |
64 | ||
6a06907d | 65 | pub(crate) fn offset_i64(self, fx: &mut FunctionCx<'_, '_, '_>, extra_offset: i64) -> Self { |
29967ef6 | 66 | if let Some(new_offset) = self.offset.try_add_i64(extra_offset) { |
6a06907d | 67 | Pointer { base: self.base, offset: new_offset } |
29967ef6 XL |
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 | } | |
6a06907d XL |
76 | PointerBase::Dangling(align) => { |
77 | fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(align.bytes()).unwrap()) | |
78 | } | |
29967ef6 XL |
79 | }; |
80 | let addr = fx.bcx.ins().iadd_imm(base_addr, new_offset); | |
6a06907d | 81 | Pointer { base: PointerBase::Addr(addr), offset: Offset32::new(0) } |
29967ef6 XL |
82 | } else { |
83 | panic!( | |
84 | "self.offset ({}) + extra_offset ({}) not representable in i64", | |
85 | base_offset, extra_offset | |
86 | ); | |
87 | } | |
88 | } | |
89 | } | |
90 | ||
6a06907d | 91 | pub(crate) fn offset_value(self, fx: &mut FunctionCx<'_, '_, '_>, extra_offset: Value) -> Self { |
29967ef6 XL |
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) => { | |
6a06907d | 98 | let base_addr = fx.bcx.ins().stack_addr(fx.pointer_type, stack_slot, self.offset); |
29967ef6 XL |
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) => { | |
6a06907d XL |
105 | let addr = |
106 | fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(align.bytes()).unwrap()); | |
29967ef6 XL |
107 | Pointer { |
108 | base: PointerBase::Addr(fx.bcx.ins().iadd(addr, extra_offset)), | |
109 | offset: self.offset, | |
110 | } | |
111 | } | |
112 | } | |
113 | } | |
114 | ||
6a06907d | 115 | pub(crate) fn load(self, fx: &mut FunctionCx<'_, '_, '_>, ty: Type, flags: MemFlags) -> Value { |
29967ef6 XL |
116 | match self.base { |
117 | PointerBase::Addr(base_addr) => fx.bcx.ins().load(ty, flags, base_addr, self.offset), | |
6a06907d | 118 | PointerBase::Stack(stack_slot) => fx.bcx.ins().stack_load(ty, stack_slot, self.offset), |
29967ef6 XL |
119 | PointerBase::Dangling(_align) => unreachable!(), |
120 | } | |
121 | } | |
122 | ||
6a06907d | 123 | pub(crate) fn store(self, fx: &mut FunctionCx<'_, '_, '_>, value: Value, flags: MemFlags) { |
29967ef6 XL |
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) => { | |
6a06907d | 129 | fx.bcx.ins().stack_store(value, stack_slot, self.offset); |
29967ef6 XL |
130 | } |
131 | PointerBase::Dangling(_align) => unreachable!(), | |
132 | } | |
133 | } | |
134 | } |