1 // 2 //Copyright (C) 2014-2015 LunarG, Inc. 3 //Copyright (C) 2015-2016 Google, Inc. 4 // 5 //All rights reserved. 6 // 7 //Redistribution and use in source and binary forms, with or without 8 //modification, are permitted provided that the following conditions 9 //are met: 10 // 11 // Redistributions of source code must retain the above copyright 12 // notice, this list of conditions and the following disclaimer. 13 // 14 // Redistributions in binary form must reproduce the above 15 // copyright notice, this list of conditions and the following 16 // disclaimer in the documentation and/or other materials provided 17 // with the distribution. 18 // 19 // Neither the name of 3Dlabs Inc. Ltd. nor the names of its 20 // contributors may be used to endorse or promote products derived 21 // from this software without specific prior written permission. 22 // 23 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 //"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 //FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 27 //COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28 //INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29 //BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31 //CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 //LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 33 //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 //POSSIBILITY OF SUCH DAMAGE. 35 36 // 37 // Helper for making SPIR-V IR. Generally, this is documented in the header 38 // SpvBuilder.h. 39 // 40 41 #include <assert.h> 42 #include <stdlib.h> 43 44 #include <unordered_set> 45 #include <algorithm> 46 47 #include "SpvBuilder.h" 48 49 #ifndef _WIN32 50 #include <cstdio> 51 #endif 52 53 namespace spv { 54 55 Builder::Builder(unsigned int magicNumber, SpvBuildLogger* buildLogger) : 56 source(SourceLanguageUnknown), 57 sourceVersion(0), 58 addressModel(AddressingModelLogical), 59 memoryModel(MemoryModelGLSL450), 60 builderNumber(magicNumber), 61 buildPoint(0), 62 uniqueId(0), 63 mainFunction(0), 64 generatingOpCodeForSpecConst(false), 65 logger(buildLogger) 66 { 67 clearAccessChain(); 68 } 69 70 Builder::~Builder() 71 { 72 } 73 74 Id Builder::import(const char* name) 75 { 76 Instruction* import = new Instruction(getUniqueId(), NoType, OpExtInstImport); 77 import->addStringOperand(name); 78 79 imports.push_back(std::unique_ptr<Instruction>(import)); 80 return import->getResultId(); 81 } 82 83 // For creating new groupedTypes (will return old type if the requested one was already made). 84 Id Builder::makeVoidType() 85 { 86 Instruction* type; 87 if (groupedTypes[OpTypeVoid].size() == 0) { 88 type = new Instruction(getUniqueId(), NoType, OpTypeVoid); 89 groupedTypes[OpTypeVoid].push_back(type); 90 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); 91 module.mapInstruction(type); 92 } else 93 type = groupedTypes[OpTypeVoid].back(); 94 95 return type->getResultId(); 96 } 97 98 Id Builder::makeBoolType() 99 { 100 Instruction* type; 101 if (groupedTypes[OpTypeBool].size() == 0) { 102 type = new Instruction(getUniqueId(), NoType, OpTypeBool); 103 groupedTypes[OpTypeBool].push_back(type); 104 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); 105 module.mapInstruction(type); 106 } else 107 type = groupedTypes[OpTypeBool].back(); 108 109 return type->getResultId(); 110 } 111 112 Id Builder::makeSamplerType() 113 { 114 Instruction* type; 115 if (groupedTypes[OpTypeSampler].size() == 0) { 116 type = new Instruction(getUniqueId(), NoType, OpTypeSampler); 117 groupedTypes[OpTypeSampler].push_back(type); 118 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); 119 module.mapInstruction(type); 120 } else 121 type = groupedTypes[OpTypeSampler].back(); 122 123 return type->getResultId(); 124 } 125 126 Id Builder::makePointer(StorageClass storageClass, Id pointee) 127 { 128 // try to find it 129 Instruction* type; 130 for (int t = 0; t < (int)groupedTypes[OpTypePointer].size(); ++t) { 131 type = groupedTypes[OpTypePointer][t]; 132 if (type->getImmediateOperand(0) == (unsigned)storageClass && 133 type->getIdOperand(1) == pointee) 134 return type->getResultId(); 135 } 136 137 // not found, make it 138 type = new Instruction(getUniqueId(), NoType, OpTypePointer); 139 type->addImmediateOperand(storageClass); 140 type->addIdOperand(pointee); 141 groupedTypes[OpTypePointer].push_back(type); 142 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); 143 module.mapInstruction(type); 144 145 return type->getResultId(); 146 } 147 148 Id Builder::makeIntegerType(int width, bool hasSign) 149 { 150 // try to find it 151 Instruction* type; 152 for (int t = 0; t < (int)groupedTypes[OpTypeInt].size(); ++t) { 153 type = groupedTypes[OpTypeInt][t]; 154 if (type->getImmediateOperand(0) == (unsigned)width && 155 type->getImmediateOperand(1) == (hasSign ? 1u : 0u)) 156 return type->getResultId(); 157 } 158 159 // not found, make it 160 type = new Instruction(getUniqueId(), NoType, OpTypeInt); 161 type->addImmediateOperand(width); 162 type->addImmediateOperand(hasSign ? 1 : 0); 163 groupedTypes[OpTypeInt].push_back(type); 164 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); 165 module.mapInstruction(type); 166 167 // deal with capabilities 168 switch (width) { 169 case 16: 170 addCapability(CapabilityInt16); 171 break; 172 case 64: 173 addCapability(CapabilityInt64); 174 break; 175 default: 176 break; 177 } 178 179 return type->getResultId(); 180 } 181 182 Id Builder::makeFloatType(int width) 183 { 184 // try to find it 185 Instruction* type; 186 for (int t = 0; t < (int)groupedTypes[OpTypeFloat].size(); ++t) { 187 type = groupedTypes[OpTypeFloat][t]; 188 if (type->getImmediateOperand(0) == (unsigned)width) 189 return type->getResultId(); 190 } 191 192 // not found, make it 193 type = new Instruction(getUniqueId(), NoType, OpTypeFloat); 194 type->addImmediateOperand(width); 195 groupedTypes[OpTypeFloat].push_back(type); 196 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); 197 module.mapInstruction(type); 198 199 // deal with capabilities 200 switch (width) { 201 case 16: 202 addCapability(CapabilityFloat16); 203 break; 204 case 64: 205 addCapability(CapabilityFloat64); 206 break; 207 default: 208 break; 209 } 210 211 return type->getResultId(); 212 } 213 214 // Make a struct without checking for duplication. 215 // See makeStructResultType() for non-decorated structs 216 // needed as the result of some instructions, which does 217 // check for duplicates. 218 Id Builder::makeStructType(const std::vector<Id>& members, const char* name) 219 { 220 // Don't look for previous one, because in the general case, 221 // structs can be duplicated except for decorations. 222 223 // not found, make it 224 Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeStruct); 225 for (int op = 0; op < (int)members.size(); ++op) 226 type->addIdOperand(members[op]); 227 groupedTypes[OpTypeStruct].push_back(type); 228 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); 229 module.mapInstruction(type); 230 addName(type->getResultId(), name); 231 232 return type->getResultId(); 233 } 234 235 // Make a struct for the simple results of several instructions, 236 // checking for duplication. 237 Id Builder::makeStructResultType(Id type0, Id type1) 238 { 239 // try to find it 240 Instruction* type; 241 for (int t = 0; t < (int)groupedTypes[OpTypeStruct].size(); ++t) { 242 type = groupedTypes[OpTypeStruct][t]; 243 if (type->getNumOperands() != 2) 244 continue; 245 if (type->getIdOperand(0) != type0 || 246 type->getIdOperand(1) != type1) 247 continue; 248 return type->getResultId(); 249 } 250 251 // not found, make it 252 std::vector<spv::Id> members; 253 members.push_back(type0); 254 members.push_back(type1); 255 256 return makeStructType(members, "ResType"); 257 } 258 259 Id Builder::makeVectorType(Id component, int size) 260 { 261 // try to find it 262 Instruction* type; 263 for (int t = 0; t < (int)groupedTypes[OpTypeVector].size(); ++t) { 264 type = groupedTypes[OpTypeVector][t]; 265 if (type->getIdOperand(0) == component && 266 type->getImmediateOperand(1) == (unsigned)size) 267 return type->getResultId(); 268 } 269 270 // not found, make it 271 type = new Instruction(getUniqueId(), NoType, OpTypeVector); 272 type->addIdOperand(component); 273 type->addImmediateOperand(size); 274 groupedTypes[OpTypeVector].push_back(type); 275 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); 276 module.mapInstruction(type); 277 278 return type->getResultId(); 279 } 280 281 Id Builder::makeMatrixType(Id component, int cols, int rows) 282 { 283 assert(cols <= maxMatrixSize && rows <= maxMatrixSize); 284 285 Id column = makeVectorType(component, rows); 286 287 // try to find it 288 Instruction* type; 289 for (int t = 0; t < (int)groupedTypes[OpTypeMatrix].size(); ++t) { 290 type = groupedTypes[OpTypeMatrix][t]; 291 if (type->getIdOperand(0) == column && 292 type->getImmediateOperand(1) == (unsigned)cols) 293 return type->getResultId(); 294 } 295 296 // not found, make it 297 type = new Instruction(getUniqueId(), NoType, OpTypeMatrix); 298 type->addIdOperand(column); 299 type->addImmediateOperand(cols); 300 groupedTypes[OpTypeMatrix].push_back(type); 301 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); 302 module.mapInstruction(type); 303 304 return type->getResultId(); 305 } 306 307 // TODO: performance: track arrays per stride 308 // If a stride is supplied (non-zero) make an array. 309 // If no stride (0), reuse previous array types. 310 // 'size' is an Id of a constant or specialization constant of the array size 311 Id Builder::makeArrayType(Id element, Id sizeId, int stride) 312 { 313 Instruction* type; 314 if (stride == 0) { 315 // try to find existing type 316 for (int t = 0; t < (int)groupedTypes[OpTypeArray].size(); ++t) { 317 type = groupedTypes[OpTypeArray][t]; 318 if (type->getIdOperand(0) == element && 319 type->getIdOperand(1) == sizeId) 320 return type->getResultId(); 321 } 322 } 323 324 // not found, make it 325 type = new Instruction(getUniqueId(), NoType, OpTypeArray); 326 type->addIdOperand(element); 327 type->addIdOperand(sizeId); 328 groupedTypes[OpTypeArray].push_back(type); 329 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); 330 module.mapInstruction(type); 331 332 return type->getResultId(); 333 } 334 335 Id Builder::makeRuntimeArray(Id element) 336 { 337 Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeRuntimeArray); 338 type->addIdOperand(element); 339 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); 340 module.mapInstruction(type); 341 342 return type->getResultId(); 343 } 344 345 Id Builder::makeFunctionType(Id returnType, const std::vector<Id>& paramTypes) 346 { 347 // try to find it 348 Instruction* type; 349 for (int t = 0; t < (int)groupedTypes[OpTypeFunction].size(); ++t) { 350 type = groupedTypes[OpTypeFunction][t]; 351 if (type->getIdOperand(0) != returnType || (int)paramTypes.size() != type->getNumOperands() - 1) 352 continue; 353 bool mismatch = false; 354 for (int p = 0; p < (int)paramTypes.size(); ++p) { 355 if (paramTypes[p] != type->getIdOperand(p + 1)) { 356 mismatch = true; 357 break; 358 } 359 } 360 if (! mismatch) 361 return type->getResultId(); 362 } 363 364 // not found, make it 365 type = new Instruction(getUniqueId(), NoType, OpTypeFunction); 366 type->addIdOperand(returnType); 367 for (int p = 0; p < (int)paramTypes.size(); ++p) 368 type->addIdOperand(paramTypes[p]); 369 groupedTypes[OpTypeFunction].push_back(type); 370 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); 371 module.mapInstruction(type); 372 373 return type->getResultId(); 374 } 375 376 Id Builder::makeImageType(Id sampledType, Dim dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format) 377 { 378 // try to find it 379 Instruction* type; 380 for (int t = 0; t < (int)groupedTypes[OpTypeImage].size(); ++t) { 381 type = groupedTypes[OpTypeImage][t]; 382 if (type->getIdOperand(0) == sampledType && 383 type->getImmediateOperand(1) == (unsigned int)dim && 384 type->getImmediateOperand(2) == ( depth ? 1u : 0u) && 385 type->getImmediateOperand(3) == (arrayed ? 1u : 0u) && 386 type->getImmediateOperand(4) == ( ms ? 1u : 0u) && 387 type->getImmediateOperand(5) == sampled && 388 type->getImmediateOperand(6) == (unsigned int)format) 389 return type->getResultId(); 390 } 391 392 // not found, make it 393 type = new Instruction(getUniqueId(), NoType, OpTypeImage); 394 type->addIdOperand(sampledType); 395 type->addImmediateOperand( dim); 396 type->addImmediateOperand( depth ? 1 : 0); 397 type->addImmediateOperand(arrayed ? 1 : 0); 398 type->addImmediateOperand( ms ? 1 : 0); 399 type->addImmediateOperand(sampled); 400 type->addImmediateOperand((unsigned int)format); 401 402 groupedTypes[OpTypeImage].push_back(type); 403 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); 404 module.mapInstruction(type); 405 406 // deal with capabilities 407 switch (dim) { 408 case DimBuffer: 409 if (sampled) 410 addCapability(CapabilitySampledBuffer); 411 else 412 addCapability(CapabilityImageBuffer); 413 break; 414 case Dim1D: 415 if (sampled) 416 addCapability(CapabilitySampled1D); 417 else 418 addCapability(CapabilityImage1D); 419 break; 420 case DimCube: 421 if (arrayed) { 422 if (sampled) 423 addCapability(CapabilitySampledCubeArray); 424 else 425 addCapability(CapabilityImageCubeArray); 426 } 427 break; 428 case DimRect: 429 if (sampled) 430 addCapability(CapabilitySampledRect); 431 else 432 addCapability(CapabilityImageRect); 433 break; 434 case DimSubpassData: 435 addCapability(CapabilityInputAttachment); 436 break; 437 default: 438 break; 439 } 440 441 if (ms) { 442 if (arrayed) 443 addCapability(CapabilityImageMSArray); 444 if (! sampled) 445 addCapability(CapabilityStorageImageMultisample); 446 } 447 448 return type->getResultId(); 449 } 450 451 Id Builder::makeSampledImageType(Id imageType) 452 { 453 // try to find it 454 Instruction* type; 455 for (int t = 0; t < (int)groupedTypes[OpTypeSampledImage].size(); ++t) { 456 type = groupedTypes[OpTypeSampledImage][t]; 457 if (type->getIdOperand(0) == imageType) 458 return type->getResultId(); 459 } 460 461 // not found, make it 462 type = new Instruction(getUniqueId(), NoType, OpTypeSampledImage); 463 type->addIdOperand(imageType); 464 465 groupedTypes[OpTypeSampledImage].push_back(type); 466 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); 467 module.mapInstruction(type); 468 469 return type->getResultId(); 470 } 471 472 Id Builder::getDerefTypeId(Id resultId) const 473 { 474 Id typeId = getTypeId(resultId); 475 assert(isPointerType(typeId)); 476 477 return module.getInstruction(typeId)->getImmediateOperand(1); 478 } 479 480 Op Builder::getMostBasicTypeClass(Id typeId) const 481 { 482 Instruction* instr = module.getInstruction(typeId); 483 484 Op typeClass = instr->getOpCode(); 485 switch (typeClass) 486 { 487 case OpTypeVoid: 488 case OpTypeBool: 489 case OpTypeInt: 490 case OpTypeFloat: 491 case OpTypeStruct: 492 return typeClass; 493 case OpTypeVector: 494 case OpTypeMatrix: 495 case OpTypeArray: 496 case OpTypeRuntimeArray: 497 return getMostBasicTypeClass(instr->getIdOperand(0)); 498 case OpTypePointer: 499 return getMostBasicTypeClass(instr->getIdOperand(1)); 500 default: 501 assert(0); 502 return OpTypeFloat; 503 } 504 } 505 506 int Builder::getNumTypeConstituents(Id typeId) const 507 { 508 Instruction* instr = module.getInstruction(typeId); 509 510 switch (instr->getOpCode()) 511 { 512 case OpTypeBool: 513 case OpTypeInt: 514 case OpTypeFloat: 515 return 1; 516 case OpTypeVector: 517 case OpTypeMatrix: 518 return instr->getImmediateOperand(1); 519 case OpTypeArray: 520 { 521 Id lengthId = instr->getImmediateOperand(1); 522 return module.getInstruction(lengthId)->getImmediateOperand(0); 523 } 524 case OpTypeStruct: 525 return instr->getNumOperands(); 526 default: 527 assert(0); 528 return 1; 529 } 530 } 531 532 // Return the lowest-level type of scalar that an homogeneous composite is made out of. 533 // Typically, this is just to find out if something is made out of ints or floats. 534 // However, it includes returning a structure, if say, it is an array of structure. 535 Id Builder::getScalarTypeId(Id typeId) const 536 { 537 Instruction* instr = module.getInstruction(typeId); 538 539 Op typeClass = instr->getOpCode(); 540 switch (typeClass) 541 { 542 case OpTypeVoid: 543 case OpTypeBool: 544 case OpTypeInt: 545 case OpTypeFloat: 546 case OpTypeStruct: 547 return instr->getResultId(); 548 case OpTypeVector: 549 case OpTypeMatrix: 550 case OpTypeArray: 551 case OpTypeRuntimeArray: 552 case OpTypePointer: 553 return getScalarTypeId(getContainedTypeId(typeId)); 554 default: 555 assert(0); 556 return NoResult; 557 } 558 } 559 560 // Return the type of 'member' of a composite. 561 Id Builder::getContainedTypeId(Id typeId, int member) const 562 { 563 Instruction* instr = module.getInstruction(typeId); 564 565 Op typeClass = instr->getOpCode(); 566 switch (typeClass) 567 { 568 case OpTypeVector: 569 case OpTypeMatrix: 570 case OpTypeArray: 571 case OpTypeRuntimeArray: 572 return instr->getIdOperand(0); 573 case OpTypePointer: 574 return instr->getIdOperand(1); 575 case OpTypeStruct: 576 return instr->getIdOperand(member); 577 default: 578 assert(0); 579 return NoResult; 580 } 581 } 582 583 // Return the immediately contained type of a given composite type. 584 Id Builder::getContainedTypeId(Id typeId) const 585 { 586 return getContainedTypeId(typeId, 0); 587 } 588 589 // See if a scalar constant of this type has already been created, so it 590 // can be reused rather than duplicated. (Required by the specification). 591 Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value) const 592 { 593 Instruction* constant; 594 for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) { 595 constant = groupedConstants[typeClass][i]; 596 if (constant->getOpCode() == opcode && 597 constant->getTypeId() == typeId && 598 constant->getImmediateOperand(0) == value) 599 return constant->getResultId(); 600 } 601 602 return 0; 603 } 604 605 // Version of findScalarConstant (see above) for scalars that take two operands (e.g. a 'double' or 'int64'). 606 Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2) const 607 { 608 Instruction* constant; 609 for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) { 610 constant = groupedConstants[typeClass][i]; 611 if (constant->getOpCode() == opcode && 612 constant->getTypeId() == typeId && 613 constant->getImmediateOperand(0) == v1 && 614 constant->getImmediateOperand(1) == v2) 615 return constant->getResultId(); 616 } 617 618 return 0; 619 } 620 621 // Return true if consuming 'opcode' means consuming a constant. 622 // "constant" here means after final transform to executable code, 623 // the value consumed will be a constant, so includes specialization. 624 bool Builder::isConstantOpCode(Op opcode) const 625 { 626 switch (opcode) { 627 case OpUndef: 628 case OpConstantTrue: 629 case OpConstantFalse: 630 case OpConstant: 631 case OpConstantComposite: 632 case OpConstantSampler: 633 case OpConstantNull: 634 case OpSpecConstantTrue: 635 case OpSpecConstantFalse: 636 case OpSpecConstant: 637 case OpSpecConstantComposite: 638 case OpSpecConstantOp: 639 return true; 640 default: 641 return false; 642 } 643 } 644 645 // Return true if consuming 'opcode' means consuming a specialization constant. 646 bool Builder::isSpecConstantOpCode(Op opcode) const 647 { 648 switch (opcode) { 649 case OpSpecConstantTrue: 650 case OpSpecConstantFalse: 651 case OpSpecConstant: 652 case OpSpecConstantComposite: 653 case OpSpecConstantOp: 654 return true; 655 default: 656 return false; 657 } 658 } 659 660 Id Builder::makeBoolConstant(bool b, bool specConstant) 661 { 662 Id typeId = makeBoolType(); 663 Instruction* constant; 664 Op opcode = specConstant ? (b ? OpSpecConstantTrue : OpSpecConstantFalse) : (b ? OpConstantTrue : OpConstantFalse); 665 666 // See if we already made it. Applies only to regular constants, because specialization constants 667 // must remain distinct for the purpose of applying a SpecId decoration. 668 if (! specConstant) { 669 Id existing = 0; 670 for (int i = 0; i < (int)groupedConstants[OpTypeBool].size(); ++i) { 671 constant = groupedConstants[OpTypeBool][i]; 672 if (constant->getTypeId() == typeId && constant->getOpCode() == opcode) 673 existing = constant->getResultId(); 674 } 675 676 if (existing) 677 return existing; 678 } 679 680 // Make it 681 Instruction* c = new Instruction(getUniqueId(), typeId, opcode); 682 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c)); 683 groupedConstants[OpTypeBool].push_back(c); 684 module.mapInstruction(c); 685 686 return c->getResultId(); 687 } 688 689 Id Builder::makeIntConstant(Id typeId, unsigned value, bool specConstant) 690 { 691 Op opcode = specConstant ? OpSpecConstant : OpConstant; 692 693 // See if we already made it. Applies only to regular constants, because specialization constants 694 // must remain distinct for the purpose of applying a SpecId decoration. 695 if (! specConstant) { 696 Id existing = findScalarConstant(OpTypeInt, opcode, typeId, value); 697 if (existing) 698 return existing; 699 } 700 701 Instruction* c = new Instruction(getUniqueId(), typeId, opcode); 702 c->addImmediateOperand(value); 703 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c)); 704 groupedConstants[OpTypeInt].push_back(c); 705 module.mapInstruction(c); 706 707 return c->getResultId(); 708 } 709 710 Id Builder::makeInt64Constant(Id typeId, unsigned long long value, bool specConstant) 711 { 712 Op opcode = specConstant ? OpSpecConstant : OpConstant; 713 714 unsigned op1 = value & 0xFFFFFFFF; 715 unsigned op2 = value >> 32; 716 717 // See if we already made it. Applies only to regular constants, because specialization constants 718 // must remain distinct for the purpose of applying a SpecId decoration. 719 if (! specConstant) { 720 Id existing = findScalarConstant(OpTypeInt, opcode, typeId, op1, op2); 721 if (existing) 722 return existing; 723 } 724 725 Instruction* c = new Instruction(getUniqueId(), typeId, opcode); 726 c->addImmediateOperand(op1); 727 c->addImmediateOperand(op2); 728 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c)); 729 groupedConstants[OpTypeInt].push_back(c); 730 module.mapInstruction(c); 731 732 return c->getResultId(); 733 } 734 735 Id Builder::makeFloatConstant(float f, bool specConstant) 736 { 737 Op opcode = specConstant ? OpSpecConstant : OpConstant; 738 Id typeId = makeFloatType(32); 739 union { float fl; unsigned int ui; } u; 740 u.fl = f; 741 unsigned value = u.ui; 742 743 // See if we already made it. Applies only to regular constants, because specialization constants 744 // must remain distinct for the purpose of applying a SpecId decoration. 745 if (! specConstant) { 746 Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, value); 747 if (existing) 748 return existing; 749 } 750 751 Instruction* c = new Instruction(getUniqueId(), typeId, opcode); 752 c->addImmediateOperand(value); 753 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c)); 754 groupedConstants[OpTypeFloat].push_back(c); 755 module.mapInstruction(c); 756 757 return c->getResultId(); 758 } 759 760 Id Builder::makeDoubleConstant(double d, bool specConstant) 761 { 762 Op opcode = specConstant ? OpSpecConstant : OpConstant; 763 Id typeId = makeFloatType(64); 764 union { double db; unsigned long long ull; } u; 765 u.db = d; 766 unsigned long long value = u.ull; 767 unsigned op1 = value & 0xFFFFFFFF; 768 unsigned op2 = value >> 32; 769 770 // See if we already made it. Applies only to regular constants, because specialization constants 771 // must remain distinct for the purpose of applying a SpecId decoration. 772 if (! specConstant) { 773 Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, op1, op2); 774 if (existing) 775 return existing; 776 } 777 778 Instruction* c = new Instruction(getUniqueId(), typeId, opcode); 779 c->addImmediateOperand(op1); 780 c->addImmediateOperand(op2); 781 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c)); 782 groupedConstants[OpTypeFloat].push_back(c); 783 module.mapInstruction(c); 784 785 return c->getResultId(); 786 } 787 788 Id Builder::findCompositeConstant(Op typeClass, std::vector<Id>& comps) const 789 { 790 Instruction* constant = 0; 791 bool found = false; 792 for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) { 793 constant = groupedConstants[typeClass][i]; 794 795 // same shape? 796 if (constant->getNumOperands() != (int)comps.size()) 797 continue; 798 799 // same contents? 800 bool mismatch = false; 801 for (int op = 0; op < constant->getNumOperands(); ++op) { 802 if (constant->getIdOperand(op) != comps[op]) { 803 mismatch = true; 804 break; 805 } 806 } 807 if (! mismatch) { 808 found = true; 809 break; 810 } 811 } 812 813 return found ? constant->getResultId() : NoResult; 814 } 815 816 // Comments in header 817 Id Builder::makeCompositeConstant(Id typeId, std::vector<Id>& members, bool specConstant) 818 { 819 Op opcode = specConstant ? OpSpecConstantComposite : OpConstantComposite; 820 assert(typeId); 821 Op typeClass = getTypeClass(typeId); 822 823 switch (typeClass) { 824 case OpTypeVector: 825 case OpTypeArray: 826 case OpTypeStruct: 827 case OpTypeMatrix: 828 break; 829 default: 830 assert(0); 831 return makeFloatConstant(0.0); 832 } 833 834 if (! specConstant) { 835 Id existing = findCompositeConstant(typeClass, members); 836 if (existing) 837 return existing; 838 } 839 840 Instruction* c = new Instruction(getUniqueId(), typeId, opcode); 841 for (int op = 0; op < (int)members.size(); ++op) 842 c->addIdOperand(members[op]); 843 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c)); 844 groupedConstants[typeClass].push_back(c); 845 module.mapInstruction(c); 846 847 return c->getResultId(); 848 } 849 850 Instruction* Builder::addEntryPoint(ExecutionModel model, Function* function, const char* name) 851 { 852 Instruction* entryPoint = new Instruction(OpEntryPoint); 853 entryPoint->addImmediateOperand(model); 854 entryPoint->addIdOperand(function->getId()); 855 entryPoint->addStringOperand(name); 856 857 entryPoints.push_back(std::unique_ptr<Instruction>(entryPoint)); 858 859 return entryPoint; 860 } 861 862 // Currently relying on the fact that all 'value' of interest are small non-negative values. 863 void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, int value1, int value2, int value3) 864 { 865 Instruction* instr = new Instruction(OpExecutionMode); 866 instr->addIdOperand(entryPoint->getId()); 867 instr->addImmediateOperand(mode); 868 if (value1 >= 0) 869 instr->addImmediateOperand(value1); 870 if (value2 >= 0) 871 instr->addImmediateOperand(value2); 872 if (value3 >= 0) 873 instr->addImmediateOperand(value3); 874 875 executionModes.push_back(std::unique_ptr<Instruction>(instr)); 876 } 877 878 void Builder::addName(Id id, const char* string) 879 { 880 Instruction* name = new Instruction(OpName); 881 name->addIdOperand(id); 882 name->addStringOperand(string); 883 884 names.push_back(std::unique_ptr<Instruction>(name)); 885 } 886 887 void Builder::addMemberName(Id id, int memberNumber, const char* string) 888 { 889 Instruction* name = new Instruction(OpMemberName); 890 name->addIdOperand(id); 891 name->addImmediateOperand(memberNumber); 892 name->addStringOperand(string); 893 894 names.push_back(std::unique_ptr<Instruction>(name)); 895 } 896 897 void Builder::addLine(Id target, Id fileName, int lineNum, int column) 898 { 899 Instruction* line = new Instruction(OpLine); 900 line->addIdOperand(target); 901 line->addIdOperand(fileName); 902 line->addImmediateOperand(lineNum); 903 line->addImmediateOperand(column); 904 905 lines.push_back(std::unique_ptr<Instruction>(line)); 906 } 907 908 void Builder::addDecoration(Id id, Decoration decoration, int num) 909 { 910 if (decoration == spv::DecorationMax) 911 return; 912 Instruction* dec = new Instruction(OpDecorate); 913 dec->addIdOperand(id); 914 dec->addImmediateOperand(decoration); 915 if (num >= 0) 916 dec->addImmediateOperand(num); 917 918 decorations.push_back(std::unique_ptr<Instruction>(dec)); 919 } 920 921 void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, int num) 922 { 923 Instruction* dec = new Instruction(OpMemberDecorate); 924 dec->addIdOperand(id); 925 dec->addImmediateOperand(member); 926 dec->addImmediateOperand(decoration); 927 if (num >= 0) 928 dec->addImmediateOperand(num); 929 930 decorations.push_back(std::unique_ptr<Instruction>(dec)); 931 } 932 933 // Comments in header 934 Function* Builder::makeEntrypoint(const char* entryPoint) 935 { 936 assert(! mainFunction); 937 938 Block* entry; 939 std::vector<Id> params; 940 std::vector<Decoration> precisions; 941 942 mainFunction = makeFunctionEntry(NoPrecision, makeVoidType(), entryPoint, params, precisions, &entry); 943 944 return mainFunction; 945 } 946 947 // Comments in header 948 Function* Builder::makeFunctionEntry(Decoration precision, Id returnType, const char* name, 949 const std::vector<Id>& paramTypes, const std::vector<Decoration>& precisions, Block **entry) 950 { 951 // Make the function and initial instructions in it 952 Id typeId = makeFunctionType(returnType, paramTypes); 953 Id firstParamId = paramTypes.size() == 0 ? 0 : getUniqueIds((int)paramTypes.size()); 954 Function* function = new Function(getUniqueId(), returnType, typeId, firstParamId, module); 955 956 // Set up the precisions 957 setPrecision(function->getId(), precision); 958 for (unsigned p = 0; p < (unsigned)precisions.size(); ++p) 959 setPrecision(firstParamId + p, precisions[p]); 960 961 // CFG 962 if (entry) { 963 *entry = new Block(getUniqueId(), *function); 964 function->addBlock(*entry); 965 setBuildPoint(*entry); 966 } 967 968 if (name) 969 addName(function->getId(), name); 970 971 functions.push_back(std::unique_ptr<Function>(function)); 972 973 return function; 974 } 975 976 // Comments in header 977 void Builder::makeReturn(bool implicit, Id retVal) 978 { 979 if (retVal) { 980 Instruction* inst = new Instruction(NoResult, NoType, OpReturnValue); 981 inst->addIdOperand(retVal); 982 buildPoint->addInstruction(std::unique_ptr<Instruction>(inst)); 983 } else 984 buildPoint->addInstruction(std::unique_ptr<Instruction>(new Instruction(NoResult, NoType, OpReturn))); 985 986 if (! implicit) 987 createAndSetNoPredecessorBlock("post-return"); 988 } 989 990 // Comments in header 991 void Builder::leaveFunction() 992 { 993 Block* block = buildPoint; 994 Function& function = buildPoint->getParent(); 995 assert(block); 996 997 // If our function did not contain a return, add a return void now. 998 if (! block->isTerminated()) { 999 if (function.getReturnType() == makeVoidType()) 1000 makeReturn(true); 1001 else { 1002 makeReturn(true, createUndefined(function.getReturnType())); 1003 } 1004 } 1005 } 1006 1007 // Comments in header 1008 void Builder::makeDiscard() 1009 { 1010 buildPoint->addInstruction(std::unique_ptr<Instruction>(new Instruction(OpKill))); 1011 createAndSetNoPredecessorBlock("post-discard"); 1012 } 1013 1014 // Comments in header 1015 Id Builder::createVariable(StorageClass storageClass, Id type, const char* name) 1016 { 1017 Id pointerType = makePointer(storageClass, type); 1018 Instruction* inst = new Instruction(getUniqueId(), pointerType, OpVariable); 1019 inst->addImmediateOperand(storageClass); 1020 1021 switch (storageClass) { 1022 case StorageClassFunction: 1023 // Validation rules require the declaration in the entry block 1024 buildPoint->getParent().addLocalVariable(std::unique_ptr<Instruction>(inst)); 1025 break; 1026 1027 default: 1028 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst)); 1029 module.mapInstruction(inst); 1030 break; 1031 } 1032 1033 if (name) 1034 addName(inst->getResultId(), name); 1035 1036 return inst->getResultId(); 1037 } 1038 1039 // Comments in header 1040 Id Builder::createUndefined(Id type) 1041 { 1042 Instruction* inst = new Instruction(getUniqueId(), type, OpUndef); 1043 buildPoint->addInstruction(std::unique_ptr<Instruction>(inst)); 1044 return inst->getResultId(); 1045 } 1046 1047 // Comments in header 1048 void Builder::createStore(Id rValue, Id lValue) 1049 { 1050 Instruction* store = new Instruction(OpStore); 1051 store->addIdOperand(lValue); 1052 store->addIdOperand(rValue); 1053 buildPoint->addInstruction(std::unique_ptr<Instruction>(store)); 1054 } 1055 1056 // Comments in header 1057 Id Builder::createLoad(Id lValue) 1058 { 1059 Instruction* load = new Instruction(getUniqueId(), getDerefTypeId(lValue), OpLoad); 1060 load->addIdOperand(lValue); 1061 buildPoint->addInstruction(std::unique_ptr<Instruction>(load)); 1062 1063 return load->getResultId(); 1064 } 1065 1066 // Comments in header 1067 Id Builder::createAccessChain(StorageClass storageClass, Id base, std::vector<Id>& offsets) 1068 { 1069 // Figure out the final resulting type. 1070 spv::Id typeId = getTypeId(base); 1071 assert(isPointerType(typeId) && offsets.size() > 0); 1072 typeId = getContainedTypeId(typeId); 1073 for (int i = 0; i < (int)offsets.size(); ++i) { 1074 if (isStructType(typeId)) { 1075 assert(isConstantScalar(offsets[i])); 1076 typeId = getContainedTypeId(typeId, getConstantScalar(offsets[i])); 1077 } else 1078 typeId = getContainedTypeId(typeId, offsets[i]); 1079 } 1080 typeId = makePointer(storageClass, typeId); 1081 1082 // Make the instruction 1083 Instruction* chain = new Instruction(getUniqueId(), typeId, OpAccessChain); 1084 chain->addIdOperand(base); 1085 for (int i = 0; i < (int)offsets.size(); ++i) 1086 chain->addIdOperand(offsets[i]); 1087 buildPoint->addInstruction(std::unique_ptr<Instruction>(chain)); 1088 1089 return chain->getResultId(); 1090 } 1091 1092 Id Builder::createArrayLength(Id base, unsigned int member) 1093 { 1094 Instruction* length = new Instruction(getUniqueId(), makeIntType(32), OpArrayLength); 1095 length->addIdOperand(base); 1096 length->addImmediateOperand(member); 1097 buildPoint->addInstruction(std::unique_ptr<Instruction>(length)); 1098 1099 return length->getResultId(); 1100 } 1101 1102 Id Builder::createCompositeExtract(Id composite, Id typeId, unsigned index) 1103 { 1104 // Generate code for spec constants if in spec constant operation 1105 // generation mode. 1106 if (generatingOpCodeForSpecConst) { 1107 return createSpecConstantOp(OpCompositeExtract, typeId, std::vector<Id>(1, composite), std::vector<Id>(1, index)); 1108 } 1109 Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract); 1110 extract->addIdOperand(composite); 1111 extract->addImmediateOperand(index); 1112 buildPoint->addInstruction(std::unique_ptr<Instruction>(extract)); 1113 1114 return extract->getResultId(); 1115 } 1116 1117 Id Builder::createCompositeExtract(Id composite, Id typeId, std::vector<unsigned>& indexes) 1118 { 1119 // Generate code for spec constants if in spec constant operation 1120 // generation mode. 1121 if (generatingOpCodeForSpecConst) { 1122 return createSpecConstantOp(OpCompositeExtract, typeId, std::vector<Id>(1, composite), indexes); 1123 } 1124 Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract); 1125 extract->addIdOperand(composite); 1126 for (int i = 0; i < (int)indexes.size(); ++i) 1127 extract->addImmediateOperand(indexes[i]); 1128 buildPoint->addInstruction(std::unique_ptr<Instruction>(extract)); 1129 1130 return extract->getResultId(); 1131 } 1132 1133 Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, unsigned index) 1134 { 1135 Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert); 1136 insert->addIdOperand(object); 1137 insert->addIdOperand(composite); 1138 insert->addImmediateOperand(index); 1139 buildPoint->addInstruction(std::unique_ptr<Instruction>(insert)); 1140 1141 return insert->getResultId(); 1142 } 1143 1144 Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, std::vector<unsigned>& indexes) 1145 { 1146 Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert); 1147 insert->addIdOperand(object); 1148 insert->addIdOperand(composite); 1149 for (int i = 0; i < (int)indexes.size(); ++i) 1150 insert->addImmediateOperand(indexes[i]); 1151 buildPoint->addInstruction(std::unique_ptr<Instruction>(insert)); 1152 1153 return insert->getResultId(); 1154 } 1155 1156 Id Builder::createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex) 1157 { 1158 Instruction* extract = new Instruction(getUniqueId(), typeId, OpVectorExtractDynamic); 1159 extract->addIdOperand(vector); 1160 extract->addIdOperand(componentIndex); 1161 buildPoint->addInstruction(std::unique_ptr<Instruction>(extract)); 1162 1163 return extract->getResultId(); 1164 } 1165 1166 Id Builder::createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex) 1167 { 1168 Instruction* insert = new Instruction(getUniqueId(), typeId, OpVectorInsertDynamic); 1169 insert->addIdOperand(vector); 1170 insert->addIdOperand(component); 1171 insert->addIdOperand(componentIndex); 1172 buildPoint->addInstruction(std::unique_ptr<Instruction>(insert)); 1173 1174 return insert->getResultId(); 1175 } 1176 1177 // An opcode that has no operands, no result id, and no type 1178 void Builder::createNoResultOp(Op opCode) 1179 { 1180 Instruction* op = new Instruction(opCode); 1181 buildPoint->addInstruction(std::unique_ptr<Instruction>(op)); 1182 } 1183 1184 // An opcode that has one operand, no result id, and no type 1185 void Builder::createNoResultOp(Op opCode, Id operand) 1186 { 1187 Instruction* op = new Instruction(opCode); 1188 op->addIdOperand(operand); 1189 buildPoint->addInstruction(std::unique_ptr<Instruction>(op)); 1190 } 1191 1192 // An opcode that has one operand, no result id, and no type 1193 void Builder::createNoResultOp(Op opCode, const std::vector<Id>& operands) 1194 { 1195 Instruction* op = new Instruction(opCode); 1196 for (auto it = operands.cbegin(); it != operands.cend(); ++it) 1197 op->addIdOperand(*it); 1198 buildPoint->addInstruction(std::unique_ptr<Instruction>(op)); 1199 } 1200 1201 void Builder::createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask semantics) 1202 { 1203 Instruction* op = new Instruction(OpControlBarrier); 1204 op->addImmediateOperand(makeUintConstant(execution)); 1205 op->addImmediateOperand(makeUintConstant(memory)); 1206 op->addImmediateOperand(makeUintConstant(semantics)); 1207 buildPoint->addInstruction(std::unique_ptr<Instruction>(op)); 1208 } 1209 1210 void Builder::createMemoryBarrier(unsigned executionScope, unsigned memorySemantics) 1211 { 1212 Instruction* op = new Instruction(OpMemoryBarrier); 1213 op->addImmediateOperand(makeUintConstant(executionScope)); 1214 op->addImmediateOperand(makeUintConstant(memorySemantics)); 1215 buildPoint->addInstruction(std::unique_ptr<Instruction>(op)); 1216 } 1217 1218 // An opcode that has one operands, a result id, and a type 1219 Id Builder::createUnaryOp(Op opCode, Id typeId, Id operand) 1220 { 1221 // Generate code for spec constants if in spec constant operation 1222 // generation mode. 1223 if (generatingOpCodeForSpecConst) { 1224 return createSpecConstantOp(opCode, typeId, std::vector<Id>(1, operand), std::vector<Id>()); 1225 } 1226 Instruction* op = new Instruction(getUniqueId(), typeId, opCode); 1227 op->addIdOperand(operand); 1228 buildPoint->addInstruction(std::unique_ptr<Instruction>(op)); 1229 1230 return op->getResultId(); 1231 } 1232 1233 Id Builder::createBinOp(Op opCode, Id typeId, Id left, Id right) 1234 { 1235 // Generate code for spec constants if in spec constant operation 1236 // generation mode. 1237 if (generatingOpCodeForSpecConst) { 1238 std::vector<Id> operands(2); 1239 operands[0] = left; operands[1] = right; 1240 return createSpecConstantOp(opCode, typeId, operands, std::vector<Id>()); 1241 } 1242 Instruction* op = new Instruction(getUniqueId(), typeId, opCode); 1243 op->addIdOperand(left); 1244 op->addIdOperand(right); 1245 buildPoint->addInstruction(std::unique_ptr<Instruction>(op)); 1246 1247 return op->getResultId(); 1248 } 1249 1250 Id Builder::createTriOp(Op opCode, Id typeId, Id op1, Id op2, Id op3) 1251 { 1252 // Generate code for spec constants if in spec constant operation 1253 // generation mode. 1254 if (generatingOpCodeForSpecConst) { 1255 std::vector<Id> operands(3); 1256 operands[0] = op1; 1257 operands[1] = op2; 1258 operands[2] = op3; 1259 return createSpecConstantOp( 1260 opCode, typeId, operands, std::vector<Id>()); 1261 } 1262 Instruction* op = new Instruction(getUniqueId(), typeId, opCode); 1263 op->addIdOperand(op1); 1264 op->addIdOperand(op2); 1265 op->addIdOperand(op3); 1266 buildPoint->addInstruction(std::unique_ptr<Instruction>(op)); 1267 1268 return op->getResultId(); 1269 } 1270 1271 Id Builder::createOp(Op opCode, Id typeId, const std::vector<Id>& operands) 1272 { 1273 Instruction* op = new Instruction(getUniqueId(), typeId, opCode); 1274 for (auto it = operands.cbegin(); it != operands.cend(); ++it) 1275 op->addIdOperand(*it); 1276 buildPoint->addInstruction(std::unique_ptr<Instruction>(op)); 1277 1278 return op->getResultId(); 1279 } 1280 1281 Id Builder::createSpecConstantOp(Op opCode, Id typeId, const std::vector<Id>& operands, const std::vector<unsigned>& literals) 1282 { 1283 Instruction* op = new Instruction(getUniqueId(), typeId, OpSpecConstantOp); 1284 op->addImmediateOperand((unsigned) opCode); 1285 for (auto it = operands.cbegin(); it != operands.cend(); ++it) 1286 op->addIdOperand(*it); 1287 for (auto it = literals.cbegin(); it != literals.cend(); ++it) 1288 op->addImmediateOperand(*it); 1289 module.mapInstruction(op); 1290 constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(op)); 1291 1292 return op->getResultId(); 1293 } 1294 1295 Id Builder::createFunctionCall(spv::Function* function, std::vector<spv::Id>& args) 1296 { 1297 Instruction* op = new Instruction(getUniqueId(), function->getReturnType(), OpFunctionCall); 1298 op->addIdOperand(function->getId()); 1299 for (int a = 0; a < (int)args.size(); ++a) 1300 op->addIdOperand(args[a]); 1301 buildPoint->addInstruction(std::unique_ptr<Instruction>(op)); 1302 1303 return op->getResultId(); 1304 } 1305 1306 // Comments in header 1307 Id Builder::createRvalueSwizzle(Decoration precision, Id typeId, Id source, std::vector<unsigned>& channels) 1308 { 1309 if (channels.size() == 1) 1310 return setPrecision(createCompositeExtract(source, typeId, channels.front()), precision); 1311 1312 if (generatingOpCodeForSpecConst) { 1313 std::vector<Id> operands(2); 1314 operands[0] = operands[1] = source; 1315 return setPrecision(createSpecConstantOp(OpVectorShuffle, typeId, operands, channels), precision); 1316 } 1317 Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle); 1318 assert(isVector(source)); 1319 swizzle->addIdOperand(source); 1320 swizzle->addIdOperand(source); 1321 for (int i = 0; i < (int)channels.size(); ++i) 1322 swizzle->addImmediateOperand(channels[i]); 1323 buildPoint->addInstruction(std::unique_ptr<Instruction>(swizzle)); 1324 1325 return setPrecision(swizzle->getResultId(), precision); 1326 } 1327 1328 // Comments in header 1329 Id Builder::createLvalueSwizzle(Id typeId, Id target, Id source, std::vector<unsigned>& channels) 1330 { 1331 assert(getNumComponents(source) == (int)channels.size()); 1332 if (channels.size() == 1 && getNumComponents(source) == 1) 1333 return createCompositeInsert(source, target, typeId, channels.front()); 1334 1335 Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle); 1336 assert(isVector(source)); 1337 assert(isVector(target)); 1338 swizzle->addIdOperand(target); 1339 swizzle->addIdOperand(source); 1340 1341 // Set up an identity shuffle from the base value to the result value 1342 unsigned int components[4]; 1343 int numTargetComponents = getNumComponents(target); 1344 for (int i = 0; i < numTargetComponents; ++i) 1345 components[i] = i; 1346 1347 // Punch in the l-value swizzle 1348 for (int i = 0; i < (int)channels.size(); ++i) 1349 components[channels[i]] = numTargetComponents + i; 1350 1351 // finish the instruction with these components selectors 1352 for (int i = 0; i < numTargetComponents; ++i) 1353 swizzle->addImmediateOperand(components[i]); 1354 buildPoint->addInstruction(std::unique_ptr<Instruction>(swizzle)); 1355 1356 return swizzle->getResultId(); 1357 } 1358 1359 // Comments in header 1360 void Builder::promoteScalar(Decoration precision, Id& left, Id& right) 1361 { 1362 int direction = getNumComponents(right) - getNumComponents(left); 1363 1364 if (direction > 0) 1365 left = smearScalar(precision, left, makeVectorType(getTypeId(left), getNumComponents(right))); 1366 else if (direction < 0) 1367 right = smearScalar(precision, right, makeVectorType(getTypeId(right), getNumComponents(left))); 1368 1369 return; 1370 } 1371 1372 // Comments in header 1373 Id Builder::smearScalar(Decoration precision, Id scalar, Id vectorType) 1374 { 1375 assert(getNumComponents(scalar) == 1); 1376 assert(getTypeId(scalar) == getScalarTypeId(vectorType)); 1377 1378 int numComponents = getNumTypeComponents(vectorType); 1379 if (numComponents == 1) 1380 return scalar; 1381 1382 Instruction* smear = nullptr; 1383 if (generatingOpCodeForSpecConst) { 1384 auto members = std::vector<spv::Id>(numComponents, scalar); 1385 // Sometime even in spec-constant-op mode, the temporary vector created by 1386 // promoting a scalar might not be a spec constant. This should depend on 1387 // the scalar. 1388 // e.g.: 1389 // const vec2 spec_const_result = a_spec_const_vec2 + a_front_end_const_scalar; 1390 // In such cases, the temporary vector created from a_front_end_const_scalar 1391 // is not a spec constant vector, even though the binary operation node is marked 1392 // as 'specConstant' and we are in spec-constant-op mode. 1393 auto result_id = makeCompositeConstant(vectorType, members, isSpecConstant(scalar)); 1394 smear = module.getInstruction(result_id); 1395 } else { 1396 smear = new Instruction(getUniqueId(), vectorType, OpCompositeConstruct); 1397 for (int c = 0; c < numComponents; ++c) 1398 smear->addIdOperand(scalar); 1399 buildPoint->addInstruction(std::unique_ptr<Instruction>(smear)); 1400 } 1401 1402 return setPrecision(smear->getResultId(), precision); 1403 } 1404 1405 // Comments in header 1406 Id Builder::createBuiltinCall(Id resultType, Id builtins, int entryPoint, std::vector<Id>& args) 1407 { 1408 Instruction* inst = new Instruction(getUniqueId(), resultType, OpExtInst); 1409 inst->addIdOperand(builtins); 1410 inst->addImmediateOperand(entryPoint); 1411 for (int arg = 0; arg < (int)args.size(); ++arg) 1412 inst->addIdOperand(args[arg]); 1413 1414 buildPoint->addInstruction(std::unique_ptr<Instruction>(inst)); 1415 1416 return inst->getResultId(); 1417 } 1418 1419 // Accept all parameters needed to create a texture instruction. 1420 // Create the correct instruction based on the inputs, and make the call. 1421 Id Builder::createTextureCall(Decoration precision, Id resultType, bool sparse, bool fetch, bool proj, bool gather, bool noImplicitLod, const TextureParameters& parameters) 1422 { 1423 static const int maxTextureArgs = 10; 1424 Id texArgs[maxTextureArgs] = {}; 1425 1426 // 1427 // Set up the fixed arguments 1428 // 1429 int numArgs = 0; 1430 bool explicitLod = false; 1431 texArgs[numArgs++] = parameters.sampler; 1432 texArgs[numArgs++] = parameters.coords; 1433 if (parameters.Dref != NoResult) 1434 texArgs[numArgs++] = parameters.Dref; 1435 if (parameters.component != NoResult) 1436 texArgs[numArgs++] = parameters.component; 1437 1438 // 1439 // Set up the optional arguments 1440 // 1441 int optArgNum = numArgs; // track which operand, if it exists, is the mask of optional arguments 1442 ++numArgs; // speculatively make room for the mask operand 1443 ImageOperandsMask mask = ImageOperandsMaskNone; // the mask operand 1444 if (parameters.bias) { 1445 mask = (ImageOperandsMask)(mask | ImageOperandsBiasMask); 1446 texArgs[numArgs++] = parameters.bias; 1447 } 1448 if (parameters.lod) { 1449 mask = (ImageOperandsMask)(mask | ImageOperandsLodMask); 1450 texArgs[numArgs++] = parameters.lod; 1451 explicitLod = true; 1452 } else if (parameters.gradX) { 1453 mask = (ImageOperandsMask)(mask | ImageOperandsGradMask); 1454 texArgs[numArgs++] = parameters.gradX; 1455 texArgs[numArgs++] = parameters.gradY; 1456 explicitLod = true; 1457 } else if (noImplicitLod && ! fetch && ! gather) { 1458 // have to explicitly use lod of 0 if not allowed to have them be implicit, and 1459 // we would otherwise be about to issue an implicit instruction 1460 mask = (ImageOperandsMask)(mask | ImageOperandsLodMask); 1461 texArgs[numArgs++] = makeFloatConstant(0.0); 1462 explicitLod = true; 1463 } 1464 if (parameters.offset) { 1465 if (isConstant(parameters.offset)) 1466 mask = (ImageOperandsMask)(mask | ImageOperandsConstOffsetMask); 1467 else { 1468 addCapability(CapabilityImageGatherExtended); 1469 mask = (ImageOperandsMask)(mask | ImageOperandsOffsetMask); 1470 } 1471 texArgs[numArgs++] = parameters.offset; 1472 } 1473 if (parameters.offsets) { 1474 mask = (ImageOperandsMask)(mask | ImageOperandsConstOffsetsMask); 1475 texArgs[numArgs++] = parameters.offsets; 1476 } 1477 if (parameters.sample) { 1478 mask = (ImageOperandsMask)(mask | ImageOperandsSampleMask); 1479 texArgs[numArgs++] = parameters.sample; 1480 } 1481 if (parameters.lodClamp) { 1482 // capability if this bit is used 1483 addCapability(CapabilityMinLod); 1484 1485 mask = (ImageOperandsMask)(mask | ImageOperandsMinLodMask); 1486 texArgs[numArgs++] = parameters.lodClamp; 1487 } 1488 if (mask == ImageOperandsMaskNone) 1489 --numArgs; // undo speculative reservation for the mask argument 1490 else 1491 texArgs[optArgNum] = mask; 1492 1493 // 1494 // Set up the instruction 1495 // 1496 Op opCode = OpNop; // All paths below need to set this 1497 if (fetch) { 1498 if (sparse) 1499 opCode = OpImageSparseFetch; 1500 else 1501 opCode = OpImageFetch; 1502 } else if (gather) { 1503 if (parameters.Dref) 1504 if (sparse) 1505 opCode = OpImageSparseDrefGather; 1506 else 1507 opCode = OpImageDrefGather; 1508 else 1509 if (sparse) 1510 opCode = OpImageSparseGather; 1511 else 1512 opCode = OpImageGather; 1513 } else if (explicitLod) { 1514 if (parameters.Dref) { 1515 if (proj) 1516 if (sparse) 1517 opCode = OpImageSparseSampleProjDrefExplicitLod; 1518 else 1519 opCode = OpImageSampleProjDrefExplicitLod; 1520 else 1521 if (sparse) 1522 opCode = OpImageSparseSampleDrefExplicitLod; 1523 else 1524 opCode = OpImageSampleDrefExplicitLod; 1525 } else { 1526 if (proj) 1527 if (sparse) 1528 opCode = OpImageSparseSampleProjExplicitLod; 1529 else 1530 opCode = OpImageSampleProjExplicitLod; 1531 else 1532 if (sparse) 1533 opCode = OpImageSparseSampleExplicitLod; 1534 else 1535 opCode = OpImageSampleExplicitLod; 1536 } 1537 } else { 1538 if (parameters.Dref) { 1539 if (proj) 1540 if (sparse) 1541 opCode = OpImageSparseSampleProjDrefImplicitLod; 1542 else 1543 opCode = OpImageSampleProjDrefImplicitLod; 1544 else 1545 if (sparse) 1546 opCode = OpImageSparseSampleDrefImplicitLod; 1547 else 1548 opCode = OpImageSampleDrefImplicitLod; 1549 } else { 1550 if (proj) 1551 if (sparse) 1552 opCode = OpImageSparseSampleProjImplicitLod; 1553 else 1554 opCode = OpImageSampleProjImplicitLod; 1555 else 1556 if (sparse) 1557 opCode = OpImageSparseSampleImplicitLod; 1558 else 1559 opCode = OpImageSampleImplicitLod; 1560 } 1561 } 1562 1563 // See if the result type is expecting a smeared result. 1564 // This happens when a legacy shadow*() call is made, which 1565 // gets a vec4 back instead of a float. 1566 Id smearedType = resultType; 1567 if (! isScalarType(resultType)) { 1568 switch (opCode) { 1569 case OpImageSampleDrefImplicitLod: 1570 case OpImageSampleDrefExplicitLod: 1571 case OpImageSampleProjDrefImplicitLod: 1572 case OpImageSampleProjDrefExplicitLod: 1573 resultType = getScalarTypeId(resultType); 1574 break; 1575 default: 1576 break; 1577 } 1578 } 1579 1580 Id typeId0 = 0; 1581 Id typeId1 = 0; 1582 1583 if (sparse) { 1584 typeId0 = resultType; 1585 typeId1 = getDerefTypeId(parameters.texelOut); 1586 resultType = makeStructResultType(typeId0, typeId1); 1587 } 1588 1589 // Build the SPIR-V instruction 1590 Instruction* textureInst = new Instruction(getUniqueId(), resultType, opCode); 1591 for (int op = 0; op < optArgNum; ++op) 1592 textureInst->addIdOperand(texArgs[op]); 1593 if (optArgNum < numArgs) 1594 textureInst->addImmediateOperand(texArgs[optArgNum]); 1595 for (int op = optArgNum + 1; op < numArgs; ++op) 1596 textureInst->addIdOperand(texArgs[op]); 1597 setPrecision(textureInst->getResultId(), precision); 1598 buildPoint->addInstruction(std::unique_ptr<Instruction>(textureInst)); 1599 1600 Id resultId = textureInst->getResultId(); 1601 1602 if (sparse) { 1603 // set capability 1604 addCapability(CapabilitySparseResidency); 1605 1606 // Decode the return type that was a special structure 1607 createStore(createCompositeExtract(resultId, typeId1, 1), parameters.texelOut); 1608 resultId = createCompositeExtract(resultId, typeId0, 0); 1609 setPrecision(resultId, precision); 1610 } else { 1611 // When a smear is needed, do it, as per what was computed 1612 // above when resultType was changed to a scalar type. 1613 if (resultType != smearedType) 1614 resultId = smearScalar(precision, resultId, smearedType); 1615 } 1616 1617 return resultId; 1618 } 1619 1620 // Comments in header 1621 Id Builder::createTextureQueryCall(Op opCode, const TextureParameters& parameters) 1622 { 1623 // All these need a capability 1624 addCapability(CapabilityImageQuery); 1625 1626 // Figure out the result type 1627 Id resultType = 0; 1628 switch (opCode) { 1629 case OpImageQuerySize: 1630 case OpImageQuerySizeLod: 1631 { 1632 int numComponents = 0; 1633 switch (getTypeDimensionality(getImageType(parameters.sampler))) { 1634 case Dim1D: 1635 case DimBuffer: 1636 numComponents = 1; 1637 break; 1638 case Dim2D: 1639 case DimCube: 1640 case DimRect: 1641 case DimSubpassData: 1642 numComponents = 2; 1643 break; 1644 case Dim3D: 1645 numComponents = 3; 1646 break; 1647 1648 default: 1649 assert(0); 1650 break; 1651 } 1652 if (isArrayedImageType(getImageType(parameters.sampler))) 1653 ++numComponents; 1654 if (numComponents == 1) 1655 resultType = makeIntType(32); 1656 else 1657 resultType = makeVectorType(makeIntType(32), numComponents); 1658 1659 break; 1660 } 1661 case OpImageQueryLod: 1662 resultType = makeVectorType(makeFloatType(32), 2); 1663 break; 1664 case OpImageQueryLevels: 1665 case OpImageQuerySamples: 1666 resultType = makeIntType(32); 1667 break; 1668 default: 1669 assert(0); 1670 break; 1671 } 1672 1673 Instruction* query = new Instruction(getUniqueId(), resultType, opCode); 1674 query->addIdOperand(parameters.sampler); 1675 if (parameters.coords) 1676 query->addIdOperand(parameters.coords); 1677 if (parameters.lod) 1678 query->addIdOperand(parameters.lod); 1679 buildPoint->addInstruction(std::unique_ptr<Instruction>(query)); 1680 1681 return query->getResultId(); 1682 } 1683 1684 // External comments in header. 1685 // Operates recursively to visit the composite's hierarchy. 1686 Id Builder::createCompositeCompare(Decoration precision, Id value1, Id value2, bool equal) 1687 { 1688 Id boolType = makeBoolType(); 1689 Id valueType = getTypeId(value1); 1690 1691 Id resultId = NoResult; 1692 1693 int numConstituents = getNumTypeConstituents(valueType); 1694 1695 // Scalars and Vectors 1696 1697 if (isScalarType(valueType) || isVectorType(valueType)) { 1698 assert(valueType == getTypeId(value2)); 1699 // These just need a single comparison, just have 1700 // to figure out what it is. 1701 Op op; 1702 switch (getMostBasicTypeClass(valueType)) { 1703 case OpTypeFloat: 1704 op = equal ? OpFOrdEqual : OpFOrdNotEqual; 1705 break; 1706 case OpTypeInt: 1707 default: 1708 op = equal ? OpIEqual : OpINotEqual; 1709 break; 1710 case OpTypeBool: 1711 op = equal ? OpLogicalEqual : OpLogicalNotEqual; 1712 precision = NoPrecision; 1713 break; 1714 } 1715 1716 if (isScalarType(valueType)) { 1717 // scalar 1718 resultId = createBinOp(op, boolType, value1, value2); 1719 } else { 1720 // vector 1721 resultId = createBinOp(op, makeVectorType(boolType, numConstituents), value1, value2); 1722 setPrecision(resultId, precision); 1723 // reduce vector compares... 1724 resultId = createUnaryOp(equal ? OpAll : OpAny, boolType, resultId); 1725 } 1726 1727 return setPrecision(resultId, precision); 1728 } 1729 1730 // Only structs, arrays, and matrices should be left. 1731 // They share in common the reduction operation across their constituents. 1732 assert(isAggregateType(valueType) || isMatrixType(valueType)); 1733 1734 // Compare each pair of constituents 1735 for (int constituent = 0; constituent < numConstituents; ++constituent) { 1736 std::vector<unsigned> indexes(1, constituent); 1737 Id constituentType1 = getContainedTypeId(getTypeId(value1), constituent); 1738 Id constituentType2 = getContainedTypeId(getTypeId(value2), constituent); 1739 Id constituent1 = createCompositeExtract(value1, constituentType1, indexes); 1740 Id constituent2 = createCompositeExtract(value2, constituentType2, indexes); 1741 1742 Id subResultId = createCompositeCompare(precision, constituent1, constituent2, equal); 1743 1744 if (constituent == 0) 1745 resultId = subResultId; 1746 else 1747 resultId = setPrecision(createBinOp(equal ? OpLogicalAnd : OpLogicalOr, boolType, resultId, subResultId), precision); 1748 } 1749 1750 return resultId; 1751 } 1752 1753 // OpCompositeConstruct 1754 Id Builder::createCompositeConstruct(Id typeId, std::vector<Id>& constituents) 1755 { 1756 assert(isAggregateType(typeId) || (getNumTypeConstituents(typeId) > 1 && getNumTypeConstituents(typeId) == (int)constituents.size())); 1757 1758 if (generatingOpCodeForSpecConst) { 1759 // Sometime, even in spec-constant-op mode, the constant composite to be 1760 // constructed may not be a specialization constant. 1761 // e.g.: 1762 // const mat2 m2 = mat2(a_spec_const, a_front_end_const, another_front_end_const, third_front_end_const); 1763 // The first column vector should be a spec constant one, as a_spec_const is a spec constant. 1764 // The second column vector should NOT be spec constant, as it does not contain any spec constants. 1765 // To handle such cases, we check the constituents of the constant vector to determine whether this 1766 // vector should be created as a spec constant. 1767 return makeCompositeConstant(typeId, constituents, 1768 std::any_of(constituents.begin(), constituents.end(), 1769 [&](spv::Id id) { return isSpecConstant(id); })); 1770 } 1771 1772 Instruction* op = new Instruction(getUniqueId(), typeId, OpCompositeConstruct); 1773 for (int c = 0; c < (int)constituents.size(); ++c) 1774 op->addIdOperand(constituents[c]); 1775 buildPoint->addInstruction(std::unique_ptr<Instruction>(op)); 1776 1777 return op->getResultId(); 1778 } 1779 1780 // Vector or scalar constructor 1781 Id Builder::createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId) 1782 { 1783 Id result = NoResult; 1784 unsigned int numTargetComponents = getNumTypeComponents(resultTypeId); 1785 unsigned int targetComponent = 0; 1786 1787 // Special case: when calling a vector constructor with a single scalar 1788 // argument, smear the scalar 1789 if (sources.size() == 1 && isScalar(sources[0]) && numTargetComponents > 1) 1790 return smearScalar(precision, sources[0], resultTypeId); 1791 1792 Id scalarTypeId = getScalarTypeId(resultTypeId); 1793 std::vector<Id> constituents; // accumulate the arguments for OpCompositeConstruct 1794 for (unsigned int i = 0; i < sources.size(); ++i) { 1795 assert(! isAggregate(sources[i])); 1796 unsigned int sourceSize = getNumComponents(sources[i]); 1797 unsigned int sourcesToUse = sourceSize; 1798 if (sourcesToUse + targetComponent > numTargetComponents) 1799 sourcesToUse = numTargetComponents - targetComponent; 1800 1801 for (unsigned int s = 0; s < sourcesToUse; ++s) { 1802 Id arg = sources[i]; 1803 if (sourceSize > 1) { 1804 std::vector<unsigned> swiz; 1805 swiz.push_back(s); 1806 arg = createRvalueSwizzle(precision, scalarTypeId, arg, swiz); 1807 } 1808 1809 if (numTargetComponents > 1) 1810 constituents.push_back(arg); 1811 else 1812 result = arg; 1813 ++targetComponent; 1814 } 1815 1816 if (targetComponent >= numTargetComponents) 1817 break; 1818 } 1819 1820 if (constituents.size() > 0) 1821 result = createCompositeConstruct(resultTypeId, constituents); 1822 1823 return setPrecision(result, precision); 1824 } 1825 1826 // Comments in header 1827 Id Builder::createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId) 1828 { 1829 Id componentTypeId = getScalarTypeId(resultTypeId); 1830 int numCols = getTypeNumColumns(resultTypeId); 1831 int numRows = getTypeNumRows(resultTypeId); 1832 1833 Instruction* instr = module.getInstruction(componentTypeId); 1834 Id bitCount = instr->getIdOperand(0); 1835 1836 // Will use a two step process 1837 // 1. make a compile-time 2D array of values 1838 // 2. construct a matrix from that array 1839 1840 // Step 1. 1841 1842 // initialize the array to the identity matrix 1843 Id ids[maxMatrixSize][maxMatrixSize]; 1844 Id one = (bitCount == 64 ? makeDoubleConstant(1.0) : makeFloatConstant(1.0)); 1845 Id zero = (bitCount == 64 ? makeDoubleConstant(0.0) : makeFloatConstant(0.0)); 1846 for (int col = 0; col < 4; ++col) { 1847 for (int row = 0; row < 4; ++row) { 1848 if (col == row) 1849 ids[col][row] = one; 1850 else 1851 ids[col][row] = zero; 1852 } 1853 } 1854 1855 // modify components as dictated by the arguments 1856 if (sources.size() == 1 && isScalar(sources[0])) { 1857 // a single scalar; resets the diagonals 1858 for (int col = 0; col < 4; ++col) 1859 ids[col][col] = sources[0]; 1860 } else if (isMatrix(sources[0])) { 1861 // constructing from another matrix; copy over the parts that exist in both the argument and constructee 1862 Id matrix = sources[0]; 1863 int minCols = std::min(numCols, getNumColumns(matrix)); 1864 int minRows = std::min(numRows, getNumRows(matrix)); 1865 for (int col = 0; col < minCols; ++col) { 1866 std::vector<unsigned> indexes; 1867 indexes.push_back(col); 1868 for (int row = 0; row < minRows; ++row) { 1869 indexes.push_back(row); 1870 ids[col][row] = createCompositeExtract(matrix, componentTypeId, indexes); 1871 indexes.pop_back(); 1872 setPrecision(ids[col][row], precision); 1873 } 1874 } 1875 } else { 1876 // fill in the matrix in column-major order with whatever argument components are available 1877 int row = 0; 1878 int col = 0; 1879 1880 for (int arg = 0; arg < (int)sources.size(); ++arg) { 1881 Id argComp = sources[arg]; 1882 for (int comp = 0; comp < getNumComponents(sources[arg]); ++comp) { 1883 if (getNumComponents(sources[arg]) > 1) { 1884 argComp = createCompositeExtract(sources[arg], componentTypeId, comp); 1885 setPrecision(argComp, precision); 1886 } 1887 ids[col][row++] = argComp; 1888 if (row == numRows) { 1889 row = 0; 1890 col++; 1891 } 1892 } 1893 } 1894 } 1895 1896 1897 // Step 2: Construct a matrix from that array. 1898 // First make the column vectors, then make the matrix. 1899 1900 // make the column vectors 1901 Id columnTypeId = getContainedTypeId(resultTypeId); 1902 std::vector<Id> matrixColumns; 1903 for (int col = 0; col < numCols; ++col) { 1904 std::vector<Id> vectorComponents; 1905 for (int row = 0; row < numRows; ++row) 1906 vectorComponents.push_back(ids[col][row]); 1907 Id column = createCompositeConstruct(columnTypeId, vectorComponents); 1908 setPrecision(column, precision); 1909 matrixColumns.push_back(column); 1910 } 1911 1912 // make the matrix 1913 return setPrecision(createCompositeConstruct(resultTypeId, matrixColumns), precision); 1914 } 1915 1916 // Comments in header 1917 Builder::If::If(Id cond, Builder& gb) : 1918 builder(gb), 1919 condition(cond), 1920 elseBlock(0) 1921 { 1922 function = &builder.getBuildPoint()->getParent(); 1923 1924 // make the blocks, but only put the then-block into the function, 1925 // the else-block and merge-block will be added later, in order, after 1926 // earlier code is emitted 1927 thenBlock = new Block(builder.getUniqueId(), *function); 1928 mergeBlock = new Block(builder.getUniqueId(), *function); 1929 1930 // Save the current block, so that we can add in the flow control split when 1931 // makeEndIf is called. 1932 headerBlock = builder.getBuildPoint(); 1933 1934 function->addBlock(thenBlock); 1935 builder.setBuildPoint(thenBlock); 1936 } 1937 1938 // Comments in header 1939 void Builder::If::makeBeginElse() 1940 { 1941 // Close out the "then" by having it jump to the mergeBlock 1942 builder.createBranch(mergeBlock); 1943 1944 // Make the first else block and add it to the function 1945 elseBlock = new Block(builder.getUniqueId(), *function); 1946 function->addBlock(elseBlock); 1947 1948 // Start building the else block 1949 builder.setBuildPoint(elseBlock); 1950 } 1951 1952 // Comments in header 1953 void Builder::If::makeEndIf() 1954 { 1955 // jump to the merge block 1956 builder.createBranch(mergeBlock); 1957 1958 // Go back to the headerBlock and make the flow control split 1959 builder.setBuildPoint(headerBlock); 1960 builder.createSelectionMerge(mergeBlock, SelectionControlMaskNone); 1961 if (elseBlock) 1962 builder.createConditionalBranch(condition, thenBlock, elseBlock); 1963 else 1964 builder.createConditionalBranch(condition, thenBlock, mergeBlock); 1965 1966 // add the merge block to the function 1967 function->addBlock(mergeBlock); 1968 builder.setBuildPoint(mergeBlock); 1969 } 1970 1971 // Comments in header 1972 void Builder::makeSwitch(Id selector, int numSegments, std::vector<int>& caseValues, std::vector<int>& valueIndexToSegment, int defaultSegment, 1973 std::vector<Block*>& segmentBlocks) 1974 { 1975 Function& function = buildPoint->getParent(); 1976 1977 // make all the blocks 1978 for (int s = 0; s < numSegments; ++s) 1979 segmentBlocks.push_back(new Block(getUniqueId(), function)); 1980 1981 Block* mergeBlock = new Block(getUniqueId(), function); 1982 1983 // make and insert the switch's selection-merge instruction 1984 createSelectionMerge(mergeBlock, SelectionControlMaskNone); 1985 1986 // make the switch instruction 1987 Instruction* switchInst = new Instruction(NoResult, NoType, OpSwitch); 1988 switchInst->addIdOperand(selector); 1989 auto defaultOrMerge = (defaultSegment >= 0) ? segmentBlocks[defaultSegment] : mergeBlock; 1990 switchInst->addIdOperand(defaultOrMerge->getId()); 1991 defaultOrMerge->addPredecessor(buildPoint); 1992 for (int i = 0; i < (int)caseValues.size(); ++i) { 1993 switchInst->addImmediateOperand(caseValues[i]); 1994 switchInst->addIdOperand(segmentBlocks[valueIndexToSegment[i]]->getId()); 1995 segmentBlocks[valueIndexToSegment[i]]->addPredecessor(buildPoint); 1996 } 1997 buildPoint->addInstruction(std::unique_ptr<Instruction>(switchInst)); 1998 1999 // push the merge block 2000 switchMerges.push(mergeBlock); 2001 } 2002 2003 // Comments in header 2004 void Builder::addSwitchBreak() 2005 { 2006 // branch to the top of the merge block stack 2007 createBranch(switchMerges.top()); 2008 createAndSetNoPredecessorBlock("post-switch-break"); 2009 } 2010 2011 // Comments in header 2012 void Builder::nextSwitchSegment(std::vector<Block*>& segmentBlock, int nextSegment) 2013 { 2014 int lastSegment = nextSegment - 1; 2015 if (lastSegment >= 0) { 2016 // Close out previous segment by jumping, if necessary, to next segment 2017 if (! buildPoint->isTerminated()) 2018 createBranch(segmentBlock[nextSegment]); 2019 } 2020 Block* block = segmentBlock[nextSegment]; 2021 block->getParent().addBlock(block); 2022 setBuildPoint(block); 2023 } 2024 2025 // Comments in header 2026 void Builder::endSwitch(std::vector<Block*>& /*segmentBlock*/) 2027 { 2028 // Close out previous segment by jumping, if necessary, to next segment 2029 if (! buildPoint->isTerminated()) 2030 addSwitchBreak(); 2031 2032 switchMerges.top()->getParent().addBlock(switchMerges.top()); 2033 setBuildPoint(switchMerges.top()); 2034 2035 switchMerges.pop(); 2036 } 2037 2038 Block& Builder::makeNewBlock() 2039 { 2040 Function& function = buildPoint->getParent(); 2041 auto block = new Block(getUniqueId(), function); 2042 function.addBlock(block); 2043 return *block; 2044 } 2045 2046 Builder::LoopBlocks& Builder::makeNewLoop() 2047 { 2048 // This verbosity is needed to simultaneously get the same behavior 2049 // everywhere (id's in the same order), have a syntax that works 2050 // across lots of versions of C++, have no warnings from pedantic 2051 // compilation modes, and leave the rest of the code alone. 2052 Block& head = makeNewBlock(); 2053 Block& body = makeNewBlock(); 2054 Block& merge = makeNewBlock(); 2055 Block& continue_target = makeNewBlock(); 2056 LoopBlocks blocks(head, body, merge, continue_target); 2057 loops.push(blocks); 2058 return loops.top(); 2059 } 2060 2061 void Builder::createLoopContinue() 2062 { 2063 createBranch(&loops.top().continue_target); 2064 // Set up a block for dead code. 2065 createAndSetNoPredecessorBlock("post-loop-continue"); 2066 } 2067 2068 void Builder::createLoopExit() 2069 { 2070 createBranch(&loops.top().merge); 2071 // Set up a block for dead code. 2072 createAndSetNoPredecessorBlock("post-loop-break"); 2073 } 2074 2075 void Builder::closeLoop() 2076 { 2077 loops.pop(); 2078 } 2079 2080 void Builder::clearAccessChain() 2081 { 2082 accessChain.base = NoResult; 2083 accessChain.indexChain.clear(); 2084 accessChain.instr = NoResult; 2085 accessChain.swizzle.clear(); 2086 accessChain.component = NoResult; 2087 accessChain.preSwizzleBaseType = NoType; 2088 accessChain.isRValue = false; 2089 } 2090 2091 // Comments in header 2092 void Builder::accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType) 2093 { 2094 // swizzles can be stacked in GLSL, but simplified to a single 2095 // one here; the base type doesn't change 2096 if (accessChain.preSwizzleBaseType == NoType) 2097 accessChain.preSwizzleBaseType = preSwizzleBaseType; 2098 2099 // if needed, propagate the swizzle for the current access chain 2100 if (accessChain.swizzle.size()) { 2101 std::vector<unsigned> oldSwizzle = accessChain.swizzle; 2102 accessChain.swizzle.resize(0); 2103 for (unsigned int i = 0; i < swizzle.size(); ++i) { 2104 accessChain.swizzle.push_back(oldSwizzle[swizzle[i]]); 2105 } 2106 } else 2107 accessChain.swizzle = swizzle; 2108 2109 // determine if we need to track this swizzle anymore 2110 simplifyAccessChainSwizzle(); 2111 } 2112 2113 // Comments in header 2114 void Builder::accessChainStore(Id rvalue) 2115 { 2116 assert(accessChain.isRValue == false); 2117 2118 transferAccessChainSwizzle(true); 2119 Id base = collapseAccessChain(); 2120 2121 if (accessChain.swizzle.size() && accessChain.component != NoResult) 2122 logger->missingFunctionality("simultaneous l-value swizzle and dynamic component selection"); 2123 2124 // If swizzle still exists, it is out-of-order or not full, we must load the target vector, 2125 // extract and insert elements to perform writeMask and/or swizzle. 2126 Id source = NoResult; 2127 if (accessChain.swizzle.size()) { 2128 Id tempBaseId = createLoad(base); 2129 source = createLvalueSwizzle(getTypeId(tempBaseId), tempBaseId, rvalue, accessChain.swizzle); 2130 } 2131 2132 // dynamic component selection 2133 if (accessChain.component != NoResult) { 2134 Id tempBaseId = (source == NoResult) ? createLoad(base) : source; 2135 source = createVectorInsertDynamic(tempBaseId, getTypeId(tempBaseId), rvalue, accessChain.component); 2136 } 2137 2138 if (source == NoResult) 2139 source = rvalue; 2140 2141 createStore(source, base); 2142 } 2143 2144 // Comments in header 2145 Id Builder::accessChainLoad(Decoration precision, Id resultType) 2146 { 2147 Id id; 2148 2149 if (accessChain.isRValue) { 2150 // transfer access chain, but keep it static, so we can stay in registers 2151 transferAccessChainSwizzle(false); 2152 if (accessChain.indexChain.size() > 0) { 2153 Id swizzleBase = accessChain.preSwizzleBaseType != NoType ? accessChain.preSwizzleBaseType : resultType; 2154 2155 // if all the accesses are constants, we can use OpCompositeExtract 2156 std::vector<unsigned> indexes; 2157 bool constant = true; 2158 for (int i = 0; i < (int)accessChain.indexChain.size(); ++i) { 2159 if (isConstantScalar(accessChain.indexChain[i])) 2160 indexes.push_back(getConstantScalar(accessChain.indexChain[i])); 2161 else { 2162 constant = false; 2163 break; 2164 } 2165 } 2166 2167 if (constant) 2168 id = createCompositeExtract(accessChain.base, swizzleBase, indexes); 2169 else { 2170 // make a new function variable for this r-value 2171 Id lValue = createVariable(StorageClassFunction, getTypeId(accessChain.base), "indexable"); 2172 2173 // store into it 2174 createStore(accessChain.base, lValue); 2175 2176 // move base to the new variable 2177 accessChain.base = lValue; 2178 accessChain.isRValue = false; 2179 2180 // load through the access chain 2181 id = createLoad(collapseAccessChain()); 2182 } 2183 setPrecision(id, precision); 2184 } else 2185 id = accessChain.base; // no precision, it was set when this was defined 2186 } else { 2187 transferAccessChainSwizzle(true); 2188 // load through the access chain 2189 id = createLoad(collapseAccessChain()); 2190 setPrecision(id, precision); 2191 } 2192 2193 // Done, unless there are swizzles to do 2194 if (accessChain.swizzle.size() == 0 && accessChain.component == NoResult) 2195 return id; 2196 2197 // Do remaining swizzling 2198 // First, static swizzling 2199 if (accessChain.swizzle.size()) { 2200 // static swizzle 2201 Id swizzledType = getScalarTypeId(getTypeId(id)); 2202 if (accessChain.swizzle.size() > 1) 2203 swizzledType = makeVectorType(swizzledType, (int)accessChain.swizzle.size()); 2204 id = createRvalueSwizzle(precision, swizzledType, id, accessChain.swizzle); 2205 } 2206 2207 // dynamic single-component selection 2208 if (accessChain.component != NoResult) 2209 id = setPrecision(createVectorExtractDynamic(id, resultType, accessChain.component), precision); 2210 2211 return id; 2212 } 2213 2214 Id Builder::accessChainGetLValue() 2215 { 2216 assert(accessChain.isRValue == false); 2217 2218 transferAccessChainSwizzle(true); 2219 Id lvalue = collapseAccessChain(); 2220 2221 // If swizzle exists, it is out-of-order or not full, we must load the target vector, 2222 // extract and insert elements to perform writeMask and/or swizzle. This does not 2223 // go with getting a direct l-value pointer. 2224 assert(accessChain.swizzle.size() == 0); 2225 assert(accessChain.component == NoResult); 2226 2227 return lvalue; 2228 } 2229 2230 // comment in header 2231 Id Builder::accessChainGetInferredType() 2232 { 2233 // anything to operate on? 2234 if (accessChain.base == NoResult) 2235 return NoType; 2236 Id type = getTypeId(accessChain.base); 2237 2238 // do initial dereference 2239 if (! accessChain.isRValue) 2240 type = getContainedTypeId(type); 2241 2242 // dereference each index 2243 for (auto it = accessChain.indexChain.cbegin(); it != accessChain.indexChain.cend(); ++it) { 2244 if (isStructType(type)) 2245 type = getContainedTypeId(type, getConstantScalar(*it)); 2246 else 2247 type = getContainedTypeId(type); 2248 } 2249 2250 // dereference swizzle 2251 if (accessChain.swizzle.size() == 1) 2252 type = getContainedTypeId(type); 2253 else if (accessChain.swizzle.size() > 1) 2254 type = makeVectorType(getContainedTypeId(type), (int)accessChain.swizzle.size()); 2255 2256 // dereference component selection 2257 if (accessChain.component) 2258 type = getContainedTypeId(type); 2259 2260 return type; 2261 } 2262 2263 // comment in header 2264 void Builder::eliminateDeadDecorations() { 2265 std::unordered_set<const Block*> reachable_blocks; 2266 std::unordered_set<Id> unreachable_definitions; 2267 // Collect IDs defined in unreachable blocks. For each function, label the 2268 // reachable blocks first. Then for each unreachable block, collect the 2269 // result IDs of the instructions in it. 2270 for (std::vector<Function*>::const_iterator fi = module.getFunctions().cbegin(); 2271 fi != module.getFunctions().cend(); fi++) { 2272 Function* f = *fi; 2273 Block* entry = f->getEntryBlock(); 2274 inReadableOrder(entry, [&reachable_blocks](const Block* b) { 2275 reachable_blocks.insert(b); 2276 }); 2277 for (std::vector<Block*>::const_iterator bi = f->getBlocks().cbegin(); 2278 bi != f->getBlocks().cend(); bi++) { 2279 Block* b = *bi; 2280 if (!reachable_blocks.count(b)) { 2281 for (std::vector<std::unique_ptr<Instruction> >::const_iterator 2282 ii = b->getInstructions().cbegin(); 2283 ii != b->getInstructions().cend(); ii++) { 2284 Instruction* i = ii->get(); 2285 unreachable_definitions.insert(i->getResultId()); 2286 } 2287 } 2288 } 2289 } 2290 decorations.erase(std::remove_if(decorations.begin(), decorations.end(), 2291 [&unreachable_definitions](std::unique_ptr<Instruction>& I) -> bool { 2292 Instruction* inst = I.get(); 2293 Id decoration_id = inst->getIdOperand(0); 2294 return unreachable_definitions.count(decoration_id) != 0; 2295 }), 2296 decorations.end()); 2297 } 2298 2299 void Builder::dump(std::vector<unsigned int>& out) const 2300 { 2301 // Header, before first instructions: 2302 out.push_back(MagicNumber); 2303 out.push_back(Version); 2304 out.push_back(builderNumber); 2305 out.push_back(uniqueId + 1); 2306 out.push_back(0); 2307 2308 // Capabilities 2309 for (auto it = capabilities.cbegin(); it != capabilities.cend(); ++it) { 2310 Instruction capInst(0, 0, OpCapability); 2311 capInst.addImmediateOperand(*it); 2312 capInst.dump(out); 2313 } 2314 2315 // TBD: OpExtension ... 2316 2317 dumpInstructions(out, imports); 2318 Instruction memInst(0, 0, OpMemoryModel); 2319 memInst.addImmediateOperand(addressModel); 2320 memInst.addImmediateOperand(memoryModel); 2321 memInst.dump(out); 2322 2323 // Instructions saved up while building: 2324 dumpInstructions(out, entryPoints); 2325 dumpInstructions(out, executionModes); 2326 2327 // Debug instructions 2328 if (source != SourceLanguageUnknown) { 2329 Instruction sourceInst(0, 0, OpSource); 2330 sourceInst.addImmediateOperand(source); 2331 sourceInst.addImmediateOperand(sourceVersion); 2332 sourceInst.dump(out); 2333 } 2334 for (int e = 0; e < (int)extensions.size(); ++e) { 2335 Instruction extInst(0, 0, OpSourceExtension); 2336 extInst.addStringOperand(extensions[e]); 2337 extInst.dump(out); 2338 } 2339 dumpInstructions(out, names); 2340 dumpInstructions(out, lines); 2341 2342 // Annotation instructions 2343 dumpInstructions(out, decorations); 2344 2345 dumpInstructions(out, constantsTypesGlobals); 2346 dumpInstructions(out, externals); 2347 2348 // The functions 2349 module.dump(out); 2350 } 2351 2352 // 2353 // Protected methods. 2354 // 2355 2356 // Turn the described access chain in 'accessChain' into an instruction 2357 // computing its address. This *cannot* include complex swizzles, which must 2358 // be handled after this is called, but it does include swizzles that select 2359 // an individual element, as a single address of a scalar type can be 2360 // computed by an OpAccessChain instruction. 2361 Id Builder::collapseAccessChain() 2362 { 2363 assert(accessChain.isRValue == false); 2364 2365 if (accessChain.indexChain.size() > 0) { 2366 if (accessChain.instr == 0) { 2367 StorageClass storageClass = (StorageClass)module.getStorageClass(getTypeId(accessChain.base)); 2368 accessChain.instr = createAccessChain(storageClass, accessChain.base, accessChain.indexChain); 2369 } 2370 2371 return accessChain.instr; 2372 } else 2373 return accessChain.base; 2374 2375 // note that non-trivial swizzling is left pending... 2376 } 2377 2378 // clear out swizzle if it is redundant, that is reselecting the same components 2379 // that would be present without the swizzle. 2380 void Builder::simplifyAccessChainSwizzle() 2381 { 2382 // If the swizzle has fewer components than the vector, it is subsetting, and must stay 2383 // to preserve that fact. 2384 if (getNumTypeComponents(accessChain.preSwizzleBaseType) > (int)accessChain.swizzle.size()) 2385 return; 2386 2387 // if components are out of order, it is a swizzle 2388 for (unsigned int i = 0; i < accessChain.swizzle.size(); ++i) { 2389 if (i != accessChain.swizzle[i]) 2390 return; 2391 } 2392 2393 // otherwise, there is no need to track this swizzle 2394 accessChain.swizzle.clear(); 2395 if (accessChain.component == NoResult) 2396 accessChain.preSwizzleBaseType = NoType; 2397 } 2398 2399 // To the extent any swizzling can become part of the chain 2400 // of accesses instead of a post operation, make it so. 2401 // If 'dynamic' is true, include transferring a non-static component index, 2402 // otherwise, only transfer static indexes. 2403 // 2404 // Also, Boolean vectors are likely to be special. While 2405 // for external storage, they should only be integer types, 2406 // function-local bool vectors could use sub-word indexing, 2407 // so keep that as a separate Insert/Extract on a loaded vector. 2408 void Builder::transferAccessChainSwizzle(bool dynamic) 2409 { 2410 // too complex? 2411 if (accessChain.swizzle.size() > 1) 2412 return; 2413 2414 // non existent? 2415 if (accessChain.swizzle.size() == 0 && accessChain.component == NoResult) 2416 return; 2417 2418 // single component... 2419 2420 // skip doing it for Boolean vectors 2421 if (isBoolType(getContainedTypeId(accessChain.preSwizzleBaseType))) 2422 return; 2423 2424 if (accessChain.swizzle.size() == 1) { 2425 // handle static component 2426 accessChain.indexChain.push_back(makeUintConstant(accessChain.swizzle.front())); 2427 accessChain.swizzle.clear(); 2428 // note, the only valid remaining dynamic access would be to this one 2429 // component, so don't bother even looking at accessChain.component 2430 accessChain.preSwizzleBaseType = NoType; 2431 accessChain.component = NoResult; 2432 } else if (dynamic && accessChain.component != NoResult) { 2433 // handle dynamic component 2434 accessChain.indexChain.push_back(accessChain.component); 2435 accessChain.preSwizzleBaseType = NoType; 2436 accessChain.component = NoResult; 2437 } 2438 } 2439 2440 // Utility method for creating a new block and setting the insert point to 2441 // be in it. This is useful for flow-control operations that need a "dummy" 2442 // block proceeding them (e.g. instructions after a discard, etc). 2443 void Builder::createAndSetNoPredecessorBlock(const char* /*name*/) 2444 { 2445 Block* block = new Block(getUniqueId(), buildPoint->getParent()); 2446 block->setUnreachable(); 2447 buildPoint->getParent().addBlock(block); 2448 setBuildPoint(block); 2449 2450 //if (name) 2451 // addName(block->getId(), name); 2452 } 2453 2454 // Comments in header 2455 void Builder::createBranch(Block* block) 2456 { 2457 Instruction* branch = new Instruction(OpBranch); 2458 branch->addIdOperand(block->getId()); 2459 buildPoint->addInstruction(std::unique_ptr<Instruction>(branch)); 2460 block->addPredecessor(buildPoint); 2461 } 2462 2463 void Builder::createSelectionMerge(Block* mergeBlock, unsigned int control) 2464 { 2465 Instruction* merge = new Instruction(OpSelectionMerge); 2466 merge->addIdOperand(mergeBlock->getId()); 2467 merge->addImmediateOperand(control); 2468 buildPoint->addInstruction(std::unique_ptr<Instruction>(merge)); 2469 } 2470 2471 void Builder::createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control) 2472 { 2473 Instruction* merge = new Instruction(OpLoopMerge); 2474 merge->addIdOperand(mergeBlock->getId()); 2475 merge->addIdOperand(continueBlock->getId()); 2476 merge->addImmediateOperand(control); 2477 buildPoint->addInstruction(std::unique_ptr<Instruction>(merge)); 2478 } 2479 2480 void Builder::createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock) 2481 { 2482 Instruction* branch = new Instruction(OpBranchConditional); 2483 branch->addIdOperand(condition); 2484 branch->addIdOperand(thenBlock->getId()); 2485 branch->addIdOperand(elseBlock->getId()); 2486 buildPoint->addInstruction(std::unique_ptr<Instruction>(branch)); 2487 thenBlock->addPredecessor(buildPoint); 2488 elseBlock->addPredecessor(buildPoint); 2489 } 2490 2491 void Builder::dumpInstructions(std::vector<unsigned int>& out, const std::vector<std::unique_ptr<Instruction> >& instructions) const 2492 { 2493 for (int i = 0; i < (int)instructions.size(); ++i) { 2494 instructions[i]->dump(out); 2495 } 2496 } 2497 2498 }; // end spv namespace 2499