]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_middle/src/mir/interpret/allocation/init_mask/tests.rs
New upstream version 1.70.0+dfsg1
[rustc.git] / compiler / rustc_middle / src / mir / interpret / allocation / init_mask / tests.rs
CommitLineData
353b0b11
FG
1use super::*;
2use crate::mir::interpret::alloc_range;
3
4#[test]
5fn uninit_mask() {
6 let mut mask = InitMask::new(Size::from_bytes(500), false);
7 assert!(!mask.get(Size::from_bytes(499)));
8 mask.set_range(alloc_range(Size::from_bytes(499), Size::from_bytes(1)), true);
9 assert!(mask.get(Size::from_bytes(499)));
10 mask.set_range((100..256).into(), true);
11 for i in 0..100 {
12 assert!(!mask.get(Size::from_bytes(i)), "{i} should not be set");
13 }
14 for i in 100..256 {
15 assert!(mask.get(Size::from_bytes(i)), "{i} should be set");
16 }
17 for i in 256..499 {
18 assert!(!mask.get(Size::from_bytes(i)), "{i} should not be set");
19 }
20}
21
22/// Returns the number of materialized blocks for this mask.
23fn materialized_block_count(mask: &InitMask) -> usize {
24 match mask.blocks {
25 InitMaskBlocks::Lazy { .. } => 0,
26 InitMaskBlocks::Materialized(ref blocks) => blocks.blocks.len(),
27 }
28}
29
30#[test]
31fn materialize_mask_within_range() {
32 // To have spare bits, we use a mask size smaller than its block size of 64.
33 let mut mask = InitMask::new(Size::from_bytes(16), false);
34 assert_eq!(materialized_block_count(&mask), 0);
35
36 // Forces materialization, but doesn't require growth. This is case #1 documented in the
37 // `set_range` method.
38 mask.set_range((8..16).into(), true);
39 assert_eq!(materialized_block_count(&mask), 1);
40
41 for i in 0..8 {
42 assert!(!mask.get(Size::from_bytes(i)), "{i} should not be set");
43 }
44 for i in 8..16 {
45 assert!(mask.get(Size::from_bytes(i)), "{i} should be set");
46 }
47}
48
49#[test]
50fn grow_within_unused_bits_with_full_overwrite() {
51 // To have spare bits, we use a mask size smaller than its block size of 64.
52 let mut mask = InitMask::new(Size::from_bytes(16), true);
53 for i in 0..16 {
54 assert!(mask.get(Size::from_bytes(i)), "{i} should be set");
55 }
56
57 // Grow without requiring an additional block. Full overwrite.
58 // This can be fully handled without materialization.
59 let range = (0..32).into();
60 mask.set_range(range, true);
61
62 for i in 0..32 {
63 assert!(mask.get(Size::from_bytes(i)), "{i} should be set");
64 }
65
66 assert_eq!(materialized_block_count(&mask), 0);
67}
68
69// This test checks that an initmask's spare capacity is correctly used when growing within block
70// capacity. This can be fully handled without materialization.
71#[test]
72fn grow_same_state_within_unused_bits() {
73 // To have spare bits, we use a mask size smaller than its block size of 64.
74 let mut mask = InitMask::new(Size::from_bytes(16), true);
75 for i in 0..16 {
76 assert!(mask.get(Size::from_bytes(i)), "{i} should be set");
77 }
78
79 // Grow without requiring an additional block. The gap between the current length and the
80 // range's beginning should be set to the same value as the range.
81 let range = (24..32).into();
82 mask.set_range(range, true);
83
84 // We want to make sure the unused bits in the first block are correct
85 for i in 16..24 {
86 assert!(mask.get(Size::from_bytes(i)), "{i} should be set");
87 }
88
89 for i in 24..32 {
90 assert!(mask.get(Size::from_bytes(i)), "{i} should be set");
91 }
92
93 assert_eq!(1, mask.range_as_init_chunks((0..32).into()).count());
94 assert_eq!(materialized_block_count(&mask), 0);
95}
96
97// This is the same test as `grow_same_state_within_unused_bits` but with both init and uninit
98// states: this forces materialization; otherwise the mask could stay lazy even when needing to
99// grow.
100#[test]
101fn grow_mixed_state_within_unused_bits() {
102 // To have spare bits, we use a mask size smaller than its block size of 64.
103 let mut mask = InitMask::new(Size::from_bytes(16), true);
104 for i in 0..16 {
105 assert!(mask.get(Size::from_bytes(i)), "{i} should be set");
106 }
107
108 // Grow without requiring an additional block. The gap between the current length and the
109 // range's beginning should be set to the same value as the range. Note: since this is fully
110 // out-of-bounds of the current mask, this is case #3 described in the `set_range` method.
111 let range = (24..32).into();
112 mask.set_range(range, false);
113
114 // We want to make sure the unused bits in the first block are correct
115 for i in 16..24 {
116 assert!(!mask.get(Size::from_bytes(i)), "{i} should not be set");
117 }
118
119 for i in 24..32 {
120 assert!(!mask.get(Size::from_bytes(i)), "{i} should not be set");
121 }
122
123 assert_eq!(1, mask.range_as_init_chunks((0..16).into()).count());
124 assert_eq!(2, mask.range_as_init_chunks((0..32).into()).count());
125 assert_eq!(materialized_block_count(&mask), 1);
126}
127
128// This is similar to `grow_mixed_state_within_unused_bits` to force materialization, but the range
129// to set partially overlaps the mask, so this requires a different growth + write pattern in the
130// mask.
131#[test]
132fn grow_within_unused_bits_with_overlap() {
133 // To have spare bits, we use a mask size smaller than its block size of 64.
134 let mut mask = InitMask::new(Size::from_bytes(16), true);
135 for i in 0..16 {
136 assert!(mask.get(Size::from_bytes(i)), "{i} should be set");
137 }
138
139 // Grow without requiring an additional block, but leave no gap after the current len. Note:
140 // since this is partially out-of-bounds of the current mask, this is case #2 described in the
141 // `set_range` method.
142 let range = (8..24).into();
143 mask.set_range(range, false);
144
145 // We want to make sure the unused bits in the first block are correct
146 for i in 8..24 {
147 assert!(!mask.get(Size::from_bytes(i)), "{i} should not be set");
148 }
149
150 assert_eq!(1, mask.range_as_init_chunks((0..8).into()).count());
151 assert_eq!(2, mask.range_as_init_chunks((0..24).into()).count());
152 assert_eq!(materialized_block_count(&mask), 1);
153}
154
155// Force materialization before a full overwrite: the mask can now become lazy.
156#[test]
157fn grow_mixed_state_within_unused_bits_and_full_overwrite() {
158 // To have spare bits, we use a mask size smaller than its block size of 64.
159 let mut mask = InitMask::new(Size::from_bytes(16), true);
160 let range = (0..16).into();
161 assert!(mask.is_range_initialized(range).is_ok());
162
163 // Force materialization.
164 let range = (8..24).into();
165 mask.set_range(range, false);
166 assert!(mask.is_range_initialized(range).is_err());
167 assert_eq!(materialized_block_count(&mask), 1);
168
169 // Full overwrite, lazy blocks would be enough from now on.
170 let range = (0..32).into();
171 mask.set_range(range, true);
172 assert!(mask.is_range_initialized(range).is_ok());
173
174 assert_eq!(1, mask.range_as_init_chunks((0..32).into()).count());
175 assert_eq!(materialized_block_count(&mask), 0);
176}
177
178// Check that growth outside the current capacity can still be lazy: if the init state doesn't
179// change, we don't need materialized blocks.
180#[test]
181fn grow_same_state_outside_capacity() {
182 // To have spare bits, we use a mask size smaller than its block size of 64.
183 let mut mask = InitMask::new(Size::from_bytes(16), true);
184 for i in 0..16 {
185 assert!(mask.get(Size::from_bytes(i)), "{i} should be set");
186 }
187 assert_eq!(materialized_block_count(&mask), 0);
188
189 // Grow to 10 blocks with the same init state.
190 let range = (24..640).into();
191 mask.set_range(range, true);
192
193 assert_eq!(1, mask.range_as_init_chunks((0..640).into()).count());
194 assert_eq!(materialized_block_count(&mask), 0);
195}