Files
intel-graphics-compiler/visa/BinaryEncodingCNL.cpp
DianaChen f0962ad863 IGA: Clean-up gcc warnings
Clean-up gcc warnings, such as
-Werror=misleading-indentation
-Werror=catch-value
-Werror=class-memaccess
-Werror=unused-variable
-Werror=unused-but-set-variable
2025-07-01 18:23:24 +02:00

2570 lines
86 KiB
C++

/*========================== begin_copyright_notice ============================
Copyright (C) 2017-2021 Intel Corporation
SPDX-License-Identifier: MIT
============================= end_copyright_notice ===========================*/
#include "Assertions.h"
#include "BinaryEncodingCNL.h"
#include "BuildIR.h"
using namespace vISA;
////////////////////////////// DST ////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////// SRC ///////////////
////////////////////////////// SRC ///////////////
uint32_t BinaryEncodingBase::getEUOpcode(G4_opcode g4opc) {
G9HDL::EU_OPCODE euopcode = G9HDL::EU_OPCODE_ILLEGAL;
switch (g4opc) {
// 3src - complete
case G4_bfe:
euopcode = G9HDL::EU_OPCODE_BFE;
break;
case G4_bfi2:
euopcode = G9HDL::EU_OPCODE_BFI2;
break;
case G4_csel:
euopcode = G9HDL::EU_OPCODE_CSEL;
break;
case G4_lrp:
euopcode = G9HDL::EU_OPCODE_LRP;
break;
case G4_mad:
euopcode = G9HDL::EU_OPCODE_MAD;
break;
case G4_madm:
euopcode = G9HDL::EU_OPCODE_MADM;
break;
// 1src - complete
case G4_bfrev:
euopcode = G9HDL::EU_OPCODE_BFREV;
break;
case G4_cbit:
euopcode = G9HDL::EU_OPCODE_CBIT;
break;
case G4_fbh:
euopcode = G9HDL::EU_OPCODE_FBH;
break;
case G4_fbl:
euopcode = G9HDL::EU_OPCODE_FBL;
break;
case G4_lzd:
euopcode = G9HDL::EU_OPCODE_LZD;
break;
case G4_mov:
euopcode = G9HDL::EU_OPCODE_MOV;
break;
case G4_movi:
euopcode = G9HDL::EU_OPCODE_MOVI;
break;
case G4_not:
euopcode = G9HDL::EU_OPCODE_NOT;
break;
case G4_rndd:
euopcode = G9HDL::EU_OPCODE_RNDD;
break;
case G4_rnde:
euopcode = G9HDL::EU_OPCODE_RNDE;
break;
case G4_rndu:
euopcode = G9HDL::EU_OPCODE_RNDU;
break;
case G4_rndz:
euopcode = G9HDL::EU_OPCODE_RNDZ;
break;
case G4_frc:
euopcode = G9HDL::EU_OPCODE_FRC;
break;
// 2src - complete
case G4_add:
euopcode = G9HDL::EU_OPCODE_ADD;
break;
case G4_addc:
euopcode = G9HDL::EU_OPCODE_ADDC;
break;
case G4_and:
euopcode = G9HDL::EU_OPCODE_AND;
break;
case G4_asr:
euopcode = G9HDL::EU_OPCODE_ASR;
break;
case G4_avg:
euopcode = G9HDL::EU_OPCODE_AVG;
break;
case G4_bfi1:
euopcode = G9HDL::EU_OPCODE_BFI1;
break;
case G4_cmp:
euopcode = G9HDL::EU_OPCODE_CMP;
break;
case G4_cmpn:
euopcode = G9HDL::EU_OPCODE_CMPN;
break;
case G4_dp2:
euopcode = G9HDL::EU_OPCODE_DP2;
break;
case G4_dp3:
euopcode = G9HDL::EU_OPCODE_DP3;
break;
case G4_dp4:
euopcode = G9HDL::EU_OPCODE_DP4;
break;
case G4_dph:
euopcode = G9HDL::EU_OPCODE_DPH;
break;
case G4_line:
euopcode = G9HDL::EU_OPCODE_LINE;
break;
case G4_mac:
euopcode = G9HDL::EU_OPCODE_MAC;
break;
case G4_mach:
euopcode = G9HDL::EU_OPCODE_MACH;
break;
case G4_mul:
euopcode = G9HDL::EU_OPCODE_MUL;
break;
case G4_or:
euopcode = G9HDL::EU_OPCODE_OR;
break;
case G4_pln:
euopcode = G9HDL::EU_OPCODE_PLN;
break;
case G4_sad2:
euopcode = G9HDL::EU_OPCODE_SAD2;
break;
case G4_sada2:
euopcode = G9HDL::EU_OPCODE_SADA2;
break;
case G4_sel:
euopcode = G9HDL::EU_OPCODE_SEL;
break;
case G4_shl:
euopcode = G9HDL::EU_OPCODE_SHL;
break;
case G4_shr:
euopcode = G9HDL::EU_OPCODE_SHR;
break;
case G4_xor:
euopcode = G9HDL::EU_OPCODE_XOR;
break;
case G4_subb:
euopcode = G9HDL::EU_OPCODE_SUBB;
break;
// send type
case G4_send:
euopcode = G9HDL::EU_OPCODE_SEND;
break;
case G4_sendc:
euopcode = G9HDL::EU_OPCODE_SENDC;
break;
case G4_sends:
euopcode = G9HDL::EU_OPCODE_SENDS;
break;
case G4_sendsc:
euopcode = G9HDL::EU_OPCODE_SENDSC;
break;
// math type
case G4_math:
euopcode = G9HDL::EU_OPCODE_MATH;
break;
// control flow
case G4_brc:
euopcode = G9HDL::EU_OPCODE_BRC;
break;
case G4_brd:
euopcode = G9HDL::EU_OPCODE_BRD;
break;
case G4_break:
euopcode = G9HDL::EU_OPCODE_BREAK;
break;
case G4_call:
euopcode = G9HDL::EU_OPCODE_CALL;
break;
// case G4_calla: euopcode = G9HDL::EU_OPCODE_CALLA; break;
case G4_cont:
euopcode = G9HDL::EU_OPCODE_CONT;
break;
case G4_else:
euopcode = G9HDL::EU_OPCODE_ELSE;
break;
case G4_endif:
euopcode = G9HDL::EU_OPCODE_ENDIF;
break;
case G4_goto:
euopcode = G9HDL::EU_OPCODE_GOTO;
break;
case G4_halt:
euopcode = G9HDL::EU_OPCODE_HALT;
break;
case G4_if:
euopcode = G9HDL::EU_OPCODE_IF;
break;
case G4_jmpi:
euopcode = G9HDL::EU_OPCODE_JMPI;
break;
case G4_join:
euopcode = G9HDL::EU_OPCODE_JOIN;
break;
case G4_return:
euopcode = G9HDL::EU_OPCODE_RET;
break;
case G4_wait:
euopcode = G9HDL::EU_OPCODE_WAIT;
break;
case G4_while:
euopcode = G9HDL::EU_OPCODE_WHILE;
break;
// misc:
case G4_nop:
euopcode = G9HDL::EU_OPCODE_NOP;
break;
case G4_illegal:
euopcode = G9HDL::EU_OPCODE_ILLEGAL;
break;
case G4_smov:
euopcode = G9HDL::EU_OPCODE_SMOV;
break;
default:
vISA_ASSERT_UNREACHABLE("Invalid G4 opcode!");
break;
}
return (uint32_t)euopcode;
}
/// \brief Returns the HDL immediate type for a given source operand
///
static inline int GetOperandSrcHDLImmType(G4_Type srcType) {
int type = G11HDL::SRCIMMTYPE_UD;
switch (srcType) {
case Type_UD:
type = G11HDL::SRCIMMTYPE_UD;
break;
case Type_D:
type = G11HDL::SRCIMMTYPE_D;
break;
case Type_UW:
type = G11HDL::SRCIMMTYPE_UW;
break;
case Type_W:
type = G11HDL::SRCIMMTYPE_W;
break;
case Type_UV:
type = G11HDL::SRCIMMTYPE_UV;
break;
case Type_VF:
type = G11HDL::SRCIMMTYPE_VF;
break;
case Type_V:
type = G11HDL::SRCIMMTYPE_V;
break;
case Type_F:
type = G11HDL::SRCIMMTYPE_F;
break;
case Type_UQ:
type = G11HDL::SRCIMMTYPE_UQ;
break;
case Type_Q:
type = G11HDL::SRCIMMTYPE_Q;
break;
case Type_DF:
type = G11HDL::SRCIMMTYPE_DF;
break;
case Type_HF:
type = G11HDL::SRCIMMTYPE_HF;
break;
default:
vISA_ASSERT_UNREACHABLE("invalid type");
break;
}
return type;
}
/// \brief Returns the HDL source type for a given source operand
///
static inline int GetOperandSrcHDLType(G4_Type regType) {
int type = G11HDL::SRCTYPE_UD;
switch (regType) {
case Type_UD:
type = G11HDL::SRCTYPE_UD;
break;
case Type_D:
type = G11HDL::SRCTYPE_D;
break;
case Type_UW:
type = G11HDL::SRCTYPE_UW;
break;
case Type_W:
type = G11HDL::SRCTYPE_W;
break;
case Type_UB:
type = G11HDL::SRCTYPE_UB;
break;
case Type_B:
type = G11HDL::SRCTYPE_B;
break;
case Type_DF:
type = G11HDL::SRCTYPE_DF;
break;
case Type_F:
type = G11HDL::SRCTYPE_F;
break;
case Type_UQ:
type = G11HDL::SRCTYPE_UQ;
break;
case Type_Q:
type = G11HDL::SRCTYPE_Q;
break;
case Type_HF:
type = G11HDL::SRCTYPE_HF;
break;
default:
vISA_ASSERT_UNREACHABLE("invalid type");
break;
}
return type;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////// ENCODERS ///////////////
////////////////////////////// HEADER ///////////////
/// \brief (Header) Field encoder for instruction opcode
///
void BinaryEncodingCNL::EncodeOpCode(G4_INST *inst,
G9HDL::EU_INSTRUCTION_HEADER &header) {
G4_opcode opcode = inst->opcode();
G9HDL::EU_OPCODE euopcode = getEUOpcode(opcode);
header.SetOpcode(euopcode);
}
G9HDL::EU_OPCODE BinaryEncodingCNL::getEUOpcode(G4_opcode g4opc) {
switch (g4opc) {
// GEN11 specific
case G4_ror:
return G9HDL::EU_OPCODE_ROR;
case G4_rol:
return G9HDL::EU_OPCODE_ROL;
case G4_dp4a:
return G9HDL::EU_OPCODE_DP4A;
default:
break;
}
return (G9HDL::EU_OPCODE)BinaryEncodingBase::getEUOpcode(g4opc);
}
////////////////////////////// HEADER.CONTROLS ///////////////
/// \brief (Helper) Converts v-isa execution size to HDL exec size enumeration
///
static inline G9HDL::EXECSIZE
GetHDLExecSizeFromVISAExecSize(uint32_t execSize) {
switch (execSize) {
case ES_1_CHANNEL:
return G9HDL::EXECSIZE_1_CHANNEL_SCALAR_OPERATION;
case ES_2_CHANNELS:
return G9HDL::EXECSIZE_2_CHANNELS;
case ES_4_CHANNELS:
return G9HDL::EXECSIZE_4_CHANNELS;
case ES_8_CHANNELS:
return G9HDL::EXECSIZE_8_CHANNELS;
case ES_16_CHANNELS:
return G9HDL::EXECSIZE_16_CHANNELS;
case ES_32_CHANNELS:
return G9HDL::EXECSIZE_32_CHANNELS;
}
// Default:
return G9HDL::EXECSIZE_1_CHANNEL_SCALAR_OPERATION;
}
//////////////////////////////////////////////////////////////////////////
/// \brief (Header) Field encoder for execution size
///
void BinaryEncodingCNL::EncodeExecSize(
G4_INST *inst, G9HDL::EU_INSTRUCTION_CONTROLS_A &controls) {
G9HDL::EXECSIZE exSz;
exSz = GetHDLExecSizeFromVISAExecSize(GetEncodeExecSize(inst));
controls.SetExecsize(exSz);
}
//////////////////////////////////////////////////////////////////////////
/// \brief (Header) Field encoder for access mode bit
///
void BinaryEncodingCNL::EncodeAccessMode(
G4_INST *inst, G9HDL::EU_INSTRUCTION_CONTROLS_A &controls) {
if (inst->isAligned1Inst()) {
controls.SetAccessmode(G9HDL::ACCESSMODE_ALIGN1);
} else if (inst->isAligned16Inst()) {
controls.SetAccessmode(G9HDL::ACCESSMODE_ALIGN16);
}
}
//////////////////////////////////////////////////////////////////////////
/// \brief (Header) Field encoder for QTR control fields
///
void BinaryEncodingCNL::EncodeQtrControl(
G4_INST *inst, G9HDL::EU_INSTRUCTION_CONTROLS_A &controls) {
G9HDL::QTRCTRL qtrCtrl = G9HDL::QTRCTRL_1Q;
G9HDL::NIBCTRL nibCtrl = G9HDL::NIBCTRL::NIBCTRL_EVEN;
switch (inst->getMaskOffset()) {
case 0:
qtrCtrl = G9HDL::QTRCTRL_1Q;
nibCtrl = G9HDL::NIBCTRL_ODD;
break;
case 4:
qtrCtrl = G9HDL::QTRCTRL_1Q;
nibCtrl = G9HDL::NIBCTRL_EVEN;
break;
case 8:
qtrCtrl = G9HDL::QTRCTRL_2Q;
nibCtrl = G9HDL::NIBCTRL_ODD;
break;
case 12:
qtrCtrl = G9HDL::QTRCTRL_2Q;
nibCtrl = G9HDL::NIBCTRL_EVEN;
break;
case 16:
qtrCtrl = G9HDL::QTRCTRL_3Q;
nibCtrl = G9HDL::NIBCTRL_ODD;
break;
case 20:
qtrCtrl = G9HDL::QTRCTRL_3Q;
nibCtrl = G9HDL::NIBCTRL_EVEN;
break;
case 24:
qtrCtrl = G9HDL::QTRCTRL_4Q;
nibCtrl = G9HDL::NIBCTRL_ODD;
break;
case 28:
qtrCtrl = G9HDL::QTRCTRL_4Q;
nibCtrl = G9HDL::NIBCTRL_EVEN;
break;
}
controls.SetQtrctrl(qtrCtrl);
controls.SetNibctrl(nibCtrl);
}
/// \brief Field encoder for dependency control check fields
inline void BinaryEncodingCNL::EncodeDepControl(
G4_INST *inst, G9HDL::EU_INSTRUCTION_CONTROLS_A &controlsA) {
if (inst->isNoDDChkInst()) {
if (inst->isNoDDClrInst()) {
controlsA.SetDepctrl(G9HDL::DEPCTRL_NODDCLR_NODDCHK);
} else {
controlsA.SetDepctrl(G9HDL::DEPCTRL_NODDCHK);
}
} else {
if (inst->isNoDDClrInst()) {
controlsA.SetDepctrl(G9HDL::DEPCTRL_NODDCLR);
} else {
controlsA.SetDepctrl(G9HDL::DEPCTRL_NONE);
}
}
}
/// \brief Field encoder for thread control field. Includes some logic that is
// dependant on the platform.
inline void BinaryEncodingCNL::EncodeThreadControl(
G4_INST *inst, G9HDL::EU_INSTRUCTION_CONTROLS_A &controlsA) {
if (inst->opcode() == G4_if || inst->opcode() == G4_else ||
inst->opcode() == G4_endif) {
}
else {
controlsA.SetThreadControl(
inst->isAtomicInst() ? G9HDL::THREADCTRL_ATOMIC :
// CHAI: Add Switch InstOpt support
(inst->isYieldInst()
? G9HDL::THREADCTRL_SWITCH
: (inst->isNoPreemptInst() ? G9HDL::THREADCTRL_NOPREEMPT
: G9HDL::THREADCTRL_NORMAL)));
}
}
/// \brief Field encoder for ACC write control field
void BinaryEncodingCNL::EncodeAccWrCtrl(
G4_INST *inst, G9HDL::EU_INSTRUCTION_CONTROLS &instructionControls) {
if (inst->isAccWrCtrlInst() ||
(inst->isFlowControl() && inst->opcode() != G4_jmpi &&
inst->asCFInst()->isBackward())) {
instructionControls.SetControlsB_Accwrctrl(G9HDL::ACCWRCTRL_UPDATE_ACC);
}
}
//////////////////////////////////////////////////////////////////////////
//// Field encoder
void BinaryEncodingCNL::EncodeInstModifier(
G4_INST *inst, G9HDL::EU_INSTRUCTION_CONTROLS &instructionControls) {
if (inst->getSaturate()) {
instructionControls.SetControlsB_Saturate(G9HDL::SATURATE_SAT);
} else {
instructionControls.SetControlsB_Saturate(
G9HDL::SATURATE_NO_DESTINATION_MODIFICATION);
}
}
//////////////////////////////////////////////////////////////////////////
//// Field encoder
void BinaryEncodingCNL::EncodeFlagRegPredicate(
G4_INST *inst, G9HDL::EU_INSTRUCTION_CONTROLS_A &instructionControlsA) {
G4_Predicate *pred = inst->getPredicate();
if (pred) {
switch (pred->getState()) {
// plus and undef are normal
case PredState_Plus:
case PredState_undef:
instructionControlsA.SetPredinv(G9HDL::PREDINV_POSITIVE);
// instructionHeader.SetControl_Predinv(G9HDL::PREDINV_POSITIVE);
// flagState = PREDICATE_STATE_NORMAL;
break;
// minus is invert
case PredState_Minus:
instructionControlsA.SetPredinv(G9HDL::PREDINV_NEGATIVE);
// instructionHeader.SetControl_Predinv(G9HDL::PREDINV_NEGATIVE);
// flagState = PREDICATE_STATE_INVERT<<4;
break;
}
G9HDL::PREDCTRL predCtrl = G9HDL::PREDCTRL_SEQUENTIAL_FLAG_CHANNEL_MAPPING;
if (inst->isAligned16Inst()) {
switch (getAlign16PredCtrl(pred)) {
case PRED_ALIGN16_DEFAULT:
predCtrl = G9HDL::PREDCTRL_SEQUENTIAL_FLAG_CHANNEL_MAPPING;
break;
case PRED_ALIGN16_X:
predCtrl = G9HDL::PREDCTRL_REPLICATION_SWIZZLE_X;
break;
case PRED_ALIGN16_Y:
predCtrl = G9HDL::PREDCTRL_REPLICATION_SWIZZLE_Y;
break;
case PRED_ALIGN16_Z:
predCtrl = G9HDL::PREDCTRL_REPLICATION_SWIZZLE_Z;
break;
case PRED_ALIGN16_W:
predCtrl = G9HDL::PREDCTRL_REPLICATION_SWIZZLE_W;
break;
case PRED_ALIGN16_ANY4H:
predCtrl = G9HDL::PREDCTRL_ANY4H;
break;
case PRED_ALIGN16_ALL4H:
predCtrl = G9HDL::PREDCTRL_ALL4H;
break;
default:
vISA_ASSERT_UNREACHABLE("invalid align16 predicate control");
}
instructionControlsA.SetPredctrl(predCtrl);
// instructionHeader.SetControl_Predctrl(predCtrl);
} else {
auto pc = pred->getControl();
if (pc != PRED_DEFAULT)
predCtrl = (G9HDL::PREDCTRL)GetAlign1PredCtrl(pc);
instructionControlsA.SetPredctrl(predCtrl);
}
}
}
static const unsigned CONDITION_MODIIFER[11] = {
(unsigned)G9HDL::CONDMODIFIER_Z, (unsigned)G9HDL::CONDMODIFIER_E,
(unsigned)G9HDL::CONDMODIFIER_NZ, (unsigned)G9HDL::CONDMODIFIER_NE,
(unsigned)G9HDL::CONDMODIFIER_G, (unsigned)G9HDL::CONDMODIFIER_GE,
(unsigned)G9HDL::CONDMODIFIER_L, (unsigned)G9HDL::CONDMODIFIER_LE,
(unsigned)G9HDL::CONDMODIFIER_O, // Mod_o
(unsigned)G9HDL::CONDMODIFIER_O, // Mod_r
(unsigned)G9HDL::CONDMODIFIER_U // Mod_u
};
/// \brief Field encoder
///
void BinaryEncodingCNL::EncodeCondModifier(
G4_INST *inst, G9HDL::EU_INSTRUCTION_CONTROLS &instructionControls) {
G4_CondMod *cModifier = inst->getCondMod();
if (cModifier) {
G9HDL::CONDMODIFIER value;
unsigned mod = (unsigned)cModifier->getMod();
vISA_ASSERT(mod != (unsigned)Mod_r && mod < (unsigned)Mod_cond_undef,
// case Mod_r:
// value = G9HDL::CONDMODIFIER_O; //7
// break;
"[Verifying]:[ERR]: Invalid conditional modifier:\t");
value = (G9HDL::CONDMODIFIER)CONDITION_MODIIFER[mod];
instructionControls.SetCondmodifier(value);
}
}
/// \brief Encodes instruction header DWORD, common for all types of
/// instructions
inline void
BinaryEncodingCNL::EncodeInstHeader(G4_INST *inst,
G9HDL::EU_INSTRUCTION_HEADER &header) {
G9HDL::EU_INSTRUCTION_CONTROLS &controls = header.GetControl();
G9HDL::EU_INSTRUCTION_CONTROLS_A &controlsA = controls.GetControlsA();
header.Init();
EncodeOpCode(inst, header);
EncodeExecSize(inst, controlsA);
EncodeAccessMode(inst, controlsA);
EncodeQtrControl(inst, controlsA);
EncodeThreadControl(inst, controlsA);
EncodeDepControl(inst, controlsA);
EncodeFlagRegPredicate(inst, controlsA);
EncodeAccWrCtrl(inst, controls);
EncodeInstModifier(inst, controls);
EncodeCondModifier(inst, controls);
controls.SetControlsB_Cmptctrl(inst->isCompactedInst()
? G9HDL::CMPTCTRL_COMPACTED
: G9HDL::CMPTCTRL_NOCOMPACTION);
if (inst->isBreakPointInst())
controls.SetControlsB_Debugctrl(G9HDL::DEBUGCTRL_BREAKPOINT);
}
////////////////////////////// DST.OPERAND_CONTROLS ///////////////
////////////////////////////// DST.OPERAND_CONTROLS ///////////////
////////////////////////////// DST.OPERAND_CONTROLS ///////////////
////////////////////////////// DST.OPERAND_CONTROLS ///////////////
////////////////////////////// DST.OPERAND_CONTROLS ///////////////
////////////////////////////// DST.OPERAND_CONTROLS ///////////////
////////////////////////////// DST.OPERAND_CONTROLS ///////////////
////////////////////////////// DST.OPERAND_CONTROLS ///////////////
//////////////////////////////////////////////////////////////////////////
//// Field encoder
inline void BinaryEncodingCNL::EncodeDstHorzStride(
G4_INST *inst, G4_DstRegRegion *dst,
G9HDL::EU_INSTRUCTION_OPERAND_CONTROLS &opnds) {
switch (dst->getHorzStride()) {
case 1:
// NOTE: not sure if this is correct?
if (inst->isAligned16Inst()) {
// NOTE: use align1 union, even if setting align16 field. Masks are equal.
// note: Although Dst.HorzStride is a don't care for Align16, HW needs
// this to be programmed as '01'.
opnds.GetDestinationRegisterRegion_Align1()
.SetDestinationHorizontalStride(G9HDL::HORZSTRIDE_4_ELEMENTS);
} else {
opnds.GetDestinationRegisterRegion_Align1()
.SetDestinationHorizontalStride(G9HDL::HORZSTRIDE_1_ELEMENTS);
}
break;
case 2:
opnds.GetDestinationRegisterRegion_Align1().SetDestinationHorizontalStride(
G9HDL::HORZSTRIDE_2_ELEMENTS);
break;
case 4:
opnds.GetDestinationRegisterRegion_Align1().SetDestinationHorizontalStride(
G9HDL::HORZSTRIDE_4_ELEMENTS);
break;
case UNDEFINED_SHORT:
opnds.GetDestinationRegisterRegion_Align1().SetDestinationHorizontalStride(
G9HDL::HORZSTRIDE_1_ELEMENTS);
break;
default:
vISA_ASSERT_UNREACHABLE("wrong dst horizontal stride");
break;
}
}
//////////////////////////////////////////////////////////////////////////
//// Field encoder
// NOTE: could change interface, so that 'dst' is passed directly
void BinaryEncodingCNL::EncodeDstChanEn(
G4_INST *inst, G9HDL::EU_INSTRUCTION_OPERAND_CONTROLS &opnds) {
G4_DstRegRegion *dst = inst->getDst();
if (dst->isAccRegValid()) {
// NOTE: this one is special case for instructions that use special
// accumulators
opnds.GetDestinationRegisterRegion_Align16().SetDestinationChannelEnable(
dst->getAccRegSel());
} else {
G4_DstRegRegion *dstRegion = static_cast<G4_DstRegRegion *>(dst);
opnds.GetDestinationRegisterRegion_Align16().SetDestinationChannelEnable(
getWriteMask(dstRegion));
}
}
//////////////////////////////////////////////////////////////////////////
//// Field encoder
// NOTE: could change interface, so that 'dst' is passed directly
// NOTE2: Encoding for ARF register type is moved into setting reg destination
// logic.
void BinaryEncodingCNL::EncodeDstRegFile(
G4_INST *inst, G9HDL::EU_INSTRUCTION_OPERAND_CONTROLS &opnds) {
G4_DstRegRegion *dst = inst->getDst();
switch (EncodingHelper::GetDstRegFile(
dst)) { // Bug Line 846, bitrange: 3-4, should be: 35-36
case REG_FILE_A:
opnds.SetDestinationRegisterFile(G9HDL::REGFILE_ARF);
break;
case REG_FILE_R:
opnds.SetDestinationRegisterFile(G9HDL::REGFILE_GRF);
break;
case REG_FILE_M:
vISA_ASSERT_UNREACHABLE(0, " Memory is invalid register file on CNL");
// opnds.SetDestinationRegisterFile(G9HDL::REGFILE_IMM); break;
default:
break;
}
}
//////////////////////////////////////////////////////////////////////////
//// Field encoder
// NOTE: could change interface, so that 'dst' is passed directly
void BinaryEncodingCNL::EncodeDstRegNum(
G4_INST *inst, G9HDL::EU_INSTRUCTION_OPERAND_CONTROLS &opnds) {
G4_DstRegRegion *dst = inst->getDst();
if (EncodingHelper::GetDstRegFile(dst) != REG_FILE_A &&
EncodingHelper::GetDstAddrMode(dst) == ADDR_MODE_IMMED) {
uint32_t byteAddress = dst->getLinearizedStart();
if (inst->isAligned1Inst()) {
// register number: 256 bit (32 byte) aligned part of an address
// sub-register number: 32 byte address (5 bits encoding) within a GRF
// 98765 43210
// regn |subre
opnds.GetDestinationRegisterRegion_Align1()
.SetDestinationRegisterNumber_DestinationRegisterNumber(byteAddress >>
5);
if (dst->isAccRegValid() &&
kernel.fg.builder->encodeAccRegSelAsAlign1()) {
vISA_ASSERT((byteAddress & 0x1F) == 0,
"subreg must be 0 for dst with special accumulator");
opnds.GetDestinationRegisterRegion_Align1().SetDestinationSpecialAcc(
dst->getAccRegSel());
} else {
opnds.GetDestinationRegisterRegion_Align1()
.SetDestinationSubregisterNumber_DestinationSubRegisterNumber(
byteAddress & 0x1F);
}
} else { // align 16
// register number: 256 bit (32 byte) aligned part of an address
// sub-register number: first/second 16 byte part of 32 byte address.
// Encoded with 1 bit.
// 98765 43210
// regn |x0000
// opnds.GetDestinationRegisterRegion_Align1().
// SetDestinationRegisterNumber_DestinationRegisterNumber(byteAddress
// >> 5);
opnds.GetDestinationRegisterRegion_Align16()
.SetDestinationRegisterNumber_DestinationRegisterNumber(byteAddress >>
5);
// opnds.GetDestinationRegisterRegion_Align1().
// SetDestinationSubregisterNumber_DestinationSubRegisterNumber((byteAddress
// >> 4) & 0x1);
opnds.GetDestinationRegisterRegion_Align16()
.SetDestinationSubregisterNumber((WORD)byteAddress);
}
}
}
//////////////////////////////////////////////////////////////////////////
//// Field encoder
// NOTE: could change interface, so that 'dst' is passed directly
//
// SetDstArchRegNum (53:56) + SetDstArchRegFile (57:60)
// SetDstArchSubRegNumByte (48:52)
// essentially, this encoding is split in three parts:
// setting reg num : arch reg file + arch reg number
// setting sub-reg-num
// Here, we fuse two original methods into one: EncodeDstArchRegNum and
// EncodeDstRegFile for ARF
void BinaryEncodingCNL::EncodeDstArchRegNum(
G4_INST *inst, G9HDL::EU_INSTRUCTION_OPERAND_CONTROLS &opnds) {
G4_DstRegRegion *dst = inst->getDst();
if (EncodingHelper::GetDstRegFile(dst) == REG_FILE_A &&
EncodingHelper::GetDstAddrMode(dst) == ADDR_MODE_IMMED) {
if (EncodingHelper::GetDstArchRegType(dst) != ARCH_REG_FILE_NULL) {
bool valid;
unsigned short RegFile =
(unsigned short)EncodingHelper::GetDstArchRegType(dst); // 4 bits
unsigned short RegNumValue = dst->ExRegNum(valid);
// 7654|3210
// RegF|RegNumVal
unsigned short EncodedRegNum = RegFile << 4;
EncodedRegNum = EncodedRegNum | (RegNumValue & 0xF);
// the same as for align16
opnds.GetDestinationRegisterRegion_Align1()
.SetDestinationRegisterNumber_DestinationRegisterNumber(
EncodedRegNum);
{
bool subValid;
unsigned short RegSubNumValue = dst->ExSubRegNum(subValid);
unsigned short ElementSizeValue =
EncodingHelper::GetElementSizeValue(dst);
uint32_t regOffset = RegSubNumValue * ElementSizeValue;
if (inst->isAligned1Inst()) {
// sub-register number: 32 byte address (5 bits encoding) within a GRF
opnds.GetDestinationRegisterRegion_Align1()
.SetDestinationSubregisterNumber_DestinationSubRegisterNumber(
(WORD)regOffset);
} else { // align 16
// sub-register number: first/second 16 byte part of 32 byte address.
// Encoded with 1 bit.
// 9876543210
// regn|x0000
// opnds.GetDestinationRegisterRegion_Align16().SetDestinationSubregisterNumber((regOffset
// >> 4) & 0x1);
opnds.GetDestinationRegisterRegion_Align16()
.SetDestinationSubregisterNumber((WORD)regOffset);
}
}
}
}
}
//////////////////////////////////////////////////////////////////////////
//// Field encoder
// NOTE: could change interface, so that 'dst' is passed directly
void BinaryEncodingCNL::EncodeDstIndirectRegNum(
G4_INST *inst, G9HDL::EU_INSTRUCTION_OPERAND_CONTROLS &opnds) {
G4_DstRegRegion *dst = inst->getDst();
if (EncodingHelper::GetDstRegFile(dst) == REG_FILE_R ||
EncodingHelper::GetDstRegFile(dst) == REG_FILE_M) {
if (EncodingHelper::GetDstAddrMode(dst) == ADDR_MODE_INDIR) { // Indirect
bool subValid;
unsigned short IndAddrRegSubNumValue = 0;
short IndAddrImmedValue = 0;
IndAddrRegSubNumValue = dst->ExIndSubRegNum(subValid);
IndAddrImmedValue = dst->ExIndImmVal();
// the same is for align16
opnds.GetDestinationRegisterRegion_Align1()
.SetDestinationAddressSubregisterNumber_AddressSubregisterNumber(
IndAddrRegSubNumValue);
/* Set the indirect address immediate value. */
if (inst->isAligned1Inst()) {
// bits [0-8]
opnds.GetDestinationRegisterRegion_Align1()
.SetDestinationAddressImmediate(IndAddrImmedValue);
// bit[9:9]
opnds.SetDestinationAddressImmediate99(IndAddrImmedValue >> 9);
} else { // here we are setting align16
// bits [4-8]
opnds.GetDestinationRegisterRegion_Align16()
.SetDestinationAddressImmediate84((IndAddrImmedValue >> 4) & 0x1F);
// bit[9:9], originally: (IndAddrImmedValue / BYTES_PER_OWORD) >> 5
opnds.SetDestinationAddressImmediate99(IndAddrImmedValue >> 9);
}
}
}
}
/// \brief Encodes instruction operand (1st DWORD) of instruction
///
/// src0 reg file and type are not encoded here, even though they belong to
/// dword 1
inline void BinaryEncodingCNL::EncodeOperandDst(
G4_INST *inst, G9HDL::EU_INSTRUCTION_OPERAND_CONTROLS &opnds) {
G4_DstRegRegion *dst = inst->getDst();
DstBuilder<G9HDL::EU_INSTRUCTION_OPERAND_CONTROLS>::EncodeFlagReg(inst,
opnds);
DstBuilder<G9HDL::EU_INSTRUCTION_OPERAND_CONTROLS>::EncodeMaskCtrl(inst,
opnds);
if (dst == NULL) {
return;
}
EncodeDstRegFile(inst, opnds);
DstBuilder<G9HDL::EU_INSTRUCTION_OPERAND_CONTROLS>::EncodeOperandDstType(
inst, opnds);
if (inst->isAligned16Inst()) {
EncodeDstChanEn(inst, opnds);
}
// Note: dst doesn't have the vertical stride and width
EncodeDstRegNum(inst, opnds);
EncodeDstArchRegNum(inst, opnds);
EncodeDstIndirectRegNum(inst, opnds);
EncodeDstHorzStride(inst, dst, opnds);
DstBuilder<G9HDL::EU_INSTRUCTION_OPERAND_CONTROLS>::EncodeDstAddrMode(inst,
opnds);
}
// EU_INSTRUCTION_BASIC_ONE_SRC
// (EU_INSTRUCTION_SOURCES_REG
// EU_INSTRUCTION_OPERAND_SRC_REG_ALIGN1
// or
// EU_INSTRUCTION_OPERAND_SRC_REG_ALIGN16)
// or
// (EU_INSTRUCTION_SOURCES_IMM32
inline void BinaryEncodingCNL::EncodeOneSrcInst(
G4_INST *inst, G9HDL::EU_INSTRUCTION_BASIC_ONE_SRC &oneSrc) {
EncodeInstHeader(inst, oneSrc.Common.Header);
EncodeOperandDst(inst, oneSrc.Common.OperandControls);
G4_Operand *src0 = inst->getSrc(0);
// EncodeSrc0RegFile
oneSrc.GetOperandControls().SetSrc0Regfile(
TranslateVisaToHDLRegFile(EncodingHelper::GetSrcRegFile(src0)));
// EncodeSrc0Type
if (src0->isImm()) {
oneSrc.GetOperandControls().SetSrc0Srctype_Imm(
GetOperandSrcHDLImmType(src0->getType()));
} else {
oneSrc.GetOperandControls().SetSrc0Srctype(
GetOperandSrcHDLType(src0->getType()));
}
if (src0->isImm()) {
// this should be compiled as dead code in non-debug mode
vISA_ASSERT(inst->opcode() == G4_mov || src0->getTypeSize() != 8,
"only Mov is allowed for 64-bit immediate");
if (src0->getTypeSize() == 8) {
G9HDL::EU_INSTRUCTION_IMM64_SRC *ptr =
(G9HDL::EU_INSTRUCTION_IMM64_SRC *)&oneSrc;
EncodeSrcImm64Data(*ptr, src0);
} else {
// EncodeSrcImmData(oneSrc.GetImmsource(), src0);
SrcBuilder<G9HDL::EU_INSTRUCTION_SOURCES_IMM32, 0>::EncodeSrcImmData(
oneSrc.GetImmsource(), src0);
}
} else {
SrcBuilder<G9HDL::EU_INSTRUCTION_SOURCES_REG,
0>::EncodeEuInstructionSourcesReg(inst, src0,
oneSrc.GetRegsource(),
*this); // by reference
}
}
inline void BinaryEncodingCNL::EncodeTwoSrcInst(
G4_INST *inst, G9HDL::EU_INSTRUCTION_BASIC_TWO_SRC &twoSrc) {
EncodeInstHeader(inst, twoSrc.Common.Header);
EncodeOperandDst(inst, twoSrc.Common.OperandControls);
G4_Operand *src0 = inst->getSrc(0);
G4_Operand *src1 = inst->getSrc(1);
// EncodeSrc0RegFile
twoSrc.GetOperandControls().SetSrc0Regfile(
TranslateVisaToHDLRegFile(EncodingHelper::GetSrcRegFile(src0)));
[[maybe_unused]]
bool src0ImmOk = inst->isMath() && inst->asMathInst()->isOneSrcMath();
vISA_ASSERT(src0ImmOk || !src0->isImm(),
"src0 is immediate in two src instruction!");
// EncodeSrc0Type
if (src0->isImm()) {
twoSrc.GetOperandControls().SetSrc0Srctype_Imm(
GetOperandSrcHDLImmType(src0->getType()));
} else {
if (inst->isSend()) {
twoSrc.GetOperandControls().SetSrc0Srctype(GetOperandSrcHDLType(Type_F));
} else {
twoSrc.GetOperandControls().SetSrc0Srctype(
GetOperandSrcHDLType(src0->getType()));
}
}
if (src0->isImm()) {
vISA_ASSERT(src0->getTypeSize() < 8,
"only Mov is allowed for 64bit immediate");
// FIXME: feels like this should be 0 here, but it gives a type mismatch as
// the headers assume src0 must be REG
SrcBuilder<G9HDL::EU_INSTRUCTION_SOURCES_REG_IMM, 1>::EncodeSrcImmData(
twoSrc.GetImmsource(), src0);
} else {
SrcBuilder<G9HDL::EU_INSTRUCTION_SOURCES_REG_REG,
0>::EncodeEuInstructionSourcesReg(inst, src0,
twoSrc.GetRegsource(),
*this); // by reference
}
// no need to encode one src math instruction
if (inst->isMath() && src1->isNullReg() && !src0->isImm()) {
SrcBuilder<G9HDL::EU_INSTRUCTION_SOURCES_REG_REG,
1>::EncodeEuInstructionNullSourcesReg(inst, src1,
twoSrc.GetRegsource());
return;
}
twoSrc.GetRegsource().SetSrc1Regfile(
TranslateVisaToHDLRegFile(EncodingHelper::GetSrcRegFile(src1)));
if (src1->isImm()) {
twoSrc.GetImmsource().SetSrc1Srctype(
GetOperandSrcHDLImmType(src1->getType()));
}
// adding to fix above no need to encode type if src0 is immediate and src1 is
// null reg
else if (!(inst->isMath() && src1->isNullReg() && src0->isImm())) {
twoSrc.GetRegsource().SetSrc1Srctype(GetOperandSrcHDLType(src1->getType()));
}
if (src1->isImm()) {
vISA_ASSERT(inst->opcode() == G4_mov || src1->getTypeSize() != 8,
"only Mov is allowed for 64bit immediate");
SrcBuilder<G9HDL::EU_INSTRUCTION_SOURCES_REG_IMM, 1>::EncodeSrcImmData(
twoSrc.GetImmsource(), src1);
} else {
if (src0->isImm()) {
// src1 must be null, and don't encode anything so it won't overwrite
// src0's imm value
vISA_ASSERT(src1->isNullReg(),
"src1 must be null ARF if src0 is immediate");
} else {
SrcBuilder<G9HDL::EU_INSTRUCTION_SOURCES_REG_REG,
1>::EncodeEuInstructionSourcesReg(inst, src1,
twoSrc.GetRegsource(),
*this); // by reference
}
}
}
/// \brief Given a two-src mask, apply a patch for send instruction
///
void PatchSend(G4_INST *inst, G9HDL::EU_INSTRUCTION_BASIC_TWO_SRC *twoSrc) {
vISA_ASSERT(inst->getMsgDescRaw(), "expected raw descriptor");
uint32_t msgDesc = inst->getMsgDescRaw()->getExtendedDesc();
EncExtMsgDescriptor emd;
emd.ulData = msgDesc;
G9HDL::EU_INSTRUCTION_SEND *sendInstruction =
(G9HDL::EU_INSTRUCTION_SEND *)twoSrc;
G9HDL::SFID sfid = (G9HDL::SFID)emd.ExtMsgDescriptor.TargetUnitId;
sendInstruction->SetSharedFunctionIdSfid(sfid);
sendInstruction->SetExdesc1111(msgDesc);
// this is a hack, but:
// fixme: this is missing in auto-header, currently need to override the acc
// write field
if (inst->isNoSrcDepSet()) {
// equivalent to: mybin->SetBits(bitsNoSrcDepSet_0, bitsNoSrcDepSet_1, 1);
sendInstruction->SetControlsB_Accwrctrl(G9HDL::ACCWRCTRL_UPDATE_ACC); // 0x1
}
G9HDL::EOT eot = (G9HDL::EOT)emd.ExtMsgDescriptor.EndOfThread;
sendInstruction->GetMessage().SetEot(eot);
}
/// \brief EncodeMathControl
///
void PatchMath(G4_INST *inst, G9HDL::EU_INSTRUCTION_BASIC_TWO_SRC *twoSrc) {
vISA_ASSERT(inst->isMath(), "PatchMath must be called on math instruction.");
unsigned int MathControlValue = inst->asMathInst()->getMathCtrl();
unsigned MathFunction = MathControlValue & 0xf;
G9HDL::EU_INSTRUCTION_MATH *mathInstruction =
(G9HDL::EU_INSTRUCTION_MATH *)twoSrc;
G9HDL::FC mathFunctionControl = (G9HDL::FC)MathFunction;
mathInstruction->SetFunctionControlFc(mathFunctionControl);
// fixme: what about partial precision bit?
// if (!mybin->GetIs3Src()) {
// mybin->SetBits(bitsMathFunction_0, bitsMathFunction_1, MathFunction);
// mybin->SetBits(bitsMathPartPrec_0, bitsMathPartPrec_1, MathPartPrec);
// }
}
inline G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC::DESTINATION_DATA_TYPE
Get3SrcLimitedType(G4_Type type) {
switch (type) {
case Type_F:
return G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC::DESTINATION_DATA_TYPE_F;
case Type_D:
return G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC::DESTINATION_DATA_TYPE_D;
case Type_UD:
return G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC::DESTINATION_DATA_TYPE_UD;
case Type_DF:
return G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC::DESTINATION_DATA_TYPE_DF;
case Type_HF:
return G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC::DESTINATION_DATA_TYPE_HF;
default:
break;
}
// default
return G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC::DESTINATION_DATA_TYPE_F;
}
inline static G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC::SOURCE_DATA_TYPE
Get3SrcLimitedSrcType(G4_Type type) {
switch (type) {
case Type_F:
return G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC::SOURCE_DATA_TYPE_F;
case Type_D:
return G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC::SOURCE_DATA_TYPE_D;
case Type_UD:
return G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC::SOURCE_DATA_TYPE_UD;
case Type_DF:
return G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC::SOURCE_DATA_TYPE_DF;
case Type_HF:
return G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC::SOURCE_DATA_TYPE_HF;
default:
break;
}
// default
return G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC::SOURCE_DATA_TYPE_F;
}
/// Gets align1 ternary instruction limited type, given execution type
/// (integer/float)
inline static G9HDL::TERNARYALIGN1DATATYPE Get3SrcAlign1LimitedSrcType(
G4_Type type, G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC::EXECUTION_DATATYPE
isFloatExecutionType) {
if (isFloatExecutionType ==
G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC::EXECUTION_DATATYPE_FLOAT) {
switch (type) {
case Type_F:
return G9HDL::TERNARYALIGN1DATATYPE::TERNARYALIGN1DATATYPE_F;
case Type_DF:
return G9HDL::TERNARYALIGN1DATATYPE::TERNARYALIGN1DATATYPE_DF;
case Type_HF:
return G9HDL::TERNARYALIGN1DATATYPE::TERNARYALIGN1DATATYPE_HF;
case Type_NF:
return G9HDL::TERNARYALIGN1DATATYPE::TERNARYALIGN1DATATYPE_NF;
default:
vISA_ASSERT_UNREACHABLE("wrong type for align1 ternary instruction with float "
"execution type.");
break;
}
// Some reasonable default:
return G9HDL::TERNARYALIGN1DATATYPE::TERNARYALIGN1DATATYPE_F;
} else {
switch (type) {
case Type_UD:
return G9HDL::TERNARYALIGN1DATATYPE::TERNARYALIGN1DATATYPE_UD;
case Type_D:
return G9HDL::TERNARYALIGN1DATATYPE::TERNARYALIGN1DATATYPE_D;
case Type_UW:
return G9HDL::TERNARYALIGN1DATATYPE::TERNARYALIGN1DATATYPE_UW;
case Type_W:
return G9HDL::TERNARYALIGN1DATATYPE::TERNARYALIGN1DATATYPE_W;
case Type_UB:
return G9HDL::TERNARYALIGN1DATATYPE::TERNARYALIGN1DATATYPE_UB;
case Type_B:
return G9HDL::TERNARYALIGN1DATATYPE::TERNARYALIGN1DATATYPE_B;
default:
vISA_ASSERT_UNREACHABLE("wrong type for align1 ternary instruction with integer "
"execution type.");
break;
}
// Some reasonable default:
return G9HDL::TERNARYALIGN1DATATYPE::TERNARYALIGN1DATATYPE_UD;
}
}
inline void BinaryEncodingCNL::EncodeThreeSrcInst(
G4_INST *inst, G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC &threeSrc) {
G4_Operand *src0 = inst->getSrc(0);
G4_Operand *src1 = inst->getSrc(1);
G4_Operand *src2 = inst->getSrc(2);
G4_Operand *dst = inst->getDst();
EncodeInstHeader(inst, threeSrc.Common.Header);
// threeSrc doesn't have OperandControls field, need to implement its dst
// encoding separately
DstBuilder<G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC>::EncodeFlagReg(inst,
threeSrc);
DstBuilder<G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC>::EncodeMaskCtrl(inst,
threeSrc);
{
threeSrc.SetDestinationDataType(Get3SrcLimitedType(dst->getType()));
threeSrc.SetSourceDataType(Get3SrcLimitedSrcType(src0->getType()));
if (src1->getType() == Type_HF) {
threeSrc.SetSource1Type(1);
}
if (src2->getType() == Type_HF) {
threeSrc.SetSource2Type(1);
}
G4_DstRegRegion *dst = inst->getDst();
// this is for 'special accumulators', encoded with channel enable..
if (dst->isAccRegValid()) {
threeSrc.SetDestinationChannelEnable(dst->getAccRegSel());
// NOTE: this one is special case for instructions that use special
// accumulators
} else {
G4_DstRegRegion *dstRegion = static_cast<G4_DstRegRegion *>(dst);
threeSrc.SetDestinationChannelEnable(getWriteMask(dstRegion));
}
if (EncodingHelper::GetDstRegFile(dst) != REG_FILE_A &&
EncodingHelper::GetDstAddrMode(dst) == ADDR_MODE_IMMED) {
uint32_t byteAddress = dst->getLinearizedStart();
threeSrc.SetDestinationRegisterNumber_DestinationRegisterNumber(
byteAddress >> 5);
// must be DWORD aligned
// 3 bits for subregnum
threeSrc.SetDestinationSubregisterNumber((byteAddress >> 2) & 0x7);
vISA_ASSERT(inst->isAligned16Inst(), "3src only support align16 mode");
}
// src0
{
// EncodeSrc0RepCtrl
G4_SrcRegRegion *src0Region = src0->asSrcRegRegion();
G4_SrcRegRegion *src1Region = src1->asSrcRegRegion();
G4_SrcRegRegion *src2Region = src2->asSrcRegRegion();
// source modifiers:
SrcBuilder<G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC, 0>::EncodeSrcModifier(
inst, src0, threeSrc);
SrcBuilder<G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC, 1>::EncodeSrcModifier(
inst, src1, threeSrc);
SrcBuilder<G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC, 2>::EncodeSrcModifier(
inst, src2, threeSrc);
// rep control:
SrcBuilder<G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC,
0>::Encode3SrcReplicateControl(&threeSrc, src0Region, *this);
SrcBuilder<G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC,
1>::Encode3SrcReplicateControl(&threeSrc, src1Region, *this);
SrcBuilder<G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC,
2>::Encode3SrcReplicateControl(&threeSrc, src2Region, *this);
// chan select:
SrcBuilder<G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC, 0>::EncodeSrcChanSelect(
&threeSrc, inst, src0, src0Region, *this);
SrcBuilder<G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC, 1>::EncodeSrcChanSelect(
&threeSrc, inst, src1, src1Region, *this);
SrcBuilder<G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC, 2>::EncodeSrcChanSelect(
&threeSrc, inst, src2, src2Region, *this);
SrcBuilder<G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC, 0>::EncodeSrcRegNum3Src(
inst, src0, threeSrc);
SrcBuilder<G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC, 1>::EncodeSrcRegNum3Src(
inst, src1, threeSrc);
SrcBuilder<G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC, 2>::EncodeSrcRegNum3Src(
inst, src2, threeSrc);
// register
// sub-register
}
}
}
inline void BinaryEncodingCNL::EncodeThreeSrcInstAlign1(
G4_INST *inst, G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC &threeSrc) {
G4_Operand *src0 = inst->getSrc(0);
G4_Operand *src1 = inst->getSrc(1);
G4_Operand *src2 = inst->getSrc(2);
G4_DstRegRegion *dst = inst->getDst();
// Common instruction fields:
EncodeInstHeader(inst, threeSrc.TheStructure.Common.Header);
DstBuilder<G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC>::EncodeFlagReg(inst,
threeSrc);
DstBuilder<G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC>::EncodeMaskCtrl(inst,
threeSrc);
vISA_ASSERT(
(IS_TYPE_FLOAT_ALL(src0->getType()) &&
IS_TYPE_FLOAT_ALL(src1->getType()) &&
IS_TYPE_FLOAT_ALL(src2->getType()) &&
IS_TYPE_FLOAT_ALL(dst->getType())) ||
(IS_TYPE_INT(src0->getType()) && IS_TYPE_INT(src1->getType()) &&
IS_TYPE_INT(src2->getType()) && IS_TYPE_INT(dst->getType())),
"No mixed mode in align1 ternary encoding.");
G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC::EXECUTION_DATATYPE execType =
IS_TYPE_FLOAT_ALL(dst->getType())
? G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC::EXECUTION_DATATYPE_FLOAT
: G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC::EXECUTION_DATATYPE_INTEGER;
threeSrc.SetExecutionDatatype(execType);
// DST REGFILE
switch (EncodingHelper::GetDstRegFile(dst)) {
case REG_FILE_R:
threeSrc.SetDestinationRegisterFile(
G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC::DESTINATION_REGISTER_FILE_GRF);
break;
case REG_FILE_A:
threeSrc.SetDestinationRegisterFile(
G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC::DESTINATION_REGISTER_FILE_ARF);
break;
default:
vISA_ASSERT_UNREACHABLE("Invalid dst register file for for align1 ternary "
"instruction (expected grf or arf).");
break;
}
// SRC modifiers:
if (src0->isSrcRegRegion()) {
threeSrc.SetSource0Modifier(
BinaryEncodingCNL::GetSrcHLDMod(src0->asSrcRegRegion()));
} else {
threeSrc.SetSource0Modifier(G9HDL::SRCMOD_NO_MODIFICATION);
}
if (src1->isSrcRegRegion()) {
threeSrc.SetSource1Modifier(
BinaryEncodingCNL::GetSrcHLDMod(src1->asSrcRegRegion()));
} else {
threeSrc.SetSource1Modifier(G9HDL::SRCMOD_NO_MODIFICATION);
}
if (src2->isSrcRegRegion()) {
threeSrc.SetSource2Modifier(
BinaryEncodingCNL::GetSrcHLDMod(src2->asSrcRegRegion()));
} else {
threeSrc.SetSource2Modifier(G9HDL::SRCMOD_NO_MODIFICATION);
}
// SRC0 regfile
switch (EncodingHelper::GetSrcRegFile(src0)) {
case REG_FILE_R:
threeSrc.SetSource0RegisterFile(
G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC::SOURCE_0_REGISTER_FILE_GRF);
break;
case REG_FILE_I:
threeSrc.SetSource0RegisterFile(
G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC::SOURCE_0_REGISTER_FILE_IMM);
break;
case REG_FILE_A:
vISA_ASSERT(src0->getType() == Type_NF,
"Invalid register file for src0 in align1 ternary instruction "
"(expected grf or imm).");
threeSrc.SetSource0RegisterFile(
G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC::SOURCE_0_REGISTER_FILE_ARF);
break;
default:
break;
}
// SRC1 regfile
switch (EncodingHelper::GetSrcRegFile(src1)) {
case REG_FILE_R:
threeSrc.SetSource1RegisterFile(
G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC::SOURCE_1_REGISTER_FILE_GRF);
break;
case REG_FILE_A:
threeSrc.SetSource1RegisterFile(
G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC::SOURCE_1_REGISTER_FILE_ARF);
break;
default:
vISA_ASSERT_UNREACHABLE("Invalid register file for src1 in align1 ternary "
"instruction(expected grf or arf).");
break;
}
// SRC2 regfile
switch (EncodingHelper::GetSrcRegFile(src2)) {
case REG_FILE_R:
threeSrc.SetSource2RegisterFile(
G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC::SOURCE_2_REGISTER_FILE_GRF);
break;
case REG_FILE_I:
threeSrc.SetSource2RegisterFile(
G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC::SOURCE_2_REGISTER_FILE_IMM);
break;
default:
vISA_ASSERT_UNREACHABLE("Invalid register file for src2 in align1 ternary "
"instruction(expected grf or imm).");
break;
}
threeSrc.SetDestinationDatatype(
Get3SrcAlign1LimitedSrcType(dst->getType(), execType));
// Dst reg/subreg
switch (EncodingHelper::GetDstRegFile(dst)) {
case REG_FILE_R: {
uint32_t byteAddress = dst->getLinearizedStart();
if (kernel.fg.builder->encodeAccRegSelAsAlign1() && dst->isAccRegValid()) {
// special accumulator region (acc2-acc9) is encoded as part of subreg
vISA_ASSERT((byteAddress & 0x1F) == 0,
"subreg must be 0 for dst with special accumulator");
threeSrc.SetDestinationSpecialAcc(dst->getAccRegSel());
} else {
threeSrc.SetDestinationSubregisterNumber(byteAddress & 0x1f);
}
threeSrc.SetDestinationRegisterNumber(byteAddress >> 5);
break;
}
case REG_FILE_A: {
bool valid;
unsigned short RegFile =
(unsigned short)EncodingHelper::GetDstArchRegType(dst); // 4 bits
unsigned short RegNumValue = dst->ExRegNum(valid);
// 7654|3210
// RegF|RegNumVal
unsigned short EncodedRegNum = RegFile << 4;
EncodedRegNum = EncodedRegNum | (RegNumValue & 0xF);
threeSrc.SetDestinationRegisterNumber(EncodedRegNum);
break;
}
default:
vISA_ASSERT_UNREACHABLE("Invalid register file for dst in align1 ternary "
"instruction(expected grf or acc).");
break;
}
switch (dst->getHorzStride()) {
case 1:
threeSrc.SetDestinationHorizontalStride(
G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC::
DESTINATION_HORIZONTAL_STRIDE_1_ELEMENT);
break;
case 2:
threeSrc.SetDestinationHorizontalStride(
G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC::
DESTINATION_HORIZONTAL_STRIDE_2_ELEMENT);
break;
case UNDEFINED_SHORT:
vISA_ASSERT_UNREACHABLE(
"Dst horizontal stride for align1 ternary instruction is undefined.");
threeSrc.SetDestinationHorizontalStride(
G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC::
DESTINATION_HORIZONTAL_STRIDE_1_ELEMENT);
break;
default:
vISA_ASSERT_UNREACHABLE("Wrong dst horizontal stride for align1 ternary "
"instruction (is neither 1 nor 2).");
break;
}
// SRC0 fields
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
threeSrc.SetSource0Datatype(
Get3SrcAlign1LimitedSrcType(src0->getType(), execType));
if (src0->isSrcRegRegion()) {
const RegionDesc *regdesc0 = src0->asSrcRegRegion()->getRegion();
vISA_ASSERT(regdesc0, "Align1 ternary encoder: src0 region desc for "
"ternary instruction is null!");
// look for <N;N,1> contiguous region
if (regdesc0->vertStride > 8) {
// TODO: should we care about this case?
vISA_ASSERT(
0, "Align1 3 src instruction with vertStride>8 not supported yet.");
} else {
// src0: vstride
switch (regdesc0->vertStride) {
case 0:
SrcOperandEncoder<G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC, 0>::
SetSourceVerticalStride(&threeSrc,
G9HDL::TERNARYALIGN1VERTSTRIDE_0_ELEMENTS);
break;
case 2:
SrcOperandEncoder<G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC, 0>::
SetSourceVerticalStride(&threeSrc,
G9HDL::TERNARYALIGN1VERTSTRIDE_2_ELEMENTS);
break;
case 4:
SrcOperandEncoder<G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC, 0>::
SetSourceVerticalStride(&threeSrc,
G9HDL::TERNARYALIGN1VERTSTRIDE_4_ELEMENTS);
break;
case 8:
SrcOperandEncoder<G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC, 0>::
SetSourceVerticalStride(&threeSrc,
G9HDL::TERNARYALIGN1VERTSTRIDE_8_ELEMENTS);
break;
default:
vISA_ASSERT_UNREACHABLE(
"wrong vertical stride for ternary align1 instruction at src0!");
break;
}
// src0: hstride
SrcBuilder<G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC,
0>::EncodeSrcHorzStride(inst, &threeSrc, regdesc0, src0);
}
vISA_ASSERT(EncodingHelper::GetSrcRegFile(src0) != REG_FILE_I,
"Align1 ternary: src0 register file must not be immediate if "
"src region is present. ");
if (EncodingHelper::GetSrcRegFile(src0) != REG_FILE_A) {
uint32_t byteAddress = src0->getLinearizedStart();
threeSrc.SetSource0RegisterNumber_SourceRegisterNumber(byteAddress >> 5);
if (kernel.fg.builder->encodeAccRegSelAsAlign1() &&
src0->isAccRegValid()) {
vISA_ASSERT((byteAddress & 0x1F) == 0,
"subreg must be 0 for source with special accumualators");
threeSrc.SetSource0SpecialAcc(src0->getAccRegSel());
} else {
threeSrc.SetSource0SubregisterNumber_SourceSubRegisterNumber(
byteAddress & 0x1f);
}
} else {
vISA_ASSERT(src0->getType() == Type_NF,
"only NF type src0 can be accumulator");
// encode acc
bool valid;
unsigned short RegFile =
(unsigned short)EncodingHelper::GetSrcArchRegType(src0); // 4 bits
unsigned short RegNumValue = src0->asSrcRegRegion()->ExRegNum(valid);
// 7654|3210
// RegF|RegNumVal
unsigned short EncodedRegNum = RegFile << 4;
EncodedRegNum = EncodedRegNum | (RegNumValue & 0xF);
threeSrc.SetSource0RegisterNumber_SourceRegisterNumber(EncodedRegNum);
}
} else {
vISA_ASSERT(EncodingHelper::GetSrcRegFile(src0) == REG_FILE_I,
"Align1 ternary: src0 reg file must be immediate if operand "
"is immediate.");
G4_Imm *isrc = (G4_Imm *)src0->asImm();
threeSrc.SetSource0ImmediateValue((uint32_t)isrc->getImm());
}
// SRC1 fields
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
threeSrc.SetSource1Datatype(
Get3SrcAlign1LimitedSrcType(src1->getType(), execType));
vISA_ASSERT(EncodingHelper::GetSrcRegFile(src1) != REG_FILE_I,
"Align1 ternary:src1 immediate register file not supported by "
"definition.");
if (EncodingHelper::GetSrcRegFile(src1) != REG_FILE_A) {
uint32_t byteAddress = src1->getLinearizedStart();
threeSrc.SetSource1RegisterNumber_SourceRegisterNumber(byteAddress >> 5);
if (kernel.fg.builder->encodeAccRegSelAsAlign1() && src1->isAccRegValid()) {
vISA_ASSERT((byteAddress & 0x1F) == 0,
"subreg must be 0 for source with special accumualators");
threeSrc.SetSource1SpecialAcc(src1->getAccRegSel());
} else {
threeSrc.SetSource1SubregisterNumber_SourceSubRegisterNumber(byteAddress &
0x1f);
}
} else {
// encode acc
bool valid;
unsigned short RegFile =
(unsigned short)EncodingHelper::GetSrcArchRegType(src1); // 4 bits
unsigned short RegNumValue = src1->asSrcRegRegion()->ExRegNum(valid);
// 7654|3210
// RegF|RegNumVal
unsigned short EncodedRegNum = RegFile << 4;
EncodedRegNum = EncodedRegNum | (RegNumValue & 0xF);
threeSrc.SetSource1RegisterNumber_SourceRegisterNumber(EncodedRegNum);
}
const RegionDesc *regdesc1 = src1->asSrcRegRegion()->getRegion();
vISA_ASSERT(regdesc1, "Align1 ternary encoder: src1 region desc for ternary "
"instruction is null!");
// look for <N;N,1> contiguous region
if (regdesc1->vertStride > 8) {
// TODO: should we care about this case?
vISA_ASSERT(
0, "align1 3 src instruction with vertStride>8 not supported yet.");
} else {
SrcBuilder<G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC, 1>::EncodeSrcHorzStride(
inst, &threeSrc, regdesc1, src1);
// src1: vstride
switch (regdesc1->vertStride) {
case 0:
SrcOperandEncoder<G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC, 1>::
SetSourceVerticalStride(&threeSrc,
G9HDL::TERNARYALIGN1VERTSTRIDE_0_ELEMENTS);
break;
case 2:
SrcOperandEncoder<G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC, 1>::
SetSourceVerticalStride(&threeSrc,
G9HDL::TERNARYALIGN1VERTSTRIDE_2_ELEMENTS);
break;
case 4:
SrcOperandEncoder<G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC, 1>::
SetSourceVerticalStride(&threeSrc,
G9HDL::TERNARYALIGN1VERTSTRIDE_4_ELEMENTS);
break;
case 8:
SrcOperandEncoder<G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC, 1>::
SetSourceVerticalStride(&threeSrc,
G9HDL::TERNARYALIGN1VERTSTRIDE_8_ELEMENTS);
break;
default:
vISA_ASSERT_UNREACHABLE(
"wrong vertical stride for ternary align1 instruction at src0!");
break;
}
}
// SRC2 fields
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
threeSrc.SetSource2Datatype(
Get3SrcAlign1LimitedSrcType(src2->getType(), execType));
if (src2->isSrcRegRegion()) {
const RegionDesc *regdesc2 = src2->asSrcRegRegion()->getRegion();
vISA_ASSERT(regdesc2, "Align1 ternary instruction: src2 region desc for "
"instruction is null!");
vISA_ASSERT(EncodingHelper::GetSrcRegFile(src2) != REG_FILE_I,
"Align1 ternary encoder: src2 reg file is immediate even if "
"src region present.");
// src2 reg/subreg
if (EncodingHelper::GetSrcRegFile(src2) != REG_FILE_A) {
uint32_t byteAddress = src2->getLinearizedStart();
threeSrc.SetSource2RegisterNumber_SourceRegisterNumber(byteAddress >> 5);
if (kernel.fg.builder->encodeAccRegSelAsAlign1() &&
src2->isAccRegValid()) {
vISA_ASSERT((byteAddress & 0x1F) == 0,
"subreg must be 0 for source with special accumualators");
threeSrc.SetSource2SpecialAcc(src2->getAccRegSel());
} else {
threeSrc.SetSource2SubregisterNumber_SourceSubRegisterNumber(
byteAddress & 0x1f);
}
}
switch (regdesc2->horzStride) {
case 0:
SrcOperandEncoder<G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC, 2>::
SetSourceHorizontalStride(&threeSrc, G9HDL::HORZSTRIDE_0_ELEMENTS);
break;
case 1:
SrcOperandEncoder<G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC, 2>::
SetSourceHorizontalStride(&threeSrc, G9HDL::HORZSTRIDE_1_ELEMENTS);
break;
case 2:
SrcOperandEncoder<G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC, 2>::
SetSourceHorizontalStride(&threeSrc, G9HDL::HORZSTRIDE_2_ELEMENTS);
break;
case 4:
SrcOperandEncoder<G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC, 2>::
SetSourceHorizontalStride(&threeSrc, G9HDL::HORZSTRIDE_4_ELEMENTS);
break;
default:
vISA_ASSERT_UNREACHABLE("Align1 ternary: src2 has non-encodable horizontal "
"stride (accepted: 0,1,2,4).");
break;
}
} else {
vISA_ASSERT(EncodingHelper::GetSrcRegFile(src2) == REG_FILE_I,
"Align1 ternary: src2 reg file must be immediate if operand "
"is immediate.");
G4_Imm *isrc = (G4_Imm *)src2->asImm();
threeSrc.SetSource2ImmediateValue((uint32_t)isrc->getImm());
}
}
/// \brief Get compaction control bit from already encoded binary instruction
///
uint32_t BinaryEncodingCNL::GetCompactCtrl(BinInst *mybin) {
G9HDL::EU_INSTRUCTION_HEADER *ptr =
(G9HDL::EU_INSTRUCTION_HEADER *)&(mybin->DWords);
return (uint32_t)ptr->GetControl().GetControlsB_Cmptctrl();
}
/// \brief Set compaction control bit. TODO: how to write to mybin->DWords.
/// below doesn't work
///
void BinaryEncodingCNL::SetCompactCtrl(BinInst *mybin, uint32_t value) {
G9HDL::EU_INSTRUCTION_HEADER *ptr =
(G9HDL::EU_INSTRUCTION_HEADER *)&(mybin->DWords);
ptr->GetControl().SetControlsB_Cmptctrl(G9HDL::CMPTCTRL_COMPACTED);
}
/// \brief Encode JIP and(or) UIP at their respective places
///
/// Comments are left from original binary encoder
/// TODO: move as a class method
void BinaryEncodingCNL::SetBranchOffsets(G4_INST *inst, uint32_t JIP,
uint32_t UIP) {
BinInst *mybin = getBinInst(inst);
G4_opcode opc = inst->opcode();
{
if (opc == G4_if || opc == G4_break || opc == G4_cont || opc == G4_halt ||
opc == G4_goto || opc == G4_else) {
// cast binary as branch two src
// note: if an instruction has both JIP and UIP, then
// only src0 type and regfile are being set (higher dword is occupied)
G9HDL::EU_INSTRUCTION_BRANCH_TWO_SRC *twoSrc =
(G9HDL::EU_INSTRUCTION_BRANCH_TWO_SRC *)mybin->DWords;
twoSrc->GetOperandControl().SetSrc0Regfile(G9HDL::REGFILE_IMM);
twoSrc->GetOperandControl().SetSrc0Srctype_Imm(
GetOperandSrcHDLImmType(Type_D));
twoSrc->SetJip(JIP);
twoSrc->SetUip(UIP);
// SetBranchJIPUIP(mybin, JIP, UIP);
} else {
G9HDL::EU_INSTRUCTION_BRANCH_ONE_SRC *oneSrc =
(G9HDL::EU_INSTRUCTION_BRANCH_ONE_SRC *)mybin->DWords;
oneSrc->SetSrc1Regfile(G9HDL::REGFILE_IMM);
oneSrc->SetSrc1Srctype(GetOperandSrcHDLImmType(Type_D));
oneSrc->SetJip(JIP);
// SetBranchJIP(mybin, JIP);
}
}
}
/// \brief encodes JIP and(or) UIP offsets
///
/// This is done in this separate method, and not during the main
/// encoding phase, since the real jump offsets are visible only
/// now.
bool BinaryEncodingCNL::EncodeConditionalBranches(G4_INST *inst,
uint32_t insOffset) {
std::string jipLabel;
std::string uipLabel;
int32_t jipOffset = 0;
int32_t uipOffset = 0;
G4_opcode op = inst->opcode();
// while and case only have JIP for all platforms
// break, cont and halt have both JIP and UIP for all platforms
if (op == G4_if || op == G4_else || op == G4_endif || op == G4_while ||
op == G4_break || op == G4_cont || op == G4_halt || op == G4_goto ||
op == G4_join) {
G4_Label *jip = inst->asCFInst()->getJip();
if (jip) {
int32_t info = GetLabelInfo(jip);
if (info == -1) {
return false;
}
jipOffset = info - insOffset;
jipOffset *= (int32_t)JUMP_INST_COUNT_SIZE;
} else if (op == G4_while || op == G4_endif || op == G4_join) {
{
BinInst *mybin = getBinInst(inst);
G9HDL::EU_INSTRUCTION_BRANCH_ONE_SRC *oneSrc =
(G9HDL::EU_INSTRUCTION_BRANCH_ONE_SRC *)mybin->DWords;
oneSrc->SetSrc1Regfile(G9HDL::REGFILE_IMM);
oneSrc->SetSrc1Srctype(GetOperandSrcHDLImmType(Type_D));
}
}
}
// halt has both JIP and UIP on all platforms
// else has JIP for all platforms; else has UIP for BDW only
if (op == G4_break || op == G4_cont || op == G4_halt || op == G4_if ||
op == G4_else || op == G4_goto) {
G4_Label *uip = inst->asCFInst()->getUip();
if (uip) {
int32_t info = GetLabelInfo(uip);
if (info == -1) {
return false;
}
uipOffset = info - insOffset;
uipOffset *= (uint32_t)JUMP_INST_COUNT_SIZE;
}
}
if (op == G4_endif && jipOffset == 0) {
jipOffset = INST_SIZE;
}
if (jipOffset != 0 || uipOffset != 0) {
SetBranchOffsets(inst, jipOffset, uipOffset);
}
if (op == G4_jmpi && inst->getSrc(0) && inst->getSrc(0)->isLabel()) {
// find the label's IP count
G4_Operand *opnd = inst->getSrc(0);
BinInst *mybin = getBinInst(inst);
// Calculate the address offset
// Label has the same IP count as the following instruction,
// "break 1" is to the fall through instruction
int32_t info = GetLabelInfo(opnd->asLabel());
if (info == -1) {
return false;
}
int32_t jmpOffset = info - insOffset;
if (GetCompactCtrl(mybin))
jmpOffset -= 1;
else
jmpOffset -= 2;
jmpOffset *= (int32_t)JUMP_INST_COUNT_SIZE;
// FIXME: add compaction support
// if (GetCompactCtrl(mybin))
//{
// SetCmpSrc1RegNum(mybin, jmpOffset & 0xff); // 63:56
// SetCmpSrc1Index(mybin, (jmpOffset >> 8)& 0x1f);
// }
// else
{
BinInst *mybin = getBinInst(inst);
G9HDL::EU_INSTRUCTION_BRANCH_ONE_SRC *oneSrc =
(G9HDL::EU_INSTRUCTION_BRANCH_ONE_SRC *)mybin->DWords;
oneSrc->SetSrc1Regfile(G9HDL::REGFILE_IMM);
oneSrc->SetSrc1Srctype(GetOperandSrcHDLImmType(Type_D));
oneSrc->SetJip((uint32_t)jmpOffset);
}
}
if (op == G4_call && inst->getSrc(0) && inst->getSrc(0)->isLabel()) {
G4_Operand *opnd = inst->getSrc(0);
int32_t info = GetLabelInfo(opnd->asLabel());
if (info == -1) {
return false;
}
int32_t jmpOffset = info - insOffset;
{ jmpOffset *= (int32_t)JUMP_INST_COUNT_SIZE; }
BinInst *mybin = getBinInst(inst);
G9HDL::EU_INSTRUCTION_BRANCH_ONE_SRC *oneSrc =
(G9HDL::EU_INSTRUCTION_BRANCH_ONE_SRC *)mybin->DWords;
oneSrc->SetSource0_SourceVerticalStride(G9HDL::VERTSTRIDE_2_ELEMENTS);
oneSrc->SetSource0_SourceWidth(G9HDL::WIDTH_4_ELEMENTS);
oneSrc->SetSource0_SourceHorizontalStride(G9HDL::HORZSTRIDE_1_ELEMENTS);
oneSrc->SetSrc1Regfile(G9HDL::REGFILE_IMM);
oneSrc->SetSrc1Srctype(GetOperandSrcHDLImmType(Type_D));
oneSrc->SetJip((uint32_t)jmpOffset);
// TODO: do not forget about compacted variant
}
return true;
}
/// \brief initializes auto-header generated structure for split send
/// instruction
///
BinaryEncodingCNL::Status
BinaryEncodingCNL::EncodeSplitSend(G4_INST *inst,
G9HDL::EU_INSTRUCTION_SENDS &sends) {
Status myStatus = SUCCESS;
G9HDL::EU_INSTRUCTION_BASIC_TWO_SRC *twoSrcMirror =
(G9HDL::EU_INSTRUCTION_BASIC_TWO_SRC *)&sends;
EncodeInstHeader(inst, twoSrcMirror->Common.Header);
// encode dst part
// trimmed down EncodeOperandDst
{
DstBuilder<G9HDL::EU_INSTRUCTION_SENDS>::EncodeFlagReg(inst, sends);
DstBuilder<G9HDL::EU_INSTRUCTION_SENDS>::EncodeMaskCtrl(inst, sends);
DstBuilder<G9HDL::EU_INSTRUCTION_SENDS>::EncodeOperandDstType(inst, sends);
DstBuilder<G9HDL::EU_INSTRUCTION_SENDS>::EncodeDstAddrMode(inst, sends);
G4_DstRegRegion *dst = inst->getDst();
// encode dst reg file
// note: for sends, we have only one bit available for dst reg file
{
switch (EncodingHelper::GetDstRegFile(dst)) {
case REG_FILE_R:
sends.SetDestinationRegisterFile(G9HDL::REGFILE_GRF);
break;
case REG_FILE_A:
sends.SetDestinationRegisterFile(G9HDL::REGFILE_ARF);
break;
default:
vISA_ASSERT_UNREACHABLE(" Invalid register file for split-send.");
break;
}
}
if (EncodingHelper::GetDstAddrMode(dst) == ADDR_MODE_INDIR) {
// addr subregister
// addr immediate
bool subValid;
uint16_t IndAddrRegSubNumValue = dst->ExIndSubRegNum(subValid);
int16_t IndAddrImmedValue = dst->ExIndImmVal();
sends.SetDestinationAddressSubregisterNumber(IndAddrRegSubNumValue);
sends.SetDestinationAddressImmediate84((IndAddrImmedValue >> 4) & 0x1F);
sends.SetDestinationAddressImmediateSign9((IndAddrImmedValue >> 9) & 0x1);
} else {
if (EncodingHelper::GetDstRegFile(dst) != REG_FILE_A) {
uint32_t byteAddress = dst->getLinearizedStart();
vISA_ASSERT(byteAddress % 16 == 0,
"dst for sends/sendsc must be oword-aligned");
sends.SetDestinationRegisterNumber(byteAddress >> 5);
sends.SetDestinationSubregisterNumber4((byteAddress >> 4) & 0x1);
}
}
}
// encode src1
{
G4_Operand *src1 = inst->getSrc(1);
// src1 reg file - 1 bit
switch (EncodingHelper::GetSrcRegFile(src1)) {
case REG_FILE_R:
sends.SetSrc1Regfile(G9HDL::REGFILE_GRF);
break;
case REG_FILE_A:
sends.SetSrc1Regfile(G9HDL::REGFILE_ARF);
break;
default:
vISA_ASSERT_UNREACHABLE(" Invalid register file for split-send.");
break;
}
G4_SrcRegRegion *src1Region = src1->asSrcRegRegion();
SrcBuilder<G9HDL::EU_INSTRUCTION_SENDS, 1>::EncodeSrcAddrMode(&sends, inst,
src1);
if (EncodingHelper::GetSrcAddrMode(src1) == ADDR_MODE_INDIR) {
bool subValid;
uint16_t IndAddrRegSubNumValue = src1Region->ExIndSubRegNum(subValid);
int16_t IndAddrImmedValue = src1Region->ExIndImmVal();
sends.SetSource1_SourceAddressImmediate84((IndAddrImmedValue >> 4) &
0x1F);
sends.SetSource1_SourceAddressImmediateSign9((IndAddrImmedValue >> 9) &
0x1);
sends.SetSource1_SourceAddressSubregisterNumber_0(IndAddrRegSubNumValue);
} else {
uint32_t byteAddress = src1->getLinearizedStart();
vISA_ASSERT(byteAddress % 32 == 0,
"src1 for sends/sendsc must be GRF-aligned");
sends.SetSource1_SourceRegisterNumber(byteAddress >> 5);
// mybin->SetBits(bitsSendsSrc1RegNum_0, bitsSendsSrc1RegNum_1,
// byteAddress >> 5);
}
}
// encode src0
{
G4_SrcRegRegion *src0 = inst->getSrc(0)->asSrcRegRegion();
// note: no regfile for src0
SrcBuilder<G9HDL::EU_INSTRUCTION_SENDS, 0>::EncodeSrcAddrMode(&sends, inst,
src0);
if (EncodingHelper::GetSrcAddrMode(src0) == ADDR_MODE_INDIR) {
bool subValid;
uint16_t IndAddrRegSubNumValue = src0->ExIndSubRegNum(subValid);
int16_t IndAddrImmedValue = src0->ExIndImmVal();
sends.SetSource0_SourceAddressImmediate84((IndAddrImmedValue >> 4) &
0x1F);
sends.SetSource0_SourceAddressImmediateSign9((IndAddrImmedValue >> 9) &
0x1);
sends.SetSource0_SourceAddressSubregisterNumber(IndAddrRegSubNumValue);
} else {
uint32_t byteAddress = src0->getLinearizedStart();
vISA_ASSERT(byteAddress % 32 == 0,
"src1 for sends/sendsc must be GRF-aligned");
sends.SetSource0_SourceRegisterNumber(byteAddress >> 5);
// mybin->SetBits(bitsSendsSrc1RegNum_0, bitsSendsSrc1RegNum_1,
// byteAddress >> 5);
}
}
// encode src2
{
G4_Operand *src2 = inst->getSrc(2);
if (src2 == NULL) {
return FAILURE;
}
if (src2->isImm()) {
sends.SetSelreg32desc(0);
sends.GetMessage().GetDWORD(0) = (uint32_t)src2->asImm()->getInt();
} else if (src2->isSrcRegRegion() && src2->asSrcRegRegion()->isDirectA0()) {
sends.SetSelreg32desc(1);
}
}
// Patch SFID and EOT
{
vISA_ASSERT(inst->getMsgDescRaw(), "expected raw descriptor");
uint32_t msgDesc = inst->getMsgDescRaw()->getExtendedDesc();
EncExtMsgDescriptor emd;
emd.ulData = msgDesc;
G9HDL::SFID sfid = (G9HDL::SFID)emd.ExtMsgDescriptor.TargetUnitId;
sends.SetSharedFunctionIdSfid(sfid);
G9HDL::EOT eot = (G9HDL::EOT)emd.ExtMsgDescriptor.EndOfThread;
sends.GetMessage().SetEot(eot);
// additional extended msg desc to be encoded
sends.SetExdesc96(msgDesc);
sends.SetExdesc3116(msgDesc);
sends.SetExdesc1111(msgDesc);
// encoding for src3 A0 is done in DoAllEncodingSplitSEND later on
}
// this is a hack, but:
// fixme: this is missing in auto-header, currently need to override the acc
// write field
if (inst->isNoSrcDepSet()) {
// equivalent to: mybin->SetBits(bitsNoSrcDepSet_0, bitsNoSrcDepSet_1, 1);
sends.SetControlsB_Accwrctrl(G9HDL::ACCWRCTRL_UPDATE_ACC); // 0x1
}
return myStatus;
}
/// \brief Do customized encoding of WAIT instruction
///
BinaryEncodingCNL::Status BinaryEncodingCNL::DoAllEncodingWAIT(G4_INST *inst) {
Status myStatus = SUCCESS;
G9HDL::EU_INSTRUCTION_BASIC_ONE_SRC oneSrc;
oneSrc.Init();
EncodeInstHeader(inst, oneSrc.Common.Header);
EncodeOperandDst(inst, oneSrc.Common.OperandControls);
G4_Operand *src0 = inst->getSrc(0);
// EncodeSrc0RegFile
oneSrc.GetOperandControls().SetSrc0Regfile(
TranslateVisaToHDLRegFile(EncodingHelper::GetSrcRegFile(src0)));
// EncodeSrc0Type
vISA_ASSERT(!src0->isImm(),
"src0 must not be immediate in WAIT instruction!");
{
oneSrc.GetOperandControls().SetSrc0Srctype(
GetOperandSrcHDLType(src0->getType()));
}
SrcBuilder<G9HDL::EU_INSTRUCTION_SOURCES_REG,
0>::EncodeEuInstructionSourcesReg(inst, src0,
oneSrc.GetRegsource(),
*this); // by reference
// Dst patching:
RegFile regFile = EncodingHelper::GetSrcRegFile(src0);
vISA_ASSERT(regFile == REG_FILE_A,
"WAIT instruction source has reg file different than ARF!");
oneSrc.Common.OperandControls.SetDestinationRegisterFile(
TranslateVisaToHDLRegFile(regFile));
if (regFile == REG_FILE_A) {
bool valid;
G4_SrcRegRegion *src0Region = src0->asSrcRegRegion();
unsigned short RegFile =
(unsigned short)EncodingHelper::GetSrcArchRegType(src0); // 4 bits
unsigned short RegNumValue = src0Region->ExRegNum(valid);
unsigned short EncodedRegNum =
PackArchRegTypeAndArchRegFile(RegFile, RegNumValue);
oneSrc.Common.OperandControls.GetDestinationRegisterRegion_Align1()
.SetDestinationRegisterNumber_DestinationRegisterNumber(EncodedRegNum);
{
bool subValid;
unsigned short RegSubNumValue = src0Region->ExSubRegNum(subValid);
unsigned short ElementSizeValue =
EncodingHelper::GetElementSizeValue(src0);
uint32_t regOffset = RegSubNumValue * ElementSizeValue;
if (inst->isAligned1Inst()) {
// sub-register number: 32 byte address (5 bits encoding) within a GRF
oneSrc.Common.OperandControls.GetDestinationRegisterRegion_Align1()
.SetDestinationSubregisterNumber_DestinationSubRegisterNumber(
(WORD)regOffset);
} else { // align 16
// sub-register number: first/second 16 byte part of 32 byte address.
// Encoded with 1 bit.
// 9876543210
// regn|x0000
// opnds.GetDestinationRegisterRegion_Align16().SetDestinationSubregisterNumber((regOffset
// >> 4) & 0x1);
oneSrc.Common.OperandControls.GetDestinationRegisterRegion_Align16()
.SetDestinationSubregisterNumber((WORD)regOffset);
}
}
}
oneSrc.Common.OperandControls.GetDestinationRegisterRegion_Align1()
.SetDestinationHorizontalStride(G9HDL::HORZSTRIDE_1_ELEMENTS);
oneSrc.Common.OperandControls.SetDestinationAddressingMode(
TranslateVisaToHDLAddrMode(EncodingHelper::GetSrcAddrMode(src0)));
BinInst *bin = getBinInst(inst);
bin->DWords[0] = oneSrc.GetDWord(0);
bin->DWords[1] = oneSrc.GetDWord(1);
bin->DWords[2] = oneSrc.GetDWord(2);
bin->DWords[3] = oneSrc.GetDWord(3);
return myStatus;
}
/// \brief Do encoding of JMPI instruction
///
BinaryEncodingCNL::Status BinaryEncodingCNL::DoAllEncodingJMPI(G4_INST *inst) {
Status myStatus = SUCCESS;
G9HDL::EU_INSTRUCTION_BRANCH_ONE_SRC brOneSrc;
brOneSrc.Init();
EncodeInstHeader(inst, brOneSrc.GetHeader());
// BEGIN: OPND CONTROL WORD:
DstBuilder<G9HDL::EU_INSTRUCTION_OPERAND_CONTROLS>::EncodeFlagReg(
inst, brOneSrc.GetOperandControl());
DstBuilder<G9HDL::EU_INSTRUCTION_OPERAND_CONTROLS>::EncodeMaskCtrl(
inst, brOneSrc.GetOperandControl());
// hardcode:
brOneSrc.GetOperandControl().SetDestinationRegisterFile(G9HDL::REGFILE_ARF);
brOneSrc.GetOperandControl().SetDestinationDataType(G11HDL::DSTTYPE_UD);
brOneSrc.GetOperandControl().SetDestinationAddressingMode(
G9HDL::ADDRMODE_DIRECT);
// FIXME: bxml does not have arch reg file enumerations
unsigned short RegFile = ARCH_REG_FILE_IP; // 4 bits
unsigned short RegNumValue = 0;
// 7654|3210
// RegF|RegNumVal
unsigned short EncodedRegNum = RegFile << 4;
EncodedRegNum = EncodedRegNum | (RegNumValue & 0xF);
// the same as for align16
brOneSrc.GetOperandControl()
.GetDestinationRegisterRegion_Align1()
.SetDestinationRegisterNumber_DestinationRegisterNumber(EncodedRegNum);
brOneSrc.GetOperandControl()
.GetDestinationRegisterRegion_Align1()
.SetDestinationSubregisterNumber_DestinationSubRegisterNumber(0);
brOneSrc.GetOperandControl()
.GetDestinationRegisterRegion_Align1()
.SetDestinationHorizontalStride(G9HDL::HORZSTRIDE_1_ELEMENTS);
// src0, but belongs to opndCtl dword
brOneSrc.GetOperandControl().SetSrc0Regfile(G9HDL::REGFILE_ARF);
brOneSrc.GetOperandControl().SetSrc0Srctype(GetOperandSrcHDLType(Type_UD));
// END: OPND CONTROL WORD
// BEGIN: src0
if (inst->getSrc(0)) {
SrcOperandEncoder<G9HDL::EU_INSTRUCTION_BRANCH_ONE_SRC,
0>::SetSourceAddressingMode(&brOneSrc,
G9HDL::ADDRMODE_DIRECT);
// FIXME: bxml does not have arch reg file enumerations
unsigned short RegFile = ARCH_REG_FILE_IP; // 4 bits
unsigned short RegNumValue = 0;
// 7654|3210
// RegF|RegNumVal
unsigned short EncodedRegNum = RegFile << 4;
EncodedRegNum = EncodedRegNum | (RegNumValue & 0xF);
SrcOperandEncoder<G9HDL::EU_INSTRUCTION_BRANCH_ONE_SRC,
0>::SetSourceRegisterNumber(&brOneSrc, EncodedRegNum);
SrcOperandEncoder<G9HDL::EU_INSTRUCTION_BRANCH_ONE_SRC,
0>::SetSourceSubRegisterNumber(&brOneSrc, 0);
brOneSrc.SetSource0_SourceWidth(G9HDL::WIDTH_1_ELEMENTS);
if (inst->getSrc(0)->isLabel()) {
brOneSrc.SetSource0_SourceVerticalStride(G9HDL::VERTSTRIDE_0_ELEMENTS);
brOneSrc.SetSource0_SourceHorizontalStride(G9HDL::HORZSTRIDE_0_ELEMENTS);
brOneSrc.SetSource0_SourceModifier(G9HDL::SRCMOD_NO_MODIFICATION);
}
}
if (inst->getSrc(0) && inst->getSrc(0)->isSrcRegRegion()) {
G9HDL::EU_INSTRUCTION_BASIC_TWO_SRC *ptr =
(G9HDL::EU_INSTRUCTION_BASIC_TWO_SRC *)&brOneSrc;
SrcBuilder<G9HDL::EU_INSTRUCTION_SOURCES_REG_REG,
1>::EncodeEuInstructionSourcesReg(inst, inst->getSrc(0),
ptr->GetRegsource(),
*this); // by reference
ptr->GetRegsource().SetSrc1Regfile(TranslateVisaToHDLRegFile(
EncodingHelper::GetSrcRegFile(inst->getSrc(0))));
if (!inst->getSrc(0)->isImm()) {
ptr->GetRegsource().SetSrc1Srctype(
GetOperandSrcHDLType(inst->getSrc(0)->getType()));
}
}
// END: src0
// BEGIN: src1
// The rest is encoded in EncodeConditionalBranches
// END: src1
BinInst *bin = getBinInst(inst);
bin->DWords[0] = brOneSrc.GetDWORD(0);
bin->DWords[1] = brOneSrc.GetDWORD(1);
bin->DWords[2] = brOneSrc.GetDWORD(2);
bin->DWords[3] = brOneSrc.GetDWORD(3);
return myStatus;
}
BinaryEncodingCNL::Status BinaryEncodingCNL::DoAllEncodingCALL(G4_INST *inst) {
Status myStatus = SUCCESS;
BinInst *bin = getBinInst(inst);
G9HDL::EU_INSTRUCTION_BRANCH_ONE_SRC oneSrc;
oneSrc.Init();
EncodeInstHeader(inst, oneSrc.GetHeader());
EncodeOperandDst(inst, oneSrc.GetOperandControl());
if (inst->getSrc(0) && !inst->getSrc(0)->isLabel()) {
// indirect call
G9HDL::EU_INSTRUCTION_BASIC_TWO_SRC *ptr =
(G9HDL::EU_INSTRUCTION_BASIC_TWO_SRC *)&oneSrc;
SrcBuilder<G9HDL::EU_INSTRUCTION_SOURCES_REG_REG,
1>::EncodeEuInstructionSourcesReg(inst, inst->getSrc(0),
ptr->GetRegsource(),
*this); // by reference
ptr->GetRegsource().SetSrc1Regfile(TranslateVisaToHDLRegFile(
EncodingHelper::GetSrcRegFile(inst->getSrc(0))));
if (!inst->getSrc(0)->isImm()) {
ptr->GetRegsource().SetSrc1Srctype(
GetOperandSrcHDLType(inst->getSrc(0)->getType()));
}
} else {
// Needed for correctness
oneSrc.SetSrc1Regfile(G9HDL::REGFILE_IMM);
oneSrc.SetSrc1Srctype(GetOperandSrcHDLImmType(Type_D));
}
bin->DWords[0] = oneSrc.GetDWORD(0);
bin->DWords[1] = oneSrc.GetDWORD(1);
bin->DWords[2] = oneSrc.GetDWORD(2);
bin->DWords[3] = oneSrc.GetDWORD(3);
return myStatus;
}
/// \brief Do encoding of control flow type instructions
///
BinaryEncodingCNL::Status BinaryEncodingCNL::DoAllEncodingCF(G4_INST *inst) {
Status myStatus = SUCCESS;
BinInst *bin = getBinInst(inst);
G9HDL::EU_INSTRUCTION_BRANCH_TWO_SRC brTwoSrc;
brTwoSrc.Init();
// brTwoSrc.Common.OperandControls
EncodeInstHeader(inst, brTwoSrc.GetHeader());
// fixme: not sure why we are setting only this field for dst, but keep the
// binary encoding the same as original one...
brTwoSrc.GetOperandControl()
.GetDestinationRegisterRegion_Align1()
.SetDestinationHorizontalStride(G9HDL::HORZSTRIDE_1_ELEMENTS);
DstBuilder<G9HDL::EU_INSTRUCTION_OPERAND_CONTROLS>::EncodeFlagReg(
inst, brTwoSrc.GetOperandControl());
DstBuilder<G9HDL::EU_INSTRUCTION_OPERAND_CONTROLS>::EncodeMaskCtrl(
inst, brTwoSrc.GetOperandControl());
bin->DWords[0] = brTwoSrc.GetDWord(0);
bin->DWords[1] = brTwoSrc.GetDWord(1);
bin->DWords[2] = brTwoSrc.GetDWord(2);
bin->DWords[3] = brTwoSrc.GetDWord(3);
return myStatus;
}
/// \brief Do encoding of split send instruction
///
BinaryEncodingCNL::Status
BinaryEncodingCNL::DoAllEncodingSplitSEND(G4_INST *inst) {
Status myStatus = SUCCESS;
BinInst *bin = getBinInst(inst);
G9HDL::EU_INSTRUCTION_SENDS sends;
sends.Init();
EncodeSplitSend(inst, sends);
bin->DWords[0] = sends.GetDWORD(0);
bin->DWords[1] = sends.GetDWORD(1);
bin->DWords[2] = sends.GetDWORD(2);
bin->DWords[3] = sends.GetDWORD(3);
// This is a workaround for BXML defect
G4_Operand *src3 = inst->getSrc(3);
// additional extended msg desc to be encoded
// FIXME: does it apply to regular SKL+ sends too?
if (src3 && src3->isSrcRegRegion() && src3->asSrcRegRegion()->isDirectA0()) {
bin->SetBits(bitsSendsSelReg32ExDesc_0, bitsSendsSelReg32ExDesc_1, 1);
bin->SetBits(bitsSendsExDescRegNum_0, bitsSendsExDescRegNum_1,
src3->asSrcRegRegion()->getBase()->asRegVar()->getPhyRegOff());
}
return myStatus;
}
/// \brief Do encoding of all 'regular' one, two or three-src instructions
/// Treats send and math instructions as two-src and patches them
/// accordingly.
BinaryEncodingCNL::Status
BinaryEncodingCNL::DoAllEncodingRegular(G4_INST *inst) {
Status myStatus = SUCCESS;
vISA_ASSERT(!inst->isSplitSend(), "Improper instruction type called with "
"DoAllEncodingRegular: sends or sendsc");
BinInst *bin = getBinInst(inst);
int i = inst->getNumSrc();
switch (i) {
case 0: {
// for nop, we have to encode the opcode, borrow the oneSrc format
G9HDL::EU_INSTRUCTION_BASIC_ONE_SRC oneSrc;
oneSrc.Init();
EncodeOpCode(inst, oneSrc.Common.Header);
bin->DWords[0] = oneSrc.GetDWord(0);
bin->DWords[1] = oneSrc.GetDWord(1);
bin->DWords[2] = oneSrc.GetDWord(2);
bin->DWords[3] = oneSrc.GetDWord(3);
break;
}
case 1:
G9HDL::EU_INSTRUCTION_BASIC_ONE_SRC oneSrc;
oneSrc.Init();
EncodeOneSrcInst(inst, oneSrc);
bin->DWords[0] = oneSrc.GetDWord(0);
bin->DWords[1] = oneSrc.GetDWord(1);
bin->DWords[2] = oneSrc.GetDWord(2);
bin->DWords[3] = oneSrc.GetDWord(3);
break;
case 2:
G9HDL::EU_INSTRUCTION_BASIC_TWO_SRC twoSrc;
twoSrc.Init();
EncodeTwoSrcInst(inst, twoSrc);
if (inst->isSend()) {
PatchSend(inst, &twoSrc);
} else if (inst->isMath()) {
// fixme: math is only for two-src encoding?
PatchMath(inst, &twoSrc);
}
bin->DWords[0] = twoSrc.GetDWord(0);
bin->DWords[1] = twoSrc.GetDWord(1);
bin->DWords[2] = twoSrc.GetDWord(2);
bin->DWords[3] = twoSrc.GetDWord(3);
break;
case 3: {
if (inst->isAligned1Inst()) {
G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC threeSrcAlign1;
threeSrcAlign1.Init();
EncodeThreeSrcInstAlign1(inst, threeSrcAlign1);
bin->DWords[0] = threeSrcAlign1.GetRawData(0);
bin->DWords[1] = threeSrcAlign1.GetRawData(1);
bin->DWords[2] = threeSrcAlign1.GetRawData(2);
bin->DWords[3] = threeSrcAlign1.GetRawData(3);
} else {
G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC threeSrc;
threeSrc.Init();
EncodeThreeSrcInst(inst, threeSrc);
bin->DWords[0] = threeSrc.GetDWORD(0);
bin->DWords[1] = threeSrc.GetDWORD(1);
bin->DWords[2] = threeSrc.GetDWORD(2);
bin->DWords[3] = threeSrc.GetDWORD(3);
}
} break;
default:
break;
}
return myStatus;
}
/// \brief Do all encoding for an instruction.
BinaryEncodingCNL::Status BinaryEncodingCNL::DoAllEncoding(G4_INST *inst) {
Status myStatus = SUCCESS;
bool isFCCall = false, isFCRet = false;
if (inst->opcode() == G4_label)
return myStatus;
if (inst->opcode() == G4_illegal)
return FAILURE;
EncodingHelper::mark3Src(inst, *this);
{
// Prolog:
if (inst->opcode() == G4_pseudo_fc_call) {
inst->asCFInst()->pseudoCallToCall();
isFCCall = true;
}
if (inst->opcode() == G4_pseudo_fc_ret) {
inst->asCFInst()->pseudoRetToRet();
isFCRet = true;
}
if (inst->opcode() == G4_jmpi) {
DoAllEncodingJMPI(inst);
} else if (inst->opcode() == G4_wait) {
DoAllEncodingWAIT(inst);
} else if (inst->opcode() == G4_if || inst->opcode() == G4_endif ||
inst->opcode() == G4_else || inst->opcode() == G4_while ||
inst->opcode() == G4_break || inst->opcode() == G4_cont ||
inst->opcode() == G4_halt || inst->opcode() == G4_goto ||
inst->opcode() == G4_join) {
DoAllEncodingCF(inst);
} else if (inst->opcode() == G4_call) {
DoAllEncodingCALL(inst);
} else if (inst->isSplitSend()) {
DoAllEncodingSplitSEND(inst);
} else if (!EncodingHelper::hasLabelString(inst)) {
DoAllEncodingRegular(inst);
}
// Epilog:
if (isFCCall == true) {
inst->setOpcode(G4_pseudo_fc_call);
}
if (isFCRet == true) {
inst->setOpcode(G4_pseudo_fc_ret);
}
}
return myStatus;
}
/// \brief Entry point.
///
/// This is counterpart of ProduceBinaryInstructions from 'old' encoder
void BinaryEncodingCNL::DoAll() {
std::vector<ForwardJmpOffset> offsetVector;
FixInst();
BinaryEncodingBase::InitPlatform();
// BDW/CHV/SKL/BXT/CNL use the same compaction tables except from 3src.
for (uint8_t i = 0; i < (int)COMPACT_TABLE_SIZE; i++) {
BDWCompactControlTable.AddIndex(IVBCompactControlTable[i], i);
BDWCompactSourceTable.AddIndex(IVBCompactSourceTable[i], i);
BDWCompactSubRegTable.AddIndex(IVBCompactSubRegTable[i], i);
BDWCompactSubRegTable.AddIndex1(IVBCompactSubRegTable[i] & 0x1F, i);
BDWCompactSubRegTable.AddIndex2(IVBCompactSubRegTable[i] & 0x3FF, i);
if (kernel.getPlatform() >= GENX_ICLLP) {
BDWCompactDataTypeTableStr.AddIndex(ICLCompactDataTypeTable[i], i);
} else {
BDWCompactDataTypeTableStr.AddIndex(BDWCompactDataTypeTable[i], i);
}
}
int globalInstNum = 0;
int globalHalfInstNum = 0;
BB_LIST_ITER ib, bend(kernel.fg.end());
for (ib = kernel.fg.begin(); ib != bend; ++ib) {
G4_BB *bb = *ib;
int localInstNum = 0;
int localHalfInstNum = 0;
/**
* Traverse the instruction lists
*/
INST_LIST_ITER ii, iend(bb->end());
for (ii = bb->begin(); ii != iend; ++ii) {
/* do detailed encoding here */
G4_INST *inst = *ii;
G4_opcode opcode = inst->opcode();
if (opcode != G4_label) {
// reuse "BinInst" from BinaryEncoding.h which can be simplified
BinInst *bin = new (mem) BinInst();
setBinInst(inst, bin);
bin->DWords[0] = 0;
bin->DWords[1] = 0;
bin->DWords[2] = 0;
bin->DWords[3] = 0;
DoAllEncoding(inst);
if (inst->opcode() == G4_pseudo_fc_call ||
inst->opcode() == G4_pseudo_fc_ret) {
getBinInst(inst)->SetDontCompactFlag(true);
}
if (doCompaction()) {
getBinInst(inst)->SetMustCompactFlag(false);
getBinInst(inst)->SetDontCompactFlag(inst->isNoCompactedInst());
/**
* handling switch/case for gen6: jump table should not be compacted
*/
bool compacted;
{
TIME_SCOPE(ENCODE_COMPACTION);
compacted = BinaryEncodingBase::compactOneInstruction(inst);
}
if (compacted) {
inst->setCompacted();
}
}
binInstList.push_back(getBinInst(inst));
if (inst->opcode() >= G4_jmpi && inst->opcode() <= G4_join) {
if (!EncodeConditionalBranches(inst, globalHalfInstNum)) {
offsetVector.push_back(ForwardJmpOffset(inst, globalHalfInstNum));
}
}
}
BuildLabelMap(inst, localHalfInstNum, localInstNum, globalHalfInstNum,
globalInstNum);
} // for inst
} // for bb
kernel.setAsmCount(globalInstNum);
SetInstCounts((uint32_t)globalHalfInstNum);
for (auto x = offsetVector.begin(), vEnd = offsetVector.end(); x != vEnd;
x++) {
if (!EncodeConditionalBranches(x->inst, x->offset)) {
vISA_ASSERT(false, "invalid label!");
}
}
}