Index: llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp =================================================================== --- llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp +++ llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp @@ -716,8 +716,10 @@ explicit BDVState(Value *OriginalValue) : OriginalValue(OriginalValue) {} - explicit BDVState(Value *OriginalValue, StatusTy Status, Value *BaseValue = nullptr) - : OriginalValue(OriginalValue), Status(Status), BaseValue(BaseValue) { + explicit BDVState(Value *OriginalValue, StatusTy Status, bool IsDerived, + Value *BaseValue = nullptr) + : OriginalValue(OriginalValue), Status(Status), IsDerived(IsDerived), + BaseValue(BaseValue) { assert(Status != Base || BaseValue); } @@ -728,6 +730,7 @@ bool isBase() const { return getStatus() == Base; } bool isUnknown() const { return getStatus() == Unknown; } bool isConflict() const { return getStatus() == Conflict; } + bool isDerived() const { return IsDerived; } // Values of type BDVState form a lattice, and this function implements the // meet @@ -736,14 +739,18 @@ auto markConflict = [&]() { Status = BDVState::Conflict; BaseValue = nullptr; + IsDerived |= Other.IsDerived; }; // Conflict is a final state. - if (isConflict()) + if (isConflict()) { + IsDerived |= Other.IsDerived; return; + } // if we are not known - just take other state. if (isUnknown()) { Status = Other.getStatus(); BaseValue = Other.getBaseValue(); + IsDerived = Other.IsDerived; return; } // We are base. @@ -760,11 +767,13 @@ if (getBaseValue() != Other.getBaseValue()) return markConflict(); // We are identical, do nothing. + IsDerived |= Other.IsDerived; } bool operator==(const BDVState &Other) const { - return OriginalValue == Other.OriginalValue && BaseValue == Other.BaseValue && - Status == Other.Status; + return OriginalValue == Other.OriginalValue && + BaseValue == Other.BaseValue && Status == Other.Status && + IsDerived == Other.IsDerived; } bool operator!=(const BDVState &other) const { return !(*this == other); } @@ -795,6 +804,7 @@ private: AssertingVH OriginalValue; // instruction this state corresponds to StatusTy Status = Unknown; + bool IsDerived = false; AssertingVH BaseValue = nullptr; // Non-null only if Status == Base. }; @@ -971,7 +981,8 @@ if (I != States.end()) return I->second; assert(areBothVectorOrScalar(BaseValue, Input)); - return BDVState(BaseValue, BDVState::Base, BaseValue); + return BDVState(BaseValue, BDVState::Base, + Input->stripPointerCasts() != BaseValue, BaseValue); }; bool Progress = true; @@ -1019,6 +1030,19 @@ } #endif + ToRemove.clear(); + for (auto Pair : States) { + Value *BDV = Pair.first; + if (!Pair.second.isDerived()) + ToRemove.push_back(BDV); + } + + for (Value *V : ToRemove) { + States.erase(V); + // Cache the fact V is it's own base for later usage. + Cache[V] = V; + } + // Handle all instructions that have a vector BDV, but the instruction itself // is of scalar type. for (auto Pair : States) { @@ -1046,14 +1070,14 @@ auto *BaseInst = ExtractElementInst::Create( State.getBaseValue(), EE->getIndexOperand(), "base_ee", EE); BaseInst->setMetadata("is_base_value", MDNode::get(I->getContext(), {})); - States[I] = BDVState(I, BDVState::Base, BaseInst); + States[I] = BDVState(I, BDVState::Base, false, BaseInst); } else if (!isa(I->getType())) { // We need to handle cases that have a vector base but the instruction is // a scalar type (these could be phis or selects or any instruction that // are of scalar type, but the base can be a vector type). We // conservatively set this as conflict. Setting the base value for these // conflicts is handled in the next loop which traverses States. - States[I] = BDVState(I, BDVState::Conflict); + States[I] = BDVState(I, BDVState::Conflict, true); } } @@ -1100,7 +1124,7 @@ BaseInst->setName(getMangledName(I)); // Add metadata marking this as a base value BaseInst->setMetadata("is_base_value", MDNode::get(I->getContext(), {})); - States[I] = BDVState(I, BDVState::Conflict, BaseInst); + States[I] = BDVState(I, BDVState::Conflict, true, BaseInst); } #ifndef NDEBUG Index: llvm/test/Transforms/RewriteStatepointsForGC/base-inference.ll =================================================================== --- llvm/test/Transforms/RewriteStatepointsForGC/base-inference.ll +++ llvm/test/Transforms/RewriteStatepointsForGC/base-inference.ll @@ -133,9 +133,8 @@ ; CHECK-NEXT: [[GEP]] = getelementptr i8, i8 addrspace(1)* [[PHI]], i64 16 ; CHECK-NEXT: br i1 [[C:%.*]], label [[EXIT:%.*]], label [[LOOP]] ; CHECK: exit: -; CHECK-NEXT: [[STATEPOINT_TOKEN:%.*]] = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 2882400000, i32 0, void ()* elementtype(void ()) @foo, i32 0, i32 0, i32 0, i32 0) [ "gc-live"(i8 addrspace(1)* [[PHI]], i8 addrspace(1)* [[A1]]) ] -; CHECK-NEXT: [[PHI_RELOCATED:%.*]] = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token [[STATEPOINT_TOKEN]], i32 1, i32 0) -; CHECK-NEXT: [[A1_RELOCATED:%.*]] = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token [[STATEPOINT_TOKEN]], i32 1, i32 1) +; CHECK-NEXT: [[STATEPOINT_TOKEN:%.*]] = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 2882400000, i32 0, void ()* elementtype(void ()) @foo, i32 0, i32 0, i32 0, i32 0) [ "gc-live"(i8 addrspace(1)* [[PHI]]) ] +; CHECK-NEXT: [[PHI_RELOCATED:%.*]] = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token [[STATEPOINT_TOKEN]], i32 0, i32 0) ; CHECK-NEXT: ret i8 addrspace(1)* [[PHI_RELOCATED]] ; entry: Index: llvm/test/Transforms/RewriteStatepointsForGC/base-pointers-10.ll =================================================================== --- llvm/test/Transforms/RewriteStatepointsForGC/base-pointers-10.ll +++ llvm/test/Transforms/RewriteStatepointsForGC/base-pointers-10.ll @@ -11,10 +11,8 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: -; CHECK-NEXT: [[DOT01:%.*]] = phi i64 addrspace(1)* [ [[BASE_OBJ_X:%.*]], [[ENTRY:%.*]] ], [ [[BASE_OBJ_X_RELOCATED_CASTED:%.*]], [[MERGE:%.*]] ] -; CHECK-NEXT: [[DOT0:%.*]] = phi i64 addrspace(1)* [ [[BASE_OBJ_Y:%.*]], [[ENTRY]] ], [ [[BASE_OBJ_Y_RELOCATED_CASTED:%.*]], [[MERGE]] ] -; CHECK-NEXT: [[CURRENT_X:%.*]] = phi i64 addrspace(1)* [ [[BASE_OBJ_X]], [[ENTRY]] ], [ [[NEXT_X_RELOCATED_CASTED:%.*]], [[MERGE]] ] -; CHECK-NEXT: [[CURRENT_Y:%.*]] = phi i64 addrspace(1)* [ [[BASE_OBJ_Y]], [[ENTRY]] ], [ [[NEXT_Y_RELOCATED_CASTED:%.*]], [[MERGE]] ] +; CHECK-NEXT: [[CURRENT_X:%.*]] = phi i64 addrspace(1)* [ [[BASE_OBJ_X:%.*]], [[ENTRY:%.*]] ], [ [[NEXT_X_REMAT:%.*]], [[MERGE:%.*]] ] +; CHECK-NEXT: [[CURRENT_Y:%.*]] = phi i64 addrspace(1)* [ [[BASE_OBJ_Y:%.*]], [[ENTRY]] ], [ [[NEXT_Y_REMAT:%.*]], [[MERGE]] ] ; CHECK-NEXT: [[CURRENT:%.*]] = phi i64 addrspace(1)* [ null, [[ENTRY]] ], [ [[NEXT_RELOCATED_CASTED:%.*]], [[MERGE]] ] ; CHECK-NEXT: [[CONDITION:%.*]] = call i1 @runtime_value() ; CHECK-NEXT: [[NEXT_X:%.*]] = getelementptr i64, i64 addrspace(1)* [[CURRENT_X]], i32 1 @@ -25,21 +23,16 @@ ; CHECK: false: ; CHECK-NEXT: br label [[MERGE]] ; CHECK: merge: -; CHECK-NEXT: [[NEXT_BASE:%.*]] = phi i64 addrspace(1)* [ [[DOT01]], [[TRUE]] ], [ [[DOT0]], [[FALSE]] ], !is_base_value !0 ; CHECK-NEXT: [[NEXT:%.*]] = phi i64 addrspace(1)* [ [[NEXT_X]], [[TRUE]] ], [ [[NEXT_Y]], [[FALSE]] ] -; CHECK-NEXT: [[STATEPOINT_TOKEN:%.*]] = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 2882400000, i32 0, void ()* elementtype(void ()) @do_safepoint, i32 0, i32 0, i32 0, i32 0) [ "deopt"(i32 0, i32 -1, i32 0, i32 0, i32 0), "gc-live"(i64 addrspace(1)* [[NEXT_X]], i64 addrspace(1)* [[NEXT_Y]], i64 addrspace(1)* [[NEXT]], i64 addrspace(1)* [[DOT01]], i64 addrspace(1)* [[DOT0]], i64 addrspace(1)* [[NEXT_BASE]]) ] -; CHECK-NEXT: [[NEXT_X_RELOCATED:%.*]] = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token [[STATEPOINT_TOKEN]], i32 3, i32 0) -; CHECK-NEXT: [[NEXT_X_RELOCATED_CASTED]] = bitcast i8 addrspace(1)* [[NEXT_X_RELOCATED]] to i64 addrspace(1)* -; CHECK-NEXT: [[NEXT_Y_RELOCATED:%.*]] = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token [[STATEPOINT_TOKEN]], i32 4, i32 1) -; CHECK-NEXT: [[NEXT_Y_RELOCATED_CASTED]] = bitcast i8 addrspace(1)* [[NEXT_Y_RELOCATED]] to i64 addrspace(1)* -; CHECK-NEXT: [[NEXT_RELOCATED:%.*]] = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token [[STATEPOINT_TOKEN]], i32 5, i32 2) +; CHECK-NEXT: [[STATEPOINT_TOKEN:%.*]] = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 2882400000, i32 0, void ()* elementtype(void ()) @do_safepoint, i32 0, i32 0, i32 0, i32 0) [ "deopt"(i32 0, i32 -1, i32 0, i32 0, i32 0), "gc-live"(i64 addrspace(1)* [[NEXT]], i64 addrspace(1)* [[CURRENT_X]], i64 addrspace(1)* [[CURRENT_Y]]) ] +; CHECK-NEXT: [[NEXT_RELOCATED:%.*]] = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token [[STATEPOINT_TOKEN]], i32 0, i32 0) ; CHECK-NEXT: [[NEXT_RELOCATED_CASTED]] = bitcast i8 addrspace(1)* [[NEXT_RELOCATED]] to i64 addrspace(1)* -; CHECK-NEXT: [[BASE_OBJ_X_RELOCATED:%.*]] = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token [[STATEPOINT_TOKEN]], i32 3, i32 3) -; CHECK-NEXT: [[BASE_OBJ_X_RELOCATED_CASTED]] = bitcast i8 addrspace(1)* [[BASE_OBJ_X_RELOCATED]] to i64 addrspace(1)* -; CHECK-NEXT: [[BASE_OBJ_Y_RELOCATED:%.*]] = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token [[STATEPOINT_TOKEN]], i32 4, i32 4) -; CHECK-NEXT: [[BASE_OBJ_Y_RELOCATED_CASTED]] = bitcast i8 addrspace(1)* [[BASE_OBJ_Y_RELOCATED]] to i64 addrspace(1)* -; CHECK-NEXT: [[NEXT_BASE_RELOCATED:%.*]] = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token [[STATEPOINT_TOKEN]], i32 5, i32 5) -; CHECK-NEXT: [[NEXT_BASE_RELOCATED_CASTED:%.*]] = bitcast i8 addrspace(1)* [[NEXT_BASE_RELOCATED]] to i64 addrspace(1)* +; CHECK-NEXT: [[CURRENT_X_RELOCATED:%.*]] = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token [[STATEPOINT_TOKEN]], i32 1, i32 1) +; CHECK-NEXT: [[CURRENT_X_RELOCATED_CASTED:%.*]] = bitcast i8 addrspace(1)* [[CURRENT_X_RELOCATED]] to i64 addrspace(1)* +; CHECK-NEXT: [[CURRENT_Y_RELOCATED:%.*]] = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token [[STATEPOINT_TOKEN]], i32 2, i32 2) +; CHECK-NEXT: [[CURRENT_Y_RELOCATED_CASTED:%.*]] = bitcast i8 addrspace(1)* [[CURRENT_Y_RELOCATED]] to i64 addrspace(1)* +; CHECK-NEXT: [[NEXT_Y_REMAT]] = getelementptr i64, i64 addrspace(1)* [[CURRENT_Y_RELOCATED_CASTED]], i32 1 +; CHECK-NEXT: [[NEXT_X_REMAT]] = getelementptr i64, i64 addrspace(1)* [[CURRENT_X_RELOCATED_CASTED]], i32 1 ; CHECK-NEXT: br label [[LOOP]] ; entry: Index: llvm/test/Transforms/RewriteStatepointsForGC/base-pointers-14.ll =================================================================== --- llvm/test/Transforms/RewriteStatepointsForGC/base-pointers-14.ll +++ llvm/test/Transforms/RewriteStatepointsForGC/base-pointers-14.ll @@ -32,22 +32,17 @@ ret i8 addrspace(1)* %b6 } -; FIXME: In this test case %b5.base and %b6.base (inserted by RS4GC) are -; identical to %b5 and %b6 ; correspondingly. define i8 addrspace(1)* @test2(i1 %c, i8 addrspace(1)* %b1, i8 addrspace(1)* %b2) gc "statepoint-example" { ; CHECK-LABEL: @test2( ; CHECK-NEXT: left: ; CHECK-NEXT: br i1 [[C:%.*]], label [[LOOP:%.*]], label [[MERGE2:%.*]] ; CHECK: loop: -; CHECK-NEXT: [[B5_BASE:%.*]] = phi i8 addrspace(1)* [ [[B2:%.*]], [[LEFT:%.*]] ], [ [[B5_BASE]], [[LOOP]] ], [ [[B6_BASE_RELOCATED:%.*]], [[MERGE2]] ], !is_base_value !0 -; CHECK-NEXT: [[B5:%.*]] = phi i8 addrspace(1)* [ [[B2]], [[LEFT]] ], [ [[B5]], [[LOOP]] ], [ [[B6_RELOCATED:%.*]], [[MERGE2]] ] +; CHECK-NEXT: [[B5:%.*]] = phi i8 addrspace(1)* [ [[B2:%.*]], [[LEFT:%.*]] ], [ [[B5]], [[LOOP]] ], [ [[B6_RELOCATED:%.*]], [[MERGE2]] ] ; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[MERGE2]] ; CHECK: merge2: -; CHECK-NEXT: [[B6_BASE:%.*]] = phi i8 addrspace(1)* [ [[B1:%.*]], [[LEFT]] ], [ [[B5_BASE]], [[LOOP]] ], !is_base_value !0 -; CHECK-NEXT: [[B6:%.*]] = phi i8 addrspace(1)* [ [[B1]], [[LEFT]] ], [ [[B5]], [[LOOP]] ] -; CHECK-NEXT: [[STATEPOINT_TOKEN:%.*]] = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 2882400000, i32 0, void ()* elementtype(void ()) @foo, i32 0, i32 0, i32 0, i32 0) [ "deopt"(), "gc-live"(i8 addrspace(1)* [[B6_BASE]], i8 addrspace(1)* [[B6]]) ] -; CHECK-NEXT: [[B6_BASE_RELOCATED]] = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token [[STATEPOINT_TOKEN]], i32 0, i32 0) -; CHECK-NEXT: [[B6_RELOCATED]] = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token [[STATEPOINT_TOKEN]], i32 0, i32 1) +; CHECK-NEXT: [[B6:%.*]] = phi i8 addrspace(1)* [ [[B1:%.*]], [[LEFT]] ], [ [[B5]], [[LOOP]] ] +; CHECK-NEXT: [[STATEPOINT_TOKEN:%.*]] = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 2882400000, i32 0, void ()* elementtype(void ()) @foo, i32 0, i32 0, i32 0, i32 0) [ "deopt"(), "gc-live"(i8 addrspace(1)* [[B6]]) ] +; CHECK-NEXT: [[B6_RELOCATED]] = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token [[STATEPOINT_TOKEN]], i32 0, i32 0) ; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]] ; CHECK: exit: ; CHECK-NEXT: ret i8 addrspace(1)* [[B6_RELOCATED]] Index: llvm/test/Transforms/RewriteStatepointsForGC/base-pointers-9.ll =================================================================== --- llvm/test/Transforms/RewriteStatepointsForGC/base-pointers-9.ll +++ llvm/test/Transforms/RewriteStatepointsForGC/base-pointers-9.ll @@ -10,16 +10,13 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: -; CHECK-NEXT: [[DOT0:%.*]] = phi i64 addrspace(1)* [ [[BASE_OBJ:%.*]], [[ENTRY:%.*]] ], [ [[BASE_OBJ_RELOCATED_CASTED:%.*]], [[LOOP]] ] -; CHECK-NEXT: [[CURRENT:%.*]] = phi i64 addrspace(1)* [ [[BASE_OBJ]], [[ENTRY]] ], [ [[NEXT_RELOCATED_CASTED:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[CURRENT:%.*]] = phi i64 addrspace(1)* [ [[BASE_OBJ:%.*]], [[ENTRY:%.*]] ], [ [[NEXT_RELOCATED_CASTED:%.*]], [[LOOP]] ] ; CHECK-NEXT: [[CONDITION:%.*]] = call i1 @runtime_value() ; CHECK-NEXT: [[MAYBE_NEXT:%.*]] = getelementptr i64, i64 addrspace(1)* [[CURRENT]], i32 1 ; CHECK-NEXT: [[NEXT:%.*]] = select i1 [[CONDITION]], i64 addrspace(1)* [[MAYBE_NEXT]], i64 addrspace(1)* [[CURRENT]] -; CHECK-NEXT: [[STATEPOINT_TOKEN:%.*]] = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 2882400000, i32 0, void ()* elementtype(void ()) @do_safepoint, i32 0, i32 0, i32 0, i32 0) [ "deopt"(i32 0, i32 -1, i32 0, i32 0, i32 0), "gc-live"(i64 addrspace(1)* [[NEXT]], i64 addrspace(1)* [[DOT0]]) ] -; CHECK-NEXT: [[NEXT_RELOCATED:%.*]] = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token [[STATEPOINT_TOKEN]], i32 1, i32 0) +; CHECK-NEXT: [[STATEPOINT_TOKEN:%.*]] = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 2882400000, i32 0, void ()* elementtype(void ()) @do_safepoint, i32 0, i32 0, i32 0, i32 0) [ "deopt"(i32 0, i32 -1, i32 0, i32 0, i32 0), "gc-live"(i64 addrspace(1)* [[NEXT]]) ] +; CHECK-NEXT: [[NEXT_RELOCATED:%.*]] = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token [[STATEPOINT_TOKEN]], i32 0, i32 0) ; CHECK-NEXT: [[NEXT_RELOCATED_CASTED]] = bitcast i8 addrspace(1)* [[NEXT_RELOCATED]] to i64 addrspace(1)* -; CHECK-NEXT: [[BASE_OBJ_RELOCATED:%.*]] = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token [[STATEPOINT_TOKEN]], i32 1, i32 1) -; CHECK-NEXT: [[BASE_OBJ_RELOCATED_CASTED]] = bitcast i8 addrspace(1)* [[BASE_OBJ_RELOCATED]] to i64 addrspace(1)* ; CHECK-NEXT: br label [[LOOP]] ; entry: