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_BACKEND_NATIVE_INSTENCODER_HPP 10 #define IGA_BACKEND_NATIVE_INSTENCODER_HPP 11 12 #include "MInst.hpp" 13 #include "Field.hpp" 14 #include "../BitProcessor.hpp" 15 #include "../EncoderOpts.hpp" 16 #include "../../IR/Kernel.hpp" 17 #include "../../asserts.hpp" 18 #include "../../bits.hpp" 19 #include "../../strings.hpp" 20 // 21 #include <cstdint> 22 #include <functional> 23 #include <sstream> 24 #include <string> 25 #include <vector> 26 // 27 #ifdef _DEBUG 28 // IGA_IGA_VALIDATE_BITS adds extra structures and code to ensure that each bit 29 // the instruction encoded gets written at most once. This can catch 30 // accidental field overlaps quite effectively. 31 // 32 // The neceessary assumption follows that encoders must not get lazy or sloppy 33 // and just clobber bits. Set it once only. 34 #define IGA_VALIDATE_BITS 35 #endif 36 37 38 namespace iga 39 { 40 // immLo <= offset < immHi rangeContains(int immLo,int immHi,int offset)41 static inline bool rangeContains(int immLo, int immHi, int offset) { 42 return immLo <= offset && offset < immHi; 43 } 44 45 struct InstEncoderState 46 { 47 int instIndex = 0; 48 const Instruction* inst = nullptr; 49 #ifdef IGA_VALIDATE_BITS 50 // All the bit fields set by some field during this instruction encoding 51 // e.g. if a field with bits [127:96] is set to 00000000....0001b 52 // this bit mask will contain 1111....111b's for that field 53 // This allows us to detect writing to two overlapped fields, which 54 // indicates an internal logical error in the encoder. 55 MInst dirty; 56 // This contains a list of all the fields we set during an instruction 57 // encoding so we can run through the list and determine which fields 58 // overlapped. 59 std::vector<const Fragment *> fragmentsSet; 60 #endif InstEncoderStateiga::InstEncoderState61 InstEncoderState( 62 int _instIndex 63 , const Instruction *_inst 64 #ifdef IGA_VALIDATE_BITS 65 , const MInst &_dirty 66 , const std::vector<const Fragment*> &_fieldsSet 67 #endif 68 ) 69 : instIndex(_instIndex) 70 , inst(_inst) 71 #ifdef IGA_VALIDATE_BITS 72 , dirty(_dirty) 73 , fragmentsSet(_fieldsSet) 74 #endif 75 { 76 } InstEncoderStateiga::InstEncoderState77 InstEncoderState() { } 78 }; 79 80 struct Backpatch 81 { 82 InstEncoderState state; 83 const Block *target; 84 const Field &fragment; 85 enum Type {REL, ABS} type; 86 Backpatchiga::Backpatch87 Backpatch( 88 InstEncoderState &_state, 89 const Block *_target, 90 const Field &_field, 91 Type _type = REL) 92 : state(_state) 93 , target(_target) 94 , fragment(_field) 95 , type(_type) { } 96 // TODO: determine where copy construction used to eliminate 97 // Backpatch(const Backpatch&) = delete; 98 }; 99 typedef std::vector<Backpatch> BackpatchList; 100 101 // can be passed into the encoding if we want to know the result 102 struct CompactionDebugInfo { 103 std::vector<Op> fieldOps; // the op we were trying to compact 104 std::vector<const CompactionMapping *> fieldMisses; // which indices missed 105 std::vector<uint64_t> fieldMapping; // what we tried to match (parallel) 106 }; 107 enum class CompactionResult { 108 CR_SUCCESS, 109 CR_NO_COMPACT, // {NoCompact} (or -Xnoautocompact and {} 110 CR_NO_FORMAT, // e.g. send or jump 111 CR_NO_AUTOCOMPACT, // no annotation and {Compacted} not set 112 CR_MISS // fragment misses 113 }; 114 115 ////////////////////////////////////////////////////////// 116 // generic encoder for all platforms 117 // subclasses specialize the necessary functions 118 class InstEncoder : public BitProcessor 119 { 120 // the encoder options (e.g. for auto-compaction) 121 EncoderOpts opts; 122 // 123 // the platform we're encoding for 124 const Model &model; 125 // 126 // The target bits to encode to 127 MInst *bits = nullptr; 128 // 129 // A backpatch list that we can add to. A parent encoder is permitted 130 // to copy or shadow this list. Hence, this class may not assume the 131 // state is preserved between the calls of encodeInstruction and 132 // resolveBackpatch. 133 BackpatchList backpatches; 134 // 135 // state used by the encoder (can be saved for backpatches) 136 InstEncoderState state; 137 public: InstEncoder(const EncoderOpts & _opts,BitProcessor & _parent,const Model & _model)138 InstEncoder( 139 const EncoderOpts &_opts, 140 BitProcessor &_parent, 141 const Model &_model) 142 : BitProcessor(_parent) 143 , opts(_opts) 144 , model(_model) { } 145 InstEncoder(const InstEncoder&) = delete; 146 getBackpatches()147 BackpatchList &getBackpatches() {return backpatches;} 148 getInst() const149 const Instruction &getInst() const {return *state.inst;} getOpSpec() const150 const OpSpec &getOpSpec() const {return getInst().getOpSpec();} getModel() const151 const Model &getModel() const {return model;} platform() const152 Platform platform() const {return getModel().platform;} 153 154 // void setBits(MInst mi) {*bits = mi;} 155 // MInst getBits() const {return *bits;} 156 157 //////////////////////////////////////////////////////////////////////// 158 // external interface (called by parent encoder; e.g. SerialEncoder) // 159 //////////////////////////////////////////////////////////////////////// 160 161 // Called externally by our parent encoder algorithm to start the encoding 162 // of an instruction. The instruction size is determined by the compaction 163 // bit in the target instruction. encodeInstruction(int ix,const Instruction & i,MInst * _bits)164 void encodeInstruction( 165 int ix, 166 const Instruction &i, 167 MInst *_bits) 168 { 169 setCurrInst(&i); 170 171 state.instIndex = ix; 172 state.inst = &i; 173 #ifdef IGA_VALIDATE_BITS 174 state.dirty.qw0 = 0; 175 state.dirty.qw1 = 0; 176 state.fragmentsSet.clear(); 177 #endif 178 memset(_bits, 0, sizeof(*_bits)); 179 bits = _bits; 180 encodeForPlatform(i); 181 } 182 resolveBackpatch(Backpatch & bp,MInst * _bits)183 void resolveBackpatch(Backpatch &bp, MInst *_bits) { 184 bits = _bits; 185 state = bp.state; 186 setCurrInst(bp.state.inst); 187 if (bp.type == Backpatch::ABS) { 188 encode(bp.fragment, bp.target->getPC()); 189 } else { 190 encode(bp.fragment, bp.target->getPC() - bp.state.inst->getPC()); 191 } 192 } 193 194 ////////////////////////////////////////////////////// 195 // internal (to the encoder package, not private) instances of 196 // encodeForPlatform<P> and their subtrees will call these methods. 197 ////////////////////////////////////////////////////// registerBackpatch(const Field & f,const Block * b,Backpatch::Type t=Backpatch::Type::REL)198 void registerBackpatch( 199 const Field &f, 200 const Block *b, 201 Backpatch::Type t = Backpatch::Type::REL) 202 { 203 backpatches.emplace_back(state, b, f, t); 204 } 205 encode(const Field & f,int32_t val)206 void encode(const Field &f, int32_t val) {encodeFieldBits(f, (uint32_t)val);} encode(const Field & f,int64_t val)207 void encode(const Field &f, int64_t val) {encodeFieldBits(f, (uint64_t)val);} encode(const Field & f,uint32_t val)208 void encode(const Field &f, uint32_t val) {encodeFieldBits(f, (uint64_t)val);} encode(const Field & f,uint64_t val)209 void encode(const Field &f, uint64_t val) {encodeFieldBits(f, val);} encode(const Field & f,bool val)210 void encode(const Field &f, bool val) {encodeFieldBits(f, val ? 1 : 0);} 211 void encode(const Field &f, const OpSpec &os); 212 void encode(const Field &f, ExecSize es); 213 void encode(const Field &f, MathMacroExt acc); 214 void encode(const Field &f, Region::Vert vt); 215 void encode(const Field &f, Region::Width wi); 216 void encode(const Field &f, Region::Horz hz); 217 void encode(const Field &f, SrcModifier mods); 218 template <OpIx IX> 219 void encodeSubreg( 220 const Field &f, 221 RegName reg, 222 RegRef rr, 223 Type ty); 224 void encodeReg( 225 const Field &fREGFILE, 226 const Field &fREG, 227 RegName reg, 228 int regNum); 229 230 ////////////////////////////////////////////////////// 231 // Helper Functions 232 ////////////////////////////////////////////////////// 233 void encodeFieldBits(const Field &f, uint64_t val0); 234 encodingError(const std::string & msg)235 void encodingError(const std::string &msg) { 236 encodingError("", msg); 237 } encodingError(const Field * f,const std::string & msg)238 void encodingError(const Field *f, const std::string &msg) { 239 encodingError(f ? f->name : "", msg); 240 } encodingError(const Field & f,const std::string & msg)241 void encodingError(const Field &f, const std::string &msg) { 242 encodingError(f.name, msg); 243 } encodingError(OpIx ix,const std::string & msg)244 void encodingError(OpIx ix, const std::string &msg) { 245 encodingError(ToStringOpIx(ix), msg); 246 } encodingError(const std::string & ctx,const std::string & msg)247 void encodingError(const std::string &ctx, const std::string &msg) { 248 if (ctx.empty()) { 249 errorT(msg); 250 } else { 251 errorT(ctx, ": ", msg); 252 } 253 } internalErrorBadIR(const std::string & what)254 void internalErrorBadIR(const std::string &what) { 255 errorT("INTERNAL ERROR: malformed IR: ", what); 256 } internalErrorBadIR(const Field & f,const char * msg=nullptr)257 void internalErrorBadIR(const Field &f, const char *msg = nullptr) { 258 if (msg) { 259 internalErrorBadIR(iga::format(f.name, ": ", msg)); 260 } else { 261 internalErrorBadIR(f.name); 262 } 263 } 264 265 template <typename T> encodeEnum(const Field & f,T lo,T hi,T x)266 void encodeEnum(const Field &f, T lo, T hi, T x) { 267 if (x < lo || x > hi) { 268 encodingError(f, "invalid value"); 269 } 270 encodeFieldBits(f, static_cast<uint64_t>(x)); 271 } 272 private: 273 #ifdef IGA_VALIDATE_BITS 274 void reportFieldOverlap(const Fragment &fr); 275 #endif 276 private: 277 void encodeForPlatform(const Instruction &i); 278 void encodeForPlatformFamilyXE(const Instruction &i); 279 }; // end class InstEncoder 280 281 /////////////////////////////////////////////////////////////////////////// 282 // longer method implementations (declared above) 283 /////////////////////////////////////////////////////////////////////////// 284 encode(const Field & f,const OpSpec & os)285 inline void InstEncoder::encode(const Field &f, const OpSpec &os) 286 { 287 if (!os.isValid()) { 288 encodingError(f, "invalid opcode"); 289 } 290 encodeFieldBits(f, os.opcode); 291 } 292 293 #define ENCODING_CASE(X, V) case X: val = (V); break encode(const Field & f,ExecSize es)294 inline void InstEncoder::encode(const Field &f, ExecSize es) 295 { 296 uint64_t val = 0; 297 switch (es) { 298 ENCODING_CASE(ExecSize::SIMD1, 0); 299 ENCODING_CASE(ExecSize::SIMD2, 1); 300 ENCODING_CASE(ExecSize::SIMD4, 2); 301 ENCODING_CASE(ExecSize::SIMD8, 3); 302 ENCODING_CASE(ExecSize::SIMD16, 4); 303 ENCODING_CASE(ExecSize::SIMD32, 5); 304 default: internalErrorBadIR(f); 305 } 306 encodeFieldBits(f, val); 307 } 308 309 // encodes this as an math macro operand reference (e.g. r12.mme2) 310 // *not* as an explicit operand (for context save and restore) encode(const Field & f,MathMacroExt mme)311 inline void InstEncoder::encode(const Field &f, MathMacroExt mme) { 312 uint64_t val = 0; 313 switch (mme) { 314 ENCODING_CASE(MathMacroExt::MME0, 0x0); 315 ENCODING_CASE(MathMacroExt::MME1, 0x1); 316 ENCODING_CASE(MathMacroExt::MME2, 0x2); 317 ENCODING_CASE(MathMacroExt::MME3, 0x3); 318 ENCODING_CASE(MathMacroExt::MME4, 0x4); 319 ENCODING_CASE(MathMacroExt::MME5, 0x5); 320 ENCODING_CASE(MathMacroExt::MME6, 0x6); 321 ENCODING_CASE(MathMacroExt::MME7, 0x7); 322 ENCODING_CASE(MathMacroExt::NOMME, 0x8); 323 default: internalErrorBadIR(f); 324 } 325 encodeFieldBits(f, val); 326 } 327 encode(const Field & f,Region::Vert vt)328 inline void InstEncoder::encode(const Field &f, Region::Vert vt) 329 { 330 uint64_t val = 0; 331 switch (vt) { 332 ENCODING_CASE(Region::Vert::VT_0, 0x0); 333 ENCODING_CASE(Region::Vert::VT_1, 0x1); 334 ENCODING_CASE(Region::Vert::VT_2, 0x2); 335 ENCODING_CASE(Region::Vert::VT_4, 0x3); 336 ENCODING_CASE(Region::Vert::VT_8, 0x4); 337 ENCODING_CASE(Region::Vert::VT_16, 0x5); 338 ENCODING_CASE(Region::Vert::VT_32, 0x6); 339 case Region::Vert::VT_VxH: 340 val = 0xF; 341 if (f.encodedLength() == 3) { 342 val = 0x7; // XeHPC+ 343 } 344 break; 345 default: internalErrorBadIR(f); 346 } 347 encodeFieldBits(f, val); 348 } 349 encode(const Field & f,Region::Width wi)350 inline void InstEncoder::encode(const Field &f, Region::Width wi) { 351 uint64_t val = 0; 352 switch (wi) { 353 ENCODING_CASE(Region::Width::WI_1, 0x0); 354 ENCODING_CASE(Region::Width::WI_2, 0x1); 355 ENCODING_CASE(Region::Width::WI_4, 0x2); 356 ENCODING_CASE(Region::Width::WI_8, 0x3); 357 ENCODING_CASE(Region::Width::WI_16, 0x4); 358 default: internalErrorBadIR(f); 359 } 360 encodeFieldBits(f, val); 361 } 362 encode(const Field & f,Region::Horz hz)363 inline void InstEncoder::encode(const Field &f, Region::Horz hz) { 364 uint64_t val = 0; 365 switch (hz) { 366 ENCODING_CASE(Region::Horz::HZ_0, 0); 367 ENCODING_CASE(Region::Horz::HZ_1, 1); 368 ENCODING_CASE(Region::Horz::HZ_2, 2); 369 ENCODING_CASE(Region::Horz::HZ_4, 3); 370 default: internalErrorBadIR(f); 371 } 372 encodeFieldBits(f, val); 373 } 374 encode(const Field & f,SrcModifier mods)375 inline void InstEncoder::encode(const Field &f, SrcModifier mods) { 376 uint64_t val = 0; 377 switch (mods) { 378 ENCODING_CASE(SrcModifier::NONE, 0x0); 379 ENCODING_CASE(SrcModifier::ABS, 0x1); 380 ENCODING_CASE(SrcModifier::NEG, 0x2); 381 ENCODING_CASE(SrcModifier::NEG_ABS, 0x3); 382 default: internalErrorBadIR(f); 383 } 384 encodeFieldBits(f, val); 385 } 386 #undef ENCODING_CASE 387 encodeReg(const Field & fREGFILE,const Field & fREG,RegName reg,int regNum)388 inline void InstEncoder::encodeReg( 389 const Field &fREGFILE, 390 const Field &fREG, 391 RegName reg, 392 int regNum) 393 { 394 const RegInfo *ri = model.lookupRegInfoByRegName(reg); 395 if (ri == nullptr) { 396 internalErrorBadIR(fREG, "unsupported register for platform"); 397 return; 398 } 399 uint8_t regNumBits = 0; 400 if (!ri->encode(regNum, regNumBits)) { 401 internalErrorBadIR(fREG, "invalid register"); 402 return; 403 } 404 encodeFieldBits(fREGFILE, reg == RegName::GRF_R ? 1 : 0); 405 encodeFieldBits(fREG, regNumBits); 406 } 407 408 template <OpIx IX> encodeSubreg(const Field & f,RegName reg,RegRef rr,Type ty)409 inline void InstEncoder::encodeSubreg( 410 const Field &f, RegName reg, RegRef rr, Type ty) 411 { 412 uint64_t val = (uint64_t)rr.subRegNum; 413 // branches have implicit :d 414 val = ty == Type::INVALID ? 4*val : 415 SubRegToBinaryOffset((int)val, reg, ty, model.platform); 416 if (platform() >= Platform::XE_HPC && 417 reg == RegName::ARF_FC) 418 { 419 val = 2 * val; 420 } 421 encodeFieldBits(f, val); 422 } 423 424 encodeForPlatform(const Instruction & i)425 inline void InstEncoder::encodeForPlatform(const Instruction &i) 426 { 427 switch (platform()) { 428 case Platform::XE: 429 case Platform::XE_HP: 430 case Platform::XE_HPG: 431 case Platform::XE_HPC: 432 case Platform::FUTURE: 433 default: 434 // caller checks this and gives a soft error 435 IGA_ASSERT_FALSE("unsupported platform for native encoder"); 436 } 437 } 438 } // end iga::* 439 #endif /* IGA_BACKEND_NATIVE_INSTENCODER_HPP */ 440