// Copyright 2019 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. #include "Reactor.hpp" #include "Assert.hpp" #include "CPUID.hpp" #include "Debug.hpp" #include "Print.hpp" #if defined(_WIN32) # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN # endif # include #endif #include #include // Define REACTOR_MATERIALIZE_LVALUES_ON_DEFINITION to non-zero to ensure all // variables have a stack location obtained through alloca(). #ifndef REACTOR_MATERIALIZE_LVALUES_ON_DEFINITION # define REACTOR_MATERIALIZE_LVALUES_ON_DEFINITION 0 #endif namespace rr { thread_local Variable::UnmaterializedVariables *Variable::unmaterializedVariables = nullptr; void Variable::UnmaterializedVariables::add(const Variable *v) { variables.emplace(v, counter++); } void Variable::UnmaterializedVariables::remove(const Variable *v) { auto iter = variables.find(v); if(iter != variables.end()) { variables.erase(iter); } } void Variable::UnmaterializedVariables::clear() { variables.clear(); } void Variable::UnmaterializedVariables::materializeAll() { // Flatten map of Variable* to monotonically increasing counter to a vector, // then sort it by the counter, so that we materialize in variable usage order. std::vector> sorted; sorted.resize(variables.size()); std::copy(variables.begin(), variables.end(), sorted.begin()); std::sort(sorted.begin(), sorted.end(), [&](auto &lhs, auto &rhs) { return lhs.second < rhs.second; }); for(auto &v : sorted) { v.first->materialize(); } variables.clear(); } Variable::Variable(Type *type, int arraySize) : type(type) , arraySize(arraySize) { #if REACTOR_MATERIALIZE_LVALUES_ON_DEFINITION materialize(); #else unmaterializedVariables->add(this); #endif } Variable::~Variable() { // `unmaterializedVariables` can be null at this point due to the function // already having been finalized, while classes derived from `Function<>` // can have member `Variable` fields which are destructed afterwards. if(unmaterializedVariables) { unmaterializedVariables->remove(this); } } void Variable::materialize() const { if(!address) { address = Nucleus::allocateStackVariable(getType(), arraySize); RR_DEBUG_INFO_EMIT_VAR(address); if(rvalue) { storeValue(rvalue); rvalue = nullptr; } } } Value *Variable::loadValue() const { if(rvalue) { return rvalue; } if(!address) { // TODO: Return undef instead. materialize(); } return Nucleus::createLoad(address, getType(), false, 0); } Value *Variable::storeValue(Value *value) const { if(address) { return Nucleus::createStore(value, address, getType(), false, 0); } rvalue = value; return value; } Value *Variable::getBaseAddress() const { materialize(); return address; } Value *Variable::getElementPointer(Value *index, bool unsignedIndex) const { return Nucleus::createGEP(getBaseAddress(), getType(), index, unsignedIndex); } void Variable::materializeAll() { unmaterializedVariables->materializeAll(); } void Variable::killUnmaterialized() { unmaterializedVariables->clear(); } // NOTE: Only 12 bits out of 16 of the |select| value are used. // More specifically, the value should look like: // // msb lsb // v v // [.xxx|.yyy|.zzz|.www] where '.' means an ignored bit // // This format makes it easy to write calls with hexadecimal select values, // since each hex digit is a separate swizzle index. // // For example: // createShuffle4( [a,b,c,d], [e,f,g,h], 0x0123 ) -> [a,b,c,d] // createShuffle4( [a,b,c,d], [e,f,g,h], 0x4567 ) -> [e,f,g,h] // createShuffle4( [a,b,c,d], [e,f,g,h], 0x4012 ) -> [e,a,b,c] // static Value *createShuffle4(Value *lhs, Value *rhs, uint16_t select) { std::vector swizzle = { (select >> 12) & 0x07, (select >> 8) & 0x07, (select >> 4) & 0x07, (select >> 0) & 0x07, }; return Nucleus::createShuffleVector(lhs, rhs, swizzle); } // NOTE: Only 8 bits out of 16 of the |select| value are used. // More specifically, the value should look like: // // msb lsb // v v // [..xx|..yy|..zz|..ww] where '.' means an ignored bit // // This format makes it easy to write calls with hexadecimal select values, // since each hex digit is a separate swizzle index. // // For example: // createSwizzle4( [a,b,c,d], 0x0123 ) -> [a,b,c,d] // createSwizzle4( [a,b,c,d], 0x0033 ) -> [a,a,d,d] // static Value *createSwizzle4(Value *val, uint16_t select) { std::vector swizzle = { (select >> 12) & 0x03, (select >> 8) & 0x03, (select >> 4) & 0x03, (select >> 0) & 0x03, }; return Nucleus::createShuffleVector(val, val, swizzle); } static Value *createMask4(Value *lhs, Value *rhs, uint16_t select) { bool mask[4] = { false, false, false, false }; mask[(select >> 12) & 0x03] = true; mask[(select >> 8) & 0x03] = true; mask[(select >> 4) & 0x03] = true; mask[(select >> 0) & 0x03] = true; std::vector swizzle = { mask[0] ? 4 : 0, mask[1] ? 5 : 1, mask[2] ? 6 : 2, mask[3] ? 7 : 3, }; return Nucleus::createShuffleVector(lhs, rhs, swizzle); } Bool::Bool(Argument argument) { store(argument.rvalue()); } Bool::Bool(bool x) { storeValue(Nucleus::createConstantBool(x)); } Bool::Bool(RValue rhs) { store(rhs); } Bool::Bool(const Bool &rhs) { store(rhs.load()); } Bool::Bool(const Reference &rhs) { store(rhs.load()); } RValue Bool::operator=(RValue rhs) { return store(rhs); } RValue Bool::operator=(const Bool &rhs) { return store(rhs.load()); } RValue Bool::operator=(const Reference &rhs) { return store(rhs.load()); } RValue operator!(RValue val) { return RValue(Nucleus::createNot(val.value())); } RValue operator&&(RValue lhs, RValue rhs) { return RValue(Nucleus::createAnd(lhs.value(), rhs.value())); } RValue operator||(RValue lhs, RValue rhs) { return RValue(Nucleus::createOr(lhs.value(), rhs.value())); } RValue operator!=(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpNE(lhs.value(), rhs.value())); } RValue operator==(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpEQ(lhs.value(), rhs.value())); } Byte::Byte(Argument argument) { store(argument.rvalue()); } Byte::Byte(RValue cast) { Value *integer = Nucleus::createTrunc(cast.value(), Byte::type()); storeValue(integer); } Byte::Byte(RValue cast) { Value *integer = Nucleus::createTrunc(cast.value(), Byte::type()); storeValue(integer); } Byte::Byte(RValue cast) { Value *integer = Nucleus::createTrunc(cast.value(), Byte::type()); storeValue(integer); } Byte::Byte(int x) { storeValue(Nucleus::createConstantByte((unsigned char)x)); } Byte::Byte(unsigned char x) { storeValue(Nucleus::createConstantByte(x)); } Byte::Byte(RValue rhs) { store(rhs); } Byte::Byte(const Byte &rhs) { store(rhs.load()); } Byte::Byte(const Reference &rhs) { store(rhs.load()); } RValue Byte::operator=(RValue rhs) { return store(rhs); } RValue Byte::operator=(const Byte &rhs) { return store(rhs.load()); } RValue Byte::operator=(const Reference &rhs) { return store(rhs.load()); } RValue operator+(RValue lhs, RValue rhs) { return RValue(Nucleus::createAdd(lhs.value(), rhs.value())); } RValue operator-(RValue lhs, RValue rhs) { return RValue(Nucleus::createSub(lhs.value(), rhs.value())); } RValue operator*(RValue lhs, RValue rhs) { return RValue(Nucleus::createMul(lhs.value(), rhs.value())); } RValue operator/(RValue lhs, RValue rhs) { return RValue(Nucleus::createUDiv(lhs.value(), rhs.value())); } RValue operator%(RValue lhs, RValue rhs) { return RValue(Nucleus::createURem(lhs.value(), rhs.value())); } RValue operator&(RValue lhs, RValue rhs) { return RValue(Nucleus::createAnd(lhs.value(), rhs.value())); } RValue operator|(RValue lhs, RValue rhs) { return RValue(Nucleus::createOr(lhs.value(), rhs.value())); } RValue operator^(RValue lhs, RValue rhs) { return RValue(Nucleus::createXor(lhs.value(), rhs.value())); } RValue operator<<(RValue lhs, RValue rhs) { return RValue(Nucleus::createShl(lhs.value(), rhs.value())); } RValue operator>>(RValue lhs, RValue rhs) { return RValue(Nucleus::createLShr(lhs.value(), rhs.value())); } RValue operator+=(Byte &lhs, RValue rhs) { return lhs = lhs + rhs; } RValue operator-=(Byte &lhs, RValue rhs) { return lhs = lhs - rhs; } RValue operator*=(Byte &lhs, RValue rhs) { return lhs = lhs * rhs; } RValue operator/=(Byte &lhs, RValue rhs) { return lhs = lhs / rhs; } RValue operator%=(Byte &lhs, RValue rhs) { return lhs = lhs % rhs; } RValue operator&=(Byte &lhs, RValue rhs) { return lhs = lhs & rhs; } RValue operator|=(Byte &lhs, RValue rhs) { return lhs = lhs | rhs; } RValue operator^=(Byte &lhs, RValue rhs) { return lhs = lhs ^ rhs; } RValue operator<<=(Byte &lhs, RValue rhs) { return lhs = lhs << rhs; } RValue operator>>=(Byte &lhs, RValue rhs) { return lhs = lhs >> rhs; } RValue operator+(RValue val) { return val; } RValue operator-(RValue val) { return RValue(Nucleus::createNeg(val.value())); } RValue operator~(RValue val) { return RValue(Nucleus::createNot(val.value())); } RValue operator++(Byte &val, int) // Post-increment { RValue res = val; Value *inc = Nucleus::createAdd(res.value(), Nucleus::createConstantByte((unsigned char)1)); val.storeValue(inc); return res; } const Byte &operator++(Byte &val) // Pre-increment { Value *inc = Nucleus::createAdd(val.loadValue(), Nucleus::createConstantByte((unsigned char)1)); val.storeValue(inc); return val; } RValue operator--(Byte &val, int) // Post-decrement { RValue res = val; Value *inc = Nucleus::createSub(res.value(), Nucleus::createConstantByte((unsigned char)1)); val.storeValue(inc); return res; } const Byte &operator--(Byte &val) // Pre-decrement { Value *inc = Nucleus::createSub(val.loadValue(), Nucleus::createConstantByte((unsigned char)1)); val.storeValue(inc); return val; } RValue operator<(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpULT(lhs.value(), rhs.value())); } RValue operator<=(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpULE(lhs.value(), rhs.value())); } RValue operator>(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpUGT(lhs.value(), rhs.value())); } RValue operator>=(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpUGE(lhs.value(), rhs.value())); } RValue operator!=(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpNE(lhs.value(), rhs.value())); } RValue operator==(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpEQ(lhs.value(), rhs.value())); } SByte::SByte(Argument argument) { store(argument.rvalue()); } SByte::SByte(RValue cast) { Value *integer = Nucleus::createTrunc(cast.value(), SByte::type()); storeValue(integer); } SByte::SByte(RValue cast) { Value *integer = Nucleus::createTrunc(cast.value(), SByte::type()); storeValue(integer); } SByte::SByte(signed char x) { storeValue(Nucleus::createConstantByte(x)); } SByte::SByte(RValue rhs) { store(rhs); } SByte::SByte(const SByte &rhs) { store(rhs.load()); } SByte::SByte(const Reference &rhs) { store(rhs.load()); } RValue SByte::operator=(RValue rhs) { return store(rhs); } RValue SByte::operator=(const SByte &rhs) { return store(rhs.load()); } RValue SByte::operator=(const Reference &rhs) { return store(rhs.load()); } RValue operator+(RValue lhs, RValue rhs) { return RValue(Nucleus::createAdd(lhs.value(), rhs.value())); } RValue operator-(RValue lhs, RValue rhs) { return RValue(Nucleus::createSub(lhs.value(), rhs.value())); } RValue operator*(RValue lhs, RValue rhs) { return RValue(Nucleus::createMul(lhs.value(), rhs.value())); } RValue operator/(RValue lhs, RValue rhs) { return RValue(Nucleus::createSDiv(lhs.value(), rhs.value())); } RValue operator%(RValue lhs, RValue rhs) { return RValue(Nucleus::createSRem(lhs.value(), rhs.value())); } RValue operator&(RValue lhs, RValue rhs) { return RValue(Nucleus::createAnd(lhs.value(), rhs.value())); } RValue operator|(RValue lhs, RValue rhs) { return RValue(Nucleus::createOr(lhs.value(), rhs.value())); } RValue operator^(RValue lhs, RValue rhs) { return RValue(Nucleus::createXor(lhs.value(), rhs.value())); } RValue operator<<(RValue lhs, RValue rhs) { return RValue(Nucleus::createShl(lhs.value(), rhs.value())); } RValue operator>>(RValue lhs, RValue rhs) { return RValue(Nucleus::createAShr(lhs.value(), rhs.value())); } RValue operator+=(SByte &lhs, RValue rhs) { return lhs = lhs + rhs; } RValue operator-=(SByte &lhs, RValue rhs) { return lhs = lhs - rhs; } RValue operator*=(SByte &lhs, RValue rhs) { return lhs = lhs * rhs; } RValue operator/=(SByte &lhs, RValue rhs) { return lhs = lhs / rhs; } RValue operator%=(SByte &lhs, RValue rhs) { return lhs = lhs % rhs; } RValue operator&=(SByte &lhs, RValue rhs) { return lhs = lhs & rhs; } RValue operator|=(SByte &lhs, RValue rhs) { return lhs = lhs | rhs; } RValue operator^=(SByte &lhs, RValue rhs) { return lhs = lhs ^ rhs; } RValue operator<<=(SByte &lhs, RValue rhs) { return lhs = lhs << rhs; } RValue operator>>=(SByte &lhs, RValue rhs) { return lhs = lhs >> rhs; } RValue operator+(RValue val) { return val; } RValue operator-(RValue val) { return RValue(Nucleus::createNeg(val.value())); } RValue operator~(RValue val) { return RValue(Nucleus::createNot(val.value())); } RValue operator++(SByte &val, int) // Post-increment { RValue res = val; Value *inc = Nucleus::createAdd(res.value(), Nucleus::createConstantByte((signed char)1)); val.storeValue(inc); return res; } const SByte &operator++(SByte &val) // Pre-increment { Value *inc = Nucleus::createAdd(val.loadValue(), Nucleus::createConstantByte((signed char)1)); val.storeValue(inc); return val; } RValue operator--(SByte &val, int) // Post-decrement { RValue res = val; Value *inc = Nucleus::createSub(res.value(), Nucleus::createConstantByte((signed char)1)); val.storeValue(inc); return res; } const SByte &operator--(SByte &val) // Pre-decrement { Value *inc = Nucleus::createSub(val.loadValue(), Nucleus::createConstantByte((signed char)1)); val.storeValue(inc); return val; } RValue operator<(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpSLT(lhs.value(), rhs.value())); } RValue operator<=(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpSLE(lhs.value(), rhs.value())); } RValue operator>(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpSGT(lhs.value(), rhs.value())); } RValue operator>=(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpSGE(lhs.value(), rhs.value())); } RValue operator!=(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpNE(lhs.value(), rhs.value())); } RValue operator==(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpEQ(lhs.value(), rhs.value())); } Short::Short(Argument argument) { store(argument.rvalue()); } Short::Short(RValue cast) { Value *integer = Nucleus::createTrunc(cast.value(), Short::type()); storeValue(integer); } Short::Short(short x) { storeValue(Nucleus::createConstantShort(x)); } Short::Short(RValue rhs) { store(rhs); } Short::Short(const Short &rhs) { store(rhs.load()); } Short::Short(const Reference &rhs) { store(rhs.load()); } RValue Short::operator=(RValue rhs) { return store(rhs); } RValue Short::operator=(const Short &rhs) { return store(rhs.load()); } RValue Short::operator=(const Reference &rhs) { return store(rhs.load()); } RValue operator+(RValue lhs, RValue rhs) { return RValue(Nucleus::createAdd(lhs.value(), rhs.value())); } RValue operator-(RValue lhs, RValue rhs) { return RValue(Nucleus::createSub(lhs.value(), rhs.value())); } RValue operator*(RValue lhs, RValue rhs) { return RValue(Nucleus::createMul(lhs.value(), rhs.value())); } RValue operator/(RValue lhs, RValue rhs) { return RValue(Nucleus::createSDiv(lhs.value(), rhs.value())); } RValue operator%(RValue lhs, RValue rhs) { return RValue(Nucleus::createSRem(lhs.value(), rhs.value())); } RValue operator&(RValue lhs, RValue rhs) { return RValue(Nucleus::createAnd(lhs.value(), rhs.value())); } RValue operator|(RValue lhs, RValue rhs) { return RValue(Nucleus::createOr(lhs.value(), rhs.value())); } RValue operator^(RValue lhs, RValue rhs) { return RValue(Nucleus::createXor(lhs.value(), rhs.value())); } RValue operator<<(RValue lhs, RValue rhs) { return RValue(Nucleus::createShl(lhs.value(), rhs.value())); } RValue operator>>(RValue lhs, RValue rhs) { return RValue(Nucleus::createAShr(lhs.value(), rhs.value())); } RValue operator+=(Short &lhs, RValue rhs) { return lhs = lhs + rhs; } RValue operator-=(Short &lhs, RValue rhs) { return lhs = lhs - rhs; } RValue operator*=(Short &lhs, RValue rhs) { return lhs = lhs * rhs; } RValue operator/=(Short &lhs, RValue rhs) { return lhs = lhs / rhs; } RValue operator%=(Short &lhs, RValue rhs) { return lhs = lhs % rhs; } RValue operator&=(Short &lhs, RValue rhs) { return lhs = lhs & rhs; } RValue operator|=(Short &lhs, RValue rhs) { return lhs = lhs | rhs; } RValue operator^=(Short &lhs, RValue rhs) { return lhs = lhs ^ rhs; } RValue operator<<=(Short &lhs, RValue rhs) { return lhs = lhs << rhs; } RValue operator>>=(Short &lhs, RValue rhs) { return lhs = lhs >> rhs; } RValue operator+(RValue val) { return val; } RValue operator-(RValue val) { return RValue(Nucleus::createNeg(val.value())); } RValue operator~(RValue val) { return RValue(Nucleus::createNot(val.value())); } RValue operator++(Short &val, int) // Post-increment { RValue res = val; Value *inc = Nucleus::createAdd(res.value(), Nucleus::createConstantShort((short)1)); val.storeValue(inc); return res; } const Short &operator++(Short &val) // Pre-increment { Value *inc = Nucleus::createAdd(val.loadValue(), Nucleus::createConstantShort((short)1)); val.storeValue(inc); return val; } RValue operator--(Short &val, int) // Post-decrement { RValue res = val; Value *inc = Nucleus::createSub(res.value(), Nucleus::createConstantShort((short)1)); val.storeValue(inc); return res; } const Short &operator--(Short &val) // Pre-decrement { Value *inc = Nucleus::createSub(val.loadValue(), Nucleus::createConstantShort((short)1)); val.storeValue(inc); return val; } RValue operator<(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpSLT(lhs.value(), rhs.value())); } RValue operator<=(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpSLE(lhs.value(), rhs.value())); } RValue operator>(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpSGT(lhs.value(), rhs.value())); } RValue operator>=(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpSGE(lhs.value(), rhs.value())); } RValue operator!=(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpNE(lhs.value(), rhs.value())); } RValue operator==(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpEQ(lhs.value(), rhs.value())); } UShort::UShort(Argument argument) { store(argument.rvalue()); } UShort::UShort(RValue cast) { Value *integer = Nucleus::createTrunc(cast.value(), UShort::type()); storeValue(integer); } UShort::UShort(RValue cast) { Value *integer = Nucleus::createTrunc(cast.value(), UShort::type()); storeValue(integer); } UShort::UShort(RValue cast) { Value *integer = Nucleus::createZExt(cast.value(), UShort::type()); storeValue(integer); } UShort::UShort(unsigned short x) { storeValue(Nucleus::createConstantShort(x)); } UShort::UShort(RValue rhs) { store(rhs); } UShort::UShort(const UShort &rhs) { store(rhs.load()); } UShort::UShort(const Reference &rhs) { store(rhs.load()); } RValue UShort::operator=(RValue rhs) { return store(rhs); } RValue UShort::operator=(const UShort &rhs) { return store(rhs.load()); } RValue UShort::operator=(const Reference &rhs) { return store(rhs.load()); } RValue operator+(RValue lhs, RValue rhs) { return RValue(Nucleus::createAdd(lhs.value(), rhs.value())); } RValue operator-(RValue lhs, RValue rhs) { return RValue(Nucleus::createSub(lhs.value(), rhs.value())); } RValue operator*(RValue lhs, RValue rhs) { return RValue(Nucleus::createMul(lhs.value(), rhs.value())); } RValue operator/(RValue lhs, RValue rhs) { return RValue(Nucleus::createUDiv(lhs.value(), rhs.value())); } RValue operator%(RValue lhs, RValue rhs) { return RValue(Nucleus::createURem(lhs.value(), rhs.value())); } RValue operator&(RValue lhs, RValue rhs) { return RValue(Nucleus::createAnd(lhs.value(), rhs.value())); } RValue operator|(RValue lhs, RValue rhs) { return RValue(Nucleus::createOr(lhs.value(), rhs.value())); } RValue operator^(RValue lhs, RValue rhs) { return RValue(Nucleus::createXor(lhs.value(), rhs.value())); } RValue operator<<(RValue lhs, RValue rhs) { return RValue(Nucleus::createShl(lhs.value(), rhs.value())); } RValue operator>>(RValue lhs, RValue rhs) { return RValue(Nucleus::createLShr(lhs.value(), rhs.value())); } RValue operator+=(UShort &lhs, RValue rhs) { return lhs = lhs + rhs; } RValue operator-=(UShort &lhs, RValue rhs) { return lhs = lhs - rhs; } RValue operator*=(UShort &lhs, RValue rhs) { return lhs = lhs * rhs; } RValue operator/=(UShort &lhs, RValue rhs) { return lhs = lhs / rhs; } RValue operator%=(UShort &lhs, RValue rhs) { return lhs = lhs % rhs; } RValue operator&=(UShort &lhs, RValue rhs) { return lhs = lhs & rhs; } RValue operator|=(UShort &lhs, RValue rhs) { return lhs = lhs | rhs; } RValue operator^=(UShort &lhs, RValue rhs) { return lhs = lhs ^ rhs; } RValue operator<<=(UShort &lhs, RValue rhs) { return lhs = lhs << rhs; } RValue operator>>=(UShort &lhs, RValue rhs) { return lhs = lhs >> rhs; } RValue operator+(RValue val) { return val; } RValue operator-(RValue val) { return RValue(Nucleus::createNeg(val.value())); } RValue operator~(RValue val) { return RValue(Nucleus::createNot(val.value())); } RValue operator++(UShort &val, int) // Post-increment { RValue res = val; Value *inc = Nucleus::createAdd(res.value(), Nucleus::createConstantShort((unsigned short)1)); val.storeValue(inc); return res; } const UShort &operator++(UShort &val) // Pre-increment { Value *inc = Nucleus::createAdd(val.loadValue(), Nucleus::createConstantShort((unsigned short)1)); val.storeValue(inc); return val; } RValue operator--(UShort &val, int) // Post-decrement { RValue res = val; Value *inc = Nucleus::createSub(res.value(), Nucleus::createConstantShort((unsigned short)1)); val.storeValue(inc); return res; } const UShort &operator--(UShort &val) // Pre-decrement { Value *inc = Nucleus::createSub(val.loadValue(), Nucleus::createConstantShort((unsigned short)1)); val.storeValue(inc); return val; } RValue operator<(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpULT(lhs.value(), rhs.value())); } RValue operator<=(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpULE(lhs.value(), rhs.value())); } RValue operator>(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpUGT(lhs.value(), rhs.value())); } RValue operator>=(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpUGE(lhs.value(), rhs.value())); } RValue operator!=(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpNE(lhs.value(), rhs.value())); } RValue operator==(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpEQ(lhs.value(), rhs.value())); } Byte4::Byte4(RValue cast) { storeValue(Nucleus::createBitCast(cast.value(), type())); } Byte4::Byte4(RValue cast) { // TODO(b/148379603): Optimize narrowing swizzle. *this = As(Swizzle(As(cast), 0x0246'0246)); } Byte4::Byte4(RValue cast) { // TODO(b/148379603): Optimize narrowing swizzle. *this = As(Swizzle(As(cast), 0x0246'0246)); } Byte4::Byte4(RValue cast) { // TODO(b/148379603): Optimize narrowing swizzle. *this = As(Swizzle(As(cast), 0x048C'048C'048C'048C)); } Byte4::Byte4(RValue cast) { // TODO(b/148379603): Optimize narrowing swizzle. *this = As(Swizzle(As(cast), 0x048C'048C'048C'048C)); } Byte4::Byte4(RValue rhs) { store(rhs); } Byte4::Byte4(const Byte4 &rhs) { store(rhs.load()); } Byte4::Byte4(const Reference &rhs) { store(rhs.load()); } RValue Byte4::operator=(RValue rhs) { return store(rhs); } RValue Byte4::operator=(const Byte4 &rhs) { return store(rhs.load()); } RValue Insert(RValue val, RValue element, int i) { return RValue(Nucleus::createInsertElement(val.value(), element.value(), i)); } Byte8::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) { std::vector constantVector = { x0, x1, x2, x3, x4, x5, x6, x7 }; storeValue(Nucleus::createConstantVector(constantVector, type())); } Byte8::Byte8(RValue rhs) { store(rhs); } Byte8::Byte8(const Byte8 &rhs) { store(rhs.load()); } Byte8::Byte8(const Reference &rhs) { store(rhs.load()); } RValue Byte8::operator=(RValue rhs) { return store(rhs); } RValue Byte8::operator=(const Byte8 &rhs) { return store(rhs.load()); } RValue Byte8::operator=(const Reference &rhs) { return store(rhs.load()); } RValue operator+(RValue lhs, RValue rhs) { return RValue(Nucleus::createAdd(lhs.value(), rhs.value())); } RValue operator-(RValue lhs, RValue rhs) { return RValue(Nucleus::createSub(lhs.value(), rhs.value())); } // RValue operator*(RValue lhs, RValue rhs) // { // return RValue(Nucleus::createMul(lhs.value(), rhs.value())); // } // RValue operator/(RValue lhs, RValue rhs) // { // return RValue(Nucleus::createUDiv(lhs.value(), rhs.value())); // } // RValue operator%(RValue lhs, RValue rhs) // { // return RValue(Nucleus::createURem(lhs.value(), rhs.value())); // } RValue operator&(RValue lhs, RValue rhs) { return RValue(Nucleus::createAnd(lhs.value(), rhs.value())); } RValue operator|(RValue lhs, RValue rhs) { return RValue(Nucleus::createOr(lhs.value(), rhs.value())); } RValue operator^(RValue lhs, RValue rhs) { return RValue(Nucleus::createXor(lhs.value(), rhs.value())); } // RValue operator<<(RValue lhs, unsigned char rhs) // { // return RValue(Nucleus::createShl(lhs.value(), rhs.value())); // } // RValue operator>>(RValue lhs, unsigned char rhs) // { // return RValue(Nucleus::createLShr(lhs.value(), rhs.value())); // } RValue operator+=(Byte8 &lhs, RValue rhs) { return lhs = lhs + rhs; } RValue operator-=(Byte8 &lhs, RValue rhs) { return lhs = lhs - rhs; } // RValue operator*=(Byte8 &lhs, RValue rhs) // { // return lhs = lhs * rhs; // } // RValue operator/=(Byte8 &lhs, RValue rhs) // { // return lhs = lhs / rhs; // } // RValue operator%=(Byte8 &lhs, RValue rhs) // { // return lhs = lhs % rhs; // } RValue operator&=(Byte8 &lhs, RValue rhs) { return lhs = lhs & rhs; } RValue operator|=(Byte8 &lhs, RValue rhs) { return lhs = lhs | rhs; } RValue operator^=(Byte8 &lhs, RValue rhs) { return lhs = lhs ^ rhs; } // RValue operator<<=(Byte8 &lhs, RValue rhs) // { // return lhs = lhs << rhs; // } // RValue operator>>=(Byte8 &lhs, RValue rhs) // { // return lhs = lhs >> rhs; // } // RValue operator+(RValue val) // { // return val; // } // RValue operator-(RValue val) // { // return RValue(Nucleus::createNeg(val.value())); // } RValue operator~(RValue val) { return RValue(Nucleus::createNot(val.value())); } RValue Swizzle(RValue x, uint32_t select) { // Real type is v16i8 // TODO(b/148379603): Optimize narrowing swizzle. std::vector shuffle = { static_cast((select >> 28) & 0x07), static_cast((select >> 24) & 0x07), static_cast((select >> 20) & 0x07), static_cast((select >> 16) & 0x07), static_cast((select >> 12) & 0x07), static_cast((select >> 8) & 0x07), static_cast((select >> 4) & 0x07), static_cast((select >> 0) & 0x07), static_cast((select >> 28) & 0x07), static_cast((select >> 24) & 0x07), static_cast((select >> 20) & 0x07), static_cast((select >> 16) & 0x07), static_cast((select >> 12) & 0x07), static_cast((select >> 8) & 0x07), static_cast((select >> 4) & 0x07), static_cast((select >> 0) & 0x07), }; return As(Nucleus::createShuffleVector(x.value(), x.value(), shuffle)); } RValue Unpack(RValue x) { // TODO(b/148379603): Optimize narrowing swizzle. std::vector shuffle = { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7 }; // Real type is v16i8 return As(Nucleus::createShuffleVector(x.value(), x.value(), shuffle)); } RValue Unpack(RValue x, RValue y) { return UnpackLow(As(x), As(y)); } RValue UnpackLow(RValue x, RValue y) { // TODO(b/148379603): Optimize narrowing swizzle. std::vector shuffle = { 0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23 }; // Real type is v16i8 return As(Nucleus::createShuffleVector(x.value(), y.value(), shuffle)); } RValue UnpackHigh(RValue x, RValue y) { // TODO(b/148379603): Optimize narrowing swizzle. std::vector shuffle = { 0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23 }; // Real type is v16i8 auto lowHigh = RValue(Nucleus::createShuffleVector(x.value(), y.value(), shuffle)); return As(Swizzle(As(lowHigh), 0x2323)); } SByte8::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) { std::vector constantVector = { x0, x1, x2, x3, x4, x5, x6, x7 }; Value *vector = Nucleus::createConstantVector(constantVector, type()); storeValue(Nucleus::createBitCast(vector, type())); } SByte8::SByte8(RValue rhs) { store(rhs); } SByte8::SByte8(const SByte8 &rhs) { store(rhs.load()); } SByte8::SByte8(const Reference &rhs) { store(rhs.load()); } RValue SByte8::operator=(RValue rhs) { return store(rhs); } RValue SByte8::operator=(const SByte8 &rhs) { return store(rhs.load()); } RValue SByte8::operator=(const Reference &rhs) { return store(rhs.load()); } RValue operator+(RValue lhs, RValue rhs) { return RValue(Nucleus::createAdd(lhs.value(), rhs.value())); } RValue operator-(RValue lhs, RValue rhs) { return RValue(Nucleus::createSub(lhs.value(), rhs.value())); } // RValue operator*(RValue lhs, RValue rhs) // { // return RValue(Nucleus::createMul(lhs.value(), rhs.value())); // } // RValue operator/(RValue lhs, RValue rhs) // { // return RValue(Nucleus::createSDiv(lhs.value(), rhs.value())); // } // RValue operator%(RValue lhs, RValue rhs) // { // return RValue(Nucleus::createSRem(lhs.value(), rhs.value())); // } RValue operator&(RValue lhs, RValue rhs) { return RValue(Nucleus::createAnd(lhs.value(), rhs.value())); } RValue operator|(RValue lhs, RValue rhs) { return RValue(Nucleus::createOr(lhs.value(), rhs.value())); } RValue operator^(RValue lhs, RValue rhs) { return RValue(Nucleus::createXor(lhs.value(), rhs.value())); } // RValue operator<<(RValue lhs, unsigned char rhs) // { // return RValue(Nucleus::createShl(lhs.value(), rhs.value())); // } // RValue operator>>(RValue lhs, unsigned char rhs) // { // return RValue(Nucleus::createAShr(lhs.value(), rhs.value())); // } RValue operator+=(SByte8 &lhs, RValue rhs) { return lhs = lhs + rhs; } RValue operator-=(SByte8 &lhs, RValue rhs) { return lhs = lhs - rhs; } // RValue operator*=(SByte8 &lhs, RValue rhs) // { // return lhs = lhs * rhs; // } // RValue operator/=(SByte8 &lhs, RValue rhs) // { // return lhs = lhs / rhs; // } // RValue operator%=(SByte8 &lhs, RValue rhs) // { // return lhs = lhs % rhs; // } RValue operator&=(SByte8 &lhs, RValue rhs) { return lhs = lhs & rhs; } RValue operator|=(SByte8 &lhs, RValue rhs) { return lhs = lhs | rhs; } RValue operator^=(SByte8 &lhs, RValue rhs) { return lhs = lhs ^ rhs; } // RValue operator<<=(SByte8 &lhs, RValue rhs) // { // return lhs = lhs << rhs; // } // RValue operator>>=(SByte8 &lhs, RValue rhs) // { // return lhs = lhs >> rhs; // } // RValue operator+(RValue val) // { // return val; // } // RValue operator-(RValue val) // { // return RValue(Nucleus::createNeg(val.value())); // } RValue operator~(RValue val) { return RValue(Nucleus::createNot(val.value())); } RValue UnpackLow(RValue x, RValue y) { // TODO(b/148379603): Optimize narrowing swizzle. std::vector shuffle = { 0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23 }; // Real type is v16i8 return As(Nucleus::createShuffleVector(x.value(), y.value(), shuffle)); } RValue UnpackHigh(RValue x, RValue y) { // TODO(b/148379603): Optimize narrowing swizzle. std::vector shuffle = { 0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23 }; // Real type is v16i8 auto lowHigh = RValue(Nucleus::createShuffleVector(x.value(), y.value(), shuffle)); return As(Swizzle(As(lowHigh), 0x2323)); } Byte16::Byte16(RValue rhs) { store(rhs); } Byte16::Byte16(const Byte16 &rhs) { store(rhs.load()); } Byte16::Byte16(const Reference &rhs) { store(rhs.load()); } RValue Byte16::operator=(RValue rhs) { return store(rhs); } RValue Byte16::operator=(const Byte16 &rhs) { return store(rhs.load()); } RValue Byte16::operator=(const Reference &rhs) { return store(rhs.load()); } RValue Swizzle(RValue x, uint64_t select) { std::vector shuffle = { static_cast((select >> 60) & 0x0F), static_cast((select >> 56) & 0x0F), static_cast((select >> 52) & 0x0F), static_cast((select >> 48) & 0x0F), static_cast((select >> 44) & 0x0F), static_cast((select >> 40) & 0x0F), static_cast((select >> 36) & 0x0F), static_cast((select >> 32) & 0x0F), static_cast((select >> 28) & 0x0F), static_cast((select >> 24) & 0x0F), static_cast((select >> 20) & 0x0F), static_cast((select >> 16) & 0x0F), static_cast((select >> 12) & 0x0F), static_cast((select >> 8) & 0x0F), static_cast((select >> 4) & 0x0F), static_cast((select >> 0) & 0x0F), }; return As(Nucleus::createShuffleVector(x.value(), x.value(), shuffle)); } Short2::Short2(RValue cast) { storeValue(Nucleus::createBitCast(cast.value(), type())); } UShort2::UShort2(RValue cast) { storeValue(Nucleus::createBitCast(cast.value(), type())); } Short4::Short4(RValue cast) { Value *vector = loadValue(); Value *element = Nucleus::createTrunc(cast.value(), Short::type()); Value *insert = Nucleus::createInsertElement(vector, element, 0); Value *swizzle = Swizzle(RValue(insert), 0x0000).value(); storeValue(swizzle); } Short4::Short4(RValue cast) : Short4(As(cast)) { } // Short4::Short4(RValue cast) // { // } Short4::Short4(short xyzw) { std::vector constantVector = { xyzw }; storeValue(Nucleus::createConstantVector(constantVector, type())); } Short4::Short4(short x, short y, short z, short w) { std::vector constantVector = { x, y, z, w }; storeValue(Nucleus::createConstantVector(constantVector, type())); } Short4::Short4(RValue rhs) { store(rhs); } Short4::Short4(const Short4 &rhs) { store(rhs.load()); } Short4::Short4(const Reference &rhs) { store(rhs.load()); } Short4::Short4(RValue rhs) { storeValue(rhs.value()); } Short4::Short4(const UShort4 &rhs) { storeValue(rhs.loadValue()); } Short4::Short4(const Reference &rhs) { storeValue(rhs.loadValue()); } RValue Short4::operator=(RValue rhs) { return store(rhs); } RValue Short4::operator=(const Short4 &rhs) { return store(rhs.load()); } RValue Short4::operator=(const Reference &rhs) { return store(rhs.load()); } RValue Short4::operator=(RValue rhs) { return RValue(storeValue(rhs.value())); } RValue Short4::operator=(const UShort4 &rhs) { return RValue(storeValue(rhs.loadValue())); } RValue Short4::operator=(const Reference &rhs) { return RValue(storeValue(rhs.loadValue())); } RValue operator+(RValue lhs, RValue rhs) { return RValue(Nucleus::createAdd(lhs.value(), rhs.value())); } RValue operator-(RValue lhs, RValue rhs) { return RValue(Nucleus::createSub(lhs.value(), rhs.value())); } RValue operator*(RValue lhs, RValue rhs) { return RValue(Nucleus::createMul(lhs.value(), rhs.value())); } // RValue operator/(RValue lhs, RValue rhs) // { // return RValue(Nucleus::createSDiv(lhs.value(), rhs.value())); // } // RValue operator%(RValue lhs, RValue rhs) // { // return RValue(Nucleus::createSRem(lhs.value(), rhs.value())); // } RValue operator&(RValue lhs, RValue rhs) { return RValue(Nucleus::createAnd(lhs.value(), rhs.value())); } RValue operator|(RValue lhs, RValue rhs) { return RValue(Nucleus::createOr(lhs.value(), rhs.value())); } RValue operator^(RValue lhs, RValue rhs) { return RValue(Nucleus::createXor(lhs.value(), rhs.value())); } RValue operator+=(Short4 &lhs, RValue rhs) { return lhs = lhs + rhs; } RValue operator-=(Short4 &lhs, RValue rhs) { return lhs = lhs - rhs; } RValue operator*=(Short4 &lhs, RValue rhs) { return lhs = lhs * rhs; } // RValue operator/=(Short4 &lhs, RValue rhs) // { // return lhs = lhs / rhs; // } // RValue operator%=(Short4 &lhs, RValue rhs) // { // return lhs = lhs % rhs; // } RValue operator&=(Short4 &lhs, RValue rhs) { return lhs = lhs & rhs; } RValue operator|=(Short4 &lhs, RValue rhs) { return lhs = lhs | rhs; } RValue operator^=(Short4 &lhs, RValue rhs) { return lhs = lhs ^ rhs; } RValue operator<<=(Short4 &lhs, unsigned char rhs) { return lhs = lhs << rhs; } RValue operator>>=(Short4 &lhs, unsigned char rhs) { return lhs = lhs >> rhs; } // RValue operator+(RValue val) // { // return val; // } RValue operator-(RValue val) { return RValue(Nucleus::createNeg(val.value())); } RValue operator~(RValue val) { return RValue(Nucleus::createNot(val.value())); } RValue RoundShort4(RValue cast) { RValue int4 = RoundInt(cast); return As(PackSigned(int4, int4)); } RValue UnpackLow(RValue x, RValue y) { std::vector shuffle = { 0, 8, 1, 9, 2, 10, 3, 11 }; // Real type is v8i16 return As(Nucleus::createShuffleVector(x.value(), y.value(), shuffle)); } RValue UnpackHigh(RValue x, RValue y) { // TODO(b/148379603): Optimize narrowing swizzle. std::vector shuffle = { 0, 8, 1, 9, 2, 10, 3, 11 }; // Real type is v8i16 auto lowHigh = RValue(Nucleus::createShuffleVector(x.value(), y.value(), shuffle)); return As(Swizzle(As(lowHigh), 0x2323)); } RValue Swizzle(RValue x, uint16_t select) { // Real type is v8i16 // TODO(b/148379603): Optimize narrowing swizzle. std::vector shuffle = { (select >> 12) & 0x03, (select >> 8) & 0x03, (select >> 4) & 0x03, (select >> 0) & 0x03, (select >> 12) & 0x03, (select >> 8) & 0x03, (select >> 4) & 0x03, (select >> 0) & 0x03, }; return As(Nucleus::createShuffleVector(x.value(), x.value(), shuffle)); } RValue Insert(RValue val, RValue element, int i) { return RValue(Nucleus::createInsertElement(val.value(), element.value(), i)); } RValue Extract(RValue val, int i) { return RValue(Nucleus::createExtractElement(val.value(), Short::type(), i)); } UShort4::UShort4(RValue cast) : UShort4(As(cast)) { } UShort4::UShort4(RValue cast) { *this = Short4(cast); } UShort4::UShort4(unsigned short xyzw) { std::vector constantVector = { xyzw }; storeValue(Nucleus::createConstantVector(constantVector, type())); } UShort4::UShort4(unsigned short x, unsigned short y, unsigned short z, unsigned short w) { std::vector constantVector = { x, y, z, w }; storeValue(Nucleus::createConstantVector(constantVector, type())); } UShort4::UShort4(RValue rhs) { store(rhs); } UShort4::UShort4(const UShort4 &rhs) { store(rhs.load()); } UShort4::UShort4(const Reference &rhs) { store(rhs.load()); } UShort4::UShort4(RValue rhs) { storeValue(rhs.value()); } UShort4::UShort4(const Short4 &rhs) { storeValue(rhs.loadValue()); } UShort4::UShort4(const Reference &rhs) { storeValue(rhs.loadValue()); } RValue UShort4::operator=(RValue rhs) { return store(rhs); } RValue UShort4::operator=(const UShort4 &rhs) { return store(rhs.load()); } RValue UShort4::operator=(const Reference &rhs) { return store(rhs.load()); } RValue UShort4::operator=(RValue rhs) { return RValue(storeValue(rhs.value())); } RValue UShort4::operator=(const Short4 &rhs) { return RValue(storeValue(rhs.loadValue())); } RValue UShort4::operator=(const Reference &rhs) { return RValue(storeValue(rhs.loadValue())); } RValue operator+(RValue lhs, RValue rhs) { return RValue(Nucleus::createAdd(lhs.value(), rhs.value())); } RValue operator-(RValue lhs, RValue rhs) { return RValue(Nucleus::createSub(lhs.value(), rhs.value())); } RValue operator*(RValue lhs, RValue rhs) { return RValue(Nucleus::createMul(lhs.value(), rhs.value())); } RValue operator&(RValue lhs, RValue rhs) { return RValue(Nucleus::createAnd(lhs.value(), rhs.value())); } RValue operator|(RValue lhs, RValue rhs) { return RValue(Nucleus::createOr(lhs.value(), rhs.value())); } RValue operator^(RValue lhs, RValue rhs) { return RValue(Nucleus::createXor(lhs.value(), rhs.value())); } RValue operator<<=(UShort4 &lhs, unsigned char rhs) { return lhs = lhs << rhs; } RValue operator>>=(UShort4 &lhs, unsigned char rhs) { return lhs = lhs >> rhs; } RValue operator~(RValue val) { return RValue(Nucleus::createNot(val.value())); } RValue Insert(RValue val, RValue element, int i) { return RValue(Nucleus::createInsertElement(val.value(), element.value(), i)); } Short8::Short8(short c) { std::vector constantVector = { c }; storeValue(Nucleus::createConstantVector(constantVector, type())); } Short8::Short8(short c0, short c1, short c2, short c3, short c4, short c5, short c6, short c7) { std::vector constantVector = { c0, c1, c2, c3, c4, c5, c6, c7 }; storeValue(Nucleus::createConstantVector(constantVector, type())); } Short8::Short8(RValue rhs) { store(rhs); } Short8::Short8(const Reference &rhs) { store(rhs.load()); } Short8::Short8(RValue lo, RValue hi) { std::vector shuffle = { 0, 1, 2, 3, 8, 9, 10, 11 }; // Real type is v8i16 Value *packed = Nucleus::createShuffleVector(lo.value(), hi.value(), shuffle); storeValue(packed); } RValue Short8::operator=(RValue rhs) { return store(rhs); } RValue Short8::operator=(const Short8 &rhs) { return store(rhs.load()); } RValue Short8::operator=(const Reference &rhs) { return store(rhs.load()); } RValue operator+(RValue lhs, RValue rhs) { return RValue(Nucleus::createAdd(lhs.value(), rhs.value())); } RValue operator&(RValue lhs, RValue rhs) { return RValue(Nucleus::createAnd(lhs.value(), rhs.value())); } UShort8::UShort8(unsigned short c) { std::vector constantVector = { c }; storeValue(Nucleus::createConstantVector(constantVector, type())); } UShort8::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) { std::vector constantVector = { c0, c1, c2, c3, c4, c5, c6, c7 }; storeValue(Nucleus::createConstantVector(constantVector, type())); } UShort8::UShort8(RValue rhs) { store(rhs); } UShort8::UShort8(const Reference &rhs) { store(rhs.load()); } UShort8::UShort8(RValue lo, RValue hi) { std::vector shuffle = { 0, 1, 2, 3, 8, 9, 10, 11 }; // Real type is v8i16 Value *packed = Nucleus::createShuffleVector(lo.value(), hi.value(), shuffle); storeValue(packed); } RValue UShort8::operator=(RValue rhs) { return store(rhs); } RValue UShort8::operator=(const UShort8 &rhs) { return store(rhs.load()); } RValue UShort8::operator=(const Reference &rhs) { return store(rhs.load()); } RValue operator&(RValue lhs, RValue rhs) { return RValue(Nucleus::createAnd(lhs.value(), rhs.value())); } RValue operator+(RValue lhs, RValue rhs) { return RValue(Nucleus::createAdd(lhs.value(), rhs.value())); } RValue operator*(RValue lhs, RValue rhs) { return RValue(Nucleus::createMul(lhs.value(), rhs.value())); } RValue operator+=(UShort8 &lhs, RValue rhs) { return lhs = lhs + rhs; } RValue operator~(RValue val) { return RValue(Nucleus::createNot(val.value())); } RValue Swizzle(RValue x, uint32_t select) { std::vector swizzle = { static_cast((select >> 28) & 0x07), static_cast((select >> 24) & 0x07), static_cast((select >> 20) & 0x07), static_cast((select >> 16) & 0x07), static_cast((select >> 12) & 0x07), static_cast((select >> 8) & 0x07), static_cast((select >> 4) & 0x07), static_cast((select >> 0) & 0x07), }; return RValue(Nucleus::createShuffleVector(x.value(), x.value(), swizzle)); } Int::Int(Argument argument) { store(argument.rvalue()); } Int::Int(RValue cast) { Value *integer = Nucleus::createZExt(cast.value(), Int::type()); storeValue(integer); } Int::Int(RValue cast) { Value *integer = Nucleus::createSExt(cast.value(), Int::type()); storeValue(integer); } Int::Int(RValue cast) { Value *integer = Nucleus::createSExt(cast.value(), Int::type()); storeValue(integer); } Int::Int(RValue cast) { Value *integer = Nucleus::createZExt(cast.value(), Int::type()); storeValue(integer); } Int::Int(RValue cast) { *this = Extract(cast, 0); } Int::Int(RValue cast) { Value *integer = Nucleus::createTrunc(cast.value(), Int::type()); storeValue(integer); } Int::Int(RValue cast) { Value *integer = Nucleus::createFPToSI(cast.value(), Int::type()); storeValue(integer); } Int::Int(int x) { storeValue(Nucleus::createConstantInt(x)); } Int::Int(RValue rhs) { store(rhs); } Int::Int(RValue rhs) { storeValue(rhs.value()); } Int::Int(const Int &rhs) { store(rhs.load()); } Int::Int(const Reference &rhs) { store(rhs.load()); } Int::Int(const UInt &rhs) { storeValue(rhs.loadValue()); } Int::Int(const Reference &rhs) { storeValue(rhs.loadValue()); } RValue Int::operator=(int rhs) { return RValue(storeValue(Nucleus::createConstantInt(rhs))); } RValue Int::operator=(RValue rhs) { return store(rhs); } RValue Int::operator=(RValue rhs) { storeValue(rhs.value()); return RValue(rhs); } RValue Int::operator=(const Int &rhs) { return store(rhs.load()); } RValue Int::operator=(const Reference &rhs) { return store(rhs.load()); } RValue Int::operator=(const UInt &rhs) { return RValue(storeValue(rhs.loadValue())); } RValue Int::operator=(const Reference &rhs) { return RValue(storeValue(rhs.loadValue())); } RValue operator+(RValue lhs, RValue rhs) { return RValue(Nucleus::createAdd(lhs.value(), rhs.value())); } RValue operator-(RValue lhs, RValue rhs) { return RValue(Nucleus::createSub(lhs.value(), rhs.value())); } RValue operator*(RValue lhs, RValue rhs) { return RValue(Nucleus::createMul(lhs.value(), rhs.value())); } RValue operator/(RValue lhs, RValue rhs) { return RValue(Nucleus::createSDiv(lhs.value(), rhs.value())); } RValue operator%(RValue lhs, RValue rhs) { return RValue(Nucleus::createSRem(lhs.value(), rhs.value())); } RValue operator&(RValue lhs, RValue rhs) { return RValue(Nucleus::createAnd(lhs.value(), rhs.value())); } RValue operator|(RValue lhs, RValue rhs) { return RValue(Nucleus::createOr(lhs.value(), rhs.value())); } RValue operator^(RValue lhs, RValue rhs) { return RValue(Nucleus::createXor(lhs.value(), rhs.value())); } RValue operator<<(RValue lhs, RValue rhs) { return RValue(Nucleus::createShl(lhs.value(), rhs.value())); } RValue operator>>(RValue lhs, RValue rhs) { return RValue(Nucleus::createAShr(lhs.value(), rhs.value())); } RValue operator+=(Int &lhs, RValue rhs) { return lhs = lhs + rhs; } RValue operator-=(Int &lhs, RValue rhs) { return lhs = lhs - rhs; } RValue operator*=(Int &lhs, RValue rhs) { return lhs = lhs * rhs; } RValue operator/=(Int &lhs, RValue rhs) { return lhs = lhs / rhs; } RValue operator%=(Int &lhs, RValue rhs) { return lhs = lhs % rhs; } RValue operator&=(Int &lhs, RValue rhs) { return lhs = lhs & rhs; } RValue operator|=(Int &lhs, RValue rhs) { return lhs = lhs | rhs; } RValue operator^=(Int &lhs, RValue rhs) { return lhs = lhs ^ rhs; } RValue operator<<=(Int &lhs, RValue rhs) { return lhs = lhs << rhs; } RValue operator>>=(Int &lhs, RValue rhs) { return lhs = lhs >> rhs; } RValue operator+(RValue val) { return val; } RValue operator-(RValue val) { return RValue(Nucleus::createNeg(val.value())); } RValue operator~(RValue val) { return RValue(Nucleus::createNot(val.value())); } RValue operator<(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpSLT(lhs.value(), rhs.value())); } RValue operator<=(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpSLE(lhs.value(), rhs.value())); } RValue operator>(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpSGT(lhs.value(), rhs.value())); } RValue operator>=(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpSGE(lhs.value(), rhs.value())); } RValue operator!=(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpNE(lhs.value(), rhs.value())); } RValue operator==(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpEQ(lhs.value(), rhs.value())); } RValue Max(RValue x, RValue y) { return IfThenElse(x > y, x, y); } RValue Min(RValue x, RValue y) { return IfThenElse(x < y, x, y); } RValue Clamp(RValue x, RValue min, RValue max) { return Min(Max(x, min), max); } Long::Long(RValue cast) { Value *integer = Nucleus::createSExt(cast.value(), Long::type()); storeValue(integer); } Long::Long(RValue cast) { Value *integer = Nucleus::createZExt(cast.value(), Long::type()); storeValue(integer); } Long::Long(RValue rhs) { store(rhs); } RValue Long::operator=(int64_t rhs) { return RValue(storeValue(Nucleus::createConstantLong(rhs))); } RValue Long::operator=(RValue rhs) { return store(rhs); } RValue Long::operator=(const Long &rhs) { return store(rhs.load()); } RValue Long::operator=(const Reference &rhs) { return store(rhs.load()); } RValue operator+(RValue lhs, RValue rhs) { return RValue(Nucleus::createAdd(lhs.value(), rhs.value())); } RValue operator-(RValue lhs, RValue rhs) { return RValue(Nucleus::createSub(lhs.value(), rhs.value())); } RValue operator*(RValue lhs, RValue rhs) { return RValue(Nucleus::createMul(lhs.value(), rhs.value())); } RValue operator>>(RValue lhs, RValue rhs) { return RValue(Nucleus::createAShr(lhs.value(), rhs.value())); } RValue operator+=(Long &lhs, RValue rhs) { return lhs = lhs + rhs; } RValue operator-=(Long &lhs, RValue rhs) { return lhs = lhs - rhs; } RValue AddAtomic(RValue> x, RValue y) { return RValue(Nucleus::createAtomicAdd(x.value(), y.value())); } RValue AddAtomic(RValue> x, RValue y, std::memory_order memoryOrder) { return RValue(Nucleus::createAtomicAdd(x.value(), y.value(), memoryOrder)); } RValue SubAtomic(RValue> x, RValue y, std::memory_order memoryOrder) { return RValue(Nucleus::createAtomicSub(x.value(), y.value(), memoryOrder)); } RValue AndAtomic(RValue> x, RValue y, std::memory_order memoryOrder) { return RValue(Nucleus::createAtomicAnd(x.value(), y.value(), memoryOrder)); } RValue OrAtomic(RValue> x, RValue y, std::memory_order memoryOrder) { return RValue(Nucleus::createAtomicOr(x.value(), y.value(), memoryOrder)); } RValue XorAtomic(RValue> x, RValue y, std::memory_order memoryOrder) { return RValue(Nucleus::createAtomicXor(x.value(), y.value(), memoryOrder)); } RValue ExchangeAtomic(RValue> x, RValue y, std::memory_order memoryOrder) { return RValue(Nucleus::createAtomicExchange(x.value(), y.value(), memoryOrder)); } RValue CompareExchangeAtomic(RValue> x, RValue y, RValue compare, std::memory_order memoryOrderEqual, std::memory_order memoryOrderUnequal) { return RValue(Nucleus::createAtomicCompareExchange(x.value(), y.value(), compare.value(), memoryOrderEqual, memoryOrderUnequal)); } UInt::UInt(Argument argument) { store(argument.rvalue()); } UInt::UInt(RValue cast) { Value *integer = Nucleus::createZExt(cast.value(), UInt::type()); storeValue(integer); } UInt::UInt(RValue cast) { Value *integer = Nucleus::createTrunc(cast.value(), UInt::type()); storeValue(integer); } UInt::UInt(int x) { storeValue(Nucleus::createConstantInt(x)); } UInt::UInt(unsigned int x) { storeValue(Nucleus::createConstantInt(x)); } UInt::UInt(RValue rhs) { store(rhs); } UInt::UInt(RValue rhs) { storeValue(rhs.value()); } UInt::UInt(const UInt &rhs) { store(rhs.load()); } UInt::UInt(const Reference &rhs) { store(rhs.load()); } UInt::UInt(const Int &rhs) { storeValue(rhs.loadValue()); } UInt::UInt(const Reference &rhs) { storeValue(rhs.loadValue()); } RValue UInt::operator=(unsigned int rhs) { return RValue(storeValue(Nucleus::createConstantInt(rhs))); } RValue UInt::operator=(RValue rhs) { return store(rhs); } RValue UInt::operator=(RValue rhs) { storeValue(rhs.value()); return RValue(rhs); } RValue UInt::operator=(const UInt &rhs) { return store(rhs.load()); } RValue UInt::operator=(const Reference &rhs) { return store(rhs.load()); } RValue UInt::operator=(const Int &rhs) { return RValue(storeValue(rhs.loadValue())); } RValue UInt::operator=(const Reference &rhs) { return RValue(storeValue(rhs.loadValue())); } RValue operator+(RValue lhs, RValue rhs) { return RValue(Nucleus::createAdd(lhs.value(), rhs.value())); } RValue operator-(RValue lhs, RValue rhs) { return RValue(Nucleus::createSub(lhs.value(), rhs.value())); } RValue operator*(RValue lhs, RValue rhs) { return RValue(Nucleus::createMul(lhs.value(), rhs.value())); } RValue operator/(RValue lhs, RValue rhs) { return RValue(Nucleus::createUDiv(lhs.value(), rhs.value())); } RValue operator%(RValue lhs, RValue rhs) { return RValue(Nucleus::createURem(lhs.value(), rhs.value())); } RValue operator&(RValue lhs, RValue rhs) { return RValue(Nucleus::createAnd(lhs.value(), rhs.value())); } RValue operator|(RValue lhs, RValue rhs) { return RValue(Nucleus::createOr(lhs.value(), rhs.value())); } RValue operator^(RValue lhs, RValue rhs) { return RValue(Nucleus::createXor(lhs.value(), rhs.value())); } RValue operator<<(RValue lhs, RValue rhs) { return RValue(Nucleus::createShl(lhs.value(), rhs.value())); } RValue operator>>(RValue lhs, RValue rhs) { return RValue(Nucleus::createLShr(lhs.value(), rhs.value())); } RValue operator+=(UInt &lhs, RValue rhs) { return lhs = lhs + rhs; } RValue operator-=(UInt &lhs, RValue rhs) { return lhs = lhs - rhs; } RValue operator*=(UInt &lhs, RValue rhs) { return lhs = lhs * rhs; } RValue operator/=(UInt &lhs, RValue rhs) { return lhs = lhs / rhs; } RValue operator%=(UInt &lhs, RValue rhs) { return lhs = lhs % rhs; } RValue operator&=(UInt &lhs, RValue rhs) { return lhs = lhs & rhs; } RValue operator|=(UInt &lhs, RValue rhs) { return lhs = lhs | rhs; } RValue operator^=(UInt &lhs, RValue rhs) { return lhs = lhs ^ rhs; } RValue operator<<=(UInt &lhs, RValue rhs) { return lhs = lhs << rhs; } RValue operator>>=(UInt &lhs, RValue rhs) { return lhs = lhs >> rhs; } RValue operator+(RValue val) { return val; } RValue operator-(RValue val) { return RValue(Nucleus::createNeg(val.value())); } RValue operator~(RValue val) { return RValue(Nucleus::createNot(val.value())); } RValue Max(RValue x, RValue y) { return IfThenElse(x > y, x, y); } RValue Min(RValue x, RValue y) { return IfThenElse(x < y, x, y); } RValue Clamp(RValue x, RValue min, RValue max) { return Min(Max(x, min), max); } RValue operator<(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpULT(lhs.value(), rhs.value())); } RValue operator<=(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpULE(lhs.value(), rhs.value())); } RValue operator>(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpUGT(lhs.value(), rhs.value())); } RValue operator>=(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpUGE(lhs.value(), rhs.value())); } RValue operator!=(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpNE(lhs.value(), rhs.value())); } RValue operator==(RValue lhs, RValue rhs) { return RValue(Nucleus::createICmpEQ(lhs.value(), rhs.value())); } Int2::Int2(RValue cast) { storeValue(Nucleus::createBitCast(cast.value(), type())); } Int2::Int2(int x, int y) { std::vector constantVector = { x, y }; storeValue(Nucleus::createConstantVector(constantVector, type())); } Int2::Int2(RValue rhs) { store(rhs); } Int2::Int2(const Int2 &rhs) { store(rhs.load()); } Int2::Int2(const Reference &rhs) { store(rhs.load()); } Int2::Int2(RValue lo, RValue hi) { std::vector shuffle = { 0, 4, 1, 5 }; Value *packed = Nucleus::createShuffleVector(Int4(lo).loadValue(), Int4(hi).loadValue(), shuffle); storeValue(Nucleus::createBitCast(packed, Int2::type())); } RValue Int2::operator=(RValue rhs) { return store(rhs); } RValue Int2::operator=(const Int2 &rhs) { return store(rhs.load()); } RValue Int2::operator=(const Reference &rhs) { return store(rhs.load()); } RValue operator+(RValue lhs, RValue rhs) { return RValue(Nucleus::createAdd(lhs.value(), rhs.value())); } RValue operator-(RValue lhs, RValue rhs) { return RValue(Nucleus::createSub(lhs.value(), rhs.value())); } // RValue operator*(RValue lhs, RValue rhs) // { // return RValue(Nucleus::createMul(lhs.value(), rhs.value())); // } // RValue operator/(RValue lhs, RValue rhs) // { // return RValue(Nucleus::createSDiv(lhs.value(), rhs.value())); // } // RValue operator%(RValue lhs, RValue rhs) // { // return RValue(Nucleus::createSRem(lhs.value(), rhs.value())); // } RValue operator&(RValue lhs, RValue rhs) { return RValue(Nucleus::createAnd(lhs.value(), rhs.value())); } RValue operator|(RValue lhs, RValue rhs) { return RValue(Nucleus::createOr(lhs.value(), rhs.value())); } RValue operator^(RValue lhs, RValue rhs) { return RValue(Nucleus::createXor(lhs.value(), rhs.value())); } RValue operator+=(Int2 &lhs, RValue rhs) { return lhs = lhs + rhs; } RValue operator-=(Int2 &lhs, RValue rhs) { return lhs = lhs - rhs; } // RValue operator*=(Int2 &lhs, RValue rhs) // { // return lhs = lhs * rhs; // } // RValue operator/=(Int2 &lhs, RValue rhs) // { // return lhs = lhs / rhs; // } // RValue operator%=(Int2 &lhs, RValue rhs) // { // return lhs = lhs % rhs; // } RValue operator&=(Int2 &lhs, RValue rhs) { return lhs = lhs & rhs; } RValue operator|=(Int2 &lhs, RValue rhs) { return lhs = lhs | rhs; } RValue operator^=(Int2 &lhs, RValue rhs) { return lhs = lhs ^ rhs; } RValue operator<<=(Int2 &lhs, unsigned char rhs) { return lhs = lhs << rhs; } RValue operator>>=(Int2 &lhs, unsigned char rhs) { return lhs = lhs >> rhs; } // RValue operator+(RValue val) // { // return val; // } // RValue operator-(RValue val) // { // return RValue(Nucleus::createNeg(val.value())); // } RValue operator~(RValue val) { return RValue(Nucleus::createNot(val.value())); } RValue UnpackLow(RValue x, RValue y) { // TODO(b/148379603): Optimize narrowing swizzle. std::vector shuffle = { 0, 4, 1, 5 }; // Real type is v4i32 return As(Nucleus::createShuffleVector(x.value(), y.value(), shuffle)); } RValue UnpackHigh(RValue x, RValue y) { // TODO(b/148379603): Optimize narrowing swizzle. std::vector shuffle = { 0, 4, 1, 5 }; // Real type is v4i32 auto lowHigh = RValue(Nucleus::createShuffleVector(x.value(), y.value(), shuffle)); return As(Swizzle(lowHigh, 0x2323)); } RValue Extract(RValue val, int i) { return RValue(Nucleus::createExtractElement(val.value(), Int::type(), i)); } RValue Insert(RValue val, RValue element, int i) { return RValue(Nucleus::createInsertElement(val.value(), element.value(), i)); } UInt2::UInt2(unsigned int x, unsigned int y) { std::vector constantVector = { x, y }; storeValue(Nucleus::createConstantVector(constantVector, type())); } UInt2::UInt2(RValue rhs) { store(rhs); } UInt2::UInt2(const UInt2 &rhs) { store(rhs.load()); } UInt2::UInt2(const Reference &rhs) { store(rhs.load()); } RValue UInt2::operator=(RValue rhs) { return store(rhs); } RValue UInt2::operator=(const UInt2 &rhs) { return store(rhs.load()); } RValue UInt2::operator=(const Reference &rhs) { return store(rhs.load()); } RValue operator+(RValue lhs, RValue rhs) { return RValue(Nucleus::createAdd(lhs.value(), rhs.value())); } RValue operator-(RValue lhs, RValue rhs) { return RValue(Nucleus::createSub(lhs.value(), rhs.value())); } // RValue operator*(RValue lhs, RValue rhs) // { // return RValue(Nucleus::createMul(lhs.value(), rhs.value())); // } // RValue operator/(RValue lhs, RValue rhs) // { // return RValue(Nucleus::createUDiv(lhs.value(), rhs.value())); // } // RValue operator%(RValue lhs, RValue rhs) // { // return RValue(Nucleus::createURem(lhs.value(), rhs.value())); // } RValue operator&(RValue lhs, RValue rhs) { return RValue(Nucleus::createAnd(lhs.value(), rhs.value())); } RValue operator|(RValue lhs, RValue rhs) { return RValue(Nucleus::createOr(lhs.value(), rhs.value())); } RValue operator^(RValue lhs, RValue rhs) { return RValue(Nucleus::createXor(lhs.value(), rhs.value())); } RValue operator+=(UInt2 &lhs, RValue rhs) { return lhs = lhs + rhs; } RValue operator-=(UInt2 &lhs, RValue rhs) { return lhs = lhs - rhs; } // RValue operator*=(UInt2 &lhs, RValue rhs) // { // return lhs = lhs * rhs; // } // RValue operator/=(UInt2 &lhs, RValue rhs) // { // return lhs = lhs / rhs; // } // RValue operator%=(UInt2 &lhs, RValue rhs) // { // return lhs = lhs % rhs; // } RValue operator&=(UInt2 &lhs, RValue rhs) { return lhs = lhs & rhs; } RValue operator|=(UInt2 &lhs, RValue rhs) { return lhs = lhs | rhs; } RValue operator^=(UInt2 &lhs, RValue rhs) { return lhs = lhs ^ rhs; } RValue operator<<=(UInt2 &lhs, unsigned char rhs) { return lhs = lhs << rhs; } RValue operator>>=(UInt2 &lhs, unsigned char rhs) { return lhs = lhs >> rhs; } // RValue operator+(RValue val) // { // return val; // } // RValue operator-(RValue val) // { // return RValue(Nucleus::createNeg(val.value())); // } RValue operator~(RValue val) { return RValue(Nucleus::createNot(val.value())); } RValue Extract(RValue val, int i) { return RValue(Nucleus::createExtractElement(val.value(), UInt::type(), i)); } RValue Insert(RValue val, RValue element, int i) { return RValue(Nucleus::createInsertElement(val.value(), element.value(), i)); } Int4::Int4() : XYZW(this) { } Int4::Int4(RValue cast) : XYZW(this) { Value *xyzw = Nucleus::createFPToSI(cast.value(), Int4::type()); storeValue(xyzw); } Int4::Int4(int xyzw) : XYZW(this) { constant(xyzw, xyzw, xyzw, xyzw); } Int4::Int4(int x, int yzw) : XYZW(this) { constant(x, yzw, yzw, yzw); } Int4::Int4(int x, int y, int zw) : XYZW(this) { constant(x, y, zw, zw); } Int4::Int4(int x, int y, int z, int w) : XYZW(this) { constant(x, y, z, w); } void Int4::constant(int x, int y, int z, int w) { std::vector constantVector = { x, y, z, w }; storeValue(Nucleus::createConstantVector(constantVector, type())); } Int4::Int4(RValue rhs) : XYZW(this) { store(rhs); } Int4::Int4(const Int4 &rhs) : XYZW(this) { store(rhs.load()); } Int4::Int4(const Reference &rhs) : XYZW(this) { store(rhs.load()); } Int4::Int4(RValue rhs) : XYZW(this) { storeValue(rhs.value()); } Int4::Int4(const UInt4 &rhs) : XYZW(this) { storeValue(rhs.loadValue()); } Int4::Int4(const Reference &rhs) : XYZW(this) { storeValue(rhs.loadValue()); } Int4::Int4(RValue lo, RValue hi) : XYZW(this) { std::vector shuffle = { 0, 1, 4, 5 }; // Real type is v4i32 Value *packed = Nucleus::createShuffleVector(lo.value(), hi.value(), shuffle); storeValue(packed); } Int4::Int4(const Int &rhs) : XYZW(this) { *this = RValue(rhs.loadValue()); } Int4::Int4(const Reference &rhs) : XYZW(this) { *this = RValue(rhs.loadValue()); } RValue Int4::operator=(int x) { return *this = Int4(x, x, x, x); } RValue Int4::operator=(RValue rhs) { return store(rhs); } RValue Int4::operator=(const Int4 &rhs) { return store(rhs.load()); } RValue Int4::operator=(const Reference &rhs) { return store(rhs.load()); } RValue operator+(RValue lhs, RValue rhs) { return RValue(Nucleus::createAdd(lhs.value(), rhs.value())); } RValue operator-(RValue lhs, RValue rhs) { return RValue(Nucleus::createSub(lhs.value(), rhs.value())); } RValue operator*(RValue lhs, RValue rhs) { return RValue(Nucleus::createMul(lhs.value(), rhs.value())); } RValue operator/(RValue lhs, RValue rhs) { return RValue(Nucleus::createSDiv(lhs.value(), rhs.value())); } RValue operator%(RValue lhs, RValue rhs) { return RValue(Nucleus::createSRem(lhs.value(), rhs.value())); } RValue operator&(RValue lhs, RValue rhs) { return RValue(Nucleus::createAnd(lhs.value(), rhs.value())); } RValue operator|(RValue lhs, RValue rhs) { return RValue(Nucleus::createOr(lhs.value(), rhs.value())); } RValue operator^(RValue lhs, RValue rhs) { return RValue(Nucleus::createXor(lhs.value(), rhs.value())); } RValue operator<<(RValue lhs, RValue rhs) { return RValue(Nucleus::createShl(lhs.value(), rhs.value())); } RValue operator>>(RValue lhs, RValue rhs) { return RValue(Nucleus::createAShr(lhs.value(), rhs.value())); } RValue operator+=(Int4 &lhs, RValue rhs) { return lhs = lhs + rhs; } RValue operator-=(Int4 &lhs, RValue rhs) { return lhs = lhs - rhs; } RValue operator*=(Int4 &lhs, RValue rhs) { return lhs = lhs * rhs; } // RValue operator/=(Int4 &lhs, RValue rhs) // { // return lhs = lhs / rhs; // } // RValue operator%=(Int4 &lhs, RValue rhs) // { // return lhs = lhs % rhs; // } RValue operator&=(Int4 &lhs, RValue rhs) { return lhs = lhs & rhs; } RValue operator|=(Int4 &lhs, RValue rhs) { return lhs = lhs | rhs; } RValue operator^=(Int4 &lhs, RValue rhs) { return lhs = lhs ^ rhs; } RValue operator<<=(Int4 &lhs, unsigned char rhs) { return lhs = lhs << rhs; } RValue operator>>=(Int4 &lhs, unsigned char rhs) { return lhs = lhs >> rhs; } RValue operator+(RValue val) { return val; } RValue operator-(RValue val) { return RValue(Nucleus::createNeg(val.value())); } RValue operator~(RValue val) { return RValue(Nucleus::createNot(val.value())); } RValue Extract(RValue x, int i) { return RValue(Nucleus::createExtractElement(x.value(), Int::type(), i)); } RValue Insert(RValue x, RValue element, int i) { return RValue(Nucleus::createInsertElement(x.value(), element.value(), i)); } RValue Swizzle(RValue x, uint16_t select) { return RValue(createSwizzle4(x.value(), select)); } RValue Shuffle(RValue x, RValue y, unsigned short select) { return RValue(createShuffle4(x.value(), y.value(), select)); } UInt4::UInt4() : XYZW(this) { } UInt4::UInt4(int xyzw) : XYZW(this) { constant(xyzw, xyzw, xyzw, xyzw); } UInt4::UInt4(int x, int yzw) : XYZW(this) { constant(x, yzw, yzw, yzw); } UInt4::UInt4(int x, int y, int zw) : XYZW(this) { constant(x, y, zw, zw); } UInt4::UInt4(int x, int y, int z, int w) : XYZW(this) { constant(x, y, z, w); } void UInt4::constant(int x, int y, int z, int w) { std::vector constantVector = { x, y, z, w }; storeValue(Nucleus::createConstantVector(constantVector, type())); } UInt4::UInt4(RValue rhs) : XYZW(this) { store(rhs); } UInt4::UInt4(const UInt4 &rhs) : XYZW(this) { store(rhs.load()); } UInt4::UInt4(const Reference &rhs) : XYZW(this) { store(rhs.load()); } UInt4::UInt4(RValue rhs) : XYZW(this) { storeValue(rhs.value()); } UInt4::UInt4(const Int4 &rhs) : XYZW(this) { storeValue(rhs.loadValue()); } UInt4::UInt4(const Reference &rhs) : XYZW(this) { storeValue(rhs.loadValue()); } UInt4::UInt4(RValue lo, RValue hi) : XYZW(this) { std::vector shuffle = { 0, 1, 4, 5 }; // Real type is v4i32 Value *packed = Nucleus::createShuffleVector(lo.value(), hi.value(), shuffle); storeValue(packed); } UInt4::UInt4(const UInt &rhs) : XYZW(this) { *this = RValue(rhs.loadValue()); } UInt4::UInt4(const Reference &rhs) : XYZW(this) { *this = RValue(rhs.loadValue()); } RValue UInt4::operator=(RValue rhs) { return store(rhs); } RValue UInt4::operator=(const UInt4 &rhs) { return store(rhs.load()); } RValue UInt4::operator=(const Reference &rhs) { return store(rhs.load()); } RValue operator+(RValue lhs, RValue rhs) { return RValue(Nucleus::createAdd(lhs.value(), rhs.value())); } RValue operator-(RValue lhs, RValue rhs) { return RValue(Nucleus::createSub(lhs.value(), rhs.value())); } RValue operator*(RValue lhs, RValue rhs) { return RValue(Nucleus::createMul(lhs.value(), rhs.value())); } RValue operator/(RValue lhs, RValue rhs) { return RValue(Nucleus::createUDiv(lhs.value(), rhs.value())); } RValue operator%(RValue lhs, RValue rhs) { return RValue(Nucleus::createURem(lhs.value(), rhs.value())); } RValue operator&(RValue lhs, RValue rhs) { return RValue(Nucleus::createAnd(lhs.value(), rhs.value())); } RValue operator|(RValue lhs, RValue rhs) { return RValue(Nucleus::createOr(lhs.value(), rhs.value())); } RValue operator^(RValue lhs, RValue rhs) { return RValue(Nucleus::createXor(lhs.value(), rhs.value())); } RValue operator<<(RValue lhs, RValue rhs) { return RValue(Nucleus::createShl(lhs.value(), rhs.value())); } RValue operator>>(RValue lhs, RValue rhs) { return RValue(Nucleus::createLShr(lhs.value(), rhs.value())); } RValue operator+=(UInt4 &lhs, RValue rhs) { return lhs = lhs + rhs; } RValue operator-=(UInt4 &lhs, RValue rhs) { return lhs = lhs - rhs; } RValue operator*=(UInt4 &lhs, RValue rhs) { return lhs = lhs * rhs; } // RValue operator/=(UInt4 &lhs, RValue rhs) // { // return lhs = lhs / rhs; // } // RValue operator%=(UInt4 &lhs, RValue rhs) // { // return lhs = lhs % rhs; // } RValue operator&=(UInt4 &lhs, RValue rhs) { return lhs = lhs & rhs; } RValue operator|=(UInt4 &lhs, RValue rhs) { return lhs = lhs | rhs; } RValue operator^=(UInt4 &lhs, RValue rhs) { return lhs = lhs ^ rhs; } RValue operator<<=(UInt4 &lhs, unsigned char rhs) { return lhs = lhs << rhs; } RValue operator>>=(UInt4 &lhs, unsigned char rhs) { return lhs = lhs >> rhs; } RValue operator+(RValue val) { return val; } RValue operator-(RValue val) { return RValue(Nucleus::createNeg(val.value())); } RValue operator~(RValue val) { return RValue(Nucleus::createNot(val.value())); } RValue Extract(RValue x, int i) { return RValue(Nucleus::createExtractElement(x.value(), Int::type(), i)); } RValue Insert(RValue x, RValue element, int i) { return RValue(Nucleus::createInsertElement(x.value(), element.value(), i)); } RValue Swizzle(RValue x, uint16_t select) { return RValue(createSwizzle4(x.value(), select)); } RValue Shuffle(RValue x, RValue y, unsigned short select) { return RValue(createShuffle4(x.value(), y.value(), select)); } Half::Half(RValue cast) { UInt fp32i = As(cast); UInt abs = fp32i & 0x7FFFFFFF; UShort fp16i((fp32i & 0x80000000) >> 16); // sign If(abs > 0x47FFEFFF) // Infinity { fp16i |= UShort(0x7FFF); } Else { If(abs < 0x38800000) // Denormal { Int mantissa = (abs & 0x007FFFFF) | 0x00800000; Int e = 113 - (abs >> 23); abs = IfThenElse(e < 24, (mantissa >> e), Int(0)); fp16i |= UShort((abs + 0x00000FFF + ((abs >> 13) & 1)) >> 13); } Else { fp16i |= UShort((abs + 0xC8000000 + 0x00000FFF + ((abs >> 13) & 1)) >> 13); } } storeValue(fp16i.loadValue()); } Float::Float(RValue cast) { Value *integer = Nucleus::createSIToFP(cast.value(), Float::type()); storeValue(integer); } Float::Float(RValue cast) { RValue result = Float(Int(cast & UInt(0x7FFFFFFF))) + As((As(cast) >> 31) & As(Float(0x80000000u))); storeValue(result.value()); } Float::Float(RValue cast) { Int fp16i(As(cast)); Int s = (fp16i >> 15) & 0x00000001; Int e = (fp16i >> 10) & 0x0000001F; Int m = fp16i & 0x000003FF; UInt fp32i(s << 31); If(e == 0) { If(m != 0) { While((m & 0x00000400) == 0) { m <<= 1; e -= 1; } fp32i |= As(((e + (127 - 15) + 1) << 23) | ((m & ~0x00000400) << 13)); } } Else { fp32i |= As(((e + (127 - 15)) << 23) | (m << 13)); } storeValue(As(fp32i).value()); } Float::Float(float x) { // C++ does not have a way to write an infinite or NaN literal, // nor does it allow division by zero as a constant expression. // Thus we should not accept inf or NaN as a Reactor Float constant, // as this would typically idicate a bug, and avoids undefined // behavior. // // This also prevents the issue of the LLVM JIT only taking double // values for constructing floating-point constants. During the // conversion from single-precision to double, a signaling NaN can // become a quiet NaN, thus altering its bit pattern. Hence this // assert is also helpful for detecting cases where integers are // being reinterpreted as float and then bitcast to integer again, // which does not guarantee preserving the integer value. // // The inifinity() method can be used to obtain positive infinity. // Should NaN constants be required, methods like quiet_NaN() and // signaling_NaN() should be added (matching std::numeric_limits). ASSERT(std::isfinite(x)); storeValue(Nucleus::createConstantFloat(x)); } // TODO(b/140302841): Negative infinity can be obtained by using '-infinity()'. // This comes at a minor run-time JIT cost, and the backend may or may not // perform constant folding. This can be optimized by having Reactor perform // the folding, which would still be cheaper than having a capable backend do it. Float Float::infinity() { Float result; constexpr double inf = std::numeric_limits::infinity(); result.storeValue(Nucleus::createConstantFloat(inf)); return result; } Float::Float(RValue rhs) { store(rhs); } Float::Float(const Float &rhs) { store(rhs.load()); } Float::Float(const Reference &rhs) { store(rhs.load()); } Float::Float(Argument argument) { store(argument.rvalue()); } RValue Float::operator=(float rhs) { return RValue(storeValue(Nucleus::createConstantFloat(rhs))); } RValue Float::operator=(RValue rhs) { return store(rhs); } RValue Float::operator=(const Float &rhs) { return store(rhs.load()); } RValue Float::operator=(const Reference &rhs) { return store(rhs.load()); } RValue operator+(RValue lhs, RValue rhs) { return RValue(Nucleus::createFAdd(lhs.value(), rhs.value())); } RValue operator-(RValue lhs, RValue rhs) { return RValue(Nucleus::createFSub(lhs.value(), rhs.value())); } RValue operator*(RValue lhs, RValue rhs) { return RValue(Nucleus::createFMul(lhs.value(), rhs.value())); } RValue operator/(RValue lhs, RValue rhs) { return RValue(Nucleus::createFDiv(lhs.value(), rhs.value())); } RValue operator+=(Float &lhs, RValue rhs) { return lhs = lhs + rhs; } RValue operator-=(Float &lhs, RValue rhs) { return lhs = lhs - rhs; } RValue operator*=(Float &lhs, RValue rhs) { return lhs = lhs * rhs; } RValue operator/=(Float &lhs, RValue rhs) { return lhs = lhs / rhs; } RValue operator+(RValue val) { return val; } RValue operator-(RValue val) { return RValue(Nucleus::createFNeg(val.value())); } RValue operator<(RValue lhs, RValue rhs) { return RValue(Nucleus::createFCmpOLT(lhs.value(), rhs.value())); } RValue operator<=(RValue lhs, RValue rhs) { return RValue(Nucleus::createFCmpOLE(lhs.value(), rhs.value())); } RValue operator>(RValue lhs, RValue rhs) { return RValue(Nucleus::createFCmpOGT(lhs.value(), rhs.value())); } RValue operator>=(RValue lhs, RValue rhs) { return RValue(Nucleus::createFCmpOGE(lhs.value(), rhs.value())); } RValue operator!=(RValue lhs, RValue rhs) { return RValue(Nucleus::createFCmpONE(lhs.value(), rhs.value())); } RValue operator==(RValue lhs, RValue rhs) { return RValue(Nucleus::createFCmpOEQ(lhs.value(), rhs.value())); } RValue Abs(RValue x) { return IfThenElse(x > 0.0f, x, -x); } RValue Max(RValue x, RValue y) { return IfThenElse(x > y, x, y); } RValue Min(RValue x, RValue y) { return IfThenElse(x < y, x, y); } Float2::Float2(RValue cast) { storeValue(Nucleus::createBitCast(cast.value(), type())); } Float4::Float4(RValue cast) : XYZW(this) { Value *a = Int4(cast).loadValue(); Value *xyzw = Nucleus::createSIToFP(a, Float4::type()); storeValue(xyzw); } Float4::Float4(RValue cast) : XYZW(this) { Value *a = Int4(cast).loadValue(); Value *xyzw = Nucleus::createSIToFP(a, Float4::type()); storeValue(xyzw); } Float4::Float4(RValue cast) : XYZW(this) { Int4 c(cast); storeValue(Nucleus::createSIToFP(RValue(c).value(), Float4::type())); } Float4::Float4(RValue cast) : XYZW(this) { Int4 c(cast); storeValue(Nucleus::createSIToFP(RValue(c).value(), Float4::type())); } Float4::Float4(RValue cast) : XYZW(this) { Value *xyzw = Nucleus::createSIToFP(cast.value(), Float4::type()); storeValue(xyzw); } Float4::Float4(RValue cast) : XYZW(this) { RValue result = Float4(Int4(cast & UInt4(0x7FFFFFFF))) + As((As(cast) >> 31) & As(Float4(0x80000000u))); storeValue(result.value()); } Float4::Float4() : XYZW(this) { } Float4::Float4(float xyzw) : XYZW(this) { constant(xyzw, xyzw, xyzw, xyzw); } Float4::Float4(float x, float yzw) : XYZW(this) { constant(x, yzw, yzw, yzw); } Float4::Float4(float x, float y, float zw) : XYZW(this) { constant(x, y, zw, zw); } Float4::Float4(float x, float y, float z, float w) : XYZW(this) { constant(x, y, z, w); } Float4 Float4::infinity() { Float4 result; constexpr double inf = std::numeric_limits::infinity(); std::vector constantVector = { inf }; result.storeValue(Nucleus::createConstantVector(constantVector, type())); return result; } void Float4::constant(float x, float y, float z, float w) { // See Float(float) constructor for the rationale behind this assert. ASSERT(std::isfinite(x) && std::isfinite(y) && std::isfinite(z) && std::isfinite(w)); std::vector constantVector = { x, y, z, w }; storeValue(Nucleus::createConstantVector(constantVector, type())); } Float4::Float4(RValue rhs) : XYZW(this) { store(rhs); } Float4::Float4(const Float4 &rhs) : XYZW(this) { store(rhs.load()); } Float4::Float4(const Reference &rhs) : XYZW(this) { store(rhs.load()); } Float4::Float4(const Float &rhs) : XYZW(this) { *this = RValue(rhs.loadValue()); } Float4::Float4(const Reference &rhs) : XYZW(this) { *this = RValue(rhs.loadValue()); } Float4::Float4(RValue lo, RValue hi) : XYZW(this) { std::vector shuffle = { 0, 1, 4, 5 }; // Real type is v4i32 Value *packed = Nucleus::createShuffleVector(lo.value(), hi.value(), shuffle); storeValue(packed); } RValue Float4::operator=(float x) { return *this = Float4(x, x, x, x); } RValue Float4::operator=(RValue rhs) { return store(rhs); } RValue Float4::operator=(const Float4 &rhs) { return store(rhs.load()); } RValue Float4::operator=(const Reference &rhs) { return store(rhs.load()); } RValue Float4::operator=(RValue rhs) { return *this = Float4(rhs); } RValue Float4::operator=(const Float &rhs) { return *this = Float4(rhs); } RValue Float4::operator=(const Reference &rhs) { return *this = Float4(rhs); } RValue operator+(RValue lhs, RValue rhs) { return RValue(Nucleus::createFAdd(lhs.value(), rhs.value())); } RValue operator-(RValue lhs, RValue rhs) { return RValue(Nucleus::createFSub(lhs.value(), rhs.value())); } RValue operator*(RValue lhs, RValue rhs) { return RValue(Nucleus::createFMul(lhs.value(), rhs.value())); } RValue operator/(RValue lhs, RValue rhs) { return RValue(Nucleus::createFDiv(lhs.value(), rhs.value())); } RValue operator+=(Float4 &lhs, RValue rhs) { return lhs = lhs + rhs; } RValue operator-=(Float4 &lhs, RValue rhs) { return lhs = lhs - rhs; } RValue operator*=(Float4 &lhs, RValue rhs) { return lhs = lhs * rhs; } RValue operator/=(Float4 &lhs, RValue rhs) { return lhs = lhs / rhs; } RValue operator%=(Float4 &lhs, RValue rhs) { return lhs = lhs % rhs; } RValue operator+(RValue val) { return val; } RValue operator-(RValue val) { return RValue(Nucleus::createFNeg(val.value())); } RValue Insert(RValue x, RValue element, int i) { return RValue(Nucleus::createInsertElement(x.value(), element.value(), i)); } RValue Extract(RValue x, int i) { return RValue(Nucleus::createExtractElement(x.value(), Float::type(), i)); } RValue Swizzle(RValue x, uint16_t select) { return RValue(createSwizzle4(x.value(), select)); } RValue Shuffle(RValue x, RValue y, uint16_t select) { return RValue(createShuffle4(x.value(), y.value(), select)); } RValue ShuffleLowHigh(RValue x, RValue y, uint16_t imm) { std::vector shuffle = { ((imm >> 12) & 0x03) + 0, ((imm >> 8) & 0x03) + 0, ((imm >> 4) & 0x03) + 4, ((imm >> 0) & 0x03) + 4, }; return RValue(Nucleus::createShuffleVector(x.value(), y.value(), shuffle)); } RValue UnpackLow(RValue x, RValue y) { std::vector shuffle = { 0, 4, 1, 5 }; return RValue(Nucleus::createShuffleVector(x.value(), y.value(), shuffle)); } RValue UnpackHigh(RValue x, RValue y) { std::vector shuffle = { 2, 6, 3, 7 }; return RValue(Nucleus::createShuffleVector(x.value(), y.value(), shuffle)); } RValue Mask(Float4 &lhs, RValue rhs, uint16_t select) { Value *vector = lhs.loadValue(); Value *result = createMask4(vector, rhs.value(), select); lhs.storeValue(result); return RValue(result); } RValue IsInf(RValue x) { return CmpEQ(As(x) & Int4(0x7FFFFFFF), Int4(0x7F800000)); } RValue IsNan(RValue x) { return ~CmpEQ(x, x); } RValue Exp2(RValue x) { return Call(exp2f, x); } RValue Log2(RValue x) { return Call(log2f, x); } RValue Sin(RValue x) { return ScalarizeCall(sinf, x); } RValue Cos(RValue x) { return ScalarizeCall(cosf, x); } RValue Tan(RValue x) { return ScalarizeCall(tanf, x); } RValue Asin(RValue x) { return ScalarizeCall(asinf, x); } RValue Acos(RValue x) { return ScalarizeCall(acosf, x); } RValue Atan(RValue x) { return ScalarizeCall(atanf, x); } RValue Sinh(RValue x) { return ScalarizeCall(sinhf, x); } RValue Cosh(RValue x) { return ScalarizeCall(coshf, x); } RValue Tanh(RValue x) { return ScalarizeCall(tanhf, x); } RValue Asinh(RValue x) { return ScalarizeCall(asinhf, x); } RValue Acosh(RValue x) { return ScalarizeCall(acoshf, x); } RValue Atanh(RValue x) { return ScalarizeCall(atanhf, x); } RValue Atan2(RValue x, RValue y) { return ScalarizeCall(atan2f, x, y); } RValue Pow(RValue x, RValue y) { return ScalarizeCall(powf, x, y); } RValue Exp(RValue x) { return ScalarizeCall(expf, x); } RValue Log(RValue x) { return ScalarizeCall(logf, x); } RValue Exp2(RValue x) { return ScalarizeCall(exp2f, x); } RValue Log2(RValue x) { return ScalarizeCall(log2f, x); } RValue> operator+(RValue> lhs, int offset) { return lhs + RValue(Nucleus::createConstantInt(offset)); } RValue> operator+(RValue> lhs, RValue offset) { return RValue>(Nucleus::createGEP(lhs.value(), Byte::type(), offset.value(), false)); } RValue> operator+(RValue> lhs, RValue offset) { return RValue>(Nucleus::createGEP(lhs.value(), Byte::type(), offset.value(), true)); } RValue> operator+=(Pointer &lhs, int offset) { return lhs = lhs + offset; } RValue> operator+=(Pointer &lhs, RValue offset) { return lhs = lhs + offset; } RValue> operator+=(Pointer &lhs, RValue offset) { return lhs = lhs + offset; } RValue> operator-(RValue> lhs, int offset) { return lhs + -offset; } RValue> operator-(RValue> lhs, RValue offset) { return lhs + -offset; } RValue> operator-(RValue> lhs, RValue offset) { return lhs + -offset; } RValue> operator-=(Pointer &lhs, int offset) { return lhs = lhs - offset; } RValue> operator-=(Pointer &lhs, RValue offset) { return lhs = lhs - offset; } RValue> operator-=(Pointer &lhs, RValue offset) { return lhs = lhs - offset; } RValue AnyTrue(const RValue &bools) { return SignMask(bools) != 0; } RValue AnyFalse(const RValue &bools) { return SignMask(~bools) != 0; // TODO(b/214588983): Compare against mask of 4 1's to avoid bitwise NOT. } RValue AllTrue(const RValue &bools) { return SignMask(~bools) == 0; // TODO(b/214588983): Compare against mask of 4 1's to avoid bitwise NOT. } RValue AllFalse(const RValue &bools) { return SignMask(bools) == 0; } RValue Divergent(const RValue &ints) { auto broadcastFirst = Int4(Extract(ints, 0)); return AnyTrue(CmpNEQ(broadcastFirst, ints)); } RValue Divergent(const RValue &floats) { auto broadcastFirst = Float4(Extract(floats, 0)); return AnyTrue(CmpNEQ(broadcastFirst, floats)); } RValue Uniform(const RValue &ints) { auto broadcastFirst = Int4(Extract(ints, 0)); return AllFalse(CmpNEQ(broadcastFirst, ints)); } RValue Uniform(const RValue &floats) { auto broadcastFirst = Float4(Extract(floats, 0)); return AllFalse(CmpNEQ(broadcastFirst, floats)); } void Return() { Nucleus::createRetVoid(); // Place any unreachable instructions in an unreferenced block. Nucleus::setInsertBlock(Nucleus::createBasicBlock()); } void branch(RValue cmp, BasicBlock *bodyBB, BasicBlock *endBB) { Nucleus::createCondBr(cmp.value(), bodyBB, endBB); Nucleus::setInsertBlock(bodyBB); } RValue MaskedLoad(RValue> base, RValue mask, unsigned int alignment, bool zeroMaskedLanes /* = false */) { return RValue(Nucleus::createMaskedLoad(base.value(), Float::type(), mask.value(), alignment, zeroMaskedLanes)); } RValue MaskedLoad(RValue> base, RValue mask, unsigned int alignment, bool zeroMaskedLanes /* = false */) { return RValue(Nucleus::createMaskedLoad(base.value(), Int::type(), mask.value(), alignment, zeroMaskedLanes)); } void MaskedStore(RValue> base, RValue val, RValue mask, unsigned int alignment) { Nucleus::createMaskedStore(base.value(), val.value(), mask.value(), alignment); } void MaskedStore(RValue> base, RValue val, RValue mask, unsigned int alignment) { Nucleus::createMaskedStore(base.value(), val.value(), mask.value(), alignment); } void Fence(std::memory_order memoryOrder) { ASSERT_MSG(memoryOrder == std::memory_order_acquire || memoryOrder == std::memory_order_release || memoryOrder == std::memory_order_acq_rel || memoryOrder == std::memory_order_seq_cst, "Unsupported memoryOrder: %d", int(memoryOrder)); Nucleus::createFence(memoryOrder); } Bool CToReactor::cast(bool v) { return type(v); } Byte CToReactor::cast(uint8_t v) { return type(v); } SByte CToReactor::cast(int8_t v) { return type(v); } Short CToReactor::cast(int16_t v) { return type(v); } UShort CToReactor::cast(uint16_t v) { return type(v); } Int CToReactor::cast(int32_t v) { return type(v); } UInt CToReactor::cast(uint32_t v) { return type(v); } Float CToReactor::cast(float v) { return type(v); } Float4 CToReactor::cast(float v[4]) { return type(v[0], v[1], v[2], v[3]); } // TODO: Long has no constructor that takes a uint64_t // Long CToReactor::cast(uint64_t v) { return type(v); } #ifdef ENABLE_RR_PRINT static std::string replaceAll(std::string str, const std::string &substr, const std::string &replacement) { size_t pos = 0; while((pos = str.find(substr, pos)) != std::string::npos) { str.replace(pos, substr.length(), replacement); pos += replacement.length(); } return str; } // extractAll returns a vector containing the extracted n scalar values of the vector vec. static std::vector extractAll(Value *vec, int n) { Type *elemTy = Nucleus::getContainedType(Nucleus::getType(vec)); std::vector elements; elements.reserve(n); for(int i = 0; i < n; i++) { auto el = Nucleus::createExtractElement(vec, elemTy, i); elements.push_back(el); } return elements; } // toInt returns all the integer values in vals extended to a printf-required storage value static std::vector toInt(const std::vector &vals, bool isSigned) { auto storageTy = Nucleus::getPrintfStorageType(Int::type()); std::vector elements; elements.reserve(vals.size()); for(auto v : vals) { if(isSigned) { elements.push_back(Nucleus::createSExt(v, storageTy)); } else { elements.push_back(Nucleus::createZExt(v, storageTy)); } } return elements; } // toFloat returns all the float values in vals extended to extended to a printf-required storage value static std::vector toFloat(const std::vector &vals) { auto storageTy = Nucleus::getPrintfStorageType(Float::type()); std::vector elements; elements.reserve(vals.size()); for(auto v : vals) { elements.push_back(Nucleus::createFPExt(v, storageTy)); } return elements; } std::vector PrintValue::Ty::val(const RValue &v) { auto t = Nucleus::createConstantString("true"); auto f = Nucleus::createConstantString("false"); return { Nucleus::createSelect(v.value(), t, f) }; } std::vector PrintValue::Ty::val(const RValue &v) { return toInt({ v.value() }, false); } std::vector PrintValue::Ty::val(const RValue &v) { return toInt(extractAll(v.value(), 4), false); } std::vector PrintValue::Ty::val(const RValue &v) { return toInt({ v.value() }, true); } std::vector PrintValue::Ty::val(const RValue &v) { return toInt(extractAll(v.value(), 2), true); } std::vector PrintValue::Ty::val(const RValue &v) { return toInt(extractAll(v.value(), 4), true); } std::vector PrintValue::Ty::val(const RValue &v) { return toInt({ v.value() }, false); } std::vector PrintValue::Ty::val(const RValue &v) { return toInt(extractAll(v.value(), 2), false); } std::vector PrintValue::Ty::val(const RValue &v) { return toInt(extractAll(v.value(), 4), false); } std::vector PrintValue::Ty::val(const RValue &v) { return toInt({ v.value() }, true); } std::vector PrintValue::Ty::val(const RValue &v) { return toInt(extractAll(v.value(), 4), true); } std::vector PrintValue::Ty::val(const RValue &v) { return toInt({ v.value() }, false); } std::vector PrintValue::Ty::val(const RValue &v) { return toInt(extractAll(v.value(), 4), false); } std::vector PrintValue::Ty::val(const RValue &v) { return toFloat({ v.value() }); } std::vector PrintValue::Ty::val(const RValue &v) { return toFloat(extractAll(v.value(), 4)); } std::vector PrintValue::Ty::val(const RValue &v) { return toInt(extractAll(v.value(), SIMD::Width), true); } std::vector PrintValue::Ty::val(const RValue &v) { return toInt(extractAll(v.value(), SIMD::Width), false); } std::vector PrintValue::Ty::val(const RValue &v) { return toFloat(extractAll(v.value(), SIMD::Width)); } std::vector PrintValue::Ty::val(const char *v) { return { Nucleus::createConstantString(v) }; } void Printv(const char *function, const char *file, int line, const char *fmt, std::initializer_list args) { // Build the printf format message string. std::string str; if(file != nullptr) { str += (line > 0) ? "%s:%d " : "%s "; } if(function != nullptr) { str += "%s "; } str += fmt; // Perform substitution on all '{n}' bracketed indices in the format // message. int i = 0; for(const PrintValue &arg : args) { str = replaceAll(str, "{" + std::to_string(i++) + "}", arg.format); } std::vector vals; vals.reserve(8); // The format message is always the first argument. vals.push_back(Nucleus::createConstantString(str)); // Add optional file, line and function info if provided. if(file != nullptr) { vals.push_back(Nucleus::createConstantString(file)); if(line > 0) { vals.push_back(Nucleus::createConstantInt(line)); } } if(function != nullptr) { vals.push_back(Nucleus::createConstantString(function)); } // Add all format arguments. for(const PrintValue &arg : args) { for(auto val : arg.values) { vals.push_back(val); } } // This call is implemented by each backend VPrintf(vals); } // This is the function that is called by VPrintf from the backends int DebugPrintf(const char *format, ...) { // Uncomment this to make it so that we do not print, but the call to this function is emitted. // Useful when debugging emitted code to see the Reactor source location. // # define RR_PRINT_OUTPUT_TYPE_STUB # if defined(RR_PRINT_OUTPUT_TYPE_STUB) return 0; # else int result; va_list args; va_start(args, format); char buffer[2048]; result = vsprintf(buffer, format, args); va_end(args); std::fputs(buffer, stdout); # if defined(_WIN32) OutputDebugString(buffer); # endif return result; # endif } #endif // ENABLE_RR_PRINT // Functions implemented by backends bool HasRcpApprox(); RValue RcpApprox(RValue x, bool exactAtPow2 = false); RValue RcpApprox(RValue x, bool exactAtPow2 = false); template static RValue DoRcp(RValue x, bool relaxedPrecision, bool exactAtPow2) { #if defined(__i386__) || defined(__x86_64__) // On x86, 1/x is fast enough, except for lower precision bool approx = HasRcpApprox() && relaxedPrecision; #else bool approx = HasRcpApprox(); #endif T rcp; if(approx) { rcp = RcpApprox(x, exactAtPow2); if(!relaxedPrecision) { // Perform one more iteration of Newton-Rhapson division to increase precision rcp = (rcp + rcp) - (x * rcp * rcp); } } else { rcp = T(1.0f) / x; } return rcp; } RValue Rcp(RValue x, bool relaxedPrecision, bool exactAtPow2) { RR_DEBUG_INFO_UPDATE_LOC(); return DoRcp(x, relaxedPrecision, exactAtPow2); } RValue Rcp(RValue x, bool relaxedPrecision, bool exactAtPow2) { RR_DEBUG_INFO_UPDATE_LOC(); return DoRcp(x, relaxedPrecision, exactAtPow2); } // Functions implemented by backends bool HasRcpSqrtApprox(); RValue RcpSqrtApprox(RValue x); RValue RcpSqrtApprox(RValue x); template struct CastToIntType; template<> struct CastToIntType { using type = Int4; }; template<> struct CastToIntType { using type = Int; }; // TODO: move to Reactor.hpp? RValue CmpNEQ(RValue x, RValue y) { return IfThenElse(x != y, Int(~0), Int(0)); } template static RValue DoRcpSqrt(RValue x, bool relaxedPrecision) { #if defined(__i386__) || defined(__x86_64__) // On x86, 1/x is fast enough, except for lower precision bool approx = HasRcpApprox() && relaxedPrecision; #else bool approx = HasRcpApprox(); #endif if(approx) { using IntType = typename CastToIntType::type; T rsq = RcpSqrtApprox(x); if(!relaxedPrecision) { rsq = rsq * (T(3.0f) - rsq * rsq * x) * T(0.5f); rsq = As(CmpNEQ(As(x), IntType(0x7F800000)) & As(rsq)); } return rsq; } else { return T(1.0f) / Sqrt(x); } } RValue RcpSqrt(RValue x, bool relaxedPrecision) { return DoRcpSqrt(x, relaxedPrecision); } RValue RcpSqrt(RValue x, bool relaxedPrecision) { return DoRcpSqrt(x, relaxedPrecision); } } // namespace rr