23 changes: 16 additions & 7 deletions bolt/lib/Core/BinaryContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,6 @@ BinaryContext::BinaryContext(std::unique_ptr<MCContext> Ctx,
InstPrinter(std::move(InstPrinter)), MIA(std::move(MIA)),
MIB(std::move(MIB)), MRI(std::move(MRI)), DisAsm(std::move(DisAsm)),
Logger(Logger), InitialDynoStats(isAArch64()) {
Relocation::Arch = this->TheTriple->getArch();
RegularPageSize = isAArch64() ? RegularPageSizeAArch64 : RegularPageSizeX86;
PageAlign = opts::NoHugePages ? RegularPageSize : HugePageSize;
}
Expand Down Expand Up @@ -1056,18 +1055,28 @@ void BinaryContext::adjustCodePadding() {
MCSymbol *BinaryContext::registerNameAtAddress(StringRef Name, uint64_t Address,
uint64_t Size,
uint16_t Alignment,
unsigned Flags) {
unsigned Flags,
BinarySection *Section) {
// Register the name with MCContext.
MCSymbol *Symbol = Ctx->getOrCreateSymbol(Name);
BinaryData *BD;

// Register out of section symbols only in GlobalSymbols map
if (Section && Section->getEndAddress() == Address) {
BD = new BinaryData(*Symbol, Address, Size, Alignment ? Alignment : 1,
*Section, Flags);
GlobalSymbols[Name] = BD;
return Symbol;
}

auto GAI = BinaryDataMap.find(Address);
BinaryData *BD;
if (GAI == BinaryDataMap.end()) {
ErrorOr<BinarySection &> SectionOrErr = getSectionForAddress(Address);
BinarySection &Section =
SectionOrErr ? SectionOrErr.get() : absoluteSection();
BinarySection &SectionRef = Section ? *Section
: SectionOrErr ? SectionOrErr.get()
: absoluteSection();
BD = new BinaryData(*Symbol, Address, Size, Alignment ? Alignment : 1,
Section, Flags);
SectionRef, Flags);
GAI = BinaryDataMap.emplace(Address, BD).first;
GlobalSymbols[Name] = BD;
updateObjectNesting(GAI);
Expand Down Expand Up @@ -1402,7 +1411,7 @@ void BinaryContext::postProcessSymbolTable() {
if ((BD->getName().starts_with("SYMBOLat") ||
BD->getName().starts_with("DATAat")) &&
!BD->getParent() && !BD->getSize() && !BD->isAbsolute() &&
BD->getSection()) {
BD->getSection().getSize()) {
this->errs() << "BOLT-WARNING: zero-sized top level symbol: " << *BD
<< "\n";
Valid = false;
Expand Down
5 changes: 4 additions & 1 deletion bolt/lib/Core/BinaryFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2502,7 +2502,10 @@ void BinaryFunction::annotateCFIState() {
}
}

assert(StateStack.empty() && "corrupt CFI stack");
if (!StateStack.empty()) {
BC.errs() << "BOLT-WARNING: non-empty CFI stack at the end of " << *this
<< '\n';
}
}

namespace {
Expand Down
62 changes: 46 additions & 16 deletions bolt/lib/Core/DIEBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -461,17 +461,11 @@ getUnitForOffset(DIEBuilder &Builder, DWARFContext &DWCtx,
return nullptr;
}

uint32_t
DIEBuilder::finalizeDIEs(DWARFUnit &CU, DIE &Die,
std::optional<BOLTDWARF5AccelTableData *> Parent,
uint32_t NumberParentsInChain, uint32_t &CurOffset) {
uint32_t DIEBuilder::finalizeDIEs(DWARFUnit &CU, DIE &Die,
uint32_t &CurOffset) {
getState().DWARFDieAddressesParsed.erase(Die.getOffset());
uint32_t CurSize = 0;
Die.setOffset(CurOffset);
std::optional<BOLTDWARF5AccelTableData *> NameEntry =
DebugNamesTable.addAccelTableEntry(
CU, Die, SkeletonCU ? SkeletonCU->getDWOId() : std::nullopt,
NumberParentsInChain, Parent);
// It is possible that an indexed debugging information entry has a parent
// that is not indexed (for example, if its parent does not have a name
// attribute). In such a case, a parent attribute may point to a nameless
Expand All @@ -485,18 +479,13 @@ DIEBuilder::finalizeDIEs(DWARFUnit &CU, DIE &Die,
// If Parent is nullopt and NumberParentsInChain is not zero, then forward
// declaration was encountered in this DF traversal. Propagating nullopt for
// Parent to children.
if (!Parent && NumberParentsInChain)
NameEntry = std::nullopt;
if (NameEntry)
++NumberParentsInChain;
for (DIEValue &Val : Die.values())
CurSize += Val.sizeOf(CU.getFormParams());
CurSize += getULEB128Size(Die.getAbbrevNumber());
CurOffset += CurSize;

for (DIE &Child : Die.children()) {
uint32_t ChildSize =
finalizeDIEs(CU, Child, NameEntry, NumberParentsInChain, CurOffset);
uint32_t ChildSize = finalizeDIEs(CU, Child, CurOffset);
CurSize += ChildSize;
}
// for children end mark.
Expand All @@ -514,10 +503,9 @@ void DIEBuilder::finish() {
DIE *UnitDIE = getUnitDIEbyUnit(CU);
uint32_t HeaderSize = CU.getHeaderSize();
uint32_t CurOffset = HeaderSize;
DebugNamesTable.setCurrentUnit(CU, UnitStartOffset);
std::vector<std::optional<BOLTDWARF5AccelTableData *>> Parents;
Parents.push_back(std::nullopt);
finalizeDIEs(CU, *UnitDIE, std::nullopt, 0, CurOffset);
finalizeDIEs(CU, *UnitDIE, CurOffset);

DWARFUnitInfo &CurUnitInfo = getUnitInfoByDwarfUnit(CU);
CurUnitInfo.UnitOffset = UnitStartOffset;
Expand Down Expand Up @@ -548,6 +536,48 @@ void DIEBuilder::finish() {
dbgs() << Twine::utohexstr(Address) << "\n";
}
}
}

void DIEBuilder::populateDebugNamesTable(
DWARFUnit &CU, const DIE &Die,
std::optional<BOLTDWARF5AccelTableData *> Parent,
uint32_t NumberParentsInChain) {
std::optional<BOLTDWARF5AccelTableData *> NameEntry =
DebugNamesTable.addAccelTableEntry(
CU, Die, SkeletonCU ? SkeletonCU->getDWOId() : std::nullopt,
NumberParentsInChain, Parent);
if (!Parent && NumberParentsInChain)
NameEntry = std::nullopt;
if (NameEntry)
++NumberParentsInChain;

for (const DIE &Child : Die.children())
populateDebugNamesTable(CU, Child, NameEntry, NumberParentsInChain);
}

void DIEBuilder::updateDebugNamesTable() {
auto finalizeDebugNamesTableForCU = [&](DWARFUnit &CU,
uint64_t &UnitStartOffset) -> void {
DIE *UnitDIE = getUnitDIEbyUnit(CU);
DebugNamesTable.setCurrentUnit(CU, UnitStartOffset);
populateDebugNamesTable(CU, *UnitDIE, std::nullopt, 0);

DWARFUnitInfo &CurUnitInfo = getUnitInfoByDwarfUnit(CU);
UnitStartOffset += CurUnitInfo.UnitLength;
};

uint64_t TypeUnitStartOffset = 0;
for (DWARFUnit *CU : getState().DUList) {
if (!(CU->getVersion() < 5 && CU->isTypeUnit()))
break;
finalizeDebugNamesTableForCU(*CU, TypeUnitStartOffset);
}

for (DWARFUnit *CU : getState().DUList) {
if (CU->getVersion() < 5 && CU->isTypeUnit())
continue;
finalizeDebugNamesTableForCU(*CU, DebugNamesUnitSize);
}
updateReferences();
}

Expand Down
3 changes: 1 addition & 2 deletions bolt/lib/Core/GDBIndex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ void GDBIndex::updateGdbIndexSection(
DebugARangesSectionWriter &ARangesSectionWriter) {
if (!BC.getGdbIndexSection())
return;

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

Expand Down Expand Up @@ -141,7 +140,7 @@ void GDBIndex::updateGdbIndexSection(
write64le(Buffer + 8, CUInfo.second.Length + 4);
Buffer += 16;
}

sortGDBIndexTUEntryVector();
// Rewrite TU CU List, since abbrevs can be different.
// Entry example:
// 0: offset = 0x00000000, type_offset = 0x0000001e, type_signature =
Expand Down
1 change: 0 additions & 1 deletion bolt/lib/Rewrite/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
set(LLVM_LINK_COMPONENTS
Core
DebugInfoDWARF
DWP
JITLink
MC
Object
Expand Down
292 changes: 30 additions & 262 deletions bolt/lib/Rewrite/DWARFRewriter.cpp

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions bolt/lib/Rewrite/MachORewriteInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ MachORewriteInstance::MachORewriteInstance(object::MachOObjectFile *InputFile,
StringRef ToolPath, Error &Err)
: InputFile(InputFile), ToolPath(ToolPath) {
ErrorAsOutParameter EAO(&Err);
Relocation::Arch = InputFile->makeTriple().getArch();
auto BCOrErr = BinaryContext::createBinaryContext(
InputFile->makeTriple(), InputFile->getFileName(), nullptr,
/* IsPIC */ true, DWARFContext::create(*InputFile),
Expand Down
84 changes: 75 additions & 9 deletions bolt/lib/Rewrite/RewriteInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ RewriteInstance::RewriteInstance(ELFObjectFileBase *File, const int Argc,
}
}

Relocation::Arch = TheTriple.getArch();
auto BCOrErr = BinaryContext::createBinaryContext(
TheTriple, File->getFileName(), Features.get(), IsPIC,
DWARFContext::create(*File, DWARFContext::ProcessDebugRelocations::Ignore,
Expand Down Expand Up @@ -955,13 +956,13 @@ void RewriteInstance::discoverFileObjects() {
uint64_t SymbolSize = ELFSymbolRef(Symbol).getSize();
uint64_t SymbolAlignment = Symbol.getAlignment();

auto registerName = [&](uint64_t FinalSize) {
auto registerName = [&](uint64_t FinalSize, BinarySection *Section = NULL) {
// Register names even if it's not a function, e.g. for an entry point.
BC->registerNameAtAddress(UniqueName, SymbolAddress, FinalSize,
SymbolAlignment, SymbolFlags);
SymbolAlignment, SymbolFlags, Section);
if (!AlternativeName.empty())
BC->registerNameAtAddress(AlternativeName, SymbolAddress, FinalSize,
SymbolAlignment, SymbolFlags);
SymbolAlignment, SymbolFlags, Section);
};

section_iterator Section =
Expand All @@ -986,12 +987,25 @@ void RewriteInstance::discoverFileObjects() {
<< " for function\n");

if (SymbolAddress == Section->getAddress() + Section->getSize()) {
ErrorOr<BinarySection &> SectionOrError =
BC->getSectionForAddress(Section->getAddress());

// Skip symbols from invalid sections
if (!SectionOrError) {
BC->errs() << "BOLT-WARNING: " << UniqueName << " (0x"
<< Twine::utohexstr(SymbolAddress)
<< ") does not have any section\n";
continue;
}

assert(SymbolSize == 0 &&
"unexpect non-zero sized symbol at end of section");
LLVM_DEBUG(
dbgs()
<< "BOLT-DEBUG: rejecting as symbol points to end of its section\n");
registerName(SymbolSize);
LLVM_DEBUG({
dbgs() << "BOLT-DEBUG: rejecting as symbol " << UniqueName
<< " points to end of " << SectionOrError->getName()
<< " section\n";
});
registerName(SymbolSize, &SectionOrError.get());
continue;
}

Expand Down Expand Up @@ -2143,6 +2157,14 @@ bool RewriteInstance::analyzeRelocation(
if (!Relocation::isSupported(RType))
return false;

auto IsWeakReference = [](const SymbolRef &Symbol) {
Expected<uint32_t> SymFlagsOrErr = Symbol.getFlags();
if (!SymFlagsOrErr)
return false;
return (*SymFlagsOrErr & SymbolRef::SF_Undefined) &&
(*SymFlagsOrErr & SymbolRef::SF_Weak);
};

const bool IsAArch64 = BC->isAArch64();

const size_t RelSize = Relocation::getSizeForType(RType);
Expand Down Expand Up @@ -2174,7 +2196,8 @@ bool RewriteInstance::analyzeRelocation(
// Section symbols are marked as ST_Debug.
IsSectionRelocation = (cantFail(Symbol.getType()) == SymbolRef::ST_Debug);
// Check for PLT entry registered with symbol name
if (!SymbolAddress && (IsAArch64 || BC->isRISCV())) {
if (!SymbolAddress && !IsWeakReference(Symbol) &&
(IsAArch64 || BC->isRISCV())) {
const BinaryData *BD = BC->getPLTBinaryDataByName(SymbolName);
SymbolAddress = BD ? BD->getAddress() : 0;
}
Expand Down Expand Up @@ -2603,7 +2626,7 @@ void RewriteInstance::handleRelocation(const SectionRef &RelocatedSection,
Expected<StringRef> SectionName = Section->getName();
if (SectionName && !SectionName->empty())
ReferencedSection = BC->getUniqueSectionByName(*SectionName);
} else if (ReferencedSymbol && ContainingBF &&
} else if (BC->isRISCV() && ReferencedSymbol && ContainingBF &&
(cantFail(Symbol.getFlags()) & SymbolRef::SF_Absolute)) {
// This might be a relocation for an ABS symbols like __global_pointer$ on
// RISC-V
Expand All @@ -2614,6 +2637,30 @@ void RewriteInstance::handleRelocation(const SectionRef &RelocatedSection,
}
}

if (Relocation::isGOT(RType) && !Relocation::isTLS(RType)) {
auto exitOnGotEndSymol = [&](StringRef Name) {
BC->errs() << "BOLT-ERROR: GOT table contains currently unsupported "
"section end symbol "
<< Name << "\n";
exit(1);
};

if (SymbolIter != InputFile->symbol_end() && ReferencedSection) {
if (cantFail(SymbolIter->getAddress()) ==
ReferencedSection->getEndAddress())
exitOnGotEndSymol(cantFail(SymbolIter->getName()));
} else {
// If no section and symbol are provided by relocation, try to find the
// symbol by its name, including the possibility that the symbol is local.
BinaryData *BD = BC->getBinaryDataByName(SymbolName);
if (!BD && NR.getUniquifiedNameCount(SymbolName) == 1)
BD = BC->getBinaryDataByName(NR.getUniqueName(SymbolName, 1));

if ((BD && BD->getAddress() == BD->getSection().getEndAddress()))
exitOnGotEndSymol(BD->getName());
}
}

if (!ReferencedSection)
ReferencedSection = BC->getSectionForAddress(SymbolAddress);

Expand Down Expand Up @@ -3131,18 +3178,24 @@ void RewriteInstance::initializeMetadataManager() {
}

void RewriteInstance::processSectionMetadata() {
NamedRegionTimer T("processmetadata-section", "process section metadata",
TimerGroupName, TimerGroupDesc, opts::TimeRewrite);
initializeMetadataManager();

MetadataManager.runSectionInitializers();
}

void RewriteInstance::processMetadataPreCFG() {
NamedRegionTimer T("processmetadata-precfg", "process metadata pre-CFG",
TimerGroupName, TimerGroupDesc, opts::TimeRewrite);
MetadataManager.runInitializersPreCFG();

processProfileDataPreCFG();
}

void RewriteInstance::processMetadataPostCFG() {
NamedRegionTimer T("processmetadata-postcfg", "process metadata post-CFG",
TimerGroupName, TimerGroupDesc, opts::TimeRewrite);
MetadataManager.runInitializersPostCFG();
}

Expand Down Expand Up @@ -3194,6 +3247,7 @@ void RewriteInstance::processProfileData() {
if (opts::AggregateOnly) {
PrintProgramStats PPS(&*BAT);
BC->logBOLTErrorsAndQuitOnFatal(PPS.runOnFunctions(*BC));
TimerGroup::printAll(outs());
exit(0);
}
}
Expand Down Expand Up @@ -3536,10 +3590,14 @@ void RewriteInstance::emitAndLink() {
}

void RewriteInstance::finalizeMetadataPreEmit() {
NamedRegionTimer T("finalizemetadata-preemit", "finalize metadata pre-emit",
TimerGroupName, TimerGroupDesc, opts::TimeRewrite);
MetadataManager.runFinalizersPreEmit();
}

void RewriteInstance::updateMetadata() {
NamedRegionTimer T("updatemetadata-postemit", "update metadata post-emit",
TimerGroupName, TimerGroupDesc, opts::TimeRewrite);
MetadataManager.runFinalizersAfterEmit();

if (opts::UpdateDebugSections) {
Expand Down Expand Up @@ -5498,6 +5556,14 @@ uint64_t RewriteInstance::getNewFunctionOrDataAddress(uint64_t OldAddress) {
if (const BinaryFunction *BF =
BC->getBinaryFunctionContainingAddress(OldAddress)) {
if (BF->isEmitted()) {
// If OldAddress is the another entry point of
// the function, then BOLT could get the new address.
if (BF->isMultiEntry()) {
for (const BinaryBasicBlock &BB : *BF)
if (BB.isEntryPoint() &&
(BF->getAddress() + BB.getOffset()) == OldAddress)
return BF->getOutputAddress() + BB.getOffset();
}
BC->errs() << "BOLT-ERROR: unable to get new address corresponding to "
"input address 0x"
<< Twine::utohexstr(OldAddress) << " in function " << *BF
Expand Down
9 changes: 9 additions & 0 deletions bolt/test/AArch64/Inputs/build_id.ldscript
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
SECTIONS
{
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS;
.note.gnu.build-id (0x400400):
{
build_id_note = ABSOLUTE(.);
*(.note.gnu.build-id)
}
}
6 changes: 6 additions & 0 deletions bolt/test/AArch64/Inputs/got_end_of_section_symbol.lld_script
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
SECTIONS {
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS;
.data : { *(.data) *(.array) }
.text : { *(.text) }
.got : { *(.got) *(.igot) }
}
25 changes: 25 additions & 0 deletions bolt/test/AArch64/build_id.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// This test checks that referencing build_id through GOT table
// would result in GOT access after disassembly, not directly
// to build_id address.

// RUN: %clang %cflags -fuse-ld=lld -Wl,-T,%S/Inputs/build_id.ldscript -Wl,-q \
// RUN: -Wl,--no-relax -Wl,--build-id=sha1 %s -o %t.exe
// RUN: llvm-bolt -print-disasm --print-only=get_build_id %t.exe -o %t.bolt | \
// RUN: FileCheck %s

// CHECK: adrp [[REG:x[0-28]+]], __BOLT_got_zero
// CHECK: ldr x{{.*}}, [[[REG]], :lo12:__BOLT_got_zero{{.*}}]

struct build_id_note {
char pad[16];
char hash[20];
};

extern const struct build_id_note build_id_note;

__attribute__((noinline)) char get_build_id() { return build_id_note.hash[0]; }

int main() {
get_build_id();
return 0;
}
28 changes: 28 additions & 0 deletions bolt/test/AArch64/got_end_of_section_symbol.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown \
# RUN: %s -o %t.o
# RUN: %clang %cflags -nostartfiles -nodefaultlibs -static -Wl,--no-relax \
# RUN: -Wl,-q -Wl,-T %S/Inputs/got_end_of_section_symbol.lld_script \
# RUN: %t.o -o %t.exe
# RUN: not llvm-bolt %t.exe -o %t.bolt 2>&1 | FileCheck %s

# CHECK: BOLT-ERROR: GOT table contains currently unsupported section end
# CHECK-SAME: symbol array_end

.section .array, "a", @progbits
.globl array_start
.globl array_end
array_start:
.word 0
array_end:

.section .text
.globl _start
.type _start, %function
_start:
adrp x1, #:got:array_start
ldr x1, [x1, #:got_lo12:array_start]
adrp x0, #:got:array_end
ldr x0, [x0, #:got_lo12:array_end]
adrp x2, #:got:_start
ldr x2, [x2, #:got_lo12:_start]
ret
34 changes: 34 additions & 0 deletions bolt/test/AArch64/update-weak-reference-symbol.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// This test checks whether BOLT can correctly handle relocations against weak symbols.

// RUN: %clang %cflags -Wl,-z,notext -shared -Wl,-q %s -o %t.so
// RUN: llvm-bolt %t.so -o %t.so.bolt
// RUN: llvm-nm -n %t.so.bolt > %t.out.txt
// RUN: llvm-objdump -dj .rodata %t.so.bolt >> %t.out.txt
// RUN: FileCheck %s --input-file=%t.out.txt

# CHECK: w func_1
# CHECK: {{0+}}[[#%x,ADDR:]] W func_2

# CHECK: {{.*}} <.rodata>:
# CHECK-NEXT: {{.*}} .word 0x00000000
# CHECK-NEXT: {{.*}} .word 0x00000000
# CHECK-NEXT: {{.*}} .word 0x{{[0]+}}[[#ADDR]]
# CHECK-NEXT: {{.*}} .word 0x00000000

.text
.weak func_2
.weak func_1
.global wow
.type wow, %function
wow:
bl func_1
bl func_2
ret
.type func_2, %function
func_2:
ret
.section .rodata
.LC0:
.xword func_1
.LC1:
.xword func_2
326 changes: 326 additions & 0 deletions bolt/test/X86/Inputs/build_id.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,326 @@
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_EXEC
Machine: EM_X86_64
Entry: 0x4010A0
ProgramHeaders:
- Type: PT_PHDR
Flags: [ PF_R ]
VAddr: 0x400040
Align: 0x8
Offset: 0x40
- Type: PT_INTERP
Flags: [ PF_R ]
FirstSec: .interp
LastSec: .interp
VAddr: 0x400444
Offset: 0x444
- Type: PT_LOAD
Flags: [ PF_X, PF_R ]
FirstSec: .init
LastSec: .fini
VAddr: 0x401000
Align: 0x1000
Offset: 0x1000
- Type: PT_LOAD
Flags: [ PF_R ]
FirstSec: .rodata
LastSec: .rodata
VAddr: 0x402000
Align: 0x1000
Offset: 0x2000
- Type: PT_LOAD
Flags: [ PF_W, PF_R ]
FirstSec: .init_array
LastSec: .bss
VAddr: 0x403DD8
Align: 0x1000
Offset: 0x2DD8
- Type: PT_DYNAMIC
Flags: [ PF_W, PF_R ]
FirstSec: .dynamic
LastSec: .dynamic
VAddr: 0x403DE8
Align: 0x8
Offset: 0x2DE8
- Type: PT_NOTE
Flags: [ PF_R ]
FirstSec: .note.gnu.build-id
LastSec: .note.ABI-tag
VAddr: 0x400400
Align: 0x4
Offset: 0x400
Sections:
- Name: .note.gnu.build-id
Type: SHT_NOTE
Flags: [ SHF_ALLOC ]
Address: 0x400400
AddressAlign: 0x4
Offset: 0x400
Notes:
- Name: GNU
Desc: 3C34F7D1612996940C48F98DC272543BC3C9C956
Type: NT_PRPSINFO
- Name: .note.ABI-tag
Type: SHT_NOTE
Flags: [ SHF_ALLOC ]
Address: 0x400424
AddressAlign: 0x4
Notes:
- Name: GNU
Desc: '00000000030000000200000000000000'
Type: NT_VERSION
- Name: .interp
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC ]
Address: 0x400444
AddressAlign: 0x1
Content: 2F6C696236342F6C642D6C696E75782D7838362D36342E736F2E3200
- Name: .gnu.hash
Type: SHT_GNU_HASH
Flags: [ SHF_ALLOC ]
Address: 0x400460
Link: .dynsym
AddressAlign: 0x8
Header:
SymNdx: 0x7
Shift2: 0x6
BloomFilter: [ 0x810000 ]
HashBuckets: [ 0x7, 0x0 ]
HashValues: [ 0x6DCE65D1 ]
- Name: .dynsym
Type: SHT_DYNSYM
Flags: [ SHF_ALLOC ]
Address: 0x400488
Link: .dynstr
AddressAlign: 0x8
- Name: .dynstr
Type: SHT_STRTAB
Flags: [ SHF_ALLOC ]
Address: 0x400548
AddressAlign: 0x1
- Name: .gnu.version
Type: SHT_GNU_versym
Flags: [ SHF_ALLOC ]
Address: 0x4005F2
Link: .dynsym
AddressAlign: 0x2
Entries: [ 0, 2, 3, 1, 1, 4, 1, 2 ]
- Name: .gnu.version_r
Type: SHT_GNU_verneed
Flags: [ SHF_ALLOC ]
Address: 0x400608
Link: .dynstr
AddressAlign: 0x8
Dependencies:
- Version: 1
File: libc.so.6
Entries:
- Name: GLIBC_2.3.4
Hash: 157882740
Flags: 0
Other: 4
- Name: GLIBC_2.34
Hash: 110530996
Flags: 0
Other: 3
- Name: GLIBC_2.2.5
Hash: 157882997
Flags: 0
Other: 2
- Name: .init
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
Address: 0x401000
AddressAlign: 0x4
Offset: 0x1000
Content: F30F1EFA4883EC08488B05D92F00004885C07402FFD04883C408C3
- Name: .plt.sec
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
Address: 0x401060
AddressAlign: 0x10
EntSize: 0x10
Content: F30F1EFAF2FF25AD2F00000F1F440000F30F1EFAF2FF25A52F00000F1F440000
- Name: .text
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
Address: 0x401080
AddressAlign: 0x10
Content: F30F1EFA4883EC0831C0E80101000031C04883C408C3662E0F1F840000000000F30F1EFA31ED4989D15E4889E24883E4F050544531C031C9488D3DC1FFFFFFFF15132F0000F4662E0F1F840000000000488D3D612F0000488D055A2F00004839F87415488B05F62E00004885C07409FFE00F1F8000000000C30F1F8000000000488D3D312F0000488D352A2F00004829FE4889F048C1EE3F48C1F8034801C648D1FE7414488B05C52E00004885C07408FFE0660F1F440000C30F1F8000000000F30F1EFA803DED2E000000752B5548833DA22E0000004889E5740C488B3DCE2E0000E8E9FEFFFFE864FFFFFFC605C52E0000015DC30F1F00C30F1F8000000000F30F1EFAE977FFFFFF0F1F8000000000F30F1EFA415455488D2D660E000053488D1D6AF2FFFF4C8D6314660F1F4400000FB6134889EEBF0100000031C04883C301E8AAFEFFFF4C39E375E55BBF0A0000005D415CE987FEFFFF
- Name: .fini
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
Address: 0x4011DC
AddressAlign: 0x4
Content: F30F1EFA4883EC084883C408C3
- Name: .rodata
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC ]
Address: 0x402000
AddressAlign: 0x4
Offset: 0x2000
Content: '0100020025303268687800'
- Name: .init_array
Type: SHT_INIT_ARRAY
Flags: [ SHF_WRITE, SHF_ALLOC ]
Address: 0x403DD8
AddressAlign: 0x8
EntSize: 0x8
Offset: 0x2DD8
Content: '8011400000000000'
- Name: .fini_array
Type: SHT_FINI_ARRAY
Flags: [ SHF_WRITE, SHF_ALLOC ]
Address: 0x403DE0
AddressAlign: 0x8
EntSize: 0x8
Content: '4011400000000000'
- Name: .dynamic
Type: SHT_DYNAMIC
Flags: [ SHF_WRITE, SHF_ALLOC ]
Address: 0x403DE8
Link: .dynstr
AddressAlign: 0x8
Entries:
- Tag: DT_NEEDED
Value: 0x37
- Tag: DT_INIT
Value: 0x401000
- Tag: DT_FINI
Value: 0x4011DC
- Tag: DT_INIT_ARRAY
Value: 0x403DD8
- Tag: DT_INIT_ARRAYSZ
Value: 0x8
- Tag: DT_FINI_ARRAY
Value: 0x403DE0
- Tag: DT_FINI_ARRAYSZ
Value: 0x8
- Tag: DT_GNU_HASH
Value: 0x400460
- Tag: DT_STRTAB
Value: 0x400548
- Tag: DT_SYMTAB
Value: 0x400488
- Tag: DT_STRSZ
Value: 0xA9
- Tag: DT_SYMENT
Value: 0x18
- Tag: DT_DEBUG
Value: 0x0
- Tag: DT_PLTGOT
Value: 0x404000
- Tag: DT_PLTRELSZ
Value: 0x30
- Tag: DT_PLTREL
Value: 0x7
- Tag: DT_FLAGS
Value: 0x8
- Tag: DT_FLAGS_1
Value: 0x8000001
- Tag: DT_VERNEED
Value: 0x400608
- Tag: DT_VERNEEDNUM
Value: 0x1
- Tag: DT_VERSYM
Value: 0x4005F2
- Tag: DT_RELACOUNT
Value: 0x3
- Tag: DT_NULL
Value: 0x0
- Name: .data
Type: SHT_PROGBITS
Flags: [ SHF_WRITE, SHF_ALLOC ]
Address: 0x404028
AddressAlign: 0x8
Content: '00000000000000003040400000000000'
- Name: .tm_clone_table
Type: SHT_PROGBITS
Flags: [ SHF_WRITE, SHF_ALLOC ]
Address: 0x404038
AddressAlign: 0x8
- Name: .bss
Type: SHT_NOBITS
Flags: [ SHF_WRITE, SHF_ALLOC ]
Address: 0x404038
AddressAlign: 0x1
Size: 0x8
- Name: .rela.text
Type: SHT_RELA
Flags: [ SHF_INFO_LINK ]
Link: .symtab
AddressAlign: 0x8
Info: .text
Relocations:
- Offset: 0x40108B
Symbol: print_build_id
Type: R_X86_64_PLT32
Addend: -4
- Offset: 0x4010BB
Symbol: main
Type: R_X86_64_PC32
Addend: -4
- Offset: 0x4011A2
Symbol: build_id_note
Type: R_X86_64_PC32
Addend: 12
- Type: SectionHeaderTable
Sections:
- Name: .note.gnu.build-id
- Name: .note.ABI-tag
- Name: .interp
- Name: .gnu.hash
- Name: .dynsym
- Name: .dynstr
- Name: .gnu.version
- Name: .gnu.version_r
- Name: .init
- Name: .plt.sec
- Name: .text
- Name: .rela.text
- Name: .fini
- Name: .rodata
- Name: .init_array
- Name: .fini_array
- Name: .dynamic
- Name: .data
- Name: .tm_clone_table
- Name: .bss
- Name: .symtab
- Name: .strtab
- Name: .shstrtab
Symbols:
- Name: print_build_id
Type: STT_FUNC
Section: .text
Binding: STB_GLOBAL
Value: 0x401190
Size: 0x49
- Name: _end
Section: .bss
Binding: STB_GLOBAL
Value: 0x404040
- Name: _start
Type: STT_FUNC
Section: .text
Binding: STB_GLOBAL
Value: 0x4010A0
Size: 0x26
- Name: __bss_start
Section: .bss
Binding: STB_GLOBAL
Value: 0x404038
- Name: main
Type: STT_FUNC
Section: .text
Binding: STB_GLOBAL
Value: 0x401080
Size: 0x16
- Name: build_id_note
Index: SHN_ABS
Binding: STB_GLOBAL
Value: 0x400400
...
8 changes: 8 additions & 0 deletions bolt/test/X86/build_id.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// This test checks that relocation addend used to address build_id fields
// is properly disassembled by BOLT.

RUN: yaml2obj %p/Inputs/build_id.yaml &> %t.exe
RUN: llvm-bolt -print-disasm --print-only=print_build_id %t.exe -o %t.bolt | \
RUN: FileCheck %s

CHECK: leaq build_id_note+16(%rip), %rbx
13 changes: 0 additions & 13 deletions bolt/test/X86/debug-fission-single-convert.s
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,6 @@
# CHECK-ADDR-SEC: 0x00000000: Addrs: [
# CHECK-ADDR-SEC: 0x0000000000601000

# RUN: llvm-bolt %t.exe --reorder-blocks=reverse --update-debug-sections --dwarf-output-path=%T -o %t.bolt.2.exe --write-dwp=true \
# RUN: --always-convert-to-ranges=true
# RUN: not llvm-dwarfdump --show-form --verbose --debug-info %t.bolt.2.exe.dwp &> %tAddrIndexTestDwp
# RUN: cat %tAddrIndexTestDwp | FileCheck %s --check-prefix=CHECK-DWP-DEBUG

# CHECK-DWP-DEBUG: DW_TAG_compile_unit [1] *
# CHECK-DWP-DEBUG: DW_AT_producer [DW_FORM_GNU_str_index] (indexed (0000000a) string = "clang version 13.0.0")
# CHECK-DWP-DEBUG: DW_AT_language [DW_FORM_data2] (DW_LANG_C_plus_plus)
# CHECK-DWP-DEBUG: DW_AT_name [DW_FORM_GNU_str_index] (indexed (0000000b) string = "foo")
# CHECK-DWP-DEBUG: DW_AT_GNU_dwo_name [DW_FORM_GNU_str_index] (indexed (0000000c) string = "foo")
# CHECK-DWP-DEBUG: DW_AT_GNU_dwo_id [DW_FORM_data8] (0x06105e732fad3796)


//clang++ -ffunction-sections -fno-exceptions -g -gsplit-dwarf=split -S debug-fission-simple.cpp -o debug-fission-simple.s
static int foo = 2;
int doStuff(int val) {
Expand Down
12 changes: 0 additions & 12 deletions bolt/test/X86/debug-fission-single.s
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,6 @@
# CHECK-ADDR-SEC: 0x00000000: Addrs: [
# CHECK-ADDR-SEC: 0x0000000000601000

# RUN: llvm-bolt %t.exe --reorder-blocks=reverse --update-debug-sections --dwarf-output-path=%T -o %t.bolt.2.exe --write-dwp=true
# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt.2.exe.dwp &> %tAddrIndexTestDwp
# RUN: cat %tAddrIndexTestDwp | FileCheck %s --check-prefix=CHECK-DWP-DEBUG

# CHECK-DWP-DEBUG: DW_TAG_compile_unit [1] *
# CHECK-DWP-DEBUG: DW_AT_producer [DW_FORM_GNU_str_index] (indexed (0000000a) string = "clang version 13.0.0")
# CHECK-DWP-DEBUG: DW_AT_language [DW_FORM_data2] (DW_LANG_C_plus_plus)
# CHECK-DWP-DEBUG: DW_AT_name [DW_FORM_GNU_str_index] (indexed (0000000b) string = "foo")
# CHECK-DWP-DEBUG: DW_AT_GNU_dwo_name [DW_FORM_GNU_str_index] (indexed (0000000c) string = "foo")
# CHECK-DWP-DEBUG: DW_AT_GNU_dwo_id [DW_FORM_data8] (0x06105e732fad3796)


//clang++ -ffunction-sections -fno-exceptions -g -gsplit-dwarf=split -S debug-fission-simple.cpp -o debug-fission-simple.s
static int foo = 2;
int doStuff(int val) {
Expand Down
30 changes: 0 additions & 30 deletions bolt/test/X86/dwarf4-ftypes-dwo-input-dwp-output.test

This file was deleted.

45 changes: 0 additions & 45 deletions bolt/test/X86/dwarf4-ftypes-dwo-mono-input-dwp-output.test

This file was deleted.

8 changes: 4 additions & 4 deletions bolt/test/X86/dwarf4-split-gdb-index-types-gdb-generated.test
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
# POSTCHECK-NEXT: 0: Offset = 0x0, Length = 0x34
# POSTCHECK-NEXT: 1: Offset = 0x34, Length = 0x34
# POSTCHECK: Types CU list offset = 0x38, has 4 entries
# POSTCHECK-NEXT: 0: offset = 0x00000000, type_offset = 0x0000001e, type_signature = 0x675d23e4f33235f2
# POSTCHECK-NEXT: 1: offset = 0x0000004a, type_offset = 0x0000001e, type_signature = 0x49dc260088be7e56
# POSTCHECK-NEXT: 2: offset = 0x00000000, type_offset = 0x0000001e, type_signature = 0x104ec427d2ebea6f
# POSTCHECK-NEXT: 3: offset = 0x0000004a, type_offset = 0x0000001e, type_signature = 0xb4580bc1535df1e4
# POSTCHECK-NEXT: 0: offset = 0x0000004a, type_offset = 0x0000001e, type_signature = 0xb4580bc1535df1e4
# POSTCHECK-NEXT: 1: offset = 0x00000000, type_offset = 0x0000001e, type_signature = 0x675d23e4f33235f2
# POSTCHECK-NEXT: 2: offset = 0x0000004a, type_offset = 0x0000001e, type_signature = 0x49dc260088be7e56
# POSTCHECK-NEXT: 3: offset = 0x00000000, type_offset = 0x0000001e, type_signature = 0x104ec427d2ebea6f
# POSTCHECK: Address area offset = 0x98, has 2 entries
# POSTCHECK-NEXT: Low/High address = [0x[[#%.4x,ADDR:]],
# POSTCHECK-SAME: 0x[[#ADDR + 0x7a]]) (Size: 0x7a), CU id = 0
Expand Down
53 changes: 0 additions & 53 deletions bolt/test/X86/dwarf5-df-types-modify-dwo-name-mixed.test
Original file line number Diff line number Diff line change
Expand Up @@ -72,59 +72,6 @@
; BOLT-NEXT: "helper.cpp"
; BOLT-NEXT: "helper.dwo"


;; Tests that BOLT correctly handles updating DW_AT_dwo_name when it outputs a DWP file.
;; Currently skipping one of Type units because it is not being de-dupped.
;; In the tu-index this TU is not present.
; RUN: rm main.exe.bolt
; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections --write-dwp
; RUN: llvm-dwarfdump --debug-info -r 0 main.exe.bolt.dwp > logDWP.txt
; RUN: llvm-dwarfdump --debug-str-offsets main.exe.bolt.dwp >> logDWP.txt
; RUN: cat logDWP.txt | FileCheck -check-prefix=BOLT-DWP %s
; BOLT-DWP: DW_TAG_type_unit
; BOLT-DWP: DW_AT_comp_dir (".")
; BOLT-DWP: DW_AT_dwo_name ("main.dwo.dwo")
; BOLT-DWP: DW_TAG_type_unit
; BOLT-DWP: DW_AT_comp_dir (".")
; BOLT-DWP: DW_AT_dwo_name ("main.dwo.dwo")
; BOLT-DWP: DW_TAG_compile_unit
; BOLT-DWP: DW_AT_dwo_name ("main.dwo.dwo")
; BOLT-DWP: DW_TAG_type_unit
; BOLT-DWP-NOT: DW_AT_dwo_name
; BOLT-DWP: Contribution size = 68, Format = DWARF32, Version = 5
; BOLT-DWP-NEXT: "main"
; BOLT-DWP-NEXT: "int"
; BOLT-DWP-NEXT: "argc"
; BOLT-DWP-NEXT: "argv"
; BOLT-DWP-NEXT: "char"
; BOLT-DWP-NEXT: "f2"
; BOLT-DWP-NEXT: "."
; BOLT-DWP-NEXT: "main.dwo.dwo"
; BOLT-DWP-NEXT: "c1"
; BOLT-DWP-NEXT: "Foo2"
; BOLT-DWP-NEXT: "f3"
; BOLT-DWP-NEXT: "c2"
; BOLT-DWP-NEXT: "c3"
; BOLT-DWP-NEXT: "Foo2a"
; BOLT-DWP-NEXT: "clang version 18.0.0git (git@github.com:ayermolo/llvm-project.git db35fa8fc524127079662802c4735dbf397f86d0)"
; BOLT-DWP-NEXT: "main.cpp"
; BOLT-DWP-NEXT: Contribution size = 64, Format = DWARF32, Version = 5
; BOLT-DWP-NEXT: "fooint"
; BOLT-DWP-NEXT: "int"
; BOLT-DWP-NEXT: "_Z3foov"
; BOLT-DWP-NEXT: "foo"
; BOLT-DWP-NEXT: "fint"
; BOLT-DWP-NEXT: "c1"
; BOLT-DWP-NEXT: "c2"
; BOLT-DWP-NEXT: "Foo2Int"
; BOLT-DWP-NEXT: "f"
; BOLT-DWP-NEXT: "char"
; BOLT-DWP-NEXT: "c3"
; BOLT-DWP-NEXT: "Foo2a"
; BOLT-DWP-NEXT: "clang version 18.0.0"
; BOLT-DWP-NEXT: "helper.cpp"
; BOLT-DWP-NEXT: "helper.dwo

;; Tests that BOLT correctly handles updating DW_AT_comp_dir/DW_AT_dwo_name when outptut directory is specified.

; RUN: mkdir DWOOut
Expand Down
25 changes: 0 additions & 25 deletions bolt/test/X86/dwarf5-df-types-modify-dwo-name.test
Original file line number Diff line number Diff line change
Expand Up @@ -73,31 +73,6 @@
; BOLT-NEXT: "clang version 18.0.0git (git@github.com:ayermolo/llvm-project.git db35fa8fc524127079662802c4735dbf397f86d0)"
; BOLT-NEXT: "helper.cpp"


;; Tests that BOLT correctly handles updating DW_AT_dwo_name when it outputs a DWP file.
;; Currently skipping one of Type units because it is not being de-dupped.
;; In the tu-index this TU is not present.
; RUN: rm main.exe.bolt
; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections --write-dwp
; RUN: llvm-dwarfdump --debug-info -r 0 main.exe.bolt.dwp > logDWP.txt
; RUN: llvm-dwarfdump --debug-str-offsets main.exe.bolt.dwp >> logDWP.txt
; RUN: cat logDWP.txt | FileCheck -check-prefix=BOLT-DWP %s
; BOLT-DWP: DW_TAG_type_unit
; BOLT-DWP: DW_AT_comp_dir (".")
; BOLT-DWP: DW_AT_dwo_name ("main.dwo.dwo")
; BOLT-DWP: DW_TAG_type_unit
; BOLT-DWP: DW_AT_comp_dir (".")
; BOLT-DWP: DW_AT_dwo_name ("main.dwo.dwo")
; BOLT-DWP: DW_TAG_compile_unit
; BOLT-DWP: DW_AT_dwo_name ("main.dwo.dwo")
; BOLT-DWP: DW_TAG_type_unit
; BOLT-DWP: DW_AT_comp_dir (".")
; BOLT-DWP: DW_AT_dwo_name ("helper.dwo.dwo")
; BOLT-DWP: DW_TAG_type_unit
; BOLT-DWP: DW_TAG_compile_unit
; BOLT-DWP: DW_AT_name ("helper.cpp")
; BOLT-DWP: DW_AT_dwo_name ("helper.dwo.dwo")

;; Tests that BOLT correctly handles updating DW_AT_comp_dir/DW_AT_dwo_name when outptut directory is specified.

; RUN: mkdir DWOOut
Expand Down
55 changes: 0 additions & 55 deletions bolt/test/X86/dwarf5-ftypes-dwo-mono-input-dwp-output.test

This file was deleted.

32 changes: 32 additions & 0 deletions bolt/test/X86/dynamic-relocs-on-entry.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// This test examines whether BOLT can correctly process when
// dynamic relocation points to other entry points of the
// function.

# RUN: %clang %cflags -fPIC -pie %s -o %t.exe -nostdlib -Wl,-q
# RUN: llvm-bolt %t.exe -o %t.bolt > %t.out.txt
# RUN: readelf -r %t.bolt >> %t.out.txt
# RUN: llvm-objdump --disassemble-symbols=chain %t.bolt >> %t.out.txt
# RUN: FileCheck %s --input-file=%t.out.txt

## Check if the new address in `chain` is correctly updated by BOLT
# CHECK: Relocation section '.rela.dyn' at offset 0x{{.*}} contains 1 entry:
# CHECK: {{.*}} R_X86_64_RELATIVE [[#%x,ADDR:]]
# CHECK: [[#ADDR]]: c3 retq
.text
.type chain, @function
chain:
movq $1, %rax
Label:
ret
.size chain, .-chain

.type _start, @function
.global _start
_start:
jmpq *.Lfoo(%rip)
ret
.size _start, .-_start

.data
.Lfoo:
.quad Label
4 changes: 2 additions & 2 deletions bolt/test/X86/section-end-sym.s
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
## Check that BOLT doesn't consider end-of-section symbols (e.g., _etext) as
## functions.

# REQUIRES: x86_64-linux, asserts
# REQUIRES: system-linux, asserts

# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux %s -o %t.o
# RUN: ld.lld %t.o -o %t.exe -q
# RUN: llvm-bolt %t.exe -o %t.null --print-cfg --debug-only=bolt 2>&1 \
# RUN: | FileCheck %s

# CHECK: considering symbol etext for function
# CHECK-NEXT: rejecting as symbol points to end of its section
# CHECK-NEXT: rejecting as symbol etext points to end of .text section
# CHECK-NOT: Binary Function "etext{{.*}}" after building cfg


Expand Down
22 changes: 22 additions & 0 deletions bolt/test/timers.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/* This test checks timers for metadata manager phases.
# RUN: %clang %cflags %s -o %t.exe
# RUN: link_fdata %s %t.exe %t.fdata
# RUN: llvm-bolt %t.exe -o %t.null --data %t.fdata -w %t.yaml --time-rewrite \
# RUN: 2>&1 | FileCheck %s
# RUN: link_fdata %s %t.exe %t.preagg PREAGG
# RUN: perf2bolt %t.exe -o %t.null -p %t.preagg --pa --time-rewrite \
# RUN: 2>&1 | FileCheck %s --check-prefix=CHECK-P2B
# CHECK-DAG: update metadata post-emit
# CHECK-DAG: process section metadata
# CHECK-DAG: process metadata pre-CFG
# CHECK-DAG: process metadata post-CFG
# CHECK-DAG: finalize metadata pre-emit
# CHECK-P2B-DAG: process section metadata
# CHECK-P2B-DAG: process metadata pre-CFG
# FDATA: 0 [unknown] 0 1 main 0 1 0
# PREAGG: B X:0 #main# 1 0
*/
int main() { return 0; }
1 change: 1 addition & 0 deletions bolt/unittests/Core/BinaryContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ struct BinaryContextTester : public testing::TestWithParam<Triple::ArchType> {
}

void initializeBOLT() {
Relocation::Arch = ObjFile->makeTriple().getArch();
BC = cantFail(BinaryContext::createBinaryContext(
ObjFile->makeTriple(), ObjFile->getFileName(), nullptr, true,
DWARFContext::create(*ObjFile.get()), {llvm::outs(), llvm::errs()}));
Expand Down
1 change: 1 addition & 0 deletions bolt/unittests/Core/MCPlusBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ struct MCPlusBuilderTester : public testing::TestWithParam<Triple::ArchType> {
}

void initializeBolt() {
Relocation::Arch = ObjFile->makeTriple().getArch();
BC = cantFail(BinaryContext::createBinaryContext(
ObjFile->makeTriple(), ObjFile->getFileName(), nullptr, true,
DWARFContext::create(*ObjFile.get()), {llvm::outs(), llvm::errs()}));
Expand Down
6 changes: 2 additions & 4 deletions clang-tools-extra/clang-tidy/tool/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ clang_target_link_libraries(clangTidyMain
# Support plugins.
if(CLANG_PLUGIN_SUPPORT)
set(support_plugins SUPPORT_PLUGINS)
set(export_symbols EXPORT_SYMBOLS_FOR_PLUGINS)
endif()

add_clang_tool(clang-tidy
Expand All @@ -41,6 +42,7 @@ add_clang_tool(clang-tidy
DEPENDS
clang-resource-headers
${support_plugins}
${export_symbols}
)
clang_target_link_libraries(clang-tidy
PRIVATE
Expand All @@ -57,10 +59,6 @@ target_link_libraries(clang-tidy
${ALL_CLANG_TIDY_CHECKS}
)

if(CLANG_PLUGIN_SUPPORT)
export_executable_symbols_for_plugins(clang-tidy)
endif()

install(PROGRAMS clang-tidy-diff.py
DESTINATION "${CMAKE_INSTALL_DATADIR}/clang"
COMPONENT clang-tidy)
Expand Down
2 changes: 1 addition & 1 deletion clang-tools-extra/clangd/unittests/HoverTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1325,7 +1325,7 @@ class Foo final {})cpp";
HI.LocalScope = "";
HI.Kind = index::SymbolKind::TypeAlias;
HI.Definition = "template <typename T> using AA = A<T>";
HI.Type = {"A<T>", "type-parameter-0-0"}; // FIXME: should be 'T'
HI.Type = {"A<T>", "T"};
HI.TemplateParameters = {
{{"typename"}, std::string("T"), std::nullopt}};
}},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ T qux(T Generic) {
async::Future<T> TemplateType;
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: unused local variable 'TemplateType' of type 'async::Future<T>' [bugprone-unused-local-non-trivial-variable]
a::Future<T> AliasTemplateType;
// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: unused local variable 'AliasTemplateType' of type 'a::Future<T>' (aka 'Future<type-parameter-0-0>') [bugprone-unused-local-non-trivial-variable]
// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: unused local variable 'AliasTemplateType' of type 'a::Future<T>' (aka 'Future<T>') [bugprone-unused-local-non-trivial-variable]
[[maybe_unused]] async::Future<Units> MaybeUnused;
return Generic;
}
Expand Down
243 changes: 115 additions & 128 deletions clang/bindings/python/clang/cindex.py

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

def find_function_declarations(node, declarations=[]):
if node.kind == clang.cindex.CursorKind.FUNCTION_DECL:
declarations.append((node.spelling, node.exception_specification_kind))
declarations.append(node)
for child in node.get_children():
declarations = find_function_declarations(child, declarations)
return declarations
Expand All @@ -33,4 +33,12 @@ def test_exception_specification_kind(self):
("square2", ExceptionSpecificationKind.BASIC_NOEXCEPT),
("square3", ExceptionSpecificationKind.COMPUTED_NOEXCEPT),
]
self.assertListEqual(declarations, expected)
from_cursor = [
(node.spelling, node.exception_specification_kind) for node in declarations
]
from_type = [
(node.spelling, node.type.get_exception_specification_kind())
for node in declarations
]
self.assertListEqual(from_cursor, expected)
self.assertListEqual(from_type, expected)
6 changes: 3 additions & 3 deletions clang/cmake/caches/Fuchsia-stage2.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -300,15 +300,15 @@ if(FUCHSIA_SDK)
set(LLVM_RUNTIME_MULTILIB_hwasan+noexcept_TARGETS "aarch64-unknown-fuchsia;riscv64-unknown-fuchsia" CACHE STRING "")
endif()

foreach(target armv6m-unknown-eabi;armv7m-unknown-eabi;armv8m.main-unknown-eabi)
foreach(target armv6m-none-eabi;armv7m-none-eabi;armv8m.main-none-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 MinSizeRel CACHE STRING "")
foreach(lang C;CXX;ASM)
set(BUILTINS_${target}_CMAKE_${lang}_local_flags "--target=${target} -mthumb")
if(${target} STREQUAL "armv8m.main-unknown-eabi")
if(${target} STREQUAL "armv8m.main-none-eabi")
set(BUILTINS_${target}_CMAKE_${lang}_local_flags "${BUILTINS_${target}_CMAKE_${lang}_local_flags} -mfloat-abi=softfp -march=armv8m.main+fp+dsp -mcpu=cortex-m33" CACHE STRING "")
endif()
set(BUILTINS_${target}_CMAKE_${lang}_FLAGS "${BUILTINS_${target}_CMAKE_${lang}_local_flags}" CACHE STRING "")
Expand All @@ -328,7 +328,7 @@ foreach(target armv6m-unknown-eabi;armv7m-unknown-eabi;armv8m.main-unknown-eabi)
# TODO: The preprocessor defines workaround various issues in libc and libc++ integration.
# These should be addressed and removed over time.
set(RUNTIMES_${target}_CMAKE_${lang}_local_flags "--target=${target} -mthumb -Wno-atomic-alignment \"-Dvfprintf(stream, format, vlist)=vprintf(format, vlist)\" \"-Dfprintf(stream, format, ...)=printf(format)\" \"-Dtimeval=struct timeval{int tv_sec; int tv_usec;}\" \"-Dgettimeofday(tv, tz)\" -D_LIBCPP_PRINT=1")
if(${target} STREQUAL "armv8m.main-unknown-eabi")
if(${target} STREQUAL "armv8m.main-none-eabi")
set(RUNTIMES_${target}_CMAKE_${lang}_local_flags "${RUNTIMES_${target}_CMAKE_${lang}_local_flags} -mfloat-abi=softfp -march=armv8m.main+fp+dsp -mcpu=cortex-m33" CACHE STRING "")
endif()
set(RUNTIMES_${target}_CMAKE_${lang}_FLAGS "${RUNTIMES_${target}_CMAKE_${lang}_local_flags}" CACHE STRING "")
Expand Down
4 changes: 3 additions & 1 deletion clang/cmake/modules/AddClang.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ endmacro(add_clang_library)
macro(add_clang_executable name)
add_llvm_executable( ${name} ${ARGN} )
set_clang_windows_version_resource_properties(${name})
set_target_properties(${name} PROPERTIES XCODE_GENERATE_SCHEME ON)
endmacro(add_clang_executable)

macro(add_clang_tool name)
Expand All @@ -159,7 +160,7 @@ macro(add_clang_tool name)
AND (NOT LLVM_DISTRIBUTION_COMPONENTS OR ${name} IN_LIST LLVM_DISTRIBUTION_COMPONENTS)
)
set(get_obj_args ${ARGN})
list(FILTER get_obj_args EXCLUDE REGEX "^SUPPORT_PLUGINS$")
list(FILTER get_obj_args EXCLUDE REGEX "^(SUPPORT_PLUGINS|EXPORT_SYMBOLS_FOR_PLUGINS)$")
generate_llvm_objects(${name} ${get_obj_args})
add_custom_target(${name} DEPENDS llvm-driver clang-resource-headers)
else()
Expand All @@ -181,6 +182,7 @@ macro(add_clang_tool name)
set_property(GLOBAL APPEND PROPERTY CLANG_EXPORTS ${name})
endif()
endif()
set_target_properties(${name} PROPERTIES XCODE_GENERATE_SCHEME ON)
endmacro()

macro(add_clang_symlink name dest)
Expand Down
2 changes: 1 addition & 1 deletion clang/docs/ClangFormatStyleOptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1484,7 +1484,7 @@ the configuration (without a prefix: ``Auto``).
* ``OAS_AlignAfterOperator`` (in configuration: ``AlignAfterOperator``)
Horizontally align operands of binary and ternary expressions.

This is similar to ``AO_Align``, except when
This is similar to ``OAS_Align``, except when
``BreakBeforeBinaryOperators`` is set, the operator is un-indented so
that the wrapped operand is aligned with the operand on the first line.

Expand Down
12 changes: 10 additions & 2 deletions clang/docs/CommandGuide/clang.rst
Original file line number Diff line number Diff line change
Expand Up @@ -429,8 +429,12 @@ Code Generation Options

:option:`-Ofast` Enables all the optimizations from :option:`-O3` along
with other aggressive optimizations that may violate strict compliance with
language standards. This is deprecated in favor of :option:`-O3`
in combination with :option:`-ffast-math`.
language standards. This is deprecated in Clang 19 and a warning is emitted
that :option:`-O3` in combination with :option:`-ffast-math` should be used
instead if the request for non-standard math behavior is intended. There
is no timeline yet for removal; the aim is to discourage use of
:option:`-Ofast` due to the surprising behavior of an optimization flag
changing the observable behavior of correct code.

:option:`-Os` Like :option:`-O2` with extra optimizations to reduce code
size.
Expand Down Expand Up @@ -699,6 +703,10 @@ Preprocessor Options

Do not search clang's builtin directory for include files.

.. option:: -nostdinc++

Do not search the system C++ standard library directory for include files.

.. option:: -fkeep-system-includes

Usable only with :option:`-E`. Do not copy the preprocessed content of
Expand Down
5 changes: 1 addition & 4 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1503,6 +1503,7 @@ Conditional ``explicit`` __cpp_conditional_explicit C+
``static operator()`` __cpp_static_call_operator C++23 C++03
Attributes on Lambda-Expressions C++23 C++11
Attributes on Structured Bindings __cpp_structured_bindings C++26 C++03
Pack Indexing __cpp_pack_indexing C++26 C++03
``= delete ("should have a reason");`` __cpp_deleted_function C++26 C++03
-------------------------------------------- -------------------------------- ------------- -------------
Designated initializers (N494) C99 C89
Expand Down Expand Up @@ -1615,10 +1616,6 @@ The following type trait primitives are supported by Clang. Those traits marked
* ``__is_nothrow_assignable`` (C++, MSVC 2013)
* ``__is_nothrow_constructible`` (C++, MSVC 2013)
* ``__is_nothrow_destructible`` (C++, MSVC 2013)
* ``__is_nullptr`` (C++, GNU, Microsoft, Embarcadero):
Returns true for ``std::nullptr_t`` and false for everything else. The
corresponding standard library feature is ``std::is_null_pointer``, but
``__is_null_pointer`` is already in use by some implementations.
* ``__is_object`` (C++, Embarcadero)
* ``__is_pod`` (C++, GNU, Microsoft, Embarcadero):
Note, the corresponding standard trait was deprecated in C++20.
Expand Down
9 changes: 8 additions & 1 deletion clang/docs/MemorySanitizer.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,18 @@ MemorySanitizer
Introduction
============

MemorySanitizer is a detector of uninitialized reads. It consists of a
MemorySanitizer is a detector of uninitialized memory use. It consists of a
compiler instrumentation module and a run-time library.

Typical slowdown introduced by MemorySanitizer is **3x**.

Here is a not comprehensive of list cases when MemorySanitizer will report an error:

* Uninitialized value was used in a conditional branch.
* Uninitialized pointer was used for memory accesses.
* Uninitialized value was passed or returned from a function call, which is considered an undefined behavior. The check can be disabled with ``-fno-sanitize-memory-param-retval``.
* Uninitialized data was passed into some libc calls.

How to build
============

Expand Down
9 changes: 8 additions & 1 deletion clang/docs/OpenMPSupport.rst
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@ implementation.
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
| device | user-defined mappers | :good:`done` | D56326,D58638,D58523,D58074,D60972,D59474 |
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
| device | map array-section with implicit mapper | :good:`done` | https://github.com/llvm/llvm-project/pull/101101 |
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
| device | mapping lambda expression | :good:`done` | D51107 |
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
| device | clause: use_device_addr for target data | :good:`done` | |
Expand Down Expand Up @@ -312,7 +314,7 @@ implementation.
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
| misc | assumes directives | :part:`worked on` | |
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
| misc | assume directive | :part:`worked on` | |
| misc | assume directive | :good:`done` | |
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
| misc | nothing directive | :good:`done` | D123286 |
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
Expand Down Expand Up @@ -358,5 +360,10 @@ considered for standardization. Please post on the
| device extension | `'ompx_hold' map type modifier | :good:`prototyped` | D106509, D106510 |
| | <https://openmp.llvm.org/docs/openacc/OpenMPExtensions.html#ompx-hold>`_ | | |
+------------------------------+-----------------------------------------------------------------------------------+--------------------------+--------------------------------------------------------+
| device extension | `'ompx_bare' clause on 'target teams' construct | :good:`prototyped` | #66844, #70612 |
| | <https://www.osti.gov/servlets/purl/2205717>`_ | | |
+------------------------------+-----------------------------------------------------------------------------------+--------------------------+--------------------------------------------------------+
| device extension | Multi-dim 'num_teams' clause on 'target teams ompx_bare' construct | :good:`partial` | #99732, #101407 |
+------------------------------+-----------------------------------------------------------------------------------+--------------------------+--------------------------------------------------------+

.. _Discourse forums (Runtimes - OpenMP category): https://discourse.llvm.org/c/runtimes/openmp/35
49 changes: 48 additions & 1 deletion clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,18 @@ These changes are ones which we think may surprise users when upgrading to
Clang |release| because of the opportunity they pose for disruption to existing
code bases.

- The ``le32`` and ``le64`` targets have been removed.

C/C++ Language Potentially Breaking Changes
-------------------------------------------

C++ Specific Potentially Breaking Changes
-----------------------------------------

- The type trait builtin ``__is_nullptr`` has been removed, since it has very
few users and can be written as ``__is_same(__remove_cv(T), decltype(nullptr))``,
which GCC supports as well.

ABI Changes in This Version
---------------------------

Expand All @@ -69,6 +75,9 @@ sections with improvements to Clang's support for those languages.

C++ Language Changes
--------------------
- Allow single element access of GCC vector/ext_vector_type object to be
constant expression. Supports the `V.xyzw` syntax and other tidbits
as seen in OpenCL. Selecting multiple elements is left as a future work.

C++17 Feature Support
^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -101,6 +110,9 @@ C2y Feature Support
C23 Feature Support
^^^^^^^^^^^^^^^^^^^

Non-comprehensive list of changes in this release
-------------------------------------------------

New Compiler Flags
------------------

Expand All @@ -124,13 +136,16 @@ Attribute Changes in Clang
- The ``hybrid_patchable`` attribute is now supported on ARM64EC targets. It can be used to specify
that a function requires an additional x86-64 thunk, which may be patched at runtime.

- Introduced a new attribute ``[[clang::coro_await_elidable]]`` on coroutine return types
to express elideability at call sites where the coroutine is co_awaited as a prvalue.

Improvements to Clang's diagnostics
-----------------------------------

- Some template related diagnostics have been improved.

.. code-block:: c++

void foo() { template <typename> int i; } // error: templates can only be declared in namespace or class scope

struct S {
Expand All @@ -144,6 +159,9 @@ Improvements to Clang's diagnostics
- Clang now diagnoses undefined behavior in constant expressions more consistently. This includes invalid shifts, and signed overflow in arithmetic.

- -Wdangling-assignment-gsl is enabled by default.
- Clang now does a better job preserving the template arguments as written when specializing concepts.
- Clang now always preserves the template arguments as written used
to specialize template type aliases.

Improvements to Clang's time-trace
----------------------------------
Expand All @@ -156,6 +174,8 @@ Bug Fixes in This Version

- Fixed the definition of ``ATOMIC_FLAG_INIT`` in ``<stdatomic.h>`` so it can
be used in C++.
- Fixed a failed assertion when checking required literal types in C context. (#GH101304).
- Fixed a crash when trying to transform a dependent address space type. Fixes #GH101685.

Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -170,6 +190,17 @@ Bug Fixes to C++ Support
- Fixed a failed assertion when checking invalid delete operator declaration. (#GH96191)
- Fix a crash when checking destructor reference with an invalid initializer. (#GH97230)
- Clang now correctly parses potentially declarative nested-name-specifiers in pointer-to-member declarators.
- Fix a crash when checking the initialzier of an object that was initialized
with a string literal. (#GH82167)
- Fix a crash when matching template template parameters with templates which have
parameters of different class type. (#GH101394)
- Clang now correctly recognizes the correct context for parameter
substitutions in concepts, so it doesn't incorrectly complain of missing
module imports in those situations. (#GH60336)
- Fix init-capture packs having a size of one before being instantiated. (#GH63677)
- Clang now preserves the unexpanded flag in a lambda transform used for pack expansion. (#GH56852), (#GH85667),
(#GH99877).
- Fixed a bug when diagnosing ambiguous explicit specializations of constrained member functions.

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -183,6 +214,9 @@ Miscellaneous Clang Crashes Fixed
- Fixed a crash in C due to incorrect lookup that members in nested anonymous struct/union
can be found as ordinary identifiers in struct/union definition. (#GH31295)

- Fixed a crash caused by long chains of ``sizeof`` and other similar operators
that can be followed by a non-parenthesized expression. (#GH45061)

OpenACC Specific Changes
------------------------

Expand Down Expand Up @@ -211,6 +245,10 @@ X86 Support
functions defined by the ``*mmintrin.h`` headers. A mapping can be
found in the file ``clang/www/builtins.py``.

- Support ISA of ``AVX10.2``.
* Supported MINMAX intrinsics of ``*_(mask(z)))_minmax(ne)_p[s|d|h|bh]`` and
``*_(mask(z)))_minmax_s[s|d|h]``.

Arm and AArch64 Support
^^^^^^^^^^^^^^^^^^^^^^^

Expand Down Expand Up @@ -296,9 +334,18 @@ Sanitizers

Python Binding Changes
----------------------
- Fixed an issue that led to crashes when calling ``Type.get_exception_specification_kind``.

OpenMP Support
--------------
- Added support for 'omp assume' directive.

Improvements
^^^^^^^^^^^^
- Improve the handling of mapping array-section for struct containing nested structs with user defined mappers

- `num_teams` now accepts multiple expressions when it is used along in ``target teams ompx_bare`` construct.
This allows the target region to be launched with multi-dim grid on GPUs.

Additional Information
======================
Expand Down
17 changes: 10 additions & 7 deletions clang/docs/StandardCPlusPlusModules.rst
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,16 @@ BMIs cannot be shipped in an archive to create a module library. Instead, the
BMIs(``*.pcm``) are compiled into object files(``*.o``) and those object files
are added to the archive instead.

clang-cl
~~~~~~~~

``clang-cl`` supports the same options as ``clang++`` for modules as detailed above;
there is no need to prefix these options with ``/clang:``. Note that ``cl.exe``
`options to emit/consume IFC files <https://devblogs.microsoft.com/cppblog/using-cpp-modules-in-msvc-from-the-command-line-part-1/>` are *not* supported.
The resultant precompiled modules are also not compatible for use with ``cl.exe``.

We recommend that build system authors use the above-mentioned ``clang++`` options with ``clang-cl`` to build modules.

Consistency Requirements
~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down Expand Up @@ -1387,13 +1397,6 @@ have ``.cppm`` (or ``.ccm``, ``.cxxm``, ``.c++m``) as the file extension.
However, the behavior is inconsistent with other compilers. This is tracked by
`#57416 <https://github.com/llvm/llvm-project/issues/57416>`_.

clang-cl is not compatible with standard C++ modules
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

``/clang:-fmodule-file`` and ``/clang:-fprebuilt-module-path`` cannot be used
to specify the BMI with ``clang-cl.exe``. This is tracked by
`#64118 <https://github.com/llvm/llvm-project/issues/64118>`_.

Incorrect ODR violation diagnostics
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down
6 changes: 6 additions & 0 deletions clang/docs/UsersManual.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4745,6 +4745,12 @@ Execute ``clang-cl /?`` to see a list of supported options:
-flto=<value> Set LTO mode to either 'full' or 'thin'
-flto Enable LTO in 'full' mode
-fmerge-all-constants Allow merging of constants
-fmodule-file=<module_name>=<module-file>
Use the specified module file that provides the module <module_name>
-fmodule-header=<header>
Build <header> as a C++20 header unit
-fmodule-output=<path>
Save intermediate module file results when compiling a standard C++ module unit.
-fms-compatibility-version=<value>
Dot-separated value representing the Microsoft compiler version
number to report in _MSC_VER (0 = don't define it; default is same value as installed cl.exe, or 1933)
Expand Down
40 changes: 37 additions & 3 deletions clang/docs/analyzer/checkers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2498,15 +2498,49 @@ Check for pointer arithmetic on locations other than array elements.

alpha.core.PointerSub (C)
"""""""""""""""""""""""""
Check for pointer subtractions on two pointers pointing to different memory chunks.
Check for pointer subtractions on two pointers pointing to different memory
chunks. According to the C standard §6.5.6 only subtraction of pointers that
point into (or one past the end) the same array object is valid (for this
purpose non-array variables are like arrays of size 1).

.. code-block:: c

void test() {
int x, y;
int d = &y - &x; // warn
int a, b, c[10], d[10];
int x = &c[3] - &c[1];
x = &d[4] - &c[1]; // warn: 'c' and 'd' are different arrays
x = (&a + 1) - &a;
x = &b - &a; // warn: 'a' and 'b' are different variables
x = (&a + 2) - &a; // warn: for a variable it is only valid to have a pointer
// to one past the address of it
x = &c[10] - &c[0];
x = &c[11] - &c[0]; // warn: index larger than one past the end
x = &c[-1] - &c[0]; // warn: negative index
}

struct S {
int x[10];
int y[10];
};

void test1() {
struct S a[10];
struct S b;
int d = &a[4] - &a[6];
d = &a[0].x[3] - &a[0].x[1];
d = a[0].y - a[0].x; // warn: 'S.b' and 'S.a' are different objects
d = (char *)&b.y - (char *)&b.x; // warn: different members of the same object
d = (char *)&b.y - (char *)&b; // warn: object of type S is not the same array as a member of it
}

There may be existing applications that use code like above for calculating
offsets of members in a structure, using pointer subtractions. This is still
undefined behavior according to the standard and code like this can be replaced
with the `offsetof` macro.

The checker only reports cases where stack-allocated objects are involved (no
warnings on pointers to memory allocated by `malloc`).

.. _alpha-core-StackAddressAsyncEscape:

alpha.core.StackAddressAsyncEscape (C)
Expand Down
1 change: 0 additions & 1 deletion clang/docs/tools/clang-formatted-files.txt
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,6 @@ clang/lib/Basic/Targets/BPF.cpp
clang/lib/Basic/Targets/BPF.h
clang/lib/Basic/Targets/Hexagon.h
clang/lib/Basic/Targets/Lanai.h
clang/lib/Basic/Targets/Le64.h
clang/lib/Basic/Targets/M68k.h
clang/lib/Basic/Targets/MSP430.h
clang/lib/Basic/Targets/NVPTX.cpp
Expand Down
9 changes: 8 additions & 1 deletion clang/include/clang-c/Index.h
Original file line number Diff line number Diff line change
Expand Up @@ -2154,6 +2154,10 @@ enum CXCursorKind {
*/
CXCursor_OMPInterchangeDirective = 308,

/** OpenMP assume directive.
*/
CXCursor_OMPAssumeDirective = 309,

/** OpenACC Compute Construct.
*/
CXCursor_OpenACCComputeConstruct = 320,
Expand Down Expand Up @@ -2974,7 +2978,10 @@ enum CXTypeKind {

CXType_ExtVector = 176,
CXType_Atomic = 177,
CXType_BTFTagAttributed = 178
CXType_BTFTagAttributed = 178,

// HLSL Intangible Types
CXType_HLSLResource = 179
};

/**
Expand Down
5 changes: 2 additions & 3 deletions clang/include/clang/AST/ASTConcept.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,8 @@ class ConstraintSatisfaction : public llvm::FoldingSetNode {
ConstraintSatisfaction() = default;

ConstraintSatisfaction(const NamedDecl *ConstraintOwner,
ArrayRef<TemplateArgument> TemplateArgs) :
ConstraintOwner(ConstraintOwner), TemplateArgs(TemplateArgs.begin(),
TemplateArgs.end()) { }
ArrayRef<TemplateArgument> TemplateArgs)
: ConstraintOwner(ConstraintOwner), TemplateArgs(TemplateArgs) {}

using SubstitutionDiagnostic = std::pair<SourceLocation, StringRef>;
using Detail = llvm::PointerUnion<Expr *, SubstitutionDiagnostic *>;
Expand Down
4 changes: 3 additions & 1 deletion clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -1173,6 +1173,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
#include "clang/Basic/WebAssemblyReferenceTypes.def"
#define AMDGPU_TYPE(Name, Id, SingletonId) CanQualType SingletonId;
#include "clang/Basic/AMDGPUTypes.def"
#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) CanQualType SingletonId;
#include "clang/Basic/HLSLIntangibleTypes.def"

// Types for deductions in C++0x [stmt.ranged]'s desugaring. Built on demand.
mutable QualType AutoDeductTy; // Deduction against 'auto'.
Expand Down Expand Up @@ -1369,7 +1371,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
bool AsWritten = false);

/// Get a function type and produce the equivalent function type where
/// pointer size address spaces in the return type and parameter tyeps are
/// pointer size address spaces in the return type and parameter types are
/// replaced with the default address space.
QualType getFunctionTypeWithoutPtrSizes(QualType T);

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 @@ -673,6 +673,9 @@ class alignas(8) Decl {
/// Whether this declaration comes from explicit global module.
bool isFromExplicitGlobalModule() const;

/// Whether this declaration comes from global module.
bool isFromGlobalModule() const;

/// Whether this declaration comes from a named module.
bool isInNamedModule() const;

Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/AST/DeclCXX.h
Original file line number Diff line number Diff line change
Expand Up @@ -1206,6 +1206,13 @@ class CXXRecordDecl : public RecordDecl {
return D.HasPublicFields || D.HasProtectedFields || D.HasPrivateFields;
}

/// If this is a standard-layout class or union, any and all data members will
/// be declared in the same type.
///
/// This retrieves the type where any fields are declared,
/// or the current class if there is no class with fields.
const CXXRecordDecl *getStandardLayoutBaseWithFields() const;

/// Whether this class is polymorphic (C++ [class.virtual]),
/// which means that the class contains or inherits a virtual function.
bool isPolymorphic() const { return data().Polymorphic; }
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -2991,6 +2991,9 @@ class CallExpr : public Expr {

bool hasStoredFPFeatures() const { return CallExprBits.HasFPFeatures; }

bool isCoroMustElide() const { return CallExprBits.IsCoroMustElide; }
void setCoroMustElide(bool V = true) { CallExprBits.IsCoroMustElide = V; }

Decl *getCalleeDecl() { return getCallee()->getReferencedDeclOfCallee(); }
const Decl *getCalleeDecl() const {
return getCallee()->getReferencedDeclOfCallee();
Expand Down
7 changes: 4 additions & 3 deletions clang/include/clang/AST/ExprCXX.h
Original file line number Diff line number Diff line change
Expand Up @@ -3229,7 +3229,7 @@ class UnresolvedLookupExpr final
const DeclarationNameInfo &NameInfo, bool RequiresADL,
const TemplateArgumentListInfo *TemplateArgs,
UnresolvedSetIterator Begin, UnresolvedSetIterator End,
bool KnownDependent);
bool KnownDependent, bool KnownInstantiationDependent);

UnresolvedLookupExpr(EmptyShell Empty, unsigned NumResults,
bool HasTemplateKWAndArgsInfo);
Expand All @@ -3248,7 +3248,7 @@ class UnresolvedLookupExpr final
NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &NameInfo, bool RequiresADL,
UnresolvedSetIterator Begin, UnresolvedSetIterator End,
bool KnownDependent);
bool KnownDependent, bool KnownInstantiationDependent);

// After canonicalization, there may be dependent template arguments in
// CanonicalConverted But none of Args is dependent. When any of
Expand All @@ -3258,7 +3258,8 @@ class UnresolvedLookupExpr final
NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo, bool RequiresADL,
const TemplateArgumentListInfo *Args, UnresolvedSetIterator Begin,
UnresolvedSetIterator End, bool KnownDependent);
UnresolvedSetIterator End, bool KnownDependent,
bool KnownInstantiationDependent);

static UnresolvedLookupExpr *CreateEmpty(const ASTContext &Context,
unsigned NumResults,
Expand Down
317 changes: 286 additions & 31 deletions clang/include/clang/AST/OpenMPClause.h
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,66 @@ template <class T> class OMPVarListClause : public OMPClause {
}
};

/// Class that represents a list of directive kinds (parallel, target, etc.)
/// as used in \c absent, \c contains clauses.
template <class T> class OMPDirectiveListClause : public OMPClause {
/// Location of '('.
SourceLocation LParenLoc;

protected:
/// Number of directive kinds listed in the clause
unsigned NumKinds;

public:
/// Build a clause with \a NumKinds directive kinds.
///
/// \param K The clause kind.
/// \param StartLoc Starting location of the clause (the clause keyword).
/// \param LParenLoc Location of '('.
/// \param EndLoc Ending location of the clause.
/// \param NumKinds Number of directive kinds listed in the clause.
OMPDirectiveListClause(OpenMPClauseKind K, SourceLocation StartLoc,
SourceLocation LParenLoc, SourceLocation EndLoc,
unsigned NumKinds)
: OMPClause(K, StartLoc, EndLoc), LParenLoc(LParenLoc),
NumKinds(NumKinds) {}

child_range children() {
return child_range(child_iterator(), child_iterator());
}

const_child_range children() const {
return const_child_range(const_child_iterator(), const_child_iterator());
}

child_range used_children() {
return child_range(child_iterator(), child_iterator());
}
const_child_range used_children() const {
return const_child_range(const_child_iterator(), const_child_iterator());
}

MutableArrayRef<OpenMPDirectiveKind> getDirectiveKinds() {
return MutableArrayRef<OpenMPDirectiveKind>(
static_cast<T *>(this)
->template getTrailingObjects<OpenMPDirectiveKind>(),
NumKinds);
}

void setDirectiveKinds(ArrayRef<OpenMPDirectiveKind> DK) {
assert(
DK.size() == NumKinds &&
"Number of directive kinds is not the same as the preallocated buffer");
std::copy(DK.begin(), DK.end(),
static_cast<T *>(this)
->template getTrailingObjects<OpenMPDirectiveKind>());
}

SourceLocation getLParenLoc() { return LParenLoc; }

void setLParenLoc(SourceLocation S) { LParenLoc = S; }
};

/// This represents 'allocator' clause in the '#pragma omp ...'
/// directive.
///
Expand Down Expand Up @@ -2013,6 +2073,184 @@ class OMPMergeableClause : public OMPClause {
}
};

/// This represents the 'absent' clause in the '#pragma omp assume'
/// directive.
///
/// \code
/// #pragma omp assume absent(<directive-name list>)
/// \endcode
/// In this example directive '#pragma omp assume' has an 'absent' clause.
class OMPAbsentClause final
: public OMPDirectiveListClause<OMPAbsentClause>,
private llvm::TrailingObjects<OMPAbsentClause, OpenMPDirectiveKind> {
friend OMPDirectiveListClause;
friend TrailingObjects;

/// Build 'absent' clause.
///
/// \param StartLoc Starting location of the clause.
/// \param LParenLoc Location of '('.
/// \param EndLoc Ending location of the clause.
/// \param NumKinds Number of directive kinds listed in the clause.
OMPAbsentClause(SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation EndLoc, unsigned NumKinds)
: OMPDirectiveListClause<OMPAbsentClause>(
llvm::omp::OMPC_absent, StartLoc, LParenLoc, EndLoc, NumKinds) {}

/// Build an empty clause.
OMPAbsentClause(unsigned NumKinds)
: OMPDirectiveListClause<OMPAbsentClause>(
llvm::omp::OMPC_absent, SourceLocation(), SourceLocation(),
SourceLocation(), NumKinds) {}

public:
static OMPAbsentClause *Create(const ASTContext &C,
ArrayRef<OpenMPDirectiveKind> DKVec,
SourceLocation Loc, SourceLocation LLoc,
SourceLocation RLoc);

static OMPAbsentClause *CreateEmpty(const ASTContext &C, unsigned NumKinds);

static bool classof(const OMPClause *C) {
return C->getClauseKind() == llvm::omp::OMPC_absent;
}
};

/// This represents the 'contains' clause in the '#pragma omp assume'
/// directive.
///
/// \code
/// #pragma omp assume contains(<directive-name list>)
/// \endcode
/// In this example directive '#pragma omp assume' has a 'contains' clause.
class OMPContainsClause final
: public OMPDirectiveListClause<OMPContainsClause>,
private llvm::TrailingObjects<OMPContainsClause, OpenMPDirectiveKind> {
friend OMPDirectiveListClause;
friend TrailingObjects;

/// Build 'contains' clause.
///
/// \param StartLoc Starting location of the clause.
/// \param LParenLoc Location of '('.
/// \param EndLoc Ending location of the clause.
/// \param NumKinds Number of directive kinds listed in the clause.
OMPContainsClause(SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation EndLoc, unsigned NumKinds)
: OMPDirectiveListClause<OMPContainsClause>(
llvm::omp::OMPC_contains, StartLoc, LParenLoc, EndLoc, NumKinds) {}

/// Build an empty clause.
OMPContainsClause(unsigned NumKinds)
: OMPDirectiveListClause<OMPContainsClause>(
llvm::omp::OMPC_contains, SourceLocation(), SourceLocation(),
SourceLocation(), NumKinds) {}

public:
static OMPContainsClause *Create(const ASTContext &C,
ArrayRef<OpenMPDirectiveKind> DKVec,
SourceLocation Loc, SourceLocation LLoc,
SourceLocation RLoc);

static OMPContainsClause *CreateEmpty(const ASTContext &C, unsigned NumKinds);

static bool classof(const OMPClause *C) {
return C->getClauseKind() == llvm::omp::OMPC_contains;
}
};

/// This represents the 'holds' clause in the '#pragma omp assume'
/// directive.
///
/// \code
/// #pragma omp assume holds(<expr>)
/// \endcode
/// In this example directive '#pragma omp assume' has a 'holds' clause.
class OMPHoldsClause final
: public OMPOneStmtClause<llvm::omp::OMPC_holds, OMPClause> {
friend class OMPClauseReader;

public:
/// Build 'holds' clause.
///
/// \param StartLoc Starting location of the clause.
/// \param EndLoc Ending location of the clause.
OMPHoldsClause(Expr *E, SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation EndLoc)
: OMPOneStmtClause(E, StartLoc, LParenLoc, EndLoc) {}

/// Build an empty clause.
OMPHoldsClause() : OMPOneStmtClause() {}

Expr *getExpr() const { return getStmtAs<Expr>(); }
void setExpr(Expr *E) { setStmt(E); }
};

/// This represents the 'no_openmp' clause in the '#pragma omp assume'
/// directive.
///
/// \code
/// #pragma omp assume no_openmp
/// \endcode
/// In this example directive '#pragma omp assume' has a 'no_openmp' clause.
class OMPNoOpenMPClause final
: public OMPNoChildClause<llvm::omp::OMPC_no_openmp> {
public:
/// Build 'no_openmp' clause.
///
/// \param StartLoc Starting location of the clause.
/// \param EndLoc Ending location of the clause.
OMPNoOpenMPClause(SourceLocation StartLoc, SourceLocation EndLoc)
: OMPNoChildClause(StartLoc, EndLoc) {}

/// Build an empty clause.
OMPNoOpenMPClause() : OMPNoChildClause() {}
};

/// This represents the 'no_openmp_routines' clause in the '#pragma omp assume'
/// directive.
///
/// \code
/// #pragma omp assume no_openmp_routines
/// \endcode
/// In this example directive '#pragma omp assume' has a 'no_openmp_routines'
/// clause.
class OMPNoOpenMPRoutinesClause final
: public OMPNoChildClause<llvm::omp::OMPC_no_openmp_routines> {
public:
/// Build 'no_openmp_routines' clause.
///
/// \param StartLoc Starting location of the clause.
/// \param EndLoc Ending location of the clause.
OMPNoOpenMPRoutinesClause(SourceLocation StartLoc, SourceLocation EndLoc)
: OMPNoChildClause(StartLoc, EndLoc) {}

/// Build an empty clause.
OMPNoOpenMPRoutinesClause() : OMPNoChildClause() {}
};

/// This represents the 'no_parallelism' clause in the '#pragma omp assume'
/// directive.
///
/// \code
/// #pragma omp assume no_parallelism
/// \endcode
/// In this example directive '#pragma omp assume' has a 'no_parallelism'
/// clause.
class OMPNoParallelismClause final
: public OMPNoChildClause<llvm::omp::OMPC_no_parallelism> {
public:
/// Build 'no_parallelism' clause.
///
/// \param StartLoc Starting location of the clause.
/// \param EndLoc Ending location of the clause.
OMPNoParallelismClause(SourceLocation StartLoc, SourceLocation EndLoc)
: OMPNoChildClause(StartLoc, EndLoc) {}

/// Build an empty clause.
OMPNoParallelismClause() : OMPNoChildClause() {}
};

/// This represents 'read' clause in the '#pragma omp atomic' directive.
///
/// \code
Expand Down Expand Up @@ -6131,60 +6369,77 @@ class OMPMapClause final : public OMPMappableExprListClause<OMPMapClause>,
/// \endcode
/// In this example directive '#pragma omp teams' has clause 'num_teams'
/// with single expression 'n'.
class OMPNumTeamsClause : public OMPClause, public OMPClauseWithPreInit {
friend class OMPClauseReader;
///
/// When 'ompx_bare' clause exists on a 'target' directive, 'num_teams' clause
/// can accept up to three expressions.
///
/// \code
/// #pragma omp target teams ompx_bare num_teams(x, y, z)
/// \endcode
class OMPNumTeamsClause final
: public OMPVarListClause<OMPNumTeamsClause>,
public OMPClauseWithPreInit,
private llvm::TrailingObjects<OMPNumTeamsClause, Expr *> {
friend OMPVarListClause;
friend TrailingObjects;

/// Location of '('.
SourceLocation LParenLoc;

/// NumTeams number.
Stmt *NumTeams = nullptr;
OMPNumTeamsClause(const ASTContext &C, SourceLocation StartLoc,
SourceLocation LParenLoc, SourceLocation EndLoc, unsigned N)
: OMPVarListClause(llvm::omp::OMPC_num_teams, StartLoc, LParenLoc, EndLoc,
N),
OMPClauseWithPreInit(this) {}

/// Set the NumTeams number.
///
/// \param E NumTeams number.
void setNumTeams(Expr *E) { NumTeams = E; }
/// Build an empty clause.
OMPNumTeamsClause(unsigned N)
: OMPVarListClause(llvm::omp::OMPC_num_teams, SourceLocation(),
SourceLocation(), SourceLocation(), N),
OMPClauseWithPreInit(this) {}

public:
/// Build 'num_teams' clause.
/// Creates clause with a list of variables \a VL.
///
/// \param E Expression associated with this clause.
/// \param HelperE Helper Expression associated with this clause.
/// \param CaptureRegion Innermost OpenMP region where expressions in this
/// clause must be captured.
/// \param C AST context.
/// \param StartLoc Starting location of the clause.
/// \param LParenLoc Location of '('.
/// \param EndLoc Ending location of the clause.
OMPNumTeamsClause(Expr *E, Stmt *HelperE, OpenMPDirectiveKind CaptureRegion,
SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation EndLoc)
: OMPClause(llvm::omp::OMPC_num_teams, StartLoc, EndLoc),
OMPClauseWithPreInit(this), LParenLoc(LParenLoc), NumTeams(E) {
setPreInitStmt(HelperE, CaptureRegion);
}
/// \param VL List of references to the variables.
/// \param PreInit
static OMPNumTeamsClause *
Create(const ASTContext &C, OpenMPDirectiveKind CaptureRegion,
SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation EndLoc, ArrayRef<Expr *> VL, Stmt *PreInit);

/// Build an empty clause.
OMPNumTeamsClause()
: OMPClause(llvm::omp::OMPC_num_teams, SourceLocation(),
SourceLocation()),
OMPClauseWithPreInit(this) {}
/// Creates an empty clause with \a N variables.
///
/// \param C AST context.
/// \param N The number of variables.
static OMPNumTeamsClause *CreateEmpty(const ASTContext &C, unsigned N);

/// Sets the location of '('.
void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }

/// Returns the location of '('.
SourceLocation getLParenLoc() const { return LParenLoc; }

/// Return NumTeams number.
Expr *getNumTeams() { return cast<Expr>(NumTeams); }
/// Return NumTeams expressions.
ArrayRef<Expr *> getNumTeams() { return getVarRefs(); }

/// Return NumTeams number.
Expr *getNumTeams() const { return cast<Expr>(NumTeams); }
/// Return NumTeams expressions.
ArrayRef<Expr *> getNumTeams() const {
return const_cast<OMPNumTeamsClause *>(this)->getNumTeams();
}

child_range children() { return child_range(&NumTeams, &NumTeams + 1); }
child_range children() {
return child_range(reinterpret_cast<Stmt **>(varlist_begin()),
reinterpret_cast<Stmt **>(varlist_end()));
}

const_child_range children() const {
return const_child_range(&NumTeams, &NumTeams + 1);
auto Children = const_cast<OMPNumTeamsClause *>(this)->children();
return const_child_range(Children.begin(), Children.end());
}

child_range used_children() {
Expand Down
37 changes: 36 additions & 1 deletion clang/include/clang/AST/RecursiveASTVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -3238,6 +3238,9 @@ DEF_TRAVERSE_STMT(OMPParallelGenericLoopDirective,
DEF_TRAVERSE_STMT(OMPTargetParallelGenericLoopDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })

DEF_TRAVERSE_STMT(OMPAssumeDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })

DEF_TRAVERSE_STMT(OMPErrorDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })

Expand Down Expand Up @@ -3480,6 +3483,38 @@ bool RecursiveASTVisitor<Derived>::VisitOMPAcqRelClause(OMPAcqRelClause *) {
return true;
}

template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPAbsentClause(OMPAbsentClause *) {
return true;
}

template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPHoldsClause(OMPHoldsClause *) {
return true;
}

template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPContainsClause(OMPContainsClause *) {
return true;
}

template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPNoOpenMPClause(OMPNoOpenMPClause *) {
return true;
}

template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPNoOpenMPRoutinesClause(
OMPNoOpenMPRoutinesClause *) {
return true;
}

template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPNoParallelismClause(
OMPNoParallelismClause *) {
return true;
}

template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPAcquireClause(OMPAcquireClause *) {
return true;
Expand Down Expand Up @@ -3793,8 +3828,8 @@ bool RecursiveASTVisitor<Derived>::VisitOMPMapClause(OMPMapClause *C) {
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPNumTeamsClause(
OMPNumTeamsClause *C) {
TRY_TO(VisitOMPClauseList(C));
TRY_TO(VisitOMPClauseWithPreInit(C));
TRY_TO(TraverseStmt(C->getNumTeams()));
return true;
}

Expand Down
5 changes: 4 additions & 1 deletion clang/include/clang/AST/Stmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -561,8 +561,11 @@ class alignas(void *) Stmt {
LLVM_PREFERRED_TYPE(bool)
unsigned HasFPFeatures : 1;

/// True if the call expression is a must-elide call to a coroutine.
unsigned IsCoroMustElide : 1;

/// Padding used to align OffsetToTrailingObjects to a byte multiple.
unsigned : 24 - 3 - NumExprBits;
unsigned : 24 - 4 - NumExprBits;

/// The offset in bytes from the this pointer to the start of the
/// trailing objects belonging to CallExpr. Intentionally byte sized
Expand Down
30 changes: 30 additions & 0 deletions clang/include/clang/AST/StmtOpenMP.h
Original file line number Diff line number Diff line change
Expand Up @@ -6468,6 +6468,36 @@ class OMPErrorDirective final : public OMPExecutableDirective {
return T->getStmtClass() == OMPErrorDirectiveClass;
}
};

// It's not really an executable directive, but it seems convenient to use
// that as the parent class.
class OMPAssumeDirective final : public OMPExecutableDirective {
friend class ASTStmtReader;
friend class OMPExecutableDirective;

private:
OMPAssumeDirective(SourceLocation StartLoc, SourceLocation EndLoc)
: OMPExecutableDirective(OMPAssumeDirectiveClass, llvm::omp::OMPD_assume,
StartLoc, EndLoc) {}

explicit OMPAssumeDirective()
: OMPExecutableDirective(OMPAssumeDirectiveClass, llvm::omp::OMPD_assume,
SourceLocation(), SourceLocation()) {}

public:
static OMPAssumeDirective *Create(const ASTContext &Ctx,
SourceLocation StartLoc,
SourceLocation EndLoc,
ArrayRef<OMPClause *> Clauses, Stmt *AStmt);

static OMPAssumeDirective *CreateEmpty(const ASTContext &C,
unsigned NumClauses, EmptyShell);

static bool classof(const Stmt *T) {
return T->getStmtClass() == OMPAssumeDirectiveClass;
}
};

} // end namespace clang

#endif
25 changes: 25 additions & 0 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -2509,6 +2509,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
bool isFunctionNoProtoType() const { return getAs<FunctionNoProtoType>(); }
bool isFunctionProtoType() const { return getAs<FunctionProtoType>(); }
bool isPointerType() const;
bool isPointerOrReferenceType() const;
bool isSignableType() const;
bool isAnyPointerType() const; // Any C pointer or ObjC object pointer
bool isCountAttributedType() const;
Expand Down Expand Up @@ -2629,6 +2630,10 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
bool isBitIntType() const; // Bit-precise integer type
bool isOpenCLSpecificType() const; // Any OpenCL specific type

#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) bool is##Id##Type() const;
#include "clang/Basic/HLSLIntangibleTypes.def"
bool isHLSLSpecificType() const; // Any HLSL specific type

/// Determines if this type, which must satisfy
/// isObjCLifetimeType(), is implicitly __unsafe_unretained rather
/// than implicitly __strong.
Expand Down Expand Up @@ -3021,6 +3026,9 @@ class BuiltinType : public Type {
// AMDGPU types
#define AMDGPU_TYPE(Name, Id, SingletonId) Id,
#include "clang/Basic/AMDGPUTypes.def"
// HLSL intangible Types
#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) Id,
#include "clang/Basic/HLSLIntangibleTypes.def"
// All other builtin types
#define BUILTIN_TYPE(Id, SingletonId) Id,
#define LAST_BUILTIN_TYPE(Id) LastKind = Id
Expand Down Expand Up @@ -7996,6 +8004,10 @@ inline bool Type::isPointerType() const {
return isa<PointerType>(CanonicalType);
}

inline bool Type::isPointerOrReferenceType() const {
return isPointerType() || isReferenceType();
}

inline bool Type::isAnyPointerType() const {
return isPointerType() || isObjCObjectPointerType();
}
Expand Down Expand Up @@ -8256,6 +8268,19 @@ inline bool Type::isOpenCLSpecificType() const {
isQueueT() || isReserveIDT() || isPipeType() || isOCLExtOpaqueType();
}

#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) \
inline bool Type::is##Id##Type() const { \
return isSpecificBuiltinType(BuiltinType::Id); \
}
#include "clang/Basic/HLSLIntangibleTypes.def"

inline bool Type::isHLSLSpecificType() const {
#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) is##Id##Type() ||
return
#include "clang/Basic/HLSLIntangibleTypes.def"
false; // end boolean or operation
}

inline bool Type::isTemplateTypeParmType() const {
return isa<TemplateTypeParmType>(CanonicalType);
}
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/AST/TypeProperties.td
Original file line number Diff line number Diff line change
Expand Up @@ -872,6 +872,10 @@ let Class = BuiltinType in {
case BuiltinType::ID: return ctx.SINGLETON_ID;
#include "clang/Basic/AMDGPUTypes.def"

#define HLSL_INTANGIBLE_TYPE(NAME, ID, SINGLETON_ID) \
case BuiltinType::ID: return ctx.SINGLETON_ID;
#include "clang/Basic/HLSLIntangibleTypes.def"

#define BUILTIN_TYPE(ID, SINGLETON_ID) \
case BuiltinType::ID: return ctx.SINGLETON_ID;
#include "clang/AST/BuiltinTypes.def"
Expand Down
19 changes: 19 additions & 0 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -1220,6 +1220,14 @@ def CoroDisableLifetimeBound : InheritableAttr {
let SimpleHandler = 1;
}

def CoroAwaitElidable : InheritableAttr {
let Spellings = [Clang<"coro_await_elidable">];
let Subjects = SubjectList<[CXXRecord]>;
let LangOpts = [CPlusPlus];
let Documentation = [CoroAwaitElidableDoc];
let SimpleHandler = 1;
}

// OSObject-based attributes.
def OSConsumed : InheritableParamAttr {
let Spellings = [Clang<"os_consumed">];
Expand Down Expand Up @@ -2050,6 +2058,17 @@ def Convergent : InheritableAttr {
let SimpleHandler = 1;
}

def NoConvergent : InheritableAttr {
let Spellings = [Clang<"noconvergent">, Declspec<"noconvergent">];
let Subjects = SubjectList<[Function, Stmt], WarnDiag,
"functions and statements">;
let LangOpts = [CUDA];
let Documentation = [NoConvergentDocs];
let SimpleHandler = 1;
}

def : MutualExclusions<[Convergent, NoConvergent]>;

def NoInline : DeclOrStmtAttr {
let Spellings = [CustomKeyword<"__noinline__">, GCC<"noinline">,
CXX11<"clang", "noinline">, C23<"clang", "noinline">,
Expand Down
61 changes: 60 additions & 1 deletion clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -1382,6 +1382,34 @@ Sample usage:
}];
}

def NoConvergentDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
This attribute prevents a function from being treated as convergent, which
means that optimizations can only move calls to that function to
control-equivalent blocks. If a statement is marked as ``noconvergent`` and
contains calls, it also prevents those calls from being treated as convergent.
In other words, those calls are not restricted to only being moved to
control-equivalent blocks.

In languages following SPMD/SIMT programming model, e.g., CUDA/HIP, function
declarations and calls are treated as convergent by default for correctness.
This ``noconvergent`` attribute is helpful for developers to prevent them from
being treated as convergent when it's safe.

.. code-block:: c

__device__ float bar(float);
__device__ float foo(float) __attribute__((noconvergent)) {}

__device__ int example(void) {
float x;
[[clang::noconvergent]] x = bar(x);
}

}];
}

def NoSplitStackDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
Expand Down Expand Up @@ -8119,6 +8147,38 @@ but do not pass them to the underlying coroutine or pass them by value.
}];
}

def CoroAwaitElidableDoc : Documentation {
let Category = DocCatDecl;
let Content = [{
The ``[[clang::coro_await_elidable]]`` is a class attribute which can be applied
to a coroutine return type.

When a coroutine function that returns such a type calls another coroutine function,
the compiler performs heap allocation elision when the call to the coroutine function
is immediately co_awaited as a prvalue. In this case, the coroutine frame for the
callee will be a local variable within the enclosing braces in the caller's stack
frame. And the local variable, like other variables in coroutines, may be collected
into the coroutine frame, which may be allocated on the heap.

Example:

.. code-block:: c++

class [[clang::coro_await_elidable]] Task { ... };

Task foo();
Task bar() {
co_await foo(); // foo()'s coroutine frame on this line is elidable
auto t = foo(); // foo()'s coroutine frame on this line is NOT elidable
co_await t;
}

The behavior is undefined if the caller coroutine is destroyed earlier than the
callee coroutine.

}];
}

def CountedByDocs : Documentation {
let Category = DocCatField;
let Content = [{
Expand Down Expand Up @@ -8278,4 +8338,3 @@ Declares that a function potentially allocates heap memory, and prevents any pot
of ``nonallocating`` by the compiler.
}];
}

Loading