From 81c69e1404010ede8e16d7c975bb6e5bb17cb52c Mon Sep 17 00:00:00 2001 From: Douglas Yung Date: Tue, 19 May 2026 09:20:09 +0000 Subject: [PATCH 01/16] Bump version to 22.1.7 --- cmake/Modules/LLVMVersion.cmake | 2 +- libcxx/include/__config | 2 +- llvm/utils/gn/secondary/llvm/version.gni | 2 +- llvm/utils/lit/lit/__init__.py | 2 +- llvm/utils/mlgo-utils/mlgo/__init__.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cmake/Modules/LLVMVersion.cmake b/cmake/Modules/LLVMVersion.cmake index a9e64b9e17818..feb48f124e6ee 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 6) + set(LLVM_VERSION_PATCH 7) endif() if(NOT DEFINED LLVM_VERSION_SUFFIX) set(LLVM_VERSION_SUFFIX) diff --git a/libcxx/include/__config b/libcxx/include/__config index da2d40589341d..3a34eea8edc1e 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 220106 +# define _LIBCPP_VERSION 220107 # define _LIBCPP_CONCAT_IMPL(_X, _Y) _X##_Y # define _LIBCPP_CONCAT(_X, _Y) _LIBCPP_CONCAT_IMPL(_X, _Y) diff --git a/llvm/utils/gn/secondary/llvm/version.gni b/llvm/utils/gn/secondary/llvm/version.gni index f5c7d1c580ca5..22820f1de88aa 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 = 6 +llvm_version_patch = 7 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 b591b0a238234..5d26e351fd2e8 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, 6) +__versioninfo__ = (22, 1, 7) __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 cc46823453295..3b4b668e5bdd1 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, 6) +__versioninfo__ = (22, 1, 7) __version__ = ( ".".join(str(v) for v in __versioninfo__) + "dev" From e624f1204282bef96279d07a03bf9ec27056ff5e Mon Sep 17 00:00:00 2001 From: Weibo He Date: Wed, 25 Mar 2026 10:37:31 +0800 Subject: [PATCH 02/16] [CoroSplit] Never collect allocas used by catchpad into frame (#186728) Windows EH requires exception objects allocated on stack. But there is no reliable way to identify them. CoroSplit employs a best-effort algorithm to determine whether allocas persist on the stack or the frame, which may result in miscompilation when Windows exceptions are used. This patch proposes that we treat allocas used by catchpad as exception objects and never place them on the frame. A verifier check is added to enforce that operands of catchpad are either constants or allocas. Close #143235 Close #153949 Close #182584 --- llvm/docs/Coroutines.rst | 3 + llvm/lib/Transforms/Coroutines/SpillUtils.cpp | 7 ++ .../Transforms/Coroutines/coro-alloca-10.ll | 66 +++++++++++++++++++ 3 files changed, 76 insertions(+) create mode 100644 llvm/test/Transforms/Coroutines/coro-alloca-10.ll diff --git a/llvm/docs/Coroutines.rst b/llvm/docs/Coroutines.rst index 0e6b49c84acee..9fa403e68e13b 100644 --- a/llvm/docs/Coroutines.rst +++ b/llvm/docs/Coroutines.rst @@ -2252,4 +2252,7 @@ Areas Requiring Attention #. Make required changes to make sure that coroutine optimizations work with LTO. +#. In Windows EH, exception objects must be allocated on the stack (see :ref:wineh for details). + We identify an exception object as an alloca that has `catchpad` users. + #. More tests, more tests, more tests diff --git a/llvm/lib/Transforms/Coroutines/SpillUtils.cpp b/llvm/lib/Transforms/Coroutines/SpillUtils.cpp index 81fe0c9acd413..05abccf0f9a97 100644 --- a/llvm/lib/Transforms/Coroutines/SpillUtils.cpp +++ b/llvm/lib/Transforms/Coroutines/SpillUtils.cpp @@ -180,6 +180,13 @@ struct AllocaUseVisitor : PtrUseVisitor { handleAlias(I); } + void visitCatchPadInst(CatchPadInst &I) { + // Windows EH requires exception objects allocated on the stack, + // shortcut the traversal and keep it on stack. + ShouldLiveOnFrame = false; + Base::Worklist.clear(); + } + void visitInsertElementInst(InsertElementInst &I) { enqueueUsers(I); handleAlias(I); diff --git a/llvm/test/Transforms/Coroutines/coro-alloca-10.ll b/llvm/test/Transforms/Coroutines/coro-alloca-10.ll new file mode 100644 index 0000000000000..a5fb67d59edd1 --- /dev/null +++ b/llvm/test/Transforms/Coroutines/coro-alloca-10.ll @@ -0,0 +1,66 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 +; Test that catchpad is specially handled. Do not collect exception object into coroutine frame. +; RUN: opt < %s -passes='coro-split,simplifycfg,early-cse' -S | FileCheck %s + +define void @fn() presplitcoroutine personality i32 0 { +; CHECK-LABEL: define void @fn() personality i32 0 { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[EXCEPTION_OBJ_RELOAD_ADDR:%.*]] = alloca ptr, align 8 +; CHECK-NEXT: [[ID:%.*]] = call token @llvm.coro.id(i32 16, ptr null, ptr null, ptr @fn.resumers) +; CHECK-NEXT: [[MEM:%.*]] = call noalias nonnull ptr @malloc(i64 24) +; CHECK-NEXT: [[HDL:%.*]] = call noalias nonnull ptr @llvm.coro.begin(token [[ID]], ptr [[MEM]]) +; CHECK-NEXT: store ptr @fn.resume, ptr [[HDL]], align 8 +; CHECK-NEXT: [[DESTROY_ADDR:%.*]] = getelementptr inbounds nuw [[FN_FRAME:%.*]], ptr [[HDL]], i32 0, i32 1 +; CHECK-NEXT: store ptr @fn.destroy, ptr [[DESTROY_ADDR]], align 8 +; CHECK-NEXT: store ptr null, ptr [[EXCEPTION_OBJ_RELOAD_ADDR]], align 8 +; CHECK-NEXT: [[INDEX_ADDR4:%.*]] = getelementptr inbounds nuw [[FN_FRAME]], ptr [[HDL]], i32 0, i32 2 +; CHECK-NEXT: store i1 false, ptr [[INDEX_ADDR4]], align 1 +; CHECK-NEXT: ret void +; +entry: + %exception.obj = alloca ptr, align 8 + %id = call token @llvm.coro.id(i32 16, ptr null, ptr null, ptr null) + %size = call i64 @llvm.coro.size.i64() + %mem = call noalias nonnull ptr @malloc(i64 %size) + %hdl = call ptr @llvm.coro.begin(token %id, ptr %mem) + store ptr null, ptr %exception.obj, align 8 + br label %while + +while: + %save = call token @llvm.coro.save(ptr null) + %suspend = call i8 @llvm.coro.suspend(token %save, i1 false) + switch i8 %suspend, label %coro.ret [ + i8 0, label %await.ready + ] + +await.ready: + invoke void @throw() + to label %unreachable unwind label %catch.dispatch + +catch.dispatch: + %switch = catchswitch within none [label %catch] unwind label %ehcleanup + +catch: + %pad = catchpad within %switch [ptr null, i32 8, ptr %exception.obj] + invoke void @use(ptr %exception.obj) [ "funclet"(token %pad) ] + to label %catch.ret unwind label %ehcleanup + +catch.ret: + catchret from %pad to label %while + +ehcleanup: + %cleanup = cleanuppad within none [] + call void @llvm.coro.end(ptr null, i1 true, token none) [ "funclet"(token %cleanup) ] + cleanupret from %cleanup unwind to caller + +coro.ret: + call void @llvm.coro.end(ptr null, i1 false, token none) + ret void + +unreachable: + unreachable +} + +declare ptr @malloc(i64) +declare void @throw() +declare void @use(ptr) From 823afe046164918015c2907ca840b4ff45b80343 Mon Sep 17 00:00:00 2001 From: Chuanqi Xu Date: Fri, 8 May 2026 11:48:54 +0800 Subject: [PATCH 03/16] Reland [C++20] [Modules] Don't profiling the callee of CXXFoldExpr (#190732) (#195983) Close https://github.com/llvm/llvm-project/issues/190333 For the test case, the root cause of the problem is, the compiler thought the declaration of `operator &&` in consumer.cpp may change the meaning of '&&' in the requrie clause of `F::operator()`. But it doesn't make sense. Here we skip profiling the callee to solve the problem. Note that we've already record the kind of the operator. So '&&' and '||' won't be confused. --- See the discussion in https://github.com/llvm/llvm-project/pull/194283 For the new found pattern that we may have other binary operator (e.g., operator +) in the require clause, e.g., ```C++ template requires requires(T t, U u) { t + u; } void operator()(T, U) {} ``` This is a new problem and we need to solve it in other PR. (cherry picked from commit 2751c7ed066d08d3c801670e6c5629a39ddfe90e) --- clang/lib/AST/StmtProfile.cpp | 21 +++++- clang/test/Modules/polluted-operator.cppm | 79 ----------------------- clang/test/SemaCXX/GH190333.cpp | 6 ++ 3 files changed, 26 insertions(+), 80 deletions(-) delete mode 100644 clang/test/Modules/polluted-operator.cppm create mode 100644 clang/test/SemaCXX/GH190333.cpp diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index a626d043676e0..03b5563854f83 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -2369,7 +2369,26 @@ void StmtProfiler::VisitMaterializeTemporaryExpr( } void StmtProfiler::VisitCXXFoldExpr(const CXXFoldExpr *S) { - VisitExpr(S); + VisitStmtNoChildren(S); + // The callee sub-expression is not part of how the expression is written, + // so it's not added to the profile. + // + // Example: + // template requires ((sizeof(T) > 0) && ...) void f() {} + // class A; + // void operator&&(A, A); + // template requires ((sizeof(T) > 0) && ...) void f() {} + // + // Both definitions have identically written fold expressions, but semantic + // analysis adds the overloaded operator to the second one. + if (S->getLHS()) + Visit(S->getLHS()); + else + ID.AddInteger(0); + if (S->getRHS()) + Visit(S->getRHS()); + else + ID.AddInteger(0); ID.AddInteger(S->getOperator()); } diff --git a/clang/test/Modules/polluted-operator.cppm b/clang/test/Modules/polluted-operator.cppm deleted file mode 100644 index 45cc5e37d6a64..0000000000000 --- a/clang/test/Modules/polluted-operator.cppm +++ /dev/null @@ -1,79 +0,0 @@ -// RUN: rm -rf %t -// RUN: mkdir -p %t -// RUN: split-file %s %t -// -// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/a.cppm -o %t/a.pcm -// RUN: %clang_cc1 -std=c++20 %t/b.cppm -fprebuilt-module-path=%t -emit-module-interface -o %t/b.pcm -verify -// -// Testing the behavior of `-fskip-odr-check-in-gmf` -// RUN: %clang_cc1 -std=c++20 -fskip-odr-check-in-gmf -emit-module-interface %t/a.cppm -o \ -// RUN: %t/a.pcm -// RUN: %clang_cc1 -std=c++20 -fskip-odr-check-in-gmf %t/b.cppm -fprebuilt-module-path=%t \ -// RUN: -emit-module-interface -DSKIP_ODR_CHECK_IN_GMF -o %t/b.pcm -verify - -// RUN: %clang_cc1 -std=c++20 -emit-reduced-module-interface %t/a.cppm -o %t/a.pcm -// RUN: %clang_cc1 -std=c++20 %t/b.cppm -fprebuilt-module-path=%t -emit-reduced-module-interface \ -// RUN: -o %t/b.pcm -verify -DREDUCED - -//--- foo.h - -namespace std -{ - template - void operator &&(_Dom1 __v, _Dom1 __w) - { - return; - } -} - -//--- bar.h -namespace std -{ - template - struct _Traits - { - static constexpr bool _S_copy_ctor = - (__is_trivial(_Types) && ...); - }; - - template - struct variant - { - void - swap(variant& __rhs) - noexcept((__is_trivial(_Types) && ...)) - { - } - }; -} - -//--- a.cppm -module; -// The operator&& defined in 'foo.h' will pollute the -// expression '__is_trivial(_Types) && ...' in bar.h -#include "foo.h" -#include "bar.h" -export module a; -export namespace std { - using std::variant; - using std::_Traits; - using std::operator&&; -} - -//--- b.cppm -module; -#include "bar.h" -export module b; -import a; -export namespace std { - using std::variant; - using std::_Traits; - using std::operator&&; -} - -#ifdef SKIP_ODR_CHECK_IN_GMF -// expected-no-diagnostics -#else -// expected-error@* {{has different definitions in different modules; first difference is defined here found data member '_S_copy_ctor' with an initializer}} -// expected-note@* {{but in 'a.' found data member '_S_copy_ctor' with a different initializer}} -#endif diff --git a/clang/test/SemaCXX/GH190333.cpp b/clang/test/SemaCXX/GH190333.cpp new file mode 100644 index 0000000000000..2c43eb7a16d8a --- /dev/null +++ b/clang/test/SemaCXX/GH190333.cpp @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s + +template requires ((sizeof(T) > 0) && ...) void f() {} // expected-note{{previous definition is here}} +class A; +void operator&&(A, A); +template requires ((sizeof(T) > 0) && ...) void f() {} // expected-error{{redefinition of 'f'}} From 4d5dffb59420df29cc3b419a7fc90834aed7f7a9 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Sat, 16 May 2026 14:38:18 -0700 Subject: [PATCH 04/16] [ELF] Initialize Symbol fields in the constructor instead of via memset (#198129) `initSectionsAndLocalSyms` and `makeDefined` memset the storage to zero and then placement-new a Symbol-derived object into it. Placement new begins a new object's lifetime. The standard does not seem to guarantee the memset bytes carry into members the constructor leaves uninitialized. lld built by GCC 16 can make Valgrind report reads of Symbol::flags (via getSymSectionIndex during finalizeSections) as uses of uninitialized values (ClangBuiltLinux/linux#2162). This patch reinstates the per-field initialization that commit 778742760534 ("[ELF] Avoid redundant assignment to Symbol fields. NFC") had replaced with a bulk memset. (cherry picked from commit 905a88b923433eb8cd83677ea55bee82eb9ba498) --- lld/ELF/InputFiles.cpp | 2 -- lld/ELF/Symbols.h | 20 ++++++++++++-------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index 176f6937a8d66..7ba2be5d1608f 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -1261,7 +1261,6 @@ void ObjFile::initSectionsAndLocalSyms(bool ignoreComdats) { if (!firstGlobal) return; SymbolUnion *locals = makeThreadLocalN(firstGlobal); - memset(locals, 0, sizeof(SymbolUnion) * firstGlobal); ArrayRef eSyms = this->getELFSyms(); for (size_t i = 0, end = firstGlobal; i != end; ++i) { @@ -1297,7 +1296,6 @@ void ObjFile::initSectionsAndLocalSyms(bool ignoreComdats) { else new (symbols[i]) Defined(ctx, this, name, STB_LOCAL, eSym.st_other, type, eSym.st_value, eSym.st_size, sec); - symbols[i]->partition = 1; symbols[i]->isUsedInRegularObj = true; } } diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h index 034c8734addb8..23994ccea1ef0 100644 --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -102,7 +102,7 @@ class Symbol { uint8_t symbolKind; // The partition whose dynamic symbol table contains this symbol's definition. - uint8_t partition; + uint8_t partition = 1; // True if this symbol is preemptible at load time. // @@ -242,8 +242,13 @@ class Symbol { Symbol(Kind k, InputFile *file, StringRef name, uint8_t binding, uint8_t stOther, uint8_t type) : file(file), nameData(name.data()), nameSize(name.size()), type(type), - binding(binding), stOther(stOther), symbolKind(k), ltoCanOmit(false), - archSpecificBit(false) {} + 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), + inDynamicList(false), referenced(false), referencedAfterWrap(false) {} void overwrite(Symbol &sym, Kind k) const { if (sym.traced) @@ -302,12 +307,12 @@ class Symbol { // Temporary flags used to communicate which symbol entries need PLT and GOT // entries during postScanRelocations(); - std::atomic flags; + std::atomic flags = 0; // A ctx.symAux index used to access GOT/PLT entry indexes. This is allocated // in postScanRelocations(). - uint32_t auxIdx; - uint32_t dynsymIndex; + uint32_t auxIdx = 0; + uint32_t dynsymIndex = 0; // If `file` is SharedFile (for SharedSymbol or copy-relocated Defined), this // represents the Verdef index within the input DSO, which will be converted @@ -315,7 +320,7 @@ class Symbol { // index (VER_NDX_LOCAL, VER_NDX_GLOBAL, or a named version). // VER_NDX_LOCAL indicates a defined symbol that has been localized by a // version script's local: directive or --exclude-libs. - uint16_t versionId; + uint16_t versionId = 0; LLVM_PREFERRED_TYPE(bool) uint8_t versionScriptAssigned : 1; @@ -526,7 +531,6 @@ union SymbolUnion { template Defined *makeDefined(T &&...args) { auto *sym = getSpecificAllocSingleton().Allocate(); - memset(sym, 0, sizeof(Symbol)); auto &s = *new (reinterpret_cast(sym)) Defined(std::forward(args)...); return &s; } From 6e5effc4990b9cf475180a46b8d08c7db391cd83 Mon Sep 17 00:00:00 2001 From: hev Date: Wed, 20 May 2026 09:09:52 +0800 Subject: [PATCH 05/16] [LoongArch] Revert "Add patterns to support vector type average instructions generation" (#198306) Fixes #198254 --- .../LoongArch/LoongArchLASXInstrInfo.td | 18 - .../Target/LoongArch/LoongArchLSXInstrInfo.td | 30 -- .../LoongArch/lasx/ir-instruction/avg.ll | 321 ------------------ .../LoongArch/lsx/ir-instruction/avg.ll | 321 ------------------ 4 files changed, 690 deletions(-) delete mode 100644 llvm/test/CodeGen/LoongArch/lasx/ir-instruction/avg.ll delete mode 100644 llvm/test/CodeGen/LoongArch/lsx/ir-instruction/avg.ll diff --git a/llvm/lib/Target/LoongArch/LoongArchLASXInstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchLASXInstrInfo.td index fa4b720e7ba98..d539781dc63eb 100644 --- a/llvm/lib/Target/LoongArch/LoongArchLASXInstrInfo.td +++ b/llvm/lib/Target/LoongArch/LoongArchLASXInstrInfo.td @@ -2037,24 +2037,6 @@ def : Pat<(v4i32(fp_to_uint v4f64:$vj)), (XVFTINTRZ_LU_D v4f64:$vj)), sub_128)>; -// XVAVG_{B/H/W/D/BU/HU/WU/DU}, XVAVGR_{B/H/W/D/BU/HU/WU/DU} -defm : VAvgPat; -defm : VAvgPat; -defm : VAvgPat; -defm : VAvgPat; -defm : VAvgPat; -defm : VAvgPat; -defm : VAvgPat; -defm : VAvgPat; -defm : VAvgrPat; -defm : VAvgrPat; -defm : VAvgrPat; -defm : VAvgrPat; -defm : VAvgrPat; -defm : VAvgrPat; -defm : VAvgrPat; -defm : VAvgrPat; - // abs def : Pat<(abs v32i8:$xj), (XVSIGNCOV_B v32i8:$xj, v32i8:$xj)>; def : Pat<(abs v16i16:$xj), (XVSIGNCOV_H v16i16:$xj, v16i16:$xj)>; diff --git a/llvm/lib/Target/LoongArch/LoongArchLSXInstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchLSXInstrInfo.td index da7b6e833c996..1336e751ed355 100644 --- a/llvm/lib/Target/LoongArch/LoongArchLSXInstrInfo.td +++ b/llvm/lib/Target/LoongArch/LoongArchLSXInstrInfo.td @@ -1530,18 +1530,6 @@ multiclass InsertExtractPatV2 { } } -multiclass VAvgPat { - def : Pat<(OpNode (vt (add vt:$vj, vt:$vk)), (vt (vsplat_imm_eq_1))), - (!cast(Inst) vt:$vj, vt:$vk)>; -} - -multiclass VAvgrPat { - def : Pat<(OpNode (vt (add (vt (add vt:$vj, vt:$vk)), - (vt (vsplat_imm_eq_1)))), - (vt (vsplat_imm_eq_1))), - (!cast(Inst) vt:$vj, vt:$vk)>; -} - let Predicates = [HasExtLSX] in { // VADD_{B/H/W/D} @@ -2187,24 +2175,6 @@ def : Pat<(f32 f32imm_vldi:$in), def : Pat<(f64 f64imm_vldi:$in), (f64 (EXTRACT_SUBREG (VLDI (to_f64imm_vldi f64imm_vldi:$in)), sub_64))>; -// VAVG_{B/H/W/D/BU/HU/WU/DU}, VAVGR_{B/H/W/D/BU/HU/WU/DU} -defm : VAvgPat; -defm : VAvgPat; -defm : VAvgPat; -defm : VAvgPat; -defm : VAvgPat; -defm : VAvgPat; -defm : VAvgPat; -defm : VAvgPat; -defm : VAvgrPat; -defm : VAvgrPat; -defm : VAvgrPat; -defm : VAvgrPat; -defm : VAvgrPat; -defm : VAvgrPat; -defm : VAvgrPat; -defm : VAvgrPat; - // abs def : Pat<(abs v16i8:$vj), (VSIGNCOV_B v16i8:$vj, v16i8:$vj)>; def : Pat<(abs v8i16:$vj), (VSIGNCOV_H v8i16:$vj, v8i16:$vj)>; diff --git a/llvm/test/CodeGen/LoongArch/lasx/ir-instruction/avg.ll b/llvm/test/CodeGen/LoongArch/lasx/ir-instruction/avg.ll deleted file mode 100644 index 5c5c19935080b..0000000000000 --- a/llvm/test/CodeGen/LoongArch/lasx/ir-instruction/avg.ll +++ /dev/null @@ -1,321 +0,0 @@ -; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6 -; RUN: llc --mtriple=loongarch32 --mattr=+32s,+lasx < %s | FileCheck %s --check-prefixes=CHECK,LA32 -; RUN: llc --mtriple=loongarch64 --mattr=+lasx < %s | FileCheck %s --check-prefixes=CHECK,LA64 - -define void @xvavg_b(ptr %res, ptr %a, ptr %b) nounwind { -; CHECK-LABEL: xvavg_b: -; CHECK: # %bb.0: # %entry -; CHECK-NEXT: xvld $xr0, $a1, 0 -; CHECK-NEXT: xvld $xr1, $a2, 0 -; CHECK-NEXT: xvavg.b $xr0, $xr0, $xr1 -; CHECK-NEXT: xvst $xr0, $a0, 0 -; CHECK-NEXT: ret -entry: - %va = load <32 x i8>, ptr %a - %vb = load <32 x i8>, ptr %b - %add = add <32 x i8> %va, %vb - %shr = ashr <32 x i8> %add, - store <32 x i8> %shr, ptr %res - ret void -} - -define void @xvavg_h(ptr %res, ptr %a, ptr %b) nounwind { -; CHECK-LABEL: xvavg_h: -; CHECK: # %bb.0: # %entry -; CHECK-NEXT: xvld $xr0, $a1, 0 -; CHECK-NEXT: xvld $xr1, $a2, 0 -; CHECK-NEXT: xvavg.h $xr0, $xr0, $xr1 -; CHECK-NEXT: xvst $xr0, $a0, 0 -; CHECK-NEXT: ret -entry: - %va = load <16 x i16>, ptr %a - %vb = load <16 x i16>, ptr %b - %add = add <16 x i16> %va, %vb - %shr = ashr <16 x i16> %add, - store <16 x i16> %shr, ptr %res - ret void -} - -define void @xvavg_w(ptr %res, ptr %a, ptr %b) nounwind { -; CHECK-LABEL: xvavg_w: -; CHECK: # %bb.0: # %entry -; CHECK-NEXT: xvld $xr0, $a1, 0 -; CHECK-NEXT: xvld $xr1, $a2, 0 -; CHECK-NEXT: xvavg.w $xr0, $xr0, $xr1 -; CHECK-NEXT: xvst $xr0, $a0, 0 -; CHECK-NEXT: ret -entry: - %va = load <8 x i32>, ptr %a - %vb = load <8 x i32>, ptr %b - %add = add <8 x i32> %va, %vb - %shr = ashr <8 x i32> %add, - store <8 x i32> %shr, ptr %res - ret void -} - -define void @xvavg_d(ptr %res, ptr %a, ptr %b) nounwind { -; LA32-LABEL: xvavg_d: -; LA32: # %bb.0: # %entry -; LA32-NEXT: xvld $xr0, $a1, 0 -; LA32-NEXT: xvld $xr1, $a2, 0 -; LA32-NEXT: xvadd.d $xr0, $xr0, $xr1 -; LA32-NEXT: xvsrai.d $xr0, $xr0, 1 -; LA32-NEXT: xvst $xr0, $a0, 0 -; LA32-NEXT: ret -; -; LA64-LABEL: xvavg_d: -; LA64: # %bb.0: # %entry -; LA64-NEXT: xvld $xr0, $a1, 0 -; LA64-NEXT: xvld $xr1, $a2, 0 -; LA64-NEXT: xvavg.d $xr0, $xr0, $xr1 -; LA64-NEXT: xvst $xr0, $a0, 0 -; LA64-NEXT: ret -entry: - %va = load <4 x i64>, ptr %a - %vb = load <4 x i64>, ptr %b - %add = add <4 x i64> %va, %vb - %shr = ashr <4 x i64> %add, - store <4 x i64> %shr, ptr %res - ret void -} - -define void @xvavg_bu(ptr %res, ptr %a, ptr %b) nounwind { -; CHECK-LABEL: xvavg_bu: -; CHECK: # %bb.0: # %entry -; CHECK-NEXT: xvld $xr0, $a1, 0 -; CHECK-NEXT: xvld $xr1, $a2, 0 -; CHECK-NEXT: xvavg.bu $xr0, $xr0, $xr1 -; CHECK-NEXT: xvst $xr0, $a0, 0 -; CHECK-NEXT: ret -entry: - %va = load <32 x i8>, ptr %a - %vb = load <32 x i8>, ptr %b - %add = add <32 x i8> %va, %vb - %shr = lshr <32 x i8> %add, - store <32 x i8> %shr, ptr %res - ret void -} - -define void @xvavg_hu(ptr %res, ptr %a, ptr %b) nounwind { -; CHECK-LABEL: xvavg_hu: -; CHECK: # %bb.0: # %entry -; CHECK-NEXT: xvld $xr0, $a1, 0 -; CHECK-NEXT: xvld $xr1, $a2, 0 -; CHECK-NEXT: xvavg.hu $xr0, $xr0, $xr1 -; CHECK-NEXT: xvst $xr0, $a0, 0 -; CHECK-NEXT: ret -entry: - %va = load <16 x i16>, ptr %a - %vb = load <16 x i16>, ptr %b - %add = add <16 x i16> %va, %vb - %shr = lshr <16 x i16> %add, - store <16 x i16> %shr, ptr %res - ret void -} - -define void @xvavg_wu(ptr %res, ptr %a, ptr %b) nounwind { -; CHECK-LABEL: xvavg_wu: -; CHECK: # %bb.0: # %entry -; CHECK-NEXT: xvld $xr0, $a1, 0 -; CHECK-NEXT: xvld $xr1, $a2, 0 -; CHECK-NEXT: xvavg.wu $xr0, $xr0, $xr1 -; CHECK-NEXT: xvst $xr0, $a0, 0 -; CHECK-NEXT: ret -entry: - %va = load <8 x i32>, ptr %a - %vb = load <8 x i32>, ptr %b - %add = add <8 x i32> %va, %vb - %shr = lshr <8 x i32> %add, - store <8 x i32> %shr, ptr %res - ret void -} - -define void @xvavg_du(ptr %res, ptr %a, ptr %b) nounwind { -; LA32-LABEL: xvavg_du: -; LA32: # %bb.0: # %entry -; LA32-NEXT: xvld $xr0, $a1, 0 -; LA32-NEXT: xvld $xr1, $a2, 0 -; LA32-NEXT: xvadd.d $xr0, $xr0, $xr1 -; LA32-NEXT: xvsrli.d $xr0, $xr0, 1 -; LA32-NEXT: xvst $xr0, $a0, 0 -; LA32-NEXT: ret -; -; LA64-LABEL: xvavg_du: -; LA64: # %bb.0: # %entry -; LA64-NEXT: xvld $xr0, $a1, 0 -; LA64-NEXT: xvld $xr1, $a2, 0 -; LA64-NEXT: xvavg.du $xr0, $xr0, $xr1 -; LA64-NEXT: xvst $xr0, $a0, 0 -; LA64-NEXT: ret -entry: - %va = load <4 x i64>, ptr %a - %vb = load <4 x i64>, ptr %b - %add = add <4 x i64> %va, %vb - %shr = lshr <4 x i64> %add, - store <4 x i64> %shr, ptr %res - ret void -} - -define void @xvavgr_b(ptr %res, ptr %a, ptr %b) nounwind { -; CHECK-LABEL: xvavgr_b: -; CHECK: # %bb.0: # %entry -; CHECK-NEXT: xvld $xr0, $a1, 0 -; CHECK-NEXT: xvld $xr1, $a2, 0 -; CHECK-NEXT: xvavgr.b $xr0, $xr0, $xr1 -; CHECK-NEXT: xvst $xr0, $a0, 0 -; CHECK-NEXT: ret -entry: - %va = load <32 x i8>, ptr %a - %vb = load <32 x i8>, ptr %b - %add = add <32 x i8> %va, %vb - %add1 = add <32 x i8> %add, - %shr = ashr <32 x i8> %add1, - store <32 x i8> %shr, ptr %res - ret void -} - -define void @xvavgr_h(ptr %res, ptr %a, ptr %b) nounwind { -; CHECK-LABEL: xvavgr_h: -; CHECK: # %bb.0: # %entry -; CHECK-NEXT: xvld $xr0, $a1, 0 -; CHECK-NEXT: xvld $xr1, $a2, 0 -; CHECK-NEXT: xvavgr.h $xr0, $xr0, $xr1 -; CHECK-NEXT: xvst $xr0, $a0, 0 -; CHECK-NEXT: ret -entry: - %va = load <16 x i16>, ptr %a - %vb = load <16 x i16>, ptr %b - %add = add <16 x i16> %va, %vb - %add1 = add <16 x i16> %add, - %shr = ashr <16 x i16> %add1, - store <16 x i16> %shr, ptr %res - ret void -} - -define void @xvavgr_w(ptr %res, ptr %a, ptr %b) nounwind { -; CHECK-LABEL: xvavgr_w: -; CHECK: # %bb.0: # %entry -; CHECK-NEXT: xvld $xr0, $a1, 0 -; CHECK-NEXT: xvld $xr1, $a2, 0 -; CHECK-NEXT: xvavgr.w $xr0, $xr0, $xr1 -; CHECK-NEXT: xvst $xr0, $a0, 0 -; CHECK-NEXT: ret -entry: - %va = load <8 x i32>, ptr %a - %vb = load <8 x i32>, ptr %b - %add = add <8 x i32> %va, %vb - %add1 = add <8 x i32> %add, - %shr = ashr <8 x i32> %add1, - store <8 x i32> %shr, ptr %res - ret void -} - -define void @xvavgr_d(ptr %res, ptr %a, ptr %b) nounwind { -; LA32-LABEL: xvavgr_d: -; LA32: # %bb.0: # %entry -; LA32-NEXT: xvld $xr0, $a1, 0 -; LA32-NEXT: xvld $xr1, $a2, 0 -; LA32-NEXT: xvadd.d $xr0, $xr0, $xr1 -; LA32-NEXT: xvaddi.du $xr0, $xr0, 1 -; LA32-NEXT: xvsrai.d $xr0, $xr0, 1 -; LA32-NEXT: xvst $xr0, $a0, 0 -; LA32-NEXT: ret -; -; LA64-LABEL: xvavgr_d: -; LA64: # %bb.0: # %entry -; LA64-NEXT: xvld $xr0, $a1, 0 -; LA64-NEXT: xvld $xr1, $a2, 0 -; LA64-NEXT: xvavgr.d $xr0, $xr0, $xr1 -; LA64-NEXT: xvst $xr0, $a0, 0 -; LA64-NEXT: ret -entry: - %va = load <4 x i64>, ptr %a - %vb = load <4 x i64>, ptr %b - %add = add <4 x i64> %va, %vb - %add1 = add <4 x i64> %add, - %shr = ashr <4 x i64> %add1, - store <4 x i64> %shr, ptr %res - ret void -} - -define void @xvavgr_bu(ptr %res, ptr %a, ptr %b) nounwind { -; CHECK-LABEL: xvavgr_bu: -; CHECK: # %bb.0: # %entry -; CHECK-NEXT: xvld $xr0, $a1, 0 -; CHECK-NEXT: xvld $xr1, $a2, 0 -; CHECK-NEXT: xvavgr.bu $xr0, $xr0, $xr1 -; CHECK-NEXT: xvst $xr0, $a0, 0 -; CHECK-NEXT: ret -entry: - %va = load <32 x i8>, ptr %a - %vb = load <32 x i8>, ptr %b - %add = add <32 x i8> %va, %vb - %add1 = add <32 x i8> %add, - %shr = lshr <32 x i8> %add1, - store <32 x i8> %shr, ptr %res - ret void -} - -define void @xvavgr_hu(ptr %res, ptr %a, ptr %b) nounwind { -; CHECK-LABEL: xvavgr_hu: -; CHECK: # %bb.0: # %entry -; CHECK-NEXT: xvld $xr0, $a1, 0 -; CHECK-NEXT: xvld $xr1, $a2, 0 -; CHECK-NEXT: xvavgr.hu $xr0, $xr0, $xr1 -; CHECK-NEXT: xvst $xr0, $a0, 0 -; CHECK-NEXT: ret -entry: - %va = load <16 x i16>, ptr %a - %vb = load <16 x i16>, ptr %b - %add = add <16 x i16> %va, %vb - %add1 = add <16 x i16> %add, - %shr = lshr <16 x i16> %add1, - store <16 x i16> %shr, ptr %res - ret void -} - -define void @xvavgr_wu(ptr %res, ptr %a, ptr %b) nounwind { -; CHECK-LABEL: xvavgr_wu: -; CHECK: # %bb.0: # %entry -; CHECK-NEXT: xvld $xr0, $a1, 0 -; CHECK-NEXT: xvld $xr1, $a2, 0 -; CHECK-NEXT: xvavgr.wu $xr0, $xr0, $xr1 -; CHECK-NEXT: xvst $xr0, $a0, 0 -; CHECK-NEXT: ret -entry: - %va = load <8 x i32>, ptr %a - %vb = load <8 x i32>, ptr %b - %add = add <8 x i32> %va, %vb - %add1 = add <8 x i32> %add, - %shr = lshr <8 x i32> %add1, - store <8 x i32> %shr, ptr %res - ret void -} - -define void @xvavgr_du(ptr %res, ptr %a, ptr %b) nounwind { -; LA32-LABEL: xvavgr_du: -; LA32: # %bb.0: # %entry -; LA32-NEXT: xvld $xr0, $a1, 0 -; LA32-NEXT: xvld $xr1, $a2, 0 -; LA32-NEXT: xvadd.d $xr0, $xr0, $xr1 -; LA32-NEXT: xvaddi.du $xr0, $xr0, 1 -; LA32-NEXT: xvsrli.d $xr0, $xr0, 1 -; LA32-NEXT: xvst $xr0, $a0, 0 -; LA32-NEXT: ret -; -; LA64-LABEL: xvavgr_du: -; LA64: # %bb.0: # %entry -; LA64-NEXT: xvld $xr0, $a1, 0 -; LA64-NEXT: xvld $xr1, $a2, 0 -; LA64-NEXT: xvavgr.du $xr0, $xr0, $xr1 -; LA64-NEXT: xvst $xr0, $a0, 0 -; LA64-NEXT: ret -entry: - %va = load <4 x i64>, ptr %a - %vb = load <4 x i64>, ptr %b - %add = add <4 x i64> %va, %vb - %add1 = add <4 x i64> %add, - %shr = lshr <4 x i64> %add1, - store <4 x i64> %shr, ptr %res - ret void -} diff --git a/llvm/test/CodeGen/LoongArch/lsx/ir-instruction/avg.ll b/llvm/test/CodeGen/LoongArch/lsx/ir-instruction/avg.ll deleted file mode 100644 index 334af22edee59..0000000000000 --- a/llvm/test/CodeGen/LoongArch/lsx/ir-instruction/avg.ll +++ /dev/null @@ -1,321 +0,0 @@ -; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6 -; RUN: llc --mtriple=loongarch32 --mattr=+32s,+lsx < %s | FileCheck %s --check-prefixes=CHECK,LA32 -; RUN: llc --mtriple=loongarch64 --mattr=+lsx < %s | FileCheck %s --check-prefixes=CHECK,LA64 - -define void @vavg_b(ptr %res, ptr %a, ptr %b) nounwind { -; CHECK-LABEL: vavg_b: -; CHECK: # %bb.0: # %entry -; CHECK-NEXT: vld $vr0, $a1, 0 -; CHECK-NEXT: vld $vr1, $a2, 0 -; CHECK-NEXT: vavg.b $vr0, $vr0, $vr1 -; CHECK-NEXT: vst $vr0, $a0, 0 -; CHECK-NEXT: ret -entry: - %va = load <16 x i8>, ptr %a - %vb = load <16 x i8>, ptr %b - %add = add <16 x i8> %va, %vb - %shr = ashr <16 x i8> %add, - store <16 x i8> %shr, ptr %res - ret void -} - -define void @vavg_h(ptr %res, ptr %a, ptr %b) nounwind { -; CHECK-LABEL: vavg_h: -; CHECK: # %bb.0: # %entry -; CHECK-NEXT: vld $vr0, $a1, 0 -; CHECK-NEXT: vld $vr1, $a2, 0 -; CHECK-NEXT: vavg.h $vr0, $vr0, $vr1 -; CHECK-NEXT: vst $vr0, $a0, 0 -; CHECK-NEXT: ret -entry: - %va = load <8 x i16>, ptr %a - %vb = load <8 x i16>, ptr %b - %add = add <8 x i16> %va, %vb - %shr = ashr <8 x i16> %add, - store <8 x i16> %shr, ptr %res - ret void -} - -define void @vavg_w(ptr %res, ptr %a, ptr %b) nounwind { -; CHECK-LABEL: vavg_w: -; CHECK: # %bb.0: # %entry -; CHECK-NEXT: vld $vr0, $a1, 0 -; CHECK-NEXT: vld $vr1, $a2, 0 -; CHECK-NEXT: vavg.w $vr0, $vr0, $vr1 -; CHECK-NEXT: vst $vr0, $a0, 0 -; CHECK-NEXT: ret -entry: - %va = load <4 x i32>, ptr %a - %vb = load <4 x i32>, ptr %b - %add = add <4 x i32> %va, %vb - %shr = ashr <4 x i32> %add, - store <4 x i32> %shr, ptr %res - ret void -} - -define void @vavg_d(ptr %res, ptr %a, ptr %b) nounwind { -; LA32-LABEL: vavg_d: -; LA32: # %bb.0: # %entry -; LA32-NEXT: vld $vr0, $a1, 0 -; LA32-NEXT: vld $vr1, $a2, 0 -; LA32-NEXT: vadd.d $vr0, $vr0, $vr1 -; LA32-NEXT: vsrai.d $vr0, $vr0, 1 -; LA32-NEXT: vst $vr0, $a0, 0 -; LA32-NEXT: ret -; -; LA64-LABEL: vavg_d: -; LA64: # %bb.0: # %entry -; LA64-NEXT: vld $vr0, $a1, 0 -; LA64-NEXT: vld $vr1, $a2, 0 -; LA64-NEXT: vavg.d $vr0, $vr0, $vr1 -; LA64-NEXT: vst $vr0, $a0, 0 -; LA64-NEXT: ret -entry: - %va = load <2 x i64>, ptr %a - %vb = load <2 x i64>, ptr %b - %add = add <2 x i64> %va, %vb - %shr = ashr <2 x i64> %add, - store <2 x i64> %shr, ptr %res - ret void -} - -define void @vavg_bu(ptr %res, ptr %a, ptr %b) nounwind { -; CHECK-LABEL: vavg_bu: -; CHECK: # %bb.0: # %entry -; CHECK-NEXT: vld $vr0, $a1, 0 -; CHECK-NEXT: vld $vr1, $a2, 0 -; CHECK-NEXT: vavg.bu $vr0, $vr0, $vr1 -; CHECK-NEXT: vst $vr0, $a0, 0 -; CHECK-NEXT: ret -entry: - %va = load <16 x i8>, ptr %a - %vb = load <16 x i8>, ptr %b - %add = add <16 x i8> %va, %vb - %shr = lshr <16 x i8> %add, - store <16 x i8> %shr, ptr %res - ret void -} - -define void @vavg_hu(ptr %res, ptr %a, ptr %b) nounwind { -; CHECK-LABEL: vavg_hu: -; CHECK: # %bb.0: # %entry -; CHECK-NEXT: vld $vr0, $a1, 0 -; CHECK-NEXT: vld $vr1, $a2, 0 -; CHECK-NEXT: vavg.hu $vr0, $vr0, $vr1 -; CHECK-NEXT: vst $vr0, $a0, 0 -; CHECK-NEXT: ret -entry: - %va = load <8 x i16>, ptr %a - %vb = load <8 x i16>, ptr %b - %add = add <8 x i16> %va, %vb - %shr = lshr <8 x i16> %add, - store <8 x i16> %shr, ptr %res - ret void -} - -define void @vavg_wu(ptr %res, ptr %a, ptr %b) nounwind { -; CHECK-LABEL: vavg_wu: -; CHECK: # %bb.0: # %entry -; CHECK-NEXT: vld $vr0, $a1, 0 -; CHECK-NEXT: vld $vr1, $a2, 0 -; CHECK-NEXT: vavg.wu $vr0, $vr0, $vr1 -; CHECK-NEXT: vst $vr0, $a0, 0 -; CHECK-NEXT: ret -entry: - %va = load <4 x i32>, ptr %a - %vb = load <4 x i32>, ptr %b - %add = add <4 x i32> %va, %vb - %shr = lshr <4 x i32> %add, - store <4 x i32> %shr, ptr %res - ret void -} - -define void @vavg_du(ptr %res, ptr %a, ptr %b) nounwind { -; LA32-LABEL: vavg_du: -; LA32: # %bb.0: # %entry -; LA32-NEXT: vld $vr0, $a1, 0 -; LA32-NEXT: vld $vr1, $a2, 0 -; LA32-NEXT: vadd.d $vr0, $vr0, $vr1 -; LA32-NEXT: vsrli.d $vr0, $vr0, 1 -; LA32-NEXT: vst $vr0, $a0, 0 -; LA32-NEXT: ret -; -; LA64-LABEL: vavg_du: -; LA64: # %bb.0: # %entry -; LA64-NEXT: vld $vr0, $a1, 0 -; LA64-NEXT: vld $vr1, $a2, 0 -; LA64-NEXT: vavg.du $vr0, $vr0, $vr1 -; LA64-NEXT: vst $vr0, $a0, 0 -; LA64-NEXT: ret -entry: - %va = load <2 x i64>, ptr %a - %vb = load <2 x i64>, ptr %b - %add = add <2 x i64> %va, %vb - %shr = lshr <2 x i64> %add, - store <2 x i64> %shr, ptr %res - ret void -} - -define void @vavgr_b(ptr %res, ptr %a, ptr %b) nounwind { -; CHECK-LABEL: vavgr_b: -; CHECK: # %bb.0: # %entry -; CHECK-NEXT: vld $vr0, $a1, 0 -; CHECK-NEXT: vld $vr1, $a2, 0 -; CHECK-NEXT: vavgr.b $vr0, $vr0, $vr1 -; CHECK-NEXT: vst $vr0, $a0, 0 -; CHECK-NEXT: ret -entry: - %va = load <16 x i8>, ptr %a - %vb = load <16 x i8>, ptr %b - %add = add <16 x i8> %va, %vb - %add1 = add <16 x i8> %add, - %shr = ashr <16 x i8> %add1, - store <16 x i8> %shr, ptr %res - ret void -} - -define void @vavgr_h(ptr %res, ptr %a, ptr %b) nounwind { -; CHECK-LABEL: vavgr_h: -; CHECK: # %bb.0: # %entry -; CHECK-NEXT: vld $vr0, $a1, 0 -; CHECK-NEXT: vld $vr1, $a2, 0 -; CHECK-NEXT: vavgr.h $vr0, $vr0, $vr1 -; CHECK-NEXT: vst $vr0, $a0, 0 -; CHECK-NEXT: ret -entry: - %va = load <8 x i16>, ptr %a - %vb = load <8 x i16>, ptr %b - %add = add <8 x i16> %va, %vb - %add1 = add <8 x i16> %add, - %shr = ashr <8 x i16> %add1, - store <8 x i16> %shr, ptr %res - ret void -} - -define void @vavgr_w(ptr %res, ptr %a, ptr %b) nounwind { -; CHECK-LABEL: vavgr_w: -; CHECK: # %bb.0: # %entry -; CHECK-NEXT: vld $vr0, $a1, 0 -; CHECK-NEXT: vld $vr1, $a2, 0 -; CHECK-NEXT: vavgr.w $vr0, $vr0, $vr1 -; CHECK-NEXT: vst $vr0, $a0, 0 -; CHECK-NEXT: ret -entry: - %va = load <4 x i32>, ptr %a - %vb = load <4 x i32>, ptr %b - %add = add <4 x i32> %va, %vb - %add1 = add <4 x i32> %add, - %shr = ashr <4 x i32> %add1, - store <4 x i32> %shr, ptr %res - ret void -} - -define void @vavgr_d(ptr %res, ptr %a, ptr %b) nounwind { -; LA32-LABEL: vavgr_d: -; LA32: # %bb.0: # %entry -; LA32-NEXT: vld $vr0, $a1, 0 -; LA32-NEXT: vld $vr1, $a2, 0 -; LA32-NEXT: vadd.d $vr0, $vr0, $vr1 -; LA32-NEXT: vaddi.du $vr0, $vr0, 1 -; LA32-NEXT: vsrai.d $vr0, $vr0, 1 -; LA32-NEXT: vst $vr0, $a0, 0 -; LA32-NEXT: ret -; -; LA64-LABEL: vavgr_d: -; LA64: # %bb.0: # %entry -; LA64-NEXT: vld $vr0, $a1, 0 -; LA64-NEXT: vld $vr1, $a2, 0 -; LA64-NEXT: vavgr.d $vr0, $vr0, $vr1 -; LA64-NEXT: vst $vr0, $a0, 0 -; LA64-NEXT: ret -entry: - %va = load <2 x i64>, ptr %a - %vb = load <2 x i64>, ptr %b - %add = add <2 x i64> %va, %vb - %add1 = add <2 x i64> %add, - %shr = ashr <2 x i64> %add1, - store <2 x i64> %shr, ptr %res - ret void -} - -define void @vavgr_bu(ptr %res, ptr %a, ptr %b) nounwind { -; CHECK-LABEL: vavgr_bu: -; CHECK: # %bb.0: # %entry -; CHECK-NEXT: vld $vr0, $a1, 0 -; CHECK-NEXT: vld $vr1, $a2, 0 -; CHECK-NEXT: vavgr.bu $vr0, $vr0, $vr1 -; CHECK-NEXT: vst $vr0, $a0, 0 -; CHECK-NEXT: ret -entry: - %va = load <16 x i8>, ptr %a - %vb = load <16 x i8>, ptr %b - %add = add <16 x i8> %va, %vb - %add1 = add <16 x i8> %add, - %shr = lshr <16 x i8> %add1, - store <16 x i8> %shr, ptr %res - ret void -} - -define void @vavgr_hu(ptr %res, ptr %a, ptr %b) nounwind { -; CHECK-LABEL: vavgr_hu: -; CHECK: # %bb.0: # %entry -; CHECK-NEXT: vld $vr0, $a1, 0 -; CHECK-NEXT: vld $vr1, $a2, 0 -; CHECK-NEXT: vavgr.hu $vr0, $vr0, $vr1 -; CHECK-NEXT: vst $vr0, $a0, 0 -; CHECK-NEXT: ret -entry: - %va = load <8 x i16>, ptr %a - %vb = load <8 x i16>, ptr %b - %add = add <8 x i16> %va, %vb - %add1 = add <8 x i16> %add, - %shr = lshr <8 x i16> %add1, - store <8 x i16> %shr, ptr %res - ret void -} - -define void @vavgr_wu(ptr %res, ptr %a, ptr %b) nounwind { -; CHECK-LABEL: vavgr_wu: -; CHECK: # %bb.0: # %entry -; CHECK-NEXT: vld $vr0, $a1, 0 -; CHECK-NEXT: vld $vr1, $a2, 0 -; CHECK-NEXT: vavgr.wu $vr0, $vr0, $vr1 -; CHECK-NEXT: vst $vr0, $a0, 0 -; CHECK-NEXT: ret -entry: - %va = load <4 x i32>, ptr %a - %vb = load <4 x i32>, ptr %b - %add = add <4 x i32> %va, %vb - %add1 = add <4 x i32> %add, - %shr = lshr <4 x i32> %add1, - store <4 x i32> %shr, ptr %res - ret void -} - -define void @vavgr_du(ptr %res, ptr %a, ptr %b) nounwind { -; LA32-LABEL: vavgr_du: -; LA32: # %bb.0: # %entry -; LA32-NEXT: vld $vr0, $a1, 0 -; LA32-NEXT: vld $vr1, $a2, 0 -; LA32-NEXT: vadd.d $vr0, $vr0, $vr1 -; LA32-NEXT: vaddi.du $vr0, $vr0, 1 -; LA32-NEXT: vsrli.d $vr0, $vr0, 1 -; LA32-NEXT: vst $vr0, $a0, 0 -; LA32-NEXT: ret -; -; LA64-LABEL: vavgr_du: -; LA64: # %bb.0: # %entry -; LA64-NEXT: vld $vr0, $a1, 0 -; LA64-NEXT: vld $vr1, $a2, 0 -; LA64-NEXT: vavgr.du $vr0, $vr0, $vr1 -; LA64-NEXT: vst $vr0, $a0, 0 -; LA64-NEXT: ret -entry: - %va = load <2 x i64>, ptr %a - %vb = load <2 x i64>, ptr %b - %add = add <2 x i64> %va, %vb - %add1 = add <2 x i64> %add, - %shr = lshr <2 x i64> %add1, - store <2 x i64> %shr, ptr %res - ret void -} From 8798085803f18d2ad763c2060660b7af5708fe5d Mon Sep 17 00:00:00 2001 From: Joseph Huber Date: Mon, 18 May 2026 10:08:44 -0500 Subject: [PATCH 06/16] [libc] Demote compiler check error to a warning (#198033) Summary: This check exists to encode the policy that this is only intended to be built with a just-built compiler. In practice it's a little too strict and breaks pretty much every six months when the version bumps or when people try to build a separate patch. Just demote to a warning. (cherry picked from commit 13da33e922fe43cd97246f5e33320acc4f5ea186) --- libc/cmake/modules/prepare_libc_gpu_build.cmake | 2 +- openmp/device/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libc/cmake/modules/prepare_libc_gpu_build.cmake b/libc/cmake/modules/prepare_libc_gpu_build.cmake index 55cd0242eedeb..2686a5dc4b4df 100644 --- a/libc/cmake/modules/prepare_libc_gpu_build.cmake +++ b/libc/cmake/modules/prepare_libc_gpu_build.cmake @@ -7,7 +7,7 @@ endif() set(req_ver "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH}") if(LLVM_VERSION_MAJOR AND NOT (CMAKE_CXX_COMPILER_ID MATCHES "[Cc]lang" AND ${CMAKE_CXX_COMPILER_VERSION} VERSION_EQUAL "${req_ver}")) - message(FATAL_ERROR "Cannot build libc for GPU. CMake compiler " + message(WARNING "libc for GPU requires an up-to-date clang. CMake compiler " "'${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}' " " is not 'Clang ${req_ver}'.") endif() diff --git a/openmp/device/CMakeLists.txt b/openmp/device/CMakeLists.txt index 54cfdfef440a5..06fd5f0f2ed59 100644 --- a/openmp/device/CMakeLists.txt +++ b/openmp/device/CMakeLists.txt @@ -2,7 +2,7 @@ set(req_ver "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH}") if(LLVM_VERSION_MAJOR AND NOT (CMAKE_CXX_COMPILER_ID MATCHES "[Cc]lang" AND ${CMAKE_CXX_COMPILER_VERSION} VERSION_EQUAL "${req_ver}")) - message(FATAL_ERROR "Cannot build GPU device runtime. CMake compiler " + message(WARNING "openmp for GPU requires an up-to-date clang. CMake compiler " "'${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}' " " is not 'Clang ${req_ver}'.") endif() From 48967cc1a0d4851b01b0548932ac77b86017f053 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Tue, 10 Mar 2026 14:32:13 -0700 Subject: [PATCH 07/16] build: adjust LLDB and clang library naming on Windows (#185084) Ensure that use of the GNU driver does not change the library name on Windows. We would check the build tools being MSVC rather than targeting Windows to select the output name. (cherry picked from commit 687e66c989887542b1702a7a99eeaa4e25edd12e) --- clang/tools/libclang/CMakeLists.txt | 2 +- lldb/source/API/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/tools/libclang/CMakeLists.txt b/clang/tools/libclang/CMakeLists.txt index b0105f5a5f79f..19011c8a64096 100644 --- a/clang/tools/libclang/CMakeLists.txt +++ b/clang/tools/libclang/CMakeLists.txt @@ -120,7 +120,7 @@ if (MSVC AND ENABLE_SHARED AND ENABLE_STATIC) unset(ENABLE_STATIC) endif() -if(MSVC) +if(WIN32 AND NOT MINGW) set(output_name "libclang") else() set(output_name "clang") diff --git a/lldb/source/API/CMakeLists.txt b/lldb/source/API/CMakeLists.txt index e27f90f2e873d..186f3b3b65299 100644 --- a/lldb/source/API/CMakeLists.txt +++ b/lldb/source/API/CMakeLists.txt @@ -265,7 +265,7 @@ elseif (LLDB_EXPORT_ALL_SYMBOLS) add_llvm_symbol_exports(liblldb ${exported_symbol_file}) endif() -if (NOT MSVC) +if(NOT WIN32 OR MINGW) set_target_properties(liblldb PROPERTIES OUTPUT_NAME lldb From ad9524f3865770ed410bbc7d91fa50dc2d223027 Mon Sep 17 00:00:00 2001 From: Amy Kwan Date: Sun, 17 May 2026 09:08:02 -0400 Subject: [PATCH 08/16] [PowerPC] Fix i128 vcmpequb optimization for loads with range metadata and small constants (#196801) The combine introduced in 55aff64d2c6ef50d2ed725d7dd1fb34080486237 lowers scalar i128 compares into vector compares by reissuing the original loads as v16i8 loads. However, the combine was reusing the original MachineMemOperand without modification. If the original i128 load carries !range metadata, the MMO encodes that range using i128 values. Reusing this MMO for a v16i8 load is incorrect as range metadata is only valid for integer scalar types and its bitwidth must match the memory VT. This patch fixes this by creating a new MachineMemOperand for the vector vector load. Additionally, we restrict the combine for constant operands to avoid cases that are better handled by scalar lowering. Small constants (fit within 16 bits) are excluded to prevent generating suboptimal vector compares. (cherry picked from commit 1907b586384b51be2f6b44490c46941f08ff6974) --- llvm/lib/Target/PowerPC/PPCISelLowering.cpp | 36 ++- llvm/test/CodeGen/PowerPC/ppc-i128-cmp.ll | 282 ++++++++++++++++++++ 2 files changed, 310 insertions(+), 8 deletions(-) create mode 100644 llvm/test/CodeGen/PowerPC/ppc-i128-cmp.ll diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp index bdba040529d00..56aa33fdd4098 100644 --- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -15586,17 +15586,27 @@ SDValue PPCTargetLowering::DAGCombineExtBoolTrunc(SDNode *N, } // The function check a i128 load can convert to 16i8 load for Vcmpequb. -static bool canConvertToVcmpequb(SDValue &LHS, SDValue &RHS) { +static bool canConvertToVcmpequb(SDValue &LHS, SDValue &RHS, bool IsPPC64) { - auto isValidForConvert = [](SDValue &Operand) { + auto isValidForConvert = [IsPPC64](SDValue &Operand) { if (!Operand.hasOneUse()) return false; if (Operand.getValueType() != MVT::i128) return false; - if (Operand.getOpcode() == ISD::Constant) + if (Operand.getOpcode() == ISD::Constant) { + auto *C = cast(Operand); + const APInt &Val = C->getAPIntValue(); + // On PPC64, comparing an i128 value loaded from memory against a + // constant smaller than 2^16 is usually better left to scalar lowering. + // In that case, the compare can be lowered using xori (since xori has a + // 16-bit immediate field), which is cheaper than materializing a vector + // constant and using vcmpequb. + if (IsPPC64 && Val.ult(1ULL << 16)) + return false; return true; + } auto *LoadNode = dyn_cast(Operand); if (!LoadNode) @@ -15647,10 +15657,19 @@ SDValue convertTwoLoadsAndCmpToVCMPEQUB(SelectionDAG &DAG, SDNode *N, assert(Operand.getOpcode() == ISD::LOAD && "Must be LoadSDNode here."); auto *LoadNode = cast(Operand); - SDValue NewLoad = - DAG.getLoad(MVT::v16i8, DL, LoadNode->getChain(), - LoadNode->getBasePtr(), LoadNode->getMemOperand()); - DAG.ReplaceAllUsesOfValueWith(Operand.getValue(1), NewLoad.getValue(1)); + // Create a new MachineMemOperand without range metadata. + // Range metadata is only valid for integer scalar types, not vectors. + // The original i128 load may have range metadata, but when we convert + // to v16i8, that metadata is no longer semantically valid. + MachineMemOperand *MMO = LoadNode->getMemOperand(); + MachineFunction &MF = DAG.getMachineFunction(); + MachineMemOperand *NewMMO = MF.getMachineMemOperand( + MMO->getPointerInfo(), MMO->getFlags(), MMO->getSize(), MMO->getAlign(), + MMO->getAAInfo(), nullptr, MMO->getSyncScopeID(), + MMO->getSuccessOrdering(), MMO->getFailureOrdering()); + SDValue NewLoad = DAG.getLoad(MVT::v16i8, DL, LoadNode->getChain(), + LoadNode->getBasePtr(), NewMMO); + DAG.ReplaceAllUsesOfValueWith(SDValue(LoadNode, 1), NewLoad.getValue(1)); return NewLoad; }; @@ -15815,7 +15834,8 @@ SDValue PPCTargetLowering::combineSetCC(SDNode *N, // This transformation replaces memcmp(a, b, 16) with two vector loads // and one vector compare instruction. - if (Subtarget.hasAltivec() && canConvertToVcmpequb(LHS, RHS)) + if (Subtarget.hasAltivec() && + canConvertToVcmpequb(LHS, RHS, Subtarget.isPPC64())) return convertTwoLoadsAndCmpToVCMPEQUB(DCI.DAG, N, SDLoc(N)); } diff --git a/llvm/test/CodeGen/PowerPC/ppc-i128-cmp.ll b/llvm/test/CodeGen/PowerPC/ppc-i128-cmp.ll new file mode 100644 index 0000000000000..c661d7da690b4 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/ppc-i128-cmp.ll @@ -0,0 +1,282 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6 +; RUN: llc -mcpu=pwr8 -ppc-asm-full-reg-names -mtriple=powerpc64-ibm-aix < %s | \ +; RUN: FileCheck %s --check-prefixes=COMMON,CHECK-AIX64 +; RUN: llc -mcpu=pwr8 -ppc-asm-full-reg-names -mtriple=powerpc64le-unknown-linux-gnu < %s | \ +; RUN: FileCheck %s --check-prefixes=COMMON,CHECK-LINUX +; RUN: llc -mcpu=pwr8 -ppc-asm-full-reg-names -mtriple=powerpc-ibm-aix < %s | \ +; RUN: FileCheck %s --check-prefixes=COMMON,CHECK-AIX32 + +define i1 @test1() { +; CHECK-AIX64-LABEL: test1: +; CHECK-AIX64: # %bb.0: # %bb +; CHECK-AIX64-NEXT: ld r3, 0(0) +; CHECK-AIX64-NEXT: ld r4, 8(0) +; CHECK-AIX64-NEXT: or r3, r4, r3 +; CHECK-AIX64-NEXT: cntlzd r3, r3 +; CHECK-AIX64-NEXT: rldicl r3, r3, 58, 63 +; CHECK-AIX64-NEXT: blr +; +; CHECK-LINUX-LABEL: test1: +; CHECK-LINUX: # %bb.0: # %bb +; CHECK-LINUX-NEXT: ld r3, 8(0) +; CHECK-LINUX-NEXT: ld r4, 0(0) +; CHECK-LINUX-NEXT: or r3, r4, r3 +; CHECK-LINUX-NEXT: cntlzd r3, r3 +; CHECK-LINUX-NEXT: rldicl r3, r3, 58, 63 +; CHECK-LINUX-NEXT: blr +; +; CHECK-AIX32-LABEL: test1: +; CHECK-AIX32: # %bb.0: # %bb +; CHECK-AIX32-NEXT: li r3, 0 +; CHECK-AIX32-NEXT: xxlxor vs35, vs35, vs35 +; CHECK-AIX32-NEXT: lxvw4x vs34, 0, r3 +; CHECK-AIX32-NEXT: vcmpequb. v2, v2, v3 +; CHECK-AIX32-NEXT: mfocrf r3, 2 +; CHECK-AIX32-NEXT: rlwinm r3, r3, 25, 31, 31 +; CHECK-AIX32-NEXT: blr +bb: + %load = load i128, ptr null, align 16 + %icmp = icmp eq i128 %load, 0 + ret i1 %icmp +} + +define i1 @test2() { +; CHECK-AIX64-LABEL: test2: +; CHECK-AIX64: # %bb.0: # %bb +; CHECK-AIX64-NEXT: ld r4, 8(0) +; CHECK-AIX64-NEXT: ld r3, 0(0) +; CHECK-AIX64-NEXT: xori r4, r4, 10 +; CHECK-AIX64-NEXT: or r3, r4, r3 +; CHECK-AIX64-NEXT: cntlzd r3, r3 +; CHECK-AIX64-NEXT: rldicl r3, r3, 58, 63 +; CHECK-AIX64-NEXT: blr +; +; CHECK-LINUX-LABEL: test2: +; CHECK-LINUX: # %bb.0: # %bb +; CHECK-LINUX-NEXT: ld r4, 0(0) +; CHECK-LINUX-NEXT: ld r3, 8(0) +; CHECK-LINUX-NEXT: xori r4, r4, 10 +; CHECK-LINUX-NEXT: or r3, r4, r3 +; CHECK-LINUX-NEXT: cntlzd r3, r3 +; CHECK-LINUX-NEXT: rldicl r3, r3, 58, 63 +; CHECK-LINUX-NEXT: blr +; +; CHECK-AIX32-LABEL: test2: +; CHECK-AIX32: # %bb.0: # %bb +; CHECK-AIX32-NEXT: li r3, 0 +; CHECK-AIX32-NEXT: lxvw4x vs34, 0, r3 +; CHECK-AIX32-NEXT: lwz r3, L..C0(r2) # %const.0 +; CHECK-AIX32-NEXT: lxvw4x vs35, 0, r3 +; CHECK-AIX32-NEXT: vcmpequb. v2, v2, v3 +; CHECK-AIX32-NEXT: mfocrf r3, 2 +; CHECK-AIX32-NEXT: rlwinm r3, r3, 25, 31, 31 +; CHECK-AIX32-NEXT: blr +bb: + %load = load i128, ptr null, align 16 + %icmp = icmp eq i128 %load, 10 + ret i1 %icmp +} + +define i1 @test3() { +; CHECK-AIX64-LABEL: test3: +; CHECK-AIX64: # %bb.0: # %bb +; CHECK-AIX64-NEXT: ld r4, 8(0) +; CHECK-AIX64-NEXT: ld r3, 0(0) +; CHECK-AIX64-NEXT: xori r4, r4, 65535 +; CHECK-AIX64-NEXT: or r3, r4, r3 +; CHECK-AIX64-NEXT: cntlzd r3, r3 +; CHECK-AIX64-NEXT: rldicl r3, r3, 58, 63 +; CHECK-AIX64-NEXT: blr +; +; CHECK-LINUX-LABEL: test3: +; CHECK-LINUX: # %bb.0: # %bb +; CHECK-LINUX-NEXT: ld r4, 0(0) +; CHECK-LINUX-NEXT: ld r3, 8(0) +; CHECK-LINUX-NEXT: xori r4, r4, 65535 +; CHECK-LINUX-NEXT: or r3, r4, r3 +; CHECK-LINUX-NEXT: cntlzd r3, r3 +; CHECK-LINUX-NEXT: rldicl r3, r3, 58, 63 +; CHECK-LINUX-NEXT: blr +; +; CHECK-AIX32-LABEL: test3: +; CHECK-AIX32: # %bb.0: # %bb +; CHECK-AIX32-NEXT: li r3, 0 +; CHECK-AIX32-NEXT: lxvw4x vs34, 0, r3 +; CHECK-AIX32-NEXT: lwz r3, L..C1(r2) # %const.0 +; CHECK-AIX32-NEXT: lxvw4x vs35, 0, r3 +; CHECK-AIX32-NEXT: vcmpequb. v2, v2, v3 +; CHECK-AIX32-NEXT: mfocrf r3, 2 +; CHECK-AIX32-NEXT: rlwinm r3, r3, 25, 31, 31 +; CHECK-AIX32-NEXT: blr +bb: + %load = load i128, ptr null, align 16 + %icmp = icmp eq i128 %load, 65535 + ret i1 %icmp +} + +define i1 @test4() { +; CHECK-AIX64-LABEL: test4: +; CHECK-AIX64: # %bb.0: # %bb +; CHECK-AIX64-NEXT: li r3, 0 +; CHECK-AIX64-NEXT: lxvw4x vs34, 0, r3 +; CHECK-AIX64-NEXT: ld r3, L..C0(r2) # %const.0 +; CHECK-AIX64-NEXT: lxvd2x vs35, 0, r3 +; CHECK-AIX64-NEXT: vcmpequb. v2, v2, v3 +; CHECK-AIX64-NEXT: mfocrf r3, 2 +; CHECK-AIX64-NEXT: rlwinm r3, r3, 25, 31, 31 +; CHECK-AIX64-NEXT: blr +; +; CHECK-LINUX-LABEL: test4: +; CHECK-LINUX: # %bb.0: # %bb +; CHECK-LINUX-NEXT: li r3, 0 +; CHECK-LINUX-NEXT: lxvd2x vs34, 0, r3 +; CHECK-LINUX-NEXT: addis r3, r2, .LCPI3_0@toc@ha +; CHECK-LINUX-NEXT: addi r3, r3, .LCPI3_0@toc@l +; CHECK-LINUX-NEXT: lxvd2x vs35, 0, r3 +; CHECK-LINUX-NEXT: vcmpequb. v2, v2, v3 +; CHECK-LINUX-NEXT: mfocrf r3, 2 +; CHECK-LINUX-NEXT: rlwinm r3, r3, 25, 31, 31 +; CHECK-LINUX-NEXT: blr +; +; CHECK-AIX32-LABEL: test4: +; CHECK-AIX32: # %bb.0: # %bb +; CHECK-AIX32-NEXT: li r3, 0 +; CHECK-AIX32-NEXT: lxvw4x vs34, 0, r3 +; CHECK-AIX32-NEXT: lwz r3, L..C2(r2) # %const.0 +; CHECK-AIX32-NEXT: lxvw4x vs35, 0, r3 +; CHECK-AIX32-NEXT: vcmpequb. v2, v2, v3 +; CHECK-AIX32-NEXT: mfocrf r3, 2 +; CHECK-AIX32-NEXT: rlwinm r3, r3, 25, 31, 31 +; CHECK-AIX32-NEXT: blr +bb: + %load = load i128, ptr null, align 16 + %icmp = icmp eq i128 %load, 65536 + ret i1 %icmp +} + +; Test using the !range metadata +define i1 @test5() { +; CHECK-AIX64-LABEL: test5: +; CHECK-AIX64: # %bb.0: # %bb +; CHECK-AIX64-NEXT: ld r3, 0(0) +; CHECK-AIX64-NEXT: ld r4, 8(0) +; CHECK-AIX64-NEXT: or r3, r4, r3 +; CHECK-AIX64-NEXT: cntlzd r3, r3 +; CHECK-AIX64-NEXT: rldicl r3, r3, 58, 63 +; CHECK-AIX64-NEXT: blr +; +; CHECK-LINUX-LABEL: test5: +; CHECK-LINUX: # %bb.0: # %bb +; CHECK-LINUX-NEXT: ld r3, 8(0) +; CHECK-LINUX-NEXT: ld r4, 0(0) +; CHECK-LINUX-NEXT: or r3, r4, r3 +; CHECK-LINUX-NEXT: cntlzd r3, r3 +; CHECK-LINUX-NEXT: rldicl r3, r3, 58, 63 +; CHECK-LINUX-NEXT: blr +; +; CHECK-AIX32-LABEL: test5: +; CHECK-AIX32: # %bb.0: # %bb +; CHECK-AIX32-NEXT: li r3, 0 +; CHECK-AIX32-NEXT: xxlxor vs35, vs35, vs35 +; CHECK-AIX32-NEXT: lxvw4x vs34, 0, r3 +; CHECK-AIX32-NEXT: vcmpequb. v2, v2, v3 +; CHECK-AIX32-NEXT: mfocrf r3, 2 +; CHECK-AIX32-NEXT: rlwinm r3, r3, 25, 31, 31 +; CHECK-AIX32-NEXT: blr +bb: + %load = load i128, ptr null, align 16, !range !0 + %icmp = icmp eq i128 %load, 0 + ret i1 %icmp +} + +define i1 @test6() { +; CHECK-AIX64-LABEL: test6: +; CHECK-AIX64: # %bb.0: # %bb +; CHECK-AIX64-NEXT: ld r4, 8(0) +; CHECK-AIX64-NEXT: ld r3, 0(0) +; CHECK-AIX64-NEXT: xori r4, r4, 65535 +; CHECK-AIX64-NEXT: or r3, r4, r3 +; CHECK-AIX64-NEXT: cntlzd r3, r3 +; CHECK-AIX64-NEXT: rldicl r3, r3, 58, 63 +; CHECK-AIX64-NEXT: blr +; +; CHECK-LINUX-LABEL: test6: +; CHECK-LINUX: # %bb.0: # %bb +; CHECK-LINUX-NEXT: ld r4, 0(0) +; CHECK-LINUX-NEXT: ld r3, 8(0) +; CHECK-LINUX-NEXT: xori r4, r4, 65535 +; CHECK-LINUX-NEXT: or r3, r4, r3 +; CHECK-LINUX-NEXT: cntlzd r3, r3 +; CHECK-LINUX-NEXT: rldicl r3, r3, 58, 63 +; CHECK-LINUX-NEXT: blr +; +; CHECK-AIX32-LABEL: test6: +; CHECK-AIX32: # %bb.0: # %bb +; CHECK-AIX32-NEXT: li r3, 0 +; CHECK-AIX32-NEXT: lxvw4x vs34, 0, r3 +; CHECK-AIX32-NEXT: lwz r3, L..C3(r2) # %const.0 +; CHECK-AIX32-NEXT: lxvw4x vs35, 0, r3 +; CHECK-AIX32-NEXT: vcmpequb. v2, v2, v3 +; CHECK-AIX32-NEXT: mfocrf r3, 2 +; CHECK-AIX32-NEXT: rlwinm r3, r3, 25, 31, 31 +; CHECK-AIX32-NEXT: blr +bb: + %load = load i128, ptr null, align 16, !range !1 + %icmp = icmp eq i128 %load, 65535 + ret i1 %icmp +} + +define i1 @test7() { +; COMMON-LABEL: test7: +; COMMON: # %bb.0: # %bb +; COMMON-NEXT: li r3, 0 +; COMMON-NEXT: blr +bb: + %load = load i128, ptr null, align 16, !range !1 + %icmp = icmp eq i128 %load, 65536 + ret i1 %icmp +} + +define i1 @test8() { +; CHECK-AIX64-LABEL: test8: +; CHECK-AIX64: # %bb.0: # %bb +; CHECK-AIX64-NEXT: li r3, 0 +; CHECK-AIX64-NEXT: lxvw4x vs34, 0, r3 +; CHECK-AIX64-NEXT: ld r3, L..C1(r2) # %const.0 +; CHECK-AIX64-NEXT: lxvd2x vs35, 0, r3 +; CHECK-AIX64-NEXT: vcmpequb. v2, v2, v3 +; CHECK-AIX64-NEXT: mfocrf r3, 2 +; CHECK-AIX64-NEXT: rlwinm r3, r3, 25, 31, 31 +; CHECK-AIX64-NEXT: blr +; +; CHECK-LINUX-LABEL: test8: +; CHECK-LINUX: # %bb.0: # %bb +; CHECK-LINUX-NEXT: li r3, 0 +; CHECK-LINUX-NEXT: lxvd2x vs34, 0, r3 +; CHECK-LINUX-NEXT: addis r3, r2, .LCPI7_0@toc@ha +; CHECK-LINUX-NEXT: addi r3, r3, .LCPI7_0@toc@l +; CHECK-LINUX-NEXT: lxvd2x vs35, 0, r3 +; CHECK-LINUX-NEXT: vcmpequb. v2, v2, v3 +; CHECK-LINUX-NEXT: mfocrf r3, 2 +; CHECK-LINUX-NEXT: rlwinm r3, r3, 25, 31, 31 +; CHECK-LINUX-NEXT: blr +; +; CHECK-AIX32-LABEL: test8: +; CHECK-AIX32: # %bb.0: # %bb +; CHECK-AIX32-NEXT: li r3, 0 +; CHECK-AIX32-NEXT: lxvw4x vs34, 0, r3 +; CHECK-AIX32-NEXT: lwz r3, L..C4(r2) # %const.0 +; CHECK-AIX32-NEXT: lxvw4x vs35, 0, r3 +; CHECK-AIX32-NEXT: vcmpequb. v2, v2, v3 +; CHECK-AIX32-NEXT: mfocrf r3, 2 +; CHECK-AIX32-NEXT: rlwinm r3, r3, 25, 31, 31 +; CHECK-AIX32-NEXT: blr +bb: + %load = load i128, ptr null, align 16, !range !2 + %icmp = icmp eq i128 %load, 65536 + ret i1 %icmp +} + +!0 = !{i128 0, i128 2} +!1 = !{i128 0, i128 65536} +!2 = !{i128 0, i128 65537} From 6ac68778a76e1c0ab62b3cc8ac555f349bf62048 Mon Sep 17 00:00:00 2001 From: Simon Pilgrim Date: Mon, 23 Feb 2026 12:01:49 +0000 Subject: [PATCH 09/16] [X86] Add test coverage for #137422 (#182832) (cherry picked from commit 0e3a96d0ec01e3575674d72c4e23bf98affdca28) --- .../CodeGen/X86/vector-shuffle-512-v64.ll | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/llvm/test/CodeGen/X86/vector-shuffle-512-v64.ll b/llvm/test/CodeGen/X86/vector-shuffle-512-v64.ll index ef20cf2a09bba..63b4de59372d9 100644 --- a/llvm/test/CodeGen/X86/vector-shuffle-512-v64.ll +++ b/llvm/test/CodeGen/X86/vector-shuffle-512-v64.ll @@ -1987,6 +1987,79 @@ define <512 x i8> @PR153457(<512 x i8> %a0, <512 x i8> %a1) nounwind { ret <512 x i8> %shuffle2 } +; PR137422 +define <64 x i8> @narrow_u32x16x4_to_u8x64(<64 x i8> %x0, <64 x i8> %x1, <64 x i8> %x2, <64 x i8> %x3) { +; AVX512F-LABEL: narrow_u32x16x4_to_u8x64: +; AVX512F: # %bb.0: +; AVX512F-NEXT: vextracti64x4 $1, %zmm1, %ymm4 +; AVX512F-NEXT: vpbroadcastd {{.*#+}} ymm5 = [0,4,8,12,0,4,8,12,0,4,8,12,0,4,8,12,0,4,8,12,0,4,8,12,0,4,8,12,0,4,8,12] +; AVX512F-NEXT: vpshufb %ymm5, %ymm4, %ymm4 +; AVX512F-NEXT: vpshufb %ymm5, %ymm1, %ymm1 +; AVX512F-NEXT: vpmovsxbd {{.*#+}} ymm6 = [0,4,0,4,0,4,16,20] +; AVX512F-NEXT: vpermt2d %zmm4, %zmm6, %zmm1 +; AVX512F-NEXT: vpmovdb %zmm0, %xmm0 +; AVX512F-NEXT: vpblendd {{.*#+}} ymm0 = ymm0[0,1,2,3],ymm1[4,5,6,7] +; AVX512F-NEXT: vextracti64x4 $1, %zmm3, %ymm1 +; AVX512F-NEXT: vpshufb %ymm5, %ymm1, %ymm1 +; AVX512F-NEXT: vpshufb %ymm5, %ymm3, %ymm3 +; AVX512F-NEXT: vpermt2d %zmm1, %zmm6, %zmm3 +; AVX512F-NEXT: vpmovdb %zmm2, %xmm1 +; AVX512F-NEXT: vpblendd {{.*#+}} ymm1 = ymm1[0,1,2,3],ymm3[4,5,6,7] +; AVX512F-NEXT: vshufi64x2 {{.*#+}} zmm0 = zmm0[0,1,2,3],zmm1[0,1,2,3] +; AVX512F-NEXT: retq +; +; AVX512BW-LABEL: narrow_u32x16x4_to_u8x64: +; AVX512BW: # %bb.0: +; AVX512BW-NEXT: vmovdqa64 {{.*#+}} zmm4 = [128,128,128,128,0,4,8,12,u,u,u,u,u,u,u,u,128,128,128,128,16,20,24,28,u,u,u,u,u,u,u,u,128,128,128,128,32,36,40,44,u,u,u,u,u,u,u,u,128,128,128,128,48,52,56,60,u,u,u,u,u,u,u,u] +; AVX512BW-NEXT: vpshufb %zmm4, %zmm1, %zmm1 +; AVX512BW-NEXT: vmovdqa64 {{.*#+}} zmm5 = [0,4,8,12,128,128,128,128,u,u,u,u,u,u,u,u,16,20,24,28,128,128,128,128,u,u,u,u,u,u,u,u,32,36,40,44,128,128,128,128,u,u,u,u,u,u,u,u,48,52,56,60,128,128,128,128,u,u,u,u,u,u,u,u] +; AVX512BW-NEXT: vpshufb %zmm5, %zmm0, %zmm0 +; AVX512BW-NEXT: vporq %zmm1, %zmm0, %zmm1 +; AVX512BW-NEXT: vpshufb %zmm4, %zmm3, %zmm0 +; AVX512BW-NEXT: vpshufb %zmm5, %zmm2, %zmm2 +; AVX512BW-NEXT: vporq %zmm0, %zmm2, %zmm2 +; AVX512BW-NEXT: vpmovsxbd {{.*#+}} zmm0 = [0,4,8,12,1,5,9,13,16,20,24,28,17,21,25,29] +; AVX512BW-NEXT: vpermi2d %zmm2, %zmm1, %zmm0 +; AVX512BW-NEXT: retq +; +; AVX512DQ-LABEL: narrow_u32x16x4_to_u8x64: +; AVX512DQ: # %bb.0: +; AVX512DQ-NEXT: vextracti64x4 $1, %zmm1, %ymm4 +; AVX512DQ-NEXT: vpbroadcastd {{.*#+}} ymm5 = [0,4,8,12,0,4,8,12,0,4,8,12,0,4,8,12,0,4,8,12,0,4,8,12,0,4,8,12,0,4,8,12] +; AVX512DQ-NEXT: vpshufb %ymm5, %ymm4, %ymm4 +; AVX512DQ-NEXT: vpshufb %ymm5, %ymm1, %ymm1 +; AVX512DQ-NEXT: vpmovsxbd {{.*#+}} ymm6 = [0,4,0,4,0,4,16,20] +; AVX512DQ-NEXT: vpermt2d %zmm4, %zmm6, %zmm1 +; AVX512DQ-NEXT: vpmovdb %zmm0, %xmm0 +; AVX512DQ-NEXT: vpblendd {{.*#+}} ymm0 = ymm0[0,1,2,3],ymm1[4,5,6,7] +; AVX512DQ-NEXT: vextracti64x4 $1, %zmm3, %ymm1 +; AVX512DQ-NEXT: vpshufb %ymm5, %ymm1, %ymm1 +; AVX512DQ-NEXT: vpshufb %ymm5, %ymm3, %ymm3 +; AVX512DQ-NEXT: vpermt2d %zmm1, %zmm6, %zmm3 +; AVX512DQ-NEXT: vpmovdb %zmm2, %xmm1 +; AVX512DQ-NEXT: vpblendd {{.*#+}} ymm1 = ymm1[0,1,2,3],ymm3[4,5,6,7] +; AVX512DQ-NEXT: vshufi64x2 {{.*#+}} zmm0 = zmm0[0,1,2,3],zmm1[0,1,2,3] +; AVX512DQ-NEXT: retq +; +; AVX512VBMI-LABEL: narrow_u32x16x4_to_u8x64: +; AVX512VBMI: # %bb.0: +; AVX512VBMI-NEXT: vmovdqa64 {{.*#+}} zmm4 = [128,128,128,128,0,4,8,12,u,u,u,u,u,u,u,u,128,128,128,128,16,20,24,28,u,u,u,u,u,u,u,u,128,128,128,128,32,36,40,44,u,u,u,u,u,u,u,u,128,128,128,128,48,52,56,60,u,u,u,u,u,u,u,u] +; AVX512VBMI-NEXT: vpshufb %zmm4, %zmm1, %zmm1 +; AVX512VBMI-NEXT: vmovdqa64 {{.*#+}} zmm5 = [0,4,8,12,128,128,128,128,u,u,u,u,u,u,u,u,16,20,24,28,128,128,128,128,u,u,u,u,u,u,u,u,32,36,40,44,128,128,128,128,u,u,u,u,u,u,u,u,48,52,56,60,128,128,128,128,u,u,u,u,u,u,u,u] +; AVX512VBMI-NEXT: vpshufb %zmm5, %zmm0, %zmm0 +; AVX512VBMI-NEXT: vporq %zmm1, %zmm0, %zmm1 +; AVX512VBMI-NEXT: vpshufb %zmm4, %zmm3, %zmm0 +; AVX512VBMI-NEXT: vpshufb %zmm5, %zmm2, %zmm2 +; AVX512VBMI-NEXT: vporq %zmm0, %zmm2, %zmm2 +; AVX512VBMI-NEXT: vpmovsxbd {{.*#+}} zmm0 = [0,4,8,12,1,5,9,13,16,20,24,28,17,21,25,29] +; AVX512VBMI-NEXT: vpermi2d %zmm2, %zmm1, %zmm0 +; AVX512VBMI-NEXT: retq + %lo = shufflevector <64 x i8> %x0, <64 x i8> %x1, <64 x i32> + %hi = shufflevector <64 x i8> %x2, <64 x i8> %x3, <64 x i32> + %res = shufflevector <64 x i8> %lo, <64 x i8> %hi, <64 x i32> + ret <64 x i8> %res +} + define <64 x i8> @shuffle_v32i16_zextinreg_to_v16i32(<64 x i8> %a) { ; ALL-LABEL: shuffle_v32i16_zextinreg_to_v16i32: ; ALL: # %bb.0: From c43c9b426055a78abbd3f7751865b6fb0d717fff Mon Sep 17 00:00:00 2001 From: Simon Pilgrim Date: Mon, 23 Feb 2026 14:41:35 +0000 Subject: [PATCH 10/16] [X86] lowerV64I8Shuffle - prefer VPERMV3 byte shuffles to OR(PSHUFB,PSHUFB) on VBMI targets (#182852) Minor improvement for #137422 (cherry picked from commit 8f5880d3ae4e5dfc748985d90e5413671028aa3e) --- llvm/lib/Target/X86/X86ISelLowering.cpp | 6 +++ .../CodeGen/X86/vector-shuffle-512-v64.ll | 43 ++++++++----------- 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp index cc255251ee235..ddd92c5422f53 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -18023,6 +18023,12 @@ static SDValue lowerV64I8Shuffle(const SDLoc &DL, ArrayRef Mask, Mask, Subtarget, DAG)) return V; + // VBMI can use VPERMV/VPERMV3 byte shuffles more efficiently than + // OR(PSHUFB,PSHUFB). + if (Subtarget.hasVBMI()) + return lowerShuffleWithPERMV(DL, MVT::v64i8, Mask, V1, V2, Subtarget, + DAG); + // If we can't directly blend but can use PSHUFB, that will be better as it // can both shuffle and set up the inefficient blend. bool V1InUse, V2InUse; diff --git a/llvm/test/CodeGen/X86/vector-shuffle-512-v64.ll b/llvm/test/CodeGen/X86/vector-shuffle-512-v64.ll index 63b4de59372d9..02c2106451707 100644 --- a/llvm/test/CodeGen/X86/vector-shuffle-512-v64.ll +++ b/llvm/test/CodeGen/X86/vector-shuffle-512-v64.ll @@ -1951,15 +1951,17 @@ define <512 x i8> @PR153457(<512 x i8> %a0, <512 x i8> %a1) nounwind { ; AVX512VBMI-NEXT: vbroadcasti64x4 {{.*#+}} zmm3 = [0,1,2,3,4,5,6,66,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,67,0,1,2,3,4,5,6,66,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,67] ; AVX512VBMI-NEXT: # zmm3 = mem[0,1,2,3,0,1,2,3] ; AVX512VBMI-NEXT: vpermi2b %zmm0, %zmm2, %zmm3 -; AVX512VBMI-NEXT: vpshufb {{.*#+}} zmm2 = zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zmm0[1,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u],zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero -; AVX512VBMI-NEXT: vpshufb {{.*#+}} zmm1 = zmm1[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14],zero,zmm1[u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63] -; AVX512VBMI-NEXT: vporq %zmm2, %zmm1, %zmm1 -; AVX512VBMI-NEXT: vmovdqa {{.*#+}} ymm2 = [u,u,u,u,u,u,u,u,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,71] -; AVX512VBMI-NEXT: vpermi2b %zmm0, %zmm6, %zmm2 +; AVX512VBMI-NEXT: vbroadcasti64x4 {{.*#+}} zmm2 = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,65,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,65,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63] +; AVX512VBMI-NEXT: # zmm2 = mem[0,1,2,3,0,1,2,3] +; AVX512VBMI-NEXT: vpermi2b %zmm0, %zmm1, %zmm2 +; AVX512VBMI-NEXT: vmovdqa {{.*#+}} ymm1 = [u,u,u,u,u,u,u,u,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,71] +; AVX512VBMI-NEXT: vpermi2b %zmm0, %zmm6, %zmm1 ; AVX512VBMI-NEXT: vmovdqa64 {{.*#+}} zmm6 = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,0,64,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,56,57,58,59,60,61,62,63] ; AVX512VBMI-NEXT: vpermi2b %zmm7, %zmm0, %zmm6 -; AVX512VBMI-NEXT: vpmovsxbw {{.*#+}} zmm0 = [0,1,2,3,33,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,21,22,23,24,25,26,27,28,29,30,31] -; AVX512VBMI-NEXT: vpermi2w %zmm7, %zmm3, %zmm0 +; AVX512VBMI-NEXT: vinserti32x4 $1, %xmm7, %zmm2, %zmm0 +; AVX512VBMI-NEXT: vpshufb {{.*#+}} zmm0 = zmm0[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,17,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63] +; AVX512VBMI-NEXT: vpmovsxbw {{.*#+}} zmm2 = [0,1,2,3,33,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,21,22,23,24,25,26,27,28,29,30,31] +; AVX512VBMI-NEXT: vpermi2w %zmm7, %zmm3, %zmm2 ; AVX512VBMI-NEXT: vmovdqa64 {{.*#+}} zmm3 = [67,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,68,u,u,u,u,u,u,u] ; AVX512VBMI-NEXT: vpermi2b %zmm7, %zmm4, %zmm3 ; AVX512VBMI-NEXT: vinserti32x4 $3, %xmm7, %zmm5, %zmm4 @@ -1967,17 +1969,15 @@ define <512 x i8> @PR153457(<512 x i8> %a0, <512 x i8> %a1) nounwind { ; AVX512VBMI-NEXT: vbroadcasti64x4 {{.*#+}} zmm5 = [16,17,18,19,35,0,0,0,8,9,10,11,12,13,14,15,16,17,18,19,35,0,0,0,8,9,10,11,12,13,14,15] ; AVX512VBMI-NEXT: # zmm5 = mem[0,1,2,3,0,1,2,3] ; AVX512VBMI-NEXT: vpermi2w %zmm7, %zmm8, %zmm5 -; AVX512VBMI-NEXT: vinserti64x4 $1, %ymm7, %zmm2, %zmm2 -; AVX512VBMI-NEXT: vpshufb {{.*#+}} zmm2 = zmm2[u,u,u,u,u,u,u,u,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,39,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u] -; AVX512VBMI-NEXT: vmovdqa64 {{.*#+}} zmm8 = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,65,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63] -; AVX512VBMI-NEXT: vpermi2b %zmm7, %zmm1, %zmm8 +; AVX512VBMI-NEXT: vinserti64x4 $1, %ymm7, %zmm1, %zmm1 +; AVX512VBMI-NEXT: vpshufb {{.*#+}} zmm1 = zmm1[u,u,u,u,u,u,u,u,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,39,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u,u] ; AVX512VBMI-NEXT: vmovdqa64 %zmm5, 320(%rdi) ; AVX512VBMI-NEXT: vmovdqa64 %zmm4, 256(%rdi) ; AVX512VBMI-NEXT: vmovdqa64 %zmm3, 192(%rdi) -; AVX512VBMI-NEXT: vmovdqa64 %zmm0, 128(%rdi) -; AVX512VBMI-NEXT: vmovdqa64 %zmm8, 64(%rdi) +; AVX512VBMI-NEXT: vmovdqa64 %zmm2, 128(%rdi) +; AVX512VBMI-NEXT: vmovdqa64 %zmm0, 64(%rdi) ; AVX512VBMI-NEXT: vmovdqa64 %zmm6, (%rdi) -; AVX512VBMI-NEXT: vmovdqa64 %zmm2, 384(%rdi) +; AVX512VBMI-NEXT: vmovdqa64 %zmm1, 384(%rdi) ; AVX512VBMI-NEXT: movq %rbp, %rsp ; AVX512VBMI-NEXT: popq %rbp ; AVX512VBMI-NEXT: vzeroupper @@ -2043,16 +2043,11 @@ define <64 x i8> @narrow_u32x16x4_to_u8x64(<64 x i8> %x0, <64 x i8> %x1, <64 x i ; ; AVX512VBMI-LABEL: narrow_u32x16x4_to_u8x64: ; AVX512VBMI: # %bb.0: -; AVX512VBMI-NEXT: vmovdqa64 {{.*#+}} zmm4 = [128,128,128,128,0,4,8,12,u,u,u,u,u,u,u,u,128,128,128,128,16,20,24,28,u,u,u,u,u,u,u,u,128,128,128,128,32,36,40,44,u,u,u,u,u,u,u,u,128,128,128,128,48,52,56,60,u,u,u,u,u,u,u,u] -; AVX512VBMI-NEXT: vpshufb %zmm4, %zmm1, %zmm1 -; AVX512VBMI-NEXT: vmovdqa64 {{.*#+}} zmm5 = [0,4,8,12,128,128,128,128,u,u,u,u,u,u,u,u,16,20,24,28,128,128,128,128,u,u,u,u,u,u,u,u,32,36,40,44,128,128,128,128,u,u,u,u,u,u,u,u,48,52,56,60,128,128,128,128,u,u,u,u,u,u,u,u] -; AVX512VBMI-NEXT: vpshufb %zmm5, %zmm0, %zmm0 -; AVX512VBMI-NEXT: vporq %zmm1, %zmm0, %zmm1 -; AVX512VBMI-NEXT: vpshufb %zmm4, %zmm3, %zmm0 -; AVX512VBMI-NEXT: vpshufb %zmm5, %zmm2, %zmm2 -; AVX512VBMI-NEXT: vporq %zmm0, %zmm2, %zmm2 -; AVX512VBMI-NEXT: vpmovsxbd {{.*#+}} zmm0 = [0,4,8,12,1,5,9,13,16,20,24,28,17,21,25,29] -; AVX512VBMI-NEXT: vpermi2d %zmm2, %zmm1, %zmm0 +; AVX512VBMI-NEXT: vmovdqa64 {{.*#+}} zmm4 = [0,4,8,12,64,68,72,76,u,u,u,u,u,u,u,u,16,20,24,28,80,84,88,92,u,u,u,u,u,u,u,u,32,36,40,44,96,100,104,108,u,u,u,u,u,u,u,u,48,52,56,60,112,116,120,124,u,u,u,u,u,u,u,u] +; AVX512VBMI-NEXT: vpermt2b %zmm1, %zmm4, %zmm0 +; AVX512VBMI-NEXT: vpermt2b %zmm3, %zmm4, %zmm2 +; AVX512VBMI-NEXT: vpmovsxbd {{.*#+}} zmm1 = [0,4,8,12,1,5,9,13,16,20,24,28,17,21,25,29] +; AVX512VBMI-NEXT: vpermt2d %zmm2, %zmm1, %zmm0 ; AVX512VBMI-NEXT: retq %lo = shufflevector <64 x i8> %x0, <64 x i8> %x1, <64 x i32> %hi = shufflevector <64 x i8> %x2, <64 x i8> %x3, <64 x i32> From 6db0725886bb9fafab67f2eb362d4b84354fe7de Mon Sep 17 00:00:00 2001 From: Simon Pilgrim Date: Tue, 24 Feb 2026 17:52:54 +0000 Subject: [PATCH 11/16] [X86] lowerV64I8Shuffle - avoid lowerShuffleAsRepeatedMaskAndLanePermute call on VBMI targets (#183109) Shuffle combining fails to fold the inner shuffles first, but luckily the LanePermuteAnd* methods are enough if we have VPERMB as a fallback Fixes #137422 (cherry picked from commit 1b9fea021840f17c41ea980300d0fc45e7285909) --- llvm/lib/Target/X86/X86ISelLowering.cpp | 12 ++++++++---- llvm/test/CodeGen/X86/vector-shuffle-512-v64.ll | 6 +++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp index ddd92c5422f53..8dfd800a18284 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -18004,9 +18004,12 @@ static SDValue lowerV64I8Shuffle(const SDLoc &DL, ArrayRef Mask, // Try to create an in-lane repeating shuffle mask and then shuffle the // results into the target lanes. - if (SDValue V = lowerShuffleAsRepeatedMaskAndLanePermute( - DL, MVT::v64i8, V1, V2, Mask, Subtarget, DAG)) - return V; + // FIXME: Avoid on VBMI targets as the post lane permute often interferes + // with shuffle combining (should be fixed by topological DAG sorting). + if (!Subtarget.hasVBMI()) + if (SDValue V = lowerShuffleAsRepeatedMaskAndLanePermute( + DL, MVT::v64i8, V1, V2, Mask, Subtarget, DAG)) + return V; if (SDValue Result = lowerShuffleAsLanePermuteAndPermute( DL, MVT::v64i8, V1, V2, Mask, DAG, Subtarget)) @@ -18047,7 +18050,8 @@ static SDValue lowerV64I8Shuffle(const SDLoc &DL, ArrayRef Mask, if (Subtarget.hasVBMI()) return lowerShuffleWithPERMV(DL, MVT::v64i8, Mask, V1, V2, Subtarget, DAG); - return splitAndLowerShuffle(DL, MVT::v64i8, V1, V2, Mask, DAG, /*SimpleOnly*/ false); + return splitAndLowerShuffle(DL, MVT::v64i8, V1, V2, Mask, DAG, + /*SimpleOnly*/ false); } /// High-level routine to lower various 512-bit x86 vector shuffles. diff --git a/llvm/test/CodeGen/X86/vector-shuffle-512-v64.ll b/llvm/test/CodeGen/X86/vector-shuffle-512-v64.ll index 02c2106451707..c20680a2bd855 100644 --- a/llvm/test/CodeGen/X86/vector-shuffle-512-v64.ll +++ b/llvm/test/CodeGen/X86/vector-shuffle-512-v64.ll @@ -2043,11 +2043,11 @@ define <64 x i8> @narrow_u32x16x4_to_u8x64(<64 x i8> %x0, <64 x i8> %x1, <64 x i ; ; AVX512VBMI-LABEL: narrow_u32x16x4_to_u8x64: ; AVX512VBMI: # %bb.0: -; AVX512VBMI-NEXT: vmovdqa64 {{.*#+}} zmm4 = [0,4,8,12,64,68,72,76,u,u,u,u,u,u,u,u,16,20,24,28,80,84,88,92,u,u,u,u,u,u,u,u,32,36,40,44,96,100,104,108,u,u,u,u,u,u,u,u,48,52,56,60,112,116,120,124,u,u,u,u,u,u,u,u] +; AVX512VBMI-NEXT: vbroadcasti64x4 {{.*#+}} zmm4 = [0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124] +; AVX512VBMI-NEXT: # zmm4 = mem[0,1,2,3,0,1,2,3] ; AVX512VBMI-NEXT: vpermt2b %zmm1, %zmm4, %zmm0 ; AVX512VBMI-NEXT: vpermt2b %zmm3, %zmm4, %zmm2 -; AVX512VBMI-NEXT: vpmovsxbd {{.*#+}} zmm1 = [0,4,8,12,1,5,9,13,16,20,24,28,17,21,25,29] -; AVX512VBMI-NEXT: vpermt2d %zmm2, %zmm1, %zmm0 +; AVX512VBMI-NEXT: vshufi64x2 {{.*#+}} zmm0 = zmm0[0,1,2,3],zmm2[4,5,6,7] ; AVX512VBMI-NEXT: retq %lo = shufflevector <64 x i8> %x0, <64 x i8> %x1, <64 x i32> %hi = shufflevector <64 x i8> %x2, <64 x i8> %x3, <64 x i32> From 294ae8d1e62a3bd238c411d22a109e0b38ddc363 Mon Sep 17 00:00:00 2001 From: Amy Kwan Date: Wed, 27 May 2026 09:27:11 -0400 Subject: [PATCH 12/16] [PowerPC] Drop invalid range metadata when lowering i64 load to fp in INT_TO_FP (#198705) When lowering an i64 load in LowerINT_TO_FP, we were forwarding the original !range metadata to a new f64 load. This is invalid because the metadata no longer matches the value type/semantics, and can trigger assertions when lowering i64 to fp (double or float) conversions. This patch fixes this by passing a nullptr for the Ranges operand when calling getLoad() and adds extra test cases to cover signed/unsigned i64 to f32/f64 conversions and to ensure they do not assert when the !range metadata is present. The assertion this patch attempts to fix is: ``` Assertion failed: (!MMO->getRanges() || (mdconst::extract(MMO->getRanges()->getOperand(0)) ->getBitWidth() == MemVT.getScalarSizeInBits() && MemVT.isInteger())) && "Range metadata and load type must match!" ``` This assert was originally seen when building Rust on AIX. (cherry picked from commit 78f5f7717a2e058c4d685feb3edb7d991efacbc2) --- llvm/lib/Target/PowerPC/PPCISelLowering.cpp | 4 +- llvm/test/CodeGen/PowerPC/ppc-i64-to-fp.ll | 100 ++++++++++++++++++++ 2 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 llvm/test/CodeGen/PowerPC/ppc-i64-to-fp.ll diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp index 56aa33fdd4098..48d76fe0452b1 100644 --- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -8822,8 +8822,10 @@ SDValue PPCTargetLowering::LowerINT_TO_FP(SDValue Op, MachineFunction &MF = DAG.getMachineFunction(); if (canReuseLoadAddress(SINT, MVT::i64, RLI, DAG)) { + // Drop range metadata, as this metadata becomes invalid for f64 bit + // reinterpretation of i64 values. Bits = DAG.getLoad(MVT::f64, dl, RLI.Chain, RLI.Ptr, RLI.MPI, - RLI.Alignment, RLI.MMOFlags(), RLI.AAInfo, RLI.Ranges); + RLI.Alignment, RLI.MMOFlags(), RLI.AAInfo, nullptr); if (RLI.ResChain) DAG.makeEquivalentMemoryOrdering(RLI.ResChain, Bits.getValue(1)); } else if (Subtarget.hasLFIWAX() && diff --git a/llvm/test/CodeGen/PowerPC/ppc-i64-to-fp.ll b/llvm/test/CodeGen/PowerPC/ppc-i64-to-fp.ll new file mode 100644 index 0000000000000..b6f58938d03bf --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/ppc-i64-to-fp.ll @@ -0,0 +1,100 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6 +; RUN: llc -mcpu=pwr8 -ppc-asm-full-reg-names -mtriple=powerpc64le-unknown-linux-gnu < %s | \ +; RUN: FileCheck %s --check-prefix=COMMON +; RUN: llc -mcpu=pwr8 -ppc-asm-full-reg-names -mtriple=powerpc64-ibm-aix < %s | \ +; RUN: FileCheck %s --check-prefix=COMMON +; RUN: llc -mcpu=pwr8 -ppc-asm-full-reg-names -mtriple=powerpc-ibm-aix < %s | \ +; RUN: FileCheck %s --check-prefix=CHECK-AIX32 + +; Test that assertions related to the range metadata when converting from i64 +; to i32 does not occur. + +define float @case_i64_uitofp_f32(ptr %p) { +; COMMON-LABEL: case_i64_uitofp_f32: +; COMMON: # %bb.0: # %entry +; COMMON-NEXT: lfd f0, 0(r3) +; COMMON-NEXT: xscvuxdsp f1, f0 +; COMMON-NEXT: blr +; +; CHECK-AIX32-LABEL: case_i64_uitofp_f32: +; CHECK-AIX32: # %bb.0: # %entry +; CHECK-AIX32-NEXT: lwz r4, 4(r3) +; CHECK-AIX32-NEXT: stw r4, -4(r1) +; CHECK-AIX32-NEXT: lwz r3, 0(r3) +; CHECK-AIX32-NEXT: stw r3, -8(r1) +; CHECK-AIX32-NEXT: lfd f0, -8(r1) +; CHECK-AIX32-NEXT: xscvuxdsp f1, f0 +; CHECK-AIX32-NEXT: blr +entry: + %x = load i64, ptr %p, align 8, !range !0 + %y = uitofp i64 %x to float + ret float %y +} + +define double @case_i64_sitofp_f64(ptr %p) { +; COMMON-LABEL: case_i64_sitofp_f64: +; COMMON: # %bb.0: # %entry +; COMMON-NEXT: lfd f0, 0(r3) +; COMMON-NEXT: xscvsxddp f1, f0 +; COMMON-NEXT: blr +; +; CHECK-AIX32-LABEL: case_i64_sitofp_f64: +; CHECK-AIX32: # %bb.0: # %entry +; CHECK-AIX32-NEXT: lwz r4, 4(r3) +; CHECK-AIX32-NEXT: stw r4, -4(r1) +; CHECK-AIX32-NEXT: lwz r3, 0(r3) +; CHECK-AIX32-NEXT: stw r3, -8(r1) +; CHECK-AIX32-NEXT: lfd f0, -8(r1) +; CHECK-AIX32-NEXT: xscvsxddp f1, f0 +; CHECK-AIX32-NEXT: blr +entry: + %x = load i64, ptr %p, align 8, !range !0 + %y = sitofp i64 %x to double + ret double %y +} + +define double @case_i64_uitofp_f64(ptr %p) { +; COMMON-LABEL: case_i64_uitofp_f64: +; COMMON: # %bb.0: # %entry +; COMMON-NEXT: lfd f0, 0(r3) +; COMMON-NEXT: xscvuxddp f1, f0 +; COMMON-NEXT: blr +; +; CHECK-AIX32-LABEL: case_i64_uitofp_f64: +; CHECK-AIX32: # %bb.0: # %entry +; CHECK-AIX32-NEXT: lwz r4, 4(r3) +; CHECK-AIX32-NEXT: stw r4, -4(r1) +; CHECK-AIX32-NEXT: lwz r3, 0(r3) +; CHECK-AIX32-NEXT: stw r3, -8(r1) +; CHECK-AIX32-NEXT: lfd f0, -8(r1) +; CHECK-AIX32-NEXT: xscvuxddp f1, f0 +; CHECK-AIX32-NEXT: blr +entry: + %x = load i64, ptr %p, align 8, !range !0 + %y = uitofp i64 %x to double + ret double %y +} + +define float @case_i64_sitofp_f32(ptr %p) { +; COMMON-LABEL: case_i64_sitofp_f32: +; COMMON: # %bb.0: # %entry +; COMMON-NEXT: lfd f0, 0(r3) +; COMMON-NEXT: xscvsxdsp f1, f0 +; COMMON-NEXT: blr +; +; CHECK-AIX32-LABEL: case_i64_sitofp_f32: +; CHECK-AIX32: # %bb.0: # %entry +; CHECK-AIX32-NEXT: lwz r4, 4(r3) +; CHECK-AIX32-NEXT: stw r4, -4(r1) +; CHECK-AIX32-NEXT: lwz r3, 0(r3) +; CHECK-AIX32-NEXT: stw r3, -8(r1) +; CHECK-AIX32-NEXT: lfd f0, -8(r1) +; CHECK-AIX32-NEXT: xscvsxdsp f1, f0 +; CHECK-AIX32-NEXT: blr +entry: + %x = load i64, ptr %p, align 8, !range !0 + %y = sitofp i64 %x to float + ret float %y +} + +!0 = !{i64 1, i64 0} From a760d7c07024feaf3b58212edd388a4f016a71ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Thu, 28 May 2026 11:03:51 +0300 Subject: [PATCH 13/16] [LLD] [COFF] Fix handling of immediates in ARM64_SECREL_HIGH12A (#200060) Just like for PAGEBASE_REL21, the immediate in SECREL_HIGH12A is the byte offset, not a page offset. The byte level offset is added to the symbol offset, which only then after that gets shifted right by 12. This makes the handling of this immediate consistent with what MS link.exe does. The existing testcase had a zero immediate in the instruction for this relocation. This makes it clear that immediate offsets with SECREL_HIGH12A do work fine, where the byte level offsets end up carrying over to the upper bits. (cherry picked from commit 5c95f6a859394757b92b0d63ff90b9175056deb6) --- lld/COFF/Chunks.cpp | 9 ++++++--- lld/test/COFF/arm64-relocs-imports.test | 10 +++++----- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp index 409491d4a1f89..efc9ff113e623 100644 --- a/lld/COFF/Chunks.cpp +++ b/lld/COFF/Chunks.cpp @@ -300,13 +300,16 @@ static void applySecRelHigh12A(const SectionChunk *sec, uint8_t *off, OutputSection *os, uint64_t s) { if (!checkSecRel(sec, os)) return; - uint64_t secRel = (s - os->getRVA()) >> 12; - if (0xfff < secRel) { + uint32_t orig = read32le(off); + uint64_t imm = (orig >> 10) & 0xFFF; + orig &= ~(0xFFF << 10); + imm = (s + imm - os->getRVA()) >> 12; + if (0xfff < imm) { error("overflow in SECREL_HIGH12A relocation in section: " + sec->getSectionName()); return; } - applyArm64Imm(off, secRel & 0xfff, 0); + write32le(off, orig | (imm << 10)); } static void applySecRelLdr(const SectionChunk *sec, uint8_t *off, diff --git a/lld/test/COFF/arm64-relocs-imports.test b/lld/test/COFF/arm64-relocs-imports.test index da2fd1f941d8a..c048a570674c7 100644 --- a/lld/test/COFF/arm64-relocs-imports.test +++ b/lld/test/COFF/arm64-relocs-imports.test @@ -39,8 +39,8 @@ # BEFORE: 74: 00000000 udf #0 # BEFORE: 78: 00000001 udf #1 # BEFORE: 7c: 00000001 udf #1 -# BEFORE: 80: 91000000 add x0, x0, #0 -# BEFORE: 84: 91400000 add x0, x0, #0, lsl #12 +# BEFORE: 80: 913c0000 add x0, x0, #3840 +# BEFORE: 84: 917c0000 add x0, x0, #3840, lsl #12 # BEFORE: 88: f9400000 ldr x0, [x0] # BEFORE: 8c: 00000001 udf #1 # BEFORE: 90: 30091a20 adr x0, 0x123d5 @@ -83,8 +83,8 @@ # AFTER: 140001074: 00000001 udf #1 # AFTER: 140001078: 00002009 udf #8201 # AFTER: 14000107c: 00000009 udf #9 -# AFTER: 140001080: 910e2000 add x0, x0, #904 -# AFTER: 140001084: 91400400 add x0, x0, #1, lsl #12 +# AFTER: 140001080: 910a2000 add x0, x0, #648 +# AFTER: 140001084: 91400800 add x0, x0, #2, lsl #12 # AFTER: 140001088: f941c400 ldr x0, [x0, #904] # AFTER: 14000108c: 00000003 udf #3 # AFTER: 140001090: 300995e0 adr x0, 0x14001434d @@ -104,7 +104,7 @@ sections: - Name: .text Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] Alignment: 4 - SectionData: FE0F1FF80000009000080091000000940001403900014079000140B9000140F90001003900010079000100B9000100F90001403D0001407D000140BD000140FD0001C03D0001003D0001007D000100BD000100FD0001803D000540F9201A01B000FC4FF9E0031F2AFE0741F8C0035FD6080000000000000001000000010000000000009100004091000040f901000000201a093001000054000000360100000002008090 + SectionData: FE0F1FF80000009000080091000000940001403900014079000140B9000140F90001003900010079000100B9000100F90001403D0001407D000140BD000140FD0001C03D0001003D0001007D000100BD000100FD0001803D000540F9201A01B000FC4FF9E0031F2AFE0741F8C0035FD60800000000000000010000000100000000003C9100007C91000040f901000000201a093001000054000000360100000002008090 Relocations: - VirtualAddress: 4 SymbolName: .Lstr From 2615295c15bab420d8134aff473c098a48403d42 Mon Sep 17 00:00:00 2001 From: Nikolas Klauser Date: Thu, 28 May 2026 19:35:34 +0200 Subject: [PATCH 14/16] [libc++] Fix multi{map,set}::extract not returning the first matching element (#199703) According to [associative.reqmts] `extract(k)` returns the _first_ element in the container with key equivalent to k. (cherry picked from commit 72871f6fa1f1edc3df45d01b67f5093ff9d8e8b5) --- libcxx/include/__tree | 4 ++-- .../multimap.modifiers/extract_key.pass.cpp | 13 +++++++++++++ .../associative/multiset/extract_key.pass.cpp | 13 +++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/libcxx/include/__tree b/libcxx/include/__tree index eb17f7d36936c..ddeb82f91b8ad 100644 --- a/libcxx/include/__tree +++ b/libcxx/include/__tree @@ -2026,8 +2026,8 @@ __tree<_Tp, _Compare, _Allocator>::__node_handle_insert_unique(const_iterator __ template template _LIBCPP_HIDE_FROM_ABI _NodeHandle __tree<_Tp, _Compare, _Allocator>::__node_handle_extract(key_type const& __key) { - iterator __it = find(__key); - if (__it == end()) + iterator __it = __lower_bound_multi(__key); + if (__it == end() || __value_comp_(__key, *__it)) return _NodeHandle(); return __node_handle_extract<_NodeHandle>(__it); } diff --git a/libcxx/test/std/containers/associative/multimap/multimap.modifiers/extract_key.pass.cpp b/libcxx/test/std/containers/associative/multimap/multimap.modifiers/extract_key.pass.cpp index b3027b3b0f727..42184edbdb8b6 100644 --- a/libcxx/test/std/containers/associative/multimap/multimap.modifiers/extract_key.pass.cpp +++ b/libcxx/test/std/containers/associative/multimap/multimap.modifiers/extract_key.pass.cpp @@ -50,6 +50,19 @@ int main(int, char**) { test(m, std::begin(keys), std::end(keys)); } + { // Check that the first element is returned + std::multimap m = {{1, 1}, {1, 2}, {1, 3}}; + auto ptr = std::addressof(m.begin()->first); + auto res = m.extract(1); + assert(std::addressof(res.key()) == ptr); + } + + { // Check that no element is returned if there is no match + std::multimap m = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}, {6, 6}}; + auto res = m.extract(0); + assert(!res); + } + { std::multimap, Counter> m = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}, {6, 6}}; { diff --git a/libcxx/test/std/containers/associative/multiset/extract_key.pass.cpp b/libcxx/test/std/containers/associative/multiset/extract_key.pass.cpp index 24d98cfaaf31a..ec75a6c5d835c 100644 --- a/libcxx/test/std/containers/associative/multiset/extract_key.pass.cpp +++ b/libcxx/test/std/containers/associative/multiset/extract_key.pass.cpp @@ -48,6 +48,19 @@ int main(int, char**) { test(m, std::begin(keys), std::end(keys)); } + { // Check that the first element is returned + std::multiset m = {1, 1, 1}; + auto ptr = std::addressof(*m.begin()); + auto res = m.extract(1); + assert(std::addressof(res.value()) == ptr); + } + + { // Check that no element is returned if there is no match + std::multiset m = {1, 2, 3}; + auto res = m.extract(0); + assert(!res); + } + { std::multiset> m = {1, 2, 3, 4, 5, 6}; { From a2b77904509333f5c9aa8e71427c694961e417c9 Mon Sep 17 00:00:00 2001 From: Dominik Steenken Date: Fri, 29 May 2026 14:16:22 +0200 Subject: [PATCH 15/16] [SystemZ] Fix off-by-one error in backend (#200141) When combineCCMask is called on a TM node with two constant operands, and all of the bits in the mask are active, the existing APInt bit access goes off the overall length of the integer by one. This commit fixes that by using the index value of the leftmost active bit, rather than the number of active bits. (cherry picked from commit 78eca55b542b6bca573f34a1b359fa949c3a8c89) --- .../Target/SystemZ/SystemZISelLowering.cpp | 2 +- .../CodeGen/SystemZ/combine-ccmask-tm-full.ll | 41 +++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 llvm/test/CodeGen/SystemZ/combine-ccmask-tm-full.ll diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp index c3ded986fd68e..48df65ab5871e 100644 --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp +++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -8843,7 +8843,7 @@ static bool combineCCMask(SDValue &CCReg, int &CCValid, int &CCMask, auto Result = Op0APVal & Op1APVal; bool AllOnes = Result == Op1APVal; bool AllZeros = Result == 0; - bool IsLeftMostBitSet = Result[Op1APVal.getActiveBits()] != 0; + bool IsLeftMostBitSet = Result[Op1APVal.getActiveBits() - 1] != 0; return AllZeros ? 0 : AllOnes ? 3 : IsLeftMostBitSet ? 2 : 1; }; SDValue Op0 = CCNode->getOperand(0); diff --git a/llvm/test/CodeGen/SystemZ/combine-ccmask-tm-full.ll b/llvm/test/CodeGen/SystemZ/combine-ccmask-tm-full.ll new file mode 100644 index 0000000000000..85ab999d00bd7 --- /dev/null +++ b/llvm/test/CodeGen/SystemZ/combine-ccmask-tm-full.ll @@ -0,0 +1,41 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6 +; Test that DAGCombiner doesn't crash when combining CCMask with TM instruction +; where all bits in the mask are active (off-by-one error regression test). +; +; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z10 | FileCheck %s + +define void @test_tm_full_mask(ptr %ptr) { +; CHECK-LABEL: test_tm_full_mask: +; CHECK: # %bb.0: +; CHECK-NEXT: lb %r0, 0(%r2) +; CHECK-NEXT: tmll %r0, 1 +; CHECK-NEXT: lhi %r1, 1 +; CHECK-NEXT: jne .LBB0_2 +; CHECK-NEXT: # %bb.1: +; CHECK-NEXT: lr %r1, %r0 +; CHECK-NEXT: .LBB0_2: +; CHECK-NEXT: tmll %r1, 1 +; CHECK-NEXT: je .LBB0_4 +; CHECK-NEXT: # %bb.3: # %if.then +; CHECK-NEXT: mvi 0(%r2), 1 +; CHECK-NEXT: .LBB0_4: # %loop +; CHECK-NEXT: # =>This Inner Loop Header: Depth=1 +; CHECK-NEXT: j .LBB0_4 + %1 = load i1, ptr %ptr, align 4 + %2 = freeze i1 %1 + %3 = select i1 %2, i32 0, i32 -1973148440 + %4 = trunc i32 %3 to i16 + %5 = or disjoint i16 %4, 1 + %6 = icmp ult i16 %5, 3 + %7 = and i32 %3, -1973157888 + %8 = icmp eq i32 %7, 0 + %9 = select i1 %6, i1 %8, i1 %2 + br i1 %9, label %if.then, label %loop + +if.then: + store i1 true, ptr %ptr, align 4 + br label %loop + +loop: + br label %loop +} From a255c1ed36a1d06f79bd2633ba9f8d900153007c Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Fri, 29 May 2026 08:38:12 -0700 Subject: [PATCH 16/16] [WebAssembly] Avoid crash in LateEHPrepare with empty cleanup pads (#200322) WebAssemblyLateEHPrepare::addCatchRefsAndThrowRefs was using Catch->getIterator()->getNextNode() to find the insertion position after the CATCH (or CATCH_ALL) instruction in an EH pad. If the CATCH/CATCH_ALL instruction is the last instruction in the basic block, getNextNode() returns nullptr, which causees a crash when passed to BuildMI. This patch fixes it by using std::next(Catch->getIterator()) which returns MBB.end() if the catch is the last instruction, and the overload of BuildMI that takes an iterator correctly handles BB.end(). Fixes #197077 Assisted-By: Gemini (cherry picked from commit dc40fccbc1f8fcd6d53c970efe199fc02464b986) --- .../WebAssembly/WebAssemblyLateEHPrepare.cpp | 3 ++- llvm/test/CodeGen/WebAssembly/exception.ll | 27 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp index 8ac32f939c5f2..3189ad37d2c49 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp @@ -312,7 +312,8 @@ bool WebAssemblyLateEHPrepare::addCatchRefsAndThrowRefs(MachineFunction &MF) { // caught exception is rethrown. And convert RETHROWs to THROW_REFs. for (auto &[EHPad, Rethrows] : EHPadToRethrows) { auto *Catch = WebAssembly::findCatch(EHPad); - auto *InsertPos = Catch->getIterator()->getNextNode(); + assert(Catch && "CATCH not found in EHPad"); + auto InsertPos = std::next(Catch->getIterator()); auto ExnReg = MRI.createVirtualRegister(&WebAssembly::EXNREFRegClass); if (Catch->getOpcode() == WebAssembly::CATCH) { MachineInstrBuilder MIB = BuildMI(*EHPad, InsertPos, Catch->getDebugLoc(), diff --git a/llvm/test/CodeGen/WebAssembly/exception.ll b/llvm/test/CodeGen/WebAssembly/exception.ll index 11e5be83d11cd..f738216d087ec 100644 --- a/llvm/test/CodeGen/WebAssembly/exception.ll +++ b/llvm/test/CodeGen/WebAssembly/exception.ll @@ -672,5 +672,32 @@ attributes #0 = { nounwind } attributes #1 = { noreturn } attributes #2 = { noreturn nounwind } +; CHECK-LABEL: empty_cleanup_pad: +; CHECK: try_table (catch_all_ref 0) +; CHECK: throw_ref +define void @empty_cleanup_pad(i32 %arg) personality ptr @__gxx_wasm_personality_v0 { +entry: + br label %loop + +loop: + invoke void @foo() + to label %loop unwind label %cleanup + +cleanup: + %exn = cleanuppad within none [] + br label %dispatch + +dispatch: ; preds = %cleanup, %dispatch + %cond = icmp eq i32 %arg, 0 + br i1 %cond, label %ret, label %dispatch + +ret: ; preds = %dispatch + cleanupret from %exn unwind label %cleanup2 + +cleanup2: ; preds = %ret + %exn2 = cleanuppad within none [] + ret void +} + ;; The exception tag should not be defined locally ; CHECK-NOT: __cpp_exception: