[llvm] 9e362bb - [InstCombine] Remove unused entries in gc-live bundle of statepoint

Philip Reames via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 21 12:55:27 PDT 2020


Serguei,

The code appears correct, but I really think this deserves a bit more in 
the way of testing.  (Did you by any chance forget to include a new file?)

Philip

On 8/21/20 11:37 AM, Serguei Katkov via llvm-commits wrote:
> Author: Serguei Katkov
> Date: 2020-08-22T01:36:22+07:00
> New Revision: 9e362bb0eb52732cd9224d02bb7ce613bb47c1fc
>
> URL: https://github.com/llvm/llvm-project/commit/9e362bb0eb52732cd9224d02bb7ce613bb47c1fc
> DIFF: https://github.com/llvm/llvm-project/commit/9e362bb0eb52732cd9224d02bb7ce613bb47c1fc.diff
>
> LOG: [InstCombine] Remove unused entries in gc-live bundle of statepoint
>
> If some of gc live value are not used in gc.relocate we can remove them
> from gc-live bundle of statepoint instruction.
>
> Also the CL removes duplicated Values in gc-live bundle.
>
> Reviewers: reames, dantrushin
> Reviewed By: dantrushin
> Subscribers: llvm-commits
> Differential Revision: https://reviews.llvm.org/D85959
>
> Added:
>      
>
> Modified:
>      llvm/include/llvm/IR/Instructions.h
>      llvm/lib/IR/Instructions.cpp
>      llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
>      llvm/test/Transforms/InstCombine/statepoint-iter.ll
>
> Removed:
>      
>
>
> ################################################################################
> diff  --git a/llvm/include/llvm/IR/Instructions.h b/llvm/include/llvm/IR/Instructions.h
> index 63194fa93cbc..5beda48214d6 100644
> --- a/llvm/include/llvm/IR/Instructions.h
> +++ b/llvm/include/llvm/IR/Instructions.h
> @@ -1561,6 +1561,16 @@ class CallInst : public CallBase {
>     static CallInst *Create(CallInst *CI, ArrayRef<OperandBundleDef> Bundles,
>                             Instruction *InsertPt = nullptr);
>   
> +  /// Create a clone of \p CI with a
> diff erent set of operand bundles and
> +  /// insert it before \p InsertPt.
> +  ///
> +  /// The returned call instruction is identical \p CI in every way except that
> +  /// the operand bundle for the new instruction is set to the operand bundle
> +  /// in \p Bundle.
> +  static CallInst *CreateWithReplacedBundle(CallInst *CI,
> +                                            OperandBundleDef Bundle,
> +                                            Instruction *InsertPt = nullptr);
> +
>     /// Generate the IR for a call to malloc:
>     /// 1. Compute the malloc call's argument as the specified type's size,
>     ///    possibly multiplied by the array size if the array size is not
> @@ -3778,6 +3788,16 @@ class InvokeInst : public CallBase {
>     static InvokeInst *Create(InvokeInst *II, ArrayRef<OperandBundleDef> Bundles,
>                               Instruction *InsertPt = nullptr);
>   
> +  /// Create a clone of \p II with a
> diff erent set of operand bundles and
> +  /// insert it before \p InsertPt.
> +  ///
> +  /// The returned invoke instruction is identical to \p II in every way except
> +  /// that the operand bundle for the new instruction is set to the operand
> +  /// bundle in \p Bundle.
> +  static InvokeInst *CreateWithReplacedBundle(InvokeInst *II,
> +                                              OperandBundleDef Bundles,
> +                                              Instruction *InsertPt = nullptr);
> +
>     // get*Dest - Return the destination basic blocks...
>     BasicBlock *getNormalDest() const {
>       return cast<BasicBlock>(Op<NormalDestOpEndIdx>());
>
> diff  --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp
> index 7a3fbc367d1c..763b1f564ce1 100644
> --- a/llvm/lib/IR/Instructions.cpp
> +++ b/llvm/lib/IR/Instructions.cpp
> @@ -515,6 +515,18 @@ CallInst *CallInst::Create(CallInst *CI, ArrayRef<OperandBundleDef> OpB,
>     return NewCI;
>   }
>   
> +CallInst *CallInst::CreateWithReplacedBundle(CallInst *CI, OperandBundleDef OpB,
> +                                             Instruction *InsertPt) {
> +  SmallVector<OperandBundleDef, 2> OpDefs;
> +  for (unsigned i = 0, e = CI->getNumOperandBundles(); i < e; ++i) {
> +    auto ChildOB = CI->getOperandBundleAt(i);
> +    if (ChildOB.getTagName() != OpB.getTag())
> +      OpDefs.emplace_back(ChildOB);
> +  }
> +  OpDefs.emplace_back(OpB);
> +  return CallInst::Create(CI, OpDefs, InsertPt);
> +}
> +
>   // Update profile weight for call instruction by scaling it using the ratio
>   // of S/T. The meaning of "branch_weights" meta data for call instruction is
>   // transfered to represent call count.
> @@ -826,6 +838,18 @@ InvokeInst *InvokeInst::Create(InvokeInst *II, ArrayRef<OperandBundleDef> OpB,
>     return NewII;
>   }
>   
> +InvokeInst *InvokeInst::CreateWithReplacedBundle(InvokeInst *II,
> +                                                 OperandBundleDef OpB,
> +                                                 Instruction *InsertPt) {
> +  SmallVector<OperandBundleDef, 2> OpDefs;
> +  for (unsigned i = 0, e = II->getNumOperandBundles(); i < e; ++i) {
> +    auto ChildOB = II->getOperandBundleAt(i);
> +    if (ChildOB.getTagName() != OpB.getTag())
> +      OpDefs.emplace_back(ChildOB);
> +  }
> +  OpDefs.emplace_back(OpB);
> +  return InvokeInst::Create(II, OpDefs, InsertPt);
> +}
>   
>   LandingPadInst *InvokeInst::getLandingPadInst() const {
>     return cast<LandingPadInst>(getUnwindDest()->getFirstNonPHI());
>
> diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
> index aec8667c077d..c6c4105b9b30 100644
> --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
> +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
> @@ -1487,7 +1487,8 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
>       break;
>     }
>     case Intrinsic::experimental_gc_statepoint: {
> -    auto &GCSP = *cast<GCStatepointInst>(II);
> +    GCStatepointInst &GCSP = *cast<GCStatepointInst>(II);
> +    SmallPtrSet<Value *, 32> LiveGcValues;
>       for (const GCRelocateInst *Reloc : GCSP.getGCRelocates()) {
>         GCRelocateInst &GCR = *const_cast<GCRelocateInst *>(Reloc);
>   
> @@ -1539,7 +1540,48 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
>         // Canonicalize on the type from the uses to the defs
>   
>         // TODO: relocate((gep p, C, C2, ...)) -> gep(relocate(p), C, C2, ...)
> +      LiveGcValues.insert(BasePtr);
> +      LiveGcValues.insert(DerivedPtr);
>       }
> +    Optional<OperandBundleUse> Bundle =
> +        GCSP.getOperandBundle(LLVMContext::OB_gc_live);
> +    unsigned NumOfGCLives = LiveGcValues.size();
> +    if (!Bundle.hasValue() || NumOfGCLives == Bundle->Inputs.size())
> +      break;
> +    // We can reduce the size of gc live bundle.
> +    DenseMap<Value *, unsigned> Val2Idx;
> +    std::vector<Value *> NewLiveGc;
> +    for (unsigned I = 0, E = Bundle->Inputs.size(); I < E; ++I) {
> +      Value *V = Bundle->Inputs[I];
> +      if (Val2Idx.count(V))
> +        continue;
> +      if (LiveGcValues.count(V)) {
> +        Val2Idx[V] = NewLiveGc.size();
> +        NewLiveGc.push_back(V);
> +      } else
> +        Val2Idx[V] = NumOfGCLives;
> +    }
> +    // Update all gc.relocates
> +    for (const GCRelocateInst *Reloc : GCSP.getGCRelocates()) {
> +      GCRelocateInst &GCR = *const_cast<GCRelocateInst *>(Reloc);
> +      Value *BasePtr = GCR.getBasePtr();
> +      assert(Val2Idx.count(BasePtr) && Val2Idx[BasePtr] != NumOfGCLives &&
> +             "Missed live gc for base pointer");
> +      auto *OpIntTy1 = GCR.getOperand(1)->getType();
> +      GCR.setOperand(1, ConstantInt::get(OpIntTy1, Val2Idx[BasePtr]));
> +      Value *DerivedPtr = GCR.getDerivedPtr();
> +      assert(Val2Idx.count(DerivedPtr) && Val2Idx[DerivedPtr] != NumOfGCLives &&
> +             "Missed live gc for derived pointer");
> +      auto *OpIntTy2 = GCR.getOperand(2)->getType();
> +      GCR.setOperand(2, ConstantInt::get(OpIntTy2, Val2Idx[DerivedPtr]));
> +    }
> +    // Create new statepoint instruction.
> +    OperandBundleDef NewBundle("gc-live", NewLiveGc);
> +    if (isa<CallInst>(II))
> +      return CallInst::CreateWithReplacedBundle(cast<CallInst>(II), NewBundle);
> +    else
> +      return InvokeInst::CreateWithReplacedBundle(cast<InvokeInst>(II),
> +                                                  NewBundle);
>       break;
>     }
>     case Intrinsic::experimental_guard: {
>
> diff  --git a/llvm/test/Transforms/InstCombine/statepoint-iter.ll b/llvm/test/Transforms/InstCombine/statepoint-iter.ll
> index 53025a472b9f..a4865ea30f7a 100644
> --- a/llvm/test/Transforms/InstCombine/statepoint-iter.ll
> +++ b/llvm/test/Transforms/InstCombine/statepoint-iter.ll
> @@ -1,3 +1,4 @@
> +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
>   ; RUN: opt < %s -instcombine -instcombine-max-iterations=1 -S | FileCheck %s
>   ; These tests check the optimizations specific to
>   ; pointers being relocated at a statepoint.
> @@ -6,6 +7,18 @@
>   declare void @func()
>   
>   define i1 @test_null(i1 %cond) gc "statepoint-example" {
> +; CHECK-LABEL: @test_null(
> +; CHECK-NEXT:  entry:
> +; CHECK-NEXT:    br i1 [[COND:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]
> +; CHECK:       right:
> +; CHECK-NEXT:    br label [[MERGE:%.*]]
> +; CHECK:       left:
> +; CHECK-NEXT:    [[SAFEPOINT_TOKEN:%.*]] = tail call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* nonnull @func, i32 0, i32 0, i32 0, i32 0) [ "gc-live"() ]
> +; CHECK-NEXT:    br label [[MERGE]]
> +; CHECK:       merge:
> +; CHECK-NEXT:    [[SAFEPOINT_TOKEN2:%.*]] = tail call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* nonnull @func, i32 0, i32 0, i32 0, i32 0) [ "gc-live"() ]
> +; CHECK-NEXT:    ret i1 true
> +;
>   entry:
>     br i1 %cond, label %left, label %right
>   
> @@ -23,13 +36,21 @@ merge:
>     %pnew2 = call i32* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token2,  i32 0, i32 0)
>     %cmp = icmp eq i32* %pnew2, null
>     ret i1 %cmp
> -; CHECK-LABEL: test_null
> -; CHECK-NOT: %pnew
> -; CHECK-NOT: %pnew2
> -; CHECK: ret i1 true
>   }
>   
>   define i32* @test_undef(i1 %cond) gc "statepoint-example" {
> +; CHECK-LABEL: @test_undef(
> +; CHECK-NEXT:  entry:
> +; CHECK-NEXT:    br i1 [[COND:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]
> +; CHECK:       right:
> +; CHECK-NEXT:    br label [[MERGE:%.*]]
> +; CHECK:       left:
> +; CHECK-NEXT:    [[SAFEPOINT_TOKEN:%.*]] = tail call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* nonnull @func, i32 0, i32 0, i32 0, i32 0) [ "gc-live"() ]
> +; CHECK-NEXT:    br label [[MERGE]]
> +; CHECK:       merge:
> +; CHECK-NEXT:    [[SAFEPOINT_TOKEN2:%.*]] = tail call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* nonnull @func, i32 0, i32 0, i32 0, i32 0) [ "gc-live"() ]
> +; CHECK-NEXT:    ret i32* undef
> +;
>   entry:
>     br i1 %cond, label %left, label %right
>   
> @@ -46,10 +67,6 @@ merge:
>     %safepoint_token2 = tail call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0) ["gc-live" (i32* %pnew_phi)]
>     %pnew2 = call i32* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token2,  i32 0, i32 0)
>     ret i32* %pnew2
> -; CHECK-LABEL: test_undef
> -; CHECK-NOT: %pnew
> -; CHECK-NOT: %pnew2
> -; CHECK: ret i32* undef
>   }
>   
>   declare token @llvm.experimental.gc.statepoint.p0f_isVoidf(i64, i32, void ()*, i32, i32, ...)
>
>
>          
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits


More information about the llvm-commits mailing list