xref: /llvm-project/llvm/test/Transforms/InstCombine/bitcast-function.ll (revision 2caaec65c04ea7d0e9568b7895b7a46d6100cb75)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
2; RUN: opt -S -passes=instcombine -o - %s | FileCheck %s
3target datalayout = "e-p:32:32:32-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v16:16:16-v24:32:32-v32:32:32-v64:64:64-v128:128:128-a0:0:64"
4
5define internal <2 x i32> @func_v2i32(<2 x i32> %v) noinline nounwind {
6; CHECK-LABEL: define internal <2 x i32> @func_v2i32
7; CHECK-SAME: (<2 x i32> [[V:%.*]]) #[[ATTR0:[0-9]+]] {
8; CHECK-NEXT:  entry:
9; CHECK-NEXT:    ret <2 x i32> [[V]]
10;
11entry:
12  ret <2 x i32> %v
13}
14
15define internal <2 x float> @func_v2f32(<2 x float> %v) noinline nounwind {
16; CHECK-LABEL: define internal <2 x float> @func_v2f32
17; CHECK-SAME: (<2 x float> [[V:%.*]]) #[[ATTR0]] {
18; CHECK-NEXT:  entry:
19; CHECK-NEXT:    ret <2 x float> [[V]]
20;
21entry:
22  ret <2 x float> %v
23}
24
25define internal <4 x float> @func_v4f32(<4 x float> %v) noinline nounwind {
26; CHECK-LABEL: define internal <4 x float> @func_v4f32
27; CHECK-SAME: (<4 x float> [[V:%.*]]) #[[ATTR0]] {
28; CHECK-NEXT:  entry:
29; CHECK-NEXT:    ret <4 x float> [[V]]
30;
31entry:
32  ret <4 x float> %v
33}
34
35define internal i32 @func_i32(i32 %v) noinline nounwind {
36; CHECK-LABEL: define internal i32 @func_i32
37; CHECK-SAME: (i32 [[V:%.*]]) #[[ATTR0]] {
38; CHECK-NEXT:  entry:
39; CHECK-NEXT:    ret i32 [[V]]
40;
41entry:
42  ret i32 %v
43}
44
45define internal i64 @func_i64(i64 %v) noinline nounwind {
46; CHECK-LABEL: define internal i64 @func_i64
47; CHECK-SAME: (i64 [[V:%.*]]) #[[ATTR0]] {
48; CHECK-NEXT:  entry:
49; CHECK-NEXT:    ret i64 [[V]]
50;
51entry:
52  ret i64 %v
53}
54
55define internal <2 x i64> @func_v2i64(<2 x i64> %v) noinline nounwind {
56; CHECK-LABEL: define internal <2 x i64> @func_v2i64
57; CHECK-SAME: (<2 x i64> [[V:%.*]]) #[[ATTR0]] {
58; CHECK-NEXT:  entry:
59; CHECK-NEXT:    ret <2 x i64> [[V]]
60;
61entry:
62  ret <2 x i64> %v
63}
64
65define internal <2 x ptr> @func_v2i32p(<2 x ptr> %v) noinline nounwind {
66; CHECK-LABEL: define internal <2 x ptr> @func_v2i32p
67; CHECK-SAME: (<2 x ptr> [[V:%.*]]) #[[ATTR0]] {
68; CHECK-NEXT:  entry:
69; CHECK-NEXT:    ret <2 x ptr> [[V]]
70;
71entry:
72  ret <2 x ptr> %v
73}
74
75; Valid cases, only bitcast for argument / return type and call underlying function
76
77; Test cast between scalars with same bit sizes
78; Sizes match, should only bitcast
79define void @bitcast_scalar(ptr noalias %source, ptr noalias %dest) nounwind {
80; CHECK-LABEL: define void @bitcast_scalar
81; CHECK-SAME: (ptr noalias [[SOURCE:%.*]], ptr noalias [[DEST:%.*]]) #[[ATTR1:[0-9]+]] {
82; CHECK-NEXT:  entry:
83; CHECK-NEXT:    [[TMP1:%.*]] = load i32, ptr [[SOURCE]], align 8
84; CHECK-NEXT:    [[CALL:%.*]] = call i32 @func_i32(i32 [[TMP1]]) #[[ATTR1]]
85; CHECK-NEXT:    store i32 [[CALL]], ptr [[DEST]], align 8
86; CHECK-NEXT:    ret void
87;
88entry:
89  %tmp = load float, ptr %source, align 8
90  %call = call float @func_i32(float %tmp) nounwind
91  store float %call, ptr %dest, align 8
92  ret void
93}
94
95; Test cast between vectors with same number of elements and bit sizes
96; Sizes match, should only bitcast
97define void @bitcast_vector(ptr noalias %source, ptr noalias %dest) nounwind {
98; CHECK-LABEL: define void @bitcast_vector
99; CHECK-SAME: (ptr noalias [[SOURCE:%.*]], ptr noalias [[DEST:%.*]]) #[[ATTR1]] {
100; CHECK-NEXT:  entry:
101; CHECK-NEXT:    [[TMP1:%.*]] = load <2 x i32>, ptr [[SOURCE]], align 8
102; CHECK-NEXT:    [[CALL:%.*]] = call <2 x i32> @func_v2i32(<2 x i32> [[TMP1]]) #[[ATTR1]]
103; CHECK-NEXT:    store <2 x i32> [[CALL]], ptr [[DEST]], align 8
104; CHECK-NEXT:    ret void
105;
106entry:
107  %tmp = load <2 x float>, ptr %source, align 8
108  %call = call <2 x float> @func_v2i32(<2 x float> %tmp) nounwind
109  store <2 x float> %call, ptr %dest, align 8
110  ret void
111}
112
113; Test cast from vector to scalar with same number of bits
114; Sizes match, should only bitcast
115define void @bitcast_vector_scalar_same_size(ptr noalias %source, ptr noalias %dest) nounwind {
116; CHECK-LABEL: define void @bitcast_vector_scalar_same_size
117; CHECK-SAME: (ptr noalias [[SOURCE:%.*]], ptr noalias [[DEST:%.*]]) #[[ATTR1]] {
118; CHECK-NEXT:  entry:
119; CHECK-NEXT:    [[TMP1:%.*]] = load i64, ptr [[SOURCE]], align 8
120; CHECK-NEXT:    [[CALL:%.*]] = call i64 @func_i64(i64 [[TMP1]]) #[[ATTR1]]
121; CHECK-NEXT:    store i64 [[CALL]], ptr [[DEST]], align 8
122; CHECK-NEXT:    ret void
123;
124entry:
125  %tmp = load <2 x float>, ptr %source, align 8
126  %call = call <2 x float> @func_i64(<2 x float> %tmp) nounwind
127  store <2 x float> %call, ptr %dest, align 8
128  ret void
129}
130
131; Test cast from scalar to vector with same number of bits
132define void @bitcast_scalar_vector_same_size(ptr noalias %source, ptr noalias %dest) nounwind {
133; CHECK-LABEL: define void @bitcast_scalar_vector_same_size
134; CHECK-SAME: (ptr noalias [[SOURCE:%.*]], ptr noalias [[DEST:%.*]]) #[[ATTR1]] {
135; CHECK-NEXT:  entry:
136; CHECK-NEXT:    [[TMP1:%.*]] = load <2 x float>, ptr [[SOURCE]], align 8
137; CHECK-NEXT:    [[CALL:%.*]] = call <2 x float> @func_v2f32(<2 x float> [[TMP1]]) #[[ATTR1]]
138; CHECK-NEXT:    store <2 x float> [[CALL]], ptr [[DEST]], align 8
139; CHECK-NEXT:    ret void
140;
141entry:
142  %tmp = load i64, ptr %source, align 8
143  %call = call i64 @func_v2f32(i64 %tmp) nounwind
144  store i64 %call, ptr %dest, align 8
145  ret void
146}
147
148; Test cast between vectors of pointers
149define void @bitcast_vector_ptrs_same_size(ptr noalias %source, ptr noalias %dest) nounwind {
150; CHECK-LABEL: define void @bitcast_vector_ptrs_same_size
151; CHECK-SAME: (ptr noalias [[SOURCE:%.*]], ptr noalias [[DEST:%.*]]) #[[ATTR1]] {
152; CHECK-NEXT:  entry:
153; CHECK-NEXT:    [[TMP:%.*]] = load <2 x ptr>, ptr [[SOURCE]], align 8
154; CHECK-NEXT:    [[CALL:%.*]] = call <2 x ptr> @func_v2i32p(<2 x ptr> [[TMP]]) #[[ATTR1]]
155; CHECK-NEXT:    store <2 x ptr> [[CALL]], ptr [[DEST]], align 8
156; CHECK-NEXT:    ret void
157;
158entry:
159  %tmp = load <2 x ptr>, ptr %source, align 8
160  %call = call <2 x ptr> @func_v2i32p(<2 x ptr> %tmp) nounwind
161  store <2 x ptr> %call, ptr %dest, align 8
162  ret void
163}
164
165; Invalid cases:
166
167; Test cast between scalars with different bit sizes
168define void @bitcast_mismatch_scalar_size(ptr noalias %source, ptr noalias %dest) nounwind {
169; CHECK-LABEL: define void @bitcast_mismatch_scalar_size
170; CHECK-SAME: (ptr noalias [[SOURCE:%.*]], ptr noalias [[DEST:%.*]]) #[[ATTR1]] {
171; CHECK-NEXT:  entry:
172; CHECK-NEXT:    [[TMP:%.*]] = load float, ptr [[SOURCE]], align 8
173; CHECK-NEXT:    [[CALL:%.*]] = call float @func_i64(float [[TMP]]) #[[ATTR1]]
174; CHECK-NEXT:    store float [[CALL]], ptr [[DEST]], align 8
175; CHECK-NEXT:    ret void
176;
177entry:
178  %tmp = load float, ptr %source, align 8
179  %call = call float @func_i64(float %tmp) nounwind
180  store float %call, ptr %dest, align 8
181  ret void
182}
183
184; Test cast between vectors with different bit sizes but the
185; same number of elements
186define void @bitcast_mismatch_vector_element_and_bit_size(ptr noalias %source, ptr noalias %dest) nounwind {
187; CHECK-LABEL: define void @bitcast_mismatch_vector_element_and_bit_size
188; CHECK-SAME: (ptr noalias [[SOURCE:%.*]], ptr noalias [[DEST:%.*]]) #[[ATTR1]] {
189; CHECK-NEXT:  entry:
190; CHECK-NEXT:    [[TMP:%.*]] = load <2 x float>, ptr [[SOURCE]], align 8
191; CHECK-NEXT:    [[CALL:%.*]] = call <2 x float> @func_v2i64(<2 x float> [[TMP]]) #[[ATTR1]]
192; CHECK-NEXT:    store <2 x float> [[CALL]], ptr [[DEST]], align 8
193; CHECK-NEXT:    ret void
194;
195entry:
196  %tmp = load <2 x float>, ptr %source, align 8
197  %call = call <2 x float> @func_v2i64(<2 x float> %tmp) nounwind
198  store <2 x float> %call, ptr %dest, align 8
199  ret void
200}
201
202; Test cast between vectors with same number of bits and different
203; numbers of elements
204define void @bitcast_vector_mismatched_number_elements(ptr noalias %source, ptr noalias %dest) nounwind {
205; CHECK-LABEL: define void @bitcast_vector_mismatched_number_elements
206; CHECK-SAME: (ptr noalias [[SOURCE:%.*]], ptr noalias [[DEST:%.*]]) #[[ATTR1]] {
207; CHECK-NEXT:  entry:
208; CHECK-NEXT:    [[TMP:%.*]] = load <4 x float>, ptr [[SOURCE]], align 8
209; CHECK-NEXT:    [[CALL:%.*]] = call <4 x float> @func_v2i32(<4 x float> [[TMP]]) #[[ATTR1]]
210; CHECK-NEXT:    store <4 x float> [[CALL]], ptr [[DEST]], align 8
211; CHECK-NEXT:    ret void
212;
213entry:
214  %tmp = load <4 x float>, ptr %source, align 8
215  %call = call <4 x float> @func_v2i32(<4 x float> %tmp) nounwind
216  store <4 x float> %call, ptr %dest, align 8
217  ret void
218}
219
220; Test cast between vector and scalar with different number of bits
221define void @bitcast_vector_scalar_mismatched_bit_size(ptr noalias %source, ptr noalias %dest) nounwind {
222; CHECK-LABEL: define void @bitcast_vector_scalar_mismatched_bit_size
223; CHECK-SAME: (ptr noalias [[SOURCE:%.*]], ptr noalias [[DEST:%.*]]) #[[ATTR1]] {
224; CHECK-NEXT:  entry:
225; CHECK-NEXT:    [[TMP:%.*]] = load <4 x float>, ptr [[SOURCE]], align 8
226; CHECK-NEXT:    [[CALL:%.*]] = call <4 x float> @func_i64(<4 x float> [[TMP]]) #[[ATTR1]]
227; CHECK-NEXT:    store <4 x float> [[CALL]], ptr [[DEST]], align 8
228; CHECK-NEXT:    ret void
229;
230entry:
231  %tmp = load <4 x float>, ptr %source, align 8
232  %call = call <4 x float> @func_i64(<4 x float> %tmp) nounwind
233  store <4 x float> %call, ptr %dest, align 8
234  ret void
235}
236
237; Test cast between vector of pointers and scalar with different number of bits
238define void @bitcast_vector_ptrs_scalar_mismatched_bit_size(ptr noalias %source, ptr noalias %dest) nounwind {
239; CHECK-LABEL: define void @bitcast_vector_ptrs_scalar_mismatched_bit_size
240; CHECK-SAME: (ptr noalias [[SOURCE:%.*]], ptr noalias [[DEST:%.*]]) #[[ATTR1]] {
241; CHECK-NEXT:  entry:
242; CHECK-NEXT:    [[TMP:%.*]] = load <4 x ptr>, ptr [[SOURCE]], align 8
243; CHECK-NEXT:    [[CALL:%.*]] = call <4 x ptr> @func_i64(<4 x ptr> [[TMP]]) #[[ATTR1]]
244; CHECK-NEXT:    store <4 x ptr> [[CALL]], ptr [[DEST]], align 8
245; CHECK-NEXT:    ret void
246;
247entry:
248  %tmp = load <4 x ptr>, ptr %source, align 8
249  %call = call <4 x ptr> @func_i64(<4 x ptr> %tmp) nounwind
250  store <4 x ptr> %call, ptr %dest, align 8
251  ret void
252}
253
254; Test cast from scalar to vector of pointers with same number of bits
255; We don't know the pointer size at this point, so this can't be done
256define void @bitcast_scalar_vector_ptrs_same_size(ptr noalias %source, ptr noalias %dest) nounwind {
257; CHECK-LABEL: define void @bitcast_scalar_vector_ptrs_same_size
258; CHECK-SAME: (ptr noalias [[SOURCE:%.*]], ptr noalias [[DEST:%.*]]) #[[ATTR1]] {
259; CHECK-NEXT:  entry:
260; CHECK-NEXT:    [[TMP:%.*]] = load i64, ptr [[SOURCE]], align 8
261; CHECK-NEXT:    [[CALL:%.*]] = call i64 @func_v2i32p(i64 [[TMP]]) #[[ATTR1]]
262; CHECK-NEXT:    store i64 [[CALL]], ptr [[DEST]], align 8
263; CHECK-NEXT:    ret void
264;
265entry:
266  %tmp = load i64, ptr %source, align 8
267  %call = call i64 @func_v2i32p(i64 %tmp) nounwind
268  store i64 %call, ptr %dest, align 8
269  ret void
270}
271
272; Test cast between scalar and vector with different number of bits
273define void @bitcast_scalar_vector_mismatched_bit_size(ptr noalias %source, ptr noalias %dest) nounwind {
274; CHECK-LABEL: define void @bitcast_scalar_vector_mismatched_bit_size
275; CHECK-SAME: (ptr noalias [[SOURCE:%.*]], ptr noalias [[DEST:%.*]]) #[[ATTR1]] {
276; CHECK-NEXT:  entry:
277; CHECK-NEXT:    [[TMP:%.*]] = load i64, ptr [[SOURCE]], align 8
278; CHECK-NEXT:    [[CALL:%.*]] = call i64 @func_v4f32(i64 [[TMP]]) #[[ATTR1]]
279; CHECK-NEXT:    store i64 [[CALL]], ptr [[DEST]], align 8
280; CHECK-NEXT:    ret void
281;
282entry:
283  %tmp = load i64, ptr %source, align 8
284  %call = call i64 @func_v4f32(i64 %tmp) nounwind
285  store i64 %call, ptr %dest, align 8
286  ret void
287}
288
289