1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -passes='function(gvn)' -S | FileCheck -check-prefixes=CHECK-GVN %s 3 4; Also do some runs using an GVN+O1 pipeline, using O1 to clean up after GVN. 5; This is to easier see the semantic of the resulting IR and that it hopefully 6; is the same as if only running O1 directly. 7; 8; RUN: opt < %s -passes='function(gvn),default<O1>' -S | FileCheck -check-prefixes=CHECK-GVN-O1 %s 9; RUN: opt < %s -passes='default<O1>' -S | FileCheck -check-prefixes=CHECK-O1 %s 10 11; This is a reproducer for the miscompile reported here: 12; https://github.com/llvm/llvm-project/issues/57025 13; 14; Explanation of the test case: 15; - Outer loop will do three iterations i:=0, i:=1 and i:=2 16; - When is i==0 the value 7 is stored to arr[0] 17; - When is i!=0 the value 42 is stored to arr[i] 18; - There is a nestled while loop reduced down to something just setting j:=i 19; and then exiting. 20; - In while.end arr[j] (i.e. the just stored to arr[i]) is loaded, 21; and the loaded value is passed to the verify function. 22; - There is a dead load of the not yet initialized arr[j+1] in the epilog 23; block. This might seem irrelevant, but is needed to reproduce the 24; miscompile. 25; 26; Expected semantic of the function is that verify() will be called three 27; times, with the values 7, 42 and 42. 28 29declare void @verify(i16) 30 31define void @test(i16 %g) { 32; CHECK-GVN-LABEL: @test( 33; CHECK-GVN-NEXT: entry: 34; CHECK-GVN-NEXT: [[ARR:%.*]] = alloca [4 x i16], align 1 35; CHECK-GVN-NEXT: br label [[FOR_BODY:%.*]] 36; CHECK-GVN: for.body: 37; CHECK-GVN-NEXT: [[I:%.*]] = phi i16 [ 0, [[ENTRY:%.*]] ], [ [[NEXT_I:%.*]], [[WHILE_END:%.*]] ] 38; CHECK-GVN-NEXT: [[CMP0:%.*]] = icmp eq i16 [[I]], 0 39; CHECK-GVN-NEXT: br i1 [[CMP0]], label [[STORE_IDX_0:%.*]], label [[STORE_IDX_I:%.*]] 40; CHECK-GVN: store.idx.0: 41; CHECK-GVN-NEXT: store i16 7, ptr [[ARR]], align 1 42; CHECK-GVN-NEXT: br label [[STORE_DONE:%.*]] 43; CHECK-GVN: store.idx.i: 44; CHECK-GVN-NEXT: [[ARR_I:%.*]] = getelementptr [4 x i16], ptr [[ARR]], i16 0, i16 [[I]] 45; CHECK-GVN-NEXT: store i16 42, ptr [[ARR_I]], align 1 46; CHECK-GVN-NEXT: br label [[STORE_DONE]] 47; CHECK-GVN: store.done: 48; CHECK-GVN-NEXT: br label [[WHILE_BODY:%.*]] 49; CHECK-GVN: while.body: 50; CHECK-GVN-NEXT: br i1 false, label [[WHILE_BODY_WHILE_BODY_CRIT_EDGE:%.*]], label [[WHILE_END]] 51; CHECK-GVN: while.body.while.body_crit_edge: 52; CHECK-GVN-NEXT: br label [[WHILE_BODY]] 53; CHECK-GVN: while.end: 54; CHECK-GVN-NEXT: [[ARR_J:%.*]] = getelementptr [4 x i16], ptr [[ARR]], i16 0, i16 [[I]] 55; CHECK-GVN-NEXT: [[VALUE:%.*]] = load i16, ptr [[ARR_J]], align 1 56; CHECK-GVN-NEXT: tail call void @verify(i16 [[VALUE]]) 57; CHECK-GVN-NEXT: [[NEXT_I]] = add i16 [[I]], 1 58; CHECK-GVN-NEXT: [[ARR_NEXT_I:%.*]] = getelementptr [4 x i16], ptr [[ARR]], i16 0, i16 [[NEXT_I]] 59; CHECK-GVN-NEXT: [[CMP4:%.*]] = icmp slt i16 [[NEXT_I]], 3 60; CHECK-GVN-NEXT: br i1 [[CMP4]], label [[FOR_BODY]], label [[FOR_END:%.*]] 61; CHECK-GVN: for.end: 62; CHECK-GVN-NEXT: ret void 63; 64; CHECK-GVN-O1-LABEL: @test( 65; CHECK-GVN-O1-NEXT: entry: 66; CHECK-GVN-O1-NEXT: tail call void @verify(i16 7) 67; CHECK-GVN-O1-NEXT: tail call void @verify(i16 42) 68; CHECK-GVN-O1-NEXT: tail call void @verify(i16 42) 69; CHECK-GVN-O1-NEXT: ret void 70; 71; CHECK-O1-LABEL: @test( 72; CHECK-O1-NEXT: entry: 73; CHECK-O1-NEXT: tail call void @verify(i16 7) 74; CHECK-O1-NEXT: tail call void @verify(i16 42) 75; CHECK-O1-NEXT: tail call void @verify(i16 42) 76; CHECK-O1-NEXT: ret void 77; 78entry: 79 %arr = alloca [4 x i16], align 1 80 br label %for.body 81 82for.body: ; preds = %epilog, %entry 83 %i = phi i16 [ 0, %entry ], [ %next.i, %epilog ] 84 %cmp0 = icmp eq i16 %i, 0 85 br i1 %cmp0, label %store.idx.0, label %store.idx.i 86 87store.idx.0: ; preds = %for.body 88 store i16 7, ptr %arr, align 1 89 br label %store.done 90 91store.idx.i: ; preds = %for.body 92 %arr.i = getelementptr [4 x i16], ptr %arr, i16 0, i16 %i 93 store i16 42, ptr %arr.i, align 1 94 br label %store.done 95 96store.done: ; preds = %store.idx.i, %store.idx.0 97 br label %while.body 98 99while.body: ; preds = %while.body, %store.done 100 %j = phi i16 [ %i, %store.done ], [ 0, %while.body ] 101 ; Constant foldable conditional branch. 102 ; Needed to reproduce the fault! 103 br i1 false, label %while.body, label %while.end 104 105while.end: ; preds = %while.body 106 %arr.j = getelementptr [4 x i16], ptr %arr, i16 0, i16 %j 107 %value = load i16, ptr %arr.j, align 1 108 tail call void @verify(i16 %value) 109 br label %epilog 110 111epilog: ; preds = %while.end 112 %next.i = add i16 %j, 1 113 %arr.next.i = getelementptr [4 x i16], ptr %arr, i16 0, i16 %next.i 114 ; A dead load. 115 ; Needed to reproduce the fault! 116 %dead = load i16, ptr %arr.next.i, align 1 117 %cmp4 = icmp slt i16 %next.i, 3 118 br i1 %cmp4, label %for.body, label %for.end 119 120for.end: ; preds = %epilog 121 ret void 122} 123