Turn StripPointerCast() into a method
[oota-llvm.git] / lib / CodeGen / SelectionDAG / SelectionDAGISel.cpp
index 93de65239834125eea73f233d660cd86d262c4e7..7ac5218ecfda29890aa5ac275b13943837a95ae7 100644 (file)
@@ -75,8 +75,8 @@ MachinePassRegistry RegisterScheduler::Registry;
 ///
 //===---------------------------------------------------------------------===//
 namespace {
-  cl::opt<RegisterScheduler::FunctionPassCtor, false,
-          RegisterPassParser<RegisterScheduler> >
+  static cl::opt<RegisterScheduler::FunctionPassCtor, false,
+                 RegisterPassParser<RegisterScheduler> >
   ISHeuristic("pre-RA-sched",
               cl::init(&createDefaultScheduler),
               cl::desc("Instruction schedulers available (before register"
@@ -152,9 +152,6 @@ namespace {
     
     RegsForValue() : TLI(0) {}
     
-    RegsForValue(const TargetLowering &tli,
-                 unsigned Reg, MVT::ValueType regvt, MVT::ValueType valuevt)
-      : TLI(&tli), ValueVTs(1, valuevt), RegVTs(1, regvt), Regs(1, Reg) {}
     RegsForValue(const TargetLowering &tli,
                  const SmallVector<unsigned, 4> &regs, 
                  MVT::ValueType regvt, MVT::ValueType valuevt)
@@ -179,6 +176,15 @@ namespace {
       }
     }
     
+    /// append - Add the specified values to this one.
+    void append(const RegsForValue &RHS) {
+      TLI = RHS.TLI;
+      ValueVTs.append(RHS.ValueVTs.begin(), RHS.ValueVTs.end());
+      RegVTs.append(RHS.RegVTs.begin(), RHS.RegVTs.end());
+      Regs.append(RHS.Regs.begin(), RHS.Regs.end());
+    }
+    
+    
     /// getCopyFromRegs - Emit a series of CopyFromReg nodes that copies from
     /// this value and returns the result as a ValueVTs value.  This uses 
     /// Chain/Flag as the input and updates them for the output Chain/Flag.
@@ -726,6 +732,10 @@ public:
     assert(0 && "UserOp2 should not exist at instruction selection time!");
     abort();
   }
+  
+private:
+  inline const char *implVisitBinaryAtomic(CallInst& I, ISD::NodeType Op);
+
 };
 } // end namespace llvm
 
@@ -1266,8 +1276,8 @@ void SelectionDAGLowering::FindMergedConditions(Value *Cond,
         case FCmpInst::FCMP_OLT:   FOC = ISD::SETLT; FPC = ISD::SETOLT; break;
         case FCmpInst::FCMP_OLE:   FOC = ISD::SETLE; FPC = ISD::SETOLE; break;
         case FCmpInst::FCMP_ONE:   FOC = ISD::SETNE; FPC = ISD::SETONE; break;
-        case FCmpInst::FCMP_ORD:   FOC = ISD::SETEQ; FPC = ISD::SETO;   break;
-        case FCmpInst::FCMP_UNO:   FOC = ISD::SETNE; FPC = ISD::SETUO;  break;
+        case FCmpInst::FCMP_ORD:   FOC = FPC = ISD::SETO;   break;
+        case FCmpInst::FCMP_UNO:   FOC = FPC = ISD::SETUO;  break;
         case FCmpInst::FCMP_UEQ:   FOC = ISD::SETEQ; FPC = ISD::SETUEQ; break;
         case FCmpInst::FCMP_UGT:   FOC = ISD::SETGT; FPC = ISD::SETUGT; break;
         case FCmpInst::FCMP_UGE:   FOC = ISD::SETGE; FPC = ISD::SETUGE; break;
@@ -2311,8 +2321,8 @@ void SelectionDAGLowering::visitFCmp(User &I) {
     case FCmpInst::FCMP_OLT:   FOC = ISD::SETLT; FPC = ISD::SETOLT; break;
     case FCmpInst::FCMP_OLE:   FOC = ISD::SETLE; FPC = ISD::SETOLE; break;
     case FCmpInst::FCMP_ONE:   FOC = ISD::SETNE; FPC = ISD::SETONE; break;
-    case FCmpInst::FCMP_ORD:   FOC = ISD::SETEQ; FPC = ISD::SETO;   break;
-    case FCmpInst::FCMP_UNO:   FOC = ISD::SETNE; FPC = ISD::SETUO;  break;
+    case FCmpInst::FCMP_ORD:   FOC = FPC = ISD::SETO;   break;
+    case FCmpInst::FCMP_UNO:   FOC = FPC = ISD::SETUO;  break;
     case FCmpInst::FCMP_UEQ:   FOC = ISD::SETEQ; FPC = ISD::SETUEQ; break;
     case FCmpInst::FCMP_UGT:   FOC = ISD::SETGT; FPC = ISD::SETUGT; break;
     case FCmpInst::FCMP_UGE:   FOC = ISD::SETGE; FPC = ISD::SETUGE; break;
@@ -2702,7 +2712,7 @@ void SelectionDAGLowering::visitTargetIntrinsic(CallInst &I,
 
 /// ExtractTypeInfo - Returns the type info, possibly bitcast, encoded in V.
 static GlobalVariable *ExtractTypeInfo (Value *V) {
-  V = IntrinsicInst::StripPointerCasts(V);
+  V = V->stripPointerCasts();
   GlobalVariable *GV = dyn_cast<GlobalVariable>(V);
   assert ((GV || isa<ConstantPointerNull>(V)) &&
           "TypeInfo must be a global variable or NULL");
@@ -2763,6 +2773,22 @@ static void addCatchInfo(CallInst &I, MachineModuleInfo *MMI,
   }
 }
 
+
+/// Inlined utility function to implement binary input atomic intrinsics for 
+// visitIntrinsicCall: I is a call instruction
+//                     Op is the associated NodeType for I
+const char *
+SelectionDAGLowering::implVisitBinaryAtomic(CallInst& I, ISD::NodeType Op) {
+  SDOperand Root = getRoot();   
+  SDOperand O2 = getValue(I.getOperand(2));
+  SDOperand L = DAG.getAtomic(Op, Root, 
+                              getValue(I.getOperand(1)), 
+                              O2, O2.getValueType());
+  setValue(&I, L);
+  DAG.setRoot(L.getValue(1));
+  return 0;
+}
+
 /// visitIntrinsicCall - Lower the call to the specified intrinsic function.  If
 /// we want to emit this as a call to a named external function, return the name
 /// otherwise lower it and return null.
@@ -3124,8 +3150,7 @@ SelectionDAGLowering::visitIntrinsicCall(CallInst &I, unsigned Intrinsic) {
     return 0;
 
   case Intrinsic::init_trampoline: {
-    const Function *F =
-      cast<Function>(IntrinsicInst::StripPointerCasts(I.getOperand(2)));
+    const Function *F = cast<Function>(I.getOperand(2)->stripPointerCasts());
 
     SDOperand Ops[6];
     Ops[0] = getRoot();
@@ -3199,27 +3224,26 @@ SelectionDAGLowering::visitIntrinsicCall(CallInst &I, unsigned Intrinsic) {
     DAG.setRoot(L.getValue(1));
     return 0;
   }
-  case Intrinsic::atomic_las: {
-    SDOperand Root = getRoot();   
-    SDOperand O2 = getValue(I.getOperand(2));
-    SDOperand L = DAG.getAtomic(ISD::ATOMIC_LAS, Root, 
-                                getValue(I.getOperand(1)), 
-                                O2, O2.getValueType());
-    setValue(&I, L);
-    DAG.setRoot(L.getValue(1));
-    return 0;
-  }
-  case Intrinsic::atomic_swap: {
-    SDOperand Root = getRoot();   
-    SDOperand O2 = getValue(I.getOperand(2));
-    SDOperand L = DAG.getAtomic(ISD::ATOMIC_SWAP, Root, 
-                                getValue(I.getOperand(1)), 
-                                O2, O2.getValueType());
-    setValue(&I, L);
-    DAG.setRoot(L.getValue(1));
-    return 0;
-  }
-
+  case Intrinsic::atomic_las:
+    return implVisitBinaryAtomic(I, ISD::ATOMIC_LAS);
+  case Intrinsic::atomic_lss:
+    return implVisitBinaryAtomic(I, ISD::ATOMIC_LSS);
+  case Intrinsic::atomic_load_and:
+    return implVisitBinaryAtomic(I, ISD::ATOMIC_LOAD_AND);
+  case Intrinsic::atomic_load_or:
+    return implVisitBinaryAtomic(I, ISD::ATOMIC_LOAD_OR);
+  case Intrinsic::atomic_load_xor:
+    return implVisitBinaryAtomic(I, ISD::ATOMIC_LOAD_XOR);
+  case Intrinsic::atomic_load_min:
+    return implVisitBinaryAtomic(I, ISD::ATOMIC_LOAD_MIN);
+  case Intrinsic::atomic_load_max:
+    return implVisitBinaryAtomic(I, ISD::ATOMIC_LOAD_MAX);
+  case Intrinsic::atomic_load_umin:
+    return implVisitBinaryAtomic(I, ISD::ATOMIC_LOAD_UMIN);
+  case Intrinsic::atomic_load_umax:
+      return implVisitBinaryAtomic(I, ISD::ATOMIC_LOAD_UMAX);                                              
+  case Intrinsic::atomic_swap:
+    return implVisitBinaryAtomic(I, ISD::ATOMIC_SWAP);
   }
 }
 
@@ -3458,8 +3482,18 @@ void RegsForValue::getCopyToRegs(SDOperand Val, SelectionDAG &DAG,
     Chains[i] = Part.getValue(0);
   }
   
-  if (NumRegs == 1)
-    Chain = Chains[0];
+  if (NumRegs == 1 || Flag)
+    // If NumRegs > 1 && Flag is used then the use of the last CopyToReg is 
+    // flagged to it. That is the CopyToReg nodes and the user are considered
+    // a single scheduling unit. If we create a TokenFactor and return it as
+    // chain, then the TokenFactor is both a predecessor (operand) of the
+    // user as well as a successor (the TF operands are flagged to the user).
+    // c1, f1 = CopyToReg
+    // c2, f2 = CopyToReg
+    // c3     = TokenFactor c1, c2
+    // ...
+    //        = op c3, ..., f2
+    Chain = Chains[NumRegs-1];
   else
     Chain = DAG.getNode(ISD::TokenFactor, MVT::Other, &Chains[0], NumRegs);
 }
@@ -3747,7 +3781,6 @@ GetRegistersForValue(SDISelAsmOperandInfo &OpInfo, bool HasEarlyClobber,
   }
   
   // Otherwise, we couldn't allocate enough registers for this.
-  return;
 }
 
 
@@ -3931,7 +3964,7 @@ void SelectionDAGLowering::visitInlineAsm(CallSite CS) {
   // Loop over all of the inputs, copying the operand values into the
   // appropriate registers and processing the output regs.
   RegsForValue RetValRegs;
-  
   // IndirectStoresToEmit - The set of stores to emit after the inline asm node.
   std::vector<std::pair<RegsForValue, Value*> > IndirectStoresToEmit;
   
@@ -3963,15 +3996,16 @@ void SelectionDAGLowering::visitInlineAsm(CallSite CS) {
         exit(1);
       }
 
-      if (!OpInfo.isIndirect) {
-        // This is the result value of the call.
-        assert(RetValRegs.Regs.empty() &&
-               "Cannot have multiple output constraints yet!");
-        assert(CS.getType() != Type::VoidTy && "Bad inline asm!");
-        RetValRegs = OpInfo.AssignedRegs;
-      } else {
+      // If this is an indirect operand, store through the pointer after the
+      // asm.
+      if (OpInfo.isIndirect) {
         IndirectStoresToEmit.push_back(std::make_pair(OpInfo.AssignedRegs,
                                                       OpInfo.CallOperandVal));
+      } else {
+        // This is the result value of the call.
+        assert(CS.getType() != Type::VoidTy && "Bad inline asm!");
+        // Concatenate this output onto the outputs list.
+        RetValRegs.append(OpInfo.AssignedRegs);
       }
       
       // Add information to the INLINEASM node to know that this register is
@@ -4007,8 +4041,8 @@ void SelectionDAGLowering::visitInlineAsm(CallSite CS) {
           // Add NumOps>>3 registers to MatchedRegs.
           RegsForValue MatchedRegs;
           MatchedRegs.TLI = &TLI;
-          MatchedRegs.ValueVTs.resize(1, InOperandVal.getValueType());
-          MatchedRegs.RegVTs.resize(1, AsmNodeOperands[CurOp+1].getValueType());
+          MatchedRegs.ValueVTs.push_back(InOperandVal.getValueType());
+          MatchedRegs.RegVTs.push_back(AsmNodeOperands[CurOp+1].getValueType());
           for (unsigned i = 0, e = NumOps>>3; i != e; ++i) {
             unsigned Reg =
               cast<RegisterSDNode>(AsmNodeOperands[++CurOp])->getReg();
@@ -4103,17 +4137,24 @@ void SelectionDAGLowering::visitInlineAsm(CallSite CS) {
   // and set it as the value of the call.
   if (!RetValRegs.Regs.empty()) {
     SDOperand Val = RetValRegs.getCopyFromRegs(DAG, Chain, &Flag);
-    
-    // If the result of the inline asm is a vector, it may have the wrong
-    // width/num elts.  Make sure to convert it to the right type with
+
+    // If any of the results of the inline asm is a vector, it may have the
+    // wrong width/num elts.  This can happen for register classes that can
+    // contain multiple different value types.  The preg or vreg allocated may
+    // not have the same VT as was expected.  Convert it to the right type with
     // bit_convert.
-    if (MVT::isVector(Val.getValueType())) {
-      const VectorType *VTy = cast<VectorType>(CS.getType());
-      MVT::ValueType DesiredVT = TLI.getValueType(VTy);
-      
-      Val = DAG.getNode(ISD::BIT_CONVERT, DesiredVT, Val);
+    if (const StructType *ResSTy = dyn_cast<StructType>(CS.getType())) {
+      for (unsigned i = 0, e = ResSTy->getNumElements(); i != e; ++i) {
+        if (MVT::isVector(Val.Val->getValueType(i)))
+          Val = DAG.getNode(ISD::BIT_CONVERT,
+                            TLI.getValueType(ResSTy->getElementType(i)), Val);
+      }
+    } else {
+      if (MVT::isVector(Val.getValueType()))
+        Val = DAG.getNode(ISD::BIT_CONVERT, TLI.getValueType(CS.getType()),
+                          Val);
     }
-    
+
     setValue(CS.getInstruction(), Val);
   }
   
@@ -4496,8 +4537,6 @@ void SelectionDAGISel::getAnalysisUsage(AnalysisUsage &AU) const {
   AU.setPreservesAll();
 }
 
-
-
 bool SelectionDAGISel::runOnFunction(Function &Fn) {
   // Get alias analysis for load/store combining.
   AA = &getAnalysis<AliasAnalysis>();
@@ -4589,6 +4628,40 @@ static void copyCatchInfo(BasicBlock *SrcBB, BasicBlock *DestBB,
     }
 }
 
+/// IsFixedFrameObjectWithPosOffset - Check if object is a fixed frame object and
+/// whether object offset >= 0.
+static bool
+IsFixedFrameObjectWithPosOffset(MachineFrameInfo * MFI, SDOperand Op) {
+  if (!isa<FrameIndexSDNode>(Op)) return false;
+
+  FrameIndexSDNode * FrameIdxNode = dyn_cast<FrameIndexSDNode>(Op);
+  int FrameIdx =  FrameIdxNode->getIndex();
+  return MFI->isFixedObjectIndex(FrameIdx) &&
+    MFI->getObjectOffset(FrameIdx) >= 0;
+}
+
+/// IsPossiblyOverwrittenArgumentOfTailCall - Check if the operand could
+/// possibly be overwritten when lowering the outgoing arguments in a tail
+/// call. Currently the implementation of this call is very conservative and
+/// assumes all arguments sourcing from FORMAL_ARGUMENTS or a CopyFromReg with
+/// virtual registers would be overwritten by direct lowering.
+static bool IsPossiblyOverwrittenArgumentOfTailCall(SDOperand Op,
+                                                    MachineFrameInfo * MFI) {
+  RegisterSDNode * OpReg = NULL;
+  if (Op.getOpcode() == ISD::FORMAL_ARGUMENTS ||
+      (Op.getOpcode()== ISD::CopyFromReg &&
+       (OpReg = dyn_cast<RegisterSDNode>(Op.getOperand(1))) &&
+       (OpReg->getReg() >= TargetRegisterInfo::FirstVirtualRegister)) ||
+      (Op.getOpcode() == ISD::LOAD &&
+       IsFixedFrameObjectWithPosOffset(MFI, Op.getOperand(1))) ||
+      (Op.getOpcode() == ISD::MERGE_VALUES &&
+       Op.getOperand(Op.ResNo).getOpcode() == ISD::LOAD &&
+       IsFixedFrameObjectWithPosOffset(MFI, Op.getOperand(Op.ResNo).
+                                       getOperand(1))))
+    return true;
+  return false;
+}
+
 /// CheckDAGForTailCallsAndFixThem - This Function looks for CALL nodes in the
 /// DAG and fixes their tailcall attribute operand.
 static void CheckDAGForTailCallsAndFixThem(SelectionDAG &DAG, 
@@ -4613,19 +4686,51 @@ static void CheckDAGForTailCallsAndFixThem(SelectionDAG &DAG,
       // eligible (no RET or the target rejects) the attribute is fixed to
       // false. The TargetLowering::IsEligibleForTailCallOptimization function
       // must correctly identify tail call optimizable calls.
-      if (isMarkedTailCall && 
-          (Ret==NULL || 
-           !TLI.IsEligibleForTailCallOptimization(OpCall, OpRet, DAG))) {
+      if (!isMarkedTailCall) continue;
+      if (Ret==NULL ||
+          !TLI.IsEligibleForTailCallOptimization(OpCall, OpRet, DAG)) {
+        // Not eligible. Mark CALL node as non tail call.
         SmallVector<SDOperand, 32> Ops;
         unsigned idx=0;
-        for(SDNode::op_iterator I =OpCall.Val->op_begin(), 
-              E=OpCall.Val->op_end(); I!=E; I++, idx++) {
+        for(SDNode::op_iterator I =OpCall.Val->op_begin(),
+              E = OpCall.Val->op_end(); I != E; I++, idx++) {
           if (idx!=3)
             Ops.push_back(*I);
-          else 
+          else
             Ops.push_back(DAG.getConstant(false, TLI.getPointerTy()));
         }
         DAG.UpdateNodeOperands(OpCall, Ops.begin(), Ops.size());
+      } else {
+        // Look for tail call clobbered arguments. Emit a series of
+        // copyto/copyfrom virtual register nodes to protect them.
+        SmallVector<SDOperand, 32> Ops;
+        SDOperand Chain = OpCall.getOperand(0), InFlag;
+        unsigned idx=0;
+        for(SDNode::op_iterator I = OpCall.Val->op_begin(),
+              E = OpCall.Val->op_end(); I != E; I++, idx++) {
+          SDOperand Arg = *I;
+          if (idx > 4 && (idx % 2)) {
+            bool isByVal = cast<ARG_FLAGSSDNode>(OpCall.getOperand(idx+1))->
+              getArgFlags().isByVal();
+            MachineFunction &MF = DAG.getMachineFunction();
+            MachineFrameInfo *MFI = MF.getFrameInfo();
+            if (!isByVal &&
+                IsPossiblyOverwrittenArgumentOfTailCall(Arg, MFI)) {
+              MVT::ValueType VT = Arg.getValueType();
+              unsigned VReg = MF.getRegInfo().
+                createVirtualRegister(TLI.getRegClassFor(VT));
+              Chain = DAG.getCopyToReg(Chain, VReg, Arg, InFlag);
+              InFlag = Chain.getValue(1);
+              Arg = DAG.getCopyFromReg(Chain, VReg, VT, InFlag);
+              Chain = Arg.getValue(1);
+              InFlag = Arg.getValue(2);
+            }
+          }
+          Ops.push_back(Arg);
+        }
+        // Link in chain of CopyTo/CopyFromReg.
+        Ops[0] = Chain;
+        DAG.UpdateNodeOperands(OpCall, Ops.begin(), Ops.size());
       }
     }
   }