1 /*========================== begin_copyright_notice ============================
2 
3 Copyright (C) 2017-2021 Intel Corporation
4 
5 SPDX-License-Identifier: MIT
6 
7 ============================= end_copyright_notice ===========================*/
8 
9 #include "BinaryEncodingIGA.h"
10 #include "GTGPU_RT_ASM_Interface.h"
11 #include "iga/IGALibrary/api/igaEncoderWrapper.hpp"
12 #include "Timer.h"
13 #include "BuildIR.h"
14 #include "Common_ISA_framework.h"
15 
16 #include <map>
17 #include <utility>
18 
19 
20 using namespace iga;
21 using namespace vISA;
22 
23 // all the gunk related to extended send descriptors
24 struct SendExDescOpts {
25     SendDesc      exDesc;
26     int           xlen = -1;
27     InstOptSet    extraOpts;
28 };
29 
30 class BinaryEncodingIGA
31 {
32     int               IGAInstId = 0;
33     Mem_Manager&      mem;
34     G4_Kernel&        kernel;
35     std::string       fileName;
36     Kernel*      IGAKernel = nullptr;
37     const Model* platformModel;
38     const TARGET_PLATFORM   platform;
39 
40 public:
41     BinaryEncodingIGA(vISA::Mem_Manager &m, vISA::G4_Kernel& k, std::string fname);
~BinaryEncodingIGA()42     ~BinaryEncodingIGA() {delete IGAKernel;}
43 
44     void SetSWSB(G4_INST * inst, SWSB & sw);
45 
46     // translates and encodes (formerly "DoAll")
47     void Encode();
48 
49     ///////////////////////////////////////////////////////////////////////////
50     // these function translate G4 IR to IGA IR
51     Instruction *translateInstruction(G4_INST *g4inst, Block*& bbNew);
52     void translateInstructionDst(G4_INST *g4inst, Instruction *igaInst);
53     void translateInstructionBranchSrcs(G4_INST *g4inst, Instruction *igaInst, Block*& bbNew);
54     void translateInstructionSrcs(G4_INST *g4inst, Instruction *igaInst);
55 
56     void FixInst();
57     void *EmitBinary(size_t& binarySize);
58 
59 private:
60     BinaryEncodingIGA(const BinaryEncodingIGA& other);
61     BinaryEncodingIGA& operator=(const BinaryEncodingIGA& other);
62 
63     std::map<G4_Label*, Block*> labelToBlockMap;
64 
65 public:
66     static ExecSize       getIGAExecSize(int execSize);
67     static ChannelOffset  getIGAChannelOffset(int offset);
68     static MaskCtrl       getIGAMaskCtrl(bool noMask);
69     static RegName        getIGAARFName(G4_ArchRegKind areg);
70     static Type           getIGAType(G4_Type type, TARGET_PLATFORM genxPlatform);
71 
72     /// getIGAInternalPlatform - a helper function to transform visa platform to iga platform
73     static Platform       getIGAInternalPlatform(TARGET_PLATFORM genxPlatform);
74 
75     static std::pair<const OpSpec *,Subfunction> getIgaOpInfo(
76         const G4_INST *inst, const Model *m, bool allowUnknownOp, const IR_Builder& builder);
77 private:
78     static PredCtrl getIGAPredCtrl(G4_Predicate_Control g4PredCntrl);
79     static Predication getIGAPredication(G4_Predicate* predG4);
getIGABranchCntrl(bool isOn)80     static BranchCntrl getIGABranchCntrl(bool isOn)
81     {
82         return isOn ? BranchCntrl::ON : BranchCntrl::OFF;
83     }
getIGADstModifier(bool sat)84     static DstModifier getIGADstModifier(bool sat)
85     {
86         return sat ? DstModifier::SAT : DstModifier::NONE;
87     }
88     static SrcModifier   getIGASrcModifier(G4_SrcModifier srcMod);
89     static Region::Vert  getIGAVert(int vstride);
90     static Region::Width getIGAWidth(int width);
91     static Region::Horz  getIGAHorz(int hstride);
92     static Region        getIGARegion(G4_SrcRegRegion* srcRegion, int srcPos);
93 
getIGAImplAcc(G4_AccRegSel accSel) const94     MathMacroExt getIGAImplAcc(G4_AccRegSel accSel) const
95     {
96         switch (accSel)
97         {
98         case ACC2:      return MathMacroExt::MME0;
99         case ACC3:      return MathMacroExt::MME1;
100         case ACC4:      return MathMacroExt::MME2;
101         case ACC5:      return MathMacroExt::MME3;
102         case ACC6:      return MathMacroExt::MME4;
103         case ACC7:      return MathMacroExt::MME5;
104         case ACC8:      return MathMacroExt::MME6;
105         case ACC9:      return MathMacroExt::MME7;
106         case NOACC:     return MathMacroExt::NOMME;
107         default:
108             assert(false && "illegal acc (mme) channel select");
109             return MathMacroExt::INVALID;
110         }
111     }
getIGAImmType(G4_Type type)112     ImmVal::Kind getIGAImmType(G4_Type type)
113     {
114         switch (type)
115         {
116         case Type_UW:       return ImmVal::Kind::U16;
117         case Type_W:        return ImmVal::Kind::S16;
118         case Type_UD:       return ImmVal::Kind::U32;
119         case Type_D:        return ImmVal::Kind::S32;
120         case Type_UQ:       return ImmVal::Kind::U64;
121         case Type_Q:        return ImmVal::Kind::S64;
122         case Type_HF:       return ImmVal::Kind::F16;
123         case Type_F:        return ImmVal::Kind::F32;
124         case Type_DF:       return ImmVal::Kind::F64;
125         case Type_UV:
126         case Type_V:
127         case Type_VF:       return ImmVal::Kind::U32;
128         default:
129             assert(false && "invalid immediate type");
130             return ImmVal::Kind::UNDEF;
131         }
132     }
133     InstOptSet getIGAInstOptSet(G4_INST* inst) const;
134 
135     SendDesc getIGASendDesc(G4_INST* sendInst) const;
136     SendExDescOpts getIGASendExDesc(G4_INST* sendInst) const;
137     SendDesc encodeExDescImm(G4_INST* sendInst, SendExDescOpts &sdos) const;
138     SendDesc encodeExDescRegA0(G4_INST* sendInst, SendExDescOpts &sdos) const;
139 
getIGARegName(G4_Operand * opnd) const140     RegName getIGARegName(G4_Operand* opnd) const
141     {
142         G4_VarBase *base = opnd->getBase();
143         assert(base != nullptr && "base should not be null");
144         if (base->isRegVar())
145         {
146             G4_VarBase *phyReg = base->asRegVar()->getPhyReg();
147             return phyReg->isAreg() ? getIGAARFName(phyReg->asAreg()->getArchRegType()) : RegName::GRF_R;
148         }
149         else
150         {
151             return base->isAreg() ? getIGAARFName(base->asAreg()->getArchRegType()) : RegName::GRF_R;
152         }
153     }
getIGARegRef(G4_Operand * opnd) const154     RegRef getIGARegRef(G4_Operand* opnd) const
155     {
156         RegRef regRef;
157         G4_VarBase *base = opnd->getBase();
158         assert(base != nullptr && "base should not be null");
159         if (base->isGreg())
160         {
161             uint32_t byteAddress = opnd->getLinearizedStart();
162             regRef.regNum = byteAddress / numEltPerGRF<Type_UB>();
163             regRef.subRegNum =
164                 (byteAddress % numEltPerGRF<Type_UB>()) / opnd->getTypeSize();
165         }
166         else if (opnd->isSrcRegRegion())
167         {
168             bool valid, subvalid;
169             regRef.regNum = (uint8_t)opnd->asSrcRegRegion()->ExRegNum(valid);
170             regRef.subRegNum = (uint8_t)opnd->asSrcRegRegion()->ExSubRegNum(subvalid);
171         }
172         else
173         {
174             assert(opnd->isDstRegRegion() && "expect DstRegRegion");
175             bool valid, subvalid;
176             regRef.regNum = (uint8_t)opnd->asDstRegRegion()->ExRegNum(valid);
177             regRef.subRegNum = (uint8_t)opnd->asDstRegRegion()->ExSubRegNum(subvalid);
178         }
179         return regRef;
180     }
181 
lookupIGABlock(G4_Label * label,Kernel & IGAKernel)182     Block *lookupIGABlock(G4_Label* label, Kernel& IGAKernel)
183     {
184         Block *b = nullptr;
185         auto itr = labelToBlockMap.find(label);
186         if (itr == labelToBlockMap.end())
187         {
188             b = IGAKernel.createBlock();
189             labelToBlockMap[label] = b;
190         }
191         else {
192             b = itr->second;
193         }
194         return b;
195     }
196 
197     void getIGAFlagInfo(
198         G4_INST* inst,
199         const OpSpec* opSpec,
200         Subfunction sf,
201         Predication& pred,
202         FlagModifier& condMod,
203         RegRef& flagReg);
204 
getIGAFlagReg(G4_VarBase * g4Base) const205     RegRef getIGAFlagReg(G4_VarBase* g4Base) const
206     {
207         RegRef reg = REGREF_INVALID;
208         bool flagRegNumValid = true;
209         reg.regNum = (uint8_t)g4Base->ExRegNum(flagRegNumValid);
210         ASSERT_USER(flagRegNumValid, "Unable to retrieve flag Reg Num for predicate or conditional modifier.");
211         reg.subRegNum = (uint8_t)g4Base->asRegVar()->getPhyRegOff();
212         return reg;
213     }
214 
getIGAFlagModifier(G4_CondMod * cMod) const215     FlagModifier getIGAFlagModifier(G4_CondMod* cMod) const
216     {
217         if (cMod == nullptr)
218         {
219             return FlagModifier::NONE;
220         }
221 
222         G4_CondModifier mod = cMod->getMod();
223         switch (mod)
224         {
225         case Mod_z:     // fallthrough
226         case Mod_e:     return FlagModifier::EQ;
227         case Mod_nz:    // fallthrough
228         case Mod_ne:    return FlagModifier::NE;
229         case Mod_g:     return FlagModifier::GT;
230         case Mod_ge:    return FlagModifier::GE;
231         case Mod_l:     return FlagModifier::LT;
232         case Mod_le:    return FlagModifier::LE;
233         case Mod_o:     // fallthrough
234         case Mod_r:     return FlagModifier::OV;
235         case Mod_u:     return FlagModifier::UN;
236         default:
237             ASSERT_USER(false, "Invalid FlagModifier.");
238             return FlagModifier::NONE;
239         }
240     }
241 
242     // get IGA type from GenPrecision
getIGAPrecisionType(GenPrecision p) const243     Type getIGAPrecisionType(GenPrecision p) const
244     {
245         switch (p)
246         {
247         case GenPrecision::U1:   return Type::U1;
248         case GenPrecision::U2:   return Type::U2;
249         case GenPrecision::U4:   return Type::U4;
250         case GenPrecision::U8:   return Type::UB;
251         case GenPrecision::S2:   return Type::S2;
252         case GenPrecision::S4:   return Type::S4;
253         case GenPrecision::S8:   return Type::B;
254         case GenPrecision::FP16: return Type::HF;
255         case GenPrecision::BF16: return Type::BF;
256         case GenPrecision::BF8:  return Type::BF8;
257         case GenPrecision::TF32: return Type::TF32;
258         default:
259             assert(false && "illegal Operand Precision");
260             return Type::INVALID;
261         }
262     }
263 
getIGADpasType(G4_InstDpas * DpasInst,int SrcOprdIx) const264     Type getIGADpasType(G4_InstDpas* DpasInst, int SrcOprdIx) const
265     {
266         Type ty;
267         switch (SrcOprdIx) {
268         default:
269             MUST_BE_TRUE(false, "Invalid SrcOprdIx!");
270             break;
271         case 0:
272         {
273             G4_Operand* src0 = DpasInst->getSrc(0);
274             if (src0->isNullReg()) {
275                 ty = getIGAType(DpasInst->getDst()->getType(), platform);
276             }
277             else
278             {
279                 ty = getIGAType(src0->getType(), platform);
280             }
281             break;
282         }
283         case 1:
284             ty = getIGAPrecisionType(DpasInst->getSrc1Precision());
285             break;
286         case 2:
287             ty = getIGAPrecisionType(DpasInst->getSrc2Precision());
288             break;
289         }
290         return ty;
291     }
292 
getIGADpasRegRef(G4_InstDpas * DpasInst,int SrcOprdIx) const293     RegRef getIGADpasRegRef(G4_InstDpas* DpasInst, int SrcOprdIx) const
294     {
295         G4_Operand* src = DpasInst->getSrc(SrcOprdIx);
296         RegRef regref = getIGARegRef(src);
297         if (SrcOprdIx == 2) {
298             // By default, subRegNum is in terms of operand's type (D/UD for
299             // dpas's src1/2). IGA needs it to be in terms of precision type.
300             // Note that no need to do it for src1 as it must be grf-aligned!
301             assert((regref.subRegNum % 2) == 0 &&
302                 "Minimum alignemnt of dpas's src2 must be QW");
303             uint32_t bitOffsets = regref.subRegNum * src->getTypeSize() * 8;
304             uint32_t PBits = G4_InstDpas::GetPrecisionSizeInBits(DpasInst->getSrc2Precision());
305             regref.subRegNum = bitOffsets / PBits;
306         }
307         return regref;
308     }
309 
getBfnFC(const G4_INST * inst)310     static BfnFC getBfnFC(const G4_INST *inst)
311     {
312         uint8_t funcCtrl = inst->asBfnInst()->getBooleanFuncCtrl();
313         return BfnFC(funcCtrl);
314     }
315     static iga::SFID getSFID(const G4_INST* inst);
316     static MathFC getMathFC(const G4_INST *inst);
317     Type getIGAType(const G4_INST* I, Gen4_Operand_Number O, TARGET_PLATFORM P);
318 
319     void *m_kernelBuffer;
320     uint32_t m_kernelBufferSize;
321 }; // class BinaryEncodingIGA
322 
323 
getIGAInternalPlatform(TARGET_PLATFORM genxPlatform)324 Platform BinaryEncodingIGA::getIGAInternalPlatform(TARGET_PLATFORM genxPlatform)
325 {
326     Platform platform = Platform::INVALID;
327     switch (genxPlatform)
328     {
329     case GENX_BDW:
330         platform = Platform::GEN8;
331         break;
332     case GENX_CHV:
333         platform = Platform::GEN8;
334         break;
335     case GENX_SKL:
336     case GENX_BXT:
337         platform = Platform::GEN9;
338         break;
339     case GENX_ICLLP:
340         platform = Platform::GEN11;
341         break;
342     case GENX_TGLLP:
343         platform = Platform::XE;
344         break;
345     case XeHP_SDV:
346         platform = Platform::XE_HP;
347         break;
348     case GENX_DG2:
349         platform = Platform::XE_HPG;
350         break;
351     case GENX_PVC:
352         platform = Platform::XE_HPC;
353         break;
354     case GENX_PVCXT:
355         platform = Platform::XE_HPC;
356         break;
357     default:
358         break;
359     }
360 
361     return platform;
362 }
363 
BinaryEncodingIGA(vISA::Mem_Manager & m,vISA::G4_Kernel & k,std::string fname)364 BinaryEncodingIGA::BinaryEncodingIGA(
365     vISA::Mem_Manager &m,
366     vISA::G4_Kernel& k,
367     std::string fname)
368     : mem(m), kernel(k), fileName(fname), m_kernelBuffer(nullptr),
369     m_kernelBufferSize(0), platform(k.fg.builder->getPlatform())
370 {
371     platformModel = Model::LookupModel(getIGAInternalPlatform(getGenxPlatform()));
372     IGAKernel = new Kernel(*platformModel);
373 }
374 
getIGAInstOptSet(G4_INST * inst) const375 InstOptSet BinaryEncodingIGA::getIGAInstOptSet(G4_INST* inst) const
376 {
377     InstOptSet options;
378 
379     if (inst->isAccWrCtrlInst() && kernel.fg.builder->encodeAccWrEn())
380     {
381         options.add(InstOpt::ACCWREN);
382     }
383     if (inst->isAtomicInst())
384     {
385         options.add(InstOpt::ATOMIC);
386     }
387     if (inst->isBreakPointInst())
388     {
389         options.add(InstOpt::BREAKPOINT);
390     }
391     if (inst->isNoDDChkInst())
392     {
393         options.add(InstOpt::NODDCHK);
394     }
395     if (inst->isNoDDClrInst())
396     {
397         options.add(InstOpt::NODDCLR);
398     }
399     if (inst->isNoPreemptInst())
400     {
401         options.add(InstOpt::NOPREEMPT);
402     }
403     if (inst->isYieldInst())
404     {
405         options.add(InstOpt::SWITCH);
406     }
407     if (inst->isSend())
408     {
409         if (inst->isEOT())
410         {
411             options.add(InstOpt::EOT);
412         }
413         if (inst->isNoSrcDepSet())
414         {
415             options.add(InstOpt::NOSRCDEPSET);
416         }
417         if (inst->asSendInst()->isSerializedInst())
418         {
419             options.add(InstOpt::SERIALIZE);
420         }
421     }
422 
423     // Force instruction to be compacted if InstOpt::COMPACTED is given
424     // even if autoCompact is not given to IGA
425     if (inst->isCompactedInst())
426     {
427         options.add(InstOpt::COMPACTED);
428     }
429 
430     // Force instruction to be nocompacted
431     if (inst->isNoCompactedInst())
432     {
433         options.add(InstOpt::NOCOMPACT);
434     }
435 
436     return options;
437 }
438 
439 
FixInst()440 void BinaryEncodingIGA::FixInst()
441 {
442     for (auto bb : kernel.fg)
443     {
444         for (auto iter = bb->begin(); iter != bb->end();)
445         {
446             G4_INST* inst = *iter;
447             if (inst->isIntrinsic())
448             {
449                 // WA for simulation:  remove any intrinsics that should be lowered before binary encoding
450                 MUST_BE_TRUE(inst->asIntrinsicInst()->getLoweredByPhase() == Phase::BinaryEncoding,
451                     "Unexpected intrinsics in binary encoding");
452                 iter = bb->erase(iter);
453             }
454             else
455             {
456                 ++iter;
457             }
458         }
459     }
460 }
461 
getSFID(const G4_INST * inst)462 iga::SFID BinaryEncodingIGA::getSFID(const G4_INST *inst)
463 {
464     ASSERT_USER(inst->isSend(), "Only send has SFID");
465 
466     G4_SendDesc *msgDesc = inst->getMsgDesc();
467     auto funcID = msgDesc->getSFID();
468 
469     auto sfid = iga::SFID::INVALID;
470     switch (funcID)
471     {
472     case vISA::SFID::NULL_SFID: sfid = iga::SFID::NULL_; break;
473     case vISA::SFID::SAMPLER:   sfid = iga::SFID::SMPL; break;
474     case vISA::SFID::GATEWAY:   sfid = iga::SFID::GTWY; break;
475     case vISA::SFID::DP_DC2:    sfid = iga::SFID::DC2; break;
476     case vISA::SFID::DP_WRITE:  sfid = iga::SFID::RC; break;
477     case vISA::SFID::URB:       sfid = iga::SFID::URB; break;
478     case vISA::SFID::SPAWNER:   sfid = iga::SFID::TS; break;
479     case vISA::SFID::VME:       sfid = iga::SFID::VME; break;
480     case vISA::SFID::DP_CC:     sfid = iga::SFID::DCRO; break;
481     case vISA::SFID::DP_DC0:    sfid = iga::SFID::DC0; break;
482     case vISA::SFID::DP_PI:     sfid = iga::SFID::PIXI; break;
483     case vISA::SFID::DP_DC1:    sfid = iga::SFID::DC1; break;
484     case vISA::SFID::CRE:       sfid = iga::SFID::CRE; break;
485     case vISA::SFID::SLM:       sfid = iga::SFID::SLM; break;
486     case vISA::SFID::UGM:       sfid = iga::SFID::UGM; break;
487     case vISA::SFID::BTD:       sfid = iga::SFID::BTD; break;
488     case vISA::SFID::RTHW:      sfid = iga::SFID::RTA; break;
489     case vISA::SFID::TGM:       sfid = iga::SFID::TGM; break;
490     case vISA::SFID::UGML:      sfid = iga::SFID::UGML; break;
491     default:
492         ASSERT_USER(false, "Unknow SFID generated from vISA");
493         break;
494     }
495 
496     return sfid;
497 }
getMathFC(const G4_INST * inst)498 MathFC BinaryEncodingIGA::getMathFC(const G4_INST *inst)
499 {
500     G4_MathOp mathControlValue = inst->asMathInst()->getMathCtrl();
501 
502     switch (mathControlValue)
503     {
504     case MATH_INV:          return MathFC::INV;
505     case MATH_LOG:          return MathFC::LOG;
506     case MATH_EXP:          return MathFC::EXP;
507     case MATH_SQRT:         return MathFC::SQT;
508     case MATH_RSQ:          return MathFC::RSQT;
509     case MATH_SIN:          return MathFC::SIN;
510     case MATH_COS:          return MathFC::COS;
511     case MATH_FDIV:         return MathFC::FDIV;
512     case MATH_POW:          return MathFC::POW;
513     case MATH_INT_DIV:      return MathFC::IDIV;
514     case MATH_INT_DIV_QUOT: return MathFC::IQOT;
515     case MATH_INT_DIV_REM:  return MathFC::IREM;
516     case MATH_INVM:         return MathFC::INVM;
517     case MATH_RSQRTM:       return MathFC::RSQTM;
518     default:
519         ASSERT_USER(false, "invalid math subfunction");
520         return MathFC::INVALID;
521     }
522 }
523 
524 
525 //
526 // Return the IGA op for the given vISA instruction <op> for platform p.
527 // <inst> is sometimes necessary to compute the subopcode (e.g., send)
528 // As vISA may call this function to access instruction properties such as
529 // saturation and conditional modifier and this may happen before all pseudo
530 // opperations are lowered, <allowUnknownOp> may be used to suppress assert;
531 // an invalid will be returned in this case.
532 //
getIgaOpInfo(const G4_INST * inst,const Model * m,bool allowUnknownOp,const IR_Builder & builder)533 std::pair<const OpSpec *,Subfunction> BinaryEncodingIGA::getIgaOpInfo(
534     const G4_INST *inst, const Model *m, bool allowUnknownOp, const IR_Builder& builder)
535 {
536     Platform p = m->platform;
537     Op igaOp = Op::INVALID;
538     Subfunction sf = InvalidFC::INVALID;
539     switch (inst->opcode())
540     {
541     case G4_illegal: igaOp = Op::ILLEGAL; break;
542     case G4_mov:     igaOp = Op::MOV; break;
543     case G4_sel:     igaOp = Op::SEL; break;
544     case G4_movi:    igaOp = Op::MOVI; break;
545     case G4_not:     igaOp = Op::NOT; break;
546     case G4_and:     igaOp = Op::AND; break;
547     case G4_or:      igaOp = Op::OR; break;
548     case G4_xor:     igaOp = Op::XOR; break;
549     case G4_shr:     igaOp = Op::SHR; break;
550     case G4_shl:     igaOp = Op::SHL; break;
551     case G4_smov:    igaOp = Op::SMOV; break;
552     case G4_asr:     igaOp = Op::ASR; break;
553     case G4_ror:     igaOp = Op::ROR; break;
554     case G4_rol:     igaOp = Op::ROL; break;
555     case G4_cmp:     igaOp = Op::CMP; break;
556     case G4_cmpn:    igaOp = Op::CMPN; break;
557     case G4_csel:    igaOp = Op::CSEL; break;
558     case G4_bfrev:   igaOp = Op::BFREV; break;
559     case G4_bfe:     igaOp = Op::BFE; break;
560     case G4_bfi1:    igaOp = Op::BFI1; break;
561     case G4_bfi2:    igaOp = Op::BFI2; break;
562     case G4_jmpi:    igaOp = Op::JMPI; break;
563     case G4_brd:     igaOp = Op::BRD; break;
564     case G4_if:      igaOp = Op::IF; break;
565     case G4_brc:     igaOp = Op::BRC; break;
566     case G4_else:    igaOp = Op::ELSE; break;
567     case G4_endif:   igaOp = Op::ENDIF; break;
568     case G4_while:   igaOp = Op::WHILE; break;
569     case G4_break:   igaOp = Op::BREAK; break;
570     case G4_cont:    igaOp = Op::CONT; break;
571     case G4_halt:    igaOp = Op::HALT; break;
572     case G4_call:
573     {
574         igaOp = Op::CALL;
575         // check if we're using calla for indirect call
576         if (builder.supportCallaRegSrc()) {
577             // check if we're doing indiret call
578             if (inst->getSrc(0)->isGreg() || inst->getSrc(0)->isA0())
579                 igaOp = Op::CALLA;
580         }
581         break;
582     }
583     case G4_return:  igaOp = Op::RET; break;
584     case G4_goto:    igaOp = Op::GOTO; break;
585     case G4_join:    igaOp = Op::JOIN; break;
586     case G4_wait:
587         if (p >= Platform::XE)
588         {
589             igaOp = Op::SYNC;
590             sf = SyncFC::BAR;
591         }
592         else
593         {
594             igaOp = Op::WAIT;
595         }
596         break;
597     case G4_send:
598         igaOp = Op::SEND;
599         sf = getSFID(inst);
600         break;
601     case G4_sendc:
602         igaOp = Op::SENDC;
603         sf = getSFID(inst);
604         break;
605     case G4_sends:
606         sf = getSFID(inst);
607         if (p >= Platform::XE) {
608             // G4 IR still calls send sends after Xe
609             igaOp = Op::SEND;
610         } else {
611             igaOp = Op::SENDS;
612         }
613         break;
614     case G4_sendsc:
615         sf = getSFID(inst);
616         if (p >= Platform::XE) {
617             // G4 IR still calls send sends after Xe
618             igaOp = Op::SENDC;
619         } else {
620             igaOp = Op::SENDSC;
621         }
622         break;
623     case G4_math:
624         sf = getMathFC(inst);
625         igaOp = Op::MATH;
626         break;
627     case G4_add:     igaOp = Op::ADD; break;
628     case G4_mul:     igaOp = Op::MUL; break;
629     case G4_avg:     igaOp = Op::AVG; break;
630     case G4_frc:     igaOp = Op::FRC; break;
631     case G4_rndu:    igaOp = Op::RNDU; break;
632     case G4_rndd:    igaOp = Op::RNDD; break;
633     case G4_rnde:    igaOp = Op::RNDE; break;
634     case G4_rndz:    igaOp = Op::RNDZ; break;
635     case G4_mac:     igaOp = Op::MAC; break;
636     case G4_mach:
637         igaOp = Op::MACH;
638         if (inst->getPlatform() >= GENX_PVC && !inst->isAccWrCtrlInst())
639         {
640             igaOp = Op::MACL;
641         }
642         break;
643     case G4_lzd:     igaOp = Op::LZD; break;
644     case G4_fbh:     igaOp = Op::FBH; break;
645     case G4_fbl:     igaOp = Op::FBL; break;
646     case G4_cbit:    igaOp = Op::CBIT; break;
647     case G4_addc:    igaOp = Op::ADDC; break;
648     case G4_subb:    igaOp = Op::SUBB; break;
649     case G4_sad2:    igaOp = Op::SAD2; break;
650     case G4_sada2:   igaOp = Op::SADA2; break;
651     case G4_dp4:     igaOp = Op::DP4; break;
652     case G4_dph:     igaOp = Op::DPH; break;
653     case G4_dp3:     igaOp = Op::DP3; break;
654     case G4_dp2:     igaOp = Op::DP2; break;
655     case G4_dp4a:    igaOp = Op::DP4A; break;
656     case G4_dpas:
657     case G4_dpasw:
658     {
659         igaOp = inst->opcode() == G4_dpasw ? Op::DPASW : Op::DPAS;
660         G4_InstDpas* dpasInst = inst->asDpasInst();
661         uint8_t D = dpasInst->getSystolicDepth();
662         uint8_t C = dpasInst->getRepeatCount();
663         sf = GetDpasFC(D, C);
664         break;
665     }
666     case G4_add3:    igaOp = Op::ADD3; break;
667     case G4_bfn:
668         igaOp = Op::BFN;
669         sf = getBfnFC(inst);
670         break;
671     case G4_line:    igaOp = Op::LINE; break;
672     case G4_pln:     igaOp = Op::PLN; break;
673     case G4_mad:     igaOp = Op::MAD; break;
674     case G4_lrp:     igaOp = Op::LRP; break;
675     case G4_madm:    igaOp = Op::MADM; break;
676     case G4_nop:     igaOp = Op::NOP; break;
677     case G4_label:
678         break;
679     case G4_pseudo_mad: igaOp = Op::MAD; break;
680     case G4_do:
681         ASSERT_USER(!allowUnknownOp, "G4_do is not GEN ISA OPCODE.");
682         break;
683     case G4_pseudo_and:   igaOp = Op::AND; break;
684     case G4_pseudo_or:    igaOp = Op::OR; break;
685     case G4_pseudo_xor:   igaOp = Op::XOR; break;
686     case G4_pseudo_not:   igaOp = Op::NOT; break;
687     case G4_pseudo_fcall: igaOp = Op::CALL; break;
688     case G4_pseudo_fret:  igaOp = Op::RET; break;
689     case G4_pseudo_sada2: igaOp = Op::SADA2; break;
690     case G4_pseudo_exit:
691         ASSERT_USER(!allowUnknownOp, "G4_pseudo_exit not GEN ISA OPCODE.");
692         break;
693     case G4_pseudo_fc_call: igaOp = Op::CALL; break;
694     case G4_pseudo_fc_ret:  igaOp = Op::RET; break;
695     case G4_intrinsic:
696         ASSERT_USER(!allowUnknownOp, "G4_intrinsic not GEN ISA OPCODE.");
697         break;
698     case G4_sync_nop:
699         igaOp = Op::SYNC;
700         sf = SyncFC::NOP;
701         break;
702     case G4_sync_allrd:
703         igaOp = Op::SYNC;
704         sf = SyncFC::ALLRD;
705         break;
706     case G4_sync_allwr:
707         igaOp = Op::SYNC;
708         sf = SyncFC::ALLWR;
709         break;
710     case G4_sync_fence:
711         igaOp = Op::SYNC;
712         sf = SyncFC::FENCE;
713         break;
714     case G4_fcvt:
715         igaOp = Op::MOV;
716         break;
717     case G4_srnd:  igaOp = Op::SRND; break;
718     case G4_NUM_OPCODE:
719         assert(false);
720         break;
721     case G4_mulh:
722         ASSERT_USER(!allowUnknownOp, "G4_mulh is not GEN ISA OPCODE.");
723         break;
724     case G4_madw:
725         ASSERT_USER(!allowUnknownOp, "G4_madw not GEN ISA OPCODE.");
726         break;
727     default:
728         ASSERT_USER(!allowUnknownOp, "INVALID opcode.");
729         break;
730     }
731     const OpSpec *os = &m->lookupOpSpec(igaOp);
732     return std::pair<const OpSpec *,Subfunction>(os, sf);
733 }
734 
SetSWSB(G4_INST * inst,SWSB & sw)735 void BinaryEncodingIGA::SetSWSB(G4_INST *inst, SWSB &sw)
736 {
737     // Set token, e.g. $0
738     using SWSBTokenType = vISA::G4_INST::SWSBTokenType;
739     if (inst->tokenHonourInstruction() && (inst->getTokenType() == SWSBTokenType::SB_SET))
740     {
741         sw.tokenType = SWSB::TokenType::SET;
742         sw.sbid = inst->getToken();
743     }
744 
745     if (inst->opcode() == G4_mad && inst->hasNoACCSBSet())
746     {
747         sw.spToken = SWSB::SpecialToken::NOACCSBSET;
748     }
749     // Set distance, e.g. A@1
750     using DistanceType = vISA::G4_INST::DistanceType;
751     if ((unsigned)inst->getDistance())
752     {
753         // check the distance type for multi-dist-pipes
754         if (kernel.fg.builder->hasThreeALUPipes() ||
755             kernel.fg.builder->hasFourALUPipes()) {
756             switch (inst->getDistanceTypeXe())
757             {
758             case DistanceType::DIST:
759                 sw.distType = SWSB::DistType::REG_DIST;
760                 break;
761             case DistanceType::DISTALL:
762                 sw.distType = SWSB::DistType::REG_DIST_ALL;
763                 break;
764             case DistanceType::DISTINT:
765                 sw.distType = SWSB::DistType::REG_DIST_INT;
766                 break;
767             case DistanceType::DISTFLOAT:
768                 sw.distType = SWSB::DistType::REG_DIST_FLOAT;
769                 break;
770             case DistanceType::DISTLONG:
771                 sw.distType = SWSB::DistType::REG_DIST_LONG;
772                 break;
773             case DistanceType::DISTMATH:
774                 sw.distType = SWSB::DistType::REG_DIST_MATH;
775                 break;
776             default:
777                 break;
778             }
779         }
780         else
781         {
782             // there is only one pipe on single-dist-pipe platform,
783             // must be REG_DIST
784             sw.distType = SWSB::DistType::REG_DIST;
785         }
786         sw.minDist = (uint32_t)inst->getDistance();
787     }
788 
789     // Set token dependency, e.g. $1.src
790     if (inst->getTokenType() == SWSBTokenType::AFTER_READ ||
791         inst->getTokenType() == SWSBTokenType::AFTER_WRITE)
792     {
793         uint8_t token = (uint8_t)inst->getToken();
794         if (inst->getTokenType() == SWSBTokenType::AFTER_READ)
795         {
796             sw.tokenType = SWSB::TokenType::SRC;
797         }
798         else if (inst->getTokenType() == SWSBTokenType::AFTER_WRITE)
799         {
800             sw.tokenType = SWSB::TokenType::DST;
801         }
802         sw.sbid = token;
803     }
804     return;
805 }
806 
getIGAFlagInfo(G4_INST * inst,const OpSpec * opSpec,Subfunction sf,Predication & pred,FlagModifier & condMod,RegRef & flagReg)807 void BinaryEncodingIGA::getIGAFlagInfo(
808     G4_INST* inst,
809     const OpSpec* opSpec,
810     Subfunction sf,
811     Predication& pred,
812     FlagModifier& condMod,
813     RegRef& flagReg)
814 {
815     G4_Predicate* predG4 = inst->getPredicate();
816     G4_CondMod* condModG4 = inst->getCondMod();
817     RegRef predFlag;
818     bool hasPredFlag = false;
819 
820     if (opSpec->supportsPredication() && predG4 != nullptr)
821     {
822         pred = getIGAPredication(predG4);
823         predFlag = getIGAFlagReg(predG4->getBase());
824         flagReg = predFlag;
825         hasPredFlag = true;
826     }
827 
828     bool hasImplicitModifier =
829         opSpec->is(Op::MATH) && IsMacro(sf.math);
830 
831     if ((opSpec->supportsFlagModifier() || hasImplicitModifier) &&
832         condModG4 != nullptr)
833     {
834         condMod = getIGAFlagModifier(condModG4);
835         // in case for min/max sel instruction, it could have CondMod but has no flag registers
836         if (condModG4->getBase() != nullptr) {
837             flagReg = getIGAFlagReg(condModG4->getBase());
838             // pred and condMod Flags must be the same
839             assert(!hasPredFlag || predFlag == flagReg);
840         }
841     }
842 }
843 
844 #if 0
845 static void DebugCaching(G4_Kernel &kernel)
846 {
847     std::map<uint32_t,std::pair<Caching,Caching>> descs;
848     for (auto bb : kernel.fg) {
849         for (auto inst : *bb)
850         {
851             if (inst->isSend()) {
852                 G4_SendDescRaw *sd = inst->getMsgDescRaw();
853                 if (sd) {
854                     descs[sd->getDesc()] = sd->getCaching();
855                 }
856             }
857         }
858     }
859     for (const auto &p : descs) {
860         std::cerr << std::hex << "0x" << p.first <<
861             " ===>"
862             "  L1=" << std::dec << int(p.second.first) <<
863             "  L3=" << std::dec << int(p.second.second) <<
864             "\n";
865     }
866 }
867 #endif
868 
Encode()869 void BinaryEncodingIGA::Encode()
870 {
871     // DebugCaching(this->kernel);
872 
873     FixInst();
874     Block* currBB = nullptr;
875 
876     auto isFirstInstLabel = [this]()
877     {
878         for (auto bb : kernel.fg)
879         {
880             for (auto inst : *bb)
881             {
882                 return inst->isLabel();
883             }
884         }
885         return false;
886     };
887 
888     // Make the size of the first BB be multiple of 4 instructions, and do not compact
889     // any instructions in it, so that the size of the first BB is multiple of 64 bytes
890     if (kernel.hasPerThreadPayloadBB() || kernel.hasComputeFFIDProlog())
891     {
892         G4_BB* first_bb = *kernel.fg.begin();
893         size_t num_inst = first_bb->size();
894         assert(num_inst != 0 && "the first BB must not be empty");
895         // label instructions don't count. Only the first instruction could be a label
896         if (first_bb->front()->isLabel())
897             --num_inst;
898 
899         if (num_inst % 4 != 0) {
900             size_t num_nop = 4 - (num_inst % 4);
901             for (size_t i = 0; i < num_nop; ++i)
902                 first_bb->push_back(
903                     kernel.fg.builder->createNop(InstOpt_NoCompact));
904         }
905         // set all instruction to be NoCompact
906         for (auto inst : *first_bb)
907         {
908             inst->setOptionOn(InstOpt_NoCompact);
909         }
910     }
911 
912     if (!isFirstInstLabel())
913     {
914         // create a new BB if kernel does not start with label
915         currBB = IGAKernel->createBlock();
916         IGAKernel->appendBlock(currBB);
917     }
918 
919     std::list<std::pair<Instruction*, G4_INST*>> encodedInsts;
920     Block *bbNew = nullptr;
921     for (auto bb : this->kernel.fg)
922     {
923         for (auto inst : *bb)
924         {
925             bbNew = nullptr;
926             if (inst->isLabel())
927             {
928                 // note that we create a new IGA BB per label instead of directly mapping vISA BB to IGA BB,
929                 // as some vISA BBs can have multiple labels (e.g., multiple endifs)
930                 G4_Label* label = inst->getLabel();
931                 currBB = lookupIGABlock(label, *IGAKernel);
932                 IGAKernel->appendBlock(currBB);
933                 continue;
934             }
935 
936             Instruction *igaInst = translateInstruction(inst, bbNew);
937             if (!igaInst) {
938                 // assertion failure already reported
939                 continue;
940             }
941 
942             igaInst->addInstOpts(getIGAInstOptSet(inst));
943 
944             if (getPlatformGeneration(platform) >= PlatformGen::XE) {
945                 SWSB sw;
946                 SetSWSB(inst, sw);
947 
948                 SWSB::InstType instTy = SWSB::InstType::UNKNOWN;
949                 if (inst->isMathPipeInst())
950                     instTy = SWSB::InstType::MATH;
951                 else if (inst->isDpas())
952                     instTy = SWSB::InstType::DPAS;
953                 else if (inst->isSend())
954                     instTy = SWSB::InstType::SEND;
955                 else
956                     instTy = SWSB::InstType::OTHERS;
957 
958                 // Verify if swsb is in encode-able dist and token combination
959                 if (!sw.verify(GetIGASWSBEncodeMode(*kernel.fg.builder), instTy))
960                     IGA_ASSERT_FALSE("Invalid swsb dist and token combination");
961                 igaInst->setSWSB(sw);
962             }
963 
964 #if _DEBUG
965             igaInst->validate();
966 #endif
967             currBB->appendInstruction(igaInst);
968 
969             if (bbNew)
970             {
971                 // Fall through block is created.
972                 // So the new block needs to become current block
973                 // so that jump offsets can be calculated correctly
974                 currBB = bbNew;
975             }
976             // If, in future, we generate multiple binary inst
977             // for a single G4_INST, then it should be safe to
978             // make pair between the G4_INST and first encoded
979             // binary inst.
980             encodedInsts.push_back(std::make_pair(igaInst, inst));
981         }
982     }
983 
984     kernel.setAsmCount(IGAInstId);
985 
986     if (m_kernelBuffer)
987     {
988         m_kernelBufferSize = 0;
989         delete static_cast<uint8_t*>(m_kernelBuffer);
990         m_kernelBuffer = nullptr;
991     }
992 
993 
994     { // time the encoding
995         TIME_SCOPE(IGA_ENCODER);
996         bool autoCompact = kernel.getOption(vISA_Compaction);
997         if (platform == GENX_PVC)
998             autoCompact = false; // PVC-A0 compaction is off (IGA only does B0+)
999 
1000         KernelEncoder encoder(IGAKernel, autoCompact);
1001         encoder.setSWSBEncodingMode(GetIGASWSBEncodeMode(*kernel.fg.builder));
1002 
1003         if (kernel.getOption(vISA_EnableIGASWSB))
1004         {
1005             encoder.enableIGAAutoDeps();
1006         }
1007 
1008         encoder.encode();
1009 
1010         m_kernelBufferSize = encoder.getBinarySize();
1011         m_kernelBuffer = allocCodeBlock(m_kernelBufferSize);
1012         memcpy_s(m_kernelBuffer, m_kernelBufferSize, encoder.getBinary(), m_kernelBufferSize);
1013     }
1014 
1015     // encodedPC is available after encoding
1016     for (auto&& inst : encodedInsts)
1017     {
1018         inst.second->setGenOffset(inst.first->getPC());
1019     }
1020     if (kernel.hasPerThreadPayloadBB())
1021     {
1022         kernel.fg.builder->getJitInfo()->offsetToSkipPerThreadDataLoad =
1023             kernel.getPerThreadNextOff();
1024     }
1025     if (kernel.hasCrossThreadPayloadBB())
1026     {
1027         kernel.fg.builder->getJitInfo()->offsetToSkipCrossThreadDataLoad =
1028             kernel.getCrossThreadNextOff();
1029     }
1030     if (kernel.hasComputeFFIDProlog())
1031     {
1032         // something weird will happen if kernel has both PerThreadProlog and ComputeFFIDProlog
1033         assert(!kernel.hasPerThreadPayloadBB() && !kernel.hasCrossThreadPayloadBB());
1034         kernel.fg.builder->getJitInfo()->offsetToSkipSetFFIDGP =
1035             kernel.getComputeFFIDGPNextOff();
1036         kernel.fg.builder->getJitInfo()->offsetToSkipSetFFIDGP1 =
1037             kernel.getComputeFFIDGP1NextOff();
1038     }
1039 }
1040 
translateInstruction(G4_INST * g4inst,Block * & bbNew)1041 Instruction *BinaryEncodingIGA::translateInstruction(
1042     G4_INST *g4inst, Block*& bbNew)
1043 {
1044     Instruction *igaInst = nullptr;
1045     auto opinfo = getIgaOpInfo(g4inst, platformModel, false, *kernel.fg.builder);
1046     // common fields: op, predicate, flag reg, exec size, exec mask offset,
1047     // mask ctrl, conditional modifier
1048     const OpSpec* opSpec = opinfo.first;
1049     if (opSpec == nullptr || !opSpec->isValid())
1050     {
1051         std::cerr << "INVALID opcode " << G4_Inst_Table[g4inst->opcode()].str << "\n";
1052         ASSERT_USER(false, "INVALID OPCODE.");
1053         return nullptr;
1054     }
1055     Op igaOp = opSpec->op;
1056     Subfunction sf = opinfo.second;
1057     Predication pred;
1058     RegRef flagReg {0, 0};
1059     ExecSize execSize = getIGAExecSize(g4inst->getExecSize());
1060     ChannelOffset chOff = getIGAChannelOffset(g4inst->getMaskOffset());
1061     MaskCtrl maskCtrl =
1062         getIGAMaskCtrl(g4inst->opcode() == G4_jmpi || g4inst->isWriteEnableInst());
1063     FlagModifier condModifier = FlagModifier::NONE;
1064 
1065     getIGAFlagInfo(g4inst, opSpec, sf, pred, condModifier, flagReg);
1066 
1067     if (opSpec->isBranching())
1068     {
1069         BranchCntrl brnchCtrl = getIGABranchCntrl(g4inst->asCFInst()->isBackward());
1070         igaInst = IGAKernel->createBranchInstruction(
1071             *opSpec,
1072             pred,
1073             flagReg,
1074             execSize,
1075             chOff,
1076             maskCtrl,
1077             brnchCtrl);
1078     }
1079     else if (opSpec->isSendOrSendsFamily())
1080     {
1081         SendDesc desc = getIGASendDesc(g4inst);
1082         SendExDescOpts sdos = getIGASendExDesc(g4inst);
1083         igaInst =
1084             IGAKernel->createSendInstruction(
1085                 *opSpec,
1086                 sf.send,
1087                 pred,
1088                 flagReg,
1089                 execSize,
1090                 chOff,
1091                 maskCtrl,
1092                 sdos.exDesc,
1093                 desc);
1094 
1095         ASSERT_USER(igaInst, "Instruction is NULL");
1096         if (!igaInst) {
1097             return nullptr;
1098         }
1099 
1100         igaInst->setSrc1Length(sdos.xlen);
1101         igaInst->addInstOpts(sdos.extraOpts);
1102     }
1103     else if (opSpec->op == Op::NOP)
1104     {
1105         igaInst = IGAKernel->createNopInstruction();
1106     }
1107     else if (opSpec->op == Op::ILLEGAL)
1108     {
1109         igaInst = IGAKernel->createIllegalInstruction();
1110     }
1111     else
1112     {
1113         igaInst =
1114             IGAKernel->createBasicInstruction(
1115                 *opSpec,
1116                 pred,
1117                 flagReg,
1118                 execSize,
1119                 chOff,
1120                 maskCtrl,
1121                 condModifier,
1122                 sf);
1123     }
1124 
1125     ASSERT_USER(igaInst, "Instruction is NULL");
1126     if (!igaInst) {
1127         // only on asserts; this should only happen if memory allocation
1128         // fails for some reason
1129         return nullptr;
1130     }
1131 
1132     igaInst->setID(IGAInstId++);
1133     igaInst->setLoc(g4inst->getCISAOff()); // make IGA src off track CISA id
1134 
1135     if (opSpec->supportsDestination())
1136     {
1137         translateInstructionDst(g4inst, igaInst);
1138     }
1139 
1140     if (opSpec->isBranching() &&
1141         igaOp != Op::JMPI &&
1142         igaOp != Op::RET &&
1143         igaOp != Op::CALL &&
1144         igaOp != Op::CALLA &&
1145         igaOp != Op::BRC &&
1146         igaOp != Op::BRD)
1147     {
1148         translateInstructionBranchSrcs(g4inst, igaInst, bbNew);
1149     }
1150     else
1151     {
1152         translateInstructionSrcs(g4inst, igaInst);
1153     }
1154 
1155     return igaInst;
1156 }
1157 
translateInstructionDst(G4_INST * g4inst,Instruction * igaInst)1158 void BinaryEncodingIGA::translateInstructionDst(
1159     G4_INST *g4inst, Instruction *igaInst)
1160 {
1161     assert(g4inst->getDst() && "dst must not be null");
1162     G4_DstRegRegion* dst = g4inst->getDst();
1163     DstModifier dstModifier = getIGADstModifier(g4inst->getSaturate());
1164     Region::Horz hstride = getIGAHorz(dst->getHorzStride());
1165     Type type = getIGAType(g4inst, Opnd_dst, platform);
1166 
1167     // workaround for SKL bug
1168     // not all bits are copied from immediate descriptor
1169     if (g4inst->isSend() && platform >= GENX_SKL && platform < GENX_ICLLP)
1170     {
1171         const G4_SendDescRaw* msgDesc = g4inst->getMsgDescRaw();
1172         assert(msgDesc && "expected raw descriptor");
1173         G4_Operand* descOpnd = g4inst->isSplitSend() ?
1174             g4inst->getSrc(2) : g4inst->getSrc(1);
1175         if (!descOpnd->isImm() && msgDesc->is16BitReturn())
1176         {
1177             type = Type::HF;
1178         }
1179     }
1180 
1181     if (igaInst->isMacro())
1182     {
1183         RegRef regRef = getIGARegRef(dst);
1184         Region::Horz hstride = getIGAHorz(dst->getHorzStride());
1185         igaInst->setMacroDestination(
1186             dstModifier,
1187             getIGARegName(dst),
1188             regRef,
1189             getIGAImplAcc(dst->getAccRegSel()),
1190             hstride,
1191             type);
1192     }
1193     else if (dst->getRegAccess() == Direct)
1194     {
1195         igaInst->setDirectDestination(
1196             dstModifier,
1197             getIGARegName(dst),
1198             getIGARegRef(dst),
1199             hstride,
1200             type);
1201     }
1202     else
1203     { // Operand::Kind::INDIRECT
1204         RegRef regRef {0, 0};
1205         bool valid;
1206         regRef.subRegNum = (uint8_t)dst->ExIndSubRegNum(valid);
1207         igaInst->setInidirectDestination(
1208             dstModifier,
1209             regRef,
1210             dst->getAddrImm(),
1211             hstride,
1212             type);
1213     }
1214 }
1215 
translateInstructionBranchSrcs(G4_INST * inst,Instruction * igaInst,Block * & bbNew)1216 void BinaryEncodingIGA::translateInstructionBranchSrcs(
1217     G4_INST *inst, Instruction *igaInst, Block*& bbNew)
1218 {
1219     if (inst->asCFInst()->getJip())
1220     {
1221         // encode jip/uip for branch inst
1222         // note that it does not apply to jmpi/call/ret/brc/brd,
1223         // which may have register sources. Their label appears directly as
1224         // source operand instead.
1225         G4_Operand* uip = inst->asCFInst()->getUip();
1226         G4_Operand* jip = inst->asCFInst()->getJip();
1227         //iga will take care off
1228         if (uip)
1229         {
1230             igaInst->setLabelSource(SourceIndex::SRC1,
1231                 lookupIGABlock(uip->asLabel(), *IGAKernel), Type::UD);
1232         }
1233 
1234         igaInst->setLabelSource(SourceIndex::SRC0,
1235             lookupIGABlock(jip->asLabel(), *IGAKernel), Type::UD);
1236     }
1237     else
1238     {
1239         // Creating a fall through block
1240         bbNew = IGAKernel->createBlock();
1241         igaInst->setLabelSource(SourceIndex::SRC0, bbNew, Type::UD);
1242         IGAKernel->appendBlock(bbNew);
1243     }
1244 }
1245 
translateInstructionSrcs(G4_INST * inst,Instruction * igaInst)1246 void BinaryEncodingIGA::translateInstructionSrcs(
1247     G4_INST *inst, Instruction *igaInst)
1248 {
1249     // set source operands
1250     int numSrcToEncode = inst->getNumSrc();
1251     if (inst->isSend())
1252     {
1253         // skip desc/exdesc as they are handled separately
1254         numSrcToEncode = inst->isSplitSend() ? 2 : 1;
1255 
1256         if (numSrcToEncode == 1 && platformModel->platform >= Platform::XE)
1257         {
1258             RegRef regTemp(0, 0);
1259             Region rgnTemp = Region::SRC010;
1260 
1261             igaInst->setDirectSource(
1262                 SourceIndex::SRC1,
1263                 SrcModifier::NONE,
1264                 RegName::ARF_NULL,
1265                 regTemp,
1266                 rgnTemp,
1267                 Type::INVALID);
1268         }
1269     }
1270     if (platform >= GENX_ICLLP
1271         && inst->opcode() == G4_movi && numSrcToEncode == 1)
1272     {
1273         // From ICL, 'movi' becomes a binary instruction with an
1274         // optional immediate operand, which needs encoding as null
1275         // or imm32. So far, within vISA jitter, 'movi' is still
1276         // modeled as unary instruction, setting src1 to null for
1277         // platforms >= CNL.
1278         RegRef regTemp(0, 0);
1279         Region rgnTemp = Region::SRC110;
1280         igaInst->setDirectSource(SourceIndex::SRC1,
1281             SrcModifier::NONE,
1282             RegName::ARF_NULL,
1283             regTemp, rgnTemp,
1284             Type::UB);
1285     }
1286     for (int i = 0; i < numSrcToEncode; i++)
1287     {
1288         SourceIndex opIx = SourceIndex::SRC0;
1289         switch (i) {
1290         case 0: opIx = SourceIndex::SRC0; break;
1291         case 1: opIx = SourceIndex::SRC1; break;
1292         case 2: opIx = SourceIndex::SRC2; break;
1293         default:
1294             assert(0 && "invalid source index number");
1295             break;
1296         }
1297 
1298         G4_Operand* src = inst->getSrc(i);
1299 
1300         if (src->isSrcRegRegion())
1301         {
1302             G4_SrcRegRegion* srcRegion = src->asSrcRegRegion();
1303             SrcModifier srcMod = getIGASrcModifier(srcRegion->getModifier());
1304             Region region = getIGARegion(srcRegion, i);
1305             Type type = Type::INVALID;
1306 
1307             // let IGA take care of types for send/s instructions
1308             if (!igaInst->getOpSpec().isSendOrSendsFamily())
1309             {
1310                 type = getIGAType(inst, inst->getSrcOperandNum(i), platform);
1311             }
1312             else if (i == 0 && platform >= GENX_SKL && platform < GENX_ICLLP)
1313             {
1314                 // work around for SKL bug
1315                 // not all bits are copied from immediate descriptor
1316                 G4_SendDescRaw* msgDesc = inst->getMsgDescRaw();
1317                 assert(msgDesc && "expected raw descriptor");
1318                 G4_Operand* descOpnd = inst->isSplitSend() ?
1319                     inst->getSrc(2) : inst->getSrc(1);
1320                 if (!descOpnd->isImm() && msgDesc->is16BitInput())
1321                 {
1322                     type = Type::HF;
1323                 }
1324             }
1325 
1326             if (igaInst->isMacro())
1327             {
1328                 auto accRegSel =
1329                     srcRegion->isNullReg() ? NOACC : srcRegion->getAccRegSel();
1330                 RegRef regRef = getIGARegRef(srcRegion);
1331                 igaInst->setMacroSource(
1332                     opIx,
1333                     srcMod,
1334                     getIGARegName(srcRegion),
1335                     regRef,
1336                     getIGAImplAcc(accRegSel),
1337                     region,
1338                     type);
1339             }
1340             else if (inst->isDpas())
1341             {
1342                 assert(srcRegion->getRegAccess() == Direct &&
1343                     "dpas does not support indirect GRF operands");
1344                 G4_InstDpas* dpasInst = inst->asDpasInst();
1345                 RegRef regRef = getIGADpasRegRef(dpasInst, i);
1346                 type = getIGADpasType(dpasInst, i);
1347 
1348                 igaInst->setDirectSource(
1349                     opIx,
1350                     srcMod,
1351                     getIGARegName(srcRegion),
1352                     regRef,
1353                     region,
1354                     type);
1355             }
1356             else if (srcRegion->getRegAccess() == Direct)
1357             {
1358                 igaInst->setDirectSource(
1359                     opIx,
1360                     srcMod,
1361                     getIGARegName(srcRegion),
1362                     getIGARegRef(srcRegion),
1363                     region,
1364                     type);
1365             }
1366             else
1367             {
1368                 RegRef regRef {0, 0};
1369                 bool valid;
1370                 regRef.subRegNum = (uint8_t)srcRegion->ExIndSubRegNum(valid);
1371                 // set to GRF for indirect register access
1372                 iga::RegName regName = iga::RegName::GRF_R;
1373 
1374                 igaInst->setInidirectSource(
1375                     opIx,
1376                     srcMod,
1377                     regName,
1378                     regRef,
1379                     srcRegion->getAddrImm(),
1380                     region,
1381                     type);
1382             }
1383         }
1384         else if (src->isLabel())
1385         {
1386             igaInst->setLabelSource(opIx,
1387                 lookupIGABlock(src->asLabel(), *IGAKernel), Type::UD);
1388         }
1389         else if (src->isImm())
1390         {
1391             Type type = getIGAType(src->getType(), platform);
1392             ImmVal val;
1393             val = src->asImm()->getImm();
1394             val.kind = getIGAImmType(src->getType());
1395             igaInst->setImmediateSource(opIx, val, type);
1396         }
1397         else
1398         {
1399             IGA_ASSERT_FALSE("unexpected src kind");
1400         }
1401     } // for
1402 }
1403 
getIGASendDesc(G4_INST * sendInst) const1404 SendDesc BinaryEncodingIGA::getIGASendDesc(G4_INST* sendInst) const
1405 {
1406     SendDesc desc;
1407     assert(sendInst->isSend() && "expect send inst");
1408     G4_Operand* msgDesc = sendInst->isSplitSend() ?
1409         sendInst->getSrc(2) : sendInst->getSrc(1);
1410     if (msgDesc->isImm())
1411     {
1412         desc.type = SendDesc::Kind::IMM;
1413         desc.imm = (uint32_t)msgDesc->asImm()->getImm();
1414         // This is a WA that needs to add fence.ugm before EOT
1415         //     fence.ugm.invalidate.tile works, but performance for raytracing
1416         //     might be affected. HW team came out a way to get around of it
1417         //     by using reserved Flush TYPE = 6, with the following
1418         //            DG2_Backup_Mode = 0
1419         //            Flush_Range = 0
1420         //     (So, it is fence.ugm.6.tile !)
1421         auto msgDesc = sendInst->asSendInst()->getMsgDesc();
1422         if (msgDesc->isLSC() && msgDesc->isFence())
1423         {
1424             // Flush Type : bit[14:12]
1425             uint32_t flushTy = ((desc.imm >> 12) & 0x7);
1426             if (flushTy == 6)
1427             {
1428                 // DG2 fence desc
1429                 //   both backupMode(bit[18]) and flushRange(bit[15]) must be zero
1430                 constexpr uint32_t backupMode = (1 << 18), flushRange = (1 << 15);
1431                 desc.imm = desc.imm & ~(backupMode | flushRange);
1432             }
1433         }
1434     }
1435     else
1436     {
1437         desc.type = SendDesc::Kind::REG32A;
1438         desc.reg.regNum = 0; // must be a0
1439         bool valid = false;
1440         desc.reg.subRegNum = (uint8_t)msgDesc->asSrcRegRegion()->ExSubRegNum(valid);
1441         assert(valid && "invalid subreg");
1442     }
1443 
1444     return desc;
1445 }
1446 
1447 ///////////////////////////////////////////////////////////////////////////////
1448 // ExDesc encoding
encodeExDescSendUnary(G4_INST * sendInst,int & xlen,InstOptSet & extraOpts)1449 static SendDesc encodeExDescSendUnary(
1450     G4_INST* sendInst, int& xlen, InstOptSet& extraOpts)
1451 {
1452     SendDesc exDescIga;
1453 
1454     // old unary packed send
1455     // exDesc is stored in SendMsgDesc and must be IMM
1456     G4_SendDescRaw* descG4 = sendInst->getMsgDescRaw();
1457     assert(descG4 != nullptr && "expected raw send");
1458 
1459     exDescIga.type = SendDesc::Kind::IMM;
1460     uint32_t tVal = descG4->getExtendedDesc();
1461 
1462     if (getPlatformGeneration(sendInst->getPlatform()) >= PlatformGen::XE)
1463     {
1464         // We must clear the funcID in the extended message.
1465         // In Xe+ this is part of the EU encoding, not the descriptor.
1466         // vISA/G4IR still treat it as part of the descriptor.
1467         tVal = tVal & 0xFFFFFFF0;
1468 
1469         // clear the EOT bit which is not part of exDesc
1470         tVal &= ~(1 << 5);
1471     }
1472     exDescIga.imm = tVal;
1473 
1474     // non-split send implies Src1.Length == 0
1475     xlen = 0;
1476 
1477     return exDescIga;
1478 }
1479 
1480 ////////////////////////////////////////////////////////////////////
1481 // these handle binary sends (old "sends" and Xe+ "send"
1482 //
encodeExDescImm(G4_INST * sendInst,SendExDescOpts & sdos) const1483 SendDesc BinaryEncodingIGA::encodeExDescImm(
1484     G4_INST* sendInst,
1485     SendExDescOpts &sdos) const
1486 {
1487     SendDesc exDescIga;
1488 
1489     G4_Operand* exDescG4 = sendInst->getSrc(3);
1490     G4_SendDescRaw* descG4 = sendInst->getMsgDescRaw();
1491     assert(descG4 != nullptr && "expected raw descriptor");
1492 
1493     sdos.xlen = (int)descG4->extMessageLength();
1494     //
1495     exDescIga.type = SendDesc::Kind::IMM;
1496     exDescIga.imm = (uint32_t)exDescG4->asImm()->getImm();
1497     // We must clear the funcID in the extended message for Xe+
1498     // because it is part of the EU instruction, not the descriptor,
1499     // and, vISA/G4-IR still thinks of it as part of the descriptor.
1500     //
1501     // Ditto for the EOT bit which is moved out of extDesc
1502     //
1503     // The extended message format
1504     // struct ExtendedMsgDescLayout {
1505     //    uint32_t funcID : 4;       // bit 0:3 << not part of ExDesc
1506     //    uint32_t unnamed1 : 1;     // bit 4
1507     //    uint32_t eot : 1;          // bit 5 << not part of ExDesc
1508     //    uint32_t extMsgLength : 5; // bit 6:10
1509     //    uint32_t unnamed2 : 5;     // bit 11:15
1510     //    uint32_t extFuncCtrl : 16; // bit 16:31
1511     // };
1512     if (getPlatformGeneration(sendInst->getPlatform()) >= PlatformGen::XE)
1513     {
1514         exDescIga.imm &= 0xFFFFFFC0;
1515     }
1516     if (kernel.fg.builder->encodeSendSrc1Length())
1517     {
1518         // In DG2+ ExDesc[10:6] is no longer Src1.Length even for imm
1519         // and the field is always part of the EU encoding
1520         if (descG4->isCPSEnabled()) {
1521             sdos.extraOpts.add(InstOpt::CPS);
1522         }
1523         // We must keep ExDesc[10:6] as Src1.Len until we fix the
1524         // 100s of uses that assume this.
1525         // IGA expects these bits to be 0's on this platform
1526         //
1527         // FIXME: remove the if guard once we enable DG2
1528         // (i.e. once DG2 targets IGA DG2 and not XE_HP, we should clear
1529         // the bottom 12b for DG2 too) and only use the IR fields above
1530         // (exDescArg.{cps,src1Length})
1531         exDescIga.imm &= 0xFFFFF000;
1532     }
1533     // Note: ExBSO is never permitted for imm descriptors
1534 
1535     // clear the EOT bit which is not part of exDesc on XE+
1536     if (getPlatformGeneration(sendInst->getPlatform()) >= PlatformGen::XE)
1537         exDescIga.imm &= ~(1 << 5);
1538 
1539     return exDescIga;
1540 }
1541 
encodeExDescRegA0(G4_INST * sendInst,SendExDescOpts & sdos) const1542 SendDesc BinaryEncodingIGA::encodeExDescRegA0(
1543     G4_INST* sendInst, SendExDescOpts &sdos) const
1544 {
1545     G4_Operand* exDescG4 = sendInst->getSrc(3);
1546     const G4_SendDescRaw* descG4 = sendInst->getMsgDescRaw();
1547     assert(descG4 != nullptr && "expected raw descriptor");
1548 
1549     SendDesc exDescIga;
1550     exDescIga.type = SendDesc::Kind::REG32A;
1551     exDescIga.reg.regNum = 0; // must be a0
1552     bool valid = false;
1553     exDescIga.reg.subRegNum =
1554         (uint16_t)exDescG4->asSrcRegRegion()->ExSubRegNum(valid);
1555     assert(valid && "invalid subreg");
1556 
1557     if (kernel.fg.builder->useNewExtDescFormat() && descG4->isCPSEnabled()) {
1558         // CPS is an instruction option if using RegDesc+ExBSO
1559         sdos.extraOpts.add(InstOpt::CPS);
1560     }
1561 
1562     // By default all RegDesc in the new descriptor format will use
1563     // the ExBSO model if at all possible
1564     bool encodeExBso = kernel.fg.builder->useNewExtDescFormat();
1565     // On DG2 LSC mustn't use ExBSO for BTI (hardware restriction).
1566     // If this is an LSC descriptor, then dig out the LscAddrType field and
1567     // compare to 3 (which means BTI).
1568     const bool isLsc = descG4->isLscOp();
1569     const bool isLscBti = isLsc && descG4->getLscAddrType() == LSC_ADDR_TYPE_BTI;
1570     const bool isUgm = sendInst->getMsgDesc()->getSFID() == vISA::SFID::UGM;
1571     encodeExBso &= !isLscBti;
1572     if (encodeExBso)
1573         sdos.extraOpts.add(InstOpt::EXBSO);
1574 
1575     // G4 IR keeps Src1.Length (xlen) separate.  So it's known,
1576     // (even with a reg desc in nonExBSO mode)
1577     sdos.xlen = (int)descG4->extMessageLength();
1578 
1579     return exDescIga;
1580 }
1581 
1582 
1583 
getIGASendExDesc(G4_INST * sendInst) const1584 SendExDescOpts BinaryEncodingIGA::getIGASendExDesc(G4_INST* sendInst) const {
1585     SendExDescOpts sdos;
1586 
1587     assert(sendInst->isSend() && "expect send inst");
1588 
1589     if (sendInst->isEOT())
1590         sdos.extraOpts.add(InstOpt::EOT);
1591 
1592     if (sendInst->isSplitSend())
1593     {
1594         const G4_Operand* exDesc = sendInst->getSrc(3);
1595         sdos.exDesc = exDesc->isImm() ?
1596             encodeExDescImm(sendInst, sdos) :
1597             encodeExDescRegA0(sendInst, sdos);
1598     }
1599     else
1600     {
1601         sdos.exDesc = encodeExDescSendUnary(sendInst, sdos.xlen, sdos.extraOpts);
1602     }
1603 
1604     return sdos;
1605 }
1606 
EmitBinary(size_t & binarySize)1607 void *BinaryEncodingIGA::EmitBinary(size_t& binarySize)
1608 {
1609     binarySize = m_kernelBufferSize;
1610 
1611     if (kernel.getOption(vISA_GenerateBinary))
1612     {
1613         std::string binFileName = fileName + ".dat";
1614         if (CisaFramework::allowDump(*kernel.getOptions(), binFileName))
1615         {
1616             std::string errStr;
1617             std::ofstream os(binFileName, std::ios::binary);
1618             if (!os)
1619             {
1620                 errStr = "Can't open " + binFileName + ".\n";
1621                 MUST_BE_TRUE(0, errStr);
1622                 return nullptr;
1623             }
1624             os.write((const char*)m_kernelBuffer, binarySize);
1625         }
1626     }
1627 
1628     return m_kernelBuffer;
1629 }
1630 
getIGAExecSize(int execSize)1631 ExecSize BinaryEncodingIGA::getIGAExecSize(int execSize)
1632 {
1633     switch (execSize)
1634     {
1635     case 1:     return ExecSize::SIMD1;
1636     case 2:     return ExecSize::SIMD2;
1637     case 4:     return ExecSize::SIMD4;
1638     case 8:     return ExecSize::SIMD8;
1639     case 16:    return ExecSize::SIMD16;
1640     case 32:    return ExecSize::SIMD32;
1641     default:
1642         assert(false && "illegal simd size");
1643         return ExecSize::INVALID;
1644     }
1645 }
1646 
getIGAChannelOffset(int offset)1647 ChannelOffset BinaryEncodingIGA::getIGAChannelOffset(int offset)
1648 {
1649     switch (offset)
1650     {
1651     case 0:     return ChannelOffset::M0;
1652     case 4:     return ChannelOffset::M4;
1653     case 8:     return ChannelOffset::M8;
1654     case 12:    return ChannelOffset::M12;
1655     case 16:    return ChannelOffset::M16;
1656     case 20:    return ChannelOffset::M20;
1657     case 24:    return ChannelOffset::M24;
1658     case 28:    return ChannelOffset::M28;
1659     default:
1660         assert(false && "illegal mask offset");
1661         return ChannelOffset::M0;
1662     }
1663 }
1664 
getIGAMaskCtrl(bool noMask)1665 MaskCtrl BinaryEncodingIGA::getIGAMaskCtrl(bool noMask)
1666 {
1667     return noMask ? MaskCtrl::NOMASK : MaskCtrl::NORMAL;
1668 }
1669 
getIGAARFName(G4_ArchRegKind areg)1670 RegName BinaryEncodingIGA::getIGAARFName(G4_ArchRegKind areg)
1671 {
1672     switch (areg)
1673     {
1674     case AREG_NULL:     return RegName::ARF_NULL;
1675     case AREG_A0:       return RegName::ARF_A;
1676     case AREG_ACC0:
1677     case AREG_ACC1:     return RegName::ARF_ACC;
1678     case AREG_MASK0:    return RegName::ARF_CE;
1679     case AREG_MS0:      return RegName::ARF_MSG;
1680     case AREG_DBG:      return RegName::ARF_DBG;
1681     case AREG_SR0:      return RegName::ARF_SR;
1682     case AREG_CR0:      return RegName::ARF_CR;
1683     case AREG_N0:
1684     case AREG_N1:       return RegName::ARF_N;
1685     case AREG_IP:       return RegName::ARF_IP;
1686     case AREG_F0:
1687     case AREG_F1:
1688     case AREG_F2:
1689     case AREG_F3:
1690         return RegName::ARF_F;
1691     case AREG_TM0:      return RegName::ARF_TM;
1692     case AREG_TDR0:     return RegName::ARF_TDR;
1693     case AREG_SP:       return RegName::ARF_SP;
1694     default:
1695         assert(false && "illegal ARF");
1696         return RegName::INVALID;
1697     }
1698 }
1699 
getIGAType(const G4_INST * I,Gen4_Operand_Number O,TARGET_PLATFORM P)1700 Type BinaryEncodingIGA::getIGAType(const G4_INST* I, Gen4_Operand_Number O, TARGET_PLATFORM P)
1701 {
1702 
1703     G4_Type Ty = I->getOperand(O)->getType();
1704     if (I->opcode() == G4_fcvt)
1705     {
1706         if (Ty == Type_UB)
1707         {
1708             return Type::BF8;
1709         }
1710         if (Ty == Type_UD)
1711         {
1712             return Type::TF32;
1713         }
1714     }
1715     if (I->opcode() == G4_srnd)
1716     {
1717         if (O == Opnd_dst && Ty == Type_UB)
1718         {
1719             return Type::BF8;
1720         }
1721     }
1722     return getIGAType(Ty, P);
1723 }
1724 
getIGAType(G4_Type type,TARGET_PLATFORM genxPlatform)1725 Type BinaryEncodingIGA::getIGAType(G4_Type type, TARGET_PLATFORM genxPlatform)
1726 {
1727     switch (type)
1728     {
1729     case Type_UB:   return Type::UB;
1730     case Type_B:    return Type::B;
1731     case Type_UW:   return Type::UW;
1732     case Type_W:    return Type::W;
1733     case Type_UD:   return Type::UD;
1734     case Type_D:    return Type::D;
1735     case Type_UQ:   return Type::UQ;
1736     case Type_Q:    return Type::Q;
1737     case Type_HF:   return Type::HF;
1738     case Type_F:    return Type::F;
1739     case Type_DF:   return Type::DF;
1740     case Type_UV:   return Type::UV;
1741     case Type_V:    return Type::V;
1742     case Type_VF:   return Type::VF;
1743     case Type_NF:   return Type::NF;
1744     case Type_BF:   return Type::BF;
1745     default:
1746         assert(false && "illegal type");
1747         return Type::INVALID;
1748     }
1749 }
1750 
getIGAPredCtrl(G4_Predicate_Control g4PrCtl)1751 PredCtrl BinaryEncodingIGA::getIGAPredCtrl(G4_Predicate_Control g4PrCtl)
1752 {
1753     switch (g4PrCtl)
1754     {
1755     case PRED_DEFAULT:      return PredCtrl::SEQ;
1756     case PRED_ANY2H:        return PredCtrl::ANY2H;
1757     case PRED_ANY4H:        return PredCtrl::ANY4H;
1758     case PRED_ANY8H:        return PredCtrl::ANY8H;
1759     case PRED_ANY16H:       return PredCtrl::ANY16H;
1760     case PRED_ANY32H:       return PredCtrl::ANY32H;
1761     case PRED_ALL2H:        return PredCtrl::ALL2H;
1762     case PRED_ALL4H:        return PredCtrl::ALL4H;
1763     case PRED_ALL8H:        return PredCtrl::ALL8H;
1764     case PRED_ALL16H:       return PredCtrl::ALL16H;
1765     case PRED_ALL32H:       return PredCtrl::ALL32H;
1766     case PRED_ANYV:         return PredCtrl::ANYV;
1767     case PRED_ALLV:         return PredCtrl::ALLV;
1768     case PRED_ANY_WHOLE:    return PredCtrl::ANY;
1769     case PRED_ALL_WHOLE:    return PredCtrl::ALL;
1770     default:
1771         assert(false && "illegal predicate control");
1772         return PredCtrl::NONE;
1773     }
1774 }
1775 
getIGAPredication(G4_Predicate * predG4)1776 Predication BinaryEncodingIGA::getIGAPredication(G4_Predicate* predG4)
1777 {
1778     Predication pred;
1779     if (predG4)
1780     {
1781         pred.function = getIGAPredCtrl(predG4->getControl());
1782         pred.inverse = predG4->getState() != PredState_Plus;
1783     }
1784     return pred;
1785 }
1786 
getIGASrcModifier(G4_SrcModifier srcMod)1787 SrcModifier BinaryEncodingIGA::getIGASrcModifier(G4_SrcModifier srcMod)
1788 {
1789     switch (srcMod)
1790     {
1791     case Mod_Minus:         return SrcModifier::NEG;
1792     case Mod_Abs:           return SrcModifier::ABS;
1793     case Mod_Minus_Abs:     return SrcModifier::NEG_ABS;
1794     case Mod_Not:           return SrcModifier::NEG;
1795     case Mod_src_undef:     return SrcModifier::NONE;
1796     default:
1797         assert(false && "illegal source modifier");
1798         return SrcModifier::NONE;
1799     }
1800 }
1801 
getIGAVert(int vstride)1802 Region::Vert BinaryEncodingIGA::getIGAVert(int vstride)
1803 {
1804     switch (vstride)
1805     {
1806     case 0:                 return Region::Vert::VT_0;
1807     case 1:                 return Region::Vert::VT_1;
1808     case 2:                 return Region::Vert::VT_2;
1809     case 4:                 return Region::Vert::VT_4;
1810     case 8:                 return Region::Vert::VT_8;
1811     case 16:                return Region::Vert::VT_16;
1812     case 32:                return Region::Vert::VT_32;
1813     case UNDEFINED_SHORT:   return Region::Vert::VT_VxH;
1814     default:
1815         assert(false && "illegal vstride");
1816         return Region::Vert::VT_INVALID;
1817     }
1818 }
1819 
getIGAWidth(int width)1820 Region::Width BinaryEncodingIGA::getIGAWidth(int width)
1821 {
1822     switch (width)
1823     {
1824     case 1:     return Region::Width::WI_1;
1825     case 2:     return Region::Width::WI_2;
1826     case 4:     return Region::Width::WI_4;
1827     case 8:     return Region::Width::WI_8;
1828     case 16:    return Region::Width::WI_16;
1829     default:
1830         assert(false && "illegal width");
1831         return Region::Width::WI_INVALID;
1832     }
1833 }
1834 
getIGAHorz(int hstride)1835 Region::Horz BinaryEncodingIGA::getIGAHorz(int hstride)
1836 {
1837     switch (hstride)
1838     {
1839     case 0:     return Region::Horz::HZ_0;
1840     case 1:     return Region::Horz::HZ_1;
1841     case 2:     return Region::Horz::HZ_2;
1842     case 4:     return Region::Horz::HZ_4;
1843     default:
1844         assert(false && "illegal hstride");
1845         return Region::Horz::HZ_INVALID;
1846     }
1847 }
1848 
getIGARegion(G4_SrcRegRegion * srcRegion,int srcPos)1849 Region BinaryEncodingIGA::getIGARegion(
1850     G4_SrcRegRegion* srcRegion, int srcPos)
1851 {
1852     Region igaRegion;
1853     const RegionDesc* region = srcRegion->getRegion();
1854     if ((srcRegion->getInst()->getNumSrc() == 3 &&
1855         !srcRegion->getInst()->isSend()))
1856     {
1857         // special handling for 3src instructions
1858         if (srcPos != 2)
1859         {
1860             // for src0 and src1, IGA/GED does not like width to be set
1861             igaRegion.set(
1862                 getIGAVert(region->vertStride),
1863                 Region::Width::WI_INVALID,
1864                 getIGAHorz(region->horzStride));
1865         }
1866         else
1867         {
1868             // for src2, IGA expects both VS and W to be invalid
1869             igaRegion.set(
1870                 Region::Vert::VT_INVALID,
1871                 Region::Width::WI_INVALID,
1872                 getIGAHorz(region->horzStride));
1873         }
1874     }
1875     else
1876     {
1877         igaRegion.set(
1878             getIGAVert(region->vertStride),
1879             getIGAWidth(region->width),
1880             getIGAHorz(region->horzStride));
1881     }
1882     return igaRegion;
1883 }
1884 
EncodeKernelIGA(vISA::Mem_Manager & m,vISA::G4_Kernel & k,const std::string & fname)1885 EncodeResult vISA::EncodeKernelIGA(
1886     vISA::Mem_Manager &m,
1887     vISA::G4_Kernel& k,
1888     const std::string &fname)
1889 {
1890     EncodeResult r;
1891     BinaryEncodingIGA encoder(m, k, fname);
1892     encoder.Encode();
1893     r.binary = encoder.EmitBinary(r.binaryLen);
1894     return r;
1895 }
1896 
GetIGASWSBEncodeMode(const IR_Builder & builder)1897 SWSB_ENCODE_MODE vISA::GetIGASWSBEncodeMode(const IR_Builder& builder) {
1898     if (getPlatformGeneration(builder.getPlatform()) < PlatformGen::XE)
1899         return SWSB_ENCODE_MODE::SWSBInvalidMode;
1900 
1901     if (builder.hasThreeALUPipes()) {
1902         return SWSB_ENCODE_MODE::ThreeDistPipe;
1903     }
1904     else if (builder.hasFourALUPipes()) {
1905         if (builder.getPlatform() == GENX_PVC)
1906             return SWSB_ENCODE_MODE::FourDistPipe;
1907         return SWSB_ENCODE_MODE::FourDistPipeReduction;
1908     }
1909 
1910     return SWSB_ENCODE_MODE::SingleDistPipe;
1911 }
1912 
GetModel(TARGET_PLATFORM p)1913 static const Model *GetModel(TARGET_PLATFORM p)
1914 {
1915     const Model *m = Model::LookupModel(
1916         BinaryEncodingIGA::getIGAInternalPlatform(p));
1917     return m;
1918 }
1919 
InstSupportsSaturationIGA(TARGET_PLATFORM p,const G4_INST & i,const IR_Builder & builder)1920 bool vISA::InstSupportsSaturationIGA(TARGET_PLATFORM p, const G4_INST &i, const IR_Builder& builder)
1921 {
1922     const Model *m = GetModel(p);
1923     if(m)
1924     {
1925         auto oi = BinaryEncodingIGA::getIgaOpInfo(&i, m, true, builder);
1926         return oi.first && oi.first->isValid() && oi.first->supportsSaturation();
1927     }
1928     else
1929     {
1930         return false;
1931     }
1932 }
1933 
InstSupportsSrcModifierIGA(TARGET_PLATFORM p,const G4_INST & i,const IR_Builder & builder)1934 bool vISA::InstSupportsSrcModifierIGA(TARGET_PLATFORM p, const G4_INST &i, const IR_Builder& builder)
1935 {
1936     const Model *m = GetModel(p);
1937     if(m)
1938     {
1939         auto oi = BinaryEncodingIGA::getIgaOpInfo(&i, m, true, builder);
1940         return oi.first && oi.first->isValid() && oi.first->supportsSourceModifiers();
1941     }
1942     else
1943     {
1944         return false;
1945     }
1946 }
1947 
1948