* \file context.hpp
* \author Benjamin Segovia <benjamin.segovia@intel.com>
*/
+
#ifndef __GBE_CONTEXT_HPP__
#define __GBE_CONTEXT_HPP__
GBE_DELETE(this->p);
}
- /*! XXX Make both structures the same! */
- INLINE void setInstructionState(GenInstructionState &dst,
- const SelectionState &src)
- {
- dst.execWidth = src.execWidth;
- dst.quarterControl = src.quarterControl;
- dst.noMask = src.noMask;
- dst.flag = src.flag;
- dst.subFlag = src.subFlag;
- dst.predicate = src.predicate;
- dst.inversePredicate = src.inversePredicate;
- }
-
void GenContext::emitInstructionStream(void) {
// Emit Gen ISA
sel->foreachInstruction([&](const SelectionInstruction &insn) {
const uint32_t opcode = insn.opcode;
p->push();
- setInstructionState(p->curr, insn.state);
+ // no more virtual register here in that part of the code generation
+ GBE_ASSERT(insn.state.physicalFlag);
+ p->curr = insn.state;
switch (opcode) {
#define DECL_SELECTION_IR(OPCODE, FAMILY) \
case SEL_OP_##OPCODE: this->emit##FAMILY(insn); break;
// Use shifts rather than muls which are limited to 32x16 bit sources
const uint32_t perLaneShift = logi2(perLaneSize);
const uint32_t perThreadShift = logi2(perThreadSize);
- const SelectionReg selStatckPtr = this->simdWidth == 8 ?
- SelectionReg::ud8grf(ir::ocl::stackptr) :
- SelectionReg::ud16grf(ir::ocl::stackptr);
- const GenReg stackptr = ra->genReg(selStatckPtr);
+ const GenRegister selStatckPtr = this->simdWidth == 8 ?
+ GenRegister::ud8grf(ir::ocl::stackptr) :
+ GenRegister::ud16grf(ir::ocl::stackptr);
+ const GenRegister stackptr = ra->genReg(selStatckPtr);
const uint32_t nr = offset / GEN_REG_SIZE;
const uint32_t subnr = (offset % GEN_REG_SIZE) / sizeof(uint32_t);
- const GenReg bufferptr = GenReg::ud1grf(nr, subnr);
+ const GenRegister bufferptr = GenRegister::ud1grf(nr, subnr);
// We compute the per-lane stack pointer here
p->push();
p->curr.execWidth = 1;
p->curr.predicate = GEN_PREDICATE_NONE;
- p->SHR(GenReg::ud1grf(126,0), GenReg::ud1grf(0,5), GenReg::immud(10));
+ p->SHR(GenRegister::ud1grf(126,0), GenRegister::ud1grf(0,5), GenRegister::immud(10));
p->curr.execWidth = this->simdWidth;
- p->SHL(stackptr, stackptr, GenReg::immud(perLaneShift));
+ p->SHL(stackptr, stackptr, GenRegister::immud(perLaneShift));
p->curr.execWidth = 1;
- p->SHL(GenReg::ud1grf(126,0), GenReg::ud1grf(126,0), GenReg::immud(perThreadShift));
+ p->SHL(GenRegister::ud1grf(126,0), GenRegister::ud1grf(126,0), GenRegister::immud(perThreadShift));
p->curr.execWidth = this->simdWidth;
p->ADD(stackptr, stackptr, bufferptr);
- p->ADD(stackptr, stackptr, GenReg::ud1grf(126,0));
+ p->ADD(stackptr, stackptr, GenRegister::ud1grf(126,0));
p->pop();
}
}
void GenContext::emitUnaryInstruction(const SelectionInstruction &insn) {
- const GenReg dst = ra->genReg(insn.dst[0]);
- const GenReg src = ra->genReg(insn.src[0]);
+ const GenRegister dst = ra->genReg(insn.dst[0]);
+ const GenRegister src = ra->genReg(insn.src[0]);
switch (insn.opcode) {
case SEL_OP_MOV: p->MOV(dst, src); break;
case SEL_OP_NOT: p->NOT(dst, src); break;
}
void GenContext::emitBinaryInstruction(const SelectionInstruction &insn) {
- const GenReg dst = ra->genReg(insn.dst[0]);
- const GenReg src0 = ra->genReg(insn.src[0]);
- const GenReg src1 = ra->genReg(insn.src[1]);
+ const GenRegister dst = ra->genReg(insn.dst[0]);
+ const GenRegister src0 = ra->genReg(insn.src[0]);
+ const GenRegister src1 = ra->genReg(insn.src[1]);
switch (insn.opcode) {
case SEL_OP_SEL: p->SEL(dst, src0, src1); break;
case SEL_OP_AND: p->AND(dst, src0, src1); break;
}
void GenContext::emitMathInstruction(const SelectionInstruction &insn) {
- const GenReg dst = ra->genReg(insn.dst[0]);
- const GenReg src0 = ra->genReg(insn.src[0]);
- const GenReg src1 = ra->genReg(insn.src[1]);
+ const GenRegister dst = ra->genReg(insn.dst[0]);
+ const GenRegister src0 = ra->genReg(insn.src[0]);
+ const GenRegister src1 = ra->genReg(insn.src[1]);
const uint32_t function = insn.extra.function;
p->MATH(dst, function, src0, src1);
}
void GenContext::emitCompareInstruction(const SelectionInstruction &insn) {
- const GenReg src0 = ra->genReg(insn.src[0]);
- const GenReg src1 = ra->genReg(insn.src[1]);
+ const GenRegister src0 = ra->genReg(insn.src[0]);
+ const GenRegister src1 = ra->genReg(insn.src[1]);
p->CMP(insn.extra.function, src0, src1);
}
void GenContext::emitJumpInstruction(const SelectionInstruction &insn) {
const ir::LabelIndex label(insn.index);
- const GenReg src = ra->genReg(insn.src[0]);
+ const GenRegister src = ra->genReg(insn.src[0]);
this->branchPos2.push_back(std::make_pair(label, p->store.size()));
p->JMPI(src);
}
p->curr.predicate = GEN_PREDICATE_NONE;
p->curr.execWidth = 8;
p->curr.noMask = 1;
- p->MOV(GenReg::f8grf(127,0), GenReg::f8grf(0,0));
+ p->MOV(GenRegister::f8grf(127,0), GenRegister::f8grf(0,0));
p->EOT(127);
p->pop();
}
void GenContext::emitUntypedReadInstruction(const SelectionInstruction &insn) {
- const GenReg dst = ra->genReg(insn.dst[0]);
- const GenReg src = ra->genReg(insn.src[0]);
+ const GenRegister dst = ra->genReg(insn.dst[0]);
+ const GenRegister src = ra->genReg(insn.src[0]);
const uint32_t bti = insn.extra.function;
const uint32_t elemNum = insn.extra.elem;
p->UNTYPED_READ(dst, src, bti, elemNum);
}
void GenContext::emitUntypedWriteInstruction(const SelectionInstruction &insn) {
- const GenReg src = ra->genReg(insn.src[0]);
+ const GenRegister src = ra->genReg(insn.src[0]);
const uint32_t bti = insn.extra.function;
const uint32_t elemNum = insn.extra.elem;
p->UNTYPED_WRITE(src, bti, elemNum);
}
void GenContext::emitByteGatherInstruction(const SelectionInstruction &insn) {
- const GenReg dst = ra->genReg(insn.dst[0]);
- const GenReg src = ra->genReg(insn.src[0]);
+ const GenRegister dst = ra->genReg(insn.dst[0]);
+ const GenRegister src = ra->genReg(insn.src[0]);
const uint32_t bti = insn.extra.function;
const uint32_t elemSize = insn.extra.elem;
p->BYTE_GATHER(dst, src, bti, elemSize);
}
void GenContext::emitByteScatterInstruction(const SelectionInstruction &insn) {
- const GenReg src = ra->genReg(insn.src[0]);
+ const GenRegister src = ra->genReg(insn.src[0]);
const uint32_t bti = insn.extra.function;
const uint32_t elemSize = insn.extra.elem;
p->BYTE_SCATTER(src, bti, elemSize);
void GenContext::emitRegionInstruction(const SelectionInstruction &insn) {
GBE_ASSERT(insn.dst[0].width == GEN_WIDTH_8 ||
insn.dst[0].width == GEN_WIDTH_16);
- const GenReg src = ra->genReg(insn.src[0]);
- const GenReg dst = ra->genReg(insn.dst[1]);
- const GenReg final = ra->genReg(insn.dst[0]);
+ const GenRegister src = ra->genReg(insn.src[0]);
+ const GenRegister dst = ra->genReg(insn.dst[1]);
+ const GenRegister final = ra->genReg(insn.dst[0]);
// Region dimensions
const uint32_t offset = insn.extra.offset;
{
const uint32_t dstnr = dstOffset / GEN_REG_SIZE;
const uint32_t dstsubnr = (dstOffset % GEN_REG_SIZE) / sizeof(int);
- const GenReg dstReg = GenReg::f1grf(dstnr, dstsubnr);
+ const GenRegister dstReg = GenRegister::f1grf(dstnr, dstsubnr);
if (srcOffset + sizeof(int) > end)
- p->MOV(dstReg, GenReg::immf(0.f));
+ p->MOV(dstReg, GenRegister::immf(0.f));
else {
GBE_ASSERT(srcOffset % sizeof(int) == 0);
const uint32_t srcnr = srcOffset / GEN_REG_SIZE;
const uint32_t srcsubnr = (srcOffset % GEN_REG_SIZE) / sizeof(int);
- const GenReg srcReg = GenReg::f1grf(srcnr, srcsubnr);
+ const GenRegister srcReg = GenRegister::f1grf(srcnr, srcsubnr);
p->MOV(dstReg, srcReg);
}
}
}
p->pop();
- p->MOV(GenReg::retype(final, GEN_TYPE_F), GenReg::retype(dst, GEN_TYPE_F));
+ p->MOV(GenRegister::retype(final, GEN_TYPE_F), GenRegister::retype(dst, GEN_TYPE_F));
}
void GenContext::emitRGatherInstruction(const SelectionInstruction &insn) {
- const GenReg index0 = GenReg::retype(ra->genReg(insn.src[0]), GEN_TYPE_UW);
- const GenReg dst0 = GenReg::retype(ra->genReg(insn.dst[0]), GEN_TYPE_F);
- const GenReg src = ra->genReg(insn.src[1]);
+ const GenRegister index0 = GenRegister::retype(ra->genReg(insn.src[0]), GEN_TYPE_UW);
+ const GenRegister dst0 = GenRegister::retype(ra->genReg(insn.dst[0]), GEN_TYPE_F);
+ const GenRegister src = ra->genReg(insn.src[1]);
const uint32_t offset = src.nr * GEN_REG_SIZE + src.subnr;
p->push();
p->curr.execWidth = 8;
- p->SHL(GenReg::addr8(0), index0, GenReg::immuw(2));
- p->ADD(GenReg::addr8(0), GenReg::addr8(0), GenReg::immuw(offset));
- p->MOV(dst0, GenReg::indirect(GEN_TYPE_F, 0, GEN_WIDTH_8));
+ p->SHL(GenRegister::addr8(0), index0, GenRegister::immuw(2));
+ p->ADD(GenRegister::addr8(0), GenRegister::addr8(0), GenRegister::immuw(offset));
+ p->MOV(dst0, GenRegister::indirect(GEN_TYPE_F, 0, GEN_WIDTH_8));
p->pop();
if (simdWidth == 16) {
- const GenReg dst1 = GenReg::Qn(dst0, 1);
- const GenReg index1 = GenReg::Qn(index0, 1);
+ const GenRegister dst1 = GenRegister::Qn(dst0, 1);
+ const GenRegister index1 = GenRegister::Qn(index0, 1);
p->push();
p->curr.execWidth = 8;
p->curr.quarterControl = GEN_COMPRESSION_Q2;
- p->SHL(GenReg::addr8(0), index1, GenReg::immuw(2));
- p->ADD(GenReg::addr8(0), GenReg::addr8(0), GenReg::immuw(offset));
- p->MOV(dst1, GenReg::indirect(GEN_TYPE_F, 0, GEN_WIDTH_8));
+ p->SHL(GenRegister::addr8(0), index1, GenRegister::immuw(2));
+ p->ADD(GenRegister::addr8(0), GenRegister::addr8(0), GenRegister::immuw(offset));
+ p->MOV(dst1, GenRegister::indirect(GEN_TYPE_F, 0, GEN_WIDTH_8));
p->pop();
}
}
void GenContext::emitOBReadInstruction(const SelectionInstruction &insn) {
- const GenReg dst = ra->genReg(insn.dst[0]);
- const GenReg addr = ra->genReg(insn.src[0]);
- const GenReg first = GenReg::ud1grf(addr.nr,addr.subnr/sizeof(float));
- GenReg header;
+ const GenRegister dst = ra->genReg(insn.dst[0]);
+ const GenRegister addr = ra->genReg(insn.src[0]);
+ const GenRegister first = GenRegister::ud1grf(addr.nr,addr.subnr/sizeof(float));
+ GenRegister header;
if (simdWidth == 8)
- header = GenReg::retype(ra->genReg(insn.src[1]), GEN_TYPE_F);
+ header = GenRegister::retype(ra->genReg(insn.src[1]), GEN_TYPE_F);
else
- header = GenReg::retype(GenReg::Qn(ra->genReg(insn.src[1]),1), GEN_TYPE_F);
+ header = GenRegister::retype(GenRegister::Qn(ra->genReg(insn.src[1]),1), GEN_TYPE_F);
p->push();
// Copy r0 into the header first
p->curr.execWidth = 8;
p->curr.predicate = GEN_PREDICATE_NONE;
p->curr.noMask = 1;
- p->MOV(header, GenReg::f8grf(0,0));
+ p->MOV(header, GenRegister::f8grf(0,0));
// Update the header with the current address
p->curr.execWidth = 1;
const uint32_t nr = header.nr;
const uint32_t subnr = header.subnr / sizeof(float);
- p->SHR(GenReg::ud1grf(nr, subnr+2), first, GenReg::immud(4));
+ p->SHR(GenRegister::ud1grf(nr, subnr+2), first, GenRegister::immud(4));
// Put zero in the general state base address
- p->MOV(GenReg::f1grf(nr, subnr+5), GenReg::immf(0));
+ p->MOV(GenRegister::f1grf(nr, subnr+5), GenRegister::immf(0));
// Now read the data
p->OBREAD(dst, header, insn.extra.function, insn.extra.elem);
}
void GenContext::emitOBWriteInstruction(const SelectionInstruction &insn) {
- const GenReg addr = ra->genReg(insn.src[2]);
- const GenReg first = GenReg::ud1grf(addr.nr,addr.subnr/sizeof(float));
- GenReg header;
+ const GenRegister addr = ra->genReg(insn.src[2]);
+ const GenRegister first = GenRegister::ud1grf(addr.nr,addr.subnr/sizeof(float));
+ GenRegister header;
if (simdWidth == 8)
- header = GenReg::retype(ra->genReg(insn.src[0]), GEN_TYPE_F);
+ header = GenRegister::retype(ra->genReg(insn.src[0]), GEN_TYPE_F);
else
- header = GenReg::retype(GenReg::Qn(ra->genReg(insn.src[0]),1), GEN_TYPE_F);
+ header = GenRegister::retype(GenRegister::Qn(ra->genReg(insn.src[0]),1), GEN_TYPE_F);
p->push();
// Copy r0 into the header first
p->curr.execWidth = 8;
p->curr.predicate = GEN_PREDICATE_NONE;
p->curr.noMask = 1;
- p->MOV(header, GenReg::f8grf(0,0));
+ p->MOV(header, GenRegister::f8grf(0,0));
// Update the header with the current address
p->curr.execWidth = 1;
const uint32_t nr = header.nr;
const uint32_t subnr = header.subnr / sizeof(float);
- p->SHR(GenReg::ud1grf(nr, subnr+2), first, GenReg::immud(4));
+ p->SHR(GenRegister::ud1grf(nr, subnr+2), first, GenRegister::immud(4));
// Put zero in the general state base address
- p->MOV(GenReg::f1grf(nr, subnr+5), GenReg::immf(0));
+ p->MOV(GenRegister::f1grf(nr, subnr+5), GenRegister::immf(0));
// Now read the data
p->OBWRITE(header, insn.extra.function, insn.extra.elem);
void emitInstructionStream(void);
/*! Set the correct target values for the branches */
void patchBranches(void);
- /*! Forward ir::Function method */
+ /*! Forward ir::Function isSpecialReg method */
INLINE bool isSpecialReg(ir::Register reg) const {
return fn.isSpecialReg(reg);
}
INLINE const ir::Liveness::LiveOut &getLiveOut(const ir::BasicBlock *bb) const {
return this->liveness->getLiveOut(bb);
}
-
/*! Final Gen ISA emission helper functions */
void emitLabelInstruction(const SelectionInstruction &insn);
void emitUnaryInstruction(const SelectionInstruction &insn);
#endif /* __GBE_GEN_CONTEXT_HPP__ */
+
* Keith Whitwell <keith@tungstengraphics.com>
*/
-#ifndef GEN_DEFINES_H
-#define GEN_DEFINES_H
+#ifndef __GEN_DEFS_HPP__
+#define __GEN_DEFS_HPP__
#include <cstdint>
#define GEN_ALIGN_1 0
#define GEN_ALIGN_16 1
+#define GEN_REG_SIZE 32
+
#define GEN_ADDRESS_DIRECT 0
#define GEN_ADDRESS_REGISTER_INDIRECT_REGISTER 1
} bits3;
};
-#endif /* GEN_DEFINES_H */
+#endif /* __GEN_DEFS_HPP__ */
//////////////////////////////////////////////////////////////////////////
// Some helper functions to encode
//////////////////////////////////////////////////////////////////////////
- INLINE bool isVectorOfBytes(GenReg reg) {
+ INLINE bool isVectorOfBytes(GenRegister reg) {
if (reg.hstride != GEN_HORIZONTAL_STRIDE_0 &&
(reg.type == GEN_TYPE_UB || reg.type == GEN_TYPE_B))
return true;
return false;
}
- INLINE bool needToSplitAlu1(GenEncoder *p, GenReg dst, GenReg src) {
+ INLINE bool needToSplitAlu1(GenEncoder *p, GenRegister dst, GenRegister src) {
if (p->curr.execWidth != 16) return false;
if (isVectorOfBytes(dst) == true) return true;
if (isVectorOfBytes(src) == true) return true;
return false;
}
- INLINE bool needToSplitAlu2(GenEncoder *p, GenReg dst, GenReg src0, GenReg src1) {
+ INLINE bool needToSplitAlu2(GenEncoder *p, GenRegister dst, GenRegister src0, GenRegister src1) {
if (p->curr.execWidth != 16) return false;
if (isVectorOfBytes(dst) == true) return true;
if (isVectorOfBytes(src0) == true) return true;
return false;
}
- INLINE bool needToSplitCmp(GenEncoder *p, GenReg src0, GenReg src1) {
+ INLINE bool needToSplitCmp(GenEncoder *p, GenRegister src0, GenRegister src1) {
if (p->curr.execWidth != 16) return false;
if (isVectorOfBytes(src0) == true) return true;
if (isVectorOfBytes(src1) == true) return true;
bool header_present = false,
bool end_of_thread = false)
{
- p->setSrc1(inst, GenReg::immd(0));
+ p->setSrc1(inst, GenRegister::immd(0));
inst->bits3.generic_gen5.header_present = header_present;
inst->bits3.generic_gen5.response_length = response_length;
inst->bits3.generic_gen5.msg_length = msg_length;
}
}
- void GenEncoder::setDst(GenInstruction *insn, GenReg dest) {
+ void GenEncoder::setDst(GenInstruction *insn, GenRegister dest) {
if (dest.file != GEN_ARCHITECTURE_REGISTER_FILE)
assert(dest.nr < 128);
insn->bits1.da1.dest_horiz_stride = dest.hstride;
}
- void GenEncoder::setSrc0(GenInstruction *insn, GenReg reg) {
+ void GenEncoder::setSrc0(GenInstruction *insn, GenRegister reg) {
if (reg.file != GEN_ARCHITECTURE_REGISTER_FILE)
assert(reg.nr < 128);
insn->bits2.da1.src0_address_mode = reg.address_mode;
if (reg.file == GEN_IMMEDIATE_VALUE) {
- insn->bits3.ud = reg.dw1.ud;
+ insn->bits3.ud = reg.immediate.ud;
/* Required to set some fields in src1 as well: */
insn->bits1.da1.src1_reg_file = 0; /* arf */
}
}
- void GenEncoder::setSrc1(GenInstruction *insn, GenReg reg) {
+ void GenEncoder::setSrc1(GenInstruction *insn, GenRegister reg) {
assert(reg.nr < 128);
insn->bits1.da1.src1_reg_file = reg.file;
assert(insn->bits1.da1.src0_reg_file != GEN_IMMEDIATE_VALUE);
if (reg.file == GEN_IMMEDIATE_VALUE)
- insn->bits3.ud = reg.dw1.ud;
+ insn->bits3.ud = reg.immediate.ud;
else {
assert (reg.address_mode == GEN_ADDRESS_DIRECT);
if (insn->header.access_mode == GEN_ALIGN_1) {
0
};
- void GenEncoder::UNTYPED_READ(GenReg dst, GenReg src, uint32_t bti, uint32_t elemNum) {
+ void GenEncoder::UNTYPED_READ(GenRegister dst, GenRegister src, uint32_t bti, uint32_t elemNum) {
GenInstruction *insn = this->next(GEN_OPCODE_SEND);
assert(elemNum >= 1 || elemNum <= 4);
uint32_t msg_length = 0;
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));
+ this->setDst(insn, GenRegister::uw16grf(dst.nr, 0));
+ this->setSrc0(insn, GenRegister::ud8grf(src.nr, 0));
+ this->setSrc1(insn, GenRegister::immud(0));
setDPUntypedRW(this,
insn,
bti,
response_length);
}
- void GenEncoder::UNTYPED_WRITE(GenReg msg, uint32_t bti, uint32_t elemNum) {
+ void GenEncoder::UNTYPED_WRITE(GenRegister msg, uint32_t bti, uint32_t elemNum) {
GenInstruction *insn = this->next(GEN_OPCODE_SEND);
assert(elemNum >= 1 || elemNum <= 4);
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));
+ this->setDst(insn, GenRegister::retype(GenRegister::null(), GEN_TYPE_UD));
msg_length = 1+elemNum;
} else if (this->curr.execWidth == 16) {
- this->setDst(insn, GenReg::retype(GenReg::null(), GEN_TYPE_UW));
+ this->setDst(insn, GenRegister::retype(GenRegister::null(), GEN_TYPE_UW));
msg_length = 2*(1+elemNum);
}
else
NOT_IMPLEMENTED;
- this->setSrc0(insn, GenReg::ud8grf(msg.nr, 0));
- this->setSrc1(insn, GenReg::immud(0));
+ this->setSrc0(insn, GenRegister::ud8grf(msg.nr, 0));
+ this->setSrc1(insn, GenRegister::immud(0));
setDPUntypedRW(this,
insn,
bti,
response_length);
}
- void GenEncoder::BYTE_GATHER(GenReg dst, GenReg src, uint32_t bti, uint32_t elemSize) {
+ void GenEncoder::BYTE_GATHER(GenRegister dst, GenRegister src, uint32_t bti, uint32_t elemSize) {
GenInstruction *insn = this->next(GEN_OPCODE_SEND);
uint32_t msg_length = 0;
uint32_t response_length = 0;
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));
+ this->setDst(insn, GenRegister::uw16grf(dst.nr, 0));
+ this->setSrc0(insn, GenRegister::ud8grf(src.nr, 0));
+ this->setSrc1(insn, GenRegister::immud(0));
setDPByteScatterGather(this,
insn,
bti,
response_length);
}
- void GenEncoder::BYTE_SCATTER(GenReg msg, uint32_t bti, uint32_t elemSize) {
+ void GenEncoder::BYTE_SCATTER(GenRegister 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));
+ this->setDst(insn, GenRegister::retype(GenRegister::null(), GEN_TYPE_UD));
msg_length = 2;
} else if (this->curr.execWidth == 16) {
- this->setDst(insn, GenReg::retype(GenReg::null(), GEN_TYPE_UW));
+ this->setDst(insn, GenRegister::retype(GenRegister::null(), GEN_TYPE_UW));
msg_length = 4;
} else
NOT_IMPLEMENTED;
- this->setSrc0(insn, GenReg::ud8grf(msg.nr, 0));
- this->setSrc1(insn, GenReg::immud(0));
+ this->setSrc0(insn, GenRegister::ud8grf(msg.nr, 0));
+ this->setSrc1(insn, GenRegister::immud(0));
setDPByteScatterGather(this,
insn,
bti,
return &this->store.back();
}
- INLINE void alu1(GenEncoder *p, uint32_t opcode, GenReg dst, GenReg src) {
+ INLINE void alu1(GenEncoder *p, uint32_t opcode, GenRegister dst, GenRegister src) {
if (needToSplitAlu1(p, dst, src) == false) {
GenInstruction *insn = p->next(opcode);
p->setHeader(insn);
p->setHeader(insnQ2);
insnQ2->header.quarter_control = GEN_COMPRESSION_Q2;
insnQ2->header.execution_size = GEN_WIDTH_8;
- p->setDst(insnQ2, GenReg::Qn(dst, 1));
- p->setSrc0(insnQ2, GenReg::Qn(src, 1));
+ p->setDst(insnQ2, GenRegister::Qn(dst, 1));
+ p->setSrc0(insnQ2, GenRegister::Qn(src, 1));
}
}
INLINE void alu2(GenEncoder *p,
uint32_t opcode,
- GenReg dst,
- GenReg src0,
- GenReg src1,
+ GenRegister dst,
+ GenRegister src0,
+ GenRegister src1,
int accWriteControl = 0)
{
if (needToSplitAlu2(p, dst, src0, src1) == false) {
insnQ2->header.acc_wr_control = accWriteControl;
insnQ2->header.quarter_control = GEN_COMPRESSION_Q2;
insnQ2->header.execution_size = GEN_WIDTH_8;
- p->setDst(insnQ2, GenReg::Qn(dst, 1));
- p->setSrc0(insnQ2, GenReg::Qn(src0, 1));
- p->setSrc1(insnQ2, GenReg::Qn(src1, 1));
+ p->setDst(insnQ2, GenRegister::Qn(dst, 1));
+ p->setSrc0(insnQ2, GenRegister::Qn(src0, 1));
+ p->setSrc1(insnQ2, GenRegister::Qn(src1, 1));
}
}
#if 0
static int
- get_3src_subreg_nr(GenReg reg)
+ get_3src_subreg_nr(GenRegister reg)
{
if (reg.vstride == GEN_VERTICAL_STRIDE_0) {
assert(brw_is_single_value_swizzle(reg.dw1.bits.swizzle));
static GenInstruction *alu3(GenEncoder *p,
uint32_t opcode,
- GenReg dest,
- GenReg src0,
- GenReg src1,
- GenReg src2)
+ GenRegister dest,
+ GenRegister src0,
+ GenRegister src1,
+ GenRegister src2)
{
GenInstruction *insn = p->next(opcode);
#endif
#define ALU1(OP) \
- void GenEncoder::OP(GenReg dest, GenReg src0) { \
+ void GenEncoder::OP(GenRegister dest, GenRegister src0) { \
alu1(this, GEN_OPCODE_##OP, dest, src0); \
}
#define ALU2(OP) \
- void GenEncoder::OP(GenReg dest, GenReg src0, GenReg src1) { \
+ void GenEncoder::OP(GenRegister dest, GenRegister src0, GenRegister src1) { \
alu2(this, GEN_OPCODE_##OP, dest, src0, src1); \
}
#define ALU3(OP) \
- void GenEncoder::OP(GenReg dest, GenReg src0, GenReg src1, GenReg src2) { \
+ void GenEncoder::OP(GenRegister dest, GenRegister src0, GenRegister src1, GenRegister src2) { \
alu3(this, GEN_OPCODE_##OP, dest, src0, src1, src2); \
}
ALU2(PLN)
// ALU3(MAD)
- void GenEncoder::MACH(GenReg dest, GenReg src0, GenReg src1) {
+ void GenEncoder::MACH(GenRegister dest, GenRegister src0, GenRegister src1) {
alu2(this, GEN_OPCODE_MACH, dest, src0, src1, 1);
}
- void GenEncoder::ADD(GenReg dest, GenReg src0, GenReg src1) {
+ void GenEncoder::ADD(GenRegister dest, GenRegister src0, GenRegister src1) {
if (src0.type == GEN_TYPE_F ||
(src0.file == GEN_IMMEDIATE_VALUE &&
src0.type == GEN_TYPE_VF)) {
alu2(this, GEN_OPCODE_ADD, dest, src0, src1);
}
- void GenEncoder::MUL(GenReg dest, GenReg src0, GenReg src1) {
+ void GenEncoder::MUL(GenRegister dest, GenRegister src0, GenRegister src1) {
if (src0.type == GEN_TYPE_D ||
src0.type == GEN_TYPE_UD ||
src1.type == GEN_TYPE_D ||
void GenEncoder::NOP(void) {
GenInstruction *insn = this->next(GEN_OPCODE_NOP);
- this->setDst(insn, GenReg::retype(GenReg::f4grf(0,0), GEN_TYPE_UD));
- this->setSrc0(insn, GenReg::retype(GenReg::f4grf(0,0), GEN_TYPE_UD));
- this->setSrc1(insn, GenReg::immud(0x0));
+ this->setDst(insn, GenRegister::retype(GenRegister::f4grf(0,0), GEN_TYPE_UD));
+ this->setSrc0(insn, GenRegister::retype(GenRegister::f4grf(0,0), GEN_TYPE_UD));
+ this->setSrc1(insn, GenRegister::immud(0x0));
}
- void GenEncoder::JMPI(GenReg src) {
- alu2(this, GEN_OPCODE_JMPI, GenReg::ip(), GenReg::ip(), src);
+ void GenEncoder::JMPI(GenRegister src) {
+ alu2(this, GEN_OPCODE_JMPI, GenRegister::ip(), GenRegister::ip(), src);
}
void GenEncoder::patchJMPI(uint32_t insnID, int32_t jumpDistance) {
GenInstruction &insn = this->store[insnID];
assert(insnID < this->store.size());
assert(insn.header.opcode == GEN_OPCODE_JMPI);
- this->setSrc1(&insn, GenReg::immd(jumpDistance));
+ this->setSrc1(&insn, GenRegister::immd(jumpDistance));
}
- void GenEncoder::CMP(uint32_t conditional, GenReg src0, GenReg src1) {
+ void GenEncoder::CMP(uint32_t conditional, GenRegister src0, GenRegister src1) {
if (needToSplitCmp(this, src0, src1) == false) {
GenInstruction *insn = this->next(GEN_OPCODE_CMP);
this->setHeader(insn);
insn->header.destreg_or_condmod = conditional;
- this->setDst(insn, GenReg::null());
+ this->setDst(insn, GenRegister::null());
this->setSrc0(insn, src0);
this->setSrc1(insn, src1);
} else {
insnQ1->header.quarter_control = GEN_COMPRESSION_Q1;
insnQ1->header.execution_size = GEN_WIDTH_8;
insnQ1->header.destreg_or_condmod = conditional;
- this->setDst(insnQ1, GenReg::null());
+ this->setDst(insnQ1, GenRegister::null());
this->setSrc0(insnQ1, src0);
this->setSrc1(insnQ1, src1);
insnQ2->header.quarter_control = GEN_COMPRESSION_Q2;
insnQ2->header.execution_size = GEN_WIDTH_8;
insnQ2->header.destreg_or_condmod = conditional;
- this->setDst(insnQ2, GenReg::null());
- this->setSrc0(insnQ2, GenReg::Qn(src0, 1));
- this->setSrc1(insnQ2, GenReg::Qn(src1, 1));
+ this->setDst(insnQ2, GenRegister::null());
+ this->setSrc0(insnQ2, GenRegister::Qn(src0, 1));
+ this->setSrc1(insnQ2, GenRegister::Qn(src1, 1));
}
}
void GenEncoder::WAIT(void) {
GenInstruction *insn = this->next(GEN_OPCODE_WAIT);
- GenReg src = GenReg::notification1();
+ GenRegister src = GenRegister::notification1();
this->setDst(insn, src);
this->setSrc0(insn, src);
- this->setSrc1(insn, GenReg::null());
+ this->setSrc1(insn, GenRegister::null());
insn->header.execution_size = 0; /* must */
insn->header.predicate_control = 0;
insn->header.quarter_control = 0;
}
- void GenEncoder::MATH(GenReg dest, uint32_t function, GenReg src0, GenReg src1) {
+ void GenEncoder::MATH(GenRegister dest, uint32_t function, GenRegister src0, GenRegister src1) {
GenInstruction *insn = this->next(GEN_OPCODE_MATH);
assert(dest.file == GEN_GENERAL_REGISTER_FILE);
assert(src0.file == GEN_GENERAL_REGISTER_FILE);
this->setSrc1(insn, src1);
}
- void GenEncoder::SAMPLE(GenReg dest,
+ void GenEncoder::SAMPLE(GenRegister dest,
uint32_t msg_reg_nr,
- GenReg src0,
+ GenRegister src0,
uint32_t bti,
uint32_t sampler,
uint32_t writemask,
return_format);
}
- void GenEncoder::OBREAD(GenReg dst, GenReg header, uint32_t bti, uint32_t size) {
+ void GenEncoder::OBREAD(GenRegister dst, GenRegister header, uint32_t bti, uint32_t size) {
GenInstruction *insn = this->next(GEN_OPCODE_SEND);
const uint32_t msg_length = 1;
const uint32_t response_length = size / 2; // Size is in owords
this->setHeader(insn);
- this->setDst(insn, GenReg::uw16grf(dst.nr, 0));
- this->setSrc0(insn, GenReg::ud8grf(header.nr, 0));
- this->setSrc1(insn, GenReg::immud(0));
+ this->setDst(insn, GenRegister::uw16grf(dst.nr, 0));
+ this->setSrc0(insn, GenRegister::ud8grf(header.nr, 0));
+ this->setSrc1(insn, GenRegister::immud(0));
insn->header.execution_size = response_length == 1 ? GEN_WIDTH_8 : GEN_WIDTH_16;
setOBlockRW(this,
insn,
response_length);
}
- void GenEncoder::OBWRITE(GenReg header, uint32_t bti, uint32_t size) {
+ void GenEncoder::OBWRITE(GenRegister header, uint32_t bti, uint32_t size) {
GenInstruction *insn = this->next(GEN_OPCODE_SEND);
const uint32_t msg_length = 1 + size / 2; // Size is in owords
const uint32_t response_length = 0;
this->setHeader(insn);
- this->setSrc0(insn, GenReg::ud8grf(header.nr, 0));
- this->setSrc1(insn, GenReg::immud(0));
- this->setDst(insn, GenReg::retype(GenReg::null(), GEN_TYPE_UW));
+ this->setSrc0(insn, GenRegister::ud8grf(header.nr, 0));
+ this->setSrc1(insn, GenRegister::immud(0));
+ this->setDst(insn, GenRegister::retype(GenRegister::null(), GEN_TYPE_UW));
insn->header.execution_size = msg_length == 2 ? GEN_WIDTH_8 : GEN_WIDTH_16;
setOBlockRW(this,
insn,
void GenEncoder::EOT(uint32_t msg) {
GenInstruction *insn = this->next(GEN_OPCODE_SEND);
- this->setDst(insn, GenReg::retype(GenReg::null(), GEN_TYPE_UD));
- this->setSrc0(insn, GenReg::ud8grf(msg,0));
- this->setSrc1(insn, GenReg::immud(0));
+ this->setDst(insn, GenRegister::retype(GenRegister::null(), GEN_TYPE_UD));
+ this->setSrc0(insn, GenRegister::ud8grf(msg,0));
+ this->setSrc1(insn, GenRegister::immud(0));
insn->header.execution_size = GEN_WIDTH_8;
insn->bits3.spawner_gen5.resource = GEN_DO_NOT_DEREFERENCE_URB;
insn->bits3.spawner_gen5.msg_length = 1;
#define __GBE_GEN_ENCODER_HPP__
#include "backend/gen_defs.hpp"
+#include "backend/gen_register.hpp"
#include "sys/platform.hpp"
#include "sys/vector.hpp"
#include <cassert>
-#define GEN_REG_SIZE 32
-#define GEN_EU_MAX_INSN_STACK 5
-
namespace gbe
{
- /*! Type size in bytes for each Gen type */
- INLINE int typeSize(uint32_t type) {
- switch(type) {
- case GEN_TYPE_UD:
- case GEN_TYPE_D:
- case GEN_TYPE_F:
- return 4;
- case GEN_TYPE_HF:
- case GEN_TYPE_UW:
- case GEN_TYPE_W:
- return 2;
- case GEN_TYPE_UB:
- case GEN_TYPE_B:
- return 1;
- default:
- assert(0);
- return 0;
- }
- }
-
- /*! Convert a hstride to a number of element */
- INLINE uint32_t stride(uint32_t stride) {
- switch (stride) {
- case 0: return 0;
- case 1: return 1;
- case 2: return 2;
- case 3: return 4;
- case 4: return 8;
- case 5: return 16;
- default: assert(0); return 0;
- }
- }
-
- /*! These are not hardware structs, just something useful to pass around */
- class GenReg
- {
- public:
- /*! Empty constructor */
- INLINE GenReg(void) {}
-
- /*! General constructor */
- INLINE GenReg(uint32_t file,
- uint32_t nr,
- uint32_t subnr,
- uint32_t type,
- uint32_t vstride,
- uint32_t width,
- uint32_t hstride)
- {
- if (file == GEN_GENERAL_REGISTER_FILE)
- assert(nr < GEN_MAX_GRF);
- else if (file == GEN_ARCHITECTURE_REGISTER_FILE)
- assert(nr <= GEN_ARF_IP);
-
- this->type = type;
- this->file = file;
- this->nr = nr;
- this->subnr = subnr * typeSize(type);
- this->negation = 0;
- this->absolute = 0;
- this->vstride = vstride;
- this->width = width;
- this->hstride = hstride;
- this->address_mode = GEN_ADDRESS_DIRECT;
- }
-
- /*! Build an indirectly addressed source */
- static INLINE GenReg indirect(uint32_t type, uint32_t subnr, uint32_t width) {
- GenReg reg;
- reg.type = type;
- reg.file = GEN_GENERAL_REGISTER_FILE;
- reg.address_mode = GEN_ADDRESS_REGISTER_INDIRECT_REGISTER;
- reg.width = width;
- reg.subnr = subnr;
- reg.nr = 0;
- reg.negation = 0;
- reg.absolute = 0;
- reg.vstride = 0;
- reg.hstride = 0;
- return reg;
- }
-
- static INLINE GenReg Qn(GenReg reg, uint32_t quarter) {
- if (reg.hstride == GEN_HORIZONTAL_STRIDE_0) // scalar register
- return reg;
- else {
- const uint32_t typeSz = typeSize(reg.type);
- const uint32_t horizontal = stride(reg.hstride);
- const uint32_t grfOffset = reg.nr*GEN_REG_SIZE + reg.subnr;
- const uint32_t nextOffset = grfOffset + 8*quarter*horizontal*typeSz;
- reg.nr = nextOffset / GEN_REG_SIZE;
- reg.subnr = (nextOffset % GEN_REG_SIZE);
- return reg;
- }
- }
-
- static INLINE GenReg vec16(uint32_t file, uint32_t nr, uint32_t subnr) {
- return GenReg(file,
- nr,
- subnr,
- GEN_TYPE_F,
- GEN_VERTICAL_STRIDE_8,
- GEN_WIDTH_8,
- GEN_HORIZONTAL_STRIDE_1);
- }
-
- static INLINE GenReg vec8(uint32_t file, uint32_t nr, uint32_t subnr) {
- return GenReg(file,
- nr,
- subnr,
- GEN_TYPE_F,
- GEN_VERTICAL_STRIDE_8,
- GEN_WIDTH_8,
- GEN_HORIZONTAL_STRIDE_1);
- }
-
- static INLINE GenReg vec4(uint32_t file, uint32_t nr, uint32_t subnr) {
- return GenReg(file,
- nr,
- subnr,
- GEN_TYPE_F,
- GEN_VERTICAL_STRIDE_4,
- GEN_WIDTH_4,
- GEN_HORIZONTAL_STRIDE_1);
- }
-
- static INLINE GenReg vec2(uint32_t file, uint32_t nr, uint32_t subnr) {
- return GenReg(file,
- nr,
- subnr,
- GEN_TYPE_F,
- GEN_VERTICAL_STRIDE_2,
- GEN_WIDTH_2,
- GEN_HORIZONTAL_STRIDE_1);
- }
-
- static INLINE GenReg vec1(uint32_t file, uint32_t nr, uint32_t subnr) {
- return GenReg(file,
- nr,
- subnr,
- GEN_TYPE_F,
- GEN_VERTICAL_STRIDE_0,
- GEN_WIDTH_1,
- GEN_HORIZONTAL_STRIDE_0);
- }
-
- static INLINE GenReg retype(GenReg reg, uint32_t type) {
- reg.type = type;
- return reg;
- }
-
- static INLINE GenReg suboffset(GenReg reg, uint32_t delta) {
- reg.subnr += delta * typeSize(reg.type);
- return reg;
- }
-
- static INLINE GenReg ud16(uint32_t file, uint32_t nr, uint32_t subnr) {
- return retype(vec16(file, nr, subnr), GEN_TYPE_UD);
- }
-
- static INLINE GenReg ud8(uint32_t file, uint32_t nr, uint32_t subnr) {
- return retype(vec8(file, nr, subnr), GEN_TYPE_UD);
- }
-
- static INLINE GenReg ud1(uint32_t file, uint32_t nr, uint32_t subnr) {
- return retype(vec1(file, nr, subnr), GEN_TYPE_UD);
- }
-
- static INLINE GenReg d8(uint32_t file, uint32_t nr, uint32_t subnr) {
- return retype(vec8(file, nr, subnr), GEN_TYPE_D);
- }
-
- static INLINE GenReg uw16(uint32_t file, uint32_t nr, uint32_t subnr) {
- return suboffset(retype(vec16(file, nr, 0), GEN_TYPE_UW), subnr);
- }
-
- static INLINE GenReg uw8(uint32_t file, uint32_t nr, uint32_t subnr) {
- return suboffset(retype(vec8(file, nr, 0), GEN_TYPE_UW), subnr);
- }
-
- static INLINE GenReg uw1(uint32_t file, uint32_t nr, uint32_t subnr) {
- return suboffset(retype(vec1(file, nr, 0), GEN_TYPE_UW), subnr);
- }
-
- static INLINE GenReg ub16(uint32_t file, uint32_t nr, uint32_t subnr) {
- return GenReg(file,
- nr,
- subnr,
- GEN_TYPE_UB,
- GEN_VERTICAL_STRIDE_16,
- GEN_WIDTH_8,
- GEN_HORIZONTAL_STRIDE_2);
- }
-
- static INLINE GenReg ub8(uint32_t file, uint32_t nr, uint32_t subnr) {
- return GenReg(file,
- nr,
- subnr,
- GEN_TYPE_UB,
- GEN_VERTICAL_STRIDE_16,
- GEN_WIDTH_8,
- GEN_HORIZONTAL_STRIDE_2);
- }
-
- static INLINE GenReg ub1(uint32_t file, uint32_t nr, uint32_t subnr) {
- return suboffset(retype(vec1(file, nr, 0), GEN_TYPE_UB), subnr);
- }
-
- static INLINE GenReg imm(uint32_t type) {
- return GenReg(GEN_IMMEDIATE_VALUE,
- 0,
- 0,
- type,
- GEN_VERTICAL_STRIDE_0,
- GEN_WIDTH_1,
- GEN_HORIZONTAL_STRIDE_0);
- }
-
- static INLINE GenReg immf(float f) {
- GenReg immediate = imm(GEN_TYPE_F);
- immediate.dw1.f = f;
- return immediate;
- }
-
- static INLINE GenReg immd(int d) {
- GenReg immediate = imm(GEN_TYPE_D);
- immediate.dw1.d = d;
- return immediate;
- }
-
- static INLINE GenReg immud(uint32_t ud) {
- GenReg immediate = imm(GEN_TYPE_UD);
- immediate.dw1.ud = ud;
- return immediate;
- }
-
- static INLINE GenReg immuw(uint16_t uw) {
- GenReg immediate = imm(GEN_TYPE_UW);
- immediate.dw1.ud = uw | (uw << 16);
- return immediate;
- }
-
- static INLINE GenReg immw(int16_t w) {
- GenReg immediate = imm(GEN_TYPE_W);
- immediate.dw1.d = w | (w << 16);
- return immediate;
- }
-
- static INLINE GenReg immv(uint32_t v) {
- GenReg immediate = imm(GEN_TYPE_V);
- immediate.vstride = GEN_VERTICAL_STRIDE_0;
- immediate.width = GEN_WIDTH_8;
- immediate.hstride = GEN_HORIZONTAL_STRIDE_1;
- immediate.dw1.ud = v;
- return immediate;
- }
-
- static INLINE GenReg f1grf(uint32_t nr, uint32_t subnr) {
- return vec1(GEN_GENERAL_REGISTER_FILE, nr, subnr);
- }
-
- static INLINE GenReg f2grf(uint32_t nr, uint32_t subnr) {
- return vec2(GEN_GENERAL_REGISTER_FILE, nr, subnr);
- }
-
- static INLINE GenReg f4grf(uint32_t nr, uint32_t subnr) {
- return vec4(GEN_GENERAL_REGISTER_FILE, nr, subnr);
- }
-
- static INLINE GenReg f8grf(uint32_t nr, uint32_t subnr) {
- return vec8(GEN_GENERAL_REGISTER_FILE, nr, subnr);
- }
-
- static INLINE GenReg f16grf(uint32_t nr, uint32_t subnr) {
- return vec16(GEN_GENERAL_REGISTER_FILE, nr, subnr);
- }
-
- static INLINE GenReg ud16grf(uint32_t nr, uint32_t subnr) {
- return ud16(GEN_GENERAL_REGISTER_FILE, nr, subnr);
- }
-
- static INLINE GenReg ud8grf(uint32_t nr, uint32_t subnr) {
- return ud8(GEN_GENERAL_REGISTER_FILE, nr, subnr);
- }
-
- static INLINE GenReg ud1grf(uint32_t nr, uint32_t subnr) {
- return ud1(GEN_GENERAL_REGISTER_FILE, nr, subnr);
- }
-
- static INLINE GenReg uw1grf(uint32_t nr, uint32_t subnr) {
- return uw1(GEN_GENERAL_REGISTER_FILE, nr, subnr);
- }
-
- static INLINE GenReg uw8grf(uint32_t nr, uint32_t subnr) {
- return uw8(GEN_GENERAL_REGISTER_FILE, nr, subnr);
- }
-
- static INLINE GenReg uw16grf(uint32_t nr, uint32_t subnr) {
- return uw16(GEN_GENERAL_REGISTER_FILE, nr, subnr);
- }
-
- static INLINE GenReg ub1grf(uint32_t nr, uint32_t subnr) {
- return ub1(GEN_GENERAL_REGISTER_FILE, nr, subnr);
- }
-
- static INLINE GenReg ub8grf(uint32_t nr, uint32_t subnr) {
- return ub8(GEN_GENERAL_REGISTER_FILE, nr, subnr);
- }
-
- static INLINE GenReg ub16grf(uint32_t nr, uint32_t subnr) {
- return ub16(GEN_GENERAL_REGISTER_FILE, nr, subnr);
- }
-
- static INLINE GenReg null(void) {
- return vec8(GEN_ARCHITECTURE_REGISTER_FILE, GEN_ARF_NULL, 0);
- }
-
- static INLINE GenReg acc(void) {
- return vec8(GEN_ARCHITECTURE_REGISTER_FILE, GEN_ARF_ACCUMULATOR, 0);
- }
-
- static INLINE GenReg ip(void) {
- return GenReg(GEN_ARCHITECTURE_REGISTER_FILE,
- GEN_ARF_IP,
- 0,
- GEN_TYPE_D,
- GEN_VERTICAL_STRIDE_4,
- GEN_WIDTH_1,
- GEN_HORIZONTAL_STRIDE_0);
- }
-
- static INLINE GenReg notification1(void) {
- return GenReg(GEN_ARCHITECTURE_REGISTER_FILE,
- GEN_ARF_NOTIFICATION_COUNT,
- 1,
- GEN_TYPE_UD,
- GEN_VERTICAL_STRIDE_0,
- GEN_WIDTH_1,
- GEN_HORIZONTAL_STRIDE_0);
- }
-
- static INLINE GenReg flag(uint32_t nr, uint32_t subnr) {
- return uw1(GEN_ARCHITECTURE_REGISTER_FILE, GEN_ARF_FLAG | nr, subnr);
- }
-
- static INLINE GenReg mask(uint32_t subnr) {
- return uw1(GEN_ARCHITECTURE_REGISTER_FILE, GEN_ARF_MASK, subnr);
- }
-
- static INLINE GenReg addr1(uint32_t subnr) {
- return uw1(GEN_ARCHITECTURE_REGISTER_FILE, GEN_ARF_ADDRESS, subnr);
- }
-
- static INLINE GenReg addr8(uint32_t subnr) {
- return uw8(GEN_ARCHITECTURE_REGISTER_FILE, GEN_ARF_ADDRESS, subnr);
- }
-
- static INLINE GenReg next(GenReg reg) {
- reg.nr++;
- return reg;
- }
-
- static INLINE GenReg negate(GenReg reg) {
- reg.negation ^= 1;
- return reg;
- }
-
- static INLINE GenReg abs(GenReg reg) {
- reg.absolute = 1;
- reg.negation = 0;
- return reg;
- }
-
- uint32_t type:4;
- uint32_t file:2;
- uint32_t nr:8;
- uint32_t subnr:5; /* :1 in align16 */
- uint32_t negation:1; /* source only */
- uint32_t absolute:1; /* source only */
- uint32_t vstride:4; /* source only */
- uint32_t width:3; /* src only, align1 only */
- uint32_t hstride:2; /* align1 only */
- uint32_t address_mode:1; /* relative addressing, hopefully! */
-
- union {
- float f;
- int32_t d;
- uint32_t ud;
- } dw1;
- };
-
- /*! The state for each instruction. */
- struct GenInstructionState
- {
- uint32_t execWidth:6;
- uint32_t quarterControl:2;
- uint32_t noMask:1;
- uint32_t flag:1;
- uint32_t subFlag:1;
- uint32_t predicate:4;
- uint32_t inversePredicate:1;
- };
-
/*! Helper structure to emit Gen instructions */
class GenEncoder
{
// Encoding functions
////////////////////////////////////////////////////////////////////////
-#define ALU1(OP) void OP(GenReg dest, GenReg src0);
-#define ALU2(OP) void OP(GenReg dest, GenReg src0, GenReg src1);
-#define ALU3(OP) void OP(GenReg dest, GenReg src0, GenReg src1, GenReg src2);
+#define ALU1(OP) void OP(GenRegister dest, GenRegister src0);
+#define ALU2(OP) void OP(GenRegister dest, GenRegister src0, GenRegister src1);
+#define ALU3(OP) void OP(GenRegister dest, GenRegister src0, GenRegister src1, GenRegister src2);
ALU1(MOV)
ALU1(RNDZ)
ALU1(RNDE)
#undef ALU3
/*! Jump indexed instruction */
- void JMPI(GenReg src);
+ void JMPI(GenRegister src);
/*! Compare instructions */
- void CMP(uint32_t conditional, GenReg src0, GenReg src1);
+ void CMP(uint32_t conditional, GenRegister src0, GenRegister src1);
/*! EOT is used to finish GPGPU threads */
void EOT(uint32_t msg_nr);
/*! No-op */
/*! Wait instruction (used for the barrier) */
void WAIT(void);
/*! Untyped read (upto 4 channels) */
- void UNTYPED_READ(GenReg dst, GenReg src, uint32_t bti, uint32_t elemNum);
+ void UNTYPED_READ(GenRegister dst, GenRegister src, uint32_t bti, uint32_t elemNum);
/*! Untyped write (upto 4 channels) */
- void UNTYPED_WRITE(GenReg src, uint32_t bti, uint32_t elemNum);
+ void UNTYPED_WRITE(GenRegister 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 elemSize);
+ void BYTE_GATHER(GenRegister dst, GenRegister src, uint32_t bti, uint32_t elemSize);
/*! Byte scatter (for unaligned bytes, shorts and ints) */
- void BYTE_SCATTER(GenReg src, uint32_t bti, uint32_t elemSize);
+ void BYTE_SCATTER(GenRegister src, uint32_t bti, uint32_t elemSize);
/*! OBlock read */
- void OBREAD(GenReg dst, GenReg header, uint32_t bti, uint32_t elemSize);
+ void OBREAD(GenRegister dst, GenRegister header, uint32_t bti, uint32_t elemSize);
/*! OBlock read */
- void OBWRITE(GenReg header, uint32_t bti, uint32_t elemSize);
+ void OBWRITE(GenRegister header, uint32_t bti, uint32_t elemSize);
/*! Send instruction for the sampler */
- void SAMPLE(GenReg dest,
+ void SAMPLE(GenRegister dest,
uint32_t msg_reg_nr,
- GenReg src0,
+ GenRegister src0,
uint32_t bti,
uint32_t sampler,
uint32_t writemask,
uint32_t simd_mode,
uint32_t return_format);
/*! Extended math function */
- void MATH(GenReg dst, uint32_t function, GenReg src0, GenReg src1);
+ void MATH(GenRegister dst, uint32_t function, GenRegister src0, GenRegister src1);
/*! Patch JMPI (located at index insnID) with the given jump distance */
void patchJMPI(uint32_t insnID, int32_t jumpDistance);
// Helper functions to encode
////////////////////////////////////////////////////////////////////////
void setHeader(GenInstruction *insn);
- void setDst(GenInstruction *insn, GenReg dest);
- void setSrc0(GenInstruction *insn, GenReg reg);
- void setSrc1(GenInstruction *insn, GenReg reg);
+ void setDst(GenInstruction *insn, GenRegister dest);
+ void setSrc0(GenInstruction *insn, GenRegister reg);
+ void setSrc1(GenInstruction *insn, GenRegister reg);
GenInstruction *next(uint32_t opcode);
GBE_CLASS(GenEncoder); //!< Use custom allocators
};
#include "backend/gen_insn_selection.hpp"
#include "backend/gen_context.hpp"
#include "ir/function.hpp"
+#include "sys/cvar.hpp"
namespace gbe
{
///////////////////////////////////////////////////////////////////////////
+ // SelectionInstruction
+ ///////////////////////////////////////////////////////////////////////////
+
+ void SelectionInstruction::appendBefore(const SelectionInstruction &other) {
+ Selection *selection = this->parent->parent;
+ SelectionInstruction *toAppend = selection->newSelectionInstruction(other);
+ SelectionInstruction *prev = this->prev;
+ this->prev = toAppend;
+ toAppend->next = this;
+ if (prev) {
+ toAppend->prev = prev;
+ prev->next = toAppend;
+ } else {
+ GBE_ASSERT (this == this->parent->insnHead);
+ this->parent->insnHead = toAppend;
+ }
+ }
+
+ void SelectionInstruction::appendAfter(const SelectionInstruction &other) {
+ Selection *selection = this->parent->parent;
+ SelectionInstruction *toAppend = selection->newSelectionInstruction(other);
+ SelectionInstruction *next = this->next;
+ this->next = toAppend;
+ toAppend->prev = this;
+ if (next) {
+ toAppend->next = next;
+ next->prev = toAppend;
+ } else {
+ GBE_ASSERT (this == this->parent->insnTail);
+ this->parent->insnTail = toAppend;
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
// Selection
///////////////////////////////////////////////////////////////////////////
+
Selection::Selection(GenContext &ctx) :
ctx(ctx), blockHead(NULL), blockTail(NULL), block(NULL),
curr(ctx.getSimdWidth()), file(ctx.getFunction().getRegisterFile()),
tmp = this->reg(ir::FAMILY_DWORD);
// Generate the MOV instruction and replace the register in the instruction
- SelectionInstruction *mov = this->newSelectionInstruction();
- mov->opcode = SEL_OP_MOV;
- mov->src[0] = SelectionReg::retype(insn->src[regID], GEN_TYPE_F);
- mov->state = SelectionState(simdWidth);
- mov->dstNum = mov->srcNum = 1;
- if (simdWidth == 8)
- insn->src[regID] = mov->dst[0] = SelectionReg::f8grf(tmp);
- else
- insn->src[regID] = mov->dst[0] = SelectionReg::f16grf(tmp);
-
- // Insert the MOV instruction before the current instruction
- SelectionInstruction *prev = insn->prev;
- insn->prev = mov;
- mov->next = insn;
- if (prev) {
- mov->prev = prev;
- prev->next = mov;
- } else {
- GBE_ASSERT (insn == block->insnHead);
- block->insnHead = mov;
- }
+ SelectionInstruction mov;
+ mov.opcode = SEL_OP_MOV;
+ mov.src[0] = GenRegister::retype(insn->src[regID], GEN_TYPE_F);
+ mov.state = GenInstructionState(simdWidth);
+ mov.dstNum = mov.srcNum = 1;
+ insn->src[regID] = mov.dst[0] = GenRegister::fxgrf(simdWidth, tmp);
+ insn->appendBefore(mov);
return tmp;
}
tmp = this->reg(ir::FAMILY_DWORD);
// Generate the MOV instruction and replace the register in the instruction
- SelectionInstruction *mov = this->newSelectionInstruction();
- mov->opcode = SEL_OP_MOV;
- mov->dst[0] = SelectionReg::retype(insn->dst[regID], GEN_TYPE_F);
- mov->state = SelectionState(simdWidth);
- mov->dstNum = mov->srcNum = 1;
- if (simdWidth == 8)
- insn->dst[regID] = mov->src[0] = SelectionReg::f8grf(tmp);
- else
- insn->dst[regID] = mov->src[0] = SelectionReg::f16grf(tmp);
-
- // Insert the MOV instruction after the current instruction
- SelectionInstruction *next = insn->next;
- insn->next = mov;
- mov->prev = insn;
- if (next) {
- mov->next = next;
- next->prev = mov;
- } else {
- GBE_ASSERT (insn == block->insnTail);
- block->insnTail = mov;
- }
+ SelectionInstruction mov;
+ mov.opcode = SEL_OP_MOV;
+ mov.dst[0] = GenRegister::retype(insn->dst[regID], GEN_TYPE_F);
+ mov.state = GenInstructionState(simdWidth);
+ mov.dstNum = mov.srcNum = 1;
+ insn->dst[regID] = mov.src[0] = GenRegister::fxgrf(simdWidth, tmp);
+ insn->appendAfter(mov);
return tmp;
}
#define SEL_REG(SIMD16, SIMD8, SIMD1) \
if (ctx.sel->isScalarOrBool(reg) == true) \
- return SelectionReg::retype(SelectionReg::SIMD1(reg), genType); \
+ return GenRegister::retype(GenRegister::SIMD1(reg), genType); \
else if (simdWidth == 8) \
- return SelectionReg::retype(SelectionReg::SIMD8(reg), genType); \
+ return GenRegister::retype(GenRegister::SIMD8(reg), genType); \
else { \
GBE_ASSERT (simdWidth == 16); \
- return SelectionReg::retype(SelectionReg::SIMD16(reg), genType); \
+ return GenRegister::retype(GenRegister::SIMD16(reg), genType); \
}
- SelectionReg Selection::selReg(ir::Register reg, ir::Type type) {
+ GenRegister Selection::selReg(ir::Register reg, ir::Type type) {
using namespace ir;
const uint32_t genType = getGenType(type);
const uint32_t simdWidth = ctx.getSimdWidth();
default: NOT_SUPPORTED;
}
GBE_ASSERT(false);
- return SelectionReg();
+ return GenRegister();
}
#undef SEL_REG
- SelectionReg Selection::selRegQn(ir::Register reg, uint32_t q, ir::Type type) {
- SelectionReg sreg = this->selReg(reg, type);
+ GenRegister Selection::selRegQn(ir::Register reg, uint32_t q, ir::Type type) {
+ GenRegister sreg = this->selReg(reg, type);
sreg.quarter = q;
return sreg;
}
/*! Syntactic sugar for method declaration */
- typedef const SelectionReg &Reg;
+ typedef const GenRegister &Reg;
void Selection::LABEL(ir::LabelIndex index) {
SelectionInstruction *insn = this->appendInsn();
}
void Selection::UNTYPED_READ(Reg addr,
- const SelectionReg *dst,
+ const GenRegister *dst,
uint32_t elemNum,
uint32_t bti)
{
}
void Selection::UNTYPED_WRITE(Reg addr,
- const SelectionReg *src,
- uint32_t elemNum,
- uint32_t bti)
+ const GenRegister *src,
+ uint32_t elemNum,
+ uint32_t bti)
{
SelectionInstruction *insn = this->appendInsn();
SelectionVector *vector = this->appendVector();
insn->dstNum = 1;
}
- void Selection::REGION(Reg dst0, Reg dst1, const SelectionReg *src,
+ void Selection::REGION(Reg dst0, Reg dst1, const GenRegister *src,
uint32_t offset, uint32_t vstride,
uint32_t width, uint32_t hstride,
uint32_t srcNum)
vector->isSrc = 1;
}
- void Selection::RGATHER(Reg dst, const SelectionReg *src, uint32_t srcNum)
+ void Selection::RGATHER(Reg dst, const GenRegister *src, uint32_t srcNum)
{
SelectionInstruction *insn = this->appendInsn();
SelectionVector *vector = this->appendVector();
void emitFenceInstruction(const ir::FenceInstruction &insn);
void emitLabelInstruction(const ir::LabelInstruction &insn);
/*! It is not natively suppored on Gen. We implement it here */
- void emitIntMul32x32(const ir::Instruction &insn, SelectionReg dst, SelectionReg src0, SelectionReg src1);
+ void emitIntMul32x32(const ir::Instruction &insn, GenRegister dst, GenRegister src0, GenRegister src1);
/*! Use untyped writes and reads for everything aligned on 4 bytes */
- void emitUntypedRead(const ir::LoadInstruction &insn, SelectionReg address);
+ void emitUntypedRead(const ir::LoadInstruction &insn, GenRegister address);
void emitUntypedWrite(const ir::StoreInstruction &insn);
/*! Use byte scatters and gathers for everything not aligned on 4 bytes */
- void emitByteGather(const ir::LoadInstruction &insn, SelectionReg address, SelectionReg value);
- void emitByteScatter(const ir::StoreInstruction &insn, SelectionReg address, SelectionReg value);
+ void emitByteGather(const ir::LoadInstruction &insn, GenRegister address, GenRegister value);
+ void emitByteScatter(const ir::StoreInstruction &insn, GenRegister address, GenRegister value);
/*! Backward and forward branches are handled slightly differently */
void emitForwardBranch(const ir::BranchInstruction&, ir::LabelIndex dst, ir::LabelIndex src);
void emitBackwardBranch(const ir::BranchInstruction&, ir::LabelIndex dst, ir::LabelIndex src);
}
void SimpleSelection::emitIntMul32x32(const ir::Instruction &insn,
- SelectionReg dst,
- SelectionReg src0,
- SelectionReg src1)
+ GenRegister dst,
+ GenRegister src0,
+ GenRegister src1)
{
using namespace ir;
- const uint32_t width = this->curr.execWidth;
+ const uint32_t simdWidth = this->curr.execWidth;
this->push();
// Either left part of the 16-wide register or just a simd 8 register
- dst = SelectionReg::retype(dst, GEN_TYPE_D);
- src0 = SelectionReg::retype(src0, GEN_TYPE_D);
- src1 = SelectionReg::retype(src1, GEN_TYPE_D);
+ dst = GenRegister::retype(dst, GEN_TYPE_D);
+ src0 = GenRegister::retype(src0, GEN_TYPE_D);
+ src1 = GenRegister::retype(src1, GEN_TYPE_D);
this->curr.execWidth = 8;
this->curr.quarterControl = GEN_COMPRESSION_Q1;
- this->MUL(SelectionReg::retype(SelectionReg::acc(), GEN_TYPE_D), src0, src1);
- this->MACH(SelectionReg::retype(SelectionReg::null(), GEN_TYPE_D), src0, src1);
- this->MOV(SelectionReg::retype(dst, GEN_TYPE_F), SelectionReg::acc());
+ this->MUL(GenRegister::retype(GenRegister::acc(), GEN_TYPE_D), src0, src1);
+ this->MACH(GenRegister::retype(GenRegister::null(), GEN_TYPE_D), src0, src1);
+ this->MOV(GenRegister::retype(dst, GEN_TYPE_F), GenRegister::acc());
// Right part of the 16-wide register now
- if (width == 16) {
+ if (simdWidth == 16) {
this->curr.noMask = 1;
- const SelectionReg nextSrc0 = this->selRegQn(insn.getSrc(0), 1, TYPE_S32);
- const SelectionReg nextSrc1 = this->selRegQn(insn.getSrc(1), 1, TYPE_S32);
- this->MUL(SelectionReg::retype(SelectionReg::acc(), GEN_TYPE_D), nextSrc0, nextSrc1);
- this->MACH(SelectionReg::retype(SelectionReg::null(), GEN_TYPE_D), nextSrc0, nextSrc1);
+ const GenRegister nextSrc0 = this->selRegQn(insn.getSrc(0), 1, TYPE_S32);
+ const GenRegister nextSrc1 = this->selRegQn(insn.getSrc(1), 1, TYPE_S32);
+ this->MUL(GenRegister::retype(GenRegister::acc(), GEN_TYPE_D), nextSrc0, nextSrc1);
+ this->MACH(GenRegister::retype(GenRegister::null(), GEN_TYPE_D), nextSrc0, nextSrc1);
this->curr.quarterControl = GEN_COMPRESSION_Q2;
const ir::Register reg = this->reg(FAMILY_DWORD);
- this->MOV(SelectionReg::f8grf(reg), SelectionReg::acc());
+ this->MOV(GenRegister::f8grf(reg), GenRegister::acc());
this->curr.noMask = 0;
- this->MOV(SelectionReg::retype(SelectionReg::next(dst), GEN_TYPE_F),
- SelectionReg::f8grf(reg));
+ this->MOV(GenRegister::retype(GenRegister::next(dst), GEN_TYPE_F),
+ GenRegister::f8grf(reg));
}
this->pop();
using namespace ir;
const Opcode opcode = insn.getOpcode();
const Type type = insn.getType();
- SelectionReg dst = this->selReg(insn.getDst(0), type);
- SelectionReg src0 = this->selReg(insn.getSrc(0), type);
- SelectionReg src1 = this->selReg(insn.getSrc(1), type);
+ GenRegister dst = this->selReg(insn.getDst(0), type);
+ GenRegister src0 = this->selReg(insn.getSrc(0), type);
+ GenRegister src1 = this->selReg(insn.getSrc(1), type);
this->push();
// Output the binary instruction
switch (opcode) {
case OP_ADD: this->ADD(dst, src0, src1); break;
- case OP_SUB: this->ADD(dst, src0, SelectionReg::negate(src1)); break;
+ case OP_SUB: this->ADD(dst, src0, GenRegister::negate(src1)); break;
case OP_AND: this->AND(dst, src0, src1); break;
case OP_XOR: this->XOR(dst, src0, src1); break;
case OP_OR: this->OR(dst, src0, src1); break;
// Get all registers for the instruction
const Type type = insn.getType();
- const SelectionReg pred = this->selReg(insn.getPredicate(), TYPE_BOOL);
- const SelectionReg dst = this->selReg(insn.getDst(0), type);
- const SelectionReg src0 = this->selReg(insn.getSrc(SelectInstruction::src0Index), type);
- const SelectionReg src1 = this->selReg(insn.getSrc(SelectInstruction::src1Index), type);
+ const GenRegister dst = this->selReg(insn.getDst(0), type);
+ const GenRegister src0 = this->selReg(insn.getSrc(SelectInstruction::src0Index), type);
+ const GenRegister src1 = this->selReg(insn.getSrc(SelectInstruction::src1Index), type);
// Since we cannot predicate the select instruction with our current mask,
// we need to perform the selection in two steps (one to select, one to
// update the destination register)
const RegisterFamily family = getFamily(type);
- const SelectionReg tmp = this->selReg(this->reg(family), type);
+ const GenRegister tmp = this->selReg(this->reg(family), type);
const uint32_t simdWidth = ctx.getSimdWidth();
-
+ const Register pred = insn.getPredicate();
this->push();
- // Move the predicate into a flag register (TODO use cmp:w with blockIP)
- this->curr.predicate = GEN_PREDICATE_NONE;
- this->curr.execWidth = 1;
- this->curr.noMask = 1;
- this->MOV(SelectionReg::flag(0,1), pred);
-
- // Perform the selection
this->curr.predicate = GEN_PREDICATE_NORMAL;
this->curr.execWidth = simdWidth;
+ this->curr.physicalFlag = 0;
+ this->curr.flagIndex = uint16_t(pred);
this->curr.noMask = 0;
- this->curr.flag = 0;
- this->curr.subFlag = 1;
this->SEL(tmp, src0, src1);
this->pop();
using namespace ir;
const Type type = insn.getType();
const Immediate imm = insn.getImmediate();
- const SelectionReg dst = this->selReg(insn.getDst(0), type);
+ const GenRegister dst = this->selReg(insn.getDst(0), type);
switch (type) {
- case TYPE_U32: this->MOV(dst, SelectionReg::immud(imm.data.u32)); break;
- case TYPE_S32: this->MOV(dst, SelectionReg::immd(imm.data.s32)); break;
- case TYPE_U16: this->MOV(dst, SelectionReg::immuw(imm.data.u16)); break;
- case TYPE_S16: this->MOV(dst, SelectionReg::immw(imm.data.s16)); break;
- case TYPE_U8: this->MOV(dst, SelectionReg::immuw(imm.data.u8)); break;
- case TYPE_S8: this->MOV(dst, SelectionReg::immw(imm.data.s8)); break;
- case TYPE_FLOAT: this->MOV(dst, SelectionReg::immf(imm.data.f32)); break;
+ case TYPE_U32: this->MOV(dst, GenRegister::immud(imm.data.u32)); break;
+ case TYPE_S32: this->MOV(dst, GenRegister::immd(imm.data.s32)); break;
+ case TYPE_U16: this->MOV(dst, GenRegister::immuw(imm.data.u16)); break;
+ case TYPE_S16: this->MOV(dst, GenRegister::immw(imm.data.s16)); break;
+ case TYPE_U8: this->MOV(dst, GenRegister::immuw(imm.data.u8)); break;
+ case TYPE_S8: this->MOV(dst, GenRegister::immw(imm.data.s8)); break;
+ case TYPE_FLOAT: this->MOV(dst, GenRegister::immf(imm.data.f32)); break;
default: NOT_SUPPORTED;
}
}
- void SimpleSelection::emitUntypedRead(const ir::LoadInstruction &insn, SelectionReg addr)
+ void SimpleSelection::emitUntypedRead(const ir::LoadInstruction &insn, GenRegister addr)
{
using namespace ir;
const uint32_t valueNum = insn.getValueNum();
- SelectionReg dst[valueNum];
+ GenRegister dst[valueNum];
for (uint32_t dstID = 0; dstID < valueNum; ++dstID)
- dst[dstID] = SelectionReg::retype(this->selReg(insn.getValue(dstID)), GEN_TYPE_F);
+ dst[dstID] = GenRegister::retype(this->selReg(insn.getValue(dstID)), GEN_TYPE_F);
this->UNTYPED_READ(addr, dst, valueNum, 0);
}
}
void SimpleSelection::emitByteGather(const ir::LoadInstruction &insn,
- SelectionReg address,
- SelectionReg value)
+ GenRegister address,
+ GenRegister value)
{
using namespace ir;
GBE_ASSERT(insn.getValueNum() == 1);
if (elemSize == GEN_BYTE_SCATTER_WORD ||
elemSize == GEN_BYTE_SCATTER_BYTE) {
dst = this->reg(FAMILY_DWORD);
- if (simdWidth == 8)
- this->BYTE_GATHER(SelectionReg::f8grf(dst), address, elemSize, 0);
- else if (simdWidth == 16)
- this->BYTE_GATHER(SelectionReg::f16grf(dst), address, elemSize, 0);
- else
- NOT_IMPLEMENTED;
+ this->BYTE_GATHER(GenRegister::fxgrf(simdWidth, dst), address, elemSize, 0);
}
// Repack bytes or words using a converting mov instruction
if (elemSize == GEN_BYTE_SCATTER_WORD)
- this->MOV(SelectionReg::retype(value, GEN_TYPE_UW), SelectionReg::unpacked_uw(dst));
+ this->MOV(GenRegister::retype(value, GEN_TYPE_UW), GenRegister::unpacked_uw(dst));
else if (elemSize == GEN_BYTE_SCATTER_BYTE)
- this->MOV(SelectionReg::retype(value, GEN_TYPE_UB), SelectionReg::unpacked_ub(dst));
+ this->MOV(GenRegister::retype(value, GEN_TYPE_UB), GenRegister::unpacked_ub(dst));
}
void SimpleSelection::emitLoadInstruction(const ir::LoadInstruction &insn) {
using namespace ir;
- const SelectionReg address = this->selReg(insn.getAddress());
+ const GenRegister address = this->selReg(insn.getAddress());
GBE_ASSERT(insn.getAddressSpace() == MEM_GLOBAL ||
insn.getAddressSpace() == MEM_PRIVATE);
GBE_ASSERT(ctx.isScalarReg(insn.getValue(0)) == false);
if (insn.isAligned() == true)
this->emitUntypedRead(insn, address);
else {
- const SelectionReg value = this->selReg(insn.getValue(0));
+ const GenRegister value = this->selReg(insn.getValue(0));
this->emitByteGather(insn, address, value);
}
}
using namespace ir;
const uint32_t valueNum = insn.getValueNum();
const uint32_t addrID = ir::StoreInstruction::addressIndex;
- SelectionReg addr, value[valueNum];
+ GenRegister addr, value[valueNum];
- addr = SelectionReg::retype(this->selReg(insn.getSrc(addrID)), GEN_TYPE_F);;
+ addr = GenRegister::retype(this->selReg(insn.getSrc(addrID)), GEN_TYPE_F);;
for (uint32_t valueID = 0; valueID < valueNum; ++valueID)
- value[valueID] = SelectionReg::retype(this->selReg(insn.getValue(valueID)), GEN_TYPE_F);
+ value[valueID] = GenRegister::retype(this->selReg(insn.getValue(valueID)), GEN_TYPE_F);
this->UNTYPED_WRITE(addr, value, valueNum, 0);
}
void SimpleSelection::emitByteScatter(const ir::StoreInstruction &insn,
- SelectionReg addr,
- SelectionReg value)
+ GenRegister addr,
+ GenRegister value)
{
using namespace ir;
const Type type = insn.getValueType();
const uint32_t elemSize = getByteScatterGatherSize(type);
const uint32_t simdWidth = ctx.getSimdWidth();
- const SelectionReg dst = value;
+ const GenRegister dst = value;
GBE_ASSERT(insn.getValueNum() == 1);
- if (simdWidth == 8) {
- if (elemSize == GEN_BYTE_SCATTER_WORD) {
- value = SelectionReg::ud8grf(this->reg(FAMILY_DWORD));
- this->MOV(value, SelectionReg::retype(dst, GEN_TYPE_UW));
- } else if (elemSize == GEN_BYTE_SCATTER_BYTE) {
- value = SelectionReg::ud8grf(this->reg(FAMILY_DWORD));
- this->MOV(value, SelectionReg::retype(dst, GEN_TYPE_UB));
- }
- } else if (simdWidth == 16) {
- if (elemSize == GEN_BYTE_SCATTER_WORD) {
- value = SelectionReg::ud16grf(this->reg(FAMILY_DWORD));
- this->MOV(value, SelectionReg::retype(dst, GEN_TYPE_UW));
- } else if (elemSize == GEN_BYTE_SCATTER_BYTE) {
- value = SelectionReg::ud16grf(this->reg(FAMILY_DWORD));
- this->MOV(value, SelectionReg::retype(dst, GEN_TYPE_UB));
- }
- } else
- NOT_IMPLEMENTED;
-
+ if (elemSize == GEN_BYTE_SCATTER_WORD) {
+ value = GenRegister::udxgrf(simdWidth, this->reg(FAMILY_DWORD));
+ this->MOV(value, GenRegister::retype(dst, GEN_TYPE_UW));
+ } else if (elemSize == GEN_BYTE_SCATTER_BYTE) {
+ value = GenRegister::udxgrf(simdWidth, this->reg(FAMILY_DWORD));
+ this->MOV(value, GenRegister::retype(dst, GEN_TYPE_UB));
+ }
this->BYTE_SCATTER(addr, value, elemSize, 1);
}
if (insn.isAligned() == true)
this->emitUntypedWrite(insn);
else {
- const SelectionReg address = this->selReg(insn.getAddress());
- const SelectionReg value = this->selReg(insn.getValue(0));
+ const GenRegister address = this->selReg(insn.getAddress());
+ const GenRegister value = this->selReg(insn.getValue(0));
this->emitByteScatter(insn, address, value);
}
}
ir::LabelIndex src)
{
using namespace ir;
- const SelectionReg ip = this->selReg(ocl::blockip, TYPE_U16);
+ const GenRegister ip = this->selReg(ocl::blockip, TYPE_U16);
const LabelIndex jip = ctx.getLabelIndex(&insn);
const uint32_t simdWidth = ctx.getSimdWidth();
// Inefficient code. If the instruction is predicated, we build the flag
// register from the boolean vector
if (insn.isPredicated() == true) {
- const SelectionReg pred = this->selReg(insn.getPredicateIndex(), TYPE_U16);
-
- // Reset the flag register
- this->push();
- this->curr.predicate = GEN_PREDICATE_NONE;
- this->curr.execWidth = 1;
- this->curr.noMask = 1;
- this->MOV(SelectionReg::flag(0,1), pred);
- this->pop();
+ const Register pred = insn.getPredicateIndex();
// Update the PcIPs
this->push();
- this->curr.flag = 0;
- this->curr.subFlag = 1;
- this->MOV(ip, SelectionReg::immuw(uint16_t(dst)));
+ this->curr.physicalFlag = 0;
+ this->curr.flagIndex = uint16_t(pred);
+ this->MOV(ip, GenRegister::immuw(uint16_t(dst)));
this->pop();
if (nextLabel == jip) return;
// all PcIPs are greater than the next block IP to be sure that we can
// jump
this->push();
+ this->curr.physicalFlag = 0;
+ this->curr.flagIndex = uint16_t(pred);
this->curr.predicate = GEN_PREDICATE_NONE;
- this->curr.flag = 0;
- this->curr.subFlag = 1;
- this->CMP(GEN_CONDITIONAL_G, ip, SelectionReg::immuw(nextLabel));
+ this->CMP(GEN_CONDITIONAL_G, ip, GenRegister::immuw(nextLabel));
// Branch to the jump target
if (simdWidth == 8)
NOT_SUPPORTED;
this->curr.execWidth = 1;
this->curr.noMask = 1;
- this->JMPI(SelectionReg::immd(0), jip);
+ this->JMPI(GenRegister::immd(0), jip);
this->pop();
} else {
// Update the PcIPs
- this->MOV(ip, SelectionReg::immuw(uint16_t(dst)));
+ this->MOV(ip, GenRegister::immuw(uint16_t(dst)));
// Do not emit branch when we go to the next block anyway
if (nextLabel == jip) return;
this->curr.execWidth = 1;
this->curr.noMask = 1;
this->curr.predicate = GEN_PREDICATE_NONE;
- this->JMPI(SelectionReg::immd(0), jip);
+ this->JMPI(GenRegister::immd(0), jip);
this->pop();
}
}
ir::LabelIndex src)
{
using namespace ir;
- const SelectionReg ip = this->selReg(ocl::blockip, TYPE_U16);
+ const GenRegister ip = this->selReg(ocl::blockip, TYPE_U16);
const Function &fn = ctx.getFunction();
const BasicBlock &bb = fn.getBlock(src);
const LabelIndex jip = ctx.getLabelIndex(&insn);
// Inefficient code: we make a GRF to flag conversion
if (insn.isPredicated() == true) {
- const SelectionReg pred = this->selReg(insn.getPredicateIndex(), TYPE_U16);
+ const Register pred = insn.getPredicateIndex();
// Update the PcIPs for all the branches. Just put the IPs of the next
// block. Next instruction will properly reupdate the IPs of the lanes
// that actually take the branch
const LabelIndex next = bb.getNextBlock()->getLabelIndex();
- this->MOV(ip, SelectionReg::immuw(uint16_t(next)));
-
- // Rebuild the flag register by comparing the boolean with 1s
- this->push();
- this->curr.noMask = 1;
- this->curr.execWidth = 1;
- this->curr.predicate = GEN_PREDICATE_NONE;
- this->MOV(SelectionReg::flag(0,1), pred);
- this->pop();
+ this->MOV(ip, GenRegister::immuw(uint16_t(next)));
this->push();
- this->curr.flag = 0;
- this->curr.subFlag = 1;
-
// Re-update the PcIPs for the branches that takes the backward jump
- this->MOV(ip, SelectionReg::immuw(uint16_t(dst)));
+ this->curr.physicalFlag = 0;
+ this->curr.flagIndex = uint16_t(pred);
+ this->MOV(ip, GenRegister::immuw(uint16_t(dst)));
// Branch to the jump target
if (simdWidth == 8)
NOT_SUPPORTED;
this->curr.execWidth = 1;
this->curr.noMask = 1;
- this->JMPI(SelectionReg::immd(0), jip);
+ this->JMPI(GenRegister::immd(0), jip);
this->pop();
} else {
// Update the PcIPs
- this->MOV(ip, SelectionReg::immuw(uint16_t(dst)));
+ this->MOV(ip, GenRegister::immuw(uint16_t(dst)));
// Branch to the jump target
this->push();
this->curr.execWidth = 1;
this->curr.noMask = 1;
this->curr.predicate = GEN_PREDICATE_NONE;
- this->JMPI(SelectionReg::immd(0), jip);
+ this->JMPI(GenRegister::immd(0), jip);
this->pop();
}
}
-
void SimpleSelection::emitCompareInstruction(const ir::CompareInstruction &insn) {
using namespace ir;
const Opcode opcode = insn.getOpcode();
const Type type = insn.getType();
const uint32_t genCmp = getGenCompare(opcode);
- const SelectionReg dst = this->selReg(insn.getDst(0), TYPE_BOOL);
- const SelectionReg src0 = this->selReg(insn.getSrc(0), type);
- const SelectionReg src1 = this->selReg(insn.getSrc(1), type);
+ const Register dst = insn.getDst(0);
+ const GenRegister src0 = this->selReg(insn.getSrc(0), type);
+ const GenRegister src1 = this->selReg(insn.getSrc(1), type);
- // Copy the predicate to save it basically (TODO use cmp:w with blockIP)
+ // Limit the compare to the active lanes. Use the same compare as for f0.0
this->push();
- this->curr.noMask = 1;
- this->curr.execWidth = 1;
+ const LabelIndex label = insn.getParent()->getLabelIndex();
+ const GenRegister blockip = this->selReg(ocl::blockip, TYPE_U16);
+ const GenRegister labelReg = GenRegister::immuw(label);
this->curr.predicate = GEN_PREDICATE_NONE;
- this->MOV(SelectionReg::flag(0,1), SelectionReg::flag(0,0));
+ this->curr.physicalFlag = 0;
+ this->curr.flagIndex = uint16_t(dst);
+ this->CMP(GEN_CONDITIONAL_LE, blockip, labelReg);
this->pop();
- // Emit the compare instruction itself
this->push();
- this->curr.flag = 0;
- this->curr.subFlag = 1;
+ this->curr.physicalFlag = 0;
+ this->curr.flagIndex = uint16_t(dst);
this->CMP(genCmp, src0, src1);
this->pop();
-
- // We emit an unoptimized code where we store the resulting mask in a GRF
- this->push();
- this->curr.execWidth = 1;
- this->curr.predicate = GEN_PREDICATE_NONE;
- this->MOV(dst, SelectionReg::flag(0,1));
- this->pop();
}
void SimpleSelection::emitConvertInstruction(const ir::ConvertInstruction &insn) {
const Type srcType = insn.getSrcType();
const RegisterFamily dstFamily = getFamily(dstType);
const RegisterFamily srcFamily = getFamily(srcType);
- const SelectionReg dst = this->selReg(insn.getDst(0), dstType);
- const SelectionReg src = this->selReg(insn.getSrc(0), srcType);
+ const GenRegister dst = this->selReg(insn.getDst(0), dstType);
+ const GenRegister src = this->selReg(insn.getSrc(0), srcType);
GBE_ASSERT(dstFamily != FAMILY_QWORD && srcFamily != FAMILY_QWORD);
// We need two instructions to make the conversion
if (dstFamily != FAMILY_DWORD && srcFamily == FAMILY_DWORD) {
- SelectionReg unpacked;
+ GenRegister unpacked;
if (dstFamily == FAMILY_WORD) {
const uint32_t type = TYPE_U16 ? GEN_TYPE_UW : GEN_TYPE_W;
- unpacked = SelectionReg::unpacked_uw(this->reg(FAMILY_DWORD));
- unpacked = SelectionReg::retype(unpacked, type);
+ unpacked = GenRegister::unpacked_uw(this->reg(FAMILY_DWORD));
+ unpacked = GenRegister::retype(unpacked, type);
} else {
const uint32_t type = TYPE_U8 ? GEN_TYPE_UB : GEN_TYPE_B;
- unpacked = SelectionReg::unpacked_ub(this->reg(FAMILY_DWORD));
- unpacked = SelectionReg::retype(unpacked, type);
+ unpacked = GenRegister::unpacked_ub(this->reg(FAMILY_DWORD));
+ unpacked = GenRegister::retype(unpacked, type);
}
this->MOV(unpacked, src);
this->MOV(dst, unpacked);
void SimpleSelection::emitLabelInstruction(const ir::LabelInstruction &insn) {
using namespace ir;
const LabelIndex label = insn.getLabelIndex();
- const SelectionReg src0 = this->selReg(ocl::blockip);
- const SelectionReg src1 = SelectionReg::immuw(label);
+ const GenRegister src0 = this->selReg(ocl::blockip);
+ const GenRegister src1 = GenRegister::immuw(label);
const uint32_t simdWidth = ctx.getSimdWidth();
this->LABEL(label);
this->push();
this->curr.predicate = GEN_PREDICATE_NONE;
this->curr.flag = 0;
- this->CMP(GEN_CONDITIONAL_LE, SelectionReg::retype(src0, GEN_TYPE_UW), src1);
+ this->curr.subFlag = 0;
+ this->CMP(GEN_CONDITIONAL_LE, GenRegister::retype(src0, GEN_TYPE_UW), src1);
this->pop();
// If it is required, insert a JUMP to bypass the block
this->curr.flag = 0;
this->curr.subFlag = 0;
this->curr.noMask = 1;
- this->JMPI(SelectionReg::immd(0), jip);
+ this->JMPI(GenRegister::immd(0), jip);
this->pop();
}
}
using namespace ir;
// Two destinations: one is the real destination, one is a temporary
- SelectionReg dst0 = this->selReg(insn.getDst(0)), dst1;
+ GenRegister dst0 = this->selReg(insn.getDst(0)), dst1;
if (ctx.getSimdWidth() == 8)
- dst1 = SelectionReg::ud8grf(this->reg(FAMILY_DWORD));
+ dst1 = GenRegister::ud8grf(this->reg(FAMILY_DWORD));
else
- dst1 = SelectionReg::ud16grf(this->reg(FAMILY_DWORD));
+ dst1 = GenRegister::ud16grf(this->reg(FAMILY_DWORD));
// Get all the sources
- SelectionReg src[SelectionInstruction::MAX_SRC_NUM];
+ GenRegister src[SelectionInstruction::MAX_SRC_NUM];
const uint32_t srcNum = insn.getSrcNum();
GBE_ASSERT(srcNum <= SelectionInstruction::MAX_SRC_NUM);
for (uint32_t srcID = 0; srcID < insn.getSrcNum(); ++srcID)
void SimpleSelection::emitVoteInstruction(const ir::VoteInstruction &insn) {
using namespace ir;
const uint32_t simdWidth = ctx.getSimdWidth();
- const SelectionReg dst = this->selReg(insn.getDst(0), TYPE_U16);
- const SelectionReg src = this->selReg(insn.getSrc(0), TYPE_U16);
+ const GenRegister dst = this->selReg(insn.getDst(0), TYPE_U16);
+ const GenRegister src = this->selReg(insn.getSrc(0), TYPE_U16);
- // Limit the vote to the active lanes
+ // Limit the vote to the active lanes. Use the same compare as for f0.0
this->push();
- // Move the predicate into a flag register (TODO use cmp:w with blockIP)
+ const LabelIndex label = insn.getParent()->getLabelIndex();
+ const GenRegister blockip = this->selReg(ocl::blockip, TYPE_U16);
+ const GenRegister labelReg = GenRegister::immuw(label);
this->curr.predicate = GEN_PREDICATE_NONE;
- this->curr.execWidth = 1;
- this->curr.noMask = 1;
- this->MOV(SelectionReg::flag(0,1), SelectionReg::flag(0,0));
+ this->curr.flag = 0;
+ this->curr.subFlag = 1;
+ this->CMP(GEN_CONDITIONAL_LE, blockip, labelReg);
this->pop();
// Emit the compare instruction to get the flag register
const uint32_t genCmp = vote == VOTE_ANY ? GEN_CONDITIONAL_NEQ : GEN_CONDITIONAL_EQ;
this->curr.flag = 0;
this->curr.subFlag = 1;
- this->CMP(genCmp, src, SelectionReg::immuw(0));
+ this->CMP(genCmp, src, GenRegister::immuw(0));
this->pop();
// Broadcast the result to the destination
if (vote == VOTE_ANY)
- this->MOV(dst, SelectionReg::flag(0,1));
+ this->MOV(dst, GenRegister::flag(0,1));
else {
- const SelectionReg tmp = this->selReg(this->reg(FAMILY_WORD), TYPE_U16);
+ const GenRegister tmp = this->selReg(this->reg(FAMILY_WORD), TYPE_U16);
this->push();
// Set all lanes of tmp to zero
this->curr.predicate = GEN_PREDICATE_NONE;
- this->MOV(tmp, SelectionReg::immuw(0));
+ this->MOV(tmp, GenRegister::immuw(0));
// Compute the short values with no mask
this->curr.flag = 0;
this->curr.predicate = simdWidth == 8 ?
GEN_PREDICATE_ALIGN1_ANY8H :
GEN_PREDICATE_ALIGN1_ANY16H;
- this->MOV(tmp, SelectionReg::immuw(1));
+ this->MOV(tmp, GenRegister::immuw(1));
this->pop();
// Update the destination with the proper mask
void SimpleSelection::emitRGatherInstruction(const ir::RGatherInstruction &insn) {
using namespace ir;
// Two destinations: one is the real destination, one is a temporary
- const SelectionReg dst = this->selReg(insn.getDst(0)), dst1;
+ const GenRegister dst = this->selReg(insn.getDst(0)), dst1;
// Get all the sources
- SelectionReg src[SelectionInstruction::MAX_SRC_NUM];
+ GenRegister src[SelectionInstruction::MAX_SRC_NUM];
const uint32_t srcNum = insn.getSrcNum();
GBE_ASSERT(srcNum <= SelectionInstruction::MAX_SRC_NUM);
for (uint32_t srcID = 0; srcID < insn.getSrcNum(); ++srcID)
void SimpleSelection::emitOBReadInstruction(const ir::OBReadInstruction &insn) {
using namespace ir;
- const SelectionReg header = this->selReg(this->reg(FAMILY_DWORD), TYPE_U32);
- const SelectionReg addr = this->selReg(insn.getAddress(), TYPE_U32);
- const SelectionReg value = this->selReg(insn.getValue(), TYPE_U32);
+ const GenRegister header = this->selReg(this->reg(FAMILY_DWORD), TYPE_U32);
+ const GenRegister addr = this->selReg(insn.getAddress(), TYPE_U32);
+ const GenRegister value = this->selReg(insn.getValue(), TYPE_U32);
const uint32_t simdWidth = ctx.getSimdWidth();
this->OBREAD(value, addr, header, 0xff, simdWidth * sizeof(int));
}
void SimpleSelection::emitOBWriteInstruction(const ir::OBWriteInstruction &insn) {
using namespace ir;
- const SelectionReg header = this->selReg(this->reg(FAMILY_DWORD), TYPE_U32);
- const SelectionReg addr = this->selReg(insn.getAddress(), TYPE_U32);
- const SelectionReg value = this->selReg(insn.getValue(), TYPE_U32);
+ const GenRegister header = this->selReg(this->reg(FAMILY_DWORD), TYPE_U32);
+ const GenRegister addr = this->selReg(insn.getAddress(), TYPE_U32);
+ const GenRegister value = this->selReg(insn.getValue(), TYPE_U32);
const uint32_t simdWidth = ctx.getSimdWidth();
this->OBWRITE(addr, value, header, 0xff, simdWidth * sizeof(int));
}
#include "ir/register.hpp"
#include "ir/instruction.hpp"
-#include "backend/gen_defs.hpp"
+#include "backend/gen_register.hpp"
#include "backend/gen_encoder.hpp"
#include "backend/gen_context.hpp"
#include "sys/vector.hpp"
};
}
- /*! The state of each instruction */
- class SelectionState
- {
- public:
- INLINE SelectionState(uint32_t simdWidth = 8) {
- this->execWidth = simdWidth;
- this->quarterControl = GEN_COMPRESSION_Q1;
- this->noMask = 0;
- this->flag = 0;
- this->subFlag = 0;
- this->predicate = GEN_PREDICATE_NORMAL;
- this->inversePredicate = 0;
- }
- uint32_t execWidth:6;
- uint32_t quarterControl:2;
- uint32_t noMask:1;
- uint32_t flag:1;
- uint32_t subFlag:1;
- uint32_t predicate:4;
- uint32_t inversePredicate:1;
- };
-
- /*! This is a book-keeping structure that is not exactly a virtual register
- * and not exactly a physical register. Basically, it is a Gen register
- * *before* the register allocation i.e. it contains the info to get it
- * properly encoded later but it is not associated to a GRF, a flag or
- * anything Gen related yet.
- */
- class SelectionReg
- {
- public:
- /*! Empty constructor */
- INLINE SelectionReg(void) {}
-
- /*! General constructor */
- INLINE SelectionReg(uint32_t file,
- ir::Register reg,
- uint32_t type,
- uint32_t vstride,
- uint32_t width,
- uint32_t hstride)
- {
- this->type = type;
- this->file = file;
- this->reg = reg;
- this->negation = 0;
- this->absolute = 0;
- this->vstride = vstride;
- this->width = width;
- this->hstride = hstride;
- this->quarter = 0;
- this->nr = this->subnr = 0;
- }
-
- /*! For specific physical registers only (acc, null) */
- INLINE SelectionReg(uint32_t file,
- uint32_t nr,
- uint32_t subnr,
- uint32_t type,
- uint32_t vstride,
- uint32_t width,
- uint32_t hstride)
- {
- this->type = type;
- this->file = file;
- this->nr = nr;
- this->subnr = subnr * typeSize(type);
- this->negation = 0;
- this->absolute = 0;
- this->vstride = vstride;
- this->width = width;
- this->hstride = hstride;
- this->quarter = 0;
- }
-
- /*! Associated virtual register */
- ir::Register reg;
-
- /*! For immediates */
- union {
- float f;
- int32_t d;
- uint32_t ud;
- } immediate;
-
- uint32_t nr:8; //!< Just for some physical registers (acc, null)
- uint32_t subnr:5; //!< Idem
- uint32_t type:4; //!< Gen type
- uint32_t file:2; //!< Register file
- uint32_t negation:1; //!< For source
- uint32_t absolute:1; //!< For source
- uint32_t vstride:4; //!< Vertical stride
- uint32_t width:3; //!< Width
- uint32_t hstride:2; //!< Horizontal stride
- uint32_t quarter:2; //!< To choose which part we want
-
- static INLINE SelectionReg Qn(SelectionReg reg, uint32_t quarter) {
- if (reg.hstride == GEN_HORIZONTAL_STRIDE_0) // scalar register
- return reg;
- else {
- reg.quarter = quarter;
- return reg;
- }
- }
-
- static INLINE SelectionReg vec16(uint32_t file, ir::Register reg) {
- return SelectionReg(file,
- reg,
- GEN_TYPE_F,
- GEN_VERTICAL_STRIDE_8,
- GEN_WIDTH_8,
- GEN_HORIZONTAL_STRIDE_1);
- }
-
- static INLINE SelectionReg vec8(uint32_t file, ir::Register reg) {
- return SelectionReg(file,
- reg,
- GEN_TYPE_F,
- GEN_VERTICAL_STRIDE_8,
- GEN_WIDTH_8,
- GEN_HORIZONTAL_STRIDE_1);
- }
-
- static INLINE SelectionReg vec4(uint32_t file, ir::Register reg) {
- return SelectionReg(file,
- reg,
- GEN_TYPE_F,
- GEN_VERTICAL_STRIDE_4,
- GEN_WIDTH_4,
- GEN_HORIZONTAL_STRIDE_1);
- }
-
- static INLINE SelectionReg vec2(uint32_t file, ir::Register reg) {
- return SelectionReg(file,
- reg,
- GEN_TYPE_F,
- GEN_VERTICAL_STRIDE_2,
- GEN_WIDTH_2,
- GEN_HORIZONTAL_STRIDE_1);
- }
-
- static INLINE SelectionReg vec1(uint32_t file, ir::Register reg) {
- return SelectionReg(file,
- reg,
- GEN_TYPE_F,
- GEN_VERTICAL_STRIDE_0,
- GEN_WIDTH_1,
- GEN_HORIZONTAL_STRIDE_0);
- }
-
- static INLINE SelectionReg retype(SelectionReg reg, uint32_t type) {
- reg.type = type;
- return reg;
- }
-
- static INLINE SelectionReg ud16(uint32_t file, ir::Register reg) {
- return retype(vec16(file, reg), GEN_TYPE_UD);
- }
-
- static INLINE SelectionReg ud8(uint32_t file, ir::Register reg) {
- return retype(vec8(file, reg), GEN_TYPE_UD);
- }
-
- static INLINE SelectionReg ud1(uint32_t file, ir::Register reg) {
- return retype(vec1(file, reg), GEN_TYPE_UD);
- }
-
- static INLINE SelectionReg d8(uint32_t file, ir::Register reg) {
- return retype(vec8(file, reg), GEN_TYPE_D);
- }
-
- static INLINE SelectionReg uw16(uint32_t file, ir::Register reg) {
- return retype(vec16(file, reg), GEN_TYPE_UW);
- }
-
- static INLINE SelectionReg uw8(uint32_t file, ir::Register reg) {
- return retype(vec8(file, reg), GEN_TYPE_UW);
- }
-
- static INLINE SelectionReg uw1(uint32_t file, ir::Register reg) {
- return retype(vec1(file, reg), GEN_TYPE_UW);
- }
-
- static INLINE SelectionReg ub16(uint32_t file, ir::Register reg) {
- return SelectionReg(file,
- reg,
- GEN_TYPE_UB,
- GEN_VERTICAL_STRIDE_16,
- GEN_WIDTH_8,
- GEN_HORIZONTAL_STRIDE_2);
- }
-
- static INLINE SelectionReg ub8(uint32_t file, ir::Register reg) {
- return SelectionReg(file,
- reg,
- GEN_TYPE_UB,
- GEN_VERTICAL_STRIDE_16,
- GEN_WIDTH_8,
- GEN_HORIZONTAL_STRIDE_2);
- }
-
- static INLINE SelectionReg ub1(uint32_t file, ir::Register reg) {
- return retype(vec1(file, reg), GEN_TYPE_UB);
- }
-
- static INLINE SelectionReg unpacked_uw(ir::Register reg) {
- return SelectionReg(GEN_GENERAL_REGISTER_FILE,
- reg,
- GEN_TYPE_UW,
- GEN_VERTICAL_STRIDE_16,
- GEN_WIDTH_8,
- GEN_HORIZONTAL_STRIDE_2);
- }
-
- static INLINE SelectionReg unpacked_ub(ir::Register reg) {
- return SelectionReg(GEN_GENERAL_REGISTER_FILE,
- reg,
- GEN_TYPE_UB,
- GEN_VERTICAL_STRIDE_32,
- GEN_WIDTH_8,
- GEN_HORIZONTAL_STRIDE_4);
- }
-
- static INLINE SelectionReg imm(uint32_t type) {
- return SelectionReg(GEN_IMMEDIATE_VALUE,
- ir::Register(),
- type,
- GEN_VERTICAL_STRIDE_0,
- GEN_WIDTH_1,
- GEN_HORIZONTAL_STRIDE_0);
- }
-
- static INLINE SelectionReg immf(float f) {
- SelectionReg immediate = imm(GEN_TYPE_F);
- immediate.immediate.f = f;
- return immediate;
- }
-
- static INLINE SelectionReg immd(int d) {
- SelectionReg immediate = imm(GEN_TYPE_D);
- immediate.immediate.d = d;
- return immediate;
- }
-
- static INLINE SelectionReg immud(uint32_t ud) {
- SelectionReg immediate = imm(GEN_TYPE_UD);
- immediate.immediate.ud = ud;
- return immediate;
- }
-
- static INLINE SelectionReg immuw(uint16_t uw) {
- SelectionReg immediate = imm(GEN_TYPE_UW);
- immediate.immediate.ud = uw | (uw << 16);
- return immediate;
- }
-
- static INLINE SelectionReg immw(int16_t w) {
- SelectionReg immediate = imm(GEN_TYPE_W);
- immediate.immediate.d = w | (w << 16);
- return immediate;
- }
-
- static INLINE SelectionReg immv(uint32_t v) {
- SelectionReg immediate = imm(GEN_TYPE_V);
- immediate.vstride = GEN_VERTICAL_STRIDE_0;
- immediate.width = GEN_WIDTH_8;
- immediate.hstride = GEN_HORIZONTAL_STRIDE_1;
- immediate.immediate.ud = v;
- return immediate;
- }
-
- static INLINE SelectionReg immvf(uint32_t v) {
- SelectionReg immediate = imm(GEN_TYPE_VF);
- immediate.vstride = GEN_VERTICAL_STRIDE_0;
- immediate.width = GEN_WIDTH_4;
- immediate.hstride = GEN_HORIZONTAL_STRIDE_1;
- immediate.immediate.ud = v;
- return immediate;
- }
-
- static INLINE SelectionReg immvf4(uint32_t v0, uint32_t v1, uint32_t v2, uint32_t v3) {
- SelectionReg immediate = imm(GEN_TYPE_VF);
- immediate.vstride = GEN_VERTICAL_STRIDE_0;
- immediate.width = GEN_WIDTH_4;
- immediate.hstride = GEN_HORIZONTAL_STRIDE_1;
- immediate.immediate.ud = ((v0 << 0) | (v1 << 8) | (v2 << 16) | (v3 << 24));
- return immediate;
- }
-
- static INLINE SelectionReg f1grf(ir::Register reg) {
- return vec1(GEN_GENERAL_REGISTER_FILE, reg);
- }
-
- static INLINE SelectionReg f2grf(ir::Register reg) {
- return vec2(GEN_GENERAL_REGISTER_FILE, reg);
- }
-
- static INLINE SelectionReg f4grf(ir::Register reg) {
- return vec4(GEN_GENERAL_REGISTER_FILE, reg);
- }
-
- static INLINE SelectionReg f8grf(ir::Register reg) {
- return vec8(GEN_GENERAL_REGISTER_FILE, reg);
- }
-
- static INLINE SelectionReg f16grf(ir::Register reg) {
- return vec16(GEN_GENERAL_REGISTER_FILE, reg);
- }
-
- static INLINE SelectionReg ud16grf(ir::Register reg) {
- return ud16(GEN_GENERAL_REGISTER_FILE, reg);
- }
-
- static INLINE SelectionReg ud8grf(ir::Register reg) {
- return ud8(GEN_GENERAL_REGISTER_FILE, reg);
- }
-
- static INLINE SelectionReg ud1grf(ir::Register reg) {
- return ud1(GEN_GENERAL_REGISTER_FILE, reg);
- }
-
- static INLINE SelectionReg uw1grf(ir::Register reg) {
- return uw1(GEN_GENERAL_REGISTER_FILE, reg);
- }
-
- static INLINE SelectionReg uw8grf(ir::Register reg) {
- return uw8(GEN_GENERAL_REGISTER_FILE, reg);
- }
-
- static INLINE SelectionReg uw16grf(ir::Register reg) {
- return uw16(GEN_GENERAL_REGISTER_FILE, reg);
- }
-
- static INLINE SelectionReg ub1grf(ir::Register reg) {
- return ub1(GEN_GENERAL_REGISTER_FILE, reg);
- }
-
- static INLINE SelectionReg ub8grf(ir::Register reg) {
- return ub8(GEN_GENERAL_REGISTER_FILE, reg);
- }
-
- static INLINE SelectionReg ub16grf(ir::Register reg) {
- return ub16(GEN_GENERAL_REGISTER_FILE, reg);
- }
-
- static INLINE SelectionReg null(void) {
- return SelectionReg(GEN_ARCHITECTURE_REGISTER_FILE,
- GEN_ARF_NULL,
- 0,
- GEN_TYPE_F,
- GEN_VERTICAL_STRIDE_8,
- GEN_WIDTH_8,
- GEN_HORIZONTAL_STRIDE_1);
- }
-
- static INLINE SelectionReg acc(void) {
- return SelectionReg(GEN_ARCHITECTURE_REGISTER_FILE,
- GEN_ARF_ACCUMULATOR,
- 0,
- GEN_TYPE_F,
- GEN_VERTICAL_STRIDE_8,
- GEN_WIDTH_8,
- GEN_HORIZONTAL_STRIDE_1);
- }
-
- static INLINE SelectionReg ip(void) {
- return SelectionReg(GEN_ARCHITECTURE_REGISTER_FILE,
- GEN_ARF_IP,
- 0,
- GEN_TYPE_D,
- GEN_VERTICAL_STRIDE_4,
- GEN_WIDTH_1,
- GEN_HORIZONTAL_STRIDE_0);
- }
-
- static INLINE SelectionReg notification1(void) {
- return SelectionReg(GEN_ARCHITECTURE_REGISTER_FILE,
- GEN_ARF_NOTIFICATION_COUNT,
- 1,
- GEN_TYPE_UD,
- GEN_VERTICAL_STRIDE_0,
- GEN_WIDTH_1,
- GEN_HORIZONTAL_STRIDE_0);
- }
-
- static INLINE SelectionReg flag(uint32_t nr, uint32_t subnr) {
- return SelectionReg(GEN_ARCHITECTURE_REGISTER_FILE,
- GEN_ARF_FLAG | nr,
- subnr,
- GEN_TYPE_UW,
- GEN_VERTICAL_STRIDE_0,
- GEN_WIDTH_1,
- GEN_HORIZONTAL_STRIDE_0);
- }
-
- static INLINE SelectionReg next(SelectionReg reg) {
- reg.quarter++;
- return reg;
- }
-
- static INLINE SelectionReg negate(SelectionReg reg) {
- reg.negation ^= 1;
- return reg;
- }
-
- static INLINE SelectionReg abs(SelectionReg reg) {
- reg.absolute = 1;
- reg.negation = 0;
- return reg;
- }
- };
-
/*! Selection opcodes properly encoded from 0 to n for fast jump tables
* generations
*/
SelectionBlock *parent;
/*! Instruction are chained in the block */
SelectionInstruction *prev, *next;
+ /*! Append an instruction before this one */
+ void appendBefore(const SelectionInstruction &insn);
+ /*! Append an instruction after this one */
+ void appendAfter(const SelectionInstruction &insn);
/*! No more than 6 sources (used by typed writes) */
enum { MAX_SRC_NUM = 8 };
/*! No more than 4 destinations (used by samples and untyped reads) */
enum { MAX_DST_NUM = 4 };
/*! All destinations */
- SelectionReg dst[MAX_DST_NUM];
+ GenRegister dst[MAX_DST_NUM];
/*! All sources */
- SelectionReg src[MAX_SRC_NUM];
+ GenRegister src[MAX_SRC_NUM];
/*! State of the instruction (extra fields neeed for the encoding) */
- SelectionState state;
+ GenInstructionState state;
/*! Gen opcode */
uint8_t opcode;
union {
/*! We chain the selection vectors together */
SelectionVector *next;
/*! Directly points to the selection instruction registers */
- SelectionReg *reg;
+ GenRegister *reg;
/*! Number of registers in the vector */
uint16_t regNum;
/*! Indicate if this a destination or a source vector */
INLINE ir::RegisterData getRegisterData(ir::Register reg) const {
return file.get(reg);
}
+ /*! Get the family for the given register */
+ INLINE ir::RegisterFamily getRegisterFamily(ir::Register reg) const {
+ return file.get(reg).family;
+ }
/*! Registers in the register file */
INLINE uint32_t regNum(void) const { return file.regNum(); }
protected:
/*! Append a new vector of registers in the current block */
SelectionVector *appendVector(void);
/*! Return the selection register from the GenIR one */
- SelectionReg selReg(ir::Register, ir::Type type = ir::TYPE_FLOAT);
+ GenRegister selReg(ir::Register, ir::Type type = ir::TYPE_FLOAT);
/*! Compute the nth register part when using SIMD8 with Qn (n in 2,3,4) */
- SelectionReg selRegQn(ir::Register, uint32_t quarter, ir::Type type = ir::TYPE_FLOAT);
+ GenRegister selRegQn(ir::Register, uint32_t quarter, ir::Type type = ir::TYPE_FLOAT);
/*! To handle selection block allocation */
DECL_POOL(SelectionBlock, blockPool);
/*! To handle selection instruction allocation */
/*! Currently processed block */
SelectionBlock *block;
/*! Current instruction state to use */
- SelectionState curr;
+ GenInstructionState curr;
/*! State used to encode the instructions */
- SelectionState stack[MAX_STATE_NUM];
+ GenInstructionState stack[MAX_STATE_NUM];
/*! We append new registers so we duplicate the function register file */
ir::RegisterFile file;
/*! Number of states currently pushed */
/*! Number of vector allocated */
uint32_t vectorNum;
/*! To make function prototypes more readable */
- typedef const SelectionReg &Reg;
+ typedef const GenRegister &Reg;
#define ALU1(OP) \
INLINE void OP(Reg dst, Reg src) { ALU1(SEL_OP_##OP, dst, src); }
/*! Wait instruction (used for the barrier) */
void WAIT(void);
/*! Untyped read (up to 4 elements) */
- void UNTYPED_READ(Reg addr, const SelectionReg *dst, uint32_t elemNum, uint32_t bti);
+ void UNTYPED_READ(Reg addr, const GenRegister *dst, uint32_t elemNum, uint32_t bti);
/*! Untyped write (up to 4 elements) */
- void UNTYPED_WRITE(Reg addr, const SelectionReg *src, uint32_t elemNum, uint32_t bti);
+ void UNTYPED_WRITE(Reg addr, const GenRegister *src, uint32_t elemNum, uint32_t bti);
/*! Byte gather (for unaligned bytes, shorts and ints) */
void BYTE_GATHER(Reg dst, Reg addr, uint32_t elemSize, uint32_t bti);
/*! Byte scatter (for unaligned bytes, shorts and ints) */
/*! Encode binary instructions */
void ALU2(uint32_t opcode, Reg dst, Reg src0, Reg src1);
/*! Encode regioning */
- void REGION(Reg dst0, Reg dst1, const SelectionReg *src, uint32_t offset, uint32_t vstride, uint32_t width, uint32_t hstride, uint32_t srcNum);
+ void REGION(Reg dst0, Reg dst1, const GenRegister *src, uint32_t offset, uint32_t vstride, uint32_t width, uint32_t hstride, uint32_t srcNum);
/*! Encode regioning */
- void RGATHER(Reg dst, const SelectionReg *src, uint32_t srcNum);
+ void RGATHER(Reg dst, const GenRegister *src, uint32_t srcNum);
/*! Use custom allocators */
GBE_CLASS(Selection);
+ friend class SelectionBlock;
+ friend class SelectionInstruction;
};
/*! This is a simple one-to-many instruction selection */
#include "ir/function.hpp"
#include "backend/gen_insn_selection.hpp"
#include "backend/gen_reg_allocation.hpp"
+#include "backend/gen_register.hpp"
#include "backend/program.hpp"
#include <algorithm>
#include <climits>
GenRegAllocator::GenRegAllocator(GenContext &ctx) : ctx(ctx) {}
GenRegAllocator::~GenRegAllocator(void) {}
-#define INSERT_REG(SIMD16, SIMD8, SIMD1) \
- if (ctx.sel->isScalarOrBool(reg) == true) \
- RA.insert(std::make_pair(reg, GenReg::SIMD1(nr, subnr))); \
- else if (simdWidth == 8) \
- RA.insert(std::make_pair(reg, GenReg::SIMD8(nr, subnr))); \
- else if (simdWidth == 16) \
- RA.insert(std::make_pair(reg, GenReg::SIMD16(nr, subnr))); \
- else \
- NOT_SUPPORTED;
-
void GenRegAllocator::allocatePayloadReg(gbe_curbe_type value,
ir::Register reg,
uint32_t subValue,
{
using namespace ir;
const Kernel *kernel = ctx.getKernel();
- const Function &fn = ctx.getFunction();
- const uint32_t simdWidth = ctx.getSimdWidth();
const int32_t curbeOffset = kernel->getCurbeOffset(value, subValue);
if (curbeOffset >= 0) {
- const uint32_t offset = curbeOffset + subOffset;
- const ir::RegisterData data = fn.getRegisterData(reg);
- const ir::RegisterFamily family = data.family;
- const bool isScalar = ctx.sel->isScalarOrBool(reg);
- const uint32_t typeSize = isScalar ? familyScalarSize[family] : familyVectorSize[family];
- const uint32_t nr = (offset + GEN_REG_SIZE) / GEN_REG_SIZE;
- const uint32_t subnr = ((offset + GEN_REG_SIZE) % GEN_REG_SIZE) / typeSize;
- switch (family) {
- case FAMILY_BOOL: INSERT_REG(uw1grf, uw1grf, uw1grf); break;
- case FAMILY_WORD: INSERT_REG(uw16grf, uw8grf, uw1grf); break;
- case FAMILY_BYTE: INSERT_REG(ub16grf, ub8grf, ub1grf); break;
- case FAMILY_DWORD: INSERT_REG(f16grf, f8grf, f1grf); break;
- default: NOT_SUPPORTED;
- }
+ const uint32_t offset = GEN_REG_SIZE + curbeOffset + subOffset;
+ RA.insert(std::make_pair(reg, offset));
this->intervals[reg].minID = 0;
}
}
const uint32_t regSize = simdWidth*typeSize;
uint32_t grfOffset;
while ((grfOffset = ctx.allocate(regSize, regSize)) == 0) {
- IF_DEBUG(const bool success =) this->expire(interval);
+ IF_DEBUG(const bool success =) this->expireGRF(interval);
GBE_ASSERTM(success, "Register allocation failed");
}
- if (grfOffset != 0) {
- const uint32_t nr = grfOffset / GEN_REG_SIZE;
- const uint32_t subnr = (grfOffset % GEN_REG_SIZE) / typeSize;
- switch (family) {
- case FAMILY_BOOL: INSERT_REG(uw1grf, uw1grf, uw1grf); break;
- case FAMILY_WORD: INSERT_REG(uw16grf, uw8grf, uw1grf); break;
- case FAMILY_BYTE: INSERT_REG(ub16grf, ub8grf, ub1grf); break;
- case FAMILY_DWORD: INSERT_REG(f16grf, f8grf, f1grf); break;
- default: NOT_SUPPORTED;
- }
- } else
- GBE_ASSERTM(false, "Unable to register allocate");
+ GBE_ASSERTM(grfOffset != 0, "Unable to register allocate");
+ RA.insert(std::make_pair(reg, grfOffset));
}
-#undef INSERT_REG
-
bool GenRegAllocator::isAllocated(const SelectionVector *vector) const {
const ir::Register first = vector->reg[0].reg;
const auto it = vectorMap.find(first);
return sortStartingPoint ? i0->minID < i1->minID : i0->maxID < i1->maxID;
}
- bool GenRegAllocator::expire(const GenRegInterval &limit) {
+ bool GenRegAllocator::expireGRF(const GenRegInterval &limit) {
while (this->expiringID != ending.size()) {
const GenRegInterval *toExpire = this->ending[this->expiringID];
const ir::Register reg = toExpire->reg;
- if (toExpire->minID >= limit.maxID)
+
+ // Ignore booleans that were allocated with flags
+ // if (ctx.getRegisterFamily(reg) == ir::FAMILY_BOOL && !grfBooleans.contains(reg)) {
+ if (ctx.sel->getRegisterFamily(reg) == ir::FAMILY_BOOL) {
+ this->expiringID++;
+ continue;
+ }
+ if (toExpire->maxID >= limit.minID)
return false;
auto it = RA.find(reg);
GBE_ASSERT(it != RA.end());
// Case 1 - it does not belong to a vector. Just remove it
if (vectorMap.contains(reg) == false) {
- const uint32_t offset = it->second.nr * GEN_REG_SIZE + it->second.subnr;
- ctx.deallocate(offset);
+ ctx.deallocate(it->second);
this->expiringID++;
return true;
// Case 2 - check that the vector has not been already removed. If not,
const ir::Register first = vector->reg[0].reg;
auto it = RA.find(first);
GBE_ASSERT(it != RA.end());
- const uint32_t offset = it->second.nr * GEN_REG_SIZE + it->second.subnr;
- ctx.deallocate(offset);
+ ctx.deallocate(it->second);
expired.insert(vector);
this->expiringID++;
return true;
return false;
}
+ void GenRegAllocator::allocateFlags(Selection &selection) {
+
+ // Store the registers allocated in the map
+ map<ir::Register, uint32_t> allocatedFlags;
+ GenRegInterval spill = ir::Register(ir::RegisterFile::MAX_INDEX);
+
+ // we have two flags we use for booleans f1.0 and f1.1
+ const uint32_t flagNum = 2;
+ uint32_t freeFlags[] = {0,1};
+ uint32_t freeNum = flagNum;
+
+ // Perform the linear scan allocator on the flag registers only. We only use
+ // two flags registers for the booleans right now: f1.0 and f1.1
+ const uint32_t regNum = ctx.sel->regNum();
+ uint32_t endID = 0; // interval to expire
+ for (uint32_t startID = 0; startID < regNum; ++startID) {
+ const GenRegInterval &interval = *this->starting[startID];
+ const ir::Register reg = interval.reg;
+ if (ctx.sel->getRegisterFamily(reg) != ir::FAMILY_BOOL)
+ continue; // Not a flag. We don't care
+ if (grfBooleans.contains(reg))
+ continue; // Cannot use a flag register
+ if (interval.maxID == -INT_MAX)
+ continue; // Unused register
+ if (freeNum != 0) {
+ spill = interval;
+ allocatedFlags.insert(std::make_pair(reg, freeFlags[--freeNum]));
+ }
+ else {
+ // Try to expire one register
+ while (endID != ending.size()) {
+ const GenRegInterval *toExpire = this->ending[endID];
+ const ir::Register reg = toExpire->reg;
+ // We cannot expire this interval and the next ones
+ if (toExpire->maxID >= interval.minID)
+ break;
+ // Must be a boolean allocated with a flag register
+ if (ctx.sel->getRegisterFamily(reg) != ir::FAMILY_BOOL || grfBooleans.contains(reg)) {
+ endID++;
+ continue;
+ }
+ // We reuse a flag from a previous interval (the oldest one)
+ auto it = allocatedFlags.find(toExpire->reg);
+ GBE_ASSERT(it != allocatedFlags.end());
+ freeFlags[freeNum++] = it->second;
+ break;
+ }
+
+ // We need to spill one of the previous boolean values
+ if (freeNum == 0) {
+ GBE_ASSERT(uint16_t(spill.reg) != ir::RegisterFile::MAX_INDEX);
+ // We spill the last inserted boolean and use its flag instead for
+ // this one
+ if (spill.maxID > interval.maxID) {
+ auto it = allocatedFlags.find(spill.reg);
+ GBE_ASSERT(it != allocatedFlags.end());
+ allocatedFlags.insert(std::make_pair(reg, it->second));
+ allocatedFlags.erase(spill.reg);
+ grfBooleans.insert(spill.reg);
+ spill = interval;
+ }
+ // We will a grf for the current register
+ else
+ grfBooleans.insert(reg);
+ }
+ else
+ allocatedFlags.insert(std::make_pair(reg, freeFlags[--freeNum]));
+ }
+ }
+
+ // Now, we traverse all the selection instructions and we patch them to make
+ // them use flag registers
+ selection.foreachInstruction([&](SelectionInstruction &insn) {
+ const uint32_t srcNum = insn.srcNum, dstNum = insn.dstNum;
+
+ // Patch the source booleans
+ for (uint32_t srcID = 0; srcID < srcNum; ++srcID) {
+ const GenRegister selReg = insn.src[srcID];
+ const ir::Register reg = selReg.reg;
+ if (selReg.physical || ctx.sel->getRegisterFamily(reg) != ir::FAMILY_BOOL)
+ continue;
+ auto it = allocatedFlags.find(reg);
+ if (it == allocatedFlags.end())
+ continue;
+ // Use a flag register for it now
+ insn.src[srcID] = GenRegister::flag(1,it->second);
+ }
+
+ // Patch the destination booleans
+ for (uint32_t dstID = 0; dstID < dstNum; ++dstID) {
+ const GenRegister selReg = insn.dst[dstID];
+ const ir::Register reg = selReg.reg;
+ if (selReg.physical || ctx.sel->getRegisterFamily(reg) != ir::FAMILY_BOOL)
+ continue;
+ auto it = allocatedFlags.find(reg);
+ if (it == allocatedFlags.end())
+ continue;
+ // Use a flag register for it now
+ insn.dst[dstID] = GenRegister::flag(1,it->second);
+ }
+
+ // Patch the predicate now. Note that only compares actually modify it (it
+ // is called a "conditional modifier"). The other instructions just read
+ // it
+ if (insn.state.physicalFlag == 0) {
+ auto it = allocatedFlags.find(ir::Register(insn.state.flagIndex));
+ // Just patch it if we can use a flag directly
+ if (it != allocatedFlags.end()) {
+ insn.state.flag = 1;
+ insn.state.subFlag = it->second;
+ insn.state.physicalFlag = 1;
+ }
+ // When we let the boolean in a GRF, use f0.1 as a temporary
+ else {
+ // Mov the GRF to the flag such that the flag can be read
+ SelectionInstruction mov;
+ mov.opcode = SEL_OP_MOV;
+ mov.state = GenInstructionState(1);
+ mov.state.predicate = GEN_PREDICATE_NONE;
+ mov.state.noMask = 1;
+ mov.dstNum = mov.srcNum = 1;
+ mov.src[0] = GenRegister::uw1grf(ir::Register(insn.state.flagIndex));
+ mov.dst[0] = GenRegister::flag(0,1);
+ insn.appendBefore(mov);
+
+ // We can use f0.1 (our "backdoor" flag)
+ insn.state.flag = 0;
+ insn.state.subFlag = 1;
+ insn.state.physicalFlag = 1;
+
+ // Compare instructions update the flags so we must copy it back to
+ // the GRF
+ if (insn.opcode == SEL_OP_CMP) {
+ std::swap(mov.src[0], mov.dst[0]);
+ insn.appendAfter(mov);
+ }
+ }
+ }
+ });
+ }
+
+ void GenRegAllocator::allocateGRFs(Selection &selection) {
+
+ // Perform the linear scan allocator
+ const uint32_t regNum = ctx.sel->regNum();
+ for (uint32_t startID = 0; startID < regNum; ++startID) {
+ const GenRegInterval &interval = *this->starting[startID];
+ const ir::Register reg = interval.reg;
+ if (interval.maxID == -INT_MAX)
+ continue; // Unused register
+ if (RA.contains(reg))
+ continue; // already allocated
+
+ // Case 1: the register belongs to a vector, allocate all the registers in
+ // one piece
+ auto it = vectorMap.find(reg);
+ if (it != vectorMap.end()) {
+ const SelectionVector *vector = it->second.first;
+ const uint32_t simdWidth = ctx.getSimdWidth();
+ const uint32_t alignment = simdWidth * sizeof(uint32_t);
+ const uint32_t size = vector->regNum * alignment;
+ uint32_t grfOffset;
+ while ((grfOffset = ctx.allocate(size, alignment)) == 0) {
+ IF_DEBUG(const bool success =) this->expireGRF(interval);
+ GBE_ASSERTM(success, "Register allocation failed");
+ }
+ for (uint32_t regID = 0; regID < vector->regNum; ++regID, grfOffset += alignment) {
+ const ir::Register reg = vector->reg[regID].reg;
+ GBE_ASSERT(RA.contains(reg) == false);
+ RA.insert(std::make_pair(reg, grfOffset));
+ }
+ }
+ // Case 2: This is a regular scalar register, allocate it alone
+ else
+ this->createGenReg(interval);
+ }
+ }
+
void GenRegAllocator::allocate(Selection &selection) {
using namespace ir;
const Kernel *kernel = ctx.getKernel();
const Function &fn = ctx.getFunction();
- const uint32_t simdWidth = ctx.getSimdWidth();
GBE_ASSERT(fn.getProfile() == PROFILE_OCL);
// Allocate all the vectors first since they need to be contiguous
allocatePayloadReg(GBE_CURBE_STACK_POINTER, ocl::stackptr);
// Group IDs are always allocated by the hardware in r0
- RA.insert(std::make_pair(ocl::groupid0, GenReg::f1grf(0, 1)));
- RA.insert(std::make_pair(ocl::groupid1, GenReg::f1grf(0, 6)));
- RA.insert(std::make_pair(ocl::groupid2, GenReg::f1grf(0, 7)));
+ RA.insert(std::make_pair(ocl::groupid0, 1*sizeof(float))); // r0.1
+ RA.insert(std::make_pair(ocl::groupid1, 6*sizeof(float))); // r0.6
+ RA.insert(std::make_pair(ocl::groupid2, 7*sizeof(float))); // r0.7
// block IP used to handle the mask in SW is always allocated
- int32_t blockIPOffset = GEN_REG_SIZE + kernel->getCurbeOffset(GBE_CURBE_BLOCK_IP,0);
+ const int32_t blockIPOffset = GEN_REG_SIZE + kernel->getCurbeOffset(GBE_CURBE_BLOCK_IP,0);
GBE_ASSERT(blockIPOffset >= 0 && blockIPOffset % GEN_REG_SIZE == 0);
- blockIPOffset /= GEN_REG_SIZE;
- if (simdWidth == 8)
- RA.insert(std::make_pair(ocl::blockip, GenReg::uw8grf(blockIPOffset, 0)));
- else if (simdWidth == 16)
- RA.insert(std::make_pair(ocl::blockip, GenReg::uw16grf(blockIPOffset, 0)));
- else
- NOT_SUPPORTED;
+ RA.insert(std::make_pair(ocl::blockip, blockIPOffset));
this->intervals[ocl::blockip].minID = 0;
// Allocate all (non-structure) argument parameters
block.foreach([&](const SelectionInstruction &insn) {
const uint32_t srcNum = insn.srcNum, dstNum = insn.dstNum;
for (uint32_t srcID = 0; srcID < srcNum; ++srcID) {
- const SelectionReg &selReg = insn.src[srcID];
+ const GenRegister &selReg = insn.src[srcID];
const ir::Register reg = selReg.reg;
if (selReg.file != GEN_GENERAL_REGISTER_FILE ||
reg == ir::ocl::groupid0 ||
this->intervals[reg].maxID = max(this->intervals[reg].maxID, insnID);
}
for (uint32_t dstID = 0; dstID < dstNum; ++dstID) {
- const SelectionReg &selReg = insn.dst[dstID];
+ const GenRegister &selReg = insn.dst[dstID];
const ir::Register reg = selReg.reg;
if (selReg.file != GEN_GENERAL_REGISTER_FILE ||
reg == ir::ocl::groupid0 ||
this->intervals[reg].minID = min(this->intervals[reg].minID, insnID);
this->intervals[reg].maxID = max(this->intervals[reg].maxID, insnID);
}
+
+ // Flag registers can only go to src[0]
+ const SelectionOpcode opcode = SelectionOpcode(insn.opcode);
+ if (opcode == SEL_OP_AND || opcode == SEL_OP_OR) {
+ const ir::Register reg = insn.src[1].reg;
+ if (ctx.sel->getRegisterFamily(reg) == ir::FAMILY_BOOL)
+ grfBooleans.insert(reg);
+ }
+
+ // OK, a flag is used as a predicate or a conditional modifier
+ if (insn.state.physicalFlag == 0) {
+ const ir::Register reg = ir::Register(insn.state.flagIndex);
+ this->intervals[reg].minID = min(this->intervals[reg].minID, insnID);
+ this->intervals[reg].maxID = max(this->intervals[reg].maxID, insnID);
+ }
lastID = insnID;
insnID++;
});
}
// Sort both intervals in starting point and ending point increasing orders
- uint32_t regNum = ctx.sel->regNum();
+ const uint32_t regNum = ctx.sel->regNum();
this->starting.resize(regNum);
this->ending.resize(regNum);
for (uint32_t regID = 0; regID < regNum; ++regID)
break;
}
- // Perform the linear scan allocator
- for (uint32_t startID = 0; startID < regNum; ++startID) {
- const GenRegInterval &interval = *this->starting[startID];
- const ir::Register reg = interval.reg;
- if (interval.maxID == -INT_MAX)
- continue; // Unused register
- if (RA.contains(reg))
- continue; // already allocated
+ // First we try to put all booleans registers into flags
+ this->allocateFlags(selection);
- // Case 1: the register belongs to a vector, allocate all the registers in
- // one piece
- auto it = vectorMap.find(reg);
- if (it != vectorMap.end()) {
- const SelectionVector *vector = it->second.first;
- const uint32_t simdWidth = ctx.getSimdWidth();
- const uint32_t alignment = simdWidth * sizeof(uint32_t);
- const uint32_t size = vector->regNum * alignment;
- uint32_t grfOffset;
- while ((grfOffset = ctx.allocate(size, alignment)) == 0) {
- IF_DEBUG(const bool success =) this->expire(interval);
- GBE_ASSERTM(success, "Register allocation failed");
- }
- //GBE_ASSERTM(grfOffset != 0, "Unable to register allocate");
- for (uint32_t regID = 0; regID < vector->regNum; ++regID, grfOffset += alignment) {
- const ir::Register reg = vector->reg[regID].reg;
- const uint32_t nr = grfOffset / GEN_REG_SIZE;
- const uint32_t subnr = (grfOffset % GEN_REG_SIZE) / sizeof(uint32_t);
- GBE_ASSERT(RA.contains(reg) == false);
- if (simdWidth == 16)
- RA.insert(std::make_pair(reg, GenReg::f16grf(nr, subnr)));
- else if (simdWidth == 8)
- RA.insert(std::make_pair(reg, GenReg::f8grf(nr, subnr)));
- else
- NOT_SUPPORTED;
- }
- }
- // Case 2: This is a regular scalar register, allocate it alone
- else
- this->createGenReg(interval);
- }
+ // Allocate all the GRFs now (regular register and boolean that are not in
+ // flag registers)
+ this->allocateGRFs(selection);
}
- INLINE void setGenReg(GenReg &dst, const SelectionReg &src) {
- dst.type = src.type;
- dst.file = src.file;
- dst.negation = src.negation;
- dst.absolute = src.absolute;
- dst.vstride = src.vstride;
- dst.width = src.width;
- dst.hstride = src.hstride;
- dst.address_mode = GEN_ADDRESS_DIRECT;
- dst.dw1.ud = src.immediate.ud;
+ INLINE GenRegister setGenReg(const GenRegister &src, uint32_t grfOffset) {
+ GenRegister dst;
+ dst = src;
+ dst.physical = 1;
+ dst.nr = grfOffset / GEN_REG_SIZE;
+ dst.subnr = grfOffset % GEN_REG_SIZE;
+ return dst;
}
- GenReg GenRegAllocator::genReg(const SelectionReg ®) {
+ GenRegister GenRegAllocator::genReg(const GenRegister ®) {
// Right now, only GRF are allocated (TODO bool) ...
if (reg.file == GEN_GENERAL_REGISTER_FILE) {
GBE_ASSERT(RA.contains(reg.reg) != false);
- GenReg dst = RA.find(reg.reg)->second;
- setGenReg(dst, reg);
+ const uint32_t grfOffset = RA.find(reg.reg)->second;
+ const GenRegister dst = setGenReg(reg, grfOffset);
if (reg.quarter != 0)
- dst = GenReg::Qn(dst, reg.quarter);
- return dst;
+ return GenRegister::Qn(dst, reg.quarter);
+ else
+ return dst;
}
// Other registers are already physical registers
- else {
- GenReg dst;
- setGenReg(dst, reg);
- dst.nr = reg.nr;
- dst.subnr = reg.subnr;
- return dst;
- }
+ else
+ return reg;
}
} /* namespace gbe */
#include "ir/register.hpp"
#include "backend/gen_context.hpp"
+#include "backend/gen_register.hpp"
#include "backend/program.h"
namespace gbe
{
class Selection; // Pre-register allocation code generation
- class SelectionReg; // Pre-register allocation Gen register
+ class GenRegister; // Pre-register allocation Gen register
class GenRegInterval; // Liveness interval for each register
/*! Provides the location of a register in a vector */
/*! Perform the register allocation */
void allocate(Selection &selection);
/*! Return the Gen register from the selection register */
- GenReg genReg(const SelectionReg ®);
+ GenRegister genReg(const GenRegister ®);
/*! Return the Gen register from the GenIR one */
- GenReg genReg(ir::Register, ir::Type type = ir::TYPE_FLOAT);
+ GenRegister genReg(ir::Register, ir::Type type = ir::TYPE_FLOAT);
private:
- /*! Expire one interval upto interval limit. Return true if one interval was
- * successfully expired
- */
- bool expire(const GenRegInterval &limit);
+ /*! Expire one GRF interval. Return true if one was successfully expired */
+ bool expireGRF(const GenRegInterval &limit);
+ /*! Expire a flag register. Return true if one was successfully expired */
+ bool expireFlag(const GenRegInterval &limit);
+ /*! Allocate the virtual boolean (== flags) registers */
+ void allocateFlags(Selection &selection);
+ /*! Allocate the GRF registers */
+ void allocateGRFs(Selection &selection);
/*! Create a Gen register from a register set in the payload */
void allocatePayloadReg(gbe_curbe_type, ir::Register, uint32_t subValue = 0, uint32_t subOffset = 0);
/*! Create the intervals for each register */
void coalesce(Selection &selection, SelectionVector *vector);
/*! The context owns the register allocator */
GenContext &ctx;
- /*! Map virtual registers to physical registers */
- map<ir::Register, GenReg> RA;
+ /*! Map virtual registers to offset in the (physical) register file */
+ map<ir::Register, uint32_t> RA;
/*! Provides the position of each register in a vector */
map<ir::Register, VectorLocation> vectorMap;
/*! All vectors used in the selection */
vector<SelectionVector*> vectors;
/*! All vectors that are already expired */
set<SelectionVector*> expired;
+ /*! The set of booleans that will go to GRF (cannot be kept into flags) */
+ set<ir::Register> grfBooleans;
/*! All the register intervals */
vector<GenRegInterval> intervals;
/*! Intervals sorting based on starting point positions */
--- /dev/null
+/*
+ * Copyright 2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file gen_reg.hpp
+ * \author Benjamin Segovia <benjamin.segovia@intel.com>
+ */
+
+#ifndef __GEN_REGISTER_HPP__
+#define __GEN_REGISTER_HPP__
+
+#include "backend/gen_defs.hpp"
+#include "ir/register.hpp"
+#include "sys/platform.hpp"
+
+namespace gbe
+{
+
+ /*! Type size in bytes for each Gen type */
+ INLINE int typeSize(uint32_t type) {
+ switch(type) {
+ case GEN_TYPE_UD:
+ case GEN_TYPE_D:
+ case GEN_TYPE_F:
+ return 4;
+ case GEN_TYPE_HF:
+ case GEN_TYPE_UW:
+ case GEN_TYPE_W:
+ return 2;
+ case GEN_TYPE_UB:
+ case GEN_TYPE_B:
+ return 1;
+ default:
+ assert(0);
+ return 0;
+ }
+ }
+
+ /*! Convert a hstride to a number of element */
+ INLINE uint32_t stride(uint32_t stride) {
+ switch (stride) {
+ case 0: return 0;
+ case 1: return 1;
+ case 2: return 2;
+ case 3: return 4;
+ case 4: return 8;
+ case 5: return 16;
+ default: assert(0); return 0;
+ }
+ }
+
+ /*! Encode the instruction state. Note that the flag register can be either
+ * physical (i.e. a real Gen flag) or a virtual boolean register. The flag
+ * register allocation will turn all virtual boolean registers into flag
+ * registers
+ */
+ class GenInstructionState
+ {
+ public:
+ INLINE GenInstructionState(uint32_t simdWidth = 8) {
+ this->execWidth = simdWidth;
+ this->quarterControl = GEN_COMPRESSION_Q1;
+ this->noMask = 0;
+ this->flag = 0;
+ this->subFlag = 0;
+ this->predicate = GEN_PREDICATE_NORMAL;
+ this->inversePredicate = 0;
+ this->physicalFlag = 1;
+ this->flagIndex = 0;
+ }
+ uint32_t physicalFlag:1; //!< Physical or virtual flag register
+ uint32_t flag:1; //!< Only if physical flag
+ uint32_t subFlag:1; //!< Only if physical flag
+ uint32_t flagIndex:16; //!< Only if virtual flag (index of the register)
+ uint32_t execWidth:5;
+ uint32_t quarterControl:2;
+ uint32_t noMask:1;
+ uint32_t predicate:4;
+ uint32_t inversePredicate:1;
+ };
+
+ static_assert(sizeof(GenInstructionState) == sizeof(uint32_t), "Invalid state size");
+
+ /*! This is a book-keeping structure used to encode both virtual and physical
+ * registers
+ */
+ class GenRegister
+ {
+ public:
+ /*! Empty constructor */
+ INLINE GenRegister(void) {}
+
+ /*! General constructor */
+ INLINE GenRegister(uint32_t file,
+ ir::Register reg,
+ uint32_t type,
+ uint32_t vstride,
+ uint32_t width,
+ uint32_t hstride)
+ {
+ this->type = type;
+ this->file = file;
+ this->physical = 0;
+ this->reg = reg;
+ this->negation = 0;
+ this->absolute = 0;
+ this->vstride = vstride;
+ this->width = width;
+ this->hstride = hstride;
+ this->quarter = 0;
+ this->nr = this->subnr = 0;
+ this->address_mode = GEN_ADDRESS_DIRECT;
+ }
+
+ /*! For specific physical registers only */
+ INLINE GenRegister(uint32_t file,
+ uint32_t nr,
+ uint32_t subnr,
+ uint32_t type,
+ uint32_t vstride,
+ uint32_t width,
+ uint32_t hstride)
+ {
+ this->type = type;
+ this->file = file;
+ this->nr = nr;
+ this->physical = 1;
+ this->subnr = subnr * typeSize(type);
+ this->negation = 0;
+ this->absolute = 0;
+ this->vstride = vstride;
+ this->width = width;
+ this->hstride = hstride;
+ this->quarter = 0;
+ this->address_mode = GEN_ADDRESS_DIRECT;
+ }
+
+ /*! Associated virtual register */
+ ir::Register reg;
+
+ /*! For immediates */
+ union {
+ float f;
+ int32_t d;
+ uint32_t ud;
+ } immediate;
+
+ uint32_t nr:7; //!< Just for some physical registers (acc, null)
+ uint32_t subnr:5; //!< Idem
+ uint32_t physical:1; //!< 1 if physical, 0 otherwise
+ uint32_t type:4; //!< Gen type
+ uint32_t file:2; //!< Register file
+ uint32_t negation:1; //!< For source
+ uint32_t absolute:1; //!< For source
+ uint32_t vstride:4; //!< Vertical stride
+ uint32_t width:3; //!< Width
+ uint32_t hstride:2; //!< Horizontal stride
+ uint32_t quarter:1; //!< To choose which part we want (Q1 / Q2)
+ uint32_t address_mode; //!< direct or indirec2t
+
+ static INLINE GenRegister QnVirtual(GenRegister reg, uint32_t quarter) {
+ GBE_ASSERT(reg.physical == 0);
+ if (reg.hstride == GEN_HORIZONTAL_STRIDE_0) // scalar register
+ return reg;
+ else {
+ reg.quarter = quarter;
+ return reg;
+ }
+ }
+
+ static INLINE GenRegister QnPhysical(GenRegister reg, uint32_t quarter) {
+ GBE_ASSERT(reg.physical);
+ if (reg.hstride == GEN_HORIZONTAL_STRIDE_0) // scalar register
+ return reg;
+ else {
+ const uint32_t typeSz = typeSize(reg.type);
+ const uint32_t horizontal = stride(reg.hstride);
+ const uint32_t grfOffset = reg.nr*GEN_REG_SIZE + reg.subnr;
+ const uint32_t nextOffset = grfOffset + 8*quarter*horizontal*typeSz;
+ reg.nr = nextOffset / GEN_REG_SIZE;
+ reg.subnr = (nextOffset % GEN_REG_SIZE);
+ return reg;
+ }
+ }
+
+ static INLINE GenRegister Qn(GenRegister reg, uint32_t quarter) {
+ if (reg.physical)
+ return QnPhysical(reg, quarter);
+ else
+ return QnVirtual(reg, quarter);
+ }
+
+ static INLINE GenRegister vec16(uint32_t file, ir::Register reg) {
+ return GenRegister(file,
+ reg,
+ GEN_TYPE_F,
+ GEN_VERTICAL_STRIDE_8,
+ GEN_WIDTH_8,
+ GEN_HORIZONTAL_STRIDE_1);
+ }
+
+ static INLINE GenRegister vec8(uint32_t file, ir::Register reg) {
+ return GenRegister(file,
+ reg,
+ GEN_TYPE_F,
+ GEN_VERTICAL_STRIDE_8,
+ GEN_WIDTH_8,
+ GEN_HORIZONTAL_STRIDE_1);
+ }
+
+ static INLINE GenRegister vec4(uint32_t file, ir::Register reg) {
+ return GenRegister(file,
+ reg,
+ GEN_TYPE_F,
+ GEN_VERTICAL_STRIDE_4,
+ GEN_WIDTH_4,
+ GEN_HORIZONTAL_STRIDE_1);
+ }
+
+ static INLINE GenRegister vec2(uint32_t file, ir::Register reg) {
+ return GenRegister(file,
+ reg,
+ GEN_TYPE_F,
+ GEN_VERTICAL_STRIDE_2,
+ GEN_WIDTH_2,
+ GEN_HORIZONTAL_STRIDE_1);
+ }
+
+ static INLINE GenRegister vec1(uint32_t file, ir::Register reg) {
+ return GenRegister(file,
+ reg,
+ GEN_TYPE_F,
+ GEN_VERTICAL_STRIDE_0,
+ GEN_WIDTH_1,
+ GEN_HORIZONTAL_STRIDE_0);
+ }
+
+ static INLINE GenRegister retype(GenRegister reg, uint32_t type) {
+ reg.type = type;
+ return reg;
+ }
+
+ static INLINE GenRegister ud16(uint32_t file, ir::Register reg) {
+ return retype(vec16(file, reg), GEN_TYPE_UD);
+ }
+
+ static INLINE GenRegister ud8(uint32_t file, ir::Register reg) {
+ return retype(vec8(file, reg), GEN_TYPE_UD);
+ }
+
+ static INLINE GenRegister ud1(uint32_t file, ir::Register reg) {
+ return retype(vec1(file, reg), GEN_TYPE_UD);
+ }
+
+ static INLINE GenRegister d8(uint32_t file, ir::Register reg) {
+ return retype(vec8(file, reg), GEN_TYPE_D);
+ }
+
+ static INLINE GenRegister uw16(uint32_t file, ir::Register reg) {
+ return retype(vec16(file, reg), GEN_TYPE_UW);
+ }
+
+ static INLINE GenRegister uw8(uint32_t file, ir::Register reg) {
+ return retype(vec8(file, reg), GEN_TYPE_UW);
+ }
+
+ static INLINE GenRegister uw1(uint32_t file, ir::Register reg) {
+ return retype(vec1(file, reg), GEN_TYPE_UW);
+ }
+
+ static INLINE GenRegister ub16(uint32_t file, ir::Register reg) {
+ return GenRegister(file,
+ reg,
+ GEN_TYPE_UB,
+ GEN_VERTICAL_STRIDE_16,
+ GEN_WIDTH_8,
+ GEN_HORIZONTAL_STRIDE_2);
+ }
+
+ static INLINE GenRegister ub8(uint32_t file, ir::Register reg) {
+ return GenRegister(file,
+ reg,
+ GEN_TYPE_UB,
+ GEN_VERTICAL_STRIDE_16,
+ GEN_WIDTH_8,
+ GEN_HORIZONTAL_STRIDE_2);
+ }
+
+ static INLINE GenRegister ub1(uint32_t file, ir::Register reg) {
+ return retype(vec1(file, reg), GEN_TYPE_UB);
+ }
+
+ static INLINE GenRegister unpacked_uw(ir::Register reg) {
+ return GenRegister(GEN_GENERAL_REGISTER_FILE,
+ reg,
+ GEN_TYPE_UW,
+ GEN_VERTICAL_STRIDE_16,
+ GEN_WIDTH_8,
+ GEN_HORIZONTAL_STRIDE_2);
+ }
+
+ static INLINE GenRegister unpacked_ub(ir::Register reg) {
+ return GenRegister(GEN_GENERAL_REGISTER_FILE,
+ reg,
+ GEN_TYPE_UB,
+ GEN_VERTICAL_STRIDE_32,
+ GEN_WIDTH_8,
+ GEN_HORIZONTAL_STRIDE_4);
+ }
+
+ static INLINE GenRegister imm(uint32_t type) {
+ return GenRegister(GEN_IMMEDIATE_VALUE,
+ 0,
+ 0,
+ type,
+ GEN_VERTICAL_STRIDE_0,
+ GEN_WIDTH_1,
+ GEN_HORIZONTAL_STRIDE_0);
+ }
+
+ static INLINE GenRegister immf(float f) {
+ GenRegister immediate = imm(GEN_TYPE_F);
+ immediate.immediate.f = f;
+ return immediate;
+ }
+
+ static INLINE GenRegister immd(int d) {
+ GenRegister immediate = imm(GEN_TYPE_D);
+ immediate.immediate.d = d;
+ return immediate;
+ }
+
+ static INLINE GenRegister immud(uint32_t ud) {
+ GenRegister immediate = imm(GEN_TYPE_UD);
+ immediate.immediate.ud = ud;
+ return immediate;
+ }
+
+ static INLINE GenRegister immuw(uint16_t uw) {
+ GenRegister immediate = imm(GEN_TYPE_UW);
+ immediate.immediate.ud = uw | (uw << 16);
+ return immediate;
+ }
+
+ static INLINE GenRegister immw(int16_t w) {
+ GenRegister immediate = imm(GEN_TYPE_W);
+ immediate.immediate.d = w | (w << 16);
+ return immediate;
+ }
+
+ static INLINE GenRegister immv(uint32_t v) {
+ GenRegister immediate = imm(GEN_TYPE_V);
+ immediate.vstride = GEN_VERTICAL_STRIDE_0;
+ immediate.width = GEN_WIDTH_8;
+ immediate.hstride = GEN_HORIZONTAL_STRIDE_1;
+ immediate.immediate.ud = v;
+ return immediate;
+ }
+
+ static INLINE GenRegister immvf(uint32_t v) {
+ GenRegister immediate = imm(GEN_TYPE_VF);
+ immediate.vstride = GEN_VERTICAL_STRIDE_0;
+ immediate.width = GEN_WIDTH_4;
+ immediate.hstride = GEN_HORIZONTAL_STRIDE_1;
+ immediate.immediate.ud = v;
+ return immediate;
+ }
+
+ static INLINE GenRegister immvf4(uint32_t v0, uint32_t v1, uint32_t v2, uint32_t v3) {
+ GenRegister immediate = imm(GEN_TYPE_VF);
+ immediate.vstride = GEN_VERTICAL_STRIDE_0;
+ immediate.width = GEN_WIDTH_4;
+ immediate.hstride = GEN_HORIZONTAL_STRIDE_1;
+ immediate.immediate.ud = ((v0 << 0) | (v1 << 8) | (v2 << 16) | (v3 << 24));
+ return immediate;
+ }
+
+ static INLINE GenRegister f1grf(ir::Register reg) {
+ return vec1(GEN_GENERAL_REGISTER_FILE, reg);
+ }
+
+ static INLINE GenRegister f2grf(ir::Register reg) {
+ return vec2(GEN_GENERAL_REGISTER_FILE, reg);
+ }
+
+ static INLINE GenRegister f4grf(ir::Register reg) {
+ return vec4(GEN_GENERAL_REGISTER_FILE, reg);
+ }
+
+ static INLINE GenRegister f8grf(ir::Register reg) {
+ return vec8(GEN_GENERAL_REGISTER_FILE, reg);
+ }
+
+ static INLINE GenRegister f16grf(ir::Register reg) {
+ return vec16(GEN_GENERAL_REGISTER_FILE, reg);
+ }
+
+ static INLINE GenRegister ud16grf(ir::Register reg) {
+ return ud16(GEN_GENERAL_REGISTER_FILE, reg);
+ }
+
+ static INLINE GenRegister ud8grf(ir::Register reg) {
+ return ud8(GEN_GENERAL_REGISTER_FILE, reg);
+ }
+
+ static INLINE GenRegister ud1grf(ir::Register reg) {
+ return ud1(GEN_GENERAL_REGISTER_FILE, reg);
+ }
+
+ static INLINE GenRegister uw1grf(ir::Register reg) {
+ return uw1(GEN_GENERAL_REGISTER_FILE, reg);
+ }
+
+ static INLINE GenRegister uw8grf(ir::Register reg) {
+ return uw8(GEN_GENERAL_REGISTER_FILE, reg);
+ }
+
+ static INLINE GenRegister uw16grf(ir::Register reg) {
+ return uw16(GEN_GENERAL_REGISTER_FILE, reg);
+ }
+
+ static INLINE GenRegister ub1grf(ir::Register reg) {
+ return ub1(GEN_GENERAL_REGISTER_FILE, reg);
+ }
+
+ static INLINE GenRegister ub8grf(ir::Register reg) {
+ return ub8(GEN_GENERAL_REGISTER_FILE, reg);
+ }
+
+ static INLINE GenRegister ub16grf(ir::Register reg) {
+ return ub16(GEN_GENERAL_REGISTER_FILE, reg);
+ }
+
+ static INLINE GenRegister null(void) {
+ return GenRegister(GEN_ARCHITECTURE_REGISTER_FILE,
+ GEN_ARF_NULL,
+ 0,
+ GEN_TYPE_F,
+ GEN_VERTICAL_STRIDE_8,
+ GEN_WIDTH_8,
+ GEN_HORIZONTAL_STRIDE_1);
+ }
+
+ static INLINE GenRegister acc(void) {
+ return GenRegister(GEN_ARCHITECTURE_REGISTER_FILE,
+ GEN_ARF_ACCUMULATOR,
+ 0,
+ GEN_TYPE_F,
+ GEN_VERTICAL_STRIDE_8,
+ GEN_WIDTH_8,
+ GEN_HORIZONTAL_STRIDE_1);
+ }
+
+ static INLINE GenRegister ip(void) {
+ return GenRegister(GEN_ARCHITECTURE_REGISTER_FILE,
+ GEN_ARF_IP,
+ 0,
+ GEN_TYPE_D,
+ GEN_VERTICAL_STRIDE_4,
+ GEN_WIDTH_1,
+ GEN_HORIZONTAL_STRIDE_0);
+ }
+
+ static INLINE GenRegister notification1(void) {
+ return GenRegister(GEN_ARCHITECTURE_REGISTER_FILE,
+ GEN_ARF_NOTIFICATION_COUNT,
+ 1,
+ GEN_TYPE_UD,
+ GEN_VERTICAL_STRIDE_0,
+ GEN_WIDTH_1,
+ GEN_HORIZONTAL_STRIDE_0);
+ }
+
+ static INLINE GenRegister flag(uint32_t nr, uint32_t subnr) {
+ return GenRegister(GEN_ARCHITECTURE_REGISTER_FILE,
+ GEN_ARF_FLAG | nr,
+ subnr,
+ GEN_TYPE_UW,
+ GEN_VERTICAL_STRIDE_0,
+ GEN_WIDTH_1,
+ GEN_HORIZONTAL_STRIDE_0);
+ }
+
+ static INLINE GenRegister next(GenRegister reg) {
+ if (reg.physical)
+ reg.nr++;
+ else
+ reg.quarter++;
+ return reg;
+ }
+
+ /*! Build an indirectly addressed source */
+ static INLINE GenRegister indirect(uint32_t type, uint32_t subnr, uint32_t width) {
+ GenRegister reg;
+ reg.type = type;
+ reg.file = GEN_GENERAL_REGISTER_FILE;
+ reg.address_mode = GEN_ADDRESS_REGISTER_INDIRECT_REGISTER;
+ reg.width = width;
+ reg.subnr = subnr;
+ reg.nr = 0;
+ reg.negation = 0;
+ reg.absolute = 0;
+ reg.vstride = 0;
+ reg.hstride = 0;
+ return reg;
+ }
+
+ static INLINE GenRegister vec16(uint32_t file, uint32_t nr, uint32_t subnr) {
+ return GenRegister(file,
+ nr,
+ subnr,
+ GEN_TYPE_F,
+ GEN_VERTICAL_STRIDE_8,
+ GEN_WIDTH_8,
+ GEN_HORIZONTAL_STRIDE_1);
+ }
+
+ static INLINE GenRegister vec8(uint32_t file, uint32_t nr, uint32_t subnr) {
+ return GenRegister(file,
+ nr,
+ subnr,
+ GEN_TYPE_F,
+ GEN_VERTICAL_STRIDE_8,
+ GEN_WIDTH_8,
+ GEN_HORIZONTAL_STRIDE_1);
+ }
+
+ static INLINE GenRegister vec4(uint32_t file, uint32_t nr, uint32_t subnr) {
+ return GenRegister(file,
+ nr,
+ subnr,
+ GEN_TYPE_F,
+ GEN_VERTICAL_STRIDE_4,
+ GEN_WIDTH_4,
+ GEN_HORIZONTAL_STRIDE_1);
+ }
+
+ static INLINE GenRegister vec2(uint32_t file, uint32_t nr, uint32_t subnr) {
+ return GenRegister(file,
+ nr,
+ subnr,
+ GEN_TYPE_F,
+ GEN_VERTICAL_STRIDE_2,
+ GEN_WIDTH_2,
+ GEN_HORIZONTAL_STRIDE_1);
+ }
+
+ static INLINE GenRegister vec1(uint32_t file, uint32_t nr, uint32_t subnr) {
+ return GenRegister(file,
+ nr,
+ subnr,
+ GEN_TYPE_F,
+ GEN_VERTICAL_STRIDE_0,
+ GEN_WIDTH_1,
+ GEN_HORIZONTAL_STRIDE_0);
+ }
+
+ static INLINE GenRegister suboffset(GenRegister reg, uint32_t delta) {
+ reg.subnr += delta * typeSize(reg.type);
+ return reg;
+ }
+
+ static INLINE GenRegister ud16(uint32_t file, uint32_t nr, uint32_t subnr) {
+ return retype(vec16(file, nr, subnr), GEN_TYPE_UD);
+ }
+
+ static INLINE GenRegister ud8(uint32_t file, uint32_t nr, uint32_t subnr) {
+ return retype(vec8(file, nr, subnr), GEN_TYPE_UD);
+ }
+
+ static INLINE GenRegister ud1(uint32_t file, uint32_t nr, uint32_t subnr) {
+ return retype(vec1(file, nr, subnr), GEN_TYPE_UD);
+ }
+
+ static INLINE GenRegister d8(uint32_t file, uint32_t nr, uint32_t subnr) {
+ return retype(vec8(file, nr, subnr), GEN_TYPE_D);
+ }
+
+ static INLINE GenRegister uw16(uint32_t file, uint32_t nr, uint32_t subnr) {
+ return suboffset(retype(vec16(file, nr, 0), GEN_TYPE_UW), subnr);
+ }
+
+ static INLINE GenRegister uw8(uint32_t file, uint32_t nr, uint32_t subnr) {
+ return suboffset(retype(vec8(file, nr, 0), GEN_TYPE_UW), subnr);
+ }
+
+ static INLINE GenRegister uw1(uint32_t file, uint32_t nr, uint32_t subnr) {
+ return suboffset(retype(vec1(file, nr, 0), GEN_TYPE_UW), subnr);
+ }
+
+ static INLINE GenRegister ub16(uint32_t file, uint32_t nr, uint32_t subnr) {
+ return GenRegister(file,
+ nr,
+ subnr,
+ GEN_TYPE_UB,
+ GEN_VERTICAL_STRIDE_16,
+ GEN_WIDTH_8,
+ GEN_HORIZONTAL_STRIDE_2);
+ }
+
+ static INLINE GenRegister ub8(uint32_t file, uint32_t nr, uint32_t subnr) {
+ return GenRegister(file,
+ nr,
+ subnr,
+ GEN_TYPE_UB,
+ GEN_VERTICAL_STRIDE_16,
+ GEN_WIDTH_8,
+ GEN_HORIZONTAL_STRIDE_2);
+ }
+
+ static INLINE GenRegister ub1(uint32_t file, uint32_t nr, uint32_t subnr) {
+ return suboffset(retype(vec1(file, nr, 0), GEN_TYPE_UB), subnr);
+ }
+
+ static INLINE GenRegister f1grf(uint32_t nr, uint32_t subnr) {
+ return vec1(GEN_GENERAL_REGISTER_FILE, nr, subnr);
+ }
+
+ static INLINE GenRegister f2grf(uint32_t nr, uint32_t subnr) {
+ return vec2(GEN_GENERAL_REGISTER_FILE, nr, subnr);
+ }
+
+ static INLINE GenRegister f4grf(uint32_t nr, uint32_t subnr) {
+ return vec4(GEN_GENERAL_REGISTER_FILE, nr, subnr);
+ }
+
+ static INLINE GenRegister f8grf(uint32_t nr, uint32_t subnr) {
+ return vec8(GEN_GENERAL_REGISTER_FILE, nr, subnr);
+ }
+
+ static INLINE GenRegister f16grf(uint32_t nr, uint32_t subnr) {
+ return vec16(GEN_GENERAL_REGISTER_FILE, nr, subnr);
+ }
+
+ static INLINE GenRegister ud16grf(uint32_t nr, uint32_t subnr) {
+ return ud16(GEN_GENERAL_REGISTER_FILE, nr, subnr);
+ }
+
+ static INLINE GenRegister ud8grf(uint32_t nr, uint32_t subnr) {
+ return ud8(GEN_GENERAL_REGISTER_FILE, nr, subnr);
+ }
+
+ static INLINE GenRegister ud1grf(uint32_t nr, uint32_t subnr) {
+ return ud1(GEN_GENERAL_REGISTER_FILE, nr, subnr);
+ }
+
+ static INLINE GenRegister uw1grf(uint32_t nr, uint32_t subnr) {
+ return uw1(GEN_GENERAL_REGISTER_FILE, nr, subnr);
+ }
+
+ static INLINE GenRegister uw8grf(uint32_t nr, uint32_t subnr) {
+ return uw8(GEN_GENERAL_REGISTER_FILE, nr, subnr);
+ }
+
+ static INLINE GenRegister uw16grf(uint32_t nr, uint32_t subnr) {
+ return uw16(GEN_GENERAL_REGISTER_FILE, nr, subnr);
+ }
+
+ static INLINE GenRegister ub1grf(uint32_t nr, uint32_t subnr) {
+ return ub1(GEN_GENERAL_REGISTER_FILE, nr, subnr);
+ }
+
+ static INLINE GenRegister ub8grf(uint32_t nr, uint32_t subnr) {
+ return ub8(GEN_GENERAL_REGISTER_FILE, nr, subnr);
+ }
+
+ static INLINE GenRegister ub16grf(uint32_t nr, uint32_t subnr) {
+ return ub16(GEN_GENERAL_REGISTER_FILE, nr, subnr);
+ }
+
+ static INLINE GenRegister mask(uint32_t subnr) {
+ return uw1(GEN_ARCHITECTURE_REGISTER_FILE, GEN_ARF_MASK, subnr);
+ }
+
+ static INLINE GenRegister addr1(uint32_t subnr) {
+ return uw1(GEN_ARCHITECTURE_REGISTER_FILE, GEN_ARF_ADDRESS, subnr);
+ }
+
+ static INLINE GenRegister addr8(uint32_t subnr) {
+ return uw8(GEN_ARCHITECTURE_REGISTER_FILE, GEN_ARF_ADDRESS, subnr);
+ }
+
+ static INLINE GenRegister negate(GenRegister reg) {
+ reg.negation ^= 1;
+ return reg;
+ }
+
+ static INLINE GenRegister abs(GenRegister reg) {
+ reg.absolute = 1;
+ reg.negation = 0;
+ return reg;
+ }
+
+ /*! Generate register encoding with run-time simdWidth */
+#define DECL_REG_ENCODER(NAME, SIMD16, SIMD8, SIMD1) \
+ template <typename... Args> \
+ static INLINE GenRegister NAME(uint32_t simdWidth, Args... values) { \
+ if (simdWidth == 16) \
+ return SIMD16(values...); \
+ else if (simdWidth == 8) \
+ return SIMD8(values...); \
+ else if (simdWidth == 1) \
+ return SIMD1(values...); \
+ else { \
+ NOT_IMPLEMENTED; \
+ return SIMD1(values...); \
+ } \
+ }
+ DECL_REG_ENCODER(fxgrf, f16grf, f8grf, f1grf);
+ DECL_REG_ENCODER(uwxgrf, uw16grf, uw8grf, uw1grf);
+ DECL_REG_ENCODER(udxgrf, ud16grf, ud8grf, ud1grf);
+#undef DECL_REG_ENCODER
+ };
+} /* namespace gbe */
+
+#endif /* __GEN_REGISTER_HPP__ */
+