1; RUN: llc -mtriple=x86_64-linux < %s | FileCheck %s 2; RUN: opt -passes='require<profile-summary>,function(codegenprepare)' -S -mtriple=x86_64-linux < %s | FileCheck %s --check-prefix OPT 3 4 5; The exit block containing extractvalue can be duplicated into the BB 6; containing call. And later tail call can be generated. 7 8; CHECK-LABEL: test1: 9; CHECK: je foo # TAILCALL 10; CHECK: jmp bar # TAILCALL 11 12; OPT-LABEL: test1 13; OPT: if.then.i: 14; OPT-NEXT: tail call { ptr, i64 } @bar 15; OPT-NEXT: extractvalue 16; OPT-NEXT: ret 17; 18; OPT: if.end.i: 19; OPT-NEXT: tail call { ptr, i64 } @foo 20; OPT-NEXT: extractvalue 21; OPT-NEXT: ret 22 23define ptr @test1(i64 %size) { 24entry: 25 %cmp.i.i = icmp ugt i64 %size, 16384 26 %add.i.i = add i64 %size, 7 27 %div.i.i = lshr i64 %add.i.i, 3 28 %phitmp.i.i = trunc i64 %div.i.i to i32 29 %cmp1.i = icmp eq i32 %phitmp.i.i, 0 30 %cmp.i = or i1 %cmp.i.i, %cmp1.i 31 br i1 %cmp.i, label %if.end.i, label %if.then.i 32 if.then.i: ; preds = %entry 33 %call1.i = tail call { ptr, i64 } @bar(i64 %size) 34 br label %exit 35 36if.end.i: ; preds = %entry 37 %call2.i = tail call { ptr, i64 } @foo(i64 %size) 38 br label %exit 39 40exit: 41 %call1.i.sink = phi { ptr, i64 } [ %call1.i, %if.then.i ], [ %call2.i, %if.end.i ] 42 %ev = extractvalue { ptr, i64 } %call1.i.sink, 0 43 ret ptr %ev 44} 45 46 47; The extractvalue extracts a field with non-zero offset, so the exit block 48; can't be duplicated. 49 50; CHECK-LABEL: test2: 51; CHECK: callq bar 52; CHECK: callq foo 53 54; OPT-LABEL: test2 55; OPT: if.then.i: 56; OPT-NEXT: tail call { ptr, i64 } @bar 57; OPT-NEXT: br label %exit 58; 59; OPT: if.end.i: 60; OPT-NEXT: tail call { ptr, i64 } @foo 61; OPT-NEXT: br label %exit 62; 63; OPT: exit: 64; OPT-NEXT: phi 65; OPT-NEXT: extractvalue 66; OPT-NEXT: ret 67 68define i64 @test2(i64 %size) { 69entry: 70 %cmp.i.i = icmp ugt i64 %size, 16384 71 %add.i.i = add i64 %size, 7 72 %div.i.i = lshr i64 %add.i.i, 3 73 %phitmp.i.i = trunc i64 %div.i.i to i32 74 %cmp1.i = icmp eq i32 %phitmp.i.i, 0 75 %cmp.i = or i1 %cmp.i.i, %cmp1.i 76 br i1 %cmp.i, label %if.end.i, label %if.then.i 77 if.then.i: ; preds = %entry 78 %call1.i = tail call { ptr, i64 } @bar(i64 %size) 79 br label %exit 80 81if.end.i: ; preds = %entry 82 %call2.i = tail call { ptr, i64 } @foo(i64 %size) 83 br label %exit 84 85exit: 86 %call1.i.sink = phi { ptr, i64 } [ %call1.i, %if.then.i ], [ %call2.i, %if.end.i ] 87 %ev = extractvalue { ptr, i64 } %call1.i.sink, 1 88 ret i64 %ev 89} 90 91 92; The extractvalue accesses a nest struct type, the extracted field has zero 93; offset, so the exit block can still be duplicated, and tail call generated. 94 95; CHECK-LABEL: test3: 96; CHECK: je qux # TAILCALL 97; CHECK: jmp baz # TAILCALL 98 99; OPT-LABEL: test3 100; OPT: if.then.i: 101; OPT-NEXT: tail call { { ptr, i64 }, i64 } @baz 102; OPT-NEXT: extractvalue 103; OPT-NEXT: ret 104; 105; OPT: if.end.i: 106; OPT-NEXT: tail call { { ptr, i64 }, i64 } @qux 107; OPT-NEXT: extractvalue 108; OPT-NEXT: ret 109 110define ptr @test3(i64 %size) { 111entry: 112 %cmp.i.i = icmp ugt i64 %size, 16384 113 %add.i.i = add i64 %size, 7 114 %div.i.i = lshr i64 %add.i.i, 3 115 %phitmp.i.i = trunc i64 %div.i.i to i32 116 %cmp1.i = icmp eq i32 %phitmp.i.i, 0 117 %cmp.i = or i1 %cmp.i.i, %cmp1.i 118 br i1 %cmp.i, label %if.end.i, label %if.then.i 119 120if.then.i: ; preds = %entry 121 %call1.i = tail call { {ptr, i64}, i64 } @baz(i64 %size) 122 br label %exit 123 124if.end.i: ; preds = %entry 125 %call2.i = tail call { {ptr, i64}, i64 } @qux(i64 %size) 126 br label %exit 127 128exit: 129 %call1.i.sink = phi { {ptr, i64}, i64 } [ %call1.i, %if.then.i ], [ %call2.i, %if.end.i ] 130 %ev = extractvalue { {ptr, i64}, i64 } %call1.i.sink, 0, 0 131 ret ptr %ev 132} 133 134 135; The extractvalue accesses a nest struct with non-zero offset, so the exit 136; block can't be duplicated. 137 138; CHECK-LABEL: test4: 139; CHECK: callq baz 140; CHECK: callq qux 141 142; OPT-LABEL: test4 143; OPT: if.then.i: 144; OPT-NEXT: tail call { { ptr, i64 }, i64 } @baz 145; OPT-NEXT: br label %exit 146; 147; OPT: if.end.i: 148; OPT-NEXT: tail call { { ptr, i64 }, i64 } @qux 149; OPT-NEXT: br label %exit 150; 151; OPT: exit: 152; OPT-NEXT: phi 153; OPT-NEXT: extractvalue 154; OPT-NEXT: ret 155 156define i64 @test4(i64 %size) { 157entry: 158 %cmp.i.i = icmp ugt i64 %size, 16384 159 %add.i.i = add i64 %size, 7 160 %div.i.i = lshr i64 %add.i.i, 3 161 %phitmp.i.i = trunc i64 %div.i.i to i32 162 %cmp1.i = icmp eq i32 %phitmp.i.i, 0 163 %cmp.i = or i1 %cmp.i.i, %cmp1.i 164 br i1 %cmp.i, label %if.end.i, label %if.then.i 165 166if.then.i: ; preds = %entry 167 %call1.i = tail call { {ptr, i64}, i64 } @baz(i64 %size) 168 br label %exit 169 170if.end.i: ; preds = %entry 171 %call2.i = tail call { {ptr, i64}, i64 } @qux(i64 %size) 172 br label %exit 173 174exit: 175 %call1.i.sink = phi { {ptr, i64}, i64 } [ %call1.i, %if.then.i ], [ %call2.i, %if.end.i ] 176 %ev = extractvalue { {ptr, i64}, i64 } %call1.i.sink, 0, 1 177 ret i64 %ev 178} 179 180 181declare dso_local { ptr, i64 } @foo(i64) 182declare dso_local { ptr, i64 } @bar(i64) 183declare dso_local { {ptr, i64}, i64 } @baz(i64) 184declare dso_local { {ptr, i64}, i64 } @qux(i64) 185