123 lines
5.1 KiB
LLVM
123 lines
5.1 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt < %s -passes='function(gvn)' -S | FileCheck -check-prefixes=CHECK-GVN %s
|
|
|
|
; Also do some runs using an GVN+O1 pipeline, using O1 to clean up after GVN.
|
|
; This is to easier see the semantic of the resulting IR and that it hopefully
|
|
; is the same as if only running O1 directly.
|
|
;
|
|
; RUN: opt < %s -passes='function(gvn),default<O1>' -S | FileCheck -check-prefixes=CHECK-GVN-O1 %s
|
|
; RUN: opt < %s -passes='default<O1>' -S | FileCheck -check-prefixes=CHECK-O1 %s
|
|
|
|
; This is a reproducer for the miscompile reported here:
|
|
; https://github.com/llvm/llvm-project/issues/57025
|
|
;
|
|
; Explanation of the test case:
|
|
; - Outer loop will do three iterations i:=0, i:=1 and i:=2
|
|
; - When is i==0 the value 7 is stored to arr[0]
|
|
; - When is i!=0 the value 42 is stored to arr[i]
|
|
; - There is a nestled while loop reduced down to something just setting j:=i
|
|
; and then exiting.
|
|
; - In while.end arr[j] (i.e. the just stored to arr[i]) is loaded,
|
|
; and the loaded value is passed to the verify function.
|
|
; - There is a dead load of the not yet initialized arr[j+1] in the epilog
|
|
; block. This might seem irrelevant, but is needed to reproduce the
|
|
; miscompile.
|
|
;
|
|
; Expected semantic of the function is that verify() will be called three
|
|
; times, with the values 7, 42 and 42.
|
|
|
|
declare void @verify(i16)
|
|
|
|
define void @test(i16 %g) {
|
|
; CHECK-GVN-LABEL: @test(
|
|
; CHECK-GVN-NEXT: entry:
|
|
; CHECK-GVN-NEXT: [[ARR:%.*]] = alloca [4 x i16], align 1
|
|
; CHECK-GVN-NEXT: br label [[FOR_BODY:%.*]]
|
|
; CHECK-GVN: for.body:
|
|
; CHECK-GVN-NEXT: [[I:%.*]] = phi i16 [ 0, [[ENTRY:%.*]] ], [ [[NEXT_I:%.*]], [[WHILE_END:%.*]] ]
|
|
; CHECK-GVN-NEXT: [[CMP0:%.*]] = icmp eq i16 [[I]], 0
|
|
; CHECK-GVN-NEXT: br i1 [[CMP0]], label [[STORE_IDX_0:%.*]], label [[STORE_IDX_I:%.*]]
|
|
; CHECK-GVN: store.idx.0:
|
|
; CHECK-GVN-NEXT: store i16 7, ptr [[ARR]], align 1
|
|
; CHECK-GVN-NEXT: br label [[STORE_DONE:%.*]]
|
|
; CHECK-GVN: store.idx.i:
|
|
; CHECK-GVN-NEXT: [[ARR_I:%.*]] = getelementptr [4 x i16], ptr [[ARR]], i16 0, i16 [[I]]
|
|
; CHECK-GVN-NEXT: store i16 42, ptr [[ARR_I]], align 1
|
|
; CHECK-GVN-NEXT: br label [[STORE_DONE]]
|
|
; CHECK-GVN: store.done:
|
|
; CHECK-GVN-NEXT: br label [[WHILE_BODY:%.*]]
|
|
; CHECK-GVN: while.body:
|
|
; CHECK-GVN-NEXT: br i1 false, label [[WHILE_BODY_WHILE_BODY_CRIT_EDGE:%.*]], label [[WHILE_END]]
|
|
; CHECK-GVN: while.body.while.body_crit_edge:
|
|
; CHECK-GVN-NEXT: br label [[WHILE_BODY]]
|
|
; CHECK-GVN: while.end:
|
|
; CHECK-GVN-NEXT: [[ARR_J:%.*]] = getelementptr [4 x i16], ptr [[ARR]], i16 0, i16 [[I]]
|
|
; CHECK-GVN-NEXT: [[VALUE:%.*]] = load i16, ptr [[ARR_J]], align 1
|
|
; CHECK-GVN-NEXT: tail call void @verify(i16 [[VALUE]])
|
|
; CHECK-GVN-NEXT: [[NEXT_I]] = add i16 [[I]], 1
|
|
; CHECK-GVN-NEXT: [[ARR_NEXT_I:%.*]] = getelementptr [4 x i16], ptr [[ARR]], i16 0, i16 [[NEXT_I]]
|
|
; CHECK-GVN-NEXT: [[CMP4:%.*]] = icmp slt i16 [[NEXT_I]], 3
|
|
; CHECK-GVN-NEXT: br i1 [[CMP4]], label [[FOR_BODY]], label [[FOR_END:%.*]]
|
|
; CHECK-GVN: for.end:
|
|
; CHECK-GVN-NEXT: ret void
|
|
;
|
|
; CHECK-GVN-O1-LABEL: @test(
|
|
; CHECK-GVN-O1-NEXT: entry:
|
|
; CHECK-GVN-O1-NEXT: tail call void @verify(i16 7)
|
|
; CHECK-GVN-O1-NEXT: tail call void @verify(i16 42)
|
|
; CHECK-GVN-O1-NEXT: tail call void @verify(i16 42)
|
|
; CHECK-GVN-O1-NEXT: ret void
|
|
;
|
|
; CHECK-O1-LABEL: @test(
|
|
; CHECK-O1-NEXT: entry:
|
|
; CHECK-O1-NEXT: tail call void @verify(i16 7)
|
|
; CHECK-O1-NEXT: tail call void @verify(i16 42)
|
|
; CHECK-O1-NEXT: tail call void @verify(i16 42)
|
|
; CHECK-O1-NEXT: ret void
|
|
;
|
|
entry:
|
|
%arr = alloca [4 x i16], align 1
|
|
br label %for.body
|
|
|
|
for.body: ; preds = %epilog, %entry
|
|
%i = phi i16 [ 0, %entry ], [ %next.i, %epilog ]
|
|
%cmp0 = icmp eq i16 %i, 0
|
|
br i1 %cmp0, label %store.idx.0, label %store.idx.i
|
|
|
|
store.idx.0: ; preds = %for.body
|
|
store i16 7, ptr %arr, align 1
|
|
br label %store.done
|
|
|
|
store.idx.i: ; preds = %for.body
|
|
%arr.i = getelementptr [4 x i16], ptr %arr, i16 0, i16 %i
|
|
store i16 42, ptr %arr.i, align 1
|
|
br label %store.done
|
|
|
|
store.done: ; preds = %store.idx.i, %store.idx.0
|
|
br label %while.body
|
|
|
|
while.body: ; preds = %while.body, %store.done
|
|
%j = phi i16 [ %i, %store.done ], [ 0, %while.body ]
|
|
; Constant foldable conditional branch.
|
|
; Needed to reproduce the fault!
|
|
br i1 false, label %while.body, label %while.end
|
|
|
|
while.end: ; preds = %while.body
|
|
%arr.j = getelementptr [4 x i16], ptr %arr, i16 0, i16 %j
|
|
%value = load i16, ptr %arr.j, align 1
|
|
tail call void @verify(i16 %value)
|
|
br label %epilog
|
|
|
|
epilog: ; preds = %while.end
|
|
%next.i = add i16 %j, 1
|
|
%arr.next.i = getelementptr [4 x i16], ptr %arr, i16 0, i16 %next.i
|
|
; A dead load.
|
|
; Needed to reproduce the fault!
|
|
%dead = load i16, ptr %arr.next.i, align 1
|
|
%cmp4 = icmp slt i16 %next.i, 3
|
|
br i1 %cmp4, label %for.body, label %for.end
|
|
|
|
for.end: ; preds = %epilog
|
|
ret void
|
|
}
|