Vendor import of clang trunk r306325:
https://llvm.org/svn/llvm-project/cfe/trunk@306325
This commit is contained in:
parent
325377b573
commit
ef915aab0a
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor/clang/dist/; revision=320376 svn path=/vendor/clang/clang-trunk-r306325/; revision=320377; tag=vendor/clang/clang-trunk-r306325
@ -856,15 +856,15 @@ mentioned above, call:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
_Block_object_assign(&dst->target, src->target, BLOCK_FIELD_<appropo>);
|
||||
_Block_object_assign(&dst->target, src->target, BLOCK_FIELD_<apropos>);
|
||||
|
||||
in the copy helper and:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
_Block_object_dispose(->target, BLOCK_FIELD_<appropo>);
|
||||
_Block_object_dispose(->target, BLOCK_FIELD_<apropos>);
|
||||
|
||||
in the dispose helper where ``<appropo>`` is:
|
||||
in the dispose helper where ``<apropos>`` is:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
@ -888,7 +888,7 @@ and functions are generated in the same manner.
|
||||
Under ObjC we allow ``__weak`` as an attribute on ``__block`` variables, and
|
||||
this causes the addition of ``BLOCK_FIELD_IS_WEAK`` orred onto the
|
||||
``BLOCK_FIELD_IS_BYREF`` flag when copying the ``block_byref`` structure in the
|
||||
``Block`` copy helper, and onto the ``BLOCK_FIELD_<appropo>`` field within the
|
||||
``Block`` copy helper, and onto the ``BLOCK_FIELD_<apropos>`` field within the
|
||||
``block_byref`` copy/dispose helper calls.
|
||||
|
||||
The prototypes, and summary, of the helper functions are:
|
||||
|
@ -120,6 +120,18 @@ entity.
|
||||
It operates on the current, potentially unsaved buffer and does not create
|
||||
or save any files. To revert a formatting, just undo.
|
||||
|
||||
An alternative option is to format changes when saving a file and thus to
|
||||
have a zero-effort integration into the coding workflow. To do this, add this to
|
||||
your `.vimrc`:
|
||||
|
||||
.. code-block:: vim
|
||||
|
||||
function! Formatonsave()
|
||||
let l:formatdiff = 1
|
||||
pyf ~/llvm/tools/clang/tools/clang-format/clang-format.py
|
||||
endfunction
|
||||
autocmd BufWritePre *.h,*.cc,*.cpp call Formatonsave()
|
||||
|
||||
|
||||
Emacs Integration
|
||||
=================
|
||||
|
@ -309,12 +309,28 @@ the configuration (without a prefix: ``Auto``).
|
||||
* ``SFS_None`` (in configuration: ``None``)
|
||||
Never merge functions into a single line.
|
||||
|
||||
* ``SFS_InlineOnly`` (in configuration: ``InlineOnly``)
|
||||
Only merge functions defined inside a class. Same as "inline",
|
||||
except it does not implies "empty": i.e. top level empty functions
|
||||
are not merged either.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
class Foo {
|
||||
void f() { foo(); }
|
||||
};
|
||||
void f() {
|
||||
foo();
|
||||
}
|
||||
void f() {
|
||||
}
|
||||
|
||||
* ``SFS_Empty`` (in configuration: ``Empty``)
|
||||
Only merge empty functions.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
void f() { bar(); }
|
||||
void f() {}
|
||||
void f2() {
|
||||
bar2();
|
||||
}
|
||||
@ -327,6 +343,10 @@ the configuration (without a prefix: ``Auto``).
|
||||
class Foo {
|
||||
void f() { foo(); }
|
||||
};
|
||||
void f() {
|
||||
foo();
|
||||
}
|
||||
void f() {}
|
||||
|
||||
* ``SFS_All`` (in configuration: ``All``)
|
||||
Merge all functions fitting on a single line.
|
||||
@ -518,147 +538,159 @@ the configuration (without a prefix: ``Auto``).
|
||||
|
||||
* ``bool AfterClass`` Wrap class definitions.
|
||||
|
||||
.. code-block:: c++
|
||||
.. code-block:: c++
|
||||
|
||||
true:
|
||||
class foo
|
||||
{};
|
||||
true:
|
||||
class foo {};
|
||||
|
||||
false:
|
||||
class foo {};
|
||||
false:
|
||||
class foo
|
||||
{};
|
||||
|
||||
* ``bool AfterControlStatement`` Wrap control statements (``if``/``for``/``while``/``switch``/..).
|
||||
|
||||
.. code-block:: c++
|
||||
.. code-block:: c++
|
||||
|
||||
true:
|
||||
if (foo())
|
||||
{
|
||||
} else
|
||||
{}
|
||||
for (int i = 0; i < 10; ++i)
|
||||
{}
|
||||
true:
|
||||
if (foo())
|
||||
{
|
||||
} else
|
||||
{}
|
||||
for (int i = 0; i < 10; ++i)
|
||||
{}
|
||||
|
||||
false:
|
||||
if (foo()) {
|
||||
} else {
|
||||
}
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
}
|
||||
false:
|
||||
if (foo()) {
|
||||
} else {
|
||||
}
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
}
|
||||
|
||||
* ``bool AfterEnum`` Wrap enum definitions.
|
||||
|
||||
.. code-block:: c++
|
||||
.. code-block:: c++
|
||||
|
||||
true:
|
||||
enum X : int
|
||||
{
|
||||
B
|
||||
};
|
||||
true:
|
||||
enum X : int
|
||||
{
|
||||
B
|
||||
};
|
||||
|
||||
false:
|
||||
enum X : int { B };
|
||||
false:
|
||||
enum X : int { B };
|
||||
|
||||
* ``bool AfterFunction`` Wrap function definitions.
|
||||
|
||||
.. code-block:: c++
|
||||
.. code-block:: c++
|
||||
|
||||
true:
|
||||
void foo()
|
||||
{
|
||||
bar();
|
||||
bar2();
|
||||
}
|
||||
true:
|
||||
void foo()
|
||||
{
|
||||
bar();
|
||||
bar2();
|
||||
}
|
||||
|
||||
false:
|
||||
void foo() {
|
||||
bar();
|
||||
bar2();
|
||||
}
|
||||
false:
|
||||
void foo() {
|
||||
bar();
|
||||
bar2();
|
||||
}
|
||||
|
||||
* ``bool AfterNamespace`` Wrap namespace definitions.
|
||||
|
||||
.. code-block:: c++
|
||||
.. code-block:: c++
|
||||
|
||||
true:
|
||||
namespace
|
||||
{
|
||||
int foo();
|
||||
int bar();
|
||||
}
|
||||
true:
|
||||
namespace
|
||||
{
|
||||
int foo();
|
||||
int bar();
|
||||
}
|
||||
|
||||
false:
|
||||
namespace {
|
||||
int foo();
|
||||
int bar();
|
||||
}
|
||||
false:
|
||||
namespace {
|
||||
int foo();
|
||||
int bar();
|
||||
}
|
||||
|
||||
* ``bool AfterObjCDeclaration`` Wrap ObjC definitions (``@autoreleasepool``, interfaces, ..).
|
||||
|
||||
* ``bool AfterStruct`` Wrap struct definitions.
|
||||
|
||||
.. code-block:: c++
|
||||
.. code-block:: c++
|
||||
|
||||
true:
|
||||
struct foo
|
||||
{
|
||||
int x;
|
||||
};
|
||||
true:
|
||||
struct foo
|
||||
{
|
||||
int x;
|
||||
};
|
||||
|
||||
false:
|
||||
struct foo {
|
||||
int x;
|
||||
};
|
||||
false:
|
||||
struct foo {
|
||||
int x;
|
||||
};
|
||||
|
||||
* ``bool AfterUnion`` Wrap union definitions.
|
||||
|
||||
.. code-block:: c++
|
||||
.. code-block:: c++
|
||||
|
||||
true:
|
||||
union foo
|
||||
{
|
||||
int x;
|
||||
}
|
||||
true:
|
||||
union foo
|
||||
{
|
||||
int x;
|
||||
}
|
||||
|
||||
false:
|
||||
union foo {
|
||||
int x;
|
||||
}
|
||||
false:
|
||||
union foo {
|
||||
int x;
|
||||
}
|
||||
|
||||
* ``bool BeforeCatch`` Wrap before ``catch``.
|
||||
|
||||
.. code-block:: c++
|
||||
.. code-block:: c++
|
||||
|
||||
true:
|
||||
try {
|
||||
foo();
|
||||
}
|
||||
catch () {
|
||||
}
|
||||
true:
|
||||
try {
|
||||
foo();
|
||||
}
|
||||
catch () {
|
||||
}
|
||||
|
||||
false:
|
||||
try {
|
||||
foo();
|
||||
} catch () {
|
||||
}
|
||||
false:
|
||||
try {
|
||||
foo();
|
||||
} catch () {
|
||||
}
|
||||
|
||||
* ``bool BeforeElse`` Wrap before ``else``.
|
||||
|
||||
.. code-block:: c++
|
||||
.. code-block:: c++
|
||||
|
||||
true:
|
||||
if (foo()) {
|
||||
}
|
||||
else {
|
||||
}
|
||||
true:
|
||||
if (foo()) {
|
||||
}
|
||||
else {
|
||||
}
|
||||
|
||||
false:
|
||||
if (foo()) {
|
||||
} else {
|
||||
}
|
||||
false:
|
||||
if (foo()) {
|
||||
} else {
|
||||
}
|
||||
|
||||
* ``bool IndentBraces`` Indent the wrapped braces themselves.
|
||||
|
||||
* ``bool SplitEmptyFunctionBody`` If ``false``, empty function body can be put on a single line.
|
||||
This option is used only if the opening brace of the function has
|
||||
already been wrapped, i.e. the `AfterFunction` brace wrapping mode is
|
||||
set, and the function could/should not be put on a single line (as per
|
||||
`AllowShortFunctionsOnASingleLine` and constructor formatting options).
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
int f() vs. inf f()
|
||||
{} {
|
||||
}
|
||||
|
||||
|
||||
**BreakAfterJavaFieldAnnotations** (``bool``)
|
||||
Break after each annotation on a field in Java files.
|
||||
@ -899,17 +931,40 @@ the configuration (without a prefix: ``Auto``).
|
||||
firstValue :
|
||||
SecondValueVeryVeryVeryVeryLong;
|
||||
|
||||
**BreakConstructorInitializersBeforeComma** (``bool``)
|
||||
Always break constructor initializers before commas and align
|
||||
the commas with the colon.
|
||||
**BreakConstructorInitializers** (``BreakConstructorInitializersStyle``)
|
||||
The constructor initializers style to use.
|
||||
|
||||
Possible values:
|
||||
|
||||
* ``BCIS_BeforeColon`` (in configuration: ``BeforeColon``)
|
||||
Break constructor initializers before the colon and after the commas.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
Constructor()
|
||||
: initializer1(),
|
||||
initializer2()
|
||||
|
||||
* ``BCIS_BeforeComma`` (in configuration: ``BeforeComma``)
|
||||
Break constructor initializers before the colon and commas, and align
|
||||
the commas with the colon.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
Constructor()
|
||||
: initializer1()
|
||||
, initializer2()
|
||||
|
||||
* ``BCIS_AfterColon`` (in configuration: ``AfterColon``)
|
||||
Break constructor initializers after the colon and commas.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
Constructor() :
|
||||
initializer1(),
|
||||
initializer2()
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
true: false:
|
||||
SomeClass::Constructor() vs. SomeClass::Constructor() : a(a),
|
||||
: a(a) b(b),
|
||||
, b(b) c(c) {}
|
||||
, c(c) {}
|
||||
|
||||
**BreakStringLiterals** (``bool``)
|
||||
Allow breaking string literals when formatting.
|
||||
@ -931,6 +986,31 @@ the configuration (without a prefix: ``Auto``).
|
||||
// Will leave the following line unaffected
|
||||
#include <vector> // FOOBAR pragma: keep
|
||||
|
||||
**CompactNamespaces** (``bool``)
|
||||
If ``true``, consecutive namespace declarations will be on the same
|
||||
line. If ``false``, each namespace is declared on a new line.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
true:
|
||||
namespace Foo { namespace Bar {
|
||||
}}
|
||||
|
||||
false:
|
||||
namespace Foo {
|
||||
namespace Bar {
|
||||
}
|
||||
}
|
||||
|
||||
If it does not fit on a single line, the overflowing namespaces get
|
||||
wrapped:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
namespace Foo { namespace Bar {
|
||||
namespace Extra {
|
||||
}}}
|
||||
|
||||
**ConstructorInitializerAllOnOneLineOrOnePerLine** (``bool``)
|
||||
If the constructor initializers don't fit on a line, put each
|
||||
initializer on its own line.
|
||||
@ -1321,6 +1401,9 @@ the configuration (without a prefix: ``Auto``).
|
||||
Add a space in front of an Objective-C protocol list, i.e. use
|
||||
``Foo <Protocol>`` instead of ``Foo<Protocol>``.
|
||||
|
||||
**PenaltyBreakAssignment** (``unsigned``)
|
||||
The penalty for breaking around an assignment operator.
|
||||
|
||||
**PenaltyBreakBeforeFirstCallParameter** (``unsigned``)
|
||||
The penalty for breaking a function call after ``call(``.
|
||||
|
||||
@ -1392,6 +1475,15 @@ the configuration (without a prefix: ``Auto``).
|
||||
#include "b.h" vs. #include "a.h"
|
||||
#include "a.h" #include "b.h"
|
||||
|
||||
**SortUsingDeclarations** (``bool``)
|
||||
If ``true``, clang-format will sort using declarations.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
false: true:
|
||||
using std::cout; vs. using std::cin;
|
||||
using std::cin; using std::cout;
|
||||
|
||||
**SpaceAfterCStyleCast** (``bool``)
|
||||
If ``true``, a space is inserted after C style casts.
|
||||
|
||||
|
@ -28,7 +28,9 @@ The core routine of LibFormat is ``reformat()``:
|
||||
|
||||
This reads a token stream out of the lexer ``Lex`` and reformats all the code
|
||||
ranges in ``Ranges``. The ``FormatStyle`` controls basic decisions made during
|
||||
formatting. A list of options can be found under :ref:`style-options`.
|
||||
formatting. A list of options can be found under :ref:`style-options`.
|
||||
|
||||
The style options are described in :doc:`ClangFormatStyleOptions`.
|
||||
|
||||
|
||||
.. _style-options:
|
||||
|
@ -27,7 +27,7 @@ executable, so make sure to use ``clang`` (not ``ld``) for the final
|
||||
link step. When linking shared libraries, the MemorySanitizer run-time
|
||||
is not linked, so ``-Wl,-z,defs`` may cause link errors (don't use it
|
||||
with MemorySanitizer). To get a reasonable performance add ``-O1`` or
|
||||
higher. To get meaninful stack traces in error messages add
|
||||
higher. To get meaningful stack traces in error messages add
|
||||
``-fno-omit-frame-pointer``. To get perfect stack traces you may need
|
||||
to disable inlining (just use ``-O1``) and tail call elimination
|
||||
(``-fno-optimize-sibling-calls``).
|
||||
|
@ -274,6 +274,11 @@ To specify an alternate directory for raw profiles, use
|
||||
Drawbacks and limitations
|
||||
=========================
|
||||
|
||||
* Prior to version 2.26, the GNU binutils BFD linker is not able link programs
|
||||
compiled with ``-fcoverage-mapping`` in its ``--gc-sections`` mode. Possible
|
||||
workarounds include disabling ``--gc-sections``, upgrading to a newer version
|
||||
of BFD, or using the Gold linker.
|
||||
|
||||
* Code coverage does not handle unpredictable changes in control flow or stack
|
||||
unwinding in the presence of exceptions precisely. Consider the following
|
||||
function:
|
||||
|
@ -126,6 +126,50 @@ which currently must be enabled through a linker option.
|
||||
- lld (as of LLVM r296702):
|
||||
``-Wl,--thinlto-cache-dir=/path/to/cache``
|
||||
|
||||
Cache Pruning
|
||||
-------------
|
||||
|
||||
To help keep the size of the cache under control, ThinLTO supports cache
|
||||
pruning. Cache pruning is supported with ld64 and ELF lld, but currently only
|
||||
ELF lld allows you to control the policy with a policy string. The cache
|
||||
policy must be specified with a linker option.
|
||||
|
||||
- ELF lld (as of LLVM r298036):
|
||||
``-Wl,--thinlto-cache-policy,POLICY``
|
||||
|
||||
A policy string is a series of key-value pairs separated by ``:`` characters.
|
||||
Possible key-value pairs are:
|
||||
|
||||
- ``cache_size=X%``: The maximum size for the cache directory is ``X`` percent
|
||||
of the available space on the the disk. Set to 100 to indicate no limit,
|
||||
50 to indicate that the cache size will not be left over half the available
|
||||
disk space. A value over 100 is invalid. A value of 0 disables the percentage
|
||||
size-based pruning. The default is 75%.
|
||||
|
||||
- ``cache_size_bytes=X``, ``cache_size_bytes=Xk``, ``cache_size_bytes=Xm``,
|
||||
``cache_size_bytes=Xg``:
|
||||
Sets the maximum size for the cache directory to ``X`` bytes (or KB, MB,
|
||||
GB respectively). A value over the amount of available space on the disk
|
||||
will be reduced to the amount of available space. A value of 0 disables
|
||||
the byte size-based pruning. The default is no byte size-based pruning.
|
||||
|
||||
Note that ThinLTO will apply both size-based pruning policies simultaneously,
|
||||
and changing one does not affect the other. For example, a policy of
|
||||
``cache_size_bytes=1g`` on its own will cause both the 1GB and default 75%
|
||||
policies to be applied unless the default ``cache_size`` is overridden.
|
||||
|
||||
- ``prune_after=Xs``, ``prune_after=Xm``, ``prune_after=Xh``: Sets the
|
||||
expiration time for cache files to ``X`` seconds (or minutes, hours
|
||||
respectively). When a file hasn't been accessed for ``prune_after`` seconds,
|
||||
it is removed from the cache. A value of 0 disables the expiration-based
|
||||
pruning. The default is 1 week.
|
||||
|
||||
- ``prune_interval=Xs``, ``prune_interval=Xm``, ``prune_interval=Xh``:
|
||||
Sets the pruning interval to ``X`` seconds (or minutes, hours
|
||||
respectively). This is intended to be used to avoid scanning the directory
|
||||
too often. It does not impact the decision of which files to prune. A
|
||||
value of 0 forces the scan to occur. The default is every 20 minutes.
|
||||
|
||||
Clang Bootstrap
|
||||
---------------
|
||||
|
||||
|
@ -24,10 +24,10 @@ def doxygen2rst(text):
|
||||
text = re.sub(r'\\\w+ ', '', text)
|
||||
return text
|
||||
|
||||
def indent(text, columns):
|
||||
def indent(text, columns, indent_first_line=True):
|
||||
indent = ' ' * columns
|
||||
s = re.sub(r'\n([^\n])', '\n' + indent + '\\1', text, flags=re.S)
|
||||
if s.startswith('\n'):
|
||||
if not indent_first_line or s.startswith('\n'):
|
||||
return s
|
||||
return indent + s
|
||||
|
||||
@ -64,7 +64,9 @@ def __init__(self, name, comment):
|
||||
self.comment = comment.strip()
|
||||
|
||||
def __str__(self):
|
||||
return '\n* ``%s`` %s' % (self.name, doxygen2rst(self.comment))
|
||||
return '\n* ``%s`` %s' % (
|
||||
self.name,
|
||||
doxygen2rst(indent(self.comment, 2, indent_first_line=False)))
|
||||
|
||||
class Enum:
|
||||
def __init__(self, name, comment):
|
||||
@ -179,7 +181,7 @@ class State:
|
||||
if enums.has_key(option.type):
|
||||
option.enum = enums[option.type]
|
||||
elif nested_structs.has_key(option.type):
|
||||
option.nested_struct = nested_structs[option.type];
|
||||
option.nested_struct = nested_structs[option.type]
|
||||
else:
|
||||
raise Exception('Unknown type: %s' % option.type)
|
||||
return options
|
||||
@ -195,4 +197,3 @@ class State:
|
||||
|
||||
with open(DOC_FILE, 'wb') as output:
|
||||
output.write(contents)
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
|* *|
|
||||
|*===----------------------------------------------------------------------===*|
|
||||
|* *|
|
||||
|* This header provides a public inferface to use CompilationDatabase without *|
|
||||
|* This header provides a public interface to use CompilationDatabase without *|
|
||||
|* the full Clang C++ API. *|
|
||||
|* *|
|
||||
\*===----------------------------------------------------------------------===*/
|
||||
|
@ -7,7 +7,7 @@
|
||||
|* *|
|
||||
|*===----------------------------------------------------------------------===*|
|
||||
|* *|
|
||||
|* This header provides a public inferface to a Clang library for extracting *|
|
||||
|* This header provides a public interface to a Clang library for extracting *|
|
||||
|* high-level symbol information from source files without exposing the full *|
|
||||
|* Clang C++ API. *|
|
||||
|* *|
|
||||
|
@ -1656,6 +1656,7 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
unsigned HasImplicitReturnZero : 1;
|
||||
unsigned IsLateTemplateParsed : 1;
|
||||
unsigned IsConstexpr : 1;
|
||||
unsigned InstantiationIsPending:1;
|
||||
|
||||
/// \brief Indicates if the function uses __try.
|
||||
unsigned UsesSEHTry : 1;
|
||||
@ -1751,6 +1752,7 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
IsDeleted(false), IsTrivial(false), IsDefaulted(false),
|
||||
IsExplicitlyDefaulted(false), HasImplicitReturnZero(false),
|
||||
IsLateTemplateParsed(false), IsConstexpr(isConstexprSpecified),
|
||||
InstantiationIsPending(false),
|
||||
UsesSEHTry(false), HasSkippedBody(false), WillHaveBody(false),
|
||||
EndRangeLoc(NameInfo.getEndLoc()), TemplateOrSpecialization(),
|
||||
DNLoc(NameInfo.getInfo()) {}
|
||||
@ -1872,7 +1874,7 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
///
|
||||
bool isThisDeclarationADefinition() const {
|
||||
return IsDeleted || IsDefaulted || Body || IsLateTemplateParsed ||
|
||||
hasDefiningAttr();
|
||||
WillHaveBody || hasDefiningAttr();
|
||||
}
|
||||
|
||||
/// doesThisDeclarationHaveABody - Returns whether this specific
|
||||
@ -1943,6 +1945,15 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
|
||||
bool isConstexpr() const { return IsConstexpr; }
|
||||
void setConstexpr(bool IC) { IsConstexpr = IC; }
|
||||
|
||||
/// \brief Whether the instantiation of this function is pending.
|
||||
/// This bit is set when the decision to instantiate this function is made
|
||||
/// and unset if and when the function body is created. That leaves out
|
||||
/// cases where instantiation did not happen because the template definition
|
||||
/// was not seen in this TU. This bit remains set in those cases, under the
|
||||
/// assumption that the instantiation will happen in some other TU.
|
||||
bool instantiationIsPending() const { return InstantiationIsPending; }
|
||||
void setInstantiationIsPending(bool IC) { InstantiationIsPending = IC; }
|
||||
|
||||
/// \brief Indicates the function uses __try.
|
||||
bool usesSEHTry() const { return UsesSEHTry; }
|
||||
void setUsesSEHTry(bool UST) { UsesSEHTry = UST; }
|
||||
|
@ -202,26 +202,33 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl {
|
||||
OBJC_TQ_CSNullability = 0x40
|
||||
};
|
||||
|
||||
protected:
|
||||
// Enumeration values used in the bits stored in NextInContextAndBits.
|
||||
enum {
|
||||
/// \brief Whether this declaration is a top-level declaration (function,
|
||||
/// global variable, etc.) that is lexically inside an objc container
|
||||
/// definition.
|
||||
TopLevelDeclInObjCContainerFlag = 0x01,
|
||||
|
||||
/// \brief Whether this declaration is private to the module in which it was
|
||||
/// defined.
|
||||
ModulePrivateFlag = 0x02
|
||||
/// The kind of ownership a declaration has, for visibility purposes.
|
||||
/// This enumeration is designed such that higher values represent higher
|
||||
/// levels of name hiding.
|
||||
enum class ModuleOwnershipKind : unsigned {
|
||||
/// This declaration is not owned by a module.
|
||||
Unowned,
|
||||
/// This declaration has an owning module, but is globally visible
|
||||
/// (typically because its owning module is visible and we know that
|
||||
/// modules cannot later become hidden in this compilation).
|
||||
/// After serialization and deserialization, this will be converted
|
||||
/// to VisibleWhenImported.
|
||||
Visible,
|
||||
/// This declaration has an owning module, and is visible when that
|
||||
/// module is imported.
|
||||
VisibleWhenImported,
|
||||
/// This declaration has an owning module, but is only visible to
|
||||
/// lookups that occur within that module.
|
||||
ModulePrivate
|
||||
};
|
||||
|
||||
|
||||
protected:
|
||||
/// \brief The next declaration within the same lexical
|
||||
/// DeclContext. These pointers form the linked list that is
|
||||
/// traversed via DeclContext's decls_begin()/decls_end().
|
||||
///
|
||||
/// The extra two bits are used for the TopLevelDeclInObjCContainer and
|
||||
/// ModulePrivate bits.
|
||||
llvm::PointerIntPair<Decl *, 2, unsigned> NextInContextAndBits;
|
||||
/// The extra two bits are used for the ModuleOwnershipKind.
|
||||
llvm::PointerIntPair<Decl *, 2, ModuleOwnershipKind> NextInContextAndBits;
|
||||
|
||||
private:
|
||||
friend class DeclContext;
|
||||
@ -282,6 +289,11 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl {
|
||||
/// are regarded as "referenced" but not "used".
|
||||
unsigned Referenced : 1;
|
||||
|
||||
/// \brief Whether this declaration is a top-level declaration (function,
|
||||
/// global variable, etc.) that is lexically inside an objc container
|
||||
/// definition.
|
||||
unsigned TopLevelDeclInObjCContainer : 1;
|
||||
|
||||
/// \brief Whether statistic collection is enabled.
|
||||
static bool StatisticsEnabled;
|
||||
|
||||
@ -294,11 +306,6 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl {
|
||||
/// \brief Whether this declaration was loaded from an AST file.
|
||||
unsigned FromASTFile : 1;
|
||||
|
||||
/// \brief Whether this declaration is hidden from normal name lookup, e.g.,
|
||||
/// because it is was loaded from an AST file is either module-private or
|
||||
/// because its submodule has not been made visible.
|
||||
unsigned Hidden : 1;
|
||||
|
||||
/// IdentifierNamespace - This specifies what IDNS_* namespace this lives in.
|
||||
unsigned IdentifierNamespace : 13;
|
||||
|
||||
@ -332,26 +339,38 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl {
|
||||
private:
|
||||
bool AccessDeclContextSanity() const;
|
||||
|
||||
/// Get the module ownership kind to use for a local lexical child of \p DC,
|
||||
/// which may be either a local or (rarely) an imported declaration.
|
||||
static ModuleOwnershipKind getModuleOwnershipKindForChildOf(DeclContext *DC) {
|
||||
if (DC) {
|
||||
auto *D = cast<Decl>(DC);
|
||||
auto MOK = D->getModuleOwnershipKind();
|
||||
if (MOK != ModuleOwnershipKind::Unowned &&
|
||||
(!D->isFromASTFile() || D->hasLocalOwningModuleStorage()))
|
||||
return MOK;
|
||||
// If D is not local and we have no local module storage, then we don't
|
||||
// need to track module ownership at all.
|
||||
}
|
||||
return ModuleOwnershipKind::Unowned;
|
||||
}
|
||||
|
||||
protected:
|
||||
Decl(Kind DK, DeclContext *DC, SourceLocation L)
|
||||
: NextInContextAndBits(), DeclCtx(DC), Loc(L), DeclKind(DK),
|
||||
InvalidDecl(0), HasAttrs(false), Implicit(false), Used(false),
|
||||
Referenced(false), Access(AS_none), FromASTFile(0),
|
||||
Hidden(DC && cast<Decl>(DC)->Hidden &&
|
||||
(!cast<Decl>(DC)->isFromASTFile() ||
|
||||
hasLocalOwningModuleStorage())),
|
||||
: NextInContextAndBits(nullptr, getModuleOwnershipKindForChildOf(DC)),
|
||||
DeclCtx(DC), Loc(L), DeclKind(DK), InvalidDecl(0), HasAttrs(false),
|
||||
Implicit(false), Used(false), Referenced(false),
|
||||
TopLevelDeclInObjCContainer(false), Access(AS_none), FromASTFile(0),
|
||||
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
|
||||
CacheValidAndLinkage(0) {
|
||||
if (StatisticsEnabled) add(DK);
|
||||
}
|
||||
|
||||
Decl(Kind DK, EmptyShell Empty)
|
||||
: NextInContextAndBits(), DeclKind(DK), InvalidDecl(0),
|
||||
HasAttrs(false), Implicit(false), Used(false), Referenced(false),
|
||||
Access(AS_none), FromASTFile(0), Hidden(0),
|
||||
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
|
||||
CacheValidAndLinkage(0)
|
||||
{
|
||||
: NextInContextAndBits(), DeclKind(DK), InvalidDecl(0), HasAttrs(false),
|
||||
Implicit(false), Used(false), Referenced(false),
|
||||
TopLevelDeclInObjCContainer(false), Access(AS_none), FromASTFile(0),
|
||||
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
|
||||
CacheValidAndLinkage(0) {
|
||||
if (StatisticsEnabled) add(DK);
|
||||
}
|
||||
|
||||
@ -551,16 +570,11 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl {
|
||||
/// global variable, etc.) that is lexically inside an objc container
|
||||
/// definition.
|
||||
bool isTopLevelDeclInObjCContainer() const {
|
||||
return NextInContextAndBits.getInt() & TopLevelDeclInObjCContainerFlag;
|
||||
return TopLevelDeclInObjCContainer;
|
||||
}
|
||||
|
||||
void setTopLevelDeclInObjCContainer(bool V = true) {
|
||||
unsigned Bits = NextInContextAndBits.getInt();
|
||||
if (V)
|
||||
Bits |= TopLevelDeclInObjCContainerFlag;
|
||||
else
|
||||
Bits &= ~TopLevelDeclInObjCContainerFlag;
|
||||
NextInContextAndBits.setInt(Bits);
|
||||
TopLevelDeclInObjCContainer = V;
|
||||
}
|
||||
|
||||
/// \brief Looks on this and related declarations for an applicable
|
||||
@ -570,7 +584,7 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl {
|
||||
/// \brief Whether this declaration was marked as being private to the
|
||||
/// module in which it was defined.
|
||||
bool isModulePrivate() const {
|
||||
return NextInContextAndBits.getInt() & ModulePrivateFlag;
|
||||
return getModuleOwnershipKind() == ModuleOwnershipKind::ModulePrivate;
|
||||
}
|
||||
|
||||
/// \brief Whether this declaration is exported (by virtue of being lexically
|
||||
@ -585,15 +599,14 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl {
|
||||
const Attr *getDefiningAttr() const;
|
||||
|
||||
protected:
|
||||
/// \brief Specify whether this declaration was marked as being private
|
||||
/// \brief Specify that this declaration was marked as being private
|
||||
/// to the module in which it was defined.
|
||||
void setModulePrivate(bool MP = true) {
|
||||
unsigned Bits = NextInContextAndBits.getInt();
|
||||
if (MP)
|
||||
Bits |= ModulePrivateFlag;
|
||||
else
|
||||
Bits &= ~ModulePrivateFlag;
|
||||
NextInContextAndBits.setInt(Bits);
|
||||
void setModulePrivate() {
|
||||
// The module-private specifier has no effect on unowned declarations.
|
||||
// FIXME: We should track this in some way for source fidelity.
|
||||
if (getModuleOwnershipKind() == ModuleOwnershipKind::Unowned)
|
||||
return;
|
||||
setModuleOwnershipKind(ModuleOwnershipKind::ModulePrivate);
|
||||
}
|
||||
|
||||
/// \brief Set the owning module ID.
|
||||
@ -692,7 +705,7 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl {
|
||||
/// \brief Get the imported owning module, if this decl is from an imported
|
||||
/// (non-local) module.
|
||||
Module *getImportedOwningModule() const {
|
||||
if (!isFromASTFile())
|
||||
if (!isFromASTFile() || !hasOwningModule())
|
||||
return nullptr;
|
||||
|
||||
return getOwningModuleSlow();
|
||||
@ -701,31 +714,57 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl {
|
||||
/// \brief Get the local owning module, if known. Returns nullptr if owner is
|
||||
/// not yet known or declaration is not from a module.
|
||||
Module *getLocalOwningModule() const {
|
||||
if (isFromASTFile() || !Hidden)
|
||||
if (isFromASTFile() || !hasOwningModule())
|
||||
return nullptr;
|
||||
|
||||
assert(hasLocalOwningModuleStorage() &&
|
||||
"hidden local decl but no local module storage");
|
||||
"owned local decl but no local module storage");
|
||||
return reinterpret_cast<Module *const *>(this)[-1];
|
||||
}
|
||||
void setLocalOwningModule(Module *M) {
|
||||
assert(!isFromASTFile() && Hidden && hasLocalOwningModuleStorage() &&
|
||||
assert(!isFromASTFile() && hasOwningModule() &&
|
||||
hasLocalOwningModuleStorage() &&
|
||||
"should not have a cached owning module");
|
||||
reinterpret_cast<Module **>(this)[-1] = M;
|
||||
}
|
||||
|
||||
/// Is this declaration owned by some module?
|
||||
bool hasOwningModule() const {
|
||||
return getModuleOwnershipKind() != ModuleOwnershipKind::Unowned;
|
||||
}
|
||||
|
||||
/// Get the module that owns this declaration.
|
||||
Module *getOwningModule() const {
|
||||
return isFromASTFile() ? getImportedOwningModule() : getLocalOwningModule();
|
||||
}
|
||||
|
||||
/// \brief Determine whether this declaration is hidden from name lookup.
|
||||
bool isHidden() const { return Hidden; }
|
||||
/// \brief Determine whether this declaration might be hidden from name
|
||||
/// lookup. Note that the declaration might be visible even if this returns
|
||||
/// \c false, if the owning module is visible within the query context.
|
||||
// FIXME: Rename this to make it clearer what it does.
|
||||
bool isHidden() const {
|
||||
return (int)getModuleOwnershipKind() > (int)ModuleOwnershipKind::Visible;
|
||||
}
|
||||
|
||||
/// Set that this declaration is globally visible, even if it came from a
|
||||
/// module that is not visible.
|
||||
void setVisibleDespiteOwningModule() {
|
||||
if (hasOwningModule())
|
||||
setModuleOwnershipKind(ModuleOwnershipKind::Visible);
|
||||
}
|
||||
|
||||
/// \brief Get the kind of module ownership for this declaration.
|
||||
ModuleOwnershipKind getModuleOwnershipKind() const {
|
||||
return NextInContextAndBits.getInt();
|
||||
}
|
||||
|
||||
/// \brief Set whether this declaration is hidden from name lookup.
|
||||
void setHidden(bool Hide) {
|
||||
assert((!Hide || isFromASTFile() || hasLocalOwningModuleStorage()) &&
|
||||
"declaration with no owning module can't be hidden");
|
||||
Hidden = Hide;
|
||||
void setModuleOwnershipKind(ModuleOwnershipKind MOK) {
|
||||
assert(!(getModuleOwnershipKind() == ModuleOwnershipKind::Unowned &&
|
||||
MOK != ModuleOwnershipKind::Unowned && !isFromASTFile() &&
|
||||
!hasLocalOwningModuleStorage()) &&
|
||||
"no storage available for owning module for this declaration");
|
||||
NextInContextAndBits.setInt(MOK);
|
||||
}
|
||||
|
||||
unsigned getIdentifierNamespace() const {
|
||||
|
@ -17,6 +17,8 @@
|
||||
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/Regex.h"
|
||||
#include <vector>
|
||||
|
||||
namespace clang {
|
||||
@ -319,6 +321,26 @@ struct OnlyLargestCloneConstraint {
|
||||
void constrain(std::vector<CloneDetector::CloneGroup> &Result);
|
||||
};
|
||||
|
||||
struct FilenamePatternConstraint {
|
||||
StringRef IgnoredFilesPattern;
|
||||
std::shared_ptr<llvm::Regex> IgnoredFilesRegex;
|
||||
|
||||
FilenamePatternConstraint(StringRef IgnoredFilesPattern)
|
||||
: IgnoredFilesPattern(IgnoredFilesPattern) {
|
||||
IgnoredFilesRegex = std::make_shared<llvm::Regex>("^(" +
|
||||
IgnoredFilesPattern.str() + "$)");
|
||||
}
|
||||
|
||||
bool isAutoGenerated(const CloneDetector::CloneGroup &Group);
|
||||
|
||||
void constrain(std::vector<CloneDetector::CloneGroup> &CloneGroups) {
|
||||
CloneConstraint::filterGroups(
|
||||
CloneGroups, [this](const CloneDetector::CloneGroup &Group) {
|
||||
return isAutoGenerated(Group);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/// Analyzes the pattern of the referenced variables in a statement.
|
||||
class VariablePattern {
|
||||
|
||||
|
@ -52,6 +52,7 @@
|
||||
// LL -> long long
|
||||
// LLL -> __int128_t (e.g. LLLi)
|
||||
// W -> int64_t
|
||||
// N -> 'int' size if target is LP64, 'L' otherwise.
|
||||
// S -> signed
|
||||
// U -> unsigned
|
||||
// I -> Required to constant fold to an integer constant expression.
|
||||
@ -718,11 +719,11 @@ BUILTIN(__builtin_rindex, "c*cC*i", "Fn")
|
||||
LANGBUILTIN(_alloca, "v*z", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__assume, "vb", "n", ALL_MS_LANGUAGES)
|
||||
LIBBUILTIN(_byteswap_ushort, "UsUs", "fnc", "stdlib.h", ALL_MS_LANGUAGES)
|
||||
LIBBUILTIN(_byteswap_ulong, "ULiULi", "fnc", "stdlib.h", ALL_MS_LANGUAGES)
|
||||
LIBBUILTIN(_byteswap_ulong, "UNiUNi", "fnc", "stdlib.h", ALL_MS_LANGUAGES)
|
||||
LIBBUILTIN(_byteswap_uint64, "ULLiULLi", "fnc", "stdlib.h", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__debugbreak, "v", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__exception_code, "ULi", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_exception_code, "ULi", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__exception_code, "UNi", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_exception_code, "UNi", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__exception_info, "v*", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_exception_info, "v*", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__abnormal_termination, "i", "n", ALL_MS_LANGUAGES)
|
||||
@ -730,33 +731,33 @@ LANGBUILTIN(_abnormal_termination, "i", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__GetExceptionInfo, "v*.", "ntu", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedAnd8, "ccD*c", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedAnd16, "ssD*s", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedAnd, "LiLiD*Li", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedAnd, "NiNiD*Ni", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedCompareExchange8, "ccD*cc", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedCompareExchange16, "ssD*ss", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedCompareExchange, "LiLiD*LiLi", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedCompareExchange, "NiNiD*NiNi", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedCompareExchange64, "LLiLLiD*LLiLLi", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedCompareExchangePointer, "v*v*D*v*v*", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedDecrement16, "ssD*", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedDecrement, "LiLiD*", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedExchange, "LiLiD*Li", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedDecrement, "NiNiD*", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedExchange, "NiNiD*Ni", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedExchange8, "ccD*c", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedExchange16, "ssD*s", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedExchangeAdd8, "ccD*c", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedExchangeAdd16, "ssD*s", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedExchangeAdd, "LiLiD*Li", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedExchangeAdd, "NiNiD*Ni", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedExchangePointer, "v*v*D*v*", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedExchangeSub8, "ccD*c", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedExchangeSub16, "ssD*s", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedExchangeSub, "LiLiD*Li", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedExchangeSub, "NiNiD*Ni", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedIncrement16, "ssD*", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedIncrement, "LiLiD*", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedIncrement, "NiNiD*", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedOr8, "ccD*c", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedOr16, "ssD*s", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedOr, "LiLiD*Li", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedOr, "NiNiD*Ni", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedXor8, "ccD*c", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedXor16, "ssD*s", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedXor, "LiLiD*Li", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_interlockedbittestandset, "UcLiD*Li", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_InterlockedXor, "NiNiD*Ni", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_interlockedbittestandset, "UcNiD*Ni", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__noop, "i.", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__popcnt16, "UsUs", "nc", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__popcnt, "UiUi", "nc", ALL_MS_LANGUAGES)
|
||||
@ -765,12 +766,12 @@ LANGBUILTIN(_ReturnAddress, "v*", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_rotl8, "UcUcUc", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_rotl16, "UsUsUc", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_rotl, "UiUii", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_lrotl, "ULiULii", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_lrotl, "UNiUNii", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_rotl64, "ULLiULLii", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_rotr8, "UcUcUc", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_rotr16, "UsUsUc", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_rotr, "UiUii", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_lrotr, "ULiULii", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_lrotr, "UNiUNii", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_rotr64, "ULLiULLii", "n", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__va_start, "vc**.", "nt", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(__fastfail, "vUi", "nr", ALL_MS_LANGUAGES)
|
||||
|
@ -215,10 +215,10 @@ LANGBUILTIN(_MoveFromCoprocessor2, "UiIUiIUiIUiIUiIUi", "", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_MoveToCoprocessor, "vUiIUiIUiIUiIUiIUi", "", ALL_MS_LANGUAGES)
|
||||
LANGBUILTIN(_MoveToCoprocessor2, "vUiIUiIUiIUiIUiIUi", "", ALL_MS_LANGUAGES)
|
||||
|
||||
TARGET_HEADER_BUILTIN(_BitScanForward, "UcULi*ULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(_BitScanReverse, "UcULi*ULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(_BitScanForward64, "UcULi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(_BitScanReverse64, "UcULi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(_BitScanForward, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(_BitScanReverse, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(_BitScanForward64, "UcUNi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(_BitScanReverse64, "UcUNi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
|
||||
TARGET_HEADER_BUILTIN(_InterlockedAnd64, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(_InterlockedDecrement64, "LLiLLiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
|
@ -1822,8 +1822,8 @@ TARGET_BUILTIN(__builtin_ia32_mwaitx, "vUiUiUi", "", "mwaitx")
|
||||
TARGET_BUILTIN(__builtin_ia32_clzero, "vv*", "", "clzero")
|
||||
|
||||
// MSVC
|
||||
TARGET_HEADER_BUILTIN(_BitScanForward, "UcULi*ULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(_BitScanReverse, "UcULi*ULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(_BitScanForward, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(_BitScanReverse, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
|
||||
TARGET_HEADER_BUILTIN(_ReadWriteBarrier, "v", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(_ReadBarrier, "v", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
@ -1838,15 +1838,15 @@ TARGET_HEADER_BUILTIN(__stosb, "vUc*Ucz", "nh", "intrin.h", ALL_MS_LANGUAGES, ""
|
||||
TARGET_HEADER_BUILTIN(__int2c, "v", "nr", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(__ud2, "v", "nr", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
|
||||
TARGET_HEADER_BUILTIN(__readfsbyte, "UcULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(__readfsword, "UsULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(__readfsdword, "ULiULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(__readfsqword, "ULLiULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(__readfsbyte, "UcUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(__readfsword, "UsUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(__readfsdword, "UNiUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(__readfsqword, "ULLiUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
|
||||
TARGET_HEADER_BUILTIN(__readgsbyte, "UcULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(__readgsword, "UsULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(__readgsdword, "ULiULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(__readgsqword, "ULLiULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(__readgsbyte, "UcUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(__readgsword, "UsUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(__readgsdword, "UNiUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(__readgsqword, "ULLiUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
|
||||
#undef BUILTIN
|
||||
#undef TARGET_BUILTIN
|
||||
|
@ -22,8 +22,8 @@
|
||||
# define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANG, FEATURE) BUILTIN(ID, TYPE, ATTRS)
|
||||
#endif
|
||||
|
||||
TARGET_HEADER_BUILTIN(_BitScanForward64, "UcULi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(_BitScanReverse64, "UcULi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(_BitScanForward64, "UcUNi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(_BitScanReverse64, "UcUNi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
|
||||
TARGET_HEADER_BUILTIN(__mulh, "LLiLLiLLi", "nch", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(__umulh, "ULLiULLiULLi", "nch", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
|
@ -226,6 +226,9 @@ def warn_drv_enabling_rtti_with_exceptions : Warning<
|
||||
def warn_drv_disabling_vptr_no_rtti_default : Warning<
|
||||
"implicitly disabling vptr sanitizer because rtti wasn't enabled">,
|
||||
InGroup<DiagGroup<"auto-disable-vptr-sanitizer">>;
|
||||
def warn_drv_object_size_disabled_O0 : Warning<
|
||||
"the object size sanitizer has no effect at -O0, but is explicitly enabled: %0">,
|
||||
InGroup<InvalidCommandLineArgument>;
|
||||
|
||||
def note_drv_command_failed_diag_msg : Note<
|
||||
"diagnostic msg: %0">;
|
||||
|
@ -98,7 +98,9 @@ def CXX11CompatDeprecatedWritableStr :
|
||||
def DeprecatedAttributes : DiagGroup<"deprecated-attributes">;
|
||||
def DeprecatedDeclarations : DiagGroup<"deprecated-declarations">;
|
||||
def UnavailableDeclarations : DiagGroup<"unavailable-declarations">;
|
||||
def UnguardedAvailability : DiagGroup<"unguarded-availability">;
|
||||
def UnguardedAvailabilityNew : DiagGroup<"unguarded-availability-new">;
|
||||
def UnguardedAvailability : DiagGroup<"unguarded-availability",
|
||||
[UnguardedAvailabilityNew]>;
|
||||
// partial-availability is an alias of unguarded-availability.
|
||||
def : DiagGroup<"partial-availability", [UnguardedAvailability]>;
|
||||
def DeprecatedDynamicExceptionSpec
|
||||
@ -149,6 +151,7 @@ def GNUFlexibleArrayUnionMember : DiagGroup<"gnu-flexible-array-union-member">;
|
||||
def GNUFoldingConstant : DiagGroup<"gnu-folding-constant">;
|
||||
def FormatExtraArgs : DiagGroup<"format-extra-args">;
|
||||
def FormatZeroLength : DiagGroup<"format-zero-length">;
|
||||
def CXX1zCompatMangling : DiagGroup<"c++1z-compat-mangling">;
|
||||
|
||||
// Warnings for C++1y code which is not compatible with prior C++ standards.
|
||||
def CXXPre14Compat : DiagGroup<"c++98-c++11-compat">;
|
||||
@ -211,7 +214,8 @@ def CXX14CompatPedantic : DiagGroup<"c++14-compat-pedantic",
|
||||
[CXXPre1zCompatPedantic]>;
|
||||
|
||||
def CXX1zCompat : DiagGroup<"c++1z-compat", [DeprecatedRegister,
|
||||
DeprecatedIncrementBool]>;
|
||||
DeprecatedIncrementBool,
|
||||
CXX1zCompatMangling]>;
|
||||
|
||||
def ExitTimeDestructors : DiagGroup<"exit-time-destructors">;
|
||||
def FlexibleArrayExtensions : DiagGroup<"flexible-array-extensions">;
|
||||
|
@ -507,7 +507,7 @@ def warn_deprecated_copy_operation : Warning<
|
||||
InGroup<Deprecated>, DefaultIgnore;
|
||||
def warn_cxx1z_compat_exception_spec_in_signature : Warning<
|
||||
"mangled name of %0 will change in C++17 due to non-throwing exception "
|
||||
"specification in function signature">, InGroup<CXX1zCompat>;
|
||||
"specification in function signature">, InGroup<CXX1zCompatMangling>;
|
||||
|
||||
def warn_global_constructor : Warning<
|
||||
"declaration requires a global constructor">,
|
||||
@ -2870,8 +2870,13 @@ def note_protocol_method : Note<
|
||||
def warn_unguarded_availability :
|
||||
Warning<"%0 is only available on %1 %2 or newer">,
|
||||
InGroup<UnguardedAvailability>, DefaultIgnore;
|
||||
def warn_unguarded_availability_new :
|
||||
Warning<warn_unguarded_availability.Text>,
|
||||
InGroup<UnguardedAvailabilityNew>;
|
||||
def warn_partial_availability : Warning<"%0 is only available conditionally">,
|
||||
InGroup<UnguardedAvailability>, DefaultIgnore;
|
||||
def warn_partial_availability_new : Warning<warn_partial_availability.Text>,
|
||||
InGroup<UnguardedAvailabilityNew>;
|
||||
def note_partial_availability_silence : Note<
|
||||
"explicitly redeclare %0 to silence this warning">;
|
||||
def note_unguarded_available_silence : Note<
|
||||
@ -2879,9 +2884,14 @@ def note_unguarded_available_silence : Note<
|
||||
" this warning">;
|
||||
def warn_partial_message : Warning<"%0 is partial: %1">,
|
||||
InGroup<UnguardedAvailability>, DefaultIgnore;
|
||||
def warn_partial_message_new : Warning<warn_partial_message.Text>,
|
||||
InGroup<UnguardedAvailabilityNew>;
|
||||
def warn_partial_fwdclass_message : Warning<
|
||||
"%0 may be partial because the receiver type is unknown">,
|
||||
InGroup<UnguardedAvailability>, DefaultIgnore;
|
||||
def warn_partial_fwdclass_message_new :
|
||||
Warning<warn_partial_fwdclass_message.Text>,
|
||||
InGroup<UnguardedAvailabilityNew>;
|
||||
def warn_at_available_unchecked_use : Warning<
|
||||
"%select{@available|__builtin_available}0 does not guard availability here; "
|
||||
"use if (%select{@available|__builtin_available}0) instead">,
|
||||
@ -6341,6 +6351,15 @@ def err_exceptions_disabled : Error<
|
||||
"cannot use '%0' with exceptions disabled">;
|
||||
def err_objc_exceptions_disabled : Error<
|
||||
"cannot use '%0' with Objective-C exceptions disabled">;
|
||||
def warn_throw_in_noexcept_func
|
||||
: Warning<"%0 has a non-throwing exception specification but can still "
|
||||
"throw, resulting in unexpected program termination">,
|
||||
InGroup<Exceptions>;
|
||||
def note_throw_in_dtor
|
||||
: Note<"destructor or deallocator has a (possibly implicit) non-throwing "
|
||||
"excepton specification">;
|
||||
def note_throw_in_function
|
||||
: Note<"non-throwing function declare here">;
|
||||
def err_seh_try_outside_functions : Error<
|
||||
"cannot use SEH '__try' in blocks, captured regions, or Obj-C method decls">;
|
||||
def err_mixing_cxx_try_seh_try : Error<
|
||||
@ -8311,6 +8330,9 @@ def err_opencl_ext_vector_component_invalid_length : Error<
|
||||
"vector component access has invalid length %0. Supported: 1,2,3,4,8,16.">;
|
||||
def err_opencl_function_variable : Error<
|
||||
"%select{non-kernel function|function scope}0 variable cannot be declared in %1 address space">;
|
||||
def err_opencl_addrspace_scope : Error<
|
||||
"variables in the %0 address space can only be declared in the outermost "
|
||||
"scope of a kernel function">;
|
||||
def err_static_function_scope : Error<
|
||||
"variables in function scope cannot be declared static">;
|
||||
def err_opencl_bitfields : Error<
|
||||
|
@ -112,8 +112,13 @@ def note_module_odr_violation_possible_decl : Note<
|
||||
def err_module_odr_violation_different_definitions : Error<
|
||||
"%q0 has different definitions in different modules; "
|
||||
"%select{definition in module '%2' is here|defined here}1">;
|
||||
def note_first_module_difference : Note<
|
||||
"in first definition, possible difference is here">;
|
||||
def note_module_odr_violation_different_definitions : Note<
|
||||
"definition in module '%0' is here">;
|
||||
def note_second_module_difference : Note<
|
||||
"in second definition, possible difference is here">;
|
||||
|
||||
def err_module_odr_violation_different_instantiations : Error<
|
||||
"instantiation of %q0 is different in different modules">;
|
||||
|
||||
|
@ -393,7 +393,9 @@ class Module {
|
||||
|
||||
/// \brief Retrieve the full name of this module, including the path from
|
||||
/// its top-level module.
|
||||
std::string getFullModuleName() const;
|
||||
/// \param AllowStringLiterals If \c true, components that might not be
|
||||
/// lexically valid as identifiers will be emitted as string literals.
|
||||
std::string getFullModuleName(bool AllowStringLiterals = false) const;
|
||||
|
||||
/// \brief Whether the full name of this module is equal to joining
|
||||
/// \p nameParts with "."s.
|
||||
|
@ -227,6 +227,7 @@ def OP_UNAVAILABLE : Operation {
|
||||
// u: unsigned integer (int/float args)
|
||||
// f: float (int args)
|
||||
// F: double (int args)
|
||||
// H: half (int args)
|
||||
// d: default
|
||||
// g: default, ignore 'Q' size modifier.
|
||||
// j: default, force 'Q' size modifier.
|
||||
@ -345,6 +346,7 @@ def OP_MLSLHi : Op<(call "vmlsl", $p0, (call "vget_high", $p1),
|
||||
(call "vget_high", $p2))>;
|
||||
def OP_MLSLHi_N : Op<(call "vmlsl_n", $p0, (call "vget_high", $p1), $p2)>;
|
||||
def OP_MUL_N : Op<(op "*", $p0, (dup $p1))>;
|
||||
def OP_MULX_N : Op<(call "vmulx", $p0, (dup $p1))>;
|
||||
def OP_MLA_N : Op<(op "+", $p0, (op "*", $p1, (dup $p2)))>;
|
||||
def OP_MLS_N : Op<(op "-", $p0, (op "*", $p1, (dup $p2)))>;
|
||||
def OP_FMLA_N : Op<(call "vfma", $p0, $p1, (dup $p2))>;
|
||||
@ -1661,3 +1663,186 @@ def SCALAR_SQRDMLSH_LANEQ : SOpInst<"vqrdmlsh_laneq", "sssji", "SsSi", OP_SCALAR
|
||||
def SCALAR_VDUP_LANE : IInst<"vdup_lane", "sdi", "ScSsSiSlSfSdSUcSUsSUiSUlSPcSPs">;
|
||||
def SCALAR_VDUP_LANEQ : IInst<"vdup_laneq", "sji", "ScSsSiSlSfSdSUcSUsSUiSUlSPcSPs">;
|
||||
}
|
||||
|
||||
// ARMv8.2-A FP16 intrinsics.
|
||||
let ArchGuard = "defined(__ARM_FEATURE_FP16_VECTOR_ARITHMETIC) && defined(__aarch64__)" in {
|
||||
|
||||
// ARMv8.2-A FP16 one-operand vector intrinsics.
|
||||
|
||||
// Comparison
|
||||
def CMEQH : SInst<"vceqz", "ud", "hQh">;
|
||||
def CMGEH : SInst<"vcgez", "ud", "hQh">;
|
||||
def CMGTH : SInst<"vcgtz", "ud", "hQh">;
|
||||
def CMLEH : SInst<"vclez", "ud", "hQh">;
|
||||
def CMLTH : SInst<"vcltz", "ud", "hQh">;
|
||||
|
||||
// Vector conversion
|
||||
def VCVT_F16 : SInst<"vcvt_f16", "Hd", "sUsQsQUs">;
|
||||
def VCVT_S16 : SInst<"vcvt_s16", "xd", "hQh">;
|
||||
def VCVT_U16 : SInst<"vcvt_u16", "ud", "hQh">;
|
||||
def VCVTA_S16 : SInst<"vcvta_s16", "xd", "hQh">;
|
||||
def VCVTA_U16 : SInst<"vcvta_u16", "ud", "hQh">;
|
||||
def VCVTM_S16 : SInst<"vcvtm_s16", "xd", "hQh">;
|
||||
def VCVTM_U16 : SInst<"vcvtm_u16", "ud", "hQh">;
|
||||
def VCVTN_S16 : SInst<"vcvtn_s16", "xd", "hQh">;
|
||||
def VCVTN_U16 : SInst<"vcvtn_u16", "ud", "hQh">;
|
||||
def VCVTP_S16 : SInst<"vcvtp_s16", "xd", "hQh">;
|
||||
def VCVTP_U16 : SInst<"vcvtp_u16", "ud", "hQh">;
|
||||
|
||||
// Vector rounding
|
||||
def FRINTZH : SInst<"vrnd", "dd", "hQh">;
|
||||
def FRINTNH : SInst<"vrndn", "dd", "hQh">;
|
||||
def FRINTAH : SInst<"vrnda", "dd", "hQh">;
|
||||
def FRINTPH : SInst<"vrndp", "dd", "hQh">;
|
||||
def FRINTMH : SInst<"vrndm", "dd", "hQh">;
|
||||
def FRINTXH : SInst<"vrndx", "dd", "hQh">;
|
||||
def FRINTIH : SInst<"vrndi", "dd", "hQh">;
|
||||
|
||||
// Misc.
|
||||
def VABSH : SInst<"vabs", "dd", "hQh">;
|
||||
def VNEGH : SOpInst<"vneg", "dd", "hQh", OP_NEG>;
|
||||
def VRECPEH : SInst<"vrecpe", "dd", "hQh">;
|
||||
def FRSQRTEH : SInst<"vrsqrte", "dd", "hQh">;
|
||||
def FSQRTH : SInst<"vsqrt", "dd", "hQh">;
|
||||
|
||||
// ARMv8.2-A FP16 two-operands vector intrinsics.
|
||||
|
||||
// Misc.
|
||||
def VADDH : SOpInst<"vadd", "ddd", "hQh", OP_ADD>;
|
||||
def VABDH : SInst<"vabd", "ddd", "hQh">;
|
||||
def VSUBH : SOpInst<"vsub", "ddd", "hQh", OP_SUB>;
|
||||
|
||||
// Comparison
|
||||
let InstName = "vacge" in {
|
||||
def VCAGEH : SInst<"vcage", "udd", "hQh">;
|
||||
def VCALEH : SInst<"vcale", "udd", "hQh">;
|
||||
}
|
||||
let InstName = "vacgt" in {
|
||||
def VCAGTH : SInst<"vcagt", "udd", "hQh">;
|
||||
def VCALTH : SInst<"vcalt", "udd", "hQh">;
|
||||
}
|
||||
def VCEQH : SOpInst<"vceq", "udd", "hQh", OP_EQ>;
|
||||
def VCGEH : SOpInst<"vcge", "udd", "hQh", OP_GE>;
|
||||
def VCGTH : SOpInst<"vcgt", "udd", "hQh", OP_GT>;
|
||||
let InstName = "vcge" in
|
||||
def VCLEH : SOpInst<"vcle", "udd", "hQh", OP_LE>;
|
||||
let InstName = "vcgt" in
|
||||
def VCLTH : SOpInst<"vclt", "udd", "hQh", OP_LT>;
|
||||
|
||||
// Vector conversion
|
||||
let isVCVT_N = 1 in {
|
||||
def VCVT_N_F16 : SInst<"vcvt_n_f16", "Hdi", "sUsQsQUs">;
|
||||
def VCVT_N_S16 : SInst<"vcvt_n_s16", "xdi", "hQh">;
|
||||
def VCVT_N_U16 : SInst<"vcvt_n_u16", "udi", "hQh">;
|
||||
}
|
||||
|
||||
// Max/Min
|
||||
def VMAXH : SInst<"vmax", "ddd", "hQh">;
|
||||
def VMINH : SInst<"vmin", "ddd", "hQh">;
|
||||
def FMAXNMH : SInst<"vmaxnm", "ddd", "hQh">;
|
||||
def FMINNMH : SInst<"vminnm", "ddd", "hQh">;
|
||||
|
||||
// Multiplication/Division
|
||||
def VMULH : SOpInst<"vmul", "ddd", "hQh", OP_MUL>;
|
||||
def MULXH : SInst<"vmulx", "ddd", "hQh">;
|
||||
def FDIVH : IOpInst<"vdiv", "ddd", "hQh", OP_DIV>;
|
||||
|
||||
// Pairwise addition
|
||||
def VPADDH : SInst<"vpadd", "ddd", "hQh">;
|
||||
|
||||
// Pairwise Max/Min
|
||||
def VPMAXH : SInst<"vpmax", "ddd", "hQh">;
|
||||
def VPMINH : SInst<"vpmin", "ddd", "hQh">;
|
||||
// Pairwise MaxNum/MinNum
|
||||
def FMAXNMPH : SInst<"vpmaxnm", "ddd", "hQh">;
|
||||
def FMINNMPH : SInst<"vpminnm", "ddd", "hQh">;
|
||||
|
||||
// Reciprocal/Sqrt
|
||||
def VRECPSH : SInst<"vrecps", "ddd", "hQh">;
|
||||
def VRSQRTSH : SInst<"vrsqrts", "ddd", "hQh">;
|
||||
|
||||
// ARMv8.2-A FP16 three-operands vector intrinsics.
|
||||
|
||||
// Vector fused multiply-add operations
|
||||
def VFMAH : SInst<"vfma", "dddd", "hQh">;
|
||||
def VFMSH : SOpInst<"vfms", "dddd", "hQh", OP_FMLS>;
|
||||
|
||||
// ARMv8.2-A FP16 lane vector intrinsics.
|
||||
|
||||
// FMA lane
|
||||
def VFMA_LANEH : IInst<"vfma_lane", "dddgi", "hQh">;
|
||||
def VFMA_LANEQH : IInst<"vfma_laneq", "dddji", "hQh">;
|
||||
|
||||
// FMA lane with scalar argument
|
||||
def FMLA_NH : SOpInst<"vfma_n", "ddds", "hQh", OP_FMLA_N>;
|
||||
// Scalar floating point fused multiply-add (scalar, by element)
|
||||
def SCALAR_FMLA_LANEH : IInst<"vfma_lane", "sssdi", "Sh">;
|
||||
def SCALAR_FMLA_LANEQH : IInst<"vfma_laneq", "sssji", "Sh">;
|
||||
|
||||
// FMS lane
|
||||
def VFMS_LANEH : IOpInst<"vfms_lane", "dddgi", "hQh", OP_FMS_LN>;
|
||||
def VFMS_LANEQH : IOpInst<"vfms_laneq", "dddji", "hQh", OP_FMS_LNQ>;
|
||||
// FMS lane with scalar argument
|
||||
def FMLS_NH : SOpInst<"vfms_n", "ddds", "hQh", OP_FMLS_N>;
|
||||
// Scalar floating foint fused multiply-subtract (scalar, by element)
|
||||
def SCALAR_FMLS_LANEH : IOpInst<"vfms_lane", "sssdi", "Sh", OP_FMS_LN>;
|
||||
def SCALAR_FMLS_LANEQH : IOpInst<"vfms_laneq", "sssji", "Sh", OP_FMS_LNQ>;
|
||||
|
||||
// Mul lane
|
||||
def VMUL_LANEH : IOpInst<"vmul_lane", "ddgi", "hQh", OP_MUL_LN>;
|
||||
def VMUL_LANEQH : IOpInst<"vmul_laneq", "ddji", "hQh", OP_MUL_LN>;
|
||||
def VMUL_NH : IOpInst<"vmul_n", "dds", "hQh", OP_MUL_N>;
|
||||
// Scalar floating point multiply (scalar, by element)
|
||||
def SCALAR_FMUL_LANEH : IOpInst<"vmul_lane", "ssdi", "Sh", OP_SCALAR_MUL_LN>;
|
||||
def SCALAR_FMUL_LANEQH : IOpInst<"vmul_laneq", "ssji", "Sh", OP_SCALAR_MUL_LN>;
|
||||
|
||||
// Mulx lane
|
||||
def VMULX_LANEH : IOpInst<"vmulx_lane", "ddgi", "hQh", OP_MULX_LN>;
|
||||
def VMULX_LANEQH : IOpInst<"vmulx_laneq", "ddji", "hQh", OP_MULX_LN>;
|
||||
def VMULX_NH : IOpInst<"vmulx_n", "dds", "hQh", OP_MULX_N>;
|
||||
// TODO: Scalar floating point multiply extended (scalar, by element)
|
||||
// Below ones are commented out because they need vmulx_f16(float16_t, float16_t)
|
||||
// which will be implemented later with fp16 scalar intrinsic (arm_fp16.h)
|
||||
//def SCALAR_FMULX_LANEH : IOpInst<"vmulx_lane", "ssdi", "Sh", OP_SCALAR_MUL_LN>;
|
||||
//def SCALAR_FMULX_LANEQH : IOpInst<"vmulx_laneq", "ssji", "Sh", OP_SCALAR_MUL_LN>;
|
||||
|
||||
// ARMv8.2-A FP16 reduction vector intrinsics.
|
||||
def VMAXVH : SInst<"vmaxv", "sd", "hQh">;
|
||||
def VMINVH : SInst<"vminv", "sd", "hQh">;
|
||||
def FMAXNMVH : SInst<"vmaxnmv", "sd", "hQh">;
|
||||
def FMINNMVH : SInst<"vminnmv", "sd", "hQh">;
|
||||
|
||||
// Data processing intrinsics - section 5
|
||||
|
||||
// Logical operations
|
||||
let isHiddenLInst = 1 in
|
||||
def VBSLH : SInst<"vbsl", "dudd", "hQh">;
|
||||
|
||||
// Transposition operations
|
||||
def VZIPH : WInst<"vzip", "2dd", "hQh">;
|
||||
def VUZPH : WInst<"vuzp", "2dd", "hQh">;
|
||||
def VTRNH : WInst<"vtrn", "2dd", "hQh">;
|
||||
|
||||
// Set all lanes to same value.
|
||||
/* Already implemented prior to ARMv8.2-A.
|
||||
def VMOV_NH : WOpInst<"vmov_n", "ds", "hQh", OP_DUP>;
|
||||
def VDUP_NH : WOpInst<"vdup_n", "ds", "hQh", OP_DUP>;
|
||||
def VDUP_LANE1H : WOpInst<"vdup_lane", "dgi", "hQh", OP_DUP_LN>;*/
|
||||
|
||||
// Vector Extract
|
||||
def VEXTH : WInst<"vext", "dddi", "hQh">;
|
||||
|
||||
// Reverse vector elements
|
||||
def VREV64H : WOpInst<"vrev64", "dd", "hQh", OP_REV64>;
|
||||
|
||||
// Permutation
|
||||
def VTRN1H : SOpInst<"vtrn1", "ddd", "hQh", OP_TRN1>;
|
||||
def VZIP1H : SOpInst<"vzip1", "ddd", "hQh", OP_ZIP1>;
|
||||
def VUZP1H : SOpInst<"vuzp1", "ddd", "hQh", OP_UZP1>;
|
||||
def VTRN2H : SOpInst<"vtrn2", "ddd", "hQh", OP_TRN2>;
|
||||
def VZIP2H : SOpInst<"vzip2", "ddd", "hQh", OP_ZIP2>;
|
||||
def VUZP2H : SOpInst<"vuzp2", "ddd", "hQh", OP_UZP2>;
|
||||
|
||||
def SCALAR_VDUP_LANEH : IInst<"vdup_lane", "sdi", "Sh">;
|
||||
def SCALAR_VDUP_LANEQH : IInst<"vdup_laneq", "sji", "Sh">;
|
||||
}
|
||||
|
@ -134,7 +134,6 @@ def migrator_no_finalize_removal : Flag<["-"], "no-finalize-removal">,
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
let Flags = [CC1Option, CC1AsOption, NoDriverOption] in {
|
||||
|
||||
def debug_info_kind_EQ : Joined<["-"], "debug-info-kind=">;
|
||||
def debug_info_macro : Flag<["-"], "debug-info-macro">,
|
||||
HelpText<"Emit macro debug information">;
|
||||
@ -144,20 +143,22 @@ def fdebug_compilation_dir : Separate<["-"], "fdebug-compilation-dir">,
|
||||
HelpText<"The compilation directory to embed in the debug info.">;
|
||||
def dwarf_debug_flags : Separate<["-"], "dwarf-debug-flags">,
|
||||
HelpText<"The string to embed in the Dwarf debug flags record.">;
|
||||
def compress_debug_sections : Flag<["-", "--"], "compress-debug-sections">,
|
||||
HelpText<"DWARF debug sections compression">;
|
||||
def compress_debug_sections_EQ : Flag<["-"], "compress-debug-sections=">,
|
||||
HelpText<"DWARF debug sections compression type">;
|
||||
def mno_exec_stack : Flag<["-"], "mnoexecstack">,
|
||||
HelpText<"Mark the file as not needing an executable stack">;
|
||||
def massembler_fatal_warnings : Flag<["-"], "massembler-fatal-warnings">,
|
||||
HelpText<"Make assembler warnings fatal">;
|
||||
def mrelax_relocations : Flag<["--"], "mrelax-relocations">,
|
||||
HelpText<"Use relaxable elf relocations">;
|
||||
def compress_debug_sections : Flag<["-"], "compress-debug-sections">,
|
||||
HelpText<"Compress DWARF debug sections using zlib">;
|
||||
def msave_temp_labels : Flag<["-"], "msave-temp-labels">,
|
||||
HelpText<"Save temporary labels in the symbol table. "
|
||||
"Note this may change .s semantics and shouldn't generally be used "
|
||||
"on compiler-generated code.">;
|
||||
def mrelocation_model : Separate<["-"], "mrelocation-model">,
|
||||
HelpText<"The relocation model to use">;
|
||||
HelpText<"The relocation model to use">, Values<"static,pic,ropi,rwpi,ropi-rwpi,dynamic-no-pic">;
|
||||
def fno_math_builtin : Flag<["-"], "fno-math-builtin">,
|
||||
HelpText<"Disable implicit builtin knowledge of math functions">;
|
||||
}
|
||||
@ -228,7 +229,7 @@ def no_struct_path_tbaa : Flag<["-"], "no-struct-path-tbaa">,
|
||||
def masm_verbose : Flag<["-"], "masm-verbose">,
|
||||
HelpText<"Generate verbose assembly output">;
|
||||
def mcode_model : Separate<["-"], "mcode-model">,
|
||||
HelpText<"The code model to use">;
|
||||
HelpText<"The code model to use">, Values<"small,kernel,medium,large">;
|
||||
def mdebug_pass : Separate<["-"], "mdebug-pass">,
|
||||
HelpText<"Enable additional debug output">;
|
||||
def mdisable_fp_elim : Flag<["-"], "mdisable-fp-elim">,
|
||||
@ -307,7 +308,7 @@ def fsanitize_coverage_no_prune
|
||||
HelpText<"Disable coverage pruning (i.e. instrument all blocks/edges)">;
|
||||
def fprofile_instrument_EQ : Joined<["-"], "fprofile-instrument=">,
|
||||
HelpText<"Enable PGO instrumentation. The accepted value is clang, llvm, "
|
||||
"or none">;
|
||||
"or none">, Values<"none,clang,llvm">;
|
||||
def fprofile_instrument_path_EQ : Joined<["-"], "fprofile-instrument-path=">,
|
||||
HelpText<"Generate instrumented code to collect execution counts into "
|
||||
"<file> (overridden by LLVM_PROFILE_FILE env var)">;
|
||||
@ -347,9 +348,9 @@ def diagnostic_serialized_file : Separate<["-"], "serialize-diagnostic-file">,
|
||||
HelpText<"File for serializing diagnostics in a binary format">;
|
||||
|
||||
def fdiagnostics_format : Separate<["-"], "fdiagnostics-format">,
|
||||
HelpText<"Change diagnostic formatting to match IDE and command line tools">;
|
||||
HelpText<"Change diagnostic formatting to match IDE and command line tools">, Values<"clang,msvc,msvc-fallback,vi">;
|
||||
def fdiagnostics_show_category : Separate<["-"], "fdiagnostics-show-category">,
|
||||
HelpText<"Print diagnostic category">;
|
||||
HelpText<"Print diagnostic category">, Values<"none,id,name">;
|
||||
def fno_diagnostics_use_presumed_location : Flag<["-"], "fno-diagnostics-use-presumed-location">,
|
||||
HelpText<"Ignore #line directives when displaying diagnostic locations">;
|
||||
def ftabstop : Separate<["-"], "ftabstop">, MetaVarName<"<N>">,
|
||||
@ -594,11 +595,11 @@ def fconstant_string_class : Separate<["-"], "fconstant-string-class">,
|
||||
MetaVarName<"<class name>">,
|
||||
HelpText<"Specify the class to use for constant Objective-C string objects.">;
|
||||
def fobjc_arc_cxxlib_EQ : Joined<["-"], "fobjc-arc-cxxlib=">,
|
||||
HelpText<"Objective-C++ Automatic Reference Counting standard library kind">;
|
||||
HelpText<"Objective-C++ Automatic Reference Counting standard library kind">, Values<"libc++,libstdc++,none">;
|
||||
def fobjc_runtime_has_weak : Flag<["-"], "fobjc-runtime-has-weak">,
|
||||
HelpText<"The target Objective-C runtime supports ARC weak operations">;
|
||||
def fobjc_dispatch_method_EQ : Joined<["-"], "fobjc-dispatch-method=">,
|
||||
HelpText<"Objective-C dispatch method to use">;
|
||||
HelpText<"Objective-C dispatch method to use">, Values<"legacy,non-legacy,mixed">;
|
||||
def disable_objc_default_synthesize_properties : Flag<["-"], "disable-objc-default-synthesize-properties">,
|
||||
HelpText<"disable the default synthesis of Objective-C properties">;
|
||||
def fencode_extended_block_signature : Flag<["-"], "fencode-extended-block-signature">,
|
||||
@ -672,7 +673,7 @@ def fnative_half_arguments_and_returns : Flag<["-"], "fnative-half-arguments-and
|
||||
def fallow_half_arguments_and_returns : Flag<["-"], "fallow-half-arguments-and-returns">,
|
||||
HelpText<"Allow function arguments and returns of type half">;
|
||||
def fdefault_calling_conv_EQ : Joined<["-"], "fdefault-calling-conv=">,
|
||||
HelpText<"Set default MS calling convention">;
|
||||
HelpText<"Set default MS calling convention">, Values<"cdecl,fastcall,stdcall,vectorcall">;
|
||||
def finclude_default_header : Flag<["-"], "finclude-default-header">,
|
||||
HelpText<"Include the default header file for OpenCL">;
|
||||
def fpreserve_vec3_type : Flag<["-"], "fpreserve-vec3-type">,
|
||||
|
@ -39,8 +39,9 @@ enum ClangFlags {
|
||||
|
||||
enum ID {
|
||||
OPT_INVALID = 0, // This is not an option ID.
|
||||
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
|
||||
HELPTEXT, METAVAR) OPT_##ID,
|
||||
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
|
||||
HELPTEXT, METAVAR, VALUES) \
|
||||
OPT_##ID,
|
||||
#include "clang/Driver/Options.inc"
|
||||
LastOption
|
||||
#undef OPTION
|
||||
|
@ -493,7 +493,7 @@ def cl_mad_enable : Flag<["-"], "cl-mad-enable">, Group<opencl_Group>, Flags<[CC
|
||||
def cl_no_signed_zeros : Flag<["-"], "cl-no-signed-zeros">, Group<opencl_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"OpenCL only. Allow use of less precise no signed zeros computations in the generated binary.">;
|
||||
def cl_std_EQ : Joined<["-"], "cl-std=">, Group<opencl_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"OpenCL language standard to compile for.">;
|
||||
HelpText<"OpenCL language standard to compile for.">, Values<"cl,CL,cl1.1,CL1.1,cl1.2,CL1.2,cl2.0,CL2.0">;
|
||||
def cl_denorms_are_zero : Flag<["-"], "cl-denorms-are-zero">, Group<opencl_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"OpenCL only. Allow denormals to be flushed to zero.">;
|
||||
def cl_fp32_correctly_rounded_divide_sqrt : Flag<["-"], "cl-fp32-correctly-rounded-divide-sqrt">, Group<opencl_Group>, Flags<[CC1Option]>,
|
||||
@ -804,7 +804,7 @@ def fno_sanitize_coverage
|
||||
: CommaJoined<["-"], "fno-sanitize-coverage=">,
|
||||
Group<f_clang_Group>, Flags<[CoreOption, DriverOption]>,
|
||||
HelpText<"Disable specified features of coverage instrumentation for "
|
||||
"Sanitizers">;
|
||||
"Sanitizers">, Values<"func,bb,edge,indirect-calls,trace-bb,trace-cmp,trace-div,trace-gep,8bit-counters,trace-pc,trace-pc-guard,no-prune,inline-8bit-counters">;
|
||||
def fsanitize_memory_track_origins_EQ : Joined<["-"], "fsanitize-memory-track-origins=">,
|
||||
Group<f_clang_Group>,
|
||||
HelpText<"Enable origins tracking in MemorySanitizer">;
|
||||
@ -923,7 +923,7 @@ def ftrapping_math : Flag<["-"], "ftrapping-math">, Group<f_Group>, Flags<[CC1Op
|
||||
def fno_trapping_math : Flag<["-"], "fno-trapping-math">, Group<f_Group>, Flags<[CC1Option]>;
|
||||
def ffp_contract : Joined<["-"], "ffp-contract=">, Group<f_Group>,
|
||||
Flags<[CC1Option]>, HelpText<"Form fused FP ops (e.g. FMAs): fast (everywhere)"
|
||||
" | on (according to FP_CONTRACT pragma, default) | off (never fuse)">;
|
||||
" | on (according to FP_CONTRACT pragma, default) | off (never fuse)">, Values<"fast,on,off">;
|
||||
|
||||
def ffor_scope : Flag<["-"], "ffor-scope">, Group<f_Group>;
|
||||
def fno_for_scope : Flag<["-"], "fno-for-scope">, Group<f_Group>;
|
||||
@ -1000,7 +1000,7 @@ def flat__namespace : Flag<["-"], "flat_namespace">;
|
||||
def flax_vector_conversions : Flag<["-"], "flax-vector-conversions">, Group<f_Group>;
|
||||
def flimited_precision_EQ : Joined<["-"], "flimited-precision=">, Group<f_Group>;
|
||||
def flto_EQ : Joined<["-"], "flto=">, Flags<[CoreOption, CC1Option]>, Group<f_Group>,
|
||||
HelpText<"Set LTO mode to either 'full' or 'thin'">;
|
||||
HelpText<"Set LTO mode to either 'full' or 'thin'">, Values<"thin,full">;
|
||||
def flto : Flag<["-"], "flto">, Flags<[CoreOption, CC1Option]>, Group<f_Group>,
|
||||
HelpText<"Enable LTO in 'full' mode">;
|
||||
def fno_lto : Flag<["-"], "fno-lto">, Group<f_Group>,
|
||||
@ -1158,7 +1158,7 @@ def fno_experimental_new_pass_manager : Flag<["-"], "fno-experimental-new-pass-m
|
||||
Group<f_clang_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"Disables an experimental new pass manager in LLVM.">;
|
||||
def fveclib : Joined<["-"], "fveclib=">, Group<f_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"Use the given vector functions library">;
|
||||
HelpText<"Use the given vector functions library">, Values<"Accelerate,SVML,none">;
|
||||
def fno_lax_vector_conversions : Flag<["-"], "fno-lax-vector-conversions">, Group<f_Group>,
|
||||
HelpText<"Disallow implicit conversions between vectors with a different number of elements or different element types">, Flags<[CC1Option]>;
|
||||
def fno_merge_all_constants : Flag<["-"], "fno-merge-all-constants">, Group<f_Group>,
|
||||
@ -1342,7 +1342,7 @@ def fno_short_wchar : Flag<["-"], "fno-short-wchar">, Group<f_Group>, Flags<[CC1
|
||||
HelpText<"Force wchar_t to be an unsigned int">;
|
||||
def fshow_overloads_EQ : Joined<["-"], "fshow-overloads=">, Group<f_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"Which overload candidates to show when overload resolution fails: "
|
||||
"best|all; defaults to all">;
|
||||
"best|all; defaults to all">, Values<"best,all">;
|
||||
def fshow_column : Flag<["-"], "fshow-column">, Group<f_Group>, Flags<[CC1Option]>;
|
||||
def fshow_source_location : Flag<["-"], "fshow-source-location">, Group<f_Group>;
|
||||
def fspell_checking : Flag<["-"], "fspell-checking">, Group<f_Group>;
|
||||
@ -1456,7 +1456,7 @@ def fuse_init_array : Flag<["-"], "fuse-init-array">, Group<f_Group>, Flags<[CC1
|
||||
def fno_var_tracking : Flag<["-"], "fno-var-tracking">, Group<clang_ignored_f_Group>;
|
||||
def fverbose_asm : Flag<["-"], "fverbose-asm">, Group<f_Group>;
|
||||
def fvisibility_EQ : Joined<["-"], "fvisibility=">, Group<f_Group>,
|
||||
HelpText<"Set the default symbol visibility for all global declarations">;
|
||||
HelpText<"Set the default symbol visibility for all global declarations">, Values<"hidden,default">;
|
||||
def fvisibility_inlines_hidden : Flag<["-"], "fvisibility-inlines-hidden">, Group<f_Group>,
|
||||
HelpText<"Give inline C++ member functions default visibility by default">,
|
||||
Flags<[CC1Option]>;
|
||||
@ -1563,6 +1563,10 @@ def gdwarf_aranges : Flag<["-"], "gdwarf-aranges">, Group<g_flags_Group>;
|
||||
def gmodules : Flag <["-"], "gmodules">, Group<gN_Group>,
|
||||
HelpText<"Generate debug info with external references to clang modules"
|
||||
" or precompiled headers">;
|
||||
def gz : Flag<["-"], "gz">, Group<g_flags_Group>,
|
||||
HelpText<"DWARF debug sections compression type">;
|
||||
def gz_EQ : Joined<["-"], "gz=">, Group<g_flags_Group>,
|
||||
HelpText<"DWARF debug sections compression type">;
|
||||
def headerpad__max__install__names : Joined<["-"], "headerpad_max_install_names">;
|
||||
def help : Flag<["-", "--"], "help">, Flags<[CC1Option,CC1AsOption]>,
|
||||
HelpText<"Display available options">;
|
||||
@ -1677,7 +1681,7 @@ def minline_all_stringops : Flag<["-"], "minline-all-stringops">, Group<clang_ig
|
||||
def mno_inline_all_stringops : Flag<["-"], "mno-inline-all-stringops">, Group<clang_ignored_m_Group>;
|
||||
def malign_double : Flag<["-"], "malign-double">, Group<m_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"Align doubles to two words in structs (x86 only)">;
|
||||
def mfloat_abi_EQ : Joined<["-"], "mfloat-abi=">, Group<m_Group>;
|
||||
def mfloat_abi_EQ : Joined<["-"], "mfloat-abi=">, Group<m_Group>, Values<"soft,softfp,hard">;
|
||||
def mfpmath_EQ : Joined<["-"], "mfpmath=">, Group<m_Group>;
|
||||
def mfpu_EQ : Joined<["-"], "mfpu=">, Group<m_Group>;
|
||||
def mhwdiv_EQ : Joined<["-"], "mhwdiv=">, Group<m_Group>;
|
||||
@ -1709,9 +1713,9 @@ def mstack_alignment : Joined<["-"], "mstack-alignment=">, Group<m_Group>, Flags
|
||||
def mstack_probe_size : Joined<["-"], "mstack-probe-size=">, Group<m_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"Set the stack probe size">;
|
||||
def mthread_model : Separate<["-"], "mthread-model">, Group<m_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"The thread model to use, e.g. posix, single (posix by default)">;
|
||||
HelpText<"The thread model to use, e.g. posix, single (posix by default)">, Values<"posix,single">;
|
||||
def meabi : Separate<["-"], "meabi">, Group<m_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"Set EABI type, e.g. 4, 5 or gnu (default depends on triple)">;
|
||||
HelpText<"Set EABI type, e.g. 4, 5 or gnu (default depends on triple)">, Values<"default,4,5,gnu">;
|
||||
|
||||
def mmmx : Flag<["-"], "mmmx">, Group<m_x86_Features_Group>;
|
||||
def mno_3dnowa : Flag<["-"], "mno-3dnowa">, Group<m_x86_Features_Group>;
|
||||
@ -2205,7 +2209,7 @@ def std_default_EQ : Joined<["-"], "std-default=">;
|
||||
def std_EQ : Joined<["-", "--"], "std=">, Flags<[CC1Option]>,
|
||||
Group<CompileOnly_Group>, HelpText<"Language standard to compile for">;
|
||||
def stdlib_EQ : Joined<["-", "--"], "stdlib=">, Flags<[CC1Option]>,
|
||||
HelpText<"C++ standard library to use">;
|
||||
HelpText<"C++ standard library to use">, Values<"libc++,libstdc++,platform">;
|
||||
def sub__library : JoinedOrSeparate<["-"], "sub_library">;
|
||||
def sub__umbrella : JoinedOrSeparate<["-"], "sub_umbrella">;
|
||||
def system_header_prefix : Joined<["--"], "system-header-prefix=">,
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "llvm/ADT/TinyPtrVector.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include <map>
|
||||
#include <tuple>
|
||||
|
||||
namespace clang {
|
||||
class LangOptions;
|
||||
@ -41,10 +42,20 @@ class EditedSource {
|
||||
typedef std::map<FileOffset, FileEdit> FileEditsTy;
|
||||
FileEditsTy FileEdits;
|
||||
|
||||
// Location of argument use inside the macro body
|
||||
typedef std::pair<IdentifierInfo*, SourceLocation> MacroArgUse;
|
||||
llvm::DenseMap<unsigned, SmallVector<MacroArgUse, 2>>
|
||||
ExpansionToArgMap;
|
||||
struct MacroArgUse {
|
||||
IdentifierInfo *Identifier;
|
||||
SourceLocation ImmediateExpansionLoc;
|
||||
// Location of argument use inside the top-level macro
|
||||
SourceLocation UseLoc;
|
||||
|
||||
bool operator==(const MacroArgUse &Other) const {
|
||||
return std::tie(Identifier, ImmediateExpansionLoc, UseLoc) ==
|
||||
std::tie(Other.Identifier, Other.ImmediateExpansionLoc,
|
||||
Other.UseLoc);
|
||||
}
|
||||
};
|
||||
|
||||
llvm::DenseMap<unsigned, SmallVector<MacroArgUse, 2>> ExpansionToArgMap;
|
||||
SmallVector<std::pair<SourceLocation, MacroArgUse>, 2>
|
||||
CurrCommitMacroArgExps;
|
||||
|
||||
|
@ -184,9 +184,23 @@ struct FormatStyle {
|
||||
enum ShortFunctionStyle {
|
||||
/// \brief Never merge functions into a single line.
|
||||
SFS_None,
|
||||
/// \brief Only merge functions defined inside a class. Same as "inline",
|
||||
/// except it does not implies "empty": i.e. top level empty functions
|
||||
/// are not merged either.
|
||||
/// \code
|
||||
/// class Foo {
|
||||
/// void f() { foo(); }
|
||||
/// };
|
||||
/// void f() {
|
||||
/// foo();
|
||||
/// }
|
||||
/// void f() {
|
||||
/// }
|
||||
/// \endcode
|
||||
SFS_InlineOnly,
|
||||
/// \brief Only merge empty functions.
|
||||
/// \code
|
||||
/// void f() { bar(); }
|
||||
/// void f() {}
|
||||
/// void f2() {
|
||||
/// bar2();
|
||||
/// }
|
||||
@ -197,6 +211,10 @@ struct FormatStyle {
|
||||
/// class Foo {
|
||||
/// void f() { foo(); }
|
||||
/// };
|
||||
/// void f() {
|
||||
/// foo();
|
||||
/// }
|
||||
/// void f() {}
|
||||
/// \endcode
|
||||
SFS_Inline,
|
||||
/// \brief Merge all functions fitting on a single line.
|
||||
@ -634,12 +652,12 @@ struct FormatStyle {
|
||||
/// struct foo
|
||||
/// {
|
||||
/// int x;
|
||||
/// }
|
||||
/// };
|
||||
///
|
||||
/// false:
|
||||
/// struct foo {
|
||||
/// int x;
|
||||
/// }
|
||||
/// };
|
||||
/// \endcode
|
||||
bool AfterStruct;
|
||||
/// \brief Wrap union definitions.
|
||||
@ -715,7 +733,7 @@ struct FormatStyle {
|
||||
/// ? firstValue
|
||||
/// : SecondValueVeryVeryVeryVeryLong;
|
||||
///
|
||||
/// true:
|
||||
/// false:
|
||||
/// veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongDescription ?
|
||||
/// firstValue :
|
||||
/// SecondValueVeryVeryVeryVeryLong;
|
||||
@ -723,8 +741,7 @@ struct FormatStyle {
|
||||
bool BreakBeforeTernaryOperators;
|
||||
|
||||
/// \brief Different ways to break initializers.
|
||||
enum BreakConstructorInitializersStyle
|
||||
{
|
||||
enum BreakConstructorInitializersStyle {
|
||||
/// Break constructor initializers before the colon and after the commas.
|
||||
/// \code
|
||||
/// Constructor()
|
||||
@ -749,7 +766,7 @@ struct FormatStyle {
|
||||
BCIS_AfterColon
|
||||
};
|
||||
|
||||
/// \brief The constructor initializers style to use..
|
||||
/// \brief The constructor initializers style to use.
|
||||
BreakConstructorInitializersStyle BreakConstructorInitializers;
|
||||
|
||||
/// \brief Break after each annotation on a field in Java files.
|
||||
@ -1253,6 +1270,14 @@ struct FormatStyle {
|
||||
/// \endcode
|
||||
bool SortIncludes;
|
||||
|
||||
/// \brief If ``true``, clang-format will sort using declarations.
|
||||
/// \code
|
||||
/// false: true:
|
||||
/// using std::cout; vs. using std::cin;
|
||||
/// using std::cin; using std::cout;
|
||||
/// \endcode
|
||||
bool SortUsingDeclarations;
|
||||
|
||||
/// \brief If ``true``, a space is inserted after C style casts.
|
||||
/// \code
|
||||
/// true: false:
|
||||
@ -1641,6 +1666,16 @@ tooling::Replacements fixNamespaceEndComments(const FormatStyle &Style,
|
||||
ArrayRef<tooling::Range> Ranges,
|
||||
StringRef FileName = "<stdin>");
|
||||
|
||||
/// \brief Sort consecutive using declarations in the given \p Ranges in
|
||||
/// \p Code.
|
||||
///
|
||||
/// Returns the ``Replacements`` that sort the using declarations in all
|
||||
/// \p Ranges in \p Code.
|
||||
tooling::Replacements sortUsingDeclarations(const FormatStyle &Style,
|
||||
StringRef Code,
|
||||
ArrayRef<tooling::Range> Ranges,
|
||||
StringRef FileName = "<stdin>");
|
||||
|
||||
/// \brief Returns the ``LangOpts`` that the formatter expects you to set.
|
||||
///
|
||||
/// \param Style determines specific settings for lexing mode.
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "clang/Lex/PreprocessingRecord.h"
|
||||
#include "clang/Sema/CodeCompleteConsumer.h"
|
||||
#include "clang/Serialization/ASTBitCodes.h"
|
||||
#include "clang/Frontend/PrecompiledPreamble.h"
|
||||
#include "llvm/ADT/IntrusiveRefCntPtr.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
@ -199,103 +200,15 @@ class ASTUnit {
|
||||
/// of that loading. It must be cleared when preamble is recreated.
|
||||
llvm::StringMap<SourceLocation> PreambleSrcLocCache;
|
||||
|
||||
public:
|
||||
class PreambleData {
|
||||
const FileEntry *File;
|
||||
std::vector<char> Buffer;
|
||||
mutable unsigned NumLines;
|
||||
|
||||
public:
|
||||
PreambleData() : File(nullptr), NumLines(0) { }
|
||||
|
||||
void assign(const FileEntry *F, const char *begin, const char *end) {
|
||||
File = F;
|
||||
Buffer.assign(begin, end);
|
||||
NumLines = 0;
|
||||
}
|
||||
|
||||
void clear() { Buffer.clear(); File = nullptr; NumLines = 0; }
|
||||
|
||||
size_t size() const { return Buffer.size(); }
|
||||
bool empty() const { return Buffer.empty(); }
|
||||
|
||||
const char *getBufferStart() const { return &Buffer[0]; }
|
||||
|
||||
unsigned getNumLines() const {
|
||||
if (NumLines)
|
||||
return NumLines;
|
||||
countLines();
|
||||
return NumLines;
|
||||
}
|
||||
|
||||
SourceRange getSourceRange(const SourceManager &SM) const {
|
||||
SourceLocation FileLoc = SM.getLocForStartOfFile(SM.getPreambleFileID());
|
||||
return SourceRange(FileLoc, FileLoc.getLocWithOffset(size()-1));
|
||||
}
|
||||
|
||||
private:
|
||||
void countLines() const;
|
||||
};
|
||||
|
||||
const PreambleData &getPreambleData() const {
|
||||
return Preamble;
|
||||
}
|
||||
|
||||
/// Data used to determine if a file used in the preamble has been changed.
|
||||
struct PreambleFileHash {
|
||||
/// All files have size set.
|
||||
off_t Size;
|
||||
|
||||
/// Modification time is set for files that are on disk. For memory
|
||||
/// buffers it is zero.
|
||||
time_t ModTime;
|
||||
|
||||
/// Memory buffers have MD5 instead of modification time. We don't
|
||||
/// compute MD5 for on-disk files because we hope that modification time is
|
||||
/// enough to tell if the file was changed.
|
||||
llvm::MD5::MD5Result MD5;
|
||||
|
||||
static PreambleFileHash createForFile(off_t Size, time_t ModTime);
|
||||
static PreambleFileHash
|
||||
createForMemoryBuffer(const llvm::MemoryBuffer *Buffer);
|
||||
|
||||
friend bool operator==(const PreambleFileHash &LHS,
|
||||
const PreambleFileHash &RHS);
|
||||
|
||||
friend bool operator!=(const PreambleFileHash &LHS,
|
||||
const PreambleFileHash &RHS) {
|
||||
return !(LHS == RHS);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
/// \brief The contents of the preamble that has been precompiled to
|
||||
/// \c PreambleFile.
|
||||
PreambleData Preamble;
|
||||
|
||||
/// \brief Whether the preamble ends at the start of a new line.
|
||||
///
|
||||
/// Used to inform the lexer as to whether it's starting at the beginning of
|
||||
/// a line after skipping the preamble.
|
||||
bool PreambleEndsAtStartOfLine;
|
||||
|
||||
/// \brief Keeps track of the files that were used when computing the
|
||||
/// preamble, with both their buffer size and their modification time.
|
||||
///
|
||||
/// If any of the files have changed from one compile to the next,
|
||||
/// the preamble must be thrown away.
|
||||
llvm::StringMap<PreambleFileHash> FilesInPreamble;
|
||||
/// The contents of the preamble.
|
||||
llvm::Optional<PrecompiledPreamble> Preamble;
|
||||
|
||||
/// \brief When non-NULL, this is the buffer used to store the contents of
|
||||
/// the main file when it has been padded for use with the precompiled
|
||||
/// preamble.
|
||||
std::unique_ptr<llvm::MemoryBuffer> SavedMainFileBuffer;
|
||||
|
||||
/// \brief When non-NULL, this is the buffer used to store the
|
||||
/// contents of the preamble when it has been padded to build the
|
||||
/// precompiled preamble.
|
||||
std::unique_ptr<llvm::MemoryBuffer> PreambleBuffer;
|
||||
|
||||
/// \brief The number of warnings that occurred while parsing the preamble.
|
||||
///
|
||||
/// This value will be used to restore the state of the \c DiagnosticsEngine
|
||||
@ -438,21 +351,6 @@ class ASTUnit {
|
||||
std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer,
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> VFS);
|
||||
|
||||
struct ComputedPreamble {
|
||||
llvm::MemoryBuffer *Buffer;
|
||||
std::unique_ptr<llvm::MemoryBuffer> Owner;
|
||||
unsigned Size;
|
||||
bool PreambleEndsAtStartOfLine;
|
||||
ComputedPreamble(llvm::MemoryBuffer *Buffer,
|
||||
std::unique_ptr<llvm::MemoryBuffer> Owner, unsigned Size,
|
||||
bool PreambleEndsAtStartOfLine)
|
||||
: Buffer(Buffer), Owner(std::move(Owner)), Size(Size),
|
||||
PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {}
|
||||
};
|
||||
ComputedPreamble ComputePreamble(CompilerInvocation &Invocation,
|
||||
unsigned MaxLines,
|
||||
IntrusiveRefCntPtr<vfs::FileSystem> VFS);
|
||||
|
||||
std::unique_ptr<llvm::MemoryBuffer> getMainBufferWithPrecompiledPreamble(
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
||||
const CompilerInvocation &PreambleInvocationIn,
|
||||
@ -607,12 +505,6 @@ class ASTUnit {
|
||||
void findFileRegionDecls(FileID File, unsigned Offset, unsigned Length,
|
||||
SmallVectorImpl<Decl *> &Decls);
|
||||
|
||||
/// \brief Add a new top-level declaration, identified by its ID in
|
||||
/// the precompiled preamble.
|
||||
void addTopLevelDeclFromPreamble(serialization::DeclID D) {
|
||||
TopLevelDeclsInPreamble.push_back(D);
|
||||
}
|
||||
|
||||
/// \brief Retrieve a reference to the current top-level name hash value.
|
||||
///
|
||||
/// Note: This is used internally by the top-level tracking action
|
||||
|
248
include/clang/Frontend/PrecompiledPreamble.h
Normal file
248
include/clang/Frontend/PrecompiledPreamble.h
Normal file
@ -0,0 +1,248 @@
|
||||
//===--- PrecompiledPreamble.h - Build precompiled preambles ----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Helper class to build precompiled preamble.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_FRONTEND_PRECOMPILED_PREAMBLE_H
|
||||
#define LLVM_CLANG_FRONTEND_PRECOMPILED_PREAMBLE_H
|
||||
|
||||
#include "clang/Lex/Lexer.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "llvm/ADT/IntrusiveRefCntPtr.h"
|
||||
#include "llvm/Support/MD5.h"
|
||||
#include <memory>
|
||||
#include <system_error>
|
||||
#include <type_traits>
|
||||
|
||||
namespace llvm {
|
||||
class MemoryBuffer;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
namespace vfs {
|
||||
class FileSystem;
|
||||
}
|
||||
|
||||
class CompilerInstance;
|
||||
class CompilerInvocation;
|
||||
class DeclGroupRef;
|
||||
class PCHContainerOperations;
|
||||
|
||||
/// A size of the preamble and a flag required by
|
||||
/// PreprocessorOptions::PrecompiledPreambleBytes.
|
||||
struct PreambleBounds {
|
||||
PreambleBounds(unsigned Size, bool PreambleEndsAtStartOfLine)
|
||||
: Size(Size), PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {}
|
||||
|
||||
/// \brief Size of the preamble in bytes.
|
||||
unsigned Size;
|
||||
/// \brief Whether the preamble ends at the start of a new line.
|
||||
///
|
||||
/// Used to inform the lexer as to whether it's starting at the beginning of
|
||||
/// a line after skipping the preamble.
|
||||
bool PreambleEndsAtStartOfLine;
|
||||
};
|
||||
|
||||
/// \brief Runs lexer to compute suggested preamble bounds.
|
||||
PreambleBounds ComputePreambleBounds(const LangOptions &LangOpts,
|
||||
llvm::MemoryBuffer *Buffer,
|
||||
unsigned MaxLines);
|
||||
|
||||
class PreambleCallbacks;
|
||||
|
||||
/// A class holding a PCH and all information to check whether it is valid to
|
||||
/// reuse the PCH for the subsequent runs. Use BuildPreamble to create PCH and
|
||||
/// CanReusePreamble + AddImplicitPreamble to make use of it.
|
||||
class PrecompiledPreamble {
|
||||
class TempPCHFile;
|
||||
struct PreambleFileHash;
|
||||
|
||||
public:
|
||||
/// \brief Try to build PrecompiledPreamble for \p Invocation. See
|
||||
/// BuildPreambleError for possible error codes.
|
||||
///
|
||||
/// \param Invocation Original CompilerInvocation with options to compile the
|
||||
/// file.
|
||||
///
|
||||
/// \param MainFileBuffer Buffer with the contents of the main file.
|
||||
///
|
||||
/// \param Bounds Bounds of the preamble, result of calling
|
||||
/// ComputePreambleBounds.
|
||||
///
|
||||
/// \param Diagnostics Diagnostics engine to be used while building the
|
||||
/// preamble.
|
||||
///
|
||||
/// \param VFS An instance of vfs::FileSystem to be used for file
|
||||
/// accesses.
|
||||
///
|
||||
/// \param PCHContainerOps An instance of PCHContainerOperations.
|
||||
///
|
||||
/// \param Callbacks A set of callbacks to be executed when building
|
||||
/// the preamble.
|
||||
static llvm::ErrorOr<PrecompiledPreamble>
|
||||
Build(const CompilerInvocation &Invocation,
|
||||
const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds,
|
||||
DiagnosticsEngine &Diagnostics, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
||||
PreambleCallbacks &Callbacks);
|
||||
|
||||
PrecompiledPreamble(PrecompiledPreamble &&) = default;
|
||||
PrecompiledPreamble &operator=(PrecompiledPreamble &&) = default;
|
||||
|
||||
/// PreambleBounds used to build the preamble
|
||||
PreambleBounds getBounds() const;
|
||||
|
||||
/// Check whether PrecompiledPreamble can be reused for the new contents(\p
|
||||
/// MainFileBuffer) of the main file.
|
||||
bool CanReuse(const CompilerInvocation &Invocation,
|
||||
const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds,
|
||||
vfs::FileSystem *VFS) const;
|
||||
|
||||
/// Changes options inside \p CI to use PCH from this preamble. Also remaps
|
||||
/// main file to \p MainFileBuffer.
|
||||
void AddImplicitPreamble(CompilerInvocation &CI,
|
||||
llvm::MemoryBuffer *MainFileBuffer) const;
|
||||
|
||||
private:
|
||||
PrecompiledPreamble(TempPCHFile PCHFile, std::vector<char> PreambleBytes,
|
||||
bool PreambleEndsAtStartOfLine,
|
||||
llvm::StringMap<PreambleFileHash> FilesInPreamble);
|
||||
|
||||
/// A temp file that would be deleted on destructor call. If destructor is not
|
||||
/// called for any reason, the file will be deleted at static objects'
|
||||
/// destruction.
|
||||
/// An assertion will fire if two TempPCHFiles are created with the same name,
|
||||
/// so it's not intended to be used outside preamble-handling.
|
||||
class TempPCHFile {
|
||||
public:
|
||||
// A main method used to construct TempPCHFile.
|
||||
static llvm::ErrorOr<TempPCHFile> CreateNewPreamblePCHFile();
|
||||
|
||||
/// Call llvm::sys::fs::createTemporaryFile to create a new temporary file.
|
||||
static llvm::ErrorOr<TempPCHFile> createInSystemTempDir(const Twine &Prefix,
|
||||
StringRef Suffix);
|
||||
/// Create a new instance of TemporaryFile for file at \p Path. Use with
|
||||
/// extreme caution, there's an assertion checking that there's only a
|
||||
/// single instance of TempPCHFile alive for each path.
|
||||
static llvm::ErrorOr<TempPCHFile> createFromCustomPath(const Twine &Path);
|
||||
|
||||
private:
|
||||
TempPCHFile(std::string FilePath);
|
||||
|
||||
public:
|
||||
TempPCHFile(TempPCHFile &&Other);
|
||||
TempPCHFile &operator=(TempPCHFile &&Other);
|
||||
|
||||
TempPCHFile(const TempPCHFile &) = delete;
|
||||
~TempPCHFile();
|
||||
|
||||
/// A path where temporary file is stored.
|
||||
llvm::StringRef getFilePath() const;
|
||||
|
||||
private:
|
||||
void RemoveFileIfPresent();
|
||||
|
||||
private:
|
||||
llvm::Optional<std::string> FilePath;
|
||||
};
|
||||
|
||||
/// Data used to determine if a file used in the preamble has been changed.
|
||||
struct PreambleFileHash {
|
||||
/// All files have size set.
|
||||
off_t Size = 0;
|
||||
|
||||
/// Modification time is set for files that are on disk. For memory
|
||||
/// buffers it is zero.
|
||||
time_t ModTime = 0;
|
||||
|
||||
/// Memory buffers have MD5 instead of modification time. We don't
|
||||
/// compute MD5 for on-disk files because we hope that modification time is
|
||||
/// enough to tell if the file was changed.
|
||||
llvm::MD5::MD5Result MD5 = {};
|
||||
|
||||
static PreambleFileHash createForFile(off_t Size, time_t ModTime);
|
||||
static PreambleFileHash
|
||||
createForMemoryBuffer(const llvm::MemoryBuffer *Buffer);
|
||||
|
||||
friend bool operator==(const PreambleFileHash &LHS,
|
||||
const PreambleFileHash &RHS) {
|
||||
return LHS.Size == RHS.Size && LHS.ModTime == RHS.ModTime &&
|
||||
LHS.MD5 == RHS.MD5;
|
||||
}
|
||||
friend bool operator!=(const PreambleFileHash &LHS,
|
||||
const PreambleFileHash &RHS) {
|
||||
return !(LHS == RHS);
|
||||
}
|
||||
};
|
||||
|
||||
/// Manages the lifetime of temporary file that stores a PCH.
|
||||
TempPCHFile PCHFile;
|
||||
/// Keeps track of the files that were used when computing the
|
||||
/// preamble, with both their buffer size and their modification time.
|
||||
///
|
||||
/// If any of the files have changed from one compile to the next,
|
||||
/// the preamble must be thrown away.
|
||||
llvm::StringMap<PreambleFileHash> FilesInPreamble;
|
||||
/// The contents of the file that was used to precompile the preamble. Only
|
||||
/// contains first PreambleBounds::Size bytes. Used to compare if the relevant
|
||||
/// part of the file has not changed, so that preamble can be reused.
|
||||
std::vector<char> PreambleBytes;
|
||||
/// See PreambleBounds::PreambleEndsAtStartOfLine
|
||||
bool PreambleEndsAtStartOfLine;
|
||||
};
|
||||
|
||||
/// A set of callbacks to gather useful information while building a preamble.
|
||||
class PreambleCallbacks {
|
||||
public:
|
||||
virtual ~PreambleCallbacks() = default;
|
||||
|
||||
/// Called after FrontendAction::Execute(), but before
|
||||
/// FrontendAction::EndSourceFile(). Can be used to transfer ownership of
|
||||
/// various CompilerInstance fields before they are destroyed.
|
||||
virtual void AfterExecute(CompilerInstance &CI);
|
||||
/// Called after PCH has been emitted. \p Writer may be used to retrieve
|
||||
/// information about AST, serialized in PCH.
|
||||
virtual void AfterPCHEmitted(ASTWriter &Writer);
|
||||
/// Called for each TopLevelDecl.
|
||||
/// NOTE: To allow more flexibility a custom ASTConsumer could probably be
|
||||
/// used instead, but having only this method allows a simpler API.
|
||||
virtual void HandleTopLevelDecl(DeclGroupRef DG);
|
||||
/// Called for each macro defined in the Preamble.
|
||||
/// NOTE: To allow more flexibility a custom PPCallbacks could probably be
|
||||
/// used instead, but having only this method allows a simpler API.
|
||||
virtual void HandleMacroDefined(const Token &MacroNameTok,
|
||||
const MacroDirective *MD);
|
||||
};
|
||||
|
||||
enum class BuildPreambleError {
|
||||
PreambleIsEmpty = 1,
|
||||
CouldntCreateTempFile,
|
||||
CouldntCreateTargetInfo,
|
||||
CouldntCreateVFSOverlay,
|
||||
BeginSourceFileFailed,
|
||||
CouldntEmitPCH
|
||||
};
|
||||
|
||||
class BuildPreambleErrorCategory final : public std::error_category {
|
||||
public:
|
||||
const char *name() const noexcept override;
|
||||
std::string message(int condition) const override;
|
||||
};
|
||||
|
||||
std::error_code make_error_code(BuildPreambleError Error);
|
||||
} // namespace clang
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct is_error_code_enum<clang::BuildPreambleError> : std::true_type {};
|
||||
} // namespace std
|
||||
|
||||
#endif
|
@ -1835,11 +1835,20 @@ class Preprocessor {
|
||||
/// \brief A fast PTH version of SkipExcludedConditionalBlock.
|
||||
void PTHSkipExcludedConditionalBlock();
|
||||
|
||||
/// Information about the result for evaluating an expression for a
|
||||
/// preprocessor directive.
|
||||
struct DirectiveEvalResult {
|
||||
/// Whether the expression was evaluated as true or not.
|
||||
bool Conditional;
|
||||
/// True if the expression contained identifiers that were undefined.
|
||||
bool IncludedUndefinedIds;
|
||||
};
|
||||
|
||||
/// \brief Evaluate an integer constant expression that may occur after a
|
||||
/// \#if or \#elif directive and return it as a bool.
|
||||
/// \#if or \#elif directive and return a \p DirectiveEvalResult object.
|
||||
///
|
||||
/// If the expression is equivalent to "!defined(X)" return X in IfNDefMacro.
|
||||
bool EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro);
|
||||
DirectiveEvalResult EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro);
|
||||
|
||||
/// \brief Install the standard preprocessor pragmas:
|
||||
/// \#pragma GCC poison/system_header/dependency and \#pragma once.
|
||||
|
@ -96,8 +96,15 @@ class PreprocessorOptions {
|
||||
std::string TokenCache;
|
||||
|
||||
/// When enabled, preprocessor is in a mode for parsing a single file only.
|
||||
///
|
||||
/// Disables #includes of other files and if there are unresolved identifiers
|
||||
/// in preprocessor directive conditions it causes all blocks to be parsed so
|
||||
/// that the client can get the maximum amount of information from the parser.
|
||||
bool SingleFileParseMode = false;
|
||||
|
||||
/// When enabled, the preprocessor will construct editor placeholder tokens.
|
||||
bool LexEditorPlaceholders = true;
|
||||
|
||||
/// \brief True if the SourceManager should report the original file name for
|
||||
/// contents of files that were remapped to other files. Defaults to true.
|
||||
bool RemappedFilesKeepOriginalName;
|
||||
@ -185,6 +192,7 @@ class PreprocessorOptions {
|
||||
ImplicitPTHInclude.clear();
|
||||
TokenCache.clear();
|
||||
SingleFileParseMode = false;
|
||||
LexEditorPlaceholders = true;
|
||||
RetainRemappedFileBuffers = true;
|
||||
PrecompiledPreambleBytes.first = 0;
|
||||
PrecompiledPreambleBytes.second = 0;
|
||||
|
@ -604,7 +604,7 @@ class Parser : public CodeCompletionHandler {
|
||||
}
|
||||
|
||||
/// getTypeAnnotation - Read a parsed type out of an annotation token.
|
||||
static ParsedType getTypeAnnotation(Token &Tok) {
|
||||
static ParsedType getTypeAnnotation(const Token &Tok) {
|
||||
return ParsedType::getFromOpaquePtr(Tok.getAnnotationValue());
|
||||
}
|
||||
|
||||
@ -615,7 +615,7 @@ class Parser : public CodeCompletionHandler {
|
||||
|
||||
/// \brief Read an already-translated primary expression out of an annotation
|
||||
/// token.
|
||||
static ExprResult getExprAnnotation(Token &Tok) {
|
||||
static ExprResult getExprAnnotation(const Token &Tok) {
|
||||
return ExprResult::getFromOpaquePointer(Tok.getAnnotationValue());
|
||||
}
|
||||
|
||||
@ -1852,6 +1852,7 @@ class Parser : public CodeCompletionHandler {
|
||||
DSC_trailing, // C++11 trailing-type-specifier in a trailing return type
|
||||
DSC_alias_declaration, // C++11 type-specifier-seq in an alias-declaration
|
||||
DSC_top_level, // top-level/namespace declaration context
|
||||
DSC_template_param, // template parameter context
|
||||
DSC_template_type_arg, // template type argument context
|
||||
DSC_objc_method_result, // ObjC method result context, enables 'instancetype'
|
||||
DSC_condition // condition declaration context
|
||||
@ -1862,6 +1863,7 @@ class Parser : public CodeCompletionHandler {
|
||||
static bool isTypeSpecifier(DeclSpecContext DSC) {
|
||||
switch (DSC) {
|
||||
case DSC_normal:
|
||||
case DSC_template_param:
|
||||
case DSC_class:
|
||||
case DSC_top_level:
|
||||
case DSC_objc_method_result:
|
||||
@ -1882,6 +1884,7 @@ class Parser : public CodeCompletionHandler {
|
||||
static bool isClassTemplateDeductionContext(DeclSpecContext DSC) {
|
||||
switch (DSC) {
|
||||
case DSC_normal:
|
||||
case DSC_template_param:
|
||||
case DSC_class:
|
||||
case DSC_top_level:
|
||||
case DSC_condition:
|
||||
|
@ -2153,7 +2153,8 @@ class Sema {
|
||||
bool &OwnedDecl, bool &IsDependent,
|
||||
SourceLocation ScopedEnumKWLoc,
|
||||
bool ScopedEnumUsesClassTag, TypeResult UnderlyingType,
|
||||
bool IsTypeSpecifier, SkipBodyInfo *SkipBody = nullptr);
|
||||
bool IsTypeSpecifier, bool IsTemplateParamOrArg,
|
||||
SkipBodyInfo *SkipBody = nullptr);
|
||||
|
||||
Decl *ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
|
||||
unsigned TagSpec, SourceLocation TagLoc,
|
||||
|
@ -180,6 +180,11 @@ class BasicValueFactory {
|
||||
return getValue(X);
|
||||
}
|
||||
|
||||
inline const llvm::APSInt& getZeroWithTypeSize(QualType T) {
|
||||
assert(T->isScalarType());
|
||||
return getValue(0, Ctx.getTypeSize(T), true);
|
||||
}
|
||||
|
||||
inline const llvm::APSInt& getZeroWithPtrWidth(bool isUnsigned = true) {
|
||||
return getValue(0, Ctx.getTypeSize(Ctx.VoidPtrTy), isUnsigned);
|
||||
}
|
||||
|
@ -315,6 +315,13 @@ class SValBuilder {
|
||||
return nonloc::ConcreteInt(BasicVals.getTruthValue(b));
|
||||
}
|
||||
|
||||
/// Create NULL pointer, with proper pointer bit-width for given address
|
||||
/// space.
|
||||
/// \param type pointer type.
|
||||
Loc makeNullWithType(QualType type) {
|
||||
return loc::ConcreteInt(BasicVals.getZeroWithTypeSize(type));
|
||||
}
|
||||
|
||||
Loc makeNull() {
|
||||
return loc::ConcreteInt(BasicVals.getZeroWithPtrWidth());
|
||||
}
|
||||
|
@ -894,7 +894,7 @@ void ASTContext::mergeDefinitionIntoModule(NamedDecl *ND, Module *M,
|
||||
if (getLangOpts().ModulesLocalVisibility)
|
||||
MergedDefModules[ND].push_back(M);
|
||||
else
|
||||
ND->setHidden(false);
|
||||
ND->setVisibleDespiteOwningModule();
|
||||
}
|
||||
|
||||
void ASTContext::deduplicateMergedDefinitonsFor(NamedDecl *ND) {
|
||||
@ -8513,7 +8513,7 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
|
||||
RequiresICE = false;
|
||||
|
||||
// Read the prefixed modifiers first.
|
||||
bool Done = false;
|
||||
bool Done = false, IsSpecialLong = false;
|
||||
while (!Done) {
|
||||
switch (*Str++) {
|
||||
default: Done = true; --Str; break;
|
||||
@ -8531,12 +8531,24 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
|
||||
Unsigned = true;
|
||||
break;
|
||||
case 'L':
|
||||
assert(!IsSpecialLong && "Can't use 'L' with 'W' or 'N' modifiers");
|
||||
assert(HowLong <= 2 && "Can't have LLLL modifier");
|
||||
++HowLong;
|
||||
break;
|
||||
case 'N': {
|
||||
// 'N' behaves like 'L' for all non LP64 targets and 'int' otherwise.
|
||||
assert(!IsSpecialLong && "Can't use two 'N' or 'W' modifiers!");
|
||||
assert(HowLong == 0 && "Can't use both 'L' and 'N' modifiers!");
|
||||
IsSpecialLong = true;
|
||||
if (Context.getTargetInfo().getLongWidth() == 32)
|
||||
++HowLong;
|
||||
break;
|
||||
}
|
||||
case 'W':
|
||||
// This modifier represents int64 type.
|
||||
assert(!IsSpecialLong && "Can't use two 'N' or 'W' modifiers!");
|
||||
assert(HowLong == 0 && "Can't use both 'L' and 'W' modifiers!");
|
||||
IsSpecialLong = true;
|
||||
switch (Context.getTargetInfo().getInt64Type()) {
|
||||
default:
|
||||
llvm_unreachable("Unexpected integer type");
|
||||
|
@ -1184,6 +1184,31 @@ void ASTDumper::VisitFunctionDecl(const FunctionDecl *D) {
|
||||
I != E; ++I)
|
||||
dumpCXXCtorInitializer(*I);
|
||||
|
||||
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D))
|
||||
if (MD->size_overridden_methods() != 0) {
|
||||
auto dumpOverride =
|
||||
[=](const CXXMethodDecl *D) {
|
||||
SplitQualType T_split = D->getType().split();
|
||||
OS << D << " " << D->getParent()->getName() << "::";
|
||||
if (isa<CXXDestructorDecl>(D))
|
||||
OS << "~" << D->getParent()->getName();
|
||||
else
|
||||
OS << D->getName();
|
||||
OS << " '" << QualType::getAsString(T_split) << "'";
|
||||
};
|
||||
|
||||
dumpChild([=] {
|
||||
auto FirstOverrideItr = MD->begin_overridden_methods();
|
||||
OS << "Overrides: [ ";
|
||||
dumpOverride(*FirstOverrideItr);
|
||||
for (const auto *Override :
|
||||
llvm::make_range(FirstOverrideItr + 1,
|
||||
MD->end_overridden_methods()))
|
||||
dumpOverride(Override);
|
||||
OS << " ]";
|
||||
});
|
||||
}
|
||||
|
||||
if (D->doesThisDeclarationHaveABody())
|
||||
dumpStmt(D->getBody());
|
||||
}
|
||||
|
@ -319,6 +319,9 @@ namespace clang {
|
||||
bool ImportArrayChecked(const InContainerTy &InContainer, OIter Obegin) {
|
||||
return ImportArrayChecked(InContainer.begin(), InContainer.end(), Obegin);
|
||||
}
|
||||
|
||||
// Importing overrides.
|
||||
void ImportOverrides(CXXMethodDecl *ToMethod, CXXMethodDecl *FromMethod);
|
||||
};
|
||||
}
|
||||
|
||||
@ -2025,6 +2028,9 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
|
||||
// Add this function to the lexical context.
|
||||
LexicalDC->addDeclInternal(ToFunction);
|
||||
|
||||
if (auto *FromCXXMethod = dyn_cast<CXXMethodDecl>(D))
|
||||
ImportOverrides(cast<CXXMethodDecl>(ToFunction), FromCXXMethod);
|
||||
|
||||
return ToFunction;
|
||||
}
|
||||
|
||||
@ -5499,6 +5505,14 @@ Expr *ASTNodeImporter::VisitSubstNonTypeTemplateParmExpr(
|
||||
Replacement);
|
||||
}
|
||||
|
||||
void ASTNodeImporter::ImportOverrides(CXXMethodDecl *ToMethod,
|
||||
CXXMethodDecl *FromMethod) {
|
||||
for (auto *FromOverriddenMethod : FromMethod->overridden_methods())
|
||||
ToMethod->addOverriddenMethod(
|
||||
cast<CXXMethodDecl>(Importer.Import(const_cast<CXXMethodDecl*>(
|
||||
FromOverriddenMethod))));
|
||||
}
|
||||
|
||||
ASTImporter::ASTImporter(ASTContext &ToContext, FileManager &ToFileManager,
|
||||
ASTContext &FromContext, FileManager &FromFileManager,
|
||||
bool MinimalImport)
|
||||
|
@ -278,12 +278,12 @@ void Decl::setLexicalDeclContext(DeclContext *DC) {
|
||||
// FIXME: We shouldn't be changing the lexical context of declarations
|
||||
// imported from AST files.
|
||||
if (!isFromASTFile()) {
|
||||
Hidden = cast<Decl>(DC)->Hidden && hasLocalOwningModuleStorage();
|
||||
if (Hidden)
|
||||
setModuleOwnershipKind(getModuleOwnershipKindForChildOf(DC));
|
||||
if (hasOwningModule())
|
||||
setLocalOwningModule(cast<Decl>(DC)->getOwningModule());
|
||||
}
|
||||
|
||||
assert((!Hidden || getOwningModule()) &&
|
||||
assert((!hasOwningModule() || getOwningModule()) &&
|
||||
"hidden declaration has no owning module");
|
||||
}
|
||||
|
||||
@ -1352,7 +1352,7 @@ void DeclContext::removeDecl(Decl *D) {
|
||||
// Remove only decls that have a name
|
||||
if (!ND->getDeclName()) return;
|
||||
|
||||
auto *DC = this;
|
||||
auto *DC = D->getDeclContext();
|
||||
do {
|
||||
StoredDeclsMap *Map = DC->getPrimaryContext()->LookupPtr;
|
||||
if (Map) {
|
||||
|
@ -41,6 +41,7 @@ class LazyASTImporter : public ASTImporter {
|
||||
Decl *Imported(Decl *From, Decl *To) override {
|
||||
if (auto ToTag = dyn_cast<TagDecl>(To)) {
|
||||
ToTag->setHasExternalLexicalStorage();
|
||||
ToTag->setMustBuildLookupTable();
|
||||
} else if (auto ToNamespace = dyn_cast<NamespaceDecl>(To)) {
|
||||
ToNamespace->setHasExternalVisibleStorage();
|
||||
}
|
||||
|
@ -18,9 +18,9 @@
|
||||
#include "clang/AST/Stmt.h"
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
#include "clang/Lex/Lexer.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/MD5.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
@ -366,6 +366,23 @@ void OnlyLargestCloneConstraint::constrain(
|
||||
}
|
||||
}
|
||||
|
||||
bool FilenamePatternConstraint::isAutoGenerated(const CloneDetector::CloneGroup &Group) {
|
||||
std::string Error;
|
||||
if (IgnoredFilesPattern.empty() || Group.empty() ||
|
||||
!IgnoredFilesRegex->isValid(Error))
|
||||
return false;
|
||||
|
||||
for (const StmtSequence &S : Group) {
|
||||
const SourceManager &SM = S.getASTContext().getSourceManager();
|
||||
StringRef Filename = llvm::sys::path::filename(SM.getFilename(
|
||||
S.getContainingDecl()->getLocation()));
|
||||
if (IgnoredFilesRegex->match(Filename))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static size_t createHash(llvm::MD5 &Hash) {
|
||||
size_t HashCode;
|
||||
|
||||
@ -618,8 +635,7 @@ void CloneConstraint::splitCloneGroups(
|
||||
if (Indexes[j])
|
||||
continue;
|
||||
|
||||
// If a following StmtSequence belongs to our CloneGroup, we add it to
|
||||
// it.
|
||||
// If a following StmtSequence belongs to our CloneGroup, we add it.
|
||||
const StmtSequence &Candidate = HashGroup[j];
|
||||
|
||||
if (!Compare(Prototype, Candidate))
|
||||
|
@ -13,6 +13,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Basic/Module.h"
|
||||
#include "clang/Basic/CharInfo.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
@ -125,7 +126,36 @@ const Module *Module::getTopLevelModule() const {
|
||||
return Result;
|
||||
}
|
||||
|
||||
std::string Module::getFullModuleName() const {
|
||||
static StringRef getModuleNameFromComponent(
|
||||
const std::pair<std::string, SourceLocation> &IdComponent) {
|
||||
return IdComponent.first;
|
||||
}
|
||||
static StringRef getModuleNameFromComponent(StringRef R) { return R; }
|
||||
|
||||
template<typename InputIter>
|
||||
static void printModuleId(raw_ostream &OS, InputIter Begin, InputIter End,
|
||||
bool AllowStringLiterals = true) {
|
||||
for (InputIter It = Begin; It != End; ++It) {
|
||||
if (It != Begin)
|
||||
OS << ".";
|
||||
|
||||
StringRef Name = getModuleNameFromComponent(*It);
|
||||
if (!AllowStringLiterals || isValidIdentifier(Name))
|
||||
OS << Name;
|
||||
else {
|
||||
OS << '"';
|
||||
OS.write_escaped(Name);
|
||||
OS << '"';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
static void printModuleId(raw_ostream &OS, const Container &C) {
|
||||
return printModuleId(OS, C.begin(), C.end());
|
||||
}
|
||||
|
||||
std::string Module::getFullModuleName(bool AllowStringLiterals) const {
|
||||
SmallVector<StringRef, 2> Names;
|
||||
|
||||
// Build up the set of module names (from innermost to outermost).
|
||||
@ -133,15 +163,11 @@ std::string Module::getFullModuleName() const {
|
||||
Names.push_back(M->Name);
|
||||
|
||||
std::string Result;
|
||||
for (SmallVectorImpl<StringRef>::reverse_iterator I = Names.rbegin(),
|
||||
IEnd = Names.rend();
|
||||
I != IEnd; ++I) {
|
||||
if (!Result.empty())
|
||||
Result += '.';
|
||||
|
||||
Result += *I;
|
||||
}
|
||||
|
||||
|
||||
llvm::raw_string_ostream Out(Result);
|
||||
printModuleId(Out, Names.rbegin(), Names.rend(), AllowStringLiterals);
|
||||
Out.flush();
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
@ -240,14 +266,6 @@ Module *Module::findSubmodule(StringRef Name) const {
|
||||
return SubModules[Pos->getValue()];
|
||||
}
|
||||
|
||||
static void printModuleId(raw_ostream &OS, const ModuleId &Id) {
|
||||
for (unsigned I = 0, N = Id.size(); I != N; ++I) {
|
||||
if (I)
|
||||
OS << ".";
|
||||
OS << Id[I].first;
|
||||
}
|
||||
}
|
||||
|
||||
void Module::getExportedModules(SmallVectorImpl<Module *> &Exported) const {
|
||||
// All non-explicit submodules are exported.
|
||||
for (std::vector<Module *>::const_iterator I = SubModules.begin(),
|
||||
@ -334,7 +352,8 @@ void Module::print(raw_ostream &OS, unsigned Indent) const {
|
||||
OS << "framework ";
|
||||
if (IsExplicit)
|
||||
OS << "explicit ";
|
||||
OS << "module " << Name;
|
||||
OS << "module ";
|
||||
printModuleId(OS, &Name, &Name + 1);
|
||||
|
||||
if (IsSystem || IsExternC) {
|
||||
OS.indent(Indent + 2);
|
||||
@ -434,7 +453,7 @@ void Module::print(raw_ostream &OS, unsigned Indent) const {
|
||||
OS.indent(Indent + 2);
|
||||
OS << "export ";
|
||||
if (Module *Restriction = Exports[I].getPointer()) {
|
||||
OS << Restriction->getFullModuleName();
|
||||
OS << Restriction->getFullModuleName(true);
|
||||
if (Exports[I].getInt())
|
||||
OS << ".*";
|
||||
} else {
|
||||
@ -455,7 +474,7 @@ void Module::print(raw_ostream &OS, unsigned Indent) const {
|
||||
for (unsigned I = 0, N = DirectUses.size(); I != N; ++I) {
|
||||
OS.indent(Indent + 2);
|
||||
OS << "use ";
|
||||
OS << DirectUses[I]->getFullModuleName();
|
||||
OS << DirectUses[I]->getFullModuleName(true);
|
||||
OS << "\n";
|
||||
}
|
||||
|
||||
@ -488,7 +507,7 @@ void Module::print(raw_ostream &OS, unsigned Indent) const {
|
||||
for (unsigned I = 0, N = Conflicts.size(); I != N; ++I) {
|
||||
OS.indent(Indent + 2);
|
||||
OS << "conflict ";
|
||||
OS << Conflicts[I].Other->getFullModuleName();
|
||||
OS << Conflicts[I].Other->getFullModuleName(true);
|
||||
OS << ", \"";
|
||||
OS.write_escaped(Conflicts[I].Message);
|
||||
OS << "\"\n";
|
||||
|
@ -359,15 +359,6 @@ void SourceManager::initializeForReplay(const SourceManager &Old) {
|
||||
return Clone;
|
||||
};
|
||||
|
||||
// Set up our main file ID as a copy of the old source manager's main file.
|
||||
const SLocEntry &OldMainFile = Old.getSLocEntry(Old.getMainFileID());
|
||||
assert(OldMainFile.isFile() && "main file is macro expansion?");
|
||||
auto *MainCC = CloneContentCache(OldMainFile.getFile().getContentCache());
|
||||
MemBufferInfos.push_back(MainCC);
|
||||
setMainFileID(createFileID(MainCC, SourceLocation(),
|
||||
OldMainFile.getFile().getFileCharacteristic(),
|
||||
0, 0));
|
||||
|
||||
// Ensure all SLocEntries are loaded from the external source.
|
||||
for (unsigned I = 0, N = Old.LoadedSLocEntryTable.size(); I != N; ++I)
|
||||
if (!Old.SLocEntryLoaded[I])
|
||||
|
@ -507,6 +507,11 @@ bool TargetInfo::validateOutputConstraint(ConstraintInfo &Info) const {
|
||||
case '?': // Disparage slightly code.
|
||||
case '!': // Disparage severely.
|
||||
case '*': // Ignore for choosing register preferences.
|
||||
case 'i': // Ignore i,n,E,F as output constraints (match from the other
|
||||
// chars)
|
||||
case 'n':
|
||||
case 'E':
|
||||
case 'F':
|
||||
break; // Pass them.
|
||||
}
|
||||
|
||||
|
@ -111,6 +111,21 @@ class CloudABITargetInfo : public OSTargetInfo<Target> {
|
||||
: OSTargetInfo<Target>(Triple, Opts) {}
|
||||
};
|
||||
|
||||
// Ananas target
|
||||
template<typename Target>
|
||||
class AnanasTargetInfo : public OSTargetInfo<Target> {
|
||||
protected:
|
||||
void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
|
||||
MacroBuilder &Builder) const override {
|
||||
// Ananas defines
|
||||
Builder.defineMacro("__Ananas__");
|
||||
Builder.defineMacro("__ELF__");
|
||||
}
|
||||
public:
|
||||
AnanasTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
|
||||
: OSTargetInfo<Target>(Triple, Opts) {}
|
||||
};
|
||||
|
||||
static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts,
|
||||
const llvm::Triple &Triple,
|
||||
StringRef &PlatformName,
|
||||
@ -6172,6 +6187,8 @@ class AArch64TargetInfo : public TargetInfo {
|
||||
unsigned Crypto;
|
||||
unsigned Unaligned;
|
||||
unsigned V8_1A;
|
||||
unsigned V8_2A;
|
||||
unsigned HasFullFP16;
|
||||
|
||||
static const Builtin::Info BuiltinInfo[];
|
||||
|
||||
@ -6303,6 +6320,8 @@ class AArch64TargetInfo : public TargetInfo {
|
||||
|
||||
if (V8_1A)
|
||||
Builder.defineMacro("__ARM_FEATURE_QRDMX", "1");
|
||||
if (V8_2A && FPU == NeonMode && HasFullFP16)
|
||||
Builder.defineMacro("__ARM_FEATURE_FP16_VECTOR_ARITHMETIC", "1");
|
||||
|
||||
// All of the __sync_(bool|val)_compare_and_swap_(1|2|4|8) builtins work.
|
||||
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
|
||||
@ -6330,6 +6349,8 @@ class AArch64TargetInfo : public TargetInfo {
|
||||
Crypto = 0;
|
||||
Unaligned = 1;
|
||||
V8_1A = 0;
|
||||
V8_2A = 0;
|
||||
HasFullFP16 = 0;
|
||||
|
||||
for (const auto &Feature : Features) {
|
||||
if (Feature == "+neon")
|
||||
@ -6342,6 +6363,10 @@ class AArch64TargetInfo : public TargetInfo {
|
||||
Unaligned = 0;
|
||||
if (Feature == "+v8.1a")
|
||||
V8_1A = 1;
|
||||
if (Feature == "+v8.2a")
|
||||
V8_2A = 1;
|
||||
if (Feature == "+fullfp16")
|
||||
HasFullFP16 = 1;
|
||||
}
|
||||
|
||||
setDataLayout();
|
||||
@ -7493,7 +7518,7 @@ class MSP430TargetInfo : public TargetInfo {
|
||||
IntPtrType = SignedInt;
|
||||
PtrDiffType = SignedInt;
|
||||
SigAtomicType = SignedLong;
|
||||
resetDataLayout("e-m:e-p:16:16-i32:16:32-a:16-n8:16");
|
||||
resetDataLayout("e-m:e-p:16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S16");
|
||||
}
|
||||
void getTargetDefines(const LangOptions &Opts,
|
||||
MacroBuilder &Builder) const override {
|
||||
@ -9520,6 +9545,8 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple,
|
||||
return new DarwinI386TargetInfo(Triple, Opts);
|
||||
|
||||
switch (os) {
|
||||
case llvm::Triple::Ananas:
|
||||
return new AnanasTargetInfo<X86_32TargetInfo>(Triple, Opts);
|
||||
case llvm::Triple::CloudABI:
|
||||
return new CloudABITargetInfo<X86_32TargetInfo>(Triple, Opts);
|
||||
case llvm::Triple::Linux: {
|
||||
@ -9575,6 +9602,8 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple,
|
||||
return new DarwinX86_64TargetInfo(Triple, Opts);
|
||||
|
||||
switch (os) {
|
||||
case llvm::Triple::Ananas:
|
||||
return new AnanasTargetInfo<X86_64TargetInfo>(Triple, Opts);
|
||||
case llvm::Triple::CloudABI:
|
||||
return new CloudABITargetInfo<X86_64TargetInfo>(Triple, Opts);
|
||||
case llvm::Triple::Linux: {
|
||||
|
@ -2956,8 +2956,9 @@ static llvm::VectorType *GetNeonType(CodeGenFunction *CGF,
|
||||
return llvm::VectorType::get(CGF->Int8Ty, V1Ty ? 1 : (8 << IsQuad));
|
||||
case NeonTypeFlags::Int16:
|
||||
case NeonTypeFlags::Poly16:
|
||||
case NeonTypeFlags::Float16:
|
||||
return llvm::VectorType::get(CGF->Int16Ty, V1Ty ? 1 : (4 << IsQuad));
|
||||
case NeonTypeFlags::Float16:
|
||||
return llvm::VectorType::get(CGF->HalfTy, V1Ty ? 1 : (4 << IsQuad));
|
||||
case NeonTypeFlags::Int32:
|
||||
return llvm::VectorType::get(CGF->Int32Ty, V1Ty ? 1 : (2 << IsQuad));
|
||||
case NeonTypeFlags::Int64:
|
||||
@ -2980,6 +2981,8 @@ static llvm::VectorType *GetFloatNeonType(CodeGenFunction *CGF,
|
||||
NeonTypeFlags IntTypeFlags) {
|
||||
int IsQuad = IntTypeFlags.isQuad();
|
||||
switch (IntTypeFlags.getEltType()) {
|
||||
case NeonTypeFlags::Int16:
|
||||
return llvm::VectorType::get(CGF->HalfTy, (4 << IsQuad));
|
||||
case NeonTypeFlags::Int32:
|
||||
return llvm::VectorType::get(CGF->FloatTy, (2 << IsQuad));
|
||||
case NeonTypeFlags::Int64:
|
||||
@ -3127,55 +3130,80 @@ static const NeonIntrinsicInfo ARMSIMDIntrinsicMap [] = {
|
||||
NEONMAP1(vcvt_f16_f32, arm_neon_vcvtfp2hf, 0),
|
||||
NEONMAP1(vcvt_f32_f16, arm_neon_vcvthf2fp, 0),
|
||||
NEONMAP0(vcvt_f32_v),
|
||||
NEONMAP2(vcvt_n_f16_v, arm_neon_vcvtfxu2fp, arm_neon_vcvtfxs2fp, 0),
|
||||
NEONMAP2(vcvt_n_f32_v, arm_neon_vcvtfxu2fp, arm_neon_vcvtfxs2fp, 0),
|
||||
NEONMAP1(vcvt_n_s16_v, arm_neon_vcvtfp2fxs, 0),
|
||||
NEONMAP1(vcvt_n_s32_v, arm_neon_vcvtfp2fxs, 0),
|
||||
NEONMAP1(vcvt_n_s64_v, arm_neon_vcvtfp2fxs, 0),
|
||||
NEONMAP1(vcvt_n_u16_v, arm_neon_vcvtfp2fxu, 0),
|
||||
NEONMAP1(vcvt_n_u32_v, arm_neon_vcvtfp2fxu, 0),
|
||||
NEONMAP1(vcvt_n_u64_v, arm_neon_vcvtfp2fxu, 0),
|
||||
NEONMAP0(vcvt_s16_v),
|
||||
NEONMAP0(vcvt_s32_v),
|
||||
NEONMAP0(vcvt_s64_v),
|
||||
NEONMAP0(vcvt_u16_v),
|
||||
NEONMAP0(vcvt_u32_v),
|
||||
NEONMAP0(vcvt_u64_v),
|
||||
NEONMAP1(vcvta_s16_v, arm_neon_vcvtas, 0),
|
||||
NEONMAP1(vcvta_s32_v, arm_neon_vcvtas, 0),
|
||||
NEONMAP1(vcvta_s64_v, arm_neon_vcvtas, 0),
|
||||
NEONMAP1(vcvta_u32_v, arm_neon_vcvtau, 0),
|
||||
NEONMAP1(vcvta_u64_v, arm_neon_vcvtau, 0),
|
||||
NEONMAP1(vcvtaq_s16_v, arm_neon_vcvtas, 0),
|
||||
NEONMAP1(vcvtaq_s32_v, arm_neon_vcvtas, 0),
|
||||
NEONMAP1(vcvtaq_s64_v, arm_neon_vcvtas, 0),
|
||||
NEONMAP1(vcvtaq_u16_v, arm_neon_vcvtau, 0),
|
||||
NEONMAP1(vcvtaq_u32_v, arm_neon_vcvtau, 0),
|
||||
NEONMAP1(vcvtaq_u64_v, arm_neon_vcvtau, 0),
|
||||
NEONMAP1(vcvtm_s16_v, arm_neon_vcvtms, 0),
|
||||
NEONMAP1(vcvtm_s32_v, arm_neon_vcvtms, 0),
|
||||
NEONMAP1(vcvtm_s64_v, arm_neon_vcvtms, 0),
|
||||
NEONMAP1(vcvtm_u16_v, arm_neon_vcvtmu, 0),
|
||||
NEONMAP1(vcvtm_u32_v, arm_neon_vcvtmu, 0),
|
||||
NEONMAP1(vcvtm_u64_v, arm_neon_vcvtmu, 0),
|
||||
NEONMAP1(vcvtmq_s16_v, arm_neon_vcvtms, 0),
|
||||
NEONMAP1(vcvtmq_s32_v, arm_neon_vcvtms, 0),
|
||||
NEONMAP1(vcvtmq_s64_v, arm_neon_vcvtms, 0),
|
||||
NEONMAP1(vcvtmq_u16_v, arm_neon_vcvtmu, 0),
|
||||
NEONMAP1(vcvtmq_u32_v, arm_neon_vcvtmu, 0),
|
||||
NEONMAP1(vcvtmq_u64_v, arm_neon_vcvtmu, 0),
|
||||
NEONMAP1(vcvtn_s16_v, arm_neon_vcvtns, 0),
|
||||
NEONMAP1(vcvtn_s32_v, arm_neon_vcvtns, 0),
|
||||
NEONMAP1(vcvtn_s64_v, arm_neon_vcvtns, 0),
|
||||
NEONMAP1(vcvtn_u16_v, arm_neon_vcvtnu, 0),
|
||||
NEONMAP1(vcvtn_u32_v, arm_neon_vcvtnu, 0),
|
||||
NEONMAP1(vcvtn_u64_v, arm_neon_vcvtnu, 0),
|
||||
NEONMAP1(vcvtnq_s16_v, arm_neon_vcvtns, 0),
|
||||
NEONMAP1(vcvtnq_s32_v, arm_neon_vcvtns, 0),
|
||||
NEONMAP1(vcvtnq_s64_v, arm_neon_vcvtns, 0),
|
||||
NEONMAP1(vcvtnq_u16_v, arm_neon_vcvtnu, 0),
|
||||
NEONMAP1(vcvtnq_u32_v, arm_neon_vcvtnu, 0),
|
||||
NEONMAP1(vcvtnq_u64_v, arm_neon_vcvtnu, 0),
|
||||
NEONMAP1(vcvtp_s16_v, arm_neon_vcvtps, 0),
|
||||
NEONMAP1(vcvtp_s32_v, arm_neon_vcvtps, 0),
|
||||
NEONMAP1(vcvtp_s64_v, arm_neon_vcvtps, 0),
|
||||
NEONMAP1(vcvtp_u16_v, arm_neon_vcvtpu, 0),
|
||||
NEONMAP1(vcvtp_u32_v, arm_neon_vcvtpu, 0),
|
||||
NEONMAP1(vcvtp_u64_v, arm_neon_vcvtpu, 0),
|
||||
NEONMAP1(vcvtpq_s16_v, arm_neon_vcvtps, 0),
|
||||
NEONMAP1(vcvtpq_s32_v, arm_neon_vcvtps, 0),
|
||||
NEONMAP1(vcvtpq_s64_v, arm_neon_vcvtps, 0),
|
||||
NEONMAP1(vcvtpq_u16_v, arm_neon_vcvtpu, 0),
|
||||
NEONMAP1(vcvtpq_u32_v, arm_neon_vcvtpu, 0),
|
||||
NEONMAP1(vcvtpq_u64_v, arm_neon_vcvtpu, 0),
|
||||
NEONMAP0(vcvtq_f32_v),
|
||||
NEONMAP2(vcvtq_n_f16_v, arm_neon_vcvtfxu2fp, arm_neon_vcvtfxs2fp, 0),
|
||||
NEONMAP2(vcvtq_n_f32_v, arm_neon_vcvtfxu2fp, arm_neon_vcvtfxs2fp, 0),
|
||||
NEONMAP1(vcvtq_n_s16_v, arm_neon_vcvtfp2fxs, 0),
|
||||
NEONMAP1(vcvtq_n_s32_v, arm_neon_vcvtfp2fxs, 0),
|
||||
NEONMAP1(vcvtq_n_s64_v, arm_neon_vcvtfp2fxs, 0),
|
||||
NEONMAP1(vcvtq_n_u16_v, arm_neon_vcvtfp2fxu, 0),
|
||||
NEONMAP1(vcvtq_n_u32_v, arm_neon_vcvtfp2fxu, 0),
|
||||
NEONMAP1(vcvtq_n_u64_v, arm_neon_vcvtfp2fxu, 0),
|
||||
NEONMAP0(vcvtq_s16_v),
|
||||
NEONMAP0(vcvtq_s32_v),
|
||||
NEONMAP0(vcvtq_s64_v),
|
||||
NEONMAP0(vcvtq_u16_v),
|
||||
NEONMAP0(vcvtq_u32_v),
|
||||
NEONMAP0(vcvtq_u64_v),
|
||||
NEONMAP0(vext_v),
|
||||
@ -3338,19 +3366,27 @@ static const NeonIntrinsicInfo AArch64SIMDIntrinsicMap[] = {
|
||||
NEONMAP1(vcnt_v, ctpop, Add1ArgType),
|
||||
NEONMAP1(vcntq_v, ctpop, Add1ArgType),
|
||||
NEONMAP1(vcvt_f16_f32, aarch64_neon_vcvtfp2hf, 0),
|
||||
NEONMAP0(vcvt_f16_v),
|
||||
NEONMAP1(vcvt_f32_f16, aarch64_neon_vcvthf2fp, 0),
|
||||
NEONMAP0(vcvt_f32_v),
|
||||
NEONMAP2(vcvt_n_f16_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0),
|
||||
NEONMAP2(vcvt_n_f32_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0),
|
||||
NEONMAP2(vcvt_n_f64_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0),
|
||||
NEONMAP1(vcvt_n_s16_v, aarch64_neon_vcvtfp2fxs, 0),
|
||||
NEONMAP1(vcvt_n_s32_v, aarch64_neon_vcvtfp2fxs, 0),
|
||||
NEONMAP1(vcvt_n_s64_v, aarch64_neon_vcvtfp2fxs, 0),
|
||||
NEONMAP1(vcvt_n_u16_v, aarch64_neon_vcvtfp2fxu, 0),
|
||||
NEONMAP1(vcvt_n_u32_v, aarch64_neon_vcvtfp2fxu, 0),
|
||||
NEONMAP1(vcvt_n_u64_v, aarch64_neon_vcvtfp2fxu, 0),
|
||||
NEONMAP0(vcvtq_f16_v),
|
||||
NEONMAP0(vcvtq_f32_v),
|
||||
NEONMAP2(vcvtq_n_f16_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0),
|
||||
NEONMAP2(vcvtq_n_f32_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0),
|
||||
NEONMAP2(vcvtq_n_f64_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0),
|
||||
NEONMAP1(vcvtq_n_s16_v, aarch64_neon_vcvtfp2fxs, 0),
|
||||
NEONMAP1(vcvtq_n_s32_v, aarch64_neon_vcvtfp2fxs, 0),
|
||||
NEONMAP1(vcvtq_n_s64_v, aarch64_neon_vcvtfp2fxs, 0),
|
||||
NEONMAP1(vcvtq_n_u16_v, aarch64_neon_vcvtfp2fxu, 0),
|
||||
NEONMAP1(vcvtq_n_u32_v, aarch64_neon_vcvtfp2fxu, 0),
|
||||
NEONMAP1(vcvtq_n_u64_v, aarch64_neon_vcvtfp2fxu, 0),
|
||||
NEONMAP1(vcvtx_f32_v, aarch64_neon_fcvtxn, AddRetType | Add1ArgType),
|
||||
@ -3819,9 +3855,20 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr(
|
||||
case NEON::BI__builtin_neon_vcageq_v:
|
||||
case NEON::BI__builtin_neon_vcagt_v:
|
||||
case NEON::BI__builtin_neon_vcagtq_v: {
|
||||
llvm::Type *VecFlt = llvm::VectorType::get(
|
||||
VTy->getScalarSizeInBits() == 32 ? FloatTy : DoubleTy,
|
||||
VTy->getNumElements());
|
||||
llvm::Type *Ty;
|
||||
switch (VTy->getScalarSizeInBits()) {
|
||||
default: llvm_unreachable("unexpected type");
|
||||
case 32:
|
||||
Ty = FloatTy;
|
||||
break;
|
||||
case 64:
|
||||
Ty = DoubleTy;
|
||||
break;
|
||||
case 16:
|
||||
Ty = HalfTy;
|
||||
break;
|
||||
}
|
||||
llvm::Type *VecFlt = llvm::VectorType::get(Ty, VTy->getNumElements());
|
||||
llvm::Type *Tys[] = { VTy, VecFlt };
|
||||
Function *F = CGM.getIntrinsic(LLVMIntrinsic, Tys);
|
||||
return EmitNeonCall(F, Ops, NameHint);
|
||||
@ -3838,8 +3885,16 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr(
|
||||
Ty = GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float32, false, Quad));
|
||||
return Usgn ? Builder.CreateUIToFP(Ops[0], Ty, "vcvt")
|
||||
: Builder.CreateSIToFP(Ops[0], Ty, "vcvt");
|
||||
case NEON::BI__builtin_neon_vcvt_f16_v:
|
||||
case NEON::BI__builtin_neon_vcvtq_f16_v:
|
||||
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
|
||||
Ty = GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float16, false, Quad));
|
||||
return Usgn ? Builder.CreateUIToFP(Ops[0], Ty, "vcvt")
|
||||
: Builder.CreateSIToFP(Ops[0], Ty, "vcvt");
|
||||
case NEON::BI__builtin_neon_vcvt_n_f16_v:
|
||||
case NEON::BI__builtin_neon_vcvt_n_f32_v:
|
||||
case NEON::BI__builtin_neon_vcvt_n_f64_v:
|
||||
case NEON::BI__builtin_neon_vcvtq_n_f16_v:
|
||||
case NEON::BI__builtin_neon_vcvtq_n_f32_v:
|
||||
case NEON::BI__builtin_neon_vcvtq_n_f64_v: {
|
||||
llvm::Type *Tys[2] = { GetFloatNeonType(this, Type), Ty };
|
||||
@ -3847,11 +3902,15 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr(
|
||||
Function *F = CGM.getIntrinsic(Int, Tys);
|
||||
return EmitNeonCall(F, Ops, "vcvt_n");
|
||||
}
|
||||
case NEON::BI__builtin_neon_vcvt_n_s16_v:
|
||||
case NEON::BI__builtin_neon_vcvt_n_s32_v:
|
||||
case NEON::BI__builtin_neon_vcvt_n_u16_v:
|
||||
case NEON::BI__builtin_neon_vcvt_n_u32_v:
|
||||
case NEON::BI__builtin_neon_vcvt_n_s64_v:
|
||||
case NEON::BI__builtin_neon_vcvt_n_u64_v:
|
||||
case NEON::BI__builtin_neon_vcvtq_n_s16_v:
|
||||
case NEON::BI__builtin_neon_vcvtq_n_s32_v:
|
||||
case NEON::BI__builtin_neon_vcvtq_n_u16_v:
|
||||
case NEON::BI__builtin_neon_vcvtq_n_u32_v:
|
||||
case NEON::BI__builtin_neon_vcvtq_n_s64_v:
|
||||
case NEON::BI__builtin_neon_vcvtq_n_u64_v: {
|
||||
@ -3863,44 +3922,63 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr(
|
||||
case NEON::BI__builtin_neon_vcvt_u32_v:
|
||||
case NEON::BI__builtin_neon_vcvt_s64_v:
|
||||
case NEON::BI__builtin_neon_vcvt_u64_v:
|
||||
case NEON::BI__builtin_neon_vcvt_s16_v:
|
||||
case NEON::BI__builtin_neon_vcvt_u16_v:
|
||||
case NEON::BI__builtin_neon_vcvtq_s32_v:
|
||||
case NEON::BI__builtin_neon_vcvtq_u32_v:
|
||||
case NEON::BI__builtin_neon_vcvtq_s64_v:
|
||||
case NEON::BI__builtin_neon_vcvtq_u64_v: {
|
||||
case NEON::BI__builtin_neon_vcvtq_u64_v:
|
||||
case NEON::BI__builtin_neon_vcvtq_s16_v:
|
||||
case NEON::BI__builtin_neon_vcvtq_u16_v: {
|
||||
Ops[0] = Builder.CreateBitCast(Ops[0], GetFloatNeonType(this, Type));
|
||||
return Usgn ? Builder.CreateFPToUI(Ops[0], Ty, "vcvt")
|
||||
: Builder.CreateFPToSI(Ops[0], Ty, "vcvt");
|
||||
}
|
||||
case NEON::BI__builtin_neon_vcvta_s16_v:
|
||||
case NEON::BI__builtin_neon_vcvta_s32_v:
|
||||
case NEON::BI__builtin_neon_vcvta_s64_v:
|
||||
case NEON::BI__builtin_neon_vcvta_u32_v:
|
||||
case NEON::BI__builtin_neon_vcvta_u64_v:
|
||||
case NEON::BI__builtin_neon_vcvtaq_s16_v:
|
||||
case NEON::BI__builtin_neon_vcvtaq_s32_v:
|
||||
case NEON::BI__builtin_neon_vcvtaq_s64_v:
|
||||
case NEON::BI__builtin_neon_vcvtaq_u16_v:
|
||||
case NEON::BI__builtin_neon_vcvtaq_u32_v:
|
||||
case NEON::BI__builtin_neon_vcvtaq_u64_v:
|
||||
case NEON::BI__builtin_neon_vcvtn_s16_v:
|
||||
case NEON::BI__builtin_neon_vcvtn_s32_v:
|
||||
case NEON::BI__builtin_neon_vcvtn_s64_v:
|
||||
case NEON::BI__builtin_neon_vcvtn_u16_v:
|
||||
case NEON::BI__builtin_neon_vcvtn_u32_v:
|
||||
case NEON::BI__builtin_neon_vcvtn_u64_v:
|
||||
case NEON::BI__builtin_neon_vcvtnq_s16_v:
|
||||
case NEON::BI__builtin_neon_vcvtnq_s32_v:
|
||||
case NEON::BI__builtin_neon_vcvtnq_s64_v:
|
||||
case NEON::BI__builtin_neon_vcvtnq_u16_v:
|
||||
case NEON::BI__builtin_neon_vcvtnq_u32_v:
|
||||
case NEON::BI__builtin_neon_vcvtnq_u64_v:
|
||||
case NEON::BI__builtin_neon_vcvtp_s16_v:
|
||||
case NEON::BI__builtin_neon_vcvtp_s32_v:
|
||||
case NEON::BI__builtin_neon_vcvtp_s64_v:
|
||||
case NEON::BI__builtin_neon_vcvtp_u16_v:
|
||||
case NEON::BI__builtin_neon_vcvtp_u32_v:
|
||||
case NEON::BI__builtin_neon_vcvtp_u64_v:
|
||||
case NEON::BI__builtin_neon_vcvtpq_s16_v:
|
||||
case NEON::BI__builtin_neon_vcvtpq_s32_v:
|
||||
case NEON::BI__builtin_neon_vcvtpq_s64_v:
|
||||
case NEON::BI__builtin_neon_vcvtpq_u16_v:
|
||||
case NEON::BI__builtin_neon_vcvtpq_u32_v:
|
||||
case NEON::BI__builtin_neon_vcvtpq_u64_v:
|
||||
case NEON::BI__builtin_neon_vcvtm_s16_v:
|
||||
case NEON::BI__builtin_neon_vcvtm_s32_v:
|
||||
case NEON::BI__builtin_neon_vcvtm_s64_v:
|
||||
case NEON::BI__builtin_neon_vcvtm_u16_v:
|
||||
case NEON::BI__builtin_neon_vcvtm_u32_v:
|
||||
case NEON::BI__builtin_neon_vcvtm_u64_v:
|
||||
case NEON::BI__builtin_neon_vcvtmq_s16_v:
|
||||
case NEON::BI__builtin_neon_vcvtmq_s32_v:
|
||||
case NEON::BI__builtin_neon_vcvtmq_s64_v:
|
||||
case NEON::BI__builtin_neon_vcvtmq_u16_v:
|
||||
case NEON::BI__builtin_neon_vcvtmq_u32_v:
|
||||
case NEON::BI__builtin_neon_vcvtmq_u64_v: {
|
||||
llvm::Type *Tys[2] = { Ty, GetFloatNeonType(this, Type) };
|
||||
@ -6110,7 +6188,9 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
|
||||
Ops[2] = EmitNeonSplat(Ops[2], cast<ConstantInt>(Ops[3]));
|
||||
return Builder.CreateCall(F, {Ops[2], Ops[1], Ops[0]});
|
||||
}
|
||||
case NEON::BI__builtin_neon_vfmah_lane_f16:
|
||||
case NEON::BI__builtin_neon_vfmas_lane_f32:
|
||||
case NEON::BI__builtin_neon_vfmah_laneq_f16:
|
||||
case NEON::BI__builtin_neon_vfmas_laneq_f32:
|
||||
case NEON::BI__builtin_neon_vfmad_lane_f64:
|
||||
case NEON::BI__builtin_neon_vfmad_laneq_f64: {
|
||||
@ -6285,18 +6365,25 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
|
||||
case NEON::BI__builtin_neon_vcvt_u32_v:
|
||||
case NEON::BI__builtin_neon_vcvt_s64_v:
|
||||
case NEON::BI__builtin_neon_vcvt_u64_v:
|
||||
case NEON::BI__builtin_neon_vcvt_s16_v:
|
||||
case NEON::BI__builtin_neon_vcvt_u16_v:
|
||||
case NEON::BI__builtin_neon_vcvtq_s32_v:
|
||||
case NEON::BI__builtin_neon_vcvtq_u32_v:
|
||||
case NEON::BI__builtin_neon_vcvtq_s64_v:
|
||||
case NEON::BI__builtin_neon_vcvtq_u64_v: {
|
||||
case NEON::BI__builtin_neon_vcvtq_u64_v:
|
||||
case NEON::BI__builtin_neon_vcvtq_s16_v:
|
||||
case NEON::BI__builtin_neon_vcvtq_u16_v: {
|
||||
Ops[0] = Builder.CreateBitCast(Ops[0], GetFloatNeonType(this, Type));
|
||||
if (usgn)
|
||||
return Builder.CreateFPToUI(Ops[0], Ty);
|
||||
return Builder.CreateFPToSI(Ops[0], Ty);
|
||||
}
|
||||
case NEON::BI__builtin_neon_vcvta_s16_v:
|
||||
case NEON::BI__builtin_neon_vcvta_s32_v:
|
||||
case NEON::BI__builtin_neon_vcvtaq_s16_v:
|
||||
case NEON::BI__builtin_neon_vcvtaq_s32_v:
|
||||
case NEON::BI__builtin_neon_vcvta_u32_v:
|
||||
case NEON::BI__builtin_neon_vcvtaq_u16_v:
|
||||
case NEON::BI__builtin_neon_vcvtaq_u32_v:
|
||||
case NEON::BI__builtin_neon_vcvta_s64_v:
|
||||
case NEON::BI__builtin_neon_vcvtaq_s64_v:
|
||||
@ -6306,9 +6393,13 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
|
||||
llvm::Type *Tys[2] = { Ty, GetFloatNeonType(this, Type) };
|
||||
return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvta");
|
||||
}
|
||||
case NEON::BI__builtin_neon_vcvtm_s16_v:
|
||||
case NEON::BI__builtin_neon_vcvtm_s32_v:
|
||||
case NEON::BI__builtin_neon_vcvtmq_s16_v:
|
||||
case NEON::BI__builtin_neon_vcvtmq_s32_v:
|
||||
case NEON::BI__builtin_neon_vcvtm_u16_v:
|
||||
case NEON::BI__builtin_neon_vcvtm_u32_v:
|
||||
case NEON::BI__builtin_neon_vcvtmq_u16_v:
|
||||
case NEON::BI__builtin_neon_vcvtmq_u32_v:
|
||||
case NEON::BI__builtin_neon_vcvtm_s64_v:
|
||||
case NEON::BI__builtin_neon_vcvtmq_s64_v:
|
||||
@ -6318,9 +6409,13 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
|
||||
llvm::Type *Tys[2] = { Ty, GetFloatNeonType(this, Type) };
|
||||
return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtm");
|
||||
}
|
||||
case NEON::BI__builtin_neon_vcvtn_s16_v:
|
||||
case NEON::BI__builtin_neon_vcvtn_s32_v:
|
||||
case NEON::BI__builtin_neon_vcvtnq_s16_v:
|
||||
case NEON::BI__builtin_neon_vcvtnq_s32_v:
|
||||
case NEON::BI__builtin_neon_vcvtn_u16_v:
|
||||
case NEON::BI__builtin_neon_vcvtn_u32_v:
|
||||
case NEON::BI__builtin_neon_vcvtnq_u16_v:
|
||||
case NEON::BI__builtin_neon_vcvtnq_u32_v:
|
||||
case NEON::BI__builtin_neon_vcvtn_s64_v:
|
||||
case NEON::BI__builtin_neon_vcvtnq_s64_v:
|
||||
@ -6330,9 +6425,13 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
|
||||
llvm::Type *Tys[2] = { Ty, GetFloatNeonType(this, Type) };
|
||||
return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtn");
|
||||
}
|
||||
case NEON::BI__builtin_neon_vcvtp_s16_v:
|
||||
case NEON::BI__builtin_neon_vcvtp_s32_v:
|
||||
case NEON::BI__builtin_neon_vcvtpq_s16_v:
|
||||
case NEON::BI__builtin_neon_vcvtpq_s32_v:
|
||||
case NEON::BI__builtin_neon_vcvtp_u16_v:
|
||||
case NEON::BI__builtin_neon_vcvtp_u32_v:
|
||||
case NEON::BI__builtin_neon_vcvtpq_u16_v:
|
||||
case NEON::BI__builtin_neon_vcvtpq_u32_v:
|
||||
case NEON::BI__builtin_neon_vcvtp_s64_v:
|
||||
case NEON::BI__builtin_neon_vcvtpq_s64_v:
|
||||
@ -6505,6 +6604,24 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
|
||||
Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxv");
|
||||
return Builder.CreateTrunc(Ops[0], Int16Ty);
|
||||
}
|
||||
case NEON::BI__builtin_neon_vmaxv_f16: {
|
||||
Int = Intrinsic::aarch64_neon_fmaxv;
|
||||
Ty = HalfTy;
|
||||
VTy = llvm::VectorType::get(HalfTy, 4);
|
||||
llvm::Type *Tys[2] = { Ty, VTy };
|
||||
Ops.push_back(EmitScalarExpr(E->getArg(0)));
|
||||
Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxv");
|
||||
return Builder.CreateTrunc(Ops[0], HalfTy);
|
||||
}
|
||||
case NEON::BI__builtin_neon_vmaxvq_f16: {
|
||||
Int = Intrinsic::aarch64_neon_fmaxv;
|
||||
Ty = HalfTy;
|
||||
VTy = llvm::VectorType::get(HalfTy, 8);
|
||||
llvm::Type *Tys[2] = { Ty, VTy };
|
||||
Ops.push_back(EmitScalarExpr(E->getArg(0)));
|
||||
Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxv");
|
||||
return Builder.CreateTrunc(Ops[0], HalfTy);
|
||||
}
|
||||
case NEON::BI__builtin_neon_vminv_u8: {
|
||||
Int = Intrinsic::aarch64_neon_uminv;
|
||||
Ty = Int32Ty;
|
||||
@ -6577,6 +6694,60 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
|
||||
Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminv");
|
||||
return Builder.CreateTrunc(Ops[0], Int16Ty);
|
||||
}
|
||||
case NEON::BI__builtin_neon_vminv_f16: {
|
||||
Int = Intrinsic::aarch64_neon_fminv;
|
||||
Ty = HalfTy;
|
||||
VTy = llvm::VectorType::get(HalfTy, 4);
|
||||
llvm::Type *Tys[2] = { Ty, VTy };
|
||||
Ops.push_back(EmitScalarExpr(E->getArg(0)));
|
||||
Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminv");
|
||||
return Builder.CreateTrunc(Ops[0], HalfTy);
|
||||
}
|
||||
case NEON::BI__builtin_neon_vminvq_f16: {
|
||||
Int = Intrinsic::aarch64_neon_fminv;
|
||||
Ty = HalfTy;
|
||||
VTy = llvm::VectorType::get(HalfTy, 8);
|
||||
llvm::Type *Tys[2] = { Ty, VTy };
|
||||
Ops.push_back(EmitScalarExpr(E->getArg(0)));
|
||||
Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminv");
|
||||
return Builder.CreateTrunc(Ops[0], HalfTy);
|
||||
}
|
||||
case NEON::BI__builtin_neon_vmaxnmv_f16: {
|
||||
Int = Intrinsic::aarch64_neon_fmaxnmv;
|
||||
Ty = HalfTy;
|
||||
VTy = llvm::VectorType::get(HalfTy, 4);
|
||||
llvm::Type *Tys[2] = { Ty, VTy };
|
||||
Ops.push_back(EmitScalarExpr(E->getArg(0)));
|
||||
Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxnmv");
|
||||
return Builder.CreateTrunc(Ops[0], HalfTy);
|
||||
}
|
||||
case NEON::BI__builtin_neon_vmaxnmvq_f16: {
|
||||
Int = Intrinsic::aarch64_neon_fmaxnmv;
|
||||
Ty = HalfTy;
|
||||
VTy = llvm::VectorType::get(HalfTy, 8);
|
||||
llvm::Type *Tys[2] = { Ty, VTy };
|
||||
Ops.push_back(EmitScalarExpr(E->getArg(0)));
|
||||
Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxnmv");
|
||||
return Builder.CreateTrunc(Ops[0], HalfTy);
|
||||
}
|
||||
case NEON::BI__builtin_neon_vminnmv_f16: {
|
||||
Int = Intrinsic::aarch64_neon_fminnmv;
|
||||
Ty = HalfTy;
|
||||
VTy = llvm::VectorType::get(HalfTy, 4);
|
||||
llvm::Type *Tys[2] = { Ty, VTy };
|
||||
Ops.push_back(EmitScalarExpr(E->getArg(0)));
|
||||
Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminnmv");
|
||||
return Builder.CreateTrunc(Ops[0], HalfTy);
|
||||
}
|
||||
case NEON::BI__builtin_neon_vminnmvq_f16: {
|
||||
Int = Intrinsic::aarch64_neon_fminnmv;
|
||||
Ty = HalfTy;
|
||||
VTy = llvm::VectorType::get(HalfTy, 8);
|
||||
llvm::Type *Tys[2] = { Ty, VTy };
|
||||
Ops.push_back(EmitScalarExpr(E->getArg(0)));
|
||||
Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminnmv");
|
||||
return Builder.CreateTrunc(Ops[0], HalfTy);
|
||||
}
|
||||
case NEON::BI__builtin_neon_vmul_n_f64: {
|
||||
Ops[0] = Builder.CreateBitCast(Ops[0], DoubleTy);
|
||||
Value *RHS = Builder.CreateBitCast(EmitScalarExpr(E->getArg(1)), DoubleTy);
|
||||
|
@ -2906,7 +2906,7 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
|
||||
|
||||
llvm::Instruction *Ret;
|
||||
if (RV) {
|
||||
EmitReturnValueCheck(RV, EndLoc);
|
||||
EmitReturnValueCheck(RV);
|
||||
Ret = Builder.CreateRet(RV);
|
||||
} else {
|
||||
Ret = Builder.CreateRetVoid();
|
||||
@ -2916,8 +2916,7 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
|
||||
Ret->setDebugLoc(std::move(RetDbgLoc));
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitReturnValueCheck(llvm::Value *RV,
|
||||
SourceLocation EndLoc) {
|
||||
void CodeGenFunction::EmitReturnValueCheck(llvm::Value *RV) {
|
||||
// A current decl may not be available when emitting vtable thunks.
|
||||
if (!CurCodeDecl)
|
||||
return;
|
||||
@ -2950,27 +2949,30 @@ void CodeGenFunction::EmitReturnValueCheck(llvm::Value *RV,
|
||||
|
||||
SanitizerScope SanScope(this);
|
||||
|
||||
llvm::BasicBlock *Check = nullptr;
|
||||
llvm::BasicBlock *NoCheck = nullptr;
|
||||
if (requiresReturnValueNullabilityCheck()) {
|
||||
// Before doing the nullability check, make sure that the preconditions for
|
||||
// the check are met.
|
||||
Check = createBasicBlock("nullcheck");
|
||||
NoCheck = createBasicBlock("no.nullcheck");
|
||||
Builder.CreateCondBr(RetValNullabilityPrecondition, Check, NoCheck);
|
||||
EmitBlock(Check);
|
||||
}
|
||||
|
||||
// Now do the null check. If the returns_nonnull attribute is present, this
|
||||
// is done unconditionally.
|
||||
llvm::Value *Cond = Builder.CreateIsNotNull(RV);
|
||||
llvm::Constant *StaticData[] = {
|
||||
EmitCheckSourceLocation(EndLoc), EmitCheckSourceLocation(AttrLoc),
|
||||
};
|
||||
EmitCheck(std::make_pair(Cond, CheckKind), Handler, StaticData, None);
|
||||
|
||||
// Make sure the "return" source location is valid. If we're checking a
|
||||
// nullability annotation, make sure the preconditions for the check are met.
|
||||
llvm::BasicBlock *Check = createBasicBlock("nullcheck");
|
||||
llvm::BasicBlock *NoCheck = createBasicBlock("no.nullcheck");
|
||||
llvm::Value *SLocPtr = Builder.CreateLoad(ReturnLocation, "return.sloc.load");
|
||||
llvm::Value *CanNullCheck = Builder.CreateIsNotNull(SLocPtr);
|
||||
if (requiresReturnValueNullabilityCheck())
|
||||
EmitBlock(NoCheck);
|
||||
CanNullCheck =
|
||||
Builder.CreateAnd(CanNullCheck, RetValNullabilityPrecondition);
|
||||
Builder.CreateCondBr(CanNullCheck, Check, NoCheck);
|
||||
EmitBlock(Check);
|
||||
|
||||
// Now do the null check.
|
||||
llvm::Value *Cond = Builder.CreateIsNotNull(RV);
|
||||
llvm::Constant *StaticData[] = {EmitCheckSourceLocation(AttrLoc)};
|
||||
llvm::Value *DynamicData[] = {SLocPtr};
|
||||
EmitCheck(std::make_pair(Cond, CheckKind), Handler, StaticData, DynamicData);
|
||||
|
||||
EmitBlock(NoCheck);
|
||||
|
||||
#ifndef NDEBUG
|
||||
// The return location should not be used after the check has been emitted.
|
||||
ReturnLocation = Address::invalid();
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool isInAllocaArgument(CGCXXABI &ABI, QualType type) {
|
||||
@ -3813,7 +3815,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
|
||||
assert(NumIRArgs == 1);
|
||||
if (RV.isScalar() || RV.isComplex()) {
|
||||
// Make a temporary alloca to pass the argument.
|
||||
Address Addr = CreateMemTemp(I->Ty, ArgInfo.getIndirectAlign());
|
||||
Address Addr = CreateMemTemp(I->Ty, ArgInfo.getIndirectAlign(),
|
||||
"indirect-arg-temp", false);
|
||||
IRCallArgs[FirstIRArg] = Addr.getPointer();
|
||||
|
||||
LValue argLV = MakeAddrLValue(Addr, I->Ty);
|
||||
@ -3842,7 +3845,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
|
||||
< Align.getQuantity()) ||
|
||||
(ArgInfo.getIndirectByVal() && (RVAddrSpace != ArgAddrSpace))) {
|
||||
// Create an aligned temporary, and copy to it.
|
||||
Address AI = CreateMemTemp(I->Ty, ArgInfo.getIndirectAlign());
|
||||
Address AI = CreateMemTemp(I->Ty, ArgInfo.getIndirectAlign(),
|
||||
"byval-temp", false);
|
||||
IRCallArgs[FirstIRArg] = AI.getPointer();
|
||||
EmitAggregateCopy(AI, Addr, I->Ty, RV.isVolatileQualified());
|
||||
} else {
|
||||
|
@ -2770,10 +2770,19 @@ CodeGenFunction::CanDevirtualizeMemberFunctionCall(const Expr *Base,
|
||||
|
||||
// We can devirtualize calls on an object accessed by a class member access
|
||||
// expression, since by C++11 [basic.life]p6 we know that it can't refer to
|
||||
// a derived class object constructed in the same location.
|
||||
// a derived class object constructed in the same location. However, we avoid
|
||||
// devirtualizing a call to a template function that we could instantiate
|
||||
// implicitly, but have not decided to do so. This is needed because if this
|
||||
// function does not get instantiated, the devirtualization will create a
|
||||
// direct call to a function whose body may not exist. In contrast, calls to
|
||||
// template functions that are not defined in this TU are allowed to be
|
||||
// devirtualized under assumption that it is user responsibility to
|
||||
// instantiate them in some other TU.
|
||||
if (const MemberExpr *ME = dyn_cast<MemberExpr>(Base))
|
||||
if (const ValueDecl *VD = dyn_cast<ValueDecl>(ME->getMemberDecl()))
|
||||
return VD->getType()->isRecordType();
|
||||
return VD->getType()->isRecordType() &&
|
||||
(MD->instantiationIsPending() || MD->isDefined() ||
|
||||
!MD->isImplicitlyInstantiable());
|
||||
|
||||
// Likewise for calls on an object accessed by a (non-reference) pointer to
|
||||
// member access.
|
||||
|
@ -954,6 +954,7 @@ void CodeGenFunction::EmitLifetimeEnd(llvm::Value *Size, llvm::Value *Addr) {
|
||||
CodeGenFunction::AutoVarEmission
|
||||
CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
|
||||
QualType Ty = D.getType();
|
||||
assert(Ty.getAddressSpace() == LangAS::Default);
|
||||
|
||||
AutoVarEmission emission(D);
|
||||
|
||||
@ -1046,8 +1047,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
|
||||
// Create the alloca. Note that we set the name separately from
|
||||
// building the instruction so that it's there even in no-asserts
|
||||
// builds.
|
||||
address = CreateTempAlloca(allocaTy, allocaAlignment);
|
||||
address.getPointer()->setName(D.getName());
|
||||
address = CreateTempAlloca(allocaTy, allocaAlignment, D.getName());
|
||||
|
||||
// Don't emit lifetime markers for MSVC catch parameters. The lifetime of
|
||||
// the catch parameter starts in the catchpad instruction, and we can't
|
||||
@ -1107,27 +1107,9 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
|
||||
llvm::Type *llvmTy = ConvertTypeForMem(elementType);
|
||||
|
||||
// Allocate memory for the array.
|
||||
llvm::AllocaInst *vla = Builder.CreateAlloca(llvmTy, elementCount, "vla");
|
||||
vla->setAlignment(alignment.getQuantity());
|
||||
|
||||
address = Address(vla, alignment);
|
||||
address = CreateTempAlloca(llvmTy, alignment, "vla", elementCount);
|
||||
}
|
||||
|
||||
// Alloca always returns a pointer in alloca address space, which may
|
||||
// be different from the type defined by the language. For example,
|
||||
// in C++ the auto variables are in the default address space. Therefore
|
||||
// cast alloca to the expected address space when necessary.
|
||||
auto T = D.getType();
|
||||
assert(T.getAddressSpace() == LangAS::Default);
|
||||
if (getASTAllocaAddressSpace() != LangAS::Default) {
|
||||
auto *Addr = getTargetHooks().performAddrSpaceCast(
|
||||
*this, address.getPointer(), getASTAllocaAddressSpace(),
|
||||
T.getAddressSpace(),
|
||||
address.getElementType()->getPointerTo(
|
||||
getContext().getTargetAddressSpace(T.getAddressSpace())),
|
||||
/*non-null*/ true);
|
||||
address = Address(Addr, address.getAlignment());
|
||||
}
|
||||
setAddrOfLocalVar(&D, address);
|
||||
emission.Addr = address;
|
||||
|
||||
|
@ -61,18 +61,36 @@ llvm::Value *CodeGenFunction::EmitCastToVoidPtr(llvm::Value *value) {
|
||||
/// CreateTempAlloca - This creates a alloca and inserts it into the entry
|
||||
/// block.
|
||||
Address CodeGenFunction::CreateTempAlloca(llvm::Type *Ty, CharUnits Align,
|
||||
const Twine &Name) {
|
||||
auto Alloca = CreateTempAlloca(Ty, Name);
|
||||
const Twine &Name,
|
||||
llvm::Value *ArraySize,
|
||||
bool CastToDefaultAddrSpace) {
|
||||
auto Alloca = CreateTempAlloca(Ty, Name, ArraySize);
|
||||
Alloca->setAlignment(Align.getQuantity());
|
||||
return Address(Alloca, Align);
|
||||
llvm::Value *V = Alloca;
|
||||
// Alloca always returns a pointer in alloca address space, which may
|
||||
// be different from the type defined by the language. For example,
|
||||
// in C++ the auto variables are in the default address space. Therefore
|
||||
// cast alloca to the default address space when necessary.
|
||||
if (CastToDefaultAddrSpace && getASTAllocaAddressSpace() != LangAS::Default) {
|
||||
auto DestAddrSpace = getContext().getTargetAddressSpace(LangAS::Default);
|
||||
V = getTargetHooks().performAddrSpaceCast(
|
||||
*this, V, getASTAllocaAddressSpace(), LangAS::Default,
|
||||
Ty->getPointerTo(DestAddrSpace), /*non-null*/ true);
|
||||
}
|
||||
|
||||
return Address(V, Align);
|
||||
}
|
||||
|
||||
/// CreateTempAlloca - This creates a alloca and inserts it into the entry
|
||||
/// block.
|
||||
/// CreateTempAlloca - This creates an alloca and inserts it into the entry
|
||||
/// block if \p ArraySize is nullptr, otherwise inserts it at the current
|
||||
/// insertion point of the builder.
|
||||
llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(llvm::Type *Ty,
|
||||
const Twine &Name) {
|
||||
const Twine &Name,
|
||||
llvm::Value *ArraySize) {
|
||||
if (ArraySize)
|
||||
return Builder.CreateAlloca(Ty, ArraySize, Name);
|
||||
return new llvm::AllocaInst(Ty, CGM.getDataLayout().getAllocaAddrSpace(),
|
||||
nullptr, Name, AllocaInsertPt);
|
||||
ArraySize, Name, AllocaInsertPt);
|
||||
}
|
||||
|
||||
/// CreateDefaultAlignTempAlloca - This creates an alloca with the
|
||||
@ -99,14 +117,18 @@ Address CodeGenFunction::CreateIRTemp(QualType Ty, const Twine &Name) {
|
||||
return CreateTempAlloca(ConvertType(Ty), Align, Name);
|
||||
}
|
||||
|
||||
Address CodeGenFunction::CreateMemTemp(QualType Ty, const Twine &Name) {
|
||||
Address CodeGenFunction::CreateMemTemp(QualType Ty, const Twine &Name,
|
||||
bool CastToDefaultAddrSpace) {
|
||||
// FIXME: Should we prefer the preferred type alignment here?
|
||||
return CreateMemTemp(Ty, getContext().getTypeAlignInChars(Ty), Name);
|
||||
return CreateMemTemp(Ty, getContext().getTypeAlignInChars(Ty), Name,
|
||||
CastToDefaultAddrSpace);
|
||||
}
|
||||
|
||||
Address CodeGenFunction::CreateMemTemp(QualType Ty, CharUnits Align,
|
||||
const Twine &Name) {
|
||||
return CreateTempAlloca(ConvertTypeForMem(Ty), Align, Name);
|
||||
const Twine &Name,
|
||||
bool CastToDefaultAddrSpace) {
|
||||
return CreateTempAlloca(ConvertTypeForMem(Ty), Align, Name, nullptr,
|
||||
CastToDefaultAddrSpace);
|
||||
}
|
||||
|
||||
/// EvaluateExprAsBool - Perform the usual unary conversions on the specified
|
||||
|
@ -308,7 +308,7 @@ class ObjCCommonTypesHelper {
|
||||
SmallVector<CanQualType,5> Params;
|
||||
Params.push_back(Ctx.VoidPtrTy);
|
||||
Params.push_back(Ctx.VoidPtrTy);
|
||||
Params.push_back(Ctx.LongTy);
|
||||
Params.push_back(Ctx.getSizeType());
|
||||
Params.push_back(Ctx.BoolTy);
|
||||
Params.push_back(Ctx.BoolTy);
|
||||
llvm::FunctionType *FTy =
|
||||
|
@ -1024,6 +1024,18 @@ void CodeGenFunction::EmitReturnOfRValue(RValue RV, QualType Ty) {
|
||||
/// if the function returns void, or may be missing one if the function returns
|
||||
/// non-void. Fun stuff :).
|
||||
void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
|
||||
if (requiresReturnValueCheck()) {
|
||||
llvm::Constant *SLoc = EmitCheckSourceLocation(S.getLocStart());
|
||||
auto *SLocPtr =
|
||||
new llvm::GlobalVariable(CGM.getModule(), SLoc->getType(), false,
|
||||
llvm::GlobalVariable::PrivateLinkage, SLoc);
|
||||
SLocPtr->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
|
||||
CGM.getSanitizerMetadata()->disableSanitizerForGlobal(SLocPtr);
|
||||
assert(ReturnLocation.isValid() && "No valid return location");
|
||||
Builder.CreateStore(Builder.CreateBitCast(SLocPtr, Int8PtrTy),
|
||||
ReturnLocation);
|
||||
}
|
||||
|
||||
// Returning from an outlined SEH helper is UB, and we already warn on it.
|
||||
if (IsOutlinedSEHHelper) {
|
||||
Builder.CreateUnreachable();
|
||||
|
@ -860,6 +860,13 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
|
||||
|
||||
Builder.SetInsertPoint(EntryBB);
|
||||
|
||||
// If we're checking the return value, allocate space for a pointer to a
|
||||
// precise source location of the checked return statement.
|
||||
if (requiresReturnValueCheck()) {
|
||||
ReturnLocation = CreateDefaultAlignTempAlloca(Int8PtrTy, "return.sloc.ptr");
|
||||
InitTempAlloca(ReturnLocation, llvm::ConstantPointerNull::get(Int8PtrTy));
|
||||
}
|
||||
|
||||
// Emit subprogram debug descriptor.
|
||||
if (CGDebugInfo *DI = getDebugInfo()) {
|
||||
// Reconstruct the type from the argument list so that implicit parameters,
|
||||
@ -887,8 +894,10 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
|
||||
if (CGM.getCodeGenOpts().InstrumentForProfiling) {
|
||||
if (CGM.getCodeGenOpts().CallFEntry)
|
||||
Fn->addFnAttr("fentry-call", "true");
|
||||
else
|
||||
Fn->addFnAttr("counting-function", getTarget().getMCountName());
|
||||
else {
|
||||
if (!CurFuncDecl || !CurFuncDecl->hasAttr<NoInstrumentFunctionAttr>())
|
||||
Fn->addFnAttr("counting-function", getTarget().getMCountName());
|
||||
}
|
||||
}
|
||||
|
||||
if (RetTy->isVoidType()) {
|
||||
|
@ -116,9 +116,9 @@ enum TypeEvaluationKind {
|
||||
SANITIZER_CHECK(MulOverflow, mul_overflow, 0) \
|
||||
SANITIZER_CHECK(NegateOverflow, negate_overflow, 0) \
|
||||
SANITIZER_CHECK(NullabilityArg, nullability_arg, 0) \
|
||||
SANITIZER_CHECK(NullabilityReturn, nullability_return, 0) \
|
||||
SANITIZER_CHECK(NullabilityReturn, nullability_return, 1) \
|
||||
SANITIZER_CHECK(NonnullArg, nonnull_arg, 0) \
|
||||
SANITIZER_CHECK(NonnullReturn, nonnull_return, 0) \
|
||||
SANITIZER_CHECK(NonnullReturn, nonnull_return, 1) \
|
||||
SANITIZER_CHECK(OutOfBounds, out_of_bounds, 0) \
|
||||
SANITIZER_CHECK(PointerOverflow, pointer_overflow, 0) \
|
||||
SANITIZER_CHECK(ShiftOutOfBounds, shift_out_of_bounds, 0) \
|
||||
@ -1407,6 +1407,17 @@ class CodeGenFunction : public CodeGenTypeCache {
|
||||
return RetValNullabilityPrecondition;
|
||||
}
|
||||
|
||||
/// Used to store precise source locations for return statements by the
|
||||
/// runtime return value checks.
|
||||
Address ReturnLocation = Address::invalid();
|
||||
|
||||
/// Check if the return value of this function requires sanitization.
|
||||
bool requiresReturnValueCheck() const {
|
||||
return requiresReturnValueNullabilityCheck() ||
|
||||
(SanOpts.has(SanitizerKind::ReturnsNonnullAttribute) &&
|
||||
CurCodeDecl && CurCodeDecl->getAttr<ReturnsNonNullAttr>());
|
||||
}
|
||||
|
||||
llvm::BasicBlock *TerminateLandingPad;
|
||||
llvm::BasicBlock *TerminateHandler;
|
||||
llvm::BasicBlock *TrapBB;
|
||||
@ -1778,7 +1789,7 @@ class CodeGenFunction : public CodeGenTypeCache {
|
||||
SourceLocation EndLoc);
|
||||
|
||||
/// Emit a test that checks if the return value \p RV is nonnull.
|
||||
void EmitReturnValueCheck(llvm::Value *RV, SourceLocation EndLoc);
|
||||
void EmitReturnValueCheck(llvm::Value *RV);
|
||||
|
||||
/// EmitStartEHSpec - Emit the start of the exception spec.
|
||||
void EmitStartEHSpec(const Decl *D);
|
||||
@ -1916,13 +1927,36 @@ class CodeGenFunction : public CodeGenTypeCache {
|
||||
LValueBaseInfo *BaseInfo = nullptr);
|
||||
LValue EmitLoadOfPointerLValue(Address Ptr, const PointerType *PtrTy);
|
||||
|
||||
/// CreateTempAlloca - This creates a alloca and inserts it into the entry
|
||||
/// block. The caller is responsible for setting an appropriate alignment on
|
||||
/// CreateTempAlloca - This creates an alloca and inserts it into the entry
|
||||
/// block if \p ArraySize is nullptr, otherwise inserts it at the current
|
||||
/// insertion point of the builder. The caller is responsible for setting an
|
||||
/// appropriate alignment on
|
||||
/// the alloca.
|
||||
llvm::AllocaInst *CreateTempAlloca(llvm::Type *Ty,
|
||||
const Twine &Name = "tmp");
|
||||
///
|
||||
/// \p ArraySize is the number of array elements to be allocated if it
|
||||
/// is not nullptr.
|
||||
///
|
||||
/// LangAS::Default is the address space of pointers to local variables and
|
||||
/// temporaries, as exposed in the source language. In certain
|
||||
/// configurations, this is not the same as the alloca address space, and a
|
||||
/// cast is needed to lift the pointer from the alloca AS into
|
||||
/// LangAS::Default. This can happen when the target uses a restricted
|
||||
/// address space for the stack but the source language requires
|
||||
/// LangAS::Default to be a generic address space. The latter condition is
|
||||
/// common for most programming languages; OpenCL is an exception in that
|
||||
/// LangAS::Default is the private address space, which naturally maps
|
||||
/// to the stack.
|
||||
///
|
||||
/// Because the address of a temporary is often exposed to the program in
|
||||
/// various ways, this function will perform the cast by default. The cast
|
||||
/// may be avoided by passing false as \p CastToDefaultAddrSpace; this is
|
||||
/// more efficient if the caller knows that the address will not be exposed.
|
||||
llvm::AllocaInst *CreateTempAlloca(llvm::Type *Ty, const Twine &Name = "tmp",
|
||||
llvm::Value *ArraySize = nullptr);
|
||||
Address CreateTempAlloca(llvm::Type *Ty, CharUnits align,
|
||||
const Twine &Name = "tmp");
|
||||
const Twine &Name = "tmp",
|
||||
llvm::Value *ArraySize = nullptr,
|
||||
bool CastToDefaultAddrSpace = true);
|
||||
|
||||
/// CreateDefaultAlignedTempAlloca - This creates an alloca with the
|
||||
/// default ABI alignment of the given LLVM type.
|
||||
@ -1957,9 +1991,12 @@ class CodeGenFunction : public CodeGenTypeCache {
|
||||
Address CreateIRTemp(QualType T, const Twine &Name = "tmp");
|
||||
|
||||
/// CreateMemTemp - Create a temporary memory object of the given type, with
|
||||
/// appropriate alignment.
|
||||
Address CreateMemTemp(QualType T, const Twine &Name = "tmp");
|
||||
Address CreateMemTemp(QualType T, CharUnits Align, const Twine &Name = "tmp");
|
||||
/// appropriate alignment. Cast it to the default address space if
|
||||
/// \p CastToDefaultAddrSpace is true.
|
||||
Address CreateMemTemp(QualType T, const Twine &Name = "tmp",
|
||||
bool CastToDefaultAddrSpace = true);
|
||||
Address CreateMemTemp(QualType T, CharUnits Align, const Twine &Name = "tmp",
|
||||
bool CastToDefaultAddrSpace = true);
|
||||
|
||||
/// CreateAggTemp - Create a temporary memory object for the given
|
||||
/// aggregate type.
|
||||
|
@ -98,6 +98,7 @@ CodeGenModule::CodeGenModule(ASTContext &C, const HeaderSearchOptions &HSO,
|
||||
Int16Ty = llvm::Type::getInt16Ty(LLVMContext);
|
||||
Int32Ty = llvm::Type::getInt32Ty(LLVMContext);
|
||||
Int64Ty = llvm::Type::getInt64Ty(LLVMContext);
|
||||
HalfTy = llvm::Type::getHalfTy(LLVMContext);
|
||||
FloatTy = llvm::Type::getFloatTy(LLVMContext);
|
||||
DoubleTy = llvm::Type::getDoubleTy(LLVMContext);
|
||||
PointerWidthInBits = C.getTargetInfo().getPointerWidth(0);
|
||||
@ -506,6 +507,26 @@ void CodeGenModule::Release() {
|
||||
LangOpts.CUDADeviceFlushDenormalsToZero ? 1 : 0);
|
||||
}
|
||||
|
||||
// Emit OpenCL specific module metadata: OpenCL/SPIR version.
|
||||
if (LangOpts.OpenCL) {
|
||||
EmitOpenCLMetadata();
|
||||
// Emit SPIR version.
|
||||
if (getTriple().getArch() == llvm::Triple::spir ||
|
||||
getTriple().getArch() == llvm::Triple::spir64) {
|
||||
// SPIR v2.0 s2.12 - The SPIR version used by the module is stored in the
|
||||
// opencl.spir.version named metadata.
|
||||
llvm::Metadata *SPIRVerElts[] = {
|
||||
llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
|
||||
Int32Ty, LangOpts.OpenCLVersion / 100)),
|
||||
llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
|
||||
Int32Ty, (LangOpts.OpenCLVersion / 100 > 1) ? 0 : 2))};
|
||||
llvm::NamedMDNode *SPIRVerMD =
|
||||
TheModule.getOrInsertNamedMetadata("opencl.spir.version");
|
||||
llvm::LLVMContext &Ctx = TheModule.getContext();
|
||||
SPIRVerMD->addOperand(llvm::MDNode::get(Ctx, SPIRVerElts));
|
||||
}
|
||||
}
|
||||
|
||||
if (uint32_t PLevel = Context.getLangOpts().PICLevel) {
|
||||
assert(PLevel < 3 && "Invalid PIC Level");
|
||||
getModule().setPICLevel(static_cast<llvm::PICLevel::Level>(PLevel));
|
||||
@ -529,6 +550,20 @@ void CodeGenModule::Release() {
|
||||
EmitTargetMetadata();
|
||||
}
|
||||
|
||||
void CodeGenModule::EmitOpenCLMetadata() {
|
||||
// SPIR v2.0 s2.13 - The OpenCL version used by the module is stored in the
|
||||
// opencl.ocl.version named metadata node.
|
||||
llvm::Metadata *OCLVerElts[] = {
|
||||
llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
|
||||
Int32Ty, LangOpts.OpenCLVersion / 100)),
|
||||
llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
|
||||
Int32Ty, (LangOpts.OpenCLVersion % 100) / 10))};
|
||||
llvm::NamedMDNode *OCLVerMD =
|
||||
TheModule.getOrInsertNamedMetadata("opencl.ocl.version");
|
||||
llvm::LLVMContext &Ctx = TheModule.getContext();
|
||||
OCLVerMD->addOperand(llvm::MDNode::get(Ctx, OCLVerElts));
|
||||
}
|
||||
|
||||
void CodeGenModule::UpdateCompletedType(const TagDecl *TD) {
|
||||
// Make sure that this type is translated.
|
||||
Types.UpdateCompletedType(TD);
|
||||
|
@ -1321,6 +1321,9 @@ class CodeGenModule : public CodeGenTypeCache {
|
||||
/// Emits target specific Metadata for global declarations.
|
||||
void EmitTargetMetadata();
|
||||
|
||||
/// Emits OpenCL specific Metadata e.g. OpenCL version.
|
||||
void EmitOpenCLMetadata();
|
||||
|
||||
/// Emit the llvm.gcov metadata used to tell LLVM where to emit the .gcno and
|
||||
/// .gcda files in a way that persists in .bc files.
|
||||
void EmitCoverageFile();
|
||||
|
@ -36,7 +36,7 @@ struct CodeGenTypeCache {
|
||||
/// i8, i16, i32, and i64
|
||||
llvm::IntegerType *Int8Ty, *Int16Ty, *Int32Ty, *Int64Ty;
|
||||
/// float, double
|
||||
llvm::Type *FloatTy, *DoubleTy;
|
||||
llvm::Type *HalfTy, *FloatTy, *DoubleTy;
|
||||
|
||||
/// int
|
||||
llvm::IntegerType *IntTy;
|
||||
|
@ -57,6 +57,10 @@ static CharUnits getTypeStoreSize(CodeGenModule &CGM, llvm::Type *type) {
|
||||
return CharUnits::fromQuantity(CGM.getDataLayout().getTypeStoreSize(type));
|
||||
}
|
||||
|
||||
static CharUnits getTypeAllocSize(CodeGenModule &CGM, llvm::Type *type) {
|
||||
return CharUnits::fromQuantity(CGM.getDataLayout().getTypeAllocSize(type));
|
||||
}
|
||||
|
||||
void SwiftAggLowering::addTypedData(QualType type, CharUnits begin) {
|
||||
// Deal with various aggregate types as special cases:
|
||||
|
||||
@ -542,7 +546,9 @@ SwiftAggLowering::getCoerceAndExpandTypes() const {
|
||||
packed = true;
|
||||
|
||||
elts.push_back(entry.Type);
|
||||
lastEnd = entry.End;
|
||||
|
||||
lastEnd = entry.Begin + getTypeAllocSize(CGM, entry.Type);
|
||||
assert(entry.End <= lastEnd);
|
||||
}
|
||||
|
||||
// We don't need to adjust 'packed' to deal with possible tail padding
|
||||
|
@ -951,8 +951,7 @@ class X86_32ABIInfo : public SwiftABIInfo {
|
||||
Class classify(QualType Ty) const;
|
||||
ABIArgInfo classifyReturnType(QualType RetTy, CCState &State) const;
|
||||
ABIArgInfo classifyArgumentType(QualType RetTy, CCState &State) const;
|
||||
ABIArgInfo reclassifyHvaArgType(QualType RetTy, CCState &State,
|
||||
const ABIArgInfo& current) const;
|
||||
|
||||
/// \brief Updates the number of available free registers, returns
|
||||
/// true if any registers were allocated.
|
||||
bool updateFreeRegs(QualType Ty, CCState &State) const;
|
||||
@ -1536,27 +1535,6 @@ bool X86_32ABIInfo::shouldPrimitiveUseInReg(QualType Ty, CCState &State) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
ABIArgInfo
|
||||
X86_32ABIInfo::reclassifyHvaArgType(QualType Ty, CCState &State,
|
||||
const ABIArgInfo ¤t) const {
|
||||
// Assumes vectorCall calling convention.
|
||||
const Type *Base = nullptr;
|
||||
uint64_t NumElts = 0;
|
||||
|
||||
if (!Ty->isBuiltinType() && !Ty->isVectorType() &&
|
||||
isHomogeneousAggregate(Ty, Base, NumElts)) {
|
||||
if (State.FreeSSERegs >= NumElts) {
|
||||
// HVA types get passed directly in registers if there is room.
|
||||
State.FreeSSERegs -= NumElts;
|
||||
return getDirectX86Hva();
|
||||
}
|
||||
// If there's no room, the HVA gets passed as normal indirect
|
||||
// structure.
|
||||
return getIndirectResult(Ty, /*ByVal=*/false, State);
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
|
||||
CCState &State) const {
|
||||
// FIXME: Set alignment on indirect arguments.
|
||||
@ -1575,35 +1553,20 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
|
||||
}
|
||||
}
|
||||
|
||||
// vectorcall adds the concept of a homogenous vector aggregate, similar
|
||||
// to other targets, regcall uses some of the HVA rules.
|
||||
// Regcall uses the concept of a homogenous vector aggregate, similar
|
||||
// to other targets.
|
||||
const Type *Base = nullptr;
|
||||
uint64_t NumElts = 0;
|
||||
if ((State.CC == llvm::CallingConv::X86_VectorCall ||
|
||||
State.CC == llvm::CallingConv::X86_RegCall) &&
|
||||
if (State.CC == llvm::CallingConv::X86_RegCall &&
|
||||
isHomogeneousAggregate(Ty, Base, NumElts)) {
|
||||
|
||||
if (State.CC == llvm::CallingConv::X86_RegCall) {
|
||||
if (State.FreeSSERegs >= NumElts) {
|
||||
State.FreeSSERegs -= NumElts;
|
||||
if (Ty->isBuiltinType() || Ty->isVectorType())
|
||||
return ABIArgInfo::getDirect();
|
||||
return ABIArgInfo::getExpand();
|
||||
|
||||
}
|
||||
return getIndirectResult(Ty, /*ByVal=*/false, State);
|
||||
} else if (State.CC == llvm::CallingConv::X86_VectorCall) {
|
||||
if (State.FreeSSERegs >= NumElts && (Ty->isBuiltinType() || Ty->isVectorType())) {
|
||||
// Actual floating-point types get registers first time through if
|
||||
// there is registers available
|
||||
State.FreeSSERegs -= NumElts;
|
||||
if (State.FreeSSERegs >= NumElts) {
|
||||
State.FreeSSERegs -= NumElts;
|
||||
if (Ty->isBuiltinType() || Ty->isVectorType())
|
||||
return ABIArgInfo::getDirect();
|
||||
} else if (!Ty->isBuiltinType() && !Ty->isVectorType()) {
|
||||
// HVA Types only get registers after everything else has been
|
||||
// set, so it gets set as indirect for now.
|
||||
return ABIArgInfo::getIndirect(getContext().getTypeAlignInChars(Ty));
|
||||
}
|
||||
return ABIArgInfo::getExpand();
|
||||
}
|
||||
return getIndirectResult(Ty, /*ByVal=*/false, State);
|
||||
}
|
||||
|
||||
if (isAggregateTypeForABI(Ty)) {
|
||||
@ -1684,31 +1647,53 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
|
||||
|
||||
void X86_32ABIInfo::computeVectorCallArgs(CGFunctionInfo &FI, CCState &State,
|
||||
bool &UsedInAlloca) const {
|
||||
// Vectorcall only allows the first 6 parameters to be passed in registers,
|
||||
// and homogeneous vector aggregates are only put into registers as a second
|
||||
// priority.
|
||||
unsigned Count = 0;
|
||||
CCState ZeroState = State;
|
||||
ZeroState.FreeRegs = ZeroState.FreeSSERegs = 0;
|
||||
// HVAs must be done as a second priority for registers, so the deferred
|
||||
// items are dealt with by going through the pattern a second time.
|
||||
// Vectorcall x86 works subtly different than in x64, so the format is
|
||||
// a bit different than the x64 version. First, all vector types (not HVAs)
|
||||
// are assigned, with the first 6 ending up in the YMM0-5 or XMM0-5 registers.
|
||||
// This differs from the x64 implementation, where the first 6 by INDEX get
|
||||
// registers.
|
||||
// After that, integers AND HVAs are assigned Left to Right in the same pass.
|
||||
// Integers are passed as ECX/EDX if one is available (in order). HVAs will
|
||||
// first take up the remaining YMM/XMM registers. If insufficient registers
|
||||
// remain but an integer register (ECX/EDX) is available, it will be passed
|
||||
// in that, else, on the stack.
|
||||
for (auto &I : FI.arguments()) {
|
||||
if (Count < VectorcallMaxParamNumAsReg)
|
||||
I.info = classifyArgumentType(I.type, State);
|
||||
else
|
||||
// Parameters after the 6th cannot be passed in registers,
|
||||
// so pretend there are no registers left for them.
|
||||
I.info = classifyArgumentType(I.type, ZeroState);
|
||||
UsedInAlloca |= (I.info.getKind() == ABIArgInfo::InAlloca);
|
||||
++Count;
|
||||
// First pass do all the vector types.
|
||||
const Type *Base = nullptr;
|
||||
uint64_t NumElts = 0;
|
||||
const QualType& Ty = I.type;
|
||||
if ((Ty->isVectorType() || Ty->isBuiltinType()) &&
|
||||
isHomogeneousAggregate(Ty, Base, NumElts)) {
|
||||
if (State.FreeSSERegs >= NumElts) {
|
||||
State.FreeSSERegs -= NumElts;
|
||||
I.info = ABIArgInfo::getDirect();
|
||||
} else {
|
||||
I.info = classifyArgumentType(Ty, State);
|
||||
}
|
||||
UsedInAlloca |= (I.info.getKind() == ABIArgInfo::InAlloca);
|
||||
}
|
||||
}
|
||||
Count = 0;
|
||||
// Go through the arguments a second time to get HVAs registers if there
|
||||
// are still some available.
|
||||
|
||||
for (auto &I : FI.arguments()) {
|
||||
if (Count < VectorcallMaxParamNumAsReg)
|
||||
I.info = reclassifyHvaArgType(I.type, State, I.info);
|
||||
++Count;
|
||||
// Second pass, do the rest!
|
||||
const Type *Base = nullptr;
|
||||
uint64_t NumElts = 0;
|
||||
const QualType& Ty = I.type;
|
||||
bool IsHva = isHomogeneousAggregate(Ty, Base, NumElts);
|
||||
|
||||
if (IsHva && !Ty->isVectorType() && !Ty->isBuiltinType()) {
|
||||
// Assign true HVAs (non vector/native FP types).
|
||||
if (State.FreeSSERegs >= NumElts) {
|
||||
State.FreeSSERegs -= NumElts;
|
||||
I.info = getDirectX86Hva();
|
||||
} else {
|
||||
I.info = getIndirectResult(Ty, /*ByVal=*/false, State);
|
||||
}
|
||||
} else if (!IsHva) {
|
||||
// Assign all Non-HVAs, so this will exclude Vector/FP args.
|
||||
I.info = classifyArgumentType(Ty, State);
|
||||
UsedInAlloca |= (I.info.getKind() == ABIArgInfo::InAlloca);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3901,6 +3886,8 @@ void WinX86_64ABIInfo::computeVectorCallArgs(CGFunctionInfo &FI,
|
||||
bool IsRegCall) const {
|
||||
unsigned Count = 0;
|
||||
for (auto &I : FI.arguments()) {
|
||||
// Vectorcall in x64 only permits the first 6 arguments to be passed
|
||||
// as XMM/YMM registers.
|
||||
if (Count < VectorcallMaxParamNumAsReg)
|
||||
I.info = classify(I.type, FreeSSERegs, false, IsVectorCall, IsRegCall);
|
||||
else {
|
||||
@ -3913,11 +3900,8 @@ void WinX86_64ABIInfo::computeVectorCallArgs(CGFunctionInfo &FI,
|
||||
++Count;
|
||||
}
|
||||
|
||||
Count = 0;
|
||||
for (auto &I : FI.arguments()) {
|
||||
if (Count < VectorcallMaxParamNumAsReg)
|
||||
I.info = reclassifyHvaArgType(I.type, FreeSSERegs, I.info);
|
||||
++Count;
|
||||
I.info = reclassifyHvaArgType(I.type, FreeSSERegs, I.info);
|
||||
}
|
||||
}
|
||||
|
||||
@ -7344,8 +7328,6 @@ class AMDGPUTargetCodeGenInfo : public TargetCodeGenInfo {
|
||||
};
|
||||
}
|
||||
|
||||
static void appendOpenCLVersionMD (CodeGen::CodeGenModule &CGM);
|
||||
|
||||
void AMDGPUTargetCodeGenInfo::setTargetAttributes(
|
||||
const Decl *D,
|
||||
llvm::GlobalValue *GV,
|
||||
@ -7402,8 +7384,6 @@ void AMDGPUTargetCodeGenInfo::setTargetAttributes(
|
||||
if (NumVGPR != 0)
|
||||
F->addFnAttr("amdgpu-num-vgpr", llvm::utostr(NumVGPR));
|
||||
}
|
||||
|
||||
appendOpenCLVersionMD(M);
|
||||
}
|
||||
|
||||
unsigned AMDGPUTargetCodeGenInfo::getOpenCLKernelCallingConv() const {
|
||||
@ -8074,8 +8054,6 @@ class SPIRTargetCodeGenInfo : public TargetCodeGenInfo {
|
||||
public:
|
||||
SPIRTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
|
||||
: TargetCodeGenInfo(new DefaultABIInfo(CGT)) {}
|
||||
void emitTargetMD(const Decl *D, llvm::GlobalValue *GV,
|
||||
CodeGen::CodeGenModule &M) const override;
|
||||
unsigned getOpenCLKernelCallingConv() const override;
|
||||
};
|
||||
|
||||
@ -8090,41 +8068,6 @@ void computeSPIRKernelABIInfo(CodeGenModule &CGM, CGFunctionInfo &FI) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Emit SPIR specific metadata: OpenCL and SPIR version.
|
||||
void SPIRTargetCodeGenInfo::emitTargetMD(const Decl *D, llvm::GlobalValue *GV,
|
||||
CodeGen::CodeGenModule &CGM) const {
|
||||
llvm::LLVMContext &Ctx = CGM.getModule().getContext();
|
||||
llvm::Type *Int32Ty = llvm::Type::getInt32Ty(Ctx);
|
||||
llvm::Module &M = CGM.getModule();
|
||||
// SPIR v2.0 s2.12 - The SPIR version used by the module is stored in the
|
||||
// opencl.spir.version named metadata.
|
||||
llvm::Metadata *SPIRVerElts[] = {
|
||||
llvm::ConstantAsMetadata::get(
|
||||
llvm::ConstantInt::get(Int32Ty, CGM.getLangOpts().OpenCLVersion / 100)),
|
||||
llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
|
||||
Int32Ty, (CGM.getLangOpts().OpenCLVersion / 100 > 1) ? 0 : 2))};
|
||||
llvm::NamedMDNode *SPIRVerMD =
|
||||
M.getOrInsertNamedMetadata("opencl.spir.version");
|
||||
SPIRVerMD->addOperand(llvm::MDNode::get(Ctx, SPIRVerElts));
|
||||
appendOpenCLVersionMD(CGM);
|
||||
}
|
||||
|
||||
static void appendOpenCLVersionMD(CodeGen::CodeGenModule &CGM) {
|
||||
llvm::LLVMContext &Ctx = CGM.getModule().getContext();
|
||||
llvm::Type *Int32Ty = llvm::Type::getInt32Ty(Ctx);
|
||||
llvm::Module &M = CGM.getModule();
|
||||
// SPIR v2.0 s2.13 - The OpenCL version used by the module is stored in the
|
||||
// opencl.ocl.version named metadata node.
|
||||
llvm::Metadata *OCLVerElts[] = {
|
||||
llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
|
||||
Int32Ty, CGM.getLangOpts().OpenCLVersion / 100)),
|
||||
llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
|
||||
Int32Ty, (CGM.getLangOpts().OpenCLVersion % 100) / 10))};
|
||||
llvm::NamedMDNode *OCLVerMD =
|
||||
M.getOrInsertNamedMetadata("opencl.ocl.version");
|
||||
OCLVerMD->addOperand(llvm::MDNode::get(Ctx, OCLVerElts));
|
||||
}
|
||||
|
||||
unsigned SPIRTargetCodeGenInfo::getOpenCLKernelCallingConv() const {
|
||||
return llvm::CallingConv::SPIR_KERNEL;
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ add_clang_library(clangDriver
|
||||
ToolChains/Arch/Sparc.cpp
|
||||
ToolChains/Arch/SystemZ.cpp
|
||||
ToolChains/Arch/X86.cpp
|
||||
ToolChains/Ananas.cpp
|
||||
ToolChains/AMDGPU.cpp
|
||||
ToolChains/AVR.cpp
|
||||
ToolChains/Bitrig.cpp
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "InputInfo.h"
|
||||
#include "ToolChains/AMDGPU.h"
|
||||
#include "ToolChains/AVR.h"
|
||||
#include "ToolChains/Ananas.h"
|
||||
#include "ToolChains/Bitrig.h"
|
||||
#include "ToolChains/Clang.h"
|
||||
#include "ToolChains/CloudABI.h"
|
||||
@ -1227,7 +1228,32 @@ bool Driver::HandleImmediateArgs(const Compilation &C) {
|
||||
if (Arg *A = C.getArgs().getLastArg(options::OPT_autocomplete)) {
|
||||
// Print out all options that start with a given argument. This is used for
|
||||
// shell autocompletion.
|
||||
llvm::outs() << llvm::join(Opts->findByPrefix(A->getValue()), " ") << '\n';
|
||||
StringRef PassedFlags = A->getValue();
|
||||
std::vector<std::string> SuggestedCompletions;
|
||||
|
||||
if (PassedFlags.find(',') == StringRef::npos) {
|
||||
// If the flag is in the form of "--autocomplete=-foo",
|
||||
// we were requested to print out all option names that start with "-foo".
|
||||
// For example, "--autocomplete=-fsyn" is expanded to "-fsyntax-only".
|
||||
SuggestedCompletions = Opts->findByPrefix(PassedFlags);
|
||||
} else {
|
||||
// If the flag is in the form of "--autocomplete=foo,bar", we were
|
||||
// requested to print out all option values for "-foo" that start with
|
||||
// "bar". For example,
|
||||
// "--autocomplete=-stdlib=,l" is expanded to "libc++" and "libstdc++".
|
||||
StringRef Option, Arg;
|
||||
std::tie(Option, Arg) = PassedFlags.split(',');
|
||||
SuggestedCompletions = Opts->suggestValueCompletions(Option, Arg);
|
||||
}
|
||||
|
||||
// Sort the autocomplete candidates so that shells print them out in a
|
||||
// deterministic order. We could sort in any way, but we chose
|
||||
// case-insensitive sorting for consistency with the -help option
|
||||
// which prints out options in the case-insensitive alphabetical order.
|
||||
std::sort(SuggestedCompletions.begin(), SuggestedCompletions.end(),
|
||||
[](StringRef A, StringRef B) { return A.compare_lower(B) < 0; });
|
||||
|
||||
llvm::outs() << llvm::join(SuggestedCompletions, " ") << '\n';
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -3724,6 +3750,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
|
||||
case llvm::Triple::Haiku:
|
||||
TC = llvm::make_unique<toolchains::Haiku>(*this, Target, Args);
|
||||
break;
|
||||
case llvm::Triple::Ananas:
|
||||
TC = llvm::make_unique<toolchains::Ananas>(*this, Target, Args);
|
||||
break;
|
||||
case llvm::Triple::CloudABI:
|
||||
TC = llvm::make_unique<toolchains::CloudABI>(*this, Target, Args);
|
||||
break;
|
||||
|
@ -21,10 +21,10 @@ using namespace llvm::opt;
|
||||
#undef PREFIX
|
||||
|
||||
static const OptTable::Info InfoTable[] = {
|
||||
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
|
||||
HELPTEXT, METAVAR) \
|
||||
{ PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, PARAM, \
|
||||
FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS },
|
||||
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
|
||||
HELPTEXT, METAVAR, VALUES) \
|
||||
{PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, \
|
||||
PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS, VALUES},
|
||||
#include "clang/Driver/Options.inc"
|
||||
#undef OPTION
|
||||
};
|
||||
|
@ -208,12 +208,28 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
|
||||
SanitizerMask TrappingKinds = parseSanitizeTrapArgs(D, Args);
|
||||
SanitizerMask InvalidTrappingKinds = TrappingKinds & NotAllowedWithTrap;
|
||||
|
||||
// The object size sanitizer should not be enabled at -O0.
|
||||
Arg *OptLevel = Args.getLastArg(options::OPT_O_Group);
|
||||
bool RemoveObjectSizeAtO0 =
|
||||
!OptLevel || OptLevel->getOption().matches(options::OPT_O0);
|
||||
|
||||
for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend();
|
||||
I != E; ++I) {
|
||||
const auto *Arg = *I;
|
||||
if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) {
|
||||
Arg->claim();
|
||||
SanitizerMask Add = parseArgValues(D, Arg, true);
|
||||
SanitizerMask Add = parseArgValues(D, Arg, /*AllowGroups=*/true);
|
||||
|
||||
if (RemoveObjectSizeAtO0) {
|
||||
AllRemove |= SanitizerKind::ObjectSize;
|
||||
|
||||
// The user explicitly enabled the object size sanitizer. Warn that
|
||||
// that this does nothing at -O0.
|
||||
if (Add & SanitizerKind::ObjectSize)
|
||||
D.Diag(diag::warn_drv_object_size_disabled_O0)
|
||||
<< Arg->getAsString(Args);
|
||||
}
|
||||
|
||||
AllAddedKinds |= expandSanitizerGroups(Add);
|
||||
|
||||
// Avoid diagnosing any sanitizer which is disabled later.
|
||||
|
120
lib/Driver/ToolChains/Ananas.cpp
Normal file
120
lib/Driver/ToolChains/Ananas.cpp
Normal file
@ -0,0 +1,120 @@
|
||||
//===--- Ananas.cpp - Ananas ToolChain Implementations ------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Ananas.h"
|
||||
#include "InputInfo.h"
|
||||
#include "CommonArgs.h"
|
||||
#include "clang/Config/config.h"
|
||||
#include "clang/Driver/Compilation.h"
|
||||
#include "clang/Driver/Driver.h"
|
||||
#include "clang/Driver/Options.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/Option/ArgList.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
|
||||
using namespace clang::driver;
|
||||
using namespace clang::driver::tools;
|
||||
using namespace clang::driver::toolchains;
|
||||
using namespace clang;
|
||||
using namespace llvm::opt;
|
||||
|
||||
void ananas::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
const InputInfo &Output,
|
||||
const InputInfoList &Inputs,
|
||||
const ArgList &Args,
|
||||
const char *LinkingOutput) const {
|
||||
claimNoWarnArgs(Args);
|
||||
ArgStringList CmdArgs;
|
||||
|
||||
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
|
||||
|
||||
CmdArgs.push_back("-o");
|
||||
CmdArgs.push_back(Output.getFilename());
|
||||
|
||||
for (const auto &II : Inputs)
|
||||
CmdArgs.push_back(II.getFilename());
|
||||
|
||||
const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
|
||||
C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
|
||||
}
|
||||
|
||||
void ananas::Linker::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
const InputInfo &Output,
|
||||
const InputInfoList &Inputs,
|
||||
const ArgList &Args,
|
||||
const char *LinkingOutput) const {
|
||||
const ToolChain &ToolChain = getToolChain();
|
||||
const Driver &D = ToolChain.getDriver();
|
||||
ArgStringList CmdArgs;
|
||||
|
||||
// Silence warning for "clang -g foo.o -o foo"
|
||||
Args.ClaimAllArgs(options::OPT_g_Group);
|
||||
// and "clang -emit-llvm foo.o -o foo"
|
||||
Args.ClaimAllArgs(options::OPT_emit_llvm);
|
||||
// and for "clang -w foo.o -o foo". Other warning options are already
|
||||
// handled somewhere else.
|
||||
Args.ClaimAllArgs(options::OPT_w);
|
||||
|
||||
if (!D.SysRoot.empty())
|
||||
CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
|
||||
|
||||
// Ananas only supports static linkage for now.
|
||||
CmdArgs.push_back("-Bstatic");
|
||||
|
||||
if (Output.isFilename()) {
|
||||
CmdArgs.push_back("-o");
|
||||
CmdArgs.push_back(Output.getFilename());
|
||||
} else {
|
||||
assert(Output.isNothing() && "Invalid output.");
|
||||
}
|
||||
|
||||
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
|
||||
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o")));
|
||||
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
|
||||
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o")));
|
||||
}
|
||||
|
||||
Args.AddAllArgs(CmdArgs, options::OPT_L);
|
||||
ToolChain.AddFilePathLibArgs(Args, CmdArgs);
|
||||
Args.AddAllArgs(CmdArgs,
|
||||
{options::OPT_T_Group, options::OPT_e, options::OPT_s,
|
||||
options::OPT_t, options::OPT_Z_Flag, options::OPT_r});
|
||||
|
||||
if (D.isUsingLTO())
|
||||
AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin, D);
|
||||
|
||||
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
|
||||
|
||||
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
|
||||
if (D.CCCIsCXX())
|
||||
ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
|
||||
CmdArgs.push_back("-lc");
|
||||
}
|
||||
|
||||
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
|
||||
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o")));
|
||||
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
|
||||
}
|
||||
|
||||
const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
|
||||
C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
|
||||
}
|
||||
|
||||
// Ananas - Ananas tool chain which can call as(1) and ld(1) directly.
|
||||
|
||||
Ananas::Ananas(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
|
||||
: Generic_ELF(D, Triple, Args) {
|
||||
getFilePaths().push_back(getDriver().SysRoot + "/usr/lib");
|
||||
}
|
||||
|
||||
Tool *Ananas::buildAssembler() const {
|
||||
return new tools::ananas::Assembler(*this);
|
||||
}
|
||||
|
||||
Tool *Ananas::buildLinker() const { return new tools::ananas::Linker(*this); }
|
67
lib/Driver/ToolChains/Ananas.h
Normal file
67
lib/Driver/ToolChains/Ananas.h
Normal file
@ -0,0 +1,67 @@
|
||||
//===--- Ananas.h - Ananas ToolChain Implementations --------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ANANAS_H
|
||||
#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ANANAS_H
|
||||
|
||||
#include "Gnu.h"
|
||||
#include "clang/Driver/Tool.h"
|
||||
#include "clang/Driver/ToolChain.h"
|
||||
|
||||
namespace clang {
|
||||
namespace driver {
|
||||
namespace tools {
|
||||
|
||||
/// ananas -- Directly call GNU Binutils assembler and linker
|
||||
namespace ananas {
|
||||
class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool {
|
||||
public:
|
||||
Assembler(const ToolChain &TC)
|
||||
: GnuTool("ananas::Assembler", "assembler", TC) {}
|
||||
|
||||
bool hasIntegratedCPP() const override { return false; }
|
||||
|
||||
void ConstructJob(Compilation &C, const JobAction &JA,
|
||||
const InputInfo &Output, const InputInfoList &Inputs,
|
||||
const llvm::opt::ArgList &TCArgs,
|
||||
const char *LinkingOutput) const override;
|
||||
};
|
||||
|
||||
class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
|
||||
public:
|
||||
Linker(const ToolChain &TC) : GnuTool("ananas::Linker", "linker", TC) {}
|
||||
|
||||
bool hasIntegratedCPP() const override { return false; }
|
||||
bool isLinkJob() const override { return true; }
|
||||
|
||||
void ConstructJob(Compilation &C, const JobAction &JA,
|
||||
const InputInfo &Output, const InputInfoList &Inputs,
|
||||
const llvm::opt::ArgList &TCArgs,
|
||||
const char *LinkingOutput) const override;
|
||||
};
|
||||
} // end namespace ananas
|
||||
} // end namespace tools
|
||||
|
||||
namespace toolchains {
|
||||
|
||||
class LLVM_LIBRARY_VISIBILITY Ananas : public Generic_ELF {
|
||||
public:
|
||||
Ananas(const Driver &D, const llvm::Triple &Triple,
|
||||
const llvm::opt::ArgList &Args);
|
||||
|
||||
protected:
|
||||
Tool *buildAssembler() const override;
|
||||
Tool *buildLinker() const override;
|
||||
};
|
||||
|
||||
} // end namespace toolchains
|
||||
} // end namespace driver
|
||||
} // end namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ANANAS_H
|
@ -910,6 +910,37 @@ static void RenderDebugEnablingArgs(const ArgList &Args, ArgStringList &CmdArgs,
|
||||
}
|
||||
}
|
||||
|
||||
static void RenderDebugInfoCompressionArgs(const ArgList &Args,
|
||||
ArgStringList &CmdArgs,
|
||||
const Driver &D) {
|
||||
const Arg *A = Args.getLastArg(options::OPT_gz, options::OPT_gz_EQ);
|
||||
if (!A)
|
||||
return;
|
||||
|
||||
if (A->getOption().getID() == options::OPT_gz) {
|
||||
if (llvm::zlib::isAvailable())
|
||||
CmdArgs.push_back("-compress-debug-sections");
|
||||
else
|
||||
D.Diag(diag::warn_debug_compression_unavailable);
|
||||
return;
|
||||
}
|
||||
|
||||
StringRef Value = A->getValue();
|
||||
if (Value == "none") {
|
||||
CmdArgs.push_back("-compress-debug-sections=none");
|
||||
} else if (Value == "zlib" || Value == "zlib-gnu") {
|
||||
if (llvm::zlib::isAvailable()) {
|
||||
CmdArgs.push_back(
|
||||
Args.MakeArgString("-compress-debug-sections=" + Twine(Value)));
|
||||
} else {
|
||||
D.Diag(diag::warn_debug_compression_unavailable);
|
||||
}
|
||||
} else {
|
||||
D.Diag(diag::err_drv_unsupported_option_argument)
|
||||
<< A->getOption().getName() << Value;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *RelocationModelName(llvm::Reloc::Model Model) {
|
||||
switch (Model) {
|
||||
case llvm::Reloc::Static:
|
||||
@ -1747,10 +1778,6 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
|
||||
// arg after parsing the '-I' arg.
|
||||
bool TakeNextArg = false;
|
||||
|
||||
// When using an integrated assembler, translate -Wa, and -Xassembler
|
||||
// options.
|
||||
bool CompressDebugSections = false;
|
||||
|
||||
bool UseRelaxRelocations = ENABLE_X86_RELAX_RELOCATIONS;
|
||||
const char *MipsTargetFeature = nullptr;
|
||||
for (const Arg *A :
|
||||
@ -1825,12 +1852,11 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
|
||||
CmdArgs.push_back("-massembler-fatal-warnings");
|
||||
} else if (Value == "--noexecstack") {
|
||||
CmdArgs.push_back("-mnoexecstack");
|
||||
} else if (Value == "-compress-debug-sections" ||
|
||||
Value == "--compress-debug-sections") {
|
||||
CompressDebugSections = true;
|
||||
} else if (Value == "-nocompress-debug-sections" ||
|
||||
} else if (Value.startswith("-compress-debug-sections") ||
|
||||
Value.startswith("--compress-debug-sections") ||
|
||||
Value == "-nocompress-debug-sections" ||
|
||||
Value == "--nocompress-debug-sections") {
|
||||
CompressDebugSections = false;
|
||||
CmdArgs.push_back(Value.data());
|
||||
} else if (Value == "-mrelax-relocations=yes" ||
|
||||
Value == "--mrelax-relocations=yes") {
|
||||
UseRelaxRelocations = true;
|
||||
@ -1883,12 +1909,6 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
|
||||
}
|
||||
}
|
||||
}
|
||||
if (CompressDebugSections) {
|
||||
if (llvm::zlib::isAvailable())
|
||||
CmdArgs.push_back("-compress-debug-sections");
|
||||
else
|
||||
D.Diag(diag::warn_debug_compression_unavailable);
|
||||
}
|
||||
if (UseRelaxRelocations)
|
||||
CmdArgs.push_back("--mrelax-relocations");
|
||||
if (MipsTargetFeature != nullptr) {
|
||||
@ -2824,6 +2844,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
CmdArgs.push_back("-generate-type-units");
|
||||
}
|
||||
|
||||
RenderDebugInfoCompressionArgs(Args, CmdArgs, D);
|
||||
|
||||
bool UseSeparateSections = isUseSeparateSections(Triple);
|
||||
|
||||
if (Args.hasFlag(options::OPT_ffunction_sections,
|
||||
@ -4927,6 +4949,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
|
||||
const llvm::Triple &Triple = getToolChain().getEffectiveTriple();
|
||||
const std::string &TripleStr = Triple.getTriple();
|
||||
const auto &D = getToolChain().getDriver();
|
||||
|
||||
// Don't warn about "clang -w -c foo.s"
|
||||
Args.ClaimAllArgs(options::OPT_w);
|
||||
@ -5014,6 +5037,8 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
}
|
||||
RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DwarfVersion,
|
||||
llvm::DebuggerKind::Default);
|
||||
RenderDebugInfoCompressionArgs(Args, CmdArgs, D);
|
||||
|
||||
|
||||
// Handle -fPIC et al -- the relocation-model affects the assembler
|
||||
// for some targets.
|
||||
|
@ -650,6 +650,8 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C,
|
||||
const InputInfoList &Inputs,
|
||||
const ArgList &Args,
|
||||
const char *LinkingOutput) const {
|
||||
const auto &D = getToolChain().getDriver();
|
||||
|
||||
claimNoWarnArgs(Args);
|
||||
|
||||
ArgStringList CmdArgs;
|
||||
@ -660,6 +662,23 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C,
|
||||
std::tie(RelocationModel, PICLevel, IsPIE) =
|
||||
ParsePICArgs(getToolChain(), Args);
|
||||
|
||||
if (const Arg *A = Args.getLastArg(options::OPT_gz, options::OPT_gz_EQ)) {
|
||||
if (A->getOption().getID() == options::OPT_gz) {
|
||||
CmdArgs.push_back("-compress-debug-sections");
|
||||
} else {
|
||||
StringRef Value = A->getValue();
|
||||
if (Value == "none") {
|
||||
CmdArgs.push_back("-compress-debug-sections=none");
|
||||
} else if (Value == "zlib" || Value == "zlib-gnu") {
|
||||
CmdArgs.push_back(
|
||||
Args.MakeArgString("-compress-debug-sections=" + Twine(Value)));
|
||||
} else {
|
||||
D.Diag(diag::err_drv_unsupported_option_argument)
|
||||
<< A->getOption().getName() << Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (getToolChain().getArch()) {
|
||||
default:
|
||||
break;
|
||||
@ -2319,9 +2338,11 @@ bool Generic_GCC::IsIntegratedAssemblerDefault() const {
|
||||
return true;
|
||||
case llvm::Triple::mips64:
|
||||
case llvm::Triple::mips64el:
|
||||
// Enabled for Debian mips64/mips64el only. Other targets are unable to
|
||||
// distinguish N32 from N64.
|
||||
if (getTriple().getEnvironment() == llvm::Triple::GNUABI64)
|
||||
// Enabled for Debian and Android mips64/mipsel, as they can precisely
|
||||
// identify the ABI in use (Debian) or only use N64 for MIPS64 (Android).
|
||||
// Other targets are unable to distinguish N32 from N64.
|
||||
if (getTriple().getEnvironment() == llvm::Triple::GNUABI64 ||
|
||||
getTriple().isAndroid())
|
||||
return true;
|
||||
return false;
|
||||
default:
|
||||
|
@ -83,6 +83,8 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
if (Args.hasArg(options::OPT_pthread))
|
||||
CmdArgs.push_back("-lpthread");
|
||||
|
||||
CmdArgs.push_back("-allow-undefined-file");
|
||||
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("wasm.syms")));
|
||||
CmdArgs.push_back("-lc");
|
||||
CmdArgs.push_back("-lcompiler_rt");
|
||||
}
|
||||
@ -104,8 +106,7 @@ WebAssembly::WebAssembly(const Driver &D, const llvm::Triple &Triple,
|
||||
|
||||
getProgramPaths().push_back(getDriver().getInstalledDir());
|
||||
|
||||
getFilePaths().push_back(
|
||||
getDriver().SysRoot + "/lib" + (Triple.isArch32Bit() ? "32" : "64"));
|
||||
getFilePaths().push_back(getDriver().SysRoot + "/lib");
|
||||
}
|
||||
|
||||
bool WebAssembly::IsMathErrnoDefault() const { return false; }
|
||||
|
@ -28,13 +28,18 @@ void EditedSource::deconstructMacroArgLoc(SourceLocation Loc,
|
||||
MacroArgUse &ArgUse) {
|
||||
assert(SourceMgr.isMacroArgExpansion(Loc));
|
||||
SourceLocation DefArgLoc = SourceMgr.getImmediateExpansionRange(Loc).first;
|
||||
ExpansionLoc = SourceMgr.getImmediateExpansionRange(DefArgLoc).first;
|
||||
SourceLocation ImmediateExpansionLoc =
|
||||
SourceMgr.getImmediateExpansionRange(DefArgLoc).first;
|
||||
ExpansionLoc = ImmediateExpansionLoc;
|
||||
while (SourceMgr.isMacroBodyExpansion(ExpansionLoc))
|
||||
ExpansionLoc = SourceMgr.getImmediateExpansionRange(ExpansionLoc).first;
|
||||
SmallString<20> Buf;
|
||||
StringRef ArgName = Lexer::getSpelling(SourceMgr.getSpellingLoc(DefArgLoc),
|
||||
Buf, SourceMgr, LangOpts);
|
||||
ArgUse = {nullptr, SourceLocation()};
|
||||
ArgUse = MacroArgUse{nullptr, SourceLocation(), SourceLocation()};
|
||||
if (!ArgName.empty())
|
||||
ArgUse = {&IdentTable.get(ArgName), SourceMgr.getSpellingLoc(DefArgLoc)};
|
||||
ArgUse = {&IdentTable.get(ArgName), ImmediateExpansionLoc,
|
||||
SourceMgr.getSpellingLoc(DefArgLoc)};
|
||||
}
|
||||
|
||||
void EditedSource::startingCommit() {}
|
||||
@ -69,10 +74,11 @@ bool EditedSource::canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs) {
|
||||
deconstructMacroArgLoc(OrigLoc, ExpLoc, ArgUse);
|
||||
auto I = ExpansionToArgMap.find(ExpLoc.getRawEncoding());
|
||||
if (I != ExpansionToArgMap.end() &&
|
||||
std::find_if(
|
||||
I->second.begin(), I->second.end(), [&](const MacroArgUse &U) {
|
||||
return ArgUse.first == U.first && ArgUse.second != U.second;
|
||||
}) != I->second.end()) {
|
||||
find_if(I->second, [&](const MacroArgUse &U) {
|
||||
return ArgUse.Identifier == U.Identifier &&
|
||||
std::tie(ArgUse.ImmediateExpansionLoc, ArgUse.UseLoc) !=
|
||||
std::tie(U.ImmediateExpansionLoc, U.UseLoc);
|
||||
}) != I->second.end()) {
|
||||
// Trying to write in a macro argument input that has already been
|
||||
// written by a previous commit for another expansion of the same macro
|
||||
// argument name. For example:
|
||||
@ -89,7 +95,6 @@ bool EditedSource::canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -102,13 +107,13 @@ bool EditedSource::commitInsert(SourceLocation OrigLoc,
|
||||
return true;
|
||||
|
||||
if (SourceMgr.isMacroArgExpansion(OrigLoc)) {
|
||||
SourceLocation ExpLoc;
|
||||
MacroArgUse ArgUse;
|
||||
SourceLocation ExpLoc;
|
||||
deconstructMacroArgLoc(OrigLoc, ExpLoc, ArgUse);
|
||||
if (ArgUse.first)
|
||||
if (ArgUse.Identifier)
|
||||
CurrCommitMacroArgExps.emplace_back(ExpLoc, ArgUse);
|
||||
}
|
||||
|
||||
|
||||
FileEdit &FA = FileEdits[Offs];
|
||||
if (FA.Text.empty()) {
|
||||
FA.Text = copyString(text);
|
||||
|
@ -13,6 +13,7 @@ add_clang_library(clangFormat
|
||||
TokenAnnotator.cpp
|
||||
UnwrappedLineFormatter.cpp
|
||||
UnwrappedLineParser.cpp
|
||||
UsingDeclarationsSorter.cpp
|
||||
WhitespaceManager.cpp
|
||||
|
||||
LINK_LIBS
|
||||
|
@ -453,7 +453,8 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
|
||||
State.Column += Spaces;
|
||||
if (Current.isNot(tok::comment) && Previous.is(tok::l_paren) &&
|
||||
Previous.Previous &&
|
||||
Previous.Previous->isOneOf(tok::kw_if, tok::kw_for)) {
|
||||
(Previous.Previous->isOneOf(tok::kw_if, tok::kw_for) ||
|
||||
Previous.Previous->endsSequence(tok::kw_constexpr, tok::kw_if))) {
|
||||
// Treat the condition inside an if as if it was a second function
|
||||
// parameter, i.e. let nested calls have a continuation indent.
|
||||
State.Stack.back().LastSpace = State.Column;
|
||||
@ -1049,7 +1050,9 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State,
|
||||
(Current.is(TT_ArrayInitializerLSquare) && EndsInComma) ||
|
||||
Current.is(TT_DictLiteral) ||
|
||||
Style.Language == FormatStyle::LK_Proto || !Style.BinPackArguments ||
|
||||
(NextNoComment && NextNoComment->is(TT_DesignatedInitializerPeriod));
|
||||
(NextNoComment &&
|
||||
NextNoComment->isOneOf(TT_DesignatedInitializerPeriod,
|
||||
TT_DesignatedInitializerLSquare));
|
||||
if (Current.ParameterCount > 1)
|
||||
NestedBlockIndent = std::max(NestedBlockIndent, State.Column + 1);
|
||||
} else {
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "TokenAnnotator.h"
|
||||
#include "UnwrappedLineFormatter.h"
|
||||
#include "UnwrappedLineParser.h"
|
||||
#include "UsingDeclarationsSorter.h"
|
||||
#include "WhitespaceManager.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/DiagnosticOptions.h"
|
||||
@ -96,6 +97,7 @@ template <> struct ScalarEnumerationTraits<FormatStyle::ShortFunctionStyle> {
|
||||
IO.enumCase(Value, "All", FormatStyle::SFS_All);
|
||||
IO.enumCase(Value, "true", FormatStyle::SFS_All);
|
||||
IO.enumCase(Value, "Inline", FormatStyle::SFS_Inline);
|
||||
IO.enumCase(Value, "InlineOnly", FormatStyle::SFS_InlineOnly);
|
||||
IO.enumCase(Value, "Empty", FormatStyle::SFS_Empty);
|
||||
}
|
||||
};
|
||||
@ -377,6 +379,7 @@ template <> struct MappingTraits<FormatStyle> {
|
||||
IO.mapOptional("PointerAlignment", Style.PointerAlignment);
|
||||
IO.mapOptional("ReflowComments", Style.ReflowComments);
|
||||
IO.mapOptional("SortIncludes", Style.SortIncludes);
|
||||
IO.mapOptional("SortUsingDeclarations", Style.SortUsingDeclarations);
|
||||
IO.mapOptional("SpaceAfterCStyleCast", Style.SpaceAfterCStyleCast);
|
||||
IO.mapOptional("SpaceAfterTemplateKeyword", Style.SpaceAfterTemplateKeyword);
|
||||
IO.mapOptional("SpaceBeforeAssignmentOperators",
|
||||
@ -617,6 +620,7 @@ FormatStyle getLLVMStyle() {
|
||||
|
||||
LLVMStyle.DisableFormat = false;
|
||||
LLVMStyle.SortIncludes = true;
|
||||
LLVMStyle.SortUsingDeclarations = true;
|
||||
|
||||
return LLVMStyle;
|
||||
}
|
||||
@ -771,6 +775,7 @@ FormatStyle getNoStyle() {
|
||||
FormatStyle NoStyle = getLLVMStyle();
|
||||
NoStyle.DisableFormat = true;
|
||||
NoStyle.SortIncludes = false;
|
||||
NoStyle.SortUsingDeclarations = false;
|
||||
return NoStyle;
|
||||
}
|
||||
|
||||
@ -1877,38 +1882,53 @@ tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
|
||||
return tooling::Replacements();
|
||||
if (Expanded.Language == FormatStyle::LK_JavaScript && isMpegTS(Code))
|
||||
return tooling::Replacements();
|
||||
auto Env = Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
|
||||
|
||||
auto reformatAfterApplying = [&] (TokenAnalyzer& Fixer) {
|
||||
tooling::Replacements Fixes = Fixer.process();
|
||||
if (!Fixes.empty()) {
|
||||
auto NewCode = applyAllReplacements(Code, Fixes);
|
||||
if (NewCode) {
|
||||
auto NewEnv = Environment::CreateVirtualEnvironment(
|
||||
*NewCode, FileName,
|
||||
tooling::calculateRangesAfterReplacements(Fixes, Ranges));
|
||||
Formatter Format(*NewEnv, Expanded, Status);
|
||||
return Fixes.merge(Format.process());
|
||||
}
|
||||
}
|
||||
Formatter Format(*Env, Expanded, Status);
|
||||
return Format.process();
|
||||
};
|
||||
typedef std::function<tooling::Replacements(const Environment &)>
|
||||
AnalyzerPass;
|
||||
SmallVector<AnalyzerPass, 4> Passes;
|
||||
|
||||
if (Style.Language == FormatStyle::LK_Cpp &&
|
||||
Style.FixNamespaceComments) {
|
||||
NamespaceEndCommentsFixer CommentsFixer(*Env, Expanded);
|
||||
return reformatAfterApplying(CommentsFixer);
|
||||
if (Style.Language == FormatStyle::LK_Cpp) {
|
||||
if (Style.FixNamespaceComments)
|
||||
Passes.emplace_back([&](const Environment &Env) {
|
||||
return NamespaceEndCommentsFixer(Env, Expanded).process();
|
||||
});
|
||||
|
||||
if (Style.SortUsingDeclarations)
|
||||
Passes.emplace_back([&](const Environment &Env) {
|
||||
return UsingDeclarationsSorter(Env, Expanded).process();
|
||||
});
|
||||
}
|
||||
|
||||
if (Style.Language == FormatStyle::LK_JavaScript &&
|
||||
Style.JavaScriptQuotes != FormatStyle::JSQS_Leave) {
|
||||
JavaScriptRequoter Requoter(*Env, Expanded);
|
||||
return reformatAfterApplying(Requoter);
|
||||
Style.JavaScriptQuotes != FormatStyle::JSQS_Leave)
|
||||
Passes.emplace_back([&](const Environment &Env) {
|
||||
return JavaScriptRequoter(Env, Expanded).process();
|
||||
});
|
||||
|
||||
Passes.emplace_back([&](const Environment &Env) {
|
||||
return Formatter(Env, Expanded, Status).process();
|
||||
});
|
||||
|
||||
std::unique_ptr<Environment> Env =
|
||||
Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
|
||||
llvm::Optional<std::string> CurrentCode = None;
|
||||
tooling::Replacements Fixes;
|
||||
for (size_t I = 0, E = Passes.size(); I < E; ++I) {
|
||||
tooling::Replacements PassFixes = Passes[I](*Env);
|
||||
auto NewCode = applyAllReplacements(
|
||||
CurrentCode ? StringRef(*CurrentCode) : Code, PassFixes);
|
||||
if (NewCode) {
|
||||
Fixes = Fixes.merge(PassFixes);
|
||||
if (I + 1 < E) {
|
||||
CurrentCode = std::move(*NewCode);
|
||||
Env = Environment::CreateVirtualEnvironment(
|
||||
*CurrentCode, FileName,
|
||||
tooling::calculateRangesAfterReplacements(Fixes, Ranges));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Formatter Format(*Env, Expanded, Status);
|
||||
return Format.process();
|
||||
return Fixes;
|
||||
}
|
||||
|
||||
tooling::Replacements cleanup(const FormatStyle &Style, StringRef Code,
|
||||
@ -1943,6 +1963,16 @@ tooling::Replacements fixNamespaceEndComments(const FormatStyle &Style,
|
||||
return Fix.process();
|
||||
}
|
||||
|
||||
tooling::Replacements sortUsingDeclarations(const FormatStyle &Style,
|
||||
StringRef Code,
|
||||
ArrayRef<tooling::Range> Ranges,
|
||||
StringRef FileName) {
|
||||
std::unique_ptr<Environment> Env =
|
||||
Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
|
||||
UsingDeclarationsSorter Sorter(*Env, Style);
|
||||
return Sorter.process();
|
||||
}
|
||||
|
||||
LangOptions getFormattingLangOpts(const FormatStyle &Style) {
|
||||
LangOptions LangOpts;
|
||||
LangOpts.CPlusPlus = 1;
|
||||
|
@ -39,6 +39,7 @@ namespace format {
|
||||
TYPE(ConflictStart) \
|
||||
TYPE(CtorInitializerColon) \
|
||||
TYPE(CtorInitializerComma) \
|
||||
TYPE(DesignatedInitializerLSquare) \
|
||||
TYPE(DesignatedInitializerPeriod) \
|
||||
TYPE(DictLiteral) \
|
||||
TYPE(ForEachMacro) \
|
||||
|
@ -145,6 +145,7 @@ class AnnotatingParser {
|
||||
(Left->Previous->isOneOf(tok::kw_static_assert, tok::kw_decltype,
|
||||
tok::kw_if, tok::kw_while, tok::l_paren,
|
||||
tok::comma) ||
|
||||
Left->Previous->endsSequence(tok::kw_constexpr, tok::kw_if) ||
|
||||
Left->Previous->is(TT_BinaryOperator))) {
|
||||
// static_assert, if and while usually contain expressions.
|
||||
Contexts.back().IsExpression = true;
|
||||
@ -339,6 +340,9 @@ class AnnotatingParser {
|
||||
Contexts.back().ContextKind == tok::l_brace &&
|
||||
Parent->isOneOf(tok::l_brace, tok::comma)) {
|
||||
Left->Type = TT_JsComputedPropertyName;
|
||||
} else if (Style.isCpp() && Contexts.back().ContextKind == tok::l_brace &&
|
||||
Parent && Parent->isOneOf(tok::l_brace, tok::comma)) {
|
||||
Left->Type = TT_DesignatedInitializerLSquare;
|
||||
} else if (CurrentToken->is(tok::r_square) && Parent &&
|
||||
Parent->is(TT_TemplateCloser)) {
|
||||
Left->Type = TT_ArraySubscriptLSquare;
|
||||
@ -391,7 +395,8 @@ class AnnotatingParser {
|
||||
if (CurrentToken->isOneOf(tok::r_paren, tok::r_brace))
|
||||
return false;
|
||||
if (CurrentToken->is(tok::colon)) {
|
||||
if (Left->is(TT_ArraySubscriptLSquare)) {
|
||||
if (Left->isOneOf(TT_ArraySubscriptLSquare,
|
||||
TT_DesignatedInitializerLSquare)) {
|
||||
Left->Type = TT_ObjCMethodExpr;
|
||||
StartsObjCMethodExpr = true;
|
||||
Contexts.back().ColonIsObjCMethodExpr = true;
|
||||
@ -572,6 +577,8 @@ class AnnotatingParser {
|
||||
break;
|
||||
case tok::kw_if:
|
||||
case tok::kw_while:
|
||||
if (Tok->is(tok::kw_if) && CurrentToken && CurrentToken->is(tok::kw_constexpr))
|
||||
next();
|
||||
if (CurrentToken && CurrentToken->is(tok::l_paren)) {
|
||||
next();
|
||||
if (!parseParens(/*LookForDecls=*/true))
|
||||
@ -1972,7 +1979,8 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
|
||||
if (Right.is(TT_LambdaLSquare) && Left.is(tok::equal))
|
||||
return 35;
|
||||
if (!Right.isOneOf(TT_ObjCMethodExpr, TT_LambdaLSquare,
|
||||
TT_ArrayInitializerLSquare))
|
||||
TT_ArrayInitializerLSquare,
|
||||
TT_DesignatedInitializerLSquare))
|
||||
return 500;
|
||||
}
|
||||
|
||||
@ -2060,7 +2068,8 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
|
||||
Style.AlignAfterOpenBracket != FormatStyle::BAS_DontAlign)
|
||||
return 100;
|
||||
if (Left.is(tok::l_paren) && Left.Previous &&
|
||||
Left.Previous->isOneOf(tok::kw_if, tok::kw_for))
|
||||
(Left.Previous->isOneOf(tok::kw_if, tok::kw_for)
|
||||
|| Left.Previous->endsSequence(tok::kw_constexpr, tok::kw_if)))
|
||||
return 1000;
|
||||
if (Left.is(tok::equal) && InFunctionDecl)
|
||||
return 110;
|
||||
@ -2192,7 +2201,8 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
|
||||
(Style.SpacesInSquareBrackets &&
|
||||
Right.MatchingParen->is(TT_ArraySubscriptLSquare)));
|
||||
if (Right.is(tok::l_square) &&
|
||||
!Right.isOneOf(TT_ObjCMethodExpr, TT_LambdaLSquare) &&
|
||||
!Right.isOneOf(TT_ObjCMethodExpr, TT_LambdaLSquare,
|
||||
TT_DesignatedInitializerLSquare) &&
|
||||
!Left.isOneOf(tok::numeric_constant, TT_DictLiteral))
|
||||
return false;
|
||||
if (Left.is(tok::l_brace) && Right.is(tok::r_brace))
|
||||
@ -2211,6 +2221,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
|
||||
(Left.isOneOf(tok::kw_if, tok::pp_elif, tok::kw_for, tok::kw_while,
|
||||
tok::kw_switch, tok::kw_case, TT_ForEachMacro,
|
||||
TT_ObjCForIn) ||
|
||||
Left.endsSequence(tok::kw_constexpr, tok::kw_if) ||
|
||||
(Left.isOneOf(tok::kw_try, Keywords.kw___except, tok::kw_catch,
|
||||
tok::kw_new, tok::kw_delete) &&
|
||||
(!Left.Previous || Left.Previous->isNot(tok::period))))) ||
|
||||
@ -2391,8 +2402,9 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
|
||||
if (Left.is(tok::greater) && Right.is(tok::greater))
|
||||
return Right.is(TT_TemplateCloser) && Left.is(TT_TemplateCloser) &&
|
||||
(Style.Standard != FormatStyle::LS_Cpp11 || Style.SpacesInAngles);
|
||||
if (Right.isOneOf(tok::arrow, tok::period, tok::arrowstar, tok::periodstar) ||
|
||||
Left.isOneOf(tok::arrow, tok::period, tok::arrowstar, tok::periodstar))
|
||||
if (Right.isOneOf(tok::arrow, tok::arrowstar, tok::periodstar) ||
|
||||
Left.isOneOf(tok::arrow, tok::period, tok::arrowstar, tok::periodstar) ||
|
||||
(Right.is(tok::period) && Right.isNot(TT_DesignatedInitializerPeriod)))
|
||||
return false;
|
||||
if (!Style.SpaceBeforeAssignmentOperators &&
|
||||
Right.getPrecedence() == prec::Assignment)
|
||||
@ -2468,8 +2480,8 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
|
||||
return Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_None ||
|
||||
Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Empty ||
|
||||
(Left.NestingLevel == 0 && Line.Level == 0 &&
|
||||
Style.AllowShortFunctionsOnASingleLine ==
|
||||
FormatStyle::SFS_Inline);
|
||||
Style.AllowShortFunctionsOnASingleLine &
|
||||
FormatStyle::SFS_InlineOnly);
|
||||
} else if (Style.Language == FormatStyle::LK_Java) {
|
||||
if (Right.is(tok::plus) && Left.is(tok::string_literal) && Right.Next &&
|
||||
Right.Next->is(tok::string_literal))
|
||||
|
@ -226,7 +226,7 @@ class LineJoiner {
|
||||
Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_All ||
|
||||
(Style.AllowShortFunctionsOnASingleLine >= FormatStyle::SFS_Empty &&
|
||||
I[1]->First->is(tok::r_brace)) ||
|
||||
(Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Inline &&
|
||||
(Style.AllowShortFunctionsOnASingleLine & FormatStyle::SFS_InlineOnly &&
|
||||
TheLine->Level != 0);
|
||||
|
||||
if (Style.CompactNamespaces) {
|
||||
@ -434,8 +434,11 @@ class LineJoiner {
|
||||
} else if (Limit != 0 && !Line.startsWith(tok::kw_namespace) &&
|
||||
!startsExternCBlock(Line)) {
|
||||
// We don't merge short records.
|
||||
if (Line.First->isOneOf(tok::kw_class, tok::kw_union, tok::kw_struct,
|
||||
Keywords.kw_interface))
|
||||
FormatToken *RecordTok =
|
||||
Line.First->is(tok::kw_typedef) ? Line.First->Next : Line.First;
|
||||
if (RecordTok &&
|
||||
RecordTok->isOneOf(tok::kw_class, tok::kw_union, tok::kw_struct,
|
||||
Keywords.kw_interface))
|
||||
return 0;
|
||||
|
||||
// Check that we still have three lines and they fit into the limit.
|
||||
|
@ -1516,6 +1516,8 @@ void UnwrappedLineParser::parseSquare() {
|
||||
void UnwrappedLineParser::parseIfThenElse() {
|
||||
assert(FormatTok->Tok.is(tok::kw_if) && "'if' expected");
|
||||
nextToken();
|
||||
if (FormatTok->Tok.is(tok::kw_constexpr))
|
||||
nextToken();
|
||||
if (FormatTok->Tok.is(tok::l_paren))
|
||||
parseParens();
|
||||
bool NeedsUnwrappedLine = false;
|
||||
|
144
lib/Format/UsingDeclarationsSorter.cpp
Normal file
144
lib/Format/UsingDeclarationsSorter.cpp
Normal file
@ -0,0 +1,144 @@
|
||||
//===--- UsingDeclarationsSorter.cpp ----------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// \brief This file implements UsingDeclarationsSorter, a TokenAnalyzer that
|
||||
/// sorts consecutive using declarations.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "UsingDeclarationsSorter.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/Regex.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#define DEBUG_TYPE "using-declarations-sorter"
|
||||
|
||||
namespace clang {
|
||||
namespace format {
|
||||
|
||||
namespace {
|
||||
|
||||
struct UsingDeclaration {
|
||||
const AnnotatedLine *Line;
|
||||
std::string Label;
|
||||
|
||||
UsingDeclaration(const AnnotatedLine *Line, const std::string &Label)
|
||||
: Line(Line), Label(Label) {}
|
||||
|
||||
bool operator<(const UsingDeclaration &Other) const {
|
||||
return Label < Other.Label;
|
||||
}
|
||||
};
|
||||
|
||||
/// Computes the label of a using declaration starting at tthe using token
|
||||
/// \p UsingTok.
|
||||
/// If \p UsingTok doesn't begin a using declaration, returns the empty string.
|
||||
/// Note that this detects specifically using declarations, as in:
|
||||
/// using A::B::C;
|
||||
/// and not type aliases, as in:
|
||||
/// using A = B::C;
|
||||
/// Type aliases are in general not safe to permute.
|
||||
std::string computeUsingDeclarationLabel(const FormatToken *UsingTok) {
|
||||
assert(UsingTok && UsingTok->is(tok::kw_using) && "Expecting a using token");
|
||||
std::string Label;
|
||||
const FormatToken *Tok = UsingTok->Next;
|
||||
if (Tok && Tok->is(tok::kw_typename)) {
|
||||
Label.append("typename ");
|
||||
Tok = Tok->Next;
|
||||
}
|
||||
if (Tok && Tok->is(tok::coloncolon)) {
|
||||
Label.append("::");
|
||||
Tok = Tok->Next;
|
||||
}
|
||||
bool HasIdentifier = false;
|
||||
while (Tok && Tok->is(tok::identifier)) {
|
||||
HasIdentifier = true;
|
||||
Label.append(Tok->TokenText.str());
|
||||
Tok = Tok->Next;
|
||||
if (!Tok || Tok->isNot(tok::coloncolon))
|
||||
break;
|
||||
Label.append("::");
|
||||
Tok = Tok->Next;
|
||||
}
|
||||
if (HasIdentifier && Tok && Tok->isOneOf(tok::semi, tok::comma))
|
||||
return Label;
|
||||
return "";
|
||||
}
|
||||
|
||||
void endUsingDeclarationBlock(
|
||||
SmallVectorImpl<UsingDeclaration> *UsingDeclarations,
|
||||
const SourceManager &SourceMgr, tooling::Replacements *Fixes) {
|
||||
SmallVector<UsingDeclaration, 4> SortedUsingDeclarations(
|
||||
UsingDeclarations->begin(), UsingDeclarations->end());
|
||||
std::sort(SortedUsingDeclarations.begin(), SortedUsingDeclarations.end());
|
||||
for (size_t I = 0, E = UsingDeclarations->size(); I < E; ++I) {
|
||||
if ((*UsingDeclarations)[I].Line == SortedUsingDeclarations[I].Line)
|
||||
continue;
|
||||
auto Begin = (*UsingDeclarations)[I].Line->First->Tok.getLocation();
|
||||
auto End = (*UsingDeclarations)[I].Line->Last->Tok.getEndLoc();
|
||||
auto SortedBegin =
|
||||
SortedUsingDeclarations[I].Line->First->Tok.getLocation();
|
||||
auto SortedEnd = SortedUsingDeclarations[I].Line->Last->Tok.getEndLoc();
|
||||
StringRef Text(SourceMgr.getCharacterData(SortedBegin),
|
||||
SourceMgr.getCharacterData(SortedEnd) -
|
||||
SourceMgr.getCharacterData(SortedBegin));
|
||||
DEBUG({
|
||||
StringRef OldText(SourceMgr.getCharacterData(Begin),
|
||||
SourceMgr.getCharacterData(End) -
|
||||
SourceMgr.getCharacterData(Begin));
|
||||
llvm::dbgs() << "Replacing '" << OldText << "' with '" << Text << "'\n";
|
||||
});
|
||||
auto Range = CharSourceRange::getCharRange(Begin, End);
|
||||
auto Err = Fixes->add(tooling::Replacement(SourceMgr, Range, Text));
|
||||
if (Err) {
|
||||
llvm::errs() << "Error while sorting using declarations: "
|
||||
<< llvm::toString(std::move(Err)) << "\n";
|
||||
}
|
||||
}
|
||||
UsingDeclarations->clear();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
UsingDeclarationsSorter::UsingDeclarationsSorter(const Environment &Env,
|
||||
const FormatStyle &Style)
|
||||
: TokenAnalyzer(Env, Style) {}
|
||||
|
||||
tooling::Replacements UsingDeclarationsSorter::analyze(
|
||||
TokenAnnotator &Annotator, SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
|
||||
FormatTokenLexer &Tokens) {
|
||||
const SourceManager &SourceMgr = Env.getSourceManager();
|
||||
AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
|
||||
AnnotatedLines.end());
|
||||
tooling::Replacements Fixes;
|
||||
SmallVector<UsingDeclaration, 4> UsingDeclarations;
|
||||
for (size_t I = 0, E = AnnotatedLines.size(); I != E; ++I) {
|
||||
if (!AnnotatedLines[I]->Affected || AnnotatedLines[I]->InPPDirective ||
|
||||
!AnnotatedLines[I]->startsWith(tok::kw_using) ||
|
||||
AnnotatedLines[I]->First->Finalized) {
|
||||
endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
|
||||
continue;
|
||||
}
|
||||
if (AnnotatedLines[I]->First->NewlinesBefore > 1)
|
||||
endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
|
||||
std::string Label = computeUsingDeclarationLabel(AnnotatedLines[I]->First);
|
||||
if (Label.empty()) {
|
||||
endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
|
||||
continue;
|
||||
}
|
||||
UsingDeclarations.push_back(UsingDeclaration(AnnotatedLines[I], Label));
|
||||
}
|
||||
endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
|
||||
return Fixes;
|
||||
}
|
||||
|
||||
} // namespace format
|
||||
} // namespace clang
|
37
lib/Format/UsingDeclarationsSorter.h
Normal file
37
lib/Format/UsingDeclarationsSorter.h
Normal file
@ -0,0 +1,37 @@
|
||||
//===--- UsingDeclarationsSorter.h ------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// \brief This file declares UsingDeclarationsSorter, a TokenAnalyzer that
|
||||
/// sorts consecutive using declarations.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_LIB_FORMAT_USINGDECLARATIONSSORTER_H
|
||||
#define LLVM_CLANG_LIB_FORMAT_USINGDECLARATIONSSORTER_H
|
||||
|
||||
#include "TokenAnalyzer.h"
|
||||
|
||||
namespace clang {
|
||||
namespace format {
|
||||
|
||||
class UsingDeclarationsSorter : public TokenAnalyzer {
|
||||
public:
|
||||
UsingDeclarationsSorter(const Environment &Env, const FormatStyle &Style);
|
||||
|
||||
tooling::Replacements
|
||||
analyze(TokenAnnotator &Annotator,
|
||||
SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
|
||||
FormatTokenLexer &Tokens) override;
|
||||
};
|
||||
|
||||
} // end namespace format
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -38,6 +38,7 @@ add_clang_library(clangFrontend
|
||||
ModuleDependencyCollector.cpp
|
||||
MultiplexConsumer.cpp
|
||||
PCHContainerOperations.cpp
|
||||
PrecompiledPreamble.cpp
|
||||
PrintPreprocessedOutput.cpp
|
||||
SerializedDiagnosticPrinter.cpp
|
||||
SerializedDiagnosticReader.cpp
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/Basic/CharInfo.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Basic/MemoryBufferCache.h"
|
||||
@ -1902,17 +1903,23 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
|
||||
void CompilerInstance::loadModuleFromSource(SourceLocation ImportLoc,
|
||||
StringRef ModuleName,
|
||||
StringRef Source) {
|
||||
// Avoid creating filenames with special characters.
|
||||
SmallString<128> CleanModuleName(ModuleName);
|
||||
for (auto &C : CleanModuleName)
|
||||
if (!isAlphanumeric(C))
|
||||
C = '_';
|
||||
|
||||
// FIXME: Using a randomized filename here means that our intermediate .pcm
|
||||
// output is nondeterministic (as .pcm files refer to each other by name).
|
||||
// Can this affect the output in any way?
|
||||
SmallString<128> ModuleFileName;
|
||||
if (std::error_code EC = llvm::sys::fs::createTemporaryFile(
|
||||
ModuleName, "pcm", ModuleFileName)) {
|
||||
CleanModuleName, "pcm", ModuleFileName)) {
|
||||
getDiagnostics().Report(ImportLoc, diag::err_fe_unable_to_open_output)
|
||||
<< ModuleFileName << EC.message();
|
||||
return;
|
||||
}
|
||||
std::string ModuleMapFileName = (ModuleName + ".map").str();
|
||||
std::string ModuleMapFileName = (CleanModuleName + ".map").str();
|
||||
|
||||
FrontendInputFile Input(
|
||||
ModuleMapFileName,
|
||||
|
@ -745,9 +745,22 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
|
||||
Opts.InstrumentForProfiling = Args.hasArg(OPT_pg);
|
||||
Opts.CallFEntry = Args.hasArg(OPT_mfentry);
|
||||
Opts.EmitOpenCLArgMetadata = Args.hasArg(OPT_cl_kernel_arg_info);
|
||||
// TODO: map this from -gz in the driver and give it a named value
|
||||
if (Args.hasArg(OPT_compress_debug_sections))
|
||||
Opts.setCompressDebugSections(llvm::DebugCompressionType::GNU);
|
||||
|
||||
if (const Arg *A = Args.getLastArg(OPT_compress_debug_sections,
|
||||
OPT_compress_debug_sections_EQ)) {
|
||||
if (A->getOption().getID() == OPT_compress_debug_sections) {
|
||||
// TODO: be more clever about the compression type auto-detection
|
||||
Opts.setCompressDebugSections(llvm::DebugCompressionType::GNU);
|
||||
} else {
|
||||
auto DCT = llvm::StringSwitch<llvm::DebugCompressionType>(A->getValue())
|
||||
.Case("none", llvm::DebugCompressionType::None)
|
||||
.Case("zlib", llvm::DebugCompressionType::Z)
|
||||
.Case("zlib-gnu", llvm::DebugCompressionType::GNU)
|
||||
.Default(llvm::DebugCompressionType::None);
|
||||
Opts.setCompressDebugSections(DCT);
|
||||
}
|
||||
}
|
||||
|
||||
Opts.RelaxELFRelocations = Args.hasArg(OPT_mrelax_relocations);
|
||||
Opts.DebugCompilationDir = Args.getLastArgValue(OPT_fdebug_compilation_dir);
|
||||
for (auto A : Args.filtered(OPT_mlink_bitcode_file, OPT_mlink_cuda_bitcode)) {
|
||||
@ -892,14 +905,18 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
|
||||
|
||||
Opts.DiagnosticsWithHotness =
|
||||
Args.hasArg(options::OPT_fdiagnostics_show_hotness);
|
||||
bool UsingSampleProfile = !Opts.SampleProfileFile.empty();
|
||||
|
||||
if (Opts.DiagnosticsWithHotness &&
|
||||
Opts.getProfileUse() == CodeGenOptions::ProfileNone)
|
||||
Opts.getProfileUse() == CodeGenOptions::ProfileNone &&
|
||||
!UsingSampleProfile) {
|
||||
Diags.Report(diag::warn_drv_fdiagnostics_show_hotness_requires_pgo);
|
||||
}
|
||||
|
||||
// If the user requested to use a sample profile for PGO, then the
|
||||
// backend will need to track source location information so the profile
|
||||
// can be incorporated into the IR.
|
||||
if (!Opts.SampleProfileFile.empty())
|
||||
if (UsingSampleProfile)
|
||||
NeedLocTracking = true;
|
||||
|
||||
// If the user requested a flag that requires source locations available in
|
||||
@ -2379,9 +2396,51 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
|
||||
Opts.AllowEditorPlaceholders = Args.hasArg(OPT_fallow_editor_placeholders);
|
||||
}
|
||||
|
||||
static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) {
|
||||
switch (Action) {
|
||||
case frontend::ASTDeclList:
|
||||
case frontend::ASTDump:
|
||||
case frontend::ASTPrint:
|
||||
case frontend::ASTView:
|
||||
case frontend::EmitAssembly:
|
||||
case frontend::EmitBC:
|
||||
case frontend::EmitHTML:
|
||||
case frontend::EmitLLVM:
|
||||
case frontend::EmitLLVMOnly:
|
||||
case frontend::EmitCodeGenOnly:
|
||||
case frontend::EmitObj:
|
||||
case frontend::FixIt:
|
||||
case frontend::GenerateModule:
|
||||
case frontend::GenerateModuleInterface:
|
||||
case frontend::GeneratePCH:
|
||||
case frontend::GeneratePTH:
|
||||
case frontend::ParseSyntaxOnly:
|
||||
case frontend::ModuleFileInfo:
|
||||
case frontend::VerifyPCH:
|
||||
case frontend::PluginAction:
|
||||
case frontend::PrintDeclContext:
|
||||
case frontend::RewriteObjC:
|
||||
case frontend::RewriteTest:
|
||||
case frontend::RunAnalysis:
|
||||
case frontend::MigrateSource:
|
||||
return false;
|
||||
|
||||
case frontend::DumpRawTokens:
|
||||
case frontend::DumpTokens:
|
||||
case frontend::InitOnly:
|
||||
case frontend::PrintPreamble:
|
||||
case frontend::PrintPreprocessedInput:
|
||||
case frontend::RewriteMacros:
|
||||
case frontend::RunPreprocessorOnly:
|
||||
return true;
|
||||
}
|
||||
llvm_unreachable("invalid frontend action");
|
||||
}
|
||||
|
||||
static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
|
||||
FileManager &FileMgr,
|
||||
DiagnosticsEngine &Diags) {
|
||||
DiagnosticsEngine &Diags,
|
||||
frontend::ActionKind Action) {
|
||||
using namespace options;
|
||||
Opts.ImplicitPCHInclude = Args.getLastArgValue(OPT_include_pch);
|
||||
Opts.ImplicitPTHInclude = Args.getLastArgValue(OPT_include_pth);
|
||||
@ -2454,6 +2513,12 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
|
||||
else
|
||||
Opts.ObjCXXARCStandardLibrary = (ObjCXXARCStandardLibraryKind)Library;
|
||||
}
|
||||
|
||||
// Always avoid lexing editor placeholders when we're just running the
|
||||
// preprocessor as we never want to emit the
|
||||
// "editor placeholder in source file" error in PP only mode.
|
||||
if (isStrictlyPreprocessorAction(Action))
|
||||
Opts.LexEditorPlaceholders = false;
|
||||
}
|
||||
|
||||
static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts,
|
||||
@ -2461,45 +2526,10 @@ static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts,
|
||||
frontend::ActionKind Action) {
|
||||
using namespace options;
|
||||
|
||||
switch (Action) {
|
||||
case frontend::ASTDeclList:
|
||||
case frontend::ASTDump:
|
||||
case frontend::ASTPrint:
|
||||
case frontend::ASTView:
|
||||
case frontend::EmitAssembly:
|
||||
case frontend::EmitBC:
|
||||
case frontend::EmitHTML:
|
||||
case frontend::EmitLLVM:
|
||||
case frontend::EmitLLVMOnly:
|
||||
case frontend::EmitCodeGenOnly:
|
||||
case frontend::EmitObj:
|
||||
case frontend::FixIt:
|
||||
case frontend::GenerateModule:
|
||||
case frontend::GenerateModuleInterface:
|
||||
case frontend::GeneratePCH:
|
||||
case frontend::GeneratePTH:
|
||||
case frontend::ParseSyntaxOnly:
|
||||
case frontend::ModuleFileInfo:
|
||||
case frontend::VerifyPCH:
|
||||
case frontend::PluginAction:
|
||||
case frontend::PrintDeclContext:
|
||||
case frontend::RewriteObjC:
|
||||
case frontend::RewriteTest:
|
||||
case frontend::RunAnalysis:
|
||||
case frontend::MigrateSource:
|
||||
Opts.ShowCPP = 0;
|
||||
break;
|
||||
|
||||
case frontend::DumpRawTokens:
|
||||
case frontend::DumpTokens:
|
||||
case frontend::InitOnly:
|
||||
case frontend::PrintPreamble:
|
||||
case frontend::PrintPreprocessedInput:
|
||||
case frontend::RewriteMacros:
|
||||
case frontend::RunPreprocessorOnly:
|
||||
if (isStrictlyPreprocessorAction(Action))
|
||||
Opts.ShowCPP = !Args.hasArg(OPT_dM);
|
||||
break;
|
||||
}
|
||||
else
|
||||
Opts.ShowCPP = 0;
|
||||
|
||||
Opts.ShowComments = Args.hasArg(OPT_C);
|
||||
Opts.ShowLineMarkers = !Args.hasArg(OPT_P);
|
||||
@ -2626,7 +2656,8 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
|
||||
// ParsePreprocessorArgs and remove the FileManager
|
||||
// parameters from the function and the "FileManager.h" #include.
|
||||
FileManager FileMgr(Res.getFileSystemOpts());
|
||||
ParsePreprocessorArgs(Res.getPreprocessorOpts(), Args, FileMgr, Diags);
|
||||
ParsePreprocessorArgs(Res.getPreprocessorOpts(), Args, FileMgr, Diags,
|
||||
Res.getFrontendOpts().ProgramAction);
|
||||
ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), Args,
|
||||
Res.getFrontendOpts().ProgramAction);
|
||||
|
||||
|
@ -561,7 +561,6 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
|
||||
CI.setFileManager(&AST->getFileManager());
|
||||
CI.createSourceManager(CI.getFileManager());
|
||||
CI.getSourceManager().initializeForReplay(AST->getSourceManager());
|
||||
CI.createPreprocessor(getTranslationUnitKind());
|
||||
|
||||
// Set up the input file for replay purposes.
|
||||
auto Kind = AST->getInputKind();
|
||||
|
@ -517,7 +517,7 @@ void PrintPreprocessedAction::ExecuteAction() {
|
||||
// file. This is mostly a sanity check in case the file has no
|
||||
// newlines whatsoever.
|
||||
if (end - cur > 256) end = cur + 256;
|
||||
|
||||
|
||||
while (next < end) {
|
||||
if (*cur == 0x0D) { // CR
|
||||
if (*next == 0x0A) // CRLF
|
||||
|
563
lib/Frontend/PrecompiledPreamble.cpp
Normal file
563
lib/Frontend/PrecompiledPreamble.cpp
Normal file
@ -0,0 +1,563 @@
|
||||
//===--- PrecompiledPreamble.cpp - Build precompiled preambles --*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Helper class to build precompiled preamble.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Frontend/PrecompiledPreamble.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "clang/Basic/VirtualFileSystem.h"
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
#include "clang/Frontend/CompilerInvocation.h"
|
||||
#include "clang/Frontend/FrontendActions.h"
|
||||
#include "clang/Frontend/FrontendOptions.h"
|
||||
#include "clang/Lex/Lexer.h"
|
||||
#include "clang/Lex/PreprocessorOptions.h"
|
||||
#include "clang/Serialization/ASTWriter.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/ADT/StringSet.h"
|
||||
#include "llvm/Support/CrashRecoveryContext.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/Mutex.h"
|
||||
#include "llvm/Support/MutexGuard.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
namespace {
|
||||
|
||||
/// Keeps a track of files to be deleted in destructor.
|
||||
class TemporaryFiles {
|
||||
public:
|
||||
// A static instance to be used by all clients.
|
||||
static TemporaryFiles &getInstance();
|
||||
|
||||
private:
|
||||
// Disallow constructing the class directly.
|
||||
TemporaryFiles() = default;
|
||||
// Disallow copy.
|
||||
TemporaryFiles(const TemporaryFiles &) = delete;
|
||||
|
||||
public:
|
||||
~TemporaryFiles();
|
||||
|
||||
/// Adds \p File to a set of tracked files.
|
||||
void addFile(StringRef File);
|
||||
|
||||
/// Remove \p File from disk and from the set of tracked files.
|
||||
void removeFile(StringRef File);
|
||||
|
||||
private:
|
||||
llvm::sys::SmartMutex<false> Mutex;
|
||||
llvm::StringSet<> Files;
|
||||
};
|
||||
|
||||
TemporaryFiles &TemporaryFiles::getInstance() {
|
||||
static TemporaryFiles Instance;
|
||||
return Instance;
|
||||
}
|
||||
|
||||
TemporaryFiles::~TemporaryFiles() {
|
||||
llvm::MutexGuard Guard(Mutex);
|
||||
for (const auto &File : Files)
|
||||
llvm::sys::fs::remove(File.getKey());
|
||||
}
|
||||
|
||||
void TemporaryFiles::addFile(StringRef File) {
|
||||
llvm::MutexGuard Guard(Mutex);
|
||||
auto IsInserted = Files.insert(File).second;
|
||||
(void)IsInserted;
|
||||
assert(IsInserted && "File has already been added");
|
||||
}
|
||||
|
||||
void TemporaryFiles::removeFile(StringRef File) {
|
||||
llvm::MutexGuard Guard(Mutex);
|
||||
auto WasPresent = Files.erase(File);
|
||||
(void)WasPresent;
|
||||
assert(WasPresent && "File was not tracked");
|
||||
llvm::sys::fs::remove(File);
|
||||
}
|
||||
|
||||
class PreambleMacroCallbacks : public PPCallbacks {
|
||||
public:
|
||||
PreambleMacroCallbacks(PreambleCallbacks &Callbacks) : Callbacks(Callbacks) {}
|
||||
|
||||
void MacroDefined(const Token &MacroNameTok,
|
||||
const MacroDirective *MD) override {
|
||||
Callbacks.HandleMacroDefined(MacroNameTok, MD);
|
||||
}
|
||||
|
||||
private:
|
||||
PreambleCallbacks &Callbacks;
|
||||
};
|
||||
|
||||
class PrecompilePreambleAction : public ASTFrontendAction {
|
||||
public:
|
||||
PrecompilePreambleAction(PreambleCallbacks &Callbacks)
|
||||
: Callbacks(Callbacks) {}
|
||||
|
||||
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
|
||||
StringRef InFile) override;
|
||||
|
||||
bool hasEmittedPreamblePCH() const { return HasEmittedPreamblePCH; }
|
||||
|
||||
void setEmittedPreamblePCH(ASTWriter &Writer) {
|
||||
this->HasEmittedPreamblePCH = true;
|
||||
Callbacks.AfterPCHEmitted(Writer);
|
||||
}
|
||||
|
||||
bool shouldEraseOutputFiles() override { return !hasEmittedPreamblePCH(); }
|
||||
bool hasCodeCompletionSupport() const override { return false; }
|
||||
bool hasASTFileSupport() const override { return false; }
|
||||
TranslationUnitKind getTranslationUnitKind() override { return TU_Prefix; }
|
||||
|
||||
private:
|
||||
friend class PrecompilePreambleConsumer;
|
||||
|
||||
bool HasEmittedPreamblePCH = false;
|
||||
PreambleCallbacks &Callbacks;
|
||||
};
|
||||
|
||||
class PrecompilePreambleConsumer : public PCHGenerator {
|
||||
public:
|
||||
PrecompilePreambleConsumer(PrecompilePreambleAction &Action,
|
||||
const Preprocessor &PP, StringRef isysroot,
|
||||
std::unique_ptr<raw_ostream> Out)
|
||||
: PCHGenerator(PP, "", isysroot, std::make_shared<PCHBuffer>(),
|
||||
ArrayRef<std::shared_ptr<ModuleFileExtension>>(),
|
||||
/*AllowASTWithErrors=*/true),
|
||||
Action(Action), Out(std::move(Out)) {}
|
||||
|
||||
bool HandleTopLevelDecl(DeclGroupRef DG) override {
|
||||
Action.Callbacks.HandleTopLevelDecl(DG);
|
||||
return true;
|
||||
}
|
||||
|
||||
void HandleTranslationUnit(ASTContext &Ctx) override {
|
||||
PCHGenerator::HandleTranslationUnit(Ctx);
|
||||
if (!hasEmittedPCH())
|
||||
return;
|
||||
|
||||
// Write the generated bitstream to "Out".
|
||||
*Out << getPCH();
|
||||
// Make sure it hits disk now.
|
||||
Out->flush();
|
||||
// Free the buffer.
|
||||
llvm::SmallVector<char, 0> Empty;
|
||||
getPCH() = std::move(Empty);
|
||||
|
||||
Action.setEmittedPreamblePCH(getWriter());
|
||||
}
|
||||
|
||||
private:
|
||||
PrecompilePreambleAction &Action;
|
||||
std::unique_ptr<raw_ostream> Out;
|
||||
};
|
||||
|
||||
std::unique_ptr<ASTConsumer>
|
||||
PrecompilePreambleAction::CreateASTConsumer(CompilerInstance &CI,
|
||||
|
||||
StringRef InFile) {
|
||||
std::string Sysroot;
|
||||
std::string OutputFile;
|
||||
std::unique_ptr<raw_ostream> OS =
|
||||
GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot,
|
||||
OutputFile);
|
||||
if (!OS)
|
||||
return nullptr;
|
||||
|
||||
if (!CI.getFrontendOpts().RelocatablePCH)
|
||||
Sysroot.clear();
|
||||
|
||||
CI.getPreprocessor().addPPCallbacks(
|
||||
llvm::make_unique<PreambleMacroCallbacks>(Callbacks));
|
||||
return llvm::make_unique<PrecompilePreambleConsumer>(
|
||||
*this, CI.getPreprocessor(), Sysroot, std::move(OS));
|
||||
}
|
||||
|
||||
template <class T> bool moveOnNoError(llvm::ErrorOr<T> Val, T &Output) {
|
||||
if (!Val)
|
||||
return false;
|
||||
Output = std::move(*Val);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
PreambleBounds clang::ComputePreambleBounds(const LangOptions &LangOpts,
|
||||
llvm::MemoryBuffer *Buffer,
|
||||
unsigned MaxLines) {
|
||||
auto Pre = Lexer::ComputePreamble(Buffer->getBuffer(), LangOpts, MaxLines);
|
||||
return PreambleBounds(Pre.first, Pre.second);
|
||||
}
|
||||
|
||||
llvm::ErrorOr<PrecompiledPreamble> PrecompiledPreamble::Build(
|
||||
const CompilerInvocation &Invocation,
|
||||
const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds,
|
||||
DiagnosticsEngine &Diagnostics, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
||||
PreambleCallbacks &Callbacks) {
|
||||
assert(VFS && "VFS is null");
|
||||
|
||||
if (!Bounds.Size)
|
||||
return BuildPreambleError::PreambleIsEmpty;
|
||||
|
||||
auto PreambleInvocation = std::make_shared<CompilerInvocation>(Invocation);
|
||||
FrontendOptions &FrontendOpts = PreambleInvocation->getFrontendOpts();
|
||||
PreprocessorOptions &PreprocessorOpts =
|
||||
PreambleInvocation->getPreprocessorOpts();
|
||||
|
||||
// Create a temporary file for the precompiled preamble. In rare
|
||||
// circumstances, this can fail.
|
||||
llvm::ErrorOr<PrecompiledPreamble::TempPCHFile> PreamblePCHFile =
|
||||
PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile();
|
||||
if (!PreamblePCHFile)
|
||||
return BuildPreambleError::CouldntCreateTempFile;
|
||||
|
||||
// Save the preamble text for later; we'll need to compare against it for
|
||||
// subsequent reparses.
|
||||
std::vector<char> PreambleBytes(MainFileBuffer->getBufferStart(),
|
||||
MainFileBuffer->getBufferStart() +
|
||||
Bounds.Size);
|
||||
bool PreambleEndsAtStartOfLine = Bounds.PreambleEndsAtStartOfLine;
|
||||
|
||||
// Tell the compiler invocation to generate a temporary precompiled header.
|
||||
FrontendOpts.ProgramAction = frontend::GeneratePCH;
|
||||
// FIXME: Generate the precompiled header into memory?
|
||||
FrontendOpts.OutputFile = PreamblePCHFile->getFilePath();
|
||||
PreprocessorOpts.PrecompiledPreambleBytes.first = 0;
|
||||
PreprocessorOpts.PrecompiledPreambleBytes.second = false;
|
||||
|
||||
// Create the compiler instance to use for building the precompiled preamble.
|
||||
std::unique_ptr<CompilerInstance> Clang(
|
||||
new CompilerInstance(std::move(PCHContainerOps)));
|
||||
|
||||
// Recover resources if we crash before exiting this method.
|
||||
llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> CICleanup(
|
||||
Clang.get());
|
||||
|
||||
Clang->setInvocation(std::move(PreambleInvocation));
|
||||
Clang->setDiagnostics(&Diagnostics);
|
||||
|
||||
// Create the target instance.
|
||||
Clang->setTarget(TargetInfo::CreateTargetInfo(
|
||||
Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
|
||||
if (!Clang->hasTarget())
|
||||
return BuildPreambleError::CouldntCreateTargetInfo;
|
||||
|
||||
// Inform the target of the language options.
|
||||
//
|
||||
// FIXME: We shouldn't need to do this, the target should be immutable once
|
||||
// created. This complexity should be lifted elsewhere.
|
||||
Clang->getTarget().adjust(Clang->getLangOpts());
|
||||
|
||||
assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
|
||||
"Invocation must have exactly one source file!");
|
||||
assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() ==
|
||||
InputKind::Source &&
|
||||
"FIXME: AST inputs not yet supported here!");
|
||||
assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() !=
|
||||
InputKind::LLVM_IR &&
|
||||
"IR inputs not support here!");
|
||||
|
||||
// Clear out old caches and data.
|
||||
Diagnostics.Reset();
|
||||
ProcessWarningOptions(Diagnostics, Clang->getDiagnosticOpts());
|
||||
|
||||
VFS =
|
||||
createVFSFromCompilerInvocation(Clang->getInvocation(), Diagnostics, VFS);
|
||||
if (!VFS)
|
||||
return BuildPreambleError::CouldntCreateVFSOverlay;
|
||||
|
||||
// Create a file manager object to provide access to and cache the filesystem.
|
||||
Clang->setFileManager(new FileManager(Clang->getFileSystemOpts(), VFS));
|
||||
|
||||
// Create the source manager.
|
||||
Clang->setSourceManager(
|
||||
new SourceManager(Diagnostics, Clang->getFileManager()));
|
||||
|
||||
auto PreambleDepCollector = std::make_shared<DependencyCollector>();
|
||||
Clang->addDependencyCollector(PreambleDepCollector);
|
||||
|
||||
// Remap the main source file to the preamble buffer.
|
||||
StringRef MainFilePath = FrontendOpts.Inputs[0].getFile();
|
||||
auto PreambleInputBuffer = llvm::MemoryBuffer::getMemBufferCopy(
|
||||
MainFileBuffer->getBuffer().slice(0, Bounds.Size), MainFilePath);
|
||||
if (PreprocessorOpts.RetainRemappedFileBuffers) {
|
||||
// MainFileBuffer will be deleted by unique_ptr after leaving the method.
|
||||
PreprocessorOpts.addRemappedFile(MainFilePath, PreambleInputBuffer.get());
|
||||
} else {
|
||||
// In that case, remapped buffer will be deleted by CompilerInstance on
|
||||
// BeginSourceFile, so we call release() to avoid double deletion.
|
||||
PreprocessorOpts.addRemappedFile(MainFilePath,
|
||||
PreambleInputBuffer.release());
|
||||
}
|
||||
|
||||
std::unique_ptr<PrecompilePreambleAction> Act;
|
||||
Act.reset(new PrecompilePreambleAction(Callbacks));
|
||||
if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0]))
|
||||
return BuildPreambleError::BeginSourceFileFailed;
|
||||
|
||||
Act->Execute();
|
||||
|
||||
// Run the callbacks.
|
||||
Callbacks.AfterExecute(*Clang);
|
||||
|
||||
Act->EndSourceFile();
|
||||
|
||||
if (!Act->hasEmittedPreamblePCH())
|
||||
return BuildPreambleError::CouldntEmitPCH;
|
||||
|
||||
// Keep track of all of the files that the source manager knows about,
|
||||
// so we can verify whether they have changed or not.
|
||||
llvm::StringMap<PrecompiledPreamble::PreambleFileHash> FilesInPreamble;
|
||||
|
||||
SourceManager &SourceMgr = Clang->getSourceManager();
|
||||
for (auto &Filename : PreambleDepCollector->getDependencies()) {
|
||||
const FileEntry *File = Clang->getFileManager().getFile(Filename);
|
||||
if (!File || File == SourceMgr.getFileEntryForID(SourceMgr.getMainFileID()))
|
||||
continue;
|
||||
if (time_t ModTime = File->getModificationTime()) {
|
||||
FilesInPreamble[File->getName()] =
|
||||
PrecompiledPreamble::PreambleFileHash::createForFile(File->getSize(),
|
||||
ModTime);
|
||||
} else {
|
||||
llvm::MemoryBuffer *Buffer = SourceMgr.getMemoryBufferForFile(File);
|
||||
FilesInPreamble[File->getName()] =
|
||||
PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(Buffer);
|
||||
}
|
||||
}
|
||||
|
||||
return PrecompiledPreamble(
|
||||
std::move(*PreamblePCHFile), std::move(PreambleBytes),
|
||||
PreambleEndsAtStartOfLine, std::move(FilesInPreamble));
|
||||
}
|
||||
|
||||
PreambleBounds PrecompiledPreamble::getBounds() const {
|
||||
return PreambleBounds(PreambleBytes.size(), PreambleEndsAtStartOfLine);
|
||||
}
|
||||
|
||||
bool PrecompiledPreamble::CanReuse(const CompilerInvocation &Invocation,
|
||||
const llvm::MemoryBuffer *MainFileBuffer,
|
||||
PreambleBounds Bounds,
|
||||
vfs::FileSystem *VFS) const {
|
||||
|
||||
assert(
|
||||
Bounds.Size <= MainFileBuffer->getBufferSize() &&
|
||||
"Buffer is too large. Bounds were calculated from a different buffer?");
|
||||
|
||||
auto PreambleInvocation = std::make_shared<CompilerInvocation>(Invocation);
|
||||
PreprocessorOptions &PreprocessorOpts =
|
||||
PreambleInvocation->getPreprocessorOpts();
|
||||
|
||||
if (!Bounds.Size)
|
||||
return false;
|
||||
|
||||
// We've previously computed a preamble. Check whether we have the same
|
||||
// preamble now that we did before, and that there's enough space in
|
||||
// the main-file buffer within the precompiled preamble to fit the
|
||||
// new main file.
|
||||
if (PreambleBytes.size() != Bounds.Size ||
|
||||
PreambleEndsAtStartOfLine != Bounds.PreambleEndsAtStartOfLine ||
|
||||
memcmp(PreambleBytes.data(), MainFileBuffer->getBufferStart(),
|
||||
Bounds.Size) != 0)
|
||||
return false;
|
||||
// The preamble has not changed. We may be able to re-use the precompiled
|
||||
// preamble.
|
||||
|
||||
// Check that none of the files used by the preamble have changed.
|
||||
// First, make a record of those files that have been overridden via
|
||||
// remapping or unsaved_files.
|
||||
std::map<llvm::sys::fs::UniqueID, PreambleFileHash> OverriddenFiles;
|
||||
for (const auto &R : PreprocessorOpts.RemappedFiles) {
|
||||
vfs::Status Status;
|
||||
if (!moveOnNoError(VFS->status(R.second), Status)) {
|
||||
// If we can't stat the file we're remapping to, assume that something
|
||||
// horrible happened.
|
||||
return false;
|
||||
}
|
||||
|
||||
OverriddenFiles[Status.getUniqueID()] = PreambleFileHash::createForFile(
|
||||
Status.getSize(), llvm::sys::toTimeT(Status.getLastModificationTime()));
|
||||
}
|
||||
|
||||
for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) {
|
||||
vfs::Status Status;
|
||||
if (!moveOnNoError(VFS->status(RB.first), Status))
|
||||
return false;
|
||||
|
||||
OverriddenFiles[Status.getUniqueID()] =
|
||||
PreambleFileHash::createForMemoryBuffer(RB.second);
|
||||
}
|
||||
|
||||
// Check whether anything has changed.
|
||||
for (const auto &F : FilesInPreamble) {
|
||||
vfs::Status Status;
|
||||
if (!moveOnNoError(VFS->status(F.first()), Status)) {
|
||||
// If we can't stat the file, assume that something horrible happened.
|
||||
return false;
|
||||
}
|
||||
|
||||
std::map<llvm::sys::fs::UniqueID, PreambleFileHash>::iterator Overridden =
|
||||
OverriddenFiles.find(Status.getUniqueID());
|
||||
if (Overridden != OverriddenFiles.end()) {
|
||||
// This file was remapped; check whether the newly-mapped file
|
||||
// matches up with the previous mapping.
|
||||
if (Overridden->second != F.second)
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// The file was not remapped; check whether it has changed on disk.
|
||||
if (Status.getSize() != uint64_t(F.second.Size) ||
|
||||
llvm::sys::toTimeT(Status.getLastModificationTime()) !=
|
||||
F.second.ModTime)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void PrecompiledPreamble::AddImplicitPreamble(
|
||||
CompilerInvocation &CI, llvm::MemoryBuffer *MainFileBuffer) const {
|
||||
auto &PreprocessorOpts = CI.getPreprocessorOpts();
|
||||
|
||||
// Configure ImpicitPCHInclude.
|
||||
PreprocessorOpts.PrecompiledPreambleBytes.first = PreambleBytes.size();
|
||||
PreprocessorOpts.PrecompiledPreambleBytes.second = PreambleEndsAtStartOfLine;
|
||||
PreprocessorOpts.ImplicitPCHInclude = PCHFile.getFilePath();
|
||||
PreprocessorOpts.DisablePCHValidation = true;
|
||||
|
||||
// Remap main file to point to MainFileBuffer.
|
||||
auto MainFilePath = CI.getFrontendOpts().Inputs[0].getFile();
|
||||
PreprocessorOpts.addRemappedFile(MainFilePath, MainFileBuffer);
|
||||
}
|
||||
|
||||
PrecompiledPreamble::PrecompiledPreamble(
|
||||
TempPCHFile PCHFile, std::vector<char> PreambleBytes,
|
||||
bool PreambleEndsAtStartOfLine,
|
||||
llvm::StringMap<PreambleFileHash> FilesInPreamble)
|
||||
: PCHFile(std::move(PCHFile)), FilesInPreamble(FilesInPreamble),
|
||||
PreambleBytes(std::move(PreambleBytes)),
|
||||
PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {}
|
||||
|
||||
llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
|
||||
PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile() {
|
||||
// FIXME: This is a hack so that we can override the preamble file during
|
||||
// crash-recovery testing, which is the only case where the preamble files
|
||||
// are not necessarily cleaned up.
|
||||
const char *TmpFile = ::getenv("CINDEXTEST_PREAMBLE_FILE");
|
||||
if (TmpFile)
|
||||
return TempPCHFile::createFromCustomPath(TmpFile);
|
||||
return TempPCHFile::createInSystemTempDir("preamble", "pch");
|
||||
}
|
||||
|
||||
llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
|
||||
PrecompiledPreamble::TempPCHFile::createInSystemTempDir(const Twine &Prefix,
|
||||
StringRef Suffix) {
|
||||
llvm::SmallString<64> File;
|
||||
auto EC = llvm::sys::fs::createTemporaryFile(Prefix, Suffix, /*ref*/ File);
|
||||
if (EC)
|
||||
return EC;
|
||||
return TempPCHFile(std::move(File).str());
|
||||
}
|
||||
|
||||
llvm::ErrorOr<PrecompiledPreamble::TempPCHFile>
|
||||
PrecompiledPreamble::TempPCHFile::createFromCustomPath(const Twine &Path) {
|
||||
return TempPCHFile(Path.str());
|
||||
}
|
||||
|
||||
PrecompiledPreamble::TempPCHFile::TempPCHFile(std::string FilePath)
|
||||
: FilePath(std::move(FilePath)) {
|
||||
TemporaryFiles::getInstance().addFile(*this->FilePath);
|
||||
}
|
||||
|
||||
PrecompiledPreamble::TempPCHFile::TempPCHFile(TempPCHFile &&Other) {
|
||||
FilePath = std::move(Other.FilePath);
|
||||
Other.FilePath = None;
|
||||
}
|
||||
|
||||
PrecompiledPreamble::TempPCHFile &PrecompiledPreamble::TempPCHFile::
|
||||
operator=(TempPCHFile &&Other) {
|
||||
RemoveFileIfPresent();
|
||||
|
||||
FilePath = std::move(Other.FilePath);
|
||||
Other.FilePath = None;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PrecompiledPreamble::TempPCHFile::~TempPCHFile() { RemoveFileIfPresent(); }
|
||||
|
||||
void PrecompiledPreamble::TempPCHFile::RemoveFileIfPresent() {
|
||||
if (FilePath) {
|
||||
TemporaryFiles::getInstance().removeFile(*FilePath);
|
||||
FilePath = None;
|
||||
}
|
||||
}
|
||||
|
||||
llvm::StringRef PrecompiledPreamble::TempPCHFile::getFilePath() const {
|
||||
assert(FilePath && "TempPCHFile doesn't have a FilePath. Had it been moved?");
|
||||
return *FilePath;
|
||||
}
|
||||
|
||||
PrecompiledPreamble::PreambleFileHash
|
||||
PrecompiledPreamble::PreambleFileHash::createForFile(off_t Size,
|
||||
time_t ModTime) {
|
||||
PreambleFileHash Result;
|
||||
Result.Size = Size;
|
||||
Result.ModTime = ModTime;
|
||||
Result.MD5 = {};
|
||||
return Result;
|
||||
}
|
||||
|
||||
PrecompiledPreamble::PreambleFileHash
|
||||
PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(
|
||||
const llvm::MemoryBuffer *Buffer) {
|
||||
PreambleFileHash Result;
|
||||
Result.Size = Buffer->getBufferSize();
|
||||
Result.ModTime = 0;
|
||||
|
||||
llvm::MD5 MD5Ctx;
|
||||
MD5Ctx.update(Buffer->getBuffer().data());
|
||||
MD5Ctx.final(Result.MD5);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
void PreambleCallbacks::AfterExecute(CompilerInstance &CI) {}
|
||||
void PreambleCallbacks::AfterPCHEmitted(ASTWriter &Writer) {}
|
||||
void PreambleCallbacks::HandleTopLevelDecl(DeclGroupRef DG) {}
|
||||
void PreambleCallbacks::HandleMacroDefined(const Token &MacroNameTok,
|
||||
const MacroDirective *MD) {}
|
||||
|
||||
std::error_code clang::make_error_code(BuildPreambleError Error) {
|
||||
return std::error_code(static_cast<int>(Error), BuildPreambleErrorCategory());
|
||||
}
|
||||
|
||||
const char *BuildPreambleErrorCategory::name() const noexcept {
|
||||
return "build-preamble.error";
|
||||
}
|
||||
|
||||
std::string BuildPreambleErrorCategory::message(int condition) const {
|
||||
switch (static_cast<BuildPreambleError>(condition)) {
|
||||
case BuildPreambleError::PreambleIsEmpty:
|
||||
return "Preamble is empty";
|
||||
case BuildPreambleError::CouldntCreateTempFile:
|
||||
return "Could not create temporary file for PCH";
|
||||
case BuildPreambleError::CouldntCreateTargetInfo:
|
||||
return "CreateTargetInfo() return null";
|
||||
case BuildPreambleError::CouldntCreateVFSOverlay:
|
||||
return "Could not create VFS Overlay";
|
||||
case BuildPreambleError::BeginSourceFileFailed:
|
||||
return "BeginSourceFile() return an error";
|
||||
case BuildPreambleError::CouldntEmitPCH:
|
||||
return "Could not emit PCH";
|
||||
}
|
||||
llvm_unreachable("unexpected BuildPreambleError");
|
||||
}
|
@ -349,7 +349,7 @@ void PrintPPOutputPPCallbacks::InclusionDirective(SourceLocation HashLoc,
|
||||
case tok::pp_include_next:
|
||||
startNewLineIfNeeded();
|
||||
MoveToLine(HashLoc);
|
||||
OS << "#pragma clang module import " << Imported->getFullModuleName()
|
||||
OS << "#pragma clang module import " << Imported->getFullModuleName(true)
|
||||
<< " /* clang -E: implicit import for "
|
||||
<< "#" << PP.getSpelling(IncludeTok) << " "
|
||||
<< (IsAngled ? '<' : '"') << FileName << (IsAngled ? '>' : '"')
|
||||
@ -378,14 +378,14 @@ void PrintPPOutputPPCallbacks::InclusionDirective(SourceLocation HashLoc,
|
||||
/// Handle entering the scope of a module during a module compilation.
|
||||
void PrintPPOutputPPCallbacks::BeginModule(const Module *M) {
|
||||
startNewLineIfNeeded();
|
||||
OS << "#pragma clang module begin " << M->getFullModuleName();
|
||||
OS << "#pragma clang module begin " << M->getFullModuleName(true);
|
||||
setEmittedDirectiveOnThisLine();
|
||||
}
|
||||
|
||||
/// Handle leaving the scope of a module during a module compilation.
|
||||
void PrintPPOutputPPCallbacks::EndModule(const Module *M) {
|
||||
startNewLineIfNeeded();
|
||||
OS << "#pragma clang module end /*" << M->getFullModuleName() << "*/";
|
||||
OS << "#pragma clang module end /*" << M->getFullModuleName(true) << "*/";
|
||||
setEmittedDirectiveOnThisLine();
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "clang/Rewrite/Frontend/FrontendActions.h"
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/Basic/CharInfo.h"
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
#include "clang/Frontend/FrontendActions.h"
|
||||
#include "clang/Frontend/FrontendDiagnostic.h"
|
||||
@ -224,7 +225,15 @@ class RewriteIncludesAction::RewriteImportsListener : public ASTReaderListener {
|
||||
auto OS = Out.lock();
|
||||
assert(OS && "loaded module file after finishing rewrite action?");
|
||||
|
||||
(*OS) << "#pragma clang module build " << MF->ModuleName << "\n";
|
||||
(*OS) << "#pragma clang module build ";
|
||||
if (isValidIdentifier(MF->ModuleName))
|
||||
(*OS) << MF->ModuleName;
|
||||
else {
|
||||
(*OS) << '"';
|
||||
OS->write_escaped(MF->ModuleName);
|
||||
(*OS) << '"';
|
||||
}
|
||||
(*OS) << '\n';
|
||||
|
||||
// Rewrite the contents of the module in a separate compiler instance.
|
||||
CompilerInstance Instance(CI.getPCHContainerOperations(),
|
||||
@ -234,9 +243,12 @@ class RewriteIncludesAction::RewriteImportsListener : public ASTReaderListener {
|
||||
Instance.createDiagnostics(
|
||||
new ForwardingDiagnosticConsumer(CI.getDiagnosticClient()),
|
||||
/*ShouldOwnClient=*/true);
|
||||
Instance.getFrontendOpts().DisableFree = false;
|
||||
Instance.getFrontendOpts().Inputs.clear();
|
||||
Instance.getFrontendOpts().Inputs.emplace_back(
|
||||
Filename, InputKind(InputKind::Unknown, InputKind::Precompiled));
|
||||
Instance.getFrontendOpts().ModuleFiles.clear();
|
||||
Instance.getFrontendOpts().ModuleMapFiles.clear();
|
||||
// Don't recursively rewrite imports. We handle them all at the top level.
|
||||
Instance.getPreprocessorOutputOpts().RewriteImports = false;
|
||||
|
||||
|
@ -140,7 +140,7 @@ void InclusionRewriter::WriteLineInfo(StringRef Filename, int Line,
|
||||
}
|
||||
|
||||
void InclusionRewriter::WriteImplicitModuleImport(const Module *Mod) {
|
||||
OS << "#pragma clang module import " << Mod->getFullModuleName()
|
||||
OS << "#pragma clang module import " << Mod->getFullModuleName(true)
|
||||
<< " /* clang -frewrite-includes: implicit import */" << MainEOL;
|
||||
}
|
||||
|
||||
@ -471,15 +471,15 @@ void InclusionRewriter::Process(FileID FileId,
|
||||
else if (const IncludedFile *Inc = FindIncludeAtLocation(Loc)) {
|
||||
const Module *Mod = FindEnteredModule(Loc);
|
||||
if (Mod)
|
||||
OS << "#pragma clang module begin " << Mod->getFullModuleName()
|
||||
<< "\n";
|
||||
OS << "#pragma clang module begin "
|
||||
<< Mod->getFullModuleName(true) << "\n";
|
||||
|
||||
// Include and recursively process the file.
|
||||
Process(Inc->Id, Inc->FileType);
|
||||
|
||||
if (Mod)
|
||||
OS << "#pragma clang module end /*" << Mod->getFullModuleName()
|
||||
<< "*/\n";
|
||||
OS << "#pragma clang module end /*"
|
||||
<< Mod->getFullModuleName(true) << "*/\n";
|
||||
|
||||
// Add line marker to indicate we're returning from an included
|
||||
// file.
|
||||
|
@ -351,9 +351,11 @@ class IndexingDeclVisitor : public ConstDeclVisitor<IndexingDeclVisitor, bool> {
|
||||
IndexCtx.indexTagDecl(D, Relations);
|
||||
} else {
|
||||
auto *Parent = dyn_cast<NamedDecl>(D->getDeclContext());
|
||||
SmallVector<SymbolRelation, 1> Relations;
|
||||
gatherTemplatePseudoOverrides(D, Relations);
|
||||
return IndexCtx.handleReference(D, D->getLocation(), Parent,
|
||||
D->getLexicalDeclContext(),
|
||||
SymbolRoleSet());
|
||||
SymbolRoleSet(), Relations);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@ -609,18 +611,16 @@ class IndexingDeclVisitor : public ConstDeclVisitor<IndexingDeclVisitor, bool> {
|
||||
ClassTemplateSpecializationDecl *D) {
|
||||
// FIXME: Notify subsequent callbacks if info comes from implicit
|
||||
// instantiation.
|
||||
if (D->isThisDeclarationADefinition()) {
|
||||
llvm::PointerUnion<ClassTemplateDecl *,
|
||||
ClassTemplatePartialSpecializationDecl *>
|
||||
Template = D->getSpecializedTemplateOrPartial();
|
||||
const Decl *SpecializationOf =
|
||||
Template.is<ClassTemplateDecl *>()
|
||||
? (Decl *)Template.get<ClassTemplateDecl *>()
|
||||
: Template.get<ClassTemplatePartialSpecializationDecl *>();
|
||||
IndexCtx.indexTagDecl(
|
||||
D, SymbolRelation(SymbolRoleSet(SymbolRole::RelationSpecializationOf),
|
||||
SpecializationOf));
|
||||
}
|
||||
llvm::PointerUnion<ClassTemplateDecl *,
|
||||
ClassTemplatePartialSpecializationDecl *>
|
||||
Template = D->getSpecializedTemplateOrPartial();
|
||||
const Decl *SpecializationOf =
|
||||
Template.is<ClassTemplateDecl *>()
|
||||
? (Decl *)Template.get<ClassTemplateDecl *>()
|
||||
: Template.get<ClassTemplatePartialSpecializationDecl *>();
|
||||
IndexCtx.indexTagDecl(
|
||||
D, SymbolRelation(SymbolRoleSet(SymbolRole::RelationSpecializationOf),
|
||||
SpecializationOf));
|
||||
if (TypeSourceInfo *TSI = D->getTypeAsWritten())
|
||||
IndexCtx.indexTypeSourceInfo(TSI, /*Parent=*/nullptr,
|
||||
D->getLexicalDeclContext());
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "clang/Lex/LexDiagnostic.h"
|
||||
#include "clang/Lex/LiteralSupport.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Lex/PreprocessorOptions.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
@ -2750,7 +2751,7 @@ static const char *findPlaceholderEnd(const char *CurPtr,
|
||||
|
||||
bool Lexer::lexEditorPlaceholder(Token &Result, const char *CurPtr) {
|
||||
assert(CurPtr[-1] == '<' && CurPtr[0] == '#' && "Not a placeholder!");
|
||||
if (!PP || LexingRawMode)
|
||||
if (!PP || !PP->getPreprocessorOpts().LexEditorPlaceholders || LexingRawMode)
|
||||
return false;
|
||||
const char *End = findPlaceholderEnd(CurPtr + 1, BufferEnd);
|
||||
if (!End)
|
||||
|
@ -538,7 +538,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
|
||||
assert(CurPPLexer->LexingRawMode && "We have to be skipping here!");
|
||||
CurPPLexer->LexingRawMode = false;
|
||||
IdentifierInfo *IfNDefMacro = nullptr;
|
||||
const bool CondValue = EvaluateDirectiveExpression(IfNDefMacro);
|
||||
const bool CondValue = EvaluateDirectiveExpression(IfNDefMacro).Conditional;
|
||||
CurPPLexer->LexingRawMode = true;
|
||||
if (Callbacks) {
|
||||
const SourceLocation CondEnd = CurPPLexer->getSourceLocation();
|
||||
@ -635,7 +635,7 @@ void Preprocessor::PTHSkipExcludedConditionalBlock() {
|
||||
// Evaluate the condition of the #elif.
|
||||
IdentifierInfo *IfNDefMacro = nullptr;
|
||||
CurPTHLexer->ParsingPreprocessorDirective = true;
|
||||
bool ShouldEnter = EvaluateDirectiveExpression(IfNDefMacro);
|
||||
bool ShouldEnter = EvaluateDirectiveExpression(IfNDefMacro).Conditional;
|
||||
CurPTHLexer->ParsingPreprocessorDirective = false;
|
||||
|
||||
// If this condition is true, enter it!
|
||||
@ -2654,7 +2654,13 @@ void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef,
|
||||
}
|
||||
|
||||
// Should we include the stuff contained by this directive?
|
||||
if (!MI == isIfndef) {
|
||||
if (PPOpts->SingleFileParseMode && !MI) {
|
||||
// In 'single-file-parse mode' undefined identifiers trigger parsing of all
|
||||
// the directive blocks.
|
||||
CurPPLexer->pushConditionalLevel(DirectiveTok.getLocation(),
|
||||
/*wasskip*/false, /*foundnonskip*/false,
|
||||
/*foundelse*/false);
|
||||
} else if (!MI == isIfndef) {
|
||||
// Yes, remember that we are inside a conditional, then lex the next token.
|
||||
CurPPLexer->pushConditionalLevel(DirectiveTok.getLocation(),
|
||||
/*wasskip*/false, /*foundnonskip*/true,
|
||||
@ -2676,7 +2682,8 @@ void Preprocessor::HandleIfDirective(Token &IfToken,
|
||||
// Parse and evaluate the conditional expression.
|
||||
IdentifierInfo *IfNDefMacro = nullptr;
|
||||
const SourceLocation ConditionalBegin = CurPPLexer->getSourceLocation();
|
||||
const bool ConditionalTrue = EvaluateDirectiveExpression(IfNDefMacro);
|
||||
const DirectiveEvalResult DER = EvaluateDirectiveExpression(IfNDefMacro);
|
||||
const bool ConditionalTrue = DER.Conditional;
|
||||
const SourceLocation ConditionalEnd = CurPPLexer->getSourceLocation();
|
||||
|
||||
// If this condition is equivalent to #ifndef X, and if this is the first
|
||||
@ -2695,7 +2702,12 @@ void Preprocessor::HandleIfDirective(Token &IfToken,
|
||||
(ConditionalTrue ? PPCallbacks::CVK_True : PPCallbacks::CVK_False));
|
||||
|
||||
// Should we include the stuff contained by this directive?
|
||||
if (ConditionalTrue) {
|
||||
if (PPOpts->SingleFileParseMode && DER.IncludedUndefinedIds) {
|
||||
// In 'single-file-parse mode' undefined identifiers trigger parsing of all
|
||||
// the directive blocks.
|
||||
CurPPLexer->pushConditionalLevel(IfToken.getLocation(), /*wasskip*/false,
|
||||
/*foundnonskip*/false, /*foundelse*/false);
|
||||
} else if (ConditionalTrue) {
|
||||
// Yes, remember that we are inside a conditional, then lex the next token.
|
||||
CurPPLexer->pushConditionalLevel(IfToken.getLocation(), /*wasskip*/false,
|
||||
/*foundnonskip*/true, /*foundelse*/false);
|
||||
@ -2756,6 +2768,14 @@ void Preprocessor::HandleElseDirective(Token &Result) {
|
||||
if (Callbacks)
|
||||
Callbacks->Else(Result.getLocation(), CI.IfLoc);
|
||||
|
||||
if (PPOpts->SingleFileParseMode && !CI.FoundNonSkip) {
|
||||
// In 'single-file-parse mode' undefined identifiers trigger parsing of all
|
||||
// the directive blocks.
|
||||
CurPPLexer->pushConditionalLevel(CI.IfLoc, /*wasskip*/false,
|
||||
/*foundnonskip*/false, /*foundelse*/true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Finally, skip the rest of the contents of this block.
|
||||
SkipExcludedConditionalBlock(CI.IfLoc, /*Foundnonskip*/true,
|
||||
/*FoundElse*/true, Result.getLocation());
|
||||
@ -2791,6 +2811,14 @@ void Preprocessor::HandleElifDirective(Token &ElifToken) {
|
||||
SourceRange(ConditionalBegin, ConditionalEnd),
|
||||
PPCallbacks::CVK_NotEvaluated, CI.IfLoc);
|
||||
|
||||
if (PPOpts->SingleFileParseMode && !CI.FoundNonSkip) {
|
||||
// In 'single-file-parse mode' undefined identifiers trigger parsing of all
|
||||
// the directive blocks.
|
||||
CurPPLexer->pushConditionalLevel(ElifToken.getLocation(), /*wasskip*/false,
|
||||
/*foundnonskip*/false, /*foundelse*/false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Finally, skip the rest of the contents of this block.
|
||||
SkipExcludedConditionalBlock(CI.IfLoc, /*Foundnonskip*/true,
|
||||
/*FoundElse*/CI.FoundElse,
|
||||
|
@ -73,6 +73,7 @@ class PPValue {
|
||||
|
||||
static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
|
||||
Token &PeekTok, bool ValueLive,
|
||||
bool &IncludedUndefinedIds,
|
||||
Preprocessor &PP);
|
||||
|
||||
/// DefinedTracker - This struct is used while parsing expressions to keep track
|
||||
@ -93,6 +94,7 @@ struct DefinedTracker {
|
||||
/// TheMacro - When the state is DefinedMacro or NotDefinedMacro, this
|
||||
/// indicates the macro that was checked.
|
||||
IdentifierInfo *TheMacro;
|
||||
bool IncludedUndefinedIds = false;
|
||||
};
|
||||
|
||||
/// EvaluateDefined - Process a 'defined(sym)' expression.
|
||||
@ -128,6 +130,7 @@ static bool EvaluateDefined(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
|
||||
MacroDefinition Macro = PP.getMacroDefinition(II);
|
||||
Result.Val = !!Macro;
|
||||
Result.Val.setIsUnsigned(false); // Result is signed intmax_t.
|
||||
DT.IncludedUndefinedIds = !Macro;
|
||||
|
||||
// If there is a macro, mark it used.
|
||||
if (Result.Val != 0 && ValueLive)
|
||||
@ -255,6 +258,8 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
|
||||
Result.Val.setIsUnsigned(false); // "0" is signed intmax_t 0.
|
||||
Result.setIdentifier(II);
|
||||
Result.setRange(PeekTok.getLocation());
|
||||
DT.IncludedUndefinedIds = (II->getTokenID() != tok::kw_true &&
|
||||
II->getTokenID() != tok::kw_false);
|
||||
PP.LexNonComment(PeekTok);
|
||||
return false;
|
||||
}
|
||||
@ -400,7 +405,8 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
|
||||
// Just use DT unmodified as our result.
|
||||
} else {
|
||||
// Otherwise, we have something like (x+y), and we consumed '(x'.
|
||||
if (EvaluateDirectiveSubExpr(Result, 1, PeekTok, ValueLive, PP))
|
||||
if (EvaluateDirectiveSubExpr(Result, 1, PeekTok, ValueLive,
|
||||
DT.IncludedUndefinedIds, PP))
|
||||
return true;
|
||||
|
||||
if (PeekTok.isNot(tok::r_paren)) {
|
||||
@ -532,6 +538,7 @@ static void diagnoseUnexpectedOperator(Preprocessor &PP, PPValue &LHS,
|
||||
/// evaluation, such as division by zero warnings.
|
||||
static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
|
||||
Token &PeekTok, bool ValueLive,
|
||||
bool &IncludedUndefinedIds,
|
||||
Preprocessor &PP) {
|
||||
unsigned PeekPrec = getPrecedence(PeekTok.getKind());
|
||||
// If this token isn't valid, report the error.
|
||||
@ -571,6 +578,7 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
|
||||
// Parse the RHS of the operator.
|
||||
DefinedTracker DT;
|
||||
if (EvaluateValue(RHS, PeekTok, DT, RHSIsLive, PP)) return true;
|
||||
IncludedUndefinedIds = DT.IncludedUndefinedIds;
|
||||
|
||||
// Remember the precedence of this operator and get the precedence of the
|
||||
// operator immediately to the right of the RHS.
|
||||
@ -601,7 +609,8 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
|
||||
RHSPrec = ThisPrec+1;
|
||||
|
||||
if (PeekPrec >= RHSPrec) {
|
||||
if (EvaluateDirectiveSubExpr(RHS, RHSPrec, PeekTok, RHSIsLive, PP))
|
||||
if (EvaluateDirectiveSubExpr(RHS, RHSPrec, PeekTok, RHSIsLive,
|
||||
IncludedUndefinedIds, PP))
|
||||
return true;
|
||||
PeekPrec = getPrecedence(PeekTok.getKind());
|
||||
}
|
||||
@ -769,7 +778,8 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
|
||||
// Parse anything after the : with the same precedence as ?. We allow
|
||||
// things of equal precedence because ?: is right associative.
|
||||
if (EvaluateDirectiveSubExpr(AfterColonVal, ThisPrec,
|
||||
PeekTok, AfterColonLive, PP))
|
||||
PeekTok, AfterColonLive,
|
||||
IncludedUndefinedIds, PP))
|
||||
return true;
|
||||
|
||||
// Now that we have the condition, the LHS and the RHS of the :, evaluate.
|
||||
@ -806,7 +816,8 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
|
||||
/// EvaluateDirectiveExpression - Evaluate an integer constant expression that
|
||||
/// may occur after a #if or #elif directive. If the expression is equivalent
|
||||
/// to "!defined(X)" return X in IfNDefMacro.
|
||||
bool Preprocessor::EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
|
||||
Preprocessor::DirectiveEvalResult
|
||||
Preprocessor::EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
|
||||
SaveAndRestore<bool> PPDir(ParsingIfOrElifDirective, true);
|
||||
// Save the current state of 'DisableMacroExpansion' and reset it to false. If
|
||||
// 'DisableMacroExpansion' is true, then we must be in a macro argument list
|
||||
@ -833,7 +844,7 @@ bool Preprocessor::EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
|
||||
|
||||
// Restore 'DisableMacroExpansion'.
|
||||
DisableMacroExpansion = DisableMacroExpansionAtStartOfDirective;
|
||||
return false;
|
||||
return {false, DT.IncludedUndefinedIds};
|
||||
}
|
||||
|
||||
// If we are at the end of the expression after just parsing a value, there
|
||||
@ -847,20 +858,20 @@ bool Preprocessor::EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
|
||||
|
||||
// Restore 'DisableMacroExpansion'.
|
||||
DisableMacroExpansion = DisableMacroExpansionAtStartOfDirective;
|
||||
return ResVal.Val != 0;
|
||||
return {ResVal.Val != 0, DT.IncludedUndefinedIds};
|
||||
}
|
||||
|
||||
// Otherwise, we must have a binary operator (e.g. "#if 1 < 2"), so parse the
|
||||
// operator and the stuff after it.
|
||||
if (EvaluateDirectiveSubExpr(ResVal, getPrecedence(tok::question),
|
||||
Tok, true, *this)) {
|
||||
Tok, true, DT.IncludedUndefinedIds, *this)) {
|
||||
// Parse error, skip the rest of the macro line.
|
||||
if (Tok.isNot(tok::eod))
|
||||
DiscardUntilEndOfDirective();
|
||||
|
||||
// Restore 'DisableMacroExpansion'.
|
||||
DisableMacroExpansion = DisableMacroExpansionAtStartOfDirective;
|
||||
return false;
|
||||
return {false, DT.IncludedUndefinedIds};
|
||||
}
|
||||
|
||||
// If we aren't at the tok::eod token, something bad happened, like an extra
|
||||
@ -872,5 +883,5 @@ bool Preprocessor::EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
|
||||
|
||||
// Restore 'DisableMacroExpansion'.
|
||||
DisableMacroExpansion = DisableMacroExpansionAtStartOfDirective;
|
||||
return ResVal.Val != 0;
|
||||
return {ResVal.Val != 0, DT.IncludedUndefinedIds};
|
||||
}
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "clang/Basic/TokenKinds.h"
|
||||
#include "clang/Lex/HeaderSearch.h"
|
||||
#include "clang/Lex/LexDiagnostic.h"
|
||||
#include "clang/Lex/LiteralSupport.h"
|
||||
#include "clang/Lex/MacroInfo.h"
|
||||
#include "clang/Lex/PPCallbacks.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
@ -754,15 +755,52 @@ void Preprocessor::HandlePragmaIncludeAlias(Token &Tok) {
|
||||
getHeaderSearchInfo().AddIncludeAlias(OriginalSource, ReplaceFileName);
|
||||
}
|
||||
|
||||
// Lex a component of a module name: either an identifier or a string literal;
|
||||
// for components that can be expressed both ways, the two forms are equivalent.
|
||||
static bool LexModuleNameComponent(
|
||||
Preprocessor &PP, Token &Tok,
|
||||
std::pair<IdentifierInfo *, SourceLocation> &ModuleNameComponent,
|
||||
bool First) {
|
||||
PP.LexUnexpandedToken(Tok);
|
||||
if (Tok.is(tok::string_literal) && !Tok.hasUDSuffix()) {
|
||||
StringLiteralParser Literal(Tok, PP);
|
||||
if (Literal.hadError)
|
||||
return true;
|
||||
ModuleNameComponent = std::make_pair(
|
||||
PP.getIdentifierInfo(Literal.GetString()), Tok.getLocation());
|
||||
} else if (!Tok.isAnnotation() && Tok.getIdentifierInfo()) {
|
||||
ModuleNameComponent =
|
||||
std::make_pair(Tok.getIdentifierInfo(), Tok.getLocation());
|
||||
} else {
|
||||
PP.Diag(Tok.getLocation(), diag::err_pp_expected_module_name) << First;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool LexModuleName(
|
||||
Preprocessor &PP, Token &Tok,
|
||||
llvm::SmallVectorImpl<std::pair<IdentifierInfo *, SourceLocation>>
|
||||
&ModuleName) {
|
||||
while (true) {
|
||||
std::pair<IdentifierInfo*, SourceLocation> NameComponent;
|
||||
if (LexModuleNameComponent(PP, Tok, NameComponent, ModuleName.empty()))
|
||||
return true;
|
||||
ModuleName.push_back(NameComponent);
|
||||
|
||||
PP.LexUnexpandedToken(Tok);
|
||||
if (Tok.isNot(tok::period))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Preprocessor::HandlePragmaModuleBuild(Token &Tok) {
|
||||
SourceLocation Loc = Tok.getLocation();
|
||||
|
||||
LexUnexpandedToken(Tok);
|
||||
if (Tok.isAnnotation() || !Tok.getIdentifierInfo()) {
|
||||
Diag(Tok.getLocation(), diag::err_pp_expected_module_name) << true;
|
||||
std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc;
|
||||
if (LexModuleNameComponent(*this, Tok, ModuleNameLoc, true))
|
||||
return;
|
||||
}
|
||||
IdentifierInfo *ModuleName = Tok.getIdentifierInfo();
|
||||
IdentifierInfo *ModuleName = ModuleNameLoc.first;
|
||||
|
||||
LexUnexpandedToken(Tok);
|
||||
if (Tok.isNot(tok::eod)) {
|
||||
@ -1383,26 +1421,6 @@ struct PragmaMessageHandler : public PragmaHandler {
|
||||
}
|
||||
};
|
||||
|
||||
static bool LexModuleName(
|
||||
Preprocessor &PP, Token &Tok,
|
||||
llvm::SmallVectorImpl<std::pair<IdentifierInfo *, SourceLocation>>
|
||||
&ModuleName) {
|
||||
while (true) {
|
||||
PP.LexUnexpandedToken(Tok);
|
||||
if (Tok.isAnnotation() || !Tok.getIdentifierInfo()) {
|
||||
PP.Diag(Tok.getLocation(), diag::err_pp_expected_module_name)
|
||||
<< ModuleName.empty();
|
||||
return true;
|
||||
}
|
||||
|
||||
ModuleName.emplace_back(Tok.getIdentifierInfo(), Tok.getLocation());
|
||||
|
||||
PP.LexUnexpandedToken(Tok);
|
||||
if (Tok.isNot(tok::period))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle the clang \#pragma module import extension. The syntax is:
|
||||
/// \code
|
||||
/// #pragma clang module import some.module.name
|
||||
@ -1473,7 +1491,7 @@ struct PragmaModuleBeginHandler : public PragmaHandler {
|
||||
// be loaded or implicitly loadable.
|
||||
// FIXME: We could create the submodule here. We'd need to know whether
|
||||
// it's supposed to be explicit, but not much else.
|
||||
Module *M = PP.getHeaderSearchInfo().getModuleMap().findModule(Current);
|
||||
Module *M = PP.getHeaderSearchInfo().lookupModule(Current);
|
||||
if (!M) {
|
||||
PP.Diag(ModuleName.front().second,
|
||||
diag::err_pp_module_begin_no_module_map) << Current;
|
||||
|
@ -2629,6 +2629,8 @@ Parser::getDeclSpecContextFromDeclaratorContext(unsigned Context) {
|
||||
return DSC_class;
|
||||
if (Context == Declarator::FileContext)
|
||||
return DSC_top_level;
|
||||
if (Context == Declarator::TemplateParamContext)
|
||||
return DSC_template_param;
|
||||
if (Context == Declarator::TemplateTypeArgContext)
|
||||
return DSC_template_type_arg;
|
||||
if (Context == Declarator::TrailingReturnContext)
|
||||
@ -4261,7 +4263,9 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
|
||||
AS, DS.getModulePrivateSpecLoc(), TParams,
|
||||
Owned, IsDependent, ScopedEnumKWLoc,
|
||||
IsScopedUsingClassTag, BaseType,
|
||||
DSC == DSC_type_specifier, &SkipBody);
|
||||
DSC == DSC_type_specifier,
|
||||
DSC == DSC_template_param ||
|
||||
DSC == DSC_template_type_arg, &SkipBody);
|
||||
|
||||
if (SkipBody.ShouldSkip) {
|
||||
assert(TUK == Sema::TUK_Definition && "can only skip a definition");
|
||||
|
@ -1887,7 +1887,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
|
||||
SourceLocation(), false,
|
||||
clang::TypeResult(),
|
||||
DSC == DSC_type_specifier,
|
||||
&SkipBody);
|
||||
DSC == DSC_template_param ||
|
||||
DSC == DSC_template_type_arg, &SkipBody);
|
||||
|
||||
// If ActOnTag said the type was dependent, try again with the
|
||||
// less common call.
|
||||
|
@ -3627,6 +3627,14 @@ void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) {
|
||||
SourceLocation OrigLoc = Tok.getLocation();
|
||||
|
||||
assert(!LM.Toks.empty() && "ParseLexedObjCMethodDef - Empty body!");
|
||||
// Store an artificial EOF token to ensure that we don't run off the end of
|
||||
// the method's body when we come to parse it.
|
||||
Token Eof;
|
||||
Eof.startToken();
|
||||
Eof.setKind(tok::eof);
|
||||
Eof.setEofData(MCDecl);
|
||||
Eof.setLocation(OrigLoc);
|
||||
LM.Toks.push_back(Eof);
|
||||
// Append the current token at the end of the new token stream so that it
|
||||
// doesn't get lost.
|
||||
LM.Toks.push_back(Tok);
|
||||
@ -3658,7 +3666,7 @@ void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) {
|
||||
Actions.ActOnDefaultCtorInitializers(MCDecl);
|
||||
ParseFunctionStatementBody(MCDecl, BodyScope);
|
||||
}
|
||||
|
||||
|
||||
if (Tok.getLocation() != OrigLoc) {
|
||||
// Due to parsing error, we either went over the cached tokens or
|
||||
// there are still cached tokens left. If it's the latter case skip the
|
||||
@ -3670,4 +3678,6 @@ void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) {
|
||||
while (Tok.getLocation() != OrigLoc && Tok.isNot(tok::eof))
|
||||
ConsumeAnyToken();
|
||||
}
|
||||
// Clean up the remaining EOF token.
|
||||
ConsumeAnyToken();
|
||||
}
|
||||
|
@ -674,7 +674,8 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
|
||||
// FIXME: The type should probably be restricted in some way... Not all
|
||||
// declarators (parts of declarators?) are accepted for parameters.
|
||||
DeclSpec DS(AttrFactory);
|
||||
ParseDeclarationSpecifiers(DS);
|
||||
ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none,
|
||||
DSC_template_param);
|
||||
|
||||
// Parse this as a typename.
|
||||
Declarator ParamDecl(DS, Declarator::TemplateParamContext);
|
||||
|
@ -278,6 +278,150 @@ static void checkRecursiveFunction(Sema &S, const FunctionDecl *FD,
|
||||
S.Diag(Body->getLocStart(), diag::warn_infinite_recursive_function);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Check for throw in a non-throwing function.
|
||||
//===----------------------------------------------------------------------===//
|
||||
enum ThrowState {
|
||||
FoundNoPathForThrow,
|
||||
FoundPathForThrow,
|
||||
FoundPathWithNoThrowOutFunction,
|
||||
};
|
||||
|
||||
static bool isThrowCaught(const CXXThrowExpr *Throw,
|
||||
const CXXCatchStmt *Catch) {
|
||||
const Type *ThrowType = nullptr;
|
||||
if (Throw->getSubExpr())
|
||||
ThrowType = Throw->getSubExpr()->getType().getTypePtrOrNull();
|
||||
if (!ThrowType)
|
||||
return false;
|
||||
const Type *CaughtType = Catch->getCaughtType().getTypePtrOrNull();
|
||||
if (!CaughtType)
|
||||
return true;
|
||||
if (ThrowType->isReferenceType())
|
||||
ThrowType = ThrowType->castAs<ReferenceType>()
|
||||
->getPointeeType()
|
||||
->getUnqualifiedDesugaredType();
|
||||
if (CaughtType->isReferenceType())
|
||||
CaughtType = CaughtType->castAs<ReferenceType>()
|
||||
->getPointeeType()
|
||||
->getUnqualifiedDesugaredType();
|
||||
if (CaughtType == ThrowType)
|
||||
return true;
|
||||
const CXXRecordDecl *CaughtAsRecordType =
|
||||
CaughtType->getPointeeCXXRecordDecl();
|
||||
const CXXRecordDecl *ThrowTypeAsRecordType = ThrowType->getAsCXXRecordDecl();
|
||||
if (CaughtAsRecordType && ThrowTypeAsRecordType)
|
||||
return ThrowTypeAsRecordType->isDerivedFrom(CaughtAsRecordType);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool isThrowCaughtByHandlers(const CXXThrowExpr *CE,
|
||||
const CXXTryStmt *TryStmt) {
|
||||
for (unsigned H = 0, E = TryStmt->getNumHandlers(); H < E; ++H) {
|
||||
if (isThrowCaught(CE, TryStmt->getHandler(H)))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool doesThrowEscapePath(CFGBlock Block, SourceLocation &OpLoc) {
|
||||
for (const auto &B : Block) {
|
||||
if (B.getKind() != CFGElement::Statement)
|
||||
continue;
|
||||
const auto *CE = dyn_cast<CXXThrowExpr>(B.getAs<CFGStmt>()->getStmt());
|
||||
if (!CE)
|
||||
continue;
|
||||
|
||||
OpLoc = CE->getThrowLoc();
|
||||
for (const auto &I : Block.succs()) {
|
||||
if (!I.isReachable())
|
||||
continue;
|
||||
if (const auto *Terminator =
|
||||
dyn_cast_or_null<CXXTryStmt>(I->getTerminator()))
|
||||
if (isThrowCaughtByHandlers(CE, Terminator))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool hasThrowOutNonThrowingFunc(SourceLocation &OpLoc, CFG *BodyCFG) {
|
||||
|
||||
unsigned ExitID = BodyCFG->getExit().getBlockID();
|
||||
|
||||
SmallVector<ThrowState, 16> States(BodyCFG->getNumBlockIDs(),
|
||||
FoundNoPathForThrow);
|
||||
States[BodyCFG->getEntry().getBlockID()] = FoundPathWithNoThrowOutFunction;
|
||||
|
||||
SmallVector<CFGBlock *, 16> Stack;
|
||||
Stack.push_back(&BodyCFG->getEntry());
|
||||
while (!Stack.empty()) {
|
||||
CFGBlock *CurBlock = Stack.back();
|
||||
Stack.pop_back();
|
||||
|
||||
unsigned ID = CurBlock->getBlockID();
|
||||
ThrowState CurState = States[ID];
|
||||
if (CurState == FoundPathWithNoThrowOutFunction) {
|
||||
if (ExitID == ID)
|
||||
continue;
|
||||
|
||||
if (doesThrowEscapePath(*CurBlock, OpLoc))
|
||||
CurState = FoundPathForThrow;
|
||||
}
|
||||
|
||||
// Loop over successor blocks and add them to the Stack if their state
|
||||
// changes.
|
||||
for (const auto &I : CurBlock->succs())
|
||||
if (I.isReachable()) {
|
||||
unsigned NextID = I->getBlockID();
|
||||
if (NextID == ExitID && CurState == FoundPathForThrow) {
|
||||
States[NextID] = CurState;
|
||||
} else if (States[NextID] < CurState) {
|
||||
States[NextID] = CurState;
|
||||
Stack.push_back(I);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Return true if the exit node is reachable, and only reachable through
|
||||
// a throw expression.
|
||||
return States[ExitID] == FoundPathForThrow;
|
||||
}
|
||||
|
||||
static void EmitDiagForCXXThrowInNonThrowingFunc(Sema &S, SourceLocation OpLoc,
|
||||
const FunctionDecl *FD) {
|
||||
if (!S.getSourceManager().isInSystemHeader(OpLoc)) {
|
||||
S.Diag(OpLoc, diag::warn_throw_in_noexcept_func) << FD;
|
||||
if (S.getLangOpts().CPlusPlus11 &&
|
||||
(isa<CXXDestructorDecl>(FD) ||
|
||||
FD->getDeclName().getCXXOverloadedOperator() == OO_Delete ||
|
||||
FD->getDeclName().getCXXOverloadedOperator() == OO_Array_Delete))
|
||||
S.Diag(FD->getLocation(), diag::note_throw_in_dtor);
|
||||
else
|
||||
S.Diag(FD->getLocation(), diag::note_throw_in_function);
|
||||
}
|
||||
}
|
||||
|
||||
static void checkThrowInNonThrowingFunc(Sema &S, const FunctionDecl *FD,
|
||||
AnalysisDeclContext &AC) {
|
||||
CFG *BodyCFG = AC.getCFG();
|
||||
if (!BodyCFG)
|
||||
return;
|
||||
if (BodyCFG->getExit().pred_empty())
|
||||
return;
|
||||
SourceLocation OpLoc;
|
||||
if (hasThrowOutNonThrowingFunc(OpLoc, BodyCFG))
|
||||
EmitDiagForCXXThrowInNonThrowingFunc(S, OpLoc, FD);
|
||||
}
|
||||
|
||||
static bool isNoexcept(const FunctionDecl *FD) {
|
||||
const auto *FPT = FD->getType()->castAs<FunctionProtoType>();
|
||||
if (FPT->getExceptionSpecType() != EST_None &&
|
||||
FPT->isNothrow(FD->getASTContext()))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Check for missing return value.
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -2127,6 +2271,12 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
|
||||
}
|
||||
}
|
||||
|
||||
// Check for throw out of non-throwing function.
|
||||
if (!Diags.isIgnored(diag::warn_throw_in_noexcept_func, D->getLocStart()))
|
||||
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
|
||||
if (S.getLangOpts().CPlusPlus && isNoexcept(FD))
|
||||
checkThrowInNonThrowingFunc(S, FD, AC);
|
||||
|
||||
// If none of the previous checks caused a CFG build, trigger one here
|
||||
// for -Wtautological-overlap-compare
|
||||
if (!Diags.isIgnored(diag::warn_tautological_overlap_comparison,
|
||||
|
@ -740,6 +740,9 @@ void Sema::ActOnEndOfTranslationUnit() {
|
||||
// Load pending instantiations from the external source.
|
||||
SmallVector<PendingImplicitInstantiation, 4> Pending;
|
||||
ExternalSource->ReadPendingInstantiations(Pending);
|
||||
for (auto PII : Pending)
|
||||
if (auto Func = dyn_cast<FunctionDecl>(PII.first))
|
||||
Func->setInstantiationIsPending(true);
|
||||
PendingInstantiations.insert(PendingInstantiations.begin(),
|
||||
Pending.begin(), Pending.end());
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user