[llvm] [LoopInterchange] Forbid interchange if load store type wider than element type (PR #77885)

via llvm-commits llvm-commits at lists.llvm.org
Thu Jan 11 23:39:25 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: None (ShivaChen)

<details>
<summary>Changes</summary>

Consider the following case, interchange is not valid as the store type(int) is wider than the array element type(char).

    char p[7];
    for (int j = 0; j < 2; ++j)
      for (int i = 0; i < 2; ++i)
        *((int*)&p[2*i+j]) = 2*i+j+1;

---
Full diff: https://github.com/llvm/llvm-project/pull/77885.diff


2 Files Affected:

- (modified) llvm/lib/Transforms/Scalar/LoopInterchange.cpp (+38) 
- (added) llvm/test/Transforms/LoopInterchange/not-interchanged-wider-store.ll (+46) 


``````````diff
diff --git a/llvm/lib/Transforms/Scalar/LoopInterchange.cpp b/llvm/lib/Transforms/Scalar/LoopInterchange.cpp
index 277f530ee25fc1..443644c40cebab 100644
--- a/llvm/lib/Transforms/Scalar/LoopInterchange.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopInterchange.cpp
@@ -82,6 +82,40 @@ static void printDepMatrix(CharMatrix &DepMatrix) {
 }
 #endif
 
+// Consider the following case, interchange is not valid as the store type(int)
+// is wider than the array element type(char).
+//
+// char p[7];
+// for (int j = 0; j < 2; ++j)
+//   for (int i = 0; i < 2; ++i)
+//     *((int*)&p[2*i+j]) = 2*i+j+1;
+//
+// Return true if the load/store type is wider than the element type.
+static bool isWiderLoadStore(Instruction *I) {
+  Value *Ptr = getLoadStorePointerOperand(I);
+  Type *ITy = getLoadStoreType(I);
+
+  if (!ITy->isSingleValueType())
+    return false;
+
+  if (auto *GEP = dyn_cast<GetElementPtrInst>(Ptr)) {
+    Type *ElementTy = GEP->getSourceElementType();
+
+    while (isa<ArrayType>(ElementTy)) {
+      ElementTy = ElementTy->getArrayElementType();
+      if (ElementTy->isSingleValueType())
+        if (ITy->getScalarSizeInBits() > ElementTy->getScalarSizeInBits()) {
+          LLVM_DEBUG(dbgs() << "Loads or Stores Type " << *ITy
+                            << " is wider than the element type " << *ElementTy
+                            << "\n");
+          return true;
+        }
+    }
+  }
+
+  return false;
+}
+
 static bool populateDependencyMatrix(CharMatrix &DepMatrix, unsigned Level,
                                      Loop *L, DependenceInfo *DI,
                                      ScalarEvolution *SE) {
@@ -98,10 +132,14 @@ static bool populateDependencyMatrix(CharMatrix &DepMatrix, unsigned Level,
       if (auto *Ld = dyn_cast<LoadInst>(&I)) {
         if (!Ld->isSimple())
           return false;
+        if (isWiderLoadStore(&I))
+          return false;
         MemInstr.push_back(&I);
       } else if (auto *St = dyn_cast<StoreInst>(&I)) {
         if (!St->isSimple())
           return false;
+        if (isWiderLoadStore(&I))
+          return false;
         MemInstr.push_back(&I);
       }
     }
diff --git a/llvm/test/Transforms/LoopInterchange/not-interchanged-wider-store.ll b/llvm/test/Transforms/LoopInterchange/not-interchanged-wider-store.ll
new file mode 100644
index 00000000000000..a50751b1344c78
--- /dev/null
+++ b/llvm/test/Transforms/LoopInterchange/not-interchanged-wider-store.ll
@@ -0,0 +1,46 @@
+; REQUIRES: asserts
+; RUN: opt < %s -passes=loop-interchange -cache-line-size=64 -verify-dom-info -verify-loop-info \
+; RUN:     -S -debug 2>&1 | FileCheck %s
+
+;; Loops should not be interchanged in this case as the store is wider than
+;; array element type
+;;
+;;  char p[7];
+;;  for (int j = 0; j < 2; ++j)
+;;    for (int i = 0; i < 2; ++i)
+;;      *((int*)&p[2*i+j]) = 2*i+j+1;
+
+; CHECK: Loads or Stores Type i32 is wider than the element type i8
+; CHECK: Populating dependency matrix failed
+
+define i32 @main() {
+entry:
+  %p = alloca [7 x i8], align 1
+  br label %for.cond1.preheader
+
+; Loop:
+for.cond1.preheader:                              ; preds = %entry, %for.cond.cleanup3
+  %indvars.iv29 = phi i64 [ 0, %entry ], [ %indvars.iv.next30, %for.cond.cleanup3 ]
+  br label %for.body4
+
+for.cond.cleanup3:                                ; preds = %for.body4
+  %indvars.iv.next30 = add nuw nsw i64 %indvars.iv29, 1
+  %cmp = icmp eq i64 %indvars.iv29, 0
+  br i1 %cmp, label %for.cond1.preheader, label %for.cond.cleanup
+
+for.body4:                                        ; preds = %for.cond1.preheader, %for.body4
+  %indvars.iv = phi i64 [ 0, %for.cond1.preheader ], [ %indvars.iv.next, %for.body4 ]
+  %0 = shl nuw nsw i64 %indvars.iv, 1
+  %1 = add nuw nsw i64 %0, %indvars.iv29
+  %2 = add nuw nsw i64 %1, 1
+  %arrayidx = getelementptr inbounds [7 x i8], ptr %p, i64 0, i64 %1
+  %3 = trunc i64 %2 to i32
+  store i32 %3, ptr %arrayidx, align 1
+  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+  %cmp2 = icmp eq i64 %indvars.iv, 0
+  br i1 %cmp2, label %for.body4, label %for.cond.cleanup3
+
+; Exit blocks
+for.cond.cleanup:                                 ; preds = %for.cond.cleanup3
+  ret i32 0
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/77885


More information about the llvm-commits mailing list