diff options
-rw-r--r-- | llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp | 99 | ||||
-rw-r--r-- | llvm/test/CodeGen/AArch64/GlobalISel/arm64-instructionselect.mir | 104 |
2 files changed, 203 insertions, 0 deletions
diff --git a/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp index 4aa02f56bd2..164beacea0d 100644 --- a/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp +++ b/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp @@ -394,6 +394,105 @@ bool AArch64InstructionSelector::select(MachineInstr &I) const { // operands to use appropriate classes. return constrainSelectedInstRegOperands(I, TII, TRI, RBI); } + + case TargetOpcode::G_ANYEXT: { + const unsigned DstReg = I.getOperand(0).getReg(); + const unsigned SrcReg = I.getOperand(1).getReg(); + + const RegisterBank &RB = *RBI.getRegBank(DstReg, MRI, TRI); + + if (RB.getID() != AArch64::GPRRegBankID) { + DEBUG(dbgs() << "G_ANYEXT on bank: " << RB << ", expected: GPR\n"); + return false; + } + + const unsigned DstSize = MRI.getType(DstReg).getSizeInBits(); + + if (DstSize == 0) { + DEBUG(dbgs() << "G_ANYEXT operand has no size, not a gvreg?\n"); + return false; + } + + const TargetRegisterClass *RC = nullptr; + if (DstSize <= 32) { + RC = &AArch64::GPR32RegClass; + } else if (DstSize == 64) { + RC = &AArch64::GPR64RegClass; + } else { + DEBUG(dbgs() << "G_ANYEXT to size: " << DstSize + << ", expected: 32 or 64\n"); + return false; + } + + if (!RBI.constrainGenericRegister(SrcReg, *RC, MRI) || + !RBI.constrainGenericRegister(DstReg, *RC, MRI)) { + DEBUG(dbgs() << "Failed to constrain G_ANYEXT\n"); + return false; + } + + BuildMI(MBB, I, I.getDebugLoc(), TII.get(AArch64::COPY)) + .addDef(DstReg) + .addUse(SrcReg); + + I.eraseFromParent(); + return true; + } + + case TargetOpcode::G_ZEXT: + case TargetOpcode::G_SEXT: { + unsigned Opcode = I.getOpcode(); + const LLT DstTy = MRI.getType(I.getOperand(0).getReg()), + SrcTy = MRI.getType(I.getOperand(1).getReg()); + const bool isSigned = Opcode == TargetOpcode::G_SEXT; + const unsigned DefReg = I.getOperand(0).getReg(); + const unsigned SrcReg = I.getOperand(1).getReg(); + const RegisterBank &RB = *RBI.getRegBank(DefReg, MRI, TRI); + + if (RB.getID() != AArch64::GPRRegBankID) { + DEBUG(dbgs() << TII.getName(I.getOpcode()) << " on bank: " << RB + << ", expected: GPR\n"); + return false; + } + + MachineInstr *ExtI; + if (DstTy == LLT::scalar(64)) { + // FIXME: Can we avoid manually doing this? + if (!RBI.constrainGenericRegister(SrcReg, AArch64::GPR32RegClass, MRI)) { + DEBUG(dbgs() << "Failed to constrain " << TII.getName(Opcode) + << " operand\n"); + return false; + } + + const unsigned SrcXReg = + MRI.createVirtualRegister(&AArch64::GPR64RegClass); + BuildMI(MBB, I, I.getDebugLoc(), TII.get(AArch64::SUBREG_TO_REG)) + .addDef(SrcXReg) + .addImm(0) + .addUse(SrcReg) + .addImm(AArch64::sub_32); + + const unsigned NewOpc = isSigned ? AArch64::SBFMXri : AArch64::UBFMXri; + ExtI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(NewOpc)) + .addDef(DefReg) + .addUse(SrcXReg) + .addImm(0) + .addImm(SrcTy.getSizeInBits() - 1); + } else if (DstTy == LLT::scalar(32)) { + const unsigned NewOpc = isSigned ? AArch64::SBFMWri : AArch64::UBFMWri; + ExtI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(NewOpc)) + .addDef(DefReg) + .addUse(SrcReg) + .addImm(0) + .addImm(SrcTy.getSizeInBits() - 1); + } else { + return false; + } + + constrainSelectedInstRegOperands(*ExtI, TII, TRI, RBI); + + I.eraseFromParent(); + return true; + } } return false; diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/arm64-instructionselect.mir b/llvm/test/CodeGen/AArch64/GlobalISel/arm64-instructionselect.mir index 4846c8fa348..2d3c9f2512e 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/arm64-instructionselect.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/arm64-instructionselect.mir @@ -82,6 +82,10 @@ @var_got = external global i8 define i8* @global_got() { ret i8* undef } + + define void @anyext_gpr() { ret void } + define void @zext_gpr() { ret void } + define void @sext_gpr() { ret void } ... --- @@ -1319,3 +1323,103 @@ body: | bb.0: %0(p0) = G_GLOBAL_VALUE @var_got ... + +--- +# CHECK-LABEL: name: anyext_gpr +name: anyext_gpr +legalized: true +regBankSelected: true + +# CHECK: registers: +# CHECK-NEXT: - { id: 0, class: gpr64 } +# CHECK-NEXT: - { id: 1, class: gpr64 } +# CHECK-NEXT: - { id: 2, class: gpr32 } +# CHECK-NEXT: - { id: 3, class: gpr32 } +registers: + - { id: 0, class: gpr } + - { id: 1, class: gpr } + - { id: 2, class: gpr } + - { id: 3, class: gpr } + +# CHECK: body: +# CHECK: %0 = COPY %w0 +# CHECK: %1 = COPY %0 +# CHECK: %2 = COPY %w0 +# CHECK: %3 = COPY %2 +body: | + bb.0: + liveins: %x0 + + %0(s32) = COPY %w0 + %1(s64) = G_ANYEXT %0 + %2(s8) = COPY %w0 + %3(s32) = G_ANYEXT %2 +... + +--- +# CHECK-LABEL: name: zext_gpr +name: zext_gpr +legalized: true +regBankSelected: true + +# CHECK: registers: +# CHECK-NEXT: - { id: 0, class: gpr32 } +# CHECK-NEXT: - { id: 1, class: gpr64 } +# CHECK-NEXT: - { id: 2, class: gpr32 } +# CHECK-NEXT: - { id: 3, class: gpr32 } +# CHECK-NEXT: - { id: 4, class: gpr64 } +registers: + - { id: 0, class: gpr } + - { id: 1, class: gpr } + - { id: 2, class: gpr } + - { id: 3, class: gpr } + +# CHECK: body: +# CHECK: %0 = COPY %w0 +# CHECK: %4 = SUBREG_TO_REG 0, %0, 15 +# CHECK: %1 = UBFMXri %4, 0, 31 +# CHECK: %2 = COPY %w0 +# CHECK: %3 = UBFMWri %2, 0, 7 +body: | + bb.0: + liveins: %x0 + + %0(s32) = COPY %w0 + %1(s64) = G_ZEXT %0 + %2(s8) = COPY %w0 + %3(s32) = G_ZEXT %2 +... + +--- +# CHECK-LABEL: name: sext_gpr +name: sext_gpr +legalized: true +regBankSelected: true + +# CHECK: registers: +# CHECK-NEXT: - { id: 0, class: gpr32 } +# CHECK-NEXT: - { id: 1, class: gpr64 } +# CHECK-NEXT: - { id: 2, class: gpr32 } +# CHECK-NEXT: - { id: 3, class: gpr32 } +# CHECK-NEXT: - { id: 4, class: gpr64 } +registers: + - { id: 0, class: gpr } + - { id: 1, class: gpr } + - { id: 2, class: gpr } + - { id: 3, class: gpr } + +# CHECK: body: +# CHECK: %0 = COPY %w0 +# CHECK: %4 = SUBREG_TO_REG 0, %0, 15 +# CHECK: %1 = SBFMXri %4, 0, 31 +# CHECK: %2 = COPY %w0 +# CHECK: %3 = SBFMWri %2, 0, 7 +body: | + bb.0: + liveins: %x0 + + %0(s32) = COPY %w0 + %1(s64) = G_SEXT %0 + %2(s8) = COPY %w0 + %3(s32) = G_SEXT %2 +... |