422 changes: 422 additions & 0 deletions flang/unittests/Runtime/AccessTest.cpp

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions flang/unittests/Runtime/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
add_flang_unittest(FlangRuntimeTests
AccessTest.cpp
Allocatable.cpp
ArrayConstructor.cpp
BufferTest.cpp
Expand Down
18 changes: 18 additions & 0 deletions libc/hdr/types/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,21 @@ add_proxy_header_library(
FULL_BUILD_DEPENDS
libc.include.llvm-libc-types.struct_timespec
)

add_proxy_header_library(
fenv_t
HDRS
fenv_t.h
FULL_BUILD_DEPENDS
libc.include.llvm-libc-types.fenv_t
libc.incude.fenv
)

add_proxy_header_library(
fexcept_t
HDRS
fexcept_t.h
FULL_BUILD_DEPENDS
libc.include.llvm-libc-types.fexcept_t
libc.incude.fenv
)
22 changes: 22 additions & 0 deletions libc/hdr/types/fenv_t.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//===-- Definition of macros from fenv_t.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
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_HDR_FENV_T_H
#define LLVM_LIBC_HDR_FENV_T_H

#ifdef LIBC_FULL_BUILD

#include "include/llvm-libc-types/fenv_t.h"

#else // Overlay mode

#include <fenv.h>

#endif // LLVM_LIBC_FULL_BUILD

#endif // LLVM_LIBC_HDR_FENV_T_H
22 changes: 22 additions & 0 deletions libc/hdr/types/fexcept_t.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//===-- Definition of macros from fexcept_t.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
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_HDR_FEXCEPT_T_H
#define LLVM_LIBC_HDR_FEXCEPT_T_H

#ifdef LIBC_FULL_BUILD

#include "include/llvm-libc-types/fexcept_t.h"

#else // Overlay mode

#include <fenv.h>

#endif // LLVM_LIBC_FULL_BUILD

#endif // LLVM_LIBC_HDR_FENV_T_H
2 changes: 1 addition & 1 deletion libc/src/__support/FPUtil/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ add_header_library(
HDRS
FEnvImpl.h
DEPENDS
libc.include.fenv
libc.hdr.types.fenv_t
libc.hdr.fenv_macros
libc.hdr.math_macros
libc.src.__support.macros.attributes
Expand Down
2 changes: 1 addition & 1 deletion libc/src/__support/FPUtil/aarch64/FEnvImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
#endif

#include <arm_acle.h>
#include <fenv.h>
#include <stdint.h>

#include "hdr/fenv_macros.h"
#include "hdr/types/fenv_t.h"
#include "src/__support/FPUtil/FPBits.h"

namespace LIBC_NAMESPACE {
Expand Down
2 changes: 1 addition & 1 deletion libc/src/__support/FPUtil/aarch64/fenv_darwin_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
#endif

#include <arm_acle.h>
#include <fenv.h>
#include <stdint.h>

#include "hdr/fenv_macros.h"
#include "hdr/types/fenv_t.h"
#include "src/__support/FPUtil/FPBits.h"

namespace LIBC_NAMESPACE {
Expand Down
2 changes: 1 addition & 1 deletion libc/src/__support/FPUtil/arm/FEnvImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_ARM_FENVIMPL_H

#include "hdr/fenv_macros.h"
#include "hdr/types/fenv_t.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/macros/attributes.h" // For LIBC_INLINE
#include <fenv.h>
#include <stdint.h>

namespace LIBC_NAMESPACE {
Expand Down
1 change: 1 addition & 0 deletions libc/src/__support/FPUtil/riscv/FEnvImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_RISCV_FENVIMPL_H

#include "hdr/fenv_macros.h"
#include "hdr/types/fenv_t.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/macros/attributes.h" // For LIBC_INLINE_ASM
#include "src/__support/macros/config.h" // For LIBC_INLINE
Expand Down
2 changes: 1 addition & 1 deletion libc/src/__support/FPUtil/x86_64/FEnvImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
#error "Invalid include"
#endif

#include <fenv.h>
#include <stdint.h>

#include "hdr/types/fenv_t.h"
#include "src/__support/macros/sanitizer.h"

namespace LIBC_NAMESPACE {
Expand Down
7 changes: 6 additions & 1 deletion libc/src/fenv/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ add_entrypoint_object(
HDRS
fegetround.h
DEPENDS
libc.include.fenv
libc.src.__support.FPUtil.fenv_impl
COMPILE_OPTIONS
-O2
Expand Down Expand Up @@ -71,6 +70,7 @@ add_entrypoint_object(
fegetenv.h
DEPENDS
libc.hdr.fenv_macros
libc.hdr.types.fenv_t
libc.src.__support.FPUtil.fenv_impl
COMPILE_OPTIONS
-O2
Expand All @@ -84,6 +84,7 @@ add_entrypoint_object(
fesetenv.h
DEPENDS
libc.hdr.fenv_macros
libc.hdr.types.fenv_t
libc.src.__support.FPUtil.fenv_impl
COMPILE_OPTIONS
-O2
Expand All @@ -97,6 +98,7 @@ add_entrypoint_object(
fegetexceptflag.h
DEPENDS
libc.hdr.fenv_macros
libc.hdr.types.fexcept_t
libc.src.__support.FPUtil.fenv_impl
COMPILE_OPTIONS
-O2
Expand All @@ -123,6 +125,7 @@ add_entrypoint_object(
fesetexceptflag.h
DEPENDS
libc.hdr.fenv_macros
libc.hdr.types.fexcept_t
libc.src.__support.FPUtil.fenv_impl
COMPILE_OPTIONS
-O2
Expand All @@ -136,6 +139,7 @@ add_entrypoint_object(
feholdexcept.h
DEPENDS
libc.hdr.fenv_macros
libc.hdr.types.fenv_t
libc.src.__support.FPUtil.fenv_impl
COMPILE_OPTIONS
-O2
Expand All @@ -149,6 +153,7 @@ add_entrypoint_object(
feupdateenv.h
DEPENDS
libc.hdr.fenv_macros
libc.hdr.types.fenv_t
libc.src.__support.FPUtil.fenv_impl
COMPILE_OPTIONS
-O2
Expand Down
2 changes: 1 addition & 1 deletion libc/src/fenv/fegetenv.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#ifndef LLVM_LIBC_SRC_FENV_FEGETENV_H
#define LLVM_LIBC_SRC_FENV_FEGETENV_H

#include <fenv.h>
#include "hdr/types/fenv_t.h"

namespace LIBC_NAMESPACE {

Expand Down
3 changes: 1 addition & 2 deletions libc/src/fenv/fegetexceptflag.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@
//===----------------------------------------------------------------------===//

#include "src/fenv/fegetexceptflag.h"
#include "hdr/types/fexcept_t.h"
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/common.h"

#include <fenv.h>

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(int, fegetexceptflag, (fexcept_t * flagp, int excepts)) {
Expand Down
2 changes: 1 addition & 1 deletion libc/src/fenv/feholdexcept.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
//===----------------------------------------------------------------------===//

#include "src/fenv/feholdexcept.h"
#include "hdr/types/fenv_t.h"
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/common.h"
#include <fenv.h>

namespace LIBC_NAMESPACE {

Expand Down
2 changes: 1 addition & 1 deletion libc/src/fenv/feholdexcept.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#ifndef LLVM_LIBC_SRC_FENV_FEHOLDEXCEPT_H
#define LLVM_LIBC_SRC_FENV_FEHOLDEXCEPT_H

#include <fenv.h>
#include "hdr/types/fenv_t.h"

namespace LIBC_NAMESPACE {

Expand Down
2 changes: 1 addition & 1 deletion libc/src/fenv/fesetenv.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#ifndef LLVM_LIBC_SRC_FENV_FESETENV_H
#define LLVM_LIBC_SRC_FENV_FESETENV_H

#include <fenv.h>
#include "hdr/types/fenv_t.h"

namespace LIBC_NAMESPACE {

Expand Down
2 changes: 1 addition & 1 deletion libc/src/fenv/fesetexceptflag.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
//===----------------------------------------------------------------------===//

#include "src/fenv/fesetexceptflag.h"
#include "hdr/types/fexcept_t.h"
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/common.h"
#include <fenv.h>

namespace LIBC_NAMESPACE {

Expand Down
2 changes: 1 addition & 1 deletion libc/src/fenv/feupdateenv.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#ifndef LLVM_LIBC_SRC_FENV_FEUPDATEENV_H
#define LLVM_LIBC_SRC_FENV_FEUPDATEENV_H

#include <fenv.h>
#include "hdr/types/fenv_t.h"

namespace LIBC_NAMESPACE {

Expand Down
1 change: 1 addition & 0 deletions libc/test/UnitTest/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ add_unittest_framework_library(
LibcTest
libc.src.__support.FPUtil.fp_bits
libc.src.__support.FPUtil.fenv_impl
libc.hdr.types.fenv_t
)

add_unittest_framework_library(
Expand Down
7 changes: 4 additions & 3 deletions libc/test/UnitTest/FPExceptMatcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@

#include "FPExceptMatcher.h"

#include <fenv.h>
#include "hdr/types/fenv_t.h"
#include "src/__support/FPUtil/FEnvImpl.h"
#include <memory>
#include <setjmp.h>
#include <signal.h>
Expand Down Expand Up @@ -36,12 +37,12 @@ FPExceptMatcher::FPExceptMatcher(FunctionCaller *func) {

caughtExcept = false;
fenv_t oldEnv;
fegetenv(&oldEnv);
fputil::get_env(&oldEnv);
if (sigsetjmp(jumpBuffer, 1) == 0)
funcUP->call();
// We restore the previous floating point environment after
// the call to the function which can potentially raise SIGFPE.
fesetenv(&oldEnv);
fputil::set_env(&oldEnv);
signal(SIGFPE, oldSIGFPEHandler);
exceptionRaised = caughtExcept;
}
Expand Down
3 changes: 1 addition & 2 deletions libc/test/src/fenv/exception_flags_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@
//
//===----------------------------------------------------------------------===//

#include "hdr/types/fexcept_t.h"
#include "src/fenv/fegetexceptflag.h"
#include "src/fenv/fesetexceptflag.h"

#include "src/__support/FPUtil/FEnvImpl.h"
#include "test/UnitTest/Test.h"

#include <fenv.h>

TEST(LlvmLibcFenvTest, GetExceptFlagAndSetExceptFlag) {
// We will disable all exceptions to prevent invocation of the exception
// handler.
Expand Down
3 changes: 1 addition & 2 deletions libc/test/src/fenv/feholdexcept_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,14 @@
//
//===----------------------------------------------------------------------===//

#include "hdr/types/fenv_t.h"
#include "src/fenv/feholdexcept.h"

#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/macros/properties/architectures.h"
#include "test/UnitTest/FPExceptMatcher.h"
#include "test/UnitTest/Test.h"

#include <fenv.h>

TEST(LlvmLibcFEnvTest, RaiseAndCrash) {
#if defined(LIBC_TARGET_ARCH_IS_ANY_ARM) || \
defined(LIBC_TARGET_ARCH_IS_ANY_RISCV)
Expand Down
2 changes: 1 addition & 1 deletion libc/test/src/fenv/feupdateenv_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
//
//===----------------------------------------------------------------------===//

#include "hdr/types/fenv_t.h"
#include "src/fenv/feupdateenv.h"

#include "src/__support/FPUtil/FEnvImpl.h"
#include "test/UnitTest/Test.h"

#include <fenv.h>
#include <signal.h>

TEST(LlvmLibcFEnvTest, UpdateEnvTest) {
Expand Down
3 changes: 1 addition & 2 deletions libc/test/src/fenv/getenv_and_setenv_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//
//===----------------------------------------------------------------------===//

#include "hdr/types/fenv_t.h"
#include "src/fenv/fegetenv.h"
#include "src/fenv/fegetround.h"
#include "src/fenv/fesetenv.h"
Expand All @@ -14,8 +15,6 @@
#include "src/__support/FPUtil/FEnvImpl.h"
#include "test/UnitTest/Test.h"

#include <fenv.h>

TEST(LlvmLibcFenvTest, GetEnvAndSetEnv) {
// We will disable all exceptions to prevent invocation of the exception
// handler.
Expand Down
2 changes: 2 additions & 0 deletions libcxx/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,7 @@ set(files
__numeric/transform_exclusive_scan.h
__numeric/transform_inclusive_scan.h
__numeric/transform_reduce.h
__pstl/cpu_algos/cpu_traits.h
__random/bernoulli_distribution.h
__random/binomial_distribution.h
__random/cauchy_distribution.h
Expand Down Expand Up @@ -859,6 +860,7 @@ set(files
__utility/in_place.h
__utility/integer_sequence.h
__utility/is_pointer_in_range.h
__utility/is_valid_range.h
__utility/move.h
__utility/no_destroy.h
__utility/pair.h
Expand Down
47 changes: 1 addition & 46 deletions libcxx/include/__algorithm/pstl_backends/cpu_backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,52 +9,6 @@
#ifndef _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKEND_H
#define _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKEND_H

#include <__config>

/*
// _Functor takes a subrange for [__first, __last) that should be executed in serial
template <class _RandomAccessIterator, class _Functor>
optional<__empty> __parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Functor __func);
template <class _Iterator, class _UnaryOp, class _Tp, class _BinaryOp, class _Reduction>
optional<_Tp>
__parallel_transform_reduce(_Iterator __first, _Iterator __last, _UnaryOp, _Tp __init, _BinaryOp, _Reduction);
// Cancel the execution of other jobs - they aren't needed anymore
void __cancel_execution();
template <class _RandomAccessIterator1,
class _RandomAccessIterator2,
class _RandomAccessIterator3,
class _Compare,
class _LeafMerge>
optional<void> __parallel_merge(
_RandomAccessIterator1 __first1,
_RandomAccessIterator1 __last1,
_RandomAccessIterator2 __first2,
_RandomAccessIterator2 __last2,
_RandomAccessIterator3 __outit,
_Compare __comp,
_LeafMerge __leaf_merge);
template <class _RandomAccessIterator, class _Comp, class _LeafSort>
void __parallel_stable_sort(_RandomAccessIterator __first,
_RandomAccessIterator __last,
_Comp __comp,
_LeafSort __leaf_sort);
TODO: Document the parallel backend
Exception handling
==================
CPU backends are expected to report errors (i.e. failure to allocate) by returning a disengaged `optional` from their
implementation. Exceptions shouldn't be used to report an internal failure-to-allocate, since all exceptions are turned
into a program termination at the front-end level. When a backend returns a disengaged `optional` to the frontend, the
frontend will turn that into a call to `std::__throw_bad_alloc();` to report the internal failure to the user.
*/

#include <__algorithm/pstl_backends/cpu_backends/any_of.h>
#include <__algorithm/pstl_backends/cpu_backends/backend.h>
#include <__algorithm/pstl_backends/cpu_backends/fill.h>
Expand All @@ -64,5 +18,6 @@ frontend will turn that into a call to `std::__throw_bad_alloc();` to report the
#include <__algorithm/pstl_backends/cpu_backends/stable_sort.h>
#include <__algorithm/pstl_backends/cpu_backends/transform.h>
#include <__algorithm/pstl_backends/cpu_backends/transform_reduce.h>
#include <__config>

#endif // _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKEND_H
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <__config>
#include <__functional/operations.h>
#include <__iterator/concepts.h>
#include <__pstl/cpu_algos/cpu_traits.h>
#include <__type_traits/is_execution_policy.h>
#include <__utility/move.h>
#include <__utility/pair.h>
Expand All @@ -30,13 +31,13 @@ _LIBCPP_PUSH_MACROS

_LIBCPP_BEGIN_NAMESPACE_STD

template <class _Index, class _Brick>
template <class _Backend, class _Index, class _Brick>
_LIBCPP_HIDE_FROM_ABI optional<bool> __parallel_or(_Index __first, _Index __last, _Brick __f) {
std::atomic<bool> __found(false);
auto __ret = __par_backend::__parallel_for(__first, __last, [__f, &__found](_Index __i, _Index __j) {
auto __ret = __pstl::__cpu_traits<_Backend>::__for_each(__first, __last, [__f, &__found](_Index __i, _Index __j) {
if (!__found.load(std::memory_order_relaxed) && __f(__i, __j)) {
__found.store(true, std::memory_order_relaxed);
__par_backend::__cancel_execution();
__pstl::__cpu_traits<_Backend>::__cancel_execution();
}
});
if (!__ret)
Expand Down Expand Up @@ -74,7 +75,7 @@ _LIBCPP_HIDE_FROM_ABI optional<bool>
__pstl_any_of(__cpu_backend_tag, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) {
if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
__has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
return std::__parallel_or(
return std::__parallel_or<__cpu_backend_tag>(
__first, __last, [&__pred](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
auto __res = std::__pstl_any_of<__remove_parallel_policy_t<_ExecutionPolicy>>(
__cpu_backend_tag{}, __brick_first, __brick_last, __pred);
Expand Down
14 changes: 9 additions & 5 deletions libcxx/include/__algorithm/pstl_backends/cpu_backends/backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,20 @@
# pragma GCC system_header
#endif

#if _LIBCPP_STD_VER >= 17
#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17

_LIBCPP_BEGIN_NAMESPACE_STD

struct __cpu_backend_tag {};

inline constexpr size_t __lane_size = 64;
# if defined(_LIBCPP_PSTL_CPU_BACKEND_SERIAL)
using __cpu_backend_tag = __pstl::__serial_backend_tag;
# elif defined(_LIBCPP_PSTL_CPU_BACKEND_THREAD)
using __cpu_backend_tag = __pstl::__std_thread_backend_tag;
# elif defined(_LIBCPP_PSTL_CPU_BACKEND_LIBDISPATCH)
using __cpu_backend_tag = __pstl::__libdispatch_backend_tag;
# endif

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP_STD_VER >= 17
#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && && _LIBCPP_STD_VER >= 17

#endif // _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKEND_BACKEND_H
3 changes: 2 additions & 1 deletion libcxx/include/__algorithm/pstl_backends/cpu_backends/fill.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <__algorithm/pstl_backends/cpu_backends/backend.h>
#include <__config>
#include <__iterator/concepts.h>
#include <__pstl/cpu_algos/cpu_traits.h>
#include <__type_traits/is_execution_policy.h>
#include <__utility/empty.h>
#include <optional>
Expand All @@ -39,7 +40,7 @@ _LIBCPP_HIDE_FROM_ABI optional<__empty>
__pstl_fill(__cpu_backend_tag, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) {
if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
__has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
return __par_backend::__parallel_for(
return __pstl::__cpu_traits<__cpu_backend_tag>::__for_each(
__first, __last, [&__value](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
[[maybe_unused]] auto __res = std::__pstl_fill<__remove_parallel_policy_t<_ExecutionPolicy>>(
__cpu_backend_tag{}, __brick_first, __brick_last, __value);
Expand Down
22 changes: 12 additions & 10 deletions libcxx/include/__algorithm/pstl_backends/cpu_backends/find_if.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <__functional/operations.h>
#include <__iterator/concepts.h>
#include <__iterator/iterator_traits.h>
#include <__pstl/cpu_algos/cpu_traits.h>
#include <__type_traits/is_execution_policy.h>
#include <__utility/move.h>
#include <__utility/pair.h>
Expand All @@ -33,16 +34,16 @@ _LIBCPP_PUSH_MACROS

_LIBCPP_BEGIN_NAMESPACE_STD

template <class _Index, class _Brick, class _Compare>
template <class _Backend, class _Index, class _Brick, class _Compare>
_LIBCPP_HIDE_FROM_ABI optional<_Index>
__parallel_find(_Index __first, _Index __last, _Brick __f, _Compare __comp, bool __b_first) {
typedef typename std::iterator_traits<_Index>::difference_type _DifferenceType;
const _DifferenceType __n = __last - __first;
_DifferenceType __initial_dist = __b_first ? __n : -1;
std::atomic<_DifferenceType> __extremum(__initial_dist);
// TODO: find out what is better here: parallel_for or parallel_reduce
auto __res =
__par_backend::__parallel_for(__first, __last, [__comp, __f, __first, &__extremum](_Index __i, _Index __j) {
auto __res = __pstl::__cpu_traits<_Backend>::__for_each(
__first, __last, [__comp, __f, __first, &__extremum](_Index __i, _Index __j) {
// See "Reducing Contention Through Priority Updates", PPoPP '13, for discussion of
// why using a shared variable scales fairly well in this situation.
if (__comp(__i - __first, __extremum)) {
Expand All @@ -61,12 +62,12 @@ __parallel_find(_Index __first, _Index __last, _Brick __f, _Compare __comp, bool
return __extremum.load() != __initial_dist ? __first + __extremum.load() : __last;
}

template <class _Index, class _DifferenceType, class _Compare>
template <class _Backend, class _Index, class _DifferenceType, class _Compare>
_LIBCPP_HIDE_FROM_ABI _Index
__simd_first(_Index __first, _DifferenceType __begin, _DifferenceType __end, _Compare __comp) noexcept {
// Experiments show good block sizes like this
const _DifferenceType __block_size = 8;
alignas(__lane_size) _DifferenceType __lane[__block_size] = {0};
const _DifferenceType __block_size = 8;
alignas(__pstl::__cpu_traits<_Backend>::__lane_size) _DifferenceType __lane[__block_size] = {0};
while (__end - __begin >= __block_size) {
_DifferenceType __found = 0;
_PSTL_PRAGMA_SIMD_REDUCTION(| : __found) for (_DifferenceType __i = __begin; __i < __begin + __block_size; ++__i) {
Expand Down Expand Up @@ -102,7 +103,7 @@ _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator>
__pstl_find_if(__cpu_backend_tag, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) {
if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
__has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
return std::__parallel_find(
return std::__parallel_find<__cpu_backend_tag>(
__first,
__last,
[&__pred](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
Expand All @@ -116,9 +117,10 @@ __pstl_find_if(__cpu_backend_tag, _ForwardIterator __first, _ForwardIterator __l
} else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> &&
__has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
using __diff_t = __iter_diff_t<_ForwardIterator>;
return std::__simd_first(__first, __diff_t(0), __last - __first, [&__pred](_ForwardIterator __iter, __diff_t __i) {
return __pred(__iter[__i]);
});
return std::__simd_first<__cpu_backend_tag>(
__first, __diff_t(0), __last - __first, [&__pred](_ForwardIterator __iter, __diff_t __i) {
return __pred(__iter[__i]);
});
} else {
return std::find_if(__first, __last, __pred);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <__algorithm/pstl_backends/cpu_backends/backend.h>
#include <__config>
#include <__iterator/concepts.h>
#include <__pstl/cpu_algos/cpu_traits.h>
#include <__type_traits/is_execution_policy.h>
#include <__utility/empty.h>
#include <optional>
Expand All @@ -39,7 +40,7 @@ _LIBCPP_HIDE_FROM_ABI optional<__empty>
__pstl_for_each(__cpu_backend_tag, _ForwardIterator __first, _ForwardIterator __last, _Functor __func) {
if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
__has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
return std::__par_backend::__parallel_for(
return __pstl::__cpu_traits<__cpu_backend_tag>::__for_each(
__first, __last, [__func](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
[[maybe_unused]] auto __res = std::__pstl_for_each<__remove_parallel_policy_t<_ExecutionPolicy>>(
__cpu_backend_tag{}, __brick_first, __brick_last, __func);
Expand Down
457 changes: 231 additions & 226 deletions libcxx/include/__algorithm/pstl_backends/cpu_backends/libdispatch.h

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <__algorithm/pstl_backends/cpu_backends/backend.h>
#include <__config>
#include <__iterator/concepts.h>
#include <__pstl/cpu_algos/cpu_traits.h>
#include <__type_traits/is_execution_policy.h>
#include <__utility/move.h>
#include <optional>
Expand Down Expand Up @@ -45,7 +46,7 @@ _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator> __pstl_merge(
__has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
__has_random_access_iterator_category_or_concept<_ForwardIterator2>::value &&
__has_random_access_iterator_category_or_concept<_ForwardOutIterator>::value) {
auto __res = __par_backend::__parallel_merge(
auto __res = __pstl::__cpu_traits<__cpu_backend_tag>::__merge(
__first1,
__last1,
__first2,
Expand Down
98 changes: 50 additions & 48 deletions libcxx/include/__algorithm/pstl_backends/cpu_backends/serial.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#define _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_SERIAL_H

#include <__config>
#include <__pstl/cpu_algos/cpu_traits.h>
#include <__utility/empty.h>
#include <__utility/move.h>
#include <cstddef>
Expand All @@ -26,54 +27,55 @@ _LIBCPP_PUSH_MACROS
# include <__undef_macros>

_LIBCPP_BEGIN_NAMESPACE_STD

namespace __par_backend {
inline namespace __serial_cpu_backend {

template <class _RandomAccessIterator, class _Fp>
_LIBCPP_HIDE_FROM_ABI optional<__empty>
__parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Fp __f) {
__f(__first, __last);
return __empty{};
}

template <class _Index, class _UnaryOp, class _Tp, class _BinaryOp, class _Reduce>
_LIBCPP_HIDE_FROM_ABI optional<_Tp>
__parallel_transform_reduce(_Index __first, _Index __last, _UnaryOp, _Tp __init, _BinaryOp, _Reduce __reduce) {
return __reduce(std::move(__first), std::move(__last), std::move(__init));
}

template <class _RandomAccessIterator, class _Compare, class _LeafSort>
_LIBCPP_HIDE_FROM_ABI optional<__empty> __parallel_stable_sort(
_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp, _LeafSort __leaf_sort) {
__leaf_sort(__first, __last, __comp);
return __empty{};
}

_LIBCPP_HIDE_FROM_ABI inline void __cancel_execution() {}

template <class _RandomAccessIterator1,
class _RandomAccessIterator2,
class _RandomAccessIterator3,
class _Compare,
class _LeafMerge>
_LIBCPP_HIDE_FROM_ABI optional<__empty> __parallel_merge(
_RandomAccessIterator1 __first1,
_RandomAccessIterator1 __last1,
_RandomAccessIterator2 __first2,
_RandomAccessIterator2 __last2,
_RandomAccessIterator3 __outit,
_Compare __comp,
_LeafMerge __leaf_merge) {
__leaf_merge(__first1, __last1, __first2, __last2, __outit, __comp);
return __empty{};
}

// TODO: Complete this list

} // namespace __serial_cpu_backend
} // namespace __par_backend

namespace __pstl {

struct __serial_backend_tag {};

template <>
struct __cpu_traits<__serial_backend_tag> {
template <class _RandomAccessIterator, class _Fp>
_LIBCPP_HIDE_FROM_ABI static optional<__empty>
__for_each(_RandomAccessIterator __first, _RandomAccessIterator __last, _Fp __f) {
__f(__first, __last);
return __empty{};
}

template <class _Index, class _UnaryOp, class _Tp, class _BinaryOp, class _Reduce>
_LIBCPP_HIDE_FROM_ABI static optional<_Tp>
__transform_reduce(_Index __first, _Index __last, _UnaryOp, _Tp __init, _BinaryOp, _Reduce __reduce) {
return __reduce(std::move(__first), std::move(__last), std::move(__init));
}

template <class _RandomAccessIterator, class _Compare, class _LeafSort>
_LIBCPP_HIDE_FROM_ABI static optional<__empty>
__stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp, _LeafSort __leaf_sort) {
__leaf_sort(__first, __last, __comp);
return __empty{};
}

_LIBCPP_HIDE_FROM_ABI static void __cancel_execution() {}

template <class _RandomAccessIterator1,
class _RandomAccessIterator2,
class _RandomAccessIterator3,
class _Compare,
class _LeafMerge>
_LIBCPP_HIDE_FROM_ABI static optional<__empty>
__merge(_RandomAccessIterator1 __first1,
_RandomAccessIterator1 __last1,
_RandomAccessIterator2 __first2,
_RandomAccessIterator2 __last2,
_RandomAccessIterator3 __outit,
_Compare __comp,
_LeafMerge __leaf_merge) {
__leaf_merge(__first1, __last1, __first2, __last2, __outit, __comp);
return __empty{};
}

static constexpr size_t __lane_size = 64;
};

} // namespace __pstl
_LIBCPP_END_NAMESPACE_STD

_LIBCPP_POP_MACROS
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <__algorithm/pstl_backends/cpu_backends/backend.h>
#include <__algorithm/stable_sort.h>
#include <__config>
#include <__pstl/cpu_algos/cpu_traits.h>
#include <__type_traits/is_execution_policy.h>
#include <__utility/empty.h>
#include <optional>
Expand All @@ -28,7 +29,7 @@ template <class _ExecutionPolicy, class _RandomAccessIterator, class _Comp>
_LIBCPP_HIDE_FROM_ABI optional<__empty>
__pstl_stable_sort(__cpu_backend_tag, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) {
if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy>) {
return __par_backend::__parallel_stable_sort(
return __pstl::__cpu_traits<__cpu_backend_tag>::__stable_sort(
__first, __last, __comp, [](_RandomAccessIterator __g_first, _RandomAccessIterator __g_last, _Comp __g_comp) {
std::stable_sort(__g_first, __g_last, __g_comp);
});
Expand Down
96 changes: 50 additions & 46 deletions libcxx/include/__algorithm/pstl_backends/cpu_backends/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include <__assert>
#include <__config>
#include <__pstl/cpu_algos/cpu_traits.h>
#include <__utility/empty.h>
#include <__utility/move.h>
#include <cstddef>
Expand All @@ -29,52 +30,55 @@ _LIBCPP_PUSH_MACROS
// by a proper implementation once the PSTL implementation is somewhat stable.

_LIBCPP_BEGIN_NAMESPACE_STD

namespace __par_backend {
inline namespace __thread_cpu_backend {

template <class _RandomAccessIterator, class _Fp>
_LIBCPP_HIDE_FROM_ABI optional<__empty>
__parallel_for(_RandomAccessIterator __first, _RandomAccessIterator __last, _Fp __f) {
__f(__first, __last);
return __empty{};
}

template <class _Index, class _UnaryOp, class _Tp, class _BinaryOp, class _Reduce>
_LIBCPP_HIDE_FROM_ABI optional<_Tp>
__parallel_transform_reduce(_Index __first, _Index __last, _UnaryOp, _Tp __init, _BinaryOp, _Reduce __reduce) {
return __reduce(std::move(__first), std::move(__last), std::move(__init));
}

template <class _RandomAccessIterator, class _Compare, class _LeafSort>
_LIBCPP_HIDE_FROM_ABI optional<__empty> __parallel_stable_sort(
_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp, _LeafSort __leaf_sort) {
__leaf_sort(__first, __last, __comp);
return __empty{};
}

_LIBCPP_HIDE_FROM_ABI inline void __cancel_execution() {}

template <class _RandomAccessIterator1,
class _RandomAccessIterator2,
class _RandomAccessIterator3,
class _Compare,
class _LeafMerge>
_LIBCPP_HIDE_FROM_ABI optional<__empty> __parallel_merge(
_RandomAccessIterator1 __first1,
_RandomAccessIterator1 __last1,
_RandomAccessIterator2 __first2,
_RandomAccessIterator2 __last2,
_RandomAccessIterator3 __outit,
_Compare __comp,
_LeafMerge __leaf_merge) {
__leaf_merge(__first1, __last1, __first2, __last2, __outit, __comp);
return __empty{};
}

} // namespace __thread_cpu_backend
} // namespace __par_backend

namespace __pstl {

struct __std_thread_backend_tag {};

template <>
struct __cpu_traits<__std_thread_backend_tag> {
template <class _RandomAccessIterator, class _Fp>
_LIBCPP_HIDE_FROM_ABI static optional<__empty>
__for_each(_RandomAccessIterator __first, _RandomAccessIterator __last, _Fp __f) {
__f(__first, __last);
return __empty{};
}

template <class _Index, class _UnaryOp, class _Tp, class _BinaryOp, class _Reduce>
_LIBCPP_HIDE_FROM_ABI static optional<_Tp>
__transform_reduce(_Index __first, _Index __last, _UnaryOp, _Tp __init, _BinaryOp, _Reduce __reduce) {
return __reduce(std::move(__first), std::move(__last), std::move(__init));
}

template <class _RandomAccessIterator, class _Compare, class _LeafSort>
_LIBCPP_HIDE_FROM_ABI static optional<__empty>
__stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp, _LeafSort __leaf_sort) {
__leaf_sort(__first, __last, __comp);
return __empty{};
}

_LIBCPP_HIDE_FROM_ABI static void __cancel_execution() {}

template <class _RandomAccessIterator1,
class _RandomAccessIterator2,
class _RandomAccessIterator3,
class _Compare,
class _LeafMerge>
_LIBCPP_HIDE_FROM_ABI static optional<__empty>
__merge(_RandomAccessIterator1 __first1,
_RandomAccessIterator1 __last1,
_RandomAccessIterator2 __first2,
_RandomAccessIterator2 __last2,
_RandomAccessIterator3 __outit,
_Compare __comp,
_LeafMerge __leaf_merge) {
__leaf_merge(__first1, __last1, __first2, __last2, __outit, __comp);
return __empty{};
}

static constexpr size_t __lane_size = 64;
};

} // namespace __pstl
_LIBCPP_END_NAMESPACE_STD

#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && && _LIBCPP_STD_VER >= 17
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <__config>
#include <__iterator/concepts.h>
#include <__iterator/iterator_traits.h>
#include <__pstl/cpu_algos/cpu_traits.h>
#include <__type_traits/enable_if.h>
#include <__type_traits/is_execution_policy.h>
#include <__type_traits/remove_cvref.h>
Expand Down Expand Up @@ -49,7 +50,7 @@ _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator> __pstl_transform(
if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
__has_random_access_iterator_category_or_concept<_ForwardIterator>::value &&
__has_random_access_iterator_category_or_concept<_ForwardOutIterator>::value) {
std::__par_backend::__parallel_for(
__pstl::__cpu_traits<__cpu_backend_tag>::__for_each(
__first, __last, [__op, __first, __result](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
auto __res = std::__pstl_transform<__remove_parallel_policy_t<_ExecutionPolicy>>(
__cpu_backend_tag{}, __brick_first, __brick_last, __result + (__brick_first - __first), __op);
Expand Down Expand Up @@ -97,7 +98,7 @@ _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator> __pstl_transform(
__has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
__has_random_access_iterator_category_or_concept<_ForwardIterator2>::value &&
__has_random_access_iterator_category_or_concept<_ForwardOutIterator>::value) {
auto __res = std::__par_backend::__parallel_for(
auto __res = __pstl::__cpu_traits<__cpu_backend_tag>::__for_each(
__first1,
__last1,
[__op, __first1, __first2, __result](_ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <__iterator/concepts.h>
#include <__iterator/iterator_traits.h>
#include <__numeric/transform_reduce.h>
#include <__pstl/cpu_algos/cpu_traits.h>
#include <__type_traits/desugars_to.h>
#include <__type_traits/is_arithmetic.h>
#include <__type_traits/is_execution_policy.h>
Expand All @@ -32,7 +33,8 @@ _LIBCPP_PUSH_MACROS

_LIBCPP_BEGIN_NAMESPACE_STD

template <typename _DifferenceType,
template <typename _Backend,
typename _DifferenceType,
typename _Tp,
typename _BinaryOperation,
typename _UnaryOperation,
Expand All @@ -48,7 +50,8 @@ __simd_transform_reduce(_DifferenceType __n, _Tp __init, _BinaryOperation, _Unar
return __init;
}

template <typename _Size,
template <typename _Backend,
typename _Size,
typename _Tp,
typename _BinaryOperation,
typename _UnaryOperation,
Expand All @@ -58,7 +61,8 @@ template <typename _Size,
int> = 0>
_LIBCPP_HIDE_FROM_ABI _Tp
__simd_transform_reduce(_Size __n, _Tp __init, _BinaryOperation __binary_op, _UnaryOperation __f) noexcept {
const _Size __block_size = __lane_size / sizeof(_Tp);
constexpr size_t __lane_size = __pstl::__cpu_traits<_Backend>::__lane_size;
const _Size __block_size = __lane_size / sizeof(_Tp);
if (__n > 2 * __block_size && __block_size > 1) {
alignas(__lane_size) char __lane_buffer[__lane_size];
_Tp* __lane = reinterpret_cast<_Tp*>(__lane_buffer);
Expand Down Expand Up @@ -116,7 +120,7 @@ _LIBCPP_HIDE_FROM_ABI optional<_Tp> __pstl_transform_reduce(
if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
__has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
__has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
return __par_backend::__parallel_transform_reduce(
return __pstl::__cpu_traits<__cpu_backend_tag>::__transform_reduce(
__first1,
std::move(__last1),
[__first1, __first2, __transform](_ForwardIterator1 __iter) {
Expand All @@ -138,7 +142,7 @@ _LIBCPP_HIDE_FROM_ABI optional<_Tp> __pstl_transform_reduce(
} else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> &&
__has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
__has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
return std::__simd_transform_reduce(
return std::__simd_transform_reduce<__cpu_backend_tag>(
__last1 - __first1, std::move(__init), std::move(__reduce), [&](__iter_diff_t<_ForwardIterator1> __i) {
return __transform(__first1[__i], __first2[__i]);
});
Expand All @@ -163,7 +167,7 @@ _LIBCPP_HIDE_FROM_ABI optional<_Tp> __pstl_transform_reduce(
_UnaryOperation __transform) {
if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
__has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
return __par_backend::__parallel_transform_reduce(
return __pstl::__cpu_traits<__cpu_backend_tag>::__transform_reduce(
std::move(__first),
std::move(__last),
[__transform](_ForwardIterator __iter) { return __transform(*__iter); },
Expand All @@ -182,7 +186,7 @@ _LIBCPP_HIDE_FROM_ABI optional<_Tp> __pstl_transform_reduce(
});
} else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> &&
__has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
return std::__simd_transform_reduce(
return std::__simd_transform_reduce<__cpu_backend_tag>(
__last - __first,
std::move(__init),
std::move(__reduce),
Expand Down
86 changes: 86 additions & 0 deletions libcxx/include/__pstl/cpu_algos/cpu_traits.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
//===----------------------------------------------------------------------===//
//
// 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 _LIBCPP___PSTL_CPU_ALGOS_CPU_TRAITS_H
#define _LIBCPP___PSTL_CPU_ALGOS_CPU_TRAITS_H

#include <__config>
#include <cstddef>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

_LIBCPP_PUSH_MACROS
#include <__undef_macros>

_LIBCPP_BEGIN_NAMESPACE_STD
namespace __pstl {

// __cpu_traits
//
// This traits class encapsulates the basis operations for a CPU-based implementation of the PSTL.
// All the operations in the PSTL can be implemented from these basis operations, so a pure CPU backend
// only needs to customize these traits in order to get an implementation of the whole PSTL.
//
// Basis operations
// ================
//
// template <class _RandomAccessIterator, class _Functor>
// optional<__empty> __for_each(_RandomAccessIterator __first, _RandomAccessIterator __last, _Functor __func);
// - __func must take a subrange of [__first, __last) that should be executed in serial
//
// template <class _Iterator, class _UnaryOp, class _Tp, class _BinaryOp, class _Reduction>
// optional<_Tp> __transform_reduce(_Iterator __first, _Iterator __last, _UnaryOp, _Tp __init, _BinaryOp, _Reduction);
//
// template <class _RandomAccessIterator1,
// class _RandomAccessIterator2,
// class _RandomAccessIterator3,
// class _Compare,
// class _LeafMerge>
// optional<_RandomAccessIterator3> __merge(_RandomAccessIterator1 __first1,
// _RandomAccessIterator1 __last1,
// _RandomAccessIterator2 __first2,
// _RandomAccessIterator2 __last2,
// _RandomAccessIterator3 __outit,
// _Compare __comp,
// _LeafMerge __leaf_merge);
//
// template <class _RandomAccessIterator, class _Comp, class _LeafSort>
// optional<__empty> __stable_sort(_RandomAccessIterator __first,
// _RandomAccessIterator __last,
// _Comp __comp,
// _LeafSort __leaf_sort);
//
// void __cancel_execution();
// Cancel the execution of other jobs - they aren't needed anymore. This is not a binding request,
// some backends may not actually be able to cancel jobs.
//
// constexpr size_t __lane_size;
// Size of SIMD lanes.
// TODO: Merge this with __native_vector_size from __algorithm/simd_utils.h
//
//
// Exception handling
// ==================
//
// CPU backends are expected to report errors (i.e. failure to allocate) by returning a disengaged `optional` from their
// implementation. Exceptions shouldn't be used to report an internal failure-to-allocate, since all exceptions are
// turned into a program termination at the front-end level. When a backend returns a disengaged `optional` to the
// frontend, the frontend will turn that into a call to `std::__throw_bad_alloc();` to report the internal failure to
// the user.

template <class _Backend>
struct __cpu_traits;

} // namespace __pstl
_LIBCPP_END_NAMESPACE_STD

_LIBCPP_POP_MACROS

#endif // _LIBCPP___PSTL_CPU_ALGOS_CPU_TRAITS_H
6 changes: 3 additions & 3 deletions libcxx/include/__utility/is_pointer_in_range.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <__type_traits/is_constant_evaluated.h>
#include <__type_traits/void_t.h>
#include <__utility/declval.h>
#include <__utility/is_valid_range.h>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
Expand All @@ -34,16 +35,15 @@ struct __is_less_than_comparable<_Tp, _Up, __void_t<decltype(std::declval<_Tp>()
template <class _Tp, class _Up, __enable_if_t<__is_less_than_comparable<const _Tp*, const _Up*>::value, int> = 0>
_LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_SANITIZE("address") bool __is_pointer_in_range(
const _Tp* __begin, const _Tp* __end, const _Up* __ptr) {
if (__libcpp_is_constant_evaluated()) {
_LIBCPP_ASSERT_VALID_INPUT_RANGE(__builtin_constant_p(__begin <= __end), "__begin and __end do not form a range");
_LIBCPP_ASSERT_VALID_INPUT_RANGE(std::__is_valid_range(__begin, __end), "[__begin, __end) is not a valid range");

if (__libcpp_is_constant_evaluated()) {
// If this is not a constant during constant evaluation we know that __ptr is not part of the allocation where
// [__begin, __end) is.
if (!__builtin_constant_p(__begin <= __ptr && __ptr < __end))
return false;
}

// Checking this for unrelated pointers is technically UB, but no compiler optimizes based on it (currently).
return !__less<>()(__ptr, __begin) && __less<>()(__ptr, __end);
}

Expand Down
37 changes: 37 additions & 0 deletions libcxx/include/__utility/is_valid_range.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//===----------------------------------------------------------------------===//
//
// 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 _LIBCPP___UTILITY_IS_VALID_RANGE_H
#define _LIBCPP___UTILITY_IS_VALID_RANGE_H

#include <__algorithm/comp.h>
#include <__config>
#include <__type_traits/is_constant_evaluated.h>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

_LIBCPP_BEGIN_NAMESPACE_STD

template <class _Tp>
_LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_SANITIZE("address") bool
__is_valid_range(const _Tp* __first, const _Tp* __last) {
if (__libcpp_is_constant_evaluated()) {
// If this is not a constant during constant evaluation, that is because __first and __last are not
// part of the same allocation. If they are part of the same allocation, we must still make sure they
// are ordered properly.
return __builtin_constant_p(__first <= __last) && __first <= __last;
}

return !__less<>()(__last, __first);
}

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP___UTILITY_IS_VALID_RANGE_H
1 change: 1 addition & 0 deletions libcxx/include/libcxx.imp
Original file line number Diff line number Diff line change
Expand Up @@ -853,6 +853,7 @@
{ include: [ "<__utility/in_place.h>", "private", "<utility>", "public" ] },
{ include: [ "<__utility/integer_sequence.h>", "private", "<utility>", "public" ] },
{ include: [ "<__utility/is_pointer_in_range.h>", "private", "<utility>", "public" ] },
{ include: [ "<__utility/is_valid_range.h>", "private", "<utility>", "public" ] },
{ include: [ "<__utility/move.h>", "private", "<utility>", "public" ] },
{ include: [ "<__utility/no_destroy.h>", "private", "<utility>", "public" ] },
{ include: [ "<__utility/pair.h>", "private", "<utility>", "public" ] },
Expand Down
3 changes: 3 additions & 0 deletions libcxx/include/module.modulemap
Original file line number Diff line number Diff line change
Expand Up @@ -1613,6 +1613,8 @@ module std_private_numeric_transform_exclusive_scan [system] { header "__numeric
module std_private_numeric_transform_inclusive_scan [system] { header "__numeric/transform_inclusive_scan.h" }
module std_private_numeric_transform_reduce [system] { header "__numeric/transform_reduce.h" }

module std_private_pstl_cpu_algos_cpu_traits [system] { header "__pstl/cpu_algos/cpu_traits.h" }

module std_private_queue_fwd [system] { header "__fwd/queue.h" }

module std_private_random_bernoulli_distribution [system] { header "__random/bernoulli_distribution.h" }
Expand Down Expand Up @@ -2073,6 +2075,7 @@ module std_private_utility_forward_like [system] { header "__utility/f
module std_private_utility_in_place [system] { header "__utility/in_place.h" }
module std_private_utility_integer_sequence [system] { header "__utility/integer_sequence.h" }
module std_private_utility_is_pointer_in_range [system] { header "__utility/is_pointer_in_range.h" }
module std_private_utility_is_valid_range [system] { header "__utility/is_valid_range.h" }
module std_private_utility_move [system] {
header "__utility/move.h"
export std_private_type_traits_is_copy_constructible
Expand Down
7 changes: 2 additions & 5 deletions libcxx/src/pstl/libdispatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
#include <dispatch/dispatch.h>

_LIBCPP_BEGIN_NAMESPACE_STD

namespace __par_backend::inline __libdispatch {
namespace __pstl::__libdispatch {

void __dispatch_apply(size_t chunk_count, void* context, void (*func)(void* context, size_t chunk)) noexcept {
::dispatch_apply_f(chunk_count, DISPATCH_APPLY_AUTO, context, func);
Expand All @@ -29,7 +28,5 @@ __chunk_partitions __partition_chunks(ptrdiff_t element_count) noexcept {
return partitions;
}

// NOLINTNEXTLINE(llvm-namespace-comment) // This is https://llvm.org/PR56804
} // namespace __par_backend::inline __libdispatch

} // namespace __pstl::__libdispatch
_LIBCPP_END_NAMESPACE_STD
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,21 @@

int main(int, char**) {
{
auto chunks = std::__par_backend::__libdispatch::__partition_chunks(0);
auto chunks = std::__pstl::__libdispatch::__partition_chunks(0);
assert(chunks.__chunk_count_ == 1);
assert(chunks.__first_chunk_size_ == 0);
assert(chunks.__chunk_size_ == 0);
}

{
auto chunks = std::__par_backend::__libdispatch::__partition_chunks(1);
auto chunks = std::__pstl::__libdispatch::__partition_chunks(1);
assert(chunks.__chunk_count_ == 1);
assert(chunks.__first_chunk_size_ == 1);
assert(chunks.__chunk_size_ == 1);
}

for (std::ptrdiff_t i = 2; i != 2ll << 20; ++i) {
auto chunks = std::__par_backend::__libdispatch::__partition_chunks(i);
auto chunks = std::__pstl::__libdispatch::__partition_chunks(i);
assert(chunks.__chunk_count_ >= 1);
assert(chunks.__chunk_count_ <= i);
assert((chunks.__chunk_count_ - 1) * chunks.__chunk_size_ + chunks.__first_chunk_size_ == i);
Expand Down
68 changes: 68 additions & 0 deletions libcxx/test/libcxx/utilities/is_valid_range.pass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//===----------------------------------------------------------------------===//
//
// 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 <__utility/is_valid_range.h>
#include <cassert>

#include "test_macros.h"

template <class T, class TQualified>
TEST_CONSTEXPR_CXX14 void check_type() {
{
// We need to ensure that the addresses of i and j are ordered as &i < &j for
// the test below to work portably, so we define them in a struct.
struct {
T i = 0;
T j = 0;
} storage;
assert(std::__is_valid_range(static_cast<TQualified*>(&storage.i), static_cast<TQualified*>(&storage.i)));
assert(std::__is_valid_range(static_cast<TQualified*>(&storage.i), static_cast<TQualified*>(&storage.i + 1)));

assert(!std::__is_valid_range(static_cast<TQualified*>(&storage.j), static_cast<TQualified*>(&storage.i)));
assert(!std::__is_valid_range(static_cast<TQualified*>(&storage.i + 1), static_cast<TQualified*>(&storage.i)));

// We detect this as being a valid range even though it is not really valid.
assert(std::__is_valid_range(static_cast<TQualified*>(&storage.i), static_cast<TQualified*>(&storage.j)));
}

{
T arr[3] = {1, 2, 3};
assert(std::__is_valid_range(static_cast<TQualified*>(&arr[0]), static_cast<TQualified*>(&arr[0])));
assert(std::__is_valid_range(static_cast<TQualified*>(&arr[0]), static_cast<TQualified*>(&arr[1])));
assert(std::__is_valid_range(static_cast<TQualified*>(&arr[0]), static_cast<TQualified*>(&arr[2])));

assert(!std::__is_valid_range(static_cast<TQualified*>(&arr[1]), static_cast<TQualified*>(&arr[0])));
assert(!std::__is_valid_range(static_cast<TQualified*>(&arr[2]), static_cast<TQualified*>(&arr[0])));
}

#if TEST_STD_VER >= 20
{
T* arr = new int[4]{1, 2, 3, 4};
assert(std::__is_valid_range(static_cast<TQualified*>(arr), static_cast<TQualified*>(arr + 4)));
delete[] arr;
}
#endif
}

TEST_CONSTEXPR_CXX14 bool test() {
check_type<int, int>();
check_type<int, int const>();
check_type<int, int volatile>();
check_type<int, int const volatile>();

return true;
}

int main(int, char**) {
test();
#if TEST_STD_VER >= 14
static_assert(test(), "");
#endif

return 0;
}
10 changes: 7 additions & 3 deletions libcxx/utils/ci/run-buildbot
Original file line number Diff line number Diff line change
Expand Up @@ -368,18 +368,22 @@ bootstrapping-build)
-DCMAKE_CXX_COMPILER_LAUNCHER="ccache" \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX="${INSTALL_DIR}" \
-DLLVM_ENABLE_PROJECTS="clang" \
-DLLVM_ENABLE_PROJECTS="clang;lldb" \
-DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind" \
-DLLVM_RUNTIME_TARGETS="$(${CXX} --print-target-triple)" \
-DLLVM_HOST_TRIPLE="$(${CXX} --print-target-triple)" \
-DLLVM_TARGETS_TO_BUILD="host" \
-DRUNTIMES_BUILD_ALLOW_DARWIN=ON \
-DLLVM_ENABLE_ASSERTIONS=ON \
-DLLVM_LIT_ARGS="-sv --xunit-xml-output test-results.xml --timeout=1500 --time-tests"

echo "+++ Running the libc++ and libc++abi tests"
echo "+++ Running the LLDB libc++ data formatter tests"
${NINJA} -vC "${BUILD_DIR}" check-lldb-api-functionalities-data-formatter-data-formatter-stl-libcxx

echo "--- Running the libc++ and libc++abi tests"
${NINJA} -vC "${BUILD_DIR}" check-runtimes

echo "--- Installing libc++ and libc++abi to a fake location"
echo "+++ Installing libc++ and libc++abi to a fake location"
${NINJA} -vC "${BUILD_DIR}" install-runtimes

ccache -s
Expand Down
1 change: 1 addition & 0 deletions libcxx/utils/generate_iwyu_mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ def IWYU_mapping(header: str) -> typing.Optional[typing.List[str]]:
ignore = [
"__debug_utils/.+",
"__fwd/get[.]h",
"__pstl/.+",
"__support/.+",
"__utility/private_constructor_tag.h",
]
Expand Down
5 changes: 5 additions & 0 deletions libcxxabi/src/aix_state_tab_eh.inc
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,13 @@ static void invoke_destructor(FSMEntry* fsmEntry, void* addr) {
_LIBCXXABI_TRACE_STATETAB0("returned from scalar destructor\n");
} else {
_LIBCXXABI_TRACE_STATETAB0("calling vector destructor\n");
// TODO: in the legacy ABI, destructors had a second argument. We don't expect to encounter
// destructors of this type in the itanium-based ABI, so this should be safe, but this could use some cleanup.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-function-type"
__cxa_vec_cleanup(addr, reinterpret_cast<size_t>(fsmEntry->elementCount), fsmEntry->elemSize,
reinterpret_cast<destruct_f>(fsmEntry->destructor));
#pragma GCC diagnostic pop
_LIBCXXABI_TRACE_STATETAB0("returned from vector destructor\n");
}
} catch (...) {
Expand Down
7 changes: 7 additions & 0 deletions lld/COFF/Chunks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,13 @@ void SectionChunk::getRuntimePseudoRelocs(
dyn_cast_or_null<Defined>(file->getSymbol(rel.SymbolTableIndex));
if (!target || !target->isRuntimePseudoReloc)
continue;
// If the target doesn't have a chunk allocated, it may be a
// DefinedImportData symbol which ended up unnecessary after GC.
// Normally we wouldn't eliminate section chunks that are referenced, but
// references within DWARF sections don't count for keeping section chunks
// alive. Thus such dangling references in DWARF sections are expected.
if (!target->getChunk())
continue;
int sizeInBits =
getRuntimePseudoRelocSize(rel.Type, file->ctx.config.machine);
if (sizeInBits == 0) {
Expand Down
10 changes: 9 additions & 1 deletion lld/COFF/Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2072,8 +2072,16 @@ void Writer::createRuntimePseudoRelocs() {
return;
}

if (!rels.empty())
if (!rels.empty()) {
log("Writing " + Twine(rels.size()) + " runtime pseudo relocations");
const char *symbolName = "_pei386_runtime_relocator";
Symbol *relocator = ctx.symtab.findUnderscore(symbolName);
if (!relocator)
error("output image has runtime pseudo relocations, but the function " +
Twine(symbolName) +
" is missing; it is needed for fixing the relocations at runtime");
}

PseudoRelocTableChunk *table = make<PseudoRelocTableChunk>(rels);
rdataSec->addChunk(table);
EmptyChunk *endOfList = make<EmptyChunk>();
Expand Down
8 changes: 4 additions & 4 deletions lld/MachO/ObjC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ class ObjcCategoryMerger {
const PointerListInfo &ptrList);

Defined *emitCategory(const ClassExtensionInfo &extInfo);
Defined *emitCatListEntrySec(const std::string &forCateogryName,
Defined *emitCatListEntrySec(const std::string &forCategoryName,
const std::string &forBaseClassName,
ObjFile *objFile);
Defined *emitCategoryBody(const std::string &name, const Defined *nameSym,
Expand Down Expand Up @@ -878,7 +878,7 @@ void ObjcCategoryMerger::emitAndLinkPointerList(

// This method creates an __objc_catlist ConcatInputSection with a single slot
Defined *
ObjcCategoryMerger::emitCatListEntrySec(const std::string &forCateogryName,
ObjcCategoryMerger::emitCatListEntrySec(const std::string &forCategoryName,
const std::string &forBaseClassName,
ObjFile *objFile) {
uint32_t sectionSize = target->wordSize;
Expand All @@ -894,7 +894,7 @@ ObjcCategoryMerger::emitCatListEntrySec(const std::string &forCateogryName,
newCatList->parent = infoCategoryWriter.catListInfo.outputSection;

std::string catSymName = "<__objc_catlist slot for merged category ";
catSymName += forBaseClassName + "(" + forCateogryName + ")>";
catSymName += forBaseClassName + "(" + forCategoryName + ")>";

Defined *catListSym = make<Defined>(
newStringData(catSymName.c_str()), /*file=*/objFile, newCatList,
Expand Down Expand Up @@ -1069,7 +1069,7 @@ void ObjcCategoryMerger::collectAndValidateCategoriesData() {
off += target->wordSize) {
Defined *categorySym = tryGetDefinedAtIsecOffset(catListCisec, off);
assert(categorySym &&
"Failed to get a valid cateogry at __objc_catlit offset");
"Failed to get a valid category at __objc_catlit offset");

// We only support ObjC categories (no swift + @objc)
// TODO: Support swift + @objc categories also
Expand Down
3 changes: 3 additions & 0 deletions lld/test/COFF/autoimport-arm-data.s
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
.text
.thumb
main:
bx lr
.global _pei386_runtime_relocator
_pei386_runtime_relocator:
bx lr
.data
ptr:
Expand Down
3 changes: 3 additions & 0 deletions lld/test/COFF/autoimport-arm64-data.s
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
.global main
.text
main:
ret
.global _pei386_runtime_relocator
_pei386_runtime_relocator:
ret
.data
ptr:
Expand Down
41 changes: 41 additions & 0 deletions lld/test/COFF/autoimport-gc.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# REQUIRES: x86
# RUN: split-file %s %t.dir

# RUN: llvm-mc -triple=x86_64-windows-gnu %t.dir/lib.s -filetype=obj -o %t.dir/lib.obj
# RUN: lld-link -out:%t.dir/lib.dll -dll -entry:DllMainCRTStartup %t.dir/lib.obj -lldmingw -implib:%t.dir/lib.lib

# RUN: llvm-mc -triple=x86_64-windows-gnu %t.dir/main.s -filetype=obj -o %t.dir/main.obj
# RUN: lld-link -lldmingw -out:%t.dir/main.exe -entry:main %t.dir/main.obj %t.dir/lib.lib -opt:ref -debug:dwarf

#--- main.s
.global main
.section .text$main,"xr",one_only,main
main:
ret

.global other
.section .text$other,"xr",one_only,other
other:
movq .refptr.variable(%rip), %rax
movl (%rax), %eax
ret

.section .rdata$.refptr.variable,"dr",discard,.refptr.variable
.global .refptr.variable
.refptr.variable:
.quad variable

.section .debug_info
.long 1
.quad variable
.long 2

#--- lib.s
.global variable
.global DllMainCRTStartup
.text
DllMainCRTStartup:
ret
.data
variable:
.long 42
3 changes: 3 additions & 0 deletions lld/test/COFF/autoimport-gnu-implib.s
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,8 @@
.text
main:
movl data(%rip), %eax
ret
.global _pei386_runtime_relocator
_pei386_runtime_relocator:
ret
.data
36 changes: 36 additions & 0 deletions lld/test/COFF/autoimport-handler-func.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# REQUIRES: x86
# RUN: split-file %s %t.dir

# RUN: llvm-dlltool -m i386:x86-64 -d %t.dir/lib.def -D lib.dll -l %t.dir/lib.lib

# RUN: llvm-mc -triple=x86_64-windows-gnu %t.dir/main.s -filetype=obj -o %t.dir/main.obj
# RUN: llvm-mc -triple=x86_64-windows-gnu %t.dir/func.s -filetype=obj -o %t.dir/func.obj
# RUN: env LLD_IN_TEST=1 not lld-link -lldmingw -out:%t.dir/main.exe -entry:main %t.dir/main.obj %t.dir/lib.lib 2>&1 | FileCheck %s --check-prefix=ERR

# RUN: lld-link -lldmingw -out:%t.dir/main.exe -entry:main %t.dir/main.obj %t.dir/func.obj %t.dir/lib.lib 2>&1 | FileCheck %s --check-prefix=NOERR --allow-empty

# ERR: error: output image has runtime pseudo relocations, but the function _pei386_runtime_relocator is missing; it is needed for fixing the relocations at runtime

# NOERR-NOT: error

#--- main.s
.global main
.text
main:
ret

.data
.long 1
.quad variable
.long 2

#--- func.s
.global _pei386_runtime_relocator
.text
_pei386_runtime_relocator:
ret

#--- lib.def
EXPORTS
variable DATA

3 changes: 3 additions & 0 deletions lld/test/COFF/autoimport-warn.s
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ main:
movl variable2(%rip), %ecx
addl %ecx, %eax
ret
.global _pei386_runtime_relocator
_pei386_runtime_relocator:
ret

.section .rdata$.refptr.variable1,"dr",discard,.refptr.variable1
.global .refptr.variable1
Expand Down
3 changes: 3 additions & 0 deletions lld/test/COFF/autoimport-x86.s
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@
.text
main:
movl variable(%rip), %eax
ret
.global _pei386_runtime_relocator
_pei386_runtime_relocator:
ret
.data
ptr:
Expand Down
2 changes: 1 addition & 1 deletion lldb/cmake/modules/LLDBFramework.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ add_custom_command(TARGET liblldb POST_BUILD
if(NOT APPLE_EMBEDDED)
if (TARGET clang-resource-headers)
add_dependencies(liblldb clang-resource-headers)
set(clang_resource_headers_dir $<TARGET_PROPERTY:clang-resource-headers,RUNTIME_OUTPUT_DIRECTORY>)
set(clang_resource_headers_dir $<TARGET_PROPERTY:clang-resource-headers,INTERFACE_INCLUDE_DIRECTORIES>)
else()
set(clang_resource_headers_dir ${LLDB_EXTERNAL_CLANG_RESOURCE_DIR}/include)
if(NOT EXISTS ${clang_resource_headers_dir})
Expand Down
2 changes: 1 addition & 1 deletion lldb/include/lldb/lldb-enumerations.h
Original file line number Diff line number Diff line change
Expand Up @@ -1310,7 +1310,7 @@ enum CompletionType {

/// Specifies if children need to be re-computed
/// after a call to \ref SyntheticChildrenFrontEnd::Update.
enum class ChildCacheState {
enum ChildCacheState {
eRefetch = 0, ///< Children need to be recomputed dynamically.

eReuse = 1, ///< Children did not change and don't need to be recomputed;
Expand Down
2 changes: 2 additions & 0 deletions lldb/packages/Python/lldbsuite/test/lldbtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,8 @@ def setUpCommands(cls):
"settings set symbols.enable-external-lookup false",
# Inherit the TCC permissions from the inferior's parent.
"settings set target.inherit-tcc true",
# Based on https://discourse.llvm.org/t/running-lldb-in-a-container/76801/4
"settings set target.disable-aslr false",
# Kill rather than detach from the inferior if something goes wrong.
"settings set target.detach-on-error false",
# Disable fix-its by default so that incorrect expressions in tests don't
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1049,7 +1049,6 @@ void ClangExpressionDeclMap::LookupInModulesDeclVendor(
context.AddNamedDecl(copied_function);

context.m_found_function_with_type_info = true;
context.m_found_function = true;
} else if (auto copied_var = dyn_cast<clang::VarDecl>(copied_decl)) {
context.AddNamedDecl(copied_var);
context.m_found_variable = true;
Expand Down Expand Up @@ -1299,7 +1298,6 @@ void ClangExpressionDeclMap::LookupFunction(

AddOneFunction(context, sym_ctx.function, nullptr);
context.m_found_function_with_type_info = true;
context.m_found_function = true;
} else if (sym_ctx.symbol) {
Symbol *symbol = sym_ctx.symbol;
if (target && symbol->GetType() == eSymbolTypeReExported) {
Expand Down Expand Up @@ -1331,10 +1329,8 @@ void ClangExpressionDeclMap::LookupFunction(
if (!context.m_found_function_with_type_info) {
if (extern_symbol) {
AddOneFunction(context, nullptr, extern_symbol);
context.m_found_function = true;
} else if (non_extern_symbol) {
AddOneFunction(context, nullptr, non_extern_symbol);
context.m_found_function = true;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ struct NameSearchContext {

bool m_found_variable = false;
bool m_found_function_with_type_info = false;
bool m_found_function = false;
bool m_found_local_vars_nsp = false;
bool m_found_type = false;

Expand Down
1 change: 1 addition & 0 deletions lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN
LibCxxQueue.cpp
LibCxxRangesRefView.cpp
LibCxxSliceArray.cpp
LibCxxProxyArray.cpp
LibCxxSpan.cpp
LibCxxTuple.cpp
LibCxxUnorderedMap.cpp
Expand Down
11 changes: 11 additions & 0 deletions lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -760,6 +760,12 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
lldb_private::formatters::LibcxxStdSliceArraySyntheticFrontEndCreator,
"libc++ std::slice_array synthetic children",
"^std::__[[:alnum:]]+::slice_array<.+>$", stl_deref_flags, true);
AddCXXSynthetic(
cpp_category_sp,
lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEndCreator,
"libc++ synthetic children for the valarray proxy arrays",
"^std::__[[:alnum:]]+::(gslice|mask|indirect)_array<.+>$",
stl_deref_flags, true);
AddCXXSynthetic(
cpp_category_sp,
lldb_private::formatters::LibcxxStdForwardListSyntheticFrontEndCreator,
Expand Down Expand Up @@ -890,6 +896,11 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
"libc++ std::slice_array summary provider",
"^std::__[[:alnum:]]+::slice_array<.+>$", stl_summary_flags,
true);
AddCXXSummary(cpp_category_sp,
lldb_private::formatters::LibcxxContainerSummaryProvider,
"libc++ summary provider for the valarray proxy arrays",
"^std::__[[:alnum:]]+::(gslice|mask|indirect)_array<.+>$",
stl_summary_flags, true);
AddCXXSummary(
cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider,
"libc++ std::list summary provider",
Expand Down
4 changes: 4 additions & 0 deletions lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,10 @@ SyntheticChildrenFrontEnd *
LibcxxStdSliceArraySyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);

SyntheticChildrenFrontEnd *
LibcxxStdProxyArraySyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);

SyntheticChildrenFrontEnd *
LibcxxStdListSyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);
Expand Down
194 changes: 194 additions & 0 deletions lldb/source/Plugins/Language/CPlusPlus/LibCxxProxyArray.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
//===-- LibCxxProxyArray.cpp-----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "LibCxx.h"

#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include <optional>

using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::formatters;

namespace lldb_private {
namespace formatters {

/// Data formatter for libc++'s std::"proxy_array".
///
/// A proxy_array's are created by using:
/// std::gslice_array operator[](const std::gslice& gslicearr);
/// std::mask_array operator[](const std::valarray<bool>& boolarr);
/// std::indirect_array operator[](const std::valarray<std::size_t>& indarr);
///
/// These arrays have the following members:
/// - __vp_ points to std::valarray::__begin_
/// - __1d_ an array of offsets of the elements from @a __vp_
class LibcxxStdProxyArraySyntheticFrontEnd : public SyntheticChildrenFrontEnd {
public:
LibcxxStdProxyArraySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);

~LibcxxStdProxyArraySyntheticFrontEnd() override;

llvm::Expected<uint32_t> CalculateNumChildren() override;

lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;

lldb::ChildCacheState Update() override;

bool MightHaveChildren() override;

size_t GetIndexOfChildWithName(ConstString name) override;

private:
/// A non-owning pointer to the array's __vp_.
ValueObject *m_base = nullptr;
/// The type of the array's template argument T.
CompilerType m_element_type;
/// The sizeof the array's template argument T.
uint32_t m_element_size = 0;

/// A non-owning pointer to the array's __1d_.__begin_.
ValueObject *m_start = nullptr;
/// A non-owning pointer to the array's __1d_.__end_.
ValueObject *m_finish = nullptr;
/// The type of the __1d_ array's template argument T (size_t).
CompilerType m_element_type_size_t;
/// The sizeof the __1d_ array's template argument T (size_t)
uint32_t m_element_size_size_t = 0;
};

} // namespace formatters
} // namespace lldb_private

lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd::
LibcxxStdProxyArraySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
: SyntheticChildrenFrontEnd(*valobj_sp), m_element_type() {
if (valobj_sp)
Update();
}

lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd::
~LibcxxStdProxyArraySyntheticFrontEnd() {
// these need to stay around because they are child objects who will follow
// their parent's life cycle
// delete m_base;
}

llvm::Expected<uint32_t> lldb_private::formatters::
LibcxxStdProxyArraySyntheticFrontEnd::CalculateNumChildren() {

if (!m_start || !m_finish)
return 0;
uint64_t start_val = m_start->GetValueAsUnsigned(0);
uint64_t finish_val = m_finish->GetValueAsUnsigned(0);

if (start_val == 0 || finish_val == 0)
return 0;

if (start_val >= finish_val)
return 0;

size_t num_children = (finish_val - start_val);
if (num_children % m_element_size_size_t)
return 0;
return num_children / m_element_size_size_t;
}

lldb::ValueObjectSP
lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd::GetChildAtIndex(
uint32_t idx) {
if (!m_base)
return lldb::ValueObjectSP();

uint64_t offset = idx * m_element_size_size_t;
offset = offset + m_start->GetValueAsUnsigned(0);

lldb::ValueObjectSP indirect = CreateValueObjectFromAddress(
"", offset, m_backend.GetExecutionContextRef(), m_element_type_size_t);
if (!indirect)
return lldb::ValueObjectSP();

const size_t value = indirect->GetValueAsUnsigned(0);
if (!value)
return lldb::ValueObjectSP();

offset = value * m_element_size;
offset = offset + m_base->GetValueAsUnsigned(0);

StreamString name;
name.Printf("[%" PRIu64 "] -> [%zu]", (uint64_t)idx, value);
return CreateValueObjectFromAddress(name.GetString(), offset,
m_backend.GetExecutionContextRef(),
m_element_type);
}

lldb::ChildCacheState
lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd::Update() {
m_base = nullptr;
m_start = nullptr;
m_finish = nullptr;

CompilerType type = m_backend.GetCompilerType();
if (type.GetNumTemplateArguments() == 0)
return ChildCacheState::eRefetch;

m_element_type = type.GetTypeTemplateArgument(0);
if (std::optional<uint64_t> size = m_element_type.GetByteSize(nullptr))
m_element_size = *size;

if (m_element_size == 0)
return ChildCacheState::eRefetch;

ValueObjectSP vector = m_backend.GetChildMemberWithName("__1d_");
if (!vector)
return ChildCacheState::eRefetch;

type = vector->GetCompilerType();
if (type.GetNumTemplateArguments() == 0)
return ChildCacheState::eRefetch;

m_element_type_size_t = type.GetTypeTemplateArgument(0);
if (std::optional<uint64_t> size = m_element_type_size_t.GetByteSize(nullptr))
m_element_size_size_t = *size;

if (m_element_size_size_t == 0)
return ChildCacheState::eRefetch;

ValueObjectSP base = m_backend.GetChildMemberWithName("__vp_");
ValueObjectSP start = vector->GetChildMemberWithName("__begin_");
ValueObjectSP finish = vector->GetChildMemberWithName("__end_");
if (!base || !start || !finish)
return ChildCacheState::eRefetch;

m_base = base.get();
m_start = start.get();
m_finish = finish.get();

return ChildCacheState::eRefetch;
}

bool lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd::
MightHaveChildren() {
return true;
}

size_t lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd::
GetIndexOfChildWithName(ConstString name) {
if (!m_base)
return std::numeric_limits<size_t>::max();
return ExtractIndexFromString(name.GetCString());
}

lldb_private::SyntheticChildrenFrontEnd *
lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEndCreator(
CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
if (!valobj_sp)
return nullptr;
return new LibcxxStdProxyArraySyntheticFrontEnd(valobj_sp);
}
79 changes: 6 additions & 73 deletions lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -459,85 +459,19 @@ TypeSystemClang::ConvertAccessTypeToAccessSpecifier(AccessType access) {
return AS_none;
}

static void ParseLangArgs(LangOptions &Opts, InputKind IK, const char *triple) {
static void ParseLangArgs(LangOptions &Opts, ArchSpec arch) {
// FIXME: Cleanup per-file based stuff.

// Set some properties which depend solely on the input kind; it would be
// nice to move these to the language standard, and have the driver resolve
// the input kind + language standard.
if (IK.getLanguage() == clang::Language::Asm) {
Opts.AsmPreprocessor = 1;
} else if (IK.isObjectiveC()) {
Opts.ObjC = 1;
}

LangStandard::Kind LangStd = LangStandard::lang_unspecified;

if (LangStd == LangStandard::lang_unspecified) {
// Based on the base language, pick one.
switch (IK.getLanguage()) {
case clang::Language::Unknown:
case clang::Language::CIR:
case clang::Language::LLVM_IR:
case clang::Language::RenderScript:
llvm_unreachable("Invalid input kind!");
case clang::Language::OpenCL:
LangStd = LangStandard::lang_opencl10;
break;
case clang::Language::OpenCLCXX:
LangStd = LangStandard::lang_openclcpp10;
break;
case clang::Language::Asm:
case clang::Language::C:
case clang::Language::ObjC:
LangStd = LangStandard::lang_gnu99;
break;
case clang::Language::CXX:
case clang::Language::ObjCXX:
LangStd = LangStandard::lang_gnucxx98;
break;
case clang::Language::CUDA:
case clang::Language::HIP:
LangStd = LangStandard::lang_gnucxx17;
break;
case clang::Language::HLSL:
LangStd = LangStandard::lang_hlsl;
break;
}
}

const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd);
Opts.LineComment = Std.hasLineComments();
Opts.C99 = Std.isC99();
Opts.CPlusPlus = Std.isCPlusPlus();
Opts.CPlusPlus11 = Std.isCPlusPlus11();
Opts.CPlusPlus14 = Std.isCPlusPlus14();
Opts.CPlusPlus17 = Std.isCPlusPlus17();
Opts.CPlusPlus20 = Std.isCPlusPlus20();
Opts.Digraphs = Std.hasDigraphs();
Opts.GNUMode = Std.isGNUMode();
Opts.GNUInline = !Std.isC99();
Opts.HexFloats = Std.hasHexFloats();

Opts.WChar = true;

// OpenCL has some additional defaults.
if (LangStd == LangStandard::lang_opencl10) {
Opts.OpenCL = 1;
Opts.AltiVec = 1;
Opts.CXXOperatorNames = 1;
Opts.setLaxVectorConversions(LangOptions::LaxVectorConversionKind::All);
}

// OpenCL and C++ both have bool, true, false keywords.
Opts.Bool = Opts.OpenCL || Opts.CPlusPlus;
std::vector<std::string> Includes;
LangOptions::setLangDefaults(Opts, clang::Language::ObjCXX, arch.GetTriple(),
Includes, clang::LangStandard::lang_gnucxx98);

Opts.setValueVisibilityMode(DefaultVisibility);

// Mimicing gcc's behavior, trigraphs are only enabled if -trigraphs is
// specified, or -std is set to a conforming mode.
Opts.Trigraphs = !Opts.GNUMode;
Opts.CharIsSigned = ArchSpec(triple).CharIsSignedByDefault();
Opts.CharIsSigned = arch.CharIsSignedByDefault();
Opts.OptimizeSize = 0;

// FIXME: Eliminate this dependency.
Expand Down Expand Up @@ -727,8 +661,7 @@ void TypeSystemClang::CreateASTContext() {
m_ast_owned = true;

m_language_options_up = std::make_unique<LangOptions>();
ParseLangArgs(*m_language_options_up, clang::Language::ObjCXX,
GetTargetTriple());
ParseLangArgs(*m_language_options_up, ArchSpec(GetTargetTriple()));

m_identifier_table_up =
std::make_unique<IdentifierTable>(*m_language_options_up, nullptr);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -909,6 +909,9 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(
if (!m_register_map_initialized)
return false;

if (m_disasm_context == nullptr)
return false;

addr_t current_func_text_offset = 0;
int current_sp_bytes_offset_from_fa = 0;
bool is_aligned = false;
Expand Down Expand Up @@ -1570,6 +1573,9 @@ bool x86AssemblyInspectionEngine::FindFirstNonPrologueInstruction(
if (!m_register_map_initialized)
return false;

if (m_disasm_context == nullptr)
return false;

while (offset < size) {
int regno;
int insn_len;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ def test_diagnose_dereference_function_return(self):
TestBase.setUp(self)
self.build()
exe = self.getBuildArtifact("a.out")
# FIXME: This default changed in lldbtest.py and this test
# seems to rely on having it turned off.
self.runCmd("settings set target.disable-aslr true")
self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
self.runCmd("run", RUN_SUCCEEDED)
self.expect("thread list", "Thread should be stopped", substrs=["stopped"])
Expand Down
6 changes: 5 additions & 1 deletion lldb/test/API/functionalities/asan/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
C_SOURCES := main.c
CFLAGS_EXTRAS := -fsanitize=address -g -gcolumn-info
asan: CFLAGS_EXTRAS := -fsanitize=address -g -gcolumn-info
asan: all

libsanitizers: CFLAGS_EXTRAS := -fsanitize=address -fsanitize-stable-abi -g -gcolumn-info
libsanitizers: all

include Makefile.rules
73 changes: 72 additions & 1 deletion lldb/test/API/functionalities/asan/TestMemoryHistory.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,21 @@
from lldbsuite.test import lldbplatform
from lldbsuite.test import lldbutil

from functionalities.libsanitizers.util import no_libsanitizers

class AsanTestCase(TestBase):
@skipIfFreeBSD # llvm.org/pr21136 runtimes not yet available by default
@expectedFailureNetBSD
@skipUnlessAddressSanitizer
def test(self):
self.build()
self.build(make_targets=["asan"])
self.asan_tests()

@skipIf(oslist=no_match(["macosx"]))
def test_libsanitizers_asan(self):
self.build(make_targets=["libsanitizers"])
self.libsanitizer_tests()

def setUp(self):
# Call super's setUp().
TestBase.setUp(self)
Expand All @@ -26,6 +32,71 @@ def setUp(self):
self.line_free = line_number("main.c", "// free line")
self.line_breakpoint = line_number("main.c", "// break line")

# Test line numbers: rdar://126237493
def libsanitizer_tests(self):
target = self.createTestTarget()

if no_libsanitizers(self):
self.skipTest("libsanitizers not found")

self.runCmd(
"env SanitizersAddress=1 MallocSanitizerZone=1 MallocSecureAllocator=0"
)

self.runCmd("run")

# In libsanitizers, memory history is not supported until a report has been generated
self.expect(
"thread list",
"Process should be stopped due to ASan report",
substrs=["stopped", "stop reason = Use of deallocated memory"],
)

# test the 'memory history' command
self.expect(
"memory history 'pointer'",
substrs=[
"Memory deallocated by Thread",
"a.out`f2",
"main.c",
"Memory allocated by Thread",
"a.out`f1",
"main.c",
],
)

# do the same using SB API
process = self.dbg.GetSelectedTarget().process
val = (
process.GetSelectedThread().GetSelectedFrame().EvaluateExpression("pointer")
)
addr = val.GetValueAsUnsigned()
threads = process.GetHistoryThreads(addr)
self.assertEqual(threads.GetSize(), 2)

history_thread = threads.GetThreadAtIndex(0)
self.assertTrue(history_thread.num_frames >= 2)
self.assertEqual(
history_thread.frames[1].GetLineEntry().GetFileSpec().GetFilename(),
"main.c",
)

history_thread = threads.GetThreadAtIndex(1)
self.assertTrue(history_thread.num_frames >= 2)
self.assertEqual(
history_thread.frames[1].GetLineEntry().GetFileSpec().GetFilename(),
"main.c",
)

# let's free the container (SBThreadCollection) and see if the
# SBThreads still live
threads = None
self.assertTrue(history_thread.num_frames >= 2)
self.assertEqual(
history_thread.frames[1].GetLineEntry().GetFileSpec().GetFilename(),
"main.c",
)

def asan_tests(self):
target = self.createTestTarget()

Expand Down
20 changes: 17 additions & 3 deletions lldb/test/API/functionalities/asan/TestReportData.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,22 @@
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil

from functionalities.libsanitizers.util import no_libsanitizers

class AsanTestReportDataCase(TestBase):
@skipIfFreeBSD # llvm.org/pr21136 runtimes not yet available by default
@expectedFailureNetBSD
@skipUnlessAddressSanitizer
@skipIf(archs=["i386"], bugnumber="llvm.org/PR36710")
def test(self):
self.build()
self.build(make_targets=["asan"])
self.asan_tests()

@skipIf(oslist=no_match(["macosx"]))
def test_libsanitizers_asan(self):
self.build(make_targets=["libsanitizers"])
self.asan_tests(libsanitizers=True)

def setUp(self):
# Call super's setUp().
TestBase.setUp(self)
Expand All @@ -29,10 +35,18 @@ def setUp(self):
self.line_crash = line_number("main.c", "// BOOM line")
self.col_crash = 16

def asan_tests(self):
def asan_tests(self, libsanitizers=False):
target = self.createTestTarget()

self.registerSanitizerLibrariesWithTarget(target)
if libsanitizers and no_libsanitizers(self):
self.skipTest("libsanitizers not found")

if libsanitizers:
self.runCmd(
"env SanitizersAddress=1 MallocSanitizerZone=1 MallocSecureAllocator=0"
)
else:
self.registerSanitizerLibrariesWithTarget(target)

self.runCmd("run")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,21 +89,93 @@ def test_with_run_command(self):
"frame variable sa",
substrs=[
"sa = stride=2 size=4",
"[0] = 1",
"[1] = 3",
"[2] = 5",
"[3] = 7",
"[0] = 11",
"[1] = 13",
"[2] = 15",
"[3] = 17",
"}",
],
)

# check access-by-index
self.expect("frame variable sa[0]", substrs=["1"])
self.expect("frame variable sa[1]", substrs=["3"])
self.expect("frame variable sa[2]", substrs=["5"])
self.expect("frame variable sa[3]", substrs=["7"])
self.expect("frame variable sa[0]", substrs=["11"])
self.expect("frame variable sa[1]", substrs=["13"])
self.expect("frame variable sa[2]", substrs=["15"])
self.expect("frame variable sa[3]", substrs=["17"])
self.expect(
"frame variable sa[4]",
error=True,
substrs=['array index 4 is not valid for "(slice_array<int>) sa"'],
)

#
# std::gslice_array
#

self.expect(
"frame variable ga",
substrs=[
"ga = size=3",
"[0] -> [3] = 13",
"[1] -> [4] = 14",
"[2] -> [5] = 15",
"}",
],
)

# check access-by-index
self.expect("frame variable ga[0]", substrs=["13"])
self.expect("frame variable ga[1]", substrs=["14"])
self.expect("frame variable ga[2]", substrs=["15"])
self.expect(
"frame variable ga[3]",
error=True,
substrs=['array index 3 is not valid for "(gslice_array<int>) ga"'],
)
#
# std::mask_array
#

self.expect(
"frame variable ma",
substrs=[
"ma = size=2",
"[0] -> [1] = 11",
"[1] -> [2] = 12",
"}",
],
)

# check access-by-index
self.expect("frame variable ma[0]", substrs=["11"])
self.expect("frame variable ma[1]", substrs=["12"])
self.expect(
"frame variable ma[2]",
error=True,
substrs=['array index 2 is not valid for "(mask_array<int>) ma"'],
)

#
# std::indirect_array
#

self.expect(
"frame variable ia",
substrs=[
"ia = size=3",
"[0] -> [3] = 13",
"[1] -> [6] = 16",
"[2] -> [9] = 19",
"}",
],
)

# check access-by-index
self.expect("frame variable ia[0]", substrs=["13"])
self.expect("frame variable ia[1]", substrs=["16"])
self.expect("frame variable ia[2]", substrs=["19"])
self.expect(
"frame variable ia[3]",
error=True,
substrs=['array index 3 is not valid for "(indirect_array<int>) ia"'],
)
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@ int main() {

std::valarray<double> va_double({1.0, 0.5, 0.25, 0.125});

std::valarray<int> va({0, 1, 2, 3, 4, 5, 6, 7, 8, 9});
std::valarray<int> va({10, 11, 12, 13, 14, 15, 16, 17, 18, 19});
std::slice_array<int> sa = va[std::slice(1, 4, 2)];
std::gslice_array<int> ga = va[std::gslice(
3, std::valarray<std::size_t>(3, 1), std::valarray<std::size_t>(1, 1))];
std::mask_array<int> ma = va[std::valarray<bool>{false, true, true}];
std::indirect_array<int> ia = va[std::valarray<size_t>{3, 6, 9}];

std::cout << "break here\n";
}
3 changes: 3 additions & 0 deletions lldb/test/API/functionalities/libsanitizers/util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
def no_libsanitizers(testbase):
testbase.runCmd("image list libsystem_sanitizers.dylib", check=False)
return not "libsystem_sanitizers.dylib" in testbase.res.GetOutput()
12 changes: 8 additions & 4 deletions lldb/test/Shell/lit.cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,14 @@
)

# Enable sanitizer runtime flags.
config.environment["ASAN_OPTIONS"] = "detect_stack_use_after_return=1"
config.environment["TSAN_OPTIONS"] = "halt_on_error=1"
if platform.system() == "Darwin":
config.environment["MallocNanoZone"] = "0"
if "Address" in config.llvm_use_sanitizer:
config.environment["ASAN_OPTIONS"] = "detect_stack_use_after_return=1"
if platform.system() == "Darwin":
config.environment["MallocNanoZone"] = "0"

if "Thread" in config.llvm_use_sanitizer:
config.environment["TSAN_OPTIONS"] = "halt_on_error=1"


# Support running the test suite under the lldb-repro wrapper. This makes it
# possible to capture a test suite run and then rerun all the test from the
Expand Down
1 change: 1 addition & 0 deletions lldb/test/Shell/lit.site.cfg.py.in
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ config.lldb_enable_lua = @LLDB_ENABLE_LUA@
config.lldb_build_directory = "@LLDB_TEST_BUILD_DIRECTORY@"
config.have_lldb_server = @LLDB_TOOL_LLDB_SERVER_BUILD@
config.lldb_system_debugserver = @LLDB_USE_SYSTEM_DEBUGSERVER@
config.llvm_use_sanitizer = "@LLVM_USE_SANITIZER@"
# The shell tests use their own module caches.
config.lldb_module_cache = os.path.join("@LLDB_TEST_MODULE_CACHE_LLDB@", "lldb-shell")
config.clang_module_cache = os.path.join("@LLDB_TEST_MODULE_CACHE_CLANG@", "lldb-shell")
Expand Down
4 changes: 4 additions & 0 deletions lldb/unittests/UnwindAssembly/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,7 @@ endif()
if ("X86" IN_LIST LLVM_TARGETS_TO_BUILD)
add_subdirectory(x86)
endif()

if (NOT "X86" IN_LIST LLVM_TARGETS_TO_BUILD)
add_subdirectory(x86-but-no-x86-target)
endif()
10 changes: 10 additions & 0 deletions lldb/unittests/UnwindAssembly/x86-but-no-x86-target/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
add_lldb_unittest(UnwindAssemblyX86ButNoX86TargetTests
Testx86AssemblyInspectionEngine.cpp
LINK_LIBS
lldbCore
lldbSymbol
lldbPluginUnwindAssemblyX86
LINK_COMPONENTS
Support
${LLVM_TARGETS_TO_BUILD}
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
//===-- Testx86AssemblyInspectionEngine.cpp -------------------------------===//

//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "gtest/gtest.h"

#include "Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h"
#include "lldb/Core/AddressRange.h"
#include "lldb/Symbol/UnwindPlan.h"
#include "lldb/Utility/ArchSpec.h"

#include "llvm/Support/TargetSelect.h"

#include <memory>
#include <vector>

using namespace lldb;
using namespace lldb_private;

class Testx86AssemblyInspectionEngine : public testing::Test {
public:
static void SetUpTestCase();
};

void Testx86AssemblyInspectionEngine::SetUpTestCase() {
llvm::InitializeAllTargets();
llvm::InitializeAllAsmPrinters();
llvm::InitializeAllTargetMCs();
llvm::InitializeAllDisassemblers();
}

// only defining the register names / numbers that the unwinder is actually
// using today

// names should match the constants below. These will be the eRegisterKindLLDB
// register numbers.

const char *x86_64_reg_names[] = {"rax", "rbx", "rcx", "rdx", "rsp", "rbp",
"rsi", "rdi", "r8", "r9", "r10", "r11",
"r12", "r13", "r14", "r15", "rip"};

enum x86_64_regs {
k_rax = 0,
k_rbx = 1,
k_rcx = 2,
k_rdx = 3,
k_rsp = 4,
k_rbp = 5,
k_rsi = 6,
k_rdi = 7,
k_r8 = 8,
k_r9 = 9,
k_r10 = 10,
k_r11 = 11,
k_r12 = 12,
k_r13 = 13,
k_r14 = 14,
k_r15 = 15,
k_rip = 16
};

std::unique_ptr<x86AssemblyInspectionEngine> Getx86_64Inspector() {

ArchSpec arch("x86_64-apple-macosx");
std::unique_ptr<x86AssemblyInspectionEngine> engine(
new x86AssemblyInspectionEngine(arch));

std::vector<x86AssemblyInspectionEngine::lldb_reg_info> lldb_regnums;
int i = 0;
for (const auto &name : x86_64_reg_names) {
x86AssemblyInspectionEngine::lldb_reg_info ri;
ri.name = name;
ri.lldb_regnum = i++;
lldb_regnums.push_back(ri);
}

engine->Initialize(lldb_regnums);
return engine;
}

TEST_F(Testx86AssemblyInspectionEngine, TestSimple64bitFrameFunction) {
std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();

// 'int main() { }' compiled for x86_64-apple-macosx with clang
uint8_t data[] = {
0x55, // offset 0 -- pushq %rbp
0x48, 0x89, 0xe5, // offset 1 -- movq %rsp, %rbp
0x31, 0xc0, // offset 4 -- xorl %eax, %eax
0x5d, // offset 6 -- popq %rbp
0xc3 // offset 7 -- retq
};

AddressRange sample_range(0x1000, sizeof(data));

UnwindPlan unwind_plan(eRegisterKindLLDB);
EXPECT_FALSE(engine->GetNonCallSiteUnwindPlanFromAssembly(
data, sizeof(data), sample_range, unwind_plan));
}
4 changes: 3 additions & 1 deletion lldb/unittests/tools/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
if(LLDB_TOOL_LLDB_SERVER_BUILD)
add_subdirectory(lldb-server)
if (NOT LLVM_USE_SANITIZER MATCHES ".*Address.*")
add_subdirectory(lldb-server)
endif()
endif()
3 changes: 3 additions & 0 deletions llvm/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@ Changes to the C API

* Deprecated ``LLVMConstNUWNeg`` and ``LLVMBuildNUWNeg``.

* Added ``LLVMAtomicRMWBinOpUIncWrap`` and ``LLVMAtomicRMWBinOpUDecWrap`` to
``LLVMAtomicRMWBinOp`` enum for AtomicRMW instructions.

Changes to the CodeGen infrastructure
-------------------------------------

Expand Down
60 changes: 32 additions & 28 deletions llvm/include/llvm-c/Core.h
Original file line number Diff line number Diff line change
Expand Up @@ -361,35 +361,39 @@ typedef enum {
} LLVMAtomicOrdering;

typedef enum {
LLVMAtomicRMWBinOpXchg, /**< Set the new value and return the one old */
LLVMAtomicRMWBinOpAdd, /**< Add a value and return the old one */
LLVMAtomicRMWBinOpSub, /**< Subtract a value and return the old one */
LLVMAtomicRMWBinOpAnd, /**< And a value and return the old one */
LLVMAtomicRMWBinOpNand, /**< Not-And a value and return the old one */
LLVMAtomicRMWBinOpOr, /**< OR a value and return the old one */
LLVMAtomicRMWBinOpXor, /**< Xor a value and return the old one */
LLVMAtomicRMWBinOpMax, /**< Sets the value if it's greater than the
original using a signed comparison and return
the old one */
LLVMAtomicRMWBinOpMin, /**< Sets the value if it's Smaller than the
original using a signed comparison and return
the old one */
LLVMAtomicRMWBinOpUMax, /**< Sets the value if it's greater than the
original using an unsigned comparison and return
the old one */
LLVMAtomicRMWBinOpUMin, /**< Sets the value if it's greater than the
original using an unsigned comparison and return
the old one */
LLVMAtomicRMWBinOpFAdd, /**< Add a floating point value and return the
old one */
LLVMAtomicRMWBinOpFSub, /**< Subtract a floating point value and return the
LLVMAtomicRMWBinOpXchg, /**< Set the new value and return the one old */
LLVMAtomicRMWBinOpAdd, /**< Add a value and return the old one */
LLVMAtomicRMWBinOpSub, /**< Subtract a value and return the old one */
LLVMAtomicRMWBinOpAnd, /**< And a value and return the old one */
LLVMAtomicRMWBinOpNand, /**< Not-And a value and return the old one */
LLVMAtomicRMWBinOpOr, /**< OR a value and return the old one */
LLVMAtomicRMWBinOpXor, /**< Xor a value and return the old one */
LLVMAtomicRMWBinOpMax, /**< Sets the value if it's greater than the
original using a signed comparison and return
the old one */
LLVMAtomicRMWBinOpMin, /**< Sets the value if it's Smaller than the
original using a signed comparison and return
the old one */
LLVMAtomicRMWBinOpUMax, /**< Sets the value if it's greater than the
original using an unsigned comparison and return
the old one */
LLVMAtomicRMWBinOpUMin, /**< Sets the value if it's greater than the
original using an unsigned comparison and return
the old one */
LLVMAtomicRMWBinOpFAdd, /**< Add a floating point value and return the
old one */
LLVMAtomicRMWBinOpFMax, /**< Sets the value if it's greater than the
original using an floating point comparison and
return the old one */
LLVMAtomicRMWBinOpFMin, /**< Sets the value if it's smaller than the
original using an floating point comparison and
return the old one */
LLVMAtomicRMWBinOpFSub, /**< Subtract a floating point value and return the
old one */
LLVMAtomicRMWBinOpFMax, /**< Sets the value if it's greater than the
original using an floating point comparison and
return the old one */
LLVMAtomicRMWBinOpFMin, /**< Sets the value if it's smaller than the
original using an floating point comparison and
return the old one */
LLVMAtomicRMWBinOpUIncWrap, /**< Increments the value, wrapping back to zero
when incremented above input value */
LLVMAtomicRMWBinOpUDecWrap, /**< Decrements the value, wrapping back to
the input value when decremented below zero */
} LLVMAtomicRMWBinOp;

typedef enum {
Expand Down
6 changes: 3 additions & 3 deletions llvm/include/llvm/Analysis/TypeMetadataUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ void findDevirtualizableCallsForTypeCheckedLoad(
/// Used for example from GlobalDCE to find an entry in a C++ vtable that
/// matches a vcall offset.
///
/// To support Swift vtables, getPointerAtOffset can see through "relative
/// To support relative vtables, getPointerAtOffset can see through "relative
/// pointers", i.e. (sub-)expressions of the form of:
///
/// @symbol = ... {
Expand All @@ -87,8 +87,8 @@ std::pair<Function *, Constant *>
getFunctionAtVTableOffset(GlobalVariable *GV, uint64_t Offset, Module &M);

/// Finds the same "relative pointer" pattern as described above, where the
/// target is `F`, and replaces the entire pattern with a constant zero.
void replaceRelativePointerUsersWithZero(Function *F);
/// target is `C`, and replaces the entire pattern with a constant zero.
void replaceRelativePointerUsersWithZero(Constant *C);

} // namespace llvm

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIB_CODEGEN_LIVEDEBUGVARIABLES_H
#define LLVM_LIB_CODEGEN_LIVEDEBUGVARIABLES_H
#ifndef LLVM_CODEGEN_LIVEDEBUGVARIABLES_H
#define LLVM_CODEGEN_LIVEDEBUGVARIABLES_H

#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/Support/Compiler.h"
Expand All @@ -29,7 +29,7 @@ template <typename T> class ArrayRef;
class LiveIntervals;
class VirtRegMap;

class LLVM_LIBRARY_VISIBILITY LiveDebugVariables : public MachineFunctionPass {
class LiveDebugVariables : public MachineFunctionPass {
void *pImpl = nullptr;

public:
Expand Down Expand Up @@ -65,4 +65,4 @@ class LLVM_LIBRARY_VISIBILITY LiveDebugVariables : public MachineFunctionPass {

} // end namespace llvm

#endif // LLVM_LIB_CODEGEN_LIVEDEBUGVARIABLES_H
#endif // LLVM_CODEGEN_LIVEDEBUGVARIABLES_H
18 changes: 18 additions & 0 deletions llvm/include/llvm/CodeGen/LivePhysRegs.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@

namespace llvm {

template <typename T> class ArrayRef;

class MachineInstr;
class MachineFunction;
class MachineOperand;
Expand Down Expand Up @@ -207,6 +209,22 @@ static inline bool recomputeLiveIns(MachineBasicBlock &MBB) {
return oldLiveIns != newLiveIns;
}

/// Convenience function for recomputing live-in's for a set of MBBs until the
/// computation converges.
inline void fullyRecomputeLiveIns(ArrayRef<MachineBasicBlock *> MBBs) {
MachineBasicBlock *const *Data = MBBs.data();
const size_t Len = MBBs.size();
while (true) {
bool AnyChange = false;
for (size_t I = 0; I < Len; ++I)
if (recomputeLiveIns(*Data[I]))
AnyChange = true;
if (!AnyChange)
return;
}
}


} // end namespace llvm

#endif // LLVM_CODEGEN_LIVEPHYSREGS_H
5 changes: 5 additions & 0 deletions llvm/include/llvm/CodeGen/TargetLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -4873,6 +4873,11 @@ class TargetLowering : public TargetLoweringBase {
bool verifyReturnAddressArgumentIsConstant(SDValue Op,
SelectionDAG &DAG) const;

#ifndef NDEBUG
/// Check the given SDNode. Aborts if it is invalid.
virtual void verifyTargetSDNode(const SDNode *N) const {};
#endif

//===--------------------------------------------------------------------===//
// Inline Asm Support hooks
//
Expand Down
3 changes: 3 additions & 0 deletions llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,9 @@ class DWARFDebugNames : public DWARFAcceleratorTable {
/// Returns Hdr field
Header getHeader() const { return Hdr; }

/// Returns Offsets field
DWARFDebugNamesOffsets getOffsets() const { return Offsets; }

/// Reads offset of compilation unit CU. CU is 0-based.
uint64_t getCUOffset(uint32_t CU) const;
uint32_t getCUCount() const { return Hdr.CompUnitCount; }
Expand Down
2 changes: 1 addition & 1 deletion llvm/include/llvm/Frontend/OpenMP/ClauseT.h
Original file line number Diff line number Diff line change
Expand Up @@ -949,7 +949,7 @@ struct ReductionT {
using ReductionIdentifiers = ListT<type::ReductionIdentifierT<I, E>>;
ENUM(ReductionModifier, Default, Inscan, Task);
using TupleTrait = std::true_type;
std::tuple<ReductionIdentifiers, OPT(ReductionModifier), List> t;
std::tuple<OPT(ReductionModifier), ReductionIdentifiers, List> t;
};

// V5.2: [15.8.1] `memory-order` clauses
Expand Down
14 changes: 12 additions & 2 deletions llvm/include/llvm/IR/IRBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -2004,8 +2004,18 @@ class IRBuilderBase {
// Instruction creation methods: Cast/Conversion Operators
//===--------------------------------------------------------------------===//

Value *CreateTrunc(Value *V, Type *DestTy, const Twine &Name = "") {
return CreateCast(Instruction::Trunc, V, DestTy, Name);
Value *CreateTrunc(Value *V, Type *DestTy, const Twine &Name = "",
bool IsNUW = false, bool IsNSW = false) {
if (V->getType() == DestTy)
return V;
if (Value *Folded = Folder.FoldCast(Instruction::Trunc, V, DestTy))
return Folded;
Instruction *I = CastInst::Create(Instruction::Trunc, V, DestTy);
if (IsNUW)
I->setHasNoUnsignedWrap();
if (IsNSW)
I->setHasNoSignedWrap();
return Insert(I, Name);
}

Value *CreateZExt(Value *V, Type *DestTy, const Twine &Name = "",
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 @@ -57,4 +57,5 @@ let TargetPrefix = "spv" in {
def int_spv_create_handle : ClangBuiltin<"__builtin_hlsl_create_handle">,
Intrinsic<[ llvm_ptr_ty ], [llvm_i8_ty], [IntrWillReturn]>;
def int_spv_all : DefaultAttrsIntrinsic<[llvm_i1_ty], [llvm_any_ty]>;
def int_spv_any : DefaultAttrsIntrinsic<[llvm_i1_ty], [llvm_any_ty]>;
}
1 change: 1 addition & 0 deletions llvm/include/llvm/IR/Verifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ class TBAAVerifier {
/// Visit an instruction and return true if it is valid, return false if an
/// invalid TBAA is attached.
bool visitTBAAMetadata(Instruction &I, const MDNode *MD);
bool visitTBAAStructMetadata(Instruction &I, const MDNode *MD);
};

/// Check a function for errors, useful for use when debugging a
Expand Down
19 changes: 17 additions & 2 deletions llvm/include/llvm/Support/Endian.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ template <typename value_type, std::size_t alignment, typename CharT>
return ret;
}

template <typename value_type, endianness endian, std::size_t alignment,
typename CharT>
template <typename value_type, endianness endian,
std::size_t alignment = unaligned, typename CharT>
[[nodiscard]] inline value_type readNext(const CharT *&memory) {
return readNext<value_type, alignment, CharT>(memory, endian);
}
Expand All @@ -102,6 +102,21 @@ inline void write(void *memory, value_type value) {
write<value_type, alignment>(memory, value, endian);
}

/// Write a value of a particular endianness, and increment the buffer past that
/// value.
template <typename value_type, std::size_t alignment = unaligned,
typename CharT>
inline void writeNext(CharT *&memory, value_type value, endianness endian) {
write(memory, value, endian);
memory += sizeof(value_type);
}

template <typename value_type, endianness endian,
std::size_t alignment = unaligned, typename CharT>
inline void writeNext(CharT *&memory, value_type value) {
writeNext<value_type, alignment, CharT>(memory, value, endian);
}

template <typename value_type>
using make_unsigned_t = std::make_unsigned_t<value_type>;

Expand Down
9 changes: 3 additions & 6 deletions llvm/include/llvm/Support/OnDiskHashTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -368,14 +368,12 @@ template <typename Info> class OnDiskChainedHashTable {

// 'Items' starts with a 16-bit unsigned integer representing the
// number of items in this bucket.
unsigned Len =
endian::readNext<uint16_t, llvm::endianness::little, unaligned>(Items);
unsigned Len = endian::readNext<uint16_t, llvm::endianness::little>(Items);

for (unsigned i = 0; i < Len; ++i) {
// Read the hash.
hash_value_type ItemHash =
endian::readNext<hash_value_type, llvm::endianness::little,
unaligned>(Items);
endian::readNext<hash_value_type, llvm::endianness::little>(Items);

// Determine the length of the key and the data.
const std::pair<offset_type, offset_type> &L =
Expand Down Expand Up @@ -473,8 +471,7 @@ class OnDiskIterableChainedHashTable : public OnDiskChainedHashTable<Info> {
// 'Items' starts with a 16-bit unsigned integer representing the
// number of items in this bucket.
NumItemsInBucketLeft =
endian::readNext<uint16_t, llvm::endianness::little, unaligned>(
Ptr);
endian::readNext<uint16_t, llvm::endianness::little>(Ptr);
}
Ptr += sizeof(hash_value_type); // Skip the hash.
// Determine the length of the key and the data.
Expand Down
10 changes: 8 additions & 2 deletions llvm/include/llvm/Target/GlobalISel/Combine.td
Original file line number Diff line number Diff line change
Expand Up @@ -443,14 +443,20 @@ def select_constant_cmp: GICombineRule<
// TODO: handle compares (currently not marked as isCommutable)
def commute_int_constant_to_rhs : GICombineRule<
(defs root:$root),
(match (wip_match_opcode G_ADD, G_MUL, G_AND, G_OR, G_XOR):$root,
(match (wip_match_opcode G_ADD, G_MUL, G_AND, G_OR, G_XOR,
G_SMIN, G_SMAX, G_UMIN, G_UMAX, G_UADDO, G_SADDO,
G_UMULO, G_SMULO, G_UMULH, G_SMULH,
G_UADDSAT, G_SADDSAT, G_SMULFIX, G_UMULFIX,
G_SMULFIXSAT, G_UMULFIXSAT):$root,
[{ return Helper.matchCommuteConstantToRHS(*${root}); }]),
(apply [{ Helper.applyCommuteBinOpOperands(*${root}); }])
>;

def commute_fp_constant_to_rhs : GICombineRule<
(defs root:$root),
(match (wip_match_opcode G_FADD, G_FMUL):$root,
(match (wip_match_opcode G_FADD, G_FMUL, G_FMINNUM, G_FMAXNUM,
G_FMINNUM_IEEE, G_FMAXNUM_IEEE,
G_FMINIMUM, G_FMAXIMUM):$root,
[{ return Helper.matchCommuteFPConstantToRHS(*${root}); }]),
(apply [{ Helper.applyCommuteBinOpOperands(*${root}); }])
>;
Expand Down
Loading