Skip to content

Commit 48c24e4

Browse files
committed
Add behavior tests for Arc and Rc
1 parent fbcff0a commit 48c24e4

2 files changed

Lines changed: 254 additions & 0 deletions

File tree

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
//! This test pins the behaviors of some `Rc` and `Arc` operations so that changes are noticed.
2+
//! These operations are frequently used, so they should behave as expected.
3+
4+
//@ compile-flags: --crate-type=lib -Z merge-functions=disabled -C opt-level=3 -C llvm-args=-x86-asm-syntax=intel
5+
//@ assembly-output: emit-asm
6+
//@ only-x86_64
7+
use std::mem;
8+
use std::rc::{Rc, Weak as RcWeak};
9+
use std::sync::{Arc, Weak as ArcWeak};
10+
11+
// CHECK-LABEL: rc_new:
12+
// CHECK: mov edi, 24
13+
// CHECK-NEXT: mov esi, 8
14+
// CHECK-NEXT: call qword ptr {{.*}}__rust_alloc
15+
// CHECK-NEXT: test rax, rax
16+
// CHECK-NEXT: je [[RC_NEW_ALLOC_FAIL:\..+]]
17+
// CHECK-NEXT: mov qword ptr [rax], 1
18+
// CHECK-NEXT: mov qword ptr [rax + 8], 1
19+
// CHECK-NEXT: mov qword ptr [rax + 16], rbx
20+
// CHECK-NEXT: pop rbx
21+
// CHECK: ret
22+
// CHECK-NEXT: [[RC_NEW_ALLOC_FAIL]]:
23+
// CHECK: mov edi, 8
24+
// CHECK-NEXT: mov esi, 24
25+
// CHECK-NEXT: call qword ptr {{.*}}handle_alloc_error
26+
#[unsafe(no_mangle)]
27+
pub fn rc_new(x: usize) -> Rc<usize> {
28+
Rc::new(x)
29+
}
30+
31+
// CHECK-LABEL: rc_deref:
32+
// CHECK: mov rax, qword ptr [rdi]
33+
// CHECK-NEXT: add rax, 16
34+
// CHECK-NEXT: ret
35+
#[unsafe(no_mangle)]
36+
pub fn rc_deref(rc: &Rc<usize>) -> &usize {
37+
rc
38+
}
39+
40+
// CHECK-LABEL: rc_increment:
41+
// CHECK: mov rax, qword ptr [rdi]
42+
// CHECK-NEXT: inc qword ptr [rax]
43+
// CHECK-NEXT: je [[RC_INCREMENT_OVERFLOW:\..+]]
44+
// CHECK-NEXT: ret
45+
// CHECK-NEXT: [[RC_INCREMENT_OVERFLOW]]:
46+
// CHECK-NEXT: ud2
47+
#[unsafe(no_mangle)]
48+
pub fn rc_increment(rc: &Rc<usize>) {
49+
mem::forget(Rc::clone(rc));
50+
}
51+
52+
// CHECK-LABEL: rc_decrement:
53+
// CHECK: push rax
54+
// CHECK: mov qword ptr [rsp], rdi
55+
// CHECK-NEXT: dec qword ptr [rdi]
56+
// CHECK-NEXT: je [[RC_DECREMENT_SLOW:\..+]]
57+
// CHECK-NEXT: pop rax
58+
// CHECK: ret
59+
// CHECK-NEXT: [[RC_DECREMENT_SLOW]]:
60+
// CHECK: mov rdi, rsp
61+
// CHECK-NEXT: call qword ptr {{.*}}drop_slow
62+
// CHECK-NEXT: pop rax
63+
// CHECK: ret
64+
#[unsafe(no_mangle)]
65+
pub fn rc_decrement(rc: Rc<usize>) {
66+
drop(rc);
67+
}
68+
69+
// CHECK-LABEL: rc_downgrade:
70+
// CHECK: mov rax, qword ptr [rdi]
71+
// CHECK-NEXT: inc qword ptr [rax + 8]
72+
// CHECK-NEXT: je [[RC_DOWNGRADE_OVERFLOW:\..+]]
73+
// CHECK-NEXT: ret
74+
// CHECK-NEXT: [[RC_DOWNGRADE_OVERFLOW]]:
75+
// CHECK-NEXT: ud2
76+
#[unsafe(no_mangle)]
77+
pub fn rc_downgrade(rc: &Rc<usize>) {
78+
mem::forget(Rc::downgrade(rc));
79+
}
80+
81+
// CHECK-LABEL: rc_upgrade:
82+
// CHECK: mov rax, qword ptr [rdi]
83+
// CHECK-NEXT: cmp rax, -1
84+
// CHECK-NEXT: je [[RC_UPGRADE_RET:\..+]]
85+
// CHECK-NEXT: mov rcx, qword ptr [rax]
86+
// CHECK-NEXT: test rcx, rcx
87+
// CHECK-NEXT: je [[RC_UPGRADE_RET]]
88+
// CHECK-NEXT: inc rcx
89+
// CHECK-NEXT: mov qword ptr [rax], rcx
90+
// CHECK-NEXT: je [[RC_UPGRADE_OVERFLOW:\..+]]
91+
// CHECK-NEXT: [[RC_UPGRADE_RET]]:
92+
// CHECK-NEXT: ret
93+
// CHECK-NEXT: [[RC_UPGRADE_OVERFLOW]]:
94+
// CHECK-NEXT: ud2
95+
#[unsafe(no_mangle)]
96+
pub fn rc_upgrade(weak: &RcWeak<usize>) {
97+
mem::forget(weak.upgrade());
98+
}
99+
100+
// CHECK-LABEL: arc_new:
101+
// CHECK: mov edi, 24
102+
// CHECK-NEXT: mov esi, 8
103+
// CHECK-NEXT: call qword ptr {{.*}}__rust_alloc
104+
// CHECK-NEXT: test rax, rax
105+
// CHECK-NEXT: je [[ARC_NEW_ALLOC_FAIL:\..+]]
106+
// CHECK-NEXT: mov qword ptr [rax], 1
107+
// CHECK-NEXT: mov qword ptr [rax + 8], 1
108+
// CHECK-NEXT: mov qword ptr [rax + 16], rbx
109+
// CHECK-NEXT: pop rbx
110+
// CHECK: ret
111+
// CHECK-NEXT: [[ARC_NEW_ALLOC_FAIL]]:
112+
// CHECK: mov edi, 8
113+
// CHECK-NEXT: mov esi, 24
114+
// CHECK-NEXT: call qword ptr {{.*}}handle_alloc_error
115+
#[unsafe(no_mangle)]
116+
pub fn arc_new(x: usize) -> Arc<usize> {
117+
Arc::new(x)
118+
}
119+
120+
// CHECK-LABEL: arc_deref:
121+
// CHECK: mov rax, qword ptr [rdi]
122+
// CHECK-NEXT: add rax, 16
123+
// CHECK-NEXT: ret
124+
#[unsafe(no_mangle)]
125+
pub fn arc_deref(arc: &Arc<usize>) -> &usize {
126+
arc
127+
}
128+
129+
// CHECK-LABEL: arc_increment:
130+
// CHECK: mov rax, qword ptr [rdi]
131+
// CHECK-NEXT: lock inc qword ptr [rax]
132+
// CHECK-NEXT: jle [[ARC_INCREMENT_OVERFLOW:\..+]]
133+
// CHECK-NEXT: ret
134+
// CHECK-NEXT: [[ARC_INCREMENT_OVERFLOW]]:
135+
// CHECK-NEXT: ud2
136+
#[unsafe(no_mangle)]
137+
pub fn arc_increment(arc: &Arc<usize>) {
138+
mem::forget(Arc::clone(arc));
139+
}
140+
141+
// CHECK-LABEL: arc_decrement:
142+
// CHECK: push rax
143+
// CHECK: mov qword ptr [rsp], rdi
144+
// CHECK-NEXT: lock dec qword ptr [rdi]
145+
// CHECK-NEXT: jne [[ARC_DECREMENT_RET:\..+]]
146+
// CHECK-NEXT: #MEMBARRIER
147+
// CHECK-NEXT: mov rdi, rsp
148+
// CHECK-NEXT: call qword ptr {{.*}}drop_slow
149+
// CHECK-NEXT: [[ARC_DECREMENT_RET]]:
150+
// CHECK-NEXT: pop rax
151+
// CHECK: ret
152+
#[unsafe(no_mangle)]
153+
pub fn arc_decrement(arc: Arc<usize>) {
154+
drop(arc);
155+
}
156+
157+
// CHECK-LABEL: arc_downgrade:
158+
// CHECK: push rax
159+
// CHECK: mov rcx, qword ptr [rdi]
160+
// CHECK-NEXT: jmp [[ARC_DOWNGRADE_LOAD:\..+]]
161+
// CHECK: [[ARC_DOWNGRADE_PAUSE:\..+]]:
162+
// CHECK-NEXT: pause
163+
// CHECK-NEXT: [[ARC_DOWNGRADE_LOAD]]:
164+
// CHECK-NEXT: mov rax, qword ptr [rcx + 8]
165+
// CHECK: [[ARC_DOWNGRADE_RETRY:\..+]]:
166+
// CHECK-NEXT: cmp rax, -1
167+
// CHECK-NEXT: je [[ARC_DOWNGRADE_PAUSE]]
168+
// CHECK-NEXT: test rax, rax
169+
// CHECK-NEXT: js [[ARC_DOWNGRADE_OVERFLOW:\..+]]
170+
// CHECK-NEXT: lea rdx, [rax + 1]
171+
// CHECK-NEXT: lock cmpxchg qword ptr [rcx + 8], rdx
172+
// CHECK-NEXT: jne [[ARC_DOWNGRADE_RETRY]]
173+
// CHECK-NEXT: pop rax
174+
// CHECK: ret
175+
// CHECK: [[ARC_DOWNGRADE_OVERFLOW]]:
176+
// CHECK: lea rdi, {{.*}}]
177+
// CHECK-NEXT: call qword ptr {{.*}}panic_arc_overflow
178+
#[unsafe(no_mangle)]
179+
pub fn arc_downgrade(arc: &Arc<usize>) {
180+
mem::forget(Arc::downgrade(arc));
181+
}
182+
183+
// CHECK-LABEL: arc_upgrade:
184+
// CHECK: push rax
185+
// CHECK: mov rcx, qword ptr [rdi]
186+
// CHECK-NEXT: cmp rcx, -1
187+
// CHECK-NEXT: je [[ARC_UPGRADE_RET:\..+]]
188+
// CHECK-NEXT: mov rax, qword ptr [rcx]
189+
// CHECK: [[ARC_UPGRADE_RETRY:\..+]]:
190+
// CHECK-NEXT: test rax, rax
191+
// CHECK-NEXT: je [[ARC_UPGRADE_RET]]
192+
// CHECK-NEXT: js [[ARC_UPGRADE_OVERFLOW:\..+]]
193+
// CHECK-NEXT: lea rdx, [rax + 1]
194+
// CHECK-NEXT: lock cmpxchg qword ptr [rcx], rdx
195+
// CHECK-NEXT: jne [[ARC_UPGRADE_RETRY]]
196+
// CHECK-NEXT: [[ARC_UPGRADE_RET]]:
197+
// CHECK-NEXT: pop rax
198+
// CHECK: ret
199+
// CHECK: [[ARC_UPGRADE_OVERFLOW]]:
200+
// CHECK: lea rdi, {{.*}}]
201+
// CHECK-NEXT: call qword ptr {{.*}}panic_arc_overflow
202+
#[unsafe(no_mangle)]
203+
pub fn arc_upgrade(weak: &ArcWeak<usize>) {
204+
mem::forget(weak.upgrade());
205+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//@ compile-flags: -O -Z merge-functions=disabled
2+
3+
#![crate_type = "lib"]
4+
5+
use std::rc::{self, Rc};
6+
use std::sync::{self, Arc};
7+
8+
// Ensures that we can create array of `Weak`s using `memset`.
9+
10+
#[no_mangle]
11+
pub fn array_of_rc_weak() -> [rc::Weak<u32>; 100] {
12+
// CHECK-LABEL: @array_of_rc_weak(
13+
// CHECK-NEXT: start:
14+
// CHECK-NEXT: call void @llvm.memset.
15+
// CHECK-NEXT: ret void
16+
[(); 100].map(|()| rc::Weak::new())
17+
}
18+
19+
#[no_mangle]
20+
pub fn array_of_sync_weak() -> [sync::Weak<u32>; 100] {
21+
// CHECK-LABEL: @array_of_sync_weak(
22+
// CHECK-NEXT: start:
23+
// CHECK-NEXT: call void @llvm.memset.
24+
// CHECK-NEXT: ret void
25+
[(); 100].map(|()| sync::Weak::new())
26+
}
27+
28+
// Asserts that converting from `&Option<Rc<T>>` and `&Option<Arc<T>>` to `Option<&T>` required
29+
// checking for `None`.
30+
31+
#[no_mangle]
32+
pub fn option_rc_as_deref_no_cmp(rc: &Option<Rc<u32>>) -> Option<&u32> {
33+
// CHECK-LABEL: @option_rc_as_deref_no_cmp(ptr
34+
// CHECK-NEXT: start:
35+
// CHECK-NEXT: load ptr, ptr
36+
// CHECK-NEXT: icmp
37+
// CHECK: ret ptr
38+
rc.as_deref()
39+
}
40+
41+
#[no_mangle]
42+
pub fn option_arc_as_deref_no_cmp(arc: &Option<Arc<u32>>) -> Option<&u32> {
43+
// CHECK-LABEL: @option_arc_as_deref_no_cmp(ptr
44+
// CHECK-NEXT: start:
45+
// CHECK-NEXT: load ptr, ptr
46+
// CHECK-NEXT: icmp
47+
// CHECK: ret ptr
48+
arc.as_deref()
49+
}

0 commit comments

Comments
 (0)