[llvm] r307365 - [ARM] GlobalISel: Select hard G_FCMP for s32

Diana Picus via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 7 01:39:04 PDT 2017


Author: rovka
Date: Fri Jul  7 01:39:04 2017
New Revision: 307365

URL: http://llvm.org/viewvc/llvm-project?rev=307365&view=rev
Log:
[ARM] GlobalISel: Select hard G_FCMP for s32

We lower to a sequence consisting of:
- MOVi 0 into a register
- VCMPS to do the actual comparison and set the VFP flags
- FMSTAT to move the flags out of the VFP unit
- MOVCCi to either use the "zero register" that we have previously set
  with the MOVi, or move 1 into the result register, based on the values
  of the flags

As was the case with soft-float, for some predicates (one, ueq) we
actually need two comparisons instead of just one. When that happens, we
generate two VCMPS-FMSTAT-MOVCCi sequences and chain them by means of
using the result of the first MOVCCi as the "zero register" for the
second one. This is a bit overkill, since one comparison followed by
two non-flag-setting conditional moves should be enough. In any case,
the backend manages to CSE one of the comparisons away so it doesn't
matter much.

Note that unlike SelectionDAG and FastISel, we always use VCMPS, and not
VCMPES. This makes the code a lot simpler, and it also seems correct
since the LLVM Lang Ref defines simple true/false returns if the
operands are QNaN's. For SNaN's, even VCMPS throws an Invalid Operand
exception, so they won't be slipping through unnoticed.

Implementation-wise, this introduces a template so we can share the same
code that we use for handling integer comparisons, since the only
differences are in the details (exact opcodes to be used etc). Hopefully
this will be easy to extend to s64 G_FCMP.

Modified:
    llvm/trunk/lib/Target/ARM/ARMInstructionSelector.cpp
    llvm/trunk/test/CodeGen/ARM/GlobalISel/arm-instruction-select-cmp.mir
    llvm/trunk/test/CodeGen/ARM/GlobalISel/arm-isel-fp.ll

Modified: llvm/trunk/lib/Target/ARM/ARMInstructionSelector.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstructionSelector.cpp?rev=307365&r1=307364&r2=307365&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/ARMInstructionSelector.cpp (original)
+++ llvm/trunk/lib/Target/ARM/ARMInstructionSelector.cpp Fri Jul  7 01:39:04 2017
@@ -44,9 +44,12 @@ public:
 private:
   bool selectImpl(MachineInstr &I) const;
 
