Index: llvm/lib/Target/PowerPC/GISel/PPCInstructionSelector.cpp =================================================================== --- llvm/lib/Target/PowerPC/GISel/PPCInstructionSelector.cpp +++ llvm/lib/Target/PowerPC/GISel/PPCInstructionSelector.cpp @@ -43,6 +43,11 @@ /// selector for the patterns that do not require complex C++. bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const; + bool selectConst(MachineInstr &I, MachineBasicBlock &MBB, + MachineRegisterInfo &MRI) const; + bool selectSExt(MachineInstr &I, MachineBasicBlock &MBB, + MachineRegisterInfo &MRI) const; + const PPCInstrInfo &TII; const PPCRegisterInfo &TRI; const PPCRegisterBankInfo &RBI; @@ -91,6 +96,102 @@ return true; } +bool PPCInstructionSelector::selectConst(MachineInstr &I, + MachineBasicBlock &MBB, + MachineRegisterInfo &MRI) const { + assert(I.getOpcode() == TargetOpcode::G_CONSTANT && "Unexpected G code"); + + MachineInstr *MI = nullptr; + Register DstReg = I.getOperand(0).getReg(); + APInt ConstValue = I.getOperand(1).getCImm()->getValue(); + if (ConstValue.isIntN(16)) { + bool NeedMask = !ConstValue.isIntN(15); + uint64_t Cst = ConstValue.getZExtValue(); + Register TmpReg = + NeedMask ? MRI.createVirtualRegister(&PPC::G8RCRegClass) : DstReg; + MI = + BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::LI8), TmpReg).addImm(Cst); + if (NeedMask) { + constrainSelectedInstRegOperands(*MI, TII, TRI, RBI); + MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::RLDIC), DstReg) + .addReg(TmpReg, RegState::Kill) + .addImm(0) + .addImm(16); + } + } else if (ConstValue.isSignedIntN(16)) { + int64_t Cst = ConstValue.getSExtValue(); + MI = + BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::LI8), DstReg).addImm(Cst); + } else if (ConstValue.isSignedIntN(32)) { + int64_t Cst = ConstValue.getSExtValue(); + int64_t UpperCst = Cst >> 16; + int64_t LowerCst = Cst & 0xffff; + Register TmpReg = MRI.createVirtualRegister(&PPC::G8RCRegClass); + MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::LIS8), TmpReg) + .addImm(UpperCst); + constrainSelectedInstRegOperands(*MI, TII, TRI, RBI); + MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::ORI8), DstReg) + .addReg(TmpReg, RegState::Kill) + .addImm(LowerCst); + } else if (ConstValue.isIntN(32)) { + bool NeedMask = !ConstValue.isIntN(31); + uint64_t Cst = ConstValue.getZExtValue(); + uint64_t UpperCst = Cst >> 16; + uint64_t LowerCst = Cst & 0xffff; + Register TmpReg = + NeedMask ? MRI.createVirtualRegister(&PPC::G8RCRegClass) : DstReg; + if (UpperCst == 0xffff && (LowerCst & 0x8000) == 0x8000) { + MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::LI8), TmpReg) + .addImm(LowerCst); + } else { + Register Tmp2Reg = MRI.createVirtualRegister(&PPC::G8RCRegClass); + MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::LIS8), Tmp2Reg) + .addImm(UpperCst); + constrainSelectedInstRegOperands(*MI, TII, TRI, RBI); + MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::ORI8), TmpReg) + .addReg(Tmp2Reg, RegState::Kill) + .addImm(LowerCst); + } + if (NeedMask) { + constrainSelectedInstRegOperands(*MI, TII, TRI, RBI); + MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::RLDIC), DstReg) + .addReg(TmpReg, RegState::Kill) + .addImm(0) + .addImm(32); + } + } else + return false; + I.eraseFromParent(); + return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI); +} + +bool PPCInstructionSelector::selectSExt(MachineInstr &I, MachineBasicBlock &MBB, + MachineRegisterInfo &MRI) const { + assert(I.getOpcode() == TargetOpcode::G_SEXT_INREG && "Unexpected G code"); + + Register DstReg = I.getOperand(0).getReg(); + Register SrcReg = I.getOperand(1).getReg(); + + unsigned Opc; + switch (I.getOperand(2).getImm()) { + case 8: + Opc = PPC::EXTSB8; + break; + case 16: + Opc = PPC::EXTSH8; + break; + case 32: + Opc = PPC::EXTSW; + break; + default: + return false; + } + MachineInstr *MI = + BuildMI(MBB, I, I.getDebugLoc(), TII.get(Opc), DstReg).addReg(SrcReg); + I.eraseFromParent(); + return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI); +} + bool PPCInstructionSelector::select(MachineInstr &I) { auto &MBB = *I.getParent(); auto &MF = *MBB.getParent(); @@ -105,7 +206,15 @@ if (selectImpl(I, *CoverageInfo)) return true; - return false; + + switch (I.getOpcode()) { + case TargetOpcode::G_CONSTANT: + return selectConst(I, MBB, MRI); + case TargetOpcode::G_SEXT_INREG: + return selectSExt(I, MBB, MRI); + default: + return false; + } } namespace llvm { Index: llvm/lib/Target/PowerPC/GISel/PPCLegalizerInfo.cpp =================================================================== --- llvm/lib/Target/PowerPC/GISel/PPCLegalizerInfo.cpp +++ llvm/lib/Target/PowerPC/GISel/PPCLegalizerInfo.cpp @@ -19,11 +19,21 @@ PPCLegalizerInfo::PPCLegalizerInfo(const PPCSubtarget &ST) { using namespace TargetOpcode; + const LLT S8 = LLT::scalar(8); + const LLT S16 = LLT::scalar(16); + const LLT S32 = LLT::scalar(32); const LLT S64 = LLT::scalar(64); getActionDefinitionsBuilder(G_IMPLICIT_DEF).legalFor({S64}); getActionDefinitionsBuilder(G_CONSTANT) .legalFor({S64}) .clampScalar(0, S64, S64); + getActionDefinitionsBuilder(G_TRUNC) + .legalForCartesianProduct({S8, S16, S32}, {S64}); + getActionDefinitionsBuilder({G_ZEXT, G_SEXT, G_ANYEXT}) + .legalForCartesianProduct({S64}, {S8, S16, S32}) + .clampScalar(0, S64, S64); + getActionDefinitionsBuilder(G_SEXT_INREG) + .legalForTypeWithAnyImm({S64}); getActionDefinitionsBuilder({G_AND, G_OR, G_XOR}) .legalFor({S64}) .clampScalar(0, S64, S64); Index: llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.cpp =================================================================== --- llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.cpp +++ llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.cpp @@ -35,6 +35,8 @@ case PPC::G8RCRegClassID: case PPC::G8RC_NOX0RegClassID: case PPC::G8RC_and_G8RC_NOX0RegClassID: + case PPC::G8pRCRegClassID: + case PPC::G8pRC_with_sub_32_in_GPRC_NOR0RegClassID: return getRegBank(PPC::GPRRegBankID); default: llvm_unreachable("Unexpected register class"); @@ -70,10 +72,19 @@ case TargetOpcode::G_AND: case TargetOpcode::G_OR: case TargetOpcode::G_XOR: + // Truncation & extension ops. + case TargetOpcode::G_SEXT: + case TargetOpcode::G_ZEXT: + case TargetOpcode::G_ANYEXT: + case TargetOpcode::G_TRUNC: assert(NumOperands <= 3 && "This code is for instructions with 3 or less operands"); OperandsMapping = getValueMapping(PMI_GPR64); break; + case TargetOpcode::G_SEXT_INREG: + OperandsMapping = getOperandsMapping( + {getValueMapping(PMI_GPR64), getValueMapping(PMI_GPR64), nullptr}); + break; case TargetOpcode::G_CONSTANT: OperandsMapping = getOperandsMapping({getValueMapping(PMI_GPR64), nullptr}); break; Index: llvm/test/CodeGen/PowerPC/GlobalISel/ppc-isel-constant.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/PowerPC/GlobalISel/ppc-isel-constant.ll @@ -0,0 +1,54 @@ +; RUN: llc -mtriple ppc64le-linux -global-isel -o - < %s | FileCheck %s -check-prefixes=CHECK,LINUX + +; CHECK-LABEL: f1: +; LINUX: li 3, 1 +; LINUX: blr +define zeroext i32 @f1() { + ret i32 1 +} + +; CHECK-LABEL: f2: +; LINUX: li 3, -1 +; LINUX: rldic 3, 3, 0, 32 +; LINUX: blr +define zeroext i32 @f2() { + ret i32 -1 +} + +; CHECK-LABEL: f3: +; LINUX: li 3, 1 +; LINUX: blr +define signext i32 @f3() { + ret i32 1 +} + +; CHECK-LABEL: f4: +; LINUX: li 3, -1 +; LINUX: blr +define signext i32 @f4() { + ret i32 -1 +} + +; CHECK-LABEL: f5: +; LINUX: li 3, -52 +; LINUX: blr +define signext i32 @f5() { + ret i32 -52 +} + +; CHECK-LABEL: f6: +; LINUX: li 3, -13142 +; LINUX: rldic 3, 3, 0, 16 +; LINUX: blr +define zeroext i32 @f6() { + ret i32 52394 +} + +; CHECK-LABEL: f7: +; LINUX: lis 3, -18 +; LINUX: ori 3, 3, 56780 +; LINUX: rldic 3, 3, 0, 32 +; LINUX: blr +define zeroext i32 @f7() { + ret i32 4293844428 +} Index: llvm/test/CodeGen/PowerPC/GlobalISel/ppc-isel-logical.ll =================================================================== --- llvm/test/CodeGen/PowerPC/GlobalISel/ppc-isel-logical.ll +++ llvm/test/CodeGen/PowerPC/GlobalISel/ppc-isel-logical.ll @@ -8,6 +8,65 @@ ret i64 %res } +; CHECK-LABEL: test_andui32: +; LINUX: li 5, -1 +; LINUX: and 3, 3, 4 +; LINUX: rldic 4, 5, 0, 32 +; LINUX: and 3, 3, 4 +; LINUX: blr +define zeroext i32 @test_andui32(i32 zeroext %a, i32 zeroext %b) { + %res = and i32 %a, %b + ret i32 %res +} + +; CHECK-LABEL: test_andsi32: +; LINUX: and 3, 3, 4 +; LINUX: extsw 3, 3 +; LINUX: blr +define signext i32 @test_andsi32(i32 signext %a, i32 signext %b) { + %res = and i32 %a, %b + ret i32 %res +} + +; CHECK-LABEL: test_andui16: +; LINUX: li 5, -1 +; LINUX: and 3, 3, 4 +; LINUX: rldic 4, 5, 0, 16 +; LINUX: and 3, 3, 4 +; LINUX: blr +define zeroext i16 @test_andui16(i16 zeroext %a, i16 zeroext %b) { + %res = and i16 %a, %b + ret i16 %res +} + +; CHECK-LABEL: test_andsi16: +; LINUX: and 3, 3, 4 +; LINUX: extsh 3, 3 +; LINUX: blr +define signext i16 @test_andsi16(i16 signext %a, i16 signext %b) { + %res = and i16 %a, %b + ret i16 %res +} + +; CHECK-LABEL: test_andui8: +; LINUX: li 5, 255 +; LINUX: and 3, 3, 4 +; LINUX: and 3, 3, 5 +; LINUX: blr +define zeroext i8 @test_andui8(i8 zeroext %a, i8 zeroext %b) { + %res = and i8 %a, %b + ret i8 %res +} + +; CHECK-LABEL: test_andsi8: +; LINUX: and 3, 3, 4 +; LINUX: extsb 3, 3 +; LINUX: blr +define signext i8 @test_andsi8(i8 signext %a, i8 signext %b) { + %res = and i8 %a, %b + ret i8 %res +} + ; CHECK-LABEL: test_nandi64: ; LINUX: nand 3, 3, 4 ; LINUX: blr