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