277 changes: 163 additions & 114 deletions libclc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ project( libclc VERSION 0.2.0 LANGUAGES CXX C)

set(CMAKE_CXX_STANDARD 17)

# Add path for custom modules
list( INSERT CMAKE_MODULE_PATH 0 "${PROJECT_SOURCE_DIR}/cmake/modules" )

set( LIBCLC_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} )
set( LIBCLC_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR} )
set( LIBCLC_OBJFILE_DIR ${LIBCLC_BINARY_DIR}/obj.libclc.dir )

include( AddLibclc )

include( GNUInstallDirs )
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS
amdgcn-amdhsa/lib/SOURCES;
Expand All @@ -27,31 +36,51 @@ set( LIBCLC_TARGETS_TO_BUILD "all"

option( ENABLE_RUNTIME_SUBNORMAL "Enable runtime linking of subnormal support." OFF )

find_package(LLVM REQUIRED HINTS "${LLVM_CMAKE_DIR}")
include(AddLLVM)
if( LIBCLC_STANDALONE_BUILD OR CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR )
# Out-of-tree configuration
set( LIBCLC_STANDALONE_BUILD TRUE )

message( STATUS "libclc LLVM version: ${LLVM_PACKAGE_VERSION}" )
find_package(LLVM REQUIRED HINTS "${LLVM_CMAKE_DIR}")
include(AddLLVM)

if( LLVM_PACKAGE_VERSION VERSION_LESS LIBCLC_MIN_LLVM )
message( FATAL_ERROR "libclc needs at least LLVM ${LIBCLC_MIN_LLVM}" )
endif()
message( STATUS "libclc LLVM version: ${LLVM_PACKAGE_VERSION}" )

find_program( LLVM_CLANG clang PATHS ${LLVM_TOOLS_BINARY_DIR} NO_DEFAULT_PATH )
find_program( LLVM_AS llvm-as PATHS ${LLVM_TOOLS_BINARY_DIR} NO_DEFAULT_PATH )
find_program( LLVM_LINK llvm-link PATHS ${LLVM_TOOLS_BINARY_DIR} NO_DEFAULT_PATH )
find_program( LLVM_OPT opt PATHS ${LLVM_TOOLS_BINARY_DIR} NO_DEFAULT_PATH )
find_program( LLVM_SPIRV llvm-spirv PATHS ${LLVM_TOOLS_BINARY_DIR} NO_DEFAULT_PATH )
if( LLVM_PACKAGE_VERSION VERSION_LESS LIBCLC_MIN_LLVM )
message( FATAL_ERROR "libclc needs at least LLVM ${LIBCLC_MIN_LLVM}" )
endif()

# Import required tools as targets
foreach( tool clang llvm-as llvm-link opt )
find_program( LLVM_TOOL_${tool} ${tool} PATHS ${LLVM_TOOLS_BINARY_DIR} NO_DEFAULT_PATH )
add_executable( libclc::${tool} IMPORTED GLOBAL )
set_target_properties( libclc::${tool} PROPERTIES IMPORTED_LOCATION ${LLVM_TOOL_${tool}} )
endforeach()
else()
# In-tree configuration
set( LIBCLC_STANDALONE_BUILD FALSE )

set( LLVM_PACKAGE_VERSION ${LLVM_VERSION} )

# Print toolchain
message( STATUS "libclc toolchain - clang: ${LLVM_CLANG}" )
message( STATUS "libclc toolchain - llvm-as: ${LLVM_AS}" )
message( STATUS "libclc toolchain - llvm-link: ${LLVM_LINK}" )
message( STATUS "libclc toolchain - opt: ${LLVM_OPT}" )
message( STATUS "libclc toolchain - llvm-spirv: ${LLVM_SPIRV}" )
if( NOT LLVM_CLANG OR NOT LLVM_OPT OR NOT LLVM_AS OR NOT LLVM_LINK )
# Note that we check this later (for both build types) but we can provide a
# more useful error message when built in-tree. We assume that LLVM tools are
# always available so don't warn here.
if( NOT clang IN_LIST LLVM_ENABLE_PROJECTS )
message(FATAL_ERROR "Clang is not enabled, but is required to build libclc in-tree")
endif()

foreach( tool clang llvm-as llvm-link opt )
add_executable(libclc::${tool} ALIAS ${tool})
endforeach()
endif()

if( NOT TARGET libclc::clang OR NOT TARGET libclc::opt
OR NOT TARGET libclc::llvm-as OR NOT TARGET libclc::llvm-link )
message( FATAL_ERROR "libclc toolchain incomplete!" )
endif()

# llvm-spirv is an optional dependency, used to build spirv-* targets.
find_program( LLVM_SPIRV llvm-spirv PATHS ${LLVM_TOOLS_BINARY_DIR} NO_DEFAULT_PATH )

# List of all targets. Note that some are added dynamically below.
set( LIBCLC_TARGETS_ALL
amdgcn--
Expand Down Expand Up @@ -90,24 +119,9 @@ if( "spirv-mesa3d-" IN_LIST LIBCLC_TARGETS_TO_BUILD OR "spirv64-mesa3d-" IN_LIST
endif()
endif()

set( CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake )
set( CMAKE_CLC_COMPILER ${LLVM_CLANG} )
set( CMAKE_CLC_ARCHIVE ${LLVM_LINK} )
set( CMAKE_LLAsm_PREPROCESSOR ${LLVM_CLANG} )
set( CMAKE_LLAsm_COMPILER ${LLVM_AS} )
set( CMAKE_LLAsm_ARCHIVE ${LLVM_LINK} )

# Construct LLVM version define
set( LLVM_VERSION_DEFINE "-DHAVE_LLVM=0x${LLVM_VERSION_MAJOR}0${LLVM_VERSION_MINOR}" )


# LLVM 13 enables standard includes by default
if( LLVM_PACKAGE_VERSION VERSION_GREATER_EQUAL 13.0.0 )
set( CMAKE_LLAsm_FLAGS "${CMAKE_LLAsm_FLAGS} -cl-no-stdinc" )
set( CMAKE_CLC_FLAGS "${CMAKE_CLC_FLAGS} -cl-no-stdinc" )
endif()

enable_language( CLC LLAsm )
# This needs to be set before any target that needs it
# We need to use LLVM_INCLUDE_DIRS here, because if we are linking to an
# llvm build directory, this includes $src/llvm/include which is where all the
Expand All @@ -122,7 +136,7 @@ set(LLVM_LINK_COMPONENTS
IRReader
Support
)
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
if( LIBCLC_STANDALONE_BUILD )
add_llvm_executable( prepare_builtins utils/prepare-builtins.cpp )
else()
add_llvm_utility( prepare_builtins utils/prepare-builtins.cpp )
Expand Down Expand Up @@ -167,12 +181,14 @@ install( FILES ${CMAKE_CURRENT_BINARY_DIR}/libclc.pc DESTINATION "${CMAKE_INSTAL
install( DIRECTORY generic/include/clc DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" )

if( ENABLE_RUNTIME_SUBNORMAL )
add_library( subnormal_use_default STATIC
generic/lib/subnormal_use_default.ll )
add_library( subnormal_disable STATIC
generic/lib/subnormal_disable.ll )
install( TARGETS subnormal_use_default subnormal_disable ARCHIVE
DESTINATION "${CMAKE_INSTALL_DATADIR}/clc" )
foreach( file subnormal_use_default subnormal_disable )
link_bc(
TARGET ${file}
INPUTS ${PROJECT_SOURCE_DIR}/generic/lib/${file}.ll
)
install( FILES $<TARGET_PROPERTY:${file},TARGET_FILE> ARCHIVE
DESTINATION "${CMAKE_INSTALL_DATADIR}/clc" )
endforeach()
endif()

find_package( Python3 REQUIRED COMPONENTS Interpreter )
Expand Down Expand Up @@ -232,131 +248,164 @@ foreach( t ${LIBCLC_TARGETS_TO_BUILD} )

# Add the generated convert.cl here to prevent adding the one listed in
# SOURCES
set( objects ) # A "set" of already-added input files
set( rel_files ) # Source directory input files, relative to the root dir
set( gen_files ) # Generated binary input files, relative to the binary dir
if( NOT ${ARCH} STREQUAL "spirv" AND NOT ${ARCH} STREQUAL "spirv64" )
if( NOT ENABLE_RUNTIME_SUBNORMAL AND NOT ${ARCH} STREQUAL "clspv" AND
NOT ${ARCH} STREQUAL "clspv64" )
set( rel_files convert.cl )
set( objects convert.cl )
list( APPEND gen_files convert.cl )
list( APPEND objects convert.cl )
list( APPEND rel_files generic/lib/subnormal_use_default.ll )
elseif(${ARCH} STREQUAL "clspv" OR ${ARCH} STREQUAL "clspv64")
set( rel_files clspv-convert.cl )
set( objects clspv-convert.cl )
list( APPEND gen_files clspv-convert.cl )
list( APPEND objects clspv-convert.cl )
endif()
else()
set( rel_files )
set( objects )
endif()

foreach( l ${source_list} )
file( READ ${l} file_list )
string( REPLACE "\n" ";" file_list ${file_list} )
get_filename_component( dir ${l} DIRECTORY )
foreach( f ${file_list} )
list( FIND objects ${f} found )
if( found EQUAL -1 )
# Only add each file once, so that targets can 'specialize' builtins
if( NOT ${f} IN_LIST objects )
list( APPEND objects ${f} )
list( APPEND rel_files ${dir}/${f} )
# FIXME: This should really go away
file( TO_CMAKE_PATH ${PROJECT_SOURCE_DIR}/${dir}/${f} src_loc )
get_filename_component( fdir ${src_loc} DIRECTORY )

set_source_files_properties( ${dir}/${f}
PROPERTIES COMPILE_FLAGS "-I ${fdir}" )
endif()
endforeach()
endforeach()

foreach( d ${${t}_devices} )
# Some targets don't have a specific GPU to target
if( ${d} STREQUAL "none" OR ${ARCH} STREQUAL "spirv" OR ${ARCH} STREQUAL "spirv64" )
set( mcpu )
set( arch_suffix "${t}" )
else()
set( mcpu "-mcpu=${d}" )
set( arch_suffix "${d}-${t}" )
get_libclc_device_info(
TRIPLE ${t}
DEVICE ${d}
CPU cpu
ARCH_SUFFIX arch_suffix
CLANG_TRIPLE clang_triple
)

set( mcpu )
if( NOT "${cpu}" STREQUAL "" )
set( mcpu "-mcpu=${cpu}" )
endif()

message( STATUS " device: ${d} ( ${${d}_aliases} )" )

if ( ${ARCH} STREQUAL "spirv" OR ${ARCH} STREQUAL "spirv64" )
if( ${ARCH} STREQUAL "spirv" )
set( t "spir--" )
else()
set( t "spir64--" )
endif()
if ( ARCH STREQUAL spirv OR ARCH STREQUAL spirv64 )
set( build_flags -O0 -finline-hint-functions )
set( opt_flags )
set( spvflags --spirv-max-version=1.1 )
elseif( ${ARCH} STREQUAL "clspv" )
set( t "spir--" )
set( build_flags "-Wno-unknown-assumption")
set( opt_flags -O3 )
elseif( ${ARCH} STREQUAL "clspv64" )
set( t "spir64--" )
elseif( ARCH STREQUAL clspv OR ARCH STREQUAL clspv64 )
set( build_flags "-Wno-unknown-assumption")
set( opt_flags -O3 )
else()
set( build_flags )
set( opt_flags -O3 )
endif()

set( LIBCLC_ARCH_OBJFILE_DIR "${LIBCLC_OBJFILE_DIR}/${arch_suffix}" )
file( MAKE_DIRECTORY ${LIBCLC_ARCH_OBJFILE_DIR} )

string( TOUPPER "CLC_${ARCH}" CLC_TARGET_DEFINE )

list( APPEND build_flags
-D__CLC_INTERNAL
-D${CLC_TARGET_DEFINE}
-I${PROJECT_SOURCE_DIR}/generic/include
# FIXME: Fix libclc to not require disabling this noisy warning
-Wno-bitwise-conditional-parentheses
)

set( bytecode_files "" )
foreach( file IN LISTS gen_files rel_files )
# We need to take each file and produce an absolute input file, as well
# as a unique architecture-specific output file. We deal with a mix of
# different input files, which makes this trickier.
if( ${file} IN_LIST gen_files )
# Generated files are given just as file names, which we must make
# absolute to the binary directory.
set( input_file ${CMAKE_CURRENT_BINARY_DIR}/${file} )
set( output_file "${LIBCLC_ARCH_OBJFILE_DIR}/${file}.o" )
else()
# Other files are originally relative to each SOURCE file, which are
# then make relative to the libclc root directory. We must normalize
# the path (e.g., ironing out any ".."), then make it relative to the
# root directory again, and use that relative path component for the
# binary path.
get_filename_component( abs_path ${file} ABSOLUTE BASE_DIR ${PROJECT_SOURCE_DIR} )
file( RELATIVE_PATH root_rel_path ${PROJECT_SOURCE_DIR} ${abs_path} )
set( input_file ${PROJECT_SOURCE_DIR}/${file} )
set( output_file "${LIBCLC_ARCH_OBJFILE_DIR}/${root_rel_path}.o" )
endif()

get_filename_component( file_dir ${file} DIRECTORY )

compile_to_bc(
TRIPLE ${clang_triple}
INPUT ${input_file}
OUTPUT ${output_file}
EXTRA_OPTS "${mcpu}" -fno-builtin -nostdlib
"${build_flags}" -I${PROJECT_SOURCE_DIR}/${file_dir}
)
list( APPEND bytecode_files ${output_file} )
endforeach()

set( builtins_link_lib_tgt builtins.link.${arch_suffix} )
add_library( ${builtins_link_lib_tgt} STATIC ${rel_files} )
# Make sure we depend on the pseudo target to prevent
# multiple invocations
add_dependencies( ${builtins_link_lib_tgt} generate_convert.cl )
add_dependencies( ${builtins_link_lib_tgt} clspv-generate_convert.cl )
# CMake will turn this include into absolute path
target_include_directories( ${builtins_link_lib_tgt} PRIVATE
"generic/include" )
target_compile_definitions( ${builtins_link_lib_tgt} PRIVATE
"__CLC_INTERNAL" )
string( TOUPPER "-DCLC_${ARCH}" CLC_TARGET_DEFINE )
target_compile_definitions( ${builtins_link_lib_tgt} PRIVATE
${CLC_TARGET_DEFINE} )
target_compile_options( ${builtins_link_lib_tgt} PRIVATE -target
${t} ${mcpu} -fno-builtin -nostdlib ${build_flags} )
set_target_properties( ${builtins_link_lib_tgt} PROPERTIES
LINKER_LANGUAGE CLC )

set( obj_suffix ${arch_suffix}.bc )
set( builtins_opt_lib_tgt builtins.opt.${obj_suffix} )

# Add opt target
add_custom_command( OUTPUT ${builtins_opt_lib_tgt}
COMMAND ${LLVM_OPT} ${opt_flags} -o ${builtins_opt_lib_tgt}
$<TARGET_FILE:${builtins_link_lib_tgt}>
DEPENDS ${builtins_link_lib_tgt} )
add_custom_target( "opt.${obj_suffix}" ALL
DEPENDS ${builtins_opt_lib_tgt} )

if( ${ARCH} STREQUAL "spirv" OR ${ARCH} STREQUAL "spirv64" )

link_bc(
TARGET ${builtins_link_lib_tgt}
INPUTS ${bytecode_files}
)

set( builtins_link_lib $<TARGET_PROPERTY:${builtins_link_lib_tgt},TARGET_FILE> )

if( ARCH STREQUAL spirv OR ARCH STREQUAL spirv64 )
set( spv_suffix ${arch_suffix}.spv )
add_custom_command( OUTPUT "${spv_suffix}"
COMMAND ${LLVM_SPIRV} ${spvflags} -o "${spv_suffix}" $<TARGET_FILE:${builtins_link_lib_tgt}>
DEPENDS ${builtins_link_lib_tgt} )
add_custom_command( OUTPUT ${spv_suffix}
COMMAND ${LLVM_SPIRV} ${spvflags} -o ${spv_suffix} ${builtins_link_lib}
DEPENDS ${builtins_link_lib_tgt}
)
add_custom_target( "prepare-${spv_suffix}" ALL DEPENDS "${spv_suffix}" )
install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${spv_suffix}
DESTINATION "${CMAKE_INSTALL_DATADIR}/clc" )
else()
set( builtins_opt_lib_tgt builtins.opt.${arch_suffix} )

# Add opt target
add_custom_command( OUTPUT ${builtins_opt_lib_tgt}.bc
COMMAND libclc::opt ${opt_flags} -o ${builtins_opt_lib_tgt}.bc
${builtins_link_lib}
DEPENDS libclc::opt ${builtins_link_lib_tgt}
)
add_custom_target( ${builtins_opt_lib_tgt}
ALL DEPENDS ${builtins_opt_lib_tgt}.bc
)
set_target_properties( ${builtins_opt_lib_tgt}
PROPERTIES TARGET_FILE ${builtins_opt_lib_tgt}.bc
)

# Add prepare target
add_custom_command( OUTPUT "${obj_suffix}"
COMMAND prepare_builtins -o "${obj_suffix}" ${builtins_opt_lib_tgt}
DEPENDS "opt.${obj_suffix}" ${builtins_opt_lib_tgt} prepare_builtins )
add_custom_target( "prepare-${obj_suffix}" ALL DEPENDS "${obj_suffix}" )
set( obj_suffix ${arch_suffix}.bc )
add_custom_command( OUTPUT ${obj_suffix}
COMMAND prepare_builtins -o ${obj_suffix}
$<TARGET_PROPERTY:${builtins_opt_lib_tgt},TARGET_FILE>
DEPENDS ${builtins_opt_lib_tgt} prepare_builtins )
add_custom_target( prepare-${obj_suffix} ALL DEPENDS ${obj_suffix} )

# nvptx-- targets don't include workitem builtins
if( NOT ${t} MATCHES ".*ptx.*--$" )
if( NOT clang_triple MATCHES ".*ptx.*--$" )
add_test( NAME external-calls-${obj_suffix}
COMMAND ./check_external_calls.sh ${CMAKE_CURRENT_BINARY_DIR}/${obj_suffix} ${LLVM_TOOLS_BINARY_DIR}
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} )
endif()

install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${obj_suffix} DESTINATION "${CMAKE_INSTALL_DATADIR}/clc" )
foreach( a ${${d}_aliases} )
set( alias_suffix "${a}-${t}.bc" )
set( alias_suffix "${a}-${clang_triple}.bc" )
add_custom_target( ${alias_suffix} ALL
COMMAND ${CMAKE_COMMAND} -E create_symlink ${obj_suffix} ${alias_suffix}
DEPENDS "prepare-${obj_suffix}" )
DEPENDS prepare-${obj_suffix} )
install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${alias_suffix} DESTINATION "${CMAKE_INSTALL_DATADIR}/clc" )
endforeach( a )
endif()
Expand Down
9 changes: 0 additions & 9 deletions libclc/cmake/CMakeCLCCompiler.cmake.in

