diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp index d010c3ce7e5223..3f735a8484d841 100644 --- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp @@ -34,6 +34,7 @@ #include "MisplacedWideningCastCheck.h" #include "MoveForwardingReferenceCheck.h" #include "MultipleStatementMacroCheck.h" +#include "NoEscapeCheck.h" #include "NotNullTerminatedResultCheck.h" #include "ParentVirtualCallCheck.h" #include "PosixReturnCheck.h" @@ -120,6 +121,7 @@ class BugproneModule : public ClangTidyModule { "bugprone-multiple-statement-macro"); CheckFactories.registerCheck( "bugprone-narrowing-conversions"); + CheckFactories.registerCheck("bugprone-no-escape"); CheckFactories.registerCheck( "bugprone-not-null-terminated-result"); CheckFactories.registerCheck( diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt index 6cc60ff0d7bcfc..6e7a94928a5afc 100644 --- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt @@ -29,6 +29,7 @@ add_clang_library(clangTidyBugproneModule MisplacedWideningCastCheck.cpp MoveForwardingReferenceCheck.cpp MultipleStatementMacroCheck.cpp + NoEscapeCheck.cpp NotNullTerminatedResultCheck.cpp ParentVirtualCallCheck.cpp PosixReturnCheck.cpp diff --git a/clang-tools-extra/clang-tidy/bugprone/NoEscapeCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/NoEscapeCheck.cpp new file mode 100644 index 00000000000000..654e80d9a9c6c8 --- /dev/null +++ b/clang-tools-extra/clang-tidy/bugprone/NoEscapeCheck.cpp @@ -0,0 +1,51 @@ +//===--- NoEscapeCheck.cpp - clang-tidy -----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "NoEscapeCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace bugprone { + +void NoEscapeCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher(callExpr(callee(functionDecl(hasName("::dispatch_async"))), + argumentCountIs(2), + hasArgument(1, blockExpr().bind("arg-block"))), + this); + Finder->addMatcher(callExpr(callee(functionDecl(hasName("::dispatch_after"))), + argumentCountIs(3), + hasArgument(2, blockExpr().bind("arg-block"))), + this); +} + +void NoEscapeCheck::check(const MatchFinder::MatchResult &Result) { + const auto *MatchedEscapingBlock = + Result.Nodes.getNodeAs("arg-block"); + const BlockDecl *EscapingBlockDecl = MatchedEscapingBlock->getBlockDecl(); + for (const BlockDecl::Capture &CapturedVar : EscapingBlockDecl->captures()) { + const VarDecl *Var = CapturedVar.getVariable(); + if (Var && Var->hasAttr()) { + // FIXME: Add a method to get the location of the use of a CapturedVar so + // that we can diagnose the use of the pointer instead of the block. + diag(MatchedEscapingBlock->getBeginLoc(), + "pointer %0 with attribute 'noescape' is captured by an " + "asynchronously-executed block") + << Var; + diag(Var->getBeginLoc(), "the 'noescape' attribute is declared here.", + DiagnosticIDs::Note); + } + } +} + +} // namespace bugprone +} // namespace tidy +} // namespace clang diff --git a/clang-tools-extra/clang-tidy/bugprone/NoEscapeCheck.h b/clang-tools-extra/clang-tidy/bugprone/NoEscapeCheck.h new file mode 100644 index 00000000000000..126c37c9df0a18 --- /dev/null +++ b/clang-tools-extra/clang-tidy/bugprone/NoEscapeCheck.h @@ -0,0 +1,39 @@ +//===--- NoEscapeCheck.h - clang-tidy ---------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_NOESCAPECHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_NOESCAPECHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang { +namespace tidy { +namespace bugprone { + +/// Block arguments in `dispatch_async()` and `dispatch_after()` are guaranteed +/// to escape. If those blocks capture any pointers with the `noescape` +/// attribute, then we warn the user of their error. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-no-escape.html +class NoEscapeCheck : public ClangTidyCheck { +public: + NoEscapeCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.Blocks; + } + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace bugprone +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_NOESCAPECHECK_H diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index c66d5eb6069e9d..c08fd45c2f9679 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -94,6 +94,12 @@ New checks result of a memory allocation function (``malloc()``, ``calloc()``, ``realloc()``, ``alloca()``) instead of its argument. +- New :doc:`bugprone-no-escape + ` check. + + Finds pointers with the ``noescape`` attribute that are captured by an + asynchronously-executed block. + - New :doc:`bugprone-spuriously-wake-up-functions ` check. @@ -206,14 +212,14 @@ Changes in existing checks Now checks ``std::basic_string_view`` by default. - Improved :doc:`readability-else-after-return - ` check now supports a + ` check now supports a `WarnOnConditionVariables` option to control whether to refactor condition variables where possible. - Improved :doc:`readability-identifier-naming ` check. - Now able to rename member references in class template definitions with + Now able to rename member references in class template definitions with explicit access. - Improved :doc:`readability-qualified-auto diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone-no-escape.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone-no-escape.rst new file mode 100644 index 00000000000000..ea137b9679cc2a --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone-no-escape.rst @@ -0,0 +1,18 @@ +.. title:: clang-tidy - bugprone-no-escape + +bugprone-no-escape +================== + +Finds pointers with the ``noescape`` attribute that are captured by an +asynchronously-executed block. The block arguments in ``dispatch_async()`` and +``dispatch_after()`` are guaranteed to escape, so it is an error if a pointer with the +``noescape`` attribute is captured by one of these blocks. + +The following is an example of an invalid use of the ``noescape`` attribute. + + .. code-block:: objc + void foo(__attribute__((noescape)) int *p) { + dispatch_async(queue, ^{ + *p = 123; + }); + }); diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index 7356c585d20ccb..78fed1a8ed9cda 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -70,6 +70,7 @@ Clang-Tidy Checks `bugprone-misplaced-widening-cast `_, `bugprone-move-forwarding-reference `_, "Yes" `bugprone-multiple-statement-macro `_, + `bugprone-no-escape `_, "Yes" `bugprone-not-null-terminated-result `_, "Yes" `bugprone-parent-virtual-call `_, "Yes" `bugprone-posix-return `_, "Yes" diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone-no-escape.m b/clang-tools-extra/test/clang-tidy/checkers/bugprone-no-escape.m new file mode 100644 index 00000000000000..11dba3345fa1a7 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone-no-escape.m @@ -0,0 +1,28 @@ +// RUN: %check_clang_tidy %s bugprone-no-escape %t +// RUN: %check_clang_tidy %s -assume-filename=bugprone-no-escape.c bugprone-no-escape %t -- -- -fblocks + +typedef struct dispatch_queue_s *dispatch_queue_t; +typedef struct dispatch_time_s *dispatch_time_t; +typedef void (^dispatch_block_t)(void); +void dispatch_async(dispatch_queue_t queue, dispatch_block_t block); +void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block); + +extern dispatch_queue_t queue; + +void test_noescape_attribute(__attribute__((noescape)) int *p, int *q) { + dispatch_async(queue, ^{ + *p = 123; + // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: pointer 'p' with attribute 'noescape' is captured by an asynchronously-executed block [bugprone-no-escape] + // CHECK-MESSAGES: :[[@LINE-4]]:30: note: the 'noescape' attribute is declared here. + }); + + dispatch_after(456, queue, ^{ + *p = 789; + // CHECK-MESSAGES: :[[@LINE-2]]:30: warning: pointer 'p' with attribute 'noescape' is captured by an asynchronously-executed block [bugprone-no-escape] + }); + + dispatch_async(queue, ^{ + *q = 0; + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:25: warning: pointer 'q' with attribute 'noescape' is captured by an asynchronously-executed block + }); +} diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 37e0b77e79ed7c..76c38686a05099 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -1099,6 +1099,11 @@ def ObjCSignedCharBool : DiagGroup<"objc-signed-char-bool", ObjCBoolConstantConversion, TautologicalObjCBoolCompare]>; +def ObjCPotentiallyDirectSelector : DiagGroup<"potentially-direct-selector">; +def ObjCStrictPotentiallyDirectSelector : + DiagGroup<"strict-potentially-direct-selector", + [ObjCPotentiallyDirectSelector]>; + // Inline ASM warnings. def ASMOperandWidths : DiagGroup<"asm-operand-widths">; def ASM : DiagGroup<"asm", [ diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index c935545610e04a..e99fd3d1f10563 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1378,8 +1378,14 @@ def warn_multiple_selectors: Warning< "several methods with selector %0 of mismatched types are found " "for the @selector expression">, InGroup, DefaultIgnore; -def err_direct_selector_expression: Error< +def err_direct_selector_expression : Error< "@selector expression formed with direct selector %0">; +def warn_potentially_direct_selector_expression : Warning< + "@selector expression formed with potentially direct selector %0">, + InGroup; +def warn_strict_potentially_direct_selector_expression : Warning< + warn_potentially_direct_selector_expression.Text>, + InGroup, DefaultIgnore; def err_objc_kindof_nonobject : Error< "'__kindof' specifier cannot be applied to non-object type %0">; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 91969267cdb945..1d81ede5dc31e8 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -219,8 +219,9 @@ static RValue EmitBinaryAtomicPost(CodeGenFunction &CGF, Kind, Args[0], Args[1], llvm::AtomicOrdering::SequentiallyConsistent); Result = CGF.Builder.CreateBinOp(Op, Result, Args[1]); if (Invert) - Result = CGF.Builder.CreateBinOp(llvm::Instruction::Xor, Result, - llvm::ConstantInt::get(IntType, -1)); + Result = + CGF.Builder.CreateBinOp(llvm::Instruction::Xor, Result, + llvm::ConstantInt::getAllOnesValue(IntType)); Result = EmitFromInt(CGF, Result, T, ValueType); return RValue::get(Result); } diff --git a/clang/lib/Driver/ToolChains/HIP.cpp b/clang/lib/Driver/ToolChains/HIP.cpp index f75be81622bf70..15c9dbf3488d0d 100644 --- a/clang/lib/Driver/ToolChains/HIP.cpp +++ b/clang/lib/Driver/ToolChains/HIP.cpp @@ -193,8 +193,7 @@ void AMDGCN::Linker::constructGenerateObjFileFromHIPFatBinary( Objf << ObjBuffer; - ArgStringList McArgs{"-triple", Args.MakeArgString(TC.getTripleString()), - "-o", Output.getFilename(), + ArgStringList McArgs{"-o", Output.getFilename(), McinFile, "--filetype=obj"}; const char *Mc = Args.MakeArgString(TC.GetProgramPath("llvm-mc")); C.addCommand(std::make_unique(JA, *this, ResponseFileSupport::None(), diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 2b52415b2800d8..77858b17d62c6d 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -11936,27 +11936,31 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, } } -static void CheckConditionalOperator(Sema &S, ConditionalOperator *E, +static void CheckConditionalOperator(Sema &S, AbstractConditionalOperator *E, SourceLocation CC, QualType T); static void CheckConditionalOperand(Sema &S, Expr *E, QualType T, SourceLocation CC, bool &ICContext) { E = E->IgnoreParenImpCasts(); - if (isa(E)) - return CheckConditionalOperator(S, cast(E), CC, T); + if (auto *CO = dyn_cast(E)) + return CheckConditionalOperator(S, CO, CC, T); AnalyzeImplicitConversions(S, E, CC); if (E->getType() != T) return CheckImplicitConversion(S, E, T, CC, &ICContext); } -static void CheckConditionalOperator(Sema &S, ConditionalOperator *E, +static void CheckConditionalOperator(Sema &S, AbstractConditionalOperator *E, SourceLocation CC, QualType T) { AnalyzeImplicitConversions(S, E->getCond(), E->getQuestionLoc()); + Expr *TrueExpr = E->getTrueExpr(); + if (auto *BCO = dyn_cast(E)) + TrueExpr = BCO->getCommon(); + bool Suspicious = false; - CheckConditionalOperand(S, E->getTrueExpr(), T, CC, Suspicious); + CheckConditionalOperand(S, TrueExpr, T, CC, Suspicious); CheckConditionalOperand(S, E->getFalseExpr(), T, CC, Suspicious); if (T->isBooleanType()) @@ -11975,7 +11979,7 @@ static void CheckConditionalOperator(Sema &S, ConditionalOperator *E, if (E->getType() == T) return; Suspicious = false; - CheckImplicitConversion(S, E->getTrueExpr()->IgnoreParenImpCasts(), + CheckImplicitConversion(S, TrueExpr->IgnoreParenImpCasts(), E->getType(), CC, &Suspicious); if (!Suspicious) CheckImplicitConversion(S, E->getFalseExpr()->IgnoreParenImpCasts(), @@ -12038,7 +12042,7 @@ static void AnalyzeImplicitConversions( // For conditional operators, we analyze the arguments as if they // were being fed directly into the output. - if (auto *CO = dyn_cast(SourceExpr)) { + if (auto *CO = dyn_cast(SourceExpr)) { CheckConditionalOperator(S, CO, CC, T); return; } diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index 192e4184d14440..228a1ec3ba1f91 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -1228,33 +1228,66 @@ static void DiagnoseMismatchedSelectors(Sema &S, SourceLocation AtLoc, } } -static void HelperToDiagnoseDirectSelectorsExpr(Sema &S, SourceLocation AtLoc, - Selector Sel, - ObjCMethodList &MethList, - bool &onlyDirect) { +static ObjCMethodDecl *LookupDirectMethodInMethodList(Sema &S, Selector Sel, + ObjCMethodList &MethList, + bool &onlyDirect, + bool &anyDirect) { + (void)Sel; ObjCMethodList *M = &MethList; - for (M = M->getNext(); M; M = M->getNext()) { + ObjCMethodDecl *DirectMethod = nullptr; + for (; M; M = M->getNext()) { ObjCMethodDecl *Method = M->getMethod(); - if (Method->getSelector() != Sel) + if (!Method) continue; - if (!Method->isDirectMethod()) + assert(Method->getSelector() == Sel && "Method with wrong selector in method list"); + if (Method->isDirectMethod()) { + anyDirect = true; + DirectMethod = Method; + } else onlyDirect = false; } + + return DirectMethod; } -static void DiagnoseDirectSelectorsExpr(Sema &S, SourceLocation AtLoc, - Selector Sel, bool &onlyDirect) { - for (Sema::GlobalMethodPool::iterator b = S.MethodPool.begin(), - e = S.MethodPool.end(); b != e; b++) { - // first, instance methods - ObjCMethodList &InstMethList = b->second.first; - HelperToDiagnoseDirectSelectorsExpr(S, AtLoc, Sel, InstMethList, - onlyDirect); +// Search the global pool for (potentially) direct methods matching the given +// selector. If a non-direct method is found, set \param onlyDirect to false. If +// a direct method is found, set \param anyDirect to true. Returns a direct +// method, if any. +static ObjCMethodDecl *LookupDirectMethodInGlobalPool(Sema &S, Selector Sel, + bool &onlyDirect, + bool &anyDirect) { + auto Iter = S.MethodPool.find(Sel); + if (Iter == S.MethodPool.end()) + return nullptr; - // second, class methods - ObjCMethodList &ClsMethList = b->second.second; - HelperToDiagnoseDirectSelectorsExpr(S, AtLoc, Sel, ClsMethList, onlyDirect); - } + ObjCMethodDecl *DirectInstance = LookupDirectMethodInMethodList( + S, Sel, Iter->second.first, onlyDirect, anyDirect); + ObjCMethodDecl *DirectClass = LookupDirectMethodInMethodList( + S, Sel, Iter->second.second, onlyDirect, anyDirect); + + return DirectInstance ? DirectInstance : DirectClass; +} + +static ObjCMethodDecl *findMethodInCurrentClass(Sema &S, Selector Sel) { + auto *CurMD = S.getCurMethodDecl(); + if (!CurMD) + return nullptr; + ObjCInterfaceDecl *IFace = CurMD->getClassInterface(); + + // The language enforce that only one direct method is present in a given + // class, so we just need to find one method in the current class to know + // whether Sel is potentially direct in this context. + if (ObjCMethodDecl *MD = IFace->lookupMethod(Sel, /*isInstance=*/true)) + return MD; + if (ObjCMethodDecl *MD = IFace->lookupPrivateMethod(Sel, /*isInstance=*/true)) + return MD; + if (ObjCMethodDecl *MD = IFace->lookupMethod(Sel, /*isInstance=*/false)) + return MD; + if (ObjCMethodDecl *MD = IFace->lookupPrivateMethod(Sel, /*isInstance=*/false)) + return MD; + + return nullptr; } ExprResult Sema::ParseObjCSelectorExpression(Selector Sel, @@ -1280,15 +1313,38 @@ ExprResult Sema::ParseObjCSelectorExpression(Selector Sel, } else Diag(SelLoc, diag::warn_undeclared_selector) << Sel; } else { - bool onlyDirect = Method->isDirectMethod(); - DiagnoseDirectSelectorsExpr(*this, AtLoc, Sel, onlyDirect); DiagnoseMismatchedSelectors(*this, AtLoc, Method, LParenLoc, RParenLoc, WarnMultipleSelectors); + + bool onlyDirect = true; + bool anyDirect = false; + ObjCMethodDecl *GlobalDirectMethod = + LookupDirectMethodInGlobalPool(*this, Sel, onlyDirect, anyDirect); + if (onlyDirect) { Diag(AtLoc, diag::err_direct_selector_expression) << Method->getSelector(); Diag(Method->getLocation(), diag::note_direct_method_declared_at) << Method->getDeclName(); + } else if (anyDirect) { + // If we saw any direct methods, see if we see a direct member of the + // current class. If so, the @selector will likely be used to refer to + // this direct method. + ObjCMethodDecl *LikelyTargetMethod = findMethodInCurrentClass(*this, Sel); + if (LikelyTargetMethod && LikelyTargetMethod->isDirectMethod()) { + Diag(AtLoc, diag::warn_potentially_direct_selector_expression) << Sel; + Diag(LikelyTargetMethod->getLocation(), + diag::note_direct_method_declared_at) + << LikelyTargetMethod->getDeclName(); + } else if (!LikelyTargetMethod) { + // Otherwise, emit the "strict" variant of this diagnostic, unless + // LikelyTargetMethod is non-direct. + Diag(AtLoc, diag::warn_strict_potentially_direct_selector_expression) + << Sel; + Diag(GlobalDirectMethod->getLocation(), + diag::note_direct_method_declared_at) + << GlobalDirectMethod->getDeclName(); + } } } diff --git a/clang/test/CodeGen/Atomics.c b/clang/test/CodeGen/Atomics.c index d960ac6df2f96b..ebc9c139775a9d 100644 --- a/clang/test/CodeGen/Atomics.c +++ b/clang/test/CodeGen/Atomics.c @@ -10,6 +10,8 @@ signed int si; unsigned int ui; signed long long sll; unsigned long long ull; +__int128 s128; +unsigned __int128 u128; void test_op_ignore (void) // CHECK-LABEL: define void @test_op_ignore { @@ -48,6 +50,8 @@ void test_op_ignore (void) // CHECK-LABEL: define void @test_op_ignore (void) __sync_fetch_and_xor (&ui, 1); // CHECK: atomicrmw xor i32 (void) __sync_fetch_and_xor (&sll, 1); // CHECK: atomicrmw xor i64 (void) __sync_fetch_and_xor (&ull, 1); // CHECK: atomicrmw xor i64 + (void) __sync_fetch_and_xor (&u128, 1); // CHECK: atomicrmw xor i128 + (void) __sync_fetch_and_xor (&s128, 1); // CHECK: atomicrmw xor i128 (void) __sync_fetch_and_nand (&sc, 1); // CHECK: atomicrmw nand i8 (void) __sync_fetch_and_nand (&uc, 1); // CHECK: atomicrmw nand i8 @@ -168,27 +172,43 @@ void test_op_and_fetch (void) sc = __sync_nand_and_fetch (&sc, uc); // CHECK: atomicrmw nand // CHECK: and // CHECK: xor + // CHECK: -1 uc = __sync_nand_and_fetch (&uc, uc); // CHECK: atomicrmw nand // CHECK: and // CHECK: xor + // CHECK: -1 ss = __sync_nand_and_fetch (&ss, uc); // CHECK: atomicrmw nand // CHECK: and // CHECK: xor + // CHECK: -1 us = __sync_nand_and_fetch (&us, uc); // CHECK: atomicrmw nand // CHECK: and // CHECK: xor + // CHECK: -1 si = __sync_nand_and_fetch (&si, uc); // CHECK: atomicrmw nand // CHECK: and // CHECK: xor + // CHECK: -1 ui = __sync_nand_and_fetch (&ui, uc); // CHECK: atomicrmw nand // CHECK: and // CHECK: xor + // CHECK: -1 sll = __sync_nand_and_fetch (&sll, uc); // CHECK: atomicrmw nand // CHECK: and // CHECK: xor + // CHECK: -1 ull = __sync_nand_and_fetch (&ull, uc); // CHECK: atomicrmw nand // CHECK: and // CHECK: xor + // CHECK: -1 + u128 = __sync_nand_and_fetch (&u128, uc); // CHECK: atomicrmw nand + // CHECK: and + // CHECK: xor + // CHECK: -1 + s128 = __sync_nand_and_fetch (&s128, uc); // CHECK: atomicrmw nand + // CHECK: and + // CHECK: xor + // CHECK: -1 sc = __sync_and_and_fetch (&sc, uc); // CHECK: atomicrmw and uc = __sync_and_and_fetch (&uc, uc); // CHECK: atomicrmw and diff --git a/clang/test/Driver/hip-link-save-temps.hip b/clang/test/Driver/hip-link-save-temps.hip index 60f71d0c5249b0..f2d3630dd119f0 100644 --- a/clang/test/Driver/hip-link-save-temps.hip +++ b/clang/test/Driver/hip-link-save-temps.hip @@ -45,8 +45,7 @@ // CHECK-SAME: "-o" "a.out-hip-amdgcn-amd-amdhsa-gfx900" "obj1-hip-amdgcn-amd-amdhsa-gfx900.o" "obj2-hip-amdgcn-amd-amdhsa-gfx900.o" // CHECK: "{{.*lld.*}}" {{.*}} "-plugin-opt=-amdgpu-internalize-symbols" // CHECK-SAME: "-o" "a.out-hip-amdgcn-amd-amdhsa-gfx906" "obj1-hip-amdgcn-amd-amdhsa-gfx906.o" "obj2-hip-amdgcn-amd-amdhsa-gfx906.o" -// CHECK: {{".*llvm-mc.*"}} "-triple" "amdgcn-amd-amdhsa" "-o" -// CHECK-SAME: "[[OBJBUNDLE:.*.o]]" "{{.*}}.mcin" "--filetype=obj" +// CHECK: {{".*llvm-mc.*"}} "-o" "[[OBJBUNDLE:.*.o]]" "{{.*}}.mcin" "--filetype=obj" // OUT: "{{.*ld.*}}" {{.*}} "-o" "executable" {{.*}} "[[OBJBUNDLE]]" // NOUT: "{{.*ld.*}}" {{.*}} "-o" "a.out" {{.*}} "[[OBJBUNDLE]]" // SLO: "{{.*llvm-ar.*}}" "rcsD" "libTest.a" {{.*}} "[[OBJBUNDLE]]" diff --git a/clang/test/Driver/hip-toolchain-rdc-separate.hip b/clang/test/Driver/hip-toolchain-rdc-separate.hip index f65b95c7de77ad..ab89e19256be96 100644 --- a/clang/test/Driver/hip-toolchain-rdc-separate.hip +++ b/clang/test/Driver/hip-toolchain-rdc-separate.hip @@ -122,8 +122,7 @@ // LINK-SAME: "-targets={{.*}},hip-amdgcn-amd-amdhsa-gfx803,hip-amdgcn-amd-amdhsa-gfx900" // LINK-SAME: "-inputs={{.*}},[[IMG_DEV1]],[[IMG_DEV2]]" "-outputs=[[BUNDLE:.*hipfb]]" -// LINK: {{".*llvm-mc.*"}} "-triple" "amdgcn-amd-amdhsa" "-o" -// LINK-SAME: "[[OBJBUNDLE:.*o]]" "{{.*}}.mcin" "--filetype=obj" +// LINK: {{".*llvm-mc.*"}} "-o" "[[OBJBUNDLE:.*o]]" "{{.*}}.mcin" "--filetype=obj" // LINK: [[LD:".*ld.*"]] {{.*}} "-o" "a.out" {{.*}} "[[A_OBJ_HOST]]" // LINK-SAME: "[[B_OBJ_HOST]]" "[[OBJBUNDLE]]" diff --git a/clang/test/Driver/hip-toolchain-rdc-static-lib.hip b/clang/test/Driver/hip-toolchain-rdc-static-lib.hip index 56b54afbf29f79..dc29b0f87e366a 100644 --- a/clang/test/Driver/hip-toolchain-rdc-static-lib.hip +++ b/clang/test/Driver/hip-toolchain-rdc-static-lib.hip @@ -78,7 +78,6 @@ // CHECK-SAME: "-targets={{.*}},hip-amdgcn-amd-amdhsa-gfx803,hip-amdgcn-amd-amdhsa-gfx900" // CHECK-SAME: "-inputs={{.*}},[[IMG_DEV1]],[[IMG_DEV2]]" "-outputs=[[BUNDLE:.*hipfb]]" -// CHECK: [[MC:".*llvm-mc"]] "-triple" "amdgcn-amd-amdhsa" -// CHECK-SAME: "-o" [[OBJBUNDLE:".*o"]] "{{.*}}.mcin" "--filetype=obj" +// CHECK: [[MC:".*llvm-mc"]] "-o" [[OBJBUNDLE:".*o"]] "{{.*}}.mcin" "--filetype=obj" // CHECK: [[AR:".*llvm-ar.*"]] "rcsD" "{{.*}}.out" [[A_OBJ_HOST]] [[B_OBJ_HOST]] [[OBJBUNDLE]] diff --git a/clang/test/Driver/hip-toolchain-rdc.hip b/clang/test/Driver/hip-toolchain-rdc.hip index 045bbf44ae912d..97d5e59c0c4b12 100644 --- a/clang/test/Driver/hip-toolchain-rdc.hip +++ b/clang/test/Driver/hip-toolchain-rdc.hip @@ -90,8 +90,7 @@ // CHECK-SAME: "-targets={{.*}},hip-amdgcn-amd-amdhsa-gfx803,hip-amdgcn-amd-amdhsa-gfx900" // CHECK-SAME: "-inputs={{.*}},[[IMG_DEV1]],[[IMG_DEV2]]" "-outputs=[[BUNDLE:.*hipfb]]" -// CHECK: [[MC:".*llvm-mc"]] "-triple" "amdgcn-amd-amdhsa" -// CHECK-SAME: "-o" [[OBJBUNDLE:".*o"]] "{{.*}}.mcin" "--filetype=obj" +// CHECK: [[MC:".*llvm-mc"]] "-o" [[OBJBUNDLE:".*o"]] "{{.*}}.mcin" "--filetype=obj" // output the executable // CHECK: [[LD:".*ld.*"]] {{.*}}"-o" "a.out" {{.*}} [[A_OBJ_HOST]] [[B_OBJ_HOST]] [[OBJBUNDLE]] diff --git a/clang/test/SemaObjC/potentially-direct-selector.m b/clang/test/SemaObjC/potentially-direct-selector.m new file mode 100644 index 00000000000000..04f9d2111c9b18 --- /dev/null +++ b/clang/test/SemaObjC/potentially-direct-selector.m @@ -0,0 +1,157 @@ +// RUN: %clang_cc1 %s -Wpotentially-direct-selector -verify +// RUN: %clang_cc1 %s -Wstrict-potentially-direct-selector -verify=expected,strict + +#define NS_DIRECT __attribute__((objc_direct)) + +__attribute__((objc_root_class)) +@interface Dummies +-(void)inBase; +-(void)inBaseImpl; +-(void)inBaseCat; +-(void)inBaseCatImpl; +-(void)inDerived; +-(void)inDerivedImpl; +-(void)inDerivedCat; +-(void)inDerivedCatImpl; ++(void)inBaseClass; ++(void)inDerivedClass; ++(void)inDerivedCatClass; +@end + +__attribute__((objc_root_class)) +@interface Base +-(void)inBase NS_DIRECT; // expected-note + {{direct method}} ++(void)inBaseClass NS_DIRECT; // expected-note + {{direct method}} +@end + +@implementation Base +-(void)inBaseImpl NS_DIRECT { // expected-note + {{direct method}} +} +-(void)inBase {} ++(void)inBaseClass {} +@end + +@interface Base (Cat) +-(void)inBaseCat NS_DIRECT; // expected-note + {{direct method}} +@end + +@implementation Base (Cat) +-(void)inBaseCatImpl NS_DIRECT { // expected-note + {{direct method}} +} +-(void)inBaseCat {} +@end + +@interface Derived : Base +-(void)inDerived NS_DIRECT; // expected-note + {{direct method}} ++(void)inDerivedClass NS_DIRECT; // expected-note + {{direct method}} +@end + +@implementation Derived +-(void)inDerivedImpl NS_DIRECT { // expected-note + {{direct method}} +} +-(void)inDerived {} ++(void)inDerivedClass {} +@end + +@interface Derived (Cat) +-(void)inDerivedCat NS_DIRECT; // expected-note + {{direct method}} ++(void)inDerivedCatClass NS_DIRECT; // expected-note + {{direct method}} +@end + +@implementation Derived (Cat) +-(void)inDerivedCatImpl NS_DIRECT { // expected-note + {{direct method}} +} +-(void)inDerivedCat {} ++(void)inDerivedCatClass {} + +-(void)test1 { + (void)@selector(inBase); // expected-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inBaseImpl); // expected-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inBaseCat); // expected-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inBaseCatImpl); // expected-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inDerived); // expected-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inDerivedImpl); // expected-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inDerivedCat); // expected-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inDerivedCatImpl); // expected-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inDerivedClass); // expected-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inBaseClass); // expected-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inDerivedCatClass); // expected-warning{{@selector expression formed with potentially direct selector}} +} +@end + +void test2() { + (void)@selector(inBase); // strict-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inBaseImpl); // strict-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inBaseCat); // strict-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inBaseCatImpl); // strict-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inDerived); // strict-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inDerivedImpl); // strict-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inDerivedCat); // strict-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inDerivedCatImpl); // strict-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inDerivedClass); // strict-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inBaseClass); // strict-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inDerivedCatClass); // strict-warning{{@selector expression formed with potentially direct selector}} +} + +@interface OnlyBase : Base @end +@implementation OnlyBase +-(void)test3 { + (void)@selector(inBase); // expected-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inBaseImpl); // expected-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inBaseCat); // expected-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inBaseCatImpl); // expected-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inDerived); // strict-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inDerivedImpl); // strict-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inDerivedCat); // strict-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inDerivedCatImpl); // strict-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inDerivedClass); // strict-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inBaseClass); // expected-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inDerivedCatClass); // strict-warning{{@selector expression formed with potentially direct selector}} +} +@end + +__attribute__((objc_root_class)) +@interface Unrelated @end +@implementation Unrelated +-(void)test4 { + (void)@selector(inBase); // strict-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inBaseImpl); // strict-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inBaseCat); // strict-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inBaseCatImpl); // strict-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inDerived); // strict-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inDerivedImpl); // strict-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inDerivedCat); // strict-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inDerivedCatImpl); // strict-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inDerivedClass); // strict-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inBaseClass); // strict-warning{{@selector expression formed with potentially direct selector}} + (void)@selector(inDerivedCatClass); // strict-warning{{@selector expression formed with potentially direct selector}} +} +@end + +@implementation Dummies +-(void)inBase {} +-(void)inBaseImpl {} +-(void)inBaseCat {} +-(void)inBaseCatImpl {} +-(void)inDerived {} +-(void)inDerivedImpl {} +-(void)inDerivedCat {} +-(void)inDerivedCatImpl {} ++(void)inBaseClass {} ++(void)inDerivedClass {} ++(void)inDerivedCatClass {} + +-(void)test5 { + (void)@selector(inBase); + (void)@selector(inBaseImpl); + (void)@selector(inBaseCat); + (void)@selector(inBaseCatImpl); + (void)@selector(inDerived); + (void)@selector(inDerivedImpl); + (void)@selector(inDerivedCat); + (void)@selector(inDerivedCatImpl); + (void)@selector(inDerivedClass); + (void)@selector(inBaseClass); + (void)@selector(inDerivedCatClass); +} +@end diff --git a/clang/test/SemaObjC/signed-char-bool-conversion.m b/clang/test/SemaObjC/signed-char-bool-conversion.m index 183f60fafcd5ad..9442d8fa86a90b 100644 --- a/clang/test/SemaObjC/signed-char-bool-conversion.m +++ b/clang/test/SemaObjC/signed-char-bool-conversion.m @@ -108,3 +108,15 @@ int main() { f(); // expected-note {{in instantiation of function template specialization 'f' requested here}} } #endif + +void t5(BOOL b) { + int i; + b = b ?: YES; // no warning + b = b ?: i; // expected-warning {{implicit conversion from integral type 'int' to 'BOOL'}} + b = (b = i) // expected-warning {{implicit conversion from integral type 'int' to 'BOOL'}} + ?: YES; + b = (1 ? YES : i) ?: YES; // expected-warning {{implicit conversion from integral type 'int' to 'BOOL'}} + b = b ?: (1 ? i : i); // expected-warning 2 {{implicit conversion from integral type 'int' to 'BOOL'}} + + b = b ? YES : (i ?: 0); // expected-warning {{implicit conversion from integral type 'int' to 'BOOL'}} +} diff --git a/compiler-rt/lib/asan/tests/asan_test.cpp b/compiler-rt/lib/asan/tests/asan_test.cpp index 83b0b0e8d33e93..edc98ed1852026 100644 --- a/compiler-rt/lib/asan/tests/asan_test.cpp +++ b/compiler-rt/lib/asan/tests/asan_test.cpp @@ -588,9 +588,6 @@ NOINLINE void TouchStackFunc() { A[i] = i*i; } -// Disabled due to rdar://problem/62141412 -#if !(defined(__APPLE__) && defined(__i386__)) - // Test that we handle longjmp and do not report false positives on stack. TEST(AddressSanitizer, LongJmpTest) { static jmp_buf buf; @@ -600,7 +597,6 @@ TEST(AddressSanitizer, LongJmpTest) { TouchStackFunc(); } } -#endif #if !defined(_WIN32) // Only basic longjmp is available on Windows. NOINLINE void UnderscopeLongJmpFunc1(jmp_buf buf) { @@ -662,8 +658,6 @@ TEST(AddressSanitizer, UnderscopeLongJmpTest) { } } -// Disabled due to rdar://problem/62141412 -#if !(defined(__APPLE__) && defined(__i386__)) TEST(AddressSanitizer, SigLongJmpTest) { static sigjmp_buf buf; if (!sigsetjmp(buf, 1)) { @@ -674,8 +668,6 @@ TEST(AddressSanitizer, SigLongJmpTest) { } #endif -#endif - // FIXME: Why does clang-cl define __EXCEPTIONS? #if defined(__EXCEPTIONS) && !defined(_WIN32) NOINLINE void ThrowFunc() { diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform.h index c68bfa25875585..f0b1e04d1dd686 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform.h @@ -132,6 +132,12 @@ # define SANITIZER_X32 0 #endif +#if defined(__i386__) || defined(_M_IX86) +# define SANITIZER_I386 1 +#else +# define SANITIZER_I386 0 +#endif + #if defined(__mips__) # define SANITIZER_MIPS 1 # if defined(__mips64) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h index fb0dbfb2e9ae1e..a5fcbadb2597de 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -597,7 +597,10 @@ #define SANITIZER_INTERCEPT_QSORT \ (SI_POSIX && !SI_IOSSIM && !SI_WATCHOS && !SI_TVOS && !SI_ANDROID) #define SANITIZER_INTERCEPT_QSORT_R (SI_LINUX && !SI_ANDROID) -#define SANITIZER_INTERCEPT_SIGALTSTACK SI_POSIX +// sigaltstack on i386 macOS cannot be intercepted due to setjmp() +// calling it and assuming that it does not clobber registers. +#define SANITIZER_INTERCEPT_SIGALTSTACK \ + (SI_POSIX && !(SANITIZER_MAC && SANITIZER_I386)) #define SANITIZER_INTERCEPT_UNAME (SI_POSIX && !SI_FREEBSD) #define SANITIZER_INTERCEPT___XUNAME SI_FREEBSD diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td index 0a16faa2b8fe90..bc12f4d455466f 100644 --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -635,6 +635,7 @@ def: F<"no-copy-dt-needed-entries">; def: F<"no-ctors-in-init-array">; def: F<"no-keep-memory">; def: F<"no-pipeline-knowledge">; +def: F<"no-relax">; def: F<"no-warn-mismatch">; def: Flag<["-"], "p">; def: Separate<["--", "-"], "rpath-link">; diff --git a/lld/docs/ld.lld.1 b/lld/docs/ld.lld.1 index 0522feb145f1a3..3acc818afa223f 100644 --- a/lld/docs/ld.lld.1 +++ b/lld/docs/ld.lld.1 @@ -308,6 +308,8 @@ Disable merging .ARM.exidx entries. Page align sections. .It Fl -no-omagic Do not set the text data sections to be writable, page align sections. +.It Fl -no-relax +Disable target-specific relaxations. This is currently a no-op. .It Fl -no-rosegment Do not put read-only non-executable sections in their own segment. .It Fl -no-undefined-version diff --git a/lld/test/ELF/silent-ignore.test b/lld/test/ELF/silent-ignore.test index 600c9f86b18a5b..6f76809d0e119a 100644 --- a/lld/test/ELF/silent-ignore.test +++ b/lld/test/ELF/silent-ignore.test @@ -7,6 +7,7 @@ RUN: -no-copy-dt-needed-entries \ RUN: -no-ctors-in-init-array \ RUN: -no-keep-memory \ RUN: -no-pipeline-knowledge \ +RUN: --no-relax \ RUN: -no-warn-mismatch \ RUN: -p \ RUN: -rpath-link . \ diff --git a/lldb/include/lldb/Utility/DataExtractor.h b/lldb/include/lldb/Utility/DataExtractor.h index 8f82ae5af42da1..0210af5cf6d189 100644 --- a/lldb/include/lldb/Utility/DataExtractor.h +++ b/lldb/include/lldb/Utility/DataExtractor.h @@ -9,12 +9,14 @@ #ifndef LLDB_UTILITY_DATAEXTRACTOR_H #define LLDB_UTILITY_DATAEXTRACTOR_H +#include "lldb/Utility/Endian.h" #include "lldb/lldb-defines.h" #include "lldb/lldb-enumerations.h" #include "lldb/lldb-forward.h" #include "lldb/lldb-types.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/Support/DataExtractor.h" +#include "llvm/Support/SwapByteOrder.h" #include #include @@ -979,6 +981,21 @@ class DataExtractor { } protected: + template T Get(lldb::offset_t *offset_ptr, T fail_value) const { + constexpr size_t src_size = sizeof(T); + T val = fail_value; + + const T *src = static_cast(GetData(offset_ptr, src_size)); + if (!src) + return val; + + memcpy(&val, src, src_size); + if (m_byte_order != endian::InlHostByteOrder()) + llvm::sys::swapByteOrder(val); + + return val; + } + // Member variables const uint8_t *m_start; ///< A pointer to the first byte of data. const uint8_t diff --git a/lldb/source/Utility/DataExtractor.cpp b/lldb/source/Utility/DataExtractor.cpp index ac3662a8e3c83b..64b878d7dee743 100644 --- a/lldb/source/Utility/DataExtractor.cpp +++ b/lldb/source/Utility/DataExtractor.cpp @@ -15,7 +15,6 @@ #include "lldb/Utility/DataBuffer.h" #include "lldb/Utility/DataBufferHeap.h" -#include "lldb/Utility/Endian.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/Stream.h" @@ -624,41 +623,11 @@ int64_t DataExtractor::GetMaxS64Bitfield(offset_t *offset_ptr, size_t size, } float DataExtractor::GetFloat(offset_t *offset_ptr) const { - typedef float float_type; - float_type val = 0.0; - const size_t src_size = sizeof(float_type); - const float_type *src = - static_cast(GetData(offset_ptr, src_size)); - if (src) { - if (m_byte_order != endian::InlHostByteOrder()) { - const uint8_t *src_data = reinterpret_cast(src); - uint8_t *dst_data = reinterpret_cast(&val); - for (size_t i = 0; i < sizeof(float_type); ++i) - dst_data[sizeof(float_type) - 1 - i] = src_data[i]; - } else { - val = *src; - } - } - return val; + return Get(offset_ptr, 0.0f); } double DataExtractor::GetDouble(offset_t *offset_ptr) const { - typedef double float_type; - float_type val = 0.0; - const size_t src_size = sizeof(float_type); - const float_type *src = - static_cast(GetData(offset_ptr, src_size)); - if (src) { - if (m_byte_order != endian::InlHostByteOrder()) { - const uint8_t *src_data = reinterpret_cast(src); - uint8_t *dst_data = reinterpret_cast(&val); - for (size_t i = 0; i < sizeof(float_type); ++i) - dst_data[sizeof(float_type) - 1 - i] = src_data[i]; - } else { - val = *src; - } - } - return val; + return Get(offset_ptr, 0.0); } long double DataExtractor::GetLongDouble(offset_t *offset_ptr) const { diff --git a/lldb/unittests/Utility/DataExtractorTest.cpp b/lldb/unittests/Utility/DataExtractorTest.cpp index 109c15297b165a..536e69755d17bb 100644 --- a/lldb/unittests/Utility/DataExtractorTest.cpp +++ b/lldb/unittests/Utility/DataExtractorTest.cpp @@ -299,3 +299,105 @@ TEST(DataExtractorTest, GetULEB128_bit63) { EXPECT_EQ(expected, BE.GetULEB128(&offset)); EXPECT_EQ(9U, offset); } + +TEST(DataExtractorTest, GetFloat) { + float expected = 4.0f; + lldb::offset_t offset; + + { + uint8_t buffer[] = {0x00, 0x00, 0x80, 0x40}; + DataExtractor LE(buffer, sizeof(buffer), lldb::eByteOrderLittle, + sizeof(void *)); + + offset = 0; + EXPECT_DOUBLE_EQ(expected, LE.GetFloat(&offset)); + EXPECT_EQ(4U, offset); + } + + { + uint8_t buffer[] = {0x40, 0x80, 0x00, 0x00}; + DataExtractor BE(buffer, sizeof(buffer), lldb::eByteOrderBig, + sizeof(void *)); + offset = 0; + EXPECT_DOUBLE_EQ(expected, BE.GetFloat(&offset)); + EXPECT_EQ(4U, offset); + } +} + +TEST(DataExtractorTest, GetFloatUnaligned) { + float expected = 4.0f; + lldb::offset_t offset; + + { + uint8_t buffer[] = {0x00, 0x00, 0x00, 0x80, 0x40}; + DataExtractor LE(buffer, sizeof(buffer), lldb::eByteOrderLittle, + sizeof(void *)); + + offset = 1; + EXPECT_DOUBLE_EQ(expected, LE.GetFloat(&offset)); + EXPECT_EQ(5U, offset); + } + + { + uint8_t buffer[] = {0x00, 0x40, 0x80, 0x00, 0x00}; + DataExtractor BE(buffer, sizeof(buffer), lldb::eByteOrderBig, + sizeof(void *)); + offset = 1; + EXPECT_DOUBLE_EQ(expected, BE.GetFloat(&offset)); + EXPECT_EQ(5U, offset); + } +} + +TEST(DataExtractorTest, GetDouble) { + if (sizeof(double) != 8) + return; + + double expected = 4.0f; + lldb::offset_t offset; + + { + uint8_t buffer[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40}; + DataExtractor LE(buffer, sizeof(buffer), lldb::eByteOrderLittle, + sizeof(void *)); + + offset = 0; + EXPECT_DOUBLE_EQ(expected, LE.GetDouble(&offset)); + EXPECT_EQ(8U, offset); + } + + { + uint8_t buffer[] = {0x40, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + DataExtractor BE(buffer, sizeof(buffer), lldb::eByteOrderBig, + sizeof(void *)); + offset = 0; + EXPECT_DOUBLE_EQ(expected, BE.GetDouble(&offset)); + EXPECT_EQ(8U, offset); + } +} + +TEST(DataExtractorTest, GetDoubleUnaligned) { + if (sizeof(double) != 8) + return; + + float expected = 4.0f; + lldb::offset_t offset; + + { + uint8_t buffer[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40}; + DataExtractor LE(buffer, sizeof(buffer), lldb::eByteOrderLittle, + sizeof(void *)); + + offset = 1; + EXPECT_DOUBLE_EQ(expected, LE.GetDouble(&offset)); + EXPECT_EQ(9U, offset); + } + + { + uint8_t buffer[] = {0x00, 0x40, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + DataExtractor BE(buffer, sizeof(buffer), lldb::eByteOrderBig, + sizeof(void *)); + offset = 1; + EXPECT_DOUBLE_EQ(expected, BE.GetDouble(&offset)); + EXPECT_EQ(9U, offset); + } +} diff --git a/llvm/docs/DeveloperPolicy.rst b/llvm/docs/DeveloperPolicy.rst index 22f29a06b28936..8d424e63372a78 100644 --- a/llvm/docs/DeveloperPolicy.rst +++ b/llvm/docs/DeveloperPolicy.rst @@ -521,8 +521,69 @@ C API Changes release notes so that it's clear to external users who do not follow the project how the C API is changing and evolving. -New Targets ------------ +.. _toolchain: + +Updating Toolchain Requirements +------------------------------- + +We intend to require newer toolchains as time goes by. This means LLVM's +codebase can use newer versions of C++ as they get standardized. Requiring newer +toolchains to build LLVM can be painful for those building LLVM; therefore, it +will only be done through the following process: + + * It is a general goal to support LLVM and GCC versions from the last 3 years + at a minimum. This time-based guideline is not strict: we may support much + older compilers, or decide to support fewer versions. + + * An RFC is sent to the `llvm-dev mailing list `_ + + - Detail upsides of the version increase (e.g. which newer C++ language or + library features LLVM should use; avoid miscompiles in particular compiler + versions, etc). + - Detail downsides on important platforms (e.g. Ubuntu LTS status). + + * Once the RFC reaches consensus, update the CMake toolchain version checks as + well as the :doc:`getting started` guide. This provides a + softer transition path for developers compiling LLVM, because the + error can be turned into a warning using a CMake flag. This is an important + step: LLVM still doesn't have code which requires the new toolchains, but it + soon will. If you compile LLVM but don't read the mailing list, we should + tell you! + + * Ensure that at least one LLVM release has had this soft-error. Not all + developers compile LLVM top-of-tree. These release-bound developers should + also be told about upcoming changes. + + * Turn the soft-error into a hard-error after said LLVM release has branched. + + * Update the :doc:`coding standards` to allow the new + features we've explicitly approved in the RFC. + + * Start using the new features in LLVM's codebase. + +Here's a `sample RFC +`_ and the +`corresponding change `_. + +.. _new-llvm-components: + +Introducing New Components into LLVM +==================================== + +The LLVM community is a vibrant and exciting place to be, and we look to be +inclusive of new projects and foster new communities, and increase +collaboration across industry and academia. + +That said, we need to strike a balance between being inclusive of new ideas and +people and the cost of ongoing maintenance that new code requires. As such, we +have the following general policies for introducing major new components into +the LLVM world. However, this is really only intended to cover common cases +that we have seen arise: different situations are different, and we are open +to discussing unusual cases as well - just start an RFC thread on the +`llvm-dev mailing list `_. + +Adding a New Target +------------------- LLVM is very receptive to new targets, even experimental ones, but a number of problems can appear when adding new large portions of code, and back-ends are @@ -606,49 +667,111 @@ In essences, these rules are necessary for targets to gain and retain their status, but also markers to define bit-rot, and will be used to clean up the tree from unmaintained targets. -.. _toolchain: - -Updating Toolchain Requirements -------------------------------- - -We intend to require newer toolchains as time goes by. This means LLVM's -codebase can use newer versions of C++ as they get standardized. Requiring newer -toolchains to build LLVM can be painful for those building LLVM; therefore, it -will only be done through the following process: - - * Generally, try to support LLVM and GCC versions from the last 3 years at a - minimum. This time-based guideline is not strict: we may support much older - compilers, or decide to support fewer versions. - - * An RFC is sent to the `llvm-dev mailing list `_ - - - Detail upsides of the version increase (e.g. which newer C++ language or - library features LLVM should use; avoid miscompiles in particular compiler - versions, etc). - - Detail downsides on important platforms (e.g. Ubuntu LTS status). - - * Once the RFC reaches consensus, update the CMake toolchain version checks as - well as the :doc:`getting started` guide. We want to - soft-error when developers compile LLVM. We say "soft-error" because the - error can be turned into a warning using a CMake flag. This is an important - step: LLVM still doesn't have code which requires the new toolchains, but it - soon will. If you compile LLVM but don't read the mailing list, we should - tell you! - - * Ensure that at least one LLVM release has had this soft-error. Not all - developers compile LLVM top-of-tree. These release-bound developers should - also be told about upcoming changes. - - * Turn the soft-error into a hard-error after said LLVM release has branched. +Adding an Established Project To the LLVM Monorepo +-------------------------------------------------- + +The `LLVM monorepo `_ is the centerpoint +of development in the LLVM world, and has all of the primary LLVM components, +including the LLVM optimizer and code generators, Clang, LLDB, etc. `Monorepos +in general `_ are great because they +allow atomic commits to the project, simplify CI, and make it easier for +subcommunities to collaborate. + +That said, the burden to add things to the LLVM monorepo needs to be very high - +code that is added to this repository is checked out by everyone in the +community. As such, we hold subprojects to a high bar similar to "official +targets", they: + + * Must be generally aligned with the mission of the LLVM project to advance + compilers, languages, tools, runtimes, etc. + * Must conform to all of the policies laid out in this developer policy + document, including license, patent, coding standards, and code of conduct. + * Must have an active community that maintains the code, including established + code owners. + * Should have reasonable documentation about how it works, including a high + quality README file. + * Should have CI to catch breakage within the project itself or due to + underlying LLVM dependencies. + * Should have code free of issues the community finds contentious, or be on a + clear path to resolving them. + * Must be proposed through the LLVM RFC process, and have its addition approved + by the LLVM community - this ultimately mediates the resolution of the + "should" concerns above. + +If you have a project that you think would make sense to add to the LLVM +monorepo, please start an RFC thread on the llvm-dev mailing list to kick off +the discussion. This process can take some time and iteration - please don’t +be discouraged or intimidated by that! + +If you have an earlier stage project that you think is aligned with LLVM, please +see the "Incubating New Projects" section. + +Incubating New Projects +----------------------- - * Update the :doc:`coding standards` to allow the new - features we've explicitly approved in the RFC. +The burden to add a new project to the LLVM monorepo is intentionally very high, +but that can have a chilling effect on new and innovative projects. To help +foster these sorts of projects, LLVM supports an "incubator" process that is +much easier to get started with. It provides space for potentially valuable, +new top-level and sub-projects to reach a critical mass before they have enough +code to prove their utility and grow a community. This also allows +collaboration between teams that already have permissions to make contributions +to projects under the LLVM umbrella. + +Projects which can be considered for the LLVM incubator meet the following +criteria: + + * Must be generally aligned with the mission of the LLVM project to advance + compilers, languages, tools, runtimes, etc. + * Must conform to the license, patent, and code of conduct policies laid out + in this developer policy document. + * Must have a documented charter and development plan, e.g. in the form of a + README file, mission statement, and/or manifesto. + * Should conform to coding standards, incremental development process, and + other expectations. + * Should have a sense of the community that it hopes to eventually foster, and + there should be interest from members with different affiliations / + organizations. + * Should have a feasible path to eventually graduate as a dedicated top-level + or sub-project within the `LLVM monorepo + `_. + * Should include a notice (e.g. in the project README or web page) that the + project is in ‘incubation status’ and is not included in LLVM releases (see + suggested wording below). + * Must be proposed through the LLVM RFC process, and have its addition + approved by the LLVM community - this ultimately mediates the resolution of + the "should" concerns above. + +That said, the project need not have any code to get started, and need not have +an established community at all! Furthermore, incubating projects may pass +through transient states that violate the "Should" guidelines above, or would +otherwise make them unsuitable for direct inclusion in the monorepo (e.g. +dependencies that have not yet been factored appropriately, leveraging +experimental components or APIs that are not yet upstream, etc). + +When approved, the llvm-admin group can grant the new project: + * A new repository in the LLVM Github Organization - but not the LLVM monorepo. + * New mailing list, discourse forum, and/or discord chat hosted with other LLVM + forums. + * Other infrastructure integration can be discussed on a case-by-case basis. + +Graduation to the mono-repo would follow existing processes and standards for +becoming a first-class part of the monorepo. Similarly, an incubating project +may be eventually retired, but no process has been established for that yet. If +and when this comes up, please start an RFC discussion on llvm-dev. + +This process is very new - please expect the details to change, it is always +safe to ask on the `llvm-dev mailing list +`_ about this. + +Suggested disclaimer for the project README and the main project web page: - * Start using the new features in LLVM's codebase. +:: -Here's a `sample RFC -`_ and the -`corresponding change `_. + This project is participating in the LLVM Incubator process: as such, it is + not part of any official LLVM release. While incubation status is not + necessarily a reflection of the completeness or stability of the code, it + does indicate that the project is not yet endorsed as a component of LLVM. .. _copyright-license-patents: diff --git a/llvm/include/llvm/DebugInfo/PDB/Native/NativeLineNumber.h b/llvm/include/llvm/DebugInfo/PDB/Native/NativeLineNumber.h index f105526adf5618..a7ce82c70b08cb 100644 --- a/llvm/include/llvm/DebugInfo/PDB/Native/NativeLineNumber.h +++ b/llvm/include/llvm/DebugInfo/PDB/Native/NativeLineNumber.h @@ -19,7 +19,8 @@ namespace pdb { class NativeLineNumber : public IPDBLineNumber { public: explicit NativeLineNumber(const NativeSession &Session, - const codeview::LineInfo Line, uint32_t Length, + const codeview::LineInfo Line, + uint32_t ColumnNumber, uint32_t Length, uint32_t Section, uint32_t Offset, uint32_t SrcFileId); @@ -39,6 +40,7 @@ class NativeLineNumber : public IPDBLineNumber { private: const NativeSession &Session; const codeview::LineInfo Line; + uint32_t ColumnNumber; uint32_t Section; uint32_t Offset; uint32_t Length; diff --git a/llvm/include/llvm/DebugInfo/PDB/Native/SymbolCache.h b/llvm/include/llvm/DebugInfo/PDB/Native/SymbolCache.h index e14ef320991619..90fd19a7a2fba7 100644 --- a/llvm/include/llvm/DebugInfo/PDB/Native/SymbolCache.h +++ b/llvm/include/llvm/DebugInfo/PDB/Native/SymbolCache.h @@ -75,6 +75,7 @@ class SymbolCache { struct LineTableEntry { uint64_t Addr; codeview::LineInfo Line; + uint32_t ColumnNumber; uint32_t FileNameIndex; bool IsTerminalEntry; }; diff --git a/llvm/include/llvm/IR/IntrinsicsPowerPC.td b/llvm/include/llvm/IR/IntrinsicsPowerPC.td index 6aa0c351e95a0e..12f4a3ce8e28fc 100644 --- a/llvm/include/llvm/IR/IntrinsicsPowerPC.td +++ b/llvm/include/llvm/IR/IntrinsicsPowerPC.td @@ -522,6 +522,15 @@ let TargetPrefix = "ppc" in { // All intrinsics start with "llvm.ppc.". Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_i64_ty, llvm_v4i32_ty], [IntrNoMem]>; + // P10 Vector Insert with immediate. + def int_ppc_altivec_vinsw : + Intrinsic<[llvm_v4i32_ty], + [llvm_v4i32_ty, llvm_i64_ty, llvm_i32_ty], + [IntrNoMem, ImmArg>]>; + def int_ppc_altivec_vinsd : + Intrinsic<[llvm_v2i64_ty], + [llvm_v2i64_ty, llvm_i64_ty, llvm_i32_ty], + [IntrNoMem, ImmArg>]>; } // Vector average. diff --git a/llvm/include/llvm/IR/LegacyPassNameParser.h b/llvm/include/llvm/IR/LegacyPassNameParser.h index 931181930d1636..c33b9fc404729f 100644 --- a/llvm/include/llvm/IR/LegacyPassNameParser.h +++ b/llvm/include/llvm/IR/LegacyPassNameParser.h @@ -73,11 +73,6 @@ class PassNameParser : public PassRegistrationListener, llvm_unreachable(nullptr); } addLiteralOption(P->getPassArgument().data(), P, P->getPassName().data()); - - // Temporary alias for basicaa -> basic-aa - // TODO: remove once everything is migrated to basic-aa - if (P->getPassArgument() == "basic-aa") - addLiteralOption("basicaa", P, "deprecated alias for basic-aa"); } void passEnumerate(const PassInfo *P) override { passRegistered(P); } diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeLineNumber.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeLineNumber.cpp index f493c180794246..2535e09baf625f 100644 --- a/llvm/lib/DebugInfo/PDB/Native/NativeLineNumber.cpp +++ b/llvm/lib/DebugInfo/PDB/Native/NativeLineNumber.cpp @@ -13,10 +13,11 @@ using namespace llvm::pdb; NativeLineNumber::NativeLineNumber(const NativeSession &Session, const codeview::LineInfo Line, - uint32_t Section, uint32_t Offset, - uint32_t Length, uint32_t SrcFileId) - : Session(Session), Line(Line), Section(Section), Offset(Offset), - Length(Length), SrcFileId(SrcFileId) {} + uint32_t ColumnNumber, uint32_t Section, + uint32_t Offset, uint32_t Length, + uint32_t SrcFileId) + : Session(Session), Line(Line), ColumnNumber(ColumnNumber), + Section(Section), Offset(Offset), Length(Length), SrcFileId(SrcFileId) {} uint32_t NativeLineNumber::getLineNumber() const { return Line.getStartLine(); } @@ -24,7 +25,7 @@ uint32_t NativeLineNumber::getLineNumberEnd() const { return Line.getEndLine(); } -uint32_t NativeLineNumber::getColumnNumber() const { return 0; } +uint32_t NativeLineNumber::getColumnNumber() const { return ColumnNumber; } uint32_t NativeLineNumber::getColumnNumberEnd() const { return 0; } diff --git a/llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp b/llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp index 83cf77aae862a3..9f15907b519e84 100644 --- a/llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp +++ b/llvm/lib/DebugInfo/PDB/Native/SymbolCache.cpp @@ -460,18 +460,33 @@ SymbolCache::findLineTable(uint16_t Modi) const { continue; std::vector Entries; + + // If there are column numbers, then they should be in a parallel stream + // to the line numbers. + auto ColIt = Group.Columns.begin(); + auto ColsEnd = Group.Columns.end(); + for (const LineNumberEntry &LN : Group.LineNumbers) { - LineInfo Line(LN.Flags); uint64_t VA = Session.getVAFromSectOffset(RelocSegment, RelocOffset + LN.Offset); - Entries.push_back({VA, Line, Group.NameIndex, false}); + LineInfo Line(LN.Flags); + uint32_t ColNum = 0; + + if (Lines.hasColumnInfo() && ColIt != ColsEnd) { + ColNum = ColIt->StartColumn; + ++ColIt; + } + Entries.push_back({VA, Line, ColNum, Group.NameIndex, false}); } // Add a terminal entry line to mark the end of this subsection. - LineInfo LastLine(Group.LineNumbers.back().Flags); uint64_t VA = Session.getVAFromSectOffset( RelocSegment, RelocOffset + Lines.header()->CodeSize); - Entries.push_back({VA, LastLine, Group.NameIndex, true}); + LineInfo LastLine(Group.LineNumbers.back().Flags); + uint32_t ColNum = + (Lines.hasColumnInfo()) ? Group.Columns.back().StartColumn : 0; + Entries.push_back({VA, LastLine, ColNum, Group.NameIndex, true}); + EntryList.push_back(Entries); } } @@ -571,8 +586,8 @@ SymbolCache::findLineNumbersByVA(uint64_t VA, uint32_t Length) const { auto ChecksumIter = ExpectedChecksums->getArray().at(LineIter->FileNameIndex); uint32_t SrcFileId = getOrCreateSourceFile(*ChecksumIter); - NativeLineNumber LineNum(Session, LineIter->Line, LineSect, LineOff, - LineLength, SrcFileId); + NativeLineNumber LineNum(Session, LineIter->Line, LineIter->ColumnNumber, + LineSect, LineOff, LineLength, SrcFileId); LineNumbers.push_back(LineNum); ++LineIter; } diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def index a28f6f9d6c3e41..ecb532ee555334 100644 --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -221,7 +221,7 @@ FUNCTION_PASS("partially-inline-libcalls", PartiallyInlineLibCallsPass()) FUNCTION_PASS("lcssa", LCSSAPass()) FUNCTION_PASS("loop-data-prefetch", LoopDataPrefetchPass()) FUNCTION_PASS("loop-load-elim", LoopLoadEliminationPass()) -FUNCTION_PASS("loop-fuse", LoopFusePass()) +FUNCTION_PASS("loop-fusion", LoopFusePass()) FUNCTION_PASS("loop-distribute", LoopDistributePass()) FUNCTION_PASS("pgo-memop-opt", PGOMemOPSizeOpt()) FUNCTION_PASS("print", PrintFunctionPass(dbgs())) diff --git a/llvm/lib/Target/PowerPC/PPCInstrPrefix.td b/llvm/lib/Target/PowerPC/PPCInstrPrefix.td index 3ed651abe45321..2c21d0a175ad48 100644 --- a/llvm/lib/Target/PowerPC/PPCInstrPrefix.td +++ b/llvm/lib/Target/PowerPC/PPCInstrPrefix.td @@ -794,8 +794,16 @@ let Predicates = [IsISA3_1] in { (int_ppc_altivec_vsrdbi v16i8:$VRA, v16i8:$VRB, i32:$SH))]>; - def VINSW : VXForm_VRT5_UIM5_RB5_ins<207, "vinsw", []>; - def VINSD : VXForm_VRT5_UIM5_RB5_ins<463, "vinsd", []>; + def VINSW : + VXForm_VRT5_UIM5_RB5_ins<207, "vinsw", + [(set v4i32:$vD, + (int_ppc_altivec_vinsw v4i32:$vDi, i64:$rB, + timm:$UIM))]>; + def VINSD : + VXForm_VRT5_UIM5_RB5_ins<463, "vinsd", + [(set v2i64:$vD, + (int_ppc_altivec_vinsd v2i64:$vDi, i64:$rB, + timm:$UIM))]>; def VINSBVLX : VXForm_VTB5_RA5_ins<15, "vinsbvlx", [(set v16i8:$vD, diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp index 651c504efc0676..3f4ebd5015953c 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -1677,19 +1677,13 @@ SDValue WebAssemblyTargetLowering::LowerShift(SDValue Op, // Only manually lower vector shifts assert(Op.getSimpleValueType().isVector()); - // Unroll non-splat vector shifts - BuildVectorSDNode *ShiftVec; - SDValue SplatVal; - if (!(ShiftVec = dyn_cast(Op.getOperand(1).getNode())) || - !(SplatVal = ShiftVec->getSplatValue())) + auto ShiftVal = Op.getOperand(1); + if (!DAG.isSplatValue(ShiftVal, /*AllowUndefs=*/true)) return unrollVectorShift(Op, DAG); - // All splats except i64x2 const splats are handled by patterns - auto *SplatConst = dyn_cast(SplatVal); - if (!SplatConst || Op.getSimpleValueType() != MVT::v2i64) - return Op; + auto SplatVal = DAG.getSplatValue(ShiftVal); + assert(SplatVal != SDValue()); - // i64x2 const splats are custom lowered to avoid unnecessary wraps unsigned Opcode; switch (Op.getOpcode()) { case ISD::SHL: @@ -1704,9 +1698,11 @@ SDValue WebAssemblyTargetLowering::LowerShift(SDValue Op, default: llvm_unreachable("unexpected opcode"); } - APInt Shift = SplatConst->getAPIntValue().zextOrTrunc(32); + + // Use anyext because none of the high bits can affect the shift + auto ScalarShift = DAG.getAnyExtOrTrunc(SplatVal, DL, MVT::i32); return DAG.getNode(Opcode, DL, Op.getValueType(), Op.getOperand(0), - DAG.getConstant(Shift, DL, MVT::i32)); + ScalarShift); } //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td index b4a8a7bc42ae87..814bb80fb693bb 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td @@ -654,55 +654,36 @@ defm BITMASK : SIMDBitmask; // Bit shifts //===----------------------------------------------------------------------===// -multiclass SIMDShift simdop> { +multiclass SIMDShift simdop> { defm _#vec_t : SIMD_I<(outs V128:$dst), (ins V128:$vec, I32:$x), (outs), (ins), - [(set (vec_t V128:$dst), - (node V128:$vec, (vec_t shift_vec)))], + [(set (vec_t V128:$dst), (node V128:$vec, I32:$x))], vec#"."#name#"\t$dst, $vec, $x", vec#"."#name, simdop>; } multiclass SIMDShiftInt baseInst> { - defm "" : SIMDShift; - defm "" : SIMDShift; - defm "" : SIMDShift; - defm "" : SIMDShift; + defm "" : SIMDShift; + defm "" : SIMDShift; + defm "" : SIMDShift; + defm "" : SIMDShift; } -// Left shift by scalar: shl -defm SHL : SIMDShiftInt; - -// Right shift by scalar: shr_s / shr_u -defm SHR_S : SIMDShiftInt; -defm SHR_U : SIMDShiftInt; - -// Truncate i64 shift operands to i32s, except if they are already i32s -foreach shifts = [[shl, SHL_v2i64], [sra, SHR_S_v2i64], [srl, SHR_U_v2i64]] in { -def : Pat<(v2i64 (shifts[0] - (v2i64 V128:$vec), - (v2i64 (splat2 (i64 (sext I32:$x)))) - )), - (v2i64 (shifts[1] (v2i64 V128:$vec), (i32 I32:$x)))>; -def : Pat<(v2i64 (shifts[0] (v2i64 V128:$vec), (v2i64 (splat2 I64:$x)))), - (v2i64 (shifts[1] (v2i64 V128:$vec), (I32_WRAP_I64 I64:$x)))>; -} - -// 2xi64 shifts with constant shift amounts are custom lowered to avoid wrapping +// WebAssembly SIMD shifts are nonstandard in that the shift amount is +// an i32 rather than a vector, so they need custom nodes. def wasm_shift_t : SDTypeProfile<1, 2, [SDTCisVec<0>, SDTCisSameAs<0, 1>, SDTCisVT<2, i32>] >; def wasm_shl : SDNode<"WebAssemblyISD::VEC_SHL", wasm_shift_t>; def wasm_shr_s : SDNode<"WebAssemblyISD::VEC_SHR_S", wasm_shift_t>; def wasm_shr_u : SDNode<"WebAssemblyISD::VEC_SHR_U", wasm_shift_t>; -foreach shifts = [[wasm_shl, SHL_v2i64], - [wasm_shr_s, SHR_S_v2i64], - [wasm_shr_u, SHR_U_v2i64]] in -def : Pat<(v2i64 (shifts[0] (v2i64 V128:$vec), I32:$x)), - (v2i64 (shifts[1] (v2i64 V128:$vec), I32:$x))>; + +// Left shift by scalar: shl +defm SHL : SIMDShiftInt; + +// Right shift by scalar: shr_s / shr_u +defm SHR_S : SIMDShiftInt; +defm SHR_U : SIMDShiftInt; //===----------------------------------------------------------------------===// // Integer binary arithmetic @@ -766,12 +747,12 @@ def add_nuw : PatFrag<(ops node:$lhs, node:$rhs), "return N->getFlags().hasNoUnsignedWrap();">; foreach nodes = [[v16i8, splat16], [v8i16, splat8]] in -def : Pat<(srl +def : Pat<(wasm_shr_u (add_nuw (add_nuw (nodes[0] V128:$lhs), (nodes[0] V128:$rhs)), (nodes[1] (i32 1)) ), - (nodes[0] (nodes[1] (i32 1))) + (i32 1) ), (!cast("AVGR_U_"#nodes[0]) V128:$lhs, V128:$rhs)>; diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp index 4821dd44e01ffa..575f358361b1b0 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -8002,10 +8002,11 @@ static SDValue LowerBuildVectorv16i8(SDValue Op, unsigned NonZeros, Elt = NextElt; } - // If our first insertion is not the first index then insert into zero - // vector to break any register dependency else use SCALAR_TO_VECTOR. + // If our first insertion is not the first index or zeros are needed, then + // insert into zero vector. Otherwise, use SCALAR_TO_VECTOR (leaves high + // elements undefined). if (!V) { - if (i != 0) + if (i != 0 || NumZero) V = getZeroVector(MVT::v8i16, Subtarget, DAG, dl); else { V = DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, MVT::v4i32, Elt); diff --git a/llvm/lib/Transforms/IPO/GlobalOpt.cpp b/llvm/lib/Transforms/IPO/GlobalOpt.cpp index ed989529d1aed7..d9fb820f7cb530 100644 --- a/llvm/lib/Transforms/IPO/GlobalOpt.cpp +++ b/llvm/lib/Transforms/IPO/GlobalOpt.cpp @@ -2442,7 +2442,7 @@ OptimizeFunctions(Module &M, // FIXME: We should also hoist alloca affected by this to the entry // block if possible. if (F->getAttributes().hasAttrSomewhere(Attribute::InAlloca) && - !F->hasAddressTaken()) { + !F->hasAddressTaken() && !hasMustTailCallers(F)) { RemoveAttribute(F, Attribute::InAlloca); Changed = true; } diff --git a/llvm/test/Analysis/BasicAA/empty.ll b/llvm/test/Analysis/BasicAA/empty.ll index 01eeb1c4193f94..a6fdcabfb3d5a2 100644 --- a/llvm/test/Analysis/BasicAA/empty.ll +++ b/llvm/test/Analysis/BasicAA/empty.ll @@ -1,4 +1,3 @@ -; RUN: opt < %s -basicaa -aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s ; RUN: opt < %s -basic-aa -aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" diff --git a/llvm/test/CodeGen/PowerPC/builtins-ppc-p10permute.ll b/llvm/test/CodeGen/PowerPC/builtins-ppc-p10permute.ll index 577bb212f01840..84bf4032aa34ff 100644 --- a/llvm/test/CodeGen/PowerPC/builtins-ppc-p10permute.ll +++ b/llvm/test/CodeGen/PowerPC/builtins-ppc-p10permute.ll @@ -231,3 +231,25 @@ entry: ret <4 x i32> %0 } declare <4 x i32> @llvm.ppc.altivec.vinswvrx(<4 x i32>, i64, <4 x i32>) + +define <4 x i32> @testVINSW(<4 x i32> %a, i64 %b) { +; CHECK-LABEL: testVINSW: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vinsw v2, r5, 1 +; CHECK-NEXT: blr +entry: + %0 = tail call <4 x i32> @llvm.ppc.altivec.vinsw(<4 x i32> %a, i64 %b, i32 1) + ret <4 x i32> %0 +} +declare <4 x i32> @llvm.ppc.altivec.vinsw(<4 x i32>, i64, i32 immarg) + +define <2 x i64> @testVINSD(<2 x i64> %a, i64 %b) { +; CHECK-LABEL: testVINSD: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vinsd v2, r5, 1 +; CHECK-NEXT: blr +entry: + %0 = tail call <2 x i64> @llvm.ppc.altivec.vinsd(<2 x i64> %a, i64 %b, i32 1) + ret <2 x i64> %0 +} +declare <2 x i64> @llvm.ppc.altivec.vinsd(<2 x i64>, i64, i32 immarg) diff --git a/llvm/test/CodeGen/WebAssembly/simd-shift-complex-splats.ll b/llvm/test/CodeGen/WebAssembly/simd-shift-complex-splats.ll new file mode 100644 index 00000000000000..ded430f8954582 --- /dev/null +++ b/llvm/test/CodeGen/WebAssembly/simd-shift-complex-splats.ll @@ -0,0 +1,27 @@ +; RUN: llc < %s -asm-verbose=false -verify-machineinstrs -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -mattr=+simd128 | FileCheck %s + +; Test that SIMD shifts can be lowered correctly even with shift +; values that are more complex than plain splats. + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +;; TODO: Optimize this further by scalarizing the add + +; CHECK-LABEL: shl_add: +; CHECK-NEXT: .functype shl_add (v128, i32, i32) -> (v128) +; CHECK-NEXT: i8x16.splat $push1=, $1 +; CHECK-NEXT: i8x16.splat $push0=, $2 +; CHECK-NEXT: i8x16.add $push2=, $pop1, $pop0 +; CHECK-NEXT: i8x16.extract_lane_u $push3=, $pop2, 0 +; CHECK-NEXT: i8x16.shl $push4=, $0, $pop3 +; CHECK-NEXT: return $pop4 +define <16 x i8> @shl_add(<16 x i8> %v, i8 %a, i8 %b) { + %t1 = insertelement <16 x i8> undef, i8 %a, i32 0 + %va = shufflevector <16 x i8> %t1, <16 x i8> undef, <16 x i32> zeroinitializer + %t2 = insertelement <16 x i8> undef, i8 %b, i32 0 + %vb = shufflevector <16 x i8> %t2, <16 x i8> undef, <16 x i32> zeroinitializer + %shift = add <16 x i8> %va, %vb + %r = shl <16 x i8> %v, %shift + ret <16 x i8> %r +} diff --git a/llvm/test/CodeGen/WebAssembly/simd-shift-unroll.ll b/llvm/test/CodeGen/WebAssembly/simd-shift-unroll.ll deleted file mode 100644 index 2a5422cb011052..00000000000000 --- a/llvm/test/CodeGen/WebAssembly/simd-shift-unroll.ll +++ /dev/null @@ -1,128 +0,0 @@ -; RUN: llc < %s -asm-verbose=false -verify-machineinstrs -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -mattr=+unimplemented-simd128 | FileCheck %s --check-prefixes CHECK,SIMD128,SIMD128-SLOW - -;; Test that the custom shift unrolling works correctly in cases that -;; cause assertion failures due to illegal types when using -;; DAG.UnrollVectorOp. Regression test for PR45178. - -target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" -target triple = "wasm32-unknown-unknown" - -; CHECK-LABEL: shl_v16i8: -; CHECK-NEXT: .functype shl_v16i8 (v128) -> (v128) -; CHECK-NEXT: i8x16.extract_lane_u $push0=, $0, 0 -; CHECK-NEXT: i32.const $push1=, 3 -; CHECK-NEXT: i32.shl $push2=, $pop0, $pop1 -; CHECK-NEXT: i8x16.splat $push3=, $pop2 -; CHECK-NEXT: i8x16.extract_lane_u $push4=, $0, 1 -; CHECK-NEXT: i8x16.replace_lane $push5=, $pop3, 1, $pop4 -; ... -; CHECK: i8x16.extract_lane_u $push32=, $0, 15 -; CHECK-NEXT: i8x16.replace_lane $push33=, $pop31, 15, $pop32 -; CHECK-NEXT: v8x16.shuffle $push34=, $pop33, $0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -; CHECK-NEXT: return $pop34 -define <16 x i8> @shl_v16i8(<16 x i8> %in) { - %out = shl <16 x i8> %in, - - %ret = shufflevector <16 x i8> %out, <16 x i8> undef, <16 x i32> zeroinitializer - ret <16 x i8> %ret -} - -; CHECK-LABEL: shr_s_v16i8: -; CHECK-NEXT: functype shr_s_v16i8 (v128) -> (v128) -; CHECK-NEXT: i8x16.extract_lane_s $push0=, $0, 0 -; CHECK-NEXT: i32.const $push1=, 3 -; CHECK-NEXT: i32.shr_s $push2=, $pop0, $pop1 -; CHECK-NEXT: i8x16.splat $push3=, $pop2 -; CHECK-NEXT: i8x16.extract_lane_s $push4=, $0, 1 -; CHECK-NEXT: i8x16.replace_lane $push5=, $pop3, 1, $pop4 -; ... -; CHECK: i8x16.extract_lane_s $push32=, $0, 15 -; CHECK-NEXT: i8x16.replace_lane $push33=, $pop31, 15, $pop32 -; CHECK-NEXT: v8x16.shuffle $push34=, $pop33, $0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -; CHECK-NEXT: return $pop34 -define <16 x i8> @shr_s_v16i8(<16 x i8> %in) { - %out = ashr <16 x i8> %in, - - %ret = shufflevector <16 x i8> %out, <16 x i8> undef, <16 x i32> zeroinitializer - ret <16 x i8> %ret -} - -; CHECK-LABEL: shr_u_v16i8: -; CHECK-NEXT: functype shr_u_v16i8 (v128) -> (v128) -; CHECK-NEXT: i8x16.extract_lane_u $push0=, $0, 0 -; CHECK-NEXT: i32.const $push1=, 3 -; CHECK-NEXT: i32.shr_u $push2=, $pop0, $pop1 -; CHECK-NEXT: i8x16.splat $push3=, $pop2 -; CHECK-NEXT: i8x16.extract_lane_u $push4=, $0, 1 -; CHECK-NEXT: i8x16.replace_lane $push5=, $pop3, 1, $pop4 -; ... -; CHECK: i8x16.extract_lane_u $push32=, $0, 15 -; CHECK-NEXT: i8x16.replace_lane $push33=, $pop31, 15, $pop32 -; CHECK-NEXT: v8x16.shuffle $push34=, $pop33, $0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -; CHECK-NEXT: return $pop34 -define <16 x i8> @shr_u_v16i8(<16 x i8> %in) { - %out = lshr <16 x i8> %in, - - %ret = shufflevector <16 x i8> %out, <16 x i8> undef, <16 x i32> zeroinitializer - ret <16 x i8> %ret -} - -; CHECK-LABEL: shl_v8i16: -; CHECK-NEXT: functype shl_v8i16 (v128) -> (v128) -; CHECK-NEXT: i16x8.extract_lane_u $push0=, $0, 0 -; CHECK-NEXT: i32.const $push1=, 9 -; CHECK-NEXT: i32.shl $push2=, $pop0, $pop1 -; CHECK-NEXT: i16x8.splat $push3=, $pop2 -; CHECK-NEXT: i16x8.extract_lane_u $push4=, $0, 1 -; CHECK-NEXT: i16x8.replace_lane $push5=, $pop3, 1, $pop4 -; ... -; CHECK: i16x8.extract_lane_u $push16=, $0, 7 -; CHECK-NEXT: i16x8.replace_lane $push17=, $pop15, 7, $pop16 -; CHECK-NEXT: v8x16.shuffle $push18=, $pop17, $0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 -; CHECK-NEXT: return $pop18 -define <8 x i16> @shl_v8i16(<8 x i16> %in) { - %out = shl <8 x i16> %in, - %ret = shufflevector <8 x i16> %out, <8 x i16> undef, <8 x i32> zeroinitializer - ret <8 x i16> %ret -} - -; CHECK-LABEL: shr_s_v8i16: -; CHECK-NEXT: functype shr_s_v8i16 (v128) -> (v128) -; CHECK-NEXT: i16x8.extract_lane_s $push0=, $0, 0 -; CHECK-NEXT: i32.const $push1=, 9 -; CHECK-NEXT: i32.shr_s $push2=, $pop0, $pop1 -; CHECK-NEXT: i16x8.splat $push3=, $pop2 -; CHECK-NEXT: i16x8.extract_lane_s $push4=, $0, 1 -; CHECK-NEXT: i16x8.replace_lane $push5=, $pop3, 1, $pop4 -; ... -; CHECK: i16x8.extract_lane_s $push16=, $0, 7 -; CHECK-NEXT: i16x8.replace_lane $push17=, $pop15, 7, $pop16 -; CHECK-NEXT: v8x16.shuffle $push18=, $pop17, $0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 -; CHECK-NEXT: return $pop18 -define <8 x i16> @shr_s_v8i16(<8 x i16> %in) { - %out = ashr <8 x i16> %in, - %ret = shufflevector <8 x i16> %out, <8 x i16> undef, <8 x i32> zeroinitializer - ret <8 x i16> %ret -} - -; CHECK-LABEL: shr_u_v8i16: -; CHECK-NEXT: functype shr_u_v8i16 (v128) -> (v128) -; CHECK-NEXT: i16x8.extract_lane_u $push0=, $0, 0 -; CHECK-NEXT: i32.const $push1=, 9 -; CHECK-NEXT: i32.shr_u $push2=, $pop0, $pop1 -; CHECK-NEXT: i16x8.splat $push3=, $pop2 -; CHECK-NEXT: i16x8.extract_lane_u $push4=, $0, 1 -; CHECK-NEXT: i16x8.replace_lane $push5=, $pop3, 1, $pop4 -; ... -; CHECK: i16x8.extract_lane_u $push16=, $0, 7 -; CHECK-NEXT: i16x8.replace_lane $push17=, $pop15, 7, $pop16 -; CHECK-NEXT: v8x16.shuffle $push18=, $pop17, $0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 -; CHECK-NEXT: return $pop18 -define <8 x i16> @shr_u_v8i16(<8 x i16> %in) { - %out = lshr <8 x i16> %in, - %ret = shufflevector <8 x i16> %out, <8 x i16> undef, <8 x i32> zeroinitializer - ret <8 x i16> %ret -} diff --git a/llvm/test/CodeGen/X86/buildvec-insertvec.ll b/llvm/test/CodeGen/X86/buildvec-insertvec.ll index 73daef78bc0407..e428ae8d591948 100644 --- a/llvm/test/CodeGen/X86/buildvec-insertvec.ll +++ b/llvm/test/CodeGen/X86/buildvec-insertvec.ll @@ -783,3 +783,51 @@ define <4 x i32> @ossfuzz5688(i32 %a0) { store i32 %4, i32* undef ret <4 x i32> %5 } + +; If we do not define all bytes that are extracted, this is a miscompile. + +define i32 @PR46586(i8* %p, <4 x i32> %v) { +; SSE2-LABEL: PR46586: +; SSE2: # %bb.0: +; SSE2-NEXT: movzbl 3(%rdi), %eax +; SSE2-NEXT: pxor %xmm1, %xmm1 +; SSE2-NEXT: pinsrw $6, %eax, %xmm1 +; SSE2-NEXT: pshufd {{.*#+}} xmm1 = xmm1[3,1,2,3] +; SSE2-NEXT: movd %xmm1, %eax +; SSE2-NEXT: pshufd {{.*#+}} xmm0 = xmm0[3,1,2,3] +; SSE2-NEXT: movd %xmm0, %ecx +; SSE2-NEXT: xorl %edx, %edx +; SSE2-NEXT: divl %ecx +; SSE2-NEXT: movl %edx, %eax +; SSE2-NEXT: retq +; +; SSE41-LABEL: PR46586: +; SSE41: # %bb.0: +; SSE41-NEXT: pmovzxbd {{.*#+}} xmm1 = mem[0],zero,zero,zero,mem[1],zero,zero,zero,mem[2],zero,zero,zero,mem[3],zero,zero,zero +; SSE41-NEXT: extractps $3, %xmm0, %ecx +; SSE41-NEXT: pextrd $3, %xmm1, %eax +; SSE41-NEXT: xorl %edx, %edx +; SSE41-NEXT: divl %ecx +; SSE41-NEXT: movl %edx, %eax +; SSE41-NEXT: retq +; +; AVX-LABEL: PR46586: +; AVX: # %bb.0: +; AVX-NEXT: vpmovzxbd {{.*#+}} xmm1 = mem[0],zero,zero,zero,mem[1],zero,zero,zero,mem[2],zero,zero,zero,mem[3],zero,zero,zero +; AVX-NEXT: vextractps $3, %xmm0, %ecx +; AVX-NEXT: vpextrd $3, %xmm1, %eax +; AVX-NEXT: xorl %edx, %edx +; AVX-NEXT: divl %ecx +; AVX-NEXT: movl %edx, %eax +; AVX-NEXT: retq + %p0 = getelementptr inbounds i8, i8* %p, i64 0 + %p3 = getelementptr inbounds i8, i8* %p, i64 3 + %t25 = load i8, i8* %p0 + %t28 = load i8, i8* %p3 + %t29 = insertelement <4 x i8> undef, i8 %t25, i32 0 + %t32 = insertelement <4 x i8> %t29, i8 %t28, i32 3 + %t33 = zext <4 x i8> %t32 to <4 x i32> + %t34 = urem <4 x i32> %t33, %v + %t35 = extractelement <4 x i32> %t34, i32 3 + ret i32 %t35 +} diff --git a/llvm/test/CodeGen/X86/extractelement-load.ll b/llvm/test/CodeGen/X86/extractelement-load.ll index 332fea81adff18..752ba5b2a33d6f 100644 --- a/llvm/test/CodeGen/X86/extractelement-load.ll +++ b/llvm/test/CodeGen/X86/extractelement-load.ll @@ -1,7 +1,8 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=i686-unknown -mattr=+sse2 | FileCheck %s --check-prefixes=X32-SSE2 ; RUN: llc < %s -mtriple=x86_64-unknown -mattr=+ssse3 | FileCheck %s --check-prefixes=X64,X64-SSSE3 -; RUN: llc < %s -mtriple=x86_64-unknown -mattr=+avx | FileCheck %s --check-prefixes=X64,X64-AVX +; RUN: llc < %s -mtriple=x86_64-unknown -mattr=+avx | FileCheck %s --check-prefixes=X64,X64-AVX,X64-AVX1 +; RUN: llc < %s -mtriple=x86_64-unknown -mattr=+avx2 | FileCheck %s --check-prefixes=X64,X64-AVX,X64-AVX2 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" @@ -265,3 +266,51 @@ entry: %cond = select i1 %cmp, float 1.000000e+00, float %vecext ret float %cond } + +; FIXME: Incorrect AVX2 codegen due to bad extraction from a VBROADCAST_LOAD of the <2 x i16> constant bitcast as <4 x i32>. +define void @subextract_broadcast_load_constant(<2 x i16>* nocapture %0, i16* nocapture %1, i16* nocapture %2) { +; X32-SSE2-LABEL: subextract_broadcast_load_constant: +; X32-SSE2: # %bb.0: +; X32-SSE2-NEXT: movl {{[0-9]+}}(%esp), %eax +; X32-SSE2-NEXT: movl {{[0-9]+}}(%esp), %ecx +; X32-SSE2-NEXT: movl {{[0-9]+}}(%esp), %edx +; X32-SSE2-NEXT: movl $-1583308898, (%edx) # imm = 0xA1A09F9E +; X32-SSE2-NEXT: movw $-24674, (%ecx) # imm = 0x9F9E +; X32-SSE2-NEXT: movw $-24160, (%eax) # imm = 0xA1A0 +; X32-SSE2-NEXT: retl +; +; X64-SSSE3-LABEL: subextract_broadcast_load_constant: +; X64-SSSE3: # %bb.0: +; X64-SSSE3-NEXT: movl $-1583308898, (%rdi) # imm = 0xA1A09F9E +; X64-SSSE3-NEXT: movw $-24674, (%rsi) # imm = 0x9F9E +; X64-SSSE3-NEXT: movw $-24160, (%rdx) # imm = 0xA1A0 +; X64-SSSE3-NEXT: retq +; +; X64-AVX1-LABEL: subextract_broadcast_load_constant: +; X64-AVX1: # %bb.0: +; X64-AVX1-NEXT: movl $-1583308898, (%rdi) # imm = 0xA1A09F9E +; X64-AVX1-NEXT: movw $-24674, (%rsi) # imm = 0x9F9E +; X64-AVX1-NEXT: movw $-24160, (%rdx) # imm = 0xA1A0 +; X64-AVX1-NEXT: retq +; +; X64-AVX2-LABEL: subextract_broadcast_load_constant: +; X64-AVX2: # %bb.0: +; X64-AVX2-NEXT: movl $-1583308898, (%rdi) # imm = 0xA1A09F9E +; X64-AVX2-NEXT: movw $-24674, (%rsi) # imm = 0x9F9E +; X64-AVX2-NEXT: movw $-24674, (%rdx) # imm = 0x9F9E +; X64-AVX2-NEXT: retq + %4 = bitcast <2 x i16>* %0 to i8* + store i8 -98, i8* %4, align 1 + %5 = getelementptr inbounds i8, i8* %4, i64 1 + store i8 -97, i8* %5, align 1 + %6 = getelementptr inbounds i8, i8* %4, i64 2 + store i8 -96, i8* %6, align 1 + %7 = getelementptr inbounds i8, i8* %4, i64 3 + store i8 -95, i8* %7, align 1 + %8 = load <2 x i16>, <2 x i16>* %0, align 4 + %9 = extractelement <2 x i16> %8, i32 0 + store i16 %9, i16* %1, align 2 + %10 = extractelement <2 x i16> %8, i32 1 + store i16 %10, i16* %2, align 2 + ret void +} diff --git a/llvm/test/Transforms/GlobalOpt/fastcc.ll b/llvm/test/Transforms/GlobalOpt/fastcc.ll index 9c9076d0155b41..edd0688ea92b7f 100644 --- a/llvm/test/Transforms/GlobalOpt/fastcc.ll +++ b/llvm/test/Transforms/GlobalOpt/fastcc.ll @@ -35,6 +35,17 @@ define internal i32 @inalloca(i32* inalloca %p) { ret i32 %rv } +define i32 @inalloca2_caller(i32* inalloca %p) { + %rv = musttail call i32 @inalloca2(i32* inalloca %p) + ret i32 %rv +} +define internal i32 @inalloca2(i32* inalloca %p) { +; Because of the musttail caller, this inalloca cannot be dropped. +; CHECK-LABEL: define internal i32 @inalloca2(i32* inalloca %p) + %rv = load i32, i32* %p + ret i32 %rv +} + define internal i32 @preallocated(i32* preallocated(i32) %p) { ; CHECK-LABEL: define internal fastcc i32 @preallocated(i32* %p) %rv = load i32, i32* %p diff --git a/llvm/test/tools/llvm-symbolizer/pdb/Inputs/test-columns.exe b/llvm/test/tools/llvm-symbolizer/pdb/Inputs/test-columns.exe new file mode 100644 index 00000000000000..1d9a40dc74e5dc Binary files /dev/null and b/llvm/test/tools/llvm-symbolizer/pdb/Inputs/test-columns.exe differ diff --git a/llvm/test/tools/llvm-symbolizer/pdb/Inputs/test-columns.pdb b/llvm/test/tools/llvm-symbolizer/pdb/Inputs/test-columns.pdb new file mode 100644 index 00000000000000..cd1093270e8434 Binary files /dev/null and b/llvm/test/tools/llvm-symbolizer/pdb/Inputs/test-columns.pdb differ diff --git a/llvm/test/tools/llvm-symbolizer/pdb/Inputs/test.cpp b/llvm/test/tools/llvm-symbolizer/pdb/Inputs/test.cpp index bf97594fa4c802..e1ac50f2e820f0 100644 --- a/llvm/test/tools/llvm-symbolizer/pdb/Inputs/test.cpp +++ b/llvm/test/tools/llvm-symbolizer/pdb/Inputs/test.cpp @@ -1,5 +1,7 @@ // To generate the corresponding EXE/PDB, run: // cl /Zi test.cpp +// To generate the PDB with column numbers, run: +// clang-cl /Zi -gcolumn-info test.cpp namespace NS { struct Foo { diff --git a/llvm/test/tools/llvm-symbolizer/pdb/pdb-native-columns.test b/llvm/test/tools/llvm-symbolizer/pdb/pdb-native-columns.test new file mode 100644 index 00000000000000..a8ccc33d035740 --- /dev/null +++ b/llvm/test/tools/llvm-symbolizer/pdb/pdb-native-columns.test @@ -0,0 +1,29 @@ +RUN: echo 0x140006BA0 > %t.input +RUN: echo 0x140006C00 >> %t.input +RUN: echo 0x140006BB0 >> %t.input +RUN: echo 0x140006C10 >> %t.input +RUN: echo 0x140006C20 >> %t.input +RUN: echo 0x140006C30 >> %t.input +RUN: echo 0x140006C40 >> %t.input +RUN: echo 0x140006C70 >> %t.input +RUN: llvm-symbolizer -obj="%p/Inputs/test-columns.exe" -use-native-pdb-reader < %t.input \ +RUN: | FileCheck %s + +This tests that the symbolizer outputs column info when it is present in the pdb. + +CHECK: foo(void) +CHECK-NEXT: test.cpp:11:1 +CHECK: {{^private_symbol$}} +CHECK-NEXT: test.cpp:14:1 +CHECK: {{^main}} +CHECK-NEXT: test.cpp:16:0 +CHECK: {{^foo_cdecl$}} +CHECK-NEXT: test.cpp:25:27 +CHECK: {{^foo_stdcall$}} +CHECK-NEXT: test.cpp:26:31 +CHECK: {{^foo_fastcall$}} +CHECK-NEXT: test.cpp:27:33 +CHECK: {{^foo_vectorcall}} +CHECK-NEXT: test.cpp:28:37 +CHECK: NS::Foo::bar(void) +CHECK-NEXT: test.cpp:6:0 diff --git a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h index e7223bf7349a53..3a701018beb54b 100644 --- a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h +++ b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h @@ -61,6 +61,8 @@ class ModuleTranslation { LLVM::ensureDistinctSuccessors(m); T translator(m, std::move(llvmModule)); + if (failed(translator.convertFunctionSignatures())) + return nullptr; if (failed(translator.convertGlobals())) return nullptr; if (failed(translator.convertFunctions())) @@ -94,6 +96,7 @@ class ModuleTranslation { /// Check whether the module contains only supported ops directly in its body. static LogicalResult checkSupportedModuleOps(Operation *m); + LogicalResult convertFunctionSignatures(); LogicalResult convertFunctions(); LogicalResult convertGlobals(); LogicalResult convertOneFunction(LLVMFuncOp func); diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp index 08150745e80bf9..657aa84afe1c2c 100644 --- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp @@ -783,12 +783,13 @@ LogicalResult ModuleTranslation::checkSupportedModuleOps(Operation *m) { return success(); } -LogicalResult ModuleTranslation::convertFunctions() { +LogicalResult ModuleTranslation::convertFunctionSignatures() { // Lock access to the llvm context. llvm::sys::SmartScopedLock scopedLock( llvmDialect->getLLVMContextMutex()); + // Declare all functions first because there may be function calls that form a - // call graph with cycles. + // call graph with cycles, or global initializers that reference functions. for (auto function : getModuleBody(mlirModule).getOps()) { llvm::FunctionCallee llvmFuncCst = llvmModule->getOrInsertFunction( function.getName(), @@ -802,6 +803,14 @@ LogicalResult ModuleTranslation::convertFunctions() { return failure(); } + return success(); +} + +LogicalResult ModuleTranslation::convertFunctions() { + // Lock access to the llvm context. + llvm::sys::SmartScopedLock scopedLock( + llvmDialect->getLLVMContextMutex()); + // Convert functions. for (auto function : getModuleBody(mlirModule).getOps()) { // Ignore external functions. diff --git a/mlir/lib/Transforms/BufferPlacement.cpp b/mlir/lib/Transforms/BufferPlacement.cpp index 71d397b47ea249..87b2687b6982f1 100644 --- a/mlir/lib/Transforms/BufferPlacement.cpp +++ b/mlir/lib/Transforms/BufferPlacement.cpp @@ -700,15 +700,19 @@ BufferAssignmentPlacer::computeAllocPosition(OpResult result) { BufferAssignmentTypeConverter::BufferAssignmentTypeConverter() { // Keep all types unchanged. addConversion([](Type type) { return type; }); - // A type conversion that converts ranked-tensor type to memref type. + // Convert RankedTensorType to MemRefType. addConversion([](RankedTensorType type) { return (Type)MemRefType::get(type.getShape(), type.getElementType()); }); + // Convert UnrankedTensorType to UnrankedMemRefType. + addConversion([](UnrankedTensorType type) { + return (Type)UnrankedMemRefType::get(type.getElementType(), 0); + }); } /// Checks if `type` has been converted from non-memref type to memref. bool BufferAssignmentTypeConverter::isConvertedMemref(Type type, Type before) { - return type.isa() && !before.isa(); + return type.isa() && !before.isa(); } //===----------------------------------------------------------------------===// diff --git a/mlir/test/Target/llvmir.mlir b/mlir/test/Target/llvmir.mlir index ef7349b01377aa..05b8ef10588aca 100644 --- a/mlir/test/Target/llvmir.mlir +++ b/mlir/test/Target/llvmir.mlir @@ -1230,3 +1230,13 @@ llvm.func @constant_bf16() -> !llvm<"bfloat"> { // CHECK: ret bfloat 0xR4120 +// ----- + +llvm.func @address_taken() { + llvm.return +} + +llvm.mlir.global internal constant @taker_of_address() : !llvm<"void()*"> { + %0 = llvm.mlir.addressof @address_taken : !llvm<"void()*"> + llvm.return %0 : !llvm<"void()*"> +} diff --git a/mlir/test/Transforms/buffer-placement-preparation-allowed-memref-results.mlir b/mlir/test/Transforms/buffer-placement-preparation-allowed-memref-results.mlir index 97c96008f26910..084ac38af6e324 100644 --- a/mlir/test/Transforms/buffer-placement-preparation-allowed-memref-results.mlir +++ b/mlir/test/Transforms/buffer-placement-preparation-allowed-memref-results.mlir @@ -64,6 +64,15 @@ func @simple_signature_conversion(%arg0: tensor<4x8xf32>) -> tensor<4x8xf32> { // ----- +// CHECK-LABEL: func @func_with_unranked_arg_and_result +func @func_with_unranked_arg_and_result(%arg0: tensor<*xf32>) -> tensor<*xf32> { + return %arg0 : tensor<*xf32> +} +// CHECK-SAME: ([[ARG:%.*]]: memref<*xf32>) -> memref<*xf32> +// CHECK-NEXT: return [[ARG]] : memref<*xf32> + +// ----- + // CHECK-LABEL: func @func_and_block_signature_conversion func @func_and_block_signature_conversion(%arg0 : tensor<2xf32>, %cond : i1, %arg1: tensor<4x4xf32>) -> tensor<4x4xf32>{ cond_br %cond, ^bb1, ^bb2 diff --git a/mlir/test/Transforms/buffer-placement-preparation.mlir b/mlir/test/Transforms/buffer-placement-preparation.mlir index 9b0755aad18009..064b0fd7e85a97 100644 --- a/mlir/test/Transforms/buffer-placement-preparation.mlir +++ b/mlir/test/Transforms/buffer-placement-preparation.mlir @@ -284,3 +284,9 @@ func @caller(%arg0: tensor<5xf32>) -> tensor<5xf32> { // CHECK: %[[Y1:.*]] = call @callee(%[[X0]], %[[Y0]]) // CHECK: linalg.copy(%[[Y0]], %[[CALLER_RESULT]]) // CHECK: return + +// CHECK-LABEL: func @func_with_unranked_arg +func @func_with_unranked_arg(%arg0: tensor<*xf32>) { + return +} +// CHECK-SAME: ([[ARG:%.*]]: memref<*xf32>)