// 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 _CONSTANT_UNION_INCLUDED_
#define _CONSTANT_UNION_INCLUDED_
#ifndef __ANDROID__
#include <assert.h>
#else
#include "../../Common/DebugAndroid.hpp"
#endif
class ConstantUnion {
public:
POOL_ALLOCATOR_NEW_DELETE();
ConstantUnion()
{
iConst = 0;
type = EbtVoid;
}
bool cast(TBasicType newType, const ConstantUnion &constant)
{
switch (newType)
{
case EbtFloat:
switch (constant.type)
{
case EbtInt: setFConst(static_cast<float>(constant.getIConst())); break;
case EbtUInt: setFConst(static_cast<float>(constant.getUConst())); break;
case EbtBool: setFConst(static_cast<float>(constant.getBConst())); break;
case EbtFloat: setFConst(static_cast<float>(constant.getFConst())); break;
default: return false;
}
break;
case EbtInt:
switch (constant.type)
{
case EbtInt: setIConst(static_cast<int>(constant.getIConst())); break;
case EbtUInt: setIConst(static_cast<int>(constant.getUConst())); break;
case EbtBool: setIConst(static_cast<int>(constant.getBConst())); break;
case EbtFloat: setIConst(static_cast<int>(constant.getFConst())); break;
default: return false;
}
break;
case EbtUInt:
switch (constant.type)
{
case EbtInt: setUConst(static_cast<unsigned int>(constant.getIConst())); break;
case EbtUInt: setUConst(static_cast<unsigned int>(constant.getUConst())); break;
case EbtBool: setUConst(static_cast<unsigned int>(constant.getBConst())); break;
case EbtFloat: setUConst(static_cast<unsigned int>(constant.getFConst())); break;
default: return false;
}
break;
case EbtBool:
switch (constant.type)
{
case EbtInt: setBConst(constant.getIConst() != 0); break;
case EbtUInt: setBConst(constant.getUConst() != 0); break;
case EbtBool: setBConst(constant.getBConst()); break;
case EbtFloat: setBConst(constant.getFConst() != 0.0f); break;
default: return false;
}
break;
case EbtStruct: // Struct fields don't get cast
switch (constant.type)
{
case EbtInt: setIConst(constant.getIConst()); break;
case EbtUInt: setUConst(constant.getUConst()); break;
case EbtBool: setBConst(constant.getBConst()); break;
case EbtFloat: setFConst(constant.getFConst()); break;
default: return false;
}
break;
default:
return false;
}
return true;
}
void setIConst(int i) {iConst = i; type = EbtInt; }
void setUConst(unsigned int u) { uConst = u; type = EbtUInt; }
void setFConst(float f) {fConst = f; type = EbtFloat; }
void setBConst(bool b) {bConst = b; type = EbtBool; }
int getIConst() const { return iConst; }
unsigned int getUConst() const { return uConst; }
float getFConst() const { return fConst; }
bool getBConst() const { return bConst; }
float getAsFloat() const
{
const int FFFFFFFFh = 0xFFFFFFFF;
switch(type)
{
case EbtInt: return reinterpret_cast<const float&>(iConst);
case EbtUInt: return reinterpret_cast<const float&>(uConst);
case EbtFloat: return fConst;
case EbtBool: return (bConst == true) ? reinterpret_cast<const float&>(FFFFFFFFh) : 0;
default: return 0;
}
}
bool operator==(const int i) const
{
return i == iConst;
}
bool operator==(const unsigned int u) const
{
return u == uConst;
}
bool operator==(const float f) const
{
return f == fConst;
}
bool operator==(const bool b) const
{
return b == bConst;
}
bool operator==(const ConstantUnion& constant) const
{
if (constant.type != type)
return false;
switch (type) {
case EbtInt:
return constant.iConst == iConst;
case EbtUInt:
return constant.uConst == uConst;
case EbtFloat:
return constant.fConst == fConst;
case EbtBool:
return constant.bConst == bConst;
default:
return false;
}
}
bool operator!=(const int i) const
{
return !operator==(i);
}
bool operator!=(const unsigned int u) const
{
return !operator==(u);
}
bool operator!=(const float f) const
{
return !operator==(f);
}
bool operator!=(const bool b) const
{
return !operator==(b);
}
bool operator!=(const ConstantUnion& constant) const
{
return !operator==(constant);
}
bool operator>(const ConstantUnion& constant) const
{
assert(type == constant.type);
switch (type) {
case EbtInt:
return iConst > constant.iConst;
case EbtUInt:
return uConst > constant.uConst;
case EbtFloat:
return fConst > constant.fConst;
default:
return false; // Invalid operation, handled at semantic analysis
}
}
bool operator<(const ConstantUnion& constant) const
{
assert(type == constant.type);
switch (type) {
case EbtInt:
return iConst < constant.iConst;
case EbtUInt:
return uConst < constant.uConst;
case EbtFloat:
return fConst < constant.fConst;
default:
return false; // Invalid operation, handled at semantic analysis
}
}
bool operator<=(const ConstantUnion& constant) const
{
assert(type == constant.type);
switch (type) {
case EbtInt:
return iConst <= constant.iConst;
case EbtUInt:
return uConst <= constant.uConst;
case EbtFloat:
return fConst <= constant.fConst;
default:
return false; // Invalid operation, handled at semantic analysis
}
}
bool operator>=(const ConstantUnion& constant) const
{
assert(type == constant.type);
switch (type) {
case EbtInt:
return iConst >= constant.iConst;
case EbtUInt:
return uConst >= constant.uConst;
case EbtFloat:
return fConst >= constant.fConst;
default:
return false; // Invalid operation, handled at semantic analysis
}
}
ConstantUnion operator+(const ConstantUnion& constant) const
{
ConstantUnion returnValue;
assert(type == constant.type);
switch (type) {
case EbtInt: returnValue.setIConst(iConst + constant.iConst); break;
case EbtUInt: returnValue.setUConst(uConst + constant.uConst); break;
case EbtFloat: returnValue.setFConst(fConst + constant.fConst); break;
default: assert(false && "Default missing");
}
return returnValue;
}
ConstantUnion operator-(const ConstantUnion& constant) const
{
ConstantUnion returnValue;
assert(type == constant.type);
switch (type) {
case EbtInt: returnValue.setIConst(iConst - constant.iConst); break;
case EbtUInt: returnValue.setUConst(uConst - constant.uConst); break;
case EbtFloat: returnValue.setFConst(fConst - constant.fConst); break;
default: assert(false && "Default missing");
}
return returnValue;
}
ConstantUnion operator*(const ConstantUnion& constant) const
{
ConstantUnion returnValue;
assert(type == constant.type);
switch (type) {
case EbtInt: returnValue.setIConst(iConst * constant.iConst); break;
case EbtUInt: returnValue.setUConst(uConst * constant.uConst); break;
case EbtFloat: returnValue.setFConst(fConst * constant.fConst); break;
default: assert(false && "Default missing");
}
return returnValue;
}
ConstantUnion operator%(const ConstantUnion& constant) const
{
ConstantUnion returnValue;
assert(type == constant.type);
switch (type) {
case EbtInt: returnValue.setIConst(iConst % constant.iConst); break;
case EbtUInt: returnValue.setUConst(uConst % constant.uConst); break;
default: assert(false && "Default missing");
}
return returnValue;
}
ConstantUnion operator>>(const ConstantUnion& constant) const
{
ConstantUnion returnValue;
assert(type == constant.type);
switch (type) {
case EbtInt: returnValue.setIConst(iConst >> constant.iConst); break;
case EbtUInt: returnValue.setUConst(uConst >> constant.uConst); break;
default: assert(false && "Default missing");
}
return returnValue;
}
ConstantUnion operator<<(const ConstantUnion& constant) const
{
ConstantUnion returnValue;
// The signedness of the second parameter might be different, but we
// don't care, since the result is undefined if the second parameter is
// negative, and aliasing should not be a problem with unions.
assert(constant.type == EbtInt || constant.type == EbtUInt);
switch (type) {
case EbtInt: returnValue.setIConst(iConst << constant.iConst); break;
case EbtUInt: returnValue.setUConst(uConst << constant.uConst); break;
default: assert(false && "Default missing");
}
return returnValue;
}
ConstantUnion operator&(const ConstantUnion& constant) const
{
ConstantUnion returnValue;
assert(constant.type == EbtInt || constant.type == EbtUInt);
switch (type) {
case EbtInt: returnValue.setIConst(iConst & constant.iConst); break;
case EbtUInt: returnValue.setUConst(uConst & constant.uConst); break;
default: assert(false && "Default missing");
}
return returnValue;
}
ConstantUnion operator|(const ConstantUnion& constant) const
{
ConstantUnion returnValue;
assert(type == constant.type);
switch (type) {
case EbtInt: returnValue.setIConst(iConst | constant.iConst); break;
case EbtUInt: returnValue.setUConst(uConst | constant.uConst); break;
default: assert(false && "Default missing");
}
return returnValue;
}
ConstantUnion operator^(const ConstantUnion& constant) const
{
ConstantUnion returnValue;
assert(type == constant.type);
switch (type) {
case EbtInt: returnValue.setIConst(iConst ^ constant.iConst); break;
case EbtUInt: returnValue.setUConst(uConst ^ constant.uConst); break;
default: assert(false && "Default missing");
}
return returnValue;
}
ConstantUnion operator&&(const ConstantUnion& constant) const
{
ConstantUnion returnValue;
assert(type == constant.type);
switch (type) {
case EbtBool: returnValue.setBConst(bConst && constant.bConst); break;
default: assert(false && "Default missing");
}
return returnValue;
}
ConstantUnion operator||(const ConstantUnion& constant) const
{
ConstantUnion returnValue;
assert(type == constant.type);
switch (type) {
case EbtBool: returnValue.setBConst(bConst || constant.bConst); break;
default: assert(false && "Default missing");
}
return returnValue;
}
TBasicType getType() const { return type; }
private:
union {
int iConst; // used for ivec, scalar ints
unsigned int uConst; // used for uvec, scalar uints
bool bConst; // used for bvec, scalar bools
float fConst; // used for vec, mat, scalar floats
} ;
TBasicType type;
};
#endif // _CONSTANT_UNION_INCLUDED_