This file was deleted.

12 changes: 0 additions & 12 deletions libclc/cmake/CMakeCLCInformation.cmake

This file was deleted.

18 changes: 0 additions & 18 deletions libclc/cmake/CMakeDetermineCLCCompiler.cmake

This file was deleted.

24 changes: 0 additions & 24 deletions libclc/cmake/CMakeDetermineLLAsmCompiler.cmake

This file was deleted.

10 changes: 0 additions & 10 deletions libclc/cmake/CMakeLLAsmCompiler.cmake.in

This file was deleted.

12 changes: 0 additions & 12 deletions libclc/cmake/CMakeLLAsmInformation.cmake

This file was deleted.

56 changes: 0 additions & 56 deletions libclc/cmake/CMakeTestCLCCompiler.cmake

This file was deleted.

56 changes: 0 additions & 56 deletions libclc/cmake/CMakeTestLLAsmCompiler.cmake

This file was deleted.

156 changes: 156 additions & 0 deletions libclc/cmake/modules/AddLibclc.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
# Compiles an OpenCL C - or assembles an LL file - to bytecode
#
# Arguments:
# * TRIPLE <string>
# Target triple for which to compile the bytecode file.
# * INPUT <string>
# File to compile/assemble to bytecode
# * OUTPUT <string>
# Bytecode file to generate
# * EXTRA_OPTS <string> ...
# List of compiler options to use. Note that some are added by default.
# * DEPENDENCIES <string> ...
# List of extra dependencies to inject
#
# Depends on the libclc::clang and libclc::llvm-as targets for compiling and
# assembling, respectively.
function(compile_to_bc)
cmake_parse_arguments(ARG
""
"TRIPLE;INPUT;OUTPUT"
"EXTRA_OPTS;DEPENDENCIES"
${ARGN}
)

# If this is an LLVM IR file (identified soley by its file suffix),
# pre-process it with clang to a temp file, then assemble that to bytecode.
set( TMP_SUFFIX )
get_filename_component( FILE_EXT ${ARG_INPUT} EXT )
if( NOT ${FILE_EXT} STREQUAL ".ll" )
# Pass '-c' when not running the preprocessor
set( PP_OPTS -c )
else()
set( PP_OPTS -E;-P )
set( TMP_SUFFIX .tmp )
endif()

set( TARGET_ARG )
if( ARG_TRIPLE )
set( TARGET_ARG "-target" ${ARG_TRIPLE} )
endif()

add_custom_command(
OUTPUT ${ARG_OUTPUT}${TMP_SUFFIX}
COMMAND libclc::clang
${TARGET_ARG}
${PP_OPTS}
${ARG_EXTRA_OPTS}
-MD -MF ${ARG_OUTPUT}.d -MT ${ARG_OUTPUT}${TMP_SUFFIX}
# LLVM 13 enables standard includes by default - we don't want
# those when pre-processing IR. We disable it unconditionally.
$<$<VERSION_GREATER_EQUAL:${LLVM_PACKAGE_VERSION},13.0.0>:-cl-no-stdinc>
-emit-llvm
-o ${ARG_OUTPUT}${TMP_SUFFIX}
-x cl
${ARG_INPUT}
DEPENDS
libclc::clang
${ARG_INPUT}
${ARG_DEPENDENCIES}
DEPFILE ${ARG_OUTPUT}.d
)

if( ${FILE_EXT} STREQUAL ".ll" )
add_custom_command(
OUTPUT ${ARG_OUTPUT}
COMMAND libclc::llvm-as -o ${ARG_OUTPUT} ${ARG_OUTPUT}${TMP_SUFFIX}
DEPENDS libclc::llvm-as ${ARG_OUTPUT}${TMP_SUFFIX}
)
endif()
endfunction()

# Links together one or more bytecode files
#
# Arguments:
# * TARGET <string>
# Custom target to create
# * INPUT <string> ...
# List of bytecode files to link together
function(link_bc)
cmake_parse_arguments(ARG
""
"TARGET"
"INPUTS"
${ARGN}
)

add_custom_command(
OUTPUT ${ARG_TARGET}.bc
COMMAND libclc::llvm-link -o ${ARG_TARGET}.bc ${ARG_INPUTS}
DEPENDS libclc::llvm-link ${ARG_INPUTS}
)

add_custom_target( ${ARG_TARGET} ALL DEPENDS ${ARG_TARGET}.bc )
set_target_properties( ${ARG_TARGET} PROPERTIES TARGET_FILE ${ARG_TARGET}.bc )
endfunction()

# Decomposes and returns variables based on a libclc triple and architecture
# combination. Returns data via one or more optional output variables.
#
# Arguments:
# * TRIPLE <string>
# libclc target triple to query
# * DEVICE <string>
# libclc device to query
#
# Optional Arguments:
# * CPU <var>
# Variable name to be set to the target CPU
# * ARCH_SUFFIX <var>
# Variable name to be set to the triple/architecture suffix
# * CLANG_TRIPLE <var>
# Variable name to be set to the normalized clang triple
function(get_libclc_device_info)
cmake_parse_arguments(ARG
""
"TRIPLE;DEVICE;CPU;ARCH_SUFFIX;CLANG_TRIPLE"
""
${ARGN}
)

if( NOT ARG_TRIPLE OR NOT ARG_DEVICE )
message( FATAL_ERROR "Must provide both TRIPLE and DEVICE" )
endif()

string( REPLACE "-" ";" TRIPLE ${ARG_TRIPLE} )
list( GET TRIPLE 0 ARCH )

# Some targets don't have a specific device architecture to target
if( ARG_DEVICE STREQUAL none OR ARCH STREQUAL spirv OR ARCH STREQUAL spirv64 )
set( cpu )
set( arch_suffix "${ARG_TRIPLE}" )
else()
set( cpu "${ARG_DEVICE}" )
set( arch_suffix "${ARG_DEVICE}-${ARG_TRIPLE}" )
endif()

if( ARG_CPU )
set( ${ARG_CPU} ${cpu} PARENT_SCOPE )
endif()

if( ARG_ARCH_SUFFIX )
set( ${ARG_ARCH_SUFFIX} ${arch_suffix} PARENT_SCOPE )
endif()

# Some libclc targets are not real clang triples: return their canonical
# triples.
if( ARCH STREQUAL spirv OR ARCH STREQUAL clspv )
set( ARG_TRIPLE "spir--" )
elseif( ARCH STREQUAL spirv64 OR ARCH STREQUAL clspv64 )
set( ARG_TRIPLE "spir64--" )
endif()

