diff --git a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp --- a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp @@ -352,6 +352,7 @@ bool tryAsSingleRLWINM8(SDNode *N); bool tryAsSingleRLWIMI(SDNode *N); bool tryAsPairOfRLDICL(SDNode *N); + bool tryAsSingleRLDIMI(SDNode *N); void PeepholePPC64(); void PeepholePPC64ZExt(); @@ -4597,6 +4598,31 @@ return true; } +bool PPCDAGToDAGISel::tryAsSingleRLDIMI(SDNode *N) { + assert(N->getOpcode() == ISD::OR && "ISD::OR SDNode expected"); + uint64_t Imm64; + unsigned MB, ME; + SDValue N0 = N->getOperand(0); + + // We won't get fewer instructions if the imm is 32-bit integer. + // rldimi requires the imm to have consecutive ones with both sides zero. + // Also, make sure the first Op has only one use, otherwise this may increase + // register pressure since rldimi is destructive. + if (!isInt64Immediate(N->getOperand(1).getNode(), Imm64) || + isUInt<32>(Imm64) || !isRunOfOnes64(Imm64, MB, ME) || !N0.hasOneUse()) + return false; + + unsigned SH = 63 - ME; + SDLoc Dl(N); + // Use select64Imm for making LI instr instead of directly putting Imm64 + SDValue Ops[] = { + N->getOperand(0), + SDValue(selectI64Imm(CurDAG, getI64Imm(-1, Dl).getNode()), 0), + getI32Imm(SH, Dl), getI32Imm(MB, Dl)}; + CurDAG->SelectNodeTo(N, PPC::RLDIMI, MVT::i64, Ops); + return true; +} + // Select - Convert the specified operand from a target-independent to a // target-specific node if it hasn't already been changed. void PPCDAGToDAGISel::Select(SDNode *N) { @@ -4844,6 +4870,11 @@ } } + // If this is 'or' against an imm with consecutive ones and both sides zero, + // try to emit rldimi + if (tryAsSingleRLDIMI(N)) + return; + // OR with a 32-bit immediate can be handled by ori + oris // without creating an immediate in a GPR. uint64_t Imm64 = 0; diff --git a/llvm/test/CodeGen/PowerPC/ori_imm32.ll b/llvm/test/CodeGen/PowerPC/ori_imm32.ll --- a/llvm/test/CodeGen/PowerPC/ori_imm32.ll +++ b/llvm/test/CodeGen/PowerPC/ori_imm32.ll @@ -16,9 +16,8 @@ define i64 @ori_test_b(i64 %a) { ; CHECK-LABEL: ori_test_b: ; CHECK: # %bb.0: # %entry -; CHECK-NEXT: li 4, 1 -; CHECK-NEXT: sldi 4, 4, 32 -; CHECK-NEXT: or 3, 3, 4 +; CHECK-NEXT: li 4, -1 +; CHECK-NEXT: rldimi 3, 4, 32, 31 ; CHECK-NEXT: blr entry: %or = or i64 %a, 4294967296 diff --git a/llvm/test/CodeGen/PowerPC/ori_imm64.ll b/llvm/test/CodeGen/PowerPC/ori_imm64.ll --- a/llvm/test/CodeGen/PowerPC/ori_imm64.ll +++ b/llvm/test/CodeGen/PowerPC/ori_imm64.ll @@ -15,10 +15,8 @@ define i64 @ori_test_2(i64 %a) { ; CHECK-LABEL: ori_test_2: ; CHECK: # %bb.0: # %entry -; CHECK-NEXT: lis 4, 15 -; CHECK-NEXT: ori 4, 4, 65535 -; CHECK-NEXT: sldi 4, 4, 29 -; CHECK-NEXT: or 3, 3, 4 +; CHECK-NEXT: li 4, -1 +; CHECK-NEXT: rldimi 3, 4, 29, 15 ; CHECK-NEXT: blr entry: %or = or i64 %a, 562949416550400 ; 0x1ffffe0000000 @@ -28,9 +26,8 @@ define i64 @ori_test_3(i64 %a) { ; CHECK-LABEL: ori_test_3: ; CHECK: # %bb.0: # %entry -; CHECK-NEXT: lis 4, -32768 -; CHECK-NEXT: rldicr 4, 4, 36, 63 -; CHECK-NEXT: or 3, 3, 4 +; CHECK-NEXT: li 4, -1 +; CHECK-NEXT: rldimi 3, 4, 3, 28 ; CHECK-NEXT: blr entry: %or = or i64 %a, 68719476728 ; 0xffffffff8 @@ -50,3 +47,20 @@ %or = or i64 %a, 17661175070719 ; 0x10101010ffff ret i64 %or } + +; Don't exploit rldimi if operand has multiple uses +define i64 @test_test_5(i64 %a, i64 %b) { +; CHECK-LABEL: test_test_5: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: li 5, 1 +; CHECK-NEXT: sldi 5, 5, 32 +; CHECK-NEXT: or 5, 3, 5 +; CHECK-NEXT: add 4, 5, 4 +; CHECK-NEXT: sub 3, 3, 4 +; CHECK-NEXT: blr +entry: + %or = or i64 %a, 4294967296 + %add = add i64 %or, %b + %div = sub i64 %a, %add + ret i64 %div +}