// Copyright 2016 The SwiftShader Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef rr_Reactor_hpp #define rr_Reactor_hpp #include "Nucleus.hpp" #include "Pragma.hpp" #include "Routine.hpp" #include "Swizzle.hpp" #include "Traits.hpp" #include #include #include #include #include #include #include #include #ifdef ENABLE_RR_DEBUG_INFO // Functions used for generating JIT debug info. // See docs/ReactorDebugInfo.md for more information. namespace rr { // Update the current source location for debug. void EmitDebugLocation(); // Bind value to its symbolic name taken from the backtrace. void EmitDebugVariable(class Value *value); // Flush any pending variable bindings before the line ends. void FlushDebug(); } // namespace rr # define RR_DEBUG_INFO_UPDATE_LOC() rr::EmitDebugLocation() # define RR_DEBUG_INFO_EMIT_VAR(value) rr::EmitDebugVariable(value) # define RR_DEBUG_INFO_FLUSH() rr::FlushDebug() #else # define RR_DEBUG_INFO_UPDATE_LOC() # define RR_DEBUG_INFO_EMIT_VAR(value) # define RR_DEBUG_INFO_FLUSH() #endif // ENABLE_RR_DEBUG_INFO #ifdef ENABLE_RR_PRINT namespace rr { int DebugPrintf(const char *format, ...); } #endif // A Clang extension to determine compiler features. // We use it to detect Sanitizer builds (e.g. -fsanitize=memory). #ifndef __has_feature # define __has_feature(x) 0 #endif namespace rr { struct Caps { static std::string backendName(); static bool coroutinesSupported(); // Support for rr::Coroutine static bool fmaIsFast(); // rr::FMA() is faster than `x * y + z` }; class Bool; class Byte; class SByte; class Byte4; class SByte4; class Byte8; class SByte8; class Byte16; class SByte16; class Short; class UShort; class Short2; class UShort2; class Short4; class UShort4; class Short8; class UShort8; class Int; class UInt; class Int2; class UInt2; class Int4; class UInt4; class Long; class Half; class Float; class Float2; class Float4; namespace SIMD { class Int; class UInt; class Float; } // namespace SIMD template<> struct Scalar { using Type = Float; }; template<> struct Scalar { using Type = Int; }; template<> struct Scalar { using Type = UInt; }; template<> struct Scalar { using Type = Float; }; template<> struct Scalar { using Type = Int; }; template<> struct Scalar { using Type = UInt; }; class Void { public: static Type *type(); }; template class RValue; template class Pointer; class Variable { friend class Nucleus; Variable() = delete; Variable &operator=(const Variable &) = delete; public: void materialize() const; Value *loadValue() const; Value *storeValue(Value *value) const; Value *getBaseAddress() const; Value *getElementPointer(Value *index, bool unsignedIndex) const; Type *getType() const { return type; } int getArraySize() const { return arraySize; } // This function is only public for testing purposes, as it affects performance. // It is not considered part of Reactor's public API. static void materializeAll(); protected: Variable(Type *type, int arraySize); Variable(const Variable &) = default; virtual ~Variable(); private: static void killUnmaterialized(); // Set of variables that do not have a stack location yet. class UnmaterializedVariables { public: void add(const Variable *v); void remove(const Variable *v); void clear(); void materializeAll(); private: int counter = 0; std::unordered_map variables; }; // This has to be a raw pointer because glibc 2.17 doesn't support __cxa_thread_atexit_impl // for destructing objects at exit. See crbug.com/1074222 static thread_local UnmaterializedVariables *unmaterializedVariables; Type *const type; const int arraySize; mutable Value *rvalue = nullptr; mutable Value *address = nullptr; }; template class LValue : public Variable { public: LValue(int arraySize = 0); RValue> operator&(); RValue load() const { return RValue(this->loadValue()); } RValue store(RValue rvalue) const { this->storeValue(rvalue.value()); return rvalue; } // self() returns the this pointer to this LValue object. // This function exists because operator&() is overloaded. inline LValue *self() { return this; } }; template class Reference { public: using reference_underlying_type = T; explicit Reference(Value *pointer, int alignment = 1); Reference(const Reference &ref) = default; RValue operator=(RValue rhs) const; RValue operator=(const Reference &ref) const; RValue operator+=(RValue rhs) const; RValue> operator&() const { return RValue>(address); } Value *loadValue() const; RValue load() const; int getAlignment() const; private: Value *const address; const int alignment; }; template struct BoolLiteral { struct Type; }; template<> struct BoolLiteral { using Type = bool; }; template struct IntLiteral { struct Type; }; template<> struct IntLiteral { using Type = int; }; template<> struct IntLiteral { using Type = unsigned int; }; template struct LongLiteral { struct Type; }; template<> struct LongLiteral { using Type = int64_t; }; template struct FloatLiteral { struct Type; }; template<> struct FloatLiteral { using Type = float; }; template struct BroadcastLiteral { struct Type; }; template<> struct BroadcastLiteral { using Type = int; }; template<> struct BroadcastLiteral { using Type = unsigned int; }; template<> struct BroadcastLiteral { using Type = float; }; template<> struct BroadcastLiteral { using Type = int; }; template<> struct BroadcastLiteral { using Type = unsigned int; }; template<> struct BroadcastLiteral { using Type = float; }; template class RValue { public: using rvalue_underlying_type = T; explicit RValue(Value *rvalue); RValue(const RValue &rvalue); RValue(const T &lvalue); RValue(typename BoolLiteral::Type b); RValue(typename IntLiteral::Type i); RValue(typename LongLiteral::Type i); RValue(typename FloatLiteral::Type f); RValue(typename BroadcastLiteral::Type x); RValue(const Reference &rhs); // Rvalues cannot be assigned to: "(a + b) = c;" RValue &operator=(const RValue &) = delete; Value *value() const { return val; } static int element_count() { return T::element_count(); } private: Value *const val; }; template class Argument { public: explicit Argument(Value *val) : val(val) {} RValue rvalue() const { return RValue(val); } private: Value *const val; }; class Bool : public LValue { public: Bool(Argument argument); Bool() = default; Bool(bool x); Bool(RValue rhs); Bool(const Bool &rhs); Bool(const Reference &rhs); // RValue operator=(bool rhs); // FIXME: Implement RValue operator=(RValue rhs); RValue operator=(const Bool &rhs); RValue operator=(const Reference &rhs); static Type *type(); }; RValue operator!(RValue val); RValue operator&&(RValue lhs, RValue rhs); RValue operator||(RValue lhs, RValue rhs); RValue operator!=(RValue lhs, RValue rhs); RValue operator==(RValue lhs, RValue rhs); class Byte : public LValue { public: Byte(Argument argument); explicit Byte(RValue cast); explicit Byte(RValue cast); explicit Byte(RValue cast); Byte() = default; Byte(int x); Byte(unsigned char x); Byte(RValue rhs); Byte(const Byte &rhs); Byte(const Reference &rhs); // RValue operator=(unsigned char rhs); // FIXME: Implement RValue operator=(RValue rhs); RValue operator=(const Byte &rhs); RValue operator=(const Reference &rhs); static Type *type(); }; RValue operator+(RValue lhs, RValue rhs); RValue operator-(RValue lhs, RValue rhs); RValue operator*(RValue lhs, RValue rhs); RValue operator/(RValue lhs, RValue rhs); RValue operator%(RValue lhs, RValue rhs); RValue operator&(RValue lhs, RValue rhs); RValue operator|(RValue lhs, RValue rhs); RValue operator^(RValue lhs, RValue rhs); RValue operator<<(RValue lhs, RValue rhs); RValue operator>>(RValue lhs, RValue rhs); RValue operator+=(Byte &lhs, RValue rhs); RValue operator-=(Byte &lhs, RValue rhs); RValue operator*=(Byte &lhs, RValue rhs); RValue operator/=(Byte &lhs, RValue rhs); RValue operator%=(Byte &lhs, RValue rhs); RValue operator&=(Byte &lhs, RValue rhs); RValue operator|=(Byte &lhs, RValue rhs); RValue operator^=(Byte &lhs, RValue rhs); RValue operator<<=(Byte &lhs, RValue rhs); RValue operator>>=(Byte &lhs, RValue rhs); RValue operator+(RValue val); RValue operator-(RValue val); RValue operator~(RValue val); RValue operator++(Byte &val, int); // Post-increment const Byte &operator++(Byte &val); // Pre-increment RValue operator--(Byte &val, int); // Post-decrement const Byte &operator--(Byte &val); // Pre-decrement RValue operator<(RValue lhs, RValue rhs); RValue operator<=(RValue lhs, RValue rhs); RValue operator>(RValue lhs, RValue rhs); RValue operator>=(RValue lhs, RValue rhs); RValue operator!=(RValue lhs, RValue rhs); RValue operator==(RValue lhs, RValue rhs); class SByte : public LValue { public: SByte(Argument argument); explicit SByte(RValue cast); explicit SByte(RValue cast); SByte() = default; SByte(signed char x); SByte(RValue rhs); SByte(const SByte &rhs); SByte(const Reference &rhs); // RValue operator=(signed char rhs); // FIXME: Implement RValue operator=(RValue rhs); RValue operator=(const SByte &rhs); RValue operator=(const Reference &rhs); static Type *type(); }; RValue operator+(RValue lhs, RValue rhs); RValue operator-(RValue lhs, RValue rhs); RValue operator*(RValue lhs, RValue rhs); RValue operator/(RValue lhs, RValue rhs); RValue operator%(RValue lhs, RValue rhs); RValue operator&(RValue lhs, RValue rhs); RValue operator|(RValue lhs, RValue rhs); RValue operator^(RValue lhs, RValue rhs); RValue operator<<(RValue lhs, RValue rhs); RValue operator>>(RValue lhs, RValue rhs); RValue operator+=(SByte &lhs, RValue rhs); RValue operator-=(SByte &lhs, RValue rhs); RValue operator*=(SByte &lhs, RValue rhs); RValue operator/=(SByte &lhs, RValue rhs); RValue operator%=(SByte &lhs, RValue rhs); RValue operator&=(SByte &lhs, RValue rhs); RValue operator|=(SByte &lhs, RValue rhs); RValue operator^=(SByte &lhs, RValue rhs); RValue operator<<=(SByte &lhs, RValue rhs); RValue operator>>=(SByte &lhs, RValue rhs); RValue operator+(RValue val); RValue operator-(RValue val); RValue operator~(RValue val); RValue operator++(SByte &val, int); // Post-increment const SByte &operator++(SByte &val); // Pre-increment RValue operator--(SByte &val, int); // Post-decrement const SByte &operator--(SByte &val); // Pre-decrement RValue operator<(RValue lhs, RValue rhs); RValue operator<=(RValue lhs, RValue rhs); RValue operator>(RValue lhs, RValue rhs); RValue operator>=(RValue lhs, RValue rhs); RValue operator!=(RValue lhs, RValue rhs); RValue operator==(RValue lhs, RValue rhs); class Short : public LValue { public: Short(Argument argument); explicit Short(RValue cast); Short() = default; Short(short x); Short(RValue rhs); Short(const Short &rhs); Short(const Reference &rhs); // RValue operator=(short rhs); // FIXME: Implement RValue operator=(RValue rhs); RValue operator=(const Short &rhs); RValue operator=(const Reference &rhs); static Type *type(); }; RValue operator+(RValue lhs, RValue rhs); RValue operator-(RValue lhs, RValue rhs); RValue operator*(RValue lhs, RValue rhs); RValue operator/(RValue lhs, RValue rhs); RValue operator%(RValue lhs, RValue rhs); RValue operator&(RValue lhs, RValue rhs); RValue operator|(RValue lhs, RValue rhs); RValue operator^(RValue lhs, RValue rhs); RValue operator<<(RValue lhs, RValue rhs); RValue operator>>(RValue lhs, RValue rhs); RValue operator+=(Short &lhs, RValue rhs); RValue operator-=(Short &lhs, RValue rhs); RValue operator*=(Short &lhs, RValue rhs); RValue operator/=(Short &lhs, RValue rhs); RValue operator%=(Short &lhs, RValue rhs); RValue operator&=(Short &lhs, RValue rhs); RValue operator|=(Short &lhs, RValue rhs); RValue operator^=(Short &lhs, RValue rhs); RValue operator<<=(Short &lhs, RValue rhs); RValue operator>>=(Short &lhs, RValue rhs); RValue operator+(RValue val); RValue operator-(RValue val); RValue operator~(RValue val); RValue operator++(Short &val, int); // Post-increment const Short &operator++(Short &val); // Pre-increment RValue operator--(Short &val, int); // Post-decrement const Short &operator--(Short &val); // Pre-decrement RValue operator<(RValue lhs, RValue rhs); RValue operator<=(RValue lhs, RValue rhs); RValue operator>(RValue lhs, RValue rhs); RValue operator>=(RValue lhs, RValue rhs); RValue operator!=(RValue lhs, RValue rhs); RValue operator==(RValue lhs, RValue rhs); class UShort : public LValue { public: UShort(Argument argument); explicit UShort(RValue cast); explicit UShort(RValue cast); explicit UShort(RValue cast); UShort() = default; UShort(unsigned short x); UShort(RValue rhs); UShort(const UShort &rhs); UShort(const Reference &rhs); // RValue operator=(unsigned short rhs); // FIXME: Implement RValue operator=(RValue rhs); RValue operator=(const UShort &rhs); RValue operator=(const Reference &rhs); static Type *type(); }; RValue operator+(RValue lhs, RValue rhs); RValue operator-(RValue lhs, RValue rhs); RValue operator*(RValue lhs, RValue rhs); RValue operator/(RValue lhs, RValue rhs); RValue operator%(RValue lhs, RValue rhs); RValue operator&(RValue lhs, RValue rhs); RValue operator|(RValue lhs, RValue rhs); RValue operator^(RValue lhs, RValue rhs); RValue operator<<(RValue lhs, RValue rhs); RValue operator>>(RValue lhs, RValue rhs); RValue operator+=(UShort &lhs, RValue rhs); RValue operator-=(UShort &lhs, RValue rhs); RValue operator*=(UShort &lhs, RValue rhs); RValue operator/=(UShort &lhs, RValue rhs); RValue operator%=(UShort &lhs, RValue rhs); RValue operator&=(UShort &lhs, RValue rhs); RValue operator|=(UShort &lhs, RValue rhs); RValue operator^=(UShort &lhs, RValue rhs); RValue operator<<=(UShort &lhs, RValue rhs); RValue operator>>=(UShort &lhs, RValue rhs); RValue operator+(RValue val); RValue operator-(RValue val); RValue operator~(RValue val); RValue operator++(UShort &val, int); // Post-increment const UShort &operator++(UShort &val); // Pre-increment RValue operator--(UShort &val, int); // Post-decrement const UShort &operator--(UShort &val); // Pre-decrement RValue operator<(RValue lhs, RValue rhs); RValue operator<=(RValue lhs, RValue rhs); RValue operator>(RValue lhs, RValue rhs); RValue operator>=(RValue lhs, RValue rhs); RValue operator!=(RValue lhs, RValue rhs); RValue operator==(RValue lhs, RValue rhs); class Byte4 : public LValue { public: explicit Byte4(RValue cast); explicit Byte4(RValue cast); explicit Byte4(RValue cast); explicit Byte4(RValue cast); explicit Byte4(RValue cast); Byte4() = default; // Byte4(int x, int y, int z, int w); Byte4(RValue rhs); Byte4(const Byte4 &rhs); Byte4(const Reference &rhs); RValue operator=(RValue rhs); RValue operator=(const Byte4 &rhs); // RValue operator=(const Reference &rhs); static Type *type(); static int element_count() { return 4; } }; RValue Insert(RValue val, RValue element, int i); // RValue operator+(RValue lhs, RValue rhs); // RValue operator-(RValue lhs, RValue rhs); // RValue operator*(RValue lhs, RValue rhs); // RValue operator/(RValue lhs, RValue rhs); // RValue operator%(RValue lhs, RValue rhs); // RValue operator&(RValue lhs, RValue rhs); // RValue operator|(RValue lhs, RValue rhs); // RValue operator^(RValue lhs, RValue rhs); // RValue operator<<(RValue lhs, RValue rhs); // RValue operator>>(RValue lhs, RValue rhs); // RValue operator+=(Byte4 &lhs, RValue rhs); // RValue operator-=(Byte4 &lhs, RValue rhs); // RValue operator*=(Byte4 &lhs, RValue rhs); // RValue operator/=(Byte4 &lhs, RValue rhs); // RValue operator%=(Byte4 &lhs, RValue rhs); // RValue operator&=(Byte4 &lhs, RValue rhs); // RValue operator|=(Byte4 &lhs, RValue rhs); // RValue operator^=(Byte4 &lhs, RValue rhs); // RValue operator<<=(Byte4 &lhs, RValue rhs); // RValue operator>>=(Byte4 &lhs, RValue rhs); // RValue operator+(RValue val); // RValue operator-(RValue val); // RValue operator~(RValue val); // RValue operator++(Byte4 &val, int); // Post-increment // const Byte4 &operator++(Byte4 &val); // Pre-increment // RValue operator--(Byte4 &val, int); // Post-decrement // const Byte4 &operator--(Byte4 &val); // Pre-decrement class SByte4 : public LValue { public: SByte4() = default; // SByte4(int x, int y, int z, int w); // SByte4(RValue rhs); // SByte4(const SByte4 &rhs); // SByte4(const Reference &rhs); // RValue operator=(RValue rhs); // RValue operator=(const SByte4 &rhs); // RValue operator=(const Reference &rhs); static Type *type(); static int element_count() { return 4; } }; // RValue operator+(RValue lhs, RValue rhs); // RValue operator-(RValue lhs, RValue rhs); // RValue operator*(RValue lhs, RValue rhs); // RValue operator/(RValue lhs, RValue rhs); // RValue operator%(RValue lhs, RValue rhs); // RValue operator&(RValue lhs, RValue rhs); // RValue operator|(RValue lhs, RValue rhs); // RValue operator^(RValue lhs, RValue rhs); // RValue operator<<(RValue lhs, RValue rhs); // RValue operator>>(RValue lhs, RValue rhs); // RValue operator+=(SByte4 &lhs, RValue rhs); // RValue operator-=(SByte4 &lhs, RValue rhs); // RValue operator*=(SByte4 &lhs, RValue rhs); // RValue operator/=(SByte4 &lhs, RValue rhs); // RValue operator%=(SByte4 &lhs, RValue rhs); // RValue operator&=(SByte4 &lhs, RValue rhs); // RValue operator|=(SByte4 &lhs, RValue rhs); // RValue operator^=(SByte4 &lhs, RValue rhs); // RValue operator<<=(SByte4 &lhs, RValue rhs); // RValue operator>>=(SByte4 &lhs, RValue rhs); // RValue operator+(RValue val); // RValue operator-(RValue val); // RValue operator~(RValue val); // RValue operator++(SByte4 &val, int); // Post-increment // const SByte4 &operator++(SByte4 &val); // Pre-increment // RValue operator--(SByte4 &val, int); // Post-decrement // const SByte4 &operator--(SByte4 &val); // Pre-decrement class Byte8 : public LValue { public: Byte8() = default; Byte8(uint8_t x0, uint8_t x1, uint8_t x2, uint8_t x3, uint8_t x4, uint8_t x5, uint8_t x6, uint8_t x7); Byte8(RValue rhs); Byte8(const Byte8 &rhs); Byte8(const Reference &rhs); RValue operator=(RValue rhs); RValue operator=(const Byte8 &rhs); RValue operator=(const Reference &rhs); static Type *type(); static int element_count() { return 8; } }; RValue operator+(RValue lhs, RValue rhs); RValue operator-(RValue lhs, RValue rhs); // RValue operator*(RValue lhs, RValue rhs); // RValue operator/(RValue lhs, RValue rhs); // RValue operator%(RValue lhs, RValue rhs); RValue operator&(RValue lhs, RValue rhs); RValue operator|(RValue lhs, RValue rhs); RValue operator^(RValue lhs, RValue rhs); // RValue operator<<(RValue lhs, RValue rhs); // RValue operator>>(RValue lhs, RValue rhs); RValue operator+=(Byte8 &lhs, RValue rhs); RValue operator-=(Byte8 &lhs, RValue rhs); // RValue operator*=(Byte8 &lhs, RValue rhs); // RValue operator/=(Byte8 &lhs, RValue rhs); // RValue operator%=(Byte8 &lhs, RValue rhs); RValue operator&=(Byte8 &lhs, RValue rhs); RValue operator|=(Byte8 &lhs, RValue rhs); RValue operator^=(Byte8 &lhs, RValue rhs); // RValue operator<<=(Byte8 &lhs, RValue rhs); // RValue operator>>=(Byte8 &lhs, RValue rhs); // RValue operator+(RValue val); // RValue operator-(RValue val); RValue operator~(RValue val); // RValue operator++(Byte8 &val, int); // Post-increment // const Byte8 &operator++(Byte8 &val); // Pre-increment // RValue operator--(Byte8 &val, int); // Post-decrement // const Byte8 &operator--(Byte8 &val); // Pre-decrement RValue AddSat(RValue x, RValue y); RValue SubSat(RValue x, RValue y); RValue Unpack(RValue x); RValue Unpack(RValue x, RValue y); RValue UnpackLow(RValue x, RValue y); RValue UnpackHigh(RValue x, RValue y); RValue SignMask(RValue x); // RValue CmpGT(RValue x, RValue y); RValue CmpEQ(RValue x, RValue y); RValue Swizzle(RValue x, uint32_t select); class SByte8 : public LValue { public: SByte8() = default; SByte8(uint8_t x0, uint8_t x1, uint8_t x2, uint8_t x3, uint8_t x4, uint8_t x5, uint8_t x6, uint8_t x7); SByte8(RValue rhs); SByte8(const SByte8 &rhs); SByte8(const Reference &rhs); RValue operator=(RValue rhs); RValue operator=(const SByte8 &rhs); RValue operator=(const Reference &rhs); static Type *type(); static int element_count() { return 8; } }; RValue operator+(RValue lhs, RValue rhs); RValue operator-(RValue lhs, RValue rhs); // RValue operator*(RValue lhs, RValue rhs); // RValue operator/(RValue lhs, RValue rhs); // RValue operator%(RValue lhs, RValue rhs); RValue operator&(RValue lhs, RValue rhs); RValue operator|(RValue lhs, RValue rhs); RValue operator^(RValue lhs, RValue rhs); // RValue operator<<(RValue lhs, RValue rhs); // RValue operator>>(RValue lhs, RValue rhs); RValue operator+=(SByte8 &lhs, RValue rhs); RValue operator-=(SByte8 &lhs, RValue rhs); // RValue operator*=(SByte8 &lhs, RValue rhs); // RValue operator/=(SByte8 &lhs, RValue rhs); // RValue operator%=(SByte8 &lhs, RValue rhs); RValue operator&=(SByte8 &lhs, RValue rhs); RValue operator|=(SByte8 &lhs, RValue rhs); RValue operator^=(SByte8 &lhs, RValue rhs); // RValue operator<<=(SByte8 &lhs, RValue rhs); // RValue operator>>=(SByte8 &lhs, RValue rhs); // RValue operator+(RValue val); // RValue operator-(RValue val); RValue operator~(RValue val); // RValue operator++(SByte8 &val, int); // Post-increment // const SByte8 &operator++(SByte8 &val); // Pre-increment // RValue operator--(SByte8 &val, int); // Post-decrement // const SByte8 &operator--(SByte8 &val); // Pre-decrement RValue AddSat(RValue x, RValue y); RValue SubSat(RValue x, RValue y); RValue UnpackLow(RValue x, RValue y); RValue UnpackHigh(RValue x, RValue y); RValue SignMask(RValue x); RValue CmpGT(RValue x, RValue y); RValue CmpEQ(RValue x, RValue y); class Byte16 : public LValue { public: Byte16() = default; Byte16(RValue rhs); Byte16(const Byte16 &rhs); Byte16(const Reference &rhs); RValue operator=(RValue rhs); RValue operator=(const Byte16 &rhs); RValue operator=(const Reference &rhs); static Type *type(); static int element_count() { return 16; } }; // RValue operator+(RValue lhs, RValue rhs); // RValue operator-(RValue lhs, RValue rhs); // RValue operator*(RValue lhs, RValue rhs); // RValue operator/(RValue lhs, RValue rhs); // RValue operator%(RValue lhs, RValue rhs); // RValue operator&(RValue lhs, RValue rhs); // RValue operator|(RValue lhs, RValue rhs); // RValue operator^(RValue lhs, RValue rhs); // RValue operator<<(RValue lhs, RValue rhs); // RValue operator>>(RValue lhs, RValue rhs); // RValue operator+=(Byte16 &lhs, RValue rhs); // RValue operator-=(Byte16 &lhs, RValue rhs); // RValue operator*=(Byte16 &lhs, RValue rhs); // RValue operator/=(Byte16 &lhs, RValue rhs); // RValue operator%=(Byte16 &lhs, RValue rhs); // RValue operator&=(Byte16 &lhs, RValue rhs); // RValue operator|=(Byte16 &lhs, RValue rhs); // RValue operator^=(Byte16 &lhs, RValue rhs); // RValue operator<<=(Byte16 &lhs, RValue rhs); // RValue operator>>=(Byte16 &lhs, RValue rhs); // RValue operator+(RValue val); // RValue operator-(RValue val); // RValue operator~(RValue val); // RValue operator++(Byte16 &val, int); // Post-increment // const Byte16 &operator++(Byte16 &val); // Pre-increment // RValue operator--(Byte16 &val, int); // Post-decrement // const Byte16 &operator--(Byte16 &val); // Pre-decrement RValue Swizzle(RValue x, uint64_t select); class SByte16 : public LValue { public: SByte16() = default; // SByte16(int x, int y, int z, int w); // SByte16(RValue rhs); // SByte16(const SByte16 &rhs); // SByte16(const Reference &rhs); // RValue operator=(RValue rhs); // RValue operator=(const SByte16 &rhs); // RValue operator=(const Reference &rhs); static Type *type(); static int element_count() { return 16; } }; // RValue operator+(RValue lhs, RValue rhs); // RValue operator-(RValue lhs, RValue rhs); // RValue operator*(RValue lhs, RValue rhs); // RValue operator/(RValue lhs, RValue rhs); // RValue operator%(RValue lhs, RValue rhs); // RValue operator&(RValue lhs, RValue rhs); // RValue operator|(RValue lhs, RValue rhs); // RValue operator^(RValue lhs, RValue rhs); // RValue operator<<(RValue lhs, RValue rhs); // RValue operator>>(RValue lhs, RValue rhs); // RValue operator+=(SByte16 &lhs, RValue rhs); // RValue operator-=(SByte16 &lhs, RValue rhs); // RValue operator*=(SByte16 &lhs, RValue rhs); // RValue operator/=(SByte16 &lhs, RValue rhs); // RValue operator%=(SByte16 &lhs, RValue rhs); // RValue operator&=(SByte16 &lhs, RValue rhs); // RValue operator|=(SByte16 &lhs, RValue rhs); // RValue operator^=(SByte16 &lhs, RValue rhs); // RValue operator<<=(SByte16 &lhs, RValue rhs); // RValue operator>>=(SByte16 &lhs, RValue rhs); // RValue operator+(RValue val); // RValue operator-(RValue val); // RValue operator~(RValue val); // RValue operator++(SByte16 &val, int); // Post-increment // const SByte16 &operator++(SByte16 &val); // Pre-increment // RValue operator--(SByte16 &val, int); // Post-decrement // const SByte16 &operator--(SByte16 &val); // Pre-decrement class Short2 : public LValue { public: explicit Short2(RValue cast); static Type *type(); static int element_count() { return 2; } }; class UShort2 : public LValue { public: explicit UShort2(RValue cast); static Type *type(); static int element_count() { return 2; } }; class Short4 : public LValue { public: explicit Short4(RValue cast); explicit Short4(RValue cast); explicit Short4(RValue cast); // explicit Short4(RValue cast); explicit Short4(RValue cast); Short4() = default; Short4(short xyzw); Short4(short x, short y, short z, short w); Short4(RValue rhs); Short4(const Short4 &rhs); Short4(const Reference &rhs); Short4(RValue rhs); Short4(const UShort4 &rhs); Short4(const Reference &rhs); RValue operator=(RValue rhs); RValue operator=(const Short4 &rhs); RValue operator=(const Reference &rhs); RValue operator=(RValue rhs); RValue operator=(const UShort4 &rhs); RValue operator=(const Reference &rhs); static Type *type(); static int element_count() { return 4; } }; RValue operator+(RValue lhs, RValue rhs); RValue operator-(RValue lhs, RValue rhs); RValue operator*(RValue lhs, RValue rhs); // RValue operator/(RValue lhs, RValue rhs); // RValue operator%(RValue lhs, RValue rhs); RValue operator&(RValue lhs, RValue rhs); RValue operator|(RValue lhs, RValue rhs); RValue operator^(RValue lhs, RValue rhs); RValue operator<<(RValue lhs, unsigned char rhs); RValue operator>>(RValue lhs, unsigned char rhs); RValue operator+=(Short4 &lhs, RValue rhs); RValue operator-=(Short4 &lhs, RValue rhs); RValue operator*=(Short4 &lhs, RValue rhs); // RValue operator/=(Short4 &lhs, RValue rhs); // RValue operator%=(Short4 &lhs, RValue rhs); RValue operator&=(Short4 &lhs, RValue rhs); RValue operator|=(Short4 &lhs, RValue rhs); RValue operator^=(Short4 &lhs, RValue rhs); RValue operator<<=(Short4 &lhs, unsigned char rhs); RValue operator>>=(Short4 &lhs, unsigned char rhs); // RValue operator+(RValue val); RValue operator-(RValue val); RValue operator~(RValue val); // RValue operator++(Short4 &val, int); // Post-increment // const Short4 &operator++(Short4 &val); // Pre-increment // RValue operator--(Short4 &val, int); // Post-decrement // const Short4 &operator--(Short4 &val); // Pre-decrement // RValue operator<(RValue lhs, RValue rhs); // RValue operator<=(RValue lhs, RValue rhs); // RValue operator>(RValue lhs, RValue rhs); // RValue operator>=(RValue lhs, RValue rhs); // RValue operator!=(RValue lhs, RValue rhs); // RValue operator==(RValue lhs, RValue rhs); RValue RoundShort4(RValue cast); RValue Max(RValue x, RValue y); RValue Min(RValue x, RValue y); RValue AddSat(RValue x, RValue y); RValue SubSat(RValue x, RValue y); RValue MulHigh(RValue x, RValue y); RValue MulAdd(RValue x, RValue y); RValue PackSigned(RValue x, RValue y); RValue PackUnsigned(RValue x, RValue y); RValue UnpackLow(RValue x, RValue y); RValue UnpackHigh(RValue x, RValue y); RValue Swizzle(RValue x, uint16_t select); RValue Insert(RValue val, RValue element, int i); RValue Extract(RValue val, int i); RValue CmpGT(RValue x, RValue y); RValue CmpEQ(RValue x, RValue y); class UShort4 : public LValue { public: explicit UShort4(RValue cast); explicit UShort4(RValue cast); explicit UShort4(RValue cast, bool saturate = false); UShort4() = default; UShort4(unsigned short xyzw); UShort4(unsigned short x, unsigned short y, unsigned short z, unsigned short w); UShort4(RValue rhs); UShort4(const UShort4 &rhs); UShort4(const Reference &rhs); UShort4(RValue rhs); UShort4(const Short4 &rhs); UShort4(const Reference &rhs); RValue operator=(RValue rhs); RValue operator=(const UShort4 &rhs); RValue operator=(const Reference &rhs); RValue operator=(RValue rhs); RValue operator=(const Short4 &rhs); RValue operator=(const Reference &rhs); static Type *type(); static int element_count() { return 4; } }; RValue operator+(RValue lhs, RValue rhs); RValue operator-(RValue lhs, RValue rhs); RValue operator*(RValue lhs, RValue rhs); // RValue operator/(RValue lhs, RValue rhs); // RValue operator%(RValue lhs, RValue rhs); RValue operator&(RValue lhs, RValue rhs); RValue operator|(RValue lhs, RValue rhs); RValue operator^(RValue lhs, RValue rhs); RValue operator<<(RValue lhs, unsigned char rhs); RValue operator>>(RValue lhs, unsigned char rhs); // RValue operator+=(UShort4 &lhs, RValue rhs); // RValue operator-=(UShort4 &lhs, RValue rhs); // RValue operator*=(UShort4 &lhs, RValue rhs); // RValue operator/=(UShort4 &lhs, RValue rhs); // RValue operator%=(UShort4 &lhs, RValue rhs); // RValue operator&=(UShort4 &lhs, RValue rhs); // RValue operator|=(UShort4 &lhs, RValue rhs); // RValue operator^=(UShort4 &lhs, RValue rhs); RValue operator<<=(UShort4 &lhs, unsigned char rhs); RValue operator>>=(UShort4 &lhs, unsigned char rhs); // RValue operator+(RValue val); // RValue operator-(RValue val); RValue operator~(RValue val); // RValue operator++(UShort4 &val, int); // Post-increment // const UShort4 &operator++(UShort4 &val); // Pre-increment // RValue operator--(UShort4 &val, int); // Post-decrement // const UShort4 &operator--(UShort4 &val); // Pre-decrement RValue Insert(RValue val, RValue element, int i); RValue Max(RValue x, RValue y); RValue Min(RValue x, RValue y); RValue AddSat(RValue x, RValue y); RValue SubSat(RValue x, RValue y); RValue MulHigh(RValue x, RValue y); RValue Average(RValue x, RValue y); class Short8 : public LValue { public: Short8() = default; Short8(short c); Short8(short c0, short c1, short c2, short c3, short c4, short c5, short c6, short c7); Short8(RValue rhs); // Short8(const Short8 &rhs); Short8(const Reference &rhs); Short8(RValue lo, RValue hi); RValue operator=(RValue rhs); RValue operator=(const Short8 &rhs); RValue operator=(const Reference &rhs); static Type *type(); static int element_count() { return 8; } }; RValue operator+(RValue lhs, RValue rhs); // RValue operator-(RValue lhs, RValue rhs); // RValue operator*(RValue lhs, RValue rhs); // RValue operator/(RValue lhs, RValue rhs); // RValue operator%(RValue lhs, RValue rhs); RValue operator&(RValue lhs, RValue rhs); // RValue operator|(RValue lhs, RValue rhs); // RValue operator^(RValue lhs, RValue rhs); RValue operator<<(RValue lhs, unsigned char rhs); RValue operator>>(RValue lhs, unsigned char rhs); // RValue operator<<(RValue lhs, RValue rhs); // RValue operator>>(RValue lhs, RValue rhs); // RValue operator+=(Short8 &lhs, RValue rhs); // RValue operator-=(Short8 &lhs, RValue rhs); // RValue operator*=(Short8 &lhs, RValue rhs); // RValue operator/=(Short8 &lhs, RValue rhs); // RValue operator%=(Short8 &lhs, RValue rhs); // RValue operator&=(Short8 &lhs, RValue rhs); // RValue operator|=(Short8 &lhs, RValue rhs); // RValue operator^=(Short8 &lhs, RValue rhs); // RValue operator<<=(Short8 &lhs, RValue rhs); // RValue operator>>=(Short8 &lhs, RValue rhs); // RValue operator+(RValue val); // RValue operator-(RValue val); // RValue operator~(RValue val); // RValue operator++(Short8 &val, int); // Post-increment // const Short8 &operator++(Short8 &val); // Pre-increment // RValue operator--(Short8 &val, int); // Post-decrement // const Short8 &operator--(Short8 &val); // Pre-decrement // RValue operator<(RValue lhs, RValue rhs); // RValue operator<=(RValue lhs, RValue rhs); // RValue operator>(RValue lhs, RValue rhs); // RValue operator>=(RValue lhs, RValue rhs); // RValue operator!=(RValue lhs, RValue rhs); // RValue operator==(RValue lhs, RValue rhs); RValue MulHigh(RValue x, RValue y); RValue MulAdd(RValue x, RValue y); class UShort8 : public LValue { public: UShort8() = default; UShort8(unsigned short c); UShort8(unsigned short c0, unsigned short c1, unsigned short c2, unsigned short c3, unsigned short c4, unsigned short c5, unsigned short c6, unsigned short c7); UShort8(RValue rhs); // UShort8(const UShort8 &rhs); UShort8(const Reference &rhs); UShort8(RValue lo, RValue hi); RValue operator=(RValue rhs); RValue operator=(const UShort8 &rhs); RValue operator=(const Reference &rhs); static Type *type(); static int element_count() { return 8; } }; RValue operator+(RValue lhs, RValue rhs); // RValue operator-(RValue lhs, RValue rhs); RValue operator*(RValue lhs, RValue rhs); // RValue operator/(RValue lhs, RValue rhs); // RValue operator%(RValue lhs, RValue rhs); RValue operator&(RValue lhs, RValue rhs); // RValue operator|(RValue lhs, RValue rhs); // RValue operator^(RValue lhs, RValue rhs); RValue operator<<(RValue lhs, unsigned char rhs); RValue operator>>(RValue lhs, unsigned char rhs); // RValue operator<<(RValue lhs, RValue rhs); // RValue operator>>(RValue lhs, RValue rhs); RValue operator+=(UShort8 &lhs, RValue rhs); // RValue operator-=(UShort8 &lhs, RValue rhs); // RValue operator*=(UShort8 &lhs, RValue rhs); // RValue operator/=(UShort8 &lhs, RValue rhs); // RValue operator%=(UShort8 &lhs, RValue rhs); // RValue operator&=(UShort8 &lhs, RValue rhs); // RValue operator|=(UShort8 &lhs, RValue rhs); // RValue operator^=(UShort8 &lhs, RValue rhs); // RValue operator<<=(UShort8 &lhs, RValue rhs); // RValue operator>>=(UShort8 &lhs, RValue rhs); // RValue operator+(RValue val); // RValue operator-(RValue val); RValue operator~(RValue val); // RValue operator++(UShort8 &val, int); // Post-increment // const UShort8 &operator++(UShort8 &val); // Pre-increment // RValue operator--(UShort8 &val, int); // Post-decrement // const UShort8 &operator--(UShort8 &val); // Pre-decrement // RValue operator<(RValue lhs, RValue rhs); // RValue operator<=(RValue lhs, RValue rhs); // RValue operator>(RValue lhs, RValue rhs); // RValue operator>=(RValue lhs, RValue rhs); // RValue operator!=(RValue lhs, RValue rhs); // RValue operator==(RValue lhs, RValue rhs); RValue Swizzle(RValue x, uint32_t select); RValue MulHigh(RValue x, RValue y); class Int : public LValue { public: Int(Argument argument); explicit Int(RValue cast); explicit Int(RValue cast); explicit Int(RValue cast); explicit Int(RValue cast); explicit Int(RValue cast); explicit Int(RValue cast); explicit Int(RValue cast); Int() = default; Int(int x); Int(RValue rhs); Int(RValue rhs); Int(const Int &rhs); Int(const UInt &rhs); Int(const Reference &rhs); Int(const Reference &rhs); template Int(const SwizzleMask1 &rhs); RValue operator=(int rhs); RValue operator=(RValue rhs); RValue operator=(RValue rhs); RValue operator=(const Int &rhs); RValue operator=(const UInt &rhs); RValue operator=(const Reference &rhs); RValue operator=(const Reference &rhs); template RValue operator=(const SwizzleMask1 &rhs); static Type *type(); }; RValue operator+(RValue lhs, RValue rhs); RValue operator-(RValue lhs, RValue rhs); RValue operator*(RValue lhs, RValue rhs); RValue operator/(RValue lhs, RValue rhs); RValue operator%(RValue lhs, RValue rhs); RValue operator&(RValue lhs, RValue rhs); RValue operator|(RValue lhs, RValue rhs); RValue operator^(RValue lhs, RValue rhs); RValue operator<<(RValue lhs, RValue rhs); RValue operator>>(RValue lhs, RValue rhs); RValue operator+=(Int &lhs, RValue rhs); RValue operator-=(Int &lhs, RValue rhs); RValue operator*=(Int &lhs, RValue rhs); RValue operator/=(Int &lhs, RValue rhs); RValue operator%=(Int &lhs, RValue rhs); RValue operator&=(Int &lhs, RValue rhs); RValue operator|=(Int &lhs, RValue rhs); RValue operator^=(Int &lhs, RValue rhs); RValue operator<<=(Int &lhs, RValue rhs); RValue operator>>=(Int &lhs, RValue rhs); RValue operator+(RValue val); RValue operator-(RValue val); RValue operator~(RValue val); RValue operator++(Int &val, int); // Post-increment const Int &operator++(Int &val); // Pre-increment RValue operator--(Int &val, int); // Post-decrement const Int &operator--(Int &val); // Pre-decrement RValue operator<(RValue lhs, RValue rhs); RValue operator<=(RValue lhs, RValue rhs); RValue operator>(RValue lhs, RValue rhs); RValue operator>=(RValue lhs, RValue rhs); RValue operator!=(RValue lhs, RValue rhs); RValue operator==(RValue lhs, RValue rhs); RValue Max(RValue x, RValue y); RValue Min(RValue x, RValue y); RValue Clamp(RValue x, RValue min, RValue max); RValue RoundInt(RValue cast); class Long : public LValue { public: // Long(Argument argument); // explicit Long(RValue cast); // explicit Long(RValue cast); explicit Long(RValue cast); explicit Long(RValue cast); // explicit Long(RValue cast); Long() = default; // Long(qword x); Long(RValue rhs); // Long(RValue rhs); // Long(const Long &rhs); // Long(const Reference &rhs); // Long(const ULong &rhs); // Long(const Reference &rhs); RValue operator=(int64_t rhs); RValue operator=(RValue rhs); // RValue operator=(RValue rhs); RValue operator=(const Long &rhs); RValue operator=(const Reference &rhs); // RValue operator=(const ULong &rhs); // RValue operator=(const Reference &rhs); static Type *type(); }; RValue operator+(RValue lhs, RValue rhs); RValue operator-(RValue lhs, RValue rhs); RValue operator*(RValue lhs, RValue rhs); // RValue operator/(RValue lhs, RValue rhs); // RValue operator%(RValue lhs, RValue rhs); // RValue operator&(RValue lhs, RValue rhs); // RValue operator|(RValue lhs, RValue rhs); // RValue operator^(RValue lhs, RValue rhs); // RValue operator<<(RValue lhs, RValue rhs); RValue operator>>(RValue lhs, RValue rhs); RValue operator+=(Long &lhs, RValue rhs); RValue operator-=(Long &lhs, RValue rhs); // RValue operator*=(Long &lhs, RValue rhs); // RValue operator/=(Long &lhs, RValue rhs); // RValue operator%=(Long &lhs, RValue rhs); // RValue operator&=(Long &lhs, RValue rhs); // RValue operator|=(Long &lhs, RValue rhs); // RValue operator^=(Long &lhs, RValue rhs); // RValue operator<<=(Long &lhs, RValue rhs); // RValue operator>>=(Long &lhs, RValue rhs); // RValue operator+(RValue val); // RValue operator-(RValue val); // RValue operator~(RValue val); // RValue operator++(Long &val, int); // Post-increment // const Long &operator++(Long &val); // Pre-increment // RValue operator--(Long &val, int); // Post-decrement // const Long &operator--(Long &val); // Pre-decrement // RValue operator<(RValue lhs, RValue rhs); // RValue operator<=(RValue lhs, RValue rhs); // RValue operator>(RValue lhs, RValue rhs); // RValue operator>=(RValue lhs, RValue rhs); // RValue operator!=(RValue lhs, RValue rhs); // RValue operator==(RValue lhs, RValue rhs); // RValue RoundLong(RValue cast); RValue AddAtomic(RValue> x, RValue y); class UInt : public LValue { public: UInt(Argument argument); explicit UInt(RValue cast); explicit UInt(RValue cast); explicit UInt(RValue cast); UInt() = default; UInt(int x); UInt(unsigned int x); UInt(RValue rhs); UInt(RValue rhs); UInt(const UInt &rhs); UInt(const Int &rhs); UInt(const Reference &rhs); UInt(const Reference &rhs); RValue operator=(unsigned int rhs); RValue operator=(RValue rhs); RValue operator=(RValue rhs); RValue operator=(const UInt &rhs); RValue operator=(const Int &rhs); RValue operator=(const Reference &rhs); RValue operator=(const Reference &rhs); static Type *type(); }; RValue operator+(RValue lhs, RValue rhs); RValue operator-(RValue lhs, RValue rhs); RValue operator*(RValue lhs, RValue rhs); RValue operator/(RValue lhs, RValue rhs); RValue operator%(RValue lhs, RValue rhs); RValue operator&(RValue lhs, RValue rhs); RValue operator|(RValue lhs, RValue rhs); RValue operator^(RValue lhs, RValue rhs); RValue operator<<(RValue lhs, RValue rhs); RValue operator>>(RValue lhs, RValue rhs); RValue operator+=(UInt &lhs, RValue rhs); RValue operator-=(UInt &lhs, RValue rhs); RValue operator*=(UInt &lhs, RValue rhs); RValue operator/=(UInt &lhs, RValue rhs); RValue operator%=(UInt &lhs, RValue rhs); RValue operator&=(UInt &lhs, RValue rhs); RValue operator|=(UInt &lhs, RValue rhs); RValue operator^=(UInt &lhs, RValue rhs); RValue operator<<=(UInt &lhs, RValue rhs); RValue operator>>=(UInt &lhs, RValue rhs); RValue operator+(RValue val); RValue operator-(RValue val); RValue operator~(RValue val); RValue operator++(UInt &val, int); // Post-increment const UInt &operator++(UInt &val); // Pre-increment RValue operator--(UInt &val, int); // Post-decrement const UInt &operator--(UInt &val); // Pre-decrement RValue operator<(RValue lhs, RValue rhs); RValue operator<=(RValue lhs, RValue rhs); RValue operator>(RValue lhs, RValue rhs); RValue operator>=(RValue lhs, RValue rhs); RValue operator!=(RValue lhs, RValue rhs); RValue operator==(RValue lhs, RValue rhs); RValue Max(RValue x, RValue y); RValue Min(RValue x, RValue y); RValue Clamp(RValue x, RValue min, RValue max); RValue AddAtomic(RValue> x, RValue y, std::memory_order memoryOrder); RValue SubAtomic(RValue> x, RValue y, std::memory_order memoryOrder); RValue AndAtomic(RValue> x, RValue y, std::memory_order memoryOrder); RValue OrAtomic(RValue> x, RValue y, std::memory_order memoryOrder); RValue XorAtomic(RValue> x, RValue y, std::memory_order memoryOrder); RValue MinAtomic(RValue> x, RValue y, std::memory_order memoryOrder); RValue MaxAtomic(RValue> x, RValue y, std::memory_order memoryOrder); RValue MinAtomic(RValue> x, RValue y, std::memory_order memoryOrder); RValue MaxAtomic(RValue> x, RValue y, std::memory_order memoryOrder); RValue ExchangeAtomic(RValue> x, RValue y, std::memory_order memoryOrder); RValue CompareExchangeAtomic(RValue> x, RValue y, RValue compare, std::memory_order memoryOrderEqual, std::memory_order memoryOrderUnequal); // RValue RoundUInt(RValue cast); class Int2 : public LValue { public: // explicit Int2(RValue cast); explicit Int2(RValue cast); Int2() = default; Int2(int x, int y); Int2(RValue rhs); Int2(const Int2 &rhs); Int2(const Reference &rhs); Int2(RValue lo, RValue hi); RValue operator=(RValue rhs); RValue operator=(const Int2 &rhs); RValue operator=(const Reference &rhs); static Type *type(); static int element_count() { return 2; } }; RValue operator+(RValue lhs, RValue rhs); RValue operator-(RValue lhs, RValue rhs); // RValue operator*(RValue lhs, RValue rhs); // RValue operator/(RValue lhs, RValue rhs); // RValue operator%(RValue lhs, RValue rhs); RValue operator&(RValue lhs, RValue rhs); RValue operator|(RValue lhs, RValue rhs); RValue operator^(RValue lhs, RValue rhs); RValue operator<<(RValue lhs, unsigned char rhs); RValue operator>>(RValue lhs, unsigned char rhs); RValue operator+=(Int2 &lhs, RValue rhs); RValue operator-=(Int2 &lhs, RValue rhs); // RValue operator*=(Int2 &lhs, RValue rhs); // RValue operator/=(Int2 &lhs, RValue rhs); // RValue operator%=(Int2 &lhs, RValue rhs); RValue operator&=(Int2 &lhs, RValue rhs); RValue operator|=(Int2 &lhs, RValue rhs); RValue operator^=(Int2 &lhs, RValue rhs); RValue operator<<=(Int2 &lhs, unsigned char rhs); RValue operator>>=(Int2 &lhs, unsigned char rhs); // RValue operator+(RValue val); // RValue operator-(RValue val); RValue operator~(RValue val); // RValue operator++(Int2 &val, int); // Post-increment // const Int2 &operator++(Int2 &val); // Pre-increment // RValue operator--(Int2 &val, int); // Post-decrement // const Int2 &operator--(Int2 &val); // Pre-decrement // RValue operator<(RValue lhs, RValue rhs); // RValue operator<=(RValue lhs, RValue rhs); // RValue operator>(RValue lhs, RValue rhs); // RValue operator>=(RValue lhs, RValue rhs); // RValue operator!=(RValue lhs, RValue rhs); // RValue operator==(RValue lhs, RValue rhs); // RValue RoundInt(RValue cast); RValue UnpackLow(RValue x, RValue y); RValue UnpackHigh(RValue x, RValue y); RValue Extract(RValue val, int i); RValue Insert(RValue val, RValue element, int i); class UInt2 : public LValue { public: UInt2() = default; UInt2(unsigned int x, unsigned int y); UInt2(RValue rhs); UInt2(const UInt2 &rhs); UInt2(const Reference &rhs); RValue operator=(RValue rhs); RValue operator=(const UInt2 &rhs); RValue operator=(const Reference &rhs); static Type *type(); static int element_count() { return 2; } }; RValue operator+(RValue lhs, RValue rhs); RValue operator-(RValue lhs, RValue rhs); // RValue operator*(RValue lhs, RValue rhs); // RValue operator/(RValue lhs, RValue rhs); // RValue operator%(RValue lhs, RValue rhs); RValue operator&(RValue lhs, RValue rhs); RValue operator|(RValue lhs, RValue rhs); RValue operator^(RValue lhs, RValue rhs); RValue operator<<(RValue lhs, unsigned char rhs); RValue operator>>(RValue lhs, unsigned char rhs); RValue operator+=(UInt2 &lhs, RValue rhs); RValue operator-=(UInt2 &lhs, RValue rhs); // RValue operator*=(UInt2 &lhs, RValue rhs); // RValue operator/=(UInt2 &lhs, RValue rhs); // RValue operator%=(UInt2 &lhs, RValue rhs); RValue operator&=(UInt2 &lhs, RValue rhs); RValue operator|=(UInt2 &lhs, RValue rhs); RValue operator^=(UInt2 &lhs, RValue rhs); RValue operator<<=(UInt2 &lhs, unsigned char rhs); RValue operator>>=(UInt2 &lhs, unsigned char rhs); // RValue operator+(RValue val); // RValue operator-(RValue val); RValue operator~(RValue val); // RValue operator++(UInt2 &val, int); // Post-increment // const UInt2 &operator++(UInt2 &val); // Pre-increment // RValue operator--(UInt2 &val, int); // Post-decrement // const UInt2 &operator--(UInt2 &val); // Pre-decrement // RValue operator<(RValue lhs, RValue rhs); // RValue operator<=(RValue lhs, RValue rhs); // RValue operator>(RValue lhs, RValue rhs); // RValue operator>=(RValue lhs, RValue rhs); // RValue operator!=(RValue lhs, RValue rhs); // RValue operator==(RValue lhs, RValue rhs); // RValue RoundInt(RValue cast); RValue Extract(RValue val, int i); RValue Insert(RValue val, RValue element, int i); class Int4 : public LValue, public XYZW { public: explicit Int4(RValue cast); explicit Int4(RValue cast); explicit Int4(RValue cast); explicit Int4(RValue cast); explicit Int4(RValue cast); Int4(); Int4(int xyzw); Int4(int x, int yzw); Int4(int x, int y, int zw); Int4(int x, int y, int z, int w); Int4(RValue rhs); Int4(const Int4 &rhs); Int4(const Reference &rhs); Int4(RValue rhs); Int4(const UInt4 &rhs); Int4(const Reference &rhs); Int4(RValue lo, RValue hi); Int4(RValue rhs); Int4(const Int &rhs); Int4(const Reference &rhs); template Int4(const SwizzleMask1 &rhs); RValue operator=(int broadcast); RValue operator=(RValue rhs); RValue operator=(const Int4 &rhs); RValue operator=(const Reference &rhs); static Type *type(); static int element_count() { return 4; } private: void constant(int x, int y, int z, int w); }; RValue operator+(RValue lhs, RValue rhs); RValue operator-(RValue lhs, RValue rhs); RValue operator*(RValue lhs, RValue rhs); RValue operator/(RValue lhs, RValue rhs); RValue operator%(RValue lhs, RValue rhs); RValue operator&(RValue lhs, RValue rhs); RValue operator|(RValue lhs, RValue rhs); RValue operator^(RValue lhs, RValue rhs); RValue operator<<(RValue lhs, unsigned char rhs); RValue operator>>(RValue lhs, unsigned char rhs); RValue operator<<(RValue lhs, RValue rhs); RValue operator>>(RValue lhs, RValue rhs); RValue operator+=(Int4 &lhs, RValue rhs); RValue operator-=(Int4 &lhs, RValue rhs); RValue operator*=(Int4 &lhs, RValue rhs); // RValue operator/=(Int4 &lhs, RValue rhs); // RValue operator%=(Int4 &lhs, RValue rhs); RValue operator&=(Int4 &lhs, RValue rhs); RValue operator|=(Int4 &lhs, RValue rhs); RValue operator^=(Int4 &lhs, RValue rhs); RValue operator<<=(Int4 &lhs, unsigned char rhs); RValue operator>>=(Int4 &lhs, unsigned char rhs); RValue operator+(RValue val); RValue operator-(RValue val); RValue operator~(RValue val); // RValue operator++(Int4 &val, int); // Post-increment // const Int4 &operator++(Int4 &val); // Pre-increment // RValue operator--(Int4 &val, int); // Post-decrement // const Int4 &operator--(Int4 &val); // Pre-decrement // RValue operator<(RValue lhs, RValue rhs); // RValue operator<=(RValue lhs, RValue rhs); // RValue operator>(RValue lhs, RValue rhs); // RValue operator>=(RValue lhs, RValue rhs); // RValue operator!=(RValue lhs, RValue rhs); // RValue operator==(RValue lhs, RValue rhs); RValue CmpEQ(RValue x, RValue y); RValue CmpLT(RValue x, RValue y); RValue CmpLE(RValue x, RValue y); RValue CmpNEQ(RValue x, RValue y); RValue CmpNLT(RValue x, RValue y); RValue CmpNLE(RValue x, RValue y); inline RValue CmpGT(RValue x, RValue y) { return CmpNLE(x, y); } inline RValue CmpGE(RValue x, RValue y) { return CmpNLT(x, y); } RValue Abs(RValue x); RValue Max(RValue x, RValue y); RValue Min(RValue x, RValue y); // Convert to nearest integer. If a converted value is outside of the integer // range, the returned result is undefined. RValue RoundInt(RValue cast); // Rounds to the nearest integer, but clamps very large values to an // implementation-dependent range. // Specifically, on x86, values larger than 2147483583.0 are converted to // 2147483583 (0x7FFFFFBF) instead of producing 0x80000000. RValue RoundIntClamped(RValue cast); RValue PackSigned(RValue x, RValue y); RValue PackUnsigned(RValue x, RValue y); RValue Extract(RValue val, int i); RValue Insert(RValue val, RValue element, int i); RValue SignMask(RValue x); RValue Swizzle(RValue x, uint16_t select); RValue Shuffle(RValue x, RValue y, uint16_t select); RValue MulHigh(RValue x, RValue y); class UInt4 : public LValue, public XYZW { public: explicit UInt4(RValue cast); UInt4(); UInt4(int xyzw); UInt4(int x, int yzw); UInt4(int x, int y, int zw); UInt4(int x, int y, int z, int w); UInt4(RValue rhs); UInt4(const UInt4 &rhs); UInt4(const Reference &rhs); UInt4(RValue rhs); UInt4(const Int4 &rhs); UInt4(const Reference &rhs); UInt4(RValue lo, RValue hi); UInt4(RValue rhs); UInt4(const UInt &rhs); UInt4(const Reference &rhs); RValue operator=(RValue rhs); RValue operator=(const UInt4 &rhs); RValue operator=(const Reference &rhs); static Type *type(); static int element_count() { return 4; } private: void constant(int x, int y, int z, int w); }; RValue operator+(RValue lhs, RValue rhs); RValue operator-(RValue lhs, RValue rhs); RValue operator*(RValue lhs, RValue rhs); RValue operator/(RValue lhs, RValue rhs); RValue operator%(RValue lhs, RValue rhs); RValue operator&(RValue lhs, RValue rhs); RValue operator|(RValue lhs, RValue rhs); RValue operator^(RValue lhs, RValue rhs); RValue operator<<(RValue lhs, unsigned char rhs); RValue operator>>(RValue lhs, unsigned char rhs); RValue operator<<(RValue lhs, RValue rhs); RValue operator>>(RValue lhs, RValue rhs); RValue operator+=(UInt4 &lhs, RValue rhs); RValue operator-=(UInt4 &lhs, RValue rhs); RValue operator*=(UInt4 &lhs, RValue rhs); // RValue operator/=(UInt4 &lhs, RValue rhs); // RValue operator%=(UInt4 &lhs, RValue rhs); RValue operator&=(UInt4 &lhs, RValue rhs); RValue operator|=(UInt4 &lhs, RValue rhs); RValue operator^=(UInt4 &lhs, RValue rhs); RValue operator<<=(UInt4 &lhs, unsigned char rhs); RValue operator>>=(UInt4 &lhs, unsigned char rhs); RValue operator+(RValue val); RValue operator-(RValue val); RValue operator~(RValue val); // RValue operator++(UInt4 &val, int); // Post-increment // const UInt4 &operator++(UInt4 &val); // Pre-increment // RValue operator--(UInt4 &val, int); // Post-decrement // const UInt4 &operator--(UInt4 &val); // Pre-decrement // RValue operator<(RValue lhs, RValue rhs); // RValue operator<=(RValue lhs, RValue rhs); // RValue operator>(RValue lhs, RValue rhs); // RValue operator>=(RValue lhs, RValue rhs); // RValue operator!=(RValue lhs, RValue rhs); // RValue operator==(RValue lhs, RValue rhs); RValue CmpEQ(RValue x, RValue y); RValue CmpLT(RValue x, RValue y); RValue CmpLE(RValue x, RValue y); RValue CmpNEQ(RValue x, RValue y); RValue CmpNLT(RValue x, RValue y); RValue CmpNLE(RValue x, RValue y); inline RValue CmpGT(RValue x, RValue y) { return CmpNLE(x, y); } inline RValue CmpGE(RValue x, RValue y) { return CmpNLT(x, y); } RValue Max(RValue x, RValue y); RValue Min(RValue x, RValue y); RValue MulHigh(RValue x, RValue y); RValue Extract(RValue val, int i); RValue Insert(RValue val, RValue element, int i); // RValue RoundInt(RValue cast); RValue Swizzle(RValue x, uint16_t select); RValue Shuffle(RValue x, RValue y, uint16_t select); class Half : public LValue { public: explicit Half(RValue cast); static Type *type(); }; class Float : public LValue { public: explicit Float(RValue cast); explicit Float(RValue cast); explicit Float(RValue cast); Float() = default; Float(float x); Float(RValue rhs); Float(const Float &rhs); Float(const Reference &rhs); Float(Argument argument); template Float(const SwizzleMask1 &rhs); RValue operator=(float rhs); RValue operator=(RValue rhs); RValue operator=(const Float &rhs); RValue operator=(const Reference &rhs); template RValue operator=(const SwizzleMask1 &rhs); static Float infinity(); static Type *type(); }; RValue operator+(RValue lhs, RValue rhs); RValue operator-(RValue lhs, RValue rhs); RValue operator*(RValue lhs, RValue rhs); RValue operator/(RValue lhs, RValue rhs); RValue operator+=(Float &lhs, RValue rhs); RValue operator-=(Float &lhs, RValue rhs); RValue operator*=(Float &lhs, RValue rhs); RValue operator/=(Float &lhs, RValue rhs); RValue operator+(RValue val); RValue operator-(RValue val); RValue operator<(RValue lhs, RValue rhs); RValue operator<=(RValue lhs, RValue rhs); RValue operator>(RValue lhs, RValue rhs); RValue operator>=(RValue lhs, RValue rhs); RValue operator!=(RValue lhs, RValue rhs); RValue operator==(RValue lhs, RValue rhs); RValue Abs(RValue x); RValue Max(RValue x, RValue y); RValue Min(RValue x, RValue y); RValue Rcp(RValue x, bool relaxedPrecision, bool exactAtPow2 = false); RValue RcpSqrt(RValue x, bool relaxedPrecision); RValue Sqrt(RValue x); // RValue IsInf(RValue x); // RValue IsNan(RValue x); RValue Round(RValue x); RValue Trunc(RValue x); RValue Frac(RValue x); RValue Floor(RValue x); RValue Ceil(RValue x); // Trigonometric functions // TODO: Currently unimplemented for Subzero. // RValue Sin(RValue x); // RValue Cos(RValue x); // RValue Tan(RValue x); // RValue Asin(RValue x); // RValue Acos(RValue x); // RValue Atan(RValue x); // RValue Sinh(RValue x); // RValue Cosh(RValue x); // RValue Tanh(RValue x); // RValue Asinh(RValue x); // RValue Acosh(RValue x); // RValue Atanh(RValue x); // RValue Atan2(RValue x, RValue y); // Exponential functions // TODO: Currently unimplemented for Subzero. // RValue Pow(RValue x, RValue y); // RValue Exp(RValue x); // RValue Log(RValue x); RValue Exp2(RValue x); RValue Log2(RValue x); class Float2 : public LValue { public: // explicit Float2(RValue cast); // explicit Float2(RValue cast); // explicit Float2(RValue cast); // explicit Float2(RValue cast); // explicit Float2(RValue cast); explicit Float2(RValue cast); Float2() = default; // Float2(float x, float y); // Float2(RValue rhs); // Float2(const Float2 &rhs); // Float2(const Reference &rhs); // Float2(RValue rhs); // Float2(const Float &rhs); // Float2(const Reference &rhs); // template // Float2(const SwizzleMask1 &rhs); // RValue operator=(float broadcast); // RValue operator=(RValue rhs); // RValue operator=(const Float2 &rhs); // RValue operator=(const Reference &rhs); // RValue operator=(RValue rhs); // RValue operator=(const Float &rhs); // RValue operator=(const Reference &rhs); // template // RValue operator=(const SwizzleMask1 &rhs); static Type *type(); static int element_count() { return 2; } }; // RValue operator+(RValue lhs, RValue rhs); // RValue operator-(RValue lhs, RValue rhs); // RValue operator*(RValue lhs, RValue rhs); // RValue operator/(RValue lhs, RValue rhs); // RValue operator%(RValue lhs, RValue rhs); // RValue operator+=(Float2 &lhs, RValue rhs); // RValue operator-=(Float2 &lhs, RValue rhs); // RValue operator*=(Float2 &lhs, RValue rhs); // RValue operator/=(Float2 &lhs, RValue rhs); // RValue operator%=(Float2 &lhs, RValue rhs); // RValue operator+(RValue val); // RValue operator-(RValue val); // RValue Abs(RValue x); // RValue Max(RValue x, RValue y); // RValue Min(RValue x, RValue y); // RValue Swizzle(RValue x, uint16_t select); // RValue Mask(Float2 &lhs, RValue rhs, uint16_t select); class Float4 : public LValue, public XYZW { public: explicit Float4(RValue cast); explicit Float4(RValue cast); explicit Float4(RValue cast); explicit Float4(RValue cast); explicit Float4(RValue cast); explicit Float4(RValue cast); Float4(); Float4(float xyzw); Float4(float x, float yzw); Float4(float x, float y, float zw); Float4(float x, float y, float z, float w); Float4(RValue rhs); Float4(const Float4 &rhs); Float4(const Reference &rhs); Float4(RValue rhs); Float4(const Float &rhs); Float4(const Reference &rhs); template Float4(const SwizzleMask1 &rhs); template Float4(const Swizzle4 &rhs); template Float4(const Swizzle2 &x, const Swizzle2 &y); template Float4(const SwizzleMask2 &x, const Swizzle2 &y); template Float4(const Swizzle2 &x, const SwizzleMask2 &y); template Float4(const SwizzleMask2 &x, const SwizzleMask2 &y); Float4(RValue lo, RValue hi); RValue operator=(float broadcast); RValue operator=(RValue rhs); RValue operator=(const Float4 &rhs); RValue operator=(const Reference &rhs); RValue operator=(RValue rhs); RValue operator=(const Float &rhs); RValue operator=(const Reference &rhs); template RValue operator=(const SwizzleMask1 &rhs); template RValue operator=(const Swizzle4 &rhs); static Float4 infinity(); static Type *type(); static int element_count() { return 4; } private: void constant(float x, float y, float z, float w); }; RValue operator+(RValue lhs, RValue rhs); RValue operator-(RValue lhs, RValue rhs); RValue operator*(RValue lhs, RValue rhs); RValue operator/(RValue lhs, RValue rhs); RValue operator%(RValue lhs, RValue rhs); RValue operator+=(Float4 &lhs, RValue rhs); RValue operator-=(Float4 &lhs, RValue rhs); RValue operator*=(Float4 &lhs, RValue rhs); RValue operator/=(Float4 &lhs, RValue rhs); RValue operator%=(Float4 &lhs, RValue rhs); RValue operator+(RValue val); RValue operator-(RValue val); // Computes `x * y + z`, which may be fused into one operation to produce a higher-precision result. RValue MulAdd(RValue x, RValue y, RValue z); // Computes a fused `x * y + z` operation. Caps::fmaIsFast indicates whether it emits an FMA instruction. RValue FMA(RValue x, RValue y, RValue z); RValue Abs(RValue x); RValue Max(RValue x, RValue y); RValue Min(RValue x, RValue y); RValue Rcp(RValue x, bool relaxedPrecision, bool exactAtPow2 = false); RValue RcpSqrt(RValue x, bool relaxedPrecision); RValue Sqrt(RValue x); RValue Insert(RValue val, RValue element, int i); RValue Extract(RValue x, int i); RValue Swizzle(RValue x, uint16_t select); RValue Shuffle(RValue x, RValue y, uint16_t select); RValue ShuffleLowHigh(RValue x, RValue y, uint16_t imm); RValue UnpackLow(RValue x, RValue y); RValue UnpackHigh(RValue x, RValue y); RValue Mask(Float4 &lhs, RValue rhs, uint16_t select); RValue SignMask(RValue x); // Ordered comparison functions RValue CmpEQ(RValue x, RValue y); RValue CmpLT(RValue x, RValue y); RValue CmpLE(RValue x, RValue y); RValue CmpNEQ(RValue x, RValue y); RValue CmpNLT(RValue x, RValue y); RValue CmpNLE(RValue x, RValue y); inline RValue CmpGT(RValue x, RValue y) { return CmpNLE(x, y); } inline RValue CmpGE(RValue x, RValue y) { return CmpNLT(x, y); } // Unordered comparison functions RValue CmpUEQ(RValue x, RValue y); RValue CmpULT(RValue x, RValue y); RValue CmpULE(RValue x, RValue y); RValue CmpUNEQ(RValue x, RValue y); RValue CmpUNLT(RValue x, RValue y); RValue CmpUNLE(RValue x, RValue y); inline RValue CmpUGT(RValue x, RValue y) { return CmpUNLE(x, y); } inline RValue CmpUGE(RValue x, RValue y) { return CmpUNLT(x, y); } RValue IsInf(RValue x); RValue IsNan(RValue x); RValue Round(RValue x); RValue Trunc(RValue x); RValue Frac(RValue x); RValue Floor(RValue x); RValue Ceil(RValue x); inline RValue Mix(RValue x, RValue y, RValue frac) { return (x * (Float4(1.0f) - frac)) + (y * frac); } // Trigonometric functions RValue Sin(RValue x); RValue Cos(RValue x); RValue Tan(RValue x); RValue Asin(RValue x); RValue Acos(RValue x); RValue Atan(RValue x); RValue Sinh(RValue x); RValue Cosh(RValue x); RValue Tanh(RValue x); RValue Asinh(RValue x); RValue Acosh(RValue x); RValue Atanh(RValue x); RValue Atan2(RValue x, RValue y); // Exponential functions RValue Pow(RValue x, RValue y); RValue Exp(RValue x); RValue Log(RValue x); RValue Exp2(RValue x); RValue Log2(RValue x); // Call a unary C function on each element of a vector type. template inline RValue ScalarizeCall(Func func, const RValue &x) { T result; for(int i = 0; i < T::element_count(); i++) { result = Insert(result, Call(func, Extract(x, i)), i); } return result; } // Call a binary C function on each element of a vector type. template inline RValue ScalarizeCall(Func func, const RValue &x, const RValue &y) { T result; for(int i = 0; i < T::element_count(); i++) { result = Insert(result, Call(func, Extract(x, i), Extract(y, i)), i); } return result; } // Call a ternary C function on each element of a vector type. template inline RValue ScalarizeCall(Func func, const RValue &x, const RValue &y, const RValue &z) { T result; for(int i = 0; i < T::element_count(); i++) { result = Insert(result, Call(func, Extract(x, i), Extract(y, i), Extract(z, i)), i); } return result; } // Invoke a unary lambda expression on each element of a vector type. template inline RValue Scalarize(Func func, const RValue &x) { T result; for(int i = 0; i < T::element_count(); i++) { result = Insert(result, func(Extract(x, i)), i); } return result; } // Invoke a binary lambda expression on each element of a vector type. template inline RValue Scalarize(Func func, const RValue &x, const RValue &y) { T result; for(int i = 0; i < T::element_count(); i++) { result = Insert(result, func(Extract(x, i), Extract(y, i)), i); } return result; } // Invoke a ternary lambda expression on each element of a vector type. template inline RValue Scalarize(Func func, const RValue &x, const RValue &y, const RValue &z) { T result; for(int i = 0; i < T::element_count(); i++) { result = Insert(result, func(Extract(x, i), Extract(y, i), Extract(z, i)), i); } return result; } // Bit Manipulation functions. // TODO: Currently unimplemented for Subzero. // Count leading zeros. // Returns 32 when: !isZeroUndef && x == 0. // Returns an undefined value when: isZeroUndef && x == 0. RValue Ctlz(RValue x, bool isZeroUndef); RValue Ctlz(RValue x, bool isZeroUndef); // Count trailing zeros. // Returns 32 when: !isZeroUndef && x == 0. // Returns an undefined value when: isZeroUndef && x == 0. RValue Cttz(RValue x, bool isZeroUndef); RValue Cttz(RValue x, bool isZeroUndef); template class Pointer : public LValue> { public: template Pointer(RValue> pointerS, int alignment = 1) : alignment(alignment) { Value *pointerT = Nucleus::createBitCast(pointerS.value(), Nucleus::getPointerType(T::type())); this->storeValue(pointerT); } template Pointer(const Pointer &pointer, int alignment = 1) : alignment(alignment) { Value *pointerS = pointer.loadValue(); Value *pointerT = Nucleus::createBitCast(pointerS, Nucleus::getPointerType(T::type())); this->storeValue(pointerT); } Pointer(Argument> argument); Pointer(); Pointer(RValue> rhs); Pointer(const Pointer &rhs); Pointer(const Reference> &rhs); Pointer(std::nullptr_t); RValue> operator=(RValue> rhs); RValue> operator=(const Pointer &rhs); RValue> operator=(const Reference> &rhs); RValue> operator=(std::nullptr_t); Reference operator*() const; Reference operator[](int index) const; Reference operator[](unsigned int index) const; Reference operator[](RValue index) const; Reference operator[](RValue index) const; static Type *type(); private: const int alignment; }; RValue> operator+(RValue> lhs, int offset); RValue> operator+(RValue> lhs, RValue offset); RValue> operator+(RValue> lhs, RValue offset); RValue> operator+=(Pointer &lhs, int offset); RValue> operator+=(Pointer &lhs, RValue offset); RValue> operator+=(Pointer &lhs, RValue offset); RValue> operator-(RValue> lhs, int offset); RValue> operator-(RValue> lhs, RValue offset); RValue> operator-(RValue> lhs, RValue offset); RValue> operator-=(Pointer &lhs, int offset); RValue> operator-=(Pointer &lhs, RValue offset); RValue> operator-=(Pointer &lhs, RValue offset); template RValue operator==(const Pointer &lhs, const Pointer &rhs) { return RValue(Nucleus::createICmpEQ(lhs.loadValue(), rhs.loadValue())); } template RValue operator!=(const Pointer &lhs, const Pointer &rhs) { return RValue(Nucleus::createICmpNE(lhs.loadValue(), rhs.loadValue())); } template RValue Load(RValue> pointer, unsigned int alignment, bool atomic, std::memory_order memoryOrder) { return RValue(Nucleus::createLoad(pointer.value(), T::type(), false, alignment, atomic, memoryOrder)); } template RValue Load(Pointer pointer, unsigned int alignment, bool atomic, std::memory_order memoryOrder) { return Load(RValue>(pointer), alignment, atomic, memoryOrder); } // TODO: Use SIMD to template these. // TODO(b/155867273): These can be undeprecated if implemented for Subzero. [[deprecated]] RValue MaskedLoad(RValue> base, RValue mask, unsigned int alignment, bool zeroMaskedLanes = false); [[deprecated]] RValue MaskedLoad(RValue> base, RValue mask, unsigned int alignment, bool zeroMaskedLanes = false); [[deprecated]] void MaskedStore(RValue> base, RValue val, RValue mask, unsigned int alignment); [[deprecated]] void MaskedStore(RValue> base, RValue val, RValue mask, unsigned int alignment); template void Store(RValue value, RValue> pointer, unsigned int alignment, bool atomic, std::memory_order memoryOrder) { Nucleus::createStore(value.value(), pointer.value(), T::type(), false, alignment, atomic, memoryOrder); } template void Store(RValue value, Pointer pointer, unsigned int alignment, bool atomic, std::memory_order memoryOrder) { Store(value, RValue>(pointer), alignment, atomic, memoryOrder); } template void Store(T value, Pointer pointer, unsigned int alignment, bool atomic, std::memory_order memoryOrder) { Store(RValue(value), RValue>(pointer), alignment, atomic, memoryOrder); } enum class OutOfBoundsBehavior { Nullify, // Loads become zero, stores are elided. RobustBufferAccess, // As defined by the Vulkan spec (in short: access anywhere within bounds, or zeroing). UndefinedValue, // Only for load operations. Not secure. No program termination. UndefinedBehavior, // Program may terminate. }; RValue AnyTrue(const RValue &bools); RValue AnyFalse(const RValue &bools); RValue AllTrue(const RValue &bools); RValue AllFalse(const RValue &bools); RValue Divergent(const RValue &ints); RValue Divergent(const RValue &floats); RValue Uniform(const RValue &ints); RValue Uniform(const RValue &floats); // Fence adds a memory barrier that enforces ordering constraints on memory // operations. memoryOrder can only be one of: // std::memory_order_acquire, std::memory_order_release, // std::memory_order_acq_rel, or std::memory_order_seq_cst. void Fence(std::memory_order memoryOrder); template class Array : public LValue { public: Array(int size = S); Reference operator[](int index); Reference operator[](unsigned int index); Reference operator[](RValue index); Reference operator[](RValue index); // self() returns the this pointer to this Array object. // This function exists because operator&() is overloaded by LValue. inline Array *self() { return this; } }; // RValue> operator++(Array &val, int); // Post-increment // const Array &operator++(Array &val); // Pre-increment // RValue> operator--(Array &val, int); // Post-decrement // const Array &operator--(Array &val); // Pre-decrement void branch(RValue cmp, BasicBlock *bodyBB, BasicBlock *endBB); // ValueOf returns a rr::Value* for the given C-type, RValue, LValue // or Reference. template inline Value *ValueOf(const T &v) { return ReactorType::cast(v).loadValue(); } void Return(); template void Return(const T &ret) { static_assert(CanBeUsedAsReturn>::value, "Unsupported type for Return()"); Nucleus::createRet(ValueOf(ret)); // Place any unreachable instructions in an unreferenced block. Nucleus::setInsertBlock(Nucleus::createBasicBlock()); } // Generic template, leave undefined! template class Function; // Specialized for function types template class Function { // Static assert that the function signature is valid. static_assert(sizeof(AssertFunctionSignatureIsValid) >= 0, "Invalid function signature"); public: Function(); template Argument>::type> Arg() const { Value *arg = Nucleus::getArgument(index); return Argument>::type>(arg); } std::shared_ptr operator()(const char *name, ...); protected: std::unique_ptr core; std::vector arguments; }; template class Function : public Function { }; // FunctionT accepts a C-style function type template argument, allowing it to return a type-safe RoutineT wrapper template class FunctionT; template class FunctionT : public Function(CToReactorT...)> { public: // Type of base class using BaseType = Function(CToReactorT...)>; // Function type, e.g. void(int,float) using CFunctionType = Return(Arguments...); // Reactor function type, e.g. Void(Int, Float) using ReactorFunctionType = CToReactorT(CToReactorT...); // Returned RoutineT type using RoutineType = RoutineT; // Hide base implementations of operator() template RoutineType operator()(const char *name, VarArgs... varArgs) { return RoutineType(BaseType::operator()(name, std::forward(varArgs)...)); } }; RValue Ticks(); } // namespace rr /* Inline implementations */ namespace rr { template LValue::LValue(int arraySize) : Variable(T::type(), arraySize) { #ifdef ENABLE_RR_DEBUG_INFO materialize(); #endif // ENABLE_RR_DEBUG_INFO } template RValue> LValue::operator&() { return RValue>(this->getBaseAddress()); } template Reference::Reference(Value *pointer, int alignment) : address(pointer) , alignment(alignment) { } template RValue Reference::operator=(RValue rhs) const { Nucleus::createStore(rhs.value(), address, T::type(), false, alignment); return rhs; } template RValue Reference::operator=(const Reference &ref) const { Value *tmp = Nucleus::createLoad(ref.address, T::type(), false, ref.alignment); Nucleus::createStore(tmp, address, T::type(), false, alignment); return RValue(tmp); } template RValue Reference::operator+=(RValue rhs) const { return *this = *this + rhs; } template Value *Reference::loadValue() const { return Nucleus::createLoad(address, T::type(), false, alignment); } template RValue Reference::load() const { return RValue(loadValue()); } template int Reference::getAlignment() const { return alignment; } template RValue::RValue(const RValue &rvalue) : val(rvalue.val) { RR_DEBUG_INFO_EMIT_VAR(val); } template RValue::RValue(Value *value) : val(value) { assert(Nucleus::createBitCast(value, T::type()) == value); // Run-time type should match T, so bitcast is no-op. RR_DEBUG_INFO_EMIT_VAR(val); } template RValue::RValue(const T &lvalue) : val(lvalue.loadValue()) { RR_DEBUG_INFO_EMIT_VAR(val); } template<> inline RValue::RValue(bool b) : val(Nucleus::createConstantBool(b)) { RR_DEBUG_INFO_EMIT_VAR(val); } template RValue::RValue(typename IntLiteral::Type i) : val(Nucleus::createConstantInt(i)) { RR_DEBUG_INFO_EMIT_VAR(val); } template<> inline RValue::RValue(int64_t i) : val(Nucleus::createConstantLong(i)) { RR_DEBUG_INFO_EMIT_VAR(val); } template<> inline RValue::RValue(float f) : val(Nucleus::createConstantFloat(f)) { RR_DEBUG_INFO_EMIT_VAR(val); } inline Value *broadcast(int i, Type *type) { std::vector constantVector = { i }; return Nucleus::createConstantVector(constantVector, type); } template<> inline RValue::RValue(int i) : val(broadcast(i, Int4::type())) { RR_DEBUG_INFO_EMIT_VAR(val); } template<> inline RValue::RValue(unsigned int i) : val(broadcast(int(i), UInt4::type())) { RR_DEBUG_INFO_EMIT_VAR(val); } inline Value *broadcast(float f, Type *type) { // See Float(float) constructor for the rationale behind this assert. assert(std::isfinite(f)); std::vector constantVector = { f }; return Nucleus::createConstantVector(constantVector, type); } template<> inline RValue::RValue(float f) : val(broadcast(f, Float4::type())) { RR_DEBUG_INFO_EMIT_VAR(val); } template RValue::RValue(const Reference &ref) : val(ref.loadValue()) { RR_DEBUG_INFO_EMIT_VAR(val); } template Swizzle2::operator RValue() const { RR_DEBUG_INFO_UPDATE_LOC(); Value *vector = parent->loadValue(); return Swizzle(RValue(vector), T); } template Swizzle4::operator RValue() const { RR_DEBUG_INFO_UPDATE_LOC(); Value *vector = parent->loadValue(); return Swizzle(RValue(vector), T); } template SwizzleMask4::operator RValue() const { RR_DEBUG_INFO_UPDATE_LOC(); Value *vector = parent->loadValue(); return Swizzle(RValue(vector), T); } template RValue SwizzleMask4::operator=(RValue rhs) { RR_DEBUG_INFO_UPDATE_LOC(); return Mask(*parent, rhs, T); } template RValue SwizzleMask4::operator=(RValue::Type> rhs) { RR_DEBUG_INFO_UPDATE_LOC(); return Mask(*parent, Vector4(rhs), T); } template SwizzleMask1::operator RValue::Type>() const // FIXME: Call a non-template function { RR_DEBUG_INFO_UPDATE_LOC(); return Extract(*parent, T & 0x3); } template SwizzleMask1::operator RValue() const { RR_DEBUG_INFO_UPDATE_LOC(); Value *vector = parent->loadValue(); return Swizzle(RValue(vector), T); } template RValue SwizzleMask1::operator=(float x) { RR_DEBUG_INFO_UPDATE_LOC(); return *parent = Insert(*parent, Float(x), T & 0x3); } template RValue SwizzleMask1::operator=(RValue rhs) { RR_DEBUG_INFO_UPDATE_LOC(); return Mask(*parent, Float4(rhs), T); } template RValue SwizzleMask1::operator=(RValue::Type> rhs) // FIXME: Call a non-template function { RR_DEBUG_INFO_UPDATE_LOC(); return *parent = Insert(*parent, rhs, T & 0x3); } template SwizzleMask2::operator RValue() const { RR_DEBUG_INFO_UPDATE_LOC(); Value *vector = parent->loadValue(); return Swizzle(RValue(vector), T); } template RValue SwizzleMask2::operator=(RValue rhs) { RR_DEBUG_INFO_UPDATE_LOC(); return Mask(*parent, Float4(rhs), T); } template Int::Int(const SwizzleMask1 &rhs) { *this = rhs.operator RValue(); } template RValue Int::operator=(const SwizzleMask1 &rhs) { return *this = rhs.operator RValue(); } template Float::Float(const SwizzleMask1 &rhs) { *this = rhs.operator RValue(); } template RValue Float::operator=(const SwizzleMask1 &rhs) { return *this = rhs.operator RValue(); } template Int4::Int4(const SwizzleMask1 &rhs) : XYZW(this) { *this = rhs.operator RValue(); } template Float4::Float4(const SwizzleMask1 &rhs) : XYZW(this) { *this = rhs.operator RValue(); } template Float4::Float4(const Swizzle4 &rhs) : XYZW(this) { *this = rhs.operator RValue(); } template Float4::Float4(const Swizzle2 &x, const Swizzle2 &y) : XYZW(this) { RR_DEBUG_INFO_UPDATE_LOC(); *this = ShuffleLowHigh(*x.parent, *y.parent, (uint16_t(X) & 0xFF00u) | (uint16_t(Y >> 8) & 0x00FFu)); } template Float4::Float4(const SwizzleMask2 &x, const Swizzle2 &y) : XYZW(this) { RR_DEBUG_INFO_UPDATE_LOC(); *this = ShuffleLowHigh(*x.parent, *y.parent, (uint16_t(X) & 0xFF00u) | (uint16_t(Y >> 8) & 0x00FFu)); } template Float4::Float4(const Swizzle2 &x, const SwizzleMask2 &y) : XYZW(this) { RR_DEBUG_INFO_UPDATE_LOC(); *this = ShuffleLowHigh(*x.parent, *y.parent, (uint16_t(X) & 0xFF00u) | (uint16_t(Y >> 8) & 0x00FFu)); } template Float4::Float4(const SwizzleMask2 &x, const SwizzleMask2 &y) : XYZW(this) { RR_DEBUG_INFO_UPDATE_LOC(); *this = ShuffleLowHigh(*x.parent, *y.parent, (uint16_t(X) & 0xFF00u) | (uint16_t(Y >> 8) & 0x00FFu)); } template RValue Float4::operator=(const SwizzleMask1 &rhs) { return *this = rhs.operator RValue(); } template RValue Float4::operator=(const Swizzle4 &rhs) { return *this = rhs.operator RValue(); } // Returns a reactor pointer to the fixed-address ptr. RValue> ConstantPointer(const void *ptr); // Returns a reactor pointer to an immutable copy of the data of size bytes. RValue> ConstantData(const void *data, size_t size); template Pointer::Pointer(Argument> argument) : alignment(1) { this->store(argument.rvalue()); } template Pointer::Pointer() : alignment(1) {} template Pointer::Pointer(RValue> rhs) : alignment(1) { this->store(rhs); } template Pointer::Pointer(const Pointer &rhs) : alignment(rhs.alignment) { this->store(rhs.load()); } template Pointer::Pointer(const Reference> &rhs) : alignment(rhs.getAlignment()) { this->store(rhs.load()); } template Pointer::Pointer(std::nullptr_t) : alignment(1) { Value *value = Nucleus::createNullPointer(T::type()); this->storeValue(value); } template RValue> Pointer::operator=(RValue> rhs) { return this->store(rhs); } template RValue> Pointer::operator=(const Pointer &rhs) { return this->store(rhs.load()); } template RValue> Pointer::operator=(const Reference> &rhs) { return this->store(rhs.load()); } template RValue> Pointer::operator=(std::nullptr_t) { Value *value = Nucleus::createNullPointer(T::type()); this->storeValue(value); return RValue>(this); } template Reference Pointer::operator*() const { return Reference(this->loadValue(), alignment); } template Reference Pointer::operator[](int index) const { RR_DEBUG_INFO_UPDATE_LOC(); Value *element = Nucleus::createGEP(this->loadValue(), T::type(), Nucleus::createConstantInt(index), false); return Reference(element, alignment); } template Reference Pointer::operator[](unsigned int index) const { RR_DEBUG_INFO_UPDATE_LOC(); Value *element = Nucleus::createGEP(this->loadValue(), T::type(), Nucleus::createConstantInt(index), true); return Reference(element, alignment); } template Reference Pointer::operator[](RValue index) const { RR_DEBUG_INFO_UPDATE_LOC(); Value *element = Nucleus::createGEP(this->loadValue(), T::type(), index.value(), false); return Reference(element, alignment); } template Reference Pointer::operator[](RValue index) const { RR_DEBUG_INFO_UPDATE_LOC(); Value *element = Nucleus::createGEP(this->loadValue(), T::type(), index.value(), true); return Reference(element, alignment); } template Type *Pointer::type() { return Nucleus::getPointerType(T::type()); } template Array::Array(int size) : LValue(size) { } template Reference Array::operator[](int index) { assert(index < Variable::getArraySize()); Value *element = this->getElementPointer(Nucleus::createConstantInt(index), false); return Reference(element); } template Reference Array::operator[](unsigned int index) { assert(index < static_cast(Variable::getArraySize())); Value *element = this->getElementPointer(Nucleus::createConstantInt(index), true); return Reference(element); } template Reference Array::operator[](RValue index) { Value *element = this->getElementPointer(index.value(), false); return Reference(element); } template Reference Array::operator[](RValue index) { Value *element = this->getElementPointer(index.value(), true); return Reference(element); } // template // RValue> operator++(Array &val, int) // { // // FIXME: Requires storing the address of the array // } // template // const Array &operator++(Array &val) // { // // FIXME: Requires storing the address of the array // } // template // RValue> operator--(Array &val, int) // { // // FIXME: Requires storing the address of the array // } // template // const Array &operator--(Array &val) // { // // FIXME: Requires storing the address of the array // } template RValue IfThenElse(RValue condition, RValue ifTrue, RValue ifFalse) { RR_DEBUG_INFO_UPDATE_LOC(); return RValue(Nucleus::createSelect(condition.value(), ifTrue.value(), ifFalse.value())); } template RValue IfThenElse(RValue condition, const T &ifTrue, RValue ifFalse) { RR_DEBUG_INFO_UPDATE_LOC(); Value *trueValue = ifTrue.loadValue(); return RValue(Nucleus::createSelect(condition.value(), trueValue, ifFalse.value())); } template RValue IfThenElse(RValue condition, RValue ifTrue, const T &ifFalse) { RR_DEBUG_INFO_UPDATE_LOC(); Value *falseValue = ifFalse.loadValue(); return RValue(Nucleus::createSelect(condition.value(), ifTrue.value(), falseValue)); } template RValue IfThenElse(RValue condition, const T &ifTrue, const T &ifFalse) { RR_DEBUG_INFO_UPDATE_LOC(); Value *trueValue = ifTrue.loadValue(); Value *falseValue = ifFalse.loadValue(); return RValue(Nucleus::createSelect(condition.value(), trueValue, falseValue)); } template Function::Function() : core(new Nucleus()) { Type *types[] = { Arguments::type()... }; for(Type *type : types) { if(type != Void::type()) { arguments.push_back(type); } } Nucleus::createFunction(Return::type(), arguments); } template std::shared_ptr Function::operator()(const char *name, ...) { char fullName[1024 + 1]; va_list vararg; va_start(vararg, name); vsnprintf(fullName, 1024, name, vararg); va_end(vararg); auto routine = core->acquireRoutine(fullName); core.reset(nullptr); return routine; } template RValue ReinterpretCast(RValue val) { RR_DEBUG_INFO_UPDATE_LOC(); return RValue(Nucleus::createBitCast(val.value(), T::type())); } template RValue ReinterpretCast(const LValue &var) { RR_DEBUG_INFO_UPDATE_LOC(); Value *val = var.loadValue(); return RValue(Nucleus::createBitCast(val, T::type())); } template RValue ReinterpretCast(const Reference &var) { return ReinterpretCast(RValue(var)); } template RValue As(Value *val) { RR_DEBUG_INFO_UPDATE_LOC(); return RValue(Nucleus::createBitCast(val, T::type())); } template RValue As(RValue val) { return ReinterpretCast(val); } template RValue As(const LValue &var) { return ReinterpretCast(var); } template RValue As(const Reference &val) { return ReinterpretCast(val); } // Calls the function pointer fptr with the given arguments, return type // and parameter types. Returns the call's return value if the function has // a non-void return type. Value *Call(RValue> fptr, Type *retTy, std::initializer_list args, std::initializer_list paramTys); template class CallHelper {}; template class CallHelper { public: using RReturn = CToReactorT; static inline RReturn Call(Return(fptr)(Arguments...), CToReactorT... args) { return RValue(rr::Call( ConstantPointer(reinterpret_cast(fptr)), RReturn::type(), { ValueOf(args)... }, { CToReactorT::type()... })); } static inline RReturn Call(Pointer fptr, CToReactorT... args) { return RValue(rr::Call( fptr, RReturn::type(), { ValueOf(args)... }, { CToReactorT::type()... })); } }; template class CallHelper { public: static inline void Call(void(fptr)(Arguments...), CToReactorT... args) { rr::Call(ConstantPointer(reinterpret_cast(fptr)), Void::type(), { ValueOf(args)... }, { CToReactorT::type()... }); } static inline void Call(Pointer fptr, CToReactorT... args) { rr::Call(fptr, Void::type(), { ValueOf(args)... }, { CToReactorT::type()... }); } }; template inline ReactorTypeT CastToReactor(const T &v) { return ReactorType::cast(v); } // Calls the static function pointer fptr with the given arguments args. template inline CToReactorT Call(Return(fptr)(CArgs...), RArgs &&...args) { return CallHelper::Call(fptr, CastToReactor(std::forward(args))...); } // Calls the static function pointer fptr with the given arguments args. // Overload for calling functions with void return type. template inline void Call(void(fptr)(CArgs...), RArgs &&...args) { CallHelper::Call(fptr, CastToReactor(std::forward(args))...); } // Calls the member function pointer fptr with the given arguments args. // object can be a Class*, or a Pointer. template inline CToReactorT Call(Return (Class::*fptr)(CArgs...), C &&object, RArgs &&...args) { using Helper = CallHelper; using fptrTy = decltype(fptr); struct Static { static inline Return Call(Class *object, void *fptrptr, CArgs... args) { auto fptr = *reinterpret_cast(fptrptr); return (object->*fptr)(std::forward(args)...); } }; return Helper::Call(&Static::Call, CastToReactor(object), ConstantData(&fptr, sizeof(fptr)), CastToReactor(std::forward(args))...); } // Calls the member function pointer fptr with the given arguments args. // Overload for calling functions with void return type. // object can be a Class*, or a Pointer. template inline void Call(void (Class::*fptr)(CArgs...), C &&object, RArgs &&...args) { using Helper = CallHelper; using fptrTy = decltype(fptr); struct Static { static inline void Call(Class *object, void *fptrptr, CArgs... args) { auto fptr = *reinterpret_cast(fptrptr); (object->*fptr)(std::forward(args)...); } }; Helper::Call(&Static::Call, CastToReactor(object), ConstantData(&fptr, sizeof(fptr)), CastToReactor(std::forward(args))...); } // NonVoidFunction and VoidFunction are helper classes which define ReturnType // when F matches a non-void fuction signature or void function signature, respectively, // as the function's return type. template struct NonVoidFunction {}; template struct NonVoidFunction { using ReturnType = Return; }; template struct NonVoidFunction { }; template using NonVoidFunctionReturnType = typename NonVoidFunction::ReturnType; template struct VoidFunction {}; template struct VoidFunction { using ReturnType = void; }; template using VoidFunctionReturnType = typename VoidFunction::ReturnType; // Calls the Reactor function pointer fptr with the signature FUNCTION_SIGNATURE and arguments. // Overload for calling functions with non-void return type. template inline CToReactorT> Call(Pointer fptr, RArgs &&...args) { return CallHelper::Call(fptr, CastToReactor(std::forward(args))...); } // Calls the Reactor function pointer fptr with the signature FUNCTION_SIGNATURE and arguments. // Overload for calling functions with void return type. template inline VoidFunctionReturnType Call(Pointer fptr, RArgs &&...args) { CallHelper::Call(fptr, CastToReactor(std::forward(args))...); } // Breakpoint emits an instruction that will cause the application to trap. // This can be used to stop an attached debugger at the given call. void Breakpoint(); class ForData { public: ForData(bool init) : loopOnce(init) { } operator bool() { return loopOnce; } bool operator=(bool value) { return loopOnce = value; } bool setup() { RR_DEBUG_INFO_FLUSH(); if(Nucleus::getInsertBlock() != endBB) { testBB = Nucleus::createBasicBlock(); Nucleus::createBr(testBB); Nucleus::setInsertBlock(testBB); return true; } return false; } bool test(RValue cmp) { BasicBlock *bodyBB = Nucleus::createBasicBlock(); endBB = Nucleus::createBasicBlock(); Nucleus::createCondBr(cmp.value(), bodyBB, endBB); Nucleus::setInsertBlock(bodyBB); return true; } void end() { Nucleus::createBr(testBB); Nucleus::setInsertBlock(endBB); } private: BasicBlock *testBB = nullptr; BasicBlock *endBB = nullptr; bool loopOnce = true; }; class IfElseData { public: IfElseData(RValue cmp) { trueBB = Nucleus::createBasicBlock(); falseBB = Nucleus::createBasicBlock(); endBB = falseBB; // Until we encounter an Else statement, these are the same. Nucleus::createCondBr(cmp.value(), trueBB, falseBB); Nucleus::setInsertBlock(trueBB); } ~IfElseData() { Nucleus::createBr(endBB); Nucleus::setInsertBlock(endBB); } operator int() { return iteration; } IfElseData &operator++() { ++iteration; return *this; } void elseClause() { endBB = Nucleus::createBasicBlock(); Nucleus::createBr(endBB); Nucleus::setInsertBlock(falseBB); } private: BasicBlock *trueBB = nullptr; BasicBlock *falseBB = nullptr; BasicBlock *endBB = nullptr; int iteration = 0; }; #define For(init, cond, inc) \ for(ForData for__ = true; for__; for__ = false) \ for(init; for__.setup() && for__.test(cond); inc, for__.end()) #define While(cond) For((void)0, cond, (void)0) #define Do \ { \ BasicBlock *body__ = Nucleus::createBasicBlock(); \ Nucleus::createBr(body__); \ Nucleus::setInsertBlock(body__); #define Until(cond) \ BasicBlock *end__ = Nucleus::createBasicBlock(); \ Nucleus::createCondBr((cond).value(), end__, body__); \ Nucleus::setInsertBlock(end__); \ } \ do \ { \ } while(false) // Require a semi-colon at the end of the Until() enum { IF_BLOCK__, ELSE_CLAUSE__, ELSE_BLOCK__, IFELSE_NUM__ }; #define If(cond) \ for(IfElseData ifElse__{ cond }; ifElse__ < IFELSE_NUM__; ++ifElse__) \ if(ifElse__ == IF_BLOCK__) #define Else \ else if(ifElse__ == ELSE_CLAUSE__) \ { \ ifElse__.elseClause(); \ } \ else // ELSE_BLOCK__ // The OFFSET macro is a generalization of the offsetof() macro defined in . // It allows e.g. getting the offset of array elements, even when indexed dynamically. // We cast the address '32' and subtract it again, because null-dereference is undefined behavior. #define OFFSET(s, m) ((int)(size_t) & reinterpret_cast((((s *)32)->m)) - 32) } // namespace rr #include "Traits.inl" #endif // rr_Reactor_hpp