Introduce an GCRelocateInst class [NFC]
authorPhilip Reames <listmail@philipreames.com>
Tue, 12 Apr 2016 18:05:10 +0000 (18:05 +0000)
committerPhilip Reames <listmail@philipreames.com>
Tue, 12 Apr 2016 18:05:10 +0000 (18:05 +0000)
Previously, we were using isGCRelocate predicates.  Using a subclass of IntrinsicInst is far more idiomatic.  The refactoring also enables a couple of minor simplifications and code sharing.

llvm-svn: 266098

llvm/include/llvm/IR/Statepoint.h
llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
llvm/lib/CodeGen/SelectionDAG/StatepointLowering.cpp
llvm/lib/IR/Statepoint.cpp
llvm/lib/IR/Verifier.cpp

index 4163015..8ae08f1 100644 (file)
@@ -39,6 +39,7 @@ enum class StatepointFlags {
 };
 
 class GCRelocateInst;
+class GCResultInst;
 class ImmutableStatepoint;
 
 bool isStatepoint(ImmutableCallSite CS);
@@ -46,8 +47,6 @@ bool isStatepoint(const Value *V);
 bool isStatepoint(const Value &V);
 
 bool isGCRelocate(ImmutableCallSite CS);
-
-bool isGCResult(const Value *V);
 bool isGCResult(ImmutableCallSite CS);
 
 /// Analogous to CallSiteBase, this provides most of the actual
@@ -253,11 +252,10 @@ public:
   /// Get the experimental_gc_result call tied to this statepoint.  Can be
   /// nullptr if there isn't a gc_result tied to this statepoint.  Guaranteed to
   /// be a CallInst if non-null.
-  InstructionTy *getGCResult() const {
+  const GCResultInst *getGCResult() const {
     for (auto *U : getInstruction()->users())
-      if (isGCResult(U))
-        return cast<CallInst>(U);
-
+      if (auto *GRI = dyn_cast<GCResultInst>(U))
+        return GRI;
     return nullptr;
   }
 
@@ -306,11 +304,13 @@ public:
   explicit Statepoint(CallSite CS) : Base(CS) {}
 };
 
-/// This represents the gc.relocate intrinsic.
-class GCRelocateInst : public IntrinsicInst {
+/// Common base class for representing values projected from a statepoint.  
+/// Currently, the only projections available are gc.result and gc.relocate.
+class GCProjectionInst : public IntrinsicInst {
 public:
   static inline bool classof(const IntrinsicInst *I) {
-    return I->getIntrinsicID() == Intrinsic::experimental_gc_relocate;
+    return I->getIntrinsicID() == Intrinsic::experimental_gc_relocate ||
+      I->getIntrinsicID() == Intrinsic::experimental_gc_result;
   }
   static inline bool classof(const Value *V) {
     return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
@@ -331,6 +331,7 @@ public:
     // This takes care both of relocates for call statepoints and relocates
     // on normal path of invoke statepoint.
     if (!isa<LandingPadInst>(Token)) {
+      assert(isStatepoint(Token));
       return cast<Instruction>(Token);
     }
 
@@ -345,6 +346,17 @@ public:
 
     return InvokeBB->getTerminator();
   }
+};
+
+/// This represents the gc.relocate intrinsic.
+class GCRelocateInst : public GCProjectionInst {
+public:
+  static inline bool classof(const IntrinsicInst *I) {
+    return I->getIntrinsicID() == Intrinsic::experimental_gc_relocate;
+  }
+  static inline bool classof(const Value *V) {
+    return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
+  }
 
   /// The index into the associate statepoint's argument list
   /// which contains the base pointer of the pointer whose
@@ -370,6 +382,17 @@ public:
   }
 };
 
+/// This represents the gc.result intrinsic.
+class GCResultInst : public GCProjectionInst {
+public:
+  static inline bool classof(const IntrinsicInst *I) {
+    return I->getIntrinsicID() == Intrinsic::experimental_gc_result;
+  }
+  static inline bool classof(const Value *V) {
+    return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
+  }
+};
+
 template <typename FunTy, typename InstructionTy, typename ValueTy,
           typename CallSiteTy>
 std::vector<const GCRelocateInst *>
