191 changes: 164 additions & 27 deletions clang/lib/Analysis/UnsafeBufferUsage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@
//===----------------------------------------------------------------------===//

#include "clang/Analysis/Analyses/UnsafeBufferUsage.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Lex/Lexer.h"
Expand Down Expand Up @@ -281,10 +284,13 @@ isInUnspecifiedPointerContext(internal::Matcher<Stmt> InnerMatcher) {
// 4. the operand of a pointer subtraction operation
// (i.e., computing the distance between two pointers); or ...

auto CallArgMatcher =
callExpr(forEachArgumentWithParam(InnerMatcher,
hasPointerType() /* array also decays to pointer type*/),
unless(callee(functionDecl(hasAttr(attr::UnsafeBufferUsage)))));
// clang-format off
auto CallArgMatcher = callExpr(
forEachArgumentWithParamType(
InnerMatcher,
isAnyPointer() /* array also decays to pointer type*/),
unless(callee(
functionDecl(hasAttr(attr::UnsafeBufferUsage)))));

auto CastOperandMatcher =
castExpr(anyOf(hasCastKind(CastKind::CK_PointerToIntegral),
Expand All @@ -306,6 +312,7 @@ isInUnspecifiedPointerContext(internal::Matcher<Stmt> InnerMatcher) {
hasRHS(hasPointerType())),
eachOf(hasLHS(InnerMatcher),
hasRHS(InnerMatcher)));
// clang-format on

return stmt(anyOf(CallArgMatcher, CastOperandMatcher, CompOperandMatcher,
PtrSubtractionMatcher));
Expand Down Expand Up @@ -402,6 +409,39 @@ AST_MATCHER(CXXConstructExpr, isSafeSpanTwoParamConstruct) {
}
return false;
}

AST_MATCHER(ArraySubscriptExpr, isSafeArraySubscript) {
// FIXME: Proper solution:
// - refactor Sema::CheckArrayAccess
// - split safe/OOB/unknown decision logic from diagnostics emitting code
// - e. g. "Try harder to find a NamedDecl to point at in the note."
// already duplicated
// - call both from Sema and from here

const auto *BaseDRE =
dyn_cast<DeclRefExpr>(Node.getBase()->IgnoreParenImpCasts());
if (!BaseDRE)
return false;
if (!BaseDRE->getDecl())
return false;
const auto *CATy = Finder->getASTContext().getAsConstantArrayType(
BaseDRE->getDecl()->getType());
if (!CATy)
return false;
const APInt ArrSize = CATy->getSize();

if (const auto *IdxLit = dyn_cast<IntegerLiteral>(Node.getIdx())) {
const APInt ArrIdx = IdxLit->getValue();
// FIXME: ArrIdx.isNegative() we could immediately emit an error as that's a
// bug
if (ArrIdx.isNonNegative() &&
ArrIdx.getLimitedValue() < ArrSize.getLimitedValue())
return true;
}

return false;
}

} // namespace clang::ast_matchers

namespace {
Expand Down Expand Up @@ -594,16 +634,16 @@ class ArraySubscriptGadget : public WarningGadget {
}

static Matcher matcher() {
// FIXME: What if the index is integer literal 0? Should this be
// a safe gadget in this case?
// clang-format off
// clang-format off
return stmt(arraySubscriptExpr(
hasBase(ignoringParenImpCasts(
anyOf(hasPointerType(), hasArrayType()))),
unless(hasIndex(
anyOf(integerLiteral(equals(0)), arrayInitIndexExpr())
)))
.bind(ArraySubscrTag));
unless(anyOf(
isSafeArraySubscript(),
hasIndex(
anyOf(integerLiteral(equals(0)), arrayInitIndexExpr())
)
))).bind(ArraySubscrTag));
// clang-format on
}

