aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-06-26 20:33:12 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-06-26 20:33:12 +0000
commitef915aab0ac566c55bfb0d7a9f6635bb5d94d4af (patch)
treeac935cfa19985d33098fc13e288b5ac830672dba
parent325377b57338e700317f5e423e5b0f1c08d99a39 (diff)
downloadsrc-ef915aab0ac566c55bfb0d7a9f6635bb5d94d4af.tar.gz
src-ef915aab0ac566c55bfb0d7a9f6635bb5d94d4af.zip
Vendor import of clang trunk r306325:vendor/clang/clang-trunk-r306325
Notes
Notes: svn path=/vendor/clang/dist/; revision=320376 svn path=/vendor/clang/clang-trunk-r306325/; revision=320377; tag=vendor/clang/clang-trunk-r306325
-rw-r--r--docs/Block-ABI-Apple.rst8
-rw-r--r--docs/ClangFormat.rst12
-rw-r--r--docs/ClangFormatStyleOptions.rst300
-rw-r--r--docs/LibFormat.rst4
-rw-r--r--docs/MemorySanitizer.rst2
-rw-r--r--docs/SourceBasedCodeCoverage.rst5
-rw-r--r--docs/ThinLTO.rst44
-rw-r--r--docs/tools/dump_format_style.py11
-rw-r--r--include/clang-c/CXCompilationDatabase.h2
-rw-r--r--include/clang-c/Index.h2
-rw-r--r--include/clang/AST/Decl.h13
-rw-r--r--include/clang/AST/DeclBase.h155
-rw-r--r--include/clang/Analysis/CloneDetection.h22
-rw-r--r--include/clang/Basic/Builtins.def31
-rw-r--r--include/clang/Basic/BuiltinsARM.def8
-rw-r--r--include/clang/Basic/BuiltinsX86.def20
-rw-r--r--include/clang/Basic/BuiltinsX86_64.def4
-rw-r--r--include/clang/Basic/DiagnosticDriverKinds.td3
-rw-r--r--include/clang/Basic/DiagnosticGroups.td8
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td24
-rw-r--r--include/clang/Basic/DiagnosticSerializationKinds.td5
-rw-r--r--include/clang/Basic/Module.h4
-rw-r--r--include/clang/Basic/arm_neon.td185
-rw-r--r--include/clang/Driver/CC1Options.td23
-rw-r--r--include/clang/Driver/Options.h5
-rw-r--r--include/clang/Driver/Options.td26
-rw-r--r--include/clang/Edit/EditedSource.h19
-rw-r--r--include/clang/Format/Format.h49
-rw-r--r--include/clang/Frontend/ASTUnit.h114
-rw-r--r--include/clang/Frontend/PrecompiledPreamble.h248
-rw-r--r--include/clang/Lex/Preprocessor.h13
-rw-r--r--include/clang/Lex/PreprocessorOptions.h8
-rw-r--r--include/clang/Parse/Parser.h7
-rw-r--r--include/clang/Sema/Sema.h3
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h5
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h7
-rw-r--r--lib/AST/ASTContext.cpp16
-rw-r--r--lib/AST/ASTDumper.cpp25
-rw-r--r--lib/AST/ASTImporter.cpp14
-rw-r--r--lib/AST/DeclBase.cpp8
-rw-r--r--lib/AST/ExternalASTMerger.cpp1
-rw-r--r--lib/Analysis/CloneDetection.cpp22
-rw-r--r--lib/Basic/Module.cpp63
-rw-r--r--lib/Basic/SourceManager.cpp9
-rw-r--r--lib/Basic/TargetInfo.cpp5
-rw-r--r--lib/Basic/Targets.cpp31
-rw-r--r--lib/CodeGen/CGBuiltin.cpp183
-rw-r--r--lib/CodeGen/CGCall.cpp50
-rw-r--r--lib/CodeGen/CGClass.cpp13
-rw-r--r--lib/CodeGen/CGDecl.cpp24
-rw-r--r--lib/CodeGen/CGExpr.cpp44
-rw-r--r--lib/CodeGen/CGObjCMac.cpp2
-rw-r--r--lib/CodeGen/CGStmt.cpp12
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp13
-rw-r--r--lib/CodeGen/CodeGenFunction.h59
-rw-r--r--lib/CodeGen/CodeGenModule.cpp35
-rw-r--r--lib/CodeGen/CodeGenModule.h3
-rw-r--r--lib/CodeGen/CodeGenTypeCache.h2
-rw-r--r--lib/CodeGen/SwiftCallingConv.cpp8
-rw-r--r--lib/CodeGen/TargetInfo.cpp169
-rw-r--r--lib/Driver/CMakeLists.txt1
-rw-r--r--lib/Driver/Driver.cpp31
-rw-r--r--lib/Driver/DriverOptions.cpp8
-rw-r--r--lib/Driver/SanitizerArgs.cpp18
-rw-r--r--lib/Driver/ToolChains/Ananas.cpp120
-rw-r--r--lib/Driver/ToolChains/Ananas.h67
-rw-r--r--lib/Driver/ToolChains/Clang.cpp55
-rw-r--r--lib/Driver/ToolChains/Gnu.cpp27
-rw-r--r--lib/Driver/ToolChains/WebAssembly.cpp5
-rw-r--r--lib/Edit/EditedSource.cpp27
-rw-r--r--lib/Format/CMakeLists.txt1
-rw-r--r--lib/Format/ContinuationIndenter.cpp7
-rw-r--r--lib/Format/Format.cpp82
-rw-r--r--lib/Format/FormatToken.h1
-rw-r--r--lib/Format/TokenAnnotator.cpp28
-rw-r--r--lib/Format/UnwrappedLineFormatter.cpp9
-rw-r--r--lib/Format/UnwrappedLineParser.cpp2
-rw-r--r--lib/Format/UsingDeclarationsSorter.cpp144
-rw-r--r--lib/Format/UsingDeclarationsSorter.h37
-rw-r--r--lib/Frontend/ASTUnit.cpp802
-rw-r--r--lib/Frontend/CMakeLists.txt1
-rw-r--r--lib/Frontend/CompilerInstance.cpp11
-rw-r--r--lib/Frontend/CompilerInvocation.cpp121
-rw-r--r--lib/Frontend/FrontendAction.cpp1
-rw-r--r--lib/Frontend/FrontendActions.cpp2
-rw-r--r--lib/Frontend/PrecompiledPreamble.cpp563
-rw-r--r--lib/Frontend/PrintPreprocessedOutput.cpp6
-rw-r--r--lib/Frontend/Rewrite/FrontendActions.cpp14
-rw-r--r--lib/Frontend/Rewrite/InclusionRewriter.cpp10
-rw-r--r--lib/Index/IndexDecl.cpp26
-rw-r--r--lib/Lex/Lexer.cpp3
-rw-r--r--lib/Lex/PPDirectives.cpp38
-rw-r--r--lib/Lex/PPExpressions.cpp29
-rw-r--r--lib/Lex/Pragma.cpp70
-rw-r--r--lib/Parse/ParseDecl.cpp6
-rw-r--r--lib/Parse/ParseDeclCXX.cpp3
-rw-r--r--lib/Parse/ParseObjc.cpp12
-rw-r--r--lib/Parse/ParseTemplate.cpp3
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp150
-rw-r--r--lib/Sema/Sema.cpp3
-rw-r--r--lib/Sema/SemaCUDA.cpp6
-rw-r--r--lib/Sema/SemaDecl.cpp37
-rw-r--r--lib/Sema/SemaDeclAttr.cpp60
-rw-r--r--lib/Sema/SemaDeclCXX.cpp6
-rw-r--r--lib/Sema/SemaExpr.cpp1
-rw-r--r--lib/Sema/SemaExprCXX.cpp4
-rw-r--r--lib/Sema/SemaLookup.cpp14
-rw-r--r--lib/Sema/SemaTemplate.cpp3
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp4
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp15
-rw-r--r--lib/Serialization/ASTReader.cpp17
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp43
-rw-r--r--lib/Serialization/ASTWriter.cpp11
-rw-r--r--lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/CStringChecker.cpp51
-rw-r--r--lib/StaticAnalyzer/Checkers/CloneChecker.cpp7
-rw-r--r--lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp43
-rw-r--r--lib/StaticAnalyzer/Core/AnalyzerOptions.cpp4
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineC.cpp5
-rw-r--r--test/Analysis/analyzer-config.c4
-rw-r--r--test/Analysis/analyzer-config.cpp4
-rw-r--r--test/Analysis/builtin-assume.c8
-rw-r--r--test/Analysis/builtin-functions.cpp14
-rw-r--r--test/Analysis/copypaste/autogenerated_automoc.cpp19
-rw-r--r--test/Analysis/copypaste/dbus_autogenerated.cpp19
-rw-r--r--test/Analysis/copypaste/moc_autogenerated.cpp19
-rw-r--r--test/Analysis/copypaste/not-autogenerated.cpp14
-rw-r--r--test/Analysis/copypaste/ui_autogenerated.cpp19
-rw-r--r--test/Analysis/null-deref-ps-region.c61
-rw-r--r--test/CXX/except/except.spec/p11.cpp9
-rw-r--r--test/CodeGen/64bit-swiftcall.c18
-rw-r--r--test/CodeGen/aarch64-neon-intrinsics.c230
-rw-r--r--test/CodeGen/aarch64-neon-ldst-one.c228
-rw-r--r--test/CodeGen/aarch64-v8.2a-neon-intrinsics.c1633
-rw-r--r--test/CodeGen/address-space.c4
-rw-r--r--test/CodeGen/arm_neon_intrinsics.c240
-rw-r--r--test/CodeGen/default-address-space.c19
-rw-r--r--test/CodeGen/mcount.c39
-rw-r--r--test/CodeGen/ms-inline-asm.c6
-rw-r--r--test/CodeGen/ms-intrinsics-other.c161
-rw-r--r--test/CodeGen/ms-intrinsics-rotations.c330
-rw-r--r--test/CodeGen/no-devirt.cpp59
-rw-r--r--test/CodeGen/pr27892.c23
-rw-r--r--test/CodeGen/target-data.c2
-rw-r--r--test/CodeGen/vectorcall.c19
-rw-r--r--test/CodeGen/x86_64-arguments.c4
-rw-r--r--test/CodeGenCXX/amdgcn-automatic-variable.cpp16
-rw-r--r--test/CodeGenObjC/objc_copyStruct.m16
-rw-r--r--test/CodeGenObjC/ubsan-nonnull-and-nullability.m34
-rw-r--r--test/CodeGenObjC/ubsan-nullability.m32
-rw-r--r--test/CodeGenOpenCL/spir_version.cl17
-rw-r--r--test/Driver/ananas.c9
-rw-r--r--test/Driver/autocomplete.c36
-rw-r--r--test/Driver/compress-noias.c37
-rw-r--r--test/Driver/compress.c38
-rw-r--r--test/Driver/fsanitize-object-size.c31
-rw-r--r--test/Driver/fsanitize.c20
-rw-r--r--test/Driver/nozlibcompress.c9
-rw-r--r--test/Driver/wasm-toolchain.c6
-rw-r--r--test/FixIt/fixit-format-darwin.m17
-rw-r--r--test/Frontend/Inputs/optimization-remark-with-hotness-sample.proftext7
-rw-r--r--test/Frontend/optimization-remark-with-hotness.c12
-rw-r--r--test/Frontend/pp-only-no-editor-placeholders.c4
-rw-r--r--test/Import/indirect-struct-member-access/Inputs/S.c3
-rw-r--r--test/Import/indirect-struct-member-access/test.c4
-rw-r--r--test/Index/Core/index-source.cpp27
-rw-r--r--test/Index/singe-file-parse.m11
-rw-r--r--test/Index/single-file-parse.m121
-rw-r--r--test/Misc/Inputs/module.modulemap1
-rw-r--r--test/Misc/ast-dump-decl.c22
-rw-r--r--test/Misc/ast-dump-decl.cpp5
-rw-r--r--test/Misc/cc1as-compress.s8
-rw-r--r--test/Modules/Inputs/preprocess/file.h6
-rw-r--r--test/Modules/Inputs/preprocess/fwd.h1
-rw-r--r--test/Modules/Inputs/preprocess/module.modulemap2
-rw-r--r--test/Modules/Inputs/preprocess/other.h1
-rw-r--r--test/Modules/const-var-init-update.cpp30
-rw-r--r--test/Modules/interface-visibility.m29
-rw-r--r--test/Modules/preprocess-module.cpp44
-rw-r--r--test/Modules/string_names.cpp4
-rw-r--r--test/Parser/objc-at-implementation-eof-crash.m24
-rw-r--r--test/Parser/objc-at-interface-eof-crash.m23
-rw-r--r--test/Sema/asm.c35
-rw-r--r--test/Sema/overloadable.c20
-rw-r--r--test/SemaCXX/PR16677.cpp5
-rw-r--r--test/SemaCXX/cxx1y-deduced-return-type.cpp19
-rw-r--r--test/SemaCXX/cxx1z-noexcept-function-type.cpp3
-rw-r--r--test/SemaCXX/friend2.cpp37
-rw-r--r--test/SemaCXX/invalid-template-params.cpp23
-rw-r--r--test/SemaCXX/warn-throw-out-noexcept-func.cpp265
-rw-r--r--test/SemaObjC/unguarded-availability-new.m160
-rw-r--r--test/SemaOpenCL/storageclass.cl5
-rw-r--r--tools/clang-format/clang-format.py15
-rw-r--r--tools/clang-import-test/clang-import-test.cpp32
-rw-r--r--tools/driver/cc1as_main.cpp19
-rw-r--r--tools/driver/driver.cpp11
-rw-r--r--unittests/Format/CMakeLists.txt1
-rw-r--r--unittests/Format/FormatTest.cpp147
-rw-r--r--unittests/Format/UsingDeclarationsSorterTest.cpp234
-rw-r--r--utils/TableGen/NeonEmitter.cpp6
-rwxr-xr-xutils/bash-autocomplete.sh31
201 files changed, 7904 insertions, 2165 deletions
diff --git a/docs/Block-ABI-Apple.rst b/docs/Block-ABI-Apple.rst
index 628e6f3d90ba..7f49bbd40d71 100644
--- a/docs/Block-ABI-Apple.rst
+++ b/docs/Block-ABI-Apple.rst
@@ -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:
diff --git a/docs/ClangFormat.rst b/docs/ClangFormat.rst
index ed0e58e452d3..902afcd08ed5 100644
--- a/docs/ClangFormat.rst
+++ b/docs/ClangFormat.rst
@@ -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
=================
diff --git a/docs/ClangFormatStyleOptions.rst b/docs/ClangFormatStyleOptions.rst
index fb014241809c..6133ca9900c9 100644
--- a/docs/ClangFormatStyleOptions.rst
+++ b/docs/ClangFormatStyleOptions.rst
@@ -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.
diff --git a/docs/LibFormat.rst b/docs/LibFormat.rst
index eacdc1614567..086a52827d8c 100644
--- a/docs/LibFormat.rst
+++ b/docs/LibFormat.rst
@@ -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:
diff --git a/docs/MemorySanitizer.rst b/docs/MemorySanitizer.rst
index 8088ecdf561f..5bb19ed8a509 100644
--- a/docs/MemorySanitizer.rst
+++ b/docs/MemorySanitizer.rst
@@ -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``).
diff --git a/docs/SourceBasedCodeCoverage.rst b/docs/SourceBasedCodeCoverage.rst
index 474af30ae30f..805c98794804 100644
--- a/docs/SourceBasedCodeCoverage.rst
+++ b/docs/SourceBasedCodeCoverage.rst
@@ -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:
diff --git a/docs/ThinLTO.rst b/docs/ThinLTO.rst
index d417febda502..31fff51a61e9 100644
--- a/docs/ThinLTO.rst
+++ b/docs/ThinLTO.rst
@@ -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
---------------
diff --git a/docs/tools/dump_format_style.py b/docs/tools/dump_format_style.py
index 81a5af6ef42b..e2571f46448d 100644
--- a/docs/tools/dump_format_style.py
+++ b/docs/tools/dump_format_style.py
@@ -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 @@ class NestedField:
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 @@ def read_options(header):
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 @@ contents = substitute(contents, 'FORMAT_STYLE_OPTIONS', options_text)
with open(DOC_FILE, 'wb') as output:
output.write(contents)
-
diff --git a/include/clang-c/CXCompilationDatabase.h b/include/clang-c/CXCompilationDatabase.h
index 9359abfebfe0..29f89e52a6e3 100644
--- a/include/clang-c/CXCompilationDatabase.h
+++ b/include/clang-c/CXCompilationDatabase.h
@@ -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. *|
|* *|
\*===----------------------------------------------------------------------===*/
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index 417ac9fd369a..4241e43a9697 100644
--- a/include/clang-c/Index.h
+++ b/include/clang-c/Index.h
@@ -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. *|
|* *|
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 9d49bac26a86..30552be9b381 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -1656,6 +1656,7 @@ private:
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 @@ protected:
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 @@ public:
///
bool isThisDeclarationADefinition() const {
return IsDeleted || IsDefaulted || Body || IsLateTemplateParsed ||
- hasDefiningAttr();
+ WillHaveBody || hasDefiningAttr();
}
/// doesThisDeclarationHaveABody - Returns whether this specific
@@ -1943,6 +1945,15 @@ public:
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; }
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index c26e2d7bde95..0f1f481ae49b 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -202,26 +202,33 @@ public:
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 @@ private:
/// 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 @@ protected:
/// \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 @@ protected:
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 @@ public:
/// 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 @@ public:
/// \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 @@ public:
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 @@ public:
/// \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 @@ public:
/// \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 {
diff --git a/include/clang/Analysis/CloneDetection.h b/include/clang/Analysis/CloneDetection.h
index 3b8173558408..1ca3514e69b0 100644
--- a/include/clang/Analysis/CloneDetection.h
+++ b/include/clang/Analysis/CloneDetection.h
@@ -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 {
diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def
index a9ec172422ab..75781dc7491d 100644
--- a/include/clang/Basic/Builtins.def
+++ b/include/clang/Basic/Builtins.def
@@ -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)
diff --git a/include/clang/Basic/BuiltinsARM.def b/include/clang/Basic/BuiltinsARM.def
index e8db347d4be5..4e277f8a5a6b 100644
--- a/include/clang/Basic/BuiltinsARM.def
+++ b/include/clang/Basic/BuiltinsARM.def
@@ -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, "")
diff --git a/include/clang/Basic/BuiltinsX86.def b/include/clang/Basic/BuiltinsX86.def
index a98c8f0a53db..4cd3f1d46473 100644
--- a/include/clang/Basic/BuiltinsX86.def
+++ b/include/clang/Basic/BuiltinsX86.def
@@ -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
diff --git a/include/clang/Basic/BuiltinsX86_64.def b/include/clang/Basic/BuiltinsX86_64.def
index 2851184c2c84..4cde153d8372 100644
--- a/include/clang/Basic/BuiltinsX86_64.def
+++ b/include/clang/Basic/BuiltinsX86_64.def
@@ -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, "")
diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td
index 3833f0f28f05..eb6dd37c148d 100644
--- a/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/include/clang/Basic/DiagnosticDriverKinds.td
@@ -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">;
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index cf404768472f..464c2425a1f1 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -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">;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index aa73a6934518..cba9b251215a 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -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<
diff --git a/include/clang/Basic/DiagnosticSerializationKinds.td b/include/clang/Basic/DiagnosticSerializationKinds.td
index 0a59a633232c..3c64ebb9c7f4 100644
--- a/include/clang/Basic/DiagnosticSerializationKinds.td
+++ b/include/clang/Basic/DiagnosticSerializationKinds.td
@@ -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">;
diff --git a/include/clang/Basic/Module.h b/include/clang/Basic/Module.h
index 1e52b29367b2..177175eae965 100644
--- a/include/clang/Basic/Module.h
+++ b/include/clang/Basic/Module.h
@@ -393,7 +393,9 @@ public:
/// \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.
diff --git a/include/clang/Basic/arm_neon.td b/include/clang/Basic/arm_neon.td
index ad8d679a1664..d5c16a91a34f 100644
--- a/include/clang/Basic/arm_neon.td
+++ b/include/clang/Basic/arm_neon.td
@@ -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">;
+}
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index 1132d1345f60..c478cfc7833e 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -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">,
diff --git a/include/clang/Driver/Options.h b/include/clang/Driver/Options.h
index 57e4452f3e8c..2da3cb4828c8 100644
--- a/include/clang/Driver/Options.h
+++ b/include/clang/Driver/Options.h
@@ -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
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 6c51976e98fe..68b331fed2bd 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -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=">,
diff --git a/include/clang/Edit/EditedSource.h b/include/clang/Edit/EditedSource.h
index 970791420734..d95a0c2be805 100644
--- a/include/clang/Edit/EditedSource.h
+++ b/include/clang/Edit/EditedSource.h
@@ -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;
diff --git a/include/clang/Format/Format.h b/include/clang/Format/Format.h
index 1891c06eba51..c1b62477ed1c 100644
--- a/include/clang/Format/Format.h
+++ b/include/clang/Format/Format.h
@@ -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.
diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h
index ae54d4151415..2950c31c2d3d 100644
--- a/include/clang/Frontend/ASTUnit.h
+++ b/include/clang/Frontend/ASTUnit.h
@@ -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 @@ private:
/// 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 @@ private:
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 @@ public:
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
diff --git a/include/clang/Frontend/PrecompiledPreamble.h b/include/clang/Frontend/PrecompiledPreamble.h
new file mode 100644
index 000000000000..8307392e7feb
--- /dev/null
+++ b/include/clang/Frontend/PrecompiledPreamble.h
@@ -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
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index 302d006ea16c..712e1ab9fbf5 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -1835,11 +1835,20 @@ private:
/// \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.
diff --git a/include/clang/Lex/PreprocessorOptions.h b/include/clang/Lex/PreprocessorOptions.h
index f536be8d8e69..d91c665cf1dd 100644
--- a/include/clang/Lex/PreprocessorOptions.h
+++ b/include/clang/Lex/PreprocessorOptions.h
@@ -96,8 +96,15 @@ public:
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 @@ public:
ImplicitPTHInclude.clear();
TokenCache.clear();
SingleFileParseMode = false;
+ LexEditorPlaceholders = true;
RetainRemappedFileBuffers = true;
PrecompiledPreambleBytes.first = 0;
PrecompiledPreambleBytes.second = 0;
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index a51d3a51d435..21d699ec402e 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -604,7 +604,7 @@ public:
}
/// 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 @@ private:
/// \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 @@ private:
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 @@ private:
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 @@ private:
static bool isClassTemplateDeductionContext(DeclSpecContext DSC) {
switch (DSC) {
case DSC_normal:
+ case DSC_template_param:
case DSC_class:
case DSC_top_level:
case DSC_condition:
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 1dedf4ba24ce..02c133d1c4fc 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -2153,7 +2153,8 @@ public:
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,
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
index fb427f618575..b8ec2aa6ae8d 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
@@ -180,6 +180,11 @@ public:
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);
}
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index 14aa3af37620..d58d0a690c88 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -315,6 +315,13 @@ public:
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());
}
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 2300801c1a9c..fabfdc9ef7e5 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -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");
diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp
index d89be0d9e6fa..4758109fbcf7 100644
--- a/lib/AST/ASTDumper.cpp
+++ b/lib/AST/ASTDumper.cpp
@@ -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());
}
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 493cb6df8b83..6e33b98d2f18 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -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)
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 032a20afa834..a0594a020362 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -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) {
diff --git a/lib/AST/ExternalASTMerger.cpp b/lib/AST/ExternalASTMerger.cpp
index 1dc472a5f753..b746edaf6439 100644
--- a/lib/AST/ExternalASTMerger.cpp
+++ b/lib/AST/ExternalASTMerger.cpp
@@ -41,6 +41,7 @@ public:
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();
}
diff --git a/lib/Analysis/CloneDetection.cpp b/lib/Analysis/CloneDetection.cpp
index 5bbcbe4e5722..ee848ac711d6 100644
--- a/lib/Analysis/CloneDetection.cpp
+++ b/lib/Analysis/CloneDetection.cpp
@@ -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))
diff --git a/lib/Basic/Module.cpp b/lib/Basic/Module.cpp
index 83c524877ab0..1d96afd476ef 100644
--- a/lib/Basic/Module.cpp
+++ b/lib/Basic/Module.cpp
@@ -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";
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index fc4c6d303801..3936afab21a4 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -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])
diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp
index 8cfd8bde9cbb..4bcebadf458f 100644
--- a/lib/Basic/TargetInfo.cpp
+++ b/lib/Basic/TargetInfo.cpp
@@ -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.
}
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index a3b8330707b9..c5af99e4b6af 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -111,6 +111,21 @@ public:
: 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 @@ public:
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 @@ public:
Crypto = 0;
Unaligned = 1;
V8_1A = 0;
+ V8_2A = 0;
+ HasFullFP16 = 0;
for (const auto &Feature : Features) {
if (Feature == "+neon")
@@ -6342,6 +6363,10 @@ public:
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 @@ public:
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: {
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index 8f0c22d1f7ef..a6451b7fc3c1 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -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);
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index c65dc18be306..38d520a2beb0 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -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);
- }
+ // 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())
+ CanNullCheck =
+ Builder.CreateAnd(CanNullCheck, RetValNullabilityPrecondition);
+ Builder.CreateCondBr(CanNullCheck, Check, NoCheck);
+ EmitBlock(Check);
- // Now do the null check. If the returns_nonnull attribute is present, this
- // is done unconditionally.
+ // Now do the null check.
llvm::Value *Cond = Builder.CreateIsNotNull(RV);
- llvm::Constant *StaticData[] = {
- EmitCheckSourceLocation(EndLoc), EmitCheckSourceLocation(AttrLoc),
- };
- EmitCheck(std::make_pair(Cond, CheckKind), Handler, StaticData, None);
+ llvm::Constant *StaticData[] = {EmitCheckSourceLocation(AttrLoc)};
+ llvm::Value *DynamicData[] = {SLocPtr};
+ EmitCheck(std::make_pair(Cond, CheckKind), Handler, StaticData, DynamicData);
- if (requiresReturnValueNullabilityCheck())
- EmitBlock(NoCheck);
+ 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 {
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index 5b4dc5ff0ab3..127d7df348ee 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -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.
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 87bfa507a8c0..ccd3b8d513b1 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -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;
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 7359006677f4..2ee1c96a6619 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -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
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index c78d3febd4cd..7976c53d9e98 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -308,7 +308,7 @@ public:
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 =
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index 683f366ebe45..a13c38646164 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -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();
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index ac1a1334f103..93a4a3866193 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -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()) {
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 831eedf9e478..6785111bd052 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -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 @@ private:
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 @@ public:
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 @@ public:
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 @@ public:
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.
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 19a055075604..5319ccec163f 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -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);
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 59e56a6ba194..c5f1a2b409ee 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -1321,6 +1321,9 @@ private:
/// 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();
diff --git a/lib/CodeGen/CodeGenTypeCache.h b/lib/CodeGen/CodeGenTypeCache.h
index 450eab48a3b4..6910d36733dc 100644
--- a/lib/CodeGen/CodeGenTypeCache.h
+++ b/lib/CodeGen/CodeGenTypeCache.h
@@ -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;
diff --git a/lib/CodeGen/SwiftCallingConv.cpp b/lib/CodeGen/SwiftCallingConv.cpp
index 0bfe30a32c80..fc8e36d2c599 100644
--- a/lib/CodeGen/SwiftCallingConv.cpp
+++ b/lib/CodeGen/SwiftCallingConv.cpp
@@ -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
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index 427ec06a2fff..8d00e055306d 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -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 &current) 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 @@ public:
};
}
-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;
}
diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt
index b639927a95b6..c7ca698d95a0 100644
--- a/lib/Driver/CMakeLists.txt
+++ b/lib/Driver/CMakeLists.txt
@@ -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
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index eb504fd4e541..f23975829eaf 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.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;
diff --git a/lib/Driver/DriverOptions.cpp b/lib/Driver/DriverOptions.cpp
index 6a7410901d25..ac63b96cf96d 100644
--- a/lib/Driver/DriverOptions.cpp
+++ b/lib/Driver/DriverOptions.cpp
@@ -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
};
diff --git a/lib/Driver/SanitizerArgs.cpp b/lib/Driver/SanitizerArgs.cpp
index d6a9c35eda78..3a30f2a289b0 100644
--- a/lib/Driver/SanitizerArgs.cpp
+++ b/lib/Driver/SanitizerArgs.cpp
@@ -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.
diff --git a/lib/Driver/ToolChains/Ananas.cpp b/lib/Driver/ToolChains/Ananas.cpp
new file mode 100644
index 000000000000..a67e1d2378f5
--- /dev/null
+++ b/lib/Driver/ToolChains/Ananas.cpp
@@ -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); }
diff --git a/lib/Driver/ToolChains/Ananas.h b/lib/Driver/ToolChains/Ananas.h
new file mode 100644
index 000000000000..2563dd2d49a9
--- /dev/null
+++ b/lib/Driver/ToolChains/Ananas.h
@@ -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
diff --git a/lib/Driver/ToolChains/Clang.cpp b/lib/Driver/ToolChains/Clang.cpp
index bd4e894d6504..292cf72b56ca 100644
--- a/lib/Driver/ToolChains/Clang.cpp
+++ b/lib/Driver/ToolChains/Clang.cpp
@@ -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.
diff --git a/lib/Driver/ToolChains/Gnu.cpp b/lib/Driver/ToolChains/Gnu.cpp
index d50f8e21f62f..bca5d3a3f28b 100644
--- a/lib/Driver/ToolChains/Gnu.cpp
+++ b/lib/Driver/ToolChains/Gnu.cpp
@@ -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:
diff --git a/lib/Driver/ToolChains/WebAssembly.cpp b/lib/Driver/ToolChains/WebAssembly.cpp
index 3471569b6884..fcb6418b2517 100644
--- a/lib/Driver/ToolChains/WebAssembly.cpp
+++ b/lib/Driver/ToolChains/WebAssembly.cpp
@@ -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; }
diff --git a/lib/Edit/EditedSource.cpp b/lib/Edit/EditedSource.cpp
index 03d45cf185c9..444d0393cccd 100644
--- a/lib/Edit/EditedSource.cpp
+++ b/lib/Edit/EditedSource.cpp
@@ -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);
diff --git a/lib/Format/CMakeLists.txt b/lib/Format/CMakeLists.txt
index 0c7511c1bb07..42e6d53d9fe6 100644
--- a/lib/Format/CMakeLists.txt
+++ b/lib/Format/CMakeLists.txt
@@ -13,6 +13,7 @@ add_clang_library(clangFormat
TokenAnnotator.cpp
UnwrappedLineFormatter.cpp
UnwrappedLineParser.cpp
+ UsingDeclarationsSorter.cpp
WhitespaceManager.cpp
LINK_LIBS
diff --git a/lib/Format/ContinuationIndenter.cpp b/lib/Format/ContinuationIndenter.cpp
index 387923031f85..cca773cfe3cb 100644
--- a/lib/Format/ContinuationIndenter.cpp
+++ b/lib/Format/ContinuationIndenter.cpp
@@ -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 {
diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp
index 39da87cf9988..7659d56adf25 100644
--- a/lib/Format/Format.cpp
+++ b/lib/Format/Format.cpp
@@ -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();
- };
- if (Style.Language == FormatStyle::LK_Cpp &&
- Style.FixNamespaceComments) {
- NamespaceEndCommentsFixer CommentsFixer(*Env, Expanded);
- return reformatAfterApplying(CommentsFixer);
+ typedef std::function<tooling::Replacements(const Environment &)>
+ AnalyzerPass;
+ SmallVector<AnalyzerPass, 4> Passes;
+
+ 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;
diff --git a/lib/Format/FormatToken.h b/lib/Format/FormatToken.h
index 0c5a5284627c..c5bf48cdcc06 100644
--- a/lib/Format/FormatToken.h
+++ b/lib/Format/FormatToken.h
@@ -39,6 +39,7 @@ namespace format {
TYPE(ConflictStart) \
TYPE(CtorInitializerColon) \
TYPE(CtorInitializerComma) \
+ TYPE(DesignatedInitializerLSquare) \
TYPE(DesignatedInitializerPeriod) \
TYPE(DictLiteral) \
TYPE(ForEachMacro) \
diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp
index 7ce699cf14a1..505f42ec9a06 100644
--- a/lib/Format/TokenAnnotator.cpp
+++ b/lib/Format/TokenAnnotator.cpp
@@ -145,6 +145,7 @@ private:
(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 @@ private:
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 @@ private:
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 @@ private:
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))
diff --git a/lib/Format/UnwrappedLineFormatter.cpp b/lib/Format/UnwrappedLineFormatter.cpp
index 7f644651a6ab..8836c07cac71 100644
--- a/lib/Format/UnwrappedLineFormatter.cpp
+++ b/lib/Format/UnwrappedLineFormatter.cpp
@@ -226,7 +226,7 @@ private:
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 @@ private:
} 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.
diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp
index 27436dda67a7..f7678bb6b2a5 100644
--- a/lib/Format/UnwrappedLineParser.cpp
+++ b/lib/Format/UnwrappedLineParser.cpp
@@ -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;
diff --git a/lib/Format/UsingDeclarationsSorter.cpp b/lib/Format/UsingDeclarationsSorter.cpp
new file mode 100644
index 000000000000..fb4f59fbc9bc
--- /dev/null
+++ b/lib/Format/UsingDeclarationsSorter.cpp
@@ -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
diff --git a/lib/Format/UsingDeclarationsSorter.h b/lib/Format/UsingDeclarationsSorter.h
new file mode 100644
index 000000000000..f7d5f97e3a2a
--- /dev/null
+++ b/lib/Format/UsingDeclarationsSorter.h
@@ -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
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 8d139f2c0a6d..1f34f10f55af 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -79,17 +79,6 @@ namespace {
}
}
};
-
- struct OnDiskData {
- /// \brief The file in which the precompiled preamble is stored.
- std::string PreambleFile;
-
- /// \brief Erase the preamble file.
- void CleanPreambleFile();
-
- /// \brief Erase temporary files and the preamble file.
- void Cleanup();
- };
template <class T>
std::unique_ptr<T> valueOrNull(llvm::ErrorOr<std::unique_ptr<T>> Val) {
@@ -105,81 +94,68 @@ namespace {
Output = std::move(*Val);
return true;
}
-}
-static llvm::sys::SmartMutex<false> &getOnDiskMutex() {
- static llvm::sys::SmartMutex<false> M(/* recursive = */ true);
- return M;
-}
+/// \brief Get a source buffer for \p MainFilePath, handling all file-to-file
+/// and file-to-buffer remappings inside \p Invocation.
+static std::unique_ptr<llvm::MemoryBuffer>
+getBufferForFileHandlingRemapping(const CompilerInvocation &Invocation,
+ vfs::FileSystem *VFS,
+ StringRef FilePath) {
+ const auto &PreprocessorOpts = Invocation.getPreprocessorOpts();
-static void cleanupOnDiskMapAtExit();
+ // Try to determine if the main file has been remapped, either from the
+ // command line (to another file) or directly through the compiler
+ // invocation (to a memory buffer).
+ llvm::MemoryBuffer *Buffer = nullptr;
+ std::unique_ptr<llvm::MemoryBuffer> BufferOwner;
+ auto FileStatus = VFS->status(FilePath);
+ if (FileStatus) {
+ llvm::sys::fs::UniqueID MainFileID = FileStatus->getUniqueID();
-typedef llvm::DenseMap<const ASTUnit *,
- std::unique_ptr<OnDiskData>> OnDiskDataMap;
-static OnDiskDataMap &getOnDiskDataMap() {
- static OnDiskDataMap M;
- static bool hasRegisteredAtExit = false;
- if (!hasRegisteredAtExit) {
- hasRegisteredAtExit = true;
- atexit(cleanupOnDiskMapAtExit);
- }
- return M;
-}
+ // Check whether there is a file-file remapping of the main file
+ for (const auto &RF : PreprocessorOpts.RemappedFiles) {
+ std::string MPath(RF.first);
+ auto MPathStatus = VFS->status(MPath);
+ if (MPathStatus) {
+ llvm::sys::fs::UniqueID MID = MPathStatus->getUniqueID();
+ if (MainFileID == MID) {
+ // We found a remapping. Try to load the resulting, remapped source.
+ BufferOwner = valueOrNull(VFS->getBufferForFile(RF.second));
+ if (!BufferOwner)
+ return nullptr;
+ }
+ }
+ }
-static void cleanupOnDiskMapAtExit() {
- // Use the mutex because there can be an alive thread destroying an ASTUnit.
- llvm::MutexGuard Guard(getOnDiskMutex());
- for (const auto &I : getOnDiskDataMap()) {
- // We don't worry about freeing the memory associated with OnDiskDataMap.
- // All we care about is erasing stale files.
- I.second->Cleanup();
+ // Check whether there is a file-buffer remapping. It supercedes the
+ // file-file remapping.
+ for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) {
+ std::string MPath(RB.first);
+ auto MPathStatus = VFS->status(MPath);
+ if (MPathStatus) {
+ llvm::sys::fs::UniqueID MID = MPathStatus->getUniqueID();
+ if (MainFileID == MID) {
+ // We found a remapping.
+ BufferOwner.reset();
+ Buffer = const_cast<llvm::MemoryBuffer *>(RB.second);
+ }
+ }
+ }
}
-}
-
-static OnDiskData &getOnDiskData(const ASTUnit *AU) {
- // We require the mutex since we are modifying the structure of the
- // DenseMap.
- llvm::MutexGuard Guard(getOnDiskMutex());
- OnDiskDataMap &M = getOnDiskDataMap();
- auto &D = M[AU];
- if (!D)
- D = llvm::make_unique<OnDiskData>();
- return *D;
-}
-
-static void erasePreambleFile(const ASTUnit *AU) {
- getOnDiskData(AU).CleanPreambleFile();
-}
-static void removeOnDiskEntry(const ASTUnit *AU) {
- // We require the mutex since we are modifying the structure of the
- // DenseMap.
- llvm::MutexGuard Guard(getOnDiskMutex());
- OnDiskDataMap &M = getOnDiskDataMap();
- OnDiskDataMap::iterator I = M.find(AU);
- if (I != M.end()) {
- I->second->Cleanup();
- M.erase(I);
+ // If the main source file was not remapped, load it now.
+ if (!Buffer && !BufferOwner) {
+ BufferOwner = valueOrNull(VFS->getBufferForFile(FilePath));
+ if (!BufferOwner)
+ return nullptr;
}
-}
-
-static void setPreambleFile(const ASTUnit *AU, StringRef preambleFile) {
- getOnDiskData(AU).PreambleFile = preambleFile;
-}
-static const std::string &getPreambleFile(const ASTUnit *AU) {
- return getOnDiskData(AU).PreambleFile;
+ if (BufferOwner)
+ return BufferOwner;
+ if (!Buffer)
+ return nullptr;
+ return llvm::MemoryBuffer::getMemBufferCopy(Buffer->getBuffer(), FilePath);
}
-
-void OnDiskData::CleanPreambleFile() {
- if (!PreambleFile.empty()) {
- llvm::sys::fs::remove(PreambleFile);
- PreambleFile.clear();
- }
-}
-
-void OnDiskData::Cleanup() {
- CleanPreambleFile();
}
struct ASTUnit::ASTWriterData {
@@ -233,9 +209,6 @@ ASTUnit::~ASTUnit() {
clearFileLevelDecls();
- // Clean up the temporary files and the preamble file.
- removeOnDiskEntry(this);
-
// Free the buffers associated with remapped files. We are required to
// perform this operation here because we explicitly request that the
// compiler instance *not* free these buffers for each invocation of the
@@ -575,16 +548,24 @@ private:
/// \brief Diagnostic consumer that saves each diagnostic it is given.
class StoredDiagnosticConsumer : public DiagnosticConsumer {
- SmallVectorImpl<StoredDiagnostic> &StoredDiags;
+ SmallVectorImpl<StoredDiagnostic> *StoredDiags;
+ SmallVectorImpl<ASTUnit::StandaloneDiagnostic> *StandaloneDiags;
+ const LangOptions *LangOpts;
SourceManager *SourceMgr;
public:
- explicit StoredDiagnosticConsumer(
- SmallVectorImpl<StoredDiagnostic> &StoredDiags)
- : StoredDiags(StoredDiags), SourceMgr(nullptr) {}
+ StoredDiagnosticConsumer(
+ SmallVectorImpl<StoredDiagnostic> *StoredDiags,
+ SmallVectorImpl<ASTUnit::StandaloneDiagnostic> *StandaloneDiags)
+ : StoredDiags(StoredDiags), StandaloneDiags(StandaloneDiags),
+ LangOpts(nullptr), SourceMgr(nullptr) {
+ assert((StoredDiags || StandaloneDiags) &&
+ "No output collections were passed to StoredDiagnosticConsumer.");
+ }
void BeginSourceFile(const LangOptions &LangOpts,
const Preprocessor *PP = nullptr) override {
+ this->LangOpts = &LangOpts;
if (PP)
SourceMgr = &PP->getSourceManager();
}
@@ -603,8 +584,9 @@ class CaptureDroppedDiagnostics {
public:
CaptureDroppedDiagnostics(bool RequestCapture, DiagnosticsEngine &Diags,
- SmallVectorImpl<StoredDiagnostic> &StoredDiags)
- : Diags(Diags), Client(StoredDiags), PreviousClient(nullptr)
+ SmallVectorImpl<StoredDiagnostic> *StoredDiags,
+ SmallVectorImpl<ASTUnit::StandaloneDiagnostic> *StandaloneDiags)
+ : Diags(Diags), Client(StoredDiags, StandaloneDiags), PreviousClient(nullptr)
{
if (RequestCapture || Diags.getClient() == nullptr) {
OwningPreviousClient = Diags.takeClient();
@@ -621,16 +603,35 @@ public:
} // anonymous namespace
+static ASTUnit::StandaloneDiagnostic
+makeStandaloneDiagnostic(const LangOptions &LangOpts,
+ const StoredDiagnostic &InDiag);
+
void StoredDiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level Level,
- const Diagnostic &Info) {
+ const Diagnostic &Info) {
// Default implementation (Warnings/errors count).
DiagnosticConsumer::HandleDiagnostic(Level, Info);
// Only record the diagnostic if it's part of the source manager we know
// about. This effectively drops diagnostics from modules we're building.
// FIXME: In the long run, ee don't want to drop source managers from modules.
- if (!Info.hasSourceManager() || &Info.getSourceManager() == SourceMgr)
- StoredDiags.emplace_back(Level, Info);
+ if (!Info.hasSourceManager() || &Info.getSourceManager() == SourceMgr) {
+ StoredDiagnostic *ResultDiag = nullptr;
+ if (StoredDiags) {
+ StoredDiags->emplace_back(Level, Info);
+ ResultDiag = &StoredDiags->back();
+ }
+
+ if (StandaloneDiags) {
+ llvm::Optional<StoredDiagnostic> StoredDiag = llvm::None;
+ if (!ResultDiag) {
+ StoredDiag.emplace(Level, Info);
+ ResultDiag = StoredDiag.getPointer();
+ }
+ StandaloneDiags->push_back(
+ makeStandaloneDiagnostic(*LangOpts, *ResultDiag));
+ }
+ }
}
IntrusiveRefCntPtr<ASTReader> ASTUnit::getASTReader() const {
@@ -665,7 +666,7 @@ void ASTUnit::ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
ASTUnit &AST, bool CaptureDiagnostics) {
assert(Diags.get() && "no DiagnosticsEngine was provided");
if (CaptureDiagnostics)
- Diags->setClient(new StoredDiagnosticConsumer(AST.StoredDiagnostics));
+ Diags->setClient(new StoredDiagnosticConsumer(&AST.StoredDiagnostics, nullptr));
}
std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
@@ -780,6 +781,11 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
namespace {
+/// \brief Add the given macro to the hash of all top-level entities.
+void AddDefinedMacroToHash(const Token &MacroNameTok, unsigned &Hash) {
+ Hash = llvm::HashString(MacroNameTok.getIdentifierInfo()->getName(), Hash);
+}
+
/// \brief Preprocessor callback class that updates a hash value with the names
/// of all macros that have been defined by the translation unit.
class MacroDefinitionTrackerPPCallbacks : public PPCallbacks {
@@ -790,7 +796,7 @@ public:
void MacroDefined(const Token &MacroNameTok,
const MacroDirective *MD) override {
- Hash = llvm::HashString(MacroNameTok.getIdentifierInfo()->getName(), Hash);
+ AddDefinedMacroToHash(MacroNameTok, Hash);
}
};
@@ -916,45 +922,27 @@ public:
}
};
-class PrecompilePreambleAction : public ASTFrontendAction {
- ASTUnit &Unit;
- bool HasEmittedPreamblePCH;
-
+class ASTUnitPreambleCallbacks : public PreambleCallbacks {
public:
- explicit PrecompilePreambleAction(ASTUnit &Unit)
- : Unit(Unit), HasEmittedPreamblePCH(false) {}
+ unsigned getHash() const { return Hash; }
- std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) override;
- bool hasEmittedPreamblePCH() const { return HasEmittedPreamblePCH; }
- void setHasEmittedPreamblePCH() { HasEmittedPreamblePCH = true; }
- bool shouldEraseOutputFiles() override { return !hasEmittedPreamblePCH(); }
-
- bool hasCodeCompletionSupport() const override { return false; }
- bool hasASTFileSupport() const override { return false; }
- TranslationUnitKind getTranslationUnitKind() override { return TU_Prefix; }
-};
+ std::vector<Decl *> takeTopLevelDecls() { return std::move(TopLevelDecls); }
-class PrecompilePreambleConsumer : public PCHGenerator {
- ASTUnit &Unit;
- unsigned &Hash;
- std::vector<Decl *> TopLevelDecls;
- PrecompilePreambleAction *Action;
- std::unique_ptr<raw_ostream> Out;
+ std::vector<serialization::DeclID> takeTopLevelDeclIDs() {
+ return std::move(TopLevelDeclIDs);
+ }
-public:
- PrecompilePreambleConsumer(ASTUnit &Unit, 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),
- Unit(Unit), Hash(Unit.getCurrentTopLevelHashValue()), Action(Action),
- Out(std::move(Out)) {
- Hash = 0;
+ void AfterPCHEmitted(ASTWriter &Writer) override {
+ TopLevelDeclIDs.reserve(TopLevelDecls.size());
+ for (Decl *D : TopLevelDecls) {
+ // Invalid top-level decls may not have been serialized.
+ if (D->isInvalidDecl())
+ continue;
+ TopLevelDeclIDs.push_back(Writer.getDeclID(D));
+ }
}
- bool HandleTopLevelDecl(DeclGroupRef DG) override {
+ void HandleTopLevelDecl(DeclGroupRef DG) override {
for (Decl *D : DG) {
// FIXME: Currently ObjC method declarations are incorrectly being
// reported as top-level declarations, even though their DeclContext
@@ -965,59 +953,22 @@ public:
AddTopLevelDeclarationToHash(D, Hash);
TopLevelDecls.push_back(D);
}
- return true;
}
- void HandleTranslationUnit(ASTContext &Ctx) override {
- PCHGenerator::HandleTranslationUnit(Ctx);
- if (hasEmittedPCH()) {
- // 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);
-
- // Translate the top-level declarations we captured during
- // parsing into declaration IDs in the precompiled
- // preamble. This will allow us to deserialize those top-level
- // declarations when requested.
- for (Decl *D : TopLevelDecls) {
- // Invalid top-level decls may not have been serialized.
- if (D->isInvalidDecl())
- continue;
- Unit.addTopLevelDeclFromPreamble(getWriter().getDeclID(D));
- }
-
- Action->setHasEmittedPreamblePCH();
- }
+ void HandleMacroDefined(const Token &MacroNameTok,
+ const MacroDirective *MD) override {
+ AddDefinedMacroToHash(MacroNameTok, Hash);
}
+
+private:
+ unsigned Hash = 0;
+ std::vector<Decl *> TopLevelDecls;
+ std::vector<serialization::DeclID> TopLevelDeclIDs;
+ llvm::SmallVector<ASTUnit::StandaloneDiagnostic, 4> PreambleDiags;
};
} // anonymous namespace
-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<MacroDefinitionTrackerPPCallbacks>(
- Unit.getCurrentTopLevelHashValue()));
- return llvm::make_unique<PrecompilePreambleConsumer>(
- Unit, this, CI.getPreprocessor(), Sysroot, std::move(OS));
-}
-
static bool isNonDriverDiag(const StoredDiagnostic &StoredDiag) {
return StoredDiag.getLocation().isValid();
}
@@ -1125,15 +1076,9 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
// If the main file has been overridden due to the use of a preamble,
// make that override happen and introduce the preamble.
- PreprocessorOptions &PreprocessorOpts = Clang->getPreprocessorOpts();
if (OverrideMainBuffer) {
- PreprocessorOpts.addRemappedFile(OriginalSourceFile,
- OverrideMainBuffer.get());
- PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size();
- PreprocessorOpts.PrecompiledPreambleBytes.second
- = PreambleEndsAtStartOfLine;
- PreprocessorOpts.ImplicitPCHInclude = getPreambleFile(this);
- PreprocessorOpts.DisablePCHValidation = true;
+ assert(Preamble && "No preamble was built, but OverrideMainBuffer is not null");
+ Preamble->AddImplicitPreamble(Clang->getInvocation(), OverrideMainBuffer.get());
// The stored diagnostic has the old source manager in it; update
// the locations to refer into the new source manager. Since we've
@@ -1186,116 +1131,6 @@ error:
return true;
}
-/// \brief Simple function to retrieve a path for a preamble precompiled header.
-static std::string GetPreamblePCHPath() {
- // 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 TmpFile;
-
- SmallString<128> Path;
- llvm::sys::fs::createTemporaryFile("preamble", "pch", Path);
-
- return Path.str();
-}
-
-/// \brief Compute the preamble for the main file, providing the source buffer
-/// that corresponds to the main file along with a pair (bytes, start-of-line)
-/// that describes the preamble.
-ASTUnit::ComputedPreamble
-ASTUnit::ComputePreamble(CompilerInvocation &Invocation, unsigned MaxLines,
- IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
- FrontendOptions &FrontendOpts = Invocation.getFrontendOpts();
- PreprocessorOptions &PreprocessorOpts = Invocation.getPreprocessorOpts();
-
- // Try to determine if the main file has been remapped, either from the
- // command line (to another file) or directly through the compiler invocation
- // (to a memory buffer).
- llvm::MemoryBuffer *Buffer = nullptr;
- std::unique_ptr<llvm::MemoryBuffer> BufferOwner;
- std::string MainFilePath(FrontendOpts.Inputs[0].getFile());
- auto MainFileStatus = VFS->status(MainFilePath);
- if (MainFileStatus) {
- llvm::sys::fs::UniqueID MainFileID = MainFileStatus->getUniqueID();
-
- // Check whether there is a file-file remapping of the main file
- for (const auto &RF : PreprocessorOpts.RemappedFiles) {
- std::string MPath(RF.first);
- auto MPathStatus = VFS->status(MPath);
- if (MPathStatus) {
- llvm::sys::fs::UniqueID MID = MPathStatus->getUniqueID();
- if (MainFileID == MID) {
- // We found a remapping. Try to load the resulting, remapped source.
- BufferOwner = valueOrNull(VFS->getBufferForFile(RF.second));
- if (!BufferOwner)
- return ComputedPreamble(nullptr, nullptr, 0, true);
- }
- }
- }
-
- // Check whether there is a file-buffer remapping. It supercedes the
- // file-file remapping.
- for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) {
- std::string MPath(RB.first);
- auto MPathStatus = VFS->status(MPath);
- if (MPathStatus) {
- llvm::sys::fs::UniqueID MID = MPathStatus->getUniqueID();
- if (MainFileID == MID) {
- // We found a remapping.
- BufferOwner.reset();
- Buffer = const_cast<llvm::MemoryBuffer *>(RB.second);
- }
- }
- }
- }
-
- // If the main source file was not remapped, load it now.
- if (!Buffer && !BufferOwner) {
- BufferOwner = valueOrNull(VFS->getBufferForFile(FrontendOpts.Inputs[0].getFile()));
- if (!BufferOwner)
- return ComputedPreamble(nullptr, nullptr, 0, true);
- }
-
- if (!Buffer)
- Buffer = BufferOwner.get();
- auto Pre = Lexer::ComputePreamble(Buffer->getBuffer(),
- *Invocation.getLangOpts(), MaxLines);
- return ComputedPreamble(Buffer, std::move(BufferOwner), Pre.first,
- Pre.second);
-}
-
-ASTUnit::PreambleFileHash
-ASTUnit::PreambleFileHash::createForFile(off_t Size, time_t ModTime) {
- PreambleFileHash Result;
- Result.Size = Size;
- Result.ModTime = ModTime;
- Result.MD5 = {};
- return Result;
-}
-
-ASTUnit::PreambleFileHash ASTUnit::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;
-}
-
-namespace clang {
-bool operator==(const ASTUnit::PreambleFileHash &LHS,
- const ASTUnit::PreambleFileHash &RHS) {
- return LHS.Size == RHS.Size && LHS.ModTime == RHS.ModTime &&
- LHS.MD5 == RHS.MD5;
-}
-} // namespace clang
-
static std::pair<unsigned, unsigned>
makeStandaloneRange(CharSourceRange Range, const SourceManager &SM,
const LangOptions &LangOpts) {
@@ -1367,135 +1202,41 @@ ASTUnit::getMainBufferWithPrecompiledPreamble(
const CompilerInvocation &PreambleInvocationIn,
IntrusiveRefCntPtr<vfs::FileSystem> VFS, bool AllowRebuild,
unsigned MaxLines) {
- assert(VFS && "VFS is null");
-
- auto PreambleInvocation =
- std::make_shared<CompilerInvocation>(PreambleInvocationIn);
- FrontendOptions &FrontendOpts = PreambleInvocation->getFrontendOpts();
- PreprocessorOptions &PreprocessorOpts
- = PreambleInvocation->getPreprocessorOpts();
-
- ComputedPreamble NewPreamble =
- ComputePreamble(*PreambleInvocation, MaxLines, VFS);
- if (!NewPreamble.Size) {
- // We couldn't find a preamble in the main source. Clear out the current
- // preamble, if we have one. It's obviously no good any more.
- Preamble.clear();
- erasePreambleFile(this);
-
- // The next time we actually see a preamble, precompile it.
- PreambleRebuildCounter = 1;
+ auto MainFilePath =
+ PreambleInvocationIn.getFrontendOpts().Inputs[0].getFile();
+ std::unique_ptr<llvm::MemoryBuffer> MainFileBuffer =
+ getBufferForFileHandlingRemapping(PreambleInvocationIn, VFS.get(),
+ MainFilePath);
+ if (!MainFileBuffer)
return nullptr;
- }
-
- if (!Preamble.empty()) {
- // 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 (Preamble.size() == NewPreamble.Size &&
- PreambleEndsAtStartOfLine == NewPreamble.PreambleEndsAtStartOfLine &&
- memcmp(Preamble.getBufferStart(), NewPreamble.Buffer->getBufferStart(),
- NewPreamble.Size) == 0) {
- // 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.
- bool AnyFileChanged = false;
-
- // 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) {
- if (AnyFileChanged)
- break;
-
- 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.
- AnyFileChanged = true;
- break;
- }
- OverriddenFiles[Status.getUniqueID()] = PreambleFileHash::createForFile(
- Status.getSize(),
- llvm::sys::toTimeT(Status.getLastModificationTime()));
- }
-
- for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) {
- if (AnyFileChanged)
- break;
+ PreambleBounds Bounds =
+ ComputePreambleBounds(*PreambleInvocationIn.getLangOpts(),
+ MainFileBuffer.get(), MaxLines);
+ if (!Bounds.Size)
+ return nullptr;
- vfs::Status Status;
- if (!moveOnNoError(VFS->status(RB.first), Status)) {
- AnyFileChanged = true;
- break;
- }
+ if (Preamble) {
+ if (Preamble->CanReuse(PreambleInvocationIn, MainFileBuffer.get(), Bounds,
+ VFS.get())) {
+ // Okay! We can re-use the precompiled preamble.
- OverriddenFiles[Status.getUniqueID()] =
- PreambleFileHash::createForMemoryBuffer(RB.second);
- }
-
- // Check whether anything has changed.
- for (llvm::StringMap<PreambleFileHash>::iterator
- F = FilesInPreamble.begin(), FEnd = FilesInPreamble.end();
- !AnyFileChanged && F != FEnd;
- ++F) {
- vfs::Status Status;
- if (!moveOnNoError(VFS->status(F->first()), Status)) {
- // If we can't stat the file, assume that something horrible happened.
- AnyFileChanged = true;
- break;
- }
+ // Set the state of the diagnostic object to mimic its state
+ // after parsing the preamble.
+ getDiagnostics().Reset();
+ ProcessWarningOptions(getDiagnostics(),
+ PreambleInvocationIn.getDiagnosticOpts());
+ getDiagnostics().setNumWarnings(NumWarningsInPreamble);
- 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)
- AnyFileChanged = true;
- 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)
- AnyFileChanged = true;
- }
-
- if (!AnyFileChanged) {
- // Okay! We can re-use the precompiled preamble.
-
- // Set the state of the diagnostic object to mimic its state
- // after parsing the preamble.
- getDiagnostics().Reset();
- ProcessWarningOptions(getDiagnostics(),
- PreambleInvocation->getDiagnosticOpts());
- getDiagnostics().setNumWarnings(NumWarningsInPreamble);
-
- return llvm::MemoryBuffer::getMemBufferCopy(
- NewPreamble.Buffer->getBuffer(), FrontendOpts.Inputs[0].getFile());
- }
+ PreambleRebuildCounter = 1;
+ return MainFileBuffer;
+ } else {
+ Preamble.reset();
+ PreambleDiagnostics.clear();
+ TopLevelDeclsInPreamble.clear();
+ PreambleRebuildCounter = 1;
}
-
- // If we aren't allowed to rebuild the precompiled preamble, just
- // return now.
- if (!AllowRebuild)
- return nullptr;
-
- // We can't reuse the previously-computed preamble. Build a new one.
- Preamble.clear();
- PreambleDiagnostics.clear();
- erasePreambleFile(this);
- PreambleRebuildCounter = 1;
- } else if (!AllowRebuild) {
- // We aren't allowed to rebuild the precompiled preamble; just
- // return now.
- return nullptr;
}
// If the preamble rebuild counter > 1, it's because we previously
@@ -1506,164 +1247,61 @@ ASTUnit::getMainBufferWithPrecompiledPreamble(
return nullptr;
}
- // Create a temporary file for the precompiled preamble. In rare
- // circumstances, this can fail.
- std::string PreamblePCHPath = GetPreamblePCHPath();
- if (PreamblePCHPath.empty()) {
- // Try again next time.
- PreambleRebuildCounter = 1;
+ assert(!Preamble && "No Preamble should be stored at that point");
+ // If we aren't allowed to rebuild the precompiled preamble, just
+ // return now.
+ if (!AllowRebuild)
return nullptr;
- }
-
- // We did not previously compute a preamble, or it can't be reused anyway.
- SimpleTimer PreambleTimer(WantTiming);
- PreambleTimer.setOutput("Precompiling preamble");
-
- // Save the preamble text for later; we'll need to compare against it for
- // subsequent reparses.
- StringRef MainFilename = FrontendOpts.Inputs[0].getFile();
- Preamble.assign(FileMgr->getFile(MainFilename),
- NewPreamble.Buffer->getBufferStart(),
- NewPreamble.Buffer->getBufferStart() + NewPreamble.Size);
- PreambleEndsAtStartOfLine = NewPreamble.PreambleEndsAtStartOfLine;
-
- PreambleBuffer = llvm::MemoryBuffer::getMemBufferCopy(
- NewPreamble.Buffer->getBuffer().slice(0, Preamble.size()), MainFilename);
-
- // Remap the main source file to the preamble buffer.
- StringRef MainFilePath = FrontendOpts.Inputs[0].getFile();
- PreprocessorOpts.addRemappedFile(MainFilePath, PreambleBuffer.get());
-
- // Tell the compiler invocation to generate a temporary precompiled header.
- FrontendOpts.ProgramAction = frontend::GeneratePCH;
- // FIXME: Generate the precompiled header into memory?
- FrontendOpts.OutputFile = PreamblePCHPath;
- 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));
- OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].getFile();
-
- // Set up diagnostics, capturing all of the diagnostics produced.
- Clang->setDiagnostics(&getDiagnostics());
-
- // Create the target instance.
- Clang->setTarget(TargetInfo::CreateTargetInfo(
- Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
- if (!Clang->hasTarget()) {
- llvm::sys::fs::remove(FrontendOpts.OutputFile);
- Preamble.clear();
- PreambleRebuildCounter = DefaultPreambleRebuildInterval;
- PreprocessorOpts.RemappedFileBuffers.pop_back();
- return nullptr;
- }
-
- // 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.
- getDiagnostics().Reset();
- ProcessWarningOptions(getDiagnostics(), Clang->getDiagnosticOpts());
- checkAndRemoveNonDriverDiags(StoredDiagnostics);
- TopLevelDecls.clear();
- TopLevelDeclsInPreamble.clear();
- PreambleDiagnostics.clear();
-
- VFS = createVFSFromCompilerInvocation(Clang->getInvocation(),
- getDiagnostics(), VFS);
- if (!VFS)
- return nullptr;
-
- // 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(getDiagnostics(),
- Clang->getFileManager()));
-
- auto PreambleDepCollector = std::make_shared<DependencyCollector>();
- Clang->addDependencyCollector(PreambleDepCollector);
-
- std::unique_ptr<PrecompilePreambleAction> Act;
- Act.reset(new PrecompilePreambleAction(*this));
- if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0])) {
- llvm::sys::fs::remove(FrontendOpts.OutputFile);
- Preamble.clear();
- PreambleRebuildCounter = DefaultPreambleRebuildInterval;
- PreprocessorOpts.RemappedFileBuffers.pop_back();
- return nullptr;
+ SmallVector<StandaloneDiagnostic, 4> NewPreambleDiagsStandalone;
+ SmallVector<StoredDiagnostic, 4> NewPreambleDiags;
+ ASTUnitPreambleCallbacks Callbacks;
+ {
+ llvm::Optional<CaptureDroppedDiagnostics> Capture;
+ if (CaptureDiagnostics)
+ Capture.emplace(/*RequestCapture=*/true, *Diagnostics, &NewPreambleDiags,
+ &NewPreambleDiagsStandalone);
+
+ // We did not previously compute a preamble, or it can't be reused anyway.
+ SimpleTimer PreambleTimer(WantTiming);
+ PreambleTimer.setOutput("Precompiling preamble");
+
+ llvm::ErrorOr<PrecompiledPreamble> NewPreamble = PrecompiledPreamble::Build(
+ PreambleInvocationIn, MainFileBuffer.get(), Bounds, *Diagnostics, VFS,
+ PCHContainerOps, Callbacks);
+ if (NewPreamble) {
+ Preamble = std::move(*NewPreamble);
+ PreambleRebuildCounter = 1;
+ } else {
+ switch (static_cast<BuildPreambleError>(NewPreamble.getError().value())) {
+ case BuildPreambleError::CouldntCreateTempFile:
+ case BuildPreambleError::PreambleIsEmpty:
+ // Try again next time.
+ PreambleRebuildCounter = 1;
+ return nullptr;
+ case BuildPreambleError::CouldntCreateTargetInfo:
+ case BuildPreambleError::BeginSourceFileFailed:
+ case BuildPreambleError::CouldntEmitPCH:
+ case BuildPreambleError::CouldntCreateVFSOverlay:
+ // These erros are more likely to repeat, retry after some period.
+ PreambleRebuildCounter = DefaultPreambleRebuildInterval;
+ return nullptr;
+ }
+ llvm_unreachable("unexpected BuildPreambleError");
+ }
}
-
- Act->Execute();
- // Transfer any diagnostics generated when parsing the preamble into the set
- // of preamble diagnostics.
- for (stored_diag_iterator I = stored_diag_afterDriver_begin(),
- E = stored_diag_end();
- I != E; ++I)
- PreambleDiagnostics.push_back(
- makeStandaloneDiagnostic(Clang->getLangOpts(), *I));
+ assert(Preamble && "Preamble wasn't built");
- Act->EndSourceFile();
-
- checkAndRemoveNonDriverDiags(StoredDiagnostics);
+ TopLevelDecls.clear();
+ TopLevelDeclsInPreamble = Callbacks.takeTopLevelDeclIDs();
+ PreambleTopLevelHashValue = Callbacks.getHash();
- if (!Act->hasEmittedPreamblePCH()) {
- // The preamble PCH failed (e.g. there was a module loading fatal error),
- // so no precompiled header was generated. Forget that we even tried.
- // FIXME: Should we leave a note for ourselves to try again?
- llvm::sys::fs::remove(FrontendOpts.OutputFile);
- Preamble.clear();
- TopLevelDeclsInPreamble.clear();
- PreambleRebuildCounter = DefaultPreambleRebuildInterval;
- PreprocessorOpts.RemappedFileBuffers.pop_back();
- return nullptr;
- }
-
- // Keep track of the preamble we precompiled.
- setPreambleFile(this, FrontendOpts.OutputFile);
NumWarningsInPreamble = getDiagnostics().getNumWarnings();
-
- // Keep track of all of the files that the source manager knows about,
- // so we can verify whether they have changed or not.
- FilesInPreamble.clear();
- 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()] = PreambleFileHash::createForFile(
- File->getSize(), ModTime);
- } else {
- llvm::MemoryBuffer *Buffer = SourceMgr.getMemoryBufferForFile(File);
- FilesInPreamble[File->getName()] =
- PreambleFileHash::createForMemoryBuffer(Buffer);
- }
- }
- PreambleRebuildCounter = 1;
- PreprocessorOpts.RemappedFileBuffers.pop_back();
+ checkAndRemoveNonDriverDiags(NewPreambleDiags);
+ StoredDiagnostics = std::move(NewPreambleDiags);
+ PreambleDiagnostics = std::move(NewPreambleDiagsStandalone);
// If the hash of top-level entities differs from the hash of the top-level
// entities the last time we rebuilt the preamble, clear out the completion
@@ -1673,11 +1311,12 @@ ASTUnit::getMainBufferWithPrecompiledPreamble(
PreambleTopLevelHashValue = CurrentTopLevelHashValue;
}
- return llvm::MemoryBuffer::getMemBufferCopy(NewPreamble.Buffer->getBuffer(),
- MainFilename);
+ return MainFileBuffer;
}
void ASTUnit::RealizeTopLevelDeclsFromPreamble() {
+ assert(Preamble && "Should only be called when preamble was built");
+
std::vector<Decl *> Resolved;
Resolved.reserve(TopLevelDeclsInPreamble.size());
ExternalASTSource &Source = *getASTContext().getExternalSource();
@@ -1995,8 +1634,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
{
- CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags,
- StoredDiagnostics);
+ CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags,
+ &StoredDiagnostics, nullptr);
CI = clang::createInvocationFromCommandLine(
llvm::makeArrayRef(ArgBegin, ArgEnd), Diags);
@@ -2101,7 +1740,7 @@ bool ASTUnit::Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
// If we have a preamble file lying around, or if we might try to
// build a precompiled preamble, do so now.
std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer;
- if (!getPreambleFile(this).empty() || PreambleRebuildCounter > 0)
+ if (Preamble || PreambleRebuildCounter > 0)
OverrideMainBuffer =
getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation, VFS);
@@ -2435,7 +2074,7 @@ void ASTUnit::CodeComplete(
Clang->setDiagnostics(&Diag);
CaptureDroppedDiagnostics Capture(true,
Clang->getDiagnostics(),
- StoredDiagnostics);
+ &StoredDiagnostics, nullptr);
ProcessWarningOptions(Diag, Inv.getDiagnosticOpts());
// Create the target instance.
@@ -2484,7 +2123,7 @@ void ASTUnit::CodeComplete(
// point is within the main file, after the end of the precompiled
// preamble.
std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer;
- if (!getPreambleFile(this).empty()) {
+ if (Preamble) {
std::string CompleteFilePath(File);
auto VFS = FileMgr.getVirtualFileSystem();
@@ -2506,14 +2145,8 @@ void ASTUnit::CodeComplete(
// If the main file has been overridden due to the use of a preamble,
// make that override happen and introduce the preamble.
if (OverrideMainBuffer) {
- PreprocessorOpts.addRemappedFile(OriginalSourceFile,
- OverrideMainBuffer.get());
- PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size();
- PreprocessorOpts.PrecompiledPreambleBytes.second
- = PreambleEndsAtStartOfLine;
- PreprocessorOpts.ImplicitPCHInclude = getPreambleFile(this);
- PreprocessorOpts.DisablePCHValidation = true;
-
+ assert(Preamble && "No preamble was built, but OverrideMainBuffer is not null");
+ Preamble->AddImplicitPreamble(Clang->getInvocation(), OverrideMainBuffer.get());
OwnedBuffers.push_back(OverrideMainBuffer.release());
} else {
PreprocessorOpts.PrecompiledPreambleBytes.first = 0;
@@ -2760,11 +2393,11 @@ SourceLocation ASTUnit::mapLocationFromPreamble(SourceLocation Loc) {
if (SourceMgr)
PreambleID = SourceMgr->getPreambleFileID();
- if (Loc.isInvalid() || Preamble.empty() || PreambleID.isInvalid())
+ if (Loc.isInvalid() || !Preamble || PreambleID.isInvalid())
return Loc;
unsigned Offs;
- if (SourceMgr->isInFileID(Loc, PreambleID, &Offs) && Offs < Preamble.size()) {
+ if (SourceMgr->isInFileID(Loc, PreambleID, &Offs) && Offs < Preamble->getBounds().Size) {
SourceLocation FileLoc
= SourceMgr->getLocForStartOfFile(SourceMgr->getMainFileID());
return FileLoc.getLocWithOffset(Offs);
@@ -2781,12 +2414,12 @@ SourceLocation ASTUnit::mapLocationToPreamble(SourceLocation Loc) {
if (SourceMgr)
PreambleID = SourceMgr->getPreambleFileID();
- if (Loc.isInvalid() || Preamble.empty() || PreambleID.isInvalid())
+ if (Loc.isInvalid() || !Preamble || PreambleID.isInvalid())
return Loc;
unsigned Offs;
if (SourceMgr->isInFileID(Loc, SourceMgr->getMainFileID(), &Offs) &&
- Offs < Preamble.size()) {
+ Offs < Preamble->getBounds().Size) {
SourceLocation FileLoc = SourceMgr->getLocForStartOfFile(PreambleID);
return FileLoc.getLocWithOffset(Offs);
}
@@ -2932,17 +2565,6 @@ InputKind ASTUnit::getInputKind() const {
return InputKind(Lang, Fmt, PP);
}
-void ASTUnit::PreambleData::countLines() const {
- NumLines = 0;
- if (empty())
- return;
-
- NumLines = std::count(Buffer.begin(), Buffer.end(), '\n');
-
- if (Buffer.back() != '\n')
- ++NumLines;
-}
-
#ifndef NDEBUG
ASTUnit::ConcurrencyState::ConcurrencyState() {
Mutex = new llvm::sys::MutexImpl(/*recursive=*/true);
diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt
index 18abecd2071c..ba3bd7d28c70 100644
--- a/lib/Frontend/CMakeLists.txt
+++ b/lib/Frontend/CMakeLists.txt
@@ -38,6 +38,7 @@ add_clang_library(clangFrontend
ModuleDependencyCollector.cpp
MultiplexConsumer.cpp
PCHContainerOperations.cpp
+ PrecompiledPreamble.cpp
PrintPreprocessedOutput.cpp
SerializedDiagnosticPrinter.cpp
SerializedDiagnosticReader.cpp
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index 72a8c3818093..e5da2ae4f22e 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.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,
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 1667af2d12bb..6254b0013bab 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -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);
diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp
index 7c0b854648bd..f81a06b31869 100644
--- a/lib/Frontend/FrontendAction.cpp
+++ b/lib/Frontend/FrontendAction.cpp
@@ -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();
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index c5567a09636b..9621889b27ad 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -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
diff --git a/lib/Frontend/PrecompiledPreamble.cpp b/lib/Frontend/PrecompiledPreamble.cpp
new file mode 100644
index 000000000000..15b24cbed484
--- /dev/null
+++ b/lib/Frontend/PrecompiledPreamble.cpp
@@ -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");
+}
diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp
index 832eaf2926f0..5336de1f7468 100644
--- a/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -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();
}
diff --git a/lib/Frontend/Rewrite/FrontendActions.cpp b/lib/Frontend/Rewrite/FrontendActions.cpp
index 45feffbcb5b5..e93f737c47fd 100644
--- a/lib/Frontend/Rewrite/FrontendActions.cpp
+++ b/lib/Frontend/Rewrite/FrontendActions.cpp
@@ -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 @@ public:
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 @@ public:
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;
diff --git a/lib/Frontend/Rewrite/InclusionRewriter.cpp b/lib/Frontend/Rewrite/InclusionRewriter.cpp
index 3564cebba8a8..e0477069b340 100644
--- a/lib/Frontend/Rewrite/InclusionRewriter.cpp
+++ b/lib/Frontend/Rewrite/InclusionRewriter.cpp
@@ -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.
diff --git a/lib/Index/IndexDecl.cpp b/lib/Index/IndexDecl.cpp
index 2162c039c48b..d1127722c8ca 100644
--- a/lib/Index/IndexDecl.cpp
+++ b/lib/Index/IndexDecl.cpp
@@ -351,9 +351,11 @@ public:
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 @@ public:
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());
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index 447ff212f06e..012189aa6f9f 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -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)
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index 89c2ebd00a68..8c79e50176e1 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -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,
diff --git a/lib/Lex/PPExpressions.cpp b/lib/Lex/PPExpressions.cpp
index 862a4713e4bc..12f5084298df 100644
--- a/lib/Lex/PPExpressions.cpp
+++ b/lib/Lex/PPExpressions.cpp
@@ -73,6 +73,7 @@ public:
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};
}
diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp
index c16478dd2be4..bf2363a0a6f4 100644
--- a/lib/Lex/Pragma.cpp
+++ b/lib/Lex/Pragma.cpp
@@ -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 @@ public:
}
};
-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;
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 22696a957a10..d0ce9fc89583 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -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");
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 1a4607a84cff..a724fa242268 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -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.
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 77e63efc065e..caa6323d3209 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -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();
}
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 37c80fe5e520..944cd775d52a 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -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);
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index db688b12cbcf..934e13e72d05 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -279,6 +279,150 @@ static void checkRecursiveFunction(Sema &S, const FunctionDecl *FD,
}
//===----------------------------------------------------------------------===//
+// 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,
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index e7b0914641ff..007a5e483e6c 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -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());
}
diff --git a/lib/Sema/SemaCUDA.cpp b/lib/Sema/SemaCUDA.cpp
index b938ac387c4d..cac5f682275e 100644
--- a/lib/Sema/SemaCUDA.cpp
+++ b/lib/Sema/SemaCUDA.cpp
@@ -629,12 +629,6 @@ static bool IsKnownEmitted(Sema &S, FunctionDecl *FD) {
// emitted, because (say) the definition could include "inline".
FunctionDecl *Def = FD->getDefinition();
- // We may currently be parsing the body of FD, in which case
- // FD->getDefinition() will be null, but we still want to treat FD as though
- // it's a definition.
- if (!Def && FD->willHaveBody())
- Def = FD;
-
if (Def &&
!isDiscardableGVALinkage(S.getASTContext().GetGVALinkageForFunction(Def)))
return true;
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index cba220daf774..e340456bc6da 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -7260,11 +7260,11 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
NewVD->setInvalidDecl();
return;
}
- // OpenCL v1.1 s6.5.2 and s6.5.3 no local or constant variables
- // in functions.
if (T.getAddressSpace() == LangAS::opencl_constant ||
T.getAddressSpace() == LangAS::opencl_local) {
FunctionDecl *FD = getCurFunctionDecl();
+ // OpenCL v1.1 s6.5.2 and s6.5.3: no local or constant variables
+ // in functions.
if (FD && !FD->hasAttr<OpenCLKernelAttr>()) {
if (T.getAddressSpace() == LangAS::opencl_constant)
Diag(NewVD->getLocation(), diag::err_opencl_function_variable)
@@ -7275,6 +7275,20 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
NewVD->setInvalidDecl();
return;
}
+ // OpenCL v2.0 s6.5.2 and s6.5.3: local and constant variables must be
+ // in the outermost scope of a kernel function.
+ if (FD && FD->hasAttr<OpenCLKernelAttr>()) {
+ if (!getCurScope()->isFunctionScope()) {
+ if (T.getAddressSpace() == LangAS::opencl_constant)
+ Diag(NewVD->getLocation(), diag::err_opencl_addrspace_scope)
+ << "constant";
+ else
+ Diag(NewVD->getLocation(), diag::err_opencl_addrspace_scope)
+ << "local";
+ NewVD->setInvalidDecl();
+ return;
+ }
+ }
} else if (T.getAddressSpace() != LangAS::Default) {
// Do not allow other address spaces on automatic variable.
Diag(NewVD->getLocation(), diag::err_as_qualified_auto_decl) << 1;
@@ -12218,6 +12232,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
if (FD) {
FD->setBody(Body);
+ FD->setWillHaveBody(false);
if (getLangOpts().CPlusPlus14) {
if (!FD->isInvalidDecl() && Body && !FD->isDependentContext() &&
@@ -13075,7 +13090,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
SourceLocation ScopedEnumKWLoc,
bool ScopedEnumUsesClassTag,
TypeResult UnderlyingType,
- bool IsTypeSpecifier, SkipBodyInfo *SkipBody) {
+ bool IsTypeSpecifier, bool IsTemplateParamOrArg,
+ SkipBodyInfo *SkipBody) {
// If this is not a definition, it must have a name.
IdentifierInfo *OrigName = Name;
assert((Name != nullptr || TUK == TUK_Definition) &&
@@ -13345,11 +13361,11 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// also need to do a redeclaration lookup there, just in case
// there's a shadow friend decl.
if (Name && Previous.empty() &&
- (TUK == TUK_Reference || TUK == TUK_Friend)) {
+ (TUK == TUK_Reference || TUK == TUK_Friend || IsTemplateParamOrArg)) {
if (Invalid) goto CreateNewDecl;
assert(SS.isEmpty());
- if (TUK == TUK_Reference) {
+ if (TUK == TUK_Reference || IsTemplateParamOrArg) {
// C++ [basic.scope.pdecl]p5:
// -- for an elaborated-type-specifier of the form
//
@@ -13782,7 +13798,8 @@ CreateNewDecl:
// C++11 [dcl.type]p3:
// A type-specifier-seq shall not define a class or enumeration [...].
- if (getLangOpts().CPlusPlus && IsTypeSpecifier && TUK == TUK_Definition) {
+ if (getLangOpts().CPlusPlus && (IsTypeSpecifier || IsTemplateParamOrArg) &&
+ TUK == TUK_Definition) {
Diag(New->getLocation(), diag::err_type_defined_in_type_specifier)
<< Context.getTagDeclType(New);
Invalid = true;
@@ -16089,7 +16106,10 @@ void Sema::ActOnModuleBegin(SourceLocation DirectiveLoc, Module *Mod) {
// lexically within the module.
if (getLangOpts().trackLocalOwningModule()) {
for (auto *DC = CurContext; DC; DC = DC->getLexicalParent()) {
- cast<Decl>(DC)->setHidden(true);
+ cast<Decl>(DC)->setModuleOwnershipKind(
+ getLangOpts().ModulesLocalVisibility
+ ? Decl::ModuleOwnershipKind::VisibleWhenImported
+ : Decl::ModuleOwnershipKind::Visible);
cast<Decl>(DC)->setLocalOwningModule(Mod);
}
}
@@ -16129,7 +16149,8 @@ void Sema::ActOnModuleEnd(SourceLocation EomLoc, Module *Mod) {
for (auto *DC = CurContext; DC; DC = DC->getLexicalParent()) {
cast<Decl>(DC)->setLocalOwningModule(getCurrentModule());
if (!getCurrentModule())
- cast<Decl>(DC)->setHidden(false);
+ cast<Decl>(DC)->setModuleOwnershipKind(
+ Decl::ModuleOwnershipKind::Unowned);
}
}
}
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index b43642f5493b..e8503427536d 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -6903,6 +6903,32 @@ static bool ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K,
return true;
}
+static bool
+shouldDiagnoseAvailabilityByDefault(const ASTContext &Context,
+ const VersionTuple &DeploymentVersion,
+ const VersionTuple &DeclVersion) {
+ const auto &Triple = Context.getTargetInfo().getTriple();
+ VersionTuple ForceAvailabilityFromVersion;
+ switch (Triple.getOS()) {
+ case llvm::Triple::IOS:
+ case llvm::Triple::TvOS:
+ ForceAvailabilityFromVersion = VersionTuple(/*Major=*/11);
+ break;
+ case llvm::Triple::WatchOS:
+ ForceAvailabilityFromVersion = VersionTuple(/*Major=*/4);
+ break;
+ case llvm::Triple::Darwin:
+ case llvm::Triple::MacOSX:
+ ForceAvailabilityFromVersion = VersionTuple(/*Major=*/10, /*Minor=*/13);
+ break;
+ default:
+ // New targets should always warn about availability.
+ return Triple.getVendor() == llvm::Triple::Apple;
+ }
+ return DeploymentVersion >= ForceAvailabilityFromVersion ||
+ DeclVersion >= ForceAvailabilityFromVersion;
+}
+
static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
Decl *Ctx, const NamedDecl *D,
StringRef Message, SourceLocation Loc,
@@ -6991,13 +7017,26 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
}
break;
- case AR_NotYetIntroduced:
- diag = diag::warn_partial_availability;
- diag_message = diag::warn_partial_message;
- diag_fwdclass_message = diag::warn_partial_fwdclass_message;
+ case AR_NotYetIntroduced: {
+ // We would like to emit the diagnostic even if -Wunguarded-availability is
+ // not specified for deployment targets >= to iOS 11 or equivalent or
+ // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or
+ // later.
+ const AvailabilityAttr *AA = getAttrForPlatform(S.getASTContext(), D);
+ VersionTuple Introduced = AA->getIntroduced();
+ bool NewWarning = shouldDiagnoseAvailabilityByDefault(
+ S.Context, S.Context.getTargetInfo().getPlatformMinVersion(),
+ Introduced);
+ diag = NewWarning ? diag::warn_partial_availability_new
+ : diag::warn_partial_availability;
+ diag_message = NewWarning ? diag::warn_partial_message_new
+ : diag::warn_partial_message;
+ diag_fwdclass_message = NewWarning ? diag::warn_partial_fwdclass_message_new
+ : diag::warn_partial_fwdclass_message;
property_note_select = /* partial */ 2;
available_here_select_kind = /* partial */ 3;
break;
+ }
case AR_Available:
llvm_unreachable("Warning for availability of available declaration?");
@@ -7317,7 +7356,18 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability(
if (!ShouldDiagnoseAvailabilityInContext(SemaRef, Result, Introduced, Ctx))
return;
- SemaRef.Diag(Range.getBegin(), diag::warn_unguarded_availability)
+ // We would like to emit the diagnostic even if -Wunguarded-availability is
+ // not specified for deployment targets >= to iOS 11 or equivalent or
+ // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or
+ // later.
+ unsigned DiagKind =
+ shouldDiagnoseAvailabilityByDefault(
+ SemaRef.Context,
+ SemaRef.Context.getTargetInfo().getPlatformMinVersion(), Introduced)
+ ? diag::warn_unguarded_availability_new
+ : diag::warn_unguarded_availability;
+
+ SemaRef.Diag(Range.getBegin(), DiagKind)
<< Range << D
<< AvailabilityAttr::getPrettyPlatformName(
SemaRef.getASTContext().getTargetInfo().getPlatformName())
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 844299bb87cf..453ece9d9c4d 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -13394,7 +13394,8 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
/*ScopedEnumKWLoc=*/SourceLocation(),
/*ScopedEnumUsesClassTag=*/false,
/*UnderlyingType=*/TypeResult(),
- /*IsTypeSpecifier=*/false);
+ /*IsTypeSpecifier=*/false,
+ /*IsTemplateParamOrArg=*/false);
}
NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context);
@@ -13878,6 +13879,9 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) {
return;
}
+ // Deleted function does not have a body.
+ Fn->setWillHaveBody(false);
+
if (const FunctionDecl *Prev = Fn->getPreviousDecl()) {
// Don't consider the implicit declaration we generate for explicit
// specializations. FIXME: Do not generate these implicit declarations.
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 75a6903392ea..f49df6b3216d 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -13732,6 +13732,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
// call to such a function.
InstantiateFunctionDefinition(PointOfInstantiation, Func);
else {
+ Func->setInstantiationIsPending(true);
PendingInstantiations.push_back(std::make_pair(Func,
PointOfInstantiation));
// Notify the consumer that a function was implicitly instantiated.
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index a9ff21bc41ab..710ead30790f 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -2630,7 +2630,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
// Make the function visible to name lookup, even if we found it in
// an unimported module. It either is an implicitly-declared global
// allocation function, or is suppressing that function.
- Func->setHidden(false);
+ Func->setVisibleDespiteOwningModule();
return;
}
}
@@ -2662,7 +2662,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
FnType, /*TInfo=*/nullptr, SC_None, false, true);
Alloc->setImplicit();
// Global allocation functions should always be visible.
- Alloc->setHidden(false);
+ Alloc->setVisibleDespiteOwningModule();
// Implicit sized deallocation functions always have default visibility.
Alloc->addAttr(
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 1fb25f4e0e7c..2e7fb875a276 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -862,6 +862,16 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
if (!Record->isCompleteDefinition())
return Found;
+ // For conversion operators, 'operator auto' should only match
+ // 'operator auto'. Since 'auto' is not a type, it shouldn't be considered
+ // as a candidate for template substitution.
+ auto *ContainedDeducedType =
+ R.getLookupName().getCXXNameType()->getContainedDeducedType();
+ if (R.getLookupName().getNameKind() ==
+ DeclarationName::CXXConversionFunctionName &&
+ ContainedDeducedType && ContainedDeducedType->isUndeducedType())
+ return Found;
+
for (CXXRecordDecl::conversion_iterator U = Record->conversion_begin(),
UEnd = Record->conversion_end(); U != UEnd; ++U) {
FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(*U);
@@ -1331,7 +1341,7 @@ void Sema::makeMergedDefinitionVisible(NamedDecl *ND) {
Context.mergeDefinitionIntoModule(ND, M);
else
// We're not building a module; just make the definition visible.
- ND->setHidden(false);
+ ND->setVisibleDespiteOwningModule();
// If ND is a template declaration, make the template parameters
// visible too. They're not (necessarily) within a mergeable DeclContext.
@@ -1518,7 +1528,7 @@ bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) {
!SemaRef.getLangOpts().ModulesLocalVisibility) {
// Cache the fact that this declaration is implicitly visible because
// its parent has a visible definition.
- D->setHidden(false);
+ D->setVisibleDespiteOwningModule();
}
return true;
}
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 1eea151a4ec8..a8923ce9e27d 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -8612,7 +8612,8 @@ Sema::ActOnExplicitInstantiation(Scope *S,
/*ModulePrivateLoc=*/SourceLocation(),
MultiTemplateParamsArg(), Owned, IsDependent,
SourceLocation(), false, TypeResult(),
- /*IsTypeSpecifier*/false);
+ /*IsTypeSpecifier*/false,
+ /*IsTemplateParamOrArg*/false);
assert(!IsDependent && "explicit instantiation of dependent name not yet handled");
if (!TagD)
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index fe92dd8ac653..f4f0c804aee1 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2045,7 +2045,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
// The instantiation is visible here, even if it was first declared in an
// unimported module.
- Instantiation->setHidden(false);
+ Instantiation->setVisibleDespiteOwningModule();
// FIXME: This loses the as-written tag kind for an explicit instantiation.
Instantiation->setTagKind(Pattern->getTagKind());
@@ -2247,7 +2247,7 @@ bool Sema::InstantiateEnum(SourceLocation PointOfInstantiation,
// The instantiation is visible here, even if it was first declared in an
// unimported module.
- Instantiation->setHidden(false);
+ Instantiation->setVisibleDespiteOwningModule();
// Enter the scope of this instantiation. We don't use
// PushDeclContext because we don't have a scope.
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 148ce24293a0..abe912fb548b 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1782,6 +1782,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
Previous.clear();
}
+ if (isFriend)
+ Function->setObjectOfFriendDecl();
+
SemaRef.CheckFunctionDeclaration(/*Scope*/ nullptr, Function, Previous,
isExplicitSpecialization);
@@ -3782,6 +3785,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
// Try again at the end of the translation unit (at which point a
// definition will be required).
assert(!Recursive);
+ Function->setInstantiationIsPending(true);
PendingInstantiations.push_back(
std::make_pair(Function, PointOfInstantiation));
} else if (TSK == TSK_ImplicitInstantiation) {
@@ -3801,6 +3805,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
// Postpone late parsed template instantiations.
if (PatternDecl->isLateTemplateParsed() &&
!LateTemplateParser) {
+ Function->setInstantiationIsPending(true);
PendingInstantiations.push_back(
std::make_pair(Function, PointOfInstantiation));
return;
@@ -3863,7 +3868,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
// The instantiation is visible here, even if it was first declared in an
// unimported module.
- Function->setHidden(false);
+ Function->setVisibleDespiteOwningModule();
// Copy the inner loc start from the pattern.
Function->setInnerLocStart(PatternDecl->getInnerLocStart());
@@ -4269,7 +4274,7 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
// The instantiation is visible here, even if it was first declared in an
// unimported module.
- Var->setHidden(false);
+ Var->setVisibleDespiteOwningModule();
// If we're performing recursive template instantiation, create our own
// queue of pending implicit instantiations that we will instantiate
@@ -4285,9 +4290,6 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
InstantiateVariableInitializer(Var, PatternDecl, TemplateArgs);
PreviousContext.pop();
- // FIXME: Need to inform the ASTConsumer that we instantiated the
- // initializer?
-
// This variable may have local implicit instantiations that need to be
// instantiated within this scope.
LocalInstantiations.perform();
@@ -4397,7 +4399,6 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
if (Def->isStaticDataMember() && !Def->isOutOfLine()) {
// We're instantiating an inline static data member whose definition was
// provided inside the class.
- // FIXME: Update record?
InstantiateVariableInitializer(Var, Def, TemplateArgs);
} else if (!VarSpec) {
Var = cast_or_null<VarDecl>(SubstDecl(Def, Var->getDeclContext(),
@@ -5146,6 +5147,8 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) {
TSK_ExplicitInstantiationDefinition;
InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true,
DefinitionRequired, true);
+ if (Function->isDefined())
+ Function->setInstantiationIsPending(false);
continue;
}
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index eeb0132c1690..ef2841849ff6 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -3580,8 +3580,8 @@ static void moveMethodToBackOfGlobalList(Sema &S, ObjCMethodDecl *Method) {
void ASTReader::makeNamesVisible(const HiddenNames &Names, Module *Owner) {
assert(Owner->NameVisibility != Module::Hidden && "nothing to make visible?");
for (Decl *D : Names) {
- bool wasHidden = D->Hidden;
- D->Hidden = false;
+ bool wasHidden = D->isHidden();
+ D->setVisibleDespiteOwningModule();
if (wasHidden && SemaObj) {
if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(D)) {
@@ -3648,7 +3648,7 @@ void ASTReader::mergeDefinitionVisibility(NamedDecl *Def,
if (Def->isHidden()) {
// If MergedDef is visible or becomes visible, make the definition visible.
if (!MergedDef->isHidden())
- Def->Hidden = false;
+ Def->setVisibleDespiteOwningModule();
else if (getContext().getLangOpts().ModulesLocalVisibility) {
getContext().mergeDefinitionIntoModule(
Def, MergedDef->getImportedOwningModule(),
@@ -9324,9 +9324,20 @@ void ASTReader::diagnoseOdrViolations() {
diag::err_module_odr_violation_different_definitions)
<< FirstRecord << FirstModule.empty() << FirstModule;
+ if (FirstDecl) {
+ Diag(FirstDecl->getLocation(), diag::note_first_module_difference)
+ << FirstRecord << FirstDecl->getSourceRange();
+ }
+
Diag(SecondRecord->getLocation(),
diag::note_module_odr_violation_different_definitions)
<< SecondModule;
+
+ if (SecondDecl) {
+ Diag(SecondDecl->getLocation(), diag::note_second_module_difference)
+ << SecondDecl->getSourceRange();
+ }
+
Diagnosed = true;
break;
}
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index ed103e629216..07ab421cfc51 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -522,31 +522,29 @@ void ASTDeclReader::VisitDecl(Decl *D) {
D->setTopLevelDeclInObjCContainer(Record.readInt());
D->setAccess((AccessSpecifier)Record.readInt());
D->FromASTFile = true;
- D->setModulePrivate(Record.readInt());
- D->Hidden = D->isModulePrivate();
+ bool ModulePrivate = Record.readInt();
// Determine whether this declaration is part of a (sub)module. If so, it
// may not yet be visible.
if (unsigned SubmoduleID = readSubmoduleID()) {
// Store the owning submodule ID in the declaration.
+ D->setModuleOwnershipKind(
+ ModulePrivate ? Decl::ModuleOwnershipKind::ModulePrivate
+ : Decl::ModuleOwnershipKind::VisibleWhenImported);
D->setOwningModuleID(SubmoduleID);
- if (D->Hidden) {
- // Module-private declarations are never visible, so there is no work to do.
+ if (ModulePrivate) {
+ // Module-private declarations are never visible, so there is no work to
+ // do.
} else if (Reader.getContext().getLangOpts().ModulesLocalVisibility) {
// If local visibility is being tracked, this declaration will become
- // hidden and visible as the owning module does. Inform Sema that this
- // declaration might not be visible.
- D->Hidden = true;
+ // hidden and visible as the owning module does.
} else if (Module *Owner = Reader.getSubmodule(SubmoduleID)) {
- if (Owner->NameVisibility != Module::AllVisible) {
- // The owning module is not visible. Mark this declaration as hidden.
- D->Hidden = true;
-
- // Note that this declaration was hidden because its owning module is
- // not yet visible.
+ // Mark the declaration as visible when its owning module becomes visible.
+ if (Owner->NameVisibility == Module::AllVisible)
+ D->setVisibleDespiteOwningModule();
+ else
Reader.HiddenNamesMap[Owner].push_back(D);
- }
}
}
}
@@ -3934,10 +3932,21 @@ void ASTDeclReader::UpdateDecl(Decl *D) {
break;
}
- case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER:
- cast<VarDecl>(D)->getMemberSpecializationInfo()->setPointOfInstantiation(
+ case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER: {
+ VarDecl *VD = cast<VarDecl>(D);
+ VD->getMemberSpecializationInfo()->setPointOfInstantiation(
ReadSourceLocation());
+ uint64_t Val = Record.readInt();
+ if (Val && !VD->getInit()) {
+ VD->setInit(Record.readExpr());
+ if (Val > 1) { // IsInitKnownICE = 1, IsInitNotICE = 2, IsInitICE = 3
+ EvaluatedStmt *Eval = VD->ensureEvaluatedStmt();
+ Eval->CheckedICE = true;
+ Eval->IsICE = Val == 3;
+ }
+ }
break;
+ }
case UPD_CXX_INSTANTIATED_DEFAULT_ARGUMENT: {
auto Param = cast<ParmVarDecl>(D);
@@ -4133,7 +4142,7 @@ void ASTDeclReader::UpdateDecl(Decl *D) {
Reader.HiddenNamesMap[Owner].push_back(Exported);
} else {
// The declaration is now visible.
- Exported->Hidden = false;
+ Exported->setVisibleDespiteOwningModule();
}
break;
}
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index dcacabec1225..1c0db14ced14 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -5033,9 +5033,18 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
case UPD_CXX_ADDED_FUNCTION_DEFINITION:
break;
- case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER:
+ case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER: {
+ const VarDecl *VD = cast<VarDecl>(D);
Record.AddSourceLocation(Update.getLoc());
+ if (VD->getInit()) {
+ Record.push_back(!VD->isInitKnownICE() ? 1
+ : (VD->isInitICE() ? 3 : 2));
+ Record.AddStmt(const_cast<Expr*>(VD->getInit()));
+ } else {
+ Record.push_back(0);
+ }
break;
+ }
case UPD_CXX_INSTANTIATED_DEFAULT_ARGUMENT:
Record.AddStmt(const_cast<Expr *>(
diff --git a/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp b/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
index 48d6cd8a527c..097d4198800d 100644
--- a/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
@@ -50,8 +50,10 @@ bool BuiltinFunctionChecker::evalCall(const CallExpr *CE,
state = state->assume(ArgSVal.castAs<DefinedOrUnknownSVal>(), true);
// FIXME: do we want to warn here? Not right now. The most reports might
// come from infeasible paths, thus being false positives.
- if (!state)
+ if (!state) {
+ C.generateSink(C.getState(), C.getPredecessor());
return true;
+ }
C.addTransition(state);
return true;
diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index 32e3ce9270aa..77c24629d71e 100644
--- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -120,6 +120,7 @@ public:
void evalStdCopy(CheckerContext &C, const CallExpr *CE) const;
void evalStdCopyBackward(CheckerContext &C, const CallExpr *CE) const;
void evalStdCopyCommon(CheckerContext &C, const CallExpr *CE) const;
+ void evalMemset(CheckerContext &C, const CallExpr *CE) const;
// Utility methods
std::pair<ProgramStateRef , ProgramStateRef >
@@ -1999,6 +2000,54 @@ void CStringChecker::evalStdCopyCommon(CheckerContext &C,
C.addTransition(State);
}
+void CStringChecker::evalMemset(CheckerContext &C, const CallExpr *CE) const {
+ if (CE->getNumArgs() != 3)
+ return;
+
+ CurrentFunctionDescription = "memory set function";
+
+ const Expr *Mem = CE->getArg(0);
+ const Expr *Size = CE->getArg(2);
+ ProgramStateRef State = C.getState();
+
+ // See if the size argument is zero.
+ const LocationContext *LCtx = C.getLocationContext();
+ SVal SizeVal = State->getSVal(Size, LCtx);
+ QualType SizeTy = Size->getType();
+
+ ProgramStateRef StateZeroSize, StateNonZeroSize;
+ std::tie(StateZeroSize, StateNonZeroSize) =
+ assumeZero(C, State, SizeVal, SizeTy);
+
+ // Get the value of the memory area.
+ SVal MemVal = State->getSVal(Mem, LCtx);
+
+ // If the size is zero, there won't be any actual memory access, so
+ // just bind the return value to the Mem buffer and return.
+ if (StateZeroSize && !StateNonZeroSize) {
+ StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, MemVal);
+ C.addTransition(StateZeroSize);
+ return;
+ }
+
+ // Ensure the memory area is not null.
+ // If it is NULL there will be a NULL pointer dereference.
+ State = checkNonNull(C, StateNonZeroSize, Mem, MemVal);
+ if (!State)
+ return;
+
+ State = CheckBufferAccess(C, State, Size, Mem);
+ if (!State)
+ return;
+ State = InvalidateBuffer(C, State, Mem, C.getSVal(Mem),
+ /*IsSourceBuffer*/false, Size);
+ if (!State)
+ return;
+
+ State = State->BindExpr(CE, LCtx, MemVal);
+ C.addTransition(State);
+}
+
static bool isCPPStdLibraryFunction(const FunctionDecl *FD, StringRef Name) {
IdentifierInfo *II = FD->getIdentifier();
if (!II)
@@ -2032,6 +2081,8 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
evalFunction = &CStringChecker::evalMemcmp;
else if (C.isCLibraryFunction(FDecl, "memmove"))
evalFunction = &CStringChecker::evalMemmove;
+ else if (C.isCLibraryFunction(FDecl, "memset"))
+ evalFunction = &CStringChecker::evalMemset;
else if (C.isCLibraryFunction(FDecl, "strcpy"))
evalFunction = &CStringChecker::evalStrcpy;
else if (C.isCLibraryFunction(FDecl, "strncpy"))
diff --git a/lib/StaticAnalyzer/Checkers/CloneChecker.cpp b/lib/StaticAnalyzer/Checkers/CloneChecker.cpp
index 1885b0e39203..83955c586b68 100644
--- a/lib/StaticAnalyzer/Checkers/CloneChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CloneChecker.cpp
@@ -73,12 +73,17 @@ void CloneChecker::checkEndOfTranslationUnit(const TranslationUnitDecl *TU,
bool ReportNormalClones = Mgr.getAnalyzerOptions().getBooleanOption(
"ReportNormalClones", true, this);
+ StringRef IgnoredFilesPattern = Mgr.getAnalyzerOptions().getOptionAsString(
+ "IgnoredFilesPattern", "", this);
+
// Let the CloneDetector create a list of clones from all the analyzed
// statements. We don't filter for matching variable patterns at this point
// because reportSuspiciousClones() wants to search them for errors.
std::vector<CloneDetector::CloneGroup> AllCloneGroups;
- Detector.findClones(AllCloneGroups, RecursiveCloneTypeIIConstraint(),
+ Detector.findClones(AllCloneGroups,
+ FilenamePatternConstraint(IgnoredFilesPattern),
+ RecursiveCloneTypeIIConstraint(),
MinComplexityConstraint(MinComplexity),
MinGroupSizeConstraint(2), OnlyLargestCloneConstraint());
diff --git a/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp b/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
index af35c2b0e991..6bbaaac05e6b 100644
--- a/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
@@ -281,6 +281,9 @@ void NonLocalizedStringChecker::initUIMethods(ASTContext &Ctx) const {
IdentifierInfo *setLabelNSSegmentedControl[] = {
&Ctx.Idents.get("setLabel"), &Ctx.Idents.get("forSegment")};
ADD_METHOD(NSSegmentedControl, setLabelNSSegmentedControl, 2, 0)
+ IdentifierInfo *setToolTipNSSegmentedControl[] = {
+ &Ctx.Idents.get("setToolTip"), &Ctx.Idents.get("forSegment")};
+ ADD_METHOD(NSSegmentedControl, setToolTipNSSegmentedControl, 2, 0)
NEW_RECEIVER(NSButtonCell)
ADD_UNARY_METHOD(NSButtonCell, setTitle, 0)
@@ -562,6 +565,46 @@ void NonLocalizedStringChecker::initUIMethods(ASTContext &Ctx) const {
IdentifierInfo *setTitleUISegmentedControl[] = {
&Ctx.Idents.get("setTitle"), &Ctx.Idents.get("forSegmentAtIndex")};
ADD_METHOD(UISegmentedControl, setTitleUISegmentedControl, 2, 0)
+
+ NEW_RECEIVER(NSAccessibilityCustomRotorItemResult)
+ IdentifierInfo
+ *initWithItemLoadingTokenNSAccessibilityCustomRotorItemResult[] = {
+ &Ctx.Idents.get("initWithItemLoadingToken"),
+ &Ctx.Idents.get("customLabel")};
+ ADD_METHOD(NSAccessibilityCustomRotorItemResult,
+ initWithItemLoadingTokenNSAccessibilityCustomRotorItemResult, 2, 1)
+ ADD_UNARY_METHOD(NSAccessibilityCustomRotorItemResult, setCustomLabel, 0)
+
+ NEW_RECEIVER(UIContextualAction)
+ IdentifierInfo *contextualActionWithStyleUIContextualAction[] = {
+ &Ctx.Idents.get("contextualActionWithStyle"), &Ctx.Idents.get("title"),
+ &Ctx.Idents.get("handler")};
+ ADD_METHOD(UIContextualAction, contextualActionWithStyleUIContextualAction, 3,
+ 1)
+ ADD_UNARY_METHOD(UIContextualAction, setTitle, 0)
+
+ NEW_RECEIVER(NSAccessibilityCustomRotor)
+ IdentifierInfo *initWithLabelNSAccessibilityCustomRotor[] = {
+ &Ctx.Idents.get("initWithLabel"), &Ctx.Idents.get("itemSearchDelegate")};
+ ADD_METHOD(NSAccessibilityCustomRotor,
+ initWithLabelNSAccessibilityCustomRotor, 2, 0)
+ ADD_UNARY_METHOD(NSAccessibilityCustomRotor, setLabel, 0)
+
+ NEW_RECEIVER(NSWindowTab)
+ ADD_UNARY_METHOD(NSWindowTab, setTitle, 0)
+ ADD_UNARY_METHOD(NSWindowTab, setToolTip, 0)
+
+ NEW_RECEIVER(NSAccessibilityCustomAction)
+ IdentifierInfo *initWithNameNSAccessibilityCustomAction[] = {
+ &Ctx.Idents.get("initWithName"), &Ctx.Idents.get("handler")};
+ ADD_METHOD(NSAccessibilityCustomAction,
+ initWithNameNSAccessibilityCustomAction, 2, 0)
+ IdentifierInfo *initWithNameTargetNSAccessibilityCustomAction[] = {
+ &Ctx.Idents.get("initWithName"), &Ctx.Idents.get("target"),
+ &Ctx.Idents.get("selector")};
+ ADD_METHOD(NSAccessibilityCustomAction,
+ initWithNameTargetNSAccessibilityCustomAction, 3, 0)
+ ADD_UNARY_METHOD(NSAccessibilityCustomAction, setName, 0)
}
#define LSF_INSERT(function_name) LSF.insert(&Ctx.Idents.get(function_name));
diff --git a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
index 45ef612ee1d5..11b9f8c4f725 100644
--- a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
+++ b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
@@ -293,7 +293,7 @@ unsigned AnalyzerOptions::getMaxInlinableSize() {
DefaultValue = 4;
break;
case UMK_Deep:
- DefaultValue = 50;
+ DefaultValue = 100;
break;
}
@@ -332,7 +332,7 @@ unsigned AnalyzerOptions::getMaxNodesPerTopLevelFunction() {
DefaultValue = 75000;
break;
case UMK_Deep:
- DefaultValue = 150000;
+ DefaultValue = 225000;
break;
}
MaxNodesPerTopLevelFunction = getOptionAsInteger("max-nodes", DefaultValue);
diff --git a/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 8f720a2067b1..6f1e8391e67c 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -980,10 +980,9 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, ExplodedNode *Pred,
// transfer functions as "0 == E".
SVal Result;
if (Optional<Loc> LV = V.getAs<Loc>()) {
- Loc X = svalBuilder.makeNull();
+ Loc X = svalBuilder.makeNullWithType(Ex->getType());
Result = evalBinOp(state, BO_EQ, *LV, X, U->getType());
- }
- else if (Ex->getType()->isFloatingType()) {
+ } else if (Ex->getType()->isFloatingType()) {
// FIXME: handle floating point types.
Result = UnknownVal();
} else {
diff --git a/test/Analysis/analyzer-config.c b/test/Analysis/analyzer-config.c
index c0153a50532a..70521c63fbad 100644
--- a/test/Analysis/analyzer-config.c
+++ b/test/Analysis/analyzer-config.c
@@ -19,8 +19,8 @@ void foo() {
// CHECK-NEXT: ipa = dynamic-bifurcate
// CHECK-NEXT: ipa-always-inline-size = 3
// CHECK-NEXT: leak-diagnostics-reference-allocation = false
-// CHECK-NEXT: max-inlinable-size = 50
-// CHECK-NEXT: max-nodes = 150000
+// CHECK-NEXT: max-inlinable-size = 100
+// CHECK-NEXT: max-nodes = 225000
// CHECK-NEXT: max-times-inline-large = 32
// CHECK-NEXT: min-cfg-size-treat-functions-as-large = 14
// CHECK-NEXT: mode = deep
diff --git a/test/Analysis/analyzer-config.cpp b/test/Analysis/analyzer-config.cpp
index f84be1781160..60c03c1e497b 100644
--- a/test/Analysis/analyzer-config.cpp
+++ b/test/Analysis/analyzer-config.cpp
@@ -30,8 +30,8 @@ public:
// CHECK-NEXT: ipa = dynamic-bifurcate
// CHECK-NEXT: ipa-always-inline-size = 3
// CHECK-NEXT: leak-diagnostics-reference-allocation = false
-// CHECK-NEXT: max-inlinable-size = 50
-// CHECK-NEXT: max-nodes = 150000
+// CHECK-NEXT: max-inlinable-size = 100
+// CHECK-NEXT: max-nodes = 225000
// CHECK-NEXT: max-times-inline-large = 32
// CHECK-NEXT: min-cfg-size-treat-functions-as-large = 14
// CHECK-NEXT: mode = deep
diff --git a/test/Analysis/builtin-assume.c b/test/Analysis/builtin-assume.c
deleted file mode 100644
index 00d651d9e3be..000000000000
--- a/test/Analysis/builtin-assume.c
+++ /dev/null
@@ -1,8 +0,0 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s
-
-void clang_analyzer_eval(int);
-
-void f(int i) {
- __builtin_assume(i < 10);
- clang_analyzer_eval(i < 15); // expected-warning {{TRUE}}
-}
diff --git a/test/Analysis/builtin-functions.cpp b/test/Analysis/builtin-functions.cpp
index 4e9859754d62..2c1950251145 100644
--- a/test/Analysis/builtin-functions.cpp
+++ b/test/Analysis/builtin-functions.cpp
@@ -1,6 +1,7 @@
// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,debug.ExprInspection %s -std=c++11 -verify
void clang_analyzer_eval(bool);
+void clang_analyzer_warnIfReached();
void testAddressof(int x) {
clang_analyzer_eval(&x == __builtin_addressof(x)); // expected-warning{{TRUE}}
@@ -50,3 +51,16 @@ void test_assume_aligned_4(char *p) {
q = (char*) __builtin_assume_aligned(p + 1, 16);
clang_analyzer_eval(p == q); // expected-warning{{FALSE}}
}
+
+void f(int i) {
+ __builtin_assume(i < 10);
+ clang_analyzer_eval(i < 15); // expected-warning {{TRUE}}
+}
+
+void g(int i) {
+ if (i > 5) {
+ __builtin_assume(i < 5);
+ clang_analyzer_warnIfReached(); // Assumtion contradicts constraints.
+ // We give up the analysis on this path.
+ }
+}
diff --git a/test/Analysis/copypaste/autogenerated_automoc.cpp b/test/Analysis/copypaste/autogenerated_automoc.cpp
new file mode 100644
index 000000000000..55963c4545c9
--- /dev/null
+++ b/test/Analysis/copypaste/autogenerated_automoc.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:IgnoredFilesPattern="moc_|.*_automoc.cpp" -verify %s
+
+// Because files that have `_automoc.' in their names are most likely autogenerated,
+// we suppress copy-paste warnings here.
+
+// expected-no-diagnostics
+
+void f1() {
+ int *p1 = new int[1];
+ int *p2 = new int[1];
+ if (p1) {
+ delete [] p1;
+ p1 = nullptr;
+ }
+ if (p2) {
+ delete [] p1; // no-warning
+ p2 = nullptr;
+ }
+}
diff --git a/test/Analysis/copypaste/dbus_autogenerated.cpp b/test/Analysis/copypaste/dbus_autogenerated.cpp
new file mode 100644
index 000000000000..182437565813
--- /dev/null
+++ b/test/Analysis/copypaste/dbus_autogenerated.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:IgnoredFilesPattern="moc_|dbus_|.*_automoc" -verify %s
+
+// Because files that have `dbus_' in their names are most likely autogenerated,
+// we suppress copy-paste warnings here.
+
+// expected-no-diagnostics
+
+void f1() {
+ int *p1 = new int[1];
+ int *p2 = new int[1];
+ if (p1) {
+ delete [] p1;
+ p1 = nullptr;
+ }
+ if (p2) {
+ delete [] p1; // no-warning
+ p2 = nullptr;
+ }
+}
diff --git a/test/Analysis/copypaste/moc_autogenerated.cpp b/test/Analysis/copypaste/moc_autogenerated.cpp
new file mode 100644
index 000000000000..626fe2a3dd07
--- /dev/null
+++ b/test/Analysis/copypaste/moc_autogenerated.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:IgnoredFilesPattern="moc_|.*_automoc" -verify %s
+
+// Because files that have `moc_' in their names are most likely autogenerated,
+// we suppress copy-paste warnings here.
+
+// expected-no-diagnostics
+
+void f1() {
+ int *p1 = new int[1];
+ int *p2 = new int[1];
+ if (p1) {
+ delete [] p1;
+ p1 = nullptr;
+ }
+ if (p2) {
+ delete [] p1; // no-warning
+ p2 = nullptr;
+ }
+}
diff --git a/test/Analysis/copypaste/not-autogenerated.cpp b/test/Analysis/copypaste/not-autogenerated.cpp
new file mode 100644
index 000000000000..765e7aaf2aab
--- /dev/null
+++ b/test/Analysis/copypaste/not-autogenerated.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:IgnoredFilesPattern="moc_|ui_|dbus_|.*_automoc" -verify %s
+
+void f1() {
+ int *p1 = new int[1];
+ int *p2 = new int[1];
+ if (p1) {
+ delete [] p1; // expected-note{{Similar code using 'p1' here}}
+ p1 = nullptr;
+ }
+ if (p2) {
+ delete [] p1; // expected-warning{{Potential copy-paste error; did you really mean to use 'p1' here?}}
+ p2 = nullptr;
+ }
+}
diff --git a/test/Analysis/copypaste/ui_autogenerated.cpp b/test/Analysis/copypaste/ui_autogenerated.cpp
new file mode 100644
index 000000000000..a08c33fe9e2a
--- /dev/null
+++ b/test/Analysis/copypaste/ui_autogenerated.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:IgnoredFilesPattern="moc_|ui_|.*_automoc" -verify %s
+
+// Because files that have `ui_' in their names are most likely autogenerated,
+// we suppress copy-paste warnings here.
+
+// expected-no-diagnostics
+
+void f1() {
+ int *p1 = new int[1];
+ int *p2 = new int[1];
+ if (p1) {
+ delete [] p1;
+ p1 = nullptr;
+ }
+ if (p2) {
+ delete [] p1; // no-warning
+ p2 = nullptr;
+ }
+}
diff --git a/test/Analysis/null-deref-ps-region.c b/test/Analysis/null-deref-ps-region.c
index 6ef99ae473ca..c46ca6c52ae3 100644
--- a/test/Analysis/null-deref-ps-region.c
+++ b/test/Analysis/null-deref-ps-region.c
@@ -1,6 +1,11 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -std=gnu99 -analyzer-store=region -verify %s
-// expected-no-diagnostics
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core,unix,alpha.unix -std=gnu99 -analyzer-store=region -verify %s
+#include "Inputs/system-header-simulator.h"
+
+typedef __typeof(sizeof(int)) size_t;
+void *memset(void *__s, int __c, size_t __n);
+void *malloc(size_t __size);
+void free(void *__ptr);
// The store for 'a[1]' should not be removed mistakenly. SymbolicRegions may
// also be live roots.
@@ -13,3 +18,55 @@ void f14(int *a) {
i = *p; // no-warning
}
}
+
+void foo() {
+ int *x = malloc(sizeof(int));
+ memset(x, 0, sizeof(int));
+ int n = 1 / *x; // FIXME: no-warning
+ free(x);
+}
+
+void bar() {
+ int *x = malloc(sizeof(int));
+ memset(x, 0, 1);
+ int n = 1 / *x; // no-warning
+ free(x);
+}
+
+void testConcreteNull() {
+ int *x = 0;
+ memset(x, 0, 1); // expected-warning {{Null pointer argument in call to memory set function}}
+}
+
+void testStackArray() {
+ char buf[13];
+ memset(buf, 0, 1); // no-warning
+}
+
+void testHeapSymbol() {
+ char *buf = (char *)malloc(13);
+ memset(buf, 0, 1); // no-warning
+ free(buf);
+}
+
+void testStackArrayOutOfBound() {
+ char buf[1];
+ memset(buf, 0, 1024); // expected-warning {{Memory set function accesses out-of-bound array element}}
+}
+
+void testHeapSymbolOutOfBound() {
+ char *buf = (char *)malloc(1);
+ memset(buf, 0, 1024); // expected-warning {{Memory set function accesses out-of-bound array element}}
+ free(buf);
+}
+
+void testStackArraySameSize() {
+ char buf[1];
+ memset(buf, 0, sizeof(buf)); // no-warning
+}
+
+void testHeapSymbolSameSize() {
+ char *buf = (char *)malloc(1);
+ memset(buf, 0, 1); // no-warning
+ free(buf);
+}
diff --git a/test/CXX/except/except.spec/p11.cpp b/test/CXX/except/except.spec/p11.cpp
index 1d0a647fb4f4..196f84c557ea 100644
--- a/test/CXX/except/except.spec/p11.cpp
+++ b/test/CXX/except/except.spec/p11.cpp
@@ -1,12 +1,11 @@
// RUN: %clang_cc1 -std=c++11 -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
-// expected-no-diagnostics
// This is the "let the user shoot themselves in the foot" clause.
-void f() noexcept {
- throw 0; // no-error
+void f() noexcept { // expected-note {{non-throwing function declare here}}
+ throw 0; // expected-warning {{has a non-throwing exception specification but}}
}
-void g() throw() {
- throw 0; // no-error
+void g() throw() { // expected-note {{non-throwing function declare here}}
+ throw 0; // expected-warning {{has a non-throwing exception specification but}}
}
void h() throw(int) {
throw 0.0; // no-error
diff --git a/test/CodeGen/64bit-swiftcall.c b/test/CodeGen/64bit-swiftcall.c
index 06c314501552..92ba37cd7fe6 100644
--- a/test/CodeGen/64bit-swiftcall.c
+++ b/test/CodeGen/64bit-swiftcall.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -target-cpu core2 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -target-cpu core2 -emit-llvm -o - %s | FileCheck %s --check-prefix=X86-64
// RUN: %clang_cc1 -triple arm64-apple-ios9 -target-cpu cyclone -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple arm64-apple-ios9 -target-cpu cyclone -emit-llvm -o - %s | FileCheck %s --check-prefix=ARM64
@@ -1014,3 +1015,20 @@ typedef struct {
TEST(struct_v1f3)
// ARM64-LABEL: define swiftcc { <2 x float>, float } @return_struct_v1f3()
// ARM64-LABEL: define swiftcc void @take_struct_v1f3(<2 x float>, float)
+
+typedef struct {
+ int3 vect;
+ unsigned long long val;
+} __attribute__((packed)) padded_alloc_size_vector;
+TEST(padded_alloc_size_vector)
+// X86-64-LABEL: take_padded_alloc_size_vector(<3 x i32>, i64)
+// X86-64-NOT: [4 x i8]
+// x86-64: ret void
+
+typedef union {
+ float f1;
+ float3 fv2;
+} union_hom_fp_partial2;
+TEST(union_hom_fp_partial2)
+// X86-64-LABEL: take_union_hom_fp_partial2(i64, float)
+// ARM64-LABEL: take_union_hom_fp_partial2(i64, float)
diff --git a/test/CodeGen/aarch64-neon-intrinsics.c b/test/CodeGen/aarch64-neon-intrinsics.c
index bcb680c4b518..cbc2e72fcbac 100644
--- a/test/CodeGen/aarch64-neon-intrinsics.c
+++ b/test/CodeGen/aarch64-neon-intrinsics.c
@@ -9037,10 +9037,9 @@ int64x2_t test_vld1q_s64(int64_t const *a) {
// CHECK-LABEL: @test_vld1q_f16(
// CHECK: [[TMP0:%.*]] = bitcast half* %a to i8*
-// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <8 x i16>*
-// CHECK: [[TMP2:%.*]] = load <8 x i16>, <8 x i16>* [[TMP1]]
-// CHECK: [[TMP3:%.*]] = bitcast <8 x i16> [[TMP2]] to <8 x half>
-// CHECK: ret <8 x half> [[TMP3]]
+// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <8 x half>*
+// CHECK: [[TMP2:%.*]] = load <8 x half>, <8 x half>* [[TMP1]]
+// CHECK: ret <8 x half> [[TMP2]]
float16x8_t test_vld1q_f16(float16_t const *a) {
return vld1q_f16(a);
}
@@ -9152,10 +9151,9 @@ int64x1_t test_vld1_s64(int64_t const *a) {
// CHECK-LABEL: @test_vld1_f16(
// CHECK: [[TMP0:%.*]] = bitcast half* %a to i8*
-// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <4 x i16>*
-// CHECK: [[TMP2:%.*]] = load <4 x i16>, <4 x i16>* [[TMP1]]
-// CHECK: [[TMP3:%.*]] = bitcast <4 x i16> [[TMP2]] to <4 x half>
-// CHECK: ret <4 x half> [[TMP3]]
+// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <4 x half>*
+// CHECK: [[TMP2:%.*]] = load <4 x half>, <4 x half>* [[TMP1]]
+// CHECK: ret <4 x half> [[TMP2]]
float16x4_t test_vld1_f16(float16_t const *a) {
return vld1_f16(a);
}
@@ -9342,10 +9340,10 @@ int64x2x2_t test_vld2q_s64(int64_t const *a) {
// CHECK: [[__RET:%.*]] = alloca %struct.float16x8x2_t, align 16
// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x2_t* [[__RET]] to i8*
// CHECK: [[TMP1:%.*]] = bitcast half* %a to i8*
-// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to <8 x i16>*
-// CHECK: [[VLD2:%.*]] = call { <8 x i16>, <8 x i16> } @llvm.aarch64.neon.ld2.v8i16.p0v8i16(<8 x i16>* [[TMP2]])
-// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x i16>, <8 x i16> }*
-// CHECK: store { <8 x i16>, <8 x i16> } [[VLD2]], { <8 x i16>, <8 x i16> }* [[TMP3]]
+// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to <8 x half>*
+// CHECK: [[VLD2:%.*]] = call { <8 x half>, <8 x half> } @llvm.aarch64.neon.ld2.v8f16.p0v8f16(<8 x half>* [[TMP2]])
+// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x half>, <8 x half> }*
+// CHECK: store { <8 x half>, <8 x half> } [[VLD2]], { <8 x half>, <8 x half> }* [[TMP3]]
// CHECK: [[TMP4:%.*]] = bitcast %struct.float16x8x2_t* [[RETVAL]] to i8*
// CHECK: [[TMP5:%.*]] = bitcast %struct.float16x8x2_t* [[__RET]] to i8*
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 32, i32 16, i1 false)
@@ -9573,10 +9571,10 @@ int64x1x2_t test_vld2_s64(int64_t const *a) {
// CHECK: [[__RET:%.*]] = alloca %struct.float16x4x2_t, align 8
// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x2_t* [[__RET]] to i8*
// CHECK: [[TMP1:%.*]] = bitcast half* %a to i8*
-// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to <4 x i16>*
-// CHECK: [[VLD2:%.*]] = call { <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld2.v4i16.p0v4i16(<4 x i16>* [[TMP2]])
-// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x i16>, <4 x i16> }*
-// CHECK: store { <4 x i16>, <4 x i16> } [[VLD2]], { <4 x i16>, <4 x i16> }* [[TMP3]]
+// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to <4 x half>*
+// CHECK: [[VLD2:%.*]] = call { <4 x half>, <4 x half> } @llvm.aarch64.neon.ld2.v4f16.p0v4f16(<4 x half>* [[TMP2]])
+// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x half>, <4 x half> }*
+// CHECK: store { <4 x half>, <4 x half> } [[VLD2]], { <4 x half>, <4 x half> }* [[TMP3]]
// CHECK: [[TMP4:%.*]] = bitcast %struct.float16x4x2_t* [[RETVAL]] to i8*
// CHECK: [[TMP5:%.*]] = bitcast %struct.float16x4x2_t* [[__RET]] to i8*
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 16, i32 8, i1 false)
@@ -9804,10 +9802,10 @@ int64x2x3_t test_vld3q_s64(int64_t const *a) {
// CHECK: [[__RET:%.*]] = alloca %struct.float16x8x3_t, align 16
// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x3_t* [[__RET]] to i8*
// CHECK: [[TMP1:%.*]] = bitcast half* %a to i8*
-// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to <8 x i16>*
-// CHECK: [[VLD3:%.*]] = call { <8 x i16>, <8 x i16>, <8 x i16> } @llvm.aarch64.neon.ld3.v8i16.p0v8i16(<8 x i16>* [[TMP2]])
-// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x i16>, <8 x i16>, <8 x i16> }*
-// CHECK: store { <8 x i16>, <8 x i16>, <8 x i16> } [[VLD3]], { <8 x i16>, <8 x i16>, <8 x i16> }* [[TMP3]]
+// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to <8 x half>*
+// CHECK: [[VLD3:%.*]] = call { <8 x half>, <8 x half>, <8 x half> } @llvm.aarch64.neon.ld3.v8f16.p0v8f16(<8 x half>* [[TMP2]])
+// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x half>, <8 x half>, <8 x half> }*
+// CHECK: store { <8 x half>, <8 x half>, <8 x half> } [[VLD3]], { <8 x half>, <8 x half>, <8 x half> }* [[TMP3]]
// CHECK: [[TMP4:%.*]] = bitcast %struct.float16x8x3_t* [[RETVAL]] to i8*
// CHECK: [[TMP5:%.*]] = bitcast %struct.float16x8x3_t* [[__RET]] to i8*
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 48, i32 16, i1 false)
@@ -10035,10 +10033,10 @@ int64x1x3_t test_vld3_s64(int64_t const *a) {
// CHECK: [[__RET:%.*]] = alloca %struct.float16x4x3_t, align 8
// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x3_t* [[__RET]] to i8*
// CHECK: [[TMP1:%.*]] = bitcast half* %a to i8*
-// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to <4 x i16>*
-// CHECK: [[VLD3:%.*]] = call { <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld3.v4i16.p0v4i16(<4 x i16>* [[TMP2]])
-// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x i16>, <4 x i16>, <4 x i16> }*
-// CHECK: store { <4 x i16>, <4 x i16>, <4 x i16> } [[VLD3]], { <4 x i16>, <4 x i16>, <4 x i16> }* [[TMP3]]
+// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to <4 x half>*
+// CHECK: [[VLD3:%.*]] = call { <4 x half>, <4 x half>, <4 x half> } @llvm.aarch64.neon.ld3.v4f16.p0v4f16(<4 x half>* [[TMP2]])
+// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x half>, <4 x half>, <4 x half> }*
+// CHECK: store { <4 x half>, <4 x half>, <4 x half> } [[VLD3]], { <4 x half>, <4 x half>, <4 x half> }* [[TMP3]]
// CHECK: [[TMP4:%.*]] = bitcast %struct.float16x4x3_t* [[RETVAL]] to i8*
// CHECK: [[TMP5:%.*]] = bitcast %struct.float16x4x3_t* [[__RET]] to i8*
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 24, i32 8, i1 false)
@@ -10266,10 +10264,10 @@ int64x2x4_t test_vld4q_s64(int64_t const *a) {
// CHECK: [[__RET:%.*]] = alloca %struct.float16x8x4_t, align 16
// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x4_t* [[__RET]] to i8*
// CHECK: [[TMP1:%.*]] = bitcast half* %a to i8*
-// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to <8 x i16>*
-// CHECK: [[VLD4:%.*]] = call { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } @llvm.aarch64.neon.ld4.v8i16.p0v8i16(<8 x i16>* [[TMP2]])
-// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> }*
-// CHECK: store { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } [[VLD4]], { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> }* [[TMP3]]
+// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to <8 x half>*
+// CHECK: [[VLD4:%.*]] = call { <8 x half>, <8 x half>, <8 x half>, <8 x half> } @llvm.aarch64.neon.ld4.v8f16.p0v8f16(<8 x half>* [[TMP2]])
+// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x half>, <8 x half>, <8 x half>, <8 x half> }*
+// CHECK: store { <8 x half>, <8 x half>, <8 x half>, <8 x half> } [[VLD4]], { <8 x half>, <8 x half>, <8 x half>, <8 x half> }* [[TMP3]]
// CHECK: [[TMP4:%.*]] = bitcast %struct.float16x8x4_t* [[RETVAL]] to i8*
// CHECK: [[TMP5:%.*]] = bitcast %struct.float16x8x4_t* [[__RET]] to i8*
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 64, i32 16, i1 false)
@@ -10497,10 +10495,10 @@ int64x1x4_t test_vld4_s64(int64_t const *a) {
// CHECK: [[__RET:%.*]] = alloca %struct.float16x4x4_t, align 8
// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x4_t* [[__RET]] to i8*
// CHECK: [[TMP1:%.*]] = bitcast half* %a to i8*
-// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to <4 x i16>*
-// CHECK: [[VLD4:%.*]] = call { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld4.v4i16.p0v4i16(<4 x i16>* [[TMP2]])
-// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> }*
-// CHECK: store { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } [[VLD4]], { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> }* [[TMP3]]
+// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to <4 x half>*
+// CHECK: [[VLD4:%.*]] = call { <4 x half>, <4 x half>, <4 x half>, <4 x half> } @llvm.aarch64.neon.ld4.v4f16.p0v4f16(<4 x half>* [[TMP2]])
+// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x half>, <4 x half>, <4 x half>, <4 x half> }*
+// CHECK: store { <4 x half>, <4 x half>, <4 x half>, <4 x half> } [[VLD4]], { <4 x half>, <4 x half>, <4 x half>, <4 x half> }* [[TMP3]]
// CHECK: [[TMP4:%.*]] = bitcast %struct.float16x4x4_t* [[RETVAL]] to i8*
// CHECK: [[TMP5:%.*]] = bitcast %struct.float16x4x4_t* [[__RET]] to i8*
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 32, i32 8, i1 false)
@@ -10666,9 +10664,9 @@ void test_vst1q_s64(int64_t *a, int64x2_t b) {
// CHECK-LABEL: @test_vst1q_f16(
// CHECK: [[TMP0:%.*]] = bitcast half* %a to i8*
// CHECK: [[TMP1:%.*]] = bitcast <8 x half> %b to <16 x i8>
-// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP0]] to <8 x i16>*
-// CHECK: [[TMP3:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x i16>
-// CHECK: store <8 x i16> [[TMP3]], <8 x i16>* [[TMP2]]
+// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP0]] to <8 x half>*
+// CHECK: [[TMP3:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x half>
+// CHECK: store <8 x half> [[TMP3]], <8 x half>* [[TMP2]]
// CHECK: ret void
void test_vst1q_f16(float16_t *a, float16x8_t b) {
vst1q_f16(a, b);
@@ -10800,9 +10798,9 @@ void test_vst1_s64(int64_t *a, int64x1_t b) {
// CHECK-LABEL: @test_vst1_f16(
// CHECK: [[TMP0:%.*]] = bitcast half* %a to i8*
// CHECK: [[TMP1:%.*]] = bitcast <4 x half> %b to <8 x i8>
-// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP0]] to <4 x i16>*
-// CHECK: [[TMP3:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x i16>
-// CHECK: store <4 x i16> [[TMP3]], <4 x i16>* [[TMP2]]
+// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP0]] to <4 x half>*
+// CHECK: [[TMP3:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x half>
+// CHECK: store <4 x half> [[TMP3]], <4 x half>* [[TMP2]]
// CHECK: ret void
void test_vst1_f16(float16_t *a, float16x4_t b) {
vst1_f16(a, b);
@@ -11056,9 +11054,9 @@ void test_vst2q_s64(int64_t *a, int64x2x2_t b) {
// CHECK: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x <8 x half>], [2 x <8 x half>]* [[VAL1]], i64 0, i64 1
// CHECK: [[TMP5:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX2]], align 16
// CHECK: [[TMP6:%.*]] = bitcast <8 x half> [[TMP5]] to <16 x i8>
-// CHECK: [[TMP7:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x i16>
-// CHECK: [[TMP8:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x i16>
-// CHECK: call void @llvm.aarch64.neon.st2.v8i16.p0i8(<8 x i16> [[TMP7]], <8 x i16> [[TMP8]], i8* [[TMP2]])
+// CHECK: [[TMP7:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x half>
+// CHECK: [[TMP8:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x half>
+// CHECK: call void @llvm.aarch64.neon.st2.v8f16.p0i8(<8 x half> [[TMP7]], <8 x half> [[TMP8]], i8* [[TMP2]])
// CHECK: ret void
void test_vst2q_f16(float16_t *a, float16x8x2_t b) {
vst2q_f16(a, b);
@@ -11366,9 +11364,9 @@ void test_vst2_s64(int64_t *a, int64x1x2_t b) {
// CHECK: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x <4 x half>], [2 x <4 x half>]* [[VAL1]], i64 0, i64 1
// CHECK: [[TMP5:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX2]], align 8
// CHECK: [[TMP6:%.*]] = bitcast <4 x half> [[TMP5]] to <8 x i8>
-// CHECK: [[TMP7:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x i16>
-// CHECK: [[TMP8:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x i16>
-// CHECK: call void @llvm.aarch64.neon.st2.v4i16.p0i8(<4 x i16> [[TMP7]], <4 x i16> [[TMP8]], i8* [[TMP2]])
+// CHECK: [[TMP7:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x half>
+// CHECK: [[TMP8:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x half>
+// CHECK: call void @llvm.aarch64.neon.st2.v4f16.p0i8(<4 x half> [[TMP7]], <4 x half> [[TMP8]], i8* [[TMP2]])
// CHECK: ret void
void test_vst2_f16(float16_t *a, float16x4x2_t b) {
vst2_f16(a, b);
@@ -11716,10 +11714,10 @@ void test_vst3q_s64(int64_t *a, int64x2x3_t b) {
// CHECK: [[ARRAYIDX4:%.*]] = getelementptr inbounds [3 x <8 x half>], [3 x <8 x half>]* [[VAL3]], i64 0, i64 2
// CHECK: [[TMP7:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX4]], align 16
// CHECK: [[TMP8:%.*]] = bitcast <8 x half> [[TMP7]] to <16 x i8>
-// CHECK: [[TMP9:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x i16>
-// CHECK: [[TMP10:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x i16>
-// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x i16>
-// CHECK: call void @llvm.aarch64.neon.st3.v8i16.p0i8(<8 x i16> [[TMP9]], <8 x i16> [[TMP10]], <8 x i16> [[TMP11]], i8* [[TMP2]])
+// CHECK: [[TMP9:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x half>
+// CHECK: [[TMP10:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x half>
+// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x half>
+// CHECK: call void @llvm.aarch64.neon.st3.v8f16.p0i8(<8 x half> [[TMP9]], <8 x half> [[TMP10]], <8 x half> [[TMP11]], i8* [[TMP2]])
// CHECK: ret void
void test_vst3q_f16(float16_t *a, float16x8x3_t b) {
vst3q_f16(a, b);
@@ -12085,10 +12083,10 @@ void test_vst3_s64(int64_t *a, int64x1x3_t b) {
// CHECK: [[ARRAYIDX4:%.*]] = getelementptr inbounds [3 x <4 x half>], [3 x <4 x half>]* [[VAL3]], i64 0, i64 2
// CHECK: [[TMP7:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX4]], align 8
// CHECK: [[TMP8:%.*]] = bitcast <4 x half> [[TMP7]] to <8 x i8>
-// CHECK: [[TMP9:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x i16>
-// CHECK: [[TMP10:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x i16>
-// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x i16>
-// CHECK: call void @llvm.aarch64.neon.st3.v4i16.p0i8(<4 x i16> [[TMP9]], <4 x i16> [[TMP10]], <4 x i16> [[TMP11]], i8* [[TMP2]])
+// CHECK: [[TMP9:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x half>
+// CHECK: [[TMP10:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x half>
+// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x half>
+// CHECK: call void @llvm.aarch64.neon.st3.v4f16.p0i8(<4 x half> [[TMP9]], <4 x half> [[TMP10]], <4 x half> [[TMP11]], i8* [[TMP2]])
// CHECK: ret void
void test_vst3_f16(float16_t *a, float16x4x3_t b) {
vst3_f16(a, b);
@@ -12494,11 +12492,11 @@ void test_vst4q_s64(int64_t *a, int64x2x4_t b) {
// CHECK: [[ARRAYIDX6:%.*]] = getelementptr inbounds [4 x <8 x half>], [4 x <8 x half>]* [[VAL5]], i64 0, i64 3
// CHECK: [[TMP9:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX6]], align 16
// CHECK: [[TMP10:%.*]] = bitcast <8 x half> [[TMP9]] to <16 x i8>
-// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x i16>
-// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x i16>
-// CHECK: [[TMP13:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x i16>
-// CHECK: [[TMP14:%.*]] = bitcast <16 x i8> [[TMP10]] to <8 x i16>
-// CHECK: call void @llvm.aarch64.neon.st4.v8i16.p0i8(<8 x i16> [[TMP11]], <8 x i16> [[TMP12]], <8 x i16> [[TMP13]], <8 x i16> [[TMP14]], i8* [[TMP2]])
+// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x half>
+// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x half>
+// CHECK: [[TMP13:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x half>
+// CHECK: [[TMP14:%.*]] = bitcast <16 x i8> [[TMP10]] to <8 x half>
+// CHECK: call void @llvm.aarch64.neon.st4.v8f16.p0i8(<8 x half> [[TMP11]], <8 x half> [[TMP12]], <8 x half> [[TMP13]], <8 x half> [[TMP14]], i8* [[TMP2]])
// CHECK: ret void
void test_vst4q_f16(float16_t *a, float16x8x4_t b) {
vst4q_f16(a, b);
@@ -12922,11 +12920,11 @@ void test_vst4_s64(int64_t *a, int64x1x4_t b) {
// CHECK: [[ARRAYIDX6:%.*]] = getelementptr inbounds [4 x <4 x half>], [4 x <4 x half>]* [[VAL5]], i64 0, i64 3
// CHECK: [[TMP9:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX6]], align 8
// CHECK: [[TMP10:%.*]] = bitcast <4 x half> [[TMP9]] to <8 x i8>
-// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x i16>
-// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x i16>
-// CHECK: [[TMP13:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x i16>
-// CHECK: [[TMP14:%.*]] = bitcast <8 x i8> [[TMP10]] to <4 x i16>
-// CHECK: call void @llvm.aarch64.neon.st4.v4i16.p0i8(<4 x i16> [[TMP11]], <4 x i16> [[TMP12]], <4 x i16> [[TMP13]], <4 x i16> [[TMP14]], i8* [[TMP2]])
+// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x half>
+// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x half>
+// CHECK: [[TMP13:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x half>
+// CHECK: [[TMP14:%.*]] = bitcast <8 x i8> [[TMP10]] to <4 x half>
+// CHECK: call void @llvm.aarch64.neon.st4.v4f16.p0i8(<4 x half> [[TMP11]], <4 x half> [[TMP12]], <4 x half> [[TMP13]], <4 x half> [[TMP14]], i8* [[TMP2]])
// CHECK: ret void
void test_vst4_f16(float16_t *a, float16x4x4_t b) {
vst4_f16(a, b);
@@ -13208,10 +13206,10 @@ int64x2x2_t test_vld1q_s64_x2(int64_t const *a) {
// CHECK: [[__RET:%.*]] = alloca %struct.float16x8x2_t, align 16
// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x2_t* [[__RET]] to i8*
// CHECK: [[TMP1:%.*]] = bitcast half* %a to i8*
-// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i16*
-// CHECK: [[VLD1XN:%.*]] = call { <8 x i16>, <8 x i16> } @llvm.aarch64.neon.ld1x2.v8i16.p0i16(i16* [[TMP2]])
-// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x i16>, <8 x i16> }*
-// CHECK: store { <8 x i16>, <8 x i16> } [[VLD1XN]], { <8 x i16>, <8 x i16> }* [[TMP3]]
+// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to half*
+// CHECK: [[VLD1XN:%.*]] = call { <8 x half>, <8 x half> } @llvm.aarch64.neon.ld1x2.v8f16.p0f16(half* [[TMP2]])
+// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x half>, <8 x half> }*
+// CHECK: store { <8 x half>, <8 x half> } [[VLD1XN]], { <8 x half>, <8 x half> }* [[TMP3]]
// CHECK: [[TMP4:%.*]] = bitcast %struct.float16x8x2_t* [[RETVAL]] to i8*
// CHECK: [[TMP5:%.*]] = bitcast %struct.float16x8x2_t* [[__RET]] to i8*
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 32, i32 16, i1 false)
@@ -13454,10 +13452,10 @@ int64x1x2_t test_vld1_s64_x2(int64_t const *a) {
// CHECK: [[__RET:%.*]] = alloca %struct.float16x4x2_t, align 8
// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x2_t* [[__RET]] to i8*
// CHECK: [[TMP1:%.*]] = bitcast half* %a to i8*
-// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i16*
-// CHECK: [[VLD1XN:%.*]] = call { <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld1x2.v4i16.p0i16(i16* [[TMP2]])
-// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x i16>, <4 x i16> }*
-// CHECK: store { <4 x i16>, <4 x i16> } [[VLD1XN]], { <4 x i16>, <4 x i16> }* [[TMP3]]
+// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to half*
+// CHECK: [[VLD1XN:%.*]] = call { <4 x half>, <4 x half> } @llvm.aarch64.neon.ld1x2.v4f16.p0f16(half* [[TMP2]])
+// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x half>, <4 x half> }*
+// CHECK: store { <4 x half>, <4 x half> } [[VLD1XN]], { <4 x half>, <4 x half> }* [[TMP3]]
// CHECK: [[TMP4:%.*]] = bitcast %struct.float16x4x2_t* [[RETVAL]] to i8*
// CHECK: [[TMP5:%.*]] = bitcast %struct.float16x4x2_t* [[__RET]] to i8*
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 16, i32 8, i1 false)
@@ -13700,10 +13698,10 @@ int64x2x3_t test_vld1q_s64_x3(int64_t const *a) {
// CHECK: [[__RET:%.*]] = alloca %struct.float16x8x3_t, align 16
// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x3_t* [[__RET]] to i8*
// CHECK: [[TMP1:%.*]] = bitcast half* %a to i8*
-// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i16*
-// CHECK: [[VLD1XN:%.*]] = call { <8 x i16>, <8 x i16>, <8 x i16> } @llvm.aarch64.neon.ld1x3.v8i16.p0i16(i16* [[TMP2]])
-// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x i16>, <8 x i16>, <8 x i16> }*
-// CHECK: store { <8 x i16>, <8 x i16>, <8 x i16> } [[VLD1XN]], { <8 x i16>, <8 x i16>, <8 x i16> }* [[TMP3]]
+// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to half*
+// CHECK: [[VLD1XN:%.*]] = call { <8 x half>, <8 x half>, <8 x half> } @llvm.aarch64.neon.ld1x3.v8f16.p0f16(half* [[TMP2]])
+// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x half>, <8 x half>, <8 x half> }*
+// CHECK: store { <8 x half>, <8 x half>, <8 x half> } [[VLD1XN]], { <8 x half>, <8 x half>, <8 x half> }* [[TMP3]]
// CHECK: [[TMP4:%.*]] = bitcast %struct.float16x8x3_t* [[RETVAL]] to i8*
// CHECK: [[TMP5:%.*]] = bitcast %struct.float16x8x3_t* [[__RET]] to i8*
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 48, i32 16, i1 false)
@@ -13946,10 +13944,10 @@ int64x1x3_t test_vld1_s64_x3(int64_t const *a) {
// CHECK: [[__RET:%.*]] = alloca %struct.float16x4x3_t, align 8
// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x3_t* [[__RET]] to i8*
// CHECK: [[TMP1:%.*]] = bitcast half* %a to i8*
-// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i16*
-// CHECK: [[VLD1XN:%.*]] = call { <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld1x3.v4i16.p0i16(i16* [[TMP2]])
-// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x i16>, <4 x i16>, <4 x i16> }*
-// CHECK: store { <4 x i16>, <4 x i16>, <4 x i16> } [[VLD1XN]], { <4 x i16>, <4 x i16>, <4 x i16> }* [[TMP3]]
+// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to half*
+// CHECK: [[VLD1XN:%.*]] = call { <4 x half>, <4 x half>, <4 x half> } @llvm.aarch64.neon.ld1x3.v4f16.p0f16(half* [[TMP2]])
+// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x half>, <4 x half>, <4 x half> }*
+// CHECK: store { <4 x half>, <4 x half>, <4 x half> } [[VLD1XN]], { <4 x half>, <4 x half>, <4 x half> }* [[TMP3]]
// CHECK: [[TMP4:%.*]] = bitcast %struct.float16x4x3_t* [[RETVAL]] to i8*
// CHECK: [[TMP5:%.*]] = bitcast %struct.float16x4x3_t* [[__RET]] to i8*
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 24, i32 8, i1 false)
@@ -14192,10 +14190,10 @@ int64x2x4_t test_vld1q_s64_x4(int64_t const *a) {
// CHECK: [[__RET:%.*]] = alloca %struct.float16x8x4_t, align 16
// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x4_t* [[__RET]] to i8*
// CHECK: [[TMP1:%.*]] = bitcast half* %a to i8*
-// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i16*
-// CHECK: [[VLD1XN:%.*]] = call { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } @llvm.aarch64.neon.ld1x4.v8i16.p0i16(i16* [[TMP2]])
-// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> }*
-// CHECK: store { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } [[VLD1XN]], { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> }* [[TMP3]]
+// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to half*
+// CHECK: [[VLD1XN:%.*]] = call { <8 x half>, <8 x half>, <8 x half>, <8 x half> } @llvm.aarch64.neon.ld1x4.v8f16.p0f16(half* [[TMP2]])
+// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x half>, <8 x half>, <8 x half>, <8 x half> }*
+// CHECK: store { <8 x half>, <8 x half>, <8 x half>, <8 x half> } [[VLD1XN]], { <8 x half>, <8 x half>, <8 x half>, <8 x half> }* [[TMP3]]
// CHECK: [[TMP4:%.*]] = bitcast %struct.float16x8x4_t* [[RETVAL]] to i8*
// CHECK: [[TMP5:%.*]] = bitcast %struct.float16x8x4_t* [[__RET]] to i8*
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 64, i32 16, i1 false)
@@ -14438,10 +14436,10 @@ int64x1x4_t test_vld1_s64_x4(int64_t const *a) {
// CHECK: [[__RET:%.*]] = alloca %struct.float16x4x4_t, align 8
// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x4_t* [[__RET]] to i8*
// CHECK: [[TMP1:%.*]] = bitcast half* %a to i8*
-// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i16*
-// CHECK: [[VLD1XN:%.*]] = call { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld1x4.v4i16.p0i16(i16* [[TMP2]])
-// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> }*
-// CHECK: store { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } [[VLD1XN]], { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> }* [[TMP3]]
+// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to half*
+// CHECK: [[VLD1XN:%.*]] = call { <4 x half>, <4 x half>, <4 x half>, <4 x half> } @llvm.aarch64.neon.ld1x4.v4f16.p0f16(half* [[TMP2]])
+// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x half>, <4 x half>, <4 x half>, <4 x half> }*
+// CHECK: store { <4 x half>, <4 x half>, <4 x half>, <4 x half> } [[VLD1XN]], { <4 x half>, <4 x half>, <4 x half>, <4 x half> }* [[TMP3]]
// CHECK: [[TMP4:%.*]] = bitcast %struct.float16x4x4_t* [[RETVAL]] to i8*
// CHECK: [[TMP5:%.*]] = bitcast %struct.float16x4x4_t* [[__RET]] to i8*
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 32, i32 8, i1 false)
@@ -14752,10 +14750,10 @@ void test_vst1q_s64_x2(int64_t *a, int64x2x2_t b) {
// CHECK: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x <8 x half>], [2 x <8 x half>]* [[VAL1]], i64 0, i64 1
// CHECK: [[TMP5:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX2]], align 16
// CHECK: [[TMP6:%.*]] = bitcast <8 x half> [[TMP5]] to <16 x i8>
-// CHECK: [[TMP7:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x i16>
-// CHECK: [[TMP8:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x i16>
-// CHECK: [[TMP9:%.*]] = bitcast i8* [[TMP2]] to i16*
-// CHECK: call void @llvm.aarch64.neon.st1x2.v8i16.p0i16(<8 x i16> [[TMP7]], <8 x i16> [[TMP8]], i16* [[TMP9]])
+// CHECK: [[TMP7:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x half>
+// CHECK: [[TMP8:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x half>
+// CHECK: [[TMP9:%.*]] = bitcast i8* [[TMP2]] to half*
+// CHECK: call void @llvm.aarch64.neon.st1x2.v8f16.p0f16(<8 x half> [[TMP7]], <8 x half> [[TMP8]], half* [[TMP9]])
// CHECK: ret void
void test_vst1q_f16_x2(float16_t *a, float16x8x2_t b) {
vst1q_f16_x2(a, b);
@@ -15098,10 +15096,10 @@ void test_vst1_s64_x2(int64_t *a, int64x1x2_t b) {
// CHECK: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x <4 x half>], [2 x <4 x half>]* [[VAL1]], i64 0, i64 1
// CHECK: [[TMP5:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX2]], align 8
// CHECK: [[TMP6:%.*]] = bitcast <4 x half> [[TMP5]] to <8 x i8>
-// CHECK: [[TMP7:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x i16>
-// CHECK: [[TMP8:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x i16>
-// CHECK: [[TMP9:%.*]] = bitcast i8* [[TMP2]] to i16*
-// CHECK: call void @llvm.aarch64.neon.st1x2.v4i16.p0i16(<4 x i16> [[TMP7]], <4 x i16> [[TMP8]], i16* [[TMP9]])
+// CHECK: [[TMP7:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x half>
+// CHECK: [[TMP8:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x half>
+// CHECK: [[TMP9:%.*]] = bitcast i8* [[TMP2]] to half*
+// CHECK: call void @llvm.aarch64.neon.st1x2.v4f16.p0f16(<4 x half> [[TMP7]], <4 x half> [[TMP8]], half* [[TMP9]])
// CHECK: ret void
void test_vst1_f16_x2(float16_t *a, float16x4x2_t b) {
vst1_f16_x2(a, b);
@@ -15484,11 +15482,11 @@ void test_vst1q_s64_x3(int64_t *a, int64x2x3_t b) {
// CHECK: [[ARRAYIDX4:%.*]] = getelementptr inbounds [3 x <8 x half>], [3 x <8 x half>]* [[VAL3]], i64 0, i64 2
// CHECK: [[TMP7:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX4]], align 16
// CHECK: [[TMP8:%.*]] = bitcast <8 x half> [[TMP7]] to <16 x i8>
-// CHECK: [[TMP9:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x i16>
-// CHECK: [[TMP10:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x i16>
-// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x i16>
-// CHECK: [[TMP12:%.*]] = bitcast i8* [[TMP2]] to i16*
-// CHECK: call void @llvm.aarch64.neon.st1x3.v8i16.p0i16(<8 x i16> [[TMP9]], <8 x i16> [[TMP10]], <8 x i16> [[TMP11]], i16* [[TMP12]])
+// CHECK: [[TMP9:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x half>
+// CHECK: [[TMP10:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x half>
+// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x half>
+// CHECK: [[TMP12:%.*]] = bitcast i8* [[TMP2]] to half*
+// CHECK: call void @llvm.aarch64.neon.st1x3.v8f16.p0f16(<8 x half> [[TMP9]], <8 x half> [[TMP10]], <8 x half> [[TMP11]], half* [[TMP12]])
// CHECK: ret void
void test_vst1q_f16_x3(float16_t *a, float16x8x3_t b) {
vst1q_f16_x3(a, b);
@@ -15894,11 +15892,11 @@ void test_vst1_s64_x3(int64_t *a, int64x1x3_t b) {
// CHECK: [[ARRAYIDX4:%.*]] = getelementptr inbounds [3 x <4 x half>], [3 x <4 x half>]* [[VAL3]], i64 0, i64 2
// CHECK: [[TMP7:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX4]], align 8
// CHECK: [[TMP8:%.*]] = bitcast <4 x half> [[TMP7]] to <8 x i8>
-// CHECK: [[TMP9:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x i16>
-// CHECK: [[TMP10:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x i16>
-// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x i16>
-// CHECK: [[TMP12:%.*]] = bitcast i8* [[TMP2]] to i16*
-// CHECK: call void @llvm.aarch64.neon.st1x3.v4i16.p0i16(<4 x i16> [[TMP9]], <4 x i16> [[TMP10]], <4 x i16> [[TMP11]], i16* [[TMP12]])
+// CHECK: [[TMP9:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x half>
+// CHECK: [[TMP10:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x half>
+// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x half>
+// CHECK: [[TMP12:%.*]] = bitcast i8* [[TMP2]] to half*
+// CHECK: call void @llvm.aarch64.neon.st1x3.v4f16.p0f16(<4 x half> [[TMP9]], <4 x half> [[TMP10]], <4 x half> [[TMP11]], half* [[TMP12]])
// CHECK: ret void
void test_vst1_f16_x3(float16_t *a, float16x4x3_t b) {
vst1_f16_x3(a, b);
@@ -16344,12 +16342,12 @@ void test_vst1q_s64_x4(int64_t *a, int64x2x4_t b) {
// CHECK: [[ARRAYIDX6:%.*]] = getelementptr inbounds [4 x <8 x half>], [4 x <8 x half>]* [[VAL5]], i64 0, i64 3
// CHECK: [[TMP9:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX6]], align 16
// CHECK: [[TMP10:%.*]] = bitcast <8 x half> [[TMP9]] to <16 x i8>
-// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x i16>
-// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x i16>
-// CHECK: [[TMP13:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x i16>
-// CHECK: [[TMP14:%.*]] = bitcast <16 x i8> [[TMP10]] to <8 x i16>
-// CHECK: [[TMP15:%.*]] = bitcast i8* [[TMP2]] to i16*
-// CHECK: call void @llvm.aarch64.neon.st1x4.v8i16.p0i16(<8 x i16> [[TMP11]], <8 x i16> [[TMP12]], <8 x i16> [[TMP13]], <8 x i16> [[TMP14]], i16* [[TMP15]])
+// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x half>
+// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x half>
+// CHECK: [[TMP13:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x half>
+// CHECK: [[TMP14:%.*]] = bitcast <16 x i8> [[TMP10]] to <8 x half>
+// CHECK: [[TMP15:%.*]] = bitcast i8* [[TMP2]] to half*
+// CHECK: call void @llvm.aarch64.neon.st1x4.v8f16.p0f16(<8 x half> [[TMP11]], <8 x half> [[TMP12]], <8 x half> [[TMP13]], <8 x half> [[TMP14]], half* [[TMP15]])
// CHECK: ret void
void test_vst1q_f16_x4(float16_t *a, float16x8x4_t b) {
vst1q_f16_x4(a, b);
@@ -16818,12 +16816,12 @@ void test_vst1_s64_x4(int64_t *a, int64x1x4_t b) {
// CHECK: [[ARRAYIDX6:%.*]] = getelementptr inbounds [4 x <4 x half>], [4 x <4 x half>]* [[VAL5]], i64 0, i64 3
// CHECK: [[TMP9:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX6]], align 8
// CHECK: [[TMP10:%.*]] = bitcast <4 x half> [[TMP9]] to <8 x i8>
-// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x i16>
-// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x i16>
-// CHECK: [[TMP13:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x i16>
-// CHECK: [[TMP14:%.*]] = bitcast <8 x i8> [[TMP10]] to <4 x i16>
-// CHECK: [[TMP15:%.*]] = bitcast i8* [[TMP2]] to i16*
-// CHECK: call void @llvm.aarch64.neon.st1x4.v4i16.p0i16(<4 x i16> [[TMP11]], <4 x i16> [[TMP12]], <4 x i16> [[TMP13]], <4 x i16> [[TMP14]], i16* [[TMP15]])
+// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x half>
+// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x half>
+// CHECK: [[TMP13:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x half>
+// CHECK: [[TMP14:%.*]] = bitcast <8 x i8> [[TMP10]] to <4 x half>
+// CHECK: [[TMP15:%.*]] = bitcast i8* [[TMP2]] to half*
+// CHECK: call void @llvm.aarch64.neon.st1x4.v4f16.p0f16(<4 x half> [[TMP11]], <4 x half> [[TMP12]], <4 x half> [[TMP13]], <4 x half> [[TMP14]], half* [[TMP15]])
// CHECK: ret void
void test_vst1_f16_x4(float16_t *a, float16x4x4_t b) {
vst1_f16_x4(a, b);
diff --git a/test/CodeGen/aarch64-neon-ldst-one.c b/test/CodeGen/aarch64-neon-ldst-one.c
index 9bd9ab1cb61b..a3c5b140a0d2 100644
--- a/test/CodeGen/aarch64-neon-ldst-one.c
+++ b/test/CodeGen/aarch64-neon-ldst-one.c
@@ -90,12 +90,11 @@ int64x2_t test_vld1q_dup_s64(int64_t *a) {
// CHECK-LABEL: define <8 x half> @test_vld1q_dup_f16(half* %a) #0 {
// CHECK: [[TMP0:%.*]] = bitcast half* %a to i8*
-// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to i16*
-// CHECK: [[TMP2:%.*]] = load i16, i16* [[TMP1]]
-// CHECK: [[TMP3:%.*]] = insertelement <8 x i16> undef, i16 [[TMP2]], i32 0
-// CHECK: [[LANE:%.*]] = shufflevector <8 x i16> [[TMP3]], <8 x i16> [[TMP3]], <8 x i32> zeroinitializer
-// CHECK: [[TMP4:%.*]] = bitcast <8 x i16> [[LANE]] to <8 x half>
-// CHECK: ret <8 x half> [[TMP4]]
+// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to half*
+// CHECK: [[TMP2:%.*]] = load half, half* [[TMP1]]
+// CHECK: [[TMP3:%.*]] = insertelement <8 x half> undef, half [[TMP2]], i32 0
+// CHECK: [[LANE:%.*]] = shufflevector <8 x half> [[TMP3]], <8 x half> [[TMP3]], <8 x i32> zeroinitializer
+// CHECK: ret <8 x half> [[LANE]]
float16x8_t test_vld1q_dup_f16(float16_t *a) {
return vld1q_dup_f16(a);
}
@@ -239,12 +238,11 @@ int64x1_t test_vld1_dup_s64(int64_t *a) {
// CHECK-LABEL: define <4 x half> @test_vld1_dup_f16(half* %a) #0 {
// CHECK: [[TMP0:%.*]] = bitcast half* %a to i8*
-// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to i16*
-// CHECK: [[TMP2:%.*]] = load i16, i16* [[TMP1]]
-// CHECK: [[TMP3:%.*]] = insertelement <4 x i16> undef, i16 [[TMP2]], i32 0
-// CHECK: [[LANE:%.*]] = shufflevector <4 x i16> [[TMP3]], <4 x i16> [[TMP3]], <4 x i32> zeroinitializer
-// CHECK: [[TMP4:%.*]] = bitcast <4 x i16> [[LANE]] to <4 x half>
-// CHECK: ret <4 x half> [[TMP4]]
+// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to half*
+// CHECK: [[TMP2:%.*]] = load half, half* [[TMP1]]
+// CHECK: [[TMP3:%.*]] = insertelement <4 x half> undef, half [[TMP2]], i32 0
+// CHECK: [[LANE:%.*]] = shufflevector <4 x half> [[TMP3]], <4 x half> [[TMP3]], <4 x i32> zeroinitializer
+// CHECK: ret <4 x half> [[LANE]]
float16x4_t test_vld1_dup_f16(float16_t *a) {
return vld1_dup_f16(a);
}
@@ -447,10 +445,10 @@ int64x2x2_t test_vld2q_dup_s64(int64_t *a) {
// CHECK: [[__RET:%.*]] = alloca %struct.float16x8x2_t, align 16
// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x2_t* [[__RET]] to i8*
// CHECK: [[TMP1:%.*]] = bitcast half* %a to i8*
-// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i16*
-// CHECK: [[VLD2:%.*]] = call { <8 x i16>, <8 x i16> } @llvm.aarch64.neon.ld2r.v8i16.p0i16(i16* [[TMP2]])
-// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x i16>, <8 x i16> }*
-// CHECK: store { <8 x i16>, <8 x i16> } [[VLD2]], { <8 x i16>, <8 x i16> }* [[TMP3]]
+// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to half*
+// CHECK: [[VLD2:%.*]] = call { <8 x half>, <8 x half> } @llvm.aarch64.neon.ld2r.v8f16.p0f16(half* [[TMP2]])
+// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x half>, <8 x half> }*
+// CHECK: store { <8 x half>, <8 x half> } [[VLD2]], { <8 x half>, <8 x half> }* [[TMP3]]
// CHECK: [[TMP4:%.*]] = bitcast %struct.float16x8x2_t* [[RETVAL]] to i8*
// CHECK: [[TMP5:%.*]] = bitcast %struct.float16x8x2_t* [[__RET]] to i8*
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 32, i32 16, i1 false)
@@ -693,10 +691,10 @@ int64x1x2_t test_vld2_dup_s64(int64_t *a) {
// CHECK: [[__RET:%.*]] = alloca %struct.float16x4x2_t, align 8
// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x2_t* [[__RET]] to i8*
// CHECK: [[TMP1:%.*]] = bitcast half* %a to i8*
-// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i16*
-// CHECK: [[VLD2:%.*]] = call { <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld2r.v4i16.p0i16(i16* [[TMP2]])
-// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x i16>, <4 x i16> }*
-// CHECK: store { <4 x i16>, <4 x i16> } [[VLD2]], { <4 x i16>, <4 x i16> }* [[TMP3]]
+// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to half*
+// CHECK: [[VLD2:%.*]] = call { <4 x half>, <4 x half> } @llvm.aarch64.neon.ld2r.v4f16.p0f16(half* [[TMP2]])
+// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x half>, <4 x half> }*
+// CHECK: store { <4 x half>, <4 x half> } [[VLD2]], { <4 x half>, <4 x half> }* [[TMP3]]
// CHECK: [[TMP4:%.*]] = bitcast %struct.float16x4x2_t* [[RETVAL]] to i8*
// CHECK: [[TMP5:%.*]] = bitcast %struct.float16x4x2_t* [[__RET]] to i8*
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 16, i32 8, i1 false)
@@ -947,10 +945,10 @@ int64x2x3_t test_vld3q_dup_s64(int64_t *a) {
// CHECK: [[__RET:%.*]] = alloca %struct.float16x8x3_t, align 16
// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x3_t* [[__RET]] to i8*
// CHECK: [[TMP1:%.*]] = bitcast half* %a to i8*
-// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i16*
-// CHECK: [[VLD3:%.*]] = call { <8 x i16>, <8 x i16>, <8 x i16> } @llvm.aarch64.neon.ld3r.v8i16.p0i16(i16* [[TMP2]])
-// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x i16>, <8 x i16>, <8 x i16> }*
-// CHECK: store { <8 x i16>, <8 x i16>, <8 x i16> } [[VLD3]], { <8 x i16>, <8 x i16>, <8 x i16> }* [[TMP3]]
+// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to half*
+// CHECK: [[VLD3:%.*]] = call { <8 x half>, <8 x half>, <8 x half> } @llvm.aarch64.neon.ld3r.v8f16.p0f16(half* [[TMP2]])
+// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x half>, <8 x half>, <8 x half> }*
+// CHECK: store { <8 x half>, <8 x half>, <8 x half> } [[VLD3]], { <8 x half>, <8 x half>, <8 x half> }* [[TMP3]]
// CHECK: [[TMP4:%.*]] = bitcast %struct.float16x8x3_t* [[RETVAL]] to i8*
// CHECK: [[TMP5:%.*]] = bitcast %struct.float16x8x3_t* [[__RET]] to i8*
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 48, i32 16, i1 false)
@@ -1207,10 +1205,10 @@ int64x1x3_t test_vld3_dup_s64(int64_t *a) {
// CHECK: [[__RET:%.*]] = alloca %struct.float16x4x3_t, align 8
// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x3_t* [[__RET]] to i8*
// CHECK: [[TMP1:%.*]] = bitcast half* %a to i8*
-// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i16*
-// CHECK: [[VLD3:%.*]] = call { <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld3r.v4i16.p0i16(i16* [[TMP2]])
-// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x i16>, <4 x i16>, <4 x i16> }*
-// CHECK: store { <4 x i16>, <4 x i16>, <4 x i16> } [[VLD3]], { <4 x i16>, <4 x i16>, <4 x i16> }* [[TMP3]]
+// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to half*
+// CHECK: [[VLD3:%.*]] = call { <4 x half>, <4 x half>, <4 x half> } @llvm.aarch64.neon.ld3r.v4f16.p0f16(half* [[TMP2]])
+// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x half>, <4 x half>, <4 x half> }*
+// CHECK: store { <4 x half>, <4 x half>, <4 x half> } [[VLD3]], { <4 x half>, <4 x half>, <4 x half> }* [[TMP3]]
// CHECK: [[TMP4:%.*]] = bitcast %struct.float16x4x3_t* [[RETVAL]] to i8*
// CHECK: [[TMP5:%.*]] = bitcast %struct.float16x4x3_t* [[__RET]] to i8*
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 24, i32 8, i1 false)
@@ -1459,10 +1457,10 @@ int64x2x4_t test_vld4q_dup_s64(int64_t *a) {
// CHECK: [[__RET:%.*]] = alloca %struct.float16x8x4_t, align 16
// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x4_t* [[__RET]] to i8*
// CHECK: [[TMP1:%.*]] = bitcast half* %a to i8*
-// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i16*
-// CHECK: [[VLD4:%.*]] = call { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } @llvm.aarch64.neon.ld4r.v8i16.p0i16(i16* [[TMP2]])
-// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> }*
-// CHECK: store { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } [[VLD4]], { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> }* [[TMP3]]
+// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to half*
+// CHECK: [[VLD4:%.*]] = call { <8 x half>, <8 x half>, <8 x half>, <8 x half> } @llvm.aarch64.neon.ld4r.v8f16.p0f16(half* [[TMP2]])
+// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x half>, <8 x half>, <8 x half>, <8 x half> }*
+// CHECK: store { <8 x half>, <8 x half>, <8 x half>, <8 x half> } [[VLD4]], { <8 x half>, <8 x half>, <8 x half>, <8 x half> }* [[TMP3]]
// CHECK: [[TMP4:%.*]] = bitcast %struct.float16x8x4_t* [[RETVAL]] to i8*
// CHECK: [[TMP5:%.*]] = bitcast %struct.float16x8x4_t* [[__RET]] to i8*
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 64, i32 16, i1 false)
@@ -1705,10 +1703,10 @@ int64x1x4_t test_vld4_dup_s64(int64_t *a) {
// CHECK: [[__RET:%.*]] = alloca %struct.float16x4x4_t, align 8
// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x4_t* [[__RET]] to i8*
// CHECK: [[TMP1:%.*]] = bitcast half* %a to i8*
-// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i16*
-// CHECK: [[VLD4:%.*]] = call { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld4r.v4i16.p0i16(i16* [[TMP2]])
-// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> }*
-// CHECK: store { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } [[VLD4]], { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> }* [[TMP3]]
+// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to half*
+// CHECK: [[VLD4:%.*]] = call { <4 x half>, <4 x half>, <4 x half>, <4 x half> } @llvm.aarch64.neon.ld4r.v4f16.p0f16(half* [[TMP2]])
+// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x half>, <4 x half>, <4 x half>, <4 x half> }*
+// CHECK: store { <4 x half>, <4 x half>, <4 x half>, <4 x half> } [[VLD4]], { <4 x half>, <4 x half>, <4 x half>, <4 x half> }* [[TMP3]]
// CHECK: [[TMP4:%.*]] = bitcast %struct.float16x4x4_t* [[RETVAL]] to i8*
// CHECK: [[TMP5:%.*]] = bitcast %struct.float16x4x4_t* [[__RET]] to i8*
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 32, i32 8, i1 false)
@@ -1897,12 +1895,11 @@ int64x2_t test_vld1q_lane_s64(int64_t *a, int64x2_t b) {
// CHECK-LABEL: define <8 x half> @test_vld1q_lane_f16(half* %a, <8 x half> %b) #0 {
// CHECK: [[TMP0:%.*]] = bitcast half* %a to i8*
// CHECK: [[TMP1:%.*]] = bitcast <8 x half> %b to <16 x i8>
-// CHECK: [[TMP2:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x i16>
-// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to i16*
-// CHECK: [[TMP4:%.*]] = load i16, i16* [[TMP3]]
-// CHECK: [[VLD1_LANE:%.*]] = insertelement <8 x i16> [[TMP2]], i16 [[TMP4]], i32 7
-// CHECK: [[TMP5:%.*]] = bitcast <8 x i16> [[VLD1_LANE]] to <8 x half>
-// CHECK: ret <8 x half> [[TMP5]]
+// CHECK: [[TMP2:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x half>
+// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to half*
+// CHECK: [[TMP4:%.*]] = load half, half* [[TMP3]]
+// CHECK: [[VLD1_LANE:%.*]] = insertelement <8 x half> [[TMP2]], half [[TMP4]], i32 7
+// CHECK: ret <8 x half> [[VLD1_LANE]]
float16x8_t test_vld1q_lane_f16(float16_t *a, float16x8_t b) {
return vld1q_lane_f16(a, b, 7);
}
@@ -2054,12 +2051,11 @@ int64x1_t test_vld1_lane_s64(int64_t *a, int64x1_t b) {
// CHECK-LABEL: define <4 x half> @test_vld1_lane_f16(half* %a, <4 x half> %b) #0 {
// CHECK: [[TMP0:%.*]] = bitcast half* %a to i8*
// CHECK: [[TMP1:%.*]] = bitcast <4 x half> %b to <8 x i8>
-// CHECK: [[TMP2:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x i16>
-// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to i16*
-// CHECK: [[TMP4:%.*]] = load i16, i16* [[TMP3]]
-// CHECK: [[VLD1_LANE:%.*]] = insertelement <4 x i16> [[TMP2]], i16 [[TMP4]], i32 3
-// CHECK: [[TMP5:%.*]] = bitcast <4 x i16> [[VLD1_LANE]] to <4 x half>
-// CHECK: ret <4 x half> [[TMP5]]
+// CHECK: [[TMP2:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x half>
+// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to half*
+// CHECK: [[TMP4:%.*]] = load half, half* [[TMP3]]
+// CHECK: [[VLD1_LANE:%.*]] = insertelement <4 x half> [[TMP2]], half [[TMP4]], i32 3
+// CHECK: ret <4 x half> [[VLD1_LANE]]
float16x4_t test_vld1_lane_f16(float16_t *a, float16x4_t b) {
return vld1_lane_f16(a, b, 3);
}
@@ -2495,11 +2491,11 @@ int64x2x2_t test_vld2q_lane_s64(int64_t *a, int64x2x2_t b) {
// CHECK: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x <8 x half>], [2 x <8 x half>]* [[VAL1]], i64 0, i64 1
// CHECK: [[TMP6:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX2]], align 16
// CHECK: [[TMP7:%.*]] = bitcast <8 x half> [[TMP6]] to <16 x i8>
-// CHECK: [[TMP8:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x i16>
-// CHECK: [[TMP9:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x i16>
-// CHECK: [[VLD2_LANE:%.*]] = call { <8 x i16>, <8 x i16> } @llvm.aarch64.neon.ld2lane.v8i16.p0i8(<8 x i16> [[TMP8]], <8 x i16> [[TMP9]], i64 7, i8* [[TMP3]])
-// CHECK: [[TMP10:%.*]] = bitcast i8* [[TMP2]] to { <8 x i16>, <8 x i16> }*
-// CHECK: store { <8 x i16>, <8 x i16> } [[VLD2_LANE]], { <8 x i16>, <8 x i16> }* [[TMP10]]
+// CHECK: [[TMP8:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x half>
+// CHECK: [[TMP9:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x half>
+// CHECK: [[VLD2_LANE:%.*]] = call { <8 x half>, <8 x half> } @llvm.aarch64.neon.ld2lane.v8f16.p0i8(<8 x half> [[TMP8]], <8 x half> [[TMP9]], i64 7, i8* [[TMP3]])
+// CHECK: [[TMP10:%.*]] = bitcast i8* [[TMP2]] to { <8 x half>, <8 x half> }*
+// CHECK: store { <8 x half>, <8 x half> } [[VLD2_LANE]], { <8 x half>, <8 x half> }* [[TMP10]]
// CHECK: [[TMP11:%.*]] = bitcast %struct.float16x8x2_t* [[RETVAL]] to i8*
// CHECK: [[TMP12:%.*]] = bitcast %struct.float16x8x2_t* [[__RET]] to i8*
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP11]], i8* [[TMP12]], i64 32, i32 16, i1 false)
@@ -2927,11 +2923,11 @@ int64x1x2_t test_vld2_lane_s64(int64_t *a, int64x1x2_t b) {
// CHECK: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x <4 x half>], [2 x <4 x half>]* [[VAL1]], i64 0, i64 1
// CHECK: [[TMP6:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX2]], align 8
// CHECK: [[TMP7:%.*]] = bitcast <4 x half> [[TMP6]] to <8 x i8>
-// CHECK: [[TMP8:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x i16>
-// CHECK: [[TMP9:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x i16>
-// CHECK: [[VLD2_LANE:%.*]] = call { <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld2lane.v4i16.p0i8(<4 x i16> [[TMP8]], <4 x i16> [[TMP9]], i64 3, i8* [[TMP3]])
-// CHECK: [[TMP10:%.*]] = bitcast i8* [[TMP2]] to { <4 x i16>, <4 x i16> }*
-// CHECK: store { <4 x i16>, <4 x i16> } [[VLD2_LANE]], { <4 x i16>, <4 x i16> }* [[TMP10]]
+// CHECK: [[TMP8:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x half>
+// CHECK: [[TMP9:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x half>
+// CHECK: [[VLD2_LANE:%.*]] = call { <4 x half>, <4 x half> } @llvm.aarch64.neon.ld2lane.v4f16.p0i8(<4 x half> [[TMP8]], <4 x half> [[TMP9]], i64 3, i8* [[TMP3]])
+// CHECK: [[TMP10:%.*]] = bitcast i8* [[TMP2]] to { <4 x half>, <4 x half> }*
+// CHECK: store { <4 x half>, <4 x half> } [[VLD2_LANE]], { <4 x half>, <4 x half> }* [[TMP10]]
// CHECK: [[TMP11:%.*]] = bitcast %struct.float16x4x2_t* [[RETVAL]] to i8*
// CHECK: [[TMP12:%.*]] = bitcast %struct.float16x4x2_t* [[__RET]] to i8*
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP11]], i8* [[TMP12]], i64 16, i32 8, i1 false)
@@ -3364,12 +3360,12 @@ int64x2x3_t test_vld3q_lane_s64(int64_t *a, int64x2x3_t b) {
// CHECK: [[ARRAYIDX4:%.*]] = getelementptr inbounds [3 x <8 x half>], [3 x <8 x half>]* [[VAL3]], i64 0, i64 2
// CHECK: [[TMP8:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX4]], align 16
// CHECK: [[TMP9:%.*]] = bitcast <8 x half> [[TMP8]] to <16 x i8>
-// CHECK: [[TMP10:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x i16>
-// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x i16>
-// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP9]] to <8 x i16>
-// CHECK: [[VLD3_LANE:%.*]] = call { <8 x i16>, <8 x i16>, <8 x i16> } @llvm.aarch64.neon.ld3lane.v8i16.p0i8(<8 x i16> [[TMP10]], <8 x i16> [[TMP11]], <8 x i16> [[TMP12]], i64 7, i8* [[TMP3]])
-// CHECK: [[TMP13:%.*]] = bitcast i8* [[TMP2]] to { <8 x i16>, <8 x i16>, <8 x i16> }*
-// CHECK: store { <8 x i16>, <8 x i16>, <8 x i16> } [[VLD3_LANE]], { <8 x i16>, <8 x i16>, <8 x i16> }* [[TMP13]]
+// CHECK: [[TMP10:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x half>
+// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x half>
+// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP9]] to <8 x half>
+// CHECK: [[VLD3_LANE:%.*]] = call { <8 x half>, <8 x half>, <8 x half> } @llvm.aarch64.neon.ld3lane.v8f16.p0i8(<8 x half> [[TMP10]], <8 x half> [[TMP11]], <8 x half> [[TMP12]], i64 7, i8* [[TMP3]])
+// CHECK: [[TMP13:%.*]] = bitcast i8* [[TMP2]] to { <8 x half>, <8 x half>, <8 x half> }*
+// CHECK: store { <8 x half>, <8 x half>, <8 x half> } [[VLD3_LANE]], { <8 x half>, <8 x half>, <8 x half> }* [[TMP13]]
// CHECK: [[TMP14:%.*]] = bitcast %struct.float16x8x3_t* [[RETVAL]] to i8*
// CHECK: [[TMP15:%.*]] = bitcast %struct.float16x8x3_t* [[__RET]] to i8*
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP14]], i8* [[TMP15]], i64 48, i32 16, i1 false)
@@ -3889,12 +3885,12 @@ int64x1x3_t test_vld3_lane_s64(int64_t *a, int64x1x3_t b) {
// CHECK: [[ARRAYIDX4:%.*]] = getelementptr inbounds [3 x <4 x half>], [3 x <4 x half>]* [[VAL3]], i64 0, i64 2
// CHECK: [[TMP8:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX4]], align 8
// CHECK: [[TMP9:%.*]] = bitcast <4 x half> [[TMP8]] to <8 x i8>
-// CHECK: [[TMP10:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x i16>
-// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x i16>
-// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP9]] to <4 x i16>
-// CHECK: [[VLD3_LANE:%.*]] = call { <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld3lane.v4i16.p0i8(<4 x i16> [[TMP10]], <4 x i16> [[TMP11]], <4 x i16> [[TMP12]], i64 3, i8* [[TMP3]])
-// CHECK: [[TMP13:%.*]] = bitcast i8* [[TMP2]] to { <4 x i16>, <4 x i16>, <4 x i16> }*
-// CHECK: store { <4 x i16>, <4 x i16>, <4 x i16> } [[VLD3_LANE]], { <4 x i16>, <4 x i16>, <4 x i16> }* [[TMP13]]
+// CHECK: [[TMP10:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x half>
+// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x half>
+// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP9]] to <4 x half>
+// CHECK: [[VLD3_LANE:%.*]] = call { <4 x half>, <4 x half>, <4 x half> } @llvm.aarch64.neon.ld3lane.v4f16.p0i8(<4 x half> [[TMP10]], <4 x half> [[TMP11]], <4 x half> [[TMP12]], i64 3, i8* [[TMP3]])
+// CHECK: [[TMP13:%.*]] = bitcast i8* [[TMP2]] to { <4 x half>, <4 x half>, <4 x half> }*
+// CHECK: store { <4 x half>, <4 x half>, <4 x half> } [[VLD3_LANE]], { <4 x half>, <4 x half>, <4 x half> }* [[TMP13]]
// CHECK: [[TMP14:%.*]] = bitcast %struct.float16x4x3_t* [[RETVAL]] to i8*
// CHECK: [[TMP15:%.*]] = bitcast %struct.float16x4x3_t* [[__RET]] to i8*
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP14]], i8* [[TMP15]], i64 24, i32 8, i1 false)
@@ -4454,13 +4450,13 @@ int64x2x4_t test_vld4q_lane_s64(int64_t *a, int64x2x4_t b) {
// CHECK: [[ARRAYIDX6:%.*]] = getelementptr inbounds [4 x <8 x half>], [4 x <8 x half>]* [[VAL5]], i64 0, i64 3
// CHECK: [[TMP10:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX6]], align 16
// CHECK: [[TMP11:%.*]] = bitcast <8 x half> [[TMP10]] to <16 x i8>
-// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x i16>
-// CHECK: [[TMP13:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x i16>
-// CHECK: [[TMP14:%.*]] = bitcast <16 x i8> [[TMP9]] to <8 x i16>
-// CHECK: [[TMP15:%.*]] = bitcast <16 x i8> [[TMP11]] to <8 x i16>
-// CHECK: [[VLD4_LANE:%.*]] = call { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } @llvm.aarch64.neon.ld4lane.v8i16.p0i8(<8 x i16> [[TMP12]], <8 x i16> [[TMP13]], <8 x i16> [[TMP14]], <8 x i16> [[TMP15]], i64 7, i8* [[TMP3]])
-// CHECK: [[TMP16:%.*]] = bitcast i8* [[TMP2]] to { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> }*
-// CHECK: store { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } [[VLD4_LANE]], { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> }* [[TMP16]]
+// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x half>
+// CHECK: [[TMP13:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x half>
+// CHECK: [[TMP14:%.*]] = bitcast <16 x i8> [[TMP9]] to <8 x half>
+// CHECK: [[TMP15:%.*]] = bitcast <16 x i8> [[TMP11]] to <8 x half>
+// CHECK: [[VLD4_LANE:%.*]] = call { <8 x half>, <8 x half>, <8 x half>, <8 x half> } @llvm.aarch64.neon.ld4lane.v8f16.p0i8(<8 x half> [[TMP12]], <8 x half> [[TMP13]], <8 x half> [[TMP14]], <8 x half> [[TMP15]], i64 7, i8* [[TMP3]])
+// CHECK: [[TMP16:%.*]] = bitcast i8* [[TMP2]] to { <8 x half>, <8 x half>, <8 x half>, <8 x half> }*
+// CHECK: store { <8 x half>, <8 x half>, <8 x half>, <8 x half> } [[VLD4_LANE]], { <8 x half>, <8 x half>, <8 x half>, <8 x half> }* [[TMP16]]
// CHECK: [[TMP17:%.*]] = bitcast %struct.float16x8x4_t* [[RETVAL]] to i8*
// CHECK: [[TMP18:%.*]] = bitcast %struct.float16x8x4_t* [[__RET]] to i8*
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP17]], i8* [[TMP18]], i64 64, i32 16, i1 false)
@@ -5043,13 +5039,13 @@ int64x1x4_t test_vld4_lane_s64(int64_t *a, int64x1x4_t b) {
// CHECK: [[ARRAYIDX6:%.*]] = getelementptr inbounds [4 x <4 x half>], [4 x <4 x half>]* [[VAL5]], i64 0, i64 3
// CHECK: [[TMP10:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX6]], align 8
// CHECK: [[TMP11:%.*]] = bitcast <4 x half> [[TMP10]] to <8 x i8>
-// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x i16>
-// CHECK: [[TMP13:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x i16>
-// CHECK: [[TMP14:%.*]] = bitcast <8 x i8> [[TMP9]] to <4 x i16>
-// CHECK: [[TMP15:%.*]] = bitcast <8 x i8> [[TMP11]] to <4 x i16>
-// CHECK: [[VLD4_LANE:%.*]] = call { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld4lane.v4i16.p0i8(<4 x i16> [[TMP12]], <4 x i16> [[TMP13]], <4 x i16> [[TMP14]], <4 x i16> [[TMP15]], i64 3, i8* [[TMP3]])
-// CHECK: [[TMP16:%.*]] = bitcast i8* [[TMP2]] to { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> }*
-// CHECK: store { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } [[VLD4_LANE]], { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> }* [[TMP16]]
+// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x half>
+// CHECK: [[TMP13:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x half>
+// CHECK: [[TMP14:%.*]] = bitcast <8 x i8> [[TMP9]] to <4 x half>
+// CHECK: [[TMP15:%.*]] = bitcast <8 x i8> [[TMP11]] to <4 x half>
+// CHECK: [[VLD4_LANE:%.*]] = call { <4 x half>, <4 x half>, <4 x half>, <4 x half> } @llvm.aarch64.neon.ld4lane.v4f16.p0i8(<4 x half> [[TMP12]], <4 x half> [[TMP13]], <4 x half> [[TMP14]], <4 x half> [[TMP15]], i64 3, i8* [[TMP3]])
+// CHECK: [[TMP16:%.*]] = bitcast i8* [[TMP2]] to { <4 x half>, <4 x half>, <4 x half>, <4 x half> }*
+// CHECK: store { <4 x half>, <4 x half>, <4 x half>, <4 x half> } [[VLD4_LANE]], { <4 x half>, <4 x half>, <4 x half>, <4 x half> }* [[TMP16]]
// CHECK: [[TMP17:%.*]] = bitcast %struct.float16x4x4_t* [[RETVAL]] to i8*
// CHECK: [[TMP18:%.*]] = bitcast %struct.float16x4x4_t* [[__RET]] to i8*
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP17]], i8* [[TMP18]], i64 32, i32 8, i1 false)
@@ -5361,10 +5357,10 @@ void test_vst1q_lane_s64(int64_t *a, int64x2_t b) {
// CHECK-LABEL: define void @test_vst1q_lane_f16(half* %a, <8 x half> %b) #0 {
// CHECK: [[TMP0:%.*]] = bitcast half* %a to i8*
// CHECK: [[TMP1:%.*]] = bitcast <8 x half> %b to <16 x i8>
-// CHECK: [[TMP2:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x i16>
-// CHECK: [[TMP3:%.*]] = extractelement <8 x i16> [[TMP2]], i32 7
-// CHECK: [[TMP4:%.*]] = bitcast i8* [[TMP0]] to i16*
-// CHECK: store i16 [[TMP3]], i16* [[TMP4]]
+// CHECK: [[TMP2:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x half>
+// CHECK: [[TMP3:%.*]] = extractelement <8 x half> [[TMP2]], i32 7
+// CHECK: [[TMP4:%.*]] = bitcast i8* [[TMP0]] to half*
+// CHECK: store half [[TMP3]], half* [[TMP4]]
// CHECK: ret void
void test_vst1q_lane_f16(float16_t *a, float16x8_t b) {
vst1q_lane_f16(a, b, 7);
@@ -5517,10 +5513,10 @@ void test_vst1_lane_s64(int64_t *a, int64x1_t b) {
// CHECK-LABEL: define void @test_vst1_lane_f16(half* %a, <4 x half> %b) #0 {
// CHECK: [[TMP0:%.*]] = bitcast half* %a to i8*
// CHECK: [[TMP1:%.*]] = bitcast <4 x half> %b to <8 x i8>
-// CHECK: [[TMP2:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x i16>
-// CHECK: [[TMP3:%.*]] = extractelement <4 x i16> [[TMP2]], i32 3
-// CHECK: [[TMP4:%.*]] = bitcast i8* [[TMP0]] to i16*
-// CHECK: store i16 [[TMP3]], i16* [[TMP4]]
+// CHECK: [[TMP2:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x half>
+// CHECK: [[TMP3:%.*]] = extractelement <4 x half> [[TMP2]], i32 3
+// CHECK: [[TMP4:%.*]] = bitcast i8* [[TMP0]] to half*
+// CHECK: store half [[TMP3]], half* [[TMP4]]
// CHECK: ret void
void test_vst1_lane_f16(float16_t *a, float16x4_t b) {
vst1_lane_f16(a, b, 3);
@@ -5789,9 +5785,9 @@ void test_vst2q_lane_s64(int64_t *a, int64x2x2_t b) {
// CHECK: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x <8 x half>], [2 x <8 x half>]* [[VAL1]], i64 0, i64 1
// CHECK: [[TMP5:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX2]], align 16
// CHECK: [[TMP6:%.*]] = bitcast <8 x half> [[TMP5]] to <16 x i8>
-// CHECK: [[TMP7:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x i16>
-// CHECK: [[TMP8:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x i16>
-// CHECK: call void @llvm.aarch64.neon.st2lane.v8i16.p0i8(<8 x i16> [[TMP7]], <8 x i16> [[TMP8]], i64 7, i8* [[TMP2]])
+// CHECK: [[TMP7:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x half>
+// CHECK: [[TMP8:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x half>
+// CHECK: call void @llvm.aarch64.neon.st2lane.v8f16.p0i8(<8 x half> [[TMP7]], <8 x half> [[TMP8]], i64 7, i8* [[TMP2]])
// CHECK: ret void
void test_vst2q_lane_f16(float16_t *a, float16x8x2_t b) {
vst2q_lane_f16(a, b, 7);
@@ -6124,9 +6120,9 @@ void test_vst2_lane_s64(int64_t *a, int64x1x2_t b) {
// CHECK: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x <4 x half>], [2 x <4 x half>]* [[VAL1]], i64 0, i64 1
// CHECK: [[TMP5:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX2]], align 8
// CHECK: [[TMP6:%.*]] = bitcast <4 x half> [[TMP5]] to <8 x i8>
-// CHECK: [[TMP7:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x i16>
-// CHECK: [[TMP8:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x i16>
-// CHECK: call void @llvm.aarch64.neon.st2lane.v4i16.p0i8(<4 x i16> [[TMP7]], <4 x i16> [[TMP8]], i64 3, i8* [[TMP2]])
+// CHECK: [[TMP7:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x half>
+// CHECK: [[TMP8:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x half>
+// CHECK: call void @llvm.aarch64.neon.st2lane.v4f16.p0i8(<4 x half> [[TMP7]], <4 x half> [[TMP8]], i64 3, i8* [[TMP2]])
// CHECK: ret void
void test_vst2_lane_f16(float16_t *a, float16x4x2_t b) {
vst2_lane_f16(a, b, 3);
@@ -6499,10 +6495,10 @@ void test_vst3q_lane_s64(int64_t *a, int64x2x3_t b) {
// CHECK: [[ARRAYIDX4:%.*]] = getelementptr inbounds [3 x <8 x half>], [3 x <8 x half>]* [[VAL3]], i64 0, i64 2
// CHECK: [[TMP7:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX4]], align 16
// CHECK: [[TMP8:%.*]] = bitcast <8 x half> [[TMP7]] to <16 x i8>
-// CHECK: [[TMP9:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x i16>
-// CHECK: [[TMP10:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x i16>
-// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x i16>
-// CHECK: call void @llvm.aarch64.neon.st3lane.v8i16.p0i8(<8 x i16> [[TMP9]], <8 x i16> [[TMP10]], <8 x i16> [[TMP11]], i64 7, i8* [[TMP2]])
+// CHECK: [[TMP9:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x half>
+// CHECK: [[TMP10:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x half>
+// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x half>
+// CHECK: call void @llvm.aarch64.neon.st3lane.v8f16.p0i8(<8 x half> [[TMP9]], <8 x half> [[TMP10]], <8 x half> [[TMP11]], i64 7, i8* [[TMP2]])
// CHECK: ret void
void test_vst3q_lane_f16(float16_t *a, float16x8x3_t b) {
vst3q_lane_f16(a, b, 7);
@@ -6898,10 +6894,10 @@ void test_vst3_lane_s64(int64_t *a, int64x1x3_t b) {
// CHECK: [[ARRAYIDX4:%.*]] = getelementptr inbounds [3 x <4 x half>], [3 x <4 x half>]* [[VAL3]], i64 0, i64 2
// CHECK: [[TMP7:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX4]], align 8
// CHECK: [[TMP8:%.*]] = bitcast <4 x half> [[TMP7]] to <8 x i8>
-// CHECK: [[TMP9:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x i16>
-// CHECK: [[TMP10:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x i16>
-// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x i16>
-// CHECK: call void @llvm.aarch64.neon.st3lane.v4i16.p0i8(<4 x i16> [[TMP9]], <4 x i16> [[TMP10]], <4 x i16> [[TMP11]], i64 3, i8* [[TMP2]])
+// CHECK: [[TMP9:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x half>
+// CHECK: [[TMP10:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x half>
+// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x half>
+// CHECK: call void @llvm.aarch64.neon.st3lane.v4f16.p0i8(<4 x half> [[TMP9]], <4 x half> [[TMP10]], <4 x half> [[TMP11]], i64 3, i8* [[TMP2]])
// CHECK: ret void
void test_vst3_lane_f16(float16_t *a, float16x4x3_t b) {
vst3_lane_f16(a, b, 3);
@@ -7337,11 +7333,11 @@ void test_vst4q_lane_s64(int64_t *a, int64x2x4_t b) {
// CHECK: [[ARRAYIDX6:%.*]] = getelementptr inbounds [4 x <8 x half>], [4 x <8 x half>]* [[VAL5]], i64 0, i64 3
// CHECK: [[TMP9:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX6]], align 16
// CHECK: [[TMP10:%.*]] = bitcast <8 x half> [[TMP9]] to <16 x i8>
-// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x i16>
-// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x i16>
-// CHECK: [[TMP13:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x i16>
-// CHECK: [[TMP14:%.*]] = bitcast <16 x i8> [[TMP10]] to <8 x i16>
-// CHECK: call void @llvm.aarch64.neon.st4lane.v8i16.p0i8(<8 x i16> [[TMP11]], <8 x i16> [[TMP12]], <8 x i16> [[TMP13]], <8 x i16> [[TMP14]], i64 7, i8* [[TMP2]])
+// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x half>
+// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x half>
+// CHECK: [[TMP13:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x half>
+// CHECK: [[TMP14:%.*]] = bitcast <16 x i8> [[TMP10]] to <8 x half>
+// CHECK: call void @llvm.aarch64.neon.st4lane.v8f16.p0i8(<8 x half> [[TMP11]], <8 x half> [[TMP12]], <8 x half> [[TMP13]], <8 x half> [[TMP14]], i64 7, i8* [[TMP2]])
// CHECK: ret void
void test_vst4q_lane_f16(float16_t *a, float16x8x4_t b) {
vst4q_lane_f16(a, b, 7);
@@ -7800,11 +7796,11 @@ void test_vst4_lane_s64(int64_t *a, int64x1x4_t b) {
// CHECK: [[ARRAYIDX6:%.*]] = getelementptr inbounds [4 x <4 x half>], [4 x <4 x half>]* [[VAL5]], i64 0, i64 3
// CHECK: [[TMP9:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX6]], align 8
// CHECK: [[TMP10:%.*]] = bitcast <4 x half> [[TMP9]] to <8 x i8>
-// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x i16>
-// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x i16>
-// CHECK: [[TMP13:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x i16>
-// CHECK: [[TMP14:%.*]] = bitcast <8 x i8> [[TMP10]] to <4 x i16>
-// CHECK: call void @llvm.aarch64.neon.st4lane.v4i16.p0i8(<4 x i16> [[TMP11]], <4 x i16> [[TMP12]], <4 x i16> [[TMP13]], <4 x i16> [[TMP14]], i64 3, i8* [[TMP2]])
+// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x half>
+// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x half>
+// CHECK: [[TMP13:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x half>
+// CHECK: [[TMP14:%.*]] = bitcast <8 x i8> [[TMP10]] to <4 x half>
+// CHECK: call void @llvm.aarch64.neon.st4lane.v4f16.p0i8(<4 x half> [[TMP11]], <4 x half> [[TMP12]], <4 x half> [[TMP13]], <4 x half> [[TMP14]], i64 3, i8* [[TMP2]])
// CHECK: ret void
void test_vst4_lane_f16(float16_t *a, float16x4x4_t b) {
vst4_lane_f16(a, b, 3);
diff --git a/test/CodeGen/aarch64-v8.2a-neon-intrinsics.c b/test/CodeGen/aarch64-v8.2a-neon-intrinsics.c
new file mode 100644
index 000000000000..3f61238b64fb
--- /dev/null
+++ b/test/CodeGen/aarch64-v8.2a-neon-intrinsics.c
@@ -0,0 +1,1633 @@
+// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon -target-feature +fullfp16 -target-feature +v8.2a\
+// RUN: -fallow-half-arguments-and-returns -S -disable-O0-optnone -emit-llvm -o - %s \
+// RUN: | opt -S -mem2reg \
+// RUN: | FileCheck %s
+
+// REQUIRES: aarch64-registered-target
+
+#include <arm_neon.h>
+
+// CHECK-LABEL: test_vabs_f16
+// CHECK: [[ABS:%.*]] = call <4 x half> @llvm.fabs.v4f16(<4 x half> %a)
+// CHECK: ret <4 x half> [[ABS]]
+float16x4_t test_vabs_f16(float16x4_t a) {
+ return vabs_f16(a);
+}
+
+// CHECK-LABEL: test_vabsq_f16
+// CHECK: [[ABS:%.*]] = call <8 x half> @llvm.fabs.v8f16(<8 x half> %a)
+// CHECK: ret <8 x half> [[ABS]]
+float16x8_t test_vabsq_f16(float16x8_t a) {
+ return vabsq_f16(a);
+}
+
+// CHECK-LABEL: test_vceqz_f16
+// CHECK: [[TMP1:%.*]] = fcmp oeq <4 x half> %a, zeroinitializer
+// CHECK: [[TMP2:%.*]] = sext <4 x i1> [[TMP1]] to <4 x i16>
+// CHECK: ret <4 x i16> [[TMP2]]
+uint16x4_t test_vceqz_f16(float16x4_t a) {
+ return vceqz_f16(a);
+}
+
+// CHECK-LABEL: test_vceqzq_f16
+// CHECK: [[TMP1:%.*]] = fcmp oeq <8 x half> %a, zeroinitializer
+// CHECK: [[TMP2:%.*]] = sext <8 x i1> [[TMP1:%.*]] to <8 x i16>
+// CHECK: ret <8 x i16> [[TMP2]]
+uint16x8_t test_vceqzq_f16(float16x8_t a) {
+ return vceqzq_f16(a);
+}
+
+// CHECK-LABEL: test_vcgez_f16
+// CHECK: [[TMP1:%.*]] = fcmp oge <4 x half> %a, zeroinitializer
+// CHECK: [[TMP2:%.*]] = sext <4 x i1> [[TMP1]] to <4 x i16>
+// CHECK: ret <4 x i16> [[TMP2]]
+uint16x4_t test_vcgez_f16(float16x4_t a) {
+ return vcgez_f16(a);
+}
+
+// CHECK-LABEL: test_vcgezq_f16
+// CHECK: [[TMP1:%.*]] = fcmp oge <8 x half> %a, zeroinitializer
+// CHECK: [[TMP2:%.*]] = sext <8 x i1> [[TMP1:%.*]] to <8 x i16>
+// CHECK: ret <8 x i16> [[TMP2]]
+uint16x8_t test_vcgezq_f16(float16x8_t a) {
+ return vcgezq_f16(a);
+}
+
+// CHECK-LABEL: test_vcgtz_f16
+// CHECK: [[TMP1:%.*]] = fcmp ogt <4 x half> %a, zeroinitializer
+// CHECK: [[TMP2:%.*]] = sext <4 x i1> [[TMP1]] to <4 x i16>
+// CHECK: ret <4 x i16> [[TMP2]]
+uint16x4_t test_vcgtz_f16(float16x4_t a) {
+ return vcgtz_f16(a);
+}
+
+// CHECK-LABEL: test_vcgtzq_f16
+// CHECK: [[TMP1:%.*]] = fcmp ogt <8 x half> %a, zeroinitializer
+// CHECK: [[TMP2:%.*]] = sext <8 x i1> [[TMP1:%.*]] to <8 x i16>
+// CHECK: ret <8 x i16> [[TMP2]]
+uint16x8_t test_vcgtzq_f16(float16x8_t a) {
+ return vcgtzq_f16(a);
+}
+
+// CHECK-LABEL: test_vclez_f16
+// CHECK: [[TMP1:%.*]] = fcmp ole <4 x half> %a, zeroinitializer
+// CHECK: [[TMP2:%.*]] = sext <4 x i1> [[TMP1]] to <4 x i16>
+// CHECK: ret <4 x i16> [[TMP2]]
+uint16x4_t test_vclez_f16(float16x4_t a) {
+ return vclez_f16(a);
+}
+
+// CHECK-LABEL: test_vclezq_f16
+// CHECK: [[TMP1:%.*]] = fcmp ole <8 x half> %a, zeroinitializer
+// CHECK: [[TMP2:%.*]] = sext <8 x i1> [[TMP1:%.*]] to <8 x i16>
+// CHECK: ret <8 x i16> [[TMP2]]
+uint16x8_t test_vclezq_f16(float16x8_t a) {
+ return vclezq_f16(a);
+}
+
+// CHECK-LABEL: test_vcltz_f16
+// CHECK: [[TMP1:%.*]] = fcmp olt <4 x half> %a, zeroinitializer
+// CHECK: [[TMP2:%.*]] = sext <4 x i1> [[TMP1]] to <4 x i16>
+// CHECK: ret <4 x i16> [[TMP2]]
+uint16x4_t test_vcltz_f16(float16x4_t a) {
+ return vcltz_f16(a);
+}
+
+// CHECK-LABEL: test_vcltzq_f16
+// CHECK: [[TMP1:%.*]] = fcmp olt <8 x half> %a, zeroinitializer
+// CHECK: [[TMP2:%.*]] = sext <8 x i1> [[TMP1:%.*]] to <8 x i16>
+// CHECK: ret <8 x i16> [[TMP2]]
+uint16x8_t test_vcltzq_f16(float16x8_t a) {
+ return vcltzq_f16(a);
+}
+
+// CHECK-LABEL: test_vcvt_f16_s16
+// CHECK: [[VCVT:%.*]] = sitofp <4 x i16> %a to <4 x half>
+// CHECK: ret <4 x half> [[VCVT]]
+float16x4_t test_vcvt_f16_s16 (int16x4_t a) {
+ return vcvt_f16_s16(a);
+}
+
+// CHECK-LABEL: test_vcvtq_f16_s16
+// CHECK: [[VCVT:%.*]] = sitofp <8 x i16> %a to <8 x half>
+// CHECK: ret <8 x half> [[VCVT]]
+float16x8_t test_vcvtq_f16_s16 (int16x8_t a) {
+ return vcvtq_f16_s16(a);
+}
+
+// CHECK-LABEL: test_vcvt_f16_u16
+// CHECK: [[VCVT:%.*]] = uitofp <4 x i16> %a to <4 x half>
+// CHECK: ret <4 x half> [[VCVT]]
+float16x4_t test_vcvt_f16_u16 (uint16x4_t a) {
+ return vcvt_f16_u16(a);
+}
+
+// CHECK-LABEL: test_vcvtq_f16_u16
+// CHECK: [[VCVT:%.*]] = uitofp <8 x i16> %a to <8 x half>
+// CHECK: ret <8 x half> [[VCVT]]
+float16x8_t test_vcvtq_f16_u16 (uint16x8_t a) {
+ return vcvtq_f16_u16(a);
+}
+
+// CHECK-LABEL: test_vcvt_s16_f16
+// CHECK: [[VCVT:%.*]] = fptosi <4 x half> %a to <4 x i16>
+// CHECK: ret <4 x i16> [[VCVT]]
+int16x4_t test_vcvt_s16_f16 (float16x4_t a) {
+ return vcvt_s16_f16(a);
+}
+
+// CHECK-LABEL: test_vcvtq_s16_f16
+// CHECK: [[VCVT:%.*]] = fptosi <8 x half> %a to <8 x i16>
+// CHECK: ret <8 x i16> [[VCVT]]
+int16x8_t test_vcvtq_s16_f16 (float16x8_t a) {
+ return vcvtq_s16_f16(a);
+}
+
+// CHECK-LABEL: test_vcvt_u16_f16
+// CHECK: [[VCVT:%.*]] = fptoui <4 x half> %a to <4 x i16>
+// CHECK: ret <4 x i16> [[VCVT]]
+int16x4_t test_vcvt_u16_f16 (float16x4_t a) {
+ return vcvt_u16_f16(a);
+}
+
+// CHECK-LABEL: test_vcvtq_u16_f16
+// CHECK: [[VCVT:%.*]] = fptoui <8 x half> %a to <8 x i16>
+// CHECK: ret <8 x i16> [[VCVT]]
+int16x8_t test_vcvtq_u16_f16 (float16x8_t a) {
+ return vcvtq_u16_f16(a);
+}
+
+// CHECK-LABEL: test_vcvta_s16_f16
+// CHECK: [[VCVT:%.*]] = call <4 x i16> @llvm.aarch64.neon.fcvtas.v4i16.v4f16(<4 x half> %a)
+// CHECK: ret <4 x i16> [[VCVT]]
+int16x4_t test_vcvta_s16_f16 (float16x4_t a) {
+ return vcvta_s16_f16(a);
+}
+
+// CHECK-LABEL: test_vcvtaq_s16_f16
+// CHECK: [[VCVT:%.*]] = call <8 x i16> @llvm.aarch64.neon.fcvtas.v8i16.v8f16(<8 x half> %a)
+// CHECK: ret <8 x i16> [[VCVT]]
+int16x8_t test_vcvtaq_s16_f16 (float16x8_t a) {
+ return vcvtaq_s16_f16(a);
+}
+
+// CHECK-LABEL: test_vcvtm_s16_f16
+// CHECK: [[VCVT:%.*]] = call <4 x i16> @llvm.aarch64.neon.fcvtms.v4i16.v4f16(<4 x half> %a)
+// CHECK: ret <4 x i16> [[VCVT]]
+int16x4_t test_vcvtm_s16_f16 (float16x4_t a) {
+ return vcvtm_s16_f16(a);
+}
+
+// CHECK-LABEL: test_vcvtmq_s16_f16
+// CHECK: [[VCVT:%.*]] = call <8 x i16> @llvm.aarch64.neon.fcvtms.v8i16.v8f16(<8 x half> %a)
+// CHECK: ret <8 x i16> [[VCVT]]
+int16x8_t test_vcvtmq_s16_f16 (float16x8_t a) {
+ return vcvtmq_s16_f16(a);
+}
+
+// CHECK-LABEL: test_vcvtm_u16_f16
+// CHECK: [[VCVT:%.*]] = call <4 x i16> @llvm.aarch64.neon.fcvtmu.v4i16.v4f16(<4 x half> %a)
+// CHECK: ret <4 x i16> [[VCVT]]
+uint16x4_t test_vcvtm_u16_f16 (float16x4_t a) {
+ return vcvtm_u16_f16(a);
+}
+
+// CHECK-LABEL: test_vcvtmq_u16_f16
+// CHECK: [[VCVT:%.*]] = call <8 x i16> @llvm.aarch64.neon.fcvtmu.v8i16.v8f16(<8 x half> %a)
+// CHECK: ret <8 x i16> [[VCVT]]
+uint16x8_t test_vcvtmq_u16_f16 (float16x8_t a) {
+ return vcvtmq_u16_f16(a);
+}
+
+// CHECK-LABEL: test_vcvtn_s16_f16
+// CHECK: [[VCVT:%.*]] = call <4 x i16> @llvm.aarch64.neon.fcvtns.v4i16.v4f16(<4 x half> %a)
+// CHECK: ret <4 x i16> [[VCVT]]
+int16x4_t test_vcvtn_s16_f16 (float16x4_t a) {
+ return vcvtn_s16_f16(a);
+}
+
+// CHECK-LABEL: test_vcvtnq_s16_f16
+// CHECK: [[VCVT:%.*]] = call <8 x i16> @llvm.aarch64.neon.fcvtns.v8i16.v8f16(<8 x half> %a)
+// CHECK: ret <8 x i16> [[VCVT]]
+int16x8_t test_vcvtnq_s16_f16 (float16x8_t a) {
+ return vcvtnq_s16_f16(a);
+}
+
+// CHECK-LABEL: test_vcvtn_u16_f16
+// CHECK: [[VCVT:%.*]] = call <4 x i16> @llvm.aarch64.neon.fcvtnu.v4i16.v4f16(<4 x half> %a)
+// CHECK: ret <4 x i16> [[VCVT]]
+uint16x4_t test_vcvtn_u16_f16 (float16x4_t a) {
+ return vcvtn_u16_f16(a);
+}
+
+// CHECK-LABEL: test_vcvtnq_u16_f16
+// CHECK: [[VCVT:%.*]] = call <8 x i16> @llvm.aarch64.neon.fcvtnu.v8i16.v8f16(<8 x half> %a)
+// CHECK: ret <8 x i16> [[VCVT]]
+uint16x8_t test_vcvtnq_u16_f16 (float16x8_t a) {
+ return vcvtnq_u16_f16(a);
+}
+
+// CHECK-LABEL: test_vcvtp_s16_f16
+// CHECK: [[VCVT:%.*]] = call <4 x i16> @llvm.aarch64.neon.fcvtps.v4i16.v4f16(<4 x half> %a)
+// CHECK: ret <4 x i16> [[VCVT]]
+int16x4_t test_vcvtp_s16_f16 (float16x4_t a) {
+ return vcvtp_s16_f16(a);
+}
+
+// CHECK-LABEL: test_vcvtpq_s16_f16
+// CHECK: [[VCVT:%.*]] = call <8 x i16> @llvm.aarch64.neon.fcvtps.v8i16.v8f16(<8 x half> %a)
+// CHECK: ret <8 x i16> [[VCVT]]
+int16x8_t test_vcvtpq_s16_f16 (float16x8_t a) {
+ return vcvtpq_s16_f16(a);
+}
+
+// CHECK-LABEL: test_vcvtp_u16_f16
+// CHECK: [[VCVT:%.*]] = call <4 x i16> @llvm.aarch64.neon.fcvtpu.v4i16.v4f16(<4 x half> %a)
+// CHECK: ret <4 x i16> [[VCVT]]
+uint16x4_t test_vcvtp_u16_f16 (float16x4_t a) {
+ return vcvtp_u16_f16(a);
+}
+
+// CHECK-LABEL: test_vcvtpq_u16_f16
+// CHECK: [[VCVT:%.*]] = call <8 x i16> @llvm.aarch64.neon.fcvtpu.v8i16.v8f16(<8 x half> %a)
+// CHECK: ret <8 x i16> [[VCVT]]
+uint16x8_t test_vcvtpq_u16_f16 (float16x8_t a) {
+ return vcvtpq_u16_f16(a);
+}
+
+// FIXME: Fix the zero constant when fp16 non-storage-only type becomes available.
+// CHECK-LABEL: test_vneg_f16
+// CHECK: [[NEG:%.*]] = fsub <4 x half> <half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000>, %a
+// CHECK: ret <4 x half> [[NEG]]
+float16x4_t test_vneg_f16(float16x4_t a) {
+ return vneg_f16(a);
+}
+
+// CHECK-LABEL: test_vnegq_f16
+// CHECK: [[NEG:%.*]] = fsub <8 x half> <half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000>, %a
+// CHECK: ret <8 x half> [[NEG]]
+float16x8_t test_vnegq_f16(float16x8_t a) {
+ return vnegq_f16(a);
+}
+
+// CHECK-LABEL: test_vrecpe_f16
+// CHECK: [[RCP:%.*]] = call <4 x half> @llvm.aarch64.neon.frecpe.v4f16(<4 x half> %a)
+// CHECK: ret <4 x half> [[RCP]]
+float16x4_t test_vrecpe_f16(float16x4_t a) {
+ return vrecpe_f16(a);
+}
+
+// CHECK-LABEL: test_vrecpeq_f16
+// CHECK: [[RCP:%.*]] = call <8 x half> @llvm.aarch64.neon.frecpe.v8f16(<8 x half> %a)
+// CHECK: ret <8 x half> [[RCP]]
+float16x8_t test_vrecpeq_f16(float16x8_t a) {
+ return vrecpeq_f16(a);
+}
+
+// CHECK-LABEL: test_vrnd_f16
+// CHECK: [[RND:%.*]] = call <4 x half> @llvm.trunc.v4f16(<4 x half> %a)
+// CHECK: ret <4 x half> [[RND]]
+float16x4_t test_vrnd_f16(float16x4_t a) {
+ return vrnd_f16(a);
+}
+
+// CHECK-LABEL: test_vrndq_f16
+// CHECK: [[RND:%.*]] = call <8 x half> @llvm.trunc.v8f16(<8 x half> %a)
+// CHECK: ret <8 x half> [[RND]]
+float16x8_t test_vrndq_f16(float16x8_t a) {
+ return vrndq_f16(a);
+}
+
+// CHECK-LABEL: test_vrnda_f16
+// CHECK: [[RND:%.*]] = call <4 x half> @llvm.round.v4f16(<4 x half> %a)
+// CHECK: ret <4 x half> [[RND]]
+float16x4_t test_vrnda_f16(float16x4_t a) {
+ return vrnda_f16(a);
+}
+
+// CHECK-LABEL: test_vrndaq_f16
+// CHECK: [[RND:%.*]] = call <8 x half> @llvm.round.v8f16(<8 x half> %a)
+// CHECK: ret <8 x half> [[RND]]
+float16x8_t test_vrndaq_f16(float16x8_t a) {
+ return vrndaq_f16(a);
+}
+
+// CHECK-LABEL: test_vrndi_f16
+// CHECK: [[RND:%.*]] = call <4 x half> @llvm.nearbyint.v4f16(<4 x half> %a)
+// CHECK: ret <4 x half> [[RND]]
+float16x4_t test_vrndi_f16(float16x4_t a) {
+ return vrndi_f16(a);
+}
+
+// CHECK-LABEL: test_vrndiq_f16
+// CHECK: [[RND:%.*]] = call <8 x half> @llvm.nearbyint.v8f16(<8 x half> %a)
+// CHECK: ret <8 x half> [[RND]]
+float16x8_t test_vrndiq_f16(float16x8_t a) {
+ return vrndiq_f16(a);
+}
+
+// CHECK-LABEL: test_vrndm_f16
+// CHECK: [[RND:%.*]] = call <4 x half> @llvm.floor.v4f16(<4 x half> %a)
+// CHECK: ret <4 x half> [[RND]]
+float16x4_t test_vrndm_f16(float16x4_t a) {
+ return vrndm_f16(a);
+}
+
+// CHECK-LABEL: test_vrndmq_f16
+// CHECK: [[RND:%.*]] = call <8 x half> @llvm.floor.v8f16(<8 x half> %a)
+// CHECK: ret <8 x half> [[RND]]
+float16x8_t test_vrndmq_f16(float16x8_t a) {
+ return vrndmq_f16(a);
+}
+
+// CHECK-LABEL: test_vrndn_f16
+// CHECK: [[RND:%.*]] = call <4 x half> @llvm.aarch64.neon.frintn.v4f16(<4 x half> %a)
+// CHECK: ret <4 x half> [[RND]]
+float16x4_t test_vrndn_f16(float16x4_t a) {
+ return vrndn_f16(a);
+}
+
+// CHECK-LABEL: test_vrndnq_f16
+// CHECK: [[RND:%.*]] = call <8 x half> @llvm.aarch64.neon.frintn.v8f16(<8 x half> %a)
+// CHECK: ret <8 x half> [[RND]]
+float16x8_t test_vrndnq_f16(float16x8_t a) {
+ return vrndnq_f16(a);
+}
+
+// CHECK-LABEL: test_vrndp_f16
+// CHECK: [[RND:%.*]] = call <4 x half> @llvm.ceil.v4f16(<4 x half> %a)
+// CHECK: ret <4 x half> [[RND]]
+float16x4_t test_vrndp_f16(float16x4_t a) {
+ return vrndp_f16(a);
+}
+
+// CHECK-LABEL: test_vrndpq_f16
+// CHECK: [[RND:%.*]] = call <8 x half> @llvm.ceil.v8f16(<8 x half> %a)
+// CHECK: ret <8 x half> [[RND]]
+float16x8_t test_vrndpq_f16(float16x8_t a) {
+ return vrndpq_f16(a);
+}
+
+// CHECK-LABEL: test_vrndx_f16
+// CHECK: [[RND:%.*]] = call <4 x half> @llvm.rint.v4f16(<4 x half> %a)
+// CHECK: ret <4 x half> [[RND]]
+float16x4_t test_vrndx_f16(float16x4_t a) {
+ return vrndx_f16(a);
+}
+
+// CHECK-LABEL: test_vrndxq_f16
+// CHECK: [[RND:%.*]] = call <8 x half> @llvm.rint.v8f16(<8 x half> %a)
+// CHECK: ret <8 x half> [[RND]]
+float16x8_t test_vrndxq_f16(float16x8_t a) {
+ return vrndxq_f16(a);
+}
+
+// CHECK-LABEL: test_vrsqrte_f16
+// CHECK: [[RND:%.*]] = call <4 x half> @llvm.aarch64.neon.frsqrte.v4f16(<4 x half> %a)
+// CHECK: ret <4 x half> [[RND]]
+float16x4_t test_vrsqrte_f16(float16x4_t a) {
+ return vrsqrte_f16(a);
+}
+
+// CHECK-LABEL: test_vrsqrteq_f16
+// CHECK: [[RND:%.*]] = call <8 x half> @llvm.aarch64.neon.frsqrte.v8f16(<8 x half> %a)
+// CHECK: ret <8 x half> [[RND]]
+float16x8_t test_vrsqrteq_f16(float16x8_t a) {
+ return vrsqrteq_f16(a);
+}
+
+// CHECK-LABEL: test_vsqrt_f16
+// CHECK: [[SQR:%.*]] = call <4 x half> @llvm.sqrt.v4f16(<4 x half> %a)
+// CHECK: ret <4 x half> [[SQR]]
+float16x4_t test_vsqrt_f16(float16x4_t a) {
+ return vsqrt_f16(a);
+}
+
+// CHECK-LABEL: test_vsqrtq_f16
+// CHECK: [[SQR:%.*]] = call <8 x half> @llvm.sqrt.v8f16(<8 x half> %a)
+// CHECK: ret <8 x half> [[SQR]]
+float16x8_t test_vsqrtq_f16(float16x8_t a) {
+ return vsqrtq_f16(a);
+}
+
+// CHECK-LABEL: test_vadd_f16
+// CHECK: [[ADD:%.*]] = fadd <4 x half> %a, %b
+// CHECK: ret <4 x half> [[ADD]]
+float16x4_t test_vadd_f16(float16x4_t a, float16x4_t b) {
+ return vadd_f16(a, b);
+}
+
+// CHECK-LABEL: test_vaddq_f16
+// CHECK: [[ADD:%.*]] = fadd <8 x half> %a, %b
+// CHECK: ret <8 x half> [[ADD]]
+float16x8_t test_vaddq_f16(float16x8_t a, float16x8_t b) {
+ return vaddq_f16(a, b);
+}
+
+// CHECK-LABEL: test_vabd_f16
+// CHECK: [[ABD:%.*]] = call <4 x half> @llvm.aarch64.neon.fabd.v4f16(<4 x half> %a, <4 x half> %b)
+// CHECK: ret <4 x half> [[ABD]]
+float16x4_t test_vabd_f16(float16x4_t a, float16x4_t b) {
+ return vabd_f16(a, b);
+}
+
+// CHECK-LABEL: test_vabdq_f16
+// CHECK: [[ABD:%.*]] = call <8 x half> @llvm.aarch64.neon.fabd.v8f16(<8 x half> %a, <8 x half> %b)
+// CHECK: ret <8 x half> [[ABD]]
+float16x8_t test_vabdq_f16(float16x8_t a, float16x8_t b) {
+ return vabdq_f16(a, b);
+}
+
+// CHECK-LABEL: test_vcage_f16
+// CHECK: [[ABS:%.*]] = call <4 x i16> @llvm.aarch64.neon.facge.v4i16.v4f16(<4 x half> %a, <4 x half> %b)
+// CHECK: ret <4 x i16> [[ABS]]
+uint16x4_t test_vcage_f16(float16x4_t a, float16x4_t b) {
+ return vcage_f16(a, b);
+}
+
+// CHECK-LABEL: test_vcageq_f16
+// CHECK: [[ABS:%.*]] = call <8 x i16> @llvm.aarch64.neon.facge.v8i16.v8f16(<8 x half> %a, <8 x half> %b)
+// CHECK: ret <8 x i16> [[ABS]]
+uint16x8_t test_vcageq_f16(float16x8_t a, float16x8_t b) {
+ return vcageq_f16(a, b);
+}
+
+// CHECK-LABEL: test_vcagt_f16
+// CHECK: [[ABS:%.*]] = call <4 x i16> @llvm.aarch64.neon.facgt.v4i16.v4f16(<4 x half> %a, <4 x half> %b)
+// CHECK: ret <4 x i16> [[ABS]]
+uint16x4_t test_vcagt_f16(float16x4_t a, float16x4_t b) {
+ return vcagt_f16(a, b);
+}
+
+// CHECK-LABEL: test_vcagtq_f16
+// CHECK: [[ABS:%.*]] = call <8 x i16> @llvm.aarch64.neon.facgt.v8i16.v8f16(<8 x half> %a, <8 x half> %b)
+// CHECK: ret <8 x i16> [[ABS]]
+uint16x8_t test_vcagtq_f16(float16x8_t a, float16x8_t b) {
+ return vcagtq_f16(a, b);
+}
+
+// CHECK-LABEL: test_vcale_f16
+// CHECK: [[ABS:%.*]] = call <4 x i16> @llvm.aarch64.neon.facge.v4i16.v4f16(<4 x half> %b, <4 x half> %a)
+// CHECK: ret <4 x i16> [[ABS]]
+uint16x4_t test_vcale_f16(float16x4_t a, float16x4_t b) {
+ return vcale_f16(a, b);
+}
+
+// CHECK-LABEL: test_vcaleq_f16
+// CHECK: [[ABS:%.*]] = call <8 x i16> @llvm.aarch64.neon.facge.v8i16.v8f16(<8 x half> %b, <8 x half> %a)
+// CHECK: ret <8 x i16> [[ABS]]
+uint16x8_t test_vcaleq_f16(float16x8_t a, float16x8_t b) {
+ return vcaleq_f16(a, b);
+}
+
+// CHECK-LABEL: test_vcalt_f16
+// CHECK: [[ABS:%.*]] = call <4 x i16> @llvm.aarch64.neon.facgt.v4i16.v4f16(<4 x half> %b, <4 x half> %a)
+// CHECK: ret <4 x i16> [[ABS]]
+uint16x4_t test_vcalt_f16(float16x4_t a, float16x4_t b) {
+ return vcalt_f16(a, b);
+}
+
+// CHECK-LABEL: test_vcaltq_f16
+// CHECK: [[ABS:%.*]] = call <8 x i16> @llvm.aarch64.neon.facgt.v8i16.v8f16(<8 x half> %b, <8 x half> %a)
+// CHECK: ret <8 x i16> [[ABS]]
+uint16x8_t test_vcaltq_f16(float16x8_t a, float16x8_t b) {
+ return vcaltq_f16(a, b);
+}
+
+// CHECK-LABEL: test_vceq_f16
+// CHECK: [[TMP1:%.*]] = fcmp oeq <4 x half> %a, %b
+// CHECK: [[TMP2:%.*]] = sext <4 x i1> [[TMP1]] to <4 x i16>
+// CHECK: ret <4 x i16> [[TMP2]]
+uint16x4_t test_vceq_f16(float16x4_t a, float16x4_t b) {
+ return vceq_f16(a, b);
+}
+
+// CHECK-LABEL: test_vceqq_f16
+// CHECK: [[TMP1:%.*]] = fcmp oeq <8 x half> %a, %b
+// CHECK: [[TMP2:%.*]] = sext <8 x i1> [[TMP1:%.*]] to <8 x i16>
+// CHECK: ret <8 x i16> [[TMP2]]
+uint16x8_t test_vceqq_f16(float16x8_t a, float16x8_t b) {
+ return vceqq_f16(a, b);
+}
+
+// CHECK-LABEL: test_vcge_f16
+// CHECK: [[TMP1:%.*]] = fcmp oge <4 x half> %a, %b
+// CHECK: [[TMP2:%.*]] = sext <4 x i1> [[TMP1]] to <4 x i16>
+// CHECK: ret <4 x i16> [[TMP2]]
+uint16x4_t test_vcge_f16(float16x4_t a, float16x4_t b) {
+ return vcge_f16(a, b);
+}
+
+// CHECK-LABEL: test_vcgeq_f16
+// CHECK: [[TMP1:%.*]] = fcmp oge <8 x half> %a, %b
+// CHECK: [[TMP2:%.*]] = sext <8 x i1> [[TMP1:%.*]] to <8 x i16>
+// CHECK: ret <8 x i16> [[TMP2]]
+uint16x8_t test_vcgeq_f16(float16x8_t a, float16x8_t b) {
+ return vcgeq_f16(a, b);
+}
+
+// CHECK-LABEL: test_vcgt_f16
+// CHECK: [[TMP1:%.*]] = fcmp ogt <4 x half> %a, %b
+// CHECK: [[TMP2:%.*]] = sext <4 x i1> [[TMP1]] to <4 x i16>
+// CHECK: ret <4 x i16> [[TMP2]]
+uint16x4_t test_vcgt_f16(float16x4_t a, float16x4_t b) {
+ return vcgt_f16(a, b);
+}
+
+// CHECK-LABEL: test_vcgtq_f16
+// CHECK: [[TMP1:%.*]] = fcmp ogt <8 x half> %a, %b
+// CHECK: [[TMP2:%.*]] = sext <8 x i1> [[TMP1:%.*]] to <8 x i16>
+// CHECK: ret <8 x i16> [[TMP2]]
+uint16x8_t test_vcgtq_f16(float16x8_t a, float16x8_t b) {
+ return vcgtq_f16(a, b);
+}
+
+// CHECK-LABEL: test_vcle_f16
+// CHECK: [[TMP1:%.*]] = fcmp ole <4 x half> %a, %b
+// CHECK: [[TMP2:%.*]] = sext <4 x i1> [[TMP1]] to <4 x i16>
+// CHECK: ret <4 x i16> [[TMP2]]
+uint16x4_t test_vcle_f16(float16x4_t a, float16x4_t b) {
+ return vcle_f16(a, b);
+}
+
+// CHECK-LABEL: test_vcleq_f16
+// CHECK: [[TMP1:%.*]] = fcmp ole <8 x half> %a, %b
+// CHECK: [[TMP2:%.*]] = sext <8 x i1> [[TMP1:%.*]] to <8 x i16>
+// CHECK: ret <8 x i16> [[TMP2]]
+uint16x8_t test_vcleq_f16(float16x8_t a, float16x8_t b) {
+ return vcleq_f16(a, b);
+}
+
+// CHECK-LABEL: test_vclt_f16
+// CHECK: [[TMP1:%.*]] = fcmp olt <4 x half> %a, %b
+// CHECK: [[TMP2:%.*]] = sext <4 x i1> [[TMP1]] to <4 x i16>
+// CHECK: ret <4 x i16> [[TMP2]]
+uint16x4_t test_vclt_f16(float16x4_t a, float16x4_t b) {
+ return vclt_f16(a, b);
+}
+
+// CHECK-LABEL: test_vcltq_f16
+// CHECK: [[TMP1:%.*]] = fcmp olt <8 x half> %a, %b
+// CHECK: [[TMP2:%.*]] = sext <8 x i1> [[TMP1:%.*]] to <8 x i16>
+// CHECK: ret <8 x i16> [[TMP2]]
+uint16x8_t test_vcltq_f16(float16x8_t a, float16x8_t b) {
+ return vcltq_f16(a, b);
+}
+
+// CHECK-LABEL: test_vcvt_n_f16_s16
+// CHECK: [[CVT:%.*]] = call <4 x half> @llvm.aarch64.neon.vcvtfxs2fp.v4f16.v4i16(<4 x i16> %vcvt_n, i32 2)
+// CHECK: ret <4 x half> [[CVT]]
+float16x4_t test_vcvt_n_f16_s16(int16x4_t a) {
+ return vcvt_n_f16_s16(a, 2);
+}
+
+// CHECK-LABEL: test_vcvtq_n_f16_s16
+// CHECK: [[CVT:%.*]] = call <8 x half> @llvm.aarch64.neon.vcvtfxs2fp.v8f16.v8i16(<8 x i16> %vcvt_n, i32 2)
+// CHECK: ret <8 x half> [[CVT]]
+float16x8_t test_vcvtq_n_f16_s16(int16x8_t a) {
+ return vcvtq_n_f16_s16(a, 2);
+}
+
+// CHECK-LABEL: test_vcvt_n_f16_u16
+// CHECK: [[CVT:%.*]] = call <4 x half> @llvm.aarch64.neon.vcvtfxu2fp.v4f16.v4i16(<4 x i16> %vcvt_n, i32 2)
+// CHECK: ret <4 x half> [[CVT]]
+float16x4_t test_vcvt_n_f16_u16(uint16x4_t a) {
+ return vcvt_n_f16_u16(a, 2);
+}
+
+// CHECK-LABEL: test_vcvtq_n_f16_u16
+// CHECK: [[CVT:%.*]] = call <8 x half> @llvm.aarch64.neon.vcvtfxu2fp.v8f16.v8i16(<8 x i16> %vcvt_n, i32 2)
+// CHECK: ret <8 x half> [[CVT]]
+float16x8_t test_vcvtq_n_f16_u16(uint16x8_t a) {
+ return vcvtq_n_f16_u16(a, 2);
+}
+
+// CHECK-LABEL: test_vcvt_n_s16_f16
+// CHECK: [[CVT:%.*]] = call <4 x i16> @llvm.aarch64.neon.vcvtfp2fxs.v4i16.v4f16(<4 x half> %vcvt_n, i32 2)
+// CHECK: ret <4 x i16> [[CVT]]
+int16x4_t test_vcvt_n_s16_f16(float16x4_t a) {
+ return vcvt_n_s16_f16(a, 2);
+}
+
+// CHECK-LABEL: test_vcvtq_n_s16_f16
+// CHECK: [[CVT:%.*]] = call <8 x i16> @llvm.aarch64.neon.vcvtfp2fxs.v8i16.v8f16(<8 x half> %vcvt_n, i32 2)
+// CHECK: ret <8 x i16> [[CVT]]
+int16x8_t test_vcvtq_n_s16_f16(float16x8_t a) {
+ return vcvtq_n_s16_f16(a, 2);
+}
+
+// CHECK-LABEL: test_vcvt_n_u16_f16
+// CHECK: [[CVT:%.*]] = call <4 x i16> @llvm.aarch64.neon.vcvtfp2fxu.v4i16.v4f16(<4 x half> %vcvt_n, i32 2)
+// CHECK: ret <4 x i16> [[CVT]]
+uint16x4_t test_vcvt_n_u16_f16(float16x4_t a) {
+ return vcvt_n_u16_f16(a, 2);
+}
+
+// CHECK-LABEL: test_vcvtq_n_u16_f16
+// CHECK: [[CVT:%.*]] = call <8 x i16> @llvm.aarch64.neon.vcvtfp2fxu.v8i16.v8f16(<8 x half> %vcvt_n, i32 2)
+// CHECK: ret <8 x i16> [[CVT]]
+uint16x8_t test_vcvtq_n_u16_f16(float16x8_t a) {
+ return vcvtq_n_u16_f16(a, 2);
+}
+
+// CHECK-LABEL: test_vdiv_f16
+// CHECK: [[DIV:%.*]] = fdiv <4 x half> %a, %b
+// CHECK: ret <4 x half> [[DIV]]
+float16x4_t test_vdiv_f16(float16x4_t a, float16x4_t b) {
+ return vdiv_f16(a, b);
+}
+
+// CHECK-LABEL: test_vdivq_f16
+// CHECK: [[DIV:%.*]] = fdiv <8 x half> %a, %b
+// CHECK: ret <8 x half> [[DIV]]
+float16x8_t test_vdivq_f16(float16x8_t a, float16x8_t b) {
+ return vdivq_f16(a, b);
+}
+
+// CHECK-LABEL: test_vmax_f16
+// CHECK: [[MAX:%.*]] = call <4 x half> @llvm.aarch64.neon.fmax.v4f16(<4 x half> %a, <4 x half> %b)
+// CHECK: ret <4 x half> [[MAX]]
+float16x4_t test_vmax_f16(float16x4_t a, float16x4_t b) {
+ return vmax_f16(a, b);
+}
+
+// CHECK-LABEL: test_vmaxq_f16
+// CHECK: [[MAX:%.*]] = call <8 x half> @llvm.aarch64.neon.fmax.v8f16(<8 x half> %a, <8 x half> %b)
+// CHECK: ret <8 x half> [[MAX]]
+float16x8_t test_vmaxq_f16(float16x8_t a, float16x8_t b) {
+ return vmaxq_f16(a, b);
+}
+
+// CHECK-LABEL: test_vmaxnm_f16
+// CHECK: [[MAX:%.*]] = call <4 x half> @llvm.aarch64.neon.fmaxnm.v4f16(<4 x half> %a, <4 x half> %b)
+// CHECK: ret <4 x half> [[MAX]]
+float16x4_t test_vmaxnm_f16(float16x4_t a, float16x4_t b) {
+ return vmaxnm_f16(a, b);
+}
+
+// CHECK-LABEL: test_vmaxnmq_f16
+// CHECK: [[MAX:%.*]] = call <8 x half> @llvm.aarch64.neon.fmaxnm.v8f16(<8 x half> %a, <8 x half> %b)
+// CHECK: ret <8 x half> [[MAX]]
+float16x8_t test_vmaxnmq_f16(float16x8_t a, float16x8_t b) {
+ return vmaxnmq_f16(a, b);
+}
+
+// CHECK-LABEL: test_vmin_f16
+// CHECK: [[MIN:%.*]] = call <4 x half> @llvm.aarch64.neon.fmin.v4f16(<4 x half> %a, <4 x half> %b)
+// CHECK: ret <4 x half> [[MIN]]
+float16x4_t test_vmin_f16(float16x4_t a, float16x4_t b) {
+ return vmin_f16(a, b);
+}
+
+// CHECK-LABEL: test_vminq_f16
+// CHECK: [[MIN:%.*]] = call <8 x half> @llvm.aarch64.neon.fmin.v8f16(<8 x half> %a, <8 x half> %b)
+// CHECK: ret <8 x half> [[MIN]]
+float16x8_t test_vminq_f16(float16x8_t a, float16x8_t b) {
+ return vminq_f16(a, b);
+}
+
+// CHECK-LABEL: test_vminnm_f16
+// CHECK: [[MIN:%.*]] = call <4 x half> @llvm.aarch64.neon.fminnm.v4f16(<4 x half> %a, <4 x half> %b)
+// CHECK: ret <4 x half> [[MIN]]
+float16x4_t test_vminnm_f16(float16x4_t a, float16x4_t b) {
+ return vminnm_f16(a, b);
+}
+
+// CHECK-LABEL: test_vminnmq_f16
+// CHECK: [[MIN:%.*]] = call <8 x half> @llvm.aarch64.neon.fminnm.v8f16(<8 x half> %a, <8 x half> %b)
+// CHECK: ret <8 x half> [[MIN]]
+float16x8_t test_vminnmq_f16(float16x8_t a, float16x8_t b) {
+ return vminnmq_f16(a, b);
+}
+
+// CHECK-LABEL: test_vmul_f16
+// CHECK: [[MUL:%.*]] = fmul <4 x half> %a, %b
+// CHECK: ret <4 x half> [[MUL]]
+float16x4_t test_vmul_f16(float16x4_t a, float16x4_t b) {
+ return vmul_f16(a, b);
+}
+
+// CHECK-LABEL: test_vmulq_f16
+// CHECK: [[MUL:%.*]] = fmul <8 x half> %a, %b
+// CHECK: ret <8 x half> [[MUL]]
+float16x8_t test_vmulq_f16(float16x8_t a, float16x8_t b) {
+ return vmulq_f16(a, b);
+}
+
+// CHECK-LABEL: test_vmulx_f16
+// CHECK: [[MUL:%.*]] = call <4 x half> @llvm.aarch64.neon.fmulx.v4f16(<4 x half> %a, <4 x half> %b)
+// CHECK: ret <4 x half> [[MUL]]
+float16x4_t test_vmulx_f16(float16x4_t a, float16x4_t b) {
+ return vmulx_f16(a, b);
+}
+
+// CHECK-LABEL: test_vmulxq_f16
+// CHECK: [[MUL:%.*]] = call <8 x half> @llvm.aarch64.neon.fmulx.v8f16(<8 x half> %a, <8 x half> %b)
+// CHECK: ret <8 x half> [[MUL]]
+float16x8_t test_vmulxq_f16(float16x8_t a, float16x8_t b) {
+ return vmulxq_f16(a, b);
+}
+
+// CHECK-LABEL: test_vpadd_f16
+// CHECK: [[ADD:%.*]] = call <4 x half> @llvm.aarch64.neon.addp.v4f16(<4 x half> %a, <4 x half> %b)
+// CHECK: ret <4 x half> [[ADD]]
+float16x4_t test_vpadd_f16(float16x4_t a, float16x4_t b) {
+ return vpadd_f16(a, b);
+}
+
+// CHECK-LABEL: test_vpaddq_f16
+// CHECK: [[ADD:%.*]] = call <8 x half> @llvm.aarch64.neon.addp.v8f16(<8 x half> %a, <8 x half> %b)
+// CHECK: ret <8 x half> [[ADD]]
+float16x8_t test_vpaddq_f16(float16x8_t a, float16x8_t b) {
+ return vpaddq_f16(a, b);
+}
+
+// CHECK-LABEL: test_vpmax_f16
+// CHECK: [[MAX:%.*]] = call <4 x half> @llvm.aarch64.neon.fmaxp.v4f16(<4 x half> %a, <4 x half> %b)
+// CHECK: ret <4 x half> [[MAX]]
+float16x4_t test_vpmax_f16(float16x4_t a, float16x4_t b) {
+ return vpmax_f16(a, b);
+}
+
+// CHECK-LABEL: test_vpmaxq_f16
+// CHECK: [[MAX:%.*]] = call <8 x half> @llvm.aarch64.neon.fmaxp.v8f16(<8 x half> %a, <8 x half> %b)
+// CHECK: ret <8 x half> [[MAX]]
+float16x8_t test_vpmaxq_f16(float16x8_t a, float16x8_t b) {
+ return vpmaxq_f16(a, b);
+}
+
+// CHECK-LABEL: test_vpmaxnm_f16
+// CHECK: [[MAX:%.*]] = call <4 x half> @llvm.aarch64.neon.fmaxnmp.v4f16(<4 x half> %a, <4 x half> %b)
+// CHECK: ret <4 x half> [[MAX]]
+float16x4_t test_vpmaxnm_f16(float16x4_t a, float16x4_t b) {
+ return vpmaxnm_f16(a, b);
+}
+
+// CHECK-LABEL: test_vpmaxnmq_f16
+// CHECK: [[MAX:%.*]] = call <8 x half> @llvm.aarch64.neon.fmaxnmp.v8f16(<8 x half> %a, <8 x half> %b)
+// CHECK: ret <8 x half> [[MAX]]
+float16x8_t test_vpmaxnmq_f16(float16x8_t a, float16x8_t b) {
+ return vpmaxnmq_f16(a, b);
+}
+
+// CHECK-LABEL: test_vpmin_f16
+// CHECK: [[MIN:%.*]] = call <4 x half> @llvm.aarch64.neon.fminp.v4f16(<4 x half> %a, <4 x half> %b)
+// CHECK: ret <4 x half> [[MIN]]
+float16x4_t test_vpmin_f16(float16x4_t a, float16x4_t b) {
+ return vpmin_f16(a, b);
+}
+
+// CHECK-LABEL: test_vpminq_f16
+// CHECK: [[MIN:%.*]] = call <8 x half> @llvm.aarch64.neon.fminp.v8f16(<8 x half> %a, <8 x half> %b)
+// CHECK: ret <8 x half> [[MIN]]
+float16x8_t test_vpminq_f16(float16x8_t a, float16x8_t b) {
+ return vpminq_f16(a, b);
+}
+
+// CHECK-LABEL: test_vpminnm_f16
+// CHECK: [[MIN:%.*]] = call <4 x half> @llvm.aarch64.neon.fminnmp.v4f16(<4 x half> %a, <4 x half> %b)
+// CHECK: ret <4 x half> [[MIN]]
+float16x4_t test_vpminnm_f16(float16x4_t a, float16x4_t b) {
+ return vpminnm_f16(a, b);
+}
+
+// CHECK-LABEL: test_vpminnmq_f16
+// CHECK: [[MIN:%.*]] = call <8 x half> @llvm.aarch64.neon.fminnmp.v8f16(<8 x half> %a, <8 x half> %b)
+// CHECK: ret <8 x half> [[MIN]]
+float16x8_t test_vpminnmq_f16(float16x8_t a, float16x8_t b) {
+ return vpminnmq_f16(a, b);
+}
+
+// CHECK-LABEL: test_vrecps_f16
+// CHECK: [[MIN:%.*]] = call <4 x half> @llvm.aarch64.neon.frecps.v4f16(<4 x half> %a, <4 x half> %b)
+// CHECK: ret <4 x half> [[MIN]]
+float16x4_t test_vrecps_f16(float16x4_t a, float16x4_t b) {
+ return vrecps_f16(a, b);
+}
+
+// CHECK-LABEL: test_vrecpsq_f16
+// CHECK: [[MIN:%.*]] = call <8 x half> @llvm.aarch64.neon.frecps.v8f16(<8 x half> %a, <8 x half> %b)
+// CHECK: ret <8 x half> [[MIN]]
+float16x8_t test_vrecpsq_f16(float16x8_t a, float16x8_t b) {
+ return vrecpsq_f16(a, b);
+}
+
+// CHECK-LABEL: test_vrsqrts_f16
+// CHECK: [[MIN:%.*]] = call <4 x half> @llvm.aarch64.neon.frsqrts.v4f16(<4 x half> %a, <4 x half> %b)
+// CHECK: ret <4 x half> [[MIN]]
+float16x4_t test_vrsqrts_f16(float16x4_t a, float16x4_t b) {
+ return vrsqrts_f16(a, b);
+}
+
+// CHECK-LABEL: test_vrsqrtsq_f16
+// CHECK: [[MIN:%.*]] = call <8 x half> @llvm.aarch64.neon.frsqrts.v8f16(<8 x half> %a, <8 x half> %b)
+// CHECK: ret <8 x half> [[MIN]]
+float16x8_t test_vrsqrtsq_f16(float16x8_t a, float16x8_t b) {
+ return vrsqrtsq_f16(a, b);
+}
+
+// CHECK-LABEL: test_vsub_f16
+// CHECK: [[ADD:%.*]] = fsub <4 x half> %a, %b
+// CHECK: ret <4 x half> [[ADD]]
+float16x4_t test_vsub_f16(float16x4_t a, float16x4_t b) {
+ return vsub_f16(a, b);
+}
+
+// CHECK-LABEL: test_vsubq_f16
+// CHECK: [[ADD:%.*]] = fsub <8 x half> %a, %b
+// CHECK: ret <8 x half> [[ADD]]
+float16x8_t test_vsubq_f16(float16x8_t a, float16x8_t b) {
+ return vsubq_f16(a, b);
+}
+
+// CHECK-LABEL: test_vfma_f16
+// CHECK: [[ADD:%.*]] = call <4 x half> @llvm.fma.v4f16(<4 x half> %b, <4 x half> %c, <4 x half> %a)
+// CHECK: ret <4 x half> [[ADD]]
+float16x4_t test_vfma_f16(float16x4_t a, float16x4_t b, float16x4_t c) {
+ return vfma_f16(a, b, c);
+}
+
+// CHECK-LABEL: test_vfmaq_f16
+// CHECK: [[ADD:%.*]] = call <8 x half> @llvm.fma.v8f16(<8 x half> %b, <8 x half> %c, <8 x half> %a)
+// CHECK: ret <8 x half> [[ADD]]
+float16x8_t test_vfmaq_f16(float16x8_t a, float16x8_t b, float16x8_t c) {
+ return vfmaq_f16(a, b, c);
+}
+
+// CHECK-LABEL: test_vfms_f16
+// CHECK: [[SUB:%.*]] = fsub <4 x half> <half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000>, %b
+// CHECK: [[ADD:%.*]] = call <4 x half> @llvm.fma.v4f16(<4 x half> [[SUB]], <4 x half> %c, <4 x half> %a)
+// CHECK: ret <4 x half> [[ADD]]
+float16x4_t test_vfms_f16(float16x4_t a, float16x4_t b, float16x4_t c) {
+ return vfms_f16(a, b, c);
+}
+
+// CHECK-LABEL: test_vfmsq_f16
+// CHECK: [[SUB:%.*]] = fsub <8 x half> <half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000>, %b
+// CHECK: [[ADD:%.*]] = call <8 x half> @llvm.fma.v8f16(<8 x half> [[SUB]], <8 x half> %c, <8 x half> %a)
+// CHECK: ret <8 x half> [[ADD]]
+float16x8_t test_vfmsq_f16(float16x8_t a, float16x8_t b, float16x8_t c) {
+ return vfmsq_f16(a, b, c);
+}
+
+// CHECK-LABEL: test_vfma_lane_f16
+// CHECK: [[TMP0:%.*]] = bitcast <4 x half> %a to <8 x i8>
+// CHECK: [[TMP1:%.*]] = bitcast <4 x half> %b to <8 x i8>
+// CHECK: [[TMP2:%.*]] = bitcast <4 x half> %c to <8 x i8>
+// CHECK: [[TMP3:%.*]] = bitcast <8 x i8> [[TMP2]] to <4 x half>
+// CHECK: [[LANE:%.*]] = shufflevector <4 x half> [[TMP3]], <4 x half> [[TMP3]], <4 x i32> <i32 3, i32 3, i32 3, i32 3>
+// CHECK: [[TMP4:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x half>
+// CHECK: [[TMP5:%.*]] = bitcast <8 x i8> [[TMP0]] to <4 x half>
+// CHECK: [[FMLA:%.*]] = call <4 x half> @llvm.fma.v4f16(<4 x half> [[TMP4]], <4 x half> [[LANE]], <4 x half> [[TMP5]])
+// CHECK: ret <4 x half> [[FMLA]]
+float16x4_t test_vfma_lane_f16(float16x4_t a, float16x4_t b, float16x4_t c) {
+ return vfma_lane_f16(a, b, c, 3);
+}
+
+// CHECK-LABEL: test_vfmaq_lane_f16
+// CHECK: [[TMP0:%.*]] = bitcast <8 x half> %a to <16 x i8>
+// CHECK: [[TMP1:%.*]] = bitcast <8 x half> %b to <16 x i8>
+// CHECK: [[TMP2:%.*]] = bitcast <4 x half> %c to <8 x i8>
+// CHECK: [[TMP3:%.*]] = bitcast <8 x i8> [[TMP2]] to <4 x half>
+// CHECK: [[LANE:%.*]] = shufflevector <4 x half> [[TMP3]], <4 x half> [[TMP3]], <8 x i32> <i32 3, i32 3, i32 3, i32 3, i32 3, i32 3, i32 3, i32 3>
+// CHECK: [[TMP4:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x half>
+// CHECK: [[TMP5:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x half>
+// CHECK: [[FMLA:%.*]] = call <8 x half> @llvm.fma.v8f16(<8 x half> [[TMP4]], <8 x half> [[LANE]], <8 x half> [[TMP5]])
+// CHECK: ret <8 x half> [[FMLA]]
+float16x8_t test_vfmaq_lane_f16(float16x8_t a, float16x8_t b, float16x4_t c) {
+ return vfmaq_lane_f16(a, b, c, 3);
+}
+
+// CHECK-LABEL: test_vfma_laneq_f16
+// CHECK: [[TMP0:%.*]] = bitcast <4 x half> %a to <8 x i8>
+// CHECK: [[TMP1:%.*]] = bitcast <4 x half> %b to <8 x i8>
+// CHECK: [[TMP2:%.*]] = bitcast <8 x half> %c to <16 x i8>
+// CHECK: [[TMP3:%.*]] = bitcast <8 x i8> [[TMP0]] to <4 x half>
+// CHECK: [[TMP4:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x half>
+// CHECK: [[TMP5:%.*]] = bitcast <16 x i8> [[TMP2]] to <8 x half>
+// CHECK: [[LANE:%.*]] = shufflevector <8 x half> [[TMP5]], <8 x half> [[TMP5]], <4 x i32> <i32 7, i32 7, i32 7, i32 7>
+// CHECK: [[FMLA:%.*]] = call <4 x half> @llvm.fma.v4f16(<4 x half> [[LANE]], <4 x half> [[TMP4]], <4 x half> [[TMP3]])
+// CHECK: ret <4 x half> [[FMLA]]
+float16x4_t test_vfma_laneq_f16(float16x4_t a, float16x4_t b, float16x8_t c) {
+ return vfma_laneq_f16(a, b, c, 7);
+}
+
+// CHECK-LABEL: test_vfmaq_laneq_f16
+// CHECK: [[TMP0:%.*]] = bitcast <8 x half> %a to <16 x i8>
+// CHECK: [[TMP1:%.*]] = bitcast <8 x half> %b to <16 x i8>
+// CHECK: [[TMP2:%.*]] = bitcast <8 x half> %c to <16 x i8>
+// CHECK: [[TMP3:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x half>
+// CHECK: [[TMP4:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x half>
+// CHECK: [[TMP5:%.*]] = bitcast <16 x i8> [[TMP2]] to <8 x half>
+// CHECK: [[LANE:%.*]] = shufflevector <8 x half> [[TMP5]], <8 x half> [[TMP5]], <8 x i32> <i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7>
+// CHECK: [[FMLA:%.*]] = call <8 x half> @llvm.fma.v8f16(<8 x half> [[LANE]], <8 x half> [[TMP4]], <8 x half> [[TMP3]])
+// CHECK: ret <8 x half> [[FMLA]]
+float16x8_t test_vfmaq_laneq_f16(float16x8_t a, float16x8_t b, float16x8_t c) {
+ return vfmaq_laneq_f16(a, b, c, 7);
+}
+
+// CHECK-LABEL: test_vfma_n_f16
+// CHECK: [[TMP0:%.*]] = insertelement <4 x half> undef, half %c, i32 0
+// CHECK: [[TMP1:%.*]] = insertelement <4 x half> [[TMP0]], half %c, i32 1
+// CHECK: [[TMP2:%.*]] = insertelement <4 x half> [[TMP1]], half %c, i32 2
+// CHECK: [[TMP3:%.*]] = insertelement <4 x half> [[TMP2]], half %c, i32 3
+// CHECK: [[FMA:%.*]] = call <4 x half> @llvm.fma.v4f16(<4 x half> %b, <4 x half> [[TMP3]], <4 x half> %a)
+// CHECK: ret <4 x half> [[FMA]]
+float16x4_t test_vfma_n_f16(float16x4_t a, float16x4_t b, float16_t c) {
+ return vfma_n_f16(a, b, c);
+}
+
+// CHECK-LABEL: test_vfmaq_n_f16
+// CHECK: [[TMP0:%.*]] = insertelement <8 x half> undef, half %c, i32 0
+// CHECK: [[TMP1:%.*]] = insertelement <8 x half> [[TMP0]], half %c, i32 1
+// CHECK: [[TMP2:%.*]] = insertelement <8 x half> [[TMP1]], half %c, i32 2
+// CHECK: [[TMP3:%.*]] = insertelement <8 x half> [[TMP2]], half %c, i32 3
+// CHECK: [[TMP4:%.*]] = insertelement <8 x half> [[TMP3]], half %c, i32 4
+// CHECK: [[TMP5:%.*]] = insertelement <8 x half> [[TMP4]], half %c, i32 5
+// CHECK: [[TMP6:%.*]] = insertelement <8 x half> [[TMP5]], half %c, i32 6
+// CHECK: [[TMP7:%.*]] = insertelement <8 x half> [[TMP6]], half %c, i32 7
+// CHECK: [[FMA:%.*]] = call <8 x half> @llvm.fma.v8f16(<8 x half> %b, <8 x half> [[TMP7]], <8 x half> %a)
+// CHECK: ret <8 x half> [[FMA]]
+float16x8_t test_vfmaq_n_f16(float16x8_t a, float16x8_t b, float16_t c) {
+ return vfmaq_n_f16(a, b, c);
+}
+
+// CHECK-LABEL: test_vfmah_lane_f16
+// CHECK: [[TMP0:%.*]] = bitcast <4 x half> %c to <8 x i8>
+// CHECK: [[TMP1:%.*]] = bitcast <8 x i8> [[TMP0]] to <4 x half>
+// CHECK: [[EXTR:%.*]] = extractelement <4 x half> [[TMP1]], i32 3
+// CHECK: [[FMA:%.*]] = call half @llvm.fma.f16(half %b, half [[EXTR]], half %a)
+// CHECK: ret half [[FMA]]
+float16_t test_vfmah_lane_f16(float16_t a, float16_t b, float16x4_t c) {
+ return vfmah_lane_f16(a, b, c, 3);
+}
+
+// CHECK-LABEL: test_vfmah_laneq_f16
+// CHECK: [[TMP0:%.*]] = bitcast <8 x half> %c to <16 x i8>
+// CHECK: [[TMP1:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x half>
+// CHECK: [[EXTR:%.*]] = extractelement <8 x half> [[TMP1]], i32 7
+// CHECK: [[FMA:%.*]] = call half @llvm.fma.f16(half %b, half [[EXTR]], half %a)
+// CHECK: ret half [[FMA]]
+float16_t test_vfmah_laneq_f16(float16_t a, float16_t b, float16x8_t c) {
+ return vfmah_laneq_f16(a, b, c, 7);
+}
+
+// CHECK-LABEL: test_vfms_lane_f16
+// CHECK: [[SUB:%.*]] = fsub <4 x half> <half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000>, %b
+// CHECK: [[TMP0:%.*]] = bitcast <4 x half> %a to <8 x i8>
+// CHECK: [[TMP1:%.*]] = bitcast <4 x half> [[SUB]] to <8 x i8>
+// CHECK: [[TMP2:%.*]] = bitcast <4 x half> %c to <8 x i8>
+// CHECK: [[TMP3:%.*]] = bitcast <8 x i8> [[TMP2]] to <4 x half>
+// CHECK: [[LANE:%.*]] = shufflevector <4 x half> [[TMP3]], <4 x half> [[TMP3]], <4 x i32> <i32 3, i32 3, i32 3, i32 3>
+// CHECK: [[TMP4:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x half>
+// CHECK: [[TMP5:%.*]] = bitcast <8 x i8> [[TMP0]] to <4 x half>
+// CHECK: [[FMA:%.*]] = call <4 x half> @llvm.fma.v4f16(<4 x half> [[TMP4]], <4 x half> [[LANE]], <4 x half> [[TMP5]])
+// CHECK: ret <4 x half> [[FMA]]
+float16x4_t test_vfms_lane_f16(float16x4_t a, float16x4_t b, float16x4_t c) {
+ return vfms_lane_f16(a, b, c, 3);
+}
+
+// CHECK-LABEL: test_vfmsq_lane_f16
+// CHECK: [[SUB:%.*]] = fsub <8 x half> <half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000>, %b
+// CHECK: [[TMP0:%.*]] = bitcast <8 x half> %a to <16 x i8>
+// CHECK: [[TMP1:%.*]] = bitcast <8 x half> [[SUB]] to <16 x i8>
+// CHECK: [[TMP2:%.*]] = bitcast <4 x half> %c to <8 x i8>
+// CHECK: [[TMP3:%.*]] = bitcast <8 x i8> [[TMP2]] to <4 x half>
+// CHECK: [[LANE:%.*]] = shufflevector <4 x half> [[TMP3]], <4 x half> [[TMP3]], <8 x i32> <i32 3, i32 3, i32 3, i32 3, i32 3, i32 3, i32 3, i32 3>
+// CHECK: [[TMP4:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x half>
+// CHECK: [[TMP5:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x half>
+// CHECK: [[FMLA:%.*]] = call <8 x half> @llvm.fma.v8f16(<8 x half> [[TMP4]], <8 x half> [[LANE]], <8 x half> [[TMP5]])
+// CHECK: ret <8 x half> [[FMLA]]
+float16x8_t test_vfmsq_lane_f16(float16x8_t a, float16x8_t b, float16x4_t c) {
+ return vfmsq_lane_f16(a, b, c, 3);
+}
+
+// CHECK-LABEL: test_vfms_laneq_f16
+// CHECK: [[SUB:%.*]] = fsub <4 x half> <half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000>, %b
+// CHECK: [[TMP0:%.*]] = bitcast <4 x half> %a to <8 x i8>
+// CHECK: [[TMP1:%.*]] = bitcast <4 x half> [[SUB]] to <8 x i8>
+// CHECK: [[TMP2:%.*]] = bitcast <8 x half> %c to <16 x i8>
+// CHECK: [[TMP3:%.*]] = bitcast <8 x i8> [[TMP0]] to <4 x half>
+// CHECK: [[TMP4:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x half>
+// CHECK: [[TMP5:%.*]] = bitcast <16 x i8> [[TMP2]] to <8 x half>
+// CHECK: [[LANE:%.*]] = shufflevector <8 x half> [[TMP5]], <8 x half> [[TMP5]], <4 x i32> <i32 7, i32 7, i32 7, i32 7>
+// CHECK: [[FMLA:%.*]] = call <4 x half> @llvm.fma.v4f16(<4 x half> [[LANE]], <4 x half> [[TMP4]], <4 x half> [[TMP3]])
+// CHECK: ret <4 x half> [[FMLA]]
+float16x4_t test_vfms_laneq_f16(float16x4_t a, float16x4_t b, float16x8_t c) {
+ return vfms_laneq_f16(a, b, c, 7);
+}
+
+// CHECK-LABEL: test_vfmsq_laneq_f16
+// CHECK: [[SUB:%.*]] = fsub <8 x half> <half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000>, %b
+// CHECK: [[TMP0:%.*]] = bitcast <8 x half> %a to <16 x i8>
+// CHECK: [[TMP1:%.*]] = bitcast <8 x half> [[SUB]] to <16 x i8>
+// CHECK: [[TMP2:%.*]] = bitcast <8 x half> %c to <16 x i8>
+// CHECK: [[TMP3:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x half>
+// CHECK: [[TMP4:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x half>
+// CHECK: [[TMP5:%.*]] = bitcast <16 x i8> [[TMP2]] to <8 x half>
+// CHECK: [[LANE:%.*]] = shufflevector <8 x half> [[TMP5]], <8 x half> [[TMP5]], <8 x i32> <i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7>
+// CHECK: [[FMLA:%.*]] = call <8 x half> @llvm.fma.v8f16(<8 x half> [[LANE]], <8 x half> [[TMP4]], <8 x half> [[TMP3]])
+// CHECK: ret <8 x half> [[FMLA]]
+float16x8_t test_vfmsq_laneq_f16(float16x8_t a, float16x8_t b, float16x8_t c) {
+ return vfmsq_laneq_f16(a, b, c, 7);
+}
+
+// CHECK-LABEL: test_vfms_n_f16
+// CHECK: [[SUB:%.*]] = fsub <4 x half> <half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000>, %b
+// CHECK: [[TMP0:%.*]] = insertelement <4 x half> undef, half %c, i32 0
+// CHECK: [[TMP1:%.*]] = insertelement <4 x half> [[TMP0]], half %c, i32 1
+// CHECK: [[TMP2:%.*]] = insertelement <4 x half> [[TMP1]], half %c, i32 2
+// CHECK: [[TMP3:%.*]] = insertelement <4 x half> [[TMP2]], half %c, i32 3
+// CHECK: [[FMA:%.*]] = call <4 x half> @llvm.fma.v4f16(<4 x half> [[SUB]], <4 x half> [[TMP3]], <4 x half> %a)
+// CHECK: ret <4 x half> [[FMA]]
+float16x4_t test_vfms_n_f16(float16x4_t a, float16x4_t b, float16_t c) {
+ return vfms_n_f16(a, b, c);
+}
+
+// CHECK-LABEL: test_vfmsq_n_f16
+// CHECK: [[SUB:%.*]] = fsub <8 x half> <half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000>, %b
+// CHECK: [[TMP0:%.*]] = insertelement <8 x half> undef, half %c, i32 0
+// CHECK: [[TMP1:%.*]] = insertelement <8 x half> [[TMP0]], half %c, i32 1
+// CHECK: [[TMP2:%.*]] = insertelement <8 x half> [[TMP1]], half %c, i32 2
+// CHECK: [[TMP3:%.*]] = insertelement <8 x half> [[TMP2]], half %c, i32 3
+// CHECK: [[TMP4:%.*]] = insertelement <8 x half> [[TMP3]], half %c, i32 4
+// CHECK: [[TMP5:%.*]] = insertelement <8 x half> [[TMP4]], half %c, i32 5
+// CHECK: [[TMP6:%.*]] = insertelement <8 x half> [[TMP5]], half %c, i32 6
+// CHECK: [[TMP7:%.*]] = insertelement <8 x half> [[TMP6]], half %c, i32 7
+// CHECK: [[FMA:%.*]] = call <8 x half> @llvm.fma.v8f16(<8 x half> [[SUB]], <8 x half> [[TMP7]], <8 x half> %a)
+// CHECK: ret <8 x half> [[FMA]]
+float16x8_t test_vfmsq_n_f16(float16x8_t a, float16x8_t b, float16_t c) {
+ return vfmsq_n_f16(a, b, c);
+}
+
+// CHECK-LABEL: test_vfmsh_lane_f16
+// CHECK: [[TMP0:%.*]] = fpext half %b to float
+// CHECK: [[TMP1:%.*]] = fsub float -0.000000e+00, [[TMP0]]
+// CHECK: [[SUB:%.*]] = fptrunc float [[TMP1]] to half
+// CHECK: [[TMP2:%.*]] = bitcast <4 x half> %c to <8 x i8>
+// CHECK: [[TMP3:%.*]] = bitcast <8 x i8> [[TMP2]] to <4 x half>
+// CHECK: [[EXTR:%.*]] = extractelement <4 x half> [[TMP3]], i32 3
+// CHECK: [[FMA:%.*]] = call half @llvm.fma.f16(half [[SUB]], half [[EXTR]], half %a)
+// CHECK: ret half [[FMA]]
+float16_t test_vfmsh_lane_f16(float16_t a, float16_t b, float16x4_t c) {
+ return vfmsh_lane_f16(a, b, c, 3);
+}
+
+// CHECK-LABEL: test_vfmsh_laneq_f16
+// CHECK: [[TMP0:%.*]] = fpext half %b to float
+// CHECK: [[TMP1:%.*]] = fsub float -0.000000e+00, [[TMP0]]
+// CHECK: [[SUB:%.*]] = fptrunc float [[TMP1]] to half
+// CHECK: [[TMP2:%.*]] = bitcast <8 x half> %c to <16 x i8>
+// CHECK: [[TMP3:%.*]] = bitcast <16 x i8> [[TMP2]] to <8 x half>
+// CHECK: [[EXTR:%.*]] = extractelement <8 x half> [[TMP3]], i32 7
+// CHECK: [[FMA:%.*]] = call half @llvm.fma.f16(half [[SUB]], half [[EXTR]], half %a)
+// CHECK: ret half [[FMA]]
+float16_t test_vfmsh_laneq_f16(float16_t a, float16_t b, float16x8_t c) {
+ return vfmsh_laneq_f16(a, b, c, 7);
+}
+
+// CHECK-LABEL: test_vmul_lane_f16
+// CHECK: [[TMP0:%.*]] = shufflevector <4 x half> %b, <4 x half> %b, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
+// CHECK: [[MUL:%.*]] = fmul <4 x half> %a, [[TMP0]]
+// CHECK: ret <4 x half> [[MUL]]
+float16x4_t test_vmul_lane_f16(float16x4_t a, float16x4_t b) {
+ return vmul_lane_f16(a, b, 3);
+}
+
+// CHECK-LABEL: test_vmulq_lane_f16
+// CHECK: [[TMP0:%.*]] = shufflevector <4 x half> %b, <4 x half> %b, <8 x i32> <i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7>
+// CHECK: [[MUL:%.*]] = fmul <8 x half> %a, [[TMP0]]
+// CHECK: ret <8 x half> [[MUL]]
+float16x8_t test_vmulq_lane_f16(float16x8_t a, float16x4_t b) {
+ return vmulq_lane_f16(a, b, 7);
+}
+
+// CHECK-LABEL: test_vmul_laneq_f16
+// CHECK: [[TMP0:%.*]] = shufflevector <8 x half> %b, <8 x half> %b, <4 x i32> <i32 7, i32 7, i32 7, i32 7>
+// CHECK: [[MUL:%.*]] = fmul <4 x half> %a, [[TMP0]]
+// CHECK: ret <4 x half> [[MUL]]
+float16x4_t test_vmul_laneq_f16(float16x4_t a, float16x8_t b) {
+ return vmul_laneq_f16(a, b, 7);
+}
+
+// CHECK-LABEL: test_vmulq_laneq_f16
+// CHECK: [[TMP0:%.*]] = shufflevector <8 x half> %b, <8 x half> %b, <8 x i32> <i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7>
+// CHECK: [[MUL:%.*]] = fmul <8 x half> %a, [[TMP0]]
+// CHECK: ret <8 x half> [[MUL]]
+float16x8_t test_vmulq_laneq_f16(float16x8_t a, float16x8_t b) {
+ return vmulq_laneq_f16(a, b, 7);
+}
+
+// CHECK-LABEL: test_vmul_n_f16
+// CHECK: [[TMP0:%.*]] = insertelement <4 x half> undef, half %b, i32 0
+// CHECK: [[TMP1:%.*]] = insertelement <4 x half> [[TMP0]], half %b, i32 1
+// CHECK: [[TMP2:%.*]] = insertelement <4 x half> [[TMP1]], half %b, i32 2
+// CHECK: [[TMP3:%.*]] = insertelement <4 x half> [[TMP2]], half %b, i32 3
+// CHECK: [[MUL:%.*]] = fmul <4 x half> %a, [[TMP3]]
+// CHECK: ret <4 x half> [[MUL]]
+float16x4_t test_vmul_n_f16(float16x4_t a, float16_t b) {
+ return vmul_n_f16(a, b);
+}
+
+// CHECK-LABEL: test_vmulq_n_f16
+// CHECK: [[TMP0:%.*]] = insertelement <8 x half> undef, half %b, i32 0
+// CHECK: [[TMP1:%.*]] = insertelement <8 x half> [[TMP0]], half %b, i32 1
+// CHECK: [[TMP2:%.*]] = insertelement <8 x half> [[TMP1]], half %b, i32 2
+// CHECK: [[TMP3:%.*]] = insertelement <8 x half> [[TMP2]], half %b, i32 3
+// CHECK: [[TMP4:%.*]] = insertelement <8 x half> [[TMP3]], half %b, i32 4
+// CHECK: [[TMP5:%.*]] = insertelement <8 x half> [[TMP4]], half %b, i32 5
+// CHECK: [[TMP6:%.*]] = insertelement <8 x half> [[TMP5]], half %b, i32 6
+// CHECK: [[TMP7:%.*]] = insertelement <8 x half> [[TMP6]], half %b, i32 7
+// CHECK: [[MUL:%.*]] = fmul <8 x half> %a, [[TMP7]]
+// CHECK: ret <8 x half> [[MUL]]
+float16x8_t test_vmulq_n_f16(float16x8_t a, float16_t b) {
+ return vmulq_n_f16(a, b);
+}
+
+// FIXME: Fix it when fp16 non-storage-only type becomes available.
+// CHECK-LABEL: test_vmulh_lane_f16
+// CHECK: [[CONV0:%.*]] = fpext half %a to float
+// CHECK: [[CONV1:%.*]] = fpext half %{{.*}} to float
+// CHECK: [[MUL:%.*]] = fmul float [[CONV0:%.*]], [[CONV0:%.*]]
+// CHECK: [[CONV3:%.*]] = fptrunc float %mul to half
+// CHECK: ret half [[CONV3:%.*]]
+float16_t test_vmulh_lane_f16(float16_t a, float16x4_t b) {
+ return vmulh_lane_f16(a, b, 3);
+}
+
+// CHECK-LABEL: test_vmulh_laneq_f16
+// CHECK: [[CONV0:%.*]] = fpext half %a to float
+// CHECK: [[CONV1:%.*]] = fpext half %{{.*}} to float
+// CHECK: [[MUL:%.*]] = fmul float [[CONV0:%.*]], [[CONV0:%.*]]
+// CHECK: [[CONV3:%.*]] = fptrunc float %mul to half
+// CHECK: ret half [[CONV3:%.*]]
+float16_t test_vmulh_laneq_f16(float16_t a, float16x8_t b) {
+ return vmulh_laneq_f16(a, b, 7);
+}
+
+// CHECK-LABEL: test_vmulx_lane_f16
+// CHECK: [[TMP0:%.*]] = shufflevector <4 x half> %b, <4 x half> %b, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
+// CHECK: [[MUL:%.*]] = call <4 x half> @llvm.aarch64.neon.fmulx.v4f16(<4 x half> %a, <4 x half> [[TMP0]])
+// CHECK: ret <4 x half> [[MUL]]
+float16x4_t test_vmulx_lane_f16(float16x4_t a, float16x4_t b) {
+ return vmulx_lane_f16(a, b, 3);
+}
+
+// CHECK-LABEL: test_vmulxq_lane_f16
+// CHECK: [[TMP0:%.*]] = shufflevector <4 x half> %b, <4 x half> %b, <8 x i32> <i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7>
+// CHECK: [[MUL:%.*]] = call <8 x half> @llvm.aarch64.neon.fmulx.v8f16(<8 x half> %a, <8 x half> [[TMP0]])
+// CHECK: ret <8 x half> [[MUL]]
+float16x8_t test_vmulxq_lane_f16(float16x8_t a, float16x4_t b) {
+ return vmulxq_lane_f16(a, b, 7);
+}
+
+// CHECK-LABEL: test_vmulx_laneq_f16
+// CHECK: [[TMP0:%.*]] = shufflevector <8 x half> %b, <8 x half> %b, <4 x i32> <i32 7, i32 7, i32 7, i32 7>
+// CHECK: [[MUL:%.*]] = call <4 x half> @llvm.aarch64.neon.fmulx.v4f16(<4 x half> %a, <4 x half> [[TMP0]])
+// CHECK: ret <4 x half> [[MUL]]
+float16x4_t test_vmulx_laneq_f16(float16x4_t a, float16x8_t b) {
+ return vmulx_laneq_f16(a, b, 7);
+}
+
+// CHECK-LABEL: test_vmulxq_laneq_f16
+// CHECK: [[TMP0:%.*]] = shufflevector <8 x half> %b, <8 x half> %b, <8 x i32> <i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7>
+// CHECK: [[MUL:%.*]] = call <8 x half> @llvm.aarch64.neon.fmulx.v8f16(<8 x half> %a, <8 x half> [[TMP0]])
+// CHECK: ret <8 x half> [[MUL]]
+float16x8_t test_vmulxq_laneq_f16(float16x8_t a, float16x8_t b) {
+ return vmulxq_laneq_f16(a, b, 7);
+}
+
+// CHECK-LABEL: test_vmulx_n_f16
+// CHECK: [[TMP0:%.*]] = insertelement <4 x half> undef, half %b, i32 0
+// CHECK: [[TMP1:%.*]] = insertelement <4 x half> [[TMP0]], half %b, i32 1
+// CHECK: [[TMP2:%.*]] = insertelement <4 x half> [[TMP1]], half %b, i32 2
+// CHECK: [[TMP3:%.*]] = insertelement <4 x half> [[TMP2]], half %b, i32 3
+// CHECK: [[MUL:%.*]] = call <4 x half> @llvm.aarch64.neon.fmulx.v4f16(<4 x half> %a, <4 x half> [[TMP3]])
+// CHECK: ret <4 x half> [[MUL]]
+float16x4_t test_vmulx_n_f16(float16x4_t a, float16_t b) {
+ return vmulx_n_f16(a, b);
+}
+
+// CHECK-LABEL: test_vmulxq_n_f16
+// CHECK: [[TMP0:%.*]] = insertelement <8 x half> undef, half %b, i32 0
+// CHECK: [[TMP1:%.*]] = insertelement <8 x half> [[TMP0]], half %b, i32 1
+// CHECK: [[TMP2:%.*]] = insertelement <8 x half> [[TMP1]], half %b, i32 2
+// CHECK: [[TMP3:%.*]] = insertelement <8 x half> [[TMP2]], half %b, i32 3
+// CHECK: [[TMP4:%.*]] = insertelement <8 x half> [[TMP3]], half %b, i32 4
+// CHECK: [[TMP5:%.*]] = insertelement <8 x half> [[TMP4]], half %b, i32 5
+// CHECK: [[TMP6:%.*]] = insertelement <8 x half> [[TMP5]], half %b, i32 6
+// CHECK: [[TMP7:%.*]] = insertelement <8 x half> [[TMP6]], half %b, i32 7
+// CHECK: [[MUL:%.*]] = call <8 x half> @llvm.aarch64.neon.fmulx.v8f16(<8 x half> %a, <8 x half> [[TMP7]])
+// CHECK: ret <8 x half> [[MUL]]
+float16x8_t test_vmulxq_n_f16(float16x8_t a, float16_t b) {
+ return vmulxq_n_f16(a, b);
+}
+
+/* TODO: Not implemented yet (needs scalar intrinsic from arm_fp16.h)
+// CCHECK-LABEL: test_vmulxh_lane_f16
+// CCHECK: [[CONV0:%.*]] = fpext half %a to float
+// CCHECK: [[CONV1:%.*]] = fpext half %{{.*}} to float
+// CCHECK: [[MUL:%.*]] = fmul float [[CONV0:%.*]], [[CONV0:%.*]]
+// CCHECK: [[CONV3:%.*]] = fptrunc float %mul to half
+// CCHECK: ret half [[CONV3:%.*]]
+float16_t test_vmulxh_lane_f16(float16_t a, float16x4_t b) {
+ return vmulxh_lane_f16(a, b, 3);
+}
+
+// CCHECK-LABEL: test_vmulxh_laneq_f16
+// CCHECK: [[CONV0:%.*]] = fpext half %a to float
+// CCHECK: [[CONV1:%.*]] = fpext half %{{.*}} to float
+// CCHECK: [[MUL:%.*]] = fmul float [[CONV0:%.*]], [[CONV0:%.*]]
+// CCHECK: [[CONV3:%.*]] = fptrunc float %mul to half
+// CCHECK: ret half [[CONV3:%.*]]
+float16_t test_vmulxh_laneq_f16(float16_t a, float16x8_t b) {
+ return vmulxh_laneq_f16(a, b, 7);
+}
+*/
+
+// CHECK-LABEL: test_vmaxv_f16
+// CHECK: [[TMP0:%.*]] = bitcast <4 x half> %a to <8 x i8>
+// CHECK: [[TMP1:%.*]] = bitcast <8 x i8> [[TMP0]] to <4 x half>
+// CHECK: [[MAX:%.*]] = call half @llvm.aarch64.neon.fmaxv.f16.v4f16(<4 x half> [[TMP1]])
+// CHECK: ret half [[MAX]]
+float16_t test_vmaxv_f16(float16x4_t a) {
+ return vmaxv_f16(a);
+}
+
+// CHECK-LABEL: test_vmaxvq_f16
+// CHECK: [[TMP0:%.*]] = bitcast <8 x half> %a to <16 x i8>
+// CHECK: [[TMP1:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x half>
+// CHECK: [[MAX:%.*]] = call half @llvm.aarch64.neon.fmaxv.f16.v8f16(<8 x half> [[TMP1]])
+// CHECK: ret half [[MAX]]
+float16_t test_vmaxvq_f16(float16x8_t a) {
+ return vmaxvq_f16(a);
+}
+
+// CHECK-LABEL: test_vminv_f16
+// CHECK: [[TMP0:%.*]] = bitcast <4 x half> %a to <8 x i8>
+// CHECK: [[TMP1:%.*]] = bitcast <8 x i8> [[TMP0]] to <4 x half>
+// CHECK: [[MAX:%.*]] = call half @llvm.aarch64.neon.fminv.f16.v4f16(<4 x half> [[TMP1]])
+// CHECK: ret half [[MAX]]
+float16_t test_vminv_f16(float16x4_t a) {
+ return vminv_f16(a);
+}
+
+// CHECK-LABEL: test_vminvq_f16
+// CHECK: [[TMP0:%.*]] = bitcast <8 x half> %a to <16 x i8>
+// CHECK: [[TMP1:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x half>
+// CHECK: [[MAX:%.*]] = call half @llvm.aarch64.neon.fminv.f16.v8f16(<8 x half> [[TMP1]])
+// CHECK: ret half [[MAX]]
+float16_t test_vminvq_f16(float16x8_t a) {
+ return vminvq_f16(a);
+}
+
+// CHECK-LABEL: test_vmaxnmv_f16
+// CHECK: [[TMP0:%.*]] = bitcast <4 x half> %a to <8 x i8>
+// CHECK: [[TMP1:%.*]] = bitcast <8 x i8> [[TMP0]] to <4 x half>
+// CHECK: [[MAX:%.*]] = call half @llvm.aarch64.neon.fmaxnmv.f16.v4f16(<4 x half> [[TMP1]])
+// CHECK: ret half [[MAX]]
+float16_t test_vmaxnmv_f16(float16x4_t a) {
+ return vmaxnmv_f16(a);
+}
+
+// CHECK-LABEL: test_vmaxnmvq_f16
+// CHECK: [[TMP0:%.*]] = bitcast <8 x half> %a to <16 x i8>
+// CHECK: [[TMP1:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x half>
+// CHECK: [[MAX:%.*]] = call half @llvm.aarch64.neon.fmaxnmv.f16.v8f16(<8 x half> [[TMP1]])
+// CHECK: ret half [[MAX]]
+float16_t test_vmaxnmvq_f16(float16x8_t a) {
+ return vmaxnmvq_f16(a);
+}
+
+// CHECK-LABEL: test_vminnmv_f16
+// CHECK: [[TMP0:%.*]] = bitcast <4 x half> %a to <8 x i8>
+// CHECK: [[TMP1:%.*]] = bitcast <8 x i8> [[TMP0]] to <4 x half>
+// CHECK: [[MAX:%.*]] = call half @llvm.aarch64.neon.fminnmv.f16.v4f16(<4 x half> [[TMP1]])
+// CHECK: ret half [[MAX]]
+float16_t test_vminnmv_f16(float16x4_t a) {
+ return vminnmv_f16(a);
+}
+
+// CHECK-LABEL: test_vminnmvq_f16
+// CHECK: [[TMP0:%.*]] = bitcast <8 x half> %a to <16 x i8>
+// CHECK: [[TMP1:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x half>
+// CHECK: [[MAX:%.*]] = call half @llvm.aarch64.neon.fminnmv.f16.v8f16(<8 x half> [[TMP1]])
+// CHECK: ret half [[MAX]]
+float16_t test_vminnmvq_f16(float16x8_t a) {
+ return vminnmvq_f16(a);
+}
+
+// CHECK-LABEL: test_vbsl_f16
+// CHECK: [[TMP0:%.*]] = bitcast <4 x half> %b to <8 x i8>
+// CHECK: [[TMP1:%.*]] = bitcast <4 x half> %c to <8 x i8>
+// CHECK: [[TMP2:%.*]] = bitcast <8 x i8> [[TMP0]] to <4 x i16>
+// CHECK: [[TMP3:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x i16>
+// CHECK: [[TMP4:%.*]] = and <4 x i16> %a, [[TMP2]]
+// CHECK: [[TMP5:%.*]] = xor <4 x i16> %a, <i16 -1, i16 -1, i16 -1, i16 -1>
+// CHECK: [[TMP6:%.*]] = and <4 x i16> [[TMP5]], [[TMP3]]
+// CHECK: [[TMP7:%.*]] = or <4 x i16> [[TMP4]], [[TMP6]]
+// CHECK: [[TMP8:%.*]] = bitcast <4 x i16> [[TMP7]] to <4 x half>
+// CHECK: ret <4 x half> [[TMP8]]
+float16x4_t test_vbsl_f16(uint16x4_t a, float16x4_t b, float16x4_t c) {
+ return vbsl_f16(a, b, c);
+}
+
+// CHECK-LABEL: test_vbslq_f16
+// CHECK: [[TMP0:%.*]] = bitcast <8 x half> %b to <16 x i8>
+// CHECK: [[TMP1:%.*]] = bitcast <8 x half> %c to <16 x i8>
+// CHECK: [[TMP2:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x i16>
+// CHECK: [[TMP3:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x i16>
+// CHECK: [[TMP4:%.*]] = and <8 x i16> %a, [[TMP2]]
+// CHECK: [[TMP5:%.*]] = xor <8 x i16> %a, <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1>
+// CHECK: [[TMP6:%.*]] = and <8 x i16> [[TMP5]], [[TMP3]]
+// CHECK: [[TMP7:%.*]] = or <8 x i16> [[TMP4]], [[TMP6]]
+// CHECK: [[TMP8:%.*]] = bitcast <8 x i16> [[TMP7]] to <8 x half>
+// CHECK: ret <8 x half> [[TMP8]]
+float16x8_t test_vbslq_f16(uint16x8_t a, float16x8_t b, float16x8_t c) {
+ return vbslq_f16(a, b, c);
+}
+
+// CHECK-LABEL: test_vzip_f16
+// CHECK: [[RETVAL:%.*]] = alloca %struct.float16x4x2_t, align 8
+// CHECK: [[__RET_I:%.*]] = alloca %struct.float16x4x2_t, align 8
+// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x2_t* [[__RET_I]] to i8*
+// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <4 x half>*
+// CHECK: [[VZIP0_I:%.*]] = shufflevector <4 x half> %a, <4 x half> %b, <4 x i32> <i32 0, i32 4, i32 1, i32 5>
+// CHECK: store <4 x half> [[VZIP0_I]], <4 x half>* [[TMP1]]
+// CHECK: [[TMP2:%.*]] = getelementptr inbounds <4 x half>, <4 x half>* [[TMP1]], i32 1
+// CHECK: [[VZIP1_I:%.*]] = shufflevector <4 x half> %a, <4 x half> %b, <4 x i32> <i32 2, i32 6, i32 3, i32 7>
+// CHECK: store <4 x half> [[VZIP1_I]], <4 x half>* [[TMP2]]
+// CHECK: [[TMP5:%.*]] = bitcast %struct.float16x4x2_t* [[RETVAL]] to i8*
+// CHECK: [[TMP6:%.*]] = bitcast %struct.float16x4x2_t* [[__RET_I]] to i8*
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP5]], i8* [[TMP6]], i64 16, i32 8, i1 false)
+float16x4x2_t test_vzip_f16(float16x4_t a, float16x4_t b) {
+ return vzip_f16(a, b);
+}
+
+// CHECK-LABEL: test_vzipq_f16
+// CHECK: [[RETVAL:%.*]] = alloca %struct.float16x8x2_t, align 16
+// CHECK: [[__RET_I:%.*]] = alloca %struct.float16x8x2_t, align 16
+// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x2_t* [[__RET_I]] to i8*
+// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <8 x half>*
+// CHECK: [[VZIP0_I:%.*]] = shufflevector <8 x half> %a, <8 x half> %b, <8 x i32> <i32 0, i32 8, i32 1, i32 9, i32 2, i32 10, i32 3, i32 11>
+// CHECK: store <8 x half> [[VZIP0_I]], <8 x half>* [[TMP1]]
+// CHECK: [[TMP2:%.*]] = getelementptr inbounds <8 x half>, <8 x half>* [[TMP1]], i32 1
+// CHECK: [[VZIP1_I:%.*]] = shufflevector <8 x half> %a, <8 x half> %b, <8 x i32> <i32 4, i32 12, i32 5, i32 13, i32 6, i32 14, i32 7, i32 15>
+// CHECK: store <8 x half> [[VZIP1_I]], <8 x half>* [[TMP2]]
+// CHECK: [[TMP5:%.*]] = bitcast %struct.float16x8x2_t* [[RETVAL]] to i8*
+// CHECK: [[TMP6:%.*]] = bitcast %struct.float16x8x2_t* [[__RET_I]] to i8*
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP5]], i8* [[TMP6]], i64 32, i32 16, i1 false)
+float16x8x2_t test_vzipq_f16(float16x8_t a, float16x8_t b) {
+ return vzipq_f16(a, b);
+}
+
+// CHECK-LABEL: test_vuzp_f16
+// CHECK: [[RETVAL:%.*]] = alloca %struct.float16x4x2_t, align 8
+// CHECK: [[__RET_I:%.*]] = alloca %struct.float16x4x2_t, align 8
+// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x2_t* [[__RET_I]] to i8*
+// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <4 x half>*
+// CHECK: [[VZIP0_I:%.*]] = shufflevector <4 x half> %a, <4 x half> %b, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
+// CHECK: store <4 x half> [[VZIP0_I]], <4 x half>* [[TMP1]]
+// CHECK: [[TMP2:%.*]] = getelementptr inbounds <4 x half>, <4 x half>* [[TMP1]], i32 1
+// CHECK: [[VZIP1_I:%.*]] = shufflevector <4 x half> %a, <4 x half> %b, <4 x i32> <i32 1, i32 3, i32 5, i32 7>
+// CHECK: store <4 x half> [[VZIP1_I]], <4 x half>* [[TMP2]]
+// CHECK: [[TMP5:%.*]] = bitcast %struct.float16x4x2_t* [[RETVAL]] to i8*
+// CHECK: [[TMP6:%.*]] = bitcast %struct.float16x4x2_t* [[__RET_I]] to i8*
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP5]], i8* [[TMP6]], i64 16, i32 8, i1 false)
+float16x4x2_t test_vuzp_f16(float16x4_t a, float16x4_t b) {
+ return vuzp_f16(a, b);
+}
+
+// CHECK-LABEL: test_vuzpq_f16
+// CHECK: [[RETVAL:%.*]] = alloca %struct.float16x8x2_t, align 16
+// CHECK: [[__RET_I:%.*]] = alloca %struct.float16x8x2_t, align 16
+// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x2_t* [[__RET_I]] to i8*
+// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <8 x half>*
+// CHECK: [[VZIP0_I:%.*]] = shufflevector <8 x half> %a, <8 x half> %b, <8 x i32> <i32 0, i32 2, i32 4, i32 6, i32 8, i32 10, i32 12, i32 14>
+// CHECK: store <8 x half> [[VZIP0_I]], <8 x half>* [[TMP1]]
+// CHECK: [[TMP2:%.*]] = getelementptr inbounds <8 x half>, <8 x half>* [[TMP1]], i32 1
+// CHECK: [[VZIP1_I:%.*]] = shufflevector <8 x half> %a, <8 x half> %b, <8 x i32> <i32 1, i32 3, i32 5, i32 7, i32 9, i32 11, i32 13, i32 15>
+// CHECK: store <8 x half> [[VZIP1_I]], <8 x half>* [[TMP2]]
+// CHECK: [[TMP5:%.*]] = bitcast %struct.float16x8x2_t* [[RETVAL]] to i8*
+// CHECK: [[TMP6:%.*]] = bitcast %struct.float16x8x2_t* [[__RET_I]] to i8*
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP5]], i8* [[TMP6]], i64 32, i32 16, i1 false)
+float16x8x2_t test_vuzpq_f16(float16x8_t a, float16x8_t b) {
+ return vuzpq_f16(a, b);
+}
+
+// CHECK-LABEL: test_vtrn_f16
+// CHECK: [[RETVAL:%.*]] = alloca %struct.float16x4x2_t, align 8
+// CHECK: [[__RET_I:%.*]] = alloca %struct.float16x4x2_t, align 8
+// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x2_t* [[__RET_I]] to i8*
+// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <4 x half>*
+// CHECK: [[VZIP0_I:%.*]] = shufflevector <4 x half> %a, <4 x half> %b, <4 x i32> <i32 0, i32 4, i32 2, i32 6>
+// CHECK: store <4 x half> [[VZIP0_I]], <4 x half>* [[TMP1]]
+// CHECK: [[TMP2:%.*]] = getelementptr inbounds <4 x half>, <4 x half>* [[TMP1]], i32 1
+// CHECK: [[VZIP1_I:%.*]] = shufflevector <4 x half> %a, <4 x half> %b, <4 x i32> <i32 1, i32 5, i32 3, i32 7>
+// CHECK: store <4 x half> [[VZIP1_I]], <4 x half>* [[TMP2]]
+// CHECK: [[TMP5:%.*]] = bitcast %struct.float16x4x2_t* [[RETVAL]] to i8*
+// CHECK: [[TMP6:%.*]] = bitcast %struct.float16x4x2_t* [[__RET_I]] to i8*
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP5]], i8* [[TMP6]], i64 16, i32 8, i1 false)
+float16x4x2_t test_vtrn_f16(float16x4_t a, float16x4_t b) {
+ return vtrn_f16(a, b);
+}
+
+// CHECK-LABEL: test_vtrnq_f16
+// CHECK: [[RETVAL:%.*]] = alloca %struct.float16x8x2_t, align 16
+// CHECK: [[__RET_I:%.*]] = alloca %struct.float16x8x2_t, align 16
+// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x2_t* [[__RET_I]] to i8*
+// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <8 x half>*
+// CHECK: [[VZIP0_I:%.*]] = shufflevector <8 x half> %a, <8 x half> %b, <8 x i32> <i32 0, i32 8, i32 2, i32 10, i32 4, i32 12, i32 6, i32 14>
+// CHECK: store <8 x half> [[VZIP0_I]], <8 x half>* [[TMP1]]
+// CHECK: [[TMP2:%.*]] = getelementptr inbounds <8 x half>, <8 x half>* [[TMP1]], i32 1
+// CHECK: [[VZIP1_I:%.*]] = shufflevector <8 x half> %a, <8 x half> %b, <8 x i32> <i32 1, i32 9, i32 3, i32 11, i32 5, i32 13, i32 7, i32 15>
+// CHECK: store <8 x half> [[VZIP1_I]], <8 x half>* [[TMP2]]
+// CHECK: [[TMP5:%.*]] = bitcast %struct.float16x8x2_t* [[RETVAL]] to i8*
+// CHECK: [[TMP6:%.*]] = bitcast %struct.float16x8x2_t* [[__RET_I]] to i8*
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP5]], i8* [[TMP6]], i64 32, i32 16, i1 false)
+float16x8x2_t test_vtrnq_f16(float16x8_t a, float16x8_t b) {
+ return vtrnq_f16(a, b);
+}
+
+// CHECK-LABEL: test_vmov_n_f16
+// CHECK: [[TMP0:%.*]] = insertelement <4 x half> undef, half %a, i32 0
+// CHECK: [[TMP1:%.*]] = insertelement <4 x half> [[TMP0]], half %a, i32 1
+// CHECK: [[TMP2:%.*]] = insertelement <4 x half> [[TMP1]], half %a, i32 2
+// CHECK: [[TMP3:%.*]] = insertelement <4 x half> [[TMP2]], half %a, i32 3
+// CHECK: ret <4 x half> [[TMP3]]
+float16x4_t test_vmov_n_f16(float16_t a) {
+ return vmov_n_f16(a);
+}
+
+// CHECK-LABEL: test_vmovq_n_f16
+// CHECK: [[TMP0:%.*]] = insertelement <8 x half> undef, half %a, i32 0
+// CHECK: [[TMP1:%.*]] = insertelement <8 x half> [[TMP0]], half %a, i32 1
+// CHECK: [[TMP2:%.*]] = insertelement <8 x half> [[TMP1]], half %a, i32 2
+// CHECK: [[TMP3:%.*]] = insertelement <8 x half> [[TMP2]], half %a, i32 3
+// CHECK: [[TMP4:%.*]] = insertelement <8 x half> [[TMP3]], half %a, i32 4
+// CHECK: [[TMP5:%.*]] = insertelement <8 x half> [[TMP4]], half %a, i32 5
+// CHECK: [[TMP6:%.*]] = insertelement <8 x half> [[TMP5]], half %a, i32 6
+// CHECK: [[TMP7:%.*]] = insertelement <8 x half> [[TMP6]], half %a, i32 7
+// CHECK: ret <8 x half> [[TMP7]]
+float16x8_t test_vmovq_n_f16(float16_t a) {
+ return vmovq_n_f16(a);
+}
+
+// CHECK-LABEL: test_vdup_n_f16
+// CHECK: [[TMP0:%.*]] = insertelement <4 x half> undef, half %a, i32 0
+// CHECK: [[TMP1:%.*]] = insertelement <4 x half> [[TMP0]], half %a, i32 1
+// CHECK: [[TMP2:%.*]] = insertelement <4 x half> [[TMP1]], half %a, i32 2
+// CHECK: [[TMP3:%.*]] = insertelement <4 x half> [[TMP2]], half %a, i32 3
+// CHECK: ret <4 x half> [[TMP3]]
+float16x4_t test_vdup_n_f16(float16_t a) {
+ return vdup_n_f16(a);
+}
+
+// CHECK-LABEL: test_vdupq_n_f16
+// CHECK: [[TMP0:%.*]] = insertelement <8 x half> undef, half %a, i32 0
+// CHECK: [[TMP1:%.*]] = insertelement <8 x half> [[TMP0]], half %a, i32 1
+// CHECK: [[TMP2:%.*]] = insertelement <8 x half> [[TMP1]], half %a, i32 2
+// CHECK: [[TMP3:%.*]] = insertelement <8 x half> [[TMP2]], half %a, i32 3
+// CHECK: [[TMP4:%.*]] = insertelement <8 x half> [[TMP3]], half %a, i32 4
+// CHECK: [[TMP5:%.*]] = insertelement <8 x half> [[TMP4]], half %a, i32 5
+// CHECK: [[TMP6:%.*]] = insertelement <8 x half> [[TMP5]], half %a, i32 6
+// CHECK: [[TMP7:%.*]] = insertelement <8 x half> [[TMP6]], half %a, i32 7
+// CHECK: ret <8 x half> [[TMP7]]
+float16x8_t test_vdupq_n_f16(float16_t a) {
+ return vdupq_n_f16(a);
+}
+
+// CHECK-LABEL: test_vdup_lane_f16
+// CHECK: [[SHFL:%.*]] = shufflevector <4 x half> %a, <4 x half> %a, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
+// CHECK: ret <4 x half> [[SHFL]]
+float16x4_t test_vdup_lane_f16(float16x4_t a) {
+ return vdup_lane_f16(a, 3);
+}
+
+// CHECK-LABEL: test_vdupq_lane_f16
+// CHECK: [[SHFL:%.*]] = shufflevector <4 x half> %a, <4 x half> %a, <8 x i32> <i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7>
+// CHECK: ret <8 x half> [[SHFL]]
+float16x8_t test_vdupq_lane_f16(float16x4_t a) {
+ return vdupq_lane_f16(a, 7);
+}
+
+// CHECK-LABEL: @test_vext_f16(
+// CHECK: [[TMP0:%.*]] = bitcast <4 x half> %a to <8 x i8>
+// CHECK: [[TMP1:%.*]] = bitcast <4 x half> %b to <8 x i8>
+// CHECK: [[TMP2:%.*]] = bitcast <8 x i8> [[TMP0]] to <4 x half>
+// CHECK: [[TMP3:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x half>
+// CHECK: [[VEXT:%.*]] = shufflevector <4 x half> [[TMP2]], <4 x half> [[TMP3]], <4 x i32> <i32 2, i32 3, i32 4, i32 5>
+// CHECK: ret <4 x half> [[VEXT]]
+float16x4_t test_vext_f16(float16x4_t a, float16x4_t b) {
+ return vext_f16(a, b, 2);
+}
+
+// CHECK-LABEL: @test_vextq_f16(
+// CHECK: [[TMP0:%.*]] = bitcast <8 x half> %a to <16 x i8>
+// CHECK: [[TMP1:%.*]] = bitcast <8 x half> %b to <16 x i8>
+// CHECK: [[TMP2:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x half>
+// CHECK: [[TMP3:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x half>
+// CHECK: [[VEXT:%.*]] = shufflevector <8 x half> [[TMP2]], <8 x half> [[TMP3]], <8 x i32> <i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12>
+// CHECK: ret <8 x half> [[VEXT]]
+float16x8_t test_vextq_f16(float16x8_t a, float16x8_t b) {
+ return vextq_f16(a, b, 5);
+}
+
+// CHECK-LABEL: @test_vrev64_f16(
+// CHECK: [[SHFL:%.*]] = shufflevector <4 x half> %a, <4 x half> %a, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
+// CHECK: ret <4 x half> [[SHFL]]
+float16x4_t test_vrev64_f16(float16x4_t a) {
+ return vrev64_f16(a);
+}
+
+// CHECK-LABEL: @test_vrev64q_f16(
+// CHECK: [[SHFL:%.*]] = shufflevector <8 x half> %a, <8 x half> %a, <8 x i32> <i32 3, i32 2, i32 1, i32 0, i32 7, i32 6, i32 5, i32 4>
+// CHECK: ret <8 x half> [[SHFL]]
+float16x8_t test_vrev64q_f16(float16x8_t a) {
+ return vrev64q_f16(a);
+}
+
+// CHECK-LABEL: @test_vzip1_f16(
+// CHECK: [[SHFL:%.*]] = shufflevector <4 x half> %a, <4 x half> %b, <4 x i32> <i32 0, i32 4, i32 1, i32 5>
+// CHECK: ret <4 x half> [[SHFL]]
+float16x4_t test_vzip1_f16(float16x4_t a, float16x4_t b) {
+ return vzip1_f16(a, b);
+}
+
+// CHECK-LABEL: @test_vzip1q_f16(
+// CHECK: [[SHFL:%.*]] = shufflevector <8 x half> %a, <8 x half> %b, <8 x i32> <i32 0, i32 8, i32 1, i32 9, i32 2, i32 10, i32 3, i32 11>
+// CHECK: ret <8 x half> [[SHFL]]
+float16x8_t test_vzip1q_f16(float16x8_t a, float16x8_t b) {
+ return vzip1q_f16(a, b);
+}
+
+// CHECK-LABEL: @test_vzip2_f16(
+// CHECK: [[SHFL:%.*]] = shufflevector <4 x half> %a, <4 x half> %b, <4 x i32> <i32 2, i32 6, i32 3, i32 7>
+// CHECK: ret <4 x half> [[SHFL]]
+float16x4_t test_vzip2_f16(float16x4_t a, float16x4_t b) {
+ return vzip2_f16(a, b);
+}
+
+// CHECK-LABEL: @test_vzip2q_f16(
+// CHECK: [[SHFL:%.*]] = shufflevector <8 x half> %a, <8 x half> %b, <8 x i32> <i32 4, i32 12, i32 5, i32 13, i32 6, i32 14, i32 7, i32 15>
+// CHECK: ret <8 x half> [[SHFL]]
+float16x8_t test_vzip2q_f16(float16x8_t a, float16x8_t b) {
+ return vzip2q_f16(a, b);
+}
+
+// CHECK-LABEL: @test_vuzp1_f16(
+// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <4 x half> %a, <4 x half> %b, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
+// CHECK: ret <4 x half> [[SHUFFLE_I]]
+float16x4_t test_vuzp1_f16(float16x4_t a, float16x4_t b) {
+ return vuzp1_f16(a, b);
+}
+
+// CHECK-LABEL: @test_vuzp1q_f16(
+// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <8 x half> %a, <8 x half> %b, <8 x i32> <i32 0, i32 2, i32 4, i32 6, i32 8, i32 10, i32 12, i32 14>
+// CHECK: ret <8 x half> [[SHUFFLE_I]]
+float16x8_t test_vuzp1q_f16(float16x8_t a, float16x8_t b) {
+ return vuzp1q_f16(a, b);
+}
+
+// CHECK-LABEL: @test_vuzp2_f16(
+// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <4 x half> %a, <4 x half> %b, <4 x i32> <i32 1, i32 3, i32 5, i32 7>
+// CHECK: ret <4 x half> [[SHUFFLE_I]]
+float16x4_t test_vuzp2_f16(float16x4_t a, float16x4_t b) {
+ return vuzp2_f16(a, b);
+}
+
+// CHECK-LABEL: @test_vuzp2q_f16(
+// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <8 x half> %a, <8 x half> %b, <8 x i32> <i32 1, i32 3, i32 5, i32 7, i32 9, i32 11, i32 13, i32 15>
+// CHECK: ret <8 x half> [[SHUFFLE_I]]
+float16x8_t test_vuzp2q_f16(float16x8_t a, float16x8_t b) {
+ return vuzp2q_f16(a, b);
+}
+
+// CHECK-LABEL: @test_vtrn1_f16(
+// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <4 x half> %a, <4 x half> %b, <4 x i32> <i32 0, i32 4, i32 2, i32 6>
+// CHECK: ret <4 x half> [[SHUFFLE_I]]
+float16x4_t test_vtrn1_f16(float16x4_t a, float16x4_t b) {
+ return vtrn1_f16(a, b);
+}
+
+// CHECK-LABEL: @test_vtrn1q_f16(
+// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <8 x half> %a, <8 x half> %b, <8 x i32> <i32 0, i32 8, i32 2, i32 10, i32 4, i32 12, i32 6, i32 14>
+// CHECK: ret <8 x half> [[SHUFFLE_I]]
+float16x8_t test_vtrn1q_f16(float16x8_t a, float16x8_t b) {
+ return vtrn1q_f16(a, b);
+}
+
+// CHECK-LABEL: @test_vtrn2_f16(
+// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <4 x half> %a, <4 x half> %b, <4 x i32> <i32 1, i32 5, i32 3, i32 7>
+// CHECK: ret <4 x half> [[SHUFFLE_I]]
+float16x4_t test_vtrn2_f16(float16x4_t a, float16x4_t b) {
+ return vtrn2_f16(a, b);
+}
+
+// CHECK-LABEL: @test_vtrn2q_f16(
+// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <8 x half> %a, <8 x half> %b, <8 x i32> <i32 1, i32 9, i32 3, i32 11, i32 5, i32 13, i32 7, i32 15>
+// CHECK: ret <8 x half> [[SHUFFLE_I]]
+float16x8_t test_vtrn2q_f16(float16x8_t a, float16x8_t b) {
+ return vtrn2q_f16(a, b);
+}
+
diff --git a/test/CodeGen/address-space.c b/test/CodeGen/address-space.c
index 35e3dbdcfa73..54e059385772 100644
--- a/test/CodeGen/address-space.c
+++ b/test/CodeGen/address-space.c
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm < %s | FileCheck -check-prefixes=CHECK,GIZ %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm < %s | FileCheck -check-prefixes=CHECK,X86,GIZ %s
// RUN: %clang_cc1 -triple amdgcn -emit-llvm < %s | FileCheck -check-prefixes=CHECK,PIZ %s
-// RUN: %clang_cc1 -triple amdgcn---amdgiz -emit-llvm < %s | FileCheck -check-prefixes=CHECK,GIZ %s
+// RUN: %clang_cc1 -triple amdgcn---amdgiz -emit-llvm < %s | FileCheck -check-prefixes=CHECK,AMDGIZ,GIZ %s
// CHECK: @foo = common addrspace(1) global
int foo __attribute__((address_space(1)));
diff --git a/test/CodeGen/arm_neon_intrinsics.c b/test/CodeGen/arm_neon_intrinsics.c
index 62888dd73339..b01c90c03a96 100644
--- a/test/CodeGen/arm_neon_intrinsics.c
+++ b/test/CodeGen/arm_neon_intrinsics.c
@@ -3896,9 +3896,8 @@ int64x2_t test_vld1q_s64(int64_t const * a) {
// CHECK-LABEL: @test_vld1q_f16(
// CHECK: [[TMP0:%.*]] = bitcast half* %a to i8*
-// CHECK: [[VLD1:%.*]] = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* [[TMP0]], i32 2)
-// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> [[VLD1]] to <8 x half>
-// CHECK: ret <8 x half> [[TMP1]]
+// CHECK: [[VLD1:%.*]] = call <8 x half> @llvm.arm.neon.vld1.v8f16.p0i8(i8* [[TMP0]], i32 2)
+// CHECK: ret <8 x half> [[VLD1]]
float16x8_t test_vld1q_f16(float16_t const * a) {
return vld1q_f16(a);
}
@@ -3990,9 +3989,8 @@ int64x1_t test_vld1_s64(int64_t const * a) {
// CHECK-LABEL: @test_vld1_f16(
// CHECK: [[TMP0:%.*]] = bitcast half* %a to i8*
-// CHECK: [[VLD1:%.*]] = call <4 x i16> @llvm.arm.neon.vld1.v4i16.p0i8(i8* [[TMP0]], i32 2)
-// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[VLD1]] to <4 x half>
-// CHECK: ret <4 x half> [[TMP1]]
+// CHECK: [[VLD1:%.*]] = call <4 x half> @llvm.arm.neon.vld1.v4f16.p0i8(i8* [[TMP0]], i32 2)
+// CHECK: ret <4 x half> [[VLD1]]
float16x4_t test_vld1_f16(float16_t const * a) {
return vld1_f16(a);
}
@@ -4106,12 +4104,11 @@ int64x2_t test_vld1q_dup_s64(int64_t const * a) {
// CHECK-LABEL: @test_vld1q_dup_f16(
// CHECK: [[TMP0:%.*]] = bitcast half* %a to i8*
-// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to i16*
-// CHECK: [[TMP2:%.*]] = load i16, i16* [[TMP1]], align 2
-// CHECK: [[TMP3:%.*]] = insertelement <8 x i16> undef, i16 [[TMP2]], i32 0
-// CHECK: [[LANE:%.*]] = shufflevector <8 x i16> [[TMP3]], <8 x i16> [[TMP3]], <8 x i32> zeroinitializer
-// CHECK: [[TMP4:%.*]] = bitcast <8 x i16> [[LANE]] to <8 x half>
-// CHECK: ret <8 x half> [[TMP4]]
+// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to half*
+// CHECK: [[TMP2:%.*]] = load half, half* [[TMP1]], align 2
+// CHECK: [[TMP3:%.*]] = insertelement <8 x half> undef, half [[TMP2]], i32 0
+// CHECK: [[LANE:%.*]] = shufflevector <8 x half> [[TMP3]], <8 x half> [[TMP3]], <8 x i32> zeroinitializer
+// CHECK: ret <8 x half> [[LANE]]
float16x8_t test_vld1q_dup_f16(float16_t const * a) {
return vld1q_dup_f16(a);
}
@@ -4233,12 +4230,11 @@ int64x1_t test_vld1_dup_s64(int64_t const * a) {
// CHECK-LABEL: @test_vld1_dup_f16(
// CHECK: [[TMP0:%.*]] = bitcast half* %a to i8*
-// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to i16*
-// CHECK: [[TMP2:%.*]] = load i16, i16* [[TMP1]], align 2
-// CHECK: [[TMP3:%.*]] = insertelement <4 x i16> undef, i16 [[TMP2]], i32 0
-// CHECK: [[LANE:%.*]] = shufflevector <4 x i16> [[TMP3]], <4 x i16> [[TMP3]], <4 x i32> zeroinitializer
-// CHECK: [[TMP4:%.*]] = bitcast <4 x i16> [[LANE]] to <4 x half>
-// CHECK: ret <4 x half> [[TMP4]]
+// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to half*
+// CHECK: [[TMP2:%.*]] = load half, half* [[TMP1]], align 2
+// CHECK: [[TMP3:%.*]] = insertelement <4 x half> undef, half [[TMP2]], i32 0
+// CHECK: [[LANE:%.*]] = shufflevector <4 x half> [[TMP3]], <4 x half> [[TMP3]], <4 x i32> zeroinitializer
+// CHECK: ret <4 x half> [[LANE]]
float16x4_t test_vld1_dup_f16(float16_t const * a) {
return vld1_dup_f16(a);
}
@@ -4365,12 +4361,11 @@ int64x2_t test_vld1q_lane_s64(int64_t const * a, int64x2_t b) {
// CHECK-LABEL: @test_vld1q_lane_f16(
// CHECK: [[TMP0:%.*]] = bitcast half* %a to i8*
// CHECK: [[TMP1:%.*]] = bitcast <8 x half> %b to <16 x i8>
-// CHECK: [[TMP2:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x i16>
-// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to i16*
-// CHECK: [[TMP4:%.*]] = load i16, i16* [[TMP3]], align 2
-// CHECK: [[VLD1_LANE:%.*]] = insertelement <8 x i16> [[TMP2]], i16 [[TMP4]], i32 7
-// CHECK: [[TMP5:%.*]] = bitcast <8 x i16> [[VLD1_LANE]] to <8 x half>
-// CHECK: ret <8 x half> [[TMP5]]
+// CHECK: [[TMP2:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x half>
+// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to half*
+// CHECK: [[TMP4:%.*]] = load half, half* [[TMP3]], align 2
+// CHECK: [[VLD1_LANE:%.*]] = insertelement <8 x half> [[TMP2]], half [[TMP4]], i32 7
+// CHECK: ret <8 x half> [[VLD1_LANE]]
float16x8_t test_vld1q_lane_f16(float16_t const * a, float16x8_t b) {
return vld1q_lane_f16(a, b, 7);
}
@@ -4498,12 +4493,11 @@ int64x1_t test_vld1_lane_s64(int64_t const * a, int64x1_t b) {
// CHECK-LABEL: @test_vld1_lane_f16(
// CHECK: [[TMP0:%.*]] = bitcast half* %a to i8*
// CHECK: [[TMP1:%.*]] = bitcast <4 x half> %b to <8 x i8>
-// CHECK: [[TMP2:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x i16>
-// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to i16*
-// CHECK: [[TMP4:%.*]] = load i16, i16* [[TMP3]], align 2
-// CHECK: [[VLD1_LANE:%.*]] = insertelement <4 x i16> [[TMP2]], i16 [[TMP4]], i32 3
-// CHECK: [[TMP5:%.*]] = bitcast <4 x i16> [[VLD1_LANE]] to <4 x half>
-// CHECK: ret <4 x half> [[TMP5]]
+// CHECK: [[TMP2:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x half>
+// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to half*
+// CHECK: [[TMP4:%.*]] = load half, half* [[TMP3]], align 2
+// CHECK: [[VLD1_LANE:%.*]] = insertelement <4 x half> [[TMP2]], half [[TMP4]], i32 3
+// CHECK: ret <4 x half> [[VLD1_LANE]]
float16x4_t test_vld1_lane_f16(float16_t const * a, float16x4_t b) {
return vld1_lane_f16(a, b, 3);
}
@@ -4596,7 +4590,7 @@ int32x4x2_t test_vld2q_s32(int32_t const * a) {
// CHECK: [[__RET:%.*]] = alloca %struct.float16x8x2_t, align 16
// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x2_t* [[__RET]] to i8*
// CHECK: [[TMP1:%.*]] = bitcast half* %a to i8*
-// CHECK: [[VLD2Q_V:%.*]] = call { <8 x i16>, <8 x i16>
+// CHECK: [[VLD2Q_V:%.*]] = call { <8 x half>, <8 x half>
float16x8x2_t test_vld2q_f16(float16_t const * a) {
return vld2q_f16(a);
}
@@ -4701,7 +4695,7 @@ int64x1x2_t test_vld2_s64(int64_t const * a) {
// CHECK: [[__RET:%.*]] = alloca %struct.float16x4x2_t, align 8
// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x2_t* [[__RET]] to i8*
// CHECK: [[TMP1:%.*]] = bitcast half* %a to i8*
-// CHECK: [[VLD2_V:%.*]] = call { <4 x i16>, <4 x i16>
+// CHECK: [[VLD2_V:%.*]] = call { <4 x half>, <4 x half>
float16x4x2_t test_vld2_f16(float16_t const * a) {
return vld2_f16(a);
}
@@ -4806,7 +4800,7 @@ int64x1x2_t test_vld2_dup_s64(int64_t const * a) {
// CHECK: [[__RET:%.*]] = alloca %struct.float16x4x2_t, align 8
// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x2_t* [[__RET]] to i8*
// CHECK: [[TMP1:%.*]] = bitcast half* %a to i8*
-// CHECK: [[VLD_DUP:%.*]] = call { <4 x i16>, <4 x i16>
+// CHECK: [[VLD_DUP:%.*]] = call { <4 x half>, <4 x half>
float16x4x2_t test_vld2_dup_f16(float16_t const * a) {
return vld2_dup_f16(a);
}
@@ -4965,9 +4959,9 @@ int32x4x2_t test_vld2q_lane_s32(int32_t const * a, int32x4x2_t b) {
// CHECK: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x <8 x half>], [2 x <8 x half>]* [[VAL1]], i32 0, i32 1
// CHECK: [[TMP7:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX2]], align 16
// CHECK: [[TMP8:%.*]] = bitcast <8 x half> [[TMP7]] to <16 x i8>
-// CHECK: [[TMP9:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x i16>
-// CHECK: [[TMP10:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x i16>
-// CHECK: [[VLD2Q_LANE_V:%.*]] = call { <8 x i16>, <8 x i16>
+// CHECK: [[TMP9:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x half>
+// CHECK: [[TMP10:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x half>
+// CHECK: [[VLD2Q_LANE_V:%.*]] = call { <8 x half>, <8 x half>
float16x8x2_t test_vld2q_lane_f16(float16_t const * a, float16x8x2_t b) {
return vld2q_lane_f16(a, b, 7);
}
@@ -5198,9 +5192,9 @@ int32x2x2_t test_vld2_lane_s32(int32_t const * a, int32x2x2_t b) {
// CHECK: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x <4 x half>], [2 x <4 x half>]* [[VAL1]], i32 0, i32 1
// CHECK: [[TMP7:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX2]], align 8
// CHECK: [[TMP8:%.*]] = bitcast <4 x half> [[TMP7]] to <8 x i8>
-// CHECK: [[TMP9:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x i16>
-// CHECK: [[TMP10:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x i16>
-// CHECK: [[VLD2_LANE_V:%.*]] = call { <4 x i16>, <4 x i16>
+// CHECK: [[TMP9:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x half>
+// CHECK: [[TMP10:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x half>
+// CHECK: [[VLD2_LANE_V:%.*]] = call { <4 x half>, <4 x half>
float16x4x2_t test_vld2_lane_f16(float16_t const * a, float16x4x2_t b) {
return vld2_lane_f16(a, b, 3);
}
@@ -5337,7 +5331,7 @@ int32x4x3_t test_vld3q_s32(int32_t const * a) {
// CHECK: [[__RET:%.*]] = alloca %struct.float16x8x3_t, align 16
// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x3_t* [[__RET]] to i8*
// CHECK: [[TMP1:%.*]] = bitcast half* %a to i8*
-// CHECK: [[VLD3Q_V:%.*]] = call { <8 x i16>, <8 x i16>, <8 x i16>
+// CHECK: [[VLD3Q_V:%.*]] = call { <8 x half>, <8 x half>, <8 x half>
float16x8x3_t test_vld3q_f16(float16_t const * a) {
return vld3q_f16(a);
}
@@ -5442,7 +5436,7 @@ int64x1x3_t test_vld3_s64(int64_t const * a) {
// CHECK: [[__RET:%.*]] = alloca %struct.float16x4x3_t, align 8
// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x3_t* [[__RET]] to i8*
// CHECK: [[TMP1:%.*]] = bitcast half* %a to i8*
-// CHECK: [[VLD3_V:%.*]] = call { <4 x i16>, <4 x i16>, <4 x i16>
+// CHECK: [[VLD3_V:%.*]] = call { <4 x half>, <4 x half>, <4 x half>
float16x4x3_t test_vld3_f16(float16_t const * a) {
return vld3_f16(a);
}
@@ -5547,7 +5541,7 @@ int64x1x3_t test_vld3_dup_s64(int64_t const * a) {
// CHECK: [[__RET:%.*]] = alloca %struct.float16x4x3_t, align 8
// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x3_t* [[__RET]] to i8*
// CHECK: [[TMP1:%.*]] = bitcast half* %a to i8*
-// CHECK: [[VLD_DUP:%.*]] = call { <4 x i16>, <4 x i16>, <4 x i16>
+// CHECK: [[VLD_DUP:%.*]] = call { <4 x half>, <4 x half>, <4 x half>
float16x4x3_t test_vld3_dup_f16(float16_t const * a) {
return vld3_dup_f16(a);
}
@@ -5730,10 +5724,10 @@ int32x4x3_t test_vld3q_lane_s32(int32_t const * a, int32x4x3_t b) {
// CHECK: [[ARRAYIDX4:%.*]] = getelementptr inbounds [3 x <8 x half>], [3 x <8 x half>]* [[VAL3]], i32 0, i32 2
// CHECK: [[TMP9:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX4]], align 16
// CHECK: [[TMP10:%.*]] = bitcast <8 x half> [[TMP9]] to <16 x i8>
-// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x i16>
-// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x i16>
-// CHECK: [[TMP13:%.*]] = bitcast <16 x i8> [[TMP10]] to <8 x i16>
-// CHECK: [[VLD3Q_LANE_V:%.*]] = call { <8 x i16>, <8 x i16>, <8 x i16>
+// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x half>
+// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x half>
+// CHECK: [[TMP13:%.*]] = bitcast <16 x i8> [[TMP10]] to <8 x half>
+// CHECK: [[VLD3Q_LANE_V:%.*]] = call { <8 x half>, <8 x half>, <8 x half>
float16x8x3_t test_vld3q_lane_f16(float16_t const * a, float16x8x3_t b) {
return vld3q_lane_f16(a, b, 7);
}
@@ -6004,10 +5998,10 @@ int32x2x3_t test_vld3_lane_s32(int32_t const * a, int32x2x3_t b) {
// CHECK: [[ARRAYIDX4:%.*]] = getelementptr inbounds [3 x <4 x half>], [3 x <4 x half>]* [[VAL3]], i32 0, i32 2
// CHECK: [[TMP9:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX4]], align 8
// CHECK: [[TMP10:%.*]] = bitcast <4 x half> [[TMP9]] to <8 x i8>
-// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x i16>
-// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x i16>
-// CHECK: [[TMP13:%.*]] = bitcast <8 x i8> [[TMP10]] to <4 x i16>
-// CHECK: [[VLD3_LANE_V:%.*]] = call { <4 x i16>, <4 x i16>, <4 x i16>
+// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x half>
+// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x half>
+// CHECK: [[TMP13:%.*]] = bitcast <8 x i8> [[TMP10]] to <4 x half>
+// CHECK: [[VLD3_LANE_V:%.*]] = call { <4 x half>, <4 x half>, <4 x half>
float16x4x3_t test_vld3_lane_f16(float16_t const * a, float16x4x3_t b) {
return vld3_lane_f16(a, b, 3);
}
@@ -6157,7 +6151,7 @@ int32x4x4_t test_vld4q_s32(int32_t const * a) {
// CHECK: [[__RET:%.*]] = alloca %struct.float16x8x4_t, align 16
// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x4_t* [[__RET]] to i8*
// CHECK: [[TMP1:%.*]] = bitcast half* %a to i8*
-// CHECK: [[VLD4Q_V:%.*]] = call { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16>
+// CHECK: [[VLD4Q_V:%.*]] = call { <8 x half>, <8 x half>, <8 x half>, <8 x half>
float16x8x4_t test_vld4q_f16(float16_t const * a) {
return vld4q_f16(a);
}
@@ -6262,7 +6256,7 @@ int64x1x4_t test_vld4_s64(int64_t const * a) {
// CHECK: [[__RET:%.*]] = alloca %struct.float16x4x4_t, align 8
// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x4_t* [[__RET]] to i8*
// CHECK: [[TMP1:%.*]] = bitcast half* %a to i8*
-// CHECK: [[VLD4_V:%.*]] = call { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16>
+// CHECK: [[VLD4_V:%.*]] = call { <4 x half>, <4 x half>, <4 x half>, <4 x half>
float16x4x4_t test_vld4_f16(float16_t const * a) {
return vld4_f16(a);
}
@@ -6367,7 +6361,7 @@ int64x1x4_t test_vld4_dup_s64(int64_t const * a) {
// CHECK: [[__RET:%.*]] = alloca %struct.float16x4x4_t, align 8
// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x4_t* [[__RET]] to i8*
// CHECK: [[TMP1:%.*]] = bitcast half* %a to i8*
-// CHECK: [[VLD_DUP:%.*]] = call { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16>
+// CHECK: [[VLD_DUP:%.*]] = call { <4 x half>, <4 x half>, <4 x half>, <4 x half>
float16x4x4_t test_vld4_dup_f16(float16_t const * a) {
return vld4_dup_f16(a);
}
@@ -6574,11 +6568,11 @@ int32x4x4_t test_vld4q_lane_s32(int32_t const * a, int32x4x4_t b) {
// CHECK: [[ARRAYIDX6:%.*]] = getelementptr inbounds [4 x <8 x half>], [4 x <8 x half>]* [[VAL5]], i32 0, i32 3
// CHECK: [[TMP11:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX6]], align 16
// CHECK: [[TMP12:%.*]] = bitcast <8 x half> [[TMP11]] to <16 x i8>
-// CHECK: [[TMP13:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x i16>
-// CHECK: [[TMP14:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x i16>
-// CHECK: [[TMP15:%.*]] = bitcast <16 x i8> [[TMP10]] to <8 x i16>
-// CHECK: [[TMP16:%.*]] = bitcast <16 x i8> [[TMP12]] to <8 x i16>
-// CHECK: [[VLD4Q_LANE_V:%.*]] = call { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16>
+// CHECK: [[TMP13:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x half>
+// CHECK: [[TMP14:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x half>
+// CHECK: [[TMP15:%.*]] = bitcast <16 x i8> [[TMP10]] to <8 x half>
+// CHECK: [[TMP16:%.*]] = bitcast <16 x i8> [[TMP12]] to <8 x half>
+// CHECK: [[VLD4Q_LANE_V:%.*]] = call { <8 x half>, <8 x half>, <8 x half>, <8 x half>
float16x8x4_t test_vld4q_lane_f16(float16_t const * a, float16x8x4_t b) {
return vld4q_lane_f16(a, b, 7);
}
@@ -6889,11 +6883,11 @@ int32x2x4_t test_vld4_lane_s32(int32_t const * a, int32x2x4_t b) {
// CHECK: [[ARRAYIDX6:%.*]] = getelementptr inbounds [4 x <4 x half>], [4 x <4 x half>]* [[VAL5]], i32 0, i32 3
// CHECK: [[TMP11:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX6]], align 8
// CHECK: [[TMP12:%.*]] = bitcast <4 x half> [[TMP11]] to <8 x i8>
-// CHECK: [[TMP13:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x i16>
-// CHECK: [[TMP14:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x i16>
-// CHECK: [[TMP15:%.*]] = bitcast <8 x i8> [[TMP10]] to <4 x i16>
-// CHECK: [[TMP16:%.*]] = bitcast <8 x i8> [[TMP12]] to <4 x i16>
-// CHECK: [[VLD4_LANE_V:%.*]] = call { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16>
+// CHECK: [[TMP13:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x half>
+// CHECK: [[TMP14:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x half>
+// CHECK: [[TMP15:%.*]] = bitcast <8 x i8> [[TMP10]] to <4 x half>
+// CHECK: [[TMP16:%.*]] = bitcast <8 x i8> [[TMP12]] to <4 x half>
+// CHECK: [[VLD4_LANE_V:%.*]] = call { <4 x half>, <4 x half>, <4 x half>, <4 x half>
float16x4x4_t test_vld4_lane_f16(float16_t const * a, float16x4x4_t b) {
return vld4_lane_f16(a, b, 3);
}
@@ -15784,8 +15778,8 @@ void test_vst1q_s64(int64_t * a, int64x2_t b) {
// CHECK-LABEL: @test_vst1q_f16(
// CHECK: [[TMP0:%.*]] = bitcast half* %a to i8*
// CHECK: [[TMP1:%.*]] = bitcast <8 x half> %b to <16 x i8>
-// CHECK: [[TMP2:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x i16>
-// CHECK: call void @llvm.arm.neon.vst1.p0i8.v8i16(i8* [[TMP0]], <8 x i16> [[TMP2]], i32 2)
+// CHECK: [[TMP2:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x half>
+// CHECK: call void @llvm.arm.neon.vst1.p0i8.v8f16(i8* [[TMP0]], <8 x half> [[TMP2]], i32 2)
// CHECK: ret void
void test_vst1q_f16(float16_t * a, float16x8_t b) {
vst1q_f16(a, b);
@@ -15895,8 +15889,8 @@ void test_vst1_s64(int64_t * a, int64x1_t b) {
// CHECK-LABEL: @test_vst1_f16(
// CHECK: [[TMP0:%.*]] = bitcast half* %a to i8*
// CHECK: [[TMP1:%.*]] = bitcast <4 x half> %b to <8 x i8>
-// CHECK: [[TMP2:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x i16>
-// CHECK: call void @llvm.arm.neon.vst1.p0i8.v4i16(i8* [[TMP0]], <4 x i16> [[TMP2]], i32 2)
+// CHECK: [[TMP2:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x half>
+// CHECK: call void @llvm.arm.neon.vst1.p0i8.v4f16(i8* [[TMP0]], <4 x half> [[TMP2]], i32 2)
// CHECK: ret void
void test_vst1_f16(float16_t * a, float16x4_t b) {
vst1_f16(a, b);
@@ -16018,10 +16012,10 @@ void test_vst1q_lane_s64(int64_t * a, int64x2_t b) {
// CHECK-LABEL: @test_vst1q_lane_f16(
// CHECK: [[TMP0:%.*]] = bitcast half* %a to i8*
// CHECK: [[TMP1:%.*]] = bitcast <8 x half> %b to <16 x i8>
-// CHECK: [[TMP2:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x i16>
-// CHECK: [[TMP3:%.*]] = extractelement <8 x i16> [[TMP2]], i32 7
-// CHECK: [[TMP4:%.*]] = bitcast i8* [[TMP0]] to i16*
-// CHECK: store i16 [[TMP3]], i16* [[TMP4]], align 2
+// CHECK: [[TMP2:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x half>
+// CHECK: [[TMP3:%.*]] = extractelement <8 x half> [[TMP2]], i32 7
+// CHECK: [[TMP4:%.*]] = bitcast i8* [[TMP0]] to half*
+// CHECK: store half [[TMP3]], half* [[TMP4]], align 2
// CHECK: ret void
void test_vst1q_lane_f16(float16_t * a, float16x8_t b) {
vst1q_lane_f16(a, b, 7);
@@ -16150,10 +16144,10 @@ void test_vst1_lane_s64(int64_t * a, int64x1_t b) {
// CHECK-LABEL: @test_vst1_lane_f16(
// CHECK: [[TMP0:%.*]] = bitcast half* %a to i8*
// CHECK: [[TMP1:%.*]] = bitcast <4 x half> %b to <8 x i8>
-// CHECK: [[TMP2:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x i16>
-// CHECK: [[TMP3:%.*]] = extractelement <4 x i16> [[TMP2]], i32 3
-// CHECK: [[TMP4:%.*]] = bitcast i8* [[TMP0]] to i16*
-// CHECK: store i16 [[TMP3]], i16* [[TMP4]], align 2
+// CHECK: [[TMP2:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x half>
+// CHECK: [[TMP3:%.*]] = extractelement <4 x half> [[TMP2]], i32 3
+// CHECK: [[TMP4:%.*]] = bitcast i8* [[TMP0]] to half*
+// CHECK: store half [[TMP3]], half* [[TMP4]], align 2
// CHECK: ret void
void test_vst1_lane_f16(float16_t * a, float16x4_t b) {
vst1_lane_f16(a, b, 3);
@@ -16355,9 +16349,9 @@ void test_vst2q_s32(int32_t * a, int32x4x2_t b) {
// CHECK: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x <8 x half>], [2 x <8 x half>]* [[VAL1]], i32 0, i32 1
// CHECK: [[TMP6:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX2]], align 16
// CHECK: [[TMP7:%.*]] = bitcast <8 x half> [[TMP6]] to <16 x i8>
-// CHECK: [[TMP8:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x i16>
-// CHECK: [[TMP9:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x i16>
-// CHECK: call void @llvm.arm.neon.vst2.p0i8.v8i16(i8* [[TMP3]], <8 x i16> [[TMP8]], <8 x i16> [[TMP9]], i32 2)
+// CHECK: [[TMP8:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x half>
+// CHECK: [[TMP9:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x half>
+// CHECK: call void @llvm.arm.neon.vst2.p0i8.v8f16(i8* [[TMP3]], <8 x half> [[TMP8]], <8 x half> [[TMP9]], i32 2)
// CHECK: ret void
void test_vst2q_f16(float16_t * a, float16x8x2_t b) {
vst2q_f16(a, b);
@@ -16652,9 +16646,9 @@ void test_vst2_s64(int64_t * a, int64x1x2_t b) {
// CHECK: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x <4 x half>], [2 x <4 x half>]* [[VAL1]], i32 0, i32 1
// CHECK: [[TMP6:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX2]], align 8
// CHECK: [[TMP7:%.*]] = bitcast <4 x half> [[TMP6]] to <8 x i8>
-// CHECK: [[TMP8:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x i16>
-// CHECK: [[TMP9:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x i16>
-// CHECK: call void @llvm.arm.neon.vst2.p0i8.v4i16(i8* [[TMP3]], <4 x i16> [[TMP8]], <4 x i16> [[TMP9]], i32 2)
+// CHECK: [[TMP8:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x half>
+// CHECK: [[TMP9:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x half>
+// CHECK: call void @llvm.arm.neon.vst2.p0i8.v4f16(i8* [[TMP3]], <4 x half> [[TMP8]], <4 x half> [[TMP9]], i32 2)
// CHECK: ret void
void test_vst2_f16(float16_t * a, float16x4x2_t b) {
vst2_f16(a, b);
@@ -16855,9 +16849,9 @@ void test_vst2q_lane_s32(int32_t * a, int32x4x2_t b) {
// CHECK: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x <8 x half>], [2 x <8 x half>]* [[VAL1]], i32 0, i32 1
// CHECK: [[TMP6:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX2]], align 16
// CHECK: [[TMP7:%.*]] = bitcast <8 x half> [[TMP6]] to <16 x i8>
-// CHECK: [[TMP8:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x i16>
-// CHECK: [[TMP9:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x i16>
-// CHECK: call void @llvm.arm.neon.vst2lane.p0i8.v8i16(i8* [[TMP3]], <8 x i16> [[TMP8]], <8 x i16> [[TMP9]], i32 7, i32 2)
+// CHECK: [[TMP8:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x half>
+// CHECK: [[TMP9:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x half>
+// CHECK: call void @llvm.arm.neon.vst2lane.p0i8.v8f16(i8* [[TMP3]], <8 x half> [[TMP8]], <8 x half> [[TMP9]], i32 7, i32 2)
// CHECK: ret void
void test_vst2q_lane_f16(float16_t * a, float16x8x2_t b) {
vst2q_lane_f16(a, b, 7);
@@ -17079,9 +17073,9 @@ void test_vst2_lane_s32(int32_t * a, int32x2x2_t b) {
// CHECK: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x <4 x half>], [2 x <4 x half>]* [[VAL1]], i32 0, i32 1
// CHECK: [[TMP6:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX2]], align 8
// CHECK: [[TMP7:%.*]] = bitcast <4 x half> [[TMP6]] to <8 x i8>
-// CHECK: [[TMP8:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x i16>
-// CHECK: [[TMP9:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x i16>
-// CHECK: call void @llvm.arm.neon.vst2lane.p0i8.v4i16(i8* [[TMP3]], <4 x i16> [[TMP8]], <4 x i16> [[TMP9]], i32 3, i32 2)
+// CHECK: [[TMP8:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x half>
+// CHECK: [[TMP9:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x half>
+// CHECK: call void @llvm.arm.neon.vst2lane.p0i8.v4f16(i8* [[TMP3]], <4 x half> [[TMP8]], <4 x half> [[TMP9]], i32 3, i32 2)
// CHECK: ret void
void test_vst2_lane_f16(float16_t * a, float16x4x2_t b) {
vst2_lane_f16(a, b, 3);
@@ -17354,10 +17348,10 @@ void test_vst3q_s32(int32_t * a, int32x4x3_t b) {
// CHECK: [[ARRAYIDX4:%.*]] = getelementptr inbounds [3 x <8 x half>], [3 x <8 x half>]* [[VAL3]], i32 0, i32 2
// CHECK: [[TMP8:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX4]], align 16
// CHECK: [[TMP9:%.*]] = bitcast <8 x half> [[TMP8]] to <16 x i8>
-// CHECK: [[TMP10:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x i16>
-// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x i16>
-// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP9]] to <8 x i16>
-// CHECK: call void @llvm.arm.neon.vst3.p0i8.v8i16(i8* [[TMP3]], <8 x i16> [[TMP10]], <8 x i16> [[TMP11]], <8 x i16> [[TMP12]], i32 2)
+// CHECK: [[TMP10:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x half>
+// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x half>
+// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP9]] to <8 x half>
+// CHECK: call void @llvm.arm.neon.vst3.p0i8.v8f16(i8* [[TMP3]], <8 x half> [[TMP10]], <8 x half> [[TMP11]], <8 x half> [[TMP12]], i32 2)
// CHECK: ret void
void test_vst3q_f16(float16_t * a, float16x8x3_t b) {
vst3q_f16(a, b);
@@ -17705,10 +17699,10 @@ void test_vst3_s64(int64_t * a, int64x1x3_t b) {
// CHECK: [[ARRAYIDX4:%.*]] = getelementptr inbounds [3 x <4 x half>], [3 x <4 x half>]* [[VAL3]], i32 0, i32 2
// CHECK: [[TMP8:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX4]], align 8
// CHECK: [[TMP9:%.*]] = bitcast <4 x half> [[TMP8]] to <8 x i8>
-// CHECK: [[TMP10:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x i16>
-// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x i16>
-// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP9]] to <4 x i16>
-// CHECK: call void @llvm.arm.neon.vst3.p0i8.v4i16(i8* [[TMP3]], <4 x i16> [[TMP10]], <4 x i16> [[TMP11]], <4 x i16> [[TMP12]], i32 2)
+// CHECK: [[TMP10:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x half>
+// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x half>
+// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP9]] to <4 x half>
+// CHECK: call void @llvm.arm.neon.vst3.p0i8.v4f16(i8* [[TMP3]], <4 x half> [[TMP10]], <4 x half> [[TMP11]], <4 x half> [[TMP12]], i32 2)
// CHECK: ret void
void test_vst3_f16(float16_t * a, float16x4x3_t b) {
vst3_f16(a, b);
@@ -17946,10 +17940,10 @@ void test_vst3q_lane_s32(int32_t * a, int32x4x3_t b) {
// CHECK: [[ARRAYIDX4:%.*]] = getelementptr inbounds [3 x <8 x half>], [3 x <8 x half>]* [[VAL3]], i32 0, i32 2
// CHECK: [[TMP8:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX4]], align 16
// CHECK: [[TMP9:%.*]] = bitcast <8 x half> [[TMP8]] to <16 x i8>
-// CHECK: [[TMP10:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x i16>
-// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x i16>
-// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP9]] to <8 x i16>
-// CHECK: call void @llvm.arm.neon.vst3lane.p0i8.v8i16(i8* [[TMP3]], <8 x i16> [[TMP10]], <8 x i16> [[TMP11]], <8 x i16> [[TMP12]], i32 7, i32 2)
+// CHECK: [[TMP10:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x half>
+// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x half>
+// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP9]] to <8 x half>
+// CHECK: call void @llvm.arm.neon.vst3lane.p0i8.v8f16(i8* [[TMP3]], <8 x half> [[TMP10]], <8 x half> [[TMP11]], <8 x half> [[TMP12]], i32 7, i32 2)
// CHECK: ret void
void test_vst3q_lane_f16(float16_t * a, float16x8x3_t b) {
vst3q_lane_f16(a, b, 7);
@@ -18211,10 +18205,10 @@ void test_vst3_lane_s32(int32_t * a, int32x2x3_t b) {
// CHECK: [[ARRAYIDX4:%.*]] = getelementptr inbounds [3 x <4 x half>], [3 x <4 x half>]* [[VAL3]], i32 0, i32 2
// CHECK: [[TMP8:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX4]], align 8
// CHECK: [[TMP9:%.*]] = bitcast <4 x half> [[TMP8]] to <8 x i8>
-// CHECK: [[TMP10:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x i16>
-// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x i16>
-// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP9]] to <4 x i16>
-// CHECK: call void @llvm.arm.neon.vst3lane.p0i8.v4i16(i8* [[TMP3]], <4 x i16> [[TMP10]], <4 x i16> [[TMP11]], <4 x i16> [[TMP12]], i32 3, i32 2)
+// CHECK: [[TMP10:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x half>
+// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x half>
+// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP9]] to <4 x half>
+// CHECK: call void @llvm.arm.neon.vst3lane.p0i8.v4f16(i8* [[TMP3]], <4 x half> [[TMP10]], <4 x half> [[TMP11]], <4 x half> [[TMP12]], i32 3, i32 2)
// CHECK: ret void
void test_vst3_lane_f16(float16_t * a, float16x4x3_t b) {
vst3_lane_f16(a, b, 3);
@@ -18530,11 +18524,11 @@ void test_vst4q_s32(int32_t * a, int32x4x4_t b) {
// CHECK: [[ARRAYIDX6:%.*]] = getelementptr inbounds [4 x <8 x half>], [4 x <8 x half>]* [[VAL5]], i32 0, i32 3
// CHECK: [[TMP10:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX6]], align 16
// CHECK: [[TMP11:%.*]] = bitcast <8 x half> [[TMP10]] to <16 x i8>
-// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x i16>
-// CHECK: [[TMP13:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x i16>
-// CHECK: [[TMP14:%.*]] = bitcast <16 x i8> [[TMP9]] to <8 x i16>
-// CHECK: [[TMP15:%.*]] = bitcast <16 x i8> [[TMP11]] to <8 x i16>
-// CHECK: call void @llvm.arm.neon.vst4.p0i8.v8i16(i8* [[TMP3]], <8 x i16> [[TMP12]], <8 x i16> [[TMP13]], <8 x i16> [[TMP14]], <8 x i16> [[TMP15]], i32 2)
+// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x half>
+// CHECK: [[TMP13:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x half>
+// CHECK: [[TMP14:%.*]] = bitcast <16 x i8> [[TMP9]] to <8 x half>
+// CHECK: [[TMP15:%.*]] = bitcast <16 x i8> [[TMP11]] to <8 x half>
+// CHECK: call void @llvm.arm.neon.vst4.p0i8.v8f16(i8* [[TMP3]], <8 x half> [[TMP12]], <8 x half> [[TMP13]], <8 x half> [[TMP14]], <8 x half> [[TMP15]], i32 2)
// CHECK: ret void
void test_vst4q_f16(float16_t * a, float16x8x4_t b) {
vst4q_f16(a, b);
@@ -18935,11 +18929,11 @@ void test_vst4_s64(int64_t * a, int64x1x4_t b) {
// CHECK: [[ARRAYIDX6:%.*]] = getelementptr inbounds [4 x <4 x half>], [4 x <4 x half>]* [[VAL5]], i32 0, i32 3
// CHECK: [[TMP10:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX6]], align 8
// CHECK: [[TMP11:%.*]] = bitcast <4 x half> [[TMP10]] to <8 x i8>
-// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x i16>
-// CHECK: [[TMP13:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x i16>
-// CHECK: [[TMP14:%.*]] = bitcast <8 x i8> [[TMP9]] to <4 x i16>
-// CHECK: [[TMP15:%.*]] = bitcast <8 x i8> [[TMP11]] to <4 x i16>
-// CHECK: call void @llvm.arm.neon.vst4.p0i8.v4i16(i8* [[TMP3]], <4 x i16> [[TMP12]], <4 x i16> [[TMP13]], <4 x i16> [[TMP14]], <4 x i16> [[TMP15]], i32 2)
+// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x half>
+// CHECK: [[TMP13:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x half>
+// CHECK: [[TMP14:%.*]] = bitcast <8 x i8> [[TMP9]] to <4 x half>
+// CHECK: [[TMP15:%.*]] = bitcast <8 x i8> [[TMP11]] to <4 x half>
+// CHECK: call void @llvm.arm.neon.vst4.p0i8.v4f16(i8* [[TMP3]], <4 x half> [[TMP12]], <4 x half> [[TMP13]], <4 x half> [[TMP14]], <4 x half> [[TMP15]], i32 2)
// CHECK: ret void
void test_vst4_f16(float16_t * a, float16x4x4_t b) {
vst4_f16(a, b);
@@ -19214,11 +19208,11 @@ void test_vst4q_lane_s32(int32_t * a, int32x4x4_t b) {
// CHECK: [[ARRAYIDX6:%.*]] = getelementptr inbounds [4 x <8 x half>], [4 x <8 x half>]* [[VAL5]], i32 0, i32 3
// CHECK: [[TMP10:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX6]], align 16
// CHECK: [[TMP11:%.*]] = bitcast <8 x half> [[TMP10]] to <16 x i8>
-// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x i16>
-// CHECK: [[TMP13:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x i16>
-// CHECK: [[TMP14:%.*]] = bitcast <16 x i8> [[TMP9]] to <8 x i16>
-// CHECK: [[TMP15:%.*]] = bitcast <16 x i8> [[TMP11]] to <8 x i16>
-// CHECK: call void @llvm.arm.neon.vst4lane.p0i8.v8i16(i8* [[TMP3]], <8 x i16> [[TMP12]], <8 x i16> [[TMP13]], <8 x i16> [[TMP14]], <8 x i16> [[TMP15]], i32 7, i32 2)
+// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x half>
+// CHECK: [[TMP13:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x half>
+// CHECK: [[TMP14:%.*]] = bitcast <16 x i8> [[TMP9]] to <8 x half>
+// CHECK: [[TMP15:%.*]] = bitcast <16 x i8> [[TMP11]] to <8 x half>
+// CHECK: call void @llvm.arm.neon.vst4lane.p0i8.v8f16(i8* [[TMP3]], <8 x half> [[TMP12]], <8 x half> [[TMP13]], <8 x half> [[TMP14]], <8 x half> [[TMP15]], i32 7, i32 2)
// CHECK: ret void
void test_vst4q_lane_f16(float16_t * a, float16x8x4_t b) {
vst4q_lane_f16(a, b, 7);
@@ -19520,11 +19514,11 @@ void test_vst4_lane_s32(int32_t * a, int32x2x4_t b) {
// CHECK: [[ARRAYIDX6:%.*]] = getelementptr inbounds [4 x <4 x half>], [4 x <4 x half>]* [[VAL5]], i32 0, i32 3
// CHECK: [[TMP10:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX6]], align 8
// CHECK: [[TMP11:%.*]] = bitcast <4 x half> [[TMP10]] to <8 x i8>
-// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x i16>
-// CHECK: [[TMP13:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x i16>
-// CHECK: [[TMP14:%.*]] = bitcast <8 x i8> [[TMP9]] to <4 x i16>
-// CHECK: [[TMP15:%.*]] = bitcast <8 x i8> [[TMP11]] to <4 x i16>
-// CHECK: call void @llvm.arm.neon.vst4lane.p0i8.v4i16(i8* [[TMP3]], <4 x i16> [[TMP12]], <4 x i16> [[TMP13]], <4 x i16> [[TMP14]], <4 x i16> [[TMP15]], i32 3, i32 2)
+// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x half>
+// CHECK: [[TMP13:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x half>
+// CHECK: [[TMP14:%.*]] = bitcast <8 x i8> [[TMP9]] to <4 x half>
+// CHECK: [[TMP15:%.*]] = bitcast <8 x i8> [[TMP11]] to <4 x half>
+// CHECK: call void @llvm.arm.neon.vst4lane.p0i8.v4f16(i8* [[TMP3]], <4 x half> [[TMP12]], <4 x half> [[TMP13]], <4 x half> [[TMP14]], <4 x half> [[TMP15]], i32 3, i32 2)
// CHECK: ret void
void test_vst4_lane_f16(float16_t * a, float16x4x4_t b) {
vst4_lane_f16(a, b, 3);
diff --git a/test/CodeGen/default-address-space.c b/test/CodeGen/default-address-space.c
index 07ddf48fac2f..fc5f55ffd6f4 100644
--- a/test/CodeGen/default-address-space.c
+++ b/test/CodeGen/default-address-space.c
@@ -22,9 +22,10 @@ int *B;
int test1() { return foo; }
// COM-LABEL: define i32 @test2(i32 %i)
-// PIZ: load i32, i32 addrspace(4)*
+// COM: %[[addr:.*]] = getelementptr
+// PIZ: load i32, i32 addrspace(4)* %[[addr]]
// PIZ-NEXT: ret i32
-// CHECK: load i32, i32*
+// CHECK: load i32, i32* %[[addr]]
// CHECK-NEXT: ret i32
int test2(int i) { return ban[i]; }
@@ -42,15 +43,17 @@ void test3() {
}
// PIZ-LABEL: define void @test4(i32 addrspace(4)* %a)
-// PIZ: %[[a_addr:.*]] = alloca i32 addrspace(4)*
-// PIZ: store i32 addrspace(4)* %a, i32 addrspace(4)** %[[a_addr]]
-// PIZ: %[[r0:.*]] = load i32 addrspace(4)*, i32 addrspace(4)** %[[a_addr]]
+// PIZ: %[[alloca:.*]] = alloca i32 addrspace(4)*
+// PIZ: %[[a_addr:.*]] = addrspacecast{{.*}} %[[alloca]] to i32 addrspace(4)* addrspace(4)*
+// PIZ: store i32 addrspace(4)* %a, i32 addrspace(4)* addrspace(4)* %[[a_addr]]
+// PIZ: %[[r0:.*]] = load i32 addrspace(4)*, i32 addrspace(4)* addrspace(4)* %[[a_addr]]
// PIZ: %[[arrayidx:.*]] = getelementptr inbounds i32, i32 addrspace(4)* %[[r0]]
// PIZ: store i32 0, i32 addrspace(4)* %[[arrayidx]]
// CHECK-LABEL: define void @test4(i32* %a)
-// CHECK: %[[a_addr:.*]] = alloca i32*, align 4, addrspace(5)
-// CHECK: store i32* %a, i32* addrspace(5)* %[[a_addr]]
-// CHECK: %[[r0:.*]] = load i32*, i32* addrspace(5)* %[[a_addr]]
+// CHECK: %[[alloca:.*]] = alloca i32*, align 4, addrspace(5)
+// CHECK: %[[a_addr:.*]] = addrspacecast{{.*}} %[[alloca]] to i32**
+// CHECK: store i32* %a, i32** %[[a_addr]]
+// CHECK: %[[r0:.*]] = load i32*, i32** %[[a_addr]]
// CHECK: %[[arrayidx:.*]] = getelementptr inbounds i32, i32* %[[r0]]
// CHECK: store i32 0, i32* %[[arrayidx]]
void test4(int *a) {
diff --git a/test/CodeGen/mcount.c b/test/CodeGen/mcount.c
index 7f915841952e..2839d8ef6af3 100644
--- a/test/CodeGen/mcount.c
+++ b/test/CodeGen/mcount.c
@@ -1,18 +1,18 @@
// RUN: %clang_cc1 -pg -triple i386-unknown-unknown -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -pg -triple i386-unknown-unknown -emit-llvm -O2 -o - %s | FileCheck %s
-// RUN: %clang_cc1 -pg -triple powerpc-unknown-gnu-linux -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
-// RUN: %clang_cc1 -pg -triple powerpc64-unknown-gnu-linux -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
-// RUN: %clang_cc1 -pg -triple powerpc64le-unknown-gnu-linux -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
-// RUN: %clang_cc1 -pg -triple i386-netbsd -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
-// RUN: %clang_cc1 -pg -triple x86_64-netbsd -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
-// RUN: %clang_cc1 -pg -triple arm-netbsd-eabi -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
-// RUN: %clang_cc1 -pg -triple aarch64-netbsd -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
-// RUN: %clang_cc1 -pg -triple mips-netbsd -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
-// RUN: %clang_cc1 -pg -triple powerpc-netbsd -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
-// RUN: %clang_cc1 -pg -triple powerpc64-netbsd -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
-// RUN: %clang_cc1 -pg -triple powerpc64le-netbsd -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
-// RUN: %clang_cc1 -pg -triple sparc-netbsd -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
-// RUN: %clang_cc1 -pg -triple sparc64-netbsd -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-PREFIXED %s
+// RUN: %clang_cc1 -pg -triple powerpc-unknown-gnu-linux -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s
+// RUN: %clang_cc1 -pg -triple powerpc64-unknown-gnu-linux -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s
+// RUN: %clang_cc1 -pg -triple powerpc64le-unknown-gnu-linux -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s
+// RUN: %clang_cc1 -pg -triple i386-netbsd -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s
+// RUN: %clang_cc1 -pg -triple x86_64-netbsd -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s
+// RUN: %clang_cc1 -pg -triple arm-netbsd-eabi -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s
+// RUN: %clang_cc1 -pg -triple aarch64-netbsd -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s
+// RUN: %clang_cc1 -pg -triple mips-netbsd -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s
+// RUN: %clang_cc1 -pg -triple powerpc-netbsd -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s
+// RUN: %clang_cc1 -pg -triple powerpc64-netbsd -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s
+// RUN: %clang_cc1 -pg -triple powerpc64le-netbsd -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s
+// RUN: %clang_cc1 -pg -triple sparc-netbsd -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s
+// RUN: %clang_cc1 -pg -triple sparc64-netbsd -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s
// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s -check-prefix=NO-MCOUNT
int bar(void) {
@@ -23,10 +23,17 @@ int foo(void) {
return bar();
}
-int main(void) {
+int __attribute__((no_instrument_function)) no_instrument(void) {
return foo();
}
-// CHECK: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="mcount"{{.*}} }
-// CHECK-PREFIXED: attributes #{{[0-9]+}} = { {{.*}}"counting-function"="_mcount"{{.*}} }
+int main(void) {
+ return no_instrument();
+}
+
+// CHECK: attributes #0 = { {{.*}}"counting-function"="mcount"{{.*}} }
+// CHECK: attributes #1 = { {{.*}} }
+// CHECK-PREFIXED: attributes #0 = { {{.*}}"counting-function"="_mcount"{{.*}} }
+// CHECK-PREFIXED: attributes #1 = { {{.*}} }
// NO-MCOUNT-NOT: attributes #{{[0-9]}} = { {{.*}}"counting-function"={{.*}} }
+// NO-MCOUNT1-NOT: attributes #1 = { {{.*}}"counting-function"={{.*}} }
diff --git a/test/CodeGen/ms-inline-asm.c b/test/CodeGen/ms-inline-asm.c
index 5182d7f2e81a..d26a660c9b0a 100644
--- a/test/CodeGen/ms-inline-asm.c
+++ b/test/CodeGen/ms-inline-asm.c
@@ -627,6 +627,12 @@ void t43() {
// CHECK: call void asm sideeffect inteldialect "mov eax, $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
}
+void dot_operator(){
+// CHECK-LABEL: define void @dot_operator
+ __asm { mov eax, 3[ebx]A.b}
+// CHECK: call void asm sideeffect inteldialect "mov eax, $$3[ebx].4", "~{eax},~{dirflag},~{fpsr},~{flags}"
+}
+
void call_clobber() {
__asm call t41
// CHECK-LABEL: define void @call_clobber
diff --git a/test/CodeGen/ms-intrinsics-other.c b/test/CodeGen/ms-intrinsics-other.c
new file mode 100644
index 000000000000..d23bc7301801
--- /dev/null
+++ b/test/CodeGen/ms-intrinsics-other.c
@@ -0,0 +1,161 @@
+// RUN: %clang_cc1 -ffreestanding -fms-extensions \
+// RUN: -triple x86_64--darwin -Oz -emit-llvm %s -o - \
+// RUN: | FileCheck %s
+// RUN: %clang_cc1 -ffreestanding -fms-extensions \
+// RUN: -triple x86_64--linux -Oz -emit-llvm %s -o - \
+// RUN: | FileCheck %s
+
+// LP64 targets use 'long' as 'int' for MS intrinsics (-fms-extensions)
+#ifdef __LP64__
+#define LONG int
+#else
+#define LONG long
+#endif
+
+unsigned char test_BitScanForward(unsigned LONG *Index, unsigned LONG Mask) {
+ return _BitScanForward(Index, Mask);
+}
+// CHECK: define{{.*}}i8 @test_BitScanForward(i32* {{[a-z_ ]*}}%Index, i32 {{[a-z_ ]*}}%Mask){{.*}}{
+// CHECK: [[ISNOTZERO:%[a-z0-9._]+]] = icmp eq i32 %Mask, 0
+// CHECK: br i1 [[ISNOTZERO]], label %[[END_LABEL:[a-z0-9._]+]], label %[[ISNOTZERO_LABEL:[a-z0-9._]+]]
+// CHECK: [[END_LABEL]]:
+// CHECK: [[RESULT:%[a-z0-9._]+]] = phi i8 [ 0, %[[ISZERO_LABEL:[a-z0-9._]+]] ], [ 1, %[[ISNOTZERO_LABEL]] ]
+// CHECK: ret i8 [[RESULT]]
+// CHECK: [[ISNOTZERO_LABEL]]:
+// CHECK: [[INDEX:%[0-9]+]] = tail call i32 @llvm.cttz.i32(i32 %Mask, i1 true)
+// CHECK: store i32 [[INDEX]], i32* %Index, align 4
+// CHECK: br label %[[END_LABEL]]
+
+unsigned char test_BitScanReverse(unsigned LONG *Index, unsigned LONG Mask) {
+ return _BitScanReverse(Index, Mask);
+}
+// CHECK: define{{.*}}i8 @test_BitScanReverse(i32* {{[a-z_ ]*}}%Index, i32 {{[a-z_ ]*}}%Mask){{.*}}{
+// CHECK: [[ISNOTZERO:%[0-9]+]] = icmp eq i32 %Mask, 0
+// CHECK: br i1 [[ISNOTZERO]], label %[[END_LABEL:[a-z0-9._]+]], label %[[ISNOTZERO_LABEL:[a-z0-9._]+]]
+// CHECK: [[END_LABEL]]:
+// CHECK: [[RESULT:%[a-z0-9._]+]] = phi i8 [ 0, %[[ISZERO_LABEL:[a-z0-9._]+]] ], [ 1, %[[ISNOTZERO_LABEL]] ]
+// CHECK: ret i8 [[RESULT]]
+// CHECK: [[ISNOTZERO_LABEL]]:
+// CHECK: [[REVINDEX:%[0-9]+]] = tail call i32 @llvm.ctlz.i32(i32 %Mask, i1 true)
+// CHECK: [[INDEX:%[0-9]+]] = xor i32 [[REVINDEX]], 31
+// CHECK: store i32 [[INDEX]], i32* %Index, align 4
+// CHECK: br label %[[END_LABEL]]
+
+#if defined(__x86_64__)
+unsigned char test_BitScanForward64(unsigned LONG *Index, unsigned __int64 Mask) {
+ return _BitScanForward64(Index, Mask);
+}
+// CHECK: define{{.*}}i8 @test_BitScanForward64(i32* {{[a-z_ ]*}}%Index, i64 {{[a-z_ ]*}}%Mask){{.*}}{
+// CHECK: [[ISNOTZERO:%[a-z0-9._]+]] = icmp eq i64 %Mask, 0
+// CHECK: br i1 [[ISNOTZERO]], label %[[END_LABEL:[a-z0-9._]+]], label %[[ISNOTZERO_LABEL:[a-z0-9._]+]]
+// CHECK: [[END_LABEL]]:
+// CHECK: [[RESULT:%[a-z0-9._]+]] = phi i8 [ 0, %[[ISZERO_LABEL:[a-z0-9._]+]] ], [ 1, %[[ISNOTZERO_LABEL]] ]
+// CHECK: ret i8 [[RESULT]]
+// CHECK: [[ISNOTZERO_LABEL]]:
+// CHECK: [[INDEX:%[0-9]+]] = tail call i64 @llvm.cttz.i64(i64 %Mask, i1 true)
+// CHECK: [[TRUNC_INDEX:%[0-9]+]] = trunc i64 [[INDEX]] to i32
+// CHECK: store i32 [[TRUNC_INDEX]], i32* %Index, align 4
+// CHECK: br label %[[END_LABEL]]
+
+unsigned char test_BitScanReverse64(unsigned LONG *Index, unsigned __int64 Mask) {
+ return _BitScanReverse64(Index, Mask);
+}
+// CHECK: define{{.*}}i8 @test_BitScanReverse64(i32* {{[a-z_ ]*}}%Index, i64 {{[a-z_ ]*}}%Mask){{.*}}{
+// CHECK: [[ISNOTZERO:%[0-9]+]] = icmp eq i64 %Mask, 0
+// CHECK: br i1 [[ISNOTZERO]], label %[[END_LABEL:[a-z0-9._]+]], label %[[ISNOTZERO_LABEL:[a-z0-9._]+]]
+// CHECK: [[END_LABEL]]:
+// CHECK: [[RESULT:%[a-z0-9._]+]] = phi i8 [ 0, %[[ISZERO_LABEL:[a-z0-9._]+]] ], [ 1, %[[ISNOTZERO_LABEL]] ]
+// CHECK: ret i8 [[RESULT]]
+// CHECK: [[ISNOTZERO_LABEL]]:
+// CHECK: [[REVINDEX:%[0-9]+]] = tail call i64 @llvm.ctlz.i64(i64 %Mask, i1 true)
+// CHECK: [[TRUNC_REVINDEX:%[0-9]+]] = trunc i64 [[REVINDEX]] to i32
+// CHECK: [[INDEX:%[0-9]+]] = xor i32 [[TRUNC_REVINDEX]], 63
+// CHECK: store i32 [[INDEX]], i32* %Index, align 4
+// CHECK: br label %[[END_LABEL]]
+#endif
+
+LONG test_InterlockedExchange(LONG volatile *value, LONG mask) {
+ return _InterlockedExchange(value, mask);
+}
+// CHECK: define{{.*}}i32 @test_InterlockedExchange(i32*{{[a-z_ ]*}}%value, i32{{[a-z_ ]*}}%mask){{.*}}{
+// CHECK: [[RESULT:%[0-9]+]] = atomicrmw xchg i32* %value, i32 %mask seq_cst
+// CHECK: ret i32 [[RESULT:%[0-9]+]]
+// CHECK: }
+
+LONG test_InterlockedExchangeAdd(LONG volatile *value, LONG mask) {
+ return _InterlockedExchangeAdd(value, mask);
+}
+// CHECK: define{{.*}}i32 @test_InterlockedExchangeAdd(i32*{{[a-z_ ]*}}%value, i32{{[a-z_ ]*}}%mask){{.*}}{
+// CHECK: [[RESULT:%[0-9]+]] = atomicrmw add i32* %value, i32 %mask seq_cst
+// CHECK: ret i32 [[RESULT:%[0-9]+]]
+// CHECK: }
+
+LONG test_InterlockedExchangeSub(LONG volatile *value, LONG mask) {
+ return _InterlockedExchangeSub(value, mask);
+}
+// CHECK: define{{.*}}i32 @test_InterlockedExchangeSub(i32*{{[a-z_ ]*}}%value, i32{{[a-z_ ]*}}%mask){{.*}}{
+// CHECK: [[RESULT:%[0-9]+]] = atomicrmw sub i32* %value, i32 %mask seq_cst
+// CHECK: ret i32 [[RESULT:%[0-9]+]]
+// CHECK: }
+
+LONG test_InterlockedOr(LONG volatile *value, LONG mask) {
+ return _InterlockedOr(value, mask);
+}
+// CHECK: define{{.*}}i32 @test_InterlockedOr(i32*{{[a-z_ ]*}}%value, i32{{[a-z_ ]*}}%mask){{.*}}{
+// CHECK: [[RESULT:%[0-9]+]] = atomicrmw or i32* %value, i32 %mask seq_cst
+// CHECK: ret i32 [[RESULT:%[0-9]+]]
+// CHECK: }
+
+LONG test_InterlockedXor(LONG volatile *value, LONG mask) {
+ return _InterlockedXor(value, mask);
+}
+// CHECK: define{{.*}}i32 @test_InterlockedXor(i32*{{[a-z_ ]*}}%value, i32{{[a-z_ ]*}}%mask){{.*}}{
+// CHECK: [[RESULT:%[0-9]+]] = atomicrmw xor i32* %value, i32 %mask seq_cst
+// CHECK: ret i32 [[RESULT:%[0-9]+]]
+// CHECK: }
+
+LONG test_InterlockedAnd(LONG volatile *value, LONG mask) {
+ return _InterlockedAnd(value, mask);
+}
+// CHECK: define{{.*}}i32 @test_InterlockedAnd(i32*{{[a-z_ ]*}}%value, i32{{[a-z_ ]*}}%mask){{.*}}{
+// CHECK: [[RESULT:%[0-9]+]] = atomicrmw and i32* %value, i32 %mask seq_cst
+// CHECK: ret i32 [[RESULT:%[0-9]+]]
+// CHECK: }
+
+LONG test_InterlockedCompareExchange(LONG volatile *Destination, LONG Exchange, LONG Comperand) {
+ return _InterlockedCompareExchange(Destination, Exchange, Comperand);
+}
+// CHECK: define{{.*}}i32 @test_InterlockedCompareExchange(i32*{{[a-z_ ]*}}%Destination, i32{{[a-z_ ]*}}%Exchange, i32{{[a-z_ ]*}}%Comperand){{.*}}{
+// CHECK: [[TMP:%[0-9]+]] = cmpxchg volatile i32* %Destination, i32 %Comperand, i32 %Exchange seq_cst seq_cst
+// CHECK: [[RESULT:%[0-9]+]] = extractvalue { i32, i1 } [[TMP]], 0
+// CHECK: ret i32 [[RESULT]]
+// CHECK: }
+
+LONG test_InterlockedIncrement(LONG volatile *Addend) {
+ return _InterlockedIncrement(Addend);
+}
+// CHECK: define{{.*}}i32 @test_InterlockedIncrement(i32*{{[a-z_ ]*}}%Addend){{.*}}{
+// CHECK: [[TMP:%[0-9]+]] = atomicrmw add i32* %Addend, i32 1 seq_cst
+// CHECK: [[RESULT:%[0-9]+]] = add i32 [[TMP]], 1
+// CHECK: ret i32 [[RESULT]]
+// CHECK: }
+
+LONG test_InterlockedDecrement(LONG volatile *Addend) {
+ return _InterlockedDecrement(Addend);
+}
+// CHECK: define{{.*}}i32 @test_InterlockedDecrement(i32*{{[a-z_ ]*}}%Addend){{.*}}{
+// CHECK: [[TMP:%[0-9]+]] = atomicrmw sub i32* %Addend, i32 1 seq_cst
+// CHECK: [[RESULT:%[0-9]+]] = add i32 [[TMP]], -1
+// CHECK: ret i32 [[RESULT]]
+// CHECK: }
+
+unsigned char test_interlockedbittestandset(volatile LONG *ptr, LONG bit) {
+ return _interlockedbittestandset(ptr, bit);
+}
+// CHECK-LABEL: define{{.*}} i8 @test_interlockedbittestandset
+// CHECK: [[MASKBIT:%[0-9]+]] = shl i32 1, %bit
+// CHECK: [[OLD:%[0-9]+]] = atomicrmw or i32* %ptr, i32 [[MASKBIT]] seq_cst
+// CHECK: [[SHIFT:%[0-9]+]] = lshr i32 [[OLD]], %bit
+// CHECK: [[TRUNC:%[0-9]+]] = trunc i32 [[SHIFT]] to i8
+// CHECK: [[AND:%[0-9]+]] = and i8 [[TRUNC]], 1
+// CHECK: ret i8 [[AND]]
diff --git a/test/CodeGen/ms-intrinsics-rotations.c b/test/CodeGen/ms-intrinsics-rotations.c
index 65d25cbe85eb..9533e6c3c6a2 100644
--- a/test/CodeGen/ms-intrinsics-rotations.c
+++ b/test/CodeGen/ms-intrinsics-rotations.c
@@ -1,181 +1,169 @@
// RUN: %clang_cc1 -ffreestanding -fms-extensions -fms-compatibility -fms-compatibility-version=17.00 \
// RUN: -triple i686--windows -emit-llvm %s -o - \
-// RUN: | FileCheck %s --check-prefixes CHECK,CHECK-32BIT-LONG
+// RUN: | FileCheck %s --check-prefixes CHECK,CHECK-32BIT-LONG
// RUN: %clang_cc1 -ffreestanding -fms-extensions -fms-compatibility -fms-compatibility-version=17.00 \
// RUN: -triple thumbv7--windows -emit-llvm %s -o - \
-// RUN: | FileCheck %s --check-prefixes CHECK,CHECK-32BIT-LONG
+// RUN: | FileCheck %s --check-prefixes CHECK,CHECK-32BIT-LONG
// RUN: %clang_cc1 -ffreestanding -fms-extensions -fms-compatibility -fms-compatibility-version=17.00 \
// RUN: -triple x86_64--windows -emit-llvm %s -o - \
-// RUN: | FileCheck %s --check-prefixes CHECK,CHECK-32BIT-LONG
+// RUN: | FileCheck %s --check-prefixes CHECK,CHECK-32BIT-LONG
// RUN: %clang_cc1 -ffreestanding -fms-extensions -fms-compatibility -fms-compatibility-version=17.00 \
// RUN: -triple i686--linux -emit-llvm %s -o - \
-// RUN: | FileCheck %s --check-prefixes CHECK,CHECK-32BIT-LONG
+// RUN: | FileCheck %s --check-prefixes CHECK,CHECK-32BIT-LONG
// RUN: %clang_cc1 -ffreestanding -fms-extensions -fms-compatibility -fms-compatibility-version=17.00 \
// RUN: -triple x86_64--linux -emit-llvm %s -o - \
-// RUN: | FileCheck %s --check-prefixes CHECK,CHECK-64BIT-LONG
-
-// rotate left
-
-unsigned char test_rotl8(unsigned char value, unsigned char shift) {
- return _rotl8(value, shift);
-}
-// CHECK: i8 @test_rotl8
-// CHECK: [[SHIFT:%[0-9]+]] = and i8 %{{[0-9]+}}, 7
-// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i8 8, [[SHIFT]]
-// CHECK: [[HIGH:%[0-9]+]] = shl i8 [[VALUE:%[0-9]+]], [[SHIFT]]
-// CHECK: [[LOW:%[0-9]+]] = lshr i8 [[VALUE]], [[NEGSHIFT]]
-// CHECK: [[ROTATED:%[0-9]+]] = or i8 [[HIGH]], [[LOW]]
-// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i8 [[SHIFT]], 0
-// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i8 [[VALUE]], i8 [[ROTATED]]
-// CHECK: ret i8 [[RESULT]]
-// CHECK }
-
-unsigned short test_rotl16(unsigned short value, unsigned char shift) {
- return _rotl16(value, shift);
-}
-// CHECK: i16 @test_rotl16
-// CHECK: [[SHIFT:%[0-9]+]] = and i16 %{{[0-9]+}}, 15
-// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i16 16, [[SHIFT]]
-// CHECK: [[HIGH:%[0-9]+]] = shl i16 [[VALUE:%[0-9]+]], [[SHIFT]]
-// CHECK: [[LOW:%[0-9]+]] = lshr i16 [[VALUE]], [[NEGSHIFT]]
-// CHECK: [[ROTATED:%[0-9]+]] = or i16 [[HIGH]], [[LOW]]
-// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i16 [[SHIFT]], 0
-// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i16 [[VALUE]], i16 [[ROTATED]]
-// CHECK: ret i16 [[RESULT]]
-// CHECK }
-
-unsigned int test_rotl(unsigned int value, int shift) {
- return _rotl(value, shift);
-}
-// CHECK: i32 @test_rotl
-// CHECK: [[SHIFT:%[0-9]+]] = and i32 %{{[0-9]+}}, 31
-// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i32 32, [[SHIFT]]
-// CHECK: [[HIGH:%[0-9]+]] = shl i32 [[VALUE:%[0-9]+]], [[SHIFT]]
-// CHECK: [[LOW:%[0-9]+]] = lshr i32 [[VALUE]], [[NEGSHIFT]]
-// CHECK: [[ROTATED:%[0-9]+]] = or i32 [[HIGH]], [[LOW]]
-// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i32 [[SHIFT]], 0
-// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i32 [[VALUE]], i32 [[ROTATED]]
-// CHECK: ret i32 [[RESULT]]
-// CHECK }
-
-unsigned long test_lrotl(unsigned long value, int shift) {
- return _lrotl(value, shift);
-}
-// CHECK-32BIT-LONG: i32 @test_lrotl
-// CHECK-32BIT-LONG: [[SHIFT:%[0-9]+]] = and i32 %{{[0-9]+}}, 31
-// CHECK-32BIT-LONG: [[NEGSHIFT:%[0-9]+]] = sub i32 32, [[SHIFT]]
-// CHECK-32BIT-LONG: [[HIGH:%[0-9]+]] = shl i32 [[VALUE:%[0-9]+]], [[SHIFT]]
-// CHECK-32BIT-LONG: [[LOW:%[0-9]+]] = lshr i32 [[VALUE]], [[NEGSHIFT]]
-// CHECK-32BIT-LONG: [[ROTATED:%[0-9]+]] = or i32 [[HIGH]], [[LOW]]
-// CHECK-32BIT-LONG: [[ISZERO:%[0-9]+]] = icmp eq i32 [[SHIFT]], 0
-// CHECK-32BIT-LONG: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i32 [[VALUE]], i32 [[ROTATED]]
-// CHECK-32BIT-LONG: ret i32 [[RESULT]]
-// CHECK-32BIT-LONG }
-
-// CHECK-64BIT-LONG: i64 @test_lrotl
-// CHECK-64BIT-LONG: [[SHIFT:%[0-9]+]] = and i64 %{{[0-9]+}}, 63
-// CHECK-64BIT-LONG: [[NEGSHIFT:%[0-9]+]] = sub i64 64, [[SHIFT]]
-// CHECK-64BIT-LONG: [[HIGH:%[0-9]+]] = shl i64 [[VALUE:%[0-9]+]], [[SHIFT]]
-// CHECK-64BIT-LONG: [[LOW:%[0-9]+]] = lshr i64 [[VALUE]], [[NEGSHIFT]]
-// CHECK-64BIT-LONG: [[ROTATED:%[0-9]+]] = or i64 [[HIGH]], [[LOW]]
-// CHECK-64BIT-LONG: [[ISZERO:%[0-9]+]] = icmp eq i64 [[SHIFT]], 0
-// CHECK-64BIT-LONG: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i64 [[VALUE]], i64 [[ROTATED]]
-// CHECK-64BIT-LONG: ret i64 [[RESULT]]
-// CHECK-64BIT-LONG }
-
-unsigned __int64 test_rotl64(unsigned __int64 value, int shift) {
- return _rotl64(value, shift);
-}
-// CHECK: i64 @test_rotl64
-// CHECK: [[SHIFT:%[0-9]+]] = and i64 %{{[0-9]+}}, 63
-// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i64 64, [[SHIFT]]
-// CHECK: [[HIGH:%[0-9]+]] = shl i64 [[VALUE:%[0-9]+]], [[SHIFT]]
-// CHECK: [[LOW:%[0-9]+]] = lshr i64 [[VALUE]], [[NEGSHIFT]]
-// CHECK: [[ROTATED:%[0-9]+]] = or i64 [[HIGH]], [[LOW]]
-// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i64 [[SHIFT]], 0
-// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i64 [[VALUE]], i64 [[ROTATED]]
-// CHECK: ret i64 [[RESULT]]
-// CHECK }
-
-// rotate right
-
-unsigned char test_rotr8(unsigned char value, unsigned char shift) {
- return _rotr8(value, shift);
-}
-// CHECK: i8 @test_rotr8
-// CHECK: [[SHIFT:%[0-9]+]] = and i8 %{{[0-9]+}}, 7
-// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i8 8, [[SHIFT]]
-// CHECK: [[LOW:%[0-9]+]] = lshr i8 [[VALUE:%[0-9]+]], [[SHIFT]]
-// CHECK: [[HIGH:%[0-9]+]] = shl i8 [[VALUE]], [[NEGSHIFT]]
-// CHECK: [[ROTATED:%[0-9]+]] = or i8 [[HIGH]], [[LOW]]
-// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i8 [[SHIFT]], 0
-// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i8 [[VALUE]], i8 [[ROTATED]]
-// CHECK: ret i8 [[RESULT]]
-// CHECK }
-
-unsigned short test_rotr16(unsigned short value, unsigned char shift) {
- return _rotr16(value, shift);
-}
-// CHECK: i16 @test_rotr16
-// CHECK: [[SHIFT:%[0-9]+]] = and i16 %{{[0-9]+}}, 15
-// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i16 16, [[SHIFT]]
-// CHECK: [[LOW:%[0-9]+]] = lshr i16 [[VALUE:%[0-9]+]], [[SHIFT]]
-// CHECK: [[HIGH:%[0-9]+]] = shl i16 [[VALUE]], [[NEGSHIFT]]
-// CHECK: [[ROTATED:%[0-9]+]] = or i16 [[HIGH]], [[LOW]]
-// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i16 [[SHIFT]], 0
-// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i16 [[VALUE]], i16 [[ROTATED]]
-// CHECK: ret i16 [[RESULT]]
-// CHECK }
-
-unsigned int test_rotr(unsigned int value, int shift) {
- return _rotr(value, shift);
-}
-// CHECK: i32 @test_rotr
-// CHECK: [[SHIFT:%[0-9]+]] = and i32 %{{[0-9]+}}, 31
-// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i32 32, [[SHIFT]]
-// CHECK: [[LOW:%[0-9]+]] = lshr i32 [[VALUE:%[0-9]+]], [[SHIFT]]
-// CHECK: [[HIGH:%[0-9]+]] = shl i32 [[VALUE]], [[NEGSHIFT]]
-// CHECK: [[ROTATED:%[0-9]+]] = or i32 [[HIGH]], [[LOW]]
-// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i32 [[SHIFT]], 0
-// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i32 [[VALUE]], i32 [[ROTATED]]
-// CHECK: ret i32 [[RESULT]]
-// CHECK }
-
-unsigned long test_lrotr(unsigned long value, int shift) {
- return _lrotr(value, shift);
-}
-// CHECK-32BIT-LONG: i32 @test_lrotr
-// CHECK-32BIT-LONG: [[SHIFT:%[0-9]+]] = and i32 %{{[0-9]+}}, 31
-// CHECK-32BIT-LONG: [[NEGSHIFT:%[0-9]+]] = sub i32 32, [[SHIFT]]
-// CHECK-32BIT-LONG: [[LOW:%[0-9]+]] = lshr i32 [[VALUE:%[0-9]+]], [[SHIFT]]
-// CHECK-32BIT-LONG: [[HIGH:%[0-9]+]] = shl i32 [[VALUE]], [[NEGSHIFT]]
-// CHECK-32BIT-LONG: [[ROTATED:%[0-9]+]] = or i32 [[HIGH]], [[LOW]]
-// CHECK-32BIT-LONG: [[ISZERO:%[0-9]+]] = icmp eq i32 [[SHIFT]], 0
-// CHECK-32BIT-LONG: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i32 [[VALUE]], i32 [[ROTATED]]
-// CHECK-32BIT-LONG: ret i32 [[RESULT]]
-// CHECK-32BIT-LONG }
-
-// CHECK-64BIT-LONG: i64 @test_lrotr
-// CHECK-64BIT-LONG: [[SHIFT:%[0-9]+]] = and i64 %{{[0-9]+}}, 63
-// CHECK-64BIT-LONG: [[NEGSHIFT:%[0-9]+]] = sub i64 64, [[SHIFT]]
-// CHECK-64BIT-LONG: [[LOW:%[0-9]+]] = lshr i64 [[VALUE:%[0-9]+]], [[SHIFT]]
-// CHECK-64BIT-LONG: [[HIGH:%[0-9]+]] = shl i64 [[VALUE]], [[NEGSHIFT]]
-// CHECK-64BIT-LONG: [[ROTATED:%[0-9]+]] = or i64 [[HIGH]], [[LOW]]
-// CHECK-64BIT-LONG: [[ISZERO:%[0-9]+]] = icmp eq i64 [[SHIFT]], 0
-// CHECK-64BIT-LONG: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i64 [[VALUE]], i64 [[ROTATED]]
-// CHECK-64BIT-LONG: ret i64 [[RESULT]]
-// CHECK-64BIT-LONG }
-
-unsigned __int64 test_rotr64(unsigned __int64 value, int shift) {
- return _rotr64(value, shift);
-}
-// CHECK: i64 @test_rotr64
-// CHECK: [[SHIFT:%[0-9]+]] = and i64 %{{[0-9]+}}, 63
-// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i64 64, [[SHIFT]]
-// CHECK: [[LOW:%[0-9]+]] = lshr i64 [[VALUE:%[0-9]+]], [[SHIFT]]
-// CHECK: [[HIGH:%[0-9]+]] = shl i64 [[VALUE]], [[NEGSHIFT]]
-// CHECK: [[ROTATED:%[0-9]+]] = or i64 [[HIGH]], [[LOW]]
-// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i64 [[SHIFT]], 0
-// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i64 [[VALUE]], i64 [[ROTATED]]
-// CHECK: ret i64 [[RESULT]]
-// CHECK }
+// RUN: | FileCheck %s --check-prefixes CHECK,CHECK-32BIT-LONG
+// RUN: %clang_cc1 -ffreestanding -fms-extensions \
+// RUN: -triple x86_64--darwin -emit-llvm %s -o - \
+// RUN: | FileCheck %s --check-prefixes CHECK,CHECK-32BIT-LONG
+
+// LP64 targets use 'long' as 'int' for MS intrinsics (-fms-extensions)
+#ifdef __LP64__
+#define LONG int
+#else
+#define LONG long
+#endif
+
+// rotate left
+
+unsigned char test_rotl8(unsigned char value, unsigned char shift) {
+ return _rotl8(value, shift);
+}
+// CHECK: i8 @test_rotl8
+// CHECK: [[SHIFT:%[0-9]+]] = and i8 %{{[0-9]+}}, 7
+// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i8 8, [[SHIFT]]
+// CHECK: [[HIGH:%[0-9]+]] = shl i8 [[VALUE:%[0-9]+]], [[SHIFT]]
+// CHECK: [[LOW:%[0-9]+]] = lshr i8 [[VALUE]], [[NEGSHIFT]]
+// CHECK: [[ROTATED:%[0-9]+]] = or i8 [[HIGH]], [[LOW]]
+// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i8 [[SHIFT]], 0
+// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i8 [[VALUE]], i8 [[ROTATED]]
+// CHECK: ret i8 [[RESULT]]
+// CHECK }
+
+unsigned short test_rotl16(unsigned short value, unsigned char shift) {
+ return _rotl16(value, shift);
+}
+// CHECK: i16 @test_rotl16
+// CHECK: [[SHIFT:%[0-9]+]] = and i16 %{{[0-9]+}}, 15
+// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i16 16, [[SHIFT]]
+// CHECK: [[HIGH:%[0-9]+]] = shl i16 [[VALUE:%[0-9]+]], [[SHIFT]]
+// CHECK: [[LOW:%[0-9]+]] = lshr i16 [[VALUE]], [[NEGSHIFT]]
+// CHECK: [[ROTATED:%[0-9]+]] = or i16 [[HIGH]], [[LOW]]
+// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i16 [[SHIFT]], 0
+// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i16 [[VALUE]], i16 [[ROTATED]]
+// CHECK: ret i16 [[RESULT]]
+// CHECK }
+
+unsigned int test_rotl(unsigned int value, int shift) {
+ return _rotl(value, shift);
+}
+// CHECK: i32 @test_rotl
+// CHECK: [[SHIFT:%[0-9]+]] = and i32 %{{[0-9]+}}, 31
+// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i32 32, [[SHIFT]]
+// CHECK: [[HIGH:%[0-9]+]] = shl i32 [[VALUE:%[0-9]+]], [[SHIFT]]
+// CHECK: [[LOW:%[0-9]+]] = lshr i32 [[VALUE]], [[NEGSHIFT]]
+// CHECK: [[ROTATED:%[0-9]+]] = or i32 [[HIGH]], [[LOW]]
+// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i32 [[SHIFT]], 0
+// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i32 [[VALUE]], i32 [[ROTATED]]
+// CHECK: ret i32 [[RESULT]]
+// CHECK }
+
+unsigned LONG test_lrotl(unsigned LONG value, int shift) {
+ return _lrotl(value, shift);
+}
+// CHECK-32BIT-LONG: i32 @test_lrotl
+// CHECK-32BIT-LONG: [[SHIFT:%[0-9]+]] = and i32 %{{[0-9]+}}, 31
+// CHECK-32BIT-LONG: [[NEGSHIFT:%[0-9]+]] = sub i32 32, [[SHIFT]]
+// CHECK-32BIT-LONG: [[HIGH:%[0-9]+]] = shl i32 [[VALUE:%[0-9]+]], [[SHIFT]]
+// CHECK-32BIT-LONG: [[LOW:%[0-9]+]] = lshr i32 [[VALUE]], [[NEGSHIFT]]
+// CHECK-32BIT-LONG: [[ROTATED:%[0-9]+]] = or i32 [[HIGH]], [[LOW]]
+// CHECK-32BIT-LONG: [[ISZERO:%[0-9]+]] = icmp eq i32 [[SHIFT]], 0
+// CHECK-32BIT-LONG: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i32 [[VALUE]], i32 [[ROTATED]]
+// CHECK-32BIT-LONG: ret i32 [[RESULT]]
+// CHECK-32BIT-LONG }
+
+unsigned __int64 test_rotl64(unsigned __int64 value, int shift) {
+ return _rotl64(value, shift);
+}
+// CHECK: i64 @test_rotl64
+// CHECK: [[SHIFT:%[0-9]+]] = and i64 %{{[0-9]+}}, 63
+// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i64 64, [[SHIFT]]
+// CHECK: [[HIGH:%[0-9]+]] = shl i64 [[VALUE:%[0-9]+]], [[SHIFT]]
+// CHECK: [[LOW:%[0-9]+]] = lshr i64 [[VALUE]], [[NEGSHIFT]]
+// CHECK: [[ROTATED:%[0-9]+]] = or i64 [[HIGH]], [[LOW]]
+// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i64 [[SHIFT]], 0
+// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i64 [[VALUE]], i64 [[ROTATED]]
+// CHECK: ret i64 [[RESULT]]
+// CHECK }
+
+// rotate right
+
+unsigned char test_rotr8(unsigned char value, unsigned char shift) {
+ return _rotr8(value, shift);
+}
+// CHECK: i8 @test_rotr8
+// CHECK: [[SHIFT:%[0-9]+]] = and i8 %{{[0-9]+}}, 7
+// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i8 8, [[SHIFT]]
+// CHECK: [[LOW:%[0-9]+]] = lshr i8 [[VALUE:%[0-9]+]], [[SHIFT]]
+// CHECK: [[HIGH:%[0-9]+]] = shl i8 [[VALUE]], [[NEGSHIFT]]
+// CHECK: [[ROTATED:%[0-9]+]] = or i8 [[HIGH]], [[LOW]]
+// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i8 [[SHIFT]], 0
+// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i8 [[VALUE]], i8 [[ROTATED]]
+// CHECK: ret i8 [[RESULT]]
+// CHECK }
+
+unsigned short test_rotr16(unsigned short value, unsigned char shift) {
+ return _rotr16(value, shift);
+}
+// CHECK: i16 @test_rotr16
+// CHECK: [[SHIFT:%[0-9]+]] = and i16 %{{[0-9]+}}, 15
+// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i16 16, [[SHIFT]]
+// CHECK: [[LOW:%[0-9]+]] = lshr i16 [[VALUE:%[0-9]+]], [[SHIFT]]
+// CHECK: [[HIGH:%[0-9]+]] = shl i16 [[VALUE]], [[NEGSHIFT]]
+// CHECK: [[ROTATED:%[0-9]+]] = or i16 [[HIGH]], [[LOW]]
+// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i16 [[SHIFT]], 0
+// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i16 [[VALUE]], i16 [[ROTATED]]
+// CHECK: ret i16 [[RESULT]]
+// CHECK }
+
+unsigned int test_rotr(unsigned int value, int shift) {
+ return _rotr(value, shift);
+}
+// CHECK: i32 @test_rotr
+// CHECK: [[SHIFT:%[0-9]+]] = and i32 %{{[0-9]+}}, 31
+// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i32 32, [[SHIFT]]
+// CHECK: [[LOW:%[0-9]+]] = lshr i32 [[VALUE:%[0-9]+]], [[SHIFT]]
+// CHECK: [[HIGH:%[0-9]+]] = shl i32 [[VALUE]], [[NEGSHIFT]]
+// CHECK: [[ROTATED:%[0-9]+]] = or i32 [[HIGH]], [[LOW]]
+// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i32 [[SHIFT]], 0
+// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i32 [[VALUE]], i32 [[ROTATED]]
+// CHECK: ret i32 [[RESULT]]
+// CHECK }
+
+unsigned LONG test_lrotr(unsigned LONG value, int shift) {
+ return _lrotr(value, shift);
+}
+// CHECK-32BIT-LONG: i32 @test_lrotr
+// CHECK-32BIT-LONG: [[SHIFT:%[0-9]+]] = and i32 %{{[0-9]+}}, 31
+// CHECK-32BIT-LONG: [[NEGSHIFT:%[0-9]+]] = sub i32 32, [[SHIFT]]
+// CHECK-32BIT-LONG: [[LOW:%[0-9]+]] = lshr i32 [[VALUE:%[0-9]+]], [[SHIFT]]
+// CHECK-32BIT-LONG: [[HIGH:%[0-9]+]] = shl i32 [[VALUE]], [[NEGSHIFT]]
+// CHECK-32BIT-LONG: [[ROTATED:%[0-9]+]] = or i32 [[HIGH]], [[LOW]]
+// CHECK-32BIT-LONG: [[ISZERO:%[0-9]+]] = icmp eq i32 [[SHIFT]], 0
+// CHECK-32BIT-LONG: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i32 [[VALUE]], i32 [[ROTATED]]
+// CHECK-32BIT-LONG: ret i32 [[RESULT]]
+// CHECK-32BIT-LONG }
+
+unsigned __int64 test_rotr64(unsigned __int64 value, int shift) {
+ return _rotr64(value, shift);
+}
+// CHECK: i64 @test_rotr64
+// CHECK: [[SHIFT:%[0-9]+]] = and i64 %{{[0-9]+}}, 63
+// CHECK: [[NEGSHIFT:%[0-9]+]] = sub i64 64, [[SHIFT]]
+// CHECK: [[LOW:%[0-9]+]] = lshr i64 [[VALUE:%[0-9]+]], [[SHIFT]]
+// CHECK: [[HIGH:%[0-9]+]] = shl i64 [[VALUE]], [[NEGSHIFT]]
+// CHECK: [[ROTATED:%[0-9]+]] = or i64 [[HIGH]], [[LOW]]
+// CHECK: [[ISZERO:%[0-9]+]] = icmp eq i64 [[SHIFT]], 0
+// CHECK: [[RESULT:%[0-9]+]] = select i1 [[ISZERO]], i64 [[VALUE]], i64 [[ROTATED]]
+// CHECK: ret i64 [[RESULT]]
+// CHECK }
diff --git a/test/CodeGen/no-devirt.cpp b/test/CodeGen/no-devirt.cpp
new file mode 100644
index 000000000000..4333b7cde7c6
--- /dev/null
+++ b/test/CodeGen/no-devirt.cpp
@@ -0,0 +1,59 @@
+// RUN: %clang_cc1 %s -DUSEIT -triple %itanium_abi_triple -emit-llvm -o - | FileCheck %s
+
+// Test with decls and template defs in pch, and just use in .cpp
+// RUN: %clang_cc1 %s -DTMPL_DEF_IN_HEADER -triple %itanium_abi_triple -emit-pch -o %t
+// RUN: %clang_cc1 %s -DTMPL_DEF_IN_HEADER -DUSEIT -triple %itanium_abi_triple -include-pch %t -emit-llvm -o - | FileCheck %s
+
+// Test with A in pch, and B and C in main
+// Test with just decls in pch, and template defs and use in .cpp
+// RUN: %clang_cc1 %s -triple %itanium_abi_triple -emit-pch -o %t
+// RUN: %clang_cc1 %s -DUSEIT -triple %itanium_abi_triple -include-pch %t -emit-llvm -o - | FileCheck %s
+
+#ifndef HEADER
+#define HEADER
+template < typename T, int N = 0 > class TmplWithArray {
+public:
+ virtual T& operator [] (int idx);
+ virtual T& func1 (int idx);
+ virtual T& func2 (int idx);
+ T ar[N+1];
+};
+struct Wrapper {
+ TmplWithArray<bool, 10> data;
+ bool indexIt(int a) {
+ if (a > 6) return data[a] ; // Should not devirtualize
+ if (a > 4) return data.func1(a); // Should devirtualize
+ return data.func2(a); // Should devirtualize
+ }
+};
+
+#ifdef TMPL_DEF_IN_HEADER
+template <typename T, int N> T& TmplWithArray<T, N >::operator[](int idx) {
+ return ar[idx];
+}
+template <typename T, int N> T& TmplWithArray<T, N >::func1(int idx) {
+ return ar[idx];
+}
+#endif // TMPL_DEF_IN_HEADER
+#endif // HEADER
+
+#ifdef USEIT
+#ifndef TMPL_DEF_IN_HEADER
+template <typename T, int N> T& TmplWithArray<T, N >::operator[](int idx) {
+ return ar[idx];
+}
+template <typename T, int N> T& TmplWithArray<T, N >::func1(int idx) {
+ return ar[idx];
+}
+#endif // !TMPL_DEF_IN_HEADER
+extern Wrapper ew;
+bool stuff(int p)
+{
+ return ew.indexIt(p);
+}
+#endif
+
+// CHECK-NOT: call {{.*}} @_ZN13TmplWithArrayIbLi10EEixEi
+// CHECK-DAG: call {{.*}} @_ZN13TmplWithArrayIbLi10EE5func1Ei
+// CHECK-DAG: call {{.*}} @_ZN13TmplWithArrayIbLi10EE5func2Ei
+
diff --git a/test/CodeGen/pr27892.c b/test/CodeGen/pr27892.c
deleted file mode 100644
index 57722c4671ab..000000000000
--- a/test/CodeGen/pr27892.c
+++ /dev/null
@@ -1,23 +0,0 @@
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -fms-extensions %s -emit-llvm -o - | FileCheck %s
-
-long test1(long *p) {
- return _InterlockedIncrement(p);
-}
-// CHECK-DAG: define i64 @test1(
-// CHECK: %[[p_addr:.*]] = alloca i64*, align 8
-// CHECK: store i64* %p, i64** %[[p_addr]], align 8
-// CHECK: %[[p_load:.*]] = load i64*, i64** %[[p_addr]], align 8
-// CHECK: %[[atomic_add:.*]] = atomicrmw add i64* %[[p_load]], i64 1 seq_cst
-// CHECK: %[[res:.*]] = add i64 %[[atomic_add]], 1
-// CHECK: ret i64 %[[res]]
-
-long test2(long *p) {
- return _InterlockedDecrement(p);
-}
-// CHECK-DAG: define i64 @test2(
-// CHECK: %[[p_addr:.*]] = alloca i64*, align 8
-// CHECK: store i64* %p, i64** %[[p_addr]], align 8
-// CHECK: %[[p_load:.*]] = load i64*, i64** %[[p_addr]], align 8
-// CHECK: %[[atomic_sub:.*]] = atomicrmw sub i64* %[[p_load]], i64 1 seq_cst
-// CHECK: %[[res:.*]] = sub i64 %[[atomic_sub]], 1
-// CHECK: ret i64 %[[res]]
diff --git a/test/CodeGen/target-data.c b/test/CodeGen/target-data.c
index 1e8ce6a2fd12..68ee8f02d2ee 100644
--- a/test/CodeGen/target-data.c
+++ b/test/CodeGen/target-data.c
@@ -175,7 +175,7 @@
// RUN: %clang_cc1 -triple msp430-unknown -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=MSP430
-// MSP430: target datalayout = "e-m:e-p:16:16-i32:16:32-a:16-n8:16"
+// MSP430: target datalayout = "e-m:e-p:16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S16"
// RUN: %clang_cc1 -triple tce-unknown -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=TCE
diff --git a/test/CodeGen/vectorcall.c b/test/CodeGen/vectorcall.c
index 167f72ca2cfd..fa244fb908e0 100644
--- a/test/CodeGen/vectorcall.c
+++ b/test/CodeGen/vectorcall.c
@@ -100,8 +100,19 @@ void __vectorcall odd_size_hva(struct OddSizeHVA a) {}
// X32: define x86_vectorcallcc void @"\01odd_size_hva@@32"(%struct.OddSizeHVA inreg %a.coerce)
// X64: define x86_vectorcallcc void @"\01odd_size_hva@@32"(%struct.OddSizeHVA inreg %a.coerce)
-// The Vectorcall ABI only allows passing the first 6 items in registers, so this shouldn't
+// The Vectorcall ABI only allows passing the first 6 items in registers in x64, so this shouldn't
// consider 'p7' as a register. Instead p5 gets put into the register on the second pass.
-struct HFA2 __vectorcall AddParticles(struct HFA2 p1, float p2, struct HFA4 p3, int p4, struct HFA2 p5, float p6, float p7){ return p1;}
-// X32: define x86_vectorcallcc %struct.HFA2 @"\01AddParticles@@80"(%struct.HFA2 inreg %p1.coerce, float %p2, %struct.HFA4* inreg %p3, i32 inreg %p4, %struct.HFA2 inreg %p5.coerce, float %p6, float %p7)
-// X64: define x86_vectorcallcc %struct.HFA2 @"\01AddParticles@@96"(%struct.HFA2 inreg %p1.coerce, float %p2, %struct.HFA4* %p3, i32 %p4, %struct.HFA2 inreg %p5.coerce, float %p6, float %p7)
+// x86 should pass p2, p6 and p7 in registers, then p1 in the second pass.
+struct HFA2 __vectorcall AddParticles(struct HFA2 p1, float p2, struct HFA4 p3, int p4, struct HFA2 p5, float p6, float p7, int p8){ return p1;}
+// X32: define x86_vectorcallcc %struct.HFA2 @"\01AddParticles@@84"(%struct.HFA2 inreg %p1.coerce, float %p2, %struct.HFA4* inreg %p3, i32 inreg %p4, %struct.HFA2* %p5, float %p6, float %p7, i32 %p8)
+// X64: define x86_vectorcallcc %struct.HFA2 @"\01AddParticles@@104"(%struct.HFA2 inreg %p1.coerce, float %p2, %struct.HFA4* %p3, i32 %p4, %struct.HFA2 inreg %p5.coerce, float %p6, float %p7, i32 %p8)
+
+// Vectorcall in both architectures allows passing of an HVA as long as there is room,
+// even if it is not one of the first 6 arguments. First pass puts p4 into a
+// register on both. p9 ends up in a register in x86 only. Second pass puts p1
+// in a register, does NOT put p7 in a register (since theres no room), then puts
+// p8 in a register.
+void __vectorcall HVAAnywhere(struct HFA2 p1, int p2, int p3, float p4, int p5, int p6, struct HFA4 p7, struct HFA2 p8, float p9){}
+// X32: define x86_vectorcallcc void @"\01HVAAnywhere@@88"(%struct.HFA2 inreg %p1.coerce, i32 inreg %p2, i32 inreg %p3, float %p4, i32 %p5, i32 %p6, %struct.HFA4* %p7, %struct.HFA2 inreg %p8.coerce, float %p9)
+// X64: define x86_vectorcallcc void @"\01HVAAnywhere@@112"(%struct.HFA2 inreg %p1.coerce, i32 %p2, i32 %p3, float %p4, i32 %p5, i32 %p6, %struct.HFA4* %p7, %struct.HFA2 inreg %p8.coerce, float %p9)
+
diff --git a/test/CodeGen/x86_64-arguments.c b/test/CodeGen/x86_64-arguments.c
index 9f375d780c94..d24ea4dbab3d 100644
--- a/test/CodeGen/x86_64-arguments.c
+++ b/test/CodeGen/x86_64-arguments.c
@@ -460,7 +460,7 @@ void test54() {
test54_helper(x54, x54, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0i);
}
// AVX: @test54_helper(<8 x float> {{%[a-zA-Z0-9]+}}, <8 x float> {{%[a-zA-Z0-9]+}}, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double {{%[a-zA-Z0-9]+}}, double {{%[a-zA-Z0-9]+}})
-// AVX: @test54_helper(<8 x float> {{%[a-zA-Z0-9]+}}, <8 x float> {{%[a-zA-Z0-9]+}}, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, { double, double }* byval align 8 {{%[a-zA-Z0-9]+}})
+// AVX: @test54_helper(<8 x float> {{%[a-zA-Z0-9]+}}, <8 x float> {{%[a-zA-Z0-9]+}}, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, { double, double }* byval align 8 {{%[^)]+}})
typedef float __m512 __attribute__ ((__vector_size__ (64)));
typedef struct {
@@ -529,7 +529,7 @@ void f63(__m512 *m, __builtin_va_list argList) {
}
// AVX512: @f64_helper(<16 x float> {{%[a-zA-Z0-9]+}}, <16 x float> {{%[a-zA-Z0-9]+}}, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double {{%[a-zA-Z0-9]+}}, double {{%[a-zA-Z0-9]+}})
-// AVX512: @f64_helper(<16 x float> {{%[a-zA-Z0-9]+}}, <16 x float> {{%[a-zA-Z0-9]+}}, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, { double, double }* byval align 8 {{%[a-zA-Z0-9]+}})
+// AVX512: @f64_helper(<16 x float> {{%[a-zA-Z0-9]+}}, <16 x float> {{%[a-zA-Z0-9]+}}, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, { double, double }* byval align 8 {{%[^)]+}})
void f64_helper(__m512, ...);
__m512 x64;
void f64() {
diff --git a/test/CodeGenCXX/amdgcn-automatic-variable.cpp b/test/CodeGenCXX/amdgcn-automatic-variable.cpp
index aab720770d12..7df27c28e6d2 100644
--- a/test/CodeGenCXX/amdgcn-automatic-variable.cpp
+++ b/test/CodeGenCXX/amdgcn-automatic-variable.cpp
@@ -3,9 +3,10 @@
// CHECK-LABEL: define void @_Z5func1Pi(i32* %x)
void func1(int *x) {
// CHECK: %[[x_addr:.*]] = alloca i32*{{.*}}addrspace(5)
- // CHECK: store i32* %x, i32* addrspace(5)* %[[x_addr]]
- // CHECK: %[[r0:.*]] = load i32*, i32* addrspace(5)* %[[x_addr]]
- // CHECK: store i32 1, i32* %[[r0]]
+ // CHECK: %[[r0:.*]] = addrspacecast i32* addrspace(5)* %[[x_addr]] to i32**
+ // CHECK: store i32* %x, i32** %[[r0]]
+ // CHECK: %[[r1:.*]] = load i32*, i32** %[[r0]]
+ // CHECK: store i32 1, i32* %[[r1]]
*x = 1;
}
@@ -70,3 +71,12 @@ void func3() {
// CHECK: call void @_ZN1AD1Ev(%class.A* %[[r0]])
A a;
}
+
+// CHECK-LABEL: define void @_Z5func4i
+void func4(int x) {
+ // CHECK: %[[x_addr:.*]] = alloca i32, align 4, addrspace(5)
+ // CHECK: %[[r0:.*]] = addrspacecast i32 addrspace(5)* %[[x_addr]] to i32*
+ // CHECK: store i32 %x, i32* %[[r0]], align 4
+ // CHECK: call void @_Z5func1Pi(i32* %[[r0]])
+ func1(&x);
+}
diff --git a/test/CodeGenObjC/objc_copyStruct.m b/test/CodeGenObjC/objc_copyStruct.m
new file mode 100644
index 000000000000..7fa0ad54f3ae
--- /dev/null
+++ b/test/CodeGenObjC/objc_copyStruct.m
@@ -0,0 +1,16 @@
+// RUN: %clang -target x86_64-unknown-windows-msvc -fobjc-runtime=ios -Wno-objc-root-class -S -o - -emit-llvm %s | FileCheck %s
+// RUN: %clang -target x86_64-apple-ios -fobjc-runtime=ios -Wno-objc-root-class -S -o - -emit-llvm %s | FileCheck %s
+
+struct S {
+ float f, g;
+};
+
+@interface I
+@property struct S s;
+@end
+
+@implementation I
+@end
+
+// CHECK: declare {{.*}}void @objc_copyStruct(i8*, i8*, i64, i1, i1)
+
diff --git a/test/CodeGenObjC/ubsan-nonnull-and-nullability.m b/test/CodeGenObjC/ubsan-nonnull-and-nullability.m
index b927f55cd402..db6588dac310 100644
--- a/test/CodeGenObjC/ubsan-nonnull-and-nullability.m
+++ b/test/CodeGenObjC/ubsan-nonnull-and-nullability.m
@@ -7,16 +7,26 @@
// CHECK-LABEL: define nonnull i32* @f1
__attribute__((returns_nonnull)) int *_Nonnull f1(int *_Nonnull p) {
// CHECK: entry:
+ // CHECK-NEXT: [[SLOC_PTR:%.*]] = alloca i8*
// CHECK-NEXT: [[ADDR:%.*]] = alloca i32*
+ // CHECK-NEXT: store i8* null, i8** [[SLOC_PTR]]
// CHECK-NEXT: store i32* [[P:%.*]], i32** [[ADDR]]
+ // CHECK-NEXT: store {{.*}} [[SLOC_PTR]]
// CHECK-NEXT: [[ARG:%.*]] = load i32*, i32** [[ADDR]]
+ // CHECK-NEXT: [[SLOC:%.*]] = load {{.*}} [[SLOC_PTR]]
+ // CHECK-NEXT: [[SLOC_NONNULL:%.*]] = icmp ne i8* [[SLOC]], null
+ // CHECK-NEXT: br i1 [[SLOC_NONNULL]], label %nullcheck
+ //
+ // CHECK: nullcheck:
// CHECK-NEXT: [[ICMP:%.*]] = icmp ne i32* [[ARG]], null, !nosanitize
// CHECK-NEXT: br i1 [[ICMP]], label %[[CONT:.+]], label %[[HANDLE:[^,]+]]
// CHECK: [[HANDLE]]:
- // CHECK-NEXT: call void @__ubsan_handle_nonnull_return_abort
+ // CHECK: call void @__ubsan_handle_nonnull_return
// CHECK-NEXT: unreachable, !nosanitize
// CHECK: [[CONT]]:
- // CHECK-NEXT: ret i32*
+ // CHECK-NEXT: br label %no.nullcheck
+ // CHECK: no.nullcheck:
+ // CHECK-NEXT: ret i32* [[ARG]]
return p;
}
@@ -29,3 +39,23 @@ void call_f2() {
// CHECK-NOT: call void @__ubsan_handle_nonnull_arg_abort
f2((void *)0);
}
+
+// If the return value isn't meant to be checked, make sure we don't check it.
+// CHECK-LABEL: define i32* @f3
+int *f3(int *p) {
+ // CHECK-NOT: return.sloc
+ // CHECK-NOT: call{{.*}}ubsan
+ return p;
+}
+
+// Check for a valid "return" source location, even when there is no return
+// statement, to avoid accidentally calling the runtime.
+
+// CHECK-LABEL: define nonnull i32* @f4
+__attribute__((returns_nonnull)) int *f4() {
+ // CHECK: store i8* null, i8** [[SLOC_PTR:%.*]]
+ // CHECK: [[SLOC:%.*]] = load {{.*}} [[SLOC_PTR]]
+ // CHECK: [[SLOC_NONNULL:%.*]] = icmp ne i8* [[SLOC]], null
+ // CHECK: br i1 [[SLOC_NONNULL]], label %nullcheck
+ // CHECK: nullcheck:
+}
diff --git a/test/CodeGenObjC/ubsan-nullability.m b/test/CodeGenObjC/ubsan-nullability.m
index 7f53ea6292ee..eeb24b03c868 100644
--- a/test/CodeGenObjC/ubsan-nullability.m
+++ b/test/CodeGenObjC/ubsan-nullability.m
@@ -2,7 +2,7 @@
// RUN: %clang_cc1 -x objective-c -emit-llvm -triple x86_64-apple-macosx10.10.0 -fsanitize=nullability-arg,nullability-assign,nullability-return -w %s -o - | FileCheck %s
// RUN: %clang_cc1 -x objective-c++ -emit-llvm -triple x86_64-apple-macosx10.10.0 -fsanitize=nullability-arg,nullability-assign,nullability-return -w %s -o - | FileCheck %s
-// CHECK: [[NONNULL_RV_LOC1:@.*]] = private unnamed_addr global {{.*}} i32 109, i32 1 {{.*}} i32 100, i32 6
+// CHECK: [[NONNULL_RV_LOC1:@.*]] = private unnamed_addr global {{.*}} i32 100, i32 6
// CHECK: [[NONNULL_ARG_LOC:@.*]] = private unnamed_addr global {{.*}} i32 204, i32 15 {{.*}} i32 190, i32 23
// CHECK: [[NONNULL_ASSIGN1_LOC:@.*]] = private unnamed_addr global {{.*}} i32 305, i32 9
// CHECK: [[NONNULL_ASSIGN2_LOC:@.*]] = private unnamed_addr global {{.*}} i32 405, i32 10
@@ -10,7 +10,7 @@
// CHECK: [[NONNULL_INIT1_LOC:@.*]] = private unnamed_addr global {{.*}} i32 604, i32 25
// CHECK: [[NONNULL_INIT2_LOC1:@.*]] = private unnamed_addr global {{.*}} i32 707, i32 26
// CHECK: [[NONNULL_INIT2_LOC2:@.*]] = private unnamed_addr global {{.*}} i32 707, i32 29
-// CHECK: [[NONNULL_RV_LOC2:@.*]] = private unnamed_addr global {{.*}} i32 817, i32 1 {{.*}} i32 800, i32 6
+// CHECK: [[NONNULL_RV_LOC2:@.*]] = private unnamed_addr global {{.*}} i32 800, i32 6
#define NULL ((void *)0)
#define INULL ((int *)NULL)
@@ -19,14 +19,11 @@
// CHECK-LABEL: define i32* @{{.*}}nonnull_retval1
#line 100
int *_Nonnull nonnull_retval1(int *p) {
- // CHECK: br i1 true, label %[[NULL:.*]], label %[[NONULL:.*]], !nosanitize
- // CHECK: [[NULL]]:
// CHECK: [[ICMP:%.*]] = icmp ne i32* {{.*}}, null, !nosanitize
- // CHECK-NEXT: br i1 [[ICMP]], {{.*}}, !nosanitize
+ // CHECK: br i1 [[ICMP]], {{.*}}, !nosanitize
// CHECK: call void @__ubsan_handle_nullability_return{{.*}}[[NONNULL_RV_LOC1]]
return p;
- // CHECK: [[NONULL]]:
- // CHECK-NEXT: ret i32*
+ // CHECK: ret i32*
}
#line 190
@@ -108,10 +105,13 @@ int *_Nonnull nonnull_retval2(int *_Nonnull arg1, //< Test this.
// CHECK-NEXT: [[DO_RV_CHECK_1:%.*]] = and i1 true, [[ARG1CMP]], !nosanitize
// CHECK: [[ARG2CMP:%.*]] = icmp ne i32* %arg2, null, !nosanitize
// CHECK-NEXT: [[DO_RV_CHECK_2:%.*]] = and i1 [[DO_RV_CHECK_1]], [[ARG2CMP]]
- // CHECK: br i1 [[DO_RV_CHECK_2]], label %[[NULL:.*]], label %[[NONULL:.*]], !nosanitize
+ // CHECK: [[SLOC_PTR:%.*]] = load i8*, i8** %return.sloc.ptr
+ // CHECK-NEXT: [[SLOC_NONNULL:%.*]] = icmp ne i8* [[SLOC_PTR]], null
+ // CHECK-NEXT: [[DO_RV_CHECK_3:%.*]] = and i1 [[SLOC_NONNULL]], [[DO_RV_CHECK_2]]
+ // CHECK: br i1 [[DO_RV_CHECK_3]], label %[[NULL:.*]], label %[[NONULL:.*]], !nosanitize
// CHECK: [[NULL]]:
// CHECK-NEXT: [[ICMP:%.*]] = icmp ne i32* {{.*}}, null, !nosanitize
- // CHECK-NEXT: br i1 [[ICMP]], {{.*}}, !nosanitize
+ // CHECK: br i1 [[ICMP]], {{.*}}, !nosanitize
// CHECK: call void @__ubsan_handle_nullability_return{{.*}}[[NONNULL_RV_LOC2]]
return arg1;
// CHECK: [[NONULL]]:
@@ -129,10 +129,13 @@ int *_Nonnull nonnull_retval2(int *_Nonnull arg1, //< Test this.
+(int *_Nonnull) objc_clsmethod: (int *_Nonnull) arg1 {
// CHECK: [[ARG1CMP:%.*]] = icmp ne i32* %arg1, null, !nosanitize
// CHECK-NEXT: [[DO_RV_CHECK:%.*]] = and i1 true, [[ARG1CMP]]
- // CHECK: br i1 [[DO_RV_CHECK]], label %[[NULL:.*]], label %[[NONULL:.*]], !nosanitize
+ // CHECK: [[SLOC_PTR:%.*]] = load i8*, i8** %return.sloc.ptr
+ // CHECK-NEXT: [[SLOC_NONNULL:%.*]] = icmp ne i8* [[SLOC_PTR]], null
+ // CHECK-NEXT: [[DO_RV_CHECK_2:%.*]] = and i1 [[SLOC_NONNULL]], [[DO_RV_CHECK]]
+ // CHECK: br i1 [[DO_RV_CHECK_2]], label %[[NULL:.*]], label %[[NONULL:.*]], !nosanitize
// CHECK: [[NULL]]:
// CHECK-NEXT: [[ICMP:%.*]] = icmp ne i32* {{.*}}, null, !nosanitize
- // CHECK-NEXT: br i1 [[ICMP]], {{.*}}, !nosanitize
+ // CHECK: br i1 [[ICMP]], {{.*}}, !nosanitize
// CHECK: call void @__ubsan_handle_nullability_return{{.*}}
return arg1;
// CHECK: [[NONULL]]:
@@ -143,10 +146,13 @@ int *_Nonnull nonnull_retval2(int *_Nonnull arg1, //< Test this.
-(int *_Nonnull) objc_method: (int *_Nonnull) arg1 {
// CHECK: [[ARG1CMP:%.*]] = icmp ne i32* %arg1, null, !nosanitize
// CHECK-NEXT: [[DO_RV_CHECK:%.*]] = and i1 true, [[ARG1CMP]]
- // CHECK: br i1 [[DO_RV_CHECK]], label %[[NULL:.*]], label %[[NONULL:.*]], !nosanitize
+ // CHECK: [[SLOC_PTR:%.*]] = load i8*, i8** %return.sloc.ptr
+ // CHECK-NEXT: [[SLOC_NONNULL:%.*]] = icmp ne i8* [[SLOC_PTR]], null
+ // CHECK-NEXT: [[DO_RV_CHECK_2:%.*]] = and i1 [[SLOC_NONNULL]], [[DO_RV_CHECK]]
+ // CHECK: br i1 [[DO_RV_CHECK_2]], label %[[NULL:.*]], label %[[NONULL:.*]], !nosanitize
// CHECK: [[NULL]]:
// CHECK-NEXT: [[ICMP:%.*]] = icmp ne i32* {{.*}}, null, !nosanitize
- // CHECK-NEXT: br i1 [[ICMP]], {{.*}}, !nosanitize
+ // CHECK: br i1 [[ICMP]], {{.*}}, !nosanitize
// CHECK: call void @__ubsan_handle_nullability_return{{.*}}
return arg1;
// CHECK: [[NONULL]]:
diff --git a/test/CodeGenOpenCL/spir_version.cl b/test/CodeGenOpenCL/spir_version.cl
index 8a191282b3c7..ac5b8e8c7fa5 100644
--- a/test/CodeGenOpenCL/spir_version.cl
+++ b/test/CodeGenOpenCL/spir_version.cl
@@ -10,17 +10,18 @@
// RUN: %clang_cc1 %s -triple "amdgcn--amdhsa" -emit-llvm -o - -cl-std=CL2.0 | FileCheck %s --check-prefix=CHECK-AMDGCN-CL20
kernel void foo() {}
+kernel void bar() {}
-// CHECK-SPIR-CL10: !opencl.spir.version = !{[[SPIR:![0-9]+]]}
-// CHECK-SPIR-CL10: !opencl.ocl.version = !{[[OCL:![0-9]+]]}
-// CHECK-SPIR-CL10: [[SPIR]] = !{i32 1, i32 2}
-// CHECK-SPIR-CL10: [[OCL]] = !{i32 1, i32 0}
-// CHECK-SPIR-CL12: !opencl.spir.version = !{[[VER:![0-9]+]]}
-// CHECK-SPIR-CL12: !opencl.ocl.version = !{[[VER]]}
+// CHECK-SPIR-CL10-DAG: !opencl.spir.version = !{[[SPIR:![0-9]+]]}
+// CHECK-SPIR-CL10-DAG: !opencl.ocl.version = !{[[OCL:![0-9]+]]}
+// CHECK-SPIR-CL10-DAG: [[SPIR]] = !{i32 1, i32 2}
+// CHECK-SPIR-CL10-DAG: [[OCL]] = !{i32 1, i32 0}
+// CHECK-SPIR-CL12-DAG: !opencl.spir.version = !{[[VER:![0-9]+]]}
+// CHECK-SPIR-CL12-DAG: !opencl.ocl.version = !{[[VER]]}
// CHECK-SPIR-CL12: [[VER]] = !{i32 1, i32 2}
-// CHECK-SPIR-CL20: !opencl.spir.version = !{[[VER:![0-9]+]]}
-// CHECK-SPIR-CL20: !opencl.ocl.version = !{[[VER]]}
+// CHECK-SPIR-CL20-DAG: !opencl.spir.version = !{[[VER:![0-9]+]]}
+// CHECK-SPIR-CL20-DAG: !opencl.ocl.version = !{[[VER]]}
// CHECK-SPIR-CL20: [[VER]] = !{i32 2, i32 0}
// CHECK-AMDGCN-CL10-NOT: !opencl.spir.version
diff --git a/test/Driver/ananas.c b/test/Driver/ananas.c
new file mode 100644
index 000000000000..2a5b35ed6cec
--- /dev/null
+++ b/test/Driver/ananas.c
@@ -0,0 +1,9 @@
+// RUN: %clang -no-canonical-prefixes -target x86_64-unknown-ananas -static %s \
+// RUN: --sysroot=%S/Inputs/ananas-tree -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-STATIC %s
+// CHECK-STATIC: ld{{.*}}" "-Bstatic"
+// CHECK-STATIC: crt0.o
+// CHECK-STATIC: crti.o
+// CHECK-STATIC: crtbegin.o
+// CHECK-STATIC: crtend.o
+// CHECK-STATIC: crtn.o
diff --git a/test/Driver/autocomplete.c b/test/Driver/autocomplete.c
index 94649f243738..f0bdcce5707c 100644
--- a/test/Driver/autocomplete.c
+++ b/test/Driver/autocomplete.c
@@ -2,5 +2,37 @@
// FSYN: -fsyntax-only
// RUN: %clang --autocomplete=-s | FileCheck %s -check-prefix=STD
// STD: -std={{.*}}-stdlib=
-// RUN: %clang --autocomplete=foo | not FileCheck %s -check-prefix=NONE
-// NONE: foo
+// RUN: %clang --autocomplete=foo | FileCheck %s -check-prefix=FOO
+// FOO-NOT: foo
+// RUN: %clang --autocomplete=-stdlib=,l | FileCheck %s -check-prefix=STDLIB
+// STDLIB: libc++ libstdc++
+// RUN: %clang --autocomplete=-stdlib=, | FileCheck %s -check-prefix=STDLIBALL
+// STDLIBALL: libc++ libstdc++ platform
+// RUN: %clang --autocomplete=-meabi,d | FileCheck %s -check-prefix=MEABI
+// MEABI: default
+// RUN: %clang --autocomplete=-meabi, | FileCheck %s -check-prefix=MEABIALL
+// MEABIALL: 4 5 default gnu
+// RUN: %clang --autocomplete=-cl-std=,CL2 | FileCheck %s -check-prefix=CLSTD
+// CLSTD: CL2.0
+// RUN: %clang --autocomplete=-cl-std=, | FileCheck %s -check-prefix=CLSTDALL
+// CLSTDALL: cl CL cl1.1 CL1.1 cl1.2 CL1.2 cl2.0 CL2.0
+// RUN: %clang --autocomplete=-fno-sanitize-coverage=,f | FileCheck %s -check-prefix=FNOSANICOVER
+// FNOSANICOVER: func
+// RUN: %clang --autocomplete=-fno-sanitize-coverage=, | FileCheck %s -check-prefix=FNOSANICOVERALL
+// FNOSANICOVERALL: 8bit-counters bb edge func indirect-calls inline-8bit-counters no-prune trace-bb trace-cmp trace-div trace-gep trace-pc trace-pc-guard
+// RUN: %clang --autocomplete=-ffp-contract=, | FileCheck %s -check-prefix=FFPALL
+// FFPALL: fast off on
+// RUN: %clang --autocomplete=-flto=, | FileCheck %s -check-prefix=FLTOALL
+// FLTOALL: full thin
+// RUN: %clang --autocomplete=-fveclib=, | FileCheck %s -check-prefix=FVECLIBALL
+// FVECLIBALL: Accelerate none SVML
+// RUN: %clang --autocomplete=-fshow-overloads=, | FileCheck %s -check-prefix=FSOVERALL
+// FSOVERALL: all best
+// RUN: %clang --autocomplete=-fvisibility=, | FileCheck %s -check-prefix=FVISIBILITYALL
+// FVISIBILITYALL: default hidden
+// RUN: %clang --autocomplete=-mfloat-abi=, | FileCheck %s -check-prefix=MFLOATABIALL
+// MFLOATABIALL: hard soft softfp
+// RUN: %clang --autocomplete=-mthread-model, | FileCheck %s -check-prefix=MTHREADMODELALL
+// MTHREADMODELALL: posix single
+// RUN: %clang --autocomplete=-mrelocation-model, | FileCheck %s -check-prefix=MRELOCMODELALL
+// MRELOCMODELALL: dynamic-no-pic pic ropi ropi-rwpi rwpi static
diff --git a/test/Driver/compress-noias.c b/test/Driver/compress-noias.c
new file mode 100644
index 000000000000..d20cf366b8fc
--- /dev/null
+++ b/test/Driver/compress-noias.c
@@ -0,0 +1,37 @@
+// REQUIRES: zlib
+// REQUIRES: x86-registered-target
+
+// RUN: %clang -### -target i686-unknown-linux-gnu -fno-integrated-as -Wa,-compress-debug-sections -c %s 2>&1 | FileCheck -check-prefix CHECK-_COMPRESS_DEBUG_SECTIONS %s
+// CHECK-_COMPRESS_DEBUG_SECTIONS: "-compress-debug-sections"
+
+// RUN: %clang -### -target i686-unknown-linux-gnu -fno-integrated-as -Wa,--compress-debug-sections -c %s 2>&1 | FileCheck -check-prefix CHECK-__COMPRESS_DEBUG_SECTIONS %s
+// CHECK-__COMPRESS_DEBUG_SECTIONS: "--compress-debug-sections"
+
+// RUN: %clang -### -target i686-unknown-linux-gnu -fno-integrated-as -Wa,--compress-debug-sections -Wa,--nocompress-debug-sections -c %s 2>&1 | FileCheck -check-prefix CHECK-POSNEG %s
+// CHECK-POSNEG: "--compress-debug-sections"
+// CHECK-POSNEG: "--nocompress-debug-sections"
+
+// RUN: %clang -### -target i686-unknown-linux-gnu -fno-integrated-as -Wa,-compress-debug-sections -Wa,--compress-debug-sections -c %s 2>&1 | FileCheck -check-prefix CHECK-MULTIPLE %s
+// CHECK-MULTIPLE: "-compress-debug-sections"
+// CHECK-MULTIPLE: "--compress-debug-sections"
+
+// RUN: %clang -### -target i686-unknown-linux-gnu -fno-integrated-as -gz -x assembler -c %s 2>&1 | FileCheck -check-prefix CHECK-OPT_GZ %s
+// RUN: %clang -### -target i686-unknown-linux-gnu -fno-integrated-as -gz -c %s 2>&1 | FileCheck -check-prefix CHECK-OPT_GZ %s
+// CHECK-OPT_GZ: "-compress-debug-sections"
+
+// RUN: %clang -### -target i686-unknown-linux-gnu -fno-integrated-as -gz=none -x assembler -c %s 2>&1 | FileCheck -check-prefix CHECK-OPT_GZ_EQ_NONE %s
+// RUN: %clang -### -target i686-unknown-linux-gnu -fno-integrated-as -gz=none -c %s 2>&1 | FileCheck -check-prefix CHECK-OPT_GZ_EQ_NONE %s
+// CHECK-OPT_GZ_EQ_NONE: "-compress-debug-sections=none"
+
+// RUN: %clang -### -target i686-unknown-linux-gnu -fno-integrated-as -gz=zlib -x assembler -c %s 2>&1 | FileCheck -check-prefix CHECK-OPT_GZ_EQ_ZLIB %s
+// RUN: %clang -### -target i686-unknown-linux-gnu -fno-integrated-as -gz=zlib -c %s 2>&1 | FileCheck -check-prefix CHECK-OPT_GZ_EQ_ZLIB %s
+// CHECK-OPT_GZ_EQ_ZLIB: "-compress-debug-sections=zlib"
+
+// RUN: %clang -### -target i686-unknown-linux-gnu -fno-integrated-as -gz=zlib-gnu -x assembler -c %s 2>&1 | FileCheck -check-prefix CHECK-OPT_GZ_EQ_ZLIB_GNU %s
+// RUN: %clang -### -target i686-unknown-linux-gnu -fno-integrated-as -gz=zlib-gnu -c %s 2>&1 | FileCheck -check-prefix CHECK-OPT_GZ_EQ_ZLIB_GNU %s
+// CHECK-OPT_GZ_EQ_ZLIB_GNU: "-compress-debug-sections=zlib-gnu"
+
+// RUN: %clang -### -target i686-unknown-linux-gnu -fno-integrated-as -gz=invalid -x assembler -c %s 2>&1 | FileCheck