@@ -15111,13 +15111,11 @@ StmtResult SemaOpenMP::ActOnOpenMPTileDirective(ArrayRef<OMPClause *> Clauses,
15111
15111
ASTContext &Context = getASTContext();
15112
15112
Scope *CurScope = SemaRef.getCurScope();
15113
15113
15114
- auto SizesClauses =
15115
- OMPExecutableDirective::getClausesOfKind <OMPSizesClause>(Clauses);
15116
- if (SizesClauses.empty()) {
15117
- // A missing 'sizes' clause is already reported by the parser.
15114
+ const auto *SizesClause =
15115
+ OMPExecutableDirective::getSingleClause <OMPSizesClause>(Clauses);
15116
+ if (!SizesClause ||
15117
+ llvm::any_of(SizesClause->getSizesRefs(), [](Expr *E) { return !E; }))
15118
15118
return StmtError();
15119
- }
15120
- const OMPSizesClause *SizesClause = *SizesClauses.begin();
15121
15119
unsigned NumLoops = SizesClause->getNumSizes();
15122
15120
15123
15121
// Empty statement should only be possible if there already was an error.
@@ -15138,6 +15136,13 @@ StmtResult SemaOpenMP::ActOnOpenMPTileDirective(ArrayRef<OMPClause *> Clauses,
15138
15136
return OMPTileDirective::Create(Context, StartLoc, EndLoc, Clauses,
15139
15137
NumLoops, AStmt, nullptr, nullptr);
15140
15138
15139
+ assert(LoopHelpers.size() == NumLoops &&
15140
+ "Expecting loop iteration space dimensionality to match number of "
15141
+ "affected loops");
15142
+ assert(OriginalInits.size() == NumLoops &&
15143
+ "Expecting loop iteration space dimensionality to match number of "
15144
+ "affected loops");
15145
+
15141
15146
SmallVector<Decl *, 4> PreInits;
15142
15147
CaptureVars CopyTransformer(SemaRef);
15143
15148
@@ -15197,6 +15202,44 @@ StmtResult SemaOpenMP::ActOnOpenMPTileDirective(ArrayRef<OMPClause *> Clauses,
15197
15202
// Once the original iteration values are set, append the innermost body.
15198
15203
Stmt *Inner = Body;
15199
15204
15205
+ auto MakeDimTileSize = [&SemaRef = this->SemaRef, &CopyTransformer, &Context,
15206
+ SizesClause, CurScope](int I) -> Expr * {
15207
+ Expr *DimTileSizeExpr = SizesClause->getSizesRefs()[I];
15208
+ if (isa<ConstantExpr>(DimTileSizeExpr))
15209
+ return AssertSuccess(CopyTransformer.TransformExpr(DimTileSizeExpr));
15210
+
15211
+ // When the tile size is not a constant but a variable, it is possible to
15212
+ // pass non-positive numbers. For instance:
15213
+ // \code{c}
15214
+ // int a = 0;
15215
+ // #pragma omp tile sizes(a)
15216
+ // for (int i = 0; i < 42; ++i)
15217
+ // body(i);
15218
+ // \endcode
15219
+ // Although there is no meaningful interpretation of the tile size, the body
15220
+ // should still be executed 42 times to avoid surprises. To preserve the
15221
+ // invariant that every loop iteration is executed exactly once and not
15222
+ // cause an infinite loop, apply a minimum tile size of one.
15223
+ // Build expr:
15224
+ // \code{c}
15225
+ // (TS <= 0) ? 1 : TS
15226
+ // \endcode
15227
+ QualType DimTy = DimTileSizeExpr->getType();
15228
+ uint64_t DimWidth = Context.getTypeSize(DimTy);
15229
+ IntegerLiteral *Zero = IntegerLiteral::Create(
15230
+ Context, llvm::APInt::getZero(DimWidth), DimTy, {});
15231
+ IntegerLiteral *One =
15232
+ IntegerLiteral::Create(Context, llvm::APInt(DimWidth, 1), DimTy, {});
15233
+ Expr *Cond = AssertSuccess(SemaRef.BuildBinOp(
15234
+ CurScope, {}, BO_LE,
15235
+ AssertSuccess(CopyTransformer.TransformExpr(DimTileSizeExpr)), Zero));
15236
+ Expr *MinOne = new (Context) ConditionalOperator(
15237
+ Cond, {}, One, {},
15238
+ AssertSuccess(CopyTransformer.TransformExpr(DimTileSizeExpr)), DimTy,
15239
+ VK_PRValue, OK_Ordinary);
15240
+ return MinOne;
15241
+ };
15242
+
15200
15243
// Create tile loops from the inside to the outside.
15201
15244
for (int I = NumLoops - 1; I >= 0; --I) {
15202
15245
OMPLoopBasedDirective::HelperExprs &LoopHelper = LoopHelpers[I];
@@ -15207,10 +15250,6 @@ StmtResult SemaOpenMP::ActOnOpenMPTileDirective(ArrayRef<OMPClause *> Clauses,
15207
15250
// Commonly used variables. One of the constraints of an AST is that every
15208
15251
// node object must appear at most once, hence we define lamdas that create
15209
15252
// a new AST node at every use.
15210
- auto MakeDimTileSize = [&CopyTransformer, I, SizesClause]() -> Expr * {
15211
- Expr *DimTileSize = SizesClause->getSizesRefs()[I];
15212
- return AssertSuccess(CopyTransformer.TransformExpr(DimTileSize));
15213
- };
15214
15253
auto MakeTileIVRef = [&SemaRef = this->SemaRef, &TileIndVars, I, CntTy,
15215
15254
OrigCntVar]() {
15216
15255
return buildDeclRefExpr(SemaRef, TileIndVars[I], CntTy,
@@ -15237,7 +15276,7 @@ StmtResult SemaOpenMP::ActOnOpenMPTileDirective(ArrayRef<OMPClause *> Clauses,
15237
15276
// .tile.iv < min(.floor.iv + DimTileSize, NumIterations)
15238
15277
ExprResult EndOfTile =
15239
15278
SemaRef.BuildBinOp(CurScope, LoopHelper.Cond->getExprLoc(), BO_Add,
15240
- MakeFloorIVRef(), MakeDimTileSize());
15279
+ MakeFloorIVRef(), MakeDimTileSize(I ));
15241
15280
if (!EndOfTile.isUsable())
15242
15281
return StmtError();
15243
15282
ExprResult IsPartialTile =
@@ -15297,10 +15336,6 @@ StmtResult SemaOpenMP::ActOnOpenMPTileDirective(ArrayRef<OMPClause *> Clauses,
15297
15336
QualType CntTy = OrigCntVar->getType();
15298
15337
15299
15338
// Commonly used variables.
15300
- auto MakeDimTileSize = [&CopyTransformer, I, SizesClause]() -> Expr * {
15301
- Expr *DimTileSize = SizesClause->getSizesRefs()[I];
15302
- return AssertSuccess(CopyTransformer.TransformExpr(DimTileSize));
15303
- };
15304
15339
auto MakeFloorIVRef = [&SemaRef = this->SemaRef, &FloorIndVars, I, CntTy,
15305
15340
OrigCntVar]() {
15306
15341
return buildDeclRefExpr(SemaRef, FloorIndVars[I], CntTy,
@@ -15329,7 +15364,7 @@ StmtResult SemaOpenMP::ActOnOpenMPTileDirective(ArrayRef<OMPClause *> Clauses,
15329
15364
// For incr-statement: .floor.iv += DimTileSize
15330
15365
ExprResult IncrStmt =
15331
15366
SemaRef.BuildBinOp(CurScope, LoopHelper.Inc->getExprLoc(), BO_AddAssign,
15332
- MakeFloorIVRef(), MakeDimTileSize());
15367
+ MakeFloorIVRef(), MakeDimTileSize(I ));
15333
15368
if (!IncrStmt.isUsable())
15334
15369
return StmtError();
15335
15370
@@ -17430,16 +17465,53 @@ OMPClause *SemaOpenMP::ActOnOpenMPSizesClause(ArrayRef<Expr *> SizeExprs,
17430
17465
SourceLocation StartLoc,
17431
17466
SourceLocation LParenLoc,
17432
17467
SourceLocation EndLoc) {
17433
- for (Expr *SizeExpr : SizeExprs) {
17434
- ExprResult NumForLoopsResult = VerifyPositiveIntegerConstantInClause(
17435
- SizeExpr, OMPC_sizes, /*StrictlyPositive=*/true);
17436
- if (!NumForLoopsResult.isUsable())
17437
- return nullptr;
17468
+ SmallVector<Expr *> SanitizedSizeExprs(SizeExprs);
17469
+
17470
+ for (Expr *&SizeExpr : SanitizedSizeExprs) {
17471
+ // Skip if already sanitized, e.g. during a partial template instantiation.
17472
+ if (!SizeExpr)
17473
+ continue;
17474
+
17475
+ bool IsValid = isNonNegativeIntegerValue(SizeExpr, SemaRef, OMPC_sizes,
17476
+ /*StrictlyPositive=*/true);
17477
+
17478
+ // isNonNegativeIntegerValue returns true for non-integral types (but still
17479
+ // emits error diagnostic), so check for the expected type explicitly.
17480
+ QualType SizeTy = SizeExpr->getType();
17481
+ if (!SizeTy->isIntegerType())
17482
+ IsValid = false;
17483
+
17484
+ // Handling in templates is tricky. There are four possibilities to
17485
+ // consider:
17486
+ //
17487
+ // 1a. The expression is valid and we are in a instantiated template or not
17488
+ // in a template:
17489
+ // Pass valid expression to be further analysed later in Sema.
17490
+ // 1b. The expression is valid and we are in a template (including partial
17491
+ // instantiation):
17492
+ // isNonNegativeIntegerValue skipped any checks so there is no
17493
+ // guarantee it will be correct after instantiation.
17494
+ // ActOnOpenMPSizesClause will be called again at instantiation when
17495
+ // it is not in a dependent context anymore. This may cause warnings
17496
+ // to be emitted multiple times.
17497
+ // 2a. The expression is invalid and we are in an instantiated template or
17498
+ // not in a template:
17499
+ // Invalidate the expression with a clearly wrong value (nullptr) so
17500
+ // later in Sema we do not have to do the same validity analysis again
17501
+ // or crash from unexpected data. Error diagnostics have already been
17502
+ // emitted.
17503
+ // 2b. The expression is invalid and we are in a template (including partial
17504
+ // instantiation):
17505
+ // Pass the invalid expression as-is, template instantiation may
17506
+ // replace unexpected types/values with valid ones. The directives
17507
+ // with this clause must not try to use these expressions in dependent
17508
+ // contexts, but delay analysis until full instantiation.
17509
+ if (!SizeExpr->isInstantiationDependent() && !IsValid)
17510
+ SizeExpr = nullptr;
17438
17511
}
17439
17512
17440
- DSAStack->setAssociatedLoops(SizeExprs.size());
17441
17513
return OMPSizesClause::Create(getASTContext(), StartLoc, LParenLoc, EndLoc,
17442
- SizeExprs );
17514
+ SanitizedSizeExprs );
17443
17515
}
17444
17516
17445
17517
OMPClause *SemaOpenMP::ActOnOpenMPFullClause(SourceLocation StartLoc,
0 commit comments