Vendor import of llvm trunk r257626:

https://llvm.org/svn/llvm-project/llvm/trunk@257626
This commit is contained in:
dim 2016-01-13 19:58:01 +00:00
parent ff2ba393a5
commit e39b9e36e5
602 changed files with 26339 additions and 6797 deletions

View File

@ -308,6 +308,8 @@ endfunction(set_windows_version_resource_properties)
# SHARED;STATIC
# STATIC by default w/o BUILD_SHARED_LIBS.
# SHARED by default w/ BUILD_SHARED_LIBS.
# OBJECT
# Also create an OBJECT library target. Default if STATIC && SHARED.
# MODULE
# Target ${name} might not be created on unsupported platforms.
# Check with "if(TARGET ${name})".
@ -329,7 +331,7 @@ endfunction(set_windows_version_resource_properties)
# )
function(llvm_add_library name)
cmake_parse_arguments(ARG
"MODULE;SHARED;STATIC;DISABLE_LLVM_LINK_LLVM_DYLIB;SONAME"
"MODULE;SHARED;STATIC;OBJECT;DISABLE_LLVM_LINK_LLVM_DYLIB;SONAME"
"OUTPUT_NAME"
"ADDITIONAL_HEADERS;DEPENDS;LINK_COMPONENTS;LINK_LIBS;OBJLIBS"
${ARGN})
@ -362,7 +364,7 @@ function(llvm_add_library name)
endif()
# Generate objlib
if(ARG_SHARED AND ARG_STATIC)
if((ARG_SHARED AND ARG_STATIC) OR ARG_OBJECT)
# Generate an obj library for both targets.
set(obj_name "obj.${name}")
add_library(${obj_name} OBJECT EXCLUDE_FROM_ALL

View File

@ -363,6 +363,36 @@ if( MSVC )
append("/Zc:inline" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
if (NOT LLVM_ENABLE_TIMESTAMPS AND CMAKE_CXX_COMPILER_ID MATCHES "Clang")
# clang-cl and cl by default produce non-deterministic binaries because
# link.exe /incremental requires a timestamp in the .obj file. clang-cl
# has the flag /Brepro to force deterministic binaries, so pass that when
# LLVM_ENABLE_TIMESTAMPS is turned off.
# This checks CMAKE_CXX_COMPILER_ID in addition to check_cxx_compiler_flag()
# because cl.exe does not emit an error on flags it doesn't understand,
# letting check_cxx_compiler_flag() claim it understands all flags.
check_cxx_compiler_flag("/Brepro" SUPPORTS_BREPRO)
append_if(SUPPORTS_BREPRO "/Brepro" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
if (SUPPORTS_BREPRO)
# Check if /INCREMENTAL is passed to the linker and complain that it
# won't work with /Brepro.
string(TOUPPER "${CMAKE_EXE_LINKER_FLAGS}" upper_exe_flags)
string(TOUPPER "${CMAKE_MODULE_LINKER_FLAGS}" upper_module_flags)
string(TOUPPER "${CMAKE_SHARED_LINKER_FLAGS}" upper_shared_flags)
string(FIND "${upper_exe_flags}" "/INCREMENTAL" exe_index)
string(FIND "${upper_module_flags}" "/INCREMENTAL" module_index)
string(FIND "${upper_shared_flags}" "/INCREMENTAL" shared_index)
if (${exe_index} GREATER -1 OR
${module_index} GREATER -1 OR
${shared_index} GREATER -1)
message(FATAL_ERROR "LLVM_ENABLE_TIMESTAMPS not compatible with /INCREMENTAL linking")
endif()
endif()
endif()
# Disable sized deallocation if the flag is supported. MSVC fails to compile
# the operator new overload in User otherwise.
check_c_compiler_flag("/WX /Zc:sizedDealloc-" SUPPORTS_SIZED_DEALLOC)

View File

@ -190,7 +190,7 @@ this property are side-effect free, only depending on their input arguments and
the state of memory when they are called. This property allows calls to these
functions to be eliminated and moved around, as long as there is no store
instruction that changes the contents of memory. Note that all functions that
satisfy the ``doesNotAccessMemory`` method also satisfies ``onlyReadsMemory``.
satisfy the ``doesNotAccessMemory`` method also satisfy ``onlyReadsMemory``.
Writing a new ``AliasAnalysis`` Implementation
==============================================
@ -634,7 +634,7 @@ transformations:
* It uses mod/ref information to hoist function calls out of loops that do not
write to memory and are loop-invariant.
* If uses alias information to promote memory objects that are loaded and stored
* It uses alias information to promote memory objects that are loaded and stored
to in loops to live in a register instead. It can do this if there are no may
aliases to the loaded/stored memory location.

View File

@ -11,9 +11,9 @@ DESCRIPTION
:program:`llvm-symbolizer` reads object file names and addresses from standard
input and prints corresponding source code locations to standard output.
If object file is specified in command line, :program:`llvm-symbolizer` reads
only addresses from standard input. This
program uses debug info sections and symbol table in the object files.
If object file is specified in command line, :program:`llvm-symbolizer`
processes only addresses from standard input, the rest is output verbatim.
This program uses debug info sections and symbol table in the object files.
EXAMPLE
--------

View File

@ -775,3 +775,67 @@ C++ code:
The "inner" ``catchswitch`` consumes ``%1`` which is produced by the outer
catchswitch.
.. _wineh-constraints:
Funclet transitions
-----------------------
The EH tables for personalities that use funclets make implicit use of the
funclet nesting relationship to encode unwind destinations, and so are
constrained in the set of funclet transitions they can represent. The related
LLVM IR instructions accordingly have constraints that ensure encodability of
the EH edges in the flow graph.
A ``catchswitch``, ``catchpad``, or ``cleanuppad`` is said to be "entered"
when it executes. It may subsequently be "exited" by any of the following
means:
* A ``catchswitch`` is immediately exited when none of its constituent
``catchpad``\ s are appropriate for the in-flight exception and it unwinds
to its unwind destination or the caller.
* A ``catchpad`` and its parent ``catchswitch`` are both exited when a
``catchret`` from the ``catchpad`` is executed.
* A ``cleanuppad`` is exited when a ``cleanupret`` from it is executed.
* Any of these pads is exited when control unwinds to the function's caller,
either by a ``call`` which unwinds all the way to the function's caller,
a nested ``catchswitch`` marked "``unwinds to caller``", or a nested
``cleanuppad``\ 's ``cleanupret`` marked "``unwinds to caller"``.
* Any of these pads is exited when an unwind edge (from an ``invoke``,
nested ``catchswitch``, or nested ``cleanuppad``\ 's ``cleanupret``)
unwinds to a destination pad that is not a descendant of the given pad.
Note that the ``ret`` instruction is *not* a valid way to exit a funclet pad;
it is undefined behavior to execute a ``ret`` when a pad has been entered but
not exited.
A single unwind edge may exit any number of pads (with the restrictions that
the edge from a ``catchswitch`` must exit at least itself, and the edge from
a ``cleanupret`` must exit at least its ``cleanuppad``), and then must enter
exactly one pad, which must be distinct from all the exited pads. The parent
of the pad that an unwind edge enters must be the most-recently-entered
not-yet-exited pad (after exiting from any pads that the unwind edge exits),
or "none" if there is no such pad. This ensures that the stack of executing
funclets at run-time always corresponds to some path in the funclet pad tree
that the parent tokens encode.
All unwind edges which exit any given funclet pad (including ``cleanupret``
edges exiting their ``cleanuppad`` and ``catchswitch`` edges exiting their
``catchswitch``) must share the same unwind destination. Similarly, any
funclet pad which may be exited by unwind to caller must not be exited by
any exception edges which unwind anywhere other than the caller. This
ensures that each funclet as a whole has only one unwind destination, which
EH tables for funclet personalities may require. Note that any unwind edge
which exits a ``catchpad`` also exits its parent ``catchswitch``, so this
implies that for any given ``catchswitch``, its unwind destination must also
be the unwind destination of any unwind edge that exits any of its constituent
``catchpad``\s. Because ``catchswitch`` has no ``nounwind`` variant, and
because IR producers are not *required* to annotate calls which will not
unwind as ``nounwind``, it is legal to nest a ``call`` or an "``unwind to
caller``\ " ``catchswitch`` within a funclet pad that has an unwind
destination other than caller; it is undefined behavior for such a ``call``
or ``catchswitch`` to unwind.
Finally, the funclet pads' unwind destinations cannot form a cycle. This
ensures that EH lowering can construct "try regions" with a tree-like
structure, which funclet-based personalities may require.

View File

@ -12,26 +12,20 @@ Welcome to LLVM on Windows! This document only covers LLVM on Windows using
Visual Studio, not mingw or cygwin. In order to get started, you first need to
know some basic information.
There are many different projects that compose LLVM. The first is the LLVM
suite. This contains all of the tools, libraries, and header files needed to
use LLVM. It contains an assembler, disassembler,
bitcode analyzer and bitcode optimizer. It also contains a test suite that can
be used to test the LLVM tools.
There are many different projects that compose LLVM. The first piece is the
LLVM suite. This contains all of the tools, libraries, and header files needed
to use LLVM. It contains an assembler, disassembler, bitcode analyzer and
bitcode optimizer. It also contains basic regression tests that can be used to
test the LLVM tools and the Clang front end.
Another useful project on Windows is `Clang <http://clang.llvm.org/>`_.
Clang is a C family ([Objective]C/C++) compiler. Clang mostly works on
Windows, but does not currently understand all of the Microsoft extensions
to C and C++. Because of this, clang cannot parse the C++ standard library
included with Visual Studio, nor parts of the Windows Platform SDK. However,
most standard C programs do compile. Clang can be used to emit bitcode,
directly emit object files or even linked executables using Visual Studio's
``link.exe``.
The second piece is the `Clang <http://clang.llvm.org/>`_ front end. This
component compiles C, C++, Objective C, and Objective C++ code into LLVM
bitcode. Clang typically uses LLVM libraries to optimize the bitcode and emit
machine code. LLVM fully supports the COFF object file format, which is
compatible with all other existing Windows toolchains.
The large LLVM test suite cannot be run on the Visual Studio port at this
time.
Most of the tools build and work. ``bugpoint`` does build, but does
not work.
The last major part of LLVM, the execution Test Suite, does not run on Windows,
and this document does not discuss it.
Additional information about the LLVM directory structure and tool chain
can be found on the main :doc:`GettingStarted` page.

View File

@ -1579,6 +1579,8 @@ caller's deoptimization state to the callee's deoptimization state is
semantically equivalent to composing the caller's deoptimization
continuation after the callee's deoptimization continuation.
.. _ob_funclet:
Funclet Operand Bundles
^^^^^^^^^^^^^^^^^^^^^^^
@ -1588,6 +1590,18 @@ is within a particular funclet. There can be at most one
``"funclet"`` operand bundle attached to a call site and it must have
exactly one bundle operand.
If any funclet EH pads have been "entered" but not "exited" (per the
`description in the EH doc\ <ExceptionHandling.html#wineh-constraints>`_),
it is undefined behavior to execute a ``call`` or ``invoke`` which:
* does not have a ``"funclet"`` bundle and is not a ``call`` to a nounwind
intrinsic, or
* has a ``"funclet"`` bundle whose operand is not the most-recently-entered
not-yet-exited funclet EH pad.
Similarly, if no funclet EH pads have been entered-but-not-yet-exited,
executing a ``call`` or ``invoke`` with a ``"funclet"`` bundle is undefined behavior.
.. _moduleasm:
Module-Level Inline Assembly
@ -5404,10 +5418,12 @@ The ``parent`` argument is the token of the funclet that contains the
``catchswitch`` instruction. If the ``catchswitch`` is not inside a funclet,
this operand may be the token ``none``.
The ``default`` argument is the label of another basic block beginning with a
"pad" instruction, one of ``cleanuppad`` or ``catchswitch``.
The ``default`` argument is the label of another basic block beginning with
either a ``cleanuppad`` or ``catchswitch`` instruction. This unwind destination
must be a legal target with respect to the ``parent`` links, as described in
the `exception handling documentation\ <ExceptionHandling.html#wineh-constraints>`_.
The ``handlers`` are a list of successor blocks that each begin with a
The ``handlers`` are a nonempty list of successor blocks that each begin with a
:ref:`catchpad <i_catchpad>` instruction.
Semantics:
@ -5431,82 +5447,6 @@ Example:
dispatch2:
%cs2 = catchswitch within %parenthandler [label %handler0] unwind label %cleanup
.. _i_catchpad:
'``catchpad``' Instruction
^^^^^^^^^^^^^^^^^^^^^^^^^^
Syntax:
"""""""
::
<resultval> = catchpad within <catchswitch> [<args>*]
Overview:
"""""""""
The '``catchpad``' instruction is used by `LLVM's exception handling
system <ExceptionHandling.html#overview>`_ to specify that a basic block
begins a catch handler --- one where a personality routine attempts to transfer
control to catch an exception.
Arguments:
""""""""""
The ``catchswitch`` operand must always be a token produced by a
:ref:`catchswitch <i_catchswitch>` instruction in a predecessor block. This
ensures that each ``catchpad`` has exactly one predecessor block, and it always
terminates in a ``catchswitch``.
The ``args`` correspond to whatever information the personality routine
requires to know if this is an appropriate handler for the exception. Control
will transfer to the ``catchpad`` if this is the first appropriate handler for
the exception.
The ``resultval`` has the type :ref:`token <t_token>` and is used to match the
``catchpad`` to corresponding :ref:`catchrets <i_catchret>` and other nested EH
pads.
Semantics:
""""""""""
When the call stack is being unwound due to an exception being thrown, the
exception is compared against the ``args``. If it doesn't match, control will
not reach the ``catchpad`` instruction. The representation of ``args`` is
entirely target and personality function-specific.
Like the :ref:`landingpad <i_landingpad>` instruction, the ``catchpad``
instruction must be the first non-phi of its parent basic block.
The meaning of the tokens produced and consumed by ``catchpad`` and other "pad"
instructions is described in the
`Windows exception handling documentation <ExceptionHandling.html#wineh>`.
Executing a ``catchpad`` instruction constitutes "entering" that pad.
The pad may then be "exited" in one of three ways:
1) explicitly via a ``catchret`` that consumes it. Executing such a ``catchret``
is undefined behavior if any descendant pads have been entered but not yet
exited.
2) implicitly via a call (which unwinds all the way to the current function's caller),
or via a ``catchswitch`` or a ``cleanupret`` that unwinds to caller.
3) implicitly via an unwind edge whose destination EH pad isn't a descendant of
the ``catchpad``. When the ``catchpad`` is exited in this manner, it is
undefined behavior if the destination EH pad has a parent which is not an
ancestor of the ``catchpad`` being exited.
Example:
""""""""
.. code-block:: llvm
dispatch:
%cs = catchswitch within none [label %handler0] unwind to caller
;; A catch block which can catch an integer.
handler0:
%tok = catchpad within %cs [i8** @_ZTIi]
.. _i_catchret:
'``catchret``' Instruction
@ -5543,11 +5483,10 @@ unwinding was interrupted with a :ref:`catchpad <i_catchpad>` instruction. The
code to, for example, destroy the active exception. Control then transfers to
``normal``.
The ``token`` argument must be a token produced by a dominating ``catchpad``
instruction. The ``catchret`` destroys the physical frame established by
``catchpad``, so executing multiple returns on the same token without
re-executing the ``catchpad`` will result in undefined behavior.
See :ref:`catchpad <i_catchpad>` for more details.
The ``token`` argument must be a token produced by a ``catchpad`` instruction.
If the specified ``catchpad`` is not the most-recently-entered not-yet-exited
funclet pad (as described in the `EH documentation\ <ExceptionHandling.html#wineh-constraints>`_),
the ``catchret``'s behavior is undefined.
Example:
""""""""
@ -5581,7 +5520,15 @@ Arguments:
The '``cleanupret``' instruction requires one argument, which indicates
which ``cleanuppad`` it exits, and must be a :ref:`cleanuppad <i_cleanuppad>`.
It also has an optional successor, ``continue``.
If the specified ``cleanuppad`` is not the most-recently-entered not-yet-exited
funclet pad (as described in the `EH documentation\ <ExceptionHandling.html#wineh-constraints>`_),
the ``cleanupret``'s behavior is undefined.
The '``cleanupret``' instruction also has an optional successor, ``continue``,
which must be the label of another basic block beginning with either a
``cleanuppad`` or ``catchswitch`` instruction. This unwind destination must
be a legal target with respect to the ``parent`` links, as described in the
`exception handling documentation\ <ExceptionHandling.html#wineh-constraints>`_.
Semantics:
""""""""""
@ -5591,13 +5538,6 @@ The '``cleanupret``' instruction indicates to the
:ref:`cleanuppad <i_cleanuppad>` it transferred control to has ended.
It transfers control to ``continue`` or unwinds out of the function.
The unwind destination ``continue``, if present, must be an EH pad
whose parent is either ``none`` or an ancestor of the ``cleanuppad``
being returned from. This constitutes an exceptional exit from all
ancestors of the completed ``cleanuppad``, up to but not including
the parent of ``continue``.
See :ref:`cleanuppad <i_cleanuppad>` for more details.
Example:
""""""""
@ -6996,7 +6936,7 @@ name ``<index>`` corresponding to a metadata node with one ``i32`` entry of
value 1. The existence of the ``!nontemporal`` metadata on the instruction
tells the optimizer and code generator that this load is not expected to
be reused in the cache. The code generator may select special
instructions to save cache bandwidth, such as the MOVNT instruction on
instructions to save cache bandwidth, such as the ``MOVNT`` instruction on
x86.
The optional ``!invariant.group`` metadata must reference a
@ -8590,6 +8530,74 @@ Example:
catch i8** @_ZTIi
filter [1 x i8**] [@_ZTId]
.. _i_catchpad:
'``catchpad``' Instruction
^^^^^^^^^^^^^^^^^^^^^^^^^^
Syntax:
"""""""
::
<resultval> = catchpad within <catchswitch> [<args>*]
Overview:
"""""""""
The '``catchpad``' instruction is used by `LLVM's exception handling
system <ExceptionHandling.html#overview>`_ to specify that a basic block
begins a catch handler --- one where a personality routine attempts to transfer
control to catch an exception.
Arguments:
""""""""""
The ``catchswitch`` operand must always be a token produced by a
:ref:`catchswitch <i_catchswitch>` instruction in a predecessor block. This
ensures that each ``catchpad`` has exactly one predecessor block, and it always
terminates in a ``catchswitch``.
The ``args`` correspond to whatever information the personality routine
requires to know if this is an appropriate handler for the exception. Control
will transfer to the ``catchpad`` if this is the first appropriate handler for
the exception.
The ``resultval`` has the type :ref:`token <t_token>` and is used to match the
``catchpad`` to corresponding :ref:`catchrets <i_catchret>` and other nested EH
pads.
Semantics:
""""""""""
When the call stack is being unwound due to an exception being thrown, the
exception is compared against the ``args``. If it doesn't match, control will
not reach the ``catchpad`` instruction. The representation of ``args`` is
entirely target and personality function-specific.
Like the :ref:`landingpad <i_landingpad>` instruction, the ``catchpad``
instruction must be the first non-phi of its parent basic block.
The meaning of the tokens produced and consumed by ``catchpad`` and other "pad"
instructions is described in the
`Windows exception handling documentation\ <ExceptionHandling.html#wineh>`_.
When a ``catchpad`` has been "entered" but not yet "exited" (as
described in the `EH documentation\ <ExceptionHandling.html#wineh-constraints>`_),
it is undefined behavior to execute a :ref:`call <i_call>` or :ref:`invoke <i_invoke>`
that does not carry an appropriate :ref:`"funclet" bundle <ob_funclet>`.
Example:
""""""""
.. code-block:: llvm
dispatch:
%cs = catchswitch within none [label %handler0] unwind to caller
;; A catch block which can catch an integer.
handler0:
%tok = catchpad within %cs [i8** @_ZTIi]
.. _i_cleanuppad:
'``cleanuppad``' Instruction
@ -8644,22 +8652,10 @@ The ``cleanuppad`` instruction has several restrictions:
- A basic block that is not a cleanup block may not include a
'``cleanuppad``' instruction.
Executing a ``cleanuppad`` instruction constitutes "entering" that pad.
The pad may then be "exited" in one of three ways:
1) explicitly via a ``cleanupret`` that consumes it. Executing such a ``cleanupret``
is undefined behavior if any descendant pads have been entered but not yet
exited.
2) implicitly via a call (which unwinds all the way to the current function's caller),
or via a ``catchswitch`` or a ``cleanupret`` that unwinds to caller.
3) implicitly via an unwind edge whose destination EH pad isn't a descendant of
the ``cleanuppad``. When the ``cleanuppad`` is exited in this manner, it is
undefined behavior if the destination EH pad has a parent which is not an
ancestor of the ``cleanuppad`` being exited.
It is undefined behavior for the ``cleanuppad`` to exit via an unwind edge which
does not transitively unwind to the same destination as a constituent
``cleanupret``.
When a ``cleanuppad`` has been "entered" but not yet "exited" (as
described in the `EH documentation\ <ExceptionHandling.html#wineh-constraints>`_),
it is undefined behavior to execute a :ref:`call <i_call>` or :ref:`invoke <i_invoke>`
that does not carry an appropriate :ref:`"funclet" bundle <ob_funclet>`.
Example:
""""""""

View File

@ -136,7 +136,7 @@ reviewers, the ``Differential Revision``, etc from the review and commit it to t
arc commit --revision D<Revision>
When committing an LLVM change that has been reviewed using
When committing a change that has been reviewed using
Phabricator, the convention is for the commit message to end with the
line:
@ -153,6 +153,12 @@ This allows people reading the version history to see the review for
context. This also allows Phabricator to detect the commit, close the
review, and add a link from the review to the commit.
If you use ``git`` or ``svn`` to commit the change and forget to add the line
to your commit message, you should close the review manually. In the web UI,
under "Leap Into Action" put the SVN revision number in the Comment, set the
Action to "Close Revision" and click Submit. Note the review must have been
Accepted first.
Abandoning a change
-------------------

View File

@ -408,6 +408,9 @@ Then you can run your pass like this:
'foo' debug type
$ opt < a.bc > /dev/null -mypass -debug-only=bar
'bar' debug type
$ opt < a.bc > /dev/null -mypass -debug-only=foo,bar
'foo' debug type
'bar' debug type
Of course, in practice, you should only set ``DEBUG_TYPE`` at the top of a file,
to specify the debug type for the entire module. Be careful that you only do
@ -417,7 +420,8 @@ system in place to ensure that names do not conflict. If two different modules
use the same string, they will all be turned on when the name is specified.
This allows, for example, all debug information for instruction scheduling to be
enabled with ``-debug-only=InstrSched``, even if the source lives in multiple
files.
files. The name must not include a comma (,) as that is used to seperate the
arguments of the ``-debug-only`` option.
For performance reasons, -debug-only is not available in optimized build
(``--enable-optimized``) of LLVM.

View File

@ -4,7 +4,7 @@
#include "llvm/ExecutionEngine/Orc/LambdaResolver.h"
#include "llvm/ExecutionEngine/Orc/LazyEmittingLayer.h"
#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
#include "llvm/ExecutionEngine/Orc/OrcTargetSupport.h"
#include "llvm/ExecutionEngine/Orc/OrcArchitectureSupport.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/IRBuilder.h"

View File

@ -53,10 +53,10 @@ public:
NumClasses = 0;
}
/// join - Join the equivalence classes of a and b. After joining classes,
/// findLeader(a) == findLeader(b).
/// This requires an uncompressed map.
void join(unsigned a, unsigned b);
/// Join the equivalence classes of a and b. After joining classes,
/// findLeader(a) == findLeader(b). This requires an uncompressed map.
/// Returns the new leader.
unsigned join(unsigned a, unsigned b);
/// findLeader - Compute the leader of a's equivalence class. This is the
/// smallest member of the class.

View File

@ -0,0 +1,103 @@
//===- llvm/ADT/PointerEmbeddedInt.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_ADT_POINTEREMBEDDEDINT_H
#define LLVM_ADT_POINTEREMBEDDEDINT_H
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/Support/PointerLikeTypeTraits.h"
#include <climits>
namespace llvm {
/// Utility to embed an integer into a pointer-like type. This is specifically
/// intended to allow embedding integers where fewer bits are required than
/// exist in a pointer, and the integer can participate in abstractions along
/// side other pointer-like types. For example it can be placed into a \c
/// PointerSumType or \c PointerUnion.
///
/// Note that much like pointers, an integer value of zero has special utility
/// due to boolean conversions. For example, a non-null value can be tested for
/// in the above abstractions without testing the particular active member.
/// Also, the default constructed value zero initializes the integer.
template <typename IntT, int Bits = sizeof(IntT) * CHAR_BIT>
class PointerEmbeddedInt {
uintptr_t Value;
static_assert(Bits < sizeof(uintptr_t) * CHAR_BIT,
"Cannot embed more bits than we have in a pointer!");
enum : uintptr_t {
// We shift as many zeros into the value as we can while preserving the
// number of bits desired for the integer.
Shift = sizeof(uintptr_t) * CHAR_BIT - Bits,
// We also want to be able to mask out the preserved bits for asserts.
Mask = static_cast<uintptr_t>(-1) << Bits
};
friend class PointerLikeTypeTraits<PointerEmbeddedInt>;
explicit PointerEmbeddedInt(uintptr_t Value) : Value(Value) {}
public:
PointerEmbeddedInt() : Value(0) {}
PointerEmbeddedInt(IntT I) : Value(static_cast<uintptr_t>(I) << Shift) {
assert((I & Mask) == 0 && "Integer has bits outside those preserved!");
}
PointerEmbeddedInt &operator=(IntT I) {
assert((I & Mask) == 0 && "Integer has bits outside those preserved!");
Value = static_cast<uintptr_t>(I) << Shift;
}
// Note that this imilict conversion additionally allows all of the basic
// comparison operators to work transparently, etc.
operator IntT() const { return static_cast<IntT>(Value >> Shift); }
};
// Provide pointer like traits to support use with pointer unions and sum
// types.
template <typename IntT, int Bits>
class PointerLikeTypeTraits<PointerEmbeddedInt<IntT, Bits>> {
typedef PointerEmbeddedInt<IntT, Bits> T;
public:
static inline void *getAsVoidPointer(const T &P) {
return reinterpret_cast<void *>(P.Value);
}
static inline T getFromVoidPointer(void *P) {
return T(reinterpret_cast<uintptr_t>(P));
}
static inline T getFromVoidPointer(const void *P) {
return T(reinterpret_cast<uintptr_t>(P));
}
enum { NumLowBitsAvailable = T::Shift };
};
// Teach DenseMap how to use PointerEmbeddedInt objects as keys if the Int type
// itself can be a key.
template <typename IntT, int Bits>
struct DenseMapInfo<PointerEmbeddedInt<IntT, Bits>> {
typedef PointerEmbeddedInt<IntT, Bits> T;
typedef DenseMapInfo<IntT> IntInfo;
static inline T getEmptyKey() { return IntInfo::getEmptyKey(); }
static inline T getTombstoneKey() { return IntInfo::getTombstoneKey(); }
static unsigned getHashValue(const T &Arg) {
return IntInfo::getHashValue(Arg);
}
static bool isEqual(const T &LHS, const T &RHS) { return LHS == RHS; }
};
}
#endif

View File

@ -55,20 +55,25 @@ public:
PointerTy getPointer() const { return Info::getPointer(Value); }
IntType getInt() const { return (IntType)Info::getInt(Value); }
IntType getInt() const {
return (IntType)Info::getInt(Value);
}
void setPointer(PointerTy PtrVal) {
Value = Info::updatePointer(Value, PtrVal);
}
void setInt(IntType IntVal) { Value = Info::updateInt(Value, IntVal); }
void setInt(IntType IntVal) {
Value = Info::updateInt(Value, static_cast<intptr_t>(IntVal));
}
void initWithPointer(PointerTy PtrVal) {
Value = Info::updatePointer(0, PtrVal);
}
void setPointerAndInt(PointerTy PtrVal, IntType IntVal) {
Value = Info::updateInt(Info::updatePointer(0, PtrVal), IntVal);
Value = Info::updateInt(Info::updatePointer(0, PtrVal),
static_cast<intptr_t>(IntVal));
}
PointerTy const *getAddrOfPointer() const {

View File

@ -0,0 +1,205 @@
//===- llvm/ADT/PointerSumType.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_ADT_POINTERSUMTYPE_H
#define LLVM_ADT_POINTERSUMTYPE_H
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/PointerLikeTypeTraits.h"
namespace llvm {
/// A compile time pair of an integer tag and the pointer-like type which it
/// indexes within a sum type. Also allows the user to specify a particular
/// traits class for pointer types with custom behavior such as over-aligned
/// allocation.
template <uintptr_t N, typename PointerArgT,
typename TraitsArgT = PointerLikeTypeTraits<PointerArgT>>
struct PointerSumTypeMember {
enum { Tag = N };
typedef PointerArgT PointerT;
typedef TraitsArgT TraitsT;
};
namespace detail {
template <typename TagT, typename... MemberTs>
struct PointerSumTypeHelper;
}
/// A sum type over pointer-like types.
///
/// This is a normal tagged union across pointer-like types that uses the low
/// bits of the pointers to store the tag.
///
/// Each member of the sum type is specified by passing a \c
/// PointerSumTypeMember specialization in the variadic member argument list.
/// This allows the user to control the particular tag value associated with
/// a particular type, use the same type for multiple different tags, and
/// customize the pointer-like traits used for a particular member. Note that
/// these *must* be specializations of \c PointerSumTypeMember, no other type
/// will suffice, even if it provides a compatible interface.
///
/// This type implements all of the comparison operators and even hash table
/// support by comparing the underlying storage of the pointer values. It
/// doesn't support delegating to particular members for comparisons.
///
/// It also default constructs to a zero tag with a null pointer, whatever that
/// would be. This means that the zero value for the tag type is significant
/// and may be desireable to set to a state that is particularly desirable to
/// default construct.
///
/// There is no support for constructing or accessing with a dynamic tag as
/// that would fundamentally violate the type safety provided by the sum type.
template <typename TagT, typename... MemberTs> class PointerSumType {
uintptr_t Value;
typedef detail::PointerSumTypeHelper<TagT, MemberTs...> HelperT;
public:
PointerSumType() : Value(0) {}
/// A typed constructor for a specific tagged member of the sum type.
template <TagT N>
static PointerSumType
create(typename HelperT::template Lookup<N>::PointerT Pointer) {
PointerSumType Result;
void *V = HelperT::template Lookup<N>::TraitsT::getAsVoidPointer(Pointer);
assert((reinterpret_cast<uintptr_t>(V) & HelperT::TagMask) == 0 &&
"Pointer is insufficiently aligned to store the discriminant!");
Result.Value = reinterpret_cast<uintptr_t>(V) | N;
return Result;
}
TagT getTag() const { return static_cast<TagT>(Value & HelperT::TagMask); }
template <TagT N> bool is() const { return N == getTag(); }
template <TagT N> typename HelperT::template Lookup<N>::PointerT get() const {
void *P = is<N>() ? getImpl() : nullptr;
return HelperT::template Lookup<N>::TraitsT::getFromVoidPointer(P);
}
template <TagT N>
typename HelperT::template Lookup<N>::PointerT cast() const {
assert(is<N>() && "This instance has a different active member.");
return HelperT::template Lookup<N>::TraitsT::getFromVoidPointer(getImpl());
}
operator bool() const { return Value & HelperT::PointerMask; }
bool operator==(const PointerSumType &R) const { return Value == R.Value; }
bool operator!=(const PointerSumType &R) const { return Value != R.Value; }
bool operator<(const PointerSumType &R) const { return Value < R.Value; }
bool operator>(const PointerSumType &R) const { return Value > R.Value; }
bool operator<=(const PointerSumType &R) const { return Value <= R.Value; }
bool operator>=(const PointerSumType &R) const { return Value >= R.Value; }
uintptr_t getOpaqueValue() const { return Value; }
protected:
void *getImpl() const {
return reinterpret_cast<void *>(Value & HelperT::PointerMask);
}
};
namespace detail {
/// A helper template for implementing \c PointerSumType. It provides fast
/// compile-time lookup of the member from a particular tag value, along with
/// useful constants and compile time checking infrastructure..
template <typename TagT, typename... MemberTs>
struct PointerSumTypeHelper : MemberTs... {
// First we use a trick to allow quickly looking up information about
// a particular member of the sum type. This works because we arranged to
// have this type derive from all of the member type templates. We can select
// the matching member for a tag using type deduction during overload
// resolution.
template <TagT N, typename PointerT, typename TraitsT>
static PointerSumTypeMember<N, PointerT, TraitsT>
LookupOverload(PointerSumTypeMember<N, PointerT, TraitsT> *);
template <TagT N> static void LookupOverload(...);
template <TagT N> struct Lookup {
// Compute a particular member type by resolving the lookup helper ovorload.
typedef decltype(LookupOverload<N>(
static_cast<PointerSumTypeHelper *>(nullptr))) MemberT;
/// The Nth member's pointer type.
typedef typename MemberT::PointerT PointerT;
/// The Nth member's traits type.
typedef typename MemberT::TraitsT TraitsT;
};
// Next we need to compute the number of bits available for the discriminant
// by taking the min of the bits available for each member. Much of this
// would be amazingly easier with good constexpr support.
template <uintptr_t V, uintptr_t... Vs>
struct Min : std::integral_constant<
uintptr_t, (V < Min<Vs...>::value ? V : Min<Vs...>::value)> {
};
template <uintptr_t V>
struct Min<V> : std::integral_constant<uintptr_t, V> {};
enum { NumTagBits = Min<MemberTs::TraitsT::NumLowBitsAvailable...>::value };
// Also compute the smallest discriminant and various masks for convenience.
enum : uint64_t {
MinTag = Min<MemberTs::Tag...>::value,
PointerMask = static_cast<uint64_t>(-1) << NumTagBits,
TagMask = ~PointerMask
};
// Finally we need a recursive template to do static checks of each
// member.
template <typename MemberT, typename... InnerMemberTs>
struct Checker : Checker<InnerMemberTs...> {
static_assert(MemberT::Tag < (1 << NumTagBits),
"This discriminant value requires too many bits!");
};
template <typename MemberT> struct Checker<MemberT> : std::true_type {
static_assert(MemberT::Tag < (1 << NumTagBits),
"This discriminant value requires too many bits!");
};
static_assert(Checker<MemberTs...>::value,
"Each member must pass the checker.");
};
}
// Teach DenseMap how to use PointerSumTypes as keys.
template <typename TagT, typename... MemberTs>
struct DenseMapInfo<PointerSumType<TagT, MemberTs...>> {
typedef PointerSumType<TagT, MemberTs...> SumType;
typedef detail::PointerSumTypeHelper<TagT, MemberTs...> HelperT;
enum { SomeTag = HelperT::MinTag };
typedef typename HelperT::template Lookup<HelperT::MinTag>::PointerT
SomePointerT;
typedef DenseMapInfo<SomePointerT> SomePointerInfo;
static inline SumType getEmptyKey() {
return SumType::create<SomeTag>(SomePointerInfo::getEmptyKey());
}
static inline SumType getTombstoneKey() {
return SumType::create<SomeTag>(
SomePointerInfo::getTombstoneKey());
}
static unsigned getHashValue(const SumType &Arg) {
uintptr_t OpaqueValue = Arg.getOpaqueValue();
return DenseMapInfo<uintptr_t>::getHashValue(OpaqueValue);
}
static bool isEqual(const SumType &LHS, const SumType &RHS) {
return LHS == RHS;
}
};
}
#endif

View File

@ -101,15 +101,13 @@ namespace llvm {
/// A pointer to a SmallString instance.
SmallStringKind,
/// A char value reinterpreted as a pointer, to render as a character.
/// A char value, to render as a character.
CharKind,
/// An unsigned int value reinterpreted as a pointer, to render as an
/// unsigned decimal integer.
/// An unsigned int value, to render as an unsigned decimal integer.
DecUIKind,
/// An int value reinterpreted as a pointer, to render as a signed
/// decimal integer.
/// An int value, to render as a signed decimal integer.
DecIKind,
/// A pointer to an unsigned long value, to render as an unsigned decimal

View File

@ -104,54 +104,10 @@ class LazyCallGraph {
public:
class Node;
class SCC;
class iterator;
typedef SmallVector<PointerUnion<Function *, Node *>, 4> NodeVectorT;
typedef SmallVectorImpl<PointerUnion<Function *, Node *>> NodeVectorImplT;
/// A lazy iterator used for both the entry nodes and child nodes.
///
/// When this iterator is dereferenced, if not yet available, a function will
/// be scanned for "calls" or uses of functions and its child information
/// will be constructed. All of these results are accumulated and cached in
/// the graph.
class iterator
: public iterator_adaptor_base<iterator, NodeVectorImplT::iterator,
std::forward_iterator_tag, Node> {
friend class LazyCallGraph;
friend class LazyCallGraph::Node;
LazyCallGraph *G;
NodeVectorImplT::iterator E;
// Build the iterator for a specific position in a node list.
iterator(LazyCallGraph &G, NodeVectorImplT::iterator NI,
NodeVectorImplT::iterator E)
: iterator_adaptor_base(NI), G(&G), E(E) {
while (I != E && I->isNull())
++I;
}
public:
iterator() {}
using iterator_adaptor_base::operator++;
iterator &operator++() {
do {
++I;
} while (I != E && I->isNull());
return *this;
}
reference operator*() const {
if (I->is<Node *>())
return *I->get<Node *>();
Function *F = I->get<Function *>();
Node &ChildN = G->get(*F);
*I = &ChildN;
return ChildN;
}
};
/// A node in the call graph.
///
/// This represents a single node. It's primary roles are to cache the list of
@ -200,6 +156,51 @@ public:
bool operator!=(const Node &N) const { return !operator==(N); }
};
/// A lazy iterator used for both the entry nodes and child nodes.
///
/// When this iterator is dereferenced, if not yet available, a function will
/// be scanned for "calls" or uses of functions and its child information
/// will be constructed. All of these results are accumulated and cached in
/// the graph.
class iterator
: public iterator_adaptor_base<iterator, NodeVectorImplT::iterator,
std::forward_iterator_tag, Node> {
friend class LazyCallGraph;
friend class LazyCallGraph::Node;
LazyCallGraph *G;
NodeVectorImplT::iterator E;
// Build the iterator for a specific position in a node list.
iterator(LazyCallGraph &G, NodeVectorImplT::iterator NI,
NodeVectorImplT::iterator E)
: iterator_adaptor_base(NI), G(&G), E(E) {
while (I != E && I->isNull())
++I;
}
public:
iterator() {}
using iterator_adaptor_base::operator++;
iterator &operator++() {
do {
++I;
} while (I != E && I->isNull());
return *this;
}
reference operator*() const {
if (I->is<Node *>())
return *I->get<Node *>();
Function *F = I->get<Function *>();
Node &ChildN = G->get(*F);
*I = &ChildN;
return ChildN;
}
};
/// An SCC of the call graph.
///
/// This represents a Strongly Connected Component of the call graph as

View File

@ -59,38 +59,37 @@ template<class N, class M> class LoopInfoBase;
template<class N, class M> class LoopBase;
//===----------------------------------------------------------------------===//
/// LoopBase class - Instances of this class are used to represent loops that
/// are detected in the flow graph
/// Instances of this class are used to represent loops that are detected in the
/// flow graph.
///
template<class BlockT, class LoopT>
class LoopBase {
LoopT *ParentLoop;
// SubLoops - Loops contained entirely within this one.
// Loops contained entirely within this one.
std::vector<LoopT *> SubLoops;
// Blocks - The list of blocks in this loop. First entry is the header node.
// The list of blocks in this loop. First entry is the header node.
std::vector<BlockT*> Blocks;
SmallPtrSet<const BlockT*, 8> DenseBlockSet;
/// Indicator that this loops has been "unlooped", so there's no loop here
/// anymore.
bool IsUnloop = false;
/// Indicator that this loop is no longer a valid loop.
bool IsInvalid = false;
LoopBase(const LoopBase<BlockT, LoopT> &) = delete;
const LoopBase<BlockT, LoopT>&
operator=(const LoopBase<BlockT, LoopT> &) = delete;
public:
/// Loop ctor - This creates an empty loop.
/// This creates an empty loop.
LoopBase() : ParentLoop(nullptr) {}
~LoopBase() {
for (size_t i = 0, e = SubLoops.size(); i != e; ++i)
delete SubLoops[i];
}
/// getLoopDepth - Return the nesting level of this loop. An outer-most
/// loop has depth 1, for consistency with loop depth values used for basic
/// blocks, where depth 0 is used for blocks not inside any loops.
/// Return the nesting level of this loop. An outer-most loop has depth 1,
/// for consistency with loop depth values used for basic blocks, where depth
/// 0 is used for blocks not inside any loops.
unsigned getLoopDepth() const {
unsigned D = 1;
for (const LoopT *CurLoop = ParentLoop; CurLoop;
@ -101,33 +100,28 @@ public:
BlockT *getHeader() const { return Blocks.front(); }
LoopT *getParentLoop() const { return ParentLoop; }
/// setParentLoop is a raw interface for bypassing addChildLoop.
/// This is a raw interface for bypassing addChildLoop.
void setParentLoop(LoopT *L) { ParentLoop = L; }
/// contains - Return true if the specified loop is contained within in
/// this loop.
///
/// Return true if the specified loop is contained within in this loop.
bool contains(const LoopT *L) const {
if (L == this) return true;
if (!L) return false;
return contains(L->getParentLoop());
}
/// contains - Return true if the specified basic block is in this loop.
///
/// Return true if the specified basic block is in this loop.
bool contains(const BlockT *BB) const {
return DenseBlockSet.count(BB);
}
/// contains - Return true if the specified instruction is in this loop.
///
/// Return true if the specified instruction is in this loop.
template<class InstT>
bool contains(const InstT *Inst) const {
return contains(Inst->getParent());
}
/// iterator/begin/end - Return the loops contained entirely within this loop.
///
/// Return the loops contained entirely within this loop.
const std::vector<LoopT *> &getSubLoops() const { return SubLoops; }
std::vector<LoopT *> &getSubLoopsVector() { return SubLoops; }
typedef typename std::vector<LoopT *>::const_iterator iterator;
@ -139,8 +133,7 @@ public:
reverse_iterator rend() const { return SubLoops.rend(); }
bool empty() const { return SubLoops.empty(); }
/// getBlocks - Get a list of the basic blocks which make up this loop.
///
/// Get a list of the basic blocks which make up this loop.
const std::vector<BlockT*> &getBlocks() const { return Blocks; }
typedef typename std::vector<BlockT*>::const_iterator block_iterator;
block_iterator block_begin() const { return Blocks.begin(); }
@ -149,21 +142,19 @@ public:
return make_range(block_begin(), block_end());
}
/// getNumBlocks - Get the number of blocks in this loop in constant time.
/// Get the number of blocks in this loop in constant time.
unsigned getNumBlocks() const {
return Blocks.size();
}
/// Mark this loop as having been unlooped - the last backedge was removed and
/// we no longer have a loop.
void markUnlooped() { IsUnloop = true; }
/// Invalidate the loop, indicating that it is no longer a loop.
void invalidate() { IsInvalid = true; }
/// Return true if this no longer represents a loop.
bool isUnloop() const { return IsUnloop; }
/// Return true if this loop is no longer valid.
bool isInvalid() { return IsInvalid; }
/// isLoopExiting - True if terminator in the block can branch to another
/// block that is outside of the current loop.
///
/// True if terminator in the block can branch to another block that is
/// outside of the current loop.
bool isLoopExiting(const BlockT *BB) const {
typedef GraphTraits<const BlockT*> BlockTraits;
for (typename BlockTraits::ChildIteratorType SI =
@ -175,8 +166,7 @@ public:
return false;
}
/// getNumBackEdges - Calculate the number of back edges to the loop header
///
/// Calculate the number of back edges to the loop header.
unsigned getNumBackEdges() const {
unsigned NumBackEdges = 0;
BlockT *H = getHeader();
@ -199,53 +189,49 @@ public:
// induction variable canonicalization pass should be used to normalize loops
// for easy analysis. These methods assume canonical loops.
/// getExitingBlocks - Return all blocks inside the loop that have successors
/// outside of the loop. These are the blocks _inside of the current loop_
/// which branch out. The returned list is always unique.
///
/// Return all blocks inside the loop that have successors outside of the
/// loop. These are the blocks _inside of the current loop_ which branch out.
/// The returned list is always unique.
void getExitingBlocks(SmallVectorImpl<BlockT *> &ExitingBlocks) const;
/// getExitingBlock - If getExitingBlocks would return exactly one block,
/// return that block. Otherwise return null.
/// If getExitingBlocks would return exactly one block, return that block.
/// Otherwise return null.
BlockT *getExitingBlock() const;
/// getExitBlocks - Return all of the successor blocks of this loop. These
/// are the blocks _outside of the current loop_ which are branched to.
///
/// Return all of the successor blocks of this loop. These are the blocks
/// _outside of the current loop_ which are branched to.
void getExitBlocks(SmallVectorImpl<BlockT*> &ExitBlocks) const;
/// getExitBlock - If getExitBlocks would return exactly one block,
/// return that block. Otherwise return null.
/// If getExitBlocks would return exactly one block, return that block.
/// Otherwise return null.
BlockT *getExitBlock() const;
/// Edge type.
typedef std::pair<const BlockT*, const BlockT*> Edge;
/// getExitEdges - Return all pairs of (_inside_block_,_outside_block_).
/// Return all pairs of (_inside_block_,_outside_block_).
void getExitEdges(SmallVectorImpl<Edge> &ExitEdges) const;
/// getLoopPreheader - If there is a preheader for this loop, return it. A
/// loop has a preheader if there is only one edge to the header of the loop
/// from outside of the loop. If this is the case, the block branching to the
/// header of the loop is the preheader node.
/// If there is a preheader for this loop, return it. A loop has a preheader
/// if there is only one edge to the header of the loop from outside of the
/// loop. If this is the case, the block branching to the header of the loop
/// is the preheader node.
///
/// This method returns null if there is no preheader for the loop.
///
BlockT *getLoopPreheader() const;
/// getLoopPredecessor - If the given loop's header has exactly one unique
/// predecessor outside the loop, return it. Otherwise return null.
/// This is less strict that the loop "preheader" concept, which requires
/// If the given loop's header has exactly one unique predecessor outside the
/// loop, return it. Otherwise return null.
/// This is less strict that the loop "preheader" concept, which requires
/// the predecessor to have exactly one successor.
///
BlockT *getLoopPredecessor() const;
/// getLoopLatch - If there is a single latch block for this loop, return it.
/// If there is a single latch block for this loop, return it.
/// A latch block is a block that contains a branch back to the header.
BlockT *getLoopLatch() const;
/// getLoopLatches - Return all loop latch blocks of this loop. A latch block
/// is a block that contains a branch back to the header.
/// Return all loop latch blocks of this loop. A latch block is a block that
/// contains a branch back to the header.
void getLoopLatches(SmallVectorImpl<BlockT *> &LoopLatches) const {
BlockT *H = getHeader();
typedef GraphTraits<Inverse<BlockT*> > InvBlockTraits;
@ -260,32 +246,29 @@ public:
// APIs for updating loop information after changing the CFG
//
/// addBasicBlockToLoop - This method is used by other analyses to update loop
/// information. NewBB is set to be a new member of the current loop.
/// This method is used by other analyses to update loop information.
/// NewBB is set to be a new member of the current loop.
/// Because of this, it is added as a member of all parent loops, and is added
/// to the specified LoopInfo object as being in the current basic block. It
/// is not valid to replace the loop header with this method.
///
void addBasicBlockToLoop(BlockT *NewBB, LoopInfoBase<BlockT, LoopT> &LI);
/// replaceChildLoopWith - This is used when splitting loops up. It replaces
/// the OldChild entry in our children list with NewChild, and updates the
/// parent pointer of OldChild to be null and the NewChild to be this loop.
/// This is used when splitting loops up. It replaces the OldChild entry in
/// our children list with NewChild, and updates the parent pointer of
/// OldChild to be null and the NewChild to be this loop.
/// This updates the loop depth of the new child.
void replaceChildLoopWith(LoopT *OldChild, LoopT *NewChild);
/// addChildLoop - Add the specified loop to be a child of this loop. This
/// updates the loop depth of the new child.
///
/// Add the specified loop to be a child of this loop.
/// This updates the loop depth of the new child.
void addChildLoop(LoopT *NewChild) {
assert(!NewChild->ParentLoop && "NewChild already has a parent!");
NewChild->ParentLoop = static_cast<LoopT *>(this);
SubLoops.push_back(NewChild);
}
/// removeChildLoop - This removes the specified child from being a subloop of
/// this loop. The loop is not deleted, as it will presumably be inserted
/// into another loop.
/// This removes the specified child from being a subloop of this loop. The
/// loop is not deleted, as it will presumably be inserted into another loop.
LoopT *removeChildLoop(iterator I) {
assert(I != SubLoops.end() && "Cannot remove end iterator!");
LoopT *Child = *I;
@ -295,7 +278,7 @@ public:
return Child;
}
/// addBlockEntry - This adds a basic block directly to the basic block list.
/// This adds a basic block directly to the basic block list.
/// This should only be used by transformations that create new loops. Other
/// transformations should use addBasicBlockToLoop.
void addBlockEntry(BlockT *BB) {
@ -303,19 +286,18 @@ public:
DenseBlockSet.insert(BB);
}
/// reverseBlocks - interface to reverse Blocks[from, end of loop] in this loop
/// interface to reverse Blocks[from, end of loop] in this loop
void reverseBlock(unsigned from) {
std::reverse(Blocks.begin() + from, Blocks.end());
}
/// reserveBlocks- interface to do reserve() for Blocks
/// interface to do reserve() for Blocks
void reserveBlocks(unsigned size) {
Blocks.reserve(size);
}
/// moveToHeader - This method is used to move BB (which must be part of this
/// loop) to be the loop header of the loop (the block that dominates all
/// others).
/// This method is used to move BB (which must be part of this loop) to be the
/// loop header of the loop (the block that dominates all others).
void moveToHeader(BlockT *BB) {
if (Blocks[0] == BB) return;
for (unsigned i = 0; ; ++i) {
@ -328,9 +310,9 @@ public:
}
}
/// removeBlockFromLoop - This removes the specified basic block from the
/// current loop, updating the Blocks as appropriate. This does not update
/// the mapping in the LoopInfo class.
/// This removes the specified basic block from the current loop, updating the
/// Blocks as appropriate. This does not update the mapping in the LoopInfo
/// class.
void removeBlockFromLoop(BlockT *BB) {
auto I = std::find(Blocks.begin(), Blocks.end(), BB);
assert(I != Blocks.end() && "N is not in this list!");
@ -339,10 +321,10 @@ public:
DenseBlockSet.erase(BB);
}
/// verifyLoop - Verify loop structure
/// Verify loop structure
void verifyLoop() const;
/// verifyLoop - Verify loop structure of this loop and all nested loops.
/// Verify loop structure of this loop and all nested loops.
void verifyLoopNest(DenseSet<const LoopT*> *Loops) const;
void print(raw_ostream &OS, unsigned Depth = 0) const;
@ -368,28 +350,26 @@ class Loop : public LoopBase<BasicBlock, Loop> {
public:
Loop() {}
/// isLoopInvariant - Return true if the specified value is loop invariant
///
/// Return true if the specified value is loop invariant.
bool isLoopInvariant(const Value *V) const;
/// hasLoopInvariantOperands - Return true if all the operands of the
/// specified instruction are loop invariant.
/// Return true if all the operands of the specified instruction are loop
/// invariant.
bool hasLoopInvariantOperands(const Instruction *I) const;
/// makeLoopInvariant - If the given value is an instruction inside of the
/// loop and it can be hoisted, do so to make it trivially loop-invariant.
/// If the given value is an instruction inside of the loop and it can be
/// hoisted, do so to make it trivially loop-invariant.
/// Return true if the value after any hoisting is loop invariant. This
/// function can be used as a slightly more aggressive replacement for
/// isLoopInvariant.
///
/// If InsertPt is specified, it is the point to hoist instructions to.
/// If null, the terminator of the loop preheader is used.
///
bool makeLoopInvariant(Value *V, bool &Changed,
Instruction *InsertPt = nullptr) const;
/// makeLoopInvariant - If the given instruction is inside of the
/// loop and it can be hoisted, do so to make it trivially loop-invariant.
/// If the given instruction is inside of the loop and it can be hoisted, do
/// so to make it trivially loop-invariant.
/// Return true if the instruction after any hoisting is loop invariant. This
/// function can be used as a slightly more aggressive replacement for
/// isLoopInvariant.
@ -400,28 +380,26 @@ public:
bool makeLoopInvariant(Instruction *I, bool &Changed,
Instruction *InsertPt = nullptr) const;
/// getCanonicalInductionVariable - Check to see if the loop has a canonical
/// induction variable: an integer recurrence that starts at 0 and increments
/// by one each time through the loop. If so, return the phi node that
/// corresponds to it.
/// Check to see if the loop has a canonical induction variable: an integer
/// recurrence that starts at 0 and increments by one each time through the
/// loop. If so, return the phi node that corresponds to it.
///
/// The IndVarSimplify pass transforms loops to have a canonical induction
/// variable.
///
PHINode *getCanonicalInductionVariable() const;
/// isLCSSAForm - Return true if the Loop is in LCSSA form
/// Return true if the Loop is in LCSSA form.
bool isLCSSAForm(DominatorTree &DT) const;
/// \brief Return true if this Loop and all inner subloops are in LCSSA form.
/// Return true if this Loop and all inner subloops are in LCSSA form.
bool isRecursivelyLCSSAForm(DominatorTree &DT) const;
/// isLoopSimplifyForm - Return true if the Loop is in the form that
/// the LoopSimplify form transforms loops to, which is sometimes called
/// normal form.
/// Return true if the Loop is in the form that the LoopSimplify form
/// transforms loops to, which is sometimes called normal form.
bool isLoopSimplifyForm() const;
/// isSafeToClone - Return true if the loop body is safe to clone in practice.
/// Return true if the loop body is safe to clone in practice.
bool isSafeToClone() const;
/// Returns true if the loop is annotated parallel.
@ -454,23 +432,22 @@ public:
/// operand should should be the node itself.
void setLoopID(MDNode *LoopID) const;
/// hasDedicatedExits - Return true if no exit block for the loop
/// has a predecessor that is outside the loop.
/// Return true if no exit block for the loop has a predecessor that is
/// outside the loop.
bool hasDedicatedExits() const;
/// getUniqueExitBlocks - Return all unique successor blocks of this loop.
/// Return all unique successor blocks of this loop.
/// These are the blocks _outside of the current loop_ which are branched to.
/// This assumes that loop exits are in canonical form.
///
void getUniqueExitBlocks(SmallVectorImpl<BasicBlock *> &ExitBlocks) const;
/// getUniqueExitBlock - If getUniqueExitBlocks would return exactly one
/// block, return that block. Otherwise return null.
/// If getUniqueExitBlocks would return exactly one block, return that block.
/// Otherwise return null.
BasicBlock *getUniqueExitBlock() const;
void dump() const;
/// \brief Return the debug location of the start of this loop.
/// Return the debug location of the start of this loop.
/// This looks for a BB terminating instruction with a known debug
/// location by looking at the preheader and header blocks. If it
/// cannot find a terminating instruction with location information,
@ -498,7 +475,7 @@ private:
};
//===----------------------------------------------------------------------===//
/// LoopInfo - This class builds and contains all of the top level loop
/// This class builds and contains all of the top-level loop
/// structures in the specified function.
///
@ -507,6 +484,8 @@ class LoopInfoBase {
// BBMap - Mapping of basic blocks to the inner most loop they occur in
DenseMap<const BlockT *, LoopT *> BBMap;
std::vector<LoopT *> TopLevelLoops;
std::vector<LoopT *> RemovedLoops;
friend class LoopBase<BlockT, LoopT>;
friend class LoopInfo;
@ -538,6 +517,9 @@ public:
for (auto *L : TopLevelLoops)
delete L;
TopLevelLoops.clear();
for (auto *L : RemovedLoops)
delete L;
RemovedLoops.clear();
}
/// iterator/begin/end - The interface to the top-level loops in the current
@ -552,33 +534,30 @@ public:
reverse_iterator rend() const { return TopLevelLoops.rend(); }
bool empty() const { return TopLevelLoops.empty(); }
/// getLoopFor - Return the inner most loop that BB lives in. If a basic
/// block is in no loop (for example the entry node), null is returned.
///
/// Return the inner most loop that BB lives in. If a basic block is in no
/// loop (for example the entry node), null is returned.
LoopT *getLoopFor(const BlockT *BB) const { return BBMap.lookup(BB); }
/// operator[] - same as getLoopFor...
///
/// Same as getLoopFor.
const LoopT *operator[](const BlockT *BB) const {
return getLoopFor(BB);
}
/// getLoopDepth - Return the loop nesting level of the specified block. A
/// depth of 0 means the block is not inside any loop.
///
/// Return the loop nesting level of the specified block. A depth of 0 means
/// the block is not inside any loop.
unsigned getLoopDepth(const BlockT *BB) const {
const LoopT *L = getLoopFor(BB);
return L ? L->getLoopDepth() : 0;
}
// isLoopHeader - True if the block is a loop header node
// True if the block is a loop header node
bool isLoopHeader(const BlockT *BB) const {
const LoopT *L = getLoopFor(BB);
return L && L->getHeader() == BB;
}
/// removeLoop - This removes the specified top-level loop from this loop info
/// object. The loop is not deleted, as it will presumably be inserted into
/// This removes the specified top-level loop from this loop info object.
/// The loop is not deleted, as it will presumably be inserted into
/// another loop.
LoopT *removeLoop(iterator I) {
assert(I != end() && "Cannot remove end iterator!");
@ -588,9 +567,9 @@ public:
return L;
}
/// changeLoopFor - Change the top-level loop that contains BB to the
/// specified loop. This should be used by transformations that restructure
/// the loop hierarchy tree.
/// Change the top-level loop that contains BB to the specified loop.
/// This should be used by transformations that restructure the loop hierarchy
/// tree.
void changeLoopFor(BlockT *BB, LoopT *L) {
if (!L) {
BBMap.erase(BB);
@ -599,8 +578,8 @@ public:
BBMap[BB] = L;
}
/// changeTopLevelLoop - Replace the specified loop in the top-level loops
/// list with the indicated loop.
/// Replace the specified loop in the top-level loops list with the indicated
/// loop.
void changeTopLevelLoop(LoopT *OldLoop,
LoopT *NewLoop) {
auto I = std::find(TopLevelLoops.begin(), TopLevelLoops.end(), OldLoop);
@ -610,14 +589,13 @@ public:
"Loops already embedded into a subloop!");
}
/// addTopLevelLoop - This adds the specified loop to the collection of
/// top-level loops.
/// This adds the specified loop to the collection of top-level loops.
void addTopLevelLoop(LoopT *New) {
assert(!New->getParentLoop() && "Loop already in subloop!");
TopLevelLoops.push_back(New);
}
/// removeBlock - This method completely removes BB from all data structures,
/// This method completely removes BB from all data structures,
/// including all of the Loop objects it is nested in and our mapping from
/// BasicBlocks to loops.
void removeBlock(BlockT *BB) {
@ -670,15 +648,14 @@ public:
// Most of the public interface is provided via LoopInfoBase.
/// updateUnloop - Update LoopInfo after removing the last backedge from a
/// loop--now the "unloop". This updates the loop forest and parent loops for
/// each block so that Unloop is no longer referenced, but does not actually
/// delete the Unloop object. Generally, the loop pass manager should manage
/// deleting the Unloop.
void updateUnloop(Loop *Unloop);
/// Update LoopInfo after removing the last backedge from a loop. This updates
/// the loop forest and parent loops for each block so that \c L is no longer
/// referenced, but does not actually delete \c L immediately. The pointer
/// will remain valid until this LoopInfo's memory is released.
void markAsRemoved(Loop *L);
/// replacementPreservesLCSSAForm - Returns true if replacing From with To
/// everywhere is guaranteed to preserve LCSSA form.
/// Returns true if replacing From with To everywhere is guaranteed to
/// preserve LCSSA form.
bool replacementPreservesLCSSAForm(Instruction *From, Value *To) {
// Preserving LCSSA form is only problematic if the replacing value is an
// instruction.
@ -698,8 +675,7 @@ public:
return ToLoop->contains(getLoopFor(From->getParent()));
}
/// \brief Checks if moving a specific instruction can break LCSSA in any
/// loop.
/// Checks if moving a specific instruction can break LCSSA in any loop.
///
/// Return true if moving \p Inst to before \p NewLoc will break LCSSA,
/// assuming that the function containing \p Inst and \p NewLoc is currently

View File

@ -259,7 +259,7 @@ public:
void EmitAlignment(unsigned NumBits, const GlobalObject *GO = nullptr) const;
/// Lower the specified LLVM Constant to an MCExpr.
const MCExpr *lowerConstant(const Constant *CV);
virtual const MCExpr *lowerConstant(const Constant *CV);
/// \brief Print a general LLVM constant to the .s file.
void EmitGlobalConstant(const DataLayout &DL, const Constant *CV);

View File

@ -29,6 +29,48 @@ class MCSymbol;
class raw_ostream;
class DwarfTypeUnit;
// AsmStreamerBase - A base abstract interface class defines methods that
// can be implemented to stream objects or can be implemented to
// calculate the size of the streamed objects.
// The derived classes will use an AsmPrinter to implement the methods.
//
// TODO: complete this interface and use it to merge EmitValue and SizeOf
// methods in the DIE classes below.
class AsmStreamerBase {
protected:
const AsmPrinter *AP;
AsmStreamerBase(const AsmPrinter *AP) : AP(AP) {}
public:
virtual ~AsmStreamerBase() {}
virtual unsigned emitULEB128(uint64_t Value, const char *Desc = nullptr,
unsigned PadTo = 0) = 0;
virtual unsigned emitInt8(unsigned char Value) = 0;
virtual unsigned emitBytes(StringRef Data) = 0;
};
/// EmittingAsmStreamer - Implements AbstractAsmStreamer to stream objects.
/// Notice that the return value is not the actual size of the streamed object.
/// For size calculation use SizeReporterAsmStreamer.
class EmittingAsmStreamer : public AsmStreamerBase {
public:
EmittingAsmStreamer(const AsmPrinter *AP) : AsmStreamerBase(AP) {}
unsigned emitULEB128(uint64_t Value, const char *Desc = nullptr,
unsigned PadTo = 0) override;
unsigned emitInt8(unsigned char Value) override;
unsigned emitBytes(StringRef Data) override;
};
/// SizeReporterAsmStreamer - Only reports the size of the streamed objects.
class SizeReporterAsmStreamer : public AsmStreamerBase {
public:
SizeReporterAsmStreamer(const AsmPrinter *AP) : AsmStreamerBase(AP) {}
unsigned emitULEB128(uint64_t Value, const char *Desc = nullptr,
unsigned PadTo = 0) override;
unsigned emitInt8(unsigned char Value) override;
unsigned emitBytes(StringRef Data) override;
};
//===--------------------------------------------------------------------===//
/// DIEAbbrevData - Dwarf abbreviation data, describes one attribute of a
/// Dwarf abbreviation.

View File

@ -848,9 +848,9 @@ namespace llvm {
public:
explicit ConnectedVNInfoEqClasses(LiveIntervals &lis) : LIS(lis) {}
/// Classify - Classify the values in LI into connected components.
/// Return the number of connected components.
unsigned Classify(const LiveInterval *LI);
/// Classify the values in \p LR into connected components.
/// Returns the number of connected components.
unsigned Classify(const LiveRange &LR);
/// getEqClass - Classify creates equivalence classes numbered 0..N. Return
/// the equivalence class assigned the VNI.

View File

@ -141,6 +141,28 @@ public:
LLVM_DUMP_METHOD void dump(const TargetRegisterInfo &TRI) const;
};
/// List of registers defined and used by a machine instruction.
class RegisterOperands {
public:
/// List of virtual regiserts and register units read by the instruction.
SmallVector<unsigned, 8> Uses;
/// \brief List of virtual registers and register units defined by the
/// instruction which are not dead.
SmallVector<unsigned, 8> Defs;
/// \brief List of virtual registers and register units defined by the
/// instruction but dead.
SmallVector<unsigned, 8> DeadDefs;
/// Analyze the given instruction \p MI and fill in the Uses, Defs and
/// DeadDefs list based on the MachineOperand flags.
void collect(const MachineInstr &MI, const TargetRegisterInfo &TRI,
const MachineRegisterInfo &MRI, bool IgnoreDead = false);
/// Use liveness information to find dead defs not marked with a dead flag
/// and move them to the DeadDefs vector.
void detectDeadDefs(const MachineInstr &MI, const LiveIntervals &LIS);
};
/// Array of PressureDiffs.
class PressureDiffs {
PressureDiff *PDiffArray;
@ -161,6 +183,10 @@ public:
const PressureDiff &operator[](unsigned Idx) const {
return const_cast<PressureDiffs*>(this)->operator[](Idx);
}
/// \brief Record pressure difference induced by the given operand list to
/// node with index \p Idx.
void addInstruction(unsigned Idx, const RegisterOperands &RegOpers,
const MachineRegisterInfo &MRI);
};
/// Store the effects of a change in pressure on things that MI scheduler cares
@ -329,8 +355,17 @@ public:
void setPos(MachineBasicBlock::const_iterator Pos) { CurrPos = Pos; }
/// Recede across the previous instruction.
void recede(SmallVectorImpl<unsigned> *LiveUses = nullptr,
PressureDiff *PDiff = nullptr);
void recede(SmallVectorImpl<unsigned> *LiveUses = nullptr);
/// Recede across the previous instruction.
/// This "low-level" variant assumes that recedeSkipDebugValues() was
/// called previously and takes precomputed RegisterOperands for the
/// instruction.
void recede(const RegisterOperands &RegOpers,
SmallVectorImpl<unsigned> *LiveUses = nullptr);
/// Recede until we find an instruction which is not a DebugValue.
void recedeSkipDebugValues();
/// Advance across the current instruction.
void advance();

View File

@ -93,8 +93,6 @@ struct WinEHFuncInfo {
DenseMap<const Instruction *, int> EHPadStateMap;
DenseMap<const FuncletPadInst *, int> FuncletBaseStateMap;
DenseMap<const InvokeInst *, int> InvokeStateMap;
DenseMap<const CatchReturnInst *, const BasicBlock *>
CatchRetSuccessorColorMap;
DenseMap<MCSymbol *, std::pair<int, MCSymbol *>> LabelToStateMap;
SmallVector<CxxUnwindMapEntry, 4> CxxUnwindMap;
SmallVector<WinEHTryBlockMapEntry, 4> TryBlockMap;
@ -125,8 +123,5 @@ void calculateSEHStateNumbers(const Function *ParentFn,
WinEHFuncInfo &FuncInfo);
void calculateClrEHStateNumbers(const Function *Fn, WinEHFuncInfo &FuncInfo);
void calculateCatchReturnSuccessorColors(const Function *Fn,
WinEHFuncInfo &FuncInfo);
}
#endif // LLVM_CODEGEN_WINEHFUNCINFO_H

View File

@ -28,13 +28,16 @@ class DIPrinter {
raw_ostream &OS;
bool PrintFunctionNames;
bool PrintPretty;
void printName(const DILineInfo &Info, bool Inlined);
int PrintSourceContext;
void print(const DILineInfo &Info, bool Inlined);
void printContext(std::string FileName, int64_t Line);
public:
DIPrinter(raw_ostream &OS, bool PrintFunctionNames = true,
bool PrintPretty = false)
bool PrintPretty = false, int PrintSourceContext = 0)
: OS(OS), PrintFunctionNames(PrintFunctionNames),
PrintPretty(PrintPretty) {}
PrintPretty(PrintPretty), PrintSourceContext(PrintSourceContext) {}
DIPrinter &operator<<(const DILineInfo &Info);
DIPrinter &operator<<(const DIInliningInfo &Info);

View File

@ -19,7 +19,6 @@
#include "LambdaResolver.h"
#include "LogicalDylib.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include <list>
#include <memory>
@ -61,31 +60,36 @@ private:
typedef typename BaseLayerT::ModuleSetHandleT BaseLayerModuleSetHandleT;
class ModuleOwner {
// Provide type-erasure for the Modules and MemoryManagers.
template <typename ResourceT>
class ResourceOwner {
public:
ModuleOwner() = default;
ModuleOwner(const ModuleOwner&) = delete;
ModuleOwner& operator=(const ModuleOwner&) = delete;
virtual ~ModuleOwner() { }
virtual Module& getModule() const = 0;
ResourceOwner() = default;
ResourceOwner(const ResourceOwner&) = delete;
ResourceOwner& operator=(const ResourceOwner&) = delete;
virtual ~ResourceOwner() { }
virtual ResourceT& getResource() const = 0;
};
template <typename ModulePtrT>
class ModuleOwnerImpl : public ModuleOwner {
template <typename ResourceT, typename ResourcePtrT>
class ResourceOwnerImpl : public ResourceOwner<ResourceT> {
public:
ModuleOwnerImpl(ModulePtrT ModulePtr) : ModulePtr(std::move(ModulePtr)) {}
Module& getModule() const override { return *ModulePtr; }
ResourceOwnerImpl(ResourcePtrT ResourcePtr)
: ResourcePtr(std::move(ResourcePtr)) {}
ResourceT& getResource() const override { return *ResourcePtr; }
private:
ModulePtrT ModulePtr;
ResourcePtrT ResourcePtr;
};
template <typename ModulePtrT>
std::unique_ptr<ModuleOwner> wrapOwnership(ModulePtrT ModulePtr) {
return llvm::make_unique<ModuleOwnerImpl<ModulePtrT>>(std::move(ModulePtr));
template <typename ResourceT, typename ResourcePtrT>
std::unique_ptr<ResourceOwner<ResourceT>>
wrapOwnership(ResourcePtrT ResourcePtr) {
typedef ResourceOwnerImpl<ResourceT, ResourcePtrT> RO;
return llvm::make_unique<RO>(std::move(ResourcePtr));
}
struct LogicalModuleResources {
std::unique_ptr<ModuleOwner> SourceModuleOwner;
std::unique_ptr<ResourceOwner<Module>> SourceModule;
std::set<const Function*> StubsToClone;
std::unique_ptr<IndirectStubsMgrT> StubsMgr;
@ -93,15 +97,16 @@ private:
// Explicit move constructor to make MSVC happy.
LogicalModuleResources(LogicalModuleResources &&Other)
: SourceModuleOwner(std::move(Other.SourceModuleOwner)),
: SourceModule(std::move(Other.SourceModule)),
StubsToClone(std::move(Other.StubsToClone)),
StubsMgr(std::move(Other.StubsMgr)) {}
// Explicit move assignment to make MSVC happy.
LogicalModuleResources& operator=(LogicalModuleResources &&Other) {
SourceModuleOwner = std::move(Other.SourceModuleOwner);
SourceModule = std::move(Other.SourceModule);
StubsToClone = std::move(Other.StubsToClone);
StubsMgr = std::move(Other.StubsMgr);
return *this;
}
JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
@ -114,12 +119,35 @@ private:
};
struct LogicalDylibResources {
typedef std::function<RuntimeDyld::SymbolInfo(const std::string&)>
SymbolResolverFtor;
typedef std::function<typename BaseLayerT::ModuleSetHandleT(
BaseLayerT&,
std::unique_ptr<Module>,
std::unique_ptr<RuntimeDyld::SymbolResolver>)>
ModuleAdderFtor;
LogicalDylibResources() = default;
// Explicit move constructor to make MSVC happy.
LogicalDylibResources(LogicalDylibResources &&Other)
: ExternalSymbolResolver(std::move(Other.ExternalSymbolResolver)),
MemMgr(std::move(Other.MemMgr)),
ModuleAdder(std::move(Other.ModuleAdder)) {}
// Explicit move assignment operator to make MSVC happy.
LogicalDylibResources& operator=(LogicalDylibResources &&Other) {
ExternalSymbolResolver = std::move(Other.ExternalSymbolResolver);
MemMgr = std::move(Other.MemMgr);
ModuleAdder = std::move(Other.ModuleAdder);
return *this;
}
SymbolResolverFtor ExternalSymbolResolver;
std::unique_ptr<ResourceOwner<RuntimeDyld::MemoryManager>> MemMgr;
ModuleAdderFtor ModuleAdder;
};
typedef LogicalDylib<BaseLayerT, LogicalModuleResources,
@ -157,9 +185,6 @@ public:
MemoryManagerPtrT MemMgr,
SymbolResolverPtrT Resolver) {
assert(MemMgr == nullptr &&
"User supplied memory managers not supported with COD yet.");
LogicalDylibs.push_back(CODLogicalDylib(BaseLayer));
auto &LDResources = LogicalDylibs.back().getDylibResources();
@ -168,6 +193,18 @@ public:
return Resolver->findSymbol(Name);
};
auto &MemMgrRef = *MemMgr;
LDResources.MemMgr =
wrapOwnership<RuntimeDyld::MemoryManager>(std::move(MemMgr));
LDResources.ModuleAdder =
[&MemMgrRef](BaseLayerT &B, std::unique_ptr<Module> M,
std::unique_ptr<RuntimeDyld::SymbolResolver> R) {
std::vector<std::unique_ptr<Module>> Ms;
Ms.push_back(std::move(M));
return B.addModuleSet(std::move(Ms), &MemMgrRef, std::move(R));
};
// Process each of the modules in this module set.
for (auto &M : Ms)
addLogicalModule(LogicalDylibs.back(), std::move(M));
@ -215,9 +252,9 @@ private:
auto LMH = LD.createLogicalModule();
auto &LMResources = LD.getLogicalModuleResources(LMH);
LMResources.SourceModuleOwner = wrapOwnership(std::move(SrcMPtr));
LMResources.SourceModule = wrapOwnership<Module>(std::move(SrcMPtr));
Module &SrcM = LMResources.SourceModuleOwner->getModule();
Module &SrcM = LMResources.SourceModule->getResource();
// Create the GlobalValues module.
const DataLayout &DL = SrcM.getDataLayout();
@ -326,12 +363,9 @@ private:
return RuntimeDyld::SymbolInfo(nullptr);
});
std::vector<std::unique_ptr<Module>> GVsMSet;
GVsMSet.push_back(std::move(GVsM));
auto GVsH =
BaseLayer.addModuleSet(std::move(GVsMSet),
llvm::make_unique<SectionMemoryManager>(),
std::move(GVsResolver));
LD.getDylibResources().ModuleAdder(BaseLayer, std::move(GVsM),
std::move(GVsResolver));
LD.addToLogicalModule(LMH, GVsH);
}
@ -348,7 +382,7 @@ private:
LogicalModuleHandle LMH,
Function &F) {
auto &LMResources = LD.getLogicalModuleResources(LMH);
Module &SrcM = LMResources.SourceModuleOwner->getModule();
Module &SrcM = LMResources.SourceModule->getResource();
// If F is a declaration we must already have compiled it.
if (F.isDeclaration())
@ -386,7 +420,7 @@ private:
LogicalModuleHandle LMH,
const PartitionT &Part) {
auto &LMResources = LD.getLogicalModuleResources(LMH);
Module &SrcM = LMResources.SourceModuleOwner->getModule();
Module &SrcM = LMResources.SourceModule->getResource();
// Create the module.
std::string NewName = SrcM.getName();
@ -445,7 +479,6 @@ private:
moveFunctionBody(*F, VMap, &Materializer);
// Create memory manager and symbol resolver.
auto MemMgr = llvm::make_unique<SectionMemoryManager>();
auto Resolver = createLambdaResolver(
[this, &LD, LMH](const std::string &Name) {
if (auto Symbol = LD.findSymbolInternally(LMH, Name))
@ -459,10 +492,9 @@ private:
Symbol.getFlags());
return RuntimeDyld::SymbolInfo(nullptr);
});
std::vector<std::unique_ptr<Module>> PartMSet;
PartMSet.push_back(std::move(M));
return BaseLayer.addModuleSet(std::move(PartMSet), std::move(MemMgr),
std::move(Resolver));
return LD.getDylibResources().ModuleAdder(BaseLayer, std::move(M),
std::move(Resolver));
}
BaseLayerT &BaseLayer;

View File

@ -22,6 +22,7 @@
#include "llvm/IR/Mangler.h"
#include "llvm/IR/Module.h"
#include "llvm/Transforms/Utils/ValueMapper.h"
#include "llvm/Support/Process.h"
#include <sstream>
namespace llvm {
@ -179,14 +180,15 @@ private:
std::error_code EC;
auto TrampolineBlock =
sys::OwningMemoryBlock(
sys::Memory::allocateMappedMemory(TargetT::PageSize, nullptr,
sys::Memory::allocateMappedMemory(sys::Process::getPageSize(), nullptr,
sys::Memory::MF_READ |
sys::Memory::MF_WRITE, EC));
assert(!EC && "Failed to allocate trampoline block");
unsigned NumTrampolines =
(TargetT::PageSize - TargetT::PointerSize) / TargetT::TrampolineSize;
(sys::Process::getPageSize() - TargetT::PointerSize) /
TargetT::TrampolineSize;
uint8_t *TrampolineMem = static_cast<uint8_t*>(TrampolineBlock.base());
TargetT::writeTrampolines(TrampolineMem, ResolverBlock.base(),
@ -240,8 +242,8 @@ private:
virtual void anchor();
};
/// @brief IndirectStubsManager implementation for a concrete target, e.g.
/// OrcX86_64. (See OrcTargetSupport.h).
/// @brief IndirectStubsManager implementation for the host architecture, e.g.
/// OrcX86_64. (See OrcArchitectureSupport.h).
template <typename TargetT>
class LocalIndirectStubsManager : public IndirectStubsManager {
public:

View File

@ -108,9 +108,7 @@ private:
void Finalize() override {
State = Finalizing;
RTDyld->resolveRelocations();
RTDyld->registerEHFrames();
MemMgr->finalizeMemory();
RTDyld->finalizeWithMemoryManagerLocking();
State = Finalized;
}

View File

@ -1,4 +1,4 @@
//===-- OrcTargetSupport.h - Code to support specific targets --*- C++ -*-===//
//===-- OrcArchitectureSupport.h - Architecture support code ---*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@ -7,32 +7,76 @@
//
//===----------------------------------------------------------------------===//
//
// Target specific code for Orc, e.g. callback assembly.
// Architecture specific code for Orc, e.g. callback assembly.
//
// Target classes should be part of the JIT *target* process, not the host
// Architecture classes should be part of the JIT *target* process, not the host
// process (except where you're doing hosted JITing and the two are one and the
// same).
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_EXECUTIONENGINE_ORC_ORCTARGETSUPPORT_H
#define LLVM_EXECUTIONENGINE_ORC_ORCTARGETSUPPORT_H
#ifndef LLVM_EXECUTIONENGINE_ORC_ORCARCHITECTURESUPPORT_H
#define LLVM_EXECUTIONENGINE_ORC_ORCARCHITECTURESUPPORT_H
#include "IndirectionUtils.h"
#include "llvm/Support/Memory.h"
#include "llvm/Support/Process.h"
namespace llvm {
namespace orc {
/// Generic ORC Architecture support.
///
/// This class can be substituted as the target architecure support class for
/// ORC templates that require one (e.g. IndirectStubsManagers). It does not
/// support lazy JITing however, and any attempt to use that functionality
/// will result in execution of an llvm_unreachable.
class OrcGenericArchitecture {
public:
static const unsigned PointerSize = sizeof(uintptr_t);
static const unsigned TrampolineSize = 1;
static const unsigned ResolverCodeSize = 1;
typedef TargetAddress (*JITReentryFn)(void *CallbackMgr, void *TrampolineId);
static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,
void *CallbackMgr) {
llvm_unreachable("writeResolverCode is not supported by the generic host "
"support class");
}
static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,
unsigned NumTrampolines) {
llvm_unreachable("writeTrampolines is not supported by the generic host "
"support class");
}
class IndirectStubsInfo {
public:
const static unsigned StubSize = 1;
unsigned getNumStubs() const { llvm_unreachable("Not supported"); }
void *getStub(unsigned Idx) const { llvm_unreachable("Not supported"); }
void **getPtr(unsigned Idx) const { llvm_unreachable("Not supported"); }
};
static std::error_code emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
unsigned MinStubs,
void *InitialPtrVal) {
llvm_unreachable("emitIndirectStubsBlock is not supported by the generic "
"host support class");
}
};
/// @brief X86_64 support.
///
/// X86_64 supports lazy JITing.
class OrcX86_64 {
public:
static const unsigned PageSize = 4096;
static const unsigned PointerSize = 8;
static const unsigned TrampolineSize = 8;
static const unsigned ResolverCodeSize = 0x78;
typedef TargetAddress (*JITReentryFn)(void *CallbackMgr,
void *TrampolineId);
typedef TargetAddress (*JITReentryFn)(void *CallbackMgr, void *TrampolineId);
/// @brief Write the resolver code into the given memory. The user is be
/// responsible for allocating the memory and setting permissions.
@ -49,16 +93,16 @@ public:
/// makeIndirectStubsBlock function.
class IndirectStubsInfo {
friend class OrcX86_64;
public:
const static unsigned StubSize = 8;
const static unsigned PtrSize = 8;
IndirectStubsInfo() : NumStubs(0) {}
IndirectStubsInfo(IndirectStubsInfo &&Other)
: NumStubs(Other.NumStubs), StubsMem(std::move(Other.StubsMem)) {
Other.NumStubs = 0;
}
IndirectStubsInfo& operator=(IndirectStubsInfo &&Other) {
IndirectStubsInfo &operator=(IndirectStubsInfo &&Other) {
NumStubs = Other.NumStubs;
Other.NumStubs = 0;
StubsMem = std::move(Other.StubsMem);
@ -70,17 +114,18 @@ public:
/// @brief Get a pointer to the stub at the given index, which must be in
/// the range 0 .. getNumStubs() - 1.
void* getStub(unsigned Idx) const {
return static_cast<uint64_t*>(StubsMem.base()) + Idx;
void *getStub(unsigned Idx) const {
return static_cast<uint64_t *>(StubsMem.base()) + Idx;
}
/// @brief Get a pointer to the implementation-pointer at the given index,
/// which must be in the range 0 .. getNumStubs() - 1.
void** getPtr(unsigned Idx) const {
void **getPtr(unsigned Idx) const {
char *PtrsBase =
static_cast<char*>(StubsMem.base()) + NumStubs * StubSize;
return reinterpret_cast<void**>(PtrsBase) + Idx;
static_cast<char *>(StubsMem.base()) + NumStubs * StubSize;
return reinterpret_cast<void **>(PtrsBase) + Idx;
}
private:
unsigned NumStubs;
sys::OwningMemoryBlock StubsMem;
@ -100,4 +145,4 @@ public:
} // End namespace orc.
} // End namespace llvm.
#endif // LLVM_EXECUTIONENGINE_ORC_ORCTARGETSUPPORT_H
#endif // LLVM_EXECUTIONENGINE_ORC_ORCARCHITECTURESUPPORT_H

View File

@ -0,0 +1,37 @@
//===------ OrcError.h - Reject symbol lookup requests ------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Define an error category, error codes, and helper utilities for Orc.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_EXECUTIONENGINE_ORC_ORCERROR_H
#define LLVM_EXECUTIONENGINE_ORC_ORCERROR_H
#include <system_error>
namespace llvm {
namespace orc {
enum class OrcErrorCode : int {
// RPC Errors
RemoteAllocatorDoesNotExist = 1,
RemoteAllocatorIdAlreadyInUse,
RemoteMProtectAddrUnrecognized,
RemoteIndirectStubsOwnerDoesNotExist,
RemoteIndirectStubsOwnerIdAlreadyInUse,
UnexpectedRPCCall
};
std::error_code orcError(OrcErrorCode ErrCode);
} // End namespace orc.
} // End namespace llvm.
#endif // LLVM_EXECUTIONENGINE_ORC_ORCERROR_H

View File

@ -0,0 +1,784 @@
//===---- OrcRemoteTargetClient.h - Orc Remote-target Client ----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the OrcRemoteTargetClient class and helpers. This class
// can be used to communicate over an RPCChannel with an OrcRemoteTargetServer
// instance to support remote-JITing.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H
#define LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H
#include "IndirectionUtils.h"
#include "OrcRemoteTargetRPCAPI.h"
#include <system_error>
#define DEBUG_TYPE "orc-remote"
namespace llvm {
namespace orc {
namespace remote {
/// This class provides utilities (including memory manager, indirect stubs
/// manager, and compile callback manager types) that support remote JITing
/// in ORC.
///
/// Each of the utility classes talks to a JIT server (an instance of the
/// OrcRemoteTargetServer class) via an RPC system (see RPCUtils.h) to carry out
/// its actions.
template <typename ChannelT>
class OrcRemoteTargetClient : public OrcRemoteTargetRPCAPI {
public:
/// Remote memory manager.
class RCMemoryManager : public RuntimeDyld::MemoryManager {
public:
RCMemoryManager(OrcRemoteTargetClient &Client, ResourceIdMgr::ResourceId Id)
: Client(Client), Id(Id) {
DEBUG(dbgs() << "Created remote allocator " << Id << "\n");
}
RCMemoryManager(RCMemoryManager &&Other)
: Client(std::move(Other.Client)), Id(std::move(Other.Id)),
Unmapped(std::move(Other.Unmapped)),
Unfinalized(std::move(Other.Unfinalized)) {}
RCMemoryManager operator=(RCMemoryManager &&Other) {
Client = std::move(Other.Client);
Id = std::move(Other.Id);
Unmapped = std::move(Other.Unmapped);
Unfinalized = std::move(Other.Unfinalized);
return *this;
}
~RCMemoryManager() {
Client.destroyRemoteAllocator(Id);
DEBUG(dbgs() << "Destroyed remote allocator " << Id << "\n");
}
uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
unsigned SectionID,
StringRef SectionName) override {
Unmapped.back().CodeAllocs.emplace_back(Size, Alignment);
uint8_t *Alloc = reinterpret_cast<uint8_t *>(
Unmapped.back().CodeAllocs.back().getLocalAddress());
DEBUG(dbgs() << "Allocator " << Id << " allocated code for "
<< SectionName << ": " << Alloc << " (" << Size
<< " bytes, alignment " << Alignment << ")\n");
return Alloc;
}
uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
unsigned SectionID, StringRef SectionName,
bool IsReadOnly) override {
if (IsReadOnly) {
Unmapped.back().RODataAllocs.emplace_back(Size, Alignment);
uint8_t *Alloc = reinterpret_cast<uint8_t *>(
Unmapped.back().RODataAllocs.back().getLocalAddress());
DEBUG(dbgs() << "Allocator " << Id << " allocated ro-data for "
<< SectionName << ": " << Alloc << " (" << Size
<< " bytes, alignment " << Alignment << ")\n");
return Alloc;
} // else...
Unmapped.back().RWDataAllocs.emplace_back(Size, Alignment);
uint8_t *Alloc = reinterpret_cast<uint8_t *>(
Unmapped.back().RWDataAllocs.back().getLocalAddress());
DEBUG(dbgs() << "Allocator " << Id << " allocated rw-data for "
<< SectionName << ": " << Alloc << " (" << Size
<< " bytes, alignment " << Alignment << ")\n");
return Alloc;
}
void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign,
uintptr_t RODataSize, uint32_t RODataAlign,
uintptr_t RWDataSize,
uint32_t RWDataAlign) override {
Unmapped.push_back(ObjectAllocs());
DEBUG(dbgs() << "Allocator " << Id << " reserved:\n");
if (CodeSize != 0) {
std::error_code EC = Client.reserveMem(Unmapped.back().RemoteCodeAddr,
Id, CodeSize, CodeAlign);
// FIXME; Add error to poll.
assert(!EC && "Failed reserving remote memory.");
(void)EC;
DEBUG(dbgs() << " code: "
<< format("0x%016x", Unmapped.back().RemoteCodeAddr)
<< " (" << CodeSize << " bytes, alignment " << CodeAlign
<< ")\n");
}
if (RODataSize != 0) {
std::error_code EC = Client.reserveMem(Unmapped.back().RemoteRODataAddr,
Id, RODataSize, RODataAlign);
// FIXME; Add error to poll.
assert(!EC && "Failed reserving remote memory.");
(void)EC;
DEBUG(dbgs() << " ro-data: "
<< format("0x%016x", Unmapped.back().RemoteRODataAddr)
<< " (" << RODataSize << " bytes, alignment "
<< RODataAlign << ")\n");
}
if (RWDataSize != 0) {
std::error_code EC = Client.reserveMem(Unmapped.back().RemoteRWDataAddr,
Id, RWDataSize, RWDataAlign);
// FIXME; Add error to poll.
assert(!EC && "Failed reserving remote memory.");
(void)EC;
DEBUG(dbgs() << " rw-data: "
<< format("0x%016x", Unmapped.back().RemoteRWDataAddr)
<< " (" << RWDataSize << " bytes, alignment "
<< RWDataAlign << ")\n");
}
}
bool needsToReserveAllocationSpace() override { return true; }
void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr,
size_t Size) override {}
void deregisterEHFrames(uint8_t *addr, uint64_t LoadAddr,
size_t Size) override {}
void notifyObjectLoaded(RuntimeDyld &Dyld,
const object::ObjectFile &Obj) override {
DEBUG(dbgs() << "Allocator " << Id << " applied mappings:\n");
for (auto &ObjAllocs : Unmapped) {
{
TargetAddress NextCodeAddr = ObjAllocs.RemoteCodeAddr;
for (auto &Alloc : ObjAllocs.CodeAllocs) {
NextCodeAddr = RoundUpToAlignment(NextCodeAddr, Alloc.getAlign());
Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextCodeAddr);
DEBUG(dbgs() << " code: "
<< static_cast<void *>(Alloc.getLocalAddress())
<< " -> " << format("0x%016x", NextCodeAddr) << "\n");
Alloc.setRemoteAddress(NextCodeAddr);
NextCodeAddr += Alloc.getSize();
}
}
{
TargetAddress NextRODataAddr = ObjAllocs.RemoteRODataAddr;
for (auto &Alloc : ObjAllocs.RODataAllocs) {
NextRODataAddr =
RoundUpToAlignment(NextRODataAddr, Alloc.getAlign());
Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextRODataAddr);
DEBUG(dbgs() << " ro-data: "
<< static_cast<void *>(Alloc.getLocalAddress())
<< " -> " << format("0x%016x", NextRODataAddr)
<< "\n");
Alloc.setRemoteAddress(NextRODataAddr);
NextRODataAddr += Alloc.getSize();
}
}
{
TargetAddress NextRWDataAddr = ObjAllocs.RemoteRWDataAddr;
for (auto &Alloc : ObjAllocs.RWDataAllocs) {
NextRWDataAddr =
RoundUpToAlignment(NextRWDataAddr, Alloc.getAlign());
Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextRWDataAddr);
DEBUG(dbgs() << " rw-data: "
<< static_cast<void *>(Alloc.getLocalAddress())
<< " -> " << format("0x%016x", NextRWDataAddr)
<< "\n");
Alloc.setRemoteAddress(NextRWDataAddr);
NextRWDataAddr += Alloc.getSize();
}
}
Unfinalized.push_back(std::move(ObjAllocs));
}
Unmapped.clear();
}
bool finalizeMemory(std::string *ErrMsg = nullptr) override {
DEBUG(dbgs() << "Allocator " << Id << " finalizing:\n");
for (auto &ObjAllocs : Unfinalized) {
for (auto &Alloc : ObjAllocs.CodeAllocs) {
DEBUG(dbgs() << " copying code: "
<< static_cast<void *>(Alloc.getLocalAddress()) << " -> "
<< format("0x%016x", Alloc.getRemoteAddress()) << " ("
<< Alloc.getSize() << " bytes)\n");
Client.writeMem(Alloc.getRemoteAddress(), Alloc.getLocalAddress(),
Alloc.getSize());
}
if (ObjAllocs.RemoteCodeAddr) {
DEBUG(dbgs() << " setting R-X permissions on code block: "
<< format("0x%016x", ObjAllocs.RemoteCodeAddr) << "\n");
Client.setProtections(Id, ObjAllocs.RemoteCodeAddr,
sys::Memory::MF_READ | sys::Memory::MF_EXEC);
}
for (auto &Alloc : ObjAllocs.RODataAllocs) {
DEBUG(dbgs() << " copying ro-data: "
<< static_cast<void *>(Alloc.getLocalAddress()) << " -> "
<< format("0x%016x", Alloc.getRemoteAddress()) << " ("
<< Alloc.getSize() << " bytes)\n");
Client.writeMem(Alloc.getRemoteAddress(), Alloc.getLocalAddress(),
Alloc.getSize());
}
if (ObjAllocs.RemoteRODataAddr) {
DEBUG(dbgs() << " setting R-- permissions on ro-data block: "
<< format("0x%016x", ObjAllocs.RemoteRODataAddr)
<< "\n");
Client.setProtections(Id, ObjAllocs.RemoteRODataAddr,
sys::Memory::MF_READ);
}
for (auto &Alloc : ObjAllocs.RWDataAllocs) {
DEBUG(dbgs() << " copying rw-data: "
<< static_cast<void *>(Alloc.getLocalAddress()) << " -> "
<< format("0x%016x", Alloc.getRemoteAddress()) << " ("
<< Alloc.getSize() << " bytes)\n");
Client.writeMem(Alloc.getRemoteAddress(), Alloc.getLocalAddress(),
Alloc.getSize());
}
if (ObjAllocs.RemoteRWDataAddr) {
DEBUG(dbgs() << " setting RW- permissions on rw-data block: "
<< format("0x%016x", ObjAllocs.RemoteRWDataAddr)
<< "\n");
Client.setProtections(Id, ObjAllocs.RemoteRWDataAddr,
sys::Memory::MF_READ | sys::Memory::MF_WRITE);
}
}
Unfinalized.clear();
return false;
}
private:
class Alloc {
public:
Alloc(uint64_t Size, unsigned Align)
: Size(Size), Align(Align), Contents(new char[Size + Align - 1]),
RemoteAddr(0) {}
Alloc(Alloc &&Other)
: Size(std::move(Other.Size)), Align(std::move(Other.Align)),
Contents(std::move(Other.Contents)),
RemoteAddr(std::move(Other.RemoteAddr)) {}
Alloc &operator=(Alloc &&Other) {
Size = std::move(Other.Size);
Align = std::move(Other.Align);
Contents = std::move(Other.Contents);
RemoteAddr = std::move(Other.RemoteAddr);
return *this;
}
uint64_t getSize() const { return Size; }
unsigned getAlign() const { return Align; }
char *getLocalAddress() const {
uintptr_t LocalAddr = reinterpret_cast<uintptr_t>(Contents.get());
LocalAddr = RoundUpToAlignment(LocalAddr, Align);
return reinterpret_cast<char *>(LocalAddr);
}
void setRemoteAddress(TargetAddress RemoteAddr) {
this->RemoteAddr = RemoteAddr;
}
TargetAddress getRemoteAddress() const { return RemoteAddr; }
private:
uint64_t Size;
unsigned Align;
std::unique_ptr<char[]> Contents;
TargetAddress RemoteAddr;
};
struct ObjectAllocs {
ObjectAllocs()
: RemoteCodeAddr(0), RemoteRODataAddr(0), RemoteRWDataAddr(0) {}
ObjectAllocs(ObjectAllocs &&Other)
: RemoteCodeAddr(std::move(Other.RemoteCodeAddr)),
RemoteRODataAddr(std::move(Other.RemoteRODataAddr)),
RemoteRWDataAddr(std::move(Other.RemoteRWDataAddr)),
CodeAllocs(std::move(Other.CodeAllocs)),
RODataAllocs(std::move(Other.RODataAllocs)),
RWDataAllocs(std::move(Other.RWDataAllocs)) {}
ObjectAllocs &operator=(ObjectAllocs &&Other) {
RemoteCodeAddr = std::move(Other.RemoteCodeAddr);
RemoteRODataAddr = std::move(Other.RemoteRODataAddr);
RemoteRWDataAddr = std::move(Other.RemoteRWDataAddr);
CodeAllocs = std::move(Other.CodeAllocs);
RODataAllocs = std::move(Other.RODataAllocs);
RWDataAllocs = std::move(Other.RWDataAllocs);
return *this;
}
TargetAddress RemoteCodeAddr;
TargetAddress RemoteRODataAddr;
TargetAddress RemoteRWDataAddr;
std::vector<Alloc> CodeAllocs, RODataAllocs, RWDataAllocs;
};
OrcRemoteTargetClient &Client;
ResourceIdMgr::ResourceId Id;
std::vector<ObjectAllocs> Unmapped;
std::vector<ObjectAllocs> Unfinalized;
};
/// Remote indirect stubs manager.
class RCIndirectStubsManager : public IndirectStubsManager {
public:
RCIndirectStubsManager(OrcRemoteTargetClient &Remote,
ResourceIdMgr::ResourceId Id)
: Remote(Remote), Id(Id) {}
~RCIndirectStubsManager() { Remote.destroyIndirectStubsManager(Id); }
std::error_code createStub(StringRef StubName, TargetAddress StubAddr,
JITSymbolFlags StubFlags) override {
if (auto EC = reserveStubs(1))
return EC;
return createStubInternal(StubName, StubAddr, StubFlags);
}
std::error_code createStubs(const StubInitsMap &StubInits) override {
if (auto EC = reserveStubs(StubInits.size()))
return EC;
for (auto &Entry : StubInits)
if (auto EC = createStubInternal(Entry.first(), Entry.second.first,
Entry.second.second))
return EC;
return std::error_code();
}
JITSymbol findStub(StringRef Name, bool ExportedStubsOnly) override {
auto I = StubIndexes.find(Name);
if (I == StubIndexes.end())
return nullptr;
auto Key = I->second.first;
auto Flags = I->second.second;
auto StubSymbol = JITSymbol(getStubAddr(Key), Flags);
if (ExportedStubsOnly && !StubSymbol.isExported())
return nullptr;
return StubSymbol;
}
JITSymbol findPointer(StringRef Name) override {
auto I = StubIndexes.find(Name);
if (I == StubIndexes.end())
return nullptr;
auto Key = I->second.first;
auto Flags = I->second.second;
return JITSymbol(getPtrAddr(Key), Flags);
}
std::error_code updatePointer(StringRef Name,
TargetAddress NewAddr) override {
auto I = StubIndexes.find(Name);
assert(I != StubIndexes.end() && "No stub pointer for symbol");
auto Key = I->second.first;
return Remote.writePointer(getPtrAddr(Key), NewAddr);
}
private:
struct RemoteIndirectStubsInfo {
RemoteIndirectStubsInfo(TargetAddress StubBase, TargetAddress PtrBase,
unsigned NumStubs)
: StubBase(StubBase), PtrBase(PtrBase), NumStubs(NumStubs) {}
TargetAddress StubBase;
TargetAddress PtrBase;
unsigned NumStubs;
};
OrcRemoteTargetClient &Remote;
ResourceIdMgr::ResourceId Id;
std::vector<RemoteIndirectStubsInfo> RemoteIndirectStubsInfos;
typedef std::pair<uint16_t, uint16_t> StubKey;
std::vector<StubKey> FreeStubs;
StringMap<std::pair<StubKey, JITSymbolFlags>> StubIndexes;
std::error_code reserveStubs(unsigned NumStubs) {
if (NumStubs <= FreeStubs.size())
return std::error_code();
unsigned NewStubsRequired = NumStubs - FreeStubs.size();
TargetAddress StubBase;
TargetAddress PtrBase;
unsigned NumStubsEmitted;
Remote.emitIndirectStubs(StubBase, PtrBase, NumStubsEmitted, Id,
NewStubsRequired);
unsigned NewBlockId = RemoteIndirectStubsInfos.size();
RemoteIndirectStubsInfos.push_back(
RemoteIndirectStubsInfo(StubBase, PtrBase, NumStubsEmitted));
for (unsigned I = 0; I < NumStubsEmitted; ++I)
FreeStubs.push_back(std::make_pair(NewBlockId, I));
return std::error_code();
}
std::error_code createStubInternal(StringRef StubName,
TargetAddress InitAddr,
JITSymbolFlags StubFlags) {
auto Key = FreeStubs.back();
FreeStubs.pop_back();
StubIndexes[StubName] = std::make_pair(Key, StubFlags);
return Remote.writePointer(getPtrAddr(Key), InitAddr);
}
TargetAddress getStubAddr(StubKey K) {
assert(RemoteIndirectStubsInfos[K.first].StubBase != 0 &&
"Missing stub address");
return RemoteIndirectStubsInfos[K.first].StubBase +
K.second * Remote.getIndirectStubSize();
}
TargetAddress getPtrAddr(StubKey K) {
assert(RemoteIndirectStubsInfos[K.first].PtrBase != 0 &&
"Missing pointer address");
return RemoteIndirectStubsInfos[K.first].PtrBase +
K.second * Remote.getPointerSize();
}
};
/// Remote compile callback manager.
class RCCompileCallbackManager : public JITCompileCallbackManager {
public:
RCCompileCallbackManager(TargetAddress ErrorHandlerAddress,
OrcRemoteTargetClient &Remote)
: JITCompileCallbackManager(ErrorHandlerAddress), Remote(Remote) {
assert(!Remote.CompileCallback && "Compile callback already set");
Remote.CompileCallback = [this](TargetAddress TrampolineAddr) {
return executeCompileCallback(TrampolineAddr);
};
Remote.emitResolverBlock();
}
private:
void grow() {
TargetAddress BlockAddr = 0;
uint32_t NumTrampolines = 0;
auto EC = Remote.emitTrampolineBlock(BlockAddr, NumTrampolines);
assert(!EC && "Failed to create trampolines");
uint32_t TrampolineSize = Remote.getTrampolineSize();
for (unsigned I = 0; I < NumTrampolines; ++I)
this->AvailableTrampolines.push_back(BlockAddr + (I * TrampolineSize));
}
OrcRemoteTargetClient &Remote;
};
/// Create an OrcRemoteTargetClient.
/// Channel is the ChannelT instance to communicate on. It is assumed that
/// the channel is ready to be read from and written to.
static ErrorOr<OrcRemoteTargetClient> Create(ChannelT &Channel) {
std::error_code EC;
OrcRemoteTargetClient H(Channel, EC);
if (EC)
return EC;
return H;
}
/// Call the int(void) function at the given address in the target and return
/// its result.
std::error_code callIntVoid(int &Result, TargetAddress Addr) {
DEBUG(dbgs() << "Calling int(*)(void) " << format("0x%016x", Addr) << "\n");
if (auto EC = call<CallIntVoid>(Channel, Addr))
return EC;
unsigned NextProcId;
if (auto EC = listenForCompileRequests(NextProcId))
return EC;
if (NextProcId != CallIntVoidResponseId)
return orcError(OrcErrorCode::UnexpectedRPCCall);
return handle<CallIntVoidResponse>(Channel, [&](int R) {
Result = R;
DEBUG(dbgs() << "Result: " << R << "\n");
return std::error_code();
});
}
/// Call the int(int, char*[]) function at the given address in the target and
/// return its result.
std::error_code callMain(int &Result, TargetAddress Addr,
const std::vector<std::string> &Args) {
DEBUG(dbgs() << "Calling int(*)(int, char*[]) " << format("0x%016x", Addr)
<< "\n");
if (auto EC = call<CallMain>(Channel, Addr, Args))
return EC;
unsigned NextProcId;
if (auto EC = listenForCompileRequests(NextProcId))
return EC;
if (NextProcId != CallMainResponseId)
return orcError(OrcErrorCode::UnexpectedRPCCall);
return handle<CallMainResponse>(Channel, [&](int R) {
Result = R;
DEBUG(dbgs() << "Result: " << R << "\n");
return std::error_code();
});
}
/// Call the void() function at the given address in the target and wait for
/// it to finish.
std::error_code callVoidVoid(TargetAddress Addr) {
DEBUG(dbgs() << "Calling void(*)(void) " << format("0x%016x", Addr)
<< "\n");
if (auto EC = call<CallVoidVoid>(Channel, Addr))
return EC;
unsigned NextProcId;
if (auto EC = listenForCompileRequests(NextProcId))
return EC;
if (NextProcId != CallVoidVoidResponseId)
return orcError(OrcErrorCode::UnexpectedRPCCall);
return handle<CallVoidVoidResponse>(Channel, doNothing);
}
/// Create an RCMemoryManager which will allocate its memory on the remote
/// target.
std::error_code
createRemoteMemoryManager(std::unique_ptr<RCMemoryManager> &MM) {
assert(!MM && "MemoryManager should be null before creation.");
auto Id = AllocatorIds.getNext();
if (auto EC = call<CreateRemoteAllocator>(Channel, Id))
return EC;
MM = llvm::make_unique<RCMemoryManager>(*this, Id);
return std::error_code();
}
/// Create an RCIndirectStubsManager that will allocate stubs on the remote
/// target.
std::error_code
createIndirectStubsManager(std::unique_ptr<RCIndirectStubsManager> &I) {
assert(!I && "Indirect stubs manager should be null before creation.");
auto Id = IndirectStubOwnerIds.getNext();
if (auto EC = call<CreateIndirectStubsOwner>(Channel, Id))
return EC;
I = llvm::make_unique<RCIndirectStubsManager>(*this, Id);
return std::error_code();
}
/// Search for symbols in the remote process. Note: This should be used by
/// symbol resolvers *after* they've searched the local symbol table in the
/// JIT stack.
std::error_code getSymbolAddress(TargetAddress &Addr, StringRef Name) {
// Check for an 'out-of-band' error, e.g. from an MM destructor.
if (ExistingError)
return ExistingError;
// Request remote symbol address.
if (auto EC = call<GetSymbolAddress>(Channel, Name))
return EC;
return expect<GetSymbolAddressResponse>(Channel, [&](TargetAddress &A) {
Addr = A;
DEBUG(dbgs() << "Remote address lookup " << Name << " = "
<< format("0x%016x", Addr) << "\n");
return std::error_code();
});
}
/// Get the triple for the remote target.
const std::string &getTargetTriple() const { return RemoteTargetTriple; }
std::error_code terminateSession() { return call<TerminateSession>(Channel); }
private:
OrcRemoteTargetClient(ChannelT &Channel, std::error_code &EC)
: Channel(Channel), RemotePointerSize(0), RemotePageSize(0),
RemoteTrampolineSize(0), RemoteIndirectStubSize(0) {
if ((EC = call<GetRemoteInfo>(Channel)))
return;
EC = expect<GetRemoteInfoResponse>(
Channel, readArgs(RemoteTargetTriple, RemotePointerSize, RemotePageSize,
RemoteTrampolineSize, RemoteIndirectStubSize));
}
void destroyRemoteAllocator(ResourceIdMgr::ResourceId Id) {
if (auto EC = call<DestroyRemoteAllocator>(Channel, Id)) {
// FIXME: This will be triggered by a removeModuleSet call: Propagate
// error return up through that.
llvm_unreachable("Failed to destroy remote allocator.");
AllocatorIds.release(Id);
}
}
std::error_code destroyIndirectStubsManager(ResourceIdMgr::ResourceId Id) {
IndirectStubOwnerIds.release(Id);
return call<DestroyIndirectStubsOwner>(Channel, Id);
}
std::error_code emitIndirectStubs(TargetAddress &StubBase,
TargetAddress &PtrBase,
uint32_t &NumStubsEmitted,
ResourceIdMgr::ResourceId Id,
uint32_t NumStubsRequired) {
if (auto EC = call<EmitIndirectStubs>(Channel, Id, NumStubsRequired))
return EC;
return expect<EmitIndirectStubsResponse>(
Channel, readArgs(StubBase, PtrBase, NumStubsEmitted));
}
std::error_code emitResolverBlock() {
// Check for an 'out-of-band' error, e.g. from an MM destructor.
if (ExistingError)
return ExistingError;
return call<EmitResolverBlock>(Channel);
}
std::error_code emitTrampolineBlock(TargetAddress &BlockAddr,
uint32_t &NumTrampolines) {
// Check for an 'out-of-band' error, e.g. from an MM destructor.
if (ExistingError)
return ExistingError;
if (auto EC = call<EmitTrampolineBlock>(Channel))
return EC;
return expect<EmitTrampolineBlockResponse>(
Channel, [&](TargetAddress BAddr, uint32_t NTrampolines) {
BlockAddr = BAddr;
NumTrampolines = NTrampolines;
return std::error_code();
});
}
uint32_t getIndirectStubSize() const { return RemoteIndirectStubSize; }
uint32_t getPageSize() const { return RemotePageSize; }
uint32_t getPointerSize() const { return RemotePointerSize; }
uint32_t getTrampolineSize() const { return RemoteTrampolineSize; }
std::error_code listenForCompileRequests(uint32_t &NextId) {
// Check for an 'out-of-band' error, e.g. from an MM destructor.
if (ExistingError)
return ExistingError;
if (auto EC = getNextProcId(Channel, NextId))
return EC;
while (NextId == RequestCompileId) {
TargetAddress TrampolineAddr = 0;
if (auto EC = handle<RequestCompile>(Channel, readArgs(TrampolineAddr)))
return EC;
TargetAddress ImplAddr = CompileCallback(TrampolineAddr);
if (auto EC = call<RequestCompileResponse>(Channel, ImplAddr))
return EC;
if (auto EC = getNextProcId(Channel, NextId))
return EC;
}
return std::error_code();
}
std::error_code readMem(char *Dst, TargetAddress Src, uint64_t Size) {
// Check for an 'out-of-band' error, e.g. from an MM destructor.
if (ExistingError)
return ExistingError;
if (auto EC = call<ReadMem>(Channel, Src, Size))
return EC;
if (auto EC = expect<ReadMemResponse>(
Channel, [&]() { return Channel.readBytes(Dst, Size); }))
return EC;
return std::error_code();
}
std::error_code reserveMem(TargetAddress &RemoteAddr,
ResourceIdMgr::ResourceId Id, uint64_t Size,
uint32_t Align) {
// Check for an 'out-of-band' error, e.g. from an MM destructor.
if (ExistingError)
return ExistingError;
if (std::error_code EC = call<ReserveMem>(Channel, Id, Size, Align))
return EC;
return expect<ReserveMemResponse>(Channel, readArgs(RemoteAddr));
}
std::error_code setProtections(ResourceIdMgr::ResourceId Id,
TargetAddress RemoteSegAddr,
unsigned ProtFlags) {
return call<SetProtections>(Channel, Id, RemoteSegAddr, ProtFlags);
}
std::error_code writeMem(TargetAddress Addr, const char *Src, uint64_t Size) {
// Check for an 'out-of-band' error, e.g. from an MM destructor.
if (ExistingError)
return ExistingError;
// Make the send call.
if (auto EC = call<WriteMem>(Channel, Addr, Size))
return EC;
// Follow this up with the section contents.
if (auto EC = Channel.appendBytes(Src, Size))
return EC;
return Channel.send();
}
std::error_code writePointer(TargetAddress Addr, TargetAddress PtrVal) {
// Check for an 'out-of-band' error, e.g. from an MM destructor.
if (ExistingError)
return ExistingError;
return call<WritePtr>(Channel, Addr, PtrVal);
}
static std::error_code doNothing() { return std::error_code(); }
ChannelT &Channel;
std::error_code ExistingError;
std::string RemoteTargetTriple;
uint32_t RemotePointerSize;
uint32_t RemotePageSize;
uint32_t RemoteTrampolineSize;
uint32_t RemoteIndirectStubSize;
ResourceIdMgr AllocatorIds, IndirectStubOwnerIds;
std::function<TargetAddress(TargetAddress)> CompileCallback;
};
} // end namespace remote
} // end namespace orc
} // end namespace llvm
#undef DEBUG_TYPE
#endif

View File

@ -0,0 +1,185 @@
//===--- OrcRemoteTargetRPCAPI.h - Orc Remote-target RPC API ----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the Orc remote-target RPC API. It should not be used
// directly, but is used by the RemoteTargetClient and RemoteTargetServer
// classes.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETRPCAPI_H
#define LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETRPCAPI_H
#include "JITSymbol.h"
#include "RPCChannel.h"
#include "RPCUtils.h"
namespace llvm {
namespace orc {
namespace remote {
class OrcRemoteTargetRPCAPI : public RPC<RPCChannel> {
protected:
class ResourceIdMgr {
public:
typedef uint64_t ResourceId;
ResourceIdMgr() : NextId(0) {}
ResourceId getNext() {
if (!FreeIds.empty()) {
ResourceId I = FreeIds.back();
FreeIds.pop_back();
return I;
}
return NextId++;
}
void release(ResourceId I) { FreeIds.push_back(I); }
private:
ResourceId NextId;
std::vector<ResourceId> FreeIds;
};
public:
enum JITProcId : uint32_t {
InvalidId = 0,
CallIntVoidId,
CallIntVoidResponseId,
CallMainId,
CallMainResponseId,
CallVoidVoidId,
CallVoidVoidResponseId,
CreateRemoteAllocatorId,
CreateIndirectStubsOwnerId,
DestroyRemoteAllocatorId,
DestroyIndirectStubsOwnerId,
EmitIndirectStubsId,
EmitIndirectStubsResponseId,
EmitResolverBlockId,
EmitTrampolineBlockId,
EmitTrampolineBlockResponseId,
GetSymbolAddressId,
GetSymbolAddressResponseId,
GetRemoteInfoId,
GetRemoteInfoResponseId,
ReadMemId,
ReadMemResponseId,
ReserveMemId,
ReserveMemResponseId,
RequestCompileId,
RequestCompileResponseId,
SetProtectionsId,
TerminateSessionId,
WriteMemId,
WritePtrId
};
static const char *getJITProcIdName(JITProcId Id);
typedef Procedure<CallIntVoidId, TargetAddress /* FnAddr */> CallIntVoid;
typedef Procedure<CallIntVoidResponseId, int /* Result */>
CallIntVoidResponse;
typedef Procedure<CallMainId, TargetAddress /* FnAddr */,
std::vector<std::string> /* Args */>
CallMain;
typedef Procedure<CallMainResponseId, int /* Result */> CallMainResponse;
typedef Procedure<CallVoidVoidId, TargetAddress /* FnAddr */> CallVoidVoid;
typedef Procedure<CallVoidVoidResponseId> CallVoidVoidResponse;
typedef Procedure<CreateRemoteAllocatorId,
ResourceIdMgr::ResourceId /* Allocator ID */>
CreateRemoteAllocator;
typedef Procedure<CreateIndirectStubsOwnerId,
ResourceIdMgr::ResourceId /* StubsOwner ID */>
CreateIndirectStubsOwner;
typedef Procedure<DestroyRemoteAllocatorId,
ResourceIdMgr::ResourceId /* Allocator ID */>
DestroyRemoteAllocator;
typedef Procedure<DestroyIndirectStubsOwnerId,
ResourceIdMgr::ResourceId /* StubsOwner ID */>
DestroyIndirectStubsOwner;
typedef Procedure<EmitIndirectStubsId,
ResourceIdMgr::ResourceId /* StubsOwner ID */,
uint32_t /* NumStubsRequired */>
EmitIndirectStubs;
typedef Procedure<
EmitIndirectStubsResponseId, TargetAddress /* StubsBaseAddr */,
TargetAddress /* PtrsBaseAddr */, uint32_t /* NumStubsEmitted */>
EmitIndirectStubsResponse;
typedef Procedure<EmitResolverBlockId> EmitResolverBlock;
typedef Procedure<EmitTrampolineBlockId> EmitTrampolineBlock;
typedef Procedure<EmitTrampolineBlockResponseId,
TargetAddress /* BlockAddr */,
uint32_t /* NumTrampolines */>
EmitTrampolineBlockResponse;
typedef Procedure<GetSymbolAddressId, std::string /*SymbolName*/>
GetSymbolAddress;
typedef Procedure<GetSymbolAddressResponseId, uint64_t /* SymbolAddr */>
GetSymbolAddressResponse;
typedef Procedure<GetRemoteInfoId> GetRemoteInfo;
typedef Procedure<GetRemoteInfoResponseId, std::string /* Triple */,
uint32_t /* PointerSize */, uint32_t /* PageSize */,
uint32_t /* TrampolineSize */,
uint32_t /* IndirectStubSize */>
GetRemoteInfoResponse;
typedef Procedure<ReadMemId, TargetAddress /* Src */, uint64_t /* Size */>
ReadMem;
typedef Procedure<ReadMemResponseId> ReadMemResponse;
typedef Procedure<ReserveMemId, ResourceIdMgr::ResourceId /* Id */,
uint64_t /* Size */, uint32_t /* Align */>
ReserveMem;
typedef Procedure<ReserveMemResponseId, TargetAddress /* Addr */>
ReserveMemResponse;
typedef Procedure<RequestCompileId, TargetAddress /* TrampolineAddr */>
RequestCompile;
typedef Procedure<RequestCompileResponseId, TargetAddress /* ImplAddr */>
RequestCompileResponse;
typedef Procedure<SetProtectionsId, ResourceIdMgr::ResourceId /* Id */,
TargetAddress /* Dst */, uint32_t /* ProtFlags */>
SetProtections;
typedef Procedure<TerminateSessionId> TerminateSession;
typedef Procedure<WriteMemId, TargetAddress /* Dst */, uint64_t /* Size */
/* Data should follow */>
WriteMem;
typedef Procedure<WritePtrId, TargetAddress /* Dst */,
TargetAddress /* Val */>
WritePtr;
};
} // end namespace remote
} // end namespace orc
} // end namespace llvm
#endif

View File

@ -0,0 +1,432 @@
//===---- OrcRemoteTargetServer.h - Orc Remote-target Server ----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the OrcRemoteTargetServer class. It can be used to build a
// JIT server that can execute code sent from an OrcRemoteTargetClient.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETSERVER_H
#define LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETSERVER_H
#include "OrcRemoteTargetRPCAPI.h"
#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/raw_ostream.h"
#include <map>
#define DEBUG_TYPE "orc-remote"
namespace llvm {
namespace orc {
namespace remote {
template <typename ChannelT, typename TargetT>
class OrcRemoteTargetServer : public OrcRemoteTargetRPCAPI {
public:
typedef std::function<TargetAddress(const std::string &Name)>
SymbolLookupFtor;
OrcRemoteTargetServer(ChannelT &Channel, SymbolLookupFtor SymbolLookup)
: Channel(Channel), SymbolLookup(std::move(SymbolLookup)) {}
std::error_code getNextProcId(JITProcId &Id) {
return deserialize(Channel, Id);
}
std::error_code handleKnownProcedure(JITProcId Id) {
typedef OrcRemoteTargetServer ThisT;
DEBUG(dbgs() << "Handling known proc: " << getJITProcIdName(Id) << "\n");
switch (Id) {
case CallIntVoidId:
return handle<CallIntVoid>(Channel, *this, &ThisT::handleCallIntVoid);
case CallMainId:
return handle<CallMain>(Channel, *this, &ThisT::handleCallMain);
case CallVoidVoidId:
return handle<CallVoidVoid>(Channel, *this, &ThisT::handleCallVoidVoid);
case CreateRemoteAllocatorId:
return handle<CreateRemoteAllocator>(Channel, *this,
&ThisT::handleCreateRemoteAllocator);
case CreateIndirectStubsOwnerId:
return handle<CreateIndirectStubsOwner>(
Channel, *this, &ThisT::handleCreateIndirectStubsOwner);
case DestroyRemoteAllocatorId:
return handle<DestroyRemoteAllocator>(
Channel, *this, &ThisT::handleDestroyRemoteAllocator);
case DestroyIndirectStubsOwnerId:
return handle<DestroyIndirectStubsOwner>(
Channel, *this, &ThisT::handleDestroyIndirectStubsOwner);
case EmitIndirectStubsId:
return handle<EmitIndirectStubs>(Channel, *this,
&ThisT::handleEmitIndirectStubs);
case EmitResolverBlockId:
return handle<EmitResolverBlock>(Channel, *this,
&ThisT::handleEmitResolverBlock);
case EmitTrampolineBlockId:
return handle<EmitTrampolineBlock>(Channel, *this,
&ThisT::handleEmitTrampolineBlock);
case GetSymbolAddressId:
return handle<GetSymbolAddress>(Channel, *this,
&ThisT::handleGetSymbolAddress);
case GetRemoteInfoId:
return handle<GetRemoteInfo>(Channel, *this, &ThisT::handleGetRemoteInfo);
case ReadMemId:
return handle<ReadMem>(Channel, *this, &ThisT::handleReadMem);
case ReserveMemId:
return handle<ReserveMem>(Channel, *this, &ThisT::handleReserveMem);
case SetProtectionsId:
return handle<SetProtections>(Channel, *this,
&ThisT::handleSetProtections);
case WriteMemId:
return handle<WriteMem>(Channel, *this, &ThisT::handleWriteMem);
case WritePtrId:
return handle<WritePtr>(Channel, *this, &ThisT::handleWritePtr);
default:
return orcError(OrcErrorCode::UnexpectedRPCCall);
}
llvm_unreachable("Unhandled JIT RPC procedure Id.");
}
std::error_code requestCompile(TargetAddress &CompiledFnAddr,
TargetAddress TrampolineAddr) {
if (auto EC = call<RequestCompile>(Channel, TrampolineAddr))
return EC;
while (1) {
JITProcId Id = InvalidId;
if (auto EC = getNextProcId(Id))
return EC;
switch (Id) {
case RequestCompileResponseId:
return handle<RequestCompileResponse>(Channel,
readArgs(CompiledFnAddr));
default:
if (auto EC = handleKnownProcedure(Id))
return EC;
}
}
llvm_unreachable("Fell through request-compile command loop.");
}
private:
struct Allocator {
Allocator() = default;
Allocator(Allocator &&Other) : Allocs(std::move(Other.Allocs)) {}
Allocator &operator=(Allocator &&Other) {
Allocs = std::move(Other.Allocs);
return *this;
}
~Allocator() {
for (auto &Alloc : Allocs)
sys::Memory::releaseMappedMemory(Alloc.second);
}
std::error_code allocate(void *&Addr, size_t Size, uint32_t Align) {
std::error_code EC;
sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(
Size, nullptr, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC);
if (EC)
return EC;
Addr = MB.base();
assert(Allocs.find(MB.base()) == Allocs.end() && "Duplicate alloc");
Allocs[MB.base()] = std::move(MB);
return std::error_code();
}
std::error_code setProtections(void *block, unsigned Flags) {
auto I = Allocs.find(block);
if (I == Allocs.end())
return orcError(OrcErrorCode::RemoteMProtectAddrUnrecognized);
return sys::Memory::protectMappedMemory(I->second, Flags);
}
private:
std::map<void *, sys::MemoryBlock> Allocs;
};
static std::error_code doNothing() { return std::error_code(); }
static TargetAddress reenter(void *JITTargetAddr, void *TrampolineAddr) {
TargetAddress CompiledFnAddr = 0;
auto T = static_cast<OrcRemoteTargetServer *>(JITTargetAddr);
auto EC = T->requestCompile(
CompiledFnAddr, static_cast<TargetAddress>(
reinterpret_cast<uintptr_t>(TrampolineAddr)));
assert(!EC && "Compile request failed");
(void)EC;
return CompiledFnAddr;
}
std::error_code handleCallIntVoid(TargetAddress Addr) {
typedef int (*IntVoidFnTy)();
IntVoidFnTy Fn =
reinterpret_cast<IntVoidFnTy>(static_cast<uintptr_t>(Addr));
DEBUG(dbgs() << " Calling "
<< reinterpret_cast<void *>(reinterpret_cast<intptr_t>(Fn))
<< "\n");
int Result = Fn();
DEBUG(dbgs() << " Result = " << Result << "\n");
return call<CallIntVoidResponse>(Channel, Result);
}
std::error_code handleCallMain(TargetAddress Addr,
std::vector<std::string> Args) {
typedef int (*MainFnTy)(int, const char *[]);
MainFnTy Fn = reinterpret_cast<MainFnTy>(static_cast<uintptr_t>(Addr));
int ArgC = Args.size() + 1;
int Idx = 1;
std::unique_ptr<const char *[]> ArgV(new const char *[ArgC + 1]);
ArgV[0] = "<jit process>";
for (auto &Arg : Args)
ArgV[Idx++] = Arg.c_str();
DEBUG(dbgs() << " Calling " << reinterpret_cast<void *>(Fn) << "\n");
int Result = Fn(ArgC, ArgV.get());
DEBUG(dbgs() << " Result = " << Result << "\n");
return call<CallMainResponse>(Channel, Result);
}
std::error_code handleCallVoidVoid(TargetAddress Addr) {
typedef void (*VoidVoidFnTy)();
VoidVoidFnTy Fn =
reinterpret_cast<VoidVoidFnTy>(static_cast<uintptr_t>(Addr));
DEBUG(dbgs() << " Calling " << reinterpret_cast<void *>(Fn) << "\n");
Fn();
DEBUG(dbgs() << " Complete.\n");
return call<CallVoidVoidResponse>(Channel);
}
std::error_code handleCreateRemoteAllocator(ResourceIdMgr::ResourceId Id) {
auto I = Allocators.find(Id);
if (I != Allocators.end())
return orcError(OrcErrorCode::RemoteAllocatorIdAlreadyInUse);
DEBUG(dbgs() << " Created allocator " << Id << "\n");
Allocators[Id] = Allocator();
return std::error_code();
}
std::error_code handleCreateIndirectStubsOwner(ResourceIdMgr::ResourceId Id) {
auto I = IndirectStubsOwners.find(Id);
if (I != IndirectStubsOwners.end())
return orcError(OrcErrorCode::RemoteIndirectStubsOwnerIdAlreadyInUse);
DEBUG(dbgs() << " Create indirect stubs owner " << Id << "\n");
IndirectStubsOwners[Id] = ISBlockOwnerList();
return std::error_code();
}
std::error_code handleDestroyRemoteAllocator(ResourceIdMgr::ResourceId Id) {
auto I = Allocators.find(Id);
if (I == Allocators.end())
return orcError(OrcErrorCode::RemoteAllocatorDoesNotExist);
Allocators.erase(I);
DEBUG(dbgs() << " Destroyed allocator " << Id << "\n");
return std::error_code();
}
std::error_code
handleDestroyIndirectStubsOwner(ResourceIdMgr::ResourceId Id) {
auto I = IndirectStubsOwners.find(Id);
if (I == IndirectStubsOwners.end())
return orcError(OrcErrorCode::RemoteIndirectStubsOwnerDoesNotExist);
IndirectStubsOwners.erase(I);
return std::error_code();
}
std::error_code handleEmitIndirectStubs(ResourceIdMgr::ResourceId Id,
uint32_t NumStubsRequired) {
DEBUG(dbgs() << " ISMgr " << Id << " request " << NumStubsRequired
<< " stubs.\n");
auto StubOwnerItr = IndirectStubsOwners.find(Id);
if (StubOwnerItr == IndirectStubsOwners.end())
return orcError(OrcErrorCode::RemoteIndirectStubsOwnerDoesNotExist);
typename TargetT::IndirectStubsInfo IS;
if (auto EC =
TargetT::emitIndirectStubsBlock(IS, NumStubsRequired, nullptr))
return EC;
TargetAddress StubsBase =
static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(IS.getStub(0)));
TargetAddress PtrsBase =
static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(IS.getPtr(0)));
uint32_t NumStubsEmitted = IS.getNumStubs();
auto &BlockList = StubOwnerItr->second;
BlockList.push_back(std::move(IS));
return call<EmitIndirectStubsResponse>(Channel, StubsBase, PtrsBase,
NumStubsEmitted);
}
std::error_code handleEmitResolverBlock() {
std::error_code EC;
ResolverBlock = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
TargetT::ResolverCodeSize, nullptr,
sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
if (EC)
return EC;
TargetT::writeResolverCode(static_cast<uint8_t *>(ResolverBlock.base()),
&reenter, this);
return sys::Memory::protectMappedMemory(ResolverBlock.getMemoryBlock(),
sys::Memory::MF_READ |
sys::Memory::MF_EXEC);
}
std::error_code handleEmitTrampolineBlock() {
std::error_code EC;
auto TrampolineBlock =
sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
sys::Process::getPageSize(), nullptr,
sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
if (EC)
return EC;
unsigned NumTrampolines =
(sys::Process::getPageSize() - TargetT::PointerSize) /
TargetT::TrampolineSize;
uint8_t *TrampolineMem = static_cast<uint8_t *>(TrampolineBlock.base());
TargetT::writeTrampolines(TrampolineMem, ResolverBlock.base(),
NumTrampolines);
EC = sys::Memory::protectMappedMemory(TrampolineBlock.getMemoryBlock(),
sys::Memory::MF_READ |
sys::Memory::MF_EXEC);
TrampolineBlocks.push_back(std::move(TrampolineBlock));
return call<EmitTrampolineBlockResponse>(
Channel,
static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(TrampolineMem)),
NumTrampolines);
}
std::error_code handleGetSymbolAddress(const std::string &Name) {
TargetAddress Addr = SymbolLookup(Name);
DEBUG(dbgs() << " Symbol '" << Name << "' = " << format("0x%016x", Addr)
<< "\n");
return call<GetSymbolAddressResponse>(Channel, Addr);
}
std::error_code handleGetRemoteInfo() {
std::string ProcessTriple = sys::getProcessTriple();
uint32_t PointerSize = TargetT::PointerSize;
uint32_t PageSize = sys::Process::getPageSize();
uint32_t TrampolineSize = TargetT::TrampolineSize;
uint32_t IndirectStubSize = TargetT::IndirectStubsInfo::StubSize;
DEBUG(dbgs() << " Remote info:\n"
<< " triple = '" << ProcessTriple << "'\n"
<< " pointer size = " << PointerSize << "\n"
<< " page size = " << PageSize << "\n"
<< " trampoline size = " << TrampolineSize << "\n"
<< " indirect stub size = " << IndirectStubSize << "\n");
return call<GetRemoteInfoResponse>(Channel, ProcessTriple, PointerSize,
PageSize, TrampolineSize,
IndirectStubSize);
}
std::error_code handleReadMem(TargetAddress RSrc, uint64_t Size) {
char *Src = reinterpret_cast<char *>(static_cast<uintptr_t>(RSrc));
DEBUG(dbgs() << " Reading " << Size << " bytes from "
<< static_cast<void *>(Src) << "\n");
if (auto EC = call<ReadMemResponse>(Channel))
return EC;
if (auto EC = Channel.appendBytes(Src, Size))
return EC;
return Channel.send();
}
std::error_code handleReserveMem(ResourceIdMgr::ResourceId Id, uint64_t Size,
uint32_t Align) {
auto I = Allocators.find(Id);
if (I == Allocators.end())
return orcError(OrcErrorCode::RemoteAllocatorDoesNotExist);
auto &Allocator = I->second;
void *LocalAllocAddr = nullptr;
if (auto EC = Allocator.allocate(LocalAllocAddr, Size, Align))
return EC;
DEBUG(dbgs() << " Allocator " << Id << " reserved " << LocalAllocAddr
<< " (" << Size << " bytes, alignment " << Align << ")\n");
TargetAddress AllocAddr =
static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(LocalAllocAddr));
return call<ReserveMemResponse>(Channel, AllocAddr);
}
std::error_code handleSetProtections(ResourceIdMgr::ResourceId Id,
TargetAddress Addr, uint32_t Flags) {
auto I = Allocators.find(Id);
if (I == Allocators.end())
return orcError(OrcErrorCode::RemoteAllocatorDoesNotExist);
auto &Allocator = I->second;
void *LocalAddr = reinterpret_cast<void *>(static_cast<uintptr_t>(Addr));
DEBUG(dbgs() << " Allocator " << Id << " set permissions on " << LocalAddr
<< " to " << (Flags & sys::Memory::MF_READ ? 'R' : '-')
<< (Flags & sys::Memory::MF_WRITE ? 'W' : '-')
<< (Flags & sys::Memory::MF_EXEC ? 'X' : '-') << "\n");
return Allocator.setProtections(LocalAddr, Flags);
}
std::error_code handleWriteMem(TargetAddress RDst, uint64_t Size) {
char *Dst = reinterpret_cast<char *>(static_cast<uintptr_t>(RDst));
DEBUG(dbgs() << " Writing " << Size << " bytes to "
<< format("0x%016x", RDst) << "\n");
return Channel.readBytes(Dst, Size);
}
std::error_code handleWritePtr(TargetAddress Addr, TargetAddress PtrVal) {
DEBUG(dbgs() << " Writing pointer *" << format("0x%016x", Addr) << " = "
<< format("0x%016x", PtrVal) << "\n");
uintptr_t *Ptr =
reinterpret_cast<uintptr_t *>(static_cast<uintptr_t>(Addr));
*Ptr = static_cast<uintptr_t>(PtrVal);
return std::error_code();
}
ChannelT &Channel;
SymbolLookupFtor SymbolLookup;
std::map<ResourceIdMgr::ResourceId, Allocator> Allocators;
typedef std::vector<typename TargetT::IndirectStubsInfo> ISBlockOwnerList;
std::map<ResourceIdMgr::ResourceId, ISBlockOwnerList> IndirectStubsOwners;
sys::OwningMemoryBlock ResolverBlock;
std::vector<sys::OwningMemoryBlock> TrampolineBlocks;
};
} // end namespace remote
} // end namespace orc
} // end namespace llvm
#undef DEBUG_TYPE
#endif

View File

@ -0,0 +1,179 @@
// -*- c++ -*-
#ifndef LLVM_EXECUTIONENGINE_ORC_RPCCHANNEL_H
#define LLVM_EXECUTIONENGINE_ORC_RPCCHANNEL_H
#include "OrcError.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/Endian.h"
#include <system_error>
namespace llvm {
namespace orc {
namespace remote {
/// Interface for byte-streams to be used with RPC.
class RPCChannel {
public:
virtual ~RPCChannel() {}
/// Read Size bytes from the stream into *Dst.
virtual std::error_code readBytes(char *Dst, unsigned Size) = 0;
/// Read size bytes from *Src and append them to the stream.
virtual std::error_code appendBytes(const char *Src, unsigned Size) = 0;
/// Flush the stream if possible.
virtual std::error_code send() = 0;
};
/// RPC channel serialization for a variadic list of arguments.
template <typename T, typename... Ts>
std::error_code serialize_seq(RPCChannel &C, const T &Arg, const Ts &... Args) {
if (auto EC = serialize(C, Arg))
return EC;
return serialize_seq(C, Args...);
}
/// RPC channel serialization for an (empty) variadic list of arguments.
inline std::error_code serialize_seq(RPCChannel &C) {
return std::error_code();
}
/// RPC channel deserialization for a variadic list of arguments.
template <typename T, typename... Ts>
std::error_code deserialize_seq(RPCChannel &C, T &Arg, Ts &... Args) {
if (auto EC = deserialize(C, Arg))
return EC;
return deserialize_seq(C, Args...);
}
/// RPC channel serialization for an (empty) variadic list of arguments.
inline std::error_code deserialize_seq(RPCChannel &C) {
return std::error_code();
}
/// RPC channel serialization for integer primitives.
template <typename T>
typename std::enable_if<
std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
std::is_same<T, uint16_t>::value || std::is_same<T, int16_t>::value ||
std::is_same<T, uint8_t>::value || std::is_same<T, int8_t>::value,
std::error_code>::type
serialize(RPCChannel &C, T V) {
support::endian::byte_swap<T, support::big>(V);
return C.appendBytes(reinterpret_cast<const char *>(&V), sizeof(T));
}
/// RPC channel deserialization for integer primitives.
template <typename T>
typename std::enable_if<
std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
std::is_same<T, uint16_t>::value || std::is_same<T, int16_t>::value ||
std::is_same<T, uint8_t>::value || std::is_same<T, int8_t>::value,
std::error_code>::type
deserialize(RPCChannel &C, T &V) {
if (auto EC = C.readBytes(reinterpret_cast<char *>(&V), sizeof(T)))
return EC;
support::endian::byte_swap<T, support::big>(V);
return std::error_code();
}
/// RPC channel serialization for enums.
template <typename T>
typename std::enable_if<std::is_enum<T>::value, std::error_code>::type
serialize(RPCChannel &C, T V) {
return serialize(C, static_cast<typename std::underlying_type<T>::type>(V));
}
/// RPC channel deserialization for enums.
template <typename T>
typename std::enable_if<std::is_enum<T>::value, std::error_code>::type
deserialize(RPCChannel &C, T &V) {
typename std::underlying_type<T>::type Tmp;
std::error_code EC = deserialize(C, Tmp);
V = static_cast<T>(Tmp);
return EC;
}
/// RPC channel serialization for bools.
inline std::error_code serialize(RPCChannel &C, bool V) {
uint8_t VN = V ? 1 : 0;
return C.appendBytes(reinterpret_cast<const char *>(&VN), 1);
}
/// RPC channel deserialization for bools.
inline std::error_code deserialize(RPCChannel &C, bool &V) {
uint8_t VN = 0;
if (auto EC = C.readBytes(reinterpret_cast<char *>(&VN), 1))
return EC;
V = (VN != 0) ? true : false;
return std::error_code();
}
/// RPC channel serialization for StringRefs.
/// Note: There is no corresponding deseralization for this, as StringRef
/// doesn't own its memory and so can't hold the deserialized data.
inline std::error_code serialize(RPCChannel &C, StringRef S) {
if (auto EC = serialize(C, static_cast<uint64_t>(S.size())))
return EC;
return C.appendBytes((const char *)S.bytes_begin(), S.size());
}
/// RPC channel serialization for std::strings.
inline std::error_code serialize(RPCChannel &C, const std::string &S) {
return serialize(C, StringRef(S));
}
/// RPC channel deserialization for std::strings.
inline std::error_code deserialize(RPCChannel &C, std::string &S) {
uint64_t Count;
if (auto EC = deserialize(C, Count))
return EC;
S.resize(Count);
return C.readBytes(&S[0], Count);
}
/// RPC channel serialization for ArrayRef<T>.
template <typename T>
std::error_code serialize(RPCChannel &C, const ArrayRef<T> &A) {
if (auto EC = serialize(C, static_cast<uint64_t>(A.size())))
return EC;
for (const auto &E : A)
if (auto EC = serialize(C, E))
return EC;
return std::error_code();
}
/// RPC channel serialization for std::array<T>.
template <typename T>
std::error_code serialize(RPCChannel &C, const std::vector<T> &V) {
return serialize(C, ArrayRef<T>(V));
}
/// RPC channel deserialization for std::array<T>.
template <typename T>
std::error_code deserialize(RPCChannel &C, std::vector<T> &V) {
uint64_t Count = 0;
if (auto EC = deserialize(C, Count))
return EC;
V.resize(Count);
for (auto &E : V)
if (auto EC = deserialize(C, E))
return EC;
return std::error_code();
}
} // end namespace remote
} // end namespace orc
} // end namespace llvm
#endif

View File

@ -0,0 +1,266 @@
//===----- RPCUTils.h - Basic tilities for building RPC APIs ----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Basic utilities for building RPC APIs.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_EXECUTIONENGINE_ORC_RPCUTILS_H
#define LLVM_EXECUTIONENGINE_ORC_RPCUTILS_H
#include "llvm/ADT/STLExtras.h"
namespace llvm {
namespace orc {
namespace remote {
// Base class containing utilities that require partial specialization.
// These cannot be included in RPC, as template class members cannot be
// partially specialized.
class RPCBase {
protected:
template <typename ProcedureIdT, ProcedureIdT ProcId, typename... Ts>
class ProcedureHelper {
public:
static const ProcedureIdT Id = ProcId;
};
template <typename ChannelT, typename Proc> class CallHelper;
template <typename ChannelT, typename ProcedureIdT, ProcedureIdT ProcId,
typename... ArgTs>
class CallHelper<ChannelT, ProcedureHelper<ProcedureIdT, ProcId, ArgTs...>> {
public:
static std::error_code call(ChannelT &C, const ArgTs &... Args) {
if (auto EC = serialize(C, ProcId))
return EC;
// If you see a compile-error on this line you're probably calling a
// function with the wrong signature.
return serialize_seq(C, Args...);
}
};
template <typename ChannelT, typename Proc> class HandlerHelper;
template <typename ChannelT, typename ProcedureIdT, ProcedureIdT ProcId,
typename... ArgTs>
class HandlerHelper<ChannelT,
ProcedureHelper<ProcedureIdT, ProcId, ArgTs...>> {
public:
template <typename HandlerT>
static std::error_code handle(ChannelT &C, HandlerT Handler) {
return readAndHandle(C, Handler, llvm::index_sequence_for<ArgTs...>());
}
private:
template <typename HandlerT, size_t... Is>
static std::error_code readAndHandle(ChannelT &C, HandlerT Handler,
llvm::index_sequence<Is...> _) {
std::tuple<ArgTs...> RPCArgs;
if (auto EC = deserialize_seq(C, std::get<Is>(RPCArgs)...))
return EC;
return Handler(std::get<Is>(RPCArgs)...);
}
};
template <typename ClassT, typename... ArgTs> class MemberFnWrapper {
public:
typedef std::error_code (ClassT::*MethodT)(ArgTs...);
MemberFnWrapper(ClassT &Instance, MethodT Method)
: Instance(Instance), Method(Method) {}
std::error_code operator()(ArgTs &... Args) {
return (Instance.*Method)(Args...);
}
private:
ClassT &Instance;
MethodT Method;
};
template <typename... ArgTs> class ReadArgs {
public:
std::error_code operator()() { return std::error_code(); }
};
template <typename ArgT, typename... ArgTs>
class ReadArgs<ArgT, ArgTs...> : public ReadArgs<ArgTs...> {
public:
ReadArgs(ArgT &Arg, ArgTs &... Args)
: ReadArgs<ArgTs...>(Args...), Arg(Arg) {}
std::error_code operator()(ArgT &ArgVal, ArgTs &... ArgVals) {
this->Arg = std::move(ArgVal);
return ReadArgs<ArgTs...>::operator()(ArgVals...);
}
private:
ArgT &Arg;
};
};
/// Contains primitive utilities for defining, calling and handling calls to
/// remote procedures. ChannelT is a bidirectional stream conforming to the
/// RPCChannel interface (see RPCChannel.h), and ProcedureIdT is a procedure
/// identifier type that must be serializable on ChannelT.
///
/// These utilities support the construction of very primitive RPC utilities.
/// Their intent is to ensure correct serialization and deserialization of
/// procedure arguments, and to keep the client and server's view of the API in
/// sync.
///
/// These utilities do not support return values. These can be handled by
/// declaring a corresponding '.*Response' procedure and expecting it after a
/// call). They also do not support versioning: the client and server *must* be
/// compiled with the same procedure definitions.
///
///
///
/// Overview (see comments individual types/methods for details):
///
/// Procedure<Id, Args...> :
///
/// associates a unique serializable id with an argument list.
///
///
/// call<Proc>(Channel, Args...) :
///
/// Calls the remote procedure 'Proc' by serializing Proc's id followed by its
/// arguments and sending the resulting bytes to 'Channel'.
///
///
/// handle<Proc>(Channel, <functor matching std::error_code(Args...)> :
///
/// Handles a call to 'Proc' by deserializing its arguments and calling the
/// given functor. This assumes that the id for 'Proc' has already been
/// deserialized.
///
/// expect<Proc>(Channel, <functor matching std::error_code(Args...)> :
///
/// The same as 'handle', except that the procedure id should not have been
/// read yet. Expect will deserialize the id and assert that it matches Proc's
/// id. If it does not, and unexpected RPC call error is returned.
template <typename ChannelT, typename ProcedureIdT = uint32_t>
class RPC : public RPCBase {
public:
/// Utility class for defining/referring to RPC procedures.
///
/// Typedefs of this utility are used when calling/handling remote procedures.
///
/// ProcId should be a unique value of ProcedureIdT (i.e. not used with any
/// other Procedure typedef in the RPC API being defined.
///
/// the template argument Ts... gives the argument list for the remote
/// procedure.
///
/// E.g.
///
/// typedef Procedure<0, bool> Proc1;
/// typedef Procedure<1, std::string, std::vector<int>> Proc2;
///
/// if (auto EC = call<Proc1>(Channel, true))
/// /* handle EC */;
///
/// if (auto EC = expect<Proc2>(Channel,
/// [](std::string &S, std::vector<int> &V) {
/// // Stuff.
/// return std::error_code();
/// })
/// /* handle EC */;
///
template <ProcedureIdT ProcId, typename... Ts>
using Procedure = ProcedureHelper<ProcedureIdT, ProcId, Ts...>;
/// Serialize Args... to channel C, but do not call C.send().
///
/// For buffered channels, this can be used to queue up several calls before
/// flushing the channel.
template <typename Proc, typename... ArgTs>
static std::error_code appendCall(ChannelT &C, const ArgTs &... Args) {
return CallHelper<ChannelT, Proc>::call(C, Args...);
}
/// Serialize Args... to channel C and call C.send().
template <typename Proc, typename... ArgTs>
static std::error_code call(ChannelT &C, const ArgTs &... Args) {
if (auto EC = appendCall<Proc>(C, Args...))
return EC;
return C.send();
}
/// Deserialize and return an enum whose underlying type is ProcedureIdT.
static std::error_code getNextProcId(ChannelT &C, ProcedureIdT &Id) {
return deserialize(C, Id);
}
/// Deserialize args for Proc from C and call Handler. The signature of
/// handler must conform to 'std::error_code(Args...)' where Args... matches
/// the arguments used in the Proc typedef.
template <typename Proc, typename HandlerT>
static std::error_code handle(ChannelT &C, HandlerT Handler) {
return HandlerHelper<ChannelT, Proc>::handle(C, Handler);
}
/// Helper version of 'handle' for calling member functions.
template <typename Proc, typename ClassT, typename... ArgTs>
static std::error_code
handle(ChannelT &C, ClassT &Instance,
std::error_code (ClassT::*HandlerMethod)(ArgTs...)) {
return handle<Proc>(
C, MemberFnWrapper<ClassT, ArgTs...>(Instance, HandlerMethod));
}
/// Deserialize a ProcedureIdT from C and verify it matches the id for Proc.
/// If the id does match, deserialize the arguments and call the handler
/// (similarly to handle).
/// If the id does not match, return an unexpect RPC call error and do not
/// deserialize any further bytes.
template <typename Proc, typename HandlerT>
static std::error_code expect(ChannelT &C, HandlerT Handler) {
ProcedureIdT ProcId;
if (auto EC = getNextProcId(C, ProcId))
return EC;
if (ProcId != Proc::Id)
return orcError(OrcErrorCode::UnexpectedRPCCall);
return handle<Proc>(C, Handler);
}
/// Helper version of expect for calling member functions.
template <typename Proc, typename ClassT, typename... ArgTs>
static std::error_code
expect(ChannelT &C, ClassT &Instance,
std::error_code (ClassT::*HandlerMethod)(ArgTs...)) {
return expect<Proc>(
C, MemberFnWrapper<ClassT, ArgTs...>(Instance, HandlerMethod));
}
/// Helper for handling setter procedures - this method returns a functor that
/// sets the variables referred to by Args... to values deserialized from the
/// channel.
/// E.g.
///
/// typedef Procedure<0, bool, int> Proc1;
///
/// ...
/// bool B;
/// int I;
/// if (auto EC = expect<Proc1>(Channel, readArgs(B, I)))
/// /* Handle Args */ ;
///
template <typename... ArgTs>
static ReadArgs<ArgTs...> readArgs(ArgTs &... Args) {
return ReadArgs<ArgTs...>(Args...);
}
};
} // end namespace remote
} // end namespace orc
} // end namespace llvm
#endif

View File

@ -30,6 +30,10 @@ class ExecutionEngine;
class MCJITMemoryManager : public RuntimeDyld::MemoryManager {
public:
// Don't hide the notifyObjectLoaded method from RuntimeDyld::MemoryManager.
using RuntimeDyld::MemoryManager::notifyObjectLoaded;
/// This method is called after an object has been loaded into memory but
/// before relocations are applied to the loaded sections. The object load
/// may have been initiated by MCJIT to resolve an external symbol for another

View File

@ -95,7 +95,9 @@ public:
/// \brief Memory Management.
class MemoryManager {
friend class RuntimeDyld;
public:
MemoryManager() : FinalizationLocked(false) {}
virtual ~MemoryManager() {}
/// Allocate a memory block of (at least) the given size suitable for
@ -122,9 +124,11 @@ public:
///
/// Note that by default the callback is disabled. To enable it
/// redefine the method needsToReserveAllocationSpace to return true.
virtual void reserveAllocationSpace(uintptr_t CodeSize,
uintptr_t DataSizeRO,
uintptr_t DataSizeRW) {}
virtual void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign,
uintptr_t RODataSize,
uint32_t RODataAlign,
uintptr_t RWDataSize,
uint32_t RWDataAlign) {}
/// Override to return true to enable the reserveAllocationSpace callback.
virtual bool needsToReserveAllocationSpace() { return false; }
@ -151,8 +155,23 @@ public:
/// Returns true if an error occurred, false otherwise.
virtual bool finalizeMemory(std::string *ErrMsg = nullptr) = 0;
/// This method is called after an object has been loaded into memory but
/// before relocations are applied to the loaded sections.
///
/// Memory managers which are preparing code for execution in an external
/// address space can use this call to remap the section addresses for the
/// newly loaded object.
///
/// For clients that do not need access to an ExecutionEngine instance this
/// method should be preferred to its cousin
/// MCJITMemoryManager::notifyObjectLoaded as this method is compatible with
/// ORC JIT stacks.
virtual void notifyObjectLoaded(RuntimeDyld &RTDyld,
const object::ObjectFile &Obj) {}
private:
virtual void anchor();
bool FinalizationLocked;
};
/// \brief Symbol resolution.
@ -241,6 +260,25 @@ public:
this->ProcessAllSections = ProcessAllSections;
}
/// Perform all actions needed to make the code owned by this RuntimeDyld
/// instance executable:
///
/// 1) Apply relocations.
/// 2) Register EH frames.
/// 3) Update memory permissions*.
///
/// * Finalization is potentially recursive**, and the 3rd step will only be
/// applied by the outermost call to finalize. This allows different
/// RuntimeDyld instances to share a memory manager without the innermost
/// finalization locking the memory and causing relocation fixup errors in
/// outer instances.
///
/// ** Recursive finalization occurs when one RuntimeDyld instances needs the
/// address of a symbol owned by some other instance in order to apply
/// relocations.
///
void finalizeWithMemoryManagerLocking();
private:
// RuntimeDyldImpl is the actual class. RuntimeDyld is just the public
// interface.

View File

@ -189,4 +189,9 @@ class MergeRule<string F> {
string MergeFunc = F;
}
def : MergeRule<"setAND<LessPreciseFPMADAttr>">;
def : MergeRule<"setAND<NoInfsFPMathAttr>">;
def : MergeRule<"setAND<NoNansFPMathAttr>">;
def : MergeRule<"setAND<UnsafeFPMathAttr>">;
def : MergeRule<"setOR<NoImplicitFloatAttr>">;
def : MergeRule<"adjustCallerSSPLevel">;

View File

@ -66,7 +66,8 @@ private:
* bit 2 : HasPrologueData
* bit 3 : HasPersonalityFn
* bits 4-13 : CallingConvention
* bits 14-15 : [reserved]
* bits 14 : HasGC
* bits 15 : [reserved]
*/
/// Bits from GlobalObject::GlobalObjectSubclassData.
@ -220,9 +221,11 @@ public:
/// hasGC/getGC/setGC/clearGC - The name of the garbage collection algorithm
/// to use during code generation.
bool hasGC() const;
const char *getGC() const;
void setGC(const char *Str);
bool hasGC() const {
return getSubclassDataFromValue() & (1<<14);
}
const std::string &getGC() const;
void setGC(const std::string Str);
void clearGC();
/// @brief adds the attribute to the list of attributes.

View File

@ -178,10 +178,10 @@ public:
void clearFastMathFlags() { FMF.clear(); }
/// \brief Set the floating point math metadata to be used.
void SetDefaultFPMathTag(MDNode *FPMathTag) { DefaultFPMathTag = FPMathTag; }
void setDefaultFPMathTag(MDNode *FPMathTag) { DefaultFPMathTag = FPMathTag; }
/// \brief Set the fast-math flags to be used with generated fp-math operators
void SetFastMathFlags(FastMathFlags NewFMF) { FMF = NewFMF; }
void setFastMathFlags(FastMathFlags NewFMF) { FMF = NewFMF; }
//===--------------------------------------------------------------------===//
// RAII helpers.

View File

@ -575,7 +575,7 @@ def int_experimental_gc_statepoint : Intrinsic<[llvm_token_ty],
def int_experimental_gc_result : Intrinsic<[llvm_any_ty], [llvm_token_ty],
[IntrReadMem]>;
def int_experimental_gc_relocate : Intrinsic<[llvm_anyptr_ty],
def int_experimental_gc_relocate : Intrinsic<[llvm_any_ty],
[llvm_token_ty, llvm_i32_ty, llvm_i32_ty],
[IntrReadMem]>;

View File

@ -1507,6 +1507,60 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.".
[llvm_v64i8_ty, llvm_v64i8_ty, llvm_v64i8_ty, llvm_i64_ty],
[IntrNoMem]>;
def int_x86_avx512_mask_pshuf_d_128 :
GCCBuiltin<"__builtin_ia32_pshufd128_mask">,
Intrinsic<[llvm_v4i32_ty],
[llvm_v4i32_ty, llvm_i16_ty, llvm_v4i32_ty, llvm_i8_ty],
[IntrNoMem]>;
def int_x86_avx512_mask_pshuf_d_256 :
GCCBuiltin<"__builtin_ia32_pshufd256_mask">,
Intrinsic<[llvm_v8i32_ty],
[llvm_v8i32_ty, llvm_i16_ty, llvm_v8i32_ty, llvm_i8_ty],
[IntrNoMem]>;
def int_x86_avx512_mask_pshuf_d_512 :
GCCBuiltin<"__builtin_ia32_pshufd512_mask">,
Intrinsic<[llvm_v16i32_ty],
[llvm_v16i32_ty, llvm_i16_ty, llvm_v16i32_ty, llvm_i8_ty],
[IntrNoMem]>;
def int_x86_avx512_mask_pshufh_w_128 :
GCCBuiltin<"__builtin_ia32_pshufhw128_mask">,
Intrinsic<[llvm_v8i16_ty],
[llvm_v8i16_ty, llvm_i8_ty, llvm_v8i16_ty, llvm_i8_ty],
[IntrNoMem]>;
def int_x86_avx512_mask_pshufh_w_256 :
GCCBuiltin<"__builtin_ia32_pshufhw256_mask">,
Intrinsic<[llvm_v16i16_ty],
[llvm_v16i16_ty, llvm_i8_ty, llvm_v16i16_ty, llvm_i16_ty],
[IntrNoMem]>;
def int_x86_avx512_mask_pshufh_w_512 :
GCCBuiltin<"__builtin_ia32_pshufhw512_mask">,
Intrinsic<[llvm_v32i16_ty],
[llvm_v32i16_ty, llvm_i8_ty, llvm_v32i16_ty, llvm_i32_ty],
[IntrNoMem]>;
def int_x86_avx512_mask_pshufl_w_128 :
GCCBuiltin<"__builtin_ia32_pshuflw128_mask">,
Intrinsic<[llvm_v8i16_ty],
[llvm_v8i16_ty, llvm_i8_ty, llvm_v8i16_ty, llvm_i8_ty],
[IntrNoMem]>;
def int_x86_avx512_mask_pshufl_w_256 :
GCCBuiltin<"__builtin_ia32_pshuflw256_mask">,
Intrinsic<[llvm_v16i16_ty],
[llvm_v16i16_ty, llvm_i8_ty, llvm_v16i16_ty, llvm_i16_ty],
[IntrNoMem]>;
def int_x86_avx512_mask_pshufl_w_512 :
GCCBuiltin<"__builtin_ia32_pshuflw512_mask">,
Intrinsic<[llvm_v32i16_ty],
[llvm_v32i16_ty, llvm_i8_ty, llvm_v32i16_ty, llvm_i32_ty],
[IntrNoMem]>;
def int_x86_avx512_mask_shuf_f32x4_256 :
GCCBuiltin<"__builtin_ia32_shuf_f32x4_256_mask">,
Intrinsic<[llvm_v8f32_ty],
@ -1836,25 +1890,69 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.".
def int_x86_avx_maskload_ps_256 : GCCBuiltin<"__builtin_ia32_maskloadps256">,
Intrinsic<[llvm_v8f32_ty], [llvm_ptr_ty, llvm_v8i32_ty],
[IntrReadArgMem]>;
def int_x86_avx512_mask_loadu_ps_512 : GCCBuiltin<"__builtin_ia32_loadups512_mask">,
Intrinsic<[llvm_v16f32_ty], [llvm_ptr_ty, llvm_v16f32_ty, llvm_i16_ty],
[IntrReadArgMem]>;
def int_x86_avx512_mask_loadu_pd_512 : GCCBuiltin<"__builtin_ia32_loadupd512_mask">,
Intrinsic<[llvm_v8f64_ty], [llvm_ptr_ty, llvm_v8f64_ty, llvm_i8_ty],
[IntrReadArgMem]>;
def int_x86_avx512_mask_load_ps_512 : GCCBuiltin<"__builtin_ia32_loadaps512_mask">,
Intrinsic<[llvm_v16f32_ty], [llvm_ptr_ty, llvm_v16f32_ty, llvm_i16_ty],
[IntrReadArgMem]>;
def int_x86_avx512_mask_load_pd_512 : GCCBuiltin<"__builtin_ia32_loadapd512_mask">,
Intrinsic<[llvm_v8f64_ty], [llvm_ptr_ty, llvm_v8f64_ty, llvm_i8_ty],
[IntrReadArgMem]>;
def int_x86_avx512_mask_move_ss : GCCBuiltin<"__builtin_ia32_movss_mask">,
Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty],
[IntrNoMem]>;
def int_x86_avx512_mask_move_sd : GCCBuiltin<"__builtin_ia32_movsd_mask">,
Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty],
[IntrNoMem]>;
def int_x86_avx512_mask_loadu_ps_128 :
GCCBuiltin<"__builtin_ia32_loadups128_mask">,
Intrinsic<[llvm_v4f32_ty],
[llvm_ptr_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrReadArgMem]>;
def int_x86_avx512_mask_loadu_ps_256 :
GCCBuiltin<"__builtin_ia32_loadups256_mask">,
Intrinsic<[llvm_v8f32_ty],
[llvm_ptr_ty, llvm_v8f32_ty, llvm_i8_ty], [IntrReadArgMem]>;
def int_x86_avx512_mask_loadu_ps_512 :
GCCBuiltin<"__builtin_ia32_loadups512_mask">,
Intrinsic<[llvm_v16f32_ty],
[llvm_ptr_ty, llvm_v16f32_ty, llvm_i16_ty], [IntrReadArgMem]>;
def int_x86_avx512_mask_loadu_pd_128 :
GCCBuiltin<"__builtin_ia32_loadupd128_mask">,
Intrinsic<[llvm_v2f64_ty],
[llvm_ptr_ty, llvm_v2f64_ty, llvm_i8_ty], [IntrReadArgMem]>;
def int_x86_avx512_mask_loadu_pd_256 :
GCCBuiltin<"__builtin_ia32_loadupd256_mask">,
Intrinsic<[llvm_v4f64_ty],
[llvm_ptr_ty, llvm_v4f64_ty, llvm_i8_ty], [IntrReadArgMem]>;
def int_x86_avx512_mask_loadu_pd_512 :
GCCBuiltin<"__builtin_ia32_loadupd512_mask">,
Intrinsic<[llvm_v8f64_ty],
[llvm_ptr_ty, llvm_v8f64_ty, llvm_i8_ty], [IntrReadArgMem]>;
def int_x86_avx512_mask_load_ps_128 :
GCCBuiltin<"__builtin_ia32_loadaps128_mask">,
Intrinsic<[llvm_v4f32_ty],
[llvm_ptr_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrReadArgMem]>;
def int_x86_avx512_mask_load_ps_256 :
GCCBuiltin<"__builtin_ia32_loadaps256_mask">,
Intrinsic<[llvm_v8f32_ty],
[llvm_ptr_ty, llvm_v8f32_ty, llvm_i8_ty], [IntrReadArgMem]>;
def int_x86_avx512_mask_load_ps_512 :
GCCBuiltin<"__builtin_ia32_loadaps512_mask">,
Intrinsic<[llvm_v16f32_ty],
[llvm_ptr_ty, llvm_v16f32_ty, llvm_i16_ty], [IntrReadArgMem]>;
def int_x86_avx512_mask_load_pd_128 :
GCCBuiltin<"__builtin_ia32_loadapd128_mask">,
Intrinsic<[llvm_v2f64_ty],
[llvm_ptr_ty, llvm_v2f64_ty, llvm_i8_ty], [IntrReadArgMem]>;
def int_x86_avx512_mask_load_pd_256 :
GCCBuiltin<"__builtin_ia32_loadapd256_mask">,
Intrinsic<[llvm_v4f64_ty],
[llvm_ptr_ty, llvm_v4f64_ty, llvm_i8_ty], [IntrReadArgMem]>;
def int_x86_avx512_mask_load_pd_512 :
GCCBuiltin<"__builtin_ia32_loadapd512_mask">,
Intrinsic<[llvm_v8f64_ty],
[llvm_ptr_ty, llvm_v8f64_ty, llvm_i8_ty], [IntrReadArgMem]>;
def int_x86_avx512_mask_move_ss :
GCCBuiltin<"__builtin_ia32_movss_mask">,
Intrinsic<[llvm_v4f32_ty],
[llvm_v4f32_ty, llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty],
[IntrNoMem]>;
def int_x86_avx512_mask_move_sd :
GCCBuiltin<"__builtin_ia32_movsd_mask">,
Intrinsic<[llvm_v2f64_ty],
[llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty],
[IntrNoMem]>;
}
// Conditional store ops
@ -2262,6 +2360,46 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.".
Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty,
llvm_v2i64_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_psll_w_128 : GCCBuiltin<"__builtin_ia32_psllw128_mask">,
Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty,
llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_psll_w_256 : GCCBuiltin<"__builtin_ia32_psllw256_mask">,
Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty,
llvm_v8i16_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>;
def int_x86_avx512_mask_psll_w_512 : GCCBuiltin<"__builtin_ia32_psllw512_mask">,
Intrinsic<[llvm_v32i16_ty], [llvm_v32i16_ty,
llvm_v8i16_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>;
def int_x86_avx512_mask_psll_wi_128 : GCCBuiltin<"__builtin_ia32_psllwi128_mask">,
Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty,
llvm_i8_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_psll_wi_256 : GCCBuiltin<"__builtin_ia32_psllwi256_mask">,
Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty,
llvm_i8_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>;
def int_x86_avx512_mask_psll_wi_512 : GCCBuiltin<"__builtin_ia32_psllwi512_mask">,
Intrinsic<[llvm_v32i16_ty], [llvm_v32i16_ty,
llvm_i8_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>;
def int_x86_avx512_mask_psllv16_hi : GCCBuiltin<"__builtin_ia32_psllv16hi_mask">,
Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty,
llvm_v16i16_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>;
def int_x86_avx512_mask_psllv2_di : GCCBuiltin<"__builtin_ia32_psllv2di_mask">,
Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty,
llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_psllv32hi : GCCBuiltin<"__builtin_ia32_psllv32hi_mask">,
Intrinsic<[llvm_v32i16_ty], [llvm_v32i16_ty,
llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>;
def int_x86_avx512_mask_psllv4_di : GCCBuiltin<"__builtin_ia32_psllv4di_mask">,
Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty,
llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_psllv4_si : GCCBuiltin<"__builtin_ia32_psllv4si_mask">,
Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty,
llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_psllv8_hi : GCCBuiltin<"__builtin_ia32_psllv8hi_mask">,
Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty,
llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_psllv8_si : GCCBuiltin<"__builtin_ia32_psllv8si_mask">,
Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty,
llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_psra_d_128 : GCCBuiltin<"__builtin_ia32_psrad128_mask">,
Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty,
llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>;
@ -2823,6 +2961,28 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.".
Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty,
llvm_i8_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_psrav16_hi : GCCBuiltin<"__builtin_ia32_psrav16hi_mask">,
Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty,
llvm_v16i16_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>;
def int_x86_avx512_mask_psrav32_hi : GCCBuiltin<"__builtin_ia32_psrav32hi_mask">,
Intrinsic<[llvm_v32i16_ty], [llvm_v32i16_ty,
llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>;
def int_x86_avx512_mask_psrav4_si : GCCBuiltin<"__builtin_ia32_psrav4si_mask">,
Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty,
llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_psrav8_hi : GCCBuiltin<"__builtin_ia32_psrav8hi_mask">,
Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty,
llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_psrav8_si : GCCBuiltin<"__builtin_ia32_psrav8si_mask">,
Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty,
llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_psrav_q_128 : GCCBuiltin<"__builtin_ia32_psravq128_mask">,
Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty,
llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_psrav_q_256 : GCCBuiltin<"__builtin_ia32_psravq256_mask">,
Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty,
llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_psrlv16_hi : GCCBuiltin<"__builtin_ia32_psrlv16hi_mask">,
Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty,
llvm_v16i16_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>;
@ -2844,6 +3004,83 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.".
def int_x86_avx512_mask_psrlv8_si : GCCBuiltin<"__builtin_ia32_psrlv8si_mask">,
Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty,
llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_prorv_d_128 : GCCBuiltin<"__builtin_ia32_prorvd128_mask">,
Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty,
llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_prorv_d_256 : GCCBuiltin<"__builtin_ia32_prorvd256_mask">,
Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty,
llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_prorv_d_512 : GCCBuiltin<"__builtin_ia32_prorvd512_mask">,
Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty,
llvm_v16i32_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>;
def int_x86_avx512_mask_prorv_q_128 : GCCBuiltin<"__builtin_ia32_prorvq128_mask">,
Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty,
llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_prorv_q_256 : GCCBuiltin<"__builtin_ia32_prorvq256_mask">,
Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty,
llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_prorv_q_512 : GCCBuiltin<"__builtin_ia32_prorvq512_mask">,
Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty,
llvm_v8i64_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_prol_d_128 : GCCBuiltin<"__builtin_ia32_prold128_mask">,
Intrinsic<[llvm_v4i32_ty] , [llvm_v4i32_ty,
llvm_i8_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_prol_d_256 : GCCBuiltin<"__builtin_ia32_prold256_mask">,
Intrinsic<[llvm_v8i32_ty] , [llvm_v8i32_ty,
llvm_i8_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_prol_d_512 : GCCBuiltin<"__builtin_ia32_prold512_mask">,
Intrinsic<[llvm_v16i32_ty] , [llvm_v16i32_ty,
llvm_i8_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>;
def int_x86_avx512_mask_prol_q_128 : GCCBuiltin<"__builtin_ia32_prolq128_mask">,
Intrinsic<[llvm_v2i64_ty] , [llvm_v2i64_ty,
llvm_i8_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_prol_q_256 : GCCBuiltin<"__builtin_ia32_prolq256_mask">,
Intrinsic<[llvm_v4i64_ty] , [llvm_v4i64_ty,
llvm_i8_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_prol_q_512 : GCCBuiltin<"__builtin_ia32_prolq512_mask">,
Intrinsic<[llvm_v8i64_ty] , [llvm_v8i64_ty,
llvm_i8_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_prolv_d_128 : GCCBuiltin<"__builtin_ia32_prolvd128_mask">,
Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty,
llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_prolv_d_256 : GCCBuiltin<"__builtin_ia32_prolvd256_mask">,
Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty,
llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_prolv_d_512 : GCCBuiltin<"__builtin_ia32_prolvd512_mask">,
Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty,
llvm_v16i32_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>;
def int_x86_avx512_mask_prolv_q_128 : GCCBuiltin<"__builtin_ia32_prolvq128_mask">,
Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty,
llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_prolv_q_256 : GCCBuiltin<"__builtin_ia32_prolvq256_mask">,
Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty,
llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_prolv_q_512 : GCCBuiltin<"__builtin_ia32_prolvq512_mask">,
Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty,
llvm_v8i64_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pror_d_128 : GCCBuiltin<"__builtin_ia32_prord128_mask">,
Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty,
llvm_i8_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pror_d_256 : GCCBuiltin<"__builtin_ia32_prord256_mask">,
Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty,
llvm_i8_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pror_d_512 : GCCBuiltin<"__builtin_ia32_prord512_mask">,
Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty,
llvm_i8_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pror_q_128 : GCCBuiltin<"__builtin_ia32_prorq128_mask">,
Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty,
llvm_i8_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pror_q_256 : GCCBuiltin<"__builtin_ia32_prorq256_mask">,
Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty,
llvm_i8_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pror_q_512 : GCCBuiltin<"__builtin_ia32_prorq512_mask">,
Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty,
llvm_i8_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
}
// Gather ops
@ -4208,6 +4445,61 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.".
def int_x86_avx512_kortestc_w : GCCBuiltin<"__builtin_ia32_kortestchi">,
Intrinsic<[llvm_i32_ty], [llvm_i16_ty, llvm_i16_ty],
[IntrNoMem]>;
def int_x86_avx512_mask_pmovsxb_d_128 : GCCBuiltin<"__builtin_ia32_pmovsxbd128_mask">,
Intrinsic<[llvm_v4i32_ty], [llvm_v16i8_ty,
llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pmovsxb_d_256 : GCCBuiltin<"__builtin_ia32_pmovsxbd256_mask">,
Intrinsic<[llvm_v8i32_ty], [llvm_v16i8_ty,
llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pmovsxb_d_512 : GCCBuiltin<"__builtin_ia32_pmovsxbd512_mask">,
Intrinsic<[llvm_v16i32_ty], [llvm_v16i8_ty,
llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pmovsxb_q_128 : GCCBuiltin<"__builtin_ia32_pmovsxbq128_mask">,
Intrinsic<[llvm_v2i64_ty], [llvm_v16i8_ty,
llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pmovsxb_q_256 : GCCBuiltin<"__builtin_ia32_pmovsxbq256_mask">,
Intrinsic<[llvm_v4i64_ty], [llvm_v16i8_ty,
llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pmovsxb_q_512 : GCCBuiltin<"__builtin_ia32_pmovsxbq512_mask">,
Intrinsic<[llvm_v8i64_ty], [llvm_v16i8_ty,
llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pmovsxb_w_128 : GCCBuiltin<"__builtin_ia32_pmovsxbw128_mask">,
Intrinsic<[llvm_v8i16_ty], [llvm_v16i8_ty,
llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pmovsxb_w_256 : GCCBuiltin<"__builtin_ia32_pmovsxbw256_mask">,
Intrinsic<[llvm_v16i16_ty], [llvm_v16i8_ty,
llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pmovsxb_w_512 : GCCBuiltin<"__builtin_ia32_pmovsxbw512_mask">,
Intrinsic<[llvm_v32i16_ty], [llvm_v32i8_ty,
llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pmovsxd_q_128 : GCCBuiltin<"__builtin_ia32_pmovsxdq128_mask">,
Intrinsic<[llvm_v2i64_ty], [llvm_v4i32_ty,
llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pmovsxd_q_256 : GCCBuiltin<"__builtin_ia32_pmovsxdq256_mask">,
Intrinsic<[llvm_v4i64_ty], [llvm_v4i32_ty,
llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pmovsxd_q_512 : GCCBuiltin<"__builtin_ia32_pmovsxdq512_mask">,
Intrinsic<[llvm_v8i64_ty], [llvm_v8i32_ty,
llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pmovsxw_d_128 : GCCBuiltin<"__builtin_ia32_pmovsxwd128_mask">,
Intrinsic<[llvm_v4i32_ty], [llvm_v8i16_ty,
llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pmovsxw_d_256 : GCCBuiltin<"__builtin_ia32_pmovsxwd256_mask">,
Intrinsic<[llvm_v8i32_ty], [llvm_v8i16_ty,
llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pmovsxw_d_512 : GCCBuiltin<"__builtin_ia32_pmovsxwd512_mask">,
Intrinsic<[llvm_v16i32_ty], [llvm_v16i16_ty,
llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pmovsxw_q_128 : GCCBuiltin<"__builtin_ia32_pmovsxwq128_mask">,
Intrinsic<[llvm_v2i64_ty], [llvm_v8i16_ty,
llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pmovsxw_q_256 : GCCBuiltin<"__builtin_ia32_pmovsxwq256_mask">,
Intrinsic<[llvm_v4i64_ty], [llvm_v8i16_ty,
llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pmovsxw_q_512 : GCCBuiltin<"__builtin_ia32_pmovsxwq512_mask">,
Intrinsic<[llvm_v8i64_ty], [llvm_v8i16_ty,
llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
}
// Conversion ops
@ -5319,6 +5611,62 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.".
def int_x86_avx512_pmovzxdq : GCCBuiltin<"__builtin_ia32_pmovzxdq512">,
Intrinsic<[llvm_v8i64_ty], [llvm_v8i32_ty],
[IntrNoMem]>;
def int_x86_avx512_mask_pmovzxb_d_128 : GCCBuiltin<"__builtin_ia32_pmovzxbd128_mask">,
Intrinsic<[llvm_v4i32_ty], [llvm_v16i8_ty,
llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pmovzxb_d_256 : GCCBuiltin<"__builtin_ia32_pmovzxbd256_mask">,
Intrinsic<[llvm_v8i32_ty], [llvm_v16i8_ty,
llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pmovzxb_d_512 : GCCBuiltin<"__builtin_ia32_pmovzxbd512_mask">,
Intrinsic<[llvm_v16i32_ty], [llvm_v16i8_ty,
llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pmovzxb_q_128 : GCCBuiltin<"__builtin_ia32_pmovzxbq128_mask">,
Intrinsic<[llvm_v2i64_ty], [llvm_v16i8_ty,
llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pmovzxb_q_256 : GCCBuiltin<"__builtin_ia32_pmovzxbq256_mask">,
Intrinsic<[llvm_v4i64_ty], [llvm_v16i8_ty,
llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pmovzxb_q_512 : GCCBuiltin<"__builtin_ia32_pmovzxbq512_mask">,
Intrinsic<[llvm_v8i64_ty], [llvm_v16i8_ty,
llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pmovzxb_w_128 : GCCBuiltin<"__builtin_ia32_pmovzxbw128_mask">,
Intrinsic<[llvm_v8i16_ty], [llvm_v16i8_ty,
llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pmovzxb_w_256 : GCCBuiltin<"__builtin_ia32_pmovzxbw256_mask">,
Intrinsic<[llvm_v16i16_ty], [llvm_v16i8_ty,
llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pmovzxb_w_512 : GCCBuiltin<"__builtin_ia32_pmovzxbw512_mask">,
Intrinsic<[llvm_v32i16_ty], [llvm_v32i8_ty,
llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pmovzxd_q_128 : GCCBuiltin<"__builtin_ia32_pmovzxdq128_mask">,
Intrinsic<[llvm_v2i64_ty], [llvm_v4i32_ty,
llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pmovzxd_q_256 : GCCBuiltin<"__builtin_ia32_pmovzxdq256_mask">,
Intrinsic<[llvm_v4i64_ty], [llvm_v4i32_ty,
llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pmovzxd_q_512 : GCCBuiltin<"__builtin_ia32_pmovzxdq512_mask">,
Intrinsic<[llvm_v8i64_ty], [llvm_v8i32_ty,
llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pmovzxw_d_128 : GCCBuiltin<"__builtin_ia32_pmovzxwd128_mask">,
Intrinsic<[llvm_v4i32_ty], [llvm_v8i16_ty,
llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pmovzxw_d_256 : GCCBuiltin<"__builtin_ia32_pmovzxwd256_mask">,
Intrinsic<[llvm_v8i32_ty], [llvm_v8i16_ty,
llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pmovzxw_d_512 : GCCBuiltin<"__builtin_ia32_pmovzxwd512_mask">,
Intrinsic<[llvm_v16i32_ty], [llvm_v16i16_ty,
llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pmovzxw_q_128 : GCCBuiltin<"__builtin_ia32_pmovzxwq128_mask">,
Intrinsic<[llvm_v2i64_ty], [llvm_v8i16_ty,
llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pmovzxw_q_256 : GCCBuiltin<"__builtin_ia32_pmovzxwq256_mask">,
Intrinsic<[llvm_v4i64_ty], [llvm_v8i16_ty,
llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
def int_x86_avx512_mask_pmovzxw_q_512 : GCCBuiltin<"__builtin_ia32_pmovzxwq512_mask">,
Intrinsic<[llvm_v8i64_ty], [llvm_v8i16_ty,
llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
}
//Bitwise Ops
let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.".

View File

@ -93,6 +93,17 @@ public:
/// tag registered with an LLVMContext has an unique ID.
uint32_t getOperandBundleTagID(StringRef Tag) const;
/// Define the GC for a function
void setGC(const Function &Fn, std::string GCName);
/// Return the GC for a function
const std::string &getGC(const Function &Fn);
/// Remove the GC for a function
void deleteGC(const Function &Fn);
typedef void (*InlineAsmDiagHandlerTy)(const SMDiagnostic&, void *Context,
unsigned LocCookie);

View File

@ -915,11 +915,21 @@ public:
/// \brief Resolve cycles.
///
/// Once all forward declarations have been resolved, force cycles to be
/// resolved. If \p AllowTemps is true, then any temporary metadata
/// is ignored, otherwise it asserts when encountering temporary metadata.
/// resolved. This interface is used when there are no more temporaries,
/// and thus unresolved nodes are part of cycles and no longer need RAUW
/// support.
///
/// \pre No operands (or operands' operands, etc.) have \a isTemporary().
void resolveCycles(bool AllowTemps = false);
void resolveCycles() { resolveRecursivelyImpl(/* AllowTemps */ false); }
/// \brief Resolve cycles while ignoring temporaries.
///
/// This drops RAUW support for any temporaries, which can no longer
/// be uniqued.
///
void resolveNonTemporaries() {
resolveRecursivelyImpl(/* AllowTemps */ true);
}
/// \brief Replace a temporary node with a permanent one.
///
@ -977,6 +987,11 @@ private:
void decrementUnresolvedOperandCount();
unsigned countUnresolvedOperands();
/// Resolve cycles recursively. If \p AllowTemps is true, then any temporary
/// metadata is ignored, otherwise it asserts when encountering temporary
/// metadata.
void resolveRecursivelyImpl(bool AllowTemps);
/// \brief Mutate this to be "uniqued".
///
/// Mutate this so that \a isUniqued().

View File

@ -132,7 +132,6 @@ void initializeEarlyCSELegacyPassPass(PassRegistry &);
void initializeEliminateAvailableExternallyPass(PassRegistry&);
void initializeExpandISelPseudosPass(PassRegistry&);
void initializeForceFunctionAttrsLegacyPassPass(PassRegistry&);
void initializeFunctionAttrsPass(PassRegistry&);
void initializeGCMachineCodeAnalysisPass(PassRegistry&);
void initializeGCModuleInfoPass(PassRegistry&);
void initializeGVNPass(PassRegistry&);
@ -227,6 +226,7 @@ void initializePostDomOnlyViewerPass(PassRegistry&);
void initializePostDomPrinterPass(PassRegistry&);
void initializePostDomViewerPass(PassRegistry&);
void initializePostDominatorTreePass(PassRegistry&);
void initializePostOrderFunctionAttrsPass(PassRegistry&);
void initializePostRASchedulerPass(PassRegistry&);
void initializePostMachineSchedulerPass(PassRegistry&);
void initializePrintFunctionPassWrapperPass(PassRegistry&);
@ -242,6 +242,7 @@ void initializeRegionOnlyPrinterPass(PassRegistry&);
void initializeRegionOnlyViewerPass(PassRegistry&);
void initializeRegionPrinterPass(PassRegistry&);
void initializeRegionViewerPass(PassRegistry&);
void initializeReversePostOrderFunctionAttrsPass(PassRegistry&);
void initializeRewriteStatepointsForGCPass(PassRegistry&);
void initializeSafeStackPass(PassRegistry&);
void initializeSCCPPass(PassRegistry&);

View File

@ -157,7 +157,8 @@ namespace {
(void) llvm::createPostDomTree();
(void) llvm::createInstructionNamerPass();
(void) llvm::createMetaRenamerPass();
(void) llvm::createFunctionAttrsPass();
(void) llvm::createPostOrderFunctionAttrsPass();
(void) llvm::createReversePostOrderFunctionAttrsPass();
(void) llvm::createMergeFunctionsPass();
(void) llvm::createPrintModulePass(*(llvm::raw_ostream*)nullptr);
(void) llvm::createPrintFunctionPass(*(llvm::raw_ostream*)nullptr);

View File

@ -67,10 +67,9 @@ public:
DenseMap<unsigned, MDNode *> *ValIDToTempMDMap);
};
/// Create a new module with exported local functions renamed and promoted
/// for ThinLTO.
std::unique_ptr<Module> renameModuleForThinLTO(std::unique_ptr<Module> M,
const FunctionInfoIndex *Index);
/// Perform in-place global value handling on the given Module for
/// exported local functions renamed and promoted for ThinLTO.
bool renameModuleForThinLTO(Module &M, const FunctionInfoIndex *Index);
} // End llvm namespace

View File

@ -290,6 +290,9 @@ public:
VK_Hexagon_LD_PLT,
VK_Hexagon_IE,
VK_Hexagon_IE_GOT,
VK_WebAssembly_FUNCTION, // Function table index, rather than virtual addr
VK_TPREL,
VK_DTPREL
};

View File

@ -92,6 +92,7 @@ protected:
MCSection *DwarfLocSection;
MCSection *DwarfARangesSection;
MCSection *DwarfRangesSection;
MCSection *DwarfMacinfoSection;
// The pubnames section is no longer generated by default. The generation
// can be enabled by a compiler flag.
MCSection *DwarfPubNamesSection;
@ -245,6 +246,7 @@ public:
MCSection *getDwarfLocSection() const { return DwarfLocSection; }
MCSection *getDwarfARangesSection() const { return DwarfARangesSection; }
MCSection *getDwarfRangesSection() const { return DwarfRangesSection; }
MCSection *getDwarfMacinfoSection() const { return DwarfMacinfoSection; }
// DWARF5 Experimental Debug Info Sections
MCSection *getDwarfAccelNamesSection() const {

View File

@ -131,6 +131,10 @@ public:
void finish() override;
/// Reset any state between object emissions, i.e. the equivalent of
/// MCStreamer's reset method.
virtual void reset();
/// Callback used to implement the ldr= pseudo.
/// Add a new entry to the constant pool for the current section and return an
/// MCExpr that can be used to refer to the constant pool location.

View File

@ -858,6 +858,9 @@ public:
std::error_code getExportRVA(uint32_t &Result) const;
std::error_code getSymbolName(StringRef &Result) const;
std::error_code isForwarder(bool &Result) const;
std::error_code getForwardTo(StringRef &Result) const;
private:
const export_directory_table_entry *ExportTable;
uint32_t Index;

View File

@ -842,6 +842,8 @@ StringRef ELFObjectFile<ELFT>::getFileFormatName() const {
case ELF::EM_SPARC:
case ELF::EM_SPARC32PLUS:
return "ELF32-sparc";
case ELF::EM_WEBASSEMBLY:
return "ELF32-wasm";
default:
return "ELF32-unknown";
}
@ -861,6 +863,8 @@ StringRef ELFObjectFile<ELFT>::getFileFormatName() const {
return "ELF64-sparc";
case ELF::EM_MIPS:
return "ELF64-mips";
case ELF::EM_WEBASSEMBLY:
return "ELF64-wasm";
default:
return "ELF64-unknown";
}
@ -908,6 +912,12 @@ unsigned ELFObjectFile<ELFT>::getArch() const {
return IsLittleEndian ? Triple::sparcel : Triple::sparc;
case ELF::EM_SPARCV9:
return Triple::sparcv9;
case ELF::EM_WEBASSEMBLY:
switch (EF.getHeader()->e_ident[ELF::EI_CLASS]) {
case ELF::ELFCLASS32: return Triple::wasm32;
case ELF::ELFCLASS64: return Triple::wasm64;
default: return Triple::UnknownArch;
}
default:
return Triple::UnknownArch;

View File

@ -369,6 +369,10 @@ protected:
/// @brief This is the storage for the -time-passes option.
extern bool TimePassesIsEnabled;
/// isFunctionInPrintList - returns true if a function should be printed via
// debugging options like -print-after-all/-print-before-all.
// @brief Tells if the function IR should be printed by PrinterPass.
extern bool isFunctionInPrintList(StringRef FunctionName);
} // End llvm namespace
// Include support files that contain important APIs commonly used by Passes,

View File

@ -20,12 +20,33 @@
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/Triple.h"
#include "llvm/ADT/iterator.h"
#include "llvm/ProfileData/InstrProf.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/raw_ostream.h"
#include <system_error>
#include <tuple>
namespace llvm {
namespace coverage {
enum class coveragemap_error {
success = 0,
eof,
no_data_found,
unsupported_version,
truncated,
malformed
};
} // end of coverage namespace.
}
namespace std {
template <>
struct is_error_code_enum<llvm::coverage::coveragemap_error> : std::true_type {
};
}
namespace llvm {
class IndexedInstrProfReader;
namespace coverage {
@ -35,8 +56,6 @@ class CoverageMappingReader;
class CoverageMapping;
struct CounterExpressions;
enum CoverageMappingVersion { CoverageMappingVersion1 };
/// \brief A Counter is an abstract value that describes how to compute the
/// execution count for a region of code using the collected profile count data.
struct Counter {
@ -454,6 +473,76 @@ public:
CoverageData getCoverageForExpansion(const ExpansionRecord &Expansion);
};
const std::error_category &coveragemap_category();
inline std::error_code make_error_code(coveragemap_error E) {
return std::error_code(static_cast<int>(E), coveragemap_category());
}
// Profile coverage map has the following layout:
// [CoverageMapFileHeader]
// [ArrayStart]
// [CovMapFunctionRecord]
// [CovMapFunctionRecord]
// ...
// [ArrayEnd]
// [Encoded Region Mapping Data]
LLVM_PACKED_START
template <class IntPtrT> struct CovMapFunctionRecord {
#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Type Name;
#include "llvm/ProfileData/InstrProfData.inc"
// Return the structural hash associated with the function.
template <support::endianness Endian> uint64_t getFuncHash() const {
return support::endian::byte_swap<uint64_t, Endian>(FuncHash);
}
// Return the coverage map data size for the funciton.
template <support::endianness Endian> uint32_t getDataSize() const {
return support::endian::byte_swap<uint32_t, Endian>(DataSize);
}
// Return function lookup key. The value is consider opaque.
template <support::endianness Endian> IntPtrT getFuncNameRef() const {
return support::endian::byte_swap<IntPtrT, Endian>(NamePtr);
}
// Return the PGO name of the function */
template <support::endianness Endian>
std::error_code getFuncName(InstrProfSymtab &ProfileNames,
StringRef &FuncName) const {
IntPtrT NameRef = getFuncNameRef<Endian>();
uint32_t NameS = support::endian::byte_swap<uint32_t, Endian>(NameSize);
FuncName = ProfileNames.getFuncName(NameRef, NameS);
if (NameS && FuncName.empty())
return coveragemap_error::malformed;
return std::error_code();
}
};
// Per module coverage mapping data header, i.e. CoverageMapFileHeader
// documented above.
struct CovMapHeader {
#define COVMAP_HEADER(Type, LLVMType, Name, Init) Type Name;
#include "llvm/ProfileData/InstrProfData.inc"
template <support::endianness Endian> uint32_t getNRecords() const {
return support::endian::byte_swap<uint32_t, Endian>(NRecords);
}
template <support::endianness Endian> uint32_t getFilenamesSize() const {
return support::endian::byte_swap<uint32_t, Endian>(FilenamesSize);
}
template <support::endianness Endian> uint32_t getCoverageSize() const {
return support::endian::byte_swap<uint32_t, Endian>(CoverageSize);
}
template <support::endianness Endian> uint32_t getVersion() const {
return support::endian::byte_swap<uint32_t, Endian>(Version);
}
};
LLVM_PACKED_END
enum CoverageMappingVersion {
CoverageMappingVersion1 = 0,
// The current versin is Version1
CoverageMappingCurrentVersion = INSTR_PROF_COVMAP_VERSION
};
} // end namespace coverage
/// \brief Provide DenseMapInfo for CounterExpression
@ -484,26 +573,6 @@ template<> struct DenseMapInfo<coverage::CounterExpression> {
}
};
const std::error_category &coveragemap_category();
enum class coveragemap_error {
success = 0,
eof,
no_data_found,
unsupported_version,
truncated,
malformed
};
inline std::error_code make_error_code(coveragemap_error E) {
return std::error_code(static_cast<int>(E), coveragemap_category());
}
} // end namespace llvm
namespace std {
template <>
struct is_error_code_enum<llvm::coveragemap_error> : std::true_type {};
}
#endif // LLVM_PROFILEDATA_COVERAGEMAPPING_H_

View File

@ -30,7 +30,6 @@
#include <system_error>
#include <vector>
#define INSTR_PROF_INDEX_VERSION 3
namespace llvm {
class Function;
@ -66,7 +65,8 @@ inline StringRef getInstrProfValueProfFuncName() {
/// Return the name of the section containing function coverage mapping
/// data.
inline StringRef getInstrProfCoverageSectionName(bool AddSegment) {
return AddSegment ? "__DATA,__llvm_covmap" : "__llvm_covmap";
return AddSegment ? "__DATA," INSTR_PROF_COVMAP_SECT_NAME_STR
: INSTR_PROF_COVMAP_SECT_NAME_STR;
}
/// Return the name prefix of variables containing instrumented function names.
@ -89,6 +89,12 @@ inline StringRef getCoverageMappingVarName() {
return "__llvm_coverage_mapping";
}
/// Return the name of the internal variable recording the array
/// of PGO name vars referenced by the coverage mapping, The owning
/// functions of those names are not emitted by FE (e.g, unused inline
/// functions.)
inline StringRef getCoverageNamesVarName() { return "__llvm_coverage_names"; }
/// Return the name of function that registers all the per-function control
/// data at program startup time by calling __llvm_register_function. This
/// function has internal linkage and is called by __llvm_profile_init
@ -349,11 +355,14 @@ struct InstrProfValueSiteRecord {
return left.Value < right.Value;
});
}
/// Sort ValueData Descending by Count
inline void sortByCount();
/// Merge data from another InstrProfValueSiteRecord
/// Optionally scale merged counts by \p Weight.
instrprof_error mergeValueData(InstrProfValueSiteRecord &Input,
uint64_t Weight = 1);
instrprof_error merge(InstrProfValueSiteRecord &Input, uint64_t Weight = 1);
/// Scale up value profile data counts.
instrprof_error scale(uint64_t Weight);
};
/// Profiling information for a single function.
@ -396,6 +405,19 @@ struct InstrProfRecord {
/// Optionally scale merged counts by \p Weight.
instrprof_error merge(InstrProfRecord &Other, uint64_t Weight = 1);
/// Scale up profile counts (including value profile data) by
/// \p Weight.
instrprof_error scale(uint64_t Weight);
/// Sort value profile data (per site) by count.
void sortValueData() {
for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) {
std::vector<InstrProfValueSiteRecord> &SiteRecords =
getValueSitesForKind(Kind);
for (auto &SR : SiteRecords)
SR.sortByCount();
}
}
/// Clear value data entries
void clearValueData() {
for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind)
@ -430,6 +452,8 @@ private:
// Scale merged value counts by \p Weight.
instrprof_error mergeValueProfData(uint32_t ValueKind, InstrProfRecord &Src,
uint64_t Weight);
// Scale up value profile data count.
instrprof_error scaleValueProfData(uint32_t ValueKind, uint64_t Weight);
};
uint32_t InstrProfRecord::getNumValueKinds() const {
@ -497,11 +521,22 @@ inline support::endianness getHostEndianness() {
#define INSTR_PROF_VALUE_PROF_DATA
#include "llvm/ProfileData/InstrProfData.inc"
/*
* Initialize the record for runtime value profile data.
* Return 0 if the initialization is successful, otherwise
* return 1.
*/
void InstrProfValueSiteRecord::sortByCount() {
ValueData.sort(
[](const InstrProfValueData &left, const InstrProfValueData &right) {
return left.Count > right.Count;
});
// Now truncate
size_t max_s = INSTR_PROF_MAX_NUM_VAL_PER_SITE;
if (ValueData.size() > max_s)
ValueData.resize(max_s);
}
/*
* Initialize the record for runtime value profile data.
* Return 0 if the initialization is successful, otherwise
* return 1.
*/
int initializeValueProfRuntimeRecord(ValueProfRuntimeRecord *RuntimeRecord,
const uint16_t *NumValueSites,
ValueProfNode **Nodes);
@ -597,31 +632,6 @@ struct Header {
} // end namespace RawInstrProf
namespace coverage {
// Profile coverage map has the following layout:
// [CoverageMapFileHeader]
// [ArrayStart]
// [CovMapFunctionRecord]
// [CovMapFunctionRecord]
// ...
// [ArrayEnd]
// [Encoded Region Mapping Data]
LLVM_PACKED_START
template <class IntPtrT> struct CovMapFunctionRecord {
#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Type Name;
#include "llvm/ProfileData/InstrProfData.inc"
};
// Per module coverage mapping data header, i.e. CoverageMapFileHeader
// documented above.
struct CovMapHeader {
#define COVMAP_HEADER(Type, LLVMType, Name, Init) Type Name;
#include "llvm/ProfileData/InstrProfData.inc"
};
LLVM_PACKED_END
}
} // end namespace llvm
namespace std {

View File

@ -28,7 +28,7 @@
*
* Examples of how the template is used to instantiate structure definition:
* 1. To declare a structure:
*
*
* struct ProfData {
* #define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer) \
* Type Name;
@ -155,7 +155,7 @@ VALUE_PROF_KIND(IPVK_Last, IPVK_IndirectCallTarget)
#endif
COVMAP_FUNC_RECORD(const IntPtrT, llvm::Type::getInt8PtrTy(Ctx), \
NamePtr, llvm::ConstantExpr::getBitCast(NamePtr, \
llvm::Type::getInt8PtrTy(Ctx)))
llvm::Type::getInt8PtrTy(Ctx)))
COVMAP_FUNC_RECORD(const uint32_t, llvm::Type::getInt32Ty(Ctx), NameSize, \
llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx),\
NameValue.size()))
@ -182,7 +182,7 @@ COVMAP_HEADER(uint32_t, Int32Ty, FilenamesSize, \
COVMAP_HEADER(uint32_t, Int32Ty, CoverageSize, \
llvm::ConstantInt::get(Int32Ty, CoverageMappingSize))
COVMAP_HEADER(uint32_t, Int32Ty, Version, \
llvm::ConstantInt::get(Int32Ty, CoverageMappingVersion1))
llvm::ConstantInt::get(Int32Ty, CoverageMappingCurrentVersion))
#undef COVMAP_HEADER
/* COVMAP_HEADER end. */
@ -190,7 +190,8 @@ COVMAP_HEADER(uint32_t, Int32Ty, Version, \
#ifdef INSTR_PROF_VALUE_PROF_DATA
#define INSTR_PROF_DATA_DEFINED
/*!
#define INSTR_PROF_MAX_NUM_VAL_PER_SITE 255
/*!
* This is the header of the data structure that defines the on-disk
* layout of the value profile data of a particular kind for one function.
*/
@ -202,7 +203,7 @@ typedef struct ValueProfRecord {
* otherwise the record for this kind won't be emitted.
*/
uint32_t NumValueSites;
/*
/*
* The first element of the array that stores the number of profiled
* values for each value site. The size of the array is NumValueSites.
* Since NumValueSites is greater than zero, there is at least one
@ -226,7 +227,7 @@ typedef struct ValueProfRecord {
* \brief Return the number of value sites.
*/
uint32_t getNumValueSites() const { return NumValueSites; }
/*!
/*!
* \brief Read data from this record and save it to Record.
*/
void deserializeTo(InstrProfRecord &Record,
@ -247,10 +248,10 @@ typedef struct ValueProfRecord {
typedef struct ValueProfData {
/*
* Total size in bytes including this field. It must be a multiple
* of sizeof(uint64_t).
* of sizeof(uint64_t).
*/
uint32_t TotalSize;
/*
/*
*The number of value profile kinds that has value profile data.
* In this implementation, a value profile kind is considered to
* have profile data if the number of value profile sites for the
@ -260,7 +261,7 @@ typedef struct ValueProfData {
*/
uint32_t NumValueKinds;
/*
/*
* Following are a sequence of variable length records. The prefix/header
* of each record is defined by ValueProfRecord type. The number of
* records is NumValueKinds.
@ -314,7 +315,7 @@ typedef struct ValueProfData {
#endif
} ValueProfData;
/*
/*
* The closure is designed to abstact away two types of value profile data:
* - InstrProfRecord which is the primary data structure used to
* represent profile data in host tools (reader, writer, and profile-use)
@ -335,7 +336,7 @@ typedef struct ValueProfRecordClosure {
uint32_t (*GetNumValueData)(const void *Record, uint32_t VKind);
uint32_t (*GetNumValueDataForSite)(const void *R, uint32_t VK, uint32_t S);
/*
/*
* After extracting the value profile data from the value profile record,
* this method is used to map the in-memory value to on-disk value. If
* the method is null, value will be written out untranslated.
@ -346,7 +347,7 @@ typedef struct ValueProfRecordClosure {
ValueProfData *(*AllocValueProfData)(size_t TotalSizeInBytes);
} ValueProfRecordClosure;
/*
/*
* A wrapper struct that represents value profile runtime data.
* Like InstrProfRecord class which is used by profiling host tools,
* ValueProfRuntimeRecord also implements the abstract intefaces defined in
@ -384,7 +385,7 @@ serializeValueProfDataFromRT(const ValueProfRuntimeRecord *Record,
uint32_t getNumValueKindsRT(const void *R);
#undef INSTR_PROF_VALUE_PROF_DATA
#endif /* INSTR_PROF_VALUE_PROF_DATA */
#endif /* INSTR_PROF_VALUE_PROF_DATA */
#ifdef INSTR_PROF_COMMON_API_IMPL
@ -412,7 +413,7 @@ uint32_t getValueProfRecordHeaderSize(uint32_t NumValueSites) {
return Size;
}
/*!
/*!
* \brief Return the total size of the value profile record including the
* header and the value data.
*/
@ -432,7 +433,7 @@ InstrProfValueData *getValueProfRecordValueData(ValueProfRecord *This) {
This->NumValueSites));
}
/*!
/*!
* \brief Return the total number of value data for \c This record.
*/
INSTR_PROF_INLINE
@ -444,7 +445,7 @@ uint32_t getValueProfRecordNumValueData(ValueProfRecord *This) {
return NumValueData;
}
/*!
/*!
* \brief Use this method to advance to the next \c This \c ValueProfRecord.
*/
INSTR_PROF_INLINE
@ -465,7 +466,7 @@ ValueProfRecord *getFirstValueProfRecord(ValueProfData *This) {
/* Closure based interfaces. */
/*!
/*!
* Return the total size in bytes of the on-disk value profile data
* given the data stored in Record.
*/
@ -535,7 +536,7 @@ ValueProfData *serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
return VPD;
}
/*
/*
* The value profiler runtime library stores the value profile data
* for a given function in \c NumValueSites and \c Nodes structures.
* \c ValueProfRuntimeRecord class is used to encapsulate the runtime
@ -639,7 +640,7 @@ static ValueProfRecordClosure RTRecordClosure = {0,
getValueForSiteRT,
allocValueProfDataRT};
/*
/*
* Return the size of ValueProfData structure to store data
* recorded in the runtime record.
*/
@ -648,7 +649,7 @@ uint32_t getValueProfDataSizeRT(const ValueProfRuntimeRecord *Record) {
return getValueProfDataSize(&RTRecordClosure);
}
/*
/*
* Return a ValueProfData instance that stores the data collected
* from runtime. If \c DstData is provided by the caller, the value
* profile data will be store in *DstData and DstData is returned,
@ -696,18 +697,31 @@ serializeValueProfDataFromRT(const ValueProfRuntimeRecord *Record,
/* Raw profile format version. */
#define INSTR_PROF_RAW_VERSION 2
#define INSTR_PROF_INDEX_VERSION 3
#define INSTR_PROF_COVMAP_VERSION 0
/* Profile version is always of type uint_64_t. Reserve the upper 8 bits in the
* version for other variants of profile. We set the lowest bit of the upper 8
* bits (i.e. bit 56) to 1 to indicate if this is an IR-level instrumentaiton
* generated profile, and 0 if this is a Clang FE generated profile.
*/
#define VARIANT_MASKS_ALL 0xff00000000000000ULL
#define GET_VERSION(V) ((V) & ~VARIANT_MASKS_ALL)
/* Runtime section names and name strings. */
#define INSTR_PROF_DATA_SECT_NAME __llvm_prf_data
#define INSTR_PROF_NAME_SECT_NAME __llvm_prf_names
#define INSTR_PROF_CNTS_SECT_NAME __llvm_prf_cnts
#define INSTR_PROF_COVMAP_SECT_NAME __llvm_covmap
#define INSTR_PROF_DATA_SECT_NAME_STR \
INSTR_PROF_QUOTE(INSTR_PROF_DATA_SECT_NAME)
#define INSTR_PROF_NAME_SECT_NAME_STR \
INSTR_PROF_QUOTE(INSTR_PROF_NAME_SECT_NAME)
#define INSTR_PROF_CNTS_SECT_NAME_STR \
INSTR_PROF_QUOTE(INSTR_PROF_CNTS_SECT_NAME)
#define INSTR_PROF_DATA_SECT_NAME_STR \
INSTR_PROF_QUOTE(INSTR_PROF_DATA_SECT_NAME)
#define INSTR_PROF_NAME_SECT_NAME_STR \
INSTR_PROF_QUOTE(INSTR_PROF_NAME_SECT_NAME)
#define INSTR_PROF_CNTS_SECT_NAME_STR \
INSTR_PROF_QUOTE(INSTR_PROF_CNTS_SECT_NAME)
#define INSTR_PROF_COVMAP_SECT_NAME_STR \
INSTR_PROF_QUOTE(INSTR_PROF_COVMAP_SECT_NAME)
/* Macros to define start/stop section symbol for a given
* section on Linux. For instance
@ -751,4 +765,3 @@ typedef struct ValueProfNode {
#else
#undef INSTR_PROF_DATA_DEFINED
#endif

View File

@ -140,16 +140,9 @@ public:
/// around unsigned integers.
sampleprof_error addSamples(uint64_t S, uint64_t Weight = 1) {
bool Overflowed;
if (Weight > 1) {
S = SaturatingMultiply(S, Weight, &Overflowed);
if (Overflowed)
return sampleprof_error::counter_overflow;
}
NumSamples = SaturatingAdd(NumSamples, S, &Overflowed);
if (Overflowed)
return sampleprof_error::counter_overflow;
return sampleprof_error::success;
NumSamples = SaturatingMultiplyAdd(S, Weight, NumSamples, &Overflowed);
return Overflowed ? sampleprof_error::counter_overflow
: sampleprof_error::success;
}
/// Add called function \p F with samples \p S.
@ -161,16 +154,10 @@ public:
uint64_t Weight = 1) {
uint64_t &TargetSamples = CallTargets[F];
bool Overflowed;
if (Weight > 1) {
S = SaturatingMultiply(S, Weight, &Overflowed);
if (Overflowed)
return sampleprof_error::counter_overflow;
}
TargetSamples = SaturatingAdd(TargetSamples, S, &Overflowed);
if (Overflowed)
return sampleprof_error::counter_overflow;
return sampleprof_error::success;
TargetSamples =
SaturatingMultiplyAdd(S, Weight, TargetSamples, &Overflowed);
return Overflowed ? sampleprof_error::counter_overflow
: sampleprof_error::success;
}
/// Return true if this sample record contains function calls.
@ -215,29 +202,17 @@ public:
void dump() const;
sampleprof_error addTotalSamples(uint64_t Num, uint64_t Weight = 1) {
bool Overflowed;
if (Weight > 1) {
Num = SaturatingMultiply(Num, Weight, &Overflowed);
if (Overflowed)
return sampleprof_error::counter_overflow;
}
TotalSamples = SaturatingAdd(TotalSamples, Num, &Overflowed);
if (Overflowed)
return sampleprof_error::counter_overflow;
return sampleprof_error::success;
TotalSamples =
SaturatingMultiplyAdd(Num, Weight, TotalSamples, &Overflowed);
return Overflowed ? sampleprof_error::counter_overflow
: sampleprof_error::success;
}
sampleprof_error addHeadSamples(uint64_t Num, uint64_t Weight = 1) {
bool Overflowed;
if (Weight > 1) {
Num = SaturatingMultiply(Num, Weight, &Overflowed);
if (Overflowed)
return sampleprof_error::counter_overflow;
}
TotalHeadSamples = SaturatingAdd(TotalHeadSamples, Num, &Overflowed);
if (Overflowed)
return sampleprof_error::counter_overflow;
return sampleprof_error::success;
TotalHeadSamples =
SaturatingMultiplyAdd(Num, Weight, TotalHeadSamples, &Overflowed);
return Overflowed ? sampleprof_error::counter_overflow
: sampleprof_error::success;
}
sampleprof_error addBodySamples(uint32_t LineOffset, uint32_t Discriminator,
uint64_t Num, uint64_t Weight = 1) {

View File

@ -96,7 +96,7 @@ ARM_ARCH("iwmmxt", AK_IWMMXT, "iwmmxt", "", ARMBuildAttrs::CPUArch::v5TE,
FK_NONE, AEK_NONE)
ARM_ARCH("iwmmxt2", AK_IWMMXT2, "iwmmxt2", "", ARMBuildAttrs::CPUArch::v5TE,
FK_NONE, AEK_NONE)
ARM_ARCH("xscale", AK_XSCALE, "xscale", "", ARMBuildAttrs::CPUArch::v5TE,
ARM_ARCH("xscale", AK_XSCALE, "xscale", "v5e", ARMBuildAttrs::CPUArch::v5TE,
FK_NONE, AEK_NONE)
ARM_ARCH("armv7s", AK_ARMV7S, "7-S", "v7s", ARMBuildAttrs::CPUArch::v7,
FK_NEON_VFPV4, AEK_DSP)

View File

@ -187,6 +187,7 @@ public:
/// \brief Deallocate all but the current slab and reset the current pointer
/// to the beginning of it, freeing all memory allocated so far.
void Reset() {
// Deallocate all but the first slab, and deallocate all custom-sized slabs.
DeallocateCustomSizedSlabs();
CustomSizedSlabs.clear();
@ -198,7 +199,7 @@ public:
CurPtr = (char *)Slabs.front();
End = CurPtr + SlabSize;
// Deallocate all but the first slab, and deallocate all custom-sized slabs.
__asan_poison_memory_region(*Slabs.begin(), computeSlabSize(0));
DeallocateSlabs(std::next(Slabs.begin()), Slabs.end());
Slabs.erase(std::next(Slabs.begin()), Slabs.end());
}

View File

@ -656,6 +656,15 @@ namespace COFF {
}
};
enum CodeViewLine : unsigned {
CVL_LineNumberStartBits = 24,
CVL_LineNumberEndDeltaBits = 7,
CVL_LineNumberEndDeltaMask = (1U << CVL_LineNumberEndDeltaBits) - 1,
CVL_MaxLineNumber = (1U << CVL_LineNumberStartBits) - 1,
CVL_IsStatement = 1U << 31,
CVL_MaxColumnNumber = UINT16_MAX,
};
enum CodeViewIdentifiers {
DEBUG_LINE_TABLES_HAVE_COLUMN_RECORDS = 0x1,
DEBUG_SECTION_MAGIC = 0x4,

View File

@ -309,7 +309,12 @@ enum {
EM_COOL = 217, // iCelero CoolEngine
EM_NORC = 218, // Nanoradio Optimized RISC
EM_CSR_KALIMBA = 219, // CSR Kalimba architecture family
EM_AMDGPU = 224 // AMD GPU architecture
EM_AMDGPU = 224, // AMD GPU architecture
// A request has been made to the maintainer of the official registry for
// such numbers for an official value for WebAssembly. As soon as one is
// allocated, this enum will be updated to use it.
EM_WEBASSEMBLY = 0x4157, // WebAssembly architecture
};
// Object file classes.
@ -594,6 +599,11 @@ enum {
#include "ELFRelocs/Sparc.def"
};
// ELF Relocation types for WebAssembly
enum {
#include "ELFRelocs/WebAssembly.def"
};
#undef ELF_RELOC
// Section header.
@ -1024,7 +1034,10 @@ enum {
PT_AMDGPU_HSA_LOAD_GLOBAL_PROGRAM = 0x60000000,
PT_AMDGPU_HSA_LOAD_GLOBAL_AGENT = 0x60000001,
PT_AMDGPU_HSA_LOAD_READONLY_AGENT = 0x60000002,
PT_AMDGPU_HSA_LOAD_CODE_AGENT = 0x60000003
PT_AMDGPU_HSA_LOAD_CODE_AGENT = 0x60000003,
// WebAssembly program header types.
PT_WEBASSEMBLY_FUNCTIONS = PT_LOPROC + 0, // Function definitions.
};
// Segment flag bits.

View File

@ -0,0 +1,8 @@
#ifndef ELF_RELOC
#error "ELF_RELOC must be defined"
#endif
ELF_RELOC(R_WEBASSEMBLY_NONE, 0)
ELF_RELOC(R_WEBASSEMBLY_DATA, 1)
ELF_RELOC(R_WEBASSEMBLY_FUNCTION, 2)

View File

@ -724,25 +724,17 @@ public:
if (!this->IsPostDominators) {
// Initialize root
NodeT *entry = TraitsTy::getEntryNode(&F);
this->Roots.push_back(entry);
this->IDoms[entry] = nullptr;
this->DomTreeNodes[entry] = nullptr;
addRoot(entry);
Calculate<FT, NodeT *>(*this, F);
} else {
// Initialize the roots list
for (typename TraitsTy::nodes_iterator I = TraitsTy::nodes_begin(&F),
E = TraitsTy::nodes_end(&F);
I != E; ++I) {
I != E; ++I)
if (TraitsTy::child_begin(&*I) == TraitsTy::child_end(&*I))
addRoot(&*I);
// Prepopulate maps so that we don't get iterator invalidation issues
// later.
this->IDoms[&*I] = nullptr;
this->DomTreeNodes[&*I] = nullptr;
}
Calculate<FT, Inverse<NodeT *>>(*this, F);
}
}

View File

@ -717,6 +717,25 @@ SaturatingMultiply(T X, T Y, bool *ResultOverflowed = nullptr) {
return Z;
}
/// \brief Multiply two unsigned integers, X and Y, and add the unsigned
/// integer, A to the product. Clamp the result to the maximum representable
/// value of T on overflow. ResultOverflowed indicates if the result is larger
/// than the maximum representable value of type T.
/// Note that this is purely a convenience function as there is no distinction
/// where overflow occurred in a 'fused' multiply-add for unsigned numbers.
template <typename T>
typename std::enable_if<std::is_unsigned<T>::value, T>::type
SaturatingMultiplyAdd(T X, T Y, T A, bool *ResultOverflowed = nullptr) {
bool Dummy;
bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
T Product = SaturatingMultiply(X, Y, &Overflowed);
if (Overflowed)
return Product;
return SaturatingAdd(A, Product, &Overflowed);
}
extern const float huge_valf;
} // End llvm namespace

View File

@ -183,12 +183,20 @@ ModulePass *createBlockExtractorPass();
ModulePass *createStripDeadPrototypesPass();
//===----------------------------------------------------------------------===//
/// createFunctionAttrsPass - This pass discovers functions that do not access
/// memory, or only read memory, and gives them the readnone/readonly attribute.
/// It also discovers function arguments that are not captured by the function
/// and marks them with the nocapture attribute.
/// createPostOrderFunctionAttrsPass - This pass walks SCCs of the call graph
/// in post-order to deduce and propagate function attributes. It can discover
/// functions that do not access memory, or only read memory, and give them the
/// readnone/readonly attribute. It also discovers function arguments that are
/// not captured by the function and marks them with the nocapture attribute.
///
Pass *createFunctionAttrsPass();
Pass *createPostOrderFunctionAttrsPass();
//===----------------------------------------------------------------------===//
/// createReversePostOrderFunctionAttrsPass - This pass walks SCCs of the call
/// graph in RPO to deduce and propagate function attributes. Currently it
/// only handles synthesizing norecurse attributes.
///
Pass *createReversePostOrderFunctionAttrsPass();
//===----------------------------------------------------------------------===//
/// createMergeFunctionsPass - This pass discovers identical functions and

View File

@ -147,42 +147,12 @@ void CloneFunctionInto(Function *NewFunc, const Function *OldFunc,
ValueMapTypeRemapper *TypeMapper = nullptr,
ValueMaterializer *Materializer = nullptr);
/// A helper class used with CloneAndPruneIntoFromInst to change the default
/// behavior while instructions are being cloned.
class CloningDirector {
public:
/// This enumeration describes the way CloneAndPruneIntoFromInst should
/// proceed after the CloningDirector has examined an instruction.
enum CloningAction {
///< Continue cloning the instruction (default behavior).
CloneInstruction,
///< Skip this instruction but continue cloning the current basic block.
SkipInstruction,
///< Skip this instruction and stop cloning the current basic block.
StopCloningBB,
///< Don't clone the terminator but clone the current block's successors.
CloneSuccessors
};
virtual ~CloningDirector() {}
/// Subclasses must override this function to customize cloning behavior.
virtual CloningAction handleInstruction(ValueToValueMapTy &VMap,
const Instruction *Inst,
BasicBlock *NewBB) = 0;
virtual ValueMapTypeRemapper *getTypeRemapper() { return nullptr; }
virtual ValueMaterializer *getValueMaterializer() { return nullptr; }
};
void CloneAndPruneIntoFromInst(Function *NewFunc, const Function *OldFunc,
const Instruction *StartingInst,
ValueToValueMapTy &VMap, bool ModuleLevelChanges,
SmallVectorImpl<ReturnInst*> &Returns,
const char *NameSuffix = "",
ClonedCodeInfo *CodeInfo = nullptr,
CloningDirector *Director = nullptr);
SmallVectorImpl<ReturnInst *> &Returns,
const char *NameSuffix = "",
ClonedCodeInfo *CodeInfo = nullptr);
/// CloneAndPruneFunctionInto - This works exactly like CloneFunctionInto,
/// except that it does some simple constant prop and DCE on the fly. The

View File

@ -42,6 +42,7 @@ class TargetLibraryInfo;
class TargetTransformInfo;
class DIBuilder;
class DominatorTree;
class LazyValueInfo;
template<typename T> class SmallVectorImpl;
@ -303,7 +304,7 @@ void removeUnwindEdge(BasicBlock *BB);
/// \brief Remove all blocks that can not be reached from the function's entry.
///
/// Returns true if any basic block was removed.
bool removeUnreachableBlocks(Function &F);
bool removeUnreachableBlocks(Function &F, LazyValueInfo *LVI = nullptr);
/// \brief Combine the metadata of two instructions so that K can replace J
///

View File

@ -207,6 +207,7 @@ module LLVM_Utils {
textual header "Support/ELFRelocs/Sparc.def"
textual header "Support/ELFRelocs/SystemZ.def"
textual header "Support/ELFRelocs/x86_64.def"
textual header "Support/ELFRelocs/WebAssembly.def"
}
// This part of the module is usable from both C and C++ code.

View File

@ -586,8 +586,13 @@ FunctionModRefBehavior BasicAAResult::getModRefBehavior(const Function *F) {
return FunctionModRefBehavior(AAResultBase::getModRefBehavior(F) & Min);
}
ModRefInfo BasicAAResult::getArgModRefInfo(ImmutableCallSite CS,
unsigned ArgIdx) {
/// Returns true if this is a writeonly (i.e Mod only) parameter. Currently,
/// we don't have a writeonly attribute, so this only knows about builtin
/// intrinsics and target library functions. We could consider adding a
/// writeonly attribute in the future and moving all of these facts to either
/// Intrinsics.td or InferFunctionAttr.cpp
static bool isWriteOnlyParam(ImmutableCallSite CS, unsigned ArgIdx,
const TargetLibraryInfo &TLI) {
if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(CS.getInstruction()))
switch (II->getIntrinsicID()) {
default:
@ -597,9 +602,9 @@ ModRefInfo BasicAAResult::getArgModRefInfo(ImmutableCallSite CS,
case Intrinsic::memmove:
// We don't currently have a writeonly attribute. All other properties
// of these intrinsics are nicely described via attributes in
// Intrinsics.td and handled generically below.
// Intrinsics.td and handled generically.
if (ArgIdx == 0)
return MRI_Mod;
return true;
}
// We can bound the aliasing properties of memset_pattern16 just as we can
@ -609,7 +614,22 @@ ModRefInfo BasicAAResult::getArgModRefInfo(ImmutableCallSite CS,
// handled via InferFunctionAttr.
if (CS.getCalledFunction() && isMemsetPattern16(CS.getCalledFunction(), TLI))
if (ArgIdx == 0)
return MRI_Mod;
return true;
// TODO: memset_pattern4, memset_pattern8
// TODO: _chk variants
// TODO: strcmp, strcpy
return false;
}
ModRefInfo BasicAAResult::getArgModRefInfo(ImmutableCallSite CS,
unsigned ArgIdx) {
// Emulate the missing writeonly attribute by checking for known builtin
// intrinsics and target library functions.
if (isWriteOnlyParam(CS, ArgIdx, TLI))
return MRI_Mod;
if (CS.paramHasAttr(ArgIdx + 1, Attribute::ReadOnly))
return MRI_Ref;

View File

@ -612,9 +612,10 @@ namespace {
bool runOnSCC(CallGraphSCC &SCC) override {
Out << Banner;
for (CallGraphNode *CGN : SCC) {
if (CGN->getFunction())
CGN->getFunction()->print(Out);
else
if (CGN->getFunction()) {
if (isFunctionInPrintList(CGN->getFunction()->getName()))
CGN->getFunction()->print(Out);
} else
Out << "\nPrinting <null> Function\n";
}
return false;

View File

@ -358,21 +358,6 @@ bool GlobalsAAResult::AnalyzeUsesOfPointer(Value *V,
if (CS.isArgOperand(&U) && isFreeCall(I, &TLI)) {
if (Writers)
Writers->insert(CS->getParent()->getParent());
} else if (CS.doesNotCapture(CS.getDataOperandNo(&U))) {
Function *ParentF = CS->getParent()->getParent();
// A nocapture argument may be read from or written to, but does not
// escape unless the call can somehow recurse.
//
// nocapture "indicates that the callee does not make any copies of
// the pointer that outlive itself". Therefore if we directly or
// indirectly recurse, we must treat the pointer as escaping.
if (FunctionToSCCMap[ParentF] ==
FunctionToSCCMap[CS.getCalledFunction()])
return true;
if (Readers)
Readers->insert(ParentF);
if (Writers)
Writers->insert(ParentF);
} else {
return true; // Argument of an unknown call.
}

View File

@ -70,7 +70,7 @@ static Value *SimplifyOrInst(Value *, Value *, const Query &, unsigned);
static Value *SimplifyXorInst(Value *, Value *, const Query &, unsigned);
static Value *SimplifyTruncInst(Value *, Type *, const Query &, unsigned);
/// getFalse - For a boolean type, or a vector of boolean type, return false, or
/// For a boolean type, or a vector of boolean type, return false, or
/// a vector with every element false, as appropriate for the type.
static Constant *getFalse(Type *Ty) {
assert(Ty->getScalarType()->isIntegerTy(1) &&
@ -78,7 +78,7 @@ static Constant *getFalse(Type *Ty) {
return Constant::getNullValue(Ty);
}
/// getTrue - For a boolean type, or a vector of boolean type, return true, or
/// For a boolean type, or a vector of boolean type, return true, or
/// a vector with every element true, as appropriate for the type.
static Constant *getTrue(Type *Ty) {
assert(Ty->getScalarType()->isIntegerTy(1) &&
@ -100,7 +100,7 @@ static bool isSameCompare(Value *V, CmpInst::Predicate Pred, Value *LHS,
CRHS == LHS;
}
/// ValueDominatesPHI - Does the given value dominate the specified phi node?
/// Does the given value dominate the specified phi node?
static bool ValueDominatesPHI(Value *V, PHINode *P, const DominatorTree *DT) {
Instruction *I = dyn_cast<Instruction>(V);
if (!I)
@ -131,8 +131,8 @@ static bool ValueDominatesPHI(Value *V, PHINode *P, const DominatorTree *DT) {
return false;
}
/// ExpandBinOp - Simplify "A op (B op' C)" by distributing op over op', turning
/// it into "(A op B) op' (A op C)". Here "op" is given by Opcode and "op'" is
/// Simplify "A op (B op' C)" by distributing op over op', turning it into
/// "(A op B) op' (A op C)". Here "op" is given by Opcode and "op'" is
/// given by OpcodeToExpand, while "A" corresponds to LHS and "B op' C" to RHS.
/// Also performs the transform "(A op' B) op C" -> "(A op C) op' (B op C)".
/// Returns the simplified value, or null if no simplification was performed.
@ -193,8 +193,8 @@ static Value *ExpandBinOp(unsigned Opcode, Value *LHS, Value *RHS,
return nullptr;
}
/// SimplifyAssociativeBinOp - Generic simplifications for associative binary
/// operations. Returns the simpler value, or null if none was found.
/// Generic simplifications for associative binary operations.
/// Returns the simpler value, or null if none was found.
static Value *SimplifyAssociativeBinOp(unsigned Opc, Value *LHS, Value *RHS,
const Query &Q, unsigned MaxRecurse) {
Instruction::BinaryOps Opcode = (Instruction::BinaryOps)Opc;
@ -290,10 +290,10 @@ static Value *SimplifyAssociativeBinOp(unsigned Opc, Value *LHS, Value *RHS,
return nullptr;
}
/// ThreadBinOpOverSelect - In the case of a binary operation with a select
/// instruction as an operand, try to simplify the binop by seeing whether
/// evaluating it on both branches of the select results in the same value.
/// Returns the common value if so, otherwise returns null.
/// In the case of a binary operation with a select instruction as an operand,
/// try to simplify the binop by seeing whether evaluating it on both branches
/// of the select results in the same value. Returns the common value if so,
/// otherwise returns null.
static Value *ThreadBinOpOverSelect(unsigned Opcode, Value *LHS, Value *RHS,
const Query &Q, unsigned MaxRecurse) {
// Recursion is always used, so bail out at once if we already hit the limit.
@ -362,10 +362,9 @@ static Value *ThreadBinOpOverSelect(unsigned Opcode, Value *LHS, Value *RHS,
return nullptr;
}
/// ThreadCmpOverSelect - In the case of a comparison with a select instruction,
/// try to simplify the comparison by seeing whether both branches of the select
/// result in the same value. Returns the common value if so, otherwise returns
/// null.
/// In the case of a comparison with a select instruction, try to simplify the
/// comparison by seeing whether both branches of the select result in the same
/// value. Returns the common value if so, otherwise returns null.
static Value *ThreadCmpOverSelect(CmpInst::Predicate Pred, Value *LHS,
Value *RHS, const Query &Q,
unsigned MaxRecurse) {
@ -444,10 +443,10 @@ static Value *ThreadCmpOverSelect(CmpInst::Predicate Pred, Value *LHS,
return nullptr;
}
/// ThreadBinOpOverPHI - In the case of a binary operation with an operand that
/// is a PHI instruction, try to simplify the binop by seeing whether evaluating
/// it on the incoming phi values yields the same result for every value. If so
/// returns the common value, otherwise returns null.
/// In the case of a binary operation with an operand that is a PHI instruction,
/// try to simplify the binop by seeing whether evaluating it on the incoming
/// phi values yields the same result for every value. If so returns the common
/// value, otherwise returns null.
static Value *ThreadBinOpOverPHI(unsigned Opcode, Value *LHS, Value *RHS,
const Query &Q, unsigned MaxRecurse) {
// Recursion is always used, so bail out at once if we already hit the limit.
@ -486,10 +485,10 @@ static Value *ThreadBinOpOverPHI(unsigned Opcode, Value *LHS, Value *RHS,
return CommonValue;
}
/// ThreadCmpOverPHI - In the case of a comparison with a PHI instruction, try
/// try to simplify the comparison by seeing whether comparing with all of the
/// incoming phi values yields the same result every time. If so returns the
/// common result, otherwise returns null.
/// In the case of a comparison with a PHI instruction, try to simplify the
/// comparison by seeing whether comparing with all of the incoming phi values
/// yields the same result every time. If so returns the common result,
/// otherwise returns null.
static Value *ThreadCmpOverPHI(CmpInst::Predicate Pred, Value *LHS, Value *RHS,
const Query &Q, unsigned MaxRecurse) {
// Recursion is always used, so bail out at once if we already hit the limit.
@ -524,8 +523,8 @@ static Value *ThreadCmpOverPHI(CmpInst::Predicate Pred, Value *LHS, Value *RHS,
return CommonValue;
}
/// SimplifyAddInst - Given operands for an Add, see if we can
/// fold the result. If not, this returns null.
/// Given operands for an Add, see if we can fold the result.
/// If not, this returns null.
static Value *SimplifyAddInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW,
const Query &Q, unsigned MaxRecurse) {
if (Constant *CLHS = dyn_cast<Constant>(Op0)) {
@ -656,8 +655,8 @@ static Constant *computePointerDifference(const DataLayout &DL, Value *LHS,
return ConstantExpr::getSub(LHSOffset, RHSOffset);
}
/// SimplifySubInst - Given operands for a Sub, see if we can
/// fold the result. If not, this returns null.
/// Given operands for a Sub, see if we can fold the result.
/// If not, this returns null.
static Value *SimplifySubInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW,
const Query &Q, unsigned MaxRecurse) {
if (Constant *CLHS = dyn_cast<Constant>(Op0))
@ -889,8 +888,8 @@ static Value *SimplifyFMulInst(Value *Op0, Value *Op1,
return nullptr;
}
/// SimplifyMulInst - Given operands for a Mul, see if we can
/// fold the result. If not, this returns null.
/// Given operands for a Mul, see if we can fold the result.
/// If not, this returns null.
static Value *SimplifyMulInst(Value *Op0, Value *Op1, const Query &Q,
unsigned MaxRecurse) {
if (Constant *CLHS = dyn_cast<Constant>(Op0)) {
@ -989,8 +988,8 @@ Value *llvm::SimplifyMulInst(Value *Op0, Value *Op1, const DataLayout &DL,
RecursionLimit);
}
/// SimplifyDiv - Given operands for an SDiv or UDiv, see if we can
/// fold the result. If not, this returns null.
/// Given operands for an SDiv or UDiv, see if we can fold the result.
/// If not, this returns null.
static Value *SimplifyDiv(Instruction::BinaryOps Opcode, Value *Op0, Value *Op1,
const Query &Q, unsigned MaxRecurse) {
if (Constant *C0 = dyn_cast<Constant>(Op0)) {
@ -1075,8 +1074,8 @@ static Value *SimplifyDiv(Instruction::BinaryOps Opcode, Value *Op0, Value *Op1,
return nullptr;
}
/// SimplifySDivInst - Given operands for an SDiv, see if we can
/// fold the result. If not, this returns null.
/// Given operands for an SDiv, see if we can fold the result.
/// If not, this returns null.
static Value *SimplifySDivInst(Value *Op0, Value *Op1, const Query &Q,
unsigned MaxRecurse) {
if (Value *V = SimplifyDiv(Instruction::SDiv, Op0, Op1, Q, MaxRecurse))
@ -1093,8 +1092,8 @@ Value *llvm::SimplifySDivInst(Value *Op0, Value *Op1, const DataLayout &DL,
RecursionLimit);
}
/// SimplifyUDivInst - Given operands for a UDiv, see if we can
/// fold the result. If not, this returns null.
/// Given operands for a UDiv, see if we can fold the result.
/// If not, this returns null.
static Value *SimplifyUDivInst(Value *Op0, Value *Op1, const Query &Q,
unsigned MaxRecurse) {
if (Value *V = SimplifyDiv(Instruction::UDiv, Op0, Op1, Q, MaxRecurse))
@ -1154,8 +1153,8 @@ Value *llvm::SimplifyFDivInst(Value *Op0, Value *Op1, FastMathFlags FMF,
RecursionLimit);
}
/// SimplifyRem - Given operands for an SRem or URem, see if we can
/// fold the result. If not, this returns null.
/// Given operands for an SRem or URem, see if we can fold the result.
/// If not, this returns null.
static Value *SimplifyRem(Instruction::BinaryOps Opcode, Value *Op0, Value *Op1,
const Query &Q, unsigned MaxRecurse) {
if (Constant *C0 = dyn_cast<Constant>(Op0)) {
@ -1215,8 +1214,8 @@ static Value *SimplifyRem(Instruction::BinaryOps Opcode, Value *Op0, Value *Op1,
return nullptr;
}
/// SimplifySRemInst - Given operands for an SRem, see if we can
/// fold the result. If not, this returns null.
/// Given operands for an SRem, see if we can fold the result.
/// If not, this returns null.
static Value *SimplifySRemInst(Value *Op0, Value *Op1, const Query &Q,
unsigned MaxRecurse) {
if (Value *V = SimplifyRem(Instruction::SRem, Op0, Op1, Q, MaxRecurse))
@ -1233,8 +1232,8 @@ Value *llvm::SimplifySRemInst(Value *Op0, Value *Op1, const DataLayout &DL,
RecursionLimit);
}
/// SimplifyURemInst - Given operands for a URem, see if we can
/// fold the result. If not, this returns null.
/// Given operands for a URem, see if we can fold the result.
/// If not, this returns null.
static Value *SimplifyURemInst(Value *Op0, Value *Op1, const Query &Q,
unsigned MaxRecurse) {
if (Value *V = SimplifyRem(Instruction::URem, Op0, Op1, Q, MaxRecurse))
@ -1279,7 +1278,7 @@ Value *llvm::SimplifyFRemInst(Value *Op0, Value *Op1, FastMathFlags FMF,
RecursionLimit);
}
/// isUndefShift - Returns true if a shift by \c Amount always yields undef.
/// Returns true if a shift by \c Amount always yields undef.
static bool isUndefShift(Value *Amount) {
Constant *C = dyn_cast<Constant>(Amount);
if (!C)
@ -1306,8 +1305,8 @@ static bool isUndefShift(Value *Amount) {
return false;
}
/// SimplifyShift - Given operands for an Shl, LShr or AShr, see if we can
/// fold the result. If not, this returns null.
/// Given operands for an Shl, LShr or AShr, see if we can fold the result.
/// If not, this returns null.
static Value *SimplifyShift(unsigned Opcode, Value *Op0, Value *Op1,
const Query &Q, unsigned MaxRecurse) {
if (Constant *C0 = dyn_cast<Constant>(Op0)) {
@ -1375,8 +1374,8 @@ static Value *SimplifyRightShift(unsigned Opcode, Value *Op0, Value *Op1,
return nullptr;
}
/// SimplifyShlInst - Given operands for an Shl, see if we can
/// fold the result. If not, this returns null.
/// Given operands for an Shl, see if we can fold the result.
/// If not, this returns null.
static Value *SimplifyShlInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW,
const Query &Q, unsigned MaxRecurse) {
if (Value *V = SimplifyShift(Instruction::Shl, Op0, Op1, Q, MaxRecurse))
@ -1402,8 +1401,8 @@ Value *llvm::SimplifyShlInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW,
RecursionLimit);
}
/// SimplifyLShrInst - Given operands for an LShr, see if we can
/// fold the result. If not, this returns null.
/// Given operands for an LShr, see if we can fold the result.
/// If not, this returns null.
static Value *SimplifyLShrInst(Value *Op0, Value *Op1, bool isExact,
const Query &Q, unsigned MaxRecurse) {
if (Value *V = SimplifyRightShift(Instruction::LShr, Op0, Op1, isExact, Q,
@ -1427,8 +1426,8 @@ Value *llvm::SimplifyLShrInst(Value *Op0, Value *Op1, bool isExact,
RecursionLimit);
}
/// SimplifyAShrInst - Given operands for an AShr, see if we can
/// fold the result. If not, this returns null.
/// Given operands for an AShr, see if we can fold the result.
/// If not, this returns null.
static Value *SimplifyAShrInst(Value *Op0, Value *Op1, bool isExact,
const Query &Q, unsigned MaxRecurse) {
if (Value *V = SimplifyRightShift(Instruction::AShr, Op0, Op1, isExact, Q,
@ -1502,8 +1501,8 @@ static Value *simplifyUnsignedRangeCheck(ICmpInst *ZeroICmp,
return nullptr;
}
// Simplify (and (icmp ...) (icmp ...)) to true when we can tell that the range
// of possible values cannot be satisfied.
/// Simplify (and (icmp ...) (icmp ...)) to true when we can tell that the range
/// of possible values cannot be satisfied.
static Value *SimplifyAndOfICmps(ICmpInst *Op0, ICmpInst *Op1) {
ICmpInst::Predicate Pred0, Pred1;
ConstantInt *CI1, *CI2;
@ -1554,8 +1553,8 @@ static Value *SimplifyAndOfICmps(ICmpInst *Op0, ICmpInst *Op1) {
return nullptr;
}
/// SimplifyAndInst - Given operands for an And, see if we can
/// fold the result. If not, this returns null.
/// Given operands for an And, see if we can fold the result.
/// If not, this returns null.
static Value *SimplifyAndInst(Value *Op0, Value *Op1, const Query &Q,
unsigned MaxRecurse) {
if (Constant *CLHS = dyn_cast<Constant>(Op0)) {
@ -1661,8 +1660,8 @@ Value *llvm::SimplifyAndInst(Value *Op0, Value *Op1, const DataLayout &DL,
RecursionLimit);
}
// Simplify (or (icmp ...) (icmp ...)) to true when we can tell that the union
// contains all possible values.
/// Simplify (or (icmp ...) (icmp ...)) to true when we can tell that the union
/// contains all possible values.
static Value *SimplifyOrOfICmps(ICmpInst *Op0, ICmpInst *Op1) {
ICmpInst::Predicate Pred0, Pred1;
ConstantInt *CI1, *CI2;
@ -1713,8 +1712,8 @@ static Value *SimplifyOrOfICmps(ICmpInst *Op0, ICmpInst *Op1) {
return nullptr;
}
/// SimplifyOrInst - Given operands for an Or, see if we can
/// fold the result. If not, this returns null.
/// Given operands for an Or, see if we can fold the result.
/// If not, this returns null.
static Value *SimplifyOrInst(Value *Op0, Value *Op1, const Query &Q,
unsigned MaxRecurse) {
if (Constant *CLHS = dyn_cast<Constant>(Op0)) {
@ -1849,8 +1848,8 @@ Value *llvm::SimplifyOrInst(Value *Op0, Value *Op1, const DataLayout &DL,
RecursionLimit);
}
/// SimplifyXorInst - Given operands for a Xor, see if we can
/// fold the result. If not, this returns null.
/// Given operands for a Xor, see if we can fold the result.
/// If not, this returns null.
static Value *SimplifyXorInst(Value *Op0, Value *Op1, const Query &Q,
unsigned MaxRecurse) {
if (Constant *CLHS = dyn_cast<Constant>(Op0)) {
@ -1910,9 +1909,9 @@ static Type *GetCompareTy(Value *Op) {
return CmpInst::makeCmpResultType(Op->getType());
}
/// ExtractEquivalentCondition - Rummage around inside V looking for something
/// equivalent to the comparison "LHS Pred RHS". Return such a value if found,
/// otherwise return null. Helper function for analyzing max/min idioms.
/// Rummage around inside V looking for something equivalent to the comparison
/// "LHS Pred RHS". Return such a value if found, otherwise return null.
/// Helper function for analyzing max/min idioms.
static Value *ExtractEquivalentCondition(Value *V, CmpInst::Predicate Pred,
Value *LHS, Value *RHS) {
SelectInst *SI = dyn_cast<SelectInst>(V);
@ -2100,21 +2099,17 @@ static Constant *computePointerICmp(const DataLayout &DL,
// that might be resolve lazily to symbols in another dynamically-loaded
// library (and, thus, could be malloc'ed by the implementation).
auto IsAllocDisjoint = [](SmallVectorImpl<Value *> &Objects) {
return std::all_of(Objects.begin(), Objects.end(),
[](Value *V){
if (const AllocaInst *AI = dyn_cast<AllocaInst>(V))
return AI->getParent() && AI->getParent()->getParent() &&
AI->isStaticAlloca();
if (const GlobalValue *GV = dyn_cast<GlobalValue>(V))
return (GV->hasLocalLinkage() ||
GV->hasHiddenVisibility() ||
GV->hasProtectedVisibility() ||
GV->hasUnnamedAddr()) &&
!GV->isThreadLocal();
if (const Argument *A = dyn_cast<Argument>(V))
return A->hasByValAttr();
return false;
});
return std::all_of(Objects.begin(), Objects.end(), [](Value *V) {
if (const AllocaInst *AI = dyn_cast<AllocaInst>(V))
return AI->getParent() && AI->getFunction() && AI->isStaticAlloca();
if (const GlobalValue *GV = dyn_cast<GlobalValue>(V))
return (GV->hasLocalLinkage() || GV->hasHiddenVisibility() ||
GV->hasProtectedVisibility() || GV->hasUnnamedAddr()) &&
!GV->isThreadLocal();
if (const Argument *A = dyn_cast<Argument>(V))
return A->hasByValAttr();
return false;
});
};
if ((IsNAC(LHSUObjs) && IsAllocDisjoint(RHSUObjs)) ||
@ -2127,8 +2122,8 @@ static Constant *computePointerICmp(const DataLayout &DL,
return nullptr;
}
/// SimplifyICmpInst - Given operands for an ICmpInst, see if we can
/// fold the result. If not, this returns null.
/// Given operands for an ICmpInst, see if we can fold the result.
/// If not, this returns null.
static Value *SimplifyICmpInst(unsigned Predicate, Value *LHS, Value *RHS,
const Query &Q, unsigned MaxRecurse) {
CmpInst::Predicate Pred = (CmpInst::Predicate)Predicate;
@ -3102,8 +3097,8 @@ Value *llvm::SimplifyICmpInst(unsigned Predicate, Value *LHS, Value *RHS,
RecursionLimit);
}
/// SimplifyFCmpInst - Given operands for an FCmpInst, see if we can
/// fold the result. If not, this returns null.
/// Given operands for an FCmpInst, see if we can fold the result.
/// If not, this returns null.
static Value *SimplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
FastMathFlags FMF, const Query &Q,
unsigned MaxRecurse) {
@ -3227,8 +3222,7 @@ Value *llvm::SimplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
Query(DL, TLI, DT, AC, CxtI), RecursionLimit);
}
/// SimplifyWithOpReplaced - See if V simplifies when its operand Op is
/// replaced with RepOp.
/// See if V simplifies when its operand Op is replaced with RepOp.
static const Value *SimplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp,
const Query &Q,
unsigned MaxRecurse) {
@ -3311,8 +3305,8 @@ static const Value *SimplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp,
return nullptr;
}
/// SimplifySelectInst - Given operands for a SelectInst, see if we can fold
/// the result. If not, this returns null.
/// Given operands for a SelectInst, see if we can fold the result.
/// If not, this returns null.
static Value *SimplifySelectInst(Value *CondVal, Value *TrueVal,
Value *FalseVal, const Query &Q,
unsigned MaxRecurse) {
@ -3449,8 +3443,8 @@ Value *llvm::SimplifySelectInst(Value *Cond, Value *TrueVal, Value *FalseVal,
Query(DL, TLI, DT, AC, CxtI), RecursionLimit);
}
/// SimplifyGEPInst - Given operands for an GetElementPtrInst, see if we can
/// fold the result. If not, this returns null.
/// Given operands for an GetElementPtrInst, see if we can fold the result.
/// If not, this returns null.
static Value *SimplifyGEPInst(Type *SrcTy, ArrayRef<Value *> Ops,
const Query &Q, unsigned) {
// The type of the GEP pointer operand.
@ -3542,8 +3536,8 @@ Value *llvm::SimplifyGEPInst(ArrayRef<Value *> Ops, const DataLayout &DL,
Ops, Query(DL, TLI, DT, AC, CxtI), RecursionLimit);
}
/// SimplifyInsertValueInst - Given operands for an InsertValueInst, see if we
/// can fold the result. If not, this returns null.
/// Given operands for an InsertValueInst, see if we can fold the result.
/// If not, this returns null.
static Value *SimplifyInsertValueInst(Value *Agg, Value *Val,
ArrayRef<unsigned> Idxs, const Query &Q,
unsigned) {
@ -3579,8 +3573,8 @@ Value *llvm::SimplifyInsertValueInst(
RecursionLimit);
}
/// SimplifyExtractValueInst - Given operands for an ExtractValueInst, see if we
/// can fold the result. If not, this returns null.
/// Given operands for an ExtractValueInst, see if we can fold the result.
/// If not, this returns null.
static Value *SimplifyExtractValueInst(Value *Agg, ArrayRef<unsigned> Idxs,
const Query &, unsigned) {
if (auto *CAgg = dyn_cast<Constant>(Agg))
@ -3614,8 +3608,8 @@ Value *llvm::SimplifyExtractValueInst(Value *Agg, ArrayRef<unsigned> Idxs,
RecursionLimit);
}
/// SimplifyExtractElementInst - Given operands for an ExtractElementInst, see if we
/// can fold the result. If not, this returns null.
/// Given operands for an ExtractElementInst, see if we can fold the result.
/// If not, this returns null.
static Value *SimplifyExtractElementInst(Value *Vec, Value *Idx, const Query &,
unsigned) {
if (auto *CVec = dyn_cast<Constant>(Vec)) {
@ -3646,7 +3640,7 @@ Value *llvm::SimplifyExtractElementInst(
RecursionLimit);
}
/// SimplifyPHINode - See if we can fold the given phi. If not, returns null.
/// See if we can fold the given phi. If not, returns null.
static Value *SimplifyPHINode(PHINode *PN, const Query &Q) {
// If all of the PHI's incoming values are the same then replace the PHI node
// with the common value.
@ -3696,8 +3690,8 @@ Value *llvm::SimplifyTruncInst(Value *Op, Type *Ty, const DataLayout &DL,
//=== Helper functions for higher up the class hierarchy.
/// SimplifyBinOp - Given operands for a BinaryOperator, see if we can
/// fold the result. If not, this returns null.
/// Given operands for a BinaryOperator, see if we can fold the result.
/// If not, this returns null.
static Value *SimplifyBinOp(unsigned Opcode, Value *LHS, Value *RHS,
const Query &Q, unsigned MaxRecurse) {
switch (Opcode) {
@ -3763,8 +3757,8 @@ static Value *SimplifyBinOp(unsigned Opcode, Value *LHS, Value *RHS,
}
}
/// SimplifyFPBinOp - Given operands for a BinaryOperator, see if we can
/// fold the result. If not, this returns null.
/// Given operands for a BinaryOperator, see if we can fold the result.
/// If not, this returns null.
/// In contrast to SimplifyBinOp, try to use FastMathFlag when folding the
/// result. In case we don't need FastMathFlags, simply fall to SimplifyBinOp.
static Value *SimplifyFPBinOp(unsigned Opcode, Value *LHS, Value *RHS,
@ -3799,8 +3793,7 @@ Value *llvm::SimplifyFPBinOp(unsigned Opcode, Value *LHS, Value *RHS,
RecursionLimit);
}
/// SimplifyCmpInst - Given operands for a CmpInst, see if we can
/// fold the result.
/// Given operands for a CmpInst, see if we can fold the result.
static Value *SimplifyCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
const Query &Q, unsigned MaxRecurse) {
if (CmpInst::isIntPredicate((CmpInst::Predicate)Predicate))
@ -3938,8 +3931,8 @@ Value *llvm::SimplifyCall(Value *V, ArrayRef<Value *> Args,
Query(DL, TLI, DT, AC, CxtI), RecursionLimit);
}
/// SimplifyInstruction - See if we can compute a simplified version of this
/// instruction. If not, this returns null.
/// See if we can compute a simplified version of this instruction.
/// If not, this returns null.
Value *llvm::SimplifyInstruction(Instruction *I, const DataLayout &DL,
const TargetLibraryInfo *TLI,
const DominatorTree *DT, AssumptionCache *AC) {

View File

@ -845,6 +845,7 @@ int llvm::isStridedPtr(PredicatedScalarEvolution &PSE, Value *Ptr,
if (Lp != AR->getLoop()) {
DEBUG(dbgs() << "LAA: Bad stride - Not striding over innermost loop " <<
*Ptr << " SCEV: " << *PtrScev << "\n");
return 0;
}
// The address calculation must not wrap. Otherwise, a dependence could be

View File

@ -637,8 +637,10 @@ LoopInfo::LoopInfo(const DominatorTreeBase<BasicBlock> &DomTree) {
analyze(DomTree);
}
void LoopInfo::updateUnloop(Loop *Unloop) {
Unloop->markUnlooped();
void LoopInfo::markAsRemoved(Loop *Unloop) {
assert(!Unloop->isInvalid() && "Loop has already been removed");
Unloop->invalidate();
RemovedLoops.push_back(Unloop);
// First handle the special case of no parent loop to simplify the algorithm.
if (!Unloop->getParentLoop()) {

View File

@ -42,7 +42,11 @@ public:
}
bool runOnLoop(Loop *L, LPPassManager &) override {
P.run(*L);
auto BBI = find_if(L->blocks().begin(), L->blocks().end(),
[](BasicBlock *BB) { return BB; });
if (BBI != L->blocks().end() &&
isFunctionInPrintList((*BBI)->getParent()->getName()))
P.run(*L);
return false;
}
};
@ -174,8 +178,9 @@ bool LPPassManager::runOnFunction(Function &F) {
// Walk Loops
while (!LQ.empty()) {
bool LoopWasDeleted = false;
CurrentLoop = LQ.back();
// Run all passes on the current Loop.
for (unsigned Index = 0; Index < getNumContainedPasses(); ++Index) {
LoopPass *P = getContainedPass(Index);
@ -192,15 +197,15 @@ bool LPPassManager::runOnFunction(Function &F) {
Changed |= P->runOnLoop(CurrentLoop, *this);
}
LoopWasDeleted = CurrentLoop->isInvalid();
if (Changed)
dumpPassInfo(P, MODIFICATION_MSG, ON_LOOP_MSG,
CurrentLoop->isUnloop()
? "<deleted>"
: CurrentLoop->getHeader()->getName());
LoopWasDeleted ? "<deleted>"
: CurrentLoop->getHeader()->getName());
dumpPreservedSet(P);
if (CurrentLoop->isUnloop()) {
if (LoopWasDeleted) {
// Notify passes that the loop is being deleted.
deleteSimpleAnalysisLoop(CurrentLoop);
} else {
@ -222,12 +227,11 @@ bool LPPassManager::runOnFunction(Function &F) {
removeNotPreservedAnalysis(P);
recordAvailableAnalysis(P);
removeDeadPasses(P, CurrentLoop->isUnloop()
? "<deleted>"
: CurrentLoop->getHeader()->getName(),
removeDeadPasses(P, LoopWasDeleted ? "<deleted>"
: CurrentLoop->getHeader()->getName(),
ON_LOOP_MSG);
if (CurrentLoop->isUnloop())
if (LoopWasDeleted)
// Do not run other passes on this loop.
break;
}
@ -235,12 +239,11 @@ bool LPPassManager::runOnFunction(Function &F) {
// If the loop was deleted, release all the loop passes. This frees up
// some memory, and avoids trouble with the pass manager trying to call
// verifyAnalysis on them.
if (CurrentLoop->isUnloop()) {
if (LoopWasDeleted) {
for (unsigned Index = 0; Index < getNumContainedPasses(); ++Index) {
Pass *P = getContainedPass(Index);
freePass(P, "<deleted>", ON_LOOP_MSG);
}
delete CurrentLoop;
}
// Pop the loop from queue after running all passes.

View File

@ -26,7 +26,7 @@
// ... = load %ptr2, !alias.scope !{ !scope1, !scope2 }, !noalias !{ !scope1 }
//
// When evaluating an aliasing query, if one of the instructions is associated
// has a set of noalias scopes in some domain that is superset of the alias
// has a set of noalias scopes in some domain that is a superset of the alias
// scopes in that domain of some other instruction, then the two memory
// accesses are assumed not to alias.
//

View File

@ -70,7 +70,7 @@
// A a;
// } B;
//
// For an acess to B.a.s, we attach !5 (a path tag node) to the load/store
// For an access to B.a.s, we attach !5 (a path tag node) to the load/store
// instruction. The base type is !4 (struct B), the access type is !2 (scalar
// type short) and the offset is 4.
//

View File

@ -2556,6 +2556,9 @@ bool llvm::CannotBeOrderedLessThanZero(const Value *V, unsigned Depth) {
switch (I->getOpcode()) {
default: break;
// Unsigned integers are always nonnegative.
case Instruction::UIToFP:
return true;
case Instruction::FMul:
// x*x is always non-negative or a NaN.
if (I->getOperand(0) == I->getOperand(1))
@ -2566,6 +2569,9 @@ bool llvm::CannotBeOrderedLessThanZero(const Value *V, unsigned Depth) {
case Instruction::FRem:
return CannotBeOrderedLessThanZero(I->getOperand(0), Depth+1) &&
CannotBeOrderedLessThanZero(I->getOperand(1), Depth+1);
case Instruction::Select:
return CannotBeOrderedLessThanZero(I->getOperand(1), Depth+1) &&
CannotBeOrderedLessThanZero(I->getOperand(2), Depth+1);
case Instruction::FPExt:
case Instruction::FPTrunc:
// Widening/narrowing never change sign.
@ -2574,6 +2580,12 @@ bool llvm::CannotBeOrderedLessThanZero(const Value *V, unsigned Depth) {
if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(I))
switch (II->getIntrinsicID()) {
default: break;
case Intrinsic::maxnum:
return CannotBeOrderedLessThanZero(I->getOperand(0), Depth+1) ||
CannotBeOrderedLessThanZero(I->getOperand(1), Depth+1);
case Intrinsic::minnum:
return CannotBeOrderedLessThanZero(I->getOperand(0), Depth+1) &&
CannotBeOrderedLessThanZero(I->getOperand(1), Depth+1);
case Intrinsic::exp:
case Intrinsic::exp2:
case Intrinsic::fabs:

View File

@ -2654,8 +2654,6 @@ std::error_code BitcodeReader::parseConstants() {
return error("Invalid record");
Type *EltTy = cast<SequentialType>(CurTy)->getElementType();
unsigned Size = Record.size();
if (EltTy->isIntegerTy(8)) {
SmallVector<uint8_t, 16> Elts(Record.begin(), Record.end());
if (isa<VectorType>(CurTy))
@ -2680,21 +2678,24 @@ std::error_code BitcodeReader::parseConstants() {
V = ConstantDataVector::get(Context, Elts);
else
V = ConstantDataArray::get(Context, Elts);
} else if (EltTy->isHalfTy()) {
SmallVector<uint16_t, 16> Elts(Record.begin(), Record.end());
if (isa<VectorType>(CurTy))
V = ConstantDataVector::getFP(Context, Elts);
else
V = ConstantDataArray::getFP(Context, Elts);
} else if (EltTy->isFloatTy()) {
SmallVector<float, 16> Elts(Size);
std::transform(Record.begin(), Record.end(), Elts.begin(), BitsToFloat);
SmallVector<uint32_t, 16> Elts(Record.begin(), Record.end());
if (isa<VectorType>(CurTy))
V = ConstantDataVector::get(Context, Elts);
V = ConstantDataVector::getFP(Context, Elts);
else
V = ConstantDataArray::get(Context, Elts);
V = ConstantDataArray::getFP(Context, Elts);
} else if (EltTy->isDoubleTy()) {
SmallVector<double, 16> Elts(Size);
std::transform(Record.begin(), Record.end(), Elts.begin(),
BitsToDouble);
SmallVector<uint64_t, 16> Elts(Record.begin(), Record.end());
if (isa<VectorType>(CurTy))
V = ConstantDataVector::get(Context, Elts);
V = ConstantDataVector::getFP(Context, Elts);
else
V = ConstantDataArray::get(Context, Elts);
V = ConstantDataArray::getFP(Context, Elts);
} else {
return error("Invalid type for value");
}

View File

@ -1630,19 +1630,10 @@ static void WriteConstants(unsigned FirstVal, unsigned LastVal,
if (isa<IntegerType>(EltTy)) {
for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i)
Record.push_back(CDS->getElementAsInteger(i));
} else if (EltTy->isFloatTy()) {
for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i) {
union { float F; uint32_t I; };
F = CDS->getElementAsFloat(i);
Record.push_back(I);
}
} else {
assert(EltTy->isDoubleTy() && "Unknown ConstantData element type");
for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i) {
union { double F; uint64_t I; };
F = CDS->getElementAsDouble(i);
Record.push_back(I);
}
for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i)
Record.push_back(
CDS->getElementAsAPFloat(i).bitcastToAPInt().getLimitedValue());
}
} else if (isa<ConstantArray>(C) || isa<ConstantStruct>(C) ||
isa<ConstantVector>(C)) {

View File

@ -192,22 +192,26 @@ bool AsmPrinter::doInitialization(Module &M) {
// use the directive, where it would need the same conditionalization
// anyway.
Triple TT(getTargetTriple());
if (TT.isOSDarwin()) {
// If there is a version specified, Major will be non-zero.
if (TT.isOSDarwin() && TT.getOSMajorVersion() != 0) {
unsigned Major, Minor, Update;
TT.getOSVersion(Major, Minor, Update);
// If there is a version specified, Major will be non-zero.
if (Major) {
MCVersionMinType VersionType;
if (TT.isWatchOS())
VersionType = MCVM_WatchOSVersionMin;
else if (TT.isTvOS())
VersionType = MCVM_TvOSVersionMin;
else if (TT.isMacOSX())
VersionType = MCVM_OSXVersionMin;
else
VersionType = MCVM_IOSVersionMin;
OutStreamer->EmitVersionMin(VersionType, Major, Minor, Update);
MCVersionMinType VersionType;
if (TT.isWatchOS()) {
VersionType = MCVM_WatchOSVersionMin;
TT.getWatchOSVersion(Major, Minor, Update);
} else if (TT.isTvOS()) {
VersionType = MCVM_TvOSVersionMin;
TT.getiOSVersion(Major, Minor, Update);
} else if (TT.isMacOSX()) {
VersionType = MCVM_OSXVersionMin;
if (!TT.getMacOSXVersion(Major, Minor, Update))
Major = 0;
} else {
VersionType = MCVM_IOSVersionMin;
TT.getiOSVersion(Major, Minor, Update);
}
if (Major != 0)
OutStreamer->EmitVersionMin(VersionType, Major, Minor, Update);
}
// Allow the target to emit any magic that it wants at the start of the file.

View File

@ -31,6 +31,39 @@
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
//===----------------------------------------------------------------------===//
// EmittingAsmStreamer Implementation
//===----------------------------------------------------------------------===//
unsigned EmittingAsmStreamer::emitULEB128(uint64_t Value, const char *Desc,
unsigned PadTo) {
AP->EmitULEB128(Value, Desc, PadTo);
return 0;
}
unsigned EmittingAsmStreamer::emitInt8(unsigned char Value) {
AP->EmitInt8(Value);
return 0;
}
unsigned EmittingAsmStreamer::emitBytes(StringRef Data) {
AP->OutStreamer->EmitBytes(Data);
return 0;
}
//===----------------------------------------------------------------------===//
// SizeReporterAsmStreamer Implementation
//===----------------------------------------------------------------------===//
unsigned SizeReporterAsmStreamer::emitULEB128(uint64_t Value, const char *Desc,
unsigned PadTo) {
return getULEB128Size(Value);
}
unsigned SizeReporterAsmStreamer::emitInt8(unsigned char Value) { return 1; }
unsigned SizeReporterAsmStreamer::emitBytes(StringRef Data) {
return Data.size();
}
//===----------------------------------------------------------------------===//
// DIEAbbrevData Implementation
//===----------------------------------------------------------------------===//

View File

@ -221,7 +221,7 @@ DwarfDebug::DwarfDebug(AsmPrinter *A, Module *M)
// precedence; fall back to triple-based defaults.
if (Asm->TM.Options.DebuggerTuning != DebuggerKind::Default)
DebuggerTuning = Asm->TM.Options.DebuggerTuning;
else if (IsDarwin || TT.isOSFreeBSD())
else if (IsDarwin)
DebuggerTuning = DebuggerKind::LLDB;
else if (TT.isPS4CPU())
DebuggerTuning = DebuggerKind::SCE;
@ -561,6 +561,8 @@ void DwarfDebug::finalizeModuleInfo() {
// Collect info for variables that were optimized out.
collectDeadVariables();
unsigned MacroOffset = 0;
std::unique_ptr<AsmStreamerBase> AS(new SizeReporterAsmStreamer(Asm));
// Handle anything that needs to be done on a per-unit basis after
// all other generation.
for (const auto &P : CUMap) {
@ -613,6 +615,15 @@ void DwarfDebug::finalizeModuleInfo() {
U.setBaseAddress(TheCU.getRanges().front().getStart());
U.attachRangesOrLowHighPC(U.getUnitDie(), TheCU.takeRanges());
}
auto *CUNode = cast<DICompileUnit>(P.first);
if (CUNode->getMacros()) {
// Compile Unit has macros, emit "DW_AT_macro_info" attribute.
U.addUInt(U.getUnitDie(), dwarf::DW_AT_macro_info,
dwarf::DW_FORM_sec_offset, MacroOffset);
// Update macro section offset
MacroOffset += handleMacroNodes(AS.get(), CUNode->getMacros(), U);
}
}
// Compute DIE offsets and sizes.
@ -656,6 +667,9 @@ void DwarfDebug::endModule() {
// Emit info into a debug ranges section.
emitDebugRanges();
// Emit info into a debug macinfo section.
emitDebugMacinfo();
if (useSplitDwarf()) {
emitDebugStrDWO();
emitDebugInfoDWO();
@ -1833,6 +1847,70 @@ void DwarfDebug::emitDebugRanges() {
}
}
unsigned DwarfDebug::handleMacroNodes(AsmStreamerBase *AS,
DIMacroNodeArray Nodes,
DwarfCompileUnit &U) {
unsigned Size = 0;
for (auto *MN : Nodes) {
if (auto *M = dyn_cast<DIMacro>(MN))
Size += emitMacro(AS, *M);
else if (auto *F = dyn_cast<DIMacroFile>(MN))
Size += emitMacroFile(AS, *F, U);
else
llvm_unreachable("Unexpected DI type!");
}
return Size;
}
unsigned DwarfDebug::emitMacro(AsmStreamerBase *AS, DIMacro &M) {
int Size = 0;
Size += AS->emitULEB128(M.getMacinfoType());
Size += AS->emitULEB128(M.getLine());
StringRef Name = M.getName();
StringRef Value = M.getValue();
Size += AS->emitBytes(Name);
if (!Value.empty()) {
// There should be one space between macro name and macro value.
Size += AS->emitInt8(' ');
Size += AS->emitBytes(Value);
}
Size += AS->emitInt8('\0');
return Size;
}
unsigned DwarfDebug::emitMacroFile(AsmStreamerBase *AS, DIMacroFile &F,
DwarfCompileUnit &U) {
int Size = 0;
assert(F.getMacinfoType() == dwarf::DW_MACINFO_start_file);
Size += AS->emitULEB128(dwarf::DW_MACINFO_start_file);
Size += AS->emitULEB128(F.getLine());
DIFile *File = F.getFile();
unsigned FID =
U.getOrCreateSourceID(File->getFilename(), File->getDirectory());
Size += AS->emitULEB128(FID);
Size += handleMacroNodes(AS, F.getElements(), U);
Size += AS->emitULEB128(dwarf::DW_MACINFO_end_file);
return Size;
}
// Emit visible names into a debug macinfo section.
void DwarfDebug::emitDebugMacinfo() {
if (MCSection *Macinfo = Asm->getObjFileLowering().getDwarfMacinfoSection()) {
// Start the dwarf macinfo section.
Asm->OutStreamer->SwitchSection(Macinfo);
}
std::unique_ptr<AsmStreamerBase> AS(new EmittingAsmStreamer(Asm));
for (const auto &P : CUMap) {
auto &TheCU = *P.second;
auto *SkCU = TheCU.getSkeleton();
DwarfCompileUnit &U = SkCU ? *SkCU : TheCU;
auto *CUNode = cast<DICompileUnit>(P.first);
handleMacroNodes(AS.get(), CUNode->getMacros(), U);
}
Asm->OutStreamer->AddComment("End Of Macro List Mark");
Asm->EmitInt8(0);
}
// DWARF5 Experimental Separate Dwarf emitters.
void DwarfDebug::initSkeletonUnit(const DwarfUnit &U, DIE &Die,

View File

@ -400,18 +400,26 @@ class DwarfDebug : public AsmPrinterHandler {
/// Emit visible names into a debug str section.
void emitDebugStr();
/// Emit visible names into a debug loc section.
/// Emit variable locations into a debug loc section.
void emitDebugLoc();
/// Emit visible names into a debug loc dwo section.
/// Emit variable locations into a debug loc dwo section.
void emitDebugLocDWO();
/// Emit visible names into a debug aranges section.
/// Emit address ranges into a debug aranges section.
void emitDebugARanges();
/// Emit visible names into a debug ranges section.
/// Emit address ranges into a debug ranges section.
void emitDebugRanges();
/// Emit macros into a debug macinfo section.
void emitDebugMacinfo();
unsigned emitMacro(AsmStreamerBase *AS, DIMacro &M);
unsigned emitMacroFile(AsmStreamerBase *AS, DIMacroFile &F,
DwarfCompileUnit &U);
unsigned handleMacroNodes(AsmStreamerBase *AS, DIMacroNodeArray Nodes,
DwarfCompileUnit &U);
/// DWARF 5 Experimental Split Dwarf Emitters
/// Initialize common features of skeleton units.

View File

@ -82,13 +82,24 @@ void WinCodeViewLineTables::maybeRecordLocation(DebugLoc DL,
const MDNode *Scope = DL.getScope();
if (!Scope)
return;
unsigned LineNumber = DL.getLine();
// Skip this line if it is longer than the maximum we can record.
if (LineNumber > COFF::CVL_MaxLineNumber)
return;
unsigned ColumnNumber = DL.getCol();
// Truncate the column number if it is longer than the maximum we can record.
if (ColumnNumber > COFF::CVL_MaxColumnNumber)
ColumnNumber = 0;
StringRef Filename = getFullFilepath(Scope);
// Skip this instruction if it has the same file:line as the previous one.
assert(CurFn);
if (!CurFn->Instrs.empty()) {
const InstrInfoTy &LastInstr = InstrInfo[CurFn->Instrs.back()];
if (LastInstr.Filename == Filename && LastInstr.LineNumber == DL.getLine())
if (LastInstr.Filename == Filename && LastInstr.LineNumber == LineNumber &&
LastInstr.ColumnNumber == ColumnNumber)
return;
}
FileNameRegistry.add(Filename);
@ -96,7 +107,7 @@ void WinCodeViewLineTables::maybeRecordLocation(DebugLoc DL,
MCSymbol *MCL = Asm->MMI->getContext().createTempSymbol();
Asm->OutStreamer->EmitLabel(MCL);
CurFn->Instrs.push_back(MCL);
InstrInfo[MCL] = InstrInfoTy(Filename, DL.getLine(), DL.getCol());
InstrInfo[MCL] = InstrInfoTy(Filename, LineNumber, ColumnNumber);
}
WinCodeViewLineTables::WinCodeViewLineTables(AsmPrinter *AP)
@ -282,8 +293,9 @@ void WinCodeViewLineTables::emitDebugInfoForFunction(const Function *GV) {
ColSegEnd = ColSegI + FilenameSegmentLengths[LastSegmentStart];
ColSegI != ColSegEnd; ++ColSegI) {
unsigned ColumnNumber = InstrInfo[FI.Instrs[ColSegI]].ColumnNumber;
assert(ColumnNumber <= COFF::CVL_MaxColumnNumber);
Asm->EmitInt16(ColumnNumber); // Start column
Asm->EmitInt16(ColumnNumber); // End column
Asm->EmitInt16(0); // End column
}
Asm->OutStreamer->EmitLabel(FileSegmentEnd);
};
@ -320,7 +332,10 @@ void WinCodeViewLineTables::emitDebugInfoForFunction(const Function *GV) {
// The first PC with the given linenumber and the linenumber itself.
EmitLabelDiff(*Asm->OutStreamer, Fn, Instr);
Asm->EmitInt32(InstrInfo[Instr].LineNumber);
uint32_t LineNumber = InstrInfo[Instr].LineNumber;
assert(LineNumber <= COFF::CVL_MaxLineNumber);
uint32_t LineData = LineNumber | COFF::CVL_IsStatement;
Asm->EmitInt32(LineData);
}
FinishPreviousChunk();

View File

@ -744,18 +744,6 @@ bool BranchFolder::CreateCommonTailOnlyBlock(MachineBasicBlock *&PredBB,
return true;
}
static bool hasIdenticalMMOs(const MachineInstr *MI1, const MachineInstr *MI2) {
auto I1 = MI1->memoperands_begin(), E1 = MI1->memoperands_end();
auto I2 = MI2->memoperands_begin(), E2 = MI2->memoperands_end();
if ((E1 - I1) != (E2 - I2))
return false;
for (; I1 != E1; ++I1, ++I2) {
if (**I1 != **I2)
return false;
}
return true;
}
static void
removeMMOsFromMemoryOperations(MachineBasicBlock::iterator MBBIStartPos,
MachineBasicBlock &MBBCommon) {
@ -792,8 +780,7 @@ removeMMOsFromMemoryOperations(MachineBasicBlock::iterator MBBIStartPos,
assert(MBBICommon->isIdenticalTo(&*MBBI) && "Expected matching MIIs!");
if (MBBICommon->mayLoad() || MBBICommon->mayStore())
if (!hasIdenticalMMOs(&*MBBI, &*MBBICommon))
MBBICommon->dropMemRefs();
MBBICommon->setMemRefs(MBBICommon->mergeMemRefsWith(*MBBI));
++MBBI;
++MBBICommon;

View File

@ -1108,7 +1108,7 @@ static bool OptimizeExtractBits(BinaryOperator *ShiftI, ConstantInt *CI,
// <16 x i1> %mask, <16 x i32> %passthru)
// to a chain of basic blocks, with loading element one-by-one if
// the appropriate mask bit is set
//
//
// %1 = bitcast i8* %addr to i32*
// %2 = extractelement <16 x i1> %mask, i32 0
// %3 = icmp eq i1 %2, true
@ -1272,12 +1272,12 @@ static void ScalarizeMaskedLoad(CallInst *CI) {
// %5 = getelementptr i32* %1, i32 0
// store i32 %4, i32* %5
// br label %else
//
//
// else: ; preds = %0, %cond.store
// %6 = extractelement <16 x i1> %mask, i32 1
// %7 = icmp eq i1 %6, true
// br i1 %7, label %cond.store1, label %else2
//
//
// cond.store1: ; preds = %else
// %8 = extractelement <16 x i32> %val, i32 1
// %9 = getelementptr i32* %1, i32 1
@ -1377,24 +1377,24 @@ static void ScalarizeMaskedStore(CallInst *CI) {
// <16 x i1> %Mask, <16 x i32> %Src)
// to a chain of basic blocks, with loading element one-by-one if
// the appropriate mask bit is set
//
//
// % Ptrs = getelementptr i32, i32* %base, <16 x i64> %ind
// % Mask0 = extractelement <16 x i1> %Mask, i32 0
// % ToLoad0 = icmp eq i1 % Mask0, true
// br i1 % ToLoad0, label %cond.load, label %else
//
//
// cond.load:
// % Ptr0 = extractelement <16 x i32*> %Ptrs, i32 0
// % Load0 = load i32, i32* % Ptr0, align 4
// % Res0 = insertelement <16 x i32> undef, i32 % Load0, i32 0
// br label %else
//
//
// else:
// %res.phi.else = phi <16 x i32>[% Res0, %cond.load], [undef, % 0]
// % Mask1 = extractelement <16 x i1> %Mask, i32 1
// % ToLoad1 = icmp eq i1 % Mask1, true
// br i1 % ToLoad1, label %cond.load1, label %else2
//
//
// cond.load1:
// % Ptr1 = extractelement <16 x i32*> %Ptrs, i32 1
// % Load1 = load i32, i32* % Ptr1, align 4
@ -1526,7 +1526,7 @@ static void ScalarizeMaskedGather(CallInst *CI) {
// % Ptr0 = extractelement <16 x i32*> %Ptrs, i32 0
// store i32 %Elt0, i32* % Ptr0, align 4
// br label %else
//
//
// else:
// % Mask1 = extractelement <16 x i1> % Mask, i32 1
// % ToStore1 = icmp eq i1 % Mask1, true

View File

@ -19,6 +19,8 @@
//===----------------------------------------------------------------------===//
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
@ -30,7 +32,7 @@
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetSubtargetInfo.h"
#include <deque>
#include <queue>
#include <list>
using namespace llvm;
@ -76,16 +78,13 @@ private:
typedef std::list<VarLoc> VarLocList;
typedef SmallDenseMap<const MachineBasicBlock *, VarLocList> VarLocInMBB;
bool OLChanged; // OutgoingLocs got changed for this bb.
bool MBBJoined; // The MBB was joined.
void transferDebugValue(MachineInstr &MI, VarLocList &OpenRanges);
void transferRegisterDef(MachineInstr &MI, VarLocList &OpenRanges);
void transferTerminatorInst(MachineInstr &MI, VarLocList &OpenRanges,
bool transferTerminatorInst(MachineInstr &MI, VarLocList &OpenRanges,
VarLocInMBB &OutLocs);
void transfer(MachineInstr &MI, VarLocList &OpenRanges, VarLocInMBB &OutLocs);
bool transfer(MachineInstr &MI, VarLocList &OpenRanges, VarLocInMBB &OutLocs);
void join(MachineBasicBlock &MBB, VarLocInMBB &OutLocs, VarLocInMBB &InLocs);
bool join(MachineBasicBlock &MBB, VarLocInMBB &OutLocs, VarLocInMBB &InLocs);
bool ExtendRanges(MachineFunction &MF);
@ -225,24 +224,18 @@ void LiveDebugValues::transferRegisterDef(MachineInstr &MI,
}
/// Terminate all open ranges at the end of the current basic block.
void LiveDebugValues::transferTerminatorInst(MachineInstr &MI,
bool LiveDebugValues::transferTerminatorInst(MachineInstr &MI,
VarLocList &OpenRanges,
VarLocInMBB &OutLocs) {
bool Changed = false;
const MachineBasicBlock *CurMBB = MI.getParent();
if (!(MI.isTerminator() || (&MI == &CurMBB->instr_back())))
return;
return false;
if (OpenRanges.empty())
return;
return false;
if (OutLocs.find(CurMBB) == OutLocs.end()) {
// Create space for new Outgoing locs entries.
VarLocList VLL;
OutLocs.insert(std::make_pair(CurMBB, std::move(VLL)));
}
auto OL = OutLocs.find(CurMBB);
assert(OL != OutLocs.end());
VarLocList &VLL = OL->second;
VarLocList &VLL = OutLocs[CurMBB];
for (auto OR : OpenRanges) {
// Copy OpenRanges to OutLocs, if not already present.
@ -251,28 +244,30 @@ void LiveDebugValues::transferTerminatorInst(MachineInstr &MI,
if (std::find_if(VLL.begin(), VLL.end(),
[&](const VarLoc &V) { return (OR == V); }) == VLL.end()) {
VLL.push_back(std::move(OR));
OLChanged = true;
Changed = true;
}
}
OpenRanges.clear();
return Changed;
}
/// This routine creates OpenRanges and OutLocs.
void LiveDebugValues::transfer(MachineInstr &MI, VarLocList &OpenRanges,
bool LiveDebugValues::transfer(MachineInstr &MI, VarLocList &OpenRanges,
VarLocInMBB &OutLocs) {
bool Changed = false;
transferDebugValue(MI, OpenRanges);
transferRegisterDef(MI, OpenRanges);
transferTerminatorInst(MI, OpenRanges, OutLocs);
Changed = transferTerminatorInst(MI, OpenRanges, OutLocs);
return Changed;
}
/// This routine joins the analysis results of all incoming edges in @MBB by
/// inserting a new DBG_VALUE instruction at the start of the @MBB - if the same
/// source variable in all the predecessors of @MBB reside in the same location.
void LiveDebugValues::join(MachineBasicBlock &MBB, VarLocInMBB &OutLocs,
bool LiveDebugValues::join(MachineBasicBlock &MBB, VarLocInMBB &OutLocs,
VarLocInMBB &InLocs) {
DEBUG(dbgs() << "join MBB: " << MBB.getName() << "\n");
MBBJoined = false;
bool Changed = false;
VarLocList InLocsT; // Temporary incoming locations.
@ -282,7 +277,7 @@ void LiveDebugValues::join(MachineBasicBlock &MBB, VarLocInMBB &OutLocs,
auto OL = OutLocs.find(p);
// Join is null in case of empty OutLocs from any of the pred.
if (OL == OutLocs.end())
return;
return false;
// Just copy over the Out locs to incoming locs for the first predecessor.
if (p == *MBB.pred_begin()) {
@ -292,27 +287,18 @@ void LiveDebugValues::join(MachineBasicBlock &MBB, VarLocInMBB &OutLocs,
// Join with this predecessor.
VarLocList &VLL = OL->second;
InLocsT.erase(std::remove_if(InLocsT.begin(), InLocsT.end(),
[&](VarLoc &ILT) {
return (std::find_if(VLL.begin(), VLL.end(),
[&](const VarLoc &V) {
return (ILT == V);
}) == VLL.end());
}),
InLocsT.end());
InLocsT.erase(
std::remove_if(InLocsT.begin(), InLocsT.end(), [&](VarLoc &ILT) {
return (std::find_if(VLL.begin(), VLL.end(), [&](const VarLoc &V) {
return (ILT == V);
}) == VLL.end());
}), InLocsT.end());
}
if (InLocsT.empty())
return;
return false;
if (InLocs.find(&MBB) == InLocs.end()) {
// Create space for new Incoming locs entries.
VarLocList VLL;
InLocs.insert(std::make_pair(&MBB, std::move(VLL)));
}
auto IL = InLocs.find(&MBB);
assert(IL != InLocs.end());
VarLocList &ILL = IL->second;
VarLocList &ILL = InLocs[&MBB];
// Insert DBG_VALUE instructions, if not already inserted.
for (auto ILT : InLocsT) {
@ -331,12 +317,13 @@ void LiveDebugValues::join(MachineBasicBlock &MBB, VarLocInMBB &OutLocs,
MI->getOperand(1).setImm(DMI->getOperand(1).getImm());
DEBUG(dbgs() << "Inserted: "; MI->dump(););
++NumInserted;
MBBJoined = true; // rerun transfer().
Changed = true;
VarLoc V(ILT.Var, MI);
ILL.push_back(std::move(V));
}
}
return Changed;
}
/// Calculate the liveness information for the given machine function and
@ -346,48 +333,72 @@ bool LiveDebugValues::ExtendRanges(MachineFunction &MF) {
DEBUG(dbgs() << "\nDebug Range Extension\n");
bool Changed = false;
OLChanged = MBBJoined = false;
bool OLChanged = false;
bool MBBJoined = false;
VarLocList OpenRanges; // Ranges that are open until end of bb.
VarLocInMBB OutLocs; // Ranges that exist beyond bb.
VarLocInMBB InLocs; // Ranges that are incoming after joining.
std::deque<MachineBasicBlock *> BBWorklist;
DenseMap<unsigned int, MachineBasicBlock *> OrderToBB;
DenseMap<MachineBasicBlock *, unsigned int> BBToOrder;
std::priority_queue<unsigned int, std::vector<unsigned int>,
std::greater<unsigned int>> Worklist;
std::priority_queue<unsigned int, std::vector<unsigned int>,
std::greater<unsigned int>> Pending;
// Initialize every mbb with OutLocs.
for (auto &MBB : MF)
for (auto &MI : MBB)
transfer(MI, OpenRanges, OutLocs);
DEBUG(printVarLocInMBB(OutLocs, "OutLocs after initialization", dbgs()));
// Construct a worklist of MBBs.
for (auto &MBB : MF)
BBWorklist.push_back(&MBB);
ReversePostOrderTraversal<MachineFunction *> RPOT(&MF);
unsigned int RPONumber = 0;
for (auto RI = RPOT.begin(), RE = RPOT.end(); RI != RE; ++RI) {
OrderToBB[RPONumber] = *RI;
BBToOrder[*RI] = RPONumber;
Worklist.push(RPONumber);
++RPONumber;
}
// Perform join() and transfer() using the worklist until the ranges converge
// Ranges have converged when the worklist is empty.
while (!BBWorklist.empty()) {
MachineBasicBlock *MBB = BBWorklist.front();
BBWorklist.pop_front();
// This is a standard "union of predecessor outs" dataflow problem.
// To solve it, we perform join() and transfer() using the two worklist method
// until the ranges converge.
// Ranges have converged when both worklists are empty.
while (!Worklist.empty() || !Pending.empty()) {
// We track what is on the pending worklist to avoid inserting the same
// thing twice. We could avoid this with a custom priority queue, but this
// is probably not worth it.
SmallPtrSet<MachineBasicBlock *, 16> OnPending;
while (!Worklist.empty()) {
MachineBasicBlock *MBB = OrderToBB[Worklist.top()];
Worklist.pop();
MBBJoined = join(*MBB, OutLocs, InLocs);
join(*MBB, OutLocs, InLocs);
if (MBBJoined) {
MBBJoined = false;
Changed = true;
for (auto &MI : *MBB)
OLChanged |= transfer(MI, OpenRanges, OutLocs);
DEBUG(printVarLocInMBB(OutLocs, "OutLocs after propagating", dbgs()));
DEBUG(printVarLocInMBB(InLocs, "InLocs after propagating", dbgs()));
if (MBBJoined) {
Changed = true;
for (auto &MI : *MBB)
transfer(MI, OpenRanges, OutLocs);
DEBUG(printVarLocInMBB(OutLocs, "OutLocs after propagating", dbgs()));
DEBUG(printVarLocInMBB(InLocs, "InLocs after propagating", dbgs()));
if (OLChanged) {
OLChanged = false;
for (auto s : MBB->successors())
if (std::find(BBWorklist.begin(), BBWorklist.end(), s) ==
BBWorklist.end()) // add if not already present.
BBWorklist.push_back(s);
if (OLChanged) {
OLChanged = false;
for (auto s : MBB->successors())
if (!OnPending.count(s)) {
OnPending.insert(s);
Pending.push(BBToOrder[s]);
}
}
}
}
Worklist.swap(Pending);
// At this point, pending must be empty, since it was just the empty
// worklist
assert(Pending.empty() && "Pending should be empty");
}
DEBUG(printVarLocInMBB(OutLocs, "Final OutLocs", dbgs()));
DEBUG(printVarLocInMBB(InLocs, "Final InLocs", dbgs()));
return Changed;

View File

@ -1328,15 +1328,15 @@ void LiveRangeUpdater::flush() {
LR->verify();
}
unsigned ConnectedVNInfoEqClasses::Classify(const LiveInterval *LI) {
unsigned ConnectedVNInfoEqClasses::Classify(const LiveRange &LR) {
// Create initial equivalence classes.
EqClass.clear();
EqClass.grow(LI->getNumValNums());
EqClass.grow(LR.getNumValNums());
const VNInfo *used = nullptr, *unused = nullptr;
// Determine connections.
for (const VNInfo *VNI : LI->valnos) {
for (const VNInfo *VNI : LR.valnos) {
// Group all unused values into one class.
if (VNI->isUnused()) {
if (unused)
@ -1351,14 +1351,14 @@ unsigned ConnectedVNInfoEqClasses::Classify(const LiveInterval *LI) {
// Connect to values live out of predecessors.
for (MachineBasicBlock::const_pred_iterator PI = MBB->pred_begin(),
PE = MBB->pred_end(); PI != PE; ++PI)
if (const VNInfo *PVNI = LI->getVNInfoBefore(LIS.getMBBEndIdx(*PI)))
if (const VNInfo *PVNI = LR.getVNInfoBefore(LIS.getMBBEndIdx(*PI)))
EqClass.join(VNI->id, PVNI->id);
} else {
// Normal value defined by an instruction. Check for two-addr redef.
// FIXME: This could be coincidental. Should we really check for a tied
// operand constraint?
// Note that VNI->def may be a use slot for an early clobber def.
if (const VNInfo *UVNI = LI->getVNInfoBefore(VNI->def))
if (const VNInfo *UVNI = LR.getVNInfoBefore(VNI->def))
EqClass.join(VNI->id, UVNI->id);
}
}

View File

@ -1446,7 +1446,7 @@ void LiveIntervals::removeVRegDefAt(LiveInterval &LI, SlotIndex Pos) {
void LiveIntervals::splitSeparateComponents(LiveInterval &LI,
SmallVectorImpl<LiveInterval*> &SplitLIs) {
ConnectedVNInfoEqClasses ConEQ(*this);
unsigned NumComp = ConEQ.Classify(&LI);
unsigned NumComp = ConEQ.Classify(LI);
if (NumComp <= 1)
return;
DEBUG(dbgs() << " Split " << NumComp << " components: " << LI << '\n');

View File

@ -1182,7 +1182,7 @@ MachineBasicBlock::getProbabilityIterator(MachineBasicBlock::succ_iterator I) {
/// Return whether (physical) register "Reg" has been <def>ined and not <kill>ed
/// as of just before "MI".
///
///
/// Search is localised to a neighborhood of
/// Neighborhood instructions before (searching for defs or kills) and N
/// instructions after (searching just for defs) MI.

View File

@ -31,7 +31,7 @@ struct MachineFunctionPrinterPass : public MachineFunctionPass {
const std::string Banner;
MachineFunctionPrinterPass() : MachineFunctionPass(ID), OS(dbgs()) { }
MachineFunctionPrinterPass(raw_ostream &os, const std::string &banner)
MachineFunctionPrinterPass(raw_ostream &os, const std::string &banner)
: MachineFunctionPass(ID), OS(os), Banner(banner) {}
const char *getPassName() const override { return "MachineFunction Printer"; }
@ -42,6 +42,8 @@ struct MachineFunctionPrinterPass : public MachineFunctionPass {
}
bool runOnMachineFunction(MachineFunction &MF) override {
if (!llvm::isFunctionInPrintList(MF.getName()))
return false;
OS << "# " << Banner << ":\n";
MF.print(OS, getAnalysisIfAvailable<SlotIndexes>());
return false;

View File

@ -866,14 +866,44 @@ void MachineInstr::addMemOperand(MachineFunction &MF,
setMemRefs(NewMemRefs, NewMemRefs + NewNum);
}
/// Check to see if the MMOs pointed to by the two MemRefs arrays are
/// identical.
static bool hasIdenticalMMOs(const MachineInstr &MI1, const MachineInstr &MI2) {
auto I1 = MI1.memoperands_begin(), E1 = MI1.memoperands_end();
auto I2 = MI2.memoperands_begin(), E2 = MI2.memoperands_end();
if ((E1 - I1) != (E2 - I2))
return false;
for (; I1 != E1; ++I1, ++I2) {
if (**I1 != **I2)
return false;
}
return true;
}
std::pair<MachineInstr::mmo_iterator, unsigned>
MachineInstr::mergeMemRefsWith(const MachineInstr& Other) {
// TODO: If we end up with too many memory operands, return the empty
// conservative set rather than failing asserts.
// If either of the incoming memrefs are empty, we must be conservative and
// treat this as if we've exhausted our space for memrefs and dropped them.
if (memoperands_empty() || Other.memoperands_empty())
return std::make_pair(nullptr, 0);
// If both instructions have identical memrefs, we don't need to merge them.
// Since many instructions have a single memref, and we tend to merge things
// like pairs of loads from the same location, this catches a large number of
// cases in practice.
if (hasIdenticalMMOs(*this, Other))
return std::make_pair(MemRefs, NumMemRefs);
// TODO: consider uniquing elements within the operand lists to reduce
// space usage and fall back to conservative information less often.
size_t CombinedNumMemRefs = (memoperands_end() - memoperands_begin())
+ (Other.memoperands_end() - Other.memoperands_begin());
size_t CombinedNumMemRefs = NumMemRefs + Other.NumMemRefs;
// If we don't have enough room to store this many memrefs, be conservative
// and drop them. Otherwise, we'd fail asserts when trying to add them to
// the new instruction.
if (CombinedNumMemRefs != uint8_t(CombinedNumMemRefs))
return std::make_pair(nullptr, 0);
MachineFunction *MF = getParent()->getParent();
mmo_iterator MemBegin = MF->allocateMemRefsArray(CombinedNumMemRefs);

View File

@ -334,12 +334,11 @@ static bool InstructionStoresToFI(const MachineInstr *MI, int FI) {
// writes to all slots.
if (MI->memoperands_empty())
return true;
for (MachineInstr::mmo_iterator o = MI->memoperands_begin(),
oe = MI->memoperands_end(); o != oe; ++o) {
if (!(*o)->isStore() || !(*o)->getPseudoValue())
for (const MachineMemOperand *MemOp : MI->memoperands()) {
if (!MemOp->isStore() || !MemOp->getPseudoValue())
continue;
if (const FixedStackPseudoSourceValue *Value =
dyn_cast<FixedStackPseudoSourceValue>((*o)->getPseudoValue())) {
dyn_cast<FixedStackPseudoSourceValue>(MemOp->getPseudoValue())) {
if (Value->getFrameIndex() == FI)
return true;
}
@ -357,8 +356,7 @@ void MachineLICM::ProcessMI(MachineInstr *MI,
bool RuledOut = false;
bool HasNonInvariantUse = false;
unsigned Def = 0;
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
const MachineOperand &MO = MI->getOperand(i);
for (const MachineOperand &MO : MI->operands()) {
if (MO.isFI()) {
// Remember if the instruction stores to the frame index.
int FI = MO.getIndex();
@ -452,9 +450,7 @@ void MachineLICM::HoistRegionPostRA() {
// Walk the entire region, count number of defs for each register, and
// collect potential LICM candidates.
const std::vector<MachineBasicBlock *> &Blocks = CurLoop->getBlocks();
for (unsigned i = 0, e = Blocks.size(); i != e; ++i) {
MachineBasicBlock *BB = Blocks[i];
for (MachineBasicBlock *BB : Blocks) {
// If the header of the loop containing this basic block is a landing pad,
// then don't try to hoist instructions out of this loop.
const MachineLoop *ML = MLI->getLoopFor(BB);
@ -469,19 +465,15 @@ void MachineLICM::HoistRegionPostRA() {
}
SpeculationState = SpeculateUnknown;
for (MachineBasicBlock::iterator
MII = BB->begin(), E = BB->end(); MII != E; ++MII) {
MachineInstr *MI = &*MII;
ProcessMI(MI, PhysRegDefs, PhysRegClobbers, StoredFIs, Candidates);
}
for (MachineInstr &MI : *BB)
ProcessMI(&MI, PhysRegDefs, PhysRegClobbers, StoredFIs, Candidates);
}
// Gather the registers read / clobbered by the terminator.
BitVector TermRegs(NumRegs);
MachineBasicBlock::iterator TI = Preheader->getFirstTerminator();
if (TI != Preheader->end()) {
for (unsigned i = 0, e = TI->getNumOperands(); i != e; ++i) {
const MachineOperand &MO = TI->getOperand(i);
for (const MachineOperand &MO : TI->operands()) {
if (!MO.isReg())
continue;
unsigned Reg = MO.getReg();
@ -500,17 +492,16 @@ void MachineLICM::HoistRegionPostRA() {
// 3. Make sure candidate def should not clobber
// registers read by the terminator. Similarly its def should not be
// clobbered by the terminator.
for (unsigned i = 0, e = Candidates.size(); i != e; ++i) {
if (Candidates[i].FI != INT_MIN &&
StoredFIs.count(Candidates[i].FI))
for (CandidateInfo &Candidate : Candidates) {
if (Candidate.FI != INT_MIN &&
StoredFIs.count(Candidate.FI))
continue;
unsigned Def = Candidates[i].Def;
unsigned Def = Candidate.Def;
if (!PhysRegClobbers.test(Def) && !TermRegs.test(Def)) {
bool Safe = true;
MachineInstr *MI = Candidates[i].MI;
for (unsigned j = 0, ee = MI->getNumOperands(); j != ee; ++j) {
const MachineOperand &MO = MI->getOperand(j);
MachineInstr *MI = Candidate.MI;
for (const MachineOperand &MO : MI->operands()) {
if (!MO.isReg() || MO.isDef() || !MO.getReg())
continue;
unsigned Reg = MO.getReg();
@ -523,7 +514,7 @@ void MachineLICM::HoistRegionPostRA() {
}
}
if (Safe)
HoistPostRA(MI, Candidates[i].Def);
HoistPostRA(MI, Candidate.Def);
}
}
}
@ -532,15 +523,11 @@ void MachineLICM::HoistRegionPostRA() {
/// sure it is not killed by any instructions in the loop.
void MachineLICM::AddToLiveIns(unsigned Reg) {
const std::vector<MachineBasicBlock *> &Blocks = CurLoop->getBlocks();
for (unsigned i = 0, e = Blocks.size(); i != e; ++i) {
MachineBasicBlock *BB = Blocks[i];
for (MachineBasicBlock *BB : Blocks) {
if (!BB->isLiveIn(Reg))
BB->addLiveIn(Reg);
for (MachineBasicBlock::iterator
MII = BB->begin(), E = BB->end(); MII != E; ++MII) {
MachineInstr *MI = &*MII;
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
MachineOperand &MO = MI->getOperand(i);
for (MachineInstr &MI : *BB) {
for (MachineOperand &MO : MI.operands()) {
if (!MO.isReg() || !MO.getReg() || MO.isDef()) continue;
if (MO.getReg() == Reg || TRI->isSuperRegister(Reg, MO.getReg()))
MO.setIsKill(false);
@ -582,8 +569,8 @@ bool MachineLICM::IsGuaranteedToExecute(MachineBasicBlock *BB) {
// Check loop exiting blocks.
SmallVector<MachineBasicBlock*, 8> CurrentLoopExitingBlocks;
CurLoop->getExitingBlocks(CurrentLoopExitingBlocks);
for (unsigned i = 0, e = CurrentLoopExitingBlocks.size(); i != e; ++i)
if (!DT->dominates(BB, CurrentLoopExitingBlocks[i])) {
for (MachineBasicBlock *CurrentLoopExitingBlock : CurrentLoopExitingBlocks)
if (!DT->dominates(BB, CurrentLoopExitingBlock)) {
SpeculationState = SpeculateTrue;
return false;
}
@ -689,8 +676,7 @@ void MachineLICM::HoistOutOfLoop(MachineDomTreeNode *HeaderN) {
InitRegPressure(Preheader);
// Now perform LICM.
for (unsigned i = 0, e = Scopes.size(); i != e; ++i) {
MachineDomTreeNode *Node = Scopes[i];
for (MachineDomTreeNode *Node : Scopes) {
MachineBasicBlock *MBB = Node->getBlock();
EnterScope(MBB);
@ -858,13 +844,11 @@ static bool mayLoadFromGOTOrConstantPool(MachineInstr &MI) {
if (MI.memoperands_empty())
return true;
for (MachineInstr::mmo_iterator I = MI.memoperands_begin(),
E = MI.memoperands_end(); I != E; ++I) {
if (const PseudoSourceValue *PSV = (*I)->getPseudoValue()) {
for (MachineMemOperand *MemOp : MI.memoperands())
if (const PseudoSourceValue *PSV = MemOp->getPseudoValue())
if (PSV->isGOT() || PSV->isConstantPool())
return true;
}
}
return false;
}
@ -899,9 +883,7 @@ bool MachineLICM::IsLoopInvariantInst(MachineInstr &I) {
return false;
// The instruction is loop invariant if all of its operands are.
for (unsigned i = 0, e = I.getNumOperands(); i != e; ++i) {
const MachineOperand &MO = I.getOperand(i);
for (const MachineOperand &MO : I.operands()) {
if (!MO.isReg())
continue;
@ -1230,11 +1212,8 @@ MachineInstr *MachineLICM::ExtractHoistableLoad(MachineInstr *MI) {
/// preheader that may become duplicates of instructions that are hoisted
/// out of the loop.
void MachineLICM::InitCSEMap(MachineBasicBlock *BB) {
for (MachineBasicBlock::iterator I = BB->begin(),E = BB->end(); I != E; ++I) {
const MachineInstr *MI = &*I;
unsigned Opcode = MI->getOpcode();
CSEMap[Opcode].push_back(MI);
}
for (MachineInstr &MI : *BB)
CSEMap[MI.getOpcode()].push_back(&MI);
}
/// Find an instruction amount PrevMIs that is a duplicate of MI.
@ -1242,11 +1221,10 @@ void MachineLICM::InitCSEMap(MachineBasicBlock *BB) {
const MachineInstr*
MachineLICM::LookForDuplicate(const MachineInstr *MI,
std::vector<const MachineInstr*> &PrevMIs) {
for (unsigned i = 0, e = PrevMIs.size(); i != e; ++i) {
const MachineInstr *PrevMI = PrevMIs[i];
for (const MachineInstr *PrevMI : PrevMIs)
if (TII->produceSameValue(MI, PrevMI, (PreRegAlloc ? MRI : nullptr)))
return PrevMI;
}
return nullptr;
}
@ -1296,8 +1274,7 @@ bool MachineLICM::EliminateCSE(MachineInstr *MI,
}
}
for (unsigned i = 0, e = Defs.size(); i != e; ++i) {
unsigned Idx = Defs[i];
for (unsigned Idx : Defs) {
unsigned Reg = MI->getOperand(Idx).getReg();
unsigned DupReg = Dup->getOperand(Idx).getReg();
MRI->replaceRegWith(Reg, DupReg);
@ -1370,11 +1347,9 @@ bool MachineLICM::Hoist(MachineInstr *MI, MachineBasicBlock *Preheader) {
// Clear the kill flags of any register this instruction defines,
// since they may need to be live throughout the entire loop
// rather than just live for part of it.
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
MachineOperand &MO = MI->getOperand(i);
for (MachineOperand &MO : MI->operands())
if (MO.isReg() && MO.isDef() && !MO.isDead())
MRI->clearKillFlags(MO.getReg());
}
// Add to the CSE map.
if (CI != CSEMap.end())

View File

@ -1736,7 +1736,7 @@ void MachineVerifier::verifyLiveInterval(const LiveInterval &LI) {
// Check the LI only has one connected component.
ConnectedVNInfoEqClasses ConEQ(*LiveInts);
unsigned NumComp = ConEQ.Classify(&LI);
unsigned NumComp = ConEQ.Classify(LI);
if (NumComp > 1) {
report("Multiple connected components in live interval", MF);
report_context(LI);

View File

@ -2874,7 +2874,7 @@ void RegisterCoalescer::joinAllIntervals() {
std::vector<MBBPriorityInfo> MBBs;
MBBs.reserve(MF->size());
for (MachineFunction::iterator I = MF->begin(), E = MF->end();I != E;++I){
for (MachineFunction::iterator I = MF->begin(), E = MF->end(); I != E; ++I) {
MachineBasicBlock *MBB = &*I;
MBBs.push_back(MBBPriorityInfo(MBB, Loops->getLoopDepth(MBB),
JoinSplitEdges && isSplitEdge(MBB)));

View File

@ -313,21 +313,6 @@ static bool containsReg(ArrayRef<unsigned> RegUnits, unsigned RegUnit) {
namespace {
/// List of register defined and used by a machine instruction.
class RegisterOperands {
public:
SmallVector<unsigned, 8> Uses;
SmallVector<unsigned, 8> Defs;
SmallVector<unsigned, 8> DeadDefs;
void collect(const MachineInstr &MI, const TargetRegisterInfo &TRI,
const MachineRegisterInfo &MRI, bool IgnoreDead = false);
/// Use liveness information to find dead defs not marked with a dead flag
/// and move them to the DeadDefs vector.
void detectDeadDefs(const MachineInstr &MI, const LiveIntervals &LIS);
};
/// Collect this instruction's unique uses and defs into SmallVectors for
/// processing defs and uses in order.
///
@ -385,9 +370,11 @@ class RegisterOperandsCollector {
}
}
friend class RegisterOperands;
friend class llvm::RegisterOperands;
};
} // namespace
void RegisterOperands::collect(const MachineInstr &MI,
const TargetRegisterInfo &TRI,
const MachineRegisterInfo &MRI,
@ -417,8 +404,6 @@ void RegisterOperands::detectDeadDefs(const MachineInstr &MI,
}
}
} // namespace
/// Initialize an array of N PressureDiffs.
void PressureDiffs::init(unsigned N) {
Size = N;
@ -431,6 +416,18 @@ void PressureDiffs::init(unsigned N) {
PDiffArray = reinterpret_cast<PressureDiff*>(calloc(N, sizeof(PressureDiff)));
}
void PressureDiffs::addInstruction(unsigned Idx,
const RegisterOperands &RegOpers,
const MachineRegisterInfo &MRI) {
PressureDiff &PDiff = (*this)[Idx];
assert(!PDiff.begin()->isValid() && "stale PDiff");
for (unsigned Reg : RegOpers.Defs)
PDiff.addPressureChange(Reg, true, &MRI);
for (unsigned Reg : RegOpers.Uses)
PDiff.addPressureChange(Reg, false, &MRI);
}
/// Add a change in pressure to the pressure diff of a given instruction.
void PressureDiff::addPressureChange(unsigned RegUnit, bool IsDec,
const MachineRegisterInfo *MRI) {
@ -467,18 +464,6 @@ void PressureDiff::addPressureChange(unsigned RegUnit, bool IsDec,
}
}
/// Record the pressure difference induced by the given operand list.
static void collectPDiff(PressureDiff &PDiff, RegisterOperands &RegOpers,
const MachineRegisterInfo *MRI) {
assert(!PDiff.begin()->isValid() && "stale PDiff");
for (unsigned Reg : RegOpers.Defs)
PDiff.addPressureChange(Reg, true, MRI);
for (unsigned Reg : RegOpers.Uses)
PDiff.addPressureChange(Reg, false, MRI);
}
/// Force liveness of registers.
void RegPressureTracker::addLiveRegs(ArrayRef<unsigned> Regs) {
for (unsigned Reg : Regs) {
@ -514,39 +499,10 @@ void RegPressureTracker::discoverLiveOut(unsigned Reg) {
/// registers that are both defined and used by the instruction. If a pressure
/// difference pointer is provided record the changes is pressure caused by this
/// instruction independent of liveness.
void RegPressureTracker::recede(SmallVectorImpl<unsigned> *LiveUses,
PressureDiff *PDiff) {
assert(CurrPos != MBB->begin());
if (!isBottomClosed())
closeBottom();
// Open the top of the region using block iterators.
if (!RequireIntervals && isTopClosed())
static_cast<RegionPressure&>(P).openTop(CurrPos);
// Find the previous instruction.
do
--CurrPos;
while (CurrPos != MBB->begin() && CurrPos->isDebugValue());
void RegPressureTracker::recede(const RegisterOperands &RegOpers,
SmallVectorImpl<unsigned> *LiveUses) {
assert(!CurrPos->isDebugValue());
SlotIndex SlotIdx;
if (RequireIntervals)
SlotIdx = LIS->getInstructionIndex(CurrPos).getRegSlot();
// Open the top of the region using slot indexes.
if (RequireIntervals && isTopClosed())
static_cast<IntervalPressure&>(P).openTop(SlotIdx);
const MachineInstr &MI = *CurrPos;
RegisterOperands RegOpers;
RegOpers.collect(MI, *TRI, *MRI);
if (RequireIntervals)
RegOpers.detectDeadDefs(MI, *LIS);
if (PDiff)
collectPDiff(*PDiff, RegOpers, MRI);
// Boost pressure for all dead defs together.
increaseRegPressure(RegOpers.DeadDefs);
decreaseRegPressure(RegOpers.DeadDefs);
@ -560,6 +516,10 @@ void RegPressureTracker::recede(SmallVectorImpl<unsigned> *LiveUses,
discoverLiveOut(Reg);
}
SlotIndex SlotIdx;
if (RequireIntervals)
SlotIdx = LIS->getInstructionIndex(CurrPos).getRegSlot();
// Generate liveness for uses.
for (unsigned Reg : RegOpers.Uses) {
if (!LiveRegs.contains(Reg)) {
@ -586,6 +546,41 @@ void RegPressureTracker::recede(SmallVectorImpl<unsigned> *LiveUses,
}
}
void RegPressureTracker::recedeSkipDebugValues() {
assert(CurrPos != MBB->begin());
if (!isBottomClosed())
closeBottom();
// Open the top of the region using block iterators.
if (!RequireIntervals && isTopClosed())
static_cast<RegionPressure&>(P).openTop(CurrPos);
// Find the previous instruction.
do
--CurrPos;
while (CurrPos != MBB->begin() && CurrPos->isDebugValue());
SlotIndex SlotIdx;
if (RequireIntervals)
SlotIdx = LIS->getInstructionIndex(CurrPos).getRegSlot();
// Open the top of the region using slot indexes.
if (RequireIntervals && isTopClosed())
static_cast<IntervalPressure&>(P).openTop(SlotIdx);
}
void RegPressureTracker::recede(SmallVectorImpl<unsigned> *LiveUses) {
recedeSkipDebugValues();
const MachineInstr &MI = *CurrPos;
RegisterOperands RegOpers;
RegOpers.collect(MI, *TRI, *MRI);
if (RequireIntervals)
RegOpers.detectDeadDefs(MI, *LIS);
recede(RegOpers, LiveUses);
}
/// Advance across the current instruction.
void RegPressureTracker::advance() {
assert(!TrackUntiedDefs && "unsupported mode");

View File

@ -896,11 +896,16 @@ void ScheduleDAGInstrs::buildSchedGraph(AliasAnalysis *AA,
assert(SU && "No SUnit mapped to this MI");
if (RPTracker) {
PressureDiff *PDiff = PDiffs ? &(*PDiffs)[SU->NodeNum] : nullptr;
RPTracker->recede(/*LiveUses=*/nullptr, PDiff);
assert(RPTracker->getPos() == std::prev(MII) &&
"RPTracker can't find MI");
collectVRegUses(SU);
RegisterOperands RegOpers;
RegOpers.collect(*MI, *TRI, MRI);
if (PDiffs != nullptr)
PDiffs->addInstruction(SU->NodeNum, RegOpers, MRI);
RPTracker->recedeSkipDebugValues();
assert(&*RPTracker->getPos() == MI && "RPTracker in sync");
RPTracker->recede(RegOpers);
}
assert(
@ -1005,6 +1010,9 @@ void ScheduleDAGInstrs::buildSchedGraph(AliasAnalysis *AA,
addChainDependency(AAForDep, MFI, MF.getDataLayout(), SU,
I->second[i], RejectMemNodes, TrueMemOrderLatency);
}
// This call must come after calls to addChainDependency() since it
// consumes the 'RejectMemNodes' list that addChainDependency() possibly
// adds to.
adjustChainDeps(AA, MFI, MF.getDataLayout(), SU, &ExitSU, RejectMemNodes,
TrueMemOrderLatency);
PendingLoads.clear();
@ -1086,6 +1094,9 @@ void ScheduleDAGInstrs::buildSchedGraph(AliasAnalysis *AA,
addChainDependency(AAForDep, MFI, MF.getDataLayout(), SU, AliasChain,
RejectMemNodes);
}
// This call must come after calls to addChainDependency() since it
// consumes the 'RejectMemNodes' list that addChainDependency() possibly
// adds to.
adjustChainDeps(AA, MFI, MF.getDataLayout(), SU, &ExitSU, RejectMemNodes,
TrueMemOrderLatency);
} else if (MI->mayLoad()) {
@ -1133,13 +1144,16 @@ void ScheduleDAGInstrs::buildSchedGraph(AliasAnalysis *AA,
else
NonAliasMemUses[V].push_back(SU);
}
if (MayAlias)
adjustChainDeps(AA, MFI, MF.getDataLayout(), SU, &ExitSU,
RejectMemNodes, /*Latency=*/0);
// Add dependencies on alias and barrier chains, if needed.
if (MayAlias && AliasChain)
addChainDependency(AAForDep, MFI, MF.getDataLayout(), SU, AliasChain,
RejectMemNodes);
if (MayAlias)
// This call must come after calls to addChainDependency() since it
// consumes the 'RejectMemNodes' list that addChainDependency()
// possibly adds to.
adjustChainDeps(AA, MFI, MF.getDataLayout(), SU, &ExitSU,
RejectMemNodes, /*Latency=*/0);
if (BarrierChain)
BarrierChain->addPred(SDep(SU, SDep::Barrier));
}

View File

@ -7325,6 +7325,7 @@ SDValue DAGCombiner::visitBITCAST(SDNode *N) {
// fold (bitcast (fneg x)) ->
// flipbit = signbit
// (xor (bitcast x) (build_pair flipbit, flipbit))
//
// fold (bitcast (fabs x)) ->
// flipbit = (and (extract_element (bitcast x), 0), signbit)
// (xor (bitcast x) (build_pair flipbit, flipbit))
@ -8794,20 +8795,21 @@ SDValue DAGCombiner::visitFSQRT(SDNode *N) {
ZeroCmp, Zero, RV);
}
/// copysign(x, fp_extend(y)) -> copysign(x, y)
/// copysign(x, fp_round(y)) -> copysign(x, y)
static inline bool CanCombineFCOPYSIGN_EXTEND_ROUND(SDNode *N) {
// copysign(x, fp_extend(y)) -> copysign(x, y)
// copysign(x, fp_round(y)) -> copysign(x, y)
// Do not optimize out type conversion of f128 type yet.
// For some target like x86_64, configuration is changed
// to keep one f128 value in one SSE register, but
// instruction selection cannot handle FCOPYSIGN on
// SSE registers yet.
SDValue N1 = N->getOperand(1);
EVT N1VT = N1->getValueType(0);
EVT N1Op0VT = N1->getOperand(0)->getValueType(0);
return (N1.getOpcode() == ISD::FP_EXTEND ||
N1.getOpcode() == ISD::FP_ROUND) &&
(N1VT == N1Op0VT || N1Op0VT != MVT::f128);
if ((N1.getOpcode() == ISD::FP_EXTEND ||
N1.getOpcode() == ISD::FP_ROUND)) {
// Do not optimize out type conversion of f128 type yet.
// For some targets like x86_64, configuration is changed to keep one f128
// value in one SSE register, but instruction selection cannot handle
// FCOPYSIGN on SSE registers yet.
EVT N1VT = N1->getValueType(0);
EVT N1Op0VT = N1->getOperand(0)->getValueType(0);
return (N1VT == N1Op0VT || N1Op0VT != MVT::f128);
}
return false;
}
SDValue DAGCombiner::visitFCOPYSIGN(SDNode *N) {

View File

@ -297,8 +297,6 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf,
else if (Personality == EHPersonality::CoreCLR)
calculateClrEHStateNumbers(&fn, EHInfo);
calculateCatchReturnSuccessorColors(&fn, EHInfo);
// Map all BB references in the WinEH data to MBBs.
for (WinEHTryBlockMapEntry &TBME : EHInfo.TryBlockMap) {
for (WinEHHandlerType &H : TBME.HandlerArray) {

View File

@ -2941,6 +2941,18 @@ SDValue SelectionDAGLegalize::ExpandBitCount(unsigned Opc, SDValue Op,
// This trivially expands to CTLZ.
return DAG.getNode(ISD::CTLZ, dl, Op.getValueType(), Op);
case ISD::CTLZ: {
EVT VT = Op.getValueType();
unsigned len = VT.getSizeInBits();
if (TLI.isOperationLegalOrCustom(ISD::CTLZ_ZERO_UNDEF, VT)) {
EVT SetCCVT = getSetCCResultType(VT);
SDValue CTLZ = DAG.getNode(ISD::CTLZ_ZERO_UNDEF, dl, VT, Op);
SDValue Zero = DAG.getConstant(0, dl, VT);
SDValue SrcIsZero = DAG.getSetCC(dl, SetCCVT, Op, Zero, ISD::SETEQ);
return DAG.getNode(ISD::SELECT, dl, VT, SrcIsZero,
DAG.getConstant(len, dl, VT), CTLZ);
}
// for now, we do this:
// x = x | (x >> 1);
// x = x | (x >> 2);
@ -2950,9 +2962,7 @@ SDValue SelectionDAGLegalize::ExpandBitCount(unsigned Opc, SDValue Op,
// return popcount(~x);
//
// Ref: "Hacker's Delight" by Henry Warren
EVT VT = Op.getValueType();
EVT ShVT = TLI.getShiftAmountTy(VT, DAG.getDataLayout());
unsigned len = VT.getSizeInBits();
for (unsigned i = 0; (1U << i) <= (len / 2); ++i) {
SDValue Tmp3 = DAG.getConstant(1ULL << i, dl, ShVT);
Op = DAG.getNode(ISD::OR, dl, VT, Op,

View File

@ -262,12 +262,8 @@ SDValue DAGTypeLegalizer::PromoteIntRes_BITCAST(SDNode *N) {
return DAG.getNode(ISD::ANY_EXTEND, dl, NOutVT, GetSoftenedFloat(InOp));
case TargetLowering::TypePromoteFloat: {
// Convert the promoted float by hand.
if (NOutVT.bitsEq(NInVT)) {
SDValue PromotedOp = GetPromotedFloat(InOp);
SDValue Trunc = DAG.getNode(ISD::FP_TO_FP16, dl, NOutVT, PromotedOp);
return DAG.getNode(ISD::AssertZext, dl, NOutVT, Trunc,
DAG.getValueType(OutVT));
}
SDValue PromotedOp = GetPromotedFloat(InOp);
return DAG.getNode(ISD::FP_TO_FP16, dl, NOutVT, PromotedOp);
break;
}
case TargetLowering::TypeExpandInteger:

Some files were not shown because too many files have changed in this diff Show More