4# Copyright (c) 2015 Advanced Micro Devices, Inc. 5# All rights reserved. 6# 7# For use for simulation and test purposes only 8# 9# Redistribution and use in source and binary forms, with or without 10# modification, are permitted provided that the following conditions are met: 11# 12# 1. Redistributions of source code must retain the above copyright notice, 13# this list of conditions and the following disclaimer. 14# 15# 2. Redistributions in binary form must reproduce the above copyright notice, 16# this list of conditions and the following disclaimer in the documentation 17# and/or other materials provided with the distribution. 18# 19# 3. Neither the name of the copyright holder nor the names of its contributors 20# may be used to endorse or promote products derived from this software 21# without specific prior written permission. 22# 23# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 27# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33# POSSIBILITY OF SUCH DAMAGE. 34# 35# Author: Steve Reinhardt 36# 37 38from __future__ import print_function 39 40import sys, re 41 42from m5.util import code_formatter 43 44if len(sys.argv) != 4: 45 print("Error: need 3 args (file names)") 46 sys.exit(0) 47 48header_code = code_formatter() 49decoder_code = code_formatter() 50exec_code = code_formatter() 51 52############### 53# 54# Generate file prologs (includes etc.) 55# 56############### 57 58header_code(''' 59#include "arch/hsail/insts/decl.hh" 60#include "base/bitfield.hh" 61#include "gpu-compute/hsail_code.hh" 62#include "gpu-compute/wavefront.hh" 63 64namespace HsailISA 65{ 66''') 67header_code.indent() 68 69decoder_code(''' 70#include "arch/hsail/gpu_decoder.hh" 71#include "arch/hsail/insts/branch.hh" 72#include "arch/hsail/insts/decl.hh" 73#include "arch/hsail/insts/gen_decl.hh" 74#include "arch/hsail/insts/mem.hh" 75#include "arch/hsail/insts/mem_impl.hh" 76#include "gpu-compute/brig_object.hh" 77 78namespace HsailISA 79{ 80 std::vector<GPUStaticInst*> Decoder::decodedInsts; 81 82 GPUStaticInst* 83 Decoder::decode(MachInst machInst) 84 { 85 using namespace Brig; 86 87 const BrigInstBase *ib = machInst.brigInstBase; 88 const BrigObject *obj = machInst.brigObj; 89 90 switch(ib->opcode) { 91''') 92decoder_code.indent() 93decoder_code.indent() 94 95exec_code(''' 96#include "arch/hsail/insts/gen_decl.hh" 97#include "base/intmath.hh" 98 99namespace HsailISA 100{ 101''') 102exec_code.indent() 103 104############### 105# 106# Define code templates for class declarations (for header file) 107# 108############### 109 110# Basic header template for an instruction stub. 111header_template_stub = ''' 112class $class_name : public $base_class 113{ 114 public: 115 typedef $base_class Base; 116 117 $class_name(const Brig::BrigInstBase *ib, const BrigObject *obj) 118 : Base(ib, obj, "$opcode") 119 { 120 } 121 122 void execute(GPUDynInstPtr gpuDynInst); 123}; 124 125''' 126 127# Basic header template for an instruction with no template parameters. 128header_template_nodt = ''' 129class $class_name : public $base_class 130{ 131 public: 132 typedef $base_class Base; 133 134 $class_name(const Brig::BrigInstBase *ib, const BrigObject *obj) 135 : Base(ib, obj, "$opcode") 136 { 137 } 138 139 void execute(GPUDynInstPtr gpuDynInst); 140}; 141 142''' 143 144# Basic header template for an instruction with a single DataType 145# template parameter. 146header_template_1dt = ''' 147template<typename DataType> 148class $class_name : public $base_class<DataType> 149{ 150 public: 151 typedef $base_class<DataType> Base; 152 typedef typename DataType::CType CType; 153 154 $class_name(const Brig::BrigInstBase *ib, const BrigObject *obj) 155 : Base(ib, obj, "$opcode") 156 { 157 } 158 159 void execute(GPUDynInstPtr gpuDynInst); 160}; 161 162''' 163 164header_template_1dt_noexec = ''' 165template<typename DataType> 166class $class_name : public $base_class<DataType> 167{ 168 public: 169 typedef $base_class<DataType> Base; 170 typedef typename DataType::CType CType; 171 172 $class_name(const Brig::BrigInstBase *ib, const BrigObject *obj) 173 : Base(ib, obj, "$opcode") 174 { 175 } 176}; 177 178''' 179 180# Same as header_template_1dt, except the base class has a second 181# template parameter NumSrcOperands to allow a variable number of 182# source operands. Note that since this is implemented with an array, 183# it only works for instructions where all sources are of the same 184# type (like most arithmetics). 185header_template_1dt_varsrcs = ''' 186template<typename DataType> 187class $class_name : public $base_class<DataType, $num_srcs> 188{ 189 public: 190 typedef $base_class<DataType, $num_srcs> Base; 191 typedef typename DataType::CType CType; 192 193 $class_name(const Brig::BrigInstBase *ib, const BrigObject *obj) 194 : Base(ib, obj, "$opcode") 195 { 196 } 197 198 void execute(GPUDynInstPtr gpuDynInst); 199}; 200 201''' 202 203# Header template for instruction with two DataType template 204# parameters, one for the dest and one for the source. This is used 205# by compare and convert. 206header_template_2dt = ''' 207template<typename DestDataType, class SrcDataType> 208class $class_name : public $base_class<DestDataType, SrcDataType> 209{ 210 public: 211 typedef $base_class<DestDataType, SrcDataType> Base; 212 typedef typename DestDataType::CType DestCType; 213 typedef typename SrcDataType::CType SrcCType; 214 215 $class_name(const Brig::BrigInstBase *ib, const BrigObject *obj) 216 : Base(ib, obj, "$opcode") 217 { 218 } 219 220 void execute(GPUDynInstPtr gpuDynInst); 221}; 222 223''' 224 225header_templates = { 226 'ArithInst': header_template_1dt_varsrcs, 227 'CmovInst': header_template_1dt, 228 'ClassInst': header_template_1dt, 229 'ShiftInst': header_template_1dt, 230 'ExtractInsertInst': header_template_1dt, 231 'CmpInst': header_template_2dt, 232 'CvtInst': header_template_2dt, 233 'PopcountInst': header_template_2dt, 234 'LdInst': '', 235 'StInst': '', 236 'SpecialInstNoSrc': header_template_nodt, 237 'SpecialInst1Src': header_template_nodt, 238 'SpecialInstNoSrcNoDest': '', 239 'Stub': header_template_stub, 240} 241 242############### 243# 244# Define code templates for exec functions 245# 246############### 247 248# exec function body 249exec_template_stub = ''' 250void 251$class_name::execute(GPUDynInstPtr gpuDynInst) 252{ 253 fatal("instruction unimplemented %s\\n", gpuDynInst->disassemble()); 254} 255 256''' 257exec_template_nodt_nosrc = ''' 258void 259$class_name::execute(GPUDynInstPtr gpuDynInst) 260{ 261 Wavefront *w = gpuDynInst->wavefront(); 262 263 typedef Base::DestCType DestCType; 264 265 const VectorMask &mask = w->getPred(); 266 267 for (int lane = 0; lane < w->computeUnit->wfSize(); ++lane) { 268 if (mask[lane]) { 269 DestCType dest_val = $expr; 270 this->dest.set(w, lane, dest_val); 271 } 272 } 273} 274 275''' 276 277exec_template_nodt_1src = ''' 278void 279$class_name::execute(GPUDynInstPtr gpuDynInst) 280{ 281 Wavefront *w = gpuDynInst->wavefront(); 282 283 typedef Base::DestCType DestCType; 284 typedef Base::SrcCType SrcCType; 285 286 const VectorMask &mask = w->getPred(); 287 288 for (int lane = 0; lane < w->computeUnit->wfSize(); ++lane) { 289 if (mask[lane]) { 290 SrcCType src_val0 = this->src0.get<SrcCType>(w, lane); 291 DestCType dest_val = $expr; 292 293 this->dest.set(w, lane, dest_val); 294 } 295 } 296} 297 298''' 299 300exec_template_1dt_varsrcs = ''' 301template<typename DataType> 302void 303$class_name<DataType>::execute(GPUDynInstPtr gpuDynInst) 304{ 305 Wavefront *w = gpuDynInst->wavefront(); 306 307 const VectorMask &mask = w->getPred(); 308 309 for (int lane = 0; lane < w->computeUnit->wfSize(); ++lane) { 310 if (mask[lane]) { 311 CType dest_val; 312 if ($dest_is_src_flag) { 313 dest_val = this->dest.template get<CType>(w, lane); 314 } 315 316 CType src_val[$num_srcs]; 317 318 for (int i = 0; i < $num_srcs; ++i) { 319 src_val[i] = this->src[i].template get<CType>(w, lane); 320 } 321 322 dest_val = (CType)($expr); 323 324 this->dest.set(w, lane, dest_val); 325 } 326 } 327} 328 329''' 330 331exec_template_1dt_3srcs = ''' 332template<typename DataType> 333void 334$class_name<DataType>::execute(GPUDynInstPtr gpuDynInst) 335{ 336 Wavefront *w = gpuDynInst->wavefront(); 337 338 typedef typename Base::Src0CType Src0T; 339 typedef typename Base::Src1CType Src1T; 340 typedef typename Base::Src2CType Src2T; 341 342 const VectorMask &mask = w->getPred(); 343 344 for (int lane = 0; lane < w->computeUnit->wfSize(); ++lane) { 345 if (mask[lane]) { 346 CType dest_val; 347 348 if ($dest_is_src_flag) { 349 dest_val = this->dest.template get<CType>(w, lane); 350 } 351 352 Src0T src_val0 = this->src0.template get<Src0T>(w, lane); 353 Src1T src_val1 = this->src1.template get<Src1T>(w, lane); 354 Src2T src_val2 = this->src2.template get<Src2T>(w, lane); 355 356 dest_val = $expr; 357 358 this->dest.set(w, lane, dest_val); 359 } 360 } 361} 362 363''' 364 365exec_template_1dt_2src_1dest = ''' 366template<typename DataType> 367void 368$class_name<DataType>::execute(GPUDynInstPtr gpuDynInst) 369{ 370 Wavefront *w = gpuDynInst->wavefront(); 371 372 typedef typename Base::DestCType DestT; 373 typedef CType Src0T; 374 typedef typename Base::Src1CType Src1T; 375 376 const VectorMask &mask = w->getPred(); 377 378 for (int lane = 0; lane < w->computeUnit->wfSize(); ++lane) { 379 if (mask[lane]) { 380 DestT dest_val; 381 if ($dest_is_src_flag) { 382 dest_val = this->dest.template get<DestT>(w, lane); 383 } 384 Src0T src_val0 = this->src0.template get<Src0T>(w, lane); 385 Src1T src_val1 = this->src1.template get<Src1T>(w, lane); 386 387 dest_val = $expr; 388 389 this->dest.set(w, lane, dest_val); 390 } 391 } 392} 393 394''' 395 396exec_template_shift = ''' 397template<typename DataType> 398void 399$class_name<DataType>::execute(GPUDynInstPtr gpuDynInst) 400{ 401 Wavefront *w = gpuDynInst->wavefront(); 402 403 const VectorMask &mask = w->getPred(); 404 for (int lane = 0; lane < w->computeUnit->wfSize(); ++lane) { 405 if (mask[lane]) { 406 CType dest_val; 407 408 if ($dest_is_src_flag) { 409 dest_val = this->dest.template get<CType>(w, lane); 410 } 411 412 CType src_val0 = this->src0.template get<CType>(w, lane); 413 uint32_t src_val1 = this->src1.template get<uint32_t>(w, lane); 414 415 dest_val = $expr; 416 417 this->dest.set(w, lane, dest_val); 418 } 419 } 420} 421 422''' 423 424exec_template_2dt = ''' 425template<typename DestDataType, class SrcDataType> 426void 427$class_name<DestDataType, SrcDataType>::execute(GPUDynInstPtr gpuDynInst) 428{ 429 Wavefront *w = gpuDynInst->wavefront(); 430 431 const VectorMask &mask = w->getPred(); 432 433 for (int lane = 0; lane < w->computeUnit->wfSize(); ++lane) { 434 if (mask[lane]) { 435 DestCType dest_val; 436 SrcCType src_val[$num_srcs]; 437 438 for (int i = 0; i < $num_srcs; ++i) { 439 src_val[i] = this->src[i].template get<SrcCType>(w, lane); 440 } 441 442 dest_val = $expr; 443 444 this->dest.set(w, lane, dest_val); 445 } 446 } 447} 448 449''' 450 451exec_templates = { 452 'ArithInst': exec_template_1dt_varsrcs, 453 'CmovInst': exec_template_1dt_3srcs, 454 'ExtractInsertInst': exec_template_1dt_3srcs, 455 'ClassInst': exec_template_1dt_2src_1dest, 456 'CmpInst': exec_template_2dt, 457 'CvtInst': exec_template_2dt, 458 'PopcountInst': exec_template_2dt, 459 'LdInst': '', 460 'StInst': '', 461 'SpecialInstNoSrc': exec_template_nodt_nosrc, 462 'SpecialInst1Src': exec_template_nodt_1src, 463 'SpecialInstNoSrcNoDest': '', 464 'Stub': exec_template_stub, 465} 466 467############### 468# 469# Define code templates for the decoder cases 470# 471############### 472 473# decode template for nodt-opcode case 474decode_nodt_template = ''' 475 case BRIG_OPCODE_$brig_opcode_upper: return $constructor(ib, obj);''' 476 477decode_case_prolog_class_inst = ''' 478 case BRIG_OPCODE_$brig_opcode_upper: 479 { 480 //const BrigOperandBase *baseOp = obj->getOperand(ib->operands[1]); 481 BrigType16_t type = ((BrigInstSourceType*)ib)->sourceType; 482 //switch (baseOp->kind) { 483 // case BRIG_OPERAND_REG: 484 // type = ((const BrigOperandReg*)baseOp)->type; 485 // break; 486 // case BRIG_OPERAND_IMMED: 487 // type = ((const BrigOperandImmed*)baseOp)->type; 488 // break; 489 // default: 490 // fatal("CLASS unrecognized kind of operand %d\\n", 491 // baseOp->kind); 492 //} 493 switch (type) {''' 494 495# common prolog for 1dt- or 2dt-opcode case: switch on data type 496decode_case_prolog = ''' 497 case BRIG_OPCODE_$brig_opcode_upper: 498 { 499 switch (ib->type) {''' 500 501# single-level decode case entry (for 1dt opcodes) 502decode_case_entry = \ 503' case BRIG_TYPE_$type_name: return $constructor(ib, obj);' 504 505decode_store_prolog = \ 506' case BRIG_TYPE_$type_name: {' 507 508decode_store_case_epilog = ''' 509 }''' 510 511decode_store_case_entry = \ 512' return $constructor(ib, obj);' 513 514# common epilog for type switch 515decode_case_epilog = ''' 516 default: fatal("$brig_opcode_upper: unrecognized type %d\\n", 517 ib->type); 518 } 519 } 520 break;''' 521 522# Additional templates for nested decode on a second type field (for 523# compare and convert). These are used in place of the 524# decode_case_entry template to create a second-level switch on on the 525# second type field inside each case of the first-level type switch. 526# Because the name and location of the second type can vary, the Brig 527# instruction type must be provided in $brig_type, and the name of the 528# second type field must be provided in $type_field. 529decode_case2_prolog = ''' 530 case BRIG_TYPE_$type_name: 531 switch (((Brig$brig_type*)ib)->$type2_field) {''' 532 533decode_case2_entry = \ 534' case BRIG_TYPE_$type2_name: return $constructor(ib, obj);' 535 536decode_case2_epilog = ''' 537 default: fatal("$brig_opcode_upper: unrecognized $type2_field %d\\n", 538 ((Brig$brig_type*)ib)->$type2_field); 539 } 540 break;''' 541 542# Figure out how many source operands an expr needs by looking for the 543# highest-numbered srcN value referenced. Since sources are numbered 544# starting at 0, the return value is N+1. 545def num_src_operands(expr): 546 if expr.find('src2') != -1: 547 return 3 548 elif expr.find('src1') != -1: 549 return 2 550 elif expr.find('src0') != -1: 551 return 1 552 else: 553 return 0 554 555############### 556# 557# Define final code generation methods 558# 559# The gen_nodt, and gen_1dt, and gen_2dt methods are the interface for 560# generating actual instructions. 561# 562############### 563 564# Generate class declaration, exec function, and decode switch case 565# for an brig_opcode with a single-level type switch. The 'types' 566# parameter is a list or tuple of types for which the instruction 567# should be instantiated. 568def gen(brig_opcode, types=None, expr=None, base_class='ArithInst', 569 type2_info=None, constructor_prefix='new ', is_store=False): 570 brig_opcode_upper = brig_opcode.upper() 571 class_name = brig_opcode 572 opcode = class_name.lower() 573 574 if base_class == 'ArithInst': 575 # note that expr must be provided with ArithInst so we can 576 # derive num_srcs for the template 577 assert expr 578 579 if expr: 580 # Derive several bits of info from expr. If expr is not used, 581 # this info will be irrelevant. 582 num_srcs = num_src_operands(expr) 583 # if the RHS expression includes 'dest', then we're doing an RMW 584 # on the reg and we need to treat it like a source 585 dest_is_src = expr.find('dest') != -1 586 dest_is_src_flag = str(dest_is_src).lower() # for C++ 587 if base_class in ['ShiftInst']: 588 expr = re.sub(r'\bsrc(\d)\b', r'src_val\1', expr) 589 elif base_class in ['ArithInst', 'CmpInst', 'CvtInst', 'PopcountInst']: 590 expr = re.sub(r'\bsrc(\d)\b', r'src_val[\1]', expr) 591 else: 592 expr = re.sub(r'\bsrc(\d)\b', r'src_val\1', expr) 593 expr = re.sub(r'\bdest\b', r'dest_val', expr) 594 595 # Strip template arguments off of base class before looking up 596 # appropriate templates 597 base_class_base = re.sub(r'<.*>$', '', base_class) 598 header_code(header_templates[base_class_base]) 599 600 if base_class.startswith('SpecialInst') or base_class.startswith('Stub'): 601 exec_code(exec_templates[base_class_base]) 602 elif base_class.startswith('ShiftInst'): 603 header_code(exec_template_shift) 604 else: 605 header_code(exec_templates[base_class_base]) 606 607 if not types or isinstance(types, str): 608 # Just a single type 609 constructor = constructor_prefix + class_name 610 decoder_code(decode_nodt_template) 611 else: 612 # multiple types, need at least one level of decode 613 if brig_opcode == 'Class': 614 decoder_code(decode_case_prolog_class_inst) 615 else: 616 decoder_code(decode_case_prolog) 617 if not type2_info: 618 if not is_store: 619 # single list of types, to basic one-level decode 620 for type_name in types: 621 full_class_name = '%s<%s>' % (class_name, type_name.upper()) 622 constructor = constructor_prefix + full_class_name 623 decoder_code(decode_case_entry) 624 else: 625 # single list of types, to basic one-level decode 626 for type_name in types: 627 decoder_code(decode_store_prolog) 628 type_size = int(re.findall(r'[0-9]+', type_name)[0]) 629 src_size = 32 630 type_type = type_name[0] 631 full_class_name = '%s<%s,%s>' % (class_name, \ 632 type_name.upper(), \ 633 '%s%d' % \ 634 (type_type.upper(), \ 635 type_size)) 636 constructor = constructor_prefix + full_class_name 637 decoder_code(decode_store_case_entry) 638 decoder_code(decode_store_case_epilog) 639 else: 640 # need secondary type switch (convert, compare) 641 # unpack extra info on second switch 642 (type2_field, types2) = type2_info 643 brig_type = 'Inst%s' % brig_opcode 644 for type_name in types: 645 decoder_code(decode_case2_prolog) 646 fmt = '%s<%s,%%s>' % (class_name, type_name.upper()) 647 for type2_name in types2: 648 full_class_name = fmt % type2_name.upper() 649 constructor = constructor_prefix + full_class_name 650 decoder_code(decode_case2_entry) 651 652 decoder_code(decode_case2_epilog) 653 654 decoder_code(decode_case_epilog) 655 656############### 657# 658# Generate instructions 659# 660############### 661 662# handy abbreviations for common sets of types 663 664# arithmetic ops are typically defined only on 32- and 64-bit sizes 665arith_int_types = ('S32', 'U32', 'S64', 'U64') 666arith_float_types = ('F32', 'F64') 667arith_types = arith_int_types + arith_float_types 668 669bit_types = ('B1', 'B32', 'B64') 670 671all_int_types = ('S8', 'U8', 'S16', 'U16') + arith_int_types 672 673# I think you might be able to do 'f16' memory ops too, but we'll 674# ignore them for now. 675mem_types = all_int_types + arith_float_types 676mem_atom_types = all_int_types + ('B32', 'B64') 677 678##### Arithmetic & logical operations 679gen('Add', arith_types, 'src0 + src1') 680gen('Sub', arith_types, 'src0 - src1') 681gen('Mul', arith_types, 'src0 * src1') 682gen('Div', arith_types, 'src0 / src1') 683gen('Min', arith_types, 'std::min(src0, src1)') 684gen('Max', arith_types, 'std::max(src0, src1)') 685gen('Gcnmin', arith_types, 'std::min(src0, src1)') 686 687gen('CopySign', arith_float_types, 688 'src1 < 0 ? -std::abs(src0) : std::abs(src0)') 689gen('Sqrt', arith_float_types, 'sqrt(src0)') 690gen('Floor', arith_float_types, 'floor(src0)') 691 692# "fast" sqrt... same as slow for us 693gen('Nsqrt', arith_float_types, 'sqrt(src0)') 694gen('Nrsqrt', arith_float_types, '1.0/sqrt(src0)') 695gen('Nrcp', arith_float_types, '1.0/src0') 696gen('Fract', arith_float_types, 697 '(src0 >= 0.0)?(src0-floor(src0)):(floor(src0)-src0)') 698 699gen('Ncos', arith_float_types, 'cos(src0)'); 700gen('Nsin', arith_float_types, 'sin(src0)'); 701 702gen('And', bit_types, 'src0 & src1') 703gen('Or', bit_types, 'src0 | src1') 704gen('Xor', bit_types, 'src0 ^ src1') 705 706gen('Bitselect', bit_types, '(src1 & src0) | (src2 & ~(uint64_t)src0)') 707gen('Popcount', ('U32',), '__builtin_popcount(src0)', 'PopcountInst', \ 708 ('sourceType', ('B32', 'B64'))) 709 710gen('Shl', arith_int_types, 'src0 << (unsigned)src1', 'ShiftInst') 711gen('Shr', arith_int_types, 'src0 >> (unsigned)src1', 'ShiftInst') 712 713# gen('Mul_hi', types=('s32','u32', '??')) 714# gen('Mul24', types=('s32','u32', '??')) 715gen('Rem', arith_int_types, 'src0 - ((src0 / src1) * src1)') 716 717gen('Abs', arith_types, 'std::abs(src0)') 718gen('Neg', arith_types, '-src0') 719 720gen('Mov', bit_types + arith_types, 'src0') 721gen('Not', bit_types, 'heynot(src0)') 722 723# mad and fma differ only in rounding behavior, which we don't emulate 724# also there's an integer form of mad, but not of fma 725gen('Mad', arith_types, 'src0 * src1 + src2') 726gen('Fma', arith_float_types, 'src0 * src1 + src2') 727 728#native floating point operations 729gen('Nfma', arith_float_types, 'src0 * src1 + src2') 730 731gen('Cmov', bit_types, 'src0 ? src1 : src2', 'CmovInst') 732gen('BitAlign', bit_types, '(src0 << src2)|(src1 >> (32 - src2))') 733gen('ByteAlign', bit_types, '(src0 << 8 * src2)|(src1 >> (32 - 8 * src2))') 734 735# see base/bitfield.hh 736gen('BitExtract', arith_int_types, 'bits(src0, src1, src1 + src2 - 1)', 737 'ExtractInsertInst') 738 739gen('BitInsert', arith_int_types, 'insertBits(dest, src1, src2, src0)', 740 'ExtractInsertInst') 741 742##### Compare 743gen('Cmp', ('B1', 'S32', 'U32', 'F32'), 'compare(src0, src1, this->cmpOp)', 744 'CmpInst', ('sourceType', arith_types + bit_types)) 745gen('Class', arith_float_types, 'fpclassify(src0,src1)','ClassInst') 746 747##### Conversion 748 749# Conversion operations are only defined on B1, not B32 or B64 750cvt_types = ('B1',) + mem_types 751 752gen('Cvt', cvt_types, 'src0', 'CvtInst', ('sourceType', cvt_types)) 753 754 755##### Load & Store 756gen('Lda', mem_types, base_class = 'LdInst', constructor_prefix='decode') 757gen('Ld', mem_types, base_class = 'LdInst', constructor_prefix='decode') 758gen('St', mem_types, base_class = 'StInst', constructor_prefix='decode', 759 is_store=True) 760gen('Atomic', mem_atom_types, base_class='StInst', constructor_prefix='decode') 761gen('AtomicNoRet', mem_atom_types, base_class='StInst', 762 constructor_prefix='decode') 763 764gen('Cbr', base_class = 'LdInst', constructor_prefix='decode') 765gen('Br', base_class = 'LdInst', constructor_prefix='decode') 766 767##### Special operations 768def gen_special(brig_opcode, expr, dest_type='U32'): 769 num_srcs = num_src_operands(expr) 770 if num_srcs == 0: 771 base_class = 'SpecialInstNoSrc<%s>' % dest_type 772 elif num_srcs == 1: 773 base_class = 'SpecialInst1Src<%s>' % dest_type 774 else: 775 assert false 776 777 gen(brig_opcode, None, expr, base_class) 778 779gen_special('WorkItemId', 'w->workItemId[src0][lane]') 780gen_special('WorkItemAbsId', 781 'w->workItemId[src0][lane] + (w->workGroupId[src0] * w->workGroupSz[src0])') 782gen_special('WorkGroupId', 'w->workGroupId[src0]') 783gen_special('WorkGroupSize', 'w->workGroupSz[src0]') 784gen_special('CurrentWorkGroupSize', 'w->workGroupSz[src0]') 785gen_special('GridSize', 'w->gridSz[src0]') 786gen_special('GridGroups', 787 'divCeil(w->gridSz[src0],w->workGroupSz[src0])') 788gen_special('LaneId', 'lane') 789gen_special('WaveId', 'w->wfId') 790gen_special('Clock', 'w->computeUnit->shader->tick_cnt', 'U64') 791 792# gen_special('CU'', ') 793 794gen('Ret', base_class='SpecialInstNoSrcNoDest') 795gen('Barrier', base_class='SpecialInstNoSrcNoDest') 796gen('MemFence', base_class='SpecialInstNoSrcNoDest') 797 798# Map magic instructions to the BrigSyscall opcode 799# Magic instructions are defined in magic.hh 800# 801# In the future, real HSA kernel system calls can be implemented and coexist 802# with magic instructions. 803gen('Call', base_class='SpecialInstNoSrcNoDest') 804 805# Stubs for unimplemented instructions: 806# These may need to be implemented at some point in the future, but 807# for now we just match the instructions with their operands. 808# 809# By defining stubs for these instructions, we can work with 810# applications that have them in dead/unused code paths. 811# 812# Needed for rocm-hcc compilations for HSA backends since 813# builtins-hsail library is `cat`d onto the generated kernels. 814# The builtins-hsail library consists of handcoded hsail functions 815# that __might__ be needed by the rocm-hcc compiler in certain binaries. 816gen('Bitmask', base_class='Stub') 817gen('Bitrev', base_class='Stub') 818gen('Firstbit', base_class='Stub') 819gen('Lastbit', base_class='Stub') 820gen('Unpacklo', base_class='Stub') 821gen('Unpackhi', base_class='Stub') 822gen('Pack', base_class='Stub') 823gen('Unpack', base_class='Stub') 824gen('Lerp', base_class='Stub') 825gen('Packcvt', base_class='Stub') 826gen('Unpackcvt', base_class='Stub') 827gen('Sad', base_class='Stub') 828gen('Sadhi', base_class='Stub') 829gen('Activelanecount', base_class='Stub') 830gen('Activelaneid', base_class='Stub') 831gen('Activelanemask', base_class='Stub') 832gen('Activelanepermute', base_class='Stub') 833gen('Groupbaseptr', base_class='Stub') 834gen('Signalnoret', base_class='Stub') 835 836############### 837# 838# Generate file epilogs 839# 840############### 841header_code(''' 842template<> 843inline void 844Abs<U32>::execute(GPUDynInstPtr gpuDynInst) 845{ 846 Wavefront *w = gpuDynInst->wavefront(); 847 848 const VectorMask &mask = w->getPred(); 849 850 for (int lane = 0; lane < w->computeUnit->wfSize(); ++lane) { 851 if (mask[lane]) { 852 CType dest_val; 853 CType src_val; 854 855 src_val = this->src[0].template get<CType>(w, lane); 856 857 dest_val = (CType)(src_val); 858 859 this->dest.set(w, lane, dest_val); 860 } 861 } 862} 863 864template<> 865inline void 866Abs<U64>::execute(GPUDynInstPtr gpuDynInst) 867{ 868 Wavefront *w = gpuDynInst->wavefront(); 869 870 const VectorMask &mask = w->getPred(); 871 872 for (int lane = 0; lane < w->computeUnit->wfSize(); ++lane) { 873 if (mask[lane]) { 874 CType dest_val; 875 CType src_val; 876 877 src_val = this->src[0].template get<CType>(w, lane); 878 879 dest_val = (CType)(src_val); 880 881 this->dest.set(w, lane, dest_val); 882 } 883 } 884} 885''') 886 887header_code.dedent() 888header_code(''' 889} // namespace HsailISA 890''') 891 892# close off main decode switch 893decoder_code.dedent() 894decoder_code.dedent() 895decoder_code(''' 896 default: fatal("unrecognized Brig opcode %d\\n", ib->opcode); 897 } // end switch(ib->opcode) 898 } // end decode() 899} // namespace HsailISA 900''') 901 902exec_code.dedent() 903exec_code(''' 904} // namespace HsailISA 905''') 906 907############### 908# 909# Output accumulated code to files 910# 911############### 912header_code.write(sys.argv[1]) 913decoder_code.write(sys.argv[2]) 914exec_code.write(sys.argv[3])
| 2# Copyright (c) 2015 Advanced Micro Devices, Inc. 3# All rights reserved. 4# 5# For use for simulation and test purposes only 6# 7# Redistribution and use in source and binary forms, with or without 8# modification, are permitted provided that the following conditions are met: 9# 10# 1. Redistributions of source code must retain the above copyright notice, 11# this list of conditions and the following disclaimer. 12# 13# 2. Redistributions in binary form must reproduce the above copyright notice, 14# this list of conditions and the following disclaimer in the documentation 15# and/or other materials provided with the distribution. 16# 17# 3. Neither the name of the copyright holder nor the names of its contributors 18# may be used to endorse or promote products derived from this software 19# without specific prior written permission. 20# 21# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 25# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31# POSSIBILITY OF SUCH DAMAGE. 32# 33# Author: Steve Reinhardt 34# 35 36from __future__ import print_function 37 38import sys, re 39 40from m5.util import code_formatter 41 42if len(sys.argv) != 4: 43 print("Error: need 3 args (file names)") 44 sys.exit(0) 45 46header_code = code_formatter() 47decoder_code = code_formatter() 48exec_code = code_formatter() 49 50############### 51# 52# Generate file prologs (includes etc.) 53# 54############### 55 56header_code(''' 57#include "arch/hsail/insts/decl.hh" 58#include "base/bitfield.hh" 59#include "gpu-compute/hsail_code.hh" 60#include "gpu-compute/wavefront.hh" 61 62namespace HsailISA 63{ 64''') 65header_code.indent() 66 67decoder_code(''' 68#include "arch/hsail/gpu_decoder.hh" 69#include "arch/hsail/insts/branch.hh" 70#include "arch/hsail/insts/decl.hh" 71#include "arch/hsail/insts/gen_decl.hh" 72#include "arch/hsail/insts/mem.hh" 73#include "arch/hsail/insts/mem_impl.hh" 74#include "gpu-compute/brig_object.hh" 75 76namespace HsailISA 77{ 78 std::vector<GPUStaticInst*> Decoder::decodedInsts; 79 80 GPUStaticInst* 81 Decoder::decode(MachInst machInst) 82 { 83 using namespace Brig; 84 85 const BrigInstBase *ib = machInst.brigInstBase; 86 const BrigObject *obj = machInst.brigObj; 87 88 switch(ib->opcode) { 89''') 90decoder_code.indent() 91decoder_code.indent() 92 93exec_code(''' 94#include "arch/hsail/insts/gen_decl.hh" 95#include "base/intmath.hh" 96 97namespace HsailISA 98{ 99''') 100exec_code.indent() 101 102############### 103# 104# Define code templates for class declarations (for header file) 105# 106############### 107 108# Basic header template for an instruction stub. 109header_template_stub = ''' 110class $class_name : public $base_class 111{ 112 public: 113 typedef $base_class Base; 114 115 $class_name(const Brig::BrigInstBase *ib, const BrigObject *obj) 116 : Base(ib, obj, "$opcode") 117 { 118 } 119 120 void execute(GPUDynInstPtr gpuDynInst); 121}; 122 123''' 124 125# Basic header template for an instruction with no template parameters. 126header_template_nodt = ''' 127class $class_name : public $base_class 128{ 129 public: 130 typedef $base_class Base; 131 132 $class_name(const Brig::BrigInstBase *ib, const BrigObject *obj) 133 : Base(ib, obj, "$opcode") 134 { 135 } 136 137 void execute(GPUDynInstPtr gpuDynInst); 138}; 139 140''' 141 142# Basic header template for an instruction with a single DataType 143# template parameter. 144header_template_1dt = ''' 145template<typename DataType> 146class $class_name : public $base_class<DataType> 147{ 148 public: 149 typedef $base_class<DataType> Base; 150 typedef typename DataType::CType CType; 151 152 $class_name(const Brig::BrigInstBase *ib, const BrigObject *obj) 153 : Base(ib, obj, "$opcode") 154 { 155 } 156 157 void execute(GPUDynInstPtr gpuDynInst); 158}; 159 160''' 161 162header_template_1dt_noexec = ''' 163template<typename DataType> 164class $class_name : public $base_class<DataType> 165{ 166 public: 167 typedef $base_class<DataType> Base; 168 typedef typename DataType::CType CType; 169 170 $class_name(const Brig::BrigInstBase *ib, const BrigObject *obj) 171 : Base(ib, obj, "$opcode") 172 { 173 } 174}; 175 176''' 177 178# Same as header_template_1dt, except the base class has a second 179# template parameter NumSrcOperands to allow a variable number of 180# source operands. Note that since this is implemented with an array, 181# it only works for instructions where all sources are of the same 182# type (like most arithmetics). 183header_template_1dt_varsrcs = ''' 184template<typename DataType> 185class $class_name : public $base_class<DataType, $num_srcs> 186{ 187 public: 188 typedef $base_class<DataType, $num_srcs> Base; 189 typedef typename DataType::CType CType; 190 191 $class_name(const Brig::BrigInstBase *ib, const BrigObject *obj) 192 : Base(ib, obj, "$opcode") 193 { 194 } 195 196 void execute(GPUDynInstPtr gpuDynInst); 197}; 198 199''' 200 201# Header template for instruction with two DataType template 202# parameters, one for the dest and one for the source. This is used 203# by compare and convert. 204header_template_2dt = ''' 205template<typename DestDataType, class SrcDataType> 206class $class_name : public $base_class<DestDataType, SrcDataType> 207{ 208 public: 209 typedef $base_class<DestDataType, SrcDataType> Base; 210 typedef typename DestDataType::CType DestCType; 211 typedef typename SrcDataType::CType SrcCType; 212 213 $class_name(const Brig::BrigInstBase *ib, const BrigObject *obj) 214 : Base(ib, obj, "$opcode") 215 { 216 } 217 218 void execute(GPUDynInstPtr gpuDynInst); 219}; 220 221''' 222 223header_templates = { 224 'ArithInst': header_template_1dt_varsrcs, 225 'CmovInst': header_template_1dt, 226 'ClassInst': header_template_1dt, 227 'ShiftInst': header_template_1dt, 228 'ExtractInsertInst': header_template_1dt, 229 'CmpInst': header_template_2dt, 230 'CvtInst': header_template_2dt, 231 'PopcountInst': header_template_2dt, 232 'LdInst': '', 233 'StInst': '', 234 'SpecialInstNoSrc': header_template_nodt, 235 'SpecialInst1Src': header_template_nodt, 236 'SpecialInstNoSrcNoDest': '', 237 'Stub': header_template_stub, 238} 239 240############### 241# 242# Define code templates for exec functions 243# 244############### 245 246# exec function body 247exec_template_stub = ''' 248void 249$class_name::execute(GPUDynInstPtr gpuDynInst) 250{ 251 fatal("instruction unimplemented %s\\n", gpuDynInst->disassemble()); 252} 253 254''' 255exec_template_nodt_nosrc = ''' 256void 257$class_name::execute(GPUDynInstPtr gpuDynInst) 258{ 259 Wavefront *w = gpuDynInst->wavefront(); 260 261 typedef Base::DestCType DestCType; 262 263 const VectorMask &mask = w->getPred(); 264 265 for (int lane = 0; lane < w->computeUnit->wfSize(); ++lane) { 266 if (mask[lane]) { 267 DestCType dest_val = $expr; 268 this->dest.set(w, lane, dest_val); 269 } 270 } 271} 272 273''' 274 275exec_template_nodt_1src = ''' 276void 277$class_name::execute(GPUDynInstPtr gpuDynInst) 278{ 279 Wavefront *w = gpuDynInst->wavefront(); 280 281 typedef Base::DestCType DestCType; 282 typedef Base::SrcCType SrcCType; 283 284 const VectorMask &mask = w->getPred(); 285 286 for (int lane = 0; lane < w->computeUnit->wfSize(); ++lane) { 287 if (mask[lane]) { 288 SrcCType src_val0 = this->src0.get<SrcCType>(w, lane); 289 DestCType dest_val = $expr; 290 291 this->dest.set(w, lane, dest_val); 292 } 293 } 294} 295 296''' 297 298exec_template_1dt_varsrcs = ''' 299template<typename DataType> 300void 301$class_name<DataType>::execute(GPUDynInstPtr gpuDynInst) 302{ 303 Wavefront *w = gpuDynInst->wavefront(); 304 305 const VectorMask &mask = w->getPred(); 306 307 for (int lane = 0; lane < w->computeUnit->wfSize(); ++lane) { 308 if (mask[lane]) { 309 CType dest_val; 310 if ($dest_is_src_flag) { 311 dest_val = this->dest.template get<CType>(w, lane); 312 } 313 314 CType src_val[$num_srcs]; 315 316 for (int i = 0; i < $num_srcs; ++i) { 317 src_val[i] = this->src[i].template get<CType>(w, lane); 318 } 319 320 dest_val = (CType)($expr); 321 322 this->dest.set(w, lane, dest_val); 323 } 324 } 325} 326 327''' 328 329exec_template_1dt_3srcs = ''' 330template<typename DataType> 331void 332$class_name<DataType>::execute(GPUDynInstPtr gpuDynInst) 333{ 334 Wavefront *w = gpuDynInst->wavefront(); 335 336 typedef typename Base::Src0CType Src0T; 337 typedef typename Base::Src1CType Src1T; 338 typedef typename Base::Src2CType Src2T; 339 340 const VectorMask &mask = w->getPred(); 341 342 for (int lane = 0; lane < w->computeUnit->wfSize(); ++lane) { 343 if (mask[lane]) { 344 CType dest_val; 345 346 if ($dest_is_src_flag) { 347 dest_val = this->dest.template get<CType>(w, lane); 348 } 349 350 Src0T src_val0 = this->src0.template get<Src0T>(w, lane); 351 Src1T src_val1 = this->src1.template get<Src1T>(w, lane); 352 Src2T src_val2 = this->src2.template get<Src2T>(w, lane); 353 354 dest_val = $expr; 355 356 this->dest.set(w, lane, dest_val); 357 } 358 } 359} 360 361''' 362 363exec_template_1dt_2src_1dest = ''' 364template<typename DataType> 365void 366$class_name<DataType>::execute(GPUDynInstPtr gpuDynInst) 367{ 368 Wavefront *w = gpuDynInst->wavefront(); 369 370 typedef typename Base::DestCType DestT; 371 typedef CType Src0T; 372 typedef typename Base::Src1CType Src1T; 373 374 const VectorMask &mask = w->getPred(); 375 376 for (int lane = 0; lane < w->computeUnit->wfSize(); ++lane) { 377 if (mask[lane]) { 378 DestT dest_val; 379 if ($dest_is_src_flag) { 380 dest_val = this->dest.template get<DestT>(w, lane); 381 } 382 Src0T src_val0 = this->src0.template get<Src0T>(w, lane); 383 Src1T src_val1 = this->src1.template get<Src1T>(w, lane); 384 385 dest_val = $expr; 386 387 this->dest.set(w, lane, dest_val); 388 } 389 } 390} 391 392''' 393 394exec_template_shift = ''' 395template<typename DataType> 396void 397$class_name<DataType>::execute(GPUDynInstPtr gpuDynInst) 398{ 399 Wavefront *w = gpuDynInst->wavefront(); 400 401 const VectorMask &mask = w->getPred(); 402 for (int lane = 0; lane < w->computeUnit->wfSize(); ++lane) { 403 if (mask[lane]) { 404 CType dest_val; 405 406 if ($dest_is_src_flag) { 407 dest_val = this->dest.template get<CType>(w, lane); 408 } 409 410 CType src_val0 = this->src0.template get<CType>(w, lane); 411 uint32_t src_val1 = this->src1.template get<uint32_t>(w, lane); 412 413 dest_val = $expr; 414 415 this->dest.set(w, lane, dest_val); 416 } 417 } 418} 419 420''' 421 422exec_template_2dt = ''' 423template<typename DestDataType, class SrcDataType> 424void 425$class_name<DestDataType, SrcDataType>::execute(GPUDynInstPtr gpuDynInst) 426{ 427 Wavefront *w = gpuDynInst->wavefront(); 428 429 const VectorMask &mask = w->getPred(); 430 431 for (int lane = 0; lane < w->computeUnit->wfSize(); ++lane) { 432 if (mask[lane]) { 433 DestCType dest_val; 434 SrcCType src_val[$num_srcs]; 435 436 for (int i = 0; i < $num_srcs; ++i) { 437 src_val[i] = this->src[i].template get<SrcCType>(w, lane); 438 } 439 440 dest_val = $expr; 441 442 this->dest.set(w, lane, dest_val); 443 } 444 } 445} 446 447''' 448 449exec_templates = { 450 'ArithInst': exec_template_1dt_varsrcs, 451 'CmovInst': exec_template_1dt_3srcs, 452 'ExtractInsertInst': exec_template_1dt_3srcs, 453 'ClassInst': exec_template_1dt_2src_1dest, 454 'CmpInst': exec_template_2dt, 455 'CvtInst': exec_template_2dt, 456 'PopcountInst': exec_template_2dt, 457 'LdInst': '', 458 'StInst': '', 459 'SpecialInstNoSrc': exec_template_nodt_nosrc, 460 'SpecialInst1Src': exec_template_nodt_1src, 461 'SpecialInstNoSrcNoDest': '', 462 'Stub': exec_template_stub, 463} 464 465############### 466# 467# Define code templates for the decoder cases 468# 469############### 470 471# decode template for nodt-opcode case 472decode_nodt_template = ''' 473 case BRIG_OPCODE_$brig_opcode_upper: return $constructor(ib, obj);''' 474 475decode_case_prolog_class_inst = ''' 476 case BRIG_OPCODE_$brig_opcode_upper: 477 { 478 //const BrigOperandBase *baseOp = obj->getOperand(ib->operands[1]); 479 BrigType16_t type = ((BrigInstSourceType*)ib)->sourceType; 480 //switch (baseOp->kind) { 481 // case BRIG_OPERAND_REG: 482 // type = ((const BrigOperandReg*)baseOp)->type; 483 // break; 484 // case BRIG_OPERAND_IMMED: 485 // type = ((const BrigOperandImmed*)baseOp)->type; 486 // break; 487 // default: 488 // fatal("CLASS unrecognized kind of operand %d\\n", 489 // baseOp->kind); 490 //} 491 switch (type) {''' 492 493# common prolog for 1dt- or 2dt-opcode case: switch on data type 494decode_case_prolog = ''' 495 case BRIG_OPCODE_$brig_opcode_upper: 496 { 497 switch (ib->type) {''' 498 499# single-level decode case entry (for 1dt opcodes) 500decode_case_entry = \ 501' case BRIG_TYPE_$type_name: return $constructor(ib, obj);' 502 503decode_store_prolog = \ 504' case BRIG_TYPE_$type_name: {' 505 506decode_store_case_epilog = ''' 507 }''' 508 509decode_store_case_entry = \ 510' return $constructor(ib, obj);' 511 512# common epilog for type switch 513decode_case_epilog = ''' 514 default: fatal("$brig_opcode_upper: unrecognized type %d\\n", 515 ib->type); 516 } 517 } 518 break;''' 519 520# Additional templates for nested decode on a second type field (for 521# compare and convert). These are used in place of the 522# decode_case_entry template to create a second-level switch on on the 523# second type field inside each case of the first-level type switch. 524# Because the name and location of the second type can vary, the Brig 525# instruction type must be provided in $brig_type, and the name of the 526# second type field must be provided in $type_field. 527decode_case2_prolog = ''' 528 case BRIG_TYPE_$type_name: 529 switch (((Brig$brig_type*)ib)->$type2_field) {''' 530 531decode_case2_entry = \ 532' case BRIG_TYPE_$type2_name: return $constructor(ib, obj);' 533 534decode_case2_epilog = ''' 535 default: fatal("$brig_opcode_upper: unrecognized $type2_field %d\\n", 536 ((Brig$brig_type*)ib)->$type2_field); 537 } 538 break;''' 539 540# Figure out how many source operands an expr needs by looking for the 541# highest-numbered srcN value referenced. Since sources are numbered 542# starting at 0, the return value is N+1. 543def num_src_operands(expr): 544 if expr.find('src2') != -1: 545 return 3 546 elif expr.find('src1') != -1: 547 return 2 548 elif expr.find('src0') != -1: 549 return 1 550 else: 551 return 0 552 553############### 554# 555# Define final code generation methods 556# 557# The gen_nodt, and gen_1dt, and gen_2dt methods are the interface for 558# generating actual instructions. 559# 560############### 561 562# Generate class declaration, exec function, and decode switch case 563# for an brig_opcode with a single-level type switch. The 'types' 564# parameter is a list or tuple of types for which the instruction 565# should be instantiated. 566def gen(brig_opcode, types=None, expr=None, base_class='ArithInst', 567 type2_info=None, constructor_prefix='new ', is_store=False): 568 brig_opcode_upper = brig_opcode.upper() 569 class_name = brig_opcode 570 opcode = class_name.lower() 571 572 if base_class == 'ArithInst': 573 # note that expr must be provided with ArithInst so we can 574 # derive num_srcs for the template 575 assert expr 576 577 if expr: 578 # Derive several bits of info from expr. If expr is not used, 579 # this info will be irrelevant. 580 num_srcs = num_src_operands(expr) 581 # if the RHS expression includes 'dest', then we're doing an RMW 582 # on the reg and we need to treat it like a source 583 dest_is_src = expr.find('dest') != -1 584 dest_is_src_flag = str(dest_is_src).lower() # for C++ 585 if base_class in ['ShiftInst']: 586 expr = re.sub(r'\bsrc(\d)\b', r'src_val\1', expr) 587 elif base_class in ['ArithInst', 'CmpInst', 'CvtInst', 'PopcountInst']: 588 expr = re.sub(r'\bsrc(\d)\b', r'src_val[\1]', expr) 589 else: 590 expr = re.sub(r'\bsrc(\d)\b', r'src_val\1', expr) 591 expr = re.sub(r'\bdest\b', r'dest_val', expr) 592 593 # Strip template arguments off of base class before looking up 594 # appropriate templates 595 base_class_base = re.sub(r'<.*>$', '', base_class) 596 header_code(header_templates[base_class_base]) 597 598 if base_class.startswith('SpecialInst') or base_class.startswith('Stub'): 599 exec_code(exec_templates[base_class_base]) 600 elif base_class.startswith('ShiftInst'): 601 header_code(exec_template_shift) 602 else: 603 header_code(exec_templates[base_class_base]) 604 605 if not types or isinstance(types, str): 606 # Just a single type 607 constructor = constructor_prefix + class_name 608 decoder_code(decode_nodt_template) 609 else: 610 # multiple types, need at least one level of decode 611 if brig_opcode == 'Class': 612 decoder_code(decode_case_prolog_class_inst) 613 else: 614 decoder_code(decode_case_prolog) 615 if not type2_info: 616 if not is_store: 617 # single list of types, to basic one-level decode 618 for type_name in types: 619 full_class_name = '%s<%s>' % (class_name, type_name.upper()) 620 constructor = constructor_prefix + full_class_name 621 decoder_code(decode_case_entry) 622 else: 623 # single list of types, to basic one-level decode 624 for type_name in types: 625 decoder_code(decode_store_prolog) 626 type_size = int(re.findall(r'[0-9]+', type_name)[0]) 627 src_size = 32 628 type_type = type_name[0] 629 full_class_name = '%s<%s,%s>' % (class_name, \ 630 type_name.upper(), \ 631 '%s%d' % \ 632 (type_type.upper(), \ 633 type_size)) 634 constructor = constructor_prefix + full_class_name 635 decoder_code(decode_store_case_entry) 636 decoder_code(decode_store_case_epilog) 637 else: 638 # need secondary type switch (convert, compare) 639 # unpack extra info on second switch 640 (type2_field, types2) = type2_info 641 brig_type = 'Inst%s' % brig_opcode 642 for type_name in types: 643 decoder_code(decode_case2_prolog) 644 fmt = '%s<%s,%%s>' % (class_name, type_name.upper()) 645 for type2_name in types2: 646 full_class_name = fmt % type2_name.upper() 647 constructor = constructor_prefix + full_class_name 648 decoder_code(decode_case2_entry) 649 650 decoder_code(decode_case2_epilog) 651 652 decoder_code(decode_case_epilog) 653 654############### 655# 656# Generate instructions 657# 658############### 659 660# handy abbreviations for common sets of types 661 662# arithmetic ops are typically defined only on 32- and 64-bit sizes 663arith_int_types = ('S32', 'U32', 'S64', 'U64') 664arith_float_types = ('F32', 'F64') 665arith_types = arith_int_types + arith_float_types 666 667bit_types = ('B1', 'B32', 'B64') 668 669all_int_types = ('S8', 'U8', 'S16', 'U16') + arith_int_types 670 671# I think you might be able to do 'f16' memory ops too, but we'll 672# ignore them for now. 673mem_types = all_int_types + arith_float_types 674mem_atom_types = all_int_types + ('B32', 'B64') 675 676##### Arithmetic & logical operations 677gen('Add', arith_types, 'src0 + src1') 678gen('Sub', arith_types, 'src0 - src1') 679gen('Mul', arith_types, 'src0 * src1') 680gen('Div', arith_types, 'src0 / src1') 681gen('Min', arith_types, 'std::min(src0, src1)') 682gen('Max', arith_types, 'std::max(src0, src1)') 683gen('Gcnmin', arith_types, 'std::min(src0, src1)') 684 685gen('CopySign', arith_float_types, 686 'src1 < 0 ? -std::abs(src0) : std::abs(src0)') 687gen('Sqrt', arith_float_types, 'sqrt(src0)') 688gen('Floor', arith_float_types, 'floor(src0)') 689 690# "fast" sqrt... same as slow for us 691gen('Nsqrt', arith_float_types, 'sqrt(src0)') 692gen('Nrsqrt', arith_float_types, '1.0/sqrt(src0)') 693gen('Nrcp', arith_float_types, '1.0/src0') 694gen('Fract', arith_float_types, 695 '(src0 >= 0.0)?(src0-floor(src0)):(floor(src0)-src0)') 696 697gen('Ncos', arith_float_types, 'cos(src0)'); 698gen('Nsin', arith_float_types, 'sin(src0)'); 699 700gen('And', bit_types, 'src0 & src1') 701gen('Or', bit_types, 'src0 | src1') 702gen('Xor', bit_types, 'src0 ^ src1') 703 704gen('Bitselect', bit_types, '(src1 & src0) | (src2 & ~(uint64_t)src0)') 705gen('Popcount', ('U32',), '__builtin_popcount(src0)', 'PopcountInst', \ 706 ('sourceType', ('B32', 'B64'))) 707 708gen('Shl', arith_int_types, 'src0 << (unsigned)src1', 'ShiftInst') 709gen('Shr', arith_int_types, 'src0 >> (unsigned)src1', 'ShiftInst') 710 711# gen('Mul_hi', types=('s32','u32', '??')) 712# gen('Mul24', types=('s32','u32', '??')) 713gen('Rem', arith_int_types, 'src0 - ((src0 / src1) * src1)') 714 715gen('Abs', arith_types, 'std::abs(src0)') 716gen('Neg', arith_types, '-src0') 717 718gen('Mov', bit_types + arith_types, 'src0') 719gen('Not', bit_types, 'heynot(src0)') 720 721# mad and fma differ only in rounding behavior, which we don't emulate 722# also there's an integer form of mad, but not of fma 723gen('Mad', arith_types, 'src0 * src1 + src2') 724gen('Fma', arith_float_types, 'src0 * src1 + src2') 725 726#native floating point operations 727gen('Nfma', arith_float_types, 'src0 * src1 + src2') 728 729gen('Cmov', bit_types, 'src0 ? src1 : src2', 'CmovInst') 730gen('BitAlign', bit_types, '(src0 << src2)|(src1 >> (32 - src2))') 731gen('ByteAlign', bit_types, '(src0 << 8 * src2)|(src1 >> (32 - 8 * src2))') 732 733# see base/bitfield.hh 734gen('BitExtract', arith_int_types, 'bits(src0, src1, src1 + src2 - 1)', 735 'ExtractInsertInst') 736 737gen('BitInsert', arith_int_types, 'insertBits(dest, src1, src2, src0)', 738 'ExtractInsertInst') 739 740##### Compare 741gen('Cmp', ('B1', 'S32', 'U32', 'F32'), 'compare(src0, src1, this->cmpOp)', 742 'CmpInst', ('sourceType', arith_types + bit_types)) 743gen('Class', arith_float_types, 'fpclassify(src0,src1)','ClassInst') 744 745##### Conversion 746 747# Conversion operations are only defined on B1, not B32 or B64 748cvt_types = ('B1',) + mem_types 749 750gen('Cvt', cvt_types, 'src0', 'CvtInst', ('sourceType', cvt_types)) 751 752 753##### Load & Store 754gen('Lda', mem_types, base_class = 'LdInst', constructor_prefix='decode') 755gen('Ld', mem_types, base_class = 'LdInst', constructor_prefix='decode') 756gen('St', mem_types, base_class = 'StInst', constructor_prefix='decode', 757 is_store=True) 758gen('Atomic', mem_atom_types, base_class='StInst', constructor_prefix='decode') 759gen('AtomicNoRet', mem_atom_types, base_class='StInst', 760 constructor_prefix='decode') 761 762gen('Cbr', base_class = 'LdInst', constructor_prefix='decode') 763gen('Br', base_class = 'LdInst', constructor_prefix='decode') 764 765##### Special operations 766def gen_special(brig_opcode, expr, dest_type='U32'): 767 num_srcs = num_src_operands(expr) 768 if num_srcs == 0: 769 base_class = 'SpecialInstNoSrc<%s>' % dest_type 770 elif num_srcs == 1: 771 base_class = 'SpecialInst1Src<%s>' % dest_type 772 else: 773 assert false 774 775 gen(brig_opcode, None, expr, base_class) 776 777gen_special('WorkItemId', 'w->workItemId[src0][lane]') 778gen_special('WorkItemAbsId', 779 'w->workItemId[src0][lane] + (w->workGroupId[src0] * w->workGroupSz[src0])') 780gen_special('WorkGroupId', 'w->workGroupId[src0]') 781gen_special('WorkGroupSize', 'w->workGroupSz[src0]') 782gen_special('CurrentWorkGroupSize', 'w->workGroupSz[src0]') 783gen_special('GridSize', 'w->gridSz[src0]') 784gen_special('GridGroups', 785 'divCeil(w->gridSz[src0],w->workGroupSz[src0])') 786gen_special('LaneId', 'lane') 787gen_special('WaveId', 'w->wfId') 788gen_special('Clock', 'w->computeUnit->shader->tick_cnt', 'U64') 789 790# gen_special('CU'', ') 791 792gen('Ret', base_class='SpecialInstNoSrcNoDest') 793gen('Barrier', base_class='SpecialInstNoSrcNoDest') 794gen('MemFence', base_class='SpecialInstNoSrcNoDest') 795 796# Map magic instructions to the BrigSyscall opcode 797# Magic instructions are defined in magic.hh 798# 799# In the future, real HSA kernel system calls can be implemented and coexist 800# with magic instructions. 801gen('Call', base_class='SpecialInstNoSrcNoDest') 802 803# Stubs for unimplemented instructions: 804# These may need to be implemented at some point in the future, but 805# for now we just match the instructions with their operands. 806# 807# By defining stubs for these instructions, we can work with 808# applications that have them in dead/unused code paths. 809# 810# Needed for rocm-hcc compilations for HSA backends since 811# builtins-hsail library is `cat`d onto the generated kernels. 812# The builtins-hsail library consists of handcoded hsail functions 813# that __might__ be needed by the rocm-hcc compiler in certain binaries. 814gen('Bitmask', base_class='Stub') 815gen('Bitrev', base_class='Stub') 816gen('Firstbit', base_class='Stub') 817gen('Lastbit', base_class='Stub') 818gen('Unpacklo', base_class='Stub') 819gen('Unpackhi', base_class='Stub') 820gen('Pack', base_class='Stub') 821gen('Unpack', base_class='Stub') 822gen('Lerp', base_class='Stub') 823gen('Packcvt', base_class='Stub') 824gen('Unpackcvt', base_class='Stub') 825gen('Sad', base_class='Stub') 826gen('Sadhi', base_class='Stub') 827gen('Activelanecount', base_class='Stub') 828gen('Activelaneid', base_class='Stub') 829gen('Activelanemask', base_class='Stub') 830gen('Activelanepermute', base_class='Stub') 831gen('Groupbaseptr', base_class='Stub') 832gen('Signalnoret', base_class='Stub') 833 834############### 835# 836# Generate file epilogs 837# 838############### 839header_code(''' 840template<> 841inline void 842Abs<U32>::execute(GPUDynInstPtr gpuDynInst) 843{ 844 Wavefront *w = gpuDynInst->wavefront(); 845 846 const VectorMask &mask = w->getPred(); 847 848 for (int lane = 0; lane < w->computeUnit->wfSize(); ++lane) { 849 if (mask[lane]) { 850 CType dest_val; 851 CType src_val; 852 853 src_val = this->src[0].template get<CType>(w, lane); 854 855 dest_val = (CType)(src_val); 856 857 this->dest.set(w, lane, dest_val); 858 } 859 } 860} 861 862template<> 863inline void 864Abs<U64>::execute(GPUDynInstPtr gpuDynInst) 865{ 866 Wavefront *w = gpuDynInst->wavefront(); 867 868 const VectorMask &mask = w->getPred(); 869 870 for (int lane = 0; lane < w->computeUnit->wfSize(); ++lane) { 871 if (mask[lane]) { 872 CType dest_val; 873 CType src_val; 874 875 src_val = this->src[0].template get<CType>(w, lane); 876 877 dest_val = (CType)(src_val); 878 879 this->dest.set(w, lane, dest_val); 880 } 881 } 882} 883''') 884 885header_code.dedent() 886header_code(''' 887} // namespace HsailISA 888''') 889 890# close off main decode switch 891decoder_code.dedent() 892decoder_code.dedent() 893decoder_code(''' 894 default: fatal("unrecognized Brig opcode %d\\n", ib->opcode); 895 } // end switch(ib->opcode) 896 } // end decode() 897} // namespace HsailISA 898''') 899 900exec_code.dedent() 901exec_code(''' 902} // namespace HsailISA 903''') 904 905############### 906# 907# Output accumulated code to files 908# 909############### 910header_code.write(sys.argv[1]) 911decoder_code.write(sys.argv[2]) 912exec_code.write(sys.argv[3])
|