This avoids the danger shown in issue #60906. There were no regression tests for these patterns, so these potential failures have been around for a long time. We freeze the condition and preserve the optimization because getting rid of a div/rem is always a win. Here are a couple of examples that can be corrected by freezing the condition: https://alive2.llvm.org/ce/z/sXHTTC Differential Revision: https://reviews.llvm.org/D144671
216 lines
7.1 KiB
LLVM
216 lines
7.1 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
|
|
|
|
; It is a miscompile in most of these tests if we
|
|
; execute div/rem without freezing the potentially
|
|
; poison condition value.
|
|
|
|
define i5 @sdiv_common_divisor(i1 %b, i5 %x, i5 %y, i5 %z) {
|
|
; CHECK-LABEL: @sdiv_common_divisor(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = freeze i1 [[B:%.*]]
|
|
; CHECK-NEXT: [[SEL_V:%.*]] = select i1 [[TMP1]], i5 [[Z:%.*]], i5 [[Y:%.*]]
|
|
; CHECK-NEXT: [[SEL:%.*]] = sdiv i5 [[SEL_V]], [[X:%.*]]
|
|
; CHECK-NEXT: ret i5 [[SEL]]
|
|
;
|
|
%r1 = sdiv i5 %y, %x
|
|
%r2 = sdiv i5 %z, %x
|
|
%sel = select i1 %b, i5 %r2, i5 %r1
|
|
ret i5 %sel
|
|
}
|
|
|
|
define i5 @srem_common_divisor(i1 %b, i5 %x, i5 %y, i5 %z) {
|
|
; CHECK-LABEL: @srem_common_divisor(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = freeze i1 [[B:%.*]]
|
|
; CHECK-NEXT: [[SEL_V:%.*]] = select i1 [[TMP1]], i5 [[Z:%.*]], i5 [[Y:%.*]]
|
|
; CHECK-NEXT: [[SEL:%.*]] = srem i5 [[SEL_V]], [[X:%.*]]
|
|
; CHECK-NEXT: ret i5 [[SEL]]
|
|
;
|
|
%r1 = srem i5 %y, %x
|
|
%r2 = srem i5 %z, %x
|
|
%sel = select i1 %b, i5 %r2, i5 %r1
|
|
ret i5 %sel
|
|
}
|
|
|
|
; This is ok without freeze because UB can only happen with x==0,
|
|
; and that occurs in the original code.
|
|
|
|
define i5 @udiv_common_divisor(i1 %b, i5 %x, i5 %y, i5 %z) {
|
|
; CHECK-LABEL: @udiv_common_divisor(
|
|
; CHECK-NEXT: [[SEL_V:%.*]] = select i1 [[B:%.*]], i5 [[Z:%.*]], i5 [[Y:%.*]]
|
|
; CHECK-NEXT: [[SEL:%.*]] = udiv i5 [[SEL_V]], [[X:%.*]]
|
|
; CHECK-NEXT: ret i5 [[SEL]]
|
|
;
|
|
%r1 = udiv i5 %y, %x
|
|
%r2 = udiv i5 %z, %x
|
|
%sel = select i1 %b, i5 %r2, i5 %r1
|
|
ret i5 %sel
|
|
}
|
|
|
|
; This is ok without freeze because UB can only happen with x==0,
|
|
; and that occurs in the original code.
|
|
|
|
define i5 @urem_common_divisor(i1 %b, i5 %x, i5 %y, i5 %z) {
|
|
; CHECK-LABEL: @urem_common_divisor(
|
|
; CHECK-NEXT: [[SEL_V:%.*]] = select i1 [[B:%.*]], i5 [[Z:%.*]], i5 [[Y:%.*]]
|
|
; CHECK-NEXT: [[SEL:%.*]] = urem i5 [[SEL_V]], [[X:%.*]]
|
|
; CHECK-NEXT: ret i5 [[SEL]]
|
|
;
|
|
%r1 = urem i5 %y, %x
|
|
%r2 = urem i5 %z, %x
|
|
%sel = select i1 %b, i5 %r2, i5 %r1
|
|
ret i5 %sel
|
|
}
|
|
|
|
define i5 @sdiv_common_dividend(i1 %b, i5 %x, i5 %y, i5 %z) {
|
|
; CHECK-LABEL: @sdiv_common_dividend(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = freeze i1 [[B:%.*]]
|
|
; CHECK-NEXT: [[SEL_V:%.*]] = select i1 [[TMP1]], i5 [[Z:%.*]], i5 [[Y:%.*]]
|
|
; CHECK-NEXT: [[SEL:%.*]] = sdiv i5 [[X:%.*]], [[SEL_V]]
|
|
; CHECK-NEXT: ret i5 [[SEL]]
|
|
;
|
|
%r1 = sdiv i5 %x, %y
|
|
%r2 = sdiv i5 %x, %z
|
|
%sel = select i1 %b, i5 %r2, i5 %r1
|
|
ret i5 %sel
|
|
}
|
|
|
|
define i5 @srem_common_dividend(i1 %b, i5 %x, i5 %y, i5 %z) {
|
|
; CHECK-LABEL: @srem_common_dividend(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = freeze i1 [[B:%.*]]
|
|
; CHECK-NEXT: [[SEL_V:%.*]] = select i1 [[TMP1]], i5 [[Z:%.*]], i5 [[Y:%.*]]
|
|
; CHECK-NEXT: [[SEL:%.*]] = srem i5 [[X:%.*]], [[SEL_V]]
|
|
; CHECK-NEXT: ret i5 [[SEL]]
|
|
;
|
|
%r1 = srem i5 %x, %y
|
|
%r2 = srem i5 %x, %z
|
|
%sel = select i1 %b, i5 %r2, i5 %r1
|
|
ret i5 %sel
|
|
}
|
|
|
|
define i5 @udiv_common_dividend(i1 %b, i5 %x, i5 %y, i5 %z) {
|
|
; CHECK-LABEL: @udiv_common_dividend(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = freeze i1 [[B:%.*]]
|
|
; CHECK-NEXT: [[SEL_V:%.*]] = select i1 [[TMP1]], i5 [[Z:%.*]], i5 [[Y:%.*]]
|
|
; CHECK-NEXT: [[SEL:%.*]] = udiv i5 [[X:%.*]], [[SEL_V]]
|
|
; CHECK-NEXT: ret i5 [[SEL]]
|
|
;
|
|
%r1 = udiv i5 %x, %y
|
|
%r2 = udiv i5 %x, %z
|
|
%sel = select i1 %b, i5 %r2, i5 %r1
|
|
ret i5 %sel
|
|
}
|
|
|
|
define i5 @urem_common_dividend(i1 %b, i5 %x, i5 %y, i5 %z) {
|
|
; CHECK-LABEL: @urem_common_dividend(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = freeze i1 [[B:%.*]]
|
|
; CHECK-NEXT: [[SEL_V:%.*]] = select i1 [[TMP1]], i5 [[Z:%.*]], i5 [[Y:%.*]]
|
|
; CHECK-NEXT: [[SEL:%.*]] = urem i5 [[X:%.*]], [[SEL_V]]
|
|
; CHECK-NEXT: ret i5 [[SEL]]
|
|
;
|
|
%r1 = urem i5 %x, %y
|
|
%r2 = urem i5 %x, %z
|
|
%sel = select i1 %b, i5 %r2, i5 %r1
|
|
ret i5 %sel
|
|
}
|
|
|
|
; Repeat the above tests, but guarantee that the select
|
|
; condition is not poison via argument attribute. That
|
|
; makes it safe to execute the select before div/rem
|
|
; without needing to freeze the condition.
|
|
|
|
define i5 @sdiv_common_divisor_defined_cond(i1 noundef %b, i5 %x, i5 %y, i5 %z) {
|
|
; CHECK-LABEL: @sdiv_common_divisor_defined_cond(
|
|
; CHECK-NEXT: [[SEL_V:%.*]] = select i1 [[B:%.*]], i5 [[Z:%.*]], i5 [[Y:%.*]]
|
|
; CHECK-NEXT: [[SEL:%.*]] = sdiv i5 [[SEL_V]], [[X:%.*]]
|
|
; CHECK-NEXT: ret i5 [[SEL]]
|
|
;
|
|
%r1 = sdiv i5 %y, %x
|
|
%r2 = sdiv i5 %z, %x
|
|
%sel = select i1 %b, i5 %r2, i5 %r1
|
|
ret i5 %sel
|
|
}
|
|
|
|
define i5 @srem_common_divisor_defined_cond(i1 noundef %b, i5 %x, i5 %y, i5 %z) {
|
|
; CHECK-LABEL: @srem_common_divisor_defined_cond(
|
|
; CHECK-NEXT: [[SEL_V:%.*]] = select i1 [[B:%.*]], i5 [[Z:%.*]], i5 [[Y:%.*]]
|
|
; CHECK-NEXT: [[SEL:%.*]] = srem i5 [[SEL_V]], [[X:%.*]]
|
|
; CHECK-NEXT: ret i5 [[SEL]]
|
|
;
|
|
%r1 = srem i5 %y, %x
|
|
%r2 = srem i5 %z, %x
|
|
%sel = select i1 %b, i5 %r2, i5 %r1
|
|
ret i5 %sel
|
|
}
|
|
|
|
define i5 @udiv_common_divisor_defined_cond(i1 noundef %b, i5 %x, i5 %y, i5 %z) {
|
|
; CHECK-LABEL: @udiv_common_divisor_defined_cond(
|
|
; CHECK-NEXT: [[SEL_V:%.*]] = select i1 [[B:%.*]], i5 [[Z:%.*]], i5 [[Y:%.*]]
|
|
; CHECK-NEXT: [[SEL:%.*]] = udiv i5 [[SEL_V]], [[X:%.*]]
|
|
; CHECK-NEXT: ret i5 [[SEL]]
|
|
;
|
|
%r1 = udiv i5 %y, %x
|
|
%r2 = udiv i5 %z, %x
|
|
%sel = select i1 %b, i5 %r2, i5 %r1
|
|
ret i5 %sel
|
|
}
|
|
|
|
define i5 @urem_common_divisor_defined_cond(i1 noundef %b, i5 %x, i5 %y, i5 %z) {
|
|
; CHECK-LABEL: @urem_common_divisor_defined_cond(
|
|
; CHECK-NEXT: [[SEL_V:%.*]] = select i1 [[B:%.*]], i5 [[Z:%.*]], i5 [[Y:%.*]]
|
|
; CHECK-NEXT: [[SEL:%.*]] = urem i5 [[SEL_V]], [[X:%.*]]
|
|
; CHECK-NEXT: ret i5 [[SEL]]
|
|
;
|
|
%r1 = urem i5 %y, %x
|
|
%r2 = urem i5 %z, %x
|
|
%sel = select i1 %b, i5 %r2, i5 %r1
|
|
ret i5 %sel
|
|
}
|
|
|
|
define i5 @sdiv_common_dividend_defined_cond(i1 noundef %b, i5 %x, i5 %y, i5 %z) {
|
|
; CHECK-LABEL: @sdiv_common_dividend_defined_cond(
|
|
; CHECK-NEXT: [[SEL_V:%.*]] = select i1 [[B:%.*]], i5 [[Z:%.*]], i5 [[Y:%.*]]
|
|
; CHECK-NEXT: [[SEL:%.*]] = sdiv i5 [[X:%.*]], [[SEL_V]]
|
|
; CHECK-NEXT: ret i5 [[SEL]]
|
|
;
|
|
%r1 = sdiv i5 %x, %y
|
|
%r2 = sdiv i5 %x, %z
|
|
%sel = select i1 %b, i5 %r2, i5 %r1
|
|
ret i5 %sel
|
|
}
|
|
|
|
define i5 @srem_common_dividend_defined_cond(i1 noundef %b, i5 %x, i5 %y, i5 %z) {
|
|
; CHECK-LABEL: @srem_common_dividend_defined_cond(
|
|
; CHECK-NEXT: [[SEL_V:%.*]] = select i1 [[B:%.*]], i5 [[Z:%.*]], i5 [[Y:%.*]]
|
|
; CHECK-NEXT: [[SEL:%.*]] = srem i5 [[X:%.*]], [[SEL_V]]
|
|
; CHECK-NEXT: ret i5 [[SEL]]
|
|
;
|
|
%r1 = srem i5 %x, %y
|
|
%r2 = srem i5 %x, %z
|
|
%sel = select i1 %b, i5 %r2, i5 %r1
|
|
ret i5 %sel
|
|
}
|
|
|
|
define i5 @udiv_common_dividend_defined_cond(i1 noundef %b, i5 %x, i5 %y, i5 %z) {
|
|
; CHECK-LABEL: @udiv_common_dividend_defined_cond(
|
|
; CHECK-NEXT: [[SEL_V:%.*]] = select i1 [[B:%.*]], i5 [[Z:%.*]], i5 [[Y:%.*]]
|
|
; CHECK-NEXT: [[SEL:%.*]] = udiv i5 [[X:%.*]], [[SEL_V]]
|
|
; CHECK-NEXT: ret i5 [[SEL]]
|
|
;
|
|
%r1 = udiv i5 %x, %y
|
|
%r2 = udiv i5 %x, %z
|
|
%sel = select i1 %b, i5 %r2, i5 %r1
|
|
ret i5 %sel
|
|
}
|
|
|
|
define i5 @urem_common_dividend_defined_cond(i1 noundef %b, i5 %x, i5 %y, i5 %z) {
|
|
; CHECK-LABEL: @urem_common_dividend_defined_cond(
|
|
; CHECK-NEXT: [[SEL_V:%.*]] = select i1 [[B:%.*]], i5 [[Z:%.*]], i5 [[Y:%.*]]
|
|
; CHECK-NEXT: [[SEL:%.*]] = urem i5 [[X:%.*]], [[SEL_V]]
|
|
; CHECK-NEXT: ret i5 [[SEL]]
|
|
;
|
|
%r1 = urem i5 %x, %y
|
|
%r2 = urem i5 %x, %z
|
|
%sel = select i1 %b, i5 %r2, i5 %r1
|
|
ret i5 %sel
|
|
}
|