From ee99475068523de185dce0a449b65e684a1e6b73 Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Mon, 1 Apr 2024 15:41:38 -0400 Subject: [PATCH 001/447] [clang] Fix bitfield access unit for vbase corner case (#87238) This fixes #87227, a vbase can be placed below nvsize when empty members and/or bases are in play. We must account for that. --- clang/lib/CodeGen/CGRecordLayoutBuilder.cpp | 57 +++++++--- .../test/CodeGenCXX/bitfield-access-tail.cpp | 104 ++++++++++++------ 2 files changed, 113 insertions(+), 48 deletions(-) diff --git a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp index e32023aeac1e..634a55fec518 100644 --- a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -185,9 +185,10 @@ struct CGRecordLowering { /// Lowers an ASTRecordLayout to a llvm type. void lower(bool NonVirtualBaseType); void lowerUnion(bool isNoUniqueAddress); - void accumulateFields(); + void accumulateFields(bool isNonVirtualBaseType); RecordDecl::field_iterator - accumulateBitFields(RecordDecl::field_iterator Field, + accumulateBitFields(bool isNonVirtualBaseType, + RecordDecl::field_iterator Field, RecordDecl::field_iterator FieldEnd); void computeVolatileBitfields(); void accumulateBases(); @@ -195,8 +196,10 @@ struct CGRecordLowering { void accumulateVBases(); /// Recursively searches all of the bases to find out if a vbase is /// not the primary vbase of some base class. - bool hasOwnStorage(const CXXRecordDecl *Decl, const CXXRecordDecl *Query); + bool hasOwnStorage(const CXXRecordDecl *Decl, + const CXXRecordDecl *Query) const; void calculateZeroInit(); + CharUnits calculateTailClippingOffset(bool isNonVirtualBaseType) const; /// Lowers bitfield storage types to I8 arrays for bitfields with tail /// padding that is or can potentially be used. void clipTailPadding(); @@ -287,7 +290,7 @@ void CGRecordLowering::lower(bool NVBaseType) { computeVolatileBitfields(); return; } - accumulateFields(); + accumulateFields(NVBaseType); // RD implies C++. if (RD) { accumulateVPtrs(); @@ -378,12 +381,12 @@ void CGRecordLowering::lowerUnion(bool isNoUniqueAddress) { Packed = true; } -void CGRecordLowering::accumulateFields() { +void CGRecordLowering::accumulateFields(bool isNonVirtualBaseType) { for (RecordDecl::field_iterator Field = D->field_begin(), FieldEnd = D->field_end(); Field != FieldEnd;) { if (Field->isBitField()) { - Field = accumulateBitFields(Field, FieldEnd); + Field = accumulateBitFields(isNonVirtualBaseType, Field, FieldEnd); assert((Field == FieldEnd || !Field->isBitField()) && "Failed to accumulate all the bitfields"); } else if (Field->isZeroSize(Context)) { @@ -404,9 +407,12 @@ void CGRecordLowering::accumulateFields() { } // Create members for bitfields. Field is a bitfield, and FieldEnd is the end -// iterator of the record. Return the first non-bitfield encountered. +// iterator of the record. Return the first non-bitfield encountered. We need +// to know whether this is the base or complete layout, as virtual bases could +// affect the upper bound of bitfield access unit allocation. RecordDecl::field_iterator -CGRecordLowering::accumulateBitFields(RecordDecl::field_iterator Field, +CGRecordLowering::accumulateBitFields(bool isNonVirtualBaseType, + RecordDecl::field_iterator Field, RecordDecl::field_iterator FieldEnd) { if (isDiscreteBitFieldABI()) { // Run stores the first element of the current run of bitfields. FieldEnd is @@ -505,6 +511,10 @@ CGRecordLowering::accumulateBitFields(RecordDecl::field_iterator Field, bitsToCharUnits(Context.getTargetInfo().getRegisterWidth()); unsigned CharBits = Context.getCharWidth(); + // Limit of useable tail padding at end of the record. Computed lazily and + // cached here. + CharUnits ScissorOffset = CharUnits::Zero(); + // Data about the start of the span we're accumulating to create an access // unit from. Begin is the first bitfield of the span. If Begin is FieldEnd, // we've not got a current span. The span starts at the BeginOffset character @@ -630,10 +640,14 @@ CGRecordLowering::accumulateBitFields(RecordDecl::field_iterator Field, LimitOffset = bitsToCharUnits(getFieldBitOffset(*Probe)); goto FoundLimit; } - // We reached the end of the fields. We can't necessarily use tail - // padding in C++ structs, so the NonVirtual size is what we must - // use there. - LimitOffset = RD ? Layout.getNonVirtualSize() : Layout.getDataSize(); + // We reached the end of the fields, determine the bounds of useable + // tail padding. As this can be complex for C++, we cache the result. + if (ScissorOffset.isZero()) { + ScissorOffset = calculateTailClippingOffset(isNonVirtualBaseType); + assert(!ScissorOffset.isZero() && "Tail clipping at zero"); + } + + LimitOffset = ScissorOffset; FoundLimit:; CharUnits TypeSize = getSize(Type); @@ -838,13 +852,17 @@ void CGRecordLowering::accumulateVPtrs() { llvm::PointerType::getUnqual(Types.getLLVMContext()))); } -void CGRecordLowering::accumulateVBases() { +CharUnits +CGRecordLowering::calculateTailClippingOffset(bool isNonVirtualBaseType) const { + if (!RD) + return Layout.getDataSize(); + CharUnits ScissorOffset = Layout.getNonVirtualSize(); // In the itanium ABI, it's possible to place a vbase at a dsize that is // smaller than the nvsize. Here we check to see if such a base is placed // before the nvsize and set the scissor offset to that, instead of the // nvsize. - if (isOverlappingVBaseABI()) + if (!isNonVirtualBaseType && isOverlappingVBaseABI()) for (const auto &Base : RD->vbases()) { const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl(); if (BaseDecl->isEmpty()) @@ -856,8 +874,13 @@ void CGRecordLowering::accumulateVBases() { ScissorOffset = std::min(ScissorOffset, Layout.getVBaseClassOffset(BaseDecl)); } - Members.push_back(MemberInfo(ScissorOffset, MemberInfo::Scissor, nullptr, - RD)); + + return ScissorOffset; +} + +void CGRecordLowering::accumulateVBases() { + Members.push_back(MemberInfo(calculateTailClippingOffset(false), + MemberInfo::Scissor, nullptr, RD)); for (const auto &Base : RD->vbases()) { const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl(); if (BaseDecl->isEmpty()) @@ -882,7 +905,7 @@ void CGRecordLowering::accumulateVBases() { } bool CGRecordLowering::hasOwnStorage(const CXXRecordDecl *Decl, - const CXXRecordDecl *Query) { + const CXXRecordDecl *Query) const { const ASTRecordLayout &DeclLayout = Context.getASTRecordLayout(Decl); if (DeclLayout.isPrimaryBaseVirtual() && DeclLayout.getPrimaryBase() == Query) return false; diff --git a/clang/test/CodeGenCXX/bitfield-access-tail.cpp b/clang/test/CodeGenCXX/bitfield-access-tail.cpp index 68716fdf3b1d..1539e17cad43 100644 --- a/clang/test/CodeGenCXX/bitfield-access-tail.cpp +++ b/clang/test/CodeGenCXX/bitfield-access-tail.cpp @@ -2,45 +2,45 @@ // Configs that have cheap unaligned access // Little Endian -// RUN: %clang_cc1 -triple=aarch64-apple-darwin %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s -// RUN: %clang_cc1 -triple=aarch64-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=aarch64-apple-darwin %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT64 %s +// RUN: %clang_cc1 -triple=aarch64-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT64 %s // RUN: %clang_cc1 -triple=arm-apple-darwin %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT-DWN32 %s -// RUN: %clang_cc1 -triple=arm-none-eabi %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s -// RUN: %clang_cc1 -triple=i686-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s -// RUN: %clang_cc1 -triple=loongarch64-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s -// RUN: %clang_cc1 -triple=powerpcle-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s -// RUN: %clang_cc1 -triple=ve-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s -// RUN: %clang_cc1 -triple=wasm32 %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s -// RUN: %clang_cc1 -triple=wasm64 %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s -// RUN: %clang_cc1 -triple=x86_64-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=arm-none-eabi %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s +// RUN: %clang_cc1 -triple=i686-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s +// RUN: %clang_cc1 -triple=loongarch64-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT64 %s +// RUN: %clang_cc1 -triple=powerpcle-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s +// RUN: %clang_cc1 -triple=ve-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT64 %s +// RUN: %clang_cc1 -triple=wasm32 %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s +// RUN: %clang_cc1 -triple=wasm64 %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT64 %s +// RUN: %clang_cc1 -triple=x86_64-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT64 %s // Big Endian -// RUN: %clang_cc1 -triple=powerpc-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s -// RUN: %clang_cc1 -triple=powerpc64-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s -// RUN: %clang_cc1 -triple=systemz %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=powerpc-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s +// RUN: %clang_cc1 -triple=powerpc64-linux-gnu %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT64 %s +// RUN: %clang_cc1 -triple=systemz %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT64 %s // Configs that have expensive unaligned access // Little Endian -// RUN: %clang_cc1 -triple=amdgcn-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s -// RUN: %clang_cc1 -triple=arc-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s -// RUN: %clang_cc1 -triple=bpf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s -// RUN: %clang_cc1 -triple=csky %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s -// RUN: %clang_cc1 -triple=hexagon-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s -// RUN: %clang_cc1 -triple=le64-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s -// RUN: %clang_cc1 -triple=loongarch32-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s -// RUN: %clang_cc1 -triple=nvptx-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s -// RUN: %clang_cc1 -triple=riscv32 %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s -// RUN: %clang_cc1 -triple=riscv64 %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s -// RUN: %clang_cc1 -triple=spir-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s -// RUN: %clang_cc1 -triple=xcore-none-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=amdgcn-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT64 %s +// RUN: %clang_cc1 -triple=arc-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s +// RUN: %clang_cc1 -triple=bpf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT64 %s +// RUN: %clang_cc1 -triple=csky %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s +// RUN: %clang_cc1 -triple=hexagon-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s +// RUN: %clang_cc1 -triple=le64-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT64 %s +// RUN: %clang_cc1 -triple=loongarch32-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s +// RUN: %clang_cc1 -triple=nvptx-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s +// RUN: %clang_cc1 -triple=riscv32 %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s +// RUN: %clang_cc1 -triple=riscv64 %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT64 %s +// RUN: %clang_cc1 -triple=spir-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s +// RUN: %clang_cc1 -triple=xcore-none-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s // Big endian -// RUN: %clang_cc1 -triple=lanai-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s -// RUN: %clang_cc1 -triple=m68k-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s -// RUN: %clang_cc1 -triple=mips-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s -// RUN: %clang_cc1 -triple=mips64-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s -// RUN: %clang_cc1 -triple=sparc-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s -// RUN: %clang_cc1 -triple=tce-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT %s +// RUN: %clang_cc1 -triple=lanai-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s +// RUN: %clang_cc1 -triple=m68k-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s +// RUN: %clang_cc1 -triple=mips-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s +// RUN: %clang_cc1 -triple=mips64-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT64 %s +// RUN: %clang_cc1 -triple=sparc-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s +// RUN: %clang_cc1 -triple=tce-elf %s -emit-llvm -o /dev/null -fdump-record-layouts-simple | FileCheck --check-prefixes CHECK,LAYOUT,LAYOUT32 %s // Can use tail padding struct Pod { @@ -113,3 +113,45 @@ struct __attribute__((packed)) PNonPod { // LAYOUT-DWN32-NEXT: + +struct __attribute__((aligned(4))) Empty {} empty; + +struct Char { char a; } cbase; +struct D : virtual Char { + [[no_unique_address]] Empty e0; + [[no_unique_address]] Empty e1; + unsigned a : 24; // keep as 24bits +} d; +// CHECK-LABEL: LLVMType:%struct.D = +// LAYOUT64-SAME: type <{ ptr, [3 x i8], %struct.Char, [4 x i8] }> +// LAYOUT32-SAME: type { ptr, [3 x i8], %struct.Char } +// LAYOUT-DWN32-SAME: type { ptr, [3 x i8], %struct.Char } +// CHECK-NEXT: NonVirtualBaseLLVMType: +// LAYOUT64-SAME: %struct.D.base = type <{ ptr, i32 }> +// LAYOUT32-SAME: %struct.D = type { ptr, [3 x i8], %struct.Char } +// LAYOUT-DWN32-SAME: %struct.D = type { ptr, [3 x i8], %struct.Char } +// CHECK: BitFields:[ +// LAYOUT-NEXT: + +struct Int { int a; } ibase; +struct E : virtual Int { + [[no_unique_address]] Empty e0; + [[no_unique_address]] Empty e1; + unsigned a : 24; // expand to 32 +} e; +// CHECK-LABEL: LLVMType:%struct.E = +// LAYOUT64-SAME: type <{ ptr, i32, %struct.Int }> +// LAYOUT32-SAME: type { ptr, i32, %struct.Int } +// LAYOUT-DWN32-SAME: type { ptr, i32, %struct.Int } +// CHECK-NEXT: NonVirtualBaseLLVMType:%struct.E.base = +// LAYOUT64-SAME: type <{ ptr, i32 }> +// LAYOUT32-SAME: type { ptr, i32 } +// LAYOUT-DWN32-SAME: type { ptr, i32 } +// CHECK: BitFields:[ +// LAYOUT-NEXT: -- GitLab From ed6edf262d9061ce3c024754c4981299b5184ee2 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Mon, 1 Apr 2024 13:35:29 -0700 Subject: [PATCH 002/447] [scudo] Change isPowerOfTwo macro to return false for zero. (#87120) Clean-up all of the calls and remove the redundant == 0 checks. There is only one small visible change. For non-Android, the memalign function will now fail if alignment is zero. Before this would have passed. --- compiler-rt/lib/scudo/standalone/common.h | 6 +++++- compiler-rt/lib/scudo/standalone/stack_depot.h | 4 ++-- compiler-rt/lib/scudo/standalone/wrappers_c_checks.h | 6 ++---- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/compiler-rt/lib/scudo/standalone/common.h b/compiler-rt/lib/scudo/standalone/common.h index ae45683f1ee3..151fbd317e74 100644 --- a/compiler-rt/lib/scudo/standalone/common.h +++ b/compiler-rt/lib/scudo/standalone/common.h @@ -28,7 +28,11 @@ template inline Dest bit_cast(const Source &S) { return D; } -inline constexpr bool isPowerOfTwo(uptr X) { return (X & (X - 1)) == 0; } +inline constexpr bool isPowerOfTwo(uptr X) { + if (X == 0) + return false; + return (X & (X - 1)) == 0; +} inline constexpr uptr roundUp(uptr X, uptr Boundary) { DCHECK(isPowerOfTwo(Boundary)); diff --git a/compiler-rt/lib/scudo/standalone/stack_depot.h b/compiler-rt/lib/scudo/standalone/stack_depot.h index 98cd9707a646..0176c40aa899 100644 --- a/compiler-rt/lib/scudo/standalone/stack_depot.h +++ b/compiler-rt/lib/scudo/standalone/stack_depot.h @@ -103,7 +103,7 @@ public: // Ensure that RingSize, RingMask and TabMask are set up in a way that // all accesses are within range of BufSize. bool isValid(uptr BufSize) const { - if (RingSize == 0 || !isPowerOfTwo(RingSize)) + if (!isPowerOfTwo(RingSize)) return false; uptr RingBytes = sizeof(atomic_u64) * RingSize; if (RingMask + 1 != RingSize) @@ -112,7 +112,7 @@ public: if (TabMask == 0) return false; uptr TabSize = TabMask + 1; - if (TabSize == 0 || !isPowerOfTwo(TabSize)) + if (!isPowerOfTwo(TabSize)) return false; uptr TabBytes = sizeof(atomic_u32) * TabSize; diff --git a/compiler-rt/lib/scudo/standalone/wrappers_c_checks.h b/compiler-rt/lib/scudo/standalone/wrappers_c_checks.h index 9cd48e82792e..d0288699cf1b 100644 --- a/compiler-rt/lib/scudo/standalone/wrappers_c_checks.h +++ b/compiler-rt/lib/scudo/standalone/wrappers_c_checks.h @@ -31,15 +31,13 @@ inline void *setErrnoOnNull(void *Ptr) { // Checks aligned_alloc() parameters, verifies that the alignment is a power of // two and that the size is a multiple of alignment. inline bool checkAlignedAllocAlignmentAndSize(uptr Alignment, uptr Size) { - return Alignment == 0 || !isPowerOfTwo(Alignment) || - !isAligned(Size, Alignment); + return !isPowerOfTwo(Alignment) || !isAligned(Size, Alignment); } // Checks posix_memalign() parameters, verifies that alignment is a power of two // and a multiple of sizeof(void *). inline bool checkPosixMemalignAlignment(uptr Alignment) { - return Alignment == 0 || !isPowerOfTwo(Alignment) || - !isAligned(Alignment, sizeof(void *)); + return !isPowerOfTwo(Alignment) || !isAligned(Alignment, sizeof(void *)); } // Returns true if calloc(Size, N) overflows on Size*N calculation. Use a -- GitLab From e93b5f5a4776ffea12d03652559dfdf8d421184c Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Mon, 1 Apr 2024 13:05:34 -0700 Subject: [PATCH 003/447] [ubsan][NFC] Remove recently added `cl::init(false)` Extracted from #84858 --- clang/lib/CodeGen/BackendUtil.cpp | 7 +++---- clang/lib/CodeGen/CGExpr.cpp | 3 +-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index 82b30b8d8156..1220c575d1df 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -101,20 +101,19 @@ namespace llvm { extern cl::opt PrintPipelinePasses; cl::opt ClRemoveTraps("clang-remove-traps", cl::Optional, - cl::desc("Insert remove-traps pass."), - cl::init(false)); + cl::desc("Insert remove-traps pass.")); // Experiment to move sanitizers earlier. static cl::opt ClSanitizeOnOptimizerEarlyEP( "sanitizer-early-opt-ep", cl::Optional, - cl::desc("Insert sanitizers on OptimizerEarlyEP."), cl::init(false)); + cl::desc("Insert sanitizers on OptimizerEarlyEP.")); extern cl::opt ProfileCorrelate; // Re-link builtin bitcodes after optimization cl::opt ClRelinkBuiltinBitcodePostop( "relink-builtin-bitcode-postop", cl::Optional, - cl::desc("Re-link builtin bitcodes after optimization."), cl::init(false)); + cl::desc("Re-link builtin bitcodes after optimization.")); } // namespace llvm namespace { diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index e0d5575d57d0..54432353e742 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -56,8 +56,7 @@ using namespace CodeGen; // Experiment to make sanitizers easier to debug static llvm::cl::opt ClSanitizeDebugDeoptimization( "ubsan-unique-traps", llvm::cl::Optional, - llvm::cl::desc("Deoptimize traps for UBSAN so there is 1 trap per check"), - llvm::cl::init(false)); + llvm::cl::desc("Deoptimize traps for UBSAN so there is 1 trap per check")); //===--------------------------------------------------------------------===// // Miscellaneous Helper Methods -- GitLab From b8cc3ba409dc850776f37e27613bf74f5a80d66a Mon Sep 17 00:00:00 2001 From: Lei Wang Date: Mon, 1 Apr 2024 13:54:54 -0700 Subject: [PATCH 004/447] [PseudoProbe] Extend to skip instrumenting probe into the dests of invoke (#79919) As before we only skip instrumenting probe of `unwind`(`KnownColdBlock`) block, this PR extends to skip the both EH flow from `invoke`, i.e. also skip the `normal` dest. For more contexts: when doing call-to-invoke conversion, the block is split by the `invoke` and two extra blocks(`normal` and `unwind`) are added. With this PR, the instrumentation is the same as the one before the call-to-invoke conversion. One significant benefit is this can help mitigate the "unstable IR" issue(https://discourse.llvm.org/t/ipo-for-linkonce-odr-functions/69404), the two versions now are on the same probe instrumentation, expected to be the same checksum. To achieve the same checksum, some tweaks is needed: - Now it also skips incrementing the probe ID for the skipped probe. - The checksum is also computed based on the CFG that skips the EH edges. We observed this fixes ~5% mismatched samples. --- llvm/include/llvm/Analysis/EHUtils.h | 1 - .../llvm/Transforms/IPO/SampleProfileProbe.h | 13 +- .../lib/Transforms/IPO/SampleProfileProbe.cpp | 121 ++++++++++++-- .../ThinLTO/X86/pseudo-probe-desc-import.ll | 4 +- .../SampleProfile/pseudo-probe-eh.ll | 2 +- .../SampleProfile/pseudo-probe-invoke.ll | 155 ++++++++++++++++++ 6 files changed, 276 insertions(+), 20 deletions(-) create mode 100644 llvm/test/Transforms/SampleProfile/pseudo-probe-invoke.ll diff --git a/llvm/include/llvm/Analysis/EHUtils.h b/llvm/include/llvm/Analysis/EHUtils.h index f2ff6cbd2e90..3ad0878bd64f 100644 --- a/llvm/include/llvm/Analysis/EHUtils.h +++ b/llvm/include/llvm/Analysis/EHUtils.h @@ -79,7 +79,6 @@ static void computeEHOnlyBlocks(FunctionT &F, DenseSet &EHBlocks) { } } - EHBlocks.clear(); for (auto Entry : Statuses) { if (Entry.second == EH) EHBlocks.insert(Entry.first); diff --git a/llvm/include/llvm/Transforms/IPO/SampleProfileProbe.h b/llvm/include/llvm/Transforms/IPO/SampleProfileProbe.h index 0f2729a9462d..03aa93ce6bd3 100644 --- a/llvm/include/llvm/Transforms/IPO/SampleProfileProbe.h +++ b/llvm/include/llvm/Transforms/IPO/SampleProfileProbe.h @@ -81,8 +81,17 @@ private: uint64_t getFunctionHash() const { return FunctionHash; } uint32_t getBlockId(const BasicBlock *BB) const; uint32_t getCallsiteId(const Instruction *Call) const; - void computeCFGHash(); - void computeProbeIdForBlocks(); + void findUnreachableBlocks(DenseSet &BlocksToIgnore); + void findInvokeNormalDests(DenseSet &InvokeNormalDests); + void computeBlocksToIgnore(DenseSet &BlocksToIgnore, + DenseSet &BlocksAndCallsToIgnore); + void computeProbeIdForCallsites( + const DenseSet &BlocksAndCallsToIgnore); + const Instruction * + getOriginalTerminator(const BasicBlock *Head, + const DenseSet &BlocksToIgnore); + void computeCFGHash(const DenseSet &BlocksToIgnore); + void computeProbeIdForBlocks(const DenseSet &BlocksToIgnore); void computeProbeIdForCallsites(); Function *F; diff --git a/llvm/lib/Transforms/IPO/SampleProfileProbe.cpp b/llvm/lib/Transforms/IPO/SampleProfileProbe.cpp index 090e5560483e..4d0fa24bd57c 100644 --- a/llvm/lib/Transforms/IPO/SampleProfileProbe.cpp +++ b/llvm/lib/Transforms/IPO/SampleProfileProbe.cpp @@ -173,21 +173,114 @@ SampleProfileProber::SampleProfileProber(Function &Func, BlockProbeIds.clear(); CallProbeIds.clear(); LastProbeId = (uint32_t)PseudoProbeReservedId::Last; - computeProbeIdForBlocks(); - computeProbeIdForCallsites(); - computeCFGHash(); + + DenseSet BlocksToIgnore; + DenseSet BlocksAndCallsToIgnore; + computeBlocksToIgnore(BlocksToIgnore, BlocksAndCallsToIgnore); + + computeProbeIdForBlocks(BlocksToIgnore); + computeProbeIdForCallsites(BlocksAndCallsToIgnore); + computeCFGHash(BlocksToIgnore); +} + +// Two purposes to compute the blocks to ignore: +// 1. Reduce the IR size. +// 2. Make the instrumentation(checksum) stable. e.g. the frondend may +// generate unstable IR while optimizing nounwind attribute, some versions are +// optimized with the call-to-invoke conversion, while other versions do not. +// This discrepancy in probe ID could cause profile mismatching issues. +// Note that those ignored blocks are either cold blocks or new split blocks +// whose original blocks are instrumented, so it shouldn't degrade the profile +// quality. +void SampleProfileProber::computeBlocksToIgnore( + DenseSet &BlocksToIgnore, + DenseSet &BlocksAndCallsToIgnore) { + // Ignore the cold EH and unreachable blocks and calls. + computeEHOnlyBlocks(*F, BlocksAndCallsToIgnore); + findUnreachableBlocks(BlocksAndCallsToIgnore); + + BlocksToIgnore.insert(BlocksAndCallsToIgnore.begin(), + BlocksAndCallsToIgnore.end()); + + // Handle the call-to-invoke conversion case: make sure that the probe id and + // callsite id are consistent before and after the block split. For block + // probe, we only keep the head block probe id and ignore the block ids of the + // normal dests. For callsite probe, it's different to block probe, there is + // no additional callsite in the normal dests, so we don't ignore the + // callsites. + findInvokeNormalDests(BlocksToIgnore); +} + +// Unreachable blocks and calls are always cold, ignore them. +void SampleProfileProber::findUnreachableBlocks( + DenseSet &BlocksToIgnore) { + for (auto &BB : *F) { + if (&BB != &F->getEntryBlock() && pred_size(&BB) == 0) + BlocksToIgnore.insert(&BB); + } +} + +// In call-to-invoke conversion, basic block can be split into multiple blocks, +// only instrument probe in the head block, ignore the normal dests. +void SampleProfileProber::findInvokeNormalDests( + DenseSet &InvokeNormalDests) { + for (auto &BB : *F) { + auto *TI = BB.getTerminator(); + if (auto *II = dyn_cast(TI)) { + auto *ND = II->getNormalDest(); + InvokeNormalDests.insert(ND); + + // The normal dest and the try/catch block are connected by an + // unconditional branch. + while (pred_size(ND) == 1) { + auto *Pred = *pred_begin(ND); + if (succ_size(Pred) == 1) { + InvokeNormalDests.insert(Pred); + ND = Pred; + } else + break; + } + } + } +} + +// The call-to-invoke conversion splits the original block into a list of block, +// we need to compute the hash using the original block's successors to keep the +// CFG Hash consistent. For a given head block, we keep searching the +// succesor(normal dest or unconditional branch dest) to find the tail block, +// the tail block's successors are the original block's successors. +const Instruction *SampleProfileProber::getOriginalTerminator( + const BasicBlock *Head, const DenseSet &BlocksToIgnore) { + auto *TI = Head->getTerminator(); + if (auto *II = dyn_cast(TI)) { + return getOriginalTerminator(II->getNormalDest(), BlocksToIgnore); + } else if (succ_size(Head) == 1 && + BlocksToIgnore.contains(*succ_begin(Head))) { + // Go to the unconditional branch dest. + return getOriginalTerminator(*succ_begin(Head), BlocksToIgnore); + } + return TI; } // Compute Hash value for the CFG: the lower 32 bits are CRC32 of the index // value of each BB in the CFG. The higher 32 bits record the number of edges // preceded by the number of indirect calls. // This is derived from FuncPGOInstrumentation::computeCFGHash(). -void SampleProfileProber::computeCFGHash() { +void SampleProfileProber::computeCFGHash( + const DenseSet &BlocksToIgnore) { std::vector Indexes; JamCRC JC; for (auto &BB : *F) { - for (BasicBlock *Succ : successors(&BB)) { + if (BlocksToIgnore.contains(&BB)) + continue; + + auto *TI = getOriginalTerminator(&BB, BlocksToIgnore); + for (unsigned I = 0, E = TI->getNumSuccessors(); I != E; ++I) { + auto *Succ = TI->getSuccessor(I); auto Index = getBlockId(Succ); + // Ingore ignored-block(zero ID) to avoid unstable checksum. + if (Index == 0) + continue; for (int J = 0; J < 4; J++) Indexes.push_back((uint8_t)(Index >> (J * 8))); } @@ -207,23 +300,23 @@ void SampleProfileProber::computeCFGHash() { << ", Hash = " << FunctionHash << "\n"); } -void SampleProfileProber::computeProbeIdForBlocks() { - DenseSet KnownColdBlocks; - computeEHOnlyBlocks(*F, KnownColdBlocks); - // Insert pseudo probe to non-cold blocks only. This will reduce IR size as - // well as the binary size while retaining the profile quality. +void SampleProfileProber::computeProbeIdForBlocks( + const DenseSet &BlocksToIgnore) { for (auto &BB : *F) { - ++LastProbeId; - if (!KnownColdBlocks.contains(&BB)) - BlockProbeIds[&BB] = LastProbeId; + if (BlocksToIgnore.contains(&BB)) + continue; + BlockProbeIds[&BB] = ++LastProbeId; } } -void SampleProfileProber::computeProbeIdForCallsites() { +void SampleProfileProber::computeProbeIdForCallsites( + const DenseSet &BlocksAndCallsToIgnore) { LLVMContext &Ctx = F->getContext(); Module *M = F->getParent(); for (auto &BB : *F) { + if (BlocksAndCallsToIgnore.contains(&BB)) + continue; for (auto &I : BB) { if (!isa(I)) continue; diff --git a/llvm/test/ThinLTO/X86/pseudo-probe-desc-import.ll b/llvm/test/ThinLTO/X86/pseudo-probe-desc-import.ll index 21dd8c0fe924..f915aaccc06e 100644 --- a/llvm/test/ThinLTO/X86/pseudo-probe-desc-import.ll +++ b/llvm/test/ThinLTO/X86/pseudo-probe-desc-import.ll @@ -12,8 +12,8 @@ ; RUN: llvm-lto -thinlto-action=import %t3.bc -thinlto-index=%t3.index.bc -o /dev/null 2>&1 | FileCheck %s --check-prefix=WARN -; CHECK-NOT: {i64 6699318081062747564, i64 4294967295, !"foo" -; CHECK: !{i64 -2624081020897602054, i64 281479271677951, !"main" +; CHECK-NOT: {i64 6699318081062747564, i64 [[#]], !"foo" +; CHECK: !{i64 -2624081020897602054, i64 [[#]], !"main" ; WARN: warning: Pseudo-probe ignored: source module '{{.*}}' is compiled with -fpseudo-probe-for-profiling while destination module '{{.*}}' is not diff --git a/llvm/test/Transforms/SampleProfile/pseudo-probe-eh.ll b/llvm/test/Transforms/SampleProfile/pseudo-probe-eh.ll index 697ef44fb7ed..9954914bca43 100644 --- a/llvm/test/Transforms/SampleProfile/pseudo-probe-eh.ll +++ b/llvm/test/Transforms/SampleProfile/pseudo-probe-eh.ll @@ -18,7 +18,7 @@ entry: to label %ret unwind label %lpad ret: -; CHECK: call void @llvm.pseudoprobe +; CHECK-NOT: call void @llvm.pseudoprobe ret void lpad: ; preds = %entry diff --git a/llvm/test/Transforms/SampleProfile/pseudo-probe-invoke.ll b/llvm/test/Transforms/SampleProfile/pseudo-probe-invoke.ll new file mode 100644 index 000000000000..822ab403dee2 --- /dev/null +++ b/llvm/test/Transforms/SampleProfile/pseudo-probe-invoke.ll @@ -0,0 +1,155 @@ +; REQUIRES: x86_64-linux +; RUN: opt < %s -passes=pseudo-probe -S -o - | FileCheck %s + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +$__clang_call_terminate = comdat any + +@x = dso_local global i32 0, align 4, !dbg !0 + +; Function Attrs: mustprogress noinline nounwind uwtable +define dso_local void @_Z3barv() #0 personality ptr @__gxx_personality_v0 !dbg !14 { +entry: +; CHECK: call void @llvm.pseudoprobe(i64 -1069303473483922844, i64 1 + %0 = load volatile i32, ptr @x, align 4, !dbg !17, !tbaa !19 + %tobool = icmp ne i32 %0, 0, !dbg !17 + br i1 %tobool, label %if.then, label %if.else, !dbg !23 + +if.then: ; preds = %entry +; CHECK: call void @llvm.pseudoprobe(i64 -1069303473483922844, i64 2 + invoke void @_Z3foov() + to label %invoke.cont unwind label %terminate.lpad, !dbg !24 + +invoke.cont: ; preds = %if.then +; CHECK-NOT: call void @llvm.pseudoprobe(i64 -1069303473483922844, + invoke void @_Z3bazv() + to label %invoke.cont1 unwind label %terminate.lpad, !dbg !26 + +invoke.cont1: ; preds = %invoke.cont +; CHECK-NOT: call void @llvm.pseudoprobe(i64 -1069303473483922844, + br label %if.end, !dbg !27 + +if.else: ; preds = %entry +; CHECK: call void @llvm.pseudoprobe(i64 -1069303473483922844, i64 3 + invoke void @_Z3foov() + to label %invoke.cont2 unwind label %terminate.lpad, !dbg !28 + +invoke.cont2: ; preds = %if.else +; CHECK-NOT: call void @llvm.pseudoprobe(i64 -1069303473483922844, + br label %if.end + +if.end: ; preds = %invoke.cont2, %invoke.cont1 +; CHECK: call void @llvm.pseudoprobe(i64 -1069303473483922844, i64 4 + invoke void @_Z3foov() + to label %invoke.cont3 unwind label %terminate.lpad, !dbg !29 + +invoke.cont3: ; preds = %if.end +; CHECK-NOT: call void @llvm.pseudoprobe(i64 -1069303473483922844, + %1 = load volatile i32, ptr @x, align 4, !dbg !30, !tbaa !19 + %tobool4 = icmp ne i32 %1, 0, !dbg !30 + br i1 %tobool4, label %if.then5, label %if.end6, !dbg !32 + +if.then5: ; preds = %invoke.cont3 +; CHECK: call void @llvm.pseudoprobe(i64 -1069303473483922844, i64 5 + %2 = load volatile i32, ptr @x, align 4, !dbg !33, !tbaa !19 + %inc = add nsw i32 %2, 1, !dbg !33 + store volatile i32 %inc, ptr @x, align 4, !dbg !33, !tbaa !19 + br label %if.end6, !dbg !35 + +if.end6: ; preds = %if.then5, %invoke.cont3 +; CHECK: call void @llvm.pseudoprobe(i64 -1069303473483922844, i64 6 + ret void, !dbg !36 + +terminate.lpad: ; preds = %if.end, %if.else, %invoke.cont, %if.then +; CHECK-NOT: call void @llvm.pseudoprobe(i64 -1069303473483922844, + %3 = landingpad { ptr, i32 } + catch ptr null, !dbg !24 + %4 = extractvalue { ptr, i32 } %3, 0, !dbg !24 + call void @__clang_call_terminate(ptr %4) #3, !dbg !24 + unreachable, !dbg !24 +} + +; Function Attrs: mustprogress noinline nounwind uwtable +define dso_local void @_Z3foov() #0 !dbg !37 { +entry: + ret void, !dbg !38 +} + +declare i32 @__gxx_personality_v0(...) + +; Function Attrs: noinline noreturn nounwind uwtable +define linkonce_odr hidden void @__clang_call_terminate(ptr noundef %0) #1 comdat { + %2 = call ptr @__cxa_begin_catch(ptr %0) #4 + call void @_ZSt9terminatev() #3 + unreachable +} + +declare ptr @__cxa_begin_catch(ptr) + +declare void @_ZSt9terminatev() + +; Function Attrs: mustprogress noinline nounwind uwtable +define dso_local void @_Z3bazv() #0 !dbg !39 { +entry: + ret void, !dbg !40 +} + +; CHECK: ![[#]] = !{i64 -3270123626113159616, i64 4294967295, !"_Z3bazv"} + +attributes #0 = { mustprogress noinline nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #1 = { noinline noreturn nounwind uwtable "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #2 = { mustprogress noinline norecurse nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #3 = { noreturn nounwind } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!7, !8, !9, !10, !11, !12} +!llvm.ident = !{!13} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "x", scope: !2, file: !3, line: 1, type: !5, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 19.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "test.cpp", directory: "/home", checksumkind: CSK_MD5, checksum: "a4c7b0392f3fd9c8ebb85065159dbb02") +!4 = !{!0} +!5 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !6) +!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!7 = !{i32 7, !"Dwarf Version", i32 5} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{i32 8, !"PIC Level", i32 2} +!11 = !{i32 7, !"PIE Level", i32 2} +!12 = !{i32 7, !"uwtable", i32 2} +!13 = !{!"clang version 19.0.0"} +!14 = distinct !DISubprogram(name: "bar", linkageName: "_Z3barv", scope: !3, file: !3, line: 4, type: !15, scopeLine: 4, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2) +!15 = !DISubroutineType(types: !16) +!16 = !{null} +!17 = !DILocation(line: 5, column: 6, scope: !18) +!18 = distinct !DILexicalBlock(scope: !14, file: !3, line: 5, column: 6) +!19 = !{!20, !20, i64 0} +!20 = !{!"int", !21, i64 0} +!21 = !{!"omnipotent char", !22, i64 0} +!22 = !{!"Simple C++ TBAA"} +!23 = !DILocation(line: 5, column: 6, scope: !14) +!24 = !DILocation(line: 6, column: 5, scope: !25) +!25 = distinct !DILexicalBlock(scope: !18, file: !3, line: 5, column: 9) +!26 = !DILocation(line: 7, column: 5, scope: !25) +!27 = !DILocation(line: 8, column: 3, scope: !25) +!28 = !DILocation(line: 9, column: 5, scope: !18) +!29 = !DILocation(line: 11, column: 3, scope: !14) +!30 = !DILocation(line: 12, column: 6, scope: !31) +!31 = distinct !DILexicalBlock(scope: !14, file: !3, line: 12, column: 6) +!32 = !DILocation(line: 12, column: 6, scope: !14) +!33 = !DILocation(line: 13, column: 5, scope: !34) +!34 = distinct !DILexicalBlock(scope: !31, file: !3, line: 12, column: 9) +!35 = !DILocation(line: 14, column: 5, scope: !34) +!36 = !DILocation(line: 17, column: 1, scope: !14) +!37 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !3, file: !3, line: 19, type: !15, scopeLine: 19, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2) +!38 = !DILocation(line: 19, column: 13, scope: !37) +!39 = distinct !DISubprogram(name: "baz", linkageName: "_Z3bazv", scope: !3, file: !3, line: 18, type: !15, scopeLine: 18, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2) +!40 = !DILocation(line: 18, column: 13, scope: !39) +!41 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 22, type: !42, scopeLine: 22, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2) +!42 = !DISubroutineType(types: !43) +!43 = !{!6} +!44 = !DILocation(line: 23, column: 3, scope: !41) +!45 = !DILocation(line: 24, column: 1, scope: !41) -- GitLab From f2f01f6b03aa81d5bdbf841a88f8853620c6902b Mon Sep 17 00:00:00 2001 From: Jeff Niu Date: Mon, 1 Apr 2024 13:59:53 -0700 Subject: [PATCH 005/447] [llvm][Support] Use `thread_local` caching for llvm::get_threadid() query on Apple systems (#87219) I was profiling our compiler and noticed that `llvm::get_threadid` was at the top of the hotlist, taking up a surprising 5% (7 seconds) in the profile trace. It seems that computing this on MacOS systems is non-trivial, so cache the result in a thread_local. Co-authored-by: Mehdi Amini --- llvm/lib/Support/Unix/Threading.inc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Support/Unix/Threading.inc b/llvm/lib/Support/Unix/Threading.inc index 55e7dcfa4678..839c00c5ebbf 100644 --- a/llvm/lib/Support/Unix/Threading.inc +++ b/llvm/lib/Support/Unix/Threading.inc @@ -115,8 +115,11 @@ uint64_t llvm::get_threadid() { // Calling "mach_thread_self()" bumps the reference count on the thread // port, so we need to deallocate it. mach_task_self() doesn't bump the ref // count. - thread_port_t Self = mach_thread_self(); - mach_port_deallocate(mach_task_self(), Self); + static thread_local thread_port_t Self = [] { + thread_port_t InitSelf = mach_thread_self(); + mach_port_deallocate(mach_task_self(), Self); + return InitSelf; + }(); return Self; #elif defined(__FreeBSD__) return uint64_t(pthread_getthreadid_np()); -- GitLab From a6caceed8d27d4ebd44c517c3114a36a64ebddfe Mon Sep 17 00:00:00 2001 From: Jordan Rupprecht Date: Mon, 1 Apr 2024 16:02:12 -0500 Subject: [PATCH 006/447] [lldb] Don't crash when attempting to parse breakpoint id `N.` as `N.*` (#87263) We check if the next character after `N.` is `*` before we check its length. Using `split` on the string is cleaner and less error prone than using indices with `find` and `substr`. Note: this does not make `N.` mean anything, it just prevents assertion failures. `N.` is treated the same as an unrecognized breakpoint name: ``` (lldb) breakpoint enable 1 1 breakpoints enabled. (lldb) breakpoint enable 1.* 1 breakpoints enabled. (lldb) breakpoint enable 1. 0 breakpoints enabled. (lldb) breakpoint enable xyz 0 breakpoints enabled. ``` Found via LLDB fuzzers. --- lldb/source/Breakpoint/BreakpointIDList.cpp | 48 +++++++++---------- .../TestBreakpointLocations.py | 6 +++ 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/lldb/source/Breakpoint/BreakpointIDList.cpp b/lldb/source/Breakpoint/BreakpointIDList.cpp index 851d074e7535..97af1d40eb7a 100644 --- a/lldb/source/Breakpoint/BreakpointIDList.cpp +++ b/lldb/source/Breakpoint/BreakpointIDList.cpp @@ -16,6 +16,7 @@ #include "lldb/Utility/StreamString.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" using namespace lldb; using namespace lldb_private; @@ -111,32 +112,27 @@ llvm::Error BreakpointIDList::FindAndReplaceIDRanges( } else { // See if user has specified id.* llvm::StringRef tmp_str = old_args[i].ref(); - size_t pos = tmp_str.find('.'); - if (pos != llvm::StringRef::npos) { - llvm::StringRef bp_id_str = tmp_str.substr(0, pos); - if (BreakpointID::IsValidIDExpression(bp_id_str) && - tmp_str[pos + 1] == '*' && tmp_str.size() == (pos + 2)) { - - BreakpointSP breakpoint_sp; - auto bp_id = BreakpointID::ParseCanonicalReference(bp_id_str); - if (bp_id) - breakpoint_sp = target->GetBreakpointByID(bp_id->GetBreakpointID()); - if (!breakpoint_sp) { - new_args.Clear(); - return llvm::createStringError( - llvm::inconvertibleErrorCode(), - "'%d' is not a valid breakpoint ID.\n", - bp_id->GetBreakpointID()); - } - const size_t num_locations = breakpoint_sp->GetNumLocations(); - for (size_t j = 0; j < num_locations; ++j) { - BreakpointLocation *bp_loc = - breakpoint_sp->GetLocationAtIndex(j).get(); - StreamString canonical_id_str; - BreakpointID::GetCanonicalReference( - &canonical_id_str, bp_id->GetBreakpointID(), bp_loc->GetID()); - new_args.AppendArgument(canonical_id_str.GetString()); - } + auto [prefix, suffix] = tmp_str.split('.'); + if (suffix == "*" && BreakpointID::IsValidIDExpression(prefix)) { + + BreakpointSP breakpoint_sp; + auto bp_id = BreakpointID::ParseCanonicalReference(prefix); + if (bp_id) + breakpoint_sp = target->GetBreakpointByID(bp_id->GetBreakpointID()); + if (!breakpoint_sp) { + new_args.Clear(); + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "'%d' is not a valid breakpoint ID.\n", + bp_id->GetBreakpointID()); + } + const size_t num_locations = breakpoint_sp->GetNumLocations(); + for (size_t j = 0; j < num_locations; ++j) { + BreakpointLocation *bp_loc = + breakpoint_sp->GetLocationAtIndex(j).get(); + StreamString canonical_id_str; + BreakpointID::GetCanonicalReference( + &canonical_id_str, bp_id->GetBreakpointID(), bp_loc->GetID()); + new_args.AppendArgument(canonical_id_str.GetString()); } } } diff --git a/lldb/test/API/functionalities/breakpoint/breakpoint_locations/TestBreakpointLocations.py b/lldb/test/API/functionalities/breakpoint/breakpoint_locations/TestBreakpointLocations.py index 8930bea619bb..d87e6275f7b5 100644 --- a/lldb/test/API/functionalities/breakpoint/breakpoint_locations/TestBreakpointLocations.py +++ b/lldb/test/API/functionalities/breakpoint/breakpoint_locations/TestBreakpointLocations.py @@ -293,6 +293,12 @@ class BreakpointLocationsTestCase(TestBase): startstr="3 breakpoints enabled.", ) + # The 'breakpoint enable 1.' command should not crash. + self.expect( + "breakpoint enable 1.", + startstr="0 breakpoints enabled.", + ) + # The 'breakpoint disable 1.1' command should disable 1 location. self.expect( "breakpoint disable 1.1", -- GitLab From 03577ced1f55bf96224513f2414bf025d6877fac Mon Sep 17 00:00:00 2001 From: Maksim Panchenko Date: Mon, 1 Apr 2024 14:11:02 -0700 Subject: [PATCH 007/447] [BOLT][NFC] Fix typo --- bolt/include/bolt/Core/BinaryFunction.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bolt/include/bolt/Core/BinaryFunction.h b/bolt/include/bolt/Core/BinaryFunction.h index 5089f8491280..bc047fefa315 100644 --- a/bolt/include/bolt/Core/BinaryFunction.h +++ b/bolt/include/bolt/Core/BinaryFunction.h @@ -1168,7 +1168,7 @@ public: /// Pass an offset of the entry point in the input binary and a corresponding /// global symbol to the callback function. /// - /// Return true of all callbacks returned true, false otherwise. + /// Return true if all callbacks returned true, false otherwise. bool forEachEntryPoint(EntryPointCallbackTy Callback) const; /// Return MC symbol associated with the end of the function. -- GitLab From 70e189fbc96909d3841dd2bca4a2909345cd826f Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Mon, 1 Apr 2024 14:13:56 -0700 Subject: [PATCH 008/447] [libc] fixup ftello test (#87282) Use a seek offset that fits within the file size. This was missed in presubmit because the FILE based stdio tests aren't run in overlay mode; fullbuild is not tested in presubmit. WRITE_SIZE == 11, so using a value of 42 for offseto would cause the expression `WRITE_SIZE - offseto` to evaluate to -31 as an unsigned 64b integer (18446744073709551585ULL). Fixes #86928 --- libc/test/src/stdio/ftell_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libc/test/src/stdio/ftell_test.cpp b/libc/test/src/stdio/ftell_test.cpp index 68a969ed0c30..62745e2194be 100644 --- a/libc/test/src/stdio/ftell_test.cpp +++ b/libc/test/src/stdio/ftell_test.cpp @@ -39,7 +39,7 @@ protected: // still return the correct effective offset. ASSERT_EQ(size_t(LIBC_NAMESPACE::ftell(file)), WRITE_SIZE); - off_t offseto = 42; + off_t offseto = 5; ASSERT_EQ(0, LIBC_NAMESPACE::fseeko(file, offseto, SEEK_SET)); ASSERT_EQ(LIBC_NAMESPACE::ftello(file), offseto); ASSERT_EQ(0, LIBC_NAMESPACE::fseeko(file, -offseto, SEEK_END)); -- GitLab From 6b136ce738d1acc96d926d7999419867dea16961 Mon Sep 17 00:00:00 2001 From: Tom Stellard Date: Mon, 1 Apr 2024 14:35:39 -0700 Subject: [PATCH 009/447] [workflows] issue-write: Exit early if there are no comments (#87114) This will eliminate some unnecessary REST API calls. --- .github/workflows/issue-write.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/issue-write.yml b/.github/workflows/issue-write.yml index 02a5f7c213e8..f5b84fec17a7 100644 --- a/.github/workflows/issue-write.yml +++ b/.github/workflows/issue-write.yml @@ -31,7 +31,7 @@ jobs: script: | var fs = require('fs'); const comments = JSON.parse(fs.readFileSync('./comments')); - if (!comments) { + if (!comments || comments.length == 0) { return; } -- GitLab From 0478adc97e1a4018d866520cb149b6e6c2a9101a Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Mon, 1 Apr 2024 14:58:28 -0700 Subject: [PATCH 010/447] [Object,ELFTypes] Remove TargetEndianness Finish the rename by #86604 --- llvm/include/llvm/Object/ELFTypes.h | 1 - 1 file changed, 1 deletion(-) diff --git a/llvm/include/llvm/Object/ELFTypes.h b/llvm/include/llvm/Object/ELFTypes.h index 4617b70a2f12..4ab23e4ea81b 100644 --- a/llvm/include/llvm/Object/ELFTypes.h +++ b/llvm/include/llvm/Object/ELFTypes.h @@ -51,7 +51,6 @@ private: using packed = support::detail::packed_endian_specific_integral; public: - static const endianness TargetEndianness = E; static const endianness Endianness = E; static const bool Is64Bits = Is64; -- GitLab From 1d5e5f4d3c68e63ced47ee9b17d62fb995aa1e62 Mon Sep 17 00:00:00 2001 From: Michael Maitland Date: Mon, 1 Apr 2024 15:06:10 -0700 Subject: [PATCH 011/447] [GISEL][NFC] Fix comment for widenScalarToNextPow2 The docstring for this function incorrectly specified when a widening is not performed. This patch adds the additional specification for what happens when the type size is a power of two but it is less than MinSize. --- llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h index 6afaea3f3fc5..82e713f30ea3 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h @@ -879,7 +879,8 @@ public: } /// Widen the scalar to the next power of two that is at least MinSize. - /// No effect if the type is not a scalar or is a power of two. + /// No effect if the type is a power of two, except if the type is smaller + /// than MinSize, or if the type is a vector type. LegalizeRuleSet &widenScalarToNextPow2(unsigned TypeIdx, unsigned MinSize = 0) { using namespace LegalityPredicates; -- GitLab From 1e15371dd8843dfc52b9435afaa133997c1773d8 Mon Sep 17 00:00:00 2001 From: Mingming Liu Date: Mon, 1 Apr 2024 15:14:49 -0700 Subject: [PATCH 012/447] [ThinLTO][TypeProf] Implement vtable def import (#79381) Add annotated vtable GUID as referenced variables in per function summary, and update bitcode writer to create value-ids for these referenced vtables. - This is the part3 of type profiling work, and described in the "Virtual Table Definition Import" [1] section of the RFC. [1] https://github.com/llvm/llvm-project/pull/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 --- llvm/include/llvm/ProfileData/InstrProf.h | 12 +++- .../IndirectCallPromotionAnalysis.cpp | 4 ++ llvm/lib/Analysis/ModuleSummaryAnalysis.cpp | 20 ++++++ llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 13 +++- llvm/lib/ProfileData/InstrProf.cpp | 70 +++++++++++++------ .../thinlto-func-summary-vtableref-pgo.ll | 37 ++++++---- 6 files changed, 120 insertions(+), 36 deletions(-) diff --git a/llvm/include/llvm/ProfileData/InstrProf.h b/llvm/include/llvm/ProfileData/InstrProf.h index fd66c4ed948f..eb3c10bcba1c 100644 --- a/llvm/include/llvm/ProfileData/InstrProf.h +++ b/llvm/include/llvm/ProfileData/InstrProf.h @@ -283,7 +283,7 @@ void annotateValueSite(Module &M, Instruction &Inst, /// Extract the value profile data from \p Inst which is annotated with /// value profile meta data. Return false if there is no value data annotated, -/// otherwise return true. +/// otherwise return true. bool getValueProfDataFromInst(const Instruction &Inst, InstrProfValueKind ValueKind, uint32_t MaxNumValueData, @@ -291,6 +291,16 @@ bool getValueProfDataFromInst(const Instruction &Inst, uint32_t &ActualNumValueData, uint64_t &TotalC, bool GetNoICPValue = false); +/// Extract the value profile data from \p Inst and returns them if \p Inst is +/// annotated with value profile data. Returns nullptr otherwise. It's similar +/// to `getValueProfDataFromInst` above except that an array is allocated only +/// after a preliminary checking that the value profiles of kind `ValueKind` +/// exist. +std::unique_ptr +getValueProfDataFromInst(const Instruction &Inst, InstrProfValueKind ValueKind, + uint32_t MaxNumValueData, uint32_t &ActualNumValueData, + uint64_t &TotalC, bool GetNoICPValue = false); + inline StringRef getPGOFuncNameMetadataName() { return "PGOFuncName"; } /// Return the PGOFuncName meta data associated with a function. diff --git a/llvm/lib/Analysis/IndirectCallPromotionAnalysis.cpp b/llvm/lib/Analysis/IndirectCallPromotionAnalysis.cpp index ebfa1c8fc08e..ab53717eb889 100644 --- a/llvm/lib/Analysis/IndirectCallPromotionAnalysis.cpp +++ b/llvm/lib/Analysis/IndirectCallPromotionAnalysis.cpp @@ -45,6 +45,10 @@ static cl::opt cl::desc("Max number of promotions for a single indirect " "call callsite")); +cl::opt MaxNumVTableAnnotations( + "icp-max-num-vtables", cl::init(6), cl::Hidden, + cl::desc("Max number of vtables annotated for a vtable load instruction.")); + ICallPromotionAnalysis::ICallPromotionAnalysis() { ValueDataArray = std::make_unique(MaxNumPromotions); } diff --git a/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp b/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp index 1f15e9478324..3ad0bab827a5 100644 --- a/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp +++ b/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp @@ -82,6 +82,8 @@ static cl::opt ModuleSummaryDotFile( extern cl::opt ScalePartialSampleProfileWorkingSetSize; +extern cl::opt MaxNumVTableAnnotations; + // Walk through the operands of a given User via worklist iteration and populate // the set of GlobalValue references encountered. Invoked either on an // Instruction or a GlobalVariable (which walks its initializer). @@ -124,6 +126,24 @@ static bool findRefEdges(ModuleSummaryIndex &Index, const User *CurUser, Worklist.push_back(Operand); } } + + const Instruction *I = dyn_cast(CurUser); + if (I) { + uint32_t ActualNumValueData = 0; + uint64_t TotalCount = 0; + // MaxNumVTableAnnotations is the maximum number of vtables annotated on + // the instruction. + auto ValueDataArray = + getValueProfDataFromInst(*I, IPVK_VTableTarget, MaxNumVTableAnnotations, + ActualNumValueData, TotalCount); + + if (ValueDataArray.get()) { + for (uint32_t j = 0; j < ActualNumValueData; j++) { + RefEdges.insert(Index.getOrInsertValueInfo(/* VTableGUID = */ + ValueDataArray[j].Value)); + } + } + } return HasBlockAddress; } diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index 221eeaae6e2b..dd554e422516 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -203,7 +203,7 @@ public: for (const auto &GUIDSummaryLists : *Index) // Examine all summaries for this GUID. for (auto &Summary : GUIDSummaryLists.second.SummaryList) - if (auto FS = dyn_cast(Summary.get())) + if (auto FS = dyn_cast(Summary.get())) { // For each call in the function summary, see if the call // is to a GUID (which means it is for an indirect call, // otherwise we would have a Value for it). If so, synthesize @@ -211,6 +211,15 @@ public: for (auto &CallEdge : FS->calls()) if (!CallEdge.first.haveGVs() || !CallEdge.first.getValue()) assignValueId(CallEdge.first.getGUID()); + + // For each referenced variables in the function summary, see if the + // variable is represented by a GUID (as opposed to a symbol to + // declarations or definitions in the module). If so, synthesize a + // value id. + for (auto &RefEdge : FS->refs()) + if (!RefEdge.haveGVs() || !RefEdge.getValue()) + assignValueId(RefEdge.getGUID()); + } } protected: @@ -4188,7 +4197,7 @@ void ModuleBitcodeWriterBase::writePerModuleFunctionSummaryRecord( NameVals.push_back(SpecialRefCnts.second); // worefcnt for (auto &RI : FS->refs()) - NameVals.push_back(VE.getValueID(RI.getValue())); + NameVals.push_back(getValueId(RI)); const bool UseRelBFRecord = WriteRelBFToSummary && !F.hasProfileData() && diff --git a/llvm/lib/ProfileData/InstrProf.cpp b/llvm/lib/ProfileData/InstrProf.cpp index 90c3cfc45b98..95f900d0fff1 100644 --- a/llvm/lib/ProfileData/InstrProf.cpp +++ b/llvm/lib/ProfileData/InstrProf.cpp @@ -1271,46 +1271,44 @@ void annotateValueSite(Module &M, Instruction &Inst, Inst.setMetadata(LLVMContext::MD_prof, MDNode::get(Ctx, Vals)); } -bool getValueProfDataFromInst(const Instruction &Inst, - InstrProfValueKind ValueKind, - uint32_t MaxNumValueData, - InstrProfValueData ValueData[], - uint32_t &ActualNumValueData, uint64_t &TotalC, - bool GetNoICPValue) { +MDNode *mayHaveValueProfileOfKind(const Instruction &Inst, + InstrProfValueKind ValueKind) { MDNode *MD = Inst.getMetadata(LLVMContext::MD_prof); if (!MD) - return false; + return nullptr; - unsigned NOps = MD->getNumOperands(); + if (MD->getNumOperands() < 5) + return nullptr; - if (NOps < 5) - return false; - - // Operand 0 is a string tag "VP": MDString *Tag = cast(MD->getOperand(0)); - if (!Tag) - return false; - - if (!Tag->getString().equals("VP")) - return false; + if (!Tag || !Tag->getString().equals("VP")) + return nullptr; // Now check kind: ConstantInt *KindInt = mdconst::dyn_extract(MD->getOperand(1)); if (!KindInt) - return false; + return nullptr; if (KindInt->getZExtValue() != ValueKind) - return false; + return nullptr; + + return MD; +} +static bool getValueProfDataFromInstImpl(const MDNode *const MD, + const uint32_t MaxNumDataWant, + InstrProfValueData ValueData[], + uint32_t &ActualNumValueData, + uint64_t &TotalC, bool GetNoICPValue) { + const unsigned NOps = MD->getNumOperands(); // Get total count ConstantInt *TotalCInt = mdconst::dyn_extract(MD->getOperand(2)); if (!TotalCInt) return false; TotalC = TotalCInt->getZExtValue(); - ActualNumValueData = 0; for (unsigned I = 3; I < NOps; I += 2) { - if (ActualNumValueData >= MaxNumValueData) + if (ActualNumValueData >= MaxNumDataWant) break; ConstantInt *Value = mdconst::dyn_extract(MD->getOperand(I)); ConstantInt *Count = @@ -1327,6 +1325,36 @@ bool getValueProfDataFromInst(const Instruction &Inst, return true; } +std::unique_ptr +getValueProfDataFromInst(const Instruction &Inst, InstrProfValueKind ValueKind, + uint32_t MaxNumValueData, uint32_t &ActualNumValueData, + uint64_t &TotalC, bool GetNoICPValue) { + MDNode *MD = mayHaveValueProfileOfKind(Inst, ValueKind); + if (!MD) + return nullptr; + auto ValueDataArray = std::make_unique(MaxNumValueData); + if (!getValueProfDataFromInstImpl(MD, MaxNumValueData, ValueDataArray.get(), + ActualNumValueData, TotalC, GetNoICPValue)) + return nullptr; + return ValueDataArray; +} + +// FIXME: Migrate existing callers to the function above that returns an +// array. +bool getValueProfDataFromInst(const Instruction &Inst, + InstrProfValueKind ValueKind, + uint32_t MaxNumValueData, + InstrProfValueData ValueData[], + uint32_t &ActualNumValueData, uint64_t &TotalC, + bool GetNoICPValue) { + MDNode *MD = mayHaveValueProfileOfKind(Inst, ValueKind); + if (!MD) + return false; + return getValueProfDataFromInstImpl(MD, MaxNumValueData, ValueData, + ActualNumValueData, TotalC, + GetNoICPValue); +} + MDNode *getPGOFuncNameMetadata(const Function &F) { return F.getMetadata(getPGOFuncNameMetadataName()); } diff --git a/llvm/test/Bitcode/thinlto-func-summary-vtableref-pgo.ll b/llvm/test/Bitcode/thinlto-func-summary-vtableref-pgo.ll index 78b175caca85..ba3ce9a75ee8 100644 --- a/llvm/test/Bitcode/thinlto-func-summary-vtableref-pgo.ll +++ b/llvm/test/Bitcode/thinlto-func-summary-vtableref-pgo.ll @@ -1,20 +1,31 @@ -; RUN: opt -module-summary %s -o %t.o +; Promote at most one function and annotate at most one vtable. +; As a result, only one value (of each relevant kind) shows up in the function +; summary. + +; RUN: opt -module-summary -icp-max-num-vtables=1 -icp-max-prom=1 %s -o %t.o ; RUN: llvm-bcanalyzer -dump %t.o | FileCheck %s ; RUN: llvm-dis -o - %t.o | FileCheck %s --check-prefix=DIS - +; Round trip it through llvm-as +; RUN: llvm-dis -o - %t.o | llvm-as -o - | llvm-dis -o - | FileCheck %s --check-prefix=DIS ; CHECK: ; CHECK-NEXT: +; The `VALUE_GUID` below represents the "_ZTV4Base" referenced by the instruction +; that loads vtable pointers. +; CHECK-NEXT: ; The `VALUE_GUID` below represents the "_ZN4Base4funcEv" referenced by the ; indirect call instruction. -; CHECK-NEXT: +; CHECK-NEXT: +; NOTE vtables and functions from Derived class is dropped because +; `-icp-max-num-vtables` and `-icp-max-prom` are both set to one. ; has the format [valueid, flags, instcount, funcflags, ; numrefs, rorefcnt, worefcnt, +; m x valueid, ; n x (valueid, hotness+tailcall)] -; CHECK-NEXT: +; CHECK-NEXT: ; CHECK-NEXT: target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" @@ -31,7 +42,6 @@ define i32 @_Z4testP4Base(ptr %0) !prof !15 { !llvm.module.flags = !{!1} - !1 = !{i32 1, !"ProfileSummary", !2} !2 = !{!3, !4, !5, !6, !7, !8, !9, !10} !3 = !{!"ProfileFormat", !"InstrProf"} @@ -48,14 +58,17 @@ define i32 @_Z4testP4Base(ptr %0) !prof !15 { !14 = !{i32 999999, i64 1, i32 2} !15 = !{!"function_entry_count", i32 150} -; 1960855528937986108 is the MD5 hash of _ZTV4Base -!16 = !{!"VP", i32 2, i64 1600, i64 1960855528937986108, i64 1600} -; 5459407273543877811 is the MD5 hash of _ZN4Base4funcEv -!17 = !{!"VP", i32 0, i64 1600, i64 5459407273543877811, i64 1600} +; 1960855528937986108 is the MD5 hash of _ZTV4Base, and +; 13870436605473471591 is the MD5 hash of _ZTV7Derived +!16 = !{!"VP", i32 2, i64 150, i64 1960855528937986108, i64 100, i64 13870436605473471591, i64 50} +; 5459407273543877811 is the MD5 hash of _ZN4Base4funcEv, and +; 6174874150489409711 is the MD5 hash of _ZN7Derived4funcEv +!17 = !{!"VP", i32 0, i64 150, i64 5459407273543877811, i64 100, i64 6174874150489409711, i64 50} ; ModuleSummaryIndex stores map in std::map; so ; global value summares are printed out in the order that gv's guid increases. ; DIS: ^0 = module: (path: "{{.*}}", hash: (0, 0, 0, 0, 0)) -; DIS: ^1 = gv: (guid: 5459407273543877811) -; DIS: ^2 = gv: (name: "_Z4testP4Base", summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 4, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 0, hasUnknownCall: 1, mustBeUnreachable: 0), calls: ((callee: ^1, hotness: hot))))) ; guid = 15857150948103218965 -; DIS: ^3 = blockcount: 0 +; DIS: ^1 = gv: (guid: 1960855528937986108) +; DIS: ^2 = gv: (guid: 5459407273543877811) +; DIS: ^3 = gv: (name: "_Z4testP4Base", summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 0, canAutoHide: 0), insts: 4, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 0, alwaysInline: 0, noUnwind: 0, mayThrow: 0, hasUnknownCall: 1, mustBeUnreachable: 0), calls: ((callee: ^2, hotness: hot)), refs: (readonly ^1)))) ; guid = 15857150948103218965 +; DIS: ^4 = blockcount: 0 -- GitLab From 649f9603a2da82a32830ce1dc7ce5825d3766a1d Mon Sep 17 00:00:00 2001 From: Tom Stellard Date: Mon, 1 Apr 2024 15:17:24 -0700 Subject: [PATCH 013/447] [workflows] issue-write: Avoid race condition when PR branch is deleted (#87118) Fixes #87102 . --- .github/workflows/issue-write.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/issue-write.yml b/.github/workflows/issue-write.yml index f5b84fec17a7..4a564a5076ba 100644 --- a/.github/workflows/issue-write.yml +++ b/.github/workflows/issue-write.yml @@ -77,6 +77,15 @@ jobs: } const gql_result = await github.graphql(gql_query, gql_variables); console.log(gql_result); + // If the branch for the PR was deleted before this job has a chance + // to run, then the ref will be null. This can happen if someone: + // 1. Rebase the PR, which triggers some workflow. + // 2. Immediately merges the PR and deletes the branch. + // 3. The workflow finishes and triggers this job. + if (!gql_result.repository.ref) { + console.log("Ref has been deleted"); + return; + } console.log(gql_result.repository.ref.associatedPullRequests.nodes); var pr_number = 0; -- GitLab From f2a87b07e7fe1892a11ee9424d22dbaec5de5b5b Mon Sep 17 00:00:00 2001 From: Joseph Huber Date: Mon, 1 Apr 2024 17:26:20 -0500 Subject: [PATCH 014/447] [OpenMP] Use loaded offloading toolchains to add libraries (#87108) Summary: We want to pass these GPU libraries by default if a certain offloading toolchain is loaded for OpenMP. Previously I parsed this from the arguments because it's only available in the compilation. This doesn't really work for `native` and it's extra effort, so this patch just passes in the `Compilation` as an extr argument and uses that. Tests should be unaffected. --- clang/lib/Driver/ToolChains/CommonArgs.cpp | 58 ++++++++-------------- clang/lib/Driver/ToolChains/CommonArgs.h | 4 +- clang/lib/Driver/ToolChains/Darwin.cpp | 2 +- clang/lib/Driver/ToolChains/DragonFly.cpp | 2 +- clang/lib/Driver/ToolChains/FreeBSD.cpp | 2 +- clang/lib/Driver/ToolChains/Gnu.cpp | 2 +- clang/lib/Driver/ToolChains/Haiku.cpp | 2 +- clang/lib/Driver/ToolChains/NetBSD.cpp | 2 +- clang/lib/Driver/ToolChains/OpenBSD.cpp | 2 +- clang/lib/Driver/ToolChains/Solaris.cpp | 2 +- 10 files changed, 32 insertions(+), 46 deletions(-) diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index ace4fb99581e..62a53b85ce09 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -1075,14 +1075,14 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, /// Adds the '-lcgpu' and '-lmgpu' libraries to the compilation to include the /// LLVM C library for GPUs. -static void addOpenMPDeviceLibC(const ToolChain &TC, const ArgList &Args, +static void addOpenMPDeviceLibC(const Compilation &C, const ArgList &Args, ArgStringList &CmdArgs) { if (Args.hasArg(options::OPT_nogpulib) || Args.hasArg(options::OPT_nolibc)) return; // Check the resource directory for the LLVM libc GPU declarations. If it's // found we can assume that LLVM was built with support for the GPU libc. - SmallString<256> LibCDecls(TC.getDriver().ResourceDir); + SmallString<256> LibCDecls(C.getDriver().ResourceDir); llvm::sys::path::append(LibCDecls, "include", "llvm_libc_wrappers", "llvm-libc-decls"); bool HasLibC = llvm::sys::fs::exists(LibCDecls) && @@ -1090,38 +1090,23 @@ static void addOpenMPDeviceLibC(const ToolChain &TC, const ArgList &Args, if (!Args.hasFlag(options::OPT_gpulibc, options::OPT_nogpulibc, HasLibC)) return; - // We don't have access to the offloading toolchains here, so determine from - // the arguments if we have any active NVPTX or AMDGPU toolchains. - llvm::DenseSet Libraries; - if (const Arg *Targets = Args.getLastArg(options::OPT_fopenmp_targets_EQ)) { - if (llvm::any_of(Targets->getValues(), - [](auto S) { return llvm::Triple(S).isAMDGPU(); })) { - Libraries.insert("-lcgpu-amdgpu"); - Libraries.insert("-lmgpu-amdgpu"); - } - if (llvm::any_of(Targets->getValues(), - [](auto S) { return llvm::Triple(S).isNVPTX(); })) { - Libraries.insert("-lcgpu-nvptx"); - Libraries.insert("-lmgpu-nvptx"); - } - } + SmallVector ToolChains; + auto TCRange = C.getOffloadToolChains(Action::OFK_OpenMP); + for (auto TI = TCRange.first, TE = TCRange.second; TI != TE; ++TI) + ToolChains.push_back(TI->second); - for (StringRef Arch : Args.getAllArgValues(options::OPT_offload_arch_EQ)) { - if (llvm::any_of(llvm::split(Arch, ","), [](StringRef Str) { - return IsAMDGpuArch(StringToCudaArch(Str)); - })) { - Libraries.insert("-lcgpu-amdgpu"); - Libraries.insert("-lmgpu-amdgpu"); - } - if (llvm::any_of(llvm::split(Arch, ","), [](StringRef Str) { - return IsNVIDIAGpuArch(StringToCudaArch(Str)); - })) { - Libraries.insert("-lcgpu-nvptx"); - Libraries.insert("-lmgpu-nvptx"); - } + if (llvm::any_of(ToolChains, [](const ToolChain *TC) { + return TC->getTriple().isAMDGPU(); + })) { + CmdArgs.push_back("-lcgpu-amdgpu"); + CmdArgs.push_back("-lmgpu-amdgpu"); + } + if (llvm::any_of(ToolChains, [](const ToolChain *TC) { + return TC->getTriple().isNVPTX(); + })) { + CmdArgs.push_back("-lcgpu-nvptx"); + CmdArgs.push_back("-lmgpu-nvptx"); } - - llvm::append_range(CmdArgs, Libraries); } void tools::addOpenMPRuntimeLibraryPath(const ToolChain &TC, @@ -1153,9 +1138,10 @@ void tools::addArchSpecificRPath(const ToolChain &TC, const ArgList &Args, } } -bool tools::addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC, - const ArgList &Args, bool ForceStaticHostRuntime, - bool IsOffloadingHost, bool GompNeedsRT) { +bool tools::addOpenMPRuntime(const Compilation &C, ArgStringList &CmdArgs, + const ToolChain &TC, const ArgList &Args, + bool ForceStaticHostRuntime, bool IsOffloadingHost, + bool GompNeedsRT) { if (!Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, options::OPT_fno_openmp, false)) return false; @@ -1196,7 +1182,7 @@ bool tools::addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC, CmdArgs.push_back("-lomptarget.devicertl"); if (IsOffloadingHost) - addOpenMPDeviceLibC(TC, Args, CmdArgs); + addOpenMPDeviceLibC(C, Args, CmdArgs); addArchSpecificRPath(TC, Args, CmdArgs); addOpenMPRuntimeLibraryPath(TC, Args, CmdArgs); diff --git a/clang/lib/Driver/ToolChains/CommonArgs.h b/clang/lib/Driver/ToolChains/CommonArgs.h index bb37be4bd6ea..5581905db311 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.h +++ b/clang/lib/Driver/ToolChains/CommonArgs.h @@ -111,8 +111,8 @@ void addOpenMPRuntimeLibraryPath(const ToolChain &TC, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs); /// Returns true, if an OpenMP runtime has been added. -bool addOpenMPRuntime(llvm::opt::ArgStringList &CmdArgs, const ToolChain &TC, - const llvm::opt::ArgList &Args, +bool addOpenMPRuntime(const Compilation &C, llvm::opt::ArgStringList &CmdArgs, + const ToolChain &TC, const llvm::opt::ArgList &Args, bool ForceStaticHostRuntime = false, bool IsOffloadingHost = false, bool GompNeedsRT = false); diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp index c7682c7f1d33..caf6c4a444fd 100644 --- a/clang/lib/Driver/ToolChains/Darwin.cpp +++ b/clang/lib/Driver/ToolChains/Darwin.cpp @@ -686,7 +686,7 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, } if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) - addOpenMPRuntime(CmdArgs, getToolChain(), Args); + addOpenMPRuntime(C, CmdArgs, getToolChain(), Args); if (isObjCRuntimeLinked(Args) && !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { diff --git a/clang/lib/Driver/ToolChains/DragonFly.cpp b/clang/lib/Driver/ToolChains/DragonFly.cpp index b59a172bd6ae..1dbc46763c11 100644 --- a/clang/lib/Driver/ToolChains/DragonFly.cpp +++ b/clang/lib/Driver/ToolChains/DragonFly.cpp @@ -136,7 +136,7 @@ void dragonfly::Linker::ConstructJob(Compilation &C, const JobAction &JA, // Use the static OpenMP runtime with -static-openmp bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && !Static; - addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP); + addOpenMPRuntime(C, CmdArgs, ToolChain, Args, StaticOpenMP); if (D.CCCIsCXX()) { if (ToolChain.ShouldLinkCXXStdlib(Args)) diff --git a/clang/lib/Driver/ToolChains/FreeBSD.cpp b/clang/lib/Driver/ToolChains/FreeBSD.cpp index c5757ddebb0f..a8ee6540001e 100644 --- a/clang/lib/Driver/ToolChains/FreeBSD.cpp +++ b/clang/lib/Driver/ToolChains/FreeBSD.cpp @@ -295,7 +295,7 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, // Use the static OpenMP runtime with -static-openmp bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && !Args.hasArg(options::OPT_static); - addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP); + addOpenMPRuntime(C, CmdArgs, ToolChain, Args, StaticOpenMP); if (D.CCCIsCXX()) { if (ToolChain.ShouldLinkCXXStdlib(Args)) diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index a9c9d2475809..dedbfac6cb25 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -598,7 +598,7 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, // FIXME: Only pass GompNeedsRT = true for platforms with libgomp that // require librt. Most modern Linux platforms do, but some may not. - if (addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP, + if (addOpenMPRuntime(C, CmdArgs, ToolChain, Args, StaticOpenMP, JA.isHostOffloading(Action::OFK_OpenMP), /* GompNeedsRT= */ true)) // OpenMP runtimes implies pthreads when using the GNU toolchain. diff --git a/clang/lib/Driver/ToolChains/Haiku.cpp b/clang/lib/Driver/ToolChains/Haiku.cpp index 30464e2229e6..346652a7e4bd 100644 --- a/clang/lib/Driver/ToolChains/Haiku.cpp +++ b/clang/lib/Driver/ToolChains/Haiku.cpp @@ -107,7 +107,7 @@ void haiku::Linker::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_r)) { // Use the static OpenMP runtime with -static-openmp bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && !Static; - addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP); + addOpenMPRuntime(C, CmdArgs, ToolChain, Args, StaticOpenMP); if (D.CCCIsCXX() && ToolChain.ShouldLinkCXXStdlib(Args)) ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); diff --git a/clang/lib/Driver/ToolChains/NetBSD.cpp b/clang/lib/Driver/ToolChains/NetBSD.cpp index 0eec8fddabd5..d54f22882949 100644 --- a/clang/lib/Driver/ToolChains/NetBSD.cpp +++ b/clang/lib/Driver/ToolChains/NetBSD.cpp @@ -311,7 +311,7 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_r)) { // Use the static OpenMP runtime with -static-openmp bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && !Static; - addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP); + addOpenMPRuntime(C, CmdArgs, ToolChain, Args, StaticOpenMP); if (D.CCCIsCXX()) { if (ToolChain.ShouldLinkCXXStdlib(Args)) diff --git a/clang/lib/Driver/ToolChains/OpenBSD.cpp b/clang/lib/Driver/ToolChains/OpenBSD.cpp index 6da6728585df..e20d9fb1cfc4 100644 --- a/clang/lib/Driver/ToolChains/OpenBSD.cpp +++ b/clang/lib/Driver/ToolChains/OpenBSD.cpp @@ -221,7 +221,7 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_r)) { // Use the static OpenMP runtime with -static-openmp bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && !Static; - addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP); + addOpenMPRuntime(C, CmdArgs, ToolChain, Args, StaticOpenMP); if (D.CCCIsCXX()) { if (ToolChain.ShouldLinkCXXStdlib(Args)) diff --git a/clang/lib/Driver/ToolChains/Solaris.cpp b/clang/lib/Driver/ToolChains/Solaris.cpp index 5d7f0ae2a392..7126e018ca5b 100644 --- a/clang/lib/Driver/ToolChains/Solaris.cpp +++ b/clang/lib/Driver/ToolChains/Solaris.cpp @@ -211,7 +211,7 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA, // Use the static OpenMP runtime with -static-openmp bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && !Args.hasArg(options::OPT_static); - addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP); + addOpenMPRuntime(C, CmdArgs, ToolChain, Args, StaticOpenMP); if (D.CCCIsCXX()) { if (ToolChain.ShouldLinkCXXStdlib(Args)) -- GitLab From 9df19ce40281551bd348b262a131085cf98dadf5 Mon Sep 17 00:00:00 2001 From: David Blaikie Date: Mon, 1 Apr 2024 23:07:01 +0000 Subject: [PATCH 015/447] Add uncovered enums in switches caused by 9434c083475e42f47383f3067fe2a155db5c6a30 These are probably actually unreachable - perhaps an lldb developer would be interested in rephrasing this change to move the new cases into some unreachable/unsupported bucket, rather than my half-hearted guess at what the desired behavior would be (completely untested, because they're probably untestable/unreachable - maybe debugging from modules?) --- lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index ebcc3bc99a80..4a1c8d576552 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -4097,6 +4097,8 @@ TypeSystemClang::GetTypeClass(lldb::opaque_compiler_type_t type) { return lldb::eTypeClassArray; case clang::Type::DependentSizedArray: return lldb::eTypeClassArray; + case clang::Type::ArrayParameter: + return lldb::eTypeClassArray; case clang::Type::DependentSizedExtVector: return lldb::eTypeClassVector; case clang::Type::DependentVector: @@ -4776,6 +4778,7 @@ lldb::Encoding TypeSystemClang::GetEncoding(lldb::opaque_compiler_type_t type, case clang::Type::IncompleteArray: case clang::Type::VariableArray: + case clang::Type::ArrayParameter: break; case clang::Type::ConstantArray: @@ -5109,6 +5112,7 @@ lldb::Format TypeSystemClang::GetFormat(lldb::opaque_compiler_type_t type) { case clang::Type::IncompleteArray: case clang::Type::VariableArray: + case clang::Type::ArrayParameter: break; case clang::Type::ConstantArray: -- GitLab From 1079fc4f543c42bb09a33d2d79d90edd9c0bac91 Mon Sep 17 00:00:00 2001 From: Ivan Butygin Date: Tue, 2 Apr 2024 02:43:04 +0300 Subject: [PATCH 016/447] [mlir][pass] Add `errorHandler` param to `Pass::initializeOptions` (#87289) There is no good way to report detailed errors from inside `Pass::initializeOptions` function as context may not be available at this point and writing directly to `llvm::errs()` is not composable. See https://github.com/llvm/llvm-project/pull/87166#discussion_r1546426763 * Add error handler callback to `Pass::initializeOptions` * Update `PassOptions::parseFromString` to support custom error stream instead of using `llvm::errs()` directly. * Update default `Pass::initializeOptions` implementation to propagate error string from `parseFromString` to new error handler. * Update `MapMemRefStorageClassPass` to report error details using new API. --- mlir/include/mlir/Pass/Pass.h | 4 +++- mlir/include/mlir/Pass/PassOptions.h | 3 ++- .../MemRefToSPIRV/MapMemRefStorageClassPass.cpp | 8 +++++--- mlir/lib/Pass/Pass.cpp | 12 ++++++++++-- mlir/lib/Pass/PassRegistry.cpp | 7 ++++--- mlir/lib/Transforms/InlinerPass.cpp | 10 +++++++--- .../Dialect/Transform/test-pass-application.mlir | 1 + 7 files changed, 32 insertions(+), 13 deletions(-) diff --git a/mlir/include/mlir/Pass/Pass.h b/mlir/include/mlir/Pass/Pass.h index 070e0cad3878..0f50f3064f17 100644 --- a/mlir/include/mlir/Pass/Pass.h +++ b/mlir/include/mlir/Pass/Pass.h @@ -114,7 +114,9 @@ public: /// Derived classes may override this method to hook into the point at which /// options are initialized, but should generally always invoke this base /// class variant. - virtual LogicalResult initializeOptions(StringRef options); + virtual LogicalResult + initializeOptions(StringRef options, + function_ref errorHandler); /// Prints out the pass in the textual representation of pipelines. If this is /// an adaptor pass, print its pass managers. diff --git a/mlir/include/mlir/Pass/PassOptions.h b/mlir/include/mlir/Pass/PassOptions.h index 6717a3585d12..3a5e3224133e 100644 --- a/mlir/include/mlir/Pass/PassOptions.h +++ b/mlir/include/mlir/Pass/PassOptions.h @@ -293,7 +293,8 @@ public: /// Parse options out as key=value pairs that can then be handed off to the /// `llvm::cl` command line passing infrastructure. Everything is space /// separated. - LogicalResult parseFromString(StringRef options); + LogicalResult parseFromString(StringRef options, + raw_ostream &errorStream = llvm::errs()); /// Print the options held by this struct in a form that can be parsed via /// 'parseFromString'. diff --git a/mlir/lib/Conversion/MemRefToSPIRV/MapMemRefStorageClassPass.cpp b/mlir/lib/Conversion/MemRefToSPIRV/MapMemRefStorageClassPass.cpp index 76dab8ee4ac3..4cbc3dfdae22 100644 --- a/mlir/lib/Conversion/MemRefToSPIRV/MapMemRefStorageClassPass.cpp +++ b/mlir/lib/Conversion/MemRefToSPIRV/MapMemRefStorageClassPass.cpp @@ -272,14 +272,16 @@ public: const spirv::MemorySpaceToStorageClassMap &memorySpaceMap) : memorySpaceMap(memorySpaceMap) {} - LogicalResult initializeOptions(StringRef options) override { - if (failed(Pass::initializeOptions(options))) + LogicalResult initializeOptions( + StringRef options, + function_ref errorHandler) override { + if (failed(Pass::initializeOptions(options, errorHandler))) return failure(); if (clientAPI == "opencl") memorySpaceMap = spirv::mapMemorySpaceToOpenCLStorageClass; else if (clientAPI != "vulkan") - return failure(); + return errorHandler(llvm::Twine("Invalid clienAPI: ") + clientAPI); return success(); } diff --git a/mlir/lib/Pass/Pass.cpp b/mlir/lib/Pass/Pass.cpp index 3fb05e538666..57a6c20141d2 100644 --- a/mlir/lib/Pass/Pass.cpp +++ b/mlir/lib/Pass/Pass.cpp @@ -60,8 +60,16 @@ Operation *PassExecutionAction::getOp() const { void Pass::anchor() {} /// Attempt to initialize the options of this pass from the given string. -LogicalResult Pass::initializeOptions(StringRef options) { - return passOptions.parseFromString(options); +LogicalResult Pass::initializeOptions( + StringRef options, + function_ref errorHandler) { + std::string errStr; + llvm::raw_string_ostream os(errStr); + if (failed(passOptions.parseFromString(options, os))) { + os.flush(); + return errorHandler(errStr); + } + return success(); } /// Copy the option values from 'other', which is another instance of this diff --git a/mlir/lib/Pass/PassRegistry.cpp b/mlir/lib/Pass/PassRegistry.cpp index b0c314369190..f8149673a409 100644 --- a/mlir/lib/Pass/PassRegistry.cpp +++ b/mlir/lib/Pass/PassRegistry.cpp @@ -40,7 +40,7 @@ buildDefaultRegistryFn(const PassAllocatorFunction &allocator) { return [=](OpPassManager &pm, StringRef options, function_ref errorHandler) { std::unique_ptr pass = allocator(); - LogicalResult result = pass->initializeOptions(options); + LogicalResult result = pass->initializeOptions(options, errorHandler); std::optional pmOpName = pm.getOpName(); std::optional passOpName = pass->getOpName(); @@ -280,7 +280,8 @@ parseNextArg(StringRef options) { llvm_unreachable("unexpected control flow in pass option parsing"); } -LogicalResult detail::PassOptions::parseFromString(StringRef options) { +LogicalResult detail::PassOptions::parseFromString(StringRef options, + raw_ostream &errorStream) { // NOTE: `options` is modified in place to always refer to the unprocessed // part of the string. while (!options.empty()) { @@ -291,7 +292,7 @@ LogicalResult detail::PassOptions::parseFromString(StringRef options) { auto it = OptionsMap.find(key); if (it == OptionsMap.end()) { - llvm::errs() << ": no such option " << key << "\n"; + errorStream << ": no such option " << key << "\n"; return failure(); } if (llvm::cl::ProvidePositionalOption(it->second, value, 0)) diff --git a/mlir/lib/Transforms/InlinerPass.cpp b/mlir/lib/Transforms/InlinerPass.cpp index 9a7d5403a95d..43ca5cac8b76 100644 --- a/mlir/lib/Transforms/InlinerPass.cpp +++ b/mlir/lib/Transforms/InlinerPass.cpp @@ -64,7 +64,9 @@ private: /// Derived classes may override this method to hook into the point at which /// options are initialized, but should generally always invoke this base /// class variant. - LogicalResult initializeOptions(StringRef options) override; + LogicalResult initializeOptions( + StringRef options, + function_ref errorHandler) override; /// Inliner configuration parameters created from the pass options. InlinerConfig config; @@ -153,8 +155,10 @@ void InlinerPass::runOnOperation() { return; } -LogicalResult InlinerPass::initializeOptions(StringRef options) { - if (failed(Pass::initializeOptions(options))) +LogicalResult InlinerPass::initializeOptions( + StringRef options, + function_ref errorHandler) { + if (failed(Pass::initializeOptions(options, errorHandler))) return failure(); // Initialize the pipeline builder for operations without the dedicated diff --git a/mlir/test/Dialect/Transform/test-pass-application.mlir b/mlir/test/Dialect/Transform/test-pass-application.mlir index 7cb5387b937d..460ac3947f5c 100644 --- a/mlir/test/Dialect/Transform/test-pass-application.mlir +++ b/mlir/test/Dialect/Transform/test-pass-application.mlir @@ -78,6 +78,7 @@ module attributes {transform.with_named_sequence} { transform.named_sequence @__transform_main(%arg1: !transform.any_op) { %1 = transform.structured.match ops{["func.func"]} in %arg1 : (!transform.any_op) -> !transform.any_op // expected-error @below {{failed to add pass or pass pipeline to pipeline: canonicalize}} + // expected-error @below {{: no such option invalid-option}} transform.apply_registered_pass "canonicalize" to %1 {options = "invalid-option=1"} : (!transform.any_op) -> !transform.any_op transform.yield } -- GitLab From 6d0174e70641b1ea172ffed07c43604ef15e28ae Mon Sep 17 00:00:00 2001 From: Stephen Neuendorffer Date: Mon, 1 Apr 2024 17:04:29 -0700 Subject: [PATCH 017/447] [libc] allow libc-hdrgen to work on windows files (#87292) The code does some (overly simple?) checks on file syntax. These checks assume unix line endings and fail on windows. This commit updates the code to strip extra whitespace, making the checks more robust, particularly in the presence of windows line endings. Fixes #86023 --- libc/utils/HdrGen/Generator.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libc/utils/HdrGen/Generator.cpp b/libc/utils/HdrGen/Generator.cpp index 3bcf005adda7..d926d5d9ac3c 100644 --- a/libc/utils/HdrGen/Generator.cpp +++ b/libc/utils/HdrGen/Generator.cpp @@ -84,11 +84,19 @@ void Generator::generate(llvm::raw_ostream &OS, llvm::RecordKeeper &Records) { Line = Line.drop_front(CommandPrefixSize); P = Line.split("("); + // It's possible that we have windows line endings, so strip off the extra + // CR. + P.second = P.second.trim(); if (P.second.empty() || P.second[P.second.size() - 1] != ')') { SrcMgr.PrintMessage(llvm::SMLoc::getFromPointer(P.second.data()), llvm::SourceMgr::DK_Error, "Command argument list should begin with '(' " "and end with ')'."); + SrcMgr.PrintMessage(llvm::SMLoc::getFromPointer(P.second.data()), + llvm::SourceMgr::DK_Error, P.second.data()); + SrcMgr.PrintMessage(llvm::SMLoc::getFromPointer(P.second.data()), + llvm::SourceMgr::DK_Error, + std::to_string(P.second.size())); std::exit(1); } llvm::StringRef CommandName = P.first; -- GitLab From dd5797505ebc2dbfdd58927c4f0a11a1256696eb Mon Sep 17 00:00:00 2001 From: Abhinav Gunjal Date: Mon, 1 Apr 2024 17:36:09 -0700 Subject: [PATCH 018/447] lit_test : check if there is already a deps key in kwargs (#87290) This change checks if there is already a `deps` key in `kwargs` and concatenate it to avoid multiple values for `deps` key argument. background: https://github.com/llvm/llvm-project/pull/87022 recently added explicit `deps` to the lit_test. This is causing StableHLO bazel build failures at https://github.com/openxla/stablehlo/actions/runs/8511888283/job/23312383380?pr=2147 Tested: local build run is successful --- utils/bazel/llvm-project-overlay/llvm/lit_test.bzl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/utils/bazel/llvm-project-overlay/llvm/lit_test.bzl b/utils/bazel/llvm-project-overlay/llvm/lit_test.bzl index f754a9fc7d5e..af7ae560768d 100644 --- a/utils/bazel/llvm-project-overlay/llvm/lit_test.bzl +++ b/utils/bazel/llvm-project-overlay/llvm/lit_test.bzl @@ -10,6 +10,7 @@ def lit_test( srcs, args = None, data = None, + deps = None, **kwargs): """Runs a single test file with LLVM's lit tool. @@ -27,6 +28,7 @@ def lit_test( args = args or [] data = data or [] + deps = deps or [] native.py_test( name = name, @@ -35,7 +37,7 @@ def lit_test( args = args + ["-v"] + ["$(execpath %s)" % src for src in srcs], data = data + srcs, legacy_create_init = False, - deps = [Label("//llvm:lit")], + deps = deps + [Label("//llvm:lit")], **kwargs ) -- GitLab From 9dbd364589883ae3343a291077804c564d4b3de5 Mon Sep 17 00:00:00 2001 From: Ben Shi <2283975856@qq.com> Date: Tue, 2 Apr 2024 08:38:02 +0800 Subject: [PATCH 019/447] [AVR][NFC] Improve format of target description files (#87212) --- llvm/lib/Target/AVR/AVRInstrInfo.td | 320 +++++++--------------------- 1 file changed, 75 insertions(+), 245 deletions(-) diff --git a/llvm/lib/Target/AVR/AVRInstrInfo.td b/llvm/lib/Target/AVR/AVRInstrInfo.td index fe0d3b6c8189..38ebfab64c61 100644 --- a/llvm/lib/Target/AVR/AVRInstrInfo.td +++ b/llvm/lib/Target/AVR/AVRInstrInfo.td @@ -343,13 +343,9 @@ def AVR_COND_PL : PatLeaf<(i8 7)>; // Pessimistically assume ADJCALLSTACKDOWN / ADJCALLSTACKUP will become // sub / add which can clobber SREG. let Defs = [SP, SREG], Uses = [SP] in { - def ADJCALLSTACKDOWN : Pseudo<(outs), - (ins i16imm - : $amt, i16imm - : $amt2), - "#ADJCALLSTACKDOWN", [(AVRcallseq_start timm - : $amt, timm - : $amt2)]>; + def ADJCALLSTACKDOWN : Pseudo<(outs), (ins i16imm:$amt, i16imm:$amt2), + "#ADJCALLSTACKDOWN", + [(AVRcallseq_start timm:$amt, timm:$amt2)]>; // R31R30 is used to update SP. It is normally free because it is a // call-clobbered register but it is necessary to set it as a def as the @@ -357,13 +353,8 @@ let Defs = [SP, SREG], Uses = [SP] in { // seems). hasSideEffects needs to be set to true so this instruction isn't // considered dead. let Defs = [R31R30], hasSideEffects = 1 in def ADJCALLSTACKUP - : Pseudo<(outs), - (ins i16imm - : $amt1, i16imm - : $amt2), - "#ADJCALLSTACKUP", [(AVRcallseq_end timm - : $amt1, timm - : $amt2)]>; + : Pseudo<(outs), (ins i16imm:$amt1, i16imm:$amt2), + "#ADJCALLSTACKUP", [(AVRcallseq_end timm:$amt1, timm:$amt2)]>; } //===----------------------------------------------------------------------===// @@ -372,19 +363,9 @@ let Defs = [SP, SREG], Uses = [SP] in { let isCommutable = 1, Constraints = "$src = $rd", Defs = [SREG] in { // ADD Rd, Rr // Adds two 8-bit registers. - def ADDRdRr - : FRdRr<0b0000, 0b11, - (outs GPR8 - : $rd), - (ins GPR8 - : $src, GPR8 - : $rr), - "add\t$rd, $rr", - [(set i8 - : $rd, (add i8 - : $src, i8 - : $rr)), - (implicit SREG)]>; + def ADDRdRr : FRdRr<0b0000, 0b11, (outs GPR8:$rd),(ins GPR8:$src, GPR8:$rr), + "add\t$rd, $rr", + [(set i8:$rd, (add i8:$src, i8:$rr)), (implicit SREG)]>; // ADDW Rd+1:Rd, Rr+1:Rr // Pseudo instruction to add four 8-bit registers as two 16-bit values. @@ -392,34 +373,17 @@ let isCommutable = 1, Constraints = "$src = $rd", Defs = [SREG] in { // Expands to: // add Rd, Rr // adc Rd+1, Rr+1 - def ADDWRdRr - : Pseudo<(outs DREGS - : $rd), - (ins DREGS - : $src, DREGS - : $rr), - "addw\t$rd, $rr", - [(set i16 - : $rd, (add i16 - : $src, i16 - : $rr)), - (implicit SREG)]>; + def ADDWRdRr : Pseudo<(outs DREGS:$rd), (ins DREGS:$src, DREGS:$rr), + "addw\t$rd, $rr", + [(set i16:$rd, (add i16:$src, i16:$rr)), + (implicit SREG)]>; // ADC Rd, Rr // Adds two 8-bit registers with carry. - let Uses = [SREG] in def ADCRdRr - : FRdRr<0b0001, 0b11, - (outs GPR8 - : $rd), - (ins GPR8 - : $src, GPR8 - : $rr), - "adc\t$rd, $rr", - [(set i8 - : $rd, (adde i8 - : $src, i8 - : $rr)), - (implicit SREG)]>; + let Uses = [SREG] in + def ADCRdRr : FRdRr<0b0001, 0b11, (outs GPR8:$rd), (ins GPR8:$src, GPR8:$rr), + "adc\t$rd, $rr", + [(set i8:$rd, (adde i8:$src, i8:$rr)), (implicit SREG)]>; // ADCW Rd+1:Rd, Rr+1:Rr // Pseudo instruction to add four 8-bit registers as two 16-bit values with @@ -428,56 +392,30 @@ let isCommutable = 1, Constraints = "$src = $rd", Defs = [SREG] in { // Expands to: // adc Rd, Rr // adc Rd+1, Rr+1 - let Uses = [SREG] in def ADCWRdRr : Pseudo<(outs DREGS - : $rd), - (ins DREGS - : $src, DREGS - : $rr), - "adcw\t$rd, $rr", [ - (set i16 - : $rd, (adde i16 - : $src, i16 - : $rr)), - (implicit SREG) - ]>; + let Uses = [SREG] in + def ADCWRdRr : Pseudo<(outs DREGS:$rd), (ins DREGS:$src, DREGS:$rr), + "adcw\t$rd, $rr", + [(set i16:$rd, (adde i16:$src, i16:$rr)), + (implicit SREG)]>; // AIDW Rd, k // Adds an immediate 6-bit value K to Rd, placing the result in Rd. - def ADIWRdK - : FWRdK<0b0, - (outs IWREGS - : $rd), - (ins IWREGS - : $src, imm_arith6 - : $k), - "adiw\t$rd, $k", - [(set i16 - : $rd, (add i16 - : $src, uimm6 - : $k)), - (implicit SREG)]>, - Requires<[HasADDSUBIW]>; + def ADIWRdK : FWRdK<0b0, (outs IWREGS:$rd), (ins IWREGS :$src, imm_arith6:$k), + "adiw\t$rd, $k", + [(set i16:$rd, (add i16:$src, uimm6:$k)), + (implicit SREG)]>, + Requires<[HasADDSUBIW]>; } //===----------------------------------------------------------------------===// // Subtraction //===----------------------------------------------------------------------===// -let Constraints = "$src = $rd", Defs = [SREG] in { +let Constraints = "$rs = $rd", Defs = [SREG] in { // SUB Rd, Rr // Subtracts the 8-bit value of Rr from Rd and places the value in Rd. - def SUBRdRr - : FRdRr<0b0001, 0b10, - (outs GPR8 - : $rd), - (ins GPR8 - : $src, GPR8 - : $rr), - "sub\t$rd, $rr", - [(set i8 - : $rd, (sub i8 - : $src, i8 - : $rr)), - (implicit SREG)]>; + def SUBRdRr : FRdRr<0b0001, 0b10, (outs GPR8:$rd), (ins GPR8:$rs, GPR8:$rr), + "sub\t$rd, $rr", + [(set i8:$rd, (sub i8:$rs, i8:$rr)), (implicit SREG)]>; // SUBW Rd+1:Rd, Rr+1:Rr // Subtracts two 16-bit values and places the result into Rd. @@ -485,129 +423,58 @@ let Constraints = "$src = $rd", Defs = [SREG] in { // Expands to: // sub Rd, Rr // sbc Rd+1, Rr+1 - def SUBWRdRr - : Pseudo<(outs DREGS - : $rd), - (ins DREGS - : $src, DREGS - : $rr), - "subw\t$rd, $rr", - [(set i16 - : $rd, (sub i16 - : $src, i16 - : $rr)), - (implicit SREG)]>; + def SUBWRdRr : Pseudo<(outs DREGS:$rd), (ins DREGS:$rs, DREGS:$rr), + "subw\t$rd, $rr", + [(set i16:$rd, (sub i16:$rs, i16:$rr)), + (implicit SREG)]>; - def SUBIRdK - : FRdK<0b0101, - (outs LD8 - : $rd), - (ins LD8 - : $src, imm_ldi8 - : $k), - "subi\t$rd, $k", - [(set i8 - : $rd, (sub i8 - : $src, imm - : $k)), - (implicit SREG)]>; + def SUBIRdK : FRdK<0b0101, (outs LD8:$rd), (ins LD8:$rs, imm_ldi8:$k), + "subi\t$rd, $k", + [(set i8:$rd, (sub i8:$rs, imm:$k)), (implicit SREG)]>; // SUBIW Rd+1:Rd, K+1:K // // Expands to: // subi Rd, K // sbci Rd+1, K+1 - def SUBIWRdK - : Pseudo<(outs DLDREGS - : $rd), - (ins DLDREGS - : $src, i16imm - : $rr), - "subiw\t$rd, $rr", - [(set i16 - : $rd, (sub i16 - : $src, imm - : $rr)), - (implicit SREG)]>; + def SUBIWRdK : Pseudo<(outs DLDREGS:$rd), (ins DLDREGS:$rs, i16imm:$rr), + "subiw\t$rd, $rr", + [(set i16:$rd, (sub i16:$rs, imm:$rr)), + (implicit SREG)]>; - def SBIWRdK - : FWRdK<0b1, - (outs IWREGS - : $rd), - (ins IWREGS - : $src, imm_arith6 - : $k), - "sbiw\t$rd, $k", - [(set i16 - : $rd, (sub i16 - : $src, uimm6 - : $k)), - (implicit SREG)]>, - Requires<[HasADDSUBIW]>; + def SBIWRdK : FWRdK<0b1, (outs IWREGS:$rd), (ins IWREGS:$rs, imm_arith6:$k), + "sbiw\t$rd, $k", + [(set i16:$rd, (sub i16:$rs, uimm6:$k)), + (implicit SREG)]>, + Requires<[HasADDSUBIW]>; // Subtract with carry operations which must read the carry flag in SREG. let Uses = [SREG] in { - def SBCRdRr - : FRdRr<0b0000, 0b10, - (outs GPR8 - : $rd), - (ins GPR8 - : $src, GPR8 - : $rr), - "sbc\t$rd, $rr", - [(set i8 - : $rd, (sube i8 - : $src, i8 - : $rr)), - (implicit SREG)]>; + def SBCRdRr : FRdRr<0b0000, 0b10, (outs GPR8:$rd), (ins GPR8:$rs, GPR8:$rr), + "sbc\t$rd, $rr", + [(set i8:$rd, (sube i8:$rs, i8:$rr)), (implicit SREG)]>; // SBCW Rd+1:Rd, Rr+1:Rr // // Expands to: // sbc Rd, Rr // sbc Rd+1, Rr+1 - def SBCWRdRr : Pseudo<(outs DREGS - : $rd), - (ins DREGS - : $src, DREGS - : $rr), - "sbcw\t$rd, $rr", [ - (set i16 - : $rd, (sube i16 - : $src, i16 - : $rr)), - (implicit SREG) - ]>; + def SBCWRdRr : Pseudo<(outs DREGS:$rd), (ins DREGS:$rs, DREGS:$rr), + "sbcw\t$rd, $rr", + [(set i16:$rd, (sube i16:$rs, i16:$rr)), + (implicit SREG)]>; - def SBCIRdK - : FRdK<0b0100, - (outs LD8 - : $rd), - (ins LD8 - : $src, imm_ldi8 - : $k), - "sbci\t$rd, $k", - [(set i8 - : $rd, (sube i8 - : $src, imm - : $k)), - (implicit SREG)]>; + def SBCIRdK : FRdK<0b0100, (outs LD8:$rd), (ins LD8:$rs, imm_ldi8:$k), + "sbci\t$rd, $k", + [(set i8:$rd, (sube i8:$rs, imm:$k)), (implicit SREG)]>; // SBCIW Rd+1:Rd, K+1:K // sbci Rd, K // sbci Rd+1, K+1 - def SBCIWRdK : Pseudo<(outs DLDREGS - : $rd), - (ins DLDREGS - : $src, i16imm - : $rr), - "sbciw\t$rd, $rr", [ - (set i16 - : $rd, (sube i16 - : $src, imm - : $rr)), - (implicit SREG) - ]>; + def SBCIWRdK : Pseudo<(outs DLDREGS:$rd), (ins DLDREGS:$rs, i16imm:$rr), + "sbciw\t$rd, $rr", + [(set i16:$rd, (sube i16:$rs, imm:$rr)), + (implicit SREG)]>; } } @@ -615,27 +482,13 @@ let Constraints = "$src = $rd", Defs = [SREG] in { // Increment and Decrement //===----------------------------------------------------------------------===// let Constraints = "$src = $rd", Defs = [SREG] in { - def INCRd - : FRd<0b1001, 0b0100011, - (outs GPR8 - : $rd), - (ins GPR8 - : $src), - "inc\t$rd", [(set i8 - : $rd, (add i8 - : $src, 1)), - (implicit SREG)]>; + def INCRd : FRd<0b1001, 0b0100011, (outs GPR8:$rd), (ins GPR8:$src), + "inc\t$rd", + [(set i8:$rd, (add i8:$src, 1)), (implicit SREG)]>; - def DECRd - : FRd<0b1001, 0b0101010, - (outs GPR8 - : $rd), - (ins GPR8 - : $src), - "dec\t$rd", [(set i8 - : $rd, (add i8 - : $src, -1)), - (implicit SREG)]>; + def DECRd : FRd<0b1001, 0b0101010, (outs GPR8:$rd), (ins GPR8:$src), + "dec\t$rd", + [(set i8:$rd, (add i8:$src, -1)), (implicit SREG)]>; } //===----------------------------------------------------------------------===// @@ -646,58 +499,35 @@ let isCommutable = 1, Defs = [R1, R0, SREG] in { // MUL Rd, Rr // Multiplies Rd by Rr and places the result into R1:R0. let usesCustomInserter = 1 in { - def MULRdRr : FRdRr<0b1001, 0b11, (outs), - (ins GPR8 - : $rd, GPR8 - : $rr), - "mul\t$rd, $rr", - [/*(set R1, R0, (smullohi i8:$rd, i8:$rr))*/]>, + def MULRdRr : FRdRr<0b1001, 0b11, (outs), (ins GPR8:$rd, GPR8:$rr), + "mul\t$rd, $rr", []>, Requires<[SupportsMultiplication]>; - def MULSRdRr : FMUL2RdRr<0, (outs), - (ins LD8 - : $rd, LD8 - : $rr), + def MULSRdRr : FMUL2RdRr<0, (outs), (ins LD8:$rd, LD8:$rr), "muls\t$rd, $rr", []>, Requires<[SupportsMultiplication]>; } - def MULSURdRr : FMUL2RdRr<1, (outs), - (ins LD8lo - : $rd, LD8lo - : $rr), + def MULSURdRr : FMUL2RdRr<1, (outs), (ins LD8lo:$rd, LD8lo:$rr), "mulsu\t$rd, $rr", []>, Requires<[SupportsMultiplication]>; - def FMUL : FFMULRdRr<0b01, (outs), - (ins LD8lo - : $rd, LD8lo - : $rr), + def FMUL : FFMULRdRr<0b01, (outs), (ins LD8lo:$rd, LD8lo:$rr), "fmul\t$rd, $rr", []>, Requires<[SupportsMultiplication]>; - def FMULS : FFMULRdRr<0b10, (outs), - (ins LD8lo - : $rd, LD8lo - : $rr), + def FMULS : FFMULRdRr<0b10, (outs), (ins LD8lo:$rd, LD8lo:$rr), "fmuls\t$rd, $rr", []>, Requires<[SupportsMultiplication]>; - def FMULSU : FFMULRdRr<0b11, (outs), - (ins LD8lo - : $rd, LD8lo - : $rr), + def FMULSU : FFMULRdRr<0b11, (outs), (ins LD8lo:$rd, LD8lo:$rr), "fmulsu\t$rd, $rr", []>, Requires<[SupportsMultiplication]>; } let Defs = - [R15, R14, R13, R12, R11, R10, R9, R8, R7, R6, R5, R4, R3, R2, R1, - R0] in def DESK : FDES<(outs), - (ins i8imm - : $k), - "des\t$k", []>, - Requires<[HasDES]>; + [R15, R14, R13, R12, R11, R10, R9, R8, R7, R6, R5, R4, R3, R2, R1, R0] in +def DESK : FDES<(outs), (ins i8imm:$k), "des\t$k", []>, Requires<[HasDES]>; //===----------------------------------------------------------------------===// // Logic -- GitLab From 372c275800140f35a697f12a2e83d94d5603eaf5 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Mon, 1 Apr 2024 17:28:44 -0700 Subject: [PATCH 020/447] [dfsan][test] Disable the test with internal_symbolizer After #87191 we had to add 8b135a7d1f59a5a7adccb162abf92d751209afe7, which makes symbolizer to calls a global constructor with `realloc`. --- compiler-rt/test/dfsan/mmap_at_init.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler-rt/test/dfsan/mmap_at_init.c b/compiler-rt/test/dfsan/mmap_at_init.c index a8d7535df4a6..9129dc7d3903 100644 --- a/compiler-rt/test/dfsan/mmap_at_init.c +++ b/compiler-rt/test/dfsan/mmap_at_init.c @@ -4,6 +4,9 @@ // // Tests that calling mmap() during during dfsan initialization works. +// `internal_symbolizer` can not use `realloc` on memory from the test `calloc`. +// UNSUPPORTED: internal_symbolizer + #include #include #include -- GitLab From f33a6dcf959238e82f6ad45333e3547d8cfcfe38 Mon Sep 17 00:00:00 2001 From: Chen Zheng Date: Tue, 2 Apr 2024 08:40:28 +0800 Subject: [PATCH 021/447] [PPC][NFC] add an option for GatherAllAliasesMaxDepth (#87071) GatherAllAliases is time consuming. Add an debug option on PPC to control the complexity of the function. This is useful when debuging compile time related issues. --- llvm/lib/Target/PowerPC/PPCISelLowering.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp index 7436b202fba0..43e4a34a9b34 100644 --- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -137,6 +137,10 @@ static cl::opt PPCMinimumJumpTableEntries( "ppc-min-jump-table-entries", cl::init(64), cl::Hidden, cl::desc("Set minimum number of entries to use a jump table on PPC")); +static cl::opt PPCGatherAllAliasesMaxDepth( + "ppc-gather-alias-max-depth", cl::init(18), cl::Hidden, + cl::desc("max depth when checking alias info in GatherAllAliases()")); + STATISTIC(NumTailCalls, "Number of tail calls"); STATISTIC(NumSiblingCalls, "Number of sibling calls"); STATISTIC(ShufflesHandledWithVPERM, @@ -1512,6 +1516,8 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM, // than the corresponding branch. This information is used in CGP to decide // when to convert selects into branches. PredictableSelectIsExpensive = Subtarget.isPredictableSelectIsExpensive(); + + GatherAllAliasesMaxDepth = PPCGatherAllAliasesMaxDepth; } // *********************************** NOTE ************************************ -- GitLab From 84f24c2daffc40fc10b4ea2ae69016ebdabfc0ed Mon Sep 17 00:00:00 2001 From: Shih-Po Hung Date: Tue, 2 Apr 2024 09:26:27 +0800 Subject: [PATCH 022/447] [RISCV][TTI] Scale the cost of intrinsic umin/umax/smin/smax with LMUL (#87245) Use the return type to measure the LMUL size for throughput/latency cost --- .../Target/RISCV/RISCVTargetTransformInfo.cpp | 22 +++- .../Analysis/CostModel/RISCV/int-min-max.ll | 120 +++++++++--------- 2 files changed, 80 insertions(+), 62 deletions(-) diff --git a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp index efcaa65605e0..ed4b0ca8c941 100644 --- a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp +++ b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp @@ -810,9 +810,27 @@ RISCVTTIImpl::getIntrinsicInstrCost(const IntrinsicCostAttributes &ICA, case Intrinsic::smin: case Intrinsic::smax: { auto LT = getTypeLegalizationCost(RetTy); - if ((ST->hasVInstructions() && LT.second.isVector()) || - (LT.second.isScalarInteger() && ST->hasStdExtZbb())) + if (LT.second.isScalarInteger() && ST->hasStdExtZbb()) return LT.first; + + if (ST->hasVInstructions() && LT.second.isVector()) { + unsigned Op; + switch (ICA.getID()) { + case Intrinsic::umin: + Op = RISCV::VMINU_VV; + break; + case Intrinsic::umax: + Op = RISCV::VMAXU_VV; + break; + case Intrinsic::smin: + Op = RISCV::VMIN_VV; + break; + case Intrinsic::smax: + Op = RISCV::VMAX_VV; + break; + } + return LT.first * getRISCVInstructionCost(Op, LT.second, CostKind); + } break; } case Intrinsic::sadd_sat: diff --git a/llvm/test/Analysis/CostModel/RISCV/int-min-max.ll b/llvm/test/Analysis/CostModel/RISCV/int-min-max.ll index ec669c986c15..79cf1c84ed49 100644 --- a/llvm/test/Analysis/CostModel/RISCV/int-min-max.ll +++ b/llvm/test/Analysis/CostModel/RISCV/int-min-max.ll @@ -12,36 +12,36 @@ define void @smax() { ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %7 = call @llvm.smax.nxv2i8( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %8 = call @llvm.smax.nxv4i8( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %9 = call @llvm.smax.nxv8i8( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %10 = call @llvm.smax.nxv16i8( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %10 = call @llvm.smax.nxv16i8( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %11 = call i16 @llvm.smax.i16(i16 undef, i16 undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %12 = call <2 x i16> @llvm.smax.v2i16(<2 x i16> undef, <2 x i16> undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %13 = call <4 x i16> @llvm.smax.v4i16(<4 x i16> undef, <4 x i16> undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %14 = call <8 x i16> @llvm.smax.v8i16(<8 x i16> undef, <8 x i16> undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %15 = call <16 x i16> @llvm.smax.v16i16(<16 x i16> undef, <16 x i16> undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %15 = call <16 x i16> @llvm.smax.v16i16(<16 x i16> undef, <16 x i16> undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %16 = call @llvm.smax.nxv1i16( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %17 = call @llvm.smax.nxv2i16( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %18 = call @llvm.smax.nxv4i16( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %19 = call @llvm.smax.nxv8i16( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %20 = call @llvm.smax.nxv16i16( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %19 = call @llvm.smax.nxv8i16( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %20 = call @llvm.smax.nxv16i16( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %21 = call i32 @llvm.smax.i32(i32 undef, i32 undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %22 = call <2 x i32> @llvm.smax.v2i32(<2 x i32> undef, <2 x i32> undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %23 = call <4 x i32> @llvm.smax.v4i32(<4 x i32> undef, <4 x i32> undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %24 = call <8 x i32> @llvm.smax.v8i32(<8 x i32> undef, <8 x i32> undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %25 = call <16 x i32> @llvm.smax.v16i32(<16 x i32> undef, <16 x i32> undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %24 = call <8 x i32> @llvm.smax.v8i32(<8 x i32> undef, <8 x i32> undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %25 = call <16 x i32> @llvm.smax.v16i32(<16 x i32> undef, <16 x i32> undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %26 = call @llvm.smax.nxv1i32( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %27 = call @llvm.smax.nxv2i32( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %28 = call @llvm.smax.nxv4i32( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %29 = call @llvm.smax.nxv8i32( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %30 = call @llvm.smax.nxv16i32( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %28 = call @llvm.smax.nxv4i32( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %29 = call @llvm.smax.nxv8i32( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %30 = call @llvm.smax.nxv16i32( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %31 = call i64 @llvm.smax.i64(i64 undef, i64 undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %32 = call <2 x i64> @llvm.smax.v2i64(<2 x i64> undef, <2 x i64> undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %33 = call <4 x i64> @llvm.smax.v4i64(<4 x i64> undef, <4 x i64> undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %34 = call <8 x i64> @llvm.smax.v8i64(<8 x i64> undef, <8 x i64> undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %35 = call <16 x i64> @llvm.smax.v16i64(<16 x i64> undef, <16 x i64> undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %33 = call <4 x i64> @llvm.smax.v4i64(<4 x i64> undef, <4 x i64> undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %34 = call <8 x i64> @llvm.smax.v8i64(<8 x i64> undef, <8 x i64> undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %35 = call <16 x i64> @llvm.smax.v16i64(<16 x i64> undef, <16 x i64> undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %36 = call @llvm.smax.nxv1i64( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %37 = call @llvm.smax.nxv2i64( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %38 = call @llvm.smax.nxv4i64( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %39 = call @llvm.smax.nxv8i64( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %37 = call @llvm.smax.nxv2i64( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %38 = call @llvm.smax.nxv4i64( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %39 = call @llvm.smax.nxv8i64( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 0 for instruction: ret void ; call i8 @llvm.smax.i8(i8 undef, i8 undef) @@ -97,36 +97,36 @@ define void @smin() { ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %7 = call @llvm.smin.nxv2i8( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %8 = call @llvm.smin.nxv4i8( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %9 = call @llvm.smin.nxv8i8( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %10 = call @llvm.smin.nxv16i8( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %10 = call @llvm.smin.nxv16i8( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %11 = call i16 @llvm.smin.i16(i16 undef, i16 undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %12 = call <2 x i16> @llvm.smin.v2i16(<2 x i16> undef, <2 x i16> undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %13 = call <4 x i16> @llvm.smin.v4i16(<4 x i16> undef, <4 x i16> undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %14 = call <8 x i16> @llvm.smin.v8i16(<8 x i16> undef, <8 x i16> undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %15 = call <16 x i16> @llvm.smin.v16i16(<16 x i16> undef, <16 x i16> undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %15 = call <16 x i16> @llvm.smin.v16i16(<16 x i16> undef, <16 x i16> undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %16 = call @llvm.smin.nxv1i16( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %17 = call @llvm.smin.nxv2i16( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %18 = call @llvm.smin.nxv4i16( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %19 = call @llvm.smin.nxv8i16( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %20 = call @llvm.smin.nxv16i16( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %19 = call @llvm.smin.nxv8i16( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %20 = call @llvm.smin.nxv16i16( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %21 = call i32 @llvm.smin.i32(i32 undef, i32 undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %22 = call <2 x i32> @llvm.smin.v2i32(<2 x i32> undef, <2 x i32> undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %23 = call <4 x i32> @llvm.smin.v4i32(<4 x i32> undef, <4 x i32> undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %24 = call <8 x i32> @llvm.smin.v8i32(<8 x i32> undef, <8 x i32> undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %25 = call <16 x i32> @llvm.smin.v16i32(<16 x i32> undef, <16 x i32> undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %24 = call <8 x i32> @llvm.smin.v8i32(<8 x i32> undef, <8 x i32> undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %25 = call <16 x i32> @llvm.smin.v16i32(<16 x i32> undef, <16 x i32> undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %26 = call @llvm.smin.nxv1i32( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %27 = call @llvm.smin.nxv2i32( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %28 = call @llvm.smin.nxv4i32( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %29 = call @llvm.smin.nxv8i32( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %30 = call @llvm.smin.nxv16i32( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %28 = call @llvm.smin.nxv4i32( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %29 = call @llvm.smin.nxv8i32( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %30 = call @llvm.smin.nxv16i32( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %31 = call i64 @llvm.smin.i64(i64 undef, i64 undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %32 = call <2 x i64> @llvm.smin.v2i64(<2 x i64> undef, <2 x i64> undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %33 = call <4 x i64> @llvm.smin.v4i64(<4 x i64> undef, <4 x i64> undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %34 = call <8 x i64> @llvm.smin.v8i64(<8 x i64> undef, <8 x i64> undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %35 = call <16 x i64> @llvm.smin.v16i64(<16 x i64> undef, <16 x i64> undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %33 = call <4 x i64> @llvm.smin.v4i64(<4 x i64> undef, <4 x i64> undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %34 = call <8 x i64> @llvm.smin.v8i64(<8 x i64> undef, <8 x i64> undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %35 = call <16 x i64> @llvm.smin.v16i64(<16 x i64> undef, <16 x i64> undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %36 = call @llvm.smin.nxv1i64( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %37 = call @llvm.smin.nxv2i64( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %38 = call @llvm.smin.nxv4i64( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %39 = call @llvm.smin.nxv8i64( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %37 = call @llvm.smin.nxv2i64( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %38 = call @llvm.smin.nxv4i64( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %39 = call @llvm.smin.nxv8i64( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 0 for instruction: ret void ; call i8 @llvm.smin.i8(i8 undef, i8 undef) @@ -182,36 +182,36 @@ define void @umax() { ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %7 = call @llvm.umax.nxv2i8( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %8 = call @llvm.umax.nxv4i8( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %9 = call @llvm.umax.nxv8i8( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %10 = call @llvm.umax.nxv16i8( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %10 = call @llvm.umax.nxv16i8( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %11 = call i16 @llvm.umax.i16(i16 undef, i16 undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %12 = call <2 x i16> @llvm.umax.v2i16(<2 x i16> undef, <2 x i16> undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %13 = call <4 x i16> @llvm.umax.v4i16(<4 x i16> undef, <4 x i16> undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %14 = call <8 x i16> @llvm.umax.v8i16(<8 x i16> undef, <8 x i16> undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %15 = call <16 x i16> @llvm.umax.v16i16(<16 x i16> undef, <16 x i16> undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %15 = call <16 x i16> @llvm.umax.v16i16(<16 x i16> undef, <16 x i16> undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %16 = call @llvm.umax.nxv1i16( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %17 = call @llvm.umax.nxv2i16( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %18 = call @llvm.umax.nxv4i16( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %19 = call @llvm.umax.nxv8i16( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %20 = call @llvm.umax.nxv16i16( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %19 = call @llvm.umax.nxv8i16( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %20 = call @llvm.umax.nxv16i16( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %21 = call i32 @llvm.umax.i32(i32 undef, i32 undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %22 = call <2 x i32> @llvm.umax.v2i32(<2 x i32> undef, <2 x i32> undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %23 = call <4 x i32> @llvm.umax.v4i32(<4 x i32> undef, <4 x i32> undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %24 = call <8 x i32> @llvm.umax.v8i32(<8 x i32> undef, <8 x i32> undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %25 = call <16 x i32> @llvm.umax.v16i32(<16 x i32> undef, <16 x i32> undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %24 = call <8 x i32> @llvm.umax.v8i32(<8 x i32> undef, <8 x i32> undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %25 = call <16 x i32> @llvm.umax.v16i32(<16 x i32> undef, <16 x i32> undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %26 = call @llvm.umax.nxv1i32( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %27 = call @llvm.umax.nxv2i32( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %28 = call @llvm.umax.nxv4i32( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %29 = call @llvm.umax.nxv8i32( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %30 = call @llvm.umax.nxv16i32( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %28 = call @llvm.umax.nxv4i32( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %29 = call @llvm.umax.nxv8i32( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %30 = call @llvm.umax.nxv16i32( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %31 = call i64 @llvm.umax.i64(i64 undef, i64 undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %32 = call <2 x i64> @llvm.umax.v2i64(<2 x i64> undef, <2 x i64> undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %33 = call <4 x i64> @llvm.umax.v4i64(<4 x i64> undef, <4 x i64> undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %34 = call <8 x i64> @llvm.umax.v8i64(<8 x i64> undef, <8 x i64> undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %35 = call <16 x i64> @llvm.umax.v16i64(<16 x i64> undef, <16 x i64> undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %33 = call <4 x i64> @llvm.umax.v4i64(<4 x i64> undef, <4 x i64> undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %34 = call <8 x i64> @llvm.umax.v8i64(<8 x i64> undef, <8 x i64> undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %35 = call <16 x i64> @llvm.umax.v16i64(<16 x i64> undef, <16 x i64> undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %36 = call @llvm.umax.nxv1i64( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %37 = call @llvm.umax.nxv2i64( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %38 = call @llvm.umax.nxv4i64( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %39 = call @llvm.umax.nxv8i64( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %37 = call @llvm.umax.nxv2i64( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %38 = call @llvm.umax.nxv4i64( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %39 = call @llvm.umax.nxv8i64( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 0 for instruction: ret void ; call i8 @llvm.umax.i8(i8 undef, i8 undef) @@ -267,36 +267,36 @@ define void @umin() { ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %7 = call @llvm.umin.nxv2i8( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %8 = call @llvm.umin.nxv4i8( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %9 = call @llvm.umin.nxv8i8( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %10 = call @llvm.umin.nxv16i8( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %10 = call @llvm.umin.nxv16i8( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %11 = call i16 @llvm.umin.i16(i16 undef, i16 undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %12 = call <2 x i16> @llvm.umin.v2i16(<2 x i16> undef, <2 x i16> undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %13 = call <4 x i16> @llvm.umin.v4i16(<4 x i16> undef, <4 x i16> undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %14 = call <8 x i16> @llvm.umin.v8i16(<8 x i16> undef, <8 x i16> undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %15 = call <16 x i16> @llvm.umin.v16i16(<16 x i16> undef, <16 x i16> undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %15 = call <16 x i16> @llvm.umin.v16i16(<16 x i16> undef, <16 x i16> undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %16 = call @llvm.umin.nxv1i16( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %17 = call @llvm.umin.nxv2i16( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %18 = call @llvm.umin.nxv4i16( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %19 = call @llvm.umin.nxv8i16( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %20 = call @llvm.umin.nxv16i16( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %19 = call @llvm.umin.nxv8i16( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %20 = call @llvm.umin.nxv16i16( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %21 = call i32 @llvm.umin.i32(i32 undef, i32 undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %22 = call <2 x i32> @llvm.umin.v2i32(<2 x i32> undef, <2 x i32> undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %23 = call <4 x i32> @llvm.umin.v4i32(<4 x i32> undef, <4 x i32> undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %24 = call <8 x i32> @llvm.umin.v8i32(<8 x i32> undef, <8 x i32> undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %25 = call <16 x i32> @llvm.umin.v16i32(<16 x i32> undef, <16 x i32> undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %24 = call <8 x i32> @llvm.umin.v8i32(<8 x i32> undef, <8 x i32> undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %25 = call <16 x i32> @llvm.umin.v16i32(<16 x i32> undef, <16 x i32> undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %26 = call @llvm.umin.nxv1i32( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %27 = call @llvm.umin.nxv2i32( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %28 = call @llvm.umin.nxv4i32( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %29 = call @llvm.umin.nxv8i32( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %30 = call @llvm.umin.nxv16i32( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %28 = call @llvm.umin.nxv4i32( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %29 = call @llvm.umin.nxv8i32( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %30 = call @llvm.umin.nxv16i32( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %31 = call i64 @llvm.umin.i64(i64 undef, i64 undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %32 = call <2 x i64> @llvm.umin.v2i64(<2 x i64> undef, <2 x i64> undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %33 = call <4 x i64> @llvm.umin.v4i64(<4 x i64> undef, <4 x i64> undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %34 = call <8 x i64> @llvm.umin.v8i64(<8 x i64> undef, <8 x i64> undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %35 = call <16 x i64> @llvm.umin.v16i64(<16 x i64> undef, <16 x i64> undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %33 = call <4 x i64> @llvm.umin.v4i64(<4 x i64> undef, <4 x i64> undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %34 = call <8 x i64> @llvm.umin.v8i64(<8 x i64> undef, <8 x i64> undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %35 = call <16 x i64> @llvm.umin.v16i64(<16 x i64> undef, <16 x i64> undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %36 = call @llvm.umin.nxv1i64( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %37 = call @llvm.umin.nxv2i64( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %38 = call @llvm.umin.nxv4i64( undef, undef) -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %39 = call @llvm.umin.nxv8i64( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %37 = call @llvm.umin.nxv2i64( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %38 = call @llvm.umin.nxv4i64( undef, undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %39 = call @llvm.umin.nxv8i64( undef, undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 0 for instruction: ret void ; call i8 @llvm.umin.i8(i8 undef, i8 undef) -- GitLab From 30fd099d5062638b5fe6b89135ad6433a888023a Mon Sep 17 00:00:00 2001 From: Cyndy Ishida Date: Mon, 1 Apr 2024 18:30:23 -0700 Subject: [PATCH 023/447] [InstallAPI] Fixup dsym test (#87299) Update the test to run when the compiler is built to support arm64-darwin targets. --- clang/test/InstallAPI/diagnostics-dsym.test | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/clang/test/InstallAPI/diagnostics-dsym.test b/clang/test/InstallAPI/diagnostics-dsym.test index 8a1b394f2f86..c9cbeffef7ba 100644 --- a/clang/test/InstallAPI/diagnostics-dsym.test +++ b/clang/test/InstallAPI/diagnostics-dsym.test @@ -1,23 +1,24 @@ -; REQUIRES: 86_64-darwin +; REQUIRES: system-darwin +; REQUIRES: target-aarch64 ; RUN: rm -rf %t ; RUN: split-file %s %t // Build a simple dylib with debug info. -; RUN: %clang --target=x86_64-apple-macos10.15 -g -dynamiclib %t/foo.c \ +; RUN: %clang --target=arm64-apple-macos11 -g -dynamiclib %t/foo.c \ ; RUN: -current_version 1 -compatibility_version 1 -L%t/usr/lib \ ; RUN: -save-temps \ ; RUN: -o %t/foo.dylib -install_name %t/foo.dylib ; RUN: dsymutil %t/foo.dylib -o %t/foo.dSYM -; RUN: not clang-installapi -x c++ --target=x86_64-apple-macos10.15 \ +; RUN: not clang-installapi -x c++ --target=arm64-apple-macos11 \ ; RUN: -install_name %t/foo.dylib \ ; RUN: -current_version 1 -compatibility_version 1 \ ; RUN: -o %t/output.tbd \ ; RUN: --verify-against=%t/foo.dylib --dsym=%t/foo.dSYM \ ; RUN: --verify-mode=Pedantic 2>&1 | FileCheck %s -; CHECK: violations found for x86_64 +; CHECK: violations found for arm64 ; CHECK: foo.c:5:0: error: no declaration found for exported symbol 'bar' in dynamic library ; CHECK: foo.c:1:0: error: no declaration found for exported symbol 'foo' in dynamic library @@ -31,9 +32,9 @@ char bar = 'a'; ;--- usr/lib/libSystem.tbd --- !tapi-tbd tbd-version: 4 -targets: [ x86_64-macos ] +targets: [ arm64-macos ] install-name: '/usr/lib/libSystem.B.dylib' exports: - - targets: [ x86_64-macos ] + - targets: [ arm64-macos ] symbols: [ dyld_stub_binder ] ... -- GitLab From d7a43a00fe80007de5d7614576b180d3d21d541b Mon Sep 17 00:00:00 2001 From: Shih-Po Hung Date: Tue, 2 Apr 2024 09:30:51 +0800 Subject: [PATCH 024/447] [RISCV][TTI] Scale the cost of trunc/fptrunc/fpext with LMUL (#87101) Use the destination data type to measure the LMUL size for latency/throughput cost --- .../Target/RISCV/RISCVTargetTransformInfo.cpp | 25 +- llvm/test/Analysis/CostModel/RISCV/cast.ll | 454 +++++++++--------- .../CostModel/RISCV/reduce-scalable-fp.ll | 12 +- .../CostModel/RISCV/rvv-insertelement.ll | 84 ++-- .../CostModel/RISCV/shuffle-broadcast.ll | 2 +- 5 files changed, 298 insertions(+), 279 deletions(-) diff --git a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp index ed4b0ca8c941..38304ff90252 100644 --- a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp +++ b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp @@ -927,6 +927,7 @@ InstructionCost RISCVTTIImpl::getCastInstrCost(unsigned Opcode, Type *Dst, if (!IsTypeLegal) return BaseT::getCastInstrCost(Opcode, Dst, Src, CCH, CostKind, I); + std::pair SrcLT = getTypeLegalizationCost(Src); std::pair DstLT = getTypeLegalizationCost(Dst); int ISD = TLI->InstructionOpcodeToISD(Opcode); @@ -961,13 +962,31 @@ InstructionCost RISCVTTIImpl::getCastInstrCost(unsigned Opcode, Type *Dst, // Instead we use the following instructions to truncate to mask vector: // vand.vi v8, v8, 1 // vmsne.vi v0, v8, 0 - return 2; + return getRISCVInstructionCost({RISCV::VAND_VI, RISCV::VMSNE_VI}, + SrcLT.second, CostKind); } [[fallthrough]]; case ISD::FP_EXTEND: - case ISD::FP_ROUND: + case ISD::FP_ROUND: { // Counts of narrow/widen instructions. - return std::abs(PowDiff); + unsigned SrcEltSize = Src->getScalarSizeInBits(); + unsigned DstEltSize = Dst->getScalarSizeInBits(); + + unsigned Op = (ISD == ISD::TRUNCATE) ? RISCV::VNSRL_WI + : (ISD == ISD::FP_EXTEND) ? RISCV::VFWCVT_F_F_V + : RISCV::VFNCVT_F_F_W; + InstructionCost Cost = 0; + for (; SrcEltSize != DstEltSize;) { + MVT ElementMVT = (ISD == ISD::TRUNCATE) + ? MVT::getIntegerVT(DstEltSize) + : MVT::getFloatingPointVT(DstEltSize); + MVT DstMVT = DstLT.second.changeVectorElementType(ElementMVT); + DstEltSize = + (DstEltSize > SrcEltSize) ? DstEltSize >> 1 : DstEltSize << 1; + Cost += getRISCVInstructionCost(Op, DstMVT, CostKind); + } + return Cost; + } case ISD::FP_TO_SINT: case ISD::FP_TO_UINT: case ISD::SINT_TO_FP: diff --git a/llvm/test/Analysis/CostModel/RISCV/cast.ll b/llvm/test/Analysis/CostModel/RISCV/cast.ll index 14da9a3f79d7..6ddd57a24c51 100644 --- a/llvm/test/Analysis/CostModel/RISCV/cast.ll +++ b/llvm/test/Analysis/CostModel/RISCV/cast.ll @@ -1035,17 +1035,17 @@ define void @trunc() { ; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v4i8_v4i1 = trunc <4 x i8> undef to <4 x i1> ; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v4i16_v4i1 = trunc <4 x i16> undef to <4 x i1> ; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v4i32_v4i1 = trunc <4 x i32> undef to <4 x i1> -; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v4i64_v4i1 = trunc <4 x i64> undef to <4 x i1> +; RV32-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %v4i64_v4i1 = trunc <4 x i64> undef to <4 x i1> ; RV32-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v8i16_v8i8 = trunc <8 x i16> undef to <8 x i8> ; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v8i32_v8i8 = trunc <8 x i32> undef to <8 x i8> -; RV32-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %v8i64_v8i8 = trunc <8 x i64> undef to <8 x i8> +; RV32-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %v8i64_v8i8 = trunc <8 x i64> undef to <8 x i8> ; RV32-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v8i32_v8i16 = trunc <8 x i32> undef to <8 x i16> -; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v8i64_v8i16 = trunc <8 x i64> undef to <8 x i16> -; RV32-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v8i64_v8i32 = trunc <8 x i64> undef to <8 x i32> +; RV32-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %v8i64_v8i16 = trunc <8 x i64> undef to <8 x i16> +; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v8i64_v8i32 = trunc <8 x i64> undef to <8 x i32> ; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v8i8_v8i1 = trunc <8 x i8> undef to <8 x i1> ; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v8i16_v8i1 = trunc <8 x i16> undef to <8 x i1> -; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v8i32_v8i1 = trunc <8 x i32> undef to <8 x i1> -; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v8i64_v8i1 = trunc <8 x i64> undef to <8 x i1> +; RV32-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %v8i32_v8i1 = trunc <8 x i32> undef to <8 x i1> +; RV32-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %v8i64_v8i1 = trunc <8 x i64> undef to <8 x i1> ; RV32-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v16i16_v16i8 = trunc <2 x i16> undef to <2 x i8> ; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v16i32_v16i8 = trunc <2 x i32> undef to <2 x i8> ; RV32-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %v16i64_v16i8 = trunc <2 x i64> undef to <2 x i8> @@ -1057,44 +1057,44 @@ define void @trunc() { ; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v16i32_v16i1 = trunc <2 x i32> undef to <2 x i1> ; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v16i64_v16i1 = trunc <2 x i64> undef to <2 x i1> ; RV32-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v32i16_v32i8 = trunc <16 x i16> undef to <16 x i8> -; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v32i32_v32i8 = trunc <16 x i32> undef to <16 x i8> -; RV32-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %v32i64_v32i8 = trunc <16 x i64> undef to <16 x i8> -; RV32-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v32i32_v32i16 = trunc <16 x i32> undef to <16 x i16> -; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v32i64_v32i16 = trunc <16 x i64> undef to <16 x i16> -; RV32-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v32i64_v32i32 = trunc <16 x i64> undef to <16 x i32> +; RV32-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %v32i32_v32i8 = trunc <16 x i32> undef to <16 x i8> +; RV32-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %v32i64_v32i8 = trunc <16 x i64> undef to <16 x i8> +; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v32i32_v32i16 = trunc <16 x i32> undef to <16 x i16> +; RV32-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %v32i64_v32i16 = trunc <16 x i64> undef to <16 x i16> +; RV32-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %v32i64_v32i32 = trunc <16 x i64> undef to <16 x i32> ; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v32i8_v32i1 = trunc <16 x i8> undef to <16 x i1> -; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v32i16_v32i1 = trunc <16 x i16> undef to <16 x i1> -; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v32i32_v32i1 = trunc <16 x i32> undef to <16 x i1> -; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v32i64_v32i1 = trunc <16 x i64> undef to <16 x i1> -; RV32-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v64i16_v64i8 = trunc <64 x i16> undef to <64 x i8> -; RV32-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %v64i32_v64i8 = trunc <64 x i32> undef to <64 x i8> -; RV32-NEXT: Cost Model: Found an estimated cost of 15 for instruction: %v64i64_v64i8 = trunc <64 x i64> undef to <64 x i8> -; RV32-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %v64i32_v64i16 = trunc <64 x i32> undef to <64 x i16> -; RV32-NEXT: Cost Model: Found an estimated cost of 11 for instruction: %v64i64_v64i16 = trunc <64 x i64> undef to <64 x i16> -; RV32-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %v64i64_v64i32 = trunc <64 x i64> undef to <64 x i32> -; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v64i8_v64i1 = trunc <64 x i8> undef to <64 x i1> -; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v64i16_v64i1 = trunc <64 x i16> undef to <64 x i1> -; RV32-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %v64i32_v64i1 = trunc <64 x i32> undef to <64 x i1> +; RV32-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %v32i16_v32i1 = trunc <16 x i16> undef to <16 x i1> +; RV32-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %v32i32_v32i1 = trunc <16 x i32> undef to <16 x i1> +; RV32-NEXT: Cost Model: Found an estimated cost of 16 for instruction: %v32i64_v32i1 = trunc <16 x i64> undef to <16 x i1> +; RV32-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %v64i16_v64i8 = trunc <64 x i16> undef to <64 x i8> +; RV32-NEXT: Cost Model: Found an estimated cost of 13 for instruction: %v64i32_v64i8 = trunc <64 x i32> undef to <64 x i8> +; RV32-NEXT: Cost Model: Found an estimated cost of 31 for instruction: %v64i64_v64i8 = trunc <64 x i64> undef to <64 x i8> +; RV32-NEXT: Cost Model: Found an estimated cost of 9 for instruction: %v64i32_v64i16 = trunc <64 x i32> undef to <64 x i16> +; RV32-NEXT: Cost Model: Found an estimated cost of 27 for instruction: %v64i64_v64i16 = trunc <64 x i64> undef to <64 x i16> +; RV32-NEXT: Cost Model: Found an estimated cost of 18 for instruction: %v64i64_v64i32 = trunc <64 x i64> undef to <64 x i32> +; RV32-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %v64i8_v64i1 = trunc <64 x i8> undef to <64 x i1> +; RV32-NEXT: Cost Model: Found an estimated cost of 16 for instruction: %v64i16_v64i1 = trunc <64 x i16> undef to <64 x i1> +; RV32-NEXT: Cost Model: Found an estimated cost of 33 for instruction: %v64i32_v64i1 = trunc <64 x i32> undef to <64 x i1> ; RV32-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v64i64_v64i1 = trunc <64 x i64> undef to <64 x i1> -; RV32-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %v128i16_v128i8 = trunc <128 x i16> undef to <128 x i8> -; RV32-NEXT: Cost Model: Found an estimated cost of 11 for instruction: %v128i32_v128i8 = trunc <128 x i32> undef to <128 x i8> -; RV32-NEXT: Cost Model: Found an estimated cost of 31 for instruction: %v128i64_v128i8 = trunc <128 x i64> undef to <128 x i8> -; RV32-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %v128i32_v128i16 = trunc <128 x i32> undef to <128 x i16> -; RV32-NEXT: Cost Model: Found an estimated cost of 22 for instruction: %v128i64_v128i16 = trunc <128 x i64> undef to <128 x i16> -; RV32-NEXT: Cost Model: Found an estimated cost of 12 for instruction: %v128i64_v128i32 = trunc <128 x i64> undef to <128 x i32> -; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v128i8_v128i1 = trunc <128 x i8> undef to <128 x i1> -; RV32-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %v128i16_v128i1 = trunc <128 x i16> undef to <128 x i1> -; RV32-NEXT: Cost Model: Found an estimated cost of 11 for instruction: %v128i32_v128i1 = trunc <128 x i32> undef to <128 x i1> +; RV32-NEXT: Cost Model: Found an estimated cost of 9 for instruction: %v128i16_v128i8 = trunc <128 x i16> undef to <128 x i8> +; RV32-NEXT: Cost Model: Found an estimated cost of 27 for instruction: %v128i32_v128i8 = trunc <128 x i32> undef to <128 x i8> +; RV32-NEXT: Cost Model: Found an estimated cost of 63 for instruction: %v128i64_v128i8 = trunc <128 x i64> undef to <128 x i8> +; RV32-NEXT: Cost Model: Found an estimated cost of 18 for instruction: %v128i32_v128i16 = trunc <128 x i32> undef to <128 x i16> +; RV32-NEXT: Cost Model: Found an estimated cost of 54 for instruction: %v128i64_v128i16 = trunc <128 x i64> undef to <128 x i16> +; RV32-NEXT: Cost Model: Found an estimated cost of 36 for instruction: %v128i64_v128i32 = trunc <128 x i64> undef to <128 x i32> +; RV32-NEXT: Cost Model: Found an estimated cost of 16 for instruction: %v128i8_v128i1 = trunc <128 x i8> undef to <128 x i1> +; RV32-NEXT: Cost Model: Found an estimated cost of 33 for instruction: %v128i16_v128i1 = trunc <128 x i16> undef to <128 x i1> +; RV32-NEXT: Cost Model: Found an estimated cost of 67 for instruction: %v128i32_v128i1 = trunc <128 x i32> undef to <128 x i1> ; RV32-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %v128i64_v128i1 = trunc <128 x i64> undef to <128 x i1> -; RV32-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %v256i16_v256i8 = trunc <256 x i16> undef to <256 x i8> -; RV32-NEXT: Cost Model: Found an estimated cost of 22 for instruction: %v256i32_v256i8 = trunc <256 x i32> undef to <256 x i8> -; RV32-NEXT: Cost Model: Found an estimated cost of 62 for instruction: %v256i64_v256i8 = trunc <256 x i64> undef to <256 x i8> -; RV32-NEXT: Cost Model: Found an estimated cost of 12 for instruction: %v256i32_v256i16 = trunc <256 x i32> undef to <256 x i16> -; RV32-NEXT: Cost Model: Found an estimated cost of 44 for instruction: %v256i64_v256i16 = trunc <256 x i64> undef to <256 x i16> -; RV32-NEXT: Cost Model: Found an estimated cost of 24 for instruction: %v256i64_v256i32 = trunc <256 x i64> undef to <256 x i32> -; RV32-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %v256i8_v256i1 = trunc <256 x i8> undef to <256 x i1> -; RV32-NEXT: Cost Model: Found an estimated cost of 10 for instruction: %v256i16_v256i1 = trunc <256 x i16> undef to <256 x i1> -; RV32-NEXT: Cost Model: Found an estimated cost of 22 for instruction: %v256i32_v256i1 = trunc <256 x i32> undef to <256 x i1> +; RV32-NEXT: Cost Model: Found an estimated cost of 18 for instruction: %v256i16_v256i8 = trunc <256 x i16> undef to <256 x i8> +; RV32-NEXT: Cost Model: Found an estimated cost of 54 for instruction: %v256i32_v256i8 = trunc <256 x i32> undef to <256 x i8> +; RV32-NEXT: Cost Model: Found an estimated cost of 126 for instruction: %v256i64_v256i8 = trunc <256 x i64> undef to <256 x i8> +; RV32-NEXT: Cost Model: Found an estimated cost of 36 for instruction: %v256i32_v256i16 = trunc <256 x i32> undef to <256 x i16> +; RV32-NEXT: Cost Model: Found an estimated cost of 108 for instruction: %v256i64_v256i16 = trunc <256 x i64> undef to <256 x i16> +; RV32-NEXT: Cost Model: Found an estimated cost of 72 for instruction: %v256i64_v256i32 = trunc <256 x i64> undef to <256 x i32> +; RV32-NEXT: Cost Model: Found an estimated cost of 32 for instruction: %v256i8_v256i1 = trunc <256 x i8> undef to <256 x i1> +; RV32-NEXT: Cost Model: Found an estimated cost of 66 for instruction: %v256i16_v256i1 = trunc <256 x i16> undef to <256 x i1> +; RV32-NEXT: Cost Model: Found an estimated cost of 134 for instruction: %v256i32_v256i1 = trunc <256 x i32> undef to <256 x i1> ; RV32-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %v256i64_v256i1 = trunc <256 x i64> undef to <256 x i1> ; RV32-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv1i16_nxv1i8 = trunc undef to ; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv1i32_nxv1i8 = trunc undef to @@ -1115,56 +1115,56 @@ define void @trunc() { ; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv2i8_nxv2i1 = trunc undef to ; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv2i16_nxv2i1 = trunc undef to ; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv2i32_nxv2i1 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv2i64_nxv2i1 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %nxv2i64_nxv2i1 = trunc undef to ; RV32-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv4i16_nxv4i8 = trunc undef to ; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv4i32_nxv4i8 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %nxv4i64_nxv4i8 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %nxv4i64_nxv4i8 = trunc undef to ; RV32-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv4i32_nxv4i16 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv4i64_nxv4i16 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv4i64_nxv4i32 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %nxv4i64_nxv4i16 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv4i64_nxv4i32 = trunc undef to ; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv4i8_nxv4i1 = trunc undef to ; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv4i16_nxv4i1 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv4i32_nxv4i1 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv4i64_nxv4i1 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %nxv4i32_nxv4i1 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %nxv4i64_nxv4i1 = trunc undef to ; RV32-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv8i16_nxv8i8 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv8i32_nxv8i8 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %nxv8i64_nxv8i8 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv8i32_nxv8i16 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv8i64_nxv8i16 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv8i64_nxv8i32 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %nxv8i32_nxv8i8 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %nxv8i64_nxv8i8 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv8i32_nxv8i16 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %nxv8i64_nxv8i16 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %nxv8i64_nxv8i32 = trunc undef to ; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv8i8_nxv8i1 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv8i16_nxv8i1 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv8i32_nxv8i1 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv8i64_nxv8i1 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv16i16_nxv16i8 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv16i32_nxv16i8 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %nxv16i64_nxv16i8 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv16i32_nxv16i16 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %nxv16i64_nxv16i16 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %nxv16i64_nxv16i32 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv16i8_nxv16i1 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv16i16_nxv16i1 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv16i32_nxv16i1 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %nxv16i64_nxv16i1 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv32i16_nxv32i8 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %nxv32i32_nxv32i8 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 15 for instruction: %nxv32i64_nxv32i8 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %nxv32i32_nxv32i16 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 11 for instruction: %nxv32i64_nxv32i16 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %nxv32i64_nxv32i32 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv32i8_nxv32i1 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv32i16_nxv32i1 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %nxv32i32_nxv32i1 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 11 for instruction: %nxv32i64_nxv32i1 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %nxv64i16_nxv64i8 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 11 for instruction: %nxv64i32_nxv64i8 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %nxv8i16_nxv8i1 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %nxv8i32_nxv8i1 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 16 for instruction: %nxv8i64_nxv8i1 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv16i16_nxv16i8 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %nxv16i32_nxv16i8 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 15 for instruction: %nxv16i64_nxv16i8 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %nxv16i32_nxv16i16 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 13 for instruction: %nxv16i64_nxv16i16 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 9 for instruction: %nxv16i64_nxv16i32 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %nxv16i8_nxv16i1 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %nxv16i16_nxv16i1 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 16 for instruction: %nxv16i32_nxv16i1 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 33 for instruction: %nxv16i64_nxv16i1 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %nxv32i16_nxv32i8 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 13 for instruction: %nxv32i32_nxv32i8 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 31 for instruction: %nxv32i64_nxv32i8 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 9 for instruction: %nxv32i32_nxv32i16 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 27 for instruction: %nxv32i64_nxv32i16 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 18 for instruction: %nxv32i64_nxv32i32 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %nxv32i8_nxv32i1 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 16 for instruction: %nxv32i16_nxv32i1 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 33 for instruction: %nxv32i32_nxv32i1 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 67 for instruction: %nxv32i64_nxv32i1 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 9 for instruction: %nxv64i16_nxv64i8 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 27 for instruction: %nxv64i32_nxv64i8 = trunc undef to ; RV32-NEXT: Cost Model: Invalid cost for instruction: %nxv64i64_nxv64i8 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %nxv64i32_nxv64i16 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 23 for instruction: %nxv64i64_nxv64i16 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 13 for instruction: %nxv64i64_nxv64i32 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv64i8_nxv64i1 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %nxv64i16_nxv64i1 = trunc undef to -; RV32-NEXT: Cost Model: Found an estimated cost of 11 for instruction: %nxv64i32_nxv64i1 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 18 for instruction: %nxv64i32_nxv64i16 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 55 for instruction: %nxv64i64_nxv64i16 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 37 for instruction: %nxv64i64_nxv64i32 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 16 for instruction: %nxv64i8_nxv64i1 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 33 for instruction: %nxv64i16_nxv64i1 = trunc undef to +; RV32-NEXT: Cost Model: Found an estimated cost of 67 for instruction: %nxv64i32_nxv64i1 = trunc undef to ; RV32-NEXT: Cost Model: Invalid cost for instruction: %nxv64i64_nxv64i1 = trunc undef to ; RV32-NEXT: Cost Model: Found an estimated cost of 0 for instruction: ret void ; @@ -1188,17 +1188,17 @@ define void @trunc() { ; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v4i8_v4i1 = trunc <4 x i8> undef to <4 x i1> ; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v4i16_v4i1 = trunc <4 x i16> undef to <4 x i1> ; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v4i32_v4i1 = trunc <4 x i32> undef to <4 x i1> -; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v4i64_v4i1 = trunc <4 x i64> undef to <4 x i1> +; RV64-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %v4i64_v4i1 = trunc <4 x i64> undef to <4 x i1> ; RV64-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v8i16_v8i8 = trunc <8 x i16> undef to <8 x i8> ; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v8i32_v8i8 = trunc <8 x i32> undef to <8 x i8> -; RV64-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %v8i64_v8i8 = trunc <8 x i64> undef to <8 x i8> +; RV64-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %v8i64_v8i8 = trunc <8 x i64> undef to <8 x i8> ; RV64-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v8i32_v8i16 = trunc <8 x i32> undef to <8 x i16> -; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v8i64_v8i16 = trunc <8 x i64> undef to <8 x i16> -; RV64-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v8i64_v8i32 = trunc <8 x i64> undef to <8 x i32> +; RV64-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %v8i64_v8i16 = trunc <8 x i64> undef to <8 x i16> +; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v8i64_v8i32 = trunc <8 x i64> undef to <8 x i32> ; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v8i8_v8i1 = trunc <8 x i8> undef to <8 x i1> ; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v8i16_v8i1 = trunc <8 x i16> undef to <8 x i1> -; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v8i32_v8i1 = trunc <8 x i32> undef to <8 x i1> -; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v8i64_v8i1 = trunc <8 x i64> undef to <8 x i1> +; RV64-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %v8i32_v8i1 = trunc <8 x i32> undef to <8 x i1> +; RV64-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %v8i64_v8i1 = trunc <8 x i64> undef to <8 x i1> ; RV64-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v16i16_v16i8 = trunc <2 x i16> undef to <2 x i8> ; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v16i32_v16i8 = trunc <2 x i32> undef to <2 x i8> ; RV64-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %v16i64_v16i8 = trunc <2 x i64> undef to <2 x i8> @@ -1210,43 +1210,43 @@ define void @trunc() { ; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v16i32_v16i1 = trunc <2 x i32> undef to <2 x i1> ; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v16i64_v16i1 = trunc <2 x i64> undef to <2 x i1> ; RV64-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v32i16_v32i8 = trunc <16 x i16> undef to <16 x i8> -; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v32i32_v32i8 = trunc <16 x i32> undef to <16 x i8> -; RV64-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %v32i64_v32i8 = trunc <16 x i64> undef to <16 x i8> -; RV64-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v32i32_v32i16 = trunc <16 x i32> undef to <16 x i16> -; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v32i64_v32i16 = trunc <16 x i64> undef to <16 x i16> -; RV64-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v32i64_v32i32 = trunc <16 x i64> undef to <16 x i32> +; RV64-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %v32i32_v32i8 = trunc <16 x i32> undef to <16 x i8> +; RV64-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %v32i64_v32i8 = trunc <16 x i64> undef to <16 x i8> +; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v32i32_v32i16 = trunc <16 x i32> undef to <16 x i16> +; RV64-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %v32i64_v32i16 = trunc <16 x i64> undef to <16 x i16> +; RV64-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %v32i64_v32i32 = trunc <16 x i64> undef to <16 x i32> ; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v32i8_v32i1 = trunc <16 x i8> undef to <16 x i1> -; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v32i16_v32i1 = trunc <16 x i16> undef to <16 x i1> -; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v32i32_v32i1 = trunc <16 x i32> undef to <16 x i1> -; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v32i64_v32i1 = trunc <16 x i64> undef to <16 x i1> -; RV64-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v64i16_v64i8 = trunc <64 x i16> undef to <64 x i8> -; RV64-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %v64i32_v64i8 = trunc <64 x i32> undef to <64 x i8> -; RV64-NEXT: Cost Model: Found an estimated cost of 15 for instruction: %v64i64_v64i8 = trunc <64 x i64> undef to <64 x i8> -; RV64-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %v64i32_v64i16 = trunc <64 x i32> undef to <64 x i16> -; RV64-NEXT: Cost Model: Found an estimated cost of 11 for instruction: %v64i64_v64i16 = trunc <64 x i64> undef to <64 x i16> -; RV64-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %v64i64_v64i32 = trunc <64 x i64> undef to <64 x i32> -; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v64i8_v64i1 = trunc <64 x i8> undef to <64 x i1> -; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v64i16_v64i1 = trunc <64 x i16> undef to <64 x i1> +; RV64-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %v32i16_v32i1 = trunc <16 x i16> undef to <16 x i1> +; RV64-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %v32i32_v32i1 = trunc <16 x i32> undef to <16 x i1> +; RV64-NEXT: Cost Model: Found an estimated cost of 16 for instruction: %v32i64_v32i1 = trunc <16 x i64> undef to <16 x i1> +; RV64-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %v64i16_v64i8 = trunc <64 x i16> undef to <64 x i8> +; RV64-NEXT: Cost Model: Found an estimated cost of 13 for instruction: %v64i32_v64i8 = trunc <64 x i32> undef to <64 x i8> +; RV64-NEXT: Cost Model: Found an estimated cost of 31 for instruction: %v64i64_v64i8 = trunc <64 x i64> undef to <64 x i8> +; RV64-NEXT: Cost Model: Found an estimated cost of 9 for instruction: %v64i32_v64i16 = trunc <64 x i32> undef to <64 x i16> +; RV64-NEXT: Cost Model: Found an estimated cost of 27 for instruction: %v64i64_v64i16 = trunc <64 x i64> undef to <64 x i16> +; RV64-NEXT: Cost Model: Found an estimated cost of 18 for instruction: %v64i64_v64i32 = trunc <64 x i64> undef to <64 x i32> +; RV64-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %v64i8_v64i1 = trunc <64 x i8> undef to <64 x i1> +; RV64-NEXT: Cost Model: Found an estimated cost of 16 for instruction: %v64i16_v64i1 = trunc <64 x i16> undef to <64 x i1> ; RV64-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %v64i32_v64i1 = trunc <64 x i32> undef to <64 x i1> ; RV64-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %v64i64_v64i1 = trunc <64 x i64> undef to <64 x i1> -; RV64-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %v128i16_v128i8 = trunc <128 x i16> undef to <128 x i8> -; RV64-NEXT: Cost Model: Found an estimated cost of 11 for instruction: %v128i32_v128i8 = trunc <128 x i32> undef to <128 x i8> -; RV64-NEXT: Cost Model: Found an estimated cost of 31 for instruction: %v128i64_v128i8 = trunc <128 x i64> undef to <128 x i8> -; RV64-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %v128i32_v128i16 = trunc <128 x i32> undef to <128 x i16> -; RV64-NEXT: Cost Model: Found an estimated cost of 22 for instruction: %v128i64_v128i16 = trunc <128 x i64> undef to <128 x i16> -; RV64-NEXT: Cost Model: Found an estimated cost of 12 for instruction: %v128i64_v128i32 = trunc <128 x i64> undef to <128 x i32> -; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v128i8_v128i1 = trunc <128 x i8> undef to <128 x i1> -; RV64-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %v128i16_v128i1 = trunc <128 x i16> undef to <128 x i1> +; RV64-NEXT: Cost Model: Found an estimated cost of 9 for instruction: %v128i16_v128i8 = trunc <128 x i16> undef to <128 x i8> +; RV64-NEXT: Cost Model: Found an estimated cost of 27 for instruction: %v128i32_v128i8 = trunc <128 x i32> undef to <128 x i8> +; RV64-NEXT: Cost Model: Found an estimated cost of 63 for instruction: %v128i64_v128i8 = trunc <128 x i64> undef to <128 x i8> +; RV64-NEXT: Cost Model: Found an estimated cost of 18 for instruction: %v128i32_v128i16 = trunc <128 x i32> undef to <128 x i16> +; RV64-NEXT: Cost Model: Found an estimated cost of 54 for instruction: %v128i64_v128i16 = trunc <128 x i64> undef to <128 x i16> +; RV64-NEXT: Cost Model: Found an estimated cost of 36 for instruction: %v128i64_v128i32 = trunc <128 x i64> undef to <128 x i32> +; RV64-NEXT: Cost Model: Found an estimated cost of 16 for instruction: %v128i8_v128i1 = trunc <128 x i8> undef to <128 x i1> +; RV64-NEXT: Cost Model: Found an estimated cost of 33 for instruction: %v128i16_v128i1 = trunc <128 x i16> undef to <128 x i1> ; RV64-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v128i32_v128i1 = trunc <128 x i32> undef to <128 x i1> ; RV64-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v128i64_v128i1 = trunc <128 x i64> undef to <128 x i1> -; RV64-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %v256i16_v256i8 = trunc <256 x i16> undef to <256 x i8> -; RV64-NEXT: Cost Model: Found an estimated cost of 22 for instruction: %v256i32_v256i8 = trunc <256 x i32> undef to <256 x i8> -; RV64-NEXT: Cost Model: Found an estimated cost of 62 for instruction: %v256i64_v256i8 = trunc <256 x i64> undef to <256 x i8> -; RV64-NEXT: Cost Model: Found an estimated cost of 12 for instruction: %v256i32_v256i16 = trunc <256 x i32> undef to <256 x i16> -; RV64-NEXT: Cost Model: Found an estimated cost of 44 for instruction: %v256i64_v256i16 = trunc <256 x i64> undef to <256 x i16> -; RV64-NEXT: Cost Model: Found an estimated cost of 24 for instruction: %v256i64_v256i32 = trunc <256 x i64> undef to <256 x i32> -; RV64-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %v256i8_v256i1 = trunc <256 x i8> undef to <256 x i1> -; RV64-NEXT: Cost Model: Found an estimated cost of 10 for instruction: %v256i16_v256i1 = trunc <256 x i16> undef to <256 x i1> +; RV64-NEXT: Cost Model: Found an estimated cost of 18 for instruction: %v256i16_v256i8 = trunc <256 x i16> undef to <256 x i8> +; RV64-NEXT: Cost Model: Found an estimated cost of 54 for instruction: %v256i32_v256i8 = trunc <256 x i32> undef to <256 x i8> +; RV64-NEXT: Cost Model: Found an estimated cost of 126 for instruction: %v256i64_v256i8 = trunc <256 x i64> undef to <256 x i8> +; RV64-NEXT: Cost Model: Found an estimated cost of 36 for instruction: %v256i32_v256i16 = trunc <256 x i32> undef to <256 x i16> +; RV64-NEXT: Cost Model: Found an estimated cost of 108 for instruction: %v256i64_v256i16 = trunc <256 x i64> undef to <256 x i16> +; RV64-NEXT: Cost Model: Found an estimated cost of 72 for instruction: %v256i64_v256i32 = trunc <256 x i64> undef to <256 x i32> +; RV64-NEXT: Cost Model: Found an estimated cost of 32 for instruction: %v256i8_v256i1 = trunc <256 x i8> undef to <256 x i1> +; RV64-NEXT: Cost Model: Found an estimated cost of 66 for instruction: %v256i16_v256i1 = trunc <256 x i16> undef to <256 x i1> ; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v256i32_v256i1 = trunc <256 x i32> undef to <256 x i1> ; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v256i64_v256i1 = trunc <256 x i64> undef to <256 x i1> ; RV64-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv1i16_nxv1i8 = trunc undef to @@ -1268,57 +1268,57 @@ define void @trunc() { ; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv2i8_nxv2i1 = trunc undef to ; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv2i16_nxv2i1 = trunc undef to ; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv2i32_nxv2i1 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv2i64_nxv2i1 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %nxv2i64_nxv2i1 = trunc undef to ; RV64-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv4i16_nxv4i8 = trunc undef to ; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv4i32_nxv4i8 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %nxv4i64_nxv4i8 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %nxv4i64_nxv4i8 = trunc undef to ; RV64-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv4i32_nxv4i16 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv4i64_nxv4i16 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv4i64_nxv4i32 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %nxv4i64_nxv4i16 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv4i64_nxv4i32 = trunc undef to ; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv4i8_nxv4i1 = trunc undef to ; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv4i16_nxv4i1 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv4i32_nxv4i1 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv4i64_nxv4i1 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %nxv4i32_nxv4i1 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %nxv4i64_nxv4i1 = trunc undef to ; RV64-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv8i16_nxv8i8 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv8i32_nxv8i8 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %nxv8i64_nxv8i8 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv8i32_nxv8i16 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv8i64_nxv8i16 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv8i64_nxv8i32 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %nxv8i32_nxv8i8 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %nxv8i64_nxv8i8 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv8i32_nxv8i16 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %nxv8i64_nxv8i16 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %nxv8i64_nxv8i32 = trunc undef to ; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv8i8_nxv8i1 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv8i16_nxv8i1 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv8i32_nxv8i1 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv8i64_nxv8i1 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv16i16_nxv16i8 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv16i32_nxv16i8 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %nxv16i64_nxv16i8 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv16i32_nxv16i16 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %nxv16i64_nxv16i16 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %nxv16i64_nxv16i32 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv16i8_nxv16i1 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv16i16_nxv16i1 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv16i32_nxv16i1 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %nxv16i64_nxv16i1 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv32i16_nxv32i8 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %nxv32i32_nxv32i8 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 15 for instruction: %nxv32i64_nxv32i8 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %nxv32i32_nxv32i16 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 11 for instruction: %nxv32i64_nxv32i16 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %nxv32i64_nxv32i32 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv32i8_nxv32i1 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv32i16_nxv32i1 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %nxv32i32_nxv32i1 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 11 for instruction: %nxv32i64_nxv32i1 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %nxv64i16_nxv64i8 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 11 for instruction: %nxv64i32_nxv64i8 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 31 for instruction: %nxv64i64_nxv64i8 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %nxv64i32_nxv64i16 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 22 for instruction: %nxv64i64_nxv64i16 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 12 for instruction: %nxv64i64_nxv64i32 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv64i8_nxv64i1 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %nxv64i16_nxv64i1 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 11 for instruction: %nxv64i32_nxv64i1 = trunc undef to -; RV64-NEXT: Cost Model: Found an estimated cost of 23 for instruction: %nxv64i64_nxv64i1 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %nxv8i16_nxv8i1 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %nxv8i32_nxv8i1 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 16 for instruction: %nxv8i64_nxv8i1 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv16i16_nxv16i8 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %nxv16i32_nxv16i8 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 15 for instruction: %nxv16i64_nxv16i8 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %nxv16i32_nxv16i16 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 13 for instruction: %nxv16i64_nxv16i16 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 9 for instruction: %nxv16i64_nxv16i32 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %nxv16i8_nxv16i1 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %nxv16i16_nxv16i1 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 16 for instruction: %nxv16i32_nxv16i1 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 33 for instruction: %nxv16i64_nxv16i1 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %nxv32i16_nxv32i8 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 13 for instruction: %nxv32i32_nxv32i8 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 31 for instruction: %nxv32i64_nxv32i8 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 9 for instruction: %nxv32i32_nxv32i16 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 27 for instruction: %nxv32i64_nxv32i16 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 18 for instruction: %nxv32i64_nxv32i32 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %nxv32i8_nxv32i1 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 16 for instruction: %nxv32i16_nxv32i1 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 33 for instruction: %nxv32i32_nxv32i1 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 67 for instruction: %nxv32i64_nxv32i1 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 9 for instruction: %nxv64i16_nxv64i8 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 27 for instruction: %nxv64i32_nxv64i8 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 63 for instruction: %nxv64i64_nxv64i8 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 18 for instruction: %nxv64i32_nxv64i16 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 54 for instruction: %nxv64i64_nxv64i16 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 36 for instruction: %nxv64i64_nxv64i32 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 16 for instruction: %nxv64i8_nxv64i1 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 33 for instruction: %nxv64i16_nxv64i1 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 67 for instruction: %nxv64i32_nxv64i1 = trunc undef to +; RV64-NEXT: Cost Model: Found an estimated cost of 135 for instruction: %nxv64i64_nxv64i1 = trunc undef to ; RV64-NEXT: Cost Model: Found an estimated cost of 0 for instruction: ret void ; %v2i16_v2i8 = trunc <2 x i16> undef to <2 x i8> @@ -1495,44 +1495,44 @@ define void @fpext() { ; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v2f16_v2f64 = fpext <2 x half> undef to <2 x double> ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v2f32_v2f64 = fpext <2 x float> undef to <2 x double> ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v4f16_v4f32 = fpext <4 x half> undef to <4 x float> -; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v4f16_v4f64 = fpext <4 x half> undef to <4 x double> -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v4f32_v4f64 = fpext <4 x float> undef to <4 x double> -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v8f16_v8f32 = fpext <8 x half> undef to <8 x float> -; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v8f16_v8f64 = fpext <8 x half> undef to <8 x double> -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v8f32_v8f64 = fpext <8 x float> undef to <8 x double> -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v16f16_v16f32 = fpext <16 x half> undef to <16 x float> -; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v16f16_v16f64 = fpext <16 x half> undef to <16 x double> -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v16f32_v16f64 = fpext <16 x float> undef to <16 x double> -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v32f16_v32f32 = fpext <32 x half> undef to <32 x float> -; CHECK-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %v32f16_v32f64 = fpext <32 x half> undef to <32 x double> -; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %v32f32_v32f64 = fpext <32 x float> undef to <32 x double> -; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %v64f16_v64f32 = fpext <64 x half> undef to <64 x float> -; CHECK-NEXT: Cost Model: Found an estimated cost of 11 for instruction: %v64f16_v64f64 = fpext <64 x half> undef to <64 x double> -; CHECK-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %v64f32_v64f64 = fpext <64 x float> undef to <64 x double> -; CHECK-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %v128f16_v128f32 = fpext <128 x half> undef to <128 x float> -; CHECK-NEXT: Cost Model: Found an estimated cost of 22 for instruction: %v128f16_v128f64 = fpext <128 x half> undef to <128 x double> -; CHECK-NEXT: Cost Model: Found an estimated cost of 12 for instruction: %v128f32_v128f64 = fpext <128 x float> undef to <128 x double> +; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %v4f16_v4f64 = fpext <4 x half> undef to <4 x double> +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v4f32_v4f64 = fpext <4 x float> undef to <4 x double> +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v8f16_v8f32 = fpext <8 x half> undef to <8 x float> +; CHECK-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %v8f16_v8f64 = fpext <8 x half> undef to <8 x double> +; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %v8f32_v8f64 = fpext <8 x float> undef to <8 x double> +; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %v16f16_v16f32 = fpext <16 x half> undef to <16 x float> +; CHECK-NEXT: Cost Model: Found an estimated cost of 12 for instruction: %v16f16_v16f64 = fpext <16 x half> undef to <16 x double> +; CHECK-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %v16f32_v16f64 = fpext <16 x float> undef to <16 x double> +; CHECK-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %v32f16_v32f32 = fpext <32 x half> undef to <32 x float> +; CHECK-NEXT: Cost Model: Found an estimated cost of 25 for instruction: %v32f16_v32f64 = fpext <32 x half> undef to <32 x double> +; CHECK-NEXT: Cost Model: Found an estimated cost of 17 for instruction: %v32f32_v32f64 = fpext <32 x float> undef to <32 x double> +; CHECK-NEXT: Cost Model: Found an estimated cost of 17 for instruction: %v64f16_v64f32 = fpext <64 x half> undef to <64 x float> +; CHECK-NEXT: Cost Model: Found an estimated cost of 51 for instruction: %v64f16_v64f64 = fpext <64 x half> undef to <64 x double> +; CHECK-NEXT: Cost Model: Found an estimated cost of 34 for instruction: %v64f32_v64f64 = fpext <64 x float> undef to <64 x double> +; CHECK-NEXT: Cost Model: Found an estimated cost of 34 for instruction: %v128f16_v128f32 = fpext <128 x half> undef to <128 x float> +; CHECK-NEXT: Cost Model: Found an estimated cost of 102 for instruction: %v128f16_v128f64 = fpext <128 x half> undef to <128 x double> +; CHECK-NEXT: Cost Model: Found an estimated cost of 68 for instruction: %v128f32_v128f64 = fpext <128 x float> undef to <128 x double> ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv1f16_nxv1f32 = fpext undef to ; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv1f16_nxv1f64 = fpext undef to ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv1f32_nxv1f64 = fpext undef to ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv2f16_nxv2f32 = fpext undef to -; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv2f16_nxv2f64 = fpext undef to -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv2f32_nxv2f64 = fpext undef to -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv4f16_nxv4f32 = fpext undef to -; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv4f16_nxv4f64 = fpext undef to -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv4f32_nxv4f64 = fpext undef to -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv8f16_nxv8f32 = fpext undef to -; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv8f16_nxv8f64 = fpext undef to -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv8f32_nxv8f64 = fpext undef to -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv16f16_nxv16f32 = fpext undef to -; CHECK-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %nxv16f16_nxv16f64 = fpext undef to -; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %nxv16f32_nxv16f64 = fpext undef to -; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %nxv32f16_nxv32f32 = fpext undef to -; CHECK-NEXT: Cost Model: Found an estimated cost of 11 for instruction: %nxv32f16_nxv32f64 = fpext undef to -; CHECK-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %nxv32f32_nxv32f64 = fpext undef to -; CHECK-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %nxv64f16_nxv64f32 = fpext undef to -; CHECK-NEXT: Cost Model: Found an estimated cost of 22 for instruction: %nxv64f16_nxv64f64 = fpext undef to -; CHECK-NEXT: Cost Model: Found an estimated cost of 12 for instruction: %nxv64f32_nxv64f64 = fpext undef to +; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %nxv2f16_nxv2f64 = fpext undef to +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv2f32_nxv2f64 = fpext undef to +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv4f16_nxv4f32 = fpext undef to +; CHECK-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %nxv4f16_nxv4f64 = fpext undef to +; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %nxv4f32_nxv4f64 = fpext undef to +; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %nxv8f16_nxv8f32 = fpext undef to +; CHECK-NEXT: Cost Model: Found an estimated cost of 12 for instruction: %nxv8f16_nxv8f64 = fpext undef to +; CHECK-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %nxv8f32_nxv8f64 = fpext undef to +; CHECK-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %nxv16f16_nxv16f32 = fpext undef to +; CHECK-NEXT: Cost Model: Found an estimated cost of 25 for instruction: %nxv16f16_nxv16f64 = fpext undef to +; CHECK-NEXT: Cost Model: Found an estimated cost of 17 for instruction: %nxv16f32_nxv16f64 = fpext undef to +; CHECK-NEXT: Cost Model: Found an estimated cost of 17 for instruction: %nxv32f16_nxv32f32 = fpext undef to +; CHECK-NEXT: Cost Model: Found an estimated cost of 51 for instruction: %nxv32f16_nxv32f64 = fpext undef to +; CHECK-NEXT: Cost Model: Found an estimated cost of 34 for instruction: %nxv32f32_nxv32f64 = fpext undef to +; CHECK-NEXT: Cost Model: Found an estimated cost of 34 for instruction: %nxv64f16_nxv64f32 = fpext undef to +; CHECK-NEXT: Cost Model: Found an estimated cost of 102 for instruction: %nxv64f16_nxv64f64 = fpext undef to +; CHECK-NEXT: Cost Model: Found an estimated cost of 68 for instruction: %nxv64f32_nxv64f64 = fpext undef to ; CHECK-NEXT: Cost Model: Found an estimated cost of 0 for instruction: ret void ; %v2f16_v2f32 = fpext <2 x half> undef to <2 x float> @@ -1603,20 +1603,20 @@ define void @fptrunc() { ; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v4f64_v4f16 = fptrunc <4 x double> undef to <4 x half> ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v4f64_v4f32 = fptrunc <4 x double> undef to <4 x float> ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v8f32_v8f16 = fptrunc <8 x float> undef to <8 x half> -; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v8f64_v8f16 = fptrunc <8 x double> undef to <8 x half> -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v8f64_v8f32 = fptrunc <8 x double> undef to <8 x float> -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v16f32_v16f16 = fptrunc <16 x float> undef to <16 x half> -; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v16f64_v16f16 = fptrunc <16 x double> undef to <16 x half> -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v16f64_v16f32 = fptrunc <16 x double> undef to <16 x float> -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v32f32_v32f16 = fptrunc <32 x float> undef to <32 x half> -; CHECK-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %v32f64_v32f16 = fptrunc <32 x double> undef to <32 x half> -; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %v32f64_v32f32 = fptrunc <32 x double> undef to <32 x float> -; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %v64f32_v64f16 = fptrunc <64 x float> undef to <64 x half> -; CHECK-NEXT: Cost Model: Found an estimated cost of 11 for instruction: %v64f64_v64f16 = fptrunc <64 x double> undef to <64 x half> -; CHECK-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %v64f64_v64f32 = fptrunc <64 x double> undef to <64 x float> -; CHECK-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %v128f32_v128f16 = fptrunc <128 x float> undef to <128 x half> -; CHECK-NEXT: Cost Model: Found an estimated cost of 22 for instruction: %v128f64_v128f16 = fptrunc <128 x double> undef to <128 x half> -; CHECK-NEXT: Cost Model: Found an estimated cost of 12 for instruction: %v128f64_v128f32 = fptrunc <128 x double> undef to <128 x float> +; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %v8f64_v8f16 = fptrunc <8 x double> undef to <8 x half> +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v8f64_v8f32 = fptrunc <8 x double> undef to <8 x float> +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v16f32_v16f16 = fptrunc <16 x float> undef to <16 x half> +; CHECK-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %v16f64_v16f16 = fptrunc <16 x double> undef to <16 x half> +; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %v16f64_v16f32 = fptrunc <16 x double> undef to <16 x float> +; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %v32f32_v32f16 = fptrunc <32 x float> undef to <32 x half> +; CHECK-NEXT: Cost Model: Found an estimated cost of 13 for instruction: %v32f64_v32f16 = fptrunc <32 x double> undef to <32 x half> +; CHECK-NEXT: Cost Model: Found an estimated cost of 9 for instruction: %v32f64_v32f32 = fptrunc <32 x double> undef to <32 x float> +; CHECK-NEXT: Cost Model: Found an estimated cost of 9 for instruction: %v64f32_v64f16 = fptrunc <64 x float> undef to <64 x half> +; CHECK-NEXT: Cost Model: Found an estimated cost of 27 for instruction: %v64f64_v64f16 = fptrunc <64 x double> undef to <64 x half> +; CHECK-NEXT: Cost Model: Found an estimated cost of 18 for instruction: %v64f64_v64f32 = fptrunc <64 x double> undef to <64 x float> +; CHECK-NEXT: Cost Model: Found an estimated cost of 18 for instruction: %v128f32_v128f16 = fptrunc <128 x float> undef to <128 x half> +; CHECK-NEXT: Cost Model: Found an estimated cost of 54 for instruction: %v128f64_v128f16 = fptrunc <128 x double> undef to <128 x half> +; CHECK-NEXT: Cost Model: Found an estimated cost of 36 for instruction: %v128f64_v128f32 = fptrunc <128 x double> undef to <128 x float> ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv1f32_nxv1f16 = fptrunc undef to ; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv1f64_nxv1f16 = fptrunc undef to ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv1f64_nxv1f32 = fptrunc undef to @@ -1624,20 +1624,20 @@ define void @fptrunc() { ; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv2f64_nxv1f16 = fptrunc undef to ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv2f64_nxv1f32 = fptrunc undef to ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv4f32_nxv4f16 = fptrunc undef to -; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv4f64_nxv4f16 = fptrunc undef to -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv4f64_nxv4f32 = fptrunc undef to -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv8f32_nxv8f16 = fptrunc undef to -; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv8f64_nxv8f16 = fptrunc undef to -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv8f64_nxv8f32 = fptrunc undef to -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %nxv16f32_nxv16f16 = fptrunc undef to -; CHECK-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %nxv16f64_nxv16f16 = fptrunc undef to -; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %nxv16f64_nxv16f32 = fptrunc undef to -; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %nxv32f32_nxv32f16 = fptrunc undef to -; CHECK-NEXT: Cost Model: Found an estimated cost of 11 for instruction: %nxv32f64_nxv32f16 = fptrunc undef to -; CHECK-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %nxv32f64_nxv32f32 = fptrunc undef to -; CHECK-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %nxv64f32_nxv64f16 = fptrunc undef to -; CHECK-NEXT: Cost Model: Found an estimated cost of 22 for instruction: %nxv64f64_nxv64f16 = fptrunc undef to -; CHECK-NEXT: Cost Model: Found an estimated cost of 12 for instruction: %nxv64f64_nxv64f32 = fptrunc undef to +; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %nxv4f64_nxv4f16 = fptrunc undef to +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv4f64_nxv4f32 = fptrunc undef to +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %nxv8f32_nxv8f16 = fptrunc undef to +; CHECK-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %nxv8f64_nxv8f16 = fptrunc undef to +; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %nxv8f64_nxv8f32 = fptrunc undef to +; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %nxv16f32_nxv16f16 = fptrunc undef to +; CHECK-NEXT: Cost Model: Found an estimated cost of 13 for instruction: %nxv16f64_nxv16f16 = fptrunc undef to +; CHECK-NEXT: Cost Model: Found an estimated cost of 9 for instruction: %nxv16f64_nxv16f32 = fptrunc undef to +; CHECK-NEXT: Cost Model: Found an estimated cost of 9 for instruction: %nxv32f32_nxv32f16 = fptrunc undef to +; CHECK-NEXT: Cost Model: Found an estimated cost of 27 for instruction: %nxv32f64_nxv32f16 = fptrunc undef to +; CHECK-NEXT: Cost Model: Found an estimated cost of 18 for instruction: %nxv32f64_nxv32f32 = fptrunc undef to +; CHECK-NEXT: Cost Model: Found an estimated cost of 18 for instruction: %nxv64f32_nxv64f16 = fptrunc undef to +; CHECK-NEXT: Cost Model: Found an estimated cost of 54 for instruction: %nxv64f64_nxv64f16 = fptrunc undef to +; CHECK-NEXT: Cost Model: Found an estimated cost of 36 for instruction: %nxv64f64_nxv64f32 = fptrunc undef to ; CHECK-NEXT: Cost Model: Found an estimated cost of 0 for instruction: ret void ; %v2f32_v2f16 = fptrunc <2 x float> undef to <2 x half> diff --git a/llvm/test/Analysis/CostModel/RISCV/reduce-scalable-fp.ll b/llvm/test/Analysis/CostModel/RISCV/reduce-scalable-fp.ll index e42dc889f1ba..a9a5f4d2de54 100644 --- a/llvm/test/Analysis/CostModel/RISCV/reduce-scalable-fp.ll +++ b/llvm/test/Analysis/CostModel/RISCV/reduce-scalable-fp.ll @@ -238,7 +238,7 @@ define float @vreduce_ord_fadd_nxv4f32( %v, float %s) { define float @vreduce_fwadd_nxv4f32( %v, float %s) { ; CHECK-LABEL: 'vreduce_fwadd_nxv4f32' -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %e = fpext %v to +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %e = fpext %v to ; CHECK-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %red = call reassoc float @llvm.vector.reduce.fadd.nxv4f32(float %s, %e) ; CHECK-NEXT: Cost Model: Found an estimated cost of 0 for instruction: ret float %red ; @@ -254,7 +254,7 @@ define float @vreduce_fwadd_nxv4f32( %v, float %s) { define float @vreduce_ord_fwadd_nxv4f32( %v, float %s) { ; CHECK-LABEL: 'vreduce_ord_fwadd_nxv4f32' -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %e = fpext %v to +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %e = fpext %v to ; CHECK-NEXT: Cost Model: Found an estimated cost of 10 for instruction: %red = call float @llvm.vector.reduce.fadd.nxv4f32(float %s, %e) ; CHECK-NEXT: Cost Model: Found an estimated cost of 0 for instruction: ret float %red ; @@ -358,7 +358,7 @@ define double @vreduce_ord_fadd_nxv2f64( %v, double %s) { define double @vreduce_fwadd_nxv2f64( %v, double %s) { ; CHECK-LABEL: 'vreduce_fwadd_nxv2f64' -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %e = fpext %v to +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %e = fpext %v to ; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %red = call reassoc double @llvm.vector.reduce.fadd.nxv2f64(double %s, %e) ; CHECK-NEXT: Cost Model: Found an estimated cost of 0 for instruction: ret double %red ; @@ -374,7 +374,7 @@ define double @vreduce_fwadd_nxv2f64( %v, double %s) { define double @vreduce_ord_fwadd_nxv2f64( %v, double %s) { ; CHECK-LABEL: 'vreduce_ord_fwadd_nxv2f64' -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %e = fpext %v to +; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %e = fpext %v to ; CHECK-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %red = call double @llvm.vector.reduce.fadd.nxv2f64(double %s, %e) ; CHECK-NEXT: Cost Model: Found an estimated cost of 0 for instruction: ret double %red ; @@ -418,7 +418,7 @@ define double @vreduce_ord_fadd_nxv4f64( %v, double %s) { define double @vreduce_fwadd_nxv4f64( %v, double %s) { ; CHECK-LABEL: 'vreduce_fwadd_nxv4f64' -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %e = fpext %v to +; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %e = fpext %v to ; CHECK-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %red = call reassoc double @llvm.vector.reduce.fadd.nxv4f64(double %s, %e) ; CHECK-NEXT: Cost Model: Found an estimated cost of 0 for instruction: ret double %red ; @@ -434,7 +434,7 @@ define double @vreduce_fwadd_nxv4f64( %v, double %s) { define double @vreduce_ord_fwadd_nxv4f64( %v, double %s) { ; CHECK-LABEL: 'vreduce_ord_fwadd_nxv4f64' -; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %e = fpext %v to +; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %e = fpext %v to ; CHECK-NEXT: Cost Model: Found an estimated cost of 10 for instruction: %red = call double @llvm.vector.reduce.fadd.nxv4f64(double %s, %e) ; CHECK-NEXT: Cost Model: Found an estimated cost of 0 for instruction: ret double %red ; diff --git a/llvm/test/Analysis/CostModel/RISCV/rvv-insertelement.ll b/llvm/test/Analysis/CostModel/RISCV/rvv-insertelement.ll index 6e1ae0216f76..8b68480788f7 100644 --- a/llvm/test/Analysis/CostModel/RISCV/rvv-insertelement.ll +++ b/llvm/test/Analysis/CostModel/RISCV/rvv-insertelement.ll @@ -12,12 +12,12 @@ define void @insertelement_int(i32 %x) { ; RV32V-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %v4i1_0 = insertelement <4 x i1> undef, i1 undef, i32 0 ; RV32V-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %v8i1_0 = insertelement <8 x i1> undef, i1 undef, i32 0 ; RV32V-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %v16i1_0 = insertelement <16 x i1> undef, i1 undef, i32 0 -; RV32V-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %v32i1_0 = insertelement <32 x i1> undef, i1 undef, i32 0 +; RV32V-NEXT: Cost Model: Found an estimated cost of 9 for instruction: %v32i1_0 = insertelement <32 x i1> undef, i1 undef, i32 0 ; RV32V-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %nxv2i1_0 = insertelement undef, i1 undef, i32 0 ; RV32V-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %nxv4i1_0 = insertelement undef, i1 undef, i32 0 ; RV32V-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %nxv8i1_0 = insertelement undef, i1 undef, i32 0 -; RV32V-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %nxv16i1_0 = insertelement undef, i1 undef, i32 0 -; RV32V-NEXT: Cost Model: Found an estimated cost of 11 for instruction: %nxv32i1_0 = insertelement undef, i1 undef, i32 0 +; RV32V-NEXT: Cost Model: Found an estimated cost of 9 for instruction: %nxv16i1_0 = insertelement undef, i1 undef, i32 0 +; RV32V-NEXT: Cost Model: Found an estimated cost of 17 for instruction: %nxv32i1_0 = insertelement undef, i1 undef, i32 0 ; RV32V-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v2i8_0 = insertelement <2 x i8> undef, i8 undef, i32 0 ; RV32V-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v4i8_0 = insertelement <4 x i8> undef, i8 undef, i32 0 ; RV32V-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v8i8_0 = insertelement <8 x i8> undef, i8 undef, i32 0 @@ -66,12 +66,12 @@ define void @insertelement_int(i32 %x) { ; RV32V-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %v4i1_1 = insertelement <4 x i1> undef, i1 undef, i32 1 ; RV32V-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %v8i1_1 = insertelement <8 x i1> undef, i1 undef, i32 1 ; RV32V-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %v16i1_1 = insertelement <16 x i1> undef, i1 undef, i32 1 -; RV32V-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %v32i1_1 = insertelement <32 x i1> undef, i1 undef, i32 1 +; RV32V-NEXT: Cost Model: Found an estimated cost of 10 for instruction: %v32i1_1 = insertelement <32 x i1> undef, i1 undef, i32 1 ; RV32V-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %nxv2i1_1 = insertelement undef, i1 undef, i32 1 ; RV32V-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %nxv4i1_1 = insertelement undef, i1 undef, i32 1 ; RV32V-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %nxv8i1_1 = insertelement undef, i1 undef, i32 1 -; RV32V-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %nxv16i1_1 = insertelement undef, i1 undef, i32 1 -; RV32V-NEXT: Cost Model: Found an estimated cost of 12 for instruction: %nxv32i1_1 = insertelement undef, i1 undef, i32 1 +; RV32V-NEXT: Cost Model: Found an estimated cost of 10 for instruction: %nxv16i1_1 = insertelement undef, i1 undef, i32 1 +; RV32V-NEXT: Cost Model: Found an estimated cost of 18 for instruction: %nxv32i1_1 = insertelement undef, i1 undef, i32 1 ; RV32V-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v2i8_1 = insertelement <2 x i8> undef, i8 undef, i32 1 ; RV32V-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v4i8_1 = insertelement <4 x i8> undef, i8 undef, i32 1 ; RV32V-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v8i8_1 = insertelement <8 x i8> undef, i8 undef, i32 1 @@ -120,12 +120,12 @@ define void @insertelement_int(i32 %x) { ; RV32V-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %v4i1_x = insertelement <4 x i1> undef, i1 undef, i32 %x ; RV32V-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %v8i1_x = insertelement <8 x i1> undef, i1 undef, i32 %x ; RV32V-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %v16i1_x = insertelement <16 x i1> undef, i1 undef, i32 %x -; RV32V-NEXT: Cost Model: Found an estimated cost of 9 for instruction: %v32i1_x = insertelement <32 x i1> undef, i1 undef, i32 %x +; RV32V-NEXT: Cost Model: Found an estimated cost of 11 for instruction: %v32i1_x = insertelement <32 x i1> undef, i1 undef, i32 %x ; RV32V-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %nxv2i1_x = insertelement undef, i1 undef, i32 %x ; RV32V-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %nxv4i1_x = insertelement undef, i1 undef, i32 %x ; RV32V-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %nxv8i1_x = insertelement undef, i1 undef, i32 %x -; RV32V-NEXT: Cost Model: Found an estimated cost of 9 for instruction: %nxv16i1_x = insertelement undef, i1 undef, i32 %x -; RV32V-NEXT: Cost Model: Found an estimated cost of 13 for instruction: %nxv32i1_x = insertelement undef, i1 undef, i32 %x +; RV32V-NEXT: Cost Model: Found an estimated cost of 11 for instruction: %nxv16i1_x = insertelement undef, i1 undef, i32 %x +; RV32V-NEXT: Cost Model: Found an estimated cost of 19 for instruction: %nxv32i1_x = insertelement undef, i1 undef, i32 %x ; RV32V-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %v2i8_x = insertelement <2 x i8> undef, i8 undef, i32 %x ; RV32V-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %v4i8_x = insertelement <4 x i8> undef, i8 undef, i32 %x ; RV32V-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %v8i8_x = insertelement <8 x i8> undef, i8 undef, i32 %x @@ -177,12 +177,12 @@ define void @insertelement_int(i32 %x) { ; RV64V-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %v4i1_0 = insertelement <4 x i1> undef, i1 undef, i32 0 ; RV64V-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %v8i1_0 = insertelement <8 x i1> undef, i1 undef, i32 0 ; RV64V-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %v16i1_0 = insertelement <16 x i1> undef, i1 undef, i32 0 -; RV64V-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %v32i1_0 = insertelement <32 x i1> undef, i1 undef, i32 0 +; RV64V-NEXT: Cost Model: Found an estimated cost of 9 for instruction: %v32i1_0 = insertelement <32 x i1> undef, i1 undef, i32 0 ; RV64V-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %nxv2i1_0 = insertelement undef, i1 undef, i32 0 ; RV64V-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %nxv4i1_0 = insertelement undef, i1 undef, i32 0 ; RV64V-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %nxv8i1_0 = insertelement undef, i1 undef, i32 0 -; RV64V-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %nxv16i1_0 = insertelement undef, i1 undef, i32 0 -; RV64V-NEXT: Cost Model: Found an estimated cost of 11 for instruction: %nxv32i1_0 = insertelement undef, i1 undef, i32 0 +; RV64V-NEXT: Cost Model: Found an estimated cost of 9 for instruction: %nxv16i1_0 = insertelement undef, i1 undef, i32 0 +; RV64V-NEXT: Cost Model: Found an estimated cost of 17 for instruction: %nxv32i1_0 = insertelement undef, i1 undef, i32 0 ; RV64V-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v2i8_0 = insertelement <2 x i8> undef, i8 undef, i32 0 ; RV64V-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v4i8_0 = insertelement <4 x i8> undef, i8 undef, i32 0 ; RV64V-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v8i8_0 = insertelement <8 x i8> undef, i8 undef, i32 0 @@ -231,12 +231,12 @@ define void @insertelement_int(i32 %x) { ; RV64V-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %v4i1_1 = insertelement <4 x i1> undef, i1 undef, i32 1 ; RV64V-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %v8i1_1 = insertelement <8 x i1> undef, i1 undef, i32 1 ; RV64V-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %v16i1_1 = insertelement <16 x i1> undef, i1 undef, i32 1 -; RV64V-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %v32i1_1 = insertelement <32 x i1> undef, i1 undef, i32 1 +; RV64V-NEXT: Cost Model: Found an estimated cost of 10 for instruction: %v32i1_1 = insertelement <32 x i1> undef, i1 undef, i32 1 ; RV64V-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %nxv2i1_1 = insertelement undef, i1 undef, i32 1 ; RV64V-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %nxv4i1_1 = insertelement undef, i1 undef, i32 1 ; RV64V-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %nxv8i1_1 = insertelement undef, i1 undef, i32 1 -; RV64V-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %nxv16i1_1 = insertelement undef, i1 undef, i32 1 -; RV64V-NEXT: Cost Model: Found an estimated cost of 12 for instruction: %nxv32i1_1 = insertelement undef, i1 undef, i32 1 +; RV64V-NEXT: Cost Model: Found an estimated cost of 10 for instruction: %nxv16i1_1 = insertelement undef, i1 undef, i32 1 +; RV64V-NEXT: Cost Model: Found an estimated cost of 18 for instruction: %nxv32i1_1 = insertelement undef, i1 undef, i32 1 ; RV64V-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v2i8_1 = insertelement <2 x i8> undef, i8 undef, i32 1 ; RV64V-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v4i8_1 = insertelement <4 x i8> undef, i8 undef, i32 1 ; RV64V-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v8i8_1 = insertelement <8 x i8> undef, i8 undef, i32 1 @@ -285,12 +285,12 @@ define void @insertelement_int(i32 %x) { ; RV64V-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %v4i1_x = insertelement <4 x i1> undef, i1 undef, i32 %x ; RV64V-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %v8i1_x = insertelement <8 x i1> undef, i1 undef, i32 %x ; RV64V-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %v16i1_x = insertelement <16 x i1> undef, i1 undef, i32 %x -; RV64V-NEXT: Cost Model: Found an estimated cost of 9 for instruction: %v32i1_x = insertelement <32 x i1> undef, i1 undef, i32 %x +; RV64V-NEXT: Cost Model: Found an estimated cost of 11 for instruction: %v32i1_x = insertelement <32 x i1> undef, i1 undef, i32 %x ; RV64V-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %nxv2i1_x = insertelement undef, i1 undef, i32 %x ; RV64V-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %nxv4i1_x = insertelement undef, i1 undef, i32 %x ; RV64V-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %nxv8i1_x = insertelement undef, i1 undef, i32 %x -; RV64V-NEXT: Cost Model: Found an estimated cost of 9 for instruction: %nxv16i1_x = insertelement undef, i1 undef, i32 %x -; RV64V-NEXT: Cost Model: Found an estimated cost of 13 for instruction: %nxv32i1_x = insertelement undef, i1 undef, i32 %x +; RV64V-NEXT: Cost Model: Found an estimated cost of 11 for instruction: %nxv16i1_x = insertelement undef, i1 undef, i32 %x +; RV64V-NEXT: Cost Model: Found an estimated cost of 19 for instruction: %nxv32i1_x = insertelement undef, i1 undef, i32 %x ; RV64V-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %v2i8_x = insertelement <2 x i8> undef, i8 undef, i32 %x ; RV64V-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %v4i8_x = insertelement <4 x i8> undef, i8 undef, i32 %x ; RV64V-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %v8i8_x = insertelement <8 x i8> undef, i8 undef, i32 %x @@ -341,13 +341,13 @@ define void @insertelement_int(i32 %x) { ; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %v2i1_0 = insertelement <2 x i1> undef, i1 undef, i32 0 ; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %v4i1_0 = insertelement <4 x i1> undef, i1 undef, i32 0 ; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %v8i1_0 = insertelement <8 x i1> undef, i1 undef, i32 0 -; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %v16i1_0 = insertelement <16 x i1> undef, i1 undef, i32 0 -; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 11 for instruction: %v32i1_0 = insertelement <32 x i1> undef, i1 undef, i32 0 +; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 9 for instruction: %v16i1_0 = insertelement <16 x i1> undef, i1 undef, i32 0 +; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 17 for instruction: %v32i1_0 = insertelement <32 x i1> undef, i1 undef, i32 0 ; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %nxv2i1_0 = insertelement undef, i1 undef, i32 0 ; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %nxv4i1_0 = insertelement undef, i1 undef, i32 0 ; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %nxv8i1_0 = insertelement undef, i1 undef, i32 0 -; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %nxv16i1_0 = insertelement undef, i1 undef, i32 0 -; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 11 for instruction: %nxv32i1_0 = insertelement undef, i1 undef, i32 0 +; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 9 for instruction: %nxv16i1_0 = insertelement undef, i1 undef, i32 0 +; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 17 for instruction: %nxv32i1_0 = insertelement undef, i1 undef, i32 0 ; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v2i8_0 = insertelement <2 x i8> undef, i8 undef, i32 0 ; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v4i8_0 = insertelement <4 x i8> undef, i8 undef, i32 0 ; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v8i8_0 = insertelement <8 x i8> undef, i8 undef, i32 0 @@ -395,13 +395,13 @@ define void @insertelement_int(i32 %x) { ; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %v2i1_1 = insertelement <2 x i1> undef, i1 undef, i32 1 ; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %v4i1_1 = insertelement <4 x i1> undef, i1 undef, i32 1 ; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %v8i1_1 = insertelement <8 x i1> undef, i1 undef, i32 1 -; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %v16i1_1 = insertelement <16 x i1> undef, i1 undef, i32 1 -; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 12 for instruction: %v32i1_1 = insertelement <32 x i1> undef, i1 undef, i32 1 +; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 10 for instruction: %v16i1_1 = insertelement <16 x i1> undef, i1 undef, i32 1 +; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 18 for instruction: %v32i1_1 = insertelement <32 x i1> undef, i1 undef, i32 1 ; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %nxv2i1_1 = insertelement undef, i1 undef, i32 1 ; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %nxv4i1_1 = insertelement undef, i1 undef, i32 1 ; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %nxv8i1_1 = insertelement undef, i1 undef, i32 1 -; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %nxv16i1_1 = insertelement undef, i1 undef, i32 1 -; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 12 for instruction: %nxv32i1_1 = insertelement undef, i1 undef, i32 1 +; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 10 for instruction: %nxv16i1_1 = insertelement undef, i1 undef, i32 1 +; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 18 for instruction: %nxv32i1_1 = insertelement undef, i1 undef, i32 1 ; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v2i8_1 = insertelement <2 x i8> undef, i8 undef, i32 1 ; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v4i8_1 = insertelement <4 x i8> undef, i8 undef, i32 1 ; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v8i8_1 = insertelement <8 x i8> undef, i8 undef, i32 1 @@ -449,13 +449,13 @@ define void @insertelement_int(i32 %x) { ; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %v2i1_x = insertelement <2 x i1> undef, i1 undef, i32 %x ; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %v4i1_x = insertelement <4 x i1> undef, i1 undef, i32 %x ; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %v8i1_x = insertelement <8 x i1> undef, i1 undef, i32 %x -; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 9 for instruction: %v16i1_x = insertelement <16 x i1> undef, i1 undef, i32 %x -; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 13 for instruction: %v32i1_x = insertelement <32 x i1> undef, i1 undef, i32 %x +; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 11 for instruction: %v16i1_x = insertelement <16 x i1> undef, i1 undef, i32 %x +; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 19 for instruction: %v32i1_x = insertelement <32 x i1> undef, i1 undef, i32 %x ; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %nxv2i1_x = insertelement undef, i1 undef, i32 %x ; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %nxv4i1_x = insertelement undef, i1 undef, i32 %x ; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %nxv8i1_x = insertelement undef, i1 undef, i32 %x -; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 9 for instruction: %nxv16i1_x = insertelement undef, i1 undef, i32 %x -; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 13 for instruction: %nxv32i1_x = insertelement undef, i1 undef, i32 %x +; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 11 for instruction: %nxv16i1_x = insertelement undef, i1 undef, i32 %x +; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 19 for instruction: %nxv32i1_x = insertelement undef, i1 undef, i32 %x ; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %v2i8_x = insertelement <2 x i8> undef, i8 undef, i32 %x ; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %v4i8_x = insertelement <4 x i8> undef, i8 undef, i32 %x ; RV32ZVE64X-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %v8i8_x = insertelement <8 x i8> undef, i8 undef, i32 %x @@ -506,13 +506,13 @@ define void @insertelement_int(i32 %x) { ; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %v2i1_0 = insertelement <2 x i1> undef, i1 undef, i32 0 ; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %v4i1_0 = insertelement <4 x i1> undef, i1 undef, i32 0 ; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %v8i1_0 = insertelement <8 x i1> undef, i1 undef, i32 0 -; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %v16i1_0 = insertelement <16 x i1> undef, i1 undef, i32 0 -; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 11 for instruction: %v32i1_0 = insertelement <32 x i1> undef, i1 undef, i32 0 +; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 9 for instruction: %v16i1_0 = insertelement <16 x i1> undef, i1 undef, i32 0 +; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 17 for instruction: %v32i1_0 = insertelement <32 x i1> undef, i1 undef, i32 0 ; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %nxv2i1_0 = insertelement undef, i1 undef, i32 0 ; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %nxv4i1_0 = insertelement undef, i1 undef, i32 0 ; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %nxv8i1_0 = insertelement undef, i1 undef, i32 0 -; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %nxv16i1_0 = insertelement undef, i1 undef, i32 0 -; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 11 for instruction: %nxv32i1_0 = insertelement undef, i1 undef, i32 0 +; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 9 for instruction: %nxv16i1_0 = insertelement undef, i1 undef, i32 0 +; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 17 for instruction: %nxv32i1_0 = insertelement undef, i1 undef, i32 0 ; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v2i8_0 = insertelement <2 x i8> undef, i8 undef, i32 0 ; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v4i8_0 = insertelement <4 x i8> undef, i8 undef, i32 0 ; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %v8i8_0 = insertelement <8 x i8> undef, i8 undef, i32 0 @@ -560,13 +560,13 @@ define void @insertelement_int(i32 %x) { ; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %v2i1_1 = insertelement <2 x i1> undef, i1 undef, i32 1 ; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %v4i1_1 = insertelement <4 x i1> undef, i1 undef, i32 1 ; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %v8i1_1 = insertelement <8 x i1> undef, i1 undef, i32 1 -; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %v16i1_1 = insertelement <16 x i1> undef, i1 undef, i32 1 -; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 12 for instruction: %v32i1_1 = insertelement <32 x i1> undef, i1 undef, i32 1 +; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 10 for instruction: %v16i1_1 = insertelement <16 x i1> undef, i1 undef, i32 1 +; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 18 for instruction: %v32i1_1 = insertelement <32 x i1> undef, i1 undef, i32 1 ; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %nxv2i1_1 = insertelement undef, i1 undef, i32 1 ; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %nxv4i1_1 = insertelement undef, i1 undef, i32 1 ; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %nxv8i1_1 = insertelement undef, i1 undef, i32 1 -; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %nxv16i1_1 = insertelement undef, i1 undef, i32 1 -; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 12 for instruction: %nxv32i1_1 = insertelement undef, i1 undef, i32 1 +; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 10 for instruction: %nxv16i1_1 = insertelement undef, i1 undef, i32 1 +; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 18 for instruction: %nxv32i1_1 = insertelement undef, i1 undef, i32 1 ; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v2i8_1 = insertelement <2 x i8> undef, i8 undef, i32 1 ; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v4i8_1 = insertelement <4 x i8> undef, i8 undef, i32 1 ; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %v8i8_1 = insertelement <8 x i8> undef, i8 undef, i32 1 @@ -614,13 +614,13 @@ define void @insertelement_int(i32 %x) { ; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %v2i1_x = insertelement <2 x i1> undef, i1 undef, i32 %x ; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %v4i1_x = insertelement <4 x i1> undef, i1 undef, i32 %x ; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %v8i1_x = insertelement <8 x i1> undef, i1 undef, i32 %x -; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 9 for instruction: %v16i1_x = insertelement <16 x i1> undef, i1 undef, i32 %x -; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 13 for instruction: %v32i1_x = insertelement <32 x i1> undef, i1 undef, i32 %x +; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 11 for instruction: %v16i1_x = insertelement <16 x i1> undef, i1 undef, i32 %x +; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 19 for instruction: %v32i1_x = insertelement <32 x i1> undef, i1 undef, i32 %x ; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %nxv2i1_x = insertelement undef, i1 undef, i32 %x ; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %nxv4i1_x = insertelement undef, i1 undef, i32 %x ; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %nxv8i1_x = insertelement undef, i1 undef, i32 %x -; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 9 for instruction: %nxv16i1_x = insertelement undef, i1 undef, i32 %x -; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 13 for instruction: %nxv32i1_x = insertelement undef, i1 undef, i32 %x +; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 11 for instruction: %nxv16i1_x = insertelement undef, i1 undef, i32 %x +; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 19 for instruction: %nxv32i1_x = insertelement undef, i1 undef, i32 %x ; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %v2i8_x = insertelement <2 x i8> undef, i8 undef, i32 %x ; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %v4i8_x = insertelement <4 x i8> undef, i8 undef, i32 %x ; RV64ZVE64X-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %v8i8_x = insertelement <8 x i8> undef, i8 undef, i32 %x diff --git a/llvm/test/Analysis/CostModel/RISCV/shuffle-broadcast.ll b/llvm/test/Analysis/CostModel/RISCV/shuffle-broadcast.ll index b763198e98ba..79ba1562d0f8 100644 --- a/llvm/test/Analysis/CostModel/RISCV/shuffle-broadcast.ll +++ b/llvm/test/Analysis/CostModel/RISCV/shuffle-broadcast.ll @@ -197,7 +197,7 @@ define void @broadcast_fixed() #0{ ; CHECK-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %41 = shufflevector <32 x i1> undef, <32 x i1> undef, <32 x i32> zeroinitializer ; CHECK-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %42 = shufflevector <64 x i1> undef, <64 x i1> undef, <64 x i32> zeroinitializer ; CHECK-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %43 = shufflevector <128 x i1> undef, <128 x i1> undef, <128 x i32> zeroinitializer -; CHECK-NEXT: Cost Model: Found an estimated cost of 19 for instruction: %ins1 = insertelement <128 x i1> poison, i1 poison, i32 0 +; CHECK-NEXT: Cost Model: Found an estimated cost of 33 for instruction: %ins1 = insertelement <128 x i1> poison, i1 poison, i32 0 ; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %44 = shufflevector <128 x i1> %ins1, <128 x i1> poison, <128 x i32> zeroinitializer ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %ins2 = insertelement <2 x i8> poison, i8 3, i32 0 ; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %45 = shufflevector <2 x i8> %ins2, <2 x i8> undef, <2 x i32> zeroinitializer -- GitLab From 38113a083283d2f30a677befaa5fb86dce731c8b Mon Sep 17 00:00:00 2001 From: Matthias Springer Date: Tue, 2 Apr 2024 10:53:57 +0900 Subject: [PATCH 025/447] [mlir][IR] Trigger `notifyOperationReplaced` on `replaceAllOpUsesWith` (#84721) Before this change: `notifyOperationReplaced` was triggered when calling `RewriteBase::replaceOp`. After this change: `notifyOperationReplaced` is triggered when `RewriterBase::replaceAllOpUsesWith` or `RewriterBase::replaceOp` is called. Until now, every `notifyOperationReplaced` was always sent together with a `notifyOperationErased`, which made that `notifyOperationErased` callback irrelevant. More importantly, when a user called `RewriterBase::replaceAllOpUsesWith`+`RewriterBase::eraseOp` instead of `RewriterBase::replaceOp`, no `notifyOperationReplaced` callback was sent, even though the two notations are semantically equivalent. As an example, this can be a problem when applying patterns with the transform dialect because the `TrackingListener` will only see the `notifyOperationErased` callback and the payload op is dropped from the mappings. Note: It is still possible to write semantically equivalent code that does not trigger a `notifyOperationReplaced` (e.g., when op results are replaced one-by-one), but this commit already improves the situation a lot. --- mlir/include/mlir/IR/PatternMatch.h | 29 ++++++++++++--------- mlir/lib/IR/PatternMatch.cpp | 24 +++++++++++------ mlir/test/lib/Dialect/Test/TestPatterns.cpp | 5 +++- 3 files changed, 37 insertions(+), 21 deletions(-) diff --git a/mlir/include/mlir/IR/PatternMatch.h b/mlir/include/mlir/IR/PatternMatch.h index 070e6ed702f8..ac2b0d5a3837 100644 --- a/mlir/include/mlir/IR/PatternMatch.h +++ b/mlir/include/mlir/IR/PatternMatch.h @@ -409,9 +409,9 @@ public: /// Notify the listener that the specified operation was modified in-place. virtual void notifyOperationModified(Operation *op) {} - /// Notify the listener that the specified operation is about to be replaced - /// with another operation. This is called before the uses of the old - /// operation have been changed. + /// Notify the listener that all uses of the specified operation's results + /// are about to be replaced with the results of another operation. This is + /// called before the uses of the old operation have been changed. /// /// By default, this function calls the "operation replaced with values" /// notification. @@ -420,9 +420,10 @@ public: notifyOperationReplaced(op, replacement->getResults()); } - /// Notify the listener that the specified operation is about to be replaced - /// with the a range of values, potentially produced by other operations. - /// This is called before the uses of the operation have been changed. + /// Notify the listener that all uses of the specified operation's results + /// are about to be replaced with the a range of values, potentially + /// produced by other operations. This is called before the uses of the + /// operation have been changed. virtual void notifyOperationReplaced(Operation *op, ValueRange replacement) {} @@ -648,12 +649,16 @@ public: for (auto it : llvm::zip(from, to)) replaceAllUsesWith(std::get<0>(it), std::get<1>(it)); } - // Note: This function cannot be called `replaceAllUsesWith` because the - // overload resolution, when called with an op that can be implicitly - // converted to a Value, would be ambiguous. - void replaceAllOpUsesWith(Operation *from, ValueRange to) { - replaceAllUsesWith(from->getResults(), to); - } + + /// Find uses of `from` and replace them with `to`. Also notify the listener + /// about every in-place op modification (for every use that was replaced) + /// and that the `from` operation is about to be replaced. + /// + /// Note: This function cannot be called `replaceAllUsesWith` because the + /// overload resolution, when called with an op that can be implicitly + /// converted to a Value, would be ambiguous. + void replaceAllOpUsesWith(Operation *from, ValueRange to); + void replaceAllOpUsesWith(Operation *from, Operation *to); /// Find uses of `from` and replace them with `to` if the `functor` returns /// true. Also notify the listener about every in-place op modification (for diff --git a/mlir/lib/IR/PatternMatch.cpp b/mlir/lib/IR/PatternMatch.cpp index 4079ccc75672..5944a0ea46a1 100644 --- a/mlir/lib/IR/PatternMatch.cpp +++ b/mlir/lib/IR/PatternMatch.cpp @@ -110,6 +110,22 @@ RewriterBase::~RewriterBase() { // Out of line to provide a vtable anchor for the class. } +void RewriterBase::replaceAllOpUsesWith(Operation *from, ValueRange to) { + // Notify the listener that we're about to replace this op. + if (auto *rewriteListener = dyn_cast_if_present(listener)) + rewriteListener->notifyOperationReplaced(from, to); + + replaceAllUsesWith(from->getResults(), to); +} + +void RewriterBase::replaceAllOpUsesWith(Operation *from, Operation *to) { + // Notify the listener that we're about to replace this op. + if (auto *rewriteListener = dyn_cast_if_present(listener)) + rewriteListener->notifyOperationReplaced(from, to); + + replaceAllUsesWith(from->getResults(), to->getResults()); +} + /// This method replaces the results of the operation with the specified list of /// values. The number of provided values must match the number of results of /// the operation. The replaced op is erased. @@ -117,10 +133,6 @@ void RewriterBase::replaceOp(Operation *op, ValueRange newValues) { assert(op->getNumResults() == newValues.size() && "incorrect # of replacement values"); - // Notify the listener that we're about to replace this op. - if (auto *rewriteListener = dyn_cast_if_present(listener)) - rewriteListener->notifyOperationReplaced(op, newValues); - // Replace all result uses. Also notifies the listener of modifications. replaceAllOpUsesWith(op, newValues); @@ -136,10 +148,6 @@ void RewriterBase::replaceOp(Operation *op, Operation *newOp) { assert(op->getNumResults() == newOp->getNumResults() && "ops have different number of results"); - // Notify the listener that we're about to replace this op. - if (auto *rewriteListener = dyn_cast_if_present(listener)) - rewriteListener->notifyOperationReplaced(op, newOp); - // Replace all result uses. Also notifies the listener of modifications. replaceAllOpUsesWith(op, newOp->getResults()); diff --git a/mlir/test/lib/Dialect/Test/TestPatterns.cpp b/mlir/test/lib/Dialect/Test/TestPatterns.cpp index 2da184bc3d85..76dc825fe445 100644 --- a/mlir/test/lib/Dialect/Test/TestPatterns.cpp +++ b/mlir/test/lib/Dialect/Test/TestPatterns.cpp @@ -489,7 +489,10 @@ private: OperationName("test.new_op", op->getContext()).getIdentifier(), op->getOperands(), op->getResultTypes()); } - rewriter.replaceOp(op, newOp->getResults()); + // "replaceOp" could be used instead of "replaceAllOpUsesWith"+"eraseOp". + // A "notifyOperationReplaced" callback is triggered in either case. + rewriter.replaceAllOpUsesWith(op, newOp->getResults()); + rewriter.eraseOp(op); return success(); } }; -- GitLab From 21f85e230056172cffcaec76352e5a2019b54b86 Mon Sep 17 00:00:00 2001 From: Chuanqi Xu Date: Tue, 2 Apr 2024 09:52:52 +0800 Subject: [PATCH 026/447] [NFC] [C++20] [Modules] Pulling out getCXX20NamedModuleOutputPath into a seperate function Required in the review process of https://github.com/llvm/llvm-project/pull/85050. --- clang/lib/Driver/Driver.cpp | 14 ++------------ clang/lib/Driver/ToolChains/Clang.cpp | 18 ++++++++++++++++++ clang/lib/Driver/ToolChains/Clang.h | 15 +++++++++++++++ 3 files changed, 35 insertions(+), 12 deletions(-) diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 7a53764364ce..1a0f5f27eda2 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -5814,19 +5814,9 @@ static const char *GetModuleOutputPath(Compilation &C, const JobAction &JA, (C.getArgs().hasArg(options::OPT_fmodule_output) || C.getArgs().hasArg(options::OPT_fmodule_output_EQ))); - if (Arg *ModuleOutputEQ = - C.getArgs().getLastArg(options::OPT_fmodule_output_EQ)) - return C.addResultFile(ModuleOutputEQ->getValue(), &JA); + SmallString<256> OutputPath = + tools::getCXX20NamedModuleOutputPath(C.getArgs(), BaseInput); - SmallString<64> OutputPath; - Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o); - if (FinalOutput && C.getArgs().hasArg(options::OPT_c)) - OutputPath = FinalOutput->getValue(); - else - OutputPath = BaseInput; - - const char *Extension = types::getTypeTempSuffix(JA.getType()); - llvm::sys::path::replace_extension(OutputPath, Extension); return C.addResultFile(C.getArgs().MakeArgString(OutputPath.c_str()), &JA); } diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 3bcacff7724c..b03ac6018d2b 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -3839,6 +3839,24 @@ bool Driver::getDefaultModuleCachePath(SmallVectorImpl &Result) { return false; } +llvm::SmallString<256> +clang::driver::tools::getCXX20NamedModuleOutputPath(const ArgList &Args, + const char *BaseInput) { + if (Arg *ModuleOutputEQ = Args.getLastArg(options::OPT_fmodule_output_EQ)) + return StringRef(ModuleOutputEQ->getValue()); + + SmallString<256> OutputPath; + if (Arg *FinalOutput = Args.getLastArg(options::OPT_o); + FinalOutput && Args.hasArg(options::OPT_c)) + OutputPath = FinalOutput->getValue(); + else + OutputPath = BaseInput; + + const char *Extension = types::getTypeTempSuffix(types::TY_ModuleFile); + llvm::sys::path::replace_extension(OutputPath, Extension); + return OutputPath; +} + static bool RenderModulesOptions(Compilation &C, const Driver &D, const ArgList &Args, const InputInfo &Input, const InputInfo &Output, bool HaveStd20, diff --git a/clang/lib/Driver/ToolChains/Clang.h b/clang/lib/Driver/ToolChains/Clang.h index 0f503c4bd1c4..18f6c5ed06a5 100644 --- a/clang/lib/Driver/ToolChains/Clang.h +++ b/clang/lib/Driver/ToolChains/Clang.h @@ -193,6 +193,21 @@ DwarfFissionKind getDebugFissionKind(const Driver &D, const llvm::opt::ArgList &Args, llvm::opt::Arg *&Arg); +// Calculate the output path of the module file when compiling a module unit +// with the `-fmodule-output` option or `-fmodule-output=` option specified. +// The behavior is: +// - If `-fmodule-output=` is specfied, then the module file is +// writing to the value. +// - Otherwise if the output object file of the module unit is specified, the +// output path +// of the module file should be the same with the output object file except +// the corresponding suffix. This requires both `-o` and `-c` are specified. +// - Otherwise, the output path of the module file will be the same with the +// input with the corresponding suffix. +llvm::SmallString<256> +getCXX20NamedModuleOutputPath(const llvm::opt::ArgList &Args, + const char *BaseInput); + } // end namespace tools } // end namespace driver -- GitLab From 9067f5470573454ad33f2d1786cdfa77f7f9329c Mon Sep 17 00:00:00 2001 From: Matthias Springer Date: Tue, 2 Apr 2024 11:03:12 +0900 Subject: [PATCH 027/447] [mlir][IR][NFC] Make `replaceAllUsesWith` non-templatized (#84722) Turn `RewriterBase::replaceAllUsesWith` into a non-templatized implementation, so that it can be made virtual and be overridden in the `ConversionPatternRewriter` in a subsequent change. This change is in preparation of adding dialect conversion support for `replaceAllUsesWith`. --- mlir/include/mlir/IR/PatternMatch.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/mlir/include/mlir/IR/PatternMatch.h b/mlir/include/mlir/IR/PatternMatch.h index ac2b0d5a3837..15b1c3892948 100644 --- a/mlir/include/mlir/IR/PatternMatch.h +++ b/mlir/include/mlir/IR/PatternMatch.h @@ -635,11 +635,13 @@ public: /// Find uses of `from` and replace them with `to`. Also notify the listener /// about every in-place op modification (for every use that was replaced). void replaceAllUsesWith(Value from, Value to) { - return replaceAllUsesWith(from.getImpl(), to); + for (OpOperand &operand : llvm::make_early_inc_range(from.getUses())) { + Operation *op = operand.getOwner(); + modifyOpInPlace(op, [&]() { operand.set(to); }); + } } - template - void replaceAllUsesWith(IRObjectWithUseList *from, ValueT &&to) { - for (OperandType &operand : llvm::make_early_inc_range(from->getUses())) { + void replaceAllUsesWith(Block *from, Block *to) { + for (BlockOperand &operand : llvm::make_early_inc_range(from->getUses())) { Operation *op = operand.getOwner(); modifyOpInPlace(op, [&]() { operand.set(to); }); } -- GitLab From 49a4ec20a8be5888cbf225bab340dbaf204902c7 Mon Sep 17 00:00:00 2001 From: Rob Suderman Date: Mon, 1 Apr 2024 19:22:49 -0700 Subject: [PATCH 028/447] [mlir] Reland the dialect conversion hanging use fix (#87297) Dialect conversion sometimes can have a hanging use of an argument. Ensured that argument uses are dropped before removing the block. --- mlir/lib/Transforms/Utils/DialectConversion.cpp | 2 ++ .../TosaToLinalg/tosa-to-linalg-invalid.mlir | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/mlir/lib/Transforms/Utils/DialectConversion.cpp b/mlir/lib/Transforms/Utils/DialectConversion.cpp index 8671c1008902..270ac0a08689 100644 --- a/mlir/lib/Transforms/Utils/DialectConversion.cpp +++ b/mlir/lib/Transforms/Utils/DialectConversion.cpp @@ -279,6 +279,8 @@ public: auto &blockOps = block->getOperations(); while (!blockOps.empty()) blockOps.remove(blockOps.begin()); + for (auto arg : block->getArguments()) + arg.dropAllUses(); block->dropAllUses(); if (block->getParent()) block->erase(); diff --git a/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg-invalid.mlir b/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg-invalid.mlir index 17eec5936918..6494e1b27194 100644 --- a/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg-invalid.mlir +++ b/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg-invalid.mlir @@ -15,3 +15,16 @@ func.func @tensor_with_unknown_rank(%arg0: tensor<*xi8>) -> tensor<*xi8> { %0 = "tosa.abs"(%arg0) : (tensor<*xi8>) -> tensor<*xi8> return %0 : tensor<*xi8> } + +// ----- + +// CHECK-LABEL: @unranked_add +func.func @unranked_add(%arg0 : tensor<10x10xf32> , %arg1 : tensor<10x10xf32>, %arg2 : tensor<*xf32>) -> (tensor<10x10xf32>) { + // expected-error@+3 {{failed to legalize operation 'tosa.add'}} + %reduce = tosa.reduce_max %arg0 {axis = 1 : i32} : (tensor<10x10xf32>) -> tensor<10x1xf32> + %1 = tosa.add %reduce, %arg1 : (tensor<10x1xf32>, tensor<10x10xf32>) -> tensor<10x10xf32> + %0 = tosa.add %1, %arg2 : (tensor<10x10xf32>, tensor<*xf32>) -> tensor<*xf32> + %2 = tosa.reshape %0 {new_shape = array} : (tensor<*xf32>) -> tensor<10x10xf32> + return %2 : tensor<10x10xf32> +} + -- GitLab From b932db08bb8e56c80380468698a6f75d5ea35577 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Mon, 1 Apr 2024 20:19:59 -0700 Subject: [PATCH 029/447] [llvm-objcopy,test] Prepend error: to some messages --- llvm/test/tools/llvm-objcopy/ELF/discard-locals-rel.test | 4 ++-- llvm/test/tools/llvm-objcopy/ELF/strip-reloc-symbol.test | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/llvm/test/tools/llvm-objcopy/ELF/discard-locals-rel.test b/llvm/test/tools/llvm-objcopy/ELF/discard-locals-rel.test index 3658eb376010..00bb8fcf1820 100644 --- a/llvm/test/tools/llvm-objcopy/ELF/discard-locals-rel.test +++ b/llvm/test/tools/llvm-objcopy/ELF/discard-locals-rel.test @@ -1,5 +1,5 @@ # RUN: yaml2obj %s -o %t -# RUN: not llvm-objcopy --discard-locals %t %t2 2>&1 | FileCheck %s +# RUN: not llvm-objcopy --discard-locals %t %t2 2>&1 | FileCheck %s -DFILE=%t !ELF FileHeader: @@ -23,4 +23,4 @@ Symbols: Type: STT_FUNC Section: .text -# CHECK: not stripping symbol '.L.rel' because it is named in a relocation +# CHECK: error: '[[FILE]]': not stripping symbol '.L.rel' because it is named in a relocation diff --git a/llvm/test/tools/llvm-objcopy/ELF/strip-reloc-symbol.test b/llvm/test/tools/llvm-objcopy/ELF/strip-reloc-symbol.test index 63c9e122d9a2..941dacce2edf 100644 --- a/llvm/test/tools/llvm-objcopy/ELF/strip-reloc-symbol.test +++ b/llvm/test/tools/llvm-objcopy/ELF/strip-reloc-symbol.test @@ -1,5 +1,5 @@ # RUN: yaml2obj %s -o %t -# RUN: not llvm-objcopy -N foo %t %t2 2>&1 | FileCheck %s +# RUN: not llvm-objcopy -N foo %t %t2 2>&1 | FileCheck %s -DFILE=%t !ELF FileHeader: @@ -28,4 +28,4 @@ Symbols: Value: 0x1000 Size: 8 -# CHECK: not stripping symbol 'foo' because it is named in a relocation +# CHECK: error: '[[FILE]]': not stripping symbol 'foo' because it is named in a relocation -- GitLab From 59dd10faf8c3bb9dbcecb60d932284b8762cebf8 Mon Sep 17 00:00:00 2001 From: Luke Lau Date: Tue, 2 Apr 2024 13:02:03 +0800 Subject: [PATCH 030/447] [RISCV] Add tests for fixed vector vwsll. NFC We are missing patterns for fixed vectors, where the sexts and zexts are legalized to _vl nodes. --- .../CodeGen/RISCV/rvv/fixed-vectors-vwsll.ll | 920 ++++++++++++++++++ 1 file changed, 920 insertions(+) create mode 100644 llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vwsll.ll diff --git a/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vwsll.ll b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vwsll.ll new file mode 100644 index 000000000000..f5305a1c36de --- /dev/null +++ b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-vwsll.ll @@ -0,0 +1,920 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2 +; RUN: llc -mtriple=riscv32 -mattr=+v -verify-machineinstrs < %s | FileCheck %s +; RUN: llc -mtriple=riscv64 -mattr=+v -verify-machineinstrs < %s | FileCheck %s +; RUN: llc -mtriple=riscv32 -mattr=+v,+zvbb -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK-ZVBB +; RUN: llc -mtriple=riscv64 -mattr=+v,+zvbb -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK-ZVBB + +; ============================================================================== +; i32 -> i64 +; ============================================================================== + +define <4 x i64> @vwsll_vv_v4i64_sext(<4 x i32> %a, <4 x i32> %b) { +; CHECK-LABEL: vwsll_vv_v4i64_sext: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 4, e64, m2, ta, ma +; CHECK-NEXT: vzext.vf2 v10, v8 +; CHECK-NEXT: vsext.vf2 v12, v9 +; CHECK-NEXT: vsll.vv v8, v10, v12 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vv_v4i64_sext: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 4, e64, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf2 v10, v8 +; CHECK-ZVBB-NEXT: vsext.vf2 v12, v9 +; CHECK-ZVBB-NEXT: vsll.vv v8, v10, v12 +; CHECK-ZVBB-NEXT: ret + %x = zext <4 x i32> %a to <4 x i64> + %y = sext <4 x i32> %b to <4 x i64> + %z = shl <4 x i64> %x, %y + ret <4 x i64> %z +} + +define <4 x i64> @vwsll_vv_v4i64_zext(<4 x i32> %a, <4 x i32> %b) { +; CHECK-LABEL: vwsll_vv_v4i64_zext: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 4, e64, m2, ta, ma +; CHECK-NEXT: vzext.vf2 v10, v8 +; CHECK-NEXT: vzext.vf2 v12, v9 +; CHECK-NEXT: vsll.vv v8, v10, v12 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vv_v4i64_zext: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 4, e64, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf2 v10, v8 +; CHECK-ZVBB-NEXT: vzext.vf2 v12, v9 +; CHECK-ZVBB-NEXT: vsll.vv v8, v10, v12 +; CHECK-ZVBB-NEXT: ret + %x = zext <4 x i32> %a to <4 x i64> + %y = zext <4 x i32> %b to <4 x i64> + %z = shl <4 x i64> %x, %y + ret <4 x i64> %z +} + +define <4 x i64> @vwsll_vx_i64_v4i64(<4 x i32> %a, i64 %b) { +; CHECK-LABEL: vwsll_vx_i64_v4i64: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 4, e64, m2, ta, ma +; CHECK-NEXT: vzext.vf2 v10, v8 +; CHECK-NEXT: vsll.vx v8, v10, a0 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vx_i64_v4i64: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 4, e64, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf2 v10, v8 +; CHECK-ZVBB-NEXT: vsll.vx v8, v10, a0 +; CHECK-ZVBB-NEXT: ret + %head = insertelement <4 x i64> poison, i64 %b, i32 0 + %splat = shufflevector <4 x i64> %head, <4 x i64> poison, <4 x i32> zeroinitializer + %x = zext <4 x i32> %a to <4 x i64> + %z = shl <4 x i64> %x, %splat + ret <4 x i64> %z +} + +define <4 x i64> @vwsll_vx_i32_v4i64_sext(<4 x i32> %a, i32 %b) { +; CHECK-LABEL: vwsll_vx_i32_v4i64_sext: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 4, e32, m1, ta, ma +; CHECK-NEXT: vmv.v.x v9, a0 +; CHECK-NEXT: vsetvli zero, zero, e64, m2, ta, ma +; CHECK-NEXT: vzext.vf2 v10, v8 +; CHECK-NEXT: vsext.vf2 v12, v9 +; CHECK-NEXT: vsll.vv v8, v10, v12 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vx_i32_v4i64_sext: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 4, e32, m1, ta, ma +; CHECK-ZVBB-NEXT: vmv.v.x v9, a0 +; CHECK-ZVBB-NEXT: vsetvli zero, zero, e64, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf2 v10, v8 +; CHECK-ZVBB-NEXT: vsext.vf2 v12, v9 +; CHECK-ZVBB-NEXT: vsll.vv v8, v10, v12 +; CHECK-ZVBB-NEXT: ret + %head = insertelement <4 x i32> poison, i32 %b, i32 0 + %splat = shufflevector <4 x i32> %head, <4 x i32> poison, <4 x i32> zeroinitializer + %x = zext <4 x i32> %a to <4 x i64> + %y = sext <4 x i32> %splat to <4 x i64> + %z = shl <4 x i64> %x, %y + ret <4 x i64> %z +} + +define <4 x i64> @vwsll_vx_i32_v4i64_zext(<4 x i32> %a, i32 %b) { +; CHECK-LABEL: vwsll_vx_i32_v4i64_zext: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 4, e32, m1, ta, ma +; CHECK-NEXT: vmv.v.x v9, a0 +; CHECK-NEXT: vsetvli zero, zero, e64, m2, ta, ma +; CHECK-NEXT: vzext.vf2 v10, v8 +; CHECK-NEXT: vzext.vf2 v12, v9 +; CHECK-NEXT: vsll.vv v8, v10, v12 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vx_i32_v4i64_zext: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 4, e32, m1, ta, ma +; CHECK-ZVBB-NEXT: vmv.v.x v9, a0 +; CHECK-ZVBB-NEXT: vsetvli zero, zero, e64, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf2 v10, v8 +; CHECK-ZVBB-NEXT: vzext.vf2 v12, v9 +; CHECK-ZVBB-NEXT: vsll.vv v8, v10, v12 +; CHECK-ZVBB-NEXT: ret + %head = insertelement <4 x i32> poison, i32 %b, i32 0 + %splat = shufflevector <4 x i32> %head, <4 x i32> poison, <4 x i32> zeroinitializer + %x = zext <4 x i32> %a to <4 x i64> + %y = zext <4 x i32> %splat to <4 x i64> + %z = shl <4 x i64> %x, %y + ret <4 x i64> %z +} + +define <4 x i64> @vwsll_vx_i16_v4i64_sext(<4 x i32> %a, i16 %b) { +; CHECK-LABEL: vwsll_vx_i16_v4i64_sext: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 4, e16, mf2, ta, ma +; CHECK-NEXT: vmv.v.x v9, a0 +; CHECK-NEXT: vsetvli zero, zero, e64, m2, ta, ma +; CHECK-NEXT: vzext.vf2 v10, v8 +; CHECK-NEXT: vsext.vf4 v12, v9 +; CHECK-NEXT: vsll.vv v8, v10, v12 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vx_i16_v4i64_sext: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 4, e16, mf2, ta, ma +; CHECK-ZVBB-NEXT: vmv.v.x v9, a0 +; CHECK-ZVBB-NEXT: vsetvli zero, zero, e64, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf2 v10, v8 +; CHECK-ZVBB-NEXT: vsext.vf4 v12, v9 +; CHECK-ZVBB-NEXT: vsll.vv v8, v10, v12 +; CHECK-ZVBB-NEXT: ret + %head = insertelement <4 x i16> poison, i16 %b, i32 0 + %splat = shufflevector <4 x i16> %head, <4 x i16> poison, <4 x i32> zeroinitializer + %x = zext <4 x i32> %a to <4 x i64> + %y = sext <4 x i16> %splat to <4 x i64> + %z = shl <4 x i64> %x, %y + ret <4 x i64> %z +} + +define <4 x i64> @vwsll_vx_i16_v4i64_zext(<4 x i32> %a, i16 %b) { +; CHECK-LABEL: vwsll_vx_i16_v4i64_zext: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 4, e16, mf2, ta, ma +; CHECK-NEXT: vmv.v.x v9, a0 +; CHECK-NEXT: vsetvli zero, zero, e64, m2, ta, ma +; CHECK-NEXT: vzext.vf2 v10, v8 +; CHECK-NEXT: vzext.vf4 v12, v9 +; CHECK-NEXT: vsll.vv v8, v10, v12 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vx_i16_v4i64_zext: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 4, e16, mf2, ta, ma +; CHECK-ZVBB-NEXT: vmv.v.x v9, a0 +; CHECK-ZVBB-NEXT: vsetvli zero, zero, e64, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf2 v10, v8 +; CHECK-ZVBB-NEXT: vzext.vf4 v12, v9 +; CHECK-ZVBB-NEXT: vsll.vv v8, v10, v12 +; CHECK-ZVBB-NEXT: ret + %head = insertelement <4 x i16> poison, i16 %b, i32 0 + %splat = shufflevector <4 x i16> %head, <4 x i16> poison, <4 x i32> zeroinitializer + %x = zext <4 x i32> %a to <4 x i64> + %y = zext <4 x i16> %splat to <4 x i64> + %z = shl <4 x i64> %x, %y + ret <4 x i64> %z +} + +define <4 x i64> @vwsll_vx_i8_v4i64_sext(<4 x i32> %a, i8 %b) { +; CHECK-LABEL: vwsll_vx_i8_v4i64_sext: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 4, e8, mf4, ta, ma +; CHECK-NEXT: vmv.v.x v9, a0 +; CHECK-NEXT: vsetvli zero, zero, e64, m2, ta, ma +; CHECK-NEXT: vzext.vf2 v10, v8 +; CHECK-NEXT: vsext.vf8 v12, v9 +; CHECK-NEXT: vsll.vv v8, v10, v12 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vx_i8_v4i64_sext: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 4, e8, mf4, ta, ma +; CHECK-ZVBB-NEXT: vmv.v.x v9, a0 +; CHECK-ZVBB-NEXT: vsetvli zero, zero, e64, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf2 v10, v8 +; CHECK-ZVBB-NEXT: vsext.vf8 v12, v9 +; CHECK-ZVBB-NEXT: vsll.vv v8, v10, v12 +; CHECK-ZVBB-NEXT: ret + %head = insertelement <4 x i8> poison, i8 %b, i32 0 + %splat = shufflevector <4 x i8> %head, <4 x i8> poison, <4 x i32> zeroinitializer + %x = zext <4 x i32> %a to <4 x i64> + %y = sext <4 x i8> %splat to <4 x i64> + %z = shl <4 x i64> %x, %y + ret <4 x i64> %z +} + +define <4 x i64> @vwsll_vx_i8_v4i64_zext(<4 x i32> %a, i8 %b) { +; CHECK-LABEL: vwsll_vx_i8_v4i64_zext: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 4, e8, mf4, ta, ma +; CHECK-NEXT: vmv.v.x v9, a0 +; CHECK-NEXT: vsetvli zero, zero, e64, m2, ta, ma +; CHECK-NEXT: vzext.vf2 v10, v8 +; CHECK-NEXT: vzext.vf8 v12, v9 +; CHECK-NEXT: vsll.vv v8, v10, v12 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vx_i8_v4i64_zext: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 4, e8, mf4, ta, ma +; CHECK-ZVBB-NEXT: vmv.v.x v9, a0 +; CHECK-ZVBB-NEXT: vsetvli zero, zero, e64, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf2 v10, v8 +; CHECK-ZVBB-NEXT: vzext.vf8 v12, v9 +; CHECK-ZVBB-NEXT: vsll.vv v8, v10, v12 +; CHECK-ZVBB-NEXT: ret + %head = insertelement <4 x i8> poison, i8 %b, i32 0 + %splat = shufflevector <4 x i8> %head, <4 x i8> poison, <4 x i32> zeroinitializer + %x = zext <4 x i32> %a to <4 x i64> + %y = zext <4 x i8> %splat to <4 x i64> + %z = shl <4 x i64> %x, %y + ret <4 x i64> %z +} + +define <4 x i64> @vwsll_vi_v4i64(<4 x i32> %a) { +; CHECK-LABEL: vwsll_vi_v4i64: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 4, e64, m2, ta, ma +; CHECK-NEXT: vzext.vf2 v10, v8 +; CHECK-NEXT: vsll.vi v8, v10, 2 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vi_v4i64: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 4, e64, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf2 v10, v8 +; CHECK-ZVBB-NEXT: vsll.vi v8, v10, 2 +; CHECK-ZVBB-NEXT: ret + %x = zext <4 x i32> %a to <4 x i64> + %z = shl <4 x i64> %x, splat (i64 2) + ret <4 x i64> %z +} + +; ============================================================================== +; i16 -> i32 +; ============================================================================== + +define <8 x i32> @vwsll_vv_v8i32_sext(<8 x i16> %a, <8 x i16> %b) { +; CHECK-LABEL: vwsll_vv_v8i32_sext: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 8, e32, m2, ta, ma +; CHECK-NEXT: vzext.vf2 v10, v8 +; CHECK-NEXT: vsext.vf2 v12, v9 +; CHECK-NEXT: vsll.vv v8, v10, v12 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vv_v8i32_sext: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 8, e32, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf2 v10, v8 +; CHECK-ZVBB-NEXT: vsext.vf2 v12, v9 +; CHECK-ZVBB-NEXT: vsll.vv v8, v10, v12 +; CHECK-ZVBB-NEXT: ret + %x = zext <8 x i16> %a to <8 x i32> + %y = sext <8 x i16> %b to <8 x i32> + %z = shl <8 x i32> %x, %y + ret <8 x i32> %z +} + +define <8 x i32> @vwsll_vv_v8i32_zext(<8 x i16> %a, <8 x i16> %b) { +; CHECK-LABEL: vwsll_vv_v8i32_zext: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 8, e32, m2, ta, ma +; CHECK-NEXT: vzext.vf2 v10, v8 +; CHECK-NEXT: vzext.vf2 v12, v9 +; CHECK-NEXT: vsll.vv v8, v10, v12 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vv_v8i32_zext: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 8, e32, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf2 v10, v8 +; CHECK-ZVBB-NEXT: vzext.vf2 v12, v9 +; CHECK-ZVBB-NEXT: vsll.vv v8, v10, v12 +; CHECK-ZVBB-NEXT: ret + %x = zext <8 x i16> %a to <8 x i32> + %y = zext <8 x i16> %b to <8 x i32> + %z = shl <8 x i32> %x, %y + ret <8 x i32> %z +} + +define <8 x i32> @vwsll_vx_i64_v8i32(<8 x i16> %a, i64 %b) { +; CHECK-LABEL: vwsll_vx_i64_v8i32: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 8, e32, m2, ta, ma +; CHECK-NEXT: vzext.vf2 v10, v8 +; CHECK-NEXT: vsll.vx v8, v10, a0 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vx_i64_v8i32: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 8, e32, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf2 v10, v8 +; CHECK-ZVBB-NEXT: vsll.vx v8, v10, a0 +; CHECK-ZVBB-NEXT: ret + %head = insertelement <8 x i64> poison, i64 %b, i32 0 + %splat = shufflevector <8 x i64> %head, <8 x i64> poison, <8 x i32> zeroinitializer + %x = zext <8 x i16> %a to <8 x i32> + %y = trunc <8 x i64> %splat to <8 x i32> + %z = shl <8 x i32> %x, %y + ret <8 x i32> %z +} + +define <8 x i32> @vwsll_vx_i32_v8i32(<8 x i16> %a, i32 %b) { +; CHECK-LABEL: vwsll_vx_i32_v8i32: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 8, e32, m2, ta, ma +; CHECK-NEXT: vzext.vf2 v10, v8 +; CHECK-NEXT: vsll.vx v8, v10, a0 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vx_i32_v8i32: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 8, e32, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf2 v10, v8 +; CHECK-ZVBB-NEXT: vsll.vx v8, v10, a0 +; CHECK-ZVBB-NEXT: ret + %head = insertelement <8 x i32> poison, i32 %b, i32 0 + %splat = shufflevector <8 x i32> %head, <8 x i32> poison, <8 x i32> zeroinitializer + %x = zext <8 x i16> %a to <8 x i32> + %z = shl <8 x i32> %x, %splat + ret <8 x i32> %z +} + +define <8 x i32> @vwsll_vx_i16_v8i32_sext(<8 x i16> %a, i16 %b) { +; CHECK-LABEL: vwsll_vx_i16_v8i32_sext: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 8, e16, m1, ta, ma +; CHECK-NEXT: vmv.v.x v9, a0 +; CHECK-NEXT: vsetvli zero, zero, e32, m2, ta, ma +; CHECK-NEXT: vzext.vf2 v10, v8 +; CHECK-NEXT: vsext.vf2 v12, v9 +; CHECK-NEXT: vsll.vv v8, v10, v12 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vx_i16_v8i32_sext: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 8, e16, m1, ta, ma +; CHECK-ZVBB-NEXT: vmv.v.x v9, a0 +; CHECK-ZVBB-NEXT: vsetvli zero, zero, e32, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf2 v10, v8 +; CHECK-ZVBB-NEXT: vsext.vf2 v12, v9 +; CHECK-ZVBB-NEXT: vsll.vv v8, v10, v12 +; CHECK-ZVBB-NEXT: ret + %head = insertelement <8 x i16> poison, i16 %b, i32 0 + %splat = shufflevector <8 x i16> %head, <8 x i16> poison, <8 x i32> zeroinitializer + %x = zext <8 x i16> %a to <8 x i32> + %y = sext <8 x i16> %splat to <8 x i32> + %z = shl <8 x i32> %x, %y + ret <8 x i32> %z +} + +define <8 x i32> @vwsll_vx_i16_v8i32_zext(<8 x i16> %a, i16 %b) { +; CHECK-LABEL: vwsll_vx_i16_v8i32_zext: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 8, e16, m1, ta, ma +; CHECK-NEXT: vmv.v.x v9, a0 +; CHECK-NEXT: vsetvli zero, zero, e32, m2, ta, ma +; CHECK-NEXT: vzext.vf2 v10, v8 +; CHECK-NEXT: vzext.vf2 v12, v9 +; CHECK-NEXT: vsll.vv v8, v10, v12 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vx_i16_v8i32_zext: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 8, e16, m1, ta, ma +; CHECK-ZVBB-NEXT: vmv.v.x v9, a0 +; CHECK-ZVBB-NEXT: vsetvli zero, zero, e32, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf2 v10, v8 +; CHECK-ZVBB-NEXT: vzext.vf2 v12, v9 +; CHECK-ZVBB-NEXT: vsll.vv v8, v10, v12 +; CHECK-ZVBB-NEXT: ret + %head = insertelement <8 x i16> poison, i16 %b, i32 0 + %splat = shufflevector <8 x i16> %head, <8 x i16> poison, <8 x i32> zeroinitializer + %x = zext <8 x i16> %a to <8 x i32> + %y = zext <8 x i16> %splat to <8 x i32> + %z = shl <8 x i32> %x, %y + ret <8 x i32> %z +} + +define <8 x i32> @vwsll_vx_i8_v8i32_sext(<8 x i16> %a, i8 %b) { +; CHECK-LABEL: vwsll_vx_i8_v8i32_sext: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 8, e8, mf2, ta, ma +; CHECK-NEXT: vmv.v.x v9, a0 +; CHECK-NEXT: vsetvli zero, zero, e32, m2, ta, ma +; CHECK-NEXT: vzext.vf2 v10, v8 +; CHECK-NEXT: vsext.vf4 v12, v9 +; CHECK-NEXT: vsll.vv v8, v10, v12 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vx_i8_v8i32_sext: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 8, e8, mf2, ta, ma +; CHECK-ZVBB-NEXT: vmv.v.x v9, a0 +; CHECK-ZVBB-NEXT: vsetvli zero, zero, e32, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf2 v10, v8 +; CHECK-ZVBB-NEXT: vsext.vf4 v12, v9 +; CHECK-ZVBB-NEXT: vsll.vv v8, v10, v12 +; CHECK-ZVBB-NEXT: ret + %head = insertelement <8 x i8> poison, i8 %b, i32 0 + %splat = shufflevector <8 x i8> %head, <8 x i8> poison, <8 x i32> zeroinitializer + %x = zext <8 x i16> %a to <8 x i32> + %y = sext <8 x i8> %splat to <8 x i32> + %z = shl <8 x i32> %x, %y + ret <8 x i32> %z +} + +define <8 x i32> @vwsll_vx_i8_v8i32_zext(<8 x i16> %a, i8 %b) { +; CHECK-LABEL: vwsll_vx_i8_v8i32_zext: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 8, e8, mf2, ta, ma +; CHECK-NEXT: vmv.v.x v9, a0 +; CHECK-NEXT: vsetvli zero, zero, e32, m2, ta, ma +; CHECK-NEXT: vzext.vf2 v10, v8 +; CHECK-NEXT: vzext.vf4 v12, v9 +; CHECK-NEXT: vsll.vv v8, v10, v12 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vx_i8_v8i32_zext: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 8, e8, mf2, ta, ma +; CHECK-ZVBB-NEXT: vmv.v.x v9, a0 +; CHECK-ZVBB-NEXT: vsetvli zero, zero, e32, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf2 v10, v8 +; CHECK-ZVBB-NEXT: vzext.vf4 v12, v9 +; CHECK-ZVBB-NEXT: vsll.vv v8, v10, v12 +; CHECK-ZVBB-NEXT: ret + %head = insertelement <8 x i8> poison, i8 %b, i32 0 + %splat = shufflevector <8 x i8> %head, <8 x i8> poison, <8 x i32> zeroinitializer + %x = zext <8 x i16> %a to <8 x i32> + %y = zext <8 x i8> %splat to <8 x i32> + %z = shl <8 x i32> %x, %y + ret <8 x i32> %z +} + +define <8 x i32> @vwsll_vi_v8i32(<8 x i16> %a) { +; CHECK-LABEL: vwsll_vi_v8i32: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 8, e32, m2, ta, ma +; CHECK-NEXT: vzext.vf2 v10, v8 +; CHECK-NEXT: vsll.vi v8, v10, 2 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vi_v8i32: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 8, e32, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf2 v10, v8 +; CHECK-ZVBB-NEXT: vsll.vi v8, v10, 2 +; CHECK-ZVBB-NEXT: ret + %x = zext <8 x i16> %a to <8 x i32> + %z = shl <8 x i32> %x, splat (i32 2) + ret <8 x i32> %z +} + +; ============================================================================== +; i8 -> i16 +; ============================================================================== + +define <16 x i16> @vwsll_vv_v16i16_sext(<16 x i8> %a, <16 x i8> %b) { +; CHECK-LABEL: vwsll_vv_v16i16_sext: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 16, e16, m2, ta, ma +; CHECK-NEXT: vzext.vf2 v10, v8 +; CHECK-NEXT: vsext.vf2 v12, v9 +; CHECK-NEXT: vsll.vv v8, v10, v12 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vv_v16i16_sext: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 16, e16, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf2 v10, v8 +; CHECK-ZVBB-NEXT: vsext.vf2 v12, v9 +; CHECK-ZVBB-NEXT: vsll.vv v8, v10, v12 +; CHECK-ZVBB-NEXT: ret + %x = zext <16 x i8> %a to <16 x i16> + %y = sext <16 x i8> %b to <16 x i16> + %z = shl <16 x i16> %x, %y + ret <16 x i16> %z +} + +define <16 x i16> @vwsll_vv_v16i16_zext(<16 x i8> %a, <16 x i8> %b) { +; CHECK-LABEL: vwsll_vv_v16i16_zext: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 16, e16, m2, ta, ma +; CHECK-NEXT: vzext.vf2 v10, v8 +; CHECK-NEXT: vzext.vf2 v12, v9 +; CHECK-NEXT: vsll.vv v8, v10, v12 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vv_v16i16_zext: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 16, e16, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf2 v10, v8 +; CHECK-ZVBB-NEXT: vzext.vf2 v12, v9 +; CHECK-ZVBB-NEXT: vsll.vv v8, v10, v12 +; CHECK-ZVBB-NEXT: ret + %x = zext <16 x i8> %a to <16 x i16> + %y = zext <16 x i8> %b to <16 x i16> + %z = shl <16 x i16> %x, %y + ret <16 x i16> %z +} + +define <16 x i16> @vwsll_vx_i64_v16i16(<16 x i8> %a, i64 %b) { + %head = insertelement <8 x i64> poison, i64 %b, i32 0 + %splat = shufflevector <8 x i64> %head, <8 x i64> poison, <16 x i32> zeroinitializer + %x = zext <16 x i8> %a to <16 x i16> + %y = trunc <16 x i64> %splat to <16 x i16> + %z = shl <16 x i16> %x, %y + ret <16 x i16> %z +} + +define <16 x i16> @vwsll_vx_i32_v16i16(<16 x i8> %a, i32 %b) { +; CHECK-LABEL: vwsll_vx_i32_v16i16: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 16, e32, m4, ta, ma +; CHECK-NEXT: vmv.v.x v12, a0 +; CHECK-NEXT: vsetvli zero, zero, e16, m2, ta, ma +; CHECK-NEXT: vzext.vf2 v10, v8 +; CHECK-NEXT: vnsrl.wi v8, v12, 0 +; CHECK-NEXT: vsll.vv v8, v10, v8 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vx_i32_v16i16: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 16, e32, m4, ta, ma +; CHECK-ZVBB-NEXT: vmv.v.x v12, a0 +; CHECK-ZVBB-NEXT: vsetvli zero, zero, e16, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf2 v10, v8 +; CHECK-ZVBB-NEXT: vnsrl.wi v8, v12, 0 +; CHECK-ZVBB-NEXT: vsll.vv v8, v10, v8 +; CHECK-ZVBB-NEXT: ret + %head = insertelement <16 x i32> poison, i32 %b, i32 0 + %splat = shufflevector <16 x i32> %head, <16 x i32> poison, <16 x i32> zeroinitializer + %x = zext <16 x i8> %a to <16 x i16> + %y = trunc <16 x i32> %splat to <16 x i16> + %z = shl <16 x i16> %x, %y + ret <16 x i16> %z +} + +define <16 x i16> @vwsll_vx_i16_v16i16(<16 x i8> %a, i16 %b) { +; CHECK-LABEL: vwsll_vx_i16_v16i16: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 16, e16, m2, ta, ma +; CHECK-NEXT: vzext.vf2 v10, v8 +; CHECK-NEXT: vsll.vx v8, v10, a0 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vx_i16_v16i16: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 16, e16, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf2 v10, v8 +; CHECK-ZVBB-NEXT: vsll.vx v8, v10, a0 +; CHECK-ZVBB-NEXT: ret + %head = insertelement <16 x i16> poison, i16 %b, i32 0 + %splat = shufflevector <16 x i16> %head, <16 x i16> poison, <16 x i32> zeroinitializer + %x = zext <16 x i8> %a to <16 x i16> + %z = shl <16 x i16> %x, %splat + ret <16 x i16> %z +} + +define <16 x i16> @vwsll_vx_i8_v16i16_sext(<16 x i8> %a, i8 %b) { +; CHECK-LABEL: vwsll_vx_i8_v16i16_sext: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 16, e8, m1, ta, ma +; CHECK-NEXT: vmv.v.x v9, a0 +; CHECK-NEXT: vsetvli zero, zero, e16, m2, ta, ma +; CHECK-NEXT: vzext.vf2 v10, v8 +; CHECK-NEXT: vsext.vf2 v12, v9 +; CHECK-NEXT: vsll.vv v8, v10, v12 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vx_i8_v16i16_sext: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 16, e8, m1, ta, ma +; CHECK-ZVBB-NEXT: vmv.v.x v9, a0 +; CHECK-ZVBB-NEXT: vsetvli zero, zero, e16, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf2 v10, v8 +; CHECK-ZVBB-NEXT: vsext.vf2 v12, v9 +; CHECK-ZVBB-NEXT: vsll.vv v8, v10, v12 +; CHECK-ZVBB-NEXT: ret + %head = insertelement <16 x i8> poison, i8 %b, i32 0 + %splat = shufflevector <16 x i8> %head, <16 x i8> poison, <16 x i32> zeroinitializer + %x = zext <16 x i8> %a to <16 x i16> + %y = sext <16 x i8> %splat to <16 x i16> + %z = shl <16 x i16> %x, %y + ret <16 x i16> %z +} + +define <16 x i16> @vwsll_vx_i8_v16i16_zext(<16 x i8> %a, i8 %b) { +; CHECK-LABEL: vwsll_vx_i8_v16i16_zext: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 16, e8, m1, ta, ma +; CHECK-NEXT: vmv.v.x v9, a0 +; CHECK-NEXT: vsetvli zero, zero, e16, m2, ta, ma +; CHECK-NEXT: vzext.vf2 v10, v8 +; CHECK-NEXT: vzext.vf2 v12, v9 +; CHECK-NEXT: vsll.vv v8, v10, v12 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vx_i8_v16i16_zext: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 16, e8, m1, ta, ma +; CHECK-ZVBB-NEXT: vmv.v.x v9, a0 +; CHECK-ZVBB-NEXT: vsetvli zero, zero, e16, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf2 v10, v8 +; CHECK-ZVBB-NEXT: vzext.vf2 v12, v9 +; CHECK-ZVBB-NEXT: vsll.vv v8, v10, v12 +; CHECK-ZVBB-NEXT: ret + %head = insertelement <16 x i8> poison, i8 %b, i32 0 + %splat = shufflevector <16 x i8> %head, <16 x i8> poison, <16 x i32> zeroinitializer + %x = zext <16 x i8> %a to <16 x i16> + %y = zext <16 x i8> %splat to <16 x i16> + %z = shl <16 x i16> %x, %y + ret <16 x i16> %z +} + +define <16 x i16> @vwsll_vi_v16i16(<16 x i8> %a) { +; CHECK-LABEL: vwsll_vi_v16i16: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 16, e16, m2, ta, ma +; CHECK-NEXT: vzext.vf2 v10, v8 +; CHECK-NEXT: vsll.vi v8, v10, 2 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vi_v16i16: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 16, e16, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf2 v10, v8 +; CHECK-ZVBB-NEXT: vsll.vi v8, v10, 2 +; CHECK-ZVBB-NEXT: ret + %x = zext <16 x i8> %a to <16 x i16> + %z = shl <16 x i16> %x, splat (i16 2) + ret <16 x i16> %z +} + +; ============================================================================== +; i8 -> i64 +; ============================================================================== + +define <4 x i64> @vwsll_vv_v4i64_v4i8_sext(<4 x i8> %a, <4 x i8> %b) { +; CHECK-LABEL: vwsll_vv_v4i64_v4i8_sext: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 4, e64, m2, ta, ma +; CHECK-NEXT: vzext.vf8 v10, v8 +; CHECK-NEXT: vsext.vf8 v12, v9 +; CHECK-NEXT: vsll.vv v8, v10, v12 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vv_v4i64_v4i8_sext: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 4, e64, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf8 v10, v8 +; CHECK-ZVBB-NEXT: vsext.vf8 v12, v9 +; CHECK-ZVBB-NEXT: vsll.vv v8, v10, v12 +; CHECK-ZVBB-NEXT: ret + %x = zext <4 x i8> %a to <4 x i64> + %y = sext <4 x i8> %b to <4 x i64> + %z = shl <4 x i64> %x, %y + ret <4 x i64> %z +} + +define <4 x i64> @vwsll_vv_v4i64_v4i8_zext(<4 x i8> %a, <4 x i8> %b) { +; CHECK-LABEL: vwsll_vv_v4i64_v4i8_zext: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 4, e64, m2, ta, ma +; CHECK-NEXT: vzext.vf8 v10, v8 +; CHECK-NEXT: vzext.vf8 v12, v9 +; CHECK-NEXT: vsll.vv v8, v10, v12 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vv_v4i64_v4i8_zext: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 4, e64, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf8 v10, v8 +; CHECK-ZVBB-NEXT: vzext.vf8 v12, v9 +; CHECK-ZVBB-NEXT: vsll.vv v8, v10, v12 +; CHECK-ZVBB-NEXT: ret + %x = zext <4 x i8> %a to <4 x i64> + %y = zext <4 x i8> %b to <4 x i64> + %z = shl <4 x i64> %x, %y + ret <4 x i64> %z +} + +define <4 x i64> @vwsll_vx_i64_v4i64_v4i8(<4 x i8> %a, i64 %b) { +; CHECK-LABEL: vwsll_vx_i64_v4i64_v4i8: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 4, e64, m2, ta, ma +; CHECK-NEXT: vzext.vf8 v10, v8 +; CHECK-NEXT: vsll.vx v8, v10, a0 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vx_i64_v4i64_v4i8: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 4, e64, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf8 v10, v8 +; CHECK-ZVBB-NEXT: vsll.vx v8, v10, a0 +; CHECK-ZVBB-NEXT: ret + %head = insertelement <4 x i64> poison, i64 %b, i32 0 + %splat = shufflevector <4 x i64> %head, <4 x i64> poison, <4 x i32> zeroinitializer + %x = zext <4 x i8> %a to <4 x i64> + %z = shl <4 x i64> %x, %splat + ret <4 x i64> %z +} + +define <4 x i64> @vwsll_vx_i32_v4i64_v4i8_sext(<4 x i8> %a, i32 %b) { +; CHECK-LABEL: vwsll_vx_i32_v4i64_v4i8_sext: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 4, e32, m1, ta, ma +; CHECK-NEXT: vmv.v.x v9, a0 +; CHECK-NEXT: vsetvli zero, zero, e64, m2, ta, ma +; CHECK-NEXT: vzext.vf8 v10, v8 +; CHECK-NEXT: vsext.vf2 v12, v9 +; CHECK-NEXT: vsll.vv v8, v10, v12 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vx_i32_v4i64_v4i8_sext: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 4, e32, m1, ta, ma +; CHECK-ZVBB-NEXT: vmv.v.x v9, a0 +; CHECK-ZVBB-NEXT: vsetvli zero, zero, e64, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf8 v10, v8 +; CHECK-ZVBB-NEXT: vsext.vf2 v12, v9 +; CHECK-ZVBB-NEXT: vsll.vv v8, v10, v12 +; CHECK-ZVBB-NEXT: ret + %head = insertelement <4 x i32> poison, i32 %b, i32 0 + %splat = shufflevector <4 x i32> %head, <4 x i32> poison, <4 x i32> zeroinitializer + %x = zext <4 x i8> %a to <4 x i64> + %y = sext <4 x i32> %splat to <4 x i64> + %z = shl <4 x i64> %x, %y + ret <4 x i64> %z +} + +define <4 x i64> @vwsll_vx_i32_v4i64_v4i8_zext(<4 x i8> %a, i32 %b) { +; CHECK-LABEL: vwsll_vx_i32_v4i64_v4i8_zext: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 4, e32, m1, ta, ma +; CHECK-NEXT: vmv.v.x v9, a0 +; CHECK-NEXT: vsetvli zero, zero, e64, m2, ta, ma +; CHECK-NEXT: vzext.vf8 v10, v8 +; CHECK-NEXT: vzext.vf2 v12, v9 +; CHECK-NEXT: vsll.vv v8, v10, v12 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vx_i32_v4i64_v4i8_zext: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 4, e32, m1, ta, ma +; CHECK-ZVBB-NEXT: vmv.v.x v9, a0 +; CHECK-ZVBB-NEXT: vsetvli zero, zero, e64, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf8 v10, v8 +; CHECK-ZVBB-NEXT: vzext.vf2 v12, v9 +; CHECK-ZVBB-NEXT: vsll.vv v8, v10, v12 +; CHECK-ZVBB-NEXT: ret + %head = insertelement <4 x i32> poison, i32 %b, i32 0 + %splat = shufflevector <4 x i32> %head, <4 x i32> poison, <4 x i32> zeroinitializer + %x = zext <4 x i8> %a to <4 x i64> + %y = zext <4 x i32> %splat to <4 x i64> + %z = shl <4 x i64> %x, %y + ret <4 x i64> %z +} + +define <4 x i64> @vwsll_vx_i16_v4i64_v4i8_sext(<4 x i8> %a, i16 %b) { +; CHECK-LABEL: vwsll_vx_i16_v4i64_v4i8_sext: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 4, e16, mf2, ta, ma +; CHECK-NEXT: vmv.v.x v9, a0 +; CHECK-NEXT: vsetvli zero, zero, e64, m2, ta, ma +; CHECK-NEXT: vzext.vf8 v10, v8 +; CHECK-NEXT: vsext.vf4 v12, v9 +; CHECK-NEXT: vsll.vv v8, v10, v12 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vx_i16_v4i64_v4i8_sext: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 4, e16, mf2, ta, ma +; CHECK-ZVBB-NEXT: vmv.v.x v9, a0 +; CHECK-ZVBB-NEXT: vsetvli zero, zero, e64, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf8 v10, v8 +; CHECK-ZVBB-NEXT: vsext.vf4 v12, v9 +; CHECK-ZVBB-NEXT: vsll.vv v8, v10, v12 +; CHECK-ZVBB-NEXT: ret + %head = insertelement <4 x i16> poison, i16 %b, i32 0 + %splat = shufflevector <4 x i16> %head, <4 x i16> poison, <4 x i32> zeroinitializer + %x = zext <4 x i8> %a to <4 x i64> + %y = sext <4 x i16> %splat to <4 x i64> + %z = shl <4 x i64> %x, %y + ret <4 x i64> %z +} + +define <4 x i64> @vwsll_vx_i16_v4i64_v4i8_zext(<4 x i8> %a, i16 %b) { +; CHECK-LABEL: vwsll_vx_i16_v4i64_v4i8_zext: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 4, e16, mf2, ta, ma +; CHECK-NEXT: vmv.v.x v9, a0 +; CHECK-NEXT: vsetvli zero, zero, e64, m2, ta, ma +; CHECK-NEXT: vzext.vf8 v10, v8 +; CHECK-NEXT: vzext.vf4 v12, v9 +; CHECK-NEXT: vsll.vv v8, v10, v12 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vx_i16_v4i64_v4i8_zext: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 4, e16, mf2, ta, ma +; CHECK-ZVBB-NEXT: vmv.v.x v9, a0 +; CHECK-ZVBB-NEXT: vsetvli zero, zero, e64, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf8 v10, v8 +; CHECK-ZVBB-NEXT: vzext.vf4 v12, v9 +; CHECK-ZVBB-NEXT: vsll.vv v8, v10, v12 +; CHECK-ZVBB-NEXT: ret + %head = insertelement <4 x i16> poison, i16 %b, i32 0 + %splat = shufflevector <4 x i16> %head, <4 x i16> poison, <4 x i32> zeroinitializer + %x = zext <4 x i8> %a to <4 x i64> + %y = zext <4 x i16> %splat to <4 x i64> + %z = shl <4 x i64> %x, %y + ret <4 x i64> %z +} + +define <4 x i64> @vwsll_vx_i8_v4i64_v4i8_sext(<4 x i8> %a, i8 %b) { +; CHECK-LABEL: vwsll_vx_i8_v4i64_v4i8_sext: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 4, e8, mf4, ta, ma +; CHECK-NEXT: vmv.v.x v9, a0 +; CHECK-NEXT: vsetvli zero, zero, e64, m2, ta, ma +; CHECK-NEXT: vzext.vf8 v10, v8 +; CHECK-NEXT: vsext.vf8 v12, v9 +; CHECK-NEXT: vsll.vv v8, v10, v12 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vx_i8_v4i64_v4i8_sext: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 4, e8, mf4, ta, ma +; CHECK-ZVBB-NEXT: vmv.v.x v9, a0 +; CHECK-ZVBB-NEXT: vsetvli zero, zero, e64, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf8 v10, v8 +; CHECK-ZVBB-NEXT: vsext.vf8 v12, v9 +; CHECK-ZVBB-NEXT: vsll.vv v8, v10, v12 +; CHECK-ZVBB-NEXT: ret + %head = insertelement <4 x i8> poison, i8 %b, i32 0 + %splat = shufflevector <4 x i8> %head, <4 x i8> poison, <4 x i32> zeroinitializer + %x = zext <4 x i8> %a to <4 x i64> + %y = sext <4 x i8> %splat to <4 x i64> + %z = shl <4 x i64> %x, %y + ret <4 x i64> %z +} + +define <4 x i64> @vwsll_vx_i8_v4i64_v4i8_zext(<4 x i8> %a, i8 %b) { +; CHECK-LABEL: vwsll_vx_i8_v4i64_v4i8_zext: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 4, e8, mf4, ta, ma +; CHECK-NEXT: vmv.v.x v9, a0 +; CHECK-NEXT: vsetvli zero, zero, e64, m2, ta, ma +; CHECK-NEXT: vzext.vf8 v10, v8 +; CHECK-NEXT: vzext.vf8 v12, v9 +; CHECK-NEXT: vsll.vv v8, v10, v12 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vx_i8_v4i64_v4i8_zext: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 4, e8, mf4, ta, ma +; CHECK-ZVBB-NEXT: vmv.v.x v9, a0 +; CHECK-ZVBB-NEXT: vsetvli zero, zero, e64, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf8 v10, v8 +; CHECK-ZVBB-NEXT: vzext.vf8 v12, v9 +; CHECK-ZVBB-NEXT: vsll.vv v8, v10, v12 +; CHECK-ZVBB-NEXT: ret + %head = insertelement <4 x i8> poison, i8 %b, i32 0 + %splat = shufflevector <4 x i8> %head, <4 x i8> poison, <4 x i32> zeroinitializer + %x = zext <4 x i8> %a to <4 x i64> + %y = zext <4 x i8> %splat to <4 x i64> + %z = shl <4 x i64> %x, %y + ret <4 x i64> %z +} + +define <4 x i64> @vwsll_vi_v4i64_v4i8(<4 x i8> %a) { +; CHECK-LABEL: vwsll_vi_v4i64_v4i8: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetivli zero, 4, e64, m2, ta, ma +; CHECK-NEXT: vzext.vf8 v10, v8 +; CHECK-NEXT: vsll.vi v8, v10, 2 +; CHECK-NEXT: ret +; +; CHECK-ZVBB-LABEL: vwsll_vi_v4i64_v4i8: +; CHECK-ZVBB: # %bb.0: +; CHECK-ZVBB-NEXT: vsetivli zero, 4, e64, m2, ta, ma +; CHECK-ZVBB-NEXT: vzext.vf8 v10, v8 +; CHECK-ZVBB-NEXT: vsll.vi v8, v10, 2 +; CHECK-ZVBB-NEXT: ret + %x = zext <4 x i8> %a to <4 x i64> + %z = shl <4 x i64> %x, splat (i64 2) + ret <4 x i64> %z +} -- GitLab From 24d528cf4685668d3ad17116846769bed843e933 Mon Sep 17 00:00:00 2001 From: Prabhuk Date: Mon, 1 Apr 2024 23:21:45 -0700 Subject: [PATCH 031/447] [MIPS][CallSiteInfo][NFC] Fill CallSiteInfo only when needed (#86847) Argument-register pairs in CallSiteInfo is only needed when EmitCallSiteInfo is on. Currently, the pairs are always pushed to the vector but only used when EmitCallSiteInfo is on. Don't fill the CallSiteInfo vector unless used. Differential Revision: https://reviews.llvm.org/D107108?id=362887 Co-authored-by: Necip Fazil Yildiran --- llvm/lib/Target/Mips/MipsISelLowering.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/Target/Mips/MipsISelLowering.cpp b/llvm/lib/Target/Mips/MipsISelLowering.cpp index 0a0d40751fcf..1c9c99c6fa94 100644 --- a/llvm/lib/Target/Mips/MipsISelLowering.cpp +++ b/llvm/lib/Target/Mips/MipsISelLowering.cpp @@ -3381,7 +3381,7 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, // Collect CSInfo about which register passes which parameter. const TargetOptions &Options = DAG.getTarget().Options; - if (Options.SupportsDebugEntryValues) + if (Options.EmitCallSiteInfo) CSInfo.emplace_back(VA.getLocReg(), i); continue; -- GitLab From 93c387df908923f17875ab9cf0463d5f181318bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20K=C3=A9ri?= Date: Tue, 2 Apr 2024 08:55:20 +0200 Subject: [PATCH 032/447] [clang][analyzer] Change modeling of `fseek` in StreamChecker. (#86919) Until now function `fseek` returned nonzero on error, this is changed to -1 only. And it does not produce EOF error any more. This complies better with the POSIX standard. --- .../StaticAnalyzer/Checkers/StreamChecker.cpp | 21 +++------ clang/test/Analysis/stream-error.c | 43 ++++++++----------- clang/test/Analysis/stream-note.c | 31 ++++++++++++- 3 files changed, 55 insertions(+), 40 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp index 902c42a2799b..069e3a633c12 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp @@ -1264,15 +1264,10 @@ void StreamChecker::evalFseek(const FnDescription *Desc, const CallEvent &Call, if (!E.Init(Desc, Call, C, State)) return; - const llvm::APSInt *PosV = - C.getSValBuilder().getKnownValue(State, Call.getArgSVal(1)); - const llvm::APSInt *WhenceV = - C.getSValBuilder().getKnownValue(State, Call.getArgSVal(2)); - // Bifurcate the state into failed and non-failed. - // Return zero on success, nonzero on error. - ProgramStateRef StateNotFailed, StateFailed; - std::tie(StateFailed, StateNotFailed) = E.makeRetValAndAssumeDual(State, C); + // Return zero on success, -1 on error. + ProgramStateRef StateNotFailed = E.bindReturnValue(State, C, 0); + ProgramStateRef StateFailed = E.bindReturnValue(State, C, -1); // No failure: Reset the state to opened with no error. StateNotFailed = @@ -1282,12 +1277,10 @@ void StreamChecker::evalFseek(const FnDescription *Desc, const CallEvent &Call, // At error it is possible that fseek fails but sets none of the error flags. // If fseek failed, assume that the file position becomes indeterminate in any // case. - StreamErrorState NewErrS = ErrorNone | ErrorFError; - // Setting the position to start of file never produces EOF error. - if (!(PosV && *PosV == 0 && WhenceV && *WhenceV == SeekSetVal)) - NewErrS = NewErrS | ErrorFEof; - StateFailed = E.setStreamState(StateFailed, - StreamState::getOpened(Desc, NewErrS, true)); + // It is allowed to set the position beyond the end of the file. EOF error + // should not occur. + StateFailed = E.setStreamState( + StateFailed, StreamState::getOpened(Desc, ErrorNone | ErrorFError, true)); C.addTransition(StateFailed, E.getFailureNoteTag(this, C)); } diff --git a/clang/test/Analysis/stream-error.c b/clang/test/Analysis/stream-error.c index 88f7de4234ff..7f9116ff4014 100644 --- a/clang/test/Analysis/stream-error.c +++ b/clang/test/Analysis/stream-error.c @@ -365,27 +365,22 @@ void error_fseek(void) { return; int rc = fseek(F, 1, SEEK_SET); if (rc) { + clang_analyzer_eval(rc == -1); // expected-warning {{TRUE}} int IsFEof = feof(F), IsFError = ferror(F); - // Get feof or ferror or no error. - clang_analyzer_eval(IsFEof || IsFError); - // expected-warning@-1 {{FALSE}} - // expected-warning@-2 {{TRUE}} - clang_analyzer_eval(IsFEof && IsFError); // expected-warning {{FALSE}} + // Get ferror or no error. + clang_analyzer_eval(IsFError); // expected-warning {{FALSE}} \ + // expected-warning {{TRUE}} + clang_analyzer_eval(IsFEof); // expected-warning {{FALSE}} // Error flags should not change. - if (IsFEof) - clang_analyzer_eval(feof(F)); // expected-warning {{TRUE}} - else - clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}} + clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}} if (IsFError) - clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}} - else - clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}} + clang_analyzer_eval(ferror(F)); // expected-warning {{TRUE}} } else { - clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}} - clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}} + clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}} + clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}} // Error flags should not change. - clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}} - clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}} + clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}} + clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}} } fclose(F); } @@ -396,15 +391,13 @@ void error_fseeko(void) { return; int rc = fseeko(F, 1, SEEK_SET); if (rc) { - int IsFEof = feof(F), IsFError = ferror(F); - // Get feof or ferror or no error. - clang_analyzer_eval(IsFEof || IsFError); - // expected-warning@-1 {{FALSE}} - // expected-warning@-2 {{TRUE}} - clang_analyzer_eval(IsFEof && IsFError); // expected-warning {{FALSE}} + // Get ferror or no error. + clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}} \ + // expected-warning {{TRUE}} + clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}} } else { - clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}} - clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}} + clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}} + clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}} } fclose(F); } @@ -414,7 +407,7 @@ void error_fseek_0(void) { if (!F) return; int rc = fseek(F, 0, SEEK_SET); - if (rc) { + if (rc == -1) { int IsFEof = feof(F), IsFError = ferror(F); // Get ferror or no error, but not feof. clang_analyzer_eval(IsFError); diff --git a/clang/test/Analysis/stream-note.c b/clang/test/Analysis/stream-note.c index f77cd4aa6284..54ea699f4667 100644 --- a/clang/test/Analysis/stream-note.c +++ b/clang/test/Analysis/stream-note.c @@ -226,10 +226,39 @@ void check_indeterminate_fseek(void) { return; int Ret = fseek(F, 1, SEEK_SET); // expected-note {{Assuming this stream operation fails}} if (Ret) { // expected-note {{Taking true branch}} \ - // expected-note {{'Ret' is not equal to 0}} + // expected-note {{'Ret' is -1}} char Buf[2]; fwrite(Buf, 1, 2, F); // expected-warning {{might be 'indeterminate'}} \ // expected-note {{might be 'indeterminate'}} } fclose(F); } + +void error_fseek_ftell(void) { + FILE *F = fopen("file", "r"); + if (!F) // expected-note {{Taking false branch}} \ + // expected-note {{'F' is non-null}} + return; + fseek(F, 0, SEEK_END); // expected-note {{Assuming this stream operation fails}} + long size = ftell(F); // expected-warning {{might be 'indeterminate'}} \ + // expected-note {{might be 'indeterminate'}} + if (size == -1) { + fclose(F); + return; + } + if (size == 1) + fprintf(F, "abcd"); + fclose(F); +} + +void error_fseek_read_eof(void) { + FILE *F = fopen("file", "r"); + if (!F) + return; + if (fseek(F, 22, SEEK_SET) == -1) { + fclose(F); + return; + } + fgetc(F); // no warning + fclose(F); +} -- GitLab From 8bb9443333e0117ab61feecce9de339b11b924fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorsten=20Sch=C3=BCtt?= Date: Tue, 2 Apr 2024 09:01:24 +0200 Subject: [PATCH 033/447] [GlobalIsel] Combine G_EXTRACT_VECTOR_ELT (#85321) preliminary steps --- .../llvm/CodeGen/GlobalISel/CombinerHelper.h | 25 ++ .../CodeGen/GlobalISel/GenericMachineInstrs.h | 41 +++ .../include/llvm/Target/GlobalISel/Combine.td | 230 +++++++++++- llvm/lib/CodeGen/GlobalISel/CMakeLists.txt | 1 + .../lib/CodeGen/GlobalISel/CombinerHelper.cpp | 8 + .../GlobalISel/CombinerHelperVectorOps.cpp | 326 ++++++++++++++++++ .../GlobalISel/combine-extract-vec-elt.mir | 299 +++++++++++++++- .../CodeGen/AArch64/extract-vector-elt.ll | 18 +- .../AArch64/extractvector-oob-load.mir | 7 +- 9 files changed, 930 insertions(+), 25 deletions(-) create mode 100644 llvm/lib/CodeGen/GlobalISel/CombinerHelperVectorOps.cpp diff --git a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h index 28d9cf6260d6..3af32043391f 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h @@ -594,6 +594,10 @@ public: /// This variant does not erase \p MI after calling the build function. void applyBuildFnNoErase(MachineInstr &MI, BuildFnTy &MatchInfo); + /// Use a function which takes in a MachineIRBuilder to perform a combine. + /// By default, it erases the instruction \p MI from the function. + void applyBuildFnMO(const MachineOperand &MO, BuildFnTy &MatchInfo); + bool matchOrShiftToFunnelShift(MachineInstr &MI, BuildFnTy &MatchInfo); bool matchFunnelShiftToRotate(MachineInstr &MI); void applyFunnelShiftToRotate(MachineInstr &MI); @@ -823,6 +827,27 @@ public: /// Combine addos. bool matchAddOverflow(MachineInstr &MI, BuildFnTy &MatchInfo); + /// Combine extract vector element. + bool matchExtractVectorElement(MachineInstr &MI, BuildFnTy &MatchInfo); + + /// Combine extract vector element with freeze on the vector register. + bool matchExtractVectorElementWithFreeze(const MachineOperand &MO, + BuildFnTy &MatchInfo); + + /// Combine extract vector element with a build vector on the vector register. + bool matchExtractVectorElementWithBuildVector(const MachineOperand &MO, + BuildFnTy &MatchInfo); + + /// Combine extract vector element with a build vector trunc on the vector + /// register. + bool matchExtractVectorElementWithBuildVectorTrunc(const MachineOperand &MO, + BuildFnTy &MatchInfo); + + /// Combine extract vector element with a insert vector element on the vector + /// register and different indices. + bool matchExtractVectorElementWithDifferentIndices(const MachineOperand &MO, + BuildFnTy &MatchInfo); + private: /// Checks for legality of an indexed variant of \p LdSt. bool isIndexedLoadStoreLegal(GLoadStore &LdSt) const; diff --git a/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h b/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h index 261cfcf504d5..25e47114e4a3 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h @@ -286,6 +286,14 @@ public: } }; +/// Represents a G_BUILD_VECTOR_TRUNC. +class GBuildVectorTrunc : public GMergeLikeInstr { +public: + static bool classof(const MachineInstr *MI) { + return MI->getOpcode() == TargetOpcode::G_BUILD_VECTOR_TRUNC; + } +}; + /// Represents a G_PTR_ADD. class GPtrAdd : public GenericMachineInstr { public: @@ -739,6 +747,39 @@ public: }; }; +/// Represents an extract vector element. +class GExtractVectorElement : public GenericMachineInstr { +public: + Register getVectorReg() const { return getOperand(1).getReg(); } + Register getIndexReg() const { return getOperand(2).getReg(); } + + static bool classof(const MachineInstr *MI) { + return MI->getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT; + } +}; + +/// Represents an insert vector element. +class GInsertVectorElement : public GenericMachineInstr { +public: + Register getVectorReg() const { return getOperand(1).getReg(); } + Register getElementReg() const { return getOperand(2).getReg(); } + Register getIndexReg() const { return getOperand(3).getReg(); } + + static bool classof(const MachineInstr *MI) { + return MI->getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT; + } +}; + +/// Represents a freeze. +class GFreeze : public GenericMachineInstr { +public: + Register getSourceReg() const { return getOperand(1).getReg(); } + + static bool classof(const MachineInstr *MI) { + return MI->getOpcode() == TargetOpcode::G_FREEZE; + } +}; + } // namespace llvm #endif // LLVM_CODEGEN_GLOBALISEL_GENERICMACHINEINSTRS_H diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td index 72d3c0ea69bc..778ff7e437eb 100644 --- a/llvm/include/llvm/Target/GlobalISel/Combine.td +++ b/llvm/include/llvm/Target/GlobalISel/Combine.td @@ -1305,6 +1305,200 @@ def match_addos : GICombineRule< [{ return Helper.matchAddOverflow(*${root}, ${matchinfo}); }]), (apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>; +def match_extract_of_element_undef_vector: GICombineRule < + (defs root:$root), + (match (G_IMPLICIT_DEF $vector), + (G_EXTRACT_VECTOR_ELT $root, $vector, $idx)), + (apply (G_IMPLICIT_DEF $root)) +>; + +def match_extract_of_element_undef_index: GICombineRule < + (defs root:$root), + (match (G_IMPLICIT_DEF $idx), + (G_EXTRACT_VECTOR_ELT $root, $vector, $idx)), + (apply (G_IMPLICIT_DEF $root)) +>; + +def match_extract_of_element : GICombineRule< + (defs root:$root, build_fn_matchinfo:$matchinfo), + (match (wip_match_opcode G_EXTRACT_VECTOR_ELT):$root, + [{ return Helper.matchExtractVectorElement(*${root}, ${matchinfo}); }]), + (apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>; + +def extract_vector_element_not_const : GICombineRule< + (defs root:$root, build_fn_matchinfo:$matchinfo), + (match (G_INSERT_VECTOR_ELT $src, $x, $value, $idx), + (G_EXTRACT_VECTOR_ELT $root, $src, $idx)), + (apply (GIReplaceReg $root, $value))>; + +def extract_vector_element_different_indices : GICombineRule< + (defs root:$root, build_fn_matchinfo:$matchinfo), + (match (G_INSERT_VECTOR_ELT $src, $x, $value, $idx2), + (G_EXTRACT_VECTOR_ELT $root, $src, $idx1), + [{ return Helper.matchExtractVectorElementWithDifferentIndices(${root}, ${matchinfo}); }]), + (apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>; + +def extract_vector_element_build_vector2 : GICombineRule< + (defs root:$root, build_fn_matchinfo:$matchinfo), + (match (G_BUILD_VECTOR $src, $x, $y), + (G_EXTRACT_VECTOR_ELT $root, $src, $idx), + [{ return Helper.matchExtractVectorElementWithBuildVector(${root}, ${matchinfo}); }]), + (apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>; + +def extract_vector_element_build_vector3 : GICombineRule< + (defs root:$root, build_fn_matchinfo:$matchinfo), + (match (G_BUILD_VECTOR $src, $x, $y, $z), + (G_EXTRACT_VECTOR_ELT $root, $src, $idx), + [{ return Helper.matchExtractVectorElementWithBuildVector(${root}, ${matchinfo}); }]), + (apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>; + +def extract_vector_element_build_vector4 : GICombineRule< + (defs root:$root, build_fn_matchinfo:$matchinfo), + (match (G_BUILD_VECTOR $src, $x, $y, $z, $a), + (G_EXTRACT_VECTOR_ELT $root, $src, $idx), + [{ return Helper.matchExtractVectorElementWithBuildVector(${root}, ${matchinfo}); }]), + (apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>; + +def extract_vector_element_build_vector5 : GICombineRule< + (defs root:$root, build_fn_matchinfo:$matchinfo), + (match (G_BUILD_VECTOR $src, $x, $y, $z, $a, $b), + (G_EXTRACT_VECTOR_ELT $root, $src, $idx), + [{ return Helper.matchExtractVectorElementWithBuildVector(${root}, ${matchinfo}); }]), + (apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>; + +def extract_vector_element_build_vector6 : GICombineRule< + (defs root:$root, build_fn_matchinfo:$matchinfo), + (match (G_BUILD_VECTOR $src, $x, $y, $z, $a, $b, $c), + (G_EXTRACT_VECTOR_ELT $root, $src, $idx), + [{ return Helper.matchExtractVectorElementWithBuildVector(${root}, ${matchinfo}); }]), + (apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>; + +def extract_vector_element_build_vector7 : GICombineRule< + (defs root:$root, build_fn_matchinfo:$matchinfo), + (match (G_BUILD_VECTOR $src, $x, $y, $z, $a, $b, $c, $d), + (G_EXTRACT_VECTOR_ELT $root, $src, $idx), + [{ return Helper.matchExtractVectorElementWithBuildVector(${root}, ${matchinfo}); }]), + (apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>; + +def extract_vector_element_build_vector8 : GICombineRule< + (defs root:$root, build_fn_matchinfo:$matchinfo), + (match (G_BUILD_VECTOR $src, $x, $y, $z, $a, $b, $c, $d, $e), + (G_EXTRACT_VECTOR_ELT $root, $src, $idx), + [{ return Helper.matchExtractVectorElementWithBuildVector(${root}, ${matchinfo}); }]), + (apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>; + +def extract_vector_element_build_vector9 : GICombineRule< + (defs root:$root, build_fn_matchinfo:$matchinfo), + (match (G_BUILD_VECTOR $src, $x, $y, $z, $a, $b, $c, $d, $e, $f), + (G_EXTRACT_VECTOR_ELT $root, $src, $idx), + [{ return Helper.matchExtractVectorElementWithBuildVector(${root}, ${matchinfo}); }]), + (apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>; + +def extract_vector_element_build_vector10 : GICombineRule< + (defs root:$root, build_fn_matchinfo:$matchinfo), + (match (G_BUILD_VECTOR $src, $x, $y, $z, $a, $b, $c, $d, $e, $f, $g), + (G_EXTRACT_VECTOR_ELT $root, $src, $idx), + [{ return Helper.matchExtractVectorElementWithBuildVector(${root}, ${matchinfo}); }]), + (apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>; + +def extract_vector_element_build_vector11 : GICombineRule< + (defs root:$root, build_fn_matchinfo:$matchinfo), + (match (G_BUILD_VECTOR $src, $x, $y, $z, $a, $b, $c, $d, $e, $f, $g, $h), + (G_EXTRACT_VECTOR_ELT $root, $src, $idx), + [{ return Helper.matchExtractVectorElementWithBuildVector(${root}, ${matchinfo}); }]), + (apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>; + +def extract_vector_element_build_vector12 : GICombineRule< + (defs root:$root, build_fn_matchinfo:$matchinfo), + (match (G_BUILD_VECTOR $src, $x, $y, $z, $a, $b, $c, $d, $e, $f, $g, $h, $i), + (G_EXTRACT_VECTOR_ELT $root, $src, $idx), + [{ return Helper.matchExtractVectorElementWithBuildVector(${root}, ${matchinfo}); }]), + (apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>; + +def extract_vector_element_build_vector13 : GICombineRule< + (defs root:$root, build_fn_matchinfo:$matchinfo), + (match (G_BUILD_VECTOR $src, $x, $y, $z, $a, $b, $c, $d, $e, $f, $g, $h, $i, $j), + (G_EXTRACT_VECTOR_ELT $root, $src, $idx), + [{ return Helper.matchExtractVectorElementWithBuildVector(${root}, ${matchinfo}); }]), + (apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>; + +def extract_vector_element_build_vector14 : GICombineRule< + (defs root:$root, build_fn_matchinfo:$matchinfo), + (match (G_BUILD_VECTOR $src, $x, $y, $z, $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k), + (G_EXTRACT_VECTOR_ELT $root, $src, $idx), + [{ return Helper.matchExtractVectorElementWithBuildVector(${root}, ${matchinfo}); }]), + (apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>; + +def extract_vector_element_build_vector15 : GICombineRule< + (defs root:$root, build_fn_matchinfo:$matchinfo), + (match (G_BUILD_VECTOR $src, $x, $y, $z, $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l), + (G_EXTRACT_VECTOR_ELT $root, $src, $idx), + [{ return Helper.matchExtractVectorElementWithBuildVector(${root}, ${matchinfo}); }]), + (apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>; + +def extract_vector_element_build_vector16 : GICombineRule< + (defs root:$root, build_fn_matchinfo:$matchinfo), + (match (G_BUILD_VECTOR $src, $x, $y, $z, $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m), + (G_EXTRACT_VECTOR_ELT $root, $src, $idx), + [{ return Helper.matchExtractVectorElementWithBuildVector(${root}, ${matchinfo}); }]), + (apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>; + +def extract_vector_element_build_vector_trunc2 : GICombineRule< + (defs root:$root, build_fn_matchinfo:$matchinfo), + (match (G_BUILD_VECTOR_TRUNC $src, $x, $y), + (G_EXTRACT_VECTOR_ELT $root, $src, $idx), + [{ return Helper.matchExtractVectorElementWithBuildVectorTrunc(${root}, ${matchinfo}); }]), + (apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>; + +def extract_vector_element_build_vector_trunc3 : GICombineRule< + (defs root:$root, build_fn_matchinfo:$matchinfo), + (match (G_BUILD_VECTOR_TRUNC $src, $x, $y, $z), + (G_EXTRACT_VECTOR_ELT $root, $src, $idx), + [{ return Helper.matchExtractVectorElementWithBuildVectorTrunc(${root}, ${matchinfo}); }]), + (apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>; + +def extract_vector_element_build_vector_trunc4 : GICombineRule< + (defs root:$root, build_fn_matchinfo:$matchinfo), + (match (G_BUILD_VECTOR_TRUNC $src, $x, $y, $z, $a), + (G_EXTRACT_VECTOR_ELT $root, $src, $idx), + [{ return Helper.matchExtractVectorElementWithBuildVectorTrunc(${root}, ${matchinfo}); }]), + (apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>; + +def extract_vector_element_build_vector_trunc5 : GICombineRule< + (defs root:$root, build_fn_matchinfo:$matchinfo), + (match (G_BUILD_VECTOR_TRUNC $src, $x, $y, $z, $a, $b), + (G_EXTRACT_VECTOR_ELT $root, $src, $idx), + [{ return Helper.matchExtractVectorElementWithBuildVectorTrunc(${root}, ${matchinfo}); }]), + (apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>; + +def extract_vector_element_build_vector_trunc6 : GICombineRule< + (defs root:$root, build_fn_matchinfo:$matchinfo), + (match (G_BUILD_VECTOR_TRUNC $src, $x, $y, $z, $a, $b, $c), + (G_EXTRACT_VECTOR_ELT $root, $src, $idx), + [{ return Helper.matchExtractVectorElementWithBuildVectorTrunc(${root}, ${matchinfo}); }]), + (apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>; + +def extract_vector_element_build_vector_trunc7 : GICombineRule< + (defs root:$root, build_fn_matchinfo:$matchinfo), + (match (G_BUILD_VECTOR_TRUNC $src, $x, $y, $z, $a, $b, $c, $d), + (G_EXTRACT_VECTOR_ELT $root, $src, $idx), + [{ return Helper.matchExtractVectorElementWithBuildVectorTrunc(${root}, ${matchinfo}); }]), + (apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>; + +def extract_vector_element_build_vector_trunc8 : GICombineRule< + (defs root:$root, build_fn_matchinfo:$matchinfo), + (match (G_BUILD_VECTOR_TRUNC $src, $x, $y, $z, $a, $b, $c, $d, $e), + (G_EXTRACT_VECTOR_ELT $root, $src, $idx), + [{ return Helper.matchExtractVectorElementWithBuildVectorTrunc(${root}, ${matchinfo}); }]), + (apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>; + +def extract_vector_element_freeze : GICombineRule< + (defs root:$root, build_fn_matchinfo:$matchinfo), + (match (G_FREEZE $src, $input), + (G_EXTRACT_VECTOR_ELT $root, $src, $idx), + [{ return Helper.matchExtractVectorElementWithFreeze(${root}, ${matchinfo}); }]), + (apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>; + // Combines concat operations def concat_matchinfo : GIDefMatchData<"SmallVector">; def combine_concat_vector : GICombineRule< @@ -1313,6 +1507,37 @@ def combine_concat_vector : GICombineRule< [{ return Helper.matchCombineConcatVectors(*${root}, ${matchinfo}); }]), (apply [{ Helper.applyCombineConcatVectors(*${root}, ${matchinfo}); }])>; +// match_extract_of_element must be the first! +def vector_ops_combines: GICombineGroup<[ +match_extract_of_element_undef_vector, +match_extract_of_element_undef_index, +match_extract_of_element, +extract_vector_element_not_const, +extract_vector_element_different_indices, +extract_vector_element_build_vector2, +extract_vector_element_build_vector3, +extract_vector_element_build_vector4, +extract_vector_element_build_vector5, +extract_vector_element_build_vector7, +extract_vector_element_build_vector8, +extract_vector_element_build_vector9, +extract_vector_element_build_vector10, +extract_vector_element_build_vector11, +extract_vector_element_build_vector12, +extract_vector_element_build_vector13, +extract_vector_element_build_vector14, +extract_vector_element_build_vector15, +extract_vector_element_build_vector16, +extract_vector_element_build_vector_trunc2, +extract_vector_element_build_vector_trunc3, +extract_vector_element_build_vector_trunc4, +extract_vector_element_build_vector_trunc5, +extract_vector_element_build_vector_trunc6, +extract_vector_element_build_vector_trunc7, +extract_vector_element_build_vector_trunc8, +extract_vector_element_freeze +]>; + // FIXME: These should use the custom predicate feature once it lands. def undef_combines : GICombineGroup<[undef_to_fp_zero, undef_to_int_zero, undef_to_negative_one, @@ -1368,8 +1593,9 @@ def fma_combines : GICombineGroup<[combine_fadd_fmul_to_fmad_or_fma, def constant_fold_binops : GICombineGroup<[constant_fold_binop, constant_fold_fp_binop]>; -def all_combines : GICombineGroup<[trivial_combines, insert_vec_elt_combines, - extract_vec_elt_combines, combines_for_extload, combine_extracted_vector_load, +def all_combines : GICombineGroup<[trivial_combines, vector_ops_combines, + insert_vec_elt_combines, extract_vec_elt_combines, combines_for_extload, + combine_extracted_vector_load, undef_combines, identity_combines, phi_combines, simplify_add_to_sub, hoist_logic_op_with_same_opcode_hands, shifts_too_big, reassocs, ptr_add_immed_chain, diff --git a/llvm/lib/CodeGen/GlobalISel/CMakeLists.txt b/llvm/lib/CodeGen/GlobalISel/CMakeLists.txt index 46e6c6df5998..54ac7f72011a 100644 --- a/llvm/lib/CodeGen/GlobalISel/CMakeLists.txt +++ b/llvm/lib/CodeGen/GlobalISel/CMakeLists.txt @@ -6,6 +6,7 @@ add_llvm_component_library(LLVMGlobalISel GlobalISel.cpp Combiner.cpp CombinerHelper.cpp + CombinerHelperVectorOps.cpp GIMatchTableExecutor.cpp GISelChangeObserver.cpp IRTranslator.cpp diff --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp index 98e7c73a801f..5cf7a33a5f67 100644 --- a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp @@ -4058,6 +4058,14 @@ void CombinerHelper::applyBuildFn( MI.eraseFromParent(); } +void CombinerHelper::applyBuildFnMO(const MachineOperand &MO, + BuildFnTy &MatchInfo) { + MachineInstr *Root = getDefIgnoringCopies(MO.getReg(), MRI); + Builder.setInstrAndDebugLoc(*Root); + MatchInfo(Builder); + Root->eraseFromParent(); +} + void CombinerHelper::applyBuildFnNoErase( MachineInstr &MI, std::function &MatchInfo) { MatchInfo(Builder); diff --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelperVectorOps.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelperVectorOps.cpp new file mode 100644 index 000000000000..123bf21f657c --- /dev/null +++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelperVectorOps.cpp @@ -0,0 +1,326 @@ +//===- CombinerHelperVectorOps.cpp-----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements CombinerHelper for G_EXTRACT_VECTOR_ELT. +// +//===----------------------------------------------------------------------===// +#include "llvm/CodeGen/GlobalISel/CombinerHelper.h" +#include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h" +#include "llvm/CodeGen/GlobalISel/LegalizerHelper.h" +#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h" +#include "llvm/CodeGen/GlobalISel/MIPatternMatch.h" +#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" +#include "llvm/CodeGen/GlobalISel/Utils.h" +#include "llvm/CodeGen/LowLevelTypeUtils.h" +#include "llvm/CodeGen/MachineOperand.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/TargetLowering.h" +#include "llvm/CodeGen/TargetOpcodes.h" +#include "llvm/Support/Casting.h" +#include + +#define DEBUG_TYPE "gi-combiner" + +using namespace llvm; +using namespace MIPatternMatch; + +bool CombinerHelper::matchExtractVectorElement(MachineInstr &MI, + BuildFnTy &MatchInfo) { + GExtractVectorElement *Extract = cast(&MI); + + Register Dst = Extract->getReg(0); + Register Vector = Extract->getVectorReg(); + Register Index = Extract->getIndexReg(); + LLT DstTy = MRI.getType(Dst); + LLT VectorTy = MRI.getType(Vector); + + // The vector register can be def'd by various ops that have vector as its + // type. They can all be used for constant folding, scalarizing, + // canonicalization, or combining based on symmetry. + // + // vector like ops + // * build vector + // * build vector trunc + // * shuffle vector + // * splat vector + // * concat vectors + // * insert/extract vector element + // * insert/extract subvector + // * vector loads + // * scalable vector loads + // + // compute like ops + // * binary ops + // * unary ops + // * exts and truncs + // * casts + // * fneg + // * select + // * phis + // * cmps + // * freeze + // * bitcast + // * undef + + // We try to get the value of the Index register. + std::optional MaybeIndex = + getIConstantVRegValWithLookThrough(Index, MRI); + std::optional IndexC = std::nullopt; + + if (MaybeIndex) + IndexC = MaybeIndex->Value; + + // Fold extractVectorElement(Vector, TOOLARGE) -> undef + if (IndexC && VectorTy.isFixedVector() && + IndexC->getZExtValue() >= VectorTy.getNumElements() && + isLegalOrBeforeLegalizer({TargetOpcode::G_IMPLICIT_DEF, {DstTy}})) { + // For fixed-length vectors, it's invalid to extract out-of-range elements. + MatchInfo = [=](MachineIRBuilder &B) { B.buildUndef(Dst); }; + return true; + } + + return false; +} + +bool CombinerHelper::matchExtractVectorElementWithDifferentIndices( + const MachineOperand &MO, BuildFnTy &MatchInfo) { + MachineInstr *Root = getDefIgnoringCopies(MO.getReg(), MRI); + GExtractVectorElement *Extract = cast(Root); + + // + // %idx1:_(s64) = G_CONSTANT i64 1 + // %idx2:_(s64) = G_CONSTANT i64 2 + // %insert:_(<2 x s32>) = G_INSERT_VECTOR_ELT_ELT %bv(<2 x s32>), + // %value(s32), %idx2(s64) %extract:_(s32) = G_EXTRACT_VECTOR_ELT %insert(<2 + // x s32>), %idx1(s64) + // + // --> + // + // %insert:_(<2 x s32>) = G_INSERT_VECTOR_ELT_ELT %bv(<2 x s32>), + // %value(s32), %idx2(s64) %extract:_(s32) = G_EXTRACT_VECTOR_ELT %bv(<2 x + // s32>), %idx1(s64) + // + // + + Register Index = Extract->getIndexReg(); + + // We try to get the value of the Index register. + std::optional MaybeIndex = + getIConstantVRegValWithLookThrough(Index, MRI); + std::optional IndexC = std::nullopt; + + if (!MaybeIndex) + return false; + else + IndexC = MaybeIndex->Value; + + Register Vector = Extract->getVectorReg(); + + GInsertVectorElement *Insert = + getOpcodeDef(Vector, MRI); + if (!Insert) + return false; + + Register Dst = Extract->getReg(0); + + std::optional MaybeInsertIndex = + getIConstantVRegValWithLookThrough(Insert->getIndexReg(), MRI); + + if (MaybeInsertIndex && MaybeInsertIndex->Value != *IndexC) { + // There is no one-use check. We have to keep the insert. When both Index + // registers are constants and not equal, we can look into the Vector + // register of the insert. + MatchInfo = [=](MachineIRBuilder &B) { + B.buildExtractVectorElement(Dst, Insert->getVectorReg(), Index); + }; + return true; + } + + return false; +} + +bool CombinerHelper::matchExtractVectorElementWithFreeze( + const MachineOperand &MO, BuildFnTy &MatchInfo) { + MachineInstr *Root = getDefIgnoringCopies(MO.getReg(), MRI); + GExtractVectorElement *Extract = cast(Root); + + Register Vector = Extract->getVectorReg(); + + // + // %bv:_(<2 x s32>) = G_BUILD_VECTOR %arg1(s32), %arg2(s32) + // %freeze:_(<2 x s32>) = G_FREEZE %bv(<2 x s32>) + // %extract:_(s32) = G_EXTRACT_VECTOR_ELT %bv(<2 x s32>), %opaque(s64) + // + // --> + // + // %bv:_(<2 x s32>) = G_BUILD_VECTOR %arg1(s32), %arg2(s32) + // %extract:_(s32) = G_EXTRACT_VECTOR_ELT %bv(<2 x s32>), %opaque(s64) + // %freeze:_(s32) = G_FREEZE %extract(s32) + // + // + + // For G_FREEZE, the input and the output types are identical. Moving the + // freeze from the Vector into the front of the extract preserves the freeze + // semantics. The result is still freeze'd. Furthermore, the Vector register + // becomes easier to analyze. A build vector could have been hidden behind the + // freeze. + + // We expect a freeze on the Vector register. + GFreeze *Freeze = getOpcodeDef(Vector, MRI); + if (!Freeze) + return false; + + Register Dst = Extract->getReg(0); + LLT DstTy = MRI.getType(Dst); + + // We first have to check for one-use and legality of the freeze. + // The type of the extractVectorElement did not change. + if (!MRI.hasOneNonDBGUse(Freeze->getReg(0)) || + !isLegalOrBeforeLegalizer({TargetOpcode::G_FREEZE, {DstTy}})) + return false; + + Register Index = Extract->getIndexReg(); + + // We move the freeze from the Vector register in front of the + // extractVectorElement. + MatchInfo = [=](MachineIRBuilder &B) { + auto Extract = + B.buildExtractVectorElement(DstTy, Freeze->getSourceReg(), Index); + B.buildFreeze(Dst, Extract); + }; + + return true; +} + +bool CombinerHelper::matchExtractVectorElementWithBuildVector( + const MachineOperand &MO, BuildFnTy &MatchInfo) { + MachineInstr *Root = getDefIgnoringCopies(MO.getReg(), MRI); + GExtractVectorElement *Extract = cast(Root); + + // + // %zero:_(s64) = G_CONSTANT i64 0 + // %bv:_(<2 x s32>) = G_BUILD_VECTOR %arg1(s32), %arg2(s32) + // %extract:_(s32) = G_EXTRACT_VECTOR_ELT %bv(<2 x s32>), %zero(s64) + // + // --> + // + // %extract:_(32) = COPY %arg1(s32) + // + // + // + // %bv:_(<2 x s32>) = G_BUILD_VECTOR %arg1(s32), %arg2(s32) + // %extract:_(s32) = G_EXTRACT_VECTOR_ELT %bv(<2 x s32>), %opaque(s64) + // + // --> + // + // %bv:_(<2 x s32>) = G_BUILD_VECTOR %arg1(s32), %arg2(s32) + // %extract:_(s32) = G_EXTRACT_VECTOR_ELT %bv(<2 x s32>), %opaque(s64) + // + + Register Vector = Extract->getVectorReg(); + + // We expect a buildVector on the Vector register. + GBuildVector *Build = getOpcodeDef(Vector, MRI); + if (!Build) + return false; + + LLT VectorTy = MRI.getType(Vector); + + // There is a one-use check. There are more combines on build vectors. + EVT Ty(getMVTForLLT(VectorTy)); + if (!MRI.hasOneNonDBGUse(Build->getReg(0)) || + !getTargetLowering().aggressivelyPreferBuildVectorSources(Ty)) + return false; + + Register Index = Extract->getIndexReg(); + + // If the Index is constant, then we can extract the element from the given + // offset. + std::optional MaybeIndex = + getIConstantVRegValWithLookThrough(Index, MRI); + if (!MaybeIndex) + return false; + + // We now know that there is a buildVector def'd on the Vector register and + // the index is const. The combine will succeed. + + Register Dst = Extract->getReg(0); + + MatchInfo = [=](MachineIRBuilder &B) { + B.buildCopy(Dst, Build->getSourceReg(MaybeIndex->Value.getZExtValue())); + }; + + return true; +} + +bool CombinerHelper::matchExtractVectorElementWithBuildVectorTrunc( + const MachineOperand &MO, BuildFnTy &MatchInfo) { + MachineInstr *Root = getDefIgnoringCopies(MO.getReg(), MRI); + GExtractVectorElement *Extract = cast(Root); + + // + // %zero:_(s64) = G_CONSTANT i64 0 + // %bv:_(<2 x s32>) = G_BUILD_VECTOR_TRUNC %arg1(s64), %arg2(s64) + // %extract:_(s32) = G_EXTRACT_VECTOR_ELT %bv(<2 x s32>), %zero(s64) + // + // --> + // + // %extract:_(32) = G_TRUNC %arg1(s64) + // + // + // + // %bv:_(<2 x s32>) = G_BUILD_VECTOR_TRUNC %arg1(s64), %arg2(s64) + // %extract:_(s32) = G_EXTRACT_VECTOR_ELT %bv(<2 x s32>), %opaque(s64) + // + // --> + // + // %bv:_(<2 x s32>) = G_BUILD_VECTOR_TRUNC %arg1(s64), %arg2(s64) + // %extract:_(s32) = G_EXTRACT_VECTOR_ELT %bv(<2 x s32>), %opaque(s64) + // + + Register Vector = Extract->getVectorReg(); + + // We expect a buildVectorTrunc on the Vector register. + GBuildVectorTrunc *Build = getOpcodeDef(Vector, MRI); + if (!Build) + return false; + + LLT VectorTy = MRI.getType(Vector); + + // There is a one-use check. There are more combines on build vectors. + EVT Ty(getMVTForLLT(VectorTy)); + if (!MRI.hasOneNonDBGUse(Build->getReg(0)) || + !getTargetLowering().aggressivelyPreferBuildVectorSources(Ty)) + return false; + + Register Index = Extract->getIndexReg(); + + // If the Index is constant, then we can extract the element from the given + // offset. + std::optional MaybeIndex = + getIConstantVRegValWithLookThrough(Index, MRI); + if (!MaybeIndex) + return false; + + // We now know that there is a buildVectorTrunc def'd on the Vector register + // and the index is const. The combine will succeed. + + Register Dst = Extract->getReg(0); + LLT DstTy = MRI.getType(Dst); + LLT SrcTy = MRI.getType(Build->getSourceReg(0)); + + // For buildVectorTrunc, the inputs are truncated. + if (!isLegalOrBeforeLegalizer({TargetOpcode::G_TRUNC, {DstTy, SrcTy}})) + return false; + + MatchInfo = [=](MachineIRBuilder &B) { + B.buildTrunc(Dst, Build->getSourceReg(MaybeIndex->Value.getZExtValue())); + }; + + return true; +} diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-extract-vec-elt.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-extract-vec-elt.mir index a2116ccc7671..c2a38e26676c 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-extract-vec-elt.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-extract-vec-elt.mir @@ -192,8 +192,8 @@ body: | ... --- +# This test checks that this combine runs after the insertvec->build_vector name: extract_from_insert -alignment: 4 tracksRegLiveness: true liveins: - { reg: '$x0' } @@ -203,8 +203,6 @@ frameInfo: body: | bb.1: liveins: $x0, $x1 - ; This test checks that this combine runs after the insertvec->build_vector - ; combine. ; CHECK-LABEL: name: extract_from_insert ; CHECK: liveins: $x0, $x1 ; CHECK-NEXT: {{ $}} @@ -247,3 +245,298 @@ body: | RET_ReallyLR implicit $x0 ... +--- +name: extract_from_vector_undef +alignment: 4 +liveins: + - { reg: '$x0' } + - { reg: '$x1' } +frameInfo: + maxAlignment: 1 +body: | + bb.1: + liveins: $x0, $x1 + ; CHECK-LABEL: name: extract_from_vector_undef + ; CHECK: liveins: $x0, $x1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %extract:_(s64) = G_IMPLICIT_DEF + ; CHECK-NEXT: $x0 = COPY %extract(s64) + ; CHECK-NEXT: RET_ReallyLR implicit $x0 + %vec:_(<2 x s64>) = G_IMPLICIT_DEF + %idx:_(s32) = G_CONSTANT i32 -2 + %extract:_(s64) = G_EXTRACT_VECTOR_ELT %vec(<2 x s64>), %idx(s32) + $x0 = COPY %extract(s64) + RET_ReallyLR implicit $x0 + +... +--- +name: extract_from_index_undef +alignment: 4 +liveins: + - { reg: '$x0' } + - { reg: '$x1' } +frameInfo: + maxAlignment: 1 +body: | + bb.1: + ; CHECK-LABEL: name: extract_from_index_undef + ; CHECK: %extract:_(s64) = G_IMPLICIT_DEF + ; CHECK-NEXT: $x0 = COPY %extract(s64) + ; CHECK-NEXT: RET_ReallyLR implicit $x0 + %vec:_(<2 x s64>) = COPY $q0 + %idx:_(s32) = G_IMPLICIT_DEF + %extract:_(s64) = G_EXTRACT_VECTOR_ELT %vec(<2 x s64>), %idx(s32) + $x0 = COPY %extract(s64) + RET_ReallyLR implicit $x0 + +... +--- +name: extract_from_index_too_large +alignment: 4 +liveins: + - { reg: '$x0' } + - { reg: '$x1' } +frameInfo: + maxAlignment: 1 +body: | + bb.1: + liveins: $x0, $x1 + ; CHECK-LABEL: name: extract_from_index_too_large + ; CHECK: liveins: $x0, $x1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %extract:_(s64) = G_IMPLICIT_DEF + ; CHECK-NEXT: $x0 = COPY %extract(s64) + ; CHECK-NEXT: RET_ReallyLR implicit $x0 + %vec:_(<2 x s64>) = COPY $q0 + %idx:_(s32) = G_CONSTANT i32 3000 + %extract:_(s64) = G_EXTRACT_VECTOR_ELT %vec(<2 x s64>), %idx(s32) + $x0 = COPY %extract(s64) + RET_ReallyLR implicit $x0 + +... +--- +name: extract_with_freeze +alignment: 4 +liveins: + - { reg: '$x0' } + - { reg: '$x1' } +frameInfo: + maxAlignment: 1 +body: | + bb.1: + liveins: $x0, $x1 + ; CHECK-LABEL: name: extract_with_freeze + ; CHECK: liveins: $x0, $x1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %vec:_(<2 x s64>) = COPY $q0 + ; CHECK-NEXT: %idx:_(s32) = COPY $w1 + ; CHECK-NEXT: [[EVEC:%[0-9]+]]:_(s64) = G_EXTRACT_VECTOR_ELT %vec(<2 x s64>), %idx(s32) + ; CHECK-NEXT: %extract:_(s64) = G_FREEZE [[EVEC]] + ; CHECK-NEXT: $x0 = COPY %extract(s64) + ; CHECK-NEXT: RET_ReallyLR implicit $x0 + %vec:_(<2 x s64>) = COPY $q0 + %idx:_(s32) = COPY $w1 + %fvec:_(<2 x s64>) = G_FREEZE %vec + %extract:_(s64) = G_EXTRACT_VECTOR_ELT %fvec(<2 x s64>), %idx(s32) + $x0 = COPY %extract(s64) + RET_ReallyLR implicit $x0 + +... +--- +name: extract_from_insert_symmetry +alignment: 4 +liveins: + - { reg: '$x0' } + - { reg: '$x1' } +frameInfo: + maxAlignment: 1 +body: | + bb.1: + liveins: $x0, $x1 + ; CHECK-LABEL: name: extract_from_insert_symmetry + ; CHECK: liveins: $x0, $x1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %element:_(s64) = COPY $x1 + ; CHECK-NEXT: $x0 = COPY %element(s64) + ; CHECK-NEXT: RET_ReallyLR implicit $x0 + %vec:_(<2 x s64>) = COPY $q0 + %idx:_(s32) = COPY $w1 + %element:_(s64) = COPY $x1 + %invec:_(<2 x s64>) = G_INSERT_VECTOR_ELT %vec(<2 x s64>), %element(s64), %idx(s32) + %extract:_(s64) = G_EXTRACT_VECTOR_ELT %invec(<2 x s64>), %idx(s32) + $x0 = COPY %extract(s64) + RET_ReallyLR implicit $x0 + +... +--- +name: extract_from_insert_with_different_consts +alignment: 4 +liveins: + - { reg: '$x0' } + - { reg: '$x1' } +frameInfo: + maxAlignment: 1 +body: | + bb.1: + liveins: $x0, $x1 + ; CHECK-LABEL: name: extract_from_insert_with_different_consts + ; CHECK: liveins: $x0, $x1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %vec:_(<2 x s64>) = COPY $q0 + ; CHECK-NEXT: %idx2:_(s32) = G_CONSTANT i32 1 + ; CHECK-NEXT: %extract:_(s64) = G_EXTRACT_VECTOR_ELT %vec(<2 x s64>), %idx2(s32) + ; CHECK-NEXT: $x0 = COPY %extract(s64) + ; CHECK-NEXT: RET_ReallyLR implicit $x0 + %vec:_(<2 x s64>) = COPY $q0 + %idx:_(s32) = G_CONSTANT i32 0 + %idx2:_(s32) = G_CONSTANT i32 1 + %element:_(s64) = COPY $x1 + %invec:_(<2 x s64>) = G_INSERT_VECTOR_ELT %vec(<2 x s64>), %element(s64), %idx(s32) + %extract:_(s64) = G_EXTRACT_VECTOR_ELT %invec(<2 x s64>), %idx2(s32) + $x0 = COPY %extract(s64) + RET_ReallyLR implicit $x0 + +... +--- +name: extract_from_build_vector_non_const +alignment: 4 +liveins: + - { reg: '$x0' } + - { reg: '$x1' } +frameInfo: + maxAlignment: 1 +body: | + bb.1: + liveins: $x0, $x1 + ; CHECK-LABEL: name: extract_from_build_vector_non_const + ; CHECK: liveins: $x0, $x1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %idx:_(s32) = COPY $w0 + ; CHECK-NEXT: %arg1:_(s64) = COPY $x0 + ; CHECK-NEXT: %arg2:_(s64) = COPY $x1 + ; CHECK-NEXT: %bv:_(<2 x s64>) = G_BUILD_VECTOR %arg1(s64), %arg2(s64) + ; CHECK-NEXT: %extract:_(s64) = G_EXTRACT_VECTOR_ELT %bv(<2 x s64>), %idx(s32) + ; CHECK-NEXT: $x0 = COPY %extract(s64) + ; CHECK-NEXT: RET_ReallyLR implicit $x0 + %vec:_(<2 x s64>) = COPY $q0 + %idx:_(s32) = COPY $w0 + %arg1:_(s64) = COPY $x0 + %arg2:_(s64) = COPY $x1 + %bv:_(<2 x s64>) = G_BUILD_VECTOR %arg1(s64), %arg2(s64) + %extract:_(s64) = G_EXTRACT_VECTOR_ELT %bv(<2 x s64>), %idx(s32) + $x0 = COPY %extract(s64) + RET_ReallyLR implicit $x0 + +... +--- +name: extract_from_build_vector_const +alignment: 4 +liveins: + - { reg: '$x0' } + - { reg: '$x1' } +frameInfo: + maxAlignment: 1 +body: | + bb.1: + liveins: $x0, $x1 + ; CHECK-LABEL: name: extract_from_build_vector_const + ; CHECK: liveins: $x0, $x1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %arg1:_(s64) = COPY $x0 + ; CHECK-NEXT: $x0 = COPY %arg1(s64) + ; CHECK-NEXT: RET_ReallyLR implicit $x0 + %vec:_(<2 x s64>) = COPY $q0 + %idx:_(s32) = G_CONSTANT i32 0 + %arg1:_(s64) = COPY $x0 + %arg2:_(s64) = COPY $x1 + %bv:_(<2 x s64>) = G_BUILD_VECTOR %arg1(s64), %arg2(s64) + %extract:_(s64) = G_EXTRACT_VECTOR_ELT %bv(<2 x s64>), %idx(s32) + $x0 = COPY %extract(s64) + RET_ReallyLR implicit $x0 + +... +--- +name: extract_from_build_vector_trunc_const2 +alignment: 4 +liveins: + - { reg: '$x0' } + - { reg: '$x1' } +frameInfo: + maxAlignment: 1 +body: | + bb.1: + liveins: $x0, $x1 + ; CHECK-LABEL: name: extract_from_build_vector_trunc_const2 + ; CHECK: liveins: $x0, $x1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %arg1:_(s64) = COPY $x0 + ; CHECK-NEXT: %extract:_(s32) = G_TRUNC %arg1(s64) + ; CHECK-NEXT: $w0 = COPY %extract(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $x0 + %vec:_(<2 x s64>) = COPY $q0 + %arg1:_(s64) = COPY $x0 + %arg2:_(s64) = COPY $x1 + %arg3:_(s64) = COPY $x0 + %arg4:_(s64) = COPY $x1 + %idx:_(s32) = G_CONSTANT i32 0 + %bv:_(<4 x s32>) = G_BUILD_VECTOR_TRUNC %arg1(s64), %arg2(s64), %arg3(s64), %arg4(s64) + %extract:_(s32) = G_EXTRACT_VECTOR_ELT %bv(<4 x s32>), %idx(s32) + $w0 = COPY %extract(s32) + RET_ReallyLR implicit $x0 +... +--- +name: extract_from_build_vector_trunc2 +alignment: 4 +liveins: + - { reg: '$x0' } + - { reg: '$x1' } +frameInfo: + maxAlignment: 1 +body: | + bb.1: + liveins: $x0, $x1 + ; CHECK-LABEL: name: extract_from_build_vector_trunc2 + ; CHECK: liveins: $x0, $x1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %arg1:_(s64) = COPY $x0 + ; CHECK-NEXT: %arg2:_(s64) = COPY $x1 + ; CHECK-NEXT: %idx:_(s32) = COPY $w0 + ; CHECK-NEXT: %bv:_(<2 x s32>) = G_BUILD_VECTOR_TRUNC %arg1(s64), %arg2(s64) + ; CHECK-NEXT: %extract:_(s32) = G_EXTRACT_VECTOR_ELT %bv(<2 x s32>), %idx(s32) + ; CHECK-NEXT: $w0 = COPY %extract(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $x0 + %arg1:_(s64) = COPY $x0 + %arg2:_(s64) = COPY $x1 + %idx:_(s32) = COPY $w0 + %bv:_(<2 x s32>) = G_BUILD_VECTOR_TRUNC %arg1(s64), %arg2(s64) + %extract:_(s32) = G_EXTRACT_VECTOR_ELT %bv(<2 x s32>), %idx(s32) + $w0 = COPY %extract(s32) + RET_ReallyLR implicit $x0 +... +--- +name: extract_from_build_vector_trunc_const3 +alignment: 4 +liveins: + - { reg: '$x0' } + - { reg: '$x1' } +frameInfo: + maxAlignment: 1 +body: | + bb.1: + liveins: $x0, $x1 + ; CHECK-LABEL: name: extract_from_build_vector_trunc_const3 + ; CHECK: liveins: $x0, $x1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %arg1:_(s128) = COPY $q0 + ; CHECK-NEXT: %extract:_(s64) = G_TRUNC %arg1(s128) + ; CHECK-NEXT: $x0 = COPY %extract(s64) + ; CHECK-NEXT: RET_ReallyLR implicit $x0 + %arg1:_(s128) = COPY $q0 + %arg2:_(s128) = COPY $q1 + %idx:_(s32) = G_CONSTANT i32 0 + %bv:_(<2 x s64>) = G_BUILD_VECTOR_TRUNC %arg1(s128), %arg2(s128) + %extract:_(s64) = G_EXTRACT_VECTOR_ELT %bv(<2 x s64>), %idx(s32) + $x0 = COPY %extract(s64) + RET_ReallyLR implicit $x0 +... +--- diff --git a/llvm/test/CodeGen/AArch64/extract-vector-elt.ll b/llvm/test/CodeGen/AArch64/extract-vector-elt.ll index c5c525a15ad9..504222e0036e 100644 --- a/llvm/test/CodeGen/AArch64/extract-vector-elt.ll +++ b/llvm/test/CodeGen/AArch64/extract-vector-elt.ll @@ -25,20 +25,9 @@ entry: } define i64 @extract_v2i64_undef_vector(<2 x i64> %a, i32 %c) { -; CHECK-SD-LABEL: extract_v2i64_undef_vector: -; CHECK-SD: // %bb.0: // %entry -; CHECK-SD-NEXT: ret -; -; CHECK-GI-LABEL: extract_v2i64_undef_vector: -; CHECK-GI: // %bb.0: // %entry -; CHECK-GI-NEXT: sub sp, sp, #16 -; CHECK-GI-NEXT: .cfi_def_cfa_offset 16 -; CHECK-GI-NEXT: mov w9, w0 -; CHECK-GI-NEXT: mov x8, sp -; CHECK-GI-NEXT: and x9, x9, #0x1 -; CHECK-GI-NEXT: ldr x0, [x8, x9, lsl #3] -; CHECK-GI-NEXT: add sp, sp, #16 -; CHECK-GI-NEXT: ret +; CHECK-LABEL: extract_v2i64_undef_vector: +; CHECK: // %bb.0: // %entry +; CHECK-NEXT: ret entry: %d = extractelement <2 x i64> undef, i32 %c ret i64 %d @@ -130,7 +119,6 @@ define i64 @extract_v2i64_extract_of_insert_different_const(<2 x i64> %a, i64 %e ; ; CHECK-GI-LABEL: extract_v2i64_extract_of_insert_different_const: ; CHECK-GI: // %bb.0: // %entry -; CHECK-GI-NEXT: mov v0.d[0], x0 ; CHECK-GI-NEXT: mov d0, v0.d[1] ; CHECK-GI-NEXT: fmov x0, d0 ; CHECK-GI-NEXT: ret diff --git a/llvm/test/CodeGen/AArch64/extractvector-oob-load.mir b/llvm/test/CodeGen/AArch64/extractvector-oob-load.mir index e8c5819e75e0..e7e8c9399109 100644 --- a/llvm/test/CodeGen/AArch64/extractvector-oob-load.mir +++ b/llvm/test/CodeGen/AArch64/extractvector-oob-load.mir @@ -22,11 +22,8 @@ body: | ; CHECK-LABEL: name: f ; CHECK: liveins: $x0 ; CHECK-NEXT: {{ $}} - ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(p0) = COPY $x0 - ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 16 - ; CHECK-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[C]](s64) - ; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(s64) = G_LOAD [[PTR_ADD]](p0) :: (load (s64)) - ; CHECK-NEXT: $x0 = COPY [[LOAD]](s64) + ; CHECK-NEXT: [[DEF:%[0-9]+]]:_(s64) = G_IMPLICIT_DEF + ; CHECK-NEXT: $x0 = COPY [[DEF]](s64) ; CHECK-NEXT: RET_ReallyLR implicit $x0 %0:_(p0) = COPY $x0 %3:_(s64) = G_CONSTANT i64 224567957 -- GitLab From e47a81c1d2830dda45a561e2c092ebb0c868ed27 Mon Sep 17 00:00:00 2001 From: Sven van Haastregt Date: Tue, 2 Apr 2024 09:31:38 +0200 Subject: [PATCH 034/447] [OpenCL] Fix BIenqueue_kernel fallthrough (#83238) Handling of the `BIenqueue_kernel` builtin must not fallthrough to the `BIget_kernel_work_group_size` builtin, as these builtins have no common functionality. --- clang/lib/CodeGen/CGBuiltin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index bb007231c0b7..483f9c268599 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -5835,7 +5835,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, EmitLifetimeEnd(TmpSize, TmpPtr); return Call; } - [[fallthrough]]; + llvm_unreachable("Unexpected enqueue_kernel signature"); } // OpenCL v2.0 s6.13.17.6 - Kernel query functions need bitcast of block // parameter. -- GitLab From f6c87be1dd24a121d7eccd6b91ca808ecdf80356 Mon Sep 17 00:00:00 2001 From: Aiden Grossman Date: Tue, 2 Apr 2024 00:33:50 -0700 Subject: [PATCH 035/447] [Github] Fix typo in PR code formatting job The recent change to split the PR code formatting job accidentally misspelled the repository field when specifying the repository to fetch the code formatting utils from. This patch fixes the spelling so that the job does not throw a warning and clones the tools from the specified repository. --- .github/workflows/pr-code-format.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-code-format.yml b/.github/workflows/pr-code-format.yml index 54dfe3aadbb4..10b18f245d89 100644 --- a/.github/workflows/pr-code-format.yml +++ b/.github/workflows/pr-code-format.yml @@ -33,7 +33,7 @@ jobs: - name: Fetch code formatting utils uses: actions/checkout@v4 with: - reository: ${{ github.repository }} + repository: ${{ github.repository }} ref: ${{ github.base_ref }} sparse-checkout: | llvm/utils/git/requirements_formatting.txt -- GitLab From fa8dc363506893eb9371dd3b7590f41fa9a7174a Mon Sep 17 00:00:00 2001 From: elhewaty Date: Tue, 2 Apr 2024 09:49:31 +0200 Subject: [PATCH 036/447] [IR] Fix crashes caused by #85592 (#87169) This patch fixes the crash caused by the pull request: https://github.com/llvm/llvm-project/pull/85592 --- llvm/lib/IR/Operator.cpp | 5 +++-- llvm/test/Transforms/FunctionAttrs/noundef.ll | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/llvm/lib/IR/Operator.cpp b/llvm/lib/IR/Operator.cpp index 495769279e33..7b4449cd825f 100644 --- a/llvm/lib/IR/Operator.cpp +++ b/llvm/lib/IR/Operator.cpp @@ -28,8 +28,9 @@ bool Operator::hasPoisonGeneratingFlags() const { return OBO->hasNoUnsignedWrap() || OBO->hasNoSignedWrap(); } case Instruction::Trunc: { - auto *TI = dyn_cast(this); - return TI->hasNoUnsignedWrap() || TI->hasNoSignedWrap(); + if (auto *TI = dyn_cast(this)) + return TI->hasNoUnsignedWrap() || TI->hasNoSignedWrap(); + return false; } case Instruction::UDiv: case Instruction::SDiv: diff --git a/llvm/test/Transforms/FunctionAttrs/noundef.ll b/llvm/test/Transforms/FunctionAttrs/noundef.ll index 946b562f3955..9ab37082a303 100644 --- a/llvm/test/Transforms/FunctionAttrs/noundef.ll +++ b/llvm/test/Transforms/FunctionAttrs/noundef.ll @@ -1,6 +1,8 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4 ; RUN: opt < %s -passes='function-attrs' -S | FileCheck %s +@g_var = external global [0 x i8] + define i32 @test_ret_constant() { ; CHECK-LABEL: define noundef i32 @test_ret_constant( ; CHECK-SAME: ) #[[ATTR0:[0-9]+]] { @@ -152,3 +154,15 @@ define i32 @test_ret_constant_msan() sanitize_memory { ; ret i32 0 } + +define i64 @test_trunc_with_constexpr() { +; CHECK-LABEL: define noundef i64 @test_trunc_with_constexpr( +; CHECK-SAME: ) #[[ATTR0]] { +; CHECK-NEXT: [[ADD:%.*]] = add i32 trunc (i64 sub (i64 0, i64 ptrtoint (ptr @g_var to i64)) to i32), 1 +; CHECK-NEXT: [[CONV:%.*]] = sext i32 [[ADD]] to i64 +; CHECK-NEXT: ret i64 [[CONV]] +; + %add = add i32 trunc (i64 sub (i64 0, i64 ptrtoint (ptr @g_var to i64)) to i32), 1 + %conv = sext i32 %add to i64 + ret i64 %conv +} -- GitLab From 2d14ea68b8c0acdff7c040d581f7fde15d2683d9 Mon Sep 17 00:00:00 2001 From: jeanPerier Date: Tue, 2 Apr 2024 10:22:03 +0200 Subject: [PATCH 037/447] [flang][NFC] speed-up external name conversion pass (#86814) The ExternalNameConversion pass can be surprisingly slow on big programs. On an example with a 50kloc Fortran file with about 10000 calls to external procedures, the pass alone took 25s on my machine. This patch reduces this to 0.16s. The root cause is that using `replaceAllSymbolUses` on each modified FuncOp is very expensive: it is walking all operations and attribute every time. An alternative would be to use mlir::SymbolUserMap to avoid walking the module again and again, but this is still much more expensive than what is needed because it is essentially caching all symbol uses of the module, and there is no need to such caching here. Instead: - Do a shallow walk of the module (only top level operation) to detect FuncOp/GlobalOp that needs to be updated. Update them and place the name remapping in a DenseMap. - If any remapping were done, do a single deep walk of the module operation, and update any SymbolRefAttr that matches a name that was remapped. --- .../Transforms/ExternalNameConversion.cpp | 155 ++++-------------- 1 file changed, 34 insertions(+), 121 deletions(-) diff --git a/flang/lib/Optimizer/Transforms/ExternalNameConversion.cpp b/flang/lib/Optimizer/Transforms/ExternalNameConversion.cpp index 3a9686418c2e..b265c74c33dd 100644 --- a/flang/lib/Optimizer/Transforms/ExternalNameConversion.cpp +++ b/flang/lib/Optimizer/Transforms/ExternalNameConversion.cpp @@ -12,13 +12,9 @@ #include "flang/Optimizer/Dialect/FIROpsSupport.h" #include "flang/Optimizer/Support/InternalNames.h" #include "flang/Optimizer/Transforms/Passes.h" -#include "mlir/Dialect/LLVMIR/LLVMDialect.h" -#include "mlir/Dialect/OpenACC/OpenACC.h" -#include "mlir/Dialect/OpenMP/OpenMPDialect.h" #include "mlir/IR/Attributes.h" #include "mlir/IR/SymbolTable.h" #include "mlir/Pass/Pass.h" -#include "mlir/Transforms/DialectConversion.h" namespace fir { #define GEN_PASS_DEF_EXTERNALNAMECONVERSION @@ -44,102 +40,8 @@ mangleExternalName(const std::pair { -public: - using OpRewritePattern::OpRewritePattern; - - MangleNameOnFuncOp(mlir::MLIRContext *ctx, bool appendUnderscore) - : mlir::OpRewritePattern(ctx), - appendUnderscore(appendUnderscore) {} - - mlir::LogicalResult - matchAndRewrite(mlir::func::FuncOp op, - mlir::PatternRewriter &rewriter) const override { - mlir::LogicalResult ret = success(); - rewriter.startOpModification(op); - llvm::StringRef oldName = op.getSymName(); - auto result = fir::NameUniquer::deconstruct(oldName); - if (fir::NameUniquer::isExternalFacingUniquedName(result)) { - auto newSymbol = - rewriter.getStringAttr(mangleExternalName(result, appendUnderscore)); - - // Try to update all SymbolRef's in the module that match the current op - if (mlir::ModuleOp mod = op->getParentOfType()) - ret = op.replaceAllSymbolUses(newSymbol, mod); - - op.setSymNameAttr(newSymbol); - mlir::SymbolTable::setSymbolName(op, newSymbol); - - op->setAttr(fir::getInternalFuncNameAttrName(), - mlir::StringAttr::get(op->getContext(), oldName)); - } - rewriter.finalizeOpModification(op); - return ret; - } - -private: - bool appendUnderscore; -}; - -struct MangleNameForCommonBlock : public mlir::OpRewritePattern { -public: - using OpRewritePattern::OpRewritePattern; - - MangleNameForCommonBlock(mlir::MLIRContext *ctx, bool appendUnderscore) - : mlir::OpRewritePattern(ctx), - appendUnderscore(appendUnderscore) {} - - mlir::LogicalResult - matchAndRewrite(fir::GlobalOp op, - mlir::PatternRewriter &rewriter) const override { - rewriter.startOpModification(op); - auto result = fir::NameUniquer::deconstruct( - op.getSymref().getRootReference().getValue()); - if (fir::NameUniquer::isExternalFacingUniquedName(result)) { - auto newName = mangleExternalName(result, appendUnderscore); - op.setSymrefAttr(mlir::SymbolRefAttr::get(op.getContext(), newName)); - SymbolTable::setSymbolName(op, newName); - } - rewriter.finalizeOpModification(op); - return success(); - } - -private: - bool appendUnderscore; -}; - -struct MangleNameOnAddrOfOp : public mlir::OpRewritePattern { -public: - using OpRewritePattern::OpRewritePattern; - - MangleNameOnAddrOfOp(mlir::MLIRContext *ctx, bool appendUnderscore) - : mlir::OpRewritePattern(ctx), - appendUnderscore(appendUnderscore) {} - - mlir::LogicalResult - matchAndRewrite(fir::AddrOfOp op, - mlir::PatternRewriter &rewriter) const override { - auto result = fir::NameUniquer::deconstruct( - op.getSymbol().getRootReference().getValue()); - if (fir::NameUniquer::isExternalFacingUniquedName(result)) { - auto newName = SymbolRefAttr::get( - op.getContext(), mangleExternalName(result, appendUnderscore)); - rewriter.replaceOpWithNewOp(op, op.getResTy().getType(), - newName); - } - return success(); - } - -private: - bool appendUnderscore; -}; - class ExternalNameConversionPass : public fir::impl::ExternalNameConversionBase { public: @@ -162,31 +64,42 @@ void ExternalNameConversionPass::runOnOperation() { auto *context = &getContext(); appendUnderscores = (usePassOpt) ? appendUnderscoreOpt : appendUnderscores; + llvm::DenseMap remappings; + // Update names of external Fortran functions and names of Common Block + // globals. + for (auto &funcOrGlobal : op->getRegion(0).front()) { + if (llvm::isa(funcOrGlobal) || + llvm::isa(funcOrGlobal)) { + auto symName = funcOrGlobal.getAttrOfType( + mlir::SymbolTable::getSymbolAttrName()); + auto deconstructedName = fir::NameUniquer::deconstruct(symName); + if (fir::NameUniquer::isExternalFacingUniquedName(deconstructedName)) { + auto newName = mangleExternalName(deconstructedName, appendUnderscores); + auto newAttr = mlir::StringAttr::get(context, newName); + mlir::SymbolTable::setSymbolName(&funcOrGlobal, newAttr); + auto newSymRef = mlir::FlatSymbolRefAttr::get(newAttr); + remappings.try_emplace(symName, newSymRef); + if (llvm::isa(funcOrGlobal)) + funcOrGlobal.setAttr(fir::getInternalFuncNameAttrName(), symName); + } + } + } - mlir::RewritePatternSet patterns(context); - patterns.insert(context, appendUnderscores); - - ConversionTarget target(*context); - target.addLegalDialect(); - - target.addDynamicallyLegalOp([](mlir::func::FuncOp op) { - return !fir::NameUniquer::needExternalNameMangling(op.getSymName()); - }); - - target.addDynamicallyLegalOp([](fir::GlobalOp op) { - return !fir::NameUniquer::needExternalNameMangling( - op.getSymref().getRootReference().getValue()); - }); - - target.addDynamicallyLegalOp([](fir::AddrOfOp op) { - return !fir::NameUniquer::needExternalNameMangling( - op.getSymbol().getRootReference().getValue()); + if (remappings.empty()) + return; + + // Update all uses of the functions and globals that have been renamed. + op.walk([&remappings](mlir::Operation *nestedOp) { + llvm::SmallVector> updates; + for (const mlir::NamedAttribute &attr : nestedOp->getAttrDictionary()) + if (auto symRef = llvm::dyn_cast(attr.getValue())) + if (auto remap = remappings.find(symRef.getRootReference()); + remap != remappings.end()) + updates.emplace_back(std::pair{ + attr.getName(), mlir::SymbolRefAttr(remap->second)}); + for (auto update : updates) + nestedOp->setAttr(update.first, update.second); }); - - if (failed(applyPartialConversion(op, target, std::move(patterns)))) - signalPassFailure(); } std::unique_ptr fir::createExternalNameConversionPass() { -- GitLab From 77e5c0a95c54e0ca34b8e9c56c702490619b73c9 Mon Sep 17 00:00:00 2001 From: Marc Auberer Date: Tue, 2 Apr 2024 10:49:06 +0200 Subject: [PATCH 038/447] [AArch64][GISEL] Reduce likelihood of hash collisions for mappings in RegisterBankInfo (#87033) Fixes #85209 This patch removes the truncation from `hash_code` aka `size_t` down to `unsigned`, that currently happens on DenseMap accesses in RegisterBankInfo. This reduces the likelihood of hash collisions, as well as the likelihood of hitting EmptyKey or TombstoneKey, the special key values of DenseMap. This is not the ultimate solution to the problem, but we can do it in any case. --- llvm/include/llvm/CodeGen/RegisterBankInfo.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/llvm/include/llvm/CodeGen/RegisterBankInfo.h b/llvm/include/llvm/CodeGen/RegisterBankInfo.h index 62c4a57a605d..9704e3b1fded 100644 --- a/llvm/include/llvm/CodeGen/RegisterBankInfo.h +++ b/llvm/include/llvm/CodeGen/RegisterBankInfo.h @@ -399,22 +399,22 @@ protected: /// Keep dynamically allocated PartialMapping in a separate map. /// This shouldn't be needed when everything gets TableGen'ed. - mutable DenseMap> + mutable DenseMap> MapOfPartialMappings; /// Keep dynamically allocated ValueMapping in a separate map. /// This shouldn't be needed when everything gets TableGen'ed. - mutable DenseMap> + mutable DenseMap> MapOfValueMappings; /// Keep dynamically allocated array of ValueMapping in a separate map. /// This shouldn't be needed when everything gets TableGen'ed. - mutable DenseMap> + mutable DenseMap> MapOfOperandsMappings; /// Keep dynamically allocated InstructionMapping in a separate map. /// This shouldn't be needed when everything gets TableGen'ed. - mutable DenseMap> + mutable DenseMap> MapOfInstructionMappings; /// Getting the minimal register class of a physreg is expensive. -- GitLab From 6cce67a8f9bbab7ebaafa6f33e0efbb22dee3ea1 Mon Sep 17 00:00:00 2001 From: Vyacheslav Levytskyy Date: Tue, 2 Apr 2024 10:59:18 +0200 Subject: [PATCH 039/447] [SPIR-V] Fix validity of atomic instructions (#87051) This PR fixes validity of atomic instructions and improves type inference. More tests are able now to be accepted by `spirv-val`. --- llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp | 7 ++ llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp | 89 ++++++++++++++++--- llvm/lib/Target/SPIRV/SPIRVISelLowering.cpp | 42 +++++++++ llvm/test/CodeGen/SPIRV/ExecutionMode.ll | 1 + .../test/CodeGen/SPIRV/instructions/atomic.ll | 28 ++++-- .../SPIRV/instructions/atomic_acqrel.ll | 28 ++++-- .../CodeGen/SPIRV/instructions/atomic_seq.ll | 28 ++++-- .../SPIRV/pointers/bitcast-fix-accesschain.ll | 37 ++++++++ .../pointers/type-deduce-by-call-complex.ll | 29 ++++++ 9 files changed, 252 insertions(+), 37 deletions(-) create mode 100644 llvm/test/CodeGen/SPIRV/pointers/bitcast-fix-accesschain.ll create mode 100644 llvm/test/CodeGen/SPIRV/pointers/type-deduce-by-call-complex.ll diff --git a/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp b/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp index ad4e72a3128b..1674cef7cb82 100644 --- a/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp @@ -251,6 +251,13 @@ static SPIRVType *getArgSPIRVType(const Function &F, unsigned ArgIdx, cast(II->getOperand(2))->getZExtValue(), ST)); } + // Replace PointerType with TypedPointerType to be able to map SPIR-V types to + // LLVM types in a consistent manner + if (isUntypedPointerTy(OriginalArgType)) { + OriginalArgType = + TypedPointerType::get(Type::getInt8Ty(F.getContext()), + getPointerAddressSpace(OriginalArgType)); + } return GR->getOrCreateSPIRVType(OriginalArgType, MIRBuilder, ArgAccessQual); } diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp index 7c5a38fa48d0..b341fcb41d03 100644 --- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp @@ -65,6 +65,10 @@ class SPIRVEmitIntrinsics Type *deduceElementType(Value *I); Type *deduceElementTypeHelper(Value *I); Type *deduceElementTypeHelper(Value *I, std::unordered_set &Visited); + Type *deduceElementTypeByValueDeep(Type *ValueTy, Value *Operand, + std::unordered_set &Visited); + Type *deduceElementTypeByUsersDeep(Value *Op, + std::unordered_set &Visited); // deduce nested types of composites Type *deduceNestedTypeHelper(User *U); @@ -176,6 +180,44 @@ static inline void reportFatalOnTokenType(const Instruction *I) { false); } +// Set element pointer type to the given value of ValueTy and tries to +// specify this type further (recursively) by Operand value, if needed. +Type *SPIRVEmitIntrinsics::deduceElementTypeByValueDeep( + Type *ValueTy, Value *Operand, std::unordered_set &Visited) { + Type *Ty = ValueTy; + if (Operand) { + if (auto *PtrTy = dyn_cast(Ty)) { + if (Type *NestedTy = deduceElementTypeHelper(Operand, Visited)) + Ty = TypedPointerType::get(NestedTy, PtrTy->getAddressSpace()); + } else { + Ty = deduceNestedTypeHelper(dyn_cast(Operand), Ty, Visited); + } + } + return Ty; +} + +// Traverse User instructions to deduce an element pointer type of the operand. +Type *SPIRVEmitIntrinsics::deduceElementTypeByUsersDeep( + Value *Op, std::unordered_set &Visited) { + if (!Op || !isPointerTy(Op->getType())) + return nullptr; + + if (auto PType = dyn_cast(Op->getType())) + return PType->getElementType(); + + // maybe we already know operand's element type + if (Type *KnownTy = GR->findDeducedElementType(Op)) + return KnownTy; + + for (User *OpU : Op->users()) { + if (Instruction *Inst = dyn_cast(OpU)) { + if (Type *Ty = deduceElementTypeHelper(Inst, Visited)) + return Ty; + } + } + return nullptr; +} + // Deduce and return a successfully deduced Type of the Instruction, // or nullptr otherwise. Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(Value *I) { @@ -206,21 +248,27 @@ Type *SPIRVEmitIntrinsics::deduceElementTypeHelper( } else if (auto *Ref = dyn_cast(I)) { Ty = Ref->getResultElementType(); } else if (auto *Ref = dyn_cast(I)) { - Ty = Ref->getValueType(); - if (Value *Op = Ref->getNumOperands() > 0 ? Ref->getOperand(0) : nullptr) { - if (auto *PtrTy = dyn_cast(Ty)) { - if (Type *NestedTy = deduceElementTypeHelper(Op, Visited)) - Ty = TypedPointerType::get(NestedTy, PtrTy->getAddressSpace()); - } else { - Ty = deduceNestedTypeHelper(dyn_cast(Op), Ty, Visited); - } - } + Ty = deduceElementTypeByValueDeep( + Ref->getValueType(), + Ref->getNumOperands() > 0 ? Ref->getOperand(0) : nullptr, Visited); } else if (auto *Ref = dyn_cast(I)) { Ty = deduceElementTypeHelper(Ref->getPointerOperand(), Visited); } else if (auto *Ref = dyn_cast(I)) { if (Type *Src = Ref->getSrcTy(), *Dest = Ref->getDestTy(); isPointerTy(Src) && isPointerTy(Dest)) Ty = deduceElementTypeHelper(Ref->getOperand(0), Visited); + } else if (auto *Ref = dyn_cast(I)) { + Value *Op = Ref->getNewValOperand(); + Ty = deduceElementTypeByValueDeep(Op->getType(), Op, Visited); + } else if (auto *Ref = dyn_cast(I)) { + Value *Op = Ref->getValOperand(); + Ty = deduceElementTypeByValueDeep(Op->getType(), Op, Visited); + } else if (auto *Ref = dyn_cast(I)) { + for (unsigned i = 0; i < Ref->getNumIncomingValues(); i++) { + Ty = deduceElementTypeByUsersDeep(Ref->getIncomingValue(i), Visited); + if (Ty) + break; + } } // remember the found relationship @@ -293,6 +341,22 @@ Type *SPIRVEmitIntrinsics::deduceNestedTypeHelper( return NewTy; } } + } else if (auto *VecTy = dyn_cast(OrigTy)) { + if (Value *Op = U->getNumOperands() > 0 ? U->getOperand(0) : nullptr) { + Type *OpTy = VecTy->getElementType(); + Type *Ty = OpTy; + if (auto *PtrTy = dyn_cast(OpTy)) { + if (Type *NestedTy = deduceElementTypeHelper(Op, Visited)) + Ty = TypedPointerType::get(NestedTy, PtrTy->getAddressSpace()); + } else { + Ty = deduceNestedTypeHelper(dyn_cast(Op), OpTy, Visited); + } + if (Ty != OpTy) { + Type *NewTy = VectorType::get(Ty, VecTy->getElementCount()); + GR->addDeducedCompositeType(U, NewTy); + return NewTy; + } + } } return OrigTy; @@ -578,7 +642,8 @@ void SPIRVEmitIntrinsics::insertPtrCastOrAssignTypeInstr(Instruction *I, // Handle calls to builtins (non-intrinsics): CallInst *CI = dyn_cast(I); - if (!CI || CI->isIndirectCall() || CI->getCalledFunction()->isIntrinsic()) + if (!CI || CI->isIndirectCall() || CI->isInlineAsm() || + !CI->getCalledFunction() || CI->getCalledFunction()->isIntrinsic()) return; // collect information about formal parameter types @@ -929,6 +994,10 @@ Type *SPIRVEmitIntrinsics::deduceFunParamElementType( // maybe we already know operand's element type if (Type *KnownTy = GR->findDeducedElementType(OpArg)) return KnownTy; + // try to deduce from the operand itself + Visited.clear(); + if (Type *Ty = deduceElementTypeHelper(OpArg, Visited)) + return Ty; // search in actual parameter's users for (User *OpU : OpArg->users()) { Instruction *Inst = dyn_cast(OpU); diff --git a/llvm/lib/Target/SPIRV/SPIRVISelLowering.cpp b/llvm/lib/Target/SPIRV/SPIRVISelLowering.cpp index 4f5c1dc4f90b..90a31551f45a 100644 --- a/llvm/lib/Target/SPIRV/SPIRVISelLowering.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVISelLowering.cpp @@ -201,6 +201,17 @@ void validateForwardCalls(const SPIRVSubtarget &STI, } } +// Validation of an access chain. +void validateAccessChain(const SPIRVSubtarget &STI, MachineRegisterInfo *MRI, + SPIRVGlobalRegistry &GR, MachineInstr &I) { + SPIRVType *BaseTypeInst = GR.getSPIRVTypeForVReg(I.getOperand(0).getReg()); + if (BaseTypeInst && BaseTypeInst->getOpcode() == SPIRV::OpTypePointer) { + SPIRVType *BaseElemType = + GR.getSPIRVTypeForVReg(BaseTypeInst->getOperand(2).getReg()); + validatePtrTypes(STI, MRI, GR, I, 2, BaseElemType); + } +} + // TODO: the logic of inserting additional bitcast's is to be moved // to pre-IRTranslation passes eventually void SPIRVTargetLowering::finalizeLowering(MachineFunction &MF) const { @@ -213,16 +224,47 @@ void SPIRVTargetLowering::finalizeLowering(MachineFunction &MF) const { MBBI != MBBE;) { MachineInstr &MI = *MBBI++; switch (MI.getOpcode()) { + case SPIRV::OpAtomicLoad: + case SPIRV::OpAtomicExchange: + case SPIRV::OpAtomicCompareExchange: + case SPIRV::OpAtomicCompareExchangeWeak: + case SPIRV::OpAtomicIIncrement: + case SPIRV::OpAtomicIDecrement: + case SPIRV::OpAtomicIAdd: + case SPIRV::OpAtomicISub: + case SPIRV::OpAtomicSMin: + case SPIRV::OpAtomicUMin: + case SPIRV::OpAtomicSMax: + case SPIRV::OpAtomicUMax: + case SPIRV::OpAtomicAnd: + case SPIRV::OpAtomicOr: + case SPIRV::OpAtomicXor: + // for the above listed instructions + // OpAtomicXXX , ptr %Op, ... + // implies that %Op is a pointer to case SPIRV::OpLoad: // OpLoad , ptr %Op implies that %Op is a pointer to validatePtrTypes(STI, MRI, GR, MI, 2, GR.getSPIRVTypeForVReg(MI.getOperand(0).getReg())); break; + case SPIRV::OpAtomicStore: + // OpAtomicStore ptr %Op, , , + // implies that %Op points to the 's type + validatePtrTypes(STI, MRI, GR, MI, 0, + GR.getSPIRVTypeForVReg(MI.getOperand(3).getReg())); + break; case SPIRV::OpStore: // OpStore ptr %Op, implies that %Op points to the 's type validatePtrTypes(STI, MRI, GR, MI, 0, GR.getSPIRVTypeForVReg(MI.getOperand(1).getReg())); break; + case SPIRV::OpPtrCastToGeneric: + validateAccessChain(STI, MRI, GR, MI); + break; + case SPIRV::OpInBoundsPtrAccessChain: + if (MI.getNumOperands() == 4) + validateAccessChain(STI, MRI, GR, MI); + break; case SPIRV::OpFunctionCall: // ensure there is no mismatch between actual and expected arg types: diff --git a/llvm/test/CodeGen/SPIRV/ExecutionMode.ll b/llvm/test/CodeGen/SPIRV/ExecutionMode.ll index 3e321e1c2bd2..180b7246952d 100644 --- a/llvm/test/CodeGen/SPIRV/ExecutionMode.ll +++ b/llvm/test/CodeGen/SPIRV/ExecutionMode.ll @@ -1,4 +1,5 @@ ; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %} ; CHECK-DAG: %[[#VOID:]] = OpTypeVoid diff --git a/llvm/test/CodeGen/SPIRV/instructions/atomic.ll b/llvm/test/CodeGen/SPIRV/instructions/atomic.ll index 9715504fcc5d..ce59bb206402 100644 --- a/llvm/test/CodeGen/SPIRV/instructions/atomic.ll +++ b/llvm/test/CodeGen/SPIRV/instructions/atomic.ll @@ -1,4 +1,5 @@ ; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %} ; CHECK-DAG: OpName [[ADD:%.*]] "test_add" ; CHECK-DAG: OpName [[SUB:%.*]] "test_sub" @@ -20,7 +21,8 @@ ; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter ; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter ; CHECK-NEXT: OpLabel -; CHECK-NEXT: [[R:%.*]] = OpAtomicIAdd [[I32Ty]] [[A]] [[SCOPE]] [[RELAXED]] [[B]] +; CHECK-NEXT: [[BC_A:%.*]] = OpBitcast %[[#]] [[A]] +; CHECK-NEXT: [[R:%.*]] = OpAtomicIAdd [[I32Ty]] [[BC_A]] [[SCOPE]] [[RELAXED]] [[B]] ; CHECK-NEXT: OpReturnValue [[R]] ; CHECK-NEXT: OpFunctionEnd define i32 @test_add(i32* %ptr, i32 %val) { @@ -32,7 +34,8 @@ define i32 @test_add(i32* %ptr, i32 %val) { ; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter ; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter ; CHECK-NEXT: OpLabel -; CHECK-NEXT: [[R:%.*]] = OpAtomicISub [[I32Ty]] [[A]] [[SCOPE]] [[RELAXED]] [[B]] +; CHECK-NEXT: [[BC_A:%.*]] = OpBitcast %[[#]] [[A]] +; CHECK-NEXT: [[R:%.*]] = OpAtomicISub [[I32Ty]] [[BC_A]] [[SCOPE]] [[RELAXED]] [[B]] ; CHECK-NEXT: OpReturnValue [[R]] ; CHECK-NEXT: OpFunctionEnd define i32 @test_sub(i32* %ptr, i32 %val) { @@ -44,7 +47,8 @@ define i32 @test_sub(i32* %ptr, i32 %val) { ; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter ; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter ; CHECK-NEXT: OpLabel -; CHECK-NEXT: [[R:%.*]] = OpAtomicSMin [[I32Ty]] [[A]] [[SCOPE]] [[RELAXED]] [[B]] +; CHECK-NEXT: [[BC_A:%.*]] = OpBitcast %[[#]] [[A]] +; CHECK-NEXT: [[R:%.*]] = OpAtomicSMin [[I32Ty]] [[BC_A]] [[SCOPE]] [[RELAXED]] [[B]] ; CHECK-NEXT: OpReturnValue [[R]] ; CHECK-NEXT: OpFunctionEnd define i32 @test_min(i32* %ptr, i32 %val) { @@ -56,7 +60,8 @@ define i32 @test_min(i32* %ptr, i32 %val) { ; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter ; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter ; CHECK-NEXT: OpLabel -; CHECK-NEXT: [[R:%.*]] = OpAtomicSMax [[I32Ty]] [[A]] [[SCOPE]] [[RELAXED]] [[B]] +; CHECK-NEXT: [[BC_A:%.*]] = OpBitcast %[[#]] [[A]] +; CHECK-NEXT: [[R:%.*]] = OpAtomicSMax [[I32Ty]] [[BC_A]] [[SCOPE]] [[RELAXED]] [[B]] ; CHECK-NEXT: OpReturnValue [[R]] ; CHECK-NEXT: OpFunctionEnd define i32 @test_max(i32* %ptr, i32 %val) { @@ -68,7 +73,8 @@ define i32 @test_max(i32* %ptr, i32 %val) { ; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter ; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter ; CHECK-NEXT: OpLabel -; CHECK-NEXT: [[R:%.*]] = OpAtomicUMin [[I32Ty]] [[A]] [[SCOPE]] [[RELAXED]] [[B]] +; CHECK-NEXT: [[BC_A:%.*]] = OpBitcast %[[#]] [[A]] +; CHECK-NEXT: [[R:%.*]] = OpAtomicUMin [[I32Ty]] [[BC_A]] [[SCOPE]] [[RELAXED]] [[B]] ; CHECK-NEXT: OpReturnValue [[R]] ; CHECK-NEXT: OpFunctionEnd define i32 @test_umin(i32* %ptr, i32 %val) { @@ -80,7 +86,8 @@ define i32 @test_umin(i32* %ptr, i32 %val) { ; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter ; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter ; CHECK-NEXT: OpLabel -; CHECK-NEXT: [[R:%.*]] = OpAtomicUMax [[I32Ty]] [[A]] [[SCOPE]] [[RELAXED]] [[B]] +; CHECK-NEXT: [[BC_A:%.*]] = OpBitcast %[[#]] [[A]] +; CHECK-NEXT: [[R:%.*]] = OpAtomicUMax [[I32Ty]] [[BC_A]] [[SCOPE]] [[RELAXED]] [[B]] ; CHECK-NEXT: OpReturnValue [[R]] ; CHECK-NEXT: OpFunctionEnd define i32 @test_umax(i32* %ptr, i32 %val) { @@ -92,7 +99,8 @@ define i32 @test_umax(i32* %ptr, i32 %val) { ; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter ; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter ; CHECK-NEXT: OpLabel -; CHECK-NEXT: [[R:%.*]] = OpAtomicAnd [[I32Ty]] [[A]] [[SCOPE]] [[RELAXED]] [[B]] +; CHECK-NEXT: [[BC_A:%.*]] = OpBitcast %[[#]] [[A]] +; CHECK-NEXT: [[R:%.*]] = OpAtomicAnd [[I32Ty]] [[BC_A]] [[SCOPE]] [[RELAXED]] [[B]] ; CHECK-NEXT: OpReturnValue [[R]] ; CHECK-NEXT: OpFunctionEnd define i32 @test_and(i32* %ptr, i32 %val) { @@ -104,7 +112,8 @@ define i32 @test_and(i32* %ptr, i32 %val) { ; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter ; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter ; CHECK-NEXT: OpLabel -; CHECK-NEXT: [[R:%.*]] = OpAtomicOr [[I32Ty]] [[A]] [[SCOPE]] [[RELAXED]] [[B]] +; CHECK-NEXT: [[BC_A:%.*]] = OpBitcast %[[#]] [[A]] +; CHECK-NEXT: [[R:%.*]] = OpAtomicOr [[I32Ty]] [[BC_A]] [[SCOPE]] [[RELAXED]] [[B]] ; CHECK-NEXT: OpReturnValue [[R]] ; CHECK-NEXT: OpFunctionEnd define i32 @test_or(i32* %ptr, i32 %val) { @@ -116,7 +125,8 @@ define i32 @test_or(i32* %ptr, i32 %val) { ; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter ; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter ; CHECK-NEXT: OpLabel -; CHECK-NEXT: [[R:%.*]] = OpAtomicXor [[I32Ty]] [[A]] [[SCOPE]] [[RELAXED]] [[B]] +; CHECK-NEXT: [[BC_A:%.*]] = OpBitcast %[[#]] [[A]] +; CHECK-NEXT: [[R:%.*]] = OpAtomicXor [[I32Ty]] [[BC_A]] [[SCOPE]] [[RELAXED]] [[B]] ; CHECK-NEXT: OpReturnValue [[R]] ; CHECK-NEXT: OpFunctionEnd define i32 @test_xor(i32* %ptr, i32 %val) { diff --git a/llvm/test/CodeGen/SPIRV/instructions/atomic_acqrel.ll b/llvm/test/CodeGen/SPIRV/instructions/atomic_acqrel.ll index 63c0ae75f5ec..950dfe417637 100644 --- a/llvm/test/CodeGen/SPIRV/instructions/atomic_acqrel.ll +++ b/llvm/test/CodeGen/SPIRV/instructions/atomic_acqrel.ll @@ -1,4 +1,5 @@ ; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %} ; CHECK-DAG: OpName [[ADD:%.*]] "test_add" ; CHECK-DAG: OpName [[SUB:%.*]] "test_sub" @@ -20,7 +21,8 @@ ; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter ; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter ; CHECK-NEXT: OpLabel -; CHECK-NEXT: [[R:%.*]] = OpAtomicIAdd [[I32Ty]] [[A]] [[SCOPE]] [[ACQREL]] [[B]] +; CHECK-NEXT: [[BC_A:%.*]] = OpBitcast %[[#]] [[A]] +; CHECK-NEXT: [[R:%.*]] = OpAtomicIAdd [[I32Ty]] [[BC_A]] [[SCOPE]] [[ACQREL]] [[B]] ; CHECK-NEXT: OpReturnValue [[R]] ; CHECK-NEXT: OpFunctionEnd define i32 @test_add(i32* %ptr, i32 %val) { @@ -32,7 +34,8 @@ define i32 @test_add(i32* %ptr, i32 %val) { ; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter ; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter ; CHECK-NEXT: OpLabel -; CHECK-NEXT: [[R:%.*]] = OpAtomicISub [[I32Ty]] [[A]] [[SCOPE]] [[ACQREL]] [[B]] +; CHECK-NEXT: [[BC_A:%.*]] = OpBitcast %[[#]] [[A]] +; CHECK-NEXT: [[R:%.*]] = OpAtomicISub [[I32Ty]] [[BC_A]] [[SCOPE]] [[ACQREL]] [[B]] ; CHECK-NEXT: OpReturnValue [[R]] ; CHECK-NEXT: OpFunctionEnd define i32 @test_sub(i32* %ptr, i32 %val) { @@ -44,7 +47,8 @@ define i32 @test_sub(i32* %ptr, i32 %val) { ; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter ; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter ; CHECK-NEXT: OpLabel -; CHECK-NEXT: [[R:%.*]] = OpAtomicSMin [[I32Ty]] [[A]] [[SCOPE]] [[ACQREL]] [[B]] +; CHECK-NEXT: [[BC_A:%.*]] = OpBitcast %[[#]] [[A]] +; CHECK-NEXT: [[R:%.*]] = OpAtomicSMin [[I32Ty]] [[BC_A]] [[SCOPE]] [[ACQREL]] [[B]] ; CHECK-NEXT: OpReturnValue [[R]] ; CHECK-NEXT: OpFunctionEnd define i32 @test_min(i32* %ptr, i32 %val) { @@ -56,7 +60,8 @@ define i32 @test_min(i32* %ptr, i32 %val) { ; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter ; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter ; CHECK-NEXT: OpLabel -; CHECK-NEXT: [[R:%.*]] = OpAtomicSMax [[I32Ty]] [[A]] [[SCOPE]] [[ACQREL]] [[B]] +; CHECK-NEXT: [[BC_A:%.*]] = OpBitcast %[[#]] [[A]] +; CHECK-NEXT: [[R:%.*]] = OpAtomicSMax [[I32Ty]] [[BC_A]] [[SCOPE]] [[ACQREL]] [[B]] ; CHECK-NEXT: OpReturnValue [[R]] ; CHECK-NEXT: OpFunctionEnd define i32 @test_max(i32* %ptr, i32 %val) { @@ -68,7 +73,8 @@ define i32 @test_max(i32* %ptr, i32 %val) { ; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter ; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter ; CHECK-NEXT: OpLabel -; CHECK-NEXT: [[R:%.*]] = OpAtomicUMin [[I32Ty]] [[A]] [[SCOPE]] [[ACQREL]] [[B]] +; CHECK-NEXT: [[BC_A:%.*]] = OpBitcast %[[#]] [[A]] +; CHECK-NEXT: [[R:%.*]] = OpAtomicUMin [[I32Ty]] [[BC_A]] [[SCOPE]] [[ACQREL]] [[B]] ; CHECK-NEXT: OpReturnValue [[R]] ; CHECK-NEXT: OpFunctionEnd define i32 @test_umin(i32* %ptr, i32 %val) { @@ -80,7 +86,8 @@ define i32 @test_umin(i32* %ptr, i32 %val) { ; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter ; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter ; CHECK-NEXT: OpLabel -; CHECK-NEXT: [[R:%.*]] = OpAtomicUMax [[I32Ty]] [[A]] [[SCOPE]] [[ACQREL]] [[B]] +; CHECK-NEXT: [[BC_A:%.*]] = OpBitcast %[[#]] [[A]] +; CHECK-NEXT: [[R:%.*]] = OpAtomicUMax [[I32Ty]] [[BC_A]] [[SCOPE]] [[ACQREL]] [[B]] ; CHECK-NEXT: OpReturnValue [[R]] ; CHECK-NEXT: OpFunctionEnd define i32 @test_umax(i32* %ptr, i32 %val) { @@ -92,7 +99,8 @@ define i32 @test_umax(i32* %ptr, i32 %val) { ; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter ; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter ; CHECK-NEXT: OpLabel -; CHECK-NEXT: [[R:%.*]] = OpAtomicAnd [[I32Ty]] [[A]] [[SCOPE]] [[ACQREL]] [[B]] +; CHECK-NEXT: [[BC_A:%.*]] = OpBitcast %[[#]] [[A]] +; CHECK-NEXT: [[R:%.*]] = OpAtomicAnd [[I32Ty]] [[BC_A]] [[SCOPE]] [[ACQREL]] [[B]] ; CHECK-NEXT: OpReturnValue [[R]] ; CHECK-NEXT: OpFunctionEnd define i32 @test_and(i32* %ptr, i32 %val) { @@ -104,7 +112,8 @@ define i32 @test_and(i32* %ptr, i32 %val) { ; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter ; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter ; CHECK-NEXT: OpLabel -; CHECK-NEXT: [[R:%.*]] = OpAtomicOr [[I32Ty]] [[A]] [[SCOPE]] [[ACQREL]] [[B]] +; CHECK-NEXT: [[BC_A:%.*]] = OpBitcast %[[#]] [[A]] +; CHECK-NEXT: [[R:%.*]] = OpAtomicOr [[I32Ty]] [[BC_A]] [[SCOPE]] [[ACQREL]] [[B]] ; CHECK-NEXT: OpReturnValue [[R]] ; CHECK-NEXT: OpFunctionEnd define i32 @test_or(i32* %ptr, i32 %val) { @@ -116,7 +125,8 @@ define i32 @test_or(i32* %ptr, i32 %val) { ; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter ; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter ; CHECK-NEXT: OpLabel -; CHECK-NEXT: [[R:%.*]] = OpAtomicXor [[I32Ty]] [[A]] [[SCOPE]] [[ACQREL]] [[B]] +; CHECK-NEXT: [[BC_A:%.*]] = OpBitcast %[[#]] [[A]] +; CHECK-NEXT: [[R:%.*]] = OpAtomicXor [[I32Ty]] [[BC_A]] [[SCOPE]] [[ACQREL]] [[B]] ; CHECK-NEXT: OpReturnValue [[R]] ; CHECK-NEXT: OpFunctionEnd define i32 @test_xor(i32* %ptr, i32 %val) { diff --git a/llvm/test/CodeGen/SPIRV/instructions/atomic_seq.ll b/llvm/test/CodeGen/SPIRV/instructions/atomic_seq.ll index f6a8fe1e6db1..f142e012dcb7 100644 --- a/llvm/test/CodeGen/SPIRV/instructions/atomic_seq.ll +++ b/llvm/test/CodeGen/SPIRV/instructions/atomic_seq.ll @@ -1,4 +1,5 @@ ; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %} ; CHECK-DAG: OpName [[ADD:%.*]] "test_add" ; CHECK-DAG: OpName [[SUB:%.*]] "test_sub" @@ -20,7 +21,8 @@ ; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter ; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter ; CHECK-NEXT: OpLabel -; CHECK-NEXT: [[R:%.*]] = OpAtomicIAdd [[I32Ty]] [[A]] [[SCOPE]] [[SEQ]] [[B]] +; CHECK-NEXT: [[BC_A:%.*]] = OpBitcast %[[#]] [[A]] +; CHECK-NEXT: [[R:%.*]] = OpAtomicIAdd [[I32Ty]] [[BC_A]] [[SCOPE]] [[SEQ]] [[B]] ; CHECK-NEXT: OpReturnValue [[R]] ; CHECK-NEXT: OpFunctionEnd define i32 @test_add(i32* %ptr, i32 %val) { @@ -32,7 +34,8 @@ define i32 @test_add(i32* %ptr, i32 %val) { ; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter ; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter ; CHECK-NEXT: OpLabel -; CHECK-NEXT: [[R:%.*]] = OpAtomicISub [[I32Ty]] [[A]] [[SCOPE]] [[SEQ]] [[B]] +; CHECK-NEXT: [[BC_A:%.*]] = OpBitcast %[[#]] [[A]] +; CHECK-NEXT: [[R:%.*]] = OpAtomicISub [[I32Ty]] [[BC_A]] [[SCOPE]] [[SEQ]] [[B]] ; CHECK-NEXT: OpReturnValue [[R]] ; CHECK-NEXT: OpFunctionEnd define i32 @test_sub(i32* %ptr, i32 %val) { @@ -44,7 +47,8 @@ define i32 @test_sub(i32* %ptr, i32 %val) { ; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter ; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter ; CHECK-NEXT: OpLabel -; CHECK-NEXT: [[R:%.*]] = OpAtomicSMin [[I32Ty]] [[A]] [[SCOPE]] [[SEQ]] [[B]] +; CHECK-NEXT: [[BC_A:%.*]] = OpBitcast %[[#]] [[A]] +; CHECK-NEXT: [[R:%.*]] = OpAtomicSMin [[I32Ty]] [[BC_A]] [[SCOPE]] [[SEQ]] [[B]] ; CHECK-NEXT: OpReturnValue [[R]] ; CHECK-NEXT: OpFunctionEnd define i32 @test_min(i32* %ptr, i32 %val) { @@ -56,7 +60,8 @@ define i32 @test_min(i32* %ptr, i32 %val) { ; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter ; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter ; CHECK-NEXT: OpLabel -; CHECK-NEXT: [[R:%.*]] = OpAtomicSMax [[I32Ty]] [[A]] [[SCOPE]] [[SEQ]] [[B]] +; CHECK-NEXT: [[BC_A:%.*]] = OpBitcast %[[#]] [[A]] +; CHECK-NEXT: [[R:%.*]] = OpAtomicSMax [[I32Ty]] [[BC_A]] [[SCOPE]] [[SEQ]] [[B]] ; CHECK-NEXT: OpReturnValue [[R]] ; CHECK-NEXT: OpFunctionEnd define i32 @test_max(i32* %ptr, i32 %val) { @@ -68,7 +73,8 @@ define i32 @test_max(i32* %ptr, i32 %val) { ; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter ; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter ; CHECK-NEXT: OpLabel -; CHECK-NEXT: [[R:%.*]] = OpAtomicUMin [[I32Ty]] [[A]] [[SCOPE]] [[SEQ]] [[B]] +; CHECK-NEXT: [[BC_A:%.*]] = OpBitcast %[[#]] [[A]] +; CHECK-NEXT: [[R:%.*]] = OpAtomicUMin [[I32Ty]] [[BC_A]] [[SCOPE]] [[SEQ]] [[B]] ; CHECK-NEXT: OpReturnValue [[R]] ; CHECK-NEXT: OpFunctionEnd define i32 @test_umin(i32* %ptr, i32 %val) { @@ -80,7 +86,8 @@ define i32 @test_umin(i32* %ptr, i32 %val) { ; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter ; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter ; CHECK-NEXT: OpLabel -; CHECK-NEXT: [[R:%.*]] = OpAtomicUMax [[I32Ty]] [[A]] [[SCOPE]] [[SEQ]] [[B]] +; CHECK-NEXT: [[BC_A:%.*]] = OpBitcast %[[#]] [[A]] +; CHECK-NEXT: [[R:%.*]] = OpAtomicUMax [[I32Ty]] [[BC_A]] [[SCOPE]] [[SEQ]] [[B]] ; CHECK-NEXT: OpReturnValue [[R]] ; CHECK-NEXT: OpFunctionEnd define i32 @test_umax(i32* %ptr, i32 %val) { @@ -92,7 +99,8 @@ define i32 @test_umax(i32* %ptr, i32 %val) { ; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter ; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter ; CHECK-NEXT: OpLabel -; CHECK-NEXT: [[R:%.*]] = OpAtomicAnd [[I32Ty]] [[A]] [[SCOPE]] [[SEQ]] [[B]] +; CHECK-NEXT: [[BC_A:%.*]] = OpBitcast %[[#]] [[A]] +; CHECK-NEXT: [[R:%.*]] = OpAtomicAnd [[I32Ty]] [[BC_A]] [[SCOPE]] [[SEQ]] [[B]] ; CHECK-NEXT: OpReturnValue [[R]] ; CHECK-NEXT: OpFunctionEnd define i32 @test_and(i32* %ptr, i32 %val) { @@ -104,7 +112,8 @@ define i32 @test_and(i32* %ptr, i32 %val) { ; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter ; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter ; CHECK-NEXT: OpLabel -; CHECK-NEXT: [[R:%.*]] = OpAtomicOr [[I32Ty]] [[A]] [[SCOPE]] [[SEQ]] [[B]] +; CHECK-NEXT: [[BC_A:%.*]] = OpBitcast %[[#]] [[A]] +; CHECK-NEXT: [[R:%.*]] = OpAtomicOr [[I32Ty]] [[BC_A]] [[SCOPE]] [[SEQ]] [[B]] ; CHECK-NEXT: OpReturnValue [[R]] ; CHECK-NEXT: OpFunctionEnd define i32 @test_or(i32* %ptr, i32 %val) { @@ -116,7 +125,8 @@ define i32 @test_or(i32* %ptr, i32 %val) { ; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter ; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter ; CHECK-NEXT: OpLabel -; CHECK-NEXT: [[R:%.*]] = OpAtomicXor [[I32Ty]] [[A]] [[SCOPE]] [[SEQ]] [[B]] +; CHECK-NEXT: [[BC_A:%.*]] = OpBitcast %[[#]] [[A]] +; CHECK-NEXT: [[R:%.*]] = OpAtomicXor [[I32Ty]] [[BC_A]] [[SCOPE]] [[SEQ]] [[B]] ; CHECK-NEXT: OpReturnValue [[R]] ; CHECK-NEXT: OpFunctionEnd define i32 @test_xor(i32* %ptr, i32 %val) { diff --git a/llvm/test/CodeGen/SPIRV/pointers/bitcast-fix-accesschain.ll b/llvm/test/CodeGen/SPIRV/pointers/bitcast-fix-accesschain.ll new file mode 100644 index 000000000000..7fae6ca2c48c --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/pointers/bitcast-fix-accesschain.ll @@ -0,0 +1,37 @@ +; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %} + +; CHECK-DAG: %[[#TYCHAR:]] = OpTypeInt 8 0 +; CHECK-DAG: %[[#TYCHARPTR:]] = OpTypePointer Function %[[#TYCHAR]] +; CHECK-DAG: %[[#TYINT32:]] = OpTypeInt 32 0 +; CHECK-DAG: %[[#TYSTRUCTINT32:]] = OpTypeStruct %[[#TYINT32]] +; CHECK-DAG: %[[#TYARRAY:]] = OpTypeArray %[[#TYSTRUCTINT32]] %[[#]] +; CHECK-DAG: %[[#TYSTRUCT:]] = OpTypeStruct %[[#TYARRAY]] +; CHECK-DAG: %[[#TYSTRUCTPTR:]] = OpTypePointer Function %[[#TYSTRUCT]] +; CHECK-DAG: %[[#TYINT64:]] = OpTypeInt 64 0 +; CHECK-DAG: %[[#TYINT64PTR:]] = OpTypePointer Function %[[#TYINT64]] +; CHECK: OpFunction +; CHECK: %[[#PTRTOSTRUCT:]] = OpFunctionParameter %[[#TYSTRUCTPTR]] +; CHECK: %[[#PTRTOCHAR:]] = OpBitcast %[[#TYCHARPTR]] %[[#PTRTOSTRUCT]] +; CHECK-NEXT: OpInBoundsPtrAccessChain %[[#TYCHARPTR]] %[[#PTRTOCHAR]] +; CHECK: OpFunction +; CHECK: %[[#PTRTOSTRUCT2:]] = OpFunctionParameter %[[#TYSTRUCTPTR]] +; CHECK: %[[#ELEM:]] = OpInBoundsPtrAccessChain %[[#TYSTRUCTPTR]] %[[#PTRTOSTRUCT2]] +; CHECK-NEXT: %[[#TOLOAD:]] = OpBitcast %[[#TYINT64PTR]] %[[#ELEM]] +; CHECK-NEXT: OpLoad %[[#TYINT64]] %[[#TOLOAD]] + +%struct.S = type { i32 } +%struct.__wrapper_class = type { [7 x %struct.S] } + +define spir_kernel void @foo1(ptr noundef byval(%struct.__wrapper_class) align 4 %_arg_Arr) { +entry: + %elem = getelementptr inbounds i8, ptr %_arg_Arr, i64 0 + ret void +} + +define spir_kernel void @foo2(ptr noundef byval(%struct.__wrapper_class) align 4 %_arg_Arr) { +entry: + %elem = getelementptr inbounds %struct.__wrapper_class, ptr %_arg_Arr, i64 0 + %data = load i64, ptr %elem + ret void +} diff --git a/llvm/test/CodeGen/SPIRV/pointers/type-deduce-by-call-complex.ll b/llvm/test/CodeGen/SPIRV/pointers/type-deduce-by-call-complex.ll new file mode 100644 index 000000000000..ea7a22c31d0e --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/pointers/type-deduce-by-call-complex.ll @@ -0,0 +1,29 @@ +; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %} + +; CHECK-SPIRV-DAG: %[[Long:.*]] = OpTypeInt 32 0 +; CHECK-SPIRV-DAG: %[[Void:.*]] = OpTypeVoid +; CHECK-SPIRV-DAG: %[[Struct:.*]] = OpTypeStruct %[[Long]] +; CHECK-SPIRV-DAG: %[[StructPtr:.*]] = OpTypePointer Generic %[[Struct]] +; CHECK-SPIRV-DAG: %[[Function:.*]] = OpTypeFunction %[[Void]] %[[StructPtr]] +; CHECK-SPIRV-DAG: %[[Const:.*]] = OpConstantNull %[[Struct]] +; CHECK-SPIRV-DAG: %[[CrossStructPtr:.*]] = OpTypePointer CrossWorkgroup %[[Struct]] +; CHECK-SPIRV-DAG: %[[Var:.*]] = OpVariable %[[CrossStructPtr]] CrossWorkgroup %[[Const]] +; CHECK-SPIRV: %[[Foo:.*]] = OpFunction %[[Void]] None %[[Function]] +; CHECK-SPIRV-NEXT: OpFunctionParameter %[[StructPtr]] +; CHECK-SPIRV: %[[Casted:.*]] = OpPtrCastToGeneric %[[StructPtr]] %[[Var]] +; CHECK-SPIRV-NEXT: OpFunctionCall %[[Void]] %[[Foo]] %[[Casted]] + +%struct.global_ctor_dtor = type { i32 } +@g1 = addrspace(1) global %struct.global_ctor_dtor zeroinitializer + +define linkonce_odr spir_func void @foo(ptr addrspace(4) %this) { +entry: + ret void +} + +define internal spir_func void @bar() { +entry: + call spir_func void @foo(ptr addrspace(4) addrspacecast (ptr addrspace(1) @g1 to ptr addrspace(4))) + ret void +} -- GitLab From 6654235594d86e7ed70abb7358ed25029d1560e5 Mon Sep 17 00:00:00 2001 From: Sizov Nikita Date: Tue, 2 Apr 2024 12:39:49 +0300 Subject: [PATCH 040/447] [SelectionDAG] implement computeKnownBits for add AVG* instructions (#86754) knownBits calculation for **AVGFLOORU** / **AVGFLOORS** / **AVGCEILU** / **AVGCEILS** instructions Prerequisite for #76644 --- .../lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 15 ++++-- .../CodeGen/AArch64SelectionDAGTest.cpp | 48 +++++++++++++++++++ 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index e8d1ac1d3a91..e3b76b95eb86 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -3419,13 +3419,18 @@ KnownBits SelectionDAG::computeKnownBits(SDValue Op, const APInt &DemandedElts, Known = KnownBits::mulhs(Known, Known2); break; } - case ISD::AVGCEILU: { + case ISD::AVGFLOORU: + case ISD::AVGCEILU: + case ISD::AVGFLOORS: + case ISD::AVGCEILS: { + bool IsCeil = Opcode == ISD::AVGCEILU || Opcode == ISD::AVGCEILS; + bool IsSigned = Opcode == ISD::AVGFLOORS || Opcode == ISD::AVGCEILS; Known = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); Known2 = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); - Known = Known.zext(BitWidth + 1); - Known2 = Known2.zext(BitWidth + 1); - KnownBits One = KnownBits::makeConstant(APInt(1, 1)); - Known = KnownBits::computeForAddCarry(Known, Known2, One); + Known = IsSigned ? Known.sext(BitWidth + 1) : Known.zext(BitWidth + 1); + Known2 = IsSigned ? Known2.sext(BitWidth + 1) : Known2.zext(BitWidth + 1); + KnownBits Carry = KnownBits::makeConstant(APInt(1, IsCeil ? 1 : 0)); + Known = KnownBits::computeForAddCarry(Known, Known2, Carry); Known = Known.extractBits(BitWidth, 1); break; } diff --git a/llvm/unittests/CodeGen/AArch64SelectionDAGTest.cpp b/llvm/unittests/CodeGen/AArch64SelectionDAGTest.cpp index e0772684e3a9..27bcad7c24c4 100644 --- a/llvm/unittests/CodeGen/AArch64SelectionDAGTest.cpp +++ b/llvm/unittests/CodeGen/AArch64SelectionDAGTest.cpp @@ -796,4 +796,52 @@ TEST_F(AArch64SelectionDAGTest, computeKnownBits_extload_knownnegative) { EXPECT_EQ(Known.One, APInt(32, 0xfffffff0)); } +TEST_F(AArch64SelectionDAGTest, + computeKnownBits_AVGFLOORU_AVGFLOORS_AVGCEILU_AVGCEILS) { + SDLoc Loc; + auto Int8VT = EVT::getIntegerVT(Context, 8); + auto Int16VT = EVT::getIntegerVT(Context, 16); + auto Int8Vec8VT = EVT::getVectorVT(Context, Int8VT, 8); + auto Int16Vec8VT = EVT::getVectorVT(Context, Int16VT, 8); + + SDValue UnknownOp0 = DAG->getRegister(0, Int8Vec8VT); + SDValue UnknownOp1 = DAG->getRegister(1, Int8Vec8VT); + + SDValue ZextOp0 = + DAG->getNode(ISD::ZERO_EXTEND, Loc, Int16Vec8VT, UnknownOp0); + SDValue ZextOp1 = + DAG->getNode(ISD::ZERO_EXTEND, Loc, Int16Vec8VT, UnknownOp1); + // ZextOp0 = 00000000???????? + // ZextOp1 = 00000000???????? + // => (for all AVG* instructions) + // Known.Zero = 1111111100000000 (0xFF00) + // Known.One = 0000000000000000 (0x0000) + auto Zeroes = APInt(16, 0xFF00); + auto Ones = APInt(16, 0x0000); + + SDValue AVGFLOORU = + DAG->getNode(ISD::AVGFLOORU, Loc, Int16Vec8VT, ZextOp0, ZextOp1); + KnownBits KnownAVGFLOORU = DAG->computeKnownBits(AVGFLOORU); + EXPECT_EQ(KnownAVGFLOORU.Zero, Zeroes); + EXPECT_EQ(KnownAVGFLOORU.One, Ones); + + SDValue AVGFLOORS = + DAG->getNode(ISD::AVGFLOORU, Loc, Int16Vec8VT, ZextOp0, ZextOp1); + KnownBits KnownAVGFLOORS = DAG->computeKnownBits(AVGFLOORS); + EXPECT_EQ(KnownAVGFLOORS.Zero, Zeroes); + EXPECT_EQ(KnownAVGFLOORS.One, Ones); + + SDValue AVGCEILU = + DAG->getNode(ISD::AVGCEILU, Loc, Int16Vec8VT, ZextOp0, ZextOp1); + KnownBits KnownAVGCEILU = DAG->computeKnownBits(AVGCEILU); + EXPECT_EQ(KnownAVGCEILU.Zero, Zeroes); + EXPECT_EQ(KnownAVGCEILU.One, Ones); + + SDValue AVGCEILS = + DAG->getNode(ISD::AVGCEILS, Loc, Int16Vec8VT, ZextOp0, ZextOp1); + KnownBits KnownAVGCEILS = DAG->computeKnownBits(AVGCEILS); + EXPECT_EQ(KnownAVGCEILS.Zero, Zeroes); + EXPECT_EQ(KnownAVGCEILS.One, Ones); +} + } // end namespace llvm -- GitLab From 89cfae41ecc043f8c47be4dea4b7c740d4f950b3 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Tue, 2 Apr 2024 11:37:20 +0200 Subject: [PATCH 041/447] [mlir] Add missing #include header for std::is_pointer --- mlir/include/mlir/IR/OwningOpRef.h | 1 + 1 file changed, 1 insertion(+) diff --git a/mlir/include/mlir/IR/OwningOpRef.h b/mlir/include/mlir/IR/OwningOpRef.h index eb4bf2dc67e3..0c35eae8de09 100644 --- a/mlir/include/mlir/IR/OwningOpRef.h +++ b/mlir/include/mlir/IR/OwningOpRef.h @@ -13,6 +13,7 @@ #ifndef MLIR_IR_OWNINGOPREF_H #define MLIR_IR_OWNINGOPREF_H +#include #include namespace mlir { -- GitLab From 16da9d53519214475c04109d953022f272ac8022 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Tue, 2 Apr 2024 10:43:34 +0100 Subject: [PATCH 042/447] [VPlan] Remove redundant set of debug loc in VPInstruction (NFCI). Consistently use setDebugLocFrom and remove redundant setDebugLocFrom. --- llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp index 23d025cf33ea..124ae3108d8a 100644 --- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp +++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp @@ -455,8 +455,6 @@ Value *VPInstruction::generatePerPart(VPTransformState &State, unsigned Part) { RecurKind RK = RdxDesc.getRecurrenceKind(); - State.setDebugLocFrom(getDebugLoc()); - VPValue *LoopExitingDef = getOperand(1); Type *PhiTy = OrigPhi->getType(); VectorParts RdxParts(State.UF); @@ -551,7 +549,7 @@ void VPInstruction::execute(VPTransformState &State) { "Recipe not a FPMathOp but has fast-math flags?"); if (hasFastMathFlags()) State.Builder.setFastMathFlags(getFastMathFlags()); - State.Builder.SetCurrentDebugLocation(getDebugLoc()); + State.setDebugLocFrom(getDebugLoc()); bool GeneratesPerFirstLaneOnly = canGenerateScalarForFirstLane() && (vputils::onlyFirstLaneUsed(this) || -- GitLab From 46246683a61a081d9d78cf987fd4f024556ecdc8 Mon Sep 17 00:00:00 2001 From: Rin Dobrescu Date: Tue, 2 Apr 2024 10:47:51 +0100 Subject: [PATCH 043/447] [AArch64] Update Neoverse V2 FSQRT execution units in schedule model. (#86803) This patch updates the SVE FSQRT instruction execution units to be able to run on VX0 and VX2. --- llvm/lib/Target/AArch64/AArch64SchedNeoverseV2.td | 10 ++++------ .../AArch64/Neoverse/V2-sve-instructions.s | 14 +++++++------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/llvm/lib/Target/AArch64/AArch64SchedNeoverseV2.td b/llvm/lib/Target/AArch64/AArch64SchedNeoverseV2.td index f10b94523d2e..4d7f44e7b9b9 100644 --- a/llvm/lib/Target/AArch64/AArch64SchedNeoverseV2.td +++ b/llvm/lib/Target/AArch64/AArch64SchedNeoverseV2.td @@ -1076,14 +1076,12 @@ def V2Write_7cyc_1V02_7rc : SchedWriteRes<[V2UnitV02]> { let Latency = 7; let def V2Write_10cyc_1V02_5rc : SchedWriteRes<[V2UnitV02]> { let Latency = 10; let ReleaseAtCycles = [ 5]; } def V2Write_10cyc_1V02_9rc : SchedWriteRes<[V2UnitV02]> { let Latency = 10; let ReleaseAtCycles = [ 9]; } def V2Write_10cyc_1V02_10rc : SchedWriteRes<[V2UnitV02]> { let Latency = 10; let ReleaseAtCycles = [10]; } -def V2Write_10cyc_1V0_9rc : SchedWriteRes<[V2UnitV0]> { let Latency = 10; let ReleaseAtCycles = [ 9]; } def V2Write_10cyc_1V1_9rc : SchedWriteRes<[V2UnitV1]> { let Latency = 10; let ReleaseAtCycles = [ 9]; } -def V2Write_13cyc_1V0_12rc : SchedWriteRes<[V2UnitV0]> { let Latency = 13; let ReleaseAtCycles = [12]; } def V2Write_13cyc_1V02_12rc : SchedWriteRes<[V2UnitV02]> { let Latency = 13; let ReleaseAtCycles = [12]; } def V2Write_13cyc_1V02_13rc : SchedWriteRes<[V2UnitV02]> { let Latency = 13; let ReleaseAtCycles = [13]; } def V2Write_15cyc_1V02_14rc : SchedWriteRes<[V2UnitV02]> { let Latency = 15; let ReleaseAtCycles = [14]; } +def V2Write_16cyc_1V02_14rc : SchedWriteRes<[V2UnitV02]> { let Latency = 16; let ReleaseAtCycles = [14]; } def V2Write_16cyc_1V02_15rc : SchedWriteRes<[V2UnitV02]> { let Latency = 16; let ReleaseAtCycles = [15]; } -def V2Write_16cyc_1V0_14rc : SchedWriteRes<[V2UnitV0]> { let Latency = 16; let ReleaseAtCycles = [14]; } // Miscellaneous // ----------------------------------------------------------------------------- @@ -2567,13 +2565,13 @@ def : InstRW<[V2Write_4cyc_2V02], (instregex "^FRINT[AIMNPXZ]_ZPmZ_S")>; def : InstRW<[V2Write_3cyc_1V02], (instregex "^FRINT[AIMNPXZ]_ZPmZ_D")>; // Floating point square root, F16 -def : InstRW<[V2Write_13cyc_1V0_12rc], (instregex "^FSQRT_ZPmZ_H")>; +def : InstRW<[V2Write_13cyc_1V02_12rc], (instregex "^FSQRT_ZPmZ_H")>; // Floating point square root, F32 -def : InstRW<[V2Write_10cyc_1V0_9rc], (instregex "^FSQRT_ZPmZ_S")>; +def : InstRW<[V2Write_10cyc_1V02_9rc], (instregex "^FSQRT_ZPmZ_S")>; // Floating point square root, F64 -def : InstRW<[V2Write_16cyc_1V0_14rc], (instregex "^FSQRT_ZPmZ_D")>; +def : InstRW<[V2Write_16cyc_1V02_14rc], (instregex "^FSQRT_ZPmZ_D")>; // Floating point trigonometric exponentiation def : InstRW<[V2Write_3cyc_1V1], (instregex "^FEXPA_ZZ_[HSD]")>; diff --git a/llvm/test/tools/llvm-mca/AArch64/Neoverse/V2-sve-instructions.s b/llvm/test/tools/llvm-mca/AArch64/Neoverse/V2-sve-instructions.s index 4d6ce706b052..acd355682494 100644 --- a/llvm/test/tools/llvm-mca/AArch64/Neoverse/V2-sve-instructions.s +++ b/llvm/test/tools/llvm-mca/AArch64/Neoverse/V2-sve-instructions.s @@ -4278,9 +4278,9 @@ zip2 z31.s, z31.s, z31.s # CHECK-NEXT: 1 3 0.25 fscale z0.d, p7/m, z0.d, z31.d # CHECK-NEXT: 1 3 0.25 fscale z0.h, p7/m, z0.h, z31.h # CHECK-NEXT: 1 3 0.25 fscale z0.s, p7/m, z0.s, z31.s -# CHECK-NEXT: 1 16 14.00 fsqrt z31.d, p7/m, z31.d -# CHECK-NEXT: 1 13 12.00 fsqrt z31.h, p7/m, z31.h -# CHECK-NEXT: 1 10 9.00 fsqrt z31.s, p7/m, z31.s +# CHECK-NEXT: 1 16 7.00 fsqrt z31.d, p7/m, z31.d +# CHECK-NEXT: 1 13 6.00 fsqrt z31.h, p7/m, z31.h +# CHECK-NEXT: 1 10 4.50 fsqrt z31.s, p7/m, z31.s # CHECK-NEXT: 1 2 0.25 fsub z0.d, p0/m, z0.d, #0.5 # CHECK-NEXT: 1 2 0.25 fsub z0.d, p7/m, z0.d, z31.d # CHECK-NEXT: 1 2 0.25 fsub z0.d, z1.d, z31.d @@ -6861,7 +6861,7 @@ zip2 z31.s, z31.s, z31.s # CHECK: Resource pressure per iteration: # CHECK-NEXT: [0.0] [0.1] [1.0] [1.1] [2] [3.0] [3.1] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] -# CHECK-NEXT: - - - - 245.00 651.00 651.00 570.50 272.50 83.75 83.75 81.75 81.75 1554.25 1281.75 776.75 748.25 +# CHECK-NEXT: - - - - 245.00 651.00 651.00 570.50 272.50 83.75 83.75 81.75 81.75 1536.75 1281.75 794.25 748.25 # CHECK: Resource pressure by instruction: # CHECK-NEXT: [0.0] [0.1] [1.0] [1.1] [2] [3.0] [3.1] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] Instructions: @@ -7718,9 +7718,9 @@ zip2 z31.s, z31.s, z31.s # CHECK-NEXT: - - - - - - - - - - - - - 0.25 0.25 0.25 0.25 fscale z0.d, p7/m, z0.d, z31.d # CHECK-NEXT: - - - - - - - - - - - - - 0.25 0.25 0.25 0.25 fscale z0.h, p7/m, z0.h, z31.h # CHECK-NEXT: - - - - - - - - - - - - - 0.25 0.25 0.25 0.25 fscale z0.s, p7/m, z0.s, z31.s -# CHECK-NEXT: - - - - - - - - - - - - - 14.00 - - - fsqrt z31.d, p7/m, z31.d -# CHECK-NEXT: - - - - - - - - - - - - - 12.00 - - - fsqrt z31.h, p7/m, z31.h -# CHECK-NEXT: - - - - - - - - - - - - - 9.00 - - - fsqrt z31.s, p7/m, z31.s +# CHECK-NEXT: - - - - - - - - - - - - - 7.00 - 7.00 - fsqrt z31.d, p7/m, z31.d +# CHECK-NEXT: - - - - - - - - - - - - - 6.00 - 6.00 - fsqrt z31.h, p7/m, z31.h +# CHECK-NEXT: - - - - - - - - - - - - - 4.50 - 4.50 - fsqrt z31.s, p7/m, z31.s # CHECK-NEXT: - - - - - - - - - - - - - 0.25 0.25 0.25 0.25 fsub z0.d, p0/m, z0.d, #0.5 # CHECK-NEXT: - - - - - - - - - - - - - 0.25 0.25 0.25 0.25 fsub z0.d, p7/m, z0.d, z31.d # CHECK-NEXT: - - - - - - - - - - - - - 0.25 0.25 0.25 0.25 fsub z0.d, z1.d, z31.d -- GitLab From 1d06f41b72e429a5b3ba318ff639b8b997e21ff8 Mon Sep 17 00:00:00 2001 From: Simon Pilgrim Date: Tue, 2 Apr 2024 10:58:45 +0100 Subject: [PATCH 044/447] [VectorCombine] foldBitcastShuffle - peek through any residual bitcasts before creating a new bitcast on top (#86119) Encountered while working on #67803, wading through the chains of bitcasts that SSE intrinsics introduces - this patch helps prevents cases where the bitcast chains aren't cleared out and we can't perform further combines until after InstCombine/InstSimplify has run. --- llvm/lib/Transforms/Vectorize/VectorCombine.cpp | 12 ++++++++++-- .../VectorCombine/X86/shuffle-inseltpoison.ll | 6 ++---- llvm/test/Transforms/VectorCombine/X86/shuffle.ll | 6 ++---- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp index 7e86137f23f3..af5e7c9bc385 100644 --- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp +++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp @@ -135,6 +135,14 @@ private: }; } // namespace +/// Return the source operand of a potentially bitcasted value. If there is no +/// bitcast, return the input value itself. +static Value *peekThroughBitcasts(Value *V) { + while (auto *BitCast = dyn_cast(V)) + V = BitCast->getOperand(0); + return V; +} + static bool canWidenLoad(LoadInst *Load, const TargetTransformInfo &TTI) { // Do not widen load if atomic/volatile or under asan/hwasan/memtag/tsan. // The widened load may load data from dirty regions or create data races @@ -751,8 +759,8 @@ bool VectorCombine::foldBitcastShuffle(Instruction &I) { // bitcast (shuf V0, V1, MaskC) --> shuf (bitcast V0), (bitcast V1), MaskC' ++NumShufOfBitcast; - Value *CastV0 = Builder.CreateBitCast(V0, NewShuffleTy); - Value *CastV1 = Builder.CreateBitCast(V1, NewShuffleTy); + Value *CastV0 = Builder.CreateBitCast(peekThroughBitcasts(V0), NewShuffleTy); + Value *CastV1 = Builder.CreateBitCast(peekThroughBitcasts(V1), NewShuffleTy); Value *Shuf = Builder.CreateShuffleVector(CastV0, CastV1, NewMask); replaceValue(I, *Shuf); return true; diff --git a/llvm/test/Transforms/VectorCombine/X86/shuffle-inseltpoison.ll b/llvm/test/Transforms/VectorCombine/X86/shuffle-inseltpoison.ll index 8c5c6656ca17..74a58c8d3136 100644 --- a/llvm/test/Transforms/VectorCombine/X86/shuffle-inseltpoison.ll +++ b/llvm/test/Transforms/VectorCombine/X86/shuffle-inseltpoison.ll @@ -133,8 +133,7 @@ define <2 x i64> @PR35454_1(<2 x i64> %v) { ; SSE-NEXT: ret <2 x i64> [[BC3]] ; ; AVX-LABEL: @PR35454_1( -; AVX-NEXT: [[BC:%.*]] = bitcast <2 x i64> [[V:%.*]] to <4 x i32> -; AVX-NEXT: [[TMP1:%.*]] = bitcast <4 x i32> [[BC]] to <16 x i8> +; AVX-NEXT: [[TMP1:%.*]] = bitcast <2 x i64> [[V:%.*]] to <16 x i8> ; AVX-NEXT: [[BC1:%.*]] = shufflevector <16 x i8> [[TMP1]], <16 x i8> poison, <16 x i32> ; AVX-NEXT: [[ADD:%.*]] = shl <16 x i8> [[BC1]], ; AVX-NEXT: [[BC2:%.*]] = bitcast <16 x i8> [[ADD]] to <4 x i32> @@ -164,8 +163,7 @@ define <2 x i64> @PR35454_2(<2 x i64> %v) { ; SSE-NEXT: ret <2 x i64> [[BC3]] ; ; AVX-LABEL: @PR35454_2( -; AVX-NEXT: [[BC:%.*]] = bitcast <2 x i64> [[V:%.*]] to <4 x i32> -; AVX-NEXT: [[TMP1:%.*]] = bitcast <4 x i32> [[BC]] to <8 x i16> +; AVX-NEXT: [[TMP1:%.*]] = bitcast <2 x i64> [[V:%.*]] to <8 x i16> ; AVX-NEXT: [[BC1:%.*]] = shufflevector <8 x i16> [[TMP1]], <8 x i16> poison, <8 x i32> ; AVX-NEXT: [[ADD:%.*]] = shl <8 x i16> [[BC1]], ; AVX-NEXT: [[BC2:%.*]] = bitcast <8 x i16> [[ADD]] to <4 x i32> diff --git a/llvm/test/Transforms/VectorCombine/X86/shuffle.ll b/llvm/test/Transforms/VectorCombine/X86/shuffle.ll index 60cfc4d4b070..d1484fd5ab33 100644 --- a/llvm/test/Transforms/VectorCombine/X86/shuffle.ll +++ b/llvm/test/Transforms/VectorCombine/X86/shuffle.ll @@ -133,8 +133,7 @@ define <2 x i64> @PR35454_1(<2 x i64> %v) { ; SSE-NEXT: ret <2 x i64> [[BC3]] ; ; AVX-LABEL: @PR35454_1( -; AVX-NEXT: [[BC:%.*]] = bitcast <2 x i64> [[V:%.*]] to <4 x i32> -; AVX-NEXT: [[TMP1:%.*]] = bitcast <4 x i32> [[BC]] to <16 x i8> +; AVX-NEXT: [[TMP1:%.*]] = bitcast <2 x i64> [[V:%.*]] to <16 x i8> ; AVX-NEXT: [[BC1:%.*]] = shufflevector <16 x i8> [[TMP1]], <16 x i8> poison, <16 x i32> ; AVX-NEXT: [[ADD:%.*]] = shl <16 x i8> [[BC1]], ; AVX-NEXT: [[BC2:%.*]] = bitcast <16 x i8> [[ADD]] to <4 x i32> @@ -164,8 +163,7 @@ define <2 x i64> @PR35454_2(<2 x i64> %v) { ; SSE-NEXT: ret <2 x i64> [[BC3]] ; ; AVX-LABEL: @PR35454_2( -; AVX-NEXT: [[BC:%.*]] = bitcast <2 x i64> [[V:%.*]] to <4 x i32> -; AVX-NEXT: [[TMP1:%.*]] = bitcast <4 x i32> [[BC]] to <8 x i16> +; AVX-NEXT: [[TMP1:%.*]] = bitcast <2 x i64> [[V:%.*]] to <8 x i16> ; AVX-NEXT: [[BC1:%.*]] = shufflevector <8 x i16> [[TMP1]], <8 x i16> poison, <8 x i32> ; AVX-NEXT: [[ADD:%.*]] = shl <8 x i16> [[BC1]], ; AVX-NEXT: [[BC2:%.*]] = bitcast <8 x i16> [[ADD]] to <4 x i32> -- GitLab From 5b66b6a32ad89562732ad6a81c84783486b6187a Mon Sep 17 00:00:00 2001 From: Ivan Butygin Date: Tue, 2 Apr 2024 13:30:45 +0300 Subject: [PATCH 045/447] [mlir][pass] Add composite pass utility (#87166) Composite pass allows to run sequence of passes in the loop until fixed point or maximum number of iterations is reached. The usual candidates are canonicalize+CSE as canonicalize can open more opportunities for CSE and vice-versa. --- mlir/include/mlir/Transforms/Passes.h | 7 ++ mlir/include/mlir/Transforms/Passes.td | 17 +++ mlir/lib/Transforms/CMakeLists.txt | 1 + mlir/lib/Transforms/CompositePass.cpp | 105 ++++++++++++++++++ mlir/test/Transforms/composite-pass.mlir | 26 +++++ mlir/test/lib/Transforms/CMakeLists.txt | 1 + .../test/lib/Transforms/TestCompositePass.cpp | 38 +++++++ mlir/tools/mlir-opt/mlir-opt.cpp | 2 + 8 files changed, 197 insertions(+) create mode 100644 mlir/lib/Transforms/CompositePass.cpp create mode 100644 mlir/test/Transforms/composite-pass.mlir create mode 100644 mlir/test/lib/Transforms/TestCompositePass.cpp diff --git a/mlir/include/mlir/Transforms/Passes.h b/mlir/include/mlir/Transforms/Passes.h index 11f5b23e62c6..58bd61b2ae8b 100644 --- a/mlir/include/mlir/Transforms/Passes.h +++ b/mlir/include/mlir/Transforms/Passes.h @@ -43,6 +43,7 @@ class GreedyRewriteConfig; #define GEN_PASS_DECL_SYMBOLDCE #define GEN_PASS_DECL_SYMBOLPRIVATIZE #define GEN_PASS_DECL_TOPOLOGICALSORT +#define GEN_PASS_DECL_COMPOSITEFIXEDPOINTPASS #include "mlir/Transforms/Passes.h.inc" /// Creates an instance of the Canonicalizer pass, configured with default @@ -130,6 +131,12 @@ createSymbolPrivatizePass(ArrayRef excludeSymbols = {}); /// their producers. std::unique_ptr createTopologicalSortPass(); +/// Create composite pass, which runs provided set of passes until fixed point +/// or maximum number of iterations reached. +std::unique_ptr createCompositeFixedPointPass( + std::string name, llvm::function_ref populateFunc, + int maxIterations = 10); + //===----------------------------------------------------------------------===// // Registration //===----------------------------------------------------------------------===// diff --git a/mlir/include/mlir/Transforms/Passes.td b/mlir/include/mlir/Transforms/Passes.td index 51b2a27da639..1b40a87c63f2 100644 --- a/mlir/include/mlir/Transforms/Passes.td +++ b/mlir/include/mlir/Transforms/Passes.td @@ -552,4 +552,21 @@ def TopologicalSort : Pass<"topological-sort"> { let constructor = "mlir::createTopologicalSortPass()"; } +def CompositeFixedPointPass : Pass<"composite-fixed-point-pass"> { + let summary = "Composite fixed point pass"; + let description = [{ + Composite pass runs provided set of passes until fixed point or maximum + number of iterations reached. + }]; + + let options = [ + Option<"name", "name", "std::string", /*default=*/"\"CompositeFixedPointPass\"", + "Composite pass display name">, + Option<"pipelineStr", "pipeline", "std::string", /*default=*/"", + "Composite pass inner pipeline">, + Option<"maxIter", "max-iterations", "int", /*default=*/"10", + "Maximum number of iterations if inner pipeline">, + ]; +} + #endif // MLIR_TRANSFORMS_PASSES diff --git a/mlir/lib/Transforms/CMakeLists.txt b/mlir/lib/Transforms/CMakeLists.txt index 6c32ecf8a2a2..90c0298fb5e4 100644 --- a/mlir/lib/Transforms/CMakeLists.txt +++ b/mlir/lib/Transforms/CMakeLists.txt @@ -2,6 +2,7 @@ add_subdirectory(Utils) add_mlir_library(MLIRTransforms Canonicalizer.cpp + CompositePass.cpp ControlFlowSink.cpp CSE.cpp GenerateRuntimeVerification.cpp diff --git a/mlir/lib/Transforms/CompositePass.cpp b/mlir/lib/Transforms/CompositePass.cpp new file mode 100644 index 000000000000..b388a28da642 --- /dev/null +++ b/mlir/lib/Transforms/CompositePass.cpp @@ -0,0 +1,105 @@ +//===- CompositePass.cpp - Composite pass code ----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// CompositePass allows to run set of passes until fixed point is reached. +// +//===----------------------------------------------------------------------===// + +#include "mlir/Transforms/Passes.h" + +#include "mlir/Pass/Pass.h" +#include "mlir/Pass/PassManager.h" + +namespace mlir { +#define GEN_PASS_DEF_COMPOSITEFIXEDPOINTPASS +#include "mlir/Transforms/Passes.h.inc" +} // namespace mlir + +using namespace mlir; + +namespace { +struct CompositeFixedPointPass final + : public impl::CompositeFixedPointPassBase { + using CompositeFixedPointPassBase::CompositeFixedPointPassBase; + + CompositeFixedPointPass( + std::string name_, llvm::function_ref populateFunc, + int maxIterations) { + name = std::move(name_); + maxIter = maxIterations; + populateFunc(dynamicPM); + + llvm::raw_string_ostream os(pipelineStr); + dynamicPM.printAsTextualPipeline(os); + } + + LogicalResult initializeOptions( + StringRef options, + function_ref errorHandler) override { + if (failed(CompositeFixedPointPassBase::initializeOptions(options, + errorHandler))) + return failure(); + + if (failed(parsePassPipeline(pipelineStr, dynamicPM))) + return errorHandler("Failed to parse composite pass pipeline"); + + return success(); + } + + LogicalResult initialize(MLIRContext *context) override { + if (maxIter <= 0) + return emitError(UnknownLoc::get(context)) + << "Invalid maxIterations value: " << maxIter << "\n"; + + return success(); + } + + void getDependentDialects(DialectRegistry ®istry) const override { + dynamicPM.getDependentDialects(registry); + } + + void runOnOperation() override { + auto op = getOperation(); + OperationFingerPrint fp(op); + + int currentIter = 0; + int maxIterVal = maxIter; + while (true) { + if (failed(runPipeline(dynamicPM, op))) + return signalPassFailure(); + + if (currentIter++ >= maxIterVal) { + op->emitWarning("Composite pass \"" + llvm::Twine(name) + + "\"+ didn't converge in " + llvm::Twine(maxIterVal) + + " iterations"); + break; + } + + OperationFingerPrint newFp(op); + if (newFp == fp) + break; + + fp = newFp; + } + } + +protected: + llvm::StringRef getName() const override { return name; } + +private: + OpPassManager dynamicPM; +}; +} // namespace + +std::unique_ptr mlir::createCompositeFixedPointPass( + std::string name, llvm::function_ref populateFunc, + int maxIterations) { + + return std::make_unique(std::move(name), + populateFunc, maxIterations); +} diff --git a/mlir/test/Transforms/composite-pass.mlir b/mlir/test/Transforms/composite-pass.mlir new file mode 100644 index 000000000000..829470c2c9aa --- /dev/null +++ b/mlir/test/Transforms/composite-pass.mlir @@ -0,0 +1,26 @@ +// RUN: mlir-opt %s --log-actions-to=- --test-composite-fixed-point-pass -split-input-file | FileCheck %s +// RUN: mlir-opt %s --log-actions-to=- --composite-fixed-point-pass='name=TestCompositePass pipeline=any(canonicalize,cse)' -split-input-file | FileCheck %s + +// CHECK-LABEL: running `TestCompositePass` +// CHECK: running `Canonicalizer` +// CHECK: running `CSE` +// CHECK-NOT: running `Canonicalizer` +// CHECK-NOT: running `CSE` +func.func @test() { + return +} + +// ----- + +// CHECK-LABEL: running `TestCompositePass` +// CHECK: running `Canonicalizer` +// CHECK: running `CSE` +// CHECK: running `Canonicalizer` +// CHECK: running `CSE` +// CHECK-NOT: running `Canonicalizer` +// CHECK-NOT: running `CSE` +func.func @test() { +// this constant will be canonicalized away, causing another pass iteration + %0 = arith.constant 1.5 : f32 + return +} diff --git a/mlir/test/lib/Transforms/CMakeLists.txt b/mlir/test/lib/Transforms/CMakeLists.txt index 2a3a8608db54..a849b7ebd29e 100644 --- a/mlir/test/lib/Transforms/CMakeLists.txt +++ b/mlir/test/lib/Transforms/CMakeLists.txt @@ -20,6 +20,7 @@ endif() # Exclude tests from libMLIR.so add_mlir_library(MLIRTestTransforms TestCommutativityUtils.cpp + TestCompositePass.cpp TestConstantFold.cpp TestControlFlowSink.cpp TestInlining.cpp diff --git a/mlir/test/lib/Transforms/TestCompositePass.cpp b/mlir/test/lib/Transforms/TestCompositePass.cpp new file mode 100644 index 000000000000..5c0d93cc0d64 --- /dev/null +++ b/mlir/test/lib/Transforms/TestCompositePass.cpp @@ -0,0 +1,38 @@ +//===------ TestCompositePass.cpp --- composite test pass -----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements a pass to test the composite pass utility. +// +//===----------------------------------------------------------------------===// + +#include "mlir/Pass/Pass.h" +#include "mlir/Pass/PassManager.h" +#include "mlir/Pass/PassRegistry.h" +#include "mlir/Transforms/Passes.h" + +namespace mlir { +namespace test { +void registerTestCompositePass() { + registerPassPipeline( + "test-composite-fixed-point-pass", "Test composite pass", + [](OpPassManager &pm, StringRef optionsStr, + function_ref errorHandler) { + if (!optionsStr.empty()) + return failure(); + + pm.addPass(createCompositeFixedPointPass( + "TestCompositePass", [](OpPassManager &p) { + p.addPass(createCanonicalizerPass()); + p.addPass(createCSEPass()); + })); + return success(); + }, + [](function_ref) {}); +} +} // namespace test +} // namespace mlir diff --git a/mlir/tools/mlir-opt/mlir-opt.cpp b/mlir/tools/mlir-opt/mlir-opt.cpp index 82b3881792bf..6ce9f3041d6f 100644 --- a/mlir/tools/mlir-opt/mlir-opt.cpp +++ b/mlir/tools/mlir-opt/mlir-opt.cpp @@ -68,6 +68,7 @@ void registerTosaTestQuantUtilAPIPass(); void registerVectorizerTestPass(); namespace test { +void registerTestCompositePass(); void registerCommutativityUtils(); void registerConvertCallOpPass(); void registerInliner(); @@ -195,6 +196,7 @@ void registerTestPasses() { registerVectorizerTestPass(); registerTosaTestQuantUtilAPIPass(); + mlir::test::registerTestCompositePass(); mlir::test::registerCommutativityUtils(); mlir::test::registerConvertCallOpPass(); mlir::test::registerInliner(); -- GitLab From 2f48a1ff574573e7be170d39ab8de79d9db8bcea Mon Sep 17 00:00:00 2001 From: David Spickett Date: Tue, 2 Apr 2024 12:13:59 +0100 Subject: [PATCH 046/447] [lldb][FreeBSD] Add FreeBSD specific AT_HWCAP value (#84147) While adding register fields I realised that the AUXV values for Linux and FreeBSD disagree here. So I've added a FreeBSD specific HWCAP value that I can use from FreeBSD specific code. The alternative is translating GetAuxValue calls depending on platform, which requires that we know what we are at all times. Another way would be to convert the entries' values when we construct the AuxVector but the platform specific call that reads the data just returns a raw array. So adding another layer here is more disruption. --- lldb/source/Plugins/Process/Utility/AuxVector.h | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/lldb/source/Plugins/Process/Utility/AuxVector.h b/lldb/source/Plugins/Process/Utility/AuxVector.h index 3b0f55d35e5d..4175cb73b234 100644 --- a/lldb/source/Plugins/Process/Utility/AuxVector.h +++ b/lldb/source/Plugins/Process/Utility/AuxVector.h @@ -20,9 +20,9 @@ public: AuxVector(const lldb_private::DataExtractor &data); /// Constants describing the type of entry. - /// On Linux, running "LD_SHOW_AUXV=1 ./executable" will spew AUX + /// On Linux and FreeBSD, running "LD_SHOW_AUXV=1 ./executable" will spew AUX /// information. Added AUXV prefix to avoid potential conflicts with system- - /// defined macros + /// defined macros. For FreeBSD, the numbers can be found in sys/elf_common.h. enum EntryType { AUXV_AT_NULL = 0, ///< End of auxv. AUXV_AT_IGNORE = 1, ///< Ignore entry. @@ -39,6 +39,11 @@ public: AUXV_AT_EUID = 12, ///< Effective UID. AUXV_AT_GID = 13, ///< GID. AUXV_AT_EGID = 14, ///< Effective GID. + + // At this point Linux and FreeBSD diverge and many of the following values + // are Linux specific. If you use them make sure you are in Linux specific + // code or they have the same value on other platforms. + AUXV_AT_CLKTCK = 17, ///< Clock frequency (e.g. times(2)). AUXV_AT_PLATFORM = 15, ///< String identifying platform. AUXV_AT_HWCAP = @@ -60,6 +65,10 @@ public: AUXV_AT_L1D_CACHESHAPE = 35, AUXV_AT_L2_CACHESHAPE = 36, AUXV_AT_L3_CACHESHAPE = 37, + + // Platform specific values which may overlap the Linux values. + + AUXV_FREEBSD_AT_HWCAP = 25, ///< FreeBSD specific AT_HWCAP value. }; std::optional GetAuxValue(enum EntryType entry_type) const; -- GitLab From 198c3eecee50d90cdff4b7840cfa39eef5613870 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Tue, 2 Apr 2024 13:19:51 +0200 Subject: [PATCH 047/447] [bazel] Fix the format of libc_build_rules.bzl --- utils/bazel/llvm-project-overlay/libc/libc_build_rules.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/bazel/llvm-project-overlay/libc/libc_build_rules.bzl b/utils/bazel/llvm-project-overlay/libc/libc_build_rules.bzl index 7dc12bade260..80cf59d7ef12 100644 --- a/utils/bazel/llvm-project-overlay/libc/libc_build_rules.bzl +++ b/utils/bazel/llvm-project-overlay/libc/libc_build_rules.bzl @@ -92,7 +92,7 @@ def libc_function( # x86 targets have -mno-omit-leaf-frame-pointer. platform_copts = selects.with_or({ PLATFORM_CPU_X86_64: ["-mno-omit-leaf-frame-pointer"], - "//conditions:default": [] + "//conditions:default": [], }) copts = copts + platform_copts -- GitLab From a88a4da61a8eb3378bc333602d5b7e56a24cfb66 Mon Sep 17 00:00:00 2001 From: David Spickett Date: Tue, 2 Apr 2024 12:21:57 +0100 Subject: [PATCH 048/447] [lldb] clang-format AuxVector.h (#85057) Doing this in its own commit so the intent of 2f48a1ff574573e7be170d39ab8de79d9db8bcea is clearer. --- .../Plugins/Process/Utility/AuxVector.h | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/lldb/source/Plugins/Process/Utility/AuxVector.h b/lldb/source/Plugins/Process/Utility/AuxVector.h index 4175cb73b234..2670b34f6b0a 100644 --- a/lldb/source/Plugins/Process/Utility/AuxVector.h +++ b/lldb/source/Plugins/Process/Utility/AuxVector.h @@ -24,21 +24,21 @@ public: /// information. Added AUXV prefix to avoid potential conflicts with system- /// defined macros. For FreeBSD, the numbers can be found in sys/elf_common.h. enum EntryType { - AUXV_AT_NULL = 0, ///< End of auxv. - AUXV_AT_IGNORE = 1, ///< Ignore entry. - AUXV_AT_EXECFD = 2, ///< File descriptor of program. - AUXV_AT_PHDR = 3, ///< Program headers. - AUXV_AT_PHENT = 4, ///< Size of program header. - AUXV_AT_PHNUM = 5, ///< Number of program headers. - AUXV_AT_PAGESZ = 6, ///< Page size. - AUXV_AT_BASE = 7, ///< Interpreter base address. - AUXV_AT_FLAGS = 8, ///< Flags. - AUXV_AT_ENTRY = 9, ///< Program entry point. - AUXV_AT_NOTELF = 10, ///< Set if program is not an ELF. - AUXV_AT_UID = 11, ///< UID. - AUXV_AT_EUID = 12, ///< Effective UID. - AUXV_AT_GID = 13, ///< GID. - AUXV_AT_EGID = 14, ///< Effective GID. + AUXV_AT_NULL = 0, ///< End of auxv. + AUXV_AT_IGNORE = 1, ///< Ignore entry. + AUXV_AT_EXECFD = 2, ///< File descriptor of program. + AUXV_AT_PHDR = 3, ///< Program headers. + AUXV_AT_PHENT = 4, ///< Size of program header. + AUXV_AT_PHNUM = 5, ///< Number of program headers. + AUXV_AT_PAGESZ = 6, ///< Page size. + AUXV_AT_BASE = 7, ///< Interpreter base address. + AUXV_AT_FLAGS = 8, ///< Flags. + AUXV_AT_ENTRY = 9, ///< Program entry point. + AUXV_AT_NOTELF = 10, ///< Set if program is not an ELF. + AUXV_AT_UID = 11, ///< UID. + AUXV_AT_EUID = 12, ///< Effective UID. + AUXV_AT_GID = 13, ///< GID. + AUXV_AT_EGID = 14, ///< Effective GID. // At this point Linux and FreeBSD diverge and many of the following values // are Linux specific. If you use them make sure you are in Linux specific -- GitLab From 9a05a89d1ef73de7ab787071931f449935d841a7 Mon Sep 17 00:00:00 2001 From: Carlos Alberto Enciso Date: Tue, 2 Apr 2024 12:34:31 +0100 Subject: [PATCH 049/447] [speculative-execution] Hoists debug values unnecessarily. (#85782) After https://reviews.llvm.org/D81730: `SpeculativeExecutionPass::considerHoistingFromTo` hoists instructions, including debug intrinsics, as long as none of their used values are instructions that appear prior in the block that are not being hoisted. This behaviour has been duplicated for DPValues to get rid of a binary difference. The correct solution is not hoist these debug values at all, whichever format they're in. --- .../Scalar/SpeculativeExecution.cpp | 51 +++++++++---------- .../SpeculativeExecution/PR46267.ll | 2 +- 2 files changed, 25 insertions(+), 28 deletions(-) diff --git a/llvm/lib/Transforms/Scalar/SpeculativeExecution.cpp b/llvm/lib/Transforms/Scalar/SpeculativeExecution.cpp index 5efc340da60b..f921ee72a0a1 100644 --- a/llvm/lib/Transforms/Scalar/SpeculativeExecution.cpp +++ b/llvm/lib/Transforms/Scalar/SpeculativeExecution.cpp @@ -260,11 +260,31 @@ static InstructionCost ComputeSpeculationCost(const Instruction *I, } } +// Do not hoist any debug info intrinsics. +// ... +// if (cond) { +// x = y * z; +// foo(); +// } +// ... +// -------- Which then becomes: +// ... +// if.then: +// %x = mul i32 %y, %z +// call void @llvm.dbg.value(%x, !"x", !DIExpression()) +// call void foo() +// +// SpeculativeExecution might decide to hoist the 'y * z' calculation +// out of the 'if' block, because it is more efficient that way, so the +// '%x = mul i32 %y, %z' moves to the block above. But it might also +// decide to hoist the 'llvm.dbg.value' call. +// This is incorrect, because even if we've moved the calculation of +// 'y * z', we should not see the value of 'x' change unless we +// actually go inside the 'if' block. + bool SpeculativeExecutionPass::considerHoistingFromTo( BasicBlock &FromBlock, BasicBlock &ToBlock) { SmallPtrSet NotHoisted; - SmallDenseMap> - DbgVariableRecordsToHoist; auto HasNoUnhoistedInstr = [&NotHoisted](auto Values) { for (const Value *V : Values) { if (const auto *I = dyn_cast_or_null(V)) @@ -275,15 +295,8 @@ bool SpeculativeExecutionPass::considerHoistingFromTo( }; auto AllPrecedingUsesFromBlockHoisted = [&HasNoUnhoistedInstr](const User *U) { - // Debug variable has special operand to check it's not hoisted. - if (const auto *DVI = dyn_cast(U)) - return HasNoUnhoistedInstr(DVI->location_ops()); - - // Usially debug label intrinsic corresponds to label in LLVM IR. In - // these cases we should not move it here. - // TODO: Possible special processing needed to detect it is related to a - // hoisted instruction. - if (isa(U)) + // Do not hoist any debug info intrinsics. + if (isa(U)) return false; return HasNoUnhoistedInstr(U->operand_values()); @@ -292,12 +305,6 @@ bool SpeculativeExecutionPass::considerHoistingFromTo( InstructionCost TotalSpeculationCost = 0; unsigned NotHoistedInstCount = 0; for (const auto &I : FromBlock) { - // Make note of any DbgVariableRecords that need hoisting. DbgLabelRecords - // get left behind just like llvm.dbg.labels. - for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange())) { - if (HasNoUnhoistedInstr(DVR.location_ops())) - DbgVariableRecordsToHoist[DVR.getInstruction()].push_back(&DVR); - } const InstructionCost Cost = ComputeSpeculationCost(&I, *TTI); if (Cost.isValid() && isSafeToSpeculativelyExecute(&I) && AllPrecedingUsesFromBlockHoisted(&I)) { @@ -315,16 +322,6 @@ bool SpeculativeExecutionPass::considerHoistingFromTo( } for (auto I = FromBlock.begin(); I != FromBlock.end();) { - // If any DbgVariableRecords attached to this instruction should be hoisted, - // hoist them now - they will end up attached to either the next hoisted - // instruction or the ToBlock terminator. - if (DbgVariableRecordsToHoist.contains(&*I)) { - for (auto *DVR : DbgVariableRecordsToHoist[&*I]) { - DVR->removeFromParent(); - ToBlock.insertDbgRecordBefore(DVR, - ToBlock.getTerminator()->getIterator()); - } - } // We have to increment I before moving Current as moving Current // changes the list that I is iterating through. auto Current = I; diff --git a/llvm/test/Transforms/SpeculativeExecution/PR46267.ll b/llvm/test/Transforms/SpeculativeExecution/PR46267.ll index d940ee6a7863..69dac2220d9a 100644 --- a/llvm/test/Transforms/SpeculativeExecution/PR46267.ll +++ b/llvm/test/Transforms/SpeculativeExecution/PR46267.ll @@ -31,7 +31,6 @@ define void @f(i32 %i) { entry: ; CHECK-LABEL: @f( ; CHECK: %a2 = add i32 %i, 0 -; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 %a2 br i1 undef, label %land.rhs, label %land.end land.rhs: ; preds = %entry @@ -42,6 +41,7 @@ land.rhs: ; preds = %entry ; CHECK-NEXT: %a0 = load i32, ptr undef, align 1 ; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 %a0 ; CHECK-NEXT: call void @llvm.dbg.label +; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 %a2 call void @llvm.dbg.label(metadata !11), !dbg !10 %y = alloca i32, align 4 call void @llvm.dbg.declare(metadata ptr %y, metadata !14, metadata !DIExpression()), !dbg !10 -- GitLab From 0b13e2c82315eac8926f1c4497c4d56a507c3999 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Tue, 2 Apr 2024 13:44:38 +0200 Subject: [PATCH 050/447] [bazel] Another format fix for libc_build_rules.bzl, NFC --- utils/bazel/llvm-project-overlay/libc/libc_build_rules.bzl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/utils/bazel/llvm-project-overlay/libc/libc_build_rules.bzl b/utils/bazel/llvm-project-overlay/libc/libc_build_rules.bzl index 80cf59d7ef12..be59e18ffd89 100644 --- a/utils/bazel/llvm-project-overlay/libc/libc_build_rules.bzl +++ b/utils/bazel/llvm-project-overlay/libc/libc_build_rules.bzl @@ -78,6 +78,7 @@ def libc_function( its deps. **kwargs: Other attributes relevant for a cc_library. For example, deps. """ + # We use the explicit equals pattern here because append and += mutate the # original list, where this creates a new list and stores it in deps. copts = copts or [] @@ -89,6 +90,7 @@ def libc_function( "-fno-omit-frame-pointer", "-fstack-protector-strong", ] + # x86 targets have -mno-omit-leaf-frame-pointer. platform_copts = selects.with_or({ PLATFORM_CPU_X86_64: ["-mno-omit-leaf-frame-pointer"], -- GitLab From 7ef602b58c1ccacab20d9d01e24b281458c3facc Mon Sep 17 00:00:00 2001 From: Sam McCall Date: Tue, 2 Apr 2024 13:48:45 +0200 Subject: [PATCH 051/447] Reapply "[clang][nullability] allow _Nonnull etc on nullable class types (#82705)" (#87325) This reverts commit 28760b63bbf9e267713957105a8d17091fb0d20e. The last commit was missing the new testcase, now fixed. --- clang/docs/ReleaseNotes.rst | 15 +++++ clang/include/clang/Basic/Attr.td | 3 +- clang/include/clang/Basic/AttrDocs.td | 25 ++++++++ clang/include/clang/Basic/Features.def | 1 + clang/include/clang/Parse/Parser.h | 1 + clang/include/clang/Sema/Sema.h | 3 + clang/lib/AST/Type.cpp | 29 ++++++--- clang/lib/CodeGen/CGCall.cpp | 3 +- clang/lib/CodeGen/CodeGenFunction.cpp | 3 +- clang/lib/Parse/ParseDeclCXX.cpp | 33 +++++++--- clang/lib/Sema/SemaAttr.cpp | 12 ++++ clang/lib/Sema/SemaChecking.cpp | 9 +++ clang/lib/Sema/SemaDecl.cpp | 4 +- clang/lib/Sema/SemaDeclAttr.cpp | 18 ++++++ clang/lib/Sema/SemaInit.cpp | 5 ++ clang/lib/Sema/SemaOverload.cpp | 7 +++ clang/lib/Sema/SemaTemplate.cpp | 1 + clang/lib/Sema/SemaType.cpp | 18 ++++-- clang/test/Sema/nullability.c | 2 + clang/test/SemaCXX/nullability.cpp | 62 ++++++++++++++++++- .../Inputs/nullability-consistency-smart.h | 7 +++ .../SemaObjCXX/nullability-consistency.mm | 1 + 22 files changed, 233 insertions(+), 29 deletions(-) create mode 100644 clang/test/SemaObjCXX/Inputs/nullability-consistency-smart.h diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 76eaf0bf11c3..b2faab1f1525 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -253,6 +253,21 @@ Attribute Changes in Clang added a new extension query ``__has_extension(swiftcc)`` corresponding to the ``__attribute__((swiftcc))`` attribute. +- The ``_Nullable`` and ``_Nonnull`` family of type attributes can now apply + to certain C++ class types, such as smart pointers: + ``void useObject(std::unique_ptr _Nonnull obj);``. + + This works for standard library types including ``unique_ptr``, ``shared_ptr``, + and ``function``. See + `the attribute reference documentation `_ + for the full list. + +- The ``_Nullable`` attribute can be applied to C++ class declarations: + ``template class _Nullable MySmartPointer {};``. + + This allows the ``_Nullable`` and ``_Nonnull`` family of type attributes to + apply to this class. + Improvements to Clang's diagnostics ----------------------------------- - Clang now applies syntax highlighting to the code snippets it diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 80e607525a0a..6584460cf568 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -2178,9 +2178,10 @@ def TypeNonNull : TypeAttr { let Documentation = [TypeNonNullDocs]; } -def TypeNullable : TypeAttr { +def TypeNullable : DeclOrTypeAttr { let Spellings = [CustomKeyword<"_Nullable">]; let Documentation = [TypeNullableDocs]; +// let Subjects = SubjectList<[CXXRecord], ErrorDiag>; } def TypeNullableResult : TypeAttr { diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 3ea4d676b4f8..0ca4ea377fc3 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -4151,6 +4151,20 @@ non-underscored keywords. For example: @property (assign, nullable) NSView *superview; @property (readonly, nonnull) NSArray *subviews; @end + +As well as built-in pointer types, the nullability attributes can be attached +to C++ classes marked with the ``_Nullable`` attribute. + +The following C++ standard library types are considered nullable: +``unique_ptr``, ``shared_ptr``, ``auto_ptr``, ``exception_ptr``, ``function``, +``move_only_function`` and ``coroutine_handle``. + +Types should be marked nullable only where the type itself leaves nullability +ambiguous. For example, ``std::optional`` is not marked ``_Nullable``, because +``optional _Nullable`` is redundant and ``optional _Nonnull`` is +not a useful type. ``std::weak_ptr`` is not nullable, because its nullability +can change with no visible modification, so static annotation is unlikely to be +unhelpful. }]; } @@ -4185,6 +4199,17 @@ The ``_Nullable`` nullability qualifier indicates that a value of the int fetch_or_zero(int * _Nullable ptr); a caller of ``fetch_or_zero`` can provide null. + +The ``_Nullable`` attribute on classes indicates that the given class can +represent null values, and so the ``_Nullable``, ``_Nonnull`` etc qualifiers +make sense for this type. For example: + + .. code-block:: c + + class _Nullable ArenaPointer { ... }; + + ArenaPointer _Nonnull x = ...; + ArenaPointer _Nullable y = nullptr; }]; } diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def index b41aadc73f20..fe4d1c4afcca 100644 --- a/clang/include/clang/Basic/Features.def +++ b/clang/include/clang/Basic/Features.def @@ -94,6 +94,7 @@ EXTENSION(define_target_os_macros, FEATURE(enumerator_attributes, true) FEATURE(nullability, true) FEATURE(nullability_on_arrays, true) +FEATURE(nullability_on_classes, true) FEATURE(nullability_nullable_result, true) FEATURE(memory_sanitizer, LangOpts.Sanitize.hasOneOf(SanitizerKind::Memory | diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index bba8ef4ff017..580bf2a5d79d 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -3014,6 +3014,7 @@ private: void DiagnoseAndSkipExtendedMicrosoftTypeAttributes(); SourceLocation SkipExtendedMicrosoftTypeAttributes(); void ParseMicrosoftInheritanceClassAttributes(ParsedAttributes &attrs); + void ParseNullabilityClassAttributes(ParsedAttributes &attrs); void ParseBorlandTypeAttributes(ParsedAttributes &attrs); void ParseOpenCLKernelAttributes(ParsedAttributes &attrs); void ParseOpenCLQualifiers(ParsedAttributes &Attrs); diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index a02b684f2c77..8c98d8c7fef7 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1660,6 +1660,9 @@ public: /// Add [[gsl::Pointer]] attributes for std:: types. void inferGslPointerAttribute(TypedefNameDecl *TD); + /// Add _Nullable attributes for std:: types. + void inferNullableClassAttribute(CXXRecordDecl *CRD); + enum PragmaOptionsAlignKind { POAK_Native, // #pragma options align=native POAK_Natural, // #pragma options align=natural diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 779d8a810820..cb22c91a12aa 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -4652,16 +4652,15 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const { case Type::Auto: return ResultIfUnknown; - // Dependent template specializations can instantiate to pointer - // types unless they're known to be specializations of a class - // template. + // Dependent template specializations could instantiate to pointer types. case Type::TemplateSpecialization: - if (TemplateDecl *templateDecl - = cast(type.getTypePtr()) - ->getTemplateName().getAsTemplateDecl()) { - if (isa(templateDecl)) - return false; - } + // If it's a known class template, we can already check if it's nullable. + if (TemplateDecl *templateDecl = + cast(type.getTypePtr()) + ->getTemplateName() + .getAsTemplateDecl()) + if (auto *CTD = dyn_cast(templateDecl)) + return CTD->getTemplatedDecl()->hasAttr(); return ResultIfUnknown; case Type::Builtin: @@ -4718,6 +4717,17 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const { } llvm_unreachable("unknown builtin type"); + case Type::Record: { + const RecordDecl *RD = cast(type)->getDecl(); + // For template specializations, look only at primary template attributes. + // This is a consistent regardless of whether the instantiation is known. + if (const auto *CTSD = dyn_cast(RD)) + return CTSD->getSpecializedTemplate() + ->getTemplatedDecl() + ->hasAttr(); + return RD->hasAttr(); + } + // Non-pointer types. case Type::Complex: case Type::LValueReference: @@ -4735,7 +4745,6 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const { case Type::DependentAddressSpace: case Type::FunctionProto: case Type::FunctionNoProto: - case Type::Record: case Type::DeducedTemplateSpecialization: case Type::Enum: case Type::InjectedClassName: diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 9308528ac938..f12765b82693 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -4379,7 +4379,8 @@ void CodeGenFunction::EmitNonNullArgCheck(RValue RV, QualType ArgType, NNAttr = getNonNullAttr(AC.getDecl(), PVD, ArgType, ArgNo); bool CanCheckNullability = false; - if (SanOpts.has(SanitizerKind::NullabilityArg) && !NNAttr && PVD) { + if (SanOpts.has(SanitizerKind::NullabilityArg) && !NNAttr && PVD && + !PVD->getType()->isRecordType()) { auto Nullability = PVD->getType()->getNullability(); CanCheckNullability = Nullability && *Nullability == NullabilityKind::NonNull && diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 90324de7268e..6474d6c8c1d1 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -990,7 +990,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, // return value. Initialize the flag to 'true' and refine it in EmitParmDecl. if (SanOpts.has(SanitizerKind::NullabilityReturn)) { auto Nullability = FnRetTy->getNullability(); - if (Nullability && *Nullability == NullabilityKind::NonNull) { + if (Nullability && *Nullability == NullabilityKind::NonNull && + !FnRetTy->isRecordType()) { if (!(SanOpts.has(SanitizerKind::ReturnsNonnullAttribute) && CurCodeDecl && CurCodeDecl->getAttr())) RetValNullabilityPrecondition = diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 63fe678cbb29..861a25dc5103 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -1502,6 +1502,15 @@ void Parser::ParseMicrosoftInheritanceClassAttributes(ParsedAttributes &attrs) { } } +void Parser::ParseNullabilityClassAttributes(ParsedAttributes &attrs) { + while (Tok.is(tok::kw__Nullable)) { + IdentifierInfo *AttrName = Tok.getIdentifierInfo(); + auto Kind = Tok.getKind(); + SourceLocation AttrNameLoc = ConsumeToken(); + attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, Kind); + } +} + /// Determine whether the following tokens are valid after a type-specifier /// which could be a standalone declaration. This will conservatively return /// true if there's any doubt, and is appropriate for insert-';' fixits. @@ -1683,15 +1692,21 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, ParsedAttributes attrs(AttrFactory); // If attributes exist after tag, parse them. - MaybeParseAttributes(PAKM_CXX11 | PAKM_Declspec | PAKM_GNU, attrs); - - // Parse inheritance specifiers. - if (Tok.isOneOf(tok::kw___single_inheritance, tok::kw___multiple_inheritance, - tok::kw___virtual_inheritance)) - ParseMicrosoftInheritanceClassAttributes(attrs); - - // Allow attributes to precede or succeed the inheritance specifiers. - MaybeParseAttributes(PAKM_CXX11 | PAKM_Declspec | PAKM_GNU, attrs); + for (;;) { + MaybeParseAttributes(PAKM_CXX11 | PAKM_Declspec | PAKM_GNU, attrs); + // Parse inheritance specifiers. + if (Tok.isOneOf(tok::kw___single_inheritance, + tok::kw___multiple_inheritance, + tok::kw___virtual_inheritance)) { + ParseMicrosoftInheritanceClassAttributes(attrs); + continue; + } + if (Tok.is(tok::kw__Nullable)) { + ParseNullabilityClassAttributes(attrs); + continue; + } + break; + } // Source location used by FIXIT to insert misplaced // C++11 attributes diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp index 0dcf42e48997..a5dd158808f2 100644 --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -215,6 +215,18 @@ void Sema::inferGslOwnerPointerAttribute(CXXRecordDecl *Record) { inferGslPointerAttribute(Record, Record); } +void Sema::inferNullableClassAttribute(CXXRecordDecl *CRD) { + static llvm::StringSet<> Nullable{ + "auto_ptr", "shared_ptr", "unique_ptr", "exception_ptr", + "coroutine_handle", "function", "move_only_function", + }; + + if (CRD->isInStdNamespace() && Nullable.count(CRD->getName()) && + !CRD->hasAttr()) + for (Decl *Redecl : CRD->redecls()) + Redecl->addAttr(TypeNullableAttr::CreateImplicit(Context)); +} + void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind, SourceLocation PragmaLoc) { PragmaMsStackAction Action = Sema::PSK_Reset; diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 11401b6f56c0..3dcd18b3afc8 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -27,6 +27,7 @@ #include "clang/AST/ExprObjC.h" #include "clang/AST/ExprOpenMP.h" #include "clang/AST/FormatString.h" +#include "clang/AST/IgnoreExpr.h" #include "clang/AST/NSAPI.h" #include "clang/AST/NonTrivialTypeVisitor.h" #include "clang/AST/OperationKinds.h" @@ -7610,6 +7611,14 @@ bool Sema::getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember, /// /// Returns true if the value evaluates to null. static bool CheckNonNullExpr(Sema &S, const Expr *Expr) { + // Treat (smart) pointers constructed from nullptr as null, whether we can + // const-evaluate them or not. + // This must happen first: the smart pointer expr might have _Nonnull type! + if (isa( + IgnoreExprNodes(Expr, IgnoreImplicitAsWrittenSingleStep, + IgnoreElidableImplicitConstructorSingleStep))) + return true; + // If the expression has non-null type, it doesn't evaluate to null. if (auto nullability = Expr->IgnoreImplicit()->getType()->getNullability()) { if (*nullability == NullabilityKind::NonNull) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 5027deda0d7e..6ff85c0c5c29 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -18319,8 +18319,10 @@ CreateNewDecl: if (PrevDecl) mergeDeclAttributes(New, PrevDecl); - if (auto *CXXRD = dyn_cast(New)) + if (auto *CXXRD = dyn_cast(New)) { inferGslOwnerPointerAttribute(CXXRD); + inferNullableClassAttribute(CXXRD); + } // If there's a #pragma GCC visibility in scope, set the visibility of this // record. diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index f25f3afd0f4a..8bce04640e74 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5982,6 +5982,20 @@ static void handleBuiltinAliasAttr(Sema &S, Decl *D, D->addAttr(::new (S.Context) BuiltinAliasAttr(S.Context, AL, Ident)); } +static void handleNullableTypeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (AL.isUsedAsTypeAttr()) + return; + + if (auto *CRD = dyn_cast(D); + !CRD || !(CRD->isClass() || CRD->isStruct())) { + S.Diag(AL.getRange().getBegin(), diag::err_attribute_wrong_decl_type_str) + << AL << AL.isRegularKeywordAttribute() << "classes"; + return; + } + + handleSimpleAttribute(S, D, AL); +} + static void handlePreferredTypeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!AL.hasParsedType()) { S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1; @@ -9933,6 +9947,10 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_UsingIfExists: handleSimpleAttribute(S, D, AL); break; + + case ParsedAttr::AT_TypeNullable: + handleNullableTypeAttr(S, D, AL); + break; } } diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 777f89c70f87..e2a1951f1062 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -7082,6 +7082,11 @@ PerformConstructorInitialization(Sema &S, hasCopyOrMoveCtorParam(S.Context, getConstructorInfo(Step.Function.FoundDecl)); + // A smart pointer constructed from a nullable pointer is nullable. + if (NumArgs == 1 && !Kind.isExplicitCast()) + S.diagnoseNullableToNonnullConversion( + Entity.getType(), Args.front()->getType(), Kind.getLocation()); + // Determine the arguments required to actually perform the constructor // call. if (S.CompleteConstructorCall(Constructor, Step.Type, Args, Loc, diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 16d54c1ffe5f..0c913bc700f4 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -14826,6 +14826,13 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc, } } + // Check for nonnull = nullable. + // This won't be caught in the arg's initialization: the parameter to + // the assignment operator is not marked nonnull. + if (Op == OO_Equal) + diagnoseNullableToNonnullConversion(Args[0]->getType(), + Args[1]->getType(), OpLoc); + // Convert the arguments. if (CXXMethodDecl *Method = dyn_cast(FnDecl)) { // Best->Access is only meaningful for class members. diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 1a2d5e9310db..befec401c8ee 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -2191,6 +2191,7 @@ DeclResult Sema::CheckClassTemplate( AddPushedVisibilityAttribute(NewClass); inferGslOwnerPointerAttribute(NewClass); + inferNullableClassAttribute(NewClass); if (TUK != TUK_Friend) { // Per C++ [basic.scope.temp]p2, skip the template parameter scopes. diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index d88895d35294..8762744396f4 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -4717,6 +4717,18 @@ static bool DiagnoseMultipleAddrSpaceAttributes(Sema &S, LangAS ASOld, return false; } +// Whether this is a type broadly expected to have nullability attached. +// These types are affected by `#pragma assume_nonnull`, and missing nullability +// will be diagnosed with -Wnullability-completeness. +static bool shouldHaveNullability(QualType T) { + return T->canHaveNullability(/*ResultIfUnknown=*/false) && + // For now, do not infer/require nullability on C++ smart pointers. + // It's unclear whether the pragma's behavior is useful for C++. + // e.g. treating type-aliases and template-type-parameters differently + // from types of declarations can be surprising. + !isa(T->getCanonicalTypeInternal()); +} + static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, QualType declSpecType, TypeSourceInfo *TInfo) { @@ -4835,8 +4847,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // inner pointers. complainAboutMissingNullability = CAMN_InnerPointers; - if (T->canHaveNullability(/*ResultIfUnknown*/ false) && - !T->getNullability()) { + if (shouldHaveNullability(T) && !T->getNullability()) { // Note that we allow but don't require nullability on dependent types. ++NumPointersRemaining; } @@ -5059,8 +5070,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // If the type itself could have nullability but does not, infer pointer // nullability and perform consistency checking. if (S.CodeSynthesisContexts.empty()) { - if (T->canHaveNullability(/*ResultIfUnknown*/ false) && - !T->getNullability()) { + if (shouldHaveNullability(T) && !T->getNullability()) { if (isVaList(T)) { // Record that we've seen a pointer, but do nothing else. if (NumPointersRemaining > 0) diff --git a/clang/test/Sema/nullability.c b/clang/test/Sema/nullability.c index 7d193bea4677..0401516233b6 100644 --- a/clang/test/Sema/nullability.c +++ b/clang/test/Sema/nullability.c @@ -248,3 +248,5 @@ void arraysInBlocks(void) { void (^withTypedefBad)(INTS _Nonnull [2]) = // expected-error {{nullability specifier '_Nonnull' cannot be applied to non-pointer type 'INTS' (aka 'int[4]')}} ^(INTS _Nonnull x[2]) {}; // expected-error {{nullability specifier '_Nonnull' cannot be applied to non-pointer type 'INTS' (aka 'int[4]')}} } + +struct _Nullable NotCplusplusClass {}; // expected-error {{'_Nullable' attribute only applies to classes}} diff --git a/clang/test/SemaCXX/nullability.cpp b/clang/test/SemaCXX/nullability.cpp index 8d0c4dc195a6..d52ba4efaccd 100644 --- a/clang/test/SemaCXX/nullability.cpp +++ b/clang/test/SemaCXX/nullability.cpp @@ -4,6 +4,10 @@ #else # error nullability feature should be defined #endif +#if __has_feature(nullability_on_classes) +#else +# error smart-pointer feature should be defined +#endif #include "nullability-completeness.h" @@ -27,6 +31,7 @@ template struct AddNonNull { typedef _Nonnull T type; // expected-error{{nullability specifier '_Nonnull' cannot be applied to non-pointer type 'int'}} // expected-error@-1{{nullability specifier '_Nonnull' cannot be applied to non-pointer type 'std::nullptr_t'}} + // expected-error@-2{{nullability specifier '_Nonnull' cannot be applied to non-pointer type 'NotPtr'}} }; typedef AddNonNull::type nonnull_int_ptr_1; @@ -35,6 +40,33 @@ typedef AddNonNull::type nonnull_int_ptr_3; // expected-note{{in inst typedef AddNonNull::type nonnull_non_pointer_1; // expected-note{{in instantiation of template class 'AddNonNull' requested here}} +// Nullability on C++ class types (smart pointers). +struct NotPtr{}; +typedef AddNonNull::type nonnull_non_pointer_2; // expected-note{{in instantiation}} +struct _Nullable SmartPtr{ + SmartPtr(); + SmartPtr(nullptr_t); + SmartPtr(const SmartPtr&); + SmartPtr(SmartPtr&&); + SmartPtr &operator=(const SmartPtr&); + SmartPtr &operator=(SmartPtr&&); +}; +typedef AddNonNull::type nonnull_smart_pointer_1; +template struct _Nullable SmartPtrTemplate{}; +typedef AddNonNull>::type nonnull_smart_pointer_2; +namespace std { inline namespace __1 { + template class unique_ptr {}; + template class function; + template class function {}; +} } +typedef AddNonNull>::type nonnull_smart_pointer_3; +typedef AddNonNull>::type nonnull_smart_pointer_4; + +class Derived : public SmartPtr {}; +Derived _Nullable x; // expected-error {{'_Nullable' cannot be applied}} +class DerivedPrivate : private SmartPtr {}; +DerivedPrivate _Nullable y; // expected-error {{'_Nullable' cannot be applied}} + // Non-null checking within a template. template struct AddNonNull2 { @@ -54,6 +86,7 @@ void (*& accepts_nonnull_2)(_Nonnull int *ptr) = accepts_nonnull_1; void (X::* accepts_nonnull_3)(_Nonnull int *ptr); void accepts_nonnull_4(_Nonnull int *ptr); void (&accepts_nonnull_5)(_Nonnull int *ptr) = accepts_nonnull_4; +void accepts_nonnull_6(SmartPtr _Nonnull); void test_accepts_nonnull_null_pointer_literal(X *x) { accepts_nonnull_1(0); // expected-warning{{null passed to a callee that requires a non-null argument}} @@ -61,6 +94,8 @@ void test_accepts_nonnull_null_pointer_literal(X *x) { (x->*accepts_nonnull_3)(0); // expected-warning{{null passed to a callee that requires a non-null argument}} accepts_nonnull_4(0); // expected-warning{{null passed to a callee that requires a non-null argument}} accepts_nonnull_5(0); // expected-warning{{null passed to a callee that requires a non-null argument}} + + accepts_nonnull_6(nullptr); // expected-warning{{null passed to a callee that requires a non-null argument}} } template @@ -71,6 +106,7 @@ void test_accepts_nonnull_null_pointer_literal_template() { template void test_accepts_nonnull_null_pointer_literal_template<&accepts_nonnull_4>(); // expected-note{{instantiation of function template specialization}} void TakeNonnull(void *_Nonnull); +void TakeSmartNonnull(SmartPtr _Nonnull); // Check different forms of assignment to a nonull type from a nullable one. void AssignAndInitNonNull() { void *_Nullable nullable; @@ -81,12 +117,26 @@ void AssignAndInitNonNull() { void *_Nonnull nonnull; nonnull = nullable; // expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull'}} nonnull = {nullable}; // expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull'}} - TakeNonnull(nullable); //expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull}} TakeNonnull(nonnull); // OK + nonnull = (void *_Nonnull)nullable; // explicit cast OK + + SmartPtr _Nullable s_nullable; + SmartPtr _Nonnull s(s_nullable); // expected-warning{{implicit conversion from nullable pointer 'SmartPtr _Nullable' to non-nullable pointer type 'SmartPtr _Nonnull'}} + SmartPtr _Nonnull s2{s_nullable}; // expected-warning{{implicit conversion from nullable pointer 'SmartPtr _Nullable' to non-nullable pointer type 'SmartPtr _Nonnull'}} + SmartPtr _Nonnull s3 = {s_nullable}; // expected-warning{{implicit conversion from nullable pointer 'SmartPtr _Nullable' to non-nullable pointer type 'SmartPtr _Nonnull'}} + SmartPtr _Nonnull s4 = s_nullable; // expected-warning{{implicit conversion from nullable pointer 'SmartPtr _Nullable' to non-nullable pointer type 'SmartPtr _Nonnull'}} + SmartPtr _Nonnull s_nonnull; + s_nonnull = s_nullable; // expected-warning{{implicit conversion from nullable pointer 'SmartPtr _Nullable' to non-nullable pointer type 'SmartPtr _Nonnull'}} + s_nonnull = {s_nullable}; // no warning here - might be nice? + TakeSmartNonnull(s_nullable); //expected-warning{{implicit conversion from nullable pointer 'SmartPtr _Nullable' to non-nullable pointer type 'SmartPtr _Nonnull}} + TakeSmartNonnull(s_nonnull); // OK + s_nonnull = (SmartPtr _Nonnull)s_nullable; // explicit cast OK + s_nonnull = static_cast(s_nullable); // explicit cast OK } void *_Nullable ReturnNullable(); +SmartPtr _Nullable ReturnSmartNullable(); void AssignAndInitNonNullFromFn() { void *_Nonnull p(ReturnNullable()); // expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull'}} @@ -96,8 +146,16 @@ void AssignAndInitNonNullFromFn() { void *_Nonnull nonnull; nonnull = ReturnNullable(); // expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull'}} nonnull = {ReturnNullable()}; // expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull'}} - TakeNonnull(ReturnNullable()); //expected-warning{{implicit conversion from nullable pointer 'void * _Nullable' to non-nullable pointer type 'void * _Nonnull}} + + SmartPtr _Nonnull s(ReturnSmartNullable()); // expected-warning{{implicit conversion from nullable pointer 'SmartPtr _Nullable' to non-nullable pointer type 'SmartPtr _Nonnull'}} + SmartPtr _Nonnull s2{ReturnSmartNullable()}; // expected-warning{{implicit conversion from nullable pointer 'SmartPtr _Nullable' to non-nullable pointer type 'SmartPtr _Nonnull'}} + SmartPtr _Nonnull s3 = {ReturnSmartNullable()}; // expected-warning{{implicit conversion from nullable pointer 'SmartPtr _Nullable' to non-nullable pointer type 'SmartPtr _Nonnull'}} + SmartPtr _Nonnull s4 = ReturnSmartNullable(); // expected-warning{{implicit conversion from nullable pointer 'SmartPtr _Nullable' to non-nullable pointer type 'SmartPtr _Nonnull'}} + SmartPtr _Nonnull s_nonnull; + s_nonnull = ReturnSmartNullable(); // expected-warning{{implicit conversion from nullable pointer 'SmartPtr _Nullable' to non-nullable pointer type 'SmartPtr _Nonnull'}} + s_nonnull = {ReturnSmartNullable()}; + TakeSmartNonnull(ReturnSmartNullable()); // expected-warning{{implicit conversion from nullable pointer 'SmartPtr _Nullable' to non-nullable pointer type 'SmartPtr _Nonnull'}} } void ConditionalExpr(bool c) { diff --git a/clang/test/SemaObjCXX/Inputs/nullability-consistency-smart.h b/clang/test/SemaObjCXX/Inputs/nullability-consistency-smart.h new file mode 100644 index 000000000000..a28532e5d716 --- /dev/null +++ b/clang/test/SemaObjCXX/Inputs/nullability-consistency-smart.h @@ -0,0 +1,7 @@ +class _Nullable Smart; + +void f1(int * _Nonnull); + +void f2(Smart); // OK, not required on smart-pointer types +using Alias = Smart; +void f3(Alias); diff --git a/clang/test/SemaObjCXX/nullability-consistency.mm b/clang/test/SemaObjCXX/nullability-consistency.mm index 6921d8b9d3dd..09c9a84475a9 100644 --- a/clang/test/SemaObjCXX/nullability-consistency.mm +++ b/clang/test/SemaObjCXX/nullability-consistency.mm @@ -9,6 +9,7 @@ #include "nullability-consistency-6.h" #include "nullability-consistency-7.h" #include "nullability-consistency-8.h" +#include "nullability-consistency-smart.h" #include "nullability-consistency-system.h" void h1(int *ptr) { } // don't warn -- GitLab From beeb15b71650b46f39cb6b1917e8d05568978656 Mon Sep 17 00:00:00 2001 From: Nikolas Klauser Date: Tue, 2 Apr 2024 13:52:07 +0200 Subject: [PATCH 052/447] [libc++][NFC] Remove a few unused <__availablity> includes (#86126) --- libcxx/include/__exception/operations.h | 1 - libcxx/include/__filesystem/copy_options.h | 1 - libcxx/include/__filesystem/directory_options.h | 1 - libcxx/include/__filesystem/file_status.h | 1 - libcxx/include/__filesystem/file_time_type.h | 1 - libcxx/include/__filesystem/file_type.h | 1 - libcxx/include/__filesystem/perm_options.h | 1 - libcxx/include/__filesystem/perms.h | 1 - libcxx/include/__filesystem/space_info.h | 1 - libcxx/include/__format/format_args.h | 1 - libcxx/include/__format/format_context.h | 1 - libcxx/include/__format/formatter.h | 1 - libcxx/include/__format/formatter_bool.h | 1 - libcxx/include/__format/formatter_char.h | 1 - libcxx/include/__format/formatter_integer.h | 1 - libcxx/include/__format/formatter_pointer.h | 1 - libcxx/include/__format/formatter_string.h | 1 - libcxx/include/__fwd/format.h | 1 - libcxx/include/__locale | 1 - libcxx/include/__memory/shared_ptr.h | 1 - libcxx/include/__thread/support/pthread.h | 1 - libcxx/include/any | 1 - libcxx/include/future | 1 - libcxx/include/new | 1 - libcxx/include/shared_mutex | 1 - libcxx/include/thread | 1 - libcxx/include/typeinfo | 1 - 27 files changed, 27 deletions(-) diff --git a/libcxx/include/__exception/operations.h b/libcxx/include/__exception/operations.h index 8f374c0ccee5..0a9c7a7c7f0d 100644 --- a/libcxx/include/__exception/operations.h +++ b/libcxx/include/__exception/operations.h @@ -9,7 +9,6 @@ #ifndef _LIBCPP___EXCEPTION_OPERATIONS_H #define _LIBCPP___EXCEPTION_OPERATIONS_H -#include <__availability> #include <__config> #include diff --git a/libcxx/include/__filesystem/copy_options.h b/libcxx/include/__filesystem/copy_options.h index 1bf71292c8a6..097eebe61137 100644 --- a/libcxx/include/__filesystem/copy_options.h +++ b/libcxx/include/__filesystem/copy_options.h @@ -10,7 +10,6 @@ #ifndef _LIBCPP___FILESYSTEM_COPY_OPTIONS_H #define _LIBCPP___FILESYSTEM_COPY_OPTIONS_H -#include <__availability> #include <__config> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) diff --git a/libcxx/include/__filesystem/directory_options.h b/libcxx/include/__filesystem/directory_options.h index 683c4678e083..d0cd3ebfdaa7 100644 --- a/libcxx/include/__filesystem/directory_options.h +++ b/libcxx/include/__filesystem/directory_options.h @@ -10,7 +10,6 @@ #ifndef _LIBCPP___FILESYSTEM_DIRECTORY_OPTIONS_H #define _LIBCPP___FILESYSTEM_DIRECTORY_OPTIONS_H -#include <__availability> #include <__config> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) diff --git a/libcxx/include/__filesystem/file_status.h b/libcxx/include/__filesystem/file_status.h index 3e2b32eef82e..da316c8b0274 100644 --- a/libcxx/include/__filesystem/file_status.h +++ b/libcxx/include/__filesystem/file_status.h @@ -10,7 +10,6 @@ #ifndef _LIBCPP___FILESYSTEM_FILE_STATUS_H #define _LIBCPP___FILESYSTEM_FILE_STATUS_H -#include <__availability> #include <__config> #include <__filesystem/file_type.h> #include <__filesystem/perms.h> diff --git a/libcxx/include/__filesystem/file_time_type.h b/libcxx/include/__filesystem/file_time_type.h index e086dbcc3f51..63e4ae1578cf 100644 --- a/libcxx/include/__filesystem/file_time_type.h +++ b/libcxx/include/__filesystem/file_time_type.h @@ -10,7 +10,6 @@ #ifndef _LIBCPP___FILESYSTEM_FILE_TIME_TYPE_H #define _LIBCPP___FILESYSTEM_FILE_TIME_TYPE_H -#include <__availability> #include <__chrono/file_clock.h> #include <__chrono/time_point.h> #include <__config> diff --git a/libcxx/include/__filesystem/file_type.h b/libcxx/include/__filesystem/file_type.h index c509085d90de..e4ac1dfee9ed 100644 --- a/libcxx/include/__filesystem/file_type.h +++ b/libcxx/include/__filesystem/file_type.h @@ -10,7 +10,6 @@ #ifndef _LIBCPP___FILESYSTEM_FILE_TYPE_H #define _LIBCPP___FILESYSTEM_FILE_TYPE_H -#include <__availability> #include <__config> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) diff --git a/libcxx/include/__filesystem/perm_options.h b/libcxx/include/__filesystem/perm_options.h index 529ef13558e9..64c16ee60a17 100644 --- a/libcxx/include/__filesystem/perm_options.h +++ b/libcxx/include/__filesystem/perm_options.h @@ -10,7 +10,6 @@ #ifndef _LIBCPP___FILESYSTEM_PERM_OPTIONS_H #define _LIBCPP___FILESYSTEM_PERM_OPTIONS_H -#include <__availability> #include <__config> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) diff --git a/libcxx/include/__filesystem/perms.h b/libcxx/include/__filesystem/perms.h index 8f5f9a7e8248..458f1e6e5348 100644 --- a/libcxx/include/__filesystem/perms.h +++ b/libcxx/include/__filesystem/perms.h @@ -10,7 +10,6 @@ #ifndef _LIBCPP___FILESYSTEM_PERMS_H #define _LIBCPP___FILESYSTEM_PERMS_H -#include <__availability> #include <__config> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) diff --git a/libcxx/include/__filesystem/space_info.h b/libcxx/include/__filesystem/space_info.h index 2e80ae3b2c11..3fa57d33096f 100644 --- a/libcxx/include/__filesystem/space_info.h +++ b/libcxx/include/__filesystem/space_info.h @@ -10,7 +10,6 @@ #ifndef _LIBCPP___FILESYSTEM_SPACE_INFO_H #define _LIBCPP___FILESYSTEM_SPACE_INFO_H -#include <__availability> #include <__config> #include diff --git a/libcxx/include/__format/format_args.h b/libcxx/include/__format/format_args.h index 79fe51f96c6a..a5fde36a2981 100644 --- a/libcxx/include/__format/format_args.h +++ b/libcxx/include/__format/format_args.h @@ -10,7 +10,6 @@ #ifndef _LIBCPP___FORMAT_FORMAT_ARGS_H #define _LIBCPP___FORMAT_FORMAT_ARGS_H -#include <__availability> #include <__config> #include <__format/format_arg.h> #include <__format/format_arg_store.h> diff --git a/libcxx/include/__format/format_context.h b/libcxx/include/__format/format_context.h index bf603c5c62d9..087d4bf289b8 100644 --- a/libcxx/include/__format/format_context.h +++ b/libcxx/include/__format/format_context.h @@ -10,7 +10,6 @@ #ifndef _LIBCPP___FORMAT_FORMAT_CONTEXT_H #define _LIBCPP___FORMAT_FORMAT_CONTEXT_H -#include <__availability> #include <__concepts/same_as.h> #include <__config> #include <__format/buffer.h> diff --git a/libcxx/include/__format/formatter.h b/libcxx/include/__format/formatter.h index 47e35789b817..e2f418f936ee 100644 --- a/libcxx/include/__format/formatter.h +++ b/libcxx/include/__format/formatter.h @@ -10,7 +10,6 @@ #ifndef _LIBCPP___FORMAT_FORMATTER_H #define _LIBCPP___FORMAT_FORMATTER_H -#include <__availability> #include <__config> #include <__fwd/format.h> diff --git a/libcxx/include/__format/formatter_bool.h b/libcxx/include/__format/formatter_bool.h index 5e3daff7b3db..17dc69541e8f 100644 --- a/libcxx/include/__format/formatter_bool.h +++ b/libcxx/include/__format/formatter_bool.h @@ -12,7 +12,6 @@ #include <__algorithm/copy.h> #include <__assert> -#include <__availability> #include <__config> #include <__format/concepts.h> #include <__format/format_parse_context.h> diff --git a/libcxx/include/__format/formatter_char.h b/libcxx/include/__format/formatter_char.h index 3358d422252f..d33e84368a76 100644 --- a/libcxx/include/__format/formatter_char.h +++ b/libcxx/include/__format/formatter_char.h @@ -10,7 +10,6 @@ #ifndef _LIBCPP___FORMAT_FORMATTER_CHAR_H #define _LIBCPP___FORMAT_FORMATTER_CHAR_H -#include <__availability> #include <__concepts/same_as.h> #include <__config> #include <__format/concepts.h> diff --git a/libcxx/include/__format/formatter_integer.h b/libcxx/include/__format/formatter_integer.h index d57082b3881b..41400f00478e 100644 --- a/libcxx/include/__format/formatter_integer.h +++ b/libcxx/include/__format/formatter_integer.h @@ -10,7 +10,6 @@ #ifndef _LIBCPP___FORMAT_FORMATTER_INTEGER_H #define _LIBCPP___FORMAT_FORMATTER_INTEGER_H -#include <__availability> #include <__concepts/arithmetic.h> #include <__config> #include <__format/concepts.h> diff --git a/libcxx/include/__format/formatter_pointer.h b/libcxx/include/__format/formatter_pointer.h index 3373996ec3d5..6941343efd91 100644 --- a/libcxx/include/__format/formatter_pointer.h +++ b/libcxx/include/__format/formatter_pointer.h @@ -10,7 +10,6 @@ #ifndef _LIBCPP___FORMAT_FORMATTER_POINTER_H #define _LIBCPP___FORMAT_FORMATTER_POINTER_H -#include <__availability> #include <__config> #include <__format/concepts.h> #include <__format/format_parse_context.h> diff --git a/libcxx/include/__format/formatter_string.h b/libcxx/include/__format/formatter_string.h index d1ccfb9b5f7d..347439fc8dff 100644 --- a/libcxx/include/__format/formatter_string.h +++ b/libcxx/include/__format/formatter_string.h @@ -10,7 +10,6 @@ #ifndef _LIBCPP___FORMAT_FORMATTER_STRING_H #define _LIBCPP___FORMAT_FORMATTER_STRING_H -#include <__availability> #include <__config> #include <__format/concepts.h> #include <__format/format_parse_context.h> diff --git a/libcxx/include/__fwd/format.h b/libcxx/include/__fwd/format.h index 6f5c71243711..b30c220f8a04 100644 --- a/libcxx/include/__fwd/format.h +++ b/libcxx/include/__fwd/format.h @@ -10,7 +10,6 @@ #ifndef _LIBCPP___FWD_FORMAT_H #define _LIBCPP___FWD_FORMAT_H -#include <__availability> #include <__config> #include <__iterator/concepts.h> diff --git a/libcxx/include/__locale b/libcxx/include/__locale index 2186db849331..fab87f0d6a27 100644 --- a/libcxx/include/__locale +++ b/libcxx/include/__locale @@ -10,7 +10,6 @@ #ifndef _LIBCPP___LOCALE #define _LIBCPP___LOCALE -#include <__availability> #include <__config> #include <__locale_dir/locale_base_api.h> #include <__memory/shared_ptr.h> // __shared_count diff --git a/libcxx/include/__memory/shared_ptr.h b/libcxx/include/__memory/shared_ptr.h index 794a794d8fd8..a8ff189df2aa 100644 --- a/libcxx/include/__memory/shared_ptr.h +++ b/libcxx/include/__memory/shared_ptr.h @@ -10,7 +10,6 @@ #ifndef _LIBCPP___MEMORY_SHARED_PTR_H #define _LIBCPP___MEMORY_SHARED_PTR_H -#include <__availability> #include <__compare/compare_three_way.h> #include <__compare/ordering.h> #include <__config> diff --git a/libcxx/include/__thread/support/pthread.h b/libcxx/include/__thread/support/pthread.h index e194e5c68ad3..531f3e71de83 100644 --- a/libcxx/include/__thread/support/pthread.h +++ b/libcxx/include/__thread/support/pthread.h @@ -10,7 +10,6 @@ #ifndef _LIBCPP___THREAD_SUPPORT_PTHREAD_H #define _LIBCPP___THREAD_SUPPORT_PTHREAD_H -#include <__availability> #include <__chrono/convert_to_timespec.h> #include <__chrono/duration.h> #include <__config> diff --git a/libcxx/include/any b/libcxx/include/any index a6212fedfa2c..0e66890593c3 100644 --- a/libcxx/include/any +++ b/libcxx/include/any @@ -80,7 +80,6 @@ namespace std { */ -#include <__availability> #include <__config> #include <__memory/allocator.h> #include <__memory/allocator_destructor.h> diff --git a/libcxx/include/future b/libcxx/include/future index fda1591818a6..3c228686063e 100644 --- a/libcxx/include/future +++ b/libcxx/include/future @@ -369,7 +369,6 @@ template struct uses_allocator, Alloc>; #endif #include <__assert> -#include <__availability> #include <__chrono/duration.h> #include <__chrono/time_point.h> #include <__exception/exception_ptr.h> diff --git a/libcxx/include/new b/libcxx/include/new index 988f7a84422c..5a245dc5ef45 100644 --- a/libcxx/include/new +++ b/libcxx/include/new @@ -86,7 +86,6 @@ void operator delete[](void* ptr, void*) noexcept; */ -#include <__availability> #include <__config> #include <__exception/exception.h> #include <__type_traits/is_function.h> diff --git a/libcxx/include/shared_mutex b/libcxx/include/shared_mutex index 38b559e8930f..9cc391db6fc5 100644 --- a/libcxx/include/shared_mutex +++ b/libcxx/include/shared_mutex @@ -128,7 +128,6 @@ template # error " is not supported since libc++ has been configured without support for threads." #endif -#include <__availability> #include <__chrono/duration.h> #include <__chrono/steady_clock.h> #include <__chrono/time_point.h> diff --git a/libcxx/include/thread b/libcxx/include/thread index ed70bde76094..68ce63bd0143 100644 --- a/libcxx/include/thread +++ b/libcxx/include/thread @@ -92,7 +92,6 @@ void sleep_for(const chrono::duration& rel_time); # error " is not supported since libc++ has been configured without support for threads." #endif -#include <__availability> #include <__thread/formatter.h> #include <__thread/jthread.h> #include <__thread/support.h> diff --git a/libcxx/include/typeinfo b/libcxx/include/typeinfo index dafc7b89248e..1ae075edd4b3 100644 --- a/libcxx/include/typeinfo +++ b/libcxx/include/typeinfo @@ -56,7 +56,6 @@ public: */ -#include <__availability> #include <__config> #include <__exception/exception.h> #include <__type_traits/is_constant_evaluated.h> -- GitLab From 2950283dddab03c183c1be2d7de9d4999cc86131 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Tue, 2 Apr 2024 08:14:04 -0400 Subject: [PATCH 053/447] [libc++] Simplify the implementation of (#86843) Libc++'s own is complicated by the need to handle various platform-specific macros and to support duplicate inclusion. In reality, we only need to add a declaration of nullptr_t to it, so we can simply include the underlying outside of our guards to let it handle re-inclusion itself. --- libcxx/include/stddef.h | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/libcxx/include/stddef.h b/libcxx/include/stddef.h index 887776b150e4..470b5408336c 100644 --- a/libcxx/include/stddef.h +++ b/libcxx/include/stddef.h @@ -7,18 +7,6 @@ // //===----------------------------------------------------------------------===// -#if defined(__need_ptrdiff_t) || defined(__need_size_t) || defined(__need_wchar_t) || defined(__need_NULL) || \ - defined(__need_wint_t) - -# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) -# pragma GCC system_header -# endif - -# include_next - -#elif !defined(_LIBCPP_STDDEF_H) -# define _LIBCPP_STDDEF_H - /* stddef.h synopsis @@ -36,16 +24,19 @@ Types: */ -# include <__config> +#include <__config> + +// Note: This include is outside of header guards because we sometimes get included multiple times +// with different defines and the underlying will know how to deal with that. +#include_next + +#ifndef _LIBCPP_STDDEF_H +# define _LIBCPP_STDDEF_H # if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header # endif -# if __has_include_next() -# include_next -# endif - # ifdef __cplusplus typedef decltype(nullptr) nullptr_t; # endif -- GitLab From a4798bb0b67533b37d6b34fd5292714aac3b17d9 Mon Sep 17 00:00:00 2001 From: jeanPerier Date: Tue, 2 Apr 2024 14:29:29 +0200 Subject: [PATCH 054/447] [flang][NFC] use mlir::SymbolTable in lowering (#86673) Whenever lowering is checking if a function or global already exists in the mlir::Module, it was doing module->lookup. On big programs (~5000 globals and functions), this causes important slowdowns because these lookups are linear. Use mlir::SymbolTable to speed-up these lookups. The SymbolTable has to be created from the ModuleOp and maintained in sync. It is therefore placed in the converter, and FirOPBuilders can take a pointer to it to speed-up the lookups. This patch does not bring mlir::SymbolTable to FIR/HLFIR passes, but some passes creating a lot of runtime calls could benefit from it too. More analysis will be needed. As an example of the speed-ups, this patch speeds-up compilation of Whizard compare_amplitude_UFO.F90 from 5 mins to 2 mins on my machine (there is still room for speed-ups). --- flang/include/flang/Lower/AbstractConverter.h | 13 ++++ .../flang/Optimizer/Builder/FIRBuilder.h | 66 +++++++++---------- .../flang/Optimizer/Dialect/FIROpsSupport.h | 19 +++--- flang/lib/Lower/Bridge.cpp | 23 +++++-- flang/lib/Lower/CallInterface.cpp | 9 ++- flang/lib/Lower/OpenACC.cpp | 6 +- flang/lib/Optimizer/Builder/FIRBuilder.cpp | 60 +++++++++++++---- flang/lib/Optimizer/Builder/IntrinsicCall.cpp | 6 +- .../Optimizer/Builder/LowLevelIntrinsics.cpp | 62 +++++++++-------- .../Optimizer/Builder/PPCIntrinsicCall.cpp | 34 +++++----- flang/lib/Optimizer/Dialect/FIROps.cpp | 28 ++++++-- .../Transforms/SimplifyIntrinsics.cpp | 7 +- 12 files changed, 206 insertions(+), 127 deletions(-) diff --git a/flang/include/flang/Lower/AbstractConverter.h b/flang/include/flang/Lower/AbstractConverter.h index 32e7a5e2b040..d5dab9040d22 100644 --- a/flang/include/flang/Lower/AbstractConverter.h +++ b/flang/include/flang/Lower/AbstractConverter.h @@ -23,6 +23,10 @@ #include "mlir/IR/Operation.h" #include "llvm/ADT/ArrayRef.h" +namespace mlir { +class SymbolTable; +} + namespace fir { class KindMapping; class FirOpBuilder; @@ -305,6 +309,15 @@ public: virtual Fortran::lower::SymbolBox lookupOneLevelUpSymbol(const Fortran::semantics::Symbol &sym) = 0; + /// Return the mlir::SymbolTable associated to the ModuleOp. + /// Look-ups are faster using it than using module.lookup<>, + /// but the module op should be queried in case of failure + /// because this symbol table is not guaranteed to contain + /// all the symbols from the ModuleOp (the symbol table should + /// always be provided to the builder helper creating globals and + /// functions in order to be in sync). + virtual mlir::SymbolTable *getMLIRSymbolTable() = 0; + private: /// Options controlling lowering behavior. const Fortran::lower::LoweringOptions &loweringOptions; diff --git a/flang/include/flang/Optimizer/Builder/FIRBuilder.h b/flang/include/flang/Optimizer/Builder/FIRBuilder.h index d61bf681be61..940866b25d2f 100644 --- a/flang/include/flang/Optimizer/Builder/FIRBuilder.h +++ b/flang/include/flang/Optimizer/Builder/FIRBuilder.h @@ -28,6 +28,10 @@ #include #include +namespace mlir { +class SymbolTable; +} + namespace fir { class AbstractArrayBox; class ExtendedValue; @@ -42,8 +46,10 @@ class BoxValue; /// patterns. class FirOpBuilder : public mlir::OpBuilder, public mlir::OpBuilder::Listener { public: - explicit FirOpBuilder(mlir::Operation *op, fir::KindMapping kindMap) - : OpBuilder{op, /*listener=*/this}, kindMap{std::move(kindMap)} {} + explicit FirOpBuilder(mlir::Operation *op, fir::KindMapping kindMap, + mlir::SymbolTable *symbolTable = nullptr) + : OpBuilder{op, /*listener=*/this}, kindMap{std::move(kindMap)}, + symbolTable{symbolTable} {} explicit FirOpBuilder(mlir::OpBuilder &builder, fir::KindMapping kindMap) : OpBuilder(builder), OpBuilder::Listener(), kindMap{std::move(kindMap)} { setListener(this); @@ -69,13 +75,14 @@ public: // The listener self-reference has to be updated in case of copy-construction. FirOpBuilder(const FirOpBuilder &other) : OpBuilder(other), OpBuilder::Listener(), kindMap{other.kindMap}, - fastMathFlags{other.fastMathFlags} { + fastMathFlags{other.fastMathFlags}, symbolTable{other.symbolTable} { setListener(this); } FirOpBuilder(FirOpBuilder &&other) : OpBuilder(other), OpBuilder::Listener(), - kindMap{std::move(other.kindMap)}, fastMathFlags{other.fastMathFlags} { + kindMap{std::move(other.kindMap)}, fastMathFlags{other.fastMathFlags}, + symbolTable{other.symbolTable} { setListener(this); } @@ -95,6 +102,9 @@ public: /// Get a reference to the kind map. const fir::KindMapping &getKindMap() { return kindMap; } + /// Get func.func/fir.global symbol table attached to this builder if any. + mlir::SymbolTable *getMLIRSymbolTable() { return symbolTable; } + /// Get the default integer type [[maybe_unused]] mlir::IntegerType getDefaultIntegerType() { return getIntegerType( @@ -280,24 +290,27 @@ public: /// Get a function by name. If the function exists in the current module, it /// is returned. Otherwise, a null FuncOp is returned. mlir::func::FuncOp getNamedFunction(llvm::StringRef name) { - return getNamedFunction(getModule(), name); + return getNamedFunction(getModule(), getMLIRSymbolTable(), name); } - static mlir::func::FuncOp getNamedFunction(mlir::ModuleOp module, - llvm::StringRef name); + static mlir::func::FuncOp + getNamedFunction(mlir::ModuleOp module, const mlir::SymbolTable *symbolTable, + llvm::StringRef name); /// Get a function by symbol name. The result will be null if there is no /// function with the given symbol in the module. mlir::func::FuncOp getNamedFunction(mlir::SymbolRefAttr symbol) { - return getNamedFunction(getModule(), symbol); + return getNamedFunction(getModule(), getMLIRSymbolTable(), symbol); } - static mlir::func::FuncOp getNamedFunction(mlir::ModuleOp module, - mlir::SymbolRefAttr symbol); + static mlir::func::FuncOp + getNamedFunction(mlir::ModuleOp module, const mlir::SymbolTable *symbolTable, + mlir::SymbolRefAttr symbol); fir::GlobalOp getNamedGlobal(llvm::StringRef name) { - return getNamedGlobal(getModule(), name); + return getNamedGlobal(getModule(), getMLIRSymbolTable(), name); } static fir::GlobalOp getNamedGlobal(mlir::ModuleOp module, + const mlir::SymbolTable *symbolTable, llvm::StringRef name); /// Lazy creation of fir.convert op. @@ -313,35 +326,18 @@ public: /// result of the load if it was created, otherwise return \p val mlir::Value loadIfRef(mlir::Location loc, mlir::Value val); - /// Create a new FuncOp. If the function may have already been created, use - /// `addNamedFunction` instead. + /// Determine if the named function is already in the module. Return the + /// instance if found, otherwise add a new named function to the module. mlir::func::FuncOp createFunction(mlir::Location loc, llvm::StringRef name, mlir::FunctionType ty) { - return createFunction(loc, getModule(), name, ty); + return createFunction(loc, getModule(), name, ty, getMLIRSymbolTable()); } static mlir::func::FuncOp createFunction(mlir::Location loc, mlir::ModuleOp module, llvm::StringRef name, - mlir::FunctionType ty); - - /// Determine if the named function is already in the module. Return the - /// instance if found, otherwise add a new named function to the module. - mlir::func::FuncOp addNamedFunction(mlir::Location loc, llvm::StringRef name, - mlir::FunctionType ty) { - if (auto func = getNamedFunction(name)) - return func; - return createFunction(loc, name, ty); - } - - static mlir::func::FuncOp addNamedFunction(mlir::Location loc, - mlir::ModuleOp module, - llvm::StringRef name, - mlir::FunctionType ty) { - if (auto func = getNamedFunction(module, name)) - return func; - return createFunction(loc, module, name, ty); - } + mlir::FunctionType ty, + mlir::SymbolTable *); /// Cast the input value to IndexType. mlir::Value convertToIndexType(mlir::Location loc, mlir::Value val) { @@ -515,6 +511,10 @@ private: /// FastMathFlags that need to be set for operations that support /// mlir::arith::FastMathAttr. mlir::arith::FastMathFlags fastMathFlags{}; + + /// fir::GlobalOp and func::FuncOp symbol table to speed-up + /// lookups. + mlir::SymbolTable *symbolTable = nullptr; }; } // namespace fir diff --git a/flang/include/flang/Optimizer/Dialect/FIROpsSupport.h b/flang/include/flang/Optimizer/Dialect/FIROpsSupport.h index e8226b6df58c..f29e44504acb 100644 --- a/flang/include/flang/Optimizer/Dialect/FIROpsSupport.h +++ b/flang/include/flang/Optimizer/Dialect/FIROpsSupport.h @@ -52,16 +52,19 @@ inline bool pureCall(mlir::Operation *op) { /// Get or create a FuncOp in a module. /// /// If `module` already contains FuncOp `name`, it is returned. Otherwise, a new -/// FuncOp is created, and that new FuncOp is returned. -mlir::func::FuncOp -createFuncOp(mlir::Location loc, mlir::ModuleOp module, llvm::StringRef name, - mlir::FunctionType type, - llvm::ArrayRef attrs = {}); - -/// Get or create a GlobalOp in a module. +/// FuncOp is created, and that new FuncOp is returned. A symbol table can +/// be provided to speed-up the lookups. +mlir::func::FuncOp createFuncOp(mlir::Location loc, mlir::ModuleOp module, + llvm::StringRef name, mlir::FunctionType type, + llvm::ArrayRef attrs = {}, + const mlir::SymbolTable *symbolTable = nullptr); + +/// Get or create a GlobalOp in a module. A symbol table can be provided to +/// speed-up the lookups. fir::GlobalOp createGlobalOp(mlir::Location loc, mlir::ModuleOp module, llvm::StringRef name, mlir::Type type, - llvm::ArrayRef attrs = {}); + llvm::ArrayRef attrs = {}, + const mlir::SymbolTable *symbolTable = nullptr); /// Attribute to mark Fortran entities with the CONTIGUOUS attribute. constexpr llvm::StringRef getContiguousAttrName() { return "fir.contiguous"; } diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp index 91b898eb513e..5bba0978617c 100644 --- a/flang/lib/Lower/Bridge.cpp +++ b/flang/lib/Lower/Bridge.cpp @@ -273,7 +273,8 @@ class FirConverter : public Fortran::lower::AbstractConverter { public: explicit FirConverter(Fortran::lower::LoweringBridge &bridge) : Fortran::lower::AbstractConverter(bridge.getLoweringOptions()), - bridge{bridge}, foldingContext{bridge.createFoldingContext()} {} + bridge{bridge}, foldingContext{bridge.createFoldingContext()}, + mlirSymbolTable{bridge.getModule()} {} virtual ~FirConverter() = default; /// Convert the PFT to FIR. @@ -329,8 +330,8 @@ public: [&](Fortran::lower::pft::BlockDataUnit &b) {}, [&](Fortran::lower::pft::CompilerDirectiveUnit &d) {}, [&](Fortran::lower::pft::OpenACCDirectiveUnit &d) { - builder = new fir::FirOpBuilder(bridge.getModule(), - bridge.getKindMap()); + builder = new fir::FirOpBuilder( + bridge.getModule(), bridge.getKindMap(), &mlirSymbolTable); Fortran::lower::genOpenACCRoutineConstruct( *this, bridge.getSemanticsContext(), bridge.getModule(), d.routine, accRoutineInfos); @@ -1036,6 +1037,8 @@ private: return {}; } + mlir::SymbolTable *getMLIRSymbolTable() override { return &mlirSymbolTable; } + /// Add the symbol to the local map and return `true`. If the symbol is /// already in the map and \p forced is `false`, the map is not updated. /// Instead the value `false` is returned. @@ -4571,7 +4574,8 @@ private: llvm::dbgs() << "\n"); Fortran::lower::CalleeInterface callee(funit, *this); mlir::func::FuncOp func = callee.addEntryBlockAndMapArguments(); - builder = new fir::FirOpBuilder(func, bridge.getKindMap()); + builder = + new fir::FirOpBuilder(func, bridge.getKindMap(), &mlirSymbolTable); assert(builder && "FirOpBuilder did not instantiate"); builder->setFastMathFlags(bridge.getLoweringOptions().getMathOptions()); builder->setInsertionPointToStart(&func.front()); @@ -4839,12 +4843,14 @@ private: // FIXME: get rid of the bogus function context and instantiate the // globals directly into the module. mlir::MLIRContext *context = &getMLIRContext(); + mlir::SymbolTable *symbolTable = getMLIRSymbolTable(); mlir::func::FuncOp func = fir::FirOpBuilder::createFunction( mlir::UnknownLoc::get(context), getModuleOp(), fir::NameUniquer::doGenerated("Sham"), - mlir::FunctionType::get(context, std::nullopt, std::nullopt)); + mlir::FunctionType::get(context, std::nullopt, std::nullopt), + symbolTable); func.addEntryBlock(); - builder = new fir::FirOpBuilder(func, bridge.getKindMap()); + builder = new fir::FirOpBuilder(func, bridge.getKindMap(), symbolTable); assert(builder && "FirOpBuilder did not instantiate"); builder->setFastMathFlags(bridge.getLoweringOptions().getMathOptions()); createGlobals(); @@ -5336,6 +5342,11 @@ private: /// utilities to deal with procedure pointer components whose arguments have /// the type of the containing derived type. Fortran::lower::TypeConstructionStack typeConstructionStack; + /// MLIR symbol table of the fir.global/func.func operations. Note that it is + /// not guaranteed to contain all operations of the ModuleOp with Symbol + /// attribute since mlirSymbolTable must pro-actively be maintained when + /// new Symbol operations are created. + mlir::SymbolTable mlirSymbolTable; }; } // namespace diff --git a/flang/lib/Lower/CallInterface.cpp b/flang/lib/Lower/CallInterface.cpp index c65becc49745..29cdb3cff589 100644 --- a/flang/lib/Lower/CallInterface.cpp +++ b/flang/lib/Lower/CallInterface.cpp @@ -667,11 +667,13 @@ void Fortran::lower::CallInterface::declare() { if (!side().isIndirectCall()) { std::string name = side().getMangledName(); mlir::ModuleOp module = converter.getModuleOp(); - func = fir::FirOpBuilder::getNamedFunction(module, name); + mlir::SymbolTable *symbolTable = converter.getMLIRSymbolTable(); + func = fir::FirOpBuilder::getNamedFunction(module, symbolTable, name); if (!func) { mlir::Location loc = side().getCalleeLocation(); mlir::FunctionType ty = genFunctionType(); - func = fir::FirOpBuilder::createFunction(loc, module, name, ty); + func = + fir::FirOpBuilder::createFunction(loc, module, name, ty, symbolTable); if (const Fortran::semantics::Symbol *sym = side().getProcedureSymbol()) { if (side().isMainProgram()) { func->setAttr(fir::getSymbolAttrName(), @@ -1644,7 +1646,8 @@ mlir::func::FuncOp Fortran::lower::getOrDeclareFunction( Fortran::lower::AbstractConverter &converter) { mlir::ModuleOp module = converter.getModuleOp(); std::string name = getProcMangledName(proc, converter); - mlir::func::FuncOp func = fir::FirOpBuilder::getNamedFunction(module, name); + mlir::func::FuncOp func = fir::FirOpBuilder::getNamedFunction( + module, converter.getMLIRSymbolTable(), name); if (func) return func; diff --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp index 6e6714454f05..d933c07aba0e 100644 --- a/flang/lib/Lower/OpenACC.cpp +++ b/flang/lib/Lower/OpenACC.cpp @@ -3821,7 +3821,8 @@ void Fortran::lower::genOpenACCRoutineConstruct( std::string funcName; if (name) { funcName = converter.mangleName(*name->symbol); - funcOp = builder.getNamedFunction(mod, funcName); + funcOp = + builder.getNamedFunction(mod, builder.getMLIRSymbolTable(), funcName); } else { Fortran::semantics::Scope &scope = semanticsContext.FindScope(routineConstruct.source); @@ -3833,7 +3834,8 @@ void Fortran::lower::genOpenACCRoutineConstruct( : nullptr}; if (subpDetails && subpDetails->isInterface()) { funcName = converter.mangleName(*progUnit.symbol()); - funcOp = builder.getNamedFunction(mod, funcName); + funcOp = + builder.getNamedFunction(mod, builder.getMLIRSymbolTable(), funcName); } else { funcOp = builder.getFunction(); funcName = funcOp.getName(); diff --git a/flang/lib/Optimizer/Builder/FIRBuilder.cpp b/flang/lib/Optimizer/Builder/FIRBuilder.cpp index 2bcd5e591402..e4362b2f9e69 100644 --- a/flang/lib/Optimizer/Builder/FIRBuilder.cpp +++ b/flang/lib/Optimizer/Builder/FIRBuilder.cpp @@ -36,26 +36,56 @@ static llvm::cl::opt "name"), llvm::cl::init(32)); -mlir::func::FuncOp fir::FirOpBuilder::createFunction(mlir::Location loc, - mlir::ModuleOp module, - llvm::StringRef name, - mlir::FunctionType ty) { - return fir::createFuncOp(loc, module, name, ty); +mlir::func::FuncOp +fir::FirOpBuilder::createFunction(mlir::Location loc, mlir::ModuleOp module, + llvm::StringRef name, mlir::FunctionType ty, + mlir::SymbolTable *symbolTable) { + return fir::createFuncOp(loc, module, name, ty, /*attrs*/ {}, symbolTable); } -mlir::func::FuncOp fir::FirOpBuilder::getNamedFunction(mlir::ModuleOp modOp, - llvm::StringRef name) { +mlir::func::FuncOp +fir::FirOpBuilder::getNamedFunction(mlir::ModuleOp modOp, + const mlir::SymbolTable *symbolTable, + llvm::StringRef name) { + if (symbolTable) + if (auto func = symbolTable->lookup(name)) { +#ifdef EXPENSIVE_CHECKS + assert(func == modOp.lookupSymbol(name) && + "symbolTable and module out of sync"); +#endif + return func; + } return modOp.lookupSymbol(name); } mlir::func::FuncOp fir::FirOpBuilder::getNamedFunction(mlir::ModuleOp modOp, + const mlir::SymbolTable *symbolTable, mlir::SymbolRefAttr symbol) { + if (symbolTable) + if (auto func = symbolTable->lookup( + symbol.getLeafReference())) { +#ifdef EXPENSIVE_CHECKS + assert(func == modOp.lookupSymbol(symbol) && + "symbolTable and module out of sync"); +#endif + return func; + } return modOp.lookupSymbol(symbol); } -fir::GlobalOp fir::FirOpBuilder::getNamedGlobal(mlir::ModuleOp modOp, - llvm::StringRef name) { +fir::GlobalOp +fir::FirOpBuilder::getNamedGlobal(mlir::ModuleOp modOp, + const mlir::SymbolTable *symbolTable, + llvm::StringRef name) { + if (symbolTable) + if (auto global = symbolTable->lookup(name)) { +#ifdef EXPENSIVE_CHECKS + assert(global == modOp.lookupSymbol(name) && + "symbolTable and module out of sync"); +#endif + return global; + } return modOp.lookupSymbol(name); } @@ -279,10 +309,10 @@ fir::GlobalOp fir::FirOpBuilder::createGlobal( mlir::Location loc, mlir::Type type, llvm::StringRef name, mlir::StringAttr linkage, mlir::Attribute value, bool isConst, bool isTarget, fir::CUDADataAttributeAttr cudaAttr) { + if (auto global = getNamedGlobal(name)) + return global; auto module = getModule(); auto insertPt = saveInsertionPoint(); - if (auto glob = module.lookupSymbol(name)) - return glob; setInsertionPoint(module.getBody(), module.getBody()->end()); llvm::SmallVector attrs; if (cudaAttr) { @@ -294,6 +324,8 @@ fir::GlobalOp fir::FirOpBuilder::createGlobal( auto glob = create(loc, name, isConst, isTarget, type, value, linkage, attrs); restoreInsertionPoint(insertPt); + if (symbolTable) + symbolTable->insert(glob); return glob; } @@ -301,10 +333,10 @@ fir::GlobalOp fir::FirOpBuilder::createGlobal( mlir::Location loc, mlir::Type type, llvm::StringRef name, bool isConst, bool isTarget, std::function bodyBuilder, mlir::StringAttr linkage, fir::CUDADataAttributeAttr cudaAttr) { + if (auto global = getNamedGlobal(name)) + return global; auto module = getModule(); auto insertPt = saveInsertionPoint(); - if (auto glob = module.lookupSymbol(name)) - return glob; setInsertionPoint(module.getBody(), module.getBody()->end()); auto glob = create(loc, name, isConst, isTarget, type, mlir::Attribute{}, linkage); @@ -314,6 +346,8 @@ fir::GlobalOp fir::FirOpBuilder::createGlobal( setInsertionPointToStart(&block); bodyBuilder(*this); restoreInsertionPoint(insertPt); + if (symbolTable) + symbolTable->insert(glob); return glob; } diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp index ea1ef1f08aba..069ba81cfe96 100644 --- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp +++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp @@ -724,7 +724,7 @@ mlir::Value genLibCall(fir::FirOpBuilder &builder, mlir::Location loc, mlir::func::FuncOp funcOp = builder.getNamedFunction(libFuncName); if (!funcOp) { - funcOp = builder.addNamedFunction(loc, libFuncName, libFuncType); + funcOp = builder.createFunction(loc, libFuncName, libFuncType); // C-interoperability rules apply to these library functions. funcOp->setAttr(fir::getSymbolAttrName(), mlir::StringAttr::get(builder.getContext(), libFuncName)); @@ -1894,8 +1894,8 @@ mlir::func::FuncOp IntrinsicLibrary::getWrapper(GeneratorType generator, // Create local context to emit code into the newly created function // This new function is not linked to a source file location, only // its calls will be. - auto localBuilder = - std::make_unique(function, builder.getKindMap()); + auto localBuilder = std::make_unique( + function, builder.getKindMap(), builder.getMLIRSymbolTable()); localBuilder->setFastMathFlags(builder.getFastMathFlags()); localBuilder->setInsertionPointToStart(&function.front()); // Location of code inside wrapper of the wrapper is independent from diff --git a/flang/lib/Optimizer/Builder/LowLevelIntrinsics.cpp b/flang/lib/Optimizer/Builder/LowLevelIntrinsics.cpp index 1d07b1e724d7..bb5f77d5d4d1 100644 --- a/flang/lib/Optimizer/Builder/LowLevelIntrinsics.cpp +++ b/flang/lib/Optimizer/Builder/LowLevelIntrinsics.cpp @@ -27,8 +27,8 @@ mlir::func::FuncOp fir::factory::getLlvmMemcpy(fir::FirOpBuilder &builder) { builder.getI1Type()}; auto memcpyTy = mlir::FunctionType::get(builder.getContext(), args, std::nullopt); - return builder.addNamedFunction(builder.getUnknownLoc(), - "llvm.memcpy.p0.p0.i64", memcpyTy); + return builder.createFunction(builder.getUnknownLoc(), + "llvm.memcpy.p0.p0.i64", memcpyTy); } mlir::func::FuncOp fir::factory::getLlvmMemmove(fir::FirOpBuilder &builder) { @@ -37,8 +37,8 @@ mlir::func::FuncOp fir::factory::getLlvmMemmove(fir::FirOpBuilder &builder) { builder.getI1Type()}; auto memmoveTy = mlir::FunctionType::get(builder.getContext(), args, std::nullopt); - return builder.addNamedFunction(builder.getUnknownLoc(), - "llvm.memmove.p0.p0.i64", memmoveTy); + return builder.createFunction(builder.getUnknownLoc(), + "llvm.memmove.p0.p0.i64", memmoveTy); } mlir::func::FuncOp fir::factory::getLlvmMemset(fir::FirOpBuilder &builder) { @@ -47,16 +47,15 @@ mlir::func::FuncOp fir::factory::getLlvmMemset(fir::FirOpBuilder &builder) { builder.getI1Type()}; auto memsetTy = mlir::FunctionType::get(builder.getContext(), args, std::nullopt); - return builder.addNamedFunction(builder.getUnknownLoc(), - "llvm.memset.p0.p0.i64", memsetTy); + return builder.createFunction(builder.getUnknownLoc(), + "llvm.memset.p0.p0.i64", memsetTy); } mlir::func::FuncOp fir::factory::getRealloc(fir::FirOpBuilder &builder) { auto ptrTy = builder.getRefType(builder.getIntegerType(8)); llvm::SmallVector args = {ptrTy, builder.getI64Type()}; auto reallocTy = mlir::FunctionType::get(builder.getContext(), args, {ptrTy}); - return builder.addNamedFunction(builder.getUnknownLoc(), "realloc", - reallocTy); + return builder.createFunction(builder.getUnknownLoc(), "realloc", reallocTy); } mlir::func::FuncOp @@ -64,8 +63,8 @@ fir::factory::getLlvmGetRounding(fir::FirOpBuilder &builder) { auto int32Ty = builder.getIntegerType(32); auto funcTy = mlir::FunctionType::get(builder.getContext(), std::nullopt, {int32Ty}); - return builder.addNamedFunction(builder.getUnknownLoc(), "llvm.get.rounding", - funcTy); + return builder.createFunction(builder.getUnknownLoc(), "llvm.get.rounding", + funcTy); } mlir::func::FuncOp @@ -73,8 +72,8 @@ fir::factory::getLlvmSetRounding(fir::FirOpBuilder &builder) { auto int32Ty = builder.getIntegerType(32); auto funcTy = mlir::FunctionType::get(builder.getContext(), {int32Ty}, std::nullopt); - return builder.addNamedFunction(builder.getUnknownLoc(), "llvm.set.rounding", - funcTy); + return builder.createFunction(builder.getUnknownLoc(), "llvm.set.rounding", + funcTy); } mlir::func::FuncOp fir::factory::getLlvmStackSave(fir::FirOpBuilder &builder) { @@ -82,8 +81,8 @@ mlir::func::FuncOp fir::factory::getLlvmStackSave(fir::FirOpBuilder &builder) { auto ptrTy = builder.getRefType(builder.getIntegerType(8)); auto funcTy = mlir::FunctionType::get(builder.getContext(), std::nullopt, {ptrTy}); - return builder.addNamedFunction(builder.getUnknownLoc(), "llvm.stacksave.p0", - funcTy); + return builder.createFunction(builder.getUnknownLoc(), "llvm.stacksave.p0", + funcTy); } mlir::func::FuncOp @@ -92,8 +91,8 @@ fir::factory::getLlvmStackRestore(fir::FirOpBuilder &builder) { auto ptrTy = builder.getRefType(builder.getIntegerType(8)); auto funcTy = mlir::FunctionType::get(builder.getContext(), {ptrTy}, std::nullopt); - return builder.addNamedFunction(builder.getUnknownLoc(), - "llvm.stackrestore.p0", funcTy); + return builder.createFunction(builder.getUnknownLoc(), "llvm.stackrestore.p0", + funcTy); } mlir::func::FuncOp @@ -101,24 +100,24 @@ fir::factory::getLlvmInitTrampoline(fir::FirOpBuilder &builder) { auto ptrTy = builder.getRefType(builder.getIntegerType(8)); auto funcTy = mlir::FunctionType::get(builder.getContext(), {ptrTy, ptrTy, ptrTy}, std::nullopt); - return builder.addNamedFunction(builder.getUnknownLoc(), - "llvm.init.trampoline", funcTy); + return builder.createFunction(builder.getUnknownLoc(), "llvm.init.trampoline", + funcTy); } mlir::func::FuncOp fir::factory::getLlvmAdjustTrampoline(fir::FirOpBuilder &builder) { auto ptrTy = builder.getRefType(builder.getIntegerType(8)); auto funcTy = mlir::FunctionType::get(builder.getContext(), {ptrTy}, {ptrTy}); - return builder.addNamedFunction(builder.getUnknownLoc(), - "llvm.adjust.trampoline", funcTy); + return builder.createFunction(builder.getUnknownLoc(), + "llvm.adjust.trampoline", funcTy); } mlir::func::FuncOp fir::factory::getFeclearexcept(fir::FirOpBuilder &builder) { auto int32Ty = builder.getIntegerType(32); auto funcTy = mlir::FunctionType::get(builder.getContext(), {int32Ty}, {int32Ty}); - return builder.addNamedFunction(builder.getUnknownLoc(), "feclearexcept", - funcTy); + return builder.createFunction(builder.getUnknownLoc(), "feclearexcept", + funcTy); } mlir::func::FuncOp @@ -126,38 +125,37 @@ fir::factory::getFedisableexcept(fir::FirOpBuilder &builder) { auto int32Ty = builder.getIntegerType(32); auto funcTy = mlir::FunctionType::get(builder.getContext(), {int32Ty}, {int32Ty}); - return builder.addNamedFunction(builder.getUnknownLoc(), "fedisableexcept", - funcTy); + return builder.createFunction(builder.getUnknownLoc(), "fedisableexcept", + funcTy); } mlir::func::FuncOp fir::factory::getFeenableexcept(fir::FirOpBuilder &builder) { auto int32Ty = builder.getIntegerType(32); auto funcTy = mlir::FunctionType::get(builder.getContext(), {int32Ty}, {int32Ty}); - return builder.addNamedFunction(builder.getUnknownLoc(), "feenableexcept", - funcTy); + return builder.createFunction(builder.getUnknownLoc(), "feenableexcept", + funcTy); } mlir::func::FuncOp fir::factory::getFegetexcept(fir::FirOpBuilder &builder) { auto int32Ty = builder.getIntegerType(32); auto funcTy = mlir::FunctionType::get(builder.getContext(), std::nullopt, {int32Ty}); - return builder.addNamedFunction(builder.getUnknownLoc(), "fegetexcept", - funcTy); + return builder.createFunction(builder.getUnknownLoc(), "fegetexcept", funcTy); } mlir::func::FuncOp fir::factory::getFeraiseexcept(fir::FirOpBuilder &builder) { auto int32Ty = builder.getIntegerType(32); auto funcTy = mlir::FunctionType::get(builder.getContext(), {int32Ty}, {int32Ty}); - return builder.addNamedFunction(builder.getUnknownLoc(), "feraiseexcept", - funcTy); + return builder.createFunction(builder.getUnknownLoc(), "feraiseexcept", + funcTy); } mlir::func::FuncOp fir::factory::getFetestexcept(fir::FirOpBuilder &builder) { auto int32Ty = builder.getIntegerType(32); auto funcTy = mlir::FunctionType::get(builder.getContext(), {int32Ty}, {int32Ty}); - return builder.addNamedFunction(builder.getUnknownLoc(), "fetestexcept", - funcTy); + return builder.createFunction(builder.getUnknownLoc(), "fetestexcept", + funcTy); } diff --git a/flang/lib/Optimizer/Builder/PPCIntrinsicCall.cpp b/flang/lib/Optimizer/Builder/PPCIntrinsicCall.cpp index ab0d5079d8af..e588b19dded4 100644 --- a/flang/lib/Optimizer/Builder/PPCIntrinsicCall.cpp +++ b/flang/lib/Optimizer/Builder/PPCIntrinsicCall.cpp @@ -1084,11 +1084,11 @@ void PPCIntrinsicLibrary::genMtfsf(llvm::ArrayRef args) { if (isImm) { libFuncType = genFuncType, Ty::Integer<4>>( builder.getContext(), builder); - funcOp = builder.addNamedFunction(loc, "llvm.ppc.mtfsfi", libFuncType); + funcOp = builder.createFunction(loc, "llvm.ppc.mtfsfi", libFuncType); } else { libFuncType = genFuncType, Ty::Real<8>>( builder.getContext(), builder); - funcOp = builder.addNamedFunction(loc, "llvm.ppc.mtfsf", libFuncType); + funcOp = builder.createFunction(loc, "llvm.ppc.mtfsf", libFuncType); } builder.create(loc, funcOp, scalarArgs); } @@ -1116,7 +1116,7 @@ PPCIntrinsicLibrary::genVecAbs(mlir::Type resultType, genFuncType, Ty::RealVector<8>>(context, builder); } - funcOp = builder.addNamedFunction(loc, fname, ftype); + funcOp = builder.createFunction(loc, fname, ftype); auto callOp{builder.create(loc, funcOp, argBases[0])}; return callOp.getResult(0); } else if (auto eleTy = vTypeInfo.eleTy.dyn_cast()) { @@ -1155,7 +1155,7 @@ PPCIntrinsicLibrary::genVecAbs(mlir::Type resultType, default: llvm_unreachable("invalid integer size"); } - funcOp = builder.addNamedFunction(loc, fname, ftype); + funcOp = builder.createFunction(loc, fname, ftype); mlir::Value args[] = {zeroSubVarg1, varg1}; auto callOp{builder.create(loc, funcOp, args)}; @@ -1339,7 +1339,7 @@ PPCIntrinsicLibrary::genVecAnyCompare(mlir::Type resultType, } assert((!fname.empty() && ftype) && "invalid type"); - mlir::func::FuncOp funcOp{builder.addNamedFunction(loc, fname, ftype)}; + mlir::func::FuncOp funcOp{builder.createFunction(loc, fname, ftype)}; auto callOp{builder.create(loc, funcOp, cmpArgs)}; return callOp.getResult(0); } @@ -1445,7 +1445,7 @@ PPCIntrinsicLibrary::genVecCmp(mlir::Type resultType, std::pair funcTyNam{ getVecCmpFuncTypeAndName(vecTyInfo, vop, builder)}; - mlir::func::FuncOp funcOp = builder.addNamedFunction( + mlir::func::FuncOp funcOp = builder.createFunction( loc, std::get<0>(funcTyNam), std::get<1>(funcTyNam)); mlir::Value res{nullptr}; @@ -1572,7 +1572,7 @@ PPCIntrinsicLibrary::genVecConvert(mlir::Type resultType, Ty::Integer<4>>(context, builder)}; const llvm::StringRef fname{(isUnsigned) ? "llvm.ppc.altivec.vcfux" : "llvm.ppc.altivec.vcfsx"}; - auto funcOp{builder.addNamedFunction(loc, fname, ftype)}; + auto funcOp{builder.createFunction(loc, fname, ftype)}; mlir::Value newArgs[] = {argBases[0], convArg}; auto callOp{builder.create(loc, funcOp, newArgs)}; @@ -1627,7 +1627,7 @@ PPCIntrinsicLibrary::genVecConvert(mlir::Type resultType, const llvm::StringRef fname{"llvm.ppc.vsx.xvcvspdp"}; auto ftype{ genFuncType, Ty::RealVector<4>>(context, builder)}; - auto funcOp{builder.addNamedFunction(loc, fname, ftype)}; + auto funcOp{builder.createFunction(loc, fname, ftype)}; auto callOp{builder.create(loc, funcOp, newArgs)}; return callOp.getResult(0); @@ -1635,7 +1635,7 @@ PPCIntrinsicLibrary::genVecConvert(mlir::Type resultType, const llvm::StringRef fname{"llvm.ppc.vsx.xvcvdpsp"}; auto ftype{ genFuncType, Ty::RealVector<8>>(context, builder)}; - auto funcOp{builder.addNamedFunction(loc, fname, ftype)}; + auto funcOp{builder.createFunction(loc, fname, ftype)}; newArgs[0] = builder.create(loc, funcOp, newArgs).getResult(0); auto fvf32Ty{newArgs[0].getType()}; @@ -1963,7 +1963,7 @@ PPCIntrinsicLibrary::genVecLdCallGrp(mlir::Type resultType, auto funcType{ mlir::FunctionType::get(context, {addr.getType()}, {intrinResTy})}; - auto funcOp{builder.addNamedFunction(loc, fname, funcType)}; + auto funcOp{builder.createFunction(loc, fname, funcType)}; auto result{ builder.create(loc, funcOp, parsedArgs).getResult(0)}; @@ -2022,7 +2022,7 @@ PPCIntrinsicLibrary::genVecLvsGrp(mlir::Type resultType, llvm_unreachable("invalid vector operation for generator"); } auto funcType{mlir::FunctionType::get(context, {addr.getType()}, {mlirTy})}; - auto funcOp{builder.addNamedFunction(loc, fname, funcType)}; + auto funcOp{builder.createFunction(loc, fname, funcType)}; auto result{ builder.create(loc, funcOp, parsedArgs).getResult(0)}; @@ -2057,8 +2057,8 @@ PPCIntrinsicLibrary::genVecNmaddMsub(mlir::Type resultType, genFuncType, Ty::RealVector<8>, Ty::RealVector<8>>( context, builder))}}; - auto funcOp{builder.addNamedFunction(loc, std::get<0>(fmaMap[width]), - std::get<1>(fmaMap[width]))}; + auto funcOp{builder.createFunction(loc, std::get<0>(fmaMap[width]), + std::get<1>(fmaMap[width]))}; if (vop == VecOp::Nmadd) { // vec_nmadd(arg1, arg2, arg3) = -fma(arg1, arg2, arg3) auto callOp{builder.create(loc, funcOp, newArgs)}; @@ -2110,7 +2110,7 @@ PPCIntrinsicLibrary::genVecPerm(mlir::Type resultType, builder.create(loc, vi32Ty, mArg1).getResult(); } - auto funcOp{builder.addNamedFunction( + auto funcOp{builder.createFunction( loc, "llvm.ppc.altivec.vperm", genFuncType, Ty::IntegerVector<4>, Ty::IntegerVector<4>, Ty::IntegerVector<1>>(context, @@ -2307,7 +2307,7 @@ PPCIntrinsicLibrary::genVecShift(mlir::Type resultType, } auto funcTy{genFuncType, Ty::IntegerVector<4>, Ty::IntegerVector<4>>(context, builder)}; - mlir::func::FuncOp funcOp{builder.addNamedFunction(loc, funcName, funcTy)}; + mlir::func::FuncOp funcOp{builder.createFunction(loc, funcName, funcTy)}; auto callOp{builder.create(loc, funcOp, mlirVecArgs)}; // If the result vector type is different from the original type, need @@ -2755,7 +2755,7 @@ void PPCIntrinsicLibrary::genMmaIntr(llvm::ArrayRef args) { auto context{builder.getContext()}; mlir::FunctionType intrFuncType{getMmaIrFuncType(context, IntrId)}; mlir::func::FuncOp funcOp{ - builder.addNamedFunction(loc, getMmaIrIntrName(IntrId), intrFuncType)}; + builder.createFunction(loc, getMmaIrIntrName(IntrId), intrFuncType)}; llvm::SmallVector intrArgs; // Depending on SubToFunc, change the subroutine call to a function call. @@ -2892,7 +2892,7 @@ void PPCIntrinsicLibrary::genVecStore(llvm::ArrayRef args) { auto funcType{ mlir::FunctionType::get(context, {stTy, addr.getType()}, std::nullopt)}; - mlir::func::FuncOp funcOp = builder.addNamedFunction(loc, fname, funcType); + mlir::func::FuncOp funcOp = builder.createFunction(loc, fname, funcType); llvm::SmallVector biArgs; diff --git a/flang/lib/Optimizer/Dialect/FIROps.cpp b/flang/lib/Optimizer/Dialect/FIROps.cpp index 9bb10a42a399..dba2c30d1851 100644 --- a/flang/lib/Optimizer/Dialect/FIROps.cpp +++ b/flang/lib/Optimizer/Dialect/FIROps.cpp @@ -3677,10 +3677,19 @@ fir::parseSelector(mlir::OpAsmParser &parser, mlir::OperationState &result, return mlir::success(); } -mlir::func::FuncOp -fir::createFuncOp(mlir::Location loc, mlir::ModuleOp module, - llvm::StringRef name, mlir::FunctionType type, - llvm::ArrayRef attrs) { +mlir::func::FuncOp fir::createFuncOp(mlir::Location loc, mlir::ModuleOp module, + llvm::StringRef name, + mlir::FunctionType type, + llvm::ArrayRef attrs, + const mlir::SymbolTable *symbolTable) { + if (symbolTable) + if (auto f = symbolTable->lookup(name)) { +#ifdef EXPENSIVE_CHECKS + assert(f == module.lookupSymbol(name) && + "symbolTable and module out of sync"); +#endif + return f; + } if (auto f = module.lookupSymbol(name)) return f; mlir::OpBuilder modBuilder(module.getBodyRegion()); @@ -3692,7 +3701,16 @@ fir::createFuncOp(mlir::Location loc, mlir::ModuleOp module, fir::GlobalOp fir::createGlobalOp(mlir::Location loc, mlir::ModuleOp module, llvm::StringRef name, mlir::Type type, - llvm::ArrayRef attrs) { + llvm::ArrayRef attrs, + const mlir::SymbolTable *symbolTable) { + if (symbolTable) + if (auto g = symbolTable->lookup(name)) { +#ifdef EXPENSIVE_CHECKS + assert(g == module.lookupSymbol(name) && + "symbolTable and module out of sync"); +#endif + return g; + } if (auto g = module.lookupSymbol(name)) return g; mlir::OpBuilder modBuilder(module.getBodyRegion()); diff --git a/flang/lib/Optimizer/Transforms/SimplifyIntrinsics.cpp b/flang/lib/Optimizer/Transforms/SimplifyIntrinsics.cpp index a11aa38c771b..f7820b6b8170 100644 --- a/flang/lib/Optimizer/Transforms/SimplifyIntrinsics.cpp +++ b/flang/lib/Optimizer/Transforms/SimplifyIntrinsics.cpp @@ -1004,10 +1004,8 @@ mlir::func::FuncOp SimplifyIntrinsicsPass::getOrCreateFunction( // We can also avoid this by using internal linkage, but // this may increase the size of final executable/shared library. std::string replacementName = mlir::Twine{baseName, "_simplified"}.str(); - mlir::ModuleOp module = builder.getModule(); // If we already have a function, just return it. - mlir::func::FuncOp newFunc = - fir::FirOpBuilder::getNamedFunction(module, replacementName); + mlir::func::FuncOp newFunc = builder.getNamedFunction(replacementName); mlir::FunctionType fType = typeGenerator(builder); if (newFunc) { assert(newFunc.getFunctionType() == fType && @@ -1017,8 +1015,7 @@ mlir::func::FuncOp SimplifyIntrinsicsPass::getOrCreateFunction( // Need to build the function! auto loc = mlir::UnknownLoc::get(builder.getContext()); - newFunc = - fir::FirOpBuilder::createFunction(loc, module, replacementName, fType); + newFunc = builder.createFunction(loc, replacementName, fType); auto inlineLinkage = mlir::LLVM::linkage::Linkage::LinkonceODR; auto linkage = mlir::LLVM::LinkageAttr::get(builder.getContext(), inlineLinkage); -- GitLab From eb08c0f1659d12524f58a01bf174177b8acedf2e Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski Date: Tue, 2 Apr 2024 08:35:42 -0400 Subject: [PATCH 055/447] [Clang][Sema] Fix explicit specializations of member function templates with a deduced return type (#86817) Clang erroneously rejects the following: ``` template struct A { template auto f(); }; template<> template auto A::f(); // error: conflicting types for 'f' ``` This happens because the explicit specialization of `f` has its return type replaced with a dependent `AutoType` in `ActOnFunctionDeclarator`, but no such replacement occurs for the implicitly instantiated function template `A::f`. Since the return types don't match, the explicit specialization is diagnosed as an invalid redeclaration. This patch moves the replacement of the return type to `CheckFunctionDeclaration` so it also happens during instantiation. `setObjectOfFriendDecl` will have been called by then, so the `isFriend && CurContext->isDependentContext()` condition is made redundant & removed (as it already happens in `DeclContext::isDependentContext`). `Sema::IsOverload` only checks the _declared_ return type (which isn't changed by the adjustment), so adjusting the return type afterwards should be safe. --- .../clang-tidy/infrastructure/diagnostic.cpp | 4 +- clang/docs/ReleaseNotes.rst | 2 + clang/lib/Sema/SemaDecl.cpp | 46 ++++++++++++------- .../SemaCXX/deduced-return-type-cxx14.cpp | 18 ++++++++ 4 files changed, 50 insertions(+), 20 deletions(-) diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/diagnostic.cpp b/clang-tools-extra/test/clang-tidy/infrastructure/diagnostic.cpp index d0efc5ca7637..57d930b26e64 100644 --- a/clang-tools-extra/test/clang-tidy/infrastructure/diagnostic.cpp +++ b/clang-tools-extra/test/clang-tidy/infrastructure/diagnostic.cpp @@ -25,7 +25,7 @@ // RUN: not clang-tidy -checks='-*,modernize-use-override' %T/diagnostics/input.cpp -- -DCOMPILATION_ERROR 2>&1 | FileCheck -check-prefix=CHECK6 -implicit-check-not='{{warning:|error:}}' %s // RUN: clang-tidy -checks='-*,modernize-use-override,clang-diagnostic-macro-redefined' %s -- -DMACRO_FROM_COMMAND_LINE -std=c++20 | FileCheck -check-prefix=CHECK4 -implicit-check-not='{{warning:|error:}}' %s // RUN: clang-tidy -checks='-*,modernize-use-override,clang-diagnostic-macro-redefined,clang-diagnostic-literal-conversion' %s -- -DMACRO_FROM_COMMAND_LINE -std=c++20 -Wno-macro-redefined | FileCheck --check-prefix=CHECK7 -implicit-check-not='{{warning:|error:}}' %s -// RUN: not clang-tidy -checks='-*,modernize-use-override' %s -- -std=c++20 -DPR64602 | FileCheck -check-prefix=CHECK8 -implicit-check-not='{{warning:|error:}}' %s +// RUN: clang-tidy -checks='-*,modernize-use-override' %s -- -std=c++20 -DPR64602 // CHECK1: error: no input files [clang-diagnostic-error] // CHECK1: error: no such file or directory: '{{.*}}nonexistent.cpp' [clang-diagnostic-error] @@ -68,6 +68,4 @@ auto S<>::foo(auto) { return 1; } -// CHECK8: error: conflicting types for 'foo' [clang-diagnostic-error] -// CHECK8: note: previous declaration is here #endif diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index b2faab1f1525..3a84ff16a1e4 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -483,6 +483,8 @@ Bug Fixes to C++ Support following the first `::` were ignored). - Fix an out-of-bounds crash when checking the validity of template partial specializations. (part of #GH86757). - Fix an issue caused by not handling invalid cases when substituting into the parameter mapping of a constraint. Fixes (#GH86757). +- Fixed a bug that prevented member function templates of class templates declared with a deduced return type + from being explicitly specialized for a given implicit instantiation of the class template. Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 6ff85c0c5c29..5c1152896559 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -10124,23 +10124,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_auto_fn_virtual); } - if (getLangOpts().CPlusPlus14 && - (NewFD->isDependentContext() || - (isFriend && CurContext->isDependentContext())) && - NewFD->getReturnType()->isUndeducedType()) { - // If the function template is referenced directly (for instance, as a - // member of the current instantiation), pretend it has a dependent type. - // This is not really justified by the standard, but is the only sane - // thing to do. - // FIXME: For a friend function, we have not marked the function as being - // a friend yet, so 'isDependentContext' on the FD doesn't work. - const FunctionProtoType *FPT = - NewFD->getType()->castAs(); - QualType Result = SubstAutoTypeDependent(FPT->getReturnType()); - NewFD->setType(Context.getFunctionType(Result, FPT->getParamTypes(), - FPT->getExtProtoInfo())); - } - // C++ [dcl.fct.spec]p3: // The inline specifier shall not appear on a block scope function // declaration. @@ -12112,6 +12095,35 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, CheckConstPureAttributesUsage(*this, NewFD); + // C++ [dcl.spec.auto.general]p12: + // Return type deduction for a templated function with a placeholder in its + // declared type occurs when the definition is instantiated even if the + // function body contains a return statement with a non-type-dependent + // operand. + // + // C++ [temp.dep.expr]p3: + // An id-expression is type-dependent if it is a template-id that is not a + // concept-id and is dependent; or if its terminal name is: + // - [...] + // - associated by name lookup with one or more declarations of member + // functions of a class that is the current instantiation declared with a + // return type that contains a placeholder type, + // - [...] + // + // If this is a templated function with a placeholder in its return type, + // make the placeholder type dependent since it won't be deduced until the + // definition is instantiated. We do this here because it needs to happen + // for implicitly instantiated member functions/member function templates. + if (getLangOpts().CPlusPlus14 && + (NewFD->isDependentContext() && + NewFD->getReturnType()->isUndeducedType())) { + const FunctionProtoType *FPT = + NewFD->getType()->castAs(); + QualType NewReturnType = SubstAutoTypeDependent(FPT->getReturnType()); + NewFD->setType(Context.getFunctionType(NewReturnType, FPT->getParamTypes(), + FPT->getExtProtoInfo())); + } + // C++11 [dcl.constexpr]p8: // A constexpr specifier for a non-static member function that is not // a constructor declares that member function to be const. diff --git a/clang/test/SemaCXX/deduced-return-type-cxx14.cpp b/clang/test/SemaCXX/deduced-return-type-cxx14.cpp index 431d77ca785b..c33e07088ba3 100644 --- a/clang/test/SemaCXX/deduced-return-type-cxx14.cpp +++ b/clang/test/SemaCXX/deduced-return-type-cxx14.cpp @@ -237,6 +237,24 @@ namespace Templates { int (S::*(*p)())(double) = f; int (S::*(*q)())(double) = f; } + + template + struct MemberSpecialization { + auto f(); + template auto f(U); + template auto *f(U); + }; + + template<> + auto MemberSpecialization::f(); + + template<> + template + auto MemberSpecialization::f(U); + + template<> + template + auto *MemberSpecialization::f(U); } auto fwd_decl_using(); -- GitLab From 63d22f7a5b6afc515799f67c388bf5a8864274e4 Mon Sep 17 00:00:00 2001 From: Christian Ulmann Date: Tue, 2 Apr 2024 14:35:55 +0200 Subject: [PATCH 056/447] [MLIR][LLVM][SROA] Make GEP handling type agnostic (#86950) This commit removes SROA's type consistency constraints from LLVM dialect's GEPOp. The checks for valid indexing are now purely done by computing the GEP's offset with the aid of the data layout. To simplify handling of "nested subslots", we are tricking the SROA by handing in memory slots that hold byte array types. This ensures that subsequent accesses only need to check if their access will be in-bounds. This lifts the requirement of determining the sub-types for all but the first level of subslots. --- mlir/lib/Dialect/LLVMIR/IR/LLVMMemorySlot.cpp | 241 +++++++++++++----- mlir/test/Dialect/LLVMIR/sroa.mlir | 130 ++++++++++ 2 files changed, 312 insertions(+), 59 deletions(-) diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMMemorySlot.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMMemorySlot.cpp index f171bf7cc4be..06c1fdd2eb2d 100644 --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMMemorySlot.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMMemorySlot.cpp @@ -20,6 +20,8 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/TypeSwitch.h" +#define DEBUG_TYPE "sroa" + using namespace mlir; //===----------------------------------------------------------------------===// @@ -431,10 +433,147 @@ DeletionKind LLVM::GEPOp::removeBlockingUses( return DeletionKind::Delete; } -static bool isFirstIndexZero(LLVM::GEPOp gep) { - IntegerAttr index = - llvm::dyn_cast_if_present(gep.getIndices()[0]); - return index && index.getInt() == 0; +/// Returns the amount of bytes the provided GEP elements will offset the +/// pointer by. Returns nullopt if no constant offset could be computed. +static std::optional gepToByteOffset(const DataLayout &dataLayout, + LLVM::GEPOp gep) { + // Collects all indices. + SmallVector indices; + for (auto index : gep.getIndices()) { + auto constIndex = dyn_cast(index); + if (!constIndex) + return {}; + int64_t gepIndex = constIndex.getInt(); + // Negative indices are not supported. + if (gepIndex < 0) + return {}; + indices.push_back(gepIndex); + } + + Type currentType = gep.getElemType(); + uint64_t offset = indices[0] * dataLayout.getTypeSize(currentType); + + for (uint64_t index : llvm::drop_begin(indices)) { + bool shouldCancel = + TypeSwitch(currentType) + .Case([&](LLVM::LLVMArrayType arrayType) { + offset += + index * dataLayout.getTypeSize(arrayType.getElementType()); + currentType = arrayType.getElementType(); + return false; + }) + .Case([&](LLVM::LLVMStructType structType) { + ArrayRef body = structType.getBody(); + assert(index < body.size() && "expected valid struct indexing"); + for (uint32_t i : llvm::seq(index)) { + if (!structType.isPacked()) + offset = llvm::alignTo( + offset, dataLayout.getTypeABIAlignment(body[i])); + offset += dataLayout.getTypeSize(body[i]); + } + + // Align for the current type as well. + if (!structType.isPacked()) + offset = llvm::alignTo( + offset, dataLayout.getTypeABIAlignment(body[index])); + currentType = body[index]; + return false; + }) + .Default([&](Type type) { + LLVM_DEBUG(llvm::dbgs() + << "[sroa] Unsupported type for offset computations" + << type << "\n"); + return true; + }); + + if (shouldCancel) + return std::nullopt; + } + + return offset; +} + +namespace { +/// A struct that stores both the index into the aggregate type of the slot as +/// well as the corresponding byte offset in memory. +struct SubslotAccessInfo { + /// The parent slot's index that the access falls into. + uint32_t index; + /// The offset into the subslot of the access. + uint64_t subslotOffset; +}; +} // namespace + +/// Computes subslot access information for an access into `slot` with the given +/// offset. +/// Returns nullopt when the offset is out-of-bounds or when the access is into +/// the padding of `slot`. +static std::optional +getSubslotAccessInfo(const DestructurableMemorySlot &slot, + const DataLayout &dataLayout, LLVM::GEPOp gep) { + std::optional offset = gepToByteOffset(dataLayout, gep); + if (!offset) + return {}; + + // Helper to check that a constant index is in the bounds of the GEP index + // representation. LLVM dialects's GEP arguments have a limited bitwidth, thus + // this additional check is necessary. + auto isOutOfBoundsGEPIndex = [](uint64_t index) { + return index >= (1 << LLVM::kGEPConstantBitWidth); + }; + + Type type = slot.elemType; + if (*offset >= dataLayout.getTypeSize(type)) + return {}; + return TypeSwitch>(type) + .Case([&](LLVM::LLVMArrayType arrayType) + -> std::optional { + // Find which element of the array contains the offset. + uint64_t elemSize = dataLayout.getTypeSize(arrayType.getElementType()); + uint64_t index = *offset / elemSize; + if (isOutOfBoundsGEPIndex(index)) + return {}; + return SubslotAccessInfo{static_cast(index), + *offset - (index * elemSize)}; + }) + .Case([&](LLVM::LLVMStructType structType) + -> std::optional { + uint64_t distanceToStart = 0; + // Walk over the elements of the struct to find in which of + // them the offset is. + for (auto [index, elem] : llvm::enumerate(structType.getBody())) { + uint64_t elemSize = dataLayout.getTypeSize(elem); + if (!structType.isPacked()) { + distanceToStart = llvm::alignTo( + distanceToStart, dataLayout.getTypeABIAlignment(elem)); + // If the offset is in padding, cancel the rewrite. + if (offset < distanceToStart) + return {}; + } + + if (offset < distanceToStart + elemSize) { + if (isOutOfBoundsGEPIndex(index)) + return {}; + // The offset is within this element, stop iterating the + // struct and return the index. + return SubslotAccessInfo{static_cast(index), + *offset - distanceToStart}; + } + + // The offset is not within this element, continue walking + // over the struct. + distanceToStart += elemSize; + } + + return {}; + }); +} + +/// Constructs a byte array type of the given size. +static LLVM::LLVMArrayType getByteArrayType(MLIRContext *context, + unsigned size) { + auto byteType = IntegerType::get(context, 8); + return LLVM::LLVMArrayType::get(context, byteType, size); } LogicalResult LLVM::GEPOp::ensureOnlySafeAccesses( @@ -442,18 +581,17 @@ LogicalResult LLVM::GEPOp::ensureOnlySafeAccesses( const DataLayout &dataLayout) { if (getBase() != slot.ptr) return success(); - if (slot.elemType != getElemType()) - return failure(); - if (!isFirstIndexZero(*this)) + std::optional gepOffset = gepToByteOffset(dataLayout, *this); + if (!gepOffset) return failure(); - // Dynamic indices can be out-of-bounds (even negative), so an access with - // dynamic indices can never be considered safe. - if (!getDynamicIndices().empty()) + uint64_t slotSize = dataLayout.getTypeSize(slot.elemType); + // Check that the access is strictly inside the slot. + if (*gepOffset >= slotSize) return failure(); - Type reachedType = getResultPtrElementType(); - if (!reachedType) - return failure(); - mustBeSafelyUsed.emplace_back({getResult(), reachedType}); + // Every access that remains in bounds of the remaining slot is considered + // legal. + mustBeSafelyUsed.emplace_back( + {getRes(), getByteArrayType(getContext(), slotSize - *gepOffset)}); return success(); } @@ -464,23 +602,25 @@ bool LLVM::GEPOp::canRewire(const DestructurableMemorySlot &slot, if (!isa(getBase().getType())) return false; - if (getBase() != slot.ptr || slot.elemType != getElemType()) - return false; - if (!isFirstIndexZero(*this)) - return false; - // Dynamic indices can be out-of-bounds (even negative), so an access with - // dynamic indices can never be properly rewired. - if (!getDynamicIndices().empty()) - return false; - Type reachedType = getResultPtrElementType(); - if (!reachedType || getIndices().size() < 2) + if (getBase() != slot.ptr) return false; - auto firstLevelIndex = dyn_cast(getIndices()[1]); - if (!firstLevelIndex) + std::optional accessInfo = + getSubslotAccessInfo(slot, dataLayout, *this); + if (!accessInfo) return false; - mustBeSafelyUsed.emplace_back({getResult(), reachedType}); - assert(slot.elementPtrs.contains(firstLevelIndex)); - usedIndices.insert(firstLevelIndex); + auto indexAttr = + IntegerAttr::get(IntegerType::get(getContext(), 32), accessInfo->index); + assert(slot.elementPtrs.contains(indexAttr)); + usedIndices.insert(indexAttr); + + // The remainder of the subslot should be accesses in-bounds. Thus, we create + // a dummy slot with the size of the remainder. + Type subslotType = slot.elementPtrs.lookup(indexAttr); + uint64_t slotSize = dataLayout.getTypeSize(subslotType); + LLVM::LLVMArrayType remainingSlotType = + getByteArrayType(getContext(), slotSize - accessInfo->subslotOffset); + mustBeSafelyUsed.emplace_back({getRes(), remainingSlotType}); + return true; } @@ -488,36 +628,19 @@ DeletionKind LLVM::GEPOp::rewire(const DestructurableMemorySlot &slot, DenseMap &subslots, RewriterBase &rewriter, const DataLayout &dataLayout) { - IntegerAttr firstLevelIndex = - llvm::dyn_cast_if_present(getIndices()[1]); - const MemorySlot &newSlot = subslots.at(firstLevelIndex); - - ArrayRef remainingIndices = getRawConstantIndices().slice(2); - - // If the GEP would become trivial after this transformation, eliminate it. - // A GEP should only be eliminated if it has no indices (except the first - // pointer index), as simplifying GEPs with all-zero indices would eliminate - // structure information useful for further destruction. - if (remainingIndices.empty()) { - rewriter.replaceAllUsesWith(getResult(), newSlot.ptr); - return DeletionKind::Delete; - } - - rewriter.modifyOpInPlace(*this, [&]() { - // Rewire the indices by popping off the second index. - // Start with a single zero, then add the indices beyond the second. - SmallVector newIndices(1); - newIndices.append(remainingIndices.begin(), remainingIndices.end()); - setRawConstantIndices(newIndices); - - // Rewire the pointed type. - setElemType(newSlot.elemType); - - // Rewire the pointer. - getBaseMutable().assign(newSlot.ptr); - }); - - return DeletionKind::Keep; + std::optional accessInfo = + getSubslotAccessInfo(slot, dataLayout, *this); + assert(accessInfo && "expected access info to be checked before"); + auto indexAttr = + IntegerAttr::get(IntegerType::get(getContext(), 32), accessInfo->index); + const MemorySlot &newSlot = subslots.at(indexAttr); + + auto byteType = IntegerType::get(rewriter.getContext(), 8); + auto newPtr = rewriter.createOrFold( + getLoc(), getResult().getType(), byteType, newSlot.ptr, + ArrayRef(accessInfo->subslotOffset), getInbounds()); + rewriter.replaceAllUsesWith(getResult(), newPtr); + return DeletionKind::Delete; } //===----------------------------------------------------------------------===// diff --git a/mlir/test/Dialect/LLVMIR/sroa.mlir b/mlir/test/Dialect/LLVMIR/sroa.mlir index 3f4d17c6a43f..fe1531d988a4 100644 --- a/mlir/test/Dialect/LLVMIR/sroa.mlir +++ b/mlir/test/Dialect/LLVMIR/sroa.mlir @@ -82,6 +82,27 @@ llvm.func @multi_level_indirect() -> i32 { // ----- +// This verifies that a nested GEP's users are checked properly. In this case +// the load goes over the bounds of the memory slot and thus should block the +// splitting of the alloca. + +// CHECK-LABEL: llvm.func @nested_access_over_slot_bound +llvm.func @nested_access_over_slot_bound() -> i64 { + %0 = llvm.mlir.constant(1 : i32) : i32 + // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<(i32, struct<( + %1 = llvm.alloca %0 x !llvm.struct<(i32, struct<(array<10 x i32>)>, i32)> {alignment = 8 : i64} : (i32) -> !llvm.ptr + // CHECK: %[[GEP0:.*]] = llvm.getelementptr inbounds %[[ALLOCA]] + %2 = llvm.getelementptr inbounds %1[0, 1, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(i32, struct<(array<10 x i32>)>, i32)> + // CHECK: %[[GEP1:.*]] = llvm.getelementptr inbounds %[[GEP0]] + %3 = llvm.getelementptr inbounds %2[0, 9] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<10 x i32> + // CHECK: %[[RES:.*]] = llvm.load %[[GEP1]] + %4 = llvm.load %3 : !llvm.ptr -> i64 + // CHECK: llvm.return %[[RES]] : i64 + llvm.return %4 : i64 +} + +// ----- + // CHECK-LABEL: llvm.func @resolve_alias // CHECK-SAME: (%[[ARG:.*]]: i32) llvm.func @resolve_alias(%arg: i32) -> i32 { @@ -318,3 +339,112 @@ llvm.func @store_to_memory(%arg: !llvm.ptr) { llvm.store %1, %arg : !llvm.ptr, !llvm.ptr llvm.return } + +// ----- + +// CHECK-LABEL: llvm.func @type_mismatch_array_access +// CHECK-SAME: %[[ARG:.*]]: i32 +llvm.func @type_mismatch_array_access(%arg: i32) { + %0 = llvm.mlir.constant(1 : i32) : i32 + // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x i32 + %1 = llvm.alloca %0 x !llvm.struct<(i32, i32, i32)> : (i32) -> !llvm.ptr + %2 = llvm.getelementptr %1[8] : (!llvm.ptr) -> !llvm.ptr, i8 + // CHECK-NEXT: llvm.store %[[ARG]], %[[ALLOCA]] + llvm.store %arg, %2 : i32, !llvm.ptr + llvm.return +} + +// ----- + +// CHECK-LABEL: llvm.func @type_mismatch_struct_access +// CHECK-SAME: %[[ARG:.*]]: i32 +llvm.func @type_mismatch_struct_access(%arg: i32) { + %0 = llvm.mlir.constant(1 : i32) : i32 + // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x i32 + %1 = llvm.alloca %0 x !llvm.struct<(i32, i32, i32)> : (i32) -> !llvm.ptr + %2 = llvm.getelementptr %1[0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(i32, i32)> + // CHECK-NEXT: llvm.store %[[ARG]], %[[ALLOCA]] + llvm.store %arg, %2 : i32, !llvm.ptr + llvm.return +} + +// ----- + +// CHECK-LABEL: llvm.func @index_in_final_padding +llvm.func @index_in_final_padding(%arg: i32) { + %0 = llvm.mlir.constant(1 : i32) : i32 + // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<"foo", (i32, i8)> + %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, i8)> : (i32) -> !llvm.ptr + // CHECK: = llvm.getelementptr %[[ALLOCA]][7] : (!llvm.ptr) -> !llvm.ptr, i8 + %2 = llvm.getelementptr %1[7] : (!llvm.ptr) -> !llvm.ptr, i8 + llvm.store %arg, %2 : i32, !llvm.ptr + llvm.return +} + +// ----- + +// CHECK-LABEL: llvm.func @index_out_of_bounds +llvm.func @index_out_of_bounds(%arg: i32) { + %0 = llvm.mlir.constant(1 : i32) : i32 + // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<"foo", (i32, i32)> + %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, i32)> : (i32) -> !llvm.ptr + // CHECK: = llvm.getelementptr %[[ALLOCA]][9] : (!llvm.ptr) -> !llvm.ptr, i8 + %2 = llvm.getelementptr %1[9] : (!llvm.ptr) -> !llvm.ptr, i8 + llvm.store %arg, %2 : i32, !llvm.ptr + llvm.return +} + +// ----- + +// CHECK-LABEL: llvm.func @index_in_padding +llvm.func @index_in_padding(%arg: i16) { + %0 = llvm.mlir.constant(1 : i32) : i32 + // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<"foo", (i16, i32)> + %1 = llvm.alloca %0 x !llvm.struct<"foo", (i16, i32)> : (i32) -> !llvm.ptr + // CHECK: = llvm.getelementptr %[[ALLOCA]][2] : (!llvm.ptr) -> !llvm.ptr, i8 + %2 = llvm.getelementptr %1[2] : (!llvm.ptr) -> !llvm.ptr, i8 + llvm.store %arg, %2 : i16, !llvm.ptr + llvm.return +} + +// ----- + +// CHECK-LABEL: llvm.func @index_not_in_padding_because_packed +// CHECK-SAME: %[[ARG:.*]]: i16 +llvm.func @index_not_in_padding_because_packed(%arg: i16) { + %0 = llvm.mlir.constant(1 : i32) : i32 + // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x i32 + %1 = llvm.alloca %0 x !llvm.struct<"foo", packed (i16, i32)> : (i32) -> !llvm.ptr + %2 = llvm.getelementptr %1[2] : (!llvm.ptr) -> !llvm.ptr, i8 + // CHECK-NEXT: llvm.store %[[ARG]], %[[ALLOCA]] + llvm.store %arg, %2 : i16, !llvm.ptr + llvm.return +} + +// ----- + +// CHECK-LABEL: llvm.func @no_crash_on_negative_gep_index +// CHECK-SAME: %[[ARG:.*]]: f16 +llvm.func @no_crash_on_negative_gep_index(%arg: f16) { + %0 = llvm.mlir.constant(1 : i32) : i32 + // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<"foo", (i32, i32, i32)> + %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, i32, i32)> : (i32) -> !llvm.ptr + // CHECK: llvm.getelementptr %[[ALLOCA]][-1] : (!llvm.ptr) -> !llvm.ptr, f32 + %2 = llvm.getelementptr %1[-1] : (!llvm.ptr) -> !llvm.ptr, f32 + llvm.store %arg, %2 : f16, !llvm.ptr + llvm.return +} + +// ----- + +// CHECK-LABEL: llvm.func @out_of_bound_gep_array_access +// CHECK-SAME: %[[ARG:.*]]: i32 +llvm.func @out_of_bound_gep_array_access(%arg: i32) { + %0 = llvm.mlir.constant(1 : i32) : i32 + // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x i32 + %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, i32)> : (i32) -> !llvm.ptr + %2 = llvm.getelementptr %1[0, 4] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<4 x i8> + // CHECK-NEXT: llvm.store %[[ARG]], %[[ALLOCA]] + llvm.store %arg, %2 : i32, !llvm.ptr + llvm.return +} -- GitLab From 56aeac47ab0858db9f447b5ec43b660d9035167f Mon Sep 17 00:00:00 2001 From: Mitch Phillips Date: Tue, 2 Apr 2024 14:44:11 +0200 Subject: [PATCH 057/447] Revert "[mlir] Reland the dialect conversion hanging use fix (#87297)" This reverts commit 49a4ec20a8be5888cbf225bab340dbaf204902c7. Reason: Broke the ASan build bot with a memory leak. See the comments at https://github.com/llvm/llvm-project/pull/87297 for more information. --- mlir/lib/Transforms/Utils/DialectConversion.cpp | 2 -- .../TosaToLinalg/tosa-to-linalg-invalid.mlir | 13 ------------- 2 files changed, 15 deletions(-) diff --git a/mlir/lib/Transforms/Utils/DialectConversion.cpp b/mlir/lib/Transforms/Utils/DialectConversion.cpp index 270ac0a08689..8671c1008902 100644 --- a/mlir/lib/Transforms/Utils/DialectConversion.cpp +++ b/mlir/lib/Transforms/Utils/DialectConversion.cpp @@ -279,8 +279,6 @@ public: auto &blockOps = block->getOperations(); while (!blockOps.empty()) blockOps.remove(blockOps.begin()); - for (auto arg : block->getArguments()) - arg.dropAllUses(); block->dropAllUses(); if (block->getParent()) block->erase(); diff --git a/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg-invalid.mlir b/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg-invalid.mlir index 6494e1b27194..17eec5936918 100644 --- a/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg-invalid.mlir +++ b/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg-invalid.mlir @@ -15,16 +15,3 @@ func.func @tensor_with_unknown_rank(%arg0: tensor<*xi8>) -> tensor<*xi8> { %0 = "tosa.abs"(%arg0) : (tensor<*xi8>) -> tensor<*xi8> return %0 : tensor<*xi8> } - -// ----- - -// CHECK-LABEL: @unranked_add -func.func @unranked_add(%arg0 : tensor<10x10xf32> , %arg1 : tensor<10x10xf32>, %arg2 : tensor<*xf32>) -> (tensor<10x10xf32>) { - // expected-error@+3 {{failed to legalize operation 'tosa.add'}} - %reduce = tosa.reduce_max %arg0 {axis = 1 : i32} : (tensor<10x10xf32>) -> tensor<10x1xf32> - %1 = tosa.add %reduce, %arg1 : (tensor<10x1xf32>, tensor<10x10xf32>) -> tensor<10x10xf32> - %0 = tosa.add %1, %arg2 : (tensor<10x10xf32>, tensor<*xf32>) -> tensor<*xf32> - %2 = tosa.reshape %0 {new_shape = array} : (tensor<*xf32>) -> tensor<10x10xf32> - return %2 : tensor<10x10xf32> -} - -- GitLab From cb9cf331fa69bb8319886cdca043a742b4d19ce5 Mon Sep 17 00:00:00 2001 From: Alexey Bataev Date: Tue, 2 Apr 2024 05:52:27 -0700 Subject: [PATCH 058/447] [SLP][NFC]Do not lookup in MinBWs, reuse previously used iterator. --- llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp index 1ffc39a90674..b1940e3feed9 100644 --- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp +++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp @@ -12297,7 +12297,7 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E, bool PostponedPHIs) { Value *V = Builder.CreateBinOp( static_cast(E->getOpcode()), LHS, RHS); - propagateIRFlags(V, E->Scalars, VL0, !MinBWs.contains(E)); + propagateIRFlags(V, E->Scalars, VL0, It == MinBWs.end()); if (auto *I = dyn_cast(V)) V = propagateMetadata(I, E->Scalars); @@ -12598,8 +12598,8 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E, bool PostponedPHIs) { }, Mask, &OpScalars, &AltScalars); - propagateIRFlags(V0, OpScalars, E->getMainOp(), !MinBWs.contains(E)); - propagateIRFlags(V1, AltScalars, E->getAltOp(), !MinBWs.contains(E)); + propagateIRFlags(V0, OpScalars, E->getMainOp(), It == MinBWs.end()); + propagateIRFlags(V1, AltScalars, E->getAltOp(), It == MinBWs.end()); Value *V = Builder.CreateShuffleVector(V0, V1, Mask); if (auto *I = dyn_cast(V)) { -- GitLab From 0b9528d6bd0bfde5702b1ee5ed8a249d354434f1 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Tue, 2 Apr 2024 15:18:38 +0200 Subject: [PATCH 059/447] [clang] CTAD: Track template template type parameters that referenced in the template arguments of the RHS. (#85405) Fixes https://github.com/llvm/llvm-project/issues/85385. The Finder was missing for this case, for the crash test, the template parameter TTP was incorrectly considered as not referenced/appeared in the template arguments of the right hand side of the alias template decl, thus the synthesized deduction decl doesn't contain this TTP in the template parameter list, but we have references in the declaration, thus it caused crashes. --- clang/lib/Sema/SemaTemplate.cpp | 6 ++++++ clang/test/SemaCXX/cxx20-ctad-type-alias.cpp | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index befec401c8ee..a2b8cc14ca76 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -2720,6 +2720,12 @@ SmallVector TemplateParamsReferencedInTemplateArgumentList( return true; } + bool TraverseTemplateName(TemplateName Template) { + if (auto *TD = Template.getAsTemplateDecl()) + MarkAppeared(TD); + return RecursiveASTVisitor::TraverseTemplateName(Template); + } + void MarkAppeared(NamedDecl *ND) { if (TemplateParams.contains(ND)) ReferencedTemplateParams.insert(ND); diff --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp index ce403285b0f5..b71cd46f884d 100644 --- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp +++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp @@ -259,3 +259,23 @@ using Bar2 = Foo; // expected-error {{extraneous template parameter list in a Bar2 b = 1; // expected-error {{no viable constructor or deduction guide for deduction of template arguments}} } // namespace test19 + +// GH85385 +namespace test20 { +template