index 27d2422..6f4cd42 100644 (file)
@@ -5539,7 +5539,7 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) {
     return nullptr;
   }
   case Intrinsic::experimental_gc_result: {
-    visitGCResult(I);
+    visitGCResult(cast<GCResultInst>(I));
     return nullptr;
   }
   case Intrinsic::experimental_gc_relocate: {
index 47d8870..591361e 100644 (file)
@@ -904,7 +904,7 @@ private:
 
   // These two are implemented in StatepointLowering.cpp
   void visitGCRelocate(const GCRelocateInst &I);
-  void visitGCResult(const CallInst &I);
+  void visitGCResult(const GCResultInst &I);
 
   void visitUserOp1(const Instruction &I) {
     llvm_unreachable("UserOp1 should not exist at instruction selection time!");
index f489e3b..9b74551 100644 (file)
@@ -788,7 +788,7 @@ SelectionDAGBuilder::LowerStatepoint(ImmutableStatepoint ISP,
   SDValue ReturnValue = LowerAsSTATEPOINT(SI);
 
   // Export the result value if needed
-  const Instruction *GCResult = ISP.getGCResult();
+  const GCResultInst *GCResult = ISP.getGCResult();
   Type *RetTy = ISP.getActualReturnType();
   if (!RetTy->isVoidTy() && GCResult) {
     if (GCResult->getParent() != ISP.getCallSite().getParent()) {
@@ -862,17 +862,16 @@ void SelectionDAGBuilder::LowerCallSiteWithDeoptBundle(
                                    /* ForceVoidReturnTy  = */ false);
 }
 
-void SelectionDAGBuilder::visitGCResult(const CallInst &CI) {
+void SelectionDAGBuilder::visitGCResult(const GCResultInst &CI) {
   // The result value of the gc_result is simply the result of the actual
   // call.  We've already emitted this, so just grab the value.
-  Instruction *I = cast<Instruction>(CI.getArgOperand(0));
-  assert(isStatepoint(I) && "first argument must be a statepoint token");
+  const Instruction *I = CI.getStatepoint();
 
   if (I->getParent() != CI.getParent()) {
     // Statepoint is in different basic block so we should have stored call
     // result in a virtual register.
     // We can not use default getValue() functionality to copy value from this
-    // register because statepoint and actuall call return types can be
+    // register because statepoint and actual call return types can be
     // different, and getValue() will use CopyFromReg of the wrong type,
     // which is always i32 in our case.
     PointerType *CalleeType = cast<PointerType>(
index 13e8c63..63be1e7 100644 (file)
@@ -45,13 +45,7 @@ bool llvm::isGCRelocate(ImmutableCallSite CS) {
 }
 
 bool llvm::isGCResult(ImmutableCallSite CS) {
-  if (auto *F = getCalledFunction(CS))
-    return F->getIntrinsicID() == Intrinsic::experimental_gc_result;
-  return false;
-}
-
-bool llvm::isGCResult(const Value *V) {
-  return isGCResult(ImmutableCallSite(V));
+  return CS.getInstruction() && isa<GCResultInst>(CS.getInstruction());
 }
 
 bool llvm::isStatepointDirectiveAttr(Attribute Attr) {
index 686c1cc..8f05588 100644 (file)
@@ -1774,11 +1774,11 @@ void Verifier::verifyStatepoint(ImmutableCallSite CS) {
     const CallInst *Call = dyn_cast<const CallInst>(U);
     Assert(Call, "illegal use of statepoint token", &CI, U);
     if (!Call) continue;
-    Assert(isa<GCRelocateInst>(Call) || isGCResult(Call),
+    Assert(isa<GCRelocateInst>(Call) || isa<GCResultInst>(Call),
            "gc.result or gc.relocate are the only value uses"
            "of a gc.statepoint",
            &CI, U);
-    if (isGCResult(Call)) {
+    if (isa<GCResultInst>(Call)) {
       Assert(Call->getArgOperand(0) == &CI,
              "gc.result connected to wrong gc.statepoint", &CI, Call);
     } else if (isa<GCRelocateInst>(Call)) {