[FastISel][AArch64] Don't fold the 'and' instruction into the 'tbz/tbnz' instruction...
[oota-llvm.git] / lib / Target / AArch64 / AArch64FastISel.cpp
index b074be9419cc3be0def5f7014b0acb633b2dbe3d..d62692848014f64546c3ff24e5660d8c3d806f5d 100644 (file)
@@ -78,11 +78,9 @@ class AArch64FastISel final : public FastISel {
       return Base.Reg;
     }
     void setOffsetReg(unsigned Reg) {
-      assert(isRegBase() && "Invalid offset register access!");
       OffsetReg = Reg;
     }
     unsigned getOffsetReg() const {
-      assert(isRegBase() && "Invalid offset register access!");
       return OffsetReg;
     }
     void setFI(unsigned FI) {
@@ -189,6 +187,7 @@ private:
   unsigned emitAdd(MVT RetVT, const Value *LHS, const Value *RHS,
                    bool SetFlags = false, bool WantResult = true,
                    bool IsZExt = false);
+  unsigned emitAdd_ri_(MVT VT, unsigned Op0, bool Op0IsKill, int64_t Imm);
   unsigned emitSub(MVT RetVT, const Value *LHS, const Value *RHS,
                    bool SetFlags = false, bool WantResult = true,
                    bool IsZExt = false);
@@ -809,22 +808,23 @@ bool AArch64FastISel::computeAddress(const Value *Obj, Address &Addr, Type *Ty)
   }
   } // end switch
 
-  if (Addr.getReg()) {
-    if (!Addr.getOffsetReg()) {
-      unsigned Reg = getRegForValue(Obj);
-      if (!Reg)
-        return false;
-      Addr.setOffsetReg(Reg);
-      return true;
-    }
-    return false;
+  if (Addr.isRegBase() && !Addr.getReg()) {
+    unsigned Reg = getRegForValue(Obj);
+    if (!Reg)
+      return false;
+    Addr.setReg(Reg);
+    return true;
   }
 
-  unsigned Reg = getRegForValue(Obj);
-  if (!Reg)
-    return false;
-  Addr.setReg(Reg);
-  return true;
+  if (!Addr.getOffsetReg()) {
+    unsigned Reg = getRegForValue(Obj);
+    if (!Reg)
+      return false;
+    Addr.setOffsetReg(Reg);
+    return true;
+  }
+
+  return false;
 }
 
 bool AArch64FastISel::computeCallAddress(const Value *V, Address &Addr) {
@@ -941,8 +941,7 @@ bool AArch64FastISel::simplifyAddress(Address &Addr, MVT VT) {
   // Cannot encode an offset register and an immediate offset in the same
   // instruction. Fold the immediate offset into the load/store instruction and
   // emit an additonal add to take care of the offset register.
-  if (!ImmediateOffsetNeedsLowering && Addr.getOffset() && Addr.isRegBase() &&
-      Addr.getOffsetReg())
+  if (!ImmediateOffsetNeedsLowering && Addr.getOffset() && Addr.getOffsetReg())
     RegisterOffsetNeedsLowering = true;
 
   // Cannot encode zero register as base.
@@ -952,7 +951,8 @@ bool AArch64FastISel::simplifyAddress(Address &Addr, MVT VT) {
   // If this is a stack pointer and the offset needs to be simplified then put
   // the alloca address into a register, set the base type back to register and
   // continue. This should almost never happen.
-  if (ImmediateOffsetNeedsLowering && Addr.isFIBase()) {
+  if ((ImmediateOffsetNeedsLowering || Addr.getOffsetReg()) && Addr.isFIBase())
+  {
     unsigned ResultReg = createResultReg(&AArch64::GPR64spRegClass);
     BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(AArch64::ADDXri),
             ResultReg)
@@ -1003,20 +1003,10 @@ bool AArch64FastISel::simplifyAddress(Address &Addr, MVT VT) {
   // reg+offset into a register.
   if (ImmediateOffsetNeedsLowering) {
     unsigned ResultReg;
-    if (Addr.getReg()) {
+    if (Addr.getReg())
       // Try to fold the immediate into the add instruction.
-      if (Offset < 0)
-        ResultReg = emitAddSub_ri(/*UseAdd=*/false, MVT::i64, Addr.getReg(),
-                                  /*IsKill=*/false, -Offset);
-      else
-        ResultReg = emitAddSub_ri(/*UseAdd=*/true, MVT::i64, Addr.getReg(),
-                                  /*IsKill=*/false, Offset);
-      if (!ResultReg) {
-        unsigned ImmReg = fastEmit_i(MVT::i64, MVT::i64, ISD::Constant, Offset);
-        ResultReg = emitAddSub_rr(/*UseAdd=*/true, MVT::i64, Addr.getReg(),
-                                  /*IsKill=*/false, ImmReg, /*IsKill=*/true);
-      }
-    } else
+      ResultReg = emitAdd_ri_(MVT::i64, Addr.getReg(), /*IsKill=*/false, Offset);
+    else
       ResultReg = fastEmit_i(MVT::i64, MVT::i64, ISD::Constant, Offset);
 
     if (!ResultReg)
@@ -1059,10 +1049,8 @@ void AArch64FastISel::addLoadStoreOperands(Address &Addr,
       MIB.addReg(Addr.getOffsetReg());
       MIB.addImm(IsSigned);
       MIB.addImm(Addr.getShift() != 0);
-    } else {
-      MIB.addReg(Addr.getReg());
-      MIB.addImm(Offset);
-    }
+    } else
+      MIB.addReg(Addr.getReg()).addImm(Offset);
   }
 
   if (MMO)
@@ -1443,6 +1431,30 @@ unsigned AArch64FastISel::emitAdd(MVT RetVT, const Value *LHS, const Value *RHS,
                     IsZExt);
 }
 
+/// \brief This method is a wrapper to simplify add emission.
+///
+/// First try to emit an add with an immediate operand using emitAddSub_ri. If
+/// that fails, then try to materialize the immediate into a register and use
+/// emitAddSub_rr instead.
+unsigned AArch64FastISel::emitAdd_ri_(MVT VT, unsigned Op0, bool Op0IsKill,
+                                      int64_t Imm) {
+  unsigned ResultReg;
+  if (Imm < 0)
+    ResultReg = emitAddSub_ri(false, VT, Op0, Op0IsKill, -Imm);
+  else
+    ResultReg = emitAddSub_ri(true, VT, Op0, Op0IsKill, Imm);
+
+  if (ResultReg)
+    return ResultReg;
+
+  unsigned CReg = fastEmit_i(VT, VT, ISD::Constant, Imm);
+  if (!CReg)
+    return 0;
+
+  ResultReg = emitAddSub_rr(true, VT, Op0, Op0IsKill, CReg, true);
+  return ResultReg;
+}
+
 unsigned AArch64FastISel::emitSub(MVT RetVT, const Value *LHS, const Value *RHS,
                                   bool SetFlags, bool WantResult, bool IsZExt) {
   return emitAddSub(/*UseAdd=*/false, RetVT, LHS, RHS, SetFlags, WantResult,
@@ -2106,7 +2118,7 @@ bool AArch64FastISel::emitCompareAndBranch(const BranchInst *BI) {
       return false;
 
     if (const auto *AI = dyn_cast<BinaryOperator>(LHS))
-      if (AI->getOpcode() == Instruction::And) {
+      if (AI->getOpcode() == Instruction::And && isValueAvailable(AI)) {
         const Value *AndLHS = AI->getOperand(0);
         const Value *AndRHS = AI->getOperand(1);
 
@@ -2153,7 +2165,7 @@ bool AArch64FastISel::emitCompareAndBranch(const BranchInst *BI) {
   bool Is64Bit = BW == 64;
   if (TestBit < 32 && TestBit >= 0)
     Is64Bit = false;
-  
+
   unsigned Opc = OpcTable[IsBitTest][IsCmpNE][Is64Bit];
   const MCInstrDesc &II = TII.get(Opc);
 
@@ -2166,6 +2178,12 @@ bool AArch64FastISel::emitCompareAndBranch(const BranchInst *BI) {
     SrcReg = fastEmitInst_extractsubreg(MVT::i32, SrcReg, SrcIsKill,
                                         AArch64::sub_32);
 
+  if ((BW < 32) && !IsBitTest) {
+    EVT CmpEVT = TLI.getValueType(Ty, true);
+    SrcReg =
+        emitIntExt(CmpEVT.getSimpleVT(), SrcReg, MVT::i32, /*isZExt*/ true);
+  }
+
   // Emit the combined compare and branch instruction.
   SrcReg = constrainOperandRegClass(II, SrcReg,  II.getNumDefs());
   MachineInstrBuilder MIB =
@@ -4500,9 +4518,8 @@ bool AArch64FastISel::selectSDiv(const Instruction *I) {
     return true;
   }
 
-  unsigned Pow2MinusOne = (1 << Lg2) - 1;
-  unsigned AddReg = emitAddSub_ri(/*UseAdd=*/true, VT, Src0Reg,
-                                  /*IsKill=*/false, Pow2MinusOne);
+  int64_t Pow2MinusOne = (1ULL << Lg2) - 1;
+  unsigned AddReg = emitAdd_ri_(VT, Src0Reg, /*IsKill=*/false, Pow2MinusOne);
   if (!AddReg)
     return false;
 
@@ -4542,6 +4559,10 @@ bool AArch64FastISel::selectSDiv(const Instruction *I) {
   return true;
 }
 
+/// This is mostly a copy of the existing FastISel GEP code, but we have to
+/// duplicate it for AArch64, because otherwise we would bail out even for
+/// simple cases. This is because the standard fastEmit functions don't cover
+/// MUL at all and ADD is lowered very inefficientily.
 bool AArch64FastISel::selectGetElementPtr(const Instruction *I) {
   unsigned N = getRegForValue(I->getOperand(0));
   if (!N)
@@ -4573,15 +4594,9 @@ bool AArch64FastISel::selectGetElementPtr(const Instruction *I) {
         continue;
       }
       if (TotalOffs) {
-        N = emitAddSub_ri(/*UseAdd=*/true, VT, N, NIsKill, TotalOffs);
-        if (!N) {
-          unsigned C = fastEmit_i(VT, VT, ISD::Constant, TotalOffs);
-          if (!C)
-            return false;
-          N = emitAddSub_rr(/*UseAdd=*/true, VT, N, NIsKill, C, true);
-          if (!N)
-            return false;
-        }
+        N = emitAdd_ri_(VT, N, NIsKill, TotalOffs);
+        if (!N)
+          return false;
         NIsKill = true;
         TotalOffs = 0;
       }
@@ -4609,17 +4624,10 @@ bool AArch64FastISel::selectGetElementPtr(const Instruction *I) {
     }
   }
   if (TotalOffs) {
-    N = emitAddSub_ri(/*UseAdd=*/true, VT, N, NIsKill, TotalOffs);
-    if (!N) {
-      unsigned C = fastEmit_i(VT, VT, ISD::Constant, TotalOffs);
-      if (!C)
-        return false;
-      N = emitAddSub_rr(/*UseAdd=*/true, VT, N, NIsKill, C, true);
-      if (!N)
-        return false;
-    }
+    N = emitAdd_ri_(VT, N, NIsKill, TotalOffs);
+    if (!N)
+      return false;
   }
-
   updateValueMap(I, N);
   return true;
 }