Skip to content

Commit 74c3cca

Browse files
committed
Add behavior tests for Arc and Rc
1 parent fbcff0a commit 74c3cca

2 files changed

Lines changed: 255 additions & 0 deletions

File tree

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