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