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 @@ -1328,6 +1328,49 @@ getI32Imm(Lo16)); ++InstCntDirect; } + + // Try to use 4 instructions to materialize the immediate which is "almost" a + // splat of a 32 bit immediate. + if (InstCntDirect > 4) { + uint32_t Hi16OfHi32 = (Hi_32(Imm) >> 16) & 0xffff; + uint32_t Lo16OfHi32 = Hi_32(Imm) & 0xffff; + uint32_t Hi16OfLo32 = (Lo_32(Imm) >> 16) & 0xffff; + uint32_t Lo16OfLo32 = Lo_32(Imm) & 0xffff; + + auto getSplat = [CurDAG, dl, getI32Imm](uint32_t Hi16, uint32_t Lo16) { + SDNode *Result = + CurDAG->getMachineNode(PPC::LIS8, dl, MVT::i64, getI32Imm(Hi16)); + Result = CurDAG->getMachineNode(PPC::ORI8, dl, MVT::i64, + SDValue(Result, 0), getI32Imm(Lo16)); + SDValue Ops[] = {SDValue(Result, 0), SDValue(Result, 0), getI32Imm(32), + getI32Imm(0)}; + return CurDAG->getMachineNode(PPC::RLDIMI, dl, MVT::i64, Ops); + }; + + if (Hi16OfHi32 == Lo16OfHi32 && Lo16OfHi32 == Lo16OfLo32) { + InstCntDirect = 4; + Result = getSplat(Hi16OfLo32, Lo16OfLo32); + // Modify Hi16OfHi32. + SDValue Ops[] = {SDValue(Result, 0), SDValue(Result, 0), getI32Imm(48), + getI32Imm(0)}; + Result = CurDAG->getMachineNode(PPC::RLDIMI, dl, MVT::i64, Ops); + } else if (Hi16OfHi32 == Hi16OfLo32 && Hi16OfLo32 == Lo16OfLo32) { + InstCntDirect = 4; + Result = getSplat(Hi16OfHi32, Lo16OfHi32); + // Modify Lo16OfLo32. + SDValue Ops[] = {SDValue(Result, 0), SDValue(Result, 0), getI32Imm(16), + getI32Imm(16), getI32Imm(31)}; + Result = CurDAG->getMachineNode(PPC::RLWIMI8, dl, MVT::i64, Ops); + } else if (Lo16OfHi32 == Lo16OfLo32 && Hi16OfLo32 == Lo16OfLo32) { + InstCntDirect = 4; + Result = getSplat(Hi16OfHi32, Lo16OfHi32); + // Modify Hi16OfLo32. + SDValue Ops[] = {SDValue(Result, 0), SDValue(Result, 0), getI32Imm(16), + getI32Imm(0), getI32Imm(15)}; + Result = CurDAG->getMachineNode(PPC::RLWIMI8, dl, MVT::i64, Ops); + } + } + if (InstCnt) *InstCnt = InstCntDirect; return Result; diff --git a/llvm/test/CodeGen/PowerPC/constants-i64.ll b/llvm/test/CodeGen/PowerPC/constants-i64.ll --- a/llvm/test/CodeGen/PowerPC/constants-i64.ll +++ b/llvm/test/CodeGen/PowerPC/constants-i64.ll @@ -391,11 +391,10 @@ define i64 @imm20() { ; CHECK-LABEL: imm20: ; CHECK: # %bb.0: # %entry -; CHECK-NEXT: lis 3, -13057 -; CHECK-NEXT: ori 3, 3, 52479 -; CHECK-NEXT: rldic 3, 3, 32, 0 -; CHECK-NEXT: oris 3, 3, 291 +; CHECK-NEXT: lis 3, 291 ; CHECK-NEXT: ori 3, 3, 52479 +; CHECK-NEXT: rldimi 3, 3, 32, 0 +; CHECK-NEXT: rldimi 3, 3, 48, 0 ; CHECK-NEXT: blr entry: ret i64 14771750698406366463 ;0xCCFFCCFF0123CCFF @@ -406,9 +405,8 @@ ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: lis 3, -13057 ; CHECK-NEXT: ori 3, 3, 291 -; CHECK-NEXT: rldic 3, 3, 32, 0 -; CHECK-NEXT: oris 3, 3, 52479 -; CHECK-NEXT: ori 3, 3, 52479 +; CHECK-NEXT: rldimi 3, 3, 32, 0 +; CHECK-NEXT: rlwimi 3, 3, 16, 16, 31 ; CHECK-NEXT: blr entry: ret i64 14771526556073315583 ;0xCCFF0123CCFFCCFF @@ -419,9 +417,8 @@ ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: lis 3, 291 ; CHECK-NEXT: ori 3, 3, 52479 -; CHECK-NEXT: rldic 3, 3, 32, 7 -; CHECK-NEXT: oris 3, 3, 52479 -; CHECK-NEXT: ori 3, 3, 52479 +; CHECK-NEXT: rldimi 3, 3, 32, 0 +; CHECK-NEXT: rlwimi 3, 3, 16, 0, 15 ; CHECK-NEXT: blr entry: ret i64 82134617250843903 ;0x0123CCFFCCFFCCFF