Skip to content

Commit

Permalink
Merged master:0ad793f321ed into amd-gfx:5743f65431c1
Browse files Browse the repository at this point in the history
Local branch amd-gfx 5743f65 Merge remote-tracking branch 'llvm.org/master' into amd-gfx
Remote branch master 0ad793f [SCEV] Also use info from assumes in applyLoopGuards.
  • Loading branch information
Sw authored and Sw committed Sep 28, 2020
2 parents 5743f65 + 0ad793f commit 5e6c78e
Show file tree
Hide file tree
Showing 21 changed files with 443 additions and 215 deletions.
1 change: 1 addition & 0 deletions clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ add_clang_library(clangDaemonTweaks OBJECT
ExtractFunction.cpp
ExtractVariable.cpp
ObjCLocalizeStringLiteral.cpp
PopulateSwitch.cpp
RawStringLiteral.cpp
RemoveUsingNamespace.cpp
SwapIfBranches.cpp
Expand Down
146 changes: 146 additions & 0 deletions clang-tools-extra/clangd/refactor/tweaks/PopulateSwitch.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
//===--- PopulateSwitch.cpp --------------------------------------*- C++-*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Tweak that populates an empty switch statement of an enumeration type with
// all of the enumerators of that type.
//
// Before:
// enum Color { RED, GREEN, BLUE };
//
// void f(Color color) {
// switch (color) {}
// }
//
// After:
// enum Color { RED, GREEN, BLUE };
//
// void f(Color color) {
// switch (color) {
// case RED:
// case GREEN:
// case BLUE:
// break;
// }
// }
//
//===----------------------------------------------------------------------===//

#include "AST.h"
#include "Selection.h"
#include "refactor/Tweak.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/Type.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Tooling/Core/Replacement.h"
#include <string>

namespace clang {
namespace clangd {
namespace {
class PopulateSwitch : public Tweak {
const char *id() const override;
bool prepare(const Selection &Sel) override;
Expected<Effect> apply(const Selection &Sel) override;
std::string title() const override { return "Populate switch"; }
Intent intent() const override { return Refactor; }

private:
ASTContext *ASTCtx = nullptr;
const DeclContext *DeclCtx = nullptr;
const SwitchStmt *Switch = nullptr;
const CompoundStmt *Body = nullptr;
const EnumDecl *EnumD = nullptr;
};

REGISTER_TWEAK(PopulateSwitch)

bool PopulateSwitch::prepare(const Selection &Sel) {
ASTCtx = &Sel.AST->getASTContext();

const SelectionTree::Node *CA = Sel.ASTSelection.commonAncestor();
if (!CA)
return false;

const Stmt *CAStmt = CA->ASTNode.get<Stmt>();
if (!CAStmt)
return false;

// Go up a level if we see a compound statement.
// switch (value) {}
// ^^
if (isa<CompoundStmt>(CAStmt)) {
CA = CA->Parent;
if (!CA)
return false;

CAStmt = CA->ASTNode.get<Stmt>();
if (!CAStmt)
return false;
}

DeclCtx = &CA->getDeclContext();
Switch = dyn_cast<SwitchStmt>(CAStmt);
if (!Switch)
return false;

Body = dyn_cast<CompoundStmt>(Switch->getBody());
if (!Body)
return false;

// Since we currently always insert all enumerators, don't suggest this tweak
// if the body is not empty.
if (!Body->body_empty())
return false;

const Expr *Cond = Switch->getCond();
if (!Cond)
return false;

// Ignore implicit casts, since enums implicitly cast to integer types.
Cond = Cond->IgnoreParenImpCasts();

const EnumType *EnumT = Cond->getType()->getAsAdjusted<EnumType>();
if (!EnumT)
return false;

EnumD = EnumT->getDecl();
if (!EnumD)
return false;

// If there aren't any enumerators, there's nothing to insert.
if (EnumD->enumerator_begin() == EnumD->enumerator_end())
return false;

return true;
}

Expected<Tweak::Effect> PopulateSwitch::apply(const Selection &Sel) {
const SourceManager &SM = ASTCtx->getSourceManager();
SourceLocation Loc = Body->getRBracLoc();

std::string Text;
for (EnumConstantDecl *Enumerator : EnumD->enumerators()) {
Text += "case ";
Text += getQualification(*ASTCtx, DeclCtx, Loc, EnumD);
if (EnumD->isScoped()) {
Text += EnumD->getName();
Text += "::";
}
Text += Enumerator->getName();
Text += ":";
}
Text += "break;";

return Effect::mainFileEdit(
SM, tooling::Replacements(tooling::Replacement(SM, Loc, 0, Text)));
}
} // namespace
} // namespace clangd
} // namespace clang
90 changes: 90 additions & 0 deletions clang-tools-extra/clangd/unittests/TweakTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2813,6 +2813,96 @@ class cc {
}
}

