From fee48910d87260dd1260c58f4713f14d8ceaf34b Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Wed, 22 Apr 2020 15:52:26 -0400 Subject: [PATCH 01/14] [libc++abi] NFC: Use "" instead of <> to include __cxxabi_config.h This is more consistent with how __cxxabi_config.h is included in other files in libcxxabi/src. --- libcxxabi/src/cxa_handlers.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxxabi/src/cxa_handlers.h b/libcxxabi/src/cxa_handlers.h index c8e2e44aee1f05..a96d7e5bcf9011 100644 --- a/libcxxabi/src/cxa_handlers.h +++ b/libcxxabi/src/cxa_handlers.h @@ -12,7 +12,7 @@ #ifndef _CXA_HANDLERS_H #define _CXA_HANDLERS_H -#include <__cxxabi_config.h> +#include "__cxxabi_config.h" #include From dc5c1fa88279a63488173d06407dc7520206ba03 Mon Sep 17 00:00:00 2001 From: Jon Roelofs Date: Wed, 22 Apr 2020 13:59:57 -0600 Subject: [PATCH 02/14] [docs] Fix :option: links --- llvm/docs/CommandGuide/lit.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/docs/CommandGuide/lit.rst b/llvm/docs/CommandGuide/lit.rst index 86f1fdae3b6abf..ce3c43b19aacb6 100644 --- a/llvm/docs/CommandGuide/lit.rst +++ b/llvm/docs/CommandGuide/lit.rst @@ -165,7 +165,7 @@ SELECTION OPTIONS .. option:: --max-time=N Spend at most ``N`` seconds (approximately) running tests and then terminate. - Note that this is not an alias for :option:``--timeout=N``; the two are + Note that this is not an alias for :option:``--timeout``; the two are different kinds of maximums. .. option:: --num-shards=M @@ -193,7 +193,7 @@ SELECTION OPTIONS Spend at most ``N`` seconds (approximately) running each individual test. ``0`` means no time limit, and ``0`` is the default. Note that this is not an - alias for :option:``--max-time=N``; the two are different kinds of maximums. + alias for :option:``--max-time``; the two are different kinds of maximums. .. option:: --filter=REGEXP From a60ca4b4e9b16347ff6c2842b555badffa6c09e3 Mon Sep 17 00:00:00 2001 From: Victor Huang Date: Wed, 22 Apr 2020 15:01:29 -0500 Subject: [PATCH 03/14] [PowerPC][Future] Initial support for PCRel addressing to get block address Add initial support for PCRelative addressing to get block address instead of using TOC. Differential Revision: https://reviews.llvm.org/D76294 --- llvm/lib/Target/PowerPC/PPCISelLowering.cpp | 29 +++++++++++++------ .../CodeGen/PowerPC/pcrel-block-address.ll | 16 ++++++++++ 2 files changed, 36 insertions(+), 9 deletions(-) create mode 100644 llvm/test/CodeGen/PowerPC/pcrel-block-address.ll diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp index effb1651d0453e..2922d90472ec26 100644 --- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -2588,6 +2588,11 @@ bool PPCTargetLowering::SelectAddressRegRegOnly(SDValue N, SDValue &Base, return true; } +template static bool isValidPCRelNode(SDValue N) { + Ty *PCRelCand = dyn_cast(N); + return PCRelCand && (PCRelCand->getTargetFlags() & PPCII::MO_PCREL_FLAG); +} + /// Returns true if this address is a PC Relative address. /// PC Relative addresses are marked with the flag PPCII::MO_PCREL_FLAG /// or if the node opcode is PPCISD::MAT_PCREL_ADDR. @@ -2596,15 +2601,11 @@ bool PPCTargetLowering::SelectAddressPCRel(SDValue N, SDValue &Base) const { Base = N; if (N.getOpcode() == PPCISD::MAT_PCREL_ADDR) return true; - if (ConstantPoolSDNode *CPN = dyn_cast(N)) - if (CPN->getTargetFlags() & PPCII::MO_PCREL_FLAG) - return true; - if (GlobalAddressSDNode *GAN = dyn_cast(N)) - if (GAN->getTargetFlags() & PPCII::MO_PCREL_FLAG) - return true; - if (JumpTableSDNode *JT = dyn_cast(N)) - if (JT->getTargetFlags() & PPCII::MO_PCREL_FLAG) - return true; + if (isValidPCRelNode(N) || + isValidPCRelNode(N) || + isValidPCRelNode(N) || + isValidPCRelNode(N)) + return true; return false; } @@ -2936,6 +2937,16 @@ SDValue PPCTargetLowering::LowerBlockAddress(SDValue Op, BlockAddressSDNode *BASDN = cast(Op); const BlockAddress *BA = BASDN->getBlockAddress(); + // isUsingPCRelativeCalls() returns true when PCRelative is enabled + if (Subtarget.isUsingPCRelativeCalls()) { + SDLoc DL(BASDN); + EVT Ty = getPointerTy(DAG.getDataLayout()); + SDValue GA = DAG.getTargetBlockAddress(BA, Ty, BASDN->getOffset(), + PPCII::MO_PCREL_FLAG); + SDValue MatAddr = DAG.getNode(PPCISD::MAT_PCREL_ADDR, DL, Ty, GA); + return MatAddr; + } + // 64-bit SVR4 ABI and AIX ABI code are always position-independent. // The actual BlockAddress is stored in the TOC. if (Subtarget.is64BitELFABI() || Subtarget.isAIXABI()) { diff --git a/llvm/test/CodeGen/PowerPC/pcrel-block-address.ll b/llvm/test/CodeGen/PowerPC/pcrel-block-address.ll new file mode 100644 index 00000000000000..b7219da940276b --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/pcrel-block-address.ll @@ -0,0 +1,16 @@ +; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu \ +; RUN: -mcpu=future -ppc-asm-full-reg-names < %s | FileCheck %s +define dso_local void @blockaddress() { +; CHECK-LABEL: blockaddress: +; CHECK: # %bb.0: # %entry +; CHECK: paddi r3, 0, .Ltmp0@PCREL, 1 +; CHECK: bl helper@notoc +entry: + tail call void @helper(i8* blockaddress(@blockaddress, %label)) + br label %label + +label: ; preds = %entry + ret void +} + +declare void @helper(i8*) From e5291c4ae3f7272ca3901d1189d30e23fd578193 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Wed, 22 Apr 2020 16:17:58 -0400 Subject: [PATCH 04/14] [libc++/abi] Provide an option to turn on forgiving dynamic_cast when building libc++abi Instead of the ad-hoc #define _LIBCXX_DYNAMIC_FALLBACK, provide an option to enable the setting when building libc++abi. Also use the occasion to rename the option to something slightly more descriptive. Note that in the future, it would be great to simply remove this option altogether. However, in the meantime, it seems better to have it be an official option than something ad-hoc. --- libcxx/cmake/caches/Apple.cmake | 1 + libcxxabi/CMakeLists.txt | 6 ++++++ libcxxabi/src/CMakeLists.txt | 4 ++++ libcxxabi/src/private_typeinfo.cpp | 24 ++++++++++++------------ 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/libcxx/cmake/caches/Apple.cmake b/libcxx/cmake/caches/Apple.cmake index 5ccc53aeee0df1..215c5bd9dfb1a1 100644 --- a/libcxx/cmake/caches/Apple.cmake +++ b/libcxx/cmake/caches/Apple.cmake @@ -14,3 +14,4 @@ set(LIBCXX_HIDE_FROM_ABI_PER_TU_BY_DEFAULT ON CACHE BOOL "") set(LIBCXXABI_ENABLE_NEW_DELETE_DEFINITIONS ON CACHE BOOL "") set(LIBCXXABI_ENABLE_PIC OFF CACHE BOOL "") set(LIBCXXABI_ENABLE_ASSERTIONS OFF CACHE BOOL "") +set(LIBCXXABI_ENABLE_FORGIVING_DYNAMIC_CAST ON CACHE BOOL "") diff --git a/libcxxabi/CMakeLists.txt b/libcxxabi/CMakeLists.txt index a269806891d94f..bb79987f7477ab 100644 --- a/libcxxabi/CMakeLists.txt +++ b/libcxxabi/CMakeLists.txt @@ -65,6 +65,12 @@ option(LIBCXXABI_HAS_EXTERNAL_THREAD_API option(LIBCXXABI_BUILD_EXTERNAL_THREAD_LIBRARY "Build libc++abi with an externalized threading library. This option may only be set to ON when LIBCXXABI_ENABLE_THREADS=ON" OFF) +option(LIBCXXABI_ENABLE_FORGIVING_DYNAMIC_CAST +"Make dynamic_cast more forgiving when type_info's mistakenly have hidden \ +visibility, and thus multiple type_infos can exist for a single type. \ +When the dynamic_cast would normally fail, this option will cause the \ +library to try comparing the type_info names to see if they are equal \ +instead." OFF) # FIXME: This option should default to off. Unfortunatly GCC 4.9 fails to link # programs to due undefined references to new/delete in libc++abi. Once this diff --git a/libcxxabi/src/CMakeLists.txt b/libcxxabi/src/CMakeLists.txt index 8e88416279ea9e..7b837a4ddf2467 100644 --- a/libcxxabi/src/CMakeLists.txt +++ b/libcxxabi/src/CMakeLists.txt @@ -60,6 +60,10 @@ if (LIBCXXABI_HAS_CXA_THREAD_ATEXIT_IMPL) add_definitions(-DHAVE___CXA_THREAD_ATEXIT_IMPL) endif() +if (LIBCXXABI_ENABLE_FORGIVING_DYNAMIC_CAST) + add_definitions(-D_LIBCXXABI_FORGIVING_DYNAMIC_CAST) +endif() + if (APPLE) add_library_flags_if(LIBCXXABI_HAS_SYSTEM_LIB System) else() diff --git a/libcxxabi/src/private_typeinfo.cpp b/libcxxabi/src/private_typeinfo.cpp index 898cfaef7527be..55a90b3ae1d4d3 100644 --- a/libcxxabi/src/private_typeinfo.cpp +++ b/libcxxabi/src/private_typeinfo.cpp @@ -8,11 +8,11 @@ #include "private_typeinfo.h" -// The flag _LIBCXX_DYNAMIC_FALLBACK is used to make dynamic_cast more -// forgiving when type_info's mistakenly have hidden visibility and thus -// multiple type_infos can exist for a single type. +// The flag _LIBCXXABI_FORGIVING_DYNAMIC_CAST is used to make dynamic_cast +// more forgiving when type_info's mistakenly have hidden visibility and +// thus multiple type_infos can exist for a single type. // -// When _LIBCXX_DYNAMIC_FALLBACK is defined, and only in the case where +// When _LIBCXXABI_FORGIVING_DYNAMIC_CAST is defined, and only in the case where // there is a detected inconsistency in the type_info hierarchy during a // dynamic_cast, then the equality operation will fall back to using strcmp // on type_info names to determine type_info equality. @@ -23,7 +23,7 @@ // algorithm and an inconsistency is still detected, dynamic_cast will call // abort with an appropriate message. // -// The current implementation of _LIBCXX_DYNAMIC_FALLBACK requires a +// The current implementation of _LIBCXXABI_FORGIVING_DYNAMIC_CAST requires a // printf-like function called syslog: // // void syslog(int facility_priority, const char* format, ...); @@ -31,19 +31,19 @@ // If you want this functionality but your platform doesn't have syslog, // just implement it in terms of fprintf(stderr, ...). // -// _LIBCXX_DYNAMIC_FALLBACK is currently off by default. +// _LIBCXXABI_FORGIVING_DYNAMIC_CAST is currently off by default. // On Windows, typeids are different between DLLs and EXEs, so comparing // type_info* will work for typeids from the same compiled file but fail // for typeids from a DLL and an executable. Among other things, exceptions // are not caught by handlers since can_catch() returns false. // -// Defining _LIBCXX_DYNAMIC_FALLBACK does not help since can_catch() calls +// Defining _LIBCXXABI_FORGIVING_DYNAMIC_CAST does not help since can_catch() calls // is_equal() with use_strcmp=false so the string names are not compared. #include -#ifdef _LIBCXX_DYNAMIC_FALLBACK +#ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST #include "abort_message.h" #include #include @@ -634,7 +634,7 @@ __dynamic_cast(const void *static_ptr, const __class_type_info *static_type, info.number_of_dst_type = 1; // Do the search dynamic_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, false); -#ifdef _LIBCXX_DYNAMIC_FALLBACK +#ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST // The following if should always be false because we should definitely // find (static_ptr, static_type), either on a public or private path if (info.path_dst_ptr_to_static_ptr == unknown) @@ -652,7 +652,7 @@ __dynamic_cast(const void *static_ptr, const __class_type_info *static_type, info.number_of_dst_type = 1; dynamic_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, true); } -#endif // _LIBCXX_DYNAMIC_FALLBACK +#endif // _LIBCXXABI_FORGIVING_DYNAMIC_CAST // Query the search. if (info.path_dst_ptr_to_static_ptr == public_path) dst_ptr = dynamic_ptr; @@ -661,7 +661,7 @@ __dynamic_cast(const void *static_ptr, const __class_type_info *static_type, { // Not using giant short cut. Do the search dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, false); - #ifdef _LIBCXX_DYNAMIC_FALLBACK + #ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST // The following if should always be false because we should definitely // find (static_ptr, static_type), either on a public or private path if (info.path_dst_ptr_to_static_ptr == unknown && @@ -679,7 +679,7 @@ __dynamic_cast(const void *static_ptr, const __class_type_info *static_type, info = {dst_type, static_ptr, static_type, src2dst_offset, 0}; dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, true); } -#endif // _LIBCXX_DYNAMIC_FALLBACK +#endif // _LIBCXXABI_FORGIVING_DYNAMIC_CAST // Query the search. switch (info.number_to_static_ptr) { From f43859a099fa3587123717be941fa63ba8d0d4f2 Mon Sep 17 00:00:00 2001 From: Aaron Puchert Date: Wed, 22 Apr 2020 20:05:36 +0200 Subject: [PATCH 05/14] PR45000: Let Sema::SubstParmVarDecl handle default args of lambdas in initializers Summary: We extend the behavior for local functions and methods of local classes to lambdas in variable initializers. The initializer is not a separate scope, but we treat it as such. We also remove the (faulty) instantiation of default arguments in TreeTransform::TransformLambdaExpr, because it doesn't do proper initialization, and if it did, we would do it twice (and thus also emit eventual errors twice). Reviewed By: rsmith Differential Revision: https://reviews.llvm.org/D76038 --- clang/include/clang/AST/DeclBase.h | 9 +++++---- clang/lib/AST/DeclBase.cpp | 5 ++++- clang/lib/Sema/SemaTemplateInstantiate.cpp | 2 +- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 2 +- clang/lib/Sema/TreeTransform.h | 13 ------------- clang/test/SemaCXX/vartemplate-lambda.cpp | 8 +++++++- clang/test/SemaTemplate/instantiate-local-class.cpp | 13 +++++++++++++ 7 files changed, 31 insertions(+), 21 deletions(-) diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index b48f7e4f9308b5..91875377679da6 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -869,14 +869,15 @@ class alignas(8) Decl { return getParentFunctionOrMethod() == nullptr; } - /// Returns true if this declaration lexically is inside a function. - /// It recognizes non-defining declarations as well as members of local - /// classes: + /// Returns true if this declaration is lexically inside a function or inside + /// a variable initializer. It recognizes non-defining declarations as well + /// as members of local classes: /// \code /// void foo() { void bar(); } /// void foo2() { class ABC { void bar(); }; } + /// inline int x = [](){ return 0; }; /// \endcode - bool isLexicallyWithinFunctionOrMethod() const; + bool isInLocalScope() const; /// If this decl is defined inside a function/method/block it returns /// the corresponding DeclContext, otherwise it returns null. diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 8a18de1e8248ef..2aab53f4fa9087 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -332,13 +332,16 @@ void Decl::setDeclContextsImpl(DeclContext *SemaDC, DeclContext *LexicalDC, } } -bool Decl::isLexicallyWithinFunctionOrMethod() const { +bool Decl::isInLocalScope() const { const DeclContext *LDC = getLexicalDeclContext(); while (true) { if (LDC->isFunctionOrMethod()) return true; if (!isa(LDC)) return false; + if (const auto *CRD = dyn_cast(LDC)) + if (CRD->isLambda()) + return true; LDC = LDC->getLexicalParent(); } return false; diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index e2b3ebba6bbe85..4b6b92ccab2c5a 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -2380,7 +2380,7 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, UnparsedDefaultArgInstantiations[OldParm].push_back(NewParm); } else if (Expr *Arg = OldParm->getDefaultArg()) { FunctionDecl *OwningFunc = cast(OldParm->getDeclContext()); - if (OwningFunc->isLexicallyWithinFunctionOrMethod()) { + if (OwningFunc->isInLocalScope()) { // Instantiate default arguments for methods of local classes (DR1484) // and non-defining declarations. Sema::ContextRAII SavedContext(*this, OwningFunc); diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 551517581063bc..a6541dabe6b246 100755 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -4363,7 +4363,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, EPI.ExceptionSpec.Type != EST_None && EPI.ExceptionSpec.Type != EST_DynamicNone && EPI.ExceptionSpec.Type != EST_BasicNoexcept && - !Tmpl->isLexicallyWithinFunctionOrMethod()) { + !Tmpl->isInLocalScope()) { FunctionDecl *ExceptionSpecTemplate = Tmpl; if (EPI.ExceptionSpec.Type == EST_Uninstantiated) ExceptionSpecTemplate = EPI.ExceptionSpec.SourceTemplate; diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index abde968bed8cd6..da6ff8e5cea804 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -12219,19 +12219,6 @@ TreeTransform::TransformLambdaExpr(LambdaExpr *E) { LSI->CallOperator = NewCallOperator; - for (unsigned I = 0, NumParams = NewCallOperator->getNumParams(); - I != NumParams; ++I) { - auto *P = NewCallOperator->getParamDecl(I); - if (P->hasUninstantiatedDefaultArg()) { - EnterExpressionEvaluationContext Eval( - getSema(), - Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed, P); - ExprResult R = getDerived().TransformExpr( - E->getCallOperator()->getParamDecl(I)->getDefaultArg()); - P->setDefaultArg(R.get()); - } - } - getDerived().transformAttrs(E->getCallOperator(), NewCallOperator); getDerived().transformedLocalDecl(E->getCallOperator(), {NewCallOperator}); diff --git a/clang/test/SemaCXX/vartemplate-lambda.cpp b/clang/test/SemaCXX/vartemplate-lambda.cpp index 6744968bcc4d37..b17c9bb8dcb9e9 100644 --- a/clang/test/SemaCXX/vartemplate-lambda.cpp +++ b/clang/test/SemaCXX/vartemplate-lambda.cpp @@ -4,7 +4,12 @@ template auto fn0 = [] {}; template void foo0() { fn0(); } template auto fn1 = [](auto a) { return a + T(1); }; -template auto v1 = [](int a = T(1)) { return a; }(); +template auto v1 = [](int a = T()) { return a; }(); +// expected-error@-1{{cannot initialize a parameter of type 'int' with an rvalue of type 'int *'}} +// expected-error@-2{{no matching function for call}} +// expected-note@-3{{passing argument to parameter 'a' here}} +// expected-note@-4{{candidate function not viable}} +// expected-note@-5{{conversion candidate of type 'int (*)(int)'}} struct S { template @@ -16,6 +21,7 @@ int foo2() { X a = 0x61; fn1(a); (void)v1; + (void)v1; // expected-note{{in instantiation of variable template specialization 'v1' requested here}} (void)S::t; // expected-note{{in instantiation of static data member 'S::t' requested here}} return 0; } diff --git a/clang/test/SemaTemplate/instantiate-local-class.cpp b/clang/test/SemaTemplate/instantiate-local-class.cpp index eaff4c4bbc8d90..550c59d617782c 100644 --- a/clang/test/SemaTemplate/instantiate-local-class.cpp +++ b/clang/test/SemaTemplate/instantiate-local-class.cpp @@ -486,3 +486,16 @@ namespace anon_union_default_member_init { } void g() { f(); } } + +namespace PR45000 { + template + void f(int x = [](T x = nullptr) -> int { return x; }()); + // expected-error@-1 {{cannot initialize a parameter of type 'int' with an rvalue of type 'nullptr_t'}} + // expected-note@-2 {{passing argument to parameter 'x' here}} + // expected-error@-3 {{no matching function for call}} + // expected-note@-4 {{candidate function not viable: requires single argument 'x', but no arguments were provided}} + // expected-note@-5 {{conversion candidate of type 'auto (*)(int) -> int'}} + + void g() { f(); } + // expected-note@-1 {{in instantiation of default function argument expression for 'f' required here}} +} From 1559485e600242343cb21c7ffbf345172008cd59 Mon Sep 17 00:00:00 2001 From: Sander de Smalen Date: Wed, 22 Apr 2020 16:45:52 +0100 Subject: [PATCH 06/14] [SveEmitter] Add builtins for svwhile This also adds the IsOverloadWhile flag which tells CGBuiltin to use both the default type (predicate) and the type of the second operand (scalar) as the overloaded types for the LLMV IR intrinsic. Reviewers: SjoerdMeijer, efriedma, rovka Reviewed By: efriedma Tags: #clang Differential Revision: https://reviews.llvm.org/D77595 --- clang/include/clang/Basic/TargetBuiltins.h | 1 + clang/include/clang/Basic/arm_sve.td | 26 +++ clang/lib/CodeGen/CGBuiltin.cpp | 3 + .../aarch64-sve-intrinsics/acle_sve_whilele.c | 151 ++++++++++++++ .../aarch64-sve-intrinsics/acle_sve_whilelt.c | 151 ++++++++++++++ .../acle_sve2_whilege.c | 185 ++++++++++++++++++ .../acle_sve2_whilegt.c | 185 ++++++++++++++++++ 7 files changed, 702 insertions(+) create mode 100644 clang/test/CodeGen/aarch64-sve-intrinsics/acle_sve_whilele.c create mode 100644 clang/test/CodeGen/aarch64-sve-intrinsics/acle_sve_whilelt.c create mode 100644 clang/test/CodeGen/aarch64-sve2-intrinsics/acle_sve2_whilege.c create mode 100644 clang/test/CodeGen/aarch64-sve2-intrinsics/acle_sve2_whilegt.c diff --git a/clang/include/clang/Basic/TargetBuiltins.h b/clang/include/clang/Basic/TargetBuiltins.h index 042f60739f8510..25c738bc37960d 100644 --- a/clang/include/clang/Basic/TargetBuiltins.h +++ b/clang/include/clang/Basic/TargetBuiltins.h @@ -234,6 +234,7 @@ namespace clang { bool isZExtReturn() const { return Flags & IsZExtReturn; } bool isByteIndexed() const { return Flags & IsByteIndexed; } bool isOverloadNone() const { return Flags & IsOverloadNone; } + bool isOverloadWhile() const { return Flags & IsOverloadWhile; } bool isOverloadDefault() const { return !(Flags & OverloadKindMask); } uint64_t getBits() const { return Flags; } diff --git a/clang/include/clang/Basic/arm_sve.td b/clang/include/clang/Basic/arm_sve.td index c2794356d25139..fd15c86bec9f5a 100644 --- a/clang/include/clang/Basic/arm_sve.td +++ b/clang/include/clang/Basic/arm_sve.td @@ -168,6 +168,7 @@ def IsStructLoad : FlagType<0x00020000>; def IsStructStore : FlagType<0x00040000>; def IsZExtReturn : FlagType<0x00080000>; // Return value is sign-extend by default def IsOverloadNone : FlagType<0x00100000>; // Intrinsic does not take any overloaded types. +def IsOverloadWhile : FlagType<0x00200000>; // Use {default type, typeof(operand1)} as overloaded types. def OverloadKindMask : FlagType<0x00E00000>; // When the masked values are all '0', the default type is used as overload type. // : : // : : @@ -528,6 +529,18 @@ let ArchGuard = "defined(__ARM_FEATURE_SVE2)" in { def SVQSHLU_M : SInst<"svqshlu[_n_{d}]", "uPdi", "csil", MergeOp1, "aarch64_sve_sqshlu", [], [ImmCheck<2, ImmCheckShiftLeft, 1>]>; } +//////////////////////////////////////////////////////////////////////////////// +// While comparisons + +def SVWHILELE_S32 : SInst<"svwhilele_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilele", [IsOverloadWhile]>; +def SVWHILELE_S64 : SInst<"svwhilele_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilele", [IsOverloadWhile]>; +def SVWHILELO_U32 : SInst<"svwhilelt_{d}[_{1}]", "Pmm", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilelo", [IsOverloadWhile]>; +def SVWHILELO_U64 : SInst<"svwhilelt_{d}[_{1}]", "Pnn", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilelo", [IsOverloadWhile]>; +def SVWHILELS_U32 : SInst<"svwhilele_{d}[_{1}]", "Pmm", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilels", [IsOverloadWhile]>; +def SVWHILELS_U64 : SInst<"svwhilele_{d}[_{1}]", "Pnn", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilels", [IsOverloadWhile]>; +def SVWHILELT_S32 : SInst<"svwhilelt_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilelt", [IsOverloadWhile]>; +def SVWHILELT_S64 : SInst<"svwhilelt_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilelt", [IsOverloadWhile]>; + //////////////////////////////////////////////////////////////////////////////// // Floating-point arithmetic @@ -567,6 +580,19 @@ def SVCNTD_PAT : SInst<"svcntd_pat", "nI", "", MergeNone, "aarch64_sve_cntd", [I def SVDOT_LANE_S : SInst<"svdot_lane[_{d}]", "ddqqi", "il", MergeNone, "aarch64_sve_sdot_lane", [], [ImmCheck<3, ImmCheckLaneIndexDot, 2>]>; def SVDOT_LANE_U : SInst<"svdot_lane[_{d}]", "ddqqi", "UiUl", MergeNone, "aarch64_sve_udot_lane", [], [ImmCheck<3, ImmCheckLaneIndexDot, 2>]>; +//////////////////////////////////////////////////////////////////////////////// +// SVE2 WhileGE/GT +let ArchGuard = "defined(__ARM_FEATURE_SVE2)" in { +def SVWHILEGE_S32 : SInst<"svwhilege_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilege", [IsOverloadWhile]>; +def SVWHILEGE_S64 : SInst<"svwhilege_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilege", [IsOverloadWhile]>; +def SVWHILEGT_S32 : SInst<"svwhilegt_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilegt", [IsOverloadWhile]>; +def SVWHILEGT_S64 : SInst<"svwhilegt_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilegt", [IsOverloadWhile]>; +def SVWHILEHI_U32 : SInst<"svwhilegt_{d}[_{1}]", "Pmm", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilehi", [IsOverloadWhile]>; +def SVWHILEHI_U64 : SInst<"svwhilegt_{d}[_{1}]", "Pnn", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilehi", [IsOverloadWhile]>; +def SVWHILEHS_U32 : SInst<"svwhilege_{d}[_{1}]", "Pmm", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilehs", [IsOverloadWhile]>; +def SVWHILEHS_U64 : SInst<"svwhilege_{d}[_{1}]", "Pnn", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilehs", [IsOverloadWhile]>; +} + //////////////////////////////////////////////////////////////////////////////// // SVE2 - Non-temporal gather/scatter let ArchGuard = "defined(__ARM_FEATURE_SVE2)" in { diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index fa461a5dd9bf4a..6c58cfd81accc4 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -7781,6 +7781,9 @@ CodeGenFunction::getSVEOverloadTypes(SVETypeFlags TypeFlags, llvm::Type *DefaultType = getSVEType(TypeFlags); + if (TypeFlags.isOverloadWhile()) + return {DefaultType, Ops[1]->getType()}; + assert(TypeFlags.isOverloadDefault() && "Unexpected value for overloads"); return {DefaultType}; } diff --git a/clang/test/CodeGen/aarch64-sve-intrinsics/acle_sve_whilele.c b/clang/test/CodeGen/aarch64-sve-intrinsics/acle_sve_whilele.c new file mode 100644 index 00000000000000..fc06fed94b015c --- /dev/null +++ b/clang/test/CodeGen/aarch64-sve-intrinsics/acle_sve_whilele.c @@ -0,0 +1,151 @@ +// RUN: %clang_cc1 -D__ARM_FEATURE_SVE -triple aarch64-none-linux-gnu -target-feature +sve -fallow-half-arguments-and-returns -S -O1 -Werror -Wall -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -D__ARM_FEATURE_SVE -DSVE_OVERLOADED_FORMS -triple aarch64-none-linux-gnu -target-feature +sve -fallow-half-arguments-and-returns -S -O1 -Werror -Wall -emit-llvm -o - %s | FileCheck %s + +#include + +#ifdef SVE_OVERLOADED_FORMS +// A simple used,unused... macro, long enough to represent any SVE builtin. +#define SVE_ACLE_FUNC(A1,A2_UNUSED,A3,A4_UNUSED) A1##A3 +#else +#define SVE_ACLE_FUNC(A1,A2,A3,A4) A1##A2##A3##A4 +#endif + +svbool_t test_svwhilele_b8_s32(int32_t op1, int32_t op2) +{ + // CHECK-LABEL: test_svwhilele_b8_s32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilele.nxv16i1.i32(i32 %op1, i32 %op2) + // CHECK: ret %[[INTRINSIC]] + return SVE_ACLE_FUNC(svwhilele_b8,_s32,,)(op1, op2); +} + +svbool_t test_svwhilele_b16_s32(int32_t op1, int32_t op2) +{ + // CHECK-LABEL: test_svwhilele_b16_s32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilele.nxv8i1.i32(i32 %op1, i32 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv8i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + return SVE_ACLE_FUNC(svwhilele_b16,_s32,,)(op1, op2); +} + +svbool_t test_svwhilele_b32_s32(int32_t op1, int32_t op2) +{ + // CHECK-LABEL: test_svwhilele_b32_s32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilele.nxv4i1.i32(i32 %op1, i32 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + return SVE_ACLE_FUNC(svwhilele_b32,_s32,,)(op1, op2); +} + +svbool_t test_svwhilele_b64_s32(int32_t op1, int32_t op2) +{ + // CHECK-LABEL: test_svwhilele_b64_s32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilele.nxv2i1.i32(i32 %op1, i32 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + return SVE_ACLE_FUNC(svwhilele_b64,_s32,,)(op1, op2); +} + +svbool_t test_svwhilele_b8_u32(uint32_t op1, uint32_t op2) +{ + // CHECK-LABEL: test_svwhilele_b8_u32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilels.nxv16i1.i32(i32 %op1, i32 %op2) + // CHECK: ret %[[INTRINSIC]] + return SVE_ACLE_FUNC(svwhilele_b8,_u32,,)(op1, op2); +} + +svbool_t test_svwhilele_b16_u32(uint32_t op1, uint32_t op2) +{ + // CHECK-LABEL: test_svwhilele_b16_u32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilels.nxv8i1.i32(i32 %op1, i32 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv8i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + return SVE_ACLE_FUNC(svwhilele_b16,_u32,,)(op1, op2); +} + +svbool_t test_svwhilele_b32_u32(uint32_t op1, uint32_t op2) +{ + // CHECK-LABEL: test_svwhilele_b32_u32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilels.nxv4i1.i32(i32 %op1, i32 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + return SVE_ACLE_FUNC(svwhilele_b32,_u32,,)(op1, op2); +} + +svbool_t test_svwhilele_b64_u32(uint32_t op1, uint32_t op2) +{ + // CHECK-LABEL: test_svwhilele_b64_u32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilels.nxv2i1.i32(i32 %op1, i32 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + return SVE_ACLE_FUNC(svwhilele_b64,_u32,,)(op1, op2); +} + +svbool_t test_svwhilele_b8_s64(int64_t op1, int64_t op2) +{ + // CHECK-LABEL: test_svwhilele_b8_s64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilele.nxv16i1.i64(i64 %op1, i64 %op2) + // CHECK: ret %[[INTRINSIC]] + return SVE_ACLE_FUNC(svwhilele_b8,_s64,,)(op1, op2); +} + +svbool_t test_svwhilele_b16_s64(int64_t op1, int64_t op2) +{ + // CHECK-LABEL: test_svwhilele_b16_s64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilele.nxv8i1.i64(i64 %op1, i64 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv8i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + return SVE_ACLE_FUNC(svwhilele_b16,_s64,,)(op1, op2); +} + +svbool_t test_svwhilele_b32_s64(int64_t op1, int64_t op2) +{ + // CHECK-LABEL: test_svwhilele_b32_s64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilele.nxv4i1.i64(i64 %op1, i64 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + return SVE_ACLE_FUNC(svwhilele_b32,_s64,,)(op1, op2); +} + +svbool_t test_svwhilele_b64_s64(int64_t op1, int64_t op2) +{ + // CHECK-LABEL: test_svwhilele_b64_s64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilele.nxv2i1.i64(i64 %op1, i64 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + return SVE_ACLE_FUNC(svwhilele_b64,_s64,,)(op1, op2); +} + +svbool_t test_svwhilele_b8_u64(uint64_t op1, uint64_t op2) +{ + // CHECK-LABEL: test_svwhilele_b8_u64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilels.nxv16i1.i64(i64 %op1, i64 %op2) + // CHECK: ret %[[INTRINSIC]] + return SVE_ACLE_FUNC(svwhilele_b8,_u64,,)(op1, op2); +} + +svbool_t test_svwhilele_b16_u64(uint64_t op1, uint64_t op2) +{ + // CHECK-LABEL: test_svwhilele_b16_u64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilels.nxv8i1.i64(i64 %op1, i64 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv8i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + return SVE_ACLE_FUNC(svwhilele_b16,_u64,,)(op1, op2); +} + +svbool_t test_svwhilele_b32_u64(uint64_t op1, uint64_t op2) +{ + // CHECK-LABEL: test_svwhilele_b32_u64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilels.nxv4i1.i64(i64 %op1, i64 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + return SVE_ACLE_FUNC(svwhilele_b32,_u64,,)(op1, op2); +} + +svbool_t test_svwhilele_b64_u64(uint64_t op1, uint64_t op2) +{ + // CHECK-LABEL: test_svwhilele_b64_u64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilels.nxv2i1.i64(i64 %op1, i64 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + return SVE_ACLE_FUNC(svwhilele_b64,_u64,,)(op1, op2); +} diff --git a/clang/test/CodeGen/aarch64-sve-intrinsics/acle_sve_whilelt.c b/clang/test/CodeGen/aarch64-sve-intrinsics/acle_sve_whilelt.c new file mode 100644 index 00000000000000..1d2480c0a8092a --- /dev/null +++ b/clang/test/CodeGen/aarch64-sve-intrinsics/acle_sve_whilelt.c @@ -0,0 +1,151 @@ +// RUN: %clang_cc1 -D__ARM_FEATURE_SVE -triple aarch64-none-linux-gnu -target-feature +sve -fallow-half-arguments-and-returns -S -O1 -Werror -Wall -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -D__ARM_FEATURE_SVE -DSVE_OVERLOADED_FORMS -triple aarch64-none-linux-gnu -target-feature +sve -fallow-half-arguments-and-returns -S -O1 -Werror -Wall -emit-llvm -o - %s | FileCheck %s + +#include + +#ifdef SVE_OVERLOADED_FORMS +// A simple used,unused... macro, long enough to represent any SVE builtin. +#define SVE_ACLE_FUNC(A1,A2_UNUSED,A3,A4_UNUSED) A1##A3 +#else +#define SVE_ACLE_FUNC(A1,A2,A3,A4) A1##A2##A3##A4 +#endif + +svbool_t test_svwhilelt_b8_s32(int32_t op1, int32_t op2) +{ + // CHECK-LABEL: test_svwhilelt_b8_s32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilelt.nxv16i1.i32(i32 %op1, i32 %op2) + // CHECK: ret %[[INTRINSIC]] + return SVE_ACLE_FUNC(svwhilelt_b8,_s32,,)(op1, op2); +} + +svbool_t test_svwhilelt_b16_s32(int32_t op1, int32_t op2) +{ + // CHECK-LABEL: test_svwhilelt_b16_s32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilelt.nxv8i1.i32(i32 %op1, i32 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv8i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + return SVE_ACLE_FUNC(svwhilelt_b16,_s32,,)(op1, op2); +} + +svbool_t test_svwhilelt_b32_s32(int32_t op1, int32_t op2) +{ + // CHECK-LABEL: test_svwhilelt_b32_s32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilelt.nxv4i1.i32(i32 %op1, i32 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + return SVE_ACLE_FUNC(svwhilelt_b32,_s32,,)(op1, op2); +} + +svbool_t test_svwhilelt_b64_s32(int32_t op1, int32_t op2) +{ + // CHECK-LABEL: test_svwhilelt_b64_s32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilelt.nxv2i1.i32(i32 %op1, i32 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + return SVE_ACLE_FUNC(svwhilelt_b64,_s32,,)(op1, op2); +} + +svbool_t test_svwhilelt_b8_u32(uint32_t op1, uint32_t op2) +{ + // CHECK-LABEL: test_svwhilelt_b8_u32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilelo.nxv16i1.i32(i32 %op1, i32 %op2) + // CHECK: ret %[[INTRINSIC]] + return SVE_ACLE_FUNC(svwhilelt_b8,_u32,,)(op1, op2); +} + +svbool_t test_svwhilelt_b16_u32(uint32_t op1, uint32_t op2) +{ + // CHECK-LABEL: test_svwhilelt_b16_u32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilelo.nxv8i1.i32(i32 %op1, i32 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv8i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + return SVE_ACLE_FUNC(svwhilelt_b16,_u32,,)(op1, op2); +} + +svbool_t test_svwhilelt_b32_u32(uint32_t op1, uint32_t op2) +{ + // CHECK-LABEL: test_svwhilelt_b32_u32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilelo.nxv4i1.i32(i32 %op1, i32 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + return SVE_ACLE_FUNC(svwhilelt_b32,_u32,,)(op1, op2); +} + +svbool_t test_svwhilelt_b64_u32(uint32_t op1, uint32_t op2) +{ + // CHECK-LABEL: test_svwhilelt_b64_u32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilelo.nxv2i1.i32(i32 %op1, i32 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + return SVE_ACLE_FUNC(svwhilelt_b64,_u32,,)(op1, op2); +} + +svbool_t test_svwhilelt_b8_s64(int64_t op1, int64_t op2) +{ + // CHECK-LABEL: test_svwhilelt_b8_s64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilelt.nxv16i1.i64(i64 %op1, i64 %op2) + // CHECK: ret %[[INTRINSIC]] + return SVE_ACLE_FUNC(svwhilelt_b8,_s64,,)(op1, op2); +} + +svbool_t test_svwhilelt_b16_s64(int64_t op1, int64_t op2) +{ + // CHECK-LABEL: test_svwhilelt_b16_s64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilelt.nxv8i1.i64(i64 %op1, i64 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv8i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + return SVE_ACLE_FUNC(svwhilelt_b16,_s64,,)(op1, op2); +} + +svbool_t test_svwhilelt_b32_s64(int64_t op1, int64_t op2) +{ + // CHECK-LABEL: test_svwhilelt_b32_s64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilelt.nxv4i1.i64(i64 %op1, i64 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + return SVE_ACLE_FUNC(svwhilelt_b32,_s64,,)(op1, op2); +} + +svbool_t test_svwhilelt_b64_s64(int64_t op1, int64_t op2) +{ + // CHECK-LABEL: test_svwhilelt_b64_s64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilelt.nxv2i1.i64(i64 %op1, i64 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + return SVE_ACLE_FUNC(svwhilelt_b64,_s64,,)(op1, op2); +} + +svbool_t test_svwhilelt_b8_u64(uint64_t op1, uint64_t op2) +{ + // CHECK-LABEL: test_svwhilelt_b8_u64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilelo.nxv16i1.i64(i64 %op1, i64 %op2) + // CHECK: ret %[[INTRINSIC]] + return SVE_ACLE_FUNC(svwhilelt_b8,_u64,,)(op1, op2); +} + +svbool_t test_svwhilelt_b16_u64(uint64_t op1, uint64_t op2) +{ + // CHECK-LABEL: test_svwhilelt_b16_u64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilelo.nxv8i1.i64(i64 %op1, i64 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv8i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + return SVE_ACLE_FUNC(svwhilelt_b16,_u64,,)(op1, op2); +} + +svbool_t test_svwhilelt_b32_u64(uint64_t op1, uint64_t op2) +{ + // CHECK-LABEL: test_svwhilelt_b32_u64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilelo.nxv4i1.i64(i64 %op1, i64 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + return SVE_ACLE_FUNC(svwhilelt_b32,_u64,,)(op1, op2); +} + +svbool_t test_svwhilelt_b64_u64(uint64_t op1, uint64_t op2) +{ + // CHECK-LABEL: test_svwhilelt_b64_u64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilelo.nxv2i1.i64(i64 %op1, i64 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + return SVE_ACLE_FUNC(svwhilelt_b64,_u64,,)(op1, op2); +} diff --git a/clang/test/CodeGen/aarch64-sve2-intrinsics/acle_sve2_whilege.c b/clang/test/CodeGen/aarch64-sve2-intrinsics/acle_sve2_whilege.c new file mode 100644 index 00000000000000..72f331609b8fae --- /dev/null +++ b/clang/test/CodeGen/aarch64-sve2-intrinsics/acle_sve2_whilege.c @@ -0,0 +1,185 @@ +// RUN: %clang_cc1 -D__ARM_FEATURE_SVE -D__ARM_FEATURE_SVE2 -triple aarch64-none-linux-gnu -target-feature +sve2 -fallow-half-arguments-and-returns -S -O1 -Werror -Wall -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -D__ARM_FEATURE_SVE -D__ARM_FEATURE_SVE2 -DSVE_OVERLOADED_FORMS -triple aarch64-none-linux-gnu -target-feature +sve2 -fallow-half-arguments-and-returns -S -O1 -Werror -Wall -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -D__ARM_FEATURE_SVE -triple aarch64-none-linux-gnu -target-feature +sve -fallow-half-arguments-and-returns -fsyntax-only -verify -verify-ignore-unexpected=error %s +// RUN: %clang_cc1 -D__ARM_FEATURE_SVE -DSVE_OVERLOADED_FORMS -triple aarch64-none-linux-gnu -target-feature +sve -fallow-half-arguments-and-returns -fsyntax-only -verify=overload -verify-ignore-unexpected=error %s + +#include + +#ifdef SVE_OVERLOADED_FORMS +// A simple used,unused... macro, long enough to represent any SVE builtin. +#define SVE_ACLE_FUNC(A1,A2_UNUSED,A3,A4_UNUSED) A1##A3 +#else +#define SVE_ACLE_FUNC(A1,A2,A3,A4) A1##A2##A3##A4 +#endif + +svbool_t test_svwhilege_b8_s32(int32_t op1, int32_t op2) +{ + // CHECK-LABEL: test_svwhilege_b8_s32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilege.nxv16i1.i32(i32 %op1, i32 %op2) + // CHECK: ret %[[INTRINSIC]] + // overload-warning@+2 {{implicit declaration of function 'svwhilege_b8'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilege_b8_s32'}} + return SVE_ACLE_FUNC(svwhilege_b8,_s32,,)(op1, op2); +} + +svbool_t test_svwhilege_b16_s32(int32_t op1, int32_t op2) +{ + // CHECK-LABEL: test_svwhilege_b16_s32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilege.nxv8i1.i32(i32 %op1, i32 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv8i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + // overload-warning@+2 {{implicit declaration of function 'svwhilege_b16'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilege_b16_s32'}} + return SVE_ACLE_FUNC(svwhilege_b16,_s32,,)(op1, op2); +} + +svbool_t test_svwhilege_b32_s32(int32_t op1, int32_t op2) +{ + // CHECK-LABEL: test_svwhilege_b32_s32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilege.nxv4i1.i32(i32 %op1, i32 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + // overload-warning@+2 {{implicit declaration of function 'svwhilege_b32'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilege_b32_s32'}} + return SVE_ACLE_FUNC(svwhilege_b32,_s32,,)(op1, op2); +} + +svbool_t test_svwhilege_b64_s32(int32_t op1, int32_t op2) +{ + // CHECK-LABEL: test_svwhilege_b64_s32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilege.nxv2i1.i32(i32 %op1, i32 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + // overload-warning@+2 {{implicit declaration of function 'svwhilege_b64'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilege_b64_s32'}} + return SVE_ACLE_FUNC(svwhilege_b64,_s32,,)(op1, op2); +} + +svbool_t test_svwhilege_b8_u32(uint32_t op1, uint32_t op2) +{ + // CHECK-LABEL: test_svwhilege_b8_u32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilehs.nxv16i1.i32(i32 %op1, i32 %op2) + // CHECK: ret %[[INTRINSIC]] + // overload-warning@+2 {{implicit declaration of function 'svwhilege_b8'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilege_b8_u32'}} + return SVE_ACLE_FUNC(svwhilege_b8,_u32,,)(op1, op2); +} + +svbool_t test_svwhilege_b16_u32(uint32_t op1, uint32_t op2) +{ + // CHECK-LABEL: test_svwhilege_b16_u32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilehs.nxv8i1.i32(i32 %op1, i32 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv8i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + // overload-warning@+2 {{implicit declaration of function 'svwhilege_b16'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilege_b16_u32'}} + return SVE_ACLE_FUNC(svwhilege_b16,_u32,,)(op1, op2); +} + +svbool_t test_svwhilege_b32_u32(uint32_t op1, uint32_t op2) +{ + // CHECK-LABEL: test_svwhilege_b32_u32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilehs.nxv4i1.i32(i32 %op1, i32 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + // overload-warning@+2 {{implicit declaration of function 'svwhilege_b32'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilege_b32_u32'}} + return SVE_ACLE_FUNC(svwhilege_b32,_u32,,)(op1, op2); +} + +svbool_t test_svwhilege_b64_u32(uint32_t op1, uint32_t op2) +{ + // CHECK-LABEL: test_svwhilege_b64_u32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilehs.nxv2i1.i32(i32 %op1, i32 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + // overload-warning@+2 {{implicit declaration of function 'svwhilege_b64'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilege_b64_u32'}} + return SVE_ACLE_FUNC(svwhilege_b64,_u32,,)(op1, op2); +} + +svbool_t test_svwhilege_b8_s64(int64_t op1, int64_t op2) +{ + // CHECK-LABEL: test_svwhilege_b8_s64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilege.nxv16i1.i64(i64 %op1, i64 %op2) + // CHECK: ret %[[INTRINSIC]] + // overload-warning@+2 {{implicit declaration of function 'svwhilege_b8'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilege_b8_s64'}} + return SVE_ACLE_FUNC(svwhilege_b8,_s64,,)(op1, op2); +} + +svbool_t test_svwhilege_b16_s64(int64_t op1, int64_t op2) +{ + // CHECK-LABEL: test_svwhilege_b16_s64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilege.nxv8i1.i64(i64 %op1, i64 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv8i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + // overload-warning@+2 {{implicit declaration of function 'svwhilege_b16'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilege_b16_s64'}} + return SVE_ACLE_FUNC(svwhilege_b16,_s64,,)(op1, op2); +} + +svbool_t test_svwhilege_b32_s64(int64_t op1, int64_t op2) +{ + // CHECK-LABEL: test_svwhilege_b32_s64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilege.nxv4i1.i64(i64 %op1, i64 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + // overload-warning@+2 {{implicit declaration of function 'svwhilege_b32'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilege_b32_s64'}} + return SVE_ACLE_FUNC(svwhilege_b32,_s64,,)(op1, op2); +} + +svbool_t test_svwhilege_b64_s64(int64_t op1, int64_t op2) +{ + // CHECK-LABEL: test_svwhilege_b64_s64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilege.nxv2i1.i64(i64 %op1, i64 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + // overload-warning@+2 {{implicit declaration of function 'svwhilege_b64'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilege_b64_s64'}} + return SVE_ACLE_FUNC(svwhilege_b64,_s64,,)(op1, op2); +} + +svbool_t test_svwhilege_b8_u64(uint64_t op1, uint64_t op2) +{ + // CHECK-LABEL: test_svwhilege_b8_u64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilehs.nxv16i1.i64(i64 %op1, i64 %op2) + // CHECK: ret %[[INTRINSIC]] + // overload-warning@+2 {{implicit declaration of function 'svwhilege_b8'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilege_b8_u64'}} + return SVE_ACLE_FUNC(svwhilege_b8,_u64,,)(op1, op2); +} + +svbool_t test_svwhilege_b16_u64(uint64_t op1, uint64_t op2) +{ + // CHECK-LABEL: test_svwhilege_b16_u64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilehs.nxv8i1.i64(i64 %op1, i64 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv8i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + // overload-warning@+2 {{implicit declaration of function 'svwhilege_b16'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilege_b16_u64'}} + return SVE_ACLE_FUNC(svwhilege_b16,_u64,,)(op1, op2); +} + +svbool_t test_svwhilege_b32_u64(uint64_t op1, uint64_t op2) +{ + // CHECK-LABEL: test_svwhilege_b32_u64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilehs.nxv4i1.i64(i64 %op1, i64 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + // overload-warning@+2 {{implicit declaration of function 'svwhilege_b32'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilege_b32_u64'}} + return SVE_ACLE_FUNC(svwhilege_b32,_u64,,)(op1, op2); +} + +svbool_t test_svwhilege_b64_u64(uint64_t op1, uint64_t op2) +{ + // CHECK-LABEL: test_svwhilege_b64_u64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilehs.nxv2i1.i64(i64 %op1, i64 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + // overload-warning@+2 {{implicit declaration of function 'svwhilege_b64'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilege_b64_u64'}} + return SVE_ACLE_FUNC(svwhilege_b64,_u64,,)(op1, op2); +} diff --git a/clang/test/CodeGen/aarch64-sve2-intrinsics/acle_sve2_whilegt.c b/clang/test/CodeGen/aarch64-sve2-intrinsics/acle_sve2_whilegt.c new file mode 100644 index 00000000000000..464f7c111e3431 --- /dev/null +++ b/clang/test/CodeGen/aarch64-sve2-intrinsics/acle_sve2_whilegt.c @@ -0,0 +1,185 @@ +// RUN: %clang_cc1 -D__ARM_FEATURE_SVE -D__ARM_FEATURE_SVE2 -triple aarch64-none-linux-gnu -target-feature +sve2 -fallow-half-arguments-and-returns -S -O1 -Werror -Wall -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -D__ARM_FEATURE_SVE -D__ARM_FEATURE_SVE2 -DSVE_OVERLOADED_FORMS -triple aarch64-none-linux-gnu -target-feature +sve2 -fallow-half-arguments-and-returns -S -O1 -Werror -Wall -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -D__ARM_FEATURE_SVE -triple aarch64-none-linux-gnu -target-feature +sve -fallow-half-arguments-and-returns -fsyntax-only -verify -verify-ignore-unexpected=error %s +// RUN: %clang_cc1 -D__ARM_FEATURE_SVE -DSVE_OVERLOADED_FORMS -triple aarch64-none-linux-gnu -target-feature +sve -fallow-half-arguments-and-returns -fsyntax-only -verify=overload -verify-ignore-unexpected=error %s + +#include + +#ifdef SVE_OVERLOADED_FORMS +// A simple used,unused... macro, long enough to represent any SVE builtin. +#define SVE_ACLE_FUNC(A1,A2_UNUSED,A3,A4_UNUSED) A1##A3 +#else +#define SVE_ACLE_FUNC(A1,A2,A3,A4) A1##A2##A3##A4 +#endif + +svbool_t test_svwhilegt_b8_s32(int32_t op1, int32_t op2) +{ + // CHECK-LABEL: test_svwhilegt_b8_s32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilegt.nxv16i1.i32(i32 %op1, i32 %op2) + // CHECK: ret %[[INTRINSIC]] + // overload-warning@+2 {{implicit declaration of function 'svwhilegt_b8'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilegt_b8_s32'}} + return SVE_ACLE_FUNC(svwhilegt_b8,_s32,,)(op1, op2); +} + +svbool_t test_svwhilegt_b16_s32(int32_t op1, int32_t op2) +{ + // CHECK-LABEL: test_svwhilegt_b16_s32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilegt.nxv8i1.i32(i32 %op1, i32 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv8i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + // overload-warning@+2 {{implicit declaration of function 'svwhilegt_b16'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilegt_b16_s32'}} + return SVE_ACLE_FUNC(svwhilegt_b16,_s32,,)(op1, op2); +} + +svbool_t test_svwhilegt_b32_s32(int32_t op1, int32_t op2) +{ + // CHECK-LABEL: test_svwhilegt_b32_s32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilegt.nxv4i1.i32(i32 %op1, i32 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + // overload-warning@+2 {{implicit declaration of function 'svwhilegt_b32'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilegt_b32_s32'}} + return SVE_ACLE_FUNC(svwhilegt_b32,_s32,,)(op1, op2); +} + +svbool_t test_svwhilegt_b64_s32(int32_t op1, int32_t op2) +{ + // CHECK-LABEL: test_svwhilegt_b64_s32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilegt.nxv2i1.i32(i32 %op1, i32 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + // overload-warning@+2 {{implicit declaration of function 'svwhilegt_b64'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilegt_b64_s32'}} + return SVE_ACLE_FUNC(svwhilegt_b64,_s32,,)(op1, op2); +} + +svbool_t test_svwhilegt_b8_u32(uint32_t op1, uint32_t op2) +{ + // CHECK-LABEL: test_svwhilegt_b8_u32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilehi.nxv16i1.i32(i32 %op1, i32 %op2) + // CHECK: ret %[[INTRINSIC]] + // overload-warning@+2 {{implicit declaration of function 'svwhilegt_b8'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilegt_b8_u32'}} + return SVE_ACLE_FUNC(svwhilegt_b8,_u32,,)(op1, op2); +} + +svbool_t test_svwhilegt_b16_u32(uint32_t op1, uint32_t op2) +{ + // CHECK-LABEL: test_svwhilegt_b16_u32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilehi.nxv8i1.i32(i32 %op1, i32 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv8i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + // overload-warning@+2 {{implicit declaration of function 'svwhilegt_b16'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilegt_b16_u32'}} + return SVE_ACLE_FUNC(svwhilegt_b16,_u32,,)(op1, op2); +} + +svbool_t test_svwhilegt_b32_u32(uint32_t op1, uint32_t op2) +{ + // CHECK-LABEL: test_svwhilegt_b32_u32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilehi.nxv4i1.i32(i32 %op1, i32 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + // overload-warning@+2 {{implicit declaration of function 'svwhilegt_b32'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilegt_b32_u32'}} + return SVE_ACLE_FUNC(svwhilegt_b32,_u32,,)(op1, op2); +} + +svbool_t test_svwhilegt_b64_u32(uint32_t op1, uint32_t op2) +{ + // CHECK-LABEL: test_svwhilegt_b64_u32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilehi.nxv2i1.i32(i32 %op1, i32 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + // overload-warning@+2 {{implicit declaration of function 'svwhilegt_b64'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilegt_b64_u32'}} + return SVE_ACLE_FUNC(svwhilegt_b64,_u32,,)(op1, op2); +} + +svbool_t test_svwhilegt_b8_s64(int64_t op1, int64_t op2) +{ + // CHECK-LABEL: test_svwhilegt_b8_s64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilegt.nxv16i1.i64(i64 %op1, i64 %op2) + // CHECK: ret %[[INTRINSIC]] + // overload-warning@+2 {{implicit declaration of function 'svwhilegt_b8'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilegt_b8_s64'}} + return SVE_ACLE_FUNC(svwhilegt_b8,_s64,,)(op1, op2); +} + +svbool_t test_svwhilegt_b16_s64(int64_t op1, int64_t op2) +{ + // CHECK-LABEL: test_svwhilegt_b16_s64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilegt.nxv8i1.i64(i64 %op1, i64 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv8i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + // overload-warning@+2 {{implicit declaration of function 'svwhilegt_b16'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilegt_b16_s64'}} + return SVE_ACLE_FUNC(svwhilegt_b16,_s64,,)(op1, op2); +} + +svbool_t test_svwhilegt_b32_s64(int64_t op1, int64_t op2) +{ + // CHECK-LABEL: test_svwhilegt_b32_s64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilegt.nxv4i1.i64(i64 %op1, i64 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + // overload-warning@+2 {{implicit declaration of function 'svwhilegt_b32'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilegt_b32_s64'}} + return SVE_ACLE_FUNC(svwhilegt_b32,_s64,,)(op1, op2); +} + +svbool_t test_svwhilegt_b64_s64(int64_t op1, int64_t op2) +{ + // CHECK-LABEL: test_svwhilegt_b64_s64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilegt.nxv2i1.i64(i64 %op1, i64 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + // overload-warning@+2 {{implicit declaration of function 'svwhilegt_b64'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilegt_b64_s64'}} + return SVE_ACLE_FUNC(svwhilegt_b64,_s64,,)(op1, op2); +} + +svbool_t test_svwhilegt_b8_u64(uint64_t op1, uint64_t op2) +{ + // CHECK-LABEL: test_svwhilegt_b8_u64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilehi.nxv16i1.i64(i64 %op1, i64 %op2) + // CHECK: ret %[[INTRINSIC]] + // overload-warning@+2 {{implicit declaration of function 'svwhilegt_b8'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilegt_b8_u64'}} + return SVE_ACLE_FUNC(svwhilegt_b8,_u64,,)(op1, op2); +} + +svbool_t test_svwhilegt_b16_u64(uint64_t op1, uint64_t op2) +{ + // CHECK-LABEL: test_svwhilegt_b16_u64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilehi.nxv8i1.i64(i64 %op1, i64 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv8i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + // overload-warning@+2 {{implicit declaration of function 'svwhilegt_b16'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilegt_b16_u64'}} + return SVE_ACLE_FUNC(svwhilegt_b16,_u64,,)(op1, op2); +} + +svbool_t test_svwhilegt_b32_u64(uint64_t op1, uint64_t op2) +{ + // CHECK-LABEL: test_svwhilegt_b32_u64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilehi.nxv4i1.i64(i64 %op1, i64 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + // overload-warning@+2 {{implicit declaration of function 'svwhilegt_b32'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilegt_b32_u64'}} + return SVE_ACLE_FUNC(svwhilegt_b32,_u64,,)(op1, op2); +} + +svbool_t test_svwhilegt_b64_u64(uint64_t op1, uint64_t op2) +{ + // CHECK-LABEL: test_svwhilegt_b64_u64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilehi.nxv2i1.i64(i64 %op1, i64 %op2) + // CHECK: %[[CAST:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %[[INTRINSIC]]) + // CHECK: ret %[[CAST]] + // overload-warning@+2 {{implicit declaration of function 'svwhilegt_b64'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilegt_b64_u64'}} + return SVE_ACLE_FUNC(svwhilegt_b64,_u64,,)(op1, op2); +} From 2d1baf606ab46daf9a322e5751d364c55c86deca Mon Sep 17 00:00:00 2001 From: Sander de Smalen Date: Wed, 22 Apr 2020 21:49:18 +0100 Subject: [PATCH 07/14] [SveEmitter] Add builtins for svwhilerw/svwhilewr This also adds the IsOverloadWhileRW flag which tells CGBuiltin to use the result predicate type and the first pointer type as the overloaded types for the LLVM IR intrinsic. Reviewers: SjoerdMeijer, efriedma Reviewed By: efriedma Tags: #clang Differential Revision: https://reviews.llvm.org/D78238 --- clang/include/clang/Basic/TargetBuiltins.h | 1 + clang/include/clang/Basic/arm_sve.td | 15 ++ clang/lib/CodeGen/CGBuiltin.cpp | 27 ++++ clang/lib/CodeGen/CodeGenFunction.h | 1 + .../acle_sve2_whilerw.c | 131 ++++++++++++++++++ .../acle_sve2_whilewr.c | 131 ++++++++++++++++++ 6 files changed, 306 insertions(+) create mode 100644 clang/test/CodeGen/aarch64-sve2-intrinsics/acle_sve2_whilerw.c create mode 100644 clang/test/CodeGen/aarch64-sve2-intrinsics/acle_sve2_whilewr.c diff --git a/clang/include/clang/Basic/TargetBuiltins.h b/clang/include/clang/Basic/TargetBuiltins.h index 25c738bc37960d..661691e3d2a50d 100644 --- a/clang/include/clang/Basic/TargetBuiltins.h +++ b/clang/include/clang/Basic/TargetBuiltins.h @@ -236,6 +236,7 @@ namespace clang { bool isOverloadNone() const { return Flags & IsOverloadNone; } bool isOverloadWhile() const { return Flags & IsOverloadWhile; } bool isOverloadDefault() const { return !(Flags & OverloadKindMask); } + bool isOverloadWhileRW() const { return Flags & IsOverloadWhileRW; } uint64_t getBits() const { return Flags; } bool isFlagSet(uint64_t Flag) const { return Flags & Flag; } diff --git a/clang/include/clang/Basic/arm_sve.td b/clang/include/clang/Basic/arm_sve.td index fd15c86bec9f5a..1feeeba6d780ba 100644 --- a/clang/include/clang/Basic/arm_sve.td +++ b/clang/include/clang/Basic/arm_sve.td @@ -169,6 +169,7 @@ def IsStructStore : FlagType<0x00040000>; def IsZExtReturn : FlagType<0x00080000>; // Return value is sign-extend by default def IsOverloadNone : FlagType<0x00100000>; // Intrinsic does not take any overloaded types. def IsOverloadWhile : FlagType<0x00200000>; // Use {default type, typeof(operand1)} as overloaded types. +def IsOverloadWhileRW : FlagType<0x00400000>; // Use {pred(default type), typeof(operand0)} as overloaded types. def OverloadKindMask : FlagType<0x00E00000>; // When the masked values are all '0', the default type is used as overload type. // : : // : : @@ -714,3 +715,17 @@ def SVSTNT1_SCATTER_INDEX_S : MInst<"svstnt1_scatter[_{2}base]_index[_{d}]", " def SVSTNT1H_SCATTER_INDEX_S : MInst<"svstnt1h_scatter[_{2}base]_index[_{d}]", "vPuld", "ilUiUl", [IsScatterStore], MemEltTyInt16, "aarch64_sve_stnt1_scatter_scalar_offset">; def SVSTNT1W_SCATTER_INDEX_S : MInst<"svstnt1w_scatter[_{2}base]_index[_{d}]", "vPuld", "lUl", [IsScatterStore], MemEltTyInt32, "aarch64_sve_stnt1_scatter_scalar_offset">; } + +//////////////////////////////////////////////////////////////////////////////// +// SVE2 - Contiguous conflict detection +let ArchGuard = "defined(__ARM_FEATURE_SVE2)" in { +def SVWHILERW_B : SInst<"svwhilerw[_{1}]", "Pcc", "cUc", MergeNone, "aarch64_sve_whilerw_b", [IsOverloadWhileRW]>; +def SVWHILERW_H : SInst<"svwhilerw[_{1}]", "Pcc", "sUsh", MergeNone, "aarch64_sve_whilerw_h", [IsOverloadWhileRW]>; +def SVWHILERW_S : SInst<"svwhilerw[_{1}]", "Pcc", "iUif", MergeNone, "aarch64_sve_whilerw_s", [IsOverloadWhileRW]>; +def SVWHILERW_D : SInst<"svwhilerw[_{1}]", "Pcc", "lUld", MergeNone, "aarch64_sve_whilerw_d", [IsOverloadWhileRW]>; + +def SVWHILEWR_B : SInst<"svwhilewr[_{1}]", "Pcc", "cUc", MergeNone, "aarch64_sve_whilewr_b", [IsOverloadWhileRW]>; +def SVWHILEWR_H : SInst<"svwhilewr[_{1}]", "Pcc", "sUsh", MergeNone, "aarch64_sve_whilewr_h", [IsOverloadWhileRW]>; +def SVWHILEWR_S : SInst<"svwhilewr[_{1}]", "Pcc", "iUif", MergeNone, "aarch64_sve_whilewr_s", [IsOverloadWhileRW]>; +def SVWHILEWR_D : SInst<"svwhilewr[_{1}]", "Pcc", "lUld", MergeNone, "aarch64_sve_whilewr_d", [IsOverloadWhileRW]>; +} diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 6c58cfd81accc4..e1dd8f9bfda522 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -7511,6 +7511,30 @@ llvm::Type *CodeGenFunction::getEltType(SVETypeFlags TypeFlags) { } } +// Return the llvm predicate vector type corresponding to the specified element +// TypeFlags. +llvm::VectorType* CodeGenFunction::getSVEPredType(SVETypeFlags TypeFlags) { + switch (TypeFlags.getEltType()) { + default: llvm_unreachable("Unhandled SVETypeFlag!"); + + case SVETypeFlags::EltTyInt8: + return llvm::VectorType::get(Builder.getInt1Ty(), { 16, true }); + case SVETypeFlags::EltTyInt16: + return llvm::VectorType::get(Builder.getInt1Ty(), { 8, true }); + case SVETypeFlags::EltTyInt32: + return llvm::VectorType::get(Builder.getInt1Ty(), { 4, true }); + case SVETypeFlags::EltTyInt64: + return llvm::VectorType::get(Builder.getInt1Ty(), { 2, true }); + + case SVETypeFlags::EltTyFloat16: + return llvm::VectorType::get(Builder.getInt1Ty(), { 8, true }); + case SVETypeFlags::EltTyFloat32: + return llvm::VectorType::get(Builder.getInt1Ty(), { 4, true }); + case SVETypeFlags::EltTyFloat64: + return llvm::VectorType::get(Builder.getInt1Ty(), { 2, true }); + } +} + // Return the llvm vector type corresponding to the specified element TypeFlags. llvm::VectorType *CodeGenFunction::getSVEType(const SVETypeFlags &TypeFlags) { switch (TypeFlags.getEltType()) { @@ -7784,6 +7808,9 @@ CodeGenFunction::getSVEOverloadTypes(SVETypeFlags TypeFlags, if (TypeFlags.isOverloadWhile()) return {DefaultType, Ops[1]->getType()}; + if (TypeFlags.isOverloadWhileRW()) + return {getSVEPredType(TypeFlags), Ops[0]->getType()}; + assert(TypeFlags.isOverloadDefault() && "Unexpected value for overloads"); return {DefaultType}; } diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 7e2624a48259d3..a16ad1d178ce34 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -3912,6 +3912,7 @@ class CodeGenFunction : public CodeGenTypeCache { ArrayRef Ops); llvm::Type *getEltType(SVETypeFlags TypeFlags); llvm::VectorType *getSVEType(const SVETypeFlags &TypeFlags); + llvm::VectorType *getSVEPredType(SVETypeFlags TypeFlags); llvm::Value *EmitSVEDupX(llvm::Value *Scalar); llvm::Value *EmitSVEPredicateCast(llvm::Value *Pred, llvm::VectorType *VTy); llvm::Value *EmitSVEGatherLoad(SVETypeFlags TypeFlags, diff --git a/clang/test/CodeGen/aarch64-sve2-intrinsics/acle_sve2_whilerw.c b/clang/test/CodeGen/aarch64-sve2-intrinsics/acle_sve2_whilerw.c new file mode 100644 index 00000000000000..cfb2600aaf05d2 --- /dev/null +++ b/clang/test/CodeGen/aarch64-sve2-intrinsics/acle_sve2_whilerw.c @@ -0,0 +1,131 @@ +// RUN: %clang_cc1 -D__ARM_FEATURE_SVE -D__ARM_FEATURE_SVE2 -triple aarch64-none-linux-gnu -target-feature +sve2 -fallow-half-arguments-and-returns -S -O1 -Werror -Wall -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -D__ARM_FEATURE_SVE -D__ARM_FEATURE_SVE2 -DSVE_OVERLOADED_FORMS -triple aarch64-none-linux-gnu -target-feature +sve2 -fallow-half-arguments-and-returns -S -O1 -Werror -Wall -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -D__ARM_FEATURE_SVE -triple aarch64-none-linux-gnu -target-feature +sve -fallow-half-arguments-and-returns -fsyntax-only -verify -verify-ignore-unexpected=error %s +// RUN: %clang_cc1 -D__ARM_FEATURE_SVE -DSVE_OVERLOADED_FORMS -triple aarch64-none-linux-gnu -target-feature +sve -fallow-half-arguments-and-returns -fsyntax-only -verify=overload -verify-ignore-unexpected=error %s + +#include + +#ifdef SVE_OVERLOADED_FORMS +// A simple used,unused... macro, long enough to represent any SVE builtin. +#define SVE_ACLE_FUNC(A1,A2_UNUSED,A3,A4_UNUSED) A1##A3 +#else +#define SVE_ACLE_FUNC(A1,A2,A3,A4) A1##A2##A3##A4 +#endif + +svbool_t test_svwhilerw_s8(const int8_t *op1, const int8_t *op2) +{ + // CHECK-LABEL: test_svwhilerw_s8 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilerw.b.nxv16i1.p0i8(i8* %op1, i8* %op2) + // CHECK: ret %[[INTRINSIC]] + // overload-warning@+2 {{implicit declaration of function 'svwhilerw'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilerw_s8'}} + return SVE_ACLE_FUNC(svwhilerw,_s8,,)(op1, op2); +} + +svbool_t test_svwhilerw_s16(const int16_t *op1, const int16_t *op2) +{ + // CHECK-LABEL: test_svwhilerw_s16 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilerw.h.nxv8i1.p0i16(i16* %op1, i16* %op2) + // CHECK: %[[INTRINSIC_REINT:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv8i1( %[[INTRINSIC]]) + // CHECK: ret %[[INTRINSIC_REINT]] + // overload-warning@+2 {{implicit declaration of function 'svwhilerw'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilerw_s16'}} + return SVE_ACLE_FUNC(svwhilerw,_s16,,)(op1, op2); +} + +svbool_t test_svwhilerw_s32(const int32_t *op1, const int32_t *op2) +{ + // CHECK-LABEL: test_svwhilerw_s32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilerw.s.nxv4i1.p0i32(i32* %op1, i32* %op2) + // CHECK: %[[INTRINSIC_REINT:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( %[[INTRINSIC]]) + // CHECK: ret %[[INTRINSIC_REINT]] + // overload-warning@+2 {{implicit declaration of function 'svwhilerw'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilerw_s32'}} + return SVE_ACLE_FUNC(svwhilerw,_s32,,)(op1, op2); +} + +svbool_t test_svwhilerw_s64(const int64_t *op1, const int64_t *op2) +{ + // CHECK-LABEL: test_svwhilerw_s64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilerw.d.nxv2i1.p0i64(i64* %op1, i64* %op2) + // CHECK: %[[INTRINSIC_REINT:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %[[INTRINSIC]]) + // CHECK: ret %[[INTRINSIC_REINT]] + // overload-warning@+2 {{implicit declaration of function 'svwhilerw'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilerw_s64'}} + return SVE_ACLE_FUNC(svwhilerw,_s64,,)(op1, op2); +} + +svbool_t test_svwhilerw_u8(const uint8_t *op1, const uint8_t *op2) +{ + // CHECK-LABEL: test_svwhilerw_u8 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilerw.b.nxv16i1.p0i8(i8* %op1, i8* %op2) + // CHECK: ret %[[INTRINSIC]] + // overload-warning@+2 {{implicit declaration of function 'svwhilerw'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilerw_u8'}} + return SVE_ACLE_FUNC(svwhilerw,_u8,,)(op1, op2); +} + +svbool_t test_svwhilerw_u16(const uint16_t *op1, const uint16_t *op2) +{ + // CHECK-LABEL: test_svwhilerw_u16 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilerw.h.nxv8i1.p0i16(i16* %op1, i16* %op2) + // CHECK: %[[INTRINSIC_REINT:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv8i1( %[[INTRINSIC]]) + // CHECK: ret %[[INTRINSIC_REINT]] + // overload-warning@+2 {{implicit declaration of function 'svwhilerw'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilerw_u16'}} + return SVE_ACLE_FUNC(svwhilerw,_u16,,)(op1, op2); +} + +svbool_t test_svwhilerw_u32(const uint32_t *op1, const uint32_t *op2) +{ + // CHECK-LABEL: test_svwhilerw_u32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilerw.s.nxv4i1.p0i32(i32* %op1, i32* %op2) + // CHECK: %[[INTRINSIC_REINT:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( %[[INTRINSIC]]) + // CHECK: ret %[[INTRINSIC_REINT]] + // overload-warning@+2 {{implicit declaration of function 'svwhilerw'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilerw_u32'}} + return SVE_ACLE_FUNC(svwhilerw,_u32,,)(op1, op2); +} + +svbool_t test_svwhilerw_u64(const uint64_t *op1, const uint64_t *op2) +{ + // CHECK-LABEL: test_svwhilerw_u64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilerw.d.nxv2i1.p0i64(i64* %op1, i64* %op2) + // CHECK: %[[INTRINSIC_REINT:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %[[INTRINSIC]]) + // CHECK: ret %[[INTRINSIC_REINT]] + // overload-warning@+2 {{implicit declaration of function 'svwhilerw'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilerw_u64'}} + return SVE_ACLE_FUNC(svwhilerw,_u64,,)(op1, op2); +} + +svbool_t test_svwhilerw_f16(const float16_t *op1, const float16_t *op2) +{ + // CHECK-LABEL: test_svwhilerw_f16 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilerw.h.nxv8i1.p0f16(half* %op1, half* %op2) + // CHECK: %[[INTRINSIC_REINT:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv8i1( %[[INTRINSIC]]) + // CHECK: ret %[[INTRINSIC_REINT]] + // overload-warning@+2 {{implicit declaration of function 'svwhilerw'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilerw_f16'}} + return SVE_ACLE_FUNC(svwhilerw,_f16,,)(op1, op2); +} + +svbool_t test_svwhilerw_f32(const float32_t *op1, const float32_t *op2) +{ + // CHECK-LABEL: test_svwhilerw_f32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilerw.s.nxv4i1.p0f32(float* %op1, float* %op2) + // CHECK: %[[INTRINSIC_REINT:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( %[[INTRINSIC]]) + // CHECK: ret %[[INTRINSIC_REINT]] + // overload-warning@+2 {{implicit declaration of function 'svwhilerw'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilerw_f32'}} + return SVE_ACLE_FUNC(svwhilerw,_f32,,)(op1, op2); +} + +svbool_t test_svwhilerw_f64(const float64_t *op1, const float64_t *op2) +{ + // CHECK-LABEL: test_svwhilerw_f64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilerw.d.nxv2i1.p0f64(double* %op1, double* %op2) + // CHECK: %[[INTRINSIC_REINT:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %[[INTRINSIC]]) + // overload-warning@+2 {{implicit declaration of function 'svwhilerw'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilerw_f64'}} + return SVE_ACLE_FUNC(svwhilerw,_f64,,)(op1, op2); +} diff --git a/clang/test/CodeGen/aarch64-sve2-intrinsics/acle_sve2_whilewr.c b/clang/test/CodeGen/aarch64-sve2-intrinsics/acle_sve2_whilewr.c new file mode 100644 index 00000000000000..8495a30cd801c3 --- /dev/null +++ b/clang/test/CodeGen/aarch64-sve2-intrinsics/acle_sve2_whilewr.c @@ -0,0 +1,131 @@ +// RUN: %clang_cc1 -D__ARM_FEATURE_SVE -D__ARM_FEATURE_SVE2 -triple aarch64-none-linux-gnu -target-feature +sve2 -fallow-half-arguments-and-returns -S -O1 -Werror -Wall -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -D__ARM_FEATURE_SVE -D__ARM_FEATURE_SVE2 -DSVE_OVERLOADED_FORMS -triple aarch64-none-linux-gnu -target-feature +sve2 -fallow-half-arguments-and-returns -S -O1 -Werror -Wall -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -D__ARM_FEATURE_SVE -triple aarch64-none-linux-gnu -target-feature +sve -fallow-half-arguments-and-returns -fsyntax-only -verify -verify-ignore-unexpected=error %s +// RUN: %clang_cc1 -D__ARM_FEATURE_SVE -DSVE_OVERLOADED_FORMS -triple aarch64-none-linux-gnu -target-feature +sve -fallow-half-arguments-and-returns -fsyntax-only -verify=overload -verify-ignore-unexpected=error %s + +#include + +#ifdef SVE_OVERLOADED_FORMS +// A simple used,unused... macro, long enough to represent any SVE builtin. +#define SVE_ACLE_FUNC(A1,A2_UNUSED,A3,A4_UNUSED) A1##A3 +#else +#define SVE_ACLE_FUNC(A1,A2,A3,A4) A1##A2##A3##A4 +#endif + +svbool_t test_svwhilewr_s8(const int8_t *op1, const int8_t *op2) +{ + // CHECK-LABEL: test_svwhilewr_s8 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilewr.b.nxv16i1.p0i8(i8* %op1, i8* %op2) + // CHECK: ret %[[INTRINSIC]] + // overload-warning@+2 {{implicit declaration of function 'svwhilewr'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilewr_s8'}} + return SVE_ACLE_FUNC(svwhilewr,_s8,,)(op1, op2); +} + +svbool_t test_svwhilewr_s16(const int16_t *op1, const int16_t *op2) +{ + // CHECK-LABEL: test_svwhilewr_s16 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilewr.h.nxv8i1.p0i16(i16* %op1, i16* %op2) + // CHECK: %[[INTRINSIC_REINT:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv8i1( %[[INTRINSIC]]) + // CHECK: ret %[[INTRINSIC_REINT]] + // overload-warning@+2 {{implicit declaration of function 'svwhilewr'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilewr_s16'}} + return SVE_ACLE_FUNC(svwhilewr,_s16,,)(op1, op2); +} + +svbool_t test_svwhilewr_s32(const int32_t *op1, const int32_t *op2) +{ + // CHECK-LABEL: test_svwhilewr_s32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilewr.s.nxv4i1.p0i32(i32* %op1, i32* %op2) + // CHECK: %[[INTRINSIC_REINT:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( %[[INTRINSIC]]) + // CHECK: ret %[[INTRINSIC_REINT]] + // overload-warning@+2 {{implicit declaration of function 'svwhilewr'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilewr_s32'}} + return SVE_ACLE_FUNC(svwhilewr,_s32,,)(op1, op2); +} + +svbool_t test_svwhilewr_s64(const int64_t *op1, const int64_t *op2) +{ + // CHECK-LABEL: test_svwhilewr_s64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilewr.d.nxv2i1.p0i64(i64* %op1, i64* %op2) + // CHECK: %[[INTRINSIC_REINT:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %[[INTRINSIC]]) + // CHECK: ret %[[INTRINSIC_REINT]] + // overload-warning@+2 {{implicit declaration of function 'svwhilewr'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilewr_s64'}} + return SVE_ACLE_FUNC(svwhilewr,_s64,,)(op1, op2); +} + +svbool_t test_svwhilewr_u8(const uint8_t *op1, const uint8_t *op2) +{ + // CHECK-LABEL: test_svwhilewr_u8 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilewr.b.nxv16i1.p0i8(i8* %op1, i8* %op2) + // CHECK: ret %[[INTRINSIC]] + // overload-warning@+2 {{implicit declaration of function 'svwhilewr'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilewr_u8'}} + return SVE_ACLE_FUNC(svwhilewr,_u8,,)(op1, op2); +} + +svbool_t test_svwhilewr_u16(const uint16_t *op1, const uint16_t *op2) +{ + // CHECK-LABEL: test_svwhilewr_u16 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilewr.h.nxv8i1.p0i16(i16* %op1, i16* %op2) + // CHECK: %[[INTRINSIC_REINT:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv8i1( %[[INTRINSIC]]) + // CHECK: ret %[[INTRINSIC_REINT]] + // overload-warning@+2 {{implicit declaration of function 'svwhilewr'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilewr_u16'}} + return SVE_ACLE_FUNC(svwhilewr,_u16,,)(op1, op2); +} + +svbool_t test_svwhilewr_u32(const uint32_t *op1, const uint32_t *op2) +{ + // CHECK-LABEL: test_svwhilewr_u32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilewr.s.nxv4i1.p0i32(i32* %op1, i32* %op2) + // CHECK: %[[INTRINSIC_REINT:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( %[[INTRINSIC]]) + // CHECK: ret %[[INTRINSIC_REINT]] + // overload-warning@+2 {{implicit declaration of function 'svwhilewr'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilewr_u32'}} + return SVE_ACLE_FUNC(svwhilewr,_u32,,)(op1, op2); +} + +svbool_t test_svwhilewr_u64(const uint64_t *op1, const uint64_t *op2) +{ + // CHECK-LABEL: test_svwhilewr_u64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilewr.d.nxv2i1.p0i64(i64* %op1, i64* %op2) + // CHECK: %[[INTRINSIC_REINT:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %[[INTRINSIC]]) + // CHECK: ret %[[INTRINSIC_REINT]] + // overload-warning@+2 {{implicit declaration of function 'svwhilewr'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilewr_u64'}} + return SVE_ACLE_FUNC(svwhilewr,_u64,,)(op1, op2); +} + +svbool_t test_svwhilewr_f16(const float16_t *op1, const float16_t *op2) +{ + // CHECK-LABEL: test_svwhilewr_f16 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilewr.h.nxv8i1.p0f16(half* %op1, half* %op2) + // CHECK: %[[INTRINSIC_REINT:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv8i1( %[[INTRINSIC]]) + // CHECK: ret %[[INTRINSIC_REINT]] + // overload-warning@+2 {{implicit declaration of function 'svwhilewr'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilewr_f16'}} + return SVE_ACLE_FUNC(svwhilewr,_f16,,)(op1, op2); +} + +svbool_t test_svwhilewr_f32(const float32_t *op1, const float32_t *op2) +{ + // CHECK-LABEL: test_svwhilewr_f32 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilewr.s.nxv4i1.p0f32(float* %op1, float* %op2) + // CHECK: %[[INTRINSIC_REINT:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv4i1( %[[INTRINSIC]]) + // CHECK: ret %[[INTRINSIC_REINT]] + // overload-warning@+2 {{implicit declaration of function 'svwhilewr'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilewr_f32'}} + return SVE_ACLE_FUNC(svwhilewr,_f32,,)(op1, op2); +} + +svbool_t test_svwhilewr_f64(const float64_t *op1, const float64_t *op2) +{ + // CHECK-LABEL: test_svwhilewr_f64 + // CHECK: %[[INTRINSIC:.*]] = call @llvm.aarch64.sve.whilewr.d.nxv2i1.p0f64(double* %op1, double* %op2) + // CHECK: %[[INTRINSIC_REINT:.*]] = call @llvm.aarch64.sve.convert.to.svbool.nxv2i1( %[[INTRINSIC]]) + // overload-warning@+2 {{implicit declaration of function 'svwhilewr'}} + // expected-warning@+1 {{implicit declaration of function 'svwhilewr_f64'}} + return SVE_ACLE_FUNC(svwhilewr,_f64,,)(op1, op2); +} From 352b612a7141bdb07e8b043f4ec9b8c2d5faca45 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Wed, 22 Apr 2020 22:00:51 +0100 Subject: [PATCH 08/14] [SCCP] Drop unnecessary early exit for ExtractValueInst. visitExtractValueInst uses mergeInValue, so it already can handle constant ranges. Initially the early exit was using isOverdefined to keep things as NFC during the initial move to ValueLatticeElement. As the function already supports constant ranges, it can just use ValueState[&I].isOverdefined. Reviewers: efriedma, mssimpso, davide Reviewed By: efriedma Differential Revision: https://reviews.llvm.org/D78393 --- llvm/lib/Transforms/Scalar/SCCP.cpp | 10 ++++----- .../test/Transforms/SCCP/conditions-ranges.ll | 21 +++++++++++++++---- .../Transforms/SCCP/constant-range-struct.ll | 1 - 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/llvm/lib/Transforms/Scalar/SCCP.cpp b/llvm/lib/Transforms/Scalar/SCCP.cpp index 6d640fe8f9f4e7..1b159dd69d281c 100644 --- a/llvm/lib/Transforms/Scalar/SCCP.cpp +++ b/llvm/lib/Transforms/Scalar/SCCP.cpp @@ -810,16 +810,16 @@ void SCCPSolver::visitCastInst(CastInst &I) { } void SCCPSolver::visitExtractValueInst(ExtractValueInst &EVI) { - // ResolvedUndefsIn might mark I as overdefined. Bail out, even if we would - // discover a concrete value later. - if (isOverdefined(ValueState[&EVI])) - return (void)markOverdefined(&EVI); - // If this returns a struct, mark all elements over defined, we don't track // structs in structs. if (EVI.getType()->isStructTy()) return (void)markOverdefined(&EVI); + // ResolvedUndefsIn might mark I as overdefined. Bail out, even if we would + // discover a concrete value later. + if (ValueState[&EVI].isOverdefined()) + return (void)markOverdefined(&EVI); + // If this is extracting from more than one level of struct, we don't know. if (EVI.getNumIndices() != 1) return (void)markOverdefined(&EVI); diff --git a/llvm/test/Transforms/SCCP/conditions-ranges.ll b/llvm/test/Transforms/SCCP/conditions-ranges.ll index 400c49e337df75..baaf8cbf1c2f52 100644 --- a/llvm/test/Transforms/SCCP/conditions-ranges.ll +++ b/llvm/test/Transforms/SCCP/conditions-ranges.ll @@ -989,6 +989,12 @@ define void @f18_conditions_chained_and(i32 %a, i32 %b) { ; CHECK-NEXT: call void @use(i1 [[F_2]]) ; CHECK-NEXT: [[F_3:%.*]] = icmp ugt i32 [[A]], 100 ; CHECK-NEXT: call void @use(i1 [[F_3]]) +; CHECK-NEXT: [[F_4:%.*]] = icmp eq i32 [[B]], 0 +; CHECK-NEXT: call void @use(i1 [[F_3]]) +; CHECK-NEXT: [[F_5:%.*]] = icmp eq i32 [[B]], 20 +; CHECK-NEXT: call void @use(i1 [[F_5]]) +; CHECK-NEXT: [[F_6:%.*]] = icmp ugt i32 [[B]], 100 +; CHECK-NEXT: call void @use(i1 [[F_6]]) ; CHECK-NEXT: [[T_1:%.*]] = icmp ult i32 [[A]], 100 ; CHECK-NEXT: call void @use(i1 [[T_1]]) ; CHECK-NEXT: [[T_2:%.*]] = icmp ne i32 [[A]], 20 @@ -1001,8 +1007,8 @@ define void @f18_conditions_chained_and(i32 %a, i32 %b) { ; CHECK-NEXT: call void @use(i1 [[C_3]]) ; CHECK-NEXT: ret void ; CHECK: false: -; CHECK-NEXT: [[F_4:%.*]] = icmp eq i32 [[A]], 50 -; CHECK-NEXT: call void @use(i1 [[F_4]]) +; CHECK-NEXT: [[F_7:%.*]] = icmp eq i32 [[A]], 50 +; CHECK-NEXT: call void @use(i1 [[F_7]]) ; CHECK-NEXT: [[T_3:%.*]] = icmp ne i32 [[A]], 50 ; CHECK-NEXT: call void @use(i1 [[T_3]]) ; CHECK-NEXT: [[C_4:%.*]] = icmp eq i32 [[A]], 10 @@ -1027,6 +1033,13 @@ true: ; %a in [21, 100) call void @use(i1 %f.2) %f.3 = icmp ugt i32 %a, 100 call void @use(i1 %f.3) + %f.4 = icmp eq i32 %b, 0 + call void @use(i1 %f.3) + %f.5 = icmp eq i32 %b, 20 + call void @use(i1 %f.5) + %f.6 = icmp ugt i32 %b, 100 + call void @use(i1 %f.6) + ; Conditions below are true. %t.1 = icmp ult i32 %a, 100 @@ -1045,8 +1058,8 @@ true: ; %a in [21, 100) false: ; Conditions below are false; - %f.4 = icmp eq i32 %a, 50 - call void @use(i1 %f.4) + %f.7 = icmp eq i32 %a, 50 + call void @use(i1 %f.7) ; Conditions below are true; %t.3 = icmp ne i32 %a, 50 diff --git a/llvm/test/Transforms/SCCP/constant-range-struct.ll b/llvm/test/Transforms/SCCP/constant-range-struct.ll index d3c5e5513b9ed8..6a602feefa4caf 100644 --- a/llvm/test/Transforms/SCCP/constant-range-struct.ll +++ b/llvm/test/Transforms/SCCP/constant-range-struct.ll @@ -159,6 +159,5 @@ define void @struct2_caller() { %c.4 = icmp ugt i64 %v2, 250 call void @use(i1 %c.4) - ret void } From a5bf02815d8b8d1a76682a63281561f076968dae Mon Sep 17 00:00:00 2001 From: Sergej Jaskiewicz Date: Thu, 16 Apr 2020 16:31:00 +0300 Subject: [PATCH 09/14] [TimeProfiler] Emit real process ID and thread names Differential Revision: https://reviews.llvm.org/D78027 --- clang/test/Driver/check-time-trace.cpp | 1 + lld/test/ELF/time-trace.s | 1 + llvm/lib/Support/TimeProfiler.cpp | 43 +++++++++++++++++--------- 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/clang/test/Driver/check-time-trace.cpp b/clang/test/Driver/check-time-trace.cpp index bff2c1984daa90..1484462b72bbe9 100644 --- a/clang/test/Driver/check-time-trace.cpp +++ b/clang/test/Driver/check-time-trace.cpp @@ -14,6 +14,7 @@ // CHECK-NEXT: "ts": // CHECK: "name": "clang{{.*}}" // CHECK: "name": "process_name" +// CHECK: "name": "thread_name" template struct Struct { diff --git a/lld/test/ELF/time-trace.s b/lld/test/ELF/time-trace.s index 74311a98411090..8085a256649e48 100644 --- a/lld/test/ELF/time-trace.s +++ b/lld/test/ELF/time-trace.s @@ -34,6 +34,7 @@ # Check process_name entry field # CHECK: "name": "ld.lld{{(.exe)?}}" # CHECK: "name": "process_name" +# CHECK: "name": "thread_name" .globl _start _start: diff --git a/llvm/lib/Support/TimeProfiler.cpp b/llvm/lib/Support/TimeProfiler.cpp index 510f763b8fe35e..c907c1aaf983a9 100644 --- a/llvm/lib/Support/TimeProfiler.cpp +++ b/llvm/lib/Support/TimeProfiler.cpp @@ -16,6 +16,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/JSON.h" #include "llvm/Support/Path.h" +#include "llvm/Support/Process.h" #include "llvm/Support/Threading.h" #include #include @@ -75,7 +76,10 @@ struct Entry { struct llvm::TimeTraceProfiler { TimeTraceProfiler(unsigned TimeTraceGranularity = 0, StringRef ProcName = "") : StartTime(steady_clock::now()), ProcName(ProcName), - Tid(llvm::get_threadid()), TimeTraceGranularity(TimeTraceGranularity) {} + Pid(sys::Process::getProcessId()), Tid(llvm::get_threadid()), + TimeTraceGranularity(TimeTraceGranularity) { + llvm::get_thread_name(ThreadName); + } void begin(std::string Name, llvm::function_ref Detail) { Stack.emplace_back(steady_clock::now(), TimePointType(), std::move(Name), @@ -138,8 +142,8 @@ struct llvm::TimeTraceProfiler { auto StartUs = E.getFlameGraphStartUs(StartTime); auto DurUs = E.getFlameGraphDurUs(); - J.object([&]{ - J.attribute("pid", 1); + J.object([&] { + J.attribute("pid", Pid); J.attribute("tid", int64_t(Tid)); J.attribute("ph", "X"); J.attribute("ts", StartUs); @@ -194,8 +198,8 @@ struct llvm::TimeTraceProfiler { auto DurUs = duration_cast(Total.second.second).count(); auto Count = AllCountAndTotalPerName[Total.first].first; - J.object([&]{ - J.attribute("pid", 1); + J.object([&] { + J.attribute("pid", Pid); J.attribute("tid", int64_t(TotalTid)); J.attribute("ph", "X"); J.attribute("ts", 0); @@ -210,16 +214,23 @@ struct llvm::TimeTraceProfiler { ++TotalTid; } - // Emit metadata event with process name. - J.object([&] { - J.attribute("cat", ""); - J.attribute("pid", 1); - J.attribute("tid", 0); - J.attribute("ts", 0); - J.attribute("ph", "M"); - J.attribute("name", "process_name"); - J.attributeObject("args", [&] { J.attribute("name", ProcName); }); - }); + auto writeMetadataEvent = [&](const char *Name, uint64_t Tid, + StringRef arg) { + J.object([&] { + J.attribute("cat", ""); + J.attribute("pid", Pid); + J.attribute("tid", int64_t(Tid)); + J.attribute("ts", 0); + J.attribute("ph", "M"); + J.attribute("name", Name); + J.attributeObject("args", [&] { J.attribute("name", arg); }); + }); + }; + + writeMetadataEvent("process_name", Tid, ProcName); + writeMetadataEvent("thread_name", Tid, ThreadName); + for (const TimeTraceProfiler *TTP : ThreadTimeTraceProfilerInstances) + writeMetadataEvent("thread_name", TTP->Tid, TTP->ThreadName); J.arrayEnd(); J.attributeEnd(); @@ -231,6 +242,8 @@ struct llvm::TimeTraceProfiler { StringMap CountAndTotalPerName; const TimePointType StartTime; const std::string ProcName; + const sys::Process::Pid Pid; + SmallString<0> ThreadName; const uint64_t Tid; // Minimum time granularity (in microseconds) From fedd32e2fa3600ea795b7acb715ddf8d89d7123a Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Tue, 21 Apr 2020 16:50:19 -0700 Subject: [PATCH 10/14] [JITLink] Read MachO Header CPU field only in jitLink_MachO. It's the only field we need in this function. --- llvm/lib/ExecutionEngine/JITLink/MachO.cpp | 26 ++++++++++++++-------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/llvm/lib/ExecutionEngine/JITLink/MachO.cpp b/llvm/lib/ExecutionEngine/JITLink/MachO.cpp index 58bc0f56e1555f..2ef2f5e9409d73 100644 --- a/llvm/lib/ExecutionEngine/JITLink/MachO.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/MachO.cpp @@ -16,9 +16,9 @@ #include "llvm/BinaryFormat/MachO.h" #include "llvm/ExecutionEngine/JITLink/MachO_arm64.h" #include "llvm/ExecutionEngine/JITLink/MachO_x86_64.h" -#include "llvm/Support/Endian.h" #include "llvm/Support/Format.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SwapByteOrder.h" using namespace llvm; @@ -34,7 +34,9 @@ void jitLink_MachO(std::unique_ptr Ctx) { StringRef Data = Ctx->getObjectBuffer().getBuffer(); if (Data.size() < 4) { - Ctx->notifyFailed(make_error("Truncated MachO buffer")); + StringRef BufferName = Ctx->getObjectBuffer().getBufferIdentifier(); + Ctx->notifyFailed(make_error("Truncated MachO buffer \"" + + BufferName + "\"")); return; } @@ -51,20 +53,26 @@ void jitLink_MachO(std::unique_ptr Ctx) { make_error("MachO 32-bit platforms not supported")); return; } else if (Magic == MachO::MH_MAGIC_64 || Magic == MachO::MH_CIGAM_64) { - MachO::mach_header_64 Header; - memcpy(&Header, Data.data(), sizeof(MachO::mach_header_64)); + if (Data.size() < sizeof(MachO::mach_header_64)) { + StringRef BufferName = Ctx->getObjectBuffer().getBufferIdentifier(); + Ctx->notifyFailed(make_error("Truncated MachO buffer \"" + + BufferName + "\"")); + return; + } + + // Read the CPU type from the header. + uint32_t CPUType; + memcpy(&CPUType, Data.data() + 4, sizeof(uint32_t)); if (Magic == MachO::MH_CIGAM_64) - swapStruct(Header); + ByteSwap_32(CPUType); LLVM_DEBUG({ - dbgs() << "jitLink_MachO: cputype = " - << format("0x%08" PRIx32, Header.cputype) - << ", cpusubtype = " << format("0x%08" PRIx32, Header.cpusubtype) + dbgs() << "jitLink_MachO: cputype = " << format("0x%08" PRIx32, CPUType) << "\n"; }); - switch (Header.cputype) { + switch (CPUType) { case MachO::CPU_TYPE_ARM64: return jitLink_MachO_arm64(std::move(Ctx)); case MachO::CPU_TYPE_X86_64: From 3ceea67c091d556ec672e65ec4e9d72997e76807 Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Wed, 22 Apr 2020 10:18:44 -0700 Subject: [PATCH 11/14] [JITLink] Fix edge removal iterator invalidation. This patch changes Block::removeEdge to return a valid iterator to the new next element, and uses this to update the edge removal algorithm in LinkGraph::splitBlock. --- .../include/llvm/ExecutionEngine/JITLink/JITLink.h | 4 ++-- llvm/lib/ExecutionEngine/JITLink/JITLink.cpp | 14 +++++--------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h b/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h index 967397f10ad373..000dd18fb373d8 100644 --- a/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h +++ b/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h @@ -248,8 +248,8 @@ class Block : public Addressable { bool edges_empty() const { return Edges.empty(); } /// Remove the edge pointed to by the given iterator. - /// Invalidates all iterators that point to or past the given one. - void removeEdge(const_edge_iterator I) { Edges.erase(I); } + /// Returns an iterator to the new next element. + edge_iterator removeEdge(edge_iterator I) { return Edges.erase(I); } private: static constexpr uint64_t MaxAlignmentOffset = (1ULL << 57) - 1; diff --git a/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp b/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp index 6c924f88957769..c60076e02afa41 100644 --- a/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp @@ -180,18 +180,14 @@ Block &LinkGraph::splitBlock(Block &B, size_t SplitIndex, // Copy edges to NewBlock (recording their iterators so that we can remove // them from B), and update of Edges remaining on B. std::vector EdgesToRemove; - for (auto I = B.edges().begin(), E = B.edges().end(); I != E; ++I) { + for (auto I = B.edges().begin(); I != B.edges().end();) { if (I->getOffset() < SplitIndex) { NewBlock.addEdge(*I); - EdgesToRemove.push_back(I); - } else + I = B.removeEdge(I); + } else { I->setOffset(I->getOffset() - SplitIndex); - } - - // Remove edges that were transfered to NewBlock from B. - while (!EdgesToRemove.empty()) { - B.removeEdge(EdgesToRemove.back()); - EdgesToRemove.pop_back(); + ++I; + } } } From 1a78b0bd3829381e7be627b459c22083bf4671d4 Mon Sep 17 00:00:00 2001 From: Eli Friedman Date: Tue, 21 Apr 2020 17:40:41 -0700 Subject: [PATCH 12/14] [MachineOutliner] Teach outliner to set live-ins Preserving liveness can be useful even late in the pipeline, if we're doing substantial optimization work afterwards. (See, for example, D76065.) Teach MachineOutliner how to correctly set live-ins on the basic block in outlined functions. Differential Revision: https://reviews.llvm.org/D78605 --- llvm/lib/CodeGen/MachineOutliner.cpp | 31 ++++++++++++++++--- llvm/lib/Target/AArch64/AArch64InstrInfo.cpp | 10 ++++-- llvm/lib/Target/RISCV/RISCVInstrInfo.cpp | 2 ++ .../AArch64/machine-outliner-calls.mir | 5 +-- .../machine-outliner-retaddr-sign-sp-mod.mir | 4 ++- 5 files changed, 43 insertions(+), 9 deletions(-) diff --git a/llvm/lib/CodeGen/MachineOutliner.cpp b/llvm/lib/CodeGen/MachineOutliner.cpp index bd30bd41f07cde..e15dcc32c2ba7f 100644 --- a/llvm/lib/CodeGen/MachineOutliner.cpp +++ b/llvm/lib/CodeGen/MachineOutliner.cpp @@ -1178,12 +1178,35 @@ MachineFunction *MachineOutliner::createOutlinedFunction( MBB.insert(MBB.end(), NewMI); } - TII.buildOutlinedFrame(MBB, MF, OF); - - // Outlined functions shouldn't preserve liveness. - MF.getProperties().reset(MachineFunctionProperties::Property::TracksLiveness); + // Set normal properties for a late MachineFunction. + MF.getProperties().reset(MachineFunctionProperties::Property::IsSSA); + MF.getProperties().set(MachineFunctionProperties::Property::NoPHIs); + MF.getProperties().set(MachineFunctionProperties::Property::NoVRegs); + MF.getProperties().set(MachineFunctionProperties::Property::TracksLiveness); MF.getRegInfo().freezeReservedRegs(MF); + // Compute live-in set for outlined fn + const MachineRegisterInfo &MRI = MF.getRegInfo(); + const TargetRegisterInfo &TRI = *MRI.getTargetRegisterInfo(); + LivePhysRegs LiveIns(TRI); + for (auto &Cand : OF.Candidates) { + // Figure out live-ins at the first instruction. + MachineBasicBlock &OutlineBB = *Cand.front()->getParent(); + LivePhysRegs CandLiveIns(TRI); + CandLiveIns.addLiveOuts(OutlineBB); + for (const MachineInstr &MI : + reverse(make_range(Cand.front(), OutlineBB.end()))) + CandLiveIns.stepBackward(MI); + + // The live-in set for the outlined function is the union of the live-ins + // from all the outlining points. + for (MCPhysReg Reg : make_range(CandLiveIns.begin(), CandLiveIns.end())) + LiveIns.addReg(Reg); + } + addLiveIns(MBB, LiveIns); + + TII.buildOutlinedFrame(MBB, MF, OF); + // If there's a DISubprogram associated with this outlined function, then // emit debug info for the outlined function. if (DISubprogram *SP = getSubprogramOrNull(OF)) { diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp index 25a317f88c7dcc..564b7c80186871 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp @@ -6450,7 +6450,8 @@ void AArch64InstrInfo::buildOutlinedFrame( IsLeafFunction = false; // LR has to be a live in so that we can save it. - MBB.addLiveIn(AArch64::LR); + if (!MBB.isLiveIn(AArch64::LR)) + MBB.addLiveIn(AArch64::LR); MachineBasicBlock::iterator It = MBB.begin(); MachineBasicBlock::iterator Et = MBB.end(); @@ -6529,8 +6530,13 @@ void AArch64InstrInfo::buildOutlinedFrame( } // It's not a tail call, so we have to insert the return ourselves. + + // LR has to be a live in so that we can return to it. + if (!MBB.isLiveIn(AArch64::LR)) + MBB.addLiveIn(AArch64::LR); + MachineInstr *ret = BuildMI(MF, DebugLoc(), get(AArch64::RET)) - .addReg(AArch64::LR, RegState::Undef); + .addReg(AArch64::LR); MBB.insert(MBB.end(), ret); signOutlinedFunction(MF, MBB, ShouldSignReturnAddr, diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp index ac8e0ab9ec13df..f64e4397dcd3c4 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp @@ -778,6 +778,8 @@ void RISCVInstrInfo::buildOutlinedFrame( } } + MBB.addLiveIn(RISCV::X5); + // Add in a return instruction to the end of the outlined frame. MBB.insert(MBB.end(), BuildMI(MF, DebugLoc(), get(RISCV::JALR)) .addReg(RISCV::X0, RegState::Define) diff --git a/llvm/test/CodeGen/AArch64/machine-outliner-calls.mir b/llvm/test/CodeGen/AArch64/machine-outliner-calls.mir index 00025ab90625d0..847ccb927f931c 100644 --- a/llvm/test/CodeGen/AArch64/machine-outliner-calls.mir +++ b/llvm/test/CodeGen/AArch64/machine-outliner-calls.mir @@ -55,7 +55,8 @@ body: | RET undef $lr # CHECK: name: OUTLINED_FUNCTION_0 -# CHECK-DAG: bb.0: +# CHECK: bb.0: +# CHECK: liveins: $x19, $x20, $x21, $x22, $x23, $x24, $x25, $x26, $x27, $x28, $d15, $d8, $d9, $d10, $d11, $d12, $d13, $d14, $lr # CHECK-DAG: frame-setup CFI_INSTRUCTION def_cfa_offset -16 # CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $w30, 16 # CHECK-NEXT: early-clobber $sp = STRXpre $lr, $sp, -16 @@ -63,4 +64,4 @@ body: | # CHECK-NEXT: $w17 = ORRWri $wzr, 1 # CHECK-NEXT: $w17 = ORRWri $wzr, 1 # CHECK-NEXT: early-clobber $sp, $lr = LDRXpost $sp, 16 -# CHECK-NEXT: RET undef $lr +# CHECK-NEXT: RET $lr diff --git a/llvm/test/CodeGen/AArch64/machine-outliner-retaddr-sign-sp-mod.mir b/llvm/test/CodeGen/AArch64/machine-outliner-retaddr-sign-sp-mod.mir index 0e829776effc89..0b86499461bbb4 100644 --- a/llvm/test/CodeGen/AArch64/machine-outliner-retaddr-sign-sp-mod.mir +++ b/llvm/test/CodeGen/AArch64/machine-outliner-retaddr-sign-sp-mod.mir @@ -196,9 +196,11 @@ body: | # CHECK: name: [[OUTLINED_FUNC]] # CHECK: body: | # CHECK-NEXT: bb.0: +# CHECK-NEXT: liveins: $lr +# CHECK-NEXT: {{^ $}} # CHECK-NEXT: frame-setup PACIASP implicit-def $lr, implicit $lr, implicit $sp # CHECK-NEXT: frame-setup CFI_INSTRUCTION negate_ra_sign_state # CHECK-NEXT: $sp = frame-setup SUBXri $sp, 16, 0 # CHECK: $sp = frame-destroy ADDXri $sp, 16, 0 # CHECK-NEXT: frame-destroy AUTIASP implicit-def $lr, implicit $lr, implicit $sp -# CHECK-NEXT: RET undef $lr +# CHECK-NEXT: RET $lr From f34fdbcf996a9b944439007b1da087be8284b803 Mon Sep 17 00:00:00 2001 From: Alexander Shaposhnikov Date: Wed, 22 Apr 2020 14:26:28 -0700 Subject: [PATCH 13/14] [llvm-objcopy][MachO] Make --remove-section clean up dead symbols Make --remove-section clean up dead symbols, return an Error if it can't be safely done. Test plan: make check-all Differential revision: https://reviews.llvm.org/D78474 --- .../MachO/remove-section-dead-symbols.test | 128 ++++++++++++++++++ .../MachO/remove-section-error.test | 120 ++++++++++++++++ .../tools/llvm-objcopy/MachO/MachOObjcopy.cpp | 6 +- llvm/tools/llvm-objcopy/MachO/MachOReader.cpp | 34 ++--- llvm/tools/llvm-objcopy/MachO/Object.cpp | 42 +++++- llvm/tools/llvm-objcopy/MachO/Object.h | 10 +- 6 files changed, 315 insertions(+), 25 deletions(-) create mode 100644 llvm/test/tools/llvm-objcopy/MachO/remove-section-dead-symbols.test create mode 100644 llvm/test/tools/llvm-objcopy/MachO/remove-section-error.test diff --git a/llvm/test/tools/llvm-objcopy/MachO/remove-section-dead-symbols.test b/llvm/test/tools/llvm-objcopy/MachO/remove-section-dead-symbols.test new file mode 100644 index 00000000000000..474369439ba629 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/MachO/remove-section-dead-symbols.test @@ -0,0 +1,128 @@ +# RUN: yaml2obj %s -o %t +# RUN: llvm-objcopy --remove-section __DATA,C %t %t.copy + +# RUN: llvm-readobj --symbols %t.copy | FileCheck %s + +# CHECK: Symbols [ +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: _A (1) +# CHECK-NEXT: Extern +# CHECK-NEXT: Type: Section (0xE) +# CHECK-NEXT: Section: __data (0x2) +# CHECK-NEXT: RefType: UndefinedNonLazy (0x0) +# CHECK-NEXT: Flags [ (0x0) +# CHECK-NEXT: ] +# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: } +# CHECK-NEXT: ] + +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x00000003 + filetype: 0x00000001 + ncmds: 4 + sizeofcmds: 432 + flags: 0x00002000 + reserved: 0x00000000 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 312 + segname: '' + vmaddr: 0 + vmsize: 8 + fileoff: 464 + filesize: 8 + maxprot: 7 + initprot: 7 + nsects: 3 + flags: 0 + Sections: + - sectname: __text + segname: __TEXT + addr: 0x0000000000000000 + size: 0 + offset: 0x000001D0 + align: 0 + reloff: 0x00000000 + nreloc: 0 + flags: 0x80000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + content: '' + - sectname: __data + segname: __DATA + addr: 0x0000000000000000 + size: 4 + offset: 0x000001D0 + align: 2 + reloff: 0x00000000 + nreloc: 0 + flags: 0x00000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + content: '01000000' + - sectname: C + segname: __DATA + addr: 0x0000000000000004 + size: 4 + offset: 0x000001D4 + align: 2 + reloff: 0x00000000 + nreloc: 0 + flags: 0x00000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + content: '02000000' + - cmd: LC_VERSION_MIN_MACOSX + cmdsize: 16 + version: 658944 + sdk: 0 + - cmd: LC_SYMTAB + cmdsize: 24 + symoff: 472 + nsyms: 2 + stroff: 504 + strsize: 8 + - cmd: LC_DYSYMTAB + cmdsize: 80 + ilocalsym: 0 + nlocalsym: 0 + iextdefsym: 0 + nextdefsym: 2 + iundefsym: 2 + nundefsym: 0 + tocoff: 0 + ntoc: 0 + modtaboff: 0 + nmodtab: 0 + extrefsymoff: 0 + nextrefsyms: 0 + indirectsymoff: 0 + nindirectsyms: 0 + extreloff: 0 + nextrel: 0 + locreloff: 0 + nlocrel: 0 +LinkEditData: + NameList: + - n_strx: 4 + n_type: 0x0F + n_sect: 2 + n_desc: 0 + n_value: 0 + - n_strx: 1 + n_type: 0x0F + n_sect: 3 + n_desc: 0 + n_value: 4 + StringTable: + - '' + - _B + - _A + - '' +... diff --git a/llvm/test/tools/llvm-objcopy/MachO/remove-section-error.test b/llvm/test/tools/llvm-objcopy/MachO/remove-section-error.test new file mode 100644 index 00000000000000..e060212fb2da65 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/MachO/remove-section-error.test @@ -0,0 +1,120 @@ +# RUN: yaml2obj %s -o %t +# RUN: not llvm-objcopy --remove-section __DATA,C %t /dev/null 2>&1 | FileCheck %s + +# CHECK: symbol '_a' defined in section with index '2' cannot be removed because it is referenced by a relocation in section '__TEXT,__text' + +## The binary used in this test was built as follows: +## main.c: +## __attribute__((section("__DATA,C"))) int a = 2; +## int f() { return a; } +## build command: +## clang -fno-exceptions -fno-unwind-tables -c main.c -o main.o + +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x00000003 + filetype: 0x00000001 + ncmds: 4 + sizeofcmds: 360 + flags: 0x00002000 + reserved: 0x00000000 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 232 + segname: '' + vmaddr: 0 + vmsize: 16 + fileoff: 392 + filesize: 16 + maxprot: 7 + initprot: 7 + nsects: 2 + flags: 0 + Sections: + - sectname: __text + segname: __TEXT + addr: 0x0000000000000000 + size: 12 + offset: 0x00000188 + align: 4 + reloff: 0x00000198 + nreloc: 1 + flags: 0x80000400 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + content: 554889E58B05000000005DC3 + relocations: + - address: 0x00000006 + symbolnum: 0 + pcrel: true + length: 2 + extern: true + type: 1 + scattered: false + value: 0 + - sectname: C + segname: __DATA + addr: 0x000000000000000C + size: 4 + offset: 0x00000194 + align: 2 + reloff: 0x00000000 + nreloc: 0 + flags: 0x00000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + content: '02000000' + - cmd: LC_BUILD_VERSION + cmdsize: 24 + platform: 1 + minos: 658944 + sdk: 658944 + ntools: 0 + - cmd: LC_SYMTAB + cmdsize: 24 + symoff: 416 + nsyms: 2 + stroff: 448 + strsize: 8 + - cmd: LC_DYSYMTAB + cmdsize: 80 + ilocalsym: 0 + nlocalsym: 0 + iextdefsym: 0 + nextdefsym: 2 + iundefsym: 2 + nundefsym: 0 + tocoff: 0 + ntoc: 0 + modtaboff: 0 + nmodtab: 0 + extrefsymoff: 0 + nextrefsyms: 0 + indirectsymoff: 0 + nindirectsyms: 0 + extreloff: 0 + nextrel: 0 + locreloff: 0 + nlocrel: 0 +LinkEditData: + NameList: + - n_strx: 4 + n_type: 0x0F + n_sect: 2 + n_desc: 0 + n_value: 12 + - n_strx: 1 + n_type: 0x0F + n_sect: 1 + n_desc: 0 + n_value: 0 + StringTable: + - '' + - _f + - _a + - '' +... diff --git a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp index 040a3710b92cfb..c2743748fa1339 100644 --- a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp +++ b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp @@ -20,7 +20,7 @@ namespace macho { using namespace object; using SectionPred = std::function &Sec)>; -static void removeSections(const CopyConfig &Config, Object &Obj) { +static Error removeSections(const CopyConfig &Config, Object &Obj) { SectionPred RemovePred = [](const std::unique_ptr
&) { return false; }; if (!Config.ToRemove.empty()) { @@ -180,7 +180,9 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) { return createStringError(llvm::errc::invalid_argument, "option not supported by llvm-objcopy for MachO"); } - removeSections(Config, Obj); + + if (Error E = removeSections(Config, Obj)) + return E; // Mark symbols to determine which symbols are still needed. if (Config.StripAll) diff --git a/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp b/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp index 6d08e3abccf5a3..b4662ec5b5cd6c 100644 --- a/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp +++ b/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp @@ -28,10 +28,11 @@ void MachOReader::readHeader(Object &O) const { } template -Section constructSectionCommon(SectionType Sec) { +Section constructSectionCommon(SectionType Sec, uint32_t Index) { StringRef SegName(Sec.segname, strnlen(Sec.segname, sizeof(Sec.segname))); StringRef SectName(Sec.sectname, strnlen(Sec.sectname, sizeof(Sec.sectname))); Section S(SegName, SectName); + S.Index = Index; S.Addr = Sec.addr; S.Size = Sec.size; S.Offset = Sec.offset; @@ -45,14 +46,15 @@ Section constructSectionCommon(SectionType Sec) { return S; } -template Section constructSection(SectionType Sec); +template +Section constructSection(SectionType Sec, uint32_t Index); -template <> Section constructSection(MachO::section Sec) { - return constructSectionCommon(Sec); +template <> Section constructSection(MachO::section Sec, uint32_t Index) { + return constructSectionCommon(Sec, Index); } -template <> Section constructSection(MachO::section_64 Sec) { - Section S = constructSectionCommon(Sec); +template <> Section constructSection(MachO::section_64 Sec, uint32_t Index) { + Section S = constructSectionCommon(Sec, Index); S.Reserved3 = Sec.reserved3; return S; } @@ -62,7 +64,7 @@ template std::vector> extractSections(const object::MachOObjectFile::LoadCommandInfo &LoadCmd, const object::MachOObjectFile &MachOObj, - size_t &NextSectionIndex) { + uint32_t &NextSectionIndex) { auto End = LoadCmd.Ptr + LoadCmd.C.cmdsize; const SectionType *Curr = reinterpret_cast(LoadCmd.Ptr + sizeof(SegmentType)); @@ -72,9 +74,11 @@ extractSections(const object::MachOObjectFile::LoadCommandInfo &LoadCmd, SectionType Sec; memcpy((void *)&Sec, Curr, sizeof(SectionType)); MachO::swapStruct(Sec); - Sections.push_back(std::make_unique
(constructSection(Sec))); + Sections.push_back( + std::make_unique
(constructSection(Sec, NextSectionIndex))); } else { - Sections.push_back(std::make_unique
(constructSection(*Curr))); + Sections.push_back( + std::make_unique
(constructSection(*Curr, NextSectionIndex))); } Section &S = *Sections.back(); @@ -110,7 +114,7 @@ extractSections(const object::MachOObjectFile::LoadCommandInfo &LoadCmd, void MachOReader::readLoadCommands(Object &O) const { // For MachO sections indices start from 1. - size_t NextSectionIndex = 1; + uint32_t NextSectionIndex = 1; for (auto LoadCmd : MachOObj.load_commands()) { LoadCommand LC; switch (LoadCmd.C.cmd) { @@ -189,12 +193,10 @@ void MachOReader::readSymbolTable(Object &O) const { for (auto Symbol : MachOObj.symbols()) { SymbolEntry SE = (MachOObj.is64Bit() - ? constructSymbolEntry( - StrTable, - MachOObj.getSymbol64TableEntry(Symbol.getRawDataRefImpl())) - : constructSymbolEntry( - StrTable, - MachOObj.getSymbolTableEntry(Symbol.getRawDataRefImpl()))); + ? constructSymbolEntry(StrTable, MachOObj.getSymbol64TableEntry( + Symbol.getRawDataRefImpl())) + : constructSymbolEntry(StrTable, MachOObj.getSymbolTableEntry( + Symbol.getRawDataRefImpl()))); O.SymTable.Symbols.push_back(std::make_unique(SE)); } diff --git a/llvm/tools/llvm-objcopy/MachO/Object.cpp b/llvm/tools/llvm-objcopy/MachO/Object.cpp index 4e2b33d840bc86..846098fb7729b3 100644 --- a/llvm/tools/llvm-objcopy/MachO/Object.cpp +++ b/llvm/tools/llvm-objcopy/MachO/Object.cpp @@ -1,5 +1,7 @@ #include "Object.h" #include "../llvm-objcopy.h" +#include "llvm/ADT/SmallPtrSet.h" +#include namespace llvm { namespace objcopy { @@ -22,11 +24,41 @@ void SymbolTable::removeSymbols( std::end(Symbols)); } -void Object::removeSections(function_ref &)> ToRemove) { - for (LoadCommand &LC : LoadCommands) - LC.Sections.erase(std::remove_if(std::begin(LC.Sections), - std::end(LC.Sections), ToRemove), - std::end(LC.Sections)); +Error Object::removeSections( + function_ref &)> ToRemove) { + std::unordered_set RemovedSectionsIndices; + for (LoadCommand &LC : LoadCommands) { + auto It = std::stable_partition( + std::begin(LC.Sections), std::end(LC.Sections), + [&](const std::unique_ptr
&Sec) { return !ToRemove(Sec); }); + for (auto I = It, End = LC.Sections.end(); I != End; ++I) + RemovedSectionsIndices.insert((*I)->Index); + LC.Sections.erase(It, LC.Sections.end()); + } + + auto IsDead = [&](const std::unique_ptr &S) -> bool { + Optional Section = S->section(); + return (Section && RemovedSectionsIndices.count(*Section)); + }; + + SmallPtrSet DeadSymbols; + for (const std::unique_ptr &Sym : SymTable.Symbols) + if (IsDead(Sym)) + DeadSymbols.insert(Sym.get()); + + for (const LoadCommand &LC : LoadCommands) + for (const std::unique_ptr
&Sec : LC.Sections) + for (const RelocationInfo &R : Sec->Relocations) + if (R.Symbol && DeadSymbols.count(R.Symbol)) + return createStringError(std::errc::invalid_argument, + "symbol '%s' defined in section with index " + "'%u' cannot be removed because it is " + "referenced by a relocation in section '%s'", + R.Symbol->Name.c_str(), + *(R.Symbol->section()), + Sec->CanonicalName.c_str()); + SymTable.removeSymbols(IsDead); + return Error::success(); } void Object::addLoadCommand(LoadCommand LC) { diff --git a/llvm/tools/llvm-objcopy/MachO/Object.h b/llvm/tools/llvm-objcopy/MachO/Object.h index d0d4554d75600c..dc828e66fcbd78 100644 --- a/llvm/tools/llvm-objcopy/MachO/Object.h +++ b/llvm/tools/llvm-objcopy/MachO/Object.h @@ -37,6 +37,7 @@ struct MachHeader { struct RelocationInfo; struct Section { + uint32_t Index; std::string Segname; std::string Sectname; // CanonicalName is a string formatted as “,". @@ -83,7 +84,7 @@ struct LoadCommand { // The raw content of the payload of the load command (located right after the // corresponding struct). In some cases it is either empty or can be // copied-over without digging into its structure. - std::vector Payload; + std::vector Payload; // Some load commands can contain (inside the payload) an array of sections, // though the contents of the sections are stored separately. The struct @@ -115,6 +116,10 @@ struct SymbolEntry { bool isUndefinedSymbol() const { return (n_type & MachO::N_TYPE) == MachO::N_UNDF; } + + Optional section() const { + return n_sect == MachO::NO_SECT ? None : Optional(n_sect); + } }; /// The location of the symbol table inside the binary is described by LC_SYMTAB @@ -306,7 +311,8 @@ struct Object { Object() : NewSectionsContents(Alloc) {} - void removeSections(function_ref &)> ToRemove); + Error + removeSections(function_ref &)> ToRemove); void addLoadCommand(LoadCommand LC); /// Creates a new segment load command in the object and returns a reference From 2464d8135e2a4dbcf821ff254012995c05e20fa0 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Wed, 22 Apr 2020 17:16:47 -0400 Subject: [PATCH 14/14] [libc++] Make sure we assume merged typeinfo names on Apple The introduction of LIBCXX_HAS_MERGED_TYPEINFO_NAMES_DEFAULT changed the default from =1 (assuming merged typeinfos) to =0 (not assuming merged typeinfos) on all platforms where at least one other __config_site macro is defined. This commit explicitly enables the assumption of merged typeinfo names on Apple platform to restore the previous behavior, at least until the underlying issue has been fixed. --- libcxx/cmake/caches/Apple.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/libcxx/cmake/caches/Apple.cmake b/libcxx/cmake/caches/Apple.cmake index 215c5bd9dfb1a1..26985c9f335e85 100644 --- a/libcxx/cmake/caches/Apple.cmake +++ b/libcxx/cmake/caches/Apple.cmake @@ -7,6 +7,7 @@ set(LIBCXX_ABI_VERSION "1" CACHE STRING "") set(LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY OFF CACHE BOOL "") set(LIBCXX_ENABLE_STATIC OFF CACHE BOOL "") set(LIBCXX_ENABLE_SHARED ON CACHE BOOL "") +set(LIBCXX_HAS_MERGED_TYPEINFO_NAMES_DEFAULT ON CACHE STRING "") set(LIBCXX_CXX_ABI libcxxabi CACHE STRING "") set(LIBCXX_ENABLE_NEW_DELETE_DEFINITIONS OFF CACHE BOOL "") set(LIBCXX_HIDE_FROM_ABI_PER_TU_BY_DEFAULT ON CACHE BOOL "")