Skip to content

[HLSL] Make HLSLAttributedResourceType canonical and add code paths to convert HLSL types to DirectX target types #110327

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 23 additions & 11 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -2662,6 +2662,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
#include "clang/Basic/HLSLIntangibleTypes.def"
bool isHLSLSpecificType() const; // Any HLSL specific type
bool isHLSLIntangibleType() const; // Any HLSL intangible type
bool isHLSLAttributedResourceType() const;

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

Attributes() : Attributes(llvm::dxil::ResourceClass::UAV, false, false) {}

friend bool operator==(const Attributes &LHS, const Attributes &RHS) {
return std::tie(LHS.ResourceClass, LHS.IsROV, LHS.RawBuffer) ==
std::tie(RHS.ResourceClass, RHS.IsROV, RHS.RawBuffer);
}
friend bool operator!=(const Attributes &LHS, const Attributes &RHS) {
return !(LHS == RHS);
}
};

private:
Expand All @@ -6279,20 +6288,21 @@ class HLSLAttributedResourceType : public Type, public llvm::FoldingSetNode {
QualType ContainedType;
const Attributes Attrs;

HLSLAttributedResourceType(QualType Canon, QualType Wrapped,
QualType Contained, const Attributes &Attrs)
: Type(HLSLAttributedResource, Canon,
HLSLAttributedResourceType(QualType Wrapped, QualType Contained,
const Attributes &Attrs)
: Type(HLSLAttributedResource, QualType(),
Contained.isNull() ? TypeDependence::None
: Contained->getDependence()),
WrappedType(Wrapped), ContainedType(Contained), Attrs(Attrs) {}

public:
QualType getWrappedType() const { return WrappedType; }
QualType getContainedType() const { return ContainedType; }
bool hasContainedType() const { return !ContainedType.isNull(); }
const Attributes &getAttrs() const { return Attrs; }

bool isSugared() const { return true; }
QualType desugar() const { return getWrappedType(); }
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }

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

inline bool Type::isHLSLSpecificType() const {
inline bool Type::isHLSLIntangibleType() const {
#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) is##Id##Type() ||
return
#include "clang/Basic/HLSLIntangibleTypes.def"
false; // end boolean or operation
isHLSLAttributedResourceType();
}

inline bool Type::isHLSLIntangibleType() const {
// All HLSL specific types are currently intangible type as well, but that
// might change in the future.
return isHLSLSpecificType();
inline bool Type::isHLSLSpecificType() const {
return isHLSLIntangibleType() || isa<HLSLAttributedResourceType>(this);
}

inline bool Type::isHLSLAttributedResourceType() const {
return isa<HLSLAttributedResourceType>(this);
}

inline bool Type::isTemplateTypeParmType() const {
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/TypeNodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ def EnumType : TypeNode<TagType>, LeafType;
def ElaboratedType : TypeNode<Type>, NeverCanonical;
def AttributedType : TypeNode<Type>, NeverCanonical;
def BTFTagAttributedType : TypeNode<Type>, NeverCanonical;
def HLSLAttributedResourceType : TypeNode<Type>, NeverCanonical;
def HLSLAttributedResourceType : TypeNode<Type>;
def TemplateTypeParmType : TypeNode<Type>, AlwaysDependent, LeafType;
def SubstTemplateTypeParmType : TypeNode<Type>, NeverCanonical;
def SubstTemplateTypeParmPackType : TypeNode<Type>, AlwaysDependent;
Expand Down
25 changes: 23 additions & 2 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3437,6 +3437,9 @@ static void encodeTypeForFunctionPointerAuth(const ASTContext &Ctx,
OS << II->getLength() << II->getName();
return;
}
case Type::HLSLAttributedResource:
llvm_unreachable("should never get here");
break;
case Type::DeducedTemplateSpecialization:
case Type::Auto:
#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
Expand Down Expand Up @@ -4108,6 +4111,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const {
case Type::BitInt:
case Type::DependentBitInt:
case Type::ArrayParameter:
case Type::HLSLAttributedResource:
llvm_unreachable("type should never be variably-modified");

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

QualType Canon = getCanonicalType(Wrapped);
Ty = new (*this, alignof(HLSLAttributedResourceType))
HLSLAttributedResourceType(Canon, Wrapped, Contained, Attrs);
HLSLAttributedResourceType(Wrapped, Contained, Attrs);

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

case Type::HLSLAttributedResource:
llvm_unreachable("unexpected type");

case Type::ArrayParameter:
case Type::Pipe:
#define ABSTRACT_TYPE(KIND, BASE)
Expand Down Expand Up @@ -11533,6 +11539,20 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, bool OfBlockPointer,
return {};
return LHS;
}
case Type::HLSLAttributedResource: {
const HLSLAttributedResourceType *LHSTy =
LHS->castAs<HLSLAttributedResourceType>();
const HLSLAttributedResourceType *RHSTy =
RHS->castAs<HLSLAttributedResourceType>();
assert(LHSTy->getWrappedType() == RHSTy->getWrappedType() &&
LHSTy->getWrappedType()->isHLSLResourceType() &&
"HLSLAttributedResourceType should always wrap __hlsl_resource_t");

if (LHSTy->getAttrs() == RHSTy->getAttrs() &&
LHSTy->getContainedType() == RHSTy->getContainedType())
return LHS;
return {};
}
}

llvm_unreachable("Invalid Type::Class!");
Expand Down Expand Up @@ -13368,6 +13388,7 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X,
SUGAR_FREE_TYPE(Record)
SUGAR_FREE_TYPE(SubstTemplateTypeParmPack)
SUGAR_FREE_TYPE(UnresolvedUsing)
SUGAR_FREE_TYPE(HLSLAttributedResource)
#undef SUGAR_FREE_TYPE
#define NON_UNIQUE_TYPE(Class) UNEXPECTED_TYPE(Class, "non-unique")
NON_UNIQUE_TYPE(TypeOfExpr)
Expand Down
15 changes: 2 additions & 13 deletions clang/lib/AST/ASTStructuralEquivalence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -802,16 +802,6 @@ static bool IsEquivalentExceptionSpec(StructuralEquivalenceContext &Context,
return true;
}

// Determine structural equivalence of two instances of
// HLSLAttributedResourceType::Attributes
static bool
IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
const HLSLAttributedResourceType::Attributes &Attrs1,
const HLSLAttributedResourceType::Attributes &Attrs2) {
return std::tie(Attrs1.ResourceClass, Attrs1.IsROV, Attrs1.RawBuffer) ==
std::tie(Attrs2.ResourceClass, Attrs2.IsROV, Attrs2.RawBuffer);
}

/// Determine structural equivalence of two types.
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
QualType T1, QualType T2) {
Expand Down Expand Up @@ -1115,9 +1105,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
Context, cast<HLSLAttributedResourceType>(T1)->getContainedType(),
cast<HLSLAttributedResourceType>(T2)->getContainedType()))
return false;
if (!IsStructurallyEquivalent(
Context, cast<HLSLAttributedResourceType>(T1)->getAttrs(),
cast<HLSLAttributedResourceType>(T2)->getAttrs()))
if (cast<HLSLAttributedResourceType>(T1)->getAttrs() !=
cast<HLSLAttributedResourceType>(T2)->getAttrs())
return false;
break;

