Skip to content

Instantly share code, notes, and snippets.

@nikic
Created January 16, 2021 11:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nikic/4bad7e7e7ecda8d9c9e9633d86836b4d to your computer and use it in GitHub Desktop.
Save nikic/4bad7e7e7ecda8d9c9e9633d86836b4d to your computer and use it in GitHub Desktop.
commit c4b903e62a8d9da14a73f0eeb44f8916df1173e4
Author: Nikita Popov <nikita.ppv@gmail.com>
Date: Sat Jan 16 12:41:35 2021 +0100
select equiv
diff --git llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 5a43b8b20db9..73e1835a7433 100644
--- llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -1113,10 +1113,24 @@ Instruction *InstCombinerImpl::foldSelectValueEquivalence(SelectInst &Sel,
// replacement cycle.
Value *CmpLHS = Cmp.getOperand(0), *CmpRHS = Cmp.getOperand(1);
if (TrueVal != CmpLHS &&
- isGuaranteedNotToBeUndefOrPoison(CmpRHS, SQ.AC, &Sel, &DT))
+ isGuaranteedNotToBeUndefOrPoison(CmpRHS, SQ.AC, &Sel, &DT)) {
if (Value *V = SimplifyWithOpReplaced(TrueVal, CmpLHS, CmpRHS, SQ,
/* AllowRefinement */ true))
return replaceOperand(Sel, Swapped ? 2 : 1, V);
+
+ // Even if TrueVal does not simplify, we can simply directly replace a use
+ // of CmpLHS with CmpRHS, as long as the instruciton is not used anywhere
+ // else. Only do this if CmpRHS is a constant, as profitability is not
+ // clear for other cases.
+ if (isa<Constant>(CmpRHS) && !isa<ConstantExpr>(CmpRHS))
+ if (auto *I = dyn_cast<Instruction>(TrueVal))
+ if (I->hasOneUse())
+ for (Use &U : I->operands())
+ if (U == CmpLHS) {
+ replaceUse(U, CmpRHS);
+ return &Sel;
+ }
+ }
if (TrueVal != CmpRHS &&
isGuaranteedNotToBeUndefOrPoison(CmpLHS, SQ.AC, &Sel, &DT))
if (Value *V = SimplifyWithOpReplaced(TrueVal, CmpRHS, CmpLHS, SQ,
diff --git llvm/test/Transforms/InstCombine/select-binop-cmp.ll llvm/test/Transforms/InstCombine/select-binop-cmp.ll
index c4a9d0941b96..b54125a53208 100644
--- llvm/test/Transforms/InstCombine/select-binop-cmp.ll
+++ llvm/test/Transforms/InstCombine/select-binop-cmp.ll
@@ -502,7 +502,7 @@ define i32 @select_xor_icmp_bad_2(i32 %x, i32 %y, i32 %z, i32 %k) {
define i32 @select_xor_icmp_bad_3(i32 %x, i32 %y, i32 %z) {
; CHECK-LABEL: @select_xor_icmp_bad_3(
; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], 3
-; CHECK-NEXT: [[B:%.*]] = xor i32 [[X]], [[Z:%.*]]
+; CHECK-NEXT: [[B:%.*]] = xor i32 [[Z:%.*]], 3
; CHECK-NEXT: [[C:%.*]] = select i1 [[A]], i32 [[B]], i32 [[Y:%.*]]
; CHECK-NEXT: ret i32 [[C]]
;
@@ -541,7 +541,7 @@ define i32 @select_xor_icmp_bad_5(i32 %x, i32 %y, i32 %z) {
define i32 @select_xor_icmp_bad_6(i32 %x, i32 %y, i32 %z) {
; CHECK-LABEL: @select_xor_icmp_bad_6(
; CHECK-NEXT: [[A_NOT:%.*]] = icmp eq i32 [[X:%.*]], 1
-; CHECK-NEXT: [[B:%.*]] = xor i32 [[X]], [[Z:%.*]]
+; CHECK-NEXT: [[B:%.*]] = xor i32 [[Z:%.*]], 1
; CHECK-NEXT: [[C:%.*]] = select i1 [[A_NOT]], i32 [[B]], i32 [[Y:%.*]]
; CHECK-NEXT: ret i32 [[C]]
;
@@ -554,7 +554,7 @@ define i32 @select_xor_icmp_bad_6(i32 %x, i32 %y, i32 %z) {
define <2 x i8> @select_xor_icmp_vec_bad(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
; CHECK-LABEL: @select_xor_icmp_vec_bad(
; CHECK-NEXT: [[A:%.*]] = icmp eq <2 x i8> [[X:%.*]], <i8 5, i8 3>
-; CHECK-NEXT: [[B:%.*]] = xor <2 x i8> [[X]], [[Z:%.*]]
+; CHECK-NEXT: [[B:%.*]] = xor <2 x i8> [[Z:%.*]], <i8 5, i8 3>
; CHECK-NEXT: [[C:%.*]] = select <2 x i1> [[A]], <2 x i8> [[B]], <2 x i8> [[Y:%.*]]
; CHECK-NEXT: ret <2 x i8> [[C]]
;
@@ -581,7 +581,7 @@ define <2 x i8> @select_xor_icmp_vec_undef(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z
define i32 @select_mul_icmp_bad(i32 %x, i32 %y, i32 %z, i32 %k) {
; CHECK-LABEL: @select_mul_icmp_bad(
; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], 3
-; CHECK-NEXT: [[B:%.*]] = mul i32 [[X]], [[Z:%.*]]
+; CHECK-NEXT: [[B:%.*]] = mul i32 [[Z:%.*]], 3
; CHECK-NEXT: [[C:%.*]] = select i1 [[A]], i32 [[B]], i32 [[Y:%.*]]
; CHECK-NEXT: ret i32 [[C]]
;
@@ -594,7 +594,7 @@ define i32 @select_mul_icmp_bad(i32 %x, i32 %y, i32 %z, i32 %k) {
define i32 @select_add_icmp_bad(i32 %x, i32 %y, i32 %z) {
; CHECK-LABEL: @select_add_icmp_bad(
; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], 1
-; CHECK-NEXT: [[B:%.*]] = add i32 [[X]], [[Z:%.*]]
+; CHECK-NEXT: [[B:%.*]] = add i32 [[Z:%.*]], 1
; CHECK-NEXT: [[C:%.*]] = select i1 [[A]], i32 [[B]], i32 [[Y:%.*]]
; CHECK-NEXT: ret i32 [[C]]
;
@@ -619,7 +619,7 @@ define i32 @select_and_icmp_zero(i32 %x, i32 %y, i32 %z) {
define i32 @select_or_icmp_bad(i32 %x, i32 %y, i32 %z) {
; CHECK-LABEL: @select_or_icmp_bad(
; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], 3
-; CHECK-NEXT: [[B:%.*]] = or i32 [[X]], [[Z:%.*]]
+; CHECK-NEXT: [[B:%.*]] = or i32 [[Z:%.*]], 3
; CHECK-NEXT: [[C:%.*]] = select i1 [[A]], i32 [[B]], i32 [[Y:%.*]]
; CHECK-NEXT: ret i32 [[C]]
;
@@ -940,7 +940,7 @@ define float @select_fsub_fcmp_bad_2(float %x, float %y, float %z) {
define i32 @select_sub_icmp_bad(i32 %x, i32 %y, i32 %z) {
; CHECK-LABEL: @select_sub_icmp_bad(
; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], 0
-; CHECK-NEXT: [[B:%.*]] = sub i32 [[X]], [[Z:%.*]]
+; CHECK-NEXT: [[B:%.*]] = sub i32 0, [[Z:%.*]]
; CHECK-NEXT: [[C:%.*]] = select i1 [[A]], i32 [[B]], i32 [[Y:%.*]]
; CHECK-NEXT: ret i32 [[C]]
;
@@ -953,7 +953,7 @@ define i32 @select_sub_icmp_bad(i32 %x, i32 %y, i32 %z) {
define i32 @select_sub_icmp_bad_2(i32 %x, i32 %y, i32 %z) {
; CHECK-LABEL: @select_sub_icmp_bad_2(
; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], 1
-; CHECK-NEXT: [[B:%.*]] = sub i32 [[Z:%.*]], [[X]]
+; CHECK-NEXT: [[B:%.*]] = add i32 [[Z:%.*]], -1
; CHECK-NEXT: [[C:%.*]] = select i1 [[A]], i32 [[B]], i32 [[Y:%.*]]
; CHECK-NEXT: ret i32 [[C]]
;
@@ -1022,7 +1022,7 @@ define i32 @select_sub_icmp_bad_5(i32 %x, i32 %y, i32 %z, i32 %k) {
define i32 @select_shl_icmp_bad(i32 %x, i32 %y, i32 %z) {
; CHECK-LABEL: @select_shl_icmp_bad(
; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], 1
-; CHECK-NEXT: [[B:%.*]] = shl i32 [[Z:%.*]], [[X]]
+; CHECK-NEXT: [[B:%.*]] = shl i32 [[Z:%.*]], 1
; CHECK-NEXT: [[C:%.*]] = select i1 [[A]], i32 [[B]], i32 [[Y:%.*]]
; CHECK-NEXT: ret i32 [[C]]
;
@@ -1035,7 +1035,7 @@ define i32 @select_shl_icmp_bad(i32 %x, i32 %y, i32 %z) {
define i32 @select_lshr_icmp_bad(i32 %x, i32 %y, i32 %z) {
; CHECK-LABEL: @select_lshr_icmp_bad(
; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], 1
-; CHECK-NEXT: [[B:%.*]] = lshr i32 [[Z:%.*]], [[X]]
+; CHECK-NEXT: [[B:%.*]] = lshr i32 [[Z:%.*]], 1
; CHECK-NEXT: [[C:%.*]] = select i1 [[A]], i32 [[B]], i32 [[Y:%.*]]
; CHECK-NEXT: ret i32 [[C]]
;
@@ -1048,7 +1048,7 @@ define i32 @select_lshr_icmp_bad(i32 %x, i32 %y, i32 %z) {
define i32 @select_ashr_icmp_bad(i32 %x, i32 %y, i32 %z) {
; CHECK-LABEL: @select_ashr_icmp_bad(
; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], 1
-; CHECK-NEXT: [[B:%.*]] = ashr i32 [[Z:%.*]], [[X]]
+; CHECK-NEXT: [[B:%.*]] = ashr i32 [[Z:%.*]], 1
; CHECK-NEXT: [[C:%.*]] = select i1 [[A]], i32 [[B]], i32 [[Y:%.*]]
; CHECK-NEXT: ret i32 [[C]]
;
@@ -1061,7 +1061,7 @@ define i32 @select_ashr_icmp_bad(i32 %x, i32 %y, i32 %z) {
define i32 @select_udiv_icmp_bad(i32 %x, i32 %y, i32 %z) {
; CHECK-LABEL: @select_udiv_icmp_bad(
; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], 3
-; CHECK-NEXT: [[B:%.*]] = udiv i32 [[Z:%.*]], [[X]]
+; CHECK-NEXT: [[B:%.*]] = udiv i32 [[Z:%.*]], 3
; CHECK-NEXT: [[C:%.*]] = select i1 [[A]], i32 [[B]], i32 [[Y:%.*]]
; CHECK-NEXT: ret i32 [[C]]
;
@@ -1074,7 +1074,7 @@ define i32 @select_udiv_icmp_bad(i32 %x, i32 %y, i32 %z) {
define i32 @select_sdiv_icmp_bad(i32 %x, i32 %y, i32 %z) {
; CHECK-LABEL: @select_sdiv_icmp_bad(
; CHECK-NEXT: [[A:%.*]] = icmp eq i32 [[X:%.*]], 3
-; CHECK-NEXT: [[B:%.*]] = sdiv i32 [[Z:%.*]], [[X]]
+; CHECK-NEXT: [[B:%.*]] = sdiv i32 [[Z:%.*]], 3
; CHECK-NEXT: [[C:%.*]] = select i1 [[A]], i32 [[B]], i32 [[Y:%.*]]
; CHECK-NEXT: ret i32 [[C]]
;
diff --git llvm/test/Transforms/InstCombine/select-safe-transforms.ll llvm/test/Transforms/InstCombine/select-safe-transforms.ll
index b16985ba1b75..f6dfb672e7f2 100644
--- llvm/test/Transforms/InstCombine/select-safe-transforms.ll
+++ llvm/test/Transforms/InstCombine/select-safe-transforms.ll
@@ -17,7 +17,7 @@ define i1 @cond_eq_and(i8 %X, i8 %Y, i8 noundef %C) {
define i1 @cond_eq_and_const(i8 %X, i8 %Y) {
; CHECK-LABEL: @cond_eq_and_const(
; CHECK-NEXT: [[COND:%.*]] = icmp eq i8 [[X:%.*]], 10
-; CHECK-NEXT: [[LHS:%.*]] = icmp ult i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT: [[LHS:%.*]] = icmp ugt i8 [[Y:%.*]], 10
; CHECK-NEXT: [[RES:%.*]] = select i1 [[COND]], i1 [[LHS]], i1 false
; CHECK-NEXT: ret i1 [[RES]]
;
@@ -43,7 +43,7 @@ define i1 @cond_eq_or(i8 %X, i8 %Y, i8 noundef %C) {
define i1 @cond_eq_or_const(i8 %X, i8 %Y) {
; CHECK-LABEL: @cond_eq_or_const(
; CHECK-NEXT: [[COND:%.*]] = icmp ne i8 [[X:%.*]], 10
-; CHECK-NEXT: [[LHS:%.*]] = icmp ult i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT: [[LHS:%.*]] = icmp ugt i8 [[Y:%.*]], 10
; CHECK-NEXT: [[RES:%.*]] = select i1 [[COND]], i1 true, i1 [[LHS]]
; CHECK-NEXT: ret i1 [[RES]]
;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment