1 // RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -disable-llvm-passes -o - | FileCheck %s
2 
3 typedef float float4 __attribute__((ext_vector_type(4)));
4 typedef short int si8 __attribute__((ext_vector_type(8)));
5 typedef unsigned int u4 __attribute__((ext_vector_type(4)));
6 
7 __attribute__((address_space(1))) int int_as_one;
8 typedef int bar;
9 bar b;
10 
11 void test_builtin_elementwise_max(float f1, float f2, double d1, double d2,
12                                   float4 vf1, float4 vf2, long long int i1,
13                                   long long int i2, si8 vi1, si8 vi2,
14                                   unsigned u1, unsigned u2, u4 vu1, u4 vu2) {
15   // CHECK-LABEL: define void @test_builtin_elementwise_max(
16 
17   // CHECK:      [[F1:%.+]] = load float, float* %f1.addr, align 4
18   // CHECK-NEXT: [[F2:%.+]] = load float, float* %f2.addr, align 4
19   // CHECK-NEXT:  call float @llvm.maxnum.f32(float %0, float %1)
20   f1 = __builtin_elementwise_max(f1, f2);
21 
22   // CHECK:      [[D1:%.+]] = load double, double* %d1.addr, align 8
23   // CHECK-NEXT: [[D2:%.+]] = load double, double* %d2.addr, align 8
24   // CHECK-NEXT: call double @llvm.maxnum.f64(double [[D1]], double [[D2]])
25   d1 = __builtin_elementwise_max(d1, d2);
26 
27   // CHECK:      [[D2:%.+]] = load double, double* %d2.addr, align 8
28   // CHECK-NEXT: call double @llvm.maxnum.f64(double 2.000000e+01, double [[D2]])
29   d1 = __builtin_elementwise_max(20.0, d2);
30 
31   // CHECK:      [[VF1:%.+]] = load <4 x float>, <4 x float>* %vf1.addr, align 16
32   // CHECK-NEXT: [[VF2:%.+]] = load <4 x float>, <4 x float>* %vf2.addr, align 16
33   // CHECK-NEXT: call <4 x float> @llvm.maxnum.v4f32(<4 x float> [[VF1]], <4 x float> [[VF2]])
34   vf1 = __builtin_elementwise_max(vf1, vf2);
35 
36   // CHECK:      [[I1:%.+]] = load i64, i64* %i1.addr, align 8
37   // CHECK-NEXT: [[I2:%.+]] = load i64, i64* %i2.addr, align 8
38   // CHECK-NEXT: call i64 @llvm.smax.i64(i64 [[I1]], i64 [[I2]])
39   i1 = __builtin_elementwise_max(i1, i2);
40 
41   // CHECK:      [[I1:%.+]] = load i64, i64* %i1.addr, align 8
42   // CHECK-NEXT: call i64 @llvm.smax.i64(i64 [[I1]], i64 10)
43   i1 = __builtin_elementwise_max(i1, 10);
44 
45   // CHECK:      [[VI1:%.+]] = load <8 x i16>, <8 x i16>* %vi1.addr, align 16
46   // CHECK-NEXT: [[VI2:%.+]] = load <8 x i16>, <8 x i16>* %vi2.addr, align 16
47   // CHECK-NEXT: call <8 x i16> @llvm.smax.v8i16(<8 x i16> [[VI1]], <8 x i16> [[VI2]])
48   vi1 = __builtin_elementwise_max(vi1, vi2);
49 
50   // CHECK:      [[U1:%.+]] = load i32, i32* %u1.addr, align 4
51   // CHECK-NEXT: [[U2:%.+]] = load i32, i32* %u2.addr, align 4
52   // CHECK-NEXT: call i32 @llvm.umax.i32(i32 [[U1]], i32 [[U2]])
53   u1 = __builtin_elementwise_max(u1, u2);
54 
55   // CHECK:      [[VU1:%.+]] = load <4 x i32>, <4 x i32>* %vu1.addr, align 16
56   // CHECK-NEXT: [[VU2:%.+]] = load <4 x i32>, <4 x i32>* %vu2.addr, align 16
57   // CHECK-NEXT: call <4 x i32> @llvm.umax.v4i32(<4 x i32> [[VU1]], <4 x i32> [[VU2]])
58   vu1 = __builtin_elementwise_max(vu1, vu2);
59 
60   // CHECK:      [[CVF1:%.+]] = load <4 x float>, <4 x float>* %cvf1, align 16
61   // CHECK-NEXT: [[VF2:%.+]] = load <4 x float>, <4 x float>* %vf2.addr, align 16
62   // CHECK-NEXT: call <4 x float> @llvm.maxnum.v4f32(<4 x float> [[CVF1]], <4 x float> [[VF2]])
63   const float4 cvf1 = vf1;
64   vf1 = __builtin_elementwise_max(cvf1, vf2);
65 
66   // CHECK:      [[VF2:%.+]] = load <4 x float>, <4 x float>* %vf2.addr, align 16
67   // CHECK-NEXT: [[CVF1:%.+]] = load <4 x float>, <4 x float>* %cvf1, align 16
68   // CHECK-NEXT: call <4 x float> @llvm.maxnum.v4f32(<4 x float> [[VF2]], <4 x float> [[CVF1]])
69   vf1 = __builtin_elementwise_max(vf2, cvf1);
70 
71   // CHECK:      [[IAS1:%.+]] = load i32, i32 addrspace(1)* @int_as_one, align 4
72   // CHECK-NEXT: [[B:%.+]] = load i32, i32* @b, align 4
73   // CHECK-NEXT: call i32 @llvm.smax.i32(i32 [[IAS1]], i32 [[B]])
74   int_as_one = __builtin_elementwise_max(int_as_one, b);
75 
76   // CHECK: call i32 @llvm.smax.i32(i32 1, i32 97)
77   i1 = __builtin_elementwise_max(1, 'a');
78 }
79 
80 void test_builtin_elementwise_min(float f1, float f2, double d1, double d2,
81                                   float4 vf1, float4 vf2, long long int i1,
82                                   long long int i2, si8 vi1, si8 vi2,
83                                   unsigned u1, unsigned u2, u4 vu1, u4 vu2) {
84   // CHECK-LABEL: define void @test_builtin_elementwise_min(
85   // CHECK:      [[F1:%.+]] = load float, float* %f1.addr, align 4
86   // CHECK-NEXT: [[F2:%.+]] = load float, float* %f2.addr, align 4
87   // CHECK-NEXT:  call float @llvm.minnum.f32(float %0, float %1)
88   f1 = __builtin_elementwise_min(f1, f2);
89 
90   // CHECK:      [[D1:%.+]] = load double, double* %d1.addr, align 8
91   // CHECK-NEXT: [[D2:%.+]] = load double, double* %d2.addr, align 8
92   // CHECK-NEXT: call double @llvm.minnum.f64(double [[D1]], double [[D2]])
93   d1 = __builtin_elementwise_min(d1, d2);
94 
95   // CHECK:      [[D1:%.+]] = load double, double* %d1.addr, align 8
96   // CHECK-NEXT: call double @llvm.minnum.f64(double [[D1]], double 2.000000e+00)
97   d1 = __builtin_elementwise_min(d1, 2.0);
98 
99   // CHECK:      [[VF1:%.+]] = load <4 x float>, <4 x float>* %vf1.addr, align 16
100   // CHECK-NEXT: [[VF2:%.+]] = load <4 x float>, <4 x float>* %vf2.addr, align 16
101   // CHECK-NEXT: call <4 x float> @llvm.minnum.v4f32(<4 x float> [[VF1]], <4 x float> [[VF2]])
102   vf1 = __builtin_elementwise_min(vf1, vf2);
103 
104   // CHECK:      [[I1:%.+]] = load i64, i64* %i1.addr, align 8
105   // CHECK-NEXT: [[I2:%.+]] = load i64, i64* %i2.addr, align 8
106   // CHECK-NEXT: call i64 @llvm.smin.i64(i64 [[I1]], i64 [[I2]])
107   i1 = __builtin_elementwise_min(i1, i2);
108 
109   // CHECK:      [[I2:%.+]] = load i64, i64* %i2.addr, align 8
110   // CHECK-NEXT: call i64 @llvm.smin.i64(i64 -11, i64 [[I2]])
111   i1 = __builtin_elementwise_min(-11, i2);
112 
113   // CHECK:      [[VI1:%.+]] = load <8 x i16>, <8 x i16>* %vi1.addr, align 16
114   // CHECK-NEXT: [[VI2:%.+]] = load <8 x i16>, <8 x i16>* %vi2.addr, align 16
115   // CHECK-NEXT: call <8 x i16> @llvm.smin.v8i16(<8 x i16> [[VI1]], <8 x i16> [[VI2]])
116   vi1 = __builtin_elementwise_min(vi1, vi2);
117 
118   // CHECK:      [[U1:%.+]] = load i32, i32* %u1.addr, align 4
119   // CHECK-NEXT: [[U2:%.+]] = load i32, i32* %u2.addr, align 4
120   // CHECK-NEXT: call i32 @llvm.umin.i32(i32 [[U1]], i32 [[U2]])
121   u1 = __builtin_elementwise_min(u1, u2);
122 
123   // CHECK:      [[U1:%.+]] = load i32, i32* %u1.addr, align 4
124   // CHECK-NEXT: [[ZEXT_U1:%.+]] = zext i32 [[U1]] to i64
125   // CHECK-NEXT: [[I2:%.+]] = load i64, i64* %i2.addr, align 8
126   // CHECK-NEXT: call i64 @llvm.smin.i64(i64 [[ZEXT_U1]], i64 [[I2]])
127   u1 = __builtin_elementwise_min(u1, i2);
128 
129   // CHECK:      [[VU1:%.+]] = load <4 x i32>, <4 x i32>* %vu1.addr, align 16
130   // CHECK-NEXT: [[VU2:%.+]] = load <4 x i32>, <4 x i32>* %vu2.addr, align 16
131   // CHECK-NEXT: call <4 x i32> @llvm.umin.v4i32(<4 x i32> [[VU1]], <4 x i32> [[VU2]])
132   vu1 = __builtin_elementwise_min(vu1, vu2);
133 
134   // CHECK:      [[CVF1:%.+]] = load <4 x float>, <4 x float>* %cvf1, align 16
135   // CHECK-NEXT: [[VF2:%.+]] = load <4 x float>, <4 x float>* %vf2.addr, align 16
136   // CHECK-NEXT: call <4 x float> @llvm.minnum.v4f32(<4 x float> [[CVF1]], <4 x float> [[VF2]])
137   const float4 cvf1 = vf1;
138   vf1 = __builtin_elementwise_min(cvf1, vf2);
139 
140   // CHECK:      [[VF2:%.+]] = load <4 x float>, <4 x float>* %vf2.addr, align 16
141   // CHECK-NEXT: [[CVF1:%.+]] = load <4 x float>, <4 x float>* %cvf1, align 16
142   // CHECK-NEXT: call <4 x float> @llvm.minnum.v4f32(<4 x float> [[VF2]], <4 x float> [[CVF1]])
143   vf1 = __builtin_elementwise_min(vf2, cvf1);
144 
145   // CHECK:      [[IAS1:%.+]] = load i32, i32 addrspace(1)* @int_as_one, align 4
146   // CHECK-NEXT: [[B:%.+]] = load i32, i32* @b, align 4
147   // CHECK-NEXT: call i32 @llvm.smin.i32(i32 [[IAS1]], i32 [[B]])
148   int_as_one = __builtin_elementwise_min(int_as_one, b);
149 }
150