[llvm] d703919 - [LoopInterchange] Add tests for instructions that aren't checked (NFC) (#201401)

via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 3 12:48:36 PDT 2026


Author: Ryotaro Kasuga
Date: 2026-06-03T19:48:31Z
New Revision: d703919410c5055132c037df810dfe70074ef58b

URL: https://github.com/llvm/llvm-project/commit/d703919410c5055132c037df810dfe70074ef58b
DIFF: https://github.com/llvm/llvm-project/commit/d703919410c5055132c037df810dfe70074ef58b.diff

LOG: [LoopInterchange] Add tests for instructions that aren't checked (NFC) (#201401)

This patch adds test cases that contain instructions which are currently
not handled properly in the legality check, leading to miscompilations.
Some of the test cases are taken from #200913, and others are cases that
trigger unsafe interchange for the same reason. I am not trying to cover
all possible instruction types here, since a follow-up patch will update
the legality check so that it can handle other instructions as well.

Added: 
    llvm/test/Transforms/LoopInterchange/atomic-memory-ordering.ll
    llvm/test/Transforms/LoopInterchange/invoke.ll

Modified: 
    

Removed: 
    


################################################################################
diff  --git a/llvm/test/Transforms/LoopInterchange/atomic-memory-ordering.ll b/llvm/test/Transforms/LoopInterchange/atomic-memory-ordering.ll
new file mode 100644
index 0000000000000..8c6fc32e16a96
--- /dev/null
+++ b/llvm/test/Transforms/LoopInterchange/atomic-memory-ordering.ll
@@ -0,0 +1,166 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt < %s -passes=loop-interchange -loop-interchange-profitabilities=ignore -S | FileCheck %s
+
+ at g = global i64 0
+
+; Test cases that contain atomic instructions inside the loops thus interchange
+; must not be applied.
+;
+; FIXME: Currently some of them are interchanged.
+
+define void @atomicrmw() {
+; CHECK-LABEL: define void @atomicrmw() {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    br label %[[FOR_J_PREHEADER:.*]]
+; CHECK:       [[FOR_I_HEADER_PREHEADER:.*]]:
+; CHECK-NEXT:    br label %[[FOR_I_HEADER:.*]]
+; CHECK:       [[FOR_I_HEADER]]:
+; CHECK-NEXT:    [[I:%.*]] = phi i64 [ [[I_NEXT:%.*]], %[[FOR_I_LATCH:.*]] ], [ 0, %[[FOR_I_HEADER_PREHEADER]] ]
+; CHECK-NEXT:    br label %[[FOR_J_SPLIT1:.*]]
+; CHECK:       [[FOR_J_PREHEADER]]:
+; CHECK-NEXT:    br label %[[FOR_J:.*]]
+; CHECK:       [[FOR_J]]:
+; CHECK-NEXT:    [[J:%.*]] = phi i64 [ [[TMP0:%.*]], %[[FOR_J_SPLIT:.*]] ], [ 0, %[[FOR_J_PREHEADER]] ]
+; CHECK-NEXT:    br label %[[FOR_I_HEADER_PREHEADER]]
+; CHECK:       [[FOR_J_SPLIT1]]:
+; CHECK-NEXT:    [[OLD:%.*]] = atomicrmw xchg ptr @g, i64 [[J]] monotonic, align 8
+; CHECK-NEXT:    [[J_NEXT:%.*]] = add i64 [[J]], 1
+; CHECK-NEXT:    [[EC_J:%.*]] = icmp eq i64 [[J_NEXT]], 8
+; CHECK-NEXT:    br label %[[FOR_I_LATCH]]
+; CHECK:       [[FOR_J_SPLIT]]:
+; CHECK-NEXT:    [[TMP0]] = add i64 [[J]], 1
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i64 [[TMP0]], 8
+; CHECK-NEXT:    br i1 [[TMP1]], label %[[EXIT:.*]], label %[[FOR_J]]
+; CHECK:       [[FOR_I_LATCH]]:
+; CHECK-NEXT:    [[I_NEXT]] = add i64 [[I]], 1
+; CHECK-NEXT:    [[EC_I:%.*]] = icmp eq i64 [[I_NEXT]], 8
+; CHECK-NEXT:    br i1 [[EC_I]], label %[[FOR_J_SPLIT]], label %[[FOR_I_HEADER]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %for.i.header
+
+for.i.header:
+  %i = phi i64 [ 0, %entry ], [ %i.next, %for.i.latch ]
+  br label %for.j
+
+for.j:
+  %j = phi i64 [ 0, %for.i.header ], [ %j.next, %for.j ]
+  %old = atomicrmw xchg ptr @g, i64 %j monotonic
+  %j.next = add i64 %j, 1
+  %ec.j = icmp eq i64 %j.next, 8
+  br i1 %ec.j, label %for.i.latch, label %for.j
+
+for.i.latch:
+  %i.next = add i64 %i, 1
+  %ec.i = icmp eq i64 %i.next, 8
+  br i1 %ec.i, label %exit, label %for.i.header
+
+exit:
+  ret void
+}
+
+define void @cmpxchg(i64 %cmp) {
+; CHECK-LABEL: define void @cmpxchg(
+; CHECK-SAME: i64 [[CMP:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    br label %[[FOR_J_PREHEADER:.*]]
+; CHECK:       [[FOR_I_HEADER_PREHEADER:.*]]:
+; CHECK-NEXT:    br label %[[FOR_I_HEADER:.*]]
+; CHECK:       [[FOR_I_HEADER]]:
+; CHECK-NEXT:    [[I:%.*]] = phi i64 [ [[I_NEXT:%.*]], %[[FOR_I_LATCH:.*]] ], [ 0, %[[FOR_I_HEADER_PREHEADER]] ]
+; CHECK-NEXT:    br label %[[FOR_J_SPLIT1:.*]]
+; CHECK:       [[FOR_J_PREHEADER]]:
+; CHECK-NEXT:    br label %[[FOR_J:.*]]
+; CHECK:       [[FOR_J]]:
+; CHECK-NEXT:    [[J:%.*]] = phi i64 [ [[TMP0:%.*]], %[[FOR_J_SPLIT:.*]] ], [ 0, %[[FOR_J_PREHEADER]] ]
+; CHECK-NEXT:    br label %[[FOR_I_HEADER_PREHEADER]]
+; CHECK:       [[FOR_J_SPLIT1]]:
+; CHECK-NEXT:    [[OLD:%.*]] = cmpxchg ptr @g, i64 [[CMP]], i64 [[J]] monotonic monotonic, align 8
+; CHECK-NEXT:    [[J_NEXT:%.*]] = add i64 [[J]], 1
+; CHECK-NEXT:    [[EC_J:%.*]] = icmp eq i64 [[J_NEXT]], 8
+; CHECK-NEXT:    br label %[[FOR_I_LATCH]]
+; CHECK:       [[FOR_J_SPLIT]]:
+; CHECK-NEXT:    [[TMP0]] = add i64 [[J]], 1
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i64 [[TMP0]], 8
+; CHECK-NEXT:    br i1 [[TMP1]], label %[[EXIT:.*]], label %[[FOR_J]]
+; CHECK:       [[FOR_I_LATCH]]:
+; CHECK-NEXT:    [[I_NEXT]] = add i64 [[I]], 1
+; CHECK-NEXT:    [[EC_I:%.*]] = icmp eq i64 [[I_NEXT]], 8
+; CHECK-NEXT:    br i1 [[EC_I]], label %[[FOR_J_SPLIT]], label %[[FOR_I_HEADER]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %for.i.header
+
+for.i.header:
+  %i = phi i64 [ 0, %entry ], [ %i.next, %for.i.latch ]
+  br label %for.j
+
+for.j:
+  %j = phi i64 [ 0, %for.i.header ], [ %j.next, %for.j ]
+  %old = cmpxchg ptr @g, i64 %cmp, i64 %j monotonic monotonic
+  %j.next = add i64 %j, 1
+  %ec.j = icmp eq i64 %j.next, 8
+  br i1 %ec.j, label %for.i.latch, label %for.j
+
+for.i.latch:
+  %i.next = add i64 %i, 1
+  %ec.i = icmp eq i64 %i.next, 8
+  br i1 %ec.i, label %exit, label %for.i.header
+
+exit:
+  ret void
+}
+
+define void @atomic_load_store(ptr noalias %A, ptr noalias %B) {
+; CHECK-LABEL: define void @atomic_load_store(
+; CHECK-SAME: ptr noalias [[A:%.*]], ptr noalias [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    br label %[[FOR_I_HEADER:.*]]
+; CHECK:       [[FOR_I_HEADER]]:
+; CHECK-NEXT:    [[I:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[FOR_I_LATCH:.*]] ]
+; CHECK-NEXT:    br label %[[FOR_J:.*]]
+; CHECK:       [[FOR_J]]:
+; CHECK-NEXT:    [[J:%.*]] = phi i64 [ 0, %[[FOR_I_HEADER]] ], [ [[J_NEXT:%.*]], %[[FOR_J]] ]
+; CHECK-NEXT:    [[GEP_A:%.*]] = getelementptr [8 x i8], ptr [[A]], i64 [[J]], i64 [[I]]
+; CHECK-NEXT:    [[GEP_B:%.*]] = getelementptr [8 x i8], ptr [[B]], i64 [[J]], i64 [[I]]
+; CHECK-NEXT:    [[VAL_A:%.*]] = load atomic i8, ptr [[GEP_A]] monotonic, align 1
+; CHECK-NEXT:    store atomic i8 [[VAL_A]], ptr [[GEP_B]] monotonic, align 1
+; CHECK-NEXT:    [[J_NEXT]] = add i64 [[J]], 1
+; CHECK-NEXT:    [[EC_J:%.*]] = icmp eq i64 [[J_NEXT]], 8
+; CHECK-NEXT:    br i1 [[EC_J]], label %[[FOR_I_LATCH]], label %[[FOR_J]]
+; CHECK:       [[FOR_I_LATCH]]:
+; CHECK-NEXT:    [[I_NEXT]] = add i64 [[I]], 1
+; CHECK-NEXT:    [[EC_I:%.*]] = icmp eq i64 [[I_NEXT]], 8
+; CHECK-NEXT:    br i1 [[EC_I]], label %[[EXIT:.*]], label %[[FOR_I_HEADER]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %for.i.header
+
+for.i.header:
+  %i = phi i64 [ 0, %entry ], [ %i.next, %for.i.latch ]
+  br label %for.j
+
+for.j:
+  %j = phi i64 [ 0, %for.i.header ], [ %j.next, %for.j ]
+  %gep.A = getelementptr [8 x i8], ptr %A, i64 %j, i64 %i
+  %gep.B = getelementptr [8 x i8], ptr %B, i64 %j, i64 %i
+  %val.A = load atomic i8, ptr %gep.A monotonic, align 1
+  store atomic i8 %val.A, ptr %gep.B monotonic, align 1
+  %j.next = add i64 %j, 1
+  %ec.j = icmp eq i64 %j.next, 8
+  br i1 %ec.j, label %for.i.latch, label %for.j
+
+for.i.latch:
+  %i.next = add i64 %i, 1
+  %ec.i = icmp eq i64 %i.next, 8
+  br i1 %ec.i, label %exit, label %for.i.header
+
+exit:
+  ret void
+}

diff  --git a/llvm/test/Transforms/LoopInterchange/invoke.ll b/llvm/test/Transforms/LoopInterchange/invoke.ll
new file mode 100644
index 0000000000000..8365eda175b82
--- /dev/null
+++ b/llvm/test/Transforms/LoopInterchange/invoke.ll
@@ -0,0 +1,74 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt < %s -passes=loop-interchange -loop-interchange-profitabilities=ignore -S | FileCheck %s
+
+ at g = global i64 0
+declare void @rd(ptr)
+declare i32 @__gxx_personality_v0(...)
+
+; The following loops must not be interchanged because the invocation of @rd
+; may read or write the memory.
+;
+; FIXME: Currently the loops pass the legality check.
+;
+define void @invoke_may_rw() personality ptr @__gxx_personality_v0 {
+; CHECK-LABEL: define void @invoke_may_rw() personality ptr @__gxx_personality_v0 {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    br label %[[I_HEADER_PREHEADER:.*]]
+; CHECK:       [[I_HEADER_PREHEADER]]:
+; CHECK-NEXT:    br label %[[I_HEADER:.*]]
+; CHECK:       [[I_HEADER]]:
+; CHECK-NEXT:    [[I:%.*]] = phi i64 [ [[I_NEXT:%.*]], %[[I_LATCH:.*]] ], [ 0, %[[I_HEADER_PREHEADER]] ]
+; CHECK-NEXT:    br label %[[J_HEADER_PREHEADER:.*]]
+; CHECK:       [[J_HEADER_PREHEADER]]:
+; CHECK-NEXT:    br label %[[J_HEADER:.*]]
+; CHECK:       [[J_HEADER]]:
+; CHECK-NEXT:    [[J:%.*]] = phi i64 [ [[TMP0:%.*]], %[[J_LATCH_SPLIT:.*]] ], [ 0, %[[J_HEADER_PREHEADER]] ]
+; CHECK-NEXT:    invoke void @rd(ptr @g)
+; CHECK-NEXT:            to label %[[J_LATCH:.*]] unwind label %[[LP:.*]]
+; CHECK:       [[LP]]:
+; CHECK-NEXT:    [[L:%.*]] = landingpad { ptr, i32 }
+; CHECK-NEXT:            cleanup
+; CHECK-NEXT:    br label %[[J_LATCH]]
+; CHECK:       [[J_LATCH]]:
+; CHECK-NEXT:    [[J_NEXT:%.*]] = add i64 [[J]], 1
+; CHECK-NEXT:    [[EC_J:%.*]] = icmp eq i64 [[J_NEXT]], 8
+; CHECK-NEXT:    br label %[[J_LATCH_SPLIT]]
+; CHECK:       [[J_LATCH_SPLIT]]:
+; CHECK-NEXT:    [[TMP0]] = add i64 [[J]], 1
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i64 [[TMP0]], 8
+; CHECK-NEXT:    br i1 [[TMP1]], label %[[I_LATCH]], label %[[J_HEADER]]
+; CHECK:       [[I_LATCH]]:
+; CHECK-NEXT:    [[I_NEXT]] = add i64 [[I]], 1
+; CHECK-NEXT:    [[EC_I:%.*]] = icmp eq i64 [[I_NEXT]], 8
+; CHECK-NEXT:    br i1 [[EC_I]], label %[[EXIT:.*]], label %[[I_HEADER]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %i.header
+
+i.header:
+  %i = phi i64 [ 0, %entry ], [ %i.next, %i.latch ]
+  br label %j.header
+
+j.header:
+  %j = phi i64 [ 0, %i.header ], [ %j.next, %j.latch ]
+  invoke void @rd(ptr @g) to label %j.latch unwind label %lp
+
+lp:
+  %l = landingpad { ptr, i32 } cleanup
+  br label %j.latch
+
+j.latch:
+  %j.next = add i64 %j, 1
+  %ec.j = icmp eq i64 %j.next, 8
+  br i1 %ec.j, label %i.latch, label %j.header
+
+i.latch:
+  %i.next = add i64 %i, 1
+  %ec.i = icmp eq i64 %i.next, 8
+  br i1 %ec.i, label %exit, label %i.header
+
+exit:
+  ret void
+}


        


More information about the llvm-commits mailing list