forked from OSchip/llvm-project
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 llvm-svn: 266111
This commit is contained in:
parent
49bd58f1eb
commit
a1a87adf59
|
@ -5376,7 +5376,9 @@ def ext_typecheck_comparison_of_distinct_pointers_nonstandard : ExtWarn<
|
|||
"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<
|
||||
|
|
|
@ -7617,6 +7617,15 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
|
|||
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() ||
|
||||
|
|
|
@ -6193,30 +6193,87 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS,
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 int *arg_gen) {
|
|||
// 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
|
||||
}
|
||||
|
|
|
@ -225,3 +225,69 @@ void test_conversion(global int *arg_glob, local int *arg_loc,
|
|||
// expected-error@-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@-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@-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@-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@-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@-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@-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@-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@-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@-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@-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
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue