72 changes: 53 additions & 19 deletions bolt/lib/Profile/StaleProfileMatching.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ cl::opt<bool>
cl::desc("Infer counts from stale profile data."),
cl::init(false), cl::Hidden, cl::cat(BoltOptCategory));

cl::opt<unsigned> StaleMatchingMinMatchedBlock(
"stale-matching-min-matched-block",
cl::desc("Percentage threshold of matched basic blocks at which stale "
"profile inference is executed."),
cl::init(0), cl::Hidden, cl::cat(BoltOptCategory));

cl::opt<unsigned> StaleMatchingMaxFuncSize(
"stale-matching-max-func-size",
cl::desc("The maximum size of a function to consider for inference."),
Expand Down Expand Up @@ -301,21 +307,21 @@ void BinaryFunction::computeBlockHashes(HashFunction HashFunction) const {
BB->setHash(BlendedHashes[I].combine());
}
}

// TODO: mediate the difference between flow function construction here in BOLT
// and in the compiler by splitting blocks with exception throwing calls at the
// call and adding the landing pad as the successor.
/// Create a wrapper flow function to use with the profile inference algorithm,
/// and initialize its jumps and metadata.
FlowFunction
createFlowFunction(const BinaryFunction::BasicBlockOrderType &BlockOrder) {
FlowFunction Func;

// Add a special "dummy" source so that there is always a unique entry point.
// Because of the extra source, for all other blocks in FlowFunction it holds
// that Block.Index == BB->getIndex() + 1
FlowBlock EntryBlock;
EntryBlock.Index = 0;
Func.Blocks.push_back(EntryBlock);

// Create FlowBlock for every basic block in the binary function
// Create FlowBlock for every basic block in the binary function.
for (const BinaryBasicBlock *BB : BlockOrder) {
Func.Blocks.emplace_back();
FlowBlock &Block = Func.Blocks.back();
Expand All @@ -325,7 +331,12 @@ createFlowFunction(const BinaryFunction::BasicBlockOrderType &BlockOrder) {
"incorrectly assigned basic block index");
}

// Create FlowJump for each jump between basic blocks in the binary function
// Add a special "dummy" sink block so there is always a unique sink.
FlowBlock SinkBlock;
SinkBlock.Index = Func.Blocks.size();
Func.Blocks.push_back(SinkBlock);

// Create FlowJump for each jump between basic blocks in the binary function.
std::vector<uint64_t> InDegree(Func.Blocks.size(), 0);
for (const BinaryBasicBlock *SrcBB : BlockOrder) {
std::unordered_set<const BinaryBasicBlock *> UniqueSuccs;
Expand All @@ -342,6 +353,16 @@ createFlowFunction(const BinaryFunction::BasicBlockOrderType &BlockOrder) {
InDegree[Jump.Target]++;
UniqueSuccs.insert(DstBB);
}
// TODO: set jump from exit block to landing pad to Unlikely.
// If the block is an exit, add a dummy edge from it to the sink block.
if (UniqueSuccs.empty()) {
Func.Jumps.emplace_back();
FlowJump &Jump = Func.Jumps.back();
Jump.Source = SrcBB->getIndex() + 1;
Jump.Target = Func.Blocks.size() - 1;
InDegree[Jump.Target]++;
}

// Collect jumps to landing pads
for (const BinaryBasicBlock *DstBB : SrcBB->landing_pads()) {
// Ignoring parallel edges
Expand All @@ -358,9 +379,9 @@ createFlowFunction(const BinaryFunction::BasicBlockOrderType &BlockOrder) {
}

// Add dummy edges to the extra sources. If there are multiple entry blocks,
// add an unlikely edge from 0 to the subsequent ones
// add an unlikely edge from 0 to the subsequent ones. Skips the sink block.
assert(InDegree[0] == 0 && "dummy entry blocks shouldn't have predecessors");
for (uint64_t I = 1; I < Func.Blocks.size(); I++) {
for (uint64_t I = 1; I < Func.Blocks.size() - 1; I++) {
const BinaryBasicBlock *BB = BlockOrder[I - 1];
if (BB->isEntryPoint() || InDegree[I] == 0) {
Func.Jumps.emplace_back();
Expand Down Expand Up @@ -391,11 +412,10 @@ createFlowFunction(const BinaryFunction::BasicBlockOrderType &BlockOrder) {
/// of the basic blocks in the binary, the count is "matched" to the block.
/// Similarly, if both the source and the target of a count in the profile are
/// matched to a jump in the binary, the count is recorded in CFG.
void matchWeightsByHashes(BinaryContext &BC,
const BinaryFunction::BasicBlockOrderType &BlockOrder,
const yaml::bolt::BinaryFunctionProfile &YamlBF,
FlowFunction &Func) {
assert(Func.Blocks.size() == BlockOrder.size() + 1);
size_t matchWeightsByHashes(
BinaryContext &BC, const BinaryFunction::BasicBlockOrderType &BlockOrder,
const yaml::bolt::BinaryFunctionProfile &YamlBF, FlowFunction &Func) {
assert(Func.Blocks.size() == BlockOrder.size() + 2);

std::vector<FlowBlock *> Blocks;
std::vector<BlendedBlockHash> BlendedHashes;
Expand Down Expand Up @@ -500,6 +520,8 @@ void matchWeightsByHashes(BinaryContext &BC,
Block.HasUnknownWeight = false;
Block.Weight = std::max(OutWeight[Block.Index], InWeight[Block.Index]);
}

return MatchedBlocks.size();
}

/// The function finds all blocks that are (i) reachable from the Entry block
Expand Down Expand Up @@ -575,13 +597,19 @@ void preprocessUnreachableBlocks(FlowFunction &Func) {
/// Decide if stale profile matching can be applied for a given function.
/// Currently we skip inference for (very) large instances and for instances
/// having "unexpected" control flow (e.g., having no sink basic blocks).
bool canApplyInference(const FlowFunction &Func) {
bool canApplyInference(const FlowFunction &Func,
const yaml::bolt::BinaryFunctionProfile &YamlBF,
const uint64_t &MatchedBlocks) {
if (Func.Blocks.size() > opts::StaleMatchingMaxFuncSize)
return false;

bool HasExitBlocks = llvm::any_of(
Func.Blocks, [&](const FlowBlock &Block) { return Block.isExit(); });
if (!HasExitBlocks)
if (MatchedBlocks * 100 <
opts::StaleMatchingMinMatchedBlock * YamlBF.Blocks.size())
return false;

// Returns false if the artificial sink block has no predecessors meaning
// there are no exit blocks.
if (Func.Blocks[Func.Blocks.size() - 1].isEntry())
return false;

return true;
Expand Down Expand Up @@ -618,7 +646,7 @@ void assignProfile(BinaryFunction &BF,
FlowFunction &Func) {
BinaryContext &BC = BF.getBinaryContext();

assert(Func.Blocks.size() == BlockOrder.size() + 1);
assert(Func.Blocks.size() == BlockOrder.size() + 2);
for (uint64_t I = 0; I < BlockOrder.size(); I++) {
FlowBlock &Block = Func.Blocks[I + 1];
BinaryBasicBlock *BB = BlockOrder[I];
Expand All @@ -640,6 +668,9 @@ void assignProfile(BinaryFunction &BF,
if (Jump->Flow == 0)
continue;

// Skips the artificial sink block.
if (Jump->Target == Func.Blocks.size() - 1)
continue;
BinaryBasicBlock &SuccBB = *BlockOrder[Jump->Target - 1];
// Check if the edge corresponds to a regular jump or a landing pad
if (BB->getSuccessor(SuccBB.getLabel())) {
Expand Down Expand Up @@ -725,18 +756,21 @@ bool YAMLProfileReader::inferStaleProfile(
const BinaryFunction::BasicBlockOrderType BlockOrder(
BF.getLayout().block_begin(), BF.getLayout().block_end());

// Tracks the number of matched blocks.

// Create a wrapper flow function to use with the profile inference algorithm.
FlowFunction Func = createFlowFunction(BlockOrder);

// Match as many block/jump counts from the stale profile as possible
matchWeightsByHashes(BF.getBinaryContext(), BlockOrder, YamlBF, Func);
size_t MatchedBlocks =
matchWeightsByHashes(BF.getBinaryContext(), BlockOrder, YamlBF, Func);

// Adjust the flow function by marking unreachable blocks Unlikely so that
// they don't get any counts assigned.
preprocessUnreachableBlocks(Func);

// Check if profile inference can be applied for the instance.
if (!canApplyInference(Func))
if (!canApplyInference(Func, YamlBF, MatchedBlocks))
return false;

// Apply the profile inference algorithm.
Expand Down
171 changes: 0 additions & 171 deletions bolt/lib/Rewrite/DWARFRewriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2060,177 +2060,6 @@ void DWARFRewriter::writeDWOFiles(
TempOut->keep();
}

void DWARFRewriter::addGDBTypeUnitEntry(const GDBIndexTUEntry &&Entry) {
std::lock_guard<std::mutex> Lock(DWARFRewriterMutex);
if (!BC.getGdbIndexSection())
return;
GDBIndexTUEntryVector.emplace_back(Entry);
}

void DWARFRewriter::updateGdbIndexSection(CUOffsetMap &CUMap, uint32_t NumCUs) {
if (!BC.getGdbIndexSection())
return;

// See https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html
// for .gdb_index section format.

StringRef GdbIndexContents = BC.getGdbIndexSection()->getContents();

const char *Data = GdbIndexContents.data();

// Parse the header.
const uint32_t Version = read32le(Data);
if (Version != 7 && Version != 8) {
errs() << "BOLT-ERROR: can only process .gdb_index versions 7 and 8\n";
exit(1);
}

// Some .gdb_index generators use file offsets while others use section
// offsets. Hence we can only rely on offsets relative to each other,
// and ignore their absolute values.
const uint32_t CUListOffset = read32le(Data + 4);
const uint32_t CUTypesOffset = read32le(Data + 8);
const uint32_t AddressTableOffset = read32le(Data + 12);
const uint32_t SymbolTableOffset = read32le(Data + 16);
const uint32_t ConstantPoolOffset = read32le(Data + 20);
Data += 24;

// Map CUs offsets to indices and verify existing index table.
std::map<uint32_t, uint32_t> OffsetToIndexMap;
const uint32_t CUListSize = CUTypesOffset - CUListOffset;
const uint32_t TUListSize = AddressTableOffset - CUTypesOffset;
const unsigned NUmCUsEncoded = CUListSize / 16;
unsigned MaxDWARFVersion = BC.DwCtx->getMaxVersion();
unsigned NumDWARF5TUs =
getGDBIndexTUEntryVector().size() - BC.DwCtx->getNumTypeUnits();
bool SkipTypeUnits = false;
// For DWARF5 Types are in .debug_info.
// LLD doesn't generate Types CU List, and in CU list offset
// only includes CUs.
// GDB 11+ includes only CUs in CU list and generates Types
// list.
// GDB 9 includes CUs and TUs in CU list and generates TYpes
// list. The NumCUs is CUs + TUs, so need to modify the check.
// For split-dwarf
// GDB-11, DWARF5: TU units from dwo are not included.
// GDB-11, DWARF4: TU units from dwo are included.
if (MaxDWARFVersion >= 5)
SkipTypeUnits = !TUListSize ? true
: ((NUmCUsEncoded + NumDWARF5TUs) ==
BC.DwCtx->getNumCompileUnits());

if (!((CUListSize == NumCUs * 16) ||
(CUListSize == (NumCUs + NumDWARF5TUs) * 16))) {
errs() << "BOLT-ERROR: .gdb_index: CU count mismatch\n";
exit(1);
}
DenseSet<uint64_t> OriginalOffsets;
for (unsigned Index = 0, Units = BC.DwCtx->getNumCompileUnits();
Index < Units; ++Index) {
const DWARFUnit *CU = BC.DwCtx->getUnitAtIndex(Index);
if (SkipTypeUnits && CU->isTypeUnit())
continue;
const uint64_t Offset = read64le(Data);
Data += 16;
if (CU->getOffset() != Offset) {
errs() << "BOLT-ERROR: .gdb_index CU offset mismatch\n";
exit(1);
}

OriginalOffsets.insert(Offset);
OffsetToIndexMap[Offset] = Index;
}

// Ignore old address table.
const uint32_t OldAddressTableSize = SymbolTableOffset - AddressTableOffset;
// Move Data to the beginning of symbol table.
Data += SymbolTableOffset - CUTypesOffset;

// Calculate the size of the new address table.
uint32_t NewAddressTableSize = 0;
for (const auto &CURangesPair : ARangesSectionWriter->getCUAddressRanges()) {
const SmallVector<DebugAddressRange, 2> &Ranges = CURangesPair.second;
NewAddressTableSize += Ranges.size() * 20;
}

// Difference between old and new table (and section) sizes.
// Could be negative.
int32_t Delta = NewAddressTableSize - OldAddressTableSize;

size_t NewGdbIndexSize = GdbIndexContents.size() + Delta;

// Free'd by ExecutableFileMemoryManager.
auto *NewGdbIndexContents = new uint8_t[NewGdbIndexSize];
uint8_t *Buffer = NewGdbIndexContents;

write32le(Buffer, Version);
write32le(Buffer + 4, CUListOffset);
write32le(Buffer + 8, CUTypesOffset);
write32le(Buffer + 12, AddressTableOffset);
write32le(Buffer + 16, SymbolTableOffset + Delta);
write32le(Buffer + 20, ConstantPoolOffset + Delta);
Buffer += 24;

using MapEntry = std::pair<uint32_t, CUInfo>;
std::vector<MapEntry> CUVector(CUMap.begin(), CUMap.end());
// Need to sort since we write out all of TUs in .debug_info before CUs.
std::sort(CUVector.begin(), CUVector.end(),
[](const MapEntry &E1, const MapEntry &E2) -> bool {
return E1.second.Offset < E2.second.Offset;
});
// Writing out CU List <Offset, Size>
for (auto &CUInfo : CUVector) {
// Skipping TU for DWARF5 when they are not included in CU list.
if (!OriginalOffsets.count(CUInfo.first))
continue;
write64le(Buffer, CUInfo.second.Offset);
// Length encoded in CU doesn't contain first 4 bytes that encode length.
write64le(Buffer + 8, CUInfo.second.Length + 4);
Buffer += 16;
}

// Rewrite TU CU List, since abbrevs can be different.
// Entry example:
// 0: offset = 0x00000000, type_offset = 0x0000001e, type_signature =
// 0x418503b8111e9a7b Spec says " triplet, the first value is the CU offset,
// the second value is the type offset in the CU, and the third value is the
// type signature" Looking at what is being generated by gdb-add-index. The
// first entry is TU offset, second entry is offset from it, and third entry
// is the type signature.
if (TUListSize)
for (const GDBIndexTUEntry &Entry : getGDBIndexTUEntryVector()) {
write64le(Buffer, Entry.UnitOffset);
write64le(Buffer + 8, Entry.TypeDIERelativeOffset);
write64le(Buffer + 16, Entry.TypeHash);
Buffer += sizeof(GDBIndexTUEntry);
}

// Generate new address table.
for (const std::pair<const uint64_t, DebugAddressRangesVector> &CURangesPair :
ARangesSectionWriter->getCUAddressRanges()) {
const uint32_t CUIndex = OffsetToIndexMap[CURangesPair.first];
const DebugAddressRangesVector &Ranges = CURangesPair.second;
for (const DebugAddressRange &Range : Ranges) {
write64le(Buffer, Range.LowPC);
write64le(Buffer + 8, Range.HighPC);
write32le(Buffer + 16, CUIndex);
Buffer += 20;
}
}

const size_t TrailingSize =
GdbIndexContents.data() + GdbIndexContents.size() - Data;
assert(Buffer + TrailingSize == NewGdbIndexContents + NewGdbIndexSize &&
"size calculation error");

// Copy over the rest of the original data.
memcpy(Buffer, Data, TrailingSize);

// Register the new section.
BC.registerOrUpdateNoteSection(".gdb_index", NewGdbIndexContents,
NewGdbIndexSize);
}

std::unique_ptr<DebugBufferVector>
DWARFRewriter::makeFinalLocListsSection(DWARFVersion Version) {
auto LocBuffer = std::make_unique<DebugBufferVector>();
Expand Down
77 changes: 70 additions & 7 deletions bolt/lib/Rewrite/LinuxKernelRewriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,8 @@ class LinuxKernelRewriter final : public MetadataRewriter {

/// Handle alternative instruction info from .altinstructions.
Error readAltInstructions();
Error tryReadAltInstructions(uint32_t AltInstFeatureSize,
bool AltInstHasPadLen, bool ParseOnly);
Error rewriteAltInstructions();

/// Read .pci_fixup
Expand Down Expand Up @@ -1319,12 +1321,69 @@ Error LinuxKernelRewriter::rewriteBugTable() {
/// u8 padlen; // present in older kernels
/// } __packed;
///
/// Note the structures is packed.
/// Note that the structure is packed.
///
/// Since the size of the "feature" field could be either u16 or u32, and
/// "padlen" presence is unknown, we attempt to parse .altinstructions section
/// using all possible combinations (four at this time). Since we validate the
/// contents of the section and its size, the detection works quite well.
/// Still, we leave the user the opportunity to specify these features on the
/// command line and skip the guesswork.
Error LinuxKernelRewriter::readAltInstructions() {
AltInstrSection = BC.getUniqueSectionByName(".altinstructions");
if (!AltInstrSection)
return Error::success();

// Presence of "padlen" field.
std::vector<bool> PadLenVariants;
if (opts::AltInstHasPadLen.getNumOccurrences())
PadLenVariants.push_back(opts::AltInstHasPadLen);
else
PadLenVariants = {false, true};

// Size (in bytes) variants of "feature" field.
std::vector<uint32_t> FeatureSizeVariants;
if (opts::AltInstFeatureSize.getNumOccurrences())
FeatureSizeVariants.push_back(opts::AltInstFeatureSize);
else
FeatureSizeVariants = {2, 4};

for (bool AltInstHasPadLen : PadLenVariants) {
for (uint32_t AltInstFeatureSize : FeatureSizeVariants) {
LLVM_DEBUG({
dbgs() << "BOLT-DEBUG: trying AltInstHasPadLen = " << AltInstHasPadLen
<< "; AltInstFeatureSize = " << AltInstFeatureSize << ";\n";
});
if (Error E = tryReadAltInstructions(AltInstFeatureSize, AltInstHasPadLen,
/*ParseOnly*/ true)) {
consumeError(std::move(E));
continue;
}

LLVM_DEBUG(dbgs() << "Matched .altinstructions format\n");

if (!opts::AltInstHasPadLen.getNumOccurrences())
BC.outs() << "BOLT-INFO: setting --" << opts::AltInstHasPadLen.ArgStr
<< '=' << AltInstHasPadLen << '\n';

if (!opts::AltInstFeatureSize.getNumOccurrences())
BC.outs() << "BOLT-INFO: setting --" << opts::AltInstFeatureSize.ArgStr
<< '=' << AltInstFeatureSize << '\n';

return tryReadAltInstructions(AltInstFeatureSize, AltInstHasPadLen,
/*ParseOnly*/ false);
}
}

// We couldn't match the format. Read again to properly propagate the error
// to the user.
return tryReadAltInstructions(opts::AltInstFeatureSize,
opts::AltInstHasPadLen, /*ParseOnly*/ false);
}

Error LinuxKernelRewriter::tryReadAltInstructions(uint32_t AltInstFeatureSize,
bool AltInstHasPadLen,
bool ParseOnly) {
const uint64_t Address = AltInstrSection->getAddress();
DataExtractor DE = DataExtractor(AltInstrSection->getContents(),
BC.AsmInfo->isLittleEndian(),
Expand All @@ -1336,12 +1395,12 @@ Error LinuxKernelRewriter::readAltInstructions() {
Address + Cursor.tell() + (int32_t)DE.getU32(Cursor);
const uint64_t AltInstAddress =
Address + Cursor.tell() + (int32_t)DE.getU32(Cursor);
const uint64_t Feature = DE.getUnsigned(Cursor, opts::AltInstFeatureSize);
const uint64_t Feature = DE.getUnsigned(Cursor, AltInstFeatureSize);
const uint8_t OrgSize = DE.getU8(Cursor);
const uint8_t AltSize = DE.getU8(Cursor);

// Older kernels may have the padlen field.
const uint8_t PadLen = opts::AltInstHasPadLen ? DE.getU8(Cursor) : 0;
const uint8_t PadLen = AltInstHasPadLen ? DE.getU8(Cursor) : 0;

if (!Cursor)
return createStringError(
Expand All @@ -1358,7 +1417,7 @@ Error LinuxKernelRewriter::readAltInstructions() {
<< "\n\tFeature: 0x" << Twine::utohexstr(Feature)
<< "\n\tOrgSize: " << (int)OrgSize
<< "\n\tAltSize: " << (int)AltSize << '\n';
if (opts::AltInstHasPadLen)
if (AltInstHasPadLen)
BC.outs() << "\tPadLen: " << (int)PadLen << '\n';
}

Expand All @@ -1375,7 +1434,7 @@ Error LinuxKernelRewriter::readAltInstructions() {

BinaryFunction *AltBF =
BC.getBinaryFunctionContainingAddress(AltInstAddress);
if (AltBF && BC.shouldEmit(*AltBF)) {
if (!ParseOnly && AltBF && BC.shouldEmit(*AltBF)) {
BC.errs()
<< "BOLT-WARNING: alternative instruction sequence found in function "
<< *AltBF << '\n';
Expand All @@ -1397,6 +1456,9 @@ Error LinuxKernelRewriter::readAltInstructions() {
" referenced by .altinstructions entry %d",
OrgInstAddress, EntryID);

if (ParseOnly)
continue;

// There could be more than one alternative instruction sequences for the
// same original instruction. Annotate each alternative separately.
std::string AnnotationName = "AltInst";
Expand All @@ -1417,8 +1479,9 @@ Error LinuxKernelRewriter::readAltInstructions() {
}
}

BC.outs() << "BOLT-INFO: parsed " << EntryID
<< " alternative instruction entries\n";
if (!ParseOnly)
BC.outs() << "BOLT-INFO: parsed " << EntryID
<< " alternative instruction entries\n";

return Error::success();
}
Expand Down
41 changes: 41 additions & 0 deletions bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1054,6 +1054,47 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
return true;
}

InstructionListType createIndirectPltCall(const MCInst &DirectCall,
const MCSymbol *TargetLocation,
MCContext *Ctx) override {
const bool IsTailCall = isTailCall(DirectCall);
assert((DirectCall.getOpcode() == AArch64::BL ||
(DirectCall.getOpcode() == AArch64::B && IsTailCall)) &&
"64-bit direct (tail) call instruction expected");

InstructionListType Code;
// Code sequence for indirect plt call:
// adrp x16 <symbol>
// ldr x17, [x16, #<offset>]
// blr x17 ; or 'br' for tail calls

MCInst InstAdrp;
InstAdrp.setOpcode(AArch64::ADRP);
InstAdrp.addOperand(MCOperand::createReg(AArch64::X16));
InstAdrp.addOperand(MCOperand::createImm(0));
setOperandToSymbolRef(InstAdrp, /* OpNum */ 1, TargetLocation,
/* Addend */ 0, Ctx, ELF::R_AARCH64_ADR_GOT_PAGE);
Code.emplace_back(InstAdrp);

MCInst InstLoad;
InstLoad.setOpcode(AArch64::LDRXui);
InstLoad.addOperand(MCOperand::createReg(AArch64::X17));
InstLoad.addOperand(MCOperand::createReg(AArch64::X16));
InstLoad.addOperand(MCOperand::createImm(0));
setOperandToSymbolRef(InstLoad, /* OpNum */ 2, TargetLocation,
/* Addend */ 0, Ctx, ELF::R_AARCH64_LD64_GOT_LO12_NC);
Code.emplace_back(InstLoad);

MCInst InstCall;
InstCall.setOpcode(IsTailCall ? AArch64::BR : AArch64::BLR);
InstCall.addOperand(MCOperand::createReg(AArch64::X17));
if (IsTailCall)
setTailCall(InstCall);
Code.emplace_back(InstCall);

return Code;
}

bool lowerTailCall(MCInst &Inst) override {
removeAnnotation(Inst, MCPlus::MCAnnotation::kTailCall);
if (getConditionalTailCall(Inst))
Expand Down
16 changes: 11 additions & 5 deletions bolt/lib/Target/X86/X86MCPlusBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1639,11 +1639,16 @@ class X86MCPlusBuilder : public MCPlusBuilder {
return true;
}

bool convertCallToIndirectCall(MCInst &Inst, const MCSymbol *TargetLocation,
MCContext *Ctx) override {
assert((Inst.getOpcode() == X86::CALL64pcrel32 ||
(Inst.getOpcode() == X86::JMP_4 && isTailCall(Inst))) &&
InstructionListType createIndirectPltCall(const MCInst &DirectCall,
const MCSymbol *TargetLocation,
MCContext *Ctx) override {
assert((DirectCall.getOpcode() == X86::CALL64pcrel32 ||
(DirectCall.getOpcode() == X86::JMP_4 && isTailCall(DirectCall))) &&
"64-bit direct (tail) call instruction expected");

InstructionListType Code;
// Create a new indirect call by converting the previous direct call.
MCInst Inst = DirectCall;
const auto NewOpcode =
(Inst.getOpcode() == X86::CALL64pcrel32) ? X86::CALL64m : X86::JMP32m;
Inst.setOpcode(NewOpcode);
Expand All @@ -1664,7 +1669,8 @@ class X86MCPlusBuilder : public MCPlusBuilder {
Inst.insert(Inst.begin(),
MCOperand::createReg(X86::RIP)); // BaseReg

return true;
Code.emplace_back(Inst);
return Code;
}

void convertIndirectCallToLoad(MCInst &Inst, MCPhysReg Reg) override {
Expand Down
15 changes: 15 additions & 0 deletions bolt/test/AArch64/plt-call.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Verify that PLTCall optimization works.

RUN: %clang %cflags %p/../Inputs/plt-tailcall.c \
RUN: -o %t -Wl,-q
RUN: llvm-bolt %t -o %t.bolt --plt=all --print-plt --print-only=foo | FileCheck %s

// Call to printf
CHECK: adrp x16, printf@GOT
CHECK: ldr x17, [x16, :lo12:printf@GOT]
CHECK: blr x17 # PLTCall: 1

// Call to puts, that was tail-call optimized
CHECK: adrp x16, puts@GOT
CHECK: ldr x17, [x16, :lo12:puts@GOT]
CHECK: br x17 # TAILCALL # PLTCall: 1
8 changes: 8 additions & 0 deletions bolt/test/Inputs/plt-tailcall.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#include "stub.h"

int foo(char *c) {
printf("");
__attribute__((musttail)) return puts(c);
}

int main() { return foo("a"); }
57 changes: 57 additions & 0 deletions bolt/test/X86/Inputs/blarge_profile_stale_low_matched_blocks.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
---
header:
profile-version: 1
binary-name: 'reader-yaml.test.tmp.exe'
binary-build-id: '<unknown>'
profile-flags: [ lbr ]
profile-origin: branch profile reader
profile-events: ''
dfs-order: false
hash-func: xxh3
functions:
- name: SolveCubic
fid: 6
hash: 0x0000000000000000
exec: 151
nblocks: 18
blocks:
- bid: 0
insns: 43
hash: 0x4600940a609c0000
exec: 151
succ: [ { bid: 1, cnt: 151, mis: 2 }, { bid: 7, cnt: 0 } ]
- bid: 1
insns: 7
hash: 0x167a1f084f130088
succ: [ { bid: 13, cnt: 151 }, { bid: 2, cnt: 0 } ]
- bid: 13
insns: 26
hash: 0xa8d50000f81902a7
succ: [ { bid: 3, cnt: 89 }, { bid: 2, cnt: 10 } ]
- bid: 3
insns: 9
hash: 0xc516000073dc00a0
succ: [ { bid: 5, cnt: 151 } ]
- bid: 5
insns: 9
hash: 0x6446e1ea500111
- name: usqrt
fid: 7
hash: 0x0000000000000000
exec: 20
nblocks: 6
blocks:
- bid: 0
insns: 4
hash: 0x0000000000000001
exec: 20
succ: [ { bid: 1, cnt: 0 } ]
- bid: 1
insns: 9
hash: 0x0000000000000001
succ: [ { bid: 3, cnt: 320, mis: 171 }, { bid: 2, cnt: 0 } ]
- bid: 3
insns: 2
hash: 0x0000000000000001
succ: [ { bid: 1, cnt: 300, mis: 33 }, { bid: 4, cnt: 20 } ]
...
175 changes: 175 additions & 0 deletions bolt/test/X86/Inputs/infer_no_exits.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
.text
.file "infer_no_exits.cpp"
.globl _Z3fooi # -- Begin function _Z3fooi
.p2align 4, 0x90
.type _Z3fooi,@function
_Z3fooi: # @_Z3fooi
.Lfunc_begin0:
.cfi_startproc
.cfi_personality 155, DW.ref.__gxx_personality_v0
.cfi_lsda 27, .Lexception0
# %bb.0: # %entry
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
subq $32, %rsp
movl %edi, -4(%rbp)
cmpl $0, -4(%rbp)
jne .LBB0_4
# %bb.1: # %if.then
movl $16, %edi
callq __cxa_allocate_exception@PLT
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -32(%rbp) # 8-byte Spill
.Ltmp0:
leaq .L.str(%rip), %rsi
callq _ZNSt12out_of_rangeC1EPKc@PLT
.Ltmp1:
jmp .LBB0_2
.LBB0_2: # %invoke.cont
movq -32(%rbp), %rdi # 8-byte Reload
movq _ZTISt12out_of_range@GOTPCREL(%rip), %rsi
movq _ZNSt12out_of_rangeD1Ev@GOTPCREL(%rip), %rdx
callq __cxa_throw@PLT
.LBB0_3: # %lpad
.Ltmp2:
movq -32(%rbp), %rdi # 8-byte Reload
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -16(%rbp)
movl %eax, -20(%rbp)
callq __cxa_free_exception@PLT
jmp .LBB0_5
.LBB0_4: # %if.end
xorl %eax, %eax
addq $32, %rsp
popq %rbp
.cfi_def_cfa %rsp, 8
retq
.LBB0_5: # %eh.resume
.cfi_def_cfa %rbp, 16
movq -16(%rbp), %rdi
callq _Unwind_Resume@PLT
.Lfunc_end0:
.size _Z3fooi, .Lfunc_end0-_Z3fooi
.cfi_endproc
.section .gcc_except_table,"a",@progbits
.p2align 2, 0x0
GCC_except_table0:
.Lexception0:
.byte 255 # @LPStart Encoding = omit
.byte 255 # @TType Encoding = omit
.byte 1 # Call site Encoding = uleb128
.uleb128 .Lcst_end0-.Lcst_begin0
.Lcst_begin0:
.uleb128 .Lfunc_begin0-.Lfunc_begin0 # >> Call Site 1 <<
.uleb128 .Ltmp0-.Lfunc_begin0 # Call between .Lfunc_begin0 and .Ltmp0
.byte 0 # has no landing pad
.byte 0 # On action: cleanup
.uleb128 .Ltmp0-.Lfunc_begin0 # >> Call Site 2 <<
.uleb128 .Ltmp1-.Ltmp0 # Call between .Ltmp0 and .Ltmp1
.uleb128 .Ltmp2-.Lfunc_begin0 # jumps to .Ltmp2
.byte 0 # On action: cleanup
.uleb128 .Ltmp1-.Lfunc_begin0 # >> Call Site 3 <<
.uleb128 .Lfunc_end0-.Ltmp1 # Call between .Ltmp1 and .Lfunc_end0
.byte 0 # has no landing pad
.byte 0 # On action: cleanup
.Lcst_end0:
.p2align 2, 0x0
# -- End function
.text
.globl main # -- Begin function main
.p2align 4, 0x90
.type main,@function
main: # @main
.Lfunc_begin1:
.cfi_startproc
.cfi_personality 155, DW.ref.__gxx_personality_v0
.cfi_lsda 27, .Lexception1
# %bb.0: # %entry
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
subq $32, %rsp
movl $0, -4(%rbp)
jmp .Ltmp3
.LBB1_2: # %lpad
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -16(%rbp)
movl %eax, -20(%rbp)
.Lcatch:
# %bb.3: # %catch
movq -16(%rbp), %rdi
callq __cxa_begin_catch@PLT
callq _ZSt9terminatev@PLT
.Ltmp3:
xorl %edi, %edi
callq _Z3fooi
xorl %eax, %eax
addq $32, %rsp
popq %rbp
.cfi_def_cfa %rsp, 8
retq
.Lgarbage:

.Lfunc_end1:
.size main, .Lfunc_end1-main
.cfi_endproc
.section .gcc_except_table,"a",@progbits
.p2align 2, 0x0
GCC_except_table1:
.Lexception1:
.byte 255 # @LPStart Encoding = omit
.byte 155 # @TType Encoding = indirect pcrel sdata4
.uleb128 .Lttbase0-.Lttbaseref0
.Lttbaseref0:
.byte 1 # Call site Encoding = uleb128
.uleb128 .Lcst_end1-.Lcst_begin1
.Lcst_begin1:
.uleb128 .Ltmp3-.Lfunc_begin1 # >> Call Site 1 <<
.uleb128 .Lgarbage-.Ltmp3 # Call between .Ltmp3 and .Ltmp4
.uleb128 .LBB1_2-.Lfunc_begin1 # jumps to .LBB1_2
.byte 1 # On action: 1
.uleb128 .Lcatch-.Lfunc_begin1 # >> Call Site 2 <<
.uleb128 .Lfunc_end1-.Ltmp3 # Call between .Ltmp4 and .Lfunc_end1
# .uleb128 .LBB1_2-.Lfunc_begin1 # jumps to .LBB1_2
.byte 0 # On action: cleanup
.byte 0 # On action: cleanup
.Lcst_end1:
.byte 1 # >> Action Record 1 <<
# Catch TypeInfo 1
.byte 0 # No further actions
.p2align 2, 0x0
# >> Catch TypeInfos <<
.long 0 # TypeInfo 1
.Lttbase0:
.p2align 2, 0x0
# -- End function
.type .L.str,@object # @.str
.section .rodata.str1.1,"aMS",@progbits,1
.L.str:
.asciz "bad value"
.size .L.str, 10

.hidden DW.ref.__gxx_personality_v0
.weak DW.ref.__gxx_personality_v0
.section .data.DW.ref.__gxx_personality_v0,"awG",@progbits,DW.ref.__gxx_personality_v0,comdat
.p2align 3, 0x0
.type DW.ref.__gxx_personality_v0,@object
.section ".note.GNU-stack","",@progbits
.addrsig
.addrsig_sym _Z3fooi
.addrsig_sym __cxa_allocate_exception
.addrsig_sym __gxx_personality_v0
.addrsig_sym __cxa_free_exception
.addrsig_sym __cxa_throw
.addrsig_sym __cxa_begin_catch
.addrsig_sym _ZSt9terminatev
.addrsig_sym _Unwind_Resume
.addrsig_sym _ZTISt12out_of_range
649 changes: 21 additions & 628 deletions bolt/test/X86/bug-reorder-bb-jrcxz.s

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions bolt/test/X86/infer_no_exits.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
## This verifies that functions where an exit block has a landing pad are covered by stale profile inference.
# RUN: %clangxx %cxxflags %p/Inputs/infer_no_exits.s -o %t.exe
# RUN: link_fdata %s %t.exe %t.preagg PREAGG
# RUN: perf2bolt %t.exe -p %t.preagg --pa -o %t.fdata -w %t.yaml
# RUN: sed -i '0,/hash:/s/0x[0-9A-Fa-f]\{16\}/0x0000000000000000/' %t.yaml
# RUN: llvm-bolt %t.exe -data %t.yaml -o %t.null -v=1 -infer-stale-profile 2>&1 \
# RUN: | FileCheck %s

# PREAGG: B X:0 #main# 1 0

# CHECK: BOLT-INFO: inferred profile for 1 (100.00% of profiled, 100.00% of stale) functions responsible for -nan% samples (0 out of 0)
20 changes: 13 additions & 7 deletions bolt/test/X86/linux-alt-instruction.s
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,30 @@
## Older kernels used to have padlen field in alt_instr. Check compatibility.

# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown --defsym PADLEN=1 \
# RUN: %s -o %t.o
# RUN: %clang %cflags -nostdlib %t.o -o %t.exe \
# RUN: %s -o %t.padlen.o
# RUN: %clang %cflags -nostdlib %t.padlen.o -o %t.padlen.exe \
# RUN: -Wl,--image-base=0xffffffff80000000,--no-dynamic-linker,--no-eh-frame-hdr,--no-pie
# RUN: llvm-bolt %t.exe --print-normalized --alt-inst-has-padlen -o %t.out \
# RUN: llvm-bolt %t.padlen.exe --print-normalized --alt-inst-has-padlen -o %t.padlen.out \
# RUN: | FileCheck %s

## Check with a larger size of "feature" field in alt_instr.

# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown \
# RUN: --defsym FEATURE_SIZE_4=1 %s -o %t.o
# RUN: %clang %cflags -nostdlib %t.o -o %t.exe \
# RUN: --defsym FEATURE_SIZE_4=1 %s -o %t.fs4.o
# RUN: %clang %cflags -nostdlib %t.fs4.o -o %t.fs4.exe \
# RUN: -Wl,--image-base=0xffffffff80000000,--no-dynamic-linker,--no-eh-frame-hdr,--no-pie
# RUN: llvm-bolt %t.exe --print-normalized --alt-inst-feature-size=4 -o %t.out \
# RUN: llvm-bolt %t.fs4.exe --print-normalized --alt-inst-feature-size=4 -o %t.fs4.out \
# RUN: | FileCheck %s

## Check that out-of-bounds read is handled properly.

# RUN: not llvm-bolt %t.exe --print-normalized --alt-inst-feature-size=2 -o %t.out
# RUN: not llvm-bolt %t.fs4.exe --alt-inst-feature-size=2 -o %t.fs4.out

## Check that BOLT automatically detects structure fields in .altinstructions.

# RUN: llvm-bolt %t.exe --print-normalized -o %t.out | FileCheck %s
# RUN: llvm-bolt %t.exe --print-normalized -o %t.padlen.out | FileCheck %s
# RUN: llvm-bolt %t.exe --print-normalized -o %t.fs4.out | FileCheck %s

# CHECK: BOLT-INFO: Linux kernel binary detected
# CHECK: BOLT-INFO: parsed 2 alternative instruction entries
Expand Down
11 changes: 11 additions & 0 deletions bolt/test/X86/plt-call.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Verify that PLTCall optimization works.

RUN: %clang %cflags %p/../Inputs/plt-tailcall.c \
RUN: -o %t -Wl,-q
RUN: llvm-bolt %t -o %t.bolt --plt=all --print-plt --print-only=foo | FileCheck %s

// Call to printf
CHECK: callq *printf@GOT(%rip) # PLTCall: 1

// Call to puts, that was tail-call optimized
CHECK: jmpl *puts@GOT(%rip) # TAILCALL # PLTCall: 1
10 changes: 10 additions & 0 deletions bolt/test/X86/stale-matching-min-matched-block.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
## This script checks the stale-matching-min-matched-block flag.

RUN: yaml2obj %p/Inputs/blarge.yaml &> %t.exe

## Testing "usqrt"
RUN: llvm-bolt %t.exe -o %t.null --b %p/Inputs/blarge_profile_stale_low_matched_blocks.yaml \
RUN: --infer-stale-profile=1 --stale-matching-min-matched-block=75 \
RUN: --profile-ignore-hash=1 --debug-only=bolt-prof 2>&1 | FileCheck %s

CHECK: BOLT-INFO: inferred profile for 1 (50.00% of profiled, 50.00% of stale) functions responsible for 46.31% samples (552 out of 1192)
40 changes: 34 additions & 6 deletions clang-tools-extra/clang-doc/tool/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,38 @@ target_link_libraries(clang-doc
clangDoc
)

install(FILES ../assets/clang-doc-default-stylesheet.css
DESTINATION "${CMAKE_INSTALL_DATADIR}/clang"
COMPONENT clang-doc)

install(FILES ../assets/index.js
DESTINATION "${CMAKE_INSTALL_DATADIR}/clang"
COMPONENT clang-doc)
set(assets
index.js
clang-doc-default-stylesheet.css
)

set(asset_dir "${CMAKE_CURRENT_SOURCE_DIR}/../assets")
set(resource_dir "${CMAKE_BINARY_DIR}/share/clang")
set(out_files)

function(copy_files_to_dst src_dir dst_dir file)
set(src "${src_dir}/${file}")
set(dst "${dst_dir}/${file}")
add_custom_command(OUTPUT ${dst}
DEPENDS ${src}
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src} ${dst}
COMMENT "Copying ${file} to ${dst_dir}"
)
list(APPEND out_files ${dst})
set(out_files ${out_files} PARENT_SCOPE)
endfunction(copy_files_to_dst)

foreach(f ${assets})
install(FILES ${asset_dir}/${f}
DESTINATION "${CMAKE_INSTALL_DATADIR}/clang"
COMPONENT clang-doc)
copy_files_to_dst(${asset_dir} ${resource_dir} ${f})
endforeach(f)

add_custom_target(copy-clang-doc-assets
DEPENDS ${out_files}
COMMENT "Copying Clang-Doc Assets"
)
set_target_properties(copy-clang-doc-assets PROPERTIES FOLDER "Clang-Doc/Assets")
add_dependencies(clang-doc copy-clang-doc-assets)
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
//===----------------------------------------------------------------------===//

#include "ReturnConstRefFromParameterCheck.h"
#include "../utils/Matchers.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"

Expand All @@ -18,20 +17,82 @@ namespace clang::tidy::bugprone {
void ReturnConstRefFromParameterCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(
returnStmt(
hasReturnValue(declRefExpr(to(parmVarDecl(hasType(hasCanonicalType(
qualType(matchers::isReferenceToConst()).bind("type"))))))),
hasAncestor(functionDecl(hasReturnTypeLoc(
loc(qualType(hasCanonicalType(equalsBoundNode("type"))))))))
hasReturnValue(declRefExpr(
to(parmVarDecl(hasType(hasCanonicalType(
qualType(lValueReferenceType(pointee(
qualType(isConstQualified()))))
.bind("type"))))
.bind("param")))),
hasAncestor(
functionDecl(hasReturnTypeLoc(loc(qualType(
hasCanonicalType(equalsBoundNode("type"))))))
.bind("func")))
.bind("ret"),
this);
}

static bool isSameTypeIgnoringConst(QualType A, QualType B) {
return A.getCanonicalType().withConst() == B.getCanonicalType().withConst();
}

static bool isSameTypeIgnoringConstRef(QualType A, QualType B) {
return isSameTypeIgnoringConst(A.getCanonicalType().getNonReferenceType(),
B.getCanonicalType().getNonReferenceType());
}

static bool hasSameParameterTypes(const FunctionDecl &FD, const FunctionDecl &O,
const ParmVarDecl &PD) {
if (FD.getNumParams() != O.getNumParams())
return false;
for (unsigned I = 0, E = FD.getNumParams(); I < E; ++I) {
const ParmVarDecl *DPD = FD.getParamDecl(I);
const QualType OPT = O.getParamDecl(I)->getType();
if (DPD == &PD) {
if (!llvm::isa<RValueReferenceType>(OPT) ||
!isSameTypeIgnoringConstRef(DPD->getType(), OPT))
return false;
} else {
if (!isSameTypeIgnoringConst(DPD->getType(), OPT))
return false;
}
}
return true;
}

static const Decl *findRVRefOverload(const FunctionDecl &FD,
const ParmVarDecl &PD) {
// Actually it would be better to do lookup in caller site.
// But in most of cases, overloads of LVRef and RVRef will appear together.
// FIXME:
// 1. overload in anonymous namespace
// 2. forward reference
DeclContext::lookup_result LookupResult =
FD.getParent()->lookup(FD.getNameInfo().getName());
if (LookupResult.isSingleResult()) {
return nullptr;
}
for (const Decl *Overload : LookupResult) {
if (Overload == &FD)
continue;
if (const auto *O = dyn_cast<FunctionDecl>(Overload))
if (hasSameParameterTypes(FD, *O, PD))
return O;
}
return nullptr;
}

void ReturnConstRefFromParameterCheck::check(
const MatchFinder::MatchResult &Result) {
const auto *FD = Result.Nodes.getNodeAs<FunctionDecl>("func");
const auto *PD = Result.Nodes.getNodeAs<ParmVarDecl>("param");
const auto *R = Result.Nodes.getNodeAs<ReturnStmt>("ret");
const SourceRange Range = R->getRetValue()->getSourceRange();
if (Range.isInvalid())
return;

if (findRVRefOverload(*FD, *PD) != nullptr)
return;

diag(Range.getBegin(),
"returning a constant reference parameter may cause use-after-free "
"when the parameter is constructed from a temporary")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
//===----------------------------------------------------------------------===//

#include "MacroUsageCheck.h"
#include "clang/Basic/TokenKinds.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/PPCallbacks.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Regex.h"
#include <algorithm>
#include <cctype>
#include <functional>

Expand All @@ -37,7 +37,10 @@ class MacroUsageCallbacks : public PPCallbacks {
const MacroDirective *MD) override {
if (SM.isWrittenInBuiltinFile(MD->getLocation()) ||
MD->getMacroInfo()->isUsedForHeaderGuard() ||
MD->getMacroInfo()->getNumTokens() == 0)
MD->getMacroInfo()->tokens_empty() ||
llvm::any_of(MD->getMacroInfo()->tokens(), [](const Token &T) {
return T.isOneOf(tok::TokenKind::hash, tok::TokenKind::hashhash);
}))
return;

if (IgnoreCommandLineMacros &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,9 @@ void InefficientVectorOperationCheck::addMatcher(
onImplicitObjectArgument(declRefExpr(to(TargetVarDecl))))
.bind(AppendCallName);
const auto AppendCall = expr(ignoringImplicit(AppendCallExpr));
const auto LoopVarInit =
declStmt(hasSingleDecl(varDecl(hasInitializer(integerLiteral(equals(0))))
.bind(LoopInitVarName)));
const auto LoopVarInit = declStmt(hasSingleDecl(
varDecl(hasInitializer(ignoringParenImpCasts(integerLiteral(equals(0)))))
.bind(LoopInitVarName)));
const auto RefersToLoopVar = ignoringParenImpCasts(
declRefExpr(to(varDecl(equalsBoundNode(LoopInitVarName)))));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,13 @@ void MoveConstArgCheck::registerMatchers(MatchFinder *Finder) {
unless(isInTemplateInstantiation()))
.bind("call-move");

Finder->addMatcher(MoveCallMatcher, this);
Finder->addMatcher(
expr(anyOf(
castExpr(hasSourceExpression(MoveCallMatcher)),
cxxConstructExpr(hasDeclaration(cxxConstructorDecl(anyOf(
isCopyConstructor(), isMoveConstructor()))),
hasArgument(0, MoveCallMatcher)))),
this);

auto ConstTypeParmMatcher =
qualType(references(isConstQualified())).bind("invocation-parm-type");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ static StringRef getControlFlowString(const Stmt &Stmt) {
return "break";
if (isa<CXXThrowExpr>(Stmt))
return "throw";
llvm_unreachable("Unknown control flow interruptor");
llvm_unreachable("Unknown control flow interrupter");
}

void ElseAfterReturnCheck::check(const MatchFinder::MatchResult &Result) {
Expand All @@ -247,12 +247,12 @@ void ElseAfterReturnCheck::check(const MatchFinder::MatchResult &Result) {
return;

bool IsLastInScope = OuterScope->body_back() == If;
StringRef ControlFlowInterruptor = getControlFlowString(*Interrupt);
const StringRef ControlFlowInterrupter = getControlFlowString(*Interrupt);

if (!IsLastInScope && containsDeclInScope(Else)) {
if (WarnOnUnfixable) {
// Warn, but don't attempt an autofix.
diag(ElseLoc, WarningMessage) << ControlFlowInterruptor;
diag(ElseLoc, WarningMessage) << ControlFlowInterrupter;
}
return;
}
Expand All @@ -264,7 +264,7 @@ void ElseAfterReturnCheck::check(const MatchFinder::MatchResult &Result) {
// If the if statement is the last statement of its enclosing statements
// scope, we can pull the decl out of the if statement.
DiagnosticBuilder Diag = diag(ElseLoc, WarningMessage)
<< ControlFlowInterruptor
<< ControlFlowInterrupter
<< SourceRange(ElseLoc);
if (checkInitDeclUsageInElse(If) != nullptr) {
Diag << tooling::fixit::createReplacement(
Expand All @@ -288,7 +288,7 @@ void ElseAfterReturnCheck::check(const MatchFinder::MatchResult &Result) {
removeElseAndBrackets(Diag, *Result.Context, Else, ElseLoc);
} else if (WarnOnUnfixable) {
// Warn, but don't attempt an autofix.
diag(ElseLoc, WarningMessage) << ControlFlowInterruptor;
diag(ElseLoc, WarningMessage) << ControlFlowInterrupter;
}
return;
}
Expand All @@ -300,7 +300,7 @@ void ElseAfterReturnCheck::check(const MatchFinder::MatchResult &Result) {
// If the if statement is the last statement of its enclosing statements
// scope, we can pull the decl out of the if statement.
DiagnosticBuilder Diag = diag(ElseLoc, WarningMessage)
<< ControlFlowInterruptor
<< ControlFlowInterrupter
<< SourceRange(ElseLoc);
Diag << tooling::fixit::createReplacement(
SourceRange(If->getIfLoc()),
Expand All @@ -312,13 +312,13 @@ void ElseAfterReturnCheck::check(const MatchFinder::MatchResult &Result) {
removeElseAndBrackets(Diag, *Result.Context, Else, ElseLoc);
} else if (WarnOnUnfixable) {
// Warn, but don't attempt an autofix.
diag(ElseLoc, WarningMessage) << ControlFlowInterruptor;
diag(ElseLoc, WarningMessage) << ControlFlowInterrupter;
}
return;
}

DiagnosticBuilder Diag = diag(ElseLoc, WarningMessage)
<< ControlFlowInterruptor << SourceRange(ElseLoc);
<< ControlFlowInterrupter << SourceRange(ElseLoc);
removeElseAndBrackets(Diag, *Result.Context, Else, ElseLoc);
}

Expand Down
18 changes: 6 additions & 12 deletions clang-tools-extra/clangd/TidyProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,10 +195,10 @@ TidyProvider addTidyChecks(llvm::StringRef Checks,
}

TidyProvider disableUnusableChecks(llvm::ArrayRef<std::string> ExtraBadChecks) {
constexpr llvm::StringLiteral Seperator(",");
constexpr llvm::StringLiteral Separator(",");
static const std::string BadChecks = llvm::join_items(
Seperator,
// We want this list to start with a seperator to
Separator,
// We want this list to start with a separator to
// simplify appending in the lambda. So including an
// empty string here will force that.
"",
Expand All @@ -221,19 +221,13 @@ TidyProvider disableUnusableChecks(llvm::ArrayRef<std::string> ExtraBadChecks) {
"-hicpp-invalid-access-moved",
// Check uses dataflow analysis, which might hang/crash unexpectedly on
// incomplete code.
"-bugprone-unchecked-optional-access",

// ----- Performance problems -----

// This check runs expensive analysis for each variable.
// It has been observed to increase reparse time by 10x.
"-misc-const-correctness");
"-bugprone-unchecked-optional-access");

size_t Size = BadChecks.size();
for (const std::string &Str : ExtraBadChecks) {
if (Str.empty())
continue;
Size += Seperator.size();
Size += Separator.size();
if (LLVM_LIKELY(Str.front() != '-'))
++Size;
Size += Str.size();
Expand All @@ -244,7 +238,7 @@ TidyProvider disableUnusableChecks(llvm::ArrayRef<std::string> ExtraBadChecks) {
for (const std::string &Str : ExtraBadChecks) {
if (Str.empty())
continue;
DisableGlob += Seperator;
DisableGlob += Separator;
if (LLVM_LIKELY(Str.front() != '-'))
DisableGlob.push_back('-');
DisableGlob += Str;
Expand Down
13 changes: 13 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,10 @@ Changes in existing checks
<clang-tidy/checks/bugprone/use-after-move>` check to also handle
calls to ``std::forward``.

- Improved :doc:`cppcoreguidelines-macro-usage
<clang-tidy/checks/cppcoreguidelines/macro-usage>` check by ignoring macro with
hash preprocessing token.

- Improved :doc:`cppcoreguidelines-missing-std-forward
<clang-tidy/checks/cppcoreguidelines/missing-std-forward>` check by no longer
giving false positives for deleted functions, by fixing false negatives when only
Expand Down Expand Up @@ -383,6 +387,15 @@ Changes in existing checks
- Improved :doc:`modernize-use-using <clang-tidy/checks/modernize/use-using>`
check by adding support for detection of typedefs declared on function level.

- Improved :doc:`performance-inefficient-vector-operation
<clang-tidy/checks/performance/inefficient-vector-operation>` fixing false
negatives caused by different variable definition type and variable initial
value type in loop initialization expression.

- Improved :doc:`performance-move-const-arg
<clang-tidy/checks/performance/move-const-arg>` check by ignoring
``std::move()`` calls when their target is used as an rvalue.

- Improved :doc:`performance-unnecessary-copy-initialization
<clang-tidy/checks/performance/unnecessary-copy-initialization>` check by
detecting more cases of constant access. In particular, pointers can be
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Examples:
#define C 0
#define F1(x, y) ((a) > (b) ? (a) : (b))
#define F2(...) (__VA_ARGS__)
#define F3(x, y) x##y
#define COMMA ,
#define NORETURN [[noreturn]]
#define DEPRECATED attribute((deprecated))
Expand Down
11 changes: 9 additions & 2 deletions clang-tools-extra/include-cleaner/lib/IncludeSpeller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "clang-include-cleaner/IncludeSpeller.h"
#include "clang-include-cleaner/Types.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Registry.h"
#include <memory>
Expand All @@ -30,8 +31,14 @@ class DefaultIncludeSpeller : public IncludeSpeller {
return Input.H.verbatim().str();
case Header::Physical:
bool IsAngled = false;
std::string WorkingDir;
if (auto WD = Input.HS.getFileMgr()
.getVirtualFileSystem()
.getCurrentWorkingDirectory())
WorkingDir = *WD;
std::string FinalSpelling = Input.HS.suggestPathToFileForDiagnostics(
Input.H.physical(), Input.Main->tryGetRealPathName(), &IsAngled);
Input.H.resolvedPath(), WorkingDir, Input.Main->tryGetRealPathName(),
&IsAngled);
return IsAngled ? "<" + FinalSpelling + ">" : "\"" + FinalSpelling + "\"";
}
llvm_unreachable("Unknown clang::include_cleaner::Header::Kind enum");
Expand Down Expand Up @@ -60,4 +67,4 @@ std::string spellHeader(const IncludeSpeller::Input &Input) {
return Spelling;
}

} // namespace clang::include_cleaner
} // namespace clang::include_cleaner
18 changes: 18 additions & 0 deletions clang-tools-extra/include-cleaner/unittests/IncludeSpellerTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,24 @@ TEST(IncludeSpeller, CanOverrideSystemHeaders) {
HS, MainFile}));
}

TEST(IncludeSpeller, RelativeIncludeSearchPath) {
TestInputs Inputs;

Inputs.WorkingDir = "/root/inner";
Inputs.ExtraArgs.push_back("-I..");
Inputs.ExtraFiles["/root/foo.h"] = "";
TestAST AST{Inputs};

auto &FM = AST.fileManager();
auto &HS = AST.preprocessor().getHeaderSearchInfo();
const auto *MainFile = AST.sourceManager().getFileEntryForID(
AST.sourceManager().getMainFileID());

EXPECT_EQ("\"foo.h\"",
spellHeader(
{Header{*FM.getOptionalFileRef("/root/foo.h")}, HS, MainFile}));
}

IncludeSpellingStrategy::Add<DummyIncludeSpeller>
Speller("dummy", "Dummy Include Speller");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,37 @@ void instantiate(const int &param, const float &paramf, int &mut_param, float &m
}

} // namespace valid

namespace overload {

int const &overload_base(int const &a) { return a; }
int const &overload_base(int &&a);

int const &overload_ret_type(int const &a) { return a; }
void overload_ret_type(int &&a);

int const &overload_params1(int p1, int const &a) { return a; }
int const & overload_params1(int p1, int &&a);

int const &overload_params2(int p1, int const &a, int p2) { return a; }
int const &overload_params2(int p1, int &&a, int p2);

int const &overload_params3(T p1, int const &a, int p2) { return a; }
int const &overload_params3(int p1, int &&a, T p2);

int const &overload_params_const(int p1, int const &a, int const p2) { return a; }
int const &overload_params_const(int const p1, int &&a, int p2);

int const &overload_params_difference1(int p1, int const &a, int p2) { return a; }
// CHECK-MESSAGES: :[[@LINE-1]]:79: warning: returning a constant reference parameter
int const &overload_params_difference1(long p1, int &&a, int p2);

int const &overload_params_difference2(int p1, int const &a, int p2) { return a; }
// CHECK-MESSAGES: :[[@LINE-1]]:79: warning: returning a constant reference parameter
int const &overload_params_difference2(int p1, int &&a, long p2);

int const &overload_params_difference3(int p1, int const &a, int p2) { return a; }
// CHECK-MESSAGES: :[[@LINE-1]]:79: warning: returning a constant reference parameter
int const &overload_params_difference3(int p1, long &&a, int p2);

} // namespace overload
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@
// CHECK-MESSAGES: [[@LINE-1]]:9: warning: variadic macro 'PROBLEMATIC_VARIADIC2' used; consider using a 'constexpr' variadic template function

// These are all examples of common macros that shouldn't have constexpr suggestions.
#define CONCAT_NAME(a, b) a##b

#define CONCAT_STR(a, b) #a #b

#define COMMA ,

#define NORETURN [[noreturn]]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -387,3 +387,38 @@ void foo(const StructWithFieldContainer &Src) {
B.push_back(Number);
}
}

namespace gh95596 {

void f(std::vector<int>& t) {
{
std::vector<int> gh95596_0;
// CHECK-FIXES: gh95596_0.reserve(10);
for (unsigned i = 0; i < 10; ++i)
gh95596_0.push_back(i);
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called inside a loop; consider pre-allocating the container capacity before the loop
}
{
std::vector<int> gh95596_1;
// CHECK-FIXES: gh95596_1.reserve(10);
for (int i = 0U; i < 10; ++i)
gh95596_1.push_back(i);
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called inside a loop; consider pre-allocating the container capacity before the loop
}
{
std::vector<int> gh95596_2;
// CHECK-FIXES: gh95596_2.reserve(10);
for (unsigned i = 0U; i < 10; ++i)
gh95596_2.push_back(i);
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called inside a loop; consider pre-allocating the container capacity before the loop
}
{
std::vector<int> gh95596_3;
// CHECK-FIXES: gh95596_3.reserve(10U);
for (int i = 0; i < 10U; ++i)
gh95596_3.push_back(i);
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called inside a loop; consider pre-allocating the container capacity before the loop
}
}

} // namespace gh95596
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,18 @@ void f8() {
int f9() { return M2(1); }

template <typename T>
T f10(const int x10) {
T f_unknown_target(const int x10) {
return std::move(x10);
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: std::move of the const variable 'x10' of the trivially-copyable type 'const int' has no effect; remove std::move() [performance-move-const-arg]
// CHECK-FIXES: return x10;
}

void f11() {
f10<int>(1);
f10<double>(1);
f_unknown_target<int>(1);
f_unknown_target<double>(1);
}

A&& f_return_right_ref() {
static A a{};
return std::move(a);
}

class NoMoveSemantics {
Expand Down
8 changes: 4 additions & 4 deletions clang/bindings/python/clang/cindex.py
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,7 @@ def name(self):

@classmethod
def from_id(cls, id):
if id >= len(cls._kinds) or cls._kinds[id] is None:
if id < 0 or id >= len(cls._kinds) or cls._kinds[id] is None:
raise ValueError("Unknown template argument kind %d" % id)
return cls._kinds[id]

Expand Down Expand Up @@ -1336,7 +1336,7 @@ def __repr__(self):
CursorKind.OMP_TEAMS_DISTRIBUTE_DIRECTIVE = CursorKind(271)

# OpenMP teams distribute simd directive.
CursorKind.OMP_TEAMS_DISTRIBUTE_DIRECTIVE = CursorKind(272)
CursorKind.OMP_TEAMS_DISTRIBUTE_SIMD_DIRECTIVE = CursorKind(272)

# OpenMP teams distribute parallel for simd directive.
CursorKind.OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD_DIRECTIVE = CursorKind(273)
Expand Down Expand Up @@ -2215,7 +2215,7 @@ def name(self):

@staticmethod
def from_id(id):
if id >= len(StorageClass._kinds) or not StorageClass._kinds[id]:
if id < 0 or id >= len(StorageClass._kinds) or not StorageClass._kinds[id]:
raise ValueError("Unknown storage class %d" % id)
return StorageClass._kinds[id]

Expand Down Expand Up @@ -2395,7 +2395,7 @@ def __repr__(self):
TypeKind.OCLRESERVEID = TypeKind(160)

TypeKind.OBJCOBJECT = TypeKind(161)
TypeKind.OBJCCLASS = TypeKind(162)
TypeKind.OBJCTYPEPARAM = TypeKind(162)
TypeKind.ATTRIBUTED = TypeKind(163)

TypeKind.OCLINTELSUBGROUPAVCMCEPAYLOAD = TypeKind(164)
Expand Down
47 changes: 47 additions & 0 deletions clang/bindings/python/tests/cindex/test_enums.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import unittest

from clang.cindex import (
CursorKind,
TemplateArgumentKind,
ExceptionSpecificationKind,
AvailabilityKind,
AccessSpecifier,
TypeKind,
RefQualifierKind,
LinkageKind,
TLSKind,
StorageClass,
)


class TestCursorKind(unittest.TestCase):
enums = [
CursorKind,
TemplateArgumentKind,
ExceptionSpecificationKind,
AvailabilityKind,
AccessSpecifier,
TypeKind,
RefQualifierKind,
LinkageKind,
TLSKind,
StorageClass,
]

def test_from_id(self):
"""Check that kinds can be constructed from valid IDs"""
for enum in self.enums:
self.assertEqual(enum.from_id(2), enum._kinds[2])
with self.assertRaises(ValueError):
enum.from_id(len(enum._kinds))
with self.assertRaises(ValueError):
enum.from_id(-1)

def test_unique_kinds(self):
"""Check that no kind name has been used multiple times"""
for enum in self.enums:
for id in range(len(enum._kinds)):
try:
enum.from_id(id).name
except ValueError:
pass
40 changes: 35 additions & 5 deletions clang/cmake/caches/Fuchsia-stage2.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -300,14 +300,14 @@ if(FUCHSIA_SDK)
set(LLVM_RUNTIME_MULTILIB_hwasan+noexcept_TARGETS "aarch64-unknown-fuchsia;riscv64-unknown-fuchsia" CACHE STRING "")
endif()

foreach(target armv6m-unknown-eabi)
foreach(target armv6m-unknown-eabi;armv7m-unknown-eabi;armv8m-unknown-eabi)
list(APPEND BUILTIN_TARGETS "${target}")
set(BUILTINS_${target}_CMAKE_SYSTEM_NAME Generic CACHE STRING "")
set(BUILTINS_${target}_CMAKE_SYSTEM_PROCESSOR arm CACHE STRING "")
set(BUILTINS_${target}_CMAKE_SYSROOT "" CACHE STRING "")
set(BUILTINS_${target}_CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "")
foreach(lang C;CXX;ASM)
set(BUILTINS_${target}_CMAKE_${lang}_FLAGS "--target=${target} -mcpu=cortex-m0plus -mthumb" CACHE STRING "")
set(BUILTINS_${target}_CMAKE_${lang}_FLAGS "--target=${target} -mthumb" CACHE STRING "")
endforeach()
foreach(type SHARED;MODULE;EXE)
set(BUILTINS_${target}_CMAKE_${type}_LINKER_FLAGS "-fuse-ld=lld" CACHE STRING "")
Expand All @@ -321,16 +321,31 @@ foreach(target armv6m-unknown-eabi)
set(RUNTIMES_${target}_CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "")
set(RUNTIMES_${target}_CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY CACHE STRING "")
foreach(lang C;CXX;ASM)
set(RUNTIMES_${target}_CMAKE_${lang}_FLAGS "--target=${target} -mcpu=cortex-m0plus -mthumb" CACHE STRING "")
set(RUNTIMES_${target}_CMAKE_${lang}_FLAGS "--target=${target} -mthumb" CACHE STRING "")
endforeach()
foreach(type SHARED;MODULE;EXE)
set(RUNTIMES_${target}_CMAKE_${type}_LINKER_FLAGS "-fuse-ld=lld" CACHE STRING "")
endforeach()
set(RUNTIMES_${target}_LLVM_LIBC_FULL_BUILD ON CACHE BOOL "")
set(RUNTIMES_${target}_LIBC_ENABLE_USE_BY_CLANG ON CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ABI_VERSION 2 CACHE STRING "")
set(RUNTIMES_${target}_LIBCXX_CXX_ABI none CACHE STRING "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_SHARED OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_STATIC OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_FILESYSTEM OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_RANDOM_DEVICE OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_LOCALIZATION OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_UNICODE OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_WIDE_CHARACTERS OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_EXCEPTIONS OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_RTTI OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_THREADS OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_MONOTONIC_CLOCK OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_INSTALL_LIBRARY OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_USE_COMPILER_RT ON CACHE BOOL "")
set(RUNTIMES_${target}_LLVM_INCLUDE_TESTS OFF CACHE BOOL "")
set(RUNTIMES_${target}_LLVM_ENABLE_ASSERTIONS OFF CACHE BOOL "")
set(RUNTIMES_${target}_LLVM_ENABLE_RUNTIMES "libc" CACHE STRING "")
set(RUNTIMES_${target}_LLVM_ENABLE_RUNTIMES "libc;libcxx" CACHE STRING "")
endforeach()

foreach(target riscv32-unknown-elf)
Expand Down Expand Up @@ -361,9 +376,24 @@ foreach(target riscv32-unknown-elf)
endforeach()
set(RUNTIMES_${target}_LLVM_LIBC_FULL_BUILD ON CACHE BOOL "")
set(RUNTIMES_${target}_LIBC_ENABLE_USE_BY_CLANG ON CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ABI_VERSION 2 CACHE STRING "")
set(RUNTIMES_${target}_LIBCXX_CXX_ABI none CACHE STRING "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_SHARED OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_STATIC OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_FILESYSTEM OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_RANDOM_DEVICE OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_LOCALIZATION OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_UNICODE OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_WIDE_CHARACTERS OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_EXCEPTIONS OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_RTTI OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_THREADS OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_ENABLE_MONOTONIC_CLOCK OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_INSTALL_LIBRARY OFF CACHE BOOL "")
set(RUNTIMES_${target}_LIBCXX_USE_COMPILER_RT ON CACHE BOOL "")
set(RUNTIMES_${target}_LLVM_INCLUDE_TESTS OFF CACHE BOOL "")
set(RUNTIMES_${target}_LLVM_ENABLE_ASSERTIONS OFF CACHE BOOL "")
set(RUNTIMES_${target}_LLVM_ENABLE_RUNTIMES "libc" CACHE STRING "")
set(RUNTIMES_${target}_LLVM_ENABLE_RUNTIMES "libc;libcxx" CACHE STRING "")
endforeach()

set(LLVM_BUILTIN_TARGETS "${BUILTIN_TARGETS}" CACHE STRING "")
Expand Down
37 changes: 34 additions & 3 deletions clang/docs/APINotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,12 @@ entries:

Name: MyFramework

:Classes, Protocols, Tags, Typedefs, Globals, Enumerators, Functions:
:Classes, Protocols, Tags, Typedefs, Globals, Enumerators, Functions, Namespaces:

Arrays of top-level declarations. Each entry in the array must have a
'Name' key with its Objective-C name. "Tags" refers to structs, enums, and
unions; "Enumerators" refers to enum cases.
'Name' key with its Objective-C or C++ name. "Tags" refers to structs,
C++ classes, enums, and unions; "Classes" refers to Objective-C classes;
"Enumerators" refers to enum cases.

::

Expand Down Expand Up @@ -157,6 +158,36 @@ declaration kind), all of which are optional:
- Class: NSBundle
SwiftName: Bundle

:SwiftImportAs:

For a class, possible values are ``owned`` (equivalent to
``SWIFT_SELF_CONTAINED``) or ``reference`` (equivalent to
``SWIFT_SHARED_REFERENCE``, also requires specifying ``SwiftReleaseOp`` and
``SwiftRetainOp``).

For a method, possible values are ``unsafe`` (equivalent
to ``SWIFT_RETURNS_INDEPENDENT_VALUE``) or ``computed_property`` (equivalent to
``SWIFT_COMPUTED_PROPERTY``).

::

Tags:
- Name: RefCountedStorage
SwiftImportAs: reference
SwiftReleaseOp: RCRelease
SwiftRetainOp: RCRetain

:SwiftCopyable:

Allows annotating a C++ class as non-copyable in Swift. Equivalent to
``SWIFT_NONCOPYABLE``, or to an explicit conformance ``: ~Copyable``.

::

Tags:
- Name: tzdb
SwiftCopyable: false

:Availability, AvailabilityMsg:

A value of "nonswift" is equivalent to ``NS_SWIFT_UNAVAILABLE``. A value of
Expand Down
4 changes: 2 additions & 2 deletions clang/docs/CommandGuide/clang.rst
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ number of cross compilers, or may only support a native target.

Specify the architecture to build for (all platforms).

.. option:: -mmacosx-version-min=<version>
.. option:: -mmacos-version-min=<version>

When building for macOS, specify the minimum version supported by your
application.
Expand Down Expand Up @@ -723,7 +723,7 @@ ENVIRONMENT

.. envvar:: MACOSX_DEPLOYMENT_TARGET

If :option:`-mmacosx-version-min` is unspecified, the default deployment
If :option:`-mmacos-version-min` is unspecified, the default deployment
target is read from this environment variable. This option only affects
Darwin targets.

Expand Down
4 changes: 2 additions & 2 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2063,7 +2063,7 @@ Objective-C @available
----------------------
It is possible to use the newest SDK but still build a program that can run on
older versions of macOS and iOS by passing ``-mmacosx-version-min=`` /
older versions of macOS and iOS by passing ``-mmacos-version-min=`` /
``-miphoneos-version-min=``.
Before LLVM 5.0, when calling a function that exists only in the OS that's
Expand All @@ -2084,7 +2084,7 @@ When a method that's introduced in the OS newer than the target OS is called, a
void my_fun(NSSomeClass* var) {
// If fancyNewMethod was added in e.g. macOS 10.12, but the code is
// built with -mmacosx-version-min=10.11, then this unconditional call
// built with -mmacos-version-min=10.11, then this unconditional call
// will emit a -Wunguarded-availability warning:
[var fancyNewMethod];
}
Expand Down
28 changes: 26 additions & 2 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,14 @@ Clang Frontend Potentially Breaking Changes
- The ``hasTypeLoc`` AST matcher will no longer match a ``classTemplateSpecializationDecl``;
existing uses should switch to ``templateArgumentLoc`` or ``hasAnyTemplateArgumentLoc`` instead.

Clang Python Bindings Potentially Breaking Changes
--------------------------------------------------
- Renamed ``CursorKind`` variant 272 from ``OMP_TEAMS_DISTRIBUTE_DIRECTIVE``
to ``OMP_TEAMS_DISTRIBUTE_SIMD_DIRECTIVE``. The previous name was incorrect, it was a duplicate
of variant 271.
- Renamed ``TypeKind`` variant 162 from ``OBJCCLASS`` to ``OBJCTYPEPARAM``.
The previous name was incorrect, it was a duplicate of variant 28.

What's New in Clang |release|?
==============================
Some of the major new features and improvements to Clang are listed
Expand Down Expand Up @@ -260,6 +268,9 @@ Resolutions to C++ Defect Reports
- Clang now requires a template argument list after a template keyword.
(`CWG96: Syntactic disambiguation using the template keyword <https://cplusplus.github.io/CWG/issues/96.html>`_).

- Clang now considers ``noexcept(typeid(expr))`` more carefully, instead of always assuming that ``std::bad_typeid`` can be thrown.
(`CWG2191: Incorrect result for noexcept(typeid(v)) <https://cplusplus.github.io/CWG/issues/2191.html>`_).

C Language Changes
------------------

Expand Down Expand Up @@ -343,6 +354,9 @@ Non-comprehensive list of changes in this release
- Added ``__is_bitwise_cloneable`` which is used to check whether a type
can be safely copied by memcpy/memmove.

- ``#pragma GCC diagnostic warning "-Wfoo"`` can now downgrade ``-Werror=foo``
errors and certain default-to-error ``-W`` diagnostics to warnings.

New Compiler Flags
------------------
- ``-fsanitize=implicit-bitfield-conversion`` checks implicit truncation and
Expand Down Expand Up @@ -846,6 +860,10 @@ Bug Fixes to C++ Support
- Fix a crash caused by improper use of ``__array_extent``. (#GH80474)
- Fixed several bugs in capturing variables within unevaluated contexts. (#GH63845), (#GH67260), (#GH69307),
(#GH88081), (#GH89496), (#GH90669) and (#GH91633).
- Fixed handling of brace ellison when building deduction guides. (#GH64625), (#GH83368).
- Clang now instantiates local constexpr functions eagerly for constant evaluators. (#GH35052), (#GH94849)
- Fixed a failed assertion when attempting to convert an integer representing the difference
between the addresses of two labels (a GNU extension) to a pointer within a constant expression. (#GH95366).

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -903,11 +921,13 @@ Arm and AArch64 Support
a feature modifier for -march and -mcpu as well as via target attributes
like ``target_version`` or ``target_clones``.
- Support has been added for the following processors (-mcpu identifiers in parenthesis):
* Arm Cortex-R52+ (cortex-r52plus).
* Arm Cortex-R82AE (cortex-r82ae).
* Arm Cortex-A78AE (cortex-a78ae).
* Arm Cortex-A520AE (cortex-a520ae).
* Arm Cortex-A720AE (cortex-a720ae).
* Arm Cortex-R82AE (cortex-r82ae).
* Arm Cortex-R52+ (cortex-r52plus).
* Arm Cortex-A725 (cortex-a725).
* Arm Cortex-X925 (cortex-x925).
* Arm Neoverse-N3 (neoverse-n3).
* Arm Neoverse-V3 (neoverse-v3).
* Arm Neoverse-V3AE (neoverse-v3ae).
Expand All @@ -918,6 +938,10 @@ Android Support
Windows Support
^^^^^^^^^^^^^^^

- The clang-cl ``/Ot`` compiler option ("optimize for speed", also implied by
``/O2``) now maps to clang's ``-O3`` optimizataztion level instead of ``-O2``.
Users who prefer the old behavior can use ``clang-cl /Ot /clang:-O2 ...``.

- Clang-cl now supports function targets with intrinsic headers. This allows
for runtime feature detection of intrinsics. Previously under clang-cl
``immintrin.h`` and similar intrinsic headers would only include the intrinsics
Expand Down
29 changes: 25 additions & 4 deletions clang/docs/SourceBasedCodeCoverage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -484,10 +484,31 @@ MC/DC Instrumentation
---------------------

When instrumenting for Modified Condition/Decision Coverage (MC/DC) using the
clang option ``-fcoverage-mcdc``, users are limited to at most **six** leaf-level
conditions in a boolean expression. A warning will be generated for boolean
expressions that contain more than six, and they will not be instrumented for
MC/DC.
clang option ``-fcoverage-mcdc``, there are two hard limits.

The maximum number of terms is limited to 32767, which is practical for
handwritten expressions. To be more restrictive in order to enforce coding rules,
use ``-Xclang -fmcdc-max-conditions=n``. Expressions with exceeded condition
counts ``n`` will generate warnings and will be excluded in the MC/DC coverage.

The number of test vectors (the maximum number of possible combinations of
expressions) is limited to 2,147,483,646. In this case, approximately
256MiB (==2GiB/8) is used to record test vectors.

To reduce memory usage, users can limit the maximum number of test vectors per
expression with ``-Xclang -fmcdc-max-test-vectors=m``.
If the number of test vectors resulting from the analysis of an expression
exceeds ``m``, a warning will be issued and the expression will be excluded
from the MC/DC coverage.

The number of test vectors ``m``, for ``n`` terms in an expression, can be
``m <= 2^n`` in the theoretical worst case, but is usually much smaller.
In simple cases, such as expressions consisting of a sequence of single
operators, ``m == n+1``. For example, ``(a && b && c && d && e && f && g)``
requires 8 test vectors.

Expressions such as ``((a0 && b0) || (a1 && b1) || ...)`` can cause the
number of test vectors to increase exponentially.

Also, if a boolean expression is embedded in the nest of another boolean
expression but separated by a non-logical operator, this is also not supported.
Expand Down
19 changes: 16 additions & 3 deletions clang/docs/UsersManual.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1138,7 +1138,7 @@ and ``#pragma clang diagnostic`` are synonyms for Clang. GCC will ignore

The pragma may control any warning that can be used from the command
line. Warnings may be set to ignored, warning, error, or fatal. The
following example code will tell Clang or GCC to ignore the -Wall
following example code will tell Clang or GCC to ignore the ``-Wall``
warnings:

.. code-block:: c
Expand Down Expand Up @@ -1186,6 +1186,15 @@ severity levels. They can be used to change severity of a particular diagnostic
for a region of source file. A notable difference from GCC is that diagnostic
not enabled via command line arguments can't be enabled this way yet.

Some diagnostics associated with a ``-W`` flag have the error severity by
default. They can be ignored or downgraded to warnings:

.. code-block:: cpp
// C only
#pragma GCC diagnostic warning "-Wimplicit-function-declaration"
int main(void) { puts(""); }
In addition to controlling warnings and errors generated by the compiler, it is
possible to generate custom warning and error messages through the following
pragmas:
Expand Down Expand Up @@ -3338,6 +3347,9 @@ below. If multiple flags are present, the last one is used.
By default, Clang does not emit type information for types that are defined
but not used in a program. To retain the debug info for these unused types,
the negation **-fno-eliminate-unused-debug-types** can be used.
This can be particulary useful on Windows, when using NATVIS files that
can reference const symbols that would otherwise be stripped, even in full
debug or standalone debug modes.

Controlling Macro Debug Info Generation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -4632,12 +4644,13 @@ Execute ``clang-cl /?`` to see a list of supported options:
/Ob0 Disable function inlining
/Ob1 Only inline functions which are (explicitly or implicitly) marked inline
/Ob2 Inline functions as deemed beneficial by the compiler
/Ob3 Same as /Ob2
/Od Disable optimization
/Og No effect
/Oi- Disable use of builtin functions
/Oi Enable use of builtin functions
/Os Optimize for size
/Ot Optimize for speed
/Os Optimize for size (like clang -Os)
/Ot Optimize for speed (like clang -O3)
/Ox Deprecated (same as /Og /Oi /Ot /Oy /Ob2); use /O2 instead
/Oy- Disable frame pointer omission (x86 only, default)
/Oy Enable frame pointer omission (x86 only)
Expand Down
15 changes: 0 additions & 15 deletions clang/docs/analyzer/checkers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2452,21 +2452,6 @@ Check for pointer subtractions on two pointers pointing to different memory chun
int d = &y - &x; // warn
}
.. _alpha-core-SizeofPtr:
alpha.core.SizeofPtr (C)
""""""""""""""""""""""""
Warn about unintended use of ``sizeof()`` on pointer expressions.
.. code-block:: c
struct s {};
int test(struct s *p) {
return sizeof(p);
// warn: sizeof(ptr) can produce an unexpected result
}
.. _alpha-core-StackAddressAsyncEscape:
alpha.core.StackAddressAsyncEscape (C)
Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -1771,6 +1771,13 @@ class ASTContext : public RefCountedBase<ASTContext> {
QualType DeducedType,
bool IsDependent) const;

private:
QualType getDeducedTemplateSpecializationTypeInternal(TemplateName Template,
QualType DeducedType,
bool IsDependent,
QualType Canon) const;

public:
/// Return the unique reference to the type for the specified TagDecl
/// (struct/union/class/enum) decl.
QualType getTagDeclType(const TagDecl *Decl) const;
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/AST/DeclBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,9 @@ class alignas(8) Decl {
/// Whether this declaration comes from another module unit.
bool isInAnotherModuleUnit() const;

/// Whether this declaration comes from the same module unit being compiled.
bool isInCurrentModuleUnit() const;

/// Whether the definition of the declaration should be emitted in external
/// sources.
bool shouldEmitInExternalSource() const;
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/AST/ExprCXX.h
Original file line number Diff line number Diff line change
Expand Up @@ -919,6 +919,10 @@ class CXXTypeidExpr : public Expr {
reinterpret_cast<Stmt **>(&const_cast<CXXTypeidExpr *>(this)->Operand);
return const_child_range(begin, begin + 1);
}

/// Whether this is of a form like "typeid(*ptr)" that can throw a
/// std::bad_typeid if a pointer is a null pointer ([expr.typeid]p2)
bool hasNullCheck() const;
};

/// A member reference to an MSPropertyDecl.
Expand Down
7 changes: 6 additions & 1 deletion clang/include/clang/AST/PrettyPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ struct PrintingPolicy {
PrintCanonicalTypes(false), PrintInjectedClassNameWithArguments(true),
UsePreferredNames(true), AlwaysIncludeTypeForTemplateArgument(false),
CleanUglifiedParameters(false), EntireContentsOfLargeArray(true),
UseEnumerators(true) {}
UseEnumerators(true), UseHLSLTypes(LO.HLSL) {}

/// Adjust this printing policy for cases where it's known that we're
/// printing C++ code (for instance, if AST dumping reaches a C++-only
Expand Down Expand Up @@ -342,6 +342,11 @@ struct PrintingPolicy {
LLVM_PREFERRED_TYPE(bool)
unsigned UseEnumerators : 1;

/// Whether or not we're printing known HLSL code and should print HLSL
/// sugared types when possible.
LLVM_PREFERRED_TYPE(bool)
unsigned UseHLSLTypes : 1;

/// Callbacks to use to allow the behavior of printing to be customized.
const PrintingCallbacks *Callbacks = nullptr;
};
Expand Down
4 changes: 3 additions & 1 deletion clang/include/clang/AST/TemplateName.h
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,9 @@ class TemplateName {
/// error.
void dump() const;

void Profile(llvm::FoldingSetNodeID &ID);
void Profile(llvm::FoldingSetNodeID &ID) {
ID.AddPointer(Storage.getOpaqueValue());
}

/// Retrieve the template name as a void pointer.
void *getAsVoidPointer() const { return Storage.getOpaqueValue(); }
Expand Down
11 changes: 4 additions & 7 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -6050,30 +6050,27 @@ class DeducedTemplateSpecializationType : public DeducedType,

DeducedTemplateSpecializationType(TemplateName Template,
QualType DeducedAsType,
bool IsDeducedAsDependent)
bool IsDeducedAsDependent, QualType Canon)
: DeducedType(DeducedTemplateSpecialization, DeducedAsType,
toTypeDependence(Template.getDependence()) |
(IsDeducedAsDependent
? TypeDependence::DependentInstantiation
: TypeDependence::None),
DeducedAsType.isNull() ? QualType(this, 0)
: DeducedAsType.getCanonicalType()),
Canon),
Template(Template) {}

public:
/// Retrieve the name of the template that we are deducing.
TemplateName getTemplateName() const { return Template;}

void Profile(llvm::FoldingSetNodeID &ID) {
void Profile(llvm::FoldingSetNodeID &ID) const {
Profile(ID, getTemplateName(), getDeducedType(), isDependentType());
}

static void Profile(llvm::FoldingSetNodeID &ID, TemplateName Template,
QualType Deduced, bool IsDependent) {
Template.Profile(ID);
QualType CanonicalType =
Deduced.isNull() ? Deduced : Deduced.getCanonicalType();
ID.AddPointer(CanonicalType.getAsOpaquePtr());
Deduced.Profile(ID);
ID.AddBoolean(IsDependent || Template.isDependent());
}

Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/BuiltinsWebAssembly.def
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ TARGET_BUILTIN(__builtin_wasm_relaxed_madd_f32x4, "V4fV4fV4fV4f", "nc", "relaxed
TARGET_BUILTIN(__builtin_wasm_relaxed_nmadd_f32x4, "V4fV4fV4fV4f", "nc", "relaxed-simd")
TARGET_BUILTIN(__builtin_wasm_relaxed_madd_f64x2, "V2dV2dV2dV2d", "nc", "relaxed-simd")
TARGET_BUILTIN(__builtin_wasm_relaxed_nmadd_f64x2, "V2dV2dV2dV2d", "nc", "relaxed-simd")
TARGET_BUILTIN(__builtin_wasm_relaxed_madd_f16x8, "V8hV8hV8hV8h", "nc", "half-precision")
TARGET_BUILTIN(__builtin_wasm_relaxed_nmadd_f16x8, "V8hV8hV8hV8h", "nc", "half-precision")

TARGET_BUILTIN(__builtin_wasm_relaxed_laneselect_i8x16, "V16ScV16ScV16ScV16Sc", "nc", "relaxed-simd")
TARGET_BUILTIN(__builtin_wasm_relaxed_laneselect_i16x8, "V8sV8sV8sV8s", "nc", "relaxed-simd")
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/CodeGenOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,8 @@ CODEGENOPT(CoverageMapping , 1, 0) ///< Generate coverage mapping regions to
CODEGENOPT(DumpCoverageMapping , 1, 0) ///< Dump the generated coverage mapping
///< regions.
CODEGENOPT(MCDCCoverage , 1, 0) ///< Enable MC/DC code coverage criteria.
VALUE_CODEGENOPT(MCDCMaxConds, 16, 32767) ///< MC/DC Maximum conditions.
VALUE_CODEGENOPT(MCDCMaxTVs, 32, 0x7FFFFFFE) ///< MC/DC Maximum test vectors.

/// If -fpcc-struct-return or -freg-struct-return is specified.
ENUM_CODEGENOPT(StructReturnConvention, StructReturnConventionKind, 2, SRCK_Default)
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticDriverKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -809,4 +809,7 @@ def warn_android_unversioned_fallback : Warning<

def err_drv_triple_version_invalid : Error<
"version '%0' in target triple '%1' is invalid">;

def warn_missing_include_dirs : Warning<
"no such include directory: '%0'">, InGroup<MissingIncludeDirs>, DefaultIgnore;
}
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/DiagnosticGroups.td
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,7 @@ def MaxUnsignedZero : DiagGroup<"max-unsigned-zero">;
def MissingBraces : DiagGroup<"missing-braces">;
def MissingDeclarations: DiagGroup<"missing-declarations">;
def : DiagGroup<"missing-format-attribute">;
def : DiagGroup<"missing-include-dirs">;
def MissingIncludeDirs : DiagGroup<"missing-include-dirs">;
def MissingNoreturn : DiagGroup<"missing-noreturn">;
def MultiChar : DiagGroup<"multichar">;
def : DiagGroup<"nested-externs">;
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/DiagnosticInstallAPIKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ def err_unsupported_environment : Error<"environment '%0' is not supported: '%1'
def err_unsupported_os : Error<"os '%0' is not supported: '%1'">;
def err_cannot_read_input_list : Error<"could not read %0 input list '%1': %2">;
def err_invalid_label: Error<"label '%0' is reserved: use a different label name for -X<label>">;
def err_directory_scanning: Error<"could not read directory '%0': %1">;
def err_more_than_one_library: Error<"more than one framework/dynamic library found">;
} // end of command line category.

let CategoryName = "Verification" in {
Expand Down
8 changes: 5 additions & 3 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -3200,9 +3200,8 @@ def err_attribute_bad_sve_vector_size : Error<
def err_attribute_arm_feature_sve_bits_unsupported : Error<
"%0 is only supported when '-msve-vector-bits=<bits>' is specified with a "
"value of 128, 256, 512, 1024 or 2048">;
def warn_attribute_arm_sm_incompat_builtin : Warning<
"builtin call has undefined behaviour when called from a %0 function">,
InGroup<DiagGroup<"undefined-arm-streaming">>;
def err_attribute_arm_sm_incompat_builtin : Error<
"builtin can only be called from a %0 function">;
def warn_attribute_arm_za_builtin_no_za_state : Warning<
"builtin call is not valid when calling from a function without active ZA state">,
InGroup<DiagGroup<"undefined-arm-za">>;
Expand Down Expand Up @@ -8779,6 +8778,9 @@ def err_typecheck_incomplete_type_not_modifiable_lvalue : Error<
def err_typecheck_lvalue_casts_not_supported : Error<
"assignment to cast is illegal, lvalue casts are not supported">;

def note_typecheck_add_deref_star_not_modifiable_lvalue : Note<
"add '*' to dereference it">;

def err_typecheck_duplicate_vector_components_not_mlvalue : Error<
"vector is not assignable (contains duplicate components)">;
def err_block_decl_ref_not_modifiable_lvalue : Error<
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Basic/SourceManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -1676,6 +1676,11 @@ class SourceManager : public RefCountedBase<SourceManager> {
isInTheSameTranslationUnit(std::pair<FileID, unsigned> &LOffs,
std::pair<FileID, unsigned> &ROffs) const;

/// \param Loc a source location in a loaded AST (of a PCH/Module file).
/// \returns a FileID uniquely identifies the AST of a loaded
/// module/PCH where `Loc` is at.
FileID getUniqueLoadedASTFileID(SourceLocation Loc) const;

/// Determines whether the two decomposed source location is in the same TU.
bool isInTheSameTranslationUnitImpl(
const std::pair<FileID, unsigned> &LOffs,
Expand Down
1,550 changes: 781 additions & 769 deletions clang/include/clang/Basic/arm_sve.td

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion clang/include/clang/Basic/arm_sve_sme_incl.td
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ def IsStreamingCompatible : FlagType<0x4000000000>;
def IsReadZA : FlagType<0x8000000000>;
def IsWriteZA : FlagType<0x10000000000>;
def IsReductionQV : FlagType<0x20000000000>;
def IsStreamingOrSVE2p1 : FlagType<0x40000000000>; // Use for intrinsics that are common between sme/sme2 and sve2p1.
def VerifyRuntimeMode : FlagType<0x40000000000>; // Use for intrinsics that are common between SVE and SME.
def IsInZA : FlagType<0x80000000000>;
def IsOutZA : FlagType<0x100000000000>;
def IsInOutZA : FlagType<0x200000000000>;
Expand Down
27 changes: 20 additions & 7 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -1790,6 +1790,14 @@ defm mcdc_coverage : BoolFOption<"coverage-mcdc",
"Enable MC/DC criteria when generating code coverage">,
NegFlag<SetFalse, [], [ClangOption], "Disable MC/DC coverage criteria">,
BothFlags<[], [ClangOption, CLOption]>>;
def fmcdc_max_conditions_EQ : Joined<["-"], "fmcdc-max-conditions=">,
Group<f_Group>, Visibility<[CC1Option]>,
HelpText<"Maximum number of conditions in MC/DC coverage">,
MarshallingInfoInt<CodeGenOpts<"MCDCMaxConds">, "32767">;
def fmcdc_max_test_vectors_EQ : Joined<["-"], "fmcdc-max-test-vectors=">,
Group<f_Group>, Visibility<[CC1Option]>,
HelpText<"Maximum number of test vectors in MC/DC coverage">,
MarshallingInfoInt<CodeGenOpts<"MCDCMaxTVs">, "0x7FFFFFFE">;
def fprofile_generate : Flag<["-"], "fprofile-generate">,
Group<f_Group>, Visibility<[ClangOption, CLOption]>,
HelpText<"Generate instrumented code to collect execution counts into default.profraw (overridden by LLVM_PROFILE_FILE env var)">;
Expand Down Expand Up @@ -2114,7 +2122,7 @@ def fno_elide_type : Flag<["-"], "fno-elide-type">, Group<f_Group>,
MarshallingInfoNegativeFlag<DiagnosticOpts<"ElideType">>;
def feliminate_unused_debug_symbols : Flag<["-"], "feliminate-unused-debug-symbols">, Group<f_Group>;
defm eliminate_unused_debug_types : OptOutCC1FFlag<"eliminate-unused-debug-types",
"Do not emit ", "Emit ", " debug info for defined but unused types">;
"Do not emit ", "Emit ", " debug info for defined but unused types", [ClangOption, CLOption]>;
def femit_all_decls : Flag<["-"], "femit-all-decls">, Group<f_Group>,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Emit all declarations, even if unused">,
Expand Down Expand Up @@ -7028,6 +7036,12 @@ def as_secure_log_file : Separate<["-"], "as-secure-log-file">,

} // let Visibility = [CC1Option, CC1AsOption]

let Visibility = [CC1Option, FC1Option] in {
def mlink_builtin_bitcode : Separate<["-"], "mlink-builtin-bitcode">,
HelpText<"Link and internalize needed symbols from the given bitcode file "
"before performing optimizations.">;
} // let Visibility = [CC1Option, FC1Option]

let Visibility = [CC1Option] in {

def llvm_verify_each : Flag<["-"], "llvm-verify-each">,
Expand Down Expand Up @@ -7130,9 +7144,6 @@ defm constructor_aliases : BoolMOption<"constructor-aliases",
" emitting complete constructors and destructors as aliases when possible">>;
def mlink_bitcode_file : Separate<["-"], "mlink-bitcode-file">,
HelpText<"Link the given bitcode file before performing optimizations.">;
def mlink_builtin_bitcode : Separate<["-"], "mlink-builtin-bitcode">,
HelpText<"Link and internalize needed symbols from the given bitcode file "
"before performing optimizations.">;
defm link_builtin_bitcode_postopt: BoolMOption<"link-builtin-bitcode-postopt",
CodeGenOpts<"LinkBitcodePostopt">, DefaultFalse,
PosFlag<SetTrue, [], [ClangOption], "Link builtin bitcodes after the "
Expand Down Expand Up @@ -8116,7 +8127,7 @@ def show_inst : Flag<["-"], "show-inst">,
def dwarf_debug_producer : Separate<["-"], "dwarf-debug-producer">,
HelpText<"The string to embed in the Dwarf debug AT_producer record.">;

def defsym : Separate<["-"], "defsym">,
def defsym : Separate<["--"], "defsym">,
HelpText<"Define a value for a symbol">;

} // let Visibility = [CC1AsOption]
Expand Down Expand Up @@ -8262,6 +8273,8 @@ def : CLFlag<"Ob1">, Alias<_SLASH_O>, AliasArgs<["b1"]>,
HelpText<"Only inline functions explicitly or implicitly marked inline">;
def : CLFlag<"Ob2">, Alias<_SLASH_O>, AliasArgs<["b2"]>,
HelpText<"Inline functions as deemed beneficial by the compiler">;
def : CLFlag<"Ob3">, Alias<_SLASH_O>, AliasArgs<["b3"]>,
HelpText<"Same as /Ob2">;
def : CLFlag<"Od", [CLOption, DXCOption]>, Alias<_SLASH_O>, AliasArgs<["d"]>,
HelpText<"Disable optimization">;
def : CLFlag<"Og">, Alias<_SLASH_O>, AliasArgs<["g"]>,
Expand All @@ -8271,9 +8284,9 @@ def : CLFlag<"Oi">, Alias<_SLASH_O>, AliasArgs<["i"]>,
def : CLFlag<"Oi-">, Alias<_SLASH_O>, AliasArgs<["i-"]>,
HelpText<"Disable use of builtin functions">;
def : CLFlag<"Os">, Alias<_SLASH_O>, AliasArgs<["s"]>,
HelpText<"Optimize for size">;
HelpText<"Optimize for size (like clang -Os)">;
def : CLFlag<"Ot">, Alias<_SLASH_O>, AliasArgs<["t"]>,
HelpText<"Optimize for speed">;
HelpText<"Optimize for speed (like clang -O3)">;
def : CLFlag<"Ox">, Alias<_SLASH_O>, AliasArgs<["x"]>,
HelpText<"Deprecated (like /Og /Oi /Ot /Oy /Ob2); use /O2">;
def : CLFlag<"Oy">, Alias<_SLASH_O>, AliasArgs<["y"]>,
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Driver/ToolChain.h
Original file line number Diff line number Diff line change
Expand Up @@ -639,7 +639,7 @@ class ToolChain {

/// ComputeEffectiveClangTriple - Return the Clang triple to use for this
/// target, which may take into account the command line arguments. For
/// example, on Darwin the -mmacosx-version-min= command line argument (which
/// example, on Darwin the -mmacos-version-min= command line argument (which
/// sets the deployment target) determines the version in the triple passed to
/// Clang.
virtual std::string ComputeEffectiveClangTriple(
Expand Down
13 changes: 6 additions & 7 deletions clang/include/clang/Format/Format.h
Original file line number Diff line number Diff line change
Expand Up @@ -5387,10 +5387,11 @@ extern const char *DefaultFallbackStyle;
/// \returns FormatStyle as specified by ``StyleName``. If ``StyleName`` is
/// "file" and no file is found, returns ``FallbackStyle``. If no style could be
/// determined, returns an Error.
Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
StringRef FallbackStyle, StringRef Code = "",
llvm::vfs::FileSystem *FS = nullptr,
bool AllowUnknownOptions = false);
Expected<FormatStyle>
getStyle(StringRef StyleName, StringRef FileName, StringRef FallbackStyle,
StringRef Code = "", llvm::vfs::FileSystem *FS = nullptr,
bool AllowUnknownOptions = false,
llvm::SourceMgr::DiagHandlerTy DiagHandler = nullptr);

// Guesses the language from the ``FileName`` and ``Code`` to be formatted.
// Defaults to FormatStyle::LK_Cpp.
Expand Down Expand Up @@ -5430,9 +5431,7 @@ bool isClangFormatOff(StringRef Comment);
} // end namespace format
} // end namespace clang

namespace std {
template <>
struct is_error_code_enum<clang::format::ParseError> : std::true_type {};
} // namespace std
struct std::is_error_code_enum<clang::format::ParseError> : std::true_type {};

#endif // LLVM_CLANG_FORMAT_FORMAT_H
2 changes: 1 addition & 1 deletion clang/include/clang/Frontend/FrontendOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,7 @@ class FrontendOptions {
std::string ProductName;

// Currently this is only used as part of the `-extract-api` action.
// A comma seperated list of files providing a list of APIs to
// A comma separated list of files providing a list of APIs to
// ignore when extracting documentation.
std::vector<std::string> ExtractAPIIgnoresFileList;

Expand Down
4 changes: 1 addition & 3 deletions clang/include/clang/Frontend/PrecompiledPreamble.h
Original file line number Diff line number Diff line change
Expand Up @@ -256,9 +256,7 @@ class BuildPreambleErrorCategory final : public std::error_category {
std::error_code make_error_code(BuildPreambleError Error);
} // namespace clang

namespace std {
template <>
struct is_error_code_enum<clang::BuildPreambleError> : std::true_type {};
} // namespace std
struct std::is_error_code_enum<clang::BuildPreambleError> : std::true_type {};

#endif
7 changes: 2 additions & 5 deletions clang/include/clang/Frontend/SerializedDiagnosticReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,8 @@ class SerializedDiagnosticReader {
} // namespace serialized_diags
} // namespace clang

namespace std {

template <>
struct is_error_code_enum<clang::serialized_diags::SDError> : std::true_type {};

} // namespace std
struct std::is_error_code_enum<clang::serialized_diags::SDError>
: std::true_type {};

#endif // LLVM_CLANG_FRONTEND_SERIALIZEDDIAGNOSTICREADER_H
81 changes: 81 additions & 0 deletions clang/include/clang/InstallAPI/DirectoryScanner.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
//===- InstallAPI/DirectoryScanner.h ----------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// The DirectoryScanner for collecting library files on the file system.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_INSTALLAPI_DIRECTORYSCANNER_H
#define LLVM_CLANG_INSTALLAPI_DIRECTORYSCANNER_H

#include "clang/Basic/FileManager.h"
#include "clang/InstallAPI/Library.h"

namespace clang::installapi {

enum ScanMode {
/// Scanning Framework directory.
ScanFrameworks,
/// Scanning Dylib directory.
ScanDylibs,
};

class DirectoryScanner {
public:
DirectoryScanner(FileManager &FM, ScanMode Mode = ScanMode::ScanFrameworks)
: FM(FM), Mode(Mode) {}

/// Scan for all input files throughout directory.
///
/// \param Directory Path of input directory.
llvm::Error scan(StringRef Directory);

/// Take over ownership of stored libraries.
std::vector<Library> takeLibraries() { return std::move(Libraries); };

/// Get all the header files in libraries.
///
/// \param Libraries Reference of collection of libraries.
static HeaderSeq getHeaders(ArrayRef<Library> Libraries);

private:
/// Collect files for dylibs in usr/(local)/lib within directory.
llvm::Error scanForUnwrappedLibraries(StringRef Directory);

/// Collect files for any frameworks within directory.
llvm::Error scanForFrameworks(StringRef Directory);

/// Get a library from the libraries collection.
Library &getOrCreateLibrary(StringRef Path, std::vector<Library> &Libs) const;

/// Collect multiple frameworks from directory.
llvm::Error scanMultipleFrameworks(StringRef Directory,
std::vector<Library> &Libs) const;
/// Collect files from nested frameworks.
llvm::Error scanSubFrameworksDirectory(StringRef Directory,
std::vector<Library> &Libs) const;

/// Collect files from framework path.
llvm::Error scanFrameworkDirectory(StringRef Path, Library &Framework) const;

/// Collect header files from path.
llvm::Error scanHeaders(StringRef Path, Library &Lib, HeaderType Type,
StringRef BasePath,
StringRef ParentPath = StringRef()) const;

/// Collect files from Version directories inside Framework directories.
llvm::Error scanFrameworkVersionsDirectory(StringRef Path,
Library &Lib) const;
FileManager &FM;
ScanMode Mode;
StringRef RootPath;
std::vector<Library> Libraries;
};

} // namespace clang::installapi

#endif // LLVM_CLANG_INSTALLAPI_DIRECTORYSCANNER_H
2 changes: 1 addition & 1 deletion clang/include/clang/InstallAPI/DylibVerifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ class DylibVerifier : llvm::MachO::RecordVisitor {

// Check if an internal declaration in zippered library has an
// external declaration for a different platform. This results
// in the symbol being in a "seperate" platform slice.
// in the symbol being in a "separate" platform slice.
bool shouldIgnoreInternalZipperedSymbol(const Record *R,
const SymbolContext &SymCtx) const;

Expand Down
13 changes: 13 additions & 0 deletions clang/include/clang/InstallAPI/HeaderFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,19 @@ class HeaderFile {
Other.Excluded, Other.Extra,
Other.Umbrella);
}

bool operator<(const HeaderFile &Other) const {
/// For parsing of headers based on ordering,
/// group by type, then whether its an umbrella.
/// Capture 'extra' headers last.
/// This optimizes the chance of a sucessful parse for
/// headers that violate IWYU.
if (isExtra() && Other.isExtra())
return std::tie(Type, Umbrella) < std::tie(Other.Type, Other.Umbrella);

return std::tie(Type, Umbrella, Extra, FullPath) <
std::tie(Other.Type, Other.Umbrella, Other.Extra, Other.FullPath);
}
};

/// Glob that represents a pattern of header files to retreive.
Expand Down
65 changes: 65 additions & 0 deletions clang/include/clang/InstallAPI/Library.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//===- InstallAPI/Library.h -------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// Defines the content of a library, such as public and private
/// header files, and whether it is a framework.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_INSTALLAPI_LIBRARY_H
#define LLVM_CLANG_INSTALLAPI_LIBRARY_H

#include "clang/InstallAPI/HeaderFile.h"
#include "clang/InstallAPI/MachO.h"

namespace clang::installapi {

class Library {
public:
Library(StringRef Directory) : BaseDirectory(Directory) {}

/// Capture the name of the framework by the install name.
///
/// \param InstallName The install name of the library encoded in a dynamic
/// library.
static StringRef getFrameworkNameFromInstallName(StringRef InstallName);

/// Get name of library by the discovered file path.
StringRef getName() const;

/// Get discovered path of library.
StringRef getPath() const { return BaseDirectory; }

/// Add a header file that belongs to the library.
///
/// \param FullPath Path to header file.
/// \param Type Access level of header.
/// \param IncludePath The way the header should be included.
void addHeaderFile(StringRef FullPath, HeaderType Type,
StringRef IncludePath = StringRef()) {
Headers.emplace_back(FullPath, Type, IncludePath);
}

/// Determine if library is empty.
bool empty() {
return SubFrameworks.empty() && Headers.empty() &&
FrameworkVersions.empty();
}

private:
std::string BaseDirectory;
HeaderSeq Headers;
std::vector<Library> SubFrameworks;
std::vector<Library> FrameworkVersions;
bool IsUnwrappedDylib{false};

friend class DirectoryScanner;
};

} // namespace clang::installapi

#endif // LLVM_CLANG_INSTALLAPI_LIBRARY_H
1 change: 1 addition & 0 deletions clang/include/clang/InstallAPI/MachO.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ using RecordLinkage = llvm::MachO::RecordLinkage;
using Record = llvm::MachO::Record;
using EncodeKind = llvm::MachO::EncodeKind;
using GlobalRecord = llvm::MachO::GlobalRecord;
using InterfaceFile = llvm::MachO::InterfaceFile;
using ObjCContainerRecord = llvm::MachO::ObjCContainerRecord;
using ObjCInterfaceRecord = llvm::MachO::ObjCInterfaceRecord;
using ObjCCategoryRecord = llvm::MachO::ObjCCategoryRecord;
Expand Down
4 changes: 3 additions & 1 deletion clang/include/clang/Lex/HeaderSearch.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,9 @@ struct HeaderFileInfo {
LLVM_PREFERRED_TYPE(bool)
unsigned isModuleHeader : 1;

/// Whether this header is a `textual header` in a module.
/// Whether this header is a `textual header` in a module. If a header is
/// textual in one module and normal in another module, this bit will not be
/// set, only `isModuleHeader`.
LLVM_PREFERRED_TYPE(bool)
unsigned isTextualModuleHeader : 1;

Expand Down
Loading