Skip to content

Commit 993baf5

Browse files
committed
Add codegen test for ScalarPair with i128 on LLVM 17
1 parent 01c30a4 commit 993baf5

File tree

1 file changed

+101
-0
lines changed

1 file changed

+101
-0
lines changed

tests/codegen/i128-x86-align.rs

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// only-x86_64
2+
// compile-flags: -O -C no-prepopulate-passes --crate-type=lib
3+
4+
// On LLVM 17 and earlier LLVM's own data layout specifies that i128 has 8 byte alignment,
5+
// while rustc wants it to have 16 byte alignment. This test checks that we handle this
6+
// correctly.
7+
8+
// CHECK: %ScalarPair = type { i32, [3 x i32], i128 }
9+
// CHECK: %Struct = type { i32, i32, [2 x i32], i128 }
10+
11+
#[repr(C)]
12+
#[derive(Clone, Copy)]
13+
pub struct ScalarPair {
14+
a: i32,
15+
b: i128,
16+
}
17+
18+
#[no_mangle]
19+
pub fn load(x: &ScalarPair) -> ScalarPair {
20+
// CHECK-LABEL: @load(
21+
// CHECK-SAME: align 16 dereferenceable(32) %x
22+
// CHECK: [[A:%.*]] = load i32, ptr %x, align 16
23+
// CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr %x, i64 16
24+
// CHECK-NEXT: [[B:%.*]] = load i128, ptr [[GEP]], align 16
25+
// CHECK-NEXT: [[IV1:%.*]] = insertvalue { i32, i128 } poison, i32 [[A]], 0
26+
// CHECK-NEXT: [[IV2:%.*]] = insertvalue { i32, i128 } [[IV1]], i128 [[B]], 1
27+
// CHECK-NEXT: ret { i32, i128 } [[IV2]]
28+
*x
29+
}
30+
31+
#[no_mangle]
32+
pub fn store(x: &mut ScalarPair) {
33+
// CHECK-LABEL: @store(
34+
// CHECK-SAME: align 16 dereferenceable(32) %x
35+
// CHECK: store i32 1, ptr %x, align 16
36+
// CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr %x, i64 16
37+
// CHECK-NEXT: store i128 2, ptr [[GEP]], align 16
38+
*x = ScalarPair { a: 1, b: 2 };
39+
}
40+
41+
#[no_mangle]
42+
pub fn alloca() {
43+
// CHECK-LABEL: @alloca(
44+
// CHECK: [[X:%.*]] = alloca %ScalarPair, align 16
45+
// CHECK: store i32 1, ptr %x, align 16
46+
// CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr %x, i64 16
47+
// CHECK-NEXT: store i128 2, ptr [[GEP]], align 16
48+
let mut x = ScalarPair { a: 1, b: 2 };
49+
store(&mut x);
50+
}
51+
52+
#[no_mangle]
53+
pub fn load_volatile(x: &ScalarPair) -> ScalarPair {
54+
// CHECK-LABEL: @load_volatile(
55+
// CHECK-SAME: align 16 dereferenceable(32) %x
56+
// CHECK: [[TMP:%.*]] = alloca %ScalarPair, align 16
57+
// CHECK: [[LOAD:%.*]] = load volatile %ScalarPair, ptr %x, align 16
58+
// CHECK-NEXT: store %ScalarPair [[LOAD]], ptr [[TMP]], align 16
59+
// CHECK-NEXT: [[A:%.*]] = load i32, ptr [[TMP]], align 16
60+
// CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[TMP]], i64 16
61+
// CHECK-NEXT: [[B:%.*]] = load i128, ptr [[GEP]], align 16
62+
unsafe { std::ptr::read_volatile(x) }
63+
}
64+
65+
#[no_mangle]
66+
pub fn transmute(x: ScalarPair) -> (std::mem::MaybeUninit<i128>, i128) {
67+
// CHECK-LABEL: define { i128, i128 } @transmute(i32 noundef %x.0, i128 noundef %x.1)
68+
// CHECK: [[TMP:%.*]] = alloca { i128, i128 }, align 16
69+
// CHECK-NEXT: store i32 %x.0, ptr [[TMP]], align 16
70+
// CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[TMP]], i64 16
71+
// CHECK-NEXT: store i128 %x.1, ptr [[GEP]], align 16
72+
// CHECK-NEXT: [[LOAD1:%.*]] = load i128, ptr %_0, align 16
73+
// CHECK-NEXT: [[GEP2:%.*]] = getelementptr inbounds i8, ptr [[TMP]], i64 16
74+
// CHECK-NEXT: [[LOAD2:%.*]] = load i128, ptr [[GEP2]], align 16
75+
// CHECK-NEXT: [[IV1:%.*]] = insertvalue { i128, i128 } poison, i128 [[LOAD1]], 0
76+
// CHECK-NEXT: [[IV2:%.*]] = insertvalue { i128, i128 } [[IV1]], i128 [[LOAD2]], 1
77+
// CHECK-NEXT: ret { i128, i128 } [[IV2]]
78+
unsafe { std::mem::transmute(x) }
79+
}
80+
81+
#[repr(C)]
82+
#[derive(Clone, Copy)]
83+
pub struct Struct {
84+
a: i32,
85+
b: i32,
86+
c: i128,
87+
}
88+
89+
#[no_mangle]
90+
pub fn store_struct(x: &mut Struct) {
91+
// CHECK-LABEL: @store_struct(
92+
// CHECK-SAME: align 16 dereferenceable(32) %x
93+
// CHECK: [[TMP:%.*]] = alloca %Struct, align 16
94+
// CHECK: store i32 1, ptr [[TMP]], align 16
95+
// CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds %Struct, ptr [[TMP]], i32 0, i32 1
96+
// CHECK-NEXT: store i32 2, ptr [[GEP1]], align 4
97+
// CHECK-NEXT: [[GEP2:%.*]] = getelementptr inbounds %Struct, ptr [[TMP]], i32 0, i32 3
98+
// CHECK-NEXT: store i128 3, ptr [[GEP2]], align 16
99+
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 16 %x, ptr align 16 [[TMP]], i64 32, i1 false)
100+
*x = Struct { a: 1, b: 2, c: 3 };
101+
}

0 commit comments

Comments
 (0)