|
15 | 15 |
|
16 | 16 | #include "AlignmentSizeCalculator.h" |
17 | 17 | #include "InitListHandler.h" |
| 18 | +#include "LowerTypeVisitor.h" |
18 | 19 | #include "RawBufferMethods.h" |
19 | 20 | #include "dxc/DXIL/DxilConstants.h" |
20 | 21 | #include "dxc/HlslIntrinsicOp.h" |
@@ -542,6 +543,71 @@ bool isVkRawBufferLoadIntrinsic(const clang::FunctionDecl *FD) { |
542 | 543 | return true; |
543 | 544 | } |
544 | 545 |
|
| 546 | +// Takes an AST member type, and determines its index in the equivalent SPIR-V |
| 547 | +// struct type. This is required as the struct layout might change between the |
| 548 | +// AST representation and SPIR-V representation. |
| 549 | +uint32_t getFieldIndexInStruct(const SpirvCodeGenOptions &spirvOptions, |
| 550 | + LowerTypeVisitor &lowerTypeVisitor, |
| 551 | + const MemberExpr *expr) { |
| 552 | + // If we are accessing a derived struct, we need to account for the number |
| 553 | + // of base structs, since they are placed as fields at the beginning of the |
| 554 | + // derived struct. |
| 555 | + auto baseType = expr->getBase()->getType(); |
| 556 | + if (baseType->isPointerType()) { |
| 557 | + baseType = baseType->getPointeeType(); |
| 558 | + } |
| 559 | + |
| 560 | + const auto *fieldDecl = |
| 561 | + dynamic_cast<const FieldDecl *>(expr->getMemberDecl()); |
| 562 | + assert(fieldDecl); |
| 563 | + const uint32_t indexAST = |
| 564 | + getNumBaseClasses(baseType) + fieldDecl->getFieldIndex(); |
| 565 | + |
| 566 | + // The AST type index is not representative of the SPIR-V type index |
| 567 | + // because we might squash some fields (bitfields by ex.). |
| 568 | + // What we need is to match each AST node with the squashed field and then, |
| 569 | + // determine the real index. |
| 570 | + const SpirvType *spvType = lowerTypeVisitor.lowerType( |
| 571 | + baseType, spirvOptions.sBufferLayoutRule, llvm::None, SourceLocation()); |
| 572 | + assert(spvType); |
| 573 | + |
| 574 | + const auto st = dynamic_cast<const StructType *>(spvType); |
| 575 | + assert(st != nullptr); |
| 576 | + const auto &fields = st->getFields(); |
| 577 | + assert(indexAST <= fields.size()); |
| 578 | + |
| 579 | + // Some fields in SPIR-V share the same index (bitfields). Computing the final |
| 580 | + // index of the requested field. |
| 581 | + uint32_t indexSPV = 0; |
| 582 | + for (size_t i = 1; i <= indexAST; i++) { |
| 583 | + // Do not remove this condition. This is required to support inheritance: |
| 584 | + // 1. SPIR-V composite first element is the parent type: |
| 585 | + // by ex "OpTypeStruct %base_struct %float". |
| 586 | + // 2. if the parent type is an empty class, it's size it zero, hence |
| 587 | + // "%float" offset is also 0. |
| 588 | + // |
| 589 | + // A way to detect such cases is to check for type difference: fields cannot |
| 590 | + // be merged if the type is different. |
| 591 | + if (fields[i - 1].type != fields[i].type) { |
| 592 | + indexSPV++; |
| 593 | + continue; |
| 594 | + } |
| 595 | + |
| 596 | + if (fields[i - 1].offset.getValueOr(0) != fields[i].offset.getValueOr(0)) { |
| 597 | + indexSPV++; |
| 598 | + continue; |
| 599 | + } |
| 600 | + } |
| 601 | + |
| 602 | + // TODO(issue #4140): remove once bitfields are implemented. |
| 603 | + // This is just a safeguard until bitfield support is in. Before bitfields, |
| 604 | + // AST indices were always correct, so this function should not change that |
| 605 | + // behavior. Once the bitfield support is in, indices will start to diverge, |
| 606 | + // and this assert should be removed. |
| 607 | + assert(indexSPV == indexAST); |
| 608 | + return indexSPV; |
| 609 | +} |
| 610 | + |
545 | 611 | } // namespace |
546 | 612 |
|
547 | 613 | SpirvEmitter::SpirvEmitter(CompilerInstance &ci) |
@@ -7614,23 +7680,17 @@ const Expr *SpirvEmitter::collectArrayStructIndices( |
7614 | 7680 | } |
7615 | 7681 | } |
7616 | 7682 |
|
7617 | | - // Append the index of the current level |
7618 | | - const auto *fieldDecl = cast<FieldDecl>(indexing->getMemberDecl()); |
7619 | | - assert(fieldDecl); |
7620 | | - // If we are accessing a derived struct, we need to account for the number |
7621 | | - // of base structs, since they are placed as fields at the beginning of the |
7622 | | - // derived struct. |
7623 | | - auto baseType = indexing->getBase()->getType(); |
7624 | | - if (baseType->isPointerType()) { |
7625 | | - baseType = baseType->getPointeeType(); |
7626 | | - } |
7627 | | - const uint32_t index = |
7628 | | - getNumBaseClasses(baseType) + fieldDecl->getFieldIndex(); |
7629 | | - if (rawIndex) { |
7630 | | - rawIndices->push_back(index); |
7631 | | - } else { |
7632 | | - indices->push_back(spvBuilder.getConstantInt( |
7633 | | - astContext.IntTy, llvm::APInt(32, index, true))); |
| 7683 | + { |
| 7684 | + LowerTypeVisitor lowerTypeVisitor(astContext, spvContext, spirvOptions); |
| 7685 | + const uint32_t fieldIndex = |
| 7686 | + getFieldIndexInStruct(spirvOptions, lowerTypeVisitor, indexing); |
| 7687 | + |
| 7688 | + if (rawIndex) { |
| 7689 | + rawIndices->push_back(fieldIndex); |
| 7690 | + } else { |
| 7691 | + indices->push_back(spvBuilder.getConstantInt( |
| 7692 | + astContext.IntTy, llvm::APInt(32, fieldIndex, true))); |
| 7693 | + } |
7634 | 7694 | } |
7635 | 7695 |
|
7636 | 7696 | return base; |
|
0 commit comments