Index: llvm/lib/Target/PowerPC/GISel/PPCInstructionSelector.cpp =================================================================== --- llvm/lib/Target/PowerPC/GISel/PPCInstructionSelector.cpp +++ llvm/lib/Target/PowerPC/GISel/PPCInstructionSelector.cpp @@ -54,6 +54,10 @@ bool selectZExt(MachineInstr &I, MachineBasicBlock &MBB, MachineRegisterInfo &MRI) const; + bool selectSExt(MachineInstr &I, MachineBasicBlock &MBB, + MachineRegisterInfo &MRI) const; + bool selectTrunc(MachineInstr &I, MachineBasicBlock &MBB, + MachineRegisterInfo &MRI) const; const PPCSubtarget &STI; const PPCInstrInfo &TII; @@ -223,33 +227,127 @@ const RegisterBank *DstRegBank = RBI.getRegBank(DstReg, MRI, TRI); const Register SrcReg = I.getOperand(1).getReg(); + MachineInstr *MI; assert(DstTy.getSizeInBits() == 64 && "Unexpected dest size!"); - assert(MRI.getType(SrcReg).getSizeInBits() == 32 && "Unexpected src size!"); + if (MRI.getType(SrcReg).getSizeInBits() == 32) { + const TargetRegisterClass *ImpDefRC = getRegClass(DstTy, DstRegBank); + Register ImpDefReg = MRI.createVirtualRegister(ImpDefRC); + BuildMI(MBB, I, I.getDebugLoc(), TII.get(TargetOpcode::IMPLICIT_DEF), + ImpDefReg); + RBI.constrainGenericRegister(ImpDefReg, *ImpDefRC, MRI); + + Register NewDefReg = + MRI.createVirtualRegister(getRegClass(DstTy, DstRegBank)); + MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(TargetOpcode::INSERT_SUBREG), + NewDefReg) + .addReg(ImpDefReg) + .addReg(SrcReg) + .addImm(PPC::sub_32); + constrainSelectedInstRegOperands(*MI, TII, TRI, RBI); + + MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::RLDICL), DstReg) + .addReg(NewDefReg) + .addImm(0) + .addImm(32); + } else { + assert(MRI.getType(SrcReg).getSizeInBits() < 32 && "Unexpected src size!"); + MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::RLDICL), DstReg) + .addReg(SrcReg) + .addImm(0) + .addImm(64 - MRI.getType(SrcReg).getSizeInBits()); + } + I.eraseFromParent(); + return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI); +} - Register ImpDefReg = - MRI.createVirtualRegister(getRegClass(DstTy, DstRegBank)); - BuildMI(MBB, I, I.getDebugLoc(), TII.get(TargetOpcode::IMPLICIT_DEF), - ImpDefReg); +bool PPCInstructionSelector::selectSExt(MachineInstr &I, MachineBasicBlock &MBB, + MachineRegisterInfo &MRI) const { + assert(I.getOpcode() == TargetOpcode::G_SEXT && "Unexpected G code"); - Register NewDefReg = - MRI.createVirtualRegister(getRegClass(DstTy, DstRegBank)); - BuildMI(MBB, I, I.getDebugLoc(), TII.get(TargetOpcode::INSERT_SUBREG), - NewDefReg) - .addReg(ImpDefReg) - .addReg(SrcReg) - .addImm(PPC::sub_32); + const Register DstReg = I.getOperand(0).getReg(); + const Register SrcReg = I.getOperand(1).getReg(); - MachineInstr *MI = - BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::RLDICL), DstReg) - .addReg(NewDefReg) - .addImm(0) - .addImm(32); + const RegisterBank *DstRB = RBI.getRegBank(DstReg, MRI, TRI); + const RegisterBank *SrcRB = RBI.getRegBank(SrcReg, MRI, TRI); + if (DstRB->getID() != SrcRB->getID()) { + LLVM_DEBUG(dbgs() << TII.getName(I.getOpcode()) + << " input/output on different banks\n"); + return false; + } + // TODO Add vector support. + if (DstRB->getID() != PPC::GPRRegBankID) + return false; + + assert(MRI.getType(DstReg).getSizeInBits() == 64 && + "Unexpected size of source operand"); + + unsigned Opc; + switch (MRI.getType(SrcReg).getSizeInBits()) { + case 8: + Opc = PPC::EXTSB8; + break; + case 16: + Opc = PPC::EXTSH8; + break; + case 32: + // Opcode would be PPC::EXTSW. + llvm_unreachable("Should have been handled by TableGen"); + 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::selectTrunc(MachineInstr &I, + MachineBasicBlock &MBB, + MachineRegisterInfo &MRI) const { + assert(I.getOpcode() == TargetOpcode::G_TRUNC && "Unexpected G code"); + + const Register DstReg = I.getOperand(0).getReg(); + const Register SrcReg = I.getOperand(1).getReg(); + + const LLT DstTy = MRI.getType(DstReg); + const LLT SrcTy = MRI.getType(SrcReg); + + const RegisterBank *DstRB = RBI.getRegBank(DstReg, MRI, TRI); + const RegisterBank *SrcRB = RBI.getRegBank(SrcReg, MRI, TRI); + + if (DstRB->getID() != SrcRB->getID()) { + LLVM_DEBUG(dbgs() << TII.getName(I.getOpcode()) + << " input/output on different banks\n"); + return false; + } + // TODO Add vector support. + if (DstRB->getID() != PPC::GPRRegBankID) + return false; + + const TypeSize DstSz = DstTy.getSizeInBits(); + const TypeSize SrcSz = SrcTy.getSizeInBits(); + assert(SrcSz == 64 && "Unexpected size of source operand"); + + if (DstSz == SrcSz) { + I.setDesc(TII.get(TargetOpcode::COPY)); + return selectCopy(I, TII, MRI, TRI, RBI); + } else if (DstSz == 32 && SrcSz == 64) { + I.setDesc(TII.get(TargetOpcode::COPY)); + I.getOperand(1).setSubReg(PPC::sub_32); + return selectCopy(I, TII, MRI, TRI, RBI); + } else { + MachineInstr *MI = + BuildMI(MBB, I, I.getDebugLoc(), TII.get(PPC::RLDICL), DstReg) + .addReg(SrcReg) + .addImm(0) + .addImm(64 - DstSz); + I.eraseFromParent(); + return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI); + } +} + bool PPCInstructionSelector::select(MachineInstr &I) { auto &MBB = *I.getParent(); auto &MF = *MBB.getParent(); @@ -313,9 +411,13 @@ case TargetOpcode::G_FPTOSI: case TargetOpcode::G_FPTOUI: return selectFPToInt(I, MBB, MRI); - // G_SEXT will be selected in tb-gen pattern. + // G_SEXT will be partly selected in tb-gen pattern. + case TargetOpcode::G_SEXT: + return selectSExt(I, MBB, MRI); case TargetOpcode::G_ZEXT: return selectZExt(I, MBB, MRI); + case TargetOpcode::G_TRUNC: + return selectTrunc(I, MBB, MRI); } return false; } Index: llvm/lib/Target/PowerPC/GISel/PPCLegalizerInfo.cpp =================================================================== --- llvm/lib/Target/PowerPC/GISel/PPCLegalizerInfo.cpp +++ llvm/lib/Target/PowerPC/GISel/PPCLegalizerInfo.cpp @@ -28,6 +28,8 @@ getActionDefinitionsBuilder(G_CONSTANT) .legalFor({S32, S64}) .clampScalar(0, S64, S64); + getActionDefinitionsBuilder(G_TRUNC) + .legalForCartesianProduct({S8, S16, S32}, {S64}); getActionDefinitionsBuilder({G_ZEXT, G_SEXT}) .legalForCartesianProduct({S64}, {S8, S16, S32}) .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 @@ -84,7 +84,8 @@ case TargetOpcode::G_AND: case TargetOpcode::G_OR: case TargetOpcode::G_XOR: - // Extension ops. + // Truncation & Extension ops. + case TargetOpcode::G_TRUNC: case TargetOpcode::G_SEXT: case TargetOpcode::G_ZEXT: assert(NumOperands <= 3 && Index: llvm/test/CodeGen/PowerPC/GlobalISel/select-exttrunc.mir =================================================================== --- /dev/null +++ llvm/test/CodeGen/PowerPC/GlobalISel/select-exttrunc.mir @@ -0,0 +1,210 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -mtriple ppc64le-linux -ppc-asm-full-reg-names -global-isel \ +# RUN: -verify-machineinstrs -run-pass=instruction-select -o - %s \ +# RUN: | FileCheck %s +--- +name: trunc8zext +alignment: 16 +legalized: true +regBankSelected: true +tracksRegLiveness: true +registers: + - { id: 0, class: gpr } + - { id: 1, class: gpr } + - { id: 2, class: gpr } +liveins: + - { reg: '$x3' } +frameInfo: + maxAlignment: 1 +machineFunctionInfo: {} +body: | + bb.1.entry: + liveins: $x3 + + ; CHECK-LABEL: name: trunc8zext + ; CHECK: liveins: $x3 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:g8rc = COPY $x3 + ; CHECK-NEXT: [[RLDICL:%[0-9]+]]:g8rc = RLDICL [[COPY]], 0, 56 + ; CHECK-NEXT: [[RLDICL1:%[0-9]+]]:g8rc = RLDICL [[RLDICL]], 0, 56 + ; CHECK-NEXT: $x3 = COPY [[RLDICL1]] + ; CHECK-NEXT: BLR8 implicit $lr8, implicit $rm, implicit $x3 + %0:gpr(s64) = COPY $x3 + %1:gpr(s8) = G_TRUNC %0(s64) + %2:gpr(s64) = G_ZEXT %1(s8) + $x3 = COPY %2(s64) + BLR8 implicit $lr8, implicit $rm, implicit $x3 + +... +--- +name: trunc16zext +alignment: 16 +legalized: true +regBankSelected: true +tracksRegLiveness: true +registers: + - { id: 0, class: gpr } + - { id: 1, class: gpr } + - { id: 2, class: gpr } +liveins: + - { reg: '$x3' } +frameInfo: + maxAlignment: 1 +machineFunctionInfo: {} +body: | + bb.1.entry: + liveins: $x3 + + ; CHECK-LABEL: name: trunc16zext + ; CHECK: liveins: $x3 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:g8rc = COPY $x3 + ; CHECK-NEXT: [[RLDICL:%[0-9]+]]:g8rc = RLDICL [[COPY]], 0, 48 + ; CHECK-NEXT: [[RLDICL1:%[0-9]+]]:g8rc = RLDICL [[RLDICL]], 0, 48 + ; CHECK-NEXT: $x3 = COPY [[RLDICL1]] + ; CHECK-NEXT: BLR8 implicit $lr8, implicit $rm, implicit $x3 + %0:gpr(s64) = COPY $x3 + %1:gpr(s16) = G_TRUNC %0(s64) + %2:gpr(s64) = G_ZEXT %1(s16) + $x3 = COPY %2(s64) + BLR8 implicit $lr8, implicit $rm, implicit $x3 + +... +--- +name: trunc32zext +alignment: 16 +legalized: true +regBankSelected: true +tracksRegLiveness: true +registers: + - { id: 0, class: gpr } + - { id: 1, class: gpr } + - { id: 2, class: gpr } +liveins: + - { reg: '$x3' } +frameInfo: + maxAlignment: 1 +machineFunctionInfo: {} +body: | + bb.1.entry: + liveins: $x3 + + ; CHECK-LABEL: name: trunc32zext + ; CHECK: liveins: $x3 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:g8rc = COPY $x3 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gprc = COPY [[COPY]].sub_32 + ; CHECK-NEXT: [[DEF:%[0-9]+]]:g8rc = IMPLICIT_DEF + ; CHECK-NEXT: [[INSERT_SUBREG:%[0-9]+]]:g8rc = INSERT_SUBREG [[DEF]], [[COPY1]], %subreg.sub_32 + ; CHECK-NEXT: [[RLDICL:%[0-9]+]]:g8rc = RLDICL [[INSERT_SUBREG]], 0, 32 + ; CHECK-NEXT: $x3 = COPY [[RLDICL]] + ; CHECK-NEXT: BLR8 implicit $lr8, implicit $rm, implicit $x3 + %0:gpr(s64) = COPY $x3 + %1:gpr(s32) = G_TRUNC %0(s64) + %2:gpr(s64) = G_ZEXT %1(s32) + $x3 = COPY %2(s64) + BLR8 implicit $lr8, implicit $rm, implicit $x3 + +... +--- +name: trunc8sext +alignment: 16 +legalized: true +regBankSelected: true +tracksRegLiveness: true +registers: + - { id: 0, class: gpr } + - { id: 1, class: gpr } + - { id: 2, class: gpr } +liveins: + - { reg: '$x3' } +frameInfo: + maxAlignment: 1 +machineFunctionInfo: {} +body: | + bb.1.entry: + liveins: $x3 + + ; CHECK-LABEL: name: trunc8sext + ; CHECK: liveins: $x3 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:g8rc = COPY $x3 + ; CHECK-NEXT: [[RLDICL:%[0-9]+]]:g8rc = RLDICL [[COPY]], 0, 56 + ; CHECK-NEXT: [[EXTSB8_:%[0-9]+]]:g8rc = EXTSB8 [[RLDICL]] + ; CHECK-NEXT: $x3 = COPY [[EXTSB8_]] + ; CHECK-NEXT: BLR8 implicit $lr8, implicit $rm, implicit $x3 + %0:gpr(s64) = COPY $x3 + %1:gpr(s8) = G_TRUNC %0(s64) + %2:gpr(s64) = G_SEXT %1(s8) + $x3 = COPY %2(s64) + BLR8 implicit $lr8, implicit $rm, implicit $x3 + +... +--- +name: trunc16sext +alignment: 16 +legalized: true +regBankSelected: true +tracksRegLiveness: true +registers: + - { id: 0, class: gpr } + - { id: 1, class: gpr } + - { id: 2, class: gpr } +liveins: + - { reg: '$x3' } +frameInfo: + maxAlignment: 1 +machineFunctionInfo: {} +body: | + bb.1.entry: + liveins: $x3 + + ; CHECK-LABEL: name: trunc16sext + ; CHECK: liveins: $x3 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:g8rc = COPY $x3 + ; CHECK-NEXT: [[RLDICL:%[0-9]+]]:g8rc = RLDICL [[COPY]], 0, 48 + ; CHECK-NEXT: [[EXTSH8_:%[0-9]+]]:g8rc = EXTSH8 [[RLDICL]] + ; CHECK-NEXT: $x3 = COPY [[EXTSH8_]] + ; CHECK-NEXT: BLR8 implicit $lr8, implicit $rm, implicit $x3 + %0:gpr(s64) = COPY $x3 + %1:gpr(s16) = G_TRUNC %0(s64) + %2:gpr(s64) = G_SEXT %1(s16) + $x3 = COPY %2(s64) + BLR8 implicit $lr8, implicit $rm, implicit $x3 + +... +--- +name: trunc32sext +alignment: 16 +legalized: true +regBankSelected: true +tracksRegLiveness: true +registers: + - { id: 0, class: gpr } + - { id: 1, class: gpr } + - { id: 2, class: gpr } +liveins: + - { reg: '$x3' } +frameInfo: + maxAlignment: 1 +machineFunctionInfo: {} +body: | + bb.1.entry: + liveins: $x3 + + ; CHECK-LABEL: name: trunc32sext + ; CHECK: liveins: $x3 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:g8rc = COPY $x3 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gprc = COPY [[COPY]].sub_32 + ; CHECK-NEXT: [[EXTSW_32_64_:%[0-9]+]]:g8rc = EXTSW_32_64 [[COPY1]] + ; CHECK-NEXT: $x3 = COPY [[EXTSW_32_64_]] + ; CHECK-NEXT: BLR8 implicit $lr8, implicit $rm, implicit $x3 + %0:gpr(s64) = COPY $x3 + %1:gpr(s32) = G_TRUNC %0(s64) + %2:gpr(s64) = G_SEXT %1(s32) + $x3 = COPY %2(s64) + BLR8 implicit $lr8, implicit $rm, implicit $x3 + +...