[llvm] [LSV] Merge contiguous chains across scalar types (PR #154069)
Drew Kersnar via llvm-commits
llvm-commits at lists.llvm.org
Tue Dec 2 12:32:25 PST 2025
dakersnar wrote:
Here are two mis-compile examples, one due to breaking of aliasing, and one due to of breaking of contiguity. I think this needs to be reworked from scratch, there are too many issues to safely resolve in follow ups. @arsenm is this sufficient motivation to revert this change?
I also question the overall strategy. This seems like a hacky way to do this, have you explored simply expanding the definition of "equivalence class" to allow all these chain elements in the same chains to begin with, rather than trying to patch them together after the first two filters (aliasing and contiguity) are complete?
```
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
; RUN: opt -mtriple=nvptx64-nvidia-cuda -passes=load-store-vectorizer -S -o - %s | FileCheck %s
; spltiChainByMayAliasInstrs should block this.
define void @correct1(ptr nocapture align 8 %ptr) {
; CHECK-LABEL: define void @correct1(
; CHECK-SAME: ptr align 8 captures(none) [[PTR:%.*]]) {
; CHECK-NEXT: [[PTR0:%.*]] = getelementptr i8, ptr [[PTR]], i64 0
; CHECK-NEXT: [[PTR3:%.*]] = getelementptr i8, ptr [[PTR]], i64 4
; CHECK-NEXT: [[L1:%.*]] = load i32, ptr [[PTR0]], align 8
; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr [[PTR3]], i8 0, i64 1, i1 false)
; CHECK-NEXT: [[L0:%.*]] = load i32, ptr [[PTR3]], align 4
; CHECK-NEXT: ret void
;
%ptr0 = getelementptr i8, ptr %ptr, i64 0
%ptr3 = getelementptr i8, ptr %ptr, i64 4
%l0 = load i32, ptr %ptr0, align 8
call void @llvm.memset.p0.i64(ptr %ptr3, i8 0, i64 1, i1 false)
%l1 = load i32, ptr %ptr3, align 4
ret void
}
; This should be blocked like above due to aliasing, but the merging does not check for aliasing.
define void @miscompile1(ptr nocapture align 8 %ptr) {
; CHECK-LABEL: define void @miscompile1(
; CHECK-SAME: ptr align 8 captures(none) [[PTR:%.*]]) {
; CHECK-NEXT: [[PTR0:%.*]] = getelementptr i8, ptr [[PTR]], i64 0
; CHECK-NEXT: [[PTR3:%.*]] = getelementptr i8, ptr [[PTR]], i64 4
; CHECK-NEXT: [[TMP1:%.*]] = load <2 x i32>, ptr [[PTR0]], align 8
; CHECK-NEXT: [[L11:%.*]] = extractelement <2 x i32> [[TMP1]], i32 0
; CHECK-NEXT: [[L0_MUT2:%.*]] = extractelement <2 x i32> [[TMP1]], i32 1
; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr [[PTR3]], i8 0, i64 1, i1 false)
; CHECK-NEXT: [[L0_MUT_BC:%.*]] = bitcast i32 [[L0_MUT2]] to <2 x i16>
; CHECK-NEXT: ret void
;
%ptr0 = getelementptr i8, ptr %ptr, i64 0
%ptr3 = getelementptr i8, ptr %ptr, i64 4
%l0 = load i32, ptr %ptr0, align 8
call void @llvm.memset.p0.i64(ptr %ptr3, i8 0, i64 1, i1 false)
%l1 = load <2 x i16>, ptr %ptr3, align 4
ret void
}
; This merge 1) breaks the promise of "contiguous" that splitChainByContiguity is supposed to guarantee, but secondly it results in a load
; that is loading more than the original code, which we have established is not legal without using a masked load.
define void @miscompile2(ptr nocapture align 16 %ptr) {
; CHECK-LABEL: define void @miscompile2(
; CHECK-SAME: ptr align 16 captures(none) [[PTR:%.*]]) {
; CHECK-NEXT: [[PTR0:%.*]] = getelementptr i8, ptr [[PTR]], i64 0
; CHECK-NEXT: [[TMP1:%.*]] = load <4 x i32>, ptr [[PTR0]], align 16
; CHECK-NEXT: [[L01:%.*]] = extractelement <4 x i32> [[TMP1]], i32 0
; CHECK-NEXT: [[L1_MUT2:%.*]] = extractelement <4 x i32> [[TMP1]], i32 3
; CHECK-NEXT: [[L1_MUT_BC:%.*]] = bitcast i32 [[L1_MUT2]] to <2 x i16>
; CHECK-NEXT: ret void
;
%ptr0 = getelementptr i8, ptr %ptr, i64 0
; 8 byte gap between ptr0 and ptr1
%ptr1 = getelementptr i8, ptr %ptr, i64 12
%l0 = load i32, ptr %ptr0, align 16
%l1 = load <2 x i16>, ptr %ptr1, align 8
ret void
}
declare void @llvm.memset.p0.i64(ptr, i8, i64, i1)
```
https://github.com/llvm/llvm-project/pull/154069
More information about the llvm-commits
mailing list