if( ARG_CLANG_TRIPLE )
set( ${ARG_CLANG_TRIPLE} ${ARG_TRIPLE} PARENT_SCOPE )
endif()
endfunction()
1 change: 0 additions & 1 deletion libclc/generic/lib/SOURCES
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ cl_khr_int64_extended_atomics/atom_max.cl
cl_khr_int64_extended_atomics/atom_min.cl
cl_khr_int64_extended_atomics/atom_or.cl
cl_khr_int64_extended_atomics/atom_xor.cl
convert.cl
common/degrees.cl
common/mix.cl
common/radians.cl
Expand Down
11 changes: 11 additions & 0 deletions libcxx/include/__bit/countl.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
//
//===----------------------------------------------------------------------===//

// TODO: __builtin_clzg is available since Clang 19 and GCC 14. When support for older versions is dropped, we can
// refactor this code to exclusively use __builtin_clzg.

#ifndef _LIBCPP___BIT_COUNTL_H
#define _LIBCPP___BIT_COUNTL_H

Expand Down Expand Up @@ -38,6 +41,9 @@ _LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_cl

#ifndef _LIBCPP_HAS_NO_INT128
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_clz(__uint128_t __x) _NOEXCEPT {
# if __has_builtin(__builtin_clzg)
return __builtin_clzg(__x);
# else
// The function is written in this form due to C++ constexpr limitations.
// The algorithm:
// - Test whether any bit in the high 64-bits is set
Expand All @@ -49,12 +55,16 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_clz(__uint128_t __x)
// zeros in the high 64-bits.
return ((__x >> 64) == 0) ? (64 + __builtin_clzll(static_cast<unsigned long long>(__x)))
: __builtin_clzll(static_cast<unsigned long long>(__x >> 64));
# endif
}
#endif // _LIBCPP_HAS_NO_INT128

template <class _Tp>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __countl_zero(_Tp __t) _NOEXCEPT {
static_assert(__libcpp_is_unsigned_integer<_Tp>::value, "__countl_zero requires an unsigned integer type");
#if __has_builtin(__builtin_clzg)
return __builtin_clzg(__t, numeric_limits<_Tp>::digits);
#else // __has_builtin(__builtin_clzg)
if (__t == 0)
return numeric_limits<_Tp>::digits;

Expand All @@ -79,6 +89,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __countl_zero(_Tp __t) _
}
return __ret + __iter;
}
#endif // __has_builtin(__builtin_clzg)
}

#if _LIBCPP_STD_VER >= 20
Expand Down
8 changes: 7 additions & 1 deletion libcxx/include/__bit/countr.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
//
//===----------------------------------------------------------------------===//

// TODO: __builtin_ctzg is available since Clang 19 and GCC 14. When support for older versions is dropped, we can
// refactor this code to exclusively use __builtin_ctzg.

#ifndef _LIBCPP___BIT_COUNTR_H
#define _LIBCPP___BIT_COUNTR_H

Expand Down Expand Up @@ -37,9 +40,11 @@ _LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_ct

template <class _Tp>
_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __countr_zero(_Tp __t) _NOEXCEPT {
#if __has_builtin(__builtin_ctzg)
return __builtin_ctzg(__t, numeric_limits<_Tp>::digits);
#else // __has_builtin(__builtin_ctzg)
if (__t == 0)
return numeric_limits<_Tp>::digits;

if (sizeof(_Tp) <= sizeof(unsigned int))
return std::__libcpp_ctz(static_cast<unsigned int>(__t));
else if (sizeof(_Tp) <= sizeof(unsigned long))
Expand All @@ -55,6 +60,7 @@ _LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __coun
}
return __ret + std::__libcpp_ctz(static_cast<unsigned long long>(__t));
}
#endif // __has_builtin(__builtin_ctzg)
}

#if _LIBCPP_STD_VER >= 20
Expand Down
7 changes: 7 additions & 0 deletions libcxx/include/__bit/popcount.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
//
//===----------------------------------------------------------------------===//

// TODO: __builtin_popcountg is available since Clang 19 and GCC 14. When support for older versions is dropped, we can
// refactor this code to exclusively use __builtin_popcountg.

#ifndef _LIBCPP___BIT_POPCOUNT_H
#define _LIBCPP___BIT_POPCOUNT_H

Expand Down Expand Up @@ -39,6 +42,9 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_popcount(unsigned lo

template <__libcpp_unsigned_integer _Tp>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr int popcount(_Tp __t) noexcept {
# if __has_builtin(__builtin_popcountg)
return __builtin_popcountg(__t);
# else // __has_builtin(__builtin_popcountg)
if (sizeof(_Tp) <= sizeof(unsigned int))
return std::__libcpp_popcount(static_cast<unsigned int>(__t));
else if (sizeof(_Tp) <= sizeof(unsigned long))
Expand All @@ -53,6 +59,7 @@ _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr int popcount(_Tp __t) noex
}
return __ret;
}
# endif // __has_builtin(__builtin_popcountg)
}

#endif // _LIBCPP_STD_VER >= 20
Expand Down
28 changes: 16 additions & 12 deletions libcxx/include/__type_traits/copy_cv.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,28 +19,32 @@ _LIBCPP_BEGIN_NAMESPACE_STD

// Let COPYCV(FROM, TO) be an alias for type TO with the addition of FROM's
// top-level cv-qualifiers.
template <class _From, class _To>
template <class _From>
struct __copy_cv {
using type = _To;
template <class _To>
using __apply = _To;
};

