GVNSink produces incorrect codegen with respect to GEPs #85333
Description
target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
target triple = "thumbv7em-none-unknown-eabi"
%"struct.std::pair" = type <{ i32, %struct.substruct, [2 x i8] }>
%struct.substruct = type { i8, i8 }
%"struct.std::random_access_iterator_tag" = type { i8 }
define linkonce_odr dso_local void @__advance(ptr noundef nonnull align 4 dereferenceable(4) %__i, i32 noundef %__n) local_unnamed_addr {
entry:
%0 = call i1 @llvm.is.constant.i32(i32 %__n)
%cmp = icmp eq i32 %__n, 1
%or.cond = and i1 %0, %cmp
br i1 %or.cond, label %if.then, label %if.else
if.then: ; preds = %entry
%1 = load ptr, ptr %__i, align 4
%incdec.ptr = getelementptr inbounds i8, ptr %1, i32 8
store ptr %incdec.ptr, ptr %__i, align 4
br label %if.end6
if.else: ; preds = %entry
%2 = call i1 @llvm.is.constant.i32(i32 %__n)
%cmp2 = icmp eq i32 %__n, -1
%or.cond7 = and i1 %2, %cmp2
br i1 %or.cond7, label %if.then3, label %if.else5
if.then3: ; preds = %if.else
%3 = load ptr, ptr %__i, align 4
%incdec.ptr4 = getelementptr inbounds i8, ptr %3, i32 -8
store ptr %incdec.ptr4, ptr %__i, align 4
br label %if.end6
if.else5: ; preds = %if.else
%4 = load ptr, ptr %__i, align 4
%add.ptr = getelementptr inbounds %"struct.std::pair", ptr %4, i32 %__n
store ptr %add.ptr, ptr %__i, align 4
br label %if.end6
if.end6: ; preds = %if.then3, %if.else5, %if.then
ret void
}
The above IR when piped through gvn-sink via ./bin/opt < /tmp/repro.ll -passes=gvn-sink -S
produces:
; ModuleID = '<stdin>'
source_filename = "<stdin>"
target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
target triple = "thumbv7em-none-unknown-eabi"
define linkonce_odr dso_local void @__advance(ptr noundef nonnull align 4 dereferenceable(4) %__i, i32 noundef %__n) local_unnamed_addr {
entry:
%0 = call i1 @llvm.is.constant.i32(i32 %__n)
%cmp = icmp eq i32 %__n, 1
%or.cond = and i1 %0, %cmp
br i1 %or.cond, label %if.then, label %if.else
if.then: ; preds = %entry
br label %if.end6
if.else: ; preds = %entry
%1 = call i1 @llvm.is.constant.i32(i32 %__n)
%cmp2 = icmp eq i32 %__n, -1
%or.cond7 = and i1 %1, %cmp2
br i1 %or.cond7, label %if.then3, label %if.else5
if.then3: ; preds = %if.else
br label %if.end6
if.else5: ; preds = %if.else
br label %if.end6
if.end6: ; preds = %if.else5, %if.then3, %if.then
%.sink1 = phi i32 [ 8, %if.then ], [ -8, %if.then3 ], [ %__n, %if.else5 ]
%2 = load ptr, ptr %__i, align 4
%incdec.ptr = getelementptr inbounds i8, ptr %2, i32 %.sink1
store ptr %incdec.ptr, ptr %__i, align 4
ret void
}
; Function Attrs: convergent nocallback nofree nosync nounwind willreturn memory(none)
declare i1 @llvm.is.constant.i32(i32) #0
attributes #0 = { convergent nocallback nofree nosync nounwind willreturn memory(none) }
The GEP in the result is incorrect. Prior, the GEPs were
%incdec.ptr = getelementptr inbounds i8, ptr %1, i32 8
%incdec.ptr4 = getelementptr inbounds i8, ptr %3, i32 -8
%add.ptr = getelementptr inbounds %"struct.std::pair", ptr %4, i32 %__n
but now it's
%incdec.ptr = getelementptr inbounds i8, ptr %2, i32 %.sink1
This results in an incorrect offset for %add.ptr = getelementptr inbounds %"struct.std::pair", ptr %4, i32 %__n
since we'd now just add %.sink1
bytes (where %.sink1 = %__n
which is the second argument), whereas before we'd add %__n * 8
bytes (where 8 is the sizeof %"struct.std::pair"
).
The before ASM is:
__advance:
ldr r2, [r0]
add.w r1, r2, r1, lsl #3
str r1, [r0]
bx lr
but the after asm is:
__advance:
ldr r2, [r0]
add r1, r2
str r1, [r0]
bx lr
The GEP should not be a candidate for sinking.
Activity