TWEAK_TEST(PopulateSwitch);
TEST_F(PopulateSwitchTest, Test) {
struct Case {
CodeContext Context;
llvm::StringRef TestSource;
llvm::StringRef ExpectedSource;
};

Case Cases[]{
{
// No enumerators
Function,
R""(enum Enum {}; ^switch ((Enum)0) {})"",
"unavailable",
},
{
// Existing enumerators in switch
Function,
R""(enum Enum {A}; ^switch ((Enum)0) {case A:break;})"",
"unavailable",
},
{
// Body not CompoundStmt
Function,
R""(enum Enum {A}; ^switch (A);)"",
"unavailable",
},
{
// Selection on switch token
Function,
R""(enum Enum {A}; ^switch (A) {})"",
R""(enum Enum {A}; switch (A) {case A:break;})"",
},
{
// Selection on switch condition
Function,
R""(enum Enum {A}; switch (^A) {})"",
R""(enum Enum {A}; switch (A) {case A:break;})"",
},
{
// Selection in switch body
Function,
R""(enum Enum {A}; switch (A) {^})"",
R""(enum Enum {A}; switch (A) {case A:break;})"",
},
{
// Scoped enumeration
Function,
R""(enum class Enum {A}; ^switch (Enum::A) {})"",
R""(enum class Enum {A}; switch (Enum::A) {case Enum::A:break;})"",
},
{
// Scoped enumeration with multiple enumerators
Function,
R""(enum class Enum {A,B}; ^switch (Enum::A) {})"",
R""(enum class Enum {A,B}; )""
R""(switch (Enum::A) {case Enum::A:case Enum::B:break;})"",
},
{
// Scoped enumerations in namespace
File,
R""(
namespace ns { enum class Enum {A}; }
void function() { ^switch (ns::Enum::A) {} }
)"",
R""(
namespace ns { enum class Enum {A}; }
void function() { switch (ns::Enum::A) {case ns::Enum::A:break;} }
)"",
},
{
// Unscoped enumerations in namespace
File,
R""(
namespace ns { enum Enum {A}; }
void function() { ^switch (ns::A) {} }
)"",
R""(
namespace ns { enum Enum {A}; }
void function() { switch (ns::A) {case ns::A:break;} }
)"",
},
};

for (const auto &Case : Cases) {
Context = Case.Context;
EXPECT_EQ(apply(Case.TestSource), Case.ExpectedSource);
}
}

} // namespace
} // namespace clangd
} // namespace clang
18 changes: 9 additions & 9 deletions lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,21 +181,21 @@ llvm::Optional<Decl *> CxxModuleHandler::tryInstantiateStdTemplate(Decl *d) {
// If we don't have a template to instiantiate, then there is nothing to do.
auto td = dyn_cast<ClassTemplateSpecializationDecl>(d);
if (!td)
return {};
return llvm::None;

// We only care about templates in the std namespace.
if (!td->getDeclContext()->isStdNamespace())
return {};
return llvm::None;

// We have a list of supported template names.
if (m_supported_templates.find(td->getName()) == m_supported_templates.end())
return {};
if (!m_supported_templates.contains(td->getName()))
return llvm::None;

// Early check if we even support instantiating this template. We do this
// before we import anything into the target AST.
auto &foreign_args = td->getTemplateInstantiationArgs();
if (!templateArgsAreSupported(foreign_args.asArray()))
return {};
return llvm::None;

// Find the local DeclContext that corresponds to the DeclContext of our
// decl we want to import.
Expand All @@ -206,7 +206,7 @@ llvm::Optional<Decl *> CxxModuleHandler::tryInstantiateStdTemplate(Decl *d) {
"Got error while searching equal local DeclContext for decl "
"'{1}':\n{0}",
td->getName());
return {};
return llvm::None;
}

