| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals smart | |
| ; RUN: opt -passes=instcombine -S < %s | FileCheck %s | |
| declare void @use.i1(i1) | |
| declare void @use.i8(i8) | |
| ; Basic test | |
| define i8 @andcond(i1 %inner.cond, i1 %alt.cond, i8 %inner.sel.trueval, i8 %inner.sel.falseval, i8 %outer.sel.trueval) { | |
| ; CHECK-LABEL: @andcond( | |
| ; CHECK-NEXT: [[INNER_SEL:%.*]] = select i1 [[ALT_COND:%.*]], i8 [[OUTER_SEL_TRUEVAL:%.*]], i8 [[INNER_SEL_TRUEVAL:%.*]] | |
| ; CHECK-NEXT: [[OUTER_SEL:%.*]] = select i1 [[INNER_COND:%.*]], i8 [[INNER_SEL]], i8 [[INNER_SEL_FALSEVAL:%.*]] | |
| ; CHECK-NEXT: ret i8 [[OUTER_SEL]] | |
| ; | |
| %outer.cond = select i1 %inner.cond, i1 %alt.cond, i1 false ; and %inner.cond, %alt.cond | |
| %inner.sel = select i1 %inner.cond, i8 %inner.sel.trueval, i8 %inner.sel.falseval | |
| %outer.sel = select i1 %outer.cond, i8 %outer.sel.trueval, i8 %inner.sel | |
| ret i8 %outer.sel | |
| } | |
| define i8 @orcond(i1 %inner.cond, i1 %alt.cond, i8 %inner.sel.trueval, i8 %inner.sel.falseval, i8 %outer.sel.falseval) { | |
| ; CHECK-LABEL: @orcond( | |
| ; CHECK-NEXT: [[INNER_SEL:%.*]] = select i1 [[ALT_COND:%.*]], i8 [[INNER_SEL_FALSEVAL:%.*]], i8 [[OUTER_SEL_FALSEVAL:%.*]] | |
| ; CHECK-NEXT: [[OUTER_SEL:%.*]] = select i1 [[INNER_COND:%.*]], i8 [[INNER_SEL_TRUEVAL:%.*]], i8 [[INNER_SEL]] | |
| ; CHECK-NEXT: ret i8 [[OUTER_SEL]] | |
| ; | |
| %outer.cond = select i1 %inner.cond, i1 true, i1 %alt.cond ; or %inner.cond, %alt.cond | |
| %inner.sel = select i1 %inner.cond, i8 %inner.sel.trueval, i8 %inner.sel.falseval | |
| %outer.sel = select i1 %outer.cond, i8 %inner.sel, i8 %outer.sel.falseval | |
| ret i8 %outer.sel | |
| } | |
| ; Extra use tests (basic test, no inversions) | |
| define i8 @andcond.extrause0(i1 %inner.cond, i1 %alt.cond, i8 %inner.sel.trueval, i8 %inner.sel.falseval, i8 %outer.sel.trueval) { | |
| ; CHECK-LABEL: @andcond.extrause0( | |
| ; CHECK-NEXT: [[OUTER_COND:%.*]] = select i1 [[INNER_COND:%.*]], i1 [[ALT_COND:%.*]], i1 false | |
| ; CHECK-NEXT: call void @use.i1(i1 [[OUTER_COND]]) | |
| ; CHECK-NEXT: [[INNER_SEL:%.*]] = select i1 [[ALT_COND]], i8 [[OUTER_SEL_TRUEVAL:%.*]], i8 [[INNER_SEL_TRUEVAL:%.*]] | |
| ; CHECK-NEXT: [[OUTER_SEL:%.*]] = select i1 [[INNER_COND]], i8 [[INNER_SEL]], i8 [[INNER_SEL_FALSEVAL:%.*]] | |
| ; CHECK-NEXT: ret i8 [[OUTER_SEL]] | |
| ; | |
| %outer.cond = select i1 %inner.cond, i1 %alt.cond, i1 false | |
| call void @use.i1(i1 %outer.cond) | |
| %inner.sel = select i1 %inner.cond, i8 %inner.sel.trueval, i8 %inner.sel.falseval | |
| %outer.sel = select i1 %outer.cond, i8 %outer.sel.trueval, i8 %inner.sel | |
| ret i8 %outer.sel | |
| } | |
| define i8 @orcond.extrause0(i1 %inner.cond, i1 %alt.cond, i8 %inner.sel.trueval, i8 %inner.sel.falseval, i8 %outer.sel.falseval) { | |
| ; CHECK-LABEL: @orcond.extrause0( | |
| ; CHECK-NEXT: [[OUTER_COND:%.*]] = select i1 [[INNER_COND:%.*]], i1 true, i1 [[ALT_COND:%.*]] | |
| ; CHECK-NEXT: call void @use.i1(i1 [[OUTER_COND]]) | |
| ; CHECK-NEXT: [[INNER_SEL:%.*]] = select i1 [[ALT_COND]], i8 [[INNER_SEL_FALSEVAL:%.*]], i8 [[OUTER_SEL_FALSEVAL:%.*]] | |
| ; CHECK-NEXT: [[OUTER_SEL:%.*]] = select i1 [[INNER_COND]], i8 [[INNER_SEL_TRUEVAL:%.*]], i8 [[INNER_SEL]] | |
| ; CHECK-NEXT: ret i8 [[OUTER_SEL]] | |
| ; | |
| %outer.cond = select i1 %inner.cond, i1 true, i1 %alt.cond | |
| call void @use.i1(i1 %outer.cond) | |
| %inner.sel = select i1 %inner.cond, i8 %inner.sel.trueval, i8 %inner.sel.falseval | |
| %outer.sel = select i1 %outer.cond, i8 %inner.sel, i8 %outer.sel.falseval | |
| ret i8 %outer.sel | |
| } | |
| define i8 @andcond.extrause1(i1 %inner.cond, i1 %alt.cond, i8 %inner.sel.trueval, i8 %inner.sel.falseval, i8 %outer.sel.trueval) { | |
| ; CHECK-LABEL: @andcond.extrause1( | |
| ; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[INNER_COND:%.*]], i8 [[INNER_SEL_TRUEVAL:%.*]], i8 [[INNER_SEL_FALSEVAL:%.*]] | |
| ; CHECK-NEXT: call void @use.i8(i8 [[TMP1]]) | |
| ; CHECK-NEXT: [[INNER_SEL:%.*]] = select i1 [[ALT_COND:%.*]], i8 [[OUTER_SEL_TRUEVAL:%.*]], i8 [[INNER_SEL_TRUEVAL]] | |
| ; CHECK-NEXT: [[OUTER_SEL:%.*]] = select i1 [[INNER_COND]], i8 [[INNER_SEL]], i8 [[INNER_SEL_FALSEVAL]] | |
| ; CHECK-NEXT: ret i8 [[OUTER_SEL]] | |
| ; | |
| %outer.cond = select i1 %inner.cond, i1 %alt.cond, i1 false | |
| %inner.sel = select i1 %inner.cond, i8 %inner.sel.trueval, i8 %inner.sel.falseval | |
| call void @use.i8(i8 %inner.sel) | |
| %outer.sel = select i1 %outer.cond, i8 %outer.sel.trueval, i8 %inner.sel | |
| ret i8 %outer.sel | |
| } | |
| define i8 @orcond.extrause1(i1 %inner.cond, i1 %alt.cond, i8 %inner.sel.trueval, i8 %inner.sel.falseval, i8 %outer.sel.falseval) { | |
| ; CHECK-LABEL: @orcond.extrause1( | |
| ; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[INNER_COND:%.*]], i8 [[INNER_SEL_TRUEVAL:%.*]], i8 [[INNER_SEL_FALSEVAL:%.*]] | |
| ; CHECK-NEXT: call void @use.i8(i8 [[TMP1]]) | |
| ; CHECK-NEXT: [[INNER_SEL:%.*]] = select i1 [[ALT_COND:%.*]], i8 [[INNER_SEL_FALSEVAL]], i8 [[OUTER_SEL_FALSEVAL:%.*]] | |
| ; CHECK-NEXT: [[OUTER_SEL:%.*]] = select i1 [[INNER_COND]], i8 [[INNER_SEL_TRUEVAL]], i8 [[INNER_SEL]] | |
| ; CHECK-NEXT: ret i8 [[OUTER_SEL]] | |
| ; | |
| %outer.cond = select i1 %inner.cond, i1 true, i1 %alt.cond | |
| %inner.sel = select i1 %inner.cond, i8 %inner.sel.trueval, i8 %inner.sel.falseval | |
| call void @use.i8(i8 %inner.sel) | |
| %outer.sel = select i1 %outer.cond, i8 %inner.sel, i8 %outer.sel.falseval | |
| ret i8 %outer.sel | |
| } | |
| define i8 @andcond.extrause2(i1 %inner.cond, i1 %alt.cond, i8 %inner.sel.trueval, i8 %inner.sel.falseval, i8 %outer.sel.trueval) { | |
| ; CHECK-LABEL: @andcond.extrause2( | |
| ; CHECK-NEXT: [[OUTER_COND:%.*]] = select i1 [[INNER_COND:%.*]], i1 [[ALT_COND:%.*]], i1 false | |
| ; CHECK-NEXT: call void @use.i1(i1 [[OUTER_COND]]) | |
| ; CHECK-NEXT: [[INNER_SEL:%.*]] = select i1 [[INNER_COND]], i8 [[INNER_SEL_TRUEVAL:%.*]], i8 [[INNER_SEL_FALSEVAL:%.*]] | |
| ; CHECK-NEXT: call void @use.i8(i8 [[INNER_SEL]]) | |
| ; CHECK-NEXT: [[OUTER_SEL:%.*]] = select i1 [[OUTER_COND]], i8 [[OUTER_SEL_TRUEVAL:%.*]], i8 [[INNER_SEL]] | |
| ; CHECK-NEXT: ret i8 [[OUTER_SEL]] | |
| ; | |
| %outer.cond = select i1 %inner.cond, i1 %alt.cond, i1 false | |
| call void @use.i1(i1 %outer.cond) | |
| %inner.sel = select i1 %inner.cond, i8 %inner.sel.trueval, i8 %inner.sel.falseval | |
| call void @use.i8(i8 %inner.sel) | |
| %outer.sel = select i1 %outer.cond, i8 %outer.sel.trueval, i8 %inner.sel | |
| ret i8 %outer.sel | |
| } | |
| define i8 @orcond.extrause2(i1 %inner.cond, i1 %alt.cond, i8 %inner.sel.trueval, i8 %inner.sel.falseval, i8 %outer.sel.falseval) { | |
| ; CHECK-LABEL: @orcond.extrause2( | |
| ; CHECK-NEXT: [[OUTER_COND:%.*]] = select i1 [[INNER_COND:%.*]], i1 true, i1 [[ALT_COND:%.*]] | |
| ; CHECK-NEXT: call void @use.i1(i1 [[OUTER_COND]]) | |
| ; CHECK-NEXT: [[INNER_SEL:%.*]] = select i1 [[INNER_COND]], i8 [[INNER_SEL_TRUEVAL:%.*]], i8 [[INNER_SEL_FALSEVAL:%.*]] | |
| ; CHECK-NEXT: call void @use.i8(i8 [[INNER_SEL]]) | |
| ; CHECK-NEXT: [[OUTER_SEL:%.*]] = select i1 [[OUTER_COND]], i8 [[INNER_SEL]], i8 [[OUTER_SEL_FALSEVAL:%.*]] | |
| ; CHECK-NEXT: ret i8 [[OUTER_SEL]] | |
| ; | |
| %outer.cond = select i1 %inner.cond, i1 true, i1 %alt.cond | |
| call void @use.i1(i1 %outer.cond) | |
| %inner.sel = select i1 %inner.cond, i8 %inner.sel.trueval, i8 %inner.sel.falseval | |
| call void @use.i8(i8 %inner.sel) | |
| %outer.sel = select i1 %outer.cond, i8 %inner.sel, i8 %outer.sel.falseval | |
| ret i8 %outer.sel | |
| } | |
| ; Mismatched 'common' cond | |
| define i8 @andcond.different.inner.cond(i1 %inner.cond.v0, i1 %inner.cond.v1, i1 %alt.cond, i8 %inner.sel.trueval, i8 %inner.sel.falseval, i8 %outer.sel.trueval) { | |
| ; CHECK-LABEL: @andcond.different.inner.cond( | |
| ; CHECK-NEXT: [[OUTER_COND:%.*]] = select i1 [[INNER_COND_V0:%.*]], i1 [[ALT_COND:%.*]], i1 false | |
| ; CHECK-NEXT: [[INNER_SEL:%.*]] = select i1 [[INNER_COND_V1:%.*]], i8 [[INNER_SEL_TRUEVAL:%.*]], i8 [[INNER_SEL_FALSEVAL:%.*]] | |
| ; CHECK-NEXT: [[OUTER_SEL:%.*]] = select i1 [[OUTER_COND]], i8 [[OUTER_SEL_TRUEVAL:%.*]], i8 [[INNER_SEL]] | |
| ; CHECK-NEXT: ret i8 [[OUTER_SEL]] | |
| ; | |
| %outer.cond = select i1 %inner.cond.v0, i1 %alt.cond, i1 false | |
| %inner.sel = select i1 %inner.cond.v1, i8 %inner.sel.trueval, i8 %inner.sel.falseval | |
| %outer.sel = select i1 %outer.cond, i8 %outer.sel.trueval, i8 %inner.sel | |
| ret i8 %outer.sel | |
| } | |
| define i8 @orcond.different.inner.cond(i1 %inner.cond.v0, i1 %inner.cond.v1, i1 %alt.cond, i8 %inner.sel.trueval, i8 %inner.sel.falseval, i8 %outer.sel.falseval) { | |
| ; CHECK-LABEL: @orcond.different.inner.cond( | |
| ; CHECK-NEXT: [[OUTER_COND:%.*]] = select i1 [[INNER_COND_V0:%.*]], i1 true, i1 [[ALT_COND:%.*]] | |
| ; CHECK-NEXT: [[INNER_SEL:%.*]] = select i1 [[INNER_COND_V1:%.*]], i8 [[INNER_SEL_TRUEVAL:%.*]], i8 [[INNER_SEL_FALSEVAL:%.*]] | |
| ; CHECK-NEXT: [[OUTER_SEL:%.*]] = select i1 [[OUTER_COND]], i8 [[INNER_SEL]], i8 [[OUTER_SEL_FALSEVAL:%.*]] | |
| ; CHECK-NEXT: ret i8 [[OUTER_SEL]] | |
| ; | |
| %outer.cond = select i1 %inner.cond.v0, i1 true, i1 %alt.cond | |
| %inner.sel = select i1 %inner.cond.v1, i8 %inner.sel.trueval, i8 %inner.sel.falseval | |
| %outer.sel = select i1 %outer.cond, i8 %inner.sel, i8 %outer.sel.falseval | |
| ret i8 %outer.sel | |
| } | |
| define i1 @andcond.different.inner.cond.both.inverted(i1 %inner.cond.v0, i1 %inner.cond.v1, i1 %alt.cond, i1 %inner.sel.trueval, i1 %inner.sel.falseval, i1 %outer.sel.trueval) { | |
| ; CHECK-LABEL: @andcond.different.inner.cond.both.inverted( | |
| ; CHECK-NEXT: [[NOT_INNER_COND_0:%.*]] = xor i1 [[INNER_COND_V0:%.*]], true | |
| ; CHECK-NEXT: [[OUTER_COND:%.*]] = select i1 [[NOT_INNER_COND_0]], i1 [[ALT_COND:%.*]], i1 false | |
| ; CHECK-NEXT: [[NOT_INNER_COND_1:%.*]] = xor i1 [[INNER_COND_V1:%.*]], true | |
| ; CHECK-NEXT: [[INNER_SEL:%.*]] = select i1 [[NOT_INNER_COND_1]], i1 [[INNER_SEL_FALSEVAL:%.*]], i1 false | |
| ; CHECK-NEXT: [[OUTER_SEL:%.*]] = select i1 [[OUTER_COND]], i1 [[OUTER_SEL_TRUEVAL:%.*]], i1 [[INNER_SEL]] | |
| ; CHECK-NEXT: ret i1 [[OUTER_SEL]] | |
| ; | |
| %not.inner.cond.0 = xor i1 %inner.cond.v0, -1 | |
| %outer.cond = select i1 %not.inner.cond.0, i1 %alt.cond, i1 false ; and %inner.cond, %alt.cond | |
| %not.inner.cond.1 = xor i1 %inner.cond.v1, -1 | |
| %inner.sel = select i1 %not.inner.cond.1, i1 %inner.sel.falseval, i1 false | |
| %outer.sel = select i1 %outer.cond, i1 %outer.sel.trueval, i1 %inner.sel | |
| ret i1 %outer.sel | |
| } | |
| define i1 @orcond.different.inner.cond.both.inverted(i1 %inner.cond.v0, i1 %inner.cond.v1, i1 %alt.cond, i1 %inner.sel.trueval, i1 %inner.sel.falseval, i1 %outer.sel.falseval) { | |
| ; CHECK-LABEL: @orcond.different.inner.cond.both.inverted( | |
| ; CHECK-NEXT: [[NOT_INNER_COND_0:%.*]] = xor i1 [[INNER_COND_V0:%.*]], true | |
| ; CHECK-NEXT: [[OUTER_COND:%.*]] = select i1 [[NOT_INNER_COND_0]], i1 true, i1 [[ALT_COND:%.*]] | |
| ; CHECK-NEXT: [[NOT_INNER_COND_1:%.*]] = xor i1 [[INNER_COND_V1:%.*]], true | |
| ; CHECK-NEXT: [[INNER_SEL:%.*]] = select i1 [[NOT_INNER_COND_1]], i1 true, i1 [[INNER_SEL_TRUEVAL:%.*]] | |
| ; CHECK-NEXT: [[OUTER_SEL:%.*]] = select i1 [[OUTER_COND]], i1 [[INNER_SEL]], i1 [[OUTER_SEL_FALSEVAL:%.*]] | |
| ; CHECK-NEXT: ret i1 [[OUTER_SEL]] | |
| ; | |
| %not.inner.cond.0 = xor i1 %inner.cond.v0, -1 | |
| %outer.cond = select i1 %not.inner.cond.0, i1 true, i1 %alt.cond ; or %inner.cond, %alt.cond | |
| %not.inner.cond.1 = xor i1 %inner.cond.v1, -1 | |
| %inner.sel = select i1 %not.inner.cond.1, i1 true, i1 %inner.sel.trueval | |
| %outer.sel = select i1 %outer.cond, i1 %inner.sel, i1 %outer.sel.falseval | |
| ret i1 %outer.sel | |
| } | |
| define i1 @andcond.different.inner.cond.inverted.in.outer.cond(i1 %inner.cond.v0, i1 %inner.cond.v1, i1 %alt.cond, i1 %inner.sel.trueval, i1 %inner.sel.falseval, i1 %outer.sel.trueval) { | |
| ; CHECK-LABEL: @andcond.different.inner.cond.inverted.in.outer.cond( | |
| ; CHECK-NEXT: [[NOT_INNER_COND_0:%.*]] = xor i1 [[INNER_COND_V0:%.*]], true | |
| ; CHECK-NEXT: [[OUTER_COND:%.*]] = select i1 [[NOT_INNER_COND_0]], i1 [[ALT_COND:%.*]], i1 false | |
| ; CHECK-NEXT: [[INNER_SEL:%.*]] = select i1 [[INNER_COND_V1:%.*]], i1 [[INNER_SEL_FALSEVAL:%.*]], i1 false | |
| ; CHECK-NEXT: [[OUTER_SEL:%.*]] = select i1 [[OUTER_COND]], i1 [[OUTER_SEL_TRUEVAL:%.*]], i1 [[INNER_SEL]] | |
| ; CHECK-NEXT: ret i1 [[OUTER_SEL]] | |
| ; | |
| %not.inner.cond.0 = xor i1 %inner.cond.v0, -1 | |
| %outer.cond = select i1 %not.inner.cond.0, i1 %alt.cond, i1 false ; and %inner.cond, %alt.cond | |
| %inner.sel = select i1 %inner.cond.v1, i1 %inner.sel.falseval, i1 false | |
| %outer.sel = select i1 %outer.cond, i1 %outer.sel.trueval, i1 %inner.sel | |
| ret i1 %outer.sel | |
| } | |
| define i1 @orcond.different.inner.cond.inverted.in.outer.cond(i1 %inner.cond.v0, i1 %inner.cond.v1, i1 %alt.cond, i1 %inner.sel.trueval, i1 %inner.sel.falseval, i1 %outer.sel.falseval) { | |
| ; CHECK-LABEL: @orcond.different.inner.cond.inverted.in.outer.cond( | |
| ; CHECK-NEXT: [[NOT_INNER_COND_0:%.*]] = xor i1 [[INNER_COND_V0:%.*]], true | |
| ; CHECK-NEXT: [[OUTER_COND:%.*]] = select i1 [[NOT_INNER_COND_0]], i1 true, i1 [[ALT_COND:%.*]] | |
| ; CHECK-NEXT: [[INNER_SEL:%.*]] = select i1 [[INNER_COND_V1:%.*]], i1 true, i1 [[INNER_SEL_TRUEVAL:%.*]] | |
| ; CHECK-NEXT: [[OUTER_SEL:%.*]] = select i1 [[OUTER_COND]], i1 [[INNER_SEL]], i1 [[OUTER_SEL_FALSEVAL:%.*]] | |
| ; CHECK-NEXT: ret i1 [[OUTER_SEL]] | |
| ; | |
| %not.inner.cond.0 = xor i1 %inner.cond.v0, -1 | |
| %outer.cond = select i1 %not.inner.cond.0, i1 true, i1 %alt.cond ; or %inner.cond, %alt.cond | |
| %inner.sel = select i1 %inner.cond.v1, i1 true, i1 %inner.sel.trueval | |
| %outer.sel = select i1 %outer.cond, i1 %inner.sel, i1 %outer.sel.falseval | |
| ret i1 %outer.sel | |
| } | |
| define i1 @andcond.different.inner.cond.inverted.in.inner.sel(i1 %inner.cond.v0, i1 %inner.cond.v1, i1 %alt.cond, i1 %inner.sel.trueval, i1 %inner.sel.falseval, i1 %outer.sel.trueval) { | |
| ; CHECK-LABEL: @andcond.different.inner.cond.inverted.in.inner.sel( | |
| ; CHECK-NEXT: [[OUTER_COND:%.*]] = select i1 [[INNER_COND_V0:%.*]], i1 [[ALT_COND:%.*]], i1 false | |
| ; CHECK-NEXT: [[NOT_INNER_COND_1:%.*]] = xor i1 [[INNER_COND_V1:%.*]], true | |
| ; CHECK-NEXT: [[INNER_SEL:%.*]] = select i1 [[NOT_INNER_COND_1]], i1 [[INNER_SEL_FALSEVAL:%.*]], i1 false | |
| ; CHECK-NEXT: [[OUTER_SEL:%.*]] = select i1 [[OUTER_COND]], i1 [[OUTER_SEL_TRUEVAL:%.*]], i1 [[INNER_SEL]] | |
| ; CHECK-NEXT: ret i1 [[OUTER_SEL]] | |
| ; | |
| %outer.cond = select i1 %inner.cond.v0, i1 %alt.cond, i1 false ; and %inner.cond, %alt.cond | |
| %not.inner.cond.1 = xor i1 %inner.cond.v1, -1 | |
| %inner.sel = select i1 %not.inner.cond.1, i1 %inner.sel.falseval, i1 false | |
| %outer.sel = select i1 %outer.cond, i1 %outer.sel.trueval, i1 %inner.sel | |
| ret i1 %outer.sel | |
| } | |
| define i1 @orcond.different.inner.cond.inverted.in.inner.sel(i1 %inner.cond.v0, i1 %inner.cond.v1, i1 %alt.cond, i1 %inner.sel.trueval, i1 %inner.sel.falseval, i1 %outer.sel.falseval) { | |
| ; CHECK-LABEL: @orcond.different.inner.cond.inverted.in.inner.sel( | |
| ; CHECK-NEXT: [[OUTER_COND:%.*]] = select i1 [[INNER_COND_V0:%.*]], i1 true, i1 [[ALT_COND:%.*]] | |
| ; CHECK-NEXT: [[NOT_INNER_COND_1:%.*]] = xor i1 [[INNER_COND_V1:%.*]], true | |
| ; CHECK-NEXT: [[INNER_SEL:%.*]] = select i1 [[NOT_INNER_COND_1]], i1 true, i1 [[INNER_SEL_TRUEVAL:%.*]] | |
| ; CHECK-NEXT: [[OUTER_SEL:%.*]] = select i1 [[OUTER_COND]], i1 [[INNER_SEL]], i1 [[OUTER_SEL_FALSEVAL:%.*]] | |
| ; CHECK-NEXT: ret i1 [[OUTER_SEL]] | |
| ; | |
| %outer.cond = select i1 %inner.cond.v0, i1 true, i1 %alt.cond ; or %inner.cond, %alt.cond | |
| %not.inner.cond.1 = xor i1 %inner.cond.v1, -1 | |
| %inner.sel = select i1 %not.inner.cond.1, i1 true, i1 %inner.sel.trueval | |
| %outer.sel = select i1 %outer.cond, i1 %inner.sel, i1 %outer.sel.falseval | |
| ret i1 %outer.sel | |
| } | |
| ; Not an inversion | |
| ; Based on reproduced from https://reviews.llvm.org/D139275#4001580 | |
| define i8 @D139275_c4001580(i1 %c0, i1 %c1, i1 %c2, i8 %inner.sel.trueval, i8 %inner.sel.falseval, i8 %outer.sel.trueval) { | |
| ; CHECK-LABEL: @D139275_c4001580( | |
| ; CHECK-NEXT: [[INNER_COND:%.*]] = xor i1 [[C0:%.*]], [[C1:%.*]] | |
| ; CHECK-NEXT: [[OUTER_COND:%.*]] = and i1 [[C2:%.*]], [[C1]] | |
| ; CHECK-NEXT: [[INNER_SEL:%.*]] = select i1 [[INNER_COND]], i8 [[INNER_SEL_TRUEVAL:%.*]], i8 [[INNER_SEL_FALSEVAL:%.*]] | |
| ; CHECK-NEXT: [[OUTER_SEL:%.*]] = select i1 [[OUTER_COND]], i8 [[OUTER_SEL_TRUEVAL:%.*]], i8 [[INNER_SEL]] | |
| ; CHECK-NEXT: ret i8 [[OUTER_SEL]] | |
| ; | |
| %inner.cond = xor i1 %c0, %c1 | |
| %outer.cond = and i1 %c2, %c1 | |
| %inner.sel = select i1 %inner.cond, i8 %inner.sel.trueval, i8 %inner.sel.falseval | |
| %outer.sel = select i1 %outer.cond, i8 %outer.sel.trueval, i8 %inner.sel | |
| ret i8 %outer.sel | |
| } | |
| ; Tests with intervening inversions | |
| ; In %outer.sel, %outer.cond is inverted | |
| define i1 @andcond.001.inv.outer.cond(i1 %inner.cond, i1 %alt.cond, i1 %inner.sel.trueval, i1 %inner.sel.falseval, i1 %outer.sel.trueval) { | |
| ; CHECK-LABEL: @andcond.001.inv.outer.cond( | |
| ; CHECK-NEXT: [[NOT_ALT_COND:%.*]] = xor i1 [[ALT_COND:%.*]], true | |
| ; CHECK-NEXT: [[INNER_SEL:%.*]] = select i1 [[NOT_ALT_COND]], i1 [[INNER_SEL_TRUEVAL:%.*]], i1 false | |
| ; CHECK-NEXT: [[OUTER_SEL:%.*]] = select i1 [[INNER_COND:%.*]], i1 [[INNER_SEL]], i1 [[INNER_SEL_FALSEVAL:%.*]] | |
| ; CHECK-NEXT: ret i1 [[OUTER_SEL]] | |
| ; | |
| %outer.cond = select i1 %inner.cond, i1 %alt.cond, i1 false ; and %inner.cond, %alt.cond | |
| %inner.sel = select i1 %inner.cond, i1 %inner.sel.trueval, i1 %inner.sel.falseval | |
| %not.outer.cond = xor i1 %outer.cond, -1 | |
| %outer.sel = select i1 %not.outer.cond, i1 %inner.sel, i1 false | |
| ret i1 %outer.sel | |
| } | |
| define i1 @orcond.001.inv.outer.cond(i1 %inner.cond, i1 %alt.cond, i1 %inner.sel.trueval, i1 %inner.sel.falseval, i1 %outer.sel.falseval) { | |
| ; CHECK-LABEL: @orcond.001.inv.outer.cond( | |
| ; CHECK-NEXT: [[NOT_ALT_COND:%.*]] = xor i1 [[ALT_COND:%.*]], true | |
| ; CHECK-NEXT: [[INNER_SEL:%.*]] = select i1 [[NOT_ALT_COND]], i1 true, i1 [[INNER_SEL_FALSEVAL:%.*]] | |
| ; CHECK-NEXT: [[OUTER_SEL:%.*]] = select i1 [[INNER_COND:%.*]], i1 [[INNER_SEL_TRUEVAL:%.*]], i1 [[INNER_SEL]] | |
| ; CHECK-NEXT: ret i1 [[OUTER_SEL]] | |
| ; | |
| %outer.cond = select i1 %inner.cond, i1 true, i1 %alt.cond ; or %inner.cond, %alt.cond | |
| %inner.sel = select i1 %inner.cond, i1 %inner.sel.trueval, i1 %inner.sel.falseval | |
| %not.outer.cond = xor i1 %outer.cond, -1 | |
| %outer.sel = select i1 %not.outer.cond, i1 true, i1 %inner.sel | |
| ret i1 %outer.sel | |
| } | |
| ; In %inner.sel, %inner.cond is inverted | |
| define i1 @andcond.010.inv.inner.cond.in.inner.sel(i1 %inner.cond, i1 %alt.cond, i1 %inner.sel.trueval, i1 %inner.sel.falseval, i1 %outer.sel.trueval) !prof !0 { | |
| ; CHECK-LABEL: @andcond.010.inv.inner.cond.in.inner.sel( | |
| ; CHECK-NEXT: [[INNER_SEL:%.*]] = select i1 [[ALT_COND:%.*]], i1 [[OUTER_SEL_TRUEVAL:%.*]], i1 false, !prof [[PROF1:![0-9]+]] | |
| ; CHECK-NEXT: [[OUTER_SEL:%.*]] = select i1 [[INNER_COND:%.*]], i1 [[INNER_SEL]], i1 [[INNER_SEL_FALSEVAL:%.*]], !prof [[PROF2:![0-9]+]] | |
| ; CHECK-NEXT: ret i1 [[OUTER_SEL]] | |
| ; | |
| %outer.cond = select i1 %inner.cond, i1 %alt.cond, i1 false ; and %inner.cond, %alt.cond, !prof !1 | |
| %not.inner.cond = xor i1 %inner.cond, -1 | |
| %inner.sel = select i1 %not.inner.cond, i1 %inner.sel.falseval, i1 false, !prof !2 | |
| %outer.sel = select i1 %outer.cond, i1 %outer.sel.trueval, i1 %inner.sel, !prof !3 | |
| ret i1 %outer.sel | |
| } | |
| define i1 @orcond.010.inv.inner.cond.in.inner.sel(i1 %inner.cond, i1 %alt.cond, i1 %inner.sel.trueval, i1 %inner.sel.falseval, i1 %outer.sel.falseval) { | |
| ; CHECK-LABEL: @orcond.010.inv.inner.cond.in.inner.sel( | |
| ; CHECK-NEXT: [[INNER_SEL:%.*]] = select i1 [[ALT_COND:%.*]], i1 true, i1 [[OUTER_SEL_FALSEVAL:%.*]] | |
| ; CHECK-NEXT: [[OUTER_SEL:%.*]] = select i1 [[INNER_COND:%.*]], i1 [[INNER_SEL_TRUEVAL:%.*]], i1 [[INNER_SEL]] | |
| ; CHECK-NEXT: ret i1 [[OUTER_SEL]] | |
| ; | |
| %outer.cond = select i1 %inner.cond, i1 true, i1 %alt.cond ; or %inner.cond, %alt.cond | |
| %not.inner.cond = xor i1 %inner.cond, -1 | |
| %inner.sel = select i1 %not.inner.cond, i1 true, i1 %inner.sel.trueval | |
| %outer.sel = select i1 %outer.cond, i1 %inner.sel, i1 %outer.sel.falseval | |
| ret i1 %outer.sel | |
| } | |
| ; In %outer.cond, %inner.cond is inverted | |
| define i8 @andcond.100.inv.inner.cond.in.outer.cond(i1 %inner.cond, i1 %alt.cond, i8 %inner.sel.trueval, i8 %inner.sel.falseval, i8 %outer.sel.trueval) { | |
| ; CHECK-LABEL: @andcond.100.inv.inner.cond.in.outer.cond( | |
| ; CHECK-NEXT: [[INNER_SEL:%.*]] = select i1 [[ALT_COND:%.*]], i8 [[OUTER_SEL_TRUEVAL:%.*]], i8 [[INNER_SEL_FALSEVAL:%.*]] | |
| ; CHECK-NEXT: [[OUTER_SEL:%.*]] = select i1 [[INNER_COND:%.*]], i8 [[INNER_SEL_TRUEVAL:%.*]], i8 [[INNER_SEL]] | |
| ; CHECK-NEXT: ret i8 [[OUTER_SEL]] | |
| ; | |
| %not.inner.cond = xor i1 %inner.cond, -1 | |
| %outer.cond = select i1 %not.inner.cond, i1 %alt.cond, i1 false ; and %inner.cond, %alt.cond | |
| %inner.sel = select i1 %inner.cond, i8 %inner.sel.trueval, i8 %inner.sel.falseval | |
| %outer.sel = select i1 %outer.cond, i8 %outer.sel.trueval, i8 %inner.sel | |
| ret i8 %outer.sel | |
| } | |
| define i8 @orcond.100.inv.inner.cond.in.outer.cond(i1 %inner.cond, i1 %alt.cond, i8 %inner.sel.trueval, i8 %inner.sel.falseval, i8 %outer.sel.falseval) { | |
| ; CHECK-LABEL: @orcond.100.inv.inner.cond.in.outer.cond( | |
| ; CHECK-NEXT: [[INNER_SEL:%.*]] = select i1 [[ALT_COND:%.*]], i8 [[INNER_SEL_TRUEVAL:%.*]], i8 [[OUTER_SEL_FALSEVAL:%.*]] | |
| ; CHECK-NEXT: [[OUTER_SEL:%.*]] = select i1 [[INNER_COND:%.*]], i8 [[INNER_SEL]], i8 [[INNER_SEL_FALSEVAL:%.*]] | |
| ; CHECK-NEXT: ret i8 [[OUTER_SEL]] | |
| ; | |
| %not.inner.cond = xor i1 %inner.cond, -1 | |
| %outer.cond = select i1 %not.inner.cond, i1 true, i1 %alt.cond ; or %inner.cond, %alt.cond | |
| %inner.sel = select i1 %inner.cond, i8 %inner.sel.trueval, i8 %inner.sel.falseval | |
| %outer.sel = select i1 %outer.cond, i8 %inner.sel, i8 %outer.sel.falseval | |
| ret i8 %outer.sel | |
| } | |
| ; In %outer.sel, %outer.cond is inverted | |
| ; In %inner.sel, %inner.cond is inverted | |
| define i1 @andcond.011.inv.outer.cond.inv.inner.cond.in.inner.sel(i1 %inner.cond, i1 %alt.cond, i1 %inner.sel.trueval, i1 %inner.sel.falseval, i1 %outer.sel.trueval) { | |
| ; CHECK-LABEL: @andcond.011.inv.outer.cond.inv.inner.cond.in.inner.sel( | |
| ; CHECK-NEXT: [[NOT_INNER_COND:%.*]] = xor i1 [[INNER_COND:%.*]], true | |
| ; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[NOT_INNER_COND]], i1 true, i1 [[INNER_SEL_FALSEVAL:%.*]] | |
| ; CHECK-NEXT: call void @use.i1(i1 [[TMP1]]) | |
| ; CHECK-NEXT: [[NOT_ALT_COND:%.*]] = xor i1 [[ALT_COND:%.*]], true | |
| ; CHECK-NEXT: [[INNER_SEL:%.*]] = select i1 [[NOT_ALT_COND]], i1 [[INNER_SEL_FALSEVAL]], i1 false | |
| ; CHECK-NEXT: [[NOT_INNER_COND1:%.*]] = xor i1 [[INNER_COND]], true | |
| ; CHECK-NEXT: [[OUTER_SEL:%.*]] = select i1 [[NOT_INNER_COND1]], i1 true, i1 [[INNER_SEL]] | |
| ; CHECK-NEXT: ret i1 [[OUTER_SEL]] | |
| ; | |
| %outer.cond = select i1 %inner.cond, i1 %alt.cond, i1 false ; and %inner.cond, %alt.cond | |
| %not.inner.cond = xor i1 %inner.cond, -1 | |
| %inner.sel = select i1 %not.inner.cond, i1 true, i1 %inner.sel.falseval | |
| %not.outer.cond = xor i1 %outer.cond, -1 | |
| call void @use.i1(i1 %inner.sel) | |
| %outer.sel = select i1 %not.outer.cond, i1 %inner.sel, i1 false | |
| ret i1 %outer.sel | |
| } | |
| define i1 @orcond.011.inv.outer.cond.inv.inner.cond.in.inner.sel(i1 %inner.cond, i1 %alt.cond, i1 %inner.sel.trueval, i1 %inner.sel.falseval, i1 %outer.sel.falseval) { | |
| ; CHECK-LABEL: @orcond.011.inv.outer.cond.inv.inner.cond.in.inner.sel( | |
| ; CHECK-NEXT: [[NOT_INNER_COND:%.*]] = xor i1 [[INNER_COND:%.*]], true | |
| ; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[NOT_INNER_COND]], i1 [[INNER_SEL_TRUEVAL:%.*]], i1 false | |
| ; CHECK-NEXT: call void @use.i1(i1 [[TMP1]]) | |
| ; CHECK-NEXT: [[NOT_ALT_COND:%.*]] = xor i1 [[ALT_COND:%.*]], true | |
| ; CHECK-NEXT: [[INNER_SEL:%.*]] = select i1 [[NOT_ALT_COND]], i1 true, i1 [[INNER_SEL_TRUEVAL]] | |
| ; CHECK-NEXT: [[NOT_INNER_COND1:%.*]] = xor i1 [[INNER_COND]], true | |
| ; CHECK-NEXT: [[OUTER_SEL:%.*]] = select i1 [[NOT_INNER_COND1]], i1 [[INNER_SEL]], i1 false | |
| ; CHECK-NEXT: ret i1 [[OUTER_SEL]] | |
| ; | |
| %outer.cond = select i1 %inner.cond, i1 true, i1 %alt.cond ; or %inner.cond, %alt.cond | |
| %not.inner.cond = xor i1 %inner.cond, -1 | |
| %inner.sel = select i1 %not.inner.cond, i1 %inner.sel.trueval, i1 false | |
| call void @use.i1(i1 %inner.sel) | |
| %not.outer.cond = xor i1 %outer.cond, -1 | |
| %outer.sel = select i1 %not.outer.cond, i1 true, i1 %inner.sel | |
| ret i1 %outer.sel | |
| } | |
| ; In %outer.sel, %outer.cond is inverted | |
| ; In %outer.cond, %inner.cond is inverted | |
| define i1 @andcond.101.inv.outer.cond.inv.inner.cond.in.outer.cond(i1 %inner.cond, i1 %alt.cond, i1 %inner.sel.trueval, i1 %inner.sel.falseval, i1 %outer.sel.trueval) { | |
| ; CHECK-LABEL: @andcond.101.inv.outer.cond.inv.inner.cond.in.outer.cond( | |
| ; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[INNER_COND:%.*]], i1 [[INNER_SEL_TRUEVAL:%.*]], i1 [[INNER_SEL_FALSEVAL:%.*]] | |
| ; CHECK-NEXT: call void @use.i1(i1 [[TMP1]]) | |
| ; CHECK-NEXT: [[ALT_COND_NOT:%.*]] = xor i1 [[ALT_COND:%.*]], true | |
| ; CHECK-NEXT: [[INNER_SEL:%.*]] = select i1 [[ALT_COND_NOT]], i1 [[INNER_SEL_FALSEVAL]], i1 false | |
| ; CHECK-NEXT: [[OUTER_SEL:%.*]] = select i1 [[INNER_COND]], i1 [[INNER_SEL_TRUEVAL]], i1 [[INNER_SEL]] | |
| ; CHECK-NEXT: ret i1 [[OUTER_SEL]] | |
| ; | |
| %not.inner.cond = xor i1 %inner.cond, -1 | |
| %outer.cond = select i1 %not.inner.cond, i1 %alt.cond, i1 false ; and %inner.cond, %alt.cond | |
| %inner.sel = select i1 %inner.cond, i1 %inner.sel.trueval, i1 %inner.sel.falseval | |
| call void @use.i1(i1 %inner.sel) | |
| %not.outer.cond = xor i1 %outer.cond, -1 | |
| %outer.sel = select i1 %not.outer.cond, i1 %inner.sel, i1 false | |
| ret i1 %outer.sel | |
| } | |
| define i1 @orcond.101.inv.outer.cond.inv.inner.cond.in.outer.cond(i1 %inner.cond, i1 %alt.cond, i1 %inner.sel.trueval, i1 %inner.sel.falseval, i1 %outer.sel.falseval) { | |
| ; CHECK-LABEL: @orcond.101.inv.outer.cond.inv.inner.cond.in.outer.cond( | |
| ; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[INNER_COND:%.*]], i1 [[INNER_SEL_TRUEVAL:%.*]], i1 [[INNER_SEL_FALSEVAL:%.*]] | |
| ; CHECK-NEXT: call void @use.i1(i1 [[TMP1]]) | |
| ; CHECK-NEXT: [[ALT_COND_NOT:%.*]] = xor i1 [[ALT_COND:%.*]], true | |
| ; CHECK-NEXT: [[INNER_SEL:%.*]] = select i1 [[ALT_COND_NOT]], i1 true, i1 [[INNER_SEL_TRUEVAL]] | |
| ; CHECK-NEXT: [[OUTER_SEL:%.*]] = select i1 [[INNER_COND]], i1 [[INNER_SEL]], i1 [[INNER_SEL_FALSEVAL]] | |
| ; CHECK-NEXT: ret i1 [[OUTER_SEL]] | |
| ; | |
| %not.inner.cond = xor i1 %inner.cond, -1 | |
| %outer.cond = select i1 %not.inner.cond, i1 true, i1 %alt.cond ; or %inner.cond, %alt.cond | |
| %inner.sel = select i1 %inner.cond, i1 %inner.sel.trueval, i1 %inner.sel.falseval | |
| call void @use.i1(i1 %inner.sel) | |
| %not.outer.cond = xor i1 %outer.cond, -1 | |
| %outer.sel = select i1 %not.outer.cond, i1 true, i1 %inner.sel | |
| ret i1 %outer.sel | |
| } | |
| ; In %inner.sel, %inner.cond is inverted | |
| ; In %outer.cond, %inner.cond is inverted | |
| define i1 @andcond.110.inv.inner.cond.in.inner.sel.inv.inner.cond.in.outer.cond(i1 %inner.cond, i1 %alt.cond, i1 %inner.sel.trueval, i1 %inner.sel.falseval, i1 %outer.sel.trueval) { | |
| ; CHECK-LABEL: @andcond.110.inv.inner.cond.in.inner.sel.inv.inner.cond.in.outer.cond( | |
| ; CHECK-NEXT: [[NOT_INNER_COND_0:%.*]] = xor i1 [[INNER_COND:%.*]], true | |
| ; CHECK-NEXT: [[INNER_SEL:%.*]] = select i1 [[ALT_COND:%.*]], i1 [[OUTER_SEL_TRUEVAL:%.*]], i1 [[INNER_SEL_FALSEVAL:%.*]] | |
| ; CHECK-NEXT: [[OUTER_SEL:%.*]] = select i1 [[NOT_INNER_COND_0]], i1 [[INNER_SEL]], i1 false | |
| ; CHECK-NEXT: ret i1 [[OUTER_SEL]] | |
| ; | |
| %not.inner.cond.0 = xor i1 %inner.cond, -1 | |
| %outer.cond = select i1 %not.inner.cond.0, i1 %alt.cond, i1 false ; and %inner.cond, %alt.cond | |
| %not.inner.cond.1 = xor i1 %inner.cond, -1 | |
| %inner.sel = select i1 %not.inner.cond.1, i1 %inner.sel.falseval, i1 false | |
| %outer.sel = select i1 %outer.cond, i1 %outer.sel.trueval, i1 %inner.sel | |
| ret i1 %outer.sel | |
| } | |
| define i1 @orcond.110.inv.inner.cond.in.inner.sel.inv.inner.cond.in.outer.cond(i1 %inner.cond, i1 %alt.cond, i1 %inner.sel.trueval, i1 %inner.sel.falseval, i1 %outer.sel.falseval) { | |
| ; CHECK-LABEL: @orcond.110.inv.inner.cond.in.inner.sel.inv.inner.cond.in.outer.cond( | |
| ; CHECK-NEXT: [[NOT_INNER_COND_0:%.*]] = xor i1 [[INNER_COND:%.*]], true | |
| ; CHECK-NEXT: [[INNER_SEL:%.*]] = select i1 [[ALT_COND:%.*]], i1 [[INNER_SEL_TRUEVAL:%.*]], i1 [[OUTER_SEL_FALSEVAL:%.*]] | |
| ; CHECK-NEXT: [[OUTER_SEL:%.*]] = select i1 [[NOT_INNER_COND_0]], i1 true, i1 [[INNER_SEL]] | |
| ; CHECK-NEXT: ret i1 [[OUTER_SEL]] | |
| ; | |
| %not.inner.cond.0 = xor i1 %inner.cond, -1 | |
| %outer.cond = select i1 %not.inner.cond.0, i1 true, i1 %alt.cond ; or %inner.cond, %alt.cond | |
| %not.inner.cond.1 = xor i1 %inner.cond, -1 | |
| %inner.sel = select i1 %not.inner.cond.1, i1 true, i1 %inner.sel.trueval | |
| %outer.sel = select i1 %outer.cond, i1 %inner.sel, i1 %outer.sel.falseval | |
| ret i1 %outer.sel | |
| } | |
| ; In %outer.sel, %outer.cond is inverted | |
| ; In %inner.sel, %inner.cond is inverted | |
| ; In %outer.cond, %inner.cond is inverted | |
| define i1 @andcond.111.inv.all.conds(i1 %inner.cond, i1 %alt.cond, i1 %inner.sel.trueval, i1 %inner.sel.falseval, i1 %outer.sel.trueval) { | |
| ; CHECK-LABEL: @andcond.111.inv.all.conds( | |
| ; CHECK-NEXT: [[NOT_INNER_COND_0:%.*]] = xor i1 [[INNER_COND:%.*]], true | |
| ; CHECK-NEXT: [[OUTER_COND:%.*]] = select i1 [[NOT_INNER_COND_0]], i1 [[ALT_COND:%.*]], i1 false | |
| ; CHECK-NEXT: call void @use.i1(i1 [[OUTER_COND]]) | |
| ; CHECK-NEXT: [[NOT_INNER_COND_1:%.*]] = xor i1 [[INNER_COND]], true | |
| ; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[NOT_INNER_COND_1]], i1 [[INNER_SEL_FALSEVAL:%.*]], i1 false | |
| ; CHECK-NEXT: call void @use.i1(i1 [[TMP1]]) | |
| ; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[INNER_COND]], i1 true, i1 [[ALT_COND]] | |
| ; CHECK-NEXT: [[TMP3:%.*]] = xor i1 [[TMP2]], true | |
| ; CHECK-NEXT: [[OUTER_SEL:%.*]] = select i1 [[TMP3]], i1 [[INNER_SEL_FALSEVAL]], i1 false | |
| ; CHECK-NEXT: ret i1 [[OUTER_SEL]] | |
| ; | |
| %not.inner.cond.0 = xor i1 %inner.cond, -1 | |
| %outer.cond = select i1 %not.inner.cond.0, i1 %alt.cond, i1 false ; and %inner.cond, %alt.cond | |
| call void @use.i1(i1 %outer.cond) | |
| %not.inner.cond.1 = xor i1 %inner.cond, -1 | |
| %inner.sel = select i1 %not.inner.cond.1, i1 %inner.sel.falseval, i1 false | |
| call void @use.i1(i1 %inner.sel) | |
| %not.outer.cond = xor i1 %outer.cond, -1 | |
| %outer.sel = select i1 %not.outer.cond, i1 %inner.sel, i1 false | |
| ret i1 %outer.sel | |
| } | |
| define i1 @orcond.111.inv.all.conds(i1 %inner.cond, i1 %alt.cond, i1 %inner.sel.trueval, i1 %inner.sel.falseval, i1 %outer.sel.falseval) { | |
| ; CHECK-LABEL: @orcond.111.inv.all.conds( | |
| ; CHECK-NEXT: [[NOT_INNER_COND_0:%.*]] = xor i1 [[INNER_COND:%.*]], true | |
| ; CHECK-NEXT: [[OUTER_COND:%.*]] = select i1 [[NOT_INNER_COND_0]], i1 true, i1 [[ALT_COND:%.*]] | |
| ; CHECK-NEXT: call void @use.i1(i1 [[OUTER_COND]]) | |
| ; CHECK-NEXT: [[NOT_INNER_COND_1:%.*]] = xor i1 [[INNER_COND]], true | |
| ; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[NOT_INNER_COND_1]], i1 true, i1 [[INNER_SEL_TRUEVAL:%.*]] | |
| ; CHECK-NEXT: call void @use.i1(i1 [[TMP1]]) | |
| ; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[INNER_COND]], i1 [[ALT_COND]], i1 false | |
| ; CHECK-NEXT: [[TMP3:%.*]] = xor i1 [[TMP2]], true | |
| ; CHECK-NEXT: [[OUTER_SEL:%.*]] = select i1 [[TMP3]], i1 true, i1 [[INNER_SEL_TRUEVAL]] | |
| ; CHECK-NEXT: ret i1 [[OUTER_SEL]] | |
| ; | |
| %not.inner.cond.0 = xor i1 %inner.cond, -1 | |
| %outer.cond = select i1 %not.inner.cond.0, i1 true, i1 %alt.cond ; or %inner.cond, %alt.cond | |
| call void @use.i1(i1 %outer.cond) | |
| %not.inner.cond.1 = xor i1 %inner.cond, -1 | |
| %inner.sel = select i1 %not.inner.cond.1, i1 true, i1 %inner.sel.trueval | |
| call void @use.i1(i1 %inner.sel) | |
| %not.outer.cond = xor i1 %outer.cond, -1 | |
| %outer.sel = select i1 %not.outer.cond, i1 true, i1 %inner.sel | |
| ret i1 %outer.sel | |
| } | |
| define i8 @test_implied_true(i8 %x) { | |
| ; CHECK-LABEL: @test_implied_true( | |
| ; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i8 [[X:%.*]], 0 | |
| ; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[CMP2]], i8 0, i8 20 | |
| ; CHECK-NEXT: ret i8 [[SEL2]] | |
| ; | |
| %cmp1 = icmp slt i8 %x, 10 | |
| %cmp2 = icmp slt i8 %x, 0 | |
| %sel1 = select i1 %cmp1, i8 0, i8 5 | |
| %sel2 = select i1 %cmp2, i8 %sel1, i8 20 | |
| ret i8 %sel2 | |
| } | |
| define <2 x i8> @test_implied_true_vec(<2 x i8> %x) { | |
| ; CHECK-LABEL: @test_implied_true_vec( | |
| ; CHECK-NEXT: [[CMP2:%.*]] = icmp slt <2 x i8> [[X:%.*]], zeroinitializer | |
| ; CHECK-NEXT: [[SEL2:%.*]] = select <2 x i1> [[CMP2]], <2 x i8> zeroinitializer, <2 x i8> splat (i8 20) | |
| ; CHECK-NEXT: ret <2 x i8> [[SEL2]] | |
| ; | |
| %cmp1 = icmp slt <2 x i8> %x, <i8 10, i8 10> | |
| %cmp2 = icmp slt <2 x i8> %x, zeroinitializer | |
| %sel1 = select <2 x i1> %cmp1, <2 x i8> zeroinitializer, <2 x i8> <i8 5, i8 5> | |
| %sel2 = select <2 x i1> %cmp2, <2 x i8> %sel1, <2 x i8> <i8 20, i8 20> | |
| ret <2 x i8> %sel2 | |
| } | |
| define i8 @test_implied_true_falseval(i8 %x) { | |
| ; CHECK-LABEL: @test_implied_true_falseval( | |
| ; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i8 [[X:%.*]], 0 | |
| ; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[CMP2]], i8 20, i8 0 | |
| ; CHECK-NEXT: ret i8 [[SEL2]] | |
| ; | |
| %cmp1 = icmp slt i8 %x, 10 | |
| %cmp2 = icmp sgt i8 %x, 0 | |
| %sel1 = select i1 %cmp1, i8 0, i8 5 | |
| %sel2 = select i1 %cmp2, i8 20, i8 %sel1 | |
| ret i8 %sel2 | |
| } | |
| define i8 @test_implied_false(i8 %x) { | |
| ; CHECK-LABEL: @test_implied_false( | |
| ; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i8 [[X:%.*]], 0 | |
| ; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[CMP2]], i8 5, i8 20 | |
| ; CHECK-NEXT: ret i8 [[SEL2]] | |
| ; | |
| %cmp1 = icmp sgt i8 %x, 10 | |
| %cmp2 = icmp slt i8 %x, 0 | |
| %sel1 = select i1 %cmp1, i8 0, i8 5 | |
| %sel2 = select i1 %cmp2, i8 %sel1, i8 20 | |
| ret i8 %sel2 | |
| } | |
| ; Negative tests | |
| define i8 @test_imply_fail(i8 %x) { | |
| ; CHECK-LABEL: @test_imply_fail( | |
| ; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 [[X:%.*]], -10 | |
| ; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i8 [[X]], 0 | |
| ; CHECK-NEXT: [[SEL1:%.*]] = select i1 [[CMP1]], i8 0, i8 5 | |
| ; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[CMP2]], i8 [[SEL1]], i8 20 | |
| ; CHECK-NEXT: ret i8 [[SEL2]] | |
| ; | |
| %cmp1 = icmp slt i8 %x, -10 | |
| %cmp2 = icmp slt i8 %x, 0 | |
| %sel1 = select i1 %cmp1, i8 0, i8 5 | |
| %sel2 = select i1 %cmp2, i8 %sel1, i8 20 | |
| ret i8 %sel2 | |
| } | |
| define <2 x i8> @test_imply_type_mismatch(<2 x i8> %x, i8 %y) { | |
| ; CHECK-LABEL: @test_imply_type_mismatch( | |
| ; CHECK-NEXT: [[CMP1:%.*]] = icmp slt <2 x i8> [[X:%.*]], splat (i8 10) | |
| ; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i8 [[Y:%.*]], 0 | |
| ; CHECK-NEXT: [[SEL1:%.*]] = select <2 x i1> [[CMP1]], <2 x i8> zeroinitializer, <2 x i8> splat (i8 5) | |
| ; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[CMP2]], <2 x i8> [[SEL1]], <2 x i8> splat (i8 20) | |
| ; CHECK-NEXT: ret <2 x i8> [[SEL2]] | |
| ; | |
| %cmp1 = icmp slt <2 x i8> %x, <i8 10, i8 10> | |
| %cmp2 = icmp slt i8 %y, 0 | |
| %sel1 = select <2 x i1> %cmp1, <2 x i8> zeroinitializer, <2 x i8> <i8 5, i8 5> | |
| %sel2 = select i1 %cmp2, <2 x i8> %sel1, <2 x i8> <i8 20, i8 20> | |
| ret <2 x i8> %sel2 | |
| } | |
| define <4 x i1> @test_dont_crash(i1 %cond, <4 x i1> %a, <4 x i1> %b) { | |
| ; CHECK-LABEL: @test_dont_crash( | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND:%.*]], <4 x i1> [[A:%.*]], <4 x i1> zeroinitializer | |
| ; CHECK-NEXT: [[AND:%.*]] = and <4 x i1> [[SEL]], [[B:%.*]] | |
| ; CHECK-NEXT: ret <4 x i1> [[AND]] | |
| ; | |
| entry: | |
| %sel = select i1 %cond, <4 x i1> %a, <4 x i1> zeroinitializer | |
| %and = and <4 x i1> %sel, %b | |
| ret <4 x i1> %and | |
| } | |
| ; x <u 13 => bit 4 is clear => (x & 16) == 0 is true | |
| define i8 @test_mask_implied_equal(i8 %x) { | |
| ; CHECK-LABEL: @test_mask_implied_equal( | |
| ; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i8 [[X:%.*]], 13 | |
| ; CHECK-NEXT: [[R:%.*]] = zext i1 [[CMP1]] to i8 | |
| ; CHECK-NEXT: ret i8 [[R]] | |
| ; | |
| %cmp1 = icmp ult i8 %x, 13 | |
| %mask = and i8 %x, 16 | |
| %cmp2 = icmp eq i8 %mask, 0 | |
| %inner = select i1 %cmp2, i8 1, i8 2 | |
| %r = select i1 %cmp1, i8 %inner, i8 0 | |
| ret i8 %r | |
| } | |
| define i8 @test_mask_implied_swapped_equal(i8 %x) { | |
| ; CHECK-LABEL: @test_mask_implied_swapped_equal( | |
| ; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i8 [[X:%.*]], 13 | |
| ; CHECK-NEXT: [[R:%.*]] = zext i1 [[CMP1]] to i8 | |
| ; CHECK-NEXT: ret i8 [[R]] | |
| ; | |
| %cmp1 = icmp ult i8 %x, 13 | |
| %mask = and i8 16, %x | |
| %cmp2 = icmp eq i8 %mask, 0 | |
| %inner = select i1 %cmp2, i8 1, i8 2 | |
| %r = select i1 %cmp1, i8 %inner, i8 0 | |
| ret i8 %r | |
| } | |
| define i8 @test_mask_no_implication_fail(i8 %x) { | |
| ; CHECK-LABEL: @test_mask_no_implication_fail( | |
| ; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i8 [[X:%.*]], 20 | |
| ; CHECK-NEXT: [[MASK:%.*]] = and i8 [[X]], 16 | |
| ; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 [[MASK]], 0 | |
| ; CHECK-NEXT: [[INNER:%.*]] = select i1 [[CMP2]], i8 1, i8 2 | |
| ; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP1]], i8 [[INNER]], i8 0 | |
| ; CHECK-NEXT: ret i8 [[R]] | |
| ; | |
| %cmp1 = icmp ult i8 %x, 20 | |
| %mask = and i8 %x, 16 | |
| %cmp2 = icmp eq i8 %mask, 0 | |
| %inner = select i1 %cmp2, i8 1, i8 2 | |
| %r = select i1 %cmp1, i8 %inner, i8 0 | |
| ret i8 %r | |
| } | |
| define i8 @test_mask_boundary_true(i8 %x) { | |
| ; CHECK-LABEL: @test_mask_boundary_true( | |
| ; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i8 [[X:%.*]], 16 | |
| ; CHECK-NEXT: [[R:%.*]] = zext i1 [[CMP1]] to i8 | |
| ; CHECK-NEXT: ret i8 [[R]] | |
| ; | |
| %cmp1 = icmp ult i8 %x, 16 | |
| %mask = and i8 %x, 16 | |
| %cmp2 = icmp eq i8 %mask, 0 | |
| %inner = select i1 %cmp2, i8 1, i8 2 | |
| %r = select i1 %cmp1, i8 %inner, i8 0 | |
| ret i8 %r | |
| } | |
| define i8 @test_mask_boundary_fail(i8 %x) { | |
| ; CHECK-LABEL: @test_mask_boundary_fail( | |
| ; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i8 [[X:%.*]], 17 | |
| ; CHECK-NEXT: [[MASK:%.*]] = and i8 [[X]], 16 | |
| ; CHECK-NEXT: [[CMP2_NOT:%.*]] = icmp eq i8 [[MASK]], 0 | |
| ; CHECK-NEXT: [[INNER:%.*]] = select i1 [[CMP2_NOT]], i8 2, i8 1 | |
| ; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP1]], i8 [[INNER]], i8 0 | |
| ; CHECK-NEXT: ret i8 [[R]] | |
| ; | |
| %cmp1 = icmp ult i8 %x, 17 | |
| %mask = and i8 %x, 16 | |
| %cmp2 = icmp ne i8 %mask, 0 | |
| %inner = select i1 %cmp2, i8 1, i8 2 | |
| %r = select i1 %cmp1, i8 %inner, i8 0 | |
| ret i8 %r | |
| } | |
| define <2 x i8> @test_mask_splat_true(<2 x i8> %x) { | |
| ; CHECK-LABEL: @test_mask_splat_true( | |
| ; CHECK-NEXT: [[CMP1:%.*]] = icmp ult <2 x i8> [[X:%.*]], splat (i8 13) | |
| ; CHECK-NEXT: [[R:%.*]] = zext <2 x i1> [[CMP1]] to <2 x i8> | |
| ; CHECK-NEXT: ret <2 x i8> [[R]] | |
| ; | |
| %cmp1 = icmp ult <2 x i8> %x, splat (i8 13) | |
| %mask = and <2 x i8> %x, splat (i8 16) | |
| %cmp2 = icmp eq <2 x i8> %mask, zeroinitializer | |
| %inner = select <2 x i1> %cmp2, <2 x i8> splat (i8 1), <2 x i8> splat (i8 2) | |
| %r = select <2 x i1> %cmp1, <2 x i8> %inner, <2 x i8> zeroinitializer | |
| ret <2 x i8> %r | |
| } | |
| define <2 x i8> @test_mask_splat_fail(<2 x i8> %x) { | |
| ; CHECK-LABEL: @test_mask_splat_fail( | |
| ; CHECK-NEXT: [[CMP1:%.*]] = icmp ult <2 x i8> [[X:%.*]], splat (i8 20) | |
| ; CHECK-NEXT: [[MASK:%.*]] = and <2 x i8> [[X]], splat (i8 16) | |
| ; CHECK-NEXT: [[CMP2:%.*]] = icmp eq <2 x i8> [[MASK]], zeroinitializer | |
| ; CHECK-NEXT: [[INNER:%.*]] = select <2 x i1> [[CMP2]], <2 x i8> splat (i8 1), <2 x i8> splat (i8 2) | |
| ; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[CMP1]], <2 x i8> [[INNER]], <2 x i8> zeroinitializer | |
| ; CHECK-NEXT: ret <2 x i8> [[R]] | |
| ; | |
| %cmp1 = icmp ult <2 x i8> %x, splat (i8 20) | |
| %mask = and <2 x i8> %x, splat (i8 16) | |
| %cmp2 = icmp eq <2 x i8> %mask, zeroinitializer | |
| %inner = select <2 x i1> %cmp2, <2 x i8> splat (i8 1), <2 x i8> splat (i8 2) | |
| %r = select <2 x i1> %cmp1, <2 x i8> %inner, <2 x i8> zeroinitializer | |
| ret <2 x i8> %r | |
| } | |
| define i8 @test_mask_signed_true(i8 %x) { | |
| ; | |
| ; CHECK-LABEL: @test_mask_signed_true( | |
| ; CHECK-NEXT: [[CMP1_INV:%.*]] = icmp sgt i8 [[X:%.*]], -1 | |
| ; CHECK-NEXT: [[R:%.*]] = zext i1 [[CMP1_INV]] to i8 | |
| ; CHECK-NEXT: ret i8 [[R]] | |
| ; | |
| %cmp1 = icmp sgt i8 %x, -1 | |
| %mask = and i8 %x, -128 | |
| %cmp2 = icmp eq i8 %mask, 0 | |
| %inner = select i1 %cmp2, i8 1, i8 2 | |
| %r = select i1 %cmp1, i8 %inner, i8 0 | |
| ret i8 %r | |
| } | |
| define i8 @test_mask_signed_fail(i8 %x) { | |
| ; CHECK-LABEL: @test_mask_signed_fail( | |
| ; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 [[X:%.*]], 13 | |
| ; CHECK-NEXT: [[MASK:%.*]] = and i8 [[X]], 16 | |
| ; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 [[MASK]], 0 | |
| ; CHECK-NEXT: [[INNER:%.*]] = select i1 [[CMP2]], i8 1, i8 2 | |
| ; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP1]], i8 [[INNER]], i8 0 | |
| ; CHECK-NEXT: ret i8 [[R]] | |
| ; | |
| %cmp1 = icmp slt i8 %x, 13 | |
| %mask = and i8 %x, 16 | |
| %cmp2 = icmp eq i8 %mask, 0 | |
| %inner = select i1 %cmp2, i8 1, i8 2 | |
| %r = select i1 %cmp1, i8 %inner, i8 0 | |
| ret i8 %r | |
| } | |
| !0 = !{!"function_entry_count", i32 10} | |
| !1 = !{!"branch_weights", i32 2, i32 3} | |
| !2 = !{!"branch_weights", i32 3, i32 2} | |
| !3 = !{!"branch_weights", i32 5, i32 7} | |
| ;. | |
| ; CHECK: [[PROF1]] = !{!"unknown", !"instcombine"} | |
| ; CHECK: [[PROF2]] = !{!"branch_weights", i32 2, i32 3} | |
| ;. |