diff options
author | wanglei <wanglei@loongson.cn> | 2024-05-16 15:35:28 +0800 |
---|---|---|
committer | wanglei <wanglei@loongson.cn> | 2024-05-16 15:35:28 +0800 |
commit | 4f8f5005ed7ea01b4b18da74b9d64e75d91bf7be (patch) | |
tree | 6b4ec92652f995a0d9514580e67366d4c7cb5e42 | |
parent | 36cb2c4fd7dd4faf60559f0b895800e81a47f4de (diff) | |
parent | d187005cad8c2cb7d44ba3dd6b01c5f0e4c14ae7 (diff) |
[𝘀𝗽𝗿] changes introduced through rebaseupstream/users/wangleiat/spr/main.loongarch-refactor-loongarchabicomputetargetabi
Created using spr 1.3.5-bogner
[skip ci]
25 files changed, 370 insertions, 203 deletions
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index 7b10482dff23..1da74ac7c8bd 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -2488,6 +2488,16 @@ bool ByteCodeExprGen<Emitter>::VisitRecoveryExpr(const RecoveryExpr *E) { return this->emitError(E); } +template <class Emitter> +bool ByteCodeExprGen<Emitter>::VisitAddrLabelExpr(const AddrLabelExpr *E) { + assert(E->getType()->isVoidPointerType()); + + unsigned Offset = allocateLocalPrimitive( + E->getLabel(), PT_Ptr, /*IsConst=*/true, /*IsExtended=*/false); + + return this->emitGetLocal(PT_Ptr, Offset, E); +} + template <class Emitter> bool ByteCodeExprGen<Emitter>::discard(const Expr *E) { OptionScope<Emitter> Scope(this, /*NewDiscardResult=*/true, /*NewInitializing=*/false); diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h index 9f83d173bbae..6039a54d32a5 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.h +++ b/clang/lib/AST/Interp/ByteCodeExprGen.h @@ -122,6 +122,7 @@ public: bool VisitPseudoObjectExpr(const PseudoObjectExpr *E); bool VisitPackIndexingExpr(const PackIndexingExpr *E); bool VisitRecoveryExpr(const RecoveryExpr *E); + bool VisitAddrLabelExpr(const AddrLabelExpr *E); protected: bool visitExpr(const Expr *E) override; diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index 2607e0743251..3e4da487e43c 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -302,7 +302,9 @@ bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc) { QualType T = VD->getType(); if (S.getLangOpts().CPlusPlus && !S.getLangOpts().CPlusPlus11) - return T->isSignedIntegerOrEnumerationType() || T->isUnsignedIntegerOrEnumerationType(); + return (T->isSignedIntegerOrEnumerationType() || + T->isUnsignedIntegerOrEnumerationType()) && + T.isConstQualified(); if (T.isConstQualified()) return true; @@ -316,12 +318,10 @@ bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc) { return false; }; - if (const auto *D = Desc->asValueDecl()) { - if (const auto *VD = dyn_cast<VarDecl>(D); - VD && VD->hasGlobalStorage() && !IsConstType(VD)) { - diagnoseNonConstVariable(S, OpPC, VD); - return S.inConstantContext(); - } + if (const auto *D = Desc->asVarDecl(); + D && D->hasGlobalStorage() && !IsConstType(D)) { + diagnoseNonConstVariable(S, OpPC, D); + return S.inConstantContext(); } return true; diff --git a/clang/lib/AST/Interp/Pointer.cpp b/clang/lib/AST/Interp/Pointer.cpp index d2e34f2c7f09..ee8cedccb8d4 100644 --- a/clang/lib/AST/Interp/Pointer.cpp +++ b/clang/lib/AST/Interp/Pointer.cpp @@ -191,7 +191,7 @@ void Pointer::print(llvm::raw_ostream &OS) const { else OS << Offset << ", "; - if (isBlockPointer() && PointeeStorage.BS.Pointee) + if (PointeeStorage.BS.Pointee) OS << PointeeStorage.BS.Pointee->getSize(); else OS << "nullptr"; diff --git a/clang/lib/AST/Interp/Program.cpp b/clang/lib/AST/Interp/Program.cpp index 31a64e13d2b1..e3d48d5a8ddb 100644 --- a/clang/lib/AST/Interp/Program.cpp +++ b/clang/lib/AST/Interp/Program.cpp @@ -152,8 +152,7 @@ std::optional<unsigned> Program::getOrCreateDummy(const ValueDecl *VD) { if (std::optional<PrimType> T = Ctx.classify(QT)) Desc = createDescriptor(VD, *T, std::nullopt, true, false); else - Desc = createDescriptor(VD, VD->getType().getTypePtr(), std::nullopt, true, - false); + Desc = createDescriptor(VD, QT.getTypePtr(), std::nullopt, true, false); if (!Desc) Desc = allocateDescriptor(VD); diff --git a/clang/lib/CodeGen/Targets/AArch64.cpp b/clang/lib/CodeGen/Targets/AArch64.cpp index e32b060ebeb9..0a4711fb2170 100644 --- a/clang/lib/CodeGen/Targets/AArch64.cpp +++ b/clang/lib/CodeGen/Targets/AArch64.cpp @@ -317,7 +317,7 @@ AArch64ABIInfo::classifyArgumentType(QualType Ty, bool IsVariadic, if (const auto *EIT = Ty->getAs<BitIntType>()) if (EIT->getNumBits() > 128) - return getNaturalAlignIndirect(Ty); + return getNaturalAlignIndirect(Ty, false); return (isPromotableIntegerTypeForABI(Ty) && isDarwinPCS() ? ABIArgInfo::getExtend(Ty) diff --git a/clang/lib/StaticAnalyzer/Checkers/ErrnoChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ErrnoChecker.cpp index 18e718e08553..72fd6781a756 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ErrnoChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ErrnoChecker.cpp @@ -205,7 +205,7 @@ void ErrnoChecker::checkPreCall(const CallEvent &Call, // Probably 'strerror'? if (CallF->isExternC() && CallF->isGlobal() && C.getSourceManager().isInSystemHeader(CallF->getLocation()) && - !isErrno(CallF)) { + !isErrnoLocationCall(Call)) { if (getErrnoState(C.getState()) == MustBeChecked) { std::optional<ento::Loc> ErrnoLoc = getErrnoLoc(C.getState()); assert(ErrnoLoc && "ErrnoLoc should exist if an errno state is set."); diff --git a/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp index 1b34ea0e056e..6ffc05f06742 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp @@ -39,10 +39,15 @@ namespace { // Name of the "errno" variable. // FIXME: Is there a system where it is not called "errno" but is a variable? const char *ErrnoVarName = "errno"; + // Names of functions that return a location of the "errno" value. // FIXME: Are there other similar function names? -const char *ErrnoLocationFuncNames[] = {"__errno_location", "___errno", - "__errno", "_errno", "__error"}; +CallDescriptionSet ErrnoLocationCalls{ + {CDM::CLibrary, {"__errno_location"}, 0, 0}, + {CDM::CLibrary, {"___errno"}, 0, 0}, + {CDM::CLibrary, {"__errno"}, 0, 0}, + {CDM::CLibrary, {"_errno"}, 0, 0}, + {CDM::CLibrary, {"__error"}, 0, 0}}; class ErrnoModeling : public Checker<check::ASTDecl<TranslationUnitDecl>, check::BeginFunction, @@ -54,16 +59,10 @@ public: void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const; bool evalCall(const CallEvent &Call, CheckerContext &C) const; - // The declaration of an "errno" variable or "errno location" function. - mutable const Decl *ErrnoDecl = nullptr; - private: - // FIXME: Names from `ErrnoLocationFuncNames` are used to build this set. - CallDescriptionSet ErrnoLocationCalls{{{"__errno_location"}, 0, 0}, - {{"___errno"}, 0, 0}, - {{"__errno"}, 0, 0}, - {{"_errno"}, 0, 0}, - {{"__error"}, 0, 0}}; + // The declaration of an "errno" variable on systems where errno is + // represented by a variable (and not a function that queries its location). + mutable const VarDecl *ErrnoDecl = nullptr; }; } // namespace @@ -74,9 +73,13 @@ REGISTER_TRAIT_WITH_PROGRAMSTATE(ErrnoRegion, const MemRegion *) REGISTER_TRAIT_WITH_PROGRAMSTATE(ErrnoState, errno_modeling::ErrnoCheckState) -/// Search for a variable called "errno" in the AST. -/// Return nullptr if not found. -static const VarDecl *getErrnoVar(ASTContext &ACtx) { +void ErrnoModeling::checkASTDecl(const TranslationUnitDecl *D, + AnalysisManager &Mgr, BugReporter &BR) const { + // Try to find the declaration of the external variable `int errno;`. + // There are also C library implementations, where the `errno` location is + // accessed via a function that returns its address; in those environments + // this callback has no effect. + ASTContext &ACtx = Mgr.getASTContext(); IdentifierInfo &II = ACtx.Idents.get(ErrnoVarName); auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II); auto Found = llvm::find_if(LookupRes, [&ACtx](const Decl *D) { @@ -86,47 +89,8 @@ static const VarDecl *getErrnoVar(ASTContext &ACtx) { VD->getType().getCanonicalType() == ACtx.IntTy; return false; }); - if (Found == LookupRes.end()) - return nullptr; - - return cast<VarDecl>(*Found); -} - -/// Search for a function with a specific name that is used to return a pointer -/// to "errno". -/// Return nullptr if no such function was found. -static const FunctionDecl *getErrnoFunc(ASTContext &ACtx) { - SmallVector<const Decl *> LookupRes; - for (StringRef ErrnoName : ErrnoLocationFuncNames) { - IdentifierInfo &II = ACtx.Idents.get(ErrnoName); - llvm::append_range(LookupRes, ACtx.getTranslationUnitDecl()->lookup(&II)); - } - - auto Found = llvm::find_if(LookupRes, [&ACtx](const Decl *D) { - if (auto *FD = dyn_cast<FunctionDecl>(D)) - return ACtx.getSourceManager().isInSystemHeader(FD->getLocation()) && - FD->isExternC() && FD->getNumParams() == 0 && - FD->getReturnType().getCanonicalType() == - ACtx.getPointerType(ACtx.IntTy); - return false; - }); - if (Found == LookupRes.end()) - return nullptr; - - return cast<FunctionDecl>(*Found); -} - -void ErrnoModeling::checkASTDecl(const TranslationUnitDecl *D, - AnalysisManager &Mgr, BugReporter &BR) const { - // Try to find an usable `errno` value. - // It can be an external variable called "errno" or a function that returns a - // pointer to the "errno" value. This function can have different names. - // The actual case is dependent on the C library implementation, we - // can only search for a match in one of these variations. - // We assume that exactly one of these cases might be true. - ErrnoDecl = getErrnoVar(Mgr.getASTContext()); - if (!ErrnoDecl) - ErrnoDecl = getErrnoFunc(Mgr.getASTContext()); + if (Found != LookupRes.end()) + ErrnoDecl = cast<VarDecl>(*Found); } void ErrnoModeling::checkBeginFunction(CheckerContext &C) const { @@ -136,25 +100,18 @@ void ErrnoModeling::checkBeginFunction(CheckerContext &C) const { ASTContext &ACtx = C.getASTContext(); ProgramStateRef State = C.getState(); - if (const auto *ErrnoVar = dyn_cast_or_null<VarDecl>(ErrnoDecl)) { - // There is an external 'errno' variable. - // Use its memory region. - // The memory region for an 'errno'-like variable is allocated in system - // space by MemRegionManager. - const MemRegion *ErrnoR = - State->getRegion(ErrnoVar, C.getLocationContext()); + const MemRegion *ErrnoR = nullptr; + + if (ErrnoDecl) { + // There is an external 'errno' variable, so we can simply use the memory + // region that's associated with it. + ErrnoR = State->getRegion(ErrnoDecl, C.getLocationContext()); assert(ErrnoR && "Memory region should exist for the 'errno' variable."); - State = State->set<ErrnoRegion>(ErrnoR); - State = - errno_modeling::setErrnoValue(State, C, 0, errno_modeling::Irrelevant); - C.addTransition(State); - } else if (ErrnoDecl) { - assert(isa<FunctionDecl>(ErrnoDecl) && "Invalid errno location function."); - // There is a function that returns the location of 'errno'. - // We must create a memory region for it in system space. - // Currently a symbolic region is used with an artifical symbol. - // FIXME: It is better to have a custom (new) kind of MemRegion for such - // cases. + } else { + // There is no 'errno' variable, so create a new symbolic memory region + // that can be used to model the return value of the "get the location of + // errno" internal functions. + // NOTE: this `SVal` is created even if errno is not defined or used. SValBuilder &SVB = C.getSValBuilder(); MemRegionManager &RMgr = C.getStateManager().getRegionManager(); @@ -162,27 +119,31 @@ void ErrnoModeling::checkBeginFunction(CheckerContext &C) const { RMgr.getGlobalsRegion(MemRegion::GlobalSystemSpaceRegionKind); // Create an artifical symbol for the region. - // It is not possible to associate a statement or expression in this case. + // Note that it is not possible to associate a statement or expression in + // this case and the `symbolTag` (opaque pointer tag) is just the address + // of the data member `ErrnoDecl` of the singleton `ErrnoModeling` checker + // object. const SymbolConjured *Sym = SVB.conjureSymbol( nullptr, C.getLocationContext(), ACtx.getLValueReferenceType(ACtx.IntTy), C.blockCount(), &ErrnoDecl); // The symbolic region is untyped, create a typed sub-region in it. // The ElementRegion is used to make the errno region a typed region. - const MemRegion *ErrnoR = RMgr.getElementRegion( + ErrnoR = RMgr.getElementRegion( ACtx.IntTy, SVB.makeZeroArrayIndex(), RMgr.getSymbolicRegion(Sym, GlobalSystemSpace), C.getASTContext()); - State = State->set<ErrnoRegion>(ErrnoR); - State = - errno_modeling::setErrnoValue(State, C, 0, errno_modeling::Irrelevant); - C.addTransition(State); } + assert(ErrnoR); + State = State->set<ErrnoRegion>(ErrnoR); + State = + errno_modeling::setErrnoValue(State, C, 0, errno_modeling::Irrelevant); + C.addTransition(State); } bool ErrnoModeling::evalCall(const CallEvent &Call, CheckerContext &C) const { // Return location of "errno" at a call to an "errno address returning" // function. - if (ErrnoLocationCalls.contains(Call)) { + if (errno_modeling::isErrnoLocationCall(Call)) { ProgramStateRef State = C.getState(); const MemRegion *ErrnoR = State->get<ErrnoRegion>(); @@ -260,14 +221,8 @@ ProgramStateRef clearErrnoState(ProgramStateRef State) { return setErrnoState(State, Irrelevant); } -bool isErrno(const Decl *D) { - if (const auto *VD = dyn_cast_or_null<VarDecl>(D)) - if (const IdentifierInfo *II = VD->getIdentifier()) - return II->getName() == ErrnoVarName; - if (const auto *FD = dyn_cast_or_null<FunctionDecl>(D)) - if (const IdentifierInfo *II = FD->getIdentifier()) - return llvm::is_contained(ErrnoLocationFuncNames, II->getName()); - return false; +bool isErrnoLocationCall(const CallEvent &CE) { + return ErrnoLocationCalls.contains(CE); } const NoteTag *getErrnoNoteTag(CheckerContext &C, const std::string &Message) { diff --git a/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h b/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h index 6b53572fe5e2..95da8a28d325 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h +++ b/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h @@ -71,12 +71,9 @@ ProgramStateRef setErrnoState(ProgramStateRef State, ErrnoCheckState EState); /// Clear state of errno (make it irrelevant). ProgramStateRef clearErrnoState(ProgramStateRef State); -/// Determine if a `Decl` node related to 'errno'. -/// This is true if the declaration is the errno variable or a function -/// that returns a pointer to the 'errno' value (usually the 'errno' macro is -/// defined with this function). \p D is not required to be a canonical -/// declaration. -bool isErrno(const Decl *D); +/// Determine if `Call` is a call to an internal function that returns the +/// location of `errno` (in environments where errno is accessed this way). +bool isErrnoLocationCall(const CallEvent &Call); /// Create a NoteTag that displays the message if the 'errno' memory region is /// marked as interesting, and resets the interestingness. diff --git a/clang/test/AST/Interp/bitfields.cpp b/clang/test/AST/Interp/bitfields.cpp index d3a8a083063a..5fc34bb1229d 100644 --- a/clang/test/AST/Interp/bitfields.cpp +++ b/clang/test/AST/Interp/bitfields.cpp @@ -102,3 +102,24 @@ namespace Compound { } static_assert(div() == 1, ""); } + +namespace test0 { + extern int int_source(); + struct A { + int aField; + int bField; + }; + + struct B { + int onebit : 2; + int twobit : 6; + int intField; + }; + + struct C : A, B { + }; + + void b(C &c) { + c.onebit = int_source(); + } +} diff --git a/clang/test/AST/Interp/c.c b/clang/test/AST/Interp/c.c index 2c675f4418ef..2a75457a4693 100644 --- a/clang/test/AST/Interp/c.c +++ b/clang/test/AST/Interp/c.c @@ -273,3 +273,8 @@ int test3(void) { /// This tests that we have full type info, even for values we cannot read. int dummyarray[5]; _Static_assert(&dummyarray[0] < &dummyarray[1], ""); // pedantic-warning {{GNU extension}} + +void addrlabelexpr(void) { + a0: ; + static void *ps[] = { &&a0 }; // pedantic-warning {{use of GNU address-of-label extension}} +} diff --git a/clang/test/AST/Interp/cxx98.cpp b/clang/test/AST/Interp/cxx98.cpp index ba6bcd97d920..be81735329db 100644 --- a/clang/test/AST/Interp/cxx98.cpp +++ b/clang/test/AST/Interp/cxx98.cpp @@ -45,3 +45,8 @@ struct C0 { }; const int c0_test = C0::Data<int*>; _Static_assert(c0_test == 0, ""); + + +int a = 0; // both-note {{declared here}} +_Static_assert(a == 0, ""); // both-error {{static assertion expression is not an integral constant expression}} \ + // both-note {{read of non-const variable 'a' is not allowed in a constant expression}} diff --git a/clang/test/Analysis/memory-model.cpp b/clang/test/Analysis/memory-model.cpp index fd5a286acb60..cd42e8c72b8b 100644 --- a/clang/test/Analysis/memory-model.cpp +++ b/clang/test/Analysis/memory-model.cpp @@ -34,9 +34,9 @@ void var_simple_ref() { } void var_simple_ptr(int *a) { - clang_analyzer_dump(a); // expected-warning {{SymRegion{reg_$0<int * a>}}} - clang_analyzer_dumpExtent(a); // expected-warning {{extent_$1{SymRegion{reg_$0<int * a>}}}} - clang_analyzer_dumpElementCount(a); // expected-warning {{(extent_$1{SymRegion{reg_$0<int * a>}}) / 4}} + clang_analyzer_dump(a); // expected-warning {{SymRegion{reg_$1<int * a>}}} + clang_analyzer_dumpExtent(a); // expected-warning {{extent_$2{SymRegion{reg_$1<int * a>}}}} + clang_analyzer_dumpElementCount(a); // expected-warning {{(extent_$2{SymRegion{reg_$1<int * a>}}) / 4}} } void var_array() { @@ -53,9 +53,9 @@ void string() { } void struct_simple_ptr(S *a) { - clang_analyzer_dump(a); // expected-warning {{SymRegion{reg_$0<S * a>}}} - clang_analyzer_dumpExtent(a); // expected-warning {{extent_$1{SymRegion{reg_$0<S * a>}}}} - clang_analyzer_dumpElementCount(a); // expected-warning {{(extent_$1{SymRegion{reg_$0<S * a>}}) / 4}} + clang_analyzer_dump(a); // expected-warning {{SymRegion{reg_$1<S * a>}}} + clang_analyzer_dumpExtent(a); // expected-warning {{extent_$2{SymRegion{reg_$1<S * a>}}}} + clang_analyzer_dumpElementCount(a); // expected-warning {{(extent_$2{SymRegion{reg_$1<S * a>}}) / 4}} } void field_ref(S a) { @@ -65,9 +65,9 @@ void field_ref(S a) { } void field_ptr(S *a) { - clang_analyzer_dump(&a->f); // expected-warning {{Element{SymRegion{reg_$0<S * a>},0 S64b,struct S}.f}} - clang_analyzer_dumpExtent(&a->f); // expected-warning {{extent_$1{SymRegion{reg_$0<S * a>}}}} - clang_analyzer_dumpElementCount(&a->f); // expected-warning {{(extent_$1{SymRegion{reg_$0<S * a>}}) / 4U}} + clang_analyzer_dump(&a->f); // expected-warning {{Element{SymRegion{reg_$1<S * a>},0 S64b,struct S}.f}} + clang_analyzer_dumpExtent(&a->f); // expected-warning {{extent_$2{SymRegion{reg_$1<S * a>}}}} + clang_analyzer_dumpElementCount(&a->f); // expected-warning {{(extent_$2{SymRegion{reg_$1<S * a>}}) / 4U}} } void symbolic_array() { diff --git a/clang/test/CodeGen/ext-int-cc.c b/clang/test/CodeGen/ext-int-cc.c index 001e866d34b4..508728172ab4 100644 --- a/clang/test/CodeGen/ext-int-cc.c +++ b/clang/test/CodeGen/ext-int-cc.c @@ -22,9 +22,9 @@ // RUN: %clang_cc1 -no-enable-noundef-analysis -triple systemz -O3 -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s --check-prefixes=SYSTEMZ // RUN: %clang_cc1 -no-enable-noundef-analysis -triple ppc64 -O3 -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s --check-prefixes=PPC64 // RUN: %clang_cc1 -no-enable-noundef-analysis -triple ppc -O3 -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s --check-prefixes=PPC32 -// RUN: %clang_cc1 -no-enable-noundef-analysis -triple aarch64 -O3 -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s --check-prefixes=AARCH64 +// RUN: %clang_cc1 -no-enable-noundef-analysis -triple aarch64 -O3 -disable-llvm-passes -fexperimental-max-bitint-width=1024 -emit-llvm -o - %s | FileCheck %s --check-prefixes=AARCH64 // RUN: %clang_cc1 -no-enable-noundef-analysis -triple aarch64 -target-abi darwinpcs -O3 -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s --check-prefixes=AARCH64DARWIN -// RUN: %clang_cc1 -no-enable-noundef-analysis -triple arm64_32-apple-ios -O3 -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s --check-prefixes=AARCH64 +// RUN: %clang_cc1 -no-enable-noundef-analysis -triple arm64_32-apple-ios -O3 -disable-llvm-passes -fexperimental-max-bitint-width=1024 -emit-llvm -o - %s | FileCheck %s --check-prefixes=AARCH64 // RUN: %clang_cc1 -no-enable-noundef-analysis -triple arm64_32-apple-ios -target-abi darwinpcs -O3 -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s --check-prefixes=AARCH64DARWIN // RUN: %clang_cc1 -no-enable-noundef-analysis -triple arm -O3 -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s --check-prefixes=ARM // RUN: %clang_cc1 -no-enable-noundef-analysis -triple loongarch64 -O3 -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s --check-prefixes=LA64 @@ -135,6 +135,7 @@ void ParamPassing4(_BitInt(129) a) {} // WIN64: define dso_local void @ParamPassing4(ptr %{{.+}}) // LIN32: define{{.*}} void @ParamPassing4(ptr %{{.+}}) // WIN32: define dso_local void @ParamPassing4(ptr %{{.+}}) +// AARCH64: define{{.*}} void @ParamPassing4(ptr %{{.+}}) // NACL-NOT: define{{.*}} void @ParamPassing4(ptr byval(i129) align 8 %{{.+}}) // NVPTX64-NOT: define{{.*}} void @ParamPassing4(ptr byval(i129) align 8 %{{.+}}) // NVPTX-NOT: define{{.*}} void @ParamPassing4(ptr byval(i129) align 8 %{{.+}}) @@ -155,7 +156,6 @@ void ParamPassing4(_BitInt(129) a) {} // SYSTEMZ-NOT: define{{.*}} void @ParamPassing4(ptr %{{.+}}) // PPC64-NOT: define{{.*}} void @ParamPassing4(ptr byval(i129) align 8 %{{.+}}) // PPC32-NOT: define{{.*}} void @ParamPassing4(ptr byval(i129) align 8 %{{.+}}) -// AARCH64-NOT: define{{.*}} void @ParamPassing4(ptr byval(i129) align 8 %{{.+}}) // AARCH64DARWIN-NOT: define{{.*}} void @ParamPassing4(ptr byval(i129) align 8 %{{.+}}) // ARM-NOT: define{{.*}} arm_aapcscc void @ParamPassing4(ptr byval(i129) align 8 %{{.+}}) // LA64-NOT: define{{.*}} void @ParamPassing4(ptr %{{.+}}) @@ -294,6 +294,7 @@ _BitInt(129) ReturnPassing5(void){} // WIN64: define dso_local void @ReturnPassing5(ptr dead_on_unwind noalias writable sret // LIN32: define{{.*}} void @ReturnPassing5(ptr dead_on_unwind noalias writable sret // WIN32: define dso_local void @ReturnPassing5(ptr dead_on_unwind noalias writable sret +// AARCH64: define{{.*}} void @ReturnPassing5(ptr dead_on_unwind noalias writable sret // NACL-NOT: define{{.*}} void @ReturnPassing5(ptr dead_on_unwind noalias writable sret // NVPTX64-NOT: define{{.*}} i129 @ReturnPassing5( // NVPTX-NOT: define{{.*}} i129 @ReturnPassing5( @@ -314,7 +315,6 @@ _BitInt(129) ReturnPassing5(void){} // SYSTEMZ-NOT: define{{.*}} void @ReturnPassing5(ptr dead_on_unwind noalias writable sret // PPC64-NOT: define{{.*}} void @ReturnPassing5(ptr dead_on_unwind noalias writable sret // PPC32-NOT: define{{.*}} void @ReturnPassing5(ptr dead_on_unwind noalias writable sret -// AARCH64-NOT: define{{.*}} void @ReturnPassing5(ptr dead_on_unwind noalias writable sret // AARCH64DARWIN-NOT: define{{.*}} void @ReturnPassing5(ptr dead_on_unwind noalias writable sret // ARM-NOT: define{{.*}} arm_aapcscc void @ReturnPassing5(ptr dead_on_unwind noalias writable sret // LA64-NOT: define{{.*}} void @ReturnPassing5(ptr dead_on_unwind noalias writable sret diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp index f723e8f66e3e..ed1101dc5e8d 100644 --- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp +++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp @@ -33,7 +33,11 @@ static bool isDummyArgument(mlir::Value v) { if (!blockArg) return false; - return blockArg.getOwner()->isEntryBlock(); + mlir::Block *owner = blockArg.getOwner(); + if (!owner->isEntryBlock() || + !mlir::isa<mlir::FunctionOpInterface>(owner->getParentOp())) + return false; + return true; } /// Temporary function to skip through all the no op operations diff --git a/flang/lib/Optimizer/Transforms/AddAliasTags.cpp b/flang/lib/Optimizer/Transforms/AddAliasTags.cpp index 684aa4462915..3642a812096d 100644 --- a/flang/lib/Optimizer/Transforms/AddAliasTags.cpp +++ b/flang/lib/Optimizer/Transforms/AddAliasTags.cpp @@ -105,6 +105,7 @@ static std::string getFuncArgName(mlir::Value arg) { "arg is a function argument"); mlir::FunctionOpInterface func = mlir::dyn_cast<mlir::FunctionOpInterface>( blockArg.getOwner()->getParentOp()); + assert(func && "This is not a function argument"); mlir::StringAttr attr = func.getArgAttrOfType<mlir::StringAttr>( blockArg.getArgNumber(), "fir.bindc_name"); if (!attr) diff --git a/flang/test/Transforms/tbaa.fir b/flang/test/Transforms/tbaa.fir index 7825ae60c71e..f94bbe4bf948 100644 --- a/flang/test/Transforms/tbaa.fir +++ b/flang/test/Transforms/tbaa.fir @@ -173,3 +173,40 @@ // CHECK: fir.store %[[VAL_8]] to %[[VAL_12]] : !fir.ref<i32> // CHECK: return // CHECK: } + +// ----- + +// Make sure we don't mistake other block arguments as dummy arguments: + +omp.declare_reduction @add_reduction_i32 : i32 init { +^bb0(%arg0: i32): + %c0_i32 = arith.constant 0 : i32 + omp.yield(%c0_i32 : i32) +} combiner { +^bb0(%arg0: i32, %arg1: i32): + %0 = arith.addi %arg0, %arg1 : i32 + omp.yield(%0 : i32) +} + +func.func @_QQmain() attributes {fir.bindc_name = "reduce"} { + %c10_i32 = arith.constant 10 : i32 + %c6_i32 = arith.constant 6 : i32 + %c-1_i32 = arith.constant -1 : i32 + %0 = fir.address_of(@_QFEi) : !fir.ref<i32> + %1 = fir.declare %0 {uniq_name = "_QFEi"} : (!fir.ref<i32>) -> !fir.ref<i32> + omp.parallel reduction(@add_reduction_i32 %1 -> %arg0 : !fir.ref<i32>) { +// CHECK: omp.parallel reduction({{.*}}) { + %8 = fir.declare %arg0 {uniq_name = "_QFEi"} : (!fir.ref<i32>) -> !fir.ref<i32> +// CHECK-NEXT: %[[DECL:.*]] = fir.declare + fir.store %c-1_i32 to %8 : !fir.ref<i32> +// CHECK-NOT: fir.store %{{.*}} to %[[DECL]] {tbaa = %{{.*}}} : !fir.ref<i32> +// CHECK: fir.store %{{.*}} to %[[DECL]] : !fir.ref<i32> + omp.terminator + } + return +} + +fir.global internal @_QFEi : i32 { + %c0_i32 = arith.constant 0 : i32 + fir.has_value %c0_i32 : i32 +} diff --git a/lldb/source/Target/UnwindLLDB.cpp b/lldb/source/Target/UnwindLLDB.cpp index 1d8bf2f88ae6..f43e940492b0 100644 --- a/lldb/source/Target/UnwindLLDB.cpp +++ b/lldb/source/Target/UnwindLLDB.cpp @@ -261,7 +261,12 @@ UnwindLLDB::CursorSP UnwindLLDB::GetOneMoreFrame(ABI *abi) { cur_idx < 100 ? cur_idx : 100, "", cur_idx); return nullptr; } - if (abi && !abi->CodeAddressIsValid(cursor_sp->start_pc)) { + + // Invalid code addresses should not appear on the stack *unless* we're + // directly below a trap handler frame (in this case, the invalid address is + // likely the cause of the trap). + if (abi && !abi->CodeAddressIsValid(cursor_sp->start_pc) && + !prev_frame->reg_ctx_lldb_sp->IsTrapHandlerFrame()) { // If the RegisterContextUnwind has a fallback UnwindPlan, it will switch to // that and return true. Subsequent calls to TryFallbackUnwindPlan() will // return false. diff --git a/lldb/test/Shell/Unwind/Inputs/unaligned-pc-sigbus.c b/lldb/test/Shell/Unwind/Inputs/unaligned-pc-sigbus.c new file mode 100644 index 000000000000..b4818de3b7fb --- /dev/null +++ b/lldb/test/Shell/Unwind/Inputs/unaligned-pc-sigbus.c @@ -0,0 +1,21 @@ +#include <signal.h> +#include <stdint.h> +#include <unistd.h> + +void sigbus_handler(int signo) { _exit(47); } + +int target_function() { return 47; } + +int main() { + signal(SIGBUS, sigbus_handler); + + // Generate a SIGBUS by deliverately calling through an unaligned function + // pointer. + union { + int (*t)(); + uintptr_t p; + } u; + u.t = target_function; + u.p |= 1; + return u.t(); +} diff --git a/lldb/test/Shell/Unwind/unaligned-pc-sigbus.test b/lldb/test/Shell/Unwind/unaligned-pc-sigbus.test new file mode 100644 index 000000000000..49f771cae95b --- /dev/null +++ b/lldb/test/Shell/Unwind/unaligned-pc-sigbus.test @@ -0,0 +1,31 @@ +# REQUIRES: target-aarch64 && native +# UNSUPPORTED: system-windows +# llvm.org/pr91610, rdar://128031075 +# XFAIL: system-darwin + +# RUN: %clang_host %S/Inputs/unaligned-pc-sigbus.c -o %t +# RUN: %lldb -s %s -o exit %t | FileCheck %s + +# Convert EXC_BAD_ACCESS into SIGBUS on darwin. +settings set platform.plugin.darwin.ignored-exceptions EXC_BAD_ACCESS + +breakpoint set -n sigbus_handler +# CHECK: Breakpoint 1: where = {{.*}}`sigbus_handler + +run +# CHECK: thread #1, {{.*}} stop reason = signal SIGBUS + +thread backtrace +# CHECK: (lldb) thread backtrace +# CHECK: frame #0: [[TARGET:0x[0-9a-fA-F]*]] {{.*}}`target_function + +continue +# CHECK: thread #1, {{.*}} stop reason = breakpoint 1 + + +thread backtrace +# CHECK: (lldb) thread backtrace +# CHECK: frame #0: {{.*}}`sigbus_handler +# Unknown number of signal trampoline frames +# CHECK: frame #{{[0-9]+}}: [[TARGET]] {{.*}}`target_function + diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp index ee39c6355c29..3ce766fc173c 100644 --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -1161,52 +1161,45 @@ void AArch64AsmPrinter::emitFunctionEntryLabel() { TS->emitDirectiveVariantPCS(CurrentFnSym); } + AsmPrinter::emitFunctionEntryLabel(); + if (TM.getTargetTriple().isWindowsArm64EC() && !MF->getFunction().hasLocalLinkage()) { // For ARM64EC targets, a function definition's name is mangled differently - // from the normal symbol. We emit the alias from the unmangled symbol to - // mangled symbol name here. - if (MDNode *Unmangled = - MF->getFunction().getMetadata("arm64ec_unmangled_name")) { - AsmPrinter::emitFunctionEntryLabel(); - - if (MDNode *ECMangled = - MF->getFunction().getMetadata("arm64ec_ecmangled_name")) { - StringRef UnmangledStr = - cast<MDString>(Unmangled->getOperand(0))->getString(); - MCSymbol *UnmangledSym = - MMI->getContext().getOrCreateSymbol(UnmangledStr); - StringRef ECMangledStr = - cast<MDString>(ECMangled->getOperand(0))->getString(); - MCSymbol *ECMangledSym = - MMI->getContext().getOrCreateSymbol(ECMangledStr); - OutStreamer->emitSymbolAttribute(UnmangledSym, MCSA_WeakAntiDep); - OutStreamer->emitAssignment( - UnmangledSym, - MCSymbolRefExpr::create(ECMangledSym, MCSymbolRefExpr::VK_WEAKREF, - MMI->getContext())); - OutStreamer->emitSymbolAttribute(ECMangledSym, MCSA_WeakAntiDep); - OutStreamer->emitAssignment( - ECMangledSym, - MCSymbolRefExpr::create(CurrentFnSym, MCSymbolRefExpr::VK_WEAKREF, - MMI->getContext())); - return; + // from the normal symbol, emit required aliases here. + auto emitFunctionAlias = [&](MCSymbol *Src, MCSymbol *Dst) { + OutStreamer->emitSymbolAttribute(Src, MCSA_WeakAntiDep); + OutStreamer->emitAssignment( + Src, MCSymbolRefExpr::create(Dst, MCSymbolRefExpr::VK_WEAKREF, + MMI->getContext())); + }; + + auto getSymbolFromMetadata = [&](StringRef Name) { + MCSymbol *Sym = nullptr; + if (MDNode *Node = MF->getFunction().getMetadata(Name)) { + StringRef NameStr = cast<MDString>(Node->getOperand(0))->getString(); + Sym = MMI->getContext().getOrCreateSymbol(NameStr); + } + return Sym; + }; + + if (MCSymbol *UnmangledSym = + getSymbolFromMetadata("arm64ec_unmangled_name")) { + MCSymbol *ECMangledSym = getSymbolFromMetadata("arm64ec_ecmangled_name"); + + if (ECMangledSym) { + // An external function, emit the alias from the unmangled symbol to + // mangled symbol name and the alias from the mangled symbol to guest + // exit thunk. + emitFunctionAlias(UnmangledSym, ECMangledSym); + emitFunctionAlias(ECMangledSym, CurrentFnSym); } else { - StringRef UnmangledStr = - cast<MDString>(Unmangled->getOperand(0))->getString(); - MCSymbol *UnmangledSym = - MMI->getContext().getOrCreateSymbol(UnmangledStr); - OutStreamer->emitSymbolAttribute(UnmangledSym, MCSA_WeakAntiDep); - OutStreamer->emitAssignment( - UnmangledSym, - MCSymbolRefExpr::create(CurrentFnSym, MCSymbolRefExpr::VK_WEAKREF, - MMI->getContext())); - return; + // A function implementation, emit the alias from the unmangled symbol + // to mangled symbol name. + emitFunctionAlias(UnmangledSym, CurrentFnSym); } } } - - return AsmPrinter::emitFunctionEntryLabel(); } /// Small jump tables contain an unsigned byte or half, representing the offset diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp index fa634e774b5c..5eb99ffd1e10 100644 --- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp +++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp @@ -1506,24 +1506,25 @@ void VPBlendRecipe::execute(VPTransformState &State) { // Note that Mask0 is never used: lanes for which no path reaches this phi and // are essentially undef are taken from In0. VectorParts Entry(State.UF); - for (unsigned In = 0; In < NumIncoming; ++In) { - for (unsigned Part = 0; Part < State.UF; ++Part) { - // We might have single edge PHIs (blocks) - use an identity - // 'select' for the first PHI operand. - Value *In0 = State.get(getIncomingValue(In), Part); - if (In == 0) - Entry[Part] = In0; // Initialize with the first incoming value. - else { - // Select between the current value and the previous incoming edge - // based on the incoming mask. - Value *Cond = State.get(getMask(In), Part); - Entry[Part] = - State.Builder.CreateSelect(Cond, In0, Entry[Part], "predphi"); - } - } - } + bool OnlyFirstLaneUsed = vputils::onlyFirstLaneUsed(this); + for (unsigned In = 0; In < NumIncoming; ++In) { + for (unsigned Part = 0; Part < State.UF; ++Part) { + // We might have single edge PHIs (blocks) - use an identity + // 'select' for the first PHI operand. + Value *In0 = State.get(getIncomingValue(In), Part, OnlyFirstLaneUsed); + if (In == 0) + Entry[Part] = In0; // Initialize with the first incoming value. + else { + // Select between the current value and the previous incoming edge + // based on the incoming mask. + Value *Cond = State.get(getMask(In), Part, OnlyFirstLaneUsed); + Entry[Part] = + State.Builder.CreateSelect(Cond, In0, Entry[Part], "predphi"); + } + } + } for (unsigned Part = 0; Part < State.UF; ++Part) - State.set(this, Entry[Part], Part); + State.set(this, Entry[Part], Part, OnlyFirstLaneUsed); } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) diff --git a/llvm/test/Transforms/LoopVectorize/RISCV/pr87378-vpinstruction-or-drop-poison-generating-flags.ll b/llvm/test/Transforms/LoopVectorize/RISCV/pr87378-vpinstruction-or-drop-poison-generating-flags.ll index 4e38630209b2..5f8141600371 100644 --- a/llvm/test/Transforms/LoopVectorize/RISCV/pr87378-vpinstruction-or-drop-poison-generating-flags.ll +++ b/llvm/test/Transforms/LoopVectorize/RISCV/pr87378-vpinstruction-or-drop-poison-generating-flags.ll @@ -40,8 +40,6 @@ define void @pr87378_vpinstruction_or_drop_poison_generating_flags(ptr %arg, i64 ; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, [[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], [[VECTOR_BODY]] ] ; CHECK-NEXT: [[VEC_IND:%.*]] = phi <vscale x 8 x i64> [ [[INDUCTION]], [[VECTOR_PH]] ], [ [[VEC_IND_NEXT:%.*]], [[VECTOR_BODY]] ] ; CHECK-NEXT: [[TMP12:%.*]] = add i64 [[INDEX]], 0 -; CHECK-NEXT: [[BROADCAST_SPLATINSERT5:%.*]] = insertelement <vscale x 8 x i64> poison, i64 [[TMP12]], i64 0 -; CHECK-NEXT: [[BROADCAST_SPLAT6:%.*]] = shufflevector <vscale x 8 x i64> [[BROADCAST_SPLATINSERT5]], <vscale x 8 x i64> poison, <vscale x 8 x i32> zeroinitializer ; CHECK-NEXT: [[TMP13:%.*]] = icmp ule <vscale x 8 x i64> [[VEC_IND]], [[BROADCAST_SPLAT]] ; CHECK-NEXT: [[TMP14:%.*]] = icmp ule <vscale x 8 x i64> [[VEC_IND]], [[BROADCAST_SPLAT2]] ; CHECK-NEXT: [[TMP15:%.*]] = select <vscale x 8 x i1> [[TMP13]], <vscale x 8 x i1> [[TMP14]], <vscale x 8 x i1> zeroinitializer @@ -52,9 +50,9 @@ define void @pr87378_vpinstruction_or_drop_poison_generating_flags(ptr %arg, i64 ; CHECK-NEXT: [[TMP20:%.*]] = xor <vscale x 8 x i1> [[TMP14]], shufflevector (<vscale x 8 x i1> insertelement (<vscale x 8 x i1> poison, i1 true, i64 0), <vscale x 8 x i1> poison, <vscale x 8 x i32> zeroinitializer) ; CHECK-NEXT: [[TMP21:%.*]] = select <vscale x 8 x i1> [[TMP13]], <vscale x 8 x i1> [[TMP20]], <vscale x 8 x i1> zeroinitializer ; CHECK-NEXT: [[TMP22:%.*]] = or <vscale x 8 x i1> [[TMP19]], [[TMP21]] -; CHECK-NEXT: [[PREDPHI:%.*]] = select <vscale x 8 x i1> [[TMP19]], <vscale x 8 x i64> [[BROADCAST_SPLAT6]], <vscale x 8 x i64> shufflevector (<vscale x 8 x i64> insertelement (<vscale x 8 x i64> poison, i64 poison, i64 0), <vscale x 8 x i64> poison, <vscale x 8 x i32> zeroinitializer) -; CHECK-NEXT: [[TMP23:%.*]] = extractelement <vscale x 8 x i64> [[PREDPHI]], i32 0 -; CHECK-NEXT: [[TMP24:%.*]] = getelementptr i16, ptr [[ARG]], i64 [[TMP23]] +; CHECK-NEXT: [[EXT:%.+]] = extractelement <vscale x 8 x i1> [[TMP19]], i32 0 +; CHECK-NEXT: [[PREDPHI:%.*]] = select i1 [[EXT]], i64 [[TMP12]], i64 poison +; CHECK-NEXT: [[TMP24:%.*]] = getelementptr i16, ptr [[ARG]], i64 [[PREDPHI]] ; CHECK-NEXT: [[TMP25:%.*]] = getelementptr i16, ptr [[TMP24]], i32 0 ; CHECK-NEXT: call void @llvm.masked.store.nxv8i16.p0(<vscale x 8 x i16> zeroinitializer, ptr [[TMP25]], i32 2, <vscale x 8 x i1> [[TMP22]]) ; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], [[TMP5]] diff --git a/llvm/test/Transforms/LoopVectorize/uniform-blend.ll b/llvm/test/Transforms/LoopVectorize/uniform-blend.ll index 71eed3b2985d..19cbcac6090c 100644 --- a/llvm/test/Transforms/LoopVectorize/uniform-blend.ll +++ b/llvm/test/Transforms/LoopVectorize/uniform-blend.ll @@ -4,19 +4,12 @@ define void @blend_uniform_iv_trunc(i1 %c) { ; CHECK-LABEL: @blend_uniform_iv_trunc( -; CHECK: vector.ph: -; CHECK-NEXT: [[MASK0:%.*]] = insertelement <4 x i1> poison, i1 %c, i64 0 -; CHECK-NEXT: [[MASK1:%.*]] = shufflevector <4 x i1> [[MASK0]], <4 x i1> poison, <4 x i32> zeroinitializer - ; CHECK: vector.body: ; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, %vector.ph ], [ [[INDEX_NEXT:%.*]], %vector.body ] ; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[INDEX]] to i16 ; CHECK-NEXT: [[TMP2:%.*]] = add i16 [[TMP1]], 0 -; CHECK-NEXT: [[BROADCAST_SPLATINSERT1:%.*]] = insertelement <4 x i16> poison, i16 [[TMP2]], i64 0 -; CHECK-NEXT: [[BROADCAST_SPLAT2:%.*]] = shufflevector <4 x i16> [[BROADCAST_SPLATINSERT1]], <4 x i16> poison, <4 x i32> zeroinitializer -; CHECK-NEXT: [[PREDPHI:%.*]] = select <4 x i1> [[MASK1]], <4 x i16> [[BROADCAST_SPLAT2]], <4 x i16> undef -; CHECK-NEXT: [[TMP4:%.*]] = extractelement <4 x i16> [[PREDPHI]], i32 0 -; CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds [32 x i16], ptr @dst, i16 0, i16 [[TMP4]] +; CHECK-NEXT: [[PREDPHI:%.*]] = select i1 %c, i16 [[TMP2]], i16 undef +; CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds [32 x i16], ptr @dst, i16 0, i16 [[PREDPHI]] ; CHECK-NEXT: [[TMP6:%.*]] = getelementptr inbounds i16, ptr [[TMP5]], i32 0 ; CHECK-NEXT: store <4 x i16> zeroinitializer, ptr [[TMP6]], align 2 ; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 4 @@ -49,17 +42,12 @@ exit: ; preds = %loop.latch define void @blend_uniform_iv(i1 %c) { ; CHECK-LABEL: @blend_uniform_iv( ; CHECK: vector.ph: -; CHECK-NEXT: [[MASK0:%.*]] = insertelement <4 x i1> poison, i1 %c, i64 0 -; CHECK-NEXT: [[MASK1:%.*]] = shufflevector <4 x i1> [[MASK0]], <4 x i1> poison, <4 x i32> zeroinitializer ; CHECK: vector.body: ; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, %vector.ph ], [ [[INDEX_NEXT:%.*]], %vector.body ] ; CHECK-NEXT: [[TMP0:%.*]] = add i64 [[INDEX]], 0 -; CHECK-NEXT: [[BROADCAST_SPLATINSERT1:%.*]] = insertelement <4 x i64> poison, i64 [[TMP0]], i64 0 -; CHECK-NEXT: [[BROADCAST_SPLAT2:%.*]] = shufflevector <4 x i64> [[BROADCAST_SPLATINSERT1]], <4 x i64> poison, <4 x i32> zeroinitializer -; CHECK-NEXT: [[PREDPHI:%.*]] = select <4 x i1> [[MASK1]], <4 x i64> [[BROADCAST_SPLAT2]], <4 x i64> undef -; CHECK-NEXT: [[TMP2:%.*]] = extractelement <4 x i64> [[PREDPHI]], i32 0 -; CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds [32 x i16], ptr @dst, i16 0, i64 [[TMP2]] +; CHECK-NEXT: [[PREDPHI:%.*]] = select i1 %c, i64 [[TMP0]], i64 undef +; CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds [32 x i16], ptr @dst, i16 0, i64 [[PREDPHI]] ; CHECK-NEXT: [[TMP4:%.*]] = getelementptr inbounds i16, ptr [[TMP3]], i32 0 ; CHECK-NEXT: store <4 x i16> zeroinitializer, ptr [[TMP4]], align 2 ; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 4 diff --git a/llvm/test/Transforms/LoopVectorize/unused-blend-mask-for-first-operand.ll b/llvm/test/Transforms/LoopVectorize/unused-blend-mask-for-first-operand.ll index d0c74897f264..0f7bd3d71feb 100644 --- a/llvm/test/Transforms/LoopVectorize/unused-blend-mask-for-first-operand.ll +++ b/llvm/test/Transforms/LoopVectorize/unused-blend-mask-for-first-operand.ll @@ -16,7 +16,7 @@ define void @test_not_first_lane_only_constant(ptr %A, ptr noalias %B) { ; CHECK-NEXT: [[OFFSET_IDX:%.*]] = trunc i32 [[INDEX]] to i16 ; CHECK-NEXT: [[TMP0:%.*]] = add i16 [[OFFSET_IDX]], 0 ; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i16, ptr [[A]], i16 [[TMP0]] -; CHECK-NEXT: [[TMP13:%.*]] = load i16, ptr %B, align 2 +; CHECK-NEXT: [[TMP13:%.*]] = load i16, ptr [[B]], align 2 ; CHECK-NEXT: [[BROADCAST_SPLATINSERT5:%.*]] = insertelement <4 x i16> poison, i16 [[TMP13]], i64 0 ; CHECK-NEXT: [[BROADCAST_SPLAT6:%.*]] = shufflevector <4 x i16> [[BROADCAST_SPLATINSERT5]], <4 x i16> poison, <4 x i32> zeroinitializer ; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds i16, ptr [[TMP1]], i32 0 @@ -86,8 +86,6 @@ define void @test_not_first_lane_only_wide_compare(ptr %A, ptr noalias %B, i16 % ; CHECK: vector.ph: ; CHECK-NEXT: [[BROADCAST_SPLATINSERT:%.*]] = insertelement <4 x i16> poison, i16 [[X]], i64 0 ; CHECK-NEXT: [[BROADCAST_SPLAT2:%.*]] = shufflevector <4 x i16> [[BROADCAST_SPLATINSERT]], <4 x i16> poison, <4 x i32> zeroinitializer -; CHECK-NEXT: [[BROADCAST_SPLATINSERT3:%.*]] = insertelement <4 x ptr> poison, ptr [[B]], i64 0 -; CHECK-NEXT: [[BROADCAST_SPLAT4:%.*]] = shufflevector <4 x ptr> [[BROADCAST_SPLATINSERT3]], <4 x ptr> poison, <4 x i32> zeroinitializer ; CHECK-NEXT: br label [[VECTOR_BODY:%.*]] ; CHECK: vector.body: ; CHECK-NEXT: [[INDEX:%.*]] = phi i32 [ 0, [[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], [[VECTOR_BODY]] ] @@ -97,8 +95,8 @@ define void @test_not_first_lane_only_wide_compare(ptr %A, ptr noalias %B, i16 % ; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds i16, ptr [[TMP1]], i32 0 ; CHECK-NEXT: [[WIDE_LOAD:%.*]] = load <4 x i16>, ptr [[TMP2]], align 2 ; CHECK-NEXT: [[TMP5:%.*]] = icmp ult <4 x i16> [[WIDE_LOAD]], [[BROADCAST_SPLAT2]] -; CHECK-NEXT: [[PREDPHI:%.*]] = select <4 x i1> [[TMP5]], <4 x ptr> poison, <4 x ptr> [[BROADCAST_SPLAT4]] -; CHECK-NEXT: [[TMP12:%.*]] = extractelement <4 x ptr> [[PREDPHI]], i32 0 +; CHECK-NEXT: [[TMP4:%.*]] = extractelement <4 x i1> [[TMP5]], i32 0 +; CHECK-NEXT: [[TMP12:%.*]] = select i1 [[TMP4]], ptr poison, ptr [[B]] ; CHECK-NEXT: [[TMP13:%.*]] = load i16, ptr [[TMP12]], align 2 ; CHECK-NEXT: [[BROADCAST_SPLATINSERT5:%.*]] = insertelement <4 x i16> poison, i16 [[TMP13]], i64 0 ; CHECK-NEXT: [[BROADCAST_SPLAT6:%.*]] = shufflevector <4 x i16> [[BROADCAST_SPLATINSERT5]], <4 x i16> poison, <4 x i32> zeroinitializer @@ -165,6 +163,101 @@ loop.latch: exit: ret void } + +define void @test_not_first_lane_only_wide_compare_incoming_order_swapped(ptr %A, ptr noalias %B, i16 %x, i16 %y) { +; CHECK-LABEL: define void @test_not_first_lane_only_wide_compare_incoming_order_swapped( +; CHECK-SAME: ptr [[A:%.*]], ptr noalias [[B:%.*]], i16 [[X:%.*]], i16 [[Y:%.*]]) { +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 false, label [[SCALAR_PH:%.*]], label [[VECTOR_PH:%.*]] +; CHECK: vector.ph: +; CHECK-NEXT: [[BROADCAST_SPLATINSERT:%.*]] = insertelement <4 x i16> poison, i16 [[X]], i64 0 +; CHECK-NEXT: [[BROADCAST_SPLAT:%.*]] = shufflevector <4 x i16> [[BROADCAST_SPLATINSERT]], <4 x i16> poison, <4 x i32> zeroinitializer +; CHECK-NEXT: [[BROADCAST_SPLATINSERT1:%.*]] = insertelement <4 x i16> poison, i16 [[Y]], i64 0 +; CHECK-NEXT: [[BROADCAST_SPLAT2:%.*]] = shufflevector <4 x i16> [[BROADCAST_SPLATINSERT1]], <4 x i16> poison, <4 x i32> zeroinitializer +; CHECK-NEXT: br label [[VECTOR_BODY:%.*]] +; CHECK: vector.body: +; CHECK-NEXT: [[INDEX:%.*]] = phi i32 [ 0, [[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], [[VECTOR_BODY]] ] +; CHECK-NEXT: [[OFFSET_IDX:%.*]] = trunc i32 [[INDEX]] to i16 +; CHECK-NEXT: [[TMP0:%.*]] = add i16 [[OFFSET_IDX]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i16, ptr [[A]], i16 [[TMP0]] +; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds i16, ptr [[TMP1]], i32 0 +; CHECK-NEXT: [[WIDE_LOAD:%.*]] = load <4 x i16>, ptr [[TMP2]], align 2 +; CHECK-NEXT: [[TMP3:%.*]] = icmp ult <4 x i16> [[WIDE_LOAD]], [[BROADCAST_SPLAT]] +; CHECK-NEXT: [[TMP4:%.*]] = xor <4 x i1> [[TMP3]], <i1 true, i1 true, i1 true, i1 true> +; CHECK-NEXT: [[TMP5:%.*]] = icmp ult <4 x i16> [[WIDE_LOAD]], [[BROADCAST_SPLAT2]] +; CHECK-NEXT: [[TMP6:%.*]] = select <4 x i1> [[TMP4]], <4 x i1> [[TMP5]], <4 x i1> zeroinitializer +; CHECK-NEXT: [[TMP7:%.*]] = xor <4 x i1> [[TMP5]], <i1 true, i1 true, i1 true, i1 true> +; CHECK-NEXT: [[TMP8:%.*]] = select <4 x i1> [[TMP4]], <4 x i1> [[TMP7]], <4 x i1> zeroinitializer +; CHECK-NEXT: [[TMP9:%.*]] = extractelement <4 x i1> [[TMP6]], i32 0 +; CHECK-NEXT: [[TMP10:%.*]] = extractelement <4 x i1> [[TMP8]], i32 0 +; CHECK-NEXT: [[TMP11:%.*]] = or i1 [[TMP9]], [[TMP10]] +; CHECK-NEXT: [[PREDPHI:%.*]] = select i1 [[TMP11]], ptr [[B]], ptr poison +; CHECK-NEXT: [[TMP12:%.*]] = load i16, ptr [[PREDPHI]], align 2 +; CHECK-NEXT: [[BROADCAST_SPLATINSERT3:%.*]] = insertelement <4 x i16> poison, i16 [[TMP12]], i64 0 +; CHECK-NEXT: [[BROADCAST_SPLAT4:%.*]] = shufflevector <4 x i16> [[BROADCAST_SPLATINSERT3]], <4 x i16> poison, <4 x i32> zeroinitializer +; CHECK-NEXT: store <4 x i16> [[BROADCAST_SPLAT4]], ptr [[TMP2]], align 2 +; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i32 [[INDEX]], 4 +; CHECK-NEXT: [[TMP13:%.*]] = icmp eq i32 [[INDEX_NEXT]], 1000 +; CHECK-NEXT: br i1 [[TMP13]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], !llvm.loop [[LOOP6:![0-9]+]] +; CHECK: middle.block: +; CHECK-NEXT: br i1 true, label [[EXIT:%.*]], label [[SCALAR_PH]] +; CHECK: scalar.ph: +; CHECK-NEXT: [[BC_RESUME_VAL:%.*]] = phi i16 [ 1000, [[MIDDLE_BLOCK]] ], [ 0, [[ENTRY:%.*]] ] +; CHECK-NEXT: br label [[LOOP_HEADER:%.*]] +; CHECK: loop.header: +; CHECK-NEXT: [[IV:%.*]] = phi i16 [ [[BC_RESUME_VAL]], [[SCALAR_PH]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ] +; CHECK-NEXT: [[GEP_A:%.*]] = getelementptr inbounds i16, ptr [[A]], i16 [[IV]] +; CHECK-NEXT: [[L_0:%.*]] = load i16, ptr [[GEP_A]], align 2 +; CHECK-NEXT: [[C_0:%.*]] = icmp ult i16 [[L_0]], [[X]] +; CHECK-NEXT: br i1 [[C_0]], label [[LOOP_LATCH]], label [[ELSE_1:%.*]] +; CHECK: else.1: +; CHECK-NEXT: [[C_1:%.*]] = icmp ult i16 [[L_0]], [[Y]] +; CHECK-NEXT: br i1 [[C_1]], label [[THEN_2:%.*]], label [[ELSE_2:%.*]] +; CHECK: then.2: +; CHECK-NEXT: br label [[ELSE_2]] +; CHECK: else.2: +; CHECK-NEXT: br label [[LOOP_LATCH]] +; CHECK: loop.latch: +; CHECK-NEXT: [[MERGE:%.*]] = phi ptr [ poison, [[LOOP_HEADER]] ], [ [[B]], [[ELSE_2]] ] +; CHECK-NEXT: [[L:%.*]] = load i16, ptr [[MERGE]], align 2 +; CHECK-NEXT: [[IV_NEXT]] = add i16 [[IV]], 1 +; CHECK-NEXT: store i16 [[L]], ptr [[GEP_A]], align 2 +; CHECK-NEXT: [[C_2:%.*]] = icmp eq i16 [[IV_NEXT]], 1000 +; CHECK-NEXT: br i1 [[C_2]], label [[EXIT]], label [[LOOP_HEADER]], !llvm.loop [[LOOP7:![0-9]+]] +; CHECK: exit: +; CHECK-NEXT: ret void +; +entry: + br label %loop.header + +loop.header: + %iv = phi i16 [ 0, %entry ], [ %iv.next, %loop.latch ] + %gep.A = getelementptr inbounds i16, ptr %A, i16 %iv + %l.0 = load i16, ptr %gep.A + %c.0 = icmp ult i16 %l.0, %x + br i1 %c.0, label %loop.latch, label %else.1 + +else.1: + %c.1 = icmp ult i16 %l.0, %y + br i1 %c.1, label %then.2, label %else.2 + +then.2: + br label %else.2 + +else.2: + br label %loop.latch + +loop.latch: + %merge = phi ptr [ poison, %loop.header ], [ %B, %else.2 ] + %l = load i16, ptr %merge, align 2 + %iv.next = add i16 %iv, 1 + store i16 %l, ptr %gep.A + %c.2 = icmp eq i16 %iv.next, 1000 + br i1 %c.2, label %exit, label %loop.header + +exit: + ret void +} ;. ; CHECK: [[LOOP0]] = distinct !{[[LOOP0]], [[META1:![0-9]+]], [[META2:![0-9]+]]} ; CHECK: [[META1]] = !{!"llvm.loop.isvectorized", i32 1} @@ -172,4 +265,6 @@ exit: ; CHECK: [[LOOP3]] = distinct !{[[LOOP3]], [[META2]], [[META1]]} ; CHECK: [[LOOP4]] = distinct !{[[LOOP4]], [[META1]], [[META2]]} ; CHECK: [[LOOP5]] = distinct !{[[LOOP5]], [[META2]], [[META1]]} +; CHECK: [[LOOP6]] = distinct !{[[LOOP6]], [[META1]], [[META2]]} +; CHECK: [[LOOP7]] = distinct !{[[LOOP7]], [[META2]], [[META1]]} ;. |