1*03ce13f7SAndroid Build Coastguard Worker // Copyright 2022 The SwiftShader Authors. All Rights Reserved.
2*03ce13f7SAndroid Build Coastguard Worker //
3*03ce13f7SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*03ce13f7SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*03ce13f7SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*03ce13f7SAndroid Build Coastguard Worker //
7*03ce13f7SAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0
8*03ce13f7SAndroid Build Coastguard Worker //
9*03ce13f7SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*03ce13f7SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*03ce13f7SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*03ce13f7SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*03ce13f7SAndroid Build Coastguard Worker // limitations under the License.
14*03ce13f7SAndroid Build Coastguard Worker
15*03ce13f7SAndroid Build Coastguard Worker #ifndef rr_SIMD_hpp
16*03ce13f7SAndroid Build Coastguard Worker #define rr_SIMD_hpp
17*03ce13f7SAndroid Build Coastguard Worker
18*03ce13f7SAndroid Build Coastguard Worker #include "Reactor.hpp"
19*03ce13f7SAndroid Build Coastguard Worker
20*03ce13f7SAndroid Build Coastguard Worker #include <functional>
21*03ce13f7SAndroid Build Coastguard Worker #include <vector>
22*03ce13f7SAndroid Build Coastguard Worker
23*03ce13f7SAndroid Build Coastguard Worker namespace rr {
24*03ce13f7SAndroid Build Coastguard Worker
25*03ce13f7SAndroid Build Coastguard Worker namespace scalar {
26*03ce13f7SAndroid Build Coastguard Worker using Int = rr::Int;
27*03ce13f7SAndroid Build Coastguard Worker using UInt = rr::UInt;
28*03ce13f7SAndroid Build Coastguard Worker using Float = rr::Float;
29*03ce13f7SAndroid Build Coastguard Worker template<class T>
30*03ce13f7SAndroid Build Coastguard Worker using Pointer = rr::Pointer<T>;
31*03ce13f7SAndroid Build Coastguard Worker } // namespace scalar
32*03ce13f7SAndroid Build Coastguard Worker
33*03ce13f7SAndroid Build Coastguard Worker namespace packed {
34*03ce13f7SAndroid Build Coastguard Worker using Int4 = rr::Int4;
35*03ce13f7SAndroid Build Coastguard Worker using UInt4 = rr::UInt4;
36*03ce13f7SAndroid Build Coastguard Worker using Float4 = rr::Float4;
37*03ce13f7SAndroid Build Coastguard Worker } // namespace packed
38*03ce13f7SAndroid Build Coastguard Worker
39*03ce13f7SAndroid Build Coastguard Worker namespace SIMD {
40*03ce13f7SAndroid Build Coastguard Worker
41*03ce13f7SAndroid Build Coastguard Worker extern const int Width;
42*03ce13f7SAndroid Build Coastguard Worker
43*03ce13f7SAndroid Build Coastguard Worker class Int;
44*03ce13f7SAndroid Build Coastguard Worker class UInt;
45*03ce13f7SAndroid Build Coastguard Worker class Float;
46*03ce13f7SAndroid Build Coastguard Worker class Pointer;
47*03ce13f7SAndroid Build Coastguard Worker
48*03ce13f7SAndroid Build Coastguard Worker class Int : public LValue<SIMD::Int>,
49*03ce13f7SAndroid Build Coastguard Worker public XYZW<SIMD::Int> // TODO(b/214583550): Eliminate and replace with SwizzleQuad() and/or other intrinsics.
50*03ce13f7SAndroid Build Coastguard Worker {
51*03ce13f7SAndroid Build Coastguard Worker public:
52*03ce13f7SAndroid Build Coastguard Worker explicit Int(RValue<SIMD::Float> cast);
53*03ce13f7SAndroid Build Coastguard Worker
54*03ce13f7SAndroid Build Coastguard Worker Int();
55*03ce13f7SAndroid Build Coastguard Worker Int(int broadcast);
56*03ce13f7SAndroid Build Coastguard Worker Int(int x, int y, int z, int w);
57*03ce13f7SAndroid Build Coastguard Worker Int(std::vector<int> v);
58*03ce13f7SAndroid Build Coastguard Worker Int(std::function<int(int)> LaneValueProducer);
59*03ce13f7SAndroid Build Coastguard Worker Int(RValue<SIMD::Int> rhs);
60*03ce13f7SAndroid Build Coastguard Worker Int(const Int &rhs);
61*03ce13f7SAndroid Build Coastguard Worker Int(const Reference<SIMD::Int> &rhs);
62*03ce13f7SAndroid Build Coastguard Worker Int(RValue<SIMD::UInt> rhs);
63*03ce13f7SAndroid Build Coastguard Worker Int(const UInt &rhs);
64*03ce13f7SAndroid Build Coastguard Worker Int(const Reference<SIMD::UInt> &rhs);
65*03ce13f7SAndroid Build Coastguard Worker Int(RValue<scalar::Int> rhs);
66*03ce13f7SAndroid Build Coastguard Worker Int(const scalar::Int &rhs);
67*03ce13f7SAndroid Build Coastguard Worker Int(const Reference<scalar::Int> &rhs);
68*03ce13f7SAndroid Build Coastguard Worker
69*03ce13f7SAndroid Build Coastguard Worker template<int T>
70*03ce13f7SAndroid Build Coastguard Worker Int(const SwizzleMask1<packed::Int4, T> &rhs);
71*03ce13f7SAndroid Build Coastguard Worker
72*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> operator=(int broadcast);
73*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> operator=(RValue<SIMD::Int> rhs);
74*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> operator=(const Int &rhs);
75*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> operator=(const Reference<SIMD::Int> &rhs);
76*03ce13f7SAndroid Build Coastguard Worker
77*03ce13f7SAndroid Build Coastguard Worker static Type *type();
element_count()78*03ce13f7SAndroid Build Coastguard Worker static int element_count() { return SIMD::Width; }
79*03ce13f7SAndroid Build Coastguard Worker };
80*03ce13f7SAndroid Build Coastguard Worker
81*03ce13f7SAndroid Build Coastguard Worker class UInt : public LValue<SIMD::UInt>,
82*03ce13f7SAndroid Build Coastguard Worker public XYZW<SIMD::UInt> // TODO(b/214583550): Eliminate and replace with SwizzleQuad() and/or other intrinsics.
83*03ce13f7SAndroid Build Coastguard Worker {
84*03ce13f7SAndroid Build Coastguard Worker public:
85*03ce13f7SAndroid Build Coastguard Worker explicit UInt(RValue<SIMD::Float> cast);
86*03ce13f7SAndroid Build Coastguard Worker
87*03ce13f7SAndroid Build Coastguard Worker UInt();
88*03ce13f7SAndroid Build Coastguard Worker UInt(int broadcast);
89*03ce13f7SAndroid Build Coastguard Worker UInt(int x, int y, int z, int w);
90*03ce13f7SAndroid Build Coastguard Worker UInt(std::vector<int> v);
91*03ce13f7SAndroid Build Coastguard Worker UInt(std::function<int(int)> LaneValueProducer);
92*03ce13f7SAndroid Build Coastguard Worker UInt(RValue<SIMD::UInt> rhs);
93*03ce13f7SAndroid Build Coastguard Worker UInt(const UInt &rhs);
94*03ce13f7SAndroid Build Coastguard Worker UInt(const Reference<SIMD::UInt> &rhs);
95*03ce13f7SAndroid Build Coastguard Worker UInt(RValue<SIMD::Int> rhs);
96*03ce13f7SAndroid Build Coastguard Worker UInt(const Int &rhs);
97*03ce13f7SAndroid Build Coastguard Worker UInt(const Reference<SIMD::Int> &rhs);
98*03ce13f7SAndroid Build Coastguard Worker UInt(RValue<scalar::UInt> rhs);
99*03ce13f7SAndroid Build Coastguard Worker UInt(const scalar::UInt &rhs);
100*03ce13f7SAndroid Build Coastguard Worker UInt(const Reference<scalar::UInt> &rhs);
101*03ce13f7SAndroid Build Coastguard Worker
102*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> operator=(RValue<SIMD::UInt> rhs);
103*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> operator=(const UInt &rhs);
104*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> operator=(const Reference<SIMD::UInt> &rhs);
105*03ce13f7SAndroid Build Coastguard Worker
106*03ce13f7SAndroid Build Coastguard Worker static Type *type();
element_count()107*03ce13f7SAndroid Build Coastguard Worker static int element_count() { return SIMD::Width; }
108*03ce13f7SAndroid Build Coastguard Worker };
109*03ce13f7SAndroid Build Coastguard Worker
110*03ce13f7SAndroid Build Coastguard Worker class Float : public LValue<SIMD::Float>,
111*03ce13f7SAndroid Build Coastguard Worker public XYZW<SIMD::Float> // TODO(b/214583550): Eliminate and replace with SwizzleQuad() and/or other intrinsics.
112*03ce13f7SAndroid Build Coastguard Worker {
113*03ce13f7SAndroid Build Coastguard Worker public:
114*03ce13f7SAndroid Build Coastguard Worker explicit Float(RValue<SIMD::Int> cast);
115*03ce13f7SAndroid Build Coastguard Worker explicit Float(RValue<SIMD::UInt> cast);
116*03ce13f7SAndroid Build Coastguard Worker
117*03ce13f7SAndroid Build Coastguard Worker Float();
118*03ce13f7SAndroid Build Coastguard Worker Float(float broadcast);
119*03ce13f7SAndroid Build Coastguard Worker Float(float x, float y, float z, float w);
120*03ce13f7SAndroid Build Coastguard Worker Float(std::vector<float> v);
121*03ce13f7SAndroid Build Coastguard Worker Float(std::function<float(int)> LaneValueProducer);
122*03ce13f7SAndroid Build Coastguard Worker Float(RValue<SIMD::Float> rhs);
123*03ce13f7SAndroid Build Coastguard Worker Float(const Float &rhs);
124*03ce13f7SAndroid Build Coastguard Worker Float(const Reference<SIMD::Float> &rhs);
125*03ce13f7SAndroid Build Coastguard Worker Float(RValue<scalar::Float> rhs);
126*03ce13f7SAndroid Build Coastguard Worker Float(const scalar::Float &rhs);
127*03ce13f7SAndroid Build Coastguard Worker Float(const Reference<scalar::Float> &rhs);
128*03ce13f7SAndroid Build Coastguard Worker
129*03ce13f7SAndroid Build Coastguard Worker Float(RValue<packed::Float4> rhs);
130*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> operator=(RValue<packed::Float4> rhs);
131*03ce13f7SAndroid Build Coastguard Worker template<int T>
132*03ce13f7SAndroid Build Coastguard Worker Float(const SwizzleMask1<packed::Float4, T> &rhs);
133*03ce13f7SAndroid Build Coastguard Worker
134*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> operator=(float broadcast);
135*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> operator=(RValue<SIMD::Float> rhs);
136*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> operator=(const Float &rhs);
137*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> operator=(const Reference<SIMD::Float> &rhs);
138*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> operator=(RValue<scalar::Float> rhs);
139*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> operator=(const scalar::Float &rhs);
140*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> operator=(const Reference<scalar::Float> &rhs);
141*03ce13f7SAndroid Build Coastguard Worker
142*03ce13f7SAndroid Build Coastguard Worker static SIMD::Float infinity();
143*03ce13f7SAndroid Build Coastguard Worker
144*03ce13f7SAndroid Build Coastguard Worker static Type *type();
element_count()145*03ce13f7SAndroid Build Coastguard Worker static int element_count() { return SIMD::Width; }
146*03ce13f7SAndroid Build Coastguard Worker };
147*03ce13f7SAndroid Build Coastguard Worker
148*03ce13f7SAndroid Build Coastguard Worker class Pointer
149*03ce13f7SAndroid Build Coastguard Worker {
150*03ce13f7SAndroid Build Coastguard Worker public:
151*03ce13f7SAndroid Build Coastguard Worker Pointer(scalar::Pointer<Byte> base, scalar::Int limit);
152*03ce13f7SAndroid Build Coastguard Worker Pointer(scalar::Pointer<Byte> base, unsigned int limit);
153*03ce13f7SAndroid Build Coastguard Worker Pointer(scalar::Pointer<Byte> base, scalar::Int limit, SIMD::Int offset);
154*03ce13f7SAndroid Build Coastguard Worker Pointer(scalar::Pointer<Byte> base, unsigned int limit, SIMD::Int offset);
155*03ce13f7SAndroid Build Coastguard Worker Pointer(std::vector<scalar::Pointer<Byte>> pointers);
156*03ce13f7SAndroid Build Coastguard Worker explicit Pointer(SIMD::UInt cast); // Cast from 32-bit integers to 32-bit pointers
157*03ce13f7SAndroid Build Coastguard Worker explicit Pointer(SIMD::UInt castLow, SIMD::UInt castHight); // Cast from pairs of 32-bit integers to 64-bit pointers
158*03ce13f7SAndroid Build Coastguard Worker
159*03ce13f7SAndroid Build Coastguard Worker Pointer &operator+=(SIMD::Int i);
160*03ce13f7SAndroid Build Coastguard Worker Pointer operator+(SIMD::Int i);
161*03ce13f7SAndroid Build Coastguard Worker Pointer &operator+=(int i);
162*03ce13f7SAndroid Build Coastguard Worker Pointer operator+(int i);
163*03ce13f7SAndroid Build Coastguard Worker
164*03ce13f7SAndroid Build Coastguard Worker SIMD::Int offsets() const;
165*03ce13f7SAndroid Build Coastguard Worker
166*03ce13f7SAndroid Build Coastguard Worker SIMD::Int isInBounds(unsigned int accessSize, OutOfBoundsBehavior robustness) const;
167*03ce13f7SAndroid Build Coastguard Worker
168*03ce13f7SAndroid Build Coastguard Worker bool isStaticallyInBounds(unsigned int accessSize, OutOfBoundsBehavior robustness) const;
169*03ce13f7SAndroid Build Coastguard Worker
170*03ce13f7SAndroid Build Coastguard Worker Int limit() const;
171*03ce13f7SAndroid Build Coastguard Worker
172*03ce13f7SAndroid Build Coastguard Worker // Returns true if all offsets are compile-time static and sequential
173*03ce13f7SAndroid Build Coastguard Worker // (N+0*step, N+1*step, N+2*step, N+3*step)
174*03ce13f7SAndroid Build Coastguard Worker bool hasStaticSequentialOffsets(unsigned int step) const;
175*03ce13f7SAndroid Build Coastguard Worker
176*03ce13f7SAndroid Build Coastguard Worker // Returns true if all offsets are compile-time static and equal
177*03ce13f7SAndroid Build Coastguard Worker // (N, N, N, N)
178*03ce13f7SAndroid Build Coastguard Worker bool hasStaticEqualOffsets() const;
179*03ce13f7SAndroid Build Coastguard Worker
180*03ce13f7SAndroid Build Coastguard Worker template<typename T>
181*03ce13f7SAndroid Build Coastguard Worker inline T Load(OutOfBoundsBehavior robustness, SIMD::Int mask, bool atomic = false, std::memory_order order = std::memory_order_relaxed, int alignment = sizeof(float));
182*03ce13f7SAndroid Build Coastguard Worker
183*03ce13f7SAndroid Build Coastguard Worker template<typename T>
184*03ce13f7SAndroid Build Coastguard Worker inline void Store(T val, OutOfBoundsBehavior robustness, SIMD::Int mask, bool atomic = false, std::memory_order order = std::memory_order_relaxed);
185*03ce13f7SAndroid Build Coastguard Worker
186*03ce13f7SAndroid Build Coastguard Worker template<typename T>
187*03ce13f7SAndroid Build Coastguard Worker inline void Store(RValue<T> val, OutOfBoundsBehavior robustness, SIMD::Int mask, bool atomic = false, std::memory_order order = std::memory_order_relaxed);
188*03ce13f7SAndroid Build Coastguard Worker
189*03ce13f7SAndroid Build Coastguard Worker scalar::Pointer<Byte> getUniformPointer() const;
190*03ce13f7SAndroid Build Coastguard Worker scalar::Pointer<Byte> getPointerForLane(int lane) const;
191*03ce13f7SAndroid Build Coastguard Worker static Pointer IfThenElse(SIMD::Int condition, const Pointer &lhs, const Pointer &rhs);
192*03ce13f7SAndroid Build Coastguard Worker
193*03ce13f7SAndroid Build Coastguard Worker void castTo(SIMD::UInt &bits) const; // Cast from 32-bit pointers to 32-bit integers
194*03ce13f7SAndroid Build Coastguard Worker void castTo(SIMD::UInt &lowerBits, SIMD::UInt &upperBits) const; // Cast from 64-bit pointers to pairs of 32-bit integers
195*03ce13f7SAndroid Build Coastguard Worker
196*03ce13f7SAndroid Build Coastguard Worker #ifdef ENABLE_RR_PRINT
197*03ce13f7SAndroid Build Coastguard Worker std::vector<rr::Value *> getPrintValues() const;
198*03ce13f7SAndroid Build Coastguard Worker #endif
199*03ce13f7SAndroid Build Coastguard Worker
200*03ce13f7SAndroid Build Coastguard Worker private:
201*03ce13f7SAndroid Build Coastguard Worker // Base address for the pointer, common across all lanes.
202*03ce13f7SAndroid Build Coastguard Worker scalar::Pointer<Byte> base;
203*03ce13f7SAndroid Build Coastguard Worker // Per-lane address for dealing with non-uniform data
204*03ce13f7SAndroid Build Coastguard Worker std::vector<scalar::Pointer<Byte>> pointers;
205*03ce13f7SAndroid Build Coastguard Worker
206*03ce13f7SAndroid Build Coastguard Worker public:
207*03ce13f7SAndroid Build Coastguard Worker // Upper (non-inclusive) limit for offsets from base.
208*03ce13f7SAndroid Build Coastguard Worker scalar::Int dynamicLimit; // If hasDynamicLimit is false, dynamicLimit is zero.
209*03ce13f7SAndroid Build Coastguard Worker unsigned int staticLimit = 0;
210*03ce13f7SAndroid Build Coastguard Worker
211*03ce13f7SAndroid Build Coastguard Worker // Per lane offsets from base.
212*03ce13f7SAndroid Build Coastguard Worker SIMD::Int dynamicOffsets; // If hasDynamicOffsets is false, all dynamicOffsets are zero.
213*03ce13f7SAndroid Build Coastguard Worker std::vector<int32_t> staticOffsets;
214*03ce13f7SAndroid Build Coastguard Worker
215*03ce13f7SAndroid Build Coastguard Worker bool hasDynamicLimit = false; // True if dynamicLimit is non-zero.
216*03ce13f7SAndroid Build Coastguard Worker bool hasDynamicOffsets = false; // True if any dynamicOffsets are non-zero.
217*03ce13f7SAndroid Build Coastguard Worker bool isBasePlusOffset = false; // True if this uses base+offset. False if this is a collection of Pointers
218*03ce13f7SAndroid Build Coastguard Worker };
219*03ce13f7SAndroid Build Coastguard Worker
220*03ce13f7SAndroid Build Coastguard Worker } // namespace SIMD
221*03ce13f7SAndroid Build Coastguard Worker
222*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> operator+(RValue<SIMD::Int> lhs, RValue<SIMD::Int> rhs);
223*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> operator-(RValue<SIMD::Int> lhs, RValue<SIMD::Int> rhs);
224*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> operator*(RValue<SIMD::Int> lhs, RValue<SIMD::Int> rhs);
225*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> operator/(RValue<SIMD::Int> lhs, RValue<SIMD::Int> rhs);
226*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> operator%(RValue<SIMD::Int> lhs, RValue<SIMD::Int> rhs);
227*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> operator&(RValue<SIMD::Int> lhs, RValue<SIMD::Int> rhs);
228*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> operator|(RValue<SIMD::Int> lhs, RValue<SIMD::Int> rhs);
229*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> operator^(RValue<SIMD::Int> lhs, RValue<SIMD::Int> rhs);
230*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> operator<<(RValue<SIMD::Int> lhs, unsigned char rhs);
231*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> operator>>(RValue<SIMD::Int> lhs, unsigned char rhs);
232*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> operator<<(RValue<SIMD::Int> lhs, RValue<SIMD::Int> rhs);
233*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> operator>>(RValue<SIMD::Int> lhs, RValue<SIMD::Int> rhs);
234*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> operator+=(SIMD::Int &lhs, RValue<SIMD::Int> rhs);
235*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> operator-=(SIMD::Int &lhs, RValue<SIMD::Int> rhs);
236*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> operator*=(SIMD::Int &lhs, RValue<SIMD::Int> rhs);
237*03ce13f7SAndroid Build Coastguard Worker // RValue<SIMD::Int> operator/=(SIMD::Int &lhs, RValue<SIMD::Int> rhs);
238*03ce13f7SAndroid Build Coastguard Worker // RValue<SIMD::Int> operator%=(SIMD::Int &lhs, RValue<SIMD::Int> rhs);
239*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> operator&=(SIMD::Int &lhs, RValue<SIMD::Int> rhs);
240*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> operator|=(SIMD::Int &lhs, RValue<SIMD::Int> rhs);
241*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> operator^=(SIMD::Int &lhs, RValue<SIMD::Int> rhs);
242*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> operator<<=(SIMD::Int &lhs, unsigned char rhs);
243*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> operator>>=(SIMD::Int &lhs, unsigned char rhs);
244*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> operator+(RValue<SIMD::Int> val);
245*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> operator-(RValue<SIMD::Int> val);
246*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> operator~(RValue<SIMD::Int> val);
247*03ce13f7SAndroid Build Coastguard Worker // RValue<SIMD::Int> operator++(SIMD::Int &val, int); // Post-increment
248*03ce13f7SAndroid Build Coastguard Worker // const Int &operator++(SIMD::Int &val); // Pre-increment
249*03ce13f7SAndroid Build Coastguard Worker // RValue<SIMD::Int> operator--(SIMD::Int &val, int); // Post-decrement
250*03ce13f7SAndroid Build Coastguard Worker // const Int &operator--(SIMD::Int &val); // Pre-decrement
251*03ce13f7SAndroid Build Coastguard Worker // RValue<Bool> operator<(RValue<SIMD::Int> lhs, RValue<SIMD::Int> rhs);
252*03ce13f7SAndroid Build Coastguard Worker // RValue<Bool> operator<=(RValue<SIMD::Int> lhs, RValue<SIMD::Int> rhs);
253*03ce13f7SAndroid Build Coastguard Worker // RValue<Bool> operator>(RValue<SIMD::Int> lhs, RValue<SIMD::Int> rhs);
254*03ce13f7SAndroid Build Coastguard Worker // RValue<Bool> operator>=(RValue<SIMD::Int> lhs, RValue<SIMD::Int> rhs);
255*03ce13f7SAndroid Build Coastguard Worker // RValue<Bool> operator!=(RValue<SIMD::Int> lhs, RValue<SIMD::Int> rhs);
256*03ce13f7SAndroid Build Coastguard Worker // RValue<Bool> operator==(RValue<SIMD::Int> lhs, RValue<SIMD::Int> rhs);
257*03ce13f7SAndroid Build Coastguard Worker
258*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> CmpEQ(RValue<SIMD::Int> x, RValue<SIMD::Int> y);
259*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> CmpLT(RValue<SIMD::Int> x, RValue<SIMD::Int> y);
260*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> CmpLE(RValue<SIMD::Int> x, RValue<SIMD::Int> y);
261*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> CmpNEQ(RValue<SIMD::Int> x, RValue<SIMD::Int> y);
262*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> CmpNLT(RValue<SIMD::Int> x, RValue<SIMD::Int> y);
263*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> CmpNLE(RValue<SIMD::Int> x, RValue<SIMD::Int> y);
CmpGT(RValue<SIMD::Int> x,RValue<SIMD::Int> y)264*03ce13f7SAndroid Build Coastguard Worker inline RValue<SIMD::Int> CmpGT(RValue<SIMD::Int> x, RValue<SIMD::Int> y)
265*03ce13f7SAndroid Build Coastguard Worker {
266*03ce13f7SAndroid Build Coastguard Worker return CmpNLE(x, y);
267*03ce13f7SAndroid Build Coastguard Worker }
CmpGE(RValue<SIMD::Int> x,RValue<SIMD::Int> y)268*03ce13f7SAndroid Build Coastguard Worker inline RValue<SIMD::Int> CmpGE(RValue<SIMD::Int> x, RValue<SIMD::Int> y)
269*03ce13f7SAndroid Build Coastguard Worker {
270*03ce13f7SAndroid Build Coastguard Worker return CmpNLT(x, y);
271*03ce13f7SAndroid Build Coastguard Worker }
272*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> Abs(RValue<SIMD::Int> x);
273*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> Max(RValue<SIMD::Int> x, RValue<SIMD::Int> y);
274*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> Min(RValue<SIMD::Int> x, RValue<SIMD::Int> y);
275*03ce13f7SAndroid Build Coastguard Worker // Convert to nearest integer. If a converted value is outside of the integer
276*03ce13f7SAndroid Build Coastguard Worker // range, the returned result is undefined.
277*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> RoundInt(RValue<SIMD::Float> cast);
278*03ce13f7SAndroid Build Coastguard Worker // Rounds to the nearest integer, but clamps very large values to an
279*03ce13f7SAndroid Build Coastguard Worker // implementation-dependent range.
280*03ce13f7SAndroid Build Coastguard Worker // Specifically, on x86, values larger than 2147483583.0 are converted to
281*03ce13f7SAndroid Build Coastguard Worker // 2147483583 (0x7FFFFFBF) instead of producing 0x80000000.
282*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> RoundIntClamped(RValue<SIMD::Float> cast);
283*03ce13f7SAndroid Build Coastguard Worker RValue<scalar::Int> Extract(RValue<SIMD::Int> val, int i);
284*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> Insert(RValue<SIMD::Int> val, RValue<scalar::Int> element, int i);
285*03ce13f7SAndroid Build Coastguard Worker RValue<packed::Int4> Extract128(RValue<SIMD::Int> val, int i);
286*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> Insert128(RValue<SIMD::Int> val, RValue<packed::Int4> element, int i);
287*03ce13f7SAndroid Build Coastguard Worker
288*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> operator+(RValue<SIMD::UInt> lhs, RValue<SIMD::UInt> rhs);
289*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> operator-(RValue<SIMD::UInt> lhs, RValue<SIMD::UInt> rhs);
290*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> operator*(RValue<SIMD::UInt> lhs, RValue<SIMD::UInt> rhs);
291*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> operator/(RValue<SIMD::UInt> lhs, RValue<SIMD::UInt> rhs);
292*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> operator%(RValue<SIMD::UInt> lhs, RValue<SIMD::UInt> rhs);
293*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> operator&(RValue<SIMD::UInt> lhs, RValue<SIMD::UInt> rhs);
294*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> operator|(RValue<SIMD::UInt> lhs, RValue<SIMD::UInt> rhs);
295*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> operator^(RValue<SIMD::UInt> lhs, RValue<SIMD::UInt> rhs);
296*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> operator<<(RValue<SIMD::UInt> lhs, unsigned char rhs);
297*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> operator>>(RValue<SIMD::UInt> lhs, unsigned char rhs);
298*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> operator<<(RValue<SIMD::UInt> lhs, RValue<SIMD::UInt> rhs);
299*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> operator>>(RValue<SIMD::UInt> lhs, RValue<SIMD::UInt> rhs);
300*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> operator+=(SIMD::UInt &lhs, RValue<SIMD::UInt> rhs);
301*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> operator-=(SIMD::UInt &lhs, RValue<SIMD::UInt> rhs);
302*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> operator*=(SIMD::UInt &lhs, RValue<SIMD::UInt> rhs);
303*03ce13f7SAndroid Build Coastguard Worker // RValue<SIMD::UInt> operator/=(SIMD::UInt &lhs, RValue<SIMD::UInt> rhs);
304*03ce13f7SAndroid Build Coastguard Worker // RValue<SIMD::UInt> operator%=(SIMD::UInt &lhs, RValue<SIMD::UInt> rhs);
305*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> operator&=(SIMD::UInt &lhs, RValue<SIMD::UInt> rhs);
306*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> operator|=(SIMD::UInt &lhs, RValue<SIMD::UInt> rhs);
307*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> operator^=(SIMD::UInt &lhs, RValue<SIMD::UInt> rhs);
308*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> operator<<=(SIMD::UInt &lhs, unsigned char rhs);
309*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> operator>>=(SIMD::UInt &lhs, unsigned char rhs);
310*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> operator+(RValue<SIMD::UInt> val);
311*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> operator-(RValue<SIMD::UInt> val);
312*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> operator~(RValue<SIMD::UInt> val);
313*03ce13f7SAndroid Build Coastguard Worker // RValue<SIMD::UInt> operator++(SIMD::UInt &val, int); // Post-increment
314*03ce13f7SAndroid Build Coastguard Worker // const UInt &operator++(SIMD::UInt &val); // Pre-increment
315*03ce13f7SAndroid Build Coastguard Worker // RValue<SIMD::UInt> operator--(SIMD::UInt &val, int); // Post-decrement
316*03ce13f7SAndroid Build Coastguard Worker // const UInt &operator--(SIMD::UInt &val); // Pre-decrement
317*03ce13f7SAndroid Build Coastguard Worker // RValue<Bool> operator<(RValue<SIMD::UInt> lhs, RValue<SIMD::UInt> rhs);
318*03ce13f7SAndroid Build Coastguard Worker // RValue<Bool> operator<=(RValue<SIMD::UInt> lhs, RValue<SIMD::UInt> rhs);
319*03ce13f7SAndroid Build Coastguard Worker // RValue<Bool> operator>(RValue<SIMD::UInt> lhs, RValue<SIMD::UInt> rhs);
320*03ce13f7SAndroid Build Coastguard Worker // RValue<Bool> operator>=(RValue<SIMD::UInt> lhs, RValue<SIMD::UInt> rhs);
321*03ce13f7SAndroid Build Coastguard Worker // RValue<Bool> operator!=(RValue<SIMD::UInt> lhs, RValue<SIMD::UInt> rhs);
322*03ce13f7SAndroid Build Coastguard Worker // RValue<Bool> operator==(RValue<SIMD::UInt> lhs, RValue<SIMD::UInt> rhs);
323*03ce13f7SAndroid Build Coastguard Worker
324*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> CmpEQ(RValue<SIMD::UInt> x, RValue<SIMD::UInt> y);
325*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> CmpLT(RValue<SIMD::UInt> x, RValue<SIMD::UInt> y);
326*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> CmpLE(RValue<SIMD::UInt> x, RValue<SIMD::UInt> y);
327*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> CmpNEQ(RValue<SIMD::UInt> x, RValue<SIMD::UInt> y);
328*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> CmpNLT(RValue<SIMD::UInt> x, RValue<SIMD::UInt> y);
329*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> CmpNLE(RValue<SIMD::UInt> x, RValue<SIMD::UInt> y);
CmpGT(RValue<SIMD::UInt> x,RValue<SIMD::UInt> y)330*03ce13f7SAndroid Build Coastguard Worker inline RValue<SIMD::UInt> CmpGT(RValue<SIMD::UInt> x, RValue<SIMD::UInt> y)
331*03ce13f7SAndroid Build Coastguard Worker {
332*03ce13f7SAndroid Build Coastguard Worker return CmpNLE(x, y);
333*03ce13f7SAndroid Build Coastguard Worker }
CmpGE(RValue<SIMD::UInt> x,RValue<SIMD::UInt> y)334*03ce13f7SAndroid Build Coastguard Worker inline RValue<SIMD::UInt> CmpGE(RValue<SIMD::UInt> x, RValue<SIMD::UInt> y)
335*03ce13f7SAndroid Build Coastguard Worker {
336*03ce13f7SAndroid Build Coastguard Worker return CmpNLT(x, y);
337*03ce13f7SAndroid Build Coastguard Worker }
338*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> Max(RValue<SIMD::UInt> x, RValue<SIMD::UInt> y);
339*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> Min(RValue<SIMD::UInt> x, RValue<SIMD::UInt> y);
340*03ce13f7SAndroid Build Coastguard Worker RValue<scalar::UInt> Extract(RValue<SIMD::UInt> val, int i);
341*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> Insert(RValue<SIMD::UInt> val, RValue<scalar::UInt> element, int i);
342*03ce13f7SAndroid Build Coastguard Worker RValue<packed::UInt4> Extract128(RValue<SIMD::UInt> val, int i);
343*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> Insert128(RValue<SIMD::UInt> val, RValue<packed::UInt4> element, int i);
344*03ce13f7SAndroid Build Coastguard Worker // RValue<SIMD::UInt> RoundInt(RValue<SIMD::Float> cast);
345*03ce13f7SAndroid Build Coastguard Worker
346*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> operator+(RValue<SIMD::Float> lhs, RValue<SIMD::Float> rhs);
347*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> operator-(RValue<SIMD::Float> lhs, RValue<SIMD::Float> rhs);
348*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> operator*(RValue<SIMD::Float> lhs, RValue<SIMD::Float> rhs);
349*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> operator/(RValue<SIMD::Float> lhs, RValue<SIMD::Float> rhs);
350*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> operator%(RValue<SIMD::Float> lhs, RValue<SIMD::Float> rhs);
351*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> operator+=(SIMD::Float &lhs, RValue<SIMD::Float> rhs);
352*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> operator-=(SIMD::Float &lhs, RValue<SIMD::Float> rhs);
353*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> operator*=(SIMD::Float &lhs, RValue<SIMD::Float> rhs);
354*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> operator/=(SIMD::Float &lhs, RValue<SIMD::Float> rhs);
355*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> operator%=(SIMD::Float &lhs, RValue<SIMD::Float> rhs);
356*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> operator+(RValue<SIMD::Float> val);
357*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> operator-(RValue<SIMD::Float> val);
358*03ce13f7SAndroid Build Coastguard Worker
359*03ce13f7SAndroid Build Coastguard Worker // Computes `x * y + z`, which may be fused into one operation to produce a higher-precision result.
360*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> MulAdd(RValue<SIMD::Float> x, RValue<SIMD::Float> y, RValue<SIMD::Float> z);
361*03ce13f7SAndroid Build Coastguard Worker // Computes a fused `x * y + z` operation. Caps::fmaIsFast indicates whether it emits an FMA instruction.
362*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> FMA(RValue<SIMD::Float> x, RValue<SIMD::Float> y, RValue<SIMD::Float> z);
363*03ce13f7SAndroid Build Coastguard Worker
364*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> Abs(RValue<SIMD::Float> x);
365*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> Max(RValue<SIMD::Float> x, RValue<SIMD::Float> y);
366*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> Min(RValue<SIMD::Float> x, RValue<SIMD::Float> y);
367*03ce13f7SAndroid Build Coastguard Worker
368*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> Rcp(RValue<SIMD::Float> x, bool relaxedPrecision, bool exactAtPow2 = false);
369*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> RcpSqrt(RValue<SIMD::Float> x, bool relaxedPrecision);
370*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> Sqrt(RValue<SIMD::Float> x);
371*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> Insert(RValue<SIMD::Float> val, RValue<rr ::Float> element, int i);
372*03ce13f7SAndroid Build Coastguard Worker RValue<rr ::Float> Extract(RValue<SIMD::Float> x, int i);
373*03ce13f7SAndroid Build Coastguard Worker RValue<packed::Float4> Extract128(RValue<SIMD::Float> val, int i);
374*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> Insert128(RValue<SIMD::Float> val, RValue<packed::Float4> element, int i);
375*03ce13f7SAndroid Build Coastguard Worker
376*03ce13f7SAndroid Build Coastguard Worker // Ordered comparison functions
377*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> CmpEQ(RValue<SIMD::Float> x, RValue<SIMD::Float> y);
378*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> CmpLT(RValue<SIMD::Float> x, RValue<SIMD::Float> y);
379*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> CmpLE(RValue<SIMD::Float> x, RValue<SIMD::Float> y);
380*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> CmpNEQ(RValue<SIMD::Float> x, RValue<SIMD::Float> y);
381*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> CmpNLT(RValue<SIMD::Float> x, RValue<SIMD::Float> y);
382*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> CmpNLE(RValue<SIMD::Float> x, RValue<SIMD::Float> y);
CmpGT(RValue<SIMD::Float> x,RValue<SIMD::Float> y)383*03ce13f7SAndroid Build Coastguard Worker inline RValue<SIMD::Int> CmpGT(RValue<SIMD::Float> x, RValue<SIMD::Float> y)
384*03ce13f7SAndroid Build Coastguard Worker {
385*03ce13f7SAndroid Build Coastguard Worker return CmpNLE(x, y);
386*03ce13f7SAndroid Build Coastguard Worker }
CmpGE(RValue<SIMD::Float> x,RValue<SIMD::Float> y)387*03ce13f7SAndroid Build Coastguard Worker inline RValue<SIMD::Int> CmpGE(RValue<SIMD::Float> x, RValue<SIMD::Float> y)
388*03ce13f7SAndroid Build Coastguard Worker {
389*03ce13f7SAndroid Build Coastguard Worker return CmpNLT(x, y);
390*03ce13f7SAndroid Build Coastguard Worker }
391*03ce13f7SAndroid Build Coastguard Worker
392*03ce13f7SAndroid Build Coastguard Worker // Unordered comparison functions
393*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> CmpUEQ(RValue<SIMD::Float> x, RValue<SIMD::Float> y);
394*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> CmpULT(RValue<SIMD::Float> x, RValue<SIMD::Float> y);
395*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> CmpULE(RValue<SIMD::Float> x, RValue<SIMD::Float> y);
396*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> CmpUNEQ(RValue<SIMD::Float> x, RValue<SIMD::Float> y);
397*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> CmpUNLT(RValue<SIMD::Float> x, RValue<SIMD::Float> y);
398*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> CmpUNLE(RValue<SIMD::Float> x, RValue<SIMD::Float> y);
CmpUGT(RValue<SIMD::Float> x,RValue<SIMD::Float> y)399*03ce13f7SAndroid Build Coastguard Worker inline RValue<SIMD::Int> CmpUGT(RValue<SIMD::Float> x, RValue<SIMD::Float> y)
400*03ce13f7SAndroid Build Coastguard Worker {
401*03ce13f7SAndroid Build Coastguard Worker return CmpUNLE(x, y);
402*03ce13f7SAndroid Build Coastguard Worker }
CmpUGE(RValue<SIMD::Float> x,RValue<SIMD::Float> y)403*03ce13f7SAndroid Build Coastguard Worker inline RValue<SIMD::Int> CmpUGE(RValue<SIMD::Float> x, RValue<SIMD::Float> y)
404*03ce13f7SAndroid Build Coastguard Worker {
405*03ce13f7SAndroid Build Coastguard Worker return CmpUNLT(x, y);
406*03ce13f7SAndroid Build Coastguard Worker }
407*03ce13f7SAndroid Build Coastguard Worker
408*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> IsInf(RValue<SIMD::Float> x);
409*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> IsNan(RValue<SIMD::Float> x);
410*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> Round(RValue<SIMD::Float> x);
411*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> Trunc(RValue<SIMD::Float> x);
412*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> Frac(RValue<SIMD::Float> x);
413*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> Floor(RValue<SIMD::Float> x);
414*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> Ceil(RValue<SIMD::Float> x);
415*03ce13f7SAndroid Build Coastguard Worker
416*03ce13f7SAndroid Build Coastguard Worker // Trigonometric functions
417*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> Sin(RValue<SIMD::Float> x);
418*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> Cos(RValue<SIMD::Float> x);
419*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> Tan(RValue<SIMD::Float> x);
420*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> Asin(RValue<SIMD::Float> x);
421*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> Acos(RValue<SIMD::Float> x);
422*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> Atan(RValue<SIMD::Float> x);
423*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> Sinh(RValue<SIMD::Float> x);
424*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> Cosh(RValue<SIMD::Float> x);
425*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> Tanh(RValue<SIMD::Float> x);
426*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> Asinh(RValue<SIMD::Float> x);
427*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> Acosh(RValue<SIMD::Float> x);
428*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> Atanh(RValue<SIMD::Float> x);
429*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> Atan2(RValue<SIMD::Float> x, RValue<SIMD::Float> y);
430*03ce13f7SAndroid Build Coastguard Worker
431*03ce13f7SAndroid Build Coastguard Worker // Exponential functions
432*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> Pow(RValue<SIMD::Float> x, RValue<SIMD::Float> y);
433*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> Exp(RValue<SIMD::Float> x);
434*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> Log(RValue<SIMD::Float> x);
435*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> Exp2(RValue<SIMD::Float> x);
436*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> Log2(RValue<SIMD::Float> x);
437*03ce13f7SAndroid Build Coastguard Worker
438*03ce13f7SAndroid Build Coastguard Worker RValue<Int> SignMask(RValue<SIMD::Int> x);
439*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> Ctlz(RValue<SIMD::UInt> x, bool isZeroUndef);
440*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> Cttz(RValue<SIMD::UInt> x, bool isZeroUndef);
441*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> MulHigh(RValue<SIMD::Int> x, RValue<SIMD::Int> y);
442*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> MulHigh(RValue<SIMD::UInt> x, RValue<SIMD::UInt> y);
443*03ce13f7SAndroid Build Coastguard Worker RValue<Bool> AnyTrue(const RValue<SIMD::Int> &bools);
444*03ce13f7SAndroid Build Coastguard Worker RValue<Bool> AnyFalse(const RValue<SIMD::Int> &bools);
445*03ce13f7SAndroid Build Coastguard Worker RValue<Bool> Divergent(const RValue<SIMD::Int> &ints);
446*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> Swizzle(RValue<SIMD::Int> x, uint16_t select);
447*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> Swizzle(RValue<SIMD::UInt> x, uint16_t select);
448*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> Swizzle(RValue<SIMD::Float> x, uint16_t select);
449*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> Shuffle(RValue<SIMD::Int> x, RValue<SIMD::Int> y, uint16_t select);
450*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::UInt> Shuffle(RValue<SIMD::UInt> x, RValue<SIMD::UInt> y, uint16_t select);
451*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> Shuffle(RValue<SIMD::Float> x, RValue<SIMD::Float> y, uint16_t select);
452*03ce13f7SAndroid Build Coastguard Worker
453*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Float> Gather(RValue<Pointer<Float>> base, RValue<SIMD::Int> offsets, RValue<SIMD::Int> mask, unsigned int alignment, bool zeroMaskedLanes = false);
454*03ce13f7SAndroid Build Coastguard Worker RValue<SIMD::Int> Gather(RValue<Pointer<Int>> base, RValue<SIMD::Int> offsets, RValue<SIMD::Int> mask, unsigned int alignment, bool zeroMaskedLanes = false);
455*03ce13f7SAndroid Build Coastguard Worker void Scatter(RValue<Pointer<Float>> base, RValue<SIMD::Float> val, RValue<SIMD::Int> offsets, RValue<SIMD::Int> mask, unsigned int alignment);
456*03ce13f7SAndroid Build Coastguard Worker void Scatter(RValue<Pointer<Int>> base, RValue<SIMD::Int> val, RValue<SIMD::Int> offsets, RValue<SIMD::Int> mask, unsigned int alignment);
457*03ce13f7SAndroid Build Coastguard Worker
458*03ce13f7SAndroid Build Coastguard Worker template<>
RValue(int i)459*03ce13f7SAndroid Build Coastguard Worker inline RValue<SIMD::Int>::RValue(int i)
460*03ce13f7SAndroid Build Coastguard Worker : val(broadcast(i, SIMD::Int::type()))
461*03ce13f7SAndroid Build Coastguard Worker {
462*03ce13f7SAndroid Build Coastguard Worker RR_DEBUG_INFO_EMIT_VAR(val);
463*03ce13f7SAndroid Build Coastguard Worker }
464*03ce13f7SAndroid Build Coastguard Worker
465*03ce13f7SAndroid Build Coastguard Worker template<>
RValue(unsigned int i)466*03ce13f7SAndroid Build Coastguard Worker inline RValue<SIMD::UInt>::RValue(unsigned int i)
467*03ce13f7SAndroid Build Coastguard Worker : val(broadcast(int(i), SIMD::UInt::type()))
468*03ce13f7SAndroid Build Coastguard Worker {
469*03ce13f7SAndroid Build Coastguard Worker RR_DEBUG_INFO_EMIT_VAR(val);
470*03ce13f7SAndroid Build Coastguard Worker }
471*03ce13f7SAndroid Build Coastguard Worker
472*03ce13f7SAndroid Build Coastguard Worker template<>
RValue(float f)473*03ce13f7SAndroid Build Coastguard Worker inline RValue<SIMD::Float>::RValue(float f)
474*03ce13f7SAndroid Build Coastguard Worker : val(broadcast(f, SIMD::Float::type()))
475*03ce13f7SAndroid Build Coastguard Worker {
476*03ce13f7SAndroid Build Coastguard Worker RR_DEBUG_INFO_EMIT_VAR(val);
477*03ce13f7SAndroid Build Coastguard Worker }
478*03ce13f7SAndroid Build Coastguard Worker
479*03ce13f7SAndroid Build Coastguard Worker template<int T>
Int(const SwizzleMask1<packed::Int4,T> & rhs)480*03ce13f7SAndroid Build Coastguard Worker SIMD::Int::Int(const SwizzleMask1<packed::Int4, T> &rhs)
481*03ce13f7SAndroid Build Coastguard Worker : XYZW(this)
482*03ce13f7SAndroid Build Coastguard Worker {
483*03ce13f7SAndroid Build Coastguard Worker *this = rhs.operator RValue<scalar::Int>();
484*03ce13f7SAndroid Build Coastguard Worker }
485*03ce13f7SAndroid Build Coastguard Worker
486*03ce13f7SAndroid Build Coastguard Worker template<int T>
Float(const SwizzleMask1<packed::Float4,T> & rhs)487*03ce13f7SAndroid Build Coastguard Worker SIMD::Float::Float(const SwizzleMask1<packed::Float4, T> &rhs)
488*03ce13f7SAndroid Build Coastguard Worker : XYZW(this)
489*03ce13f7SAndroid Build Coastguard Worker {
490*03ce13f7SAndroid Build Coastguard Worker *this = rhs.operator RValue<scalar::Float>();
491*03ce13f7SAndroid Build Coastguard Worker }
492*03ce13f7SAndroid Build Coastguard Worker
493*03ce13f7SAndroid Build Coastguard Worker template<typename T>
Load(OutOfBoundsBehavior robustness,SIMD::Int mask,bool atomic,std::memory_order order,int alignment)494*03ce13f7SAndroid Build Coastguard Worker inline T SIMD::Pointer::Load(OutOfBoundsBehavior robustness, SIMD::Int mask, bool atomic /* = false */, std::memory_order order /* = std::memory_order_relaxed */, int alignment /* = sizeof(float) */)
495*03ce13f7SAndroid Build Coastguard Worker {
496*03ce13f7SAndroid Build Coastguard Worker using EL = typename Scalar<T>::Type;
497*03ce13f7SAndroid Build Coastguard Worker
498*03ce13f7SAndroid Build Coastguard Worker if(!isBasePlusOffset)
499*03ce13f7SAndroid Build Coastguard Worker {
500*03ce13f7SAndroid Build Coastguard Worker T out = T(0);
501*03ce13f7SAndroid Build Coastguard Worker for(int i = 0; i < SIMD::Width; i++)
502*03ce13f7SAndroid Build Coastguard Worker {
503*03ce13f7SAndroid Build Coastguard Worker If(Extract(mask, i) != 0)
504*03ce13f7SAndroid Build Coastguard Worker {
505*03ce13f7SAndroid Build Coastguard Worker auto el = rr::Load(scalar::Pointer<EL>(pointers[i]), alignment, atomic, order);
506*03ce13f7SAndroid Build Coastguard Worker out = Insert(out, el, i);
507*03ce13f7SAndroid Build Coastguard Worker }
508*03ce13f7SAndroid Build Coastguard Worker }
509*03ce13f7SAndroid Build Coastguard Worker return out;
510*03ce13f7SAndroid Build Coastguard Worker }
511*03ce13f7SAndroid Build Coastguard Worker
512*03ce13f7SAndroid Build Coastguard Worker if(isStaticallyInBounds(sizeof(float), robustness))
513*03ce13f7SAndroid Build Coastguard Worker {
514*03ce13f7SAndroid Build Coastguard Worker // All elements are statically known to be in-bounds.
515*03ce13f7SAndroid Build Coastguard Worker // We can avoid costly conditional on masks.
516*03ce13f7SAndroid Build Coastguard Worker
517*03ce13f7SAndroid Build Coastguard Worker if(hasStaticSequentialOffsets(sizeof(float)))
518*03ce13f7SAndroid Build Coastguard Worker {
519*03ce13f7SAndroid Build Coastguard Worker // Offsets are sequential. Perform regular load.
520*03ce13f7SAndroid Build Coastguard Worker return rr::Load(scalar::Pointer<T>(base + staticOffsets[0]), alignment, atomic, order);
521*03ce13f7SAndroid Build Coastguard Worker }
522*03ce13f7SAndroid Build Coastguard Worker
523*03ce13f7SAndroid Build Coastguard Worker if(hasStaticEqualOffsets())
524*03ce13f7SAndroid Build Coastguard Worker {
525*03ce13f7SAndroid Build Coastguard Worker // Load one, replicate.
526*03ce13f7SAndroid Build Coastguard Worker return T(*scalar::Pointer<EL>(base + staticOffsets[0], alignment));
527*03ce13f7SAndroid Build Coastguard Worker }
528*03ce13f7SAndroid Build Coastguard Worker }
529*03ce13f7SAndroid Build Coastguard Worker else
530*03ce13f7SAndroid Build Coastguard Worker {
531*03ce13f7SAndroid Build Coastguard Worker switch(robustness)
532*03ce13f7SAndroid Build Coastguard Worker {
533*03ce13f7SAndroid Build Coastguard Worker case OutOfBoundsBehavior::Nullify:
534*03ce13f7SAndroid Build Coastguard Worker case OutOfBoundsBehavior::RobustBufferAccess:
535*03ce13f7SAndroid Build Coastguard Worker case OutOfBoundsBehavior::UndefinedValue:
536*03ce13f7SAndroid Build Coastguard Worker mask &= isInBounds(sizeof(float), robustness); // Disable out-of-bounds reads.
537*03ce13f7SAndroid Build Coastguard Worker break;
538*03ce13f7SAndroid Build Coastguard Worker case OutOfBoundsBehavior::UndefinedBehavior:
539*03ce13f7SAndroid Build Coastguard Worker // Nothing to do. Application/compiler must guarantee no out-of-bounds accesses.
540*03ce13f7SAndroid Build Coastguard Worker break;
541*03ce13f7SAndroid Build Coastguard Worker }
542*03ce13f7SAndroid Build Coastguard Worker }
543*03ce13f7SAndroid Build Coastguard Worker
544*03ce13f7SAndroid Build Coastguard Worker auto offs = offsets();
545*03ce13f7SAndroid Build Coastguard Worker
546*03ce13f7SAndroid Build Coastguard Worker if(!atomic && order == std::memory_order_relaxed)
547*03ce13f7SAndroid Build Coastguard Worker {
548*03ce13f7SAndroid Build Coastguard Worker if(hasStaticEqualOffsets())
549*03ce13f7SAndroid Build Coastguard Worker {
550*03ce13f7SAndroid Build Coastguard Worker // Load one, replicate.
551*03ce13f7SAndroid Build Coastguard Worker // Be careful of the case where the post-bounds-check mask
552*03ce13f7SAndroid Build Coastguard Worker // is 0, in which case we must not load.
553*03ce13f7SAndroid Build Coastguard Worker T out = T(0);
554*03ce13f7SAndroid Build Coastguard Worker If(AnyTrue(mask))
555*03ce13f7SAndroid Build Coastguard Worker {
556*03ce13f7SAndroid Build Coastguard Worker EL el = *scalar::Pointer<EL>(base + staticOffsets[0], alignment);
557*03ce13f7SAndroid Build Coastguard Worker out = T(el);
558*03ce13f7SAndroid Build Coastguard Worker }
559*03ce13f7SAndroid Build Coastguard Worker return out;
560*03ce13f7SAndroid Build Coastguard Worker }
561*03ce13f7SAndroid Build Coastguard Worker
562*03ce13f7SAndroid Build Coastguard Worker bool zeroMaskedLanes = true;
563*03ce13f7SAndroid Build Coastguard Worker switch(robustness)
564*03ce13f7SAndroid Build Coastguard Worker {
565*03ce13f7SAndroid Build Coastguard Worker case OutOfBoundsBehavior::Nullify:
566*03ce13f7SAndroid Build Coastguard Worker case OutOfBoundsBehavior::RobustBufferAccess: // Must either return an in-bounds value, or zero.
567*03ce13f7SAndroid Build Coastguard Worker zeroMaskedLanes = true;
568*03ce13f7SAndroid Build Coastguard Worker break;
569*03ce13f7SAndroid Build Coastguard Worker case OutOfBoundsBehavior::UndefinedValue:
570*03ce13f7SAndroid Build Coastguard Worker case OutOfBoundsBehavior::UndefinedBehavior:
571*03ce13f7SAndroid Build Coastguard Worker zeroMaskedLanes = false;
572*03ce13f7SAndroid Build Coastguard Worker break;
573*03ce13f7SAndroid Build Coastguard Worker }
574*03ce13f7SAndroid Build Coastguard Worker
575*03ce13f7SAndroid Build Coastguard Worker // TODO(b/195446858): Optimize static sequential offsets case by using masked load.
576*03ce13f7SAndroid Build Coastguard Worker
577*03ce13f7SAndroid Build Coastguard Worker return Gather(scalar::Pointer<EL>(base), offs, mask, alignment, zeroMaskedLanes);
578*03ce13f7SAndroid Build Coastguard Worker }
579*03ce13f7SAndroid Build Coastguard Worker else
580*03ce13f7SAndroid Build Coastguard Worker {
581*03ce13f7SAndroid Build Coastguard Worker T out;
582*03ce13f7SAndroid Build Coastguard Worker auto anyLanesDisabled = AnyFalse(mask);
583*03ce13f7SAndroid Build Coastguard Worker If(hasStaticEqualOffsets() && !anyLanesDisabled)
584*03ce13f7SAndroid Build Coastguard Worker {
585*03ce13f7SAndroid Build Coastguard Worker // Load one, replicate.
586*03ce13f7SAndroid Build Coastguard Worker auto offset = Extract(offs, 0);
587*03ce13f7SAndroid Build Coastguard Worker out = T(rr::Load(scalar::Pointer<EL>(&base[offset]), alignment, atomic, order));
588*03ce13f7SAndroid Build Coastguard Worker }
589*03ce13f7SAndroid Build Coastguard Worker Else If(hasStaticSequentialOffsets(sizeof(float)) && !anyLanesDisabled)
590*03ce13f7SAndroid Build Coastguard Worker {
591*03ce13f7SAndroid Build Coastguard Worker // Load all elements in a single SIMD instruction.
592*03ce13f7SAndroid Build Coastguard Worker auto offset = Extract(offs, 0);
593*03ce13f7SAndroid Build Coastguard Worker out = rr::Load(scalar::Pointer<T>(&base[offset]), alignment, atomic, order);
594*03ce13f7SAndroid Build Coastguard Worker }
595*03ce13f7SAndroid Build Coastguard Worker Else
596*03ce13f7SAndroid Build Coastguard Worker {
597*03ce13f7SAndroid Build Coastguard Worker // Divergent offsets or masked lanes.
598*03ce13f7SAndroid Build Coastguard Worker out = T(0);
599*03ce13f7SAndroid Build Coastguard Worker for(int i = 0; i < SIMD::Width; i++)
600*03ce13f7SAndroid Build Coastguard Worker {
601*03ce13f7SAndroid Build Coastguard Worker If(Extract(mask, i) != 0)
602*03ce13f7SAndroid Build Coastguard Worker {
603*03ce13f7SAndroid Build Coastguard Worker auto offset = Extract(offs, i);
604*03ce13f7SAndroid Build Coastguard Worker auto el = rr::Load(scalar::Pointer<EL>(&base[offset]), alignment, atomic, order);
605*03ce13f7SAndroid Build Coastguard Worker out = Insert(out, el, i);
606*03ce13f7SAndroid Build Coastguard Worker }
607*03ce13f7SAndroid Build Coastguard Worker }
608*03ce13f7SAndroid Build Coastguard Worker }
609*03ce13f7SAndroid Build Coastguard Worker return out;
610*03ce13f7SAndroid Build Coastguard Worker }
611*03ce13f7SAndroid Build Coastguard Worker }
612*03ce13f7SAndroid Build Coastguard Worker
613*03ce13f7SAndroid Build Coastguard Worker template<>
Load(OutOfBoundsBehavior robustness,SIMD::Int mask,bool atomic,std::memory_order order,int alignment)614*03ce13f7SAndroid Build Coastguard Worker inline SIMD::Pointer SIMD::Pointer::Load(OutOfBoundsBehavior robustness, SIMD::Int mask, bool atomic /* = false */, std::memory_order order /* = std::memory_order_relaxed */, int alignment /* = sizeof(float) */)
615*03ce13f7SAndroid Build Coastguard Worker {
616*03ce13f7SAndroid Build Coastguard Worker std::vector<scalar::Pointer<Byte>> pointers(SIMD::Width);
617*03ce13f7SAndroid Build Coastguard Worker
618*03ce13f7SAndroid Build Coastguard Worker for(int i = 0; i < SIMD::Width; i++)
619*03ce13f7SAndroid Build Coastguard Worker {
620*03ce13f7SAndroid Build Coastguard Worker If(Extract(mask, i) != 0)
621*03ce13f7SAndroid Build Coastguard Worker {
622*03ce13f7SAndroid Build Coastguard Worker pointers[i] = rr::Load(scalar::Pointer<scalar::Pointer<Byte>>(getPointerForLane(i)), alignment, atomic, order);
623*03ce13f7SAndroid Build Coastguard Worker }
624*03ce13f7SAndroid Build Coastguard Worker }
625*03ce13f7SAndroid Build Coastguard Worker
626*03ce13f7SAndroid Build Coastguard Worker return SIMD::Pointer(pointers);
627*03ce13f7SAndroid Build Coastguard Worker }
628*03ce13f7SAndroid Build Coastguard Worker
629*03ce13f7SAndroid Build Coastguard Worker template<typename T>
Store(T val,OutOfBoundsBehavior robustness,SIMD::Int mask,bool atomic,std::memory_order order)630*03ce13f7SAndroid Build Coastguard Worker inline void SIMD::Pointer::Store(T val, OutOfBoundsBehavior robustness, SIMD::Int mask, bool atomic /* = false */, std::memory_order order /* = std::memory_order_relaxed */)
631*03ce13f7SAndroid Build Coastguard Worker {
632*03ce13f7SAndroid Build Coastguard Worker using EL = typename Scalar<T>::Type;
633*03ce13f7SAndroid Build Coastguard Worker constexpr size_t alignment = sizeof(float);
634*03ce13f7SAndroid Build Coastguard Worker
635*03ce13f7SAndroid Build Coastguard Worker if(!isBasePlusOffset)
636*03ce13f7SAndroid Build Coastguard Worker {
637*03ce13f7SAndroid Build Coastguard Worker for(int i = 0; i < SIMD::Width; i++)
638*03ce13f7SAndroid Build Coastguard Worker {
639*03ce13f7SAndroid Build Coastguard Worker If(Extract(mask, i) != 0)
640*03ce13f7SAndroid Build Coastguard Worker {
641*03ce13f7SAndroid Build Coastguard Worker rr::Store(Extract(val, i), scalar::Pointer<EL>(pointers[i]), alignment, atomic, order);
642*03ce13f7SAndroid Build Coastguard Worker }
643*03ce13f7SAndroid Build Coastguard Worker }
644*03ce13f7SAndroid Build Coastguard Worker return;
645*03ce13f7SAndroid Build Coastguard Worker }
646*03ce13f7SAndroid Build Coastguard Worker
647*03ce13f7SAndroid Build Coastguard Worker auto offs = offsets();
648*03ce13f7SAndroid Build Coastguard Worker switch(robustness)
649*03ce13f7SAndroid Build Coastguard Worker {
650*03ce13f7SAndroid Build Coastguard Worker case OutOfBoundsBehavior::Nullify:
651*03ce13f7SAndroid Build Coastguard Worker case OutOfBoundsBehavior::RobustBufferAccess: // TODO: Allows writing anywhere within bounds. Could be faster than masking.
652*03ce13f7SAndroid Build Coastguard Worker case OutOfBoundsBehavior::UndefinedValue: // Should not be used for store operations. Treat as robust buffer access.
653*03ce13f7SAndroid Build Coastguard Worker mask &= isInBounds(sizeof(float), robustness); // Disable out-of-bounds writes.
654*03ce13f7SAndroid Build Coastguard Worker break;
655*03ce13f7SAndroid Build Coastguard Worker case OutOfBoundsBehavior::UndefinedBehavior:
656*03ce13f7SAndroid Build Coastguard Worker // Nothing to do. Application/compiler must guarantee no out-of-bounds accesses.
657*03ce13f7SAndroid Build Coastguard Worker break;
658*03ce13f7SAndroid Build Coastguard Worker }
659*03ce13f7SAndroid Build Coastguard Worker
660*03ce13f7SAndroid Build Coastguard Worker if(!atomic && order == std::memory_order_relaxed)
661*03ce13f7SAndroid Build Coastguard Worker {
662*03ce13f7SAndroid Build Coastguard Worker if(hasStaticEqualOffsets())
663*03ce13f7SAndroid Build Coastguard Worker {
664*03ce13f7SAndroid Build Coastguard Worker If(AnyTrue(mask))
665*03ce13f7SAndroid Build Coastguard Worker {
666*03ce13f7SAndroid Build Coastguard Worker assert(SIMD::Width == 4);
667*03ce13f7SAndroid Build Coastguard Worker
668*03ce13f7SAndroid Build Coastguard Worker // All equal. One of these writes will win -- elect the winning lane.
669*03ce13f7SAndroid Build Coastguard Worker auto v0111 = SIMD::Int(0, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
670*03ce13f7SAndroid Build Coastguard Worker auto elect = mask & ~(v0111 & (mask.xxyz | mask.xxxy | mask.xxxx));
671*03ce13f7SAndroid Build Coastguard Worker auto maskedVal = As<SIMD::Int>(val) & elect;
672*03ce13f7SAndroid Build Coastguard Worker auto scalarVal = Extract(maskedVal, 0) |
673*03ce13f7SAndroid Build Coastguard Worker Extract(maskedVal, 1) |
674*03ce13f7SAndroid Build Coastguard Worker Extract(maskedVal, 2) |
675*03ce13f7SAndroid Build Coastguard Worker Extract(maskedVal, 3);
676*03ce13f7SAndroid Build Coastguard Worker *scalar::Pointer<EL>(base + staticOffsets[0], alignment) = As<EL>(scalarVal);
677*03ce13f7SAndroid Build Coastguard Worker }
678*03ce13f7SAndroid Build Coastguard Worker }
679*03ce13f7SAndroid Build Coastguard Worker else if(hasStaticSequentialOffsets(sizeof(float)) &&
680*03ce13f7SAndroid Build Coastguard Worker isStaticallyInBounds(sizeof(float), robustness))
681*03ce13f7SAndroid Build Coastguard Worker {
682*03ce13f7SAndroid Build Coastguard Worker // TODO(b/195446858): Optimize using masked store.
683*03ce13f7SAndroid Build Coastguard Worker // Pointer has no elements OOB, and the store is not atomic.
684*03ce13f7SAndroid Build Coastguard Worker // Perform a read-modify-write.
685*03ce13f7SAndroid Build Coastguard Worker auto p = scalar::Pointer<SIMD::Int>(base + staticOffsets[0], alignment);
686*03ce13f7SAndroid Build Coastguard Worker auto prev = *p;
687*03ce13f7SAndroid Build Coastguard Worker *p = (prev & ~mask) | (As<SIMD::Int>(val) & mask);
688*03ce13f7SAndroid Build Coastguard Worker }
689*03ce13f7SAndroid Build Coastguard Worker else
690*03ce13f7SAndroid Build Coastguard Worker {
691*03ce13f7SAndroid Build Coastguard Worker Scatter(scalar::Pointer<EL>(base), val, offs, mask, alignment);
692*03ce13f7SAndroid Build Coastguard Worker }
693*03ce13f7SAndroid Build Coastguard Worker }
694*03ce13f7SAndroid Build Coastguard Worker else
695*03ce13f7SAndroid Build Coastguard Worker {
696*03ce13f7SAndroid Build Coastguard Worker auto anyLanesDisabled = AnyFalse(mask);
697*03ce13f7SAndroid Build Coastguard Worker If(hasStaticSequentialOffsets(sizeof(float)) && !anyLanesDisabled)
698*03ce13f7SAndroid Build Coastguard Worker {
699*03ce13f7SAndroid Build Coastguard Worker // Store all elements in a single SIMD instruction.
700*03ce13f7SAndroid Build Coastguard Worker auto offset = Extract(offs, 0);
701*03ce13f7SAndroid Build Coastguard Worker rr::Store(val, scalar::Pointer<T>(&base[offset]), alignment, atomic, order);
702*03ce13f7SAndroid Build Coastguard Worker }
703*03ce13f7SAndroid Build Coastguard Worker Else
704*03ce13f7SAndroid Build Coastguard Worker {
705*03ce13f7SAndroid Build Coastguard Worker // Divergent offsets or masked lanes.
706*03ce13f7SAndroid Build Coastguard Worker for(int i = 0; i < SIMD::Width; i++)
707*03ce13f7SAndroid Build Coastguard Worker {
708*03ce13f7SAndroid Build Coastguard Worker If(Extract(mask, i) != 0)
709*03ce13f7SAndroid Build Coastguard Worker {
710*03ce13f7SAndroid Build Coastguard Worker auto offset = Extract(offs, i);
711*03ce13f7SAndroid Build Coastguard Worker rr::Store(Extract(val, i), scalar::Pointer<EL>(&base[offset]), alignment, atomic, order);
712*03ce13f7SAndroid Build Coastguard Worker }
713*03ce13f7SAndroid Build Coastguard Worker }
714*03ce13f7SAndroid Build Coastguard Worker }
715*03ce13f7SAndroid Build Coastguard Worker }
716*03ce13f7SAndroid Build Coastguard Worker }
717*03ce13f7SAndroid Build Coastguard Worker
718*03ce13f7SAndroid Build Coastguard Worker template<>
Store(SIMD::Pointer val,OutOfBoundsBehavior robustness,SIMD::Int mask,bool atomic,std::memory_order order)719*03ce13f7SAndroid Build Coastguard Worker inline void SIMD::Pointer::Store(SIMD::Pointer val, OutOfBoundsBehavior robustness, SIMD::Int mask, bool atomic /* = false */, std::memory_order order /* = std::memory_order_relaxed */)
720*03ce13f7SAndroid Build Coastguard Worker {
721*03ce13f7SAndroid Build Coastguard Worker constexpr size_t alignment = sizeof(void *);
722*03ce13f7SAndroid Build Coastguard Worker
723*03ce13f7SAndroid Build Coastguard Worker for(int i = 0; i < SIMD::Width; i++)
724*03ce13f7SAndroid Build Coastguard Worker {
725*03ce13f7SAndroid Build Coastguard Worker If(Extract(mask, i) != 0)
726*03ce13f7SAndroid Build Coastguard Worker {
727*03ce13f7SAndroid Build Coastguard Worker rr::Store(val.getPointerForLane(i), scalar::Pointer<scalar::Pointer<Byte>>(getPointerForLane(i)), alignment, atomic, order);
728*03ce13f7SAndroid Build Coastguard Worker }
729*03ce13f7SAndroid Build Coastguard Worker }
730*03ce13f7SAndroid Build Coastguard Worker }
731*03ce13f7SAndroid Build Coastguard Worker
732*03ce13f7SAndroid Build Coastguard Worker template<typename T>
Store(RValue<T> val,OutOfBoundsBehavior robustness,SIMD::Int mask,bool atomic,std::memory_order order)733*03ce13f7SAndroid Build Coastguard Worker inline void SIMD::Pointer::Store(RValue<T> val, OutOfBoundsBehavior robustness, SIMD::Int mask, bool atomic /* = false */, std::memory_order order /* = std::memory_order_relaxed */)
734*03ce13f7SAndroid Build Coastguard Worker {
735*03ce13f7SAndroid Build Coastguard Worker Store(T(val), robustness, mask, atomic, order);
736*03ce13f7SAndroid Build Coastguard Worker }
737*03ce13f7SAndroid Build Coastguard Worker
738*03ce13f7SAndroid Build Coastguard Worker } // namespace rr
739*03ce13f7SAndroid Build Coastguard Worker
740*03ce13f7SAndroid Build Coastguard Worker #endif // rr_SIMD_hpp
741