2929#include "clang/SPIRV/String.h"
3030#include "clang/Sema/Sema.h"
3131#include "llvm/ADT/APInt.h"
32+ #include "llvm/ADT/SmallPtrSet.h"
33+ #include "llvm/ADT/SmallVector.h"
3234#include "llvm/ADT/SetVector.h"
3335#include "llvm/ADT/StringExtras.h"
3436#include "llvm/Support/Casting.h"
@@ -596,6 +598,7 @@ SpirvEmitter::SpirvEmitter(CompilerInstance &ci)
596598 needsLegalizationLoopUnroll(false),
597599 needsLegalizationSsaRewrite(false),
598600 sawExplicitUnrollHint(false),
601+ experimentalFastCompileRequiresDefaultPath(false),
599602 beforeHlslLegalization(false), mainSourceFile(nullptr) {
600603
601604 // Get ShaderModel from command line hlsl profile option.
@@ -1570,6 +1573,84 @@ bool SpirvEmitter::handleNodePayloadArrayType(const ParmVarDecl *decl,
15701573 }
15711574}
15721575
1576+ void SpirvEmitter::noteExperimentalFastCompileRisk(
1577+ QualType type, bool hasAliasedPointerAttr) {
1578+ if (!spirvOptions.o1ExperimentalFastCompile || type.isNull())
1579+ return;
1580+
1581+ auto hasRiskyDecorations = [](const Decl *decl) {
1582+ if (!decl || !decl->hasAttrs())
1583+ return false;
1584+
1585+ if (decl->hasAttr<VKAliasedPointerAttr>())
1586+ return true;
1587+
1588+ for (const auto *attr : decl->getAttrs()) {
1589+ if (const auto *decorateAttr = dyn_cast<VKDecorateExtAttr>(attr)) {
1590+ const auto decoration =
1591+ static_cast<spv::Decoration>(decorateAttr->getDecorate());
1592+ if (decoration == spv::Decoration::AliasedPointer ||
1593+ decoration == spv::Decoration::RestrictPointer) {
1594+ return true;
1595+ }
1596+ }
1597+ }
1598+ return false;
1599+ };
1600+
1601+ llvm::SmallVector<QualType, 8> worklist;
1602+ llvm::SmallPtrSet<const Type *, 16> visitedTypes;
1603+ worklist.push_back(type);
1604+
1605+ while (!worklist.empty()) {
1606+ QualType currentType = worklist.pop_back_val();
1607+ if (currentType.isNull())
1608+ continue;
1609+
1610+ Optional<bool> isRowMajor = llvm::None;
1611+ currentType = desugarType(currentType, &isRowMajor);
1612+
1613+ const Type *typePtr = currentType.getTypePtrOrNull();
1614+ if (!typePtr || !visitedTypes.insert(typePtr).second)
1615+ continue;
1616+
1617+ if (hasAliasedPointerAttr || hlsl::IsVKBufferPointerType(currentType) ||
1618+ isOpaqueArrayType(currentType) || isOpaqueStructType(currentType) ||
1619+ isBindlessOpaqueArray(currentType)) {
1620+ experimentalFastCompileRequiresDefaultPath = true;
1621+ return;
1622+ }
1623+
1624+ if (const auto *arrayType = currentType->getAsArrayTypeUnsafe()) {
1625+ worklist.push_back(arrayType->getElementType());
1626+ continue;
1627+ }
1628+
1629+ const auto *recordType = currentType->getAs<RecordType>();
1630+ if (!recordType)
1631+ continue;
1632+
1633+ const RecordDecl *recordDecl = recordType->getDecl();
1634+ if (hasRiskyDecorations(recordDecl)) {
1635+ experimentalFastCompileRequiresDefaultPath = true;
1636+ return;
1637+ }
1638+
1639+ if (const auto *cxxRecordDecl = dyn_cast<CXXRecordDecl>(recordDecl)) {
1640+ for (const auto &base : cxxRecordDecl->bases())
1641+ worklist.push_back(base.getType());
1642+ }
1643+
1644+ for (const FieldDecl *fieldDecl : recordDecl->fields()) {
1645+ if (hasRiskyDecorations(fieldDecl)) {
1646+ experimentalFastCompileRequiresDefaultPath = true;
1647+ return;
1648+ }
1649+ worklist.push_back(fieldDecl->getType());
1650+ }
1651+ }
1652+ }
1653+
15731654void SpirvEmitter::doFunctionDecl(const FunctionDecl *decl) {
15741655 // Forward declaration of a function inside another.
15751656 if (!decl->isThisDeclarationADefinition()) {
@@ -1578,6 +1659,8 @@ void SpirvEmitter::doFunctionDecl(const FunctionDecl *decl) {
15781659 return;
15791660 }
15801661
1662+ noteExperimentalFastCompileRisk(decl->getReturnType());
1663+
15811664 // A RAII class for maintaining the current function under traversal.
15821665 class FnEnvRAII {
15831666 public:
@@ -1682,6 +1765,7 @@ void SpirvEmitter::doFunctionDecl(const FunctionDecl *decl) {
16821765 // For non-static member function, the first parameter should be the
16831766 // object on which we are invoking this method.
16841767 QualType valueType = memberFn->getThisType(astContext)->getPointeeType();
1768+ noteExperimentalFastCompileRisk(valueType);
16851769
16861770 // Remember the parameter for the 'this' object so later we can handle
16871771 // CXXThisExpr correctly.
@@ -1716,6 +1800,8 @@ void SpirvEmitter::doFunctionDecl(const FunctionDecl *decl) {
17161800 for (uint32_t i = 0; i < decl->getNumParams(); ++i) {
17171801 const ParmVarDecl *paramDecl = decl->getParamDecl(i);
17181802 QualType paramType = paramDecl->getType();
1803+ noteExperimentalFastCompileRisk(paramType,
1804+ paramDecl->hasAttr<VKAliasedPointerAttr>());
17191805 auto *param =
17201806 declIdMapper.createFnParam(paramDecl, i + 1 + isNonStaticMemberFn);
17211807 if (isEntry) {
@@ -2038,6 +2124,8 @@ void SpirvEmitter::doVarDecl(const VarDecl *decl) {
20382124
20392125 const auto loc = decl->getLocation();
20402126 const auto range = decl->getSourceRange();
2127+ noteExperimentalFastCompileRisk(decl->getType(),
2128+ decl->hasAttr<VKAliasedPointerAttr>());
20412129
20422130 if (isExtResultIdType(decl->getType())) {
20432131 declIdMapper.createResultId(decl);
@@ -16670,7 +16758,9 @@ bool SpirvEmitter::spirvToolsOptimize(std::vector<uint32_t> *mod,
1667016758
1667116759bool SpirvEmitter::useSpirvFastCompileProfile() const {
1667216760 return spirvOptions.o1ExperimentalFastCompile &&
16673- spirvOptions.optConfig.empty();
16761+ spirvOptions.optConfig.empty() &&
16762+ !experimentalFastCompileRequiresDefaultPath &&
16763+ !declIdMapper.requiresFlatteningCompositeResources();
1667416764}
1667516765
1667616766bool SpirvEmitter::spirvToolsLegalize(std::vector<uint32_t> *mod,
0 commit comments