From 2046d72e91670114625c87e122db6e013ba089d5 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Sun, 22 Dec 2019 13:57:46 -0800 Subject: [PATCH 1/7] build: improve python checks for Windows Require a newer CMake on Windows to use the Python3 support that is packaged in CMake. This version is able to check both 32-bit and 64-bit versions and will setup everything properly without the user needing to specify PYTHON_HOME. This enables building lldb's python bindings on Windows under Azure's CI again. --- lldb/CMakeLists.txt | 3 + lldb/cmake/modules/LLDBConfig.cmake | 189 ++++------------------------ 2 files changed, 25 insertions(+), 167 deletions(-) diff --git a/lldb/CMakeLists.txt b/lldb/CMakeLists.txt index ff3d8ae707471..6170ab625c54d 100644 --- a/lldb/CMakeLists.txt +++ b/lldb/CMakeLists.txt @@ -1,4 +1,7 @@ cmake_minimum_required(VERSION 3.4.3) +if(CMAKE_SYSTEM_NAME STREQUAL Windows) + cmake_minimum_required(VERSION 3.13) +endif() if(POLICY CMP0075) cmake_policy(SET CMP0075 NEW) diff --git a/lldb/cmake/modules/LLDBConfig.cmake b/lldb/cmake/modules/LLDBConfig.cmake index c34ef76cb6521..e1da76cf62498 100644 --- a/lldb/cmake/modules/LLDBConfig.cmake +++ b/lldb/cmake/modules/LLDBConfig.cmake @@ -138,184 +138,39 @@ if (LLDB_ENABLE_LIBEDIT) set(CMAKE_EXTRA_INCLUDE_FILES) endif() -# On Windows, we can't use the normal FindPythonLibs module that comes with CMake, -# for a number of reasons. -# 1) Prior to MSVC 2015, it is only possible to embed Python if python itself was -# compiled with an identical version (and build configuration) of MSVC as LLDB. -# The standard algorithm does not take into account the differences between -# a binary release distribution of python and a custom built distribution. -# 2) From MSVC 2015 and onwards, it is only possible to use Python 3.5 or later. -# 3) FindPythonLibs queries the registry to locate Python, and when looking for a -# 64-bit version of Python, since cmake.exe is a 32-bit executable, it will see -# a 32-bit view of the registry. As such, it is impossible for FindPythonLibs to -# locate 64-bit Python libraries. -# This function is designed to address those limitations. Currently it only partially -# addresses them, but it can be improved and extended on an as-needed basis. -function(find_python_libs_windows_helper LOOKUP_DEBUG OUT_EXE_PATH_VARNAME OUT_LIB_PATH_VARNAME OUT_DLL_PATH_VARNAME OUT_VERSION_VARNAME) - if(LOOKUP_DEBUG) - set(POSTFIX "_d") - else() - set(POSTFIX "") - endif() - - file(TO_CMAKE_PATH "${PYTHON_HOME}/python${POSTFIX}.exe" PYTHON_EXE) - file(TO_CMAKE_PATH "${PYTHON_HOME}/libs/${PYTHONLIBS_BASE_NAME}${POSTFIX}.lib" PYTHON_LIB) - file(TO_CMAKE_PATH "${PYTHON_HOME}/${PYTHONLIBS_BASE_NAME}${POSTFIX}.dll" PYTHON_DLL) - - foreach(component PYTHON_EXE;PYTHON_LIB;PYTHON_DLL) - if(NOT EXISTS ${${component}}) - message(WARNING "Unable to find ${component}") - unset(${component}) - endif() - endforeach() - - if (NOT PYTHON_EXE OR NOT PYTHON_LIB OR NOT PYTHON_DLL) - message(WARNING "Unable to find all Python components. Python support will be disabled for this build.") - set(LLDB_ENABLE_PYTHON 0 PARENT_SCOPE) - return() - endif() - - # Find the version of the Python interpreter. - execute_process(COMMAND "${PYTHON_EXE}" -c - "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:3]]))" - OUTPUT_VARIABLE PYTHON_VERSION_OUTPUT - RESULT_VARIABLE PYTHON_VERSION_RESULT - ERROR_QUIET) - - if(PYTHON_VERSION_RESULT) - message(WARNING "Unable to retrieve Python executable version") - set(PYTHON_VERSION_OUTPUT "") - endif() - - set(${OUT_EXE_PATH_VARNAME} ${PYTHON_EXE} PARENT_SCOPE) - set(${OUT_LIB_PATH_VARNAME} ${PYTHON_LIB} PARENT_SCOPE) - set(${OUT_DLL_PATH_VARNAME} ${PYTHON_DLL} PARENT_SCOPE) - set(${OUT_VERSION_VARNAME} ${PYTHON_VERSION_OUTPUT} PARENT_SCOPE) -endfunction() - -function(find_python_libs_windows) - if ("${PYTHON_HOME}" STREQUAL "") - message(WARNING "LLDB embedded Python on Windows requires specifying a value for PYTHON_HOME. Python support disabled.") - set(LLDB_ENABLE_PYTHON 0 PARENT_SCOPE) - return() - endif() - - file(TO_CMAKE_PATH "${PYTHON_HOME}/Include" PYTHON_INCLUDE_DIR) - - if(EXISTS "${PYTHON_INCLUDE_DIR}/patchlevel.h") - file(STRINGS "${PYTHON_INCLUDE_DIR}/patchlevel.h" python_version_str - REGEX "^#define[ \t]+PY_VERSION[ \t]+\"[^\"]+\"") - string(REGEX REPLACE "^#define[ \t]+PY_VERSION[ \t]+\"([^\"+]+)[+]?\".*" "\\1" - PYTHONLIBS_VERSION_STRING "${python_version_str}") - message(STATUS "Found Python library version ${PYTHONLIBS_VERSION_STRING}") - string(REGEX REPLACE "([0-9]+)[.]([0-9]+)[.][0-9]+" "python\\1\\2" PYTHONLIBS_BASE_NAME "${PYTHONLIBS_VERSION_STRING}") - unset(python_version_str) - else() - message(WARNING "Unable to find ${PYTHON_INCLUDE_DIR}/patchlevel.h, Python installation is corrupt.") - message(WARNING "Python support will be disabled for this build.") - set(LLDB_ENABLE_PYTHON 0 PARENT_SCOPE) - return() - endif() - - file(TO_CMAKE_PATH "${PYTHON_HOME}" PYTHON_HOME) - # TODO(compnerd) when CMake Policy `CMP0091` is set to NEW, we should use - # if(CMAKE_MSVC_RUNTIME_LIBRARY MATCHES MultiThreadedDebug) - if(NOT DEFINED CMAKE_BUILD_TYPE) - # Multi-target generator was selected (like Visual Studio or Xcode) where no concrete build type was passed - # Lookup for both debug and release python installations - find_python_libs_windows_helper(TRUE PYTHON_DEBUG_EXE PYTHON_DEBUG_LIB PYTHON_DEBUG_DLL PYTHON_DEBUG_VERSION_STRING) - find_python_libs_windows_helper(FALSE PYTHON_RELEASE_EXE PYTHON_RELEASE_LIB PYTHON_RELEASE_DLL PYTHON_RELEASE_VERSION_STRING) - if(NOT LLDB_ENABLE_PYTHON) - set(LLDB_ENABLE_PYTHON 0 PARENT_SCOPE) - return() - endif() - - # We should have been found both debug and release python here - # Now check that their versions are equal - if(NOT PYTHON_DEBUG_VERSION_STRING STREQUAL PYTHON_RELEASE_VERSION_STRING) - message(FATAL_ERROR "Python versions for debug (${PYTHON_DEBUG_VERSION_STRING}) and release (${PYTHON_RELEASE_VERSION_STRING}) are different." - "Python installation is corrupted") - endif () - - set(PYTHON_EXECUTABLE $<$:${PYTHON_DEBUG_EXE}>$<$>:${PYTHON_RELEASE_EXE}>) - set(PYTHON_LIBRARY $<$:${PYTHON_DEBUG_LIB}>$<$>:${PYTHON_RELEASE_LIB}>) - set(PYTHON_DLL $<$:${PYTHON_DEBUG_DLL}>$<$>:${PYTHON_RELEASE_DLL}>) - set(PYTHON_VERSION_STRING ${PYTHON_RELEASE_VERSION_STRING}) - else() - # Lookup for concrete python installation depending on build type - if (CMAKE_BUILD_TYPE STREQUAL Debug) - set(LOOKUP_DEBUG_PYTHON TRUE) - else() - set(LOOKUP_DEBUG_PYTHON FALSE) - endif() - find_python_libs_windows_helper(${LOOKUP_DEBUG_PYTHON} PYTHON_EXECUTABLE PYTHON_LIBRARY PYTHON_DLL PYTHON_VERSION_STRING) - if(NOT LLDB_ENABLE_PYTHON) - set(LLDB_ENABLE_PYTHON 0 PARENT_SCOPE) - return() - endif() - endif() - - if(PYTHON_VERSION_STRING) - string(REPLACE "." ";" PYTHON_VERSION_PARTS "${PYTHON_VERSION_STRING}") - list(GET PYTHON_VERSION_PARTS 0 PYTHON_VERSION_MAJOR) - list(GET PYTHON_VERSION_PARTS 1 PYTHON_VERSION_MINOR) - list(GET PYTHON_VERSION_PARTS 2 PYTHON_VERSION_PATCH) - else() - unset(PYTHON_VERSION_MAJOR) - unset(PYTHON_VERSION_MINOR) - unset(PYTHON_VERSION_PATCH) - endif() - - # Set the same variables as FindPythonInterp and FindPythonLibs. - set(PYTHON_EXECUTABLE "${PYTHON_EXECUTABLE}" CACHE PATH "") - set(PYTHON_LIBRARY "${PYTHON_LIBRARY}" CACHE PATH "") - set(PYTHON_DLL "${PYTHON_DLL}" CACHE PATH "") - set(PYTHON_INCLUDE_DIR "${PYTHON_INCLUDE_DIR}" CACHE PATH "") - set(PYTHONLIBS_VERSION_STRING "${PYTHONLIBS_VERSION_STRING}" PARENT_SCOPE) - set(PYTHON_VERSION_STRING "${PYTHON_VERSION_STRING}" PARENT_SCOPE) - set(PYTHON_VERSION_MAJOR "${PYTHON_VERSION_MAJOR}" PARENT_SCOPE) - set(PYTHON_VERSION_MINOR "${PYTHON_VERSION_MINOR}" PARENT_SCOPE) - set(PYTHON_VERSION_PATCH "${PYTHON_VERSION_PATCH}" PARENT_SCOPE) - - message(STATUS "LLDB Found PythonExecutable: ${PYTHON_EXECUTABLE} (${PYTHON_VERSION_STRING})") - message(STATUS "LLDB Found PythonLibs: ${PYTHON_LIBRARY} (${PYTHONLIBS_VERSION_STRING})") - message(STATUS "LLDB Found PythonDLL: ${PYTHON_DLL}") - message(STATUS "LLDB Found PythonIncludeDirs: ${PYTHON_INCLUDE_DIR}") -endfunction(find_python_libs_windows) - -# Call find_python_libs_windows ahead of the rest of the python configuration. -# It's possible that it won't find a python installation and will then set -# LLDB_ENABLE_PYTHON to OFF. -if (LLDB_ENABLE_PYTHON AND "${CMAKE_SYSTEM_NAME}" STREQUAL "Windows") - find_python_libs_windows() -endif() - if (LLDB_ENABLE_PYTHON) if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows") + find_package(Python3 COMPONENTS Interpreter Development REQUIRED) + if(Python3_VERSION VERSION_LESS 3.5) + message(SEND_ERROR "Python 3.5 or newer is required (found: ${Python3_VERSION}") + endif() + set(PYTHON_LIBRARY ${Python3_LIBRARIES}) + include_directories(${Python3_INCLUDE_DIRS}) + if (NOT LLDB_RELOCATABLE_PYTHON) file(TO_CMAKE_PATH "${PYTHON_HOME}" LLDB_PYTHON_HOME) endif() else() find_package(PythonInterp REQUIRED) find_package(PythonLibs REQUIRED) - endif() - if (NOT CMAKE_CROSSCOMPILING) - string(REPLACE "." ";" pythonlibs_version_list ${PYTHONLIBS_VERSION_STRING}) - list(GET pythonlibs_version_list 0 pythonlibs_major) - list(GET pythonlibs_version_list 1 pythonlibs_minor) - - # Ignore the patch version. Some versions of macOS report a different patch - # version for the system provided interpreter and libraries. - if (NOT PYTHON_VERSION_MAJOR VERSION_EQUAL pythonlibs_major OR - NOT PYTHON_VERSION_MINOR VERSION_EQUAL pythonlibs_minor) - message(FATAL_ERROR "Found incompatible Python interpreter (${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR})" - " and Python libraries (${pythonlibs_major}.${pythonlibs_minor})") + if (NOT CMAKE_CROSSCOMPILING) + string(REPLACE "." ";" pythonlibs_version_list ${PYTHONLIBS_VERSION_STRING}) + list(GET pythonlibs_version_list 0 pythonlibs_major) + list(GET pythonlibs_version_list 1 pythonlibs_minor) + + # Ignore the patch version. Some versions of macOS report a different patch + # version for the system provided interpreter and libraries. + if (NOT PYTHON_VERSION_MAJOR VERSION_EQUAL pythonlibs_major OR + NOT PYTHON_VERSION_MINOR VERSION_EQUAL pythonlibs_minor) + message(FATAL_ERROR "Found incompatible Python interpreter (${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR})" + " and Python libraries (${pythonlibs_major}.${pythonlibs_minor})") + endif() endif() - endif() - if (PYTHON_INCLUDE_DIR) - include_directories(${PYTHON_INCLUDE_DIR}) + if (PYTHON_INCLUDE_DIR) + include_directories(${PYTHON_INCLUDE_DIR}) + endif() endif() endif() From 2791667d2e3fb8c1f0abaff93fd8caaabb2b00b9 Mon Sep 17 00:00:00 2001 From: Carl Ritson Date: Fri, 20 Dec 2019 12:51:50 +0900 Subject: [PATCH 2/7] [DAGCombiner] Check term use before applying aggressive FSUB optimisations Summary: Without this check unnecessary FMA instructions are generated when the FSUB terms are reused. This also has the side-effect that the same value is computed to different levels of precision, which can create undesirable effects if the results are used together in subsequent computation. Reviewers: arsenm, nhaehnle, foad, tpr, dstuttard, spatel Reviewed By: arsenm Subscribers: jvesely, wdng, hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D71656 --- llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 9 +- .../CodeGen/AMDGPU/fadd-fma-fmul-combine.ll | 118 +++++++++++++++++- 2 files changed, 122 insertions(+), 5 deletions(-) diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index 11756bb0ebbbf..1ae2f58415fa6 100644 --- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -11879,7 +11879,8 @@ SDValue DAGCombiner::visitFSUBForFMACombine(SDNode *N) { // fold (fsub x, (fma y, z, (fmul u, v))) // -> (fma (fneg y), z, (fma (fneg u), v, x)) if (CanFuse && N1.getOpcode() == PreferredFusedOpcode && - isContractableFMUL(N1.getOperand(2))) { + isContractableFMUL(N1.getOperand(2)) && + N1->hasOneUse()) { SDValue N20 = N1.getOperand(2).getOperand(0); SDValue N21 = N1.getOperand(2).getOperand(1); return DAG.getNode(PreferredFusedOpcode, SL, VT, @@ -11894,7 +11895,8 @@ SDValue DAGCombiner::visitFSUBForFMACombine(SDNode *N) { // fold (fsub (fma x, y, (fpext (fmul u, v))), z) // -> (fma x, y (fma (fpext u), (fpext v), (fneg z))) - if (N0.getOpcode() == PreferredFusedOpcode) { + if (N0.getOpcode() == PreferredFusedOpcode && + N0->hasOneUse()) { SDValue N02 = N0.getOperand(2); if (N02.getOpcode() == ISD::FP_EXTEND) { SDValue N020 = N02.getOperand(0); @@ -11946,7 +11948,8 @@ SDValue DAGCombiner::visitFSUBForFMACombine(SDNode *N) { // fold (fsub x, (fma y, z, (fpext (fmul u, v)))) // -> (fma (fneg y), z, (fma (fneg (fpext u)), (fpext v), x)) if (N1.getOpcode() == PreferredFusedOpcode && - N1.getOperand(2).getOpcode() == ISD::FP_EXTEND) { + N1.getOperand(2).getOpcode() == ISD::FP_EXTEND && + N1->hasOneUse()) { SDValue N120 = N1.getOperand(2).getOperand(0); if (isContractableFMUL(N120) && TLI.isFPExtFoldable(DAG, PreferredFusedOpcode, VT, diff --git a/llvm/test/CodeGen/AMDGPU/fadd-fma-fmul-combine.ll b/llvm/test/CodeGen/AMDGPU/fadd-fma-fmul-combine.ll index 0c4a77964d154..f66ea152257f7 100644 --- a/llvm/test/CodeGen/AMDGPU/fadd-fma-fmul-combine.ll +++ b/llvm/test/CodeGen/AMDGPU/fadd-fma-fmul-combine.ll @@ -219,7 +219,7 @@ define amdgpu_kernel void @fast_sub_fmuladd_fmul_multi_use_mul() #0 { ret void } -; GCN-LABEL: {{^}}fast_sub_fmuladd_fmul_multi_use_fmuladd: +; GCN-LABEL: {{^}}fast_sub_fmuladd_fmul_multi_use_fmuladd_lhs: ; GCN: buffer_load_dword [[X:v[0-9]+]] ; GCN: buffer_load_dword [[Y:v[0-9]+]] ; GCN: buffer_load_dword [[Z:v[0-9]+]] @@ -241,7 +241,7 @@ define amdgpu_kernel void @fast_sub_fmuladd_fmul_multi_use_mul() #0 { ; GCN-SLOWFMA-DAG: v_mul_f32_e32 v{{[0-9]+}}, [[X]], [[Y]] ; GCN-SLOWFMA: v_add_f32_e32 ; GCN-SLOWFMA: v_sub_f32_e32 -define amdgpu_kernel void @fast_sub_fmuladd_fmul_multi_use_fmuladd() #0 { +define amdgpu_kernel void @fast_sub_fmuladd_fmul_multi_use_fmuladd_lhs() #0 { %x = load volatile float, float addrspace(1)* undef %y = load volatile float, float addrspace(1)* undef %z = load volatile float, float addrspace(1)* undef @@ -255,6 +255,120 @@ define amdgpu_kernel void @fast_sub_fmuladd_fmul_multi_use_fmuladd() #0 { ret void } +; GCN-LABEL: {{^}}fast_sub_fmuladd_fmul_multi_use_fmuladd_rhs: +; GCN: buffer_load_dword [[X:v[0-9]+]] +; GCN: buffer_load_dword [[Y:v[0-9]+]] +; GCN: buffer_load_dword [[Z:v[0-9]+]] +; GCN: buffer_load_dword [[U:v[0-9]+]] +; GCN: buffer_load_dword [[V:v[0-9]+]] + +; GCN-DAG: v_mul_f32_e32 [[MUL:v[0-9]+]], [[U]], [[V]] + +; GCN-FLUSH-NEXT: v_mac_f32_e32 [[MUL]], [[X]], [[Y]] +; GCN-FLUSH-NEXT: v_sub_f32_e32 [[SUB:v[0-9]+]], [[Z]], [[MUL]] +; GCN-FLUSH-NEXT: buffer_store_dword [[MUL]] +; GCN-FLUSH-NEXT: buffer_store_dword [[SUB]] + +; GCN-FASTFMA-NEXT: v_fma_f32 [[FMA:v[0-9]+]], [[X]], [[Y]], [[U]] +; GCN-FASTFMA-NEXT: v_sub_f32_e32 [[SUB:v[0-9]+]], [[Z]], [[FMA]] +; GCN-FASTFMA-NEXT: buffer_store_dword [[FMA]] +; GCN-FASTFMA-NEXT: buffer_store_dword [[SUB]] + +; GCN-SLOWFMA-DAG: v_mul_f32_e32 v{{[0-9]+}}, [[X]], [[Y]] +; GCN-SLOWFMA: v_add_f32_e32 +; GCN-SLOWFMA: v_sub_f32_e32 +define amdgpu_kernel void @fast_sub_fmuladd_fmul_multi_use_fmuladd_rhs() #0 { + %x = load volatile float, float addrspace(1)* undef + %y = load volatile float, float addrspace(1)* undef + %z = load volatile float, float addrspace(1)* undef + %u = load volatile float, float addrspace(1)* undef + %v = load volatile float, float addrspace(1)* undef + %mul.u.v = fmul fast float %u, %v + %fma = call fast float @llvm.fmuladd.f32(float %x, float %y, float %mul.u.v) + %add = fsub fast float %z, %fma + store volatile float %fma, float addrspace(1)* undef + store volatile float %add, float addrspace(1)* undef + ret void +} + +; GCN-LABEL: {{^}}fast_sub_fmuladd_fpext_fmul_multi_use_fmuladd_lhs: +; GCN: buffer_load_dword [[X:v[0-9]+]] +; GCN: buffer_load_dword [[Y:v[0-9]+]] +; GCN: buffer_load_dword [[Z:v[0-9]+]] +; GCN: buffer_load_ushort [[U:v[0-9]+]] +; GCN: buffer_load_ushort [[V:v[0-9]+]] + +; GCN-DAG: v_cvt_f32_f16_e32 [[UFLOAT:v[0-9]+]], [[U]] +; GCN-DAG: v_cvt_f32_f16_e32 [[VFLOAT:v[0-9]+]], [[V]] +; GCN-DAG: v_mul_f32_e32 [[MUL:v[0-9]+]], [[UFLOAT]], [[VFLOAT]] + +; GCN-FLUSH-NEXT: v_mac_f32_e32 [[MUL]], [[X]], [[Y]] +; GCN-FLUSH-NEXT: v_sub_f32_e32 [[SUB:v[0-9]+]], [[MUL]], [[Z]] +; GCN-FLUSH-NEXT: buffer_store_dword [[MUL]] +; GCN-FLUSH-NEXT: buffer_store_dword [[SUB]] + +; GCN-FASTFMA-NEXT: v_fma_f32 [[FMA:v[0-9]+]], [[X]], [[Y]], [[UFLOAT]] +; GCN-FASTFMA-NEXT: v_sub_f32_e32 [[SUB:v[0-9]+]], [[FMA]], [[Z]] +; GCN-FASTFMA-NEXT: buffer_store_dword [[FMA]] +; GCN-FASTFMA-NEXT: buffer_store_dword [[SUB]] + +; GCN-SLOWFMA-DAG: v_mul_f32_e32 v{{[0-9]+}}, [[X]], [[Y]] +; GCN-SLOWFMA: v_add_f32_e32 +; GCN-SLOWFMA: v_sub_f32_e32 +define amdgpu_kernel void @fast_sub_fmuladd_fpext_fmul_multi_use_fmuladd_lhs() #0 { + %x = load volatile float, float addrspace(1)* undef + %y = load volatile float, float addrspace(1)* undef + %z = load volatile float, float addrspace(1)* undef + %u = load volatile half, half addrspace(1)* undef + %v = load volatile half, half addrspace(1)* undef + %mul.u.v.half = fmul fast half %u, %v + %mul.u.v = fpext half %mul.u.v.half to float + %fma = call fast float @llvm.fmuladd.f32(float %x, float %y, float %mul.u.v) + %add = fsub fast float %fma, %z + store volatile float %fma, float addrspace(1)* undef + store volatile float %add, float addrspace(1)* undef + ret void +} + +; GCN-LABEL: {{^}}fast_sub_fmuladd_fpext_fmul_multi_use_fmuladd_rhs: +; GCN: buffer_load_dword [[X:v[0-9]+]] +; GCN: buffer_load_dword [[Y:v[0-9]+]] +; GCN: buffer_load_dword [[Z:v[0-9]+]] +; GCN: buffer_load_ushort [[U:v[0-9]+]] +; GCN: buffer_load_ushort [[V:v[0-9]+]] + +; GCN-DAG: v_cvt_f32_f16_e32 [[UFLOAT:v[0-9]+]], [[U]] +; GCN-DAG: v_cvt_f32_f16_e32 [[VFLOAT:v[0-9]+]], [[V]] +; GCN-DAG: v_mul_f32_e32 [[MUL:v[0-9]+]], [[UFLOAT]], [[VFLOAT]] + +; GCN-FLUSH-NEXT: v_mac_f32_e32 [[MUL]], [[X]], [[Y]] +; GCN-FLUSH-NEXT: v_sub_f32_e32 [[SUB:v[0-9]+]], [[Z]], [[MUL]] +; GCN-FLUSH-NEXT: buffer_store_dword [[MUL]] +; GCN-FLUSH-NEXT: buffer_store_dword [[SUB]] + +; GCN-FASTFMA-NEXT: v_fma_f32 [[FMA:v[0-9]+]], [[X]], [[Y]], [[UFLOAT]] +; GCN-FASTFMA-NEXT: v_sub_f32_e32 [[SUB:v[0-9]+]], [[Z]], [[FMA]] +; GCN-FASTFMA-NEXT: buffer_store_dword [[FMA]] +; GCN-FASTFMA-NEXT: buffer_store_dword [[SUB]] + +; GCN-SLOWFMA-DAG: v_mul_f32_e32 v{{[0-9]+}}, [[X]], [[Y]] +; GCN-SLOWFMA: v_add_f32_e32 +; GCN-SLOWFMA: v_sub_f32_e32 +define amdgpu_kernel void @fast_sub_fmuladd_fpext_fmul_multi_use_fmuladd_rhs() #0 { + %x = load volatile float, float addrspace(1)* undef + %y = load volatile float, float addrspace(1)* undef + %z = load volatile float, float addrspace(1)* undef + %u = load volatile half, half addrspace(1)* undef + %v = load volatile half, half addrspace(1)* undef + %mul.u.v.half = fmul fast half %u, %v + %mul.u.v = fpext half %mul.u.v.half to float + %fma = call fast float @llvm.fmuladd.f32(float %x, float %y, float %mul.u.v) + %add = fsub fast float %z, %fma + store volatile float %fma, float addrspace(1)* undef + store volatile float %add, float addrspace(1)* undef + ret void +} + declare float @llvm.fma.f32(float, float, float) #1 declare float @llvm.fmuladd.f32(float, float, float) #1 From bd5c8d167b7cce3290d755e29623d047c2ad8e3e Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Sun, 22 Dec 2019 16:46:01 -0800 Subject: [PATCH 3/7] [lldb/ScriptInterpreter] Unify error message for command script import Rather than checking for Python explicitly, let the script interpreter handle things and print an error if the functionality is not supported. --- lldb/include/lldb/Interpreter/ScriptInterpreter.h | 5 +---- lldb/source/Commands/CommandObjectCommands.cpp | 7 ------- lldb/source/Interpreter/ScriptInterpreter.cpp | 8 ++++++++ lldb/test/Shell/ScriptInterpreter/None/import_module.test | 2 ++ 4 files changed, 11 insertions(+), 11 deletions(-) create mode 100644 lldb/test/Shell/ScriptInterpreter/None/import_module.test diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreter.h b/lldb/include/lldb/Interpreter/ScriptInterpreter.h index b32962b803552..4b866949514d4 100644 --- a/lldb/include/lldb/Interpreter/ScriptInterpreter.h +++ b/lldb/include/lldb/Interpreter/ScriptInterpreter.h @@ -459,10 +459,7 @@ class ScriptInterpreter : public PluginInterface { virtual bool LoadScriptingModule(const char *filename, bool can_reload, bool init_session, lldb_private::Status &error, - StructuredData::ObjectSP *module_sp = nullptr) { - error.SetErrorString("loading unimplemented"); - return false; - } + StructuredData::ObjectSP *module_sp = nullptr); virtual bool IsReservedWord(const char *word) { return false; } diff --git a/lldb/source/Commands/CommandObjectCommands.cpp b/lldb/source/Commands/CommandObjectCommands.cpp index b47cc372b4c1d..36d6b83d11561 100644 --- a/lldb/source/Commands/CommandObjectCommands.cpp +++ b/lldb/source/Commands/CommandObjectCommands.cpp @@ -1426,13 +1426,6 @@ class CommandObjectCommandsScriptImport : public CommandObjectParsed { }; bool DoExecute(Args &command, CommandReturnObject &result) override { - if (GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython) { - result.AppendError("only scripting language supported for module " - "importing is currently Python"); - result.SetStatus(eReturnStatusFailed); - return false; - } - if (command.empty()) { result.AppendError("command script import needs one or more arguments"); result.SetStatus(eReturnStatusFailed); diff --git a/lldb/source/Interpreter/ScriptInterpreter.cpp b/lldb/source/Interpreter/ScriptInterpreter.cpp index 0ef859061ab11..c7207db5523d6 100644 --- a/lldb/source/Interpreter/ScriptInterpreter.cpp +++ b/lldb/source/Interpreter/ScriptInterpreter.cpp @@ -42,6 +42,14 @@ void ScriptInterpreter::CollectDataForWatchpointCommandCallback( "This script interpreter does not support watchpoint callbacks."); } +bool ScriptInterpreter::LoadScriptingModule( + const char *filename, bool can_reload, bool init_session, + lldb_private::Status &error, StructuredData::ObjectSP *module_sp) { + error.SetErrorString( + "This script interpreter does not support importing modules."); + return false; +} + std::string ScriptInterpreter::LanguageToString(lldb::ScriptLanguage language) { switch (language) { case eScriptLanguageNone: diff --git a/lldb/test/Shell/ScriptInterpreter/None/import_module.test b/lldb/test/Shell/ScriptInterpreter/None/import_module.test new file mode 100644 index 0000000000000..0af7bfaf24f45 --- /dev/null +++ b/lldb/test/Shell/ScriptInterpreter/None/import_module.test @@ -0,0 +1,2 @@ +# RUN: %lldb --script-language none -o 'command script import %t' 2>&1 | FileCheck %s +# CHECK: error: module importing failed: This script interpreter does not support importing modules. From 2539cd22e96ef53da204c9bb28b8a38a582c1309 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Sun, 22 Dec 2019 16:55:38 -0800 Subject: [PATCH 4/7] [ELF] Delete a redundant R_HINT check from isStaticLinkTimeConstant(). NFC scanReloc() returns when it sees an R_HINT. --- lld/ELF/Relocations.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index 78bafe53023e0..c5aa801dee7c0 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -375,8 +375,8 @@ static bool isStaticLinkTimeConstant(RelExpr e, RelType type, const Symbol &sym, R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC, R_GOTPLTONLY_PC, R_PLT_PC, R_TLSGD_GOT, R_TLSGD_GOTPLT, R_TLSGD_PC, R_PPC32_PLTREL, R_PPC64_CALL_PLT, R_PPC64_RELAX_TOC, R_RISCV_ADD, R_TLSDESC_CALL, - R_TLSDESC_PC, R_AARCH64_TLSDESC_PAGE, R_HINT, R_TLSLD_HINT, - R_TLSIE_HINT>(e)) + R_TLSDESC_PC, R_AARCH64_TLSDESC_PAGE, R_TLSLD_HINT, R_TLSIE_HINT>( + e)) return true; // These never do, except if the entire file is position dependent or if From 7259f04dde82502f133117c5a80eebd92a5fe092 Mon Sep 17 00:00:00 2001 From: czhengsz Date: Sun, 22 Dec 2019 20:58:19 -0500 Subject: [PATCH 5/7] [SCEV] add testcase for get accurate range for addrecexpr with nuw flag --- .../Analysis/ScalarEvolution/range_nw_flag.ll | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/llvm/test/Analysis/ScalarEvolution/range_nw_flag.ll b/llvm/test/Analysis/ScalarEvolution/range_nw_flag.ll index c5640bf6dda30..65ecd312e0cbb 100644 --- a/llvm/test/Analysis/ScalarEvolution/range_nw_flag.ll +++ b/llvm/test/Analysis/ScalarEvolution/range_nw_flag.ll @@ -19,3 +19,23 @@ exit: ret void } +; CHECK-LABEL: @test-addrec-nuw +; CHECK: --> {(1 + (10 smax %offset)),+,1}<%loop> U: full-set S: full-set +define void @test-addrec-nuw(float* %input, i32 %offset, i32 %numIterations) { +entry: + %cmp = icmp sgt i32 %offset, 10 + %min.10 = select i1 %cmp, i32 %offset, i32 10 + br label %loop +loop: + %i = phi i32 [ %nexti, %loop ], [ 0, %entry ] + %nexti = add nuw i32 %i, 1 + %index32 = add nuw i32 %nexti, %min.10 + %ptr = getelementptr inbounds float, float* %input, i32 %index32 + %f = load float, float* %ptr, align 4 + %exitcond = icmp eq i32 %nexti, %numIterations + br i1 %exitcond, label %exit, label %loop + +exit: + ret void +} + From fb53396c49493e3dfd51bb75ca822bd9896210f6 Mon Sep 17 00:00:00 2001 From: Shengchen Kan Date: Mon, 23 Dec 2019 10:22:02 +0800 Subject: [PATCH 6/7] [NFC] Remove unnecessary blank and rename align-branch-64-5b.s to align-branch-64-6a.s --- llvm/include/llvm/MC/MCFragment.h | 4 ++-- .../MC/X86/{align-branch-64-5b.s => align-branch-64-6a.s} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename llvm/test/MC/X86/{align-branch-64-5b.s => align-branch-64-6a.s} (100%) diff --git a/llvm/include/llvm/MC/MCFragment.h b/llvm/include/llvm/MC/MCFragment.h index 892b65c43cf7f..246c17fe0ce50 100644 --- a/llvm/include/llvm/MC/MCFragment.h +++ b/llvm/include/llvm/MC/MCFragment.h @@ -592,8 +592,8 @@ class MCBoundaryAlignFragment : public MCFragment { uint64_t getSize() const { return Size; } void setSize(uint64_t Value) { Size = Value; } - Align getAlignment() const { return AlignBoundary; } - + Align getAlignment() const { return AlignBoundary; } + bool isFused() const { return Fused; } void setFused(bool Value) { Fused = Value; } diff --git a/llvm/test/MC/X86/align-branch-64-5b.s b/llvm/test/MC/X86/align-branch-64-6a.s similarity index 100% rename from llvm/test/MC/X86/align-branch-64-5b.s rename to llvm/test/MC/X86/align-branch-64-6a.s From e3d8ee35e4adca664a9149536e0f0b3b0ceaeaeb Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Fri, 22 Nov 2019 08:45:37 -0800 Subject: [PATCH 7/7] reland "[DebugInfo] Support to emit debugInfo for extern variables" Commit d77ae1552fc21a9f3877f3ed7e13d631f517c825 ("[DebugInfo] Support to emit debugInfo for extern variables") added deebugInfo for extern variables for BPF target. The commit is reverted by 891e25b02d760d0de18c7d46947913b3166047e7 as the committed tests using %clang instead of %clang_cc1 causing test failed in certain scenarios as reported by Reid Kleckner. This patch fixed the tests by using %clang_cc1. Differential Revision: https://reviews.llvm.org/D71818 --- clang/include/clang/AST/ASTConsumer.h | 5 ++++ clang/include/clang/Basic/TargetInfo.h | 3 +++ clang/include/clang/Sema/Sema.h | 3 +++ clang/lib/Basic/Targets/BPF.h | 2 ++ clang/lib/CodeGen/CGDebugInfo.cpp | 23 ++++++++++++++-- clang/lib/CodeGen/CGDebugInfo.h | 3 +++ clang/lib/CodeGen/CodeGenAction.cpp | 4 +++ clang/lib/CodeGen/CodeGenModule.cpp | 17 ++++++++++++ clang/lib/CodeGen/CodeGenModule.h | 3 +++ clang/lib/CodeGen/ModuleBuilder.cpp | 4 +++ clang/lib/Sema/Sema.cpp | 7 +++++ clang/lib/Sema/SemaDecl.cpp | 4 +++ clang/test/CodeGen/debug-info-extern-basic.c | 26 +++++++++++++++++++ .../CodeGen/debug-info-extern-duplicate.c | 10 +++++++ clang/test/CodeGen/debug-info-extern-multi.c | 22 ++++++++++++++++ clang/test/CodeGen/debug-info-extern-unused.c | 26 +++++++++++++++++++ llvm/include/llvm/IR/DIBuilder.h | 2 +- llvm/lib/IR/DIBuilder.cpp | 5 ++-- llvm/lib/IR/DebugInfo.cpp | 2 +- .../Transforms/Utils/CloningTest.cpp | 2 +- 20 files changed, 166 insertions(+), 7 deletions(-) create mode 100644 clang/test/CodeGen/debug-info-extern-basic.c create mode 100644 clang/test/CodeGen/debug-info-extern-duplicate.c create mode 100644 clang/test/CodeGen/debug-info-extern-multi.c create mode 100644 clang/test/CodeGen/debug-info-extern-unused.c diff --git a/clang/include/clang/AST/ASTConsumer.h b/clang/include/clang/AST/ASTConsumer.h index dc216a89c205f..ecdd8e873e1e9 100644 --- a/clang/include/clang/AST/ASTConsumer.h +++ b/clang/include/clang/AST/ASTConsumer.h @@ -102,6 +102,11 @@ class ASTConsumer { /// modified by the introduction of an implicit zero initializer. virtual void CompleteTentativeDefinition(VarDecl *D) {} + /// CompleteExternalDeclaration - Callback invoked at the end of a translation + /// unit to notify the consumer that the given external declaration should be + /// completed. + virtual void CompleteExternalDeclaration(VarDecl *D) {} + /// Callback invoked when an MSInheritanceAttr has been attached to a /// CXXRecordDecl. virtual void AssignInheritanceModel(CXXRecordDecl *RD) {} diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index 33cecdadc686c..bc06f59d41d44 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -1389,6 +1389,9 @@ class TargetInfo : public virtual TransferrableTargetInfo, virtual void setAuxTarget(const TargetInfo *Aux) {} + /// Whether target allows debuginfo types for decl only variables. + virtual bool allowDebugInfoForExternalVar() const { return false; } + protected: /// Copy type and layout related info. void copyAuxTarget(const TargetInfo *Aux); diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 8cce6fdb1259f..41c0e14591993 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -668,6 +668,9 @@ class Sema final { /// All the tentative definitions encountered in the TU. TentativeDefinitionsType TentativeDefinitions; + /// All the external declarations encoutered and used in the TU. + SmallVector ExternalDeclarations; + typedef LazyVector UnusedFileScopedDeclsType; diff --git a/clang/lib/Basic/Targets/BPF.h b/clang/lib/Basic/Targets/BPF.h index 117f81430bf40..b2f1831e960e6 100644 --- a/clang/lib/Basic/Targets/BPF.h +++ b/clang/lib/Basic/Targets/BPF.h @@ -76,6 +76,8 @@ class LLVM_LIBRARY_VISIBILITY BPFTargetInfo : public TargetInfo { return None; } + bool allowDebugInfoForExternalVar() const override { return true; } + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { switch (CC) { default: diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 8858e08f2a776..675df309e3f0f 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -4485,7 +4485,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, GVE = DBuilder.createGlobalVariableExpression( DContext, DeclName, LinkageName, Unit, LineNo, getOrCreateType(T, Unit), - Var->hasLocalLinkage(), + Var->hasLocalLinkage(), true, Expr.empty() ? nullptr : DBuilder.createExpression(Expr), getOrCreateStaticDataMemberDeclarationOrNull(D), TemplateParameters, Align); @@ -4588,10 +4588,29 @@ void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD, const APValue &Init) { GV.reset(DBuilder.createGlobalVariableExpression( DContext, Name, StringRef(), Unit, getLineNumber(VD->getLocation()), Ty, - true, InitExpr, getOrCreateStaticDataMemberDeclarationOrNull(VarD), + true, true, InitExpr, getOrCreateStaticDataMemberDeclarationOrNull(VarD), TemplateParameters, Align)); } +void CGDebugInfo::EmitExternalVariable(llvm::GlobalVariable *Var, + const VarDecl *D) { + assert(DebugKind >= codegenoptions::LimitedDebugInfo); + if (D->hasAttr()) + return; + + auto Align = getDeclAlignIfRequired(D, CGM.getContext()); + llvm::DIFile *Unit = getOrCreateFile(D->getLocation()); + StringRef Name = D->getName(); + llvm::DIType *Ty = getOrCreateType(D->getType(), Unit); + + llvm::DIScope *DContext = getDeclContextDescriptor(D); + llvm::DIGlobalVariableExpression *GVE = + DBuilder.createGlobalVariableExpression( + DContext, Name, StringRef(), Unit, getLineNumber(D->getLocation()), + Ty, false, false, nullptr, nullptr, nullptr, Align); + Var->addDebugInfo(GVE); +} + llvm::DIScope *CGDebugInfo::getCurrentContextDescriptor(const Decl *D) { if (!LexicalBlockStack.empty()) return LexicalBlockStack.back(); diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h index fed79f0095b52..90e9a61ebe96d 100644 --- a/clang/lib/CodeGen/CGDebugInfo.h +++ b/clang/lib/CodeGen/CGDebugInfo.h @@ -478,6 +478,9 @@ class CGDebugInfo { /// Emit a constant global variable's debug info. void EmitGlobalVariable(const ValueDecl *VD, const APValue &Init); + /// Emit information about an external variable. + void EmitExternalVariable(llvm::GlobalVariable *GV, const VarDecl *Decl); + /// Emit C++ using directive. void EmitUsingDirective(const UsingDirectiveDecl &UD); diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp index 95521495e133f..7f3f358d3d988 100644 --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -336,6 +336,10 @@ namespace clang { Gen->CompleteTentativeDefinition(D); } + void CompleteExternalDeclaration(VarDecl *D) override { + Gen->CompleteExternalDeclaration(D); + } + void AssignInheritanceModel(CXXRecordDecl *RD) override { Gen->AssignInheritanceModel(RD); } diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 02b2dd35bc9ad..1fc2beb12ed58 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -3730,6 +3730,10 @@ void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) { EmitGlobalVarDefinition(D); } +void CodeGenModule::EmitExternalDeclaration(const VarDecl *D) { + EmitExternalVarDeclaration(D); +} + CharUnits CodeGenModule::GetTargetTypeStoreSize(llvm::Type *Ty) const { return Context.toCharUnitsFromBits( getDataLayout().getTypeStoreSizeInBits(Ty)); @@ -4113,6 +4117,19 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D, DI->EmitGlobalVariable(GV, D); } +void CodeGenModule::EmitExternalVarDeclaration(const VarDecl *D) { + if (CGDebugInfo *DI = getModuleDebugInfo()) + if (getCodeGenOpts().getDebugInfo() >= codegenoptions::LimitedDebugInfo) { + QualType ASTTy = D->getType(); + llvm::Type *Ty = getTypes().ConvertTypeForMem(D->getType()); + llvm::PointerType *PTy = + llvm::PointerType::get(Ty, getContext().getTargetAddressSpace(ASTTy)); + llvm::Constant *GV = GetOrCreateLLVMGlobal(D->getName(), PTy, D); + DI->EmitExternalVariable( + cast(GV->stripPointerCasts()), D); + } +} + static bool isVarDeclStrongDefinition(const ASTContext &Context, CodeGenModule &CGM, const VarDecl *D, bool NoCommon) { diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 673eda3baa66c..9bf1c5ef610e4 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -1170,6 +1170,8 @@ class CodeGenModule : public CodeGenTypeCache { void EmitTentativeDefinition(const VarDecl *D); + void EmitExternalDeclaration(const VarDecl *D); + void EmitVTable(CXXRecordDecl *Class); void RefreshTypeCacheForClass(const CXXRecordDecl *Class); @@ -1405,6 +1407,7 @@ class CodeGenModule : public CodeGenTypeCache { void EmitMultiVersionFunctionDefinition(GlobalDecl GD, llvm::GlobalValue *GV); void EmitGlobalVarDefinition(const VarDecl *D, bool IsTentative = false); + void EmitExternalVarDeclaration(const VarDecl *D); void EmitAliasDefinition(GlobalDecl GD); void emitIFuncDefinition(GlobalDecl GD); void emitCPUDispatchDefinition(GlobalDecl GD); diff --git a/clang/lib/CodeGen/ModuleBuilder.cpp b/clang/lib/CodeGen/ModuleBuilder.cpp index 4154f6ebe736f..01093cf20c18c 100644 --- a/clang/lib/CodeGen/ModuleBuilder.cpp +++ b/clang/lib/CodeGen/ModuleBuilder.cpp @@ -290,6 +290,10 @@ namespace { Builder->EmitTentativeDefinition(D); } + void CompleteExternalDeclaration(VarDecl *D) override { + Builder->EmitExternalDeclaration(D); + } + void HandleVTable(CXXRecordDecl *RD) override { if (Diags.hasErrorOccurred()) return; diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 85548cbd86548..2cd158a8b43c1 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -1136,6 +1136,13 @@ void Sema::ActOnEndOfTranslationUnit() { Consumer.CompleteTentativeDefinition(VD); } + for (auto D : ExternalDeclarations) { + if (!D || D->isInvalidDecl() || D->getPreviousDecl() || !D->isUsed()) + continue; + + Consumer.CompleteExternalDeclaration(D); + } + // If there were errors, disable 'unused' warnings since they will mostly be // noise. Don't warn for a use from a module: either we should warn on all // file-scope declarations in modules or not at all, but whether the diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index f05a92008bfde..8f68be716bd37 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -12220,6 +12220,10 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) { Diag(Var->getLocation(), diag::note_private_extern); } + if (Context.getTargetInfo().allowDebugInfoForExternalVar() && + !Var->isInvalidDecl() && !getLangOpts().CPlusPlus) + ExternalDeclarations.push_back(Var); + return; case VarDecl::TentativeDefinition: diff --git a/clang/test/CodeGen/debug-info-extern-basic.c b/clang/test/CodeGen/debug-info-extern-basic.c new file mode 100644 index 0000000000000..e2c90842fffbb --- /dev/null +++ b/clang/test/CodeGen/debug-info-extern-basic.c @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -x c -debug-info-kind=limited -triple bpf-linux-gnu -emit-llvm %s -o - | FileCheck %s + +extern char ch; +int test() { + return ch; +} + +int test2() { + extern char ch2; + return ch2; +} + +extern int (*foo)(int); +int test3() { + return foo(0); +} + +// CHECK: distinct !DIGlobalVariable(name: "ch",{{.*}} type: ![[CHART:[0-9]+]], isLocal: false, isDefinition: false +// CHECK: distinct !DIGlobalVariable(name: "ch2",{{.*}} type: ![[CHART]], isLocal: false, isDefinition: false +// CHECK: ![[CHART]] = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) + +// CHECK: distinct !DIGlobalVariable(name: "foo",{{.*}} type: ![[FUNC:[0-9]+]], isLocal: false, isDefinition: false) +// CHECK: ![[FUNC]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[SUB:[0-9]+]], size: 64) +// CHECK: ![[SUB]] = !DISubroutineType(types: ![[TYPES:[0-9]+]]) +// CHECK: ![[TYPES]] = !{![[BASET:[0-9]+]], ![[BASET]]} +// CHECK: ![[BASET]] = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) diff --git a/clang/test/CodeGen/debug-info-extern-duplicate.c b/clang/test/CodeGen/debug-info-extern-duplicate.c new file mode 100644 index 0000000000000..1c6d86f4cc093 --- /dev/null +++ b/clang/test/CodeGen/debug-info-extern-duplicate.c @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -x c -debug-info-kind=limited -triple bpf-linux-gnu -emit-llvm %s -o - | FileCheck %s + +extern char ch; +extern char ch; +int test() { + return ch; +} + +// CHECK: distinct !DIGlobalVariable(name: "ch",{{.*}} type: ![[T:[0-9]+]], isLocal: false, isDefinition: false +// CHECK-NOT: distinct !DIGlobalVariable(name: "ch" diff --git a/clang/test/CodeGen/debug-info-extern-multi.c b/clang/test/CodeGen/debug-info-extern-multi.c new file mode 100644 index 0000000000000..6a9021d382b97 --- /dev/null +++ b/clang/test/CodeGen/debug-info-extern-multi.c @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -x c -debug-info-kind=limited -triple bpf-linux-gnu -emit-llvm %s -o - | FileCheck %s + +extern char ch; +int test() { + extern short sh; + return ch + sh; +} + +extern char (*foo)(char); +int test2() { + return foo(0) + ch; +} + +// CHECK: distinct !DIGlobalVariable(name: "ch",{{.*}} type: ![[Tch:[0-9]+]], isLocal: false, isDefinition: false +// CHECK: distinct !DIGlobalVariable(name: "sh",{{.*}} type: ![[Tsh:[0-9]+]], isLocal: false, isDefinition: false +// CHECK: ![[Tsh]] = !DIBasicType(name: "short", size: 16, encoding: DW_ATE_signed) + +// CHECK: distinct !DIGlobalVariable(name: "foo",{{.*}} type: ![[Tptr:[0-9]+]], isLocal: false, isDefinition: false +// ![[Tptr]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[Tsub:[0-9]+]], size: 64) +// ![[Tsub]] = !DISubroutineType(types: ![[Tproto:[0-9]+]]) +// ![[Tproto]] = !{![[Tch]], ![[Tch]]} +// CHECK: ![[Tch]] = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) diff --git a/clang/test/CodeGen/debug-info-extern-unused.c b/clang/test/CodeGen/debug-info-extern-unused.c new file mode 100644 index 0000000000000..8b89eaab27e62 --- /dev/null +++ b/clang/test/CodeGen/debug-info-extern-unused.c @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -x c -debug-info-kind=limited -triple bpf-linux-gnu -emit-llvm %s -o - | FileCheck %s + +extern char ch; +int test() { + return 0; +} + +int test2() { + extern char ch2; + return 0; +} + +extern int (*foo)(int); +int test3() { + return 0; +} + +int test4() { + extern int (*foo2)(int); + return 0; +} + +// CHECK-NOT: distinct !DIGlobalVariable(name: "ch" +// CHECK-NOT: distinct !DIGlobalVariable(name: "ch2" +// CHECK-NOT: distinct !DIGlobalVariable(name: "foo" +// CHECK-NOT: distinct !DIGlobalVariable(name: "foo2" diff --git a/llvm/include/llvm/IR/DIBuilder.h b/llvm/include/llvm/IR/DIBuilder.h index 48c0007b2ea53..7c0c5f54bb7ee 100644 --- a/llvm/include/llvm/IR/DIBuilder.h +++ b/llvm/include/llvm/IR/DIBuilder.h @@ -583,7 +583,7 @@ namespace llvm { /// specified) DIGlobalVariableExpression *createGlobalVariableExpression( DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *File, - unsigned LineNo, DIType *Ty, bool isLocalToUnit, + unsigned LineNo, DIType *Ty, bool isLocalToUnit, bool isDefined = true, DIExpression *Expr = nullptr, MDNode *Decl = nullptr, MDTuple *templateParams = nullptr, uint32_t AlignInBits = 0); diff --git a/llvm/lib/IR/DIBuilder.cpp b/llvm/lib/IR/DIBuilder.cpp index d918551a67c1c..9f5811d41b932 100644 --- a/llvm/lib/IR/DIBuilder.cpp +++ b/llvm/lib/IR/DIBuilder.cpp @@ -640,13 +640,14 @@ static void checkGlobalVariableScope(DIScope *Context) { DIGlobalVariableExpression *DIBuilder::createGlobalVariableExpression( DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *F, - unsigned LineNumber, DIType *Ty, bool isLocalToUnit, DIExpression *Expr, + unsigned LineNumber, DIType *Ty, bool isLocalToUnit, + bool isDefined, DIExpression *Expr, MDNode *Decl, MDTuple *templateParams, uint32_t AlignInBits) { checkGlobalVariableScope(Context); auto *GV = DIGlobalVariable::getDistinct( VMContext, cast_or_null(Context), Name, LinkageName, F, - LineNumber, Ty, isLocalToUnit, true, cast_or_null(Decl), + LineNumber, Ty, isLocalToUnit, isDefined, cast_or_null(Decl), templateParams, AlignInBits); if (!Expr) Expr = createExpression(); diff --git a/llvm/lib/IR/DebugInfo.cpp b/llvm/lib/IR/DebugInfo.cpp index 5bbd292582ee7..fe8311923109b 100644 --- a/llvm/lib/IR/DebugInfo.cpp +++ b/llvm/lib/IR/DebugInfo.cpp @@ -1289,7 +1289,7 @@ LLVMMetadataRef LLVMDIBuilderCreateGlobalVariableExpression( return wrap(unwrap(Builder)->createGlobalVariableExpression( unwrapDI(Scope), {Name, NameLen}, {Linkage, LinkLen}, unwrapDI(File), LineNo, unwrapDI(Ty), LocalToUnit, - unwrap(Expr), unwrapDI(Decl), + true, unwrap(Expr), unwrapDI(Decl), nullptr, AlignInBits)); } diff --git a/llvm/unittests/Transforms/Utils/CloningTest.cpp b/llvm/unittests/Transforms/Utils/CloningTest.cpp index 3d0bd10e87a99..28ad4bc880772 100644 --- a/llvm/unittests/Transforms/Utils/CloningTest.cpp +++ b/llvm/unittests/Transforms/Utils/CloningTest.cpp @@ -764,7 +764,7 @@ class CloneModule : public ::testing::Test { DBuilder.createGlobalVariableExpression( Subprogram, "unattached", "unattached", File, 1, - DBuilder.createNullPtrType(), false, Expr); + DBuilder.createNullPtrType(), false, true, Expr); auto *Entry = BasicBlock::Create(C, "", F); IBuilder.SetInsertPoint(Entry);