| // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 6 |
| // A standalone `#pragma omp tile` keeps the intra-tile loop min-bounded: the |
| // upper bound `min(.floor.iv + tilesize, N)` is materialized as a |
| // cond.true/cond.false/phi and there is no body guard. The guarded rectangular |
| // form appears only once a directive consumes the tile, see |
| // tile_collapse_reinterpret_codegen.cpp. |
| // |
| // RUN: %clang_cc1 -verify -triple x86_64-pc-linux-gnu -fopenmp -emit-llvm -o - %s | FileCheck %s --check-prefix=IR |
| // expected-no-diagnostics |
| |
| extern "C" void body(int); |
| |
| // Trip count 6, tile 4: the last tile is partial, and the min() bound alone |
| // stops it at the trip count. |
| // IR-LABEL: define dso_local void @_Z18remainder_6_tile_4v( |
| // IR-SAME: ) #[[ATTR0:[0-9]+]] { |
| // IR-NEXT: [[ENTRY:.*:]] |
| // IR-NEXT: [[I:%.*]] = alloca i32, align 4 |
| // IR-NEXT: [[DOTFLOOR_0_IV_I:%.*]] = alloca i32, align 4 |
| // IR-NEXT: [[DOTTILE_0_IV_I:%.*]] = alloca i32, align 4 |
| // IR-NEXT: store i32 0, ptr [[I]], align 4 |
| // IR-NEXT: store i32 0, ptr [[DOTFLOOR_0_IV_I]], align 4 |
| // IR-NEXT: br label %[[FOR_COND:.*]] |
| // IR: [[FOR_COND]]: |
| // IR-NEXT: [[TMP0:%.*]] = load i32, ptr [[DOTFLOOR_0_IV_I]], align 4 |
| // IR-NEXT: [[CMP:%.*]] = icmp slt i32 [[TMP0]], 6 |
| // IR-NEXT: br i1 [[CMP]], label %[[FOR_BODY:.*]], label %[[FOR_END9:.*]] |
| // IR: [[FOR_BODY]]: |
| // IR-NEXT: [[TMP1:%.*]] = load i32, ptr [[DOTFLOOR_0_IV_I]], align 4 |
| // IR-NEXT: store i32 [[TMP1]], ptr [[DOTTILE_0_IV_I]], align 4 |
| // IR-NEXT: br label %[[FOR_COND1:.*]] |
| // IR: [[FOR_COND1]]: |
| // IR-NEXT: [[TMP2:%.*]] = load i32, ptr [[DOTTILE_0_IV_I]], align 4 |
| // IR-NEXT: [[TMP3:%.*]] = load i32, ptr [[DOTFLOOR_0_IV_I]], align 4 |
| // IR-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP3]], 4 |
| // IR-NEXT: [[CMP2:%.*]] = icmp slt i32 6, [[ADD]] |
| // IR-NEXT: br i1 [[CMP2]], label %[[COND_TRUE:.*]], label %[[COND_FALSE:.*]] |
| // IR: [[COND_TRUE]]: |
| // IR-NEXT: br label %[[COND_END:.*]] |
| // IR: [[COND_FALSE]]: |
| // IR-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTFLOOR_0_IV_I]], align 4 |
| // IR-NEXT: [[ADD3:%.*]] = add nsw i32 [[TMP4]], 4 |
| // IR-NEXT: br label %[[COND_END]] |
| // IR: [[COND_END]]: |
| // IR-NEXT: [[COND:%.*]] = phi i32 [ 6, %[[COND_TRUE]] ], [ [[ADD3]], %[[COND_FALSE]] ] |
| // IR-NEXT: [[CMP4:%.*]] = icmp slt i32 [[TMP2]], [[COND]] |
| // IR-NEXT: br i1 [[CMP4]], label %[[FOR_BODY5:.*]], label %[[FOR_END:.*]] |
| // IR: [[FOR_BODY5]]: |
| // IR-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTTILE_0_IV_I]], align 4 |
| // IR-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP5]], 1 |
| // IR-NEXT: [[ADD6:%.*]] = add nsw i32 0, [[MUL]] |
| // IR-NEXT: store i32 [[ADD6]], ptr [[I]], align 4 |
| // IR-NEXT: [[TMP6:%.*]] = load i32, ptr [[I]], align 4 |
| // IR-NEXT: call void @body(i32 noundef [[TMP6]]) |
| // IR-NEXT: br label %[[FOR_INC:.*]] |
| // IR: [[FOR_INC]]: |
| // IR-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTTILE_0_IV_I]], align 4 |
| // IR-NEXT: [[INC:%.*]] = add nsw i32 [[TMP7]], 1 |
| // IR-NEXT: store i32 [[INC]], ptr [[DOTTILE_0_IV_I]], align 4 |
| // IR-NEXT: br label %[[FOR_COND1]], !llvm.loop [[LOOP2:![0-9]+]] |
| // IR: [[FOR_END]]: |
| // IR-NEXT: br label %[[FOR_INC7:.*]] |
| // IR: [[FOR_INC7]]: |
| // IR-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTFLOOR_0_IV_I]], align 4 |
| // IR-NEXT: [[ADD8:%.*]] = add nsw i32 [[TMP8]], 4 |
| // IR-NEXT: store i32 [[ADD8]], ptr [[DOTFLOOR_0_IV_I]], align 4 |
| // IR-NEXT: br label %[[FOR_COND]], !llvm.loop [[LOOP4:![0-9]+]] |
| // IR: [[FOR_END9]]: |
| // IR-NEXT: ret void |
| // |
| void remainder_6_tile_4(void) { |
| #pragma omp tile sizes(4) |
| for (int i = 0; i < 6; ++i) |
| body(i); |
| } |
| |
| // The inner `j` loop is not one of the tiled loops, so it is emitted untouched |
| // inside the intra-tile loop. |
| // IR-LABEL: define dso_local void @_Z14nested_inner_ji( |
| // IR-SAME: i32 noundef [[N:%.*]]) #[[ATTR0]] { |
| // IR-NEXT: [[ENTRY:.*:]] |
| // IR-NEXT: [[N_ADDR:%.*]] = alloca i32, align 4 |
| // IR-NEXT: [[I:%.*]] = alloca i32, align 4 |
| // IR-NEXT: [[DOTFLOOR_0_IV_I:%.*]] = alloca i32, align 4 |
| // IR-NEXT: [[DOTTILE_0_IV_I:%.*]] = alloca i32, align 4 |
| // IR-NEXT: [[J:%.*]] = alloca i32, align 4 |
| // IR-NEXT: store i32 [[N]], ptr [[N_ADDR]], align 4 |
| // IR-NEXT: store i32 0, ptr [[I]], align 4 |
| // IR-NEXT: store i32 0, ptr [[DOTFLOOR_0_IV_I]], align 4 |
| // IR-NEXT: br label %[[FOR_COND:.*]] |
| // IR: [[FOR_COND]]: |
| // IR-NEXT: [[TMP0:%.*]] = load i32, ptr [[DOTFLOOR_0_IV_I]], align 4 |
| // IR-NEXT: [[CMP:%.*]] = icmp slt i32 [[TMP0]], 6 |
| // IR-NEXT: br i1 [[CMP]], label %[[FOR_BODY:.*]], label %[[FOR_END16:.*]] |
| // IR: [[FOR_BODY]]: |
| // IR-NEXT: [[TMP1:%.*]] = load i32, ptr [[DOTFLOOR_0_IV_I]], align 4 |
| // IR-NEXT: store i32 [[TMP1]], ptr [[DOTTILE_0_IV_I]], align 4 |
| // IR-NEXT: br label %[[FOR_COND1:.*]] |
| // IR: [[FOR_COND1]]: |
| // IR-NEXT: [[TMP2:%.*]] = load i32, ptr [[DOTTILE_0_IV_I]], align 4 |
| // IR-NEXT: [[TMP3:%.*]] = load i32, ptr [[DOTFLOOR_0_IV_I]], align 4 |
| // IR-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP3]], 4 |
| // IR-NEXT: [[CMP2:%.*]] = icmp slt i32 6, [[ADD]] |
| // IR-NEXT: br i1 [[CMP2]], label %[[COND_TRUE:.*]], label %[[COND_FALSE:.*]] |
| // IR: [[COND_TRUE]]: |
| // IR-NEXT: br label %[[COND_END:.*]] |
| // IR: [[COND_FALSE]]: |
| // IR-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTFLOOR_0_IV_I]], align 4 |
| // IR-NEXT: [[ADD3:%.*]] = add nsw i32 [[TMP4]], 4 |
| // IR-NEXT: br label %[[COND_END]] |
| // IR: [[COND_END]]: |
| // IR-NEXT: [[COND:%.*]] = phi i32 [ 6, %[[COND_TRUE]] ], [ [[ADD3]], %[[COND_FALSE]] ] |
| // IR-NEXT: [[CMP4:%.*]] = icmp slt i32 [[TMP2]], [[COND]] |
| // IR-NEXT: br i1 [[CMP4]], label %[[FOR_BODY5:.*]], label %[[FOR_END13:.*]] |
| // IR: [[FOR_BODY5]]: |
| // IR-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTTILE_0_IV_I]], align 4 |
| // IR-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP5]], 1 |
| // IR-NEXT: [[ADD6:%.*]] = add nsw i32 0, [[MUL]] |
| // IR-NEXT: store i32 [[ADD6]], ptr [[I]], align 4 |
| // IR-NEXT: store i32 0, ptr [[J]], align 4 |
| // IR-NEXT: br label %[[FOR_COND7:.*]] |
| // IR: [[FOR_COND7]]: |
| // IR-NEXT: [[TMP6:%.*]] = load i32, ptr [[J]], align 4 |
| // IR-NEXT: [[TMP7:%.*]] = load i32, ptr [[N_ADDR]], align 4 |
| // IR-NEXT: [[CMP8:%.*]] = icmp slt i32 [[TMP6]], [[TMP7]] |
| // IR-NEXT: br i1 [[CMP8]], label %[[FOR_BODY9:.*]], label %[[FOR_END:.*]] |
| // IR: [[FOR_BODY9]]: |
| // IR-NEXT: [[TMP8:%.*]] = load i32, ptr [[I]], align 4 |
| // IR-NEXT: [[TMP9:%.*]] = load i32, ptr [[J]], align 4 |
| // IR-NEXT: [[ADD10:%.*]] = add nsw i32 [[TMP8]], [[TMP9]] |
| // IR-NEXT: call void @body(i32 noundef [[ADD10]]) |
| // IR-NEXT: br label %[[FOR_INC:.*]] |
| // IR: [[FOR_INC]]: |
| // IR-NEXT: [[TMP10:%.*]] = load i32, ptr [[J]], align 4 |
| // IR-NEXT: [[INC:%.*]] = add nsw i32 [[TMP10]], 1 |
| // IR-NEXT: store i32 [[INC]], ptr [[J]], align 4 |
| // IR-NEXT: br label %[[FOR_COND7]], !llvm.loop [[LOOP5:![0-9]+]] |
| // IR: [[FOR_END]]: |
| // IR-NEXT: br label %[[FOR_INC11:.*]] |
| // IR: [[FOR_INC11]]: |
| // IR-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTTILE_0_IV_I]], align 4 |
| // IR-NEXT: [[INC12:%.*]] = add nsw i32 [[TMP11]], 1 |
| // IR-NEXT: store i32 [[INC12]], ptr [[DOTTILE_0_IV_I]], align 4 |
| // IR-NEXT: br label %[[FOR_COND1]], !llvm.loop [[LOOP6:![0-9]+]] |
| // IR: [[FOR_END13]]: |
| // IR-NEXT: br label %[[FOR_INC14:.*]] |
| // IR: [[FOR_INC14]]: |
| // IR-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTFLOOR_0_IV_I]], align 4 |
| // IR-NEXT: [[ADD15:%.*]] = add nsw i32 [[TMP12]], 4 |
| // IR-NEXT: store i32 [[ADD15]], ptr [[DOTFLOOR_0_IV_I]], align 4 |
| // IR-NEXT: br label %[[FOR_COND]], !llvm.loop [[LOOP7:![0-9]+]] |
| // IR: [[FOR_END16]]: |
| // IR-NEXT: ret void |
| // |
| void nested_inner_j(int n) { |
| #pragma omp tile sizes(4) |
| for (int i = 0; i < 6; ++i) |
| for (int j = 0; j < n; ++j) |
| body(i + j); |
| } |
| //. |
| // IR: [[LOOP2]] = distinct !{[[LOOP2]], [[META3:![0-9]+]]} |
| // IR: [[META3]] = !{!"llvm.loop.mustprogress"} |
| // IR: [[LOOP4]] = distinct !{[[LOOP4]], [[META3]]} |
| // IR: [[LOOP5]] = distinct !{[[LOOP5]], [[META3]]} |
| // IR: [[LOOP6]] = distinct !{[[LOOP6]], [[META3]]} |
| // IR: [[LOOP7]] = distinct !{[[LOOP7]], [[META3]]} |
| //. |