2019-10-03 21:36:00 +08:00
|
|
|
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
|
|
; RUN: opt %s -instcombine -S | FileCheck %s
|
|
|
|
|
2020-05-21 01:54:06 +08:00
|
|
|
declare void @use4(i4)
|
2019-10-03 21:36:00 +08:00
|
|
|
declare void @use8(i8)
|
2020-04-04 05:09:38 +08:00
|
|
|
declare void @use_v2i4(<2 x i4>)
|
2020-06-18 02:37:19 +08:00
|
|
|
declare i1 @use32gen1(i32)
|
2019-10-03 21:36:00 +08:00
|
|
|
|
|
|
|
; Constant can be freely negated.
|
|
|
|
define i8 @t0(i8 %x) {
|
|
|
|
; CHECK-LABEL: @t0(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = add i8 [[X:%.*]], 42
|
|
|
|
; CHECK-NEXT: ret i8 [[T0]]
|
|
|
|
;
|
|
|
|
%t0 = sub i8 %x, -42
|
|
|
|
ret i8 %t0
|
|
|
|
}
|
|
|
|
|
|
|
|
; Negation can be negated for free
|
|
|
|
define i8 @t1(i8 %x, i8 %y) {
|
|
|
|
; CHECK-LABEL: @t1(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = sub i8 0, [[Y:%.*]]
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T0]])
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = add i8 [[X:%.*]], [[Y]]
|
|
|
|
; CHECK-NEXT: ret i8 [[T1]]
|
|
|
|
;
|
|
|
|
%t0 = sub i8 0, %y
|
|
|
|
call void @use8(i8 %t0)
|
|
|
|
%t1 = sub i8 %x, %t0
|
|
|
|
ret i8 %t1
|
|
|
|
}
|
|
|
|
|
|
|
|
; Shift-left can be negated if all uses can be updated
|
|
|
|
define i8 @t2(i8 %x, i8 %y) {
|
|
|
|
; CHECK-LABEL: @t2(
|
[InstCombine] Negator - sink sinkable negations
Summary:
As we have discussed previously (e.g. in D63992 / D64090 / [[ https://bugs.llvm.org/show_bug.cgi?id=42457 | PR42457 ]]), `sub` instruction
can almost be considered non-canonical. While we do convert `sub %x, C` -> `add %x, -C`,
we sparsely do that for non-constants. But we should.
Here, i propose to interpret `sub %x, %y` as `add (sub 0, %y), %x` IFF the negation can be sinked into the `%y`
This has some potential to cause endless combine loops (either around PHI's, or if there are some opposite transforms).
For former there's `-instcombine-negator-max-depth` option to mitigate it, should this expose any such issues
For latter, if there are still any such opposing folds, we'd need to remove the colliding fold.
In any case, reproducers welcomed!
Reviewers: spatel, nikic, efriedma, xbolva00
Reviewed By: spatel
Subscribers: xbolva00, mgorny, hiraditya, reames, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D68408
2020-04-22 02:24:36 +08:00
|
|
|
; CHECK-NEXT: [[T0_NEG:%.*]] = shl i8 42, [[Y:%.*]]
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = add i8 [[T0_NEG]], [[X:%.*]]
|
2019-10-03 21:36:00 +08:00
|
|
|
; CHECK-NEXT: ret i8 [[T1]]
|
|
|
|
;
|
|
|
|
%t0 = shl i8 -42, %y
|
|
|
|
%t1 = sub i8 %x, %t0
|
|
|
|
ret i8 %t1
|
|
|
|
}
|
|
|
|
define i8 @n2(i8 %x, i8 %y) {
|
|
|
|
; CHECK-LABEL: @n2(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = shl i8 -42, [[Y:%.*]]
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T0]])
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = sub i8 [[X:%.*]], [[T0]]
|
|
|
|
; CHECK-NEXT: ret i8 [[T1]]
|
|
|
|
;
|
|
|
|
%t0 = shl i8 -42, %y
|
|
|
|
call void @use8(i8 %t0)
|
|
|
|
%t1 = sub i8 %x, %t0
|
|
|
|
ret i8 %t1
|
|
|
|
}
|
|
|
|
define i8 @t3(i8 %x, i8 %y, i8 %z) {
|
|
|
|
; CHECK-LABEL: @t3(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = sub i8 0, [[Z:%.*]]
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T0]])
|
[InstCombine] Negator - sink sinkable negations
Summary:
As we have discussed previously (e.g. in D63992 / D64090 / [[ https://bugs.llvm.org/show_bug.cgi?id=42457 | PR42457 ]]), `sub` instruction
can almost be considered non-canonical. While we do convert `sub %x, C` -> `add %x, -C`,
we sparsely do that for non-constants. But we should.
Here, i propose to interpret `sub %x, %y` as `add (sub 0, %y), %x` IFF the negation can be sinked into the `%y`
This has some potential to cause endless combine loops (either around PHI's, or if there are some opposite transforms).
For former there's `-instcombine-negator-max-depth` option to mitigate it, should this expose any such issues
For latter, if there are still any such opposing folds, we'd need to remove the colliding fold.
In any case, reproducers welcomed!
Reviewers: spatel, nikic, efriedma, xbolva00
Reviewed By: spatel
Subscribers: xbolva00, mgorny, hiraditya, reames, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D68408
2020-04-22 02:24:36 +08:00
|
|
|
; CHECK-NEXT: [[T1_NEG:%.*]] = shl i8 [[Z]], [[Y:%.*]]
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = add i8 [[T1_NEG]], [[X:%.*]]
|
2019-10-03 21:36:00 +08:00
|
|
|
; CHECK-NEXT: ret i8 [[T2]]
|
|
|
|
;
|
|
|
|
%t0 = sub i8 0, %z
|
|
|
|
call void @use8(i8 %t0)
|
|
|
|
%t1 = shl i8 %t0, %y
|
|
|
|
%t2 = sub i8 %x, %t1
|
|
|
|
ret i8 %t2
|
|
|
|
}
|
|
|
|
define i8 @n3(i8 %x, i8 %y, i8 %z) {
|
|
|
|
; CHECK-LABEL: @n3(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = sub i8 0, [[Z:%.*]]
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T0]])
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = shl i8 [[T0]], [[Y:%.*]]
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T1]])
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = sub i8 [[X:%.*]], [[T1]]
|
|
|
|
; CHECK-NEXT: ret i8 [[T2]]
|
|
|
|
;
|
|
|
|
%t0 = sub i8 0, %z
|
|
|
|
call void @use8(i8 %t0)
|
|
|
|
%t1 = shl i8 %t0, %y
|
|
|
|
call void @use8(i8 %t1)
|
|
|
|
%t2 = sub i8 %x, %t1
|
|
|
|
ret i8 %t2
|
|
|
|
}
|
|
|
|
|
|
|
|
; Select can be negated if all it's operands can be negated and all the users of select can be updated
|
|
|
|
define i8 @t4(i8 %x, i1 %y) {
|
|
|
|
; CHECK-LABEL: @t4(
|
[InstCombine] Negator - sink sinkable negations
Summary:
As we have discussed previously (e.g. in D63992 / D64090 / [[ https://bugs.llvm.org/show_bug.cgi?id=42457 | PR42457 ]]), `sub` instruction
can almost be considered non-canonical. While we do convert `sub %x, C` -> `add %x, -C`,
we sparsely do that for non-constants. But we should.
Here, i propose to interpret `sub %x, %y` as `add (sub 0, %y), %x` IFF the negation can be sinked into the `%y`
This has some potential to cause endless combine loops (either around PHI's, or if there are some opposite transforms).
For former there's `-instcombine-negator-max-depth` option to mitigate it, should this expose any such issues
For latter, if there are still any such opposing folds, we'd need to remove the colliding fold.
In any case, reproducers welcomed!
Reviewers: spatel, nikic, efriedma, xbolva00
Reviewed By: spatel
Subscribers: xbolva00, mgorny, hiraditya, reames, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D68408
2020-04-22 02:24:36 +08:00
|
|
|
; CHECK-NEXT: [[T0_NEG:%.*]] = select i1 [[Y:%.*]], i8 42, i8 -44
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = add i8 [[T0_NEG]], [[X:%.*]]
|
2019-10-03 21:36:00 +08:00
|
|
|
; CHECK-NEXT: ret i8 [[T1]]
|
|
|
|
;
|
|
|
|
%t0 = select i1 %y, i8 -42, i8 44
|
|
|
|
%t1 = sub i8 %x, %t0
|
|
|
|
ret i8 %t1
|
|
|
|
}
|
|
|
|
define i8 @n4(i8 %x, i1 %y) {
|
|
|
|
; CHECK-LABEL: @n4(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = select i1 [[Y:%.*]], i8 -42, i8 44
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T0]])
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = sub i8 [[X:%.*]], [[T0]]
|
|
|
|
; CHECK-NEXT: ret i8 [[T1]]
|
|
|
|
;
|
|
|
|
%t0 = select i1 %y, i8 -42, i8 44
|
|
|
|
call void @use8(i8 %t0)
|
|
|
|
%t1 = sub i8 %x, %t0
|
|
|
|
ret i8 %t1
|
|
|
|
}
|
|
|
|
define i8 @n5(i8 %x, i1 %y, i8 %z) {
|
|
|
|
; CHECK-LABEL: @n5(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = select i1 [[Y:%.*]], i8 -42, i8 [[Z:%.*]]
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = sub i8 [[X:%.*]], [[T0]]
|
|
|
|
; CHECK-NEXT: ret i8 [[T1]]
|
|
|
|
;
|
|
|
|
%t0 = select i1 %y, i8 -42, i8 %z
|
|
|
|
%t1 = sub i8 %x, %t0
|
|
|
|
ret i8 %t1
|
|
|
|
}
|
|
|
|
define i8 @t6(i8 %x, i1 %y, i8 %z) {
|
|
|
|
; CHECK-LABEL: @t6(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = sub i8 0, [[Z:%.*]]
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T0]])
|
[InstCombine] Negator - sink sinkable negations
Summary:
As we have discussed previously (e.g. in D63992 / D64090 / [[ https://bugs.llvm.org/show_bug.cgi?id=42457 | PR42457 ]]), `sub` instruction
can almost be considered non-canonical. While we do convert `sub %x, C` -> `add %x, -C`,
we sparsely do that for non-constants. But we should.
Here, i propose to interpret `sub %x, %y` as `add (sub 0, %y), %x` IFF the negation can be sinked into the `%y`
This has some potential to cause endless combine loops (either around PHI's, or if there are some opposite transforms).
For former there's `-instcombine-negator-max-depth` option to mitigate it, should this expose any such issues
For latter, if there are still any such opposing folds, we'd need to remove the colliding fold.
In any case, reproducers welcomed!
Reviewers: spatel, nikic, efriedma, xbolva00
Reviewed By: spatel
Subscribers: xbolva00, mgorny, hiraditya, reames, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D68408
2020-04-22 02:24:36 +08:00
|
|
|
; CHECK-NEXT: [[T1_NEG:%.*]] = select i1 [[Y:%.*]], i8 42, i8 [[Z]]
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = add i8 [[T1_NEG]], [[X:%.*]]
|
2019-10-03 21:36:00 +08:00
|
|
|
; CHECK-NEXT: ret i8 [[T2]]
|
|
|
|
;
|
|
|
|
%t0 = sub i8 0, %z
|
|
|
|
call void @use8(i8 %t0)
|
|
|
|
%t1 = select i1 %y, i8 -42, i8 %t0
|
|
|
|
%t2 = sub i8 %x, %t1
|
|
|
|
ret i8 %t2
|
|
|
|
}
|
|
|
|
define i8 @t7(i8 %x, i1 %y, i8 %z) {
|
|
|
|
; CHECK-LABEL: @t7(
|
[InstCombine] Negator - sink sinkable negations
Summary:
As we have discussed previously (e.g. in D63992 / D64090 / [[ https://bugs.llvm.org/show_bug.cgi?id=42457 | PR42457 ]]), `sub` instruction
can almost be considered non-canonical. While we do convert `sub %x, C` -> `add %x, -C`,
we sparsely do that for non-constants. But we should.
Here, i propose to interpret `sub %x, %y` as `add (sub 0, %y), %x` IFF the negation can be sinked into the `%y`
This has some potential to cause endless combine loops (either around PHI's, or if there are some opposite transforms).
For former there's `-instcombine-negator-max-depth` option to mitigate it, should this expose any such issues
For latter, if there are still any such opposing folds, we'd need to remove the colliding fold.
In any case, reproducers welcomed!
Reviewers: spatel, nikic, efriedma, xbolva00
Reviewed By: spatel
Subscribers: xbolva00, mgorny, hiraditya, reames, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D68408
2020-04-22 02:24:36 +08:00
|
|
|
; CHECK-NEXT: [[T0_NEG:%.*]] = shl i8 -1, [[Z:%.*]]
|
|
|
|
; CHECK-NEXT: [[T1_NEG:%.*]] = select i1 [[Y:%.*]], i8 0, i8 [[T0_NEG]]
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = add i8 [[T1_NEG]], [[X:%.*]]
|
2019-10-03 21:36:00 +08:00
|
|
|
; CHECK-NEXT: ret i8 [[T2]]
|
|
|
|
;
|
|
|
|
%t0 = shl i8 1, %z
|
|
|
|
%t1 = select i1 %y, i8 0, i8 %t0
|
|
|
|
%t2 = sub i8 %x, %t1
|
|
|
|
ret i8 %t2
|
|
|
|
}
|
|
|
|
define i8 @n8(i8 %x, i1 %y, i8 %z) {
|
|
|
|
; CHECK-LABEL: @n8(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = shl i8 1, [[Z:%.*]]
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T0]])
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = select i1 [[Y:%.*]], i8 0, i8 [[T0]]
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = sub i8 [[X:%.*]], [[T1]]
|
|
|
|
; CHECK-NEXT: ret i8 [[T2]]
|
|
|
|
;
|
|
|
|
%t0 = shl i8 1, %z
|
|
|
|
call void @use8(i8 %t0)
|
|
|
|
%t1 = select i1 %y, i8 0, i8 %t0
|
|
|
|
%t2 = sub i8 %x, %t1
|
|
|
|
ret i8 %t2
|
|
|
|
}
|
|
|
|
|
2019-12-04 20:48:19 +08:00
|
|
|
; Subtraction can be negated by swapping its operands.
|
|
|
|
; x - (y - z) -> x - y + z -> x + (z - y)
|
|
|
|
define i8 @t9(i8 %x, i8 %y) {
|
2019-10-03 21:36:00 +08:00
|
|
|
; CHECK-LABEL: @t9(
|
2020-04-02 00:00:22 +08:00
|
|
|
; CHECK-NEXT: [[T0_NEG:%.*]] = sub i8 [[X:%.*]], [[Y:%.*]]
|
|
|
|
; CHECK-NEXT: ret i8 [[T0_NEG]]
|
2019-10-03 21:36:00 +08:00
|
|
|
;
|
2019-12-04 20:48:19 +08:00
|
|
|
%t0 = sub i8 %y, %x
|
|
|
|
%t1 = sub i8 0, %t0
|
|
|
|
ret i8 %t1
|
2019-10-03 21:36:00 +08:00
|
|
|
}
|
|
|
|
define i8 @n10(i8 %x, i8 %y, i8 %z) {
|
|
|
|
; CHECK-LABEL: @n10(
|
2020-04-24 02:07:23 +08:00
|
|
|
; CHECK-NEXT: [[T0:%.*]] = sub i8 [[Y:%.*]], [[X:%.*]]
|
2019-10-03 21:36:00 +08:00
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T0]])
|
2020-04-24 02:07:23 +08:00
|
|
|
; CHECK-NEXT: [[T1:%.*]] = sub i8 0, [[T0]]
|
|
|
|
; CHECK-NEXT: ret i8 [[T1]]
|
2019-10-03 21:36:00 +08:00
|
|
|
;
|
2019-12-04 20:48:19 +08:00
|
|
|
%t0 = sub i8 %y, %x
|
2019-10-03 21:36:00 +08:00
|
|
|
call void @use8(i8 %t0)
|
2019-12-04 20:48:19 +08:00
|
|
|
%t1 = sub i8 0, %t0
|
|
|
|
ret i8 %t1
|
2019-10-03 21:36:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
; Addition can be negated if both operands can be negated
|
|
|
|
; x - (y + z) -> x - y - z -> x + ((-y) + (-z)))
|
|
|
|
define i8 @t12(i8 %x, i8 %y, i8 %z) {
|
|
|
|
; CHECK-LABEL: @t12(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = sub i8 0, [[Y:%.*]]
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T0]])
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = sub i8 0, [[Z:%.*]]
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T1]])
|
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[Y]], [[Z]]
|
|
|
|
; CHECK-NEXT: [[T3:%.*]] = add i8 [[TMP1]], [[X:%.*]]
|
|
|
|
; CHECK-NEXT: ret i8 [[T3]]
|
|
|
|
;
|
|
|
|
%t0 = sub i8 0, %y
|
|
|
|
call void @use8(i8 %t0)
|
|
|
|
%t1 = sub i8 0, %z
|
|
|
|
call void @use8(i8 %t1)
|
|
|
|
%t2 = add i8 %t0, %t1
|
|
|
|
%t3 = sub i8 %x, %t2
|
|
|
|
ret i8 %t3
|
|
|
|
}
|
|
|
|
define i8 @n13(i8 %x, i8 %y, i8 %z) {
|
|
|
|
; CHECK-LABEL: @n13(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = sub i8 0, [[Y:%.*]]
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T0]])
|
[InstCombine] Negator - sink sinkable negations
Summary:
As we have discussed previously (e.g. in D63992 / D64090 / [[ https://bugs.llvm.org/show_bug.cgi?id=42457 | PR42457 ]]), `sub` instruction
can almost be considered non-canonical. While we do convert `sub %x, C` -> `add %x, -C`,
we sparsely do that for non-constants. But we should.
Here, i propose to interpret `sub %x, %y` as `add (sub 0, %y), %x` IFF the negation can be sinked into the `%y`
This has some potential to cause endless combine loops (either around PHI's, or if there are some opposite transforms).
For former there's `-instcombine-negator-max-depth` option to mitigate it, should this expose any such issues
For latter, if there are still any such opposing folds, we'd need to remove the colliding fold.
In any case, reproducers welcomed!
Reviewers: spatel, nikic, efriedma, xbolva00
Reviewed By: spatel
Subscribers: xbolva00, mgorny, hiraditya, reames, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D68408
2020-04-22 02:24:36 +08:00
|
|
|
; CHECK-NEXT: [[T1_NEG:%.*]] = sub i8 [[Y]], [[Z:%.*]]
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = add i8 [[T1_NEG]], [[X:%.*]]
|
2019-10-03 21:36:00 +08:00
|
|
|
; CHECK-NEXT: ret i8 [[T2]]
|
|
|
|
;
|
|
|
|
%t0 = sub i8 0, %y
|
|
|
|
call void @use8(i8 %t0)
|
|
|
|
%t1 = add i8 %t0, %z
|
|
|
|
%t2 = sub i8 %x, %t1
|
|
|
|
ret i8 %t2
|
|
|
|
}
|
|
|
|
define i8 @n14(i8 %x, i8 %y, i8 %z) {
|
|
|
|
; CHECK-LABEL: @n14(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = sub i8 0, [[Y:%.*]]
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T0]])
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = sub i8 0, [[Z:%.*]]
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T1]])
|
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[Y]], [[Z]]
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = sub i8 0, [[TMP1]]
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T2]])
|
|
|
|
; CHECK-NEXT: [[T3:%.*]] = add i8 [[TMP1]], [[X:%.*]]
|
|
|
|
; CHECK-NEXT: ret i8 [[T3]]
|
|
|
|
;
|
|
|
|
%t0 = sub i8 0, %y
|
|
|
|
call void @use8(i8 %t0)
|
|
|
|
%t1 = sub i8 0, %z
|
|
|
|
call void @use8(i8 %t1)
|
|
|
|
%t2 = add i8 %t0, %t1
|
|
|
|
call void @use8(i8 %t2)
|
|
|
|
%t3 = sub i8 %x, %t2
|
|
|
|
ret i8 %t3
|
|
|
|
}
|
|
|
|
|
|
|
|
; Multiplication can be negated if either one of operands can be negated
|
|
|
|
; x - (y * z) -> x + ((-y) * z) or x + ((-z) * y)
|
|
|
|
define i8 @t15(i8 %x, i8 %y, i8 %z) {
|
|
|
|
; CHECK-LABEL: @t15(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = sub i8 0, [[Y:%.*]]
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T0]])
|
[InstCombine] Negator - sink sinkable negations
Summary:
As we have discussed previously (e.g. in D63992 / D64090 / [[ https://bugs.llvm.org/show_bug.cgi?id=42457 | PR42457 ]]), `sub` instruction
can almost be considered non-canonical. While we do convert `sub %x, C` -> `add %x, -C`,
we sparsely do that for non-constants. But we should.
Here, i propose to interpret `sub %x, %y` as `add (sub 0, %y), %x` IFF the negation can be sinked into the `%y`
This has some potential to cause endless combine loops (either around PHI's, or if there are some opposite transforms).
For former there's `-instcombine-negator-max-depth` option to mitigate it, should this expose any such issues
For latter, if there are still any such opposing folds, we'd need to remove the colliding fold.
In any case, reproducers welcomed!
Reviewers: spatel, nikic, efriedma, xbolva00
Reviewed By: spatel
Subscribers: xbolva00, mgorny, hiraditya, reames, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D68408
2020-04-22 02:24:36 +08:00
|
|
|
; CHECK-NEXT: [[T1_NEG:%.*]] = mul i8 [[Y]], [[Z:%.*]]
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = add i8 [[T1_NEG]], [[X:%.*]]
|
2019-10-03 21:36:00 +08:00
|
|
|
; CHECK-NEXT: ret i8 [[T2]]
|
|
|
|
;
|
|
|
|
%t0 = sub i8 0, %y
|
|
|
|
call void @use8(i8 %t0)
|
|
|
|
%t1 = mul i8 %t0, %z
|
|
|
|
%t2 = sub i8 %x, %t1
|
|
|
|
ret i8 %t2
|
|
|
|
}
|
|
|
|
define i8 @n16(i8 %x, i8 %y, i8 %z) {
|
|
|
|
; CHECK-LABEL: @n16(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = sub i8 0, [[Y:%.*]]
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T0]])
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = mul i8 [[T0]], [[Z:%.*]]
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T1]])
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = sub i8 [[X:%.*]], [[T1]]
|
|
|
|
; CHECK-NEXT: ret i8 [[T2]]
|
|
|
|
;
|
|
|
|
%t0 = sub i8 0, %y
|
|
|
|
call void @use8(i8 %t0)
|
|
|
|
%t1 = mul i8 %t0, %z
|
|
|
|
call void @use8(i8 %t1)
|
|
|
|
%t2 = sub i8 %x, %t1
|
|
|
|
ret i8 %t2
|
|
|
|
}
|
2019-12-04 20:48:19 +08:00
|
|
|
|
|
|
|
; Phi can be negated if all incoming values can be negated
|
|
|
|
define i8 @t16(i1 %c, i8 %x) {
|
|
|
|
; CHECK-LABEL: @t16(
|
|
|
|
; CHECK-NEXT: begin:
|
|
|
|
; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]]
|
|
|
|
; CHECK: then:
|
|
|
|
; CHECK-NEXT: br label [[END:%.*]]
|
|
|
|
; CHECK: else:
|
|
|
|
; CHECK-NEXT: br label [[END]]
|
|
|
|
; CHECK: end:
|
[InstCombine] Negator - sink sinkable negations
Summary:
As we have discussed previously (e.g. in D63992 / D64090 / [[ https://bugs.llvm.org/show_bug.cgi?id=42457 | PR42457 ]]), `sub` instruction
can almost be considered non-canonical. While we do convert `sub %x, C` -> `add %x, -C`,
we sparsely do that for non-constants. But we should.
Here, i propose to interpret `sub %x, %y` as `add (sub 0, %y), %x` IFF the negation can be sinked into the `%y`
This has some potential to cause endless combine loops (either around PHI's, or if there are some opposite transforms).
For former there's `-instcombine-negator-max-depth` option to mitigate it, should this expose any such issues
For latter, if there are still any such opposing folds, we'd need to remove the colliding fold.
In any case, reproducers welcomed!
Reviewers: spatel, nikic, efriedma, xbolva00
Reviewed By: spatel
Subscribers: xbolva00, mgorny, hiraditya, reames, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D68408
2020-04-22 02:24:36 +08:00
|
|
|
; CHECK-NEXT: [[Z_NEG:%.*]] = phi i8 [ [[X:%.*]], [[THEN]] ], [ 42, [[ELSE]] ]
|
|
|
|
; CHECK-NEXT: ret i8 [[Z_NEG]]
|
2019-12-04 20:48:19 +08:00
|
|
|
;
|
|
|
|
begin:
|
|
|
|
br i1 %c, label %then, label %else
|
|
|
|
then:
|
|
|
|
%y = sub i8 0, %x
|
|
|
|
br label %end
|
|
|
|
else:
|
|
|
|
br label %end
|
|
|
|
end:
|
|
|
|
%z = phi i8 [ %y, %then], [ -42, %else ]
|
|
|
|
%n = sub i8 0, %z
|
|
|
|
ret i8 %n
|
|
|
|
}
|
|
|
|
define i8 @n17(i1 %c, i8 %x) {
|
|
|
|
; CHECK-LABEL: @n17(
|
|
|
|
; CHECK-NEXT: begin:
|
|
|
|
; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]]
|
|
|
|
; CHECK: then:
|
|
|
|
; CHECK-NEXT: [[Y:%.*]] = sub i8 0, [[X:%.*]]
|
|
|
|
; CHECK-NEXT: br label [[END:%.*]]
|
|
|
|
; CHECK: else:
|
|
|
|
; CHECK-NEXT: br label [[END]]
|
|
|
|
; CHECK: end:
|
|
|
|
; CHECK-NEXT: [[Z:%.*]] = phi i8 [ [[Y]], [[THEN]] ], [ -42, [[ELSE]] ]
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[Z]])
|
|
|
|
; CHECK-NEXT: [[N:%.*]] = sub i8 0, [[Z]]
|
|
|
|
; CHECK-NEXT: ret i8 [[N]]
|
|
|
|
;
|
|
|
|
begin:
|
|
|
|
br i1 %c, label %then, label %else
|
|
|
|
then:
|
|
|
|
%y = sub i8 0, %x
|
|
|
|
br label %end
|
|
|
|
else:
|
|
|
|
br label %end
|
|
|
|
end:
|
|
|
|
%z = phi i8 [ %y, %then], [ -42, %else ]
|
|
|
|
call void @use8(i8 %z)
|
|
|
|
%n = sub i8 0, %z
|
|
|
|
ret i8 %n
|
|
|
|
}
|
|
|
|
define i8 @n19(i1 %c, i8 %x, i8 %y) {
|
|
|
|
; CHECK-LABEL: @n19(
|
|
|
|
; CHECK-NEXT: begin:
|
|
|
|
; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]]
|
|
|
|
; CHECK: then:
|
|
|
|
; CHECK-NEXT: [[Z:%.*]] = sub i8 0, [[X:%.*]]
|
|
|
|
; CHECK-NEXT: br label [[END:%.*]]
|
|
|
|
; CHECK: else:
|
|
|
|
; CHECK-NEXT: br label [[END]]
|
|
|
|
; CHECK: end:
|
|
|
|
; CHECK-NEXT: [[R:%.*]] = phi i8 [ [[Z]], [[THEN]] ], [ [[Y:%.*]], [[ELSE]] ]
|
|
|
|
; CHECK-NEXT: [[N:%.*]] = sub i8 0, [[R]]
|
|
|
|
; CHECK-NEXT: ret i8 [[N]]
|
|
|
|
;
|
|
|
|
begin:
|
|
|
|
br i1 %c, label %then, label %else
|
|
|
|
then:
|
|
|
|
%z = sub i8 0, %x
|
|
|
|
br label %end
|
|
|
|
else:
|
|
|
|
br label %end
|
|
|
|
end:
|
|
|
|
%r = phi i8 [ %z, %then], [ %y, %else ]
|
|
|
|
%n = sub i8 0, %r
|
|
|
|
ret i8 %n
|
|
|
|
}
|
2020-06-18 02:37:19 +08:00
|
|
|
define void @phi_with_duplicate_incoming_basic_blocks(i32 %x, i32 %y, i1 %should_lookup, i32 %z) {
|
|
|
|
; CHECK-LABEL: @phi_with_duplicate_incoming_basic_blocks(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: [[X_INC_NEG:%.*]] = xor i32 [[X:%.*]], -1
|
|
|
|
; CHECK-NEXT: br i1 [[SHOULD_LOOKUP:%.*]], label [[LOOKUP:%.*]], label [[LOOP:%.*]]
|
|
|
|
; CHECK: lookup:
|
|
|
|
; CHECK-NEXT: [[TO_LOOKUP:%.*]] = phi i32 [ [[Y:%.*]], [[ENTRY:%.*]] ], [ [[METAVAL_NEG:%.*]], [[LOOP]] ]
|
|
|
|
; CHECK-NEXT: switch i32 [[TO_LOOKUP]], label [[END:%.*]] [
|
|
|
|
; CHECK-NEXT: i32 0, label [[LOOP]]
|
|
|
|
; CHECK-NEXT: i32 42, label [[LOOP]]
|
|
|
|
; CHECK-NEXT: ]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[METAVAL_NEG]] = phi i32 [ [[X_INC_NEG]], [[LOOKUP]] ], [ [[X_INC_NEG]], [[LOOKUP]] ], [ -84, [[ENTRY]] ]
|
|
|
|
; CHECK-NEXT: [[REPEAT:%.*]] = call i1 @use32gen1(i32 [[METAVAL_NEG]])
|
|
|
|
; CHECK-NEXT: br i1 [[REPEAT]], label [[LOOKUP]], label [[END]]
|
|
|
|
; CHECK: end:
|
|
|
|
; CHECK-NEXT: ret void
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
%x_inc = add i32 %x, 1
|
|
|
|
br i1 %should_lookup, label %lookup, label %loop
|
|
|
|
|
|
|
|
lookup:
|
|
|
|
%to_lookup = phi i32 [ %y, %entry ], [ %negated_metaval, %loop ]
|
|
|
|
switch i32 %to_lookup, label %end [
|
|
|
|
i32 0, label %loop
|
|
|
|
i32 42, label %loop
|
|
|
|
]
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%metaval = phi i32 [ %x_inc, %lookup ], [ %x_inc, %lookup ], [ 84, %entry ]
|
|
|
|
%negated_metaval = sub i32 0, %metaval
|
|
|
|
%repeat = call i1 @use32gen1(i32 %negated_metaval)
|
|
|
|
br i1 %repeat, label %lookup, label %end
|
|
|
|
|
|
|
|
end:
|
|
|
|
ret void
|
|
|
|
}
|
2019-12-04 20:48:19 +08:00
|
|
|
|
|
|
|
; truncation can be negated if it's operand can be negated
|
|
|
|
define i8 @t20(i8 %x, i16 %y) {
|
|
|
|
; CHECK-LABEL: @t20(
|
[InstCombine] Negator - sink sinkable negations
Summary:
As we have discussed previously (e.g. in D63992 / D64090 / [[ https://bugs.llvm.org/show_bug.cgi?id=42457 | PR42457 ]]), `sub` instruction
can almost be considered non-canonical. While we do convert `sub %x, C` -> `add %x, -C`,
we sparsely do that for non-constants. But we should.
Here, i propose to interpret `sub %x, %y` as `add (sub 0, %y), %x` IFF the negation can be sinked into the `%y`
This has some potential to cause endless combine loops (either around PHI's, or if there are some opposite transforms).
For former there's `-instcombine-negator-max-depth` option to mitigate it, should this expose any such issues
For latter, if there are still any such opposing folds, we'd need to remove the colliding fold.
In any case, reproducers welcomed!
Reviewers: spatel, nikic, efriedma, xbolva00
Reviewed By: spatel
Subscribers: xbolva00, mgorny, hiraditya, reames, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D68408
2020-04-22 02:24:36 +08:00
|
|
|
; CHECK-NEXT: [[T0_NEG:%.*]] = shl i16 42, [[Y:%.*]]
|
|
|
|
; CHECK-NEXT: [[T1_NEG:%.*]] = trunc i16 [[T0_NEG]] to i8
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = add i8 [[T1_NEG]], [[X:%.*]]
|
2019-12-04 20:48:19 +08:00
|
|
|
; CHECK-NEXT: ret i8 [[T2]]
|
|
|
|
;
|
|
|
|
%t0 = shl i16 -42, %y
|
|
|
|
%t1 = trunc i16 %t0 to i8
|
|
|
|
%t2 = sub i8 %x, %t1
|
|
|
|
ret i8 %t2
|
|
|
|
}
|
|
|
|
define i8 @n21(i8 %x, i16 %y) {
|
|
|
|
; CHECK-LABEL: @n21(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = shl i16 -42, [[Y:%.*]]
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = trunc i16 [[T0]] to i8
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T1]])
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = sub i8 [[X:%.*]], [[T1]]
|
|
|
|
; CHECK-NEXT: ret i8 [[T2]]
|
|
|
|
;
|
|
|
|
%t0 = shl i16 -42, %y
|
|
|
|
%t1 = trunc i16 %t0 to i8
|
|
|
|
call void @use8(i8 %t1)
|
|
|
|
%t2 = sub i8 %x, %t1
|
|
|
|
ret i8 %t2
|
|
|
|
}
|
2020-04-02 00:00:22 +08:00
|
|
|
|
|
|
|
define i4 @negate_xor(i4 %x) {
|
|
|
|
; CHECK-LABEL: @negate_xor(
|
2020-04-02 02:32:13 +08:00
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i4 [[X:%.*]], -6
|
|
|
|
; CHECK-NEXT: [[O_NEG:%.*]] = add i4 [[TMP1]], 1
|
|
|
|
; CHECK-NEXT: ret i4 [[O_NEG]]
|
2020-04-02 00:00:22 +08:00
|
|
|
;
|
|
|
|
%o = xor i4 %x, 5
|
|
|
|
%r = sub i4 0, %o
|
|
|
|
ret i4 %r
|
|
|
|
}
|
|
|
|
|
|
|
|
define <2 x i4> @negate_xor_vec(<2 x i4> %x) {
|
|
|
|
; CHECK-LABEL: @negate_xor_vec(
|
2020-04-02 02:32:13 +08:00
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor <2 x i4> [[X:%.*]], <i4 -6, i4 5>
|
|
|
|
; CHECK-NEXT: [[O_NEG:%.*]] = add <2 x i4> [[TMP1]], <i4 1, i4 1>
|
|
|
|
; CHECK-NEXT: ret <2 x i4> [[O_NEG]]
|
2020-04-02 00:00:22 +08:00
|
|
|
;
|
|
|
|
%o = xor <2 x i4> %x, <i4 5, i4 10>
|
|
|
|
%r = sub <2 x i4> zeroinitializer, %o
|
|
|
|
ret <2 x i4> %r
|
|
|
|
}
|
|
|
|
|
|
|
|
define i8 @negate_xor_use(i8 %x) {
|
|
|
|
; CHECK-LABEL: @negate_xor_use(
|
|
|
|
; CHECK-NEXT: [[O:%.*]] = xor i8 [[X:%.*]], 5
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[O]])
|
|
|
|
; CHECK-NEXT: [[R:%.*]] = sub i8 0, [[O]]
|
|
|
|
; CHECK-NEXT: ret i8 [[R]]
|
|
|
|
;
|
|
|
|
%o = xor i8 %x, 5
|
|
|
|
call void @use8(i8 %o)
|
|
|
|
%r = sub i8 0, %o
|
|
|
|
ret i8 %r
|
|
|
|
}
|
|
|
|
|
|
|
|
define i4 @negate_shl_xor(i4 %x, i4 %y) {
|
|
|
|
; CHECK-LABEL: @negate_shl_xor(
|
2020-04-02 02:32:13 +08:00
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = xor i4 [[X:%.*]], -6
|
|
|
|
; CHECK-NEXT: [[O_NEG:%.*]] = add i4 [[TMP1]], 1
|
|
|
|
; CHECK-NEXT: [[S_NEG:%.*]] = shl i4 [[O_NEG]], [[Y:%.*]]
|
|
|
|
; CHECK-NEXT: ret i4 [[S_NEG]]
|
2020-04-02 00:00:22 +08:00
|
|
|
;
|
|
|
|
%o = xor i4 %x, 5
|
|
|
|
%s = shl i4 %o, %y
|
|
|
|
%r = sub i4 0, %s
|
|
|
|
ret i4 %r
|
|
|
|
}
|
2020-04-04 05:09:38 +08:00
|
|
|
|
|
|
|
define i8 @negate_shl_not_uses(i8 %x, i8 %y) {
|
|
|
|
; CHECK-LABEL: @negate_shl_not_uses(
|
[InstCombine] Negator - sink sinkable negations
Summary:
As we have discussed previously (e.g. in D63992 / D64090 / [[ https://bugs.llvm.org/show_bug.cgi?id=42457 | PR42457 ]]), `sub` instruction
can almost be considered non-canonical. While we do convert `sub %x, C` -> `add %x, -C`,
we sparsely do that for non-constants. But we should.
Here, i propose to interpret `sub %x, %y` as `add (sub 0, %y), %x` IFF the negation can be sinked into the `%y`
This has some potential to cause endless combine loops (either around PHI's, or if there are some opposite transforms).
For former there's `-instcombine-negator-max-depth` option to mitigate it, should this expose any such issues
For latter, if there are still any such opposing folds, we'd need to remove the colliding fold.
In any case, reproducers welcomed!
Reviewers: spatel, nikic, efriedma, xbolva00
Reviewed By: spatel
Subscribers: xbolva00, mgorny, hiraditya, reames, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D68408
2020-04-22 02:24:36 +08:00
|
|
|
; CHECK-NEXT: [[O_NEG:%.*]] = add i8 [[X:%.*]], 1
|
|
|
|
; CHECK-NEXT: [[O:%.*]] = xor i8 [[X]], -1
|
2020-04-04 05:09:38 +08:00
|
|
|
; CHECK-NEXT: call void @use8(i8 [[O]])
|
2020-04-05 21:16:19 +08:00
|
|
|
; CHECK-NEXT: [[S_NEG:%.*]] = shl i8 [[O_NEG]], [[Y:%.*]]
|
|
|
|
; CHECK-NEXT: ret i8 [[S_NEG]]
|
2020-04-04 05:09:38 +08:00
|
|
|
;
|
|
|
|
%o = xor i8 %x, -1
|
|
|
|
call void @use8(i8 %o)
|
|
|
|
%s = shl i8 %o, %y
|
|
|
|
%r = sub i8 0, %s
|
|
|
|
ret i8 %r
|
|
|
|
}
|
|
|
|
|
|
|
|
define <2 x i4> @negate_mul_not_uses_vec(<2 x i4> %x, <2 x i4> %y) {
|
|
|
|
; CHECK-LABEL: @negate_mul_not_uses_vec(
|
[InstCombine] Negator - sink sinkable negations
Summary:
As we have discussed previously (e.g. in D63992 / D64090 / [[ https://bugs.llvm.org/show_bug.cgi?id=42457 | PR42457 ]]), `sub` instruction
can almost be considered non-canonical. While we do convert `sub %x, C` -> `add %x, -C`,
we sparsely do that for non-constants. But we should.
Here, i propose to interpret `sub %x, %y` as `add (sub 0, %y), %x` IFF the negation can be sinked into the `%y`
This has some potential to cause endless combine loops (either around PHI's, or if there are some opposite transforms).
For former there's `-instcombine-negator-max-depth` option to mitigate it, should this expose any such issues
For latter, if there are still any such opposing folds, we'd need to remove the colliding fold.
In any case, reproducers welcomed!
Reviewers: spatel, nikic, efriedma, xbolva00
Reviewed By: spatel
Subscribers: xbolva00, mgorny, hiraditya, reames, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D68408
2020-04-22 02:24:36 +08:00
|
|
|
; CHECK-NEXT: [[O_NEG:%.*]] = add <2 x i4> [[X:%.*]], <i4 1, i4 1>
|
|
|
|
; CHECK-NEXT: [[O:%.*]] = xor <2 x i4> [[X]], <i4 -1, i4 -1>
|
2020-04-04 05:09:38 +08:00
|
|
|
; CHECK-NEXT: call void @use_v2i4(<2 x i4> [[O]])
|
2020-04-05 21:16:19 +08:00
|
|
|
; CHECK-NEXT: [[S_NEG:%.*]] = mul <2 x i4> [[O_NEG]], [[Y:%.*]]
|
|
|
|
; CHECK-NEXT: ret <2 x i4> [[S_NEG]]
|
2020-04-04 05:09:38 +08:00
|
|
|
;
|
|
|
|
%o = xor <2 x i4> %x, <i4 -1, i4 -1>
|
|
|
|
call void @use_v2i4(<2 x i4> %o)
|
|
|
|
%s = mul <2 x i4> %o, %y
|
|
|
|
%r = sub <2 x i4> zeroinitializer, %s
|
|
|
|
ret <2 x i4> %r
|
|
|
|
}
|
2020-04-22 01:13:57 +08:00
|
|
|
|
|
|
|
; signed division can be negated if divisor can be negated and is not 1/-1
|
|
|
|
define i8 @negate_sdiv(i8 %x, i8 %y) {
|
|
|
|
; CHECK-LABEL: @negate_sdiv(
|
[InstCombine] Negator - sink sinkable negations
Summary:
As we have discussed previously (e.g. in D63992 / D64090 / [[ https://bugs.llvm.org/show_bug.cgi?id=42457 | PR42457 ]]), `sub` instruction
can almost be considered non-canonical. While we do convert `sub %x, C` -> `add %x, -C`,
we sparsely do that for non-constants. But we should.
Here, i propose to interpret `sub %x, %y` as `add (sub 0, %y), %x` IFF the negation can be sinked into the `%y`
This has some potential to cause endless combine loops (either around PHI's, or if there are some opposite transforms).
For former there's `-instcombine-negator-max-depth` option to mitigate it, should this expose any such issues
For latter, if there are still any such opposing folds, we'd need to remove the colliding fold.
In any case, reproducers welcomed!
Reviewers: spatel, nikic, efriedma, xbolva00
Reviewed By: spatel
Subscribers: xbolva00, mgorny, hiraditya, reames, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D68408
2020-04-22 02:24:36 +08:00
|
|
|
; CHECK-NEXT: [[T0_NEG:%.*]] = sdiv i8 [[Y:%.*]], -42
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = add i8 [[T0_NEG]], [[X:%.*]]
|
2020-04-22 01:13:57 +08:00
|
|
|
; CHECK-NEXT: ret i8 [[T1]]
|
|
|
|
;
|
|
|
|
%t0 = sdiv i8 %y, 42
|
|
|
|
%t1 = sub i8 %x, %t0
|
|
|
|
ret i8 %t1
|
|
|
|
}
|
|
|
|
define i8 @negate_sdiv_extrause(i8 %x, i8 %y) {
|
|
|
|
; CHECK-LABEL: @negate_sdiv_extrause(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = sdiv i8 [[Y:%.*]], 42
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T0]])
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = sub i8 [[X:%.*]], [[T0]]
|
|
|
|
; CHECK-NEXT: ret i8 [[T1]]
|
|
|
|
;
|
|
|
|
%t0 = sdiv i8 %y, 42
|
|
|
|
call void @use8(i8 %t0)
|
|
|
|
%t1 = sub i8 %x, %t0
|
|
|
|
ret i8 %t1
|
|
|
|
}
|
[InstCombine] Negator - sink sinkable negations
Summary:
As we have discussed previously (e.g. in D63992 / D64090 / [[ https://bugs.llvm.org/show_bug.cgi?id=42457 | PR42457 ]]), `sub` instruction
can almost be considered non-canonical. While we do convert `sub %x, C` -> `add %x, -C`,
we sparsely do that for non-constants. But we should.
Here, i propose to interpret `sub %x, %y` as `add (sub 0, %y), %x` IFF the negation can be sinked into the `%y`
This has some potential to cause endless combine loops (either around PHI's, or if there are some opposite transforms).
For former there's `-instcombine-negator-max-depth` option to mitigate it, should this expose any such issues
For latter, if there are still any such opposing folds, we'd need to remove the colliding fold.
In any case, reproducers welcomed!
Reviewers: spatel, nikic, efriedma, xbolva00
Reviewed By: spatel
Subscribers: xbolva00, mgorny, hiraditya, reames, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D68408
2020-04-22 02:24:36 +08:00
|
|
|
define i8 @negate_sdiv_extrause2(i8 %x, i8 %y) {
|
|
|
|
; CHECK-LABEL: @negate_sdiv_extrause2(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = sdiv i8 [[Y:%.*]], 42
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T0]])
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = sub nsw i8 0, [[T0]]
|
|
|
|
; CHECK-NEXT: ret i8 [[T1]]
|
|
|
|
;
|
|
|
|
%t0 = sdiv i8 %y, 42
|
|
|
|
call void @use8(i8 %t0)
|
|
|
|
%t1 = sub i8 0, %t0
|
|
|
|
ret i8 %t1
|
|
|
|
}
|
2020-04-22 01:13:57 +08:00
|
|
|
|
|
|
|
; Right-shift sign bit smear is negatible.
|
|
|
|
define i8 @negate_ashr(i8 %x, i8 %y) {
|
|
|
|
; CHECK-LABEL: @negate_ashr(
|
[InstCombine] Negator - sink sinkable negations
Summary:
As we have discussed previously (e.g. in D63992 / D64090 / [[ https://bugs.llvm.org/show_bug.cgi?id=42457 | PR42457 ]]), `sub` instruction
can almost be considered non-canonical. While we do convert `sub %x, C` -> `add %x, -C`,
we sparsely do that for non-constants. But we should.
Here, i propose to interpret `sub %x, %y` as `add (sub 0, %y), %x` IFF the negation can be sinked into the `%y`
This has some potential to cause endless combine loops (either around PHI's, or if there are some opposite transforms).
For former there's `-instcombine-negator-max-depth` option to mitigate it, should this expose any such issues
For latter, if there are still any such opposing folds, we'd need to remove the colliding fold.
In any case, reproducers welcomed!
Reviewers: spatel, nikic, efriedma, xbolva00
Reviewed By: spatel
Subscribers: xbolva00, mgorny, hiraditya, reames, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D68408
2020-04-22 02:24:36 +08:00
|
|
|
; CHECK-NEXT: [[T0_NEG:%.*]] = lshr i8 [[Y:%.*]], 7
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = add i8 [[T0_NEG]], [[X:%.*]]
|
2020-04-22 01:13:57 +08:00
|
|
|
; CHECK-NEXT: ret i8 [[T1]]
|
|
|
|
;
|
|
|
|
%t0 = ashr i8 %y, 7
|
|
|
|
%t1 = sub i8 %x, %t0
|
|
|
|
ret i8 %t1
|
|
|
|
}
|
|
|
|
define i8 @negate_lshr(i8 %x, i8 %y) {
|
|
|
|
; CHECK-LABEL: @negate_lshr(
|
[InstCombine] Negator - sink sinkable negations
Summary:
As we have discussed previously (e.g. in D63992 / D64090 / [[ https://bugs.llvm.org/show_bug.cgi?id=42457 | PR42457 ]]), `sub` instruction
can almost be considered non-canonical. While we do convert `sub %x, C` -> `add %x, -C`,
we sparsely do that for non-constants. But we should.
Here, i propose to interpret `sub %x, %y` as `add (sub 0, %y), %x` IFF the negation can be sinked into the `%y`
This has some potential to cause endless combine loops (either around PHI's, or if there are some opposite transforms).
For former there's `-instcombine-negator-max-depth` option to mitigate it, should this expose any such issues
For latter, if there are still any such opposing folds, we'd need to remove the colliding fold.
In any case, reproducers welcomed!
Reviewers: spatel, nikic, efriedma, xbolva00
Reviewed By: spatel
Subscribers: xbolva00, mgorny, hiraditya, reames, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D68408
2020-04-22 02:24:36 +08:00
|
|
|
; CHECK-NEXT: [[T0_NEG:%.*]] = ashr i8 [[Y:%.*]], 7
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = add i8 [[T0_NEG]], [[X:%.*]]
|
2020-04-22 01:13:57 +08:00
|
|
|
; CHECK-NEXT: ret i8 [[T1]]
|
|
|
|
;
|
|
|
|
%t0 = lshr i8 %y, 7
|
|
|
|
%t1 = sub i8 %x, %t0
|
|
|
|
ret i8 %t1
|
|
|
|
}
|
|
|
|
define i8 @negate_ashr_extrause(i8 %x, i8 %y) {
|
|
|
|
; CHECK-LABEL: @negate_ashr_extrause(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = ashr i8 [[Y:%.*]], 7
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T0]])
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = sub i8 [[X:%.*]], [[T0]]
|
|
|
|
; CHECK-NEXT: ret i8 [[T1]]
|
|
|
|
;
|
|
|
|
%t0 = ashr i8 %y, 7
|
|
|
|
call void @use8(i8 %t0)
|
|
|
|
%t1 = sub i8 %x, %t0
|
|
|
|
ret i8 %t1
|
|
|
|
}
|
|
|
|
define i8 @negate_lshr_extrause(i8 %x, i8 %y) {
|
|
|
|
; CHECK-LABEL: @negate_lshr_extrause(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = lshr i8 [[Y:%.*]], 7
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T0]])
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = sub i8 [[X:%.*]], [[T0]]
|
|
|
|
; CHECK-NEXT: ret i8 [[T1]]
|
|
|
|
;
|
|
|
|
%t0 = lshr i8 %y, 7
|
|
|
|
call void @use8(i8 %t0)
|
|
|
|
%t1 = sub i8 %x, %t0
|
|
|
|
ret i8 %t1
|
|
|
|
}
|
|
|
|
define i8 @negate_ashr_wrongshift(i8 %x, i8 %y) {
|
|
|
|
; CHECK-LABEL: @negate_ashr_wrongshift(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = ashr i8 [[Y:%.*]], 6
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = sub i8 [[X:%.*]], [[T0]]
|
|
|
|
; CHECK-NEXT: ret i8 [[T1]]
|
|
|
|
;
|
|
|
|
%t0 = ashr i8 %y, 6
|
|
|
|
%t1 = sub i8 %x, %t0
|
|
|
|
ret i8 %t1
|
|
|
|
}
|
|
|
|
define i8 @negate_lshr_wrongshift(i8 %x, i8 %y) {
|
|
|
|
; CHECK-LABEL: @negate_lshr_wrongshift(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = lshr i8 [[Y:%.*]], 6
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = sub i8 [[X:%.*]], [[T0]]
|
|
|
|
; CHECK-NEXT: ret i8 [[T1]]
|
|
|
|
;
|
|
|
|
%t0 = lshr i8 %y, 6
|
|
|
|
%t1 = sub i8 %x, %t0
|
|
|
|
ret i8 %t1
|
|
|
|
}
|
|
|
|
|
|
|
|
; *ext of i1 is always negatible
|
|
|
|
define i8 @negate_sext(i8 %x, i1 %y) {
|
|
|
|
; CHECK-LABEL: @negate_sext(
|
[InstCombine] Negator - sink sinkable negations
Summary:
As we have discussed previously (e.g. in D63992 / D64090 / [[ https://bugs.llvm.org/show_bug.cgi?id=42457 | PR42457 ]]), `sub` instruction
can almost be considered non-canonical. While we do convert `sub %x, C` -> `add %x, -C`,
we sparsely do that for non-constants. But we should.
Here, i propose to interpret `sub %x, %y` as `add (sub 0, %y), %x` IFF the negation can be sinked into the `%y`
This has some potential to cause endless combine loops (either around PHI's, or if there are some opposite transforms).
For former there's `-instcombine-negator-max-depth` option to mitigate it, should this expose any such issues
For latter, if there are still any such opposing folds, we'd need to remove the colliding fold.
In any case, reproducers welcomed!
Reviewers: spatel, nikic, efriedma, xbolva00
Reviewed By: spatel
Subscribers: xbolva00, mgorny, hiraditya, reames, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D68408
2020-04-22 02:24:36 +08:00
|
|
|
; CHECK-NEXT: [[T0_NEG:%.*]] = zext i1 [[Y:%.*]] to i8
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = add i8 [[T0_NEG]], [[X:%.*]]
|
2020-04-22 01:13:57 +08:00
|
|
|
; CHECK-NEXT: ret i8 [[T1]]
|
|
|
|
;
|
|
|
|
%t0 = sext i1 %y to i8
|
|
|
|
%t1 = sub i8 %x, %t0
|
|
|
|
ret i8 %t1
|
|
|
|
}
|
|
|
|
define i8 @negate_zext(i8 %x, i1 %y) {
|
|
|
|
; CHECK-LABEL: @negate_zext(
|
[InstCombine] Negator - sink sinkable negations
Summary:
As we have discussed previously (e.g. in D63992 / D64090 / [[ https://bugs.llvm.org/show_bug.cgi?id=42457 | PR42457 ]]), `sub` instruction
can almost be considered non-canonical. While we do convert `sub %x, C` -> `add %x, -C`,
we sparsely do that for non-constants. But we should.
Here, i propose to interpret `sub %x, %y` as `add (sub 0, %y), %x` IFF the negation can be sinked into the `%y`
This has some potential to cause endless combine loops (either around PHI's, or if there are some opposite transforms).
For former there's `-instcombine-negator-max-depth` option to mitigate it, should this expose any such issues
For latter, if there are still any such opposing folds, we'd need to remove the colliding fold.
In any case, reproducers welcomed!
Reviewers: spatel, nikic, efriedma, xbolva00
Reviewed By: spatel
Subscribers: xbolva00, mgorny, hiraditya, reames, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D68408
2020-04-22 02:24:36 +08:00
|
|
|
; CHECK-NEXT: [[T0_NEG:%.*]] = sext i1 [[Y:%.*]] to i8
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = add i8 [[T0_NEG]], [[X:%.*]]
|
2020-04-22 01:13:57 +08:00
|
|
|
; CHECK-NEXT: ret i8 [[T1]]
|
|
|
|
;
|
|
|
|
%t0 = zext i1 %y to i8
|
|
|
|
%t1 = sub i8 %x, %t0
|
|
|
|
ret i8 %t1
|
|
|
|
}
|
|
|
|
define i8 @negate_sext_extrause(i8 %x, i1 %y) {
|
|
|
|
; CHECK-LABEL: @negate_sext_extrause(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = sext i1 [[Y:%.*]] to i8
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T0]])
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = sub i8 [[X:%.*]], [[T0]]
|
|
|
|
; CHECK-NEXT: ret i8 [[T1]]
|
|
|
|
;
|
|
|
|
%t0 = sext i1 %y to i8
|
|
|
|
call void @use8(i8 %t0)
|
|
|
|
%t1 = sub i8 %x, %t0
|
|
|
|
ret i8 %t1
|
|
|
|
}
|
|
|
|
define i8 @negate_zext_extrause(i8 %x, i1 %y) {
|
|
|
|
; CHECK-LABEL: @negate_zext_extrause(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = zext i1 [[Y:%.*]] to i8
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T0]])
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = sub i8 [[X:%.*]], [[T0]]
|
|
|
|
; CHECK-NEXT: ret i8 [[T1]]
|
|
|
|
;
|
|
|
|
%t0 = zext i1 %y to i8
|
|
|
|
call void @use8(i8 %t0)
|
|
|
|
%t1 = sub i8 %x, %t0
|
|
|
|
ret i8 %t1
|
|
|
|
}
|
|
|
|
define i8 @negate_sext_wrongwidth(i8 %x, i2 %y) {
|
|
|
|
; CHECK-LABEL: @negate_sext_wrongwidth(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = sext i2 [[Y:%.*]] to i8
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = sub i8 [[X:%.*]], [[T0]]
|
|
|
|
; CHECK-NEXT: ret i8 [[T1]]
|
|
|
|
;
|
|
|
|
%t0 = sext i2 %y to i8
|
|
|
|
%t1 = sub i8 %x, %t0
|
|
|
|
ret i8 %t1
|
|
|
|
}
|
|
|
|
define i8 @negate_zext_wrongwidth(i8 %x, i2 %y) {
|
|
|
|
; CHECK-LABEL: @negate_zext_wrongwidth(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = zext i2 [[Y:%.*]] to i8
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = sub i8 [[X:%.*]], [[T0]]
|
|
|
|
; CHECK-NEXT: ret i8 [[T1]]
|
|
|
|
;
|
|
|
|
%t0 = zext i2 %y to i8
|
|
|
|
%t1 = sub i8 %x, %t0
|
|
|
|
ret i8 %t1
|
|
|
|
}
|
2020-04-22 19:57:57 +08:00
|
|
|
|
|
|
|
define <2 x i4> @negate_shufflevector_oneinput_reverse(<2 x i4> %x, <2 x i4> %y) {
|
|
|
|
; CHECK-LABEL: @negate_shufflevector_oneinput_reverse(
|
2020-04-22 19:58:39 +08:00
|
|
|
; CHECK-NEXT: [[T0_NEG:%.*]] = shl <2 x i4> <i4 6, i4 -5>, [[X:%.*]]
|
|
|
|
; CHECK-NEXT: [[T1_NEG:%.*]] = shufflevector <2 x i4> [[T0_NEG]], <2 x i4> undef, <2 x i32> <i32 1, i32 0>
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = add <2 x i4> [[T1_NEG]], [[Y:%.*]]
|
2020-04-22 19:57:57 +08:00
|
|
|
; CHECK-NEXT: ret <2 x i4> [[T2]]
|
|
|
|
;
|
|
|
|
%t0 = shl <2 x i4> <i4 -6, i4 5>, %x
|
|
|
|
%t1 = shufflevector <2 x i4> %t0, <2 x i4> undef, <2 x i32> <i32 1, i32 0>
|
|
|
|
%t2 = sub <2 x i4> %y, %t1
|
|
|
|
ret <2 x i4> %t2
|
|
|
|
}
|
|
|
|
define <2 x i4> @negate_shufflevector_oneinput_second_lane_is_undef(<2 x i4> %x, <2 x i4> %y) {
|
|
|
|
; CHECK-LABEL: @negate_shufflevector_oneinput_second_lane_is_undef(
|
2020-04-22 19:58:39 +08:00
|
|
|
; CHECK-NEXT: [[T0_NEG:%.*]] = shl <2 x i4> <i4 6, i4 -5>, [[X:%.*]]
|
|
|
|
; CHECK-NEXT: [[T1_NEG:%.*]] = shufflevector <2 x i4> [[T0_NEG]], <2 x i4> undef, <2 x i32> <i32 0, i32 undef>
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = add <2 x i4> [[T1_NEG]], [[Y:%.*]]
|
2020-04-22 19:57:57 +08:00
|
|
|
; CHECK-NEXT: ret <2 x i4> [[T2]]
|
|
|
|
;
|
|
|
|
%t0 = shl <2 x i4> <i4 -6, i4 5>, %x
|
|
|
|
%t1 = shufflevector <2 x i4> %t0, <2 x i4> undef, <2 x i32> <i32 0, i32 2>
|
|
|
|
%t2 = sub <2 x i4> %y, %t1
|
|
|
|
ret <2 x i4> %t2
|
|
|
|
}
|
|
|
|
define <2 x i4> @negate_shufflevector_twoinputs(<2 x i4> %x, <2 x i4> %y, <2 x i4> %z) {
|
|
|
|
; CHECK-LABEL: @negate_shufflevector_twoinputs(
|
2020-04-22 19:58:39 +08:00
|
|
|
; CHECK-NEXT: [[T0_NEG:%.*]] = shl <2 x i4> <i4 6, i4 -5>, [[X:%.*]]
|
|
|
|
; CHECK-NEXT: [[T1_NEG:%.*]] = add <2 x i4> [[Y:%.*]], <i4 undef, i4 1>
|
|
|
|
; CHECK-NEXT: [[T2_NEG:%.*]] = shufflevector <2 x i4> [[T0_NEG]], <2 x i4> [[T1_NEG]], <2 x i32> <i32 0, i32 3>
|
|
|
|
; CHECK-NEXT: [[T3:%.*]] = add <2 x i4> [[T2_NEG]], [[Z:%.*]]
|
2020-04-22 19:57:57 +08:00
|
|
|
; CHECK-NEXT: ret <2 x i4> [[T3]]
|
|
|
|
;
|
|
|
|
%t0 = shl <2 x i4> <i4 -6, i4 5>, %x
|
|
|
|
%t1 = xor <2 x i4> %y, <i4 -1, i4 -1>
|
|
|
|
%t2 = shufflevector <2 x i4> %t0, <2 x i4> %t1, <2 x i32> <i32 0, i32 3>
|
|
|
|
%t3 = sub <2 x i4> %z, %t2
|
|
|
|
ret <2 x i4> %t3
|
|
|
|
}
|
|
|
|
define <2 x i4> @negate_shufflevector_oneinput_extrause(<2 x i4> %x, <2 x i4> %y) {
|
|
|
|
; CHECK-LABEL: @negate_shufflevector_oneinput_extrause(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = shl <2 x i4> <i4 -6, i4 5>, [[X:%.*]]
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = shufflevector <2 x i4> [[T0]], <2 x i4> undef, <2 x i32> <i32 1, i32 0>
|
|
|
|
; CHECK-NEXT: call void @use_v2i4(<2 x i4> [[T1]])
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = sub <2 x i4> [[Y:%.*]], [[T1]]
|
|
|
|
; CHECK-NEXT: ret <2 x i4> [[T2]]
|
|
|
|
;
|
|
|
|
%t0 = shl <2 x i4> <i4 -6, i4 5>, %x
|
|
|
|
%t1 = shufflevector <2 x i4> %t0, <2 x i4> undef, <2 x i32> <i32 1, i32 0>
|
|
|
|
call void @use_v2i4(<2 x i4> %t1)
|
|
|
|
%t2 = sub <2 x i4> %y, %t1
|
|
|
|
ret <2 x i4> %t2
|
|
|
|
}
|
2020-04-22 22:30:58 +08:00
|
|
|
|
|
|
|
; zext of non-negative can be negated
|
|
|
|
; sext of non-positive can be negated
|
|
|
|
define i16 @negation_of_zeroext_of_nonnegative(i8 %x) {
|
|
|
|
; CHECK-LABEL: @negation_of_zeroext_of_nonnegative(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = sub i8 0, [[X:%.*]]
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = icmp sgt i8 [[T0]], -1
|
|
|
|
; CHECK-NEXT: br i1 [[T1]], label [[NONNEG_BB:%.*]], label [[NEG_BB:%.*]]
|
|
|
|
; CHECK: nonneg_bb:
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = zext i8 [[T0]] to i16
|
|
|
|
; CHECK-NEXT: [[T3:%.*]] = sub nsw i16 0, [[T2]]
|
|
|
|
; CHECK-NEXT: ret i16 [[T3]]
|
|
|
|
; CHECK: neg_bb:
|
|
|
|
; CHECK-NEXT: ret i16 0
|
|
|
|
;
|
|
|
|
%t0 = sub i8 0, %x
|
|
|
|
%t1 = icmp sge i8 %t0, 0
|
|
|
|
br i1 %t1, label %nonneg_bb, label %neg_bb
|
|
|
|
|
|
|
|
nonneg_bb:
|
|
|
|
%t2 = zext i8 %t0 to i16
|
|
|
|
%t3 = sub i16 0, %t2
|
|
|
|
ret i16 %t3
|
|
|
|
|
|
|
|
neg_bb:
|
|
|
|
ret i16 0
|
|
|
|
}
|
|
|
|
define i16 @negation_of_zeroext_of_positive(i8 %x) {
|
|
|
|
; CHECK-LABEL: @negation_of_zeroext_of_positive(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = sub i8 0, [[X:%.*]]
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = icmp sgt i8 [[T0]], 0
|
|
|
|
; CHECK-NEXT: br i1 [[T1]], label [[NONNEG_BB:%.*]], label [[NEG_BB:%.*]]
|
|
|
|
; CHECK: nonneg_bb:
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = zext i8 [[T0]] to i16
|
|
|
|
; CHECK-NEXT: [[T3:%.*]] = sub nsw i16 0, [[T2]]
|
|
|
|
; CHECK-NEXT: ret i16 [[T3]]
|
|
|
|
; CHECK: neg_bb:
|
|
|
|
; CHECK-NEXT: ret i16 0
|
|
|
|
;
|
|
|
|
%t0 = sub i8 0, %x
|
|
|
|
%t1 = icmp sgt i8 %t0, 0
|
|
|
|
br i1 %t1, label %nonneg_bb, label %neg_bb
|
|
|
|
|
|
|
|
nonneg_bb:
|
|
|
|
%t2 = zext i8 %t0 to i16
|
|
|
|
%t3 = sub i16 0, %t2
|
|
|
|
ret i16 %t3
|
|
|
|
|
|
|
|
neg_bb:
|
|
|
|
ret i16 0
|
|
|
|
}
|
|
|
|
define i16 @negation_of_signext_of_negative(i8 %x) {
|
|
|
|
; CHECK-LABEL: @negation_of_signext_of_negative(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = sub i8 0, [[X:%.*]]
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = icmp slt i8 [[T0]], 0
|
|
|
|
; CHECK-NEXT: br i1 [[T1]], label [[NEG_BB:%.*]], label [[NONNEG_BB:%.*]]
|
|
|
|
; CHECK: neg_bb:
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = sext i8 [[T0]] to i16
|
|
|
|
; CHECK-NEXT: [[T3:%.*]] = sub nsw i16 0, [[T2]]
|
|
|
|
; CHECK-NEXT: ret i16 [[T3]]
|
|
|
|
; CHECK: nonneg_bb:
|
|
|
|
; CHECK-NEXT: ret i16 0
|
|
|
|
;
|
|
|
|
%t0 = sub i8 0, %x
|
|
|
|
%t1 = icmp slt i8 %t0, 0
|
|
|
|
br i1 %t1, label %neg_bb, label %nonneg_bb
|
|
|
|
|
|
|
|
neg_bb:
|
|
|
|
%t2 = sext i8 %t0 to i16
|
|
|
|
%t3 = sub i16 0, %t2
|
|
|
|
ret i16 %t3
|
|
|
|
|
|
|
|
nonneg_bb:
|
|
|
|
ret i16 0
|
|
|
|
}
|
|
|
|
define i16 @negation_of_signext_of_nonpositive(i8 %x) {
|
|
|
|
; CHECK-LABEL: @negation_of_signext_of_nonpositive(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = sub i8 0, [[X:%.*]]
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = icmp slt i8 [[T0]], 1
|
|
|
|
; CHECK-NEXT: br i1 [[T1]], label [[NEG_BB:%.*]], label [[NONNEG_BB:%.*]]
|
|
|
|
; CHECK: neg_bb:
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = sext i8 [[T0]] to i16
|
|
|
|
; CHECK-NEXT: [[T3:%.*]] = sub nsw i16 0, [[T2]]
|
|
|
|
; CHECK-NEXT: ret i16 [[T3]]
|
|
|
|
; CHECK: nonneg_bb:
|
|
|
|
; CHECK-NEXT: ret i16 0
|
|
|
|
;
|
|
|
|
%t0 = sub i8 0, %x
|
|
|
|
%t1 = icmp sle i8 %t0, 0
|
|
|
|
br i1 %t1, label %neg_bb, label %nonneg_bb
|
|
|
|
|
|
|
|
neg_bb:
|
|
|
|
%t2 = sext i8 %t0 to i16
|
|
|
|
%t3 = sub i16 0, %t2
|
|
|
|
ret i16 %t3
|
|
|
|
|
|
|
|
nonneg_bb:
|
|
|
|
ret i16 0
|
|
|
|
}
|
|
|
|
define i16 @negation_of_signext_of_nonnegative__wrong_cast(i8 %x) {
|
|
|
|
; CHECK-LABEL: @negation_of_signext_of_nonnegative__wrong_cast(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = sub i8 0, [[X:%.*]]
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = icmp sgt i8 [[T0]], -1
|
|
|
|
; CHECK-NEXT: br i1 [[T1]], label [[NONNEG_BB:%.*]], label [[NEG_BB:%.*]]
|
|
|
|
; CHECK: nonneg_bb:
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = sext i8 [[T0]] to i16
|
|
|
|
; CHECK-NEXT: [[T3:%.*]] = sub nsw i16 0, [[T2]]
|
|
|
|
; CHECK-NEXT: ret i16 [[T3]]
|
|
|
|
; CHECK: neg_bb:
|
|
|
|
; CHECK-NEXT: ret i16 0
|
|
|
|
;
|
|
|
|
%t0 = sub i8 0, %x
|
|
|
|
%t1 = icmp sge i8 %t0, 0
|
|
|
|
br i1 %t1, label %nonneg_bb, label %neg_bb
|
|
|
|
|
|
|
|
nonneg_bb:
|
|
|
|
%t2 = sext i8 %t0 to i16
|
|
|
|
%t3 = sub i16 0, %t2
|
|
|
|
ret i16 %t3
|
|
|
|
|
|
|
|
neg_bb:
|
|
|
|
ret i16 0
|
|
|
|
}
|
|
|
|
define i16 @negation_of_zeroext_of_negative_wrongcast(i8 %x) {
|
|
|
|
; CHECK-LABEL: @negation_of_zeroext_of_negative_wrongcast(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = sub i8 0, [[X:%.*]]
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = icmp slt i8 [[T0]], 0
|
|
|
|
; CHECK-NEXT: br i1 [[T1]], label [[NEG_BB:%.*]], label [[NONNEG_BB:%.*]]
|
|
|
|
; CHECK: neg_bb:
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = zext i8 [[T0]] to i16
|
|
|
|
; CHECK-NEXT: [[T3:%.*]] = sub nsw i16 0, [[T2]]
|
|
|
|
; CHECK-NEXT: ret i16 [[T3]]
|
|
|
|
; CHECK: nonneg_bb:
|
|
|
|
; CHECK-NEXT: ret i16 0
|
|
|
|
;
|
|
|
|
%t0 = sub i8 0, %x
|
|
|
|
%t1 = icmp slt i8 %t0, 0
|
|
|
|
br i1 %t1, label %neg_bb, label %nonneg_bb
|
|
|
|
|
|
|
|
neg_bb:
|
|
|
|
%t2 = zext i8 %t0 to i16
|
|
|
|
%t3 = sub i16 0, %t2
|
|
|
|
ret i16 %t3
|
|
|
|
|
|
|
|
nonneg_bb:
|
|
|
|
ret i16 0
|
|
|
|
}
|
2020-04-28 18:07:39 +08:00
|
|
|
|
|
|
|
; 'or' of 1 and operand with no lowest bit set is 'inc'
|
|
|
|
define i8 @negation_of_increment_via_or_with_no_common_bits_set(i8 %x, i8 %y) {
|
|
|
|
; CHECK-LABEL: @negation_of_increment_via_or_with_no_common_bits_set(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = shl i8 [[Y:%.*]], 1
|
2020-04-28 18:20:04 +08:00
|
|
|
; CHECK-NEXT: [[T1_NEG:%.*]] = xor i8 [[T0]], -1
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = add i8 [[T1_NEG]], [[X:%.*]]
|
2020-04-28 18:07:39 +08:00
|
|
|
; CHECK-NEXT: ret i8 [[T2]]
|
|
|
|
;
|
|
|
|
%t0 = shl i8 %y, 1
|
|
|
|
%t1 = or i8 %t0, 1
|
|
|
|
%t2 = sub i8 %x, %t1
|
|
|
|
ret i8 %t2
|
|
|
|
}
|
|
|
|
define i8 @negation_of_increment_via_or_with_no_common_bits_set_extrause(i8 %x, i8 %y) {
|
|
|
|
; CHECK-LABEL: @negation_of_increment_via_or_with_no_common_bits_set_extrause(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = shl i8 [[Y:%.*]], 1
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = or i8 [[T0]], 1
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T1]])
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = sub i8 [[X:%.*]], [[T1]]
|
|
|
|
; CHECK-NEXT: ret i8 [[T2]]
|
|
|
|
;
|
|
|
|
%t0 = shl i8 %y, 1
|
|
|
|
%t1 = or i8 %t0, 1
|
|
|
|
call void @use8(i8 %t1)
|
|
|
|
%t2 = sub i8 %x, %t1
|
|
|
|
ret i8 %t2
|
|
|
|
}
|
|
|
|
define i8 @negation_of_increment_via_or_common_bits_set(i8 %x, i8 %y) {
|
|
|
|
; CHECK-LABEL: @negation_of_increment_via_or_common_bits_set(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = shl i8 [[Y:%.*]], 1
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = or i8 [[T0]], 3
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = sub i8 [[X:%.*]], [[T1]]
|
|
|
|
; CHECK-NEXT: ret i8 [[T2]]
|
|
|
|
;
|
|
|
|
%t0 = shl i8 %y, 1
|
|
|
|
%t1 = or i8 %t0, 3
|
|
|
|
%t2 = sub i8 %x, %t1
|
|
|
|
ret i8 %t2
|
|
|
|
}
|
|
|
|
|
|
|
|
; 'or' of operands with no common bits set is 'add'
|
|
|
|
define i8 @add_via_or_with_no_common_bits_set(i8 %x, i8 %y) {
|
|
|
|
; CHECK-LABEL: @add_via_or_with_no_common_bits_set(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = sub i8 0, [[Y:%.*]]
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T0]])
|
2020-04-28 18:20:04 +08:00
|
|
|
; CHECK-NEXT: [[T1_NEG:%.*]] = shl i8 [[Y]], 2
|
|
|
|
; CHECK-NEXT: [[T2_NEG:%.*]] = add i8 [[T1_NEG]], -3
|
|
|
|
; CHECK-NEXT: [[T3:%.*]] = add i8 [[T2_NEG]], [[X:%.*]]
|
2020-04-28 18:07:39 +08:00
|
|
|
; CHECK-NEXT: ret i8 [[T3]]
|
|
|
|
;
|
|
|
|
%t0 = sub i8 0, %y
|
|
|
|
call void @use8(i8 %t0)
|
|
|
|
%t1 = shl i8 %t0, 2
|
|
|
|
%t2 = or i8 %t1, 3
|
|
|
|
%t3 = sub i8 %x, %t2
|
|
|
|
ret i8 %t3
|
|
|
|
}
|
|
|
|
define i8 @add_via_or_with_common_bit_maybe_set(i8 %x, i8 %y) {
|
|
|
|
; CHECK-LABEL: @add_via_or_with_common_bit_maybe_set(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = sub i8 0, [[Y:%.*]]
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T0]])
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = shl i8 [[T0]], 2
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = or i8 [[T1]], 4
|
|
|
|
; CHECK-NEXT: [[T3:%.*]] = sub i8 [[X:%.*]], [[T2]]
|
|
|
|
; CHECK-NEXT: ret i8 [[T3]]
|
|
|
|
;
|
|
|
|
%t0 = sub i8 0, %y
|
|
|
|
call void @use8(i8 %t0)
|
|
|
|
%t1 = shl i8 %t0, 2
|
|
|
|
%t2 = or i8 %t1, 4
|
|
|
|
%t3 = sub i8 %x, %t2
|
|
|
|
ret i8 %t3
|
|
|
|
}
|
|
|
|
define i8 @add_via_or_with_no_common_bits_set_extrause(i8 %x, i8 %y) {
|
|
|
|
; CHECK-LABEL: @add_via_or_with_no_common_bits_set_extrause(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = sub i8 0, [[Y:%.*]]
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T0]])
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = shl i8 [[T0]], 2
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = or i8 [[T1]], 3
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T2]])
|
|
|
|
; CHECK-NEXT: [[T3:%.*]] = sub i8 [[X:%.*]], [[T2]]
|
|
|
|
; CHECK-NEXT: ret i8 [[T3]]
|
|
|
|
;
|
|
|
|
%t0 = sub i8 0, %y
|
|
|
|
call void @use8(i8 %t0)
|
|
|
|
%t1 = shl i8 %t0, 2
|
|
|
|
%t2 = or i8 %t1, 3
|
|
|
|
call void @use8(i8 %t2)
|
|
|
|
%t3 = sub i8 %x, %t2
|
|
|
|
ret i8 %t3
|
|
|
|
}
|
2020-05-21 01:54:06 +08:00
|
|
|
|
|
|
|
; `extractelement` is negatible if source operand is negatible.
|
|
|
|
define i4 @negate_extractelement(<2 x i4> %x, i32 %y, i4 %z) {
|
|
|
|
; CHECK-LABEL: @negate_extractelement(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = sub <2 x i4> zeroinitializer, [[X:%.*]]
|
|
|
|
; CHECK-NEXT: call void @use_v2i4(<2 x i4> [[T0]])
|
[InstCombine] Negator: `extractelement` is negatible if src is negatible
----------------------------------------
define i4 @negate_extractelement(<2 x i4> %x, i32 %y, i4 %z) {
%0:
%t0 = sub <2 x i4> { 0, 0 }, %x
call void @use_v2i4(<2 x i4> %t0)
%t1 = extractelement <2 x i4> %t0, i32 %y
%t2 = sub i4 %z, %t1
ret i4 %t2
}
=>
define i4 @negate_extractelement(<2 x i4> %x, i32 %y, i4 %z) {
%0:
%t0 = sub <2 x i4> { 0, 0 }, %x
call void @use_v2i4(<2 x i4> %t0)
%t1.neg = extractelement <2 x i4> %x, i32 %y
%t2 = add i4 %t1.neg, %z
ret i4 %t2
}
Transformation seems to be correct!
2020-05-21 02:01:28 +08:00
|
|
|
; CHECK-NEXT: [[T1_NEG:%.*]] = extractelement <2 x i4> [[X]], i32 [[Y:%.*]]
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = add i4 [[T1_NEG]], [[Z:%.*]]
|
2020-05-21 01:54:06 +08:00
|
|
|
; CHECK-NEXT: ret i4 [[T2]]
|
|
|
|
;
|
|
|
|
%t0 = sub <2 x i4> zeroinitializer, %x
|
|
|
|
call void @use_v2i4(<2 x i4> %t0)
|
|
|
|
%t1 = extractelement <2 x i4> %t0, i32 %y
|
|
|
|
%t2 = sub i4 %z, %t1
|
|
|
|
ret i4 %t2
|
|
|
|
}
|
|
|
|
define i4 @negate_extractelement_extrause(<2 x i4> %x, i32 %y, i4 %z) {
|
|
|
|
; CHECK-LABEL: @negate_extractelement_extrause(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = sub <2 x i4> zeroinitializer, [[X:%.*]]
|
|
|
|
; CHECK-NEXT: call void @use_v2i4(<2 x i4> [[T0]])
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = extractelement <2 x i4> [[T0]], i32 [[Y:%.*]]
|
|
|
|
; CHECK-NEXT: call void @use4(i4 [[T1]])
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = sub i4 [[Z:%.*]], [[T1]]
|
|
|
|
; CHECK-NEXT: ret i4 [[T2]]
|
|
|
|
;
|
|
|
|
%t0 = sub <2 x i4> zeroinitializer, %x
|
|
|
|
call void @use_v2i4(<2 x i4> %t0)
|
|
|
|
%t1 = extractelement <2 x i4> %t0, i32 %y
|
|
|
|
call void @use4(i4 %t1)
|
|
|
|
%t2 = sub i4 %z, %t1
|
|
|
|
ret i4 %t2
|
|
|
|
}
|
2020-05-21 02:16:57 +08:00
|
|
|
|
|
|
|
; `insertelement` is negatible if both source vector and element-to-be-inserted are negatible.
|
|
|
|
define <2 x i4> @negate_insertelement(<2 x i4> %src, i4 %a, i32 %x, <2 x i4> %b) {
|
|
|
|
; CHECK-LABEL: @negate_insertelement(
|
[InstCombine] `insertelement` is negatible if both sources are negatible
----------------------------------------
define <2 x i4> @negate_insertelement(<2 x i4> %src, i4 %a, i32 %x, <2 x i4> %b) {
%0:
%t0 = sub <2 x i4> { 0, 0 }, %src
%t1 = sub i4 0, %a
%t2 = insertelement <2 x i4> %t0, i4 %t1, i32 %x
%t3 = sub <2 x i4> %b, %t2
ret <2 x i4> %t3
}
=>
define <2 x i4> @negate_insertelement(<2 x i4> %src, i4 %a, i32 %x, <2 x i4> %b) {
%0:
%t2.neg = insertelement <2 x i4> %src, i4 %a, i32 %x
%t3 = add <2 x i4> %t2.neg, %b
ret <2 x i4> %t3
}
Transformation seems to be correct!
2020-05-21 02:37:02 +08:00
|
|
|
; CHECK-NEXT: [[T2_NEG:%.*]] = insertelement <2 x i4> [[SRC:%.*]], i4 [[A:%.*]], i32 [[X:%.*]]
|
|
|
|
; CHECK-NEXT: [[T3:%.*]] = add <2 x i4> [[T2_NEG]], [[B:%.*]]
|
2020-05-21 02:16:57 +08:00
|
|
|
; CHECK-NEXT: ret <2 x i4> [[T3]]
|
|
|
|
;
|
|
|
|
%t0 = sub <2 x i4> zeroinitializer, %src
|
|
|
|
%t1 = sub i4 zeroinitializer, %a
|
|
|
|
%t2 = insertelement <2 x i4> %t0, i4 %t1, i32 %x
|
|
|
|
%t3 = sub <2 x i4> %b, %t2
|
|
|
|
ret <2 x i4> %t3
|
|
|
|
}
|
|
|
|
define <2 x i4> @negate_insertelement_extrause(<2 x i4> %src, i4 %a, i32 %x, <2 x i4> %b) {
|
|
|
|
; CHECK-LABEL: @negate_insertelement_extrause(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = sub <2 x i4> zeroinitializer, [[SRC:%.*]]
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = sub i4 0, [[A:%.*]]
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = insertelement <2 x i4> [[T0]], i4 [[T1]], i32 [[X:%.*]]
|
|
|
|
; CHECK-NEXT: call void @use_v2i4(<2 x i4> [[T2]])
|
|
|
|
; CHECK-NEXT: [[T3:%.*]] = sub <2 x i4> [[B:%.*]], [[T2]]
|
|
|
|
; CHECK-NEXT: ret <2 x i4> [[T3]]
|
|
|
|
;
|
|
|
|
%t0 = sub <2 x i4> zeroinitializer, %src
|
|
|
|
%t1 = sub i4 zeroinitializer, %a
|
|
|
|
%t2 = insertelement <2 x i4> %t0, i4 %t1, i32 %x
|
|
|
|
call void @use_v2i4(<2 x i4> %t2)
|
|
|
|
%t3 = sub <2 x i4> %b, %t2
|
|
|
|
ret <2 x i4> %t3
|
|
|
|
}
|
|
|
|
define <2 x i4> @negate_insertelement_nonnegatible_base(<2 x i4> %src, i4 %a, i32 %x, <2 x i4> %b) {
|
|
|
|
; CHECK-LABEL: @negate_insertelement_nonnegatible_base(
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = sub i4 0, [[A:%.*]]
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = insertelement <2 x i4> [[SRC:%.*]], i4 [[T1]], i32 [[X:%.*]]
|
|
|
|
; CHECK-NEXT: [[T3:%.*]] = sub <2 x i4> [[B:%.*]], [[T2]]
|
|
|
|
; CHECK-NEXT: ret <2 x i4> [[T3]]
|
|
|
|
;
|
|
|
|
%t1 = sub i4 zeroinitializer, %a
|
|
|
|
%t2 = insertelement <2 x i4> %src, i4 %t1, i32 %x
|
|
|
|
%t3 = sub <2 x i4> %b, %t2
|
|
|
|
ret <2 x i4> %t3
|
|
|
|
}
|
|
|
|
define <2 x i4> @negate_insertelement_nonnegatible_insert(<2 x i4> %src, i4 %a, i32 %x, <2 x i4> %b) {
|
|
|
|
; CHECK-LABEL: @negate_insertelement_nonnegatible_insert(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = sub <2 x i4> zeroinitializer, [[SRC:%.*]]
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = insertelement <2 x i4> [[T0]], i4 [[A:%.*]], i32 [[X:%.*]]
|
|
|
|
; CHECK-NEXT: [[T3:%.*]] = sub <2 x i4> [[B:%.*]], [[T2]]
|
|
|
|
; CHECK-NEXT: ret <2 x i4> [[T3]]
|
|
|
|
;
|
|
|
|
%t0 = sub <2 x i4> zeroinitializer, %src
|
|
|
|
%t2 = insertelement <2 x i4> %t0, i4 %a, i32 %x
|
|
|
|
%t3 = sub <2 x i4> %b, %t2
|
|
|
|
ret <2 x i4> %t3
|
|
|
|
}
|
2020-08-05 06:52:57 +08:00
|
|
|
|
|
|
|
; left-shift by constant can always be negated
|
|
|
|
define i8 @negate_left_shift_by_constant_prefer_keeping_shl(i8 %x, i8 %y, i8 %z) {
|
|
|
|
; CHECK-LABEL: @negate_left_shift_by_constant_prefer_keeping_shl(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = sub i8 0, [[Z:%.*]]
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T0]])
|
|
|
|
; CHECK-NEXT: [[T1_NEG:%.*]] = shl i8 [[Z]], 4
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = add i8 [[T1_NEG]], [[X:%.*]]
|
|
|
|
; CHECK-NEXT: ret i8 [[T2]]
|
|
|
|
;
|
|
|
|
%t0 = sub i8 0, %z
|
|
|
|
call void @use8(i8 %t0)
|
|
|
|
%t1 = shl i8 %t0, 4
|
|
|
|
%t2 = sub i8 %x, %t1
|
|
|
|
ret i8 %t2
|
|
|
|
}
|
|
|
|
define i8 @negate_left_shift_by_constant_prefer_keeping_shl_extrause(i8 %x, i8 %y, i8 %z) {
|
|
|
|
; CHECK-LABEL: @negate_left_shift_by_constant_prefer_keeping_shl_extrause(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = sub i8 0, [[Z:%.*]]
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T0]])
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = shl i8 [[T0]], 4
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T1]])
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = sub i8 [[X:%.*]], [[T1]]
|
|
|
|
; CHECK-NEXT: ret i8 [[T2]]
|
|
|
|
;
|
|
|
|
%t0 = sub i8 0, %z
|
|
|
|
call void @use8(i8 %t0)
|
|
|
|
%t1 = shl i8 %t0, 4
|
|
|
|
call void @use8(i8 %t1)
|
|
|
|
%t2 = sub i8 %x, %t1
|
|
|
|
ret i8 %t2
|
|
|
|
}
|
|
|
|
define i8 @negate_left_shift_by_constant(i8 %x, i8 %y, i8 %z, i8 %k) {
|
|
|
|
; CHECK-LABEL: @negate_left_shift_by_constant(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = sub i8 [[K:%.*]], [[Z:%.*]]
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T0]])
|
2020-08-05 19:55:29 +08:00
|
|
|
; CHECK-NEXT: [[T1_NEG:%.*]] = mul i8 [[T0]], -16
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = add i8 [[T1_NEG]], [[X:%.*]]
|
2020-08-05 06:52:57 +08:00
|
|
|
; CHECK-NEXT: ret i8 [[T2]]
|
|
|
|
;
|
|
|
|
%t0 = sub i8 %k, %z
|
|
|
|
call void @use8(i8 %t0)
|
|
|
|
%t1 = shl i8 %t0, 4
|
|
|
|
%t2 = sub i8 %x, %t1
|
|
|
|
ret i8 %t2
|
|
|
|
}
|
|
|
|
define i8 @negate_left_shift_by_constant_extrause(i8 %x, i8 %y, i8 %z, i8 %k) {
|
|
|
|
; CHECK-LABEL: @negate_left_shift_by_constant_extrause(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = sub i8 [[K:%.*]], [[Z:%.*]]
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T0]])
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = shl i8 [[T0]], 4
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T1]])
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = sub i8 [[X:%.*]], [[T1]]
|
|
|
|
; CHECK-NEXT: ret i8 [[T2]]
|
|
|
|
;
|
|
|
|
%t0 = sub i8 %k, %z
|
|
|
|
call void @use8(i8 %t0)
|
|
|
|
%t1 = shl i8 %t0, 4
|
|
|
|
call void @use8(i8 %t1)
|
|
|
|
%t2 = sub i8 %x, %t1
|
|
|
|
ret i8 %t2
|
|
|
|
}
|
2020-08-06 00:06:40 +08:00
|
|
|
|
|
|
|
; `add` with single negatible operand is still negatible
|
|
|
|
define i8 @negate_add_with_single_negatible_operand(i8 %x, i8 %y) {
|
|
|
|
; CHECK-LABEL: @negate_add_with_single_negatible_operand(
|
2020-08-06 00:17:56 +08:00
|
|
|
; CHECK-NEXT: [[T0_NEG:%.*]] = sub i8 -42, [[X:%.*]]
|
|
|
|
; CHECK-NEXT: ret i8 [[T0_NEG]]
|
2020-08-06 00:06:40 +08:00
|
|
|
;
|
|
|
|
%t0 = add i8 %x, 42
|
|
|
|
%t1 = sub i8 0, %t0
|
|
|
|
ret i8 %t1
|
|
|
|
}
|
|
|
|
define i8 @negate_add_with_single_negatible_operand_extrause(i8 %x, i8 %y) {
|
|
|
|
; CHECK-LABEL: @negate_add_with_single_negatible_operand_extrause(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = add i8 [[X:%.*]], 42
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T0]])
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = sub i8 0, [[T0]]
|
|
|
|
; CHECK-NEXT: ret i8 [[T1]]
|
|
|
|
;
|
|
|
|
%t0 = add i8 %x, 42
|
|
|
|
call void @use8(i8 %t0)
|
|
|
|
%t1 = sub i8 0, %t0
|
|
|
|
ret i8 %t1
|
|
|
|
}
|
2020-08-06 00:17:56 +08:00
|
|
|
; But don't do this if that means just sinking the negation.
|
2020-08-06 00:06:40 +08:00
|
|
|
define i8 @negate_add_with_single_negatible_operand_non_negation(i8 %x, i8 %y) {
|
|
|
|
; CHECK-LABEL: @negate_add_with_single_negatible_operand_non_negation(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = add i8 [[X:%.*]], 42
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = sub i8 [[Y:%.*]], [[T0]]
|
|
|
|
; CHECK-NEXT: ret i8 [[T1]]
|
|
|
|
;
|
|
|
|
%t0 = add i8 %x, 42
|
|
|
|
%t1 = sub i8 %y, %t0
|
|
|
|
ret i8 %t1
|
|
|
|
}
|
2020-08-06 02:16:20 +08:00
|
|
|
|
|
|
|
; abs/nabs can be negated
|
|
|
|
define i8 @negate_abs(i8 %x, i8 %y) {
|
|
|
|
; CHECK-LABEL: @negate_abs(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = sub i8 0, [[X:%.*]]
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T0]])
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = icmp slt i8 [[X]], 0
|
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[T1]], i8 [[X]], i8 [[T0]], !prof !0
|
|
|
|
; CHECK-NEXT: [[T3:%.*]] = add i8 [[TMP1]], [[Y:%.*]]
|
|
|
|
; CHECK-NEXT: ret i8 [[T3]]
|
|
|
|
;
|
|
|
|
%t0 = sub i8 0, %x
|
|
|
|
call void @use8(i8 %t0)
|
|
|
|
%t1 = icmp slt i8 %x, 0
|
|
|
|
%t2 = select i1 %t1, i8 %t0, i8 %x, !prof !0
|
|
|
|
%t3 = sub i8 %y, %t2
|
|
|
|
ret i8 %t3
|
|
|
|
}
|
|
|
|
define i8 @negate_nabs(i8 %x, i8 %y) {
|
|
|
|
; CHECK-LABEL: @negate_nabs(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = sub i8 0, [[X:%.*]]
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T0]])
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = icmp slt i8 [[X]], 0
|
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[T1]], i8 [[T0]], i8 [[X]], !prof !0
|
|
|
|
; CHECK-NEXT: [[T3:%.*]] = add i8 [[TMP1]], [[Y:%.*]]
|
|
|
|
; CHECK-NEXT: ret i8 [[T3]]
|
|
|
|
;
|
|
|
|
%t0 = sub i8 0, %x
|
|
|
|
call void @use8(i8 %t0)
|
|
|
|
%t1 = icmp slt i8 %x, 0
|
|
|
|
%t2 = select i1 %t1, i8 %x, i8 %t0, !prof !0
|
|
|
|
%t3 = sub i8 %y, %t2
|
|
|
|
ret i8 %t3
|
|
|
|
}
|
|
|
|
|
|
|
|
; And in general, if hands of select are known to be negation of each other,
|
|
|
|
; we can negate the select
|
|
|
|
define i8 @negate_select_of_op_vs_negated_op(i8 %x, i8 %y, i1 %c) {
|
|
|
|
; CHECK-LABEL: @negate_select_of_op_vs_negated_op(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = sub i8 0, [[X:%.*]]
|
|
|
|
; CHECK-NEXT: call void @use8(i8 [[T0]])
|
2020-08-06 02:20:47 +08:00
|
|
|
; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[C:%.*]], i8 [[X]], i8 [[T0]], !prof !0
|
|
|
|
; CHECK-NEXT: [[T2:%.*]] = add i8 [[TMP1]], [[Y:%.*]]
|
2020-08-06 02:16:20 +08:00
|
|
|
; CHECK-NEXT: ret i8 [[T2]]
|
|
|
|
;
|
|
|
|
%t0 = sub i8 0, %x
|
|
|
|
call void @use8(i8 %t0)
|
|
|
|
%t1 = select i1 %c, i8 %t0, i8 %x, !prof !0
|
|
|
|
%t2 = sub i8 %y, %t1
|
|
|
|
ret i8 %t2
|
|
|
|
}
|
|
|
|
define i8 @dont_negate_ordinary_select(i8 %x, i8 %y, i8 %z, i1 %c) {
|
|
|
|
; CHECK-LABEL: @dont_negate_ordinary_select(
|
|
|
|
; CHECK-NEXT: [[T0:%.*]] = select i1 [[C:%.*]], i8 [[X:%.*]], i8 [[Y:%.*]]
|
|
|
|
; CHECK-NEXT: [[T1:%.*]] = sub i8 [[Z:%.*]], [[T0]]
|
|
|
|
; CHECK-NEXT: ret i8 [[T1]]
|
|
|
|
;
|
|
|
|
%t0 = select i1 %c, i8 %x, i8 %y
|
|
|
|
%t1 = sub i8 %z, %t0
|
|
|
|
ret i8 %t1
|
|
|
|
}
|
|
|
|
|
|
|
|
; CHECK: !0 = !{!"branch_weights", i32 40, i32 1}
|
|
|
|
!0 = !{!"branch_weights", i32 40, i32 1}
|