r266111 - PR19957: [OpenCL] Incorrectly accepts implicit address space conversion with ternary operator.
Yaxun Liu via cfe-commits
cfe-commits at lists.llvm.org
Tue Apr 12 12:43:37 PDT 2016
Author: yaxunl
Date: Tue Apr 12 14:43:36 2016
New Revision: 266111
URL: http://llvm.org/viewvc/llvm-project?rev=266111&view=rev
Log:
PR19957: [OpenCL] Incorrectly accepts implicit address space conversion with ternary operator.
Generates addrspacecast instead of bitcast for ternary operator when necessary, and diagnose ternary operator with incompatible second and third operands.
https://llvm.org/bugs/show_bug.cgi?id=19957
Differential Revision: http://reviews.llvm.org/D17412
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/AST/ASTContext.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/test/CodeGenOpenCL/address-spaces-conversions.cl
cfe/trunk/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=266111&r1=266110&r2=266111&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Apr 12 14:43:36 2016
@@ -5376,7 +5376,9 @@ def ext_typecheck_comparison_of_distinct
"composite pointer type %2">, InGroup<CompareDistinctPointerType>;
def err_typecheck_op_on_nonoverlapping_address_space_pointers : Error<
"%select{comparison between %diff{ ($ and $)|}0,1"
- "|arithmetic operation with operands of type %diff{ ($ and $)|}0,1}2"
+ "|arithmetic operation with operands of type %diff{ ($ and $)|}0,1"
+ "|conditional operator with the second and third operands of type "
+ "%diff{ ($ and $)|}0,1}2"
" which are pointers to non-overlapping address spaces">;
def err_typecheck_assign_const : Error<
Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=266111&r1=266110&r2=266111&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Tue Apr 12 14:43:36 2016
@@ -7617,6 +7617,15 @@ QualType ASTContext::mergeTypes(QualType
Qualifiers LQuals = LHSCan.getLocalQualifiers();
Qualifiers RQuals = RHSCan.getLocalQualifiers();
if (LQuals != RQuals) {
+ if (getLangOpts().OpenCL) {
+ if (LHS.getUnqualifiedType() != RHS.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() ||
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=266111&r1=266110&r2=266111&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Apr 12 14:43:36 2016
@@ -6193,30 +6193,87 @@ static QualType checkConditionalPointerC
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()) {
- S.Diag(Loc, diag::ext_typecheck_cond_incompatible_pointers)
- << LHSTy << RHSTy << LHS.get()->getSourceRange()
- << RHS.get()->getSourceRange();
// 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 = S.Context.getPointerType(S.Context.VoidTy);
- LHS = S.ImpCastExprToType(LHS.get(), incompatTy, CK_BitCast);
- RHS = S.ImpCastExprToType(RHS.get(), incompatTy, CK_BitCast);
+ 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);
+ }
return incompatTy;
}
// The pointer types are compatible.
QualType ResultTy = CompositeTy.withCVRQualifiers(MergedCVRQual);
+ auto LHSCastKind = CK_BitCast, RHSCastKind = CK_BitCast;
if (IsBlockPointer)
ResultTy = S.Context.getBlockPointerType(ResultTy);
- else
+ 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);
+ }
- LHS = S.ImpCastExprToType(LHS.get(), ResultTy, CK_BitCast);
- RHS = S.ImpCastExprToType(RHS.get(), ResultTy, CK_BitCast);
+ // 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;
}
Modified: cfe/trunk/test/CodeGenOpenCL/address-spaces-conversions.cl
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenOpenCL/address-spaces-conversions.cl?rev=266111&r1=266110&r2=266111&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenOpenCL/address-spaces-conversions.cl (original)
+++ cfe/trunk/test/CodeGenOpenCL/address-spaces-conversions.cl Tue Apr 12 14:43:36 2016
@@ -5,6 +5,7 @@
// test that we generate address space casts everywhere we need conversions of
// pointers to different address spaces
+// CHECK: define void @test
void test(global int *arg_glob, generic int *arg_gen) {
int var_priv;
arg_gen = arg_glob; // implicit cast global -> generic
@@ -39,3 +40,41 @@ void test(global int *arg_glob, generic
// CHECK-NOFAKE: bitcast
// CHECK-NOFAKE-NOT: addrspacecast
}
+
+// Test ternary operator.
+// CHECK: define void @test_ternary
+void test_ternary(void) {
+ global int *var_glob;
+ generic int *var_gen;
+ generic int *var_gen2;
+ generic float *var_gen_f;
+ generic void *var_gen_v;
+
+ var_gen = var_gen ? var_gen : var_gen2; // operands of the same addr spaces and the same type
+ // CHECK: icmp
+ // CHECK-NOT: addrspacecast
+ // CHECK-NOT: bitcast
+ // CHECK: phi
+ // CHECK: store i32 addrspace(4)* %{{.+}}, i32 addrspace(4)** %{{.+}}
+
+ var_gen = var_gen ? var_gen : var_glob; // operands of overlapping addr spaces and the same type
+ // CHECK: icmp
+ // CHECK-NOT: bitcast
+ // CHECK: %{{.+}} = addrspacecast i32 addrspace(1)* %{{.+}} to i32 addrspace(4)*
+ // CHECK: phi
+ // CHECK: store
+
+ var_gen_v = var_gen ? var_gen : var_gen_f; // operands of the same addr space and different types
+ // CHECK: icmp
+ // CHECK: %{{.+}} = bitcast i32 addrspace(4)* %{{.+}} to i8 addrspace(4)*
+ // CHECK: %{{.+}} = bitcast float addrspace(4)* %{{.+}} to i8 addrspace(4)*
+ // CHECK: phi
+ // CHECK: store
+
+ var_gen_v = var_gen ? var_glob : var_gen_f; // operands of overlapping addr spaces and different types
+ // CHECK: icmp
+ // CHECK: %{{.+}} = addrspacecast i32 addrspace(1)* %{{.+}} to i8 addrspace(4)*
+ // CHECK: %{{.+}} = bitcast float addrspace(4)* %{{.+}} to i8 addrspace(4)*
+ // CHECK: phi
+ // CHECK: store
+}
Modified: cfe/trunk/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl?rev=266111&r1=266110&r2=266111&view=diff
==============================================================================
--- cfe/trunk/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl (original)
+++ cfe/trunk/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl Tue Apr 12 14:43:36 2016
@@ -225,3 +225,69 @@ void test_conversion(global int *arg_glo
// expected-error at -2{{passing '__constant int *' to parameter of type '__generic int *' changes address space of pointer}}
#endif
}
+
+void test_ternary() {
+ AS int *var_cond;
+ generic int *var_gen;
+ global int *var_glob;
+ var_gen = 0 ? var_cond : var_glob;
+#ifdef CONSTANT
+// expected-error at -2{{conditional operator with the second and third operands of type ('__constant int *' and '__global int *') which are pointers to non-overlapping address spaces}}
+#endif
+
+ local int *var_loc;
+ var_gen = 0 ? var_cond : var_loc;
+#ifndef GENERIC
+// expected-error-re at -2{{conditional operator with the second and third operands of type ('__{{global|constant}} int *' and '__local int *') which are pointers to non-overlapping address spaces}}
+#endif
+
+ constant int *var_const;
+ var_cond = 0 ? var_cond : var_const;
+#ifndef CONSTANT
+// expected-error-re at -2{{conditional operator with the second and third operands of type ('__{{global|generic}} int *' and '__constant int *') which are pointers to non-overlapping address spaces}}
+#endif
+
+ private int *var_priv;
+ var_gen = 0 ? var_cond : var_priv;
+#ifndef GENERIC
+// expected-error-re at -2{{conditional operator with the second and third operands of type ('__{{global|constant}} int *' and 'int *') which are pointers to non-overlapping address spaces}}
+#endif
+
+ var_gen = 0 ? var_cond : var_gen;
+#ifdef CONSTANT
+// expected-error at -2{{conditional operator with the second and third operands of type ('__constant int *' and '__generic int *') which are pointers to non-overlapping address spaces}}
+#endif
+
+ void *var_void_gen;
+ global char *var_glob_ch;
+ var_void_gen = 0 ? var_cond : var_glob_ch;
+#ifdef CONSTANT
+// expected-error at -2{{conditional operator with the second and third operands of type ('__constant int *' and '__global char *') which are pointers to non-overlapping address spaces}}
+#endif
+
+ local char *var_loc_ch;
+ var_void_gen = 0 ? var_cond : var_loc_ch;
+#ifndef GENERIC
+// expected-error-re at -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}}
+#endif
+
+ constant void *var_void_const;
+ constant char *var_const_ch;
+ var_void_const = 0 ? var_cond : var_const_ch;
+#ifndef CONSTANT
+// expected-error-re at -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}}
+#endif
+
+ private char *var_priv_ch;
+ var_void_gen = 0 ? var_cond : var_priv_ch;
+#ifndef GENERIC
+// expected-error-re at -2{{conditional operator with the second and third operands of type ('__{{global|constant}} int *' and 'char *') which are pointers to non-overlapping address spaces}}
+#endif
+
+ generic char *var_gen_ch;
+ var_void_gen = 0 ? var_cond : var_gen_ch;
+#ifdef CONSTANT
+// expected-error at -2{{conditional operator with the second and third operands of type ('__constant int *' and '__generic char *') which are pointers to non-overlapping address spaces}}
+#endif
+}
+
More information about the cfe-commits
mailing list