1 ; RUN: opt < %s -instcombine -S | FileCheck %s 2 3 ;; MASKED LOADS 4 5 ; If the mask isn't constant, do nothing. 6 7 define <4 x float> @mload(i8* %f, <4 x i32> %mask) { 8 %ld = tail call <4 x float> @llvm.x86.avx.maskload.ps(i8* %f, <4 x i32> %mask) 9 ret <4 x float> %ld 10 11 ; CHECK-LABEL: @mload( 12 ; CHECK-NEXT: %ld = tail call <4 x float> @llvm.x86.avx.maskload.ps(i8* %f, <4 x i32> %mask) 13 ; CHECK-NEXT: ret <4 x float> %ld 14 } 15 16 ; Zero mask returns a zero vector. 17 18 define <4 x float> @mload_zeros(i8* %f) { 19 %ld = tail call <4 x float> @llvm.x86.avx.maskload.ps(i8* %f, <4 x i32> zeroinitializer) 20 ret <4 x float> %ld 21 22 ; CHECK-LABEL: @mload_zeros( 23 ; CHECK-NEXT: ret <4 x float> zeroinitializer 24 } 25 26 ; Only the sign bit matters. 27 28 define <4 x float> @mload_fake_ones(i8* %f) { 29 %ld = tail call <4 x float> @llvm.x86.avx.maskload.ps(i8* %f, <4 x i32> <i32 1, i32 2, i32 3, i32 2147483647>) 30 ret <4 x float> %ld 31 32 ; CHECK-LABEL: @mload_fake_ones( 33 ; CHECK-NEXT: ret <4 x float> zeroinitializer 34 } 35 36 ; All mask bits are set, so this is just a vector load. 37 38 define <4 x float> @mload_real_ones(i8* %f) { 39 %ld = tail call <4 x float> @llvm.x86.avx.maskload.ps(i8* %f, <4 x i32> <i32 -1, i32 -2, i32 -3, i32 2147483648>) 40 ret <4 x float> %ld 41 42 ; CHECK-LABEL: @mload_real_ones( 43 ; CHECK-NEXT: %castvec = bitcast i8* %f to <4 x float>* 44 ; CHECK-NEXT: %unmaskedload = load <4 x float>, <4 x float>* %castvec 45 ; CHECK-NEXT: ret <4 x float> %unmaskedload 46 } 47 48 ; It's a constant mask, so convert to an LLVM intrinsic. The backend should optimize further. 49 50 define <4 x float> @mload_one_one(i8* %f) { 51 %ld = tail call <4 x float> @llvm.x86.avx.maskload.ps(i8* %f, <4 x i32> <i32 0, i32 0, i32 0, i32 -1>) 52 ret <4 x float> %ld 53 54 ; CHECK-LABEL: @mload_one_one( 55 ; CHECK-NEXT: %castvec = bitcast i8* %f to <4 x float>* 56 ; CHECK-NEXT: %1 = call <4 x float> @llvm.masked.load.v4f32.p0v4f32(<4 x float>* %castvec, i32 1, <4 x i1> <i1 false, i1 false, i1 false, i1 true>, <4 x float> zeroinitializer) 57 ; CHECK-NEXT: ret <4 x float> %1 58 } 59 60 ; Try doubles. 61 62 define <2 x double> @mload_one_one_double(i8* %f) { 63 %ld = tail call <2 x double> @llvm.x86.avx.maskload.pd(i8* %f, <2 x i64> <i64 -1, i64 0>) 64 ret <2 x double> %ld 65 66 ; CHECK-LABEL: @mload_one_one_double( 67 ; CHECK-NEXT: %castvec = bitcast i8* %f to <2 x double>* 68 ; CHECK-NEXT: %1 = call <2 x double> @llvm.masked.load.v2f64.p0v2f64(<2 x double>* %castvec, i32 1, <2 x i1> <i1 true, i1 false>, <2 x double> zeroinitializer) 69 ; CHECK-NEXT: ret <2 x double> %1 70 } 71 72 ; Try 256-bit FP ops. 73 74 define <8 x float> @mload_v8f32(i8* %f) { 75 %ld = tail call <8 x float> @llvm.x86.avx.maskload.ps.256(i8* %f, <8 x i32> <i32 0, i32 0, i32 0, i32 -1, i32 0, i32 0, i32 0, i32 0>) 76 ret <8 x float> %ld 77 78 ; CHECK-LABEL: @mload_v8f32( 79 ; CHECK-NEXT: %castvec = bitcast i8* %f to <8 x float>* 80 ; CHECK-NEXT: %1 = call <8 x float> @llvm.masked.load.v8f32.p0v8f32(<8 x float>* %castvec, i32 1, <8 x i1> <i1 false, i1 false, i1 false, i1 true, i1 false, i1 false, i1 false, i1 false>, <8 x float> zeroinitializer) 81 ; CHECK-NEXT: ret <8 x float> %1 82 } 83 84 define <4 x double> @mload_v4f64(i8* %f) { 85 %ld = tail call <4 x double> @llvm.x86.avx.maskload.pd.256(i8* %f, <4 x i64> <i64 -1, i64 0, i64 0, i64 0>) 86 ret <4 x double> %ld 87 88 ; CHECK-LABEL: @mload_v4f64( 89 ; CHECK-NEXT: %castvec = bitcast i8* %f to <4 x double>* 90 ; CHECK-NEXT: %1 = call <4 x double> @llvm.masked.load.v4f64.p0v4f64(<4 x double>* %castvec, i32 1, <4 x i1> <i1 true, i1 false, i1 false, i1 false>, <4 x double> zeroinitializer) 91 ; CHECK-NEXT: ret <4 x double> %1 92 } 93 94 ; Try the AVX2 variants. 95 96 define <4 x i32> @mload_v4i32(i8* %f) { 97 %ld = tail call <4 x i32> @llvm.x86.avx2.maskload.d(i8* %f, <4 x i32> <i32 0, i32 0, i32 0, i32 -1>) 98 ret <4 x i32> %ld 99 100 ; CHECK-LABEL: @mload_v4i32( 101 ; CHECK-NEXT: %castvec = bitcast i8* %f to <4 x i32>* 102 ; CHECK-NEXT: %1 = call <4 x i32> @llvm.masked.load.v4i32.p0v4i32(<4 x i32>* %castvec, i32 1, <4 x i1> <i1 false, i1 false, i1 false, i1 true>, <4 x i32> zeroinitializer) 103 ; CHECK-NEXT: ret <4 x i32> %1 104 } 105 106 define <2 x i64> @mload_v2i64(i8* %f) { 107 %ld = tail call <2 x i64> @llvm.x86.avx2.maskload.q(i8* %f, <2 x i64> <i64 -1, i64 0>) 108 ret <2 x i64> %ld 109 110 ; CHECK-LABEL: @mload_v2i64( 111 ; CHECK-NEXT: %castvec = bitcast i8* %f to <2 x i64>* 112 ; CHECK-NEXT: %1 = call <2 x i64> @llvm.masked.load.v2i64.p0v2i64(<2 x i64>* %castvec, i32 1, <2 x i1> <i1 true, i1 false>, <2 x i64> zeroinitializer) 113 ; CHECK-NEXT: ret <2 x i64> %1 114 } 115 116 define <8 x i32> @mload_v8i32(i8* %f) { 117 %ld = tail call <8 x i32> @llvm.x86.avx2.maskload.d.256(i8* %f, <8 x i32> <i32 0, i32 0, i32 0, i32 -1, i32 0, i32 0, i32 0, i32 0>) 118 ret <8 x i32> %ld 119 120 ; CHECK-LABEL: @mload_v8i32( 121 ; CHECK-NEXT: %castvec = bitcast i8* %f to <8 x i32>* 122 ; CHECK-NEXT: %1 = call <8 x i32> @llvm.masked.load.v8i32.p0v8i32(<8 x i32>* %castvec, i32 1, <8 x i1> <i1 false, i1 false, i1 false, i1 true, i1 false, i1 false, i1 false, i1 false>, <8 x i32> zeroinitializer) 123 ; CHECK-NEXT: ret <8 x i32> %1 124 } 125 126 define <4 x i64> @mload_v4i64(i8* %f) { 127 %ld = tail call <4 x i64> @llvm.x86.avx2.maskload.q.256(i8* %f, <4 x i64> <i64 -1, i64 0, i64 0, i64 0>) 128 ret <4 x i64> %ld 129 130 ; CHECK-LABEL: @mload_v4i64( 131 ; CHECK-NEXT: %castvec = bitcast i8* %f to <4 x i64>* 132 ; CHECK-NEXT: %1 = call <4 x i64> @llvm.masked.load.v4i64.p0v4i64(<4 x i64>* %castvec, i32 1, <4 x i1> <i1 true, i1 false, i1 false, i1 false>, <4 x i64> zeroinitializer) 133 ; CHECK-NEXT: ret <4 x i64> %1 134 } 135 136 137 ;; MASKED STORES 138 139 ; If the mask isn't constant, do nothing. 140 141 define void @mstore(i8* %f, <4 x i32> %mask, <4 x float> %v) { 142 tail call void @llvm.x86.avx.maskstore.ps(i8* %f, <4 x i32> %mask, <4 x float> %v) 143 ret void 144 145 ; CHECK-LABEL: @mstore( 146 ; CHECK-NEXT: tail call void @llvm.x86.avx.maskstore.ps(i8* %f, <4 x i32> %mask, <4 x float> %v) 147 ; CHECK-NEXT: ret void 148 } 149 150 ; Zero mask is a nop. 151 152 define void @mstore_zeros(i8* %f, <4 x float> %v) { 153 tail call void @llvm.x86.avx.maskstore.ps(i8* %f, <4 x i32> zeroinitializer, <4 x float> %v) 154 ret void 155 156 ; CHECK-LABEL: @mstore_zeros( 157 ; CHECK-NEXT: ret void 158 } 159 160 ; Only the sign bit matters. 161 162 define void @mstore_fake_ones(i8* %f, <4 x float> %v) { 163 tail call void @llvm.x86.avx.maskstore.ps(i8* %f, <4 x i32> <i32 1, i32 2, i32 3, i32 2147483647>, <4 x float> %v) 164 ret void 165 166 ; CHECK-LABEL: @mstore_fake_ones( 167 ; CHECK-NEXT: ret void 168 } 169 170 ; All mask bits are set, so this is just a vector store. 171 172 define void @mstore_real_ones(i8* %f, <4 x float> %v) { 173 tail call void @llvm.x86.avx.maskstore.ps(i8* %f, <4 x i32> <i32 -1, i32 -2, i32 -3, i32 -2147483648>, <4 x float> %v) 174 ret void 175 176 ; CHECK-LABEL: @mstore_real_ones( 177 ; CHECK-NEXT: %castvec = bitcast i8* %f to <4 x float>* 178 ; CHECK-NEXT: store <4 x float> %v, <4 x float>* %castvec 179 ; CHECK-NEXT: ret void 180 } 181 182 ; It's a constant mask, so convert to an LLVM intrinsic. The backend should optimize further. 183 184 define void @mstore_one_one(i8* %f, <4 x float> %v) { 185 tail call void @llvm.x86.avx.maskstore.ps(i8* %f, <4 x i32> <i32 0, i32 0, i32 0, i32 -1>, <4 x float> %v) 186 ret void 187 188 ; CHECK-LABEL: @mstore_one_one( 189 ; CHECK-NEXT: %castvec = bitcast i8* %f to <4 x float>* 190 ; CHECK-NEXT: call void @llvm.masked.store.v4f32.p0v4f32(<4 x float> %v, <4 x float>* %castvec, i32 1, <4 x i1> <i1 false, i1 false, i1 false, i1 true>) 191 ; CHECK-NEXT: ret void 192 } 193 194 ; Try doubles. 195 196 define void @mstore_one_one_double(i8* %f, <2 x double> %v) { 197 tail call void @llvm.x86.avx.maskstore.pd(i8* %f, <2 x i64> <i64 -1, i64 0>, <2 x double> %v) 198 ret void 199 200 ; CHECK-LABEL: @mstore_one_one_double( 201 ; CHECK-NEXT: %castvec = bitcast i8* %f to <2 x double>* 202 ; CHECK-NEXT: call void @llvm.masked.store.v2f64.p0v2f64(<2 x double> %v, <2 x double>* %castvec, i32 1, <2 x i1> <i1 true, i1 false>) 203 ; CHECK-NEXT: ret void 204 } 205 206 ; Try 256-bit FP ops. 207 208 define void @mstore_v8f32(i8* %f, <8 x float> %v) { 209 tail call void @llvm.x86.avx.maskstore.ps.256(i8* %f, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 -1, i32 -2, i32 -3, i32 -4>, <8 x float> %v) 210 ret void 211 212 ; CHECK-LABEL: @mstore_v8f32( 213 ; CHECK-NEXT: %castvec = bitcast i8* %f to <8 x float>* 214 ; CHECK-NEXT: call void @llvm.masked.store.v8f32.p0v8f32(<8 x float> %v, <8 x float>* %castvec, i32 1, <8 x i1> <i1 false, i1 false, i1 false, i1 false, i1 true, i1 true, i1 true, i1 true>) 215 ; CHECK-NEXT: ret void 216 } 217 218 define void @mstore_v4f64(i8* %f, <4 x double> %v) { 219 tail call void @llvm.x86.avx.maskstore.pd.256(i8* %f, <4 x i64> <i64 -1, i64 0, i64 1, i64 2>, <4 x double> %v) 220 ret void 221 222 ; CHECK-LABEL: @mstore_v4f64( 223 ; CHECK-NEXT: %castvec = bitcast i8* %f to <4 x double>* 224 ; CHECK-NEXT: call void @llvm.masked.store.v4f64.p0v4f64(<4 x double> %v, <4 x double>* %castvec, i32 1, <4 x i1> <i1 true, i1 false, i1 false, i1 false>) 225 ; CHECK-NEXT: ret void 226 } 227 228 ; Try the AVX2 variants. 229 230 define void @mstore_v4i32(i8* %f, <4 x i32> %v) { 231 tail call void @llvm.x86.avx2.maskstore.d(i8* %f, <4 x i32> <i32 0, i32 1, i32 -1, i32 -2>, <4 x i32> %v) 232 ret void 233 234 ; CHECK-LABEL: @mstore_v4i32( 235 ; CHECK-NEXT: %castvec = bitcast i8* %f to <4 x i32>* 236 ; CHECK-NEXT: call void @llvm.masked.store.v4i32.p0v4i32(<4 x i32> %v, <4 x i32>* %castvec, i32 1, <4 x i1> <i1 false, i1 false, i1 true, i1 true>) 237 ; CHECK-NEXT: ret void 238 } 239 240 define void @mstore_v2i64(i8* %f, <2 x i64> %v) { 241 tail call void @llvm.x86.avx2.maskstore.q(i8* %f, <2 x i64> <i64 -1, i64 0>, <2 x i64> %v) 242 ret void 243 244 ; CHECK-LABEL: @mstore_v2i64( 245 ; CHECK-NEXT: %castvec = bitcast i8* %f to <2 x i64>* 246 ; CHECK-NEXT: call void @llvm.masked.store.v2i64.p0v2i64(<2 x i64> %v, <2 x i64>* %castvec, i32 1, <2 x i1> <i1 true, i1 false>) 247 ; CHECK-NEXT: ret void 248 } 249 250 define void @mstore_v8i32(i8* %f, <8 x i32> %v) { 251 tail call void @llvm.x86.avx2.maskstore.d.256(i8* %f, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 -1, i32 -2, i32 -3, i32 -4>, <8 x i32> %v) 252 ret void 253 254 ; CHECK-LABEL: @mstore_v8i32( 255 ; CHECK-NEXT: %castvec = bitcast i8* %f to <8 x i32>* 256 ; CHECK-NEXT: call void @llvm.masked.store.v8i32.p0v8i32(<8 x i32> %v, <8 x i32>* %castvec, i32 1, <8 x i1> <i1 false, i1 false, i1 false, i1 false, i1 true, i1 true, i1 true, i1 true>) 257 ; CHECK-NEXT: ret void 258 } 259 260 define void @mstore_v4i64(i8* %f, <4 x i64> %v) { 261 tail call void @llvm.x86.avx2.maskstore.q.256(i8* %f, <4 x i64> <i64 -1, i64 0, i64 1, i64 2>, <4 x i64> %v) 262 ret void 263 264 ; CHECK-LABEL: @mstore_v4i64( 265 ; CHECK-NEXT: %castvec = bitcast i8* %f to <4 x i64>* 266 ; CHECK-NEXT: call void @llvm.masked.store.v4i64.p0v4i64(<4 x i64> %v, <4 x i64>* %castvec, i32 1, <4 x i1> <i1 true, i1 false, i1 false, i1 false>) 267 ; CHECK-NEXT: ret void 268 } 269 270 ; The original SSE2 masked store variant. 271 272 define void @mstore_v16i8_sse2_zeros(<16 x i8> %d, i8* %p) { 273 tail call void @llvm.x86.sse2.maskmov.dqu(<16 x i8> %d, <16 x i8> zeroinitializer, i8* %p) 274 ret void 275 276 ; CHECK-LABEL: @mstore_v16i8_sse2_zeros( 277 ; CHECK-NEXT: ret void 278 } 279 280 281 declare <4 x float> @llvm.x86.avx.maskload.ps(i8*, <4 x i32>) 282 declare <2 x double> @llvm.x86.avx.maskload.pd(i8*, <2 x i64>) 283 declare <8 x float> @llvm.x86.avx.maskload.ps.256(i8*, <8 x i32>) 284 declare <4 x double> @llvm.x86.avx.maskload.pd.256(i8*, <4 x i64>) 285 286 declare <4 x i32> @llvm.x86.avx2.maskload.d(i8*, <4 x i32>) 287 declare <2 x i64> @llvm.x86.avx2.maskload.q(i8*, <2 x i64>) 288 declare <8 x i32> @llvm.x86.avx2.maskload.d.256(i8*, <8 x i32>) 289 declare <4 x i64> @llvm.x86.avx2.maskload.q.256(i8*, <4 x i64>) 290 291 declare void @llvm.x86.avx.maskstore.ps(i8*, <4 x i32>, <4 x float>) 292 declare void @llvm.x86.avx.maskstore.pd(i8*, <2 x i64>, <2 x double>) 293 declare void @llvm.x86.avx.maskstore.ps.256(i8*, <8 x i32>, <8 x float>) 294 declare void @llvm.x86.avx.maskstore.pd.256(i8*, <4 x i64>, <4 x double>) 295 296 declare void @llvm.x86.avx2.maskstore.d(i8*, <4 x i32>, <4 x i32>) 297 declare void @llvm.x86.avx2.maskstore.q(i8*, <2 x i64>, <2 x i64>) 298 declare void @llvm.x86.avx2.maskstore.d.256(i8*, <8 x i32>, <8 x i32>) 299 declare void @llvm.x86.avx2.maskstore.q.256(i8*, <4 x i64>, <4 x i64>) 300 301 declare void @llvm.x86.sse2.maskmov.dqu(<16 x i8>, <16 x i8>, i8*) 302 303