[llvm] 874a800 - [PowerPC] Exploit the rlwinm instructions for "and" with constant
QingShan Zhang via llvm-commits
llvm-commits at lists.llvm.org
Sun Dec 29 19:20:32 PST 2019
Author: QingShan Zhang
Date: 2019-12-30T03:18:31Z
New Revision: 874a8004f93538a0c9b335a7e1e34d80b57ebccd
URL: https://github.com/llvm/llvm-project/commit/874a8004f93538a0c9b335a7e1e34d80b57ebccd
DIFF: https://github.com/llvm/llvm-project/commit/874a8004f93538a0c9b335a7e1e34d80b57ebccd.diff
LOG: [PowerPC] Exploit the rlwinm instructions for "and" with constant
For now, PowerPC will using several instructions to get the constant and "and" it with the following case:
define i32 @test1(i32 %a) {
%and = and i32 %a, -2
ret i32 %and
}
However, we could exploit it with the rotate mask instructions.
MB ME
+----------------------+
|xxxxxxxxxxx00011111000|
+----------------------+
0 32 64
Notice that, we can only do it if the MB is larger than 32 and MB <= ME as
RLWINM will replace the content of [0 - 32) with [32 - 64) even we didn't rotate it.
Differential Revision: https://reviews.llvm.org/D71829
Added:
Modified:
llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h
llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
llvm/test/CodeGen/PowerPC/and-mask.ll
llvm/test/CodeGen/PowerPC/opt-cmp-inst-cr0-live.ll
llvm/test/CodeGen/PowerPC/popcnt-zext.ll
Removed:
################################################################################
diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h
index 74b67bd2e928..49443679bb31 100644
--- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h
+++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h
@@ -82,6 +82,30 @@ static inline bool isRunOfOnes(unsigned Val, unsigned &MB, unsigned &ME) {
return false;
}
+static inline bool isRunOfOnes64(uint64_t Val, unsigned &MB, unsigned &ME) {
+ if (!Val)
+ return false;
+
+ if (isShiftedMask_64(Val)) {
+ // look for the first non-zero bit
+ MB = countLeadingZeros(Val);
+ // look for the first zero bit after the run of ones
+ ME = countLeadingZeros((Val - 1) ^ Val);
+ return true;
+ } else {
+ Val = ~Val; // invert mask
+ if (isShiftedMask_64(Val)) {
+ // effectively look for the first zero bit
+ ME = countLeadingZeros(Val) - 1;
+ // effectively look for the first one bit after the run of zeros
+ MB = countLeadingZeros((Val - 1) ^ Val) + 1;
+ return true;
+ }
+ }
+ // no run present
+ return false;
+}
+
} // end namespace llvm
// Generated files will use "namespace PPC". To avoid symbol clash,
diff --git a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
index f1e9b159d3c1..a1f9de62b05a 100644
--- a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
@@ -4456,6 +4456,26 @@ bool PPCDAGToDAGISel::tryAndWithMask(SDNode *N) {
CurDAG->SelectNodeTo(N, PPC::RLDICR, MVT::i64, Ops);
return true;
}
+
+ // It is not 16-bit imm that means we need two instructions at least if
+ // using "and" instruction. Try to exploit it with rotate mask instructions.
+ if (isRunOfOnes64(Imm64, MB, ME)) {
+ if (MB >= 32 && MB <= ME) {
+ // MB ME
+ // +----------------------+
+ // |xxxxxxxxxxx00011111000|
+ // +----------------------+
+ // 0 32 64
+ // We can only do it if the MB is larger than 32 and MB <= ME
+ // as RLWINM will replace the content of [0 - 32) with [32 - 64) even
+ // we didn't rotate it.
+ SDValue Ops[] = { Val, getI64Imm(0, dl), getI64Imm(MB - 32, dl),
+ getI64Imm(ME - 32, dl) };
+ CurDAG->SelectNodeTo(N, PPC::RLWINM8, MVT::i64, Ops);
+ return true;
+ }
+ // TODO - handle it with rldicl + rldicl
+ }
}
return false;
diff --git a/llvm/test/CodeGen/PowerPC/and-mask.ll b/llvm/test/CodeGen/PowerPC/and-mask.ll
index 886657185301..89f568196327 100644
--- a/llvm/test/CodeGen/PowerPC/and-mask.ll
+++ b/llvm/test/CodeGen/PowerPC/and-mask.ll
@@ -5,10 +5,7 @@
define i32 @test1(i32 %a) {
; CHECK-LABEL: test1:
; CHECK: # %bb.0:
-; CHECK-NEXT: lis 4, 32767
-; CHECK-NEXT: ori 4, 4, 65535
-; CHECK-NEXT: sldi 4, 4, 1
-; CHECK-NEXT: and 3, 3, 4
+; CHECK-NEXT: rlwinm 3, 3, 0, 0, 30
; CHECK-NEXT: blr
%and = and i32 %a, -2
ret i32 %and
diff --git a/llvm/test/CodeGen/PowerPC/opt-cmp-inst-cr0-live.ll b/llvm/test/CodeGen/PowerPC/opt-cmp-inst-cr0-live.ll
index fac7522db04a..4a3cd710332f 100644
--- a/llvm/test/CodeGen/PowerPC/opt-cmp-inst-cr0-live.ll
+++ b/llvm/test/CodeGen/PowerPC/opt-cmp-inst-cr0-live.ll
@@ -7,12 +7,12 @@ define signext i32 @fn1(i32 %baz) {
%2 = zext i32 %1 to i64
%3 = shl i64 %2, 48
%4 = ashr exact i64 %3, 48
-; CHECK: ANDI8o killed {{[^,]+}}, 65520, implicit-def dead $cr0
+; CHECK: RLWINM8 killed {{[^,]+}}, 0, 16, 27
; CHECK: CMPLDI
; CHECK: BCC
; CHECK: ANDI8o {{[^,]+}}, 65520, implicit-def $cr0
-; CHECK: COPY $cr0
+; CHECK: COPY killed $cr0
; CHECK: BCC
%5 = icmp eq i64 %4, 0
br i1 %5, label %foo, label %bar
diff --git a/llvm/test/CodeGen/PowerPC/popcnt-zext.ll b/llvm/test/CodeGen/PowerPC/popcnt-zext.ll
index 23d49f2290f9..eab90bf2fbfe 100644
--- a/llvm/test/CodeGen/PowerPC/popcnt-zext.ll
+++ b/llvm/test/CodeGen/PowerPC/popcnt-zext.ll
@@ -299,7 +299,7 @@ define i64 @popa_i16_i64(i16 %x) {
; FAST: # %bb.0:
; FAST-NEXT: clrldi 3, 3, 48
; FAST-NEXT: popcntd 3, 3
-; FAST-NEXT: andi. 3, 3, 16
+; FAST-NEXT: rlwinm 3, 3, 0, 27, 27
; FAST-NEXT: blr
;
; SLOW-LABEL: popa_i16_i64:
@@ -325,7 +325,7 @@ define i64 @popa_i16_i64(i16 %x) {
; SLOW-NEXT: ori 4, 4, 257
; SLOW-NEXT: mullw 3, 3, 4
; SLOW-NEXT: srwi 3, 3, 24
-; SLOW-NEXT: andi. 3, 3, 16
+; SLOW-NEXT: rlwinm 3, 3, 0, 27, 27
; SLOW-NEXT: blr
%pop = call i16 @llvm.ctpop.i16(i16 %x)
%z = zext i16 %pop to i64 ; SimplifyDemandedBits may turn zext (or sext) into aext
More information about the llvm-commits
mailing list