Skip to content

Commit 512ad00

Browse files
committed
[CHERI] Baseline test for tag preservation on coerced arguments
1 parent f0277de commit 512ad00

File tree

1 file changed

+210
-0
lines changed

1 file changed

+210
-0
lines changed
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature
2+
// RUN: %riscv64_cheri_purecap_cc1 %s -emit-llvm -o - -O0 | FileCheck %s
3+
/// Test that we set the no_preserve_tags flag for coerced struct return values.
4+
/// Original test case found building XML_ExpatVersionInfo.
5+
6+
typedef struct {
7+
int major;
8+
int minor;
9+
int micro;
10+
} XML_Expat_Version;
11+
// CHECK-LABEL: define {{[^@]+}}@XML_ExpatVersionInfo
12+
// CHECK-SAME: () addrspace(200) #[[ATTR0:[0-9]+]] {
13+
// CHECK-NEXT: entry:
14+
// CHECK-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_XML_EXPAT_VERSION:%.*]], align 4, addrspace(200)
15+
// CHECK-NEXT: [[RETVAL_COERCE:%.*]] = alloca [2 x i64], align 8, addrspace(200)
16+
// CHECK-NEXT: [[TMP0:%.*]] = bitcast [[STRUCT_XML_EXPAT_VERSION]] addrspace(200)* [[RETVAL]] to i8 addrspace(200)*
17+
// CHECK-NEXT: call void @llvm.memcpy.p200i8.p200i8.i64(i8 addrspace(200)* align 4 [[TMP0]], i8 addrspace(200)* align 4 bitcast ([[STRUCT_XML_EXPAT_VERSION]] addrspace(200)* @__const.XML_ExpatVersionInfo.ret to i8 addrspace(200)*), i64 12, i1 false) #[[ATTR2:[0-9]+]]
18+
// CHECK-NEXT: [[TMP1:%.*]] = bitcast [2 x i64] addrspace(200)* [[RETVAL_COERCE]] to i8 addrspace(200)*
19+
// CHECK-NEXT: [[TMP2:%.*]] = bitcast [[STRUCT_XML_EXPAT_VERSION]] addrspace(200)* [[RETVAL]] to i8 addrspace(200)*
20+
// CHECK-NEXT: call void @llvm.memcpy.p200i8.p200i8.i64(i8 addrspace(200)* align 8 [[TMP1]], i8 addrspace(200)* align 4 [[TMP2]], i64 12, i1 false)
21+
// CHECK-NEXT: [[TMP3:%.*]] = load [2 x i64], [2 x i64] addrspace(200)* [[RETVAL_COERCE]], align 8
22+
// CHECK-NEXT: ret [2 x i64] [[TMP3]]
23+
//
24+
XML_Expat_Version XML_ExpatVersionInfo(void) {
25+
XML_Expat_Version ret = {1, 2, 3};
26+
return ret;
27+
}
28+
// CHECK-LABEL: define {{[^@]+}}@take_XML_ExpatVersionInfo
29+
// CHECK-SAME: ([2 x i64] [[V_COERCE:%.*]]) addrspace(200) #[[ATTR0]] {
30+
// CHECK-NEXT: entry:
31+
// CHECK-NEXT: [[V:%.*]] = alloca [[STRUCT_XML_EXPAT_VERSION:%.*]], align 4, addrspace(200)
32+
// CHECK-NEXT: [[TMP_COERCE:%.*]] = alloca [2 x i64], align 8, addrspace(200)
33+
// CHECK-NEXT: store [2 x i64] [[V_COERCE]], [2 x i64] addrspace(200)* [[TMP_COERCE]], align 8
34+
// CHECK-NEXT: [[TMP0:%.*]] = bitcast [[STRUCT_XML_EXPAT_VERSION]] addrspace(200)* [[V]] to i8 addrspace(200)*
35+
// CHECK-NEXT: [[TMP1:%.*]] = bitcast [2 x i64] addrspace(200)* [[TMP_COERCE]] to i8 addrspace(200)*
36+
// CHECK-NEXT: call void @llvm.memcpy.p200i8.p200i8.i64(i8 addrspace(200)* align 4 [[TMP0]], i8 addrspace(200)* align 8 [[TMP1]], i64 12, i1 false)
37+
// CHECK-NEXT: [[MAJOR:%.*]] = getelementptr inbounds [[STRUCT_XML_EXPAT_VERSION]], [[STRUCT_XML_EXPAT_VERSION]] addrspace(200)* [[V]], i32 0, i32 0
38+
// CHECK-NEXT: [[TMP2:%.*]] = load i32, i32 addrspace(200)* [[MAJOR]], align 4
39+
// CHECK-NEXT: ret i32 [[TMP2]]
40+
//
41+
int take_XML_ExpatVersionInfo(XML_Expat_Version v) {
42+
return v.major;
43+
}
44+
// CHECK-LABEL: define {{[^@]+}}@pass_XML_ExpatVersionInfo
45+
// CHECK-SAME: () addrspace(200) #[[ATTR0]] {
46+
// CHECK-NEXT: entry:
47+
// CHECK-NEXT: [[DOTCOMPOUNDLITERAL:%.*]] = alloca [[STRUCT_XML_EXPAT_VERSION:%.*]], align 4, addrspace(200)
48+
// CHECK-NEXT: [[DOTCOMPOUNDLITERAL_COERCE:%.*]] = alloca [2 x i64], align 8, addrspace(200)
49+
// CHECK-NEXT: [[MAJOR:%.*]] = getelementptr inbounds [[STRUCT_XML_EXPAT_VERSION]], [[STRUCT_XML_EXPAT_VERSION]] addrspace(200)* [[DOTCOMPOUNDLITERAL]], i32 0, i32 0
50+
// CHECK-NEXT: store i32 1, i32 addrspace(200)* [[MAJOR]], align 4
51+
// CHECK-NEXT: [[MINOR:%.*]] = getelementptr inbounds [[STRUCT_XML_EXPAT_VERSION]], [[STRUCT_XML_EXPAT_VERSION]] addrspace(200)* [[DOTCOMPOUNDLITERAL]], i32 0, i32 1
52+
// CHECK-NEXT: store i32 2, i32 addrspace(200)* [[MINOR]], align 4
53+
// CHECK-NEXT: [[MICRO:%.*]] = getelementptr inbounds [[STRUCT_XML_EXPAT_VERSION]], [[STRUCT_XML_EXPAT_VERSION]] addrspace(200)* [[DOTCOMPOUNDLITERAL]], i32 0, i32 2
54+
// CHECK-NEXT: store i32 3, i32 addrspace(200)* [[MICRO]], align 4
55+
// CHECK-NEXT: [[TMP0:%.*]] = bitcast [2 x i64] addrspace(200)* [[DOTCOMPOUNDLITERAL_COERCE]] to i8 addrspace(200)*
56+
// CHECK-NEXT: [[TMP1:%.*]] = bitcast [[STRUCT_XML_EXPAT_VERSION]] addrspace(200)* [[DOTCOMPOUNDLITERAL]] to i8 addrspace(200)*
57+
// CHECK-NEXT: call void @llvm.memcpy.p200i8.p200i8.i64(i8 addrspace(200)* align 8 [[TMP0]], i8 addrspace(200)* align 4 [[TMP1]], i64 12, i1 false)
58+
// CHECK-NEXT: [[TMP2:%.*]] = load [2 x i64], [2 x i64] addrspace(200)* [[DOTCOMPOUNDLITERAL_COERCE]], align 8
59+
// CHECK-NEXT: [[CALL:%.*]] = call signext i32 @take_XML_ExpatVersionInfo([2 x i64] [[TMP2]])
60+
// CHECK-NEXT: ret i32 [[CALL]]
61+
//
62+
int pass_XML_ExpatVersionInfo(void) {
63+
return take_XML_ExpatVersionInfo((XML_Expat_Version){1, 2, 3});
64+
}
65+
66+
typedef struct {
67+
int a;
68+
int b;
69+
} int_pair;
70+
// CHECK-LABEL: define {{[^@]+}}@ret_int_pair
71+
// CHECK-SAME: () addrspace(200) #[[ATTR0]] {
72+
// CHECK-NEXT: entry:
73+
// CHECK-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_INT_PAIR:%.*]], align 4, addrspace(200)
74+
// CHECK-NEXT: [[TMP0:%.*]] = bitcast [[STRUCT_INT_PAIR]] addrspace(200)* [[RETVAL]] to i8 addrspace(200)*
75+
// CHECK-NEXT: call void @llvm.memcpy.p200i8.p200i8.i64(i8 addrspace(200)* align 4 [[TMP0]], i8 addrspace(200)* align 4 bitcast ([[STRUCT_INT_PAIR]] addrspace(200)* @__const.ret_int_pair.ret to i8 addrspace(200)*), i64 8, i1 false) #[[ATTR2]]
76+
// CHECK-NEXT: [[TMP1:%.*]] = bitcast [[STRUCT_INT_PAIR]] addrspace(200)* [[RETVAL]] to i64 addrspace(200)*
77+
// CHECK-NEXT: [[TMP2:%.*]] = load i64, i64 addrspace(200)* [[TMP1]], align 4
78+
// CHECK-NEXT: ret i64 [[TMP2]]
79+
//
80+
int_pair ret_int_pair(void) {
81+
int_pair ret = {1, 2};
82+
return ret;
83+
}
84+
// CHECK-LABEL: define {{[^@]+}}@take_int_pair
85+
// CHECK-SAME: (i64 [[P_COERCE:%.*]]) addrspace(200) #[[ATTR0]] {
86+
// CHECK-NEXT: entry:
87+
// CHECK-NEXT: [[P:%.*]] = alloca [[STRUCT_INT_PAIR:%.*]], align 4, addrspace(200)
88+
// CHECK-NEXT: [[TMP0:%.*]] = bitcast [[STRUCT_INT_PAIR]] addrspace(200)* [[P]] to i64 addrspace(200)*
89+
// CHECK-NEXT: store i64 [[P_COERCE]], i64 addrspace(200)* [[TMP0]], align 4
90+
// CHECK-NEXT: [[A:%.*]] = getelementptr inbounds [[STRUCT_INT_PAIR]], [[STRUCT_INT_PAIR]] addrspace(200)* [[P]], i32 0, i32 0
91+
// CHECK-NEXT: [[TMP1:%.*]] = load i32, i32 addrspace(200)* [[A]], align 4
92+
// CHECK-NEXT: ret i32 [[TMP1]]
93+
//
94+
int take_int_pair(int_pair p) {
95+
return p.a;
96+
}
97+
// CHECK-LABEL: define {{[^@]+}}@pass_int_pair
98+
// CHECK-SAME: () addrspace(200) #[[ATTR0]] {
99+
// CHECK-NEXT: entry:
100+
// CHECK-NEXT: [[DOTCOMPOUNDLITERAL:%.*]] = alloca [[STRUCT_INT_PAIR:%.*]], align 4, addrspace(200)
101+
// CHECK-NEXT: [[A:%.*]] = getelementptr inbounds [[STRUCT_INT_PAIR]], [[STRUCT_INT_PAIR]] addrspace(200)* [[DOTCOMPOUNDLITERAL]], i32 0, i32 0
102+
// CHECK-NEXT: store i32 1, i32 addrspace(200)* [[A]], align 4
103+
// CHECK-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_INT_PAIR]], [[STRUCT_INT_PAIR]] addrspace(200)* [[DOTCOMPOUNDLITERAL]], i32 0, i32 1
104+
// CHECK-NEXT: store i32 2, i32 addrspace(200)* [[B]], align 4
105+
// CHECK-NEXT: [[TMP0:%.*]] = bitcast [[STRUCT_INT_PAIR]] addrspace(200)* [[DOTCOMPOUNDLITERAL]] to i64 addrspace(200)*
106+
// CHECK-NEXT: [[TMP1:%.*]] = load i64, i64 addrspace(200)* [[TMP0]], align 4
107+
// CHECK-NEXT: [[CALL:%.*]] = call signext i32 @take_int_pair(i64 [[TMP1]])
108+
// CHECK-NEXT: ret i32 [[CALL]]
109+
//
110+
int pass_int_pair(void) {
111+
return take_int_pair((int_pair){1, 2});
112+
}
113+
114+
typedef struct {
115+
__intcap a;
116+
int b;
117+
} cap_int_pair;
118+
// CHECK-LABEL: define {{[^@]+}}@ret_cap_int_pair
119+
// CHECK-SAME: ([[STRUCT_CAP_INT_PAIR:%.*]] addrspace(200)* noalias sret([[STRUCT_CAP_INT_PAIR]]) align 16 [[AGG_RESULT:%.*]]) addrspace(200) #[[ATTR0]] {
120+
// CHECK-NEXT: entry:
121+
// CHECK-NEXT: [[RESULT_PTR:%.*]] = alloca i8 addrspace(200)*, align 16, addrspace(200)
122+
// CHECK-NEXT: [[TMP0:%.*]] = bitcast [[STRUCT_CAP_INT_PAIR]] addrspace(200)* [[AGG_RESULT]] to i8 addrspace(200)*
123+
// CHECK-NEXT: store i8 addrspace(200)* [[TMP0]], i8 addrspace(200)* addrspace(200)* [[RESULT_PTR]], align 16
124+
// CHECK-NEXT: [[TMP1:%.*]] = bitcast [[STRUCT_CAP_INT_PAIR]] addrspace(200)* [[AGG_RESULT]] to i8 addrspace(200)*
125+
// CHECK-NEXT: call void @llvm.memcpy.p200i8.p200i8.i64(i8 addrspace(200)* align 16 [[TMP1]], i8 addrspace(200)* align 16 bitcast ([[STRUCT_CAP_INT_PAIR]] addrspace(200)* @__const.ret_cap_int_pair.ret to i8 addrspace(200)*), i64 32, i1 false) #[[ATTR3:[0-9]+]]
126+
// CHECK-NEXT: ret void
127+
//
128+
cap_int_pair ret_cap_int_pair(void) {
129+
cap_int_pair ret = {1, 2};
130+
return ret;
131+
}
132+
// CHECK-LABEL: define {{[^@]+}}@take_cap_int_pair
133+
// CHECK-SAME: ([[STRUCT_CAP_INT_PAIR:%.*]] addrspace(200)* [[P:%.*]]) addrspace(200) #[[ATTR0]] {
134+
// CHECK-NEXT: entry:
135+
// CHECK-NEXT: [[A:%.*]] = getelementptr inbounds [[STRUCT_CAP_INT_PAIR]], [[STRUCT_CAP_INT_PAIR]] addrspace(200)* [[P]], i32 0, i32 0
136+
// CHECK-NEXT: [[TMP0:%.*]] = load i8 addrspace(200)*, i8 addrspace(200)* addrspace(200)* [[A]], align 16
137+
// CHECK-NEXT: ret i8 addrspace(200)* [[TMP0]]
138+
//
139+
__intcap take_cap_int_pair(cap_int_pair p) {
140+
return p.a;
141+
}
142+
// CHECK-LABEL: define {{[^@]+}}@pass_cap_int_pair
143+
// CHECK-SAME: () addrspace(200) #[[ATTR0]] {
144+
// CHECK-NEXT: entry:
145+
// CHECK-NEXT: [[DOTCOMPOUNDLITERAL:%.*]] = alloca [[STRUCT_CAP_INT_PAIR:%.*]], align 16, addrspace(200)
146+
// CHECK-NEXT: [[BYVAL_TEMP:%.*]] = alloca [[STRUCT_CAP_INT_PAIR]], align 16, addrspace(200)
147+
// CHECK-NEXT: [[A:%.*]] = getelementptr inbounds [[STRUCT_CAP_INT_PAIR]], [[STRUCT_CAP_INT_PAIR]] addrspace(200)* [[DOTCOMPOUNDLITERAL]], i32 0, i32 0
148+
// CHECK-NEXT: store i8 addrspace(200)* getelementptr (i8, i8 addrspace(200)* null, i64 1), i8 addrspace(200)* addrspace(200)* [[A]], align 16
149+
// CHECK-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_CAP_INT_PAIR]], [[STRUCT_CAP_INT_PAIR]] addrspace(200)* [[DOTCOMPOUNDLITERAL]], i32 0, i32 1
150+
// CHECK-NEXT: store i32 2, i32 addrspace(200)* [[B]], align 16
151+
// CHECK-NEXT: [[TMP0:%.*]] = bitcast [[STRUCT_CAP_INT_PAIR]] addrspace(200)* [[BYVAL_TEMP]] to i8 addrspace(200)*
152+
// CHECK-NEXT: [[TMP1:%.*]] = bitcast [[STRUCT_CAP_INT_PAIR]] addrspace(200)* [[DOTCOMPOUNDLITERAL]] to i8 addrspace(200)*
153+
// CHECK-NEXT: call void @llvm.memcpy.p200i8.p200i8.i64(i8 addrspace(200)* align 16 [[TMP0]], i8 addrspace(200)* align 16 [[TMP1]], i64 32, i1 false) #[[ATTR3]]
154+
// CHECK-NEXT: [[CALL:%.*]] = call i8 addrspace(200)* @take_cap_int_pair([[STRUCT_CAP_INT_PAIR]] addrspace(200)* [[BYVAL_TEMP]])
155+
// CHECK-NEXT: ret i8 addrspace(200)* [[CALL]]
156+
//
157+
__intcap pass_cap_int_pair(void) {
158+
return take_cap_int_pair((cap_int_pair){1, 2});
159+
}
160+
161+
typedef struct {
162+
__intcap a;
163+
__intcap b;
164+
} cap_pair;
165+
// CHECK-LABEL: define {{[^@]+}}@ret_cap_pair
166+
// CHECK-SAME: ([[STRUCT_CAP_PAIR:%.*]] addrspace(200)* noalias sret([[STRUCT_CAP_PAIR]]) align 16 [[AGG_RESULT:%.*]]) addrspace(200) #[[ATTR0]] {
167+
// CHECK-NEXT: entry:
168+
// CHECK-NEXT: [[RESULT_PTR:%.*]] = alloca i8 addrspace(200)*, align 16, addrspace(200)
169+
// CHECK-NEXT: [[TMP0:%.*]] = bitcast [[STRUCT_CAP_PAIR]] addrspace(200)* [[AGG_RESULT]] to i8 addrspace(200)*
170+
// CHECK-NEXT: store i8 addrspace(200)* [[TMP0]], i8 addrspace(200)* addrspace(200)* [[RESULT_PTR]], align 16
171+
// CHECK-NEXT: [[TMP1:%.*]] = bitcast [[STRUCT_CAP_PAIR]] addrspace(200)* [[AGG_RESULT]] to i8 addrspace(200)*
172+
// CHECK-NEXT: call void @llvm.memcpy.p200i8.p200i8.i64(i8 addrspace(200)* align 16 [[TMP1]], i8 addrspace(200)* align 16 bitcast ([[STRUCT_CAP_PAIR]] addrspace(200)* @__const.ret_cap_pair.ret to i8 addrspace(200)*), i64 32, i1 false) #[[ATTR3]]
173+
// CHECK-NEXT: ret void
174+
//
175+
cap_pair ret_cap_pair(void) {
176+
cap_pair ret = {1, 2};
177+
return ret;
178+
}
179+
// CHECK-LABEL: define {{[^@]+}}@take_cap_pair
180+
// CHECK-SAME: ([[STRUCT_CAP_PAIR:%.*]] addrspace(200)* [[P:%.*]]) addrspace(200) #[[ATTR0]] {
181+
// CHECK-NEXT: entry:
182+
// CHECK-NEXT: [[A:%.*]] = getelementptr inbounds [[STRUCT_CAP_PAIR]], [[STRUCT_CAP_PAIR]] addrspace(200)* [[P]], i32 0, i32 0
183+
// CHECK-NEXT: [[TMP0:%.*]] = load i8 addrspace(200)*, i8 addrspace(200)* addrspace(200)* [[A]], align 16
184+
// CHECK-NEXT: ret i8 addrspace(200)* [[TMP0]]
185+
//
186+
__intcap take_cap_pair(cap_pair p) {
187+
return p.a;
188+
}
189+
// CHECK-LABEL: define {{[^@]+}}@pass_cap_pair
190+
// CHECK-SAME: () addrspace(200) #[[ATTR0]] {
191+
// CHECK-NEXT: entry:
192+
// CHECK-NEXT: [[DOTCOMPOUNDLITERAL:%.*]] = alloca [[STRUCT_CAP_PAIR:%.*]], align 16, addrspace(200)
193+
// CHECK-NEXT: [[BYVAL_TEMP:%.*]] = alloca [[STRUCT_CAP_PAIR]], align 16, addrspace(200)
194+
// CHECK-NEXT: [[A:%.*]] = getelementptr inbounds [[STRUCT_CAP_PAIR]], [[STRUCT_CAP_PAIR]] addrspace(200)* [[DOTCOMPOUNDLITERAL]], i32 0, i32 0
195+
// CHECK-NEXT: store i8 addrspace(200)* getelementptr (i8, i8 addrspace(200)* null, i64 1), i8 addrspace(200)* addrspace(200)* [[A]], align 16
196+
// CHECK-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_CAP_PAIR]], [[STRUCT_CAP_PAIR]] addrspace(200)* [[DOTCOMPOUNDLITERAL]], i32 0, i32 1
197+
// CHECK-NEXT: store i8 addrspace(200)* getelementptr (i8, i8 addrspace(200)* null, i64 2), i8 addrspace(200)* addrspace(200)* [[B]], align 16
198+
// CHECK-NEXT: [[TMP0:%.*]] = bitcast [[STRUCT_CAP_PAIR]] addrspace(200)* [[BYVAL_TEMP]] to i8 addrspace(200)*
199+
// CHECK-NEXT: [[TMP1:%.*]] = bitcast [[STRUCT_CAP_PAIR]] addrspace(200)* [[DOTCOMPOUNDLITERAL]] to i8 addrspace(200)*
200+
// CHECK-NEXT: call void @llvm.memcpy.p200i8.p200i8.i64(i8 addrspace(200)* align 16 [[TMP0]], i8 addrspace(200)* align 16 [[TMP1]], i64 32, i1 false) #[[ATTR3]]
201+
// CHECK-NEXT: [[CALL:%.*]] = call i8 addrspace(200)* @take_cap_pair([[STRUCT_CAP_PAIR]] addrspace(200)* [[BYVAL_TEMP]])
202+
// CHECK-NEXT: ret i8 addrspace(200)* [[CALL]]
203+
//
204+
__intcap pass_cap_pair(void) {
205+
return take_cap_pair((cap_pair){1, 2});
206+
}
207+
208+
// UTC_ARGS: --disable
209+
// CHECK: attributes #[[ATTR2]] = { no_preserve_cheri_tags }
210+
// CHECK: attributes #[[ATTR3]] = { must_preserve_cheri_tags }

0 commit comments

Comments
 (0)