diff options
Diffstat (limited to 'clang')
| -rw-r--r-- | clang/lib/AST/ASTContext.cpp | 23 | ||||
| -rw-r--r-- | clang/lib/AST/ItaniumMangle.cpp | 4 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 147 | ||||
| -rw-r--r-- | clang/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl | 37 | ||||
| -rw-r--r-- | clang/test/SemaOpenCL/overload_addrspace_resolution.cl | 29 |
5 files changed, 167 insertions, 73 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index b9264051b63..e8f98929de6 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -8066,15 +8066,6 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, Qualifiers LQuals = LHSCan.getLocalQualifiers(); Qualifiers RQuals = RHSCan.getLocalQualifiers(); if (LQuals != RQuals) { - if (getLangOpts().OpenCL) { - if (LHSCan.getUnqualifiedType() != RHSCan.getUnqualifiedType() || - LQuals.getCVRQualifiers() != RQuals.getCVRQualifiers()) - return QualType(); - if (LQuals.isAddressSpaceSupersetOf(RQuals)) - return LHS; - if (RQuals.isAddressSpaceSupersetOf(LQuals)) - return RHS; - } // If any of these qualifiers are different, we have a type // mismatch. if (LQuals.getCVRQualifiers() != RQuals.getCVRQualifiers() || @@ -8200,6 +8191,20 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, LHSPointee = LHSPointee.getUnqualifiedType(); RHSPointee = RHSPointee.getUnqualifiedType(); } + if (getLangOpts().OpenCL) { + Qualifiers LHSPteeQual = LHSPointee.getQualifiers(); + 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)) + return QualType(); + LHSPteeQual.removeAddressSpace(); + RHSPteeQual.removeAddressSpace(); + LHSPointee = + QualType(LHSPointee.getTypePtr(), LHSPteeQual.getAsOpaqueValue()); + RHSPointee = + QualType(RHSPointee.getTypePtr(), RHSPteeQual.getAsOpaqueValue()); + } QualType ResultType = mergeTypes(LHSPointee, RHSPointee, OfBlockPointer, Unqualified); if (ResultType.isNull()) return QualType(); diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 82ae9c0e328..dd99f2087f8 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -2159,10 +2159,12 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals) { } else { switch (AS) { default: llvm_unreachable("Not a language specific address space"); - // <OpenCL-addrspace> ::= "CL" [ "global" | "local" | "constant" ] + // <OpenCL-addrspace> ::= "CL" [ "global" | "local" | "constant | + // "generic" ] case LangAS::opencl_global: ASString = "CLglobal"; break; case LangAS::opencl_local: ASString = "CLlocal"; break; case LangAS::opencl_constant: ASString = "CLconstant"; break; + case LangAS::opencl_generic: ASString = "CLgeneric"; break; // <CUDA-addrspace> ::= "CU" [ "device" | "constant" | "shared" ] case LangAS::cuda_device: ASString = "CUdevice"; break; case LangAS::cuda_constant: ASString = "CUconstant"; break; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index e422fe02263..88f32bb6b3b 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -6335,92 +6335,98 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS, Qualifiers lhQual = lhptee.getQualifiers(); Qualifiers rhQual = rhptee.getQualifiers(); + unsigned ResultAddrSpace = 0; + unsigned LAddrSpace = lhQual.getAddressSpace(); + unsigned RAddrSpace = rhQual.getAddressSpace(); + if (S.getLangOpts().OpenCL) { + // OpenCL v1.1 s6.5 - Conversion between pointers to distinct address + // spaces is disallowed. + if (lhQual.isAddressSpaceSupersetOf(rhQual)) + ResultAddrSpace = LAddrSpace; + else if (rhQual.isAddressSpaceSupersetOf(lhQual)) + ResultAddrSpace = RAddrSpace; + else { + S.Diag(Loc, + diag::err_typecheck_op_on_nonoverlapping_address_space_pointers) + << LHSTy << RHSTy << 2 << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); + return QualType(); + } + } + unsigned MergedCVRQual = lhQual.getCVRQualifiers() | rhQual.getCVRQualifiers(); + auto LHSCastKind = CK_BitCast, RHSCastKind = CK_BitCast; lhQual.removeCVRQualifiers(); rhQual.removeCVRQualifiers(); + // OpenCL v2.0 specification doesn't extend compatibility of type qualifiers + // (C99 6.7.3) for address spaces. We assume that the check should behave in + // the same manner as it's defined for CVR qualifiers, so for OpenCL two + // qual types are compatible iff + // * corresponded types are compatible + // * CVR qualifiers are equal + // * address spaces are equal + // Thus for conditional operator we merge CVR and address space unqualified + // pointees and if there is a composite type we return a pointer to it with + // merged qualifiers. + if (S.getLangOpts().OpenCL) { + LHSCastKind = LAddrSpace == ResultAddrSpace + ? CK_BitCast + : CK_AddressSpaceConversion; + RHSCastKind = RAddrSpace == ResultAddrSpace + ? CK_BitCast + : CK_AddressSpaceConversion; + lhQual.removeAddressSpace(); + rhQual.removeAddressSpace(); + } + lhptee = S.Context.getQualifiedType(lhptee.getUnqualifiedType(), lhQual); rhptee = S.Context.getQualifiedType(rhptee.getUnqualifiedType(), rhQual); - // For OpenCL: - // 1. If LHS and RHS types match exactly and: - // (a) AS match => use standard C rules, no bitcast or addrspacecast - // (b) AS overlap => generate addrspacecast - // (c) AS don't overlap => give an error - // 2. if LHS and RHS types don't match: - // (a) AS match => use standard C rules, generate bitcast - // (b) AS overlap => generate addrspacecast instead of bitcast - // (c) AS don't overlap => give an error - - // For OpenCL, non-null composite type is returned only for cases 1a and 1b. QualType CompositeTy = S.Context.mergeTypes(lhptee, rhptee); - // OpenCL cases 1c, 2a, 2b, and 2c. if (CompositeTy.isNull()) { // In this situation, we assume void* type. No especially good // reason, but this is what gcc does, and we do have to pick // to get a consistent AST. QualType incompatTy; - if (S.getLangOpts().OpenCL) { - // OpenCL v1.1 s6.5 - Conversion between pointers to distinct address - // spaces is disallowed. - unsigned ResultAddrSpace; - if (lhQual.isAddressSpaceSupersetOf(rhQual)) { - // Cases 2a and 2b. - ResultAddrSpace = lhQual.getAddressSpace(); - } else if (rhQual.isAddressSpaceSupersetOf(lhQual)) { - // Cases 2a and 2b. - ResultAddrSpace = rhQual.getAddressSpace(); - } else { - // Cases 1c and 2c. - S.Diag(Loc, - diag::err_typecheck_op_on_nonoverlapping_address_space_pointers) - << LHSTy << RHSTy << 2 << LHS.get()->getSourceRange() - << RHS.get()->getSourceRange(); - return QualType(); - } - - // Continue handling cases 2a and 2b. - incompatTy = S.Context.getPointerType( - S.Context.getAddrSpaceQualType(S.Context.VoidTy, ResultAddrSpace)); - LHS = S.ImpCastExprToType(LHS.get(), incompatTy, - (lhQual.getAddressSpace() != ResultAddrSpace) - ? CK_AddressSpaceConversion /* 2b */ - : CK_BitCast /* 2a */); - RHS = S.ImpCastExprToType(RHS.get(), incompatTy, - (rhQual.getAddressSpace() != ResultAddrSpace) - ? CK_AddressSpaceConversion /* 2b */ - : CK_BitCast /* 2a */); - } else { - S.Diag(Loc, diag::ext_typecheck_cond_incompatible_pointers) - << LHSTy << RHSTy << LHS.get()->getSourceRange() - << RHS.get()->getSourceRange(); - incompatTy = S.Context.getPointerType(S.Context.VoidTy); - LHS = S.ImpCastExprToType(LHS.get(), incompatTy, CK_BitCast); - RHS = S.ImpCastExprToType(RHS.get(), incompatTy, CK_BitCast); - } + incompatTy = S.Context.getPointerType( + S.Context.getAddrSpaceQualType(S.Context.VoidTy, ResultAddrSpace)); + LHS = S.ImpCastExprToType(LHS.get(), incompatTy, LHSCastKind); + RHS = S.ImpCastExprToType(RHS.get(), incompatTy, RHSCastKind); + // FIXME: For OpenCL the warning emission and cast to void* leaves a room + // for casts between types with incompatible address space qualifiers. + // For the following code the compiler produces casts between global and + // local address spaces of the corresponded innermost pointees: + // local int *global *a; + // global int *global *b; + // a = (0 ? a : b); // see C99 6.5.16.1.p1. + S.Diag(Loc, diag::ext_typecheck_cond_incompatible_pointers) + << LHSTy << RHSTy << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); return incompatTy; } // The pointer types are compatible. - QualType ResultTy = CompositeTy.withCVRQualifiers(MergedCVRQual); - auto LHSCastKind = CK_BitCast, RHSCastKind = CK_BitCast; + // In case of OpenCL ResultTy should have the address space qualifier + // which is a superset of address spaces of both the 2nd and the 3rd + // operands of the conditional operator. + QualType ResultTy = [&, ResultAddrSpace]() { + if (S.getLangOpts().OpenCL) { + Qualifiers CompositeQuals = CompositeTy.getQualifiers(); + CompositeQuals.setAddressSpace(ResultAddrSpace); + return S.Context + .getQualifiedType(CompositeTy.getUnqualifiedType(), CompositeQuals) + .withCVRQualifiers(MergedCVRQual); + } else + return CompositeTy.withCVRQualifiers(MergedCVRQual); + }(); if (IsBlockPointer) ResultTy = S.Context.getBlockPointerType(ResultTy); else { - // Cases 1a and 1b for OpenCL. - auto ResultAddrSpace = ResultTy.getQualifiers().getAddressSpace(); - LHSCastKind = lhQual.getAddressSpace() == ResultAddrSpace - ? CK_BitCast /* 1a */ - : CK_AddressSpaceConversion /* 1b */; - RHSCastKind = rhQual.getAddressSpace() == ResultAddrSpace - ? CK_BitCast /* 1a */ - : CK_AddressSpaceConversion /* 1b */; ResultTy = S.Context.getPointerType(ResultTy); } - // For case 1a of OpenCL, S.ImpCastExprToType will not insert bitcast - // if the target type does not change. LHS = S.ImpCastExprToType(LHS.get(), ResultTy, LHSCastKind); RHS = S.ImpCastExprToType(RHS.get(), ResultTy, RHSCastKind); return ResultTy; @@ -7399,7 +7405,22 @@ checkBlockPointerTypesForAssignment(Sema &S, QualType LHSType, if (LQuals != RQuals) ConvTy = Sema::CompatiblePointerDiscardsQualifiers; - if (!S.Context.typesAreBlockPointerCompatible(LHSType, RHSType)) + // FIXME: OpenCL doesn't define the exact compile time semantics for a block + // assignment. + // The current behavior is similar to C++ lambdas. A block might be + // assigned to a variable iff its return type and parameters are compatible + // (C99 6.2.7) with the corresponding return type and parameters of the LHS of + // an assignment. Presumably it should behave in way that a function pointer + // assignment does in C, so for each parameter and return type: + // * CVR and address space of LHS should be a superset of CVR and address + // space of RHS. + // * unqualified types should be compatible. + if (S.getLangOpts().OpenCL) { + if (!S.Context.typesAreBlockPointerCompatible( + S.Context.getQualifiedType(LHSType.getUnqualifiedType(), LQuals), + S.Context.getQualifiedType(RHSType.getUnqualifiedType(), RQuals))) + return Sema::IncompatibleBlockPointer; + } else if (!S.Context.typesAreBlockPointerCompatible(LHSType, RHSType)) return Sema::IncompatibleBlockPointer; return ConvTy; diff --git a/clang/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl b/clang/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl index 97fd07a24a2..73e29e7879d 100644 --- a/clang/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl +++ b/clang/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl @@ -18,14 +18,20 @@ #ifdef GENERIC #define AS generic +#define AS_COMP local +#define AS_INCOMP constant #endif #ifdef GLOBAL #define AS global +#define AS_COMP global +#define AS_INCOMP local #endif #ifdef CONSTANT #define AS constant +#define AS_COMP constant +#define AS_INCOMP global #endif void f_glob(global int *arg_glob) {} @@ -263,12 +269,16 @@ void test_ternary() { var_void_gen = 0 ? var_cond : var_glob_ch; #ifdef CONSTANT // expected-error@-2{{conditional operator with the second and third operands of type ('__constant int *' and '__global char *') which are pointers to non-overlapping address spaces}} +#else +// expected-warning-re@-4{{pointer type mismatch ('__{{global|generic}} int *' and '__global char *')}} #endif local char *var_loc_ch; var_void_gen = 0 ? var_cond : var_loc_ch; #ifndef GENERIC // expected-error-re@-2{{conditional operator with the second and third operands of type ('__{{global|constant}} int *' and '__local char *') which are pointers to non-overlapping address spaces}} +#else +// expected-warning@-4{{pointer type mismatch ('__generic int *' and '__local char *')}} #endif constant void *var_void_const; @@ -276,18 +286,45 @@ void test_ternary() { var_void_const = 0 ? var_cond : var_const_ch; #ifndef CONSTANT // expected-error-re@-2{{conditional operator with the second and third operands of type ('__{{global|generic}} int *' and '__constant char *') which are pointers to non-overlapping address spaces}} +#else +// expected-warning@-4{{pointer type mismatch ('__constant int *' and '__constant char *')}} #endif private char *var_priv_ch; var_void_gen = 0 ? var_cond : var_priv_ch; #ifndef GENERIC // expected-error-re@-2{{conditional operator with the second and third operands of type ('__{{global|constant}} int *' and 'char *') which are pointers to non-overlapping address spaces}} +#else +// expected-warning@-4{{pointer type mismatch ('__generic int *' and 'char *')}} #endif generic char *var_gen_ch; var_void_gen = 0 ? var_cond : var_gen_ch; #ifdef CONSTANT // expected-error@-2{{conditional operator with the second and third operands of type ('__constant int *' and '__generic char *') which are pointers to non-overlapping address spaces}} +#else +// expected-warning-re@-4{{pointer type mismatch ('__{{global|generic}} int *' and '__generic char *')}} #endif } +void test_pointer_chains() { + AS int *AS *var_as_as_int; + AS int *AS_COMP *var_asc_as_int; + AS_INCOMP int *AS_COMP *var_asc_asn_int; + AS_COMP int *AS_COMP *var_asc_asc_int; + + // Case 1: + // * address spaces of corresponded most outer pointees overlaps, their canonical types are equal + // * CVR, address spaces and canonical types of the rest of pointees are equivalent. + var_as_as_int = 0 ? var_as_as_int : var_asc_as_int; + + // Case 2: Corresponded inner pointees has non-overlapping address spaces. + var_as_as_int = 0 ? var_as_as_int : var_asc_asn_int; +// expected-warning-re@-1{{pointer type mismatch ('__{{(generic|global|constant)}} int *__{{(generic|global|constant)}} *' and '__{{(local|global|constant)}} int *__{{(constant|local|global)}} *')}} + + // Case 3: Corresponded inner pointees has overlapping but not equivalent address spaces. +#ifdef GENERIC + var_as_as_int = 0 ? var_as_as_int : var_asc_asc_int; +// expected-warning-re@-1{{pointer type mismatch ('__{{(generic|global|constant)}} int *__{{(generic|global|constant)}} *' and '__{{(local|global|constant)}} int *__{{(local|global|constant)}} *')}} +#endif +} diff --git a/clang/test/SemaOpenCL/overload_addrspace_resolution.cl b/clang/test/SemaOpenCL/overload_addrspace_resolution.cl new file mode 100644 index 00000000000..fa7b6144a20 --- /dev/null +++ b/clang/test/SemaOpenCL/overload_addrspace_resolution.cl @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -cl-std=CL2.0 -emit-llvm -o - %s | FileCheck %s + +void __attribute__((overloadable)) foo(global int *a, global int *b); +void __attribute__((overloadable)) foo(generic int *a, generic int *b); +void __attribute__((overloadable)) bar(generic int *global *a, generic int *global *b); +void __attribute__((overloadable)) bar(generic int *generic *a, generic int *generic *b); + +void kernel ker() { + global int *a; + global int *b; + generic int *c; + local int *d; + generic int *generic *gengen; + generic int *local *genloc; + generic int *global *genglob; + // CHECK: call void @_Z3fooPU8CLglobaliS0_(i32* undef, i32* undef) + foo(a, b); + // CHECK: call void @_Z3fooPU9CLgenericiS0_(i32* undef, i32* undef) + foo(b, c); + // CHECK: call void @_Z3fooPU9CLgenericiS0_(i32* undef, i32* undef) + foo(a, d); + + // CHECK: call void @_Z3barPU9CLgenericPU9CLgenericiS2_(i32** undef, i32** undef) + bar(gengen, genloc); + // CHECK: call void @_Z3barPU9CLgenericPU9CLgenericiS2_(i32** undef, i32** undef) + bar(gengen, genglob); + // CHECK: call void @_Z3barPU8CLglobalPU9CLgenericiS2_(i32** undef, i32** undef) + bar(genglob, genglob); +} |