// Look up the template in our local context.
Expand All @@ -219,7 +219,7 @@ llvm::Optional<Decl *> CxxModuleHandler::tryInstantiateStdTemplate(Decl *d) {
break;
}
if (!new_class_template)
return {};
return llvm::None;

// Import the foreign template arguments.
llvm::SmallVector<TemplateArgument, 4> imported_args;
Expand All @@ -231,7 +231,7 @@ llvm::Optional<Decl *> CxxModuleHandler::tryInstantiateStdTemplate(Decl *d) {
llvm::Expected<QualType> type = m_importer->Import(arg.getAsType());
if (!type) {
LLDB_LOG_ERROR(log, type.takeError(), "Couldn't import type: {0}");
return {};
return llvm::None;
}
imported_args.push_back(TemplateArgument(*type));
break;
Expand All @@ -242,7 +242,7 @@ llvm::Optional<Decl *> CxxModuleHandler::tryInstantiateStdTemplate(Decl *d) {
m_importer->Import(arg.getIntegralType());
if (!type) {
LLDB_LOG_ERROR(log, type.takeError(), "Couldn't import type: {0}");
return {};
return llvm::None;
}
imported_args.push_back(
TemplateArgument(d->getASTContext(), integral, *type));
Expand Down
12 changes: 12 additions & 0 deletions llvm/lib/Analysis/ScalarEvolution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12658,6 +12658,18 @@ const SCEV *ScalarEvolution::applyLoopGuards(const SCEV *Expr, const Loop *L) {
getSCEV(Cmp->getOperand(1)), RewriteMap);
}

// Also collect information from assumptions dominating the loop.
for (auto &AssumeVH : AC.assumptions()) {
if (!AssumeVH)
continue;
auto *AssumeI = cast<CallInst>(AssumeVH);
auto *Cmp = dyn_cast<ICmpInst>(AssumeI->getOperand(0));
if (!Cmp || !DT.dominates(AssumeI, L->getHeader()))
continue;
CollectCondition(Cmp->getPredicate(), getSCEV(Cmp->getOperand(0)),
getSCEV(Cmp->getOperand(1)), RewriteMap);
}

if (RewriteMap.empty())
return Expr;
return SCEVParameterRewriter::rewrite(Expr, *this, RewriteMap);
Expand Down
37 changes: 10 additions & 27 deletions llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,33 +192,16 @@ void AArch64AsmPrinter::emitStartOfAsmFile(Module &M) {
return;

// Assemble feature flags that may require creation of a note section.
unsigned Flags = ELF::GNU_PROPERTY_AARCH64_FEATURE_1_BTI |
ELF::GNU_PROPERTY_AARCH64_FEATURE_1_PAC;

if (any_of(M, [](const Function &F) {
return !F.isDeclaration() &&
!F.hasFnAttribute("branch-target-enforcement");
})) {
Flags &= ~ELF::GNU_PROPERTY_AARCH64_FEATURE_1_BTI;
}

if ((Flags & ELF::GNU_PROPERTY_AARCH64_FEATURE_1_BTI) == 0 &&
any_of(M, [](const Function &F) {
return F.hasFnAttribute("branch-target-enforcement");
})) {
errs() << "warning: some functions compiled with BTI and some compiled "
"without BTI\n"
<< "warning: not setting BTI in feature flags\n";
}

if (any_of(M, [](const Function &F) {
if (F.isDeclaration())
return false;
Attribute A = F.getFnAttribute("sign-return-address");
return !A.isStringAttribute() || A.getValueAsString() == "none";
})) {
Flags &= ~ELF::GNU_PROPERTY_AARCH64_FEATURE_1_PAC;
}
unsigned Flags = 0;
if (const auto *BTE = mdconst::extract_or_null<ConstantInt>(
M.getModuleFlag("branch-target-enforcement")))
if (BTE->getZExtValue())
Flags |= ELF::GNU_PROPERTY_AARCH64_FEATURE_1_BTI;

if (const auto *Sign = mdconst::extract_or_null<ConstantInt>(
M.getModuleFlag("sign-return-address")))
if (Sign->getZExtValue())
Flags |= ELF::GNU_PROPERTY_AARCH64_FEATURE_1_PAC;

if (Flags == 0)
return;
Expand Down
Loading

0 comments on commit 5e6c78e

Please sign in to comment.