diff --git a/clang/cmake/caches/release_cpack_pre_build_strip_lto.cmake b/clang/cmake/caches/release_cpack_pre_build_strip_lto.cmake index 743b64fe00f58..e7d8830515439 100644 --- a/clang/cmake/caches/release_cpack_pre_build_strip_lto.cmake +++ b/clang/cmake/caches/release_cpack_pre_build_strip_lto.cmake @@ -1,5 +1,14 @@ file(GLOB files ${CPACK_TEMPORARY_INSTALL_DIRECTORY}/lib/*.a) +if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + set(strip_command + ${CPACK_TEMPORARY_INSTALL_DIRECTORY}/bin/llvm-bitcode-strip) + set(strip_args -r) +else() + set(strip_command ${CPACK_TEMPORARY_INSTALL_DIRECTORY}/bin/llvm-strip) + set(strip_args --no-strip-all -R .llvm.lto) +endif() + foreach(file ${files}) - execute_process(COMMAND ${CPACK_TEMPORARY_INSTALL_DIRECTORY}/bin/llvm-strip --no-strip-all -R .llvm.lto ${file}) + execute_process(COMMAND ${strip_command} ${strip_args} ${file} -o ${file}) endforeach() diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index fdaad31233b29..9ffecaca04a18 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -381,6 +381,10 @@ class HashParameterMapping : public RecursiveASTVisitor { return true; } + bool TraverseCXXThisExpr(CXXThisExpr *E) { + return inherited::TraverseType(E->getType()); + } + bool TraverseTypeLoc(TypeLoc TL, bool TraverseQualifier = true) { // We don't care about TypeLocs. So traverse Types instead. return TraverseType(TL.getType().getCanonicalType(), TraverseQualifier); @@ -394,6 +398,16 @@ class HashParameterMapping : public RecursiveASTVisitor { return true; } + bool TraverseUnresolvedUsingType(UnresolvedUsingType *T, + bool TraverseQualifier) { + // Sometimes the written type doesn't contain a qualifier which contains + // necessary template arguments, whereas the declaration does. + if (NestedNameSpecifier NNS = T->getDecl()->getQualifier(); + TraverseQualifier && NNS) + return inherited::TraverseNestedNameSpecifier(NNS); + return inherited::TraverseUnresolvedUsingType(T, TraverseQualifier); + } + bool TraverseInjectedClassNameType(InjectedClassNameType *T, bool TraverseQualifier) { return TraverseTemplateArguments(T->getTemplateArgs(SemaRef.Context)); diff --git a/clang/test/SemaTemplate/concepts-using-decl.cpp b/clang/test/SemaTemplate/concepts-using-decl.cpp index 41f7b6d2f8faa..5ccec3cee9402 100644 --- a/clang/test/SemaTemplate/concepts-using-decl.cpp +++ b/clang/test/SemaTemplate/concepts-using-decl.cpp @@ -197,3 +197,101 @@ struct child : base { }; } + +namespace GH198663 { + +template +concept HasIsTransparent = requires { typename T::is_transparent; }; + +template +struct FlatMapBase { + using key_compare = Compare; +}; + +template +struct FlatMap : FlatMapBase { + using Base = FlatMapBase; + + using typename Base::key_compare; + + void at(const K&) {} + void at(const K&) const {} + template + void at(const Other&) + requires HasIsTransparent + {} + template + void at(const Other&) const + requires HasIsTransparent + {} +}; + +template +struct Transparent { + T t; +}; + +struct TransparentComparator { + using is_transparent = void; + + template + bool operator()(const T&, const Transparent&) const; + + template + bool operator()(const Transparent&, const T& t) const; + + template + bool operator()(const T&, const T&) const; +}; + +struct NonTransparentComparator { + template + bool operator()(const T&, const Transparent&) const; + + template + bool operator()(const Transparent&, const T&) const; + + template + bool operator()(const T&, const T&) const; +}; + +template +concept CanAt = requires(M m, Transparent k) { m.at(k); }; + +using TransparentMap = FlatMap; +using NonTransparentMap = FlatMap; + +static_assert(CanAt); + +static_assert(!CanAt); + +} + +namespace GH198663_2 { + +template +auto mv(T& t) -> T&&; + +template +concept does_foo = requires(S s) { + s.template foo(); +}; + +template +struct type { + S member; + template + auto foo() -> T requires does_foo; +}; + +struct returns_int { + template + auto foo() -> T; +}; + +struct nothing {}; + +static_assert(does_foo&, int>); +static_assert(not does_foo&, int>); + +} diff --git a/cmake/Modules/LLVMVersion.cmake b/cmake/Modules/LLVMVersion.cmake index feb48f124e6ee..087b24ae6edb9 100644 --- a/cmake/Modules/LLVMVersion.cmake +++ b/cmake/Modules/LLVMVersion.cmake @@ -7,7 +7,7 @@ if(NOT DEFINED LLVM_VERSION_MINOR) set(LLVM_VERSION_MINOR 1) endif() if(NOT DEFINED LLVM_VERSION_PATCH) - set(LLVM_VERSION_PATCH 7) + set(LLVM_VERSION_PATCH 8) endif() if(NOT DEFINED LLVM_VERSION_SUFFIX) set(LLVM_VERSION_SUFFIX) diff --git a/libcxx/include/__config b/libcxx/include/__config index 3a34eea8edc1e..f72f091d28c76 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -30,7 +30,7 @@ // _LIBCPP_VERSION represents the version of libc++, which matches the version of LLVM. // Given a LLVM release LLVM XX.YY.ZZ (e.g. LLVM 17.0.1 == 17.00.01), _LIBCPP_VERSION is // defined to XXYYZZ. -# define _LIBCPP_VERSION 220107 +# define _LIBCPP_VERSION 220108 # define _LIBCPP_CONCAT_IMPL(_X, _Y) _X##_Y # define _LIBCPP_CONCAT(_X, _Y) _LIBCPP_CONCAT_IMPL(_X, _Y) diff --git a/libcxx/include/optional b/libcxx/include/optional index 12fbcdfa5c5d6..4d85ac1e0ff5e 100644 --- a/libcxx/include/optional +++ b/libcxx/include/optional @@ -828,6 +828,10 @@ private: template constexpr static bool __libcpp_opt_ref_ctor_deleted = is_lvalue_reference_v<_Tp> && reference_constructs_from_temporary_v<_Tp, _Up>; + + template + constexpr static bool __ref_ctor_enabled = + is_lvalue_reference_v<_Tp> && !reference_constructs_from_temporary_v<_Tp, _Up>; # endif // LWG2756: conditionally explicit conversion from _Up @@ -935,7 +939,7 @@ public: template ::template __enable_implicit<_Up>(), int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional(const optional<_Up>& __v) # if _LIBCPP_STD_VER >= 26 - noexcept(is_lvalue_reference_v<_Tp> && is_nothrow_constructible_v<_Tp&, _Up&>) + noexcept(is_lvalue_reference_v<_Tp> && is_nothrow_constructible_v<_Tp&, const _Up&>) # endif { this->__construct_from(__v); @@ -943,7 +947,7 @@ public: template ::template __enable_explicit<_Up>(), int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit optional(const optional<_Up>& __v) # if _LIBCPP_STD_VER >= 26 - noexcept(is_lvalue_reference_v<_Tp> && is_nothrow_constructible_v<_Tp&, _Up&>) + noexcept(is_lvalue_reference_v<_Tp> && is_nothrow_constructible_v<_Tp&, const _Up&>) # endif { this->__construct_from(__v); @@ -981,25 +985,25 @@ public: // optional(optional& rhs) template - requires(!__libcpp_opt_ref_ctor_deleted<_Up>) && (!is_same_v, optional<_Up>>) && - (!is_same_v<_Tp&, _Up>) && is_constructible_v<_Tp&, _Up&> + requires __ref_ctor_enabled<_Up&> && (!is_same_v, optional<_Up>>) && (!is_same_v<_Tp&, _Up>) && + is_constructible_v<_Tp&, _Up&> _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_Up&, _Tp&>) optional(optional<_Up>& __rhs) noexcept(is_nothrow_constructible_v<_Tp&, _Up&>) { this->__construct_from(__rhs); } template - requires __libcpp_opt_ref_ctor_deleted<_Up> && (!is_same_v, optional<_Up>>) && + requires __libcpp_opt_ref_ctor_deleted<_Up&> && (!is_same_v, optional<_Up>>) && (!is_same_v<_Tp&, _Up>) && is_constructible_v<_Tp&, _Up&> constexpr explicit optional(optional<_Up>& __rhs) noexcept = delete; // optional(const optional&) template ::template __enable_implicit<_Up>(), int> = 0> - requires __libcpp_opt_ref_ctor_deleted<_Up> + requires __libcpp_opt_ref_ctor_deleted optional(const optional<_Up>&) = delete; template ::template __enable_explicit<_Up>(), int> = 0> - requires __libcpp_opt_ref_ctor_deleted<_Up> + requires __libcpp_opt_ref_ctor_deleted explicit optional(const optional<_Up>&) = delete; // optional(optional&&) @@ -1013,16 +1017,16 @@ public: // optional(const optional&&) template - requires(!__libcpp_opt_ref_ctor_deleted<_Up>) && (!is_same_v, optional<_Up>>) && - (!is_same_v<_Tp&, _Up>) && is_constructible_v<_Tp&, _Up> + requires __ref_ctor_enabled && (!is_same_v, optional<_Up>>) && + (!is_same_v<_Tp&, _Up>) && is_constructible_v<_Tp&, const _Up> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(!is_convertible_v) optional(const optional<_Up>&& __v) noexcept(is_nothrow_constructible_v<_Tp&, const _Up>) { this->__construct_from(std::move(__v)); } template - requires __libcpp_opt_ref_ctor_deleted<_Up> && (!is_same_v, optional<_Up>>) && - (!is_same_v<_Tp&, _Up>) && is_constructible_v<_Tp&, _Up> + requires __libcpp_opt_ref_ctor_deleted && (!is_same_v, optional<_Up>>) && + (!is_same_v<_Tp&, _Up>) && is_constructible_v<_Tp&, const _Up> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional(const optional<_Up>&& __v) noexcept = delete; # endif diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/const_optional_U.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/const_optional_U.pass.cpp index 597110bcb54fe..844317c8570d9 100644 --- a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/const_optional_U.pass.cpp +++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/const_optional_U.pass.cpp @@ -151,6 +151,37 @@ constexpr bool test_ref() { assert(*o2 == 1); } + { + const std::optional o1{2}; + std::optional o2(o1); + assert(*o2 == 2); + assert(&(*o2) == &(*o1)); + } + + { + const std::optional> o1({1, 2}); + std::optional o2(o1); + assert(o2.has_value()); + assert(&(*o2) == &o1->lvalue); + assert(*o2 == 1); + } + + { + const std::optional> o1({1, 2}); + std::optional o2(std::move(o1)); + assert(o2.has_value()); + assert(&(*o2) == &o1->rvalue); + assert(*o2 == 2); + } + + { + const std::optional> o1({1, 2}); + ASSERT_NOT_NOEXCEPT(std::optional(o1)); + ASSERT_NOT_NOEXCEPT(std::optional(std::move(o1))); + } + + static_assert(!std::is_constructible_v, const std::optional>&&>); + return true; } #endif diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/optional_U.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/optional_U.pass.cpp index 39a80efa475f7..03082033cd4dc 100644 --- a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/optional_U.pass.cpp +++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/optional_U.pass.cpp @@ -144,6 +144,36 @@ constexpr bool test_ref() { assert(*o2 == 1); } + { + std::optional o1(1); + std::optional o2(o1); + assert(o2.has_value()); + assert(*o2 == 1); + assert(&(*o2) == &(*o1)); + } + + { + std::optional> o1({1, 2}); + std::optional o2(o1); + assert(o2.has_value()); + assert(*o2 == 1); + assert(&(*o2) == &o1->lvalue); + } + + { + std::optional> o1({1, 2}); + std::optional o2(std::move(o1)); + assert(o2.has_value()); + assert(*o2 == 2); + assert(&(*o2) == &o1->rvalue); + } + + { + std::optional> o1({1, 2}); + ASSERT_NOT_NOEXCEPT(std::optional(o1)); + ASSERT_NOT_NOEXCEPT(std::optional(std::move(o1))); + } + return true; } #endif @@ -164,6 +194,11 @@ int main(int, char**) { test(std::move(rhs), true); } +#if TEST_STD_VER >= 26 + // GH: #194415 + static_assert(!std::is_constructible_v, std::optional>&>); +#endif + static_assert(!(std::is_constructible, optional>::value), ""); #if TEST_STD_VER >= 26 diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/ref_constructs_from_temporary.verify.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/ref_constructs_from_temporary.verify.cpp index 53ac77a2e5620..d4c95c302d817 100644 --- a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/ref_constructs_from_temporary.verify.cpp +++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/ref_constructs_from_temporary.verify.cpp @@ -29,12 +29,10 @@ void test() { const std::optional co(1); std::optional o0(1); - // expected-error-re@*:* 10 {{call to deleted constructor of 'std::optional<{{.*}}>'}} + // expected-error-re@*:* 8 {{call to deleted constructor of 'std::optional<{{.*}}>'}} std::optional o1{1}; // optional(U&&) - std::optional o2{o0}; // optional(optional&) - std::optional o3{co}; // optional(const optional&) - std::optional o4{std::move(o0)}; // optional(optional&&&) - std::optional o5{std::move(co)}; // optional(optional&&&) + std::optional o4{std::move(o0)}; // optional(optional&&) + std::optional o5{std::move(co)}; // optional(optional&&) std::optional o6{1}; // optional(U&&) std::optional o7{o0}; // optional(optional&) diff --git a/libcxx/test/std/utilities/optional/optional.object/optional_helper_types.h b/libcxx/test/std/utilities/optional/optional.object/optional_helper_types.h index 704d99acb15e9..d9b17a0b91f3b 100644 --- a/libcxx/test/std/utilities/optional/optional.object/optional_helper_types.h +++ b/libcxx/test/std/utilities/optional/optional.object/optional_helper_types.h @@ -21,8 +21,9 @@ struct ReferenceConversion { constexpr ReferenceConversion(T lval, T rval) : lvalue(lval), rvalue(rval) {} constexpr operator T&() & noexcept { return lvalue; } - + constexpr operator const T&() const& noexcept { return lvalue; } constexpr operator T&() && noexcept { return rvalue; } + constexpr operator const T&() const&& noexcept { return rvalue; } }; template @@ -42,6 +43,14 @@ struct ReferenceConversionThrows { return lvalue; } + constexpr operator const T&() const& { + if (throws) { + TEST_THROW(1); + } + + return lvalue; + } + constexpr operator T&() && { if (throws) { TEST_THROW(2); @@ -49,6 +58,34 @@ struct ReferenceConversionThrows { return rvalue; } + + constexpr operator const T&() const&& { + if (throws) { + TEST_THROW(2); + } + + return rvalue; + } +}; + +template +struct LValueOnly { + T val{}; + + constexpr operator T&() & noexcept { return val; } + constexpr operator T&() const& = delete; + constexpr operator T&() && = delete; + constexpr operator T&() const&& = delete; +}; + +template +struct ConstRValueOnly { + mutable T val{}; + + constexpr operator T&() & = delete; + constexpr operator T&() const& = delete; + constexpr operator T&() && = delete; + constexpr operator T&() const&& { return val; }; }; #endif diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h index 23994ccea1ef0..26d28825558c9 100644 --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -243,11 +243,11 @@ class Symbol { uint8_t stOther, uint8_t type) : file(file), nameData(name.data()), nameSize(name.size()), type(type), binding(binding), stOther(stOther), symbolKind(k), isPreemptible(false), - isUsedInRegularObj(false), isExported(false), ltoCanOmit(false), - traced(false), hasVersionSuffix(false), isInIplt(false), - gotInIgot(false), folded(false), archSpecificBit(false), - scriptDefined(false), dsoDefined(false), dsoProtected(false), - versionScriptAssigned(false), thunkAccessed(false), + isUsedInRegularObj(false), used(false), isExported(false), + ltoCanOmit(false), traced(false), hasVersionSuffix(false), + isInIplt(false), gotInIgot(false), folded(false), + archSpecificBit(false), scriptDefined(false), dsoDefined(false), + dsoProtected(false), versionScriptAssigned(false), thunkAccessed(false), inDynamicList(false), referenced(false), referencedAfterWrap(false) {} void overwrite(Symbol &sym, Kind k) const { diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index 3fdb9bf7e5171..ee9238753735a 100644 --- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -23117,6 +23117,19 @@ static SDValue foldToMaskedStore(StoreSDNode *Store, SelectionDAG &DAG, if (LoadPos == 1) Mask = DAG.getNOT(Dl, Mask, Mask.getValueType()); + // A masked store follows the IR convention of a vXi1 mask (one bit per + // element). A vselect condition may instead be a wider boolean vector, e.g. + // a vXi32/vXi64 comparison result produced on AVX512 targets without VLX. + // When the matching vXi1 type is legal, narrow the mask to it so that targets + // expecting a vXi1 mask lower it correctly. Targets where vXi1 is illegal + // (e.g. AVX/AVX2) keep the wide mask and lower it as a blend/vmaskmov. + EVT MaskVT = Mask.getValueType(); + if (MaskVT.getVectorElementType() != MVT::i1) { + EVT BoolVT = MaskVT.changeVectorElementType(*DAG.getContext(), MVT::i1); + if (TLI.isTypeLegal(BoolVT)) + Mask = DAG.getNode(ISD::TRUNCATE, Dl, BoolVT, Mask); + } + return DAG.getMaskedStore(Store->getChain(), Dl, OtherVec, StorePtr, StoreOffset, Mask, VT, Store->getMemOperand(), Store->getAddressingMode()); diff --git a/llvm/lib/Target/BPF/BPFISelLowering.cpp b/llvm/lib/Target/BPF/BPFISelLowering.cpp index 5c03776dd6653..faf3af0918d54 100644 --- a/llvm/lib/Target/BPF/BPFISelLowering.cpp +++ b/llvm/lib/Target/BPF/BPFISelLowering.cpp @@ -110,6 +110,8 @@ BPFTargetLowering::BPFTargetLowering(const TargetMachine &TM, setOperationAction(ISD::ATOMIC_STORE, VT, Custom); } + setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Custom); + for (auto VT : { MVT::i32, MVT::i64 }) { if (VT == MVT::i32 && !STI.getHasAlu32()) continue; @@ -368,6 +370,8 @@ SDValue BPFTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { case ISD::ATOMIC_LOAD: case ISD::ATOMIC_STORE: return LowerATOMIC_LOAD_STORE(Op, DAG); + case ISD::ATOMIC_FENCE: + return LowerATOMIC_FENCE(Op, DAG); case ISD::TRAP: return LowerTRAP(Op, DAG); } @@ -772,6 +776,19 @@ SDValue BPFTargetLowering::LowerATOMIC_LOAD_STORE(SDValue Op, return Op; } +SDValue BPFTargetLowering::LowerATOMIC_FENCE(SDValue Op, + SelectionDAG &DAG) const { + SDLoc DL(Op); + SyncScope::ID FenceSSID = + static_cast(Op.getConstantOperandVal(2)); + + if (FenceSSID == SyncScope::SingleThread) + // MEMBARRIER is a compiler barrier; it codegens to a no-op. + return DAG.getNode(ISD::MEMBARRIER, DL, MVT::Other, Op.getOperand(0)); + + report_fatal_error("Runtime fence is not supported at the moment"); +} + static Function *createBPFUnreachable(Module *M) { if (auto *Fn = M->getFunction(BPF_TRAP)) return Fn; diff --git a/llvm/lib/Target/BPF/BPFISelLowering.h b/llvm/lib/Target/BPF/BPFISelLowering.h index 8607e4f8c9e69..df1e2d8114ae1 100644 --- a/llvm/lib/Target/BPF/BPFISelLowering.h +++ b/llvm/lib/Target/BPF/BPFISelLowering.h @@ -73,6 +73,7 @@ class BPFTargetLowering : public TargetLowering { SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG) const; SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const; SDValue LowerATOMIC_LOAD_STORE(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerATOMIC_FENCE(SDValue Op, SelectionDAG &DAG) const; SDValue LowerConstantPool(SDValue Op, SelectionDAG &DAG) const; SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const; SDValue LowerTRAP(SDValue Op, SelectionDAG &DAG) const; diff --git a/llvm/lib/Target/Hexagon/HexagonPatterns.td b/llvm/lib/Target/Hexagon/HexagonPatterns.td index f6d51acce562e..7d5e3feec6bbe 100644 --- a/llvm/lib/Target/Hexagon/HexagonPatterns.td +++ b/llvm/lib/Target/Hexagon/HexagonPatterns.td @@ -530,17 +530,22 @@ def: Pat<(i64 (bitconvert F64:$v)), (I64:$v)>; def: Pat<(f64 (bitconvert I64:$v)), (F64:$v)>; // Bit convert 32- and 64-bit types. -// All of these are bitcastable to one another: i32, v2i16, v4i8. +// All of these are bitcastable to one another: i32, f32, v2i16, v4i8. defm: NopCast_pat; defm: NopCast_pat; defm: NopCast_pat; -// All of these are bitcastable to one another: i64, v2i32, v4i16, v8i8. +defm: NopCast_pat; +defm: NopCast_pat; +// All of these are bitcastable to one another: i64, f64, v2i32, v4i16, v8i8. defm: NopCast_pat; defm: NopCast_pat; defm: NopCast_pat; defm: NopCast_pat; defm: NopCast_pat; defm: NopCast_pat; +defm: NopCast_pat; +defm: NopCast_pat; +defm: NopCast_pat; // --(3) Extend/truncate/saturate ---------------------------------------- diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp index 8246623e8e5aa..20b43538d69c4 100644 --- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp @@ -1898,6 +1898,7 @@ MachineBasicBlock::iterator RISCVFrameLowering::eliminateCallFramePseudoInstr( needsDwarfCFI(MF) && !hasFP(MF), /*NeedProbe=*/true, ProbeSize, DynAllocation, MachineInstr::NoFlags); + inlineStackProbe(MF, MBB); } else { const RISCVRegisterInfo &RI = *STI.getRegisterInfo(); RI.adjustReg(MBB, MI, DL, SPReg, SPReg, StackOffset::getFixed(Amount), diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td index 72feb5492c67a..c69cd03f97b78 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td @@ -1504,12 +1504,26 @@ multiclass SignedSaturatingTruncate; defm : SignedSaturatingTruncate; +// NOTE: the saturating is actually signed, the truncation is unsigned, see +// https://www.w3.org/TR/wasm-core-2/#-hrefop-narrowmathrmnarrowmathsfu_m-n-i multiclass UnsignedSaturatingTruncate { + Instruction narrow, int maxval> { def : Pat< (output (wasm_narrow_u - (umin (input V128:$a), (splat_vector (i32 maxval))), - (umin (input V128:$b), (splat_vector (i32 maxval))) + (smin (smax (input V128:$a), (splat_vector (i32 0))), + (splat_vector (i32 maxval))), + (smin (smax (input V128:$b), (splat_vector (i32 0))), + (splat_vector (i32 maxval))) + )), + (narrow V128:$a, V128:$b) + >; + + def : Pat< + (output (wasm_narrow_u + (smax (smin (input V128:$a), (splat_vector (i32 maxval))), + (splat_vector (i32 0))), + (smax (smin (input V128:$b), (splat_vector (i32 maxval))), + (splat_vector (i32 0))) )), (narrow V128:$a, V128:$b) >; diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp index cdc6ecfa21bcb..77589e06d9c33 100644 --- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp +++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp @@ -4282,6 +4282,7 @@ VectorizationFactor LoopVectorizationPlanner::selectVectorizationFactor() { break; } case VPInstruction::ExplicitVectorLength: + case VPInstruction::AnyOf: C += VPI->cost(VF, CostCtx); break; default: diff --git a/llvm/test/CodeGen/BPF/fence-singlethread.ll b/llvm/test/CodeGen/BPF/fence-singlethread.ll new file mode 100644 index 0000000000000..91ea38db8b8c8 --- /dev/null +++ b/llvm/test/CodeGen/BPF/fence-singlethread.ll @@ -0,0 +1,14 @@ +; RUN: llc < %s -mtriple=bpfel | FileCheck %s +; RUN: llc < %s -mtriple=bpfeb | FileCheck %s + +; CHECK-LABEL: fence_singlethread: +; CHECK-COUNT-4: #MEMBARRIER +; CHECK-NEXT: exit +define void @fence_singlethread() nounwind { +entry: + fence syncscope("singlethread") acquire + fence syncscope("singlethread") release + fence syncscope("singlethread") acq_rel + fence syncscope("singlethread") seq_cst + ret void +} diff --git a/llvm/test/CodeGen/Hexagon/bitcast-f64-vector.ll b/llvm/test/CodeGen/Hexagon/bitcast-f64-vector.ll new file mode 100644 index 0000000000000..172a3ab32e616 --- /dev/null +++ b/llvm/test/CodeGen/Hexagon/bitcast-f64-vector.ll @@ -0,0 +1,63 @@ +; RUN: llc -mtriple=hexagon -mcpu=hexagonv68 -O3 < %s | FileCheck %s + +; Verify that bitcasts between f64 and the integer vector types that share the +; DoubleRegs register class (v2i32, v4i16, v8i8) are treated as no-ops by the +; instruction selector and do not cause a "Cannot select" crash. +; +; All of i64, f64, v2i32, v4i16, v8i8 live in DoubleRegs (64-bit register +; pairs). A bitcast between any two of them is a pure reinterpretation of the +; same 64 bits. Therefore no instruction is emitted. +; +; Regression test for: llvm.org/PR195495 +; llc -mtriple=hexagon -mcpu=hexagonv68 -O3 crashed with +; "Cannot select: f64 = bitcast v2i32" when compiling Eigen's packetmath. + +; CHECK-LABEL: test_v2i32_to_f64: +; CHECK: dfcmp +; CHECK: jumpr r31 +define i1 @test_v2i32_to_f64(<2 x i32> %a) { + %bc = bitcast <2 x i32> %a to double + %cmp = fcmp une double %bc, 0.0 + ret i1 %cmp +} + +; f64->v2i32 is a no-op: the argument is already in a DoubleReg pair. +; CHECK-LABEL: test_f64_to_v2i32: +; CHECK-NOT: combine +; CHECK: jumpr r31 +define <2 x i32> @test_f64_to_v2i32(double %a) { + %bc = bitcast double %a to <2 x i32> + ret <2 x i32> %bc +} + +; CHECK-LABEL: test_v4i16_to_f64: +; CHECK: dfcmp +; CHECK: jumpr r31 +define i1 @test_v4i16_to_f64(<4 x i16> %a) { + %bc = bitcast <4 x i16> %a to double + %cmp = fcmp une double %bc, 0.0 + ret i1 %cmp +} + +; CHECK-LABEL: test_v8i8_to_f64: +; CHECK: dfcmp +; CHECK: jumpr r31 +define i1 @test_v8i8_to_f64(<8 x i8> %a) { + %bc = bitcast <8 x i8> %a to double + %cmp = fcmp une double %bc, 0.0 + ret i1 %cmp +} + +; Regression test: the original crash. +; <4 x i32> is passed in two v2i32 DoubleReg pairs; after type-legalizing +; <2 x f64> setcc into two scalar f64 setcc ops, each f64 operand is produced +; by a "f64 = bitcast v2i32" node that previously had no matching pattern. +; CHECK-LABEL: test_packetmath_reduced: +; CHECK: dfcmp +; CHECK: jumpr r31 +define <2 x i1> @test_packetmath_reduced(<4 x i32> %arg) { +entry: + %bc = bitcast <4 x i32> %arg to <2 x double> + %cmp = fcmp une <2 x double> %bc, zeroinitializer + ret <2 x i1> %cmp +} diff --git a/llvm/test/CodeGen/RISCV/stack-probing-dynamic-nonentry.ll b/llvm/test/CodeGen/RISCV/stack-probing-dynamic-nonentry.ll new file mode 100644 index 0000000000000..4c8bb653b4cff --- /dev/null +++ b/llvm/test/CodeGen/RISCV/stack-probing-dynamic-nonentry.ll @@ -0,0 +1,115 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6 +; RUN: llc -mtriple=riscv64 -mattr=+m -O2 < %s | FileCheck %s -check-prefix=RV64 +; RUN: llc -mtriple=riscv32 -mattr=+m -O2 < %s | FileCheck %s -check-prefix=RV32 + +; Test that very large outgoing call frames in functions with variable-sized +; objects get proper stack probing. The outgoing args are large enough to force +; the PROBED_STACKALLOC path, which must be expanded in a non-entry block. + +define void @f(i64 %n) #0 { +; RV64-LABEL: f: +; RV64: # %bb.0: # %entry +; RV64-NEXT: addi sp, sp, -16 +; RV64-NEXT: .cfi_def_cfa_offset 16 +; RV64-NEXT: sd zero, 0(sp) +; RV64-NEXT: sd ra, 8(sp) # 8-byte Folded Spill +; RV64-NEXT: sd s0, 0(sp) # 8-byte Folded Spill +; RV64-NEXT: .cfi_offset ra, -8 +; RV64-NEXT: .cfi_offset s0, -16 +; RV64-NEXT: addi s0, sp, 16 +; RV64-NEXT: .cfi_def_cfa s0, 0 +; RV64-NEXT: slli a0, a0, 2 +; RV64-NEXT: addi a0, a0, 15 +; RV64-NEXT: andi a0, a0, -16 +; RV64-NEXT: sub a0, sp, a0 +; RV64-NEXT: lui a1, 1 +; RV64-NEXT: .LBB0_1: # %entry +; RV64-NEXT: # =>This Inner Loop Header: Depth=1 +; RV64-NEXT: sub sp, sp, a1 +; RV64-NEXT: sd zero, 0(sp) +; RV64-NEXT: blt a0, sp, .LBB0_1 +; RV64-NEXT: # %bb.2: # %entry +; RV64-NEXT: mv sp, a0 +; RV64-NEXT: lui a1, 5 +; RV64-NEXT: sub t1, sp, a1 +; RV64-NEXT: lui t2, 1 +; RV64-NEXT: .LBB0_3: # %entry +; RV64-NEXT: # =>This Inner Loop Header: Depth=1 +; RV64-NEXT: sub sp, sp, t2 +; RV64-NEXT: sd zero, 0(sp) +; RV64-NEXT: bne sp, t1, .LBB0_3 +; RV64-NEXT: # %bb.4: # %entry +; RV64-NEXT: addi sp, sp, -2048 +; RV64-NEXT: addi sp, sp, -1424 +; RV64-NEXT: sd zero, 0(sp) +; RV64-NEXT: call g +; RV64-NEXT: lui a0, 6 +; RV64-NEXT: addi a0, a0, -624 +; RV64-NEXT: add sp, sp, a0 +; RV64-NEXT: addi sp, s0, -16 +; RV64-NEXT: .cfi_def_cfa sp, 16 +; RV64-NEXT: ld ra, 8(sp) # 8-byte Folded Reload +; RV64-NEXT: ld s0, 0(sp) # 8-byte Folded Reload +; RV64-NEXT: .cfi_restore ra +; RV64-NEXT: .cfi_restore s0 +; RV64-NEXT: addi sp, sp, 16 +; RV64-NEXT: .cfi_def_cfa_offset 0 +; RV64-NEXT: ret +; +; RV32-LABEL: f: +; RV32: # %bb.0: # %entry +; RV32-NEXT: addi sp, sp, -16 +; RV32-NEXT: .cfi_def_cfa_offset 16 +; RV32-NEXT: sw zero, 0(sp) +; RV32-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; RV32-NEXT: sw s0, 8(sp) # 4-byte Folded Spill +; RV32-NEXT: .cfi_offset ra, -4 +; RV32-NEXT: .cfi_offset s0, -8 +; RV32-NEXT: addi s0, sp, 16 +; RV32-NEXT: .cfi_def_cfa s0, 0 +; RV32-NEXT: slli a0, a0, 2 +; RV32-NEXT: addi a0, a0, 15 +; RV32-NEXT: andi a0, a0, -16 +; RV32-NEXT: sub a0, sp, a0 +; RV32-NEXT: lui a1, 1 +; RV32-NEXT: .LBB0_1: # %entry +; RV32-NEXT: # =>This Inner Loop Header: Depth=1 +; RV32-NEXT: sub sp, sp, a1 +; RV32-NEXT: sw zero, 0(sp) +; RV32-NEXT: blt a0, sp, .LBB0_1 +; RV32-NEXT: # %bb.2: # %entry +; RV32-NEXT: mv sp, a0 +; RV32-NEXT: lui a1, 5 +; RV32-NEXT: sub t1, sp, a1 +; RV32-NEXT: lui t2, 1 +; RV32-NEXT: .LBB0_3: # %entry +; RV32-NEXT: # =>This Inner Loop Header: Depth=1 +; RV32-NEXT: sub sp, sp, t2 +; RV32-NEXT: sw zero, 0(sp) +; RV32-NEXT: bne sp, t1, .LBB0_3 +; RV32-NEXT: # %bb.4: # %entry +; RV32-NEXT: addi sp, sp, -2048 +; RV32-NEXT: addi sp, sp, -1456 +; RV32-NEXT: sw zero, 0(sp) +; RV32-NEXT: call g +; RV32-NEXT: lui a0, 6 +; RV32-NEXT: addi a0, a0, -592 +; RV32-NEXT: add sp, sp, a0 +; RV32-NEXT: addi sp, s0, -16 +; RV32-NEXT: .cfi_def_cfa sp, 16 +; RV32-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; RV32-NEXT: lw s0, 8(sp) # 4-byte Folded Reload +; RV32-NEXT: .cfi_restore ra +; RV32-NEXT: .cfi_restore s0 +; RV32-NEXT: addi sp, sp, 16 +; RV32-NEXT: .cfi_def_cfa_offset 0 +; RV32-NEXT: ret +entry: + %v = alloca i32, i64 %n + call void @g(ptr %v, [3000 x i64] poison) + ret void +} + +declare void @g(ptr, [3000 x i64]) + +attributes #0 = { "probe-stack"="inline-asm" } diff --git a/llvm/test/CodeGen/WebAssembly/fpclamptosat_vec.ll b/llvm/test/CodeGen/WebAssembly/fpclamptosat_vec.ll index 55409d5b2d8c3..f77443e2725c2 100644 --- a/llvm/test/CodeGen/WebAssembly/fpclamptosat_vec.ll +++ b/llvm/test/CodeGen/WebAssembly/fpclamptosat_vec.ll @@ -484,7 +484,7 @@ entry: define <8 x i16> @utest_f16i16(<8 x half> %x) { ; CHECK-LABEL: utest_f16i16: ; CHECK: .functype utest_f16i16 (i32, i32, i32, i32, i32, i32, i32, i32) -> (v128) -; CHECK-NEXT: .local f32, f32, f32, f32, f32 +; CHECK-NEXT: .local f32, f32, f32, f32, f32, v128 ; CHECK-NEXT: # %bb.0: # %entry ; CHECK-NEXT: local.get 5 ; CHECK-NEXT: call __extendhfsf2 @@ -516,6 +516,9 @@ define <8 x i16> @utest_f16i16(<8 x half> %x) { ; CHECK-NEXT: call __extendhfsf2 ; CHECK-NEXT: i32.trunc_sat_f32_u ; CHECK-NEXT: i32x4.replace_lane 3 +; CHECK-NEXT: v128.const 65535, 65535, 65535, 65535 +; CHECK-NEXT: local.tee 13 +; CHECK-NEXT: i32x4.min_u ; CHECK-NEXT: local.get 9 ; CHECK-NEXT: i32.trunc_sat_f32_u ; CHECK-NEXT: i32x4.splat @@ -528,6 +531,8 @@ define <8 x i16> @utest_f16i16(<8 x half> %x) { ; CHECK-NEXT: local.get 11 ; CHECK-NEXT: i32.trunc_sat_f32_u ; CHECK-NEXT: i32x4.replace_lane 3 +; CHECK-NEXT: local.get 13 +; CHECK-NEXT: i32x4.min_u ; CHECK-NEXT: i16x8.narrow_i32x4_u ; CHECK-NEXT: # fallthrough-return entry: @@ -541,7 +546,7 @@ entry: define <8 x i16> @ustest_f16i16(<8 x half> %x) { ; CHECK-LABEL: ustest_f16i16: ; CHECK: .functype ustest_f16i16 (i32, i32, i32, i32, i32, i32, i32, i32) -> (v128) -; CHECK-NEXT: .local f32, f32, f32, f32, f32, v128, v128 +; CHECK-NEXT: .local f32, f32, f32, f32, f32 ; CHECK-NEXT: # %bb.0: # %entry ; CHECK-NEXT: local.get 5 ; CHECK-NEXT: call __extendhfsf2 @@ -573,12 +578,6 @@ define <8 x i16> @ustest_f16i16(<8 x half> %x) { ; CHECK-NEXT: call __extendhfsf2 ; CHECK-NEXT: i32.trunc_sat_f32_s ; CHECK-NEXT: i32x4.replace_lane 3 -; CHECK-NEXT: v128.const 65535, 65535, 65535, 65535 -; CHECK-NEXT: local.tee 13 -; CHECK-NEXT: i32x4.min_s -; CHECK-NEXT: v128.const 0, 0, 0, 0 -; CHECK-NEXT: local.tee 14 -; CHECK-NEXT: i32x4.max_s ; CHECK-NEXT: local.get 9 ; CHECK-NEXT: i32.trunc_sat_f32_s ; CHECK-NEXT: i32x4.splat @@ -591,10 +590,6 @@ define <8 x i16> @ustest_f16i16(<8 x half> %x) { ; CHECK-NEXT: local.get 11 ; CHECK-NEXT: i32.trunc_sat_f32_s ; CHECK-NEXT: i32x4.replace_lane 3 -; CHECK-NEXT: local.get 13 -; CHECK-NEXT: i32x4.min_s -; CHECK-NEXT: local.get 14 -; CHECK-NEXT: i32x4.max_s ; CHECK-NEXT: i16x8.narrow_i32x4_u ; CHECK-NEXT: # fallthrough-return entry: @@ -1850,7 +1845,7 @@ entry: define <8 x i16> @utest_f16i16_mm(<8 x half> %x) { ; CHECK-LABEL: utest_f16i16_mm: ; CHECK: .functype utest_f16i16_mm (i32, i32, i32, i32, i32, i32, i32, i32) -> (v128) -; CHECK-NEXT: .local f32, f32, f32, f32, f32 +; CHECK-NEXT: .local f32, f32, f32, f32, f32, v128 ; CHECK-NEXT: # %bb.0: # %entry ; CHECK-NEXT: local.get 5 ; CHECK-NEXT: call __extendhfsf2 @@ -1882,6 +1877,9 @@ define <8 x i16> @utest_f16i16_mm(<8 x half> %x) { ; CHECK-NEXT: call __extendhfsf2 ; CHECK-NEXT: i32.trunc_sat_f32_u ; CHECK-NEXT: i32x4.replace_lane 3 +; CHECK-NEXT: v128.const 65535, 65535, 65535, 65535 +; CHECK-NEXT: local.tee 13 +; CHECK-NEXT: i32x4.min_u ; CHECK-NEXT: local.get 9 ; CHECK-NEXT: i32.trunc_sat_f32_u ; CHECK-NEXT: i32x4.splat @@ -1894,6 +1892,8 @@ define <8 x i16> @utest_f16i16_mm(<8 x half> %x) { ; CHECK-NEXT: local.get 11 ; CHECK-NEXT: i32.trunc_sat_f32_u ; CHECK-NEXT: i32x4.replace_lane 3 +; CHECK-NEXT: local.get 13 +; CHECK-NEXT: i32x4.min_u ; CHECK-NEXT: i16x8.narrow_i32x4_u ; CHECK-NEXT: # fallthrough-return entry: @@ -1906,7 +1906,7 @@ entry: define <8 x i16> @ustest_f16i16_mm(<8 x half> %x) { ; CHECK-LABEL: ustest_f16i16_mm: ; CHECK: .functype ustest_f16i16_mm (i32, i32, i32, i32, i32, i32, i32, i32) -> (v128) -; CHECK-NEXT: .local f32, f32, f32, f32, f32, v128, v128 +; CHECK-NEXT: .local f32, f32, f32, f32, f32 ; CHECK-NEXT: # %bb.0: # %entry ; CHECK-NEXT: local.get 5 ; CHECK-NEXT: call __extendhfsf2 @@ -1938,12 +1938,6 @@ define <8 x i16> @ustest_f16i16_mm(<8 x half> %x) { ; CHECK-NEXT: call __extendhfsf2 ; CHECK-NEXT: i32.trunc_sat_f32_s ; CHECK-NEXT: i32x4.replace_lane 3 -; CHECK-NEXT: v128.const 65535, 65535, 65535, 65535 -; CHECK-NEXT: local.tee 13 -; CHECK-NEXT: i32x4.min_s -; CHECK-NEXT: v128.const 0, 0, 0, 0 -; CHECK-NEXT: local.tee 14 -; CHECK-NEXT: i32x4.max_s ; CHECK-NEXT: local.get 9 ; CHECK-NEXT: i32.trunc_sat_f32_s ; CHECK-NEXT: i32x4.splat @@ -1956,10 +1950,6 @@ define <8 x i16> @ustest_f16i16_mm(<8 x half> %x) { ; CHECK-NEXT: local.get 11 ; CHECK-NEXT: i32.trunc_sat_f32_s ; CHECK-NEXT: i32x4.replace_lane 3 -; CHECK-NEXT: local.get 13 -; CHECK-NEXT: i32x4.min_s -; CHECK-NEXT: local.get 14 -; CHECK-NEXT: i32x4.max_s ; CHECK-NEXT: i16x8.narrow_i32x4_u ; CHECK-NEXT: # fallthrough-return entry: diff --git a/llvm/test/CodeGen/WebAssembly/saturating-truncation.ll b/llvm/test/CodeGen/WebAssembly/saturating-truncation.ll index f3f3ba9b268d7..6070dfa5bed76 100644 --- a/llvm/test/CodeGen/WebAssembly/saturating-truncation.ll +++ b/llvm/test/CodeGen/WebAssembly/saturating-truncation.ll @@ -56,12 +56,19 @@ bb2: ret <8 x i16> %3 } -define <16 x i8> @i16_unsigned(<8 x i16> %a, <8 x i16> %b) { -; CHECK-LABEL: i16_unsigned: -; CHECK: .functype i16_unsigned (v128, v128) -> (v128) +; NOTE: unsigned narrow uses *signed* saturation, the manual unsigned saturation cannot be optimized out. +define <16 x i8> @i16_unsigned_sat_unsigned_truncate(<8 x i16> %a, <8 x i16> %b) { +; CHECK-LABEL: i16_unsigned_sat_unsigned_truncate: +; CHECK: .functype i16_unsigned_sat_unsigned_truncate (v128, v128) -> (v128) +; CHECK-NEXT: .local v128 ; CHECK-NEXT: # %bb.0: # %bb2 ; CHECK-NEXT: local.get 0 +; CHECK-NEXT: v128.const 255, 255, 255, 255, 255, 255, 255, 255 +; CHECK-NEXT: local.tee 2 +; CHECK-NEXT: i16x8.min_u ; CHECK-NEXT: local.get 1 +; CHECK-NEXT: local.get 2 +; CHECK-NEXT: i16x8.min_u ; CHECK-NEXT: i8x16.narrow_i16x8_u ; CHECK-NEXT: # fallthrough-return bb2: @@ -71,12 +78,19 @@ bb2: ret <16 x i8> %2 } -define <8 x i16> @i32_unsigned(<4 x i32> %a, <4 x i32> %b) { -; CHECK-LABEL: i32_unsigned: -; CHECK: .functype i32_unsigned (v128, v128) -> (v128) +; NOTE: unsigned narrow uses *signed* saturation, the manual unsigned saturation cannot be optimized out. +define <8 x i16> @i32_unsigned_sat_unsigned_truncate(<4 x i32> %a, <4 x i32> %b) { +; CHECK-LABEL: i32_unsigned_sat_unsigned_truncate: +; CHECK: .functype i32_unsigned_sat_unsigned_truncate (v128, v128) -> (v128) +; CHECK-NEXT: .local v128 ; CHECK-NEXT: # %bb.0: # %bb2 ; CHECK-NEXT: local.get 0 +; CHECK-NEXT: v128.const 65535, 65535, 65535, 65535 +; CHECK-NEXT: local.tee 2 +; CHECK-NEXT: i32x4.min_u ; CHECK-NEXT: local.get 1 +; CHECK-NEXT: local.get 2 +; CHECK-NEXT: i32x4.min_u ; CHECK-NEXT: i16x8.narrow_i32x4_u ; CHECK-NEXT: # fallthrough-return bb2: @@ -85,3 +99,53 @@ bb2: %2 = trunc nsw <8 x i32> %1 to <8 x i16> ret <8 x i16> %2 } + +; NOTE: narrow_i16x8_u uses *signed* saturation, the manual unsigned saturation cannot be optimized out. +define <16 x i8> @narrow_with_manual_unsigned_sat(<8 x i16> %a) { +; CHECK-LABEL: narrow_with_manual_unsigned_sat: +; CHECK: .functype narrow_with_manual_unsigned_sat (v128) -> (v128) +; CHECK-NEXT: # %bb.0: # %start +; CHECK-NEXT: local.get 0 +; CHECK-NEXT: v128.const 255, 255, 255, 255, 255, 255, 255, 255 +; CHECK-NEXT: i16x8.min_u +; CHECK-NEXT: local.tee 0 +; CHECK-NEXT: local.get 0 +; CHECK-NEXT: i8x16.narrow_i16x8_u +; CHECK-NEXT: # fallthrough-return +start: + %0 = tail call <8 x i16> @llvm.umin.v8i16(<8 x i16> %a, <8 x i16> splat (i16 255)) + %_21 = tail call <16 x i8> @llvm.wasm.narrow.unsigned.v16i8.v8i16(<8 x i16> %0, <8 x i16> %0) + ret <16 x i8> %_21 +} + +define <16 x i8> @i16_signed_sat_unsigned_truncate(<8 x i16> %a, <8 x i16> %b) { +; CHECK-LABEL: i16_signed_sat_unsigned_truncate: +; CHECK: .functype i16_signed_sat_unsigned_truncate (v128, v128) -> (v128) +; CHECK-NEXT: # %bb.0: # %bb2 +; CHECK-NEXT: local.get 0 +; CHECK-NEXT: local.get 1 +; CHECK-NEXT: i8x16.narrow_i16x8_u +; CHECK-NEXT: # fallthrough-return +bb2: + %0 = shufflevector <8 x i16> %a, <8 x i16> %b, <16 x i32> + %1 = tail call <16 x i16> @llvm.smax.v16i16(<16 x i16> %0, <16 x i16> zeroinitializer) + %2 = tail call <16 x i16> @llvm.smin.v16i16(<16 x i16> %1, <16 x i16> splat (i16 255)) + %3 = trunc nuw <16 x i16> %2 to <16 x i8> + ret <16 x i8> %3 +} + +define <8 x i16> @i32_signed_sat_unsigned_truncate(<4 x i32> %a, <4 x i32> %b) { +; CHECK-LABEL: i32_signed_sat_unsigned_truncate: +; CHECK: .functype i32_signed_sat_unsigned_truncate (v128, v128) -> (v128) +; CHECK-NEXT: # %bb.0: # %bb2 +; CHECK-NEXT: local.get 0 +; CHECK-NEXT: local.get 1 +; CHECK-NEXT: i16x8.narrow_i32x4_u +; CHECK-NEXT: # fallthrough-return +bb2: + %0 = shufflevector <4 x i32> %a, <4 x i32> %b, <8 x i32> + %1 = tail call <8 x i32> @llvm.smin.v8i32(<8 x i32> %0, <8 x i32> splat (i32 65535)) + %2 = tail call <8 x i32> @llvm.smax.v8i32(<8 x i32> %1, <8 x i32> zeroinitializer) + %3 = trunc nuw <8 x i32> %2 to <8 x i16> + ret <8 x i16> %3 +} diff --git a/llvm/test/CodeGen/X86/avx512-maxnum-minnum-masked-store.ll b/llvm/test/CodeGen/X86/avx512-maxnum-minnum-masked-store.ll new file mode 100644 index 0000000000000..f6ca1490b558c --- /dev/null +++ b/llvm/test/CodeGen/X86/avx512-maxnum-minnum-masked-store.ll @@ -0,0 +1,151 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=x86_64-unknown-linux -mattr=+avx | FileCheck %s --check-prefix=AVX +; RUN: llc < %s -mtriple=x86_64-unknown-linux -mattr=+avx2 | FileCheck %s --check-prefix=AVX +; RUN: llc < %s -mtriple=x86_64-unknown-linux -mattr=+avx512f | FileCheck %s --check-prefix=AVX512F +; RUN: llc < %s -mtriple=x86_64-unknown-linux -mattr=+avx512f,+avx512vl | FileCheck %s --check-prefix=AVX512VL + +; On AVX512F targets without VLX (e.g. KNL), a maxnum/minnum store-back fuses a +; legacy CMPP vector comparison into a masked store via foldToMaskedStore, so +; the vselect mask is a wide vNi32/vNi64 vector rather than vNi1. The combine +; must narrow the mask to vNi1 (legal here) before building the masked store, so +; the widening custom lowering only ever sees an i1 mask and does not assert. +; +; On AVX/AVX2 the matching vNi1 type is illegal, so the combine keeps the wide +; mask and the masked store lowers to vmaskmov (the isTypeLegal guard leaves +; this path unchanged). + +define void @maxnum_v4f32_masked_store(<4 x float> %a, ptr %ptr) { +; AVX-LABEL: maxnum_v4f32_masked_store: +; AVX: # %bb.0: +; AVX-NEXT: vmovups (%rdi), %xmm1 +; AVX-NEXT: vmaxps %xmm0, %xmm1, %xmm1 +; AVX-NEXT: vcmpordps %xmm0, %xmm0, %xmm0 +; AVX-NEXT: vmaskmovps %xmm1, %xmm0, (%rdi) +; AVX-NEXT: retq +; +; AVX512F-LABEL: maxnum_v4f32_masked_store: +; AVX512F: # %bb.0: +; AVX512F-NEXT: vmovups (%rdi), %xmm1 +; AVX512F-NEXT: vmaxps %xmm0, %xmm1, %xmm1 +; AVX512F-NEXT: vcmpunordps %xmm0, %xmm0, %xmm0 +; AVX512F-NEXT: vptestnmd %zmm0, %zmm0, %k0 +; AVX512F-NEXT: kshiftlw $12, %k0, %k0 +; AVX512F-NEXT: kshiftrw $12, %k0, %k1 +; AVX512F-NEXT: vmovups %zmm1, (%rdi) {%k1} +; AVX512F-NEXT: vzeroupper +; AVX512F-NEXT: retq +; +; AVX512VL-LABEL: maxnum_v4f32_masked_store: +; AVX512VL: # %bb.0: +; AVX512VL-NEXT: vmovups (%rdi), %xmm1 +; AVX512VL-NEXT: vmaxps %xmm0, %xmm1, %xmm1 +; AVX512VL-NEXT: vcmpordps %xmm0, %xmm0, %k1 +; AVX512VL-NEXT: vmovups %xmm1, (%rdi) {%k1} +; AVX512VL-NEXT: retq + %b = load <4 x float>, ptr %ptr, align 4 + %m = call <4 x float> @llvm.maxnum.v4f32(<4 x float> %a, <4 x float> %b) + store <4 x float> %m, ptr %ptr, align 4 + ret void +} + +define void @maxnum_v2f64_masked_store(<2 x double> %a, ptr %ptr) { +; AVX-LABEL: maxnum_v2f64_masked_store: +; AVX: # %bb.0: +; AVX-NEXT: vmovupd (%rdi), %xmm1 +; AVX-NEXT: vmaxpd %xmm0, %xmm1, %xmm1 +; AVX-NEXT: vcmpordpd %xmm0, %xmm0, %xmm0 +; AVX-NEXT: vmaskmovpd %xmm1, %xmm0, (%rdi) +; AVX-NEXT: retq +; +; AVX512F-LABEL: maxnum_v2f64_masked_store: +; AVX512F: # %bb.0: +; AVX512F-NEXT: vmovupd (%rdi), %xmm1 +; AVX512F-NEXT: vmaxpd %xmm0, %xmm1, %xmm1 +; AVX512F-NEXT: vcmpunordpd %xmm0, %xmm0, %xmm0 +; AVX512F-NEXT: vptestnmq %zmm0, %zmm0, %k0 +; AVX512F-NEXT: kshiftlw $14, %k0, %k0 +; AVX512F-NEXT: kshiftrw $14, %k0, %k1 +; AVX512F-NEXT: vmovupd %zmm1, (%rdi) {%k1} +; AVX512F-NEXT: vzeroupper +; AVX512F-NEXT: retq +; +; AVX512VL-LABEL: maxnum_v2f64_masked_store: +; AVX512VL: # %bb.0: +; AVX512VL-NEXT: vmovupd (%rdi), %xmm1 +; AVX512VL-NEXT: vmaxpd %xmm0, %xmm1, %xmm1 +; AVX512VL-NEXT: vcmpordpd %xmm0, %xmm0, %k1 +; AVX512VL-NEXT: vmovupd %xmm1, (%rdi) {%k1} +; AVX512VL-NEXT: retq + %b = load <2 x double>, ptr %ptr, align 8 + %m = call <2 x double> @llvm.maxnum.v2f64(<2 x double> %a, <2 x double> %b) + store <2 x double> %m, ptr %ptr, align 8 + ret void +} + +define void @minnum_v4f32_masked_store(<4 x float> %a, ptr %ptr) { +; AVX-LABEL: minnum_v4f32_masked_store: +; AVX: # %bb.0: +; AVX-NEXT: vmovups (%rdi), %xmm1 +; AVX-NEXT: vminps %xmm0, %xmm1, %xmm1 +; AVX-NEXT: vcmpordps %xmm0, %xmm0, %xmm0 +; AVX-NEXT: vmaskmovps %xmm1, %xmm0, (%rdi) +; AVX-NEXT: retq +; +; AVX512F-LABEL: minnum_v4f32_masked_store: +; AVX512F: # %bb.0: +; AVX512F-NEXT: vmovups (%rdi), %xmm1 +; AVX512F-NEXT: vminps %xmm0, %xmm1, %xmm1 +; AVX512F-NEXT: vcmpunordps %xmm0, %xmm0, %xmm0 +; AVX512F-NEXT: vptestnmd %zmm0, %zmm0, %k0 +; AVX512F-NEXT: kshiftlw $12, %k0, %k0 +; AVX512F-NEXT: kshiftrw $12, %k0, %k1 +; AVX512F-NEXT: vmovups %zmm1, (%rdi) {%k1} +; AVX512F-NEXT: vzeroupper +; AVX512F-NEXT: retq +; +; AVX512VL-LABEL: minnum_v4f32_masked_store: +; AVX512VL: # %bb.0: +; AVX512VL-NEXT: vmovups (%rdi), %xmm1 +; AVX512VL-NEXT: vminps %xmm0, %xmm1, %xmm1 +; AVX512VL-NEXT: vcmpordps %xmm0, %xmm0, %k1 +; AVX512VL-NEXT: vmovups %xmm1, (%rdi) {%k1} +; AVX512VL-NEXT: retq + %b = load <4 x float>, ptr %ptr, align 4 + %m = call <4 x float> @llvm.minnum.v4f32(<4 x float> %a, <4 x float> %b) + store <4 x float> %m, ptr %ptr, align 4 + ret void +} + +define void @minnum_v2f64_masked_store(<2 x double> %a, ptr %ptr) { +; AVX-LABEL: minnum_v2f64_masked_store: +; AVX: # %bb.0: +; AVX-NEXT: vmovupd (%rdi), %xmm1 +; AVX-NEXT: vminpd %xmm0, %xmm1, %xmm1 +; AVX-NEXT: vcmpordpd %xmm0, %xmm0, %xmm0 +; AVX-NEXT: vmaskmovpd %xmm1, %xmm0, (%rdi) +; AVX-NEXT: retq +; +; AVX512F-LABEL: minnum_v2f64_masked_store: +; AVX512F: # %bb.0: +; AVX512F-NEXT: vmovupd (%rdi), %xmm1 +; AVX512F-NEXT: vminpd %xmm0, %xmm1, %xmm1 +; AVX512F-NEXT: vcmpunordpd %xmm0, %xmm0, %xmm0 +; AVX512F-NEXT: vptestnmq %zmm0, %zmm0, %k0 +; AVX512F-NEXT: kshiftlw $14, %k0, %k0 +; AVX512F-NEXT: kshiftrw $14, %k0, %k1 +; AVX512F-NEXT: vmovupd %zmm1, (%rdi) {%k1} +; AVX512F-NEXT: vzeroupper +; AVX512F-NEXT: retq +; +; AVX512VL-LABEL: minnum_v2f64_masked_store: +; AVX512VL: # %bb.0: +; AVX512VL-NEXT: vmovupd (%rdi), %xmm1 +; AVX512VL-NEXT: vminpd %xmm0, %xmm1, %xmm1 +; AVX512VL-NEXT: vcmpordpd %xmm0, %xmm0, %k1 +; AVX512VL-NEXT: vmovupd %xmm1, (%rdi) {%k1} +; AVX512VL-NEXT: retq + %b = load <2 x double>, ptr %ptr, align 8 + %m = call <2 x double> @llvm.minnum.v2f64(<2 x double> %a, <2 x double> %b) + store <2 x double> %m, ptr %ptr, align 8 + ret void +} diff --git a/llvm/test/Transforms/LoopVectorize/X86/cost-any-of.ll b/llvm/test/Transforms/LoopVectorize/X86/cost-any-of.ll new file mode 100644 index 0000000000000..a03ae83a8d617 --- /dev/null +++ b/llvm/test/Transforms/LoopVectorize/X86/cost-any-of.ll @@ -0,0 +1,41 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals none --version 6 +; RUN: opt -passes=loop-vectorize -S %s | FileCheck %s + +target triple = "x86_64-unknown-linux-gnu" + +; Test case for https://github.com/llvm/llvm-project/issues/185867. +define void @fminnum_with_any_of_cost(ptr %p) #0 { +; CHECK-LABEL: define void @fminnum_with_any_of_cost( +; CHECK-SAME: ptr [[P:%.*]]) #[[ATTR0:[0-9]+]] { +; CHECK-NEXT: [[SCALAR_PH:.*]]: +; CHECK-NEXT: br label %[[LOOP:.*]] +; CHECK: [[LOOP]]: +; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, %[[SCALAR_PH]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ] +; CHECK-NEXT: [[RED:%.*]] = phi float [ 0.000000e+00, %[[SCALAR_PH]] ], [ [[MIN:%.*]], %[[LOOP]] ] +; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds float, ptr [[P]], i64 [[IV]] +; CHECK-NEXT: [[LDV:%.*]] = load float, ptr [[GEP]], align 4 +; CHECK-NEXT: [[MIN]] = tail call float @llvm.minnum.f32(float [[RED]], float [[LDV]]) +; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 1 +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[IV_NEXT]], 140 +; CHECK-NEXT: br i1 [[CMP]], label %[[EXIT:.*]], label %[[LOOP]] +; CHECK: [[EXIT]]: +; CHECK-NEXT: ret void +; +entry: + br label %loop + +loop: + %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] + %red = phi float [ 0.000000e+00, %entry ], [ %min, %loop ] + %gep = getelementptr inbounds float, ptr %p, i64 %iv + %ldv = load float, ptr %gep, align 4 + %min = tail call float @llvm.minnum.f32(float %red, float %ldv) + %iv.next = add i64 %iv, 1 + %cmp = icmp eq i64 %iv.next, 140 + br i1 %cmp, label %exit, label %loop + +exit: + ret void +} + +attributes #0 = { "target-cpu"="znver4" } diff --git a/llvm/utils/gn/secondary/llvm/version.gni b/llvm/utils/gn/secondary/llvm/version.gni index 22820f1de88aa..1b7c6951cc695 100644 --- a/llvm/utils/gn/secondary/llvm/version.gni +++ b/llvm/utils/gn/secondary/llvm/version.gni @@ -1,4 +1,4 @@ llvm_version_major = 22 llvm_version_minor = 1 -llvm_version_patch = 7 +llvm_version_patch = 8 llvm_version = "$llvm_version_major.$llvm_version_minor.$llvm_version_patch" diff --git a/llvm/utils/lit/lit/__init__.py b/llvm/utils/lit/lit/__init__.py index 5d26e351fd2e8..7dcd3b34547dc 100644 --- a/llvm/utils/lit/lit/__init__.py +++ b/llvm/utils/lit/lit/__init__.py @@ -2,7 +2,7 @@ __author__ = "Daniel Dunbar" __email__ = "daniel@minormatter.com" -__versioninfo__ = (22, 1, 7) +__versioninfo__ = (22, 1, 8) __version__ = ".".join(str(v) for v in __versioninfo__) + "dev" __all__ = [] diff --git a/llvm/utils/mlgo-utils/mlgo/__init__.py b/llvm/utils/mlgo-utils/mlgo/__init__.py index 3b4b668e5bdd1..198ab79a7e158 100644 --- a/llvm/utils/mlgo-utils/mlgo/__init__.py +++ b/llvm/utils/mlgo-utils/mlgo/__init__.py @@ -4,7 +4,7 @@ from datetime import timezone, datetime -__versioninfo__ = (22, 1, 7) +__versioninfo__ = (22, 1, 8) __version__ = ( ".".join(str(v) for v in __versioninfo__) + "dev"