switch (opcode) {
case OP_ADD: p->ADD(dst, src0, src1); break;
case OP_SUB: p->ADD(dst, src0, GenReg::negate(src1)); break;
+ case OP_AND: p->AND(dst, src0, src1); break;
+ case OP_XOR: p->XOR(dst, src0, src1); break;
+ case OP_OR: p->OR(dst, src0, src1); break;
+ case OP_SHL: p->SHL(dst, src0, src1); break;
case OP_MUL:
{
if (type == TYPE_FLOAT)
NOT_IMPLEMENTED;
break;
}
+ case OP_DIV:
+ {
+ p->MATH(dst, GEN_MATH_FUNCTION_INV, src0, src1);
+ break;
+ }
default: NOT_IMPLEMENTED;
}
}
- void GenContext::emitTernaryInstruction(const ir::TernaryInstruction &insn) {}
- void GenContext::emitSelectInstruction(const ir::SelectInstruction &insn) {}
+ void GenContext::emitTernaryInstruction(const ir::TernaryInstruction &insn) {
+ NOT_IMPLEMENTED;
+ }
+ void GenContext::emitSelectInstruction(const ir::SelectInstruction &insn) {
+ NOT_IMPLEMENTED;
+ }
void GenContext::emitCompareInstruction(const ir::CompareInstruction &insn) {
using namespace ir;
p->pop();
}
- void GenContext::emitConvertInstruction(const ir::ConvertInstruction &insn) {}
+ void GenContext::emitConvertInstruction(const ir::ConvertInstruction &insn) {
+ const ir::Type dstType = insn.getDstType();
+ const ir::Type srcType = insn.getSrcType();
+ const GenReg dst = this->genReg(insn.getDst(0), dstType);
+ const GenReg src = this->genReg(insn.getSrc(0), srcType);
+ p->MOV(dst, src);
+ }
+
void GenContext::emitBranchInstruction(const ir::BranchInstruction &insn) {
using namespace ir;
const Opcode opcode = insn.getOpcode();
} else
NOT_IMPLEMENTED;
}
- void GenContext::emitTextureInstruction(const ir::TextureInstruction &insn) {}
+
+ void GenContext::emitTextureInstruction(const ir::TextureInstruction &insn) {
+ NOT_IMPLEMENTED;
+ }
void GenContext::emitLoadImmInstruction(const ir::LoadImmInstruction &insn) {
using namespace ir;
#define GEN_UNTYPED_SIMD16 1
#define GEN_UNTYPED_SIMD8 2
+/* SIMD mode for byte scatters / gathers */
+#define GEN_BYTE_SCATTER_SIMD8 0
+#define GEN_BYTE_SCATTER_SIMD16 1
+
/* Data port message type */
#define GEN_UNTYPED_READ 5
#define GEN_UNTYPED_WRITE 13
+#define GEN_BYTE_GATHER 4
+#define GEN_BYTE_SCATTER 12
#define GEN_SAMPLER_RETURN_FORMAT_FLOAT32 0
#define GEN_SAMPLER_RETURN_FORMAT_UINT32 2
uint32_t end_of_thread:1;
} gen7_untyped_rw;
+ /*! Data port byte scatter / gather */
+ struct {
+ uint32_t bti:8;
+ uint32_t simd_mode:1;
+ uint32_t ignored0:1;
+ uint32_t data_size:2;
+ uint32_t ignored1:2;
+ uint32_t msg_type:4;
+ uint32_t category:1;
+ uint32_t header_present:1;
+ uint32_t response_length:5;
+ uint32_t msg_length:4;
+ uint32_t pad2:2;
+ uint32_t end_of_thread:1;
+ } gen7_byte_rw;
+
struct {
uint32_t src1_subreg_nr_high:1;
uint32_t src1_reg_nr:8;
NOT_SUPPORTED;
}
+ void
+ set_dp_byte_scatter_gather(GenEmitter *p,
+ GenInstruction *insn,
+ uint32_t bti,
+ uint32_t elem_size,
+ uint32_t msg_type,
+ uint32_t msg_length,
+ uint32_t response_length)
+ {
+ GenMessageTarget sfid = GEN_SFID_DATAPORT_DATA_CACHE;
+ brw_set_message_descriptor(p, insn, sfid, msg_length, response_length);
+ insn->bits3.gen7_byte_rw.msg_type = msg_type;
+ insn->bits3.gen7_byte_rw.bti = bti;
+ insn->bits3.gen7_byte_rw.data_size = elem_size;
+ if (p->curr.execWidth == 8)
+ insn->bits3.gen7_byte_rw.simd_mode = GEN_BYTE_SCATTER_SIMD8;
+ else if (p->curr.execWidth == 16)
+ insn->bits3.gen7_byte_rw.simd_mode = GEN_BYTE_SCATTER_SIMD16;
+ else
+ NOT_SUPPORTED;
+ }
+
static const uint32_t untypedRWMask[] = {
GEN_UNTYPED_ALPHA|GEN_UNTYPED_BLUE|GEN_UNTYPED_GREEN|GEN_UNTYPED_RED,
GEN_UNTYPED_ALPHA|GEN_UNTYPED_BLUE|GEN_UNTYPED_GREEN,
response_length);
}
+ void
+ GenEmitter::BYTE_GATHER(GenReg dst, GenReg src, uint32_t bti, uint32_t elemSize)
+ {
+ GenInstruction *insn = this->next(GEN_OPCODE_SEND);
+ uint32_t msg_length = 0;
+ uint32_t response_length = 0;
+ if (this->curr.execWidth == 8) {
+ msg_length = 1;
+ response_length = 1;
+ } else if (this->curr.execWidth == 16) {
+ msg_length = 2;
+ response_length = 2;
+ } else
+ NOT_IMPLEMENTED;
+
+ this->setHeader(insn);
+ this->setDst(insn, GenReg::uw16grf(dst.nr, 0));
+ this->setSrc0(insn, GenReg::ud8grf(src.nr, 0));
+ this->setSrc1(insn, GenReg::immud(0));
+ set_dp_byte_scatter_gather(this,
+ insn,
+ bti,
+ elemSize,
+ GEN_BYTE_GATHER,
+ msg_length,
+ response_length);
+ }
+
+ void
+ GenEmitter::BYTE_SCATTER(GenReg msg, uint32_t bti, uint32_t elemSize)
+ {
+ GenInstruction *insn = this->next(GEN_OPCODE_SEND);
+ uint32_t msg_length = 0;
+ uint32_t response_length = 0;
+ this->setHeader(insn);
+ if (this->curr.execWidth == 8) {
+ this->setDst(insn, GenReg::retype(GenReg::null(), GEN_TYPE_UD));
+ msg_length = 1;
+ } else if (this->curr.execWidth == 16) {
+ this->setDst(insn, GenReg::retype(GenReg::null(), GEN_TYPE_UW));
+ msg_length = 2;
+ } else
+ NOT_IMPLEMENTED;
+ this->setSrc0(insn, GenReg::ud8grf(msg.nr, 0));
+ this->setSrc1(insn, GenReg::immud(0));
+ set_dp_byte_scatter_gather(this,
+ insn,
+ bti,
+ elemSize,
+ GEN_BYTE_SCATTER,
+ msg_length,
+ response_length);
+ }
+
void set_sampler_message(GenEmitter *p,
GenInstruction *insn,
uint32_t bti,
insn->header.quarter_control = 0;
}
- void GenEmitter::MATH(GenReg dest,
- uint32_t function,
- uint32_t saturate,
- uint32_t msg_reg_nr,
- GenReg src,
- uint32_t data_type,
- uint32_t precision)
- {
- GenInstruction *insn = this->next(GEN_OPCODE_MATH);
-
- assert(dest.file == GEN_GENERAL_REGISTER_FILE);
- assert(src.file == GEN_GENERAL_REGISTER_FILE);
- assert(dest.hstride == GEN_HORIZONTAL_STRIDE_1);
-
- if (function == GEN_MATH_FUNCTION_INT_DIV_QUOTIENT ||
- function == GEN_MATH_FUNCTION_INT_DIV_REMAINDER ||
- function == GEN_MATH_FUNCTION_INT_DIV_QUOTIENT_AND_REMAINDER) {
- assert(src.type != GEN_TYPE_F);
- } else
- assert(src.type == GEN_TYPE_F);
-
- insn->header.destreg_or_condmod = function;
- insn->header.saturate = saturate;
- this->setDst(insn, dest);
- this->setSrc0(insn, src);
- this->setSrc1(insn, GenReg::null());
- }
-
-
- void GenEmitter::MATH2(GenReg dest, uint32_t function, GenReg src0, GenReg src1)
+ void GenEmitter::MATH(GenReg dest, uint32_t function, GenReg src0, GenReg src1)
{
GenInstruction *insn = this->next(GEN_OPCODE_MATH);
this->setSrc1(insn, src1);
}
- void GenEmitter::MATH16(GenReg dest,
- uint32_t function,
- uint32_t saturate,
- uint32_t msg_reg_nr,
- GenReg src,
- uint32_t precision)
- {
- GenInstruction *insn;
-
- insn = this->next(GEN_OPCODE_MATH);
-
- /* Math is the same ISA format as other opcodes, except that CondModifier
- * becomes FC[3:0] and ThreadCtrl becomes FC[5:4].
- */
- insn->header.destreg_or_condmod = function;
- insn->header.saturate = saturate;
-
- /* Source modifiers are ignored for extended math instructions. */
- assert(!src.negate);
- assert(!src.abs);
-
- this->setHeader(insn);
- this->setDst(insn, dest);
- this->setSrc0(insn, src);
- this->setSrc1(insn, GenReg::null());
- }
-
- /**
- * Texture sample instruction.
- * Note: the msg_type plus msg_length values determine exactly what kind
- * of sampling operation is performed. See volume 4, page 161 of docs.
- */
void GenEmitter::SAMPLE(GenReg dest,
uint32_t msg_reg_nr,
GenReg src0,
void UNTYPED_READ(GenReg dst, GenReg src, uint32_t bti, uint32_t elemNum);
/*! Untyped write (upto 4 channels) */
void UNTYPED_WRITE(GenReg src, uint32_t bti, uint32_t elemNum);
+ /*! Byte gather (for unaligned bytes, shorts and ints) */
+ void BYTE_GATHER(GenReg dst, GenReg src, uint32_t bti, uint32_t type);
+ /*! Byte scatter (for unaligned bytes, shorts and ints) */
+ void BYTE_SCATTER(GenReg src, uint32_t bti, uint32_t type);
/*! Send instruction for the sampler */
void SAMPLE(GenReg dest,
uint32_t msg_reg_nr,
uint32_t header_present,
uint32_t simd_mode,
uint32_t return_format);
- /*! Extended math function, float[16] */
- void MATH16(GenReg dest,
- uint32_t function,
- uint32_t saturate,
- uint32_t msg_reg_nr,
- GenReg src,
- uint32_t precision);
- /*! Extended math function, float[8] */
- void MATH(GenReg dest,
- uint32_t function,
- uint32_t saturate,
- uint32_t msg_reg_nr,
- GenReg src,
- uint32_t data_type,
- uint32_t precision);
/*! Extended math function, float[8] */
- void MATH2(GenReg dest, uint32_t function, GenReg src0, GenReg src1);
+ void MATH(GenReg dest, uint32_t function, GenReg src0, GenReg src1);
/*! Patch JMPI (located at index insnID) with the given jump distance */
void patchJMPI(uint32_t insnID, int32_t jumpDistance);
// Implements all the wellFormed methods
/////////////////////////////////////////////////////////////////////////
- /*! All Nary instruction register must be of the same family and properly
+ /*! All Nary instruction registers must be of the same family and properly
* defined (i.e. not out-of-bound)
*/
static INLINE bool checkRegisterData(RegisterFamily family,
return true;
}
+ /*! We check that the given type belongs to the provided type family */
+ static INLINE bool checkTypeFamily(const Type &type,
+ const Type *family,
+ uint32_t typeNum,
+ std::string &whyNot)
+ {
+ uint32_t typeID = 0;
+ for (; typeID < typeNum; ++typeID)
+ if (family[typeID] == type)
+ break;
+ if (typeID == typeNum) {
+ whyNot = "Type is not supported by the instruction";
+ return false;
+ }
+ return true;
+ }
+
+#define CHECK_TYPE(TYPE, FAMILY) \
+ do { \
+ if (UNLIKELY(checkTypeFamily(TYPE, FAMILY, FAMILY##Num, whyNot)) == false) \
+ return false; \
+ } while (0)
+
+ static const Type madType[] = {TYPE_FLOAT};
+ static const uint32_t madTypeNum = ARRAY_ELEM_NUM(madType);
+
+ // TODO add support for 64 bits values
+ static const Type allButBool[] = {TYPE_S8, TYPE_U8,
+ TYPE_S16, TYPE_U16,
+ TYPE_S32, TYPE_U32,
+ TYPE_FLOAT, TYPE_DOUBLE};
+ static const uint32_t allButBoolNum = ARRAY_ELEM_NUM(allButBool);
+
+ // TODO add support for 64 bits values
+ static const Type logicalType[] = {TYPE_S8, TYPE_U8,
+ TYPE_S16, TYPE_U16,
+ TYPE_S32, TYPE_U32,
+ TYPE_BOOL};
+ static const uint32_t logicalTypeNum = ARRAY_ELEM_NUM(logicalType);
+
// Unary and binary instructions share the same rules
template <uint32_t srcNum>
INLINE bool NaryInstruction<srcNum>::wellFormed(const Function &fn, std::string &whyNot) const
for (uint32_t srcID = 0; srcID < srcNum; ++srcID)
if (UNLIKELY(checkRegisterData(family, src[srcID], fn, whyNot) == false))
return false;
+ // We actually support logical operations on boolean values for AND, OR,
+ // and XOR
+ switch (this->opcode) {
+ case OP_OR:
+ case OP_XOR:
+ case OP_AND:
+ CHECK_TYPE(this->type, logicalType);
+ break;
+ default:
+ CHECK_TYPE(this->type, allButBool);
+ break;
+ }
return true;
}
if (UNLIKELY(checkRegisterData(family, regID, fn, whyNot) == false))
return false;
}
+ if (this->opcode == OP_MAD)
+ CHECK_TYPE(this->type, madType);
+ else
+ NOT_IMPLEMENTED;
return true;
}
if (UNLIKELY(checkRegisterData(family, regID, fn, whyNot) == false))
return false;
}
+ CHECK_TYPE(this->type, allButBool);
return true;
}
for (uint32_t srcID = 0; srcID < 2; ++srcID)
if (UNLIKELY(checkRegisterData(family, src[srcID], fn, whyNot) == false))
return false;
+ CHECK_TYPE(this->type, allButBool);
return true;
}
return false;
if (UNLIKELY(checkRegisterData(srcFamily, src, fn, whyNot) == false))
return false;
+ CHECK_TYPE(this->dstType, allButBool);
+ CHECK_TYPE(this->srcType, allButBool);
return true;
}
if (UNLIKELY(checkRegisterData(family, regID, fn, whyNot) == false))
return false;
}
+ CHECK_TYPE(insn.type, allButBool);
return true;
}
return false;
if (UNLIKELY(checkRegisterData(family, dst, fn, whyNot) == false))
return false;
+ CHECK_TYPE(this->type, allButBool);
return true;
}
return false;
return true;
}
+#undef CHECK_TYPE
/////////////////////////////////////////////////////////////////////////
// Implements all the output stream methods
switch (type) {
case TYPE_BOOL: return out << "bool";
case TYPE_S8: return out << "int8";
- case TYPE_U8: return out << "uin8";
+ case TYPE_U8: return out << "uint8";
case TYPE_S16: return out << "int16";
case TYPE_U16: return out << "uin16";
case TYPE_S32: return out << "int32";
}
void GenWriter::emitBinaryOperator(Instruction &I) {
- GBE_ASSERT(I.getType()->isPointerTy() == false &&
- I.getType() != Type::getInt1Ty(I.getContext()));
+#if GBE_DEBUG
+ GBE_ASSERT(I.getType()->isPointerTy() == false);
+ // We accept logical operations on booleans
+ switch (I.getOpcode()) {
+ case Instruction::And:
+ case Instruction::Or:
+ case Instruction::Xor:
+ break;
+ default:
+ GBE_ASSERT(I.getType() != Type::getInt1Ty(I.getContext()));
+ }
+#endif /* GBE_DEBUG */
// Get the element type for a vector
uint32_t elemNum;