[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