[FastISel] Add support for the stackmap intrinsic.

This implements target-independent FastISel lowering for the stackmap intrinsic.

llvm-svn: 210742
diff --git a/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp b/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp
index 99931c1..94d3be9 100644
--- a/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp
@@ -45,9 +45,11 @@
 #include "llvm/Analysis/Loads.h"
 #include "llvm/CodeGen/Analysis.h"
 #include "llvm/CodeGen/FunctionLoweringInfo.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
 #include "llvm/CodeGen/MachineInstrBuilder.h"
 #include "llvm/CodeGen/MachineModuleInfo.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/StackMaps.h"
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/DebugInfo.h"
 #include "llvm/IR/Function.h"
@@ -558,6 +560,36 @@
   return true;
 }
 
+/// \brief Add a stack map intrinsic call's live variable operands to a stackmap
+/// or patchpoint machine instruction.
+///
+bool FastISel::addStackMapLiveVars(SmallVectorImpl<MachineOperand> &Ops,
+                                   const CallInst *CI, unsigned StartIdx) {
+  for (unsigned i = StartIdx, e = CI->getNumArgOperands(); i != e; ++i) {
+    Value *Val = CI->getArgOperand(i);
+    if (auto *C = dyn_cast<ConstantInt>(Val)) {
+      Ops.push_back(MachineOperand::CreateImm(StackMaps::ConstantOp));
+      Ops.push_back(MachineOperand::CreateImm(C->getSExtValue()));
+    } else if (isa<ConstantPointerNull>(Val)) {
+      Ops.push_back(MachineOperand::CreateImm(StackMaps::ConstantOp));
+      Ops.push_back(MachineOperand::CreateImm(0));
+    } else if (auto *AI = dyn_cast<AllocaInst>(Val)) {
+      auto SI = FuncInfo.StaticAllocaMap.find(AI);
+      if (SI != FuncInfo.StaticAllocaMap.end())
+        Ops.push_back(MachineOperand::CreateFI(SI->second));
+      else
+        return false;
+    } else {
+      unsigned Reg = getRegForValue(Val);
+      if (Reg == 0)
+        return false;
+      Ops.push_back(MachineOperand::CreateReg(Reg, /*IsDef=*/false));
+    }
+  }
+
+  return true;
+}
+
 bool FastISel::SelectCall(const User *I) {
   const CallInst *Call = cast<CallInst>(I);
 
@@ -713,6 +745,76 @@
     UpdateValueMap(Call, ResultReg);
     return true;
   }
+  case Intrinsic::experimental_stackmap: {
+    // void @llvm.experimental.stackmap(i64 <id>, i32 <numShadowBytes>,
+    //                                  [live variables...])
+
+    assert(Call->getCalledFunction()->getReturnType()->isVoidTy() &&
+           "Stackmap cannot return a value.");
+
+    // The stackmap intrinsic only records the live variables (the arguments
+    // passed to it) and emits NOPS (if requested). Unlike the patchpoint
+    // intrinsic, this won't be lowered to a function call. This means we don't
+    // have to worry about calling conventions and target-specific lowering
+    // code. Instead we perform the call lowering right here.
+    //
+    // CALLSEQ_START(0)
+    // STACKMAP(id, nbytes, ...)
+    // CALLSEQ_END(0, 0)
+    //
+
+    SmallVector<MachineOperand, 32> Ops;
+
+    // Add the <id> and <numBytes> constants.
+    assert(isa<ConstantInt>(Call->getOperand(PatchPointOpers::IDPos)) &&
+           "Expected a constant integer.");
+    auto IDVal = cast<ConstantInt>(Call->getOperand(PatchPointOpers::IDPos));
+    Ops.push_back(MachineOperand::CreateImm(IDVal->getZExtValue()));
+
+    assert(isa<ConstantInt>(Call->getOperand(PatchPointOpers::NBytesPos)) &&
+           "Expected a constant integer.");
+    auto NBytesVal =
+      cast<ConstantInt>(Call->getOperand(PatchPointOpers::NBytesPos));
+    Ops.push_back(MachineOperand::CreateImm(NBytesVal->getZExtValue()));
+
+    // Push live variables for the stack map.
+    if (!addStackMapLiveVars(Ops, Call, 2))
+      return false;
+
+    // We are not adding any register mask info here, because the stackmap
+    // doesn't clobber anything.
+
+    // Add scratch registers as implicit def and early clobber.
+    CallingConv::ID CC = Call->getCallingConv();
+    const MCPhysReg *ScratchRegs = TLI.getScratchRegisters(CC);
+    for (unsigned i = 0; ScratchRegs[i]; ++i)
+      Ops.push_back(MachineOperand::CreateReg(
+        ScratchRegs[i], /*IsDef=*/true, /*IsImp=*/true, /*IsKill=*/false,
+        /*IsDead=*/false, /*IsUndef=*/false, /*IsEarlyClobber=*/true));
+
+    // Issue CALLSEQ_START
+    unsigned AdjStackDown = TII.getCallFrameSetupOpcode();
+    BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(AdjStackDown))
+      .addImm(0);
+
+    // Issue STACKMAP.
+    MachineInstrBuilder MIB;
+    MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
+                  TII.get(TargetOpcode::STACKMAP));
+
+    for (auto const &MO : Ops)
+      MIB.addOperand(MO);
+
+    // Issue CALLSEQ_END
+    unsigned AdjStackUp = TII.getCallFrameDestroyOpcode();
+    BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(AdjStackUp))
+      .addImm(0).addImm(0);
+
+    // Inform the Frame Information that we have a stackmap in this function.
+    FuncInfo.MF->getFrameInfo()->setHasStackMap();
+
+    return true;
+  }
   }
 
   // Usually, it does not make sense to initialize a value,