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