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]]
;
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]]
;
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]]
;
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]]
;
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]]
;
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]]
;
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]]
;
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]]
;
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]]
;
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]]
;
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]]
;
ret i32 %C
}
+; Can replace %x with 0, because sub is only used in the select.
define i32 @select_replace_one_use(i32 %x, i32 %y) {
; CHECK-LABEL: @select_replace_one_use(
; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[X:%.*]], 0
-; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[X]], [[Y:%.*]]
+; CHECK-NEXT: [[SUB:%.*]] = sub i32 0, [[Y:%.*]]
; CHECK-NEXT: [[S:%.*]] = select i1 [[C]], i32 [[SUB]], i32 [[Y]]
; CHECK-NEXT: ret i32 [[S]]
;
ret i32 %s
}
+; Can not replace %x with 0, because %sub has other uses as well.
define i32 @select_replace_multi_use(i32 %x, i32 %y) {
; CHECK-LABEL: @select_replace_multi_use(
; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[X:%.*]], 0
ret i32 %s
}
+; Case where the replacement allows the instruction to fold away.
define i32 @select_replace_fold(i32 %x, i32 %y, i32 %z) {
; CHECK-LABEL: @select_replace_fold(
; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[X:%.*]], 0
-; CHECK-NEXT: [[FSHR:%.*]] = call i32 @llvm.fshr.i32(i32 [[Y:%.*]], i32 [[Z:%.*]], i32 [[X]])
-; CHECK-NEXT: [[S:%.*]] = select i1 [[C]], i32 [[FSHR]], i32 [[Y]]
+; CHECK-NEXT: [[S:%.*]] = select i1 [[C]], i32 [[Z:%.*]], i32 [[Y:%.*]]
; CHECK-NEXT: ret i32 [[S]]
;
%c = icmp eq i32 %x, 0
ret i32 %s
}
+
+; Case where the use of %x is in a nested instruction.
+; FIXME: We only perform replacements one level up right now.
define i32 @select_replace_nested(i32 %x, i32 %y, i32 %z) {
; CHECK-LABEL: @select_replace_nested(
; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[X:%.*]], 0
ret i32 %s
}
+; Do not replace with constant expressions. The profitability in this case is
+; unclear, and such replacements have historically lead to infinite combine
+; loops.
define i32 @select_replace_constexpr(i32 %x, i32 %y, i32 %z) {
; CHECK-LABEL: @select_replace_constexpr(
; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[X:%.*]], ptrtoint (i32* @g to i32)
ret i32 %s
}
+; Don't replace with a potentially undef constant, as undef could evaluate
+; to different values for both uses.
define <2 x i32> @select_replace_undef(<2 x i32> %x, <2 x i32> %y) {
; CHECK-LABEL: @select_replace_undef(
; CHECK-NEXT: [[C:%.*]] = icmp eq <2 x i32> [[X:%.*]], <i32 0, i32 undef>
ret <2 x i32> %s
}
+; We can replace the call arguments, as the call is speculatable.
define i32 @select_replace_call_speculatable(i32 %x, i32 %y) {
; CHECK-LABEL: @select_replace_call_speculatable(
; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[X:%.*]], 0
-; CHECK-NEXT: [[CALL:%.*]] = call i32 @call_speculatable(i32 [[X]], i32 [[X]])
+; CHECK-NEXT: [[CALL:%.*]] = call i32 @call_speculatable(i32 0, i32 0)
; CHECK-NEXT: [[S:%.*]] = select i1 [[C]], i32 [[CALL]], i32 [[Y:%.*]]
; CHECK-NEXT: ret i32 [[S]]
;
ret i32 %s
}
+; We can't replace the call arguments, as the call is not speculatable. We
+; may end up changing side-effects or causing undefined behavior.
define i32 @select_replace_call_non_speculatable(i32 %x, i32 %y) {
; CHECK-LABEL: @select_replace_call_non_speculatable(
; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[X:%.*]], 0
ret i32 %s
}
+; We can replace %x by 2 here, because division by two cannot cause UB.
+; FIXME: As we check speculation prior to replacement, we don't catch this.
define i32 @select_replace_sdiv_speculatable(i32 %x, i32 %y) {
; CHECK-LABEL: @select_replace_sdiv_speculatable(
; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[X:%.*]], 2
ret i32 %s
}
+; We cannot replace %x by -1, because division by -1 can cause UB.
define i32 @select_replace_sdiv_non_speculatable(i32 %x, i32 %y) {
; CHECK-LABEL: @select_replace_sdiv_non_speculatable(
; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[X:%.*]], -1
ret i32 %s
}
+; We can replace %x by 2 here, because division by two cannot cause UB.
+; FIXME: As we check speculation prior to replacement, we don't catch this.
define i32 @select_replace_udiv_speculatable(i32 %x, i32 %y) {
; CHECK-LABEL: @select_replace_udiv_speculatable(
; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[X:%.*]], 2
ret i32 %s
}
+; We can't replace %x by 0 here, because that would cause UB. However,
+; replacing the udiv result by poisong is fine.
define i32 @select_replace_udiv_non_speculatable(i32 %x, i32 %y) {
; CHECK-LABEL: @select_replace_udiv_non_speculatable(
; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[X:%.*]], 0
ret i32 %s
}
+; We can't replace %i in the phi node here, because it refers to %i from
+; the previous loop iteration, not the current one.
define void @select_replace_phi(i32 %x) {
; CHECK-LABEL: @select_replace_phi(
; CHECK-NEXT: entry: