mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 18:54:02 +01:00
a7f581c4d0
Currently undef is used as a don’t-care vector when constructing a vector using a series of insertelement. However, this is problematic because undef isn’t undefined enough. Especially, a sequence of insertelement can be optimized to shufflevector, but using undef as its placeholder makes shufflevector a poison-blocking instruction because undef cannot be optimized to poison. This makes a few straightforward optimizations incorrect, such as: ``` ; https://bugs.llvm.org/show_bug.cgi?id=44185 define <4 x float> @insert_not_undef_shuffle_translate_commute(float %x, <4 x float> %y, <4 x float> %q) { %xv = insertelement <4 x float> %q, float %x, i32 2 %r = shufflevector <4 x float> %y, <4 x float> %xv, <4 x i32> { 0, 6, 2, undef } ret <4 x float> %r ; %r[3] is undef } => define <4 x float> @insert_not_undef_shuffle_translate_commute(float %x, <4 x float> %y, <4 x float> %q) { %r = insertelement <4 x float> %y, float %x, i32 1 ret <4 x float> %r ; %r[3] = %y[3], incorrect if %y[3] = poison } Transformation doesn't verify! ERROR: Target is more poisonous than source ``` I’d like to suggest 1. Using poison as insertelement’s placeholder value (IRBuilder::CreateVectorSplat should be patched too) 2. Updating shufflevector’s semantics to return poison element if mask is undef Note that poison is currently lowered into UNDEF in SelDag, so codegen part is okay. m_Undef() matches PoisonValue as well, so existing optimizations will still fire. The only concern is hidden miscompilations that will go incorrect when poison constant is given. A conservative way is copying all tests having `insertelement undef` & replacing it with `insertelement poison` & run Alive2 on it, but it will create many tests and people won’t like it. :( Instead, I’ll simply locally maintain the tests and run Alive2. If there is any bug found, I’ll report it. Relevant links: https://bugs.llvm.org/show_bug.cgi?id=43958 , http://lists.llvm.org/pipermail/llvm-dev/2019-November/137242.html Reviewed By: nikic Differential Revision: https://reviews.llvm.org/D93586
123 lines
6.4 KiB
LLVM
123 lines
6.4 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt < %s -instcombine -S -o - | FileCheck %s
|
|
|
|
; This test case was added as a reproducer for a miscompile, where instcombine
|
|
; introduced an
|
|
; srem <2 x i16> %1, <i16 undef, i16 2>
|
|
; instruction, which makes the whole srem undefined (even if we only end up
|
|
; extracting the second element in the vector).
|
|
define i16 @test_srem_orig(i16 %a, i1 %cmp) {
|
|
; CHECK-LABEL: @test_srem_orig(
|
|
; CHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <2 x i16> undef, i16 [[A:%.*]], i32 0
|
|
; CHECK-NEXT: [[TMP1:%.*]] = srem <2 x i16> [[SPLATINSERT]], <i16 2, i16 1>
|
|
; CHECK-NEXT: [[SPLAT_OP:%.*]] = shufflevector <2 x i16> [[TMP1]], <2 x i16> undef, <2 x i32> <i32 undef, i32 0>
|
|
; CHECK-NEXT: [[T2:%.*]] = select i1 [[CMP:%.*]], <2 x i16> <i16 poison, i16 1>, <2 x i16> [[SPLAT_OP]]
|
|
; CHECK-NEXT: [[T3:%.*]] = extractelement <2 x i16> [[T2]], i32 1
|
|
; CHECK-NEXT: ret i16 [[T3]]
|
|
;
|
|
%splatinsert = insertelement <2 x i16> undef, i16 %a, i32 0
|
|
%splat = shufflevector <2 x i16> %splatinsert, <2 x i16> undef, <2 x i32> zeroinitializer
|
|
%t1 = select i1 %cmp, <2 x i16> <i16 1, i16 1>, <2 x i16> %splat
|
|
%t2 = srem <2 x i16> %t1, <i16 2, i16 2>
|
|
%t3 = extractelement <2 x i16> %t2, i32 1
|
|
ret i16 %t3
|
|
}
|
|
|
|
; This is basically a reduced version of test_srem_orig (based on what the
|
|
; code would look like after a few iterations of instcombine, just before we
|
|
; try to transform the shufflevector by doing
|
|
; "evaluateInDifferentElementOrder".
|
|
define <2 x i16> @test_srem(i16 %a, i1 %cmp) {
|
|
; CHECK-LABEL: @test_srem(
|
|
; CHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <2 x i16> undef, i16 [[A:%.*]], i32 0
|
|
; CHECK-NEXT: [[T1:%.*]] = srem <2 x i16> [[SPLATINSERT]], <i16 2, i16 1>
|
|
; CHECK-NEXT: [[SPLAT_OP:%.*]] = shufflevector <2 x i16> [[T1]], <2 x i16> undef, <2 x i32> <i32 undef, i32 0>
|
|
; CHECK-NEXT: [[T2:%.*]] = select i1 [[CMP:%.*]], <2 x i16> <i16 77, i16 99>, <2 x i16> [[SPLAT_OP]]
|
|
; CHECK-NEXT: ret <2 x i16> [[T2]]
|
|
;
|
|
%splatinsert = insertelement <2 x i16> undef, i16 %a, i32 0
|
|
%t1 = srem <2 x i16> %splatinsert, <i16 2, i16 1>
|
|
%splat.op = shufflevector <2 x i16> %t1, <2 x i16> undef, <2 x i32> <i32 undef, i32 0>
|
|
%t2 = select i1 %cmp, <2 x i16> <i16 77, i16 99>, <2 x i16> %splat.op
|
|
ret <2 x i16> %t2
|
|
}
|
|
|
|
define <2 x i16> @test_urem(i16 %a, i1 %cmp) {
|
|
; CHECK-LABEL: @test_urem(
|
|
; CHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <2 x i16> undef, i16 [[A:%.*]], i32 0
|
|
; CHECK-NEXT: [[T1:%.*]] = urem <2 x i16> [[SPLATINSERT]], <i16 3, i16 1>
|
|
; CHECK-NEXT: [[SPLAT_OP:%.*]] = shufflevector <2 x i16> [[T1]], <2 x i16> undef, <2 x i32> <i32 undef, i32 0>
|
|
; CHECK-NEXT: [[T2:%.*]] = select i1 [[CMP:%.*]], <2 x i16> <i16 77, i16 99>, <2 x i16> [[SPLAT_OP]]
|
|
; CHECK-NEXT: ret <2 x i16> [[T2]]
|
|
;
|
|
%splatinsert = insertelement <2 x i16> undef, i16 %a, i32 0
|
|
%t1 = urem <2 x i16> %splatinsert, <i16 3, i16 1>
|
|
%splat.op = shufflevector <2 x i16> %t1, <2 x i16> undef, <2 x i32> <i32 undef, i32 0>
|
|
%t2 = select i1 %cmp, <2 x i16> <i16 77, i16 99>, <2 x i16> %splat.op
|
|
ret <2 x i16> %t2
|
|
}
|
|
|
|
define <2 x i16> @test_sdiv(i16 %a, i1 %cmp) {
|
|
; CHECK-LABEL: @test_sdiv(
|
|
; CHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <2 x i16> undef, i16 [[A:%.*]], i32 0
|
|
; CHECK-NEXT: [[T1:%.*]] = sdiv <2 x i16> [[SPLATINSERT]], <i16 2, i16 1>
|
|
; CHECK-NEXT: [[SPLAT_OP:%.*]] = shufflevector <2 x i16> [[T1]], <2 x i16> undef, <2 x i32> <i32 undef, i32 0>
|
|
; CHECK-NEXT: [[T2:%.*]] = select i1 [[CMP:%.*]], <2 x i16> <i16 77, i16 99>, <2 x i16> [[SPLAT_OP]]
|
|
; CHECK-NEXT: ret <2 x i16> [[T2]]
|
|
;
|
|
%splatinsert = insertelement <2 x i16> undef, i16 %a, i32 0
|
|
%t1 = sdiv <2 x i16> %splatinsert, <i16 2, i16 1>
|
|
%splat.op = shufflevector <2 x i16> %t1, <2 x i16> undef, <2 x i32> <i32 undef, i32 0>
|
|
%t2 = select i1 %cmp, <2 x i16> <i16 77, i16 99>, <2 x i16> %splat.op
|
|
ret <2 x i16> %t2
|
|
}
|
|
|
|
define <2 x i16> @test_udiv(i16 %a, i1 %cmp) {
|
|
; CHECK-LABEL: @test_udiv(
|
|
; CHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <2 x i16> undef, i16 [[A:%.*]], i32 0
|
|
; CHECK-NEXT: [[T1:%.*]] = udiv <2 x i16> [[SPLATINSERT]], <i16 3, i16 1>
|
|
; CHECK-NEXT: [[SPLAT_OP:%.*]] = shufflevector <2 x i16> [[T1]], <2 x i16> undef, <2 x i32> <i32 undef, i32 0>
|
|
; CHECK-NEXT: [[T2:%.*]] = select i1 [[CMP:%.*]], <2 x i16> <i16 77, i16 99>, <2 x i16> [[SPLAT_OP]]
|
|
; CHECK-NEXT: ret <2 x i16> [[T2]]
|
|
;
|
|
%splatinsert = insertelement <2 x i16> undef, i16 %a, i32 0
|
|
%t1 = udiv <2 x i16> %splatinsert, <i16 3, i16 1>
|
|
%splat.op = shufflevector <2 x i16> %t1, <2 x i16> undef, <2 x i32> <i32 undef, i32 0>
|
|
%t2 = select i1 %cmp, <2 x i16> <i16 77, i16 99>, <2 x i16> %splat.op
|
|
ret <2 x i16> %t2
|
|
}
|
|
|
|
; For fdiv we do not need to worry about div by undef. Verify that the
|
|
; shufflevector is eliminated here.
|
|
define <2 x float> @test_fdiv(float %a, float %b, i1 %cmp) {
|
|
; CHECK-LABEL: @test_fdiv(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = insertelement <2 x float> undef, float [[A:%.*]], i32 1
|
|
; CHECK-NEXT: [[TMP2:%.*]] = fdiv <2 x float> [[TMP1]], <float undef, float 3.000000e+00>
|
|
; CHECK-NEXT: [[T2:%.*]] = select i1 [[CMP:%.*]], <2 x float> <float 7.700000e+01, float 9.900000e+01>, <2 x float> [[TMP2]]
|
|
; CHECK-NEXT: ret <2 x float> [[T2]]
|
|
;
|
|
%splatinsert = insertelement <2 x float> undef, float %a, i32 0
|
|
%denom = insertelement <2 x float> <float 3.0, float undef>, float 1.0, i32 1
|
|
%t1 = fdiv <2 x float> %splatinsert, %denom
|
|
%splat.op = shufflevector <2 x float> %t1, <2 x float> undef, <2 x i32> <i32 undef, i32 0>
|
|
%t2 = select i1 %cmp, <2 x float> <float 77.0, float 99.0>, <2 x float> %splat.op
|
|
ret <2 x float> %t2
|
|
}
|
|
|
|
; For frem we do not need to worry about div by undef. Verify that the
|
|
; shufflevector is eliminated here.
|
|
define <2 x float> @test_frem(float %a, float %b, i1 %cmp) {
|
|
; CHECK-LABEL: @test_frem(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = insertelement <2 x float> undef, float [[A:%.*]], i32 1
|
|
; CHECK-NEXT: [[TMP2:%.*]] = frem <2 x float> [[TMP1]], <float undef, float 3.000000e+00>
|
|
; CHECK-NEXT: [[T2:%.*]] = select i1 [[CMP:%.*]], <2 x float> <float 7.700000e+01, float 9.900000e+01>, <2 x float> [[TMP2]]
|
|
; CHECK-NEXT: ret <2 x float> [[T2]]
|
|
;
|
|
%splatinsert = insertelement <2 x float> undef, float %a, i32 0
|
|
%denom = insertelement <2 x float> <float 3.0, float undef>, float 1.0, i32 1
|
|
%t1 = frem <2 x float> %splatinsert, %denom
|
|
%splat.op = shufflevector <2 x float> %t1, <2 x float> undef, <2 x i32> <i32 undef, i32 0>
|
|
%t2 = select i1 %cmp, <2 x float> <float 77.0, float 99.0>, <2 x float> %splat.op
|
|
ret <2 x float> %t2
|
|
}
|