-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[InstCombine] Replace an integer comparison of a phi
node with multiple ucmp
/scmp
operands and a constant with phi
of individual comparisons of original intrinsic's arguments
#107769
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
6f7fa77
c3424e7
833e168
bbeded8
3a8efdf
a7a2930
b5fe2cc
45157a8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you please also add negative tests where one scmp is not one-use or the icmp operand is not constant? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The case you're proposing would still actually enable this optimization since we can still move the |
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any tests where only 1 of the incoming values is an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added one |
||
} |
Uh oh!
There was an error while loading. Please reload this page.