-
Notifications
You must be signed in to change notification settings - Fork 11.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[InstCombine] Replace an integer comparison of a
phi
node with mult…
…iple `ucmp`/`scmp` operands and a constant with `phi` of individual comparisons of original intrinsic's arguments (#107769) When we have a `phi` instruction with more than one of its incoming values being a call to `ucmp` or `scmp`, which is then compared with an integer constant, we can move the comparison through the `phi` into the incoming basic blocks because we know that a comparison of `ucmp`/`scmp` with a constant will be simplified by the next iteration of InstCombine. There's a high chance that other similar patterns can be identified, in which case they can be easily handled by the same code by moving the check for "simplifiable" instructions into a lambda.
- Loading branch information
1 parent
29e5fe7
commit 21e3a21
Showing
2 changed files
with
185 additions
and
38 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
135 changes: 135 additions & 0 deletions
135
llvm/test/Transforms/InstCombine/phi-with-multiple-unsimplifiable-values.ll
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 | ||
; RUN: opt < %s -passes=instcombine -S | FileCheck %s | ||
|
||
declare void @use(i8 %value); | ||
|
||
; Since we know that any comparison of ucmp/scmp with a constant will result in | ||
; a comparison of ucmp/scmp's operands, we can propagate such a comparison | ||
; through the phi node and let the next iteration of instcombine simplify it. | ||
define i1 @icmp_of_phi_of_scmp_with_constant(i1 %c, i16 %x, i16 %y) | ||
; CHECK-LABEL: define i1 @icmp_of_phi_of_scmp_with_constant( | ||
; CHECK-SAME: i1 [[C:%.*]], i16 [[X:%.*]], i16 [[Y:%.*]]) { | ||
; CHECK-NEXT: [[ENTRY:.*:]] | ||
; CHECK-NEXT: br i1 [[C]], label %[[TRUE:.*]], label %[[FALSE:.*]] | ||
; CHECK: [[TRUE]]: | ||
; CHECK-NEXT: [[TMP0:%.*]] = icmp slt i16 [[X]], [[Y]] | ||
; CHECK-NEXT: br label %[[EXIT:.*]] | ||
; CHECK: [[FALSE]]: | ||
; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i16 [[Y]], [[X]] | ||
; CHECK-NEXT: br label %[[EXIT]] | ||
; CHECK: [[EXIT]]: | ||
; CHECK-NEXT: [[R:%.*]] = phi i1 [ [[TMP0]], %[[TRUE]] ], [ [[TMP1]], %[[FALSE]] ] | ||
; CHECK-NEXT: ret i1 [[R]] | ||
; | ||
{ | ||
entry: | ||
br i1 %c, label %true, label %false | ||
true: | ||
%cmp1 = call i8 @llvm.scmp(i16 %x, i16 %y) | ||
br label %exit | ||
false: | ||
%cmp2 = call i8 @llvm.scmp(i16 %y, i16 %x) | ||
br label %exit | ||
exit: | ||
%phi = phi i8 [%cmp1, %true], [%cmp2, %false] | ||
%r = icmp slt i8 %phi, 0 | ||
ret i1 %r | ||
} | ||
|
||
; When one of the incoming values is ucmp/scmp and the other is not we can still perform the transformation | ||
define i1 @icmp_of_phi_of_one_scmp_with_constant(i1 %c, i16 %x, i16 %y, i8 %false_val) | ||
; CHECK-LABEL: define i1 @icmp_of_phi_of_one_scmp_with_constant( | ||
; CHECK-SAME: i1 [[C:%.*]], i16 [[X:%.*]], i16 [[Y:%.*]], i8 [[FALSE_VAL:%.*]]) { | ||
; CHECK-NEXT: [[ENTRY:.*:]] | ||
; CHECK-NEXT: br i1 [[C]], label %[[TRUE:.*]], label %[[FALSE:.*]] | ||
; CHECK: [[TRUE]]: | ||
; CHECK-NEXT: [[TMP0:%.*]] = icmp slt i16 [[X]], [[Y]] | ||
; CHECK-NEXT: br label %[[EXIT:.*]] | ||
; CHECK: [[FALSE]]: | ||
; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i8 [[FALSE_VAL]], 0 | ||
; CHECK-NEXT: br label %[[EXIT]] | ||
; CHECK: [[EXIT]]: | ||
; CHECK-NEXT: [[PHI:%.*]] = phi i1 [ [[TMP0]], %[[TRUE]] ], [ [[TMP1]], %[[FALSE]] ] | ||
; CHECK-NEXT: ret i1 [[PHI]] | ||
; | ||
{ | ||
entry: | ||
br i1 %c, label %true, label %false | ||
true: | ||
%cmp1 = call i8 @llvm.scmp(i16 %x, i16 %y) | ||
br label %exit | ||
false: | ||
br label %exit | ||
exit: | ||
%phi = phi i8 [%cmp1, %true], [%false_val, %false] | ||
%r = icmp slt i8 %phi, 0 | ||
ret i1 %r | ||
} | ||
|
||
; Negative test: the RHS of comparison that uses the phi node is not constant | ||
define i1 @icmp_of_phi_of_scmp_with_non_constant(i1 %c, i16 %x, i16 %y, i8 %cmp) | ||
; CHECK-LABEL: define i1 @icmp_of_phi_of_scmp_with_non_constant( | ||
; CHECK-SAME: i1 [[C:%.*]], i16 [[X:%.*]], i16 [[Y:%.*]], i8 [[CMP:%.*]]) { | ||
; CHECK-NEXT: [[ENTRY:.*:]] | ||
; CHECK-NEXT: br i1 [[C]], label %[[TRUE:.*]], label %[[FALSE:.*]] | ||
; CHECK: [[TRUE]]: | ||
; CHECK-NEXT: [[CMP1:%.*]] = call i8 @llvm.scmp.i8.i16(i16 [[X]], i16 [[Y]]) | ||
; CHECK-NEXT: br label %[[EXIT:.*]] | ||
; CHECK: [[FALSE]]: | ||
; CHECK-NEXT: [[CMP2:%.*]] = call i8 @llvm.scmp.i8.i16(i16 [[Y]], i16 [[X]]) | ||
; CHECK-NEXT: br label %[[EXIT]] | ||
; CHECK: [[EXIT]]: | ||
; CHECK-NEXT: [[PHI:%.*]] = phi i8 [ [[CMP1]], %[[TRUE]] ], [ [[CMP2]], %[[FALSE]] ] | ||
; CHECK-NEXT: [[R:%.*]] = icmp slt i8 [[PHI]], [[CMP]] | ||
; CHECK-NEXT: ret i1 [[R]] | ||
; | ||
{ | ||
entry: | ||
br i1 %c, label %true, label %false | ||
true: | ||
%cmp1 = call i8 @llvm.scmp(i16 %x, i16 %y) | ||
br label %exit | ||
false: | ||
%cmp2 = call i8 @llvm.scmp(i16 %y, i16 %x) | ||
br label %exit | ||
exit: | ||
%phi = phi i8 [%cmp1, %true], [%cmp2, %false] | ||
%r = icmp slt i8 %phi, %cmp | ||
ret i1 %r | ||
} | ||
|
||
; Negative test: more than one incoming value of the phi node is not one-use | ||
define i1 @icmp_of_phi_of_scmp_with_constant_not_one_use(i1 %c, i16 %x, i16 %y) | ||
; CHECK-LABEL: define i1 @icmp_of_phi_of_scmp_with_constant_not_one_use( | ||
; CHECK-SAME: i1 [[C:%.*]], i16 [[X:%.*]], i16 [[Y:%.*]]) { | ||
; CHECK-NEXT: [[ENTRY:.*:]] | ||
; CHECK-NEXT: br i1 [[C]], label %[[TRUE:.*]], label %[[FALSE:.*]] | ||
; CHECK: [[TRUE]]: | ||
; CHECK-NEXT: [[CMP1:%.*]] = call i8 @llvm.scmp.i8.i16(i16 [[X]], i16 [[Y]]) | ||
; CHECK-NEXT: call void @use(i8 [[CMP1]]) | ||
; CHECK-NEXT: br label %[[EXIT:.*]] | ||
; CHECK: [[FALSE]]: | ||
; CHECK-NEXT: [[CMP2:%.*]] = call i8 @llvm.scmp.i8.i16(i16 [[Y]], i16 [[X]]) | ||
; CHECK-NEXT: call void @use(i8 [[CMP2]]) | ||
; CHECK-NEXT: br label %[[EXIT]] | ||
; CHECK: [[EXIT]]: | ||
; CHECK-NEXT: [[PHI:%.*]] = phi i8 [ [[CMP1]], %[[TRUE]] ], [ [[CMP2]], %[[FALSE]] ] | ||
; CHECK-NEXT: [[R:%.*]] = icmp slt i8 [[PHI]], 0 | ||
; CHECK-NEXT: ret i1 [[R]] | ||
; | ||
{ | ||
entry: | ||
br i1 %c, label %true, label %false | ||
true: | ||
%cmp1 = call i8 @llvm.scmp(i16 %x, i16 %y) | ||
call void @use(i8 %cmp1) | ||
br label %exit | ||
false: | ||
%cmp2 = call i8 @llvm.scmp(i16 %y, i16 %x) | ||
call void @use(i8 %cmp2) | ||
br label %exit | ||
exit: | ||
%phi = phi i8 [%cmp1, %true], [%cmp2, %false] | ||
%r = icmp slt i8 %phi, 0 | ||
ret i1 %r | ||
} |