Skip to content

Commit 6781fee

Browse files
committed
Don't permit array bound constant folding in OpenCL.
Permitting non-standards-driven "do the best you can" constant-folding of array bounds is permitted solely as a GNU compatibility feature. We should not be doing it in any language mode that is attempting to be conforming. From https://reviews.llvm.org/D20090 it appears the intent here was to permit `__constant int` globals to be used in array bounds, but the change in that patch only added half of the functionality necessary to support that in the constant evaluator. This patch adds the other half of the functionality and turns off constant folding for array bounds in OpenCL. I couldn't find any spec justification for accepting the kinds of cases that D20090 accepts, so a reference to where in the OpenCL specification this is permitted would be useful. Note that this change also affects the code generation in one test: because after 'const int n = 0' we now treat 'n' as a constant expression with value 0, it's now a null pointer, so '(local int *)n' forms a null pointer rather than a zero pointer. Reviewed By: Anastasia Differential Revision: https://reviews.llvm.org/D89520
1 parent f887854 commit 6781fee

File tree

5 files changed

+36
-29
lines changed

5 files changed

+36
-29
lines changed

clang/lib/AST/Decl.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2280,7 +2280,9 @@ void VarDecl::setInit(Expr *I) {
22802280
bool VarDecl::mightBeUsableInConstantExpressions(const ASTContext &C) const {
22812281
const LangOptions &Lang = C.getLangOpts();
22822282

2283-
if (!Lang.CPlusPlus)
2283+
// OpenCL permits const integral variables to be used in constant
2284+
// expressions, like in C++98.
2285+
if (!Lang.CPlusPlus && !Lang.OpenCL)
22842286
return false;
22852287

22862288
// Function parameters are never usable in constant expressions.
@@ -2299,7 +2301,7 @@ bool VarDecl::mightBeUsableInConstantExpressions(const ASTContext &C) const {
22992301
// Only const objects can be used in constant expressions in C++. C++98 does
23002302
// not require the variable to be non-volatile, but we consider this to be a
23012303
// defect.
2302-
if (!getType().isConstQualified() || getType().isVolatileQualified())
2304+
if (!getType().isConstant(C) || getType().isVolatileQualified())
23032305
return false;
23042306

23052307
// In C++, const, non-volatile variables of integral or enumeration types
@@ -2325,14 +2327,14 @@ bool VarDecl::isUsableInConstantExpressions(const ASTContext &Context) const {
23252327
if (!DefVD->mightBeUsableInConstantExpressions(Context))
23262328
return false;
23272329
// ... and its initializer is a constant initializer.
2328-
if (!DefVD->hasConstantInitialization())
2330+
if (Context.getLangOpts().CPlusPlus && !DefVD->hasConstantInitialization())
23292331
return false;
23302332
// C++98 [expr.const]p1:
23312333
// An integral constant-expression can involve only [...] const variables
23322334
// or static data members of integral or enumeration types initialized with
23332335
// [integer] constant expressions (dcl.init)
2334-
if (Context.getLangOpts().CPlusPlus && !Context.getLangOpts().CPlusPlus11 &&
2335-
!DefVD->hasICEInitializer(Context))
2336+
if ((Context.getLangOpts().CPlusPlus || Context.getLangOpts().OpenCL) &&
2337+
!Context.getLangOpts().CPlusPlus11 && !DefVD->hasICEInitializer(Context))
23362338
return false;
23372339
return true;
23382340
}

clang/lib/AST/ExprConstant.cpp

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3284,10 +3284,10 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
32843284
// FIXME: We don't diagnose cases that aren't potentially usable in constant
32853285
// expressions here; doing so would regress diagnostics for things like
32863286
// reading from a volatile constexpr variable.
3287-
if ((!VD->hasConstantInitialization() &&
3287+
if ((Info.getLangOpts().CPlusPlus && !VD->hasConstantInitialization() &&
32883288
VD->mightBeUsableInConstantExpressions(Info.Ctx)) ||
3289-
(Info.getLangOpts().CPlusPlus && !Info.getLangOpts().CPlusPlus11 &&
3290-
!VD->hasICEInitializer(Info.Ctx))) {
3289+
((Info.getLangOpts().CPlusPlus || Info.getLangOpts().OpenCL) &&
3290+
!Info.getLangOpts().CPlusPlus11 && !VD->hasICEInitializer(Info.Ctx))) {
32913291
Info.CCEDiag(E, diag::note_constexpr_var_init_non_constant, 1) << VD;
32923292
NoteLValueLocation(Info, Base);
32933293
}
@@ -3997,10 +3997,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
39973997
return CompleteObject();
39983998
}
39993999

4000-
// In OpenCL if a variable is in constant address space it is a const value.
4001-
bool IsConstant = BaseType.isConstQualified() ||
4002-
(Info.getLangOpts().OpenCL &&
4003-
BaseType.getAddressSpace() == LangAS::opencl_constant);
4000+
bool IsConstant = BaseType.isConstant(Info.Ctx);
40044001

40054002
// Unless we're looking at a local variable or argument in a constexpr call,
40064003
// the variable we're reading must be const.
@@ -4021,8 +4018,6 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
40214018
} else if (VD->isConstexpr()) {
40224019
// OK, we can read this variable.
40234020
} else if (BaseType->isIntegralOrEnumerationType()) {
4024-
// In OpenCL if a variable is in constant address space it is a const
4025-
// value.
40264021
if (!IsConstant) {
40274022
if (!IsAccess)
40284023
return CompleteObject(LVal.getLValueBase(), nullptr, BaseType);
@@ -14834,7 +14829,6 @@ bool Expr::EvalResult::isGlobalLValue() const {
1483414829
return IsGlobalLValue(Val.getLValueBase());
1483514830
}
1483614831

14837-
1483814832
/// isIntegerConstantExpr - this recursive routine will test if an expression is
1483914833
/// an integer constant expression.
1484014834

@@ -15037,15 +15031,20 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
1503715031
return CheckICE(cast<CXXRewrittenBinaryOperator>(E)->getSemanticForm(),
1503815032
Ctx);
1503915033
case Expr::DeclRefExprClass: {
15040-
if (isa<EnumConstantDecl>(cast<DeclRefExpr>(E)->getDecl()))
15034+
const NamedDecl *D = cast<DeclRefExpr>(E)->getDecl();
15035+
if (isa<EnumConstantDecl>(D))
1504115036
return NoDiag();
15042-
const VarDecl *VD = dyn_cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
15043-
if (VD && VD->isUsableInConstantExpressions(Ctx)) {
15044-
// C++ 7.1.5.1p2
15045-
// A variable of non-volatile const-qualified integral or enumeration
15046-
// type initialized by an ICE can be used in ICEs.
15037+
15038+
// C++ and OpenCL (FIXME: spec reference?) allow reading const-qualified
15039+
// integer variables in constant expressions:
15040+
//
15041+
// C++ 7.1.5.1p2
15042+
// A variable of non-volatile const-qualified integral or enumeration
15043+
// type initialized by an ICE can be used in ICEs.
15044+
const VarDecl *VD = dyn_cast<VarDecl>(D);
15045+
if (VD && VD->isUsableInConstantExpressions(Ctx))
1504715046
return NoDiag();
15048-
}
15047+
1504915048
return ICEDiag(IK_NotICE, E->getBeginLoc());
1505015049
}
1505115050
case Expr::UnaryOperatorClass: {

clang/lib/Sema/SemaType.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2273,9 +2273,8 @@ static ExprResult checkArraySize(Sema &S, Expr *&ArraySize,
22732273
}
22742274
} Diagnoser(VLADiag, VLAIsError);
22752275

2276-
ExprResult R = S.VerifyIntegerConstantExpression(
2277-
ArraySize, &SizeVal, Diagnoser,
2278-
S.LangOpts.OpenCL ? Sema::AllowFold : Sema::NoFold);
2276+
ExprResult R =
2277+
S.VerifyIntegerConstantExpression(ArraySize, &SizeVal, Diagnoser);
22792278
if (Diagnoser.IsVLA)
22802279
return ExprResult();
22812280
return R;

clang/test/CodeGenOpenCL/amdgpu-nullptr.cl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ int fold_int5_local = (int) &((local StructTy1*)0)->p2;
104104
// NOOPT: @test_static_var_private.sp2 = internal addrspace(1) global i8 addrspace(5)* addrspacecast (i8* null to i8 addrspace(5)*), align 4
105105
// NOOPT: @test_static_var_private.sp3 = internal addrspace(1) global i8 addrspace(5)* addrspacecast (i8* null to i8 addrspace(5)*), align 4
106106
// NOOPT: @test_static_var_private.sp4 = internal addrspace(1) global i8 addrspace(5)* null, align 4
107-
// NOOPT: @test_static_var_private.sp5 = internal addrspace(1) global i8 addrspace(5)* null, align 4
107+
// NOOPT: @test_static_var_private.sp5 = internal addrspace(1) global i8 addrspace(5)* addrspacecast (i8* null to i8 addrspace(5)*), align 4
108108
// NOOPT: @test_static_var_private.SS1 = internal addrspace(1) global %struct.StructTy1 { i8 addrspace(5)* addrspacecast (i8* null to i8 addrspace(5)*), i8 addrspace(3)* addrspacecast (i8* null to i8 addrspace(3)*), i8 addrspace(4)* null, i8 addrspace(1)* null, i8* null }, align 8
109109
// NOOPT: @test_static_var_private.SS2 = internal addrspace(1) global %struct.StructTy2 zeroinitializer, align 8
110110

@@ -123,7 +123,7 @@ void test_static_var_private(void) {
123123
// NOOPT: @test_static_var_local.sp2 = internal addrspace(1) global i8 addrspace(3)* addrspacecast (i8* null to i8 addrspace(3)*), align 4
124124
// NOOPT: @test_static_var_local.sp3 = internal addrspace(1) global i8 addrspace(3)* addrspacecast (i8* null to i8 addrspace(3)*), align 4
125125
// NOOPT: @test_static_var_local.sp4 = internal addrspace(1) global i8 addrspace(3)* null, align 4
126-
// NOOPT: @test_static_var_local.sp5 = internal addrspace(1) global i8 addrspace(3)* null, align 4
126+
// NOOPT: @test_static_var_local.sp5 = internal addrspace(1) global i8 addrspace(3)* addrspacecast (i8* null to i8 addrspace(3)*), align 4
127127
// NOOPT: @test_static_var_local.SS1 = internal addrspace(1) global %struct.StructTy1 { i8 addrspace(5)* addrspacecast (i8* null to i8 addrspace(5)*), i8 addrspace(3)* addrspacecast (i8* null to i8 addrspace(3)*), i8 addrspace(4)* null, i8 addrspace(1)* null, i8* null }, align 8
128128
// NOOPT: @test_static_var_local.SS2 = internal addrspace(1) global %struct.StructTy2 zeroinitializer, align 8
129129
void test_static_var_local(void) {
@@ -142,7 +142,7 @@ void test_static_var_local(void) {
142142
// NOOPT: store i8 addrspace(5)* addrspacecast (i8* null to i8 addrspace(5)*), i8 addrspace(5)* addrspace(5)* %sp1, align 4
143143
// NOOPT: store i8 addrspace(5)* addrspacecast (i8* null to i8 addrspace(5)*), i8 addrspace(5)* addrspace(5)* %sp2, align 4
144144
// NOOPT: store i8 addrspace(5)* null, i8 addrspace(5)* addrspace(5)* %sp3, align 4
145-
// NOOPT: store i8 addrspace(5)* null, i8 addrspace(5)* addrspace(5)* %sp4, align 4
145+
// NOOPT: store i8 addrspace(5)* addrspacecast (i8* null to i8 addrspace(5)*), i8 addrspace(5)* addrspace(5)* %sp4, align 4
146146
// NOOPT: %[[SS1:.*]] = bitcast %struct.StructTy1 addrspace(5)* %SS1 to i8 addrspace(5)*
147147
// NOOPT: call void @llvm.memcpy.p5i8.p4i8.i64(i8 addrspace(5)* align 8 %[[SS1]], i8 addrspace(4)* align 8 bitcast (%struct.StructTy1 addrspace(4)* @__const.test_func_scope_var_private.SS1 to i8 addrspace(4)*), i64 32, i1 false)
148148
// NOOPT: %[[SS2:.*]] = bitcast %struct.StructTy2 addrspace(5)* %SS2 to i8 addrspace(5)*
@@ -162,7 +162,7 @@ void test_func_scope_var_private(void) {
162162
// NOOPT: store i8 addrspace(3)* addrspacecast (i8* null to i8 addrspace(3)*), i8 addrspace(3)* addrspace(5)* %sp1, align 4
163163
// NOOPT: store i8 addrspace(3)* addrspacecast (i8* null to i8 addrspace(3)*), i8 addrspace(3)* addrspace(5)* %sp2, align 4
164164
// NOOPT: store i8 addrspace(3)* null, i8 addrspace(3)* addrspace(5)* %sp3, align 4
165-
// NOOPT: store i8 addrspace(3)* null, i8 addrspace(3)* addrspace(5)* %sp4, align 4
165+
// NOOPT: store i8 addrspace(3)* addrspacecast (i8* null to i8 addrspace(3)*), i8 addrspace(3)* addrspace(5)* %sp4, align 4
166166
// NOOPT: %[[SS1:.*]] = bitcast %struct.StructTy1 addrspace(5)* %SS1 to i8 addrspace(5)*
167167
// NOOPT: call void @llvm.memcpy.p5i8.p4i8.i64(i8 addrspace(5)* align 8 %[[SS1]], i8 addrspace(4)* align 8 bitcast (%struct.StructTy1 addrspace(4)* @__const.test_func_scope_var_local.SS1 to i8 addrspace(4)*), i64 32, i1 false)
168168
// NOOPT: %[[SS2:.*]] = bitcast %struct.StructTy2 addrspace(5)* %SS2 to i8 addrspace(5)*

clang/test/SemaOpenCL/address-spaces.cl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@
44

55
__constant int ci = 1;
66

7+
// __constant ints are allowed in constant expressions.
8+
enum use_ci_in_enum { enumerator = ci };
9+
typedef int use_ci_in_array_bound[ci];
10+
11+
// general constant folding of array bounds is not permitted
12+
typedef int folding_in_array_bounds[&ci + 3 - &ci]; // expected-error-re {{{{variable length arrays are not supported in OpenCL|array size is not a constant expression}}}} expected-note {{cannot refer to element 3}}
13+
714
__kernel void foo(__global int *gip) {
815
__local int li;
916
__local int lj = 2; // expected-error {{'__local' variable cannot have an initializer}}

0 commit comments

Comments
 (0)