Vendor import of llvm trunk r307894:
https://llvm.org/svn/llvm-project/llvm/trunk@307894
This commit is contained in:
parent
9df3605dea
commit
ca089b24d4
@ -288,6 +288,10 @@ set(LLVM_LIBDIR_SUFFIX "" CACHE STRING "Define suffix of library directory name
|
||||
set(LLVM_TOOLS_INSTALL_DIR "bin" CACHE STRING "Path for binary subdirectory (defaults to 'bin')")
|
||||
mark_as_advanced(LLVM_TOOLS_INSTALL_DIR)
|
||||
|
||||
set(LLVM_UTILS_INSTALL_DIR "bin" CACHE STRING
|
||||
"Path to install LLVM utilities (enabled by LLVM_INSTALL_UTILS=ON) (defaults to LLVM_TOOLS_INSTALL_DIR)")
|
||||
mark_as_advanced(LLVM_TOOLS_INSTALL_DIR)
|
||||
|
||||
# They are used as destination of target generators.
|
||||
set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bin)
|
||||
set(LLVM_LIBRARY_OUTPUT_INTDIR ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX})
|
||||
|
@ -91,7 +91,7 @@ function(add_llvm_symbol_exports target_name export_file)
|
||||
DEPENDS ${export_file}
|
||||
VERBATIM
|
||||
COMMENT "Creating export file for ${target_name}")
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
|
||||
if (${LLVM_LINKER_IS_SOLARISLD})
|
||||
set_property(TARGET ${target_name} APPEND_STRING PROPERTY
|
||||
LINK_FLAGS " -Wl,-M,${CMAKE_CURRENT_BINARY_DIR}/${native_export_file}")
|
||||
else()
|
||||
@ -148,13 +148,28 @@ function(add_llvm_symbol_exports target_name export_file)
|
||||
endfunction(add_llvm_symbol_exports)
|
||||
|
||||
if(NOT WIN32 AND NOT APPLE)
|
||||
# Detect what linker we have here
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_C_COMPILER} -Wl,--version
|
||||
OUTPUT_VARIABLE stdout
|
||||
ERROR_QUIET
|
||||
ERROR_VARIABLE stderr
|
||||
)
|
||||
set(LLVM_LINKER_DETECTED ON)
|
||||
if("${stdout}" MATCHES "GNU gold")
|
||||
set(LLVM_LINKER_IS_GOLD ON)
|
||||
message(STATUS "Linker detection: GNU Gold")
|
||||
elseif("${stdout}" MATCHES "^LLD")
|
||||
set(LLVM_LINKER_IS_LLD ON)
|
||||
message(STATUS "Linker detection: LLD")
|
||||
elseif("${stdout}" MATCHES "GNU ld")
|
||||
set(LLVM_LINKER_IS_GNULD ON)
|
||||
message(STATUS "Linker detection: GNU ld")
|
||||
elseif("${stderr}" MATCHES "Solaris Link Editors")
|
||||
set(LLVM_LINKER_IS_SOLARISLD ON)
|
||||
message(STATUS "Linker detection: Solaris ld")
|
||||
else()
|
||||
set(LLVM_LINKER_DETECTED OFF)
|
||||
message(STATUS "Linker detection: unknown")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@ -865,7 +880,7 @@ macro(add_llvm_utility name)
|
||||
set_target_properties(${name} PROPERTIES FOLDER "Utils")
|
||||
if( LLVM_INSTALL_UTILS AND LLVM_BUILD_UTILS )
|
||||
install (TARGETS ${name}
|
||||
RUNTIME DESTINATION bin
|
||||
RUNTIME DESTINATION ${LLVM_UTILS_INSTALL_DIR}
|
||||
COMPONENT ${name})
|
||||
if (NOT CMAKE_CONFIGURATION_TYPES)
|
||||
add_custom_target(install-${name}
|
||||
@ -1159,11 +1174,6 @@ function(add_lit_target target comment)
|
||||
list(APPEND LIT_ARGS --param build_mode=${CMAKE_CFG_INTDIR})
|
||||
endif ()
|
||||
if (EXISTS ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py)
|
||||
# reset cache after erraneous r283029
|
||||
# TODO: remove this once all buildbots run
|
||||
if (LIT_COMMAND STREQUAL "${PYTHON_EXECUTABLE} ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py")
|
||||
unset(LIT_COMMAND CACHE)
|
||||
endif()
|
||||
set (LIT_COMMAND "${PYTHON_EXECUTABLE};${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py"
|
||||
CACHE STRING "Command used to spawn llvm-lit")
|
||||
else()
|
||||
|
@ -686,8 +686,8 @@ endif()
|
||||
# lld doesn't print colored diagnostics when invoked from Ninja
|
||||
if (UNIX AND CMAKE_GENERATOR STREQUAL "Ninja")
|
||||
include(CheckLinkerFlag)
|
||||
check_linker_flag("-Wl,-color-diagnostics" LINKER_SUPPORTS_COLOR_DIAGNOSTICS)
|
||||
append_if(LINKER_SUPPORTS_COLOR_DIAGNOSTICS "-Wl,-color-diagnostics"
|
||||
check_linker_flag("-Wl,--color-diagnostics" LINKER_SUPPORTS_COLOR_DIAGNOSTICS)
|
||||
append_if(LINKER_SUPPORTS_COLOR_DIAGNOSTICS "-Wl,--color-diagnostics"
|
||||
CMAKE_EXE_LINKER_FLAGS CMAKE_MODULE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS)
|
||||
endif()
|
||||
|
||||
|
@ -195,8 +195,16 @@ function(llvm_ExternalProject_Add name source_dir)
|
||||
|
||||
# Add top-level targets
|
||||
foreach(target ${ARG_EXTRA_TARGETS})
|
||||
string(REPLACE ":" ";" target_list ${target})
|
||||
list(GET target_list 0 target)
|
||||
list(LENGTH target_list target_list_len)
|
||||
if(${target_list_len} GREATER 1)
|
||||
list(GET target_list 1 target_name)
|
||||
else()
|
||||
set(target_name "${target}")
|
||||
endif()
|
||||
llvm_ExternalProject_BuildCmd(build_runtime_cmd ${target} ${BINARY_DIR})
|
||||
add_custom_target(${target}
|
||||
add_custom_target(${target_name}
|
||||
COMMAND ${build_runtime_cmd}
|
||||
DEPENDS ${name}-configure
|
||||
WORKING_DIRECTORY ${BINARY_DIR}
|
||||
|
@ -190,9 +190,7 @@ names from both the *Processor* and *Alternative Processor* can be used.
|
||||
gfx810 - stoney amdgcn APU
|
||||
**GCN GFX9**
|
||||
--------------------------------------------------------------------
|
||||
gfx900 amdgcn dGPU - FirePro W9500
|
||||
- FirePro S9500
|
||||
- FirePro S9500x2
|
||||
gfx900 amdgcn dGPU - Radeon Vega Frontier Edition
|
||||
gfx901 amdgcn dGPU ROCm Same as gfx900
|
||||
except XNACK is
|
||||
enabled
|
||||
|
@ -536,6 +536,11 @@ LLVM-specific variables
|
||||
during the build. Enabling this option can significantly speed up build times
|
||||
especially when building LLVM in Debug configurations.
|
||||
|
||||
**LLVM_REVERSE_ITERATION**:BOOL
|
||||
If enabled, all supported unordered llvm containers would be iterated in
|
||||
reverse order. This is useful for uncovering non-determinism caused by
|
||||
iteration of unordered containers.
|
||||
|
||||
CMake Caches
|
||||
============
|
||||
|
||||
|
@ -112,33 +112,6 @@ In this example the ``extra_sources`` variable is only defined if you're
|
||||
targeting an Apple platform. For all other targets the ``extra_sources`` will be
|
||||
evaluated as empty before add_executable is given its arguments.
|
||||
|
||||
One big "Gotcha" with variable dereferencing is that ``if`` commands implicitly
|
||||
dereference values. This has some unexpected results. For example:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
if("${SOME_VAR}" STREQUAL "MSVC")
|
||||
|
||||
In this code sample MSVC will be implicitly dereferenced, which will result in
|
||||
the if command comparing the value of the dereferenced variables ``SOME_VAR``
|
||||
and ``MSVC``. A common workaround to this solution is to prepend strings being
|
||||
compared with an ``x``.
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
if("x${SOME_VAR}" STREQUAL "xMSVC")
|
||||
|
||||
This works because while ``MSVC`` is a defined variable, ``xMSVC`` is not. This
|
||||
pattern is uncommon, but it does occur in LLVM's CMake scripts.
|
||||
|
||||
.. note::
|
||||
|
||||
Once the LLVM project upgrades its minimum CMake version to 3.1 or later we
|
||||
can prevent this behavior by setting CMP0054 to new. For more information on
|
||||
CMake policies please see the cmake-policies manpage or the `cmake-policies
|
||||
online documentation
|
||||
<https://cmake.org/cmake/help/v3.4/manual/cmake-policies.7.html>`_.
|
||||
|
||||
Lists
|
||||
-----
|
||||
|
||||
|
@ -169,6 +169,13 @@ SELECTION OPTIONS
|
||||
must be in the range ``1..M``. The environment variable
|
||||
``LIT_RUN_SHARD`` can also be used in place of this option.
|
||||
|
||||
.. option:: --filter=REGEXP
|
||||
|
||||
Run only those tests whose name matches the regular expression specified in
|
||||
``REGEXP``. The environment variable ``LIT_FILTER`` can be also used in place
|
||||
of this option, which is especially useful in environments where the call
|
||||
to ``lit`` is issued indirectly.
|
||||
|
||||
ADDITIONAL OPTIONS
|
||||
------------------
|
||||
|
||||
|
@ -262,6 +262,12 @@ OPTIONS
|
||||
The demangler is expected to read a newline-separated list of symbols from
|
||||
stdin and write a newline-separated list of the same length to stdout.
|
||||
|
||||
.. option:: -num-threads=N, -j=N
|
||||
|
||||
Use N threads to write file reports (only applicable when -output-dir is
|
||||
specified). When N=0, llvm-cov auto-detects an appropriate number of threads to
|
||||
use. This is the default.
|
||||
|
||||
.. option:: -line-coverage-gt=<N>
|
||||
|
||||
Show code coverage only for functions with line coverage greater than the
|
||||
|
@ -192,6 +192,12 @@ OPTIONS
|
||||
information is dumped in a more human readable form (also in text) with
|
||||
annotations.
|
||||
|
||||
.. option:: -topn=n
|
||||
|
||||
Instruct the profile dumper to show the top ``n`` functions with the
|
||||
hottest basic blocks in the summary section. By default, the topn functions
|
||||
are not dumped.
|
||||
|
||||
.. option:: -sample
|
||||
|
||||
Specify that the input profile is a sample-based profile.
|
||||
|
@ -846,7 +846,7 @@ Overview:
|
||||
"""""""""
|
||||
|
||||
The '``llvm.coro.alloc``' intrinsic returns `true` if dynamic allocation is
|
||||
required to obtain a memory for the corutine frame and `false` otherwise.
|
||||
required to obtain a memory for the coroutine frame and `false` otherwise.
|
||||
|
||||
Arguments:
|
||||
""""""""""
|
||||
|
@ -88,15 +88,11 @@ compiled by the system compiler in the debian8 image:
|
||||
./llvm/utils/docker/build_docker_image.sh \
|
||||
--source debian8 \
|
||||
--docker-repository clang-debian8 --docker-tag "staging" \
|
||||
-- \
|
||||
-p clang -i install-clang -i install-clang-headers \
|
||||
-- \
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
|
||||
Note there are two levels of ``--`` indirection. First one separates
|
||||
``build_docker_image.sh`` arguments from ``llvm/utils/build_install_llvm.sh``
|
||||
arguments. Second one separates CMake arguments from ``build_install_llvm.sh``
|
||||
arguments. Note that build like that doesn't use a 2-stage build process that
|
||||
Note that a build like that doesn't use a 2-stage build process that
|
||||
you probably want for clang. Running a 2-stage build is a little more intricate,
|
||||
this command will do that:
|
||||
|
||||
@ -108,7 +104,6 @@ this command will do that:
|
||||
./build_docker_image.sh \
|
||||
--source debian8 \
|
||||
--docker-repository clang-debian8 --docker-tag "staging" \
|
||||
-- \
|
||||
-p clang -i stage2-install-clang -i stage2-install-clang-headers \
|
||||
-- \
|
||||
-DLLVM_TARGETS_TO_BUILD=Native -DCMAKE_BUILD_TYPE=Release \
|
||||
@ -178,7 +173,6 @@ debian8-based image using the latest ``google/stable`` sources for you:
|
||||
|
||||
./llvm/utils/docker/build_docker_image.sh \
|
||||
-s debian8 --d clang-debian8 -t "staging" \
|
||||
-- \
|
||||
--branch branches/google/stable \
|
||||
-p clang -i install-clang -i install-clang-headers \
|
||||
-- \
|
||||
|
@ -62,6 +62,9 @@ Here are the steps you can follow to do so:
|
||||
lab.llvm.org:9990 \
|
||||
<buildslave-access-name> <buildslave-access-password>
|
||||
|
||||
To point a slave to silent master please use lab.llvm.org:9994 instead
|
||||
of lab.llvm.org:9990.
|
||||
|
||||
#. Fill the buildslave description and admin name/e-mail. Here is an
|
||||
example of the buildslave description::
|
||||
|
||||
|
236
docs/LangRef.rst
236
docs/LangRef.rst
@ -2209,12 +2209,21 @@ For a simpler introduction to the ordering constraints, see the
|
||||
same address in this global order. This corresponds to the C++0x/C1x
|
||||
``memory_order_seq_cst`` and Java volatile.
|
||||
|
||||
.. _singlethread:
|
||||
.. _syncscope:
|
||||
|
||||
If an atomic operation is marked ``singlethread``, it only *synchronizes
|
||||
with* or participates in modification and seq\_cst total orderings with
|
||||
other operations running in the same thread (for example, in signal
|
||||
handlers).
|
||||
If an atomic operation is marked ``syncscope("singlethread")``, it only
|
||||
*synchronizes with* and only participates in the seq\_cst total orderings of
|
||||
other operations running in the same thread (for example, in signal handlers).
|
||||
|
||||
If an atomic operation is marked ``syncscope("<target-scope>")``, where
|
||||
``<target-scope>`` is a target specific synchronization scope, then it is target
|
||||
dependent if it *synchronizes with* and participates in the seq\_cst total
|
||||
orderings of other operations.
|
||||
|
||||
Otherwise, an atomic operation that is not marked ``syncscope("singlethread")``
|
||||
or ``syncscope("<target-scope>")`` *synchronizes with* and participates in the
|
||||
seq\_cst total orderings of other operations that are not marked
|
||||
``syncscope("singlethread")`` or ``syncscope("<target-scope>")``.
|
||||
|
||||
.. _fastmath:
|
||||
|
||||
@ -5034,7 +5043,7 @@ which is the string ``llvm.loop.licm_versioning.disable``. For example:
|
||||
|
||||
Loop distribution allows splitting a loop into multiple loops. Currently,
|
||||
this is only performed if the entire loop cannot be vectorized due to unsafe
|
||||
memory dependencies. The transformation will atempt to isolate the unsafe
|
||||
memory dependencies. The transformation will attempt to isolate the unsafe
|
||||
dependencies into their own loop.
|
||||
|
||||
This metadata can be used to selectively enable or disable distribution of the
|
||||
@ -7380,7 +7389,7 @@ Syntax:
|
||||
::
|
||||
|
||||
<result> = load [volatile] <ty>, <ty>* <pointer>[, align <alignment>][, !nontemporal !<index>][, !invariant.load !<index>][, !invariant.group !<index>][, !nonnull !<index>][, !dereferenceable !<deref_bytes_node>][, !dereferenceable_or_null !<deref_bytes_node>][, !align !<align_node>]
|
||||
<result> = load atomic [volatile] <ty>, <ty>* <pointer> [singlethread] <ordering>, align <alignment> [, !invariant.group !<index>]
|
||||
<result> = load atomic [volatile] <ty>, <ty>* <pointer> [syncscope("<target-scope>")] <ordering>, align <alignment> [, !invariant.group !<index>]
|
||||
!<index> = !{ i32 1 }
|
||||
!<deref_bytes_node> = !{i64 <dereferenceable_bytes>}
|
||||
!<align_node> = !{ i64 <value_alignment> }
|
||||
@ -7401,14 +7410,14 @@ modify the number or order of execution of this ``load`` with other
|
||||
:ref:`volatile operations <volatile>`.
|
||||
|
||||
If the ``load`` is marked as ``atomic``, it takes an extra :ref:`ordering
|
||||
<ordering>` and optional ``singlethread`` argument. The ``release`` and
|
||||
``acq_rel`` orderings are not valid on ``load`` instructions. Atomic loads
|
||||
produce :ref:`defined <memmodel>` results when they may see multiple atomic
|
||||
stores. The type of the pointee must be an integer, pointer, or floating-point
|
||||
type whose bit width is a power of two greater than or equal to eight and less
|
||||
than or equal to a target-specific size limit. ``align`` must be explicitly
|
||||
specified on atomic loads, and the load has undefined behavior if the alignment
|
||||
is not set to a value which is at least the size in bytes of the
|
||||
<ordering>` and optional ``syncscope("<target-scope>")`` argument. The
|
||||
``release`` and ``acq_rel`` orderings are not valid on ``load`` instructions.
|
||||
Atomic loads produce :ref:`defined <memmodel>` results when they may see
|
||||
multiple atomic stores. The type of the pointee must be an integer, pointer, or
|
||||
floating-point type whose bit width is a power of two greater than or equal to
|
||||
eight and less than or equal to a target-specific size limit. ``align`` must be
|
||||
explicitly specified on atomic loads, and the load has undefined behavior if the
|
||||
alignment is not set to a value which is at least the size in bytes of the
|
||||
pointee. ``!nontemporal`` does not have any defined semantics for atomic loads.
|
||||
|
||||
The optional constant ``align`` argument specifies the alignment of the
|
||||
@ -7509,7 +7518,7 @@ Syntax:
|
||||
::
|
||||
|
||||
store [volatile] <ty> <value>, <ty>* <pointer>[, align <alignment>][, !nontemporal !<index>][, !invariant.group !<index>] ; yields void
|
||||
store atomic [volatile] <ty> <value>, <ty>* <pointer> [singlethread] <ordering>, align <alignment> [, !invariant.group !<index>] ; yields void
|
||||
store atomic [volatile] <ty> <value>, <ty>* <pointer> [syncscope("<target-scope>")] <ordering>, align <alignment> [, !invariant.group !<index>] ; yields void
|
||||
|
||||
Overview:
|
||||
"""""""""
|
||||
@ -7529,14 +7538,14 @@ allowed to modify the number or order of execution of this ``store`` with other
|
||||
structural type <t_opaque>`) can be stored.
|
||||
|
||||
If the ``store`` is marked as ``atomic``, it takes an extra :ref:`ordering
|
||||
<ordering>` and optional ``singlethread`` argument. The ``acquire`` and
|
||||
``acq_rel`` orderings aren't valid on ``store`` instructions. Atomic loads
|
||||
produce :ref:`defined <memmodel>` results when they may see multiple atomic
|
||||
stores. The type of the pointee must be an integer, pointer, or floating-point
|
||||
type whose bit width is a power of two greater than or equal to eight and less
|
||||
than or equal to a target-specific size limit. ``align`` must be explicitly
|
||||
specified on atomic stores, and the store has undefined behavior if the
|
||||
alignment is not set to a value which is at least the size in bytes of the
|
||||
<ordering>` and optional ``syncscope("<target-scope>")`` argument. The
|
||||
``acquire`` and ``acq_rel`` orderings aren't valid on ``store`` instructions.
|
||||
Atomic loads produce :ref:`defined <memmodel>` results when they may see
|
||||
multiple atomic stores. The type of the pointee must be an integer, pointer, or
|
||||
floating-point type whose bit width is a power of two greater than or equal to
|
||||
eight and less than or equal to a target-specific size limit. ``align`` must be
|
||||
explicitly specified on atomic stores, and the store has undefined behavior if
|
||||
the alignment is not set to a value which is at least the size in bytes of the
|
||||
pointee. ``!nontemporal`` does not have any defined semantics for atomic stores.
|
||||
|
||||
The optional constant ``align`` argument specifies the alignment of the
|
||||
@ -7597,7 +7606,7 @@ Syntax:
|
||||
|
||||
::
|
||||
|
||||
fence [singlethread] <ordering> ; yields void
|
||||
fence [syncscope("<target-scope>")] <ordering> ; yields void
|
||||
|
||||
Overview:
|
||||
"""""""""
|
||||
@ -7631,17 +7640,17 @@ A ``fence`` which has ``seq_cst`` ordering, in addition to having both
|
||||
``acquire`` and ``release`` semantics specified above, participates in
|
||||
the global program order of other ``seq_cst`` operations and/or fences.
|
||||
|
||||
The optional ":ref:`singlethread <singlethread>`" argument specifies
|
||||
that the fence only synchronizes with other fences in the same thread.
|
||||
(This is useful for interacting with signal handlers.)
|
||||
A ``fence`` instruction can also take an optional
|
||||
":ref:`syncscope <syncscope>`" argument.
|
||||
|
||||
Example:
|
||||
""""""""
|
||||
|
||||
.. code-block:: llvm
|
||||
|
||||
fence acquire ; yields void
|
||||
fence singlethread seq_cst ; yields void
|
||||
fence acquire ; yields void
|
||||
fence syncscope("singlethread") seq_cst ; yields void
|
||||
fence syncscope("agent") seq_cst ; yields void
|
||||
|
||||
.. _i_cmpxchg:
|
||||
|
||||
@ -7653,7 +7662,7 @@ Syntax:
|
||||
|
||||
::
|
||||
|
||||
cmpxchg [weak] [volatile] <ty>* <pointer>, <ty> <cmp>, <ty> <new> [singlethread] <success ordering> <failure ordering> ; yields { ty, i1 }
|
||||
cmpxchg [weak] [volatile] <ty>* <pointer>, <ty> <cmp>, <ty> <new> [syncscope("<target-scope>")] <success ordering> <failure ordering> ; yields { ty, i1 }
|
||||
|
||||
Overview:
|
||||
"""""""""
|
||||
@ -7682,10 +7691,8 @@ must be at least ``monotonic``, the ordering constraint on failure must be no
|
||||
stronger than that on success, and the failure ordering cannot be either
|
||||
``release`` or ``acq_rel``.
|
||||
|
||||
The optional "``singlethread``" argument declares that the ``cmpxchg``
|
||||
is only atomic with respect to code (usually signal handlers) running in
|
||||
the same thread as the ``cmpxchg``. Otherwise the cmpxchg is atomic with
|
||||
respect to all other code in the system.
|
||||
A ``cmpxchg`` instruction can also take an optional
|
||||
":ref:`syncscope <syncscope>`" argument.
|
||||
|
||||
The pointer passed into cmpxchg must have alignment greater than or
|
||||
equal to the size in memory of the operand.
|
||||
@ -7739,7 +7746,7 @@ Syntax:
|
||||
|
||||
::
|
||||
|
||||
atomicrmw [volatile] <operation> <ty>* <pointer>, <ty> <value> [singlethread] <ordering> ; yields ty
|
||||
atomicrmw [volatile] <operation> <ty>* <pointer>, <ty> <value> [syncscope("<target-scope>")] <ordering> ; yields ty
|
||||
|
||||
Overview:
|
||||
"""""""""
|
||||
@ -7773,6 +7780,9 @@ be a pointer to that type. If the ``atomicrmw`` is marked as
|
||||
order of execution of this ``atomicrmw`` with other :ref:`volatile
|
||||
operations <volatile>`.
|
||||
|
||||
A ``atomicrmw`` instruction can also take an optional
|
||||
":ref:`syncscope <syncscope>`" argument.
|
||||
|
||||
Semantics:
|
||||
""""""""""
|
||||
|
||||
@ -10272,6 +10282,8 @@ overlap. It copies "len" bytes of memory over. If the argument is known
|
||||
to be aligned to some boundary, this can be specified as the fourth
|
||||
argument, otherwise it should be set to 0 or 1 (both meaning no alignment).
|
||||
|
||||
.. _int_memmove:
|
||||
|
||||
'``llvm.memmove``' Intrinsic
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@ -10327,6 +10339,8 @@ copies "len" bytes of memory over. If the argument is known to be
|
||||
aligned to some boundary, this can be specified as the fourth argument,
|
||||
otherwise it should be set to 0 or 1 (both meaning no alignment).
|
||||
|
||||
.. _int_memset:
|
||||
|
||||
'``llvm.memset.*``' Intrinsics
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@ -14168,4 +14182,154 @@ In the most general case call to the '``llvm.memcpy.element.unordered.atomic.*``
|
||||
lowered to a call to the symbol ``__llvm_memcpy_element_unordered_atomic_*``. Where '*'
|
||||
is replaced with an actual element size.
|
||||
|
||||
Optimizer is allowed to inline memory copy when it's profitable to do so.
|
||||
|
||||
'``llvm.memmove.element.unordered.atomic``' Intrinsic
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Syntax:
|
||||
"""""""
|
||||
|
||||
This is an overloaded intrinsic. You can use
|
||||
``llvm.memmove.element.unordered.atomic`` on any integer bit width and for
|
||||
different address spaces. Not all targets support all bit widths however.
|
||||
|
||||
::
|
||||
|
||||
declare void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i32(i8* <dest>,
|
||||
i8* <src>,
|
||||
i32 <len>,
|
||||
i32 <element_size>)
|
||||
declare void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i64(i8* <dest>,
|
||||
i8* <src>,
|
||||
i64 <len>,
|
||||
i32 <element_size>)
|
||||
|
||||
Overview:
|
||||
"""""""""
|
||||
|
||||
The '``llvm.memmove.element.unordered.atomic.*``' intrinsic is a specialization
|
||||
of the '``llvm.memmove.*``' intrinsic. It differs in that the ``dest`` and
|
||||
``src`` are treated as arrays with elements that are exactly ``element_size``
|
||||
bytes, and the copy between buffers uses a sequence of
|
||||
:ref:`unordered atomic <ordering>` load/store operations that are a positive
|
||||
integer multiple of the ``element_size`` in size.
|
||||
|
||||
Arguments:
|
||||
""""""""""
|
||||
|
||||
The first three arguments are the same as they are in the
|
||||
:ref:`@llvm.memmove <int_memmove>` intrinsic, with the added constraint that
|
||||
``len`` is required to be a positive integer multiple of the ``element_size``.
|
||||
If ``len`` is not a positive integer multiple of ``element_size``, then the
|
||||
behaviour of the intrinsic is undefined.
|
||||
|
||||
``element_size`` must be a compile-time constant positive power of two no
|
||||
greater than a target-specific atomic access size limit.
|
||||
|
||||
For each of the input pointers the ``align`` parameter attribute must be
|
||||
specified. It must be a power of two no less than the ``element_size``. Caller
|
||||
guarantees that both the source and destination pointers are aligned to that
|
||||
boundary.
|
||||
|
||||
Semantics:
|
||||
""""""""""
|
||||
|
||||
The '``llvm.memmove.element.unordered.atomic.*``' intrinsic copies ``len`` bytes
|
||||
of memory from the source location to the destination location. These locations
|
||||
are allowed to overlap. The memory copy is performed as a sequence of load/store
|
||||
operations where each access is guaranteed to be a multiple of ``element_size``
|
||||
bytes wide and aligned at an ``element_size`` boundary.
|
||||
|
||||
The order of the copy is unspecified. The same value may be read from the source
|
||||
buffer many times, but only one write is issued to the destination buffer per
|
||||
element. It is well defined to have concurrent reads and writes to both source
|
||||
and destination provided those reads and writes are unordered atomic when
|
||||
specified.
|
||||
|
||||
This intrinsic does not provide any additional ordering guarantees over those
|
||||
provided by a set of unordered loads from the source location and stores to the
|
||||
destination.
|
||||
|
||||
Lowering:
|
||||
"""""""""
|
||||
|
||||
In the most general case call to the
|
||||
'``llvm.memmove.element.unordered.atomic.*``' is lowered to a call to the symbol
|
||||
``__llvm_memmove_element_unordered_atomic_*``. Where '*' is replaced with an
|
||||
actual element size.
|
||||
|
||||
The optimizer is allowed to inline the memory copy when it's profitable to do so.
|
||||
|
||||
.. _int_memset_element_unordered_atomic:
|
||||
|
||||
'``llvm.memset.element.unordered.atomic``' Intrinsic
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Syntax:
|
||||
"""""""
|
||||
|
||||
This is an overloaded intrinsic. You can use ``llvm.memset.element.unordered.atomic`` on
|
||||
any integer bit width and for different address spaces. Not all targets
|
||||
support all bit widths however.
|
||||
|
||||
::
|
||||
|
||||
declare void @llvm.memset.element.unordered.atomic.p0i8.i32(i8* <dest>,
|
||||
i8 <value>,
|
||||
i32 <len>,
|
||||
i32 <element_size>)
|
||||
declare void @llvm.memset.element.unordered.atomic.p0i8.i64(i8* <dest>,
|
||||
i8 <value>,
|
||||
i64 <len>,
|
||||
i32 <element_size>)
|
||||
|
||||
Overview:
|
||||
"""""""""
|
||||
|
||||
The '``llvm.memset.element.unordered.atomic.*``' intrinsic is a specialization of the
|
||||
'``llvm.memset.*``' intrinsic. It differs in that the ``dest`` is treated as an array
|
||||
with elements that are exactly ``element_size`` bytes, and the assignment to that array
|
||||
uses uses a sequence of :ref:`unordered atomic <ordering>` store operations
|
||||
that are a positive integer multiple of the ``element_size`` in size.
|
||||
|
||||
Arguments:
|
||||
""""""""""
|
||||
|
||||
The first three arguments are the same as they are in the :ref:`@llvm.memset <int_memset>`
|
||||
intrinsic, with the added constraint that ``len`` is required to be a positive integer
|
||||
multiple of the ``element_size``. If ``len`` is not a positive integer multiple of
|
||||
``element_size``, then the behaviour of the intrinsic is undefined.
|
||||
|
||||
``element_size`` must be a compile-time constant positive power of two no greater than
|
||||
target-specific atomic access size limit.
|
||||
|
||||
The ``dest`` input pointer must have the ``align`` parameter attribute specified. It
|
||||
must be a power of two no less than the ``element_size``. Caller guarantees that
|
||||
the destination pointer is aligned to that boundary.
|
||||
|
||||
Semantics:
|
||||
""""""""""
|
||||
|
||||
The '``llvm.memset.element.unordered.atomic.*``' intrinsic sets the ``len`` bytes of
|
||||
memory starting at the destination location to the given ``value``. The memory is
|
||||
set with a sequence of store operations where each access is guaranteed to be a
|
||||
multiple of ``element_size`` bytes wide and aligned at an ``element_size`` boundary.
|
||||
|
||||
The order of the assignment is unspecified. Only one write is issued to the
|
||||
destination buffer per element. It is well defined to have concurrent reads and
|
||||
writes to the destination provided those reads and writes are unordered atomic
|
||||
when specified.
|
||||
|
||||
This intrinsic does not provide any additional ordering guarantees over those
|
||||
provided by a set of unordered stores to the destination.
|
||||
|
||||
Lowering:
|
||||
"""""""""
|
||||
|
||||
In the most general case call to the '``llvm.memset.element.unordered.atomic.*``' is
|
||||
lowered to a call to the symbol ``__llvm_memset_element_unordered_atomic_*``. Where '*'
|
||||
is replaced with an actual element size.
|
||||
|
||||
The optimizer is allowed to inline the memory assignment when it's profitable to do so.
|
||||
|
||||
|
@ -587,7 +587,7 @@ The simplest way is to have a statically initialized global object inside
|
||||
|
||||
Alternatively, you may define an optional init function and it will receive
|
||||
the program arguments that you can read and modify. Do this **only** if you
|
||||
realy need to access ``argv``/``argc``.
|
||||
really need to access ``argv``/``argc``.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
|
@ -12,7 +12,7 @@ Welcome to Chapter 1 of the "Building an ORC-based JIT in LLVM" tutorial. This
|
||||
tutorial runs through the implementation of a JIT compiler using LLVM's
|
||||
On-Request-Compilation (ORC) APIs. It begins with a simplified version of the
|
||||
KaleidoscopeJIT class used in the
|
||||
`Implementing a language with LLVM <LangImpl1.html>`_ tutorials and then
|
||||
`Implementing a language with LLVM <LangImpl01.html>`_ tutorials and then
|
||||
introduces new features like optimization, lazy compilation and remote
|
||||
execution.
|
||||
|
||||
@ -41,7 +41,7 @@ The structure of the tutorial is:
|
||||
a remote process with reduced privileges using the JIT Remote APIs.
|
||||
|
||||
To provide input for our JIT we will use the Kaleidoscope REPL from
|
||||
`Chapter 7 <LangImpl7.html>`_ of the "Implementing a language in LLVM tutorial",
|
||||
`Chapter 7 <LangImpl07.html>`_ of the "Implementing a language in LLVM tutorial",
|
||||
with one minor modification: We will remove the FunctionPassManager from the
|
||||
code for that chapter and replace it with optimization support in our JIT class
|
||||
in Chapter #2.
|
||||
@ -91,8 +91,8 @@ KaleidoscopeJIT
|
||||
|
||||
In the previous section we described our API, now we examine a simple
|
||||
implementation of it: The KaleidoscopeJIT class [1]_ that was used in the
|
||||
`Implementing a language with LLVM <LangImpl1.html>`_ tutorials. We will use
|
||||
the REPL code from `Chapter 7 <LangImpl7.html>`_ of that tutorial to supply the
|
||||
`Implementing a language with LLVM <LangImpl01.html>`_ tutorials. We will use
|
||||
the REPL code from `Chapter 7 <LangImpl07.html>`_ of that tutorial to supply the
|
||||
input for our JIT: Each time the user enters an expression the REPL will add a
|
||||
new IR module containing the code for that expression to the JIT. If the
|
||||
expression is a top-level expression like '1+1' or 'sin(x)', the REPL will also
|
||||
|
@ -25,7 +25,7 @@ IRTransformLayer, to add IR optimization support to KaleidoscopeJIT.
|
||||
Optimizing Modules using the IRTransformLayer
|
||||
=============================================
|
||||
|
||||
In `Chapter 4 <LangImpl4.html>`_ of the "Implementing a language with LLVM"
|
||||
In `Chapter 4 <LangImpl04.html>`_ of the "Implementing a language with LLVM"
|
||||
tutorial series the llvm *FunctionPassManager* is introduced as a means for
|
||||
optimizing LLVM IR. Interested readers may read that chapter for details, but
|
||||
in short: to optimize a Module we create an llvm::FunctionPassManager
|
||||
@ -148,7 +148,7 @@ At the bottom of our JIT we add a private method to do the actual optimization:
|
||||
*optimizeModule*. This function sets up a FunctionPassManager, adds some passes
|
||||
to it, runs it over every function in the module, and then returns the mutated
|
||||
module. The specific optimizations are the same ones used in
|
||||
`Chapter 4 <LangImpl4.html>`_ of the "Implementing a language with LLVM"
|
||||
`Chapter 4 <LangImpl04.html>`_ of the "Implementing a language with LLVM"
|
||||
tutorial series. Readers may visit that chapter for a more in-depth
|
||||
discussion of these, and of IR optimization in general.
|
||||
|
||||
|
@ -10,7 +10,7 @@ Chapter 2 Introduction
|
||||
|
||||
Welcome to Chapter 2 of the "`Implementing a language with
|
||||
LLVM <index.html>`_" tutorial. This chapter shows you how to use the
|
||||
lexer, built in `Chapter 1 <LangImpl1.html>`_, to build a full
|
||||
lexer, built in `Chapter 1 <LangImpl01.html>`_, to build a full
|
||||
`parser <http://en.wikipedia.org/wiki/Parsing>`_ for our Kaleidoscope
|
||||
language. Once we have a parser, we'll define and build an `Abstract
|
||||
Syntax Tree <http://en.wikipedia.org/wiki/Abstract_syntax_tree>`_ (AST).
|
||||
|
@ -10,7 +10,7 @@ Chapter 3 Introduction
|
||||
|
||||
Welcome to Chapter 3 of the "`Implementing a language with
|
||||
LLVM <index.html>`_" tutorial. This chapter shows you how to transform
|
||||
the `Abstract Syntax Tree <LangImpl2.html>`_, built in Chapter 2, into
|
||||
the `Abstract Syntax Tree <LangImpl02.html>`_, built in Chapter 2, into
|
||||
LLVM IR. This will teach you a little bit about how LLVM does things, as
|
||||
well as demonstrate how easy it is to use. It's much more work to build
|
||||
a lexer and parser than it is to generate LLVM IR code. :)
|
||||
@ -362,7 +362,7 @@ end of the new basic block. Basic blocks in LLVM are an important part
|
||||
of functions that define the `Control Flow
|
||||
Graph <http://en.wikipedia.org/wiki/Control_flow_graph>`_. Since we
|
||||
don't have any control flow, our functions will only contain one block
|
||||
at this point. We'll fix this in `Chapter 5 <LangImpl5.html>`_ :).
|
||||
at this point. We'll fix this in `Chapter 5 <LangImpl05.html>`_ :).
|
||||
|
||||
Next we add the function arguments to the NamedValues map (after first clearing
|
||||
it out) so that they're accessible to ``VariableExprAST`` nodes.
|
||||
@ -540,7 +540,7 @@ functions referencing each other.
|
||||
|
||||
This wraps up the third chapter of the Kaleidoscope tutorial. Up next,
|
||||
we'll describe how to `add JIT codegen and optimizer
|
||||
support <LangImpl4.html>`_ to this so we can actually start running
|
||||
support <LangImpl04.html>`_ to this so we can actually start running
|
||||
code!
|
||||
|
||||
Full Code Listing
|
||||
|
@ -622,7 +622,7 @@ This completes the JIT and optimizer chapter of the Kaleidoscope
|
||||
tutorial. At this point, we can compile a non-Turing-complete
|
||||
programming language, optimize and JIT compile it in a user-driven way.
|
||||
Next up we'll look into `extending the language with control flow
|
||||
constructs <LangImpl5.html>`_, tackling some interesting LLVM IR issues
|
||||
constructs <LangImpl05.html>`_, tackling some interesting LLVM IR issues
|
||||
along the way.
|
||||
|
||||
Full Code Listing
|
||||
|
@ -269,7 +269,7 @@ Phi nodes:
|
||||
#. Values that are implicit in the structure of your AST, such as the
|
||||
Phi node in this case.
|
||||
|
||||
In `Chapter 7 <LangImpl7.html>`_ of this tutorial ("mutable variables"),
|
||||
In `Chapter 7 <LangImpl07.html>`_ of this tutorial ("mutable variables"),
|
||||
we'll talk about #1 in depth. For now, just believe me that you don't
|
||||
need SSA construction to handle this case. For #2, you have the choice
|
||||
of using the techniques that we will describe for #1, or you can insert
|
||||
@ -790,7 +790,7 @@ of the tutorial. In this chapter we added two control flow constructs,
|
||||
and used them to motivate a couple of aspects of the LLVM IR that are
|
||||
important for front-end implementors to know. In the next chapter of our
|
||||
saga, we will get a bit crazier and add `user-defined
|
||||
operators <LangImpl6.html>`_ to our poor innocent language.
|
||||
operators <LangImpl06.html>`_ to our poor innocent language.
|
||||
|
||||
Full Code Listing
|
||||
=================
|
||||
|
@ -41,7 +41,7 @@ The point of going into user-defined operators in a tutorial like this
|
||||
is to show the power and flexibility of using a hand-written parser.
|
||||
Thus far, the parser we have been implementing uses recursive descent
|
||||
for most parts of the grammar and operator precedence parsing for the
|
||||
expressions. See `Chapter 2 <LangImpl2.html>`_ for details. By
|
||||
expressions. See `Chapter 2 <LangImpl02.html>`_ for details. By
|
||||
using operator precedence parsing, it is very easy to allow
|
||||
the programmer to introduce new operators into the grammar: the grammar
|
||||
is dynamically extensible as the JIT runs.
|
||||
@ -734,7 +734,7 @@ side-effects, but it can't actually define and mutate a variable itself.
|
||||
|
||||
Strikingly, variable mutation is an important feature of some languages,
|
||||
and it is not at all obvious how to `add support for mutable
|
||||
variables <LangImpl7.html>`_ without having to add an "SSA construction"
|
||||
variables <LangImpl07.html>`_ without having to add an "SSA construction"
|
||||
phase to your front-end. In the next chapter, we will describe how you
|
||||
can add variable mutation without building SSA in your front-end.
|
||||
|
||||
|
@ -258,7 +258,7 @@ a truth value as a 1-bit (bool) value.
|
||||
let then_bb = append_block context "then" the_function in
|
||||
position_at_end then_bb builder;
|
||||
|
||||
As opposed to the `C++ tutorial <LangImpl5.html>`_, we have to build our
|
||||
As opposed to the `C++ tutorial <LangImpl05.html>`_, we have to build our
|
||||
basic blocks bottom up since we can't have dangling BasicBlocks. We
|
||||
start off by saving a pointer to the first block (which might not be the
|
||||
entry block), which we'll need to build a conditional branch later. We
|
||||
|
@ -48,6 +48,7 @@ public:
|
||||
|
||||
KaleidoscopeJIT()
|
||||
: TM(EngineBuilder().selectTarget()), DL(TM->createDataLayout()),
|
||||
ObjectLayer([]() { return std::make_shared<SectionMemoryManager>(); }),
|
||||
CompileLayer(ObjectLayer, SimpleCompiler(*TM)) {
|
||||
llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr);
|
||||
}
|
||||
@ -74,9 +75,8 @@ public:
|
||||
|
||||
// Add the set to the JIT with the resolver we created above and a newly
|
||||
// created SectionMemoryManager.
|
||||
return CompileLayer.addModule(std::move(M),
|
||||
make_unique<SectionMemoryManager>(),
|
||||
std::move(Resolver));
|
||||
return cantFail(CompileLayer.addModule(std::move(M),
|
||||
std::move(Resolver)));
|
||||
}
|
||||
|
||||
JITSymbol findSymbol(const std::string Name) {
|
||||
@ -87,7 +87,7 @@ public:
|
||||
}
|
||||
|
||||
void removeModule(ModuleHandle H) {
|
||||
CompileLayer.removeModule(H);
|
||||
cantFail(CompileLayer.removeModule(H));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1150,7 +1150,7 @@ static void HandleTopLevelExpression() {
|
||||
|
||||
// Get the symbol's address and cast it to the right type (takes no
|
||||
// arguments, returns a double) so we can call it as a native function.
|
||||
double (*FP)() = (double (*)())(intptr_t)ExprSymbol.getAddress();
|
||||
double (*FP)() = (double (*)())(intptr_t)cantFail(ExprSymbol.getAddress());
|
||||
fprintf(stderr, "Evaluated to %f\n", FP());
|
||||
|
||||
// Delete the anonymous expression module from the JIT.
|
||||
|
@ -57,6 +57,7 @@ public:
|
||||
|
||||
KaleidoscopeJIT()
|
||||
: TM(EngineBuilder().selectTarget()), DL(TM->createDataLayout()),
|
||||
ObjectLayer([]() { return std::make_shared<SectionMemoryManager>(); }),
|
||||
CompileLayer(ObjectLayer, SimpleCompiler(*TM)),
|
||||
OptimizeLayer(CompileLayer,
|
||||
[this](std::shared_ptr<Module> M) {
|
||||
@ -87,9 +88,8 @@ public:
|
||||
|
||||
// Add the set to the JIT with the resolver we created above and a newly
|
||||
// created SectionMemoryManager.
|
||||
return OptimizeLayer.addModule(std::move(M),
|
||||
make_unique<SectionMemoryManager>(),
|
||||
std::move(Resolver));
|
||||
return cantFail(OptimizeLayer.addModule(std::move(M),
|
||||
std::move(Resolver)));
|
||||
}
|
||||
|
||||
JITSymbol findSymbol(const std::string Name) {
|
||||
@ -100,7 +100,7 @@ public:
|
||||
}
|
||||
|
||||
void removeModule(ModuleHandle H) {
|
||||
OptimizeLayer.removeModule(H);
|
||||
cantFail(OptimizeLayer.removeModule(H));
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -1150,7 +1150,7 @@ static void HandleTopLevelExpression() {
|
||||
|
||||
// Get the symbol's address and cast it to the right type (takes no
|
||||
// arguments, returns a double) so we can call it as a native function.
|
||||
double (*FP)() = (double (*)())(intptr_t)ExprSymbol.getAddress();
|
||||
double (*FP)() = (double (*)())(intptr_t)cantFail(ExprSymbol.getAddress());
|
||||
fprintf(stderr, "Evaluated to %f\n", FP());
|
||||
|
||||
// Delete the anonymous expression module from the JIT.
|
||||
|
@ -63,6 +63,7 @@ public:
|
||||
|
||||
KaleidoscopeJIT()
|
||||
: TM(EngineBuilder().selectTarget()), DL(TM->createDataLayout()),
|
||||
ObjectLayer([]() { return std::make_shared<SectionMemoryManager>(); }),
|
||||
CompileLayer(ObjectLayer, SimpleCompiler(*TM)),
|
||||
OptimizeLayer(CompileLayer,
|
||||
[this](std::shared_ptr<Module> M) {
|
||||
@ -100,9 +101,7 @@ public:
|
||||
|
||||
// Add the set to the JIT with the resolver we created above and a newly
|
||||
// created SectionMemoryManager.
|
||||
return CODLayer.addModule(std::move(M),
|
||||
make_unique<SectionMemoryManager>(),
|
||||
std::move(Resolver));
|
||||
return cantFail(CODLayer.addModule(std::move(M), std::move(Resolver)));
|
||||
}
|
||||
|
||||
JITSymbol findSymbol(const std::string Name) {
|
||||
@ -113,7 +112,7 @@ public:
|
||||
}
|
||||
|
||||
void removeModule(ModuleHandle H) {
|
||||
CODLayer.removeModule(H);
|
||||
cantFail(CODLayer.removeModule(H));
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -1150,7 +1150,7 @@ static void HandleTopLevelExpression() {
|
||||
|
||||
// Get the symbol's address and cast it to the right type (takes no
|
||||
// arguments, returns a double) so we can call it as a native function.
|
||||
double (*FP)() = (double (*)())(intptr_t)ExprSymbol.getAddress();
|
||||
double (*FP)() = (double (*)())(intptr_t)cantFail(ExprSymbol.getAddress());
|
||||
fprintf(stderr, "Evaluated to %f\n", FP());
|
||||
|
||||
// Delete the anonymous expression module from the JIT.
|
||||
|
@ -90,6 +90,7 @@ public:
|
||||
KaleidoscopeJIT()
|
||||
: TM(EngineBuilder().selectTarget()),
|
||||
DL(TM->createDataLayout()),
|
||||
ObjectLayer([]() { return std::make_shared<SectionMemoryManager>(); }),
|
||||
CompileLayer(ObjectLayer, SimpleCompiler(*TM)),
|
||||
OptimizeLayer(CompileLayer,
|
||||
[this](std::shared_ptr<Module> M) {
|
||||
@ -127,9 +128,8 @@ public:
|
||||
|
||||
// Add the set to the JIT with the resolver we created above and a newly
|
||||
// created SectionMemoryManager.
|
||||
return OptimizeLayer.addModule(std::move(M),
|
||||
make_unique<SectionMemoryManager>(),
|
||||
std::move(Resolver));
|
||||
return cantFail(OptimizeLayer.addModule(std::move(M),
|
||||
std::move(Resolver)));
|
||||
}
|
||||
|
||||
Error addFunctionAST(std::unique_ptr<FunctionAST> FnAST) {
|
||||
@ -175,7 +175,7 @@ public:
|
||||
addModule(std::move(M));
|
||||
auto Sym = findSymbol(SharedFnAST->getName() + "$impl");
|
||||
assert(Sym && "Couldn't find compiled function?");
|
||||
JITTargetAddress SymAddr = Sym.getAddress();
|
||||
JITTargetAddress SymAddr = cantFail(Sym.getAddress());
|
||||
if (auto Err =
|
||||
IndirectStubsMgr->updatePointer(mangle(SharedFnAST->getName()),
|
||||
SymAddr)) {
|
||||
@ -195,7 +195,7 @@ public:
|
||||
}
|
||||
|
||||
void removeModule(ModuleHandle H) {
|
||||
OptimizeLayer.removeModule(H);
|
||||
cantFail(OptimizeLayer.removeModule(H));
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -1153,7 +1153,7 @@ static void HandleTopLevelExpression() {
|
||||
|
||||
// Get the symbol's address and cast it to the right type (takes no
|
||||
// arguments, returns a double) so we can call it as a native function.
|
||||
double (*FP)() = (double (*)())(intptr_t)ExprSymbol.getAddress();
|
||||
double (*FP)() = (double (*)())(intptr_t)cantFail(ExprSymbol.getAddress());
|
||||
fprintf(stderr, "Evaluated to %f\n", FP());
|
||||
|
||||
// Delete the anonymous expression module from the JIT.
|
||||
|
@ -97,6 +97,15 @@ public:
|
||||
: TM(EngineBuilder().selectTarget(Triple(Remote.getTargetTriple()), "",
|
||||
"", SmallVector<std::string, 0>())),
|
||||
DL(TM->createDataLayout()),
|
||||
ObjectLayer([&Remote]() {
|
||||
std::unique_ptr<MyRemote::RCMemoryManager> MemMgr;
|
||||
if (auto Err = Remote.createRemoteMemoryManager(MemMgr)) {
|
||||
logAllUnhandledErrors(std::move(Err), errs(),
|
||||
"Error creating remote memory manager:");
|
||||
exit(1);
|
||||
}
|
||||
return MemMgr;
|
||||
}),
|
||||
CompileLayer(ObjectLayer, SimpleCompiler(*TM)),
|
||||
OptimizeLayer(CompileLayer,
|
||||
[this](std::shared_ptr<Module> M) {
|
||||
@ -146,18 +155,10 @@ public:
|
||||
return JITSymbol(nullptr);
|
||||
});
|
||||
|
||||
std::unique_ptr<MyRemote::RCMemoryManager> MemMgr;
|
||||
if (auto Err = Remote.createRemoteMemoryManager(MemMgr)) {
|
||||
logAllUnhandledErrors(std::move(Err), errs(),
|
||||
"Error creating remote memory manager:");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Add the set to the JIT with the resolver we created above and a newly
|
||||
// created SectionMemoryManager.
|
||||
return OptimizeLayer.addModule(std::move(M),
|
||||
std::move(MemMgr),
|
||||
std::move(Resolver));
|
||||
return cantFail(OptimizeLayer.addModule(std::move(M),
|
||||
std::move(Resolver)));
|
||||
}
|
||||
|
||||
Error addFunctionAST(std::unique_ptr<FunctionAST> FnAST) {
|
||||
@ -203,7 +204,7 @@ public:
|
||||
addModule(std::move(M));
|
||||
auto Sym = findSymbol(SharedFnAST->getName() + "$impl");
|
||||
assert(Sym && "Couldn't find compiled function?");
|
||||
JITTargetAddress SymAddr = Sym.getAddress();
|
||||
JITTargetAddress SymAddr = cantFail(Sym.getAddress());
|
||||
if (auto Err =
|
||||
IndirectStubsMgr->updatePointer(mangle(SharedFnAST->getName()),
|
||||
SymAddr)) {
|
||||
@ -227,7 +228,7 @@ public:
|
||||
}
|
||||
|
||||
void removeModule(ModuleHandle H) {
|
||||
OptimizeLayer.removeModule(H);
|
||||
cantFail(OptimizeLayer.removeModule(H));
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -1177,7 +1177,7 @@ static void HandleTopLevelExpression() {
|
||||
|
||||
// Get the symbol's address and cast it to the right type (takes no
|
||||
// arguments, returns a double) so we can call it as a native function.
|
||||
ExitOnErr(TheJIT->executeRemoteExpr(ExprSymbol.getAddress()));
|
||||
ExitOnErr(TheJIT->executeRemoteExpr(cantFail(ExprSymbol.getAddress())));
|
||||
|
||||
// Delete the anonymous expression module from the JIT.
|
||||
TheJIT->removeModule(H);
|
||||
|
@ -611,7 +611,7 @@ static void HandleTopLevelExpression() {
|
||||
|
||||
// Get the symbol's address and cast it to the right type (takes no
|
||||
// arguments, returns a double) so we can call it as a native function.
|
||||
double (*FP)() = (double (*)())(intptr_t)ExprSymbol.getAddress();
|
||||
double (*FP)() = (double (*)())(intptr_t)cantFail(ExprSymbol.getAddress());
|
||||
fprintf(stderr, "Evaluated to %f\n", FP());
|
||||
|
||||
// Delete the anonymous expression module from the JIT.
|
||||
|
@ -885,7 +885,7 @@ static void HandleTopLevelExpression() {
|
||||
|
||||
// Get the symbol's address and cast it to the right type (takes no
|
||||
// arguments, returns a double) so we can call it as a native function.
|
||||
double (*FP)() = (double (*)())(intptr_t)ExprSymbol.getAddress();
|
||||
double (*FP)() = (double (*)())(intptr_t)cantFail(ExprSymbol.getAddress());
|
||||
fprintf(stderr, "Evaluated to %f\n", FP());
|
||||
|
||||
// Delete the anonymous expression module from the JIT.
|
||||
|
@ -1004,7 +1004,7 @@ static void HandleTopLevelExpression() {
|
||||
|
||||
// Get the symbol's address and cast it to the right type (takes no
|
||||
// arguments, returns a double) so we can call it as a native function.
|
||||
double (*FP)() = (double (*)())(intptr_t)ExprSymbol.getAddress();
|
||||
double (*FP)() = (double (*)())(intptr_t)cantFail(ExprSymbol.getAddress());
|
||||
fprintf(stderr, "Evaluated to %f\n", FP());
|
||||
|
||||
// Delete the anonymous expression module from the JIT.
|
||||
|
@ -1173,7 +1173,7 @@ static void HandleTopLevelExpression() {
|
||||
|
||||
// Get the symbol's address and cast it to the right type (takes no
|
||||
// arguments, returns a double) so we can call it as a native function.
|
||||
double (*FP)() = (double (*)())(intptr_t)ExprSymbol.getAddress();
|
||||
double (*FP)() = (double (*)())(intptr_t)cantFail(ExprSymbol.getAddress());
|
||||
fprintf(stderr, "Evaluated to %f\n", FP());
|
||||
|
||||
// Delete the anonymous expression module from the JIT.
|
||||
|
@ -45,6 +45,7 @@ public:
|
||||
|
||||
KaleidoscopeJIT()
|
||||
: TM(EngineBuilder().selectTarget()), DL(TM->createDataLayout()),
|
||||
ObjectLayer([]() { return std::make_shared<SectionMemoryManager>(); }),
|
||||
CompileLayer(ObjectLayer, SimpleCompiler(*TM)) {
|
||||
llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr);
|
||||
}
|
||||
@ -62,9 +63,8 @@ public:
|
||||
return JITSymbol(nullptr);
|
||||
},
|
||||
[](const std::string &S) { return nullptr; });
|
||||
auto H = CompileLayer.addModule(std::move(M),
|
||||
make_unique<SectionMemoryManager>(),
|
||||
std::move(Resolver));
|
||||
auto H = cantFail(CompileLayer.addModule(std::move(M),
|
||||
std::move(Resolver)));
|
||||
|
||||
ModuleHandles.push_back(H);
|
||||
return H;
|
||||
@ -72,7 +72,7 @@ public:
|
||||
|
||||
void removeModule(ModuleHandleT H) {
|
||||
ModuleHandles.erase(find(ModuleHandles, H));
|
||||
CompileLayer.removeModule(H);
|
||||
cantFail(CompileLayer.removeModule(H));
|
||||
}
|
||||
|
||||
JITSymbol findSymbol(const std::string Name) {
|
||||
@ -115,7 +115,7 @@ private:
|
||||
return JITSymbol(SymAddr, JITSymbolFlags::Exported);
|
||||
|
||||
#ifdef LLVM_ON_WIN32
|
||||
// For Windows retry without "_" at begining, as RTDyldMemoryManager uses
|
||||
// For Windows retry without "_" at beginning, as RTDyldMemoryManager uses
|
||||
// GetProcAddress and standard libraries like msvcrt.dll use names
|
||||
// with and without "_" (for example "_itoa" but "sin").
|
||||
if (Name.length() > 2 && Name[0] == '_')
|
||||
|
@ -113,8 +113,9 @@ void LLVMOrcDisposeMangledSymbol(char *MangledSymbol);
|
||||
/**
|
||||
* Create a lazy compile callback.
|
||||
*/
|
||||
LLVMOrcTargetAddress
|
||||
LLVMOrcErrorCode
|
||||
LLVMOrcCreateLazyCompileCallback(LLVMOrcJITStackRef JITStack,
|
||||
LLVMOrcTargetAddress *RetAddr,
|
||||
LLVMOrcLazyCompileCallbackFn Callback,
|
||||
void *CallbackCtx);
|
||||
|
||||
@ -135,8 +136,9 @@ LLVMOrcErrorCode LLVMOrcSetIndirectStubPointer(LLVMOrcJITStackRef JITStack,
|
||||
/**
|
||||
* Add module to be eagerly compiled.
|
||||
*/
|
||||
LLVMOrcModuleHandle
|
||||
LLVMOrcErrorCode
|
||||
LLVMOrcAddEagerlyCompiledIR(LLVMOrcJITStackRef JITStack,
|
||||
LLVMOrcModuleHandle *RetHandle,
|
||||
LLVMSharedModuleRef Mod,
|
||||
LLVMOrcSymbolResolverFn SymbolResolver,
|
||||
void *SymbolResolverCtx);
|
||||
@ -144,8 +146,9 @@ LLVMOrcAddEagerlyCompiledIR(LLVMOrcJITStackRef JITStack,
|
||||
/**
|
||||
* Add module to be lazily compiled one function at a time.
|
||||
*/
|
||||
LLVMOrcModuleHandle
|
||||
LLVMOrcErrorCode
|
||||
LLVMOrcAddLazilyCompiledIR(LLVMOrcJITStackRef JITStack,
|
||||
LLVMOrcModuleHandle *RetHandle,
|
||||
LLVMSharedModuleRef Mod,
|
||||
LLVMOrcSymbolResolverFn SymbolResolver,
|
||||
void *SymbolResolverCtx);
|
||||
@ -153,10 +156,11 @@ LLVMOrcAddLazilyCompiledIR(LLVMOrcJITStackRef JITStack,
|
||||
/**
|
||||
* Add an object file.
|
||||
*/
|
||||
LLVMOrcModuleHandle LLVMOrcAddObjectFile(LLVMOrcJITStackRef JITStack,
|
||||
LLVMSharedObjectBufferRef Obj,
|
||||
LLVMOrcSymbolResolverFn SymbolResolver,
|
||||
void *SymbolResolverCtx);
|
||||
LLVMOrcErrorCode LLVMOrcAddObjectFile(LLVMOrcJITStackRef JITStack,
|
||||
LLVMOrcModuleHandle *RetHandle,
|
||||
LLVMSharedObjectBufferRef Obj,
|
||||
LLVMOrcSymbolResolverFn SymbolResolver,
|
||||
void *SymbolResolverCtx);
|
||||
|
||||
/**
|
||||
* Remove a module set from the JIT.
|
||||
@ -164,18 +168,20 @@ LLVMOrcModuleHandle LLVMOrcAddObjectFile(LLVMOrcJITStackRef JITStack,
|
||||
* This works for all modules that can be added via OrcAdd*, including object
|
||||
* files.
|
||||
*/
|
||||
void LLVMOrcRemoveModule(LLVMOrcJITStackRef JITStack, LLVMOrcModuleHandle H);
|
||||
LLVMOrcErrorCode LLVMOrcRemoveModule(LLVMOrcJITStackRef JITStack,
|
||||
LLVMOrcModuleHandle H);
|
||||
|
||||
/**
|
||||
* Get symbol address from JIT instance.
|
||||
*/
|
||||
LLVMOrcTargetAddress LLVMOrcGetSymbolAddress(LLVMOrcJITStackRef JITStack,
|
||||
const char *SymbolName);
|
||||
LLVMOrcErrorCode LLVMOrcGetSymbolAddress(LLVMOrcJITStackRef JITStack,
|
||||
LLVMOrcTargetAddress *RetAddr,
|
||||
const char *SymbolName);
|
||||
|
||||
/**
|
||||
* Dispose of an ORC JIT stack.
|
||||
*/
|
||||
void LLVMOrcDisposeInstance(LLVMOrcJITStackRef JITStack);
|
||||
LLVMOrcErrorCode LLVMOrcDisposeInstance(LLVMOrcJITStackRef JITStack);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -401,7 +401,11 @@ public:
|
||||
/// \brief Determine if this is a value of 1.
|
||||
///
|
||||
/// This checks to see if the value of this APInt is one.
|
||||
bool isOneValue() const { return getActiveBits() == 1; }
|
||||
bool isOneValue() const {
|
||||
if (isSingleWord())
|
||||
return U.VAL == 1;
|
||||
return countLeadingZerosSlowCase() == BitWidth - 1;
|
||||
}
|
||||
|
||||
/// \brief Determine if this is the largest unsigned value.
|
||||
///
|
||||
|
@ -100,6 +100,8 @@ class function_ref<Ret(Params...)> {
|
||||
}
|
||||
|
||||
public:
|
||||
function_ref() : callback(nullptr) {}
|
||||
|
||||
template <typename Callable>
|
||||
function_ref(Callable &&callable,
|
||||
typename std::enable_if<
|
||||
@ -110,6 +112,8 @@ public:
|
||||
Ret operator()(Params ...params) const {
|
||||
return callback(callable, std::forward<Params>(params)...);
|
||||
}
|
||||
|
||||
operator bool() const { return callback; }
|
||||
};
|
||||
|
||||
// deleter - Very very very simple method that is used to invoke operator
|
||||
|
@ -15,9 +15,9 @@
|
||||
#ifndef LLVM_ADT_SMALLPTRSET_H
|
||||
#define LLVM_ADT_SMALLPTRSET_H
|
||||
|
||||
#include "llvm/Config/abi-breaking.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/PointerLikeTypeTraits.h"
|
||||
#include "llvm/Support/ReverseIteration.h"
|
||||
#include "llvm/Support/type_traits.h"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
@ -29,15 +29,6 @@
|
||||
|
||||
namespace llvm {
|
||||
|
||||
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
|
||||
template <class T = void> struct ReverseIterate { static bool value; };
|
||||
#if LLVM_ENABLE_REVERSE_ITERATION
|
||||
template <class T> bool ReverseIterate<T>::value = true;
|
||||
#else
|
||||
template <class T> bool ReverseIterate<T>::value = false;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// SmallPtrSetImplBase - This is the common code shared among all the
|
||||
/// SmallPtrSet<>'s, which is almost everything. SmallPtrSet has two modes, one
|
||||
/// for small and one for large sets.
|
||||
|
@ -1353,4 +1353,4 @@ struct BFIDOTGraphTraitsBase : public DefaultDOTGraphTraits {
|
||||
|
||||
#undef DEBUG_TYPE
|
||||
|
||||
#endif
|
||||
#endif // LLVM_ANALYSIS_BLOCKFREQUENCYINFOIMPL_H
|
||||
|
@ -577,12 +577,17 @@ public:
|
||||
// analyses will eventually occur when the module pass completes.
|
||||
PA.intersect(std::move(PassPA));
|
||||
|
||||
// Update the call graph based on this function pass. This may also
|
||||
// update the current SCC to point to a smaller, more refined SCC.
|
||||
CurrentC = &updateCGAndAnalysisManagerForFunctionPass(
|
||||
CG, *CurrentC, *N, AM, UR, DebugLogging);
|
||||
assert(CG.lookupSCC(*N) == CurrentC &&
|
||||
"Current SCC not updated to the SCC containing the current node!");
|
||||
// If the call graph hasn't been preserved, update it based on this
|
||||
// function pass. This may also update the current SCC to point to
|
||||
// a smaller, more refined SCC.
|
||||
auto PAC = PA.getChecker<LazyCallGraphAnalysis>();
|
||||
if (!PAC.preserved() && !PAC.preservedSet<AllAnalysesOn<Module>>()) {
|
||||
CurrentC = &updateCGAndAnalysisManagerForFunctionPass(
|
||||
CG, *CurrentC, *N, AM, UR, DebugLogging);
|
||||
assert(
|
||||
CG.lookupSCC(*N) == CurrentC &&
|
||||
"Current SCC not updated to the SCC containing the current node!");
|
||||
}
|
||||
}
|
||||
|
||||
// By definition we preserve the proxy. And we preserve all analyses on
|
||||
|
@ -160,7 +160,7 @@ InlineParams getInlineParams(int Threshold);
|
||||
/// the -Oz flag.
|
||||
InlineParams getInlineParams(unsigned OptLevel, unsigned SizeOptLevel);
|
||||
|
||||
/// Return the cost associated with a callsite, including paramater passing
|
||||
/// Return the cost associated with a callsite, including parameter passing
|
||||
/// and the call/return instruction.
|
||||
int getCallsiteCost(CallSite CS, const DataLayout &DL);
|
||||
|
||||
|
@ -652,17 +652,23 @@ public:
|
||||
/// Make an existing internal ref edge into a call edge.
|
||||
///
|
||||
/// This may form a larger cycle and thus collapse SCCs into TargetN's SCC.
|
||||
/// If that happens, the deleted SCC pointers are returned. These SCCs are
|
||||
/// not in a valid state any longer but the pointers will remain valid
|
||||
/// until destruction of the parent graph instance for the purpose of
|
||||
/// clearing cached information.
|
||||
/// If that happens, the optional callback \p MergedCB will be invoked (if
|
||||
/// provided) on the SCCs being merged away prior to actually performing
|
||||
/// the merge. Note that this will never include the target SCC as that
|
||||
/// will be the SCC functions are merged into to resolve the cycle. Once
|
||||
/// this function returns, these merged SCCs are not in a valid state but
|
||||
/// the pointers will remain valid until destruction of the parent graph
|
||||
/// instance for the purpose of clearing cached information. This function
|
||||
/// also returns 'true' if a cycle was formed and some SCCs merged away as
|
||||
/// a convenience.
|
||||
///
|
||||
/// After this operation, both SourceN's SCC and TargetN's SCC may move
|
||||
/// position within this RefSCC's postorder list. Any SCCs merged are
|
||||
/// merged into the TargetN's SCC in order to preserve reachability analyses
|
||||
/// which took place on that SCC.
|
||||
SmallVector<SCC *, 1> switchInternalEdgeToCall(Node &SourceN,
|
||||
Node &TargetN);
|
||||
bool switchInternalEdgeToCall(
|
||||
Node &SourceN, Node &TargetN,
|
||||
function_ref<void(ArrayRef<SCC *> MergedSCCs)> MergeCB = {});
|
||||
|
||||
/// Make an existing internal call edge between separate SCCs into a ref
|
||||
/// edge.
|
||||
|
@ -224,6 +224,9 @@ public:
|
||||
SizeOffsetType visitSelectInst(SelectInst &I);
|
||||
SizeOffsetType visitUndefValue(UndefValue&);
|
||||
SizeOffsetType visitInstruction(Instruction &I);
|
||||
|
||||
private:
|
||||
bool CheckedZextOrTrunc(APInt &I);
|
||||
};
|
||||
|
||||
typedef std::pair<Value*, Value*> SizeOffsetEvalType;
|
||||
|
@ -34,10 +34,10 @@
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
#define DEBUG_TYPE "region"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// RegionBase Implementation
|
||||
template <class Tr>
|
||||
@ -901,8 +901,8 @@ void RegionInfoBase<Tr>::calculate(FuncT &F) {
|
||||
buildRegionsTree(DT->getNode(BB), TopLevelRegion);
|
||||
}
|
||||
|
||||
#undef DEBUG_TYPE
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#undef DEBUG_TYPE
|
||||
|
||||
#endif // LLVM_ANALYSIS_REGIONINFOIMPL_H
|
||||
|
@ -753,6 +753,28 @@ public:
|
||||
Value *getOrCreateResultFromMemIntrinsic(IntrinsicInst *Inst,
|
||||
Type *ExpectedType) const;
|
||||
|
||||
/// \returns The type to use in a loop expansion of a memcpy call.
|
||||
Type *getMemcpyLoopLoweringType(LLVMContext &Context, Value *Length,
|
||||
unsigned SrcAlign, unsigned DestAlign) const;
|
||||
|
||||
/// \param[out] OpsOut The operand types to copy RemainingBytes of memory.
|
||||
/// \param RemainingBytes The number of bytes to copy.
|
||||
///
|
||||
/// Calculates the operand types to use when copying \p RemainingBytes of
|
||||
/// memory, where source and destination alignments are \p SrcAlign and
|
||||
/// \p DestAlign respectively.
|
||||
void getMemcpyLoopResidualLoweringType(SmallVectorImpl<Type *> &OpsOut,
|
||||
LLVMContext &Context,
|
||||
unsigned RemainingBytes,
|
||||
unsigned SrcAlign,
|
||||
unsigned DestAlign) const;
|
||||
|
||||
/// \returns True if we want to test the new memcpy lowering functionality in
|
||||
/// Transform/Utils.
|
||||
/// Temporary. Will be removed once we move to the new functionality and
|
||||
/// remove the old.
|
||||
bool useWideIRMemcpyLoopLowering() const;
|
||||
|
||||
/// \returns True if the two functions have compatible attributes for inlining
|
||||
/// purposes.
|
||||
bool areInlineCompatible(const Function *Caller,
|
||||
@ -953,6 +975,12 @@ public:
|
||||
virtual unsigned getAtomicMemIntrinsicMaxElementSize() const = 0;
|
||||
virtual Value *getOrCreateResultFromMemIntrinsic(IntrinsicInst *Inst,
|
||||
Type *ExpectedType) = 0;
|
||||
virtual Type *getMemcpyLoopLoweringType(LLVMContext &Context, Value *Length,
|
||||
unsigned SrcAlign,
|
||||
unsigned DestAlign) const = 0;
|
||||
virtual void getMemcpyLoopResidualLoweringType(
|
||||
SmallVectorImpl<Type *> &OpsOut, LLVMContext &Context,
|
||||
unsigned RemainingBytes, unsigned SrcAlign, unsigned DestAlign) const = 0;
|
||||
virtual bool areInlineCompatible(const Function *Caller,
|
||||
const Function *Callee) const = 0;
|
||||
virtual unsigned getLoadStoreVecRegBitWidth(unsigned AddrSpace) const = 0;
|
||||
@ -1266,6 +1294,19 @@ public:
|
||||
Type *ExpectedType) override {
|
||||
return Impl.getOrCreateResultFromMemIntrinsic(Inst, ExpectedType);
|
||||
}
|
||||
Type *getMemcpyLoopLoweringType(LLVMContext &Context, Value *Length,
|
||||
unsigned SrcAlign,
|
||||
unsigned DestAlign) const override {
|
||||
return Impl.getMemcpyLoopLoweringType(Context, Length, SrcAlign, DestAlign);
|
||||
}
|
||||
void getMemcpyLoopResidualLoweringType(SmallVectorImpl<Type *> &OpsOut,
|
||||
LLVMContext &Context,
|
||||
unsigned RemainingBytes,
|
||||
unsigned SrcAlign,
|
||||
unsigned DestAlign) const override {
|
||||
Impl.getMemcpyLoopResidualLoweringType(OpsOut, Context, RemainingBytes,
|
||||
SrcAlign, DestAlign);
|
||||
}
|
||||
bool areInlineCompatible(const Function *Caller,
|
||||
const Function *Callee) const override {
|
||||
return Impl.areInlineCompatible(Caller, Callee);
|
||||
|
@ -444,6 +444,20 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Type *getMemcpyLoopLoweringType(LLVMContext &Context, Value *Length,
|
||||
unsigned SrcAlign, unsigned DestAlign) const {
|
||||
return Type::getInt8Ty(Context);
|
||||
}
|
||||
|
||||
void getMemcpyLoopResidualLoweringType(SmallVectorImpl<Type *> &OpsOut,
|
||||
LLVMContext &Context,
|
||||
unsigned RemainingBytes,
|
||||
unsigned SrcAlign,
|
||||
unsigned DestAlign) const {
|
||||
for (unsigned i = 0; i != RemainingBytes; ++i)
|
||||
OpsOut.push_back(Type::getInt8Ty(Context));
|
||||
}
|
||||
|
||||
bool areInlineCompatible(const Function *Caller,
|
||||
const Function *Callee) const {
|
||||
return (Caller->getFnAttribute("target-cpu") ==
|
||||
|
@ -523,8 +523,7 @@ template <typename T> class ArrayRef;
|
||||
/// (A)
|
||||
Optional<bool> isImpliedCondition(const Value *LHS, const Value *RHS,
|
||||
const DataLayout &DL,
|
||||
bool InvertAPred = false,
|
||||
unsigned Depth = 0,
|
||||
bool LHSIsFalse = false, unsigned Depth = 0,
|
||||
AssumptionCache *AC = nullptr,
|
||||
const Instruction *CxtI = nullptr,
|
||||
const DominatorTree *DT = nullptr);
|
||||
|
@ -94,7 +94,7 @@ struct WasmFunction {
|
||||
};
|
||||
|
||||
struct WasmDataSegment {
|
||||
uint32_t Index;
|
||||
uint32_t MemoryIndex;
|
||||
WasmInitExpr Offset;
|
||||
ArrayRef<uint8_t> Content;
|
||||
};
|
||||
@ -107,7 +107,7 @@ struct WasmElemSegment {
|
||||
|
||||
struct WasmRelocation {
|
||||
uint32_t Type; // The type of the relocation.
|
||||
int32_t Index; // Index into function to global index space.
|
||||
uint32_t Index; // Index into function to global index space.
|
||||
uint64_t Offset; // Offset from the start of the section.
|
||||
int64_t Addend; // A value to add to the symbol.
|
||||
};
|
||||
|
@ -59,6 +59,8 @@ enum BlockIDs {
|
||||
FULL_LTO_GLOBALVAL_SUMMARY_BLOCK_ID,
|
||||
|
||||
SYMTAB_BLOCK_ID,
|
||||
|
||||
SYNC_SCOPE_NAMES_BLOCK_ID,
|
||||
};
|
||||
|
||||
/// Identification block contains a string that describes the producer details,
|
||||
@ -172,6 +174,10 @@ enum OperandBundleTagCode {
|
||||
OPERAND_BUNDLE_TAG = 1, // TAG: [strchr x N]
|
||||
};
|
||||
|
||||
enum SyncScopeNameCode {
|
||||
SYNC_SCOPE_NAME = 1,
|
||||
};
|
||||
|
||||
// Value symbol table codes.
|
||||
enum ValueSymtabCodes {
|
||||
VST_CODE_ENTRY = 1, // VST_ENTRY: [valueid, namechar x N]
|
||||
@ -404,12 +410,6 @@ enum AtomicOrderingCodes {
|
||||
ORDERING_SEQCST = 6
|
||||
};
|
||||
|
||||
/// Encoded SynchronizationScope values.
|
||||
enum AtomicSynchScopeCodes {
|
||||
SYNCHSCOPE_SINGLETHREAD = 0,
|
||||
SYNCHSCOPE_CROSSTHREAD = 1
|
||||
};
|
||||
|
||||
/// Markers and flags for call instruction.
|
||||
enum CallMarkersFlags {
|
||||
CALL_TAIL = 0,
|
||||
|
@ -608,8 +608,8 @@ private:
|
||||
// Internal Implementation Details
|
||||
//===------------------------------------------------------------------===//
|
||||
|
||||
/// This emits visibility information about symbol, if this is suported by the
|
||||
/// target.
|
||||
/// This emits visibility information about symbol, if this is supported by
|
||||
/// the target.
|
||||
void EmitVisibility(MCSymbol *Sym, unsigned Visibility,
|
||||
bool IsDefinition = true) const;
|
||||
|
||||
|
@ -428,7 +428,7 @@ public:
|
||||
|
||||
std::pair<unsigned, MVT> LT = TLI->getTypeLegalizationCost(DL, Ty);
|
||||
|
||||
bool IsFloat = Ty->getScalarType()->isFloatingPointTy();
|
||||
bool IsFloat = Ty->isFPOrFPVectorTy();
|
||||
// Assume that floating point arithmetic operations cost twice as much as
|
||||
// integer operations.
|
||||
unsigned OpCost = (IsFloat ? 2 : 1);
|
||||
|
@ -16,14 +16,17 @@
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTOR_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTOR_H
|
||||
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include <bitset>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class LLT;
|
||||
class MachineInstr;
|
||||
class MachineInstrBuilder;
|
||||
class MachineOperand;
|
||||
@ -58,6 +61,131 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
enum {
|
||||
/// Record the specified instruction
|
||||
/// - NewInsnID - Instruction ID to define
|
||||
/// - InsnID - Instruction ID
|
||||
/// - OpIdx - Operand index
|
||||
GIM_RecordInsn,
|
||||
|
||||
/// Check the feature bits
|
||||
/// - Expected features
|
||||
GIM_CheckFeatures,
|
||||
|
||||
/// Check the opcode on the specified instruction
|
||||
/// - InsnID - Instruction ID
|
||||
/// - Expected opcode
|
||||
GIM_CheckOpcode,
|
||||
/// Check the instruction has the right number of operands
|
||||
/// - InsnID - Instruction ID
|
||||
/// - Expected number of operands
|
||||
GIM_CheckNumOperands,
|
||||
|
||||
/// Check the type for the specified operand
|
||||
/// - InsnID - Instruction ID
|
||||
/// - OpIdx - Operand index
|
||||
/// - Expected type
|
||||
GIM_CheckType,
|
||||
/// Check the register bank for the specified operand
|
||||
/// - InsnID - Instruction ID
|
||||
/// - OpIdx - Operand index
|
||||
/// - Expected register bank (specified as a register class)
|
||||
GIM_CheckRegBankForClass,
|
||||
/// Check the operand matches a complex predicate
|
||||
/// - InsnID - Instruction ID
|
||||
/// - OpIdx - Operand index
|
||||
/// - RendererID - The renderer to hold the result
|
||||
/// - Complex predicate ID
|
||||
GIM_CheckComplexPattern,
|
||||
/// Check the operand is a specific integer
|
||||
/// - InsnID - Instruction ID
|
||||
/// - OpIdx - Operand index
|
||||
/// - Expected integer
|
||||
GIM_CheckConstantInt,
|
||||
/// Check the operand is a specific literal integer (i.e. MO.isImm() or MO.isCImm() is true).
|
||||
/// - InsnID - Instruction ID
|
||||
/// - OpIdx - Operand index
|
||||
/// - Expected integer
|
||||
GIM_CheckLiteralInt,
|
||||
/// Check the operand is a specific intrinsic ID
|
||||
/// - InsnID - Instruction ID
|
||||
/// - OpIdx - Operand index
|
||||
/// - Expected Intrinsic ID
|
||||
GIM_CheckIntrinsicID,
|
||||
/// Check the specified operand is an MBB
|
||||
/// - InsnID - Instruction ID
|
||||
/// - OpIdx - Operand index
|
||||
GIM_CheckIsMBB,
|
||||
|
||||
/// Check if the specified operand is safe to fold into the current
|
||||
/// instruction.
|
||||
/// - InsnID - Instruction ID
|
||||
GIM_CheckIsSafeToFold,
|
||||
|
||||
//=== Renderers ===
|
||||
|
||||
/// Mutate an instruction
|
||||
/// - NewInsnID - Instruction ID to define
|
||||
/// - OldInsnID - Instruction ID to mutate
|
||||
/// - NewOpcode - The new opcode to use
|
||||
GIR_MutateOpcode,
|
||||
/// Build a new instruction
|
||||
/// - InsnID - Instruction ID to define
|
||||
/// - Opcode - The new opcode to use
|
||||
GIR_BuildMI,
|
||||
|
||||
/// Copy an operand to the specified instruction
|
||||
/// - NewInsnID - Instruction ID to modify
|
||||
/// - OldInsnID - Instruction ID to copy from
|
||||
/// - OpIdx - The operand to copy
|
||||
GIR_Copy,
|
||||
/// Copy an operand to the specified instruction
|
||||
/// - NewInsnID - Instruction ID to modify
|
||||
/// - OldInsnID - Instruction ID to copy from
|
||||
/// - OpIdx - The operand to copy
|
||||
/// - SubRegIdx - The subregister to copy
|
||||
GIR_CopySubReg,
|
||||
/// Add an implicit register def to the specified instruction
|
||||
/// - InsnID - Instruction ID to modify
|
||||
/// - RegNum - The register to add
|
||||
GIR_AddImplicitDef,
|
||||
/// Add an implicit register use to the specified instruction
|
||||
/// - InsnID - Instruction ID to modify
|
||||
/// - RegNum - The register to add
|
||||
GIR_AddImplicitUse,
|
||||
/// Add an register to the specified instruction
|
||||
/// - InsnID - Instruction ID to modify
|
||||
/// - RegNum - The register to add
|
||||
GIR_AddRegister,
|
||||
/// Add an immediate to the specified instruction
|
||||
/// - InsnID - Instruction ID to modify
|
||||
/// - Imm - The immediate to add
|
||||
GIR_AddImm,
|
||||
/// Render complex operands to the specified instruction
|
||||
/// - InsnID - Instruction ID to modify
|
||||
/// - RendererID - The renderer to call
|
||||
GIR_ComplexRenderer,
|
||||
|
||||
/// Constrain an instruction operand to a register class.
|
||||
/// - InsnID - Instruction ID to modify
|
||||
/// - OpIdx - Operand index
|
||||
/// - RCEnum - Register class enumeration value
|
||||
GIR_ConstrainOperandRC,
|
||||
/// Constrain an instructions operands according to the instruction
|
||||
/// description.
|
||||
/// - InsnID - Instruction ID to modify
|
||||
GIR_ConstrainSelectedInstOperands,
|
||||
/// Merge all memory operands into instruction.
|
||||
/// - InsnID - Instruction ID to modify
|
||||
GIR_MergeMemOperands,
|
||||
/// Erase from parent.
|
||||
/// - InsnID - Instruction ID to erase
|
||||
GIR_EraseFromParent,
|
||||
|
||||
/// A successful emission
|
||||
GIR_Done,
|
||||
};
|
||||
|
||||
/// Provides the logic to select generic machine instructions.
|
||||
class InstructionSelector {
|
||||
public:
|
||||
@ -78,9 +206,39 @@ public:
|
||||
|
||||
protected:
|
||||
using ComplexRendererFn = std::function<void(MachineInstrBuilder &)>;
|
||||
using RecordedMIVector = SmallVector<MachineInstr *, 4>;
|
||||
using NewMIVector = SmallVector<MachineInstrBuilder, 4>;
|
||||
|
||||
struct MatcherState {
|
||||
std::vector<ComplexRendererFn> Renderers;
|
||||
RecordedMIVector MIs;
|
||||
|
||||
MatcherState(unsigned MaxRenderers);
|
||||
};
|
||||
|
||||
public:
|
||||
template <class PredicateBitset, class ComplexMatcherMemFn>
|
||||
struct MatcherInfoTy {
|
||||
const LLT *TypeObjects;
|
||||
const PredicateBitset *FeatureBitsets;
|
||||
const std::vector<ComplexMatcherMemFn> ComplexPredicates;
|
||||
};
|
||||
|
||||
protected:
|
||||
InstructionSelector();
|
||||
|
||||
/// Execute a given matcher table and return true if the match was successful
|
||||
/// and false otherwise.
|
||||
template <class TgtInstructionSelector, class PredicateBitset,
|
||||
class ComplexMatcherMemFn>
|
||||
bool executeMatchTable(
|
||||
TgtInstructionSelector &ISel, NewMIVector &OutMIs, MatcherState &State,
|
||||
const MatcherInfoTy<PredicateBitset, ComplexMatcherMemFn> &MatcherInfo,
|
||||
const int64_t *MatchTable, const TargetInstrInfo &TII,
|
||||
MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
|
||||
const RegisterBankInfo &RBI,
|
||||
const PredicateBitset &AvailableFeatures) const;
|
||||
|
||||
/// Constrain a register operand of an instruction \p I to a specified
|
||||
/// register class. This could involve inserting COPYs before (for uses) or
|
||||
/// after (for defs) and may replace the operand of \p I.
|
||||
|
337
include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h
Normal file
337
include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h
Normal file
@ -0,0 +1,337 @@
|
||||
//==-- llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h ---------*- C++ -*-==//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
/// \file This file declares the API for the instruction selector.
|
||||
/// This class is responsible for selecting machine instructions.
|
||||
/// It's implemented by the target. It's used by the InstructionSelect pass.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTORIMPL_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTORIMPL_H
|
||||
|
||||
namespace llvm {
|
||||
template <class TgtInstructionSelector, class PredicateBitset,
|
||||
class ComplexMatcherMemFn>
|
||||
bool InstructionSelector::executeMatchTable(
|
||||
TgtInstructionSelector &ISel, NewMIVector &OutMIs, MatcherState &State,
|
||||
const MatcherInfoTy<PredicateBitset, ComplexMatcherMemFn> &MatcherInfo,
|
||||
const int64_t *MatchTable, const TargetInstrInfo &TII,
|
||||
MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
|
||||
const RegisterBankInfo &RBI,
|
||||
const PredicateBitset &AvailableFeatures) const {
|
||||
const int64_t *Command = MatchTable;
|
||||
while (true) {
|
||||
switch (*Command++) {
|
||||
case GIM_RecordInsn: {
|
||||
int64_t NewInsnID = *Command++;
|
||||
int64_t InsnID = *Command++;
|
||||
int64_t OpIdx = *Command++;
|
||||
|
||||
// As an optimisation we require that MIs[0] is always the root. Refuse
|
||||
// any attempt to modify it.
|
||||
assert(NewInsnID != 0 && "Refusing to modify MIs[0]");
|
||||
(void)NewInsnID;
|
||||
|
||||
MachineOperand &MO = State.MIs[InsnID]->getOperand(OpIdx);
|
||||
if (!MO.isReg()) {
|
||||
DEBUG(dbgs() << "Rejected (not a register)\n");
|
||||
return false;
|
||||
}
|
||||
if (TRI.isPhysicalRegister(MO.getReg())) {
|
||||
DEBUG(dbgs() << "Rejected (is a physical register)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
assert((size_t)NewInsnID == State.MIs.size() &&
|
||||
"Expected to store MIs in order");
|
||||
State.MIs.push_back(MRI.getVRegDef(MO.getReg()));
|
||||
DEBUG(dbgs() << "MIs[" << NewInsnID << "] = GIM_RecordInsn(" << InsnID
|
||||
<< ", " << OpIdx << ")\n");
|
||||
break;
|
||||
}
|
||||
|
||||
case GIM_CheckFeatures: {
|
||||
int64_t ExpectedBitsetID = *Command++;
|
||||
DEBUG(dbgs() << "GIM_CheckFeatures(ExpectedBitsetID=" << ExpectedBitsetID
|
||||
<< ")\n");
|
||||
if ((AvailableFeatures & MatcherInfo.FeatureBitsets[ExpectedBitsetID]) !=
|
||||
MatcherInfo.FeatureBitsets[ExpectedBitsetID]) {
|
||||
DEBUG(dbgs() << "Rejected\n");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case GIM_CheckOpcode: {
|
||||
int64_t InsnID = *Command++;
|
||||
int64_t Expected = *Command++;
|
||||
|
||||
unsigned Opcode = State.MIs[InsnID]->getOpcode();
|
||||
DEBUG(dbgs() << "GIM_CheckOpcode(MIs[" << InsnID << "], ExpectedOpcode="
|
||||
<< Expected << ") // Got=" << Opcode << "\n");
|
||||
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
|
||||
if (Opcode != Expected)
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case GIM_CheckNumOperands: {
|
||||
int64_t InsnID = *Command++;
|
||||
int64_t Expected = *Command++;
|
||||
DEBUG(dbgs() << "GIM_CheckNumOperands(MIs[" << InsnID
|
||||
<< "], Expected=" << Expected << ")\n");
|
||||
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
|
||||
if (State.MIs[InsnID]->getNumOperands() != Expected)
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
case GIM_CheckType: {
|
||||
int64_t InsnID = *Command++;
|
||||
int64_t OpIdx = *Command++;
|
||||
int64_t TypeID = *Command++;
|
||||
DEBUG(dbgs() << "GIM_CheckType(MIs[" << InsnID << "]->getOperand("
|
||||
<< OpIdx << "), TypeID=" << TypeID << ")\n");
|
||||
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
|
||||
if (MRI.getType(State.MIs[InsnID]->getOperand(OpIdx).getReg()) !=
|
||||
MatcherInfo.TypeObjects[TypeID])
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case GIM_CheckRegBankForClass: {
|
||||
int64_t InsnID = *Command++;
|
||||
int64_t OpIdx = *Command++;
|
||||
int64_t RCEnum = *Command++;
|
||||
DEBUG(dbgs() << "GIM_CheckRegBankForClass(MIs[" << InsnID
|
||||
<< "]->getOperand(" << OpIdx << "), RCEnum=" << RCEnum
|
||||
<< ")\n");
|
||||
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
|
||||
if (&RBI.getRegBankFromRegClass(*TRI.getRegClass(RCEnum)) !=
|
||||
RBI.getRegBank(State.MIs[InsnID]->getOperand(OpIdx).getReg(), MRI, TRI))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case GIM_CheckComplexPattern: {
|
||||
int64_t InsnID = *Command++;
|
||||
int64_t OpIdx = *Command++;
|
||||
int64_t RendererID = *Command++;
|
||||
int64_t ComplexPredicateID = *Command++;
|
||||
DEBUG(dbgs() << "State.Renderers[" << RendererID
|
||||
<< "] = GIM_CheckComplexPattern(MIs[" << InsnID
|
||||
<< "]->getOperand(" << OpIdx
|
||||
<< "), ComplexPredicateID=" << ComplexPredicateID << ")\n");
|
||||
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
|
||||
// FIXME: Use std::invoke() when it's available.
|
||||
if (!(State.Renderers[RendererID] =
|
||||
(ISel.*MatcherInfo.ComplexPredicates[ComplexPredicateID])(
|
||||
State.MIs[InsnID]->getOperand(OpIdx))))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case GIM_CheckConstantInt: {
|
||||
int64_t InsnID = *Command++;
|
||||
int64_t OpIdx = *Command++;
|
||||
int64_t Value = *Command++;
|
||||
DEBUG(dbgs() << "GIM_CheckConstantInt(MIs[" << InsnID << "]->getOperand("
|
||||
<< OpIdx << "), Value=" << Value << ")\n");
|
||||
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
|
||||
if (!isOperandImmEqual(State.MIs[InsnID]->getOperand(OpIdx), Value, MRI))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case GIM_CheckLiteralInt: {
|
||||
int64_t InsnID = *Command++;
|
||||
int64_t OpIdx = *Command++;
|
||||
int64_t Value = *Command++;
|
||||
DEBUG(dbgs() << "GIM_CheckLiteralInt(MIs[" << InsnID << "]->getOperand(" << OpIdx
|
||||
<< "), Value=" << Value << ")\n");
|
||||
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
|
||||
MachineOperand &OM = State.MIs[InsnID]->getOperand(OpIdx);
|
||||
if (!OM.isCImm() || !OM.getCImm()->equalsInt(Value))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case GIM_CheckIntrinsicID: {
|
||||
int64_t InsnID = *Command++;
|
||||
int64_t OpIdx = *Command++;
|
||||
int64_t Value = *Command++;
|
||||
DEBUG(dbgs() << "GIM_CheckIntrinsicID(MIs[" << InsnID << "]->getOperand(" << OpIdx
|
||||
<< "), Value=" << Value << ")\n");
|
||||
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
|
||||
MachineOperand &OM = State.MIs[InsnID]->getOperand(OpIdx);
|
||||
if (!OM.isIntrinsicID() || OM.getIntrinsicID() != Value)
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case GIM_CheckIsMBB: {
|
||||
int64_t InsnID = *Command++;
|
||||
int64_t OpIdx = *Command++;
|
||||
DEBUG(dbgs() << "GIM_CheckIsMBB(MIs[" << InsnID << "]->getOperand("
|
||||
<< OpIdx << "))\n");
|
||||
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
|
||||
if (!State.MIs[InsnID]->getOperand(OpIdx).isMBB())
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
case GIM_CheckIsSafeToFold: {
|
||||
int64_t InsnID = *Command++;
|
||||
DEBUG(dbgs() << "GIM_CheckIsSafeToFold(MIs[" << InsnID << "])\n");
|
||||
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
|
||||
if (!isObviouslySafeToFold(*State.MIs[InsnID]))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
case GIR_MutateOpcode: {
|
||||
int64_t OldInsnID = *Command++;
|
||||
int64_t NewInsnID = *Command++;
|
||||
int64_t NewOpcode = *Command++;
|
||||
assert((size_t)NewInsnID == OutMIs.size() &&
|
||||
"Expected to store MIs in order");
|
||||
OutMIs.push_back(
|
||||
MachineInstrBuilder(*State.MIs[OldInsnID]->getParent()->getParent(),
|
||||
State.MIs[OldInsnID]));
|
||||
OutMIs[NewInsnID]->setDesc(TII.get(NewOpcode));
|
||||
DEBUG(dbgs() << "GIR_MutateOpcode(OutMIs[" << NewInsnID << "], MIs["
|
||||
<< OldInsnID << "], " << NewOpcode << ")\n");
|
||||
break;
|
||||
}
|
||||
case GIR_BuildMI: {
|
||||
int64_t InsnID = *Command++;
|
||||
int64_t Opcode = *Command++;
|
||||
assert((size_t)InsnID == OutMIs.size() &&
|
||||
"Expected to store MIs in order");
|
||||
(void)InsnID;
|
||||
OutMIs.push_back(BuildMI(*State.MIs[0]->getParent(), State.MIs[0],
|
||||
State.MIs[0]->getDebugLoc(), TII.get(Opcode)));
|
||||
DEBUG(dbgs() << "GIR_BuildMI(OutMIs[" << InsnID << "], " << Opcode
|
||||
<< ")\n");
|
||||
break;
|
||||
}
|
||||
|
||||
case GIR_Copy: {
|
||||
int64_t NewInsnID = *Command++;
|
||||
int64_t OldInsnID = *Command++;
|
||||
int64_t OpIdx = *Command++;
|
||||
assert(OutMIs[NewInsnID] && "Attempted to add to undefined instruction");
|
||||
OutMIs[NewInsnID].add(State.MIs[OldInsnID]->getOperand(OpIdx));
|
||||
DEBUG(dbgs() << "GIR_Copy(OutMIs[" << NewInsnID << "], MIs[" << OldInsnID
|
||||
<< "], " << OpIdx << ")\n");
|
||||
break;
|
||||
}
|
||||
case GIR_CopySubReg: {
|
||||
int64_t NewInsnID = *Command++;
|
||||
int64_t OldInsnID = *Command++;
|
||||
int64_t OpIdx = *Command++;
|
||||
int64_t SubRegIdx = *Command++;
|
||||
assert(OutMIs[NewInsnID] && "Attempted to add to undefined instruction");
|
||||
OutMIs[NewInsnID].addReg(State.MIs[OldInsnID]->getOperand(OpIdx).getReg(),
|
||||
0, SubRegIdx);
|
||||
DEBUG(dbgs() << "GIR_CopySubReg(OutMIs[" << NewInsnID << "], MIs["
|
||||
<< OldInsnID << "], " << OpIdx << ", " << SubRegIdx
|
||||
<< ")\n");
|
||||
break;
|
||||
}
|
||||
case GIR_AddImplicitDef: {
|
||||
int64_t InsnID = *Command++;
|
||||
int64_t RegNum = *Command++;
|
||||
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
|
||||
OutMIs[InsnID].addDef(RegNum, RegState::Implicit);
|
||||
DEBUG(dbgs() << "GIR_AddImplicitDef(OutMIs[" << InsnID << "], " << RegNum
|
||||
<< ")\n");
|
||||
break;
|
||||
}
|
||||
case GIR_AddImplicitUse: {
|
||||
int64_t InsnID = *Command++;
|
||||
int64_t RegNum = *Command++;
|
||||
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
|
||||
OutMIs[InsnID].addUse(RegNum, RegState::Implicit);
|
||||
DEBUG(dbgs() << "GIR_AddImplicitUse(OutMIs[" << InsnID << "], " << RegNum
|
||||
<< ")\n");
|
||||
break;
|
||||
}
|
||||
case GIR_AddRegister: {
|
||||
int64_t InsnID = *Command++;
|
||||
int64_t RegNum = *Command++;
|
||||
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
|
||||
OutMIs[InsnID].addReg(RegNum);
|
||||
DEBUG(dbgs() << "GIR_AddRegister(OutMIs[" << InsnID << "], " << RegNum
|
||||
<< ")\n");
|
||||
break;
|
||||
}
|
||||
case GIR_AddImm: {
|
||||
int64_t InsnID = *Command++;
|
||||
int64_t Imm = *Command++;
|
||||
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
|
||||
OutMIs[InsnID].addImm(Imm);
|
||||
DEBUG(dbgs() << "GIR_AddImm(OutMIs[" << InsnID << "], " << Imm << ")\n");
|
||||
break;
|
||||
}
|
||||
case GIR_ComplexRenderer: {
|
||||
int64_t InsnID = *Command++;
|
||||
int64_t RendererID = *Command++;
|
||||
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
|
||||
State.Renderers[RendererID](OutMIs[InsnID]);
|
||||
DEBUG(dbgs() << "GIR_ComplexRenderer(OutMIs[" << InsnID << "], "
|
||||
<< RendererID << ")\n");
|
||||
break;
|
||||
}
|
||||
|
||||
case GIR_ConstrainOperandRC: {
|
||||
int64_t InsnID = *Command++;
|
||||
int64_t OpIdx = *Command++;
|
||||
int64_t RCEnum = *Command++;
|
||||
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
|
||||
constrainOperandRegToRegClass(*OutMIs[InsnID].getInstr(), OpIdx,
|
||||
*TRI.getRegClass(RCEnum), TII, TRI, RBI);
|
||||
DEBUG(dbgs() << "GIR_ConstrainOperandRC(OutMIs[" << InsnID << "], "
|
||||
<< OpIdx << ", " << RCEnum << ")\n");
|
||||
break;
|
||||
}
|
||||
case GIR_ConstrainSelectedInstOperands: {
|
||||
int64_t InsnID = *Command++;
|
||||
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
|
||||
constrainSelectedInstRegOperands(*OutMIs[InsnID].getInstr(), TII, TRI,
|
||||
RBI);
|
||||
DEBUG(dbgs() << "GIR_ConstrainSelectedInstOperands(OutMIs[" << InsnID
|
||||
<< "])\n");
|
||||
break;
|
||||
}
|
||||
case GIR_MergeMemOperands: {
|
||||
int64_t InsnID = *Command++;
|
||||
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
|
||||
for (const auto *FromMI : State.MIs)
|
||||
for (const auto &MMO : FromMI->memoperands())
|
||||
OutMIs[InsnID].addMemOperand(MMO);
|
||||
DEBUG(dbgs() << "GIR_MergeMemOperands(OutMIs[" << InsnID << "])\n");
|
||||
break;
|
||||
}
|
||||
case GIR_EraseFromParent: {
|
||||
int64_t InsnID = *Command++;
|
||||
assert(State.MIs[InsnID] &&
|
||||
"Attempted to erase an undefined instruction");
|
||||
State.MIs[InsnID]->eraseFromParent();
|
||||
DEBUG(dbgs() << "GIR_EraseFromParent(MIs[" << InsnID << "])\n");
|
||||
break;
|
||||
}
|
||||
|
||||
case GIR_Done:
|
||||
DEBUG(dbgs() << "GIR_Done");
|
||||
return true;
|
||||
|
||||
default:
|
||||
llvm_unreachable("Unexpected command");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTORIMPL_H
|
@ -101,11 +101,11 @@ private:
|
||||
const LegalizerInfo &LI;
|
||||
};
|
||||
|
||||
/// Helper function that replaces \p MI with a libcall.
|
||||
/// Helper function that creates the given libcall.
|
||||
LegalizerHelper::LegalizeResult
|
||||
replaceWithLibcall(MachineInstr &MI, MachineIRBuilder &MIRBuilder,
|
||||
RTLIB::Libcall Libcall, const CallLowering::ArgInfo &Result,
|
||||
ArrayRef<CallLowering::ArgInfo> Args);
|
||||
createLibcall(MachineIRBuilder &MIRBuilder, RTLIB::Libcall Libcall,
|
||||
const CallLowering::ArgInfo &Result,
|
||||
ArrayRef<CallLowering::ArgInfo> Args);
|
||||
|
||||
} // End namespace llvm.
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "llvm/CodeGen/LowLevelType.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/DebugLoc.h"
|
||||
|
||||
@ -59,6 +60,21 @@ class MachineIRBuilder {
|
||||
}
|
||||
|
||||
void validateTruncExt(unsigned Dst, unsigned Src, bool IsExtend);
|
||||
MachineInstrBuilder buildBinaryOp(unsigned Opcode, unsigned Res, unsigned Op0, unsigned Op1);
|
||||
|
||||
unsigned getDestFromArg(unsigned Reg) { return Reg; }
|
||||
unsigned getDestFromArg(LLT Ty) {
|
||||
return getMF().getRegInfo().createGenericVirtualRegister(Ty);
|
||||
}
|
||||
unsigned getDestFromArg(const TargetRegisterClass *RC) {
|
||||
return getMF().getRegInfo().createVirtualRegister(RC);
|
||||
}
|
||||
|
||||
unsigned getRegFromArg(unsigned Reg) { return Reg; }
|
||||
|
||||
unsigned getRegFromArg(const MachineInstrBuilder &MIB) {
|
||||
return MIB->getOperand(0).getReg();
|
||||
}
|
||||
|
||||
public:
|
||||
/// Getter for the function we currently build.
|
||||
@ -120,6 +136,22 @@ public:
|
||||
/// \return a MachineInstrBuilder for the newly created instruction.
|
||||
MachineInstrBuilder buildInstr(unsigned Opcode);
|
||||
|
||||
/// DAG like Generic method for building arbitrary instructions as above.
|
||||
/// \Opc opcode for the instruction.
|
||||
/// \Ty Either LLT/TargetRegisterClass/unsigned types for Dst
|
||||
/// \Args Variadic list of uses of types(unsigned/MachineInstrBuilder)
|
||||
/// Uses of type MachineInstrBuilder will perform
|
||||
/// getOperand(0).getReg() to convert to register.
|
||||
template <typename DstTy, typename... UseArgsTy>
|
||||
MachineInstrBuilder buildInstr(unsigned Opc, DstTy &&Ty,
|
||||
UseArgsTy &&... Args) {
|
||||
auto MIB = buildInstr(Opc).addDef(getDestFromArg(Ty));
|
||||
unsigned It[] = {(getRegFromArg(Args))...};
|
||||
for (const auto &i : It)
|
||||
MIB.addUse(i);
|
||||
return MIB;
|
||||
}
|
||||
|
||||
/// Build but don't insert <empty> = \p Opcode <empty>.
|
||||
///
|
||||
/// \pre setMF, setBasicBlock or setMI must have been called.
|
||||
@ -188,6 +220,11 @@ public:
|
||||
/// \return a MachineInstrBuilder for the newly created instruction.
|
||||
MachineInstrBuilder buildAdd(unsigned Res, unsigned Op0,
|
||||
unsigned Op1);
|
||||
template <typename DstTy, typename... UseArgsTy>
|
||||
MachineInstrBuilder buildAdd(DstTy &&Ty, UseArgsTy &&... UseArgs) {
|
||||
unsigned Res = getDestFromArg(Ty);
|
||||
return buildAdd(Res, (getRegFromArg(UseArgs))...);
|
||||
}
|
||||
|
||||
/// Build and insert \p Res<def> = G_SUB \p Op0, \p Op1
|
||||
///
|
||||
@ -295,6 +332,18 @@ public:
|
||||
MachineInstrBuilder buildAnd(unsigned Res, unsigned Op0,
|
||||
unsigned Op1);
|
||||
|
||||
/// Build and insert \p Res<def> = G_OR \p Op0, \p Op1
|
||||
///
|
||||
/// G_OR sets \p Res to the bitwise or of integer parameters \p Op0 and \p
|
||||
/// Op1.
|
||||
///
|
||||
/// \pre setBasicBlock or setMI must have been called.
|
||||
/// \pre \p Res, \p Op0 and \p Op1 must be generic virtual registers
|
||||
/// with the same (scalar or vector) type).
|
||||
///
|
||||
/// \return a MachineInstrBuilder for the newly created instruction.
|
||||
MachineInstrBuilder buildOr(unsigned Res, unsigned Op0, unsigned Op1);
|
||||
|
||||
/// Build and insert \p Res<def> = G_ANYEXT \p Op0
|
||||
///
|
||||
/// G_ANYEXT produces a register of the specified width, with bits 0 to
|
||||
@ -416,6 +465,10 @@ public:
|
||||
/// \return The newly created instruction.
|
||||
MachineInstrBuilder buildConstant(unsigned Res, int64_t Val);
|
||||
|
||||
template <typename DstType>
|
||||
MachineInstrBuilder buildConstant(DstType &&Res, int64_t Val) {
|
||||
return buildConstant(getDestFromArg(Res), Val);
|
||||
}
|
||||
/// Build and insert \p Res = G_FCONSTANT \p Val
|
||||
///
|
||||
/// G_FCONSTANT is a floating-point constant with the specified size and
|
||||
|
@ -93,12 +93,14 @@ public:
|
||||
}
|
||||
|
||||
/// Updates liveness when stepping backwards over the instruction \p MI.
|
||||
/// This removes all register units defined or clobbered in \p MI and then
|
||||
/// adds the units used (as in use operands) in \p MI.
|
||||
void stepBackward(const MachineInstr &MI);
|
||||
|
||||
/// Mark all register units live during instruction \p MI.
|
||||
/// This can be used to accumulate live/unoccupied registers over a range of
|
||||
/// instructions.
|
||||
void accumulateBackward(const MachineInstr &MI);
|
||||
/// Adds all register units used, defined or clobbered in \p MI.
|
||||
/// This is useful when walking over a range of instruction to find registers
|
||||
/// unused over the whole range.
|
||||
void accumulate(const MachineInstr &MI);
|
||||
|
||||
/// Adds registers living out of block \p MBB.
|
||||
/// Live out registers are the union of the live-in registers of the successor
|
||||
|
@ -650,7 +650,7 @@ public:
|
||||
MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, uint64_t s,
|
||||
unsigned base_alignment, const AAMDNodes &AAInfo = AAMDNodes(),
|
||||
const MDNode *Ranges = nullptr,
|
||||
SynchronizationScope SynchScope = CrossThread,
|
||||
SyncScope::ID SSID = SyncScope::System,
|
||||
AtomicOrdering Ordering = AtomicOrdering::NotAtomic,
|
||||
AtomicOrdering FailureOrdering = AtomicOrdering::NotAtomic);
|
||||
|
||||
|
@ -114,6 +114,9 @@ public:
|
||||
MOInvariant = 1u << 5,
|
||||
|
||||
// Reserved for use by target-specific passes.
|
||||
// Targets may override getSerializableMachineMemOperandTargetFlags() to
|
||||
// enable MIR serialization/parsing of these flags. If more of these flags
|
||||
// are added, the MIR printing/parsing code will need to be updated as well.
|
||||
MOTargetFlag1 = 1u << 6,
|
||||
MOTargetFlag2 = 1u << 7,
|
||||
MOTargetFlag3 = 1u << 8,
|
||||
@ -124,8 +127,8 @@ public:
|
||||
private:
|
||||
/// Atomic information for this memory operation.
|
||||
struct MachineAtomicInfo {
|
||||
/// Synchronization scope for this memory operation.
|
||||
unsigned SynchScope : 1; // enum SynchronizationScope
|
||||
/// Synchronization scope ID for this memory operation.
|
||||
unsigned SSID : 8; // SyncScope::ID
|
||||
/// Atomic ordering requirements for this memory operation. For cmpxchg
|
||||
/// atomic operations, atomic ordering requirements when store occurs.
|
||||
unsigned Ordering : 4; // enum AtomicOrdering
|
||||
@ -152,7 +155,7 @@ public:
|
||||
unsigned base_alignment,
|
||||
const AAMDNodes &AAInfo = AAMDNodes(),
|
||||
const MDNode *Ranges = nullptr,
|
||||
SynchronizationScope SynchScope = CrossThread,
|
||||
SyncScope::ID SSID = SyncScope::System,
|
||||
AtomicOrdering Ordering = AtomicOrdering::NotAtomic,
|
||||
AtomicOrdering FailureOrdering = AtomicOrdering::NotAtomic);
|
||||
|
||||
@ -202,9 +205,9 @@ public:
|
||||
/// Return the range tag for the memory reference.
|
||||
const MDNode *getRanges() const { return Ranges; }
|
||||
|
||||
/// Return the synchronization scope for this memory operation.
|
||||
SynchronizationScope getSynchScope() const {
|
||||
return static_cast<SynchronizationScope>(AtomicInfo.SynchScope);
|
||||
/// Returns the synchronization scope ID for this memory operation.
|
||||
SyncScope::ID getSyncScopeID() const {
|
||||
return static_cast<SyncScope::ID>(AtomicInfo.SSID);
|
||||
}
|
||||
|
||||
/// Return the atomic ordering requirements for this memory operation. For
|
||||
|
@ -340,6 +340,18 @@ namespace RTLIB {
|
||||
MEMCPY_ELEMENT_UNORDERED_ATOMIC_8,
|
||||
MEMCPY_ELEMENT_UNORDERED_ATOMIC_16,
|
||||
|
||||
MEMMOVE_ELEMENT_UNORDERED_ATOMIC_1,
|
||||
MEMMOVE_ELEMENT_UNORDERED_ATOMIC_2,
|
||||
MEMMOVE_ELEMENT_UNORDERED_ATOMIC_4,
|
||||
MEMMOVE_ELEMENT_UNORDERED_ATOMIC_8,
|
||||
MEMMOVE_ELEMENT_UNORDERED_ATOMIC_16,
|
||||
|
||||
MEMSET_ELEMENT_UNORDERED_ATOMIC_1,
|
||||
MEMSET_ELEMENT_UNORDERED_ATOMIC_2,
|
||||
MEMSET_ELEMENT_UNORDERED_ATOMIC_4,
|
||||
MEMSET_ELEMENT_UNORDERED_ATOMIC_8,
|
||||
MEMSET_ELEMENT_UNORDERED_ATOMIC_16,
|
||||
|
||||
// EXCEPTION HANDLING
|
||||
UNWIND_RESUME,
|
||||
|
||||
@ -515,6 +527,17 @@ namespace RTLIB {
|
||||
/// MEMCPY_ELEMENT_UNORDERED_ATOMIC_* value for the given element size or
|
||||
/// UNKNOW_LIBCALL if there is none.
|
||||
Libcall getMEMCPY_ELEMENT_UNORDERED_ATOMIC(uint64_t ElementSize);
|
||||
|
||||
/// getMEMMOVE_ELEMENT_UNORDERED_ATOMIC - Return
|
||||
/// MEMMOVE_ELEMENT_UNORDERED_ATOMIC_* value for the given element size or
|
||||
/// UNKNOW_LIBCALL if there is none.
|
||||
Libcall getMEMMOVE_ELEMENT_UNORDERED_ATOMIC(uint64_t ElementSize);
|
||||
|
||||
/// getMEMSET_ELEMENT_UNORDERED_ATOMIC - Return
|
||||
/// MEMSET_ELEMENT_UNORDERED_ATOMIC_* value for the given element size or
|
||||
/// UNKNOW_LIBCALL if there is none.
|
||||
Libcall getMEMSET_ELEMENT_UNORDERED_ATOMIC(uint64_t ElementSize);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -235,6 +235,9 @@ class TargetRegisterInfo;
|
||||
"SDep::Output edge cannot use the zero register!");
|
||||
Contents.Reg = Reg;
|
||||
}
|
||||
|
||||
raw_ostream &print(raw_ostream &O,
|
||||
const TargetRegisterInfo *TRI = nullptr) const;
|
||||
};
|
||||
|
||||
template <>
|
||||
@ -458,7 +461,10 @@ class TargetRegisterInfo;
|
||||
|
||||
void dump(const ScheduleDAG *G) const;
|
||||
void dumpAll(const ScheduleDAG *G) const;
|
||||
void print(raw_ostream &O, const ScheduleDAG *G) const;
|
||||
raw_ostream &print(raw_ostream &O,
|
||||
const SUnit *N = nullptr,
|
||||
const SUnit *X = nullptr) const;
|
||||
raw_ostream &print(raw_ostream &O, const ScheduleDAG *G) const;
|
||||
|
||||
private:
|
||||
void ComputeDepth();
|
||||
|
@ -927,7 +927,7 @@ public:
|
||||
SDValue Cmp, SDValue Swp, MachinePointerInfo PtrInfo,
|
||||
unsigned Alignment, AtomicOrdering SuccessOrdering,
|
||||
AtomicOrdering FailureOrdering,
|
||||
SynchronizationScope SynchScope);
|
||||
SyncScope::ID SSID);
|
||||
SDValue getAtomicCmpSwap(unsigned Opcode, const SDLoc &dl, EVT MemVT,
|
||||
SDVTList VTs, SDValue Chain, SDValue Ptr,
|
||||
SDValue Cmp, SDValue Swp, MachineMemOperand *MMO);
|
||||
@ -937,7 +937,7 @@ public:
|
||||
SDValue getAtomic(unsigned Opcode, const SDLoc &dl, EVT MemVT, SDValue Chain,
|
||||
SDValue Ptr, SDValue Val, const Value *PtrVal,
|
||||
unsigned Alignment, AtomicOrdering Ordering,
|
||||
SynchronizationScope SynchScope);
|
||||
SyncScope::ID SSID);
|
||||
SDValue getAtomic(unsigned Opcode, const SDLoc &dl, EVT MemVT, SDValue Chain,
|
||||
SDValue Ptr, SDValue Val, MachineMemOperand *MMO);
|
||||
|
||||
|
@ -1213,8 +1213,8 @@ public:
|
||||
/// Returns the Ranges that describes the dereference.
|
||||
const MDNode *getRanges() const { return MMO->getRanges(); }
|
||||
|
||||
/// Return the synchronization scope for this memory operation.
|
||||
SynchronizationScope getSynchScope() const { return MMO->getSynchScope(); }
|
||||
/// Returns the synchronization scope ID for this memory operation.
|
||||
SyncScope::ID getSyncScopeID() const { return MMO->getSyncScopeID(); }
|
||||
|
||||
/// Return the atomic ordering requirements for this memory operation. For
|
||||
/// cmpxchg atomic operations, return the atomic ordering requirements when
|
||||
@ -1432,8 +1432,8 @@ public:
|
||||
int64_t getSExtValue() const { return Value->getSExtValue(); }
|
||||
|
||||
bool isOne() const { return Value->isOne(); }
|
||||
bool isNullValue() const { return Value->isNullValue(); }
|
||||
bool isAllOnesValue() const { return Value->isAllOnesValue(); }
|
||||
bool isNullValue() const { return Value->isZero(); }
|
||||
bool isAllOnesValue() const { return Value->isMinusOne(); }
|
||||
|
||||
bool isOpaque() const { return ConstantSDNodeBits.IsOpaque; }
|
||||
|
||||
|
@ -735,6 +735,10 @@ public:
|
||||
uint16_t VersionBackendQFE;
|
||||
StringRef Version;
|
||||
|
||||
void setLanguage(SourceLanguage Lang) {
|
||||
Flags = CompileSym3Flags((uint32_t(Flags) & 0xFFFFFF00) | uint32_t(Lang));
|
||||
}
|
||||
|
||||
uint8_t getLanguage() const { return static_cast<uint32_t>(Flags) & 0xFF; }
|
||||
uint32_t getFlags() const { return static_cast<uint32_t>(Flags) & ~0xFF; }
|
||||
|
||||
|
@ -10,9 +10,11 @@
|
||||
#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPEINDEX_H
|
||||
#define LLVM_DEBUGINFO_CODEVIEW_TYPEINDEX_H
|
||||
|
||||
#include "llvm/ADT/DenseMapInfo.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include <cassert>
|
||||
#include <cinttypes>
|
||||
#include <functional>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
@ -265,6 +267,23 @@ struct TypeIndexOffset {
|
||||
void printTypeIndex(ScopedPrinter &Printer, StringRef FieldName, TypeIndex TI,
|
||||
TypeCollection &Types);
|
||||
}
|
||||
}
|
||||
|
||||
template <> struct DenseMapInfo<codeview::TypeIndex> {
|
||||
static inline codeview::TypeIndex getEmptyKey() {
|
||||
return codeview::TypeIndex{DenseMapInfo<uint32_t>::getEmptyKey()};
|
||||
}
|
||||
static inline codeview::TypeIndex getTombstoneKey() {
|
||||
return codeview::TypeIndex{DenseMapInfo<uint32_t>::getTombstoneKey()};
|
||||
}
|
||||
static unsigned getHashValue(const codeview::TypeIndex &TI) {
|
||||
return DenseMapInfo<uint32_t>::getHashValue(TI.getIndex());
|
||||
}
|
||||
static bool isEqual(const codeview::TypeIndex &LHS,
|
||||
const codeview::TypeIndex &RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
||||
|
@ -204,7 +204,9 @@ public:
|
||||
/// need to be consistent with the addresses used to query the DIContext and
|
||||
/// the output of this function should be deterministic, i.e. repeated calls with
|
||||
/// the same Sec should give the same address.
|
||||
virtual uint64_t getSectionLoadAddress(const object::SectionRef &Sec) const = 0;
|
||||
virtual uint64_t getSectionLoadAddress(const object::SectionRef &Sec) const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// If conveniently available, return the content of the given Section.
|
||||
///
|
||||
@ -221,12 +223,28 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
// FIXME: This is untested and unused anywhere in the LLVM project, it's
|
||||
// used/needed by Julia (an external project). It should have some coverage
|
||||
// (at least tests, but ideally example functionality).
|
||||
/// Obtain a copy of this LoadedObjectInfo.
|
||||
///
|
||||
/// The caller is responsible for deallocation once the copy is no longer required.
|
||||
virtual std::unique_ptr<LoadedObjectInfo> clone() const = 0;
|
||||
};
|
||||
|
||||
template <typename Derived, typename Base = LoadedObjectInfo>
|
||||
struct LoadedObjectInfoHelper : Base {
|
||||
protected:
|
||||
LoadedObjectInfoHelper(const LoadedObjectInfoHelper &) = default;
|
||||
LoadedObjectInfoHelper() = default;
|
||||
|
||||
public:
|
||||
template <typename... Ts>
|
||||
LoadedObjectInfoHelper(Ts &&... Args) : Base(std::forward<Ts>(Args)...) {}
|
||||
|
||||
std::unique_ptr<llvm::LoadedObjectInfo> clone() const override {
|
||||
return llvm::make_unique<Derived>(static_cast<const Derived &>(*this));
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_DEBUGINFO_DICONTEXT_H
|
||||
|
@ -226,11 +226,7 @@ public:
|
||||
virtual bool isLittleEndian() const = 0;
|
||||
virtual uint8_t getAddressSize() const = 0;
|
||||
virtual const DWARFSection &getInfoSection() = 0;
|
||||
|
||||
using TypeSectionMap = MapVector<object::SectionRef, DWARFSection,
|
||||
std::map<object::SectionRef, unsigned>>;
|
||||
|
||||
virtual const TypeSectionMap &getTypesSections() = 0;
|
||||
virtual void forEachTypesSections(function_ref<void(DWARFSection &)> F) = 0;
|
||||
virtual StringRef getAbbrevSection() = 0;
|
||||
virtual const DWARFSection &getLocSection() = 0;
|
||||
virtual StringRef getARangeSection() = 0;
|
||||
@ -252,7 +248,8 @@ public:
|
||||
|
||||
// Sections for DWARF5 split dwarf proposal.
|
||||
virtual const DWARFSection &getInfoDWOSection() = 0;
|
||||
virtual const TypeSectionMap &getTypesDWOSections() = 0;
|
||||
virtual void
|
||||
forEachTypesDWOSections(function_ref<void(DWARFSection &)> F) = 0;
|
||||
virtual StringRef getAbbrevDWOSection() = 0;
|
||||
virtual const DWARFSection &getLineDWOSection() = 0;
|
||||
virtual const DWARFSection &getLocDWOSection() = 0;
|
||||
@ -294,6 +291,9 @@ enum class ErrorPolicy { Halt, Continue };
|
||||
class DWARFContextInMemory : public DWARFContext {
|
||||
virtual void anchor();
|
||||
|
||||
using TypeSectionMap = MapVector<object::SectionRef, DWARFSection,
|
||||
std::map<object::SectionRef, unsigned>>;
|
||||
|
||||
StringRef FileName;
|
||||
bool IsLittleEndian;
|
||||
uint8_t AddressSize;
|
||||
@ -338,7 +338,8 @@ class DWARFContextInMemory : public DWARFContext {
|
||||
|
||||
SmallVector<SmallString<32>, 4> UncompressedSections;
|
||||
|
||||
StringRef *MapSectionToMember(StringRef Name);
|
||||
DWARFSection *mapNameToDWARFSection(StringRef Name);
|
||||
StringRef *mapSectionToMember(StringRef Name);
|
||||
|
||||
/// If Sec is compressed section, decompresses and updates its contents
|
||||
/// provided by Data. Otherwise leaves it unchanged.
|
||||
@ -362,7 +363,10 @@ public:
|
||||
bool isLittleEndian() const override { return IsLittleEndian; }
|
||||
uint8_t getAddressSize() const override { return AddressSize; }
|
||||
const DWARFSection &getInfoSection() override { return InfoSection; }
|
||||
const TypeSectionMap &getTypesSections() override { return TypesSections; }
|
||||
void forEachTypesSections(function_ref<void(DWARFSection &)> F) override {
|
||||
for (auto &P : TypesSections)
|
||||
F(P.second);
|
||||
}
|
||||
StringRef getAbbrevSection() override { return AbbrevSection; }
|
||||
const DWARFSection &getLocSection() override { return LocSection; }
|
||||
StringRef getARangeSection() override { return ARangeSection; }
|
||||
@ -389,8 +393,9 @@ public:
|
||||
// Sections for DWARF5 split dwarf proposal.
|
||||
const DWARFSection &getInfoDWOSection() override { return InfoDWOSection; }
|
||||
|
||||
const TypeSectionMap &getTypesDWOSections() override {
|
||||
return TypesDWOSections;
|
||||
void forEachTypesDWOSections(function_ref<void(DWARFSection &)> F) override {
|
||||
for (auto &P : TypesDWOSections)
|
||||
F(P.second);
|
||||
}
|
||||
|
||||
StringRef getAbbrevDWOSection() override { return AbbrevDWOSection; }
|
||||
|
@ -47,6 +47,7 @@ public:
|
||||
DbiModuleDescriptorBuilder &
|
||||
operator=(const DbiModuleDescriptorBuilder &) = delete;
|
||||
|
||||
void setPdbFilePathNI(uint32_t NI);
|
||||
void setObjFileName(StringRef Name);
|
||||
void addSymbol(codeview::CVSymbol Symbol);
|
||||
|
||||
@ -68,6 +69,10 @@ public:
|
||||
|
||||
uint32_t calculateSerializedLength() const;
|
||||
|
||||
/// Return the offset within the module symbol stream of the next symbol
|
||||
/// record passed to addSymbol. Add four to account for the signature.
|
||||
uint32_t getNextSymbolOffset() const { return SymbolByteSize + 4; }
|
||||
|
||||
void finalize();
|
||||
Error finalizeMsfLayout();
|
||||
|
||||
@ -81,6 +86,7 @@ private:
|
||||
msf::MSFBuilder &MSF;
|
||||
|
||||
uint32_t SymbolByteSize = 0;
|
||||
uint32_t PdbFilePathNI = 0;
|
||||
std::string ModuleName;
|
||||
std::string ObjFileName;
|
||||
std::vector<std::string> SourceFiles;
|
||||
|
@ -83,6 +83,8 @@ public:
|
||||
FixedStreamArray<SecMapEntry> getSectionMap() const;
|
||||
void visitSectionContributions(ISectionContribVisitor &Visitor) const;
|
||||
|
||||
Expected<StringRef> getECName(uint32_t NI) const;
|
||||
|
||||
private:
|
||||
Error initializeSectionContributionData();
|
||||
Error initializeSectionHeadersData();
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "llvm/Support/Error.h"
|
||||
|
||||
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBTypes.h"
|
||||
#include "llvm/Support/BinaryByteStream.h"
|
||||
@ -54,8 +55,13 @@ public:
|
||||
// Add given bytes as a new stream.
|
||||
Error addDbgStream(pdb::DbgHeaderType Type, ArrayRef<uint8_t> Data);
|
||||
|
||||
uint32_t addECName(StringRef Name);
|
||||
|
||||
uint32_t calculateSerializedLength() const;
|
||||
|
||||
void setPublicsStreamIndex(uint32_t Index);
|
||||
void setSymbolRecordStreamIndex(uint32_t Index);
|
||||
|
||||
Expected<DbiModuleDescriptorBuilder &> addModuleInfo(StringRef ModuleName);
|
||||
Error addModuleSourceFile(StringRef Module, StringRef File);
|
||||
Error addModuleSourceFile(DbiModuleDescriptorBuilder &Module, StringRef File);
|
||||
@ -75,7 +81,7 @@ public:
|
||||
private:
|
||||
struct DebugStream {
|
||||
ArrayRef<uint8_t> Data;
|
||||
uint16_t StreamNumber = 0;
|
||||
uint16_t StreamNumber = kInvalidStreamIndex;
|
||||
};
|
||||
|
||||
Error finalize();
|
||||
@ -87,7 +93,6 @@ private:
|
||||
uint32_t calculateNamesBufferSize() const;
|
||||
uint32_t calculateDbgStreamsSize() const;
|
||||
|
||||
Error generateModiSubstream();
|
||||
Error generateFileInfoSubstream();
|
||||
|
||||
msf::MSFBuilder &Msf;
|
||||
@ -100,6 +105,8 @@ private:
|
||||
uint16_t PdbDllRbld;
|
||||
uint16_t Flags;
|
||||
PDB_Machine MachineType;
|
||||
uint32_t PublicsStreamIndex = kInvalidStreamIndex;
|
||||
uint32_t SymRecordStreamIndex = kInvalidStreamIndex;
|
||||
|
||||
const DbiStreamHeader *Header;
|
||||
|
||||
@ -108,6 +115,7 @@ private:
|
||||
|
||||
StringMap<uint32_t> SourceFileNames;
|
||||
|
||||
PDBStringTableBuilder ECNamesBuilder;
|
||||
WritableBinaryStreamRef NamesBuffer;
|
||||
MutableBinaryByteStream FileInfoBuffer;
|
||||
std::vector<SectionContrib> SectionContribs;
|
||||
|
@ -44,7 +44,7 @@ public:
|
||||
bool get(StringRef Stream, uint32_t &StreamNo) const;
|
||||
void set(StringRef Stream, uint32_t StreamNo);
|
||||
void remove(StringRef Stream);
|
||||
|
||||
const StringMap<uint32_t> &getStringMap() const { return Mapping; }
|
||||
iterator_range<StringMapConstIterator<uint32_t>> entries() const;
|
||||
|
||||
private:
|
||||
|
49
include/llvm/DebugInfo/PDB/Native/NativeBuiltinSymbol.h
Normal file
49
include/llvm/DebugInfo/PDB/Native/NativeBuiltinSymbol.h
Normal file
@ -0,0 +1,49 @@
|
||||
//===- NativeBuiltinSymbol.h -------------------------------------- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_DEBUGINFO_PDB_NATIVE_NATIVEBUILTINSYMBOL_H
|
||||
#define LLVM_DEBUGINFO_PDB_NATIVE_NATIVEBUILTINSYMBOL_H
|
||||
|
||||
#include "llvm/DebugInfo/PDB/Native/NativeRawSymbol.h"
|
||||
|
||||
#include "llvm/DebugInfo/PDB/PDBTypes.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace pdb {
|
||||
|
||||
class NativeSession;
|
||||
|
||||
class NativeBuiltinSymbol : public NativeRawSymbol {
|
||||
public:
|
||||
NativeBuiltinSymbol(NativeSession &PDBSession, SymIndexId Id,
|
||||
PDB_BuiltinType T, uint64_t L);
|
||||
~NativeBuiltinSymbol() override;
|
||||
|
||||
virtual std::unique_ptr<NativeRawSymbol> clone() const override;
|
||||
|
||||
void dump(raw_ostream &OS, int Indent) const override;
|
||||
|
||||
PDB_SymType getSymTag() const override;
|
||||
|
||||
PDB_BuiltinType getBuiltinType() const override;
|
||||
bool isConstType() const override;
|
||||
uint64_t getLength() const override;
|
||||
bool isUnalignedType() const override;
|
||||
bool isVolatileType() const override;
|
||||
|
||||
protected:
|
||||
NativeSession &Session;
|
||||
PDB_BuiltinType Type;
|
||||
uint64_t Length;
|
||||
};
|
||||
|
||||
} // namespace pdb
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
@ -18,7 +18,7 @@ namespace pdb {
|
||||
|
||||
class NativeCompilandSymbol : public NativeRawSymbol {
|
||||
public:
|
||||
NativeCompilandSymbol(NativeSession &Session, uint32_t SymbolId,
|
||||
NativeCompilandSymbol(NativeSession &Session, SymIndexId SymbolId,
|
||||
DbiModuleDescriptor MI);
|
||||
|
||||
std::unique_ptr<NativeRawSymbol> clone() const override;
|
||||
|
@ -18,7 +18,7 @@ namespace pdb {
|
||||
|
||||
class NativeExeSymbol : public NativeRawSymbol {
|
||||
public:
|
||||
NativeExeSymbol(NativeSession &Session, uint32_t SymbolId);
|
||||
NativeExeSymbol(NativeSession &Session, SymIndexId SymbolId);
|
||||
|
||||
std::unique_ptr<NativeRawSymbol> clone() const override;
|
||||
|
||||
|
@ -19,9 +19,11 @@ namespace pdb {
|
||||
|
||||
class NativeSession;
|
||||
|
||||
typedef uint32_t SymIndexId;
|
||||
|
||||
class NativeRawSymbol : public IPDBRawSymbol {
|
||||
public:
|
||||
NativeRawSymbol(NativeSession &PDBSession, uint32_t SymbolId);
|
||||
NativeRawSymbol(NativeSession &PDBSession, SymIndexId SymbolId);
|
||||
|
||||
virtual std::unique_ptr<NativeRawSymbol> clone() const = 0;
|
||||
|
||||
@ -205,7 +207,7 @@ public:
|
||||
|
||||
protected:
|
||||
NativeSession &Session;
|
||||
uint32_t SymbolId;
|
||||
SymIndexId SymbolId;
|
||||
};
|
||||
|
||||
} // end namespace pdb
|
||||
|
@ -10,9 +10,13 @@
|
||||
#ifndef LLVM_DEBUGINFO_PDB_NATIVE_NATIVESESSION_H
|
||||
#define LLVM_DEBUGINFO_PDB_NATIVE_NATIVESESSION_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
|
||||
#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h"
|
||||
#include "llvm/DebugInfo/PDB/IPDBSession.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/NativeBuiltinSymbol.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/NativeRawSymbol.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
@ -35,6 +39,8 @@ public:
|
||||
std::unique_ptr<PDBSymbolCompiland>
|
||||
createCompilandSymbol(DbiModuleDescriptor MI);
|
||||
|
||||
SymIndexId findSymbolByTypeIndex(codeview::TypeIndex TI);
|
||||
|
||||
uint64_t getLoadAddress() const override;
|
||||
void setLoadAddress(uint64_t Address) override;
|
||||
std::unique_ptr<PDBSymbolExe> getGlobalScope() override;
|
||||
@ -77,6 +83,7 @@ private:
|
||||
std::unique_ptr<PDBFile> Pdb;
|
||||
std::unique_ptr<BumpPtrAllocator> Allocator;
|
||||
std::vector<std::unique_ptr<NativeRawSymbol>> SymbolCache;
|
||||
DenseMap<codeview::TypeIndex, SymIndexId> TypeIndexToSymbolId;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -31,11 +31,13 @@ class MSFBuilder;
|
||||
namespace pdb {
|
||||
class DbiStreamBuilder;
|
||||
class InfoStreamBuilder;
|
||||
class PublicsStreamBuilder;
|
||||
class TpiStreamBuilder;
|
||||
|
||||
class PDBFileBuilder {
|
||||
public:
|
||||
explicit PDBFileBuilder(BumpPtrAllocator &Allocator);
|
||||
~PDBFileBuilder();
|
||||
PDBFileBuilder(const PDBFileBuilder &) = delete;
|
||||
PDBFileBuilder &operator=(const PDBFileBuilder &) = delete;
|
||||
|
||||
@ -47,6 +49,7 @@ public:
|
||||
TpiStreamBuilder &getTpiBuilder();
|
||||
TpiStreamBuilder &getIpiBuilder();
|
||||
PDBStringTableBuilder &getStringTableBuilder();
|
||||
PublicsStreamBuilder &getPublicsBuilder();
|
||||
|
||||
Error commit(StringRef Filename);
|
||||
|
||||
@ -61,6 +64,7 @@ private:
|
||||
std::unique_ptr<msf::MSFBuilder> Msf;
|
||||
std::unique_ptr<InfoStreamBuilder> Info;
|
||||
std::unique_ptr<DbiStreamBuilder> Dbi;
|
||||
std::unique_ptr<PublicsStreamBuilder> Publics;
|
||||
std::unique_ptr<TpiStreamBuilder> Tpi;
|
||||
std::unique_ptr<TpiStreamBuilder> Ipi;
|
||||
|
||||
|
@ -56,7 +56,6 @@ private:
|
||||
const PDBStringTableHeader *Header = nullptr;
|
||||
codeview::DebugStringTableSubsectionRef Strings;
|
||||
FixedStreamArray<support::ulittle32_t> IDs;
|
||||
uint32_t ByteSize = 0;
|
||||
uint32_t NameCount = 0;
|
||||
};
|
||||
|
||||
|
@ -25,8 +25,6 @@ struct GSIHashHeader;
|
||||
class PDBFile;
|
||||
|
||||
class PublicsStream {
|
||||
struct HeaderInfo;
|
||||
|
||||
public:
|
||||
PublicsStream(PDBFile &File, std::unique_ptr<msf::MappedBlockStream> Stream);
|
||||
~PublicsStream();
|
||||
@ -65,7 +63,7 @@ private:
|
||||
FixedStreamArray<support::ulittle32_t> ThunkMap;
|
||||
FixedStreamArray<SectionOffset> SectionOffsets;
|
||||
|
||||
const HeaderInfo *Header;
|
||||
const PublicsStreamHeader *Header;
|
||||
const GSIHashHeader *HashHdr;
|
||||
};
|
||||
}
|
||||
|
54
include/llvm/DebugInfo/PDB/Native/PublicsStreamBuilder.h
Normal file
54
include/llvm/DebugInfo/PDB/Native/PublicsStreamBuilder.h
Normal file
@ -0,0 +1,54 @@
|
||||
//===- PublicsStreamBuilder.h - PDB Publics Stream Creation -----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_DEBUGINFO_PDB_RAW_PDBPUBLICSTREAMBUILDER_H
|
||||
#define LLVM_DEBUGINFO_PDB_RAW_PDBPUBLICSTREAMBUILDER_H
|
||||
|
||||
#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
|
||||
#include "llvm/Support/BinaryByteStream.h"
|
||||
#include "llvm/Support/BinaryStreamRef.h"
|
||||
#include "llvm/Support/BinaryStreamWriter.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace msf {
|
||||
class MSFBuilder;
|
||||
}
|
||||
namespace pdb {
|
||||
class PublicsStream;
|
||||
struct PublicsStreamHeader;
|
||||
|
||||
class PublicsStreamBuilder {
|
||||
public:
|
||||
explicit PublicsStreamBuilder(msf::MSFBuilder &Msf);
|
||||
~PublicsStreamBuilder();
|
||||
|
||||
PublicsStreamBuilder(const PublicsStreamBuilder &) = delete;
|
||||
PublicsStreamBuilder &operator=(const PublicsStreamBuilder &) = delete;
|
||||
|
||||
Error finalizeMsfLayout();
|
||||
uint32_t calculateSerializedLength() const;
|
||||
|
||||
Error commit(BinaryStreamWriter &PublicsWriter);
|
||||
|
||||
uint32_t getStreamIndex() const { return StreamIdx; }
|
||||
uint32_t getRecordStreamIdx() const { return RecordStreamIdx; }
|
||||
|
||||
private:
|
||||
uint32_t StreamIdx = kInvalidStreamIndex;
|
||||
uint32_t RecordStreamIdx = kInvalidStreamIndex;
|
||||
std::vector<PSHashRecord> HashRecords;
|
||||
msf::MSFBuilder &Msf;
|
||||
};
|
||||
} // namespace pdb
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
@ -255,6 +255,19 @@ struct ModuleInfoHeader {
|
||||
/// char ObjFileName[];
|
||||
};
|
||||
|
||||
// This is PSGSIHDR struct defined in
|
||||
// https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/dbi/gsi.h
|
||||
struct PublicsStreamHeader {
|
||||
support::ulittle32_t SymHash;
|
||||
support::ulittle32_t AddrMap;
|
||||
support::ulittle32_t NumThunks;
|
||||
support::ulittle32_t SizeOfThunk;
|
||||
support::ulittle16_t ISectThunkTable;
|
||||
char Padding[2];
|
||||
support::ulittle32_t OffThunkTable;
|
||||
support::ulittle32_t NumSections;
|
||||
};
|
||||
|
||||
/// Defines a 128-bit unique identifier. This maps to a GUID on Windows, but
|
||||
/// is abstracted here for the purposes of non-Windows platforms that don't have
|
||||
/// the GUID structure defined.
|
||||
|
@ -21,6 +21,8 @@
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#include "llvm/Support/Error.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class GlobalValue;
|
||||
@ -41,10 +43,11 @@ public:
|
||||
|
||||
enum FlagNames : UnderlyingType {
|
||||
None = 0,
|
||||
Weak = 1U << 0,
|
||||
Common = 1U << 1,
|
||||
Absolute = 1U << 2,
|
||||
Exported = 1U << 3
|
||||
HasError = 1U << 0,
|
||||
Weak = 1U << 1,
|
||||
Common = 1U << 2,
|
||||
Absolute = 1U << 3,
|
||||
Exported = 1U << 4
|
||||
};
|
||||
|
||||
/// @brief Default-construct a JITSymbolFlags instance.
|
||||
@ -53,6 +56,11 @@ public:
|
||||
/// @brief Construct a JITSymbolFlags instance from the given flags.
|
||||
JITSymbolFlags(FlagNames Flags) : Flags(Flags) {}
|
||||
|
||||
/// @brief Return true if there was an error retrieving this symbol.
|
||||
bool hasError() const {
|
||||
return (Flags & HasError) == HasError;
|
||||
}
|
||||
|
||||
/// @brief Returns true is the Weak flag is set.
|
||||
bool isWeak() const {
|
||||
return (Flags & Weak) == Weak;
|
||||
@ -113,11 +121,17 @@ private:
|
||||
/// @brief Represents a symbol in the JIT.
|
||||
class JITSymbol {
|
||||
public:
|
||||
using GetAddressFtor = std::function<JITTargetAddress()>;
|
||||
using GetAddressFtor = std::function<Expected<JITTargetAddress>()>;
|
||||
|
||||
/// @brief Create a 'null' symbol that represents failure to find a symbol
|
||||
/// definition.
|
||||
JITSymbol(std::nullptr_t) {}
|
||||
/// @brief Create a 'null' symbol, used to represent a "symbol not found"
|
||||
/// result from a successful (non-erroneous) lookup.
|
||||
JITSymbol(std::nullptr_t)
|
||||
: CachedAddr(0) {}
|
||||
|
||||
/// @brief Create a JITSymbol representing an error in the symbol lookup
|
||||
/// process (e.g. a network failure during a remote lookup).
|
||||
JITSymbol(Error Err)
|
||||
: Err(std::move(Err)), Flags(JITSymbolFlags::HasError) {}
|
||||
|
||||
/// @brief Create a symbol for a definition with a known address.
|
||||
JITSymbol(JITTargetAddress Addr, JITSymbolFlags Flags)
|
||||
@ -137,18 +151,59 @@ public:
|
||||
/// user can materialize the definition at any time by calling the getAddress
|
||||
/// method.
|
||||
JITSymbol(GetAddressFtor GetAddress, JITSymbolFlags Flags)
|
||||
: GetAddress(std::move(GetAddress)), Flags(Flags) {}
|
||||
: GetAddress(std::move(GetAddress)), CachedAddr(0), Flags(Flags) {}
|
||||
|
||||
JITSymbol(const JITSymbol&) = delete;
|
||||
JITSymbol& operator=(const JITSymbol&) = delete;
|
||||
|
||||
JITSymbol(JITSymbol &&Other)
|
||||
: GetAddress(std::move(Other.GetAddress)), Flags(std::move(Other.Flags)) {
|
||||
if (Flags.hasError())
|
||||
Err = std::move(Other.Err);
|
||||
else
|
||||
CachedAddr = std::move(Other.CachedAddr);
|
||||
}
|
||||
|
||||
JITSymbol& operator=(JITSymbol &&Other) {
|
||||
GetAddress = std::move(Other.GetAddress);
|
||||
Flags = std::move(Other.Flags);
|
||||
if (Flags.hasError())
|
||||
Err = std::move(Other.Err);
|
||||
else
|
||||
CachedAddr = std::move(Other.CachedAddr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~JITSymbol() {
|
||||
if (Flags.hasError())
|
||||
Err.~Error();
|
||||
else
|
||||
CachedAddr.~JITTargetAddress();
|
||||
}
|
||||
|
||||
/// @brief Returns true if the symbol exists, false otherwise.
|
||||
explicit operator bool() const { return CachedAddr || GetAddress; }
|
||||
explicit operator bool() const {
|
||||
return !Flags.hasError() && (CachedAddr || GetAddress);
|
||||
}
|
||||
|
||||
/// @brief Move the error field value out of this JITSymbol.
|
||||
Error takeError() {
|
||||
if (Flags.hasError())
|
||||
return std::move(Err);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
/// @brief Get the address of the symbol in the target address space. Returns
|
||||
/// '0' if the symbol does not exist.
|
||||
JITTargetAddress getAddress() {
|
||||
Expected<JITTargetAddress> getAddress() {
|
||||
assert(!Flags.hasError() && "getAddress called on error value");
|
||||
if (GetAddress) {
|
||||
CachedAddr = GetAddress();
|
||||
assert(CachedAddr && "Symbol could not be materialized.");
|
||||
GetAddress = nullptr;
|
||||
if (auto CachedAddrOrErr = GetAddress()) {
|
||||
GetAddress = nullptr;
|
||||
CachedAddr = *CachedAddrOrErr;
|
||||
assert(CachedAddr && "Symbol could not be materialized.");
|
||||
} else
|
||||
return CachedAddrOrErr.takeError();
|
||||
}
|
||||
return CachedAddr;
|
||||
}
|
||||
@ -157,7 +212,10 @@ public:
|
||||
|
||||
private:
|
||||
GetAddressFtor GetAddress;
|
||||
JITTargetAddress CachedAddr = 0;
|
||||
union {
|
||||
JITTargetAddress CachedAddr;
|
||||
Error Err;
|
||||
};
|
||||
JITSymbolFlags Flags;
|
||||
};
|
||||
|
||||
|
@ -146,7 +146,7 @@ private:
|
||||
std::unique_ptr<JITSymbolResolver>)>;
|
||||
|
||||
struct SourceModuleEntry {
|
||||
std::unique_ptr<ResourceOwner<Module>> SourceMod;
|
||||
std::shared_ptr<Module> SourceMod;
|
||||
std::set<Function*> StubsToClone;
|
||||
};
|
||||
|
||||
@ -154,7 +154,7 @@ private:
|
||||
using SourceModuleHandle = typename SourceModulesList::size_type;
|
||||
|
||||
SourceModuleHandle
|
||||
addSourceModule(std::unique_ptr<ResourceOwner<Module>> M) {
|
||||
addSourceModule(std::shared_ptr<Module> M) {
|
||||
SourceModuleHandle H = SourceModules.size();
|
||||
SourceModules.push_back(SourceModuleEntry());
|
||||
SourceModules.back().SourceMod = std::move(M);
|
||||
@ -162,7 +162,7 @@ private:
|
||||
}
|
||||
|
||||
Module& getSourceModule(SourceModuleHandle H) {
|
||||
return SourceModules[H].SourceMod->getResource();
|
||||
return *SourceModules[H].SourceMod;
|
||||
}
|
||||
|
||||
std::set<Function*>& getStubsToClone(SourceModuleHandle H) {
|
||||
@ -176,19 +176,21 @@ private:
|
||||
for (auto BLH : BaseLayerHandles)
|
||||
if (auto Sym = BaseLayer.findSymbolIn(BLH, Name, ExportedSymbolsOnly))
|
||||
return Sym;
|
||||
else if (auto Err = Sym.takeError())
|
||||
return std::move(Err);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void removeModulesFromBaseLayer(BaseLayerT &BaseLayer) {
|
||||
Error removeModulesFromBaseLayer(BaseLayerT &BaseLayer) {
|
||||
for (auto &BLH : BaseLayerHandles)
|
||||
BaseLayer.removeModule(BLH);
|
||||
if (auto Err = BaseLayer.removeModule(BLH))
|
||||
return Err;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
std::unique_ptr<JITSymbolResolver> ExternalSymbolResolver;
|
||||
std::unique_ptr<ResourceOwner<RuntimeDyld::MemoryManager>> MemMgr;
|
||||
std::shared_ptr<JITSymbolResolver> ExternalSymbolResolver;
|
||||
std::unique_ptr<IndirectStubsMgrT> StubsMgr;
|
||||
StaticGlobalRenamer StaticRenamer;
|
||||
ModuleAdderFtor ModuleAdder;
|
||||
SourceModulesList SourceModules;
|
||||
std::vector<BaseLayerModuleHandleT> BaseLayerHandles;
|
||||
};
|
||||
@ -196,6 +198,7 @@ private:
|
||||
using LogicalDylibList = std::list<LogicalDylib>;
|
||||
|
||||
public:
|
||||
|
||||
/// @brief Handle to loaded module.
|
||||
using ModuleHandleT = typename LogicalDylibList::iterator;
|
||||
|
||||
@ -217,48 +220,41 @@ public:
|
||||
CloneStubsIntoPartitions(CloneStubsIntoPartitions) {}
|
||||
|
||||
~CompileOnDemandLayer() {
|
||||
// FIXME: Report error on log.
|
||||
while (!LogicalDylibs.empty())
|
||||
removeModule(LogicalDylibs.begin());
|
||||
consumeError(removeModule(LogicalDylibs.begin()));
|
||||
}
|
||||
|
||||
/// @brief Add a module to the compile-on-demand layer.
|
||||
template <typename MemoryManagerPtrT, typename SymbolResolverPtrT>
|
||||
ModuleHandleT addModule(std::shared_ptr<Module> M,
|
||||
MemoryManagerPtrT MemMgr,
|
||||
SymbolResolverPtrT Resolver) {
|
||||
Expected<ModuleHandleT>
|
||||
addModule(std::shared_ptr<Module> M,
|
||||
std::shared_ptr<JITSymbolResolver> Resolver) {
|
||||
|
||||
LogicalDylibs.push_back(LogicalDylib());
|
||||
auto &LD = LogicalDylibs.back();
|
||||
LD.ExternalSymbolResolver = std::move(Resolver);
|
||||
LD.StubsMgr = CreateIndirectStubsManager();
|
||||
|
||||
auto &MemMgrRef = *MemMgr;
|
||||
LD.MemMgr = wrapOwnership<RuntimeDyld::MemoryManager>(std::move(MemMgr));
|
||||
|
||||
LD.ModuleAdder =
|
||||
[&MemMgrRef](BaseLayerT &B, std::unique_ptr<Module> M,
|
||||
std::unique_ptr<JITSymbolResolver> R) {
|
||||
return B.addModule(std::move(M), &MemMgrRef, std::move(R));
|
||||
};
|
||||
|
||||
// Process each of the modules in this module set.
|
||||
addLogicalModule(LogicalDylibs.back(), std::move(M));
|
||||
if (auto Err = addLogicalModule(LD, std::move(M)))
|
||||
return std::move(Err);
|
||||
|
||||
return std::prev(LogicalDylibs.end());
|
||||
}
|
||||
|
||||
/// @brief Add extra modules to an existing logical module.
|
||||
void addExtraModule(ModuleHandleT H, std::shared_ptr<Module> M) {
|
||||
addLogicalModule(*H, std::move(M));
|
||||
Error addExtraModule(ModuleHandleT H, std::shared_ptr<Module> M) {
|
||||
return addLogicalModule(*H, std::move(M));
|
||||
}
|
||||
|
||||
/// @brief Remove the module represented by the given handle.
|
||||
///
|
||||
/// This will remove all modules in the layers below that were derived from
|
||||
/// the module represented by H.
|
||||
void removeModule(ModuleHandleT H) {
|
||||
H->removeModulesFromBaseLayer(BaseLayer);
|
||||
Error removeModule(ModuleHandleT H) {
|
||||
auto Err = H->removeModulesFromBaseLayer(BaseLayer);
|
||||
LogicalDylibs.erase(H);
|
||||
return Err;
|
||||
}
|
||||
|
||||
/// @brief Search for the given named symbol.
|
||||
@ -272,6 +268,8 @@ public:
|
||||
return Sym;
|
||||
if (auto Sym = findSymbolIn(LDI, Name, ExportedSymbolsOnly))
|
||||
return Sym;
|
||||
else if (auto Err = Sym.takeError())
|
||||
return std::move(Err);
|
||||
}
|
||||
return BaseLayer.findSymbol(Name, ExportedSymbolsOnly);
|
||||
}
|
||||
@ -309,8 +307,9 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename ModulePtrT>
|
||||
void addLogicalModule(LogicalDylib &LD, ModulePtrT SrcMPtr) {
|
||||
|
||||
Error addLogicalModule(LogicalDylib &LD, std::shared_ptr<Module> SrcMPtr) {
|
||||
|
||||
// Rename all static functions / globals to $static.X :
|
||||
// This will unique the names across all modules in the logical dylib,
|
||||
// simplifying symbol lookup.
|
||||
@ -322,7 +321,7 @@ private:
|
||||
|
||||
// Create a logical module handle for SrcM within the logical dylib.
|
||||
Module &SrcM = *SrcMPtr;
|
||||
auto LMId = LD.addSourceModule(wrapOwnership<Module>(std::move(SrcMPtr)));
|
||||
auto LMId = LD.addSourceModule(std::move(SrcMPtr));
|
||||
|
||||
// Create stub functions.
|
||||
const DataLayout &DL = SrcM.getDataLayout();
|
||||
@ -335,9 +334,12 @@ private:
|
||||
|
||||
// Skip weak functions for which we already have definitions.
|
||||
auto MangledName = mangle(F.getName(), DL);
|
||||
if (F.hasWeakLinkage() || F.hasLinkOnceLinkage())
|
||||
if (F.hasWeakLinkage() || F.hasLinkOnceLinkage()) {
|
||||
if (auto Sym = LD.findSymbol(BaseLayer, MangledName, false))
|
||||
continue;
|
||||
else if (auto Err = Sym.takeError())
|
||||
return std::move(Err);
|
||||
}
|
||||
|
||||
// Record all functions defined by this module.
|
||||
if (CloneStubsIntoPartitions)
|
||||
@ -350,9 +352,15 @@ private:
|
||||
StubInits[MangledName] =
|
||||
std::make_pair(CCInfo.getAddress(),
|
||||
JITSymbolFlags::fromGlobalValue(F));
|
||||
CCInfo.setCompileAction([this, &LD, LMId, &F]() {
|
||||
return this->extractAndCompile(LD, LMId, F);
|
||||
});
|
||||
CCInfo.setCompileAction([this, &LD, LMId, &F]() -> JITTargetAddress {
|
||||
if (auto FnImplAddrOrErr = this->extractAndCompile(LD, LMId, F))
|
||||
return *FnImplAddrOrErr;
|
||||
else {
|
||||
// FIXME: Report error, return to 'abort' or something similar.
|
||||
consumeError(FnImplAddrOrErr.takeError());
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
auto EC = LD.StubsMgr->createStubs(StubInits);
|
||||
@ -367,7 +375,7 @@ private:
|
||||
// empty globals module.
|
||||
if (SrcM.global_empty() && SrcM.alias_empty() &&
|
||||
!SrcM.getModuleFlagsMetadata())
|
||||
return;
|
||||
return Error::success();
|
||||
|
||||
// Create the GlobalValues module.
|
||||
auto GVsM = llvm::make_unique<Module>((SrcM.getName() + ".globals").str(),
|
||||
@ -393,8 +401,9 @@ private:
|
||||
|
||||
// Initializers may refer to functions declared (but not defined) in this
|
||||
// module. Build a materializer to clone decls on demand.
|
||||
Error MaterializerErrors = Error::success();
|
||||
auto Materializer = createLambdaMaterializer(
|
||||
[&LD, &GVsM](Value *V) -> Value* {
|
||||
[&LD, &GVsM, &MaterializerErrors](Value *V) -> Value* {
|
||||
if (auto *F = dyn_cast<Function>(V)) {
|
||||
// Decls in the original module just get cloned.
|
||||
if (F->isDeclaration())
|
||||
@ -405,13 +414,24 @@ private:
|
||||
// instead.
|
||||
const DataLayout &DL = GVsM->getDataLayout();
|
||||
std::string FName = mangle(F->getName(), DL);
|
||||
auto StubSym = LD.StubsMgr->findStub(FName, false);
|
||||
unsigned PtrBitWidth = DL.getPointerTypeSizeInBits(F->getType());
|
||||
ConstantInt *StubAddr =
|
||||
ConstantInt::get(GVsM->getContext(),
|
||||
APInt(PtrBitWidth, StubSym.getAddress()));
|
||||
JITTargetAddress StubAddr = 0;
|
||||
|
||||
// Get the address for the stub. If we encounter an error while
|
||||
// doing so, stash it in the MaterializerErrors variable and use a
|
||||
// null address as a placeholder.
|
||||
if (auto StubSym = LD.StubsMgr->findStub(FName, false)) {
|
||||
if (auto StubAddrOrErr = StubSym.getAddress())
|
||||
StubAddr = *StubAddrOrErr;
|
||||
else
|
||||
MaterializerErrors = joinErrors(std::move(MaterializerErrors),
|
||||
StubAddrOrErr.takeError());
|
||||
}
|
||||
|
||||
ConstantInt *StubAddrCI =
|
||||
ConstantInt::get(GVsM->getContext(), APInt(PtrBitWidth, StubAddr));
|
||||
Constant *Init = ConstantExpr::getCast(Instruction::IntToPtr,
|
||||
StubAddr, F->getType());
|
||||
StubAddrCI, F->getType());
|
||||
return GlobalAlias::create(F->getFunctionType(),
|
||||
F->getType()->getAddressSpace(),
|
||||
F->getLinkage(), F->getName(),
|
||||
@ -435,22 +455,31 @@ private:
|
||||
NewA->setAliasee(cast<Constant>(Init));
|
||||
}
|
||||
|
||||
if (MaterializerErrors)
|
||||
return MaterializerErrors;
|
||||
|
||||
// Build a resolver for the globals module and add it to the base layer.
|
||||
auto GVsResolver = createLambdaResolver(
|
||||
[this, &LD](const std::string &Name) {
|
||||
[this, &LD](const std::string &Name) -> JITSymbol {
|
||||
if (auto Sym = LD.StubsMgr->findStub(Name, false))
|
||||
return Sym;
|
||||
if (auto Sym = LD.findSymbol(BaseLayer, Name, false))
|
||||
return Sym;
|
||||
else if (auto Err = Sym.takeError())
|
||||
return std::move(Err);
|
||||
return LD.ExternalSymbolResolver->findSymbolInLogicalDylib(Name);
|
||||
},
|
||||
[&LD](const std::string &Name) {
|
||||
return LD.ExternalSymbolResolver->findSymbol(Name);
|
||||
});
|
||||
|
||||
auto GVsH = LD.ModuleAdder(BaseLayer, std::move(GVsM),
|
||||
std::move(GVsResolver));
|
||||
LD.BaseLayerHandles.push_back(GVsH);
|
||||
if (auto GVsHOrErr =
|
||||
BaseLayer.addModule(std::move(GVsM), std::move(GVsResolver)))
|
||||
LD.BaseLayerHandles.push_back(*GVsHOrErr);
|
||||
else
|
||||
return GVsHOrErr.takeError();
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
static std::string mangle(StringRef Name, const DataLayout &DL) {
|
||||
@ -462,7 +491,7 @@ private:
|
||||
return MangledName;
|
||||
}
|
||||
|
||||
JITTargetAddress
|
||||
Expected<JITTargetAddress>
|
||||
extractAndCompile(LogicalDylib &LD,
|
||||
typename LogicalDylib::SourceModuleHandle LMId,
|
||||
Function &F) {
|
||||
@ -475,34 +504,42 @@ private:
|
||||
// Grab the name of the function being called here.
|
||||
std::string CalledFnName = mangle(F.getName(), SrcM.getDataLayout());
|
||||
|
||||
auto Part = Partition(F);
|
||||
auto PartH = emitPartition(LD, LMId, Part);
|
||||
|
||||
JITTargetAddress CalledAddr = 0;
|
||||
for (auto *SubF : Part) {
|
||||
std::string FnName = mangle(SubF->getName(), SrcM.getDataLayout());
|
||||
auto FnBodySym = BaseLayer.findSymbolIn(PartH, FnName, false);
|
||||
assert(FnBodySym && "Couldn't find function body.");
|
||||
auto Part = Partition(F);
|
||||
if (auto PartHOrErr = emitPartition(LD, LMId, Part)) {
|
||||
auto &PartH = *PartHOrErr;
|
||||
for (auto *SubF : Part) {
|
||||
std::string FnName = mangle(SubF->getName(), SrcM.getDataLayout());
|
||||
if (auto FnBodySym = BaseLayer.findSymbolIn(PartH, FnName, false)) {
|
||||
if (auto FnBodyAddrOrErr = FnBodySym.getAddress()) {
|
||||
JITTargetAddress FnBodyAddr = *FnBodyAddrOrErr;
|
||||
|
||||
JITTargetAddress FnBodyAddr = FnBodySym.getAddress();
|
||||
// If this is the function we're calling record the address so we can
|
||||
// return it from this function.
|
||||
if (SubF == &F)
|
||||
CalledAddr = FnBodyAddr;
|
||||
|
||||
// If this is the function we're calling record the address so we can
|
||||
// return it from this function.
|
||||
if (SubF == &F)
|
||||
CalledAddr = FnBodyAddr;
|
||||
// Update the function body pointer for the stub.
|
||||
if (auto EC = LD.StubsMgr->updatePointer(FnName, FnBodyAddr))
|
||||
return 0;
|
||||
|
||||
// Update the function body pointer for the stub.
|
||||
if (auto EC = LD.StubsMgr->updatePointer(FnName, FnBodyAddr))
|
||||
return 0;
|
||||
}
|
||||
} else
|
||||
return FnBodyAddrOrErr.takeError();
|
||||
} else if (auto Err = FnBodySym.takeError())
|
||||
return std::move(Err);
|
||||
else
|
||||
llvm_unreachable("Function not emitted for partition");
|
||||
}
|
||||
|
||||
LD.BaseLayerHandles.push_back(PartH);
|
||||
LD.BaseLayerHandles.push_back(PartH);
|
||||
} else
|
||||
return PartHOrErr.takeError();
|
||||
|
||||
return CalledAddr;
|
||||
}
|
||||
|
||||
template <typename PartitionT>
|
||||
BaseLayerModuleHandleT
|
||||
Expected<BaseLayerModuleHandleT>
|
||||
emitPartition(LogicalDylib &LD,
|
||||
typename LogicalDylib::SourceModuleHandle LMId,
|
||||
const PartitionT &Part) {
|
||||
@ -566,16 +603,18 @@ private:
|
||||
|
||||
// Create memory manager and symbol resolver.
|
||||
auto Resolver = createLambdaResolver(
|
||||
[this, &LD](const std::string &Name) {
|
||||
[this, &LD](const std::string &Name) -> JITSymbol {
|
||||
if (auto Sym = LD.findSymbol(BaseLayer, Name, false))
|
||||
return Sym;
|
||||
else if (auto Err = Sym.takeError())
|
||||
return std::move(Err);
|
||||
return LD.ExternalSymbolResolver->findSymbolInLogicalDylib(Name);
|
||||
},
|
||||
[&LD](const std::string &Name) {
|
||||
return LD.ExternalSymbolResolver->findSymbol(Name);
|
||||
});
|
||||
|
||||
return LD.ModuleAdder(BaseLayer, std::move(M), std::move(Resolver));
|
||||
return BaseLayer.addModule(std::move(M), std::move(Resolver));
|
||||
}
|
||||
|
||||
BaseLayerT &BaseLayer;
|
||||
|
@ -17,6 +17,8 @@
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/ExecutionEngine/JITSymbol.h"
|
||||
#include "llvm/ExecutionEngine/RuntimeDyld.h"
|
||||
#include "llvm/ExecutionEngine/Orc/OrcError.h"
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
@ -99,19 +101,24 @@ public:
|
||||
|
||||
/// @brief Run the recorded constructors/destructors through the given JIT
|
||||
/// layer.
|
||||
bool runViaLayer(JITLayerT &JITLayer) const {
|
||||
Error runViaLayer(JITLayerT &JITLayer) const {
|
||||
using CtorDtorTy = void (*)();
|
||||
|
||||
bool Error = false;
|
||||
for (const auto &CtorDtorName : CtorDtorNames)
|
||||
if (auto CtorDtorSym = JITLayer.findSymbolIn(H, CtorDtorName, false)) {
|
||||
CtorDtorTy CtorDtor =
|
||||
reinterpret_cast<CtorDtorTy>(
|
||||
static_cast<uintptr_t>(CtorDtorSym.getAddress()));
|
||||
CtorDtor();
|
||||
} else
|
||||
Error = true;
|
||||
return !Error;
|
||||
if (auto AddrOrErr = CtorDtorSym.getAddress()) {
|
||||
CtorDtorTy CtorDtor =
|
||||
reinterpret_cast<CtorDtorTy>(static_cast<uintptr_t>(*AddrOrErr));
|
||||
CtorDtor();
|
||||
} else
|
||||
return AddrOrErr.takeError();
|
||||
} else {
|
||||
if (auto Err = CtorDtorSym.takeError())
|
||||
return Err;
|
||||
else
|
||||
return make_error<JITSymbolNotFound>(CtorDtorName);
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -17,9 +17,14 @@
|
||||
|
||||
#include "llvm/ExecutionEngine/JITSymbol.h"
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class Module;
|
||||
class JITSymbolResolver;
|
||||
|
||||
namespace orc {
|
||||
|
||||
/// @brief Global mapping layer.
|
||||
@ -32,25 +37,22 @@ namespace orc {
|
||||
template <typename BaseLayerT>
|
||||
class GlobalMappingLayer {
|
||||
public:
|
||||
/// @brief Handle to a set of added modules.
|
||||
using ModuleSetHandleT = typename BaseLayerT::ModuleSetHandleT;
|
||||
|
||||
/// @brief Handle to an added module.
|
||||
using ModuleHandleT = typename BaseLayerT::ModuleHandleT;
|
||||
|
||||
/// @brief Construct an GlobalMappingLayer with the given BaseLayer
|
||||
GlobalMappingLayer(BaseLayerT &BaseLayer) : BaseLayer(BaseLayer) {}
|
||||
|
||||
/// @brief Add the given module set to the JIT.
|
||||
/// @brief Add the given module to the JIT.
|
||||
/// @return A handle for the added modules.
|
||||
template <typename ModuleSetT, typename MemoryManagerPtrT,
|
||||
typename SymbolResolverPtrT>
|
||||
ModuleSetHandleT addModuleSet(ModuleSetT Ms,
|
||||
MemoryManagerPtrT MemMgr,
|
||||
SymbolResolverPtrT Resolver) {
|
||||
return BaseLayer.addModuleSet(std::move(Ms), std::move(MemMgr),
|
||||
std::move(Resolver));
|
||||
ModuleHandleT addModule(std::shared_ptr<Module> M,
|
||||
std::shared_ptr<JITSymbolResolver> Resolver) {
|
||||
return BaseLayer.addModule(std::move(M), std::move(Resolver));
|
||||
}
|
||||
|
||||
/// @brief Remove the module set associated with the handle H.
|
||||
void removeModuleSet(ModuleSetHandleT H) { BaseLayer.removeModuleSet(H); }
|
||||
void removeModule(ModuleHandleT H) { BaseLayer.removeModule(H); }
|
||||
|
||||
/// @brief Manually set the address to return for the given symbol.
|
||||
void setGlobalMapping(const std::string &Name, JITTargetAddress Addr) {
|
||||
@ -78,15 +80,15 @@ public:
|
||||
return BaseLayer.findSymbol(Name, ExportedSymbolsOnly);
|
||||
}
|
||||
|
||||
/// @brief Get the address of the given symbol in the context of the set of
|
||||
/// modules represented by the handle H. This call is forwarded to the
|
||||
/// @brief Get the address of the given symbol in the context of the of the
|
||||
/// module represented by the handle H. This call is forwarded to the
|
||||
/// base layer's implementation.
|
||||
/// @param H The handle for the module set to search in.
|
||||
/// @param H The handle for the module to search in.
|
||||
/// @param Name The name of the symbol to search for.
|
||||
/// @param ExportedSymbolsOnly If true, search only for exported symbols.
|
||||
/// @return A handle for the given named symbol, if it is found in the
|
||||
/// given module set.
|
||||
JITSymbol findSymbolIn(ModuleSetHandleT H, const std::string &Name,
|
||||
/// given module.
|
||||
JITSymbol findSymbolIn(ModuleHandleT H, const std::string &Name,
|
||||
bool ExportedSymbolsOnly) {
|
||||
return BaseLayer.findSymbolIn(H, Name, ExportedSymbolsOnly);
|
||||
}
|
||||
@ -94,7 +96,7 @@ public:
|
||||
/// @brief Immediately emit and finalize the module set represented by the
|
||||
/// given handle.
|
||||
/// @param H Handle for module set to emit/finalize.
|
||||
void emitAndFinalize(ModuleSetHandleT H) {
|
||||
void emitAndFinalize(ModuleHandleT H) {
|
||||
BaseLayer.emitAndFinalize(H);
|
||||
}
|
||||
|
||||
|
@ -50,18 +50,18 @@ public:
|
||||
/// along with the given memory manager and symbol resolver.
|
||||
///
|
||||
/// @return A handle for the added module.
|
||||
template <typename MemoryManagerPtrT, typename SymbolResolverPtrT>
|
||||
ModuleHandleT addModule(std::shared_ptr<Module> M,
|
||||
MemoryManagerPtrT MemMgr,
|
||||
SymbolResolverPtrT Resolver) {
|
||||
Expected<ModuleHandleT>
|
||||
addModule(std::shared_ptr<Module> M,
|
||||
std::shared_ptr<JITSymbolResolver> Resolver) {
|
||||
using CompileResult = decltype(Compile(*M));
|
||||
auto Obj = std::make_shared<CompileResult>(Compile(*M));
|
||||
return BaseLayer.addObject(std::move(Obj), std::move(MemMgr),
|
||||
std::move(Resolver));
|
||||
return BaseLayer.addObject(std::move(Obj), std::move(Resolver));
|
||||
}
|
||||
|
||||
/// @brief Remove the module associated with the handle H.
|
||||
void removeModule(ModuleHandleT H) { BaseLayer.removeObject(H); }
|
||||
Error removeModule(ModuleHandleT H) {
|
||||
return BaseLayer.removeObject(H);
|
||||
}
|
||||
|
||||
/// @brief Search for the given named symbol.
|
||||
/// @param Name The name of the symbol to search for.
|
||||
@ -87,8 +87,8 @@ public:
|
||||
/// @brief Immediately emit and finalize the module represented by the given
|
||||
/// handle.
|
||||
/// @param H Handle for module to emit/finalize.
|
||||
void emitAndFinalize(ModuleHandleT H) {
|
||||
BaseLayer.emitAndFinalize(H);
|
||||
Error emitAndFinalize(ModuleHandleT H) {
|
||||
return BaseLayer.emitAndFinalize(H);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -42,16 +42,14 @@ public:
|
||||
/// the layer below, along with the memory manager and symbol resolver.
|
||||
///
|
||||
/// @return A handle for the added modules.
|
||||
template <typename MemoryManagerPtrT, typename SymbolResolverPtrT>
|
||||
ModuleHandleT addModule(std::shared_ptr<Module> M,
|
||||
MemoryManagerPtrT MemMgr,
|
||||
SymbolResolverPtrT Resolver) {
|
||||
return BaseLayer.addModule(Transform(std::move(M)), std::move(MemMgr),
|
||||
std::move(Resolver));
|
||||
Expected<ModuleHandleT>
|
||||
addModule(std::shared_ptr<Module> M,
|
||||
std::shared_ptr<JITSymbolResolver> Resolver) {
|
||||
return BaseLayer.addModule(Transform(std::move(M)), std::move(Resolver));
|
||||
}
|
||||
|
||||
/// @brief Remove the module associated with the handle H.
|
||||
void removeModule(ModuleHandleT H) { BaseLayer.removeModule(H); }
|
||||
Error removeModule(ModuleHandleT H) { return BaseLayer.removeModule(H); }
|
||||
|
||||
/// @brief Search for the given named symbol.
|
||||
/// @param Name The name of the symbol to search for.
|
||||
@ -77,8 +75,8 @@ public:
|
||||
/// @brief Immediately emit and finalize the module represented by the given
|
||||
/// handle.
|
||||
/// @param H Handle for module to emit/finalize.
|
||||
void emitAndFinalize(ModuleHandleT H) {
|
||||
BaseLayer.emitAndFinalize(H);
|
||||
Error emitAndFinalize(ModuleHandleT H) {
|
||||
return BaseLayer.emitAndFinalize(H);
|
||||
}
|
||||
|
||||
/// @brief Access the transform functor directly.
|
||||
|
@ -45,7 +45,7 @@ private:
|
||||
|
||||
template <typename DylibLookupFtorT,
|
||||
typename ExternalLookupFtorT>
|
||||
std::unique_ptr<LambdaResolver<DylibLookupFtorT, ExternalLookupFtorT>>
|
||||
std::shared_ptr<LambdaResolver<DylibLookupFtorT, ExternalLookupFtorT>>
|
||||
createLambdaResolver(DylibLookupFtorT DylibLookupFtor,
|
||||
ExternalLookupFtorT ExternalLookupFtor) {
|
||||
using LR = LambdaResolver<DylibLookupFtorT, ExternalLookupFtorT>;
|
||||
|
@ -46,8 +46,9 @@ public:
|
||||
private:
|
||||
class EmissionDeferredModule {
|
||||
public:
|
||||
EmissionDeferredModule() = default;
|
||||
virtual ~EmissionDeferredModule() = default;
|
||||
EmissionDeferredModule(std::shared_ptr<Module> M,
|
||||
std::shared_ptr<JITSymbolResolver> Resolver)
|
||||
: M(std::move(M)), Resolver(std::move(Resolver)) {}
|
||||
|
||||
JITSymbol find(StringRef Name, bool ExportedSymbolsOnly, BaseLayerT &B) {
|
||||
switch (EmitState) {
|
||||
@ -59,16 +60,24 @@ private:
|
||||
std::string PName = Name;
|
||||
JITSymbolFlags Flags = JITSymbolFlags::fromGlobalValue(*GV);
|
||||
auto GetAddress =
|
||||
[this, ExportedSymbolsOnly, PName, &B]() -> JITTargetAddress {
|
||||
[this, ExportedSymbolsOnly, PName, &B]() -> Expected<JITTargetAddress> {
|
||||
if (this->EmitState == Emitting)
|
||||
return 0;
|
||||
else if (this->EmitState == NotEmitted) {
|
||||
this->EmitState = Emitting;
|
||||
Handle = this->emitToBaseLayer(B);
|
||||
if (auto HandleOrErr = this->emitToBaseLayer(B))
|
||||
Handle = std::move(*HandleOrErr);
|
||||
else
|
||||
return HandleOrErr.takeError();
|
||||
this->EmitState = Emitted;
|
||||
}
|
||||
auto Sym = B.findSymbolIn(Handle, PName, ExportedSymbolsOnly);
|
||||
return Sym.getAddress();
|
||||
if (auto Sym = B.findSymbolIn(Handle, PName, ExportedSymbolsOnly))
|
||||
return Sym.getAddress();
|
||||
else if (auto Err = Sym.takeError())
|
||||
return std::move(Err);
|
||||
else
|
||||
llvm_unreachable("Successful symbol lookup should return "
|
||||
"definition address here");
|
||||
};
|
||||
return JITSymbol(std::move(GetAddress), Flags);
|
||||
} else
|
||||
@ -101,33 +110,10 @@ private:
|
||||
BaseLayer.emitAndFinalize(Handle);
|
||||
}
|
||||
|
||||
template <typename MemoryManagerPtrT, typename SymbolResolverPtrT>
|
||||
static std::unique_ptr<EmissionDeferredModule>
|
||||
create(BaseLayerT &B, std::shared_ptr<Module> M, MemoryManagerPtrT MemMgr,
|
||||
SymbolResolverPtrT Resolver);
|
||||
|
||||
protected:
|
||||
virtual const GlobalValue* searchGVs(StringRef Name,
|
||||
bool ExportedSymbolsOnly) const = 0;
|
||||
virtual BaseLayerHandleT emitToBaseLayer(BaseLayerT &BaseLayer) = 0;
|
||||
|
||||
private:
|
||||
enum { NotEmitted, Emitting, Emitted } EmitState = NotEmitted;
|
||||
BaseLayerHandleT Handle;
|
||||
};
|
||||
|
||||
template <typename MemoryManagerPtrT, typename SymbolResolverPtrT>
|
||||
class EmissionDeferredModuleImpl : public EmissionDeferredModule {
|
||||
public:
|
||||
EmissionDeferredModuleImpl(std::shared_ptr<Module> M,
|
||||
MemoryManagerPtrT MemMgr,
|
||||
SymbolResolverPtrT Resolver)
|
||||
: M(std::move(M)), MemMgr(std::move(MemMgr)),
|
||||
Resolver(std::move(Resolver)) {}
|
||||
|
||||
protected:
|
||||
const GlobalValue* searchGVs(StringRef Name,
|
||||
bool ExportedSymbolsOnly) const override {
|
||||
bool ExportedSymbolsOnly) const {
|
||||
// FIXME: We could clean all this up if we had a way to reliably demangle
|
||||
// names: We could just demangle name and search, rather than
|
||||
// mangling everything else.
|
||||
@ -149,15 +135,13 @@ private:
|
||||
return buildMangledSymbols(Name, ExportedSymbolsOnly);
|
||||
}
|
||||
|
||||
BaseLayerHandleT emitToBaseLayer(BaseLayerT &BaseLayer) override {
|
||||
Expected<BaseLayerHandleT> emitToBaseLayer(BaseLayerT &BaseLayer) {
|
||||
// We don't need the mangled names set any more: Once we've emitted this
|
||||
// to the base layer we'll just look for symbols there.
|
||||
MangledSymbols.reset();
|
||||
return BaseLayer.addModule(std::move(M), std::move(MemMgr),
|
||||
std::move(Resolver));
|
||||
return BaseLayer.addModule(std::move(M), std::move(Resolver));
|
||||
}
|
||||
|
||||
private:
|
||||
// If the mangled name of the given GlobalValue matches the given search
|
||||
// name (and its visibility conforms to the ExportedSymbolsOnly flag) then
|
||||
// return the symbol. Otherwise, add the mangled name to the Names map and
|
||||
@ -207,9 +191,10 @@ private:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
enum { NotEmitted, Emitting, Emitted } EmitState = NotEmitted;
|
||||
BaseLayerHandleT Handle;
|
||||
std::shared_ptr<Module> M;
|
||||
MemoryManagerPtrT MemMgr;
|
||||
SymbolResolverPtrT Resolver;
|
||||
std::shared_ptr<JITSymbolResolver> Resolver;
|
||||
mutable std::unique_ptr<StringMap<const GlobalValue*>> MangledSymbols;
|
||||
};
|
||||
|
||||
@ -219,6 +204,7 @@ private:
|
||||
ModuleListT ModuleList;
|
||||
|
||||
public:
|
||||
|
||||
/// @brief Handle to a loaded module.
|
||||
using ModuleHandleT = typename ModuleListT::iterator;
|
||||
|
||||
@ -226,24 +212,23 @@ public:
|
||||
LazyEmittingLayer(BaseLayerT &BaseLayer) : BaseLayer(BaseLayer) {}
|
||||
|
||||
/// @brief Add the given module to the lazy emitting layer.
|
||||
template <typename MemoryManagerPtrT, typename SymbolResolverPtrT>
|
||||
ModuleHandleT addModule(std::shared_ptr<Module> M,
|
||||
MemoryManagerPtrT MemMgr,
|
||||
SymbolResolverPtrT Resolver) {
|
||||
Expected<ModuleHandleT>
|
||||
addModule(std::shared_ptr<Module> M,
|
||||
std::shared_ptr<JITSymbolResolver> Resolver) {
|
||||
return ModuleList.insert(
|
||||
ModuleList.end(),
|
||||
EmissionDeferredModule::create(BaseLayer, std::move(M),
|
||||
std::move(MemMgr),
|
||||
std::move(Resolver)));
|
||||
llvm::make_unique<EmissionDeferredModule>(std::move(M),
|
||||
std::move(Resolver)));
|
||||
}
|
||||
|
||||
/// @brief Remove the module represented by the given handle.
|
||||
///
|
||||
/// This method will free the memory associated with the given module, both
|
||||
/// in this layer, and the base layer.
|
||||
void removeModule(ModuleHandleT H) {
|
||||
Error removeModule(ModuleHandleT H) {
|
||||
(*H)->removeModuleFromBaseLayer(BaseLayer);
|
||||
ModuleList.erase(H);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
/// @brief Search for the given named symbol.
|
||||
@ -276,22 +261,11 @@ public:
|
||||
/// @brief Immediately emit and finalize the module represented by the given
|
||||
/// handle.
|
||||
/// @param H Handle for module to emit/finalize.
|
||||
void emitAndFinalize(ModuleHandleT H) {
|
||||
(*H)->emitAndFinalize(BaseLayer);
|
||||
Error emitAndFinalize(ModuleHandleT H) {
|
||||
return (*H)->emitAndFinalize(BaseLayer);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename BaseLayerT>
|
||||
template <typename MemoryManagerPtrT, typename SymbolResolverPtrT>
|
||||
std::unique_ptr<typename LazyEmittingLayer<BaseLayerT>::EmissionDeferredModule>
|
||||
LazyEmittingLayer<BaseLayerT>::EmissionDeferredModule::create(
|
||||
BaseLayerT &B, std::shared_ptr<Module> M, MemoryManagerPtrT MemMgr,
|
||||
SymbolResolverPtrT Resolver) {
|
||||
using EDS = EmissionDeferredModuleImpl<MemoryManagerPtrT, SymbolResolverPtrT>;
|
||||
return llvm::make_unique<EDS>(std::move(M), std::move(MemMgr),
|
||||
std::move(Resolver));
|
||||
}
|
||||
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#include "llvm/ExecutionEngine/JITSymbol.h"
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace llvm {
|
||||
@ -42,16 +43,14 @@ public:
|
||||
/// memory manager and symbol resolver.
|
||||
///
|
||||
/// @return A handle for the added objects.
|
||||
template <typename ObjPtrT, typename MemoryManagerPtrT,
|
||||
typename SymbolResolverPtrT>
|
||||
ObjHandleT addObject(ObjPtrT Obj, MemoryManagerPtrT MemMgr,
|
||||
SymbolResolverPtrT Resolver) {
|
||||
return BaseLayer.addObject(Transform(std::move(Obj)), std::move(MemMgr),
|
||||
std::move(Resolver));
|
||||
template <typename ObjectPtr>
|
||||
Expected<ObjHandleT> addObject(ObjectPtr Obj,
|
||||
std::shared_ptr<JITSymbolResolver> Resolver) {
|
||||
return BaseLayer.addObject(Transform(std::move(Obj)), std::move(Resolver));
|
||||
}
|
||||
|
||||
/// @brief Remove the object set associated with the handle H.
|
||||
void removeObject(ObjHandleT H) { BaseLayer.removeObject(H); }
|
||||
Error removeObject(ObjHandleT H) { return BaseLayer.removeObject(H); }
|
||||
|
||||
/// @brief Search for the given named symbol.
|
||||
/// @param Name The name of the symbol to search for.
|
||||
@ -77,7 +76,9 @@ public:
|
||||
/// @brief Immediately emit and finalize the object set represented by the
|
||||
/// given handle.
|
||||
/// @param H Handle for object set to emit/finalize.
|
||||
void emitAndFinalize(ObjHandleT H) { BaseLayer.emitAndFinalize(H); }
|
||||
Error emitAndFinalize(ObjHandleT H) {
|
||||
return BaseLayer.emitAndFinalize(H);
|
||||
}
|
||||
|
||||
/// @brief Map section addresses for the objects associated with the handle H.
|
||||
void mapSectionAddress(ObjHandleT H, const void *LocalAddress,
|
||||
|
@ -22,7 +22,8 @@ namespace orc {
|
||||
|
||||
enum class OrcErrorCode : int {
|
||||
// RPC Errors
|
||||
RemoteAllocatorDoesNotExist = 1,
|
||||
JITSymbolNotFound = 1,
|
||||
RemoteAllocatorDoesNotExist,
|
||||
RemoteAllocatorIdAlreadyInUse,
|
||||
RemoteMProtectAddrUnrecognized,
|
||||
RemoteIndirectStubsOwnerDoesNotExist,
|
||||
@ -37,6 +38,18 @@ enum class OrcErrorCode : int {
|
||||
|
||||
std::error_code orcError(OrcErrorCode ErrCode);
|
||||
|
||||
class JITSymbolNotFound : public ErrorInfo<JITSymbolNotFound> {
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
JITSymbolNotFound(std::string SymbolName);
|
||||
std::error_code convertToErrorCode() const override;
|
||||
void log(raw_ostream &OS) const override;
|
||||
const std::string &getSymbolName() const;
|
||||
private:
|
||||
std::string SymbolName;
|
||||
};
|
||||
|
||||
} // End namespace orc.
|
||||
} // End namespace llvm.
|
||||
|
||||
|
@ -228,13 +228,20 @@ private:
|
||||
|
||||
public:
|
||||
|
||||
/// @brief Functor for creating memory managers.
|
||||
using MemoryManagerGetter =
|
||||
std::function<std::shared_ptr<RuntimeDyld::MemoryManager>()>;
|
||||
|
||||
/// @brief Construct an ObjectLinkingLayer with the given NotifyLoaded,
|
||||
/// and NotifyFinalized functors.
|
||||
RTDyldObjectLinkingLayer(
|
||||
MemoryManagerGetter GetMemMgr,
|
||||
NotifyLoadedFtor NotifyLoaded = NotifyLoadedFtor(),
|
||||
NotifyFinalizedFtor NotifyFinalized = NotifyFinalizedFtor())
|
||||
: NotifyLoaded(std::move(NotifyLoaded)),
|
||||
NotifyFinalized(std::move(NotifyFinalized)) {}
|
||||
: GetMemMgr(GetMemMgr),
|
||||
NotifyLoaded(std::move(NotifyLoaded)),
|
||||
NotifyFinalized(std::move(NotifyFinalized)),
|
||||
ProcessAllSections(false) {}
|
||||
|
||||
/// @brief Set the 'ProcessAllSections' flag.
|
||||
///
|
||||
@ -251,12 +258,8 @@ public:
|
||||
///
|
||||
/// @return A handle that can be used to refer to the loaded objects (for
|
||||
/// symbol searching, finalization, freeing memory, etc.).
|
||||
template <typename MemoryManagerPtrT,
|
||||
typename SymbolResolverPtrT>
|
||||
ObjHandleT addObject(ObjectPtr Obj,
|
||||
MemoryManagerPtrT MemMgr,
|
||||
SymbolResolverPtrT Resolver) {
|
||||
|
||||
Expected<ObjHandleT> addObject(ObjectPtr Obj,
|
||||
std::shared_ptr<JITSymbolResolver> Resolver) {
|
||||
auto Finalizer = [&](ObjHandleT H, RuntimeDyld &RTDyld,
|
||||
const ObjectPtr &ObjToLoad,
|
||||
std::function<void()> LOSHandleLoad) {
|
||||
@ -275,8 +278,9 @@ public:
|
||||
};
|
||||
|
||||
auto LO =
|
||||
createLinkedObject(std::move(Obj), std::move(MemMgr), std::move(Resolver),
|
||||
std::move(Finalizer), ProcessAllSections);
|
||||
createLinkedObject(std::move(Obj), GetMemMgr(),
|
||||
std::move(Resolver), std::move(Finalizer),
|
||||
ProcessAllSections);
|
||||
// LOS is an owning-ptr. Keep a non-owning one so that we can set the handle
|
||||
// below.
|
||||
auto *LOPtr = LO.get();
|
||||
@ -295,9 +299,10 @@ public:
|
||||
/// indirectly) will result in undefined behavior. If dependence tracking is
|
||||
/// required to detect or resolve such issues it should be added at a higher
|
||||
/// layer.
|
||||
void removeObject(ObjHandleT H) {
|
||||
Error removeObject(ObjHandleT H) {
|
||||
// How do we invalidate the symbols in H?
|
||||
LinkedObjList.erase(H);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
/// @brief Search for the given named symbol.
|
||||
@ -334,13 +339,15 @@ public:
|
||||
/// @brief Immediately emit and finalize the object set represented by the
|
||||
/// given handle.
|
||||
/// @param H Handle for object set to emit/finalize.
|
||||
void emitAndFinalize(ObjHandleT H) {
|
||||
Error emitAndFinalize(ObjHandleT H) {
|
||||
(*H)->finalize();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
LinkedObjectListT LinkedObjList;
|
||||
MemoryManagerGetter GetMemMgr;
|
||||
NotifyLoadedFtor NotifyLoaded;
|
||||
NotifyFinalizedFtor NotifyFinalized;
|
||||
bool ProcessAllSections = false;
|
||||
|
@ -88,21 +88,6 @@ public:
|
||||
ObjSectionToIDMap ObjSecToIDMap;
|
||||
};
|
||||
|
||||
template <typename Derived> struct LoadedObjectInfoHelper : LoadedObjectInfo {
|
||||
protected:
|
||||
LoadedObjectInfoHelper(const LoadedObjectInfoHelper &) = default;
|
||||
LoadedObjectInfoHelper() = default;
|
||||
|
||||
public:
|
||||
LoadedObjectInfoHelper(RuntimeDyldImpl &RTDyld,
|
||||
LoadedObjectInfo::ObjSectionToIDMap ObjSecToIDMap)
|
||||
: LoadedObjectInfo(RTDyld, std::move(ObjSecToIDMap)) {}
|
||||
|
||||
std::unique_ptr<llvm::LoadedObjectInfo> clone() const override {
|
||||
return llvm::make_unique<Derived>(static_cast<const Derived &>(*this));
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Memory Management.
|
||||
class MemoryManager {
|
||||
friend class RuntimeDyld;
|
||||
|
@ -680,11 +680,6 @@ class ConstantDataArray final : public ConstantDataSequential {
|
||||
explicit ConstantDataArray(Type *ty, const char *Data)
|
||||
: ConstantDataSequential(ty, ConstantDataArrayVal, Data) {}
|
||||
|
||||
/// Allocate space for exactly zero operands.
|
||||
void *operator new(size_t s) {
|
||||
return User::operator new(s, 0);
|
||||
}
|
||||
|
||||
public:
|
||||
ConstantDataArray(const ConstantDataArray &) = delete;
|
||||
|
||||
@ -739,11 +734,6 @@ class ConstantDataVector final : public ConstantDataSequential {
|
||||
explicit ConstantDataVector(Type *ty, const char *Data)
|
||||
: ConstantDataSequential(ty, ConstantDataVectorVal, Data) {}
|
||||
|
||||
// allocate space for exactly zero operands.
|
||||
void *operator new(size_t s) {
|
||||
return User::operator new(s, 0);
|
||||
}
|
||||
|
||||
public:
|
||||
ConstantDataVector(const ConstantDataVector &) = delete;
|
||||
|
||||
|
@ -1062,7 +1062,7 @@ public:
|
||||
|
||||
Value *CreateAnd(Value *LHS, Value *RHS, const Twine &Name = "") {
|
||||
if (Constant *RC = dyn_cast<Constant>(RHS)) {
|
||||
if (isa<ConstantInt>(RC) && cast<ConstantInt>(RC)->isAllOnesValue())
|
||||
if (isa<ConstantInt>(RC) && cast<ConstantInt>(RC)->isMinusOne())
|
||||
return LHS; // LHS & -1 -> LHS
|
||||
if (Constant *LC = dyn_cast<Constant>(LHS))
|
||||
return Insert(Folder.CreateAnd(LC, RC), Name);
|
||||
@ -1203,22 +1203,22 @@ public:
|
||||
return SI;
|
||||
}
|
||||
FenceInst *CreateFence(AtomicOrdering Ordering,
|
||||
SynchronizationScope SynchScope = CrossThread,
|
||||
SyncScope::ID SSID = SyncScope::System,
|
||||
const Twine &Name = "") {
|
||||
return Insert(new FenceInst(Context, Ordering, SynchScope), Name);
|
||||
return Insert(new FenceInst(Context, Ordering, SSID), Name);
|
||||
}
|
||||
AtomicCmpXchgInst *
|
||||
CreateAtomicCmpXchg(Value *Ptr, Value *Cmp, Value *New,
|
||||
AtomicOrdering SuccessOrdering,
|
||||
AtomicOrdering FailureOrdering,
|
||||
SynchronizationScope SynchScope = CrossThread) {
|
||||
SyncScope::ID SSID = SyncScope::System) {
|
||||
return Insert(new AtomicCmpXchgInst(Ptr, Cmp, New, SuccessOrdering,
|
||||
FailureOrdering, SynchScope));
|
||||
FailureOrdering, SSID));
|
||||
}
|
||||
AtomicRMWInst *CreateAtomicRMW(AtomicRMWInst::BinOp Op, Value *Ptr, Value *Val,
|
||||
AtomicOrdering Ordering,
|
||||
SynchronizationScope SynchScope = CrossThread) {
|
||||
return Insert(new AtomicRMWInst(Op, Ptr, Val, Ordering, SynchScope));
|
||||
SyncScope::ID SSID = SyncScope::System) {
|
||||
return Insert(new AtomicRMWInst(Op, Ptr, Val, Ordering, SSID));
|
||||
}
|
||||
Value *CreateGEP(Value *Ptr, ArrayRef<Value *> IdxList,
|
||||
const Twine &Name = "") {
|
||||
@ -1517,11 +1517,9 @@ public:
|
||||
const Twine &Name = "") {
|
||||
if (V->getType() == DestTy)
|
||||
return V;
|
||||
if (V->getType()->getScalarType()->isPointerTy() &&
|
||||
DestTy->getScalarType()->isIntegerTy())
|
||||
if (V->getType()->isPtrOrPtrVectorTy() && DestTy->isIntOrIntVectorTy())
|
||||
return CreatePtrToInt(V, DestTy, Name);
|
||||
if (V->getType()->getScalarType()->isIntegerTy() &&
|
||||
DestTy->getScalarType()->isPointerTy())
|
||||
if (V->getType()->isIntOrIntVectorTy() && DestTy->isPtrOrPtrVectorTy())
|
||||
return CreateIntToPtr(V, DestTy, Name);
|
||||
|
||||
return CreateBitCast(V, DestTy, Name);
|
||||
|
@ -52,11 +52,6 @@ class ConstantInt;
|
||||
class DataLayout;
|
||||
class LLVMContext;
|
||||
|
||||
enum SynchronizationScope {
|
||||
SingleThread = 0,
|
||||
CrossThread = 1
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// AllocaInst Class
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -195,17 +190,16 @@ public:
|
||||
LoadInst(Value *Ptr, const Twine &NameStr, bool isVolatile,
|
||||
unsigned Align, BasicBlock *InsertAtEnd);
|
||||
LoadInst(Value *Ptr, const Twine &NameStr, bool isVolatile, unsigned Align,
|
||||
AtomicOrdering Order, SynchronizationScope SynchScope = CrossThread,
|
||||
AtomicOrdering Order, SyncScope::ID SSID = SyncScope::System,
|
||||
Instruction *InsertBefore = nullptr)
|
||||
: LoadInst(cast<PointerType>(Ptr->getType())->getElementType(), Ptr,
|
||||
NameStr, isVolatile, Align, Order, SynchScope, InsertBefore) {}
|
||||
NameStr, isVolatile, Align, Order, SSID, InsertBefore) {}
|
||||
LoadInst(Type *Ty, Value *Ptr, const Twine &NameStr, bool isVolatile,
|
||||
unsigned Align, AtomicOrdering Order,
|
||||
SynchronizationScope SynchScope = CrossThread,
|
||||
SyncScope::ID SSID = SyncScope::System,
|
||||
Instruction *InsertBefore = nullptr);
|
||||
LoadInst(Value *Ptr, const Twine &NameStr, bool isVolatile,
|
||||
unsigned Align, AtomicOrdering Order,
|
||||
SynchronizationScope SynchScope,
|
||||
unsigned Align, AtomicOrdering Order, SyncScope::ID SSID,
|
||||
BasicBlock *InsertAtEnd);
|
||||
LoadInst(Value *Ptr, const char *NameStr, Instruction *InsertBefore);
|
||||
LoadInst(Value *Ptr, const char *NameStr, BasicBlock *InsertAtEnd);
|
||||
@ -235,34 +229,34 @@ public:
|
||||
|
||||
void setAlignment(unsigned Align);
|
||||
|
||||
/// Returns the ordering effect of this fence.
|
||||
/// Returns the ordering constraint of this load instruction.
|
||||
AtomicOrdering getOrdering() const {
|
||||
return AtomicOrdering((getSubclassDataFromInstruction() >> 7) & 7);
|
||||
}
|
||||
|
||||
/// Set the ordering constraint on this load. May not be Release or
|
||||
/// AcquireRelease.
|
||||
/// Sets the ordering constraint of this load instruction. May not be Release
|
||||
/// or AcquireRelease.
|
||||
void setOrdering(AtomicOrdering Ordering) {
|
||||
setInstructionSubclassData((getSubclassDataFromInstruction() & ~(7 << 7)) |
|
||||
((unsigned)Ordering << 7));
|
||||
}
|
||||
|
||||
SynchronizationScope getSynchScope() const {
|
||||
return SynchronizationScope((getSubclassDataFromInstruction() >> 6) & 1);
|
||||
/// Returns the synchronization scope ID of this load instruction.
|
||||
SyncScope::ID getSyncScopeID() const {
|
||||
return SSID;
|
||||
}
|
||||
|
||||
/// Specify whether this load is ordered with respect to all
|
||||
/// concurrently executing threads, or only with respect to signal handlers
|
||||
/// executing in the same thread.
|
||||
void setSynchScope(SynchronizationScope xthread) {
|
||||
setInstructionSubclassData((getSubclassDataFromInstruction() & ~(1 << 6)) |
|
||||
(xthread << 6));
|
||||
/// Sets the synchronization scope ID of this load instruction.
|
||||
void setSyncScopeID(SyncScope::ID SSID) {
|
||||
this->SSID = SSID;
|
||||
}
|
||||
|
||||
/// Sets the ordering constraint and the synchronization scope ID of this load
|
||||
/// instruction.
|
||||
void setAtomic(AtomicOrdering Ordering,
|
||||
SynchronizationScope SynchScope = CrossThread) {
|
||||
SyncScope::ID SSID = SyncScope::System) {
|
||||
setOrdering(Ordering);
|
||||
setSynchScope(SynchScope);
|
||||
setSyncScopeID(SSID);
|
||||
}
|
||||
|
||||
bool isSimple() const { return !isAtomic() && !isVolatile(); }
|
||||
@ -297,6 +291,11 @@ private:
|
||||
void setInstructionSubclassData(unsigned short D) {
|
||||
Instruction::setInstructionSubclassData(D);
|
||||
}
|
||||
|
||||
/// The synchronization scope ID of this load instruction. Not quite enough
|
||||
/// room in SubClassData for everything, so synchronization scope ID gets its
|
||||
/// own field.
|
||||
SyncScope::ID SSID;
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -325,11 +324,10 @@ public:
|
||||
unsigned Align, BasicBlock *InsertAtEnd);
|
||||
StoreInst(Value *Val, Value *Ptr, bool isVolatile,
|
||||
unsigned Align, AtomicOrdering Order,
|
||||
SynchronizationScope SynchScope = CrossThread,
|
||||
SyncScope::ID SSID = SyncScope::System,
|
||||
Instruction *InsertBefore = nullptr);
|
||||
StoreInst(Value *Val, Value *Ptr, bool isVolatile,
|
||||
unsigned Align, AtomicOrdering Order,
|
||||
SynchronizationScope SynchScope,
|
||||
unsigned Align, AtomicOrdering Order, SyncScope::ID SSID,
|
||||
BasicBlock *InsertAtEnd);
|
||||
|
||||
// allocate space for exactly two operands
|
||||
@ -356,34 +354,34 @@ public:
|
||||
|
||||
void setAlignment(unsigned Align);
|
||||
|
||||
/// Returns the ordering effect of this store.
|
||||
/// Returns the ordering constraint of this store instruction.
|
||||
AtomicOrdering getOrdering() const {
|
||||
return AtomicOrdering((getSubclassDataFromInstruction() >> 7) & 7);
|
||||
}
|
||||
|
||||
/// Set the ordering constraint on this store. May not be Acquire or
|
||||
/// AcquireRelease.
|
||||
/// Sets the ordering constraint of this store instruction. May not be
|
||||
/// Acquire or AcquireRelease.
|
||||
void setOrdering(AtomicOrdering Ordering) {
|
||||
setInstructionSubclassData((getSubclassDataFromInstruction() & ~(7 << 7)) |
|
||||
((unsigned)Ordering << 7));
|
||||
}
|
||||
|
||||
SynchronizationScope getSynchScope() const {
|
||||
return SynchronizationScope((getSubclassDataFromInstruction() >> 6) & 1);
|
||||
/// Returns the synchronization scope ID of this store instruction.
|
||||
SyncScope::ID getSyncScopeID() const {
|
||||
return SSID;
|
||||
}
|
||||
|
||||
/// Specify whether this store instruction is ordered with respect to all
|
||||
/// concurrently executing threads, or only with respect to signal handlers
|
||||
/// executing in the same thread.
|
||||
void setSynchScope(SynchronizationScope xthread) {
|
||||
setInstructionSubclassData((getSubclassDataFromInstruction() & ~(1 << 6)) |
|
||||
(xthread << 6));
|
||||
/// Sets the synchronization scope ID of this store instruction.
|
||||
void setSyncScopeID(SyncScope::ID SSID) {
|
||||
this->SSID = SSID;
|
||||
}
|
||||
|
||||
/// Sets the ordering constraint and the synchronization scope ID of this
|
||||
/// store instruction.
|
||||
void setAtomic(AtomicOrdering Ordering,
|
||||
SynchronizationScope SynchScope = CrossThread) {
|
||||
SyncScope::ID SSID = SyncScope::System) {
|
||||
setOrdering(Ordering);
|
||||
setSynchScope(SynchScope);
|
||||
setSyncScopeID(SSID);
|
||||
}
|
||||
|
||||
bool isSimple() const { return !isAtomic() && !isVolatile(); }
|
||||
@ -421,6 +419,11 @@ private:
|
||||
void setInstructionSubclassData(unsigned short D) {
|
||||
Instruction::setInstructionSubclassData(D);
|
||||
}
|
||||
|
||||
/// The synchronization scope ID of this store instruction. Not quite enough
|
||||
/// room in SubClassData for everything, so synchronization scope ID gets its
|
||||
/// own field.
|
||||
SyncScope::ID SSID;
|
||||
};
|
||||
|
||||
template <>
|
||||
@ -435,7 +438,7 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(StoreInst, Value)
|
||||
|
||||
/// An instruction for ordering other memory operations.
|
||||
class FenceInst : public Instruction {
|
||||
void Init(AtomicOrdering Ordering, SynchronizationScope SynchScope);
|
||||
void Init(AtomicOrdering Ordering, SyncScope::ID SSID);
|
||||
|
||||
protected:
|
||||
// Note: Instruction needs to be a friend here to call cloneImpl.
|
||||
@ -447,10 +450,9 @@ public:
|
||||
// Ordering may only be Acquire, Release, AcquireRelease, or
|
||||
// SequentiallyConsistent.
|
||||
FenceInst(LLVMContext &C, AtomicOrdering Ordering,
|
||||
SynchronizationScope SynchScope = CrossThread,
|
||||
SyncScope::ID SSID = SyncScope::System,
|
||||
Instruction *InsertBefore = nullptr);
|
||||
FenceInst(LLVMContext &C, AtomicOrdering Ordering,
|
||||
SynchronizationScope SynchScope,
|
||||
FenceInst(LLVMContext &C, AtomicOrdering Ordering, SyncScope::ID SSID,
|
||||
BasicBlock *InsertAtEnd);
|
||||
|
||||
// allocate space for exactly zero operands
|
||||
@ -458,28 +460,26 @@ public:
|
||||
return User::operator new(s, 0);
|
||||
}
|
||||
|
||||
/// Returns the ordering effect of this fence.
|
||||
/// Returns the ordering constraint of this fence instruction.
|
||||
AtomicOrdering getOrdering() const {
|
||||
return AtomicOrdering(getSubclassDataFromInstruction() >> 1);
|
||||
}
|
||||
|
||||
/// Set the ordering constraint on this fence. May only be Acquire, Release,
|
||||
/// AcquireRelease, or SequentiallyConsistent.
|
||||
/// Sets the ordering constraint of this fence instruction. May only be
|
||||
/// Acquire, Release, AcquireRelease, or SequentiallyConsistent.
|
||||
void setOrdering(AtomicOrdering Ordering) {
|
||||
setInstructionSubclassData((getSubclassDataFromInstruction() & 1) |
|
||||
((unsigned)Ordering << 1));
|
||||
}
|
||||
|
||||
SynchronizationScope getSynchScope() const {
|
||||
return SynchronizationScope(getSubclassDataFromInstruction() & 1);
|
||||
/// Returns the synchronization scope ID of this fence instruction.
|
||||
SyncScope::ID getSyncScopeID() const {
|
||||
return SSID;
|
||||
}
|
||||
|
||||
/// Specify whether this fence orders other operations with respect to all
|
||||
/// concurrently executing threads, or only with respect to signal handlers
|
||||
/// executing in the same thread.
|
||||
void setSynchScope(SynchronizationScope xthread) {
|
||||
setInstructionSubclassData((getSubclassDataFromInstruction() & ~1) |
|
||||
xthread);
|
||||
/// Sets the synchronization scope ID of this fence instruction.
|
||||
void setSyncScopeID(SyncScope::ID SSID) {
|
||||
this->SSID = SSID;
|
||||
}
|
||||
|
||||
// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||
@ -496,6 +496,11 @@ private:
|
||||
void setInstructionSubclassData(unsigned short D) {
|
||||
Instruction::setInstructionSubclassData(D);
|
||||
}
|
||||
|
||||
/// The synchronization scope ID of this fence instruction. Not quite enough
|
||||
/// room in SubClassData for everything, so synchronization scope ID gets its
|
||||
/// own field.
|
||||
SyncScope::ID SSID;
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -509,7 +514,7 @@ private:
|
||||
class AtomicCmpXchgInst : public Instruction {
|
||||
void Init(Value *Ptr, Value *Cmp, Value *NewVal,
|
||||
AtomicOrdering SuccessOrdering, AtomicOrdering FailureOrdering,
|
||||
SynchronizationScope SynchScope);
|
||||
SyncScope::ID SSID);
|
||||
|
||||
protected:
|
||||
// Note: Instruction needs to be a friend here to call cloneImpl.
|
||||
@ -521,13 +526,11 @@ public:
|
||||
AtomicCmpXchgInst(Value *Ptr, Value *Cmp, Value *NewVal,
|
||||
AtomicOrdering SuccessOrdering,
|
||||
AtomicOrdering FailureOrdering,
|
||||
SynchronizationScope SynchScope,
|
||||
Instruction *InsertBefore = nullptr);
|
||||
SyncScope::ID SSID, Instruction *InsertBefore = nullptr);
|
||||
AtomicCmpXchgInst(Value *Ptr, Value *Cmp, Value *NewVal,
|
||||
AtomicOrdering SuccessOrdering,
|
||||
AtomicOrdering FailureOrdering,
|
||||
SynchronizationScope SynchScope,
|
||||
BasicBlock *InsertAtEnd);
|
||||
SyncScope::ID SSID, BasicBlock *InsertAtEnd);
|
||||
|
||||
// allocate space for exactly three operands
|
||||
void *operator new(size_t s) {
|
||||
@ -561,7 +564,12 @@ public:
|
||||
/// Transparently provide more efficient getOperand methods.
|
||||
DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
|
||||
|
||||
/// Set the ordering constraint on this cmpxchg.
|
||||
/// Returns the success ordering constraint of this cmpxchg instruction.
|
||||
AtomicOrdering getSuccessOrdering() const {
|
||||
return AtomicOrdering((getSubclassDataFromInstruction() >> 2) & 7);
|
||||
}
|
||||
|
||||
/// Sets the success ordering constraint of this cmpxchg instruction.
|
||||
void setSuccessOrdering(AtomicOrdering Ordering) {
|
||||
assert(Ordering != AtomicOrdering::NotAtomic &&
|
||||
"CmpXchg instructions can only be atomic.");
|
||||
@ -569,6 +577,12 @@ public:
|
||||
((unsigned)Ordering << 2));
|
||||
}
|
||||
|
||||
/// Returns the failure ordering constraint of this cmpxchg instruction.
|
||||
AtomicOrdering getFailureOrdering() const {
|
||||
return AtomicOrdering((getSubclassDataFromInstruction() >> 5) & 7);
|
||||
}
|
||||
|
||||
/// Sets the failure ordering constraint of this cmpxchg instruction.
|
||||
void setFailureOrdering(AtomicOrdering Ordering) {
|
||||
assert(Ordering != AtomicOrdering::NotAtomic &&
|
||||
"CmpXchg instructions can only be atomic.");
|
||||
@ -576,28 +590,14 @@ public:
|
||||
((unsigned)Ordering << 5));
|
||||
}
|
||||
|
||||
/// Specify whether this cmpxchg is atomic and orders other operations with
|
||||
/// respect to all concurrently executing threads, or only with respect to
|
||||
/// signal handlers executing in the same thread.
|
||||
void setSynchScope(SynchronizationScope SynchScope) {
|
||||
setInstructionSubclassData((getSubclassDataFromInstruction() & ~2) |
|
||||
(SynchScope << 1));
|
||||
/// Returns the synchronization scope ID of this cmpxchg instruction.
|
||||
SyncScope::ID getSyncScopeID() const {
|
||||
return SSID;
|
||||
}
|
||||
|
||||
/// Returns the ordering constraint on this cmpxchg.
|
||||
AtomicOrdering getSuccessOrdering() const {
|
||||
return AtomicOrdering((getSubclassDataFromInstruction() >> 2) & 7);
|
||||
}
|
||||
|
||||
/// Returns the ordering constraint on this cmpxchg.
|
||||
AtomicOrdering getFailureOrdering() const {
|
||||
return AtomicOrdering((getSubclassDataFromInstruction() >> 5) & 7);
|
||||
}
|
||||
|
||||
/// Returns whether this cmpxchg is atomic between threads or only within a
|
||||
/// single thread.
|
||||
SynchronizationScope getSynchScope() const {
|
||||
return SynchronizationScope((getSubclassDataFromInstruction() & 2) >> 1);
|
||||
/// Sets the synchronization scope ID of this cmpxchg instruction.
|
||||
void setSyncScopeID(SyncScope::ID SSID) {
|
||||
this->SSID = SSID;
|
||||
}
|
||||
|
||||
Value *getPointerOperand() { return getOperand(0); }
|
||||
@ -652,6 +652,11 @@ private:
|
||||
void setInstructionSubclassData(unsigned short D) {
|
||||
Instruction::setInstructionSubclassData(D);
|
||||
}
|
||||
|
||||
/// The synchronization scope ID of this cmpxchg instruction. Not quite
|
||||
/// enough room in SubClassData for everything, so synchronization scope ID
|
||||
/// gets its own field.
|
||||
SyncScope::ID SSID;
|
||||
};
|
||||
|
||||
template <>
|
||||
@ -711,10 +716,10 @@ public:
|
||||
};
|
||||
|
||||
AtomicRMWInst(BinOp Operation, Value *Ptr, Value *Val,
|
||||
AtomicOrdering Ordering, SynchronizationScope SynchScope,
|
||||
AtomicOrdering Ordering, SyncScope::ID SSID,
|
||||
Instruction *InsertBefore = nullptr);
|
||||
AtomicRMWInst(BinOp Operation, Value *Ptr, Value *Val,
|
||||
AtomicOrdering Ordering, SynchronizationScope SynchScope,
|
||||
AtomicOrdering Ordering, SyncScope::ID SSID,
|
||||
BasicBlock *InsertAtEnd);
|
||||
|
||||
// allocate space for exactly two operands
|
||||
@ -748,7 +753,12 @@ public:
|
||||
/// Transparently provide more efficient getOperand methods.
|
||||
DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
|
||||
|
||||
/// Set the ordering constraint on this RMW.
|
||||
/// Returns the ordering constraint of this rmw instruction.
|
||||
AtomicOrdering getOrdering() const {
|
||||
return AtomicOrdering((getSubclassDataFromInstruction() >> 2) & 7);
|
||||
}
|
||||
|
||||
/// Sets the ordering constraint of this rmw instruction.
|
||||
void setOrdering(AtomicOrdering Ordering) {
|
||||
assert(Ordering != AtomicOrdering::NotAtomic &&
|
||||
"atomicrmw instructions can only be atomic.");
|
||||
@ -756,23 +766,14 @@ public:
|
||||
((unsigned)Ordering << 2));
|
||||
}
|
||||
|
||||
/// Specify whether this RMW orders other operations with respect to all
|
||||
/// concurrently executing threads, or only with respect to signal handlers
|
||||
/// executing in the same thread.
|
||||
void setSynchScope(SynchronizationScope SynchScope) {
|
||||
setInstructionSubclassData((getSubclassDataFromInstruction() & ~2) |
|
||||
(SynchScope << 1));
|
||||
/// Returns the synchronization scope ID of this rmw instruction.
|
||||
SyncScope::ID getSyncScopeID() const {
|
||||
return SSID;
|
||||
}
|
||||
|
||||
/// Returns the ordering constraint on this RMW.
|
||||
AtomicOrdering getOrdering() const {
|
||||
return AtomicOrdering((getSubclassDataFromInstruction() >> 2) & 7);
|
||||
}
|
||||
|
||||
/// Returns whether this RMW is atomic between threads or only within a
|
||||
/// single thread.
|
||||
SynchronizationScope getSynchScope() const {
|
||||
return SynchronizationScope((getSubclassDataFromInstruction() & 2) >> 1);
|
||||
/// Sets the synchronization scope ID of this rmw instruction.
|
||||
void setSyncScopeID(SyncScope::ID SSID) {
|
||||
this->SSID = SSID;
|
||||
}
|
||||
|
||||
Value *getPointerOperand() { return getOperand(0); }
|
||||
@ -797,13 +798,18 @@ public:
|
||||
|
||||
private:
|
||||
void Init(BinOp Operation, Value *Ptr, Value *Val,
|
||||
AtomicOrdering Ordering, SynchronizationScope SynchScope);
|
||||
AtomicOrdering Ordering, SyncScope::ID SSID);
|
||||
|
||||
// Shadow Instruction::setInstructionSubclassData with a private forwarding
|
||||
// method so that subclasses cannot accidentally use it.
|
||||
void setInstructionSubclassData(unsigned short D) {
|
||||
Instruction::setInstructionSubclassData(D);
|
||||
}
|
||||
|
||||
/// The synchronization scope ID of this rmw instruction. Not quite enough
|
||||
/// room in SubClassData for everything, so synchronization scope ID gets its
|
||||
/// own field.
|
||||
SyncScope::ID SSID;
|
||||
};
|
||||
|
||||
template <>
|
||||
@ -1101,8 +1107,7 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(GetElementPtrInst, Value)
|
||||
/// Represent an integer comparison operator.
|
||||
class ICmpInst: public CmpInst {
|
||||
void AssertOK() {
|
||||
assert(getPredicate() >= CmpInst::FIRST_ICMP_PREDICATE &&
|
||||
getPredicate() <= CmpInst::LAST_ICMP_PREDICATE &&
|
||||
assert(isIntPredicate() &&
|
||||
"Invalid ICmp predicate value");
|
||||
assert(getOperand(0)->getType() == getOperand(1)->getType() &&
|
||||
"Both operands to ICmp instruction are not of the same type!");
|
||||
@ -1244,8 +1249,7 @@ public:
|
||||
/// Represents a floating point comparison operator.
|
||||
class FCmpInst: public CmpInst {
|
||||
void AssertOK() {
|
||||
assert(getPredicate() <= FCmpInst::LAST_FCMP_PREDICATE &&
|
||||
"Invalid FCmp predicate value");
|
||||
assert(isFPPredicate() && "Invalid FCmp predicate value");
|
||||
assert(getOperand(0)->getType() == getOperand(1)->getType() &&
|
||||
"Both operands to FCmp instruction are not of the same type!");
|
||||
// Check that the operands are the right type
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user