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 #ifndef _IGA_INST_BUILDER_HPP_
10 #define _IGA_INST_BUILDER_HPP_
11 
12 #include "Kernel.hpp"
13 #include "Messages.hpp"
14 #include "../asserts.hpp"
15 #include "../ErrorHandler.hpp"
16 #include "../Frontend/IRToString.hpp"
17 #include "../Models/Models.hpp"
18 
19 #include <map>
20 #include <sstream>
21 #include <string>
22 #include <tuple>
23 #include <vector>
24 
25 namespace iga
26 {
27 // The IR Builder is called by various instruction generators that build
28 // full instructions from partial state.  This allows us to separate IR
29 // construction from the actual syntax processing or decoding.
30 //
31 // This is needed since we have to save information about the operands
32 // during the parse.  We can't create operands as we see them since we don't
33 // have an existing Instruction * until InstEnd().   E.g. createSend
34 // requires us having seen exDesc and desc.  Since these follow the operands;
35 // hence, we must save operand info as state as we go.  This allows us to
36 // treat instructions as more immutable entities rather than complex state
37 // machines (via mutation) and allows us to be a little more sure that
38 // Instruction values are correct states.
39 //
40 // A better decision would be to make the IR types mutable by at least this
41 // class
42 struct OperandInfo
43 {
44     Loc                      loc;
45     Operand::Kind            kind = Operand::Kind::INVALID;
46 
47     union // optional modifier (e.g. -r12, ~r12, (abs) (sat))
48     {
49         SrcModifier          regOpSrcMod = SrcModifier::NONE;
50         DstModifier          regOpDstMod;
51     };
52     RegName                  regOpName = RegName::INVALID;    // e.g. r#, a#, null, ...
53     Region                   regOpRgn = Region::INVALID;     // e.g. <1>, <8;8,1>
54     MathMacroExt             regOpMathMacroExtReg = MathMacroExt::INVALID; // e.g. math macro spc acc
55 
56     // direct/indirect register info
57     RegRef                   regOpReg; // direct operands
58 
59     // indirect register offset
60     int16_t                  regOpIndOff = 0; // e.g. "16" in "r[a0.4,16]"
61 
62     // imm field
63     ImmVal                   immValue;
64 
65     std::string              immLabel;
66     Type                     type = Type::INVALID;
67 
OperandInfoiga::OperandInfo68     OperandInfo()
69     {
70         kind = Operand::Kind::INVALID;
71         regOpSrcMod = SrcModifier::NONE;
72         regOpName = RegName::INVALID;
73         regOpRgn = Region::INVALID;
74         regOpMathMacroExtReg = MathMacroExt::INVALID;
75         regOpReg = REGREF_ZERO_ZERO;
76         regOpIndOff = 0;
77         immValue.u64 = 0;
78         immValue.kind = ImmVal::Kind::UNDEF;
79         immLabel.clear();
80         type = Type::INVALID;
81     }
82 
resetiga::OperandInfo83     void reset()
84     {
85         kind = Operand::Kind::INVALID;
86         regOpSrcMod = SrcModifier::NONE;
87         regOpName = RegName::INVALID;
88         regOpRgn = Region::INVALID;
89         regOpMathMacroExtReg = MathMacroExt::INVALID;
90         regOpReg = REGREF_ZERO_ZERO;
91         regOpIndOff = 0;
92         immValue.u64 = 0;
93         immValue.kind = ImmVal::Kind::UNDEF;
94         immLabel.clear();
95         type = Type::INVALID;
96     }
97 };
98 
99 
100 // Larger constructs, such as blocks, instructions, and whatnot
101 // generally consist of a ***Start() and ***End() method to denote the
102 // start and end of each feature.  Upon parse or semantic error, the
103 // parser may terminate early, and corresponding ***End() functions may
104 // not be called in those cases.
105 //
106 // The methods are roughly called in syntax order, but this isn't a strict
107 // requirement and the handler should not make any assumptions about that.
108 class InstBuilder {
109     const Model&                m_model;
110     ErrorHandler&               m_errorHandler;
111     Kernel                     *m_kernel;
112 
113     // per-instruction state
114     Loc                         m_loc;
115     Predication                 m_predication;
116     const OpSpec               *m_opSpec = nullptr;
117 
118     Subfunction                 m_subfunc;
119 
120     RegRef                      m_flagReg; // shared by predication / condition modifier
121 
122     ExecSize                    m_execSize = ExecSize::INVALID;
123     ChannelOffset               m_chOff    = ChannelOffset::M0;
124     MaskCtrl                    m_maskCtrl = MaskCtrl::NOMASK;
125 
126     FlagModifier                m_flagModifier = FlagModifier::NONE;
127     DstModifier                 m_dstModifier  = DstModifier::NONE;
128 
129     OperandInfo                 m_dst;
130     OperandInfo                 m_srcs[3];
131     int                         m_nSrcs = 0;
132 
133     SendDesc                    m_exDesc;
134     SendDesc                    m_desc;
135     // int                         m_sendDst;  // (extracted later)
136     int                         m_sendSrc0Len = -1;
137     int                         m_sendSrc1Len = -1;
138 
139     InstOptSet                  m_instOpts;
140 
141     std::string                 m_comment;
142 
143     ////////////////////////////////////////////////////////////////////
144     // During parse, we add all instructions to one list, record label
145     // locations and unresolved operands.  At the end of the parse,
146     // we'll resolve everything to numeric form and then split things into
147     // blocks at the end (if desired)
148     //
149     // one full linear list of instructions,
150     InstList                    m_insts;
151     //
152     // labels defined (block starts)
153     // (start-loc,start-pc,end-loc,end-pc
154     using LabelInfo=std::tuple<Loc,uint32_t>;
155     std::map<std::string,LabelInfo>  m_labelMap;
156     LabelInfo                       *m_currBlock = nullptr;
157     // unresolved operand labels
158     struct UnresolvedLabel {
159         Loc             loc;
160         std::string     symbol;
161         Operand        &operand;
162         Instruction    &inst;
163     };
164     std::vector<UnresolvedLabel>     m_unresolvedLabels;
165 
166     uint32_t                    m_pc = 0; // current PC
167     uint32_t                    m_nextId = 0; // next instruction id
168 
169     SWSB_ENCODE_MODE            m_swsbEncodeMode;
170 
171 public:
172     struct SWSBInfo {
173         SWSB::DistType distType = SWSB::DistType::NO_DIST;
174         uint32_t regDist = 0;      // e.g. @3       0 = not set
175         int32_t memSBidAlloc = -1; // e.g. $2      -1 = not set
176         int32_t memSBidDst = -1;   // e.g. $2.dst  -1 = not set
177         int32_t memSBidSrc = -1;   // e.g. $2.src  -1 = not set
178         SWSB::SpecialToken spToken = SWSB::SpecialToken::NONE;
179 
SWSBInfoiga::InstBuilder::SWSBInfo180         SWSBInfo() { } // sets default values as above
181 
anyBarrierSetiga::InstBuilder::SWSBInfo182         bool anyBarrierSet() const {
183             return sbidAllocSet() || sbidDstSet() || sbidSrcSet();
184         }
sbidAllocSetiga::InstBuilder::SWSBInfo185         bool sbidAllocSet()    const { return memSBidAlloc >= 0; }
sbidDstSetiga::InstBuilder::SWSBInfo186         bool sbidDstSet()      const { return memSBidDst >= 0; }
sbidSrcSetiga::InstBuilder::SWSBInfo187         bool sbidSrcSet()      const { return memSBidSrc >= 0; }
specialTokenSetiga::InstBuilder::SWSBInfo188         bool specialTokenSet() const { return spToken != SWSB::SpecialToken::NONE; }
189 
operator ==iga::InstBuilder::SWSBInfo190         bool operator==(const SWSBInfo &sbi) const {
191             return
192                 distType == sbi.distType &&
193                 regDist == sbi.regDist &&
194                 memSBidAlloc == sbi.memSBidAlloc &&
195                 memSBidDst == sbi.memSBidDst &&
196                 memSBidSrc == sbi.memSBidSrc &&
197                 spToken == sbi.spToken;
198         }
operator !=iga::InstBuilder::SWSBInfo199         bool operator!=(const SWSBInfo &sbi) const {
200             return !(*this == sbi);
201         }
202     };
203 
204 private:
205     SWSBInfo                    m_depInfo;
206 
platform() const207     Platform platform() const {return m_model.platform;}
208 
clearInstState()209     void clearInstState() {
210         m_predication.function = PredCtrl::NONE;
211         m_predication.inverse = false;
212 
213         m_flagReg = REGREF_ZERO_ZERO;
214 
215         m_opSpec = nullptr;
216 
217         m_execSize = ExecSize::SIMD1;
218         m_chOff = ChannelOffset::M0;
219         m_subfunc = InvalidFC::INVALID; // invalid
220         m_maskCtrl = MaskCtrl::NORMAL;
221 
222         m_flagModifier = FlagModifier::NONE;
223 
224         m_dstModifier = DstModifier::NONE;
225 
226         m_dst.reset();
227         for (auto &m_src : m_srcs) {
228             m_src.reset();
229         }
230         m_nSrcs = 0;
231 
232         m_exDesc.imm = 0;
233         m_desc.imm = 0;
234 
235         m_sendSrc0Len = m_sendSrc1Len = -1;
236 
237         m_instOpts.clear();
238 
239         m_depInfo = SWSBInfo();
240 
241         m_comment.clear();
242     }
243 
244 public:
InstBuilder(Kernel * kernel,ErrorHandler & e)245     InstBuilder(Kernel *kernel, ErrorHandler &e)
246         : m_model(kernel->getModel())
247         , m_errorHandler(e)
248         , m_kernel(kernel)
249     {
250         m_swsbEncodeMode = m_model.getSWSBEncodeMode();
251     }
252 
getInsts()253     InstList &getInsts() {return m_insts;}
254 
errorHandler()255     ErrorHandler &errorHandler() {return m_errorHandler;}
256 
257     ///////////////////////////////////////////////////////////////////////////
258     // specific IR accessors
isMacroOp() const259     bool isMacroOp() const {
260         return m_opSpec->is(Op::MADM) ||
261             (m_opSpec->is(Op::MATH) && IsMacro(m_subfunc.math));
262     }
263 
getExDesc() const264     const SendDesc getExDesc() const {return m_exDesc;}
getSubfunction() const265     Subfunction getSubfunction() const {return m_subfunc;}
266 
267     ///////////////////////////////////////////////////////////////////////////
268     // specific IR setters
setSWSBEncodingMode(SWSB_ENCODE_MODE mode)269     void setSWSBEncodingMode(SWSB_ENCODE_MODE mode) {
270         m_swsbEncodeMode = mode;
271     }
272 
273     // Called at the beginning of the program
ProgramStart()274     void ProgramStart() {
275         m_pc = 0;
276         m_nextId = 1;
277     }
278 
279 
ProgramEnd()280     void ProgramEnd() {
281         for (const UnresolvedLabel &u : m_unresolvedLabels) {
282             auto itr = m_labelMap.find(u.symbol);
283             if (itr == m_labelMap.end()) {
284                 m_errorHandler.reportError(u.loc, "undefined label");
285             } else {
286                 const LabelInfo &li = itr->second;
287                 int32_t val = (int32_t)std::get<1>(li);
288                 if (!u.inst.getOpSpec().isJipAbsolute()) {
289                     val -= u.inst.getPC();
290                 }
291                 u.operand.setLabelSource(val, u.operand.getType());
292             }
293         }
294         // at this point m_instList has instructions with all labels in
295         // numeric form
296     }
297 
298 
BlockStart(const Loc & loc,const std::string & label)299     void BlockStart(const Loc &loc, const std::string &label) {
300         auto itr = m_labelMap.find(label);
301         if (itr != m_labelMap.end()) {
302             std::stringstream err;
303             err << "label redefinition " << label << " (defined "
304                 << "on line " << std::get<0>(itr->second).line << ")";
305             m_errorHandler.reportError(loc, err.str());
306         } else {
307             m_labelMap[label] = LabelInfo(loc,m_pc);
308             m_currBlock = &m_labelMap[label];
309         }
310     }
311 
312 
BlockEnd(uint32_t extent)313     void BlockEnd(uint32_t extent) {
314         if (m_currBlock) {
315             // could be null if error in BlockStart
316             std::get<0>(*m_currBlock).extent = extent;
317             m_currBlock = nullptr;
318         }
319     }
320 
321 
InstStart(const Loc & loc)322     void InstStart(const Loc &loc) {
323         clearInstState();
324         m_loc = loc;
325     }
326 
327 
InstEnd(uint32_t extent)328     void InstEnd(uint32_t extent) {
329         // set the full instruction length in chars (for text)
330         // or bytes (for decoding bits)
331         m_loc.extent = extent;
332         IGA_ASSERT(m_opSpec != nullptr, "OpSpec never set");
333 
334         Instruction *inst = nullptr;
335         if (m_opSpec->is(Op::MATH)) {
336             inst =
337                 m_kernel->createBasicInstruction(
338                     *m_opSpec,
339                     m_predication,
340                     m_flagReg,
341                     m_execSize,
342                     m_chOff,
343                     m_maskCtrl,
344                     m_flagModifier,
345                     m_subfunc);
346         } else if (m_opSpec->format == OpSpec::Format::SYNC_UNARY) {
347             inst =
348                 m_kernel->createBasicInstruction(
349                     *m_opSpec,
350                     m_predication,
351                     m_flagReg,
352                     m_execSize,
353                     m_chOff,
354                     m_maskCtrl,
355                     FlagModifier::NONE,
356                     m_subfunc);
357         } else if (m_opSpec->isBranching()) {
358             inst =
359                 m_kernel->createBranchInstruction(
360                     *m_opSpec,
361                     m_predication,
362                     m_flagReg,
363                     m_execSize,
364                     m_chOff,
365                     m_maskCtrl,
366                     m_subfunc);
367         } else if (m_opSpec->isSendOrSendsFamily()) {
368             if (m_subfunc.send == SFID::INVALID) {
369                 if (platform() <= Platform::GEN11 && m_exDesc.isImm()) {
370                     m_subfunc.send =
371                         sfidFromEncoding(platform(), m_exDesc.imm);
372                 }
373             }
374             inst =
375                 m_kernel->createSendInstruction(
376                     *m_opSpec,
377                     m_subfunc.send,
378                     m_predication,
379                     m_flagReg,
380                     m_execSize,
381                     m_chOff,
382                     m_maskCtrl,
383                     m_exDesc,
384                     m_desc);
385             if (m_sendSrc0Len >= 0)
386                 inst->setSrc0Length(m_sendSrc0Len);
387             if (m_sendSrc1Len >= 0)
388                 inst->setSrc1Length(m_sendSrc1Len);
389         } else if (m_opSpec->op == Op::NOP) {
390             inst = m_kernel->createNopInstruction();
391         } else if (m_opSpec->op == Op::ILLEGAL) {
392             inst = m_kernel->createIllegalInstruction();
393         } else {
394             inst =
395                 m_kernel->createBasicInstruction(
396                     *m_opSpec,
397                     m_predication,
398                     m_flagReg,
399                     m_execSize,
400                     m_chOff,
401                     m_maskCtrl,
402                     m_flagModifier,
403                     m_subfunc);
404         }
405         inst->setLoc(m_loc);
406         m_insts.emplace_back(inst);
407 
408         if (m_opSpec->supportsDestination()) {
409             IGA_ASSERT(m_dst.kind != Operand::Kind::INVALID,
410                 "destination never set");
411             if (m_dst.kind == Operand::Kind::DIRECT) {
412                 inst->setDirectDestination(
413                     m_dstModifier,
414                     m_dst.regOpName,
415                     m_dst.regOpReg,
416                     m_dst.regOpRgn.getHz(),
417                     m_dst.type);
418             } else if (m_dst.kind == Operand::Kind::MACRO) {
419                 inst->setMacroDestination(
420                     m_dstModifier,
421                     m_dst.regOpName,
422                     m_dst.regOpReg,
423                     m_dst.regOpMathMacroExtReg,
424                     m_dst.regOpRgn.getHz(),
425                     m_dst.type);
426             } else { // Operand::Kind::INDIRECT
427                 inst->setInidirectDestination(
428                     m_dstModifier,
429                     m_dst.regOpReg,
430                     m_dst.regOpIndOff,
431                     m_dst.regOpRgn.getHz(),
432                     m_dst.type);
433             }
434         } // end setting destinations
435 
436         // set source operands
437         for (int i = 0; i < m_nSrcs; i++) {
438             const OperandInfo &src = m_srcs[i];
439             IGA_ASSERT(src.kind != Operand::Kind::INVALID, "source never set");
440 
441             SourceIndex opIx = (SourceIndex)((int)SourceIndex::SRC0 + i);
442             if (src.kind == Operand::Kind::DIRECT) {
443                 inst->setDirectSource(
444                     opIx,
445                     src.regOpSrcMod,
446                     src.regOpName,
447                     src.regOpReg,
448                     src.regOpRgn,
449                     src.type);
450             } else if (src.kind == Operand::Kind::MACRO) {
451                 inst->setMacroSource(
452                     opIx,
453                     src.regOpSrcMod,
454                     src.regOpName,
455                     src.regOpReg,
456                     src.regOpMathMacroExtReg,
457                     src.regOpRgn,
458                     src.type);
459             } else if (src.kind == Operand::Kind::INDIRECT) {
460                 inst->setInidirectSource(
461                     opIx,
462                     src.regOpSrcMod,
463                     src.regOpName,
464                     src.regOpReg,
465                     src.regOpIndOff,
466                     src.regOpRgn,
467                     src.type);
468             } else if (src.kind == Operand::Kind::LABEL) {
469                 if (src.immLabel.empty()) {
470                     // numeric label was used
471                     inst->setLabelSource(opIx, src.immValue.s32, src.type);
472                 } else {
473                     // label (unresolved)
474                     //
475                     // we'll backpatch later, but set it for the type
476                     inst->setLabelSource(opIx, 0, src.type);
477                     UnresolvedLabel u {
478                         src.loc,
479                         src.immLabel,
480                         inst->getSource(opIx),
481                         *inst};
482                     m_unresolvedLabels.push_back(u);
483                 }
484             } else if (src.kind == Operand::Kind::IMMEDIATE) {
485                 inst->setImmediateSource(opIx, src.immValue, src.type);
486             } else {
487                 IGA_ASSERT_FALSE("unexpected src kind");
488             }
489         } // for: sources
490 
491         inst->addInstOpts(m_instOpts);
492         inst->setID(m_nextId++);
493         inst->setPC(m_pc);
494         if (!m_comment.empty()) {
495             inst->setComment(m_comment);
496         }
497 
498 
499         SWSB swInfo;
500         // this assumes checks for incompatible stuff are done during parsing
501         if (m_depInfo.sbidSrcSet())
502         {
503             swInfo.sbid = m_depInfo.memSBidSrc;
504             swInfo.tokenType = SWSB::TokenType::SRC;
505         }
506         if (m_depInfo.sbidDstSet())
507         {
508             swInfo.sbid = m_depInfo.memSBidDst;
509             swInfo.tokenType = SWSB::TokenType::DST;
510         }
511         if (m_depInfo.sbidAllocSet())
512         {
513             swInfo.sbid = m_depInfo.memSBidAlloc;
514             swInfo.tokenType = SWSB::TokenType::SET;
515         }
516         if (m_depInfo.regDist > 0)
517         {
518             swInfo.minDist = m_depInfo.regDist;
519             swInfo.distType = m_depInfo.distType;
520         }
521         swInfo.spToken = m_depInfo.spToken;
522         inst->setSWSB(swInfo);
523 
524         m_pc += inst->hasInstOpt(InstOpt::COMPACTED) ? 8 : 16;
525 
526         // after any branching instruction or EOT, split the basic block
527         // Also split when there is mov with label src
528         if (inst->isBranching() || inst->hasInstOpt(InstOpt::EOT) ||
529             inst->isMovWithLabel()) {
530             BlockEnd(m_pc);
531         }
532     }
533 
534 
InstPredication(const Loc &,bool inv,const RegRef & flagReg,PredCtrl predCtrl)535     void InstPredication(
536         const Loc &,
537         bool inv,
538         const RegRef &flagReg,
539         PredCtrl predCtrl)
540     {
541         m_predication.inverse = inv;
542         m_predication.function = predCtrl;
543         m_flagReg = flagReg;
544     }
545 
546 
InstOp(const OpSpec * spec)547     void InstOp(const OpSpec *spec) {
548         m_opSpec = spec;
549     }
550 
551 
InstSubfunction(Subfunction sf)552     void InstSubfunction(Subfunction sf) {
553         IGA_ASSERT(!m_subfunc.isValid(), "subfunction already set");
554         m_subfunc = sf;
555     }
556 
557 
InstExecInfo(const Loc &,ExecSize execSize,const Loc &,ChannelOffset execOff)558     void InstExecInfo(
559         const Loc &, ExecSize execSize,
560         const Loc &, ChannelOffset execOff)
561     {
562         m_execSize = execSize;
563         m_chOff = execOff;
564     }
565 
566 
InstNoMask(const Loc &)567     void InstNoMask(const Loc &) {
568         m_maskCtrl = MaskCtrl::NOMASK;
569     }
570 
571 
572     // The flag modifier (condition modifier)
InstFlagModifier(RegRef flagReg,FlagModifier flmodf)573     void InstFlagModifier(
574         RegRef flagReg,
575         FlagModifier flmodf)
576     {
577         m_flagModifier = flmodf;
578         m_flagReg = flagReg;
579     }
580 
581 
582     /////////////////////////////////////////////
583     // destination operand callbacks
584 
585     // (sat) applied to the destination operand
InstDstOpSaturate()586     void InstDstOpSaturate() {
587         m_dstModifier = DstModifier::SAT;
588     }
589 
590     // direct access
591     //
592     // e.g. r13.4<2>:t
InstDstOpRegDirect(const Loc & loc,const RegInfo & ri,RegRef reg,Region::Horz rgnHorz,Type ty)593     void InstDstOpRegDirect(
594         const Loc &loc,
595         const RegInfo &ri,
596         RegRef reg,
597         Region::Horz rgnHorz,
598         Type ty)
599     {
600         InstDstOpRegDirect(loc,ri.regName,reg,rgnHorz,ty);
601     }
InstDstOpRegDirect(const Loc & loc,RegName rn,int reg,Region::Horz rgnHorz,Type ty)602     void InstDstOpRegDirect(
603         const Loc &loc,
604         RegName rn,
605         int reg,
606         Region::Horz rgnHorz,
607         Type ty)
608     {
609         RegRef rr;
610         rr.regNum = (uint8_t)reg;
611         InstDstOpRegDirect(loc,rn,rr,rgnHorz,ty);
612     }
InstDstOpRegDirect(const Loc & loc,RegName rn,RegRef reg,Region::Horz rgnHorz,Type ty)613     void InstDstOpRegDirect(
614         const Loc &loc,
615         RegName rn,
616         RegRef reg,
617         Region::Horz rgnHorz,
618         Type ty)
619     {
620         m_dst.kind = Operand::Kind::DIRECT;
621         m_dst.loc = loc;
622 
623         m_dst.regOpDstMod = m_dstModifier;
624         m_dst.regOpName = rn;
625         m_dst.regOpReg = reg;
626         m_dst.regOpRgn.setDstHz(rgnHorz);
627         m_dst.type = ty;
628     }
629     // math macro register access (implicit accumulator)
630     //
631     // e.g. r13.acc4:t
InstDstOpRegMathMacroExtReg(const Loc & loc,RegName rnm,int regNum,MathMacroExt mme,Region::Horz rgnH,Type ty)632     void InstDstOpRegMathMacroExtReg(
633         const Loc &loc,
634         RegName rnm,
635         int regNum,
636         MathMacroExt mme,
637         Region::Horz rgnH,
638         Type ty)
639     {
640         m_dst.kind = Operand::Kind::MACRO;
641         m_dst.loc = loc;
642 
643         m_dst.regOpDstMod = m_dstModifier;
644         m_dst.regOpName = rnm;
645         m_dst.regOpReg = RegRef(static_cast<uint8_t>(regNum), 0);
646         m_dst.regOpReg.regNum = (uint8_t)regNum;
647         m_dst.regOpRgn.setDstHz(rgnH);
648         m_dst.regOpMathMacroExtReg = mme;
649         m_dst.type = ty;
650     }
InstDstOpRegMathMacroExtReg(const Loc & loc,const RegInfo & ri,int regNum,MathMacroExt mme,Region::Horz rgnH,Type ty)651     void InstDstOpRegMathMacroExtReg(
652         const Loc &loc,
653         const RegInfo &ri,
654         int regNum,
655         MathMacroExt mme,
656         Region::Horz rgnH,
657         Type ty)
658     {
659         InstDstOpRegMathMacroExtReg(loc, ri.regName, regNum, mme, rgnH, ty);
660     }
661 
662     // e.g. r[a0.4,16]<2>:t
InstDstOpRegIndirect(const Loc & loc,RegRef addrReg,int addrOff,Region::Horz rgnHorz,Type ty)663     void InstDstOpRegIndirect(
664         const Loc &loc,
665         RegRef addrReg,
666         int addrOff,
667         Region::Horz rgnHorz,
668         Type ty)
669     {
670         m_dst.kind = Operand::Kind::INDIRECT;
671         m_dst.loc = loc;
672 
673         m_dst.regOpDstMod = m_dstModifier;
674         m_dst.regOpName = RegName::GRF_R;
675         m_dst.regOpReg = addrReg;
676         m_dst.regOpIndOff = (uint16_t)addrOff;
677         m_dst.regOpRgn.setDstHz(rgnHorz);
678         m_dst.type = ty;
679     }
680 
681     // a more generic setter
InstDstOp(const OperandInfo & opInfo)682     void InstDstOp(const OperandInfo &opInfo) {
683         m_dst = opInfo;
684         validateOperandInfo(opInfo);
685     }
686 
687     /////////////////////////////////////////////
688     // source operand callbacks
689 
690     // Direct register source operand
691     //
692     // e.g. r13.4<2>:t
InstSrcOpRegDirect(int srcOpIx,const Loc & loc,RegName rnm,int reg,Region rgn,Type ty)693     void InstSrcOpRegDirect(
694         int srcOpIx, // index of the current source operand
695         const Loc &loc,
696         RegName rnm, // the type of register
697         int reg, // register/subregister
698         Region rgn, // region parameters
699         Type ty)
700     {
701         RegRef rr((uint8_t)reg, 0);
702         InstSrcOpRegDirect(srcOpIx, loc, SrcModifier::NONE, rnm, rr, rgn, ty);
703     }
InstSrcOpRegDirect(int srcOpIx,const Loc & loc,SrcModifier srcMod,RegName rnm,RegRef rr,Region rgn,Type ty)704     void InstSrcOpRegDirect(
705         int srcOpIx, // index of the current source operand
706         const Loc &loc,
707         SrcModifier srcMod, // source modifiers on this operand
708         RegName rnm, // the type of register
709         RegRef rr, // register/subregister
710         Region rgn, // region parameters
711         Type ty)
712     {
713         OperandInfo src = m_srcs[srcOpIx]; // copy init values
714         src.loc = loc;
715         src.kind = Operand::Kind::DIRECT;
716         src.regOpSrcMod = srcMod;
717         src.regOpName = rnm;
718         src.regOpReg = rr;
719         src.regOpRgn = rgn;
720         src.type = ty;
721 
722         InstSrcOp(srcOpIx, src);
723     }
724     // math macro register access
725     //
726     // e.g. r13.acc4:t
InstSrcOpRegMathMacroExtReg(int srcOpIx,const Loc & loc,SrcModifier srcMod,RegName rnm,int regNum,MathMacroExt MathMacroExt,Region rgn,Type ty)727     void InstSrcOpRegMathMacroExtReg(
728         int srcOpIx, // index of the current source operand
729         const Loc &loc,
730         SrcModifier srcMod, // source modifiers on this operand
731         RegName rnm, // the type of register
732         int regNum,
733         MathMacroExt MathMacroExt,
734         Region rgn,
735         Type ty)
736     {
737         OperandInfo src = m_srcs[srcOpIx]; // copy init values
738         src.loc = loc;
739         src.kind = Operand::Kind::MACRO;
740         src.regOpSrcMod = srcMod;
741         src.regOpName = rnm;
742         src.regOpReg.regNum = (uint8_t)regNum;
743         src.regOpReg.subRegNum = 0;
744         src.regOpRgn = rgn;
745         src.regOpMathMacroExtReg = MathMacroExt;
746         src.type = ty;
747 
748         InstSrcOp(srcOpIx, src);
749     }
750     // parsed a source indirect operand
751     //
752     // e.g. "r[a0.4,16]<1,0>:f"
InstSrcOpRegIndirect(int srcOpIx,const Loc & loc,const SrcModifier & srcMod,RegName regName,RegRef addrReg,int addrOff,Region rgn,Type ty)753     void InstSrcOpRegIndirect(
754         int srcOpIx, // index of the current source operand
755         const Loc &loc,
756         const SrcModifier &srcMod, // source modifiers on this operand
757         RegName regName,
758         RegRef addrReg,
759         int addrOff, // e.g. 16 in r[a0.3,16] (0 if absent)
760         Region rgn,
761         Type ty)
762     {
763         OperandInfo src = m_srcs[srcOpIx]; // copy init values
764         src.loc = loc;
765         src.kind = Operand::Kind::INDIRECT;
766         src.regOpSrcMod = srcMod;
767         src.regOpName = RegName::GRF_R;
768         src.regOpReg = addrReg;
769         src.regOpIndOff = (uint16_t)addrOff;
770         src.regOpRgn = rgn;
771         src.type = ty;
772 
773         InstSrcOp(srcOpIx, src);
774     }
775 
776 
777     // Called on a source immediate operand.  Some immedidate operands
778     // will not have explicit types.  E.g. send descriptors.
779     //
780     // e.g. 14:d
781     //      0x21424
InstSrcOpImmValue(int srcOpIx,const Loc & loc,const ImmVal & val,Type ty)782     void InstSrcOpImmValue(
783         int srcOpIx,
784         const Loc &loc,
785         const ImmVal &val,
786         Type ty)
787     {
788         OperandInfo src = m_srcs[srcOpIx]; // copy init values
789         src.loc = loc;
790         src.kind = Operand::Kind::IMMEDIATE;
791         src.immValue = val;
792         src.type = ty;
793 
794         InstSrcOp(srcOpIx, src);
795     }
796 
797 
798     // Called when an immediate label is encountered (e.g. on branches)
InstSrcOpImmLabel(int srcOpIx,const Loc & loc,const std::string & sym,Type type)799     void InstSrcOpImmLabel(
800         int srcOpIx,
801         const Loc &loc,
802         const std::string &sym,
803         Type type)
804     {
805         OperandInfo src = m_srcs[srcOpIx]; // copy init values
806         src.loc = loc;
807         src.kind = Operand::Kind::LABEL;
808         src.immLabel = sym;
809         src.type = type;
810 
811         InstSrcOp(srcOpIx, src);
812     }
813 
814 
815     // almost all cases
InstSrcOpImmLabelRelative(int srcOpIx,const Loc & loc,int64_t relPc,Type type)816     void InstSrcOpImmLabelRelative(
817       int srcOpIx,
818       const Loc &loc,
819       int64_t relPc,
820       Type type)
821     {
822         // NOTE: even though jmpi is relative post-increment, remember
823         // that IGA keeps the offsets normalized as pre-increment and in
824         // bytes for uniformity (HSW had some QWord labels)
825         // (after XE jmpi is also pre-increment)
826 
827         OperandInfo src = m_srcs[srcOpIx]; // copy init values
828         src.loc = loc;
829         src.kind = Operand::Kind::LABEL;
830         src.immValue = relPc;
831         src.type = type;
832 
833         InstSrcOp(srcOpIx, src);
834     }
835 
836 
837     // calla directly calls this, everything else goes through relative
838     // (see above)
InstSrcOpImmLabelAbsolute(int srcOpIx,const Loc & loc,int64_t absPc,Type type)839     void InstSrcOpImmLabelAbsolute(
840       int srcOpIx,
841       const Loc &loc,
842       int64_t absPc, // the actual PC relative to program start
843       Type type)
844     {
845         OperandInfo src = m_srcs[srcOpIx]; // copy init values
846         src.loc = loc;
847         src.kind = Operand::Kind::LABEL;
848         src.immValue = absPc;
849         src.type = type;
850 
851         InstSrcOp(srcOpIx, src);
852     }
853 
854 
855     // a more generic setter
InstSrcOp(int srcOpIx,const OperandInfo & opInfo)856     void InstSrcOp(int srcOpIx, const OperandInfo &opInfo) {
857         m_nSrcs = m_nSrcs < srcOpIx + 1 ? srcOpIx + 1 : m_nSrcs;
858 
859         validateOperandInfo(opInfo);
860         m_srcs[srcOpIx] = opInfo;
861     }
862 
validateOperandInfo(const OperandInfo & opInfo)863     void validateOperandInfo(const OperandInfo &opInfo) {
864 #ifdef _DEBUG
865         // some sanity validation
866         switch (opInfo.kind) {
867         case Operand::Kind::DIRECT:
868         case Operand::Kind::MACRO:
869         case Operand::Kind::INDIRECT:
870         case Operand::Kind::IMMEDIATE:
871         case Operand::Kind::LABEL:
872             break;
873         default:
874             IGA_ASSERT_FALSE("OperandInfo::kind: invalid value");
875             break;
876         }
877 #endif
878     }
879 
880     // send descriptors
881     // E.g. "send ... 0xC  a0.0"
882     // (we translate  this to:  a0.0<0;1,0>:ud)
InstSendDescs(const Loc &,const SendDesc & exDesc,const Loc &,const SendDesc & desc)883     void InstSendDescs(
884         const Loc &,
885         const SendDesc &exDesc,
886         const Loc &,
887         const SendDesc &desc)
888     {
889         m_exDesc = exDesc;
890         m_desc = desc;
891     }
892 
InstSendSrc0Length(int src0Length)893     void InstSendSrc0Length(int src0Length) {
894         m_sendSrc0Len = src0Length;
895     }
InstSendSrc1Length(int src1Length)896     void InstSendSrc1Length(int src1Length) {
897         m_sendSrc1Len = src1Length;
898     }
899 
900     ///////////////////////////////////////////////////////////////////////////
901     // instruction option callbacks
InstOptsAdd(const InstOptSet & instOpts)902     void InstOptsAdd(const InstOptSet &instOpts) {
903         m_instOpts.add(instOpts);
904     }
905 
InstOptAdd(InstOpt instOpt)906     void InstOptAdd(InstOpt instOpt) {
907         m_instOpts.add(instOpt);
908     }
909 
InstDepInfoSBidSrc(Loc loc,int32_t sbid)910     void InstDepInfoSBidSrc(Loc loc, int32_t sbid) {
911         if (sbid > (int32_t)m_model.getMaxSWSBTokenNum())
912             m_errorHandler.reportError(loc, "Invalid SWSB ID number");
913         if (m_depInfo.anyBarrierSet())
914             m_errorHandler.reportError(loc, "More than one SWSB barrier set");
915 
916         m_depInfo.memSBidSrc = sbid;
917     }
918 
InstDepInfoSBidDst(Loc loc,int32_t sbid)919     void InstDepInfoSBidDst(Loc loc, int32_t sbid) {
920         if (sbid > (int32_t)m_model.getMaxSWSBTokenNum())
921             m_errorHandler.reportError(loc, "Invalid SWSB ID number");
922         if (m_depInfo.anyBarrierSet())
923             m_errorHandler.reportError(loc, "More than one SWSB barrier set");
924 
925         m_depInfo.memSBidDst = sbid;
926     }
927 
InstDepInfoSBidAlloc(Loc loc,int32_t sbid)928     void InstDepInfoSBidAlloc(Loc loc, int32_t sbid) {
929         if (sbid > (int32_t)m_model.getMaxSWSBTokenNum())
930             m_errorHandler.reportError(loc, "Invalid SWSB ID number");
931         if (m_depInfo.anyBarrierSet())
932             m_errorHandler.reportError(loc, "More than one SWSB barrier set");
933 
934         m_depInfo.memSBidAlloc = sbid;
935     }
936 
InstDepInfoDist(Loc loc,SWSB::DistType type,uint32_t dist)937     void InstDepInfoDist(Loc loc, SWSB::DistType type, uint32_t dist) {
938         if (dist > m_model.getSWSBMaxValidDistance())
939             m_errorHandler.reportError(loc, "Invalid SWSB distance number");
940         if (m_depInfo.distType != SWSB::DistType::NO_DIST)
941             m_errorHandler.reportError(loc, "More than one SWSB distance set");
942         m_depInfo.distType = type;
943         m_depInfo.regDist = dist;
944     }
945 
InstDepInfoSpecialToken(Loc loc,SWSB::SpecialToken token)946     void InstDepInfoSpecialToken(Loc loc, SWSB::SpecialToken token) {
947         m_depInfo.spToken = token;
948     }
949 
950     ///////////////////////////////////////////////
951     // for decoding from binary
InstSwsb(Loc loc,SWSB swsb)952     void InstSwsb(Loc loc, SWSB swsb) {
953         IGA_ASSERT(m_depInfo == SWSBInfo(), "resetting SWSB info");
954 
955         switch(swsb.tokenType) {
956         case SWSB::TokenType::NOTOKEN:
957             break;
958         case SWSB::TokenType::DST:
959             m_depInfo.memSBidDst = (int32_t)swsb.sbid;
960             break;
961         case SWSB::TokenType::SRC:
962             m_depInfo.memSBidSrc = (int32_t)swsb.sbid;
963             break;
964         case SWSB::TokenType::SET:
965             m_depInfo.memSBidAlloc = (int32_t)swsb.sbid;
966             break;
967         }
968 
969         m_depInfo.distType = swsb.distType;
970         if (swsb.distType != SWSB::DistType::NO_DIST)
971             m_depInfo.regDist = swsb.minDist;
972     }
973 
InstDpasDstOp(const Loc &,RegName rnm,RegRef reg,Type ty)974     void InstDpasDstOp(
975         const Loc &,
976         RegName rnm,
977         RegRef reg,
978         Type ty)
979     {
980         m_dst.kind = Operand::Kind::DIRECT;
981         m_dst.regOpDstMod = DstModifier::NONE;
982         m_dst.regOpName = rnm;
983         m_dst.regOpReg = reg;
984         m_dst.regOpRgn = m_opSpec->implicitDstRegion(false);
985         m_dst.type = ty;
986     }
InstDpasSrcOp(int srcOpIx,const Loc & loc,RegName rnm,RegRef reg,Type ty)987     void InstDpasSrcOp(
988         int srcOpIx,
989         const Loc &loc,
990         RegName rnm,
991         RegRef reg,
992         Type ty)
993     {
994         m_nSrcs = m_nSrcs < srcOpIx + 1 ? srcOpIx + 1 : m_nSrcs;
995 
996         m_srcs[srcOpIx].loc = loc;
997         m_srcs[srcOpIx].kind = Operand::Kind::DIRECT;
998         m_srcs[srcOpIx].regOpSrcMod = SrcModifier::NONE;
999         m_srcs[srcOpIx].regOpName = rnm;
1000         m_srcs[srcOpIx].regOpReg = reg;
1001         m_srcs[srcOpIx].regOpRgn =
1002             m_opSpec->implicitSrcRegion(srcOpIx, m_execSize, false);
1003         m_srcs[srcOpIx].type = ty;
1004     }
1005 
1006 
1007     // sets Instruction::setComment(...)
InstComment(std::string comment)1008     void InstComment(std::string comment)
1009     {
1010         m_comment = comment;
1011     }
1012 
1013 }; // class ParseHandler
1014 
1015 } // namespace
1016 
1017 #endif //_IR_BUILDER_HANDLER_HPP_
1018