Skip to content

Commit c78ed99

Browse files
simolltex3d
andauthored
[SER] GetAttributes(out udt) instead of templated return (#7606)
``` Old: T HitObject::GetAttributes<T>() New: void HitObject::GetAttributes(out udt) ``` - remove HitObject::GetAttributes<T> template code path from DeduceTemplateArgumentsForHLSL - cleanup intersection attribute diagnostic code path - adjust GetAttributes calls and expected AST, HLOps in tests (DXIL unaffected) Closes #7534 This is a breaking change. Merge and release must be coordinated with: - hlsl-spec change (microsoft/hlsl-specs#495) - HLK releases (SM6.9 preview tests use old signature) --------- Co-authored-by: Tex Riddell <texr@microsoft.com>
1 parent 5ceaf84 commit c78ed99

17 files changed

+209
-204
lines changed

include/dxc/HLSL/HLOperations.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,9 @@ const unsigned kHitObjectInvoke_PayloadOpIdx = 2;
462462
const unsigned kHitObjectFromRayQuery_WithAttrs_AttributeOpIdx = 4;
463463
const unsigned kHitObjectFromRayQuery_WithAttrs_NumOp = 5;
464464

465+
// HitObject::GetAttributes
466+
const unsigned kHitObjectGetAttributes_AttributeOpIdx = 2;
467+
465468
// Linear Algebra Operations
466469

467470
// MatVecMul

lib/HLSL/HLOperationLower.cpp

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6378,18 +6378,11 @@ Value *TranslateHitObjectGetAttributes(CallInst *CI, IntrinsicOp IOP,
63786378

63796379
Value *HitObjectPtr = CI->getArgOperand(1);
63806380
Value *HitObject = Builder.CreateLoad(HitObjectPtr);
6381-
6382-
Type *AttrTy = cast<PointerType>(CI->getType())->getPointerElementType();
6383-
6384-
IRBuilder<> EntryBuilder(
6385-
dxilutil::FindAllocaInsertionPt(CI->getParent()->getParent()));
6386-
unsigned AttrAlign = Helper.dataLayout.getABITypeAlignment(AttrTy);
6387-
AllocaInst *AttrMem = EntryBuilder.CreateAlloca(AttrTy);
6388-
AttrMem->setAlignment(AttrAlign);
6389-
Constant *opArg = OP->GetU32Const((unsigned)OpCode);
6390-
TrivialDxilOperation(OpCode, {opArg, HitObject, AttrMem}, CI->getType(),
6391-
Helper.voidTy, OP, Builder);
6392-
return AttrMem;
6381+
Value *AttrOutPtr =
6382+
CI->getArgOperand(HLOperandIndex::kHitObjectGetAttributes_AttributeOpIdx);
6383+
TrivialDxilOperation(OpCode, {nullptr, HitObject, AttrOutPtr},
6384+
AttrOutPtr->getType(), CI, OP);
6385+
return nullptr;
63936386
}
63946387

63956388
Value *TranslateHitObjectScalarGetter(CallInst *CI, IntrinsicOp IOP,

lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1518,6 +1518,10 @@ static bool isUDTIntrinsicArg(CallInst *CI, unsigned OpIdx) {
15181518
if (OpIdx == HLOperandIndex::kHitObjectInvoke_PayloadOpIdx)
15191519
return true;
15201520
break;
1521+
case IntrinsicOp::MOP_DxHitObject_GetAttributes:
1522+
if (OpIdx == HLOperandIndex::kHitObjectGetAttributes_AttributeOpIdx)
1523+
return true;
1524+
break;
15211525
default:
15221526
break;
15231527
}

tools/clang/include/clang/Sema/Sema.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3811,8 +3811,7 @@ class Sema {
38113811
void DiagnoseHLSLDeclAttr(const Decl *D, const Attr *A);
38123812
void DiagnoseCoherenceMismatch(const Expr *SrcExpr, QualType TargetType,
38133813
SourceLocation Loc);
3814-
void CheckHLSLFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
3815-
const FunctionProtoType *Proto);
3814+
void CheckHLSLFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall);
38163815
void DiagnoseReachableHLSLCall(CallExpr *CE, const hlsl::ShaderModel *SM,
38173816
hlsl::DXIL::ShaderKind EntrySK,
38183817
hlsl::DXIL::NodeLaunchType NodeLaunchTy,
@@ -8831,8 +8830,6 @@ class Sema {
88318830
bool AllowOnePastEnd=true, bool IndexNegated=false);
88328831
// HLSL Change Starts - checking array subscript access to vector or matrix member
88338832
void CheckHLSLArrayAccess(const Expr *expr);
8834-
bool CheckHLSLIntrinsicCall(FunctionDecl *FDecl, CallExpr *TheCall);
8835-
bool CheckHLSLFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall);
88368833
// HLSL Change ends
88378834
void CheckArrayAccess(const Expr *E);
88388835
// Used to grab the relevant information from a FormatAttr and a

tools/clang/lib/Sema/SemaChecking.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1426,7 +1426,7 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
14261426
CheckMemaccessArguments(TheCall, CMId, FnInfo);
14271427
#endif // HLSL Change Ends
14281428

1429-
CheckHLSLFunctionCall(FDecl, TheCall, Proto); // HLSL Change
1429+
CheckHLSLFunctionCall(FDecl, TheCall); // HLSL Change
14301430

14311431
return false;
14321432
}