Expand Down
6 changes: 3 additions & 3 deletions clang/lib/AST/DeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1411,10 +1411,10 @@ void CXXRecordDecl::addedMember(Decl *D) {
Ty = Ty->getArrayElementTypeNoTypeQual();

Ty = Ty->getUnqualifiedDesugaredType();
if (Ty->isBuiltinType())
data().IsHLSLIntangible |= Ty->isHLSLIntangibleType();
else if (const RecordType *RT = dyn_cast<RecordType>(Ty))
if (const RecordType *RT = dyn_cast<RecordType>(Ty))
data().IsHLSLIntangible |= RT->getAsCXXRecordDecl()->isHLSLIntangible();
else
data().IsHLSLIntangible |= Ty->isHLSLIntangibleType();
}
}

Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12167,6 +12167,7 @@ GCCTypeClass EvaluateBuiltinClassifyType(QualType T,
case Type::ObjCInterface:
case Type::ObjCObjectPointer:
case Type::Pipe:
case Type::HLSLAttributedResource:
// Classify all other types that don't fit into the regular
// classification the same way.
return GCCTypeClass::None;
Expand Down
32 changes: 32 additions & 0 deletions clang/lib/AST/ItaniumMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4512,6 +4512,38 @@ void CXXNameMangler::mangleType(const ArrayParameterType *T) {
mangleType(cast<ConstantArrayType>(T));
}

void CXXNameMangler::mangleType(const HLSLAttributedResourceType *T) {
llvm::SmallString<64> Str("_Res");
const HLSLAttributedResourceType::Attributes &Attrs = T->getAttrs();
// map resource class to HLSL virtual register letter
switch (Attrs.ResourceClass) {
case llvm::dxil::ResourceClass::UAV:
Str += "_u";
break;
case llvm::dxil::ResourceClass::SRV:
Str += "_t";
break;
case llvm::dxil::ResourceClass::CBuffer:
Str += "_b";
break;
case llvm::dxil::ResourceClass::Sampler:
Str += "_s";
break;
}
if (Attrs.IsROV)
Str += "_ROV";
if (Attrs.RawBuffer)
Str += "_Raw";
if (T->hasContainedType())
Str += "_CT";
mangleVendorQualifier(Str);

if (T->hasContainedType()) {
mangleType(T->getContainedType());
}
mangleType(T->getWrappedType());
}

void CXXNameMangler::mangleIntegerLiteral(QualType T,
const llvm::APSInt &Value) {
// <expr-primary> ::= L <type> <value number> E # integer literal
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/AST/MicrosoftMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3754,6 +3754,11 @@ void MicrosoftCXXNameMangler::mangleType(const DependentBitIntType *T,
Error(Range.getBegin(), "DependentBitInt type") << Range;
}

void MicrosoftCXXNameMangler::mangleType(const HLSLAttributedResourceType *T,
Qualifiers, SourceRange Range) {
llvm_unreachable("HLSL uses Itanium name mangling");
}

// <this-adjustment> ::= <no-adjustment> | <static-adjustment> |
// <virtual-adjustment>
// <no-adjustment> ::= A # private near
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4575,6 +4575,8 @@ static CachedProperties computeCachedProperties(const Type *T) {
return Cache::get(cast<AtomicType>(T)->getValueType());
case Type::Pipe:
return Cache::get(cast<PipeType>(T)->getElementType());
case Type::HLSLAttributedResource:
return Cache::get(cast<HLSLAttributedResourceType>(T)->getWrappedType());
}

llvm_unreachable("unhandled type class");
Expand Down Expand Up @@ -4664,6 +4666,8 @@ LinkageInfo LinkageComputer::computeTypeLinkageInfo(const Type *T) {
return computeTypeLinkageInfo(cast<AtomicType>(T)->getValueType());
case Type::Pipe:
return computeTypeLinkageInfo(cast<PipeType>(T)->getElementType());
case Type::HLSLAttributedResource:
llvm_unreachable("not yet implemented");
}

llvm_unreachable("unhandled type class");
Expand Down Expand Up @@ -4846,6 +4850,7 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const {
case Type::BitInt:
case Type::DependentBitInt:
case Type::ArrayParameter:
case Type::HLSLAttributedResource:
return false;
}
llvm_unreachable("bad type kind!");
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ TypeEvaluationKind CodeGenFunction::getEvaluationKind(QualType type) {
case Type::ObjCObjectPointer:
case Type::Pipe:
case Type::BitInt:
case Type::HLSLAttributedResource:
return TEK_Scalar;

// Complexes.
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/CodeGen/CodeGenTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,9 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
ResultType = llvm::Type::getIntNTy(getLLVMContext(), EIT->getNumBits());
break;
}
case Type::HLSLAttributedResource:
ResultType = CGM.getHLSLRuntime().convertHLSLSpecificType(Ty);
break;
}

assert(ResultType && "Didn't convert a type?");
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/CodeGen/ItaniumCXXABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3947,6 +3947,9 @@ void ItaniumRTTIBuilder::BuildVTablePointer(const Type *Ty) {
// abi::__pointer_to_member_type_info.
VTableName = "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE";
break;

case Type::HLSLAttributedResource:
llvm_unreachable("HLSL doesn't support virtual functions");
}

llvm::Constant *VTable = nullptr;
Expand Down Expand Up @@ -4209,6 +4212,9 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(
case Type::Atomic:
// No fields, at least for the moment.
break;

case Type::HLSLAttributedResource:
llvm_unreachable("HLSL doesn't support RTTI");
}

llvm::Constant *Init = llvm::ConstantStruct::getAnon(Fields);
Expand Down
41 changes: 31 additions & 10 deletions clang/lib/CodeGen/Targets/DirectX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,40 @@ class DirectXTargetCodeGenInfo : public TargetCodeGenInfo {

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

llvm::LLVMContext &Ctx = CGM.getLLVMContext();
// FIXME: translate __hlsl_resource_t to target("dx.TypedBuffer", <4 x float>,
// 1, 0, 0) only for now (RWBuffer<float4>); more work us needed to determine
// the target ext type and its parameters based on the handle type
// attributes (not yet implemented)
llvm::FixedVectorType *ElemType =
llvm::FixedVectorType::get(llvm::Type::getFloatTy(Ctx), 4);
unsigned Flags[] = {/*IsWriteable*/ 1, /*IsROV*/ 0, /*IsSigned*/ 0};
return llvm::TargetExtType::get(Ctx, "dx.TypedBuffer", {ElemType}, Flags);
const HLSLAttributedResourceType::Attributes &ResAttrs = ResType->getAttrs();
switch (ResAttrs.ResourceClass) {
case llvm::dxil::ResourceClass::UAV:
case llvm::dxil::ResourceClass::SRV: {
// TypedBuffer and RawBuffer both need element type
QualType ContainedTy = ResType->getContainedType();
if (ContainedTy.isNull())
return nullptr;

// convert element type
llvm::Type *ElemType = CGM.getTypes().ConvertType(ContainedTy);

llvm::StringRef TypeName =
ResAttrs.RawBuffer ? "dx.RawBuffer" : "dx.TypedBuffer";
SmallVector<unsigned, 3> Ints = {/*IsWriteable*/ ResAttrs.ResourceClass ==
llvm::dxil::ResourceClass::UAV,
/*IsROV*/ ResAttrs.IsROV};
if (!ResAttrs.RawBuffer)
Ints.push_back(/*IsSigned*/ ContainedTy->isSignedIntegerType());

return llvm::TargetExtType::get(Ctx, TypeName, {ElemType}, Ints);
}
case llvm::dxil::ResourceClass::CBuffer:
llvm_unreachable("dx.CBuffer handles are not implemented yet");
break;
case llvm::dxil::ResourceClass::Sampler:
llvm_unreachable("dx.Sampler handles are not implemented yet");
break;
}
}

} // namespace
Expand Down
2 changes: 0 additions & 2 deletions clang/lib/Sema/HLSLExternalSemaSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,6 @@ struct BuiltinTypeDeclBuilder {
BuiltinTypeDeclBuilder &addArraySubscriptOperator(bool IsConst) {
if (Record->isCompleteDefinition())
return *this;
assert(Fields.count("h") > 0 &&
"Subscript operator must be added after the handle.");

ASTContext &AST = Record->getASTContext();
QualType ElemTy = AST.Char8Ty;
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Sema/SemaLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3215,6 +3215,9 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) {
// Array parameter types are treated as fundamental types.
case Type::ArrayParameter:
break;

case Type::HLSLAttributedResource:
T = cast<HLSLAttributedResourceType>(T)->getWrappedType().getTypePtr();
}

if (Queue.empty())
Expand Down
Loading