Add barrier MemoryTypeFlags and SemanticFlags diagnostics (#6513)
Context-specific diagnostics are warnings with DefaultError, since in theory they could be dead code at this stage. There were some changes to existing Sema diagnostic hooks along the way. SemaHLSLDiagnoseTU.cpp - HLSLMethodCallDiagnoseVisitor - extend to non-method calls and pass CallExpr - instead of skipping when call reached from multiple entry/export functions, pass locallyVisited flag for skipping of redundant diags not dependent on entry properties. - use llvm::SmallPtrSet for DiagnosticCalls - capture launch type for entry and pass it down Replace DiagnoseHLSLMethodCall hook with CheckHLSLFunctionCall: Move hook into Sema::CheckFunctionCall in SemaChecking.cpp to be general to either a function call or a method call. Refactor existing code in DiagnoseHLSLMethodCall into CheckFinishedCrossGroupSharingCall called in the hook for this method. Add CheckBarrierCall for context-free flag validity check, called by CheckHLSLFunctionCall. Refactor CalculateLOD checking into more generic parts, dispatched based on IntrinsicOp from top-level DiagnoseReachableHLSLCall function. Switch to using new note: "entry function defined here", instead of "declared here". Fix intrinsic checking to use IsBuiltinTable on the intrinsic attribute's group. **Preparation Changes** While these could be broken out, the barrier diagnostic changes are dependent on them, and testing for some of these is dependent on the other parts of the barrier diagnostic changes. Correct errors in tests, check MaxRecords for EmptyNodeOutput in AST Note that Barrier(..., 3) means SemanticFlags: GroupSync | GroupScope. These are only valid in a shader with a visible group, and GroupSync on memory with at least group scope, so they have been changed to 0 in specific cases in these tests. Make DiagnoseSVForLaunchType a static function, add FIXME notes. Use StringRef for IsBuiltinTable, compare strings instead of pointers. Fix FileCheckerTest for -verify output. New ShaderModel::HasVisibleGroup uses ShaderKind and NodeLaunchType to determine whether shader type has a visible group.
This commit is contained in:
Родитель
fa39b3984f
Коммит
fe393e09d7
|
@ -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); }
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<HLSLBarrier>, 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<HLSLBarrier>, 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<HLSLBarrier>, DefaultError;
|
||||
def warn_hlsl_barrier_no_mem_with_required_group_scope: Warning<
|
||||
"GROUP_SCOPE specified for Barrier operation without applicable memory">,
|
||||
InGroup<HLSLBarrier>, DefaultError;
|
||||
def warn_hlsl_barrier_no_mem_with_required_device_scope: Warning<
|
||||
"DEVICE_SCOPE specified for Barrier operation without applicable memory">,
|
||||
InGroup<HLSLBarrier>, DefaultError;
|
||||
// HLSL Change Ends
|
||||
|
||||
// SPIRV Change Starts
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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<HLSLIntrinsicAttr>()) {
|
||||
hlsl::IntrinsicOp opCode =
|
||||
(IntrinsicOp)MD->getAttr<HLSLIntrinsicAttr>()->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<ClassTemplateSpecializationDecl>(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<RecordType>()->getDecl();
|
||||
if (!RD->hasAttr<HLSLNodeTrackRWInputSharingAttr>()) {
|
||||
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<HLSLIntrinsicAttr>()) {
|
||||
hlsl::IntrinsicOp opCode =
|
||||
(IntrinsicOp)MD->getAttr<HLSLIntrinsicAttr>()->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<ClassTemplateSpecializationDecl>(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<RecordType>()->getDecl();
|
||||
if (!RD->hasAttr<HLSLNodeTrackRWInputSharingAttr>()) {
|
||||
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<HLSLNodeLaunchAttr>()) {
|
||||
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<HLSLNumThreadsAttr>()) {
|
||||
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<HLSLIntrinsicAttr>();
|
||||
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<CXXMethodDecl>(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<HLSLNumThreadsAttr>()) {
|
||||
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(<UAV Resource>, 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(<node record object>, 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<HLSLIntrinsicAttr>();
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -302,24 +302,26 @@ clang::FunctionDecl *ValidateNoRecursion(CallGraphWithRecurseGuard &callGraph,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
class HLSLMethodCallDiagnoseVisitor
|
||||
: public RecursiveASTVisitor<HLSLMethodCallDiagnoseVisitor> {
|
||||
class HLSLCallDiagnoseVisitor
|
||||
: public RecursiveASTVisitor<HLSLCallDiagnoseVisitor> {
|
||||
public:
|
||||
explicit HLSLMethodCallDiagnoseVisitor(
|
||||
explicit HLSLCallDiagnoseVisitor(
|
||||
Sema *S, const hlsl::ShaderModel *SM, DXIL::ShaderKind EntrySK,
|
||||
const FunctionDecl *EntryDecl,
|
||||
std::set<CXXMemberCallExpr *> &DiagnosedCalls)
|
||||
: sema(S), SM(SM), EntrySK(EntrySK), EntryDecl(EntryDecl),
|
||||
DiagnosedCalls(DiagnosedCalls) {}
|
||||
DXIL::NodeLaunchType NodeLaunchTy, const FunctionDecl *EntryDecl,
|
||||
llvm::SmallPtrSetImpl<CallExpr *> &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<CXXMemberCallExpr *> &DiagnosedCalls;
|
||||
llvm::SmallPtrSetImpl<CallExpr *> &DiagnosedCalls;
|
||||
};
|
||||
|
||||
std::optional<uint32_t>
|
||||
|
@ -426,7 +429,7 @@ void hlsl::DiagnoseTranslationUnit(clang::Sema *self) {
|
|||
hlsl::ShaderModel::GetByName(self->getLangOpts().HLSLProfile.c_str());
|
||||
|
||||
std::set<FunctionDecl *> DiagnosedDecls;
|
||||
std::set<CXXMemberCallExpr *> DiagnosedCalls;
|
||||
llvm::SmallPtrSet<CallExpr *, 16> 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<clang::HLSLShaderAttr>())
|
||||
EntrySK = ShaderModel::KindFromFullName(Attr->getStage());
|
||||
if (EntrySK == DXIL::ShaderKind::Node)
|
||||
if (const auto *pAttr = FDecl->getAttr<HLSLNodeLaunchAttr>())
|
||||
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<clang::HLSLNodeLaunchAttr>()) {
|
||||
llvm::StringRef NodeLaunchTyStr = NodeLaunchAttr->getLaunchType();
|
||||
hlsl::DXIL::NodeLaunchType NodeLaunchTy =
|
||||
ShaderModel::NodeLaunchTypeFromName(NodeLaunchTyStr);
|
||||
Visitor.getSema()->DiagnoseSVForLaunchType(FD, NodeLaunchTy);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -63,14 +63,14 @@ void node04([MaxRecords(6)] RWGroupNodeInputRecords<RECORD> input)
|
|||
void node05([MaxRecords(5)] NodeOutput<RECORD> outputs)
|
||||
{
|
||||
ThreadNodeOutputRecords<RECORD> 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")]
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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<uint> 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();
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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<uint> 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);
|
||||
}
|
|
@ -0,0 +1,195 @@
|
|||
// RUN: %dxc -Tlib_6_8 -verify %s
|
||||
// REQUIRES: dxil-1-8
|
||||
|
||||
struct RECORD { uint a; };
|
||||
RWBuffer<uint> 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<RECORD> input,
|
||||
[MaxRecords(11)] NodeOutput<RECORD> output) {
|
||||
|
||||
GroupNodeOutputRecords<RECORD> groupRec = output.GetGroupNodeOutputRecords(1);
|
||||
// expected-error@+1{{DEVICE_SCOPE specified for Barrier operation without applicable memory}}
|
||||
Barrier(groupRec, DEVICE_SCOPE);
|
||||
groupRec.OutputComplete();
|
||||
|
||||
ThreadNodeOutputRecords<RECORD> 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<RECORD> input,
|
||||
[MaxRecords(11)] NodeOutput<RECORD> output) {
|
||||
|
||||
// expected-error@+1{{DEVICE_SCOPE specified for Barrier operation without applicable memory}}
|
||||
Barrier(input, DEVICE_SCOPE);
|
||||
|
||||
GroupNodeOutputRecords<RECORD> groupRec = output.GetGroupNodeOutputRecords(1);
|
||||
// expected-error@+1{{DEVICE_SCOPE specified for Barrier operation without applicable memory}}
|
||||
Barrier(groupRec, DEVICE_SCOPE);
|
||||
groupRec.OutputComplete();
|
||||
|
||||
ThreadNodeOutputRecords<RECORD> 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<RECORD> input,
|
||||
[MaxRecords(11)] NodeOutput<RECORD> 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<RECORD> 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<RECORD> 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();
|
||||
}
|
|
@ -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<uint> 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<RECORD> input,
|
||||
[MaxRecords(11)] NodeOutput<RECORD> 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<RECORD> 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<RECORD> 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<RECORD> input,
|
||||
[MaxRecords(11)] NodeOutput<RECORD> 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<RECORD> 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<RECORD> 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<RECORD> input,
|
||||
[MaxRecords(11)] NodeOutput<RECORD> 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<RECORD> groupRec = output.GetGroupNodeOutputRecords(1);
|
||||
Barrier(groupRec, 0);
|
||||
// Not allowed:
|
||||
// Barrier(groupRec, GROUP_SCOPE);
|
||||
// Barrier(groupRec, GROUP_SYNC);
|
||||
// Barrier(groupRec, DEVICE_SCOPE);
|
||||
groupRec.OutputComplete();
|
||||
|
||||
ThreadNodeOutputRecords<RECORD> threadRec = output.GetThreadNodeOutputRecords(1);
|
||||
Barrier(threadRec, 0);
|
||||
// Not allowed:
|
||||
// Barrier(threadRec, GROUP_SYNC);
|
||||
// Barrier(threadRec, GROUP_SCOPE);
|
||||
// Barrier(threadRec, DEVICE_SCOPE);
|
||||
threadRec.OutputComplete();
|
||||
}
|
|
@ -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<uint> 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];
|
||||
}
|
|
@ -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<uint> 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];
|
||||
}
|
|
@ -160,7 +160,7 @@ void node_RWGroupNodeInputRecords([MaxRecords(4)] RWGroupNodeInputRecords<RECORD
|
|||
[NodeLaunch("thread")]
|
||||
void node_ThreadNodeInputRecord(ThreadNodeInputRecord<RECORD> input)
|
||||
{
|
||||
Barrier(wrapper(input), 3);
|
||||
Barrier(wrapper(input), 0);
|
||||
}
|
||||
|
||||
// RWThreadNodeInputRecord
|
||||
|
@ -180,7 +180,7 @@ void node_ThreadNodeInputRecord(ThreadNodeInputRecord<RECORD> input)
|
|||
[NodeLaunch("thread")]
|
||||
void node_RWThreadNodeInputRecord(RWThreadNodeInputRecord<RECORD> 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<RECORD> 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{{.+}} <col:27, col:50> 'EmptyNodeOutput':'EmptyNodeOutput'
|
||||
// AST: |-ImplicitCastExpr 0x{{.+}} <col:27> 'EmptyNodeOutput (*)(EmptyNodeOutput)' <FunctionToPointerDecay>
|
||||
|
@ -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));
|
||||
|
|
|
@ -7,7 +7,7 @@ SamplerComparisonState ss : register(s2);
|
|||
RWStructuredBuffer<uint> o;
|
||||
Texture1D <float> 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<RECORD> 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}}
|
||||
|
|
|
@ -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 {
|
||||
|
|
Загрузка…
Ссылка в новой задаче