// 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;
@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 }
...
---
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
+...