GlobalISel: support selection of extend operations.
authorTim Northover <tnorthover@apple.com>
Tue, 11 Oct 2016 20:50:21 +0000 (20:50 +0000)
committerTim Northover <tnorthover@apple.com>
Tue, 11 Oct 2016 20:50:21 +0000 (20:50 +0000)
Patch mostly by Ahmed Bougaca.

llvm-svn: 283937

llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp
llvm/test/CodeGen/AArch64/GlobalISel/arm64-instructionselect.mir

index 4aa02f5..164beac 100644 (file)
@@ -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;
index 4846c8f..2d3c9f2 100644 (file)
 
   @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
+...