Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ static bool checkOverridingFunctionReturnType(const ASTContext *Context,

// The class type D should have the same cv-qualification as or less
// cv-qualification than the class type B.
if (DTy.isMoreQualifiedThan(BTy))
if (DTy.isMoreQualifiedThan(BTy, *Context))
return false;

return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -299,10 +299,11 @@ static bool applyDiceHeuristic(StringRef Arg, StringRef Param,

/// Checks if ArgType binds to ParamType regarding reference-ness and
/// cv-qualifiers.
static bool areRefAndQualCompatible(QualType ArgType, QualType ParamType) {
static bool areRefAndQualCompatible(QualType ArgType, QualType ParamType,
const ASTContext &Ctx) {
return !ParamType->isReferenceType() ||
ParamType.getNonReferenceType().isAtLeastAsQualifiedAs(
ArgType.getNonReferenceType());
ArgType.getNonReferenceType(), Ctx);
}

static bool isPointerOrArray(QualType TypeToCheck) {
Expand All @@ -311,12 +312,12 @@ static bool isPointerOrArray(QualType TypeToCheck) {

/// Checks whether ArgType is an array type identical to ParamType's array type.
/// Enforces array elements' qualifier compatibility as well.
static bool isCompatibleWithArrayReference(QualType ArgType,
QualType ParamType) {
static bool isCompatibleWithArrayReference(QualType ArgType, QualType ParamType,
const ASTContext &Ctx) {
if (!ArgType->isArrayType())
return false;
// Here, qualifiers belong to the elements of the arrays.
if (!ParamType.isAtLeastAsQualifiedAs(ArgType))
if (!ParamType.isAtLeastAsQualifiedAs(ArgType, Ctx))
return false;

return ParamType.getUnqualifiedType() == ArgType.getUnqualifiedType();
Expand All @@ -342,12 +343,13 @@ static QualType convertToPointeeOrArrayElementQualType(QualType TypeToConvert) {
/// every * in ParamType to the right of that cv-qualifier, except the last
/// one, must also be const-qualified.
static bool arePointersStillQualCompatible(QualType ArgType, QualType ParamType,
bool &IsParamContinuouslyConst) {
bool &IsParamContinuouslyConst,
const ASTContext &Ctx) {
// The types are compatible, if the parameter is at least as qualified as the
// argument, and if it is more qualified, it has to be const on upper pointer
// levels.
bool AreTypesQualCompatible =
ParamType.isAtLeastAsQualifiedAs(ArgType) &&
ParamType.isAtLeastAsQualifiedAs(ArgType, Ctx) &&
(!ParamType.hasQualifiers() || IsParamContinuouslyConst);
// Check whether the parameter's constness continues at the current pointer
// level.
Expand All @@ -359,9 +361,10 @@ static bool arePointersStillQualCompatible(QualType ArgType, QualType ParamType,
/// Checks whether multilevel pointers are compatible in terms of levels,
/// qualifiers and pointee type.
static bool arePointerTypesCompatible(QualType ArgType, QualType ParamType,
bool IsParamContinuouslyConst) {
bool IsParamContinuouslyConst,
const ASTContext &Ctx) {
if (!arePointersStillQualCompatible(ArgType, ParamType,
IsParamContinuouslyConst))
IsParamContinuouslyConst, Ctx))
return false;

do {
Expand All @@ -372,7 +375,7 @@ static bool arePointerTypesCompatible(QualType ArgType, QualType ParamType,
// Check whether cv-qualifiers permit compatibility on
// current level.
if (!arePointersStillQualCompatible(ArgType, ParamType,
IsParamContinuouslyConst))
IsParamContinuouslyConst, Ctx))
return false;

if (ParamType.getUnqualifiedType() == ArgType.getUnqualifiedType())
Expand All @@ -396,7 +399,7 @@ static bool areTypesCompatible(QualType ArgType, QualType ParamType,
return true;

// Check for constness and reference compatibility.
if (!areRefAndQualCompatible(ArgType, ParamType))
if (!areRefAndQualCompatible(ArgType, ParamType, Ctx))
return false;

bool IsParamReference = ParamType->isReferenceType();
Expand Down Expand Up @@ -434,7 +437,7 @@ static bool areTypesCompatible(QualType ArgType, QualType ParamType,
// When ParamType is an array reference, ArgType has to be of the same-sized
// array-type with cv-compatible element type.
if (IsParamReference && ParamType->isArrayType())
return isCompatibleWithArrayReference(ArgType, ParamType);
return isCompatibleWithArrayReference(ArgType, ParamType, Ctx);

bool IsParamContinuouslyConst =
!IsParamReference || ParamType.getNonReferenceType().isConstQualified();
Expand All @@ -444,7 +447,7 @@ static bool areTypesCompatible(QualType ArgType, QualType ParamType,
ParamType = convertToPointeeOrArrayElementQualType(ParamType);

// Check qualifier compatibility on the next level.
if (!ParamType.isAtLeastAsQualifiedAs(ArgType))
if (!ParamType.isAtLeastAsQualifiedAs(ArgType, Ctx))
return false;

if (ParamType.getUnqualifiedType() == ArgType.getUnqualifiedType())
Expand Down Expand Up @@ -472,8 +475,8 @@ static bool areTypesCompatible(QualType ArgType, QualType ParamType,
if (!(ParamType->isAnyPointerType() && ArgType->isAnyPointerType()))
return false;

return arePointerTypesCompatible(ArgType, ParamType,
IsParamContinuouslyConst);
return arePointerTypesCompatible(ArgType, ParamType, IsParamContinuouslyConst,
Ctx);
}

static bool isOverloadedUnaryOrBinarySymbolOperator(const FunctionDecl *FD) {
Expand Down
9 changes: 5 additions & 4 deletions clang/include/clang/AST/CanonicalType.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ namespace clang {
template<typename T> class CanProxy;
template<typename T> struct CanProxyAdaptor;
class CXXRecordDecl;
class ASTContext;
class EnumDecl;
class Expr;
class IdentifierInfo;
Expand Down Expand Up @@ -164,14 +165,14 @@ class CanQual {

/// Determines whether this canonical type is more qualified than
/// the @p Other canonical type.
bool isMoreQualifiedThan(CanQual<T> Other) const {
return Stored.isMoreQualifiedThan(Other.Stored);
bool isMoreQualifiedThan(CanQual<T> Other, const ASTContext &Ctx) const {
return Stored.isMoreQualifiedThan(Other.Stored, Ctx);
}

/// Determines whether this canonical type is at least as qualified as
/// the @p Other canonical type.
bool isAtLeastAsQualifiedAs(CanQual<T> Other) const {
return Stored.isAtLeastAsQualifiedAs(Other.Stored);
bool isAtLeastAsQualifiedAs(CanQual<T> Other, const ASTContext &Ctx) const {
return Stored.isAtLeastAsQualifiedAs(Other.Stored, Ctx);
}

/// If the canonical type is a reference type, returns the type that
Expand Down
59 changes: 20 additions & 39 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "clang/Basic/PointerAuthOptions.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Basic/TargetInfo.h"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dropped this include again in bc3b0fa because it was causing a significant build time regression. I assume this was a leftover from some earlier iteration of the patch.

Copy link
Contributor Author

@jhuber6 jhuber6 Nov 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't be necessary, I can make a PR to remove it again. Ah you meant you did it already, nevermind. Thanks for cleaning that up. Doing the change that was requested was really annoying so I did it off of the diff and forgot to delete that.

#include "clang/Basic/Visibility.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/APSInt.h"
Expand Down Expand Up @@ -323,6 +324,7 @@ class PointerAuthQualifier {
/// * Objective C: the GC attributes (none, weak, or strong)
class Qualifiers {
public:
Qualifiers() = default;
enum TQ : uint64_t {
// NOTE: These flags must be kept in sync with DeclSpec::TQ.
Const = 0x1,
Expand Down Expand Up @@ -697,45 +699,21 @@ class Qualifiers {
/// every address space is a superset of itself.
/// CL2.0 adds:
/// __generic is a superset of any address space except for __constant.
static bool isAddressSpaceSupersetOf(LangAS A, LangAS B) {
// Address spaces must match exactly.
return A == B ||
// Otherwise in OpenCLC v2.0 s6.5.5: every address space except
// for __constant can be used as __generic.
(A == LangAS::opencl_generic && B != LangAS::opencl_constant) ||
// We also define global_device and global_host address spaces,
// to distinguish global pointers allocated on host from pointers
// allocated on device, which are a subset of __global.
(A == LangAS::opencl_global && (B == LangAS::opencl_global_device ||
B == LangAS::opencl_global_host)) ||
(A == LangAS::sycl_global && (B == LangAS::sycl_global_device ||
B == LangAS::sycl_global_host)) ||
// Consider pointer size address spaces to be equivalent to default.
((isPtrSizeAddressSpace(A) || A == LangAS::Default) &&
(isPtrSizeAddressSpace(B) || B == LangAS::Default)) ||
// Default is a superset of SYCL address spaces.
(A == LangAS::Default &&
(B == LangAS::sycl_private || B == LangAS::sycl_local ||
B == LangAS::sycl_global || B == LangAS::sycl_global_device ||
B == LangAS::sycl_global_host)) ||
// In HIP device compilation, any cuda address space is allowed
// to implicitly cast into the default address space.
(A == LangAS::Default &&
(B == LangAS::cuda_constant || B == LangAS::cuda_device ||
B == LangAS::cuda_shared));
}
static bool isAddressSpaceSupersetOf(LangAS A, LangAS B,
const ASTContext &Ctx);

/// Returns true if the address space in these qualifiers is equal to or
/// a superset of the address space in the argument qualifiers.
bool isAddressSpaceSupersetOf(Qualifiers other) const {
return isAddressSpaceSupersetOf(getAddressSpace(), other.getAddressSpace());
bool isAddressSpaceSupersetOf(Qualifiers other, const ASTContext &Ctx) const {
return isAddressSpaceSupersetOf(getAddressSpace(), other.getAddressSpace(),
Ctx);
}

/// Determines if these qualifiers compatibly include another set.
/// Generally this answers the question of whether an object with the other
/// qualifiers can be safely used as an object with these qualifiers.
bool compatiblyIncludes(Qualifiers other) const {
return isAddressSpaceSupersetOf(other) &&
bool compatiblyIncludes(Qualifiers other, const ASTContext &Ctx) const {
return isAddressSpaceSupersetOf(other, Ctx) &&
// ObjC GC qualifiers can match, be added, or be removed, but can't
// be changed.
(getObjCGCAttr() == other.getObjCGCAttr() || !hasObjCGCAttr() ||
Expand Down Expand Up @@ -1273,11 +1251,11 @@ class QualType {

/// Determine whether this type is more qualified than the other
/// given type, requiring exact equality for non-CVR qualifiers.
bool isMoreQualifiedThan(QualType Other) const;
bool isMoreQualifiedThan(QualType Other, const ASTContext &Ctx) const;

/// Determine whether this type is at least as qualified as the other
/// given type, requiring exact equality for non-CVR qualifiers.
bool isAtLeastAsQualifiedAs(QualType Other) const;
bool isAtLeastAsQualifiedAs(QualType Other, const ASTContext &Ctx) const;

QualType getNonReferenceType() const;

Expand Down Expand Up @@ -1425,11 +1403,12 @@ class QualType {
/// address spaces overlap iff they are they same.
/// OpenCL C v2.0 s6.5.5 adds:
/// __generic overlaps with any address space except for __constant.
bool isAddressSpaceOverlapping(QualType T) const {
bool isAddressSpaceOverlapping(QualType T, const ASTContext &Ctx) const {
Qualifiers Q = getQualifiers();
Qualifiers TQ = T.getQualifiers();
// Address spaces overlap if at least one of them is a superset of another
return Q.isAddressSpaceSupersetOf(TQ) || TQ.isAddressSpaceSupersetOf(Q);
return Q.isAddressSpaceSupersetOf(TQ, Ctx) ||
TQ.isAddressSpaceSupersetOf(Q, Ctx);
}

/// Returns gc attribute of this type.
Expand Down Expand Up @@ -8112,24 +8091,26 @@ inline FunctionType::ExtInfo getFunctionExtInfo(QualType t) {
/// is more qualified than "const int", "volatile int", and
/// "int". However, it is not more qualified than "const volatile
/// int".
inline bool QualType::isMoreQualifiedThan(QualType other) const {
inline bool QualType::isMoreQualifiedThan(QualType other,
const ASTContext &Ctx) const {
Qualifiers MyQuals = getQualifiers();
Qualifiers OtherQuals = other.getQualifiers();
return (MyQuals != OtherQuals && MyQuals.compatiblyIncludes(OtherQuals));
return (MyQuals != OtherQuals && MyQuals.compatiblyIncludes(OtherQuals, Ctx));
}

/// Determine whether this type is at last
/// as qualified as the Other type. For example, "const volatile
/// int" is at least as qualified as "const int", "volatile int",
/// "int", and "const volatile int".
inline bool QualType::isAtLeastAsQualifiedAs(QualType other) const {
inline bool QualType::isAtLeastAsQualifiedAs(QualType other,
const ASTContext &Ctx) const {
Qualifiers OtherQuals = other.getQualifiers();

// Ignore __unaligned qualifier if this type is a void.
if (getUnqualifiedType()->isVoidType())
OtherQuals.removeUnaligned();

return getQualifiers().compatiblyIncludes(OtherQuals);
return getQualifiers().compatiblyIncludes(OtherQuals, Ctx);
}

/// If Type is a reference type (e.g., const
Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/Basic/TargetInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,13 @@ class TargetInfo : public TransferrableTargetInfo,
/// \param AddrSpace address space of pointee in source language.
virtual uint64_t getNullPointerValue(LangAS AddrSpace) const { return 0; }

/// Returns true if an address space can be safely converted to another.
/// \param A address space of target in source language.
/// \param B address space of source in source language.
virtual bool isAddressSpaceSupersetOf(LangAS A, LangAS B) const {
return A == B;
}

/// Return the size of '_Bool' and C++ 'bool' for this target, in bits.
unsigned getBoolWidth() const { return BoolWidth; }

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11405,7 +11405,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, bool OfBlockPointer,
Qualifiers RHSPteeQual = RHSPointee.getQualifiers();
// Blocks can't be an expression in a ternary operator (OpenCL v2.0
// 6.12.5) thus the following check is asymmetric.
if (!LHSPteeQual.isAddressSpaceSupersetOf(RHSPteeQual))
if (!LHSPteeQual.isAddressSpaceSupersetOf(RHSPteeQual, *this))
return {};
LHSPteeQual.removeAddressSpace();
RHSPteeQual.removeAddressSpace();
Expand Down
32 changes: 32 additions & 0 deletions clang/lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,38 @@ bool Qualifiers::isStrictSupersetOf(Qualifiers Other) const {
(hasObjCLifetime() && !Other.hasObjCLifetime()));
}

bool Qualifiers::isAddressSpaceSupersetOf(LangAS A, LangAS B,
const ASTContext &Ctx) {
// Address spaces must match exactly.
return A == B ||
// Otherwise in OpenCLC v2.0 s6.5.5: every address space except
// for __constant can be used as __generic.
(A == LangAS::opencl_generic && B != LangAS::opencl_constant) ||
// We also define global_device and global_host address spaces,
// to distinguish global pointers allocated on host from pointers
// allocated on device, which are a subset of __global.
(A == LangAS::opencl_global && (B == LangAS::opencl_global_device ||
B == LangAS::opencl_global_host)) ||
(A == LangAS::sycl_global &&
(B == LangAS::sycl_global_device || B == LangAS::sycl_global_host)) ||
// Consider pointer size address spaces to be equivalent to default.
((isPtrSizeAddressSpace(A) || A == LangAS::Default) &&
(isPtrSizeAddressSpace(B) || B == LangAS::Default)) ||
// Default is a superset of SYCL address spaces.
(A == LangAS::Default &&
(B == LangAS::sycl_private || B == LangAS::sycl_local ||
B == LangAS::sycl_global || B == LangAS::sycl_global_device ||
B == LangAS::sycl_global_host)) ||
// In HIP device compilation, any cuda address space is allowed
// to implicitly cast into the default address space.
(A == LangAS::Default &&
(B == LangAS::cuda_constant || B == LangAS::cuda_device ||
B == LangAS::cuda_shared)) ||
// Conversions from target specific address spaces may be legal
// depending on the target information.
Ctx.getTargetInfo().isAddressSpaceSupersetOf(A, B);
}

const IdentifierInfo* QualType::getBaseTypeIdentifier() const {
const Type* ty = getTypePtr();
NamedDecl *ND = nullptr;
Expand Down
12 changes: 12 additions & 0 deletions clang/lib/Basic/Targets/AMDGPU.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,18 @@ class LLVM_LIBRARY_VISIBILITY AMDGPUTargetInfo final : public TargetInfo {
return getPointerWidthV(AddrSpace);
}

virtual bool isAddressSpaceSupersetOf(LangAS A, LangAS B) const override {
// The flat address space AS(0) is a superset of all the other address
// spaces used by the backend target.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should exclude several address spaces. Should exclude region. Arguably also the fat pointers

Copy link
Contributor Author

@jhuber6 jhuber6 Nov 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic should only permit 0-5, I was torn on rejecting AS(2), can edit that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should reject it, it's not flat addressable. We don't have a magic aperture constant for it and the addrspacecast codegen will fail

return A == B ||
((A == LangAS::Default ||
(isTargetAddressSpace(A) &&
toTargetAddressSpace(A) == llvm::AMDGPUAS::FLAT_ADDRESS)) &&
isTargetAddressSpace(B) &&
toTargetAddressSpace(B) >= llvm::AMDGPUAS::FLAT_ADDRESS &&
toTargetAddressSpace(B) <= llvm::AMDGPUAS::PRIVATE_ADDRESS);
}

uint64_t getMaxPointerWidth() const override {
return getTriple().getArch() == llvm::Triple::amdgcn ? 64 : 32;
}
Expand Down
Loading
Loading