template <class _From, class _To>
struct __copy_cv<const _From, _To> {
using type = const _To;
template <class _From>
struct __copy_cv<const _From> {
template <class _To>
using __apply = const _To;
};

template <class _From, class _To>
struct __copy_cv<volatile _From, _To> {
using type = volatile _To;
template <class _From>
struct __copy_cv<volatile _From> {
template <class _To>
using __apply = volatile _To;
};

template <class _From, class _To>
struct __copy_cv<const volatile _From, _To> {
using type = const volatile _To;
template <class _From>
struct __copy_cv<const volatile _From> {
template <class _To>
using __apply = const volatile _To;
};

template <class _From, class _To>
using __copy_cv_t = typename __copy_cv<_From, _To>::type;
using __copy_cv_t = typename __copy_cv<_From>::template __apply<_To>;

_LIBCPP_END_NAMESPACE_STD

Expand Down
8 changes: 4 additions & 4 deletions libcxx/include/stddef.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,17 @@

#include <__config>

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

// Note: This include is outside of header guards because we sometimes get included multiple times
// with different defines and the underlying <stddef.h> will know how to deal with that.
#include_next <stddef.h>

#ifndef _LIBCPP_STDDEF_H
# define _LIBCPP_STDDEF_H

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

# ifdef __cplusplus
typedef decltype(nullptr) nullptr_t;
# endif
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,14 @@ concept is_in_value_result =
template <class Result, class T>
concept is_dangling_with = std::same_as<Result, std::ranges::fold_left_with_iter_result<std::ranges::dangling, T>>;

struct Long {
struct Integer {
int value;

constexpr Long(int const x) : value(x) {}
constexpr Integer(int const x) : value(x) {}

constexpr Long plus(int const x) const { return Long{value + x}; }
constexpr Integer plus(int const x) const { return Integer{value + x}; }

friend constexpr bool operator==(Long const& x, Long const& y) = default;
friend constexpr bool operator==(Integer const& x, Integer const& y) = default;
};

template <std::ranges::input_range R, class T, class F, std::equality_comparable Expected>
Expand All @@ -77,6 +77,7 @@ constexpr void check_iterator(R& r, T const& init, F f, Expected const& expected
assert(result.in == r.end());
assert(result.value == expected);
}

{
auto telemetry = invocable_telemetry();
auto f2 = invocable_with_telemetry(f, telemetry);
Expand All @@ -92,6 +93,7 @@ constexpr void check_iterator(R& r, T const& init, F f, Expected const& expected
std::same_as<Expected> decltype(auto) result = fold_left(r.begin(), r.end(), init, f);
assert(result == expected);
}

{
auto telemetry = invocable_telemetry();
auto f2 = invocable_with_telemetry(f, telemetry);
Expand All @@ -111,6 +113,7 @@ constexpr void check_lvalue_range(R& r, T const& init, F f, Expected const& expe
assert(result.in == r.end());
assert(result.value == expected);
}

{
auto telemetry = invocable_telemetry();
auto f2 = invocable_with_telemetry(f, telemetry);
Expand All @@ -125,6 +128,7 @@ constexpr void check_lvalue_range(R& r, T const& init, F f, Expected const& expe
std::same_as<Expected> decltype(auto) result = fold_left(r, init, f);
assert(result == expected);
}

{
auto telemetry = invocable_telemetry();
auto f2 = invocable_with_telemetry(f, telemetry);
Expand All @@ -144,6 +148,7 @@ constexpr void check_rvalue_range(R& r, T const& init, F f, Expected const& expe
is_dangling_with<Expected> decltype(auto) result = fold_left_with_iter(std::move(r2), init, f);
assert(result.value == expected);
}

{
auto telemetry = invocable_telemetry();
auto f2 = invocable_with_telemetry(f, telemetry);
Expand All @@ -160,6 +165,7 @@ constexpr void check_rvalue_range(R& r, T const& init, F f, Expected const& expe
std::same_as<Expected> decltype(auto) result = fold_left(std::move(r2), init, f);
assert(result == expected);
}

{
auto telemetry = invocable_telemetry();
auto f2 = invocable_with_telemetry(f, telemetry);
Expand All @@ -186,7 +192,7 @@ constexpr void empty_range_test_case() {
check(data, -100, std::multiplies(), -100);

check(data | std::views::take_while([](auto) { return false; }), 1.23, std::plus(), 1.23);
check(data, Long(52), &Long::plus, Long(52));
check(data, Integer(52), &Integer::plus, Integer(52));
}

constexpr void common_range_test_case() {
Expand All @@ -209,7 +215,7 @@ constexpr void common_range_test_case() {
};
check(data, 0, fib, fibonacci(data.back()));

check(data, Long(0), &Long::plus, Long(triangular_sum(data)));
check(data, Integer(0), &Integer::plus, Integer(triangular_sum(data)));
}

constexpr void non_common_range_test_case() {
Expand Down Expand Up @@ -269,6 +275,7 @@ void runtime_only_test_case() {
assert(result.in == data.end());
assert(result.value == expected);
}

{
auto input = std::istringstream(raw_data);
auto data = std::views::istream<std::string>(input);
Expand All @@ -277,11 +284,13 @@ void runtime_only_test_case() {
assert(result.in == data.end());
assert(result.value == expected);
}

{
auto input = std::istringstream(raw_data);
auto data = std::views::istream<std::string>(input);
assert(fold_left(data.begin(), data.end(), init, std::plus()) == expected);
}

{
auto input = std::istringstream(raw_data);
auto data = std::views::istream<std::string>(input);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,21 @@

// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20

// Checks that `std::ranges::fold_left_with_iter`'s requirements reject parameters that don't meet
// the overloads' constraints.
// template<input_iterator I, sentinel_for<I> S, class T,
// indirectly-binary-left-foldable<T, I> F>
// constexpr see below ranges::fold_left_with_iter(I first, S last, T init, F f);
//
// template<input_range R, class T, indirectly-binary-left-foldable<T, iterator_t<R>> F>
// constexpr see below ranges::fold_left_with_iter(R&& r, T init, F f);

// template<input_iterator I, sentinel_for<I> S, class T,
// indirectly-binary-left-foldable<T, I> F>
// constexpr see below ranges::fold_left(I first, S last, T init, F f);
//
// template<input_range R, class T, indirectly-binary-left-foldable<T, iterator_t<R>> F>
// constexpr see below ranges::fold_left(R&& r, T init, F f);

// Checks that the algorithm requirements reject parameters that don't meet the overloads' constraints.

#include <algorithm>
#include <concepts>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ struct ConvertibleFrom {
};

constexpr bool test() {
// Checks that conversion operations are correct.
{
std::ranges::in_found_result<double> res{10, true};
assert(res.in == 10);
Expand All @@ -72,6 +73,8 @@ constexpr bool test() {
assert(res2.in.content == 10);
assert(res2.found == true);
}

// Checks that conversions are possible when one of the types is move-only.
{
std::ranges::in_found_result<MoveOnly> res{MoveOnly{}, false};
assert(res.in.get() == 1);
Expand All @@ -82,10 +85,13 @@ constexpr bool test() {
assert(res.in.get() == 0);
assert(!res.found);
}
auto [in, found] = std::ranges::in_found_result<int>{2, false};
assert(in == 2);
assert(!found);

// Checks that structured bindings get the correct values.
{
auto [in, found] = std::ranges::in_found_result<int>{2, false};
assert(in == 2);
assert(!found);
}
return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ static_assert(std::is_convertible_v<const std::ranges::in_fun_result<int, int>&&
static_assert(std::is_move_constructible_v<std::ranges::in_fun_result<MoveOnly, int>>);
static_assert(std::is_move_constructible_v<std::ranges::in_fun_result<int, MoveOnly>>);

// should not copy constructible with move-only type
// should not be copy constructible with move-only type
static_assert(!std::is_copy_constructible_v<std::ranges::in_fun_result<MoveOnly, int>>);
static_assert(!std::is_copy_constructible_v<std::ranges::in_fun_result<int, MoveOnly>>);

Expand All @@ -64,6 +64,7 @@ struct ConvertibleFrom {
};

constexpr bool test() {
// Checks that conversion operations are correct.
{
std::ranges::in_fun_result<int, double> res{10, 0.};
assert(res.in == 10);
Expand All @@ -72,6 +73,8 @@ constexpr bool test() {
assert(res2.in.content == 10);
assert(res2.fun.content == 0.);
}

// Checks that conversions are possible when one of the types is move-only.
{
std::ranges::in_fun_result<MoveOnly, int> res{MoveOnly{}, 2};
assert(res.in.get() == 1);
Expand All @@ -81,6 +84,8 @@ constexpr bool test() {
assert(res2.in.get() == 1);
assert(res2.fun == 2);
}

// Checks that structured bindings get the correct values.
{
auto [in, fun] = std::ranges::in_fun_result<int, int>{1, 2};
assert(in == 1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ struct ConvertibleFrom {
};

constexpr bool test() {
// Checks that conversion operations are correct.
{
std::ranges::in_in_out_result<int, double, float> res{10, 0., 1.f};
assert(res.in1 == 10);
Expand All @@ -77,13 +78,17 @@ constexpr bool test() {
assert(res2.in2.content == 0.);
assert(res2.out.content == 1.f);
}

// Checks that conversions are possible when one of the types is move-only.
{
std::ranges::in_in_out_result<MoveOnly, int, int> res1{MoveOnly{}, 0, 0};
assert(res1.in1.get() == 1);
auto res2 = static_cast<std::ranges::in_in_out_result<MoveOnly, int, int>>(std::move(res1));
assert(res1.in1.get() == 0);
assert(res2.in1.get() == 1);
}

// Checks that structured bindings get the correct values.
{
auto [in1, in2, out] = std::ranges::in_in_out_result<int, int, int>{1, 2, 3};
assert(in1 == 1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ struct ConstructibleFrom {
};

constexpr bool test() {
// Checks that conversion operations are correct.
{
std::ranges::in_in_result<int, double> res{10L, 0.};
assert(res.in1 == 10);
Expand All @@ -67,12 +68,16 @@ constexpr bool test() {
assert(res2.in1.content == 10);
assert(res2.in2.content == 0.);
}

// Checks that conversions are possible when one of the types is move-only.
{
std::ranges::in_in_result<MoveOnly, int> res{MoveOnly{}, 0};
assert(res.in1.get() == 1);
[[maybe_unused]] auto res2 = static_cast<std::ranges::in_in_result<MoveOnly, int>>(std::move(res));
assert(res.in1.get() == 0);
}

// Checks that structured bindings get the correct values.
{
auto [in1, in2] = std::ranges::in_in_result<int, int>{1, 2};
assert(in1 == 1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ struct ConvertibleFrom {
};

constexpr bool test() {
// Checks that conversion operations are correct.
{
std::ranges::in_out_out_result<int, double, float> res{10, 0., 1.f};
assert(res.in == 10);
Expand All @@ -75,13 +76,17 @@ constexpr bool test() {
assert(res2.out1.content == 0.);
assert(res2.out2.content == 1.f);
}

// Checks that conversions are possible when one of the types is move-only.
{
std::ranges::in_out_out_result<MoveOnly, int, int> res1{MoveOnly{}, 0, 0};
assert(res1.in.get() == 1);
auto res2 = static_cast<std::ranges::in_out_out_result<MoveOnly, int, int>>(std::move(res1));
assert(res1.in.get() == 0);
assert(res2.in.get() == 1);
}

// Checks that structured bindings get the correct values.
{
auto [in, out1, out2] = std::ranges::in_out_out_result<int, int, int>{1, 2, 3};
assert(in == 1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ struct ConvertibleFrom {
};

constexpr bool test() {
// Checks that conversion operations are correct.
{
std::ranges::in_out_result<double, int> res{10, 1};
assert(res.in == 10);
Expand All @@ -67,6 +68,8 @@ constexpr bool test() {
assert(res2.in.content == 10);
assert(res2.out.content == 1);
}

// Checks that conversions are possible when one of the types is move-only.
{
std::ranges::in_out_result<MoveOnly, int> res{MoveOnly{}, 10};
assert(res.in.get() == 1);
Expand All @@ -77,6 +80,8 @@ constexpr bool test() {
assert(res2.in.get() == 1);
assert(res2.out == 10);
}

// Checks that structured bindings get the correct values.
{
auto [min, max] = std::ranges::in_out_result<int, int>{1, 2};
assert(min == 1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ static_assert(
static_assert(std::is_move_constructible_v<std::ranges::in_value_result<MoveOnly, int>>);
static_assert(std::is_move_constructible_v<std::ranges::in_value_result<int, MoveOnly>>);

// should not copy constructible with move-only type
// should not be copy constructible with move-only type
static_assert(!std::is_copy_constructible_v<std::ranges::in_value_result<MoveOnly, int>>);
static_assert(!std::is_copy_constructible_v<std::ranges::in_value_result<int, MoveOnly>>);

Expand All @@ -71,6 +71,7 @@ struct ConvertibleFrom {
};

constexpr bool test() {
// Checks that conversion operations are correct.
{
std::ranges::in_value_result<int, double> res{10, 0.};
assert(res.in == 10);
Expand All @@ -79,6 +80,8 @@ constexpr bool test() {
assert(res2.in.content == 10);
assert(res2.value.content == 0.);
}

// Checks that conversions are possible when one of the types is move-only.
{
std::ranges::in_value_result<MoveOnly, int> res{MoveOnly{}, 2};
assert(res.in.get() == 1);
Expand All @@ -88,6 +91,8 @@ constexpr bool test() {
assert(res2.in.get() == 1);
assert(res2.value == 2);
}

// Checks that structured bindings get the correct values.
{
auto [in, value] = std::ranges::in_value_result<int, int>{1, 2};
assert(in == 1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ struct ConvertibleFrom {
};

constexpr bool test() {
// Checks that conversion operations are correct.
{
std::ranges::min_max_result<double> res{10, 1};
assert(res.min == 10);
Expand All @@ -68,6 +69,8 @@ constexpr bool test() {
assert(res2.min.content == 10);
assert(res2.max.content == 1);
}

// Checks that conversions are possible when one of the types is move-only.
{
std::ranges::min_max_result<MoveOnly> res{MoveOnly{}, MoveOnly{}};
assert(res.min.get() == 1);
Expand All @@ -78,6 +81,8 @@ constexpr bool test() {
assert(res2.min.get() == 1);
assert(res2.max.get() == 1);
}

// Checks that structured bindings get the correct values.
{
auto [min, max] = std::ranges::min_max_result<int>{1, 2};
assert(min == 1);
Expand Down
7 changes: 0 additions & 7 deletions lldb/include/lldb/API/SBDebugger.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,6 @@ class LLDB_API SBInputReader {

class LLDB_API SBDebugger {
public:
FLAGS_ANONYMOUS_ENUM(){
eBroadcastBitProgress = (1 << 0),
eBroadcastBitWarning = (1 << 1),
eBroadcastBitError = (1 << 2),
eBroadcastBitProgressCategory = (1 << 3),
};

SBDebugger();

SBDebugger(const lldb::SBDebugger &rhs);
Expand Down
8 changes: 8 additions & 0 deletions lldb/include/lldb/lldb-enumerations.h
Original file line number Diff line number Diff line change
Expand Up @@ -1339,6 +1339,14 @@ enum AddressMaskRange {
eAddressMaskRangeAll = eAddressMaskRangeAny,
};

/// Used by the debugger to indicate which events are being broadcasted.
enum DebuggerBroadcastBit {
eBroadcastBitProgress = (1 << 0),
eBroadcastBitWarning = (1 << 1),
eBroadcastBitError = (1 << 2),
eBroadcastBitProgressCategory = (1 << 3),
};

} // namespace lldb

#endif // LLDB_LLDB_ENUMERATIONS_H
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,10 @@ ClangExpressionParser::ClangExpressionParser(
[[fallthrough]];
case lldb::eLanguageTypeC_plus_plus_03:
lang_opts.CPlusPlus = true;
if (process_sp)
if (process_sp
// We're stopped in a frame without debug-info. The user probably
// intends to make global queries (which should include Objective-C).
&& !(frame_sp && frame_sp->HasDebugInformation()))
lang_opts.ObjC =
process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC) != nullptr;
break;
Expand Down
35 changes: 12 additions & 23 deletions lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -553,9 +553,9 @@ bool ClangUserExpression::PrepareForParsing(
}

bool ClangUserExpression::TryParse(
DiagnosticManager &diagnostic_manager, ExecutionContextScope *exe_scope,
ExecutionContext &exe_ctx, lldb_private::ExecutionPolicy execution_policy,
bool keep_result_in_memory, bool generate_debug_info) {
DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx,
lldb_private::ExecutionPolicy execution_policy, bool keep_result_in_memory,
bool generate_debug_info) {
m_materializer_up = std::make_unique<Materializer>();

ResetDeclMap(exe_ctx, m_result_delegate, keep_result_in_memory);
Expand All @@ -574,7 +574,8 @@ bool ClangUserExpression::TryParse(
}

m_parser = std::make_unique<ClangExpressionParser>(
exe_scope, *this, generate_debug_info, m_include_directories, m_filename);
exe_ctx.GetBestExecutionContextScope(), *this, generate_debug_info,
m_include_directories, m_filename);

unsigned num_errors = m_parser->Parse(diagnostic_manager);

Expand Down Expand Up @@ -669,15 +670,8 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager,
// Parse the expression
//

Process *process = exe_ctx.GetProcessPtr();
ExecutionContextScope *exe_scope = process;

if (!exe_scope)
exe_scope = exe_ctx.GetTargetPtr();

bool parse_success = TryParse(diagnostic_manager, exe_scope, exe_ctx,
execution_policy, keep_result_in_memory,
generate_debug_info);
bool parse_success = TryParse(diagnostic_manager, exe_ctx, execution_policy,
keep_result_in_memory, generate_debug_info);
// If the expression failed to parse, check if retrying parsing with a loaded
// C++ module is possible.
if (!parse_success && shouldRetryWithCppModule(*target, execution_policy)) {
Expand All @@ -695,9 +689,8 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager,
// so recreate those.
CreateSourceCode(retry_manager, exe_ctx, m_imported_cpp_modules,
/*for_completion*/ false);
parse_success = TryParse(retry_manager, exe_scope, exe_ctx,
execution_policy, keep_result_in_memory,
generate_debug_info);
parse_success = TryParse(retry_manager, exe_ctx, execution_policy,
keep_result_in_memory, generate_debug_info);
// Return the parse diagnostics if we were successful.
if (parse_success)
diagnostic_manager = std::move(retry_manager);
Expand Down Expand Up @@ -759,6 +752,7 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager,
}
}

Process *process = exe_ctx.GetProcessPtr();
if (process && m_jit_start_addr != LLDB_INVALID_ADDRESS)
m_jit_process_wp = lldb::ProcessWP(process->shared_from_this());
return true;
Expand Down Expand Up @@ -840,13 +834,8 @@ bool ClangUserExpression::Complete(ExecutionContext &exe_ctx,
DeclMap()->SetLookupsEnabled(true);
}

Process *process = exe_ctx.GetProcessPtr();
ExecutionContextScope *exe_scope = process;

if (!exe_scope)
exe_scope = exe_ctx.GetTargetPtr();

ClangExpressionParser parser(exe_scope, *this, false);
ClangExpressionParser parser(exe_ctx.GetBestExecutionContextScope(), *this,
false);

// We have to find the source code location where the user text is inside
// the transformed expression code. When creating the transformed text, we
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,9 @@ class ClangUserExpression : public LLVMUserExpression {
/// The parameter have the same meaning as in ClangUserExpression::Parse.
/// \see ClangUserExpression::Parse
bool TryParse(DiagnosticManager &diagnostic_manager,
ExecutionContextScope *exe_scope, ExecutionContext &exe_ctx,
lldb_private::ExecutionPolicy execution_policy, bool keep_result_in_memory,
bool generate_debug_info);
ExecutionContext &exe_ctx,
lldb_private::ExecutionPolicy execution_policy,
bool keep_result_in_memory, bool generate_debug_info);

void SetupCppModuleImports(ExecutionContext &exe_ctx);

Expand Down
9 changes: 5 additions & 4 deletions lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1682,10 +1682,11 @@ TypeSystemClang::CreateTemplateTemplateParmDecl(const char *template_name) {
// type that includes a template template argument. Only the name matters for
// this purpose, so we use dummy values for the other characteristics of the
// type.
return TemplateTemplateParmDecl::Create(
ast, decl_ctx, SourceLocation(),
/*Depth*/ 0, /*Position*/ 0,
/*IsParameterPack*/ false, &identifier_info, template_param_list);
return TemplateTemplateParmDecl::Create(ast, decl_ctx, SourceLocation(),
/*Depth=*/0, /*Position=*/0,
/*IsParameterPack=*/false,
&identifier_info, /*Typename=*/false,
template_param_list);
}

ClassTemplateSpecializationDecl *
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ def test_source_locations_from_objc_modules(self):

# Import foundation so that the Obj-C module is loaded (which contains source locations
# that can be used by LLDB).
self.runCmd("expr @import Foundation")
self.runCmd("expr --language objective-c++ -- @import Foundation")
value = frame.EvaluateExpression("NSLog(1);")
self.assertFalse(value.GetError().Success())
# LLDB should print the source line that defines NSLog. To not rely on any
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ def test_expr_options(self):
self.assertTrue(val.IsValid())
self.assertFalse(val.GetError().Success())

@skipIfDarwin
def test_expr_options_lang(self):
"""These expression language options should work as expected."""
self.build()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def setUp(self):
self.broadcaster = self.dbg.GetBroadcaster()
self.listener = lldbutil.start_listening_from(
self.broadcaster,
lldb.SBDebugger.eBroadcastBitWarning | lldb.SBDebugger.eBroadcastBitError,
lldb.eBroadcastBitWarning | lldb.eBroadcastBitError,
)

def test_dwarf_symbol_loading_diagnostic_report(self):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def setUp(self):
TestBase.setUp(self)
self.broadcaster = self.dbg.GetBroadcaster()
self.listener = lldbutil.start_listening_from(
self.broadcaster, lldb.SBDebugger.eBroadcastBitProgress
self.broadcaster, lldb.eBroadcastBitProgress
)

def test_dwarf_symbol_loading_progress_report(self):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def test_clang_module_build_progress_report(self):
# other unrelated progress events.
broadcaster = self.dbg.GetBroadcaster()
listener = lldbutil.start_listening_from(
broadcaster, lldb.SBDebugger.eBroadcastBitProgress
broadcaster, lldb.eBroadcastBitProgress
)

# Trigger module builds.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,4 @@ def test_with_python_api(self):
"expr --language Objective-C++ -- id my_id = 0; my_id",
patterns=["\(id\) \$.* = nil"],
)
self.expect(
"expr --language C++ -- id my_id = 0; my_id",
patterns=["\(id\) \$.* = nullptr"],
)
self.expect("expr --language C++ -- id my_id = 0; my_id", error=True)
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
CXX_SOURCES := main.cpp
CXXFLAGS_EXTRAS := -g0

include Makefile.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"""
Test that the the expression parser enables ObjC support
when stopped in a C++ frame without debug-info.
"""

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


class TestObjCFromCppFramesWithoutDebugInfo(TestBase):
def test(self):
self.build()
(_, process, _, _) = lldbutil.run_to_name_breakpoint(self, "main")

self.assertState(process.GetState(), lldb.eStateStopped)
self.expect("expr id", error=False)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
int main() { return 0; }
2 changes: 1 addition & 1 deletion lldb/test/API/macosx/rosetta/TestRosetta.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def test_rosetta(self):
if rosetta_debugserver_installed():
broadcaster = self.dbg.GetBroadcaster()
listener = lldbutil.start_listening_from(
broadcaster, lldb.SBDebugger.eBroadcastBitWarning
broadcaster, lldb.eBroadcastBitWarning
)

target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(
Expand Down
4 changes: 2 additions & 2 deletions lldb/tools/lldb-dap/lldb-dap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -420,8 +420,8 @@ void SendStdOutStdErr(lldb::SBProcess &process) {

void ProgressEventThreadFunction() {
lldb::SBListener listener("lldb-dap.progress.listener");
g_dap.debugger.GetBroadcaster().AddListener(
listener, lldb::SBDebugger::eBroadcastBitProgress);
g_dap.debugger.GetBroadcaster().AddListener(listener,
lldb::eBroadcastBitProgress);
g_dap.broadcaster.AddListener(listener, eBroadcastBitStopProgressThread);
lldb::SBEvent event;
bool done = false;
Expand Down
2 changes: 1 addition & 1 deletion llvm/include/llvm/CodeGen/DeadMachineInstructionElim.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
namespace llvm {

class DeadMachineInstructionElimPass
: public MachinePassInfoMixin<DeadMachineInstructionElimPass> {
: public PassInfoMixin<DeadMachineInstructionElimPass> {
public:
PreservedAnalyses run(MachineFunction &MF,
MachineFunctionAnalysisManager &MFAM);
Expand Down
3 changes: 1 addition & 2 deletions llvm/include/llvm/CodeGen/FreeMachineFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@

namespace llvm {

class FreeMachineFunctionPass
: public MachinePassInfoMixin<FreeMachineFunctionPass> {
class FreeMachineFunctionPass : public PassInfoMixin<FreeMachineFunctionPass> {
public:
PreservedAnalyses run(MachineFunction &MF,
MachineFunctionAnalysisManager &MFAM);
Expand Down
4 changes: 2 additions & 2 deletions llvm/include/llvm/CodeGen/MIRPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ class MachineFunction;
class Module;
template <typename T> class SmallVectorImpl;

class PrintMIRPreparePass : public MachinePassInfoMixin<PrintMIRPreparePass> {
class PrintMIRPreparePass : public PassInfoMixin<PrintMIRPreparePass> {
raw_ostream &OS;

public:
PrintMIRPreparePass(raw_ostream &OS = errs()) : OS(OS) {}
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MFAM);
};

class PrintMIRPass : public MachinePassInfoMixin<PrintMIRPass> {
class PrintMIRPass : public PassInfoMixin<PrintMIRPass> {
raw_ostream &OS;

public:
Expand Down
108 changes: 40 additions & 68 deletions llvm/include/llvm/CodeGen/MachinePassManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,65 +36,6 @@ class MachineFunction;
extern template class AnalysisManager<MachineFunction>;
using MachineFunctionAnalysisManager = AnalysisManager<MachineFunction>;

/// A CRTP mix-in that provides informational APIs needed for machine passes.
///
/// This provides some boilerplate for types that are machine passes. It
/// automatically mixes in \c PassInfoMixin.
template <typename DerivedT>
struct MachinePassInfoMixin : public PassInfoMixin<DerivedT> {
protected:
class PropertyChanger {
MachineFunction &MF;

template <typename T>
using has_get_required_properties_t =
decltype(std::declval<T &>().getRequiredProperties());

template <typename T>
using has_get_set_properties_t =
decltype(std::declval<T &>().getSetProperties());

template <typename T>
using has_get_cleared_properties_t =
decltype(std::declval<T &>().getClearedProperties());

public:
PropertyChanger(MachineFunction &MF) : MF(MF) {
#ifndef NDEBUG
if constexpr (is_detected<has_get_required_properties_t,
DerivedT>::value) {
auto &MFProps = MF.getProperties();
auto RequiredProperties = DerivedT::getRequiredProperties();
if (!MFProps.verifyRequiredProperties(RequiredProperties)) {
errs() << "MachineFunctionProperties required by " << DerivedT::name()
<< " pass are not met by function " << MF.getName() << ".\n"
<< "Required properties: ";
RequiredProperties.print(errs());
errs() << "\nCurrent properties: ";
MFProps.print(errs());
errs() << '\n';
report_fatal_error("MachineFunctionProperties check failed");
}
}
#endif
}

~PropertyChanger() {
if constexpr (is_detected<has_get_set_properties_t, DerivedT>::value)
MF.getProperties().set(DerivedT::getSetProperties());
if constexpr (is_detected<has_get_cleared_properties_t, DerivedT>::value)
MF.getProperties().reset(DerivedT::getClearedProperties());
}
};

public:
PreservedAnalyses runImpl(MachineFunction &MF,
MachineFunctionAnalysisManager &MFAM) {
PropertyChanger PC(MF);
return static_cast<DerivedT *>(this)->run(MF, MFAM);
}
};

namespace detail {

template <typename PassT>
Expand All @@ -117,8 +58,44 @@ struct MachinePassModel
MachinePassModel &operator=(const MachinePassModel &) = delete;
PreservedAnalyses run(MachineFunction &IR,
MachineFunctionAnalysisManager &AM) override {
return this->Pass.runImpl(IR, AM);
#ifndef NDEBUG
if constexpr (is_detected<has_get_required_properties_t, PassT>::value) {
auto &MFProps = IR.getProperties();
auto RequiredProperties = PassT::getRequiredProperties();
if (!MFProps.verifyRequiredProperties(RequiredProperties)) {
errs() << "MachineFunctionProperties required by " << PassT::name()
<< " pass are not met by function " << IR.getName() << ".\n"
<< "Required properties: ";
RequiredProperties.print(errs());
errs() << "\nCurrent properties: ";
MFProps.print(errs());
errs() << '\n';
report_fatal_error("MachineFunctionProperties check failed");
}
}
#endif

auto PA = this->Pass.run(IR, AM);

if constexpr (is_detected<has_get_set_properties_t, PassT>::value)
IR.getProperties().set(PassT::getSetProperties());
if constexpr (is_detected<has_get_cleared_properties_t, PassT>::value)
IR.getProperties().reset(PassT::getClearedProperties());
return PA;
}

private:
template <typename T>
using has_get_required_properties_t =
decltype(std::declval<T &>().getRequiredProperties());

template <typename T>
using has_get_set_properties_t =
decltype(std::declval<T &>().getSetProperties());

template <typename T>
using has_get_cleared_properties_t =
decltype(std::declval<T &>().getClearedProperties());
};
} // namespace detail

Expand Down Expand Up @@ -246,20 +223,15 @@ createModuleToMachineFunctionPassAdaptor(MachineFunctionPassT &&Pass) {
template <>
template <typename PassT>
void PassManager<MachineFunction>::addPass(PassT &&Pass) {
using PassModelT =
detail::PassModel<MachineFunction, PassT, MachineFunctionAnalysisManager>;
using MachinePassModelT = detail::MachinePassModel<PassT>;
// Do not use make_unique or emplace_back, they cause too many template
// instantiations, causing terrible compile times.
if constexpr (std::is_base_of_v<MachinePassInfoMixin<PassT>, PassT>) {
Passes.push_back(std::unique_ptr<PassConceptT>(
new MachinePassModelT(std::forward<PassT>(Pass))));
} else if constexpr (std::is_same_v<PassT, PassManager<MachineFunction>>) {
if constexpr (std::is_same_v<PassT, PassManager<MachineFunction>>) {
for (auto &P : Pass.Passes)
Passes.push_back(std::move(P));
} else {
Passes.push_back(std::unique_ptr<PassConceptT>(
new PassModelT(std::forward<PassT>(Pass))));
Passes.push_back(std::unique_ptr<MachinePassModelT>(
new MachinePassModelT(std::forward<PassT>(Pass))));
}
}

Expand Down
4 changes: 2 additions & 2 deletions llvm/include/llvm/Passes/CodeGenPassBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,14 @@ namespace llvm {
} \
};
#define DUMMY_MACHINE_MODULE_PASS(NAME, PASS_NAME) \
struct PASS_NAME : public MachinePassInfoMixin<PASS_NAME> { \
struct PASS_NAME : public PassInfoMixin<PASS_NAME> { \
template <typename... Ts> PASS_NAME(Ts &&...) {} \
PreservedAnalyses run(Module &, ModuleAnalysisManager &) { \
return PreservedAnalyses::all(); \
} \
};
#define DUMMY_MACHINE_FUNCTION_PASS(NAME, PASS_NAME) \
struct PASS_NAME : public MachinePassInfoMixin<PASS_NAME> { \
struct PASS_NAME : public PassInfoMixin<PASS_NAME> { \
template <typename... Ts> PASS_NAME(Ts &&...) {} \
PreservedAnalyses run(MachineFunction &, \
MachineFunctionAnalysisManager &) { \
Expand Down
3 changes: 1 addition & 2 deletions llvm/include/llvm/Passes/PassBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -909,8 +909,7 @@ struct NoOpLoopPass : PassInfoMixin<NoOpLoopPass> {
};

/// No-op machine function pass which does nothing.
struct NoOpMachineFunctionPass
: public MachinePassInfoMixin<NoOpMachineFunctionPass> {
struct NoOpMachineFunctionPass : public PassInfoMixin<NoOpMachineFunctionPass> {
PreservedAnalyses run(MachineFunction &, MachineFunctionAnalysisManager &) {
return PreservedAnalyses::all();
}
Expand Down
5 changes: 4 additions & 1 deletion llvm/include/llvm/Passes/StandardInstrumentations.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,11 @@ class PrintIRInstrumentation {

bool shouldPrintBeforePass(StringRef PassID);
bool shouldPrintAfterPass(StringRef PassID);
bool shouldPrintBeforeCurrentPassNumber();
bool shouldPrintAfterCurrentPassNumber();
bool shouldPrintPassNumbers();
bool shouldPrintBeforePassNumber();
bool shouldPrintBeforeSomePassNumber();
bool shouldPrintAfterSomePassNumber();

void pushPassRunDescriptor(StringRef PassID, Any IR,
std::string &DumpIRFilename);
Expand Down
4 changes: 4 additions & 0 deletions llvm/include/llvm/Transforms/Utils/SCCPSolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,10 @@ class SCCPSolver {
/// works with both scalars and structs.
void markOverdefined(Value *V);

/// trackValueOfArgument - Mark the specified argument overdefined unless it
/// have range attribute. This works with both scalars and structs.
void trackValueOfArgument(Argument *V);

// isStructLatticeConstant - Return true if all the lattice values
// corresponding to elements of the structure are constants,
// false otherwise.
Expand Down
3 changes: 0 additions & 3 deletions llvm/lib/Analysis/TargetLibraryInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -813,9 +813,6 @@ static void initialize(TargetLibraryInfoImpl &TLI, const Triple &T,
TLI.setUnavailable(LibFunc_cabs);
TLI.setUnavailable(LibFunc_cabsf);
TLI.setUnavailable(LibFunc_cabsl);
TLI.setUnavailable(LibFunc_erf);
TLI.setUnavailable(LibFunc_erff);
TLI.setUnavailable(LibFunc_erfl);
TLI.setUnavailable(LibFunc_ffs);
TLI.setUnavailable(LibFunc_flockfile);
TLI.setUnavailable(LibFunc_fseeko);
Expand Down
48 changes: 36 additions & 12 deletions llvm/lib/Analysis/ValueTracking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -701,13 +701,26 @@ static void computeKnownBitsFromCmp(const Value *V, CmpInst::Predicate Pred,
break;
}
default:
const APInt *Offset = nullptr;
if (match(LHS, m_CombineOr(m_V, m_AddLike(m_V, m_APInt(Offset)))) &&
match(RHS, m_APInt(C))) {
ConstantRange LHSRange = ConstantRange::makeAllowedICmpRegion(Pred, *C);
if (Offset)
LHSRange = LHSRange.sub(*Offset);
Known = Known.unionWith(LHSRange.toKnownBits());
if (match(RHS, m_APInt(C))) {
const APInt *Offset = nullptr;
if (match(LHS, m_CombineOr(m_V, m_AddLike(m_V, m_APInt(Offset))))) {
ConstantRange LHSRange = ConstantRange::makeAllowedICmpRegion(Pred, *C);
if (Offset)
LHSRange = LHSRange.sub(*Offset);
Known = Known.unionWith(LHSRange.toKnownBits());
}
// X & Y u> C -> X u> C && Y u> C
if ((Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_UGE) &&
match(LHS, m_c_And(m_V, m_Value()))) {
Known.One.setHighBits(
(*C + (Pred == ICmpInst::ICMP_UGT)).countLeadingOnes());
}
// X | Y u< C -> X u< C && Y u< C
if ((Pred == ICmpInst::ICMP_ULT || Pred == ICmpInst::ICMP_ULE) &&
match(LHS, m_c_Or(m_V, m_Value()))) {
Known.Zero.setHighBits(
(*C - (Pred == ICmpInst::ICMP_ULT)).countLeadingZeros());
}
}
break;
}
Expand Down Expand Up @@ -9448,11 +9461,22 @@ void llvm::findValuesAffectedByCondition(
}
}
} else {
// Handle (A + C1) u< C2, which is the canonical form of
// A > C3 && A < C4.
if (match(A, m_AddLike(m_Value(X), m_ConstantInt())) &&
match(B, m_ConstantInt()))
AddAffected(X);
if (match(B, m_ConstantInt())) {
// Handle (A + C1) u< C2, which is the canonical form of
// A > C3 && A < C4.
if (match(A, m_AddLike(m_Value(X), m_ConstantInt())))
AddAffected(X);

Value *Y;
// X & Y u> C -> X >u C && Y >u C
// X | Y u< C -> X u< C && Y u< C
if (ICmpInst::isUnsigned(Pred) &&
(match(A, m_And(m_Value(X), m_Value(Y))) ||
match(A, m_Or(m_Value(X), m_Value(Y))))) {
AddAffected(X);
AddAffected(Y);
}
}

// Handle icmp slt/sgt (bitcast X to int), 0/-1, which is supported
// by computeKnownFPClass().
Expand Down
20 changes: 9 additions & 11 deletions llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24433,6 +24433,7 @@ SDValue DAGCombiner::visitEXTRACT_SUBVECTOR(SDNode *N) {
EVT NVT = N->getValueType(0);
SDValue V = N->getOperand(0);
uint64_t ExtIdx = N->getConstantOperandVal(1);
SDLoc DL(N);

// Extract from UNDEF is UNDEF.
if (V.isUndef())
Expand All @@ -24448,7 +24449,7 @@ SDValue DAGCombiner::visitEXTRACT_SUBVECTOR(SDNode *N) {
if (TLI.isExtractSubvectorCheap(NVT, V.getOperand(0).getValueType(),
V.getConstantOperandVal(1)) &&
TLI.isOperationLegalOrCustom(ISD::EXTRACT_SUBVECTOR, NVT)) {
return DAG.getNode(ISD::EXTRACT_SUBVECTOR, SDLoc(N), NVT, V.getOperand(0),
return DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, NVT, V.getOperand(0),
V.getOperand(1));
}
}
Expand All @@ -24457,7 +24458,7 @@ SDValue DAGCombiner::visitEXTRACT_SUBVECTOR(SDNode *N) {
if (V.getOpcode() == ISD::SPLAT_VECTOR)
if (DAG.isConstantValueOfAnyType(V.getOperand(0)) || V.hasOneUse())
if (!LegalOperations || TLI.isOperationLegal(ISD::SPLAT_VECTOR, NVT))
return DAG.getSplatVector(NVT, SDLoc(N), V.getOperand(0));
return DAG.getSplatVector(NVT, DL, V.getOperand(0));

// Try to move vector bitcast after extract_subv by scaling extraction index:
// extract_subv (bitcast X), Index --> bitcast (extract_subv X, Index')
Expand All @@ -24471,10 +24472,9 @@ SDValue DAGCombiner::visitEXTRACT_SUBVECTOR(SDNode *N) {
if ((SrcNumElts % DestNumElts) == 0) {
unsigned SrcDestRatio = SrcNumElts / DestNumElts;
ElementCount NewExtEC = NVT.getVectorElementCount() * SrcDestRatio;
EVT NewExtVT = EVT::getVectorVT(*DAG.getContext(), SrcVT.getScalarType(),
NewExtEC);
EVT NewExtVT =
EVT::getVectorVT(*DAG.getContext(), SrcVT.getScalarType(), NewExtEC);
if (TLI.isOperationLegalOrCustom(ISD::EXTRACT_SUBVECTOR, NewExtVT)) {
SDLoc DL(N);
SDValue NewIndex = DAG.getVectorIdxConstant(ExtIdx * SrcDestRatio, DL);
SDValue NewExtract = DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, NewExtVT,
V.getOperand(0), NewIndex);
Expand All @@ -24488,7 +24488,6 @@ SDValue DAGCombiner::visitEXTRACT_SUBVECTOR(SDNode *N) {
NVT.getVectorElementCount().divideCoefficientBy(DestSrcRatio);
EVT ScalarVT = SrcVT.getScalarType();
if ((ExtIdx % DestSrcRatio) == 0) {
SDLoc DL(N);
unsigned IndexValScaled = ExtIdx / DestSrcRatio;
EVT NewExtVT =
EVT::getVectorVT(*DAG.getContext(), ScalarVT, NewExtEC);
Expand Down Expand Up @@ -24536,7 +24535,6 @@ SDValue DAGCombiner::visitEXTRACT_SUBVECTOR(SDNode *N) {
// v2i8 extract_subvec v8i8 Y, 6
if (NVT.isFixedLengthVector() && ConcatSrcVT.isFixedLengthVector() &&
ConcatSrcNumElts % ExtNumElts == 0) {
SDLoc DL(N);
unsigned NewExtIdx = ExtIdx - ConcatOpIdx * ConcatSrcNumElts;
assert(NewExtIdx + ExtNumElts <= ConcatSrcNumElts &&
"Trying to extract from >1 concat operand?");
Expand Down Expand Up @@ -24575,13 +24573,13 @@ SDValue DAGCombiner::visitEXTRACT_SUBVECTOR(SDNode *N) {
if (NumElems == 1) {
SDValue Src = V->getOperand(IdxVal);
if (EltVT != Src.getValueType())
Src = DAG.getNode(ISD::TRUNCATE, SDLoc(N), EltVT, Src);
Src = DAG.getNode(ISD::TRUNCATE, DL, EltVT, Src);
return DAG.getBitcast(NVT, Src);
}

// Extract the pieces from the original build_vector.
SDValue BuildVec = DAG.getBuildVector(ExtractVT, SDLoc(N),
V->ops().slice(IdxVal, NumElems));
SDValue BuildVec =
DAG.getBuildVector(ExtractVT, DL, V->ops().slice(IdxVal, NumElems));
return DAG.getBitcast(NVT, BuildVec);
}
}
Expand All @@ -24608,7 +24606,7 @@ SDValue DAGCombiner::visitEXTRACT_SUBVECTOR(SDNode *N) {
return DAG.getBitcast(NVT, V.getOperand(1));
}
return DAG.getNode(
ISD::EXTRACT_SUBVECTOR, SDLoc(N), NVT,
ISD::EXTRACT_SUBVECTOR, DL, NVT,
DAG.getBitcast(N->getOperand(0).getValueType(), V.getOperand(0)),
N->getOperand(1));
}
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/IR/AsmWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3313,7 +3313,7 @@ static const char *getImportTypeName(GlobalValueSummary::ImportKind IK) {
case GlobalValueSummary::Declaration:
return "declaration";
}
assert(false && "invalid import kind");
llvm_unreachable("invalid import kind");
}

void AssemblyWriter::printFunctionSummary(const FunctionSummary *FS) {
Expand Down
1 change: 0 additions & 1 deletion llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,6 @@ template <> void SymbolRecordImpl<LabelSym>::map(IO &IO) {
IO.mapOptional("Offset", Symbol.CodeOffset, 0U);
IO.mapOptional("Segment", Symbol.Segment, uint16_t(0));
IO.mapRequired("Flags", Symbol.Flags);
IO.mapRequired("Flags", Symbol.Flags);
IO.mapRequired("DisplayName", Symbol.Name);
}

Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Passes/PassBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ class TriggerVerifierErrorPass
// A pass requires all MachineFunctionProperties.
// DO NOT USE THIS EXCEPT FOR TESTING!
class RequireAllMachineFunctionPropertiesPass
: public MachinePassInfoMixin<RequireAllMachineFunctionPropertiesPass> {
: public PassInfoMixin<RequireAllMachineFunctionPropertiesPass> {
public:
PreservedAnalyses run(MachineFunction &, MachineFunctionAnalysisManager &) {
return PreservedAnalyses::none();
Expand Down
62 changes: 44 additions & 18 deletions llvm/lib/Passes/StandardInstrumentations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,11 @@ static cl::opt<unsigned> PrintBeforePassNumber(
cl::desc("Print IR before the pass with this number as "
"reported by print-pass-numbers"));

static cl::opt<unsigned>
PrintAfterPassNumber("print-after-pass-number", cl::init(0), cl::Hidden,
cl::desc("Print IR after the pass with this number as "
"reported by print-pass-numbers"));

static cl::opt<std::string> IRDumpDirectory(
"ir-dump-directory",
cl::desc("If specified, IR printed using the "
Expand Down Expand Up @@ -854,7 +859,9 @@ void PrintIRInstrumentation::printBeforePass(StringRef PassID, Any IR) {

std::string DumpIRFilename;
if (!IRDumpDirectory.empty() &&
(shouldPrintBeforePass(PassID) || shouldPrintAfterPass(PassID)))
(shouldPrintBeforePass(PassID) || shouldPrintAfterPass(PassID) ||
shouldPrintBeforeCurrentPassNumber() ||
shouldPrintAfterCurrentPassNumber()))
DumpIRFilename = fetchDumpFilename(PassID, IR);

// Saving Module for AfterPassInvalidated operations.
Expand All @@ -873,12 +880,15 @@ void PrintIRInstrumentation::printBeforePass(StringRef PassID, Any IR) {
dbgs() << " Running pass " << CurrentPassNumber << " " << PassID
<< " on " << getIRName(IR) << "\n";

if (!shouldPrintBeforePass(PassID))
if (shouldPrintAfterCurrentPassNumber())
pushPassRunDescriptor(PassID, IR, DumpIRFilename);

if (!shouldPrintBeforePass(PassID) && !shouldPrintBeforeCurrentPassNumber())
return;

auto WriteIRToStream = [&](raw_ostream &Stream) {
Stream << "; *** IR Dump Before ";
if (shouldPrintBeforePassNumber())
if (shouldPrintBeforeSomePassNumber())
Stream << CurrentPassNumber << "-";
Stream << PassID << " on " << getIRName(IR) << " ***\n";
unwrapAndPrint(Stream, IR);
Expand All @@ -898,18 +908,21 @@ void PrintIRInstrumentation::printAfterPass(StringRef PassID, Any IR) {
if (isIgnored(PassID))
return;

if (!shouldPrintAfterPass(PassID))
if (!shouldPrintAfterPass(PassID) && !shouldPrintAfterCurrentPassNumber())
return;

auto [M, DumpIRFilename, IRName, StoredPassID] = popPassRunDescriptor(PassID);
assert(StoredPassID == PassID && "mismatched PassID");

if (!shouldPrintIR(IR) || !shouldPrintAfterPass(PassID))
if (!shouldPrintIR(IR) ||
(!shouldPrintAfterPass(PassID) && !shouldPrintAfterCurrentPassNumber()))
return;

auto WriteIRToStream = [&](raw_ostream &Stream, const StringRef IRName) {
Stream << "; *** IR Dump " << StringRef(formatv("After {0}", PassID))
<< " on " << IRName << " ***\n";
Stream << "; *** IR Dump After ";
if (shouldPrintAfterSomePassNumber())
Stream << CurrentPassNumber << "-";
Stream << StringRef(formatv("{0}", PassID)) << " on " << IRName << " ***\n";
unwrapAndPrint(Stream, IR);
};

Expand All @@ -931,14 +944,15 @@ void PrintIRInstrumentation::printAfterPassInvalidated(StringRef PassID) {
if (isIgnored(PassID))
return;

if (!shouldPrintAfterPass(PassID))
if (!shouldPrintAfterPass(PassID) && !shouldPrintAfterCurrentPassNumber())
return;

auto [M, DumpIRFilename, IRName, StoredPassID] = popPassRunDescriptor(PassID);
assert(StoredPassID == PassID && "mismatched PassID");
// Additional filtering (e.g. -filter-print-func) can lead to module
// printing being skipped.
if (!M || !shouldPrintAfterPass(PassID))
if (!M ||
(!shouldPrintAfterPass(PassID) && !shouldPrintAfterCurrentPassNumber()))
return;

auto WriteIRToStream = [&](raw_ostream &Stream, const Module *M,
Expand Down Expand Up @@ -968,10 +982,6 @@ bool PrintIRInstrumentation::shouldPrintBeforePass(StringRef PassID) {
if (shouldPrintBeforeAll())
return true;

if (shouldPrintBeforePassNumber() &&
CurrentPassNumber == PrintBeforePassNumber)
return true;

StringRef PassName = PIC->getPassNameForClassName(PassID);
return is_contained(printBeforePasses(), PassName);
}
Expand All @@ -984,26 +994,42 @@ bool PrintIRInstrumentation::shouldPrintAfterPass(StringRef PassID) {
return is_contained(printAfterPasses(), PassName);
}

bool PrintIRInstrumentation::shouldPrintBeforeCurrentPassNumber() {
return shouldPrintBeforeSomePassNumber() &&
(CurrentPassNumber == PrintBeforePassNumber);
}

bool PrintIRInstrumentation::shouldPrintAfterCurrentPassNumber() {
return shouldPrintAfterSomePassNumber() &&
(CurrentPassNumber == PrintAfterPassNumber);
}

bool PrintIRInstrumentation::shouldPrintPassNumbers() {
return PrintPassNumbers;
}

bool PrintIRInstrumentation::shouldPrintBeforePassNumber() {
bool PrintIRInstrumentation::shouldPrintBeforeSomePassNumber() {
return PrintBeforePassNumber > 0;
}

bool PrintIRInstrumentation::shouldPrintAfterSomePassNumber() {
return PrintAfterPassNumber > 0;
}

void PrintIRInstrumentation::registerCallbacks(
PassInstrumentationCallbacks &PIC) {
this->PIC = &PIC;

// BeforePass callback is not just for printing, it also saves a Module
// for later use in AfterPassInvalidated.
if (shouldPrintPassNumbers() || shouldPrintBeforePassNumber() ||
shouldPrintBeforeSomePass() || shouldPrintAfterSomePass())
// for later use in AfterPassInvalidated and keeps tracks of the
// CurrentPassNumber.
if (shouldPrintPassNumbers() || shouldPrintBeforeSomePassNumber() ||
shouldPrintAfterSomePassNumber() || shouldPrintBeforeSomePass() ||
shouldPrintAfterSomePass())
PIC.registerBeforeNonSkippedPassCallback(
[this](StringRef P, Any IR) { this->printBeforePass(P, IR); });

if (shouldPrintAfterSomePass()) {
if (shouldPrintAfterSomePass() || shouldPrintAfterSomePassNumber()) {
PIC.registerAfterPassCallback(
[this](StringRef P, Any IR, const PreservedAnalyses &) {
this->printAfterPass(P, IR);
Expand Down
9 changes: 4 additions & 5 deletions llvm/lib/ProfileData/InstrProfReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <cstdint>
#include <limits>
#include <memory>
#include <optional>
#include <system_error>
#include <utility>
#include <vector>
Expand Down Expand Up @@ -1506,13 +1507,11 @@ IndexedInstrProfReader::getMemProfRecord(const uint64_t FuncNameHash) {

// Setup a callback to convert from frame ids to frame using the on-disk
// FrameData hash table.
memprof::FrameId LastUnmappedFrameId = 0;
bool HasFrameMappingError = false;
std::optional<memprof::FrameId> LastUnmappedFrameId;
auto IdToFrameCallback = [&](const memprof::FrameId Id) {
auto FrIter = MemProfFrameTable->find(Id);
if (FrIter == MemProfFrameTable->end()) {
LastUnmappedFrameId = Id;
HasFrameMappingError = true;
return memprof::Frame(0, 0, 0, false);
}
return *FrIter;
Expand All @@ -1521,10 +1520,10 @@ IndexedInstrProfReader::getMemProfRecord(const uint64_t FuncNameHash) {
memprof::MemProfRecord Record(*Iter, IdToFrameCallback);

// Check that all frame ids were successfully converted to frames.
if (HasFrameMappingError) {
if (LastUnmappedFrameId) {
return make_error<InstrProfError>(instrprof_error::hash_mismatch,
"memprof frame not found for frame id " +
Twine(LastUnmappedFrameId));
Twine(*LastUnmappedFrameId));
}
return Record;
}
Expand Down
20 changes: 9 additions & 11 deletions llvm/lib/ProfileData/MemProfReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,13 +142,13 @@ CallStackMap readStackInfo(const char *Ptr) {
// any stack ids observed previously map to a different set of program counter
// addresses.
bool mergeStackMap(const CallStackMap &From, CallStackMap &To) {
for (const auto &IdStack : From) {
auto I = To.find(IdStack.first);
for (const auto &[Id, Stack] : From) {
auto I = To.find(Id);
if (I == To.end()) {
To[IdStack.first] = IdStack.second;
To[Id] = Stack;
} else {
// Check that the PCs are the same (in order).
if (IdStack.second != I->second)
if (Stack != I->second)
return true;
}
}
Expand Down Expand Up @@ -275,10 +275,10 @@ void RawMemProfReader::printYAML(raw_ostream &OS) {
}
// Print out the merged contents of the profiles.
OS << " Records:\n";
for (const auto &Entry : *this) {
for (const auto &[GUID, Record] : *this) {
OS << " -\n";
OS << " FunctionGUID: " << Entry.first << "\n";
Entry.second.print(OS);
OS << " FunctionGUID: " << GUID << "\n";
Record.print(OS);
}
}

Expand Down Expand Up @@ -405,9 +405,7 @@ Error RawMemProfReader::mapRawProfileToRecords() {

// Convert the raw profile callstack data into memprof records. While doing so
// keep track of related contexts so that we can fill these in later.
for (const auto &Entry : CallstackProfileData) {
const uint64_t StackId = Entry.first;

for (const auto &[StackId, MIB] : CallstackProfileData) {
auto It = StackMap.find(StackId);
if (It == StackMap.end())
return make_error<InstrProfError>(
Expand Down Expand Up @@ -455,7 +453,7 @@ Error RawMemProfReader::mapRawProfileToRecords() {
auto Result =
FunctionProfileData.insert({F.Function, IndexedMemProfRecord()});
IndexedMemProfRecord &Record = Result.first->second;
Record.AllocSites.emplace_back(Callstack, CSId, Entry.second);
Record.AllocSites.emplace_back(Callstack, CSId, MIB);

if (!F.IsInlineFrame)
break;
Expand Down
17 changes: 7 additions & 10 deletions llvm/lib/Target/X86/X86ISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1286,6 +1286,11 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
setOperationAction(ISD::CTLZ, VT, Custom);
}

if (Subtarget.hasGFNI()) {
setOperationAction(ISD::BITREVERSE, MVT::i32, Custom);
setOperationAction(ISD::BITREVERSE, MVT::i64, Custom);
}

// These might be better off as horizontal vector ops.
setOperationAction(ISD::ADD, MVT::i16, Custom);
setOperationAction(ISD::ADD, MVT::i32, Custom);
Expand Down Expand Up @@ -1496,11 +1501,6 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
setOperationAction(ISD::TRUNCATE, MVT::v32i32, Custom);
setOperationAction(ISD::TRUNCATE, MVT::v32i64, Custom);

if (Subtarget.hasGFNI()) {
setOperationAction(ISD::BITREVERSE, MVT::i32, Custom);
setOperationAction(ISD::BITREVERSE, MVT::i64, Custom);
}

for (auto VT : { MVT::v32i8, MVT::v16i16, MVT::v8i32, MVT::v4i64 }) {
setOperationAction(ISD::SETCC, VT, Custom);
setOperationAction(ISD::CTPOP, VT, Custom);
Expand Down Expand Up @@ -31337,12 +31337,9 @@ static SDValue LowerBITREVERSE(SDValue Op, const X86Subtarget &Subtarget,
if (VT.is256BitVector() && !Subtarget.hasInt256())
return splitVectorIntUnary(Op, DAG, DL);

// Lower i32/i64 to GFNI as vXi8 BITREVERSE + BSWAP
// Lower i32/i64 as vXi8 BITREVERSE + BSWAP
if (!VT.isVector()) {

assert((VT.getScalarType() == MVT::i32) ||
(VT.getScalarType() == MVT::i64));

assert((VT == MVT::i32 || VT == MVT::i64) && "Only tested for i32/i64");
MVT VecVT = MVT::getVectorVT(VT, 128 / VT.getSizeInBits());
SDValue Res = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, VecVT, In);
Res = DAG.getNode(ISD::BITREVERSE, DL, MVT::v16i8,
Expand Down
3 changes: 1 addition & 2 deletions llvm/lib/Transforms/IPO/SCCP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,8 @@ static bool runIPSCCP(
// Assume the function is called.
Solver.markBlockExecutable(&F.front());

// Assume nothing about the incoming arguments.
for (Argument &AI : F.args())
Solver.markOverdefined(&AI);
Solver.trackValueOfArgument(&AI);
}

// Determine if we can track any of the module's global variables. If so, add
Expand Down
15 changes: 14 additions & 1 deletion llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -897,7 +897,20 @@ Instruction *InstCombinerImpl::visitTrunc(TruncInst &Trunc) {
}
}

return nullptr;
bool Changed = false;
if (!Trunc.hasNoSignedWrap() &&
ComputeMaxSignificantBits(Src, /*Depth=*/0, &Trunc) <= DestWidth) {
Trunc.setHasNoSignedWrap(true);
Changed = true;
}
if (!Trunc.hasNoUnsignedWrap() &&
MaskedValueIsZero(Src, APInt::getBitsSetFrom(SrcWidth, DestWidth),
/*Depth=*/0, &Trunc)) {
Trunc.setHasNoUnsignedWrap(true);
Changed = true;
}

return Changed ? &Trunc : nullptr;
}

Instruction *InstCombinerImpl::transformZExtICmp(ICmpInst *Cmp,
Expand Down
34 changes: 34 additions & 0 deletions llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7163,6 +7163,40 @@ Instruction *InstCombinerImpl::foldICmpCommutative(ICmpInst::Predicate Pred,
if (Value *V = foldICmpWithLowBitMaskedVal(Pred, Op0, Op1, Q, *this))
return replaceInstUsesWith(CxtI, V);

// Folding (X / Y) pred X => X swap(pred) 0 for constant Y other than 0 or 1
{
const APInt *Divisor;
if (match(Op0, m_UDiv(m_Specific(Op1), m_APInt(Divisor))) &&
Divisor->ugt(1)) {
return new ICmpInst(ICmpInst::getSwappedPredicate(Pred), Op1,
Constant::getNullValue(Op1->getType()));
}

if (!ICmpInst::isUnsigned(Pred) &&
match(Op0, m_SDiv(m_Specific(Op1), m_APInt(Divisor))) &&
Divisor->ugt(1)) {
return new ICmpInst(ICmpInst::getSwappedPredicate(Pred), Op1,
Constant::getNullValue(Op1->getType()));
}
}

// Another case of this fold is (X >> Y) pred X => X swap(pred) 0 if Y != 0
{
const APInt *Shift;
if (match(Op0, m_LShr(m_Specific(Op1), m_APInt(Shift))) &&
!Shift->isZero()) {
return new ICmpInst(ICmpInst::getSwappedPredicate(Pred), Op1,
Constant::getNullValue(Op1->getType()));
}

if ((Pred == CmpInst::ICMP_SLT || Pred == CmpInst::ICMP_SGE) &&
match(Op0, m_AShr(m_Specific(Op1), m_APInt(Shift))) &&
!Shift->isZero()) {
return new ICmpInst(ICmpInst::getSwappedPredicate(Pred), Op1,
Constant::getNullValue(Op1->getType()));
}
}

return nullptr;
}

Expand Down
50 changes: 35 additions & 15 deletions llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "llvm/Analysis/BlockFrequencyInfo.h"
#include "llvm/Analysis/DomTreeUpdater.h"
#include "llvm/Analysis/GlobalsModRef.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/Analysis/PostDominators.h"
#include "llvm/Analysis/ProfileSummaryInfo.h"
#include "llvm/Analysis/StackSafetyAnalysis.h"
Expand Down Expand Up @@ -1492,23 +1493,42 @@ bool HWAddressSanitizer::instrumentStack(memtag::StackInfo &SInfo,
return true;
}

static void emitRemark(const Function &F, OptimizationRemarkEmitter &ORE,
bool Skip) {
if (Skip) {
ORE.emit([&]() {
return OptimizationRemark(DEBUG_TYPE, "Skip", &F)
<< "Skipped: F=" << ore::NV("Function", &F);
});
} else {
ORE.emit([&]() {
return OptimizationRemarkMissed(DEBUG_TYPE, "Sanitize", &F)
<< "Sanitized: F=" << ore::NV("Function", &F);
});
}
}

bool HWAddressSanitizer::selectiveInstrumentationShouldSkip(
Function &F, FunctionAnalysisManager &FAM) const {
if (ClRandomSkipRate.getNumOccurrences()) {
std::bernoulli_distribution D(ClRandomSkipRate);
return !D(*Rng);
}
if (!ClHotPercentileCutoff.getNumOccurrences())
return false;
auto &MAMProxy = FAM.getResult<ModuleAnalysisManagerFunctionProxy>(F);
ProfileSummaryInfo *PSI =
MAMProxy.getCachedResult<ProfileSummaryAnalysis>(*F.getParent());
if (!PSI || !PSI->hasProfileSummary()) {
++NumNoProfileSummaryFuncs;
return false;
}
return PSI->isFunctionHotInCallGraphNthPercentile(
ClHotPercentileCutoff, &F, FAM.getResult<BlockFrequencyAnalysis>(F));
bool Skip = [&]() {
if (ClRandomSkipRate.getNumOccurrences()) {
std::bernoulli_distribution D(ClRandomSkipRate);
return !D(*Rng);
}
if (!ClHotPercentileCutoff.getNumOccurrences())
return false;
auto &MAMProxy = FAM.getResult<ModuleAnalysisManagerFunctionProxy>(F);
ProfileSummaryInfo *PSI =
MAMProxy.getCachedResult<ProfileSummaryAnalysis>(*F.getParent());
if (!PSI || !PSI->hasProfileSummary()) {
++NumNoProfileSummaryFuncs;
return false;
}
return PSI->isFunctionHotInCallGraphNthPercentile(
ClHotPercentileCutoff, &F, FAM.getResult<BlockFrequencyAnalysis>(F));
}();
emitRemark(F, FAM.getResult<OptimizationRemarkEmitterAnalysis>(F), Skip);
return Skip;
}

void HWAddressSanitizer::sanitizeFunction(Function &F,
Expand Down
61 changes: 59 additions & 2 deletions llvm/lib/Transforms/Utils/SCCPSolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ static bool refineInstruction(SCCPSolver &Solver,
};

if (isa<OverflowingBinaryOperator>(Inst)) {
if (Inst.hasNoSignedWrap() && Inst.hasNoUnsignedWrap())
return false;

auto RangeA = GetRange(Inst.getOperand(0));
auto RangeB = GetRange(Inst.getOperand(1));
if (!Inst.hasNoUnsignedWrap()) {
Expand All @@ -146,6 +149,24 @@ static bool refineInstruction(SCCPSolver &Solver,
Inst.setNonNeg();
Changed = true;
}
} else if (TruncInst *TI = dyn_cast<TruncInst>(&Inst)) {
if (TI->hasNoSignedWrap() && TI->hasNoUnsignedWrap())
return false;

auto Range = GetRange(Inst.getOperand(0));
uint64_t DestWidth = TI->getDestTy()->getScalarSizeInBits();
if (!TI->hasNoUnsignedWrap()) {
if (Range.getActiveBits() <= DestWidth) {
TI->setHasNoUnsignedWrap(true);
Changed = true;
}
}
if (!TI->hasNoSignedWrap()) {
if (Range.getMinSignedBits() <= DestWidth) {
TI->setHasNoSignedWrap(true);
Changed = true;
}
}
}

return Changed;
Expand Down Expand Up @@ -428,6 +449,13 @@ class SCCPInstVisitor : public InstVisitor<SCCPInstVisitor> {
return markConstant(ValueState[V], V, C);
}

/// markConstantRange - Mark the object as constant range with \p CR. If the
/// object is not a constant range with the range \p CR, add it to the
/// instruction work list so that the users of the instruction are updated
/// later.
bool markConstantRange(ValueLatticeElement &IV, Value *V,
const ConstantRange &CR);

// markOverdefined - Make a value be marked as "overdefined". If the
// value is not already overdefined, add it to the overdefined instruction
// work list so that the users of the instruction are updated later.
Expand Down Expand Up @@ -788,6 +816,17 @@ class SCCPInstVisitor : public InstVisitor<SCCPInstVisitor> {
markOverdefined(ValueState[V], V);
}

void trackValueOfArgument(Argument *A) {
if (A->getType()->isIntegerTy()) {
if (std::optional<ConstantRange> Range = A->getRange()) {
markConstantRange(ValueState[A], A, *Range);
return;
}
}
// Assume nothing about the incoming arguments without range.
markOverdefined(A);
}

bool isStructLatticeConstant(Function *F, StructType *STy);

Constant *getConstant(const ValueLatticeElement &LV, Type *Ty) const;
Expand Down Expand Up @@ -873,6 +912,15 @@ bool SCCPInstVisitor::markConstant(ValueLatticeElement &IV, Value *V,
return true;
}

bool SCCPInstVisitor::markConstantRange(ValueLatticeElement &IV, Value *V,
const ConstantRange &CR) {
if (!IV.markConstantRange(CR))
return false;
LLVM_DEBUG(dbgs() << "markConstantRange: " << CR << ": " << *V << '\n');
pushToWorkList(IV, V);
return true;
}

bool SCCPInstVisitor::markOverdefined(ValueLatticeElement &IV, Value *V) {
if (!IV.markOverdefined())
return false;
Expand Down Expand Up @@ -1581,10 +1629,15 @@ void SCCPInstVisitor::visitStoreInst(StoreInst &SI) {
}

static ValueLatticeElement getValueFromMetadata(const Instruction *I) {
if (MDNode *Ranges = I->getMetadata(LLVMContext::MD_range))
if (I->getType()->isIntegerTy())
if (I->getType()->isIntegerTy()) {
if (MDNode *Ranges = I->getMetadata(LLVMContext::MD_range))
return ValueLatticeElement::getRange(
getConstantRangeFromMetadata(*Ranges));

if (const auto *CB = dyn_cast<CallBase>(I))
if (std::optional<ConstantRange> Range = CB->getRange())
return ValueLatticeElement::getRange(*Range);
}
if (I->hasMetadata(LLVMContext::MD_nonnull))
return ValueLatticeElement::getNot(
ConstantPointerNull::get(cast<PointerType>(I->getType())));
Expand Down Expand Up @@ -2090,6 +2143,10 @@ const SmallPtrSet<Function *, 16> SCCPSolver::getMRVFunctionsTracked() {

void SCCPSolver::markOverdefined(Value *V) { Visitor->markOverdefined(V); }

void SCCPSolver::trackValueOfArgument(Argument *V) {
Visitor->trackValueOfArgument(V);
}

bool SCCPSolver::isStructLatticeConstant(Function *F, StructType *STy) {
return Visitor->isStructLatticeConstant(F, STy);
}
Expand Down
57 changes: 54 additions & 3 deletions llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,32 @@ static bool isCommutative(Instruction *I) {
if (auto *Cmp = dyn_cast<CmpInst>(I))
return Cmp->isCommutative();
if (auto *BO = dyn_cast<BinaryOperator>(I))
return BO->isCommutative();
return BO->isCommutative() ||
(BO->getOpcode() == Instruction::Sub &&
!BO->hasNUsesOrMore(UsesLimit) &&
all_of(
BO->uses(),
[](const Use &U) {
// Commutative, if icmp eq/ne sub, 0
ICmpInst::Predicate Pred;
if (match(U.getUser(),
m_ICmp(Pred, m_Specific(U.get()), m_Zero())) &&
(Pred == ICmpInst::ICMP_EQ || Pred == ICmpInst::ICMP_NE))
return true;
// Commutative, if abs(sub nsw, true) or abs(sub, false).
ConstantInt *Flag;
return match(U.getUser(),
m_Intrinsic<Intrinsic::abs>(
m_Specific(U.get()), m_ConstantInt(Flag))) &&
(!cast<Instruction>(U.get())->hasNoSignedWrap() ||
Flag->isOne());
})) ||
(BO->getOpcode() == Instruction::FSub &&
!BO->hasNUsesOrMore(UsesLimit) &&
all_of(BO->uses(), [](const Use &U) {
return match(U.getUser(),
m_Intrinsic<Intrinsic::fabs>(m_Specific(U.get())));
}));
return I->isCommutative();
}

Expand Down Expand Up @@ -6838,7 +6863,7 @@ void BoUpSLP::buildTree_rec(ArrayRef<Value *> VL, unsigned Depth,

// Sort operands of the instructions so that each side is more likely to
// have the same opcode.
if (isa<BinaryOperator>(VL0) && VL0->isCommutative()) {
if (isa<BinaryOperator>(VL0) && isCommutative(VL0)) {
ValueList Left, Right;
reorderInputsAccordingToOpcode(VL, Left, Right, *this);
TE->setOperand(0, Left);
Expand Down Expand Up @@ -9020,6 +9045,9 @@ BoUpSLP::getEntryCost(const TreeEntry *E, ArrayRef<Value *> VectorizedVals,
VecOpcode =
SrcIt->second.second ? Instruction::SExt : Instruction::ZExt;
}
} else if (VecOpcode == Instruction::SIToFP && SrcIt != MinBWs.end() &&
!SrcIt->second.second) {
VecOpcode = Instruction::UIToFP;
}
auto GetScalarCost = [&](unsigned Idx) -> InstructionCost {
auto *VI = cast<Instruction>(UniqueValues[Idx]);
Expand Down Expand Up @@ -12398,6 +12426,9 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E, bool PostponedPHIs) {
VecOpcode =
SrcIt->second.second ? Instruction::SExt : Instruction::ZExt;
}
} else if (VecOpcode == Instruction::SIToFP && SrcIt != MinBWs.end() &&
!SrcIt->second.second) {
VecOpcode = Instruction::UIToFP;
}
Value *V = (VecOpcode != ShuffleOrOp && VecOpcode == Instruction::BitCast)
? InVec
Expand Down Expand Up @@ -12560,8 +12591,15 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E, bool PostponedPHIs) {
static_cast<Instruction::BinaryOps>(E->getOpcode()), LHS,
RHS);
propagateIRFlags(V, E->Scalars, VL0, It == MinBWs.end());
if (auto *I = dyn_cast<Instruction>(V))
if (auto *I = dyn_cast<Instruction>(V)) {
V = propagateMetadata(I, E->Scalars);
// Drop nuw flags for abs(sub(commutative), true).
if (!MinBWs.contains(E) && ShuffleOrOp == Instruction::Sub &&
any_of(E->Scalars, [](Value *V) {
return isCommutative(cast<Instruction>(V));
}))
I->setHasNoUnsignedWrap(/*b=*/false);
}

V = FinalShuffle(V, E, VecTy);

Expand Down Expand Up @@ -12887,6 +12925,19 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E, bool PostponedPHIs) {

propagateIRFlags(V0, OpScalars, E->getMainOp(), It == MinBWs.end());
propagateIRFlags(V1, AltScalars, E->getAltOp(), It == MinBWs.end());
auto DropNuwFlag = [&](Value *Vec, unsigned Opcode) {
// Drop nuw flags for abs(sub(commutative), true).
if (auto *I = dyn_cast<Instruction>(Vec);
I && Opcode == Instruction::Sub && !MinBWs.contains(E) &&
any_of(E->Scalars, [](Value *V) {
auto *IV = cast<Instruction>(V);
return IV->getOpcode() == Instruction::Sub &&
isCommutative(cast<Instruction>(IV));
}))
I->setHasNoUnsignedWrap(/*b=*/false);
};
DropNuwFlag(V0, E->getOpcode());
DropNuwFlag(V1, E->getAltOpcode());

Value *V = Builder.CreateShuffleVector(V0, V1, Mask);
if (auto *I = dyn_cast<Instruction>(V)) {
Expand Down
Loading