16 changes: 12 additions & 4 deletions clang/lib/CodeGen/CGExprScalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -723,7 +723,9 @@ class ScalarExprEmitter
if (Ops.Ty->isSignedIntegerOrEnumerationType()) {
switch (CGF.getLangOpts().getSignedOverflowBehavior()) {
case LangOptions::SOB_Defined:
return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul");
if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul");
[[fallthrough]];
case LangOptions::SOB_Undefined:
if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
return Builder.CreateNSWMul(Ops.LHS, Ops.RHS, "mul");
Expand Down Expand Up @@ -2568,7 +2570,9 @@ llvm::Value *ScalarExprEmitter::EmitIncDecConsiderOverflowBehavior(
StringRef Name = IsInc ? "inc" : "dec";
switch (CGF.getLangOpts().getSignedOverflowBehavior()) {
case LangOptions::SOB_Defined:
return Builder.CreateAdd(InVal, Amount, Name);
if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
return Builder.CreateAdd(InVal, Amount, Name);
[[fallthrough]];
case LangOptions::SOB_Undefined:
if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
return Builder.CreateNSWAdd(InVal, Amount, Name);
Expand Down Expand Up @@ -3913,7 +3917,9 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &op) {
if (op.Ty->isSignedIntegerOrEnumerationType()) {
switch (CGF.getLangOpts().getSignedOverflowBehavior()) {
case LangOptions::SOB_Defined:
return Builder.CreateAdd(op.LHS, op.RHS, "add");
if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
return Builder.CreateAdd(op.LHS, op.RHS, "add");
[[fallthrough]];
case LangOptions::SOB_Undefined:
if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
return Builder.CreateNSWAdd(op.LHS, op.RHS, "add");
Expand Down Expand Up @@ -4067,7 +4073,9 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
if (op.Ty->isSignedIntegerOrEnumerationType()) {
switch (CGF.getLangOpts().getSignedOverflowBehavior()) {
case LangOptions::SOB_Defined:
return Builder.CreateSub(op.LHS, op.RHS, "sub");
if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
return Builder.CreateSub(op.LHS, op.RHS, "sub");
[[fallthrough]];
case LangOptions::SOB_Undefined:
if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
return Builder.CreateNSWSub(op.LHS, op.RHS, "sub");
Expand Down
28 changes: 14 additions & 14 deletions clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ struct CGRecordLowering {
CGRecordLowering(CodeGenTypes &Types, const RecordDecl *D, bool Packed);
// Short helper routines.
/// Constructs a MemberInfo instance from an offset and llvm::Type *.
MemberInfo StorageInfo(CharUnits Offset, llvm::Type *Data) {
static MemberInfo StorageInfo(CharUnits Offset, llvm::Type *Data) {
return MemberInfo(Offset, MemberInfo::Field, Data);
}

Expand All @@ -104,7 +104,7 @@ struct CGRecordLowering {
/// fields of the same formal type. We want to emit a layout with
/// these discrete storage units instead of combining them into a
/// continuous run.
bool isDiscreteBitFieldABI() {
bool isDiscreteBitFieldABI() const {
return Context.getTargetInfo().getCXXABI().isMicrosoft() ||
D->isMsStruct(Context);
}
Expand All @@ -121,60 +121,60 @@ struct CGRecordLowering {
/// other bases, which complicates layout in specific ways.
///
/// Note specifically that the ms_struct attribute doesn't change this.
bool isOverlappingVBaseABI() {
bool isOverlappingVBaseABI() const {
return !Context.getTargetInfo().getCXXABI().isMicrosoft();
}

/// Wraps llvm::Type::getIntNTy with some implicit arguments.
llvm::Type *getIntNType(uint64_t NumBits) {
llvm::Type *getIntNType(uint64_t NumBits) const {
unsigned AlignedBits = llvm::alignTo(NumBits, Context.getCharWidth());
return llvm::Type::getIntNTy(Types.getLLVMContext(), AlignedBits);
}
/// Get the LLVM type sized as one character unit.
llvm::Type *getCharType() {
llvm::Type *getCharType() const {
return llvm::Type::getIntNTy(Types.getLLVMContext(),
Context.getCharWidth());
}
/// Gets an llvm type of size NumChars and alignment 1.
llvm::Type *getByteArrayType(CharUnits NumChars) {
llvm::Type *getByteArrayType(CharUnits NumChars) const {
assert(!NumChars.isZero() && "Empty byte arrays aren't allowed.");
llvm::Type *Type = getCharType();
return NumChars == CharUnits::One() ? Type :
(llvm::Type *)llvm::ArrayType::get(Type, NumChars.getQuantity());
}
/// Gets the storage type for a field decl and handles storage
/// for itanium bitfields that are smaller than their declared type.
llvm::Type *getStorageType(const FieldDecl *FD) {
llvm::Type *getStorageType(const FieldDecl *FD) const {
llvm::Type *Type = Types.ConvertTypeForMem(FD->getType());
if (!FD->isBitField()) return Type;
if (isDiscreteBitFieldABI()) return Type;
return getIntNType(std::min(FD->getBitWidthValue(Context),
(unsigned)Context.toBits(getSize(Type))));
}
/// Gets the llvm Basesubobject type from a CXXRecordDecl.
llvm::Type *getStorageType(const CXXRecordDecl *RD) {
llvm::Type *getStorageType(const CXXRecordDecl *RD) const {
return Types.getCGRecordLayout(RD).getBaseSubobjectLLVMType();
}
CharUnits bitsToCharUnits(uint64_t BitOffset) {
CharUnits bitsToCharUnits(uint64_t BitOffset) const {
return Context.toCharUnitsFromBits(BitOffset);
}
CharUnits getSize(llvm::Type *Type) {
CharUnits getSize(llvm::Type *Type) const {
return CharUnits::fromQuantity(DataLayout.getTypeAllocSize(Type));
}
CharUnits getAlignment(llvm::Type *Type) {
CharUnits getAlignment(llvm::Type *Type) const {
return CharUnits::fromQuantity(DataLayout.getABITypeAlign(Type));
}
bool isZeroInitializable(const FieldDecl *FD) {
bool isZeroInitializable(const FieldDecl *FD) const {
return Types.isZeroInitializable(FD->getType());
}
bool isZeroInitializable(const RecordDecl *RD) {
bool isZeroInitializable(const RecordDecl *RD) const {
return Types.isZeroInitializable(RD);
}
void appendPaddingBytes(CharUnits Size) {
if (!Size.isZero())
FieldTypes.push_back(getByteArrayType(Size));
}
uint64_t getFieldBitOffset(const FieldDecl *FD) {
uint64_t getFieldBitOffset(const FieldDecl *FD) const {
return Layout.getFieldOffset(FD->getFieldIndex());
}
// Layout routines.
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/CodeGen/CodeGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -4405,6 +4405,7 @@ class CodeGenFunction : public CodeGenTypeCache {
llvm::Value *EmitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E);
llvm::Value *EmitPPCBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
llvm::Value *EmitAMDGPUBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
llvm::Value *EmitHLSLBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
llvm::Value *EmitScalarOrConstFoldImmArg(unsigned ICEArguments, unsigned Idx,
const CallExpr *E);
llvm::Value *EmitSystemZBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
Expand Down Expand Up @@ -5013,10 +5014,10 @@ class CodeGenFunction : public CodeGenTypeCache {
llvm::Value *EmitAArch64CpuInit();
llvm::Value *
FormAArch64ResolverCondition(const MultiVersionResolverOption &RO);
llvm::Value *EmitAArch64CpuSupports(const CallExpr *E);
llvm::Value *EmitAArch64CpuSupports(ArrayRef<StringRef> FeatureStrs);
};


inline DominatingLLVMValue::saved_type
DominatingLLVMValue::save(CodeGenFunction &CGF, llvm::Value *value) {
if (!needsSaving(value)) return saved_type(value, false);
Expand Down
10 changes: 9 additions & 1 deletion clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -915,7 +915,15 @@ void CodeGenModule::Release() {
llvm::ConstantArray::get(ATy, UsedArray), "__clang_gpu_used_external");
addCompilerUsedGlobal(GV);
}

if (LangOpts.HIP) {
// Emit a unique ID so that host and device binaries from the same
// compilation unit can be associated.
auto *GV = new llvm::GlobalVariable(
getModule(), Int8Ty, false, llvm::GlobalValue::ExternalLinkage,
llvm::Constant::getNullValue(Int8Ty),
"__hip_cuid_" + getContext().getCUIDHash());
addCompilerUsedGlobal(GV);
}
emitLLVMUsed();
if (SanStats)
SanStats->finish();
Expand Down
38 changes: 21 additions & 17 deletions clang/lib/CodeGen/CodeGenPGO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> {
llvm::DenseMap<const Stmt *, unsigned> &CounterMap;
/// The next bitmap byte index to assign.
unsigned NextMCDCBitmapIdx;
/// The state of MC/DC Coverage in this function.
MCDC::State &MCDCState;
/// Maximum number of supported MC/DC conditions in a boolean expression.
unsigned MCDCMaxCond;
Expand Down Expand Up @@ -239,9 +240,12 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> {
if (MCDCMaxCond == 0)
return true;

/// At the top of the logical operator nest, reset the number of conditions.
if (LogOpStack.empty())
/// At the top of the logical operator nest, reset the number of conditions,
/// also forget previously seen split nesting cases.
if (LogOpStack.empty()) {
NumCond = 0;
SplitNestedLogicalOp = false;
}

if (const Expr *E = dyn_cast<Expr>(S)) {
const BinaryOperator *BinOp = dyn_cast<BinaryOperator>(E->IgnoreParens());
Expand Down Expand Up @@ -292,7 +296,7 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> {
"contains an operation with a nested boolean expression. "
"Expression will not be covered");
Diag.Report(S->getBeginLoc(), DiagID);
return false;
return true;
}

/// Was the maximum number of conditions encountered?
Expand All @@ -303,12 +307,12 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> {
"number of conditions (%0) exceeds max (%1). "
"Expression will not be covered");
Diag.Report(S->getBeginLoc(), DiagID) << NumCond << MCDCMaxCond;
return false;
return true;
}

// Otherwise, allocate the number of bytes required for the bitmap
// based on the number of conditions. Must be at least 1-byte long.
MCDCState.BitmapMap[BinOp] = NextMCDCBitmapIdx;
MCDCState.DecisionByStmt[BinOp].BitmapIdx = NextMCDCBitmapIdx;
unsigned SizeInBits = std::max<unsigned>(1L << NumCond, CHAR_BIT);
NextMCDCBitmapIdx += SizeInBits / CHAR_BIT;
}
Expand Down Expand Up @@ -1031,7 +1035,7 @@ void CodeGenPGO::emitCounterRegionMapping(const Decl *D) {

std::string CoverageMapping;
llvm::raw_string_ostream OS(CoverageMapping);
RegionCondIDMap.reset(new llvm::DenseMap<const Stmt *, int16_t>);
RegionMCDCState->BranchByStmt.clear();
CoverageMappingGen MappingGen(
*CGM.getCoverageMapping(), CGM.getContext().getSourceManager(),
CGM.getLangOpts(), RegionCounterMap.get(), RegionMCDCState.get());
Expand Down Expand Up @@ -1139,12 +1143,12 @@ void CodeGenPGO::emitMCDCTestVectorBitmapUpdate(CGBuilderTy &Builder,

S = S->IgnoreParens();

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

// Extract the ID of the global bitmap associated with this expression.
unsigned MCDCTestVectorBitmapID = ExprMCDCBitmapMapIterator->second;
// Extract the offset of the global bitmap associated with this expression.
unsigned MCDCTestVectorBitmapOffset = DecisionStateIter->second.BitmapIdx;
auto *I8PtrTy = llvm::PointerType::getUnqual(CGM.getLLVMContext());

// Emit intrinsic responsible for updating the global bitmap corresponding to
Expand All @@ -1155,7 +1159,7 @@ void CodeGenPGO::emitMCDCTestVectorBitmapUpdate(CGBuilderTy &Builder,
llvm::Value *Args[5] = {llvm::ConstantExpr::getBitCast(FuncNameVar, I8PtrTy),
Builder.getInt64(FunctionHash),
Builder.getInt32(RegionMCDCState->BitmapBytes),
Builder.getInt32(MCDCTestVectorBitmapID),
Builder.getInt32(MCDCTestVectorBitmapOffset),
MCDCCondBitmapAddr.getPointer()};
Builder.CreateCall(
CGM.getIntrinsic(llvm::Intrinsic::instrprof_mcdc_tvbitmap_update), Args);
Expand All @@ -1168,7 +1172,7 @@ void CodeGenPGO::emitMCDCCondBitmapReset(CGBuilderTy &Builder, const Expr *S,

S = S->IgnoreParens();

if (!RegionMCDCState->BitmapMap.contains(S))
if (!RegionMCDCState->DecisionByStmt.contains(S))
return;

// Emit intrinsic that resets a dedicated temporary value on the stack to 0.
Expand All @@ -1190,13 +1194,13 @@ void CodeGenPGO::emitMCDCCondBitmapUpdate(CGBuilderTy &Builder, const Expr *S,
// also make debugging a bit easier.
S = CodeGenFunction::stripCond(S);

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

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

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

Expand All @@ -1205,7 +1209,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),
Builder.getInt32(Branch.ID),
MCDCCondBitmapAddr.getPointer(), Val};
Builder.CreateCall(
CGM.getIntrinsic(llvm::Intrinsic::instrprof_mcdc_condbitmap_update),
Expand Down
2 changes: 0 additions & 2 deletions clang/lib/CodeGen/CodeGenPGO.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ class CodeGenPGO {
unsigned NumRegionCounters;
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 *, 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;
Expand Down
63 changes: 36 additions & 27 deletions clang/lib/CodeGen/CoverageMappingGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -684,7 +684,6 @@ struct MCDCCoverageBuilder {

llvm::SmallVector<mcdc::ConditionIDs> DecisionStack;
MCDC::State &MCDCState;
llvm::DenseMap<const Stmt *, mcdc::ConditionID> &CondIDs;
mcdc::ConditionID NextID = 0;
bool NotMapped = false;

Expand All @@ -699,8 +698,8 @@ struct MCDCCoverageBuilder {

public:
MCDCCoverageBuilder(CodeGenModule &CGM, MCDC::State &MCDCState)
: CGM(CGM), DecisionStack(1, DecisionStackSentinel), MCDCState(MCDCState),
CondIDs(MCDCState.CondIDMap) {}
: CGM(CGM), DecisionStack(1, DecisionStackSentinel),
MCDCState(MCDCState) {}

/// Return whether the build of the control flow map is at the top-level
/// (root) of a logical operator nest in a boolean expression prior to the
Expand All @@ -714,16 +713,16 @@ struct MCDCCoverageBuilder {

/// Set the given condition's ID.
void setCondID(const Expr *Cond, mcdc::ConditionID ID) {
CondIDs[CodeGenFunction::stripCond(Cond)] = ID;
MCDCState.BranchByStmt[CodeGenFunction::stripCond(Cond)].ID = ID;
}

/// Return the ID of a given condition.
mcdc::ConditionID getCondID(const Expr *Cond) const {
auto I = CondIDs.find(CodeGenFunction::stripCond(Cond));
if (I == CondIDs.end())
auto I = MCDCState.BranchByStmt.find(CodeGenFunction::stripCond(Cond));
if (I == MCDCState.BranchByStmt.end())
return -1;
else
return I->second;
return I->second.ID;
}

/// Return the LHS Decision ([0,0] if not set).
Expand All @@ -738,7 +737,7 @@ struct MCDCCoverageBuilder {

// If binary expression is disqualified, don't do mapping.
if (!isBuilding() &&
!MCDCState.BitmapMap.contains(CodeGenFunction::stripCond(E)))
!MCDCState.DecisionByStmt.contains(CodeGenFunction::stripCond(E)))
NotMapped = true;

// Don't go any further if we don't need to map condition IDs.
Expand All @@ -750,7 +749,7 @@ struct MCDCCoverageBuilder {
// If the operator itself has an assigned ID, this means it represents a
// larger subtree. In this case, assign that ID to its LHS node. Its RHS
// will receive a new ID below. Otherwise, assign ID+1 to LHS.
if (CondIDs.contains(CodeGenFunction::stripCond(E)))
if (MCDCState.BranchByStmt.contains(CodeGenFunction::stripCond(E)))
setCondID(E->getLHS(), getCondID(E));
else
setCondID(E->getLHS(), NextID++);
Expand Down Expand Up @@ -853,8 +852,6 @@ struct CounterCoverageMappingBuilder
return Counter::getCounter(CounterMap[S]);
}

unsigned getRegionBitmap(const Stmt *S) { return MCDCState.BitmapMap[S]; }

/// Push a region onto the stack.
///
/// Returns the index on the stack where the region was pushed. This can be
Expand Down Expand Up @@ -887,12 +884,11 @@ struct CounterCoverageMappingBuilder
return RegionStack.size() - 1;
}

size_t pushRegion(unsigned BitmapIdx, uint16_t Conditions,
size_t pushRegion(const mcdc::DecisionParameters &DecisionParams,
std::optional<SourceLocation> StartLoc = std::nullopt,
std::optional<SourceLocation> EndLoc = std::nullopt) {

RegionStack.emplace_back(mcdc::DecisionParameters{BitmapIdx, Conditions},
StartLoc, EndLoc);
RegionStack.emplace_back(DecisionParams, StartLoc, EndLoc);

return RegionStack.size() - 1;
}
Expand Down Expand Up @@ -1058,8 +1054,9 @@ struct CounterCoverageMappingBuilder
/// Create a Decision Region with a BitmapIdx and number of Conditions. This
/// type of region "contains" branch regions, one for each of the conditions.
/// The visualization tool will group everything together.
void createDecisionRegion(const Expr *C, unsigned BitmapIdx, unsigned Conds) {
popRegions(pushRegion(BitmapIdx, Conds, getStart(C), getEnd(C)));
void createDecisionRegion(const Expr *C,
const mcdc::DecisionParameters &DecisionParams) {
popRegions(pushRegion(DecisionParams, getStart(C), getEnd(C)));
}

/// Create a Branch Region around a SwitchCase for code coverage
Expand Down Expand Up @@ -1311,7 +1308,7 @@ struct CounterCoverageMappingBuilder
return;
assert(SpellingRegion(SM, NewStartLoc, EndLoc).isInSourceOrder());
handleFileExit(NewStartLoc);
size_t Index = pushRegion({}, NewStartLoc, EndLoc);
size_t Index = pushRegion(Counter{}, NewStartLoc, EndLoc);
getRegion().setSkipped(true);
handleFileExit(EndLoc);
popRegions(Index);
Expand Down Expand Up @@ -1961,6 +1958,20 @@ struct CounterCoverageMappingBuilder
subtractCounters(ParentCount, TrueCount));
}

void createDecision(const BinaryOperator *E) {
unsigned NumConds = MCDCBuilder.getTotalConditionsAndReset(E);
if (NumConds == 0)
return;

auto DecisionParams = mcdc::DecisionParameters{
MCDCState.DecisionByStmt[E].BitmapIdx,
NumConds,
};

// Create MCDC Decision Region.
createDecisionRegion(E, DecisionParams);
}

void VisitBinLAnd(const BinaryOperator *E) {
bool IsRootNode = MCDCBuilder.isIdle();

Expand All @@ -1981,11 +1992,6 @@ struct CounterCoverageMappingBuilder
// Track RHS True/False Decision.
const auto DecisionRHS = MCDCBuilder.back();

// Create MCDC Decision Region if at top-level (root).
unsigned NumConds = 0;
if (IsRootNode && (NumConds = MCDCBuilder.getTotalConditionsAndReset(E)))
createDecisionRegion(E, getRegionBitmap(E), NumConds);

// Extract the RHS's Execution Counter.
Counter RHSExecCnt = getRegionCounter(E);

Expand All @@ -2002,6 +2008,10 @@ struct CounterCoverageMappingBuilder
// Create Branch Region around RHS condition.
createBranchRegion(E->getRHS(), RHSTrueCnt,
subtractCounters(RHSExecCnt, RHSTrueCnt), DecisionRHS);

// Create MCDC Decision Region if at top-level (root).
if (IsRootNode)
createDecision(E);
}

// Determine whether the right side of OR operation need to be visited.
Expand Down Expand Up @@ -2034,11 +2044,6 @@ struct CounterCoverageMappingBuilder
// Track RHS True/False Decision.
const auto DecisionRHS = MCDCBuilder.back();

// Create MCDC Decision Region if at top-level (root).
unsigned NumConds = 0;
if (IsRootNode && (NumConds = MCDCBuilder.getTotalConditionsAndReset(E)))
createDecisionRegion(E, getRegionBitmap(E), NumConds);

// Extract the RHS's Execution Counter.
Counter RHSExecCnt = getRegionCounter(E);

Expand All @@ -2059,6 +2064,10 @@ struct CounterCoverageMappingBuilder
// Create Branch Region around RHS condition.
createBranchRegion(E->getRHS(), subtractCounters(RHSExecCnt, RHSFalseCnt),
RHSFalseCnt, DecisionRHS);

// Create MCDC Decision Region if at top-level (root).
if (IsRootNode)
createDecision(E);
}

void VisitLambdaExpr(const LambdaExpr *LE) {
Expand Down
14 changes: 12 additions & 2 deletions clang/lib/CodeGen/MCDCState.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,18 @@ 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;

struct Decision {
unsigned BitmapIdx;
};

llvm::DenseMap<const Stmt *, Decision> DecisionByStmt;

struct Branch {
ConditionID ID;
};

llvm::DenseMap<const Stmt *, Branch> BranchByStmt;
};

} // namespace clang::CodeGen::MCDC
Expand Down
43 changes: 43 additions & 0 deletions clang/lib/CodeGen/Targets/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "ABIInfoImpl.h"
#include "TargetInfo.h"
#include "clang/Basic/DiagnosticFrontend.h"

using namespace clang;
using namespace clang::CodeGen;
Expand Down Expand Up @@ -155,6 +156,11 @@ class AArch64TargetCodeGenInfo : public TargetCodeGenInfo {
}
return TargetCodeGenInfo::isScalarizableAsmOperand(CGF, Ty);
}

void checkFunctionCallABI(CodeGenModule &CGM, SourceLocation CallLoc,
const FunctionDecl *Caller,
const FunctionDecl *Callee,
const CallArgList &Args) const override;
};

class WindowsAArch64TargetCodeGenInfo : public AArch64TargetCodeGenInfo {
Expand Down Expand Up @@ -814,6 +820,43 @@ Address AArch64ABIInfo::EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr,
/*allowHigherAlign*/ false);
}

static bool isStreaming(const FunctionDecl *F) {
if (F->hasAttr<ArmLocallyStreamingAttr>())
return true;
if (const auto *T = F->getType()->getAs<FunctionProtoType>())
return T->getAArch64SMEAttributes() & FunctionType::SME_PStateSMEnabledMask;
return false;
}

static bool isStreamingCompatible(const FunctionDecl *F) {
if (const auto *T = F->getType()->getAs<FunctionProtoType>())
return T->getAArch64SMEAttributes() &
FunctionType::SME_PStateSMCompatibleMask;
return false;
}

void AArch64TargetCodeGenInfo::checkFunctionCallABI(
CodeGenModule &CGM, SourceLocation CallLoc, const FunctionDecl *Caller,
const FunctionDecl *Callee, const CallArgList &Args) const {
if (!Caller || !Callee || !Callee->hasAttr<AlwaysInlineAttr>())
return;

bool CallerIsStreaming = isStreaming(Caller);
bool CalleeIsStreaming = isStreaming(Callee);
bool CallerIsStreamingCompatible = isStreamingCompatible(Caller);
bool CalleeIsStreamingCompatible = isStreamingCompatible(Callee);

if (!CalleeIsStreamingCompatible &&
(CallerIsStreaming != CalleeIsStreaming || CallerIsStreamingCompatible))
CGM.getDiags().Report(CallLoc,
diag::err_function_always_inline_attribute_mismatch)
<< Caller->getDeclName() << Callee->getDeclName() << "streaming";
if (auto *NewAttr = Callee->getAttr<ArmNewAttr>())
if (NewAttr->isNewZA())
CGM.getDiags().Report(CallLoc, diag::err_function_always_inline_new_za)
<< Callee->getDeclName();
}

std::unique_ptr<TargetCodeGenInfo>
CodeGen::createAArch64TargetCodeGenInfo(CodeGenModule &CGM,
AArch64ABIKind Kind) {
Expand Down
18 changes: 18 additions & 0 deletions clang/lib/CodeGen/Targets/NVPTX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ class NVPTXTargetCodeGenInfo : public TargetCodeGenInfo {
CodeGen::CodeGenModule &M) const override;
bool shouldEmitStaticExternCAliases() const override;

llvm::Constant *getNullPointer(const CodeGen::CodeGenModule &CGM,
llvm::PointerType *T,
QualType QT) const override;

llvm::Type *getCUDADeviceBuiltinSurfaceDeviceType() const override {
// On the device side, surface reference is represented as an object handle
// in 64-bit integer.
Expand Down Expand Up @@ -285,6 +289,20 @@ void NVPTXTargetCodeGenInfo::addNVVMMetadata(llvm::GlobalValue *GV,
bool NVPTXTargetCodeGenInfo::shouldEmitStaticExternCAliases() const {
return false;
}

llvm::Constant *
NVPTXTargetCodeGenInfo::getNullPointer(const CodeGen::CodeGenModule &CGM,
llvm::PointerType *PT,
QualType QT) const {
auto &Ctx = CGM.getContext();
if (PT->getAddressSpace() != Ctx.getTargetAddressSpace(LangAS::opencl_local))
return llvm::ConstantPointerNull::get(PT);

auto NPT = llvm::PointerType::get(
PT->getContext(), Ctx.getTargetAddressSpace(LangAS::opencl_generic));
return llvm::ConstantExpr::getAddrSpaceCast(
llvm::ConstantPointerNull::get(NPT), PT);
}
}

void CodeGenModule::handleCUDALaunchBoundsAttr(llvm::Function *F,
Expand Down
40 changes: 38 additions & 2 deletions clang/lib/Driver/OffloadBundler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -588,8 +588,15 @@ class ObjectFileHandler final : public FileHandler {
StringRef Content = *ContentOrErr;

// Copy fat object contents to the output when extracting host bundle.
if (Content.size() == 1u && Content.front() == 0)
Content = StringRef(Input.getBufferStart(), Input.getBufferSize());
std::string ModifiedContent;
if (Content.size() == 1u && Content.front() == 0) {
auto HostBundleOrErr = getHostBundle();
if (!HostBundleOrErr)
return HostBundleOrErr.takeError();

ModifiedContent = std::move(*HostBundleOrErr);
Content = ModifiedContent;
}

OS.write(Content.data(), Content.size());
return Error::success();
Expand Down Expand Up @@ -692,6 +699,35 @@ class ObjectFileHandler final : public FileHandler {
}
return Error::success();
}

Expected<std::string> getHostBundle() {
TempFileHandlerRAII TempFiles;

auto ModifiedObjPathOrErr = TempFiles.Create(std::nullopt);
if (!ModifiedObjPathOrErr)
return ModifiedObjPathOrErr.takeError();
StringRef ModifiedObjPath = *ModifiedObjPathOrErr;

BumpPtrAllocator Alloc;
StringSaver SS{Alloc};
SmallVector<StringRef, 16> ObjcopyArgs{"llvm-objcopy"};

ObjcopyArgs.push_back("--regex");
ObjcopyArgs.push_back("--remove-section=__CLANG_OFFLOAD_BUNDLE__.*");
ObjcopyArgs.push_back("--");
ObjcopyArgs.push_back(BundlerConfig.InputFileNames.front());
ObjcopyArgs.push_back(ModifiedObjPath);

if (Error Err = executeObjcopy(BundlerConfig.ObjcopyPath, ObjcopyArgs))
return std::move(Err);

auto BufOrErr = MemoryBuffer::getFile(ModifiedObjPath);
if (!BufOrErr)
return createStringError(BufOrErr.getError(),
"Failed to read back the modified object file");

return BufOrErr->get()->getBuffer().str();
}
};

/// Handler for text files. The bundled file will have the following format.
Expand Down
48 changes: 42 additions & 6 deletions clang/lib/Driver/ToolChain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,19 @@ static ToolChain::RTTIMode CalculateRTTIMode(const ArgList &Args,
return NoRTTI ? ToolChain::RM_Disabled : ToolChain::RM_Enabled;
}

static ToolChain::ExceptionsMode CalculateExceptionsMode(const ArgList &Args) {
if (Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions,
true)) {
return ToolChain::EM_Enabled;
}
return ToolChain::EM_Disabled;
}

ToolChain::ToolChain(const Driver &D, const llvm::Triple &T,
const ArgList &Args)
: D(D), Triple(T), Args(Args), CachedRTTIArg(GetRTTIArgument(Args)),
CachedRTTIMode(CalculateRTTIMode(Args, Triple, CachedRTTIArg)) {
CachedRTTIMode(CalculateRTTIMode(Args, Triple, CachedRTTIArg)),
CachedExceptionsMode(CalculateExceptionsMode(Args)) {
auto addIfExists = [this](path_list &List, const std::string &Path) {
if (getVFS().exists(Path))
List.push_back(Path);
Expand Down Expand Up @@ -191,7 +200,12 @@ static void getAArch64MultilibFlags(const Driver &D,
for (const auto &Ext : AArch64::Extensions)
if (FeatureSet.contains(Ext.NegFeature))
MArch.push_back(("no" + Ext.Name).str());
MArch.insert(MArch.begin(), ("-march=" + Triple.getArchName()).str());
StringRef ArchName;
for (const auto &ArchInfo : AArch64::ArchInfos)
if (FeatureSet.contains(ArchInfo->ArchFeature))
ArchName = ArchInfo->Name;
assert(!ArchName.empty() && "at least one architecture should be found");
MArch.insert(MArch.begin(), ("-march=" + ArchName).str());
Result.push_back(llvm::join(MArch, "+"));
}

Expand Down Expand Up @@ -264,6 +278,18 @@ ToolChain::getMultilibFlags(const llvm::opt::ArgList &Args) const {
break;
}

// Include fno-exceptions and fno-rtti
// to improve multilib selection
if (getRTTIMode() == ToolChain::RTTIMode::RM_Disabled)
Result.push_back("-fno-rtti");
else
Result.push_back("-frtti");

if (getExceptionsMode() == ToolChain::ExceptionsMode::EM_Disabled)
Result.push_back("-fno-exceptions");
else
Result.push_back("-fexceptions");

// Sort and remove duplicates.
std::sort(Result.begin(), Result.end());
Result.erase(std::unique(Result.begin(), Result.end()), Result.end());
Expand Down Expand Up @@ -655,19 +681,29 @@ std::string ToolChain::getCompilerRT(const ArgList &Args, StringRef Component,
// Check for runtime files in the new layout without the architecture first.
std::string CRTBasename =
buildCompilerRTBasename(Args, Component, Type, /*AddArch=*/false);
SmallString<128> Path;
for (const auto &LibPath : getLibraryPaths()) {
SmallString<128> P(LibPath);
llvm::sys::path::append(P, CRTBasename);
if (getVFS().exists(P))
return std::string(P);
if (Path.empty())
Path = P;
}
if (getTriple().isOSAIX())
Path.clear();

// Fall back to the old expected compiler-rt name if the new one does not
// exist.
// Check the filename for the old layout if the new one does not exist.
CRTBasename =
buildCompilerRTBasename(Args, Component, Type, /*AddArch=*/true);
SmallString<128> Path(getCompilerRTPath());
llvm::sys::path::append(Path, CRTBasename);
SmallString<128> OldPath(getCompilerRTPath());
llvm::sys::path::append(OldPath, CRTBasename);
if (Path.empty() || getVFS().exists(OldPath))
return std::string(OldPath);

// If none is found, use a file name from the new layout, which may get
// printed in an error message, aiding users in knowing what Clang is
// looking for.
return std::string(Path);
}

Expand Down
1 change: 1 addition & 0 deletions clang/lib/Driver/ToolChains/AMDGPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,7 @@ void amdgpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,

addLinkerCompressDebugSectionsOption(getToolChain(), Args, CmdArgs);
Args.AddAllArgs(CmdArgs, options::OPT_L);
getToolChain().AddFilePathLibArgs(Args, CmdArgs);
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
if (C.getDriver().isUsingLTO())
addLTOOptions(getToolChain(), Args, CmdArgs, Output, Inputs[0],
Expand Down
24 changes: 12 additions & 12 deletions clang/lib/Driver/ToolChains/Arch/ARM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -890,25 +890,25 @@ llvm::ARM::FPUKind arm::getARMTargetFeatures(const Driver &D,
// SCTLR.U bit, which is architecture-specific. We assume ARMv6
// Darwin and NetBSD targets support unaligned accesses, and others don't.
//
// ARMv7 always has SCTLR.U set to 1, but it has a new SCTLR.A bit
// which raises an alignment fault on unaligned accesses. Linux
// defaults this bit to 0 and handles it as a system-wide (not
// per-process) setting. It is therefore safe to assume that ARMv7+
// Linux targets support unaligned accesses. The same goes for NaCl
// and Windows.
// ARMv7 always has SCTLR.U set to 1, but it has a new SCTLR.A bit which
// raises an alignment fault on unaligned accesses. Assume ARMv7+ supports
// unaligned accesses, except ARMv6-M, and ARMv8-M without the Main
// Extension. This aligns with the default behavior of ARM's downstream
// versions of GCC and Clang.
//
// The above behavior is consistent with GCC.
// Users can change the default behavior via -m[no-]unaliged-access.
int VersionNum = getARMSubArchVersionNumber(Triple);
if (Triple.isOSDarwin() || Triple.isOSNetBSD()) {
if (VersionNum < 6 ||
Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m)
Features.push_back("+strict-align");
} else if (Triple.isOSLinux() || Triple.isOSNaCl() ||
Triple.isOSWindows()) {
if (VersionNum < 7)
Features.push_back("+strict-align");
} else
} else if (VersionNum < 7 ||
Triple.getSubArch() ==
llvm::Triple::SubArchType::ARMSubArch_v6m ||
Triple.getSubArch() ==
llvm::Triple::SubArchType::ARMSubArch_v8m_baseline) {
Features.push_back("+strict-align");
}
}

// llvm does not support reserving registers in general. There is support
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1111,8 +1111,8 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
C.getActiveOffloadKinds() == Action::OFK_None) {
SmallString<128> P(llvm::sys::path::parent_path(D.InstalledDir));
llvm::sys::path::append(P, "include");
llvm::sys::path::append(P, "gpu-none-llvm");
CmdArgs.push_back("-c-isystem");
llvm::sys::path::append(P, getToolChain().getTripleString());
CmdArgs.push_back("-internal-isystem");
CmdArgs.push_back(Args.MakeArgString(P));
} else if (C.getActiveOffloadKinds() == Action::OFK_OpenMP) {
// TODO: CUDA / HIP include their own headers for some common functions
Expand Down
37 changes: 34 additions & 3 deletions clang/lib/Driver/ToolChains/CommonArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1087,10 +1087,41 @@ static void addOpenMPDeviceLibC(const ToolChain &TC, const ArgList &Args,
"llvm-libc-decls");
bool HasLibC = llvm::sys::fs::exists(LibCDecls) &&
llvm::sys::fs::is_directory(LibCDecls);
if (Args.hasFlag(options::OPT_gpulibc, options::OPT_nogpulibc, HasLibC)) {
CmdArgs.push_back("-lcgpu");
CmdArgs.push_back("-lmgpu");
if (!Args.hasFlag(options::OPT_gpulibc, options::OPT_nogpulibc, HasLibC))
return;

// We don't have access to the offloading toolchains here, so determine from
// the arguments if we have any active NVPTX or AMDGPU toolchains.
llvm::DenseSet<const char *> Libraries;
if (const Arg *Targets = Args.getLastArg(options::OPT_fopenmp_targets_EQ)) {
if (llvm::any_of(Targets->getValues(),
[](auto S) { return llvm::Triple(S).isAMDGPU(); })) {
Libraries.insert("-lcgpu-amdgpu");
Libraries.insert("-lmgpu-amdgpu");
}
if (llvm::any_of(Targets->getValues(),
[](auto S) { return llvm::Triple(S).isNVPTX(); })) {
Libraries.insert("-lcgpu-nvptx");
Libraries.insert("-lmgpu-nvptx");
}
}

for (StringRef Arch : Args.getAllArgValues(options::OPT_offload_arch_EQ)) {
if (llvm::any_of(llvm::split(Arch, ","), [](StringRef Str) {
return IsAMDGpuArch(StringToCudaArch(Str));
})) {
Libraries.insert("-lcgpu-amdgpu");
Libraries.insert("-lmgpu-amdgpu");
}
if (llvm::any_of(llvm::split(Arch, ","), [](StringRef Str) {
return IsNVIDIAGpuArch(StringToCudaArch(Str));
})) {
Libraries.insert("-lcgpu-nvptx");
Libraries.insert("-lmgpu-nvptx");
}
}

llvm::append_range(CmdArgs, Libraries);
}

void tools::addOpenMPRuntimeLibraryPath(const ToolChain &TC,
Expand Down
47 changes: 25 additions & 22 deletions clang/lib/Driver/ToolChains/Cuda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,10 @@ void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// Add paths specified in LIBRARY_PATH environment variable as -L options.
addDirectoryList(Args, CmdArgs, "-L", "LIBRARY_PATH");

// Add standard library search paths passed on the command line.
Args.AddAllArgs(CmdArgs, options::OPT_L);
getToolChain().AddFilePathLibArgs(Args, CmdArgs);

// Add paths for the default clang library path.
SmallString<256> DefaultLibPath =
llvm::sys::path::parent_path(TC.getDriver().Dir);
Expand All @@ -623,35 +627,34 @@ void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA,
continue;
}

// Currently, we only pass the input files to the linker, we do not pass
// any libraries that may be valid only for the host.
if (!II.isFilename())
continue;

// The 'nvlink' application performs RDC-mode linking when given a '.o'
// file and device linking when given a '.cubin' file. We always want to
// perform device linking, so just rename any '.o' files.
// FIXME: This should hopefully be removed if NVIDIA updates their tooling.
auto InputFile = getToolChain().getInputFilename(II);
if (llvm::sys::path::extension(InputFile) != ".cubin") {
// If there are no actions above this one then this is direct input and we
// can copy it. Otherwise the input is internal so a `.cubin` file should
// exist.
if (II.getAction() && II.getAction()->getInputs().size() == 0) {
const char *CubinF =
Args.MakeArgString(getToolChain().getDriver().GetTemporaryPath(
llvm::sys::path::stem(InputFile), "cubin"));
if (llvm::sys::fs::copy_file(InputFile, C.addTempFile(CubinF)))
continue;
if (II.isFilename()) {
auto InputFile = getToolChain().getInputFilename(II);
if (llvm::sys::path::extension(InputFile) != ".cubin") {
// If there are no actions above this one then this is direct input and
// we can copy it. Otherwise the input is internal so a `.cubin` file
// should exist.
if (II.getAction() && II.getAction()->getInputs().size() == 0) {
const char *CubinF =
Args.MakeArgString(getToolChain().getDriver().GetTemporaryPath(
llvm::sys::path::stem(InputFile), "cubin"));
if (llvm::sys::fs::copy_file(InputFile, C.addTempFile(CubinF)))
continue;

CmdArgs.push_back(CubinF);
CmdArgs.push_back(CubinF);
} else {
SmallString<256> Filename(InputFile);
llvm::sys::path::replace_extension(Filename, "cubin");
CmdArgs.push_back(Args.MakeArgString(Filename));
}
} else {
SmallString<256> Filename(InputFile);
llvm::sys::path::replace_extension(Filename, "cubin");
CmdArgs.push_back(Args.MakeArgString(Filename));
CmdArgs.push_back(Args.MakeArgString(InputFile));
}
} else {
CmdArgs.push_back(Args.MakeArgString(InputFile));
} else if (!II.isNothing()) {
II.getInputArg().renderAsInput(Args, CmdArgs);
}
}

Expand Down
258 changes: 245 additions & 13 deletions clang/lib/Driver/ToolChains/HIPUtility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,24 @@
#include "HIPUtility.h"
#include "CommonArgs.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Options.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TargetParser/Triple.h"
#include <deque>
#include <set>

using namespace clang;
using namespace clang::driver;
using namespace clang::driver::tools;
using namespace llvm::opt;
using llvm::dyn_cast;

#if defined(_WIN32) || defined(_WIN64)
#define NULL_FILE "nul"
Expand All @@ -36,6 +47,169 @@ static std::string normalizeForBundler(const llvm::Triple &T,
: T.normalize();
}

// Collect undefined __hip_fatbin* and __hip_gpubin_handle* symbols from all
// input object or archive files.
class HIPUndefinedFatBinSymbols {
public:
HIPUndefinedFatBinSymbols(const Compilation &C)
: C(C), DiagID(C.getDriver().getDiags().getCustomDiagID(
DiagnosticsEngine::Error,
"Error collecting HIP undefined fatbin symbols: %0")),
Quiet(C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)),
Verbose(C.getArgs().hasArg(options::OPT_v)) {
populateSymbols();
if (Verbose) {
for (auto Name : FatBinSymbols)
llvm::errs() << "Found undefined HIP fatbin symbol: " << Name << "\n";
for (auto Name : GPUBinHandleSymbols)
llvm::errs() << "Found undefined HIP gpubin handle symbol: " << Name
<< "\n";
}
}

const std::set<std::string> &getFatBinSymbols() const {
return FatBinSymbols;
}

const std::set<std::string> &getGPUBinHandleSymbols() const {
return GPUBinHandleSymbols;
}

private:
const Compilation &C;
unsigned DiagID;
bool Quiet;
bool Verbose;
std::set<std::string> FatBinSymbols;
std::set<std::string> GPUBinHandleSymbols;
std::set<std::string> DefinedFatBinSymbols;
std::set<std::string> DefinedGPUBinHandleSymbols;
const std::string FatBinPrefix = "__hip_fatbin";
const std::string GPUBinHandlePrefix = "__hip_gpubin_handle";

void populateSymbols() {
std::deque<const Action *> WorkList;
std::set<const Action *> Visited;

for (const auto &Action : C.getActions())
WorkList.push_back(Action);

while (!WorkList.empty()) {
const Action *CurrentAction = WorkList.front();
WorkList.pop_front();

if (!CurrentAction || !Visited.insert(CurrentAction).second)
continue;

if (const auto *IA = dyn_cast<InputAction>(CurrentAction)) {
std::string ID = IA->getId().str();
if (!ID.empty()) {
ID = llvm::utohexstr(llvm::MD5Hash(ID), /*LowerCase=*/true);
FatBinSymbols.insert(Twine(FatBinPrefix + "_" + ID).str());
GPUBinHandleSymbols.insert(
Twine(GPUBinHandlePrefix + "_" + ID).str());
continue;
}
if (IA->getInputArg().getNumValues() == 0)
continue;
const char *Filename = IA->getInputArg().getValue();
if (!Filename)
continue;
auto BufferOrErr = llvm::MemoryBuffer::getFile(Filename);
// Input action could be options to linker, therefore, ignore it
// if cannot read it. If it turns out to be a file that cannot be read,
// the error will be caught by the linker.
if (!BufferOrErr)
continue;

processInput(BufferOrErr.get()->getMemBufferRef());
} else
WorkList.insert(WorkList.end(), CurrentAction->getInputs().begin(),
CurrentAction->getInputs().end());
}
}

void processInput(const llvm::MemoryBufferRef &Buffer) {
// Try processing as object file first.
auto ObjFileOrErr = llvm::object::ObjectFile::createObjectFile(Buffer);
if (ObjFileOrErr) {
processSymbols(**ObjFileOrErr);
return;
}

// Then try processing as archive files.
llvm::consumeError(ObjFileOrErr.takeError());
auto ArchiveOrErr = llvm::object::Archive::create(Buffer);
if (ArchiveOrErr) {
llvm::Error Err = llvm::Error::success();
llvm::object::Archive &Archive = *ArchiveOrErr.get();
for (auto &Child : Archive.children(Err)) {
auto ChildBufOrErr = Child.getMemoryBufferRef();
if (ChildBufOrErr)
processInput(*ChildBufOrErr);
else
errorHandler(ChildBufOrErr.takeError());
}

if (Err)
errorHandler(std::move(Err));
return;
}

// Ignore other files.
llvm::consumeError(ArchiveOrErr.takeError());
}

void processSymbols(const llvm::object::ObjectFile &Obj) {
for (const auto &Symbol : Obj.symbols()) {
auto FlagOrErr = Symbol.getFlags();
if (!FlagOrErr) {
errorHandler(FlagOrErr.takeError());
continue;
}

auto NameOrErr = Symbol.getName();
if (!NameOrErr) {
errorHandler(NameOrErr.takeError());
continue;
}
llvm::StringRef Name = *NameOrErr;

bool isUndefined =
FlagOrErr.get() & llvm::object::SymbolRef::SF_Undefined;
bool isFatBinSymbol = Name.starts_with(FatBinPrefix);
bool isGPUBinHandleSymbol = Name.starts_with(GPUBinHandlePrefix);

// Handling for defined symbols
if (!isUndefined) {
if (isFatBinSymbol) {
DefinedFatBinSymbols.insert(Name.str());
FatBinSymbols.erase(Name.str());
} else if (isGPUBinHandleSymbol) {
DefinedGPUBinHandleSymbols.insert(Name.str());
GPUBinHandleSymbols.erase(Name.str());
}
continue;
}

// Add undefined symbols if they are not in the defined sets
if (isFatBinSymbol &&
DefinedFatBinSymbols.find(Name.str()) == DefinedFatBinSymbols.end())
FatBinSymbols.insert(Name.str());
else if (isGPUBinHandleSymbol &&
DefinedGPUBinHandleSymbols.find(Name.str()) ==
DefinedGPUBinHandleSymbols.end())
GPUBinHandleSymbols.insert(Name.str());
}
}

void errorHandler(llvm::Error Err) {
if (Quiet)
return;
C.getDriver().Diag(DiagID) << llvm::toString(std::move(Err));
}
};

// Construct a clang-offload-bundler command to bundle code objects for
// different devices into a HIP fat binary.
void HIP::constructHIPFatbinCommand(Compilation &C, const JobAction &JA,
Expand Down Expand Up @@ -130,26 +304,84 @@ void HIP::constructGenerateObjFileFromHIPFatBinary(
auto HostTriple =
C.getSingleOffloadToolChain<Action::OFK_Host>()->getTriple();

HIPUndefinedFatBinSymbols Symbols(C);

std::string PrimaryHipFatbinSymbol;
std::string PrimaryGpuBinHandleSymbol;
bool FoundPrimaryHipFatbinSymbol = false;
bool FoundPrimaryGpuBinHandleSymbol = false;

std::vector<std::string> AliasHipFatbinSymbols;
std::vector<std::string> AliasGpuBinHandleSymbols;

// Iterate through symbols to find the primary ones and collect others for
// aliasing
for (const auto &Symbol : Symbols.getFatBinSymbols()) {
if (!FoundPrimaryHipFatbinSymbol) {
PrimaryHipFatbinSymbol = Symbol;
FoundPrimaryHipFatbinSymbol = true;
} else
AliasHipFatbinSymbols.push_back(Symbol);
}

for (const auto &Symbol : Symbols.getGPUBinHandleSymbols()) {
if (!FoundPrimaryGpuBinHandleSymbol) {
PrimaryGpuBinHandleSymbol = Symbol;
FoundPrimaryGpuBinHandleSymbol = true;
} else
AliasGpuBinHandleSymbols.push_back(Symbol);
}

// Add MC directives to embed target binaries. We ensure that each
// section and image is 16-byte aligned. This is not mandatory, but
// increases the likelihood of data to be aligned with a cache block
// in several main host machines.
ObjStream << "# HIP Object Generator\n";
ObjStream << "# *** Automatically generated by Clang ***\n";
if (HostTriple.isWindowsMSVCEnvironment()) {
ObjStream << " .section .hip_fatbin, \"dw\"\n";
} else {
ObjStream << " .protected __hip_fatbin\n";
ObjStream << " .type __hip_fatbin,@object\n";
ObjStream << " .section .hip_fatbin,\"a\",@progbits\n";
if (FoundPrimaryGpuBinHandleSymbol) {
// Define the first gpubin handle symbol
if (HostTriple.isWindowsMSVCEnvironment())
ObjStream << " .section .hip_gpubin_handle,\"dw\"\n";
else {
ObjStream << " .protected " << PrimaryGpuBinHandleSymbol << "\n";
ObjStream << " .type " << PrimaryGpuBinHandleSymbol << ",@object\n";
ObjStream << " .section .hip_gpubin_handle,\"aw\"\n";
}
ObjStream << " .globl " << PrimaryGpuBinHandleSymbol << "\n";
ObjStream << " .p2align 3\n"; // Align 8
ObjStream << PrimaryGpuBinHandleSymbol << ":\n";
ObjStream << " .zero 8\n"; // Size 8

// Generate alias directives for other gpubin handle symbols
for (const auto &AliasSymbol : AliasGpuBinHandleSymbols) {
ObjStream << " .globl " << AliasSymbol << "\n";
ObjStream << " .set " << AliasSymbol << "," << PrimaryGpuBinHandleSymbol
<< "\n";
}
}
if (FoundPrimaryHipFatbinSymbol) {
// Define the first fatbin symbol
if (HostTriple.isWindowsMSVCEnvironment())
ObjStream << " .section .hip_fatbin,\"dw\"\n";
else {
ObjStream << " .protected " << PrimaryHipFatbinSymbol << "\n";
ObjStream << " .type " << PrimaryHipFatbinSymbol << ",@object\n";
ObjStream << " .section .hip_fatbin,\"a\",@progbits\n";
}
ObjStream << " .globl " << PrimaryHipFatbinSymbol << "\n";
ObjStream << " .p2align " << llvm::Log2(llvm::Align(HIPCodeObjectAlign))
<< "\n";
// Generate alias directives for other fatbin symbols
for (const auto &AliasSymbol : AliasHipFatbinSymbols) {
ObjStream << " .globl " << AliasSymbol << "\n";
ObjStream << " .set " << AliasSymbol << "," << PrimaryHipFatbinSymbol
<< "\n";
}
ObjStream << PrimaryHipFatbinSymbol << ":\n";
ObjStream << " .incbin ";
llvm::sys::printArg(ObjStream, BundleFile, /*Quote=*/true);
ObjStream << "\n";
}
ObjStream << " .globl __hip_fatbin\n";
ObjStream << " .p2align " << llvm::Log2(llvm::Align(HIPCodeObjectAlign))
<< "\n";
ObjStream << "__hip_fatbin:\n";
ObjStream << " .incbin ";
llvm::sys::printArg(ObjStream, BundleFile, /*Quote=*/true);
ObjStream << "\n";
if (HostTriple.isOSLinux() && HostTriple.isOSBinFormatELF())
ObjStream << " .section .note.GNU-stack, \"\", @progbits\n";
ObjStream.flush();
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Driver/ToolChains/RISCVToolchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ RISCVToolChain::GetUnwindLibType(const llvm::opt::ArgList &Args) const {
return ToolChain::UNW_None;
}

ToolChain::UnwindTableLevel RISCVToolChain::getDefaultUnwindTableLevel(
const llvm::opt::ArgList &Args) const {
return UnwindTableLevel::None;
}

void RISCVToolChain::addClangTargetOptions(
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args,
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Driver/ToolChains/RISCVToolchain.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ class LLVM_LIBRARY_VISIBILITY RISCVToolChain : public Generic_ELF {
RuntimeLibType GetDefaultRuntimeLibType() const override;
UnwindLibType
GetUnwindLibType(const llvm::opt::ArgList &Args) const override;
UnwindTableLevel
getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override;
void
AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
Expand Down
8 changes: 7 additions & 1 deletion clang/lib/Format/Format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -915,6 +915,8 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("AlignConsecutiveMacros", Style.AlignConsecutiveMacros);
IO.mapOptional("AlignConsecutiveShortCaseStatements",
Style.AlignConsecutiveShortCaseStatements);
IO.mapOptional("AlignConsecutiveTableGenCondOperatorColons",
Style.AlignConsecutiveTableGenCondOperatorColons);
IO.mapOptional("AlignEscapedNewlines", Style.AlignEscapedNewlines);
IO.mapOptional("AlignOperands", Style.AlignOperands);
IO.mapOptional("AlignTrailingComments", Style.AlignTrailingComments);
Expand Down Expand Up @@ -1420,6 +1422,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.AlignConsecutiveDeclarations = {};
LLVMStyle.AlignConsecutiveMacros = {};
LLVMStyle.AlignConsecutiveShortCaseStatements = {};
LLVMStyle.AlignConsecutiveTableGenCondOperatorColons = {};
LLVMStyle.AlignEscapedNewlines = FormatStyle::ENAS_Right;
LLVMStyle.AlignOperands = FormatStyle::OAS_Align;
LLVMStyle.AlignTrailingComments = {};
Expand Down Expand Up @@ -1591,7 +1594,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.PenaltyBreakScopeResolution = 500;
LLVMStyle.PenaltyBreakString = 1000;
LLVMStyle.PenaltyBreakTemplateDeclaration = prec::Relational;
LLVMStyle.PenaltyExcessCharacter = 1000000;
LLVMStyle.PenaltyExcessCharacter = 1'000'000;
LLVMStyle.PenaltyIndentedWhitespace = 0;
LLVMStyle.PenaltyReturnTypeOnItsOwnLine = 60;

Expand Down Expand Up @@ -1914,9 +1917,12 @@ FormatStyle getClangFormatStyle() {
FormatStyle Style = getLLVMStyle();
Style.InsertBraces = true;
Style.InsertNewlineAtEOF = true;
Style.IntegerLiteralSeparator.Decimal = 3;
Style.IntegerLiteralSeparator.DecimalMinDigits = 5;
Style.LineEnding = FormatStyle::LE_LF;
Style.RemoveBracesLLVM = true;
Style.RemoveParentheses = FormatStyle::RPS_ReturnStatement;
Style.RemoveSemicolon = true;
return Style;
}

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Format/FormatToken.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ unsigned CommaSeparatedList::formatAfterToken(LineState &State,
// bin-packed. Add a severe penalty to this so that column layouts are
// preferred if possible.
if (!Format)
return 10000;
return 10'000;

// Format the entire list.
unsigned Penalty = 0;
Expand Down
68 changes: 45 additions & 23 deletions clang/lib/Format/MacroCallReconstructor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ void forEachToken(const UnwrappedLine &Line, const T &Call,
FormatToken *Parent = nullptr) {
bool First = true;
for (const auto &N : Line.Tokens) {
Call(N.Tok, Parent, First);
Call(N.Tok, Parent, First, Line.Level);
First = false;
for (const auto &Child : N.Children)
forEachToken(Child, Call, N.Tok);
Expand All @@ -44,26 +44,25 @@ MacroCallReconstructor::MacroCallReconstructor(
unsigned Level,
const llvm::DenseMap<FormatToken *, std::unique_ptr<UnwrappedLine>>
&ActiveExpansions)
: Level(Level), IdToReconstructed(ActiveExpansions) {
: Result(Level), IdToReconstructed(ActiveExpansions) {
Result.Tokens.push_back(std::make_unique<LineNode>());
ActiveReconstructedLines.push_back(&Result);
}

void MacroCallReconstructor::addLine(const UnwrappedLine &Line) {
assert(State != Finalized);
LLVM_DEBUG(llvm::dbgs() << "MCR: new line...\n");
forEachToken(Line, [&](FormatToken *Token, FormatToken *Parent, bool First) {
add(Token, Parent, First);
});
forEachToken(Line, [&](FormatToken *Token, FormatToken *Parent, bool First,
unsigned Level) { add(Token, Parent, First, Level); });
assert(InProgress || finished());
}

UnwrappedLine MacroCallReconstructor::takeResult() && {
finalize();
assert(Result.Tokens.size() == 1 &&
Result.Tokens.front()->Children.size() == 1);
UnwrappedLine Final =
createUnwrappedLine(*Result.Tokens.front()->Children.front(), Level);
UnwrappedLine Final = createUnwrappedLine(
*Result.Tokens.front()->Children.front(), Result.Level);
assert(!Final.Tokens.empty());
return Final;
}
Expand All @@ -72,7 +71,8 @@ UnwrappedLine MacroCallReconstructor::takeResult() && {
// ExpandedParent in the incoming unwrapped line. \p First specifies whether it
// is the first token in a given unwrapped line.
void MacroCallReconstructor::add(FormatToken *Token,
FormatToken *ExpandedParent, bool First) {
FormatToken *ExpandedParent, bool First,
unsigned Level) {
LLVM_DEBUG(
llvm::dbgs() << "MCR: Token: " << Token->TokenText << ", Parent: "
<< (ExpandedParent ? ExpandedParent->TokenText : "<null>")
Expand Down Expand Up @@ -102,7 +102,7 @@ void MacroCallReconstructor::add(FormatToken *Token,
First = true;
}

prepareParent(ExpandedParent, First);
prepareParent(ExpandedParent, First, Level);

if (Token->MacroCtx) {
// If this token was generated by a macro call, add the reconstructed
Expand All @@ -129,7 +129,7 @@ void MacroCallReconstructor::add(FormatToken *Token,
// is the parent of ActiveReconstructedLines.back() in the reconstructed
// unwrapped line.
void MacroCallReconstructor::prepareParent(FormatToken *ExpandedParent,
bool NewLine) {
bool NewLine, unsigned Level) {
LLVM_DEBUG({
llvm::dbgs() << "ParentMap:\n";
debugParentMap();
Expand Down Expand Up @@ -172,7 +172,7 @@ void MacroCallReconstructor::prepareParent(FormatToken *ExpandedParent,
}
assert(!ActiveReconstructedLines.empty());
ActiveReconstructedLines.back()->Tokens.back()->Children.push_back(
std::make_unique<ReconstructedLine>());
std::make_unique<ReconstructedLine>(Level));
ActiveReconstructedLines.push_back(
&*ActiveReconstructedLines.back()->Tokens.back()->Children.back());
} else if (parentLine().Tokens.back()->Tok != Parent) {
Expand Down Expand Up @@ -424,7 +424,8 @@ bool MacroCallReconstructor::processNextReconstructed() {
SpelledParentToReconstructedParent[MacroCallStructure.back()
.ParentLastToken] = Token;
appendToken(Token);
prepareParent(Token, /*NewLine=*/true);
prepareParent(Token, /*NewLine=*/true,
MacroCallStructure.back().Line->Level);
Token->MacroParent = true;
return false;
}
Expand All @@ -435,7 +436,8 @@ bool MacroCallReconstructor::processNextReconstructed() {
[MacroCallStructure.back().Line->Tokens.back()->Tok] = Token;
Token->MacroParent = true;
appendToken(Token, MacroCallStructure.back().Line);
prepareParent(Token, /*NewLine=*/true);
prepareParent(Token, /*NewLine=*/true,
MacroCallStructure.back().Line->Level);
return true;
}
if (Token->is(tok::r_paren)) {
Expand Down Expand Up @@ -509,16 +511,36 @@ MacroCallReconstructor::createUnwrappedLine(const ReconstructedLine &Line,
for (const auto &N : Line.Tokens) {
Result.Tokens.push_back(N->Tok);
UnwrappedLineNode &Current = Result.Tokens.back();
for (const auto &Child : N->Children) {
if (Child->Tokens.empty())
continue;
Current.Children.push_back(createUnwrappedLine(*Child, Level + 1));
}
if (Current.Children.size() == 1 &&
Current.Tok->isOneOf(tok::l_paren, tok::comma)) {
Result.Tokens.splice(Result.Tokens.end(),
Current.Children.front().Tokens);
Current.Children.clear();
auto NumChildren =
std::count_if(N->Children.begin(), N->Children.end(),
[](const auto &Child) { return !Child->Tokens.empty(); });
if (NumChildren == 1 && Current.Tok->isOneOf(tok::l_paren, tok::comma)) {
// If we only have one child, and the child is due to a macro expansion
// (either attached to a left parenthesis or comma), merge the child into
// the current line to prevent forced breaks for macro arguments.
auto *Child = std::find_if(
N->Children.begin(), N->Children.end(),
[](const auto &Child) { return !Child->Tokens.empty(); });
auto Line = createUnwrappedLine(**Child, Level);
Result.Tokens.splice(Result.Tokens.end(), Line.Tokens);
} else if (NumChildren > 0) {
// When there are multiple children with different indent, make sure that
// we indent them:
// 1. One level below the current line's level.
// 2. At the correct level relative to each other.
unsigned MinChildLevel =
std::min_element(N->Children.begin(), N->Children.end(),
[](const auto &E1, const auto &E2) {
return E1->Level < E2->Level;
})
->get()
->Level;
for (const auto &Child : N->Children) {
if (Child->Tokens.empty())
continue;
Current.Children.push_back(createUnwrappedLine(
*Child, Level + 1 + (Child->Level - MinChildLevel)));
}
}
}
return Result;
Expand Down
10 changes: 5 additions & 5 deletions clang/lib/Format/Macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,8 +231,9 @@ class MacroCallReconstructor {
UnwrappedLine takeResult() &&;

private:
void add(FormatToken *Token, FormatToken *ExpandedParent, bool First);
void prepareParent(FormatToken *ExpandedParent, bool First);
void add(FormatToken *Token, FormatToken *ExpandedParent, bool First,
unsigned Level);
void prepareParent(FormatToken *ExpandedParent, bool First, unsigned Level);
FormatToken *getParentInResult(FormatToken *Parent);
void reconstruct(FormatToken *Token);
void startReconstruction(FormatToken *Token);
Expand Down Expand Up @@ -272,6 +273,8 @@ class MacroCallReconstructor {
// FIXME: Investigate changing UnwrappedLine to a pointer type and using it
// instead of rolling our own type.
struct ReconstructedLine {
explicit ReconstructedLine(unsigned Level) : Level(Level) {}
unsigned Level;
llvm::SmallVector<std::unique_ptr<LineNode>> Tokens;
};

Expand Down Expand Up @@ -373,9 +376,6 @@ class MacroCallReconstructor {
// \- )
llvm::SmallVector<MacroCallState> MacroCallStructure;

// Level the generated UnwrappedLine will be at.
const unsigned Level;

// Maps from identifier of the macro call to an unwrapped line containing
// all tokens of the macro call.
const llvm::DenseMap<FormatToken *, std::unique_ptr<UnwrappedLine>>
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3817,7 +3817,7 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) const {
do {
Tok = Tok->Next;
} while (Tok && Tok->isNot(TT_OverloadedOperatorLParen));
if (!Tok)
if (!Tok || !Tok->MatchingParen)
break;
const auto *LeftParen = Tok;
for (Tok = Tok->Next; Tok && Tok != LeftParen->MatchingParen;
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Format/UnwrappedLineFormatter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1221,7 +1221,7 @@ class OptimizingLineFormatter : public LineFormatter {
// While not empty, take first element and follow edges.
while (!Queue.empty()) {
// Quit if we still haven't found a solution by now.
if (Count > 25000000)
if (Count > 25'000'000)
return 0;

Penalty = Queue.top().first.first;
Expand All @@ -1235,7 +1235,7 @@ class OptimizingLineFormatter : public LineFormatter {

// Cut off the analysis of certain solutions if the analysis gets too
// complex. See description of IgnoreStackForComparison.
if (Count > 50000)
if (Count > 50'000)
Node->State.IgnoreStackForComparison = true;

if (!Seen.insert(&Node->State).second) {
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Format/UnwrappedLineParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ class ScopedDeclarationState {

} // end anonymous namespace

std::ostream &operator<<(std::ostream &Stream, const UnwrappedLine &Line) {
llvm::raw_os_ostream OS(Stream);
printLine(OS, Line);
return Stream;
}

class ScopedLineState {
public:
ScopedLineState(UnwrappedLineParser &Parser,
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Format/UnwrappedLineParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,8 @@ struct UnwrappedLineNode {
SmallVector<UnwrappedLine, 0> Children;
};

std::ostream &operator<<(std::ostream &Stream, const UnwrappedLine &Line);

} // end namespace format
} // end namespace clang

Expand Down
18 changes: 15 additions & 3 deletions clang/lib/Format/WhitespaceManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ const tooling::Replacements &WhitespaceManager::generateReplacements() {
alignConsecutiveDeclarations();
alignConsecutiveBitFields();
alignConsecutiveAssignments();
if (Style.isTableGen())
alignConsecutiveTableGenCondOperatorColons();
alignChainedConditionals();
alignTrailingComments();
alignEscapedNewlines();
Expand Down Expand Up @@ -849,7 +851,12 @@ void WhitespaceManager::alignConsecutiveAssignments() {
}

void WhitespaceManager::alignConsecutiveBitFields() {
if (!Style.AlignConsecutiveBitFields.Enabled)
alignConsecutiveColons(Style.AlignConsecutiveBitFields, TT_BitFieldColon);
}

void WhitespaceManager::alignConsecutiveColons(
const FormatStyle::AlignConsecutiveStyle &AlignStyle, TokenType Type) {
if (!AlignStyle.Enabled)
return;

AlignTokens(
Expand All @@ -863,9 +870,9 @@ void WhitespaceManager::alignConsecutiveBitFields() {
if (&C != &Changes.back() && (&C + 1)->NewlinesBefore > 0)
return false;

return C.Tok->is(TT_BitFieldColon);
return C.Tok->is(Type);
},
Changes, /*StartAt=*/0, Style.AlignConsecutiveBitFields);
Changes, /*StartAt=*/0, AlignStyle);
}

void WhitespaceManager::alignConsecutiveShortCaseStatements() {
Expand Down Expand Up @@ -972,6 +979,11 @@ void WhitespaceManager::alignConsecutiveShortCaseStatements() {
Changes);
}

void WhitespaceManager::alignConsecutiveTableGenCondOperatorColons() {
alignConsecutiveColons(Style.AlignConsecutiveTableGenCondOperatorColons,
TT_TableGenCondOperatorColon);
}

void WhitespaceManager::alignConsecutiveDeclarations() {
if (!Style.AlignConsecutiveDeclarations.Enabled)
return;
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/Format/WhitespaceManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,11 @@ class WhitespaceManager {
/// Align consecutive bitfields over all \c Changes.
void alignConsecutiveBitFields();

/// Align consecutive colon. For bitfields, TableGen DAGArgs and defintions.
void
alignConsecutiveColons(const FormatStyle::AlignConsecutiveStyle &AlignStyle,
TokenType Type);

/// Align consecutive declarations over all \c Changes.
void alignConsecutiveDeclarations();

Expand All @@ -235,6 +240,9 @@ class WhitespaceManager {
/// Align consecutive short case statements over all \c Changes.
void alignConsecutiveShortCaseStatements();

/// Align consecutive TableGen cond operator colon over all \c Changes.
void alignConsecutiveTableGenCondOperatorColons();

/// Align trailing comments over all \c Changes.
void alignTrailingComments();

Expand Down
15 changes: 13 additions & 2 deletions clang/lib/Frontend/ASTUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,17 @@ class ASTInfoCollector : public ASTReaderListener {
if (InitializedLanguage)
return false;

// FIXME: We did similar things in ReadHeaderSearchOptions too. But such
// style is not scaling. Probably we need to invite some mechanism to
// handle such patterns generally.
auto PICLevel = LangOpt.PICLevel;
auto PIE = LangOpt.PIE;

LangOpt = LangOpts;

LangOpt.PICLevel = PICLevel;
LangOpt.PIE = PIE;

InitializedLanguage = true;

updated();
Expand Down Expand Up @@ -790,7 +800,8 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
const std::string &Filename, const PCHContainerReader &PCHContainerRdr,
WhatToLoad ToLoad, IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
const FileSystemOptions &FileSystemOpts,
std::shared_ptr<HeaderSearchOptions> HSOpts, bool OnlyLocalDecls,
std::shared_ptr<HeaderSearchOptions> HSOpts,
std::shared_ptr<LangOptions> LangOpts, bool OnlyLocalDecls,
CaptureDiagsKind CaptureDiagnostics, bool AllowASTWithCompilerErrors,
bool UserFilesAreVolatile, IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {
std::unique_ptr<ASTUnit> AST(new ASTUnit(true));
Expand All @@ -804,7 +815,7 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(

ConfigureDiags(Diags, *AST, CaptureDiagnostics);

AST->LangOpts = std::make_shared<LangOptions>();
AST->LangOpts = LangOpts ? LangOpts : std::make_shared<LangOptions>();
AST->OnlyLocalDecls = OnlyLocalDecls;
AST->CaptureDiagnostics = CaptureDiagnostics;
AST->Diagnostics = Diags;
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Frontend/FrontendAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -689,7 +689,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromASTFile(
std::string(InputFile), CI.getPCHContainerReader(),
ASTUnit::LoadEverything, Diags, CI.getFileSystemOpts(),
CI.getHeaderSearchOptsPtr());
CI.getHeaderSearchOptsPtr(), CI.getLangOptsPtr());

if (!AST)
return false;
Expand Down
8 changes: 4 additions & 4 deletions clang/lib/Headers/arm_acle.h
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ __qdbl(int32_t __t) {
}
#endif

/* 8.4.3 Accumultating multiplications */
/* 8.4.3 Accumulating multiplications */
#if defined(__ARM_FEATURE_DSP) && __ARM_FEATURE_DSP
static __inline__ int32_t __attribute__((__always_inline__, __nodebug__))
__smlabb(int32_t __a, int32_t __b, int32_t __c) {
Expand Down Expand Up @@ -545,7 +545,7 @@ __usub16(uint16x2_t __a, uint16x2_t __b) {
}
#endif

/* 8.5.10 Parallel 16-bit multiplications */
/* 8.5.10 Parallel 16-bit multiplication */
#if defined(__ARM_FEATURE_SIMD32) && __ARM_FEATURE_SIMD32
static __inline__ int32_t __attribute__((__always_inline__, __nodebug__))
__smlad(int16x2_t __a, int16x2_t __b, int32_t __c) {
Expand Down Expand Up @@ -748,7 +748,7 @@ __arm_st64bv0(void *__addr, data512_t __value) {
#define __arm_wsrf(sysreg, v) __arm_wsr(sysreg, __builtin_bit_cast(uint32_t, v))
#define __arm_wsrf64(sysreg, v) __arm_wsr64(sysreg, __builtin_bit_cast(uint64_t, v))

/* 10.3 Memory Tagging Extensions (MTE) Intrinsics */
/* 10.3 MTE intrinsics */
#if defined(__ARM_64BIT_STATE) && __ARM_64BIT_STATE
#define __arm_mte_create_random_tag(__ptr, __mask) __builtin_arm_irg(__ptr, __mask)
#define __arm_mte_increment_tag(__ptr, __tag_offset) __builtin_arm_addg(__ptr, __tag_offset)
Expand All @@ -757,7 +757,7 @@ __arm_st64bv0(void *__addr, data512_t __value) {
#define __arm_mte_set_tag(__ptr) __builtin_arm_stg(__ptr)
#define __arm_mte_ptrdiff(__ptra, __ptrb) __builtin_arm_subp(__ptra, __ptrb)

/* 18 Memory Operations Intrinsics */
/* 18 memcpy family of operations intrinsics - MOPS */
#define __arm_mops_memset_tag(__tagged_address, __value, __size) \
__builtin_arm_mops_memset_tag(__tagged_address, __value, __size)
#endif
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Headers/cpuid.h
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@
#define bit_PREFETCHI 0x00004000
#define bit_USERMSR 0x00008000
#define bit_AVX10 0x00080000
#define bit_APXF 0x00200000

/* Features in %eax for leaf 13 sub-leaf 1 */
#define bit_XSAVEOPT 0x00000001
Expand Down
98 changes: 98 additions & 0 deletions clang/lib/Headers/hlsl/hlsl_intrinsics.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,104 @@ double3 cos(double3);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_cos)
double4 cos(double4);

//===----------------------------------------------------------------------===//
// dot product builtins
//===----------------------------------------------------------------------===//

/// \fn K dot(T X, T Y)
/// \brief Return the dot product (a scalar value) of \a X and \a Y.
/// \param X The X input value.
/// \param Y The Y input value.

_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
half dot(half, half);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
half dot(half2, half2);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
half dot(half3, half3);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
half dot(half4, half4);

#ifdef __HLSL_ENABLE_16_BIT
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
int16_t dot(int16_t, int16_t);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
int16_t dot(int16_t2, int16_t2);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
int16_t dot(int16_t3, int16_t3);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
int16_t dot(int16_t4, int16_t4);

_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
uint16_t dot(uint16_t, uint16_t);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
uint16_t dot(uint16_t2, uint16_t2);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
uint16_t dot(uint16_t3, uint16_t3);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
uint16_t dot(uint16_t4, uint16_t4);
#endif

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
float dot(float, float);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
float dot(float2, float2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
float dot(float3, float3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
float dot(float4, float4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
double dot(double, double);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
int dot(int, int);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
int dot(int2, int2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
int dot(int3, int3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
int dot(int4, int4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
uint dot(uint, uint);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
uint dot(uint2, uint2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
uint dot(uint3, uint3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
uint dot(uint4, uint4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
int64_t dot(int64_t, int64_t);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
int64_t dot(int64_t2, int64_t2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
int64_t dot(int64_t3, int64_t3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
int64_t dot(int64_t4, int64_t4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
uint64_t dot(uint64_t, uint64_t);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
uint64_t dot(uint64_t2, uint64_t2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
uint64_t dot(uint64_t3, uint64_t3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
uint64_t dot(uint64_t4, uint64_t4);

//===----------------------------------------------------------------------===//
// floor builtins
//===----------------------------------------------------------------------===//
Expand Down
11 changes: 10 additions & 1 deletion clang/lib/Parse/ParseExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1385,6 +1385,16 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
Diag(RAngleLoc,
diag::err_lambda_template_parameter_list_empty);
} else {
// We increase the template depth before recursing into a requires-clause.
//
// This depth is used for setting up a LambdaScopeInfo (in
// Sema::RecordParsingTemplateParameterDepth), which is used later when
// inventing template parameters in InventTemplateParameter.
//
// This way, abbreviated generic lambdas could have different template
// depths, avoiding substitution into the wrong template parameters during
// constraint satisfaction check.
++CurTemplateDepthTracker;
ExprResult RequiresClause;
if (TryConsumeToken(tok::kw_requires)) {
RequiresClause =
Expand All @@ -1396,7 +1406,6 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(

Actions.ActOnLambdaExplicitTemplateParameterList(
Intro, LAngleLoc, TemplateParams, RAngleLoc, RequiresClause);
++CurTemplateDepthTracker;
}
}

Expand Down
17 changes: 17 additions & 0 deletions clang/lib/Parse/ParseOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,21 @@ bool doesDirectiveHaveAssociatedStmt(OpenACCDirectiveKind DirKind) {
llvm_unreachable("Unhandled directive->assoc stmt");
}

unsigned getOpenACCScopeFlags(OpenACCDirectiveKind DirKind) {
switch (DirKind) {
case OpenACCDirectiveKind::Parallel:
// Mark this as a BreakScope/ContinueScope as well as a compute construct
// so that we can diagnose trying to 'break'/'continue' inside of one.
return Scope::BreakScope | Scope::ContinueScope |
Scope::OpenACCComputeConstructScope;
case OpenACCDirectiveKind::Invalid:
llvm_unreachable("Shouldn't be creating a scope for an invalid construct");
default:
break;
}
return 0;
}

} // namespace

// OpenACC 3.3, section 1.7:
Expand Down Expand Up @@ -1228,6 +1243,8 @@ StmtResult Parser::ParseOpenACCDirectiveStmt() {

if (doesDirectiveHaveAssociatedStmt(DirInfo.DirKind)) {
ParsingOpenACCDirectiveRAII DirScope(*this, /*Value=*/false);
ParseScope ACCScope(this, getOpenACCScopeFlags(DirInfo.DirKind));

AssocStmt = getActions().ActOnOpenACCAssociatedStmt(DirInfo.DirKind,
ParseStatement());
}
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Sema/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ add_clang_library(clangSema
Sema.cpp
SemaAccess.cpp
SemaAttr.cpp
SemaAPINotes.cpp
SemaAvailability.cpp
SemaCXXScopeSpec.cpp
SemaCast.cpp
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Sema/Scope.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ void Scope::dumpImpl(raw_ostream &OS) const {
{CompoundStmtScope, "CompoundStmtScope"},
{ClassInheritanceScope, "ClassInheritanceScope"},
{CatchScope, "CatchScope"},
{OpenACCComputeConstructScope, "OpenACCComputeConstructScope"},
};

for (auto Info : FlagInfo) {
Expand Down
988 changes: 988 additions & 0 deletions clang/lib/Sema/SemaAPINotes.cpp

Large diffs are not rendered by default.

111 changes: 102 additions & 9 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2120,10 +2120,11 @@ bool Sema::CheckTSBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
// not a valid type, emit an error message and return true. Otherwise return
// false.
static bool checkMathBuiltinElementType(Sema &S, SourceLocation Loc,
QualType Ty) {
if (!Ty->getAs<VectorType>() && !ConstantMatrixType::isValidElementType(Ty)) {
QualType ArgTy, int ArgIndex) {
if (!ArgTy->getAs<VectorType>() &&
!ConstantMatrixType::isValidElementType(ArgTy)) {
return S.Diag(Loc, diag::err_builtin_invalid_arg_type)
<< 1 << /* vector, integer or float ty*/ 0 << Ty;
<< ArgIndex << /* vector, integer or float ty*/ 0 << ArgTy;
}

return false;
Expand Down Expand Up @@ -2165,7 +2166,10 @@ static bool SemaBuiltinCpu(Sema &S, const TargetInfo &TI, CallExpr *TheCall,
return S.Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported)
<< SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc());
if (!IsCPUSupports && !TheTI->supportsCpuIs())
return S.Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported)
return S.Diag(TheCall->getBeginLoc(),
TI.getTriple().isOSAIX()
? diag::err_builtin_aix_os_unsupported
: diag::err_builtin_target_unsupported)
<< SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc());

Expr *Arg = TheCall->getArg(0)->IgnoreParenImpCasts();
Expand Down Expand Up @@ -2958,6 +2962,9 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
}
}

if (getLangOpts().HLSL && CheckHLSLBuiltinFunctionCall(BuiltinID, TheCall))
return ExprError();

// Since the target specific builtins for each arch overlap, only check those
// of the arch we are compiling for.
if (Context.BuiltinInfo.isTSBuiltin(BuiltinID)) {
Expand Down Expand Up @@ -5158,6 +5165,70 @@ bool Sema::CheckPPCMMAType(QualType Type, SourceLocation TypeLoc) {
return false;
}

// Helper function for CheckHLSLBuiltinFunctionCall
bool CheckVectorElementCallArgs(Sema *S, CallExpr *TheCall) {
assert(TheCall->getNumArgs() > 1);
ExprResult A = TheCall->getArg(0);
ExprResult B = TheCall->getArg(1);
QualType ArgTyA = A.get()->getType();
QualType ArgTyB = B.get()->getType();
auto *VecTyA = ArgTyA->getAs<VectorType>();
auto *VecTyB = ArgTyB->getAs<VectorType>();
SourceLocation BuiltinLoc = TheCall->getBeginLoc();
if (VecTyA == nullptr && VecTyB == nullptr)
return false;

if (VecTyA && VecTyB) {
bool retValue = false;
if (VecTyA->getElementType() != VecTyB->getElementType()) {
// Note: type promotion is intended to be handeled via the intrinsics
// and not the builtin itself.
S->Diag(TheCall->getBeginLoc(), diag::err_vec_builtin_incompatible_vector)
<< TheCall->getDirectCallee()
<< SourceRange(A.get()->getBeginLoc(), B.get()->getEndLoc());
retValue = true;
}
if (VecTyA->getNumElements() != VecTyB->getNumElements()) {
// if we get here a HLSLVectorTruncation is needed.
S->Diag(BuiltinLoc, diag::err_vec_builtin_incompatible_vector)
<< TheCall->getDirectCallee()
<< SourceRange(TheCall->getArg(0)->getBeginLoc(),
TheCall->getArg(1)->getEndLoc());
retValue = true;
}

if (retValue)
TheCall->setType(VecTyA->getElementType());

return retValue;
}

// Note: if we get here one of the args is a scalar which
// requires a VectorSplat on Arg0 or Arg1
S->Diag(BuiltinLoc, diag::err_vec_builtin_non_vector)
<< TheCall->getDirectCallee()
<< SourceRange(TheCall->getArg(0)->getBeginLoc(),
TheCall->getArg(1)->getEndLoc());
return true;
}

// Note: returning true in this case results in CheckBuiltinFunctionCall
// returning an ExprError
bool Sema::CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
switch (BuiltinID) {
case Builtin::BI__builtin_hlsl_dot: {
if (checkArgCount(*this, TheCall, 2))
return true;
if (CheckVectorElementCallArgs(this, TheCall))
return true;
if (SemaBuiltinVectorToScalarMath(TheCall))
return true;
break;
}
}
return false;
}

bool Sema::CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID,
CallExpr *TheCall) {
// position of memory order and scope arguments in the builtin
Expand Down Expand Up @@ -19033,6 +19104,9 @@ static bool isLayoutCompatible(ASTContext &C, FieldDecl *Field1,
return false;
}

if (Field1->hasAttr<clang::NoUniqueAddressAttr>() ||
Field2->hasAttr<clang::NoUniqueAddressAttr>())
return false;
return true;
}

Expand Down Expand Up @@ -19588,23 +19662,43 @@ bool Sema::PrepareBuiltinElementwiseMathOneArgCall(CallExpr *TheCall) {
TheCall->setArg(0, A.get());
QualType TyA = A.get()->getType();

if (checkMathBuiltinElementType(*this, A.get()->getBeginLoc(), TyA))
if (checkMathBuiltinElementType(*this, A.get()->getBeginLoc(), TyA, 1))
return true;

TheCall->setType(TyA);
return false;
}

bool Sema::SemaBuiltinElementwiseMath(CallExpr *TheCall) {
QualType Res;
if (SemaBuiltinVectorMath(TheCall, Res))
return true;
TheCall->setType(Res);
return false;
}

bool Sema::SemaBuiltinVectorToScalarMath(CallExpr *TheCall) {
QualType Res;
if (SemaBuiltinVectorMath(TheCall, Res))
return true;

if (auto *VecTy0 = Res->getAs<VectorType>())
TheCall->setType(VecTy0->getElementType());
else
TheCall->setType(Res);

return false;
}

bool Sema::SemaBuiltinVectorMath(CallExpr *TheCall, QualType &Res) {
if (checkArgCount(*this, TheCall, 2))
return true;

ExprResult A = TheCall->getArg(0);
ExprResult B = TheCall->getArg(1);
// Do standard promotions between the two arguments, returning their common
// type.
QualType Res =
UsualArithmeticConversions(A, B, TheCall->getExprLoc(), ACK_Comparison);
Res = UsualArithmeticConversions(A, B, TheCall->getExprLoc(), ACK_Comparison);
if (A.isInvalid() || B.isInvalid())
return true;

Expand All @@ -19616,12 +19710,11 @@ bool Sema::SemaBuiltinElementwiseMath(CallExpr *TheCall) {
diag::err_typecheck_call_different_arg_types)
<< TyA << TyB;

if (checkMathBuiltinElementType(*this, A.get()->getBeginLoc(), TyA))
if (checkMathBuiltinElementType(*this, A.get()->getBeginLoc(), TyA, 1))
return true;

TheCall->setArg(0, A.get());
TheCall->setArg(1, B.get());
TheCall->setType(Res);
return false;
}

Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16424,6 +16424,7 @@ void Sema::ActOnFinishDelayedAttribute(Scope *S, Decl *D,
if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D))
D = TD->getTemplatedDecl();
ProcessDeclAttributeList(S, D, Attrs);
ProcessAPINotes(D);

if (CXXMethodDecl *Method = dyn_cast_or_null<CXXMethodDecl>(D))
if (Method->isStatic())
Expand Down Expand Up @@ -19683,6 +19684,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
CDecl->setIvarRBraceLoc(RBrac);
}
}
ProcessAPINotes(Record);
}

/// Determine whether the given integral value is representable within
Expand Down Expand Up @@ -19997,6 +19999,7 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst,
// Process attributes.
ProcessDeclAttributeList(S, New, Attrs);
AddPragmaAttributes(S, New);
ProcessAPINotes(New);

// Register this decl in the current scope stack.
New->setAccess(TheEnumDecl->getAccess());
Expand Down Expand Up @@ -20195,6 +20198,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
QualType EnumType = Context.getTypeDeclType(Enum);

ProcessDeclAttributeList(S, Enum, Attrs);
ProcessAPINotes(Enum);

if (Enum->isDependentType()) {
for (unsigned i = 0, e = Elements.size(); i != e; ++i) {
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10146,6 +10146,9 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) {

// Apply additional attributes specified by '#pragma clang attribute'.
AddPragmaAttributes(S, D);

// Look for API notes that map to attributes.
ProcessAPINotes(D);
}

/// Is the given declaration allowed to use a forbidden type?
Expand Down
6 changes: 5 additions & 1 deletion clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11724,6 +11724,7 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,

ProcessDeclAttributeList(DeclRegionScope, Namespc, AttrList);
AddPragmaAttributes(DeclRegionScope, Namespc);
ProcessAPINotes(Namespc);

// FIXME: Should we be merging attributes?
if (const VisibilityAttr *Attr = Namespc->getAttr<VisibilityAttr>())
Expand Down Expand Up @@ -12270,8 +12271,10 @@ Decl *Sema::ActOnUsingDirective(Scope *S, SourceLocation UsingLoc,
Diag(IdentLoc, diag::err_expected_namespace_name) << SS.getRange();
}

if (UDir)
if (UDir) {
ProcessDeclAttributeList(S, UDir, AttrList);
ProcessAPINotes(UDir);
}

return UDir;
}
Expand Down Expand Up @@ -13563,6 +13566,7 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, AccessSpecifier AS,

ProcessDeclAttributeList(S, NewTD, AttrList);
AddPragmaAttributes(S, NewTD);
ProcessAPINotes(NewTD);

CheckTypedefForVariablyModifiedType(S, NewTD);
Invalid |= NewTD->isInvalidDecl();
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Sema/SemaDeclObjC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1072,6 +1072,7 @@ ObjCInterfaceDecl *Sema::ActOnStartClassInterface(

ProcessDeclAttributeList(TUScope, IDecl, AttrList);
AddPragmaAttributes(TUScope, IDecl);
ProcessAPINotes(IDecl);

// Merge attributes from previous declarations.
if (PrevIDecl)
Expand Down Expand Up @@ -1273,6 +1274,7 @@ ObjCProtocolDecl *Sema::ActOnStartProtocolInterface(

ProcessDeclAttributeList(TUScope, PDecl, AttrList);
AddPragmaAttributes(TUScope, PDecl);
ProcessAPINotes(PDecl);

// Merge attributes from previous declarations.
if (PrevDecl)
Expand Down Expand Up @@ -4807,6 +4809,7 @@ Decl *Sema::ActOnMethodDeclaration(
// Apply the attributes to the parameter.
ProcessDeclAttributeList(TUScope, Param, ArgInfo[i].ArgAttrs);
AddPragmaAttributes(TUScope, Param);
ProcessAPINotes(Param);

if (Param->hasAttr<BlocksAttr>()) {
Diag(Param->getLocation(), diag::err_block_on_nonlocal);
Expand Down Expand Up @@ -4837,6 +4840,7 @@ Decl *Sema::ActOnMethodDeclaration(

ProcessDeclAttributeList(TUScope, ObjCMethod, AttrList);
AddPragmaAttributes(TUScope, ObjCMethod);
ProcessAPINotes(ObjCMethod);

// Add the method now.
const ObjCMethodDecl *PrevMethod = nullptr;
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Sema/SemaObjCProperty.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2509,6 +2509,8 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
GetterMethod->addAttr(SectionAttr::CreateImplicit(
Context, SA->getName(), Loc, SectionAttr::GNU_section));

ProcessAPINotes(GetterMethod);

if (getLangOpts().ObjCAutoRefCount)
CheckARCMethodDecl(GetterMethod);
} else
Expand Down Expand Up @@ -2578,6 +2580,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
if (const SectionAttr *SA = property->getAttr<SectionAttr>())
SetterMethod->addAttr(SectionAttr::CreateImplicit(
Context, SA->getName(), Loc, SectionAttr::GNU_section));

ProcessAPINotes(SetterMethod);

// It's possible for the user to have set a very odd custom
// setter selector that causes it to have a method family.
if (getLangOpts().ObjCAutoRefCount)
Expand Down
30 changes: 30 additions & 0 deletions clang/lib/Sema/SemaStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3356,6 +3356,15 @@ Sema::ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope) {
// initialization of that variable.
return StmtError(Diag(ContinueLoc, diag::err_continue_from_cond_var_init));
}

// A 'continue' that would normally have execution continue on a block outside
// of a compute construct counts as 'branching out of' the compute construct,
// so diagnose here.
if (S->isOpenACCComputeConstructScope())
return StmtError(
Diag(ContinueLoc, diag::err_acc_branch_in_out_compute_construct)
<< /*branch*/ 0 << /*out of */ 0);

CheckJumpOutOfSEHFinally(*this, ContinueLoc, *S);

return new (Context) ContinueStmt(ContinueLoc);
Expand All @@ -3371,6 +3380,21 @@ Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) {
if (S->isOpenMPLoopScope())
return StmtError(Diag(BreakLoc, diag::err_omp_loop_cannot_use_stmt)
<< "break");

// OpenACC doesn't allow 'break'ing from a compute construct, so diagnose if
// we are trying to do so. This can come in 2 flavors: 1-the break'able thing
// (besides the compute construct) 'contains' the compute construct, at which
// point the 'break' scope will be the compute construct. Else it could be a
// loop of some sort that has a direct parent of the compute construct.
// However, a 'break' in a 'switch' marked as a compute construct doesn't
// count as 'branch out of' the compute construct.
if (S->isOpenACCComputeConstructScope() ||
(S->isLoopScope() && S->getParent() &&
S->getParent()->isOpenACCComputeConstructScope()))
return StmtError(
Diag(BreakLoc, diag::err_acc_branch_in_out_compute_construct)
<< /*branch*/ 0 << /*out of */ 0);

CheckJumpOutOfSEHFinally(*this, BreakLoc, *S);

return new (Context) BreakStmt(BreakLoc);
Expand Down Expand Up @@ -3925,6 +3949,12 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp,
RetValExp, nullptr, /*RecoverUncorrectedTypos=*/true);
if (RetVal.isInvalid())
return StmtError();

if (getCurScope()->isInOpenACCComputeConstructScope())
return StmtError(
Diag(ReturnLoc, diag::err_acc_branch_in_out_compute_construct)
<< /*return*/ 1 << /*out of */ 0);

StmtResult R =
BuildReturnStmt(ReturnLoc, RetVal.get(), /*AllowRecovery=*/true);
if (R.isInvalid() || ExprEvalContexts.back().isDiscardedStatementContext())
Expand Down
59 changes: 49 additions & 10 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2158,6 +2158,7 @@ DeclResult Sema::CheckClassTemplate(
NewClass->startDefinition();

ProcessDeclAttributeList(S, NewClass, Attr);
ProcessAPINotes(NewClass);

if (PrevClassTemplate)
mergeDeclAttributes(NewClass, PrevClassTemplate->getTemplatedDecl());
Expand Down Expand Up @@ -4958,11 +4959,10 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
return Decl;
}

ExprResult
Sema::CheckVarTemplateId(const CXXScopeSpec &SS,
const DeclarationNameInfo &NameInfo,
VarTemplateDecl *Template, SourceLocation TemplateLoc,
const TemplateArgumentListInfo *TemplateArgs) {
ExprResult Sema::CheckVarTemplateId(
const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo,
VarTemplateDecl *Template, NamedDecl *FoundD, SourceLocation TemplateLoc,
const TemplateArgumentListInfo *TemplateArgs) {

DeclResult Decl = CheckVarTemplateId(Template, TemplateLoc, NameInfo.getLoc(),
*TemplateArgs);
Expand All @@ -4978,8 +4978,7 @@ Sema::CheckVarTemplateId(const CXXScopeSpec &SS,
NameInfo.getLoc());

// Build an ordinary singleton decl ref.
return BuildDeclarationNameExpr(SS, NameInfo, Var,
/*FoundD=*/nullptr, TemplateArgs);
return BuildDeclarationNameExpr(SS, NameInfo, Var, FoundD, TemplateArgs);
}

void Sema::diagnoseMissingTemplateArguments(TemplateName Name,
Expand Down Expand Up @@ -5066,9 +5065,9 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
bool KnownDependent = false;
// In C++1y, check variable template ids.
if (R.getAsSingle<VarTemplateDecl>()) {
ExprResult Res = CheckVarTemplateId(SS, R.getLookupNameInfo(),
R.getAsSingle<VarTemplateDecl>(),
TemplateKWLoc, TemplateArgs);
ExprResult Res = CheckVarTemplateId(
SS, R.getLookupNameInfo(), R.getAsSingle<VarTemplateDecl>(),
R.getRepresentativeDecl(), TemplateKWLoc, TemplateArgs);
if (Res.isInvalid() || Res.isUsable())
return Res;
// Result is dependent. Carry on to build an UnresolvedLookupEpxr.
Expand Down Expand Up @@ -9114,6 +9113,7 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
}

ProcessDeclAttributeList(S, Specialization, Attr);
ProcessAPINotes(Specialization);

// Add alignment attributes if necessary; these attributes are checked when
// the ASTContext lays out the structure.
Expand Down Expand Up @@ -9709,6 +9709,40 @@ bool Sema::CheckFunctionTemplateSpecialization(
// Ignore access information; it doesn't figure into redeclaration checking.
FunctionDecl *Specialization = cast<FunctionDecl>(*Result);

// C++23 [except.spec]p13:
// An exception specification is considered to be needed when:
// - [...]
// - the exception specification is compared to that of another declaration
// (e.g., an explicit specialization or an overriding virtual function);
// - [...]
//
// The exception specification of a defaulted function is evaluated as
// described above only when needed; similarly, the noexcept-specifier of a
// specialization of a function template or member function of a class
// template is instantiated only when needed.
//
// The standard doesn't specify what the "comparison with another declaration"
// entails, nor the exact circumstances in which it occurs. Moreover, it does
// not state which properties of an explicit specialization must match the
// primary template.
//
// We assume that an explicit specialization must correspond with (per
// [basic.scope.scope]p4) and declare the same entity as (per [basic.link]p8)
// the declaration produced by substitution into the function template.
//
// Since the determination whether two function declarations correspond does
// not consider exception specification, we only need to instantiate it once
// we determine the primary template when comparing types per
// [basic.link]p11.1.
auto *SpecializationFPT =
Specialization->getType()->castAs<FunctionProtoType>();
// If the function has a dependent exception specification, resolve it after
// we have selected the primary template so we can check whether it matches.
if (getLangOpts().CPlusPlus17 &&
isUnresolvedExceptionSpec(SpecializationFPT->getExceptionSpecType()) &&
!ResolveExceptionSpec(FD->getLocation(), SpecializationFPT))
return true;

FunctionTemplateSpecializationInfo *SpecInfo
= Specialization->getTemplateSpecializationInfo();
assert(SpecInfo && "Function template specialization info missing?");
Expand Down Expand Up @@ -10348,6 +10382,7 @@ DeclResult Sema::ActOnExplicitInstantiation(

bool PreviouslyDLLExported = Specialization->hasAttr<DLLExportAttr>();
ProcessDeclAttributeList(S, Specialization, Attr);
ProcessAPINotes(Specialization);

// Add the explicit instantiation into its lexical context. However,
// since explicit instantiations are never found by name lookup, we
Expand Down Expand Up @@ -10758,6 +10793,9 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
Prev->setTemplateSpecializationKind(TSK, D.getIdentifierLoc());
// Merge attributes.
ProcessDeclAttributeList(S, Prev, D.getDeclSpec().getAttributes());
if (PrevTemplate)
ProcessAPINotes(Prev);

if (TSK == TSK_ExplicitInstantiationDefinition)
InstantiateVariableDefinition(D.getIdentifierLoc(), Prev);
}
Expand Down Expand Up @@ -10933,6 +10971,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
}

ProcessDeclAttributeList(S, Specialization, D.getDeclSpec().getAttributes());
ProcessAPINotes(Specialization);

// In MSVC mode, dllimported explicit instantiation definitions are treated as
// instantiation declarations.
Expand Down
14 changes: 6 additions & 8 deletions clang/lib/Sema/SemaTemplateDeduction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4632,11 +4632,9 @@ TemplateDeductionResult Sema::DeduceTemplateArguments(
Info.getLocation()))
return TemplateDeductionResult::MiscellaneousDeductionFailure;

// If the function has a dependent exception specification, resolve it now,
// so we can check that the exception specification matches.
auto *SpecializationFPT =
Specialization->getType()->castAs<FunctionProtoType>();
if (getLangOpts().CPlusPlus17 &&
if (IsAddressOfFunction && getLangOpts().CPlusPlus17 &&
isUnresolvedExceptionSpec(SpecializationFPT->getExceptionSpecType()) &&
!ResolveExceptionSpec(Info.getLocation(), SpecializationFPT))
return TemplateDeductionResult::MiscellaneousDeductionFailure;
Expand All @@ -4662,11 +4660,11 @@ TemplateDeductionResult Sema::DeduceTemplateArguments(
// specialization with respect to arguments of compatible pointer to function
// types, template argument deduction fails.
if (!ArgFunctionType.isNull()) {
if (IsAddressOfFunction
? !isSameOrCompatibleFunctionType(
Context.getCanonicalType(SpecializationType),
Context.getCanonicalType(ArgFunctionType))
: !Context.hasSameType(SpecializationType, ArgFunctionType)) {
if (IsAddressOfFunction ? !isSameOrCompatibleFunctionType(
Context.getCanonicalType(SpecializationType),
Context.getCanonicalType(ArgFunctionType))
: !Context.hasSameFunctionTypeIgnoringExceptionSpec(
SpecializationType, ArgFunctionType)) {
Info.FirstArg = TemplateArgument(SpecializationType);
Info.SecondArg = TemplateArgument(ArgFunctionType);
return TemplateDeductionResult::NonDeducedMismatch;
Expand Down
42 changes: 33 additions & 9 deletions clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,16 @@ getSimplifiedOffsets(NonLoc offset, nonloc::ConcreteInt extent,
return std::pair<NonLoc, nonloc::ConcreteInt>(offset, extent);
}

static bool isNegative(SValBuilder &SVB, ProgramStateRef State, NonLoc Value) {
const llvm::APSInt *MaxV = SVB.getMaxValue(State, Value);
return MaxV && MaxV->isNegative();
}

static bool isUnsigned(SValBuilder &SVB, NonLoc Value) {
QualType T = Value.getType(SVB.getContext());
return T->isUnsignedIntegerType();
}

// Evaluate the comparison Value < Threshold with the help of the custom
// simplification algorithm defined for this checker. Return a pair of states,
// where the first one corresponds to "value below threshold" and the second
Expand All @@ -281,18 +291,32 @@ compareValueToThreshold(ProgramStateRef State, NonLoc Value, NonLoc Threshold,
if (auto ConcreteThreshold = Threshold.getAs<nonloc::ConcreteInt>()) {
std::tie(Value, Threshold) = getSimplifiedOffsets(Value, *ConcreteThreshold, SVB);
}
if (auto ConcreteThreshold = Threshold.getAs<nonloc::ConcreteInt>()) {
QualType T = Value.getType(SVB.getContext());
if (T->isUnsignedIntegerType() && ConcreteThreshold->getValue().isNegative()) {
// In this case we reduced the bound check to a comparison of the form
// (symbol or value with unsigned type) < (negative number)
// which is always false. We are handling these cases separately because
// evalBinOpNN can perform a signed->unsigned conversion that turns the
// negative number into a huge positive value and leads to wildly
// inaccurate conclusions.

// We want to perform a _mathematical_ comparison between the numbers `Value`
// and `Threshold`; but `evalBinOpNN` evaluates a C/C++ operator that may
// perform automatic conversions. For example the number -1 is less than the
// number 1000, but -1 < `1000ull` will evaluate to `false` because the `int`
// -1 is converted to ULONGLONG_MAX.
// To avoid automatic conversions, we evaluate the "obvious" cases without
// calling `evalBinOpNN`:
if (isNegative(SVB, State, Value) && isUnsigned(SVB, Threshold)) {
if (CheckEquality) {
// negative_value == unsigned_value is always false
return {nullptr, State};
}
// negative_value < unsigned_value is always false
return {State, nullptr};
}
if (isUnsigned(SVB, Value) && isNegative(SVB, State, Threshold)) {
// unsigned_value == negative_value and unsigned_value < negative_value are
// both always false
return {nullptr, State};
}
// FIXME: these special cases are sufficient for handling real-world
// comparisons, but in theory there could be contrived situations where
// automatic conversion of a symbolic value (which can be negative and can be
// positive) leads to incorrect results.

const BinaryOperatorKind OpKind = CheckEquality ? BO_EQ : BO_LT;
auto BelowThreshold =
SVB.evalBinOpNN(State, OpKind, Value, Threshold, SVB.getConditionType())
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/StaticAnalyzer/Checkers/ErrnoChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
Expand Down
Loading