Skip to content

Commit

Permalink
[HLSL] Make HLSLAttributedResourceType canonical and add code paths t…
Browse files Browse the repository at this point in the history
…o convert HLSL types to DirectX target types (llvm#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 llvm#95952 (part 2/2)
  • Loading branch information
hekota authored and DanielCChen committed Oct 16, 2024
1 parent 0272925 commit 19834fd
Show file tree
Hide file tree
Showing 28 changed files with 277 additions and 85 deletions.
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

0 comments on commit 19834fd

Please sign in to comment.