diff --git a/llvm/lib/Target/PowerPC/GISel/PPCInstructionSelector.cpp b/llvm/lib/Target/PowerPC/GISel/PPCInstructionSelector.cpp --- a/llvm/lib/Target/PowerPC/GISel/PPCInstructionSelector.cpp +++ b/llvm/lib/Target/PowerPC/GISel/PPCInstructionSelector.cpp @@ -55,6 +55,13 @@ bool selectZExt(MachineInstr &I, MachineBasicBlock &MBB, MachineRegisterInfo &MRI) const; + std::optional selectI64ImmDirect(MachineInstr &I, + MachineBasicBlock &MBB, + MachineRegisterInfo &MRI, Register Reg, + uint64_t Imm) const; + bool selectI64Imm(MachineInstr &I, MachineBasicBlock &MBB, + MachineRegisterInfo &MRI) const; + const PPCSubtarget &STI; const PPCInstrInfo &TII; const PPCRegisterInfo &TRI; @@ -250,6 +257,379 @@ return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI); } +// For any 32 < Num < 64, check if the Imm contains at least Num consecutive +// zeros and return the number of bits by the left of these consecutive zeros. +static uint32_t findContiguousZerosAtLeast(uint64_t Imm, unsigned Num) { + uint32_t HiTZ = countTrailingZeros(Hi_32(Imm)); + uint32_t LoLZ = countLeadingZeros(Lo_32(Imm)); + if ((HiTZ + LoLZ) >= Num) + return (32 + HiTZ); + return 0; +} + +// Direct materialization of 64-bit constants by enumerated patterns. +// Similar to PPCISelDAGToDAG::selectI64ImmDirect(). +std::optional PPCInstructionSelector::selectI64ImmDirect(MachineInstr &I, + MachineBasicBlock &MBB, + MachineRegisterInfo &MRI, + Register Reg, + uint64_t Imm) const { + unsigned TZ = countTrailingZeros(Imm); + unsigned LZ = countLeadingZeros(Imm); + unsigned TO = countTrailingOnes(Imm); + unsigned LO = countLeadingOnes(Imm); + uint32_t Hi32 = Hi_32(Imm); + uint32_t Lo32 = Lo_32(Imm); + uint32_t Shift = 0; + + // Following patterns use 1 instructions to materialize the Imm. + + // 1-1) Patterns : {zeros}{15-bit valve} + // {ones}{15-bit valve} + if (isInt<16>(Imm)) + return BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::LI8), Reg) + .addImm(Imm) + .constrainAllUses(TII, TRI, RBI); + // 1-2) Patterns : {zeros}{15-bit valve}{16 zeros} + // {ones}{15-bit valve}{16 zeros} + if (TZ > 15 && (LZ > 32 || LO > 32)) + return BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::LIS8), Reg) + .addImm((Imm >> 16) & 0xffff) + .constrainAllUses(TII, TRI, RBI); + + // Following patterns use 2 instructions to materialize the Imm. + + assert(LZ < 64 && "Unexpected leading zeros here."); + // Count of ones follwing the leading zeros. + unsigned FO = countLeadingOnes(Imm << LZ); + // 2-1) Patterns : {zeros}{31-bit value} + // {ones}{31-bit value} + if (isInt<32>(Imm)) { + uint64_t ImmHi16 = (Imm >> 16) & 0xffff; + unsigned Opcode = ImmHi16 ? PPC::LIS8 : PPC::LI8; + Register TmpReg = MRI.createVirtualRegister(&PPC::G8RCRegClass); + if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(Opcode), TmpReg) + .addImm((Imm >> 16) & 0xffff) + .constrainAllUses(TII, TRI, RBI)) + return false; + return BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::ORI8), Reg) + .addReg(TmpReg, RegState::Kill) + .addImm(Imm & 0xffff) + .constrainAllUses(TII, TRI, RBI); + } + // 2-2) Patterns : {zeros}{ones}{15-bit value}{zeros} + // {zeros}{15-bit value}{zeros} + // {zeros}{ones}{15-bit value} + // {ones}{15-bit value}{zeros} + // We can take advantage of LI's sign-extension semantics to generate leading + // ones, and then use RLDIC to mask off the ones in both sides after rotation. + if ((LZ + FO + TZ) > 48) { + Register TmpReg = MRI.createVirtualRegister(&PPC::G8RCRegClass); + if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::LI8), TmpReg) + .addImm((Imm >> TZ) & 0xffff) + .constrainAllUses(TII, TRI, RBI)) + return false; + return BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::RLDIC), Reg) + .addReg(TmpReg, RegState::Kill) + .addImm(TZ) + .addImm(LZ) + .constrainAllUses(TII, TRI, RBI); + } + // 2-3) Pattern : {zeros}{15-bit value}{ones} + // Shift right the Imm by (48 - LZ) bits to construct a negtive 16 bits value, + // therefore we can take advantage of LI's sign-extension semantics, and then + // mask them off after rotation. + // + // +--LZ--||-15-bit-||--TO--+ +-------------|--16-bit--+ + // |00000001bbbbbbbbb1111111| -> |00000000000001bbbbbbbbb1| + // +------------------------+ +------------------------+ + // 63 0 63 0 + // Imm (Imm >> (48 - LZ) & 0xffff) + // +----sext-----|--16-bit--+ +clear-|-----------------+ + // |11111111111111bbbbbbbbb1| -> |00000001bbbbbbbbb1111111| + // +------------------------+ +------------------------+ + // 63 0 63 0 + // LI8: sext many leading zeros RLDICL: rotate left (48 - LZ), clear left LZ + if ((LZ + TO) > 48) { + // Since the immediates with (LZ > 32) have been handled by previous + // patterns, here we have (LZ <= 32) to make sure we will not shift right + // the Imm by a negative value. + assert(LZ <= 32 && "Unexpected shift value."); + Register TmpReg = MRI.createVirtualRegister(&PPC::G8RCRegClass); + if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::LI8), TmpReg) + .addImm(Imm >> (48 - LZ) & 0xffff) + .constrainAllUses(TII, TRI, RBI)) + return false; + return BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::RLDICL), Reg) + .addReg(TmpReg, RegState::Kill) + .addImm(48 - LZ) + .addImm(LZ) + .constrainAllUses(TII, TRI, RBI); + } + // 2-4) Patterns : {zeros}{ones}{15-bit value}{ones} + // {ones}{15-bit value}{ones} + // We can take advantage of LI's sign-extension semantics to generate leading + // ones, and then use RLDICL to mask off the ones in left sides (if required) + // after rotation. + // + // +-LZ-FO||-15-bit-||--TO--+ +-------------|--16-bit--+ + // |00011110bbbbbbbbb1111111| -> |000000000011110bbbbbbbbb| + // +------------------------+ +------------------------+ + // 63 0 63 0 + // Imm (Imm >> TO) & 0xffff + // +----sext-----|--16-bit--+ +LZ|---------------------+ + // |111111111111110bbbbbbbbb| -> |00011110bbbbbbbbb1111111| + // +------------------------+ +------------------------+ + // 63 0 63 0 + // LI8: sext many leading zeros RLDICL: rotate left TO, clear left LZ + if ((LZ + FO + TO) > 48) { + Register TmpReg = MRI.createVirtualRegister(&PPC::G8RCRegClass); + if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::LI8), TmpReg) + .addImm((Imm >> TO) & 0xffff) + .constrainAllUses(TII, TRI, RBI)) + return false; + return BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::RLDICL), Reg) + .addReg(TmpReg, RegState::Kill) + .addImm(TO) + .addImm(LZ) + .constrainAllUses(TII, TRI, RBI); + } + // 2-5) Pattern : {32 zeros}{****}{0}{15-bit value} + // If Hi32 is zero and the Lo16(in Lo32) can be presented as a positive 16 bit + // value, we can use LI for Lo16 without generating leading ones then add the + // Hi16(in Lo32). + if (LZ == 32 && ((Lo32 & 0x8000) == 0)) { + Register TmpReg = MRI.createVirtualRegister(&PPC::G8RCRegClass); + if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::LI8), TmpReg) + .addImm(Lo32 & 0xffff) + .constrainAllUses(TII, TRI, RBI)) + return false; + return BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::ORIS8), Reg) + .addReg(TmpReg, RegState::Kill) + .addImm(Lo32 >> 16) + .constrainAllUses(TII, TRI, RBI); + } + // 2-6) Patterns : {******}{49 zeros}{******} + // {******}{49 ones}{******} + // If the Imm contains 49 consecutive zeros/ones, it means that a total of 15 + // bits remain on both sides. Rotate right the Imm to construct an int<16> + // value, use LI for int<16> value and then use RLDICL without mask to rotate + // it back. + // + // 1) findContiguousZerosAtLeast(Imm, 49) + // +------|--zeros-|------+ +---ones--||---15 bit--+ + // |bbbbbb0000000000aaaaaa| -> |0000000000aaaaaabbbbbb| + // +----------------------+ +----------------------+ + // 63 0 63 0 + // + // 2) findContiguousZerosAtLeast(~Imm, 49) + // +------|--ones--|------+ +---ones--||---15 bit--+ + // |bbbbbb1111111111aaaaaa| -> |1111111111aaaaaabbbbbb| + // +----------------------+ +----------------------+ + // 63 0 63 0 + if ((Shift = findContiguousZerosAtLeast(Imm, 49)) || + (Shift = findContiguousZerosAtLeast(~Imm, 49))) { + uint64_t RotImm = APInt(64, Imm).rotr(Shift).getZExtValue(); + Register TmpReg = MRI.createVirtualRegister(&PPC::G8RCRegClass); + if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::LI8), TmpReg) + .addImm(RotImm & 0xffff) + .constrainAllUses(TII, TRI, RBI)) + return false; + return BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::RLDICL), Reg) + .addReg(TmpReg, RegState::Kill) + .addImm(Shift) + .addImm(0) + .constrainAllUses(TII, TRI, RBI); + } + + // Following patterns use 3 instructions to materialize the Imm. + + // 3-1) Patterns : {zeros}{ones}{31-bit value}{zeros} + // {zeros}{31-bit value}{zeros} + // {zeros}{ones}{31-bit value} + // {ones}{31-bit value}{zeros} + // We can take advantage of LIS's sign-extension semantics to generate leading + // ones, add the remaining bits with ORI, and then use RLDIC to mask off the + // ones in both sides after rotation. + if ((LZ + FO + TZ) > 32) { + uint64_t ImmHi16 = (Imm >> (TZ + 16)) & 0xffff; + unsigned Opcode = ImmHi16 ? PPC::LIS8 : PPC::LI8; + Register TmpReg = MRI.createVirtualRegister(&PPC::G8RCRegClass); + Register Tmp2Reg = MRI.createVirtualRegister(&PPC::G8RCRegClass); + if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(Opcode), TmpReg) + .addImm(ImmHi16) + .constrainAllUses(TII, TRI, RBI)) + return false; + if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::ORI8), Tmp2Reg) + .addReg(TmpReg, RegState::Kill) + .addImm((Imm >> TZ) & 0xffff) + .constrainAllUses(TII, TRI, RBI)) + return false; + return BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::RLDIC), Reg) + .addReg(Tmp2Reg, RegState::Kill) + .addImm(TZ) + .addImm(LZ) + .constrainAllUses(TII, TRI, RBI); + } + // 3-2) Pattern : {zeros}{31-bit value}{ones} + // Shift right the Imm by (32 - LZ) bits to construct a negative 32 bits + // value, therefore we can take advantage of LIS's sign-extension semantics, + // add the remaining bits with ORI, and then mask them off after rotation. + // This is similar to Pattern 2-3, please refer to the diagram there. + if ((LZ + TO) > 32) { + // Since the immediates with (LZ > 32) have been handled by previous + // patterns, here we have (LZ <= 32) to make sure we will not shift right + // the Imm by a negative value. + assert(LZ <= 32 && "Unexpected shift value."); + Register TmpReg = MRI.createVirtualRegister(&PPC::G8RCRegClass); + Register Tmp2Reg = MRI.createVirtualRegister(&PPC::G8RCRegClass); + if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::LIS8), TmpReg) + .addImm((Imm >> (48 - LZ)) & 0xffff) + .constrainAllUses(TII, TRI, RBI)) + return false; + if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::ORI8), Tmp2Reg) + .addReg(TmpReg, RegState::Kill) + .addImm((Imm >> (32 - LZ)) & 0xffff) + .constrainAllUses(TII, TRI, RBI)) + return false; + return BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::RLDICL), Reg) + .addReg(Tmp2Reg, RegState::Kill) + .addImm(32 - LZ) + .addImm(LZ) + .constrainAllUses(TII, TRI, RBI); + } + // 3-3) Patterns : {zeros}{ones}{31-bit value}{ones} + // {ones}{31-bit value}{ones} + // We can take advantage of LIS's sign-extension semantics to generate leading + // ones, add the remaining bits with ORI, and then use RLDICL to mask off the + // ones in left sides (if required) after rotation. + // This is similar to Pattern 2-4, please refer to the diagram there. + if ((LZ + FO + TO) > 32) { + Register TmpReg = MRI.createVirtualRegister(&PPC::G8RCRegClass); + Register Tmp2Reg = MRI.createVirtualRegister(&PPC::G8RCRegClass); + if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::LIS8), TmpReg) + .addImm((Imm >> (TO + 16)) & 0xffff) + .constrainAllUses(TII, TRI, RBI)) + return false; + if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::ORI8), Tmp2Reg) + .addReg(TmpReg, RegState::Kill) + .addImm((Imm >> TO) & 0xffff) + .constrainAllUses(TII, TRI, RBI)) + return false; + return BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::RLDICL), Reg) + .addReg(Tmp2Reg, RegState::Kill) + .addImm(TO) + .addImm(LZ) + .constrainAllUses(TII, TRI, RBI); + } + // 3-4) Patterns : High word == Low word + if (Hi32 == Lo32) { + // Handle the first 32 bits. + uint64_t ImmHi16 = (Lo32 >> 16) & 0xffff; + unsigned Opcode = ImmHi16 ? PPC::LIS8 : PPC::LI8; + Register TmpReg = MRI.createVirtualRegister(&PPC::G8RCRegClass); + Register Tmp2Reg = MRI.createVirtualRegister(&PPC::G8RCRegClass); + if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(Opcode), TmpReg) + .addImm(ImmHi16) + .constrainAllUses(TII, TRI, RBI)) + return false; + if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::ORI8), Tmp2Reg) + .addReg(TmpReg, RegState::Kill) + .addImm(Lo32 & 0xffff) + .constrainAllUses(TII, TRI, RBI)) + return false; + return BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::RLDIMI), Reg) + .addReg(Tmp2Reg) + .addReg(Tmp2Reg, RegState::Kill) + .addImm(32) + .addImm(0) + .constrainAllUses(TII, TRI, RBI); + } + // 3-5) Patterns : {******}{33 zeros}{******} + // {******}{33 ones}{******} + // If the Imm contains 33 consecutive zeros/ones, it means that a total of 31 + // bits remain on both sides. Rotate right the Imm to construct an int<32> + // value, use LIS + ORI for int<32> value and then use RLDICL without mask to + // rotate it back. + // This is similar to Pattern 2-6, please refer to the diagram there. + if ((Shift = findContiguousZerosAtLeast(Imm, 33)) || + (Shift = findContiguousZerosAtLeast(~Imm, 33))) { + uint64_t RotImm = APInt(64, Imm).rotr(Shift).getZExtValue(); + uint64_t ImmHi16 = (RotImm >> 16) & 0xffff; + unsigned Opcode = ImmHi16 ? PPC::LIS8 : PPC::LI8; + Register TmpReg = MRI.createVirtualRegister(&PPC::G8RCRegClass); + Register Tmp2Reg = MRI.createVirtualRegister(&PPC::G8RCRegClass); + if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(Opcode), TmpReg) + .addImm(ImmHi16) + .constrainAllUses(TII, TRI, RBI)) + return false; + if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::ORI8), Tmp2Reg) + .addReg(TmpReg, RegState::Kill) + .addImm(RotImm & 0xffff) + .constrainAllUses(TII, TRI, RBI)) + return false; + return BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::RLDICL), Reg) + .addReg(Tmp2Reg, RegState::Kill) + .addImm(Shift) + .addImm(0) + .constrainAllUses(TII, TRI, RBI); + } + + // If we end up here then no instructions were inserted. + return std::nullopt; +} + +// Derived from PPCISelDAGToDAG::selectI64Imm(). +// TODO: Add support for prefixed instructions. +bool PPCInstructionSelector::selectI64Imm(MachineInstr &I, + MachineBasicBlock &MBB, + MachineRegisterInfo &MRI) const { + assert(I.getOpcode() == TargetOpcode::G_CONSTANT && "Unexpected G code"); + + Register DstReg = I.getOperand(0).getReg(); + int64_t Imm = I.getOperand(1).getCImm()->getValue().getZExtValue(); + // No more than 3 instructions are used if we can select the i64 immediate + // directly. + if (std::optional Res = selectI64ImmDirect(I, MBB, MRI, DstReg, Imm)) { + I.eraseFromParent(); + return *Res; + } + + // Calculate the last bits as required. + uint32_t Hi16 = (Lo_32(Imm) >> 16) & 0xffff; + uint32_t Lo16 = Lo_32(Imm) & 0xffff; + + Register Reg = + (Hi16 || Lo16) ? MRI.createVirtualRegister(&PPC::G8RCRegClass) : DstReg; + + // Handle the upper 32 bit value. + std::optional Res = + selectI64ImmDirect(I, MBB, MRI, Reg, Imm & 0xffffffff00000000); + if (!Res || !*Res) + return false; + + // Add in the last bits as required. + if (Hi16) { + Register TmpReg = + Lo16 ? MRI.createVirtualRegister(&PPC::G8RCRegClass) : DstReg; + if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::ORIS8), TmpReg) + .addReg(Reg, RegState::Kill) + .addImm(Hi16) + .constrainAllUses(TII, TRI, RBI)) + return false; + Reg = TmpReg; + } + if (Lo16) { + if (!BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::ORI8), DstReg) + .addReg(Reg, RegState::Kill) + .addImm(Lo16) + .constrainAllUses(TII, TRI, RBI)) + return false; + } + I.eraseFromParent(); + return true; +} + bool PPCInstructionSelector::select(MachineInstr &I) { auto &MBB = *I.getParent(); auto &MF = *MBB.getParent(); @@ -316,6 +696,8 @@ // G_SEXT will be selected in tb-gen pattern. case TargetOpcode::G_ZEXT: return selectZExt(I, MBB, MRI); + case TargetOpcode::G_CONSTANT: + return selectI64Imm(I, MBB, MRI); } return false; } diff --git a/llvm/test/CodeGen/PowerPC/GlobalISel/ppc-isel-constant.ll b/llvm/test/CodeGen/PowerPC/GlobalISel/ppc-isel-constant.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/GlobalISel/ppc-isel-constant.ll @@ -0,0 +1,400 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple ppc64le-linux -ppc-asm-full-reg-names -global-isel -o - < %s \ +; RUN: | FileCheck %s + +; Function Attrs: nounwind readnone +define i64 @cn15bit1() #0 { +; CHECK-LABEL: cn15bit1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: li r3, 32767 +; CHECK-NEXT: blr +entry: + ret i64 32767 + +} + +; Function Attrs: nounwind readnone +define i64 @cn15bit2() #0 { +; CHECK-LABEL: cn15bit2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: li r3, -32767 +; CHECK-NEXT: blr +entry: + ret i64 -32767 + +} + + +; Function Attrs: nounwind readnone +define i64 @cn1() #0 { +; CHECK-LABEL: cn1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: li r3, -1 +; CHECK-NEXT: rldic r3, r3, 0, 16 +; CHECK-NEXT: blr +entry: + ret i64 281474976710655 + +} + +; Function Attrs: nounwind readnone +define i64 @cnb() #0 { +; CHECK-LABEL: cnb: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: li r3, -81 +; CHECK-NEXT: rldic r3, r3, 0, 16 +; CHECK-NEXT: blr +entry: + ret i64 281474976710575 + +} + +; Function Attrs: nounwind readnone +define i64 @f2(i64 %x) #0 { +; CHECK-LABEL: f2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: li r3, -1 +; CHECK-NEXT: rldic r3, r3, 36, 0 +; CHECK-NEXT: blr +entry: + ret i64 -68719476736 + +} + +; Function Attrs: nounwind readnone +define i64 @f2a(i64 %x) #0 { +; CHECK-LABEL: f2a: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: li r3, -337 +; CHECK-NEXT: rldic r3, r3, 30, 0 +; CHECK-NEXT: blr +entry: + ret i64 -361850994688 + +} + +; Function Attrs: nounwind readnone +define i64 @f2n(i64 %x) #0 { +; CHECK-LABEL: f2n: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: li r3, -1 +; CHECK-NEXT: rldic r3, r3, 0, 28 +; CHECK-NEXT: blr +entry: + ret i64 68719476735 + +} + +; Function Attrs: nounwind readnone +define i64 @f3(i64 %x) #0 { +; CHECK-LABEL: f3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: li r3, -1 +; CHECK-NEXT: rldic r3, r3, 0, 31 +; CHECK-NEXT: blr +entry: + ret i64 8589934591 + +} + +; Function Attrs: nounwind readnone +define i64 @cn2n() #0 { +; CHECK-LABEL: cn2n: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: lis r3, -5121 +; CHECK-NEXT: ori r3, r3, 65534 +; CHECK-NEXT: rotldi r3, r3, 22 +; CHECK-NEXT: blr +entry: + ret i64 -1407374887747585 + +} + +define i64 @uint32_1() #0 { +; CHECK-LABEL: uint32_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: li r3, 18176 +; CHECK-NEXT: oris r3, r3, 59509 +; CHECK-NEXT: blr +entry: + ret i64 3900000000 + +} + +define i32 @uint32_1_i32() #0 { +; CHECK-LABEL: uint32_1_i32: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: lis r3, -6027 +; CHECK-NEXT: ori r3, r3, 18176 +; CHECK-NEXT: blr +entry: + ret i32 -394967296 + +} + +define i64 @uint32_2() #0 { +; CHECK-LABEL: uint32_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: li r3, -1 +; CHECK-NEXT: rldic r3, r3, 0, 32 +; CHECK-NEXT: blr +entry: + ret i64 4294967295 + +} + +define i32 @uint32_2_i32() #0 { +; CHECK-LABEL: uint32_2_i32: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: li r3, -1 +; CHECK-NEXT: blr +entry: + ret i32 -1 + +} + +define i64 @uint32_3() #0 { +; CHECK-LABEL: uint32_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: li r3, 1 +; CHECK-NEXT: rldic r3, r3, 31, 32 +; CHECK-NEXT: blr +entry: + ret i64 2147483648 + +} + +define i64 @uint32_4() #0 { +; CHECK-LABEL: uint32_4: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: lis r3, -6027 +; CHECK-NEXT: ori r3, r3, 18177 +; CHECK-NEXT: rldic r3, r3, 5, 27 +; CHECK-NEXT: blr +entry: + ret i64 124800000032 + +} + +define i64 @cn_ones_1() #0 { +; CHECK-LABEL: cn_ones_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: li r3, -25633 +; CHECK-NEXT: rldicl r3, r3, 18, 30 +; CHECK-NEXT: blr +entry: + ret i64 10460594175 + +} + +define i64 @cn_ones_2() #0 { +; CHECK-LABEL: cn_ones_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: lis r3, -25638 +; CHECK-NEXT: ori r3, r3, 24575 +; CHECK-NEXT: rldicl r3, r3, 2, 30 +; CHECK-NEXT: blr +entry: + ret i64 10459119615 + +} + +define i64 @imm1() #0 { +; CHECK-LABEL: imm1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: li r3, 8465 +; CHECK-NEXT: rldic r3, r3, 28, 22 +; CHECK-NEXT: blr +entry: + ret i64 2272306135040 ;0x21110000000 +} + +define i64 @imm2() #0 { +; CHECK-LABEL: imm2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: li r3, -28536 +; CHECK-NEXT: rldicl r3, r3, 1, 32 +; CHECK-NEXT: blr +entry: + ret i64 4294910225 ;0xFFFF2111 +} + +define i64 @imm3() #0 { +; CHECK-LABEL: imm3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: li r3, -32495 +; CHECK-NEXT: rldic r3, r3, 0, 32 +; CHECK-NEXT: blr +entry: + ret i64 4294934801 ;0xFFFF8111 +} + +define i64 @imm4() #0 { +; CHECK-LABEL: imm4: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: lis r3, 33 +; CHECK-NEXT: ori r3, r3, 4352 +; CHECK-NEXT: rldimi r3, r3, 32, 0 +; CHECK-NEXT: blr +entry: + ret i64 9307365931290880 ;0x21110000211100 +} + +define i64 @imm5() #0 { +; CHECK-LABEL: imm5: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: li r3, 28685 +; CHECK-NEXT: rotldi r3, r3, 52 +; CHECK-NEXT: blr +entry: + ret i64 58546795155816455 ;0xd0000000000007 +} + +define i64 @imm6() #0 { +; CHECK-LABEL: imm6: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: lis r3, -1 +; CHECK-NEXT: ori r3, r3, 28674 +; CHECK-NEXT: rotldi r3, r3, 52 +; CHECK-NEXT: blr +entry: + ret i64 13510798882111479 ;0x2ffffffffffff7 +} + +define i64 @imm7() #0 { +; CHECK-LABEL: imm7: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: li r3, -3823 +; CHECK-NEXT: rldic r3, r3, 28, 20 +; CHECK-NEXT: blr +entry: + ret i64 16565957296128 ;0xf1110000000 +} + +define i64 @imm8() #0 { +; CHECK-LABEL: imm8: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: li r3, -7919 +; CHECK-NEXT: rldic r3, r3, 22, 22 +; CHECK-NEXT: blr +entry: + ret i64 4364831817728 ;0x3f844400000 +} + +define i64 @imm9() #0 { +; CHECK-LABEL: imm9: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: lis r3, -1 +; CHECK-NEXT: ori r3, r3, 28674 +; CHECK-NEXT: rotldi r3, r3, 52 +; CHECK-NEXT: blr +entry: + ret i64 13510798882111479 ;0x2ffffffffffff7 +} + +define i64 @imm10() #0 { +; CHECK-LABEL: imm10: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: li r3, -3823 +; CHECK-NEXT: rldic r3, r3, 28, 20 +; CHECK-NEXT: blr +entry: + ret i64 16565957296128 ;0xf1110000000 +} + +define i64 @imm11() #0 { +; CHECK-LABEL: imm11: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: li r3, -7919 +; CHECK-NEXT: rldic r3, r3, 22, 22 +; CHECK-NEXT: blr +entry: + ret i64 4364831817728 ;0x3f844400000 +} + +define i64 @imm12() #0 { +; CHECK-LABEL: imm12: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: lis r3, -29 +; CHECK-NEXT: ori r3, r3, 64577 +; CHECK-NEXT: rldic r3, r3, 12, 20 +; CHECK-NEXT: blr +entry: + ret i64 17584665923584 ;0xffe3fc41000 +} + +define i64 @imm13() #0 { +; CHECK-LABEL: imm13: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: li r3, -24847 +; CHECK-NEXT: rldicl r3, r3, 21, 27 +; CHECK-NEXT: blr +entry: + ret i64 85333114879 ;0x13de3fffff +} + +define i64 @imm13_2() #0 { +; CHECK-LABEL: imm13_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: li r3, -12424 +; CHECK-NEXT: rldicl r3, r3, 22, 26 +; CHECK-NEXT: blr +entry: + ret i64 222772068351 ;0x33de3fffff +} + +define i64 @imm14() #0 { +; CHECK-LABEL: imm14: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: li r3, -3960 +; CHECK-NEXT: rldicl r3, r3, 21, 24 +; CHECK-NEXT: blr +entry: + ret i64 1091209003007 ;0xfe111fffff +} + +define i64 @imm15() #0 { +; CHECK-LABEL: imm15: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: li r3, -8065 +; CHECK-NEXT: rldic r3, r3, 24, 0 +; CHECK-NEXT: blr +entry: + ret i64 -135308247040 +} + +define i64 @imm16() #0 { +; CHECK-LABEL: imm16: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: lis r3, -16392 +; CHECK-NEXT: ori r3, r3, 57217 +; CHECK-NEXT: rldic r3, r3, 16, 0 +; CHECK-NEXT: blr +entry: + ret i64 -70399354142720 +} + +define i64 @imm17() #0 { +; CHECK-LABEL: imm17: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: lis r3, 20344 +; CHECK-NEXT: ori r3, r3, 32847 +; CHECK-NEXT: rotldi r3, r3, 49 +; CHECK-NEXT: blr +entry: + ret i64 44473046320324337 ;0x9e000000009ef1 +} + +define i64 @imm18() #0 { +; CHECK-LABEL: imm18: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: li r3, 1 +; CHECK-NEXT: rldic r3, r3, 33, 30 +; CHECK-NEXT: oris r3, r3, 39436 +; CHECK-NEXT: ori r3, r3, 61633 +; CHECK-NEXT: blr +entry: + ret i64 11174473921 +} + +attributes #0 = { nounwind readnone }