-  bool selectICmp(MachineInstrBuilder &MIB, const ARMBaseInstrInfo &TII,
-                  MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
-                  const RegisterBankInfo &RBI) const;
+  template <typename T> struct CmpHelper;
+
+  template <typename T>
+  bool selectCmp(MachineInstrBuilder &MIB, const ARMBaseInstrInfo &TII,
+                 MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
+                 const RegisterBankInfo &RBI) const;
 
   bool selectSelect(MachineInstrBuilder &MIB, const ARMBaseInstrInfo &TII,
                     MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
@@ -253,101 +256,266 @@ static unsigned selectLoadStoreOpCode(un
   return Opc;
 }
 
-static ARMCC::CondCodes getComparePred(CmpInst::Predicate Pred) {
+// When lowering comparisons, we sometimes need to perform two compares instead
+// of just one. Get the condition codes for both comparisons. If only one is
+// needed, the second member of the pair is ARMCC::AL.
+static std::pair<ARMCC::CondCodes, ARMCC::CondCodes>
+getComparePreds(CmpInst::Predicate Pred) {
+  std::pair<ARMCC::CondCodes, ARMCC::CondCodes> Preds = {ARMCC::AL, ARMCC::AL};
   switch (Pred) {
-  // Needs two compares...
   case CmpInst::FCMP_ONE:
+    Preds = {ARMCC::GT, ARMCC::MI};
+    break;
   case CmpInst::FCMP_UEQ:
-  default:
-    // AL is our "false" for now. The other two need more compares.
-    return ARMCC::AL;
+    Preds = {ARMCC::EQ, ARMCC::VS};
+    break;
   case CmpInst::ICMP_EQ:
   case CmpInst::FCMP_OEQ:
-    return ARMCC::EQ;
+    Preds.first = ARMCC::EQ;
+    break;
   case CmpInst::ICMP_SGT:
   case CmpInst::FCMP_OGT:
-    return ARMCC::GT;
+    Preds.first = ARMCC::GT;
+    break;
   case CmpInst::ICMP_SGE:
   case CmpInst::FCMP_OGE:
-    return ARMCC::GE;
+    Preds.first = ARMCC::GE;
+    break;
   case CmpInst::ICMP_UGT:
   case CmpInst::FCMP_UGT:
-    return ARMCC::HI;
+    Preds.first = ARMCC::HI;
+    break;
   case CmpInst::FCMP_OLT:
-    return ARMCC::MI;
+    Preds.first = ARMCC::MI;
+    break;
   case CmpInst::ICMP_ULE:
   case CmpInst::FCMP_OLE:
-    return ARMCC::LS;
+    Preds.first = ARMCC::LS;
+    break;
   case CmpInst::FCMP_ORD:
-    return ARMCC::VC;
+    Preds.first = ARMCC::VC;
+    break;
   case CmpInst::FCMP_UNO:
-    return ARMCC::VS;
+    Preds.first = ARMCC::VS;
+    break;
   case CmpInst::FCMP_UGE:
-    return ARMCC::PL;
+    Preds.first = ARMCC::PL;
+    break;
   case CmpInst::ICMP_SLT:
   case CmpInst::FCMP_ULT:
-    return ARMCC::LT;
+    Preds.first = ARMCC::LT;
+    break;
   case CmpInst::ICMP_SLE:
   case CmpInst::FCMP_ULE:
-    return ARMCC::LE;
+    Preds.first = ARMCC::LE;
+    break;
   case CmpInst::FCMP_UNE:
   case CmpInst::ICMP_NE:
-    return ARMCC::NE;
+    Preds.first = ARMCC::NE;
+    break;
   case CmpInst::ICMP_UGE:
-    return ARMCC::HS;
+    Preds.first = ARMCC::HS;
+    break;
   case CmpInst::ICMP_ULT:
-    return ARMCC::LO;
+    Preds.first = ARMCC::LO;
+    break;
+  default:
+    break;
   }
+  assert(Preds.first != ARMCC::AL && "No comparisons needed?");
+  return Preds;
 }
 
-bool ARMInstructionSelector::selectICmp(MachineInstrBuilder &MIB,
-                                        const ARMBaseInstrInfo &TII,
-                                        MachineRegisterInfo &MRI,
-                                        const TargetRegisterInfo &TRI,
-                                        const RegisterBankInfo &RBI) const {
-  auto &MBB = *MIB->getParent();
-  auto InsertBefore = std::next(MIB->getIterator());
-  auto &DebugLoc = MIB->getDebugLoc();
+template <typename T> struct ARMInstructionSelector::CmpHelper {
+  CmpHelper(const ARMInstructionSelector &Selector, MachineInstrBuilder &MIB,
+            const ARMBaseInstrInfo &TII, MachineRegisterInfo &MRI,
+            const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
+      : MBB(*MIB->getParent()), InsertBefore(std::next(MIB->getIterator())),
+        DebugLoc(MIB->getDebugLoc()), TII(TII), MRI(MRI), TRI(TRI), RBI(RBI),
+        Selector(Selector) {}
+
+  // The opcode used for performing the comparison.
+  static const unsigned ComparisonOpcode;
+
+  // The opcode used for reading the flags set by the comparison. May be
+  // ARM::INSTRUCTION_LIST_END if we don't need to read the flags.
+  static const unsigned ReadFlagsOpcode;
+
+  // The opcode used for selecting the result register, based on the value
+  // of the flags.
+  static const unsigned SetResultOpcode = ARM::MOVCCi;
+
+  // The assumed register bank ID for the operands.
+  static const unsigned OperandRegBankID;
+
+  // The assumed register bank ID for the result.
+  static const unsigned ResultRegBankID = ARM::GPRRegBankID;
+
+  unsigned getZeroRegister() {
+    unsigned Reg = MRI.createVirtualRegister(&ARM::GPRRegClass);
+    putConstant(Reg, 0);
+    return Reg;
+  }
 
-  // Move 0 into the result register.
-  auto Mov0I = BuildMI(MBB, InsertBefore, DebugLoc, TII.get(ARM::MOVi))
-                   .addDef(MRI.createVirtualRegister(&ARM::GPRRegClass))
-                   .addImm(0)
-                   .add(predOps(ARMCC::AL))
-                   .add(condCodeOp());
-  if (!constrainSelectedInstRegOperands(*Mov0I, TII, TRI, RBI))
-    return false;
+  void putConstant(unsigned DestReg, unsigned Constant) {
+    (void)BuildMI(MBB, InsertBefore, DebugLoc, TII.get(ARM::MOVi))
+        .addDef(DestReg)
+        .addImm(Constant)
+        .add(predOps(ARMCC::AL))
+        .add(condCodeOp());
+  }
 
-  // Perform the comparison.
-  auto LHSReg = MIB->getOperand(2).getReg();
-  auto RHSReg = MIB->getOperand(3).getReg();
-  assert(MRI.getType(LHSReg) == MRI.getType(RHSReg) &&
-         MRI.getType(LHSReg).getSizeInBits() == 32 &&
-         MRI.getType(RHSReg).getSizeInBits() == 32 &&
-         "Unsupported types for comparison operation");
-  auto CmpI = BuildMI(MBB, InsertBefore, DebugLoc, TII.get(ARM::CMPrr))
-                  .addUse(LHSReg)
-                  .addUse(RHSReg)
-                  .add(predOps(ARMCC::AL));
-  if (!constrainSelectedInstRegOperands(*CmpI, TII, TRI, RBI))
-    return false;
+  bool insertComparison(unsigned ResReg, ARMCC::CondCodes Cond, unsigned LHSReg,
+                        unsigned RHSReg, unsigned PrevRes) {
+
+    // Perform the comparison.
+    auto CmpI = BuildMI(MBB, InsertBefore, DebugLoc, TII.get(ComparisonOpcode))
+                    .addUse(LHSReg)
+                    .addUse(RHSReg)
+                    .add(predOps(ARMCC::AL));
+    if (!Selector.constrainSelectedInstRegOperands(*CmpI, TII, TRI, RBI))
+      return false;
+
+    // Read the comparison flags (if necessary).
+    if (ReadFlagsOpcode != ARM::INSTRUCTION_LIST_END) {
+      auto ReadI =
+          BuildMI(MBB, InsertBefore, DebugLoc, TII.get(ReadFlagsOpcode))
+              .add(predOps(ARMCC::AL));
+      if (!Selector.constrainSelectedInstRegOperands(*ReadI, TII, TRI, RBI))
+        return false;
+    }
+
+    // Select either 1 or the previous result based on the value of the flags.
+    auto Mov1I = BuildMI(MBB, InsertBefore, DebugLoc, TII.get(SetResultOpcode))
+                     .addDef(ResReg)
+                     .addUse(PrevRes)
+                     .addImm(1)
+                     .add(predOps(Cond, ARM::CPSR));
+    if (!Selector.constrainSelectedInstRegOperands(*Mov1I, TII, TRI, RBI))
+      return false;
+
+    return true;
+  }
+
+  bool validateOpRegs(unsigned LHSReg, unsigned RHSReg) {
+    return MRI.getType(LHSReg) == MRI.getType(RHSReg) &&
+           validateOpReg(LHSReg, MRI, TRI, RBI) &&
+           validateOpReg(RHSReg, MRI, TRI, RBI);
+  }
+
+  bool validateResReg(unsigned ResReg) {
+    if (MRI.getType(ResReg).getSizeInBits() != 1) {
+      DEBUG(dbgs() << "Unsupported size for comparison operand");
+      return false;
+    }
+
+    if (RBI.getRegBank(ResReg, MRI, TRI)->getID() != ResultRegBankID) {
+      DEBUG(dbgs() << "Unsupported register bank for comparison operand");
+      return false;
+    }
+
+    return true;
+  }
+
+private:
+  bool validateOpReg(unsigned OpReg, MachineRegisterInfo &MRI,
+                     const TargetRegisterInfo &TRI,
+                     const RegisterBankInfo &RBI) {
+    if (MRI.getType(OpReg).getSizeInBits() != 32) {
+      DEBUG(dbgs() << "Unsupported size for comparison operand");
+      return false;
+    }
+
+    if (RBI.getRegBank(OpReg, MRI, TRI)->getID() != OperandRegBankID) {
+      DEBUG(dbgs() << "Unsupported register bank for comparison operand");
+      return false;
+    }
+
+    return true;
+  }
+
+  MachineBasicBlock &MBB;
+  MachineBasicBlock::instr_iterator InsertBefore;
+  const DebugLoc &DebugLoc;
+
+  const ARMBaseInstrInfo &TII;
+  MachineRegisterInfo &MRI;
+  const TargetRegisterInfo &TRI;
+  const RegisterBankInfo &RBI;
+
+  const ARMInstructionSelector &Selector;
+};
+
+// Specialize the opcode to be used for comparing different types of operands.
+template <>
+const unsigned ARMInstructionSelector::CmpHelper<int>::ComparisonOpcode =
+    ARM::CMPrr;
+template <>
+const unsigned ARMInstructionSelector::CmpHelper<float>::ComparisonOpcode =
+    ARM::VCMPS;
+
+// Specialize the opcode to be used for reading the comparison flags for
+// different types of operands.
+template <>
+const unsigned ARMInstructionSelector::CmpHelper<int>::ReadFlagsOpcode =
+    ARM::INSTRUCTION_LIST_END;
+template <>
+const unsigned ARMInstructionSelector::CmpHelper<float>::ReadFlagsOpcode =
+    ARM::FMSTAT;
+
+// Specialize the register bank where the operands of the comparison are assumed
+// to live.
+template <>
+const unsigned ARMInstructionSelector::CmpHelper<int>::OperandRegBankID =
+    ARM::GPRRegBankID;
+template <>
+const unsigned ARMInstructionSelector::CmpHelper<float>::OperandRegBankID =
+    ARM::FPRRegBankID;
+
+template <typename T>
+bool ARMInstructionSelector::selectCmp(MachineInstrBuilder &MIB,
+                                       const ARMBaseInstrInfo &TII,
+                                       MachineRegisterInfo &MRI,
+                                       const TargetRegisterInfo &TRI,
+                                       const RegisterBankInfo &RBI) const {
+  auto Helper = CmpHelper<T>(*this, MIB, TII, MRI, TRI, RBI);
 
-  // Move 1 into the result register if the flags say so.
   auto ResReg = MIB->getOperand(0).getReg();
+  if (!Helper.validateResReg(ResReg))
+    return false;
+
   auto Cond =
       static_cast<CmpInst::Predicate>(MIB->getOperand(1).getPredicate());
-  auto ARMCond = getComparePred(Cond);
-  if (ARMCond == ARMCC::AL)
-    return false;
+  if (Cond == CmpInst::FCMP_TRUE || Cond == CmpInst::FCMP_FALSE) {
+    Helper.putConstant(ResReg, Cond == CmpInst::FCMP_TRUE ? 1 : 0);
+    MIB->eraseFromParent();
+    return true;
+  }
 
-  auto Mov1I = BuildMI(MBB, InsertBefore, DebugLoc, TII.get(ARM::MOVCCi))
-                   .addDef(ResReg)
-                   .addUse(Mov0I->getOperand(0).getReg())
-                   .addImm(1)
-                   .add(predOps(ARMCond, ARM::CPSR));
-  if (!constrainSelectedInstRegOperands(*Mov1I, TII, TRI, RBI))
+  auto LHSReg = MIB->getOperand(2).getReg();
+  auto RHSReg = MIB->getOperand(3).getReg();
+  if (!Helper.validateOpRegs(LHSReg, RHSReg))
     return false;
 
+  auto ARMConds = getComparePreds(Cond);
+  auto ZeroReg = Helper.getZeroRegister();
+
+  if (ARMConds.second == ARMCC::AL) {
+    // Simple case, we only need one comparison and we're done.
+    if (!Helper.insertComparison(ResReg, ARMConds.first, LHSReg, RHSReg,
+                                 ZeroReg))
+      return false;
+  } else {
+    // Not so simple, we need two successive comparisons.
+    auto IntermediateRes = MRI.createVirtualRegister(&ARM::GPRRegClass);
+    if (!Helper.insertComparison(IntermediateRes, ARMConds.first, LHSReg,
+                                 RHSReg, ZeroReg))
+      return false;
+    if (!Helper.insertComparison(ResReg, ARMConds.second, LHSReg, RHSReg,
+                                 IntermediateRes))
+      return false;
+  }
+
   MIB->eraseFromParent();
   return true;
 }
@@ -496,10 +664,13 @@ bool ARMInstructionSelector::select(Mach
     I.setDesc(TII.get(COPY));
     return selectCopy(I, TII, MRI, TRI, RBI);
   }
-  case G_ICMP:
-    return selectICmp(MIB, TII, MRI, TRI, RBI);
   case G_SELECT:
     return selectSelect(MIB, TII, MRI, TRI, RBI);
+  case G_ICMP:
+    return selectCmp<int>(MIB, TII, MRI, TRI, RBI);
+  case G_FCMP:
+    assert(TII.getSubtarget().hasVFP2() && "Can't select fcmp without VFP");
+    return selectCmp<float>(MIB, TII, MRI, TRI, RBI);
   case G_GEP:
     I.setDesc(TII.get(ARM::ADDrr));
     MIB.add(predOps(ARMCC::AL)).add(condCodeOp());

Modified: llvm/trunk/test/CodeGen/ARM/GlobalISel/arm-instruction-select-cmp.mir
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/GlobalISel/arm-instruction-select-cmp.mir?rev=307365&r1=307364&r2=307365&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/ARM/GlobalISel/arm-instruction-select-cmp.mir (original)
+++ llvm/trunk/test/CodeGen/ARM/GlobalISel/arm-instruction-select-cmp.mir Fri Jul  7 01:39:04 2017
@@ -10,6 +10,27 @@
   define void @test_icmp_sge_s32() { ret void }
   define void @test_icmp_slt_s32() { ret void }
   define void @test_icmp_sle_s32() { ret void }
+
+  define void @test_fcmp_true_s32() #0 { ret void }
+  define void @test_fcmp_false_s32() #0 { ret void }
+
+  define void @test_fcmp_oeq_s32() #0 { ret void }
+  define void @test_fcmp_ogt_s32() #0 { ret void }
+  define void @test_fcmp_oge_s32() #0 { ret void }
+  define void @test_fcmp_olt_s32() #0 { ret void }
+  define void @test_fcmp_ole_s32() #0 { ret void }
+  define void @test_fcmp_ord_s32() #0 { ret void }
+  define void @test_fcmp_ugt_s32() #0 { ret void }
+  define void @test_fcmp_uge_s32() #0 { ret void }
+  define void @test_fcmp_ult_s32() #0 { ret void }
+  define void @test_fcmp_ule_s32() #0 { ret void }
+  define void @test_fcmp_une_s32() #0 { ret void }
+  define void @test_fcmp_uno_s32() #0 { ret void }
+
+  define void @test_fcmp_one_s32() #0 { ret void }
+  define void @test_fcmp_ueq_s32() #0 { ret void }
+
+  attributes #0 = { "target-features"="+vfp2" }
 ...
 ---
 name:            test_icmp_eq_s32
@@ -364,6 +385,592 @@ body:             |
 
     %3(s32) = G_ZEXT %2(s1)
     ; CHECK: [[RET:%[0-9]+]] = ANDri [[RES]], 1, 14, _, _
+
+    %r0 = COPY %3(s32)
+    ; CHECK: %r0 = COPY [[RET]]
+
+    BX_RET 14, _, implicit %r0
+    ; CHECK: BX_RET 14, _, implicit %r0
+...
+---
+name:            test_fcmp_true_s32
+# CHECK-LABEL: name: test_fcmp_true_s32
+legalized:       true
+regBankSelected: true
+selected:        false
+# CHECK: selected: true
+registers:
+  - { id: 0, class: fprb }
+  - { id: 1, class: fprb }
+  - { id: 2, class: gprb }
+  - { id: 3, class: gprb }
+body:             |
+  bb.0:
+    liveins: %s0, %s1
+
+    %0(s32) = COPY %s0
+    %1(s32) = COPY %s1
+
+    %2(s1) = G_FCMP floatpred(true),  %0(s32), %1
+    ; CHECK: [[RES:%[0-9]+]] = MOVi 1, 14, _, _
+
+    %3(s32) = G_ZEXT %2(s1)
+    ; CHECK: [[RET:%[0-9]+]] = ANDri [[RES]], 1, 14, _, _
+
+    %r0 = COPY %3(s32)
+    ; CHECK: %r0 = COPY [[RET]]
+
+    BX_RET 14, _, implicit %r0
+    ; CHECK: BX_RET 14, _, implicit %r0
+...
+---
+name:            test_fcmp_false_s32
+# CHECK-LABEL: name: test_fcmp_false_s32
+legalized:       true
+regBankSelected: true
+selected:        false
+# CHECK: selected: true
+registers:
+  - { id: 0, class: fprb }
+  - { id: 1, class: fprb }
+  - { id: 2, class: gprb }
+  - { id: 3, class: gprb }
+body:             |
+  bb.0:
+    liveins: %s0, %s1
+
+    %0(s32) = COPY %s0
+    %1(s32) = COPY %s1
+
+    %2(s1) = G_FCMP floatpred(false),  %0(s32), %1
+    ; CHECK: [[RES:%[0-9]+]] = MOVi 0, 14, _, _
+
+    %3(s32) = G_ZEXT %2(s1)
+    ; CHECK: [[RET:%[0-9]+]] = ANDri [[RES]], 1, 14, _, _
+
+    %r0 = COPY %3(s32)
+    ; CHECK: %r0 = COPY [[RET]]
+
+    BX_RET 14, _, implicit %r0
+    ; CHECK: BX_RET 14, _, implicit %r0
+...
+---
+name:            test_fcmp_oeq_s32
+# CHECK-LABEL: name: test_fcmp_oeq_s32
+legalized:       true
+regBankSelected: true
+selected:        false
+# CHECK: selected: true
+registers:
+  - { id: 0, class: fprb }
+  - { id: 1, class: fprb }
+  - { id: 2, class: gprb }
+  - { id: 3, class: gprb }
+body:             |
+  bb.0:
+    liveins: %s0, %s1
+
+    %0(s32) = COPY %s0
+    ; CHECK: [[VREGX:%[0-9]+]] = COPY %s0
+
+    %1(s32) = COPY %s1
+    ; CHECK: [[VREGY:%[0-9]+]] = COPY %s1
+
+    %2(s1) = G_FCMP floatpred(oeq),  %0(s32), %1
+    ; CHECK: [[ZERO:%[0-9]+]] = MOVi 0, 14, _, _
+    ; CHECK: VCMPS [[VREGX]], [[VREGY]], 14, _, implicit-def %fpscr_nzcv
+    ; CHECK: FMSTAT 14, _, implicit-def %cpsr, implicit %fpscr_nzcv
+    ; CHECK: [[RES:%[0-9]+]] = MOVCCi [[ZERO]], 1, 0, %cpsr
+
+    %3(s32) = G_ZEXT %2(s1)
+    ; CHECK: [[RET:%[0-9]+]] = ANDri [[RES]], 1, 14, _, _
+
+    %r0 = COPY %3(s32)
+    ; CHECK: %r0 = COPY [[RET]]
+
+    BX_RET 14, _, implicit %r0
+    ; CHECK: BX_RET 14, _, implicit %r0
+...
+---
+name:            test_fcmp_ogt_s32
+# CHECK-LABEL: name: test_fcmp_ogt_s32
+legalized:       true
+regBankSelected: true
+selected:        false
+# CHECK: selected: true
+registers:
+  - { id: 0, class: fprb }
+  - { id: 1, class: fprb }
+  - { id: 2, class: gprb }
+  - { id: 3, class: gprb }
+body:             |
+  bb.0:
+    liveins: %s0, %s1
+
+    %0(s32) = COPY %s0
+    ; CHECK: [[VREGX:%[0-9]+]] = COPY %s0
+
+    %1(s32) = COPY %s1
+    ; CHECK: [[VREGY:%[0-9]+]] = COPY %s1
+
+    %2(s1) = G_FCMP floatpred(ogt),  %0(s32), %1
+    ; CHECK: [[ZERO:%[0-9]+]] = MOVi 0, 14, _, _
+    ; CHECK: VCMPS [[VREGX]], [[VREGY]], 14, _, implicit-def %fpscr_nzcv
+    ; CHECK: FMSTAT 14, _, implicit-def %cpsr, implicit %fpscr_nzcv
+    ; CHECK: [[RES:%[0-9]+]] = MOVCCi [[ZERO]], 1, 12, %cpsr
+
+    %3(s32) = G_ZEXT %2(s1)
+    ; CHECK: [[RET:%[0-9]+]] = ANDri [[RES]], 1, 14, _, _
+
+    %r0 = COPY %3(s32)
+    ; CHECK: %r0 = COPY [[RET]]
+
+    BX_RET 14, _, implicit %r0
+    ; CHECK: BX_RET 14, _, implicit %r0
+...
+---
+name:            test_fcmp_oge_s32
+# CHECK-LABEL: name: test_fcmp_oge_s32
+legalized:       true
+regBankSelected: true
+selected:        false
+# CHECK: selected: true
+registers:
+  - { id: 0, class: fprb }
+  - { id: 1, class: fprb }
+  - { id: 2, class: gprb }
+  - { id: 3, class: gprb }
+body:             |
+  bb.0:
+    liveins: %s0, %s1
+
+    %0(s32) = COPY %s0
+    ; CHECK: [[VREGX:%[0-9]+]] = COPY %s0
+
+    %1(s32) = COPY %s1
+    ; CHECK: [[VREGY:%[0-9]+]] = COPY %s1
+
+    %2(s1) = G_FCMP floatpred(oge),  %0(s32), %1
+    ; CHECK: [[ZERO:%[0-9]+]] = MOVi 0, 14, _, _
+    ; CHECK: VCMPS [[VREGX]], [[VREGY]], 14, _, implicit-def %fpscr_nzcv
+    ; CHECK: FMSTAT 14, _, implicit-def %cpsr, implicit %fpscr_nzcv
+    ; CHECK: [[RES:%[0-9]+]] = MOVCCi [[ZERO]], 1, 10, %cpsr
+
+    %3(s32) = G_ZEXT %2(s1)
+    ; CHECK: [[RET:%[0-9]+]] = ANDri [[RES]], 1, 14, _, _
+
+    %r0 = COPY %3(s32)
+    ; CHECK: %r0 = COPY [[RET]]
+
+    BX_RET 14, _, implicit %r0
+    ; CHECK: BX_RET 14, _, implicit %r0
+...
+---
+name:            test_fcmp_olt_s32
+# CHECK-LABEL: name: test_fcmp_olt_s32
+legalized:       true
+regBankSelected: true
+selected:        false
+# CHECK: selected: true
+registers:
+  - { id: 0, class: fprb }
+  - { id: 1, class: fprb }
+  - { id: 2, class: gprb }
+  - { id: 3, class: gprb }
+body:             |
+  bb.0:
+    liveins: %s0, %s1
+
+    %0(s32) = COPY %s0
+    ; CHECK: [[VREGX:%[0-9]+]] = COPY %s0
+
+    %1(s32) = COPY %s1
+    ; CHECK: [[VREGY:%[0-9]+]] = COPY %s1
+
+    %2(s1) = G_FCMP floatpred(olt),  %0(s32), %1
+    ; CHECK: [[ZERO:%[0-9]+]] = MOVi 0, 14, _, _
+    ; CHECK: VCMPS [[VREGX]], [[VREGY]], 14, _, implicit-def %fpscr_nzcv
+    ; CHECK: FMSTAT 14, _, implicit-def %cpsr, implicit %fpscr_nzcv
+    ; CHECK: [[RES:%[0-9]+]] = MOVCCi [[ZERO]], 1, 4, %cpsr
+
+    %3(s32) = G_ZEXT %2(s1)
+    ; CHECK: [[RET:%[0-9]+]] = ANDri [[RES]], 1, 14, _, _
+
+    %r0 = COPY %3(s32)
+    ; CHECK: %r0 = COPY [[RET]]
+
+    BX_RET 14, _, implicit %r0
+    ; CHECK: BX_RET 14, _, implicit %r0
+...
+---
+name:            test_fcmp_ole_s32
+# CHECK-LABEL: name: test_fcmp_ole_s32
+legalized:       true
+regBankSelected: true
+selected:        false
+# CHECK: selected: true
+registers:
+  - { id: 0, class: fprb }
+  - { id: 1, class: fprb }
+  - { id: 2, class: gprb }
+  - { id: 3, class: gprb }
+body:             |
+  bb.0:
+    liveins: %s0, %s1
+
+    %0(s32) = COPY %s0
+    ; CHECK: [[VREGX:%[0-9]+]] = COPY %s0
+
+    %1(s32) = COPY %s1
+    ; CHECK: [[VREGY:%[0-9]+]] = COPY %s1
+
+    %2(s1) = G_FCMP floatpred(ole),  %0(s32), %1
+    ; CHECK: [[ZERO:%[0-9]+]] = MOVi 0, 14, _, _
+    ; CHECK: VCMPS [[VREGX]], [[VREGY]], 14, _, implicit-def %fpscr_nzcv
+    ; CHECK: FMSTAT 14, _, implicit-def %cpsr, implicit %fpscr_nzcv
+    ; CHECK: [[RES:%[0-9]+]] = MOVCCi [[ZERO]], 1, 9, %cpsr
+
+    %3(s32) = G_ZEXT %2(s1)
+    ; CHECK: [[RET:%[0-9]+]] = ANDri [[RES]], 1, 14, _, _
+
+    %r0 = COPY %3(s32)
+    ; CHECK: %r0 = COPY [[RET]]
+
+    BX_RET 14, _, implicit %r0
+    ; CHECK: BX_RET 14, _, implicit %r0
+...
+---
+name:            test_fcmp_ord_s32
+# CHECK-LABEL: name: test_fcmp_ord_s32
+legalized:       true
+regBankSelected: true
+selected:        false
+# CHECK: selected: true
+registers:
+  - { id: 0, class: fprb }
+  - { id: 1, class: fprb }
+  - { id: 2, class: gprb }
+  - { id: 3, class: gprb }
+body:             |
+  bb.0:
+    liveins: %s0, %s1
+
+    %0(s32) = COPY %s0
+    ; CHECK: [[VREGX:%[0-9]+]] = COPY %s0
+
+    %1(s32) = COPY %s1
+    ; CHECK: [[VREGY:%[0-9]+]] = COPY %s1
+
+    %2(s1) = G_FCMP floatpred(ord),  %0(s32), %1
+    ; CHECK: [[ZERO:%[0-9]+]] = MOVi 0, 14, _, _
+    ; CHECK: VCMPS [[VREGX]], [[VREGY]], 14, _, implicit-def %fpscr_nzcv
+    ; CHECK: FMSTAT 14, _, implicit-def %cpsr, implicit %fpscr_nzcv
+    ; CHECK: [[RES:%[0-9]+]] = MOVCCi [[ZERO]], 1, 7, %cpsr
+
+    %3(s32) = G_ZEXT %2(s1)
+    ; CHECK: [[RET:%[0-9]+]] = ANDri [[RES]], 1, 14, _, _
+
+    %r0 = COPY %3(s32)
+    ; CHECK: %r0 = COPY [[RET]]
+
+    BX_RET 14, _, implicit %r0
+    ; CHECK: BX_RET 14, _, implicit %r0
+...
+---
+name:            test_fcmp_ugt_s32
+# CHECK-LABEL: name: test_fcmp_ugt_s32
+legalized:       true
+regBankSelected: true
+selected:        false
+# CHECK: selected: true
+registers:
+  - { id: 0, class: fprb }
+  - { id: 1, class: fprb }
+  - { id: 2, class: gprb }
+  - { id: 3, class: gprb }
+body:             |
+  bb.0:
+    liveins: %s0, %s1
+
+    %0(s32) = COPY %s0
+    ; CHECK: [[VREGX:%[0-9]+]] = COPY %s0
+
+    %1(s32) = COPY %s1
+    ; CHECK: [[VREGY:%[0-9]+]] = COPY %s1
+
+    %2(s1) = G_FCMP floatpred(ugt),  %0(s32), %1
+    ; CHECK: [[ZERO:%[0-9]+]] = MOVi 0, 14, _, _
+    ; CHECK: VCMPS [[VREGX]], [[VREGY]], 14, _, implicit-def %fpscr_nzcv
+    ; CHECK: FMSTAT 14, _, implicit-def %cpsr, implicit %fpscr_nzcv
+    ; CHECK: [[RES:%[0-9]+]] = MOVCCi [[ZERO]], 1, 8, %cpsr
+
+    %3(s32) = G_ZEXT %2(s1)
+    ; CHECK: [[RET:%[0-9]+]] = ANDri [[RES]], 1, 14, _, _
+
+    %r0 = COPY %3(s32)
+    ; CHECK: %r0 = COPY [[RET]]
+
+    BX_RET 14, _, implicit %r0
+    ; CHECK: BX_RET 14, _, implicit %r0
+...
+---
+name:            test_fcmp_uge_s32
+# CHECK-LABEL: name: test_fcmp_uge_s32
+legalized:       true
+regBankSelected: true
+selected:        false
+# CHECK: selected: true
+registers:
+  - { id: 0, class: fprb }
+  - { id: 1, class: fprb }
+  - { id: 2, class: gprb }
+  - { id: 3, class: gprb }
+body:             |
+  bb.0:
+    liveins: %s0, %s1
+
+    %0(s32) = COPY %s0
+    ; CHECK: [[VREGX:%[0-9]+]] = COPY %s0
+
+    %1(s32) = COPY %s1
+    ; CHECK: [[VREGY:%[0-9]+]] = COPY %s1
+
+    %2(s1) = G_FCMP floatpred(uge),  %0(s32), %1
+    ; CHECK: [[ZERO:%[0-9]+]] = MOVi 0, 14, _, _
+    ; CHECK: VCMPS [[VREGX]], [[VREGY]], 14, _, implicit-def %fpscr_nzcv
+    ; CHECK: FMSTAT 14, _, implicit-def %cpsr, implicit %fpscr_nzcv
+    ; CHECK: [[RES:%[0-9]+]] = MOVCCi [[ZERO]], 1, 5, %cpsr
+
+    %3(s32) = G_ZEXT %2(s1)
+    ; CHECK: [[RET:%[0-9]+]] = ANDri [[RES]], 1, 14, _, _
+
+    %r0 = COPY %3(s32)
+    ; CHECK: %r0 = COPY [[RET]]
+
+    BX_RET 14, _, implicit %r0
+    ; CHECK: BX_RET 14, _, implicit %r0
+...
+---
+name:            test_fcmp_ult_s32
+# CHECK-LABEL: name: test_fcmp_ult_s32
+legalized:       true
+regBankSelected: true
+selected:        false
+# CHECK: selected: true
+registers:
+  - { id: 0, class: fprb }
+  - { id: 1, class: fprb }
+  - { id: 2, class: gprb }
+  - { id: 3, class: gprb }
+body:             |
+  bb.0:
+    liveins: %s0, %s1
+
+    %0(s32) = COPY %s0
+    ; CHECK: [[VREGX:%[0-9]+]] = COPY %s0
+
+    %1(s32) = COPY %s1
+    ; CHECK: [[VREGY:%[0-9]+]] = COPY %s1
+
+    %2(s1) = G_FCMP floatpred(ult),  %0(s32), %1
+    ; CHECK: [[ZERO:%[0-9]+]] = MOVi 0, 14, _, _
+    ; CHECK: VCMPS [[VREGX]], [[VREGY]], 14, _, implicit-def %fpscr_nzcv
+    ; CHECK: FMSTAT 14, _, implicit-def %cpsr, implicit %fpscr_nzcv
+    ; CHECK: [[RES:%[0-9]+]] = MOVCCi [[ZERO]], 1, 11, %cpsr
+
+    %3(s32) = G_ZEXT %2(s1)
+    ; CHECK: [[RET:%[0-9]+]] = ANDri [[RES]], 1, 14, _, _
+
+    %r0 = COPY %3(s32)
+    ; CHECK: %r0 = COPY [[RET]]
+
+    BX_RET 14, _, implicit %r0
+    ; CHECK: BX_RET 14, _, implicit %r0
+...
+---
+name:            test_fcmp_ule_s32
+# CHECK-LABEL: name: test_fcmp_ule_s32
+legalized:       true
+regBankSelected: true
+selected:        false
+# CHECK: selected: true
+registers:
+  - { id: 0, class: fprb }
+  - { id: 1, class: fprb }
+  - { id: 2, class: gprb }
+  - { id: 3, class: gprb }
+body:             |
+  bb.0:
+    liveins: %s0, %s1
+
+    %0(s32) = COPY %s0
+    ; CHECK: [[VREGX:%[0-9]+]] = COPY %s0
+
+    %1(s32) = COPY %s1
+    ; CHECK: [[VREGY:%[0-9]+]] = COPY %s1
+
+    %2(s1) = G_FCMP floatpred(ule),  %0(s32), %1
+    ; CHECK: [[ZERO:%[0-9]+]] = MOVi 0, 14, _, _
+    ; CHECK: VCMPS [[VREGX]], [[VREGY]], 14, _, implicit-def %fpscr_nzcv
+    ; CHECK: FMSTAT 14, _, implicit-def %cpsr, implicit %fpscr_nzcv
+    ; CHECK: [[RES:%[0-9]+]] = MOVCCi [[ZERO]], 1, 13, %cpsr
+
+    %3(s32) = G_ZEXT %2(s1)
+    ; CHECK: [[RET:%[0-9]+]] = ANDri [[RES]], 1, 14, _, _
+
+    %r0 = COPY %3(s32)
+    ; CHECK: %r0 = COPY [[RET]]
+
+    BX_RET 14, _, implicit %r0
+    ; CHECK: BX_RET 14, _, implicit %r0
+...
+---
+name:            test_fcmp_une_s32
+# CHECK-LABEL: name: test_fcmp_une_s32
+legalized:       true
+regBankSelected: true
+selected:        false
+# CHECK: selected: true
+registers:
+  - { id: 0, class: fprb }
+  - { id: 1, class: fprb }
+  - { id: 2, class: gprb }
+  - { id: 3, class: gprb }
+body:             |
+  bb.0:
+    liveins: %s0, %s1
+
+    %0(s32) = COPY %s0
+    ; CHECK: [[VREGX:%[0-9]+]] = COPY %s0
+
+    %1(s32) = COPY %s1
+    ; CHECK: [[VREGY:%[0-9]+]] = COPY %s1
+
+    %2(s1) = G_FCMP floatpred(une),  %0(s32), %1
+    ; CHECK: [[ZERO:%[0-9]+]] = MOVi 0, 14, _, _
+    ; CHECK: VCMPS [[VREGX]], [[VREGY]], 14, _, implicit-def %fpscr_nzcv
+    ; CHECK: FMSTAT 14, _, implicit-def %cpsr, implicit %fpscr_nzcv
+    ; CHECK: [[RES:%[0-9]+]] = MOVCCi [[ZERO]], 1, 1, %cpsr
+
+    %3(s32) = G_ZEXT %2(s1)
+    ; CHECK: [[RET:%[0-9]+]] = ANDri [[RES]], 1, 14, _, _
+
+    %r0 = COPY %3(s32)
+    ; CHECK: %r0 = COPY [[RET]]
+
+    BX_RET 14, _, implicit %r0
+    ; CHECK: BX_RET 14, _, implicit %r0
+...
+---
+name:            test_fcmp_uno_s32
+# CHECK-LABEL: name: test_fcmp_uno_s32
+legalized:       true
+regBankSelected: true
+selected:        false
+# CHECK: selected: true
+registers:
+  - { id: 0, class: fprb }
+  - { id: 1, class: fprb }
+  - { id: 2, class: gprb }
+  - { id: 3, class: gprb }
+body:             |
+  bb.0:
+    liveins: %s0, %s1
+
+    %0(s32) = COPY %s0
+    ; CHECK: [[VREGX:%[0-9]+]] = COPY %s0
+
+    %1(s32) = COPY %s1
+    ; CHECK: [[VREGY:%[0-9]+]] = COPY %s1
+
+    %2(s1) = G_FCMP floatpred(uno),  %0(s32), %1
+    ; CHECK: [[ZERO:%[0-9]+]] = MOVi 0, 14, _, _
+    ; CHECK: VCMPS [[VREGX]], [[VREGY]], 14, _, implicit-def %fpscr_nzcv
+    ; CHECK: FMSTAT 14, _, implicit-def %cpsr, implicit %fpscr_nzcv
+    ; CHECK: [[RES:%[0-9]+]] = MOVCCi [[ZERO]], 1, 6, %cpsr
+
+    %3(s32) = G_ZEXT %2(s1)
+    ; CHECK: [[RET:%[0-9]+]] = ANDri [[RES]], 1, 14, _, _
+
+    %r0 = COPY %3(s32)
+    ; CHECK: %r0 = COPY [[RET]]
+
+    BX_RET 14, _, implicit %r0
+    ; CHECK: BX_RET 14, _, implicit %r0
+...
+---
+name:            test_fcmp_one_s32
+# CHECK-LABEL: name: test_fcmp_one_s32
+legalized:       true
+regBankSelected: true
+selected:        false
+# CHECK: selected: true
+registers:
+  - { id: 0, class: fprb }
+  - { id: 1, class: fprb }
+  - { id: 2, class: gprb }
+  - { id: 3, class: gprb }
+body:             |
+  bb.0:
+    liveins: %s0, %s1
+
+    %0(s32) = COPY %s0
+    ; CHECK: [[VREGX:%[0-9]+]] = COPY %s0
+
+    %1(s32) = COPY %s1
+    ; CHECK: [[VREGY:%[0-9]+]] = COPY %s1
+
+    %2(s1) = G_FCMP floatpred(one),  %0(s32), %1
+    ; CHECK: [[ZERO:%[0-9]+]] = MOVi 0, 14, _, _
+    ; CHECK: VCMPS [[VREGX]], [[VREGY]], 14, _, implicit-def %fpscr_nzcv
+    ; CHECK: FMSTAT 14, _, implicit-def %cpsr, implicit %fpscr_nzcv
+    ; CHECK: [[RES1:%[0-9]+]] = MOVCCi [[ZERO]], 1, 12, %cpsr
+    ; CHECK: VCMPS [[VREGX]], [[VREGY]], 14, _, implicit-def %fpscr_nzcv
+    ; CHECK: FMSTAT 14, _, implicit-def %cpsr, implicit %fpscr_nzcv
+    ; CHECK: [[RES:%[0-9]+]] = MOVCCi [[RES1]], 1, 4, %cpsr
+
+    %3(s32) = G_ZEXT %2(s1)
+    ; CHECK: [[RET:%[0-9]+]] = ANDri [[RES]], 1, 14, _, _
+
+    %r0 = COPY %3(s32)
+    ; CHECK: %r0 = COPY [[RET]]
+
+    BX_RET 14, _, implicit %r0
+    ; CHECK: BX_RET 14, _, implicit %r0
+...
+---
+name:            test_fcmp_ueq_s32
+# CHECK-LABEL: name: test_fcmp_ueq_s32
+legalized:       true
+regBankSelected: true
+selected:        false
+# CHECK: selected: true
+registers:
+  - { id: 0, class: fprb }
+  - { id: 1, class: fprb }
+  - { id: 2, class: gprb }
+  - { id: 3, class: gprb }
+body:             |
+  bb.0:
+    liveins: %s0, %s1
+
+    %0(s32) = COPY %s0
+    ; CHECK: [[VREGX:%[0-9]+]] = COPY %s0
+
+    %1(s32) = COPY %s1
+    ; CHECK: [[VREGY:%[0-9]+]] = COPY %s1
+
+    %2(s1) = G_FCMP floatpred(ueq),  %0(s32), %1
+    ; CHECK: [[ZERO:%[0-9]+]] = MOVi 0, 14, _, _
+    ; CHECK: VCMPS [[VREGX]], [[VREGY]], 14, _, implicit-def %fpscr_nzcv
+    ; CHECK: FMSTAT 14, _, implicit-def %cpsr, implicit %fpscr_nzcv
+    ; CHECK: [[RES1:%[0-9]+]] = MOVCCi [[ZERO]], 1, 0, %cpsr
+    ; CHECK: VCMPS [[VREGX]], [[VREGY]], 14, _, implicit-def %fpscr_nzcv
+    ; CHECK: FMSTAT 14, _, implicit-def %cpsr, implicit %fpscr_nzcv
+    ; CHECK: [[RES:%[0-9]+]] = MOVCCi [[RES1]], 1, 6, %cpsr
+
+    %3(s32) = G_ZEXT %2(s1)
+    ; CHECK: [[RET:%[0-9]+]] = ANDri [[RES]], 1, 14, _, _
 
     %r0 = COPY %3(s32)
     ; CHECK: %r0 = COPY [[RET]]

Modified: llvm/trunk/test/CodeGen/ARM/GlobalISel/arm-isel-fp.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/GlobalISel/arm-isel-fp.ll?rev=307365&r1=307364&r2=307365&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/ARM/GlobalISel/arm-isel-fp.ll (original)
+++ llvm/trunk/test/CodeGen/ARM/GlobalISel/arm-isel-fp.ll Fri Jul  7 01:39:04 2017
@@ -49,3 +49,33 @@ define arm_aapcscc double @test_add_doub
   %r = fadd double %x, %y
   ret double %r
 }
+
+define arm_aapcs_vfpcc i32 @test_cmp_float_ogt(float %x, float %y) {
+; CHECK-LABEL: test_cmp_float_ogt
+; HARD: vcmp.f32
+; HARD: vmrs APSR_nzcv, fpscr
+; HARD-NEXT: movgt
+; SOFT-AEABI: blx __aeabi_fcmpgt
+; SOFT-DEFAULT: blx __gtsf2
+entry:
+  %v = fcmp ogt float %x, %y
+  %r = zext i1 %v to i32
+  ret i32 %r
+}
+
+define arm_aapcs_vfpcc i32 @test_cmp_float_one(float %x, float %y) {
+; CHECK-LABEL: test_cmp_float_one
+; HARD: vcmp.f32
+; HARD: vmrs APSR_nzcv, fpscr
+; HARD: movgt
+; HARD-NOT: vcmp
+; HARD: movmi
+; SOFT-AEABI-DAG: blx __aeabi_fcmpgt
+; SOFT-AEABI-DAG: blx __aeabi_fcmplt
+; SOFT-DEFAULT-DAG: blx __gtsf2
+; SOFT-DEFAULT-DAG: blx __ltsf2
+entry:
+  %v = fcmp one float %x, %y
+  %r = zext i1 %v to i32
+  ret i32 %r
+}




More information about the llvm-commits mailing list