Skip to content

[LAA] Fix type mismatch in getStartAndEndForAccess.#183116

Merged
kshitijvp merged 9 commits intollvm:mainfrom
kshitijvp:typeMismatch
Mar 11, 2026
Merged

[LAA] Fix type mismatch in getStartAndEndForAccess.#183116
kshitijvp merged 9 commits intollvm:mainfrom
kshitijvp:typeMismatch

Conversation

@kshitijvp
Copy link
Contributor

@kshitijvp kshitijvp commented Feb 24, 2026

SE.getUMaxExpr causes assertion failure due to type mismatch here:

https://github.com/llvm/llvm-project/blob/main/llvm/lib/Analysis/LoopAccessAnalysis.cpp#L253

Running opt -S -p loop-vectorize -debug-only=loop-vectorize llvm/test/Analysis/LoopAccessAnalysis/type-mismatch-in-scalar-evolution.ll without the changes made in LoopAccessAnalysis.cpp causes assertion failure.
This is caused by a type mismatch between SE.getSCEV(DerefRK.IRArgValue) and DerefBytesSCEV.
Fixing this by extending them to the wider type.

@llvmbot llvmbot added the llvm:analysis Includes value tracking, cost tables and constant folding label Feb 24, 2026
@kshitijvp kshitijvp requested a review from fhahn February 24, 2026 18:01
@llvmbot
Copy link
Member

llvmbot commented Feb 24, 2026

@llvm/pr-subscribers-llvm-transforms

@llvm/pr-subscribers-llvm-analysis

Author: Kshitij Paranjape (kshitijvp)

Changes

SE.getUMaxExpr causes assertion failure due to type mismatch here:

https://github.com/llvm/llvm-project/blob/main/llvm/lib/Analysis/LoopAccessAnalysis.cpp#L253

Running opt -S -p loop-vectorize -debug-only=loop-vectorize llvm/test/Analysis/LoopAccessAnalysis/type-mismatch-in-scalar-evolution.ll without the changes made in LoopAccessAnalysis.cpp causes assertion failure.
Attaching the stack dump for reference:

LV: Checking a loop in 'loop_contains_store_assumed_bounds' from input.ll
LV: Loop hints: force=? width=4 interleave=0
LV: Found a loop: for.body
LV: Found an induction variable.
opt: /home/kshitij/llvm-project/llvm/lib/Analysis/ScalarEvolution.cpp:3918: const llvm::SCEV* llvm::ScalarEvolution::getMinMaxExpr(llvm::SCEVTypes, llvm::SmallVectorImpl<const llvm::SCEV*>&): Assertion `getEffectiveSCEVType(Ops[i]->getType()) == ETy && "Operand types don't match!"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace and instructions to reproduce the bug.
Stack dump:
0.	Program arguments: opt -S -passes=loop-vectorize -debug-only=loop-vectorize -force-vector-width=4 -disable-output input.ll
1.	Running pass "function(loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>)" on module "input.ll"
2.	Running pass "loop-vectorize<no-interleave-forced-only;no-vectorize-forced-only;>" on function "loop_contains_store_assumed_bounds"
 #<!-- -->0 0x000058ee97c5e652 llvm::sys::PrintStackTrace(llvm::raw_ostream&amp;, int) (/usr/local/bin/opt+0x4f44652)
 #<!-- -->1 0x000058ee97c5af0f llvm::sys::RunSignalHandlers() (/usr/local/bin/opt+0x4f40f0f)
 #<!-- -->2 0x000058ee97c5b05c SignalHandler(int, siginfo_t*, void*) Signals.cpp:0:0
 #<!-- -->3 0x00007c49d4c45330 (/lib/x86_64-linux-gnu/libc.so.6+0x45330)
 #<!-- -->4 0x00007c49d4c9eb2c __pthread_kill_implementation ./nptl/pthread_kill.c:44:76
 #<!-- -->5 0x00007c49d4c9eb2c __pthread_kill_internal ./nptl/pthread_kill.c:78:10
 #<!-- -->6 0x00007c49d4c9eb2c pthread_kill ./nptl/pthread_kill.c:89:10
 #<!-- -->7 0x00007c49d4c4527e raise ./signal/../sysdeps/posix/raise.c:27:6
 #<!-- -->8 0x00007c49d4c288ff abort ./stdlib/abort.c:81:7
 #<!-- -->9 0x00007c49d4c2881b _nl_load_domain ./intl/loadmsgcat.c:1177:9
#<!-- -->10 0x00007c49d4c3b517 (/lib/x86_64-linux-gnu/libc.so.6+0x3b517)
#<!-- -->11 0x000058ee98003fdb llvm::ScalarEvolution::getMinMaxExpr(llvm::SCEVTypes, llvm::SmallVectorImpl&lt;llvm::SCEV const*&gt;&amp;) (/usr/local/bin/opt+0x52e9fdb)
#<!-- -->12 0x000058ee98004507 llvm::ScalarEvolution::getUMaxExpr(llvm::SCEV const*, llvm::SCEV const*) (/usr/local/bin/opt+0x52ea507)
#<!-- -->13 0x000058ee980dc728 llvm::getStartAndEndForAccess(llvm::Loop const*, llvm::SCEV const*, llvm::Type*, llvm::SCEV const*, llvm::SCEV const*, llvm::ScalarEvolution*, llvm::DenseMap&lt;std::pair&lt;llvm::SCEV const*, llvm::Type*&gt;, std::pair&lt;llvm::SCEV const*, llvm::SCEV const*&gt;, llvm::DenseMapInfo&lt;std::pair&lt;llvm::SCEV const*, llvm::Type*&gt;, void&gt;, llvm::detail::DenseMapPair&lt;std::pair&lt;llvm::SCEV const*, llvm::Type*&gt;, std::pair&lt;llvm::SCEV const*, llvm::SCEV const*&gt;&gt;&gt;*, llvm::DominatorTree*, llvm::AssumptionCache*, std::optional&lt;llvm::ScalarEvolution::LoopGuards&gt;&amp;) (/usr/local/bin/opt+0x53c2728)
#<!-- -->14 0x000058ee9814008b llvm::isDereferenceableAndAlignedInLoop(llvm::LoadInst*, llvm::Loop*, llvm::ScalarEvolution&amp;, llvm::DominatorTree&amp;, llvm::AssumptionCache*, llvm::SmallVectorImpl&lt;llvm::SCEVPredicate const*&gt;*) (/usr/local/bin/opt+0x542608b)
#<!-- -->15 0x000058ee9a0fa1ca llvm::LoopVectorizationLegality::canUncountableExitConditionLoadBeMoved(llvm::BasicBlock*) (/usr/local/bin/opt+0x73e01ca)
#<!-- -->16 0x000058ee9a0faee0 llvm::LoopVectorizationLegality::isVectorizableEarlyExitLoop() (/usr/local/bin/opt+0x73e0ee0)
#<!-- -->17 0x000058ee9a104678 llvm::LoopVectorizationLegality::canVectorize(bool) (/usr/local/bin/opt+0x73ea678)
#<!-- -->18 0x000058ee9a08c953 llvm::LoopVectorizePass::processLoop(llvm::Loop*) (/usr/local/bin/opt+0x7372953)
#<!-- -->19 0x000058ee9a090e21 llvm::LoopVectorizePass::runImpl(llvm::Function&amp;) (/usr/local/bin/opt+0x7376e21)
#<!-- -->20 0x000058ee9a0914e0 llvm::LoopVectorizePass::run(llvm::Function&amp;, llvm::AnalysisManager&lt;llvm::Function&gt;&amp;) (/usr/local/bin/opt+0x73774e0)
#<!-- -->21 0x000058ee99e419a5 llvm::detail::PassModel&lt;llvm::Function, llvm::LoopVectorizePass, llvm::AnalysisManager&lt;llvm::Function&gt;&gt;::run(llvm::Function&amp;, llvm::AnalysisManager&lt;llvm::Function&gt;&amp;) PassBuilderPipelines.cpp:0:0
#<!-- -->22 0x000058ee97f18905 llvm::PassManager&lt;llvm::Function, llvm::AnalysisManager&lt;llvm::Function&gt;&gt;::run(llvm::Function&amp;, llvm::AnalysisManager&lt;llvm::Function&gt;&amp;) (/usr/local/bin/opt+0x51fe905)
#<!-- -->23 0x000058ee995d70d5 llvm::detail::PassModel&lt;llvm::Function, llvm::PassManager&lt;llvm::Function, llvm::AnalysisManager&lt;llvm::Function&gt;&gt;, llvm::AnalysisManager&lt;llvm::Function&gt;&gt;::run(llvm::Function&amp;, llvm::AnalysisManager&lt;llvm::Function&gt;&amp;) AMDGPUTargetMachine.cpp:0:0
#<!-- -->24 0x000058ee97f17051 llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&amp;, llvm::AnalysisManager&lt;llvm::Module&gt;&amp;) (/usr/local/bin/opt+0x51fd051)
#<!-- -->25 0x000058ee995d7775 llvm::detail::PassModel&lt;llvm::Module, llvm::ModuleToFunctionPassAdaptor, llvm::AnalysisManager&lt;llvm::Module&gt;&gt;::run(llvm::Module&amp;, llvm::AnalysisManager&lt;llvm::Module&gt;&amp;) AMDGPUTargetMachine.cpp:0:0
#<!-- -->26 0x000058ee97f1783d llvm::PassManager&lt;llvm::Module, llvm::AnalysisManager&lt;llvm::Module&gt;&gt;::run(llvm::Module&amp;, llvm::AnalysisManager&lt;llvm::Module&gt;&amp;) (/usr/local/bin/opt+0x51fd83d)
#<!-- -->27 0x000058ee9c153909 llvm::runPassPipeline(llvm::StringRef, llvm::Module&amp;, llvm::TargetMachine*, llvm::TargetLibraryInfoImpl*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::StringRef, llvm::ArrayRef&lt;llvm::PassPlugin&gt;, llvm::ArrayRef&lt;std::function&lt;void (llvm::PassBuilder&amp;)&gt;&gt;, llvm::opt_tool::OutputKind, llvm::opt_tool::VerifierKind, bool, bool, bool, bool, bool, bool, bool, bool) (/usr/local/bin/opt+0x9439909)
#<!-- -->28 0x000058ee97c3f380 optMain (/usr/local/bin/opt+0x4f25380)
#<!-- -->29 0x00007c49d4c2a1ca __libc_start_call_main ./csu/../sysdeps/nptl/libc_start_call_main.h:74:3
#<!-- -->30 0x00007c49d4c2a28b call_init ./csu/../csu/libc-start.c:128:20
#<!-- -->31 0x00007c49d4c2a28b __libc_start_main ./csu/../csu/libc-start.c:347:5
#<!-- -->32 0x000058ee97c309a5 _start (/usr/local/bin/opt+0x4f169a5)

This is caused by a type mismatch between SE.getSCEV(DerefRK.IRArgValue) and DerefBytesSCEV.
Fixing this by extending them to the wider type.


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

2 Files Affected:

  • (modified) llvm/lib/Analysis/LoopAccessAnalysis.cpp (+7-2)
  • (added) llvm/test/Analysis/LoopAccessAnalysis/type-mismatch-in-scalar-evolution.ll (+34)
diff --git a/llvm/lib/Analysis/LoopAccessAnalysis.cpp b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
index 057636050db25..67530ac4ba31d 100644
--- a/llvm/lib/Analysis/LoopAccessAnalysis.cpp
+++ b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
@@ -250,8 +250,13 @@ static bool evaluatePtrAddRecAtMaxBTCWillNotWrap(
                          return true;
                        });
   if (DerefRK) {
-    DerefBytesSCEV =
-        SE.getUMaxExpr(DerefBytesSCEV, SE.getSCEV(DerefRK.IRArgValue));
+    const SCEV *DerefRKSCEV = SE.getSCEV(DerefRK.IRArgValue);
+    // Ensure both operands have the same type
+    Type *CommonTy =
+        SE.getWiderType(DerefBytesSCEV->getType(), DerefRKSCEV->getType());
+    DerefBytesSCEV = SE.getNoopOrAnyExtend(DerefBytesSCEV, CommonTy);
+    DerefRKSCEV = SE.getNoopOrAnyExtend(DerefRKSCEV, CommonTy);
+    DerefBytesSCEV = SE.getUMaxExpr(DerefBytesSCEV, DerefRKSCEV);
   }
 
   if (DerefBytesSCEV->isZero())
diff --git a/llvm/test/Analysis/LoopAccessAnalysis/type-mismatch-in-scalar-evolution.ll b/llvm/test/Analysis/LoopAccessAnalysis/type-mismatch-in-scalar-evolution.ll
new file mode 100644
index 0000000000000..0a28775ca290e
--- /dev/null
+++ b/llvm/test/Analysis/LoopAccessAnalysis/type-mismatch-in-scalar-evolution.ll
@@ -0,0 +1,34 @@
+; RUN: opt -S -p loop-vectorize -debug-only=loop-vectorize -force-vector-width=4 -disable-output 2>&1 < %s | FileCheck %s
+; REQUIRES: asserts
+
+; CHECK-LABEL: LV: Checking a loop in 'test_assumed_bounds_type_mismatch'
+; CHECK:       LV: Not vectorizing: Cannot vectorize uncountable loop.
+
+define void @test_assumed_bounds_type_mismatch(ptr noalias %array, ptr readonly %pred, i32 %n) nosync nofree {
+entry:
+  %n_bytes = mul nuw nsw i32 %n, 2
+  call void @llvm.assume(i1 true) [ "dereferenceable"(ptr %pred, i32 %n_bytes) ]
+  %tc = sext i32 %n to i64
+  br label %for.body
+
+for.body:
+  %iv = phi i64 [ 0, %entry ], [ %iv.next, %for.inc ]
+  %st.addr = getelementptr inbounds i16, ptr %array, i64 %iv
+  %data = load i16, ptr %st.addr, align 2
+  %inc = add nsw i16 %data, 1
+  store i16 %inc, ptr %st.addr, align 2
+  %ee.addr = getelementptr inbounds i16, ptr %pred, i64 %iv
+  %ee.val = load i16, ptr %ee.addr, align 2
+  %ee.cond = icmp sgt i16 %ee.val, 500
+  br i1 %ee.cond, label %exit, label %for.inc
+
+for.inc:
+  %iv.next = add nuw nsw i64 %iv, 1
+  %counted.cond = icmp eq i64 %iv.next, %tc
+  br i1 %counted.cond, label %exit, label %for.body
+
+exit:
+  ret void
+}
+
+declare void @llvm.assume(i1)
\ No newline at end of file

@kshitijvp kshitijvp requested a review from nikic February 24, 2026 18:01
@github-actions
Copy link

github-actions bot commented Feb 24, 2026

🪟 Windows x64 Test Results

  • 132104 tests passed
  • 2994 tests skipped

✅ The build succeeded and all tests passed.

@@ -0,0 +1,34 @@
; RUN: opt -S -p loop-vectorize -debug-only=loop-vectorize -force-vector-width=4 -disable-output 2>&1 < %s | FileCheck %s
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you'd need to use -passes=print<aceess-info> for tests in this directory.

would be good to add to other existing early exit tests

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added to the existing one

@github-actions
Copy link

github-actions bot commented Feb 28, 2026

🐧 Linux x64 Test Results

  • 192017 tests passed
  • 4907 tests skipped

✅ The build succeeded and all tests passed.

@kshitijvp
Copy link
Contributor Author

ping

Comment on lines +257 to +258
DerefBytesSCEV = SE.getNoopOrAnyExtend(DerefBytesSCEV, CommonTy);
DerefRKSCEV = SE.getNoopOrAnyExtend(DerefRKSCEV, CommonTy);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why any extend? Both quantities should be positive, so better always use Zext?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

ret void
}

define void @test_assumed_bounds_type_mismatch(ptr noalias %array, ptr readonly %pred, i32 %n) nosync nofree {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a reason we need a loop with a store? If not, would be good to remove the store and add to llvm/test/Transforms/LoopVectorize/dereferenceable-info-from-assumption-variable-size.ll. It should get vectorized with the crash fixed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes the store is redundant in this case, needs to be removed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removing the store instruction is causing faulting load, instead of being vectorized.

Copy link
Contributor

@fhahn fhahn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks

@fhahn fhahn changed the title [LoopAccessAnalysis] Fix type mismatch [LAA] Fix type mismatch in getStartAndEndForAccess. Mar 11, 2026
@kshitijvp
Copy link
Contributor Author

kshitijvp commented Mar 11, 2026

LGTM, thanks

The test will not be vectorized as it is potentially an early exit loop due to

  %iv.next = add nuw nsw i64 %iv, 1
  %counted.cond = icmp eq i64 %iv.next, %tc
  br i1 %counted.cond, label %exit, label %for.body

and removing the store instruction causes faulting load.
So I should move it back to early_exit_store_legality.ll as dereferenceable-info-from-assumption-variable-size.ll has only positive tests (getting vectorized).

@fhahn
Copy link
Contributor

fhahn commented Mar 11, 2026

LGTM, thanks

The test will not be vectorized as it is potentially an early exit loop due to

  %iv.next = add nuw nsw i64 %iv, 1
  %counted.cond = icmp eq i64 %iv.next, %tc
  br i1 %counted.cond, label %exit, label %for.body

and removing the store instruction causes faulting load. So I should move it back to early_exit_store_legality.ll as dereferenceable-info-from-assumption-variable-size.ll has only positive tests (getting vectorized).

It's fine as is. I also went ahead and clarified the PR title, hope that's OK with you

@kshitijvp
Copy link
Contributor Author

kshitijvp commented Mar 11, 2026

Thanks, no issues with the PR title.
Can I merge?

@fhahn
Copy link
Contributor

fhahn commented Mar 11, 2026

Thanks, no issues with the PR title. Can I merge?

sure

@kshitijvp kshitijvp merged commit d432263 into llvm:main Mar 11, 2026
10 checks passed
@xgupta
Copy link
Contributor

xgupta commented Mar 11, 2026

I think you do not need to put complete backtrace in the commit message, we do not do it in practice, describing the issue and solution is enough.

@kshitijvp
Copy link
Contributor Author

I think you do not need to put complete backtrace in the commit message, we do not do it in practice, describing the issue and solution is enough.

Sure, will change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

llvm:analysis Includes value tracking, cost tables and constant folding llvm:transforms

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants