/* * Copyright © 2012 Intel Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * */ #include "immediate.hpp" using namespace gbe; using namespace ir; #define SCALAR_SAME_TYPE_ASSERT() \ GBE_ASSERT(this->getType() == right.getType() && \ this->getElemNum() == right.getElemNum() && \ this->getElemNum() == 1) #define DECLAR_BINARY_ALL_TYPE_OP(OP) \ Immediate Immediate::operator OP (const Immediate &right) const { \ /*SCALAR_SAME_TYPE_ASSERT();*/ \ switch (this->getType()) { \ default: \ GBE_ASSERT(0); \ case TYPE_BOOL: return Immediate(*this->data.b OP *right.data.b); \ case TYPE_S8: return Immediate(*this->data.s8 OP *right.data.s8); \ case TYPE_U8: return Immediate(*this->data.u8 OP *right.data.u8); \ case TYPE_S16: return Immediate(*this->data.s16 OP *right.data.s16); \ case TYPE_U16: return Immediate(*this->data.u16 OP *right.data.u16); \ case TYPE_S32: return Immediate(*this->data.s32 OP *right.data.s32); \ case TYPE_U32: return Immediate(*this->data.u32 OP *right.data.u32); \ case TYPE_S64: return Immediate(*this->data.s64 OP *right.data.s64); \ case TYPE_U64: return Immediate(*this->data.u64 OP *right.data.u64); \ case TYPE_FLOAT: return Immediate(*this->data.f32 OP *right.data.f32); \ case TYPE_DOUBLE: return Immediate(*this->data.f64 OP *right.data.f64); \ }\ return *this;\ } DECLAR_BINARY_ALL_TYPE_OP(+) DECLAR_BINARY_ALL_TYPE_OP(-) DECLAR_BINARY_ALL_TYPE_OP(*) DECLAR_BINARY_ALL_TYPE_OP(/) DECLAR_BINARY_ALL_TYPE_OP(>) //DECLAR_BINARY_ALL_TYPE_OP(<) DECLAR_BINARY_ALL_TYPE_OP(==) DECLAR_BINARY_ALL_TYPE_OP(!=) DECLAR_BINARY_ALL_TYPE_OP(>=) DECLAR_BINARY_ALL_TYPE_OP(<=) DECLAR_BINARY_ALL_TYPE_OP(&&) #undef DECLAR_BINARY_ALL_TYPE_OP #define DECLAR_BINARY_INT_TYPE_OP(OP) \ Immediate Immediate::operator OP (const Immediate &right) const { \ /*SCALAR_SAME_TYPE_ASSERT();*/ \ switch (this->getType()) { \ default: \ GBE_ASSERT(0); \ case TYPE_BOOL: return Immediate(*this->data.b OP *right.data.b); \ case TYPE_S8: return Immediate(*this->data.s8 OP *right.data.s8); \ case TYPE_U8: return Immediate(*this->data.u8 OP *right.data.u8); \ case TYPE_S16: return Immediate(*this->data.s16 OP *right.data.s16); \ case TYPE_U16: return Immediate(*this->data.u16 OP *right.data.u16); \ case TYPE_S32: return Immediate(*this->data.s32 OP *right.data.s32); \ case TYPE_U32: return Immediate(*this->data.u32 OP *right.data.u32); \ case TYPE_S64: return Immediate(*this->data.s64 OP *right.data.s64); \ case TYPE_U64: return Immediate(*this->data.u64 OP *right.data.u64); \ }\ return *this;\ } DECLAR_BINARY_INT_TYPE_OP(%) DECLAR_BINARY_INT_TYPE_OP(&) DECLAR_BINARY_INT_TYPE_OP(|) DECLAR_BINARY_INT_TYPE_OP(^) #undef DECLAR_BINARY_INT_TYPE_OP #define DECLAR_BINARY_ASHIFT_OP(OP) \ Immediate Immediate::operator OP (const Immediate &right) const { \ GBE_ASSERT(this->getType() > TYPE_BOOL && this->getType() <= TYPE_U64); \ int32_t shift = right.getIntegerValue(); \ if (shift == 0) \ return *this; \ else \ switch (this->getType()) { \ default: \ GBE_ASSERT(0); \ case TYPE_S8: return Immediate((*this->data.s8 OP shift)); \ case TYPE_U8: return Immediate((*this->data.u8 OP shift)); \ case TYPE_S16: return Immediate((*this->data.s16 OP shift)); \ case TYPE_U16: return Immediate((*this->data.u16 OP shift)); \ case TYPE_S32: return Immediate((*this->data.s32 OP shift)); \ case TYPE_U32: return Immediate((*this->data.u32 OP shift)); \ case TYPE_S64: return Immediate((*this->data.s64 OP shift)); \ case TYPE_U64: return Immediate((*this->data.u64 OP shift)); \ } \ } DECLAR_BINARY_ASHIFT_OP(>>) DECLAR_BINARY_ASHIFT_OP(<<) #undef DECLAR_BINARY_ASHIFT_OP Immediate Immediate::lshr (const Immediate &left, const Immediate &right) { GBE_ASSERT(left.getType() > TYPE_BOOL && left.getType() <= TYPE_U64); int32_t shift = right.getIntegerValue(); if (shift == 0) return left; else switch (left.getType()) { default: GBE_ASSERT(0); case TYPE_S8: case TYPE_U8: return Immediate((*left.data.u8 >> shift)); case TYPE_S16: case TYPE_U16: return Immediate((*left.data.u16 >> shift)); case TYPE_S32: case TYPE_U32: return Immediate((*left.data.u32 >> shift)); case TYPE_S64: case TYPE_U64: return Immediate((*left.data.u64 >> shift)); } } Immediate Immediate::less (const Immediate &left, const Immediate &right) { GBE_ASSERT(left.getType() > TYPE_BOOL && left.getType() <= TYPE_DOUBLE); switch (left.getType()) { default: GBE_ASSERT(0); case TYPE_S8: return Immediate(*left.data.s8 < *right.data.s8); case TYPE_U8: return Immediate(*left.data.u8 < *right.data.u8); case TYPE_S16: return Immediate(*left.data.s16 < *right.data.s16); case TYPE_U16: return Immediate(*left.data.u16 < *right.data.u16); case TYPE_S32: return Immediate(*left.data.s32 < *right.data.s32); case TYPE_U32: return Immediate(*left.data.u32 < *right.data.u32); case TYPE_S64: return Immediate(*left.data.s64 < *right.data.s64); case TYPE_U64: return Immediate(*left.data.u64 < *right.data.u64); case TYPE_FLOAT: return Immediate(*left.data.f32 < *right.data.f32); case TYPE_DOUBLE: return Immediate(*left.data.f64 < *right.data.f64); } } Immediate Immediate::extract (const Immediate &left, const Immediate &right, Type dstType) { GBE_ASSERT(left.getType() > TYPE_BOOL && left.getType() <= TYPE_DOUBLE); GBE_ASSERT(dstType == left.getType()); uint32_t index = right.getIntegerValue(); GBE_ASSERT(index >= 0 && index < left.getElemNum()); if (left.type != IMM_TYPE_COMP) { switch (left.getType()) { default: GBE_ASSERT(0); case TYPE_BOOL: return Immediate(left.data.b[index]); case TYPE_S8: return Immediate(left.data.s8[index]); case TYPE_U8: return Immediate(left.data.u8[index]); case TYPE_S16: return Immediate(left.data.s16[index]); case TYPE_U16: return Immediate(left.data.u16[index]); case TYPE_S32: return Immediate(left.data.s32[index]); case TYPE_U32: return Immediate(left.data.u32[index]); case TYPE_S64: return Immediate(left.data.s64[index]); case TYPE_U64: return Immediate(left.data.u64[index]); case TYPE_FLOAT: return Immediate(left.data.f32[index]); case TYPE_DOUBLE: return Immediate(left.data.f64[index]); } } else return *left.data.immVec[index]; } Immediate::Immediate(ImmOpCode op, const Immediate &left, const Immediate &right, Type dstType) { switch (op) { default: GBE_ASSERT(0 && "unsupported imm op\n"); case IMM_ADD: *this = left + right; break; case IMM_SUB: *this = left - right; break; case IMM_MUL: *this = left * right; break; case IMM_DIV: *this = left / right; break; case IMM_AND: *this = left & right; break; case IMM_OR: *this = left | right; break; case IMM_XOR: *this = left ^ right; break; case IMM_REM: { if (left.getType() > TYPE_BOOL && left.getType() <= TYPE_U64) *this = left % right; else if (left.getType() == TYPE_FLOAT && right.getType() == TYPE_FLOAT) { *this = Immediate(left); *this->data.f32 = fmodf(left.getFloatValue(), right.getFloatValue()); } else if (left.getType() == TYPE_DOUBLE && right.getType() == TYPE_DOUBLE) { *this = Immediate(left); *this->data.f64 += fmod(left.getDoubleValue(), right.getDoubleValue()); } else GBE_ASSERT(0); break; } case IMM_LSHR: { if (left.getElemNum() == 1) *this = lshr(left, right); else { GBE_ASSERT(right.getIntegerValue() <= (left.getElemNum() * left.getTypeSize() * 8)); GBE_ASSERT(right.getIntegerValue() % (left.getTypeSize() * 8) == 0); copy(left, right.getIntegerValue() / (left.getTypeSize() * 8), left.getElemNum()); } break; } case IMM_ASHR: { if (left.getElemNum() == 1) *this = left >> right; else { GBE_ASSERT(0 && "Doesn't support ashr on array constant."); copy(left, right.getIntegerValue() / (left.getTypeSize() * 8), left.getElemNum()); } break; } case IMM_SHL: { if (left.getElemNum() == 1) *this = left << right; else { GBE_ASSERT(right.getIntegerValue() <= (left.getElemNum() * left.getTypeSize() * 8)); GBE_ASSERT(right.getIntegerValue() % (left.getTypeSize() * 8) == 0); copy(left, -right.getIntegerValue() / (left.getTypeSize() * 8), left.getElemNum()); } break; } case IMM_OEQ: *this = left == right; break; case IMM_ONE: *this = left != right; break; case IMM_OLE: *this = left <= right; break; case IMM_OGE: *this = left >= right; break; case IMM_OLT: *this = less(left, right); break; case IMM_OGT: *this = left > right; break; case IMM_ORD: *this = (left == left) && (right == right); break; case IMM_EXTRACT: *this = extract(left, right, dstType); break; } // If the dst type is large int, we will not change the imm type to large int. GBE_ASSERT(type == (ImmType)dstType || dstType == TYPE_LARGE_INT || dstType == TYPE_BOOL); } Immediate::Immediate(const vector immVec, Type dstType) { if (immVec.size() == 1) { *this = *immVec[0]; } else if (!(immVec[0]->isCompType()) && immVec[0]->elemNum == 1) { this->type = (ImmType)dstType; this->elemNum = immVec.size(); if (immVec[0]->getTypeSize() * immVec.size() < 8) this->data.p = &this->defaultData; else this->data.p = malloc(immVec[0]->getTypeSize() * immVec.size()); uint8_t *p = (uint8_t*)this->data.p; for(uint32_t i = 0; i < immVec.size(); i++) { GBE_ASSERT(immVec[i]->type == immVec[0]->type && immVec[i]->elemNum == 1); memcpy(p, immVec[i]->data.p, immVec[i]->getTypeSize()); p += immVec[i]->getTypeSize(); } } else { GBE_ASSERT(0); this->type = IMM_TYPE_COMP; if (immVec.size() * sizeof(Immediate*) < 8) this->data.p = &this->defaultData; else this->data.p = malloc(immVec.size() * sizeof(Immediate*)); this->elemNum = immVec.size(); for(uint32_t i = 0; i < immVec.size(); i++) this->data.immVec[i] = immVec[i]; } } // operator = and copy() are only called from constructor functions // which this never hold a memory pointer, we don't need to bother // to check the data.p before assignment. Immediate & Immediate::operator= (const Immediate & other) { if (this != &other) { type = other.type; elemNum = other.elemNum; if (other.data.p != &other.defaultData) { data.p = malloc(other.elemNum * other.getTypeSize()); memcpy(data.p, other.data.p, other.elemNum * other.getTypeSize()); } else { defaultData = other.defaultData; data.p = &defaultData; } } return *this; } void Immediate::copy(const Immediate &other, int32_t offset, uint32_t num) { if (this != &other) { if (other.type == IMM_TYPE_COMP && num == 1) { GBE_ASSERT(offset >= 0 && offset <= (int32_t)other.elemNum); *this = *other.data.immVec[offset]; return; } type = other.type; elemNum = num; if (num * other.getTypeSize() < 8) data.p = &defaultData; else data.p = malloc(num * other.getTypeSize()); uint8_t* datap = (uint8_t*)data.p; memset(datap, 0, num * other.getTypeSize()); if (offset < 0) { datap += (-offset) * other.getTypeSize(); num -= num < (uint32_t)(-offset) ? num : (-offset); offset = 0; } else if (offset > 0 && num > 1) { GBE_ASSERT((int32_t)num > offset); num -= offset; } memcpy(datap, (uint8_t*)other.data.p + offset * other.getTypeSize(), num * other.getTypeSize()); } }