Expand Down Expand Up @@ -762,21 +802,22 @@ class PointerInitGadget : public FixableGadget {
/// \code
/// p = q;
/// \endcode
class PointerAssignmentGadget : public FixableGadget {
/// where both `p` and `q` are pointers.
class PtrToPtrAssignmentGadget : public FixableGadget {
private:
static constexpr const char *const PointerAssignLHSTag = "ptrLHS";
static constexpr const char *const PointerAssignRHSTag = "ptrRHS";
const DeclRefExpr * PtrLHS; // the LHS pointer expression in `PA`
const DeclRefExpr * PtrRHS; // the RHS pointer expression in `PA`

public:
PointerAssignmentGadget(const MatchFinder::MatchResult &Result)
: FixableGadget(Kind::PointerAssignment),
PtrLHS(Result.Nodes.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)),
PtrRHS(Result.Nodes.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {}
PtrToPtrAssignmentGadget(const MatchFinder::MatchResult &Result)
: FixableGadget(Kind::PtrToPtrAssignment),
PtrLHS(Result.Nodes.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)),
PtrRHS(Result.Nodes.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {}

static bool classof(const Gadget *G) {
return G->getKind() == Kind::PointerAssignment;
return G->getKind() == Kind::PtrToPtrAssignment;
}

static Matcher matcher() {
Expand Down Expand Up @@ -811,6 +852,60 @@ class PointerAssignmentGadget : public FixableGadget {
}
};

/// An assignment expression of the form:
/// \code
/// ptr = array;
/// \endcode
/// where `p` is a pointer and `array` is a constant size array.
class CArrayToPtrAssignmentGadget : public FixableGadget {
private:
static constexpr const char *const PointerAssignLHSTag = "ptrLHS";
static constexpr const char *const PointerAssignRHSTag = "ptrRHS";
const DeclRefExpr *PtrLHS; // the LHS pointer expression in `PA`
const DeclRefExpr *PtrRHS; // the RHS pointer expression in `PA`

public:
CArrayToPtrAssignmentGadget(const MatchFinder::MatchResult &Result)
: FixableGadget(Kind::CArrayToPtrAssignment),
PtrLHS(Result.Nodes.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)),
PtrRHS(Result.Nodes.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {}

static bool classof(const Gadget *G) {
return G->getKind() == Kind::CArrayToPtrAssignment;
}

static Matcher matcher() {
auto PtrAssignExpr = binaryOperator(
allOf(hasOperatorName("="),
hasRHS(ignoringParenImpCasts(
declRefExpr(hasType(hasCanonicalType(constantArrayType())),
toSupportedVariable())
.bind(PointerAssignRHSTag))),
hasLHS(declRefExpr(hasPointerType(), toSupportedVariable())
.bind(PointerAssignLHSTag))));

return stmt(isInUnspecifiedUntypedContext(PtrAssignExpr));
}

virtual std::optional<FixItList>
getFixits(const FixitStrategy &S) const override;

virtual const Stmt *getBaseStmt() const override {
// FIXME: This should be the binary operator, assuming that this method
// makes sense at all on a FixableGadget.
return PtrLHS;
}

virtual DeclUseList getClaimedVarUseSites() const override {
return DeclUseList{PtrLHS, PtrRHS};
}

virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
getStrategyImplications() const override {
return {};
}
};

/// A call of a function or method that performs unchecked buffer operations
/// over one of its pointer parameters.
class UnsafeBufferUsageAttrGadget : public WarningGadget {
Expand Down Expand Up @@ -1434,7 +1529,7 @@ bool clang::internal::anyConflict(const SmallVectorImpl<FixItHint> &FixIts,
}

std::optional<FixItList>
PointerAssignmentGadget::getFixits(const FixitStrategy &S) const {
PtrToPtrAssignmentGadget::getFixits(const FixitStrategy &S) const {
const auto *LeftVD = cast<VarDecl>(PtrLHS->getDecl());
const auto *RightVD = cast<VarDecl>(PtrRHS->getDecl());
switch (S.lookup(LeftVD)) {
Expand All @@ -1453,6 +1548,42 @@ PointerAssignmentGadget::getFixits(const FixitStrategy &S) const {
return std::nullopt;
}

/// \returns fixit that adds .data() call after \DRE.
static inline std::optional<FixItList> createDataFixit(const ASTContext &Ctx,
const DeclRefExpr *DRE);

std::optional<FixItList>
CArrayToPtrAssignmentGadget::getFixits(const FixitStrategy &S) const {
const auto *LeftVD = cast<VarDecl>(PtrLHS->getDecl());
const auto *RightVD = cast<VarDecl>(PtrRHS->getDecl());
// TLDR: Implementing fixits for non-Wontfix strategy on both LHS and RHS is
// non-trivial.
//
// CArrayToPtrAssignmentGadget doesn't have strategy implications because
// constant size array propagates its bounds. Because of that LHS and RHS are
// addressed by two different fixits.
//
// At the same time FixitStrategy S doesn't reflect what group a fixit belongs
// to and can't be generally relied on in multi-variable Fixables!
//
// E. g. If an instance of this gadget is fixing variable on LHS then the
// variable on RHS is fixed by a different fixit and its strategy for LHS
// fixit is as if Wontfix.
//
// The only exception is Wontfix strategy for a given variable as that is
// valid for any fixit produced for the given input source code.
if (S.lookup(LeftVD) == FixitStrategy::Kind::Span) {
if (S.lookup(RightVD) == FixitStrategy::Kind::Wontfix) {
return FixItList{};
}
} else if (S.lookup(LeftVD) == FixitStrategy::Kind::Wontfix) {
if (S.lookup(RightVD) == FixitStrategy::Kind::Array) {
return createDataFixit(RightVD->getASTContext(), PtrRHS);
}
}
return std::nullopt;
}

std::optional<FixItList>
PointerInitGadget::getFixits(const FixitStrategy &S) const {
const auto *LeftVD = PtrInitLHS;
Expand Down Expand Up @@ -1870,27 +2001,33 @@ PointerDereferenceGadget::getFixits(const FixitStrategy &S) const {
return std::nullopt;
}

static inline std::optional<FixItList> createDataFixit(const ASTContext &Ctx,
const DeclRefExpr *DRE) {
const SourceManager &SM = Ctx.getSourceManager();
// Inserts the .data() after the DRE
std::optional<SourceLocation> EndOfOperand =
getPastLoc(DRE, SM, Ctx.getLangOpts());

if (EndOfOperand)
return FixItList{{FixItHint::CreateInsertion(*EndOfOperand, ".data()")}};

return std::nullopt;
}

// Generates fix-its replacing an expression of the form UPC(DRE) with
// `DRE.data()`
std::optional<FixItList>
UPCStandalonePointerGadget::getFixits(const FixitStrategy &S) const {
const auto VD = cast<VarDecl>(Node->getDecl());
switch (S.lookup(VD)) {
case FixitStrategy::Kind::Array:
case FixitStrategy::Kind::Span: {
ASTContext &Ctx = VD->getASTContext();
SourceManager &SM = Ctx.getSourceManager();
// Inserts the .data() after the DRE
std::optional<SourceLocation> EndOfOperand =
getPastLoc(Node, SM, Ctx.getLangOpts());

if (EndOfOperand)
return FixItList{{FixItHint::CreateInsertion(*EndOfOperand, ".data()")}};
return createDataFixit(VD->getASTContext(), Node);
// FIXME: Points inside a macro expansion.
break;
}
case FixitStrategy::Kind::Wontfix:
case FixitStrategy::Kind::Iterator:
case FixitStrategy::Kind::Array:
return std::nullopt;
case FixitStrategy::Kind::Vector:
llvm_unreachable("unsupported strategies for FixableGadgets");
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Basic/FileManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -547,7 +547,7 @@ FileManager::getBufferForFile(FileEntryRef FE, bool isVolatile,
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
FileManager::getBufferForFileImpl(StringRef Filename, int64_t FileSize,
bool isVolatile,
bool RequiresNullTerminator) {
bool RequiresNullTerminator) const {
if (FileSystemOpts.WorkingDir.empty())
return FS->getBufferForFile(Filename, FileSize, RequiresNullTerminator,
isVolatile);
Expand Down
18 changes: 9 additions & 9 deletions clang/lib/Basic/IdentifierTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ using namespace clang;
// A check to make sure the ObjCOrBuiltinID has sufficient room to store the
// largest possible target/aux-target combination. If we exceed this, we likely
// need to just change the ObjCOrBuiltinIDBits value in IdentifierTable.h.
static_assert(2 * LargestBuiltinID < (2 << (ObjCOrBuiltinIDBits - 1)),
static_assert(2 * LargestBuiltinID < (2 << (InterestingIdentifierBits - 1)),
"Insufficient ObjCOrBuiltinID Bits");

//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -280,13 +280,13 @@ static void AddObjCKeyword(StringRef Name,
Table.get(Name).setObjCKeywordID(ObjCID);
}

static void AddInterestingIdentifier(StringRef Name,
tok::InterestingIdentifierKind BTID,
IdentifierTable &Table) {
// Don't add 'not_interesting' identifier.
if (BTID != tok::not_interesting) {
static void AddNotableIdentifier(StringRef Name,
tok::NotableIdentifierKind BTID,
IdentifierTable &Table) {
// Don't add 'not_notable' identifier.
if (BTID != tok::not_notable) {
IdentifierInfo &Info = Table.get(Name, tok::identifier);
Info.setInterestingIdentifierID(BTID);
Info.setNotableIdentifierID(BTID);
}
}

Expand All @@ -306,8 +306,8 @@ void IdentifierTable::AddKeywords(const LangOptions &LangOpts) {
#define OBJC_AT_KEYWORD(NAME) \
if (LangOpts.ObjC) \
AddObjCKeyword(StringRef(#NAME), tok::objc_##NAME, *this);
#define INTERESTING_IDENTIFIER(NAME) \
AddInterestingIdentifier(StringRef(#NAME), tok::NAME, *this);
#define NOTABLE_IDENTIFIER(NAME) \
AddNotableIdentifier(StringRef(#NAME), tok::NAME, *this);

#define TESTING_KEYWORD(NAME, FLAGS)
#include "clang/Basic/TokenKinds.def"
Expand Down
16 changes: 14 additions & 2 deletions clang/lib/Basic/Targets/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -367,8 +367,20 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts,

// ACLE predefines. Many can only have one possible value on v8 AArch64.
Builder.defineMacro("__ARM_ACLE", "200");
Builder.defineMacro("__ARM_ARCH",
std::to_string(ArchInfo->Version.getMajor()));

// __ARM_ARCH is defined as an integer value indicating the current ARM ISA.
// For ISAs up to and including v8, __ARM_ARCH is equal to the major version
// number. For ISAs from v8.1 onwards, __ARM_ARCH is scaled up to include the
// minor version number, e.g. for ARM architecture ARMvX.Y:
// __ARM_ARCH = X * 100 + Y.
if (ArchInfo->Version.getMajor() == 8 && ArchInfo->Version.getMinor() == 0)
Builder.defineMacro("__ARM_ARCH",
std::to_string(ArchInfo->Version.getMajor()));
else
Builder.defineMacro("__ARM_ARCH",
std::to_string(ArchInfo->Version.getMajor() * 100 +
ArchInfo->Version.getMinor().value()));

Builder.defineMacro("__ARM_ARCH_PROFILE",
std::string("'") + (char)ArchInfo->Profile + "'");

Expand Down
3 changes: 1 addition & 2 deletions clang/lib/Basic/Targets/AMDGPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -285,10 +285,9 @@ void AMDGPUTargetInfo::getTargetDefines(const LangOptions &Opts,
: getArchNameR600(GPUKind));

// Sanitize the name of generic targets.
// e.g. gfx10.1-generic -> gfx10_1_generic
// e.g. gfx10-1-generic -> gfx10_1_generic
if (GPUKind >= llvm::AMDGPU::GK_AMDGCN_GENERIC_FIRST &&
GPUKind <= llvm::AMDGPU::GK_AMDGCN_GENERIC_LAST) {
std::replace(CanonName.begin(), CanonName.end(), '.', '_');
std::replace(CanonName.begin(), CanonName.end(), '-', '_');
}

Expand Down
14 changes: 11 additions & 3 deletions clang/lib/Basic/Targets/ARM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ void ARMTargetInfo::setArchInfo(llvm::ARM::ArchKind Kind) {
SubArch = llvm::ARM::getSubArch(ArchKind);
ArchProfile = llvm::ARM::parseArchProfile(SubArch);
ArchVersion = llvm::ARM::parseArchVersion(SubArch);
ArchMinorVersion = llvm::ARM::parseArchMinorVersion(SubArch);

// cache CPU related strings
CPUAttr = getCPUAttr();
Expand Down Expand Up @@ -736,9 +737,16 @@ void ARMTargetInfo::getTargetDefines(const LangOptions &Opts,
if (!CPUAttr.empty())
Builder.defineMacro("__ARM_ARCH_" + CPUAttr + "__");

// ACLE 6.4.1 ARM/Thumb instruction set architecture
// __ARM_ARCH is defined as an integer value indicating the current ARM ISA
Builder.defineMacro("__ARM_ARCH", Twine(ArchVersion));
// __ARM_ARCH is defined as an integer value indicating the current ARM ISA.
// For ISAs up to and including v8, __ARM_ARCH is equal to the major version
// number. For ISAs from v8.1 onwards, __ARM_ARCH is scaled up to include the
// minor version number, e.g. for ARM architecture ARMvX.Y:
// __ARM_ARCH = X * 100 + Y.
if (ArchVersion >= 9 || ArchMinorVersion != 0)
Builder.defineMacro("__ARM_ARCH",
Twine(ArchVersion * 100 + ArchMinorVersion));
else
Builder.defineMacro("__ARM_ARCH", Twine(ArchVersion));

if (ArchVersion >= 8) {
// ACLE 6.5.7 Crypto Extension
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/Targets/ARM.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class LLVM_LIBRARY_VISIBILITY ARMTargetInfo : public TargetInfo {
llvm::ARM::ArchKind ArchKind = llvm::ARM::ArchKind::ARMV4T;
llvm::ARM::ProfileKind ArchProfile;
unsigned ArchVersion;
unsigned ArchMinorVersion;

LLVM_PREFERRED_TYPE(FPUMode)
unsigned FPU : 5;
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ add_subdirectory(Tooling)
add_subdirectory(DirectoryWatcher)
add_subdirectory(Index)
add_subdirectory(IndexSerialization)
add_subdirectory(InstallAPI)
add_subdirectory(StaticAnalyzer)
add_subdirectory(Format)
if(CLANG_INCLUDE_TESTS)
Expand Down
16 changes: 10 additions & 6 deletions clang/lib/CodeGen/BackendConsumer.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class BackendConsumer : public ASTConsumer {
const CodeGenOptions &CodeGenOpts;
const TargetOptions &TargetOpts;
const LangOptions &LangOpts;
const FileManager &FileMgr;
std::unique_ptr<raw_pwrite_stream> AsmOutStream;
ASTContext *Context;
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS;
Expand Down Expand Up @@ -74,8 +75,8 @@ class BackendConsumer : public ASTConsumer {
const HeaderSearchOptions &HeaderSearchOpts,
const PreprocessorOptions &PPOpts,
const CodeGenOptions &CodeGenOpts,
const TargetOptions &TargetOpts,
const LangOptions &LangOpts, const std::string &InFile,
const TargetOptions &TargetOpts, const LangOptions &LangOpts,
const FileManager &FileMgr, const std::string &InFile,
SmallVector<LinkModule, 4> LinkModules,
std::unique_ptr<raw_pwrite_stream> OS, llvm::LLVMContext &C,
CoverageSourceInfo *CoverageInfo = nullptr);
Expand All @@ -88,8 +89,8 @@ class BackendConsumer : public ASTConsumer {
const HeaderSearchOptions &HeaderSearchOpts,
const PreprocessorOptions &PPOpts,
const CodeGenOptions &CodeGenOpts,
const TargetOptions &TargetOpts,
const LangOptions &LangOpts, llvm::Module *Module,
const TargetOptions &TargetOpts, const LangOptions &LangOpts,
const FileManager &FileMgr, llvm::Module *Module,
SmallVector<LinkModule, 4> LinkModules, llvm::LLVMContext &C,
CoverageSourceInfo *CoverageInfo = nullptr);

Expand All @@ -111,10 +112,13 @@ class BackendConsumer : public ASTConsumer {
void AssignInheritanceModel(CXXRecordDecl *RD) override;
void HandleVTable(CXXRecordDecl *RD) override;


// Links each entry in LinkModules into our module. Returns true on error.
// Links each entry in LinkModules into our module. Returns true on error.
bool LinkInModules(llvm::Module *M, bool ShouldLinkFiles = true);

// Load a bitcode module from -mlink-builtin-bitcode option using
// methods from a BackendConsumer instead of CompilerInstance
bool ReloadModules(llvm::Module *M);

/// Get the best possible source location to represent a diagnostic that
/// may have associated debug info.
const FullSourceLoc getBestLocationFromDebugLoc(
Expand Down
8 changes: 4 additions & 4 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3443,6 +3443,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Function *F = CGM.getIntrinsic(Intrinsic::readcyclecounter);
return RValue::get(Builder.CreateCall(F));
}
case Builtin::BI__builtin_readsteadycounter: {
Function *F = CGM.getIntrinsic(Intrinsic::readsteadycounter);
return RValue::get(Builder.CreateCall(F));
}
case Builtin::BI__builtin___clear_cache: {
Value *Begin = EmitScalarExpr(E->getArg(0));
Value *End = EmitScalarExpr(E->getArg(1));
Expand Down Expand Up @@ -5908,8 +5912,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
}
}

assert(ArgValue->getType()->canLosslesslyBitCastTo(PTy) &&
"Must be able to losslessly bit cast to param");
// Cast vector type (e.g., v256i32) to x86_amx, this only happen
// in amx intrinsics.
if (PTy->isX86_AMXTy())
Expand Down Expand Up @@ -5939,8 +5941,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
}
}

assert(V->getType()->canLosslesslyBitCastTo(RetTy) &&
"Must be able to losslessly bit cast result type");
// Cast x86_amx to vector type (e.g., v256i32), this only happen
// in amx intrinsics.
if (V->getType()->isX86_AMXTy())
Expand Down
50 changes: 25 additions & 25 deletions clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1301,27 +1301,25 @@ static llvm::Value *CreateCoercedLoad(Address Src, llvm::Type *Ty,
// If coercing a fixed vector to a scalable vector for ABI compatibility, and
// the types match, use the llvm.vector.insert intrinsic to perform the
// conversion.
if (auto *ScalableDst = dyn_cast<llvm::ScalableVectorType>(Ty)) {
if (auto *FixedSrc = dyn_cast<llvm::FixedVectorType>(SrcTy)) {
// If we are casting a fixed i8 vector to a scalable 16 x i1 predicate
if (auto *ScalableDstTy = dyn_cast<llvm::ScalableVectorType>(Ty)) {
if (auto *FixedSrcTy = dyn_cast<llvm::FixedVectorType>(SrcTy)) {
// If we are casting a fixed i8 vector to a scalable i1 predicate
// vector, use a vector insert and bitcast the result.
bool NeedsBitcast = false;
auto PredType =
llvm::ScalableVectorType::get(CGF.Builder.getInt1Ty(), 16);
llvm::Type *OrigType = Ty;
if (ScalableDst == PredType &&
FixedSrc->getElementType() == CGF.Builder.getInt8Ty()) {
ScalableDst = llvm::ScalableVectorType::get(CGF.Builder.getInt8Ty(), 2);
NeedsBitcast = true;
if (ScalableDstTy->getElementType()->isIntegerTy(1) &&
ScalableDstTy->getElementCount().isKnownMultipleOf(8) &&
FixedSrcTy->getElementType()->isIntegerTy(8)) {
ScalableDstTy = llvm::ScalableVectorType::get(
FixedSrcTy->getElementType(),
ScalableDstTy->getElementCount().getKnownMinValue() / 8);
}
if (ScalableDst->getElementType() == FixedSrc->getElementType()) {
if (ScalableDstTy->getElementType() == FixedSrcTy->getElementType()) {
auto *Load = CGF.Builder.CreateLoad(Src);
auto *UndefVec = llvm::UndefValue::get(ScalableDst);
auto *UndefVec = llvm::UndefValue::get(ScalableDstTy);
auto *Zero = llvm::Constant::getNullValue(CGF.CGM.Int64Ty);
llvm::Value *Result = CGF.Builder.CreateInsertVector(
ScalableDst, UndefVec, Load, Zero, "cast.scalable");
if (NeedsBitcast)
Result = CGF.Builder.CreateBitCast(Result, OrigType);
ScalableDstTy, UndefVec, Load, Zero, "cast.scalable");
if (ScalableDstTy != Ty)
Result = CGF.Builder.CreateBitCast(Result, Ty);
return Result;
}
}
Expand Down Expand Up @@ -3199,13 +3197,14 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
llvm::Value *Coerced = Fn->getArg(FirstIRArg);
if (auto *VecTyFrom =
dyn_cast<llvm::ScalableVectorType>(Coerced->getType())) {
// If we are casting a scalable 16 x i1 predicate vector to a fixed i8
// If we are casting a scalable i1 predicate vector to a fixed i8
// vector, bitcast the source and use a vector extract.
auto PredType =
llvm::ScalableVectorType::get(Builder.getInt1Ty(), 16);
if (VecTyFrom == PredType &&
if (VecTyFrom->getElementType()->isIntegerTy(1) &&
VecTyFrom->getElementCount().isKnownMultipleOf(8) &&
VecTyTo->getElementType() == Builder.getInt8Ty()) {
VecTyFrom = llvm::ScalableVectorType::get(Builder.getInt8Ty(), 2);
VecTyFrom = llvm::ScalableVectorType::get(
VecTyTo->getElementType(),
VecTyFrom->getElementCount().getKnownMinValue() / 8);
Coerced = Builder.CreateBitCast(Coerced, VecTyFrom);
}
if (VecTyFrom->getElementType() == VecTyTo->getElementType()) {
Expand Down Expand Up @@ -5877,12 +5876,13 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
// If coercing a fixed vector from a scalable vector for ABI
// compatibility, and the types match, use the llvm.vector.extract
// intrinsic to perform the conversion.
if (auto *FixedDst = dyn_cast<llvm::FixedVectorType>(RetIRTy)) {
if (auto *FixedDstTy = dyn_cast<llvm::FixedVectorType>(RetIRTy)) {
llvm::Value *V = CI;
if (auto *ScalableSrc = dyn_cast<llvm::ScalableVectorType>(V->getType())) {
if (FixedDst->getElementType() == ScalableSrc->getElementType()) {
if (auto *ScalableSrcTy =
dyn_cast<llvm::ScalableVectorType>(V->getType())) {
if (FixedDstTy->getElementType() == ScalableSrcTy->getElementType()) {
llvm::Value *Zero = llvm::Constant::getNullValue(CGM.Int64Ty);
V = Builder.CreateExtractVector(FixedDst, V, Zero, "cast.fixed");
V = Builder.CreateExtractVector(FixedDstTy, V, Zero, "cast.fixed");
return RValue::get(V);
}
}
Expand Down
51 changes: 25 additions & 26 deletions clang/lib/CodeGen/CGExprScalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2137,26 +2137,24 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
// If Src is a fixed vector and Dst is a scalable vector, and both have the
// same element type, use the llvm.vector.insert intrinsic to perform the
// bitcast.
if (const auto *FixedSrc = dyn_cast<llvm::FixedVectorType>(SrcTy)) {
if (const auto *ScalableDst = dyn_cast<llvm::ScalableVectorType>(DstTy)) {
// If we are casting a fixed i8 vector to a scalable 16 x i1 predicate
if (auto *FixedSrcTy = dyn_cast<llvm::FixedVectorType>(SrcTy)) {
if (auto *ScalableDstTy = dyn_cast<llvm::ScalableVectorType>(DstTy)) {
// If we are casting a fixed i8 vector to a scalable i1 predicate
// vector, use a vector insert and bitcast the result.
bool NeedsBitCast = false;
auto PredType = llvm::ScalableVectorType::get(Builder.getInt1Ty(), 16);
llvm::Type *OrigType = DstTy;
if (ScalableDst == PredType &&
FixedSrc->getElementType() == Builder.getInt8Ty()) {
DstTy = llvm::ScalableVectorType::get(Builder.getInt8Ty(), 2);
ScalableDst = cast<llvm::ScalableVectorType>(DstTy);
NeedsBitCast = true;
if (ScalableDstTy->getElementType()->isIntegerTy(1) &&
ScalableDstTy->getElementCount().isKnownMultipleOf(8) &&
FixedSrcTy->getElementType()->isIntegerTy(8)) {
ScalableDstTy = llvm::ScalableVectorType::get(
FixedSrcTy->getElementType(),
ScalableDstTy->getElementCount().getKnownMinValue() / 8);
}
if (FixedSrc->getElementType() == ScalableDst->getElementType()) {
llvm::Value *UndefVec = llvm::UndefValue::get(DstTy);
if (FixedSrcTy->getElementType() == ScalableDstTy->getElementType()) {
llvm::Value *UndefVec = llvm::UndefValue::get(ScalableDstTy);
llvm::Value *Zero = llvm::Constant::getNullValue(CGF.CGM.Int64Ty);
llvm::Value *Result = Builder.CreateInsertVector(
DstTy, UndefVec, Src, Zero, "cast.scalable");
if (NeedsBitCast)
Result = Builder.CreateBitCast(Result, OrigType);
ScalableDstTy, UndefVec, Src, Zero, "cast.scalable");
if (Result->getType() != DstTy)
Result = Builder.CreateBitCast(Result, DstTy);
return Result;
}
}
Expand All @@ -2165,18 +2163,19 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
// If Src is a scalable vector and Dst is a fixed vector, and both have the
// same element type, use the llvm.vector.extract intrinsic to perform the
// bitcast.
if (const auto *ScalableSrc = dyn_cast<llvm::ScalableVectorType>(SrcTy)) {
if (const auto *FixedDst = dyn_cast<llvm::FixedVectorType>(DstTy)) {
// If we are casting a scalable 16 x i1 predicate vector to a fixed i8
if (auto *ScalableSrcTy = dyn_cast<llvm::ScalableVectorType>(SrcTy)) {
if (auto *FixedDstTy = dyn_cast<llvm::FixedVectorType>(DstTy)) {
// If we are casting a scalable i1 predicate vector to a fixed i8
// vector, bitcast the source and use a vector extract.
auto PredType = llvm::ScalableVectorType::get(Builder.getInt1Ty(), 16);
if (ScalableSrc == PredType &&
FixedDst->getElementType() == Builder.getInt8Ty()) {
SrcTy = llvm::ScalableVectorType::get(Builder.getInt8Ty(), 2);
ScalableSrc = cast<llvm::ScalableVectorType>(SrcTy);
Src = Builder.CreateBitCast(Src, SrcTy);
if (ScalableSrcTy->getElementType()->isIntegerTy(1) &&
ScalableSrcTy->getElementCount().isKnownMultipleOf(8) &&
FixedDstTy->getElementType()->isIntegerTy(8)) {
ScalableSrcTy = llvm::ScalableVectorType::get(
FixedDstTy->getElementType(),
ScalableSrcTy->getElementCount().getKnownMinValue() / 8);
Src = Builder.CreateBitCast(Src, ScalableSrcTy);
}
if (ScalableSrc->getElementType() == FixedDst->getElementType()) {
if (ScalableSrcTy->getElementType() == FixedDstTy->getElementType()) {
llvm::Value *Zero = llvm::Constant::getNullValue(CGF.CGM.Int64Ty);
return Builder.CreateExtractVector(DstTy, Src, Zero, "cast.fixed");
}
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/CodeGen/CGStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,9 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) {
case Stmt::OMPParallelMaskedDirectiveClass:
EmitOMPParallelMaskedDirective(cast<OMPParallelMaskedDirective>(*S));
break;
case Stmt::OpenACCComputeConstructClass:
EmitOpenACCComputeConstruct(cast<OpenACCComputeConstruct>(*S));
break;
}
}

Expand Down
162 changes: 86 additions & 76 deletions clang/lib/CodeGen/CodeGenAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,56 +109,52 @@ static void reportOptRecordError(Error E, DiagnosticsEngine &Diags,
});
}

BackendConsumer::BackendConsumer(BackendAction Action, DiagnosticsEngine &Diags,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
const HeaderSearchOptions &HeaderSearchOpts,
const PreprocessorOptions &PPOpts,
const CodeGenOptions &CodeGenOpts,
const TargetOptions &TargetOpts,
const LangOptions &LangOpts,
const std::string &InFile,
SmallVector<LinkModule, 4> LinkModules,
std::unique_ptr<raw_pwrite_stream> OS,
LLVMContext &C,
CoverageSourceInfo *CoverageInfo)
: Diags(Diags), Action(Action), HeaderSearchOpts(HeaderSearchOpts),
CodeGenOpts(CodeGenOpts), TargetOpts(TargetOpts), LangOpts(LangOpts),
AsmOutStream(std::move(OS)), Context(nullptr), FS(VFS),
LLVMIRGeneration("irgen", "LLVM IR Generation Time"),
LLVMIRGenerationRefCount(0),
Gen(CreateLLVMCodeGen(Diags, InFile, std::move(VFS), HeaderSearchOpts,
PPOpts, CodeGenOpts, C, CoverageInfo)),
LinkModules(std::move(LinkModules)) {
TimerIsEnabled = CodeGenOpts.TimePasses;
llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses;
llvm::TimePassesPerRun = CodeGenOpts.TimePassesPerRun;
BackendConsumer::BackendConsumer(
BackendAction Action, DiagnosticsEngine &Diags,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
const HeaderSearchOptions &HeaderSearchOpts,
const PreprocessorOptions &PPOpts, const CodeGenOptions &CodeGenOpts,
const TargetOptions &TargetOpts, const LangOptions &LangOpts,
const FileManager &FileMgr, const std::string &InFile,
SmallVector<LinkModule, 4> LinkModules,
std::unique_ptr<raw_pwrite_stream> OS, LLVMContext &C,
CoverageSourceInfo *CoverageInfo)
: Diags(Diags), Action(Action), HeaderSearchOpts(HeaderSearchOpts),
CodeGenOpts(CodeGenOpts), TargetOpts(TargetOpts), LangOpts(LangOpts),
FileMgr(FileMgr), AsmOutStream(std::move(OS)), Context(nullptr), FS(VFS),
LLVMIRGeneration("irgen", "LLVM IR Generation Time"),
LLVMIRGenerationRefCount(0),
Gen(CreateLLVMCodeGen(Diags, InFile, std::move(VFS), HeaderSearchOpts,
PPOpts, CodeGenOpts, C, CoverageInfo)),
LinkModules(std::move(LinkModules)) {
TimerIsEnabled = CodeGenOpts.TimePasses;
llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses;
llvm::TimePassesPerRun = CodeGenOpts.TimePassesPerRun;
}

// This constructor is used in installing an empty BackendConsumer
// to use the clang diagnostic handler for IR input files. It avoids
// initializing the OS field.
BackendConsumer::BackendConsumer(BackendAction Action, DiagnosticsEngine &Diags,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
const HeaderSearchOptions &HeaderSearchOpts,
const PreprocessorOptions &PPOpts,
const CodeGenOptions &CodeGenOpts,
const TargetOptions &TargetOpts,
const LangOptions &LangOpts,
llvm::Module *Module,
SmallVector<LinkModule, 4> LinkModules,
LLVMContext &C,
CoverageSourceInfo *CoverageInfo)
: Diags(Diags), Action(Action), HeaderSearchOpts(HeaderSearchOpts),
CodeGenOpts(CodeGenOpts), TargetOpts(TargetOpts), LangOpts(LangOpts),
Context(nullptr), FS(VFS),
LLVMIRGeneration("irgen", "LLVM IR Generation Time"),
LLVMIRGenerationRefCount(0),
Gen(CreateLLVMCodeGen(Diags, "", std::move(VFS), HeaderSearchOpts,
PPOpts, CodeGenOpts, C, CoverageInfo)),
LinkModules(std::move(LinkModules)), CurLinkModule(Module) {
TimerIsEnabled = CodeGenOpts.TimePasses;
llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses;
llvm::TimePassesPerRun = CodeGenOpts.TimePassesPerRun;
BackendConsumer::BackendConsumer(
BackendAction Action, DiagnosticsEngine &Diags,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
const HeaderSearchOptions &HeaderSearchOpts,
const PreprocessorOptions &PPOpts, const CodeGenOptions &CodeGenOpts,
const TargetOptions &TargetOpts, const LangOptions &LangOpts,
const FileManager &FileMgr, llvm::Module *Module,
SmallVector<LinkModule, 4> LinkModules, LLVMContext &C,
CoverageSourceInfo *CoverageInfo)
: Diags(Diags), Action(Action), HeaderSearchOpts(HeaderSearchOpts),
CodeGenOpts(CodeGenOpts), TargetOpts(TargetOpts), LangOpts(LangOpts),
FileMgr(FileMgr), Context(nullptr), FS(VFS),
LLVMIRGeneration("irgen", "LLVM IR Generation Time"),
LLVMIRGenerationRefCount(0),
Gen(CreateLLVMCodeGen(Diags, "", std::move(VFS), HeaderSearchOpts, PPOpts,
CodeGenOpts, C, CoverageInfo)),
LinkModules(std::move(LinkModules)), CurLinkModule(Module) {
TimerIsEnabled = CodeGenOpts.TimePasses;
llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses;
llvm::TimePassesPerRun = CodeGenOpts.TimePassesPerRun;
}

llvm::Module* BackendConsumer::getModule() const {
Expand Down Expand Up @@ -233,9 +229,37 @@ void BackendConsumer::HandleInterestingDecl(DeclGroupRef D) {
HandleTopLevelDecl(D);
}

bool BackendConsumer::ReloadModules(llvm::Module *M) {
for (const CodeGenOptions::BitcodeFileToLink &F :
CodeGenOpts.LinkBitcodeFiles) {
auto BCBuf = FileMgr.getBufferForFile(F.Filename);
if (!BCBuf) {
Diags.Report(diag::err_cannot_open_file)
<< F.Filename << BCBuf.getError().message();
LinkModules.clear();
return true;
}

LLVMContext &Ctx = getModule()->getContext();
Expected<std::unique_ptr<llvm::Module>> ModuleOrErr =
getOwningLazyBitcodeModule(std::move(*BCBuf), Ctx);

if (!ModuleOrErr) {
handleAllErrors(ModuleOrErr.takeError(), [&](ErrorInfoBase &EIB) {
Diags.Report(diag::err_cannot_open_file) << F.Filename << EIB.message();
});
LinkModules.clear();
return true;
}
LinkModules.push_back({std::move(ModuleOrErr.get()), F.PropagateAttrs,
F.Internalize, F.LinkFlags});
}

return false; // success
}

// Links each entry in LinkModules into our module. Returns true on error.
bool BackendConsumer::LinkInModules(llvm::Module *M, bool ShouldLinkFiles) {

for (auto &LM : LinkModules) {
assert(LM.Module && "LinkModule does not actually have a module");

Expand All @@ -257,37 +281,22 @@ bool BackendConsumer::LinkInModules(llvm::Module *M, bool ShouldLinkFiles) {
CurLinkModule = LM.Module.get();
bool Err;

auto DoLink = [&](auto &Mod) {
if (LM.Internalize) {
Err = Linker::linkModules(
*M, std::move(Mod), LM.LinkFlags,
[](llvm::Module &M, const llvm::StringSet<> &GVS) {
internalizeModule(M, [&GVS](const llvm::GlobalValue &GV) {
return !GV.hasName() || (GVS.count(GV.getName()) == 0);
});
if (LM.Internalize) {
Err = Linker::linkModules(
*M, std::move(LM.Module), LM.LinkFlags,
[](llvm::Module &M, const llvm::StringSet<> &GVS) {
internalizeModule(M, [&GVS](const llvm::GlobalValue &GV) {
return !GV.hasName() || (GVS.count(GV.getName()) == 0);
});
} else
Err = Linker::linkModules(*M, std::move(Mod), LM.LinkFlags);
};

// Create a Clone to move to the linker, which preserves the original
// linking modules, allowing them to be linked again in the future
if (ClRelinkBuiltinBitcodePostop) {
// TODO: If CloneModule() is updated to support cloning of unmaterialized
// modules, we can remove this
if (Error E = CurLinkModule->materializeAll())
return false;

std::unique_ptr<llvm::Module> Clone = llvm::CloneModule(*LM.Module);
});
} else
Err = Linker::linkModules(*M, std::move(LM.Module), LM.LinkFlags);

DoLink(Clone);
}
// Otherwise we can link (and clean up) the original modules
else {
DoLink(LM.Module);
}
if (Err)
return true;
}

LinkModules.clear();
return false; // success
}

Expand Down Expand Up @@ -1037,8 +1046,9 @@ CodeGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
std::unique_ptr<BackendConsumer> Result(new BackendConsumer(
BA, CI.getDiagnostics(), &CI.getVirtualFileSystem(),
CI.getHeaderSearchOpts(), CI.getPreprocessorOpts(), CI.getCodeGenOpts(),
CI.getTargetOpts(), CI.getLangOpts(), std::string(InFile),
std::move(LinkModules), std::move(OS), *VMContext, CoverageInfo));
CI.getTargetOpts(), CI.getLangOpts(), CI.getFileManager(),
std::string(InFile), std::move(LinkModules), std::move(OS), *VMContext,
CoverageInfo));
BEConsumer = Result.get();

// Enable generating macro debug info only when debug info is not disabled and
Expand Down Expand Up @@ -1199,7 +1209,7 @@ void CodeGenAction::ExecuteAction() {
BackendConsumer Result(BA, CI.getDiagnostics(), &CI.getVirtualFileSystem(),
CI.getHeaderSearchOpts(), CI.getPreprocessorOpts(),
CI.getCodeGenOpts(), CI.getTargetOpts(),
CI.getLangOpts(), TheModule.get(),
CI.getLangOpts(), CI.getFileManager(), TheModule.get(),
std::move(LinkModules), *VMContext, nullptr);

// Link in each pending link module.
Expand Down
10 changes: 10 additions & 0 deletions clang/lib/CodeGen/CodeGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExprOpenMP.h"
#include "clang/AST/StmtOpenACC.h"
#include "clang/AST/StmtOpenMP.h"
#include "clang/AST/Type.h"
#include "clang/Basic/ABI.h"
Expand Down Expand Up @@ -3840,6 +3841,15 @@ class CodeGenFunction : public CodeGenTypeCache {
void EmitSections(const OMPExecutableDirective &S);

public:
//===--------------------------------------------------------------------===//
// OpenACC Emission
//===--------------------------------------------------------------------===//
void EmitOpenACCComputeConstruct(const OpenACCComputeConstruct &S) {
// TODO OpenACC: Implement this. It is currently implemented as a 'no-op',
// simply emitting its structured block, but in the future we will implement
// some sort of IR.
EmitStmt(S.getStructuredBlock());
}

//===--------------------------------------------------------------------===//
// LValue Expression Emission
Expand Down
14 changes: 14 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/RISCVISAInfo.h"
#include "llvm/Support/TimeProfiler.h"
#include "llvm/Support/xxhash.h"
#include "llvm/TargetParser/Triple.h"
Expand Down Expand Up @@ -1057,6 +1058,19 @@ void CodeGenModule::Release() {
llvm::LLVMContext &Ctx = TheModule.getContext();
getModule().addModuleFlag(llvm::Module::Error, "target-abi",
llvm::MDString::get(Ctx, ABIStr));

// Add the canonical ISA string as metadata so the backend can set the ELF
// attributes correctly. We use AppendUnique so LTO will keep all of the
// unique ISA strings that were linked together.
const std::vector<std::string> &Features =
getTarget().getTargetOpts().Features;
auto ParseResult =
llvm::RISCVISAInfo::parseFeatures(T.isRISCV64() ? 64 : 32, Features);
if (!errorToBool(ParseResult.takeError()))
getModule().addModuleFlag(
llvm::Module::AppendUnique, "riscv-isa",
llvm::MDNode::get(
Ctx, llvm::MDString::get(Ctx, (*ParseResult)->toString())));
}

if (CodeGenOpts.SanitizeCfiCrossDso) {
Expand Down
53 changes: 25 additions & 28 deletions clang/lib/CodeGen/CodeGenPGO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,7 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> {
llvm::DenseMap<const Stmt *, unsigned> &CounterMap;
/// The next bitmap byte index to assign.
unsigned NextMCDCBitmapIdx;
/// The map of statements to MC/DC bitmap coverage objects.
llvm::DenseMap<const Stmt *, unsigned> &MCDCBitmapMap;
MCDC::State &MCDCState;
/// Maximum number of supported MC/DC conditions in a boolean expression.
unsigned MCDCMaxCond;
/// The profile version.
Expand All @@ -176,11 +175,11 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> {

MapRegionCounters(PGOHashVersion HashVersion, uint64_t ProfileVersion,
llvm::DenseMap<const Stmt *, unsigned> &CounterMap,
llvm::DenseMap<const Stmt *, unsigned> &MCDCBitmapMap,
unsigned MCDCMaxCond, DiagnosticsEngine &Diag)
MCDC::State &MCDCState, unsigned MCDCMaxCond,
DiagnosticsEngine &Diag)
: NextCounter(0), Hash(HashVersion), CounterMap(CounterMap),
NextMCDCBitmapIdx(0), MCDCBitmapMap(MCDCBitmapMap),
MCDCMaxCond(MCDCMaxCond), ProfileVersion(ProfileVersion), Diag(Diag) {}
NextMCDCBitmapIdx(0), MCDCState(MCDCState), MCDCMaxCond(MCDCMaxCond),
ProfileVersion(ProfileVersion), Diag(Diag) {}

// Blocks and lambdas are handled as separate functions, so we need not
// traverse them in the parent context.
Expand Down Expand Up @@ -309,7 +308,7 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> {

// Otherwise, allocate the number of bytes required for the bitmap
// based on the number of conditions. Must be at least 1-byte long.
MCDCBitmapMap[BinOp] = NextMCDCBitmapIdx;
MCDCState.BitmapMap[BinOp] = NextMCDCBitmapIdx;
unsigned SizeInBits = std::max<unsigned>(1L << NumCond, CHAR_BIT);
NextMCDCBitmapIdx += SizeInBits / CHAR_BIT;
}
Expand Down Expand Up @@ -987,10 +986,9 @@ void CodeGenPGO::mapRegionCounters(const Decl *D) {
unsigned MCDCMaxConditions = (CGM.getCodeGenOpts().MCDCCoverage) ? 6 : 0;

RegionCounterMap.reset(new llvm::DenseMap<const Stmt *, unsigned>);
RegionMCDCBitmapMap.reset(new llvm::DenseMap<const Stmt *, unsigned>);
RegionMCDCState.reset(new MCDC::State);
MapRegionCounters Walker(HashVersion, ProfileVersion, *RegionCounterMap,
*RegionMCDCBitmapMap, MCDCMaxConditions,
CGM.getDiags());
*RegionMCDCState, MCDCMaxConditions, CGM.getDiags());
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
Walker.TraverseDecl(const_cast<FunctionDecl *>(FD));
else if (const ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(D))
Expand All @@ -1001,7 +999,7 @@ void CodeGenPGO::mapRegionCounters(const Decl *D) {
Walker.TraverseDecl(const_cast<CapturedDecl *>(CD));
assert(Walker.NextCounter > 0 && "no entry counter mapped for decl");
NumRegionCounters = Walker.NextCounter;
MCDCBitmapBytes = Walker.NextMCDCBitmapIdx;
RegionMCDCState->BitmapBytes = Walker.NextMCDCBitmapIdx;
FunctionHash = Walker.Hash.finalize();
}

Expand Down Expand Up @@ -1033,11 +1031,10 @@ void CodeGenPGO::emitCounterRegionMapping(const Decl *D) {

std::string CoverageMapping;
llvm::raw_string_ostream OS(CoverageMapping);
RegionCondIDMap.reset(new llvm::DenseMap<const Stmt *, unsigned>);
RegionCondIDMap.reset(new llvm::DenseMap<const Stmt *, int16_t>);
CoverageMappingGen MappingGen(
*CGM.getCoverageMapping(), CGM.getContext().getSourceManager(),
CGM.getLangOpts(), RegionCounterMap.get(), RegionMCDCBitmapMap.get(),
RegionCondIDMap.get());
CGM.getLangOpts(), RegionCounterMap.get(), RegionMCDCState.get());
MappingGen.emitCounterMapping(D, OS);
OS.flush();

Expand Down Expand Up @@ -1119,7 +1116,7 @@ bool CodeGenPGO::canEmitMCDCCoverage(const CGBuilderTy &Builder) {
}

void CodeGenPGO::emitMCDCParameters(CGBuilderTy &Builder) {
if (!canEmitMCDCCoverage(Builder) || !RegionMCDCBitmapMap)
if (!canEmitMCDCCoverage(Builder) || !RegionMCDCState)
return;

auto *I8PtrTy = llvm::PointerType::getUnqual(CGM.getLLVMContext());
Expand All @@ -1129,21 +1126,21 @@ void CodeGenPGO::emitMCDCParameters(CGBuilderTy &Builder) {
// anything.
llvm::Value *Args[3] = {llvm::ConstantExpr::getBitCast(FuncNameVar, I8PtrTy),
Builder.getInt64(FunctionHash),
Builder.getInt32(MCDCBitmapBytes)};
Builder.getInt32(RegionMCDCState->BitmapBytes)};
Builder.CreateCall(
CGM.getIntrinsic(llvm::Intrinsic::instrprof_mcdc_parameters), Args);
}

void CodeGenPGO::emitMCDCTestVectorBitmapUpdate(CGBuilderTy &Builder,
const Expr *S,
Address MCDCCondBitmapAddr) {
if (!canEmitMCDCCoverage(Builder) || !RegionMCDCBitmapMap)
if (!canEmitMCDCCoverage(Builder) || !RegionMCDCState)
return;

S = S->IgnoreParens();

auto ExprMCDCBitmapMapIterator = RegionMCDCBitmapMap->find(S);
if (ExprMCDCBitmapMapIterator == RegionMCDCBitmapMap->end())
auto ExprMCDCBitmapMapIterator = RegionMCDCState->BitmapMap.find(S);
if (ExprMCDCBitmapMapIterator == RegionMCDCState->BitmapMap.end())
return;

// Extract the ID of the global bitmap associated with this expression.
Expand All @@ -1157,7 +1154,7 @@ void CodeGenPGO::emitMCDCTestVectorBitmapUpdate(CGBuilderTy &Builder,
// index represents an executed test vector.
llvm::Value *Args[5] = {llvm::ConstantExpr::getBitCast(FuncNameVar, I8PtrTy),
Builder.getInt64(FunctionHash),
Builder.getInt32(MCDCBitmapBytes),
Builder.getInt32(RegionMCDCState->BitmapBytes),
Builder.getInt32(MCDCTestVectorBitmapID),
MCDCCondBitmapAddr.getPointer()};
Builder.CreateCall(
Expand All @@ -1166,12 +1163,12 @@ void CodeGenPGO::emitMCDCTestVectorBitmapUpdate(CGBuilderTy &Builder,

void CodeGenPGO::emitMCDCCondBitmapReset(CGBuilderTy &Builder, const Expr *S,
Address MCDCCondBitmapAddr) {
if (!canEmitMCDCCoverage(Builder) || !RegionMCDCBitmapMap)
if (!canEmitMCDCCoverage(Builder) || !RegionMCDCState)
return;

S = S->IgnoreParens();

if (RegionMCDCBitmapMap->find(S) == RegionMCDCBitmapMap->end())
if (!RegionMCDCState->BitmapMap.contains(S))
return;

// Emit intrinsic that resets a dedicated temporary value on the stack to 0.
Expand All @@ -1181,7 +1178,7 @@ void CodeGenPGO::emitMCDCCondBitmapReset(CGBuilderTy &Builder, const Expr *S,
void CodeGenPGO::emitMCDCCondBitmapUpdate(CGBuilderTy &Builder, const Expr *S,
Address MCDCCondBitmapAddr,
llvm::Value *Val) {
if (!canEmitMCDCCoverage(Builder) || !RegionCondIDMap)
if (!canEmitMCDCCoverage(Builder) || !RegionMCDCState)
return;

// Even though, for simplicity, parentheses and unary logical-NOT operators
Expand All @@ -1193,13 +1190,13 @@ void CodeGenPGO::emitMCDCCondBitmapUpdate(CGBuilderTy &Builder, const Expr *S,
// also make debugging a bit easier.
S = CodeGenFunction::stripCond(S);

auto ExprMCDCConditionIDMapIterator = RegionCondIDMap->find(S);
if (ExprMCDCConditionIDMapIterator == RegionCondIDMap->end())
auto ExprMCDCConditionIDMapIterator = RegionMCDCState->CondIDMap.find(S);
if (ExprMCDCConditionIDMapIterator == RegionMCDCState->CondIDMap.end())
return;

// Extract the ID of the condition we are setting in the bitmap.
unsigned CondID = ExprMCDCConditionIDMapIterator->second;
assert(CondID > 0 && "Condition has no ID!");
auto CondID = ExprMCDCConditionIDMapIterator->second;
assert(CondID >= 0 && "Condition has no ID!");

auto *I8PtrTy = llvm::PointerType::getUnqual(CGM.getLLVMContext());

Expand All @@ -1208,7 +1205,7 @@ void CodeGenPGO::emitMCDCCondBitmapUpdate(CGBuilderTy &Builder, const Expr *S,
// the resulting value is used to update the boolean expression's bitmap.
llvm::Value *Args[5] = {llvm::ConstantExpr::getBitCast(FuncNameVar, I8PtrTy),
Builder.getInt64(FunctionHash),
Builder.getInt32(CondID - 1),
Builder.getInt32(CondID),
MCDCCondBitmapAddr.getPointer(), Val};
Builder.CreateCall(
CGM.getIntrinsic(llvm::Intrinsic::instrprof_mcdc_condbitmap_update),
Expand Down
8 changes: 4 additions & 4 deletions clang/lib/CodeGen/CodeGenPGO.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "CGBuilder.h"
#include "CodeGenModule.h"
#include "CodeGenTypes.h"
#include "MCDCState.h"
#include "llvm/ProfileData/InstrProfReader.h"
#include <array>
#include <memory>
Expand All @@ -33,21 +34,20 @@ class CodeGenPGO {

std::array <unsigned, llvm::IPVK_Last + 1> NumValueSites;
unsigned NumRegionCounters;
unsigned MCDCBitmapBytes;
uint64_t FunctionHash;
std::unique_ptr<llvm::DenseMap<const Stmt *, unsigned>> RegionCounterMap;
std::unique_ptr<llvm::DenseMap<const Stmt *, unsigned>> RegionMCDCBitmapMap;
std::unique_ptr<llvm::DenseMap<const Stmt *, unsigned>> RegionCondIDMap;
std::unique_ptr<llvm::DenseMap<const Stmt *, int16_t>> RegionCondIDMap;
std::unique_ptr<llvm::DenseMap<const Stmt *, uint64_t>> StmtCountMap;
std::unique_ptr<llvm::InstrProfRecord> ProfRecord;
std::unique_ptr<MCDC::State> RegionMCDCState;
std::vector<uint64_t> RegionCounts;
uint64_t CurrentRegionCount;

public:
CodeGenPGO(CodeGenModule &CGModule)
: CGM(CGModule), FuncNameVar(nullptr), NumValueSites({{0}}),
NumRegionCounters(0), MCDCBitmapBytes(0), FunctionHash(0),
CurrentRegionCount(0) {}
NumRegionCounters(0), FunctionHash(0), CurrentRegionCount(0) {}

/// Whether or not we have PGO region data for the current function. This is
/// false both when we have no data at all and when our data has been
Expand Down
167 changes: 80 additions & 87 deletions clang/lib/CodeGen/CoverageMappingGen.cpp

Large diffs are not rendered by default.

14 changes: 8 additions & 6 deletions clang/lib/CodeGen/CoverageMappingGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ namespace CodeGen {

class CodeGenModule;

namespace MCDC {
struct State;
}

/// Organizes the cross-function state that is used while generating
/// code coverage mapping data.
class CoverageMappingModuleGen {
Expand Down Expand Up @@ -150,22 +154,20 @@ class CoverageMappingGen {
SourceManager &SM;
const LangOptions &LangOpts;
llvm::DenseMap<const Stmt *, unsigned> *CounterMap;
llvm::DenseMap<const Stmt *, unsigned> *MCDCBitmapMap;
llvm::DenseMap<const Stmt *, unsigned> *CondIDMap;
MCDC::State *MCDCState;

public:
CoverageMappingGen(CoverageMappingModuleGen &CVM, SourceManager &SM,
const LangOptions &LangOpts)
: CVM(CVM), SM(SM), LangOpts(LangOpts), CounterMap(nullptr),
MCDCBitmapMap(nullptr), CondIDMap(nullptr) {}
MCDCState(nullptr) {}

CoverageMappingGen(CoverageMappingModuleGen &CVM, SourceManager &SM,
const LangOptions &LangOpts,
llvm::DenseMap<const Stmt *, unsigned> *CounterMap,
llvm::DenseMap<const Stmt *, unsigned> *MCDCBitmapMap,
llvm::DenseMap<const Stmt *, unsigned> *CondIDMap)
MCDC::State *MCDCState)
: CVM(CVM), SM(SM), LangOpts(LangOpts), CounterMap(CounterMap),
MCDCBitmapMap(MCDCBitmapMap), CondIDMap(CondIDMap) {}
MCDCState(MCDCState) {}

/// Emit the coverage mapping data which maps the regions of
/// code to counters that will be used to find the execution
Expand Down
14 changes: 12 additions & 2 deletions clang/lib/CodeGen/LinkInModulesPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,26 @@
#include "LinkInModulesPass.h"
#include "BackendConsumer.h"

#include "clang/Basic/CodeGenOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"

using namespace llvm;

LinkInModulesPass::LinkInModulesPass(clang::BackendConsumer *BC,
bool ShouldLinkFiles)
: BC(BC), ShouldLinkFiles(ShouldLinkFiles) {}

PreservedAnalyses LinkInModulesPass::run(Module &M, ModuleAnalysisManager &AM) {
if (!BC)
return PreservedAnalyses::all();

// Re-load bitcode modules from files
if (BC->ReloadModules(&M))
report_fatal_error("Bitcode module re-loading failed, aborted!");

if (BC && BC->LinkInModules(&M, ShouldLinkFiles))
report_fatal_error("Bitcode module linking failed, compilation aborted!");
if (BC->LinkInModules(&M, ShouldLinkFiles))
report_fatal_error("Bitcode module re-linking failed, aborted!");

return PreservedAnalyses::all();
}
36 changes: 36 additions & 0 deletions clang/lib/CodeGen/MCDCState.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//===---- MCDCState.h - Per-Function MC/DC state ----------------*- 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
//
//===----------------------------------------------------------------------===//
//
// Per-Function MC/DC state for PGO
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_LIB_CODEGEN_MCDCSTATE_H
#define LLVM_CLANG_LIB_CODEGEN_MCDCSTATE_H

#include "llvm/ADT/DenseMap.h"
#include "llvm/ProfileData/Coverage/MCDCTypes.h"

namespace clang {
class Stmt;
} // namespace clang

namespace clang::CodeGen::MCDC {

using namespace llvm::coverage::mcdc;

/// Per-Function MC/DC state
struct State {
unsigned BitmapBytes = 0;
llvm::DenseMap<const Stmt *, unsigned> BitmapMap;
llvm::DenseMap<const Stmt *, ConditionID> CondIDMap;
};

} // namespace clang::CodeGen::MCDC

#endif // LLVM_CLANG_LIB_CODEGEN_MCDCSTATE_H
7 changes: 7 additions & 0 deletions clang/lib/Driver/Action.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ const char *Action::getClassName(ActionClass AC) {
case CompileJobClass: return "compiler";
case BackendJobClass: return "backend";
case AssembleJobClass: return "assembler";
case InstallAPIJobClass:
return "installapi";
case IfsMergeJobClass: return "interface-stub-merger";
case LinkJobClass: return "linker";
case LipoJobClass: return "lipo";
Expand Down Expand Up @@ -362,6 +364,11 @@ void ExtractAPIJobAction::anchor() {}
ExtractAPIJobAction::ExtractAPIJobAction(Action *Inputs, types::ID OutputType)
: JobAction(ExtractAPIJobClass, Inputs, OutputType) {}

void InstallAPIJobAction::anchor() {}

InstallAPIJobAction::InstallAPIJobAction(Action *Inputs, types::ID OutputType)
: JobAction(InstallAPIJobClass, Inputs, OutputType) {}

void AnalyzeJobAction::anchor() {}

AnalyzeJobAction::AnalyzeJobAction(Action *Input, types::ID OutputType)
Expand Down
16 changes: 15 additions & 1 deletion clang/lib/Driver/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4189,6 +4189,11 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
break;
}

if (auto *IAA = dyn_cast<InstallAPIJobAction>(Current)) {
Current = nullptr;
break;
}

// FIXME: Should we include any prior module file outputs as inputs of
// later actions in the same command line?

Expand Down Expand Up @@ -4319,6 +4324,13 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
if (!MergerInputs.empty())
Actions.push_back(
C.MakeAction<IfsMergeJobAction>(MergerInputs, types::TY_Image));
} else if (Args.hasArg(options::OPT_installapi)) {
// TODO: Lift restriction once operation can handle multiple inputs.
assert(Inputs.size() == 1 && "InstallAPI action can only handle 1 input");
const auto [InputType, InputArg] = Inputs.front();
Action *Current = C.MakeAction<InputAction>(*InputArg, InputType);
Actions.push_back(
C.MakeAction<InstallAPIJobAction>(Current, types::TY_TextAPI));
}

for (auto Opt : {options::OPT_print_supported_cpus,
Expand Down Expand Up @@ -4762,6 +4774,8 @@ Action *Driver::ConstructPhaseAction(
return C.MakeAction<VerifyPCHJobAction>(Input, types::TY_Nothing);
if (Args.hasArg(options::OPT_extract_api))
return C.MakeAction<ExtractAPIJobAction>(Input, types::TY_API_INFO);
if (Args.hasArg(options::OPT_installapi))
return C.MakeAction<InstallAPIJobAction>(Input, types::TY_TextAPI);
return C.MakeAction<CompileJobAction>(Input, types::TY_LLVM_BC);
}
case phases::Backend: {
Expand Down Expand Up @@ -6441,7 +6455,7 @@ bool Driver::ShouldUseClangCompiler(const JobAction &JA) const {
// And say "no" if this is not a kind of action clang understands.
if (!isa<PreprocessJobAction>(JA) && !isa<PrecompileJobAction>(JA) &&
!isa<CompileJobAction>(JA) && !isa<BackendJobAction>(JA) &&
!isa<ExtractAPIJobAction>(JA))
!isa<ExtractAPIJobAction>(JA) && !isa<InstallAPIJobAction>(JA))
return false;

return true;
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Driver/ToolChain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,7 @@ Tool *ToolChain::getTool(Action::ActionClass AC) const {
case Action::PrecompileJobClass:
case Action::PreprocessJobClass:
case Action::ExtractAPIJobClass:
case Action::InstallAPIJobClass:
case Action::AnalyzeJobClass:
case Action::MigrateJobClass:
case Action::VerifyPCHJobClass:
Expand Down
11 changes: 11 additions & 0 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4939,6 +4939,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Arg *ExtractAPIIgnoresFileArg =
Args.getLastArg(options::OPT_extract_api_ignores_EQ))
ExtractAPIIgnoresFileArg->render(Args, CmdArgs);
} else if (isa<InstallAPIJobAction>(JA)) {
if (!Triple.isOSDarwin())
D.Diag(diag::err_drv_installapi_unsupported) << Triple.str();

CmdArgs.push_back("-installapi");
// Add necessary library arguments for InstallAPI.
if (const Arg *A = Args.getLastArg(options::OPT_install__name))
A->render(Args, CmdArgs);
if (const Arg *A = Args.getLastArg(options::OPT_current__version))
A->render(Args, CmdArgs);

} else {
assert((isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) &&
"Invalid action for clang tool.");
Expand Down
15 changes: 15 additions & 0 deletions clang/lib/Driver/ToolChains/Flang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,20 @@ void Flang::AddRISCVTargetArgs(const ArgList &Args,
}
}

void Flang::AddX86_64TargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
if (Arg *A = Args.getLastArg(options::OPT_masm_EQ)) {
StringRef Value = A->getValue();
if (Value == "intel" || Value == "att") {
CmdArgs.push_back(Args.MakeArgString("-mllvm"));
CmdArgs.push_back(Args.MakeArgString("-x86-asm-syntax=" + Value));
} else {
getToolChain().getDriver().Diag(diag::err_drv_unsupported_option_argument)
<< A->getSpelling() << Value;
}
}
}

static void addVSDefines(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs) {

Expand Down Expand Up @@ -374,6 +388,7 @@ void Flang::addTargetOptions(const ArgList &Args,
break;
case llvm::Triple::x86_64:
getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false);
AddX86_64TargetArgs(Args, CmdArgs);
break;
}

Expand Down
7 changes: 7 additions & 0 deletions clang/lib/Driver/ToolChains/Flang.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,13 @@ class LLVM_LIBRARY_VISIBILITY Flang : public Tool {
void AddRISCVTargetArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const;

/// Add specific options for X86_64 target.
///
/// \param [in] Args The list of input driver arguments
/// \param [out] CmdArgs The list of output command arguments
void AddX86_64TargetArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const;

/// Extract offload options from the driver arguments and add them to
/// the command arguments.
/// \param [in] C The current compilation for the driver invocation
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/Format/ContinuationIndenter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,12 +329,12 @@ bool ContinuationIndenter::canBreak(const LineState &State) {
// Don't break after very short return types (e.g. "void") as that is often
// unexpected.
if (Current.is(TT_FunctionDeclarationName)) {
if (Style.AlwaysBreakAfterReturnType == FormatStyle::RTBS_None &&
if (Style.BreakAfterReturnType == FormatStyle::RTBS_None &&
State.Column < 6) {
return false;
}

if (Style.AlwaysBreakAfterReturnType == FormatStyle::RTBS_ExceptShortType) {
if (Style.BreakAfterReturnType == FormatStyle::RTBS_ExceptShortType) {
assert(State.Column >= State.FirstIndent);
if (State.Column - State.FirstIndent < 6)
return false;
Expand Down Expand Up @@ -597,7 +597,7 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
!State.Line->ReturnTypeWrapped &&
// Don't break before a C# function when no break after return type.
(!Style.isCSharp() ||
Style.AlwaysBreakAfterReturnType > FormatStyle::RTBS_ExceptShortType) &&
Style.BreakAfterReturnType > FormatStyle::RTBS_ExceptShortType) &&
// Don't always break between a JavaScript `function` and the function
// name.
!Style.isJavaScript() && Previous.isNot(tok::kw_template) &&
Expand Down
77 changes: 38 additions & 39 deletions clang/lib/Format/Format.cpp

Large diffs are not rendered by default.

12 changes: 8 additions & 4 deletions clang/lib/Format/FormatTokenLexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@
//===----------------------------------------------------------------------===//

#include "FormatTokenLexer.h"
#include "TokenAnalyzer.h"
#include "FormatToken.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Format/Format.h"
#include "llvm/Support/Regex.h"

namespace clang {
namespace format {
Expand All @@ -24,12 +28,12 @@ FormatTokenLexer::FormatTokenLexer(
llvm::SpecificBumpPtrAllocator<FormatToken> &Allocator,
IdentifierTable &IdentTable)
: FormatTok(nullptr), IsFirstToken(true), StateStack({LexerState::NORMAL}),
Column(Column), TrailingWhitespace(0), SourceMgr(SourceMgr), ID(ID),
Column(Column), TrailingWhitespace(0),
LangOpts(getFormattingLangOpts(Style)), SourceMgr(SourceMgr), ID(ID),
Style(Style), IdentTable(IdentTable), Keywords(IdentTable),
Encoding(Encoding), Allocator(Allocator), FirstInLineIndex(0),
FormattingDisabled(false), MacroBlockBeginRegex(Style.MacroBlockBegin),
MacroBlockEndRegex(Style.MacroBlockEnd) {
assert(LangOpts.CPlusPlus);
Lex.reset(new Lexer(ID, SourceMgr.getBufferOrFake(ID), SourceMgr, LangOpts));
Lex->SetKeepWhitespaceMode(true);

Expand Down Expand Up @@ -1438,7 +1442,7 @@ void FormatTokenLexer::readRawToken(FormatToken &Tok) {

void FormatTokenLexer::resetLexer(unsigned Offset) {
StringRef Buffer = SourceMgr.getBufferData(ID);
assert(LangOpts.CPlusPlus);
LangOpts = getFormattingLangOpts(Style);
Lex.reset(new Lexer(SourceMgr.getLocForStartOfFile(ID), LangOpts,
Buffer.begin(), Buffer.begin() + Offset, Buffer.end()));
Lex->SetKeepWhitespaceMode(true);
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Format/FormatTokenLexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,14 @@

#include "Encoding.h"
#include "FormatToken.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Format/Format.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Regex.h"

#include <stack>

Expand Down Expand Up @@ -115,6 +120,7 @@ class FormatTokenLexer {
unsigned Column;
unsigned TrailingWhitespace;
std::unique_ptr<Lexer> Lex;
LangOptions LangOpts;
const SourceManager &SourceMgr;
FileID ID;
const FormatStyle &Style;
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Format/IntegerLiteralSeparatorFixer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ IntegerLiteralSeparatorFixer::process(const Environment &Env,
AffectedRangeManager AffectedRangeMgr(SourceMgr, Env.getCharRanges());

const auto ID = Env.getFileID();
assert(LangOpts.CPlusPlus);
const auto LangOpts = getFormattingLangOpts(Style);
Lexer Lex(ID, SourceMgr.getBufferOrFake(ID), SourceMgr, LangOpts);
Lex.SetCommentRetentionState(true);

Expand Down
6 changes: 1 addition & 5 deletions clang/lib/Format/TokenAnalyzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@
namespace clang {
namespace format {

LangOptions LangOpts;

// FIXME: Instead of printing the diagnostic we should store it and have a
// better way to return errors through the format APIs.
class FatalDiagnosticConsumer : public DiagnosticConsumer {
Expand Down Expand Up @@ -101,11 +99,9 @@ TokenAnalyzer::TokenAnalyzer(const Environment &Env, const FormatStyle &Style)

std::pair<tooling::Replacements, unsigned>
TokenAnalyzer::process(bool SkipAnnotation) {
LangOpts = getFormattingLangOpts(Style);

tooling::Replacements Result;
llvm::SpecificBumpPtrAllocator<FormatToken> Allocator;
IdentifierTable IdentTable(LangOpts);
IdentifierTable IdentTable(getFormattingLangOpts(Style));
FormatTokenLexer Lex(Env.getSourceManager(), Env.getFileID(),
Env.getFirstStartColumn(), Style, Encoding, Allocator,
IdentTable);
Expand Down
2 changes: 0 additions & 2 deletions clang/lib/Format/TokenAnalyzer.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@
namespace clang {
namespace format {

extern LangOptions LangOpts;

class Environment {
public:
// This sets up an virtual file system with file \p FileName containing the
Expand Down
9 changes: 5 additions & 4 deletions clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1856,6 +1856,8 @@ class AnnotatingParser {
case tok::pp_elif:
Contexts.back().IsExpression = true;
next();
if (CurrentToken)
CurrentToken->SpacesRequiredBefore = true;
parseLine();
break;
default:
Expand Down Expand Up @@ -3726,14 +3728,13 @@ static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current,
bool TokenAnnotator::mustBreakForReturnType(const AnnotatedLine &Line) const {
assert(Line.MightBeFunctionDecl);

if ((Style.AlwaysBreakAfterReturnType == FormatStyle::RTBS_TopLevel ||
Style.AlwaysBreakAfterReturnType ==
FormatStyle::RTBS_TopLevelDefinitions) &&
if ((Style.BreakAfterReturnType == FormatStyle::RTBS_TopLevel ||
Style.BreakAfterReturnType == FormatStyle::RTBS_TopLevelDefinitions) &&
Line.Level > 0) {
return false;
}

switch (Style.AlwaysBreakAfterReturnType) {
switch (Style.BreakAfterReturnType) {
case FormatStyle::RTBS_None:
case FormatStyle::RTBS_Automatic:
case FormatStyle::RTBS_ExceptShortType:
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Format/UnwrappedLineParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2518,7 +2518,7 @@ bool UnwrappedLineParser::parseParens(TokenType AmpAmpTokenType) {
parseChildBlock();
break;
case tok::r_paren:
if (!MightBeStmtExpr &&
if (!MightBeStmtExpr && !Line->InMacroBody &&
Style.RemoveParentheses > FormatStyle::RPS_Leave) {
const auto *Prev = LeftParen->Previous;
const auto *Next = Tokens->peekNextToken();
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Frontend/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ set(LLVM_LINK_COMPONENTS
ProfileData
Support
TargetParser
TextAPI
)

add_clang_library(clangFrontend
Expand All @@ -27,6 +28,7 @@ add_clang_library(clangFrontend
HeaderIncludeGen.cpp
InitPreprocessor.cpp
LayoutOverrideSource.cpp
InstallAPIConsumer.cpp
LogDiagnosticPrinter.cpp
ModuleDependencyCollector.cpp
MultiplexConsumer.cpp
Expand All @@ -53,6 +55,7 @@ add_clang_library(clangFrontend
clangBasic
clangDriver
clangEdit
clangInstallAPI
clangLex
clangParse
clangSema
Expand Down
41 changes: 40 additions & 1 deletion clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,8 @@ CompilerInvocationBase::CompilerInvocationBase()
FSOpts(std::make_shared<FileSystemOptions>()),
FrontendOpts(std::make_shared<FrontendOptions>()),
DependencyOutputOpts(std::make_shared<DependencyOutputOptions>()),
PreprocessorOutputOpts(std::make_shared<PreprocessorOutputOptions>()) {}
PreprocessorOutputOpts(std::make_shared<PreprocessorOutputOptions>()),
InstallAPIOpts(std::make_shared<InstallAPIOptions>()) {}

CompilerInvocationBase &
CompilerInvocationBase::deep_copy_assign(const CompilerInvocationBase &X) {
Expand All @@ -167,6 +168,7 @@ CompilerInvocationBase::deep_copy_assign(const CompilerInvocationBase &X) {
FrontendOpts = make_shared_copy(X.getFrontendOpts());
DependencyOutputOpts = make_shared_copy(X.getDependencyOutputOpts());
PreprocessorOutputOpts = make_shared_copy(X.getPreprocessorOutputOpts());
InstallAPIOpts = make_shared_copy(X.getInstallAPIOpts());
}
return *this;
}
Expand All @@ -187,6 +189,7 @@ CompilerInvocationBase::shallow_copy_assign(const CompilerInvocationBase &X) {
FrontendOpts = X.FrontendOpts;
DependencyOutputOpts = X.DependencyOutputOpts;
PreprocessorOutputOpts = X.PreprocessorOutputOpts;
InstallAPIOpts = X.InstallAPIOpts;
}
return *this;
}
Expand Down Expand Up @@ -2158,6 +2161,34 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
return Diags.getNumErrors() == NumErrorsBefore;
}

static bool ParseInstallAPIArgs(InstallAPIOptions &Opts, ArgList &Args,
DiagnosticsEngine &Diags,
frontend::ActionKind Action) {
unsigned NumErrorsBefore = Diags.getNumErrors();

InstallAPIOptions &InstallAPIOpts = Opts;
#define INSTALLAPI_OPTION_WITH_MARSHALLING(...) \
PARSE_OPTION_WITH_MARSHALLING(Args, Diags, __VA_ARGS__)
#include "clang/Driver/Options.inc"
#undef INSTALLAPI_OPTION_WITH_MARSHALLING
if (Arg *A = Args.getLastArg(options::OPT_current__version))
Opts.CurrentVersion.parse64(A->getValue());

return Diags.getNumErrors() == NumErrorsBefore;
}

static void GenerateInstallAPIArgs(const InstallAPIOptions &Opts,
ArgumentConsumer Consumer) {
const InstallAPIOptions &InstallAPIOpts = Opts;
#define INSTALLAPI_OPTION_WITH_MARSHALLING(...) \
GENERATE_OPTION_WITH_MARSHALLING(Consumer, __VA_ARGS__)
#include "clang/Driver/Options.inc"
#undef INSTALLAPI_OPTION_WITH_MARSHALLING
if (!Opts.CurrentVersion.empty())
GenerateArg(Consumer, OPT_current__version,
std::string(Opts.CurrentVersion));
}

static void GenerateDependencyOutputArgs(const DependencyOutputOptions &Opts,
ArgumentConsumer Consumer) {
const DependencyOutputOptions &DependencyOutputOpts = Opts;
Expand Down Expand Up @@ -2557,6 +2588,7 @@ static const auto &getFrontendActionTable() {
{frontend::GeneratePCH, OPT_emit_pch},
{frontend::GenerateInterfaceStubs, OPT_emit_interface_stubs},
{frontend::InitOnly, OPT_init_only},
{frontend::InstallAPI, OPT_installapi},
{frontend::ParseSyntaxOnly, OPT_fsyntax_only},
{frontend::ModuleFileInfo, OPT_module_file_info},
{frontend::VerifyPCH, OPT_verify_pch},
Expand Down Expand Up @@ -4280,6 +4312,7 @@ static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) {
case frontend::GenerateHeaderUnit:
case frontend::GeneratePCH:
case frontend::GenerateInterfaceStubs:
case frontend::InstallAPI:
case frontend::ParseSyntaxOnly:
case frontend::ModuleFileInfo:
case frontend::VerifyPCH:
Expand Down Expand Up @@ -4654,6 +4687,11 @@ bool CompilerInvocation::CreateFromArgsImpl(
Res.getDependencyOutputOpts().Targets.empty())
Diags.Report(diag::err_fe_dependency_file_requires_MT);

if (Args.hasArg(OPT_installapi)) {
ParseInstallAPIArgs(Res.getInstallAPIOpts(), Args, Diags,
Res.getFrontendOpts().ProgramAction);
}

// If sanitizer is enabled, disable OPT_ffine_grained_bitfield_accesses.
if (Res.getCodeGenOpts().FineGrainedBitfieldAccesses &&
!Res.getLangOpts().Sanitize.empty()) {
Expand Down Expand Up @@ -4844,6 +4882,7 @@ void CompilerInvocationBase::generateCC1CommandLine(
GeneratePreprocessorOutputArgs(getPreprocessorOutputOpts(), Consumer,
getFrontendOpts().ProgramAction);
GenerateDependencyOutputArgs(getDependencyOutputOpts(), Consumer);
GenerateInstallAPIArgs(getInstallAPIOpts(), Consumer);
}

std::vector<std::string> CompilerInvocationBase::getCC1CommandLine() const {
Expand Down
95 changes: 95 additions & 0 deletions clang/lib/Frontend/InitPreprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,60 @@ void InitializeOpenCLFeatureTestMacros(const TargetInfo &TI,
Builder.defineMacro("__opencl_c_int64");
}

llvm::SmallString<32> ConstructFixedPointLiteral(llvm::APFixedPoint Val,
llvm::StringRef Suffix) {
if (Val.isSigned() && Val == llvm::APFixedPoint::getMin(Val.getSemantics())) {
// When representing the min value of a signed fixed point type in source
// code, we cannot simply write `-<lowest value>`. For example, the min
// value of a `short _Fract` cannot be written as `-1.0hr`. This is because
// the parser will read this (and really any negative numerical literal) as
// a UnaryOperator that owns a FixedPointLiteral with a positive value
// rather than just a FixedPointLiteral with a negative value. Compiling
// `-1.0hr` results in an overflow to the maximal value of that fixed point
// type. The correct way to represent a signed min value is to instead split
// it into two halves, like `(-0.5hr-0.5hr)` which is what the standard
// defines SFRACT_MIN as.
llvm::SmallString<32> Literal;
Literal.push_back('(');
llvm::SmallString<32> HalfStr =
ConstructFixedPointLiteral(Val.shr(1), Suffix);
Literal += HalfStr;
Literal += HalfStr;
Literal.push_back(')');
return Literal;
}

llvm::SmallString<32> Str(Val.toString());
Str += Suffix;
return Str;
}

void DefineFixedPointMacros(const TargetInfo &TI, MacroBuilder &Builder,
llvm::StringRef TypeName, llvm::StringRef Suffix,
unsigned Width, unsigned Scale, bool Signed) {
// Saturation doesn't affect the size or scale of a fixed point type, so we
// don't need it here.
llvm::FixedPointSemantics FXSema(
Width, Scale, Signed, /*IsSaturated=*/false,
!Signed && TI.doUnsignedFixedPointTypesHavePadding());
llvm::SmallString<32> MacroPrefix("__");
MacroPrefix += TypeName;
Builder.defineMacro(MacroPrefix + "_EPSILON__",
ConstructFixedPointLiteral(
llvm::APFixedPoint::getEpsilon(FXSema), Suffix));
Builder.defineMacro(MacroPrefix + "_FBIT__", Twine(Scale));
Builder.defineMacro(
MacroPrefix + "_MAX__",
ConstructFixedPointLiteral(llvm::APFixedPoint::getMax(FXSema), Suffix));

// ISO/IEC TR 18037:2008 doesn't specify MIN macros for unsigned types since
// they're all just zero.
if (Signed)
Builder.defineMacro(
MacroPrefix + "_MIN__",
ConstructFixedPointLiteral(llvm::APFixedPoint::getMin(FXSema), Suffix));
}

static void InitializePredefinedMacros(const TargetInfo &TI,
const LangOptions &LangOpts,
const FrontendOptions &FEOpts,
Expand Down Expand Up @@ -1097,6 +1151,47 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
TI.getTypeWidth(TI.getIntMaxType()) &&
"uintmax_t and intmax_t have different widths?");

if (LangOpts.FixedPoint) {
// Each unsigned type has the same width as their signed type.
DefineFixedPointMacros(TI, Builder, "SFRACT", "HR", TI.getShortFractWidth(),
TI.getShortFractScale(), /*Signed=*/true);
DefineFixedPointMacros(TI, Builder, "USFRACT", "UHR",
TI.getShortFractWidth(),
TI.getUnsignedShortFractScale(), /*Signed=*/false);
DefineFixedPointMacros(TI, Builder, "FRACT", "R", TI.getFractWidth(),
TI.getFractScale(), /*Signed=*/true);
DefineFixedPointMacros(TI, Builder, "UFRACT", "UR", TI.getFractWidth(),
TI.getUnsignedFractScale(), /*Signed=*/false);
DefineFixedPointMacros(TI, Builder, "LFRACT", "LR", TI.getLongFractWidth(),
TI.getLongFractScale(), /*Signed=*/true);
DefineFixedPointMacros(TI, Builder, "ULFRACT", "ULR",
TI.getLongFractWidth(),
TI.getUnsignedLongFractScale(), /*Signed=*/false);
DefineFixedPointMacros(TI, Builder, "SACCUM", "HK", TI.getShortAccumWidth(),
TI.getShortAccumScale(), /*Signed=*/true);
DefineFixedPointMacros(TI, Builder, "USACCUM", "UHK",
TI.getShortAccumWidth(),
TI.getUnsignedShortAccumScale(), /*Signed=*/false);
DefineFixedPointMacros(TI, Builder, "ACCUM", "K", TI.getAccumWidth(),
TI.getAccumScale(), /*Signed=*/true);
DefineFixedPointMacros(TI, Builder, "UACCUM", "UK", TI.getAccumWidth(),
TI.getUnsignedAccumScale(), /*Signed=*/false);
DefineFixedPointMacros(TI, Builder, "LACCUM", "LK", TI.getLongAccumWidth(),
TI.getLongAccumScale(), /*Signed=*/true);
DefineFixedPointMacros(TI, Builder, "ULACCUM", "ULK",
TI.getLongAccumWidth(),
TI.getUnsignedLongAccumScale(), /*Signed=*/false);

Builder.defineMacro("__SACCUM_IBIT__", Twine(TI.getShortAccumIBits()));
Builder.defineMacro("__USACCUM_IBIT__",
Twine(TI.getUnsignedShortAccumIBits()));
Builder.defineMacro("__ACCUM_IBIT__", Twine(TI.getAccumIBits()));
Builder.defineMacro("__UACCUM_IBIT__", Twine(TI.getUnsignedAccumIBits()));
Builder.defineMacro("__LACCUM_IBIT__", Twine(TI.getLongAccumIBits()));
Builder.defineMacro("__ULACCUM_IBIT__",
Twine(TI.getUnsignedLongAccumIBits()));
}

if (TI.hasFloat16Type())
DefineFloatMacros(Builder, "FLT16", &TI.getHalfFormat(), "F16");
DefineFloatMacros(Builder, "FLT", &TI.getFloatFormat(), "F");
Expand Down
43 changes: 43 additions & 0 deletions clang/lib/Frontend/InstallAPIConsumer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//===--- InstallAPIConsumer.cpp -------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/InstallAPI/Context.h"

using namespace clang;
using namespace clang::installapi;

std::unique_ptr<ASTConsumer>
InstallAPIAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
const InstallAPIOptions &Opts = CI.getInstallAPIOpts();
InstallAPIContext Ctx;
Ctx.BA.InstallName = Opts.InstallName;
Ctx.BA.AppExtensionSafe = CI.getLangOpts().AppExt;
Ctx.BA.CurrentVersion = Opts.CurrentVersion;
// InstallAPI requires two level namespacing.
Ctx.BA.TwoLevelNamespace = true;
Ctx.TargetTriple = CI.getTarget().getTriple();

Ctx.Diags = &CI.getDiagnostics();
Ctx.OutputLoc = CI.getFrontendOpts().OutputFile;
Ctx.OS = CreateOutputFile(CI, InFile);
if (!Ctx.OS)
return nullptr;
return std::make_unique<InstallAPIConsumer>(std::move(Ctx));
}

std::unique_ptr<llvm::raw_pwrite_stream>
InstallAPIAction::CreateOutputFile(CompilerInstance &CI, StringRef InFile) {
std::unique_ptr<raw_pwrite_stream> OS =
CI.createDefaultOutputFile(/*Binary=*/false, InFile, /*Extension=*/"tbd",
/*RemoveFileOnSignal=*/false);
if (!OS)
return nullptr;
return OS;
}
2 changes: 2 additions & 0 deletions clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ CreateFrontendBaseAction(CompilerInstance &CI) {
case GenerateInterfaceStubs:
return std::make_unique<GenerateInterfaceStubsAction>();
case InitOnly: return std::make_unique<InitOnlyAction>();
case InstallAPI:
return std::make_unique<InstallAPIAction>();
case ParseSyntaxOnly: return std::make_unique<SyntaxOnlyAction>();
case ModuleFileInfo: return std::make_unique<DumpModuleInfoAction>();
case VerifyPCH: return std::make_unique<VerifyPCHAction>();
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/Headers/hlsl/hlsl_basic_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@
namespace hlsl {
// built-in scalar data types:

/// \typedef template<typename Ty, int Size> using vector = Ty
/// __attribute__((ext_vector_type(Size)))
///
/// \tparam Ty The base type of the vector may be any builtin integral or
/// floating point type.
/// \tparam Size The size of the vector may be any value between 1 and 4.

#ifdef __HLSL_ENABLE_16_BIT
// 16-bit integer.
typedef unsigned short uint16_t;
Expand Down
172 changes: 170 additions & 2 deletions clang/lib/Headers/hlsl/hlsl_intrinsics.h

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions clang/lib/InstallAPI/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
set(LLVM_LINK_COMPONENTS
Support
TextAPI
)

add_clang_library(clangInstallAPI
Context.cpp

LINK_LIBS
clangAST
clangBasic
)
27 changes: 27 additions & 0 deletions clang/lib/InstallAPI/Context.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//===--- InstallAPI/Context.cpp -------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

#include "clang/InstallAPI/Context.h"
#include "clang/AST/ASTContext.h"
#include "llvm/TextAPI/TextAPIWriter.h"

using namespace clang;
using namespace clang::installapi;
using namespace llvm::MachO;

void InstallAPIConsumer::HandleTranslationUnit(ASTContext &Context) {
if (Context.getDiagnostics().hasErrorOccurred())
return;
InterfaceFile IF;
// Set library attributes captured through cc1 args.
Target T(Ctx.TargetTriple);
IF.addTarget(T);
IF.setFromBinaryAttrs(Ctx.BA, T);
if (auto Err = TextAPIWriter::writeToStream(*Ctx.OS, IF, Ctx.FT))
Ctx.Diags->Report(diag::err_cannot_open_file) << Ctx.OutputLoc;
}
16 changes: 11 additions & 5 deletions clang/lib/Lex/LiteralSupport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1358,11 +1358,17 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {

// Handle simple binary numbers 0b01010
if ((c1 == 'b' || c1 == 'B') && (s[1] == '0' || s[1] == '1')) {
// 0b101010 is a C++1y / GCC extension.
Diags.Report(TokLoc, LangOpts.CPlusPlus14
? diag::warn_cxx11_compat_binary_literal
: LangOpts.CPlusPlus ? diag::ext_binary_literal_cxx14
: diag::ext_binary_literal);
// 0b101010 is a C++14 and C23 extension.
unsigned DiagId;
if (LangOpts.CPlusPlus14)
DiagId = diag::warn_cxx11_compat_binary_literal;
else if (LangOpts.C23)
DiagId = diag::warn_c23_compat_binary_literal;
else if (LangOpts.CPlusPlus)
DiagId = diag::ext_binary_literal_cxx14;
else
DiagId = diag::ext_binary_literal;
Diags.Report(TokLoc, DiagId);
++s;
assert(s < ThisTokEnd && "didn't maximally munch?");
radix = 2;
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/Parse/ParseTentative.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,9 @@ bool Parser::isCXXDeclarationStatement(
getCurScope(), *II, Tok.getLocation(), SS, /*Template=*/nullptr);
if (Actions.isCurrentClassName(*II, getCurScope(), &SS) ||
isDeductionGuide) {
if (isConstructorDeclarator(/*Unqualified=*/SS.isEmpty(),
isDeductionGuide,
DeclSpec::FriendSpecified::No))
if (isConstructorDeclarator(
/*Unqualified=*/SS.isEmpty(), isDeductionGuide,
/*IsFriend=*/DeclSpec::FriendSpecified::No))
return true;
} else if (SS.isNotEmpty()) {
// If the scope is not empty, it could alternatively be something like
Expand Down
9 changes: 2 additions & 7 deletions clang/lib/Sema/DeclSpec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1102,18 +1102,13 @@ bool DeclSpec::setFunctionSpecNoreturn(SourceLocation Loc,

bool DeclSpec::SetFriendSpec(SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID) {
if (Friend_specified) {
if (isFriendSpecified()) {
PrevSpec = "friend";
// Keep the later location, so that we can later diagnose ill-formed
// declarations like 'friend class X friend;'. Per [class.friend]p3,
// 'friend' must be the first token in a friend declaration that is
// not a function declaration.
FriendLoc = Loc;
DiagID = diag::warn_duplicate_declspec;
return true;
}

Friend_specified = true;
FriendSpecifiedFirst = isEmpty();
FriendLoc = Loc;
return false;
}
Expand Down
37 changes: 30 additions & 7 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2960,6 +2960,9 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
S.mergeHLSLNumThreadsAttr(D, *NT, NT->getX(), NT->getY(), NT->getZ());
else if (const auto *SA = dyn_cast<HLSLShaderAttr>(Attr))
NewAttr = S.mergeHLSLShaderAttr(D, *SA, SA->getType());
else if (const auto *SupA = dyn_cast<SuppressAttr>(Attr))
// Do nothing. Each redeclaration should be suppressed separately.
NewAttr = nullptr;
else if (Attr->shouldInheritEvenIfAlreadyPresent() || !DeclHasAttr(D, Attr))
NewAttr = cast<InheritableAttr>(Attr->clone(S.Context));

Expand Down Expand Up @@ -6839,21 +6842,21 @@ Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD,
if (IdentifierInfo *II = NewTD->getIdentifier())
if (!NewTD->isInvalidDecl() &&
NewTD->getDeclContext()->getRedeclContext()->isTranslationUnit()) {
switch (II->getInterestingIdentifierID()) {
case tok::InterestingIdentifierKind::FILE:
switch (II->getNotableIdentifierID()) {
case tok::NotableIdentifierKind::FILE:
Context.setFILEDecl(NewTD);
break;
case tok::InterestingIdentifierKind::jmp_buf:
case tok::NotableIdentifierKind::jmp_buf:
Context.setjmp_bufDecl(NewTD);
break;
case tok::InterestingIdentifierKind::sigjmp_buf:
case tok::NotableIdentifierKind::sigjmp_buf:
Context.setsigjmp_bufDecl(NewTD);
break;
case tok::InterestingIdentifierKind::ucontext_t:
case tok::NotableIdentifierKind::ucontext_t:
Context.setucontext_tDecl(NewTD);
break;
case tok::InterestingIdentifierKind::float_t:
case tok::InterestingIdentifierKind::double_t:
case tok::NotableIdentifierKind::float_t:
case tok::NotableIdentifierKind::double_t:
NewTD->addAttr(AvailableOnlyInDefaultEvalMethodAttr::Create(Context));
break;
default:
Expand Down Expand Up @@ -17264,6 +17267,26 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
return true;
}

if (TUK == TUK_Friend && Kind == TagTypeKind::Enum) {
// C++23 [dcl.type.elab]p4:
// If an elaborated-type-specifier appears with the friend specifier as
// an entire member-declaration, the member-declaration shall have one
// of the following forms:
// friend class-key nested-name-specifier(opt) identifier ;
// friend class-key simple-template-id ;
// friend class-key nested-name-specifier template(opt)
// simple-template-id ;
//
// Since enum is not a class-key, so declarations like "friend enum E;"
// are ill-formed. Although CWG2363 reaffirms that such declarations are
// invalid, most implementations accept so we issue a pedantic warning.
Diag(KWLoc, diag::ext_enum_friend) << FixItHint::CreateRemoval(
ScopedEnum ? SourceRange(KWLoc, ScopedEnumKWLoc) : KWLoc);
assert(ScopedEnum || !ScopedEnumUsesClassTag);
Diag(KWLoc, diag::note_enum_friend)
<< (ScopedEnum + ScopedEnumUsesClassTag);
}

// Figure out the underlying type if this a enum declaration. We need to do
// this early, because it's needed to detect if this is an incompatible
// redeclaration.
Expand Down
5 changes: 0 additions & 5 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5260,11 +5260,6 @@ static void handleSuppressAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// Suppression attribute with GSL spelling requires at least 1 argument.
if (!AL.checkAtLeastNumArgs(S, 1))
return;
} else if (!isa<VarDecl>(D)) {
// Analyzer suppression applies only to variables and statements.
S.Diag(AL.getLoc(), diag::err_attribute_wrong_decl_type_str)
<< AL << 0 << "variables and statements";
return;
}

std::vector<StringRef> DiagnosticIdentifiers;
Expand Down
137 changes: 38 additions & 99 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17545,79 +17545,6 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
return Decl;
}

/// Perform semantic analysis of the given friend type declaration.
///
/// \returns A friend declaration that.
FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation LocStart,
SourceLocation FriendLoc,
TypeSourceInfo *TSInfo) {
assert(TSInfo && "NULL TypeSourceInfo for friend type declaration");

QualType T = TSInfo->getType();
SourceRange TypeRange = TSInfo->getTypeLoc().getSourceRange();

// C++03 [class.friend]p2:
// An elaborated-type-specifier shall be used in a friend declaration
// for a class.*
//
// * The class-key of the elaborated-type-specifier is required.
if (!CodeSynthesisContexts.empty()) {
// Do not complain about the form of friend template types during any kind
// of code synthesis. For template instantiation, we will have complained
// when the template was defined.
} else {
if (!T->isElaboratedTypeSpecifier()) {
// If we evaluated the type to a record type, suggest putting
// a tag in front.
if (const RecordType *RT = T->getAs<RecordType>()) {
RecordDecl *RD = RT->getDecl();

SmallString<16> InsertionText(" ");
InsertionText += RD->getKindName();

Diag(TypeRange.getBegin(),
getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_unelaborated_friend_type :
diag::ext_unelaborated_friend_type)
<< (unsigned) RD->getTagKind()
<< T
<< FixItHint::CreateInsertion(getLocForEndOfToken(FriendLoc),
InsertionText);
} else {
Diag(FriendLoc,
getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_nonclass_type_friend :
diag::ext_nonclass_type_friend)
<< T
<< TypeRange;
}
} else if (T->getAs<EnumType>()) {
Diag(FriendLoc,
getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_enum_friend :
diag::ext_enum_friend)
<< T
<< TypeRange;
}

// C++11 [class.friend]p3:
// A friend declaration that does not declare a function shall have one
// of the following forms:
// friend elaborated-type-specifier ;
// friend simple-type-specifier ;
// friend typename-specifier ;
if (getLangOpts().CPlusPlus11 && LocStart != FriendLoc)
Diag(FriendLoc, diag::err_friend_not_first_in_declaration) << T;
}

// If the type specifier in a friend declaration designates a (possibly
// cv-qualified) class type, that class is declared as a friend; otherwise,
// the friend declaration is ignored.
return FriendDecl::Create(Context, CurContext,
TSInfo->getTypeLoc().getBeginLoc(), TSInfo,
FriendLoc);
}

/// Handle a friend tag declaration where the scope specifier was
/// templated.
DeclResult Sema::ActOnTemplatedFriendTag(
Expand Down Expand Up @@ -17755,6 +17682,7 @@ DeclResult Sema::ActOnTemplatedFriendTag(
Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
MultiTemplateParamsArg TempParams) {
SourceLocation Loc = DS.getBeginLoc();
SourceLocation FriendLoc = DS.getFriendSpecLoc();

assert(DS.isFriendSpecified());
assert(DS.getStorageClassSpec() == DeclSpec::SCS_unspecified);
Expand All @@ -17766,9 +17694,10 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
// friend simple-type-specifier ;
// friend typename-specifier ;
//
// Any declaration with a type qualifier does not have that form. (It's
// legal to specify a qualified type as a friend, you just can't write the
// keywords.)
// If the friend keyword isn't first, or if the declarations has any type
// qualifiers, then the declaration doesn't have that form.
if (getLangOpts().CPlusPlus11 && !DS.isFriendSpecifiedFirst())
Diag(FriendLoc, diag::err_friend_not_first_in_declaration);
if (DS.getTypeQualifiers()) {
if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
Diag(DS.getConstSpecLoc(), diag::err_friend_decl_spec) << "const";
Expand All @@ -17795,24 +17724,35 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
if (DiagnoseUnexpandedParameterPack(Loc, TSI, UPPC_FriendDeclaration))
return nullptr;

// This is definitely an error in C++98. It's probably meant to
// be forbidden in C++0x, too, but the specification is just
// poorly written.
//
// The problem is with declarations like the following:
// template <T> friend A<T>::foo;
// where deciding whether a class C is a friend or not now hinges
// on whether there exists an instantiation of A that causes
// 'foo' to equal C. There are restrictions on class-heads
// (which we declare (by fiat) elaborated friend declarations to
// be) that makes this tractable.
//
// FIXME: handle "template <> friend class A<T>;", which
// is possibly well-formed? Who even knows?
if (TempParams.size() && !T->isElaboratedTypeSpecifier()) {
Diag(Loc, diag::err_tagless_friend_type_template)
<< DS.getSourceRange();
return nullptr;
if (!T->isElaboratedTypeSpecifier()) {
if (TempParams.size()) {
// C++23 [dcl.pre]p5:
// In a simple-declaration, the optional init-declarator-list can be
// omitted only when declaring a class or enumeration, that is, when
// the decl-specifier-seq contains either a class-specifier, an
// elaborated-type-specifier with a class-key, or an enum-specifier.
//
// The declaration of a template-declaration or explicit-specialization
// is never a member-declaration, so this must be a simple-declaration
// with no init-declarator-list. Therefore, this is ill-formed.
Diag(Loc, diag::err_tagless_friend_type_template) << DS.getSourceRange();
return nullptr;
} else if (const RecordDecl *RD = T->getAsRecordDecl()) {
SmallString<16> InsertionText(" ");
InsertionText += RD->getKindName();

Diag(Loc, getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_unelaborated_friend_type
: diag::ext_unelaborated_friend_type)
<< (unsigned)RD->getTagKind() << T
<< FixItHint::CreateInsertion(getLocForEndOfToken(FriendLoc),
InsertionText);
} else {
Diag(FriendLoc, getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_nonclass_type_friend
: diag::ext_nonclass_type_friend)
<< T << DS.getSourceRange();
}
}

// C++98 [class.friend]p1: A friend of a class is a function
Expand All @@ -17828,12 +17768,11 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,

Decl *D;
if (!TempParams.empty())
D = FriendTemplateDecl::Create(Context, CurContext, Loc,
TempParams,
TSI,
DS.getFriendSpecLoc());
D = FriendTemplateDecl::Create(Context, CurContext, Loc, TempParams, TSI,
FriendLoc);
else
D = CheckFriendTypeDecl(Loc, DS.getFriendSpecLoc(), TSI);
D = FriendDecl::Create(Context, CurContext, TSI->getTypeLoc().getBeginLoc(),
TSI, FriendLoc);

if (!D)
return nullptr;
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Sema/SemaExceptionSpec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1423,6 +1423,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
llvm_unreachable("Invalid class for expression");

// Most statements can throw if any substatement can throw.
case Stmt::OpenACCComputeConstructClass:
case Stmt::AttributedStmtClass:
case Stmt::BreakStmtClass:
case Stmt::CapturedStmtClass:
Expand Down
7 changes: 5 additions & 2 deletions clang/lib/Sema/SemaTemplateDeduction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5642,9 +5642,12 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate(
Sema::TPL_TemplateParamsEquivalent))
return nullptr;

// [dcl.fct]p5:
// Any top-level cv-qualifiers modifying a parameter type are deleted when
// forming the function type.
for (unsigned i = 0; i < NumParams1; ++i)
if (!Context.hasSameType(FD1->getParamDecl(i)->getType(),
FD2->getParamDecl(i)->getType()))
if (!Context.hasSameUnqualifiedType(FD1->getParamDecl(i)->getType(),
FD2->getParamDecl(i)->getType()))
return nullptr;

// C++20 [temp.func.order]p6.3:
Expand Down
7 changes: 2 additions & 5 deletions clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1407,11 +1407,8 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
if (!InstTy)
return nullptr;

FriendDecl *FD = SemaRef.CheckFriendTypeDecl(D->getBeginLoc(),
D->getFriendLoc(), InstTy);
if (!FD)
return nullptr;

FriendDecl *FD = FriendDecl::Create(
SemaRef.Context, Owner, D->getLocation(), InstTy, D->getFriendLoc());
FD->setAccess(AS_public);
FD->setUnsupportedFriend(D->isUnsupportedFriend());
Owner->addDecl(FD);
Expand Down
23 changes: 23 additions & 0 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtOpenACC.h"
#include "clang/AST/StmtOpenMP.h"
#include "clang/Basic/DiagnosticParse.h"
#include "clang/Basic/OpenMPKinds.h"
Expand Down Expand Up @@ -3995,6 +3996,13 @@ class TreeTransform {
return getSema().CreateRecoveryExpr(BeginLoc, EndLoc, SubExprs, Type);
}

StmtResult RebuildOpenACCComputeConstruct(OpenACCDirectiveKind K,
SourceLocation BeginLoc,
SourceLocation EndLoc,
StmtResult StrBlock) {
llvm_unreachable("Not yet implemented!");
}

private:
TypeLoc TransformTypeInObjectScope(TypeLoc TL,
QualType ObjectType,
Expand Down Expand Up @@ -10993,6 +11001,21 @@ OMPClause *TreeTransform<Derived>::TransformOMPXBareClause(OMPXBareClause *C) {
return getDerived().RebuildOMPXBareClause(C->getBeginLoc(), C->getEndLoc());
}

//===----------------------------------------------------------------------===//
// OpenACC transformation
//===----------------------------------------------------------------------===//
template <typename Derived>
StmtResult TreeTransform<Derived>::TransformOpenACCComputeConstruct(
OpenACCComputeConstruct *C) {
// TODO OpenACC: Transform clauses.

// Transform Structured Block.
StmtResult StrBlock = getDerived().TransformStmt(C->getStructuredBlock());

return getDerived().RebuildOpenACCComputeConstruct(
C->getDirectiveKind(), C->getBeginLoc(), C->getEndLoc(), StrBlock);
}

//===----------------------------------------------------------------------===//
// Expression transformation
//===----------------------------------------------------------------------===//
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/Serialization/ASTReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -988,8 +988,7 @@ ASTIdentifierLookupTraitBase::ReadKey(const unsigned char* d, unsigned n) {
static bool isInterestingIdentifier(ASTReader &Reader, IdentifierInfo &II,
bool IsModule) {
bool IsInteresting =
II.getInterestingIdentifierID() !=
tok::InterestingIdentifierKind::not_interesting ||
II.getNotableIdentifierID() != tok::NotableIdentifierKind::not_notable ||
II.getBuiltinID() != Builtin::ID::NotBuiltin ||
II.getObjCKeywordID() != tok::ObjCKeywordKind::objc_not_keyword;
return II.hadMacroDefinition() || II.isPoisoned() ||
Expand Down
Loading