-
Notifications
You must be signed in to change notification settings - Fork 10.8k
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
[llvm][CodeGen] Added a check in CodeGenPrepare::optimizeSwitchType #83322
base: main
Are you sure you want to change the base?
Conversation
Thank you for submitting a Pull Request (PR) to the LLVM Project! This PR will be automatically labeled and the relevant teams will be If you wish to, you can add reviewers by using the "Reviewers" section on this page. If this is not working for you, it is probably because you do not have write If you have received no comments on your PR for a week, you can request a review If you have further questions, they may be answered by the LLVM GitHub User Guide. You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums. |
✅ With the latest revision this PR passed the C/C++ code formatter. |
b3302a5
to
c680234
Compare
@llvm/pr-subscribers-backend-risc-v Author: Panagiotis K (karouzakisp) ChangesWhen we have two users in the Switch Condition and one of them is sext we need to check to not insert a sext and not a zext into the switch condition Type. This creates an additional instruction on RISC-V Full diff: https://github.com/llvm/llvm-project/pull/83322.diff 2 Files Affected:
diff --git a/llvm/lib/CodeGen/CodeGenPrepare.cpp b/llvm/lib/CodeGen/CodeGenPrepare.cpp
index feefe87f406365..82b02fa6216306 100644
--- a/llvm/lib/CodeGen/CodeGenPrepare.cpp
+++ b/llvm/lib/CodeGen/CodeGenPrepare.cpp
@@ -7397,7 +7397,19 @@ bool CodeGenPrepare::optimizeSwitchType(SwitchInst *SI) {
if (Arg->hasZExtAttr())
ExtType = Instruction::ZExt;
}
-
+ // If Cond has 2 users and one of them is a sext don't use a zext.
+ bool HaveSExtUser = false;
+ if (Cond->hasNUses(2)) {
+ for (auto &U : Cond->uses()) {
+ Value *V = U.get();
+ if (isa<SExtInst>(V)) {
+ HaveSExtUser = true;
+ }
+ }
+ }
+ if (HaveSExtUser) {
+ ExtType = Instruction::SExt;
+ }
auto *ExtInst = CastInst::Create(ExtType, Cond, NewType);
ExtInst->insertBefore(SI);
ExtInst->setDebugLoc(SI->getDebugLoc());
diff --git a/llvm/test/CodeGen/RISCV/switch-width.ll b/llvm/test/CodeGen/RISCV/switch-width.ll
index d902bd3276a3ce..fa3a321d85c471 100644
--- a/llvm/test/CodeGen/RISCV/switch-width.ll
+++ b/llvm/test/CodeGen/RISCV/switch-width.ll
@@ -194,7 +194,90 @@ return:
%retval = phi i32 [ -1, %sw.default ], [ 0, %sw.bb0 ], [ 1, %sw.bb1 ]
ret i32 %retval
}
+define i32 @sext_i32(i16 %a) {
+; CHECK-LABEL: sext_i32:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: lui a1, 16
+; CHECK-NEXT: addiw a1, a1, -1
+; CHECK-NEXT: and a2, a0, a1
+; CHECK-NEXT: beq a2, a1, .LBB5_3
+; CHECK-NEXT: # %bb.1: # %entry
+; CHECK-NEXT: slli a0, a0, 48
+; CHECK-NEXT: srai a0, a0, 48
+; CHECK-NEXT: li a1, 1
+; CHECK-NEXT: bne a0, a1, .LBB5_4
+; CHECK-NEXT: # %bb.2: # %sw.bb0
+; CHECK-NEXT: li a0, 0
+; CHECK-NEXT: ret
+; CHECK-NEXT: .LBB5_3: # %sw.bb1
+; CHECK-NEXT: li a0, 1
+; CHECK-NEXT: ret
+; CHECK-NEXT: .LBB5_4: # %sw.default
+; CHECK-NEXT: li a0, -1
+; CHECK-NEXT: ret
+entry:
+ %sext = sext i16 %a to i32
+ switch i32 %sext, label %sw.default [
+ i32 1, label %sw.bb0
+ i32 -1, label %sw.bb1
+ ]
+
+sw.bb0:
+ br label %return
+
+sw.bb1:
+ br label %return
+
+sw.default:
+ br label %return
+
+return:
+ %retval = phi i32 [ -1, %sw.default ], [ 0, %sw.bb0 ], [ 1, %sw.bb1 ]
+ ret i32 %retval
+}
+
+define i32 @sext_i16(i8 %a) {
+; CHECK-LABEL: sext_i16:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: andi a1, a0, 255
+; CHECK-NEXT: li a2, 255
+; CHECK-NEXT: beq a1, a2, .LBB6_3
+; CHECK-NEXT: # %bb.1: # %entry
+; CHECK-NEXT: slli a0, a0, 56
+; CHECK-NEXT: srai a0, a0, 56
+; CHECK-NEXT: slli a0, a0, 48
+; CHECK-NEXT: srli a0, a0, 48
+; CHECK-NEXT: li a1, 1
+; CHECK-NEXT: bne a0, a1, .LBB6_4
+; CHECK-NEXT: # %bb.2: # %sw.bb0
+; CHECK-NEXT: li a0, 0
+; CHECK-NEXT: ret
+; CHECK-NEXT: .LBB6_3: # %sw.bb1
+; CHECK-NEXT: li a0, 1
+; CHECK-NEXT: ret
+; CHECK-NEXT: .LBB6_4: # %sw.default
+; CHECK-NEXT: li a0, -1
+; CHECK-NEXT: ret
+entry:
+ %sext = sext i8 %a to i16
+ switch i16 %sext, label %sw.default [
+ i16 1, label %sw.bb0
+ i16 -1, label %sw.bb1
+ ]
+
+sw.bb0:
+ br label %return
+sw.bb1:
+ br label %return
+
+sw.default:
+ br label %return
+
+return:
+ %retval = phi i32 [ -1, %sw.default ], [ 0, %sw.bb0 ], [ 1, %sw.bb1 ]
+ ret i32 %retval
+}
define i32 @trunc_i12(i64 %a) {
; CHECK-LABEL: trunc_i12:
@@ -202,17 +285,17 @@ define i32 @trunc_i12(i64 %a) {
; CHECK-NEXT: lui a1, 1
; CHECK-NEXT: addiw a1, a1, -1
; CHECK-NEXT: and a0, a0, a1
-; CHECK-NEXT: beq a0, a1, .LBB5_3
+; CHECK-NEXT: beq a0, a1, .LBB7_3
; CHECK-NEXT: # %bb.1: # %entry
; CHECK-NEXT: li a1, 1
-; CHECK-NEXT: bne a0, a1, .LBB5_4
+; CHECK-NEXT: bne a0, a1, .LBB7_4
; CHECK-NEXT: # %bb.2: # %sw.bb0
; CHECK-NEXT: li a0, 0
; CHECK-NEXT: ret
-; CHECK-NEXT: .LBB5_3: # %sw.bb1
+; CHECK-NEXT: .LBB7_3: # %sw.bb1
; CHECK-NEXT: li a0, 1
; CHECK-NEXT: ret
-; CHECK-NEXT: .LBB5_4: # %sw.default
+; CHECK-NEXT: .LBB7_4: # %sw.default
; CHECK-NEXT: li a0, -1
; CHECK-NEXT: ret
entry:
@@ -241,17 +324,17 @@ define i32 @trunc_i11(i64 %a) {
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: andi a0, a0, 2047
; CHECK-NEXT: li a1, 2047
-; CHECK-NEXT: beq a0, a1, .LBB6_3
+; CHECK-NEXT: beq a0, a1, .LBB8_3
; CHECK-NEXT: # %bb.1: # %entry
; CHECK-NEXT: li a1, 1
-; CHECK-NEXT: bne a0, a1, .LBB6_4
+; CHECK-NEXT: bne a0, a1, .LBB8_4
; CHECK-NEXT: # %bb.2: # %sw.bb0
; CHECK-NEXT: li a0, 0
; CHECK-NEXT: ret
-; CHECK-NEXT: .LBB6_3: # %sw.bb1
+; CHECK-NEXT: .LBB8_3: # %sw.bb1
; CHECK-NEXT: li a0, 1
; CHECK-NEXT: ret
-; CHECK-NEXT: .LBB6_4: # %sw.default
+; CHECK-NEXT: .LBB8_4: # %sw.default
; CHECK-NEXT: li a0, -1
; CHECK-NEXT: ret
entry:
@@ -281,17 +364,17 @@ define i32 @trunc_i10(i64 %a) {
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: andi a0, a0, 1023
; CHECK-NEXT: li a1, 1023
-; CHECK-NEXT: beq a0, a1, .LBB7_3
+; CHECK-NEXT: beq a0, a1, .LBB9_3
; CHECK-NEXT: # %bb.1: # %entry
; CHECK-NEXT: li a1, 1
-; CHECK-NEXT: bne a0, a1, .LBB7_4
+; CHECK-NEXT: bne a0, a1, .LBB9_4
; CHECK-NEXT: # %bb.2: # %sw.bb0
; CHECK-NEXT: li a0, 0
; CHECK-NEXT: ret
-; CHECK-NEXT: .LBB7_3: # %sw.bb1
+; CHECK-NEXT: .LBB9_3: # %sw.bb1
; CHECK-NEXT: li a0, 1
; CHECK-NEXT: ret
-; CHECK-NEXT: .LBB7_4: # %sw.default
+; CHECK-NEXT: .LBB9_4: # %sw.default
; CHECK-NEXT: li a0, -1
; CHECK-NEXT: ret
entry:
|
Can you rephrase the description to say what the check is, and why? |
llvm/lib/CodeGen/CodeGenPrepare.cpp
Outdated
@@ -7397,7 +7397,19 @@ bool CodeGenPrepare::optimizeSwitchType(SwitchInst *SI) { | |||
if (Arg->hasZExtAttr()) | |||
ExtType = Instruction::ZExt; | |||
} | |||
|
|||
// If Cond has 2 users and one of them is a sext don't use a zext. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably be looking at the other user and using it's extend kind (sign or zero).
we probably do want the argument extend kind check to overrule, so maybe put this just above?
@@ -194,25 +194,108 @@ return: | |||
%retval = phi i32 [ -1, %sw.default ], [ 0, %sw.bb0 ], [ 1, %sw.bb1 ] | |||
ret i32 %retval | |||
} | |||
define i32 @sext_i32(i16 %a) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should add test variants here with zeroext and signext on the arguments to make sure we test the interaction.
31888ac
to
7dd7633
Compare
so that if we have more SExt Users than ZExt Users we use SExt instead of a ZExt in the Switch Condition because that creates a redundant instruction.
7dd7633
to
c186cf5
Compare
} | ||
|
||
// Some targets prefer SExt over ZExt. | ||
if (TLI->isSExtCheaperThanZExt(OldVT, RegType)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What was the point of doing this user scan if you just throw away the result?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because in some cases we have more ZExtUsers but SExt is cheaper so if create a ZExt we add more instructions.
I checked spec2017 for RISC-V with the precedence with this and It was doing worse on 500.perlbench_r if we check SExtIsCheaperThanZExt before the user scan. I can share the results later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't mean the end result, I mean the computation you perform in this code is discarded based on isSExtCheaperThanZExt
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes isSExtCheaperThanZExt needs to take precedence if it doesn't agree with the computation that I perform otherwise the code size increases as I showed above.
Maybe the gain is very small compared to the cost because we need a User Scan.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My reading of @arsenm's comment is that maybe it would be better to avoid the user scan if we dont need it as such:
if (TLI->isSExtCheaperThanZExt(OldVT, RegType))
ExtType = Instruction::SExt;
else {
// Move user scan above to here
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If one of the users is a ZExt, then ZExt should be preferable to SExt even if SExt is cheaper. An unsigned ICmp should maybe be treated as SExtUser if isSExtCheaperThanZExt. Type legalization will use sext instead of zext for unsigned icmps when isSExtCheaperThanZExt is true.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Title should be more specific about the purpose of the check, rather than state that a check was added
} | ||
|
||
// Some targets prefer SExt over ZExt. | ||
if (TLI->isSExtCheaperThanZExt(OldVT, RegType)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't mean the end result, I mean the computation you perform in this code is discarded based on isSExtCheaperThanZExt
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Title needs improvement
When we have two or more users in the Switch Condition and we have more SExt Users than ZExt Users or more signed cmp Instruction Users than unsigned cmp Instruction Users, we need to check to not insert a ZExt into the switch condition Type and rather insert a SExt. This way we can eliminate one Instruction.