diff --git a/Help/manual/cmake-modules.7.rst b/Help/manual/cmake-modules.7.rst
index 5e96d795431b556278065d4932fa29635f583b61..1e8342cc842847afd2daa6a2f7f85c1c705867b8 100644
--- a/Help/manual/cmake-modules.7.rst
+++ b/Help/manual/cmake-modules.7.rst
@@ -27,6 +27,7 @@ All Modules
    /module/CheckFortranFunctionExists
    /module/CheckFortranSourceCompiles
    /module/CheckFunctionExists
+   /module/CheckIPOSupported
    /module/CheckIncludeFileCXX
    /module/CheckIncludeFile
    /module/CheckIncludeFiles
diff --git a/Help/module/CheckIPOSupported.rst b/Help/module/CheckIPOSupported.rst
new file mode 100644
index 0000000000000000000000000000000000000000..9c8a77b0596c283612ded80614fd3bf55d7d7a50
--- /dev/null
+++ b/Help/module/CheckIPOSupported.rst
@@ -0,0 +1 @@
+.. cmake-module:: ../../Modules/CheckIPOSupported.cmake
diff --git a/Help/release/dev/CheckIPOSupported.rst b/Help/release/dev/CheckIPOSupported.rst
new file mode 100644
index 0000000000000000000000000000000000000000..dbc84e61841a25a5488b48069d2b336cf432b64b
--- /dev/null
+++ b/Help/release/dev/CheckIPOSupported.rst
@@ -0,0 +1,6 @@
+CheckIPOSupported
+-----------------
+
+* A :module:`CheckIPOSupported` module was added to help projects
+  check whether interprocedural optimization (IPO) is supported by
+  the current toolchain and CMake version.
diff --git a/Modules/CheckIPOSupported.cmake b/Modules/CheckIPOSupported.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..6f7bc8279d627f087e47478639716fabf88f654a
--- /dev/null
+++ b/Modules/CheckIPOSupported.cmake
@@ -0,0 +1,215 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+CheckIPOSupported
+-----------------
+
+Check whether the compiler supports an interprocedural optimization (IPO/LTO).
+Use this before enabling the :prop_tgt:`INTERPROCEDURAL_OPTIMIZATION` target
+property.
+
+.. command:: check_ipo_supported
+
+  ::
+
+    check_ipo_supported([RESULT <result>] [OUTPUT <output>]
+                        [LANGUAGES <lang>...])
+
+  Options are:
+
+  ``RESULT <result>``
+    Set ``<result>`` variable to ``YES`` if IPO is supported by the
+    compiler and ``NO`` otherwise.  If this option is not given then
+    the command will issue a fatal error if IPO is not supported.
+  ``OUTPUT <output>``
+    Set ``<output>`` variable with details about any error.
+  ``LANGUAGES <lang>...``
+    Specify languages whose compilers to check.
+    Languages ``C`` and ``CXX`` are supported.
+
+Examples
+^^^^^^^^
+
+.. code-block:: cmake
+
+  check_ipo_supported() # fatal error if IPO is not supported
+  set_property(TARGET foo PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
+
+.. code-block:: cmake
+
+  # Optional IPO. Do not use IPO if it's not supported by compiler.
+  check_ipo_supported(RESULT result OUTPUT output)
+  if(result)
+    set_property(TARGET foo PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
+  else()
+    message(WARNING "IPO is not supported: ${output}")
+  endif()
+
+#]=======================================================================]
+
+include(CMakeParseArguments) # cmake_parse_arguments
+
+# X_RESULT - name of the final result variable
+# X_OUTPUT - name of the variable with information about error
+macro(_ipo_not_supported output)
+  string(COMPARE EQUAL "${X_RESULT}" "" is_empty)
+  if(is_empty)
+    message(FATAL_ERROR "IPO is not supported (${output}).")
+  endif()
+
+  set("${X_RESULT}" NO PARENT_SCOPE)
+  set("${X_OUTPUT}" "${output}" PARENT_SCOPE)
+endmacro()
+
+# Run IPO/LTO test
+macro(_ipo_run_language_check language)
+  set(testdir "${CMAKE_CURRENT_BINARY_DIR}/_CMakeLTOTest-${language}")
+
+  file(REMOVE_RECURSE "${testdir}")
+  file(MAKE_DIRECTORY "${testdir}")
+
+  set(bindir "${testdir}/bin")
+  set(srcdir "${testdir}/src")
+
+  file(MAKE_DIRECTORY "${bindir}")
+  file(MAKE_DIRECTORY "${srcdir}")
+
+  set(TRY_COMPILE_PROJECT_NAME "lto-test")
+
+  set(try_compile_src "${CMAKE_ROOT}/Modules/CheckIPOSupported")
+
+  # Use:
+  # * TRY_COMPILE_PROJECT_NAME
+  # * CMAKE_VERSION
+  configure_file(
+      "${try_compile_src}/CMakeLists-${language}.txt.in"
+      "${srcdir}/CMakeLists.txt"
+      @ONLY
+  )
+
+  string(COMPARE EQUAL "${language}" "C" is_c)
+  string(COMPARE EQUAL "${language}" "CXX" is_cxx)
+
+  if(is_c)
+    set(copy_sources foo.c main.c)
+  elseif(is_cxx)
+    set(copy_sources foo.cpp main.cpp)
+  else()
+    message(FATAL_ERROR "Language not supported")
+  endif()
+
+  foreach(x ${copy_sources})
+    configure_file(
+        "${try_compile_src}/${x}"
+        "${srcdir}/${x}"
+        COPYONLY
+    )
+  endforeach()
+
+  try_compile(
+      result
+      "${bindir}"
+      "${srcdir}"
+      "${TRY_COMPILE_PROJECT_NAME}"
+      CMAKE_FLAGS
+      "-DCMAKE_VERBOSE_MAKEFILE=ON"
+      "-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON"
+      OUTPUT_VARIABLE output
+  )
+
+  if(NOT result)
+    _ipo_not_supported("${output}")
+    return()
+  endif()
+endmacro()
+
+function(check_ipo_supported)
+  # TODO: IPO policy
+
+  set(optional)
+  set(one RESULT OUTPUT)
+  set(multiple LANGUAGES)
+
+  # Introduce:
+  # * X_RESULT
+  # * X_OUTPUT
+  # * X_LANGUAGES
+  cmake_parse_arguments(X "${optional}" "${one}" "${multiple}" "${ARGV}")
+
+  string(COMPARE NOTEQUAL "${X_UNPARSED_ARGUMENTS}" "" has_unparsed)
+  if(has_unparsed)
+    message(FATAL_ERROR "Unparsed arguments: ${X_UNPARSED_ARGUMENTS}")
+  endif()
+
+  string(COMPARE EQUAL "${X_LANGUAGES}" "" no_languages)
+  if(no_languages)
+    # User did not set any languages, use defaults
+    get_property(enabled_languages GLOBAL PROPERTY ENABLED_LANGUAGES)
+    string(COMPARE EQUAL "${enabled_languages}" "" no_languages)
+    if(no_languages)
+      _ipo_not_supported(
+          "no languages found in ENABLED_LANGUAGES global property"
+      )
+      return()
+    endif()
+
+    set(languages "")
+    list(FIND enabled_languages "CXX" result)
+    if(NOT result EQUAL -1)
+      list(APPEND languages "CXX")
+    endif()
+
+    list(FIND enabled_languages "C" result)
+    if(NOT result EQUAL -1)
+      list(APPEND languages "C")
+    endif()
+
+    list(FIND enabled_languages "Fortran" result)
+    if(NOT result EQUAL -1)
+      list(APPEND languages "Fortran")
+    endif()
+
+    string(COMPARE EQUAL "${languages}" "" no_languages)
+    if(no_languages)
+      _ipo_not_supported(
+          "no C/CXX/Fortran languages found in ENABLED_LANGUAGES global property"
+      )
+      return()
+    endif()
+  else()
+    set(languages "${X_LANGUAGES}")
+
+    set(unsupported_languages "${languages}")
+    list(REMOVE_ITEM unsupported_languages "C" "CXX" "Fortran")
+    string(COMPARE NOTEQUAL "${unsupported_languages}" "" has_unsupported)
+    if(has_unsupported)
+      _ipo_not_supported(
+          "language(s) '${unsupported_languages}' not supported"
+      )
+      return()
+    endif()
+  endif()
+
+  list(FIND languages "Fortran" result)
+  if(NOT result EQUAL -1)
+    _ipo_not_supported("Fortran is not supported")
+    return()
+  endif()
+
+  if(NOT _CMAKE_IPO_SUPPORTED_BY_CMAKE)
+    _ipo_not_supported("CMake doesn't support IPO for current compiler")
+    return()
+  endif()
+
+  if(NOT _CMAKE_IPO_MAY_BE_SUPPORTED_BY_COMPILER)
+    _ipo_not_supported("compiler doesn't support IPO")
+    return()
+  endif()
+
+  foreach(x ${languages})
+    _ipo_run_language_check(${x})
+  endforeach()
+
+  set("${X_RESULT}" YES PARENT_SCOPE)
+endfunction()
diff --git a/Modules/CheckIPOSupported/CMakeLists-C.txt.in b/Modules/CheckIPOSupported/CMakeLists-C.txt.in
new file mode 100644
index 0000000000000000000000000000000000000000..d20f31f2dd541da763f6829d2cc0c17dcbdb7df6
--- /dev/null
+++ b/Modules/CheckIPOSupported/CMakeLists-C.txt.in
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION "@CMAKE_VERSION@")
+project("@TRY_COMPILE_PROJECT_NAME@" LANGUAGES C)
+
+# TODO: IPO policy
+
+add_library(foo foo.c)
+add_executable(boo main.c)
+target_link_libraries(boo PUBLIC foo)
diff --git a/Modules/CheckIPOSupported/CMakeLists-CXX.txt.in b/Modules/CheckIPOSupported/CMakeLists-CXX.txt.in
new file mode 100644
index 0000000000000000000000000000000000000000..4b55c70f97c9473cdeacc75a524650b786b70155
--- /dev/null
+++ b/Modules/CheckIPOSupported/CMakeLists-CXX.txt.in
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION "@CMAKE_VERSION@")
+project("@TRY_COMPILE_PROJECT_NAME@" LANGUAGES CXX)
+
+# TODO: IPO policy
+
+add_library(foo foo.cpp)
+add_executable(boo main.cpp)
+target_link_libraries(boo PUBLIC foo)
diff --git a/Modules/CheckIPOSupported/foo.c b/Modules/CheckIPOSupported/foo.c
new file mode 100644
index 0000000000000000000000000000000000000000..1e5659789e0e865dce3c3a6b907561f1dfddf23a
--- /dev/null
+++ b/Modules/CheckIPOSupported/foo.c
@@ -0,0 +1,4 @@
+int foo()
+{
+  return 0x42;
+}
diff --git a/Modules/CheckIPOSupported/foo.cpp b/Modules/CheckIPOSupported/foo.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1e5659789e0e865dce3c3a6b907561f1dfddf23a
--- /dev/null
+++ b/Modules/CheckIPOSupported/foo.cpp
@@ -0,0 +1,4 @@
+int foo()
+{
+  return 0x42;
+}
diff --git a/Modules/CheckIPOSupported/main.c b/Modules/CheckIPOSupported/main.c
new file mode 100644
index 0000000000000000000000000000000000000000..5be0864eeeeaab3b406d13850f01829597e918f3
--- /dev/null
+++ b/Modules/CheckIPOSupported/main.c
@@ -0,0 +1,6 @@
+int foo();
+
+int main()
+{
+  return foo();
+}
diff --git a/Modules/CheckIPOSupported/main.cpp b/Modules/CheckIPOSupported/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5be0864eeeeaab3b406d13850f01829597e918f3
--- /dev/null
+++ b/Modules/CheckIPOSupported/main.cpp
@@ -0,0 +1,6 @@
+int foo();
+
+int main()
+{
+  return foo();
+}
diff --git a/Modules/Platform/Linux-Intel.cmake b/Modules/Platform/Linux-Intel.cmake
index 85a07728e82a42b6f0c13614e1cd4138db623013..45dc36fa84e317ebce5699ade44d452c9ce462ad 100644
--- a/Modules/Platform/Linux-Intel.cmake
+++ b/Modules/Platform/Linux-Intel.cmake
@@ -30,12 +30,17 @@ macro(__linux_compiler_intel lang)
   # executables that use dlopen but do not set ENABLE_EXPORTS.
   set(CMAKE_SHARED_LIBRARY_LINK_${lang}_FLAGS "-rdynamic")
 
+  set(_CMAKE_IPO_SUPPORTED_BY_CMAKE YES)
+
   if(XIAR)
     # INTERPROCEDURAL_OPTIMIZATION
     set(CMAKE_${lang}_COMPILE_OPTIONS_IPO -ipo)
     set(CMAKE_${lang}_CREATE_STATIC_LIBRARY_IPO
       "${XIAR} cr <TARGET> <LINK_FLAGS> <OBJECTS> "
       "${XIAR} -s <TARGET> ")
+    set(_CMAKE_IPO_MAY_BE_SUPPORTED_BY_COMPILER YES)
+  else()
+    set(_CMAKE_IPO_MAY_BE_SUPPORTED_BY_COMPILER NO)
   endif()
 
   if(NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 12.0)