[clang] [clang-tools-extra] [Clang] Use TargetInfo when deciding is an address space is compatible (PR #115777)
Joseph Huber via cfe-commits
cfe-commits at lists.llvm.org
Wed Nov 13 16:45:38 PST 2024
https://github.com/jhuber6 updated https://github.com/llvm/llvm-project/pull/115777
>From 23a8d5af0ab181814885bca6ab6494be9d71f59b Mon Sep 17 00:00:00 2001
From: Joseph Huber <huberjn at outlook.com>
Date: Wed, 13 Nov 2024 18:14:05 -0600
Subject: [PATCH 1/2] use ASTContext
---
.../bugprone/VirtualNearMissCheck.cpp | 2 +-
.../SuspiciousCallArgumentCheck.cpp | 33 +++--
clang/include/clang/AST/CanonicalType.h | 9 +-
clang/include/clang/AST/Type.h | 59 +++-----
clang/include/clang/Basic/TargetInfo.h | 7 +
clang/lib/AST/ASTContext.cpp | 2 +-
clang/lib/AST/Type.cpp | 32 ++++
clang/lib/Basic/Targets/AMDGPU.h | 12 ++
clang/lib/Basic/Targets/NVPTX.h | 56 ++++---
clang/lib/Sema/SemaARM.cpp | 2 +-
clang/lib/Sema/SemaCast.cpp | 19 ++-
clang/lib/Sema/SemaCodeComplete.cpp | 10 +-
clang/lib/Sema/SemaDeclCXX.cpp | 2 +-
clang/lib/Sema/SemaExceptionSpec.cpp | 6 +-
clang/lib/Sema/SemaExpr.cpp | 24 +--
clang/lib/Sema/SemaExprCXX.cpp | 9 +-
clang/lib/Sema/SemaFixItUtils.cpp | 6 +-
clang/lib/Sema/SemaInit.cpp | 19 +--
clang/lib/Sema/SemaObjC.cpp | 2 +-
clang/lib/Sema/SemaOpenMP.cpp | 8 +-
clang/lib/Sema/SemaOverload.cpp | 48 +++---
clang/lib/Sema/SemaTemplateDeduction.cpp | 5 +-
clang/test/CodeGen/target-addrspace.cpp | 140 ++++++++++++++++++
clang/test/Sema/amdgcn-address-spaces.c | 20 +++
clang/test/Sema/nvptx-address-spaces.c | 21 +++
25 files changed, 401 insertions(+), 152 deletions(-)
create mode 100644 clang/test/CodeGen/target-addrspace.cpp
create mode 100644 clang/test/Sema/amdgcn-address-spaces.c
create mode 100644 clang/test/Sema/nvptx-address-spaces.c
diff --git a/clang-tools-extra/clang-tidy/bugprone/VirtualNearMissCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/VirtualNearMissCheck.cpp
index bebdce525e2887..76fa2d916f0e86 100644
--- a/clang-tools-extra/clang-tidy/bugprone/VirtualNearMissCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/VirtualNearMissCheck.cpp
@@ -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;
diff --git a/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp b/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp
index 18420d0c8488d2..c5eaff88e0ed3b 100644
--- a/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp
@@ -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) {
@@ -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();
@@ -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.
@@ -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 {
@@ -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())
@@ -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();
@@ -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();
@@ -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())
@@ -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) {
diff --git a/clang/include/clang/AST/CanonicalType.h b/clang/include/clang/AST/CanonicalType.h
index 6102eb01793530..06236861e26d01 100644
--- a/clang/include/clang/AST/CanonicalType.h
+++ b/clang/include/clang/AST/CanonicalType.h
@@ -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;
@@ -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
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 8979129017163b..7f3f413b721bc6 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -31,6 +31,7 @@
#include "clang/Basic/PointerAuthOptions.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Visibility.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/APSInt.h"
@@ -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,
@@ -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() ||
@@ -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;
@@ -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.
@@ -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
diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h
index 25eda907d20a7b..00d6073d0865a0 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -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; }
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 232081bdb46cff..5226ca6f5d0191 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -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();
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 7de13977176f2d..22d9ae17b39c2b 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -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;
diff --git a/clang/lib/Basic/Targets/AMDGPU.h b/clang/lib/Basic/Targets/AMDGPU.h
index fac46f215a3736..db7a095ba2a4fe 100644
--- a/clang/lib/Basic/Targets/AMDGPU.h
+++ b/clang/lib/Basic/Targets/AMDGPU.h
@@ -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.
+ 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;
}
diff --git a/clang/lib/Basic/Targets/NVPTX.h b/clang/lib/Basic/Targets/NVPTX.h
index 165b28a60fb2a9..3402f32dbde20c 100644
--- a/clang/lib/Basic/Targets/NVPTX.h
+++ b/clang/lib/Basic/Targets/NVPTX.h
@@ -17,6 +17,7 @@
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
#include "llvm/Support/Compiler.h"
+#include "llvm/Support/NVPTXAddrSpace.h"
#include "llvm/TargetParser/Triple.h"
#include <optional>
@@ -24,27 +25,26 @@ namespace clang {
namespace targets {
static const unsigned NVPTXAddrSpaceMap[] = {
- 0, // Default
- 1, // opencl_global
- 3, // opencl_local
- 4, // opencl_constant
- 0, // opencl_private
- // FIXME: generic has to be added to the target
- 0, // opencl_generic
- 1, // opencl_global_device
- 1, // opencl_global_host
- 1, // cuda_device
- 4, // cuda_constant
- 3, // cuda_shared
- 1, // sycl_global
- 1, // sycl_global_device
- 1, // sycl_global_host
- 3, // sycl_local
- 0, // sycl_private
- 0, // ptr32_sptr
- 0, // ptr32_uptr
- 0, // ptr64
- 0, // hlsl_groupshared
+ llvm::NVPTXAS::ADDRESS_SPACE_GENERIC, // Default
+ llvm::NVPTXAS::ADDRESS_SPACE_GLOBAL, // opencl_global
+ llvm::NVPTXAS::ADDRESS_SPACE_SHARED, // opencl_local
+ llvm::NVPTXAS::ADDRESS_SPACE_CONST, // opencl_constant
+ llvm::NVPTXAS::ADDRESS_SPACE_GENERIC, // opencl_private
+ llvm::NVPTXAS::ADDRESS_SPACE_GENERIC, // opencl_generic
+ llvm::NVPTXAS::ADDRESS_SPACE_GLOBAL, // opencl_global_device
+ llvm::NVPTXAS::ADDRESS_SPACE_GLOBAL, // opencl_global_host
+ llvm::NVPTXAS::ADDRESS_SPACE_GLOBAL, // cuda_device
+ llvm::NVPTXAS::ADDRESS_SPACE_CONST, // cuda_constant
+ llvm::NVPTXAS::ADDRESS_SPACE_SHARED, // cuda_shared
+ llvm::NVPTXAS::ADDRESS_SPACE_GLOBAL, // sycl_global
+ llvm::NVPTXAS::ADDRESS_SPACE_GLOBAL, // sycl_global_device
+ llvm::NVPTXAS::ADDRESS_SPACE_GLOBAL, // sycl_global_host
+ llvm::NVPTXAS::ADDRESS_SPACE_SHARED, // sycl_local
+ llvm::NVPTXAS::ADDRESS_SPACE_GENERIC, // sycl_private
+ llvm::NVPTXAS::ADDRESS_SPACE_GENERIC, // ptr32_sptr
+ llvm::NVPTXAS::ADDRESS_SPACE_GENERIC, // ptr32_uptr
+ llvm::NVPTXAS::ADDRESS_SPACE_GENERIC, // ptr64
+ llvm::NVPTXAS::ADDRESS_SPACE_GENERIC, // hlsl_groupshared
// Wasm address space values for this target are dummy values,
// as it is only enabled for Wasm targets.
20, // wasm_funcref
@@ -89,6 +89,20 @@ class LLVM_LIBRARY_VISIBILITY NVPTXTargetInfo : public TargetInfo {
bool hasFeature(StringRef Feature) const override;
+ virtual bool isAddressSpaceSupersetOf(LangAS A, LangAS B) const override {
+ // The generic address space AS(0) is a superset of all the other address
+ // spaces used by the backend target.
+ return A == B ||
+ ((A == LangAS::Default ||
+ (isTargetAddressSpace(A) &&
+ toTargetAddressSpace(A) ==
+ llvm::NVPTXAS::ADDRESS_SPACE_GENERIC)) &&
+ isTargetAddressSpace(B) &&
+ toTargetAddressSpace(B) >= llvm::NVPTXAS::ADDRESS_SPACE_GENERIC &&
+ toTargetAddressSpace(B) <= llvm::NVPTXAS::ADDRESS_SPACE_LOCAL &&
+ toTargetAddressSpace(B) != 2);
+ }
+
ArrayRef<const char *> getGCCRegNames() const override;
ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
diff --git a/clang/lib/Sema/SemaARM.cpp b/clang/lib/Sema/SemaARM.cpp
index c3a6e5ef8a9d44..3e93b38143f3b3 100644
--- a/clang/lib/Sema/SemaARM.cpp
+++ b/clang/lib/Sema/SemaARM.cpp
@@ -907,7 +907,7 @@ bool SemaARM::CheckARMBuiltinExclusiveCall(unsigned BuiltinID,
// Issue a warning if the cast is dodgy.
CastKind CastNeeded = CK_NoOp;
- if (!AddrType.isAtLeastAsQualifiedAs(ValType)) {
+ if (!AddrType.isAtLeastAsQualifiedAs(ValType, getASTContext())) {
CastNeeded = CK_BitCast;
Diag(DRE->getBeginLoc(), diag::ext_typecheck_convert_discards_qualifiers)
<< PointerArg->getType() << Context.getPointerType(AddrType)
diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp
index 3eb013e3612d1c..cfb82dcc4df451 100644
--- a/clang/lib/Sema/SemaCast.cpp
+++ b/clang/lib/Sema/SemaCast.cpp
@@ -731,7 +731,8 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType,
*CastAwayQualifiers = SrcCvrQuals - DestCvrQuals;
// If we removed a cvr-qualifier, this is casting away 'constness'.
- if (!DestCvrQuals.compatiblyIncludes(SrcCvrQuals)) {
+ if (!DestCvrQuals.compatiblyIncludes(SrcCvrQuals,
+ Self.getASTContext())) {
if (TheOffendingSrcType)
*TheOffendingSrcType = PrevUnwrappedSrcType;
if (TheOffendingDestType)
@@ -889,7 +890,7 @@ void CastOperation::CheckDynamicCast() {
assert(SrcRecord && "Bad source pointee slipped through.");
// C++ 5.2.7p1: The dynamic_cast operator shall not cast away constness.
- if (!DestPointee.isAtLeastAsQualifiedAs(SrcPointee)) {
+ if (!DestPointee.isAtLeastAsQualifiedAs(SrcPointee, Self.getASTContext())) {
Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_qualifiers_away)
<< CT_Dynamic << OrigSrcType << this->DestType << OpRange;
SrcExpr = ExprError();
@@ -1463,7 +1464,8 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
SrcPointeeQuals.removeObjCGCAttr();
SrcPointeeQuals.removeObjCLifetime();
if (DestPointeeQuals != SrcPointeeQuals &&
- !DestPointeeQuals.compatiblyIncludes(SrcPointeeQuals)) {
+ !DestPointeeQuals.compatiblyIncludes(SrcPointeeQuals,
+ Self.getASTContext())) {
msg = diag::err_bad_cxx_cast_qualifiers_away;
return TC_Failed;
}
@@ -1695,7 +1697,8 @@ TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType,
// FIXME: Being 100% compliant here would be nice to have.
// Must preserve cv, as always, unless we're in C-style mode.
- if (!CStyle && !DestType.isAtLeastAsQualifiedAs(SrcType)) {
+ if (!CStyle &&
+ !DestType.isAtLeastAsQualifiedAs(SrcType, Self.getASTContext())) {
msg = diag::err_bad_cxx_cast_qualifiers_away;
return TC_Failed;
}
@@ -2524,7 +2527,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
assert(SrcType->isPointerType() && DestType->isPointerType());
if (!CStyle &&
!DestType->getPointeeType().getQualifiers().isAddressSpaceSupersetOf(
- SrcType->getPointeeType().getQualifiers())) {
+ SrcType->getPointeeType().getQualifiers(), Self.getASTContext())) {
SuccessResult = TC_Failed;
}
} else if (IsLValueCast) {
@@ -2631,7 +2634,8 @@ static TryCastResult TryAddressSpaceCast(Sema &Self, ExprResult &SrcExpr,
return TC_NotApplicable;
auto SrcPointeeType = SrcPtrType->getPointeeType();
auto DestPointeeType = DestPtrType->getPointeeType();
- if (!DestPointeeType.isAddressSpaceOverlapping(SrcPointeeType)) {
+ if (!DestPointeeType.isAddressSpaceOverlapping(SrcPointeeType,
+ Self.getASTContext())) {
msg = diag::err_bad_cxx_cast_addr_space_mismatch;
return TC_Failed;
}
@@ -2676,7 +2680,8 @@ void CastOperation::checkAddressSpaceCast(QualType SrcType, QualType DestType) {
QualType SrcPPointee = SrcPPtr->getPointeeType();
if (Nested
? DestPPointee.getAddressSpace() != SrcPPointee.getAddressSpace()
- : !DestPPointee.isAddressSpaceOverlapping(SrcPPointee)) {
+ : !DestPPointee.isAddressSpaceOverlapping(SrcPPointee,
+ Self.getASTContext())) {
Self.Diag(OpRange.getBegin(), DiagID)
<< SrcType << DestType << AssignmentAction::Casting
<< SrcExpr.get()->getSourceRange();
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index 16a76ff9b5c241..452a8a89709f4c 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -1246,7 +1246,8 @@ enum class OverloadCompare { BothViable, Dominates, Dominated };
static OverloadCompare compareOverloads(const CXXMethodDecl &Candidate,
const CXXMethodDecl &Incumbent,
const Qualifiers &ObjectQuals,
- ExprValueKind ObjectKind) {
+ ExprValueKind ObjectKind,
+ const ASTContext &Ctx) {
// Base/derived shadowing is handled elsewhere.
if (Candidate.getDeclContext() != Incumbent.getDeclContext())
return OverloadCompare::BothViable;
@@ -1280,8 +1281,8 @@ static OverloadCompare compareOverloads(const CXXMethodDecl &Candidate,
// So make some decision based on the qualifiers.
Qualifiers CandidateQual = Candidate.getMethodQualifiers();
Qualifiers IncumbentQual = Incumbent.getMethodQualifiers();
- bool CandidateSuperset = CandidateQual.compatiblyIncludes(IncumbentQual);
- bool IncumbentSuperset = IncumbentQual.compatiblyIncludes(CandidateQual);
+ bool CandidateSuperset = CandidateQual.compatiblyIncludes(IncumbentQual, Ctx);
+ bool IncumbentSuperset = IncumbentQual.compatiblyIncludes(CandidateQual, Ctx);
if (CandidateSuperset == IncumbentSuperset)
return OverloadCompare::BothViable;
return IncumbentSuperset ? OverloadCompare::Dominates
@@ -1452,7 +1453,8 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
Result &Incumbent = Results[Entry.second];
switch (compareOverloads(*Method,
*cast<CXXMethodDecl>(Incumbent.Declaration),
- ObjectTypeQualifiers, ObjectKind)) {
+ ObjectTypeQualifiers, ObjectKind,
+ CurContext->getParentASTContext())) {
case OverloadCompare::Dominates:
// Replace the dominated overload with this one.
// FIXME: if the overload dominates multiple incumbents then we
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 8d76a35b2d2557..96e5f36363bec5 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -18332,7 +18332,7 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
// The new class type must have the same or less qualifiers as the old type.
- if (!OldClassTy.isAtLeastAsQualifiedAs(NewClassTy)) {
+ if (!OldClassTy.isAtLeastAsQualifiedAs(NewClassTy, getASTContext())) {
Diag(New->getLocation(),
diag::err_covariant_return_type_class_type_not_same_or_less_qualified)
<< New->getDeclName() << NewTy << OldTy
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index 0d5ab0b3cd09ca..bfcdab91dd6f07 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -717,9 +717,9 @@ bool Sema::handlerCanCatch(QualType HandlerType, QualType ExceptionType) {
Qualifiers EQuals, HQuals;
ExceptionType = Context.getUnqualifiedArrayType(
ExceptionType->getPointeeType(), EQuals);
- HandlerType = Context.getUnqualifiedArrayType(
- HandlerType->getPointeeType(), HQuals);
- if (!HQuals.compatiblyIncludes(EQuals))
+ HandlerType =
+ Context.getUnqualifiedArrayType(HandlerType->getPointeeType(), HQuals);
+ if (!HQuals.compatiblyIncludes(EQuals, getASTContext()))
return false;
if (HandlerType->isVoidType() && ExceptionType->isObjectType())
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 01d43317e33aed..73647c55986463 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -8025,9 +8025,9 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS,
// OpenCL v1.1 s6.5 - Conversion between pointers to distinct address
// spaces is disallowed.
- if (lhQual.isAddressSpaceSupersetOf(rhQual))
+ if (lhQual.isAddressSpaceSupersetOf(rhQual, S.getASTContext()))
ResultAddrSpace = LAddrSpace;
- else if (rhQual.isAddressSpaceSupersetOf(lhQual))
+ else if (rhQual.isAddressSpaceSupersetOf(lhQual, S.getASTContext()))
ResultAddrSpace = RAddrSpace;
else {
S.Diag(Loc, diag::err_typecheck_op_on_nonoverlapping_address_space_pointers)
@@ -8939,17 +8939,17 @@ checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType,
rhq.removeObjCLifetime();
}
- if (!lhq.compatiblyIncludes(rhq)) {
+ if (!lhq.compatiblyIncludes(rhq, S.getASTContext())) {
// Treat address-space mismatches as fatal.
- if (!lhq.isAddressSpaceSupersetOf(rhq))
+ if (!lhq.isAddressSpaceSupersetOf(rhq, S.getASTContext()))
return Sema::IncompatiblePointerDiscardsQualifiers;
// It's okay to add or remove GC or lifetime qualifiers when converting to
// and from void*.
- else if (lhq.withoutObjCGCAttr().withoutObjCLifetime()
- .compatiblyIncludes(
- rhq.withoutObjCGCAttr().withoutObjCLifetime())
- && (lhptee->isVoidType() || rhptee->isVoidType()))
+ else if (lhq.withoutObjCGCAttr().withoutObjCLifetime().compatiblyIncludes(
+ rhq.withoutObjCGCAttr().withoutObjCLifetime(),
+ S.getASTContext()) &&
+ (lhptee->isVoidType() || rhptee->isVoidType()))
; // keep old
// Treat lifetime mismatches as fatal.
@@ -9136,7 +9136,7 @@ checkObjCPointerTypesForAssignment(Sema &S, QualType LHSType,
QualType lhptee = LHSType->castAs<ObjCObjectPointerType>()->getPointeeType();
QualType rhptee = RHSType->castAs<ObjCObjectPointerType>()->getPointeeType();
- if (!lhptee.isAtLeastAsQualifiedAs(rhptee) &&
+ if (!lhptee.isAtLeastAsQualifiedAs(rhptee, S.getASTContext()) &&
// make an exception for id<P>
!LHSType->isObjCQualifiedIdType())
return Sema::CompatiblePointerDiscardsQualifiers;
@@ -10833,7 +10833,8 @@ static bool checkArithmeticBinOpPointerOperands(Sema &S, SourceLocation Loc,
// if both are pointers check if operation is valid wrt address spaces
if (isLHSPointer && isRHSPointer) {
- if (!LHSPointeeTy.isAddressSpaceOverlapping(RHSPointeeTy)) {
+ if (!LHSPointeeTy.isAddressSpaceOverlapping(RHSPointeeTy,
+ S.getASTContext())) {
S.Diag(Loc,
diag::err_typecheck_op_on_nonoverlapping_address_space_pointers)
<< LHSExpr->getType() << RHSExpr->getType() << 1 /*arithmetic op*/
@@ -12364,7 +12365,8 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
if (LCanPointeeTy != RCanPointeeTy) {
// Treat NULL constant as a special case in OpenCL.
if (getLangOpts().OpenCL && !LHSIsNull && !RHSIsNull) {
- if (!LCanPointeeTy.isAddressSpaceOverlapping(RCanPointeeTy)) {
+ if (!LCanPointeeTy.isAddressSpaceOverlapping(RCanPointeeTy,
+ getASTContext())) {
Diag(Loc,
diag::err_typecheck_op_on_nonoverlapping_address_space_pointers)
<< LHSType << RHSType << 0 /* comparison */
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index ab9367f911cc51..3b5d5c4befc0f7 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -4783,7 +4783,8 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
ToType->castAs<BlockPointerType>()->getPointeeType().getAddressSpace();
LangAS AddrSpaceR =
FromType->castAs<BlockPointerType>()->getPointeeType().getAddressSpace();
- assert(Qualifiers::isAddressSpaceSupersetOf(AddrSpaceL, AddrSpaceR) &&
+ assert(Qualifiers::isAddressSpaceSupersetOf(AddrSpaceL, AddrSpaceR,
+ getASTContext()) &&
"Invalid cast");
CastKind Kind =
AddrSpaceL != AddrSpaceR ? CK_AddressSpaceConversion : CK_BitCast;
@@ -6641,7 +6642,7 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
// same type as, or a base class of, the class of T1, and
// [cv2 > cv1].
if (FRec == TRec || FDerivedFromT) {
- if (TTy.isAtLeastAsQualifiedAs(FTy)) {
+ if (TTy.isAtLeastAsQualifiedAs(FTy, Self.getASTContext())) {
InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy);
InitializationSequence InitSeq(Self, Entity, Kind, From);
if (InitSeq) {
@@ -7363,8 +7364,8 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc,
if (Q1.getAddressSpace() == Q2.getAddressSpace()) {
Quals.setAddressSpace(Q1.getAddressSpace());
} else if (Steps.size() == 1) {
- bool MaybeQ1 = Q1.isAddressSpaceSupersetOf(Q2);
- bool MaybeQ2 = Q2.isAddressSpaceSupersetOf(Q1);
+ bool MaybeQ1 = Q1.isAddressSpaceSupersetOf(Q2, getASTContext());
+ bool MaybeQ2 = Q2.isAddressSpaceSupersetOf(Q1, getASTContext());
if (MaybeQ1 == MaybeQ2) {
// Exception for ptr size address spaces. Should be able to choose
// either address space during comparison.
diff --git a/clang/lib/Sema/SemaFixItUtils.cpp b/clang/lib/Sema/SemaFixItUtils.cpp
index 2c85a53194301f..1dad46fd6b9401 100644
--- a/clang/lib/Sema/SemaFixItUtils.cpp
+++ b/clang/lib/Sema/SemaFixItUtils.cpp
@@ -24,7 +24,7 @@ bool ConversionFixItGenerator::compareTypesSimple(CanQualType From,
Sema &S,
SourceLocation Loc,
ExprValueKind FromVK) {
- if (!To.isAtLeastAsQualifiedAs(From))
+ if (!To.isAtLeastAsQualifiedAs(From, S.getASTContext()))
return false;
From = From.getNonReferenceType();
@@ -41,8 +41,8 @@ bool ConversionFixItGenerator::compareTypesSimple(CanQualType From,
const CanQualType FromUnq = From.getUnqualifiedType();
const CanQualType ToUnq = To.getUnqualifiedType();
- if ((FromUnq == ToUnq || (S.IsDerivedFrom(Loc, FromUnq, ToUnq)) ) &&
- To.isAtLeastAsQualifiedAs(From))
+ if ((FromUnq == ToUnq || (S.IsDerivedFrom(Loc, FromUnq, ToUnq))) &&
+ To.isAtLeastAsQualifiedAs(From, S.getASTContext()))
return true;
return false;
}
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index f13355bb93cbeb..00586dc601997b 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -4718,7 +4718,7 @@ static void TryReferenceListInitialization(Sema &S,
if (T1Quals.hasAddressSpace()) {
Qualifiers T2Quals;
(void)S.Context.getUnqualifiedArrayType(InitList->getType(), T2Quals);
- if (!T1Quals.isAddressSpaceSupersetOf(T2Quals)) {
+ if (!T1Quals.isAddressSpaceSupersetOf(T2Quals, S.getASTContext())) {
Sequence.SetFailed(
InitializationSequence::FK_ReferenceInitDropsQualifiers);
return;
@@ -5324,8 +5324,9 @@ static void TryReferenceInitializationCore(Sema &S,
// shall be an rvalue reference.
// For address spaces, we interpret this to mean that an addr space
// of a reference "cv1 T1" is a superset of addr space of "cv2 T2".
- if (isLValueRef && !(T1Quals.hasConst() && !T1Quals.hasVolatile() &&
- T1Quals.isAddressSpaceSupersetOf(T2Quals))) {
+ if (isLValueRef &&
+ !(T1Quals.hasConst() && !T1Quals.hasVolatile() &&
+ T1Quals.isAddressSpaceSupersetOf(T2Quals, S.getASTContext()))) {
if (S.Context.getCanonicalType(T2) == S.Context.OverloadTy)
Sequence.SetFailed(InitializationSequence::FK_AddressOfOverloadFailed);
else if (ConvOvlResult && !Sequence.getFailedCandidateSet().empty())
@@ -5334,7 +5335,7 @@ static void TryReferenceInitializationCore(Sema &S,
ConvOvlResult);
else if (!InitCategory.isLValue())
Sequence.SetFailed(
- T1Quals.isAddressSpaceSupersetOf(T2Quals)
+ T1Quals.isAddressSpaceSupersetOf(T2Quals, S.getASTContext())
? InitializationSequence::
FK_NonConstLValueReferenceBindingToTemporary
: InitializationSequence::FK_ReferenceInitDropsQualifiers);
@@ -5519,7 +5520,7 @@ static void TryReferenceInitializationCore(Sema &S,
unsigned T2CVRQuals = T2Quals.getCVRQualifiers();
if (RefRelationship == Sema::Ref_Related &&
((T1CVRQuals | T2CVRQuals) != T1CVRQuals ||
- !T1Quals.isAddressSpaceSupersetOf(T2Quals))) {
+ !T1Quals.isAddressSpaceSupersetOf(T2Quals, S.getASTContext()))) {
Sequence.SetFailed(InitializationSequence::FK_ReferenceInitDropsQualifiers);
return;
}
@@ -5536,8 +5537,8 @@ static void TryReferenceInitializationCore(Sema &S,
Sequence.AddReferenceBindingStep(cv1T1IgnoreAS, /*BindingTemporary=*/true);
if (T1Quals.hasAddressSpace()) {
- if (!Qualifiers::isAddressSpaceSupersetOf(T1Quals.getAddressSpace(),
- LangAS::Default)) {
+ if (!Qualifiers::isAddressSpaceSupersetOf(
+ T1Quals.getAddressSpace(), LangAS::Default, S.getASTContext())) {
Sequence.SetFailed(
InitializationSequence::FK_ReferenceAddrspaceMismatchTemporary);
return;
@@ -8629,7 +8630,7 @@ static void emitBadConversionNotes(Sema &S, const InitializedEntity &entity,
!fromDecl->isInvalidDecl() && !destDecl->isInvalidDecl() &&
!fromDecl->hasDefinition() &&
destPointeeType.getQualifiers().compatiblyIncludes(
- fromPointeeType.getQualifiers()))
+ fromPointeeType.getQualifiers(), S.getASTContext()))
S.Diag(fromDecl->getLocation(), diag::note_forward_class_conversion)
<< S.getASTContext().getTagDeclType(fromDecl)
<< S.getASTContext().getTagDeclType(destDecl);
@@ -8907,7 +8908,7 @@ bool InitializationSequence::Diagnose(Sema &S,
SourceType.getQualifiers() - NonRefType.getQualifiers();
if (!NonRefType.getQualifiers().isAddressSpaceSupersetOf(
- SourceType.getQualifiers()))
+ SourceType.getQualifiers(), S.getASTContext()))
S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals)
<< NonRefType << SourceType << 1 /*addr space*/
<< Args[0]->getSourceRange();
diff --git a/clang/lib/Sema/SemaObjC.cpp b/clang/lib/Sema/SemaObjC.cpp
index 0359d18dd94525..57eda18c2d8e15 100644
--- a/clang/lib/Sema/SemaObjC.cpp
+++ b/clang/lib/Sema/SemaObjC.cpp
@@ -1350,7 +1350,7 @@ bool SemaObjC::isObjCWritebackConversion(QualType FromType, QualType ToType,
// Make sure that we have compatible qualifiers.
FromQuals.setObjCLifetime(Qualifiers::OCL_Autoreleasing);
- if (!ToQuals.compatiblyIncludes(FromQuals))
+ if (!ToQuals.compatiblyIncludes(FromQuals, getASTContext()))
return false;
// Remove qualifiers from the pointee type we're converting from; they
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index fe8bb99d2db040..dfe0da153fecee 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -18188,7 +18188,8 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range,
Lookups, [&SemaRef, Ty, Loc](ValueDecl *D) -> ValueDecl * {
if (!D->isInvalidDecl() &&
SemaRef.IsDerivedFrom(Loc, Ty, D->getType()) &&
- !Ty.isMoreQualifiedThan(D->getType()))
+ !Ty.isMoreQualifiedThan(D->getType(),
+ SemaRef.getASTContext()))
return D;
return nullptr;
})) {
@@ -21038,7 +21039,8 @@ static ExprResult buildUserDefinedMapperRef(Sema &SemaRef, Scope *S,
Lookups, [&SemaRef, Type, Loc](ValueDecl *D) -> ValueDecl * {
if (!D->isInvalidDecl() &&
SemaRef.IsDerivedFrom(Loc, Type, D->getType()) &&
- !Type.isMoreQualifiedThan(D->getType()))
+ !Type.isMoreQualifiedThan(D->getType(),
+ SemaRef.getASTContext()))
return D;
return nullptr;
})) {
@@ -21209,7 +21211,7 @@ static bool hasUserDefinedMapper(Sema &SemaRef, Scope *S,
Lookups, [&SemaRef, Type, Loc](ValueDecl *D) -> ValueDecl * {
if (!D->isInvalidDecl() &&
SemaRef.IsDerivedFrom(Loc, Type, D->getType()) &&
- !Type.isMoreQualifiedThan(D->getType()))
+ !Type.isMoreQualifiedThan(D->getType(), SemaRef.getASTContext()))
return D;
return nullptr;
});
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 4aeceba128b29b..1b4c76c840fea6 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -2963,7 +2963,7 @@ static QualType AdoptQualifiers(ASTContext &Context, QualType T, Qualifiers Qs){
if (TQs == Qs)
return T;
- if (Qs.compatiblyIncludes(TQs))
+ if (Qs.compatiblyIncludes(TQs, Context))
return Context.getQualifiedType(T, Qs);
return Context.getQualifiedType(T.getUnqualifiedType(), Qs);
@@ -2997,7 +2997,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
const ObjCInterfaceType* RHS = FromObjCPtr->getInterfaceType();
if (getLangOpts().CPlusPlus && LHS && RHS &&
!ToObjCPtr->getPointeeType().isAtLeastAsQualifiedAs(
- FromObjCPtr->getPointeeType()))
+ FromObjCPtr->getPointeeType(), getASTContext()))
return false;
ConvertedType = BuildSimilarlyQualifiedPointerType(FromObjCPtr,
ToObjCPtr->getPointeeType(),
@@ -3604,7 +3604,8 @@ static bool isNonTrivialObjCLifetimeConversion(Qualifiers FromQuals,
static bool isQualificationConversionStep(QualType FromType, QualType ToType,
bool CStyle, bool IsTopLevel,
bool &PreviousToQualsIncludeConst,
- bool &ObjCLifetimeConversion) {
+ bool &ObjCLifetimeConversion,
+ const ASTContext &Ctx) {
Qualifiers FromQuals = FromType.getQualifiers();
Qualifiers ToQuals = ToType.getQualifiers();
@@ -3635,7 +3636,7 @@ static bool isQualificationConversionStep(QualType FromType, QualType ToType,
// -- for every j > 0, if const is in cv 1,j then const is in cv
// 2,j, and similarly for volatile.
- if (!CStyle && !ToQuals.compatiblyIncludes(FromQuals))
+ if (!CStyle && !ToQuals.compatiblyIncludes(FromQuals, Ctx))
return false;
// If address spaces mismatch:
@@ -3645,8 +3646,8 @@ static bool isQualificationConversionStep(QualType FromType, QualType ToType,
// - in non-top levels it is not a valid conversion.
if (ToQuals.getAddressSpace() != FromQuals.getAddressSpace() &&
(!IsTopLevel ||
- !(ToQuals.isAddressSpaceSupersetOf(FromQuals) ||
- (CStyle && FromQuals.isAddressSpaceSupersetOf(ToQuals)))))
+ !(ToQuals.isAddressSpaceSupersetOf(FromQuals, Ctx) ||
+ (CStyle && FromQuals.isAddressSpaceSupersetOf(ToQuals, Ctx)))))
return false;
// -- if the cv 1,j and cv 2,j are different, then const is in
@@ -3693,9 +3694,10 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType,
bool PreviousToQualsIncludeConst = true;
bool UnwrappedAnyPointer = false;
while (Context.UnwrapSimilarTypes(FromType, ToType)) {
- if (!isQualificationConversionStep(
- FromType, ToType, CStyle, !UnwrappedAnyPointer,
- PreviousToQualsIncludeConst, ObjCLifetimeConversion))
+ if (!isQualificationConversionStep(FromType, ToType, CStyle,
+ !UnwrappedAnyPointer,
+ PreviousToQualsIncludeConst,
+ ObjCLifetimeConversion, getASTContext()))
return false;
UnwrappedAnyPointer = true;
}
@@ -4546,9 +4548,9 @@ CompareStandardConversionSequences(Sema &S, SourceLocation Loc,
T1 = S.Context.getQualifiedType(UnqualT1, T1Quals);
if (isa<ArrayType>(T2) && T2Quals)
T2 = S.Context.getQualifiedType(UnqualT2, T2Quals);
- if (T2.isMoreQualifiedThan(T1))
+ if (T2.isMoreQualifiedThan(T1, S.getASTContext()))
return ImplicitConversionSequence::Better;
- if (T1.isMoreQualifiedThan(T2))
+ if (T1.isMoreQualifiedThan(T2, S.getASTContext()))
return ImplicitConversionSequence::Worse;
}
}
@@ -4987,7 +4989,7 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
bool ObjCLifetimeConversion = false;
if (!isQualificationConversionStep(T2, T1, /*CStyle=*/false, TopLevel,
PreviousToQualsIncludeConst,
- ObjCLifetimeConversion))
+ ObjCLifetimeConversion, getASTContext()))
return (ConvertedReferent || Context.hasSimilarType(T1, T2))
? Ref_Related
: Ref_Incompatible;
@@ -5318,7 +5320,7 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
// MS compiler ignores __unaligned qualifier for references; do the same.
T1Quals.removeUnaligned();
T2Quals.removeUnaligned();
- if (!T1Quals.compatiblyIncludes(T2Quals))
+ if (!T1Quals.compatiblyIncludes(T2Quals, S.getASTContext()))
return ICS;
}
@@ -5836,7 +5838,7 @@ static ImplicitConversionSequence TryObjectArgumentInitialization(
if (ImplicitParamType.getCVRQualifiers() !=
FromTypeCanon.getLocalCVRQualifiers() &&
!ImplicitParamType.isAtLeastAsQualifiedAs(
- withoutUnaligned(S.Context, FromTypeCanon))) {
+ withoutUnaligned(S.Context, FromTypeCanon), S.getASTContext())) {
ICS.setBad(BadConversionSequence::bad_qualifiers,
FromType, ImplicitParamType);
return ICS;
@@ -5845,7 +5847,8 @@ static ImplicitConversionSequence TryObjectArgumentInitialization(
if (FromTypeCanon.hasAddressSpace()) {
Qualifiers QualsImplicitParamType = ImplicitParamType.getQualifiers();
Qualifiers QualsFromType = FromTypeCanon.getQualifiers();
- if (!QualsImplicitParamType.isAddressSpaceSupersetOf(QualsFromType)) {
+ if (!QualsImplicitParamType.isAddressSpaceSupersetOf(QualsFromType,
+ S.getASTContext())) {
ICS.setBad(BadConversionSequence::bad_qualifiers,
FromType, ImplicitParamType);
return ICS;
@@ -7030,7 +7033,7 @@ void Sema::AddOverloadCandidate(
// destination address space.
if (!Qualifiers::isAddressSpaceSupersetOf(
Constructor->getMethodQualifiers().getAddressSpace(),
- CandidateSet.getDestAS())) {
+ CandidateSet.getDestAS(), getASTContext())) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_object_addrspace_mismatch;
}
@@ -10678,9 +10681,9 @@ bool clang::isBetterOverloadCandidate(
LangAS AS1 = CD1->getMethodQualifiers().getAddressSpace();
LangAS AS2 = CD2->getMethodQualifiers().getAddressSpace();
if (AS1 != AS2) {
- if (Qualifiers::isAddressSpaceSupersetOf(AS2, AS1))
+ if (Qualifiers::isAddressSpaceSupersetOf(AS2, AS1, S.getASTContext()))
return true;
- if (Qualifiers::isAddressSpaceSupersetOf(AS1, AS2))
+ if (Qualifiers::isAddressSpaceSupersetOf(AS1, AS2, S.getASTContext()))
return false;
}
}
@@ -11285,7 +11288,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
}
if (CToTy.getUnqualifiedType() == CFromTy.getUnqualifiedType() &&
- !CToTy.isAtLeastAsQualifiedAs(CFromTy)) {
+ !CToTy.isAtLeastAsQualifiedAs(CFromTy, S.getASTContext())) {
Qualifiers FromQs = CFromTy.getQualifiers();
Qualifiers ToQs = CToTy.getQualifiers();
@@ -11384,7 +11387,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
if (const PointerType *FromPtrTy = FromTy->getAs<PointerType>()) {
if (const PointerType *ToPtrTy = ToTy->getAs<PointerType>()) {
if (ToPtrTy->getPointeeType().isAtLeastAsQualifiedAs(
- FromPtrTy->getPointeeType()) &&
+ FromPtrTy->getPointeeType(), S.getASTContext()) &&
!FromPtrTy->getPointeeType()->isIncompleteType() &&
!ToPtrTy->getPointeeType()->isIncompleteType() &&
S.IsDerivedFrom(SourceLocation(), ToPtrTy->getPointeeType(),
@@ -11398,11 +11401,12 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
if (const ObjCInterfaceDecl *FromIface = FromPtrTy->getInterfaceDecl())
if (const ObjCInterfaceDecl *ToIface = ToPtrTy->getInterfaceDecl())
if (ToPtrTy->getPointeeType().isAtLeastAsQualifiedAs(
- FromPtrTy->getPointeeType()) &&
+ FromPtrTy->getPointeeType(), S.getASTContext()) &&
FromIface->isSuperClassOf(ToIface))
BaseToDerivedConversion = 2;
} else if (const ReferenceType *ToRefTy = ToTy->getAs<ReferenceType>()) {
- if (ToRefTy->getPointeeType().isAtLeastAsQualifiedAs(FromTy) &&
+ if (ToRefTy->getPointeeType().isAtLeastAsQualifiedAs(FromTy,
+ S.getASTContext()) &&
!FromTy->isIncompleteType() &&
!ToRefTy->getPointeeType()->isIncompleteType() &&
S.IsDerivedFrom(SourceLocation(), ToRefTy->getPointeeType(), FromTy)) {
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 2946d8102f9897..8d234c05492a91 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -1743,7 +1743,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
// C++ [temp.deduct.conv]p4:
// If the original A is a reference type, A can be more cv-qualified
// than the deduced A
- if (!A.getQualifiers().compatiblyIncludes(P.getQualifiers()))
+ if (!A.getQualifiers().compatiblyIncludes(P.getQualifiers(),
+ S.getASTContext()))
return TemplateDeductionResult::NonDeducedMismatch;
// Strip out all extra qualifiers from the argument to figure out the
@@ -3772,7 +3773,7 @@ CheckOriginalCallArgDeduction(Sema &S, TemplateDeductionInfo &Info,
if (AQuals == DeducedAQuals) {
// Qualifiers match; there's nothing to do.
- } else if (!DeducedAQuals.compatiblyIncludes(AQuals)) {
+ } else if (!DeducedAQuals.compatiblyIncludes(AQuals, S.getASTContext())) {
return Failed();
} else {
// Qualifiers are compatible, so have the argument type adopt the
diff --git a/clang/test/CodeGen/target-addrspace.cpp b/clang/test/CodeGen/target-addrspace.cpp
new file mode 100644
index 00000000000000..9adf53611bc242
--- /dev/null
+++ b/clang/test/CodeGen/target-addrspace.cpp
@@ -0,0 +1,140 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
+// RUN: %clang_cc1 -triple nvptx64-nvidia-cuda -emit-llvm \
+// RUN: -fvisibility=hidden -o - %s | FileCheck %s --check-prefix=NVPTX
+// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -emit-llvm \
+// RUN: -fvisibility=hidden -o - %s | FileCheck %s --check-prefix=AMDGPU
+
+// NVPTX-LABEL: define hidden void @_Z1fPv(
+// NVPTX-SAME: ptr noundef [[P:%.*]]) #[[ATTR0:[0-9]+]] {
+// NVPTX-NEXT: [[ENTRY:.*:]]
+// NVPTX-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 8
+// NVPTX-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 8
+// NVPTX-NEXT: ret void
+//
+// AMDGPU-LABEL: define hidden void @_Z1fPv(
+// AMDGPU-SAME: ptr noundef [[P:%.*]]) #[[ATTR0:[0-9]+]] {
+// AMDGPU-NEXT: [[ENTRY:.*:]]
+// AMDGPU-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// AMDGPU-NEXT: [[P_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[P_ADDR]] to ptr
+// AMDGPU-NEXT: store ptr [[P]], ptr [[P_ADDR_ASCAST]], align 8
+// AMDGPU-NEXT: ret void
+//
+void f(void *p) {}
+
+// NVPTX-LABEL: define hidden void @_Z2p1Pv(
+// NVPTX-SAME: ptr noundef [[P:%.*]]) #[[ATTR0]] {
+// NVPTX-NEXT: [[ENTRY:.*:]]
+// NVPTX-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 8
+// NVPTX-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 8
+// NVPTX-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 8
+// NVPTX-NEXT: call void @_Z1fPv(ptr noundef [[TMP0]]) #[[ATTR1:[0-9]+]]
+// NVPTX-NEXT: ret void
+//
+// AMDGPU-LABEL: define hidden void @_Z2p1Pv(
+// AMDGPU-SAME: ptr noundef [[P:%.*]]) #[[ATTR0]] {
+// AMDGPU-NEXT: [[ENTRY:.*:]]
+// AMDGPU-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// AMDGPU-NEXT: [[P_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[P_ADDR]] to ptr
+// AMDGPU-NEXT: store ptr [[P]], ptr [[P_ADDR_ASCAST]], align 8
+// AMDGPU-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR_ASCAST]], align 8
+// AMDGPU-NEXT: call void @_Z1fPv(ptr noundef [[TMP0]]) #[[ATTR1:[0-9]+]]
+// AMDGPU-NEXT: ret void
+//
+void p1(void [[clang::address_space(0)]] * p) { f(p); }
+// NVPTX-LABEL: define hidden noundef ptr @_Z2p2PU3AS3v(
+// NVPTX-SAME: ptr addrspace(3) noundef [[P:%.*]]) #[[ATTR0]] {
+// NVPTX-NEXT: [[ENTRY:.*:]]
+// NVPTX-NEXT: [[P_ADDR:%.*]] = alloca ptr addrspace(3), align 8
+// NVPTX-NEXT: store ptr addrspace(3) [[P]], ptr [[P_ADDR]], align 8
+// NVPTX-NEXT: [[TMP0:%.*]] = load ptr addrspace(3), ptr [[P_ADDR]], align 8
+// NVPTX-NEXT: [[TMP1:%.*]] = addrspacecast ptr addrspace(3) [[TMP0]] to ptr
+// NVPTX-NEXT: ret ptr [[TMP1]]
+//
+// AMDGPU-LABEL: define hidden noundef ptr @_Z2p2PU3AS3v(
+// AMDGPU-SAME: ptr addrspace(3) noundef [[P:%.*]]) #[[ATTR0]] {
+// AMDGPU-NEXT: [[ENTRY:.*:]]
+// AMDGPU-NEXT: [[RETVAL:%.*]] = alloca ptr, align 8, addrspace(5)
+// AMDGPU-NEXT: [[P_ADDR:%.*]] = alloca ptr addrspace(3), align 4, addrspace(5)
+// AMDGPU-NEXT: [[RETVAL_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[RETVAL]] to ptr
+// AMDGPU-NEXT: [[P_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[P_ADDR]] to ptr
+// AMDGPU-NEXT: store ptr addrspace(3) [[P]], ptr [[P_ADDR_ASCAST]], align 4
+// AMDGPU-NEXT: [[TMP0:%.*]] = load ptr addrspace(3), ptr [[P_ADDR_ASCAST]], align 4
+// AMDGPU-NEXT: [[TMP1:%.*]] = addrspacecast ptr addrspace(3) [[TMP0]] to ptr
+// AMDGPU-NEXT: ret ptr [[TMP1]]
+//
+void *p2(void [[clang::address_space(3)]] * p) { return p; }
+// NVPTX-LABEL: define hidden noundef ptr @_Z2p3PU3AS3v(
+// NVPTX-SAME: ptr addrspace(3) noundef [[P:%.*]]) #[[ATTR0]] {
+// NVPTX-NEXT: [[ENTRY:.*:]]
+// NVPTX-NEXT: [[P_ADDR:%.*]] = alloca ptr addrspace(3), align 8
+// NVPTX-NEXT: store ptr addrspace(3) [[P]], ptr [[P_ADDR]], align 8
+// NVPTX-NEXT: [[TMP0:%.*]] = load ptr addrspace(3), ptr [[P_ADDR]], align 8
+// NVPTX-NEXT: [[TMP1:%.*]] = addrspacecast ptr addrspace(3) [[TMP0]] to ptr
+// NVPTX-NEXT: ret ptr [[TMP1]]
+//
+// AMDGPU-LABEL: define hidden noundef ptr @_Z2p3PU3AS3v(
+// AMDGPU-SAME: ptr addrspace(3) noundef [[P:%.*]]) #[[ATTR0]] {
+// AMDGPU-NEXT: [[ENTRY:.*:]]
+// AMDGPU-NEXT: [[RETVAL:%.*]] = alloca ptr, align 8, addrspace(5)
+// AMDGPU-NEXT: [[P_ADDR:%.*]] = alloca ptr addrspace(3), align 4, addrspace(5)
+// AMDGPU-NEXT: [[RETVAL_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[RETVAL]] to ptr
+// AMDGPU-NEXT: [[P_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[P_ADDR]] to ptr
+// AMDGPU-NEXT: store ptr addrspace(3) [[P]], ptr [[P_ADDR_ASCAST]], align 4
+// AMDGPU-NEXT: [[TMP0:%.*]] = load ptr addrspace(3), ptr [[P_ADDR_ASCAST]], align 4
+// AMDGPU-NEXT: [[TMP1:%.*]] = addrspacecast ptr addrspace(3) [[TMP0]] to ptr
+// AMDGPU-NEXT: ret ptr [[TMP1]]
+//
+void *p3(void [[clang::address_space(3)]] * p) { return p; }
+
+struct S {
+ S() = default;
+ ~S() = default;
+ void foo() {}
+};
+
+S s1;
+S [[clang::address_space(1)]] s2;
+S [[clang::address_space(3)]] s3;
+
+template <typename Ty> void foo(Ty *) {}
+
+// NVPTX-LABEL: define hidden void @_Z2t1Pv(
+// NVPTX-SAME: ptr noundef [[P:%.*]]) #[[ATTR0]] {
+// NVPTX-NEXT: [[ENTRY:.*:]]
+// NVPTX-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 8
+// NVPTX-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 8
+// NVPTX-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 8
+// NVPTX-NEXT: call void @_Z3fooIvEvPT_(ptr noundef [[TMP0]]) #[[ATTR1]]
+// NVPTX-NEXT: ret void
+//
+// AMDGPU-LABEL: define hidden void @_Z2t1Pv(
+// AMDGPU-SAME: ptr noundef [[P:%.*]]) #[[ATTR0]] {
+// AMDGPU-NEXT: [[ENTRY:.*:]]
+// AMDGPU-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// AMDGPU-NEXT: [[P_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[P_ADDR]] to ptr
+// AMDGPU-NEXT: store ptr [[P]], ptr [[P_ADDR_ASCAST]], align 8
+// AMDGPU-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR_ASCAST]], align 8
+// AMDGPU-NEXT: call void @_Z3fooIvEvPT_(ptr noundef [[TMP0]]) #[[ATTR1]]
+// AMDGPU-NEXT: ret void
+//
+void t1(void *p) { foo(p); }
+// NVPTX-LABEL: define hidden void @_Z2t3PU3AS3v(
+// NVPTX-SAME: ptr addrspace(3) noundef [[P:%.*]]) #[[ATTR0]] {
+// NVPTX-NEXT: [[ENTRY:.*:]]
+// NVPTX-NEXT: [[P_ADDR:%.*]] = alloca ptr addrspace(3), align 8
+// NVPTX-NEXT: store ptr addrspace(3) [[P]], ptr [[P_ADDR]], align 8
+// NVPTX-NEXT: [[TMP0:%.*]] = load ptr addrspace(3), ptr [[P_ADDR]], align 8
+// NVPTX-NEXT: call void @_Z3fooIU3AS3vEvPT_(ptr addrspace(3) noundef [[TMP0]]) #[[ATTR1]]
+// NVPTX-NEXT: ret void
+//
+// AMDGPU-LABEL: define hidden void @_Z2t3PU3AS3v(
+// AMDGPU-SAME: ptr addrspace(3) noundef [[P:%.*]]) #[[ATTR0]] {
+// AMDGPU-NEXT: [[ENTRY:.*:]]
+// AMDGPU-NEXT: [[P_ADDR:%.*]] = alloca ptr addrspace(3), align 4, addrspace(5)
+// AMDGPU-NEXT: [[P_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[P_ADDR]] to ptr
+// AMDGPU-NEXT: store ptr addrspace(3) [[P]], ptr [[P_ADDR_ASCAST]], align 4
+// AMDGPU-NEXT: [[TMP0:%.*]] = load ptr addrspace(3), ptr [[P_ADDR_ASCAST]], align 4
+// AMDGPU-NEXT: call void @_Z3fooIU3AS3vEvPT_(ptr addrspace(3) noundef [[TMP0]]) #[[ATTR1]]
+// AMDGPU-NEXT: ret void
+//
+void t3(void [[clang::address_space(3)]] *p) { foo(p); }
diff --git a/clang/test/Sema/amdgcn-address-spaces.c b/clang/test/Sema/amdgcn-address-spaces.c
new file mode 100644
index 00000000000000..50c12993ac69b8
--- /dev/null
+++ b/clang/test/Sema/amdgcn-address-spaces.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 %s -triple amdgcn-amd-amdhsa -fsyntax-only -verify
+
+#define _AS0 __attribute__((address_space(0)))
+#define _AS1 __attribute__((address_space(1)))
+#define _AS2 __attribute__((address_space(2)))
+#define _AS3 __attribute__((address_space(3)))
+#define _AS4 __attribute__((address_space(4)))
+#define _AS5 __attribute__((address_space(5)))
+#define _AS999 __attribute__((address_space(999)))
+
+void *p1(void _AS1 *p) { return p; }
+void *p2(void _AS2 *p) { return p; }
+void *p3(void _AS3 *p) { return p; }
+void *p4(void _AS4 *p) { return p; }
+void *p5(void _AS5 *p) { return p; }
+void *pi(void _AS999 *p) { return p; } // expected-error {{returning '_AS999 void *' from a function with result type 'void *' changes address space of pointer}}
+void *pc(void __attribute__((opencl_local)) *p) { return p; } // expected-error {{returning '__local void *' from a function with result type 'void *' changes address space of pointer}}
+void _AS1 *r0(void _AS1 *p) { return p; }
+void _AS1 *r1(void *p) { return p; } // expected-error {{returning 'void *' from a function with result type '_AS1 void *' changes address space of pointer}}
+void _AS1 *r2(void *p) { return (void _AS1 *)p; }
diff --git a/clang/test/Sema/nvptx-address-spaces.c b/clang/test/Sema/nvptx-address-spaces.c
new file mode 100644
index 00000000000000..184feef9612e57
--- /dev/null
+++ b/clang/test/Sema/nvptx-address-spaces.c
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 %s -triple nvptx64-nvidia-cuda -fsyntax-only -verify
+
+#define _AS0 __attribute__((address_space(0)))
+#define _AS1 __attribute__((address_space(1)))
+#define _AS2 __attribute__((address_space(2)))
+#define _AS3 __attribute__((address_space(3)))
+#define _AS4 __attribute__((address_space(4)))
+#define _AS5 __attribute__((address_space(5)))
+#define _AS999 __attribute__((address_space(999)))
+
+void *p1(void _AS1 *p) { return p; }
+void *p2(void _AS2 *p) { return p; } // expected-error {{returning '_AS2 void *' from a function with result type 'void *' changes address space of pointer}}
+void *p3(void _AS3 *p) { return p; }
+void *p4(void _AS4 *p) { return p; }
+void *p5(void _AS5 *p) { return p; }
+void *pi(void _AS999 *p) { return p; } // expected-error {{returning '_AS999 void *' from a function with result type 'void *' changes address space of pointer}}
+void *pc(void __attribute__((opencl_local)) *p) { return p; } // expected-error {{returning '__local void *' from a function with result type 'void *' changes address space of pointer}}
+void _AS1 *r0(void _AS1 *p) { return p; }
+void _AS1 *r1(void *p) { return p; } // expected-error {{returning 'void *' from a function with result type '_AS1 void *' changes address space of pointer}}
+void _AS1 *r2(void *p) { return (void _AS1 *)p; }
+
>From 80c497c8aaef809845eda00469c5b510736cdfb0 Mon Sep 17 00:00:00 2001
From: Joseph Huber <huberjn at outlook.com>
Date: Wed, 13 Nov 2024 18:45:26 -0600
Subject: [PATCH 2/2] Comments
---
clang/include/clang/AST/Type.h | 34 ++++++++++++++++++++++++++-
clang/lib/AST/Type.cpp | 33 +++-----------------------
clang/lib/Basic/Targets/NVPTX.h | 41 +++++++++++++++++----------------
3 files changed, 57 insertions(+), 51 deletions(-)
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 7f3f413b721bc6..3dd0579bd10d60 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -700,7 +700,39 @@ class Qualifiers {
/// CL2.0 adds:
/// __generic is a superset of any address space except for __constant.
static bool isAddressSpaceSupersetOf(LangAS A, LangAS B,
- const ASTContext &Ctx);
+ 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.
+ isTargetAddressSpaceSupersetOf(A, B, Ctx);
+ }
+
+ static bool isTargetAddressSpaceSupersetOf(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.
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 22d9ae17b39c2b..43579aaa9d3a4c 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -73,36 +73,9 @@ 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);
+bool Qualifiers::isTargetAddressSpaceSupersetOf(LangAS A, LangAS B,
+ const ASTContext &Ctx) {
+ return Ctx.getTargetInfo().isAddressSpaceSupersetOf(A, B);
}
const IdentifierInfo* QualType::getBaseTypeIdentifier() const {
diff --git a/clang/lib/Basic/Targets/NVPTX.h b/clang/lib/Basic/Targets/NVPTX.h
index 3402f32dbde20c..d81b89a7f24ac0 100644
--- a/clang/lib/Basic/Targets/NVPTX.h
+++ b/clang/lib/Basic/Targets/NVPTX.h
@@ -25,26 +25,27 @@ namespace clang {
namespace targets {
static const unsigned NVPTXAddrSpaceMap[] = {
- llvm::NVPTXAS::ADDRESS_SPACE_GENERIC, // Default
- llvm::NVPTXAS::ADDRESS_SPACE_GLOBAL, // opencl_global
- llvm::NVPTXAS::ADDRESS_SPACE_SHARED, // opencl_local
- llvm::NVPTXAS::ADDRESS_SPACE_CONST, // opencl_constant
- llvm::NVPTXAS::ADDRESS_SPACE_GENERIC, // opencl_private
- llvm::NVPTXAS::ADDRESS_SPACE_GENERIC, // opencl_generic
- llvm::NVPTXAS::ADDRESS_SPACE_GLOBAL, // opencl_global_device
- llvm::NVPTXAS::ADDRESS_SPACE_GLOBAL, // opencl_global_host
- llvm::NVPTXAS::ADDRESS_SPACE_GLOBAL, // cuda_device
- llvm::NVPTXAS::ADDRESS_SPACE_CONST, // cuda_constant
- llvm::NVPTXAS::ADDRESS_SPACE_SHARED, // cuda_shared
- llvm::NVPTXAS::ADDRESS_SPACE_GLOBAL, // sycl_global
- llvm::NVPTXAS::ADDRESS_SPACE_GLOBAL, // sycl_global_device
- llvm::NVPTXAS::ADDRESS_SPACE_GLOBAL, // sycl_global_host
- llvm::NVPTXAS::ADDRESS_SPACE_SHARED, // sycl_local
- llvm::NVPTXAS::ADDRESS_SPACE_GENERIC, // sycl_private
- llvm::NVPTXAS::ADDRESS_SPACE_GENERIC, // ptr32_sptr
- llvm::NVPTXAS::ADDRESS_SPACE_GENERIC, // ptr32_uptr
- llvm::NVPTXAS::ADDRESS_SPACE_GENERIC, // ptr64
- llvm::NVPTXAS::ADDRESS_SPACE_GENERIC, // hlsl_groupshared
+ 0, // Default
+ 1, // opencl_global
+ 3, // opencl_local
+ 4, // opencl_constant
+ 0, // opencl_private
+ // FIXME: generic has to be added to the target
+ 0, // opencl_generic
+ 1, // opencl_global_device
+ 1, // opencl_global_host
+ 1, // cuda_device
+ 4, // cuda_constant
+ 3, // cuda_shared
+ 1, // sycl_global
+ 1, // sycl_global_device
+ 1, // sycl_global_host
+ 3, // sycl_local
+ 0, // sycl_private
+ 0, // ptr32_sptr
+ 0, // ptr32_uptr
+ 0, // ptr64
+ 0, // hlsl_groupshared
// Wasm address space values for this target are dummy values,
// as it is only enabled for Wasm targets.
20, // wasm_funcref
More information about the cfe-commits
mailing list