25 changes: 23 additions & 2 deletions libc/src/__support/time/linux/clock_gettime.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,37 @@

#ifndef LLVM_LIBC_SRC___SUPPORT_TIME_LINUX_CLOCK_GETTIME_H
#define LLVM_LIBC_SRC___SUPPORT_TIME_LINUX_CLOCK_GETTIME_H

#include "hdr/types/clockid_t.h"
#include "hdr/types/struct_timespec.h"
#include "src/__support/OSUtil/syscall.h"
#include "src/__support/common.h"

#include "src/__support/error_or.h"
#include <sys/syscall.h>

namespace LIBC_NAMESPACE {
namespace internal {
ErrorOr<int> clock_gettime(clockid_t clockid, timespec *ts);
LIBC_INLINE ErrorOr<int> clock_gettime(clockid_t clockid, timespec *ts) {
#if SYS_clock_gettime
int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_clock_gettime,
static_cast<long>(clockid),
reinterpret_cast<long>(ts));
#elif defined(SYS_clock_gettime64)
static_assert(
sizeof(time_t) == sizeof(int64_t),
"SYS_clock_gettime64 requires struct timespec with 64-bit members.");
int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_clock_gettime64,
static_cast<long>(clockid),
reinterpret_cast<long>(ts));
#else
#error "SYS_clock_gettime and SYS_clock_gettime64 syscalls not available."
#endif
if (ret < 0)
return Error(-ret);
return ret;
}

} // namespace internal
} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC___SUPPORT_TIME_LINUX_CLOCK_GETTIME_H
43 changes: 43 additions & 0 deletions libc/src/__support/time/linux/monotonicity.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//===--- timeout linux implementation ---------------------------*- 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
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SRC___SUPPORT_TIME_LINUX_MONOTONICITY_H
#define LLVM_LIBC_SRC___SUPPORT_TIME_LINUX_MONOTONICITY_H

#include "hdr/time_macros.h"
#include "src/__support/libc_assert.h"
#include "src/__support/time/linux/abs_timeout.h"
#include "src/__support/time/linux/clock_conversion.h"
namespace LIBC_NAMESPACE {
namespace internal {
// This function is separated from abs_timeout.
// This function pulls in the dependency to clock_conversion.h,
// which may transitively depend on vDSO hence futex. However, this structure
// would be passed to futex, so we need to avoid cyclic dependencies.
// This function is going to be used in timed locks. Pthread generally uses
// realtime clocks for timeouts. However, due to non-monotoncity, realtime
// clocks reportedly lead to undesired behaviors. Therefore, we also provide a
// method to convert the timespec to a monotonic clock relative to the time of
// function call.
LIBC_INLINE void ensure_monotonicity(AbsTimeout &timeout) {
if (timeout.is_realtime()) {
auto res = AbsTimeout::from_timespec(
convert_clock(timeout.get_timespec(), CLOCK_REALTIME, CLOCK_MONOTONIC),
false);

LIBC_ASSERT(res.has_value());
if (!res.has_value())
__builtin_unreachable();

timeout = *res;
}
}
} // namespace internal
} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC___SUPPORT_TIME_LINUX_MONOTONICITY_H
12 changes: 6 additions & 6 deletions libc/src/__support/time/units.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,22 @@
namespace LIBC_NAMESPACE {
namespace time_units {
LIBC_INLINE constexpr time_t operator""_s_ns(unsigned long long s) {
return s * 1'000'000'000;
return static_cast<time_t>(s * 1'000'000'000);
}
LIBC_INLINE constexpr time_t operator""_s_us(unsigned long long s) {
return s * 1'000'000;
return static_cast<time_t>(s * 1'000'000);
}
LIBC_INLINE constexpr time_t operator""_s_ms(unsigned long long s) {
return s * 1'000;
return static_cast<time_t>(s * 1'000);
}
LIBC_INLINE constexpr time_t operator""_ms_ns(unsigned long long ms) {
return ms * 1'000'000;
return static_cast<time_t>(ms * 1'000'000);
}
LIBC_INLINE constexpr time_t operator""_ms_us(unsigned long long ms) {
return ms * 1'000;
return static_cast<time_t>(ms * 1'000);
}
LIBC_INLINE constexpr time_t operator""_us_ns(unsigned long long us) {
return us * 1'000;
return static_cast<time_t>(us * 1'000);
}
} // namespace time_units
} // namespace LIBC_NAMESPACE
Expand Down
2 changes: 1 addition & 1 deletion libc/src/errno/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ add_entrypoint_object(
COMPILE_OPTIONS
${full_build_flag}
DEPENDS
libc.include.errno
libc.hdr.errno_macros
libc.src.__support.common
)
3 changes: 0 additions & 3 deletions libc/src/errno/libc_errno.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,6 @@ void LIBC_NAMESPACE::Errno::operator=(int a) { __llvmlibc_errno = a; }
LIBC_NAMESPACE::Errno::operator int() { return __llvmlibc_errno; }

#else
// In overlay mode, we simply use the system errno.
#include <errno.h>

void LIBC_NAMESPACE::Errno::operator=(int a) { errno = a; }
LIBC_NAMESPACE::Errno::operator int() { return errno; }

Expand Down
6 changes: 1 addition & 5 deletions libc/src/errno/libc_errno.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,7 @@
#include "src/__support/macros/attributes.h"
#include "src/__support/macros/properties/architectures.h"

// TODO: https://github.com/llvm/llvm-project/issues/80172
// Separate just the definition of errno numbers in
// include/llvm-libc-macros/* and only include that instead of the system
// <errno.h>.
#include <errno.h>
#include "hdr/errno_macros.h"

// This header is to be consumed by internal implementations, in which all of
// them should refer to `libc_errno` instead of using `errno` directly from
Expand Down
16 changes: 14 additions & 2 deletions libc/src/string/memory_utils/x86_64/inline_memcpy.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,13 @@ inline_memcpy_x86_sse2_ge64_sw_prefetching(Ptr __restrict dst,
offset += K_THREE_CACHELINES;
}
}
return builtin::Memcpy<32>::loop_and_tail_offset(dst, src, count, offset);
// We don't use 'loop_and_tail_offset' because it assumes at least one
// iteration of the loop.
while (offset + 32 <= count) {
builtin::Memcpy<32>::block_offset(dst, src, offset);
offset += 32;
}
return builtin::Memcpy<32>::tail(dst, src, count);
}

[[maybe_unused]] LIBC_INLINE void
Expand Down Expand Up @@ -139,7 +145,13 @@ inline_memcpy_x86_avx_ge64_sw_prefetching(Ptr __restrict dst,
builtin::Memcpy<K_THREE_CACHELINES>::block_offset(dst, src, offset);
offset += K_THREE_CACHELINES;
}
return builtin::Memcpy<64>::loop_and_tail_offset(dst, src, count, offset);
// We don't use 'loop_and_tail_offset' because it assumes at least one
// iteration of the loop.
while (offset + 64 <= count) {
builtin::Memcpy<64>::block_offset(dst, src, offset);
offset += 64;
}
return builtin::Memcpy<64>::tail(dst, src, count);
}

[[maybe_unused]] LIBC_INLINE void
Expand Down
1 change: 1 addition & 0 deletions libc/test/src/__support/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -206,3 +206,4 @@ add_subdirectory(OSUtil)
add_subdirectory(FPUtil)
add_subdirectory(fixed_point)
add_subdirectory(HashTable)
add_subdirectory(time)
5 changes: 5 additions & 0 deletions libc/test/src/__support/time/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
add_custom_target(libc-support-time-tests)

if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
add_subdirectory(${LIBC_TARGET_OS})
endif()
9 changes: 9 additions & 0 deletions libc/test/src/__support/time/linux/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
add_libc_test(
timeout_test
SUITE libc-support-time-tests
SRCS timeout_test.cpp
DEPENDS
libc.src.__support.time.linux.abs_timeout
libc.src.__support.time.linux.monotonicity
libc.src.__support.CPP.expected
)
60 changes: 60 additions & 0 deletions libc/test/src/__support/time/linux/timeout_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//===-- unit tests for linux's timeout utilities --------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/__support/CPP/expected.h"
#include "src/__support/time/linux/abs_timeout.h"
#include "src/__support/time/linux/monotonicity.h"
#include "test/UnitTest/Test.h"

template <class T, class E>
using expected = LIBC_NAMESPACE::cpp::expected<T, E>;
using AbsTimeout = LIBC_NAMESPACE::internal::AbsTimeout;

TEST(LlvmLibcSupportLinuxTimeoutTest, NegativeSecond) {
timespec ts = {-1, 0};
expected<AbsTimeout, AbsTimeout::Error> result =
AbsTimeout::from_timespec(ts, false);
ASSERT_FALSE(result.has_value());
ASSERT_EQ(result.error(), AbsTimeout::Error::BeforeEpoch);
}
TEST(LlvmLibcSupportLinuxTimeoutTest, OverflowNano) {
using namespace LIBC_NAMESPACE::time_units;
timespec ts = {0, 2_s_ns};
expected<AbsTimeout, AbsTimeout::Error> result =
AbsTimeout::from_timespec(ts, false);
ASSERT_FALSE(result.has_value());
ASSERT_EQ(result.error(), AbsTimeout::Error::Invalid);
}
TEST(LlvmLibcSupportLinuxTimeoutTest, UnderflowNano) {
timespec ts = {0, -1};
expected<AbsTimeout, AbsTimeout::Error> result =
AbsTimeout::from_timespec(ts, false);
ASSERT_FALSE(result.has_value());
ASSERT_EQ(result.error(), AbsTimeout::Error::Invalid);
}
TEST(LlvmLibcSupportLinuxTimeoutTest, NoChangeIfClockIsMonotonic) {
timespec ts = {10000, 0};
expected<AbsTimeout, AbsTimeout::Error> result =
AbsTimeout::from_timespec(ts, false);
ASSERT_TRUE(result.has_value());
ensure_monotonicity(*result);
ASSERT_FALSE(result->is_realtime());
ASSERT_EQ(result->get_timespec().tv_sec, static_cast<time_t>(10000));
ASSERT_EQ(result->get_timespec().tv_nsec, static_cast<time_t>(0));
}
TEST(LlvmLibcSupportLinuxTimeoutTest, ValidAfterConversion) {
timespec ts;
LIBC_NAMESPACE::internal::clock_gettime(CLOCK_REALTIME, &ts);
expected<AbsTimeout, AbsTimeout::Error> result =
AbsTimeout::from_timespec(ts, true);
ASSERT_TRUE(result.has_value());
ensure_monotonicity(*result);
ASSERT_FALSE(result->is_realtime());
ASSERT_TRUE(
AbsTimeout::from_timespec(result->get_timespec(), false).has_value());
}
41 changes: 41 additions & 0 deletions libc/test/src/string/memcpy_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,14 @@
//===----------------------------------------------------------------------===//

#include "memory_utils/memory_check_utils.h"
#include "src/__support/macros/properties/os.h" // LIBC_TARGET_OS_IS_LINUX
#include "src/string/memcpy.h"
#include "test/UnitTest/Test.h"

#if !defined(LIBC_FULL_BUILD) && defined(LIBC_TARGET_OS_IS_LINUX)
#include "memory_utils/protected_pages.h"
#endif // !defined(LIBC_FULL_BUILD) && defined(LIBC_TARGET_OS_IS_LINUX)

namespace LIBC_NAMESPACE {

// Adapt CheckMemcpy signature to memcpy.
Expand All @@ -30,4 +35,40 @@ TEST(LlvmLibcMemcpyTest, SizeSweep) {
}
}

#if !defined(LIBC_FULL_BUILD) && defined(LIBC_TARGET_OS_IS_LINUX)

TEST(LlvmLibcMemcpyTest, CheckAccess) {
static constexpr size_t MAX_SIZE = 1024;
LIBC_ASSERT(MAX_SIZE < GetPageSize());
ProtectedPages pages;
const Page write_buffer = pages.GetPageA().WithAccess(PROT_WRITE);
const Page read_buffer = [&]() {
// We fetch page B in write mode.
auto page = pages.GetPageB().WithAccess(PROT_WRITE);
// And fill it with random numbers.
for (size_t i = 0; i < page.page_size; ++i)
page.page_ptr[i] = rand();
// Then return it in read mode.
return page.WithAccess(PROT_READ);
}();
for (size_t size = 0; size < MAX_SIZE; ++size) {
// We cross-check the function with two sources and two destinations.
// - The first of them (bottom) is always page aligned and faults when
// accessing bytes before it.
// - The second one (top) is not necessarily aligned and faults when
// accessing bytes after it.
const uint8_t *sources[2] = {read_buffer.bottom(size),
read_buffer.top(size)};
uint8_t *destinations[2] = {write_buffer.bottom(size),
write_buffer.top(size)};
for (const uint8_t *src : sources) {
for (uint8_t *dst : destinations) {
LIBC_NAMESPACE::memcpy(dst, src, size);
}
}
}
}

#endif // !defined(LIBC_FULL_BUILD) && defined(LIBC_TARGET_OS_IS_LINUX)

} // namespace LIBC_NAMESPACE
99 changes: 99 additions & 0 deletions libc/test/src/string/memory_utils/protected_pages.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
//===-- protected_pages.h -------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
// This file provides protected pages that fault when accessing prior or past
// it. This is useful to check memory functions that must not access outside of
// the provided size limited buffer.
//===----------------------------------------------------------------------===//

#ifndef LIBC_TEST_SRC_STRING_MEMORY_UTILS_PROTECTED_PAGES_H
#define LIBC_TEST_SRC_STRING_MEMORY_UTILS_PROTECTED_PAGES_H

#include "src/__support/macros/properties/os.h" // LIBC_TARGET_OS_IS_LINUX
#if defined(LIBC_FULL_BUILD) || !defined(LIBC_TARGET_OS_IS_LINUX)
#error "Protected pages requires mmap and cannot be used in full build mode."
#endif // defined(LIBC_FULL_BUILD) || !defined(LIBC_TARGET_OS_IS_LINUX)

#include "src/__support/macros/attributes.h" // LIBC_INLINE
#include <stddef.h> // size_t
#include <stdint.h> // uint8_t
#include <sys/mman.h> // mmap, munmap
#include <unistd.h> // sysconf, _SC_PAGESIZE

// Returns mmap page size.
LIBC_INLINE size_t GetPageSize() {
static const size_t PAGE_SIZE = sysconf(_SC_PAGESIZE);
return PAGE_SIZE;
}

// Represents a page of memory whose access can be configured throught the
// 'WithAccess' function. Accessing data above or below this page will trap as
// it is sandwiched between two pages with no read / write access.
struct Page {
// Returns an aligned pointer that can be accessed up to page_size. Accessing
// data at ptr[-1] will fault.
LIBC_INLINE uint8_t *bottom(size_t size) const {
if (size >= page_size)
__builtin_trap();
return page_ptr;
}
// Returns a pointer to a buffer that can be accessed up to size. Accessing
// data at ptr[size] will trap.
LIBC_INLINE uint8_t *top(size_t size) const {
return page_ptr + page_size - size;
}

// protection is one of PROT_READ / PROT_WRITE.
LIBC_INLINE Page &WithAccess(int protection) {
if (mprotect(page_ptr, page_size, protection) != 0)
__builtin_trap();
return *this;
}

const size_t page_size;
uint8_t *const page_ptr;
};

// Allocates 5 consecutive pages that will trap if accessed.
// | page layout | access | page name |
// |-------------|--------|:---------:|
// | 0 | trap | |
// | 1 | custom | A |
// | 2 | trap | |
// | 3 | custom | B |
// | 4 | trap | |
//
// The pages A and B can be retrieved as with 'GetPageA' / 'GetPageB' and their
// accesses can be customized through the 'WithAccess' function.
struct ProtectedPages {
static constexpr size_t PAGES = 5;

ProtectedPages()
: page_size(GetPageSize()),
ptr(mmap(/*address*/ nullptr, /*length*/ PAGES * page_size,
/*protection*/ PROT_NONE,
/*flags*/ MAP_PRIVATE | MAP_ANONYMOUS, /*fd*/ -1,
/*offset*/ 0)) {
if (reinterpret_cast<intptr_t>(ptr) == -1)
__builtin_trap();
}
~ProtectedPages() { munmap(ptr, PAGES * page_size); }

LIBC_INLINE Page GetPageA() const { return Page{page_size, page<1>()}; }
LIBC_INLINE Page GetPageB() const { return Page{page_size, page<3>()}; }

private:
template <size_t index> LIBC_INLINE uint8_t *page() const {
static_assert(index < PAGES);
return static_cast<uint8_t *>(ptr) + (index * page_size);
}

const size_t page_size;
void *const ptr = nullptr;
};

#endif // LIBC_TEST_SRC_STRING_MEMORY_UTILS_PROTECTED_PAGES_H
31 changes: 31 additions & 0 deletions libc/test/src/string/memset_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,14 @@
//===----------------------------------------------------------------------===//

#include "memory_utils/memory_check_utils.h"
#include "src/__support/macros/properties/os.h" // LIBC_TARGET_OS_IS_LINUX
#include "src/string/memset.h"
#include "test/UnitTest/Test.h"

#if !defined(LIBC_FULL_BUILD) && defined(LIBC_TARGET_OS_IS_LINUX)
#include "memory_utils/protected_pages.h"
#endif // !defined(LIBC_FULL_BUILD) && defined(LIBC_TARGET_OS_IS_LINUX)

namespace LIBC_NAMESPACE {

// Adapt CheckMemset signature to memset.
Expand All @@ -27,4 +32,30 @@ TEST(LlvmLibcMemsetTest, SizeSweep) {
}
}

#if !defined(LIBC_FULL_BUILD) && defined(LIBC_TARGET_OS_IS_LINUX)

TEST(LlvmLibcMemsetTest, CheckAccess) {
static constexpr size_t MAX_SIZE = 1024;
LIBC_ASSERT(MAX_SIZE < GetPageSize());
ProtectedPages pages;
const Page write_buffer = pages.GetPageA().WithAccess(PROT_WRITE);
const cpp::array<int, 2> fill_chars = {0, 0x7F};
for (int fill_char : fill_chars) {
for (size_t size = 0; size < MAX_SIZE; ++size) {
// We cross-check the function with two destinations.
// - The first of them (bottom) is always page aligned and faults when
// accessing bytes before it.
// - The second one (top) is not necessarily aligned and faults when
// accessing bytes after it.
uint8_t *destinations[2] = {write_buffer.bottom(size),
write_buffer.top(size)};
for (uint8_t *dst : destinations) {
LIBC_NAMESPACE::memset(dst, fill_char, size);
}
}
}
}

#endif // !defined(LIBC_FULL_BUILD) && defined(LIBC_TARGET_OS_IS_LINUX)

} // namespace LIBC_NAMESPACE
8 changes: 5 additions & 3 deletions lld/ELF/Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1338,9 +1338,11 @@ static bool compareByFilePosition(InputSection *a, InputSection *b) {
OutputSection *aOut = la->getParent();
OutputSection *bOut = lb->getParent();

if (aOut != bOut)
return aOut->addr < bOut->addr;
return la->outSecOff < lb->outSecOff;
if (aOut == bOut)
return la->outSecOff < lb->outSecOff;
if (aOut->addr == bOut->addr)
return aOut->sectionIndex < bOut->sectionIndex;
return aOut->addr < bOut->addr;
}

template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() {
Expand Down
16 changes: 16 additions & 0 deletions lldb/packages/Python/lldbsuite/test/lldbutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -1654,6 +1654,22 @@ def find_library_callable(test):
)


def install_to_target(test, path):
if lldb.remote_platform:
filename = os.path.basename(path)
remote_path = append_to_process_working_directory(test, filename)
err = lldb.remote_platform.Install(
lldb.SBFileSpec(path, True), lldb.SBFileSpec(remote_path, False)
)
if err.Fail():
raise Exception(
"remote_platform.Install('%s', '%s') failed: %s"
% (path, remote_path, err)
)
path = remote_path
return path


def read_file_on_target(test, remote):
if lldb.remote_platform:
local = test.getBuildArtifact("file_from_target")
Expand Down
2 changes: 0 additions & 2 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,6 @@ class DWARFASTParser {

virtual ConstString GetDIEClassTemplateParams(const DWARFDIE &die) = 0;

virtual lldb_private::Type *FindDefinitionTypeForDIE(const DWARFDIE &die) = 0;

static std::optional<SymbolFile::ArrayInfo>
ParseChildArrayInfo(const DWARFDIE &parent_die,
const ExecutionContext *exe_ctx = nullptr);
Expand Down
402 changes: 179 additions & 223 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp

Large diffs are not rendered by default.

197 changes: 109 additions & 88 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h

Large diffs are not rendered by default.

44 changes: 19 additions & 25 deletions lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1632,33 +1632,27 @@ bool SymbolFileDWARF::CompleteType(CompilerType &compiler_type) {
return true;
}

// Once we start resolving this type, remove it from the forward
// declaration map in case anyone's child members or other types require this
// type to get resolved.
DWARFDIE dwarf_die = GetDIE(die_it->second);
GetForwardDeclCompilerTypeToDIE().erase(die_it);
Type *type = nullptr;
if (DWARFASTParser *dwarf_ast = GetDWARFParser(*dwarf_die.GetCU()))
type = dwarf_ast->FindDefinitionTypeForDIE(dwarf_die);
if (!type)
return false;

die_it = GetForwardDeclCompilerTypeToDIE().find(
compiler_type_no_qualifiers.GetOpaqueQualType());
if (die_it != GetForwardDeclCompilerTypeToDIE().end()) {
dwarf_die = GetDIE(die_it->getSecond());
DWARFDIE dwarf_die = GetDIE(die_it->getSecond());
if (dwarf_die) {
// Once we start resolving this type, remove it from the forward
// declaration map in case anyone child members or other types require this
// type to get resolved. The type will get resolved when all of the calls
// to SymbolFileDWARF::ResolveClangOpaqueTypeDefinition are done.
GetForwardDeclCompilerTypeToDIE().erase(die_it);
}

if (Log *log = GetLog(DWARFLog::DebugInfo | DWARFLog::TypeCompletion))
GetObjectFile()->GetModule()->LogMessageVerboseBacktrace(
log, "{0:x8}: {1} ({2}) '{3}' resolving forward declaration...",
dwarf_die.GetID(), DW_TAG_value_to_name(dwarf_die.Tag()),
dwarf_die.Tag(), type->GetName().AsCString());
assert(compiler_type);
if (DWARFASTParser *dwarf_ast = GetDWARFParser(*dwarf_die.GetCU()))
return dwarf_ast->CompleteTypeFromDWARF(dwarf_die, type, compiler_type);
return true;
Type *type = GetDIEToType().lookup(dwarf_die.GetDIE());

Log *log = GetLog(DWARFLog::DebugInfo | DWARFLog::TypeCompletion);
if (log)
GetObjectFile()->GetModule()->LogMessageVerboseBacktrace(
log, "{0:x8}: {1} ({2}) '{3}' resolving forward declaration...",
dwarf_die.GetID(), DW_TAG_value_to_name(dwarf_die.Tag()),
dwarf_die.Tag(), type->GetName().AsCString());
assert(compiler_type);
if (DWARFASTParser *dwarf_ast = GetDWARFParser(*dwarf_die.GetCU()))
return dwarf_ast->CompleteTypeFromDWARF(dwarf_die, type, compiler_type);
}
return false;
}

Type *SymbolFileDWARF::ResolveType(const DWARFDIE &die,
Expand Down
4 changes: 0 additions & 4 deletions lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
Original file line number Diff line number Diff line change
Expand Up @@ -533,12 +533,8 @@ class SymbolFileDWARF : public SymbolFileCommon {
NameToOffsetMap m_function_scope_qualified_name_map;
std::unique_ptr<DWARFDebugRanges> m_ranges;
UniqueDWARFASTTypeMap m_unique_ast_type_map;
// A map from DIE to lldb_private::Type. For record type, the key might be
// either declaration DIE or definition DIE.
DIEToTypePtr m_die_to_type;
DIEToVariableSP m_die_to_variable_sp;
// A map from CompilerType to the struct/class/union/enum DIE (might be a
// declaration or a definition) that is used to construct it.
CompilerTypeToDIE m_forward_decl_compiler_type_to_die;
llvm::DenseMap<dw_offset_t, std::unique_ptr<SupportFileList>>
m_type_unit_support_files;
Expand Down
107 changes: 53 additions & 54 deletions lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,67 +13,66 @@
using namespace lldb_private::dwarf;
using namespace lldb_private::plugin::dwarf;

UniqueDWARFASTType *UniqueDWARFASTTypeList::Find(
const DWARFDIE &die, const lldb_private::Declaration &decl,
const int32_t byte_size, bool is_forward_declaration) {
for (UniqueDWARFASTType &udt : m_collection) {
bool UniqueDWARFASTTypeList::Find(const DWARFDIE &die,
const lldb_private::Declaration &decl,
const int32_t byte_size,
UniqueDWARFASTType &entry) const {
for (const UniqueDWARFASTType &udt : m_collection) {
// Make sure the tags match
if (udt.m_die.Tag() == die.Tag()) {
// If they are not both definition DIEs or both declaration DIEs, then
// don't check for byte size and declaration location, because declaration
// DIEs usually don't have those info.
bool matching_size_declaration =
udt.m_is_forward_declaration != is_forward_declaration
? true
: (udt.m_byte_size < 0 || byte_size < 0 ||
udt.m_byte_size == byte_size) &&
udt.m_declaration == decl;
if (!matching_size_declaration)
continue;
// The type has the same name, and was defined on the same file and
// line. Now verify all of the parent DIEs match.
DWARFDIE parent_arg_die = die.GetParent();
DWARFDIE parent_pos_die = udt.m_die.GetParent();
bool match = true;
bool done = false;
while (!done && match && parent_arg_die && parent_pos_die) {
const dw_tag_t parent_arg_tag = parent_arg_die.Tag();
const dw_tag_t parent_pos_tag = parent_pos_die.Tag();
if (parent_arg_tag == parent_pos_tag) {
switch (parent_arg_tag) {
case DW_TAG_class_type:
case DW_TAG_structure_type:
case DW_TAG_union_type:
case DW_TAG_namespace: {
const char *parent_arg_die_name = parent_arg_die.GetName();
if (parent_arg_die_name == nullptr) {
// Anonymous (i.e. no-name) struct
match = false;
} else {
const char *parent_pos_die_name = parent_pos_die.GetName();
if (parent_pos_die_name == nullptr ||
((parent_arg_die_name != parent_pos_die_name) &&
strcmp(parent_arg_die_name, parent_pos_die_name)))
match = false;
// Validate byte sizes of both types only if both are valid.
if (udt.m_byte_size < 0 || byte_size < 0 ||
udt.m_byte_size == byte_size) {
// Make sure the file and line match
if (udt.m_declaration == decl) {
// The type has the same name, and was defined on the same file and
// line. Now verify all of the parent DIEs match.
DWARFDIE parent_arg_die = die.GetParent();
DWARFDIE parent_pos_die = udt.m_die.GetParent();
bool match = true;
bool done = false;
while (!done && match && parent_arg_die && parent_pos_die) {
const dw_tag_t parent_arg_tag = parent_arg_die.Tag();
const dw_tag_t parent_pos_tag = parent_pos_die.Tag();
if (parent_arg_tag == parent_pos_tag) {
switch (parent_arg_tag) {
case DW_TAG_class_type:
case DW_TAG_structure_type:
case DW_TAG_union_type:
case DW_TAG_namespace: {
const char *parent_arg_die_name = parent_arg_die.GetName();
if (parent_arg_die_name ==
nullptr) // Anonymous (i.e. no-name) struct
{
match = false;
} else {
const char *parent_pos_die_name = parent_pos_die.GetName();
if (parent_pos_die_name == nullptr ||
((parent_arg_die_name != parent_pos_die_name) &&
strcmp(parent_arg_die_name, parent_pos_die_name)))
match = false;
}
} break;

case DW_TAG_compile_unit:
case DW_TAG_partial_unit:
done = true;
break;
default:
break;
}
}
} break;
parent_arg_die = parent_arg_die.GetParent();
parent_pos_die = parent_pos_die.GetParent();
}

case DW_TAG_compile_unit:
case DW_TAG_partial_unit:
done = true;
break;
default:
break;
if (match) {
entry = udt;
return true;
}
}
parent_arg_die = parent_arg_die.GetParent();
parent_pos_die = parent_pos_die.GetParent();
}

if (match) {
return &udt;
}
}
}
return nullptr;
return false;
}
36 changes: 23 additions & 13 deletions lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,31 @@ class UniqueDWARFASTType {
// Constructors and Destructors
UniqueDWARFASTType() : m_type_sp(), m_die(), m_declaration() {}

UniqueDWARFASTType(lldb::TypeSP &type_sp, const DWARFDIE &die,
const Declaration &decl, int32_t byte_size)
: m_type_sp(type_sp), m_die(die), m_declaration(decl),
m_byte_size(byte_size) {}

UniqueDWARFASTType(const UniqueDWARFASTType &rhs)
: m_type_sp(rhs.m_type_sp), m_die(rhs.m_die),
m_declaration(rhs.m_declaration), m_byte_size(rhs.m_byte_size),
m_is_forward_declaration(rhs.m_is_forward_declaration) {}
m_declaration(rhs.m_declaration), m_byte_size(rhs.m_byte_size) {}

~UniqueDWARFASTType() = default;

UniqueDWARFASTType &operator=(const UniqueDWARFASTType &rhs) {
if (this != &rhs) {
m_type_sp = rhs.m_type_sp;
m_die = rhs.m_die;
m_declaration = rhs.m_declaration;
m_byte_size = rhs.m_byte_size;
}
return *this;
}

lldb::TypeSP m_type_sp;
DWARFDIE m_die;
Declaration m_declaration;
int32_t m_byte_size = -1;
// True if the m_die is a forward declaration DIE.
bool m_is_forward_declaration = true;
};

class UniqueDWARFASTTypeList {
Expand All @@ -50,9 +62,8 @@ class UniqueDWARFASTTypeList {
m_collection.push_back(entry);
}

UniqueDWARFASTType *Find(const DWARFDIE &die, const Declaration &decl,
const int32_t byte_size,
bool is_forward_declaration);
bool Find(const DWARFDIE &die, const Declaration &decl,
const int32_t byte_size, UniqueDWARFASTType &entry) const;

protected:
typedef std::vector<UniqueDWARFASTType> collection;
Expand All @@ -69,15 +80,14 @@ class UniqueDWARFASTTypeMap {
m_collection[name.GetCString()].Append(entry);
}

UniqueDWARFASTType *Find(ConstString name, const DWARFDIE &die,
const Declaration &decl, const int32_t byte_size,
bool is_forward_declaration) {
bool Find(ConstString name, const DWARFDIE &die, const Declaration &decl,
const int32_t byte_size, UniqueDWARFASTType &entry) const {
const char *unique_name_cstr = name.GetCString();
collection::iterator pos = m_collection.find(unique_name_cstr);
collection::const_iterator pos = m_collection.find(unique_name_cstr);
if (pos != m_collection.end()) {
return pos->second.Find(die, decl, byte_size, is_forward_declaration);
return pos->second.Find(die, decl, byte_size, entry);
}
return nullptr;
return false;
}

protected:
Expand Down
2 changes: 1 addition & 1 deletion lldb/source/Target/Platform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1225,7 +1225,7 @@ Status Platform::PutFile(const FileSpec &source, const FileSpec &destination,

uint32_t permissions = source_file.get()->GetPermissions(error);
if (permissions == 0)
permissions = lldb::eFilePermissionsFileDefault;
permissions = lldb::eFilePermissionsUserRWX;

lldb::user_id_t dest_file = OpenFile(
destination, File::eOpenOptionCanCreate | File::eOpenOptionWriteOnly |
Expand Down
2 changes: 1 addition & 1 deletion lldb/source/Target/Target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -841,7 +841,7 @@ static bool CheckIfWatchpointsSupported(Target *target, Status &error) {
if (!num_supported_hardware_watchpoints)
return true;

if (num_supported_hardware_watchpoints == 0) {
if (*num_supported_hardware_watchpoints == 0) {
error.SetErrorStringWithFormat(
"Target supports (%u) hardware watchpoint slots.\n",
*num_supported_hardware_watchpoints);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil


class TestLinux64LaunchingViaDynamicLoader(TestBase):
Expand Down Expand Up @@ -39,11 +40,16 @@ def test(self):
breakpoint_shared_library = target.BreakpointCreateBySourceRegex(
"get_signal_crash", lldb.SBFileSpec("signal_file.cpp")
)
inferior_exe_path = lldbutil.install_to_target(
self, self.getBuildArtifact("a.out")
)
lldbutil.install_to_target(self, self.getBuildArtifact("libsignal_file.so"))

launch_info = lldb.SBLaunchInfo(
[
"--library-path",
self.get_process_working_directory(),
self.getBuildArtifact("a.out"),
inferior_exe_path,
]
)
launch_info.SetWorkingDirectory(self.get_process_working_directory())
Expand Down
4 changes: 4 additions & 0 deletions lldb/test/API/functionalities/exec/TestExec.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ def do_test(self, skip_exec):
# Create the target
target = self.dbg.CreateTarget(exe)

lldbutil.install_to_target(self, secondprog)

# Create any breakpoints we need
breakpoint1 = target.BreakpointCreateBySourceRegex(
"Set breakpoint 1 here", lldb.SBFileSpec("main.c", False)
Expand Down Expand Up @@ -143,6 +145,8 @@ def test_correct_thread_plan_state_before_exec(self):
exe = self.getBuildArtifact("a.out")
target = self.dbg.CreateTarget(exe)

lldbutil.install_to_target(self, self.getBuildArtifact("secondprog"))

(target, process, thread, breakpoint1) = lldbutil.run_to_source_breakpoint(
self, "Set breakpoint 1 here", lldb.SBFileSpec("main.c", False)
)
Expand Down
41 changes: 20 additions & 21 deletions lldb/test/API/tools/lldb-server/TestGdbRemoteLaunch.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ class GdbRemoteLaunchTestCase(gdbremote_testcase.GdbRemoteTestCaseBase):
@add_test_categories(["llgs"])
def test_launch_via_A(self):
self.build()
exe_path = self.getBuildArtifact("a.out")
args = [exe_path, "stderr:arg1", "stderr:arg2", "stderr:arg3"]
hex_args = [seven.hexlify(x) for x in args]

server = self.connect_to_debug_monitor()
self.assertIsNotNone(server)
self.do_handshake()
exe_path = lldbutil.install_to_target(self, self.getBuildArtifact("a.out"))
args = [exe_path, "stderr:arg1", "stderr:arg2", "stderr:arg3"]
hex_args = [seven.hexlify(x) for x in args]

# NB: strictly speaking we should use %x here but this packet
# is deprecated, so no point in changing lldb-server's expectations
self.test_sequence.add_log_lines(
Expand All @@ -38,13 +38,13 @@ def test_launch_via_A(self):
@add_test_categories(["llgs"])
def test_launch_via_vRun(self):
self.build()
exe_path = self.getBuildArtifact("a.out")
args = [exe_path, "stderr:arg1", "stderr:arg2", "stderr:arg3"]
hex_args = [seven.hexlify(x) for x in args]

server = self.connect_to_debug_monitor()
self.assertIsNotNone(server)
self.do_handshake()
exe_path = lldbutil.install_to_target(self, self.getBuildArtifact("a.out"))
args = [exe_path, "stderr:arg1", "stderr:arg2", "stderr:arg3"]
hex_args = [seven.hexlify(x) for x in args]

self.test_sequence.add_log_lines(
[
"read packet: $vRun;%s;%s;%s;%s#00" % tuple(hex_args),
Expand All @@ -60,12 +60,12 @@ def test_launch_via_vRun(self):
@add_test_categories(["llgs"])
def test_launch_via_vRun_no_args(self):
self.build()
exe_path = self.getBuildArtifact("a.out")
hex_path = seven.hexlify(exe_path)

server = self.connect_to_debug_monitor()
self.assertIsNotNone(server)
self.do_handshake()
exe_path = lldbutil.install_to_target(self, self.getBuildArtifact("a.out"))
hex_path = seven.hexlify(exe_path)

self.test_sequence.add_log_lines(
[
"read packet: $vRun;%s#00" % (hex_path,),
Expand All @@ -78,6 +78,7 @@ def test_launch_via_vRun_no_args(self):
self.expect_gdbremote_sequence()

@add_test_categories(["llgs"])
@skipIfRemote
def test_launch_failure_via_vRun(self):
self.build()
exe_path = self.getBuildArtifact("a.out")
Expand Down Expand Up @@ -110,14 +111,13 @@ def test_launch_failure_via_vRun(self):
@add_test_categories(["llgs"])
def test_QEnvironment(self):
self.build()
exe_path = self.getBuildArtifact("a.out")
env = {"FOO": "test", "BAR": "a=z"}
args = [exe_path, "print-env:FOO", "print-env:BAR"]
hex_args = [seven.hexlify(x) for x in args]

server = self.connect_to_debug_monitor()
self.assertIsNotNone(server)
self.do_handshake()
exe_path = lldbutil.install_to_target(self, self.getBuildArtifact("a.out"))
env = {"FOO": "test", "BAR": "a=z"}
args = [exe_path, "print-env:FOO", "print-env:BAR"]
hex_args = [seven.hexlify(x) for x in args]

for key, value in env.items():
self.test_sequence.add_log_lines(
Expand All @@ -143,14 +143,13 @@ def test_QEnvironment(self):
@add_test_categories(["llgs"])
def test_QEnvironmentHexEncoded(self):
self.build()
exe_path = self.getBuildArtifact("a.out")
env = {"FOO": "test", "BAR": "a=z", "BAZ": "a*}#z"}
args = [exe_path, "print-env:FOO", "print-env:BAR", "print-env:BAZ"]
hex_args = [seven.hexlify(x) for x in args]

server = self.connect_to_debug_monitor()
self.assertIsNotNone(server)
self.do_handshake()
exe_path = lldbutil.install_to_target(self, self.getBuildArtifact("a.out"))
env = {"FOO": "test", "BAR": "a=z", "BAZ": "a*}#z"}
args = [exe_path, "print-env:FOO", "print-env:BAR", "print-env:BAZ"]
hex_args = [seven.hexlify(x) for x in args]

for key, value in env.items():
hex_enc = seven.hexlify("%s=%s" % (key, value))
Expand Down
33 changes: 30 additions & 3 deletions lldb/test/API/tools/lldb-server/TestGdbRemotePlatformFile.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# lldb test suite imports
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import TestBase
from lldbsuite.test import lldbutil

# gdb-remote-specific imports
import lldbgdbserverutils
Expand Down Expand Up @@ -117,6 +118,7 @@ def test_platform_file_wronly_creat_excl_fail(self):
temp_file = self.getBuildArtifact("test")
with open(temp_file, "wb"):
pass
temp_file = lldbutil.install_to_target(self, temp_file)

# attempt to open the file with O_CREAT|O_EXCL
self.do_handshake()
Expand All @@ -140,6 +142,7 @@ def test_platform_file_size(self):
test_data = b"test data of some length"
with open(temp_path, "wb") as temp_file:
temp_file.write(test_data)
temp_path = lldbutil.install_to_target(self, temp_path)

self.do_handshake()
self.test_sequence.add_log_lines(
Expand Down Expand Up @@ -167,7 +170,11 @@ def test_platform_file_mode(self):
test_mode = 0o751

with open(temp_path, "wb") as temp_file:
os.chmod(temp_file.fileno(), test_mode)
if lldbplatformutil.getHostPlatform() == "windows":
test_mode = 0o700
else:
os.chmod(temp_file.fileno(), test_mode)
temp_path = lldbutil.install_to_target(self, temp_path)

self.do_handshake()
self.test_sequence.add_log_lines(
Expand Down Expand Up @@ -213,6 +220,7 @@ def test_platform_file_exists(self):
temp_path = self.getBuildArtifact("test")
with open(temp_path, "wb"):
pass
temp_path = lldbutil.install_to_target(self, temp_path)

self.do_handshake()
self.test_sequence.add_log_lines(
Expand Down Expand Up @@ -244,6 +252,10 @@ def test_platform_file_exists_not(self):
self.expect_gdbremote_sequence()

@skipIfWindows
# FIXME: lldb.remote_platform.Install() cannot copy opened temp file on Windows.
# It is possible to use tempfile.NamedTemporaryFile(..., delete=False) and
# delete the temp file manually at the end.
@skipIf(hostoslist=["windows"])
@add_test_categories(["llgs"])
def test_platform_file_fstat(self):
server = self.connect_to_debug_monitor()
Expand All @@ -252,12 +264,13 @@ def test_platform_file_fstat(self):
with tempfile.NamedTemporaryFile() as temp_file:
temp_file.write(b"some test data for stat")
temp_file.flush()
temp_path = lldbutil.install_to_target(self, temp_file.name)

self.do_handshake()
self.test_sequence.add_log_lines(
[
"read packet: $vFile:open:%s,0,0#00"
% (binascii.b2a_hex(temp_file.name.encode()).decode(),),
% (binascii.b2a_hex(temp_path.encode()).decode(),),
{
"direction": "send",
"regex": r"^\$F([0-9a-fA-F]+)#[0-9a-fA-F]{2}$",
Expand Down Expand Up @@ -359,9 +372,12 @@ def vFile_test(

if creat:
self.assertFalse(os.path.exists(temp_path))
if lldb.remote_platform:
temp_path = lldbutil.append_to_process_working_directory(self, "test")
else:
with open(temp_path, "wb") as temp_file:
temp_file.write(test_data.encode())
temp_path = lldbutil.install_to_target(self, temp_path)

# open the file for reading
self.do_handshake()
Expand Down Expand Up @@ -448,8 +464,19 @@ def vFile_test(

if write:
# check if the data was actually written
if lldb.remote_platform:
local_path = self.getBuildArtifact("file_from_target")
error = lldb.remote_platform.Get(
lldb.SBFileSpec(temp_path, False), lldb.SBFileSpec(local_path, True)
)
self.assertTrue(
error.Success(),
"Reading file {0} failed: {1}".format(temp_path, error),
)
temp_path = local_path

with open(temp_path, "rb") as temp_file:
if creat:
if creat and lldbplatformutil.getHostPlatform() != "windows":
self.assertEqual(
os.fstat(temp_file.fileno()).st_mode & 0o7777, 0o640
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def prep_memtags_test(self):
@skipUnlessArch("aarch64")
@skipUnlessPlatform(["linux"])
@skipUnlessAArch64MTELinuxCompiler
def test_qMemTags_packets(self):
def test_tag_read_qMemTags_packets(self):
"""Test that qMemTags packets are parsed correctly and/or rejected."""
buf_address, page_size = self.prep_memtags_test()

Expand Down Expand Up @@ -154,7 +154,7 @@ def check_tag_write(self, body, expected):
@skipUnlessArch("aarch64")
@skipUnlessPlatform(["linux"])
@skipUnlessAArch64MTELinuxCompiler
def test_QMemTags_packets(self):
def test_tag_write_QMemTags_packets(self):
"""Test that QMemTags packets are parsed correctly and/or rejected."""
buf_address, page_size = self.prep_memtags_test()

Expand Down

This file was deleted.

4 changes: 4 additions & 0 deletions llvm/docs/GettingInvolved.rst
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,10 @@ what to add to your calendar invite.
- `ics <https://calendar.google.com/calendar/ical/02582507bac79d186900712566ec3fc69b33ac24d7de0a8c76c7b19976f190c0%40group.calendar.google.com/private-6e35506dbfe13812e92e9aa8cd5d761d/basic.ics>`__
`gcal <https://calendar.google.com/calendar/u/0?cid=MDI1ODI1MDdiYWM3OWQxODY5MDA3MTI1NjZlYzNmYzY5YjMzYWMyNGQ3ZGUwYThjNzZjN2IxOTk3NmYxOTBjMEBncm91cC5jYWxlbmRhci5nb29nbGUuY29t>`__
- `Meeting details/agenda: <https://docs.google.com/document/d/1QcmUlWftPlBi-Wz6b6PipqJfvjpJ-OuRMRnN9Dm2t0c>`__
* - Vectorizer Improvement Working Group
- Every 3rd Thursday of the month
- `ics <https://drive.google.com/file/d/1ten-u-4yjOcCoONUtR4_AxsFxRDTUp1b/view?usp=sharing>`__
- `Meeting details/agenda: <https://docs.google.com/document/d/1Glzy2JiWuysbD-HBWGUOkZqT09GJ4_Ljodr0lXD5XfQ/edit>`__

Past online sync-ups
^^^^^^^^^^^^^^^^^^^^
Expand Down
7 changes: 0 additions & 7 deletions llvm/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -189,13 +189,6 @@ Changes to the Metadata Info
Changes to the Debug Info
---------------------------------

* LLVM has switched from using debug intrinsics internally to using debug
records by default. This should happen transparently when using the DIBuilder
to construct debug variable information, but will require changes for any code
that interacts with debug intrinsics directly. Debug intrinsics will only be
supported on a best-effort basis from here onwards; for more information, see
the `migration docs <https://llvm.org/docs/RemoveDIsDebugInfo.html>`_.

Changes to the LLVM tools
---------------------------------
* llvm-nm and llvm-objdump can now print symbol information from linked
Expand Down
4 changes: 4 additions & 0 deletions llvm/docs/SPIRVUsage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,10 @@ SPIR-V backend, along with their descriptions and argument details.
- None
- `[Type, Vararg]`
- Assigns names to types or values, enhancing readability and debuggability of SPIR-V code. Not emitted directly but used for metadata enrichment.
* - `int_spv_assign_decoration`
- None
- `[Type, Metadata]`
- Assigns decoration to values by associating them with metadatas. Not emitted directly but used to support SPIR-V representation in LLVM IR.
* - `int_spv_track_constant`
- Type
- `[Type, Metadata]`
Expand Down
2 changes: 1 addition & 1 deletion llvm/include/llvm/ADT/StringMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class StringMapImpl {
}

StringMapImpl(unsigned InitSize, unsigned ItemSize);
~StringMapImpl() { free(TheTable); }
unsigned RehashTable(unsigned BucketNo = 0);

/// LookupBucketFor - Look up the bucket that the specified string should end
Expand Down Expand Up @@ -203,7 +204,6 @@ class LLVM_ALLOCATORHOLDER_EMPTYBASE StringMap
}
}
}
free(TheTable);
}

using AllocTy::getAllocator;
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/AsmParser/LLParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ namespace llvm {

// Top-Level Entities
bool parseTopLevelEntities();
bool finalizeDebugInfoFormat(Module *M);
void dropUnknownMetadataReferences();
bool validateEndOfModule(bool UpgradeDebugInfo);
bool validateEndOfIndex();
Expand Down
2 changes: 1 addition & 1 deletion llvm/include/llvm/BinaryFormat/DXContainer.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ struct PartHeader {

struct BitcodeHeader {
uint8_t Magic[4]; // ACSII "DXIL".
uint8_t MajorVersion; // DXIL version.
uint8_t MinorVersion; // DXIL version.
uint8_t MajorVersion; // DXIL version.
uint16_t Unused;
uint32_t Offset; // Offset to LLVM bitcode (from start of header).
uint32_t Size; // Size of LLVM bitcode (in bytes).
Expand Down
4 changes: 2 additions & 2 deletions llvm/include/llvm/CodeGen/PseudoSourceValueManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@
#ifndef LLVM_CODEGEN_PSEUDOSOURCEVALUEMANAGER_H
#define LLVM_CODEGEN_PSEUDOSOURCEVALUEMANAGER_H

#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/CodeGen/PseudoSourceValue.h"
#include "llvm/IR/ValueMap.h"
#include <map>

namespace llvm {

Expand All @@ -27,7 +27,7 @@ class TargetMachine;
class PseudoSourceValueManager {
const TargetMachine &TM;
const PseudoSourceValue StackPSV, GOTPSV, JumpTablePSV, ConstantPoolPSV;
std::map<int, std::unique_ptr<FixedStackPseudoSourceValue>> FSValues;
SmallVector<std::unique_ptr<FixedStackPseudoSourceValue>> FSValues;
StringMap<std::unique_ptr<const ExternalSymbolPseudoSourceValue>>
ExternalCallEntries;
ValueMap<const GlobalValue *,
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/IR/IntrinsicsSPIRV.td
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ let TargetPrefix = "spv" in {
def int_spv_assign_type : Intrinsic<[], [llvm_any_ty, llvm_metadata_ty]>;
def int_spv_assign_ptr_type : Intrinsic<[], [llvm_any_ty, llvm_metadata_ty, llvm_i32_ty], [ImmArg<ArgIndex<2>>]>;
def int_spv_assign_name : Intrinsic<[], [llvm_any_ty, llvm_vararg_ty]>;
def int_spv_assign_decoration : Intrinsic<[], [llvm_any_ty, llvm_metadata_ty]>;

def int_spv_track_constant : Intrinsic<[llvm_any_ty], [llvm_any_ty, llvm_metadata_ty]>;
def int_spv_init_global : Intrinsic<[], [llvm_any_ty, llvm_any_ty]>;
Expand Down
22 changes: 3 additions & 19 deletions llvm/include/llvm/MC/MCContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -391,29 +391,13 @@ class MCContext {
/// Map of currently defined macros.
StringMap<MCAsmMacro> MacroMap;

struct ELFEntrySizeKey {
std::string SectionName;
unsigned Flags;
unsigned EntrySize;

ELFEntrySizeKey(StringRef SectionName, unsigned Flags, unsigned EntrySize)
: SectionName(SectionName), Flags(Flags), EntrySize(EntrySize) {}

bool operator<(const ELFEntrySizeKey &Other) const {
if (SectionName != Other.SectionName)
return SectionName < Other.SectionName;
if (Flags != Other.Flags)
return Flags < Other.Flags;
return EntrySize < Other.EntrySize;
}
};

// Symbols must be assigned to a section with a compatible entry size and
// flags. This map is used to assign unique IDs to sections to distinguish
// between sections with identical names but incompatible entry sizes and/or
// flags. This can occur when a symbol is explicitly assigned to a section,
// e.g. via __attribute__((section("myname"))).
std::map<ELFEntrySizeKey, unsigned> ELFEntrySizeMap;
// e.g. via __attribute__((section("myname"))). The map key is the tuple
// (section name, flags, entry size).
DenseMap<std::tuple<StringRef, unsigned, unsigned>, unsigned> ELFEntrySizeMap;

// This set is used to record the generic mergeable section names seen.
// These are sections that are created as mergeable e.g. .debug_str. We need
Expand Down
14 changes: 6 additions & 8 deletions llvm/include/llvm/TargetParser/AArch64TargetParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,12 @@ using ExtensionBitset = Bitset<AEK_NUM_EXTENSIONS>;
// SubtargetFeature which may represent either an actual extension or some
// internal LLVM property.
struct ExtensionInfo {
StringRef Name; // Human readable name, e.g. "profile".
ArchExtKind ID; // Corresponding to the ArchExtKind, this
// extensions representation in the bitfield.
StringRef Feature; // -mattr enable string, e.g. "+spe"
StringRef NegFeature; // -mattr disable string, e.g. "-spe"
StringRef Name; // Human readable name, e.g. "profile".
std::optional<StringRef> Alias; // An alias for this extension, if one exists.
ArchExtKind ID; // Corresponding to the ArchExtKind, this
// extensions representation in the bitfield.
StringRef Feature; // -mattr enable string, e.g. "+spe"
StringRef NegFeature; // -mattr disable string, e.g. "-spe"
CPUFeatures CPUFeature; // Function Multi Versioning (FMV) bitfield value
// set in __aarch64_cpu_features
StringRef DependentFeatures; // FMV enabled features string,
Expand Down Expand Up @@ -674,8 +675,6 @@ struct Alias {
inline constexpr Alias CpuAliases[] = {{"cobalt-100", "neoverse-n2"},
{"grace", "neoverse-v2"}};

inline constexpr Alias ExtAliases[] = {{"rdma", "rdm"}};

const ExtensionInfo &getExtensionByID(ArchExtKind(ExtID));

bool getExtensionFeatures(
Expand All @@ -684,7 +683,6 @@ bool getExtensionFeatures(

StringRef getArchExtFeature(StringRef ArchExt);
StringRef resolveCPUAlias(StringRef CPU);
StringRef resolveExtAlias(StringRef ArchExt);

// Information by Name
const ArchInfo *getArchForCpu(StringRef CPU);
Expand Down
2 changes: 1 addition & 1 deletion llvm/include/llvm/TargetParser/Triple.h
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,7 @@ class Triple {
/// (SubArch). This should only be called with Vulkan SPIR-V triples.
VersionTuple getVulkanVersion() const;

/// Parse the DXIL version number from the DXIL version
/// Parse the DXIL version number from the OSVersion and DXIL version
/// (SubArch). This should only be called with DXIL triples.
VersionTuple getDXILVersion() const;

Expand Down
46 changes: 29 additions & 17 deletions llvm/include/llvm/Transforms/IPO/SampleProfileMatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@

namespace llvm {

using AnchorList = std::vector<std::pair<LineLocation, FunctionId>>;
using AnchorMap = std::map<LineLocation, FunctionId>;

// Sample profile matching - fuzzy match.
class SampleProfileMatcher {
Module &M;
Expand All @@ -27,8 +30,8 @@ class SampleProfileMatcher {
const ThinOrFullLTOPhase LTOPhase;
SampleProfileMap FlattenedProfiles;
// For each function, the matcher generates a map, of which each entry is a
// mapping from the source location of current build to the source location in
// the profile.
// mapping from the source location of current build to the source location
// in the profile.
StringMap<LocToLocMap> FuncMappings;

// Match state for an anchor/callsite.
Expand Down Expand Up @@ -95,18 +98,13 @@ class SampleProfileMatcher {
return nullptr;
}
void runOnFunction(Function &F);
void findIRAnchors(const Function &F,
std::map<LineLocation, StringRef> &IRAnchors);
void findProfileAnchors(
const FunctionSamples &FS,
std::map<LineLocation, std::unordered_set<FunctionId>> &ProfileAnchors);
void findIRAnchors(const Function &F, AnchorMap &IRAnchors);
void findProfileAnchors(const FunctionSamples &FS, AnchorMap &ProfileAnchors);
// Record the callsite match states for profile staleness report, the result
// is saved in FuncCallsiteMatchStates.
void recordCallsiteMatchStates(
const Function &F, const std::map<LineLocation, StringRef> &IRAnchors,
const std::map<LineLocation, std::unordered_set<FunctionId>>
&ProfileAnchors,
const LocToLocMap *IRToProfileLocationMap);
void recordCallsiteMatchStates(const Function &F, const AnchorMap &IRAnchors,
const AnchorMap &ProfileAnchors,
const LocToLocMap *IRToProfileLocationMap);

bool isMismatchState(const enum MatchState &State) {
return State == MatchState::InitialMismatch ||
Expand Down Expand Up @@ -143,11 +141,25 @@ class SampleProfileMatcher {
}
void distributeIRToProfileLocationMap();
void distributeIRToProfileLocationMap(FunctionSamples &FS);
void runStaleProfileMatching(
const Function &F, const std::map<LineLocation, StringRef> &IRAnchors,
const std::map<LineLocation, std::unordered_set<FunctionId>>
&ProfileAnchors,
LocToLocMap &IRToProfileLocationMap);
// This function implements the Myers diff algorithm used for stale profile
// matching. The algorithm provides a simple and efficient way to find the
// Longest Common Subsequence(LCS) or the Shortest Edit Script(SES) of two
// sequences. For more details, refer to the paper 'An O(ND) Difference
// Algorithm and Its Variations' by Eugene W. Myers.
// In the scenario of profile fuzzy matching, the two sequences are the IR
// callsite anchors and profile callsite anchors. The subsequence equivalent
// parts from the resulting SES are used to remap the IR locations to the
// profile locations. As the number of function callsite is usually not big,
// we currently just implements the basic greedy version(page 6 of the paper).
LocToLocMap
longestCommonSequence(const AnchorList &IRCallsiteAnchors,
const AnchorList &ProfileCallsiteAnchors) const;
void matchNonCallsiteLocs(const LocToLocMap &AnchorMatchings,
const AnchorMap &IRAnchors,
LocToLocMap &IRToProfileLocationMap);
void runStaleProfileMatching(const Function &F, const AnchorMap &IRAnchors,
const AnchorMap &ProfileAnchors,
LocToLocMap &IRToProfileLocationMap);
void reportOrPersistProfileStats();
};
} // end namespace llvm
Expand Down
7 changes: 3 additions & 4 deletions llvm/lib/Analysis/ValueTracking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1137,20 +1137,19 @@ static void computeKnownBitsFromOperator(const Operator *I,
if (FPClasses & fcZero)
Known = Known.intersectWith(KnownBits::makeConstant(
APInt::getZero(FPType->getScalarSizeInBits())));

Known.Zero.clearSignBit();
Known.One.clearSignBit();
}

if (Result.SignBit) {
if (*Result.SignBit)
Known.makeNegative();
else
Known.makeNonNegative();
} else {
Known.Zero.clearSignBit();
Known.One.clearSignBit();
}

assert(!Known.hasConflict() && "Bits known to be one AND zero?");

break;
}

Expand Down
34 changes: 18 additions & 16 deletions llvm/lib/AsmParser/LLParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,23 @@ static std::string getTypeString(Type *T) {
return Tmp.str();
}

// Whatever debug info format we parsed, we should convert to the expected debug
// info format immediately afterwards.
bool LLParser::finalizeDebugInfoFormat(Module *M) {
// We should have already returned an error if we observed both intrinsics and
// records in this IR.
assert(!(SeenNewDbgInfoFormat && SeenOldDbgInfoFormat) &&
"Mixed debug intrinsics/records seen without a parsing error?");
if (PreserveInputDbgFormat == cl::boolOrDefault::BOU_TRUE) {
UseNewDbgInfoFormat = SeenNewDbgInfoFormat;
WriteNewDbgInfoFormatToBitcode = SeenNewDbgInfoFormat;
WriteNewDbgInfoFormat = SeenNewDbgInfoFormat;
} else if (M) {
M->setIsNewDbgInfoFormat(false);
}
return false;
}

/// Run: module ::= toplevelentity*
bool LLParser::Run(bool UpgradeDebugInfo,
DataLayoutCallbackTy DataLayoutCallback) {
Expand All @@ -91,7 +108,7 @@ bool LLParser::Run(bool UpgradeDebugInfo,
}

return parseTopLevelEntities() || validateEndOfModule(UpgradeDebugInfo) ||
validateEndOfIndex();
validateEndOfIndex() || finalizeDebugInfoFormat(M);
}

bool LLParser::parseStandaloneConstantValue(Constant *&C,
Expand Down Expand Up @@ -190,18 +207,6 @@ void LLParser::dropUnknownMetadataReferences() {
bool LLParser::validateEndOfModule(bool UpgradeDebugInfo) {
if (!M)
return false;

// We should have already returned an error if we observed both intrinsics and
// records in this IR.
assert(!(SeenNewDbgInfoFormat && SeenOldDbgInfoFormat) &&
"Mixed debug intrinsics/records seen without a parsing error?");
if (PreserveInputDbgFormat == cl::boolOrDefault::BOU_TRUE) {
UseNewDbgInfoFormat = SeenNewDbgInfoFormat;
WriteNewDbgInfoFormatToBitcode = SeenNewDbgInfoFormat;
WriteNewDbgInfoFormat = SeenNewDbgInfoFormat;
M->setNewDbgInfoFormatFlag(SeenNewDbgInfoFormat);
}

// Handle any function attribute group forward references.
for (const auto &RAG : ForwardRefAttrGroups) {
Value *V = RAG.first;
Expand Down Expand Up @@ -434,9 +439,6 @@ bool LLParser::validateEndOfModule(bool UpgradeDebugInfo) {
UpgradeModuleFlags(*M);
UpgradeSectionAttributes(*M);

if (PreserveInputDbgFormat != cl::boolOrDefault::BOU_TRUE)
M->setIsNewDbgInfoFormat(UseNewDbgInfoFormat);

if (!Slots)
return false;
// Initialize the slot mapping.
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Bitcode/Reader/BitcodeReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4319,7 +4319,7 @@ Error BitcodeReader::parseModule(uint64_t ResumeBit,
if (PreserveInputDbgFormat != cl::boolOrDefault::BOU_TRUE) {
TheModule->IsNewDbgInfoFormat =
UseNewDbgInfoFormat &&
LoadBitcodeIntoNewDbgInfoFormat != cl::boolOrDefault::BOU_FALSE;
LoadBitcodeIntoNewDbgInfoFormat == cl::boolOrDefault::BOU_TRUE;
}

this->ValueTypeCallback = std::move(Callbacks.ValueType);
Expand Down
76 changes: 44 additions & 32 deletions llvm/lib/CodeGen/GlobalISel/Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -313,13 +313,22 @@ llvm::getIConstantVRegSExtVal(Register VReg, const MachineRegisterInfo &MRI) {

namespace {

typedef std::function<bool(const MachineInstr *)> IsOpcodeFn;
typedef std::function<std::optional<APInt>(const MachineInstr *MI)> GetAPCstFn;

std::optional<ValueAndVReg> getConstantVRegValWithLookThrough(
Register VReg, const MachineRegisterInfo &MRI, IsOpcodeFn IsConstantOpcode,
GetAPCstFn getAPCstValue, bool LookThroughInstrs = true,
bool LookThroughAnyExt = false) {
// This function is used in many places, and as such, it has some
// micro-optimizations to try and make it as fast as it can be.
//
// - We use template arguments to avoid an indirect call caused by passing a
// function_ref/std::function
// - GetAPCstValue does not return std::optional<APInt> as that's expensive.
// Instead it returns true/false and places the result in a pre-constructed
// APInt.
//
// Please change this function carefully and benchmark your changes.
template <bool (*IsConstantOpcode)(const MachineInstr *),
bool (*GetAPCstValue)(const MachineInstr *MI, APInt &)>
std::optional<ValueAndVReg>
getConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI,
bool LookThroughInstrs = true,
bool LookThroughAnyExt = false) {
SmallVector<std::pair<unsigned, unsigned>, 4> SeenOpcodes;
MachineInstr *MI;

Expand Down Expand Up @@ -353,26 +362,25 @@ std::optional<ValueAndVReg> getConstantVRegValWithLookThrough(
if (!MI || !IsConstantOpcode(MI))
return std::nullopt;

std::optional<APInt> MaybeVal = getAPCstValue(MI);
if (!MaybeVal)
APInt Val;
if (!GetAPCstValue(MI, Val))
return std::nullopt;
APInt &Val = *MaybeVal;
for (auto [Opcode, Size] : reverse(SeenOpcodes)) {
switch (Opcode) {
for (auto &Pair : reverse(SeenOpcodes)) {
switch (Pair.first) {
case TargetOpcode::G_TRUNC:
Val = Val.trunc(Size);
Val = Val.trunc(Pair.second);
break;
case TargetOpcode::G_ANYEXT:
case TargetOpcode::G_SEXT:
Val = Val.sext(Size);
Val = Val.sext(Pair.second);
break;
case TargetOpcode::G_ZEXT:
Val = Val.zext(Size);
Val = Val.zext(Pair.second);
break;
}
}

return ValueAndVReg{Val, VReg};
return ValueAndVReg{std::move(Val), VReg};
}

bool isIConstant(const MachineInstr *MI) {
Expand All @@ -394,42 +402,46 @@ bool isAnyConstant(const MachineInstr *MI) {
return Opc == TargetOpcode::G_CONSTANT || Opc == TargetOpcode::G_FCONSTANT;
}

std::optional<APInt> getCImmAsAPInt(const MachineInstr *MI) {
bool getCImmAsAPInt(const MachineInstr *MI, APInt &Result) {
const MachineOperand &CstVal = MI->getOperand(1);
if (CstVal.isCImm())
return CstVal.getCImm()->getValue();
return std::nullopt;
if (!CstVal.isCImm())
return false;
Result = CstVal.getCImm()->getValue();
return true;
}

std::optional<APInt> getCImmOrFPImmAsAPInt(const MachineInstr *MI) {
bool getCImmOrFPImmAsAPInt(const MachineInstr *MI, APInt &Result) {
const MachineOperand &CstVal = MI->getOperand(1);
if (CstVal.isCImm())
return CstVal.getCImm()->getValue();
if (CstVal.isFPImm())
return CstVal.getFPImm()->getValueAPF().bitcastToAPInt();
return std::nullopt;
Result = CstVal.getCImm()->getValue();
else if (CstVal.isFPImm())
Result = CstVal.getFPImm()->getValueAPF().bitcastToAPInt();
else
return false;
return true;
}

} // end anonymous namespace

std::optional<ValueAndVReg> llvm::getIConstantVRegValWithLookThrough(
Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs) {
return getConstantVRegValWithLookThrough(VReg, MRI, isIConstant,
getCImmAsAPInt, LookThroughInstrs);
return getConstantVRegValWithLookThrough<isIConstant, getCImmAsAPInt>(
VReg, MRI, LookThroughInstrs);
}

std::optional<ValueAndVReg> llvm::getAnyConstantVRegValWithLookThrough(
Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs,
bool LookThroughAnyExt) {
return getConstantVRegValWithLookThrough(
VReg, MRI, isAnyConstant, getCImmOrFPImmAsAPInt, LookThroughInstrs,
LookThroughAnyExt);
return getConstantVRegValWithLookThrough<isAnyConstant,
getCImmOrFPImmAsAPInt>(
VReg, MRI, LookThroughInstrs, LookThroughAnyExt);
}

std::optional<FPValueAndVReg> llvm::getFConstantVRegValWithLookThrough(
Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs) {
auto Reg = getConstantVRegValWithLookThrough(
VReg, MRI, isFConstant, getCImmOrFPImmAsAPInt, LookThroughInstrs);
auto Reg =
getConstantVRegValWithLookThrough<isFConstant, getCImmOrFPImmAsAPInt>(
VReg, MRI, LookThroughInstrs);
if (!Reg)
return std::nullopt;
return FPValueAndVReg{getConstantFPVRegVal(Reg->VReg, MRI)->getValueAPF(),
Expand Down
7 changes: 6 additions & 1 deletion llvm/lib/CodeGen/PseudoSourceValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,12 @@ const PseudoSourceValue *PseudoSourceValueManager::getJumpTable() {

const PseudoSourceValue *
PseudoSourceValueManager::getFixedStack(int FI) {
std::unique_ptr<FixedStackPseudoSourceValue> &V = FSValues[FI];
// Frame index is often continuously positive, but can be negative. Use
// zig-zag encoding for dense index into FSValues vector.
unsigned Idx = (2 * unsigned(FI)) ^ (FI >> (sizeof(FI) * 8 - 1));
if (FSValues.size() <= Idx)
FSValues.resize(Idx + 1);
std::unique_ptr<FixedStackPseudoSourceValue> &V = FSValues[Idx];
if (!V)
V = std::make_unique<FixedStackPseudoSourceValue>(FI, TM);
return V.get();
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/IR/BasicBlock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ template class llvm::SymbolTableListTraits<Instruction,
BasicBlock::BasicBlock(LLVMContext &C, const Twine &Name, Function *NewParent,
BasicBlock *InsertBefore)
: Value(Type::getLabelTy(C), Value::BasicBlockVal),
IsNewDbgInfoFormat(UseNewDbgInfoFormat), Parent(nullptr) {
IsNewDbgInfoFormat(false), Parent(nullptr) {

if (NewParent)
insertInto(NewParent, InsertBefore);
Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/IR/DebugProgramInstruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -366,8 +366,8 @@ void DbgVariableRecord::setKillLocation() {
}

bool DbgVariableRecord::isKillLocation() const {
return (!hasArgList() && isa<MDNode>(getRawLocation())) ||
(getNumVariableLocationOps() == 0 && !getExpression()->isComplex()) ||
return (getNumVariableLocationOps() == 0 &&
!getExpression()->isComplex()) ||
any_of(location_ops(), [](Value *V) { return isa<UndefValue>(V); });
}

Expand Down
4 changes: 1 addition & 3 deletions llvm/lib/IR/Function.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,6 @@ static cl::opt<unsigned> NonGlobalValueMaxNameSize(
"non-global-value-max-name-size", cl::Hidden, cl::init(1024),
cl::desc("Maximum size for the name of non-global values."));

extern cl::opt<bool> UseNewDbgInfoFormat;

void Function::convertToNewDbgValues() {
IsNewDbgInfoFormat = true;
for (auto &BB : *this) {
Expand Down Expand Up @@ -440,7 +438,7 @@ Function::Function(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace,
: GlobalObject(Ty, Value::FunctionVal,
OperandTraits<Function>::op_begin(this), 0, Linkage, name,
computeAddrSpace(AddrSpace, ParentModule)),
NumArgs(Ty->getNumParams()), IsNewDbgInfoFormat(UseNewDbgInfoFormat) {
NumArgs(Ty->getNumParams()), IsNewDbgInfoFormat(false) {
assert(FunctionType::isValidReturnType(getReturnType()) &&
"invalid return type");
setGlobalObjectSubClassData(0);
Expand Down
4 changes: 1 addition & 3 deletions llvm/lib/IR/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,6 @@

using namespace llvm;

extern cl::opt<bool> UseNewDbgInfoFormat;

//===----------------------------------------------------------------------===//
// Methods to implement the globals and functions lists.
//
Expand All @@ -74,7 +72,7 @@ template class llvm::SymbolTableListTraits<GlobalIFunc>;
Module::Module(StringRef MID, LLVMContext &C)
: Context(C), ValSymTab(std::make_unique<ValueSymbolTable>(-1)),
ModuleID(std::string(MID)), SourceFileName(std::string(MID)), DL(""),
IsNewDbgInfoFormat(UseNewDbgInfoFormat) {
IsNewDbgInfoFormat(false) {
Context.addModule(this);
}

Expand Down
12 changes: 8 additions & 4 deletions llvm/lib/MC/MCContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -620,15 +620,20 @@ void MCContext::recordELFMergeableSectionInfo(StringRef SectionName,
unsigned Flags, unsigned UniqueID,
unsigned EntrySize) {
bool IsMergeable = Flags & ELF::SHF_MERGE;
if (UniqueID == GenericSectionID)
if (UniqueID == GenericSectionID) {
ELFSeenGenericMergeableSections.insert(SectionName);
// Minor performance optimization: avoid hash map lookup in
// isELFGenericMergeableSection, which will return true for SectionName.
IsMergeable = true;
}

// For mergeable sections or non-mergeable sections with a generic mergeable
// section name we enter their Unique ID into the ELFEntrySizeMap so that
// compatible globals can be assigned to the same section.

if (IsMergeable || isELFGenericMergeableSection(SectionName)) {
ELFEntrySizeMap.insert(std::make_pair(
ELFEntrySizeKey{SectionName, Flags, EntrySize}, UniqueID));
std::make_tuple(SectionName, Flags, EntrySize), UniqueID));
}
}

Expand All @@ -645,8 +650,7 @@ bool MCContext::isELFGenericMergeableSection(StringRef SectionName) {
std::optional<unsigned>
MCContext::getELFUniqueIDForEntsize(StringRef SectionName, unsigned Flags,
unsigned EntrySize) {
auto I = ELFEntrySizeMap.find(
MCContext::ELFEntrySizeKey{SectionName, Flags, EntrySize});
auto I = ELFEntrySizeMap.find(std::make_tuple(SectionName, Flags, EntrySize));
return (I != ELFEntrySizeMap.end()) ? std::optional<unsigned>(I->second)
: std::nullopt;
}
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/MC/MCDXContainerWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ uint64_t DXContainerObjectWriter::writeObject(MCAssembler &Asm,
// The program header's size field is in 32-bit words.
Header.Size = (SectionSize + sizeof(dxbc::ProgramHeader) + 3) / 4;
memcpy(Header.Bitcode.Magic, "DXIL", 4);
VersionTuple DXILVersion = TT.getDXILVersion();
Header.Bitcode.MajorVersion = DXILVersion.getMajor();
Header.Bitcode.MinorVersion = DXILVersion.getMinor().value_or(0);
Header.Bitcode.Offset = sizeof(dxbc::BitcodeHeader);
Header.Bitcode.Size = SectionSize;
if (sys::IsBigEndianHost)
Expand Down
25 changes: 10 additions & 15 deletions llvm/lib/Support/APFloat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -732,7 +732,7 @@ powerOf5(APFloatBase::integerPart *dst, unsigned int power) {
APFloatBase::integerPart pow5s[maxPowerOfFiveParts * 2 + 5];
pow5s[0] = 78125 * 5;

unsigned int partsCount[16] = { 1 };
unsigned int partsCount = 1;
APFloatBase::integerPart scratch[maxPowerOfFiveParts], *p1, *p2, *pow5;
unsigned int result;
assert(power <= maxExponent);
Expand All @@ -747,25 +747,20 @@ powerOf5(APFloatBase::integerPart *dst, unsigned int power) {
pow5 = pow5s;

for (unsigned int n = 0; power; power >>= 1, n++) {
unsigned int pc;

pc = partsCount[n];

/* Calculate pow(5,pow(2,n+3)) if we haven't yet. */
if (pc == 0) {
pc = partsCount[n - 1];
APInt::tcFullMultiply(pow5, pow5 - pc, pow5 - pc, pc, pc);
pc *= 2;
if (pow5[pc - 1] == 0)
pc--;
partsCount[n] = pc;
if (n != 0) {
APInt::tcFullMultiply(pow5, pow5 - partsCount, pow5 - partsCount,
partsCount, partsCount);
partsCount *= 2;
if (pow5[partsCount - 1] == 0)
partsCount--;
}

if (power & 1) {
APFloatBase::integerPart *tmp;

APInt::tcFullMultiply(p2, p1, pow5, result, pc);
result += pc;
APInt::tcFullMultiply(p2, p1, pow5, result, partsCount);
result += partsCount;
if (p2[result - 1] == 0)
result--;

Expand All @@ -776,7 +771,7 @@ powerOf5(APFloatBase::integerPart *dst, unsigned int power) {
p2 = tmp;
}

pow5 += pc;
pow5 += partsCount;
}

if (p1 != dst)
Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/Target/AArch64/AArch64Features.td
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ class Extension<
// not doing so.
string MArchName = TargetFeatureName;

// An alias that can be used on the command line, if the extension has one.
// Used for correcting historical names while remaining backwards compatible.
string MArchAlias = "";

// Function MultiVersioning (FMV) properties

// A C++ expression giving the number of the bit in the FMV ABI.
Expand Down Expand Up @@ -163,6 +167,7 @@ def FeatureOutlineAtomics : SubtargetFeature<"outline-atomics", "OutlineAtomics"
def FeatureFMV : SubtargetFeature<"fmv", "HasFMV", "true",
"Enable Function Multi Versioning support.">;

let MArchAlias = "rdma" in
def FeatureRDM : Extension<"rdm", "RDM",
"Enable ARMv8.1 Rounding Double Multiply Add/Subtract instructions (FEAT_RDM)",
[FeatureNEON],
Expand Down
7 changes: 6 additions & 1 deletion llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1868,7 +1868,12 @@ bool AArch64TargetLowering::shouldExpandGetActiveLaneMask(EVT ResVT,
}

bool AArch64TargetLowering::shouldExpandCttzElements(EVT VT) const {
return !Subtarget->hasSVEorSME() || VT != MVT::nxv16i1;
if (!Subtarget->hasSVEorSME())
return true;

// We can only use the BRKB + CNTP sequence with legal predicate types.
return VT != MVT::nxv16i1 && VT != MVT::nxv8i1 && VT != MVT::nxv4i1 &&
VT != MVT::nxv2i1;
}

void AArch64TargetLowering::addTypeForFixedLengthSVE(MVT VT) {
Expand Down
46 changes: 46 additions & 0 deletions llvm/lib/Target/AArch64/AArch64InstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -5449,6 +5449,52 @@ defm : SelectSetCCSwapOperands<setle, "CMGE">;
defm : SelectSetCCSwapOperands<setult, "CMHI">;
defm : SelectSetCCSwapOperands<setule, "CMHS">;

multiclass SelectSetCCZeroRHS<PatFrags InFrag, string INST> {
def : Pat<(v8i8 (InFrag (v8i8 V64:$Rn), immAllZerosV)),
(v8i8 (!cast<Instruction>(INST # v8i8rz) (v8i8 V64:$Rn)))>;
def : Pat<(v16i8 (InFrag (v16i8 V128:$Rn), immAllZerosV)),
(v16i8 (!cast<Instruction>(INST # v16i8rz) (v16i8 V128:$Rn)))>;
def : Pat<(v4i16 (InFrag (v4i16 V64:$Rn), immAllZerosV)),
(v4i16 (!cast<Instruction>(INST # v4i16rz) (v4i16 V64:$Rn)))>;
def : Pat<(v8i16 (InFrag (v8i16 V128:$Rn), immAllZerosV)),
(v8i16 (!cast<Instruction>(INST # v8i16rz) (v8i16 V128:$Rn)))>;
def : Pat<(v2i32 (InFrag (v2i32 V64:$Rn), immAllZerosV)),
(v2i32 (!cast<Instruction>(INST # v2i32rz) (v2i32 V64:$Rn)))>;
def : Pat<(v4i32 (InFrag (v4i32 V128:$Rn), immAllZerosV)),
(v4i32 (!cast<Instruction>(INST # v4i32rz) (v4i32 V128:$Rn)))>;
def : Pat<(v2i64 (InFrag (v2i64 V128:$Rn), immAllZerosV)),
(v2i64 (!cast<Instruction>(INST # v2i64rz) (v2i64 V128:$Rn)))>;
}

defm : SelectSetCCZeroRHS<seteq, "CMEQ">;
defm : SelectSetCCZeroRHS<setgt, "CMGT">;
defm : SelectSetCCZeroRHS<setge, "CMGE">;
defm : SelectSetCCZeroRHS<setlt, "CMLT">;
defm : SelectSetCCZeroRHS<setle, "CMLE">;

multiclass SelectSetCCZeroLHS<PatFrags InFrag, string INST> {
def : Pat<(v8i8 (InFrag immAllZerosV, (v8i8 V64:$Rn))),
(v8i8 (!cast<Instruction>(INST # v8i8rz) (v8i8 V64:$Rn)))>;
def : Pat<(v16i8 (InFrag immAllZerosV, (v16i8 V128:$Rn))),
(v16i8 (!cast<Instruction>(INST # v16i8rz) (v16i8 V128:$Rn)))>;
def : Pat<(v4i16 (InFrag immAllZerosV, (v4i16 V64:$Rn))),
(v4i16 (!cast<Instruction>(INST # v4i16rz) (v4i16 V64:$Rn)))>;
def : Pat<(v8i16 (InFrag immAllZerosV, (v8i16 V128:$Rn))),
(v8i16 (!cast<Instruction>(INST # v8i16rz) (v8i16 V128:$Rn)))>;
def : Pat<(v2i32 (InFrag immAllZerosV, (v2i32 V64:$Rn))),
(v2i32 (!cast<Instruction>(INST # v2i32rz) (v2i32 V64:$Rn)))>;
def : Pat<(v4i32 (InFrag immAllZerosV, (v4i32 V128:$Rn))),
(v4i32 (!cast<Instruction>(INST # v4i32rz) (v4i32 V128:$Rn)))>;
def : Pat<(v2i64 (InFrag immAllZerosV, (v2i64 V128:$Rn))),
(v2i64 (!cast<Instruction>(INST # v2i64rz) (v2i64 V128:$Rn)))>;
}

defm : SelectSetCCZeroLHS<seteq, "CMEQ">;
defm : SelectSetCCZeroLHS<setgt, "CMLT">;
defm : SelectSetCCZeroLHS<setge, "CMLE">;
defm : SelectSetCCZeroLHS<setlt, "CMGT">;
defm : SelectSetCCZeroLHS<setle, "CMGE">;

let Predicates = [HasNEON] in {
def : InstAlias<"mov{\t$dst.16b, $src.16b|.16b\t$dst, $src}",
(ORRv16i8 V128:$dst, V128:$src, V128:$src), 1>;
Expand Down
36 changes: 36 additions & 0 deletions llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -2082,6 +2082,18 @@ let Predicates = [HasSVEorSME] in {
def : Pat<(i64 (AArch64CttzElts nxv16i1:$Op1)),
(CNTP_XPP_B (BRKB_PPzP (PTRUE_B 31), PPR:$Op1),
(BRKB_PPzP (PTRUE_B 31), PPR:$Op1))>;

def : Pat<(i64 (AArch64CttzElts nxv8i1:$Op1)),
(CNTP_XPP_H (BRKB_PPzP (PTRUE_H 31), PPR:$Op1),
(BRKB_PPzP (PTRUE_H 31), PPR:$Op1))>;

def : Pat<(i64 (AArch64CttzElts nxv4i1:$Op1)),
(CNTP_XPP_S (BRKB_PPzP (PTRUE_S 31), PPR:$Op1),
(BRKB_PPzP (PTRUE_S 31), PPR:$Op1))>;

def : Pat<(i64 (AArch64CttzElts nxv2i1:$Op1)),
(CNTP_XPP_D (BRKB_PPzP (PTRUE_D 31), PPR:$Op1),
(BRKB_PPzP (PTRUE_D 31), PPR:$Op1))>;
}

defm INCB_XPiI : sve_int_pred_pattern_a<0b000, "incb", add, int_aarch64_sve_cntb>;
Expand Down Expand Up @@ -2175,6 +2187,30 @@ let Predicates = [HasSVEorSME] in {
(INSERT_SUBREG (IMPLICIT_DEF), GPR32:$Op1, sub_32)),
sub_32)>;

def : Pat<(i64 (add GPR64:$Op1, (i64 (AArch64CttzElts nxv8i1:$Op2)))),
(INCP_XP_H (BRKB_PPzP (PTRUE_H 31), PPR:$Op2), GPR64:$Op1)>;

def : Pat<(i32 (add GPR32:$Op1, (trunc (i64 (AArch64CttzElts nxv8i1:$Op2))))),
(EXTRACT_SUBREG (INCP_XP_H (BRKB_PPzP (PTRUE_H 31), PPR:$Op2),
(INSERT_SUBREG (IMPLICIT_DEF), GPR32:$Op1, sub_32)),
sub_32)>;

def : Pat<(i64 (add GPR64:$Op1, (i64 (AArch64CttzElts nxv4i1:$Op2)))),
(INCP_XP_S (BRKB_PPzP (PTRUE_S 31), PPR:$Op2), GPR64:$Op1)>;

def : Pat<(i32 (add GPR32:$Op1, (trunc (i64 (AArch64CttzElts nxv4i1:$Op2))))),
(EXTRACT_SUBREG (INCP_XP_S (BRKB_PPzP (PTRUE_S 31), PPR:$Op2),
(INSERT_SUBREG (IMPLICIT_DEF), GPR32:$Op1, sub_32)),
sub_32)>;

def : Pat<(i64 (add GPR64:$Op1, (i64 (AArch64CttzElts nxv2i1:$Op2)))),
(INCP_XP_D (BRKB_PPzP (PTRUE_D 31), PPR:$Op2), GPR64:$Op1)>;

def : Pat<(i32 (add GPR32:$Op1, (trunc (i64 (AArch64CttzElts nxv2i1:$Op2))))),
(EXTRACT_SUBREG (INCP_XP_D (BRKB_PPzP (PTRUE_D 31), PPR:$Op2),
(INSERT_SUBREG (IMPLICIT_DEF), GPR32:$Op1, sub_32)),
sub_32)>;

defm INDEX_RR : sve_int_index_rr<"index", AArch64mul_p_oneuse>;
defm INDEX_IR : sve_int_index_ir<"index", AArch64mul_p, AArch64mul_p_oneuse>;
defm INDEX_RI : sve_int_index_ri<"index">;
Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2861,8 +2861,8 @@ bool AArch64InstructionSelector::select(MachineInstr &I) {
Order != AtomicOrdering::Unordered &&
Order != AtomicOrdering::Monotonic) {
assert(!isa<GZExtLoad>(LdSt));
if (MemSizeInBytes > 64)
return false;
assert(MemSizeInBytes <= 8 &&
"128-bit atomics should already be custom-legalized");

if (isa<GLoad>(LdSt)) {
static constexpr unsigned LDAPROpcodes[] = {
Expand Down
30 changes: 13 additions & 17 deletions llvm/lib/Target/AMDGPU/SIISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,9 +233,6 @@ SITargetLowering::SITargetLowering(const TargetMachine &TM,
// sources.
setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom);
setOperationAction(ISD::FP_TO_UINT, MVT::i32, Custom);

setOperationAction(ISD::BUILD_VECTOR, MVT::v2bf16, Promote);
AddPromotedToType(ISD::BUILD_VECTOR, MVT::v2bf16, MVT::v2i16);
}

setTruncStoreAction(MVT::v2i32, MVT::v2i16, Expand);
Expand Down Expand Up @@ -744,9 +741,8 @@ SITargetLowering::SITargetLowering(const TargetMachine &TM,
setOperationAction({ISD::ANY_EXTEND, ISD::ZERO_EXTEND, ISD::SIGN_EXTEND},
MVT::v8i32, Expand);

if (!Subtarget->hasVOP3PInsts())
setOperationAction(ISD::BUILD_VECTOR,
{MVT::v2i16, MVT::v2f16, MVT::v2bf16}, Custom);
setOperationAction(ISD::BUILD_VECTOR, {MVT::v2i16, MVT::v2f16, MVT::v2bf16},
Subtarget->hasVOP3PInsts() ? Legal : Custom);

setOperationAction(ISD::FNEG, MVT::v2f16, Legal);
// This isn't really legal, but this avoids the legalizer unrolling it (and
Expand Down Expand Up @@ -3863,20 +3859,20 @@ SDValue SITargetLowering::LowerCall(CallLoweringInfo &CLI,
assert(Mask && "Missing call preserved mask for calling convention");
Ops.push_back(DAG.getRegisterMask(Mask));

if (InGlue.getNode())
Ops.push_back(InGlue);

// NOTE: This potentially results in *two* glue operands, and the wrong one
// might possibly show up where the other was intended. In particular,
// Emitter::EmitMachineNode() expects only the glued convergence token if it
// exists. Similarly, the selection of the call expects to match only the
// InGlue operand if it exists.
if (SDValue Token = CLI.ConvergenceControlToken) {
Ops.push_back(SDValue(DAG.getMachineNode(TargetOpcode::CONVERGENCECTRL_GLUE,
DL, MVT::Glue, Token),
0));
SmallVector<SDValue, 2> GlueOps;
GlueOps.push_back(Token);
if (InGlue)
GlueOps.push_back(InGlue);

InGlue = SDValue(DAG.getMachineNode(TargetOpcode::CONVERGENCECTRL_GLUE, DL,
MVT::Glue, GlueOps),
0);
}

if (InGlue)
Ops.push_back(InGlue);

SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);

// If we're doing a tall call, use a TC_RETURN here rather than an
Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/Target/AMDGPU/SIInstructions.td
Original file line number Diff line number Diff line change
Expand Up @@ -3166,7 +3166,7 @@ def : GCNPat <
(v2f16 (V_AND_B32_e64 (i32 (V_MOV_B32_e32 (i32 0xffff))), VGPR_32:$src1))
>;

foreach vecTy = [v2i16, v2f16] in {
foreach vecTy = [v2i16, v2f16, v2bf16] in {

defvar Ty = vecTy.ElementType;

Expand Down Expand Up @@ -3212,7 +3212,7 @@ def : GCNPat <
>;


foreach vecTy = [v2i16, v2f16] in {
foreach vecTy = [v2i16, v2f16, v2bf16] in {

defvar Ty = vecTy.ElementType;
defvar immzeroTy = !if(!eq(Ty, i16), immzero, fpimmzero);
Expand Down
77 changes: 29 additions & 48 deletions llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,63 +216,44 @@ void RISCVInstPrinter::printVTypeI(const MCInst *MI, unsigned OpNo,
RISCVVType::printVType(Imm, O);
}

// Print a Zcmp RList. If we are printing architectural register names rather
// than ABI register names, we need to print "{x1, x8-x9, x18-x27}" for all
// registers. Otherwise, we print "{ra, s0-s11}".
void RISCVInstPrinter::printRlist(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI, raw_ostream &O) {
unsigned Imm = MI->getOperand(OpNo).getImm();
O << "{";
switch (Imm) {
case RISCVZC::RLISTENCODE::RA:
markup(O, Markup::Register) << (ArchRegNames ? "x1" : "ra");
break;
case RISCVZC::RLISTENCODE::RA_S0:
markup(O, Markup::Register) << (ArchRegNames ? "x1" : "ra");
O << ", ";
markup(O, Markup::Register) << (ArchRegNames ? "x8" : "s0");
break;
case RISCVZC::RLISTENCODE::RA_S0_S1:
markup(O, Markup::Register) << (ArchRegNames ? "x1" : "ra");
O << ", ";
markup(O, Markup::Register) << (ArchRegNames ? "x8" : "s0");
O << '-';
markup(O, Markup::Register) << (ArchRegNames ? "x9" : "s1");
break;
case RISCVZC::RLISTENCODE::RA_S0_S2:
markup(O, Markup::Register) << (ArchRegNames ? "x1" : "ra");
O << ", ";
markup(O, Markup::Register) << (ArchRegNames ? "x8" : "s0");
O << '-';
markup(O, Markup::Register) << (ArchRegNames ? "x9" : "s2");
if (ArchRegNames) {
O << ", ";
markup(O, Markup::Register) << "x18";
}
break;
case RISCVZC::RLISTENCODE::RA_S0_S3:
case RISCVZC::RLISTENCODE::RA_S0_S4:
case RISCVZC::RLISTENCODE::RA_S0_S5:
case RISCVZC::RLISTENCODE::RA_S0_S6:
case RISCVZC::RLISTENCODE::RA_S0_S7:
case RISCVZC::RLISTENCODE::RA_S0_S8:
case RISCVZC::RLISTENCODE::RA_S0_S9:
case RISCVZC::RLISTENCODE::RA_S0_S11:
markup(O, Markup::Register) << (ArchRegNames ? "x1" : "ra");
printRegName(O, RISCV::X1);

if (Imm >= RISCVZC::RLISTENCODE::RA_S0) {
O << ", ";
markup(O, Markup::Register) << (ArchRegNames ? "x8" : "s0");
printRegName(O, RISCV::X8);
}

if (Imm >= RISCVZC::RLISTENCODE::RA_S0_S1) {
O << '-';
if (ArchRegNames) {
markup(O, Markup::Register) << "x9";
if (Imm == RISCVZC::RLISTENCODE::RA_S0_S1 || ArchRegNames)
printRegName(O, RISCV::X9);
}

if (Imm >= RISCVZC::RLISTENCODE::RA_S0_S2) {
if (ArchRegNames)
O << ", ";
markup(O, Markup::Register) << "x18";
if (Imm == RISCVZC::RLISTENCODE::RA_S0_S2 || ArchRegNames)
printRegName(O, RISCV::X18);
}

if (Imm >= RISCVZC::RLISTENCODE::RA_S0_S3) {
if (ArchRegNames)
O << '-';
}
markup(O, Markup::Register) << getRegisterName(
RISCV::X19 + (Imm == RISCVZC::RLISTENCODE::RA_S0_S11
? 8
: Imm - RISCVZC::RLISTENCODE::RA_S0_S3));
break;
default:
llvm_unreachable("invalid register list");
unsigned Offset = (Imm - RISCVZC::RLISTENCODE::RA_S0_S3);
// Encodings for S3-S9 are contiguous. There is no encoding for S10, so we
// must skip to S11(X27).
if (Imm == RISCVZC::RLISTENCODE::RA_S0_S11)
++Offset;
printRegName(O, RISCV::X19 + Offset);
}

O << "}";
}

Expand Down
35 changes: 16 additions & 19 deletions llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,16 @@ RISCVFrameLowering::RISCVFrameLowering(const RISCVSubtarget &STI)
/*TransientStackAlignment=*/getABIStackAlignment(STI.getTargetABI())),
STI(STI) {}

static const MCPhysReg AllPopRegs[] = {
RISCV::X1, RISCV::X8, RISCV::X9, RISCV::X18, RISCV::X19,
RISCV::X20, RISCV::X21, RISCV::X22, RISCV::X23, RISCV::X24,
RISCV::X25, RISCV::X26, RISCV::X27};
// Offsets which need to be scale by XLen representing locations of CSRs which
// are given a fixed location by save/restore libcalls or Zcmp Push/Pop.
static const std::pair<MCPhysReg, int8_t> FixedCSRFIMap[] = {
{/*ra*/ RISCV::X1, -1}, {/*s0*/ RISCV::X8, -2},
{/*s1*/ RISCV::X9, -3}, {/*s2*/ RISCV::X18, -4},
{/*s3*/ RISCV::X19, -5}, {/*s4*/ RISCV::X20, -6},
{/*s5*/ RISCV::X21, -7}, {/*s6*/ RISCV::X22, -8},
{/*s7*/ RISCV::X23, -9}, {/*s8*/ RISCV::X24, -10},
{/*s9*/ RISCV::X25, -11}, {/*s10*/ RISCV::X26, -12},
{/*s11*/ RISCV::X27, -13}};

// For now we use x3, a.k.a gp, as pointer to shadow call stack.
// User should not use x3 in their asm.
Expand Down Expand Up @@ -170,7 +176,7 @@ static int getLibCallID(const MachineFunction &MF,

Register MaxReg = RISCV::NoRegister;
for (auto &CS : CSI)
// RISCVRegisterInfo::hasReservedSpillSlot assigns negative frame indexes to
// assignCalleeSavedSpillSlots assigns negative frame indexes to
// registers which can be saved by libcall.
if (CS.getFrameIdx() < 0)
MaxReg = std::max(MaxReg.id(), CS.getReg().id());
Expand Down Expand Up @@ -291,7 +297,9 @@ static Register getMaxPushPopReg(const MachineFunction &MF,
const std::vector<CalleeSavedInfo> &CSI) {
Register MaxPushPopReg = RISCV::NoRegister;
for (auto &CS : CSI) {
if (llvm::is_contained(AllPopRegs, CS.getReg().id()))
if (llvm::find_if(FixedCSRFIMap, [&](auto P) {
return P.first == CS.getReg();
}) != std::end(FixedCSRFIMap))
MaxPushPopReg = std::max(MaxPushPopReg.id(), CS.getReg().id());
}
// if rlist is {rs, s0-s10}, then s11 will also be included
Expand Down Expand Up @@ -1385,17 +1393,6 @@ RISCVFrameLowering::getFirstSPAdjustAmount(const MachineFunction &MF) const {
return 0;
}

// Offsets which need to be scale by XLen representing locations of CSRs which
// are given a fixed location by save/restore libcalls or Zcmp Push/Pop.
static const std::pair<MCPhysReg, int8_t> FixedCSRFIMap[] = {
{/*ra*/ RISCV::X1, -1}, {/*s0*/ RISCV::X8, -2},
{/*s1*/ RISCV::X9, -3}, {/*s2*/ RISCV::X18, -4},
{/*s3*/ RISCV::X19, -5}, {/*s4*/ RISCV::X20, -6},
{/*s5*/ RISCV::X21, -7}, {/*s6*/ RISCV::X22, -8},
{/*s7*/ RISCV::X23, -9}, {/*s8*/ RISCV::X24, -10},
{/*s9*/ RISCV::X25, -11}, {/*s10*/ RISCV::X26, -12},
{/*s11*/ RISCV::X27, -13}};

bool RISCVFrameLowering::assignCalleeSavedSpillSlots(
MachineFunction &MF, const TargetRegisterInfo *TRI,
std::vector<CalleeSavedInfo> &CSI, unsigned &MinCSFrameIndex,
Expand Down Expand Up @@ -1498,7 +1495,7 @@ bool RISCVFrameLowering::spillCalleeSavedRegisters(
PushBuilder.addImm(0);

for (unsigned i = 0; i < PushedRegNum; i++)
PushBuilder.addUse(AllPopRegs[i], RegState::Implicit);
PushBuilder.addUse(FixedCSRFIMap[i].first, RegState::Implicit);
}
} else if (const char *SpillLibCall = getSpillLibCallName(*MF, CSI)) {
// Add spill libcall via non-callee-saved register t0.
Expand Down Expand Up @@ -1611,7 +1608,7 @@ bool RISCVFrameLowering::restoreCalleeSavedRegisters(
PopBuilder.addImm(0);

for (unsigned i = 0; i < RVFI->getRVPushRegs(); i++)
PopBuilder.addDef(AllPopRegs[i], RegState::ImplicitDefine);
PopBuilder.addDef(FixedCSRFIMap[i].first, RegState::ImplicitDefine);
}
} else {
const char *RestoreLibCall = getRestoreLibCallName(*MF, CSI);
Expand Down
15 changes: 15 additions & 0 deletions llvm/lib/Target/RISCV/RISCVISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20067,6 +20067,7 @@ const char *RISCVTargetLowering::getTargetNodeName(unsigned Opcode) const {
NODE_NAME_CASE(SWAP_CSR)
NODE_NAME_CASE(CZERO_EQZ)
NODE_NAME_CASE(CZERO_NEZ)
NODE_NAME_CASE(SW_GUARDED_BRIND)
NODE_NAME_CASE(SF_VC_XV_SE)
NODE_NAME_CASE(SF_VC_IV_SE)
NODE_NAME_CASE(SF_VC_VV_SE)
Expand Down Expand Up @@ -21660,6 +21661,20 @@ MCPhysReg RVVArgDispatcher::getNextPhysReg() {
return AllocatedPhysRegs[CurIdx++];
}

SDValue RISCVTargetLowering::expandIndirectJTBranch(const SDLoc &dl,
SDValue Value, SDValue Addr,
int JTI,
SelectionDAG &DAG) const {
if (Subtarget.hasStdExtZicfilp()) {
// When Zicfilp enabled, we need to use software guarded branch for jump
// table branch.
SDValue JTInfo = DAG.getJumpTableDebugInfo(JTI, Value, dl);
return DAG.getNode(RISCVISD::SW_GUARDED_BRIND, dl, MVT::Other, JTInfo,
Addr);
}
return TargetLowering::expandIndirectJTBranch(dl, Value, Addr, JTI, DAG);
}

namespace llvm::RISCVVIntrinsicsTable {

#define GET_RISCVVIntrinsicsTable_IMPL
Expand Down
7 changes: 7 additions & 0 deletions llvm/lib/Target/RISCV/RISCVISelLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,10 @@ enum NodeType : unsigned {
CZERO_EQZ, // vt.maskc for XVentanaCondOps.
CZERO_NEZ, // vt.maskcn for XVentanaCondOps.

/// Software guarded BRIND node. Operand 0 is the chain operand and
/// operand 1 is the target address.
SW_GUARDED_BRIND,

// FP to 32 bit int conversions for RV64. These are used to keep track of the
// result being sign extended to 64 bit. These saturate out of range inputs.
STRICT_FCVT_W_RV64 = ISD::FIRST_TARGET_STRICTFP_OPCODE,
Expand Down Expand Up @@ -869,6 +873,9 @@ class RISCVTargetLowering : public TargetLowering {

bool supportKCFIBundles() const override { return true; }

SDValue expandIndirectJTBranch(const SDLoc &dl, SDValue Value, SDValue Addr,
int JTI, SelectionDAG &DAG) const override;

MachineInstr *EmitKCFICheck(MachineBasicBlock &MBB,
MachineBasicBlock::instr_iterator &MBBI,
const TargetInstrInfo *TII) const override;
Expand Down
11 changes: 10 additions & 1 deletion llvm/lib/Target/RISCV/RISCVInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ def riscv_brcc : SDNode<"RISCVISD::BR_CC", SDT_RISCVBrCC,
def riscv_tail : SDNode<"RISCVISD::TAIL", SDT_RISCVCall,
[SDNPHasChain, SDNPOptInGlue, SDNPOutGlue,
SDNPVariadic]>;
def riscv_sw_guarded_brind : SDNode<"RISCVISD::SW_GUARDED_BRIND",
SDTBrind, [SDNPHasChain]>;
def riscv_sllw : SDNode<"RISCVISD::SLLW", SDT_RISCVIntBinOpW>;
def riscv_sraw : SDNode<"RISCVISD::SRAW", SDT_RISCVIntBinOpW>;
def riscv_srlw : SDNode<"RISCVISD::SRLW", SDT_RISCVIntBinOpW>;
Expand Down Expand Up @@ -1454,16 +1456,23 @@ def PseudoBRIND : Pseudo<(outs), (ins GPRJALR:$rs1, simm12:$imm12), []>,
PseudoInstExpansion<(JALR X0, GPR:$rs1, simm12:$imm12)>;

let Predicates = [HasStdExtZicfilp],
isBarrier = 1, isBranch = 1, isIndirectBranch = 1, isTerminator = 1 in
isBarrier = 1, isBranch = 1, isIndirectBranch = 1, isTerminator = 1 in {
def PseudoBRINDNonX7 : Pseudo<(outs), (ins GPRJALRNonX7:$rs1, simm12:$imm12), []>,
PseudoInstExpansion<(JALR X0, GPR:$rs1, simm12:$imm12)>;
def PseudoBRINDX7 : Pseudo<(outs), (ins GPRX7:$rs1, simm12:$imm12), []>,
PseudoInstExpansion<(JALR X0, GPR:$rs1, simm12:$imm12)>;
}

// For Zicfilp, need to avoid using X7/T2 for indirect branches which need
// landing pad.
let Predicates = [HasStdExtZicfilp] in {
def : Pat<(brind GPRJALRNonX7:$rs1), (PseudoBRINDNonX7 GPRJALRNonX7:$rs1, 0)>;
def : Pat<(brind (add GPRJALRNonX7:$rs1, simm12:$imm12)),
(PseudoBRINDNonX7 GPRJALRNonX7:$rs1, simm12:$imm12)>;

def : Pat<(riscv_sw_guarded_brind GPRX7:$rs1), (PseudoBRINDX7 GPRX7:$rs1, 0)>;
def : Pat<(riscv_sw_guarded_brind (add GPRX7:$rs1, simm12:$imm12)),
(PseudoBRINDX7 GPRX7:$rs1, simm12:$imm12)>;
}

let Predicates = [NoStdExtZicfilp] in {
Expand Down
6 changes: 5 additions & 1 deletion llvm/lib/Target/RISCV/RISCVProfiles.td
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@

class RISCVProfile<string name, list<SubtargetFeature> features>
: SubtargetFeature<name, "Is" # NAME, "true",
"RISC-V " # name # " profile", features>;
"RISC-V " # name # " profile", features> {
// Indicates if the profile is not yet ratified, so should be treated as
// experimental.
bit Experimental = false;
}

defvar RVI20U32Features = [Feature32Bit, FeatureStdExtI];
defvar RVI20U64Features = [Feature64Bit, FeatureStdExtI];
Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ RISCVRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
}

bool HasVectorCSR =
MF->getFunction().getCallingConv() == CallingConv::RISCV_VectorCall;
MF->getFunction().getCallingConv() == CallingConv::RISCV_VectorCall &&
Subtarget.hasVInstructions();

switch (Subtarget.getTargetABI()) {
default:
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Target/RISCV/RISCVRegisterInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ def GPRNoX0 : GPRRegisterClass<(sub GPR, X0)>;

def GPRNoX0X2 : GPRRegisterClass<(sub GPR, X0, X2)>;

def GPRX7 : GPRRegisterClass<(add X7)>;

// Don't use X1 or X5 for JALR since that is a hint to pop the return address
// stack on some microarchitectures. Also remove the reserved registers X0, X2,
// X3, and X4 as it reduces the number of register classes that get synthesized
Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -430,8 +430,8 @@ bool SPIRVCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
.addImm(static_cast<uint32_t>(executionModel))
.addUse(FuncVReg);
addStringImm(F.getName(), MIB);
} else if (F.getLinkage() == GlobalValue::LinkageTypes::ExternalLinkage ||
F.getLinkage() == GlobalValue::LinkOnceODRLinkage) {
} else if (F.getLinkage() != GlobalValue::InternalLinkage &&
F.getLinkage() != GlobalValue::PrivateLinkage) {
SPIRV::LinkageType::LinkageType LnkTy =
F.isDeclaration()
? SPIRV::LinkageType::Import
Expand Down
11 changes: 11 additions & 0 deletions llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ class SPIRVEmitIntrinsics
unsigned OperandToReplace,
IRBuilder<> &B);
void insertPtrCastOrAssignTypeInstr(Instruction *I, IRBuilder<> &B);
void insertSpirvDecorations(Instruction *I, IRBuilder<> &B);
void processGlobalValue(GlobalVariable &GV, IRBuilder<> &B);
void processParamTypes(Function *F, IRBuilder<> &B);
void processParamTypesByFunHeader(Function *F, IRBuilder<> &B);
Expand Down Expand Up @@ -1116,6 +1117,15 @@ void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I,
}
}

void SPIRVEmitIntrinsics::insertSpirvDecorations(Instruction *I,
IRBuilder<> &B) {
if (MDNode *MD = I->getMetadata("spirv.Decorations")) {
B.SetInsertPoint(I->getNextNode());
B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {I->getType()},
{I, MetadataAsValue::get(I->getContext(), MD)});
}
}

void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *I,
IRBuilder<> &B) {
auto *II = dyn_cast<IntrinsicInst>(I);
Expand Down Expand Up @@ -1287,6 +1297,7 @@ bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
insertAssignPtrTypeIntrs(I, B);
insertAssignTypeIntrs(I, B);
insertPtrCastOrAssignTypeInstr(I, B);
insertSpirvDecorations(I, B);
}

for (auto &I : instructions(Func))
Expand Down
7 changes: 7 additions & 0 deletions llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -691,6 +691,13 @@ Register SPIRVGlobalRegistry::buildGlobalVariable(
buildOpDecorate(Reg, MIRBuilder, SPIRV::Decoration::BuiltIn,
{static_cast<uint32_t>(BuiltInId)});

// If it's a global variable with "spirv.Decorations" metadata node
// recognize it as a SPIR-V friendly LLVM IR and parse "spirv.Decorations"
// arguments.
MDNode *GVarMD = nullptr;
if (GVar && (GVarMD = GVar->getMetadata("spirv.Decorations")) != nullptr)
buildOpSpirvDecorations(Reg, MIRBuilder, GVarMD);

return Reg;
}

Expand Down
9 changes: 9 additions & 0 deletions llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,15 @@ bool SPIRVInstructionSelector::spvSelect(Register ResVReg,
case TargetOpcode::G_UMULH:
return selectExtInst(ResVReg, ResType, I, CL::u_mul_hi);

case TargetOpcode::G_SADDSAT:
return selectExtInst(ResVReg, ResType, I, CL::s_add_sat);
case TargetOpcode::G_UADDSAT:
return selectExtInst(ResVReg, ResType, I, CL::u_add_sat);
case TargetOpcode::G_SSUBSAT:
return selectExtInst(ResVReg, ResType, I, CL::s_sub_sat);
case TargetOpcode::G_USUBSAT:
return selectExtInst(ResVReg, ResType, I, CL::u_sub_sat);

case TargetOpcode::G_SEXT:
return selectExt(ResVReg, ResType, I, true);
case TargetOpcode::G_ANYEXT:
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,10 @@ SPIRVLegalizerInfo::SPIRVLegalizerInfo(const SPIRVSubtarget &ST) {

// Struct return types become a single scalar, so cannot easily legalize.
getActionDefinitionsBuilder({G_SMULH, G_UMULH}).alwaysLegal();

// supported saturation arithmetic
getActionDefinitionsBuilder({G_SADDSAT, G_UADDSAT, G_SSUBSAT, G_USUBSAT})
.legalFor(allIntScalarsAndVectors);
}

getLegacyLegalizerInfo().computeTables();
Expand Down
17 changes: 17 additions & 0 deletions llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,22 @@ static void processInstrsWithTypeFolding(MachineFunction &MF,
}
}

static void insertSpirvDecorations(MachineFunction &MF, MachineIRBuilder MIB) {
SmallVector<MachineInstr *, 10> ToErase;
for (MachineBasicBlock &MBB : MF) {
for (MachineInstr &MI : MBB) {
if (!isSpvIntrinsic(MI, Intrinsic::spv_assign_decoration))
continue;
MIB.setInsertPt(*MI.getParent(), MI);
buildOpSpirvDecorations(MI.getOperand(1).getReg(), MIB,
MI.getOperand(2).getMetadata());
ToErase.push_back(&MI);
}
}
for (MachineInstr *MI : ToErase)
MI->eraseFromParent();
}

// Find basic blocks of the switch and replace registers in spv_switch() by its
// MBB equivalent.
static void processSwitches(MachineFunction &MF, SPIRVGlobalRegistry *GR,
Expand Down Expand Up @@ -639,6 +655,7 @@ bool SPIRVPreLegalizer::runOnMachineFunction(MachineFunction &MF) {
processSwitches(MF, GR, MIB);
processInstrsWithTypeFolding(MF, GR, MIB);
removeImplicitFallthroughs(MF, MIB);
insertSpirvDecorations(MF, MIB);

return true;
}
Expand Down
28 changes: 28 additions & 0 deletions llvm/lib/Target/SPIRV/SPIRVUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,34 @@ void buildOpDecorate(Register Reg, MachineInstr &I, const SPIRVInstrInfo &TII,
finishBuildOpDecorate(MIB, DecArgs, StrImm);
}

void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder,
const MDNode *GVarMD) {
for (unsigned I = 0, E = GVarMD->getNumOperands(); I != E; ++I) {
auto *OpMD = dyn_cast<MDNode>(GVarMD->getOperand(I));
if (!OpMD)
report_fatal_error("Invalid decoration");
if (OpMD->getNumOperands() == 0)
report_fatal_error("Expect operand(s) of the decoration");
ConstantInt *DecorationId =
mdconst::dyn_extract<ConstantInt>(OpMD->getOperand(0));
if (!DecorationId)
report_fatal_error("Expect SPIR-V <Decoration> operand to be the first "
"element of the decoration");
auto MIB = MIRBuilder.buildInstr(SPIRV::OpDecorate)
.addUse(Reg)
.addImm(static_cast<uint32_t>(DecorationId->getZExtValue()));
for (unsigned OpI = 1, OpE = OpMD->getNumOperands(); OpI != OpE; ++OpI) {
if (ConstantInt *OpV =
mdconst::dyn_extract<ConstantInt>(OpMD->getOperand(OpI)))
MIB.addImm(static_cast<uint32_t>(OpV->getZExtValue()));
else if (MDString *OpV = dyn_cast<MDString>(OpMD->getOperand(OpI)))
addStringImm(OpV->getString(), MIB);
else
report_fatal_error("Unexpected operand of the decoration");
}
}
}

// TODO: maybe the following two functions should be handled in the subtarget
// to allow for different OpenCL vs Vulkan handling.
unsigned storageClassToAddressSpace(SPIRV::StorageClass::StorageClass SC) {
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/Target/SPIRV/SPIRVUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ void buildOpDecorate(Register Reg, MachineInstr &I, const SPIRVInstrInfo &TII,
const std::vector<uint32_t> &DecArgs,
StringRef StrImm = "");

// Add an OpDecorate instruction by "spirv.Decorations" metadata node.
void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder,
const MDNode *GVarMD);

// Convert a SPIR-V storage class to the corresponding LLVM IR address space.
unsigned storageClassToAddressSpace(SPIRV::StorageClass::StorageClass SC);

Expand Down
7 changes: 4 additions & 3 deletions llvm/lib/Target/X86/X86ISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56741,6 +56741,7 @@ static SDValue combineFP16_TO_FP(SDNode *N, SelectionDAG &DAG,
}

static SDValue combineFP_EXTEND(SDNode *N, SelectionDAG &DAG,
TargetLowering::DAGCombinerInfo &DCI,
const X86Subtarget &Subtarget) {
EVT VT = N->getValueType(0);
bool IsStrict = N->isStrictFPOpcode();
Expand All @@ -56749,8 +56750,8 @@ static SDValue combineFP_EXTEND(SDNode *N, SelectionDAG &DAG,

SDLoc dl(N);
if (SrcVT.getScalarType() == MVT::bf16) {
if (!IsStrict && Src.getOpcode() == ISD::FP_ROUND &&
Src.getOperand(0).getValueType() == VT)
if (DCI.isAfterLegalizeDAG() && Src.getOpcode() == ISD::FP_ROUND &&
!IsStrict && Src.getOperand(0).getValueType() == VT)
return Src.getOperand(0);

if (!SrcVT.isVector())
Expand Down Expand Up @@ -57168,7 +57169,7 @@ SDValue X86TargetLowering::PerformDAGCombine(SDNode *N,
case X86ISD::KSHIFTR: return combineKSHIFT(N, DAG, DCI);
case ISD::FP16_TO_FP: return combineFP16_TO_FP(N, DAG, Subtarget);
case ISD::STRICT_FP_EXTEND:
case ISD::FP_EXTEND: return combineFP_EXTEND(N, DAG, Subtarget);
case ISD::FP_EXTEND: return combineFP_EXTEND(N, DAG, DCI, Subtarget);
case ISD::STRICT_FP_ROUND:
case ISD::FP_ROUND: return combineFP_ROUND(N, DAG, Subtarget);
case X86ISD::VBROADCAST_LOAD:
Expand Down
16 changes: 3 additions & 13 deletions llvm/lib/TargetParser/AArch64TargetParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,6 @@ StringRef AArch64::resolveCPUAlias(StringRef Name) {
return Name;
}

StringRef AArch64::resolveExtAlias(StringRef Name) {
for (const auto &A : ExtAliases)
if (A.AltName == Name)
return A.Name;
return Name;
}

StringRef AArch64::getArchExtFeature(StringRef ArchExt) {
bool IsNegated = ArchExt.starts_with("no");
StringRef ArchExtBase = IsNegated ? ArchExt.drop_front(2) : ArchExt;
Expand Down Expand Up @@ -120,13 +113,10 @@ const AArch64::ArchInfo *AArch64::parseArch(StringRef Arch) {
return {};
}

std::optional<AArch64::ExtensionInfo> AArch64::parseArchExtension(StringRef ArchExt) {
// Resolve aliases first.
ArchExt = resolveExtAlias(ArchExt);

// Then find the Extension name.
std::optional<AArch64::ExtensionInfo>
AArch64::parseArchExtension(StringRef ArchExt) {
for (const auto &A : Extensions) {
if (ArchExt == A.Name)
if (ArchExt == A.Name || ArchExt == A.Alias)
return A;
}
return {};
Expand Down
Loading