Skip to content

Commit 3b45120

Browse files
authored
[HLSL] Make HLSLAttributedResourceType canonical and add code paths to convert HLSL types to DirectX target types (#110327)
Translates `RWBuffer` and `StructuredBuffer` resources buffer types to DirectX target types `dx.TypedBuffer` and `dx.RawBuffer`. Includes a change of `HLSLAttributesResourceType` from 'sugar' type to full canonical type. This is required for codegen and other clang infrastructure to work property on HLSL resource types. Fixes #95952 (part 2/2)
1 parent 97da5e6 commit 3b45120

28 files changed

+277
-85
lines changed

clang/include/clang/AST/Type.h

+23-11
Original file line numberDiff line numberDiff line change
@@ -2662,6 +2662,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
26622662
#include "clang/Basic/HLSLIntangibleTypes.def"
26632663
bool isHLSLSpecificType() const; // Any HLSL specific type
26642664
bool isHLSLIntangibleType() const; // Any HLSL intangible type
2665+
bool isHLSLAttributedResourceType() const;
26652666

26662667
/// Determines if this type, which must satisfy
26672668
/// isObjCLifetimeType(), is implicitly __unsafe_unretained rather
@@ -6270,6 +6271,14 @@ class HLSLAttributedResourceType : public Type, public llvm::FoldingSetNode {
62706271
: ResourceClass(ResourceClass), IsROV(IsROV), RawBuffer(RawBuffer) {}
62716272

62726273
Attributes() : Attributes(llvm::dxil::ResourceClass::UAV, false, false) {}
6274+
6275+
friend bool operator==(const Attributes &LHS, const Attributes &RHS) {
6276+
return std::tie(LHS.ResourceClass, LHS.IsROV, LHS.RawBuffer) ==
6277+
std::tie(RHS.ResourceClass, RHS.IsROV, RHS.RawBuffer);
6278+
}
6279+
friend bool operator!=(const Attributes &LHS, const Attributes &RHS) {
6280+
return !(LHS == RHS);
6281+
}
62736282
};
62746283

62756284
private:
@@ -6279,20 +6288,21 @@ class HLSLAttributedResourceType : public Type, public llvm::FoldingSetNode {
62796288
QualType ContainedType;
62806289
const Attributes Attrs;
62816290

6282-
HLSLAttributedResourceType(QualType Canon, QualType Wrapped,
6283-
QualType Contained, const Attributes &Attrs)
6284-
: Type(HLSLAttributedResource, Canon,
6291+
HLSLAttributedResourceType(QualType Wrapped, QualType Contained,
6292+
const Attributes &Attrs)
6293+
: Type(HLSLAttributedResource, QualType(),
62856294
Contained.isNull() ? TypeDependence::None
62866295
: Contained->getDependence()),
62876296
WrappedType(Wrapped), ContainedType(Contained), Attrs(Attrs) {}
62886297

62896298
public:
62906299
QualType getWrappedType() const { return WrappedType; }
62916300
QualType getContainedType() const { return ContainedType; }
6301+
bool hasContainedType() const { return !ContainedType.isNull(); }
62926302
const Attributes &getAttrs() const { return Attrs; }
62936303

6294-
bool isSugared() const { return true; }
6295-
QualType desugar() const { return getWrappedType(); }
6304+
bool isSugared() const { return false; }
6305+
QualType desugar() const { return QualType(this, 0); }
62966306

62976307
void Profile(llvm::FoldingSetNodeID &ID) {
62986308
Profile(ID, WrappedType, ContainedType, Attrs);
@@ -8436,17 +8446,19 @@ inline bool Type::isOpenCLSpecificType() const {
84368446
}
84378447
#include "clang/Basic/HLSLIntangibleTypes.def"
84388448

8439-
inline bool Type::isHLSLSpecificType() const {
8449+
inline bool Type::isHLSLIntangibleType() const {
84408450
#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) is##Id##Type() ||
84418451
return
84428452
#include "clang/Basic/HLSLIntangibleTypes.def"
8443-
false; // end boolean or operation
8453+
isHLSLAttributedResourceType();
84448454
}
84458455

8446-
inline bool Type::isHLSLIntangibleType() const {
8447-
// All HLSL specific types are currently intangible type as well, but that
8448-
// might change in the future.
8449-
return isHLSLSpecificType();
8456+
inline bool Type::isHLSLSpecificType() const {
8457+
return isHLSLIntangibleType() || isa<HLSLAttributedResourceType>(this);
8458+
}
8459+
8460+
inline bool Type::isHLSLAttributedResourceType() const {
8461+
return isa<HLSLAttributedResourceType>(this);
84508462
}
84518463

84528464
inline bool Type::isTemplateTypeParmType() const {

clang/include/clang/Basic/TypeNodes.td

+1-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ def EnumType : TypeNode<TagType>, LeafType;
9393
def ElaboratedType : TypeNode<Type>, NeverCanonical;
9494
def AttributedType : TypeNode<Type>, NeverCanonical;
9595
def BTFTagAttributedType : TypeNode<Type>, NeverCanonical;
96-
def HLSLAttributedResourceType : TypeNode<Type>, NeverCanonical;
96+
def HLSLAttributedResourceType : TypeNode<Type>;
9797
def TemplateTypeParmType : TypeNode<Type>, AlwaysDependent, LeafType;
9898
def SubstTemplateTypeParmType : TypeNode<Type>, NeverCanonical;
9999
def SubstTemplateTypeParmPackType : TypeNode<Type>, AlwaysDependent;

clang/lib/AST/ASTContext.cpp

+23-2
Original file line numberDiff line numberDiff line change
@@ -3437,6 +3437,9 @@ static void encodeTypeForFunctionPointerAuth(const ASTContext &Ctx,
34373437
OS << II->getLength() << II->getName();
34383438
return;
34393439
}
3440+
case Type::HLSLAttributedResource:
3441+
llvm_unreachable("should never get here");
3442+
break;
34403443
case Type::DeducedTemplateSpecialization:
34413444
case Type::Auto:
34423445
#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
@@ -4108,6 +4111,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const {
41084111
case Type::BitInt:
41094112
case Type::DependentBitInt:
41104113
case Type::ArrayParameter:
4114+
case Type::HLSLAttributedResource:
41114115
llvm_unreachable("type should never be variably-modified");
41124116

41134117
// These types can be variably-modified but should never need to
@@ -5233,9 +5237,8 @@ QualType ASTContext::getHLSLAttributedResourceType(
52335237
if (Ty)
52345238
return QualType(Ty, 0);
52355239

5236-
QualType Canon = getCanonicalType(Wrapped);
52375240
Ty = new (*this, alignof(HLSLAttributedResourceType))
5238-
HLSLAttributedResourceType(Canon, Wrapped, Contained, Attrs);
5241+
HLSLAttributedResourceType(Wrapped, Contained, Attrs);
52395242

52405243
Types.push_back(Ty);
52415244
HLSLAttributedResourceTypes.InsertNode(Ty, InsertPos);
@@ -9106,6 +9109,9 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S,
91069109
case Type::DeducedTemplateSpecialization:
91079110
return;
91089111

9112+
case Type::HLSLAttributedResource:
9113+
llvm_unreachable("unexpected type");
9114+
91099115
case Type::ArrayParameter:
91109116
case Type::Pipe:
91119117
#define ABSTRACT_TYPE(KIND, BASE)
@@ -11533,6 +11539,20 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, bool OfBlockPointer,
1153311539
return {};
1153411540
return LHS;
1153511541
}
11542+
case Type::HLSLAttributedResource: {
11543+
const HLSLAttributedResourceType *LHSTy =
11544+
LHS->castAs<HLSLAttributedResourceType>();
11545+
const HLSLAttributedResourceType *RHSTy =
11546+
RHS->castAs<HLSLAttributedResourceType>();
11547+
assert(LHSTy->getWrappedType() == RHSTy->getWrappedType() &&
11548+
LHSTy->getWrappedType()->isHLSLResourceType() &&
11549+
"HLSLAttributedResourceType should always wrap __hlsl_resource_t");
11550+
11551+
if (LHSTy->getAttrs() == RHSTy->getAttrs() &&
11552+
LHSTy->getContainedType() == RHSTy->getContainedType())
11553+
return LHS;
11554+
return {};
11555+
}
1153611556
}
1153711557

1153811558
llvm_unreachable("Invalid Type::Class!");
@@ -13368,6 +13388,7 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X,
1336813388
SUGAR_FREE_TYPE(Record)
1336913389
SUGAR_FREE_TYPE(SubstTemplateTypeParmPack)
1337013390
SUGAR_FREE_TYPE(UnresolvedUsing)
13391+
SUGAR_FREE_TYPE(HLSLAttributedResource)
1337113392
#undef SUGAR_FREE_TYPE
1337213393
#define NON_UNIQUE_TYPE(Class) UNEXPECTED_TYPE(Class, "non-unique")
1337313394
NON_UNIQUE_TYPE(TypeOfExpr)

clang/lib/AST/ASTStructuralEquivalence.cpp

+2-13
Original file line numberDiff line numberDiff line change
@@ -802,16 +802,6 @@ static bool IsEquivalentExceptionSpec(StructuralEquivalenceContext &Context,
802802
return true;
803803
}
804804

805-
// Determine structural equivalence of two instances of
806-
// HLSLAttributedResourceType::Attributes
807-
static bool
808-
IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
809-
const HLSLAttributedResourceType::Attributes &Attrs1,
810-
const HLSLAttributedResourceType::Attributes &Attrs2) {
811-
return std::tie(Attrs1.ResourceClass, Attrs1.IsROV, Attrs1.RawBuffer) ==
812-
std::tie(Attrs2.ResourceClass, Attrs2.IsROV, Attrs2.RawBuffer);
813-
}
814-
815805
/// Determine structural equivalence of two types.
816806
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
817807
QualType T1, QualType T2) {
@@ -1115,9 +1105,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
11151105
Context, cast<HLSLAttributedResourceType>(T1)->getContainedType(),
11161106
cast<HLSLAttributedResourceType>(T2)->getContainedType()))
11171107
return false;
1118-
if (!IsStructurallyEquivalent(
1119-
Context, cast<HLSLAttributedResourceType>(T1)->getAttrs(),
1120-
cast<HLSLAttributedResourceType>(T2)->getAttrs()))
1108+
if (cast<HLSLAttributedResourceType>(T1)->getAttrs() !=
1109+
cast<HLSLAttributedResourceType>(T2)->getAttrs())
11211110
return false;
11221111
break;
11231112

clang/lib/AST/DeclCXX.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -1411,10 +1411,10 @@ void CXXRecordDecl::addedMember(Decl *D) {
14111411
Ty = Ty->getArrayElementTypeNoTypeQual();
14121412

14131413
Ty = Ty->getUnqualifiedDesugaredType();
1414-
if (Ty->isBuiltinType())
1415-
data().IsHLSLIntangible |= Ty->isHLSLIntangibleType();
1416-
else if (const RecordType *RT = dyn_cast<RecordType>(Ty))
1414+
if (const RecordType *RT = dyn_cast<RecordType>(Ty))
14171415
data().IsHLSLIntangible |= RT->getAsCXXRecordDecl()->isHLSLIntangible();
1416+
else
1417+
data().IsHLSLIntangible |= Ty->isHLSLIntangibleType();
14181418
}
14191419
}
14201420

clang/lib/AST/ExprConstant.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -12167,6 +12167,7 @@ GCCTypeClass EvaluateBuiltinClassifyType(QualType T,
1216712167
case Type::ObjCInterface:
1216812168
case Type::ObjCObjectPointer:
1216912169
case Type::Pipe:
12170+
case Type::HLSLAttributedResource:
1217012171
// Classify all other types that don't fit into the regular
1217112172
// classification the same way.
1217212173
return GCCTypeClass::None;

clang/lib/AST/ItaniumMangle.cpp

+32
Original file line numberDiff line numberDiff line change
@@ -4512,6 +4512,38 @@ void CXXNameMangler::mangleType(const ArrayParameterType *T) {
45124512
mangleType(cast<ConstantArrayType>(T));
45134513
}
45144514

4515+
void CXXNameMangler::mangleType(const HLSLAttributedResourceType *T) {
4516+
llvm::SmallString<64> Str("_Res");
4517+
const HLSLAttributedResourceType::Attributes &Attrs = T->getAttrs();
4518+
// map resource class to HLSL virtual register letter
4519+
switch (Attrs.ResourceClass) {
4520+
case llvm::dxil::ResourceClass::UAV:
4521+
Str += "_u";
4522+
break;
4523+
case llvm::dxil::ResourceClass::SRV:
4524+
Str += "_t";
4525+
break;
4526+
case llvm::dxil::ResourceClass::CBuffer:
4527+
Str += "_b";
4528+
break;
4529+
case llvm::dxil::ResourceClass::Sampler:
4530+
Str += "_s";
4531+
break;
4532+
}
4533+
if (Attrs.IsROV)
4534+
Str += "_ROV";
4535+
if (Attrs.RawBuffer)
4536+
Str += "_Raw";
4537+
if (T->hasContainedType())
4538+
Str += "_CT";
4539+
mangleVendorQualifier(Str);
4540+
4541+
if (T->hasContainedType()) {
4542+
mangleType(T->getContainedType());
4543+
}
4544+
mangleType(T->getWrappedType());
4545+
}
4546+
45154547
void CXXNameMangler::mangleIntegerLiteral(QualType T,
45164548
const llvm::APSInt &Value) {
45174549
// <expr-primary> ::= L <type> <value number> E # integer literal

clang/lib/AST/MicrosoftMangle.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -3754,6 +3754,11 @@ void MicrosoftCXXNameMangler::mangleType(const DependentBitIntType *T,
37543754
Error(Range.getBegin(), "DependentBitInt type") << Range;
37553755
}
37563756

3757+
void MicrosoftCXXNameMangler::mangleType(const HLSLAttributedResourceType *T,
3758+
Qualifiers, SourceRange Range) {
3759+
llvm_unreachable("HLSL uses Itanium name mangling");
3760+
}
3761+
37573762
// <this-adjustment> ::= <no-adjustment> | <static-adjustment> |
37583763
// <virtual-adjustment>
37593764
// <no-adjustment> ::= A # private near

clang/lib/AST/Type.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -4575,6 +4575,8 @@ static CachedProperties computeCachedProperties(const Type *T) {
45754575
return Cache::get(cast<AtomicType>(T)->getValueType());
45764576
case Type::Pipe:
45774577
return Cache::get(cast<PipeType>(T)->getElementType());
4578+
case Type::HLSLAttributedResource:
4579+
return Cache::get(cast<HLSLAttributedResourceType>(T)->getWrappedType());
45784580
}
45794581

45804582
llvm_unreachable("unhandled type class");
@@ -4664,6 +4666,8 @@ LinkageInfo LinkageComputer::computeTypeLinkageInfo(const Type *T) {
46644666
return computeTypeLinkageInfo(cast<AtomicType>(T)->getValueType());
46654667
case Type::Pipe:
46664668
return computeTypeLinkageInfo(cast<PipeType>(T)->getElementType());
4669+
case Type::HLSLAttributedResource:
4670+
llvm_unreachable("not yet implemented");
46674671
}
46684672

46694673
llvm_unreachable("unhandled type class");
@@ -4846,6 +4850,7 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const {
48464850
case Type::BitInt:
48474851
case Type::DependentBitInt:
48484852
case Type::ArrayParameter:
4853+
case Type::HLSLAttributedResource:
48494854
return false;
48504855
}
48514856
llvm_unreachable("bad type kind!");

clang/lib/CodeGen/CodeGenFunction.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@ TypeEvaluationKind CodeGenFunction::getEvaluationKind(QualType type) {
282282
case Type::ObjCObjectPointer:
283283
case Type::Pipe:
284284
case Type::BitInt:
285+
case Type::HLSLAttributedResource:
285286
return TEK_Scalar;
286287

287288
// Complexes.

clang/lib/CodeGen/CodeGenTypes.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,9 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
743743
ResultType = llvm::Type::getIntNTy(getLLVMContext(), EIT->getNumBits());
744744
break;
745745
}
746+
case Type::HLSLAttributedResource:
747+
ResultType = CGM.getHLSLRuntime().convertHLSLSpecificType(Ty);
748+
break;
746749
}
747750

748751
assert(ResultType && "Didn't convert a type?");

clang/lib/CodeGen/ItaniumCXXABI.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -3947,6 +3947,9 @@ void ItaniumRTTIBuilder::BuildVTablePointer(const Type *Ty) {
39473947
// abi::__pointer_to_member_type_info.
39483948
VTableName = "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE";
39493949
break;
3950+
3951+
case Type::HLSLAttributedResource:
3952+
llvm_unreachable("HLSL doesn't support virtual functions");
39503953
}
39513954

39523955
llvm::Constant *VTable = nullptr;
@@ -4209,6 +4212,9 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(
42094212
case Type::Atomic:
42104213
// No fields, at least for the moment.
42114214
break;
4215+
4216+
case Type::HLSLAttributedResource:
4217+
llvm_unreachable("HLSL doesn't support RTTI");
42124218
}
42134219

42144220
llvm::Constant *Init = llvm::ConstantStruct::getAnon(Fields);

clang/lib/CodeGen/Targets/DirectX.cpp

+31-10
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,40 @@ class DirectXTargetCodeGenInfo : public TargetCodeGenInfo {
2929

3030
llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(CodeGenModule &CGM,
3131
const Type *Ty) const {
32-
auto *BuiltinTy = dyn_cast<BuiltinType>(Ty);
33-
if (!BuiltinTy || BuiltinTy->getKind() != BuiltinType::HLSLResource)
32+
auto *ResType = dyn_cast<HLSLAttributedResourceType>(Ty);
33+
if (!ResType)
3434
return nullptr;
3535

3636
llvm::LLVMContext &Ctx = CGM.getLLVMContext();
37-
// FIXME: translate __hlsl_resource_t to target("dx.TypedBuffer", <4 x float>,
38-
// 1, 0, 0) only for now (RWBuffer<float4>); more work us needed to determine
39-
// the target ext type and its parameters based on the handle type
40-
// attributes (not yet implemented)
41-
llvm::FixedVectorType *ElemType =
42-
llvm::FixedVectorType::get(llvm::Type::getFloatTy(Ctx), 4);
43-
unsigned Flags[] = {/*IsWriteable*/ 1, /*IsROV*/ 0, /*IsSigned*/ 0};
44-
return llvm::TargetExtType::get(Ctx, "dx.TypedBuffer", {ElemType}, Flags);
37+
const HLSLAttributedResourceType::Attributes &ResAttrs = ResType->getAttrs();
38+
switch (ResAttrs.ResourceClass) {
39+
case llvm::dxil::ResourceClass::UAV:
40+
case llvm::dxil::ResourceClass::SRV: {
41+
// TypedBuffer and RawBuffer both need element type
42+
QualType ContainedTy = ResType->getContainedType();
43+
if (ContainedTy.isNull())
44+
return nullptr;
45+
46+
// convert element type
47+
llvm::Type *ElemType = CGM.getTypes().ConvertType(ContainedTy);
48+
49+
llvm::StringRef TypeName =
50+
ResAttrs.RawBuffer ? "dx.RawBuffer" : "dx.TypedBuffer";
51+
SmallVector<unsigned, 3> Ints = {/*IsWriteable*/ ResAttrs.ResourceClass ==
52+
llvm::dxil::ResourceClass::UAV,
53+
/*IsROV*/ ResAttrs.IsROV};
54+
if (!ResAttrs.RawBuffer)
55+
Ints.push_back(/*IsSigned*/ ContainedTy->isSignedIntegerType());
56+
57+
return llvm::TargetExtType::get(Ctx, TypeName, {ElemType}, Ints);
58+
}
59+
case llvm::dxil::ResourceClass::CBuffer:
60+
llvm_unreachable("dx.CBuffer handles are not implemented yet");
61+
break;
62+
case llvm::dxil::ResourceClass::Sampler:
63+
llvm_unreachable("dx.Sampler handles are not implemented yet");
64+
break;
65+
}
4566
}
4667

4768
} // namespace

clang/lib/Sema/HLSLExternalSemaSource.cpp

-2
Original file line numberDiff line numberDiff line change
@@ -208,8 +208,6 @@ struct BuiltinTypeDeclBuilder {
208208
BuiltinTypeDeclBuilder &addArraySubscriptOperator(bool IsConst) {
209209
if (Record->isCompleteDefinition())
210210
return *this;
211-
assert(Fields.count("h") > 0 &&
212-
"Subscript operator must be added after the handle.");
213211

214212
ASTContext &AST = Record->getASTContext();
215213
QualType ElemTy = AST.Char8Ty;

clang/lib/Sema/SemaLookup.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -3215,6 +3215,9 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) {
32153215
// Array parameter types are treated as fundamental types.
32163216
case Type::ArrayParameter:
32173217
break;
3218+
3219+
case Type::HLSLAttributedResource:
3220+
T = cast<HLSLAttributedResourceType>(T)->getWrappedType().getTypePtr();
32183221
}
32193222

32203223
if (Queue.empty())

0 commit comments

Comments
 (0)