-
Notifications
You must be signed in to change notification settings - Fork 15.4k
[LoopInterchange] Add metadata to control loop-interchange #127474
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 6 commits
1b11ebe
2418ad8
ecb9f37
6e05f92
0e954b3
7eff317
b3ae858
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -80,6 +80,17 @@ static void warnAboutLeftoverTransformations(Loop *L, | |
| "requested transformation; the transformation might be disabled or " | ||
| "specified as part of an unsupported transformation ordering"); | ||
| } | ||
|
|
||
| if (hasInterchangeTransformation(L) == TM_ForcedByUser) { | ||
| LLVM_DEBUG(dbgs() << "Leftover interchange transformation\n"); | ||
| ORE->emit( | ||
| DiagnosticInfoOptimizationFailure(DEBUG_TYPE, | ||
| "FailedRequestedInterchange", | ||
| L->getStartLoc(), L->getHeader()) | ||
| << "loop not interchanged: the optimizer was unable to perform the " | ||
| "requested transformation; the transformation might be disabled or " | ||
| "specified as part of an unsupported transformation ordering"); | ||
| } | ||
|
Comment on lines
+84
to
+93
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Is this what you intended? |
||
| } | ||
|
|
||
| static void warnAboutLeftoverTransformations(Function *F, LoopInfo *LI, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 | ||
| ; RUN: opt -passes=loop-interchange -loop-interchange-only-when-forced=0 --cache-line-size=64 -S < %s | FileCheck %s | ||
|
|
||
| ; Check that the interchange is not applied to the loop that is disabled by | ||
| ; metadata. The original code is as below: | ||
| ; | ||
| ; for (int i=0; i<128; i++) | ||
| ; for (int j=0; j<128; j++) | ||
| ; #pragma clang loop interchange(disable) | ||
| ; for (int k=0; k<128; k++) | ||
| ; for (int l=0; l<128; l++) | ||
| ; a[l][k][j][i]++; | ||
| ; | ||
| ; Since interchanges are not be applied to the k-loop, the pair (i, j) is the | ||
| ; only candidate for exchange. | ||
|
|
||
| @a = dso_local local_unnamed_addr global [128 x [128 x [128 x [128 x i32]]]] zeroinitializer, align 4 | ||
|
|
||
| define void @f() { | ||
| ; CHECK-LABEL: define void @f() { | ||
| ; CHECK-NEXT: [[ENTRY:.*:]] | ||
| ; CHECK-NEXT: br label %[[FOR_J_HEADER_PREHEADER:.*]] | ||
| ; CHECK: [[FOR_I_HEADER_PREHEADER:.*]]: | ||
| ; CHECK-NEXT: br label %[[FOR_I_HEADER:.*]] | ||
| ; CHECK: [[FOR_I_HEADER]]: | ||
| ; CHECK-NEXT: [[IV_I:%.*]] = phi i64 [ [[IV_I_NEXT:%.*]], %[[FOR_I_CLEANUP:.*]] ], [ 0, %[[FOR_I_HEADER_PREHEADER]] ] | ||
| ; CHECK-NEXT: br label %[[FOR_K_HEADER:.*]] | ||
| ; CHECK: [[FOR_J_HEADER_PREHEADER]]: | ||
| ; CHECK-NEXT: br label %[[FOR_J_HEADER:.*]] | ||
| ; CHECK: [[FOR_J_HEADER]]: | ||
| ; CHECK-NEXT: [[IV_J:%.*]] = phi i64 [ [[IV_J_NEXT:%.*]], %[[FOR_J_CLEANUP:.*]] ], [ 0, %[[FOR_J_HEADER_PREHEADER]] ] | ||
| ; CHECK-NEXT: br label %[[FOR_I_HEADER_PREHEADER]] | ||
| ; CHECK: [[FOR_K_HEADER]]: | ||
| ; CHECK-NEXT: [[IV_K:%.*]] = phi i64 [ 0, %[[FOR_I_HEADER]] ], [ [[IV_K_NEXT:%.*]], %[[FOR_K_CLEANUP:.*]] ] | ||
| ; CHECK-NEXT: br label %[[FOR_BODY:.*]] | ||
| ; CHECK: [[FOR_BODY]]: | ||
| ; CHECK-NEXT: [[IV_L:%.*]] = phi i64 [ 0, %[[FOR_K_HEADER]] ], [ [[TMP0:%.*]], %[[FOR_BODY]] ] | ||
| ; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds nuw [128 x [128 x [128 x [128 x i32]]]], ptr @a, i64 [[IV_L]], i64 [[IV_K]], i64 [[IV_J]], i64 [[IV_I]] | ||
| ; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[PTR]], align 4 | ||
| ; CHECK-NEXT: [[INC:%.*]] = add nuw nsw i32 [[VAL]], 1 | ||
| ; CHECK-NEXT: store i32 [[INC]], ptr [[PTR]], align 4 | ||
| ; CHECK-NEXT: [[TMP0]] = add nuw nsw i64 [[IV_L]], 1 | ||
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[TMP0]], 128 | ||
| ; CHECK-NEXT: br i1 [[TMP1]], label %[[FOR_K_CLEANUP]], label %[[FOR_BODY]] | ||
| ; CHECK: [[FOR_K_CLEANUP]]: | ||
| ; CHECK-NEXT: [[IV_K_NEXT]] = add nuw nsw i64 [[IV_K]], 1 | ||
| ; CHECK-NEXT: [[EXITCOND_K:%.*]] = icmp eq i64 [[IV_K_NEXT]], 128 | ||
| ; CHECK-NEXT: br i1 [[EXITCOND_K]], label %[[FOR_I_CLEANUP]], label %[[FOR_K_HEADER]], !llvm.loop [[LOOP0:![0-9]+]] | ||
| ; CHECK: [[FOR_J_CLEANUP]]: | ||
| ; CHECK-NEXT: [[IV_J_NEXT]] = add nuw nsw i64 [[IV_J]], 1 | ||
| ; CHECK-NEXT: [[EXITCOND_J:%.*]] = icmp eq i64 [[IV_J_NEXT]], 128 | ||
| ; CHECK-NEXT: br i1 [[EXITCOND_J]], label %[[EXIT:.*]], label %[[FOR_J_HEADER]] | ||
| ; CHECK: [[FOR_I_CLEANUP]]: | ||
| ; CHECK-NEXT: [[IV_I_NEXT]] = add nuw nsw i64 [[IV_I]], 1 | ||
| ; CHECK-NEXT: [[EXITCOND_I:%.*]] = icmp eq i64 [[IV_I_NEXT]], 128 | ||
| ; CHECK-NEXT: br i1 [[EXITCOND_I]], label %[[FOR_J_CLEANUP]], label %[[FOR_I_HEADER]] | ||
| ; CHECK: [[EXIT]]: | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| entry: | ||
| br label %for.i.header | ||
|
|
||
| for.i.header: | ||
| %iv.i = phi i64 [ 0, %entry ], [ %iv.i.next, %for.i.cleanup ] | ||
| br label %for.j.header | ||
|
|
||
| for.j.header: | ||
| %iv.j = phi i64 [ 0, %for.i.header ], [ %iv.j.next, %for.j.cleanup ] | ||
| br label %for.k.header | ||
|
|
||
| for.k.header: | ||
| %iv.k = phi i64 [ 0, %for.j.header ], [ %iv.k.next, %for.k.cleanup ] | ||
| br label %for.body | ||
|
|
||
| for.body: | ||
| %iv.l = phi i64 [ 0, %for.k.header ], [ %iv.l.next, %for.body ] | ||
| %ptr = getelementptr inbounds nuw [128 x [128 x [128 x [128 x i32]]]], ptr @a, i64 %iv.l, i64 %iv.k, i64 %iv.j, i64 %iv.i | ||
| %val = load i32, ptr %ptr, align 4 | ||
| %inc = add nuw nsw i32 %val, 1 | ||
| store i32 %inc, ptr %ptr, align 4 | ||
| %iv.l.next = add nuw nsw i64 %iv.l, 1 | ||
| %exitcond.l = icmp eq i64 %iv.l.next, 128 | ||
| br i1 %exitcond.l, label %for.k.cleanup, label %for.body | ||
|
|
||
| for.k.cleanup: | ||
| %iv.k.next = add nuw nsw i64 %iv.k, 1 | ||
| %exitcond.k = icmp eq i64 %iv.k.next, 128 | ||
| br i1 %exitcond.k, label %for.j.cleanup, label %for.k.header, !llvm.loop !0 | ||
|
|
||
| for.j.cleanup: | ||
| %iv.j.next = add nuw nsw i64 %iv.j, 1 | ||
| %exitcond.j = icmp eq i64 %iv.j.next, 128 | ||
| br i1 %exitcond.j, label %for.i.cleanup, label %for.j.header | ||
|
|
||
| for.i.cleanup: | ||
| %iv.i.next = add nuw nsw i64 %iv.i, 1 | ||
| %exitcond.i = icmp eq i64 %iv.i.next, 128 | ||
| br i1 %exitcond.i, label %exit, label %for.i.header | ||
|
|
||
| exit: | ||
| ret void | ||
| } | ||
|
|
||
| !0 = distinct !{!0, !1} | ||
| !1 = !{!"llvm.loop.interchange.enable", i1 false} | ||
| ;. | ||
| ; CHECK: [[LOOP0]] = distinct !{[[LOOP0]], [[META1:![0-9]+]]} | ||
| ; CHECK: [[META1]] = !{!"llvm.loop.interchange.enable", i1 false} | ||
| ;. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As for the cases where the loops to be interchanged do not interfere with each other, I plan to handle them independently. That is, the following code
will be translated like as
not as follows.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's fine, but also the less interesting case.