diff --git a/clang-tools-extra/clangd/refactor/Rename.cpp b/clang-tools-extra/clangd/refactor/Rename.cpp index 78aaa9930cd4a6..946daaf6d158da 100644 --- a/clang-tools-extra/clangd/refactor/Rename.cpp +++ b/clang-tools-extra/clangd/refactor/Rename.cpp @@ -124,6 +124,28 @@ const NamedDecl *canonicalRenameDecl(const NamedDecl *D) { if (const auto *Function = dyn_cast(D)) if (const FunctionTemplateDecl *Template = Function->getPrimaryTemplate()) return canonicalRenameDecl(Template); + if (const auto *Field = dyn_cast(D)) { + // This is a hacky way to do something like + // CXXMethodDecl::getInstantiatedFromMemberFunction for the field because + // Clang AST does not store relevant information about the field that is + // instantiated. + const auto *FieldParent = dyn_cast(Field->getParent()); + if (!FieldParent) + return Field->getCanonicalDecl(); + FieldParent = FieldParent->getTemplateInstantiationPattern(); + // Field is not instantiation. + if (!FieldParent || Field->getParent() == FieldParent) + return Field->getCanonicalDecl(); + for (const FieldDecl *Candidate : FieldParent->fields()) + if (Field->getDeclName() == Candidate->getDeclName()) + return Candidate->getCanonicalDecl(); + elog("FieldParent should have field with the same name as Field."); + } + if (const auto *VD = dyn_cast(D)) { + if (const VarDecl *OriginalVD = VD->getInstantiatedFromStaticDataMember()) + VD = OriginalVD; + return VD->getCanonicalDecl(); + } return dyn_cast(D->getCanonicalDecl()); } diff --git a/clang-tools-extra/clangd/unittests/RenameTests.cpp b/clang-tools-extra/clangd/unittests/RenameTests.cpp index c67339ff2be4e6..2382dba19659b7 100644 --- a/clang-tools-extra/clangd/unittests/RenameTests.cpp +++ b/clang-tools-extra/clangd/unittests/RenameTests.cpp @@ -540,6 +540,94 @@ TEST(RenameTest, WithinFileRename) { } )cpp", + // Fields in classes & partial and full specialiations. + R"cpp( + template + struct Foo { + T [[Vari^able]] = 42; + }; + + void foo() { + Foo f; + f.[[Varia^ble]] = 9000; + } + )cpp", + R"cpp( + template + struct Foo { + T Variable[42]; + U Another; + + void bar() {} + }; + + template + struct Foo { + T [[Var^iable]]; + void bar() { ++[[Var^iable]]; } + }; + + void foo() { + Foo f; + f.[[Var^iable]] = 9000; + } + )cpp", + R"cpp( + template + struct Foo { + T Variable[42]; + U Another; + + void bar() {} + }; + + template + struct Foo { + T Variable; + void bar() { ++Variable; } + }; + + template<> + struct Foo { + unsigned [[Var^iable]]; + void bar() { ++[[Var^iable]]; } + }; + + void foo() { + Foo f; + f.[[Var^iable]] = 9000; + } + )cpp", + // Static fields. + R"cpp( + struct Foo { + static int [[Var^iable]]; + }; + + int Foo::[[Var^iable]] = 42; + + void foo() { + int LocalInt = Foo::[[Var^iable]]; + } + )cpp", + R"cpp( + template + struct Foo { + static T [[Var^iable]]; + }; + + template <> + int Foo::[[Var^iable]] = 42; + + template <> + bool Foo::[[Var^iable]] = true; + + void foo() { + int LocalInt = Foo::[[Var^iable]]; + bool LocalBool = Foo::[[Var^iable]]; + } + )cpp", + // Template parameters. R"cpp( template diff --git a/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp b/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp index 290f3671afca9b..d37fe74a0039db 100644 --- a/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp @@ -1542,16 +1542,26 @@ bool WidenIV::widenWithVariantUse(WidenIV::NarrowIVDefUse DU) { auto AnotherOpExtKind = ExtKind; // Check that all uses are either s/zext, or narrow def (in case of we are - // widening the IV increment). + // widening the IV increment), or single-input LCSSA Phis. SmallVector ExtUsers; + SmallVector LCSSAPhiUsers; for (Use &U : NarrowUse->uses()) { - if (U.getUser() == NarrowDef) + Instruction *User = cast(U.getUser()); + if (User == NarrowDef) continue; - Instruction *User = nullptr; + if (!L->contains(User)) { + auto *LCSSAPhi = cast(User); + // Make sure there is only 1 input, so that we don't have to split + // critical edges. + if (LCSSAPhi->getNumOperands() != 1) + return false; + LCSSAPhiUsers.push_back(LCSSAPhi); + continue; + } if (ExtKind == SignExtended) - User = dyn_cast(U.getUser()); + User = dyn_cast(User); else - User = dyn_cast(U.getUser()); + User = dyn_cast(User); if (!User || User->getType() != WideType) return false; ExtUsers.push_back(User); @@ -1630,6 +1640,21 @@ bool WidenIV::widenWithVariantUse(WidenIV::NarrowIVDefUse DU) { User->replaceAllUsesWith(WideBO); DeadInsts.emplace_back(User); } + + for (PHINode *User : LCSSAPhiUsers) { + assert(User->getNumOperands() == 1 && "Checked before!"); + Builder.SetInsertPoint(User); + auto *WidePN = + Builder.CreatePHI(WideBO->getType(), 1, User->getName() + ".wide"); + BasicBlock *LoopExitingBlock = User->getParent()->getSinglePredecessor(); + assert(LoopExitingBlock && L->contains(LoopExitingBlock) && + "Not a LCSSA Phi?"); + WidePN->addIncoming(WideBO, LoopExitingBlock); + Builder.SetInsertPoint(User->getParent()->getFirstNonPHI()); + auto *TruncPN = Builder.CreateTrunc(WidePN, User->getType()); + User->replaceAllUsesWith(TruncPN); + DeadInsts.emplace_back(User); + } return true; } diff --git a/llvm/test/Transforms/IndVarSimplify/widen-loop-comp.ll b/llvm/test/Transforms/IndVarSimplify/widen-loop-comp.ll index 2bb37d23866e23..fb9b198fe8afb7 100644 --- a/llvm/test/Transforms/IndVarSimplify/widen-loop-comp.ll +++ b/llvm/test/Transforms/IndVarSimplify/widen-loop-comp.ll @@ -697,20 +697,18 @@ define i32 @test14(i32 %start, i32* %p, i32* %q) { ; CHECK: loop: ; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ [[TMP0]], [[ENTRY:%.*]] ] ; CHECK-NEXT: [[COND:%.*]] = icmp eq i64 [[INDVARS_IV]], 0 -; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[INDVARS_IV]] to i32 -; CHECK-NEXT: [[FOO:%.*]] = add i32 [[TMP1]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = add nsw i64 [[INDVARS_IV]], -1 ; CHECK-NEXT: br i1 [[COND]], label [[EXIT:%.*]], label [[BACKEDGE]] ; CHECK: backedge: -; CHECK-NEXT: [[INDEX:%.*]] = zext i32 [[FOO]] to i64 -; CHECK-NEXT: [[STORE_ADDR:%.*]] = getelementptr i32, i32* [[P:%.*]], i64 [[INDEX]] +; CHECK-NEXT: [[STORE_ADDR:%.*]] = getelementptr i32, i32* [[P:%.*]], i64 [[TMP1]] ; CHECK-NEXT: store i32 1, i32* [[STORE_ADDR]], align 4 -; CHECK-NEXT: [[LOAD_ADDR:%.*]] = getelementptr i32, i32* [[Q:%.*]], i64 [[INDEX]] -; CHECK-NEXT: [[STOP:%.*]] = load i32, i32* [[Q]], align 4 +; CHECK-NEXT: [[STOP:%.*]] = load i32, i32* [[Q:%.*]], align 4 ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp eq i32 [[STOP]], 0 ; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nsw i64 [[INDVARS_IV]], -1 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[FAILURE:%.*]] ; CHECK: exit: -; CHECK-NEXT: ret i32 -1 +; CHECK-NEXT: [[TMP2:%.*]] = trunc i64 -1 to i32 +; CHECK-NEXT: ret i32 [[TMP2]] ; CHECK: failure: ; CHECK-NEXT: unreachable ; @@ -750,24 +748,23 @@ define i32 @test15(i32 %start, i32* %p, i32* %q) { ; CHECK: loop: ; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ [[TMP0]], [[ENTRY:%.*]] ] ; CHECK-NEXT: [[COND:%.*]] = icmp eq i64 [[INDVARS_IV]], 0 -; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[INDVARS_IV]] to i32 -; CHECK-NEXT: [[FOO:%.*]] = add i32 [[TMP1]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = add nsw i64 [[INDVARS_IV]], -1 ; CHECK-NEXT: br i1 [[COND]], label [[EXIT:%.*]], label [[BACKEDGE]] ; CHECK: backedge: -; CHECK-NEXT: [[INDEX:%.*]] = zext i32 [[FOO]] to i64 -; CHECK-NEXT: [[STORE_ADDR:%.*]] = getelementptr i32, i32* [[P:%.*]], i64 [[INDEX]] +; CHECK-NEXT: [[STORE_ADDR:%.*]] = getelementptr i32, i32* [[P:%.*]], i64 [[TMP1]] ; CHECK-NEXT: store i32 1, i32* [[STORE_ADDR]], align 4 -; CHECK-NEXT: [[LOAD_ADDR:%.*]] = getelementptr i32, i32* [[Q:%.*]], i64 [[INDEX]] -; CHECK-NEXT: [[STOP:%.*]] = load i32, i32* [[Q]], align 4 +; CHECK-NEXT: [[STOP:%.*]] = load i32, i32* [[Q:%.*]], align 4 ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp eq i32 [[STOP]], 0 ; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nsw i64 [[INDVARS_IV]], -1 ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[FAILURE:%.*]] ; CHECK: exit: -; CHECK-NEXT: call void @use(i32 -1) -; CHECK-NEXT: ret i32 -1 +; CHECK-NEXT: [[TMP2:%.*]] = trunc i64 -1 to i32 +; CHECK-NEXT: call void @use(i32 [[TMP2]]) +; CHECK-NEXT: ret i32 [[TMP2]] ; CHECK: failure: -; CHECK-NEXT: [[FOO_LCSSA1:%.*]] = phi i32 [ [[FOO]], [[BACKEDGE]] ] -; CHECK-NEXT: call void @use(i32 [[FOO_LCSSA1]]) +; CHECK-NEXT: [[FOO_LCSSA1_WIDE:%.*]] = phi i64 [ [[TMP1]], [[BACKEDGE]] ] +; CHECK-NEXT: [[TMP3:%.*]] = trunc i64 [[FOO_LCSSA1_WIDE]] to i32 +; CHECK-NEXT: call void @use(i32 [[TMP3]]) ; CHECK-NEXT: unreachable ; entry: