Skip to content

Commit 24dedfd

Browse files
[OMM] Implement front end diagnostics for OMM, including on TraceRayInline, and add Availability Attributes (microsoft#7156)
This PR addresses the front end part of OMM, defining the new flags defined in the spec, and implementing the relevant diagnostics should the flags be incompatible. It also adds the second template argument to the RayQuery object, which is set to have a default value of 0 if no explicit template argument is provided. Fixes microsoft#7145 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent ec5324d commit 24dedfd

15 files changed

+447
-57
lines changed

include/dxc/DXIL/DxilConstants.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -1827,7 +1827,7 @@ enum class RayFlag : uint32_t {
18271827
CullNonOpaque = 0x80,
18281828
SkipTriangles = 0x100,
18291829
SkipProceduralPrimitives = 0x200,
1830-
ForceOMM2State = 0x400, // Force 2-state in Opacity Micromaps
1830+
ForceOMM2State = 0x400
18311831
};
18321832

18331833
// Corresponds to RAYQUERY_FLAG_* in HLSL

tools/clang/include/clang/Basic/Attr.td

+7
Original file line numberDiff line numberDiff line change
@@ -1149,6 +1149,13 @@ def HLSLNodeObject : InheritableAttr {
11491149
}];
11501150
}
11511151

1152+
// HLSL Ray Query Attribute
1153+
1154+
def HLSLRayQueryObject : InheritableAttr {
1155+
let Spellings = []; // No spellings!
1156+
let Subjects = SubjectList<[CXXRecord]>;
1157+
let Documentation = [Undocumented];
1158+
}
11521159

11531160
// HLSL Parameter Attributes
11541161

tools/clang/include/clang/Basic/DiagnosticGroups.td

+2
Original file line numberDiff line numberDiff line change
@@ -799,10 +799,12 @@ def HLSLPayloadAccessQualifer: DiagGroup<"payload-access-qualifier", [
799799
HLSLPayloadAccessQualiferPerf,
800800
HLSLPayloadAccessQualiferCall
801801
]>;
802+
def HLSLRayQueryFlags : DiagGroup<"hlsl-rayquery-flags">;
802803
def HLSLSemanticIdentifierCollision : DiagGroup<"semantic-identifier-collision">;
803804
def HLSLStructurizeExitsLifetimeMarkersConflict: DiagGroup<"structurize-exits-lifetime-markers-conflict">;
804805
def HLSLParameterUsage : DiagGroup<"parameter-usage">;
805806
def HLSLAvailability: DiagGroup<"hlsl-availability">;
807+
def HLSLAvailabilityConstant: DiagGroup<"hlsl-availability-constant">;
806808
def HLSLBarrier : DiagGroup<"hlsl-barrier">;
807809
def HLSLLegacyLiterals : DiagGroup<"hlsl-legacy-literal">;
808810
// HLSL Change Ends

tools/clang/include/clang/Basic/DiagnosticSemaKinds.td

+9
Original file line numberDiff line numberDiff line change
@@ -7652,8 +7652,17 @@ def err_payload_fields_is_payload_and_overqualified : Error<
76527652
"payload field '%0' is a payload struct. Payload access qualifiers are not allowed on payload types.">;
76537653
def warn_hlsl_payload_qualifer_dropped : Warning<
76547654
"payload access qualifiers ignored. These are only supported for lib_6_7+ targets and lib_6_6 with with the -enable-payload-qualifiers flag.">, InGroup<HLSLPayloadAccessQualifer>;
7655+
def warn_hlsl_rayquery_flags_disallowed : Warning<
7656+
"A non-zero value for the RayQueryFlags template argument requires"
7657+
" shader model 6.9 or above.">, DefaultError, InGroup<HLSLAvailability>;
7658+
def warn_hlsl_rayquery_flags_conflict : Warning<
7659+
"When using 'RAY_FLAG_FORCE_OMM_2_STATE' in RayFlags, RayQueryFlags"
7660+
" must have RAYQUERY_FLAG_ALLOW_OPACITY_MICROMAPS set.">, DefaultError, InGroup<HLSLRayQueryFlags>;
76557661
def err_hlsl_unsupported_builtin_op: Error<
76567662
"operator cannot be used with built-in type %0">;
7663+
def warn_hlsl_builtin_constant_unavailable: Warning<
7664+
"potential misuse of built-in constant %0 in shader model %1; introduced"
7665+
" in shader model %2">, InGroup<HLSLAvailabilityConstant>;
76577666
def err_hlsl_unsupported_char_literal : Error<
76587667
"unsupported style of char literal - use a single-character char-based literal">;
76597668
def err_hlsl_unsupported_clipplane_argument_expression : Error<

tools/clang/lib/AST/ASTContextHLSL.cpp

+56-23
Original file line numberDiff line numberDiff line change
@@ -545,10 +545,19 @@ hlsl::DeclareRecordTypeWithHandle(ASTContext &context, StringRef name,
545545
return typeDeclBuilder.getRecordDecl();
546546
}
547547

548+
AvailabilityAttr *ConstructAvailabilityAttribute(clang::ASTContext &context,
549+
VersionTuple Introduced) {
550+
AvailabilityAttr *AAttr = AvailabilityAttr::CreateImplicit(
551+
context, &context.Idents.get(""), clang::VersionTuple(6, 9),
552+
clang::VersionTuple(), clang::VersionTuple(), false, "");
553+
return AAttr;
554+
}
555+
548556
// creates a global static constant unsigned integer with value.
549557
// equivalent to: static const uint name = val;
550558
static void AddConstUInt(clang::ASTContext &context, DeclContext *DC,
551-
StringRef name, unsigned val) {
559+
StringRef name, unsigned val,
560+
AvailabilityAttr *AAttr = nullptr) {
552561
IdentifierInfo &Id = context.Idents.get(name, tok::TokenKind::identifier);
553562
QualType type = context.getConstType(context.UnsignedIntTy);
554563
VarDecl *varDecl = VarDecl::Create(context, DC, NoLoc, NoLoc, &Id, type,
@@ -558,6 +567,9 @@ static void AddConstUInt(clang::ASTContext &context, DeclContext *DC,
558567
context, llvm::APInt(context.getIntWidth(type), val), type, NoLoc);
559568
varDecl->setInit(exprVal);
560569
varDecl->setImplicit(true);
570+
if (AAttr)
571+
varDecl->addAttr(AAttr);
572+
561573
DC->addDecl(varDecl);
562574
}
563575

@@ -570,6 +582,7 @@ static void AddConstUInt(clang::ASTContext &context, StringRef name,
570582
struct Enumerant {
571583
StringRef name;
572584
unsigned value;
585+
AvailabilityAttr *avail = nullptr;
573586
};
574587

575588
static void AddTypedefPseudoEnum(ASTContext &context, StringRef name,
@@ -585,33 +598,45 @@ static void AddTypedefPseudoEnum(ASTContext &context, StringRef name,
585598
enumDecl->setImplicit(true);
586599
// static const uint <enumerant.name> = <enumerant.value>;
587600
for (const Enumerant &enumerant : enumerants) {
588-
AddConstUInt(context, curDC, enumerant.name, enumerant.value);
601+
AddConstUInt(context, curDC, enumerant.name, enumerant.value,
602+
enumerant.avail);
589603
}
590604
}
591605

592606
/// <summary> Adds all constants and enums for ray tracing </summary>
593607
void hlsl::AddRaytracingConstants(ASTContext &context) {
608+
609+
// Create aversion tuple for availability attributes
610+
// for the RAYQUERY_FLAG enum
611+
VersionTuple VT69 = VersionTuple(6, 9);
612+
594613
AddTypedefPseudoEnum(
595614
context, "RAY_FLAG",
596-
{
597-
{"RAY_FLAG_NONE", (unsigned)DXIL::RayFlag::None},
598-
{"RAY_FLAG_FORCE_OPAQUE", (unsigned)DXIL::RayFlag::ForceOpaque},
599-
{"RAY_FLAG_FORCE_NON_OPAQUE",
600-
(unsigned)DXIL::RayFlag::ForceNonOpaque},
601-
{"RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH",
602-
(unsigned)DXIL::RayFlag::AcceptFirstHitAndEndSearch},
603-
{"RAY_FLAG_SKIP_CLOSEST_HIT_SHADER",
604-
(unsigned)DXIL::RayFlag::SkipClosestHitShader},
605-
{"RAY_FLAG_CULL_BACK_FACING_TRIANGLES",
606-
(unsigned)DXIL::RayFlag::CullBackFacingTriangles},
607-
{"RAY_FLAG_CULL_FRONT_FACING_TRIANGLES",
608-
(unsigned)DXIL::RayFlag::CullFrontFacingTriangles},
609-
{"RAY_FLAG_CULL_OPAQUE", (unsigned)DXIL::RayFlag::CullOpaque},
610-
{"RAY_FLAG_CULL_NON_OPAQUE", (unsigned)DXIL::RayFlag::CullNonOpaque},
611-
{"RAY_FLAG_SKIP_TRIANGLES", (unsigned)DXIL::RayFlag::SkipTriangles},
612-
{"RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES",
613-
(unsigned)DXIL::RayFlag::SkipProceduralPrimitives},
614-
});
615+
{{"RAY_FLAG_NONE", (unsigned)DXIL::RayFlag::None},
616+
{"RAY_FLAG_FORCE_OPAQUE", (unsigned)DXIL::RayFlag::ForceOpaque},
617+
{"RAY_FLAG_FORCE_NON_OPAQUE", (unsigned)DXIL::RayFlag::ForceNonOpaque},
618+
{"RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH",
619+
(unsigned)DXIL::RayFlag::AcceptFirstHitAndEndSearch},
620+
{"RAY_FLAG_SKIP_CLOSEST_HIT_SHADER",
621+
(unsigned)DXIL::RayFlag::SkipClosestHitShader},
622+
{"RAY_FLAG_CULL_BACK_FACING_TRIANGLES",
623+
(unsigned)DXIL::RayFlag::CullBackFacingTriangles},
624+
{"RAY_FLAG_CULL_FRONT_FACING_TRIANGLES",
625+
(unsigned)DXIL::RayFlag::CullFrontFacingTriangles},
626+
{"RAY_FLAG_CULL_OPAQUE", (unsigned)DXIL::RayFlag::CullOpaque},
627+
{"RAY_FLAG_CULL_NON_OPAQUE", (unsigned)DXIL::RayFlag::CullNonOpaque},
628+
{"RAY_FLAG_SKIP_TRIANGLES", (unsigned)DXIL::RayFlag::SkipTriangles},
629+
{"RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES",
630+
(unsigned)DXIL::RayFlag::SkipProceduralPrimitives},
631+
{"RAY_FLAG_FORCE_OMM_2_STATE", (unsigned)DXIL::RayFlag::ForceOMM2State,
632+
ConstructAvailabilityAttribute(context, VT69)}});
633+
634+
AddTypedefPseudoEnum(
635+
context, "RAYQUERY_FLAG",
636+
{{"RAYQUERY_FLAG_NONE", (unsigned)DXIL::RayQueryFlag::None},
637+
{"RAYQUERY_FLAG_ALLOW_OPACITY_MICROMAPS",
638+
(unsigned)DXIL::RayQueryFlag::AllowOpacityMicromaps,
639+
ConstructAvailabilityAttribute(context, VT69)}});
615640

616641
AddTypedefPseudoEnum(
617642
context, "COMMITTED_STATUS",
@@ -1161,7 +1186,14 @@ CXXRecordDecl *hlsl::DeclareRayQueryType(ASTContext &context) {
11611186
// template<uint kind> RayQuery { ... }
11621187
BuiltinTypeDeclBuilder typeDeclBuilder(context.getTranslationUnitDecl(),
11631188
"RayQuery");
1164-
typeDeclBuilder.addIntegerTemplateParam("flags", context.UnsignedIntTy);
1189+
typeDeclBuilder.addIntegerTemplateParam("constRayFlags",
1190+
context.UnsignedIntTy);
1191+
// create an optional second template argument with default value
1192+
// that contains the value of DXIL::RayFlag::None
1193+
llvm::Optional<int64_t> DefaultRayQueryFlag =
1194+
static_cast<int64_t>(DXIL::RayFlag::None);
1195+
typeDeclBuilder.addIntegerTemplateParam(
1196+
"RayQueryFlags", context.UnsignedIntTy, DefaultRayQueryFlag);
11651197
typeDeclBuilder.startDefinition();
11661198
typeDeclBuilder.addField(
11671199
"h", context.UnsignedIntTy); // Add an 'h' field to hold the handle.
@@ -1178,7 +1210,8 @@ CXXRecordDecl *hlsl::DeclareRayQueryType(ASTContext &context) {
11781210
context.DeclarationNames.getCXXConstructorName(canQualType), false,
11791211
&pConstructorDecl, &pTypeSourceInfo);
11801212
typeDeclBuilder.getRecordDecl()->addDecl(pConstructorDecl);
1181-
1213+
typeDeclBuilder.getRecordDecl()->addAttr(
1214+
HLSLRayQueryObjectAttr::CreateImplicit(context));
11821215
return typeDeclBuilder.getRecordDecl();
11831216
}
11841217

tools/clang/lib/CodeGen/CGHLSLMSFinishCodeGen.cpp

+5-2
Original file line numberDiff line numberDiff line change
@@ -2839,8 +2839,11 @@ void TranslateRayQueryConstructor(HLModule &HLM) {
28392839
HLM.GetTypeSystem().GetStructAnnotation(pRQType);
28402840
DXASSERT(SA, "otherwise, could not find type annoation for RayQuery "
28412841
"specialization");
2842-
DXASSERT(SA->GetNumTemplateArgs() == 1 &&
2843-
SA->GetTemplateArgAnnotation(0).IsIntegral(),
2842+
DXASSERT((SA->GetNumTemplateArgs() == 1 &&
2843+
SA->GetTemplateArgAnnotation(0).IsIntegral()) ||
2844+
(SA->GetNumTemplateArgs() == 2 &&
2845+
SA->GetTemplateArgAnnotation(0).IsIntegral() &&
2846+
SA->GetTemplateArgAnnotation(1).IsIntegral()),
28442847
"otherwise, RayQuery has changed, or lacks template args");
28452848
llvm::IRBuilder<> Builder(CI);
28462849
llvm::Value *rayFlags =

tools/clang/lib/Sema/SemaHLSL.cpp

+82-7
Original file line numberDiff line numberDiff line change
@@ -3992,13 +3992,6 @@ class HLSLExternalSource : public ExternalSemaSource {
39923992
return IsSubobjectBasicKind(GetTypeElementKind(type));
39933993
}
39943994

3995-
bool IsRayQueryBasicKind(ArBasicKind kind) {
3996-
return kind == AR_OBJECT_RAY_QUERY;
3997-
}
3998-
bool IsRayQueryType(QualType type) {
3999-
return IsRayQueryBasicKind(GetTypeElementKind(type));
4000-
}
4001-
40023995
void WarnMinPrecision(QualType Type, SourceLocation Loc) {
40033996
Type = Type->getCanonicalTypeUnqualified();
40043997
if (IsVectorType(m_sema, Type) || IsMatrixType(m_sema, Type)) {
@@ -5326,6 +5319,39 @@ class HLSLExternalSource : public ExternalSemaSource {
53265319
return true;
53275320
}
53285321
return false;
5322+
} else if (Template->getTemplatedDecl()
5323+
->hasAttr<HLSLRayQueryObjectAttr>()) {
5324+
int numArgs = TemplateArgList.size();
5325+
DXASSERT(numArgs == 1 || numArgs == 2,
5326+
"otherwise the template has not been declared properly");
5327+
5328+
// first, determine if the rayquery flag AllowOpacityMicromaps is set
5329+
bool HasRayQueryFlagAllowOpacityMicromaps = false;
5330+
if (numArgs > 1) {
5331+
const TemplateArgument &Arg2 = TemplateArgList[1].getArgument();
5332+
Expr *Expr2 = Arg2.getAsExpr();
5333+
llvm::APSInt Arg2val;
5334+
Expr2->isIntegerConstantExpr(Arg2val, m_sema->getASTContext());
5335+
if (Arg2val.getZExtValue() &
5336+
(unsigned)DXIL::RayQueryFlag::AllowOpacityMicromaps)
5337+
HasRayQueryFlagAllowOpacityMicromaps = true;
5338+
}
5339+
5340+
// next, get the first template argument, to check if
5341+
// the ForceOMM2State flag is set
5342+
const TemplateArgument &Arg1 = TemplateArgList[0].getArgument();
5343+
Expr *Expr1 = Arg1.getAsExpr();
5344+
llvm::APSInt Arg1val;
5345+
bool HasRayFlagForceOMM2State =
5346+
Expr1->isIntegerConstantExpr(Arg1val, m_sema->getASTContext()) &&
5347+
(Arg1val.getLimitedValue() &
5348+
(uint64_t)DXIL::RayFlag::ForceOMM2State) != 0;
5349+
5350+
// finally, if ForceOMM2State is set and AllowOpacityMicromaps
5351+
// isn't, emit a warning
5352+
if (HasRayFlagForceOMM2State && !HasRayQueryFlagAllowOpacityMicromaps)
5353+
m_sema->Diag(TemplateArgList[0].getLocation(),
5354+
diag::warn_hlsl_rayquery_flags_conflict);
53295355
} else if (Template->getTemplatedDecl()->hasAttr<HLSLTessPatchAttr>()) {
53305356
DXASSERT(TemplateArgList.size() > 0,
53315357
"Tessellation patch should have at least one template args");
@@ -11568,6 +11594,52 @@ static void DiagnoseReachableBarrier(Sema &S, CallExpr *CE,
1156811594
}
1156911595
}
1157011596

11597+
bool IsRayFlagForceOMM2StateSet(Sema &sema, const CallExpr *CE) {
11598+
const Expr *Expr1 = CE->getArg(1);
11599+
llvm::APSInt constantResult;
11600+
return Expr1->isIntegerConstantExpr(constantResult, sema.getASTContext()) &&
11601+
(constantResult.getLimitedValue() &
11602+
(uint64_t)DXIL::RayFlag::ForceOMM2State) != 0;
11603+
}
11604+
11605+
void DiagnoseTraceRayInline(Sema &sema, CallExpr *callExpr) {
11606+
// Validate if the RayFlag parameter has RAY_FLAG_FORCE_OMM_2_STATE set,
11607+
// the RayQuery decl must have RAYQUERY_FLAG_ALLOW_OPACITY_MICROMAPS set,
11608+
// otherwise emit a diagnostic.
11609+
if (IsRayFlagForceOMM2StateSet(sema, callExpr)) {
11610+
CXXMemberCallExpr *CXXCallExpr = dyn_cast<CXXMemberCallExpr>(callExpr);
11611+
if (!CXXCallExpr) {
11612+
return;
11613+
}
11614+
const DeclRefExpr *DRE =
11615+
dyn_cast<DeclRefExpr>(CXXCallExpr->getImplicitObjectArgument());
11616+
assert(DRE);
11617+
QualType QT = DRE->getType();
11618+
auto *typeRecordDecl = QT->getAsCXXRecordDecl();
11619+
ClassTemplateSpecializationDecl *SpecDecl =
11620+
llvm::dyn_cast<ClassTemplateSpecializationDecl>(typeRecordDecl);
11621+
11622+
if (!SpecDecl)
11623+
return;
11624+
11625+
// Guaranteed 2 arguments since the rayquery constructor
11626+
// automatically creates 2 template args
11627+
DXASSERT(SpecDecl->getTemplateArgs().size() == 2,
11628+
"else rayquery constructor template args are not 2");
11629+
llvm::APSInt Arg2val = SpecDecl->getTemplateArgs()[1].getAsIntegral();
11630+
bool IsRayQueryAllowOMMSet =
11631+
Arg2val.getZExtValue() &
11632+
(unsigned)DXIL::RayQueryFlag::AllowOpacityMicromaps;
11633+
if (!IsRayQueryAllowOMMSet) {
11634+
// Diagnose the call
11635+
sema.Diag(CXXCallExpr->getExprLoc(),
11636+
diag::warn_hlsl_rayquery_flags_conflict);
11637+
sema.Diag(DRE->getDecl()->getLocation(), diag::note_previous_decl)
11638+
<< "RayQueryFlags";
11639+
}
11640+
}
11641+
}
11642+
1157111643
static bool isStringLiteral(QualType type) {
1157211644
if (!type->isConstantArrayType())
1157311645
return false;
@@ -11612,6 +11684,9 @@ void Sema::DiagnoseReachableHLSLCall(CallExpr *CE, const hlsl::ShaderModel *SM,
1161211684
DiagnoseReachableBarrier(*this, CE, SM, EntrySK, NodeLaunchTy, EntryDecl,
1161311685
Diags);
1161411686
break;
11687+
case hlsl::IntrinsicOp::MOP_TraceRayInline:
11688+
DiagnoseTraceRayInline(*this, CE);
11689+
break;
1161511690
default:
1161611691
break;
1161711692
}

0 commit comments

Comments
 (0)