diff --git a/include/dxc/DXIL/DxilShaderModel.h b/include/dxc/DXIL/DxilShaderModel.h index 5efc60f57..293797ba1 100644 --- a/include/dxc/DXIL/DxilShaderModel.h +++ b/include/dxc/DXIL/DxilShaderModel.h @@ -90,6 +90,18 @@ public: static const char *GetNodeLaunchTypeName(DXIL::NodeLaunchType launchTy); static DXIL::NodeLaunchType NodeLaunchTypeFromName(llvm::StringRef name); + static bool HasVisibleGroup( + DXIL::ShaderKind SK, + DXIL::NodeLaunchType launchType = DXIL::NodeLaunchType::Invalid) { + // Note: Library case is permissive; enforced at entry point. + return SK == DXIL::ShaderKind::Compute || SK == DXIL::ShaderKind::Mesh || + SK == DXIL::ShaderKind::Amplification || + SK == DXIL::ShaderKind::Library || + (SK == DXIL::ShaderKind::Node && + (launchType == DXIL::NodeLaunchType::Broadcasting || + launchType == DXIL::NodeLaunchType::Coalescing)); + } + bool operator==(const ShaderModel &other) const; bool operator!=(const ShaderModel &other) const { return !(*this == other); } diff --git a/tools/clang/include/clang/Basic/DiagnosticGroups.td b/tools/clang/include/clang/Basic/DiagnosticGroups.td index f27dd7903..ccd7cf3b6 100644 --- a/tools/clang/include/clang/Basic/DiagnosticGroups.td +++ b/tools/clang/include/clang/Basic/DiagnosticGroups.td @@ -802,4 +802,5 @@ def HLSLSemanticIdentifierCollision : DiagGroup<"semantic-identifier-collision"> def HLSLStructurizeExitsLifetimeMarkersConflict: DiagGroup<"structurize-exits-lifetime-markers-conflict">; def HLSLParameterUsage : DiagGroup<"parameter-usage">; def HLSLAvailability: DiagGroup<"hlsl-availability">; +def HLSLBarrier : DiagGroup<"hlsl-barrier">; // HLSL Change Ends diff --git a/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td b/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td index fcd821baf..a12acc3bd 100644 --- a/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -20,6 +20,9 @@ def note_callee_decl : Note<"%0 declared here">; def note_defined_here : Note<"%0 defined here">; def note_field_declared_here : Note<"%0 field declared here">; +// HLSL Change: Note for HLSL entry function location +def note_hlsl_entry_defined_here : Note<"entry function defined here">; + // For loop analysis def warn_variables_not_in_loop_body : Warning< "variable%select{s| %1|s %1 and %2|s %1, %2, and %3|s %1, %2, %3, and %4}0 " @@ -7922,6 +7925,27 @@ def err_hlsl_outputpatch_size: Error< def note_hlsl_node_array : Note<"'%0' cannot be used as an array; did you mean '%0Array'?">; def err_hlsl_controlpoints_size: Error< "number of control points %0 is outside the valid range of [1..32]">; +def err_hlsl_barrier_invalid_memory_flags: Error< + "invalid MemoryTypeFlags for Barrier operation; expected 0, ALL_MEMORY, or some combination of " + "UAV_MEMORY, GROUP_SHARED_MEMORY, NODE_INPUT_MEMORY, NODE_OUTPUT_MEMORY flags">; +def err_hlsl_barrier_invalid_semantic_flags: Error< + "invalid SemanticFlags for Barrier operation; expected 0 or some combination of " + "GROUP_SYNC, GROUP_SCOPE, DEVICE_SCOPE flags">; +def warn_hlsl_barrier_group_memory_requires_group: Warning< + "GROUP_SHARED_MEMORY specified for Barrier operation when context has no visible group">, + InGroup, DefaultError; +def warn_hlsl_barrier_node_memory_requires_node: Warning< + "NODE_INPUT_MEMORY or NODE_OUTPUT_MEMORY may only be specified for Barrier operation in a node shader">, + InGroup, DefaultError; +def warn_hlsl_barrier_group_semantic_requires_group: Warning< + "GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group">, + InGroup, DefaultError; +def warn_hlsl_barrier_no_mem_with_required_group_scope: Warning< + "GROUP_SCOPE specified for Barrier operation without applicable memory">, + InGroup, DefaultError; +def warn_hlsl_barrier_no_mem_with_required_device_scope: Warning< + "DEVICE_SCOPE specified for Barrier operation without applicable memory">, + InGroup, DefaultError; // HLSL Change Ends // SPIRV Change Starts diff --git a/tools/clang/include/clang/Sema/Sema.h b/tools/clang/include/clang/Sema/Sema.h index 5c6db7f8d..b734e0bb2 100644 --- a/tools/clang/include/clang/Sema/Sema.h +++ b/tools/clang/include/clang/Sema/Sema.h @@ -3807,14 +3807,13 @@ public: void DiagnoseGloballyCoherentMismatch(const Expr *SrcExpr, QualType TargetType, SourceLocation Loc); - bool DiagnoseHLSLMethodCall(const CXXMethodDecl *MD, SourceLocation Loc); - void DiagnoseSVForLaunchType(const FunctionDecl *FD, - hlsl::DXIL::NodeLaunchType LaunchTy); - void DiagnoseReachableHLSLMethodCall(const CXXMethodDecl *MD, - SourceLocation Loc, - const hlsl::ShaderModel *SM, - hlsl::DXIL::ShaderKind EntrySK, - const FunctionDecl *EntryDecl); + void CheckHLSLFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, + const FunctionProtoType *Proto); + void DiagnoseReachableHLSLCall(CallExpr *CE, const hlsl::ShaderModel *SM, + hlsl::DXIL::ShaderKind EntrySK, + hlsl::DXIL::NodeLaunchType NodeLaunchTy, + const FunctionDecl *EntryDecl, + bool locallyVisited); // HLSL Change Ends bool CheckUnaryExprOrTypeTraitOperand(Expr *E, UnaryExprOrTypeTrait ExprKind); diff --git a/tools/clang/lib/Sema/SemaChecking.cpp b/tools/clang/lib/Sema/SemaChecking.cpp index bea8eb361..618073385 100644 --- a/tools/clang/lib/Sema/SemaChecking.cpp +++ b/tools/clang/lib/Sema/SemaChecking.cpp @@ -1426,6 +1426,8 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, CheckMemaccessArguments(TheCall, CMId, FnInfo); #endif // HLSL Change Ends + CheckHLSLFunctionCall(FDecl, TheCall, Proto); // HLSL Change + return false; } diff --git a/tools/clang/lib/Sema/SemaHLSL.cpp b/tools/clang/lib/Sema/SemaHLSL.cpp index bdb6cf645..7b30f28b9 100644 --- a/tools/clang/lib/Sema/SemaHLSL.cpp +++ b/tools/clang/lib/Sema/SemaHLSL.cpp @@ -1853,8 +1853,8 @@ static void InitParamMods(const HLSL_INTRINSIC *pIntrinsic, } } -static bool IsBuiltinTable(LPCSTR tableName) { - return tableName == kBuiltinIntrinsicTableName; +static bool IsBuiltinTable(StringRef tableName) { + return tableName.compare(kBuiltinIntrinsicTableName) == 0; } static bool HasUnsignedOpcode(LPCSTR tableName, IntrinsicOp opcode) { @@ -11117,37 +11117,18 @@ void hlsl::DiagnoseRegisterType(clang::Sema *self, clang::SourceLocation loc, } } -// Check HLSL member call constraints -bool Sema::DiagnoseHLSLMethodCall(const CXXMethodDecl *MD, SourceLocation Loc) { - if (MD->hasAttr()) { - hlsl::IntrinsicOp opCode = - (IntrinsicOp)MD->getAttr()->getOpcode(); - // If this is a call to FinishedCrossGroupSharing then the Input record - // must have the NodeTrackRWInputSharing attribute - if (opCode == hlsl::IntrinsicOp::MOP_FinishedCrossGroupSharing) { - const CXXRecordDecl *NodeRecDecl = MD->getParent(); - // Node I/O records are templateTypes - const ClassTemplateSpecializationDecl *templateDecl = - cast(NodeRecDecl); - auto &TemplateArgs = templateDecl->getTemplateArgs(); - DXASSERT(TemplateArgs.size() == 1, - "Input record types need to have one template argument"); - auto &Rec = TemplateArgs.get(0); - clang::QualType RecType = Rec.getAsType(); - RecordDecl *RD = RecType->getAs()->getDecl(); - if (!RD->hasAttr()) { - Diags.Report(Loc, diag::err_hlsl_wg_nodetrackrwinputsharing_missing); - return true; - } - } - } - return false; -} - +// FIXME: DiagnoseSVForLaunchType is wrong in multiple ways: +// - It doesn't handle system values inside structs +// - It doesn't account for the fact that semantics are case-insensitive +// - It doesn't account for optional index at the end of semantic name +// - It permits any `SV_*` for Broadcasting launch, not just the legal ones +// - It doesn't prevent multiple system values with the same semantic +// - It doesn't check that the type is valid for the system value // Produce diagnostics for any system values attached to `FD` function // that are invalid for the `LaunchTy` launch type -void Sema::DiagnoseSVForLaunchType(const FunctionDecl *FD, - DXIL::NodeLaunchType LaunchTy) { +static void DiagnoseSVForLaunchType(const FunctionDecl *FD, + DXIL::NodeLaunchType LaunchTy, + DiagnosticsEngine &Diags) { // Validate Compute Shader system value inputs per launch mode for (ParmVarDecl *param : FD->parameters()) { for (const hlsl::UnusualAnnotation *it : param->getUnusualAnnotations()) { @@ -11188,88 +11169,376 @@ void Sema::DiagnoseSVForLaunchType(const FunctionDecl *FD, } } -// Check HLSL member call constraints for used functions. -void Sema::DiagnoseReachableHLSLMethodCall(const CXXMethodDecl *MD, - SourceLocation Loc, - const hlsl::ShaderModel *SM, - DXIL::ShaderKind EntrySK, - const FunctionDecl *EntryDecl) { - if (MD->hasAttr()) { - hlsl::IntrinsicOp opCode = - (IntrinsicOp)MD->getAttr()->getOpcode(); - switch (opCode) { - case hlsl::IntrinsicOp::MOP_CalculateLevelOfDetail: - case hlsl::IntrinsicOp::MOP_CalculateLevelOfDetailUnclamped: { - QualType SamplerComparisonTy = - HLSLExternalSource::FromSema(this)->GetBasicKindType( - AR_OBJECT_SAMPLERCOMPARISON); - if (MD->getParamDecl(0)->getType() == SamplerComparisonTy) { +///////////////////////////////////////////////////////////////////////////// +// Check HLSL intrinsic calls without call-graph context. - if (!SM->IsSM68Plus()) { +static bool CheckFinishedCrossGroupSharingCall(Sema &S, CXXMethodDecl *MD, + SourceLocation Loc) { + const CXXRecordDecl *NodeRecDecl = MD->getParent(); + // Node I/O records are templateTypes + const ClassTemplateSpecializationDecl *templateDecl = + cast(NodeRecDecl); + auto &TemplateArgs = templateDecl->getTemplateArgs(); + DXASSERT(TemplateArgs.size() == 1, + "Input record types need to have one template argument"); + auto &Rec = TemplateArgs.get(0); + clang::QualType RecType = Rec.getAsType(); + RecordDecl *RD = RecType->getAs()->getDecl(); + if (!RD->hasAttr()) { + S.Diags.Report(Loc, diag::err_hlsl_wg_nodetrackrwinputsharing_missing); + return true; + } + return false; +} - Diags.Report(Loc, - diag::warn_hlsl_intrinsic_overload_in_wrong_shader_model) - << MD->getNameAsString() + " with SamplerComparisonState" - << "6.8"; - } else { +static bool CheckBarrierCall(Sema &S, FunctionDecl *FD, CallExpr *CE) { + DXASSERT(FD->getNumParams() == 2, "otherwise, unknown Barrier overload"); - switch (EntrySK) { - default: { - if (!SM->AllowDerivatives(EntrySK)) { - Diags.Report(Loc, - diag::warn_hlsl_derivatives_in_wrong_shader_kind) - << MD->getNameAsString() << EntryDecl->getNameAsString(); - Diags.Report(EntryDecl->getLocation(), diag::note_declared_at); - } - } break; - case DXIL::ShaderKind::Compute: - case DXIL::ShaderKind::Amplification: - case DXIL::ShaderKind::Mesh: { - if (!SM->IsSM66Plus()) { - Diags.Report(Loc, - diag::warn_hlsl_derivatives_in_wrong_shader_model) - << MD->getNameAsString() << EntryDecl->getNameAsString(); - Diags.Report(EntryDecl->getLocation(), diag::note_declared_at); - } - } break; - case DXIL::ShaderKind::Node: { - if (const auto *pAttr = EntryDecl->getAttr()) { - if (pAttr->getLaunchType() != "broadcasting") { - Diags.Report(Loc, - diag::warn_hlsl_derivatives_in_wrong_shader_kind) - << MD->getNameAsString() << EntryDecl->getNameAsString(); - Diags.Report(EntryDecl->getLocation(), diag::note_declared_at); - } - } - } break; - } - if (const HLSLNumThreadsAttr *Attr = - EntryDecl->getAttr()) { - bool invalidNumThreads = false; - if (Attr->getY() != 1) { - // 2D mode requires x and y to be multiple of 2. - invalidNumThreads = - !((Attr->getX() % 2) == 0 && (Attr->getY() % 2) == 0); - } else { - // 1D mode requires x to be multiple of 4 and y and z to be 1. - invalidNumThreads = - (Attr->getX() % 4) != 0 || (Attr->getZ() != 1); - } - if (invalidNumThreads) { - Diags.Report(Loc, diag::warn_hlsl_derivatives_wrong_numthreads) - << MD->getNameAsString() << EntryDecl->getNameAsString(); - Diags.Report(EntryDecl->getLocation(), diag::note_declared_at); - } - } - } + // Emit error when MemoryTypeFlags are known to be invalid. + QualType Param0Ty = FD->getParamDecl(0)->getType(); + if (Param0Ty == + HLSLExternalSource::FromSema(&S)->GetBasicKindType(AR_BASIC_UINT32)) { + uint32_t MemoryTypeFlags = 0; + Expr *MemoryTypeFlagsExpr = CE->getArg(0); + llvm::APSInt MemoryTypeFlagsVal; + if (MemoryTypeFlagsExpr->isIntegerConstantExpr(MemoryTypeFlagsVal, + S.Context)) { + MemoryTypeFlags = MemoryTypeFlagsVal.getLimitedValue(); + if ((uint32_t)MemoryTypeFlags & + ~(uint32_t)DXIL::MemoryTypeFlag::ValidMask) { + S.Diags.Report(MemoryTypeFlagsExpr->getExprLoc(), + diag::err_hlsl_barrier_invalid_memory_flags) + << (uint32_t)MemoryTypeFlags + << (uint32_t)DXIL::MemoryTypeFlag::ValidMask; + return true; } - } break; - default: - break; } } + + // Emit error when SemanticFlags are known to be invalid. + uint32_t SemanticFlags = 0; + Expr *SemanticFlagsExpr = CE->getArg(1); + llvm::APSInt SemanticFlagsVal; + if (SemanticFlagsExpr->isIntegerConstantExpr(SemanticFlagsVal, S.Context)) { + SemanticFlags = SemanticFlagsVal.getLimitedValue(); + if ((uint32_t)SemanticFlags & + ~(uint32_t)DXIL::BarrierSemanticFlag::ValidMask) { + S.Diags.Report(SemanticFlagsExpr->getExprLoc(), + diag::err_hlsl_barrier_invalid_semantic_flags) + << (uint32_t)SemanticFlags + << (uint32_t)DXIL::BarrierSemanticFlag::ValidMask; + return true; + } + } + + return false; } +// Check HLSL call constraints, not fatal to creating the AST. +void Sema::CheckHLSLFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, + const FunctionProtoType *Proto) { + HLSLIntrinsicAttr *IntrinsicAttr = FDecl->getAttr(); + if (!IntrinsicAttr) + return; + if (!IsBuiltinTable(IntrinsicAttr->getGroup())) + return; + + hlsl::IntrinsicOp opCode = (hlsl::IntrinsicOp)IntrinsicAttr->getOpcode(); + switch (opCode) { + case hlsl::IntrinsicOp::MOP_FinishedCrossGroupSharing: + CheckFinishedCrossGroupSharingCall(*this, cast(FDecl), + TheCall->getLocStart()); + break; + case hlsl::IntrinsicOp::IOP_Barrier: + CheckBarrierCall(*this, FDecl, TheCall); + break; + default: + break; + } +} + +///////////////////////////////////////////////////////////////////////////// +// Check HLSL intrinsic calls reachable from entry/export functions. + +static void DiagnoseNumThreadsForDerivativeOp(const HLSLNumThreadsAttr *Attr, + SourceLocation LocDeriv, + FunctionDecl *FD, + const FunctionDecl *EntryDecl, + DiagnosticsEngine &Diags) { + bool invalidNumThreads = false; + if (Attr->getY() != 1) { + // 2D mode requires x and y to be multiple of 2. + invalidNumThreads = !((Attr->getX() % 2) == 0 && (Attr->getY() % 2) == 0); + } else { + // 1D mode requires x to be multiple of 4 and y and z to be 1. + invalidNumThreads = (Attr->getX() % 4) != 0 || (Attr->getZ() != 1); + } + if (invalidNumThreads) { + Diags.Report(LocDeriv, diag::warn_hlsl_derivatives_wrong_numthreads) + << FD->getNameAsString() << EntryDecl->getNameAsString(); + Diags.Report(EntryDecl->getLocation(), diag::note_hlsl_entry_defined_here); + } +} + +static void DiagnoseDerivativeOp(Sema &S, FunctionDecl *FD, SourceLocation Loc, + const hlsl::ShaderModel *SM, + DXIL::ShaderKind EntrySK, + DXIL::NodeLaunchType NodeLaunchTy, + const FunctionDecl *EntryDecl, + DiagnosticsEngine &Diags) { + switch (EntrySK) { + default: { + if (!SM->AllowDerivatives(EntrySK)) { + Diags.Report(Loc, diag::warn_hlsl_derivatives_in_wrong_shader_kind) + << FD->getNameAsString() << EntryDecl->getNameAsString(); + Diags.Report(EntryDecl->getLocation(), + diag::note_hlsl_entry_defined_here); + } + } break; + case DXIL::ShaderKind::Compute: + case DXIL::ShaderKind::Amplification: + case DXIL::ShaderKind::Mesh: { + if (!SM->IsSM66Plus()) { + Diags.Report(Loc, diag::warn_hlsl_derivatives_in_wrong_shader_model) + << FD->getNameAsString() << EntryDecl->getNameAsString(); + Diags.Report(EntryDecl->getLocation(), + diag::note_hlsl_entry_defined_here); + } + } break; + case DXIL::ShaderKind::Node: { + if (NodeLaunchTy != DXIL::NodeLaunchType::Broadcasting) { + Diags.Report(Loc, diag::warn_hlsl_derivatives_in_wrong_shader_kind) + << FD->getNameAsString() << EntryDecl->getNameAsString(); + Diags.Report(EntryDecl->getLocation(), + diag::note_hlsl_entry_defined_here); + } + } break; + } + + if (const HLSLNumThreadsAttr *Attr = + EntryDecl->getAttr()) { + DiagnoseNumThreadsForDerivativeOp(Attr, Loc, FD, EntryDecl, Diags); + } +} + +static void DiagnoseCalculateLOD(Sema &S, FunctionDecl *FD, SourceLocation Loc, + const hlsl::ShaderModel *SM, + DXIL::ShaderKind EntrySK, + DXIL::NodeLaunchType NodeLaunchTy, + const FunctionDecl *EntryDecl, + DiagnosticsEngine &Diags, + bool locallyVisited) { + if (FD->getParamDecl(0)->getType() != + HLSLExternalSource::FromSema(&S)->GetBasicKindType( + AR_OBJECT_SAMPLERCOMPARISON)) + return; + + if (!locallyVisited && !SM->IsSM68Plus()) { + Diags.Report(Loc, diag::warn_hlsl_intrinsic_overload_in_wrong_shader_model) + << FD->getNameAsString() + " with SamplerComparisonState" + << "6.8"; + return; + } + + DiagnoseDerivativeOp(S, FD, Loc, SM, EntrySK, NodeLaunchTy, EntryDecl, Diags); +} + +static uint32_t +DiagnoseMemoryFlags(SourceLocation ArgLoc, uint32_t MemoryTypeFlags, + bool hasVisibleGroup, DXIL::ShaderKind EntrySK, + const FunctionDecl *EntryDecl, DiagnosticsEngine &Diags) { + // Check flags against context. + // If DXIL::MemoryTypeFlag::AllMemory, filter flags for context, otherwise, + // emit errors for invalid flags. + uint32_t MemoryTypeFiltered = MemoryTypeFlags; + + // If group memory specified, must have a visible group. + if (!hasVisibleGroup) { + if ((uint32_t)MemoryTypeFlags & + (uint32_t)DXIL::MemoryTypeFlag::GroupFlags) { + if (MemoryTypeFlags == (uint32_t)DXIL::MemoryTypeFlag::AllMemory) { + // If AllMemory, filter out group flags. + MemoryTypeFiltered &= ~(uint32_t)DXIL::MemoryTypeFlag::GroupFlags; + } else { + Diags.Report(ArgLoc, + diag::warn_hlsl_barrier_group_memory_requires_group); + Diags.Report(EntryDecl->getLocation(), + diag::note_hlsl_entry_defined_here); + } + } + } + + // If node memory specified, must be a node shader. + if (EntrySK != DXIL::ShaderKind::Node && + EntrySK != DXIL::ShaderKind::Library && + ((uint32_t)MemoryTypeFlags & (uint32_t)DXIL::MemoryTypeFlag::NodeFlags)) { + if (MemoryTypeFlags == (uint32_t)DXIL::MemoryTypeFlag::AllMemory) { + // If AllMemory, filter out node flags. + MemoryTypeFiltered &= ~(uint32_t)DXIL::MemoryTypeFlag::NodeFlags; + } else { + Diags.Report(ArgLoc, diag::warn_hlsl_barrier_node_memory_requires_node); + Diags.Report(EntryDecl->getLocation(), + diag::note_hlsl_entry_defined_here); + } + } + + // Return filtered flags. + return MemoryTypeFiltered; +} + +static void DiagnoseSemanticFlags(SourceLocation ArgLoc, uint32_t SemanticFlags, + bool hasVisibleGroup, + bool memAtLeastGroupScope, + bool memAtLeastDeviceScope, + const FunctionDecl *EntryDecl, + DiagnosticsEngine &Diags) { + // If hasVisibleGroup is false, emit error for group flags. + if (!hasVisibleGroup) { + if ((uint32_t)SemanticFlags & + (uint32_t)DXIL::BarrierSemanticFlag::GroupFlags) { + Diags.Report(ArgLoc, + diag::warn_hlsl_barrier_group_semantic_requires_group); + Diags.Report(EntryDecl->getLocation(), + diag::note_hlsl_entry_defined_here); + } + } + + // Error on DeviceScope or GroupScope when memory lacks this scope. + if (!memAtLeastDeviceScope && + ((uint32_t)SemanticFlags & + (uint32_t)DXIL::BarrierSemanticFlag::DeviceScope)) { + Diags.Report(ArgLoc, + diag::warn_hlsl_barrier_no_mem_with_required_device_scope); + Diags.Report(EntryDecl->getLocation(), diag::note_hlsl_entry_defined_here); + } + if (!memAtLeastGroupScope && + ((uint32_t)SemanticFlags & + (uint32_t)DXIL::BarrierSemanticFlag::GroupScope)) { + Diags.Report(ArgLoc, + diag::warn_hlsl_barrier_no_mem_with_required_group_scope); + Diags.Report(EntryDecl->getLocation(), diag::note_hlsl_entry_defined_here); + } +} + +static void DiagnoseReachableBarrier(Sema &S, CallExpr *CE, + const hlsl::ShaderModel *SM, + DXIL::ShaderKind EntrySK, + DXIL::NodeLaunchType NodeLaunchTy, + const FunctionDecl *EntryDecl, + DiagnosticsEngine &Diags) { + FunctionDecl *FD = CE->getDirectCallee(); + DXASSERT(FD->getNumParams() == 2, "otherwise, unknown Barrier overload"); + + // Does shader have visible group? + // Allow exported library functions as well. + bool hasVisibleGroup = ShaderModel::HasVisibleGroup(EntrySK, NodeLaunchTy); + QualType Param0Ty = FD->getParamDecl(0)->getType(); + + // Used when checking scope flags + // Default to true to avoid over-strict diagnostics + bool memAtLeastGroupScope = true; + bool memAtLeastDeviceScope = true; + + if (Param0Ty == + HLSLExternalSource::FromSema(&S)->GetBasicKindType(AR_BASIC_UINT32)) { + // overload: Barrier(uint MemoryTypeFlags, uint SemanticFlags) + uint32_t MemoryTypeFlags = 0; + Expr *MemoryTypeFlagsExpr = CE->getArg(0); + llvm::APSInt MemoryTypeFlagsVal; + if (MemoryTypeFlagsExpr->isIntegerConstantExpr(MemoryTypeFlagsVal, + S.Context)) { + MemoryTypeFlags = MemoryTypeFlagsVal.getLimitedValue(); + MemoryTypeFlags = DiagnoseMemoryFlags(MemoryTypeFlagsExpr->getExprLoc(), + MemoryTypeFlags, hasVisibleGroup, + EntrySK, EntryDecl, Diags); + // Consider group scope if any group flags remain. + memAtLeastGroupScope = 0 != MemoryTypeFlags; + // Consider it device scope if UavMemory or any NodeFlags remain. + memAtLeastDeviceScope = + 0 != (MemoryTypeFlags & ((uint32_t)DXIL::MemoryTypeFlag::UavMemory | + (uint32_t)DXIL::MemoryTypeFlag::NodeFlags)); + } + } else { + DXIL::NodeIOKind IOKind = GetNodeIOType(Param0Ty); + if (IOKind == DXIL::NodeIOKind::Invalid) { + // overload: Barrier(, uint SemanticFlags) + // UAV objects have at least device scope. + DXASSERT(IsHLSLResourceType(Param0Ty), + "otherwise, missed a case for Barrier"); + // mem scope flags already set to true. + } else { + // Must be a record object + // overload: Barrier(, uint SemanticFlags) + // Only record objects specify a record granularity + DXASSERT((uint32_t)IOKind & + (uint32_t)DXIL::NodeIOFlags::RecordGranularityMask, + "otherwise, missed a Node object case for Barrier"); + + DXIL::NodeIOFlags RecordGranularity = (DXIL::NodeIOFlags)( + (uint32_t)IOKind & + (uint32_t)DXIL::NodeIOFlags::RecordGranularityMask); + switch (RecordGranularity) { + case DXIL::NodeIOFlags::ThreadRecord: + memAtLeastGroupScope = false; + LLVM_FALLTHROUGH; + case DXIL::NodeIOFlags::GroupRecord: + memAtLeastDeviceScope = false; + break; + default: + break; + } + } + } + + // All barrier overloads have SemanticFlags as second paramter + uint32_t SemanticFlags = 0; + Expr *SemanticFlagsExpr = CE->getArg(1); + llvm::APSInt SemanticFlagsVal; + if (SemanticFlagsExpr->isIntegerConstantExpr(SemanticFlagsVal, S.Context)) { + SemanticFlags = SemanticFlagsVal.getLimitedValue(); + DiagnoseSemanticFlags(SemanticFlagsExpr->getExprLoc(), SemanticFlags, + hasVisibleGroup, memAtLeastGroupScope, + memAtLeastDeviceScope, EntryDecl, Diags); + } +} + +// Check HLSL member call constraints for used functions. +// locallyVisited is true if this call has been visited already from any other +// entry function. Used to avoid duplicate diagnostics when not dependent on +// entry function (or export function) properties. +void Sema::DiagnoseReachableHLSLCall(CallExpr *CE, const hlsl::ShaderModel *SM, + DXIL::ShaderKind EntrySK, + DXIL::NodeLaunchType NodeLaunchTy, + const FunctionDecl *EntryDecl, + bool locallyVisited) { + FunctionDecl *FD = CE->getDirectCallee(); + if (!FD) + return; + HLSLIntrinsicAttr *IntrinsicAttr = FD->getAttr(); + if (!IntrinsicAttr) + return; + if (!IsBuiltinTable(IntrinsicAttr->getGroup())) + return; + + SourceLocation Loc = CE->getExprLoc(); + hlsl::IntrinsicOp opCode = (IntrinsicOp)IntrinsicAttr->getOpcode(); + switch (opCode) { + case hlsl::IntrinsicOp::MOP_CalculateLevelOfDetail: + case hlsl::IntrinsicOp::MOP_CalculateLevelOfDetailUnclamped: + DiagnoseCalculateLOD(*this, FD, Loc, SM, EntrySK, NodeLaunchTy, EntryDecl, + Diags, locallyVisited); + break; + case hlsl::IntrinsicOp::IOP_Barrier: + DiagnoseReachableBarrier(*this, CE, SM, EntrySK, NodeLaunchTy, EntryDecl, + Diags); + break; + default: + break; + } +} + +///////////////////////////////////////////////////////////////////////////// + bool hlsl::DiagnoseNodeStructArgument(Sema *self, TemplateArgumentLoc ArgLoc, QualType ArgTy, bool &Empty, const FieldDecl *FD) { @@ -15770,9 +16039,11 @@ void DiagnoseNodeEntry(Sema &S, FunctionDecl *FD, llvm::StringRef StageName, } } } - S.DiagnoseSVForLaunchType(FD, NodeLaunchTy); } } + + DiagnoseSVForLaunchType(FD, NodeLaunchTy, S.Diags); + return; } diff --git a/tools/clang/lib/Sema/SemaHLSLDiagnoseTU.cpp b/tools/clang/lib/Sema/SemaHLSLDiagnoseTU.cpp index 149c6b32e..1eb3df93b 100644 --- a/tools/clang/lib/Sema/SemaHLSLDiagnoseTU.cpp +++ b/tools/clang/lib/Sema/SemaHLSLDiagnoseTU.cpp @@ -302,24 +302,26 @@ clang::FunctionDecl *ValidateNoRecursion(CallGraphWithRecurseGuard &callGraph, return nullptr; } -class HLSLMethodCallDiagnoseVisitor - : public RecursiveASTVisitor { +class HLSLCallDiagnoseVisitor + : public RecursiveASTVisitor { public: - explicit HLSLMethodCallDiagnoseVisitor( + explicit HLSLCallDiagnoseVisitor( Sema *S, const hlsl::ShaderModel *SM, DXIL::ShaderKind EntrySK, - const FunctionDecl *EntryDecl, - std::set &DiagnosedCalls) - : sema(S), SM(SM), EntrySK(EntrySK), EntryDecl(EntryDecl), - DiagnosedCalls(DiagnosedCalls) {} + DXIL::NodeLaunchType NodeLaunchTy, const FunctionDecl *EntryDecl, + llvm::SmallPtrSetImpl &DiagnosedCalls) + : sema(S), SM(SM), EntrySK(EntrySK), NodeLaunchTy(NodeLaunchTy), + EntryDecl(EntryDecl), DiagnosedCalls(DiagnosedCalls) {} - bool VisitCXXMemberCallExpr(CXXMemberCallExpr *CE) { - // Skip if already diagnosed. - if (DiagnosedCalls.count(CE)) - return true; - DiagnosedCalls.insert(CE); + bool VisitCallExpr(CallExpr *CE) { + // Set flag if already diagnosed from another entry, allowing some + // diagnostics to be skipped when they are not dependent on entry + // properties. + bool locallyVisited = DiagnosedCalls.count(CE) != 0; + if (!locallyVisited) + DiagnosedCalls.insert(CE); - sema->DiagnoseReachableHLSLMethodCall(CE->getMethodDecl(), CE->getExprLoc(), - SM, EntrySK, EntryDecl); + sema->DiagnoseReachableHLSLCall(CE, SM, EntrySK, NodeLaunchTy, EntryDecl, + locallyVisited); return true; } @@ -329,8 +331,9 @@ private: clang::Sema *sema; const hlsl::ShaderModel *SM; DXIL::ShaderKind EntrySK; + DXIL::NodeLaunchType NodeLaunchTy; const FunctionDecl *EntryDecl; - std::set &DiagnosedCalls; + llvm::SmallPtrSetImpl &DiagnosedCalls; }; std::optional @@ -426,7 +429,7 @@ void hlsl::DiagnoseTranslationUnit(clang::Sema *self) { hlsl::ShaderModel::GetByName(self->getLangOpts().HLSLProfile.c_str()); std::set DiagnosedDecls; - std::set DiagnosedCalls; + llvm::SmallPtrSet DiagnosedCalls; // for each FDecl, check for recursion for (FunctionDecl *FDecl : FDeclsToCheck) { CallGraphWithRecurseGuard callGraph; @@ -520,30 +523,23 @@ void hlsl::DiagnoseTranslationUnit(clang::Sema *self) { } DXIL::ShaderKind EntrySK = shaderModel->GetKind(); + DXIL::NodeLaunchType NodeLaunchTy = DXIL::NodeLaunchType::Invalid; if (EntrySK == DXIL::ShaderKind::Library) { // For library, check if the exported function is entry with shader // attribute. if (const auto *Attr = FDecl->getAttr()) EntrySK = ShaderModel::KindFromFullName(Attr->getStage()); + if (EntrySK == DXIL::ShaderKind::Node) + if (const auto *pAttr = FDecl->getAttr()) + NodeLaunchTy = + ShaderModel::NodeLaunchTypeFromName(pAttr->getLaunchType()); } // Visit all visited functions in call graph to collect illegal intrinsic // calls. for (FunctionDecl *FD : callGraph.GetVisitedFunctions()) { - HLSLMethodCallDiagnoseVisitor Visitor(self, shaderModel, EntrySK, FDecl, - DiagnosedCalls); + HLSLCallDiagnoseVisitor Visitor(self, shaderModel, EntrySK, NodeLaunchTy, + FDecl, DiagnosedCalls); Visitor.TraverseDecl(FD); - - // diagnose any node functions that have incompatible launch types with - // the present SV semantics on each parameter. - if (EntrySK == DXIL::ShaderKind::Node) { - if (const auto *NodeLaunchAttr = - FDecl->getAttr()) { - llvm::StringRef NodeLaunchTyStr = NodeLaunchAttr->getLaunchType(); - hlsl::DXIL::NodeLaunchType NodeLaunchTy = - ShaderModel::NodeLaunchTypeFromName(NodeLaunchTyStr); - Visitor.getSema()->DiagnoseSVForLaunchType(FD, NodeLaunchTy); - } - } } } } diff --git a/tools/clang/lib/Sema/SemaOverload.cpp b/tools/clang/lib/Sema/SemaOverload.cpp index 9b110b747..650fe38ad 100644 --- a/tools/clang/lib/Sema/SemaOverload.cpp +++ b/tools/clang/lib/Sema/SemaOverload.cpp @@ -11922,10 +11922,6 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, if (Method != FoundDecl.getDecl() && DiagnoseUseOfDecl(Method, UnresExpr->getNameLoc())) return ExprError(); - // HLSL Change Start - Check method constraints - if (DiagnoseHLSLMethodCall(Method, MemExprE->getLocStart())) - return ExprError(); - // HLSL Change End break; case OR_No_Viable_Function: diff --git a/tools/clang/test/HLSLFileCheck/hlsl/workgraph/case118_barrier_objectarg.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/workgraph/case118_barrier_objectarg.hlsl index 94bd967bc..cc388daa2 100644 --- a/tools/clang/test/HLSLFileCheck/hlsl/workgraph/case118_barrier_objectarg.hlsl +++ b/tools/clang/test/HLSLFileCheck/hlsl/workgraph/case118_barrier_objectarg.hlsl @@ -63,14 +63,14 @@ void node04([MaxRecords(6)] RWGroupNodeInputRecords input) void node05([MaxRecords(5)] NodeOutput outputs) { ThreadNodeOutputRecords outrec = outputs.GetThreadNodeOutputRecords(1); - Barrier(outrec, 3); + Barrier(outrec, 0); } // CHECK: define void @node05() { // CHECK: [[NODE05_A:%[0-9]+]] = call %dx.types.NodeHandle @dx.op.createNodeOutputHandle(i32 {{[0-9]+}}, i32 0) ; CreateNodeOutputHandle(MetadataIdx) // CHECK: [[ANN_NODE05_A:%[0-9]+]] = call %dx.types.NodeHandle @dx.op.annotateNodeHandle(i32 {{[0-9]+}}, %dx.types.NodeHandle [[NODE05_A]], %dx.types.NodeInfo { i32 6, i32 4 }) // CHECK: [[NODE05_B:%[0-9]+]] = call %dx.types.NodeRecordHandle @dx.op.allocateNodeOutputRecords(i32 {{[0-9]+}}, %dx.types.NodeHandle [[ANN_NODE05_A]], i32 1, i1 true) ; AllocateNodeOutputRecords(output,numRecords,perThread) // CHECK: [[ANN_NODE05_B:%[0-9]+]] = call %dx.types.NodeRecordHandle @dx.op.annotateNodeRecordHandle(i32 {{[0-9]+}}, %dx.types.NodeRecordHandle [[NODE05_B]], %dx.types.NodeRecordInfo { i32 38, i32 4 }) -// CHECK: call void @dx.op.barrierByNodeRecordHandle(i32 {{[0-9]+}}, %dx.types.NodeRecordHandle [[ANN_NODE05_B]], i32 3) ; BarrierByNodeRecordHandle(object,SemanticFlags) +// CHECK: call void @dx.op.barrierByNodeRecordHandle(i32 {{[0-9]+}}, %dx.types.NodeRecordHandle [[ANN_NODE05_B]], i32 0) ; BarrierByNodeRecordHandle(object,SemanticFlags) [Shader("node")] [NodeLaunch("thread")] diff --git a/tools/clang/test/HLSLFileCheck/validation/callgraph/barrier-group-in-nested-fn-vs-lib68.hlsl b/tools/clang/test/HLSLFileCheck/validation/callgraph/barrier-group-in-nested-fn-vs-lib68.hlsl index 4d2ee75ac..5305df7de 100644 --- a/tools/clang/test/HLSLFileCheck/validation/callgraph/barrier-group-in-nested-fn-vs-lib68.hlsl +++ b/tools/clang/test/HLSLFileCheck/validation/callgraph/barrier-group-in-nested-fn-vs-lib68.hlsl @@ -1,4 +1,5 @@ -// RUN: %dxilver 1.8 | %dxc -T lib_6_8 -Vd %s | %D3DReflect %s | %FileCheck %s -check-prefixes=RDAT +// RUN: %dxilver 1.8 | %dxc -T lib_6_8 -Wno-hlsl-barrier -Vd %s | %D3DReflect %s | %FileCheck %s -check-prefixes=RDAT +// RUN: %dxilver 1.8 | %dxc -T lib_6_8 -verify %s // Verifies that a Barrier requiring a visible group in a noinline function // called by a vertex shader is correctly marked as requiring a group in RDAT. @@ -29,6 +30,8 @@ void write_value(uint value) { [noinline] export void barrier_group() { write_value(1); + // expected-error@+2{{GROUP_SHARED_MEMORY specified for Barrier operation when context has no visible group}} + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} Barrier(GROUP_SHARED_MEMORY, GROUP_SCOPE); write_value(2); } @@ -54,6 +57,8 @@ void intermediate() { // MinShaderTarget still indicates vertex shader. // RDAT: MinShaderTarget: 0x10060 +// expected-note@+3{{entry function defined here}} +// expected-note@+2{{entry function defined here}} [shader("vertex")] void main() { intermediate(); diff --git a/tools/clang/test/SemaHLSL/hlsl/intrinsics/barrier/barrier-cs-errors.hlsl b/tools/clang/test/SemaHLSL/hlsl/intrinsics/barrier/barrier-cs-errors.hlsl new file mode 100644 index 000000000..6289794ce --- /dev/null +++ b/tools/clang/test/SemaHLSL/hlsl/intrinsics/barrier/barrier-cs-errors.hlsl @@ -0,0 +1,33 @@ +// RUN: %dxc -Tlib_6_8 -verify %s +// RUN: %dxc -Tcs_6_8 -verify %s +// REQUIRES: dxil-1-8 + +// Test the ordinary compute shader model case with node memory flags. + +struct RECORD { uint a; }; +RWBuffer buf0; +static uint i = 7; + +// Node barriers not supported in non-node shaders. +[noinline] export +void NodeBarriers() { + // expected-error@+1{{NODE_INPUT_MEMORY or NODE_OUTPUT_MEMORY may only be specified for Barrier operation in a node shader}} + Barrier(NODE_INPUT_MEMORY, 0); + // expected-error@+1{{NODE_INPUT_MEMORY or NODE_OUTPUT_MEMORY may only be specified for Barrier operation in a node shader}} + Barrier(NODE_INPUT_MEMORY, DEVICE_SCOPE); + + // expected-error@+1{{NODE_INPUT_MEMORY or NODE_OUTPUT_MEMORY may only be specified for Barrier operation in a node shader}} + Barrier(NODE_OUTPUT_MEMORY, 0); + // expected-error@+1{{NODE_INPUT_MEMORY or NODE_OUTPUT_MEMORY may only be specified for Barrier operation in a node shader}} + Barrier(NODE_OUTPUT_MEMORY, DEVICE_SCOPE); +} + +// expected-note@+6{{entry function defined here}} +// expected-note@+5{{entry function defined here}} +// expected-note@+4{{entry function defined here}} +// expected-note@+3{{entry function defined here}} +[Shader("compute")] +[numthreads(1, 1, 1)] +void main() { + NodeBarriers(); +} diff --git a/tools/clang/test/SemaHLSL/hlsl/intrinsics/barrier/barrier-cs-local-errors.hlsl b/tools/clang/test/SemaHLSL/hlsl/intrinsics/barrier/barrier-cs-local-errors.hlsl new file mode 100644 index 000000000..cb9563379 --- /dev/null +++ b/tools/clang/test/SemaHLSL/hlsl/intrinsics/barrier/barrier-cs-local-errors.hlsl @@ -0,0 +1,21 @@ +// RUN: %dxc -Tlib_6_8 -verify %s +// RUN: %dxc -Tcs_6_8 -verify %s +// REQUIRES: dxil-1-8 + +// Test the ordinary compute shader model case with local call-site errors. +// Since these errors are emitted before we do diagnostics for reachable calls, +// and because those diagnostics are skipped if an error is already produced, +// we must do these tests separately from the ones based on reachability. + +[Shader("compute")] +[numthreads(1, 1, 1)] +void main() { + // expected-error@+1{{invalid MemoryTypeFlags for Barrier operation; expected 0, ALL_MEMORY, or some combination of UAV_MEMORY, GROUP_SHARED_MEMORY, NODE_INPUT_MEMORY, NODE_OUTPUT_MEMORY flags}} + Barrier(16, 0); + // expected-error@+1{{invalid MemoryTypeFlags for Barrier operation; expected 0, ALL_MEMORY, or some combination of UAV_MEMORY, GROUP_SHARED_MEMORY, NODE_INPUT_MEMORY, NODE_OUTPUT_MEMORY flags}} + Barrier(-1, 0); + // expected-error@+1{{invalid SemanticFlags for Barrier operation; expected 0 or some combination of GROUP_SYNC, GROUP_SCOPE, DEVICE_SCOPE flags}} + Barrier(0, 8); + // expected-error@+1{{invalid SemanticFlags for Barrier operation; expected 0 or some combination of GROUP_SYNC, GROUP_SCOPE, DEVICE_SCOPE flags}} + Barrier(0, -1); +} diff --git a/tools/clang/test/SemaHLSL/hlsl/intrinsics/barrier/barrier-cs.hlsl b/tools/clang/test/SemaHLSL/hlsl/intrinsics/barrier/barrier-cs.hlsl new file mode 100644 index 000000000..f18e8261a --- /dev/null +++ b/tools/clang/test/SemaHLSL/hlsl/intrinsics/barrier/barrier-cs.hlsl @@ -0,0 +1,62 @@ +// RUN: %dxc -Tlib_6_8 -verify %s +// RUN: %dxc -Tcs_6_8 -verify %s +// REQUIRES: dxil-1-8 + +// Test the compute shader model case with visible group. +// expected-no-diagnostics + +struct RECORD { uint a; }; +RWBuffer buf0; +static uint i = 7; + +// Barriers not requiring visible group, compatible with any shader stage. +[noinline] export +void DeviceBarriers() { + Barrier(0, 0); + + Barrier(ALL_MEMORY, 0); + Barrier(ALL_MEMORY, DEVICE_SCOPE); + Barrier(ALL_MEMORY, 2 + 2); + + Barrier(UAV_MEMORY, 0); + Barrier(UAV_MEMORY, DEVICE_SCOPE); + + // No diagnostic for non-constant expressions. + Barrier(ALL_MEMORY, i + i); + Barrier(i + i, 0); +} + +// Barriers requiring visible group. +[noinline] export +void GroupBarriers() { + Barrier(0, GROUP_SYNC); + + Barrier(ALL_MEMORY, GROUP_SYNC); + Barrier(ALL_MEMORY, GROUP_SCOPE); + Barrier(ALL_MEMORY, GROUP_SCOPE | GROUP_SYNC); + Barrier(ALL_MEMORY, DEVICE_SCOPE | GROUP_SCOPE | GROUP_SYNC); + Barrier(ALL_MEMORY, 1 + 2 + 4); + + Barrier(UAV_MEMORY, GROUP_SYNC); + Barrier(UAV_MEMORY, GROUP_SCOPE); + Barrier(UAV_MEMORY, GROUP_SCOPE | GROUP_SYNC); + Barrier(UAV_MEMORY, DEVICE_SCOPE | GROUP_SCOPE | GROUP_SYNC); + + Barrier(GROUP_SHARED_MEMORY, 0); + Barrier(GROUP_SHARED_MEMORY, GROUP_SYNC); + Barrier(GROUP_SHARED_MEMORY, GROUP_SCOPE); + Barrier(GROUP_SHARED_MEMORY, GROUP_SCOPE | GROUP_SYNC); +} + +[Shader("compute")] +[numthreads(1, 1, 1)] +void main() { + DeviceBarriers(); + GroupBarriers(); + + Barrier(buf0, 0); + Barrier(buf0, GROUP_SYNC); + Barrier(buf0, GROUP_SCOPE); + Barrier(buf0, DEVICE_SCOPE); + Barrier(buf0, DEVICE_SCOPE | GROUP_SCOPE | GROUP_SYNC); +} diff --git a/tools/clang/test/SemaHLSL/hlsl/intrinsics/barrier/barrier-node-errors.hlsl b/tools/clang/test/SemaHLSL/hlsl/intrinsics/barrier/barrier-node-errors.hlsl new file mode 100644 index 000000000..b2a8fc7c7 --- /dev/null +++ b/tools/clang/test/SemaHLSL/hlsl/intrinsics/barrier/barrier-node-errors.hlsl @@ -0,0 +1,195 @@ +// RUN: %dxc -Tlib_6_8 -verify %s +// REQUIRES: dxil-1-8 + +struct RECORD { uint a; }; +RWBuffer buf0; +static uint i = 7; + +// Errors expected when called without visible group. +[noinline] export +void GroupBarriers() { + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(0, GROUP_SYNC); + + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(ALL_MEMORY, GROUP_SYNC); + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(ALL_MEMORY, GROUP_SCOPE); + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(ALL_MEMORY, GROUP_SCOPE | GROUP_SYNC); + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(ALL_MEMORY, DEVICE_SCOPE | GROUP_SCOPE); + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(ALL_MEMORY, 1 + 2 + 4); + + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(UAV_MEMORY, GROUP_SYNC); + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(UAV_MEMORY, GROUP_SCOPE); + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(UAV_MEMORY, GROUP_SCOPE | GROUP_SYNC); + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(UAV_MEMORY, DEVICE_SCOPE | GROUP_SCOPE); + + // expected-error@+1{{GROUP_SHARED_MEMORY specified for Barrier operation when context has no visible group}} + Barrier(GROUP_SHARED_MEMORY, 0); + // expected-error@+2{{GROUP_SHARED_MEMORY specified for Barrier operation when context has no visible group}} + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(GROUP_SHARED_MEMORY, GROUP_SYNC); + // expected-error@+2{{GROUP_SHARED_MEMORY specified for Barrier operation when context has no visible group}} + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(GROUP_SHARED_MEMORY, GROUP_SCOPE); + // expected-error@+2{{GROUP_SHARED_MEMORY specified for Barrier operation when context has no visible group}} + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(GROUP_SHARED_MEMORY, GROUP_SCOPE); +} + +// Errors expected when called without visible group. +[noinline] export +void GroupNodeBarriers() { + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(NODE_INPUT_MEMORY, GROUP_SYNC); + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(NODE_INPUT_MEMORY, GROUP_SCOPE); + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(NODE_INPUT_MEMORY, GROUP_SCOPE | GROUP_SYNC); + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(NODE_INPUT_MEMORY, DEVICE_SCOPE | GROUP_SCOPE); + + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(NODE_OUTPUT_MEMORY, GROUP_SYNC); + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(NODE_OUTPUT_MEMORY, GROUP_SCOPE); + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(NODE_OUTPUT_MEMORY, GROUP_SCOPE | GROUP_SYNC); + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(NODE_OUTPUT_MEMORY, DEVICE_SCOPE | GROUP_SCOPE); +} + +// expected-note@+7{{entry function defined here}} +// expected-note@+6{{entry function defined here}} +// expected-note@+5{{entry function defined here}} +[Shader("node")] +[NodeLaunch("broadcasting")] +[NumThreads(64,1,1)] +[NodeDispatchGrid(1, 1, 1)] +void node01(RWDispatchNodeInputRecord input, + [MaxRecords(11)] NodeOutput output) { + + GroupNodeOutputRecords groupRec = output.GetGroupNodeOutputRecords(1); + // expected-error@+1{{DEVICE_SCOPE specified for Barrier operation without applicable memory}} + Barrier(groupRec, DEVICE_SCOPE); + groupRec.OutputComplete(); + + ThreadNodeOutputRecords threadRec = output.GetThreadNodeOutputRecords(1); + // expected-error@+1{{GROUP_SCOPE specified for Barrier operation without applicable memory}} + Barrier(threadRec, GROUP_SCOPE); + // expected-error@+1{{DEVICE_SCOPE specified for Barrier operation without applicable memory}} + Barrier(threadRec, DEVICE_SCOPE); + threadRec.OutputComplete(); +} + +// expected-note@+7{{entry function defined here}} +// expected-note@+6{{entry function defined here}} +// expected-note@+5{{entry function defined here}} +// expected-note@+4{{entry function defined here}} +[Shader("node")] +[NodeLaunch("coalescing")] +[NumThreads(64,1,1)] +void node01([MaxRecords(64)] RWGroupNodeInputRecords input, + [MaxRecords(11)] NodeOutput output) { + + // expected-error@+1{{DEVICE_SCOPE specified for Barrier operation without applicable memory}} + Barrier(input, DEVICE_SCOPE); + + GroupNodeOutputRecords groupRec = output.GetGroupNodeOutputRecords(1); + // expected-error@+1{{DEVICE_SCOPE specified for Barrier operation without applicable memory}} + Barrier(groupRec, DEVICE_SCOPE); + groupRec.OutputComplete(); + + ThreadNodeOutputRecords threadRec = output.GetThreadNodeOutputRecords(1); + // expected-error@+1{{GROUP_SCOPE specified for Barrier operation without applicable memory}} + Barrier(threadRec, GROUP_SCOPE); + // expected-error@+1{{DEVICE_SCOPE specified for Barrier operation without applicable memory}} + Barrier(threadRec, DEVICE_SCOPE); + threadRec.OutputComplete(); +} + +// expected-note@+40{{entry function defined here}} +// expected-note@+39{{entry function defined here}} +// expected-note@+38{{entry function defined here}} +// expected-note@+37{{entry function defined here}} +// expected-note@+36{{entry function defined here}} +// expected-note@+35{{entry function defined here}} +// expected-note@+34{{entry function defined here}} +// expected-note@+33{{entry function defined here}} +// expected-note@+32{{entry function defined here}} +// expected-note@+31{{entry function defined here}} +// expected-note@+30{{entry function defined here}} +// expected-note@+29{{entry function defined here}} +// expected-note@+28{{entry function defined here}} +// expected-note@+27{{entry function defined here}} +// expected-note@+26{{entry function defined here}} +// expected-note@+25{{entry function defined here}} +// expected-note@+24{{entry function defined here}} +// expected-note@+23{{entry function defined here}} +// expected-note@+22{{entry function defined here}} +// expected-note@+21{{entry function defined here}} +// expected-note@+20{{entry function defined here}} +// expected-note@+19{{entry function defined here}} +// expected-note@+18{{entry function defined here}} +// expected-note@+17{{entry function defined here}} +// expected-note@+16{{entry function defined here}} +// expected-note@+15{{entry function defined here}} +// expected-note@+14{{entry function defined here}} +// expected-note@+13{{entry function defined here}} +// expected-note@+12{{entry function defined here}} +// expected-note@+11{{entry function defined here}} +// expected-note@+10{{entry function defined here}} +// expected-note@+9{{entry function defined here}} +// expected-note@+8{{entry function defined here}} +// expected-note@+7{{entry function defined here}} +// expected-note@+6{{entry function defined here}} +// expected-note@+5{{entry function defined here}} +// expected-note@+4{{entry function defined here}} +// expected-note@+3{{entry function defined here}} +[Shader("node")] +[NodeLaunch("thread")] +void node02(RWThreadNodeInputRecord input, + [MaxRecords(11)] NodeOutput output) { + + GroupBarriers(); + GroupNodeBarriers(); + + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(buf0, GROUP_SYNC); + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(buf0, GROUP_SCOPE); + + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(input, GROUP_SYNC); + // expected-error@+2{{GROUP_SCOPE specified for Barrier operation without applicable memory}} + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(input, GROUP_SCOPE); + // expected-error@+1{{DEVICE_SCOPE specified for Barrier operation without applicable memory}} + Barrier(input, DEVICE_SCOPE); + + GroupNodeOutputRecords groupRec = output.GetGroupNodeOutputRecords(1); + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(groupRec, GROUP_SCOPE); + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(groupRec, GROUP_SYNC); + // expected-error@+1{{DEVICE_SCOPE specified for Barrier operation without applicable memory}} + Barrier(groupRec, DEVICE_SCOPE); + groupRec.OutputComplete(); + + ThreadNodeOutputRecords threadRec = output.GetThreadNodeOutputRecords(1); + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(threadRec, GROUP_SYNC); + // expected-error@+2{{GROUP_SCOPE specified for Barrier operation without applicable memory}} + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(threadRec, GROUP_SCOPE); + // expected-error@+1{{DEVICE_SCOPE specified for Barrier operation without applicable memory}} + Barrier(threadRec, DEVICE_SCOPE); + threadRec.OutputComplete(); +} diff --git a/tools/clang/test/SemaHLSL/hlsl/intrinsics/barrier/barrier-node.hlsl b/tools/clang/test/SemaHLSL/hlsl/intrinsics/barrier/barrier-node.hlsl new file mode 100644 index 000000000..08ce24ecc --- /dev/null +++ b/tools/clang/test/SemaHLSL/hlsl/intrinsics/barrier/barrier-node.hlsl @@ -0,0 +1,196 @@ +// RUN: %dxc -Tlib_6_8 -Wno-unused-value -verify %s +// REQUIRES: dxil-1-8 + +// Legal cases, no diagnostics expected for this file. +// expected-no-diagnostics + +struct RECORD { uint a; }; +RWBuffer buf0; +static uint i = 7; + +// Barriers not requiring visible group, compatible with any shader stage. +[noinline] export +void DeviceBarriers() { + Barrier(0, 0); + + Barrier(ALL_MEMORY, 0); + Barrier(ALL_MEMORY, DEVICE_SCOPE); + Barrier(ALL_MEMORY, 2 + 2); + + Barrier(UAV_MEMORY, 0); + Barrier(UAV_MEMORY, DEVICE_SCOPE); + + // No diagnostic for non-constant expressions. + Barrier(ALL_MEMORY, i + i); + Barrier(i + i, 0); +} + +// Barriers requiring visible group. +[noinline] export +void GroupBarriers() { + Barrier(0, GROUP_SYNC); + + Barrier(ALL_MEMORY, GROUP_SYNC); + Barrier(ALL_MEMORY, GROUP_SCOPE); + Barrier(ALL_MEMORY, GROUP_SCOPE | GROUP_SYNC); + Barrier(ALL_MEMORY, DEVICE_SCOPE | GROUP_SCOPE | GROUP_SYNC); + Barrier(ALL_MEMORY, 1 + 2 + 4); + + Barrier(UAV_MEMORY, GROUP_SYNC); + Barrier(UAV_MEMORY, GROUP_SCOPE); + Barrier(UAV_MEMORY, GROUP_SCOPE | GROUP_SYNC); + Barrier(UAV_MEMORY, DEVICE_SCOPE | GROUP_SCOPE | GROUP_SYNC); + + Barrier(GROUP_SHARED_MEMORY, 0); + Barrier(GROUP_SHARED_MEMORY, GROUP_SYNC); + Barrier(GROUP_SHARED_MEMORY, GROUP_SCOPE); + Barrier(GROUP_SHARED_MEMORY, GROUP_SCOPE | GROUP_SYNC); +} + +// Node barriers not requiring visible group, compatible with all launch modes. +[noinline] export +void NodeBarriers() { + Barrier(NODE_INPUT_MEMORY, 0); + Barrier(NODE_INPUT_MEMORY, DEVICE_SCOPE); + + Barrier(NODE_OUTPUT_MEMORY, 0); + Barrier(NODE_OUTPUT_MEMORY, DEVICE_SCOPE); +} + +// Node barriers requiring visible group. +[noinline] export +void GroupNodeBarriers() { + Barrier(NODE_INPUT_MEMORY, GROUP_SYNC); + Barrier(NODE_INPUT_MEMORY, GROUP_SCOPE); + Barrier(NODE_INPUT_MEMORY, GROUP_SCOPE | GROUP_SYNC); + Barrier(NODE_INPUT_MEMORY, DEVICE_SCOPE | GROUP_SCOPE | GROUP_SYNC); + + Barrier(NODE_OUTPUT_MEMORY, GROUP_SYNC); + Barrier(NODE_OUTPUT_MEMORY, GROUP_SCOPE); + Barrier(NODE_OUTPUT_MEMORY, GROUP_SCOPE | GROUP_SYNC); + Barrier(NODE_OUTPUT_MEMORY, DEVICE_SCOPE | GROUP_SCOPE | GROUP_SYNC); +} + +////////////////////////////////////////////////////////////////////////////// +// Entry Points + +[Shader("node")] +[NodeLaunch("broadcasting")] +[NumThreads(64,1,1)] +[NodeDispatchGrid(1, 1, 1)] +void node01(RWDispatchNodeInputRecord input, + [MaxRecords(11)] NodeOutput output) { + DeviceBarriers(); + GroupBarriers(); + NodeBarriers(); + GroupNodeBarriers(); + + Barrier(buf0, 0); + Barrier(buf0, GROUP_SYNC); + Barrier(buf0, GROUP_SCOPE); + Barrier(buf0, DEVICE_SCOPE); + Barrier(buf0, DEVICE_SCOPE | GROUP_SCOPE | GROUP_SYNC); + + Barrier(input, 0); + Barrier(input, GROUP_SYNC); + Barrier(input, GROUP_SCOPE); + Barrier(input, DEVICE_SCOPE); + Barrier(input, DEVICE_SCOPE | GROUP_SCOPE | GROUP_SYNC); + + GroupNodeOutputRecords groupRec = output.GetGroupNodeOutputRecords(1); + Barrier(groupRec, 0); + Barrier(groupRec, GROUP_SYNC); + Barrier(groupRec, GROUP_SCOPE); + Barrier(groupRec, GROUP_SCOPE | GROUP_SYNC); + // Not allowed: + // Barrier(groupRec, DEVICE_SCOPE); + groupRec.OutputComplete(); + + ThreadNodeOutputRecords threadRec = output.GetThreadNodeOutputRecords(1); + Barrier(threadRec, 0); + Barrier(threadRec, GROUP_SYNC); + // Not allowed: + // Barrier(threadRec, GROUP_SCOPE); + // Barrier(threadRec, DEVICE_SCOPE); + threadRec.OutputComplete(); +} + +[Shader("node")] +[NodeLaunch("coalescing")] +[NumThreads(64,1,1)] +void node01([MaxRecords(64)] RWGroupNodeInputRecords input, + [MaxRecords(11)] NodeOutput output) { + DeviceBarriers(); + GroupBarriers(); + NodeBarriers(); + GroupNodeBarriers(); + + Barrier(buf0, 0); + Barrier(buf0, GROUP_SYNC); + Barrier(buf0, GROUP_SCOPE); + Barrier(buf0, DEVICE_SCOPE); + Barrier(buf0, DEVICE_SCOPE | GROUP_SCOPE | GROUP_SYNC); + + Barrier(input, 0); + Barrier(input, GROUP_SYNC); + Barrier(input, GROUP_SCOPE); + Barrier(input, GROUP_SCOPE | GROUP_SYNC); + // Not allowed: + // Barrier(input, DEVICE_SCOPE); + + GroupNodeOutputRecords groupRec = output.GetGroupNodeOutputRecords(1); + Barrier(groupRec, 0); + Barrier(groupRec, GROUP_SCOPE); + Barrier(groupRec, GROUP_SYNC); + Barrier(groupRec, GROUP_SCOPE | GROUP_SYNC); + // Not allowed: + // Barrier(groupRec, DEVICE_SCOPE); + groupRec.OutputComplete(); + + ThreadNodeOutputRecords threadRec = output.GetThreadNodeOutputRecords(1); + Barrier(threadRec, 0); + Barrier(threadRec, GROUP_SYNC); + // Not allowed: + // Barrier(threadRec, GROUP_SCOPE); + // Barrier(threadRec, DEVICE_SCOPE); + threadRec.OutputComplete(); +} + +[Shader("node")] +[NodeLaunch("thread")] +void node02(RWThreadNodeInputRecord input, + [MaxRecords(11)] NodeOutput output) { + DeviceBarriers(); + NodeBarriers(); + // Not allowed: + // GroupBarriers(); + // GroupNodeBarriers(); + + Barrier(buf0, 0); + Barrier(buf0, DEVICE_SCOPE); + // Not allowed: + // Barrier(buf0, GROUP_SYNC); + // Barrier(buf0, GROUP_SCOPE); + + Barrier(input, 0); + // Not allowed: + // Barrier(input, GROUP_SYNC); + // Barrier(input, GROUP_SCOPE); + // Barrier(input, DEVICE_SCOPE); + + GroupNodeOutputRecords groupRec = output.GetGroupNodeOutputRecords(1); + Barrier(groupRec, 0); + // Not allowed: + // Barrier(groupRec, GROUP_SCOPE); + // Barrier(groupRec, GROUP_SYNC); + // Barrier(groupRec, DEVICE_SCOPE); + groupRec.OutputComplete(); + + ThreadNodeOutputRecords threadRec = output.GetThreadNodeOutputRecords(1); + Barrier(threadRec, 0); + // Not allowed: + // Barrier(threadRec, GROUP_SYNC); + // Barrier(threadRec, GROUP_SCOPE); + // Barrier(threadRec, DEVICE_SCOPE); + threadRec.OutputComplete(); +} diff --git a/tools/clang/test/SemaHLSL/hlsl/intrinsics/barrier/barrier-vs-errors.hlsl b/tools/clang/test/SemaHLSL/hlsl/intrinsics/barrier/barrier-vs-errors.hlsl new file mode 100644 index 000000000..e0f69e0e7 --- /dev/null +++ b/tools/clang/test/SemaHLSL/hlsl/intrinsics/barrier/barrier-vs-errors.hlsl @@ -0,0 +1,99 @@ +// RUN: %dxc -Tlib_6_8 -verify %s +// RUN: %dxc -Tvs_6_8 -verify %s +// REQUIRES: dxil-1-8 + +// Test the ordinary shader model case with no visible group. + +struct RECORD { uint a; }; +RWBuffer buf0; +static uint i = 7; + +// Errors expected when called without visible group. +[noinline] export +void GroupBarriers() { + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(0, GROUP_SYNC); + + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(ALL_MEMORY, GROUP_SYNC); + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(ALL_MEMORY, GROUP_SCOPE); + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(ALL_MEMORY, GROUP_SCOPE | GROUP_SYNC); + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(ALL_MEMORY, DEVICE_SCOPE | GROUP_SCOPE); + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(ALL_MEMORY, 1 + 2 + 4); + + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(UAV_MEMORY, GROUP_SYNC); + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(UAV_MEMORY, GROUP_SCOPE); + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(UAV_MEMORY, GROUP_SCOPE | GROUP_SYNC); + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(UAV_MEMORY, DEVICE_SCOPE | GROUP_SCOPE); + + // expected-error@+1{{GROUP_SHARED_MEMORY specified for Barrier operation when context has no visible group}} + Barrier(GROUP_SHARED_MEMORY, 0); + // expected-error@+2{{GROUP_SHARED_MEMORY specified for Barrier operation when context has no visible group}} + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(GROUP_SHARED_MEMORY, GROUP_SYNC); + // expected-error@+2{{GROUP_SHARED_MEMORY specified for Barrier operation when context has no visible group}} + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(GROUP_SHARED_MEMORY, GROUP_SCOPE); + // expected-error@+2{{GROUP_SHARED_MEMORY specified for Barrier operation when context has no visible group}} + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(GROUP_SHARED_MEMORY, GROUP_SCOPE); +} + +// Node barriers not supported in non-node shaders. +[noinline] export +void NodeBarriers() { + // expected-error@+1{{NODE_INPUT_MEMORY or NODE_OUTPUT_MEMORY may only be specified for Barrier operation in a node shader}} + Barrier(NODE_INPUT_MEMORY, 0); + // expected-error@+1{{NODE_INPUT_MEMORY or NODE_OUTPUT_MEMORY may only be specified for Barrier operation in a node shader}} + Barrier(NODE_INPUT_MEMORY, DEVICE_SCOPE); + + // expected-error@+1{{NODE_INPUT_MEMORY or NODE_OUTPUT_MEMORY may only be specified for Barrier operation in a node shader}} + Barrier(NODE_OUTPUT_MEMORY, 0); + // expected-error@+1{{NODE_INPUT_MEMORY or NODE_OUTPUT_MEMORY may only be specified for Barrier operation in a node shader}} + Barrier(NODE_OUTPUT_MEMORY, DEVICE_SCOPE); +} + +// expected-note@+24{{entry function defined here}} +// expected-note@+23{{entry function defined here}} +// expected-note@+22{{entry function defined here}} +// expected-note@+21{{entry function defined here}} +// expected-note@+20{{entry function defined here}} +// expected-note@+19{{entry function defined here}} +// expected-note@+18{{entry function defined here}} +// expected-note@+17{{entry function defined here}} +// expected-note@+16{{entry function defined here}} +// expected-note@+15{{entry function defined here}} +// expected-note@+14{{entry function defined here}} +// expected-note@+13{{entry function defined here}} +// expected-note@+12{{entry function defined here}} +// expected-note@+11{{entry function defined here}} +// expected-note@+10{{entry function defined here}} +// expected-note@+9{{entry function defined here}} +// expected-note@+8{{entry function defined here}} +// expected-note@+7{{entry function defined here}} +// expected-note@+6{{entry function defined here}} +// expected-note@+5{{entry function defined here}} +// expected-note@+4{{entry function defined here}} +// expected-note@+3{{entry function defined here}} +// expected-note@+2{{entry function defined here}} +[Shader("vertex")] +uint main() : OUT { + + GroupBarriers(); + NodeBarriers(); + + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(buf0, GROUP_SYNC); + // expected-error@+1{{GROUP_SYNC or GROUP_SCOPE specified for Barrier operation when context has no visible group}} + Barrier(buf0, GROUP_SCOPE); + + return buf0[0]; +} diff --git a/tools/clang/test/SemaHLSL/hlsl/intrinsics/barrier/barrier-vs.hlsl b/tools/clang/test/SemaHLSL/hlsl/intrinsics/barrier/barrier-vs.hlsl new file mode 100644 index 000000000..04b14d538 --- /dev/null +++ b/tools/clang/test/SemaHLSL/hlsl/intrinsics/barrier/barrier-vs.hlsl @@ -0,0 +1,38 @@ +// RUN: %dxc -Tlib_6_8 -verify %s +// RUN: %dxc -Tvs_6_8 -verify %s +// REQUIRES: dxil-1-8 + +// Test the ordinary shader model case with no visible group. +// expected-no-diagnostics + +struct RECORD { uint a; }; +RWBuffer buf0; +static uint i = 7; + +// Barriers not requiring visible group, compatible with any shader stage. +[noinline] export +void DeviceBarriers() { + Barrier(0, 0); + + Barrier(ALL_MEMORY, 0); + Barrier(ALL_MEMORY, DEVICE_SCOPE); + Barrier(ALL_MEMORY, 2 + 2); + + Barrier(UAV_MEMORY, 0); + Barrier(UAV_MEMORY, DEVICE_SCOPE); + + // No diagnostic for non-constant expressions. + Barrier(ALL_MEMORY, i + i); + Barrier(i + i, 0); +} + +[Shader("vertex")] +uint main() : OUT { + + DeviceBarriers(); + + Barrier(buf0, 0); + Barrier(buf0, DEVICE_SCOPE); + + return buf0[0]; +} diff --git a/tools/clang/test/SemaHLSL/hlsl/objects/NodeObjects/node-objects.hlsl b/tools/clang/test/SemaHLSL/hlsl/objects/NodeObjects/node-objects.hlsl index 5384435dc..2fd316bba 100644 --- a/tools/clang/test/SemaHLSL/hlsl/objects/NodeObjects/node-objects.hlsl +++ b/tools/clang/test/SemaHLSL/hlsl/objects/NodeObjects/node-objects.hlsl @@ -160,7 +160,7 @@ void node_RWGroupNodeInputRecords([MaxRecords(4)] RWGroupNodeInputRecords input) { - Barrier(wrapper(input), 3); + Barrier(wrapper(input), 0); } // RWThreadNodeInputRecord @@ -180,7 +180,7 @@ void node_ThreadNodeInputRecord(ThreadNodeInputRecord input) [NodeLaunch("thread")] void node_RWThreadNodeInputRecord(RWThreadNodeInputRecord input) { - Barrier(wrapper(input), 3); + Barrier(wrapper(input), 0); } // EmptyNodeInput // AST: FunctionDecl 0x{{.+}} node_EmptyNodeInput 'void (EmptyNodeInput)' @@ -238,7 +238,8 @@ void node_NodeOutput(NodeOutput output3) // EmptyNodeOutput // AST: FunctionDecl 0x{{.+}} node_EmptyNodeOutput 'void (EmptyNodeOutput)' -// AST: | |-ParmVarDecl 0x[[Param:[0-9a-f]+]] {{.+}} col:40 used loadStressChild 'EmptyNodeOutput' +// AST: | |-ParmVarDecl 0x[[Param:[0-9a-f]+]] {{.+}} col:35 used loadStressChild 'EmptyNodeOutput' +// AST: | | `-HLSLMaxRecordsAttr 0x{{.+}} 12 // call to wrapper // AST: CallExpr 0x{{.+}} 'EmptyNodeOutput':'EmptyNodeOutput' // AST: |-ImplicitCastExpr 0x{{.+}} 'EmptyNodeOutput (*)(EmptyNodeOutput)' @@ -259,7 +260,7 @@ EmptyNodeOutput outputNode) [NodeDispatchGrid(1, 1, 1)] [NumThreads(1, 1, 1)] void node_EmptyNodeOutput( - [MaxOutputRecords(1)] EmptyNodeOutput loadStressChild + [MaxRecords(12)] EmptyNodeOutput loadStressChild ) { loadStressEmptyRecWorker(wrapper(loadStressChild)); diff --git a/tools/clang/test/SemaHLSL/hlsl/objects/texture/CalculateLODExtraDiag.hlsl b/tools/clang/test/SemaHLSL/hlsl/objects/texture/CalculateLODExtraDiag.hlsl index 08e37f527..9b7919864 100644 --- a/tools/clang/test/SemaHLSL/hlsl/objects/texture/CalculateLODExtraDiag.hlsl +++ b/tools/clang/test/SemaHLSL/hlsl/objects/texture/CalculateLODExtraDiag.hlsl @@ -7,7 +7,7 @@ SamplerComparisonState ss : register(s2); RWStructuredBuffer o; Texture1D t1; -// expected-note@+3{{declared here}} +// expected-note@+3{{entry function defined here}} [numthreads(3,8,1)] [shader("compute")] void foo(uint3 id : SV_GroupThreadID) @@ -24,7 +24,7 @@ void foo2(uint3 id : SV_GroupThreadID) o[0] = t1.CalculateLevelOfDetail(ss, 0.5); } -// expected-note@+3{{declared here}} +// expected-note@+3{{entry function defined here}} [numthreads(3,1,1)] [shader("compute")] void bar(uint3 id : SV_GroupThreadID) @@ -33,7 +33,7 @@ void bar(uint3 id : SV_GroupThreadID) o[0] = t1.CalculateLevelOfDetail(ss, 0.5); } -// expected-note@+4{{declared here}} +// expected-note@+4{{entry function defined here}} [shader("mesh")] [numthreads(3,1,1)] [outputtopology("triangle")] @@ -47,7 +47,7 @@ struct Payload { float2 dummy; }; -// expected-note@+3{{declared here}} +// expected-note@+3{{entry function defined here}} [numthreads(3, 2, 1)] [shader("amplification")] void ASmain() @@ -63,7 +63,7 @@ struct RECORD { uint a; }; -// expected-note@+5{{declared here}} +// expected-note@+5{{entry function defined here}} [Shader("node")] [NodeLaunch("broadcasting")] [NodeDispatchGrid(1, 1, 1)] @@ -73,7 +73,7 @@ void node01(DispatchNodeInputRecord input) { o[0] = t1.CalculateLevelOfDetail(ss, 0.5); } -// expected-note@+5{{declared here}} +// expected-note@+5{{entry function defined here}} [Shader("node")] [NodeLaunch("coalescing")] [NumThreads(1024,1,1)] @@ -84,7 +84,7 @@ void node02() o[0] = t1.CalculateLevelOfDetail(ss, 0.5); } -// expected-note@+2 {{declared here}} +// expected-note@+2 {{entry function defined here}} [Shader("vertex")] float4 vs(float2 a :A) :SV_POSTION { float r = 0; @@ -96,8 +96,8 @@ float4 vs(float2 a :A) :SV_POSTION { SamplerComparisonState s; Texture1D t; -// expected-note@+3{{declared here}} -// expected-note@+2{{declared here}} +// expected-note@+3{{entry function defined here}} +// expected-note@+2{{entry function defined here}} [shader("vertex")] float4 vs2(float a:A) : SV_Position { // expected-error@+1 {{Intrinsic CalculateLevelOfDetail potentially used by 'vs2' requires derivatives - only available in pixel, compute, amplification, mesh, or broadcast node shaders}} diff --git a/tools/clang/unittests/HLSLTestLib/FileCheckerTest.cpp b/tools/clang/unittests/HLSLTestLib/FileCheckerTest.cpp index 2ab2ec593..987b3ed31 100644 --- a/tools/clang/unittests/HLSLTestLib/FileCheckerTest.cpp +++ b/tools/clang/unittests/HLSLTestLib/FileCheckerTest.cpp @@ -563,7 +563,7 @@ FileRunCommandPart::RunDxc(dxc::DxcDllSupport &DllSupport, FileRunCommandResult result = {}; if (SUCCEEDED(resultStatus)) { IFT(pResult->GetResult(&pCompiledBlob)); - if (!opts.AstDump && !opts.DumpDependencies) { + if (!opts.AstDump && !opts.DumpDependencies && !opts.VerifyDiagnostics) { IFT(pCompiler->Disassemble(pCompiledBlob, &pDisassembly)); result.StdOut = BlobToUtf8(pDisassembly); } else {