/*
* 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 .
*
* Author: Benjamin Segovia
*/
/**
* \file Immediate.hpp
*
* \author Benjamin Segovia
*/
#ifndef __GBE_IR_IMMEDIATE_HPP__
#define __GBE_IR_IMMEDIATE_HPP__
#include
#include "ir/type.hpp"
#include "sys/platform.hpp"
namespace gbe {
namespace ir {
typedef enum {
IMM_TRUNC = 0,
IMM_BITCAST,
IMM_ADD,
IMM_SUB,
IMM_MUL,
IMM_DIV,
IMM_REM,
IMM_SHL,
IMM_ASHR,
IMM_LSHR,
IMM_AND,
IMM_OR,
IMM_XOR,
IMM_OEQ,
IMM_ONE,
IMM_OLE,
IMM_OGE,
IMM_OLT,
IMM_OGT,
IMM_ORD,
IMM_FPTOUI,
IMM_FPTOSI,
IMM_SITOFP,
IMM_UITOFP,
IMM_EXTRACT,
IMM_SEXT,
IMM_ZEXT,
IMM_FPEXT
} ImmOpCode;
typedef enum {
IMM_TYPE_BOOL = TYPE_BOOL,
IMM_TYPE_S8 = TYPE_S8,
IMM_TYPE_U8 = TYPE_U8,
IMM_TYPE_S16 = TYPE_S16,
IMM_TYPE_U16 = TYPE_U16,
IMM_TYPE_S32 = TYPE_S32,
IMM_TYPE_U32 = TYPE_U32,
IMM_TYPE_S64 = TYPE_S64,
IMM_TYPE_U64 = TYPE_U64,
IMM_TYPE_FLOAT = TYPE_FLOAT,
IMM_TYPE_DOUBLE = TYPE_DOUBLE,
IMM_TYPE_COMP // compond immediate which consist many immediates.
} ImmType;
/*! The value as stored in the instruction */
class Immediate
{
public:
INLINE Immediate(void) { }
Immediate & operator= (const Immediate &);
INLINE Type getType(void) const {
return (Type)type;
}
INLINE bool isCompType(void) const {
return type == IMM_TYPE_COMP;
}
INLINE uint32_t getElemNum(void) const {
return elemNum;
}
uint32_t getTypeSize(void) const {
switch(type) {
default:
GBE_ASSERT(0 && "Invalid immeidate type.\n");
case TYPE_BOOL:
case TYPE_S8:
case TYPE_U8: return 1;
case TYPE_S16:
case TYPE_U16: return 2;
case TYPE_FLOAT:
case TYPE_S32:
case TYPE_U32: return 4;
case TYPE_DOUBLE:
case TYPE_S64:
case TYPE_U64: return 8;
case IMM_TYPE_COMP: return sizeof(Immediate*);
}
}
#define DECL_CONSTRUCTOR(TYPE, FIELD, IR_TYPE) \
Immediate(TYPE FIELD) { \
this->type = (ImmType)IR_TYPE; \
this->elemNum = 1; \
this->data.p = &defaultData; \
defaultData = 0ull; \
*this->data.FIELD = FIELD; \
}
DECL_CONSTRUCTOR(bool, b, TYPE_BOOL)
DECL_CONSTRUCTOR(int8_t, s8, TYPE_S8)
DECL_CONSTRUCTOR(uint8_t, u8, TYPE_U8)
DECL_CONSTRUCTOR(int16_t, s16, TYPE_S16)
DECL_CONSTRUCTOR(uint16_t, u16, TYPE_S16)
DECL_CONSTRUCTOR(int32_t, s32, TYPE_S32)
DECL_CONSTRUCTOR(uint32_t, u32, TYPE_S32)
DECL_CONSTRUCTOR(int64_t, s64, TYPE_S64)
DECL_CONSTRUCTOR(uint64_t, u64, TYPE_S64)
DECL_CONSTRUCTOR(float, f32, TYPE_FLOAT)
DECL_CONSTRUCTOR(double, f64, TYPE_DOUBLE)
#undef DECL_CONSTRUCTOR
#define DECL_CONSTRUCTOR(TYPE, FIELD, IR_TYPE, ELEMNUM) \
Immediate(TYPE *FIELD, uint32_t ELEMNUM) { \
this->type = (ImmType)IR_TYPE; \
this->elemNum = ELEMNUM; \
if (elemNum * ELEMNUM > 8) \
this->data.p = malloc(ELEMNUM * getTypeSize()); \
else \
this->data.p = &defaultData; \
defaultData = 0ull; \
memcpy(this->data.FIELD, FIELD, ELEMNUM * getTypeSize()); \
}
DECL_CONSTRUCTOR(bool, b, TYPE_BOOL, elemNum)
DECL_CONSTRUCTOR(int8_t, s8, TYPE_S8, elemNum)
DECL_CONSTRUCTOR(uint8_t, u8, TYPE_U8, elemNum)
DECL_CONSTRUCTOR(int16_t, s16, TYPE_S16, elemNum)
DECL_CONSTRUCTOR(uint16_t, u16, TYPE_S16, elemNum)
DECL_CONSTRUCTOR(int32_t, s32, TYPE_S32, elemNum)
DECL_CONSTRUCTOR(uint32_t, u32, TYPE_S32, elemNum)
DECL_CONSTRUCTOR(int64_t, s64, TYPE_S64, elemNum)
DECL_CONSTRUCTOR(uint64_t, u64, TYPE_S64, elemNum)
DECL_CONSTRUCTOR(float, f32, TYPE_FLOAT, elemNum)
DECL_CONSTRUCTOR(double, f64, TYPE_DOUBLE, elemNum)
#undef DECL_CONSTRUCTOR
Immediate(const vector immVec, Type dstType);
INLINE int64_t getIntegerValue(void) const {
switch (type) {
default:
GBE_ASSERT(0 && "Invalid immediate type.\n");
case TYPE_BOOL: return *data.b;
case TYPE_S8: return *data.s8;
case TYPE_U8: return *data.u8;
case TYPE_S16: return *data.s16;
case TYPE_U16: return *data.u16;
case TYPE_S32: return *data.s32;
case TYPE_U32: return *data.u32;
case TYPE_S64: return *data.s64;
case TYPE_U64: return *data.u64;
}
}
INLINE uint64_t getUnsignedIntegerValue(void) const {
switch (type) {
default:
GBE_ASSERT(0 && "Invalid immediate type.\n");
case TYPE_BOOL: return *data.b;
case TYPE_S8: return *data.s8;
case TYPE_U8: return *data.u8;
case TYPE_S16: return *data.s16;
case TYPE_U16: return *data.u16;
case TYPE_S32: return *data.s32;
case TYPE_U32: return *data.u32;
case TYPE_S64: return *data.s64;
case TYPE_U64: return *data.u64;
}
}
INLINE float getFloatValue(void) const {
// we allow bitcast from u32/s32 immediate to float
GBE_ASSERT(type == IMM_TYPE_FLOAT || type == IMM_TYPE_U32 || type == IMM_TYPE_S32);
return *data.f32;
}
INLINE float asFloatValue(void) const {
GBE_ASSERT(type == IMM_TYPE_FLOAT || type == IMM_TYPE_U32 || type == IMM_TYPE_S32);
return *data.f32;
}
INLINE int64_t asIntegerValue(void) const {
GBE_ASSERT(elemNum == 1);
return *data.s64;
}
INLINE double getDoubleValue(void) const {
GBE_ASSERT(type == IMM_TYPE_DOUBLE);
return *data.f64;
}
INLINE Immediate(const Immediate & other) {
*this = other;
}
Immediate(ImmOpCode op, const Immediate &other, Type dstType) {
switch (op) {
default:
GBE_ASSERT(0);
case IMM_TRUNC:
copy(other, 0, 1);
break;
case IMM_BITCAST:
if (other.type != IMM_TYPE_COMP) {
*this = other;
type = (ImmType)dstType;
} else {
vector immVec;
for(uint32_t i = 0; i < other.getElemNum(); i++)
immVec.push_back(other.data.immVec[i]);
*this = Immediate(immVec, dstType);
}
break;
case IMM_FPTOUI: *this = Immediate((uint32_t)*other.data.f32); break;
case IMM_FPTOSI: *this = Immediate((int32_t)*other.data.f32); break;
case IMM_UITOFP: *this = Immediate((float)*other.data.u32); break;
case IMM_SITOFP: *this = Immediate((float)*other.data.s32); break;
case IMM_SEXT:
{
int64_t value = other.getIntegerValue();
if (other.getType() == TYPE_BOOL)
value = -value;
switch (dstType) {
default:
GBE_ASSERT(0 && "Illegal sext constant expression");
case TYPE_S8: *this = Immediate((int8_t)value); break;
case TYPE_S16: *this = Immediate((int16_t)value); break;
case TYPE_S32: *this = Immediate((int32_t)value); break;
case TYPE_S64: *this = Immediate((int64_t)value); break;
}
}
case IMM_ZEXT:
{
uint64_t value = other.getUnsignedIntegerValue();
switch (dstType) {
default:
GBE_ASSERT(0 && "Illegal sext constant expression");
case TYPE_U8: *this = Immediate((uint8_t)value); break;
case TYPE_U16: *this = Immediate((uint16_t)value); break;
case TYPE_U32: *this = Immediate((uint32_t)value); break;
case TYPE_U64: *this = Immediate((uint64_t)value); break;
}
break;
}
case IMM_FPEXT:
{
GBE_ASSERT(other.getType() == TYPE_FLOAT && dstType == TYPE_DOUBLE);
double value = other.getFloatValue();
*this = Immediate(value);
break;
}
}
}
Immediate(ImmOpCode op, const Immediate &left, const Immediate &right, Type dstType);
~Immediate() {
if (data.p != &defaultData) {
free(data.p);
data.p = NULL;
}
}
private:
ImmType type; //!< Type of the value
uint32_t elemNum; //!< vector imm data type
uint64_t defaultData;
union {
bool *b;
int8_t *s8;
uint8_t *u8;
int16_t *s16;
uint16_t *u16;
int32_t *s32;
uint32_t *u32;
int64_t *s64;
uint64_t *u64;
float *f32;
double *f64;
const Immediate *immVec[];
void *p;
} data; //!< Value to store
Immediate operator+ (const Immediate &) const;
Immediate operator- (const Immediate &) const;
Immediate operator* (const Immediate &) const;
Immediate operator/ (const Immediate &) const;
Immediate operator> (const Immediate &) const;
Immediate operator== (const Immediate &) const;
Immediate operator!= (const Immediate &) const;
Immediate operator>= (const Immediate &) const;
Immediate operator<= (const Immediate &) const;
Immediate operator&& (const Immediate &) const;
Immediate operator% (const Immediate &) const;
Immediate operator& (const Immediate &) const;
Immediate operator| (const Immediate &) const;
Immediate operator^ (const Immediate &) const;
Immediate operator<< (const Immediate &) const;
Immediate operator>> (const Immediate &) const;
static Immediate lshr (const Immediate &left, const Immediate &right);
static Immediate less (const Immediate &left, const Immediate &right);
static Immediate extract (const Immediate &left, const Immediate &right, Type dstType);
void copy(const Immediate &other, int32_t offset, uint32_t num);
GBE_CLASS(Immediate);
};
/*! Compare two immediates */
INLINE bool operator< (const Immediate &imm0, const Immediate &imm1) {
if (imm0.getType() != imm1.getType())
return uint32_t(imm0.getType()) < uint32_t(imm1.getType());
else if (imm0.getType() == TYPE_FLOAT || imm0.getType() == TYPE_DOUBLE)
return imm0.asIntegerValue() < imm1.asIntegerValue();
else
return imm0.getIntegerValue() < imm1.getIntegerValue();
}
/*! A value is stored in a per-function vector. This is the index to it */
TYPE_SAFE(ImmediateIndex, uint16_t)
} /* namespace ir */
} /* namespace gbe */
#endif /* __GBE_IR_IMMEDIATE_HPP__ */