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