xref: /aosp_15_r20/external/swiftshader/src/Reactor/SIMD.hpp (revision 03ce13f70fcc45d86ee91b7ee4cab1936a95046e)
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