tools/clang/lib/Sema/SemaExpr.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5349,8 +5349,6 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
53495349
if (FDecl) {
53505350
if (CheckFunctionCall(FDecl, TheCall, Proto))
53515351
return ExprError();
5352-
if (CheckHLSLFunctionCall(FDecl, TheCall))
5353-
return ExprError();
53545352
if (BuiltinID)
53555353
return CheckBuiltinFunctionCall(FDecl, BuiltinID, TheCall);
53565354
} else if (NDecl) {

tools/clang/lib/Sema/SemaHLSL.cpp

Lines changed: 107 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -10829,18 +10829,24 @@ HLSLExternalSource::ApplyTypeSpecSignToParsedType(clang::QualType &type,
1082910829
}
1083010830
}
1083110831

10832-
bool DiagnoseIntersectionAttributes(Sema &S, SourceLocation Loc, QualType Ty) {
10833-
// Must be a UDT
10832+
bool CheckIntersectionAttributeArg(Sema &S, Expr *E) {
10833+
SourceLocation Loc = E->getExprLoc();
10834+
QualType Ty = E->getType();
10835+
10836+
// Identify problematic fields first (high diagnostic accuracy, may miss some
10837+
// invalid cases)
10838+
const TypeDiagContext DiagContext = TypeDiagContext::Attributes;
10839+
if (DiagnoseTypeElements(S, Loc, Ty, DiagContext, DiagContext))
10840+
return true;
10841+
10842+
// Must be a UDT (low diagnostic accuracy, catches remaining invalid cases)
1083410843
if (Ty.isNull() || !hlsl::IsHLSLCopyableAnnotatableRecord(Ty)) {
1083510844
S.Diag(Loc, diag::err_payload_attrs_must_be_udt)
1083610845
<< /*payload|attributes|callable*/ 1 << /*parameter %2|type*/ 1;
10837-
return false;
10846+
return true;
1083810847
}
1083910848

10840-
const TypeDiagContext DiagContext = TypeDiagContext::Attributes;
10841-
if (DiagnoseTypeElements(S, Loc, Ty, DiagContext, DiagContext))
10842-
return false;
10843-
return true;
10849+
return false;
1084410850
}
1084510851

1084610852
Sema::TemplateDeductionResult
@@ -10951,7 +10957,6 @@ HLSLExternalSource::DeduceTemplateArgumentsForHLSL(
1095110957
LPCSTR tableName = cursor.GetTableName();
1095210958
// Currently only intrinsic we allow for explicit template arguments are
1095310959
// for Load/Store for ByteAddressBuffer/RWByteAddressBuffer
10954-
// and HitObject::GetAttributes with user-defined intersection attributes.
1095510960

1095610961
// Check Explicit template arguments
1095710962
UINT intrinsicOp = (*cursor)->Op;
@@ -10966,11 +10971,9 @@ HLSLExternalSource::DeduceTemplateArgumentsForHLSL(
1096610971
IsBABLoad = intrinsicOp == (UINT)IntrinsicOp::MOP_Load;
1096710972
IsBABStore = intrinsicOp == (UINT)IntrinsicOp::MOP_Store;
1096810973
}
10969-
bool IsHitObjectGetAttributes =
10970-
intrinsicOp == (UINT)IntrinsicOp::MOP_DxHitObject_GetAttributes;
1097110974
if (ExplicitTemplateArgs && ExplicitTemplateArgs->size() >= 1) {
1097210975
SourceLocation Loc = ExplicitTemplateArgs->getLAngleLoc();
10973-
if (!IsBABLoad && !IsBABStore && !IsHitObjectGetAttributes) {
10976+
if (!IsBABLoad && !IsBABStore) {
1097410977
getSema()->Diag(Loc, diag::err_hlsl_intrinsic_template_arg_unsupported)
1097510978
<< intrinsicName;
1097610979
return Sema::TemplateDeductionResult::TDK_Invalid;
@@ -11000,10 +11003,6 @@ HLSLExternalSource::DeduceTemplateArgumentsForHLSL(
1100011003
return Sema::TemplateDeductionResult::TDK_Invalid;
1100111004
}
1100211005
}
11003-
if (IsHitObjectGetAttributes &&
11004-
!DiagnoseIntersectionAttributes(*getSema(), Loc,
11005-
functionTemplateTypeArg))
11006-
return Sema::TemplateDeductionResult::TDK_Invalid;
1100711006
} else if (IsBABStore) {
1100811007
// Prior to HLSL 2018, Store operation only stored scalar uint.
1100911008
if (!Is2018) {
@@ -12277,9 +12276,78 @@ static bool CheckVKBufferPointerCast(Sema &S, FunctionDecl *FD, CallExpr *CE,
1227712276
}
1227812277
#endif
1227912278

12279+
static bool isRelatedDeclMarkedNointerpolation(Expr *E) {
12280+
if (!E)
12281+
return false;
12282+
E = E->IgnoreCasts();
12283+
if (auto *DRE = dyn_cast<DeclRefExpr>(E))
12284+
return DRE->getDecl()->hasAttr<HLSLNoInterpolationAttr>();
12285+
12286+
if (auto *ME = dyn_cast<MemberExpr>(E))
12287+
return ME->getMemberDecl()->hasAttr<HLSLNoInterpolationAttr>() ||
12288+
isRelatedDeclMarkedNointerpolation(ME->getBase());
12289+
12290+
if (auto *HVE = dyn_cast<HLSLVectorElementExpr>(E))
12291+
return isRelatedDeclMarkedNointerpolation(HVE->getBase());
12292+
12293+
if (auto *ASE = dyn_cast<ArraySubscriptExpr>(E))
12294+
return isRelatedDeclMarkedNointerpolation(ASE->getBase());
12295+
12296+
return false;
12297+
}
12298+
12299+
static bool CheckIntrinsicGetAttributeAtVertex(Sema &S, FunctionDecl *FDecl,
12300+
CallExpr *TheCall) {
12301+
assert(TheCall->getNumArgs() > 0);
12302+
auto argument = TheCall->getArg(0)->IgnoreCasts();
12303+
12304+
if (!isRelatedDeclMarkedNointerpolation(argument)) {
12305+
S.Diag(argument->getExprLoc(), diag::err_hlsl_parameter_requires_attribute)
12306+
<< 0 << FDecl->getName() << "nointerpolation";
12307+
return true;
12308+
}
12309+
12310+
return false;
12311+
}
12312+
12313+
static bool CheckNoInterpolationParams(Sema &S, FunctionDecl *FDecl,
12314+
CallExpr *TheCall) {
12315+
// See #hlsl-specs/issues/181. Feature is broken. For SPIR-V we want
12316+
// to limit the scope, and fail gracefully in some cases.
12317+
if (!S.getLangOpts().SPIRV)
12318+
return false;
12319+
12320+
bool error = false;
12321+
for (unsigned i = 0; i < FDecl->getNumParams(); i++) {
12322+
assert(i < TheCall->getNumArgs());
12323+
12324+
if (!FDecl->getParamDecl(i)->hasAttr<HLSLNoInterpolationAttr>())
12325+
continue;
12326+
12327+
if (!isRelatedDeclMarkedNointerpolation(TheCall->getArg(i))) {
12328+
S.Diag(TheCall->getArg(i)->getExprLoc(),
12329+
diag::err_hlsl_parameter_requires_attribute)
12330+
<< i << FDecl->getName() << "nointerpolation";
12331+
error = true;
12332+
}
12333+
}
12334+
12335+
return error;
12336+
}
12337+
12338+
// Verify that user-defined intrinsic struct args contain no long vectors
12339+
static bool CheckUDTIntrinsicArg(Sema &S, Expr *Arg) {
12340+
const TypeDiagContext DiagContext =
12341+
TypeDiagContext::UserDefinedStructParameter;
12342+
return DiagnoseTypeElements(S, Arg->getExprLoc(), Arg->getType(), DiagContext,
12343+
DiagContext);
12344+
}
12345+
1228012346
// Check HLSL call constraints, not fatal to creating the AST.
12281-
void Sema::CheckHLSLFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
12282-
const FunctionProtoType *Proto) {
12347+
void Sema::CheckHLSLFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
12348+
if (CheckNoInterpolationParams(*this, FDecl, TheCall))
12349+
return;
12350+
1228312351
HLSLIntrinsicAttr *IntrinsicAttr = FDecl->getAttr<HLSLIntrinsicAttr>();
1228412352
if (!IntrinsicAttr)
1228512353
return;
@@ -12307,6 +12375,28 @@ void Sema::CheckHLSLFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
1230712375
case hlsl::IntrinsicOp::IOP___builtin_OuterProductAccumulate:
1230812376
CheckOuterProductAccumulateCall(*this, FDecl, TheCall);
1230912377
break;
12378+
case hlsl::IntrinsicOp::IOP_GetAttributeAtVertex:
12379+
// See #hlsl-specs/issues/181. Feature is broken. For SPIR-V we want
12380+
// to limit the scope, and fail gracefully in some cases.
12381+
if (!getLangOpts().SPIRV)
12382+
return;
12383+
CheckIntrinsicGetAttributeAtVertex(*this, FDecl, TheCall);
12384+
break;
12385+
case hlsl::IntrinsicOp::IOP_DispatchMesh:
12386+
CheckUDTIntrinsicArg(*this, TheCall->getArg(3)->IgnoreCasts());
12387+
break;
12388+
case hlsl::IntrinsicOp::IOP_CallShader:
12389+
CheckUDTIntrinsicArg(*this, TheCall->getArg(1)->IgnoreCasts());
12390+
break;
12391+
case hlsl::IntrinsicOp::IOP_TraceRay:
12392+
CheckUDTIntrinsicArg(*this, TheCall->getArg(7)->IgnoreCasts());
12393+
break;
12394+
case hlsl::IntrinsicOp::IOP_ReportHit:
12395+
CheckIntersectionAttributeArg(*this, TheCall->getArg(2)->IgnoreCasts());
12396+
break;
12397+
case hlsl::IntrinsicOp::MOP_DxHitObject_GetAttributes:
12398+
CheckIntersectionAttributeArg(*this, TheCall->getArg(0)->IgnoreCasts());
12399+
break;
1231012400
#ifdef ENABLE_SPIRV_CODEGEN
1231112401
case hlsl::IntrinsicOp::IOP_Vkreinterpret_pointer_cast:
1231212402
CheckVKBufferPointerCast(*this, FDecl, TheCall, false);
@@ -16841,118 +16931,6 @@ QualType Sema::getHLSLDefaultSpecialization(TemplateDecl *Decl) {
1684116931
return QualType();
1684216932
}
1684316933

16844-
static bool isRelatedDeclMarkedNointerpolation(Expr *E) {
16845-
if (!E)
16846-
return false;
16847-
E = E->IgnoreCasts();
16848-
if (auto *DRE = dyn_cast<DeclRefExpr>(E))
16849-
return DRE->getDecl()->hasAttr<HLSLNoInterpolationAttr>();
16850-
16851-
if (auto *ME = dyn_cast<MemberExpr>(E))
16852-
return ME->getMemberDecl()->hasAttr<HLSLNoInterpolationAttr>() ||
16853-
isRelatedDeclMarkedNointerpolation(ME->getBase());
16854-
16855-
if (auto *HVE = dyn_cast<HLSLVectorElementExpr>(E))
16856-
return isRelatedDeclMarkedNointerpolation(HVE->getBase());
16857-
16858-
if (auto *ASE = dyn_cast<ArraySubscriptExpr>(E))
16859-
return isRelatedDeclMarkedNointerpolation(ASE->getBase());
16860-
16861-
return false;
16862-
}
16863-
16864-
// Verify that user-defined intrinsic struct args contain no long vectors
16865-
static bool CheckUDTIntrinsicArg(Sema *S, Expr *Arg) {
16866-
const TypeDiagContext DiagContext =
16867-
TypeDiagContext::UserDefinedStructParameter;
16868-
return DiagnoseTypeElements(*S, Arg->getExprLoc(), Arg->getType(),
16869-
DiagContext, DiagContext);
16870-
}
16871-
16872-
static bool CheckIntrinsicGetAttributeAtVertex(Sema *S, FunctionDecl *FDecl,
16873-
CallExpr *TheCall) {
16874-
assert(TheCall->getNumArgs() > 0);
16875-
auto argument = TheCall->getArg(0)->IgnoreCasts();
16876-
16877-
if (!isRelatedDeclMarkedNointerpolation(argument)) {
16878-
S->Diag(argument->getExprLoc(), diag::err_hlsl_parameter_requires_attribute)
16879-
<< 0 << FDecl->getName() << "nointerpolation";
16880-
return true;
16881-
}
16882-
16883-
return false;
16884-
}
16885-
16886-
bool Sema::CheckHLSLIntrinsicCall(FunctionDecl *FDecl, CallExpr *TheCall) {
16887-
auto attr = FDecl->getAttr<HLSLIntrinsicAttr>();
16888-
16889-
if (!attr)
16890-
return false;
16891-
16892-
if (!IsBuiltinTable(attr->getGroup()))
16893-
return false;
16894-
16895-
switch (hlsl::IntrinsicOp(attr->getOpcode())) {
16896-
case hlsl::IntrinsicOp::IOP_GetAttributeAtVertex:
16897-
// See #hlsl-specs/issues/181. Feature is broken. For SPIR-V we want
16898-
// to limit the scope, and fail gracefully in some cases.
16899-
if (!getLangOpts().SPIRV)
16900-
return false;
16901-
// This should never happen for SPIR-V. But on the DXIL side, extension can
16902-
// be added by inserting new intrinsics, meaning opcodes can collide with
16903-
// existing ones. See the ExtensionTest.EvalAttributeCollision test.
16904-
assert(FDecl->getName() == "GetAttributeAtVertex");
16905-
return CheckIntrinsicGetAttributeAtVertex(this, FDecl, TheCall);
16906-
case hlsl::IntrinsicOp::IOP_DispatchMesh:
16907-
assert(TheCall->getNumArgs() > 3);
16908-
assert(FDecl->getName() == "DispatchMesh");
16909-
return CheckUDTIntrinsicArg(this, TheCall->getArg(3)->IgnoreCasts());
16910-
case hlsl::IntrinsicOp::IOP_CallShader:
16911-
assert(TheCall->getNumArgs() > 1);
16912-
assert(FDecl->getName() == "CallShader");
16913-
return CheckUDTIntrinsicArg(this, TheCall->getArg(1)->IgnoreCasts());
16914-
case hlsl::IntrinsicOp::IOP_TraceRay:
16915-
assert(TheCall->getNumArgs() > 7);
16916-
assert(FDecl->getName() == "TraceRay");
16917-
return CheckUDTIntrinsicArg(this, TheCall->getArg(7)->IgnoreCasts());
16918-
case hlsl::IntrinsicOp::IOP_ReportHit:
16919-
assert(TheCall->getNumArgs() > 2);
16920-
assert(FDecl->getName() == "ReportHit");
16921-
return CheckUDTIntrinsicArg(this, TheCall->getArg(2)->IgnoreCasts());
16922-
default:
16923-
break;
16924-
}
16925-
16926-
return false;
16927-
}
16928-
16929-
bool Sema::CheckHLSLFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
16930-
if (hlsl::IsIntrinsicOp(FDecl) && CheckHLSLIntrinsicCall(FDecl, TheCall))
16931-
return true;
16932-
16933-
// See #hlsl-specs/issues/181. Feature is broken. For SPIR-V we want
16934-
// to limit the scope, and fail gracefully in some cases.
16935-
if (!getLangOpts().SPIRV)
16936-
return false;
16937-
16938-
bool error = false;
16939-
for (unsigned i = 0; i < FDecl->getNumParams(); i++) {
16940-
assert(i < TheCall->getNumArgs());
16941-
16942-
if (!FDecl->getParamDecl(i)->hasAttr<HLSLNoInterpolationAttr>())
16943-
continue;
16944-
16945-
if (!isRelatedDeclMarkedNointerpolation(TheCall->getArg(i))) {
16946-
Diag(TheCall->getArg(i)->getExprLoc(),
16947-
diag::err_hlsl_parameter_requires_attribute)
16948-
<< i << FDecl->getName() << "nointerpolation";
16949-
error = true;
16950-
}
16951-
}
16952-
16953-
return error;
16954-
}
16955-
1695616934
namespace hlsl {
1695716935

1695816936
static bool nodeInputIsCompatible(DXIL::NodeIOKind IOType,

tools/clang/test/CodeGenDXIL/hlsl/objects/HitObject/hitobject_attributes.hlsl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ CustomAttrs {
2020
[shader("raygeneration")]
2121
void main() {
2222
dx::HitObject hit;
23-
CustomAttrs attrs = hit.GetAttributes<CustomAttrs>();
23+
CustomAttrs attrs;
24+
hit.GetAttributes(attrs);
2425
float sum = attrs.v.x + attrs.v.y + attrs.v.z + attrs.v.w + attrs.y;
2526
outbuf.Store(0, sum);
2627
}

0 commit comments

Comments
 (0)