diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -2287,10 +2287,6 @@ if (isa(this)) return false; - // The values of weak variables are never usable in constant expressions. - if (isWeak()) - return false; - // In C++11, any variable of reference type can be used in a constant // expression if it is initialized by a constant expression. if (Lang.CPlusPlus11 && getType()->isReferenceType()) @@ -2418,6 +2414,10 @@ } bool VarDecl::checkInitIsICE() const { + // Initializers of weak variables are never ICEs. + if (isWeak()) + return false; + EvaluatedStmt *Eval = ensureEvaluatedStmt(); if (Eval->CheckedICE) // We have already checked whether this subexpression is an diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -14816,7 +14816,7 @@ const VarDecl *VD; // Look for a declaration of this variable that has an initializer, and // check whether it is an ICE. - if (Dcl->getAnyInitializer(VD) && !VD->isWeak() && VD->checkInitIsICE()) + if (Dcl->getAnyInitializer(VD) && VD->checkInitIsICE()) return NoDiag(); else return ICEDiag(IK_NotICE, cast(E)->getLocation()); diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -1214,9 +1214,6 @@ PB.registerLoopAnalyses(LAM); PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); - if (TM) - TM->registerPassBuilderCallbacks(PB, CodeGenOpts.DebugPassManager); - ModulePassManager MPM(CodeGenOpts.DebugPassManager); if (!CodeGenOpts.DisableLLVMPasses) { diff --git a/clang/lib/Driver/ToolChains/AIX.cpp b/clang/lib/Driver/ToolChains/AIX.cpp --- a/clang/lib/Driver/ToolChains/AIX.cpp +++ b/clang/lib/Driver/ToolChains/AIX.cpp @@ -162,9 +162,6 @@ if (Args.hasArg(options::OPT_pthreads, options::OPT_pthread)) CmdArgs.push_back("-lpthreads"); - if (D.CCCIsCXX()) - CmdArgs.push_back("-lm"); - CmdArgs.push_back("-lc"); } diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -11112,7 +11112,7 @@ // might be foobar, including it failing to be a constant expression. // TODO Handle more ways the lookup or result can be invalid. if (!VD->isStaticDataMember() || !VD->isConstexpr() || !VD->hasInit() || - VD->isWeak() || !VD->checkInitIsICE()) + !VD->checkInitIsICE()) return UnsupportedSTLError(USS_InvalidMember, MemName, VD); // Attempt to evaluate the var decl as a constant expression and extract diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -13940,10 +13940,9 @@ // float vectors and truncating the result back to half vector. For now, we do // this only when HalfArgsAndReturn is set (that is, when the target is arm or // arm64). - assert( - (Opc == BO_Comma || isVector(RHS.get()->getType(), Context.HalfTy) == - isVector(LHS.get()->getType(), Context.HalfTy)) && - "both sides are half vectors or neither sides are"); + assert(isVector(RHS.get()->getType(), Context.HalfTy) == + isVector(LHS.get()->getType(), Context.HalfTy) && + "both sides are half vectors or neither sides are"); ConvertHalfVec = needsConversionOfHalfVec(ConvertHalfVec, Context, LHS.get(), RHS.get()); diff --git a/clang/test/CodeGen/builtin-nan-exception.c b/clang/test/CodeGen/builtin-nan-exception.c deleted file mode 100644 --- a/clang/test/CodeGen/builtin-nan-exception.c +++ /dev/null @@ -1,33 +0,0 @@ -// RUN: %clang -target aarch64 -emit-llvm -S %s -o - | FileCheck %s -// RUN: %clang -target lanai -emit-llvm -S %s -o - | FileCheck %s -// RUN: %clang -target riscv64 -emit-llvm -S %s -o - | FileCheck %s -// RUN: %clang -target x86_64 -emit-llvm -S %s -o - | FileCheck %s - -// Run a variety of targets to ensure there's no target-based difference. - -// An SNaN with no payload is formed by setting the bit after the -// the quiet bit (MSB of the significand). - -// CHECK: float 0x7FF8000000000000, float 0x7FF4000000000000 - -float f[] = { - __builtin_nanf(""), - __builtin_nansf(""), -}; - - -// Doubles are created and converted to floats. - -// CHECK: float 0x7FF8000000000000, float 0x7FF4000000000000 - -float converted_to_float[] = { - __builtin_nan(""), - __builtin_nans(""), -}; - -// CHECK: double 0x7FF8000000000000, double 0x7FF4000000000000 - -double d[] = { - __builtin_nan(""), - __builtin_nans(""), -}; diff --git a/clang/test/Driver/aix-ld.c b/clang/test/Driver/aix-ld.c --- a/clang/test/Driver/aix-ld.c +++ b/clang/test/Driver/aix-ld.c @@ -20,7 +20,6 @@ // CHECK-LD32: "-L[[SYSROOT]]/usr/lib" // CHECK-LD32-NOT: "-lc++" // CHECK-LD32: "[[RESOURCE_DIR]]{{/|\\\\}}lib{{/|\\\\}}aix{{/|\\\\}}libclang_rt.builtins-powerpc.a" -// CHECK-LD32-NOT: "-lm" // CHECK-LD32: "-lc" // Check powerpc64-ibm-aix7.1.0.0, 64-bit. @@ -42,7 +41,6 @@ // CHECK-LD64: "-L[[SYSROOT]]/usr/lib" // CHECK-LD64-NOT: "-lc++" // CHECK-LD64: "[[RESOURCE_DIR]]{{/|\\\\}}lib{{/|\\\\}}aix{{/|\\\\}}libclang_rt.builtins-powerpc64.a" -// CHECK-LD64-NOT: "-lm" // CHECK-LD64: "-lc" // Check powerpc-ibm-aix7.1.0.0, 32-bit. Enable POSIX thread support. @@ -66,7 +64,6 @@ // CHECK-LD32-PTHREAD-NOT: "-lc++" // CHECK-LD32-PTHREAD: "[[RESOURCE_DIR]]{{/|\\\\}}lib{{/|\\\\}}aix{{/|\\\\}}libclang_rt.builtins-powerpc.a" // CHECK-LD32-PTHREAD: "-lpthreads" -// CHECK-LD32-PTHREAD-NOT: "-lm" // CHECK-LD32-PTHREAD: "-lc" // Check powerpc64-ibm-aix7.1.0.0, 64-bit. POSIX thread alias. @@ -90,7 +87,6 @@ // CHECK-LD64-PTHREAD-NOT: "-lc++" // CHECK-LD64-PTHREAD: "[[RESOURCE_DIR]]{{/|\\\\}}lib{{/|\\\\}}aix{{/|\\\\}}libclang_rt.builtins-powerpc64.a" // CHECK-LD64-PTHREAD: "-lpthreads" -// CHECK-LD64-PTHREAD-NOT: "-lm" // CHECK-LD64-PTHREAD: "-lc" // Check powerpc-ibm-aix7.1.0.0, 32-bit. Enable profiling. @@ -113,7 +109,6 @@ // CHECK-LD32-PROF: "-L[[SYSROOT]]/usr/lib" // CHECK-LD32-PROF-NOT: "-lc++" // CHECK-LD32-PROF: "[[RESOURCE_DIR]]{{/|\\\\}}lib{{/|\\\\}}aix{{/|\\\\}}libclang_rt.builtins-powerpc.a" -// CHECK-LD32-PROF-NOT: "-lm" // CHECK-LD32-PROF: "-lc" // Check powerpc64-ibm-aix7.1.0.0, 64-bit. Enable g-profiling. @@ -136,7 +131,6 @@ // CHECK-LD64-GPROF: "-L[[SYSROOT]]/usr/lib" // CHECK-LD64-GPROF-NOT: "-lc++" // CHECK-LD64-GPROF: "[[RESOURCE_DIR]]{{/|\\\\}}lib{{/|\\\\}}aix{{/|\\\\}}libclang_rt.builtins-powerpc64.a" -// CHECK-LD64-GPROF-NOT: "-lm" // CHECK-LD64-GPROF: "-lc" // Check powerpc-ibm-aix7.1.0.0, 32-bit. Static linking. @@ -159,7 +153,6 @@ // CHECK-LD32-STATIC: "-L[[SYSROOT]]/usr/lib" // CHECK-LD32-STATIC-NOT: "-lc++" // CHECK-LD32-STATIC: "[[RESOURCE_DIR]]{{/|\\\\}}lib{{/|\\\\}}aix{{/|\\\\}}libclang_rt.builtins-powerpc.a" -// CHECK-LD32-STATIC-NOT: "-lm" // CHECK-LD32-STATIC: "-lc" // Check powerpc-ibm-aix7.1.0.0, 32-bit. Library search path. @@ -183,7 +176,6 @@ // CHECK-LD32-LIBP: "-L[[SYSROOT]]/usr/lib" // CHECK-LD32-LIBP-NOT: "-lc++" // CHECK-LD32-LIBP: "[[RESOURCE_DIR]]{{/|\\\\}}lib{{/|\\\\}}aix{{/|\\\\}}libclang_rt.builtins-powerpc.a" -// CHECK-LD32-LIBP-NOT: "-lm" // CHECK-LD32-LIBP: "-lc" // Check powerpc-ibm-aix7.1.0.0, 32-bit. nostdlib. @@ -208,7 +200,6 @@ // CHECK-LD32-NO-STD-LIB-NOT: "-lc++" // CHECK-LD32-NO-STD-LIB-NOT: "[[RESOURCE_DIR]]{{/|\\\\}}lib{{/|\\\\}}aix{{/|\\\\}}libclang_rt.builtins-powerpc.a" // CHECK-LD32-NO-STD-LIB-NOT: "-lpthreads" -// CHECK-LD32-NO-STD-LIB-NOT: "-lm" // CHECK-LD32-NO-STD-LIB-NOT: "-lc" // Check powerpc64-ibm-aix7.1.0.0, 64-bit. nodefaultlibs. @@ -233,7 +224,6 @@ // CHECK-LD64-NO-DEFAULT-LIBS-NOT: "-lc++" // CHECK-LD64-NO-DEFAULT-LIBS-NOT: "[[RESOURCE_DIR]]{{/|\\\\}}lib{{/|\\\\}}aix{{/|\\\\}}libclang_rt.builtins-powerpc64.a" // CHECK-LD64-NO-DEFAULT-LIBS-NOT: "-lpthreads" -// CHECK-LD64-NO-DEFAULT-LIBS-NOT: "-lm" // CHECK-LD64-NO-DEFAULT-LIBS-NOT: "-lc" // Check powerpc-ibm-aix7.1.0.0, 32-bit. 'bcdtors' and argument order. @@ -257,7 +247,6 @@ // CHECK-LD32-CXX-ARG-ORDER-NOT: "-bcdtors:all:0:s" // CHECK-LD32-CXX-ARG-ORDER: "-lc++" // CHECK-LD32-CXX-ARG-ORDER: "[[RESOURCE_DIR]]{{/|\\\\}}lib{{/|\\\\}}aix{{/|\\\\}}libclang_rt.builtins-powerpc.a" -// CHECK-LD32-CXX-ARG-ORDER: "-lm" // CHECK-LD32-CXX-ARG-ORDER: "-lc" // Check powerpc-ibm-aix7.1.0.0, 32-bit. lc++ and lc order. @@ -277,7 +266,6 @@ // CHECK-LD32-CXX-ARG-LCXX: "-L[[SYSROOT]]/usr/lib" // CHECK-LD32-CXX-ARG-LCXX: "-lc++" // CHECK-LD32-CXX-ARG-LCXX: "[[RESOURCE_DIR]]{{/|\\\\}}lib{{/|\\\\}}aix{{/|\\\\}}libclang_rt.builtins-powerpc.a" -// CHECK-LD32-CXX-ARG-LCXX: "-lm" // CHECK-LD32-CXX-ARG-LCXX: "-lc" // Check powerpc64-ibm-aix7.1.0.0, 64-bit. lc++ and lc order. @@ -297,7 +285,6 @@ // CHECK-LD64-CXX-ARG-LCXX: "-L[[SYSROOT]]/usr/lib" // CHECK-LD64-CXX-ARG-LCXX: "-lc++" // CHECK-LD64-CXX-ARG-LCXX: "[[RESOURCE_DIR]]{{/|\\\\}}lib{{/|\\\\}}aix{{/|\\\\}}libclang_rt.builtins-powerpc64.a" -// CHECK-LD64-CXX-ARG-LCXX: "-lm" // CHECK-LD64-CXX-ARG-LCXX: "-lc" // Check powerpc-ibm-aix7.1.0.0, 32-bit. -nodefaultlibs. @@ -318,7 +305,6 @@ // CHECK-LD32-NODEFLIB-LCXX: "-L[[SYSROOT]]/usr/lib" // CHECK-LD32-NODEFLIB-LCXX-NOT: "-lc++" // CHECK-LD32-NODEFLIB-LCXX-NOT: "[[RESOURCE_DIR]]{{/|\\\\}}lib{{/|\\\\}}aix{{/|\\\\}}libclang_rt.builtins-powerpc.a" -// CHECK-LD32-NODEFLIB-LCXX-NOT: "-lm" // CHECK-LD32-NODEFLIB-LCXX-NOT: "-lc" // Check powerpc64-ibm-aix7.1.0.0, 64-bit. -nodefaultlibs. @@ -339,7 +325,6 @@ // CHECK-LD64-NODEFLIB-LCXX: "-L[[SYSROOT]]/usr/lib" // CHECK-LD64-NODEFLIB-LCXX-NOT: "-lc++" // CHECK-LD64-NODEFLIB-LCXX-NOT: "[[RESOURCE_DIR]]{{/|\\\\}}lib{{/|\\\\}}aix{{/|\\\\}}libclang_rt.builtins-powerpc64.a" -// CHECK-LD64-NODEFLIB-LCXX-NOT: "-lm" // CHECK-LD64-NODEFLIB-LCXX-NOT: "-lc" // Check powerpc-ibm-aix7.1.0.0, 32-bit. -nostdlib. @@ -360,7 +345,6 @@ // CHECK-LD32-NOSTDLIB-LCXX: "-L[[SYSROOT]]/usr/lib" // CHECK-LD32-NOSTDLIB-LCXX-NOT: "-lc++" // CHECK-LD32-NOSTDLIB-LCXX-NOT: "[[RESOURCE_DIR]]{{/|\\\\}}lib{{/|\\\\}}aix{{/|\\\\}}libclang_rt.builtins-powerpc.a" -// CHECK-LD32-NOSTDLIB-LCXX-NOT: "-lm" // CHECK-LD32-NOSTDLIB-LCXX-NOT: "-lc" // Check powerpc64-ibm-aix7.1.0.0, 64-bit. -nostdlib. @@ -381,7 +365,6 @@ // CHECK-LD64-NOSTDLIB-LCXX: "-L[[SYSROOT]]/usr/lib" // CHECK-LD64-NOSTDLIB-LCXX-NOT: "-lc++" // CHECK-LD64-NOSTDLIB-LCXX-NOT: "[[RESOURCE_DIR]]{{/|\\\\}}lib{{/|\\\\}}aix{{/|\\\\}}libclang_rt.builtins-powerpc64.a" -// CHECK-LD64-NOSTDLIB-LCXX-NOT: "-lm" // CHECK-LD64-NOSTDLIB-LCXX-NOT: "-lc" // Check powerpc-ibm-aix7.1.0.0, 32-bit. -nostdlib++. @@ -403,7 +386,6 @@ // CHECK-LD32-NOSTDLIBXX-LCXX: "-L[[SYSROOT]]/usr/lib" // CHECK-LD32-NOSTDLIBXX-LCXX-NOT: "-lc++" // CHECK-LD32-NOSTDLIBXX-LCXX: "[[RESOURCE_DIR]]{{/|\\\\}}lib{{/|\\\\}}aix{{/|\\\\}}libclang_rt.builtins-powerpc.a" -// CHECK-LD32-NOSTDLIBXX-LCXX: "-lm" // CHECK-LD32-NOSTDLIBXX-LCXX: "-lc" // Check powerpc64-ibm-aix7.1.0.0, 64-bit. -nostdlib++. @@ -424,7 +406,6 @@ // CHECK-LD64-NOSTDLIBXX-LCXX: "-L[[SYSROOT]]/usr/lib" // CHECK-LD64-NOSTDLIBXX-LCXX-NOT: "-lc++" // CHECK-LD64-NOSTDLIBXX-LCXX: "[[RESOURCE_DIR]]{{/|\\\\}}lib{{/|\\\\}}aix{{/|\\\\}}libclang_rt.builtins-powerpc64.a" -// CHECK-LD64-NOSTDLIBXX-LCXX: "-lm" // CHECK-LD64-NOSTDLIBXX-LCXX: "-lc" // Check powerpc64-ibm-aix7.1.0.0, 32-bit. -nostartfiles. @@ -443,9 +424,8 @@ // CHECK-LD32-NOSTARTFILES-LCXX-NOT: "[[SYSROOT]]/usr/lib{{/|\\\\}}crt0.o" // CHECK-LD32-NOSTARTFILES-LCXX-NOT: "[[SYSROOT]]/usr/lib{{/|\\\\}}crti.o" // CHECK-LD32-NOSTARTFILES-LCXX: "-L[[SYSROOT]]/usr/lib" -// CHECK-LD32-NOSTARTFILES-LCXX: "-lc++" +// CHECK-LD32-NOSTARTFILES-LCXX "-lc++" // CHECK-LD32-NOSTARTFILES-LCXX: "[[RESOURCE_DIR]]{{/|\\\\}}lib{{/|\\\\}}aix{{/|\\\\}}libclang_rt.builtins-powerpc.a" -// CHECK-LD32-NOSTARTFILES-LCXX: "-lm" // CHECK-LD32-NOSTARTFILES-LCXX: "-lc" // Check powerpc64-ibm-aix7.1.0.0, 64-bit. -nostartfiles. @@ -466,7 +446,6 @@ // CHECK-LD64-NOSTARTFILES-LCXX: "-L[[SYSROOT]]/usr/lib" // CHECK-LD64-NOSTARTFILES-LCXX: "-lc++" // CHECK-LD64-NOSTARTFILES-LCXX: "[[RESOURCE_DIR]]{{/|\\\\}}lib{{/|\\\\}}aix{{/|\\\\}}libclang_rt.builtins-powerpc64.a" -// CHECK-LD64-NOSTARTFILES-LCXX: "-lm" // CHECK-LD64-NOSTARTFILES-LCXX: "-lc" // Check powerpc-ibm-aix7.1.0.0, 32-bit. -stdlib=libstdc++ invokes fatal error. @@ -504,7 +483,6 @@ // CHECK-LD32-SHARED: "-L[[SYSROOT]]/usr/lib" // CHECK-LD32-SHARED: "-lc++" // CHECK-LD32-SHARED: "[[RESOURCE_DIR]]{{/|\\\\}}lib{{/|\\\\}}aix{{/|\\\\}}libclang_rt.builtins-powerpc.a" -// CHECK-LD32-SHARED: "-lm" // CHECK-LD32-SHARED: "-lc" // Check powerpc64-ibm-aix7.1.0.0, 64-bit. -shared. @@ -527,5 +505,4 @@ // CHECK-LD64-SHARED: "-L[[SYSROOT]]/usr/lib" // CHECK-LD64-SHARED: "-lc++" // CHECK-LD64-SHARED: "[[RESOURCE_DIR]]{{/|\\\\}}lib{{/|\\\\}}aix{{/|\\\\}}libclang_rt.builtins-powerpc64.a" -// CHECK-LD64-SHARED: "-lm" // CHECK-LD64-SHARED: "-lc" diff --git a/clang/test/Sema/fp16vec-sema.c b/clang/test/Sema/fp16vec-sema.c --- a/clang/test/Sema/fp16vec-sema.c +++ b/clang/test/Sema/fp16vec-sema.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify %s typedef __fp16 half4 __attribute__ ((vector_size (8))); typedef float float4 __attribute__ ((vector_size (16))); @@ -28,8 +28,6 @@ sv0 = hv0 >= hv1; sv0 = hv0 || hv1; // expected-error{{logical expression with vector types 'half4' (vector of 4 '__fp16' values) and 'half4' is only supported in C++}} sv0 = hv0 && hv1; // expected-error{{logical expression with vector types 'half4' (vector of 4 '__fp16' values) and 'half4' is only supported in C++}} - hv0, 1; - 1, hv0; // Implicit conversion between half vectors and float vectors are not allowed. hv0 = fv0; // expected-error{{assigning to}} diff --git a/clang/test/SemaCXX/cxx20-constinit.cpp b/clang/test/SemaCXX/cxx20-constinit.cpp deleted file mode 100644 --- a/clang/test/SemaCXX/cxx20-constinit.cpp +++ /dev/null @@ -1,4 +0,0 @@ -// RUN: %clang_cc1 %s -std=c++20 -verify -// expected-no-diagnostics - -constinit int a __attribute__((weak)) = 0; diff --git a/compiler-rt/lib/scudo/standalone/atomic_helpers.h b/compiler-rt/lib/scudo/standalone/atomic_helpers.h --- a/compiler-rt/lib/scudo/standalone/atomic_helpers.h +++ b/compiler-rt/lib/scudo/standalone/atomic_helpers.h @@ -90,20 +90,6 @@ } template -inline typename T::Type atomic_fetch_and(volatile T *A, typename T::Type V, - memory_order MO) { - DCHECK(!(reinterpret_cast(A) % sizeof(*A))); - return __atomic_fetch_and(&A->ValDoNotUse, V, MO); -} - -template -inline typename T::Type atomic_fetch_or(volatile T *A, typename T::Type V, - memory_order MO) { - DCHECK(!(reinterpret_cast(A) % sizeof(*A))); - return __atomic_fetch_or(&A->ValDoNotUse, V, MO); -} - -template inline typename T::Type atomic_exchange(volatile T *A, typename T::Type V, memory_order MO) { DCHECK(!(reinterpret_cast(A) % sizeof(*A))); diff --git a/compiler-rt/lib/scudo/standalone/combined.h b/compiler-rt/lib/scudo/standalone/combined.h --- a/compiler-rt/lib/scudo/standalone/combined.h +++ b/compiler-rt/lib/scudo/standalone/combined.h @@ -15,7 +15,6 @@ #include "flags_parser.h" #include "local_cache.h" #include "memtag.h" -#include "options.h" #include "quarantine.h" #include "report.h" #include "secondary.h" @@ -145,19 +144,16 @@ reportUnrecognizedFlags(); // Store some flags locally. - if (getFlags()->may_return_null) - Primary.Options.set(OptionBit::MayReturnNull); - if (getFlags()->zero_contents) - Primary.Options.setFillContentsMode(ZeroFill); - else if (getFlags()->pattern_fill_contents) - Primary.Options.setFillContentsMode(PatternOrZeroFill); - if (getFlags()->dealloc_type_mismatch) - Primary.Options.set(OptionBit::DeallocTypeMismatch); - if (getFlags()->delete_size_mismatch) - Primary.Options.set(OptionBit::DeleteSizeMismatch); - Primary.Options.set(OptionBit::UseOddEvenTags); - - QuarantineMaxChunkSize = + Options.MayReturnNull = getFlags()->may_return_null; + Options.FillContents = + getFlags()->zero_contents + ? ZeroFill + : (getFlags()->pattern_fill_contents ? PatternOrZeroFill : NoFill); + Options.DeallocTypeMismatch = getFlags()->dealloc_type_mismatch; + Options.DeleteSizeMismatch = getFlags()->delete_size_mismatch; + Options.TrackAllocationStacks = false; + Options.UseOddEvenTags = true; + Options.QuarantineMaxChunkSize = static_cast(getFlags()->quarantine_max_chunk_size); Stats.initLinkerInitialized(); @@ -254,8 +250,8 @@ #endif } - uptr computeOddEvenMaskForPointerMaybe(Options Options, uptr Ptr, uptr Size) { - if (!Options.get(OptionBit::UseOddEvenTags)) + uptr computeOddEvenMaskForPointerMaybe(uptr Ptr, uptr Size) { + if (!Options.UseOddEvenTags) return 0; // If a chunk's tag is odd, we want the tags of the surrounding blocks to be @@ -271,7 +267,6 @@ uptr Alignment = MinAlignment, bool ZeroContents = false) { initThreadMaybe(); - Options Options = Primary.Options.load(); #ifdef GWP_ASAN_HOOKS if (UNLIKELY(GuardedAlloc.shouldSample())) { @@ -283,10 +278,10 @@ const FillContentsMode FillContents = ZeroContents ? ZeroFill : TSDRegistry.getDisableMemInit() ? NoFill - : Options.getFillContentsMode(); + : Options.FillContents; if (UNLIKELY(Alignment > MaxAlignment)) { - if (Options.get(OptionBit::MayReturnNull)) + if (Options.MayReturnNull) return nullptr; reportAlignmentTooBig(Alignment, MaxAlignment); } @@ -305,7 +300,7 @@ // Takes care of extravagantly large sizes as well as integer overflows. static_assert(MaxAllowedMallocSize < UINTPTR_MAX - MaxAlignment, ""); if (UNLIKELY(Size >= MaxAllowedMallocSize)) { - if (Options.get(OptionBit::MayReturnNull)) + if (Options.MayReturnNull) return nullptr; reportAllocationSizeTooBig(Size, NeededSize, MaxAllowedMallocSize); } @@ -341,7 +336,7 @@ FillContents); if (UNLIKELY(!Block)) { - if (Options.get(OptionBit::MayReturnNull)) + if (Options.MayReturnNull) return nullptr; reportOutOfMemory(NeededSize); } @@ -364,7 +359,7 @@ // // When memory tagging is enabled, zeroing the contents is done as part of // setting the tag. - if (UNLIKELY(useMemoryTagging(Options))) { + if (UNLIKELY(useMemoryTagging())) { uptr PrevUserPtr; Chunk::UnpackedHeader Header; const uptr BlockSize = PrimaryT::getSizeByClassId(ClassId); @@ -429,10 +424,10 @@ } } else { const uptr OddEvenMask = - computeOddEvenMaskForPointerMaybe(Options, BlockUptr, BlockSize); + computeOddEvenMaskForPointerMaybe(BlockUptr, BlockSize); TaggedPtr = prepareTaggedChunk(Ptr, Size, OddEvenMask, BlockEnd); } - storeAllocationStackMaybe(Options, Ptr); + storeAllocationStackMaybe(Ptr); } else if (UNLIKELY(FillContents != NoFill)) { // This condition is not necessarily unlikely, but since memset is // costly, we might as well mark it as such. @@ -476,7 +471,6 @@ // the TLS destructors, ending up in initialized thread specific data never // being destroyed properly. Any other heap operation will do a full init. initThreadMaybe(/*MinimalInit=*/true); - Options Options = Primary.Options.load(); #ifdef GWP_ASAN_HOOKS if (UNLIKELY(GuardedAlloc.pointerIsMine(Ptr))) { @@ -500,7 +494,7 @@ if (UNLIKELY(Header.State != Chunk::State::Allocated)) reportInvalidChunkState(AllocatorAction::Deallocating, Ptr); - if (Options.get(OptionBit::DeallocTypeMismatch)) { + if (Options.DeallocTypeMismatch) { if (Header.OriginOrWasZeroed != Origin) { // With the exception of memalign'd chunks, that can be still be free'd. if (UNLIKELY(Header.OriginOrWasZeroed != Chunk::Origin::Memalign || @@ -511,20 +505,19 @@ } const uptr Size = getSize(Ptr, &Header); - if (DeleteSize && Options.get(OptionBit::DeleteSizeMismatch)) { + if (DeleteSize && Options.DeleteSizeMismatch) { if (UNLIKELY(DeleteSize != Size)) reportDeleteSizeMismatch(Ptr, DeleteSize, Size); } - quarantineOrDeallocateChunk(Options, Ptr, &Header, Size); + quarantineOrDeallocateChunk(Ptr, &Header, Size); } void *reallocate(void *OldPtr, uptr NewSize, uptr Alignment = MinAlignment) { initThreadMaybe(); - Options Options = Primary.Options.load(); if (UNLIKELY(NewSize >= MaxAllowedMallocSize)) { - if (Options.get(OptionBit::MayReturnNull)) + if (Options.MayReturnNull) return nullptr; reportAllocationSizeTooBig(NewSize, 0, MaxAllowedMallocSize); } @@ -559,7 +552,7 @@ // Pointer has to be allocated with a malloc-type function. Some // applications think that it is OK to realloc a memalign'ed pointer, which // will trigger this check. It really isn't. - if (Options.get(OptionBit::DeallocTypeMismatch)) { + if (Options.DeallocTypeMismatch) { if (UNLIKELY(OldHeader.OriginOrWasZeroed != Chunk::Origin::Malloc)) reportDeallocTypeMismatch(AllocatorAction::Reallocating, OldPtr, OldHeader.OriginOrWasZeroed, @@ -590,11 +583,11 @@ : BlockEnd - (reinterpret_cast(OldPtr) + NewSize)) & Chunk::SizeOrUnusedBytesMask; Chunk::compareExchangeHeader(Cookie, OldPtr, &NewHeader, &OldHeader); - if (UNLIKELY(ClassId && useMemoryTagging(Options))) { + if (UNLIKELY(ClassId && useMemoryTagging())) { resizeTaggedChunk(reinterpret_cast(OldTaggedPtr) + OldSize, reinterpret_cast(OldTaggedPtr) + NewSize, BlockEnd); - storeAllocationStackMaybe(Options, OldPtr); + storeAllocationStackMaybe(OldPtr); } return OldTaggedPtr; } @@ -608,7 +601,7 @@ if (NewPtr) { const uptr OldSize = getSize(OldPtr, &OldHeader); memcpy(NewPtr, OldTaggedPtr, Min(NewSize, OldSize)); - quarantineOrDeallocateChunk(Options, OldPtr, &OldHeader, OldSize); + quarantineOrDeallocateChunk(OldPtr, &OldHeader, OldSize); } return NewPtr; } @@ -689,7 +682,7 @@ if (getChunkFromBlock(Block, &Chunk, &Header) && Header.State == Chunk::State::Allocated) { uptr TaggedChunk = Chunk; - if (useMemoryTagging(Primary.Options.load())) + if (useMemoryTagging()) TaggedChunk = loadTag(Chunk); Callback(TaggedChunk, getSize(reinterpret_cast(Chunk), &Header), Arg); @@ -704,7 +697,7 @@ bool canReturnNull() { initThreadMaybe(); - return Primary.Options.load().get(OptionBit::MayReturnNull); + return Options.MayReturnNull; } bool setOption(Option O, sptr Value) { @@ -718,9 +711,9 @@ // any particular chunk is cut in half. Therefore we use this tuning // setting to control whether odd/even tags are enabled. if (Value == M_MEMTAG_TUNING_BUFFER_OVERFLOW) - Primary.Options.set(OptionBit::UseOddEvenTags); + Options.UseOddEvenTags = true; else if (Value == M_MEMTAG_TUNING_UAF) - Primary.Options.clear(OptionBit::UseOddEvenTags); + Options.UseOddEvenTags = false; return true; } else { // We leave it to the various sub-components to decide whether or not they @@ -780,26 +773,18 @@ Header.State == Chunk::State::Allocated; } - bool useMemoryTagging() const { - return useMemoryTagging(Primary.Options.load()); - } - static bool useMemoryTagging(Options Options) { - return PrimaryT::useMemoryTagging(Options); - } + bool useMemoryTagging() { return Primary.useMemoryTagging(); } void disableMemoryTagging() { Primary.disableMemoryTagging(); } void setTrackAllocationStacks(bool Track) { initThreadMaybe(); - if (Track) - Primary.Options.set(OptionBit::TrackAllocationStacks); - else - Primary.Options.clear(OptionBit::TrackAllocationStacks); + Options.TrackAllocationStacks = Track; } void setFillContents(FillContentsMode FillContents) { initThreadMaybe(); - Primary.Options.setFillContentsMode(FillContents); + Options.FillContents = FillContents; } const char *getStackDepotAddress() const { @@ -966,7 +951,16 @@ static const uptr MaxTraceSize = 64; u32 Cookie; - u32 QuarantineMaxChunkSize; + + struct { + u8 MayReturnNull : 1; // may_return_null + FillContentsMode FillContents : 2; // zero_contents, pattern_fill_contents + u8 DeallocTypeMismatch : 1; // dealloc_type_mismatch + u8 DeleteSizeMismatch : 1; // delete_size_mismatch + u8 TrackAllocationStacks : 1; + u8 UseOddEvenTags : 1; + u32 QuarantineMaxChunkSize; // quarantine_max_chunk_size + } Options; GlobalStats Stats; PrimaryT Primary; @@ -1031,15 +1025,15 @@ reinterpret_cast(Ptr) - SizeOrUnusedBytes; } - void quarantineOrDeallocateChunk(Options Options, void *Ptr, - Chunk::UnpackedHeader *Header, uptr Size) { + void quarantineOrDeallocateChunk(void *Ptr, Chunk::UnpackedHeader *Header, + uptr Size) { Chunk::UnpackedHeader NewHeader = *Header; - if (UNLIKELY(NewHeader.ClassId && useMemoryTagging(Options))) { + if (UNLIKELY(NewHeader.ClassId && useMemoryTagging())) { u8 PrevTag = extractTag(loadTag(reinterpret_cast(Ptr))); if (!TSDRegistry.getDisableMemInit()) { uptr TaggedBegin, TaggedEnd; const uptr OddEvenMask = computeOddEvenMaskForPointerMaybe( - Options, reinterpret_cast(getBlockBegin(Ptr, &NewHeader)), + reinterpret_cast(getBlockBegin(Ptr, &NewHeader)), SizeClassMap::getSizeByClassId(NewHeader.ClassId)); // Exclude the previous tag so that immediate use after free is detected // 100% of the time. @@ -1047,14 +1041,14 @@ &TaggedEnd); } NewHeader.OriginOrWasZeroed = !TSDRegistry.getDisableMemInit(); - storeDeallocationStackMaybe(Options, Ptr, PrevTag); + storeDeallocationStackMaybe(Ptr, PrevTag); } // If the quarantine is disabled, the actual size of a chunk is 0 or larger // than the maximum allowed, we return a chunk directly to the backend. // Logical Or can be short-circuited, which introduces unnecessary // conditional jumps, so use bitwise Or and let the compiler be clever. - const bool BypassQuarantine = - !Quarantine.getCacheSize() | !Size | (Size > QuarantineMaxChunkSize); + const bool BypassQuarantine = !Quarantine.getCacheSize() | !Size | + (Size > Options.QuarantineMaxChunkSize); if (BypassQuarantine) { NewHeader.State = Chunk::State::Available; Chunk::compareExchangeHeader(Cookie, Ptr, &NewHeader, Header); @@ -1095,17 +1089,16 @@ return Offset + Chunk::getHeaderSize(); } - void storeAllocationStackMaybe(Options Options, void *Ptr) { - if (!UNLIKELY(Options.get(OptionBit::TrackAllocationStacks))) + void storeAllocationStackMaybe(void *Ptr) { + if (!UNLIKELY(Options.TrackAllocationStacks)) return; auto *Ptr32 = reinterpret_cast(Ptr); Ptr32[MemTagAllocationTraceIndex] = collectStackTrace(); Ptr32[MemTagAllocationTidIndex] = getThreadID(); } - void storeDeallocationStackMaybe(Options Options, void *Ptr, - uint8_t PrevTag) { - if (!UNLIKELY(Options.get(OptionBit::TrackAllocationStacks))) + void storeDeallocationStackMaybe(void *Ptr, uint8_t PrevTag) { + if (!UNLIKELY(Options.TrackAllocationStacks)) return; // Disable tag checks here so that we don't need to worry about zero sized diff --git a/compiler-rt/lib/scudo/standalone/options.h b/compiler-rt/lib/scudo/standalone/options.h deleted file mode 100644 --- a/compiler-rt/lib/scudo/standalone/options.h +++ /dev/null @@ -1,72 +0,0 @@ -//===-- options.h -----------------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef SCUDO_OPTIONS_H_ -#define SCUDO_OPTIONS_H_ - -#include "atomic_helpers.h" -#include "common.h" - -namespace scudo { - -enum class OptionBit { - MayReturnNull, - FillContents0of2, - FillContents1of2, - DeallocTypeMismatch, - DeleteSizeMismatch, - TrackAllocationStacks, - UseOddEvenTags, - UseMemoryTagging, -}; - -struct Options { - u32 Val; - - bool get(OptionBit Opt) const { return Val & (1U << static_cast(Opt)); } - - FillContentsMode getFillContentsMode() const { - return static_cast( - (Val >> static_cast(OptionBit::FillContents0of2)) & 3); - } -}; - -struct AtomicOptions { - atomic_u32 Val; - -public: - Options load() const { - return Options{atomic_load(&Val, memory_order_relaxed)}; - } - - void clear(OptionBit Opt) { - atomic_fetch_and(&Val, ~(1U << static_cast(Opt)), - memory_order_relaxed); - } - - void set(OptionBit Opt) { - atomic_fetch_or(&Val, 1U << static_cast(Opt), memory_order_relaxed); - } - - void setFillContentsMode(FillContentsMode FillContents) { - while (1) { - u32 Opts = atomic_load(&Val, memory_order_relaxed); - u32 NewOpts = Opts; - NewOpts &= ~(3U << static_cast(OptionBit::FillContents0of2)); - NewOpts |= static_cast(FillContents) - << static_cast(OptionBit::FillContents0of2); - if (atomic_compare_exchange_strong(&Val, &Opts, NewOpts, - memory_order_relaxed)) - break; - } - } -}; - -} // namespace scudo - -#endif // SCUDO_OPTIONS_H_ diff --git a/compiler-rt/lib/scudo/standalone/primary32.h b/compiler-rt/lib/scudo/standalone/primary32.h --- a/compiler-rt/lib/scudo/standalone/primary32.h +++ b/compiler-rt/lib/scudo/standalone/primary32.h @@ -13,7 +13,6 @@ #include "common.h" #include "list.h" #include "local_cache.h" -#include "options.h" #include "release.h" #include "report.h" #include "stats.h" @@ -207,10 +206,7 @@ return TotalReleasedBytes; } - static bool useMemoryTagging(Options Options) { - (void)Options; - return false; - } + bool useMemoryTagging() { return false; } void disableMemoryTagging() {} const char *getRegionInfoArrayAddress() const { return nullptr; } @@ -222,8 +218,6 @@ return {}; } - AtomicOptions Options; - private: static const uptr NumClasses = SizeClassMap::NumClasses; static const uptr RegionSize = 1UL << RegionSizeLog; diff --git a/compiler-rt/lib/scudo/standalone/primary64.h b/compiler-rt/lib/scudo/standalone/primary64.h --- a/compiler-rt/lib/scudo/standalone/primary64.h +++ b/compiler-rt/lib/scudo/standalone/primary64.h @@ -14,7 +14,6 @@ #include "list.h" #include "local_cache.h" #include "memtag.h" -#include "options.h" #include "release.h" #include "stats.h" #include "string_utils.h" @@ -94,8 +93,8 @@ } setOption(Option::ReleaseInterval, static_cast(ReleaseToOsInterval)); - if (SupportsMemoryTagging && systemSupportsMemoryTagging()) - Options.set(OptionBit::UseMemoryTagging); + if (SupportsMemoryTagging) + UseMemoryTagging = systemSupportsMemoryTagging(); } void init(s32 ReleaseToOsInterval) { memset(this, 0, sizeof(*this)); @@ -208,10 +207,10 @@ return TotalReleasedBytes; } - static bool useMemoryTagging(Options Options) { - return SupportsMemoryTagging && Options.get(OptionBit::UseMemoryTagging); + bool useMemoryTagging() const { + return SupportsMemoryTagging && UseMemoryTagging; } - void disableMemoryTagging() { Options.clear(OptionBit::UseMemoryTagging); } + void disableMemoryTagging() { UseMemoryTagging = false; } const char *getRegionInfoArrayAddress() const { return reinterpret_cast(RegionInfoArray); @@ -263,8 +262,6 @@ return B; } - AtomicOptions Options; - private: static const uptr RegionSize = 1UL << RegionSizeLog; static const uptr NumClasses = SizeClassMap::NumClasses; @@ -309,6 +306,7 @@ uptr PrimaryBase; MapPlatformData Data; atomic_s32 ReleaseToOsIntervalMs; + bool UseMemoryTagging; alignas(SCUDO_CACHE_LINE_SIZE) RegionInfo RegionInfoArray[NumClasses]; RegionInfo *getRegionInfo(uptr ClassId) { @@ -375,7 +373,7 @@ if (UNLIKELY(!map(reinterpret_cast(RegionBeg + MappedUser), UserMapSize, "scudo:primary", MAP_ALLOWNOMEM | MAP_RESIZABLE | - (useMemoryTagging(Options.load()) ? MAP_MEMTAG : 0), + (useMemoryTagging() ? MAP_MEMTAG : 0), &Region->Data))) return nullptr; Region->MappedUser += UserMapSize; diff --git a/compiler-rt/lib/scudo/standalone/wrappers_c.inc b/compiler-rt/lib/scudo/standalone/wrappers_c.inc --- a/compiler-rt/lib/scudo/standalone/wrappers_c.inc +++ b/compiler-rt/lib/scudo/standalone/wrappers_c.inc @@ -234,26 +234,30 @@ // Disable memory tagging for the heap. The caller must disable memory tag // checks globally (e.g. by clearing TCF0 on aarch64) before calling this -// function, and may not re-enable them after calling the function. +// function, and may not re-enable them after calling the function. The program +// must be single threaded at the point when the function is called. INTERFACE WEAK void SCUDO_PREFIX(malloc_disable_memory_tagging)() { SCUDO_ALLOCATOR.disableMemoryTagging(); } // Sets whether scudo records stack traces and other metadata for allocations // and deallocations. This function only has an effect if the allocator and -// hardware support memory tagging. +// hardware support memory tagging. The program must be single threaded at the +// point when the function is called. INTERFACE WEAK void SCUDO_PREFIX(malloc_set_track_allocation_stacks)(int track) { SCUDO_ALLOCATOR.setTrackAllocationStacks(track); } -// Sets whether scudo zero-initializes all allocated memory. +// Sets whether scudo zero-initializes all allocated memory. The program must +// be single threaded at the point when the function is called. INTERFACE WEAK void SCUDO_PREFIX(malloc_set_zero_contents)(int zero_contents) { SCUDO_ALLOCATOR.setFillContents(zero_contents ? scudo::ZeroFill : scudo::NoFill); } -// Sets whether scudo pattern-initializes all allocated memory. +// Sets whether scudo pattern-initializes all allocated memory. The program must +// be single threaded at the point when the function is called. INTERFACE WEAK void SCUDO_PREFIX(malloc_set_pattern_fill_contents)(int pattern_fill_contents) { SCUDO_ALLOCATOR.setFillContents( diff --git a/compiler-rt/test/asan/TestCases/Posix/no_asan_gen_globals.c b/compiler-rt/test/asan/TestCases/Posix/no_asan_gen_globals.c --- a/compiler-rt/test/asan/TestCases/Posix/no_asan_gen_globals.c +++ b/compiler-rt/test/asan/TestCases/Posix/no_asan_gen_globals.c @@ -1,7 +1,5 @@ // FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316 // XFAIL: android -// Bug 47607 -// XFAIL: solaris // Make sure ___asan_gen_* strings do not end up in the symbol table. // RUN: %clang_asan %s -o %t.exe diff --git a/compiler-rt/test/asan/TestCases/Posix/unpoison-alternate-stack.cpp b/compiler-rt/test/asan/TestCases/Posix/unpoison-alternate-stack.cpp --- a/compiler-rt/test/asan/TestCases/Posix/unpoison-alternate-stack.cpp +++ b/compiler-rt/test/asan/TestCases/Posix/unpoison-alternate-stack.cpp @@ -7,10 +7,7 @@ // RUN: %run %t // XFAIL: ios && !iossim -// longjmp from signal handler is unportable. -// XFAIL: solaris -#include #include #include #include @@ -86,9 +83,10 @@ void setSignalAlternateStack(void *AltStack) { sigaltstack((stack_t const *)AltStack, nullptr); - struct sigaction Action = {}; - Action.sa_sigaction = signalHandler; - Action.sa_flags = SA_SIGINFO | SA_NODEFER | SA_ONSTACK; + struct sigaction Action = { + .sa_sigaction = signalHandler, + .sa_flags = SA_SIGINFO | SA_NODEFER | SA_ONSTACK, + }; sigemptyset(&Action.sa_mask); sigaction(SIGUSR1, &Action, nullptr); @@ -139,11 +137,9 @@ // reports when the stack is reused. int main() { size_t const PageSize = sysconf(_SC_PAGESIZE); - // The Solaris defaults of 4k (32-bit) and 8k (64-bit) are too small. - size_t const MinStackSize = std::max(PTHREAD_STACK_MIN, 16 * 1024); // To align the alternate stack, we round this up to page_size. size_t const DefaultStackSize = - (MinStackSize - 1 + PageSize) & ~(PageSize - 1); + (PTHREAD_STACK_MIN - 1 + PageSize) & ~(PageSize - 1); // The alternate stack needs a certain size, or the signal handler segfaults. size_t const AltStackSize = 10 * PageSize; size_t const MappingSize = DefaultStackSize + AltStackSize; @@ -153,10 +149,11 @@ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - stack_t AltStack = {}; - AltStack.ss_sp = (char *)Mapping + DefaultStackSize; - AltStack.ss_flags = 0; - AltStack.ss_size = AltStackSize; + stack_t const AltStack = { + .ss_sp = (char *)Mapping + DefaultStackSize, + .ss_flags = 0, + .ss_size = AltStackSize, + }; pthread_t Thread; pthread_attr_t ThreadAttr; diff --git a/debuginfo-tests/CMakeLists.txt b/debuginfo-tests/CMakeLists.txt --- a/debuginfo-tests/CMakeLists.txt +++ b/debuginfo-tests/CMakeLists.txt @@ -22,16 +22,6 @@ not ) -if ("mlir" IN_LIST LLVM_ENABLE_PROJECTS) - add_llvm_executable(check-gdb-mlir-support - llvm-prettyprinters/gdb/mlir-support.cpp - ) - target_include_directories(check-gdb-mlir-support PRIVATE ${LLVM_EXTERNAL_MLIR_SOURCE_DIR}/include) - target_link_libraries(check-gdb-mlir-support PRIVATE MLIRIR) - list(APPEND DEBUGINFO_TEST_DEPS check-gdb-mlir-support) - set(MLIR_SOURCE_DIR ${LLVM_EXTERNAL_MLIR_SOURCE_DIR}) -endif() - if("compiler-rt" IN_LIST LLVM_ENABLE_PROJECTS) # llgdb-tests/asan.c and other asan* files. if(TARGET asan) diff --git a/debuginfo-tests/lit.cfg.py b/debuginfo-tests/lit.cfg.py --- a/debuginfo-tests/lit.cfg.py +++ b/debuginfo-tests/lit.cfg.py @@ -157,6 +157,6 @@ if apple_lldb_vers < 1000: config.available_features.add('apple-lldb-pre-1000') -llvm_config.feature_config( - [('--build-mode', {'Debug|RelWithDebInfo': 'debug-info'})] -) +llvm_config.feature_config([('--build-mode', { + 'Debug|RelWithDebInfo': 'debug-info' +})]) diff --git a/debuginfo-tests/lit.site.cfg.py.in b/debuginfo-tests/lit.site.cfg.py.in --- a/debuginfo-tests/lit.site.cfg.py.in +++ b/debuginfo-tests/lit.site.cfg.py.in @@ -20,8 +20,6 @@ config.host_arch = "@HOST_ARCH@" config.is_msvc = lit.util.pythonize_bool("@MSVC@") -config.mlir_src_root = "@MLIR_SOURCE_DIR@" - config.llvm_use_sanitizer = "@LLVM_USE_SANITIZER@" config.python3_executable = "@Python3_EXECUTABLE@" diff --git a/debuginfo-tests/llvm-prettyprinters/gdb/lit.local.cfg b/debuginfo-tests/llvm-prettyprinters/gdb/lit.local.cfg --- a/debuginfo-tests/llvm-prettyprinters/gdb/lit.local.cfg +++ b/debuginfo-tests/llvm-prettyprinters/gdb/lit.local.cfg @@ -4,10 +4,6 @@ if 'native' not in config.available_features or lit.util.which('gdb') is None: config.unsupported = True -if config.mlir_src_root: - config.substitutions.append(("%mlir_src_root", config.mlir_src_root)) - config.available_features.add('mlir') - config.suffixes = ['.gdb'] diff --git a/debuginfo-tests/llvm-prettyprinters/gdb/llvm-support.cpp b/debuginfo-tests/llvm-prettyprinters/gdb/llvm-support.cpp --- a/debuginfo-tests/llvm-prettyprinters/gdb/llvm-support.cpp +++ b/debuginfo-tests/llvm-prettyprinters/gdb/llvm-support.cpp @@ -53,13 +53,8 @@ return Result; }(); -int main() { - // Reference symbols that might otherwise be stripped. - ArrayRef[0]; - MutableArrayRef[0]; - !ExpectedValue; - !ExpectedError; - *OptionalValue; - *OptionalNone; - return 0; -} +// Check expected instances to avoid compile errors. +auto CheckExpectedValue = static_cast(ExpectedValue); +auto CheckExpectedError = static_cast(ExpectedError); + +int main() { return 0; } diff --git a/debuginfo-tests/llvm-prettyprinters/gdb/mlir-support.cpp b/debuginfo-tests/llvm-prettyprinters/gdb/mlir-support.cpp deleted file mode 100644 --- a/debuginfo-tests/llvm-prettyprinters/gdb/mlir-support.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "mlir/IR/Identifier.h" -#include "mlir/IR/Location.h" -#include "mlir/IR/MLIRContext.h" -#include "mlir/IR/OperationSupport.h" -#include "mlir/IR/StandardTypes.h" - -mlir::MLIRContext Context; - -auto Identifier = mlir::Identifier::get("foo", &Context); -mlir::OperationName OperationName("FooOp", &Context); -mlir::Value Value({reinterpret_cast(0x8), - mlir::Value::Kind::TrailingOpResult}); - -mlir::Type Type(nullptr); -mlir::Type IndexType = mlir::IndexType::get(&Context); -mlir::Type IntegerType = - mlir::IntegerType::get(3, mlir::IntegerType::Unsigned, &Context); -mlir::Type FloatType = mlir::Float32Type::get(&Context); -mlir::Type MemRefType = mlir::MemRefType::get({4, 5}, FloatType); -mlir::Type UnrankedMemRefType = mlir::UnrankedMemRefType::get(IntegerType, 6); -mlir::Type VectorType = mlir::VectorType::get({1, 2}, FloatType); -mlir::Type TupleType = - mlir::TupleType::get(mlir::TypeRange({IndexType, FloatType}), &Context); - -auto UnknownLoc = mlir::UnknownLoc::get(&Context); -auto FileLineColLoc = mlir::FileLineColLoc::get("file", 7, 8, &Context); -auto OpaqueLoc = mlir::OpaqueLoc::get(9, &Context); -auto NameLoc = mlir::NameLoc::get(Identifier, &Context); -auto CallSiteLoc = mlir::CallSiteLoc::get(FileLineColLoc, OpaqueLoc); -auto FusedLoc = mlir::FusedLoc::get({FileLineColLoc, NameLoc}, &Context); - -mlir::Attribute UnitAttr = mlir::UnitAttr::get(&Context); -mlir::Attribute FloatAttr = mlir::FloatAttr::get(FloatType, 1.0); -mlir::Attribute IntegerAttr = mlir::IntegerAttr::get(IntegerType, 10); -mlir::Attribute TypeAttr = mlir::TypeAttr::get(IndexType); -mlir::Attribute ArrayAttr = mlir::ArrayAttr::get({UnitAttr}, &Context); -mlir::Attribute StringAttr = mlir::StringAttr::get("foo", &Context); -mlir::Attribute ElementsAttr = mlir::DenseElementsAttr::get( - VectorType.cast(), llvm::ArrayRef{2.0f, 3.0f}); - -int main() { return 0; } diff --git a/debuginfo-tests/llvm-prettyprinters/gdb/mlir-support.gdb b/debuginfo-tests/llvm-prettyprinters/gdb/mlir-support.gdb deleted file mode 100644 --- a/debuginfo-tests/llvm-prettyprinters/gdb/mlir-support.gdb +++ /dev/null @@ -1,112 +0,0 @@ -# RUN: gdb -q -batch -n -iex 'source %mlir_src_root/utils/gdb-scripts/prettyprinters.py' -iex 'source %llvm_src_root/utils/gdb-scripts/prettyprinters.py' -x %s %llvm_tools_dir/check-gdb-mlir-support | FileCheck %s -# REQUIRES: debug-info -# REQUIRES: mlir - -break main -run - -# CHECK: "foo" -p Identifier - -# CHECK: "FooOp" -p OperationName - -# CHECK: 0x8 -# CHECK: TrailingOpResult -p Value - -# CHECK: impl = 0x0 -p Type - -# CHECK: cast -p IndexType - -# CHECK: cast -# CHECK: width = 3 -# CHECK: Unsigned -p IntegerType - -# CHECK: cast -p FloatType - -# CHECK: cast -# CHECK: shapeSize = 2 -# CHECK: shapeElements[0] = 4 -# CHECK: shapeElements[1] = 5 -p MemRefType - -# CHECK: cast -# CHECK: memorySpace = 6 -p UnrankedMemRefType - -# CHECK: cast -# CHECK: shapeSize = 2 -# CHECK: shapeElements[0] = 1 -# CHECK: shapeElements[1] = 2 -p VectorType - -# CHECK: cast -# CHECK: numElements = 2 -# CHECK: elements[0] -# CHECK: mlir::IndexType -# CHECK: elements[1] -# CHECK: mlir::Float32Type -p TupleType - -# CHECK: cast -p UnknownLoc - -# CHECK: cast -# CHECK: filename = "file" -# CHECK: line = 7 -# CHECK: column = 8 -p FileLineColLoc - -# CHECK: cast -# CHECK: underlyingLocation = 9 -p OpaqueLoc - -# CHECK: cast -# CHECK: name = "foo" -# CHECK: mlir::UnknownLoc -p NameLoc - -# CHECK: cast -# CHECK: callee -# CHECK: mlir::FileLineColLoc -# CHECK: caller -# CHECK: mlir::OpaqueLoc -p CallSiteLoc - -# CHECK: cast -# CHECK: numLocs = 2 -# CHECK: locs[0] -# CHECK: mlir::FileLineColLoc -# CHECK: locs[1] -# CHECK: mlir::NameLoc -p FusedLoc - -# CHECK: cast -p UnitAttr - -# CHECK: cast -p FloatAttr - -# CHECK: cast -p IntegerAttr - -# CHECK: cast -# CHECK: mlir::IndexType -p TypeAttr - -# CHECK: cast -# CHECK: llvm::ArrayRef of length 1 -# CHECK: mlir::UnitAttr -p ArrayAttr - -# CHECK: cast -# CHECK: value = "foo" -p StringAttr - -# CHECK: cast -p ElementsAttr diff --git a/flang/include/flang/Evaluate/characteristics.h b/flang/include/flang/Evaluate/characteristics.h --- a/flang/include/flang/Evaluate/characteristics.h +++ b/flang/include/flang/Evaluate/characteristics.h @@ -45,7 +45,7 @@ using common::CopyableIndirection; -// Are these procedures distinguishable for a generic name? +// Are these procedures distinguishable for a generic name or FINAL? bool Distinguishable(const Procedure &, const Procedure &); // Are these procedures distinguishable for a generic operator or assignment? bool DistinguishableOpOrAssign(const Procedure &, const Procedure &); diff --git a/flang/include/flang/Evaluate/type.h b/flang/include/flang/Evaluate/type.h --- a/flang/include/flang/Evaluate/type.h +++ b/flang/include/flang/Evaluate/type.h @@ -166,11 +166,9 @@ bool HasDeferredTypeParameter() const; // 7.3.2.3 & 15.5.2.4 type compatibility. - // x.IsTypeCompatibleWith(y) is true if "x => y" or passing actual y to + // x.IsTkCompatibleWith(y) is true if "x => y" or passing actual y to // dummy argument x would be valid. Be advised, this is not a reflexive - // relation. - bool IsTypeCompatibleWith(const DynamicType &) const; - // Type compatible and kind type parameters match + // relation. Kind type parameters must match. bool IsTkCompatibleWith(const DynamicType &) const; // Result will be missing when a symbol is absent or diff --git a/flang/include/flang/Semantics/symbol.h b/flang/include/flang/Semantics/symbol.h --- a/flang/include/flang/Semantics/symbol.h +++ b/flang/include/flang/Semantics/symbol.h @@ -248,6 +248,8 @@ const std::list ¶mNames() const { return paramNames_; } const SymbolVector ¶mDecls() const { return paramDecls_; } bool sequence() const { return sequence_; } + std::map &finals() { return finals_; } + const std::map &finals() const { return finals_; } bool isForwardReferenced() const { return isForwardReferenced_; } void add_paramName(const SourceName &name) { paramNames_.push_back(name); } void add_paramDecl(const Symbol &symbol) { paramDecls_.push_back(symbol); } @@ -279,6 +281,7 @@ // These are the names of the derived type's components in component // order. A parent component, if any, appears first in this list. std::list componentNames_; + std::map finals_; // FINAL :: subr bool sequence_{false}; bool isForwardReferenced_{false}; friend llvm::raw_ostream &operator<<( @@ -322,8 +325,6 @@ std::size_t alignment_{0}; // required alignment in bytes }; -class FinalProcDetails {}; // TODO - class MiscDetails { public: ENUM_CLASS(Kind, None, ConstructName, ScopeName, PassName, ComplexPartRe, @@ -471,7 +472,7 @@ ObjectEntityDetails, ProcEntityDetails, AssocEntityDetails, DerivedTypeDetails, UseDetails, UseErrorDetails, HostAssocDetails, GenericDetails, ProcBindingDetails, NamelistDetails, CommonBlockDetails, - FinalProcDetails, TypeParamDetails, MiscDetails>; + TypeParamDetails, MiscDetails>; llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Details &); std::string DetailsToString(const Details &); diff --git a/flang/include/flang/Semantics/tools.h b/flang/include/flang/Semantics/tools.h --- a/flang/include/flang/Semantics/tools.h +++ b/flang/include/flang/Semantics/tools.h @@ -162,6 +162,7 @@ } bool IsAssumedLengthCharacter(const Symbol &); bool IsExternal(const Symbol &); +bool IsModuleProcedure(const Symbol &); // Is the symbol modifiable in this scope std::optional WhyNotModifiable( const Symbol &, const Scope &); @@ -283,6 +284,20 @@ return value && *value == 0; } +// 15.2.2 +enum class ProcedureDefinitionClass { + None, + Intrinsic, + External, + Internal, + Module, + Dummy, + Pointer, + StatementFunction +}; + +ProcedureDefinitionClass ClassifyProcedure(const Symbol &); + // Derived type component iterator that provides a C++ LegacyForwardIterator // iterator over the Ordered, Direct, Ultimate or Potential components of a // DerivedTypeSpec. These iterators can be used with STL algorithms diff --git a/flang/lib/Evaluate/characteristics.cpp b/flang/lib/Evaluate/characteristics.cpp --- a/flang/lib/Evaluate/characteristics.cpp +++ b/flang/lib/Evaluate/characteristics.cpp @@ -130,7 +130,7 @@ const TypeAndShape &that, const char *thisIs, const char *thatIs, bool isElemental) const { const auto &len{that.LEN()}; - if (!type_.IsTypeCompatibleWith(that.type_)) { + if (!type_.IsTkCompatibleWith(that.type_)) { messages.Say( "%1$s type '%2$s' is not compatible with %3$s type '%4$s'"_err_en_US, thatIs, that.type_.AsFortran(len ? len->AsFortran() : ""), thisIs, diff --git a/flang/lib/Evaluate/tools.cpp b/flang/lib/Evaluate/tools.cpp --- a/flang/lib/Evaluate/tools.cpp +++ b/flang/lib/Evaluate/tools.cpp @@ -965,7 +965,6 @@ [](const GenericDetails &) { return true; }, [](const ProcBindingDetails &) { return true; }, [](const UseDetails &x) { return IsProcedure(x.symbol()); }, - // TODO: FinalProcDetails? [](const auto &) { return false; }, }, symbol.details()); diff --git a/flang/lib/Evaluate/type.cpp b/flang/lib/Evaluate/type.cpp --- a/flang/lib/Evaluate/type.cpp +++ b/flang/lib/Evaluate/type.cpp @@ -218,19 +218,6 @@ } } -static const semantics::Symbol *FindComponent( - const semantics::DerivedTypeSpec &derived, parser::CharBlock name) { - if (const auto *scope{derived.scope()}) { - auto iter{scope->find(name)}; - if (iter != scope->end()) { - return &*iter->second; - } else if (const auto *parent{GetParentTypeSpec(derived)}) { - return FindComponent(*parent, name); - } - } - return nullptr; -} - // Compares two derived type representations to see whether they both // represent the "same type" in the sense of section 7.5.2.4. using SetOfDerivedTypePairs = @@ -294,24 +281,9 @@ if (x.attrs().test(semantics::Attr::PRIVATE)) { return false; } -#if 0 // TODO - if (const auto *xObject{x.detailsIf()}) { - if (const auto *yObject{y.detailsIf()}) { -#else - if (x.has()) { - if (y.has()) { -#endif - // TODO: compare types, type parameters, bounds, &c. - return true; -} -else { - return false; -} -} // namespace Fortran::evaluate -else { - // TODO: non-object components - return true; -} + // TODO: compare types, parameters, bounds, &c. + return x.has() == + y.has(); } static bool AreCompatibleDerivedTypes(const semantics::DerivedTypeSpec *x, @@ -334,45 +306,9 @@ return param && param->attr() == common::TypeParamAttr::Kind; } -static bool IsKindTypeParameter( - const semantics::DerivedTypeSpec &derived, parser::CharBlock name) { - const semantics::Symbol *symbol{FindComponent(derived, name)}; - return symbol && IsKindTypeParameter(*symbol); -} - -bool DynamicType::IsTypeCompatibleWith(const DynamicType &that) const { - if (derived_) { - if (!AreCompatibleDerivedTypes(derived_, that.derived_, IsPolymorphic())) { - return false; - } - // The values of derived type KIND parameters must match. - for (const auto &[name, param] : derived_->parameters()) { - if (IsKindTypeParameter(*derived_, name)) { - bool ok{false}; - if (auto myValue{ToInt64(param.GetExplicit())}) { - if (const auto *thatParam{that.derived_->FindParameter(name)}) { - if (auto thatValue{ToInt64(thatParam->GetExplicit())}) { - ok = *myValue == *thatValue; - } - } - } - if (!ok) { - return false; - } - } - } - return true; - } else if (category_ == that.category_ && kind_ == that.kind_) { - // CHARACTER length is not checked here - return true; - } else { - return IsUnlimitedPolymorphic(); - } -} - // Do the kind type parameters of type1 have the same values as the -// corresponding kind type parameters of the type2? -static bool IsKindCompatible(const semantics::DerivedTypeSpec &type1, +// corresponding kind type parameters of type2? +static bool AreKindCompatible(const semantics::DerivedTypeSpec &type1, const semantics::DerivedTypeSpec &type2) { for (const auto &[name, param1] : type1.parameters()) { if (param1.isKind()) { @@ -385,18 +321,20 @@ return true; } +// See 7.3.2.3 (5) & 15.5.2.4 bool DynamicType::IsTkCompatibleWith(const DynamicType &that) const { - if (category_ != TypeCategory::Derived) { - return category_ == that.category_ && kind_ == that.kind_; - } else if (IsUnlimitedPolymorphic()) { + if (IsUnlimitedPolymorphic()) { return true; } else if (that.IsUnlimitedPolymorphic()) { return false; - } else if (!derived_ || !that.derived_ || - !IsKindCompatible(*derived_, *that.derived_)) { - return false; // kind params don't match + } else if (category_ != that.category_) { + return false; + } else if (derived_) { + return that.derived_ && + AreCompatibleDerivedTypes(derived_, that.derived_, IsPolymorphic()) && + AreKindCompatible(*derived_, *that.derived_); } else { - return AreCompatibleDerivedTypes(derived_, that.derived_, IsPolymorphic()); + return kind_ == that.kind_; } } diff --git a/flang/lib/Semantics/check-call.cpp b/flang/lib/Semantics/check-call.cpp --- a/flang/lib/Semantics/check-call.cpp +++ b/flang/lib/Semantics/check-call.cpp @@ -144,8 +144,7 @@ parser::ContextualMessages &messages{context.messages()}; PadShortCharacterActual(actual, dummy.type, actualType, messages); ConvertIntegerActual(actual, dummy.type, actualType, messages); - bool typesCompatible{ - dummy.type.type().IsTypeCompatibleWith(actualType.type())}; + bool typesCompatible{dummy.type.type().IsTkCompatibleWith(actualType.type())}; if (typesCompatible) { if (isElemental) { } else if (dummy.type.attrs().test( @@ -215,13 +214,17 @@ "Actual argument associated with TYPE(*) %s may not have type-bound procedure '%s'"_err_en_US, dummyName, tbp->name()); } - if (const Symbol * - finalizer{FindImmediateComponent(*derived, [](const Symbol &symbol) { - return symbol.has(); - })}) { // 15.5.2.4(2) - evaluate::SayWithDeclaration(messages, *finalizer, - "Actual argument associated with TYPE(*) %s may not have FINAL subroutine '%s'"_err_en_US, - dummyName, finalizer->name()); + const auto &finals{ + derived->typeSymbol().get().finals()}; + if (!finals.empty()) { // 15.5.2.4(2) + if (auto *msg{messages.Say( + "Actual argument associated with TYPE(*) %s may not have derived type '%s' with FINAL subroutine '%s'"_err_en_US, + dummyName, derived->typeSymbol().name(), + finals.begin()->first)}) { + msg->Attach(finals.begin()->first, + "FINAL subroutine '%s' in derived type '%s'"_en_US, + finals.begin()->first, derived->typeSymbol().name()); + } } } if (actualIsCoindexed) { @@ -431,14 +434,14 @@ "If a POINTER or ALLOCATABLE dummy or actual argument is polymorphic, both must be so"_err_en_US); } } else if (!actualIsUnlimited && typesCompatible) { - if (!actualType.type().IsTypeCompatibleWith(dummy.type.type())) { + if (!actualType.type().IsTkCompatibleWith(dummy.type.type())) { if (dummy.intent == common::Intent::In) { // extension: allow with warning, rule is only relevant for definables messages.Say( - "POINTER or ALLOCATABLE dummy and actual arguments should have the same declared type"_en_US); + "POINTER or ALLOCATABLE dummy and actual arguments should have the same declared type and kind"_en_US); } else { messages.Say( - "POINTER or ALLOCATABLE dummy and actual arguments must have the same declared type"_err_en_US); + "POINTER or ALLOCATABLE dummy and actual arguments must have the same declared type and kind"_err_en_US); } } if (const auto *derived{ diff --git a/flang/lib/Semantics/check-declarations.cpp b/flang/lib/Semantics/check-declarations.cpp --- a/flang/lib/Semantics/check-declarations.cpp +++ b/flang/lib/Semantics/check-declarations.cpp @@ -66,6 +66,10 @@ void CheckSubprogram(const Symbol &, const SubprogramDetails &); void CheckAssumedTypeEntity(const Symbol &, const ObjectEntityDetails &); void CheckDerivedType(const Symbol &, const DerivedTypeDetails &); + bool CheckFinal( + const Symbol &subroutine, SourceName, const Symbol &derivedType); + bool CheckDistinguishableFinals(const Symbol &f1, SourceName f1name, + const Symbol &f2, SourceName f2name, const Symbol &derivedType); void CheckGeneric(const Symbol &, const GenericDetails &); void CheckHostAssoc(const Symbol &, const HostAssocDetails &); bool CheckDefinedOperator( @@ -781,24 +785,24 @@ } void CheckHelper::CheckDerivedType( - const Symbol &symbol, const DerivedTypeDetails &details) { - const Scope *scope{symbol.scope()}; + const Symbol &derivedType, const DerivedTypeDetails &details) { + const Scope *scope{derivedType.scope()}; if (!scope) { CHECK(details.isForwardReferenced()); return; } - CHECK(scope->symbol() == &symbol); + CHECK(scope->symbol() == &derivedType); CHECK(scope->IsDerivedType()); - if (symbol.attrs().test(Attr::ABSTRACT) && // C734 - (symbol.attrs().test(Attr::BIND_C) || details.sequence())) { + if (derivedType.attrs().test(Attr::ABSTRACT) && // C734 + (derivedType.attrs().test(Attr::BIND_C) || details.sequence())) { messages_.Say("An ABSTRACT derived type must be extensible"_err_en_US); } - if (const DeclTypeSpec * parent{FindParentTypeSpec(symbol)}) { + if (const DeclTypeSpec * parent{FindParentTypeSpec(derivedType)}) { const DerivedTypeSpec *parentDerived{parent->AsDerived()}; if (!IsExtensibleType(parentDerived)) { // C705 messages_.Say("The parent type is not extensible"_err_en_US); } - if (!symbol.attrs().test(Attr::ABSTRACT) && parentDerived && + if (!derivedType.attrs().test(Attr::ABSTRACT) && parentDerived && parentDerived->typeSymbol().attrs().test(Attr::ABSTRACT)) { ScopeComponentIterator components{*parentDerived}; for (const Symbol &component : components) { @@ -811,7 +815,7 @@ } } } - DerivedTypeSpec derived{symbol.name(), symbol}; + DerivedTypeSpec derived{derivedType.name(), derivedType}; derived.set_scope(*scope); if (FindCoarrayUltimateComponent(derived) && // C736 !(parentDerived && FindCoarrayUltimateComponent(*parentDerived))) { @@ -819,7 +823,7 @@ "Type '%s' has a coarray ultimate component so the type at the base " "of its type extension chain ('%s') must be a type that has a " "coarray ultimate component"_err_en_US, - symbol.name(), scope->GetDerivedTypeBase().GetSymbol()->name()); + derivedType.name(), scope->GetDerivedTypeBase().GetSymbol()->name()); } if (FindEventOrLockPotentialComponent(derived) && // C737 !(FindEventOrLockPotentialComponent(*parentDerived) || @@ -829,13 +833,154 @@ "at the base of its type extension chain ('%s') must either have an " "EVENT_TYPE or LOCK_TYPE component, or be EVENT_TYPE or " "LOCK_TYPE"_err_en_US, - symbol.name(), scope->GetDerivedTypeBase().GetSymbol()->name()); + derivedType.name(), scope->GetDerivedTypeBase().GetSymbol()->name()); } } - if (HasIntrinsicTypeName(symbol)) { // C729 + if (HasIntrinsicTypeName(derivedType)) { // C729 messages_.Say("A derived type name cannot be the name of an intrinsic" " type"_err_en_US); } + std::map previous; + for (const auto &pair : details.finals()) { + SourceName source{pair.first}; + const Symbol &ref{*pair.second}; + if (CheckFinal(ref, source, derivedType) && + std::all_of(previous.begin(), previous.end(), + [&](std::pair prev) { + return CheckDistinguishableFinals( + ref, source, *prev.second, prev.first, derivedType); + })) { + previous.emplace(source, ref); + } + } +} + +// C786 +bool CheckHelper::CheckFinal( + const Symbol &subroutine, SourceName finalName, const Symbol &derivedType) { + if (!IsModuleProcedure(subroutine)) { + SayWithDeclaration(subroutine, finalName, + "FINAL subroutine '%s' of derived type '%s' must be a module procedure"_err_en_US, + subroutine.name(), derivedType.name()); + return false; + } + const Procedure *proc{Characterize(subroutine)}; + if (!proc) { + return false; // error recovery + } + if (!proc->IsSubroutine()) { + SayWithDeclaration(subroutine, finalName, + "FINAL subroutine '%s' of derived type '%s' must be a subroutine"_err_en_US, + subroutine.name(), derivedType.name()); + return false; + } + if (proc->dummyArguments.size() != 1) { + SayWithDeclaration(subroutine, finalName, + "FINAL subroutine '%s' of derived type '%s' must have a single dummy argument"_err_en_US, + subroutine.name(), derivedType.name()); + return false; + } + const auto &arg{proc->dummyArguments[0]}; + const Symbol *errSym{&subroutine}; + if (const auto *details{subroutine.detailsIf()}) { + if (!details->dummyArgs().empty()) { + if (const Symbol * argSym{details->dummyArgs()[0]}) { + errSym = argSym; + } + } + } + const auto *ddo{std::get_if(&arg.u)}; + if (!ddo) { + SayWithDeclaration(subroutine, finalName, + "FINAL subroutine '%s' of derived type '%s' must have a single dummy argument that is a data object"_err_en_US, + subroutine.name(), derivedType.name()); + return false; + } + bool ok{true}; + if (arg.IsOptional()) { + SayWithDeclaration(*errSym, finalName, + "FINAL subroutine '%s' of derived type '%s' must not have an OPTIONAL dummy argument"_err_en_US, + subroutine.name(), derivedType.name()); + ok = false; + } + if (ddo->attrs.test(DummyDataObject::Attr::Allocatable)) { + SayWithDeclaration(*errSym, finalName, + "FINAL subroutine '%s' of derived type '%s' must not have an ALLOCATABLE dummy argument"_err_en_US, + subroutine.name(), derivedType.name()); + ok = false; + } + if (ddo->attrs.test(DummyDataObject::Attr::Pointer)) { + SayWithDeclaration(*errSym, finalName, + "FINAL subroutine '%s' of derived type '%s' must not have a POINTER dummy argument"_err_en_US, + subroutine.name(), derivedType.name()); + ok = false; + } + if (ddo->intent == common::Intent::Out) { + SayWithDeclaration(*errSym, finalName, + "FINAL subroutine '%s' of derived type '%s' must not have a dummy argument with INTENT(OUT)"_err_en_US, + subroutine.name(), derivedType.name()); + ok = false; + } + if (ddo->attrs.test(DummyDataObject::Attr::Value)) { + SayWithDeclaration(*errSym, finalName, + "FINAL subroutine '%s' of derived type '%s' must not have a dummy argument with the VALUE attribute"_err_en_US, + subroutine.name(), derivedType.name()); + ok = false; + } + if (ddo->type.corank() > 0) { + SayWithDeclaration(*errSym, finalName, + "FINAL subroutine '%s' of derived type '%s' must not have a coarray dummy argument"_err_en_US, + subroutine.name(), derivedType.name()); + ok = false; + } + if (ddo->type.type().IsPolymorphic()) { + SayWithDeclaration(*errSym, finalName, + "FINAL subroutine '%s' of derived type '%s' must not have a polymorphic dummy argument"_err_en_US, + subroutine.name(), derivedType.name()); + ok = false; + } else if (ddo->type.type().category() != TypeCategory::Derived || + &ddo->type.type().GetDerivedTypeSpec().typeSymbol() != &derivedType) { + SayWithDeclaration(*errSym, finalName, + "FINAL subroutine '%s' of derived type '%s' must have a TYPE(%s) dummy argument"_err_en_US, + subroutine.name(), derivedType.name(), derivedType.name()); + ok = false; + } else { // check that all LEN type parameters are assumed + for (auto ref : OrderParameterDeclarations(derivedType)) { + if (const auto *paramDetails{ref->detailsIf()}) { + if (paramDetails->attr() == common::TypeParamAttr::Len) { + const auto *value{ + ddo->type.type().GetDerivedTypeSpec().FindParameter(ref->name())}; + if (!value || !value->isAssumed()) { + SayWithDeclaration(*errSym, finalName, + "FINAL subroutine '%s' of derived type '%s' must have a dummy argument with an assumed LEN type parameter '%s=*'"_err_en_US, + subroutine.name(), derivedType.name(), ref->name()); + ok = false; + } + } + } + } + } + return ok; +} + +bool CheckHelper::CheckDistinguishableFinals(const Symbol &f1, + SourceName f1Name, const Symbol &f2, SourceName f2Name, + const Symbol &derivedType) { + const Procedure *p1{Characterize(f1)}; + const Procedure *p2{Characterize(f2)}; + if (p1 && p2) { + if (characteristics::Distinguishable(*p1, *p2)) { + return true; + } + if (auto *msg{messages_.Say(f1Name, + "FINAL subroutines '%s' and '%s' of derived type '%s' cannot be distinguished by rank or KIND type parameter value"_err_en_US, + f1Name, f2Name, derivedType.name())}) { + msg->Attach(f2Name, "FINAL declaration of '%s'"_en_US, f2.name()) + .Attach(f1.name(), "Definition of '%s'"_en_US, f1Name) + .Attach(f2.name(), "Definition of '%s'"_en_US, f2Name); + } + } + return false; } void CheckHelper::CheckHostAssoc( diff --git a/flang/lib/Semantics/mod-file.h b/flang/lib/Semantics/mod-file.h --- a/flang/lib/Semantics/mod-file.h +++ b/flang/lib/Semantics/mod-file.h @@ -53,7 +53,8 @@ void WriteOne(const Scope &); void Write(const Symbol &); std::string GetAsString(const Symbol &); - void PutSymbols(const Scope &); + // Returns true if a derived type with bindings and "contains" was emitted + bool PutSymbols(const Scope &); void PutSymbol(llvm::raw_ostream &, const Symbol &); void PutDerivedType(const Symbol &); void PutSubprogram(const Symbol &); diff --git a/flang/lib/Semantics/mod-file.cpp b/flang/lib/Semantics/mod-file.cpp --- a/flang/lib/Semantics/mod-file.cpp +++ b/flang/lib/Semantics/mod-file.cpp @@ -177,7 +177,7 @@ } // Put out the visible symbols from scope. -void ModFileWriter::PutSymbols(const Scope &scope) { +bool ModFileWriter::PutSymbols(const Scope &scope) { std::string buf; llvm::raw_string_ostream typeBindings{ buf}; // stuff after CONTAINS in derived type @@ -187,6 +187,9 @@ if (auto str{typeBindings.str()}; !str.empty()) { CHECK(scope.IsDerivedType()); decls_ << "contains\n" << str; + return true; + } else { + return false; } } @@ -257,9 +260,6 @@ decls_ << "::/" << symbol.name() << "/\n"; } }, - [&](const FinalProcDetails &) { - typeBindings << "final::" << symbol.name() << '\n'; - }, [](const HostAssocDetails &) {}, [](const MiscDetails &) {}, [&](const auto &) { PutEntity(decls_, symbol); }, @@ -287,7 +287,17 @@ if (details.sequence()) { decls_ << "sequence\n"; } - PutSymbols(typeScope); + bool contains{PutSymbols(typeScope)}; + if (!details.finals().empty()) { + const char *sep{contains ? "final::" : "contains\nfinal::"}; + for (const auto &pair : details.finals()) { + decls_ << sep << pair.second->name(); + sep = ","; + } + if (*sep == ',') { + decls_ << '\n'; + } + } decls_ << "end type\n"; } diff --git a/flang/lib/Semantics/pointer-assignment.cpp b/flang/lib/Semantics/pointer-assignment.cpp --- a/flang/lib/Semantics/pointer-assignment.cpp +++ b/flang/lib/Semantics/pointer-assignment.cpp @@ -219,7 +219,7 @@ " derived type when target is unlimited polymorphic"_err_en_US; } } else { - if (!lhsType_->type().IsTypeCompatibleWith(rhsType->type())) { + if (!lhsType_->type().IsTkCompatibleWith(rhsType->type())) { msg = MessageFormattedText{ "Target type %s is not compatible with pointer type %s"_err_en_US, rhsType->type().AsFortran(), lhsType_->type().AsFortran()}; diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp --- a/flang/lib/Semantics/resolve-names.cpp +++ b/flang/lib/Semantics/resolve-names.cpp @@ -4028,8 +4028,22 @@ } void DeclarationVisitor::Post(const parser::FinalProcedureStmt &x) { - for (auto &name : x.v) { - MakeTypeSymbol(name, FinalProcDetails{}); + if (currScope().IsDerivedType() && currScope().symbol()) { + if (auto *details{currScope().symbol()->detailsIf()}) { + for (const auto &subrName : x.v) { + if (const auto *name{ResolveName(subrName)}) { + auto pair{ + details->finals().emplace(name->source, DEREF(name->symbol))}; + if (!pair.second) { // C787 + Say(name->source, + "FINAL subroutine '%s' already appeared in this derived type"_err_en_US, + name->source) + .Attach(pair.first->first, + "earlier appearance of this FINAL subroutine"_en_US); + } + } + } + } } } diff --git a/flang/lib/Semantics/symbol.cpp b/flang/lib/Semantics/symbol.cpp --- a/flang/lib/Semantics/symbol.cpp +++ b/flang/lib/Semantics/symbol.cpp @@ -228,7 +228,6 @@ [](const ProcBindingDetails &) { return "ProcBinding"; }, [](const NamelistDetails &) { return "Namelist"; }, [](const CommonBlockDetails &) { return "CommonBlockDetails"; }, - [](const FinalProcDetails &) { return "FinalProc"; }, [](const TypeParamDetails &) { return "TypeParam"; }, [](const MiscDetails &) { return "Misc"; }, [](const AssocEntityDetails &) { return "AssocEntity"; }, @@ -436,7 +435,6 @@ os << ' ' << object->name(); } }, - [&](const FinalProcDetails &) {}, [&](const TypeParamDetails &x) { DumpOptional(os, "type", x.type()); os << ' ' << common::EnumToString(x.attr()); diff --git a/flang/lib/Semantics/tools.cpp b/flang/lib/Semantics/tools.cpp --- a/flang/lib/Semantics/tools.cpp +++ b/flang/lib/Semantics/tools.cpp @@ -637,20 +637,23 @@ } bool IsFinalizable(const DerivedTypeSpec &derived) { - ScopeComponentIterator components{derived}; - return std::find_if(components.begin(), components.end(), - [](const Symbol &x) { return x.has(); }) != - components.end(); + if (!derived.typeSymbol().get().finals().empty()) { + return true; + } + DirectComponentIterator components{derived}; + return bool{std::find_if(components.begin(), components.end(), + [](const Symbol &component) { return IsFinalizable(component); })}; } -// TODO The following function returns true for all types with FINAL procedures -// This is because we don't yet fill in the data for FinalProcDetails bool HasImpureFinal(const DerivedTypeSpec &derived) { - ScopeComponentIterator components{derived}; - return std::find_if( - components.begin(), components.end(), [](const Symbol &x) { - return x.has() && !x.attrs().test(Attr::PURE); - }) != components.end(); + if (const auto *details{ + derived.typeSymbol().detailsIf()}) { + const auto &finals{details->finals()}; + return std::any_of(finals.begin(), finals.end(), + [](const auto &x) { return !x.second->attrs().test(Attr::PURE); }); + } else { + return false; + } } bool IsCoarray(const Symbol &symbol) { return symbol.Corank() > 0; } @@ -701,10 +704,12 @@ // C722 and C723: For a function to be assumed length, it must be external and // of CHARACTER type bool IsExternal(const Symbol &symbol) { - return (symbol.has() && symbol.owner().IsGlobal()) || - symbol.attrs().test(Attr::EXTERNAL); + return ClassifyProcedure(symbol) == ProcedureDefinitionClass::External; } +bool IsModuleProcedure(const Symbol &symbol) { + return ClassifyProcedure(symbol) == ProcedureDefinitionClass::Module; +} const Symbol *IsExternalInPureContext( const Symbol &symbol, const Scope &scope) { if (const auto *pureProc{FindPureProcedureContaining(scope)}) { @@ -1005,6 +1010,39 @@ return nullptr; } +ProcedureDefinitionClass ClassifyProcedure(const Symbol &symbol) { // 15.2.2 + const Symbol &ultimate{symbol.GetUltimate()}; + if (ultimate.attrs().test(Attr::INTRINSIC)) { + return ProcedureDefinitionClass::Intrinsic; + } else if (ultimate.attrs().test(Attr::EXTERNAL)) { + return ProcedureDefinitionClass::External; + } else if (const auto *procDetails{ultimate.detailsIf()}) { + if (procDetails->isDummy()) { + return ProcedureDefinitionClass::Dummy; + } else if (IsPointer(ultimate)) { + return ProcedureDefinitionClass::Pointer; + } + } else if (const Symbol * subp{FindSubprogram(symbol)}) { + if (const auto *subpDetails{subp->detailsIf()}) { + if (subpDetails->stmtFunction()) { + return ProcedureDefinitionClass::StatementFunction; + } + } + switch (ultimate.owner().kind()) { + case Scope::Kind::Global: + return ProcedureDefinitionClass::External; + case Scope::Kind::Module: + return ProcedureDefinitionClass::Module; + case Scope::Kind::MainProgram: + case Scope::Kind::Subprogram: + return ProcedureDefinitionClass::Internal; + default: + break; + } + } + return ProcedureDefinitionClass::None; +} + // ComponentIterator implementation template diff --git a/flang/runtime/descriptor-io.h b/flang/runtime/descriptor-io.h --- a/flang/runtime/descriptor-io.h +++ b/flang/runtime/descriptor-io.h @@ -159,13 +159,13 @@ } } } + if (!descriptor.IncrementSubscripts(subscripts) && j + 1 < numElements) { + io.GetIoErrorHandler().Crash( + "FormattedCharacterIO: subscripts out of bounds"); + } } else { return false; } - if (!descriptor.IncrementSubscripts(subscripts) && j + 1 < numElements) { - io.GetIoErrorHandler().Crash( - "FormattedCharacterIO: subscripts out of bounds"); - } } return true; } @@ -198,13 +198,13 @@ } } } + if (!descriptor.IncrementSubscripts(subscripts) && j + 1 < numElements) { + io.GetIoErrorHandler().Crash( + "FormattedLogicalIO: subscripts out of bounds"); + } } else { return false; } - if (!descriptor.IncrementSubscripts(subscripts) && j + 1 < numElements) { - io.GetIoErrorHandler().Crash( - "FormattedLogicalIO: subscripts out of bounds"); - } } return true; } diff --git a/flang/test/Semantics/call03.f90 b/flang/test/Semantics/call03.f90 --- a/flang/test/Semantics/call03.f90 +++ b/flang/test/Semantics/call03.f90 @@ -29,7 +29,7 @@ class(tbp), intent(in) :: this end subroutine subroutine subr02(this) - class(final), intent(in) :: this + type(final), intent(inout) :: this end subroutine subroutine poly(x) @@ -113,7 +113,7 @@ subroutine test05 ! 15.5.2.4(2) type(final) :: x - !ERROR: Actual argument associated with TYPE(*) dummy argument 'x=' may not have FINAL subroutine 'subr02' + !ERROR: Actual argument associated with TYPE(*) dummy argument 'x=' may not have derived type 'final' with FINAL subroutine 'subr02' call typestar(x) end subroutine diff --git a/flang/test/Semantics/call05.f90 b/flang/test/Semantics/call05.f90 --- a/flang/test/Semantics/call05.f90 +++ b/flang/test/Semantics/call05.f90 @@ -89,9 +89,9 @@ call spp(up) !ERROR: Actual argument type 'CLASS(*)' is not compatible with dummy argument type 't' call spa(ua) - !ERROR: POINTER or ALLOCATABLE dummy and actual arguments must have the same declared type + !ERROR: POINTER or ALLOCATABLE dummy and actual arguments must have the same declared type and kind call spp(pp2) - !ERROR: POINTER or ALLOCATABLE dummy and actual arguments must have the same declared type + !ERROR: POINTER or ALLOCATABLE dummy and actual arguments must have the same declared type and kind call spa(pa2) !ERROR: Rank of dummy argument is 1, but actual argument has rank 2 call smp(mpmat) diff --git a/flang/test/Semantics/final01.f90 b/flang/test/Semantics/final01.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/final01.f90 @@ -0,0 +1,119 @@ +! RUN: %S/test_errors.sh %s %t %f18 +! Test FINAL subroutine constraints C786-C789 +module m1 + external :: external + intrinsic :: sin + real :: object + procedure(valid), pointer :: pointer + type :: parent(kind1, len1) + integer, kind :: kind1 = 1 + integer, len :: len1 = 1 + end type + type, extends(parent) :: child(kind2, len2) + integer, kind :: kind2 = 2 + integer, len :: len2 = 2 + contains + final :: valid +!ERROR: FINAL subroutine 'external' of derived type 'child' must be a module procedure +!ERROR: FINAL subroutine 'sin' of derived type 'child' must be a module procedure +!ERROR: FINAL subroutine 'object' of derived type 'child' must be a module procedure +!ERROR: FINAL subroutine 'pointer' of derived type 'child' must be a module procedure +!ERROR: FINAL subroutine 'func' of derived type 'child' must be a subroutine + final :: external, sin, object, pointer, func +!ERROR: FINAL subroutine 's01' of derived type 'child' must have a single dummy argument that is a data object +!ERROR: FINAL subroutine 's02' of derived type 'child' must have a single dummy argument that is a data object +!ERROR: FINAL subroutine 's03' of derived type 'child' must not have a dummy argument with INTENT(OUT) +!ERROR: FINAL subroutine 's04' of derived type 'child' must not have a dummy argument with the VALUE attribute +!ERROR: FINAL subroutine 's05' of derived type 'child' must not have a POINTER dummy argument +!ERROR: FINAL subroutine 's06' of derived type 'child' must not have an ALLOCATABLE dummy argument +!ERROR: FINAL subroutine 's07' of derived type 'child' must not have a coarray dummy argument +!ERROR: FINAL subroutine 's08' of derived type 'child' must not have a polymorphic dummy argument +!ERROR: FINAL subroutine 's09' of derived type 'child' must not have a polymorphic dummy argument +!ERROR: FINAL subroutine 's10' of derived type 'child' must not have an OPTIONAL dummy argument + final :: s01, s02, s03, s04, s05, s06, s07, s08, s09, s10 +!ERROR: FINAL subroutine 's11' of derived type 'child' must have a single dummy argument +!ERROR: FINAL subroutine 's12' of derived type 'child' must have a single dummy argument +!ERROR: FINAL subroutine 's13' of derived type 'child' must have a dummy argument with an assumed LEN type parameter 'len1=*' +!ERROR: FINAL subroutine 's13' of derived type 'child' must have a dummy argument with an assumed LEN type parameter 'len2=*' +!ERROR: FINAL subroutine 's14' of derived type 'child' must have a dummy argument with an assumed LEN type parameter 'len2=*' +!ERROR: FINAL subroutine 's15' of derived type 'child' must have a dummy argument with an assumed LEN type parameter 'len1=*' +!ERROR: FINAL subroutine 's16' of derived type 'child' must not have a polymorphic dummy argument +!ERROR: FINAL subroutine 's17' of derived type 'child' must have a TYPE(child) dummy argument + final :: s11, s12, s13, s14, s15, s16, s17 +!ERROR: FINAL subroutine 'valid' already appeared in this derived type + final :: valid +!ERROR: FINAL subroutines 'valid2' and 'valid' of derived type 'child' cannot be distinguished by rank or KIND type parameter value + final :: valid2 + end type + contains + subroutine valid(x) + type(child(len1=*, len2=*)), intent(inout) :: x + end subroutine + subroutine valid2(x) + type(child(len1=*, len2=*)), intent(inout) :: x + end subroutine + real function func(x) + type(child(len1=*, len2=*)), intent(inout) :: x + func = 0. + end function + subroutine s01(*) + end subroutine + subroutine s02(x) + external :: x + end subroutine + subroutine s03(x) + type(child(kind1=3, len1=*, len2=*)), intent(out) :: x + end subroutine + subroutine s04(x) + type(child(kind1=4, len1=*, len2=*)), value :: x + end subroutine + subroutine s05(x) + type(child(kind1=5, len1=*, len2=*)), pointer :: x + end subroutine + subroutine s06(x) + type(child(kind1=6, len1=*, len2=*)), allocatable :: x + end subroutine + subroutine s07(x) + type(child(kind1=7, len1=*, len2=*)) :: x[*] + end subroutine + subroutine s08(x) + class(child(kind1=8, len1=*, len2=*)) :: x + end subroutine + subroutine s09(x) + class(*) :: x + end subroutine + subroutine s10(x) + type(child(kind1=10, len1=*, len2=*)), optional :: x + end subroutine + subroutine s11(x, y) + type(child(kind1=11, len1=*, len2=*)) :: x, y + end subroutine + subroutine s12 + end subroutine + subroutine s13(x) + type(child(kind1=13)) :: x + end subroutine + subroutine s14(x) + type(child(kind1=14, len1=*,len2=2)) :: x + end subroutine + subroutine s15(x) + type(child(kind1=15, len2=*)) :: x + end subroutine + subroutine s16(x) + type(*) :: x + end subroutine + subroutine s17(x) + type(parent(kind1=17, len1=*)) :: x + end subroutine + subroutine nested + type :: t + contains +!ERROR: FINAL subroutine 'internal' of derived type 't' must be a module procedure + final :: internal + end type + contains + subroutine internal(x) + type(t), intent(inout) :: x + end subroutine + end subroutine +end module diff --git a/flang/test/Semantics/modfile10.f90 b/flang/test/Semantics/modfile10.f90 --- a/flang/test/Semantics/modfile10.f90 +++ b/flang/test/Semantics/modfile10.f90 @@ -64,8 +64,8 @@ ! type::t2 ! integer(4)::x ! contains -! final::c ! procedure,non_overridable,private::d +! final::c ! end type ! type,abstract::t2a ! contains diff --git a/flang/test/Semantics/resolve32.f90 b/flang/test/Semantics/resolve32.f90 --- a/flang/test/Semantics/resolve32.f90 +++ b/flang/test/Semantics/resolve32.f90 @@ -57,7 +57,7 @@ contains procedure, nopass :: b => s final :: f - !ERROR: Type parameter, component, or procedure binding 'i' already defined in this type + !ERROR: FINAL subroutine 'i' of derived type 't2' must be a module procedure final :: i end type type t3 diff --git a/flang/test/Semantics/resolve55.f90 b/flang/test/Semantics/resolve55.f90 --- a/flang/test/Semantics/resolve55.f90 +++ b/flang/test/Semantics/resolve55.f90 @@ -36,25 +36,24 @@ end do end subroutine s4 -subroutine s5() +module m ! Cannot have a variable of a finalizable type in a locality spec type t1 integer :: i contains final :: f end type t1 - - type(t1) :: var - -!ERROR: Finalizable variable 'var' not allowed in a locality-spec - do concurrent(i=1:5) local(var) - end do - -contains + contains + subroutine s5() + type(t1) :: var + !ERROR: Finalizable variable 'var' not allowed in a locality-spec + do concurrent(i=1:5) local(var) + end do + end subroutine s5 subroutine f(x) type(t1) :: x end subroutine f -end subroutine s5 +end module m subroutine s6 ! Cannot have a nonpointer polymorphic dummy argument in a locality spec diff --git a/flang/unittests/Runtime/hello.cpp b/flang/unittests/Runtime/hello.cpp --- a/flang/unittests/Runtime/hello.cpp +++ b/flang/unittests/Runtime/hello.cpp @@ -118,41 +118,6 @@ } } -static void descrOutputTest() { - char buffer[9]; - // Formatted - const char *format{"(2A4)"}; - auto cookie{IONAME(BeginInternalFormattedOutput)( - buffer, sizeof buffer, format, std::strlen(format))}; - StaticDescriptor<1> staticDescriptor; - Descriptor &desc{staticDescriptor.descriptor()}; - SubscriptValue extent[]{2}; - char data[2][4]; - std::memcpy(data[0], "ABCD", 4); - std::memcpy(data[1], "EFGH", 4); - desc.Establish(TypeCode{CFI_type_char}, sizeof data[0], &data, 1, extent); - desc.Dump(); - desc.Check(); - IONAME(OutputDescriptor)(cookie, desc); - if (auto status{IONAME(EndIoStatement)(cookie)}) { - Fail() << "descrOutputTest: '" << format << "' failed, status " - << static_cast(status) << '\n'; - } else { - test("descrOutputTest(formatted)", "ABCDEFGH ", - std::string{buffer, sizeof buffer}); - } - // List-directed - cookie = IONAME(BeginInternalListOutput)(buffer, sizeof buffer); - IONAME(OutputDescriptor)(cookie, desc); - if (auto status{IONAME(EndIoStatement)(cookie)}) { - Fail() << "descrOutputTest: list-directed failed, status " - << static_cast(status) << '\n'; - } else { - test("descrOutputTest(list)", " ABCDEFGH", - std::string{buffer, sizeof buffer}); - } -} - static void realTest(const char *format, double x, const char *expect) { char buffer[800]; auto cookie{IONAME(BeginInternalFormattedOutput)( @@ -520,7 +485,6 @@ realInTest("(DC,F18.0)", " 12,5", 0x4029000000000000); listInputTest(); - descrOutputTest(); return EndTests(); } diff --git a/libcxx/lib/abi/CMakeLists.txt b/libcxx/lib/abi/CMakeLists.txt --- a/libcxx/lib/abi/CMakeLists.txt +++ b/libcxx/lib/abi/CMakeLists.txt @@ -22,8 +22,7 @@ AND ("${LIBCXX_CXX_ABI_LIBNAME}" STREQUAL "libcxxabi" OR (APPLE AND "${LIBCXX_CXX_ABI_LIBNAME}" STREQUAL "default")) AND NOT LIBCXX_ABI_UNSTABLE - AND LIBCXX_ENABLE_EXCEPTIONS - AND LIBCXX_ENABLE_NEW_DELETE_DEFINITIONS) + AND LIBCXX_ENABLE_EXCEPTIONS) add_custom_target(check-cxx-abilist ${SYMDIFF_EXE} --only-stdlib-symbols --strict ${ABILIST_FILE} $ diff --git a/lldb/include/lldb/Core/StructuredDataImpl.h b/lldb/include/lldb/Core/StructuredDataImpl.h --- a/lldb/include/lldb/Core/StructuredDataImpl.h +++ b/lldb/include/lldb/Core/StructuredDataImpl.h @@ -68,18 +68,14 @@ return error; } - // Grab the plugin - lldb::StructuredDataPluginSP plugin_sp = m_plugin_wp.lock(); - - // If there's no plugin, call underlying data's dump method: + // Grab the plugin. + auto plugin_sp = lldb::StructuredDataPluginSP(m_plugin_wp); if (!plugin_sp) { - if (!m_data_sp) { - error.SetErrorString("No data to describe."); - return error; - } - m_data_sp->Dump(stream, true); + error.SetErrorString("Cannot pretty print structured data: " + "plugin doesn't exist."); return error; } + // Get the data's description. return plugin_sp->GetDescription(m_data_sp, stream); } diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py @@ -318,13 +318,7 @@ raise _ConnectionRefused() # Got EOF, connection dropped. def create_socket(self): - try: - sock = socket.socket(family=socket.AF_INET) - except OSError as e: - if e.errno != errno.EAFNOSUPPORT: - raise - sock = socket.socket(family=socket.AF_INET6) - + sock = socket.socket() logger = self.logger triple = self.dbg.GetSelectedPlatform().GetTriple() @@ -385,7 +379,7 @@ ["*:{}".format(self.port)] else: commandline_args = self.debug_monitor_extra_args + \ - ["localhost:{}".format(self.port)] + ["127.0.0.1:{}".format(self.port)] if attach_pid: commandline_args += ["--attach=%d" % attach_pid] diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py @@ -728,26 +728,24 @@ def request_setBreakpoints(self, file_path, line_array, condition=None, hitCondition=None): (dir, base) = os.path.split(file_path) + breakpoints = [] + for line in line_array: + bp = {'line': line} + if condition is not None: + bp['condition'] = condition + if hitCondition is not None: + bp['hitCondition'] = hitCondition + breakpoints.append(bp) source_dict = { 'name': base, 'path': file_path } args_dict = { 'source': source_dict, + 'breakpoints': breakpoints, + 'lines': '%s' % (line_array), 'sourceModified': False, } - if line_array is not None: - args_dict['lines'] = '%s' % line_array - breakpoints = [] - for line in line_array: - bp = {'line': line} - if condition is not None: - bp['condition'] = condition - if hitCondition is not None: - bp['hitCondition'] = hitCondition - breakpoints.append(bp) - args_dict['breakpoints'] = breakpoints - command_dict = { 'command': 'setBreakpoints', 'type': 'request', diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -1234,7 +1234,7 @@ const int backlog = 5; TCPSocket listen_socket(true, child_processes_inherit); if (llvm::Error error = - listen_socket.Listen("localhost:0", backlog).ToError()) + listen_socket.Listen("127.0.0.1:0", backlog).ToError()) return error; Socket *accept_socket; @@ -1243,7 +1243,7 @@ llvm::SmallString<32> remote_addr; llvm::raw_svector_ostream(remote_addr) - << "connect://localhost:" << listen_socket.GetLocalPortNumber(); + << "connect://127.0.0.1:" << listen_socket.GetLocalPortNumber(); std::unique_ptr conn_up( new ConnectionFileDescriptor()); diff --git a/lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py b/lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py --- a/lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py +++ b/lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py @@ -1,4 +1,3 @@ -import errno import os import os.path import threading @@ -318,20 +317,12 @@ def __init__(self, port = 0): self.responder = MockGDBServerResponder() self.port = port - try: - self._socket = socket.socket(family=socket.AF_INET) - except OSError as e: - if e.errno != errno.EAFNOSUPPORT: - raise - self._socket = socket.socket(family=socket.AF_INET6) + self._socket = socket.socket() def start(self): # Block until the socket is up, so self.port is available immediately. # Then start a thread that waits for a client connection. - if self._socket.family == socket.AF_INET: - addr = ("127.0.0.1", self.port) - elif self._socket.family == socket.AF_INET6: - addr = ("::1", self.port) + addr = ("127.0.0.1", self.port) self._socket.bind(addr) self.port = self._socket.getsockname()[1] self._socket.listen(1) diff --git a/lldb/test/API/python_api/sbstructureddata/TestStructuredDataAPI.py b/lldb/test/API/python_api/sbstructureddata/TestStructuredDataAPI.py --- a/lldb/test/API/python_api/sbstructureddata/TestStructuredDataAPI.py +++ b/lldb/test/API/python_api/sbstructureddata/TestStructuredDataAPI.py @@ -35,13 +35,6 @@ # Tests for invalid data type self.invalid_struct_test(example) - # Test that GetDescription works: - s.Clear() - error = example.GetDescription(s) - self.assertTrue(error.Success(), "GetDescription works") - if not "key_float" in s.GetData(): - self.fail("FAILED: could not find key_float in description output") - dict_struct = lldb.SBStructuredData() dict_struct = example.GetValueForKey("key_dict") diff --git a/lldb/test/API/tools/lldb-server/commandline/TestStubReverseConnect.py b/lldb/test/API/tools/lldb-server/commandline/TestStubReverseConnect.py --- a/lldb/test/API/tools/lldb-server/commandline/TestStubReverseConnect.py +++ b/lldb/test/API/tools/lldb-server/commandline/TestStubReverseConnect.py @@ -1,6 +1,5 @@ from __future__ import print_function -import errno import gdbremote_testcase import lldbgdbserverutils import re @@ -25,20 +24,11 @@ self.listener_port = self.listener_socket.getsockname()[1] def create_listener_socket(self): - try: - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - except OSError as e: - if e.errno != errno.EAFNOSUPPORT: - raise - sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.assertIsNotNone(sock) sock.settimeout(self.DEFAULT_TIMEOUT) - if sock.family == socket.AF_INET: - bind_addr = ("127.0.0.1", 0) - elif sock.family == socket.AF_INET6: - bind_addr = ("::1", 0) - sock.bind(bind_addr) + sock.bind(("127.0.0.1", 0)) sock.listen(1) def tear_down_listener(): diff --git a/lldb/test/API/tools/lldb-vscode/breakpoint/TestVSCode_setBreakpoints.py b/lldb/test/API/tools/lldb-vscode/breakpoint/TestVSCode_setBreakpoints.py --- a/lldb/test/API/tools/lldb-vscode/breakpoint/TestVSCode_setBreakpoints.py +++ b/lldb/test/API/tools/lldb-vscode/breakpoint/TestVSCode_setBreakpoints.py @@ -221,48 +221,6 @@ @skipIfWindows @skipIfRemote - def test_clear_breakpoints_unset_breakpoints(self): - '''Test clearing breakpoints like test_set_and_clear, but clear - breakpoints by omitting the breakpoints array instead of sending an - empty one.''' - lines = [line_number('main.cpp', 'break 12'), - line_number('main.cpp', 'break 13')] - - # Visual Studio Code Debug Adaptors have no way to specify the file - # without launching or attaching to a process, so we must start a - # process in order to be able to set breakpoints. - program = self.getBuildArtifact("a.out") - self.build_and_launch(program) - - # Set one breakpoint and verify that it got set correctly. - response = self.vscode.request_setBreakpoints(self.main_path, lines) - line_to_id = {} - breakpoints = response['body']['breakpoints'] - self.assertEquals(len(breakpoints), len(lines), - "expect %u source breakpoints" % (len(lines))) - for (breakpoint, index) in zip(breakpoints, range(len(lines))): - line = breakpoint['line'] - self.assertTrue(line, lines[index]) - # Store the "id" of the breakpoint that was set for later - line_to_id[line] = breakpoint['id'] - self.assertTrue(line in lines, "line expected in lines array") - self.assertTrue(breakpoint['verified'], - "expect breakpoint verified") - - # Now clear all breakpoints for the source file by not setting the - # lines array. - lines = None - response = self.vscode.request_setBreakpoints(self.main_path, lines) - breakpoints = response['body']['breakpoints'] - self.assertEquals(len(breakpoints), 0, "expect no source breakpoints") - - # Verify with the target that all breakpoints have been cleared. - response = self.vscode.request_testGetTargetBreakpoints() - breakpoints = response['body']['breakpoints'] - self.assertEquals(len(breakpoints), 0, "expect no source breakpoints") - - @skipIfWindows - @skipIfRemote def test_functionality(self): '''Tests hitting breakpoints and the functionality of a single breakpoint, like 'conditions' and 'hitCondition' settings.''' diff --git a/lldb/tools/lldb-server/lldb-gdbserver.cpp b/lldb/tools/lldb-server/lldb-gdbserver.cpp --- a/lldb/tools/lldb-server/lldb-gdbserver.cpp +++ b/lldb/tools/lldb-server/lldb-gdbserver.cpp @@ -267,8 +267,7 @@ final_host_and_port.append("localhost"); final_host_and_port.append(host_and_port); - // Note: use rfind, because the host/port may look like "[::1]:12345". - const std::string::size_type colon_pos = final_host_and_port.rfind(':'); + const std::string::size_type colon_pos = final_host_and_port.find(':'); if (colon_pos != std::string::npos) { connection_host = final_host_and_port.substr(0, colon_pos); connection_port = final_host_and_port.substr(colon_pos + 1); diff --git a/lldb/tools/lldb-vscode/lldb-vscode.cpp b/lldb/tools/lldb-vscode/lldb-vscode.cpp --- a/lldb/tools/lldb-vscode/lldb-vscode.cpp +++ b/lldb/tools/lldb-vscode/lldb-vscode.cpp @@ -1936,32 +1936,27 @@ // Decode the source breakpoint infos for this "setBreakpoints" request SourceBreakpointMap request_bps; - // "breakpoints" may be unset, in which case we treat it the same as being set - // to an empty array. - if (breakpoints) { - for (const auto &bp : *breakpoints) { - auto bp_obj = bp.getAsObject(); - if (bp_obj) { - SourceBreakpoint src_bp(*bp_obj); - request_bps[src_bp.line] = src_bp; - - // We check if this breakpoint already exists to update it - auto existing_source_bps = g_vsc.source_breakpoints.find(path); - if (existing_source_bps != g_vsc.source_breakpoints.end()) { - const auto &existing_bp = - existing_source_bps->second.find(src_bp.line); - if (existing_bp != existing_source_bps->second.end()) { - existing_bp->second.UpdateBreakpoint(src_bp); - AppendBreakpoint(existing_bp->second.bp, response_breakpoints, path, - src_bp.line); - continue; - } + for (const auto &bp : *breakpoints) { + auto bp_obj = bp.getAsObject(); + if (bp_obj) { + SourceBreakpoint src_bp(*bp_obj); + request_bps[src_bp.line] = src_bp; + + // We check if this breakpoint already exists to update it + auto existing_source_bps = g_vsc.source_breakpoints.find(path); + if (existing_source_bps != g_vsc.source_breakpoints.end()) { + const auto &existing_bp = existing_source_bps->second.find(src_bp.line); + if (existing_bp != existing_source_bps->second.end()) { + existing_bp->second.UpdateBreakpoint(src_bp); + AppendBreakpoint(existing_bp->second.bp, response_breakpoints, path, + src_bp.line); + continue; } - // At this point the breakpoint is new - src_bp.SetBreakpoint(path.data()); - AppendBreakpoint(src_bp.bp, response_breakpoints, path, src_bp.line); - g_vsc.source_breakpoints[path][src_bp.line] = std::move(src_bp); } + // At this point the breakpoint is new + src_bp.SetBreakpoint(path.data()); + AppendBreakpoint(src_bp.bp, response_breakpoints, path, src_bp.line); + g_vsc.source_breakpoints[path][src_bp.line] = std::move(src_bp); } } diff --git a/lldb/unittests/Host/SocketTest.cpp b/lldb/unittests/Host/SocketTest.cpp --- a/lldb/unittests/Host/SocketTest.cpp +++ b/lldb/unittests/Host/SocketTest.cpp @@ -14,24 +14,12 @@ using namespace lldb_private; -struct SocketTestParams { - bool is_ipv6; - std::string localhost_ip; -}; - -class SocketTest : public testing::TestWithParam { +class SocketTest : public testing::Test { public: SubsystemRAII subsystems; - -protected: - bool HostSupportsProtocol() const { - if (GetParam().is_ipv6) - return HostSupportsIPv6(); - return HostSupportsIPv4(); - } }; -TEST_P(SocketTest, DecodeHostAndPort) { +TEST_F(SocketTest, DecodeHostAndPort) { std::string host_str; std::string port_str; int32_t port; @@ -98,7 +86,7 @@ } #if LLDB_ENABLE_POSIX -TEST_P(SocketTest, DomainListenConnectAccept) { +TEST_F(SocketTest, DomainListenConnectAccept) { llvm::SmallString<64> Path; std::error_code EC = llvm::sys::fs::createUniqueDirectory("DomainListenConnectAccept", Path); ASSERT_FALSE(EC); @@ -114,22 +102,18 @@ } #endif -TEST_P(SocketTest, TCPListen0ConnectAccept) { - if (!HostSupportsProtocol()) - return; +TEST_F(SocketTest, TCPListen0ConnectAccept) { std::unique_ptr socket_a_up; std::unique_ptr socket_b_up; - CreateTCPConnectedSockets(GetParam().localhost_ip, &socket_a_up, - &socket_b_up); + CreateTCPConnectedSockets("127.0.0.1", &socket_a_up, &socket_b_up); } -TEST_P(SocketTest, TCPGetAddress) { +TEST_F(SocketTest, TCPGetAddress) { std::unique_ptr socket_a_up; std::unique_ptr socket_b_up; - if (!HostSupportsProtocol()) + if (!HostSupportsIPv4()) return; - CreateTCPConnectedSockets(GetParam().localhost_ip, &socket_a_up, - &socket_b_up); + CreateTCPConnectedSockets("127.0.0.1", &socket_a_up, &socket_b_up); EXPECT_EQ(socket_a_up->GetLocalPortNumber(), socket_b_up->GetRemotePortNumber()); @@ -137,16 +121,11 @@ socket_a_up->GetRemotePortNumber()); EXPECT_NE(socket_a_up->GetLocalPortNumber(), socket_b_up->GetLocalPortNumber()); - EXPECT_STREQ(GetParam().localhost_ip.c_str(), - socket_a_up->GetRemoteIPAddress().c_str()); - EXPECT_STREQ(GetParam().localhost_ip.c_str(), - socket_b_up->GetRemoteIPAddress().c_str()); + EXPECT_STREQ("127.0.0.1", socket_a_up->GetRemoteIPAddress().c_str()); + EXPECT_STREQ("127.0.0.1", socket_b_up->GetRemoteIPAddress().c_str()); } -TEST_P(SocketTest, UDPConnect) { - // UDPSocket::Connect() creates sockets with AF_INET (IPv4). - if (!HostSupportsIPv4()) - return; +TEST_F(SocketTest, UDPConnect) { llvm::Expected> socket = UDPSocket::Connect("127.0.0.1:0", /*child_processes_inherit=*/false); @@ -154,9 +133,7 @@ EXPECT_TRUE(socket.get()->IsValid()); } -TEST_P(SocketTest, TCPListen0GetPort) { - if (!HostSupportsIPv4()) - return; +TEST_F(SocketTest, TCPListen0GetPort) { Predicate port_predicate; port_predicate.SetValue(0, eBroadcastNever); llvm::Expected> sock = @@ -166,13 +143,12 @@ EXPECT_NE(sock.get()->GetLocalPortNumber(), 0); } -TEST_P(SocketTest, TCPGetConnectURI) { +TEST_F(SocketTest, TCPGetConnectURI) { std::unique_ptr socket_a_up; std::unique_ptr socket_b_up; - if (!HostSupportsProtocol()) + if (!HostSupportsIPv4()) return; - CreateTCPConnectedSockets(GetParam().localhost_ip, &socket_a_up, - &socket_b_up); + CreateTCPConnectedSockets("127.0.0.1", &socket_a_up, &socket_b_up); llvm::StringRef scheme; llvm::StringRef hostname; @@ -184,8 +160,7 @@ EXPECT_EQ(port, socket_a_up->GetRemotePortNumber()); } -TEST_P(SocketTest, UDPGetConnectURI) { - // UDPSocket::Connect() creates sockets with AF_INET (IPv4). +TEST_F(SocketTest, UDPGetConnectURI) { if (!HostSupportsIPv4()) return; llvm::Expected> socket = @@ -202,7 +177,7 @@ } #if LLDB_ENABLE_POSIX -TEST_P(SocketTest, DomainGetConnectURI) { +TEST_F(SocketTest, DomainGetConnectURI) { llvm::SmallString<64> domain_path; std::error_code EC = llvm::sys::fs::createUniqueDirectory("DomainListenConnectAccept", domain_path); @@ -227,13 +202,3 @@ EXPECT_EQ(path, domain_path); } #endif - -INSTANTIATE_TEST_CASE_P( - SocketTests, SocketTest, - testing::Values(SocketTestParams{/*is_ipv6=*/false, - /*localhost_ip=*/"127.0.0.1"}, - SocketTestParams{/*is_ipv6=*/true, /*localhost_ip=*/"::1"}), - // Prints "SocketTests/SocketTest.DecodeHostAndPort/ipv4" etc. in test logs. - [](const testing::TestParamInfo &info) { - return info.param.is_ipv6 ? "ipv6" : "ipv4"; - }); diff --git a/lldb/unittests/Host/SocketTestUtilities.cpp b/lldb/unittests/Host/SocketTestUtilities.cpp --- a/lldb/unittests/Host/SocketTestUtilities.cpp +++ b/lldb/unittests/Host/SocketTestUtilities.cpp @@ -101,14 +101,13 @@ "Creating a canary {0} TCP socket failed: {1}.", Proto, Err) .str(); - bool HasProtocolError = false; + bool HasAddrNotAvail = false; handleAllErrors(std::move(Err), [&](std::unique_ptr ECErr) { - std::error_code ec = ECErr->convertToErrorCode(); - if (ec == std::make_error_code(std::errc::address_family_not_supported) || - ec == std::make_error_code(std::errc::address_not_available)) - HasProtocolError = true; + if (ECErr->convertToErrorCode() == + std::make_error_code(std::errc::address_not_available)) + HasAddrNotAvail = true; }); - if (HasProtocolError) { + if (HasAddrNotAvail) { GTEST_LOG_(WARNING) << llvm::formatv( "Assuming the host does not support {0}. Skipping test.", Proto) diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h --- a/llvm/include/llvm/CodeGen/AsmPrinter.h +++ b/llvm/include/llvm/CodeGen/AsmPrinter.h @@ -141,11 +141,7 @@ private: MCSymbol *CurrentFnEnd = nullptr; - - /// Map a basic block section ID to the exception symbol associated with that - /// section. Map entries are assigned and looked up via - /// AsmPrinter::getMBBExceptionSym. - DenseMap MBBSectionExceptionSyms; + MCSymbol *CurExceptionSym = nullptr; // The symbol used to represent the start of the current BB section of the // function. This is used to calculate the size of the BB section. @@ -242,10 +238,7 @@ MCSymbol *getFunctionBegin() const { return CurrentFnBegin; } MCSymbol *getFunctionEnd() const { return CurrentFnEnd; } - - // Return the exception symbol associated with the MBB section containing a - // given basic block. - MCSymbol *getMBBExceptionSym(const MachineBasicBlock &MBB); + MCSymbol *getCurExceptionSym(); /// Return information about object file lowering. const TargetLoweringObjectFile &getObjFileLowering() const; diff --git a/llvm/include/llvm/CodeGen/AsmPrinterHandler.h b/llvm/include/llvm/CodeGen/AsmPrinterHandler.h --- a/llvm/include/llvm/CodeGen/AsmPrinterHandler.h +++ b/llvm/include/llvm/CodeGen/AsmPrinterHandler.h @@ -24,8 +24,7 @@ class MachineInstr; class MCSymbol; -typedef MCSymbol *ExceptionSymbolProvider(AsmPrinter *Asm, - const MachineBasicBlock *MBB); +typedef MCSymbol *ExceptionSymbolProvider(AsmPrinter *Asm); /// Collects and handles AsmPrinter objects required to build debug /// or EH information. diff --git a/llvm/include/llvm/Target/TargetMachine.h b/llvm/include/llvm/Target/TargetMachine.h --- a/llvm/include/llvm/Target/TargetMachine.h +++ b/llvm/include/llvm/Target/TargetMachine.h @@ -34,7 +34,6 @@ class MCSubtargetInfo; class MCSymbol; class raw_pwrite_stream; -class PassBuilder; class PassManagerBuilder; struct PerFunctionMIParsingState; class SMDiagnostic; @@ -295,11 +294,6 @@ /// PassManagerBuilder::addExtension. virtual void adjustPassManager(PassManagerBuilder &) {} - /// Allow the target to modify the pass pipeline with New Pass Manager - /// (similar to adjustPassManager for Legacy Pass manager). - virtual void registerPassBuilderCallbacks(PassBuilder &, - bool DebugPassManager) {} - /// Add passes to the specified pass manager to get the specified file /// emitted. Typically this will involve several steps of code generation. /// This method should return true if emission of this file type is not diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1763,11 +1763,10 @@ return false; } -MCSymbol *AsmPrinter::getMBBExceptionSym(const MachineBasicBlock &MBB) { - auto Res = MBBSectionExceptionSyms.try_emplace(MBB.getSectionIDNum()); - if (Res.second) - Res.first->second = createTempSymbol("exception"); - return Res.first->second; +MCSymbol *AsmPrinter::getCurExceptionSym() { + if (!CurExceptionSym) + CurExceptionSym = createTempSymbol("exception"); + return CurExceptionSym; } void AsmPrinter::SetupMachineFunction(MachineFunction &MF) { @@ -1794,7 +1793,7 @@ CurrentFnBegin = nullptr; CurrentSectionBeginSym = nullptr; MBBSectionRanges.clear(); - MBBSectionExceptionSyms.clear(); + CurExceptionSym = nullptr; bool NeedsLocalForSize = MAI->needsLocalForSize(); if (F.hasFnAttribute("patchable-function-entry") || F.hasFnAttribute("function-instrument") || diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp @@ -81,9 +81,8 @@ } } -static MCSymbol *getExceptionSym(AsmPrinter *Asm, - const MachineBasicBlock *MBB) { - return Asm->getMBBExceptionSym(*MBB); +static MCSymbol *getExceptionSym(AsmPrinter *Asm) { + return Asm->getCurExceptionSym(); } void DwarfCFIException::beginFunction(const MachineFunction *MF) { @@ -162,7 +161,7 @@ // Provide LSDA information. if (shouldEmitLSDA) - Asm->OutStreamer->emitCFILsda(ESP(Asm, MBB), TLOF.getLSDAEncoding()); + Asm->OutStreamer->emitCFILsda(ESP(Asm), TLOF.getLSDAEncoding()); } /// endFunction - Gather and emit post-function exception information. diff --git a/llvm/lib/CodeGen/AsmPrinter/EHStreamer.h b/llvm/lib/CodeGen/AsmPrinter/EHStreamer.h --- a/llvm/lib/CodeGen/AsmPrinter/EHStreamer.h +++ b/llvm/lib/CodeGen/AsmPrinter/EHStreamer.h @@ -69,48 +69,23 @@ unsigned Action; }; - /// Structure describing a contiguous range of call-sites which reside - /// in the same procedure fragment. With -fbasic-block-sections, there will - /// be one call site range per basic block section. Otherwise, we will have - /// one call site range containing all the call sites in the function. - struct CallSiteRange { - // Symbol marking the beginning of the precedure fragment. - MCSymbol *FragmentBeginLabel = nullptr; - // Symbol marking the end of the procedure fragment. - MCSymbol *FragmentEndLabel = nullptr; - // LSDA symbol for this call-site range. - MCSymbol *ExceptionLabel = nullptr; - // Index of the first call-site entry in the call-site table which - // belongs to this range. - size_t CallSiteBeginIdx = 0; - // Index just after the last call-site entry in the call-site table which - // belongs to this range. - size_t CallSiteEndIdx = 0; - // Whether this is the call-site range containing all the landing pads. - bool IsLPRange = false; - }; - /// Compute the actions table and gather the first action index for each /// landing pad site. - void computeActionsTable( - const SmallVectorImpl &LandingPads, - SmallVectorImpl &Actions, - SmallVectorImpl &FirstActions); + void computeActionsTable(const SmallVectorImpl &LandingPads, + SmallVectorImpl &Actions, + SmallVectorImpl &FirstActions); void computePadMap(const SmallVectorImpl &LandingPads, RangeMapType &PadMap); - /// Compute the call-site table and the call-site ranges. The entry for an - /// invoke has a try-range containing the call, a non-zero landing pad and an - /// appropriate action. The entry for an ordinary call has a try-range - /// containing the call and zero for the landing pad and the action. Calls - /// marked 'nounwind' have no entry and must not be contained in the try-range - /// of any entry - they form gaps in the table. Entries must be ordered by - /// try-range address. CallSiteRanges vector is only populated for Itanium - /// exception handling. + /// Compute the call-site table. The entry for an invoke has a try-range + /// containing the call, a non-zero landing pad and an appropriate action. + /// The entry for an ordinary call has a try-range containing the call and + /// zero for the landing pad and the action. Calls marked 'nounwind' have + /// no entry and must not be contained in the try-range of any entry - they + /// form gaps in the table. Entries must be ordered by try-range address. virtual void computeCallSiteTable( SmallVectorImpl &CallSites, - SmallVectorImpl &CallSiteRanges, const SmallVectorImpl &LandingPads, const SmallVectorImpl &FirstActions); diff --git a/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp b/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp --- a/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp @@ -214,25 +214,10 @@ /// the landing pad and the action. Calls marked 'nounwind' have no entry and /// must not be contained in the try-range of any entry - they form gaps in the /// table. Entries must be ordered by try-range address. -/// -/// Call-sites are split into one or more call-site ranges associated with -/// different sections of the function. -/// -/// - Without -basic-block-sections, all call-sites are grouped into one -/// call-site-range corresponding to the function section. -/// -/// - With -basic-block-sections, one call-site range is created for each -/// section, with its FragmentBeginLabel and FragmentEndLabel respectively -// set to the beginning and ending of the corresponding section and its -// ExceptionLabel set to the exception symbol dedicated for this section. -// Later, one LSDA header will be emitted for each call-site range with its -// call-sites following. The action table and type info table will be -// shared across all ranges. -void EHStreamer::computeCallSiteTable( - SmallVectorImpl &CallSites, - SmallVectorImpl &CallSiteRanges, - const SmallVectorImpl &LandingPads, - const SmallVectorImpl &FirstActions) { +void EHStreamer:: +computeCallSiteTable(SmallVectorImpl &CallSites, + const SmallVectorImpl &LandingPads, + const SmallVectorImpl &FirstActions) { RangeMapType PadMap; computePadMap(LandingPads, PadMap); @@ -250,21 +235,6 @@ // Visit all instructions in order of address. for (const auto &MBB : *Asm->MF) { - if (&MBB == &Asm->MF->front() || MBB.isBeginSection()) { - // We start a call-site range upon function entry and at the beginning of - // every basic block section. - CallSiteRanges.push_back( - {Asm->MBBSectionRanges[MBB.getSectionIDNum()].BeginLabel, - Asm->MBBSectionRanges[MBB.getSectionIDNum()].EndLabel, - Asm->getMBBExceptionSym(MBB), CallSites.size()}); - PreviousIsInvoke = false; - SawPotentiallyThrowing = false; - LastLabel = nullptr; - } - - if (MBB.isEHPad()) - CallSiteRanges.back().IsLPRange = true; - for (const auto &MI : MBB) { if (!MI.isEHLabel()) { if (MI.isCall()) @@ -336,22 +306,13 @@ PreviousIsInvoke = true; } } - - // We end the call-site range upon function exit and at the end of every - // basic block section. - if (&MBB == &Asm->MF->back() || MBB.isEndSection()) { - // If some instruction between the previous try-range and the end of the - // function may throw, create a call-site entry with no landing pad for - // the region following the try-range. - if (SawPotentiallyThrowing && !IsSJLJ) { - CallSiteEntry Site = {LastLabel, CallSiteRanges.back().FragmentEndLabel, - nullptr, 0}; - CallSites.push_back(Site); - SawPotentiallyThrowing = false; - } - CallSiteRanges.back().CallSiteEndIdx = CallSites.size(); - } } + + // If some instruction between the previous try-range and the end of the + // function may throw, create a call-site entry with no landing pad for the + // region following the try-range. + if (SawPotentiallyThrowing && !IsSJLJ) + CallSites.push_back({LastLabel, Asm->getFunctionEnd(), nullptr, 0}); } /// Emit landing pads and actions. @@ -401,13 +362,9 @@ SmallVector FirstActions; computeActionsTable(LandingPads, Actions, FirstActions); - // Compute the call-site table and call-site ranges. Normally, there is only - // one call-site-range which covers the whole funciton. With - // -basic-block-sections, there is one call-site-range per basic block - // section. + // Compute the call-site table. SmallVector CallSites; - SmallVector CallSiteRanges; - computeCallSiteTable(CallSites, CallSiteRanges, LandingPads, FirstActions); + computeCallSiteTable(CallSites, LandingPads, FirstActions); bool IsSJLJ = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::SjLj; bool IsWasm = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::Wasm; @@ -467,49 +424,35 @@ Asm->OutContext.getOrCreateSymbol(Twine("GCC_except_table")+ Twine(Asm->getFunctionNumber())); Asm->OutStreamer->emitLabel(GCCETSym); - MCSymbol *CstEndLabel = Asm->createTempSymbol( - CallSiteRanges.size() > 1 ? "action_table_base" : "cst_end"); + Asm->OutStreamer->emitLabel(Asm->getCurExceptionSym()); + + // Emit the LSDA header. + Asm->emitEncodingByte(dwarf::DW_EH_PE_omit, "@LPStart"); + Asm->emitEncodingByte(TTypeEncoding, "@TType"); MCSymbol *TTBaseLabel = nullptr; - if (HaveTTData) + if (HaveTTData) { + // N.B.: There is a dependency loop between the size of the TTBase uleb128 + // here and the amount of padding before the aligned type table. The + // assembler must sometimes pad this uleb128 or insert extra padding before + // the type table. See PR35809 or GNU as bug 4029. + MCSymbol *TTBaseRefLabel = Asm->createTempSymbol("ttbaseref"); TTBaseLabel = Asm->createTempSymbol("ttbase"); + Asm->emitLabelDifferenceAsULEB128(TTBaseLabel, TTBaseRefLabel); + Asm->OutStreamer->emitLabel(TTBaseRefLabel); + } - const bool VerboseAsm = Asm->OutStreamer->isVerboseAsm(); - - // Helper for emitting references (offsets) for type table and the end of the - // call-site table (which marks the beginning of the action table). - // * For Itanium, these references will be emitted for every callsite range. - // * For SJLJ and Wasm, they will be emitted only once in the LSDA header. - auto EmitTypeTableRefAndCallSiteTableEndRef = [&]() { - Asm->emitEncodingByte(TTypeEncoding, "@TType"); - if (HaveTTData) { - // N.B.: There is a dependency loop between the size of the TTBase uleb128 - // here and the amount of padding before the aligned type table. The - // assembler must sometimes pad this uleb128 or insert extra padding - // before the type table. See PR35809 or GNU as bug 4029. - MCSymbol *TTBaseRefLabel = Asm->createTempSymbol("ttbaseref"); - Asm->emitLabelDifferenceAsULEB128(TTBaseLabel, TTBaseRefLabel); - Asm->OutStreamer->emitLabel(TTBaseRefLabel); - } + bool VerboseAsm = Asm->OutStreamer->isVerboseAsm(); - // The Action table follows the call-site table. So we emit the - // label difference from here (start of the call-site table for SJLJ and - // Wasm, and start of a call-site range for Itanium) to the end of the - // whole call-site table (end of the last call-site range for Itanium). - MCSymbol *CstBeginLabel = Asm->createTempSymbol("cst_begin"); - Asm->emitEncodingByte(CallSiteEncoding, "Call site"); - Asm->emitLabelDifferenceAsULEB128(CstEndLabel, CstBeginLabel); - Asm->OutStreamer->emitLabel(CstBeginLabel); - }; + // Emit the landing pad call site table. + MCSymbol *CstBeginLabel = Asm->createTempSymbol("cst_begin"); + MCSymbol *CstEndLabel = Asm->createTempSymbol("cst_end"); + Asm->emitEncodingByte(CallSiteEncoding, "Call site"); + Asm->emitLabelDifferenceAsULEB128(CstEndLabel, CstBeginLabel); + Asm->OutStreamer->emitLabel(CstBeginLabel); // SjLj / Wasm Exception handling if (IsSJLJ || IsWasm) { - Asm->OutStreamer->emitLabel(Asm->getMBBExceptionSym(Asm->MF->front())); - - // emit the LSDA header. - Asm->emitEncodingByte(dwarf::DW_EH_PE_omit, "@LPStart"); - EmitTypeTableRefAndCallSiteTableEndRef(); - unsigned idx = 0; for (SmallVectorImpl::const_iterator I = CallSites.begin(), E = CallSites.end(); I != E; ++I, ++idx) { @@ -534,7 +477,6 @@ } Asm->emitULEB128(S.Action); } - Asm->OutStreamer->emitLabel(CstEndLabel); } else { // Itanium LSDA exception handling @@ -556,124 +498,50 @@ // A missing entry in the call-site table indicates that a call is not // supposed to throw. - assert(CallSiteRanges.size() != 0 && "No call-site ranges!"); - - // There should be only one call-site range which includes all the landing - // pads. Find that call-site range here. - const CallSiteRange *LandingPadRange = nullptr; - for (const CallSiteRange &CSRange : CallSiteRanges) { - if (CSRange.IsLPRange) { - assert(LandingPadRange == nullptr && - "All landing pads must be in a single callsite range."); - LandingPadRange = &CSRange; - } - } - - // The call-site table is split into its call-site ranges, each being - // emitted as: - // [ LPStartEncoding | LPStart ] - // [ TypeTableEncoding | TypeTableOffset ] - // [ CallSiteEncoding | CallSiteTableEndOffset ] - // cst_begin -> { call-site entries contained in this range } - // - // and is followed by the next call-site range. - // - // For each call-site range, CallSiteTableEndOffset is computed as the - // difference between cst_begin of that range and the last call-site-table's - // end label. This offset is used to find the action table. - unsigned Entry = 0; - for (const CallSiteRange &CSRange : CallSiteRanges) { - if (CSRange.CallSiteBeginIdx != 0) { - // Align the call-site range for all ranges except the first. The - // first range is already aligned due to the exception table alignment. - Asm->emitAlignment(Align(4)); - } - Asm->OutStreamer->emitLabel(CSRange.ExceptionLabel); - - // Emit the LSDA header. - // If only one call-site range exists, LPStart is omitted as it is the - // same as the function entry. - if (CallSiteRanges.size() == 1) { - Asm->emitEncodingByte(dwarf::DW_EH_PE_omit, "@LPStart"); - } else if (!Asm->isPositionIndependent()) { - // For more than one call-site ranges, LPStart must be explicitly - // specified. - // For non-PIC we can simply use the absolute value. - Asm->emitEncodingByte(dwarf::DW_EH_PE_absptr, "@LPStart"); - Asm->OutStreamer->emitSymbolValue(LandingPadRange->FragmentBeginLabel, - Asm->MAI->getCodePointerSize()); - } else { - // For PIC mode, we Emit a PC-relative address for LPStart. - Asm->emitEncodingByte(dwarf::DW_EH_PE_pcrel, "@LPStart"); - MCContext &Context = Asm->OutStreamer->getContext(); - MCSymbol *Dot = Context.createTempSymbol(); - Asm->OutStreamer->emitLabel(Dot); - Asm->OutStreamer->emitValue( - MCBinaryExpr::createSub( - MCSymbolRefExpr::create(LandingPadRange->FragmentBeginLabel, - Context), - MCSymbolRefExpr::create(Dot, Context), Context), - Asm->MAI->getCodePointerSize()); - } - - EmitTypeTableRefAndCallSiteTableEndRef(); - - for (size_t CallSiteIdx = CSRange.CallSiteBeginIdx; - CallSiteIdx != CSRange.CallSiteEndIdx; ++CallSiteIdx) { - const CallSiteEntry &S = CallSites[CallSiteIdx]; + for (SmallVectorImpl::const_iterator + I = CallSites.begin(), E = CallSites.end(); I != E; ++I) { + const CallSiteEntry &S = *I; - MCSymbol *EHFuncBeginSym = CSRange.FragmentBeginLabel; - MCSymbol *EHFuncEndSym = CSRange.FragmentEndLabel; + MCSymbol *EHFuncBeginSym = Asm->getFunctionBegin(); - MCSymbol *BeginLabel = S.BeginLabel; - if (!BeginLabel) - BeginLabel = EHFuncBeginSym; - MCSymbol *EndLabel = S.EndLabel; - if (!EndLabel) - EndLabel = EHFuncEndSym; + // Offset of the call site relative to the start of the procedure. + if (VerboseAsm) + Asm->OutStreamer->AddComment(">> Call Site " + Twine(++Entry) + " <<"); + Asm->emitCallSiteOffset(S.BeginLabel, EHFuncBeginSym, CallSiteEncoding); + if (VerboseAsm) + Asm->OutStreamer->AddComment(Twine(" Call between ") + + S.BeginLabel->getName() + " and " + + S.EndLabel->getName()); + Asm->emitCallSiteOffset(S.EndLabel, S.BeginLabel, CallSiteEncoding); - // Offset of the call site relative to the start of the procedure. + // Offset of the landing pad relative to the start of the procedure. + if (!S.LPad) { if (VerboseAsm) - Asm->OutStreamer->AddComment(">> Call Site " + Twine(++Entry) + - " <<"); - Asm->emitCallSiteOffset(BeginLabel, EHFuncBeginSym, CallSiteEncoding); + Asm->OutStreamer->AddComment(" has no landing pad"); + Asm->emitCallSiteValue(0, CallSiteEncoding); + } else { if (VerboseAsm) - Asm->OutStreamer->AddComment(Twine(" Call between ") + - BeginLabel->getName() + " and " + - EndLabel->getName()); - Asm->emitCallSiteOffset(EndLabel, BeginLabel, CallSiteEncoding); - - // Offset of the landing pad relative to the start of the landing pad - // fragment. - if (!S.LPad) { - if (VerboseAsm) - Asm->OutStreamer->AddComment(" has no landing pad"); - Asm->emitCallSiteValue(0, CallSiteEncoding); - } else { - if (VerboseAsm) - Asm->OutStreamer->AddComment(Twine(" jumps to ") + - S.LPad->LandingPadLabel->getName()); - Asm->emitCallSiteOffset(S.LPad->LandingPadLabel, - LandingPadRange->FragmentBeginLabel, - CallSiteEncoding); - } + Asm->OutStreamer->AddComment(Twine(" jumps to ") + + S.LPad->LandingPadLabel->getName()); + Asm->emitCallSiteOffset(S.LPad->LandingPadLabel, EHFuncBeginSym, + CallSiteEncoding); + } - // Offset of the first associated action record, relative to the start - // of the action table. This value is biased by 1 (1 indicates the start - // of the action table), and 0 indicates that there are no actions. - if (VerboseAsm) { - if (S.Action == 0) - Asm->OutStreamer->AddComment(" On action: cleanup"); - else - Asm->OutStreamer->AddComment(" On action: " + - Twine((S.Action - 1) / 2 + 1)); - } - Asm->emitULEB128(S.Action); + // Offset of the first associated action record, relative to the start of + // the action table. This value is biased by 1 (1 indicates the start of + // the action table), and 0 indicates that there are no actions. + if (VerboseAsm) { + if (S.Action == 0) + Asm->OutStreamer->AddComment(" On action: cleanup"); + else + Asm->OutStreamer->AddComment(" On action: " + + Twine((S.Action - 1) / 2 + 1)); } + Asm->emitULEB128(S.Action); } - Asm->OutStreamer->emitLabel(CstEndLabel); } + Asm->OutStreamer->emitLabel(CstEndLabel); // Emit the Action Table. int Entry = 0; @@ -728,7 +596,7 @@ const std::vector &TypeInfos = MF->getTypeInfos(); const std::vector &FilterIds = MF->getFilterIds(); - const bool VerboseAsm = Asm->OutStreamer->isVerboseAsm(); + bool VerboseAsm = Asm->OutStreamer->isVerboseAsm(); int Entry = 0; // Emit the Catch TypeInfos. diff --git a/llvm/lib/CodeGen/AsmPrinter/WasmException.h b/llvm/lib/CodeGen/AsmPrinter/WasmException.h --- a/llvm/lib/CodeGen/AsmPrinter/WasmException.h +++ b/llvm/lib/CodeGen/AsmPrinter/WasmException.h @@ -32,7 +32,6 @@ // Compute the call site table for wasm EH. void computeCallSiteTable( SmallVectorImpl &CallSites, - SmallVectorImpl &CallSiteRanges, const SmallVectorImpl &LandingPads, const SmallVectorImpl &FirstActions) override; }; diff --git a/llvm/lib/CodeGen/AsmPrinter/WasmException.cpp b/llvm/lib/CodeGen/AsmPrinter/WasmException.cpp --- a/llvm/lib/CodeGen/AsmPrinter/WasmException.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/WasmException.cpp @@ -76,7 +76,6 @@ // information. void WasmException::computeCallSiteTable( SmallVectorImpl &CallSites, - SmallVectorImpl &CallSiteRanges, const SmallVectorImpl &LandingPads, const SmallVectorImpl &FirstActions) { MachineFunction &MF = *Asm->MF; diff --git a/llvm/lib/CodeGen/BasicBlockSections.cpp b/llvm/lib/CodeGen/BasicBlockSections.cpp --- a/llvm/lib/CodeGen/BasicBlockSections.cpp +++ b/llvm/lib/CodeGen/BasicBlockSections.cpp @@ -293,26 +293,6 @@ updateBranches(MF, PreLayoutFallThroughs); } -// If the exception section begins with a landing pad, that landing pad will -// assume a zero offset (relative to @LPStart) in the LSDA. However, a value of -// zero implies "no landing pad." This function inserts a NOP just before the EH -// pad label to ensure a nonzero offset. Returns true if padding is not needed. -static bool avoidZeroOffsetLandingPad(MachineFunction &MF) { - for (auto &MBB : MF) { - if (MBB.isBeginSection() && MBB.isEHPad()) { - MachineBasicBlock::iterator MI = MBB.begin(); - while (!MI->isEHLabel()) - ++MI; - MCInst Noop; - MF.getSubtarget().getInstrInfo()->getNoop(Noop); - BuildMI(MBB, MI, DebugLoc(), - MF.getSubtarget().getInstrInfo()->get(Noop.getOpcode())); - return false; - } - } - return true; -} - bool BasicBlockSections::runOnMachineFunction(MachineFunction &MF) { auto BBSectionsType = MF.getTarget().getBBSectionsType(); assert(BBSectionsType != BasicBlockSection::None && @@ -374,7 +354,6 @@ }; sortBasicBlocksAndUpdateBranches(MF, Comparator); - avoidZeroOffsetLandingPad(MF); return true; } diff --git a/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp b/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp --- a/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp +++ b/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp @@ -1564,15 +1564,6 @@ continue; } - // If the BaseReg has been modified, then we cannot do the optimization. - // For example, in the following pattern - // ldr x1 [x2] - // ldr x2 [x3] - // ldr x4 [x2, #8], - // the first and third ldr cannot be converted to ldp x1, x4, [x2] - if (!ModifiedRegUnits.available(BaseReg)) - return E; - // If the Rt of the second instruction was not modified or used between // the two instructions and none of the instructions between the second // and first alias with the second, we can combine the second into the diff --git a/llvm/lib/Target/ARM/ARMAsmPrinter.cpp b/llvm/lib/Target/ARM/ARMAsmPrinter.cpp --- a/llvm/lib/Target/ARM/ARMAsmPrinter.cpp +++ b/llvm/lib/Target/ARM/ARMAsmPrinter.cpp @@ -903,7 +903,7 @@ MCSymbol *MCSym; if (ACPV->isLSDA()) { - MCSym = getMBBExceptionSym(MF->front()); + MCSym = getCurExceptionSym(); } else if (ACPV->isBlockAddress()) { const BlockAddress *BA = cast(ACPV)->getBlockAddress(); diff --git a/llvm/lib/Target/Hexagon/HexagonTargetMachine.h b/llvm/lib/Target/Hexagon/HexagonTargetMachine.h --- a/llvm/lib/Target/Hexagon/HexagonTargetMachine.h +++ b/llvm/lib/Target/Hexagon/HexagonTargetMachine.h @@ -37,8 +37,6 @@ static unsigned getModuleMatchQuality(const Module &M); void adjustPassManager(PassManagerBuilder &PMB) override; - void registerPassBuilderCallbacks(PassBuilder &PB, - bool DebugPassManager) override; TargetPassConfig *createPassConfig(PassManagerBase &PM) override; TargetTransformInfo getTargetTransformInfo(const Function &F) override; diff --git a/llvm/lib/Target/Hexagon/HexagonTargetMachine.cpp b/llvm/lib/Target/Hexagon/HexagonTargetMachine.cpp --- a/llvm/lib/Target/Hexagon/HexagonTargetMachine.cpp +++ b/llvm/lib/Target/Hexagon/HexagonTargetMachine.cpp @@ -22,7 +22,6 @@ #include "llvm/CodeGen/TargetPassConfig.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Module.h" -#include "llvm/Passes/PassBuilder.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" @@ -274,18 +273,6 @@ }); } -void HexagonTargetMachine::registerPassBuilderCallbacks(PassBuilder &PB, - bool DebugPassManager) { - PB.registerOptimizerLastEPCallback( - [=](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) { - LoopPassManager LPM(DebugPassManager); - FunctionPassManager FPM(DebugPassManager); - LPM.addPass(HexagonVectorLoopCarriedReusePass()); - FPM.addPass(createFunctionToLoopPassAdaptor(std::move(LPM))); - MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); - }); -} - TargetTransformInfo HexagonTargetMachine::getTargetTransformInfo(const Function &F) { return TargetTransformInfo(HexagonTTIImpl(this, F)); diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -40939,7 +40939,8 @@ // (x > 0) ? x : 0 -> (x >= 0) ? x : 0 // (x < -1) ? x : -1 -> (x <= -1) ? x : -1 // This allows use of COND_S / COND_NS (see TranslateX86CC) which eliminates - // the need for an extra compare against zero. e.g. + // the need for an extra compare + // against zero. e.g. // (a - b) > 0 : (a - b) ? 0 -> (a - b) >= 0 : (a - b) ? 0 // subl %esi, %edi // testl %edi, %edi @@ -40949,28 +40950,17 @@ // xorl %eax, %eax // subl %esi, $edi // cmovsl %eax, %edi - // - // We can also canonicalize - // (x s> 1) ? x : 1 -> (x s>= 1) ? x : 1 -> (x s> 0) ? x : 1 - // (x u> 1) ? x : 1 -> (x u>= 1) ? x : 1 -> (x != 0) ? x : 1 - // This allows the use of a test instruction for the compare. if (N->getOpcode() == ISD::SELECT && Cond.getOpcode() == ISD::SETCC && Cond.hasOneUse() && LHS == Cond.getOperand(0) && RHS == Cond.getOperand(1)) { ISD::CondCode CC = cast(Cond.getOperand(2))->get(); - if ((CC == ISD::SETGT && (isNullConstant(RHS) || isOneConstant(RHS))) || + if ((CC == ISD::SETGT && isNullConstant(RHS)) || (CC == ISD::SETLT && isAllOnesConstant(RHS))) { ISD::CondCode NewCC = CC == ISD::SETGT ? ISD::SETGE : ISD::SETLE; Cond = DAG.getSetCC(SDLoc(Cond), Cond.getValueType(), Cond.getOperand(0), Cond.getOperand(1), NewCC); return DAG.getSelect(DL, VT, Cond, LHS, RHS); } - if (CC == ISD::SETUGT && isOneConstant(RHS)) { - ISD::CondCode NewCC = ISD::SETUGE; - Cond = DAG.getSetCC(SDLoc(Cond), Cond.getValueType(), - Cond.getOperand(0), Cond.getOperand(1), NewCC); - return DAG.getSelect(DL, VT, Cond, LHS, RHS); - } } // Match VSELECTs into subs with unsigned saturation. diff --git a/llvm/test/CodeGen/AArch64/aarch64-ldst-modified-baseReg.mir b/llvm/test/CodeGen/AArch64/aarch64-ldst-modified-baseReg.mir deleted file mode 100644 --- a/llvm/test/CodeGen/AArch64/aarch64-ldst-modified-baseReg.mir +++ /dev/null @@ -1,105 +0,0 @@ -# RUN: llc -mtriple=aarch64-linux-gnu -verify-machineinstrs -run-pass=aarch64-ldst-opt %s -o - | FileCheck %s -# -# When the AArch64 Load Store Optimization pass tries to convert load instructions -# into a ldp instruction, and when the base register of the second ldr instruction -# has been modified in between these two ldr instructions, the conversion should not -# occur. -# -# For example, for the following pattern: -# ldr x9 [x10] -# ldr x10 [x8] -# ldr x10 [x10, 8], -# the first and third ldr instructions cannot be converted to ldp x9, x10, [x10]. -# -# CHECK-LABEL: name: ldr-modified-baseReg-no-ldp1 -# CHECK-NOT: LDP -# CHECK: $x9 = LDRXui $x10, 1 :: (load 8) -# CHECK: $x10 = LDURXi $x8, 1 :: (load 8) -# CHECK: $x10 = LDRXui $x10, 0 :: (load 8) -# CHECK: RET ---- -name: ldr-modified-baseReg-no-ldp1 -tracksRegLiveness: true -body: | - bb.0: - liveins: $x8, $x10 - - $x9 = LDRXui $x10, 1 :: (load 8) - $x10 = LDURXi $x8, 1 :: (load 8) - $x10 = LDRXui $x10, 0 :: (load 8) - RET undef $lr, implicit undef $w0 -... - -# CHECK-LABEL: name: str-modified-baseReg-no-stp1 -# CHECK-NOT: STP -# CHECK: STRXui $x9, $x10, 1 :: (store 8) -# CHECK: $x10 = LDRXui $x8, 0 :: (load 8) -# CHECK: STRXui $x10, $x10, 0 :: (store 8) -# CHECK: RET ---- -name: str-modified-baseReg-no-stp1 -tracksRegLiveness: true -body: | - bb.0: - liveins: $x9, $x8, $x10 - - STRXui $x9, $x10, 1 :: (store 8) - $x10 = LDRXui $x8, 0 :: (load 8) - STRXui $x10, $x10, 0 :: (store 8) - RET undef $lr, implicit undef $w0 -... - -# CHECK-LABEL: name: ldr-modified-baseReg-no-ldp2 -# CHECK-NOT: LDP -# CHECK: $x9 = LDRXui $x10, 1 :: (load 8) -# CHECK: $x10 = MOVi64imm 13 -# CHECK: $x11 = LDRXui $x10, 0 :: (load 8) -# CHECK: RET ---- -name: ldr-modified-baseReg-no-ldp2 -tracksRegLiveness: true -body: | - bb.0: - liveins: $x8, $x10 - - $x9 = LDRXui $x10, 1 :: (load 8) - $x10 = MOVi64imm 13 - $x11 = LDRXui $x10, 0 :: (load 8) - RET undef $lr, implicit undef $w0 -... - -# CHECK-LABEL: name: ldr-modified-baseReg-no-ldp3 -# CHECK-NOT: LDP -# CHECK: $x9 = LDRXui $x10, 1 :: (load 8) -# CHECK: $x10 = ADDXri $x8, $x11, 0 -# CHECK: $x12 = LDRXui $x10, 0 :: (load 8) -# CHECK: RET ---- -name: ldr-modified-baseReg-no-ldp3 -tracksRegLiveness: true -body: | - bb.0: - liveins: $x8, $x10, $x11 - - $x9 = LDRXui $x10, 1 :: (load 8) - $x10 = ADDXri $x8, $x11, 0 - $x12 = LDRXui $x10, 0 :: (load 8) - RET undef $lr, implicit undef $w0 -... - -# CHECK-LABEL: name: ldr-modified-baseAddr-convert-to-ldp -# CHECK: $x12, $x9 = LDPXi $x10, 0 :: (load 8) -# CHECK: STRXui $x11, $x10, 1 :: (store 8) -# CHECK: RET ---- -name: ldr-modified-baseAddr-convert-to-ldp -tracksRegLiveness: true -body: | - bb.0: - liveins: $x8, $x10, $x11 - - $x9 = LDRXui $x10, 1 :: (load 8) - STRXui $x11, $x10, 1 :: (store 8) - $x12 = LDRXui $x10, 0 :: (load 8) - RET undef $lr, implicit undef $w0 -... diff --git a/llvm/test/CodeGen/Hexagon/registerpassbuildercallbacks.ll b/llvm/test/CodeGen/Hexagon/registerpassbuildercallbacks.ll deleted file mode 100644 --- a/llvm/test/CodeGen/Hexagon/registerpassbuildercallbacks.ll +++ /dev/null @@ -1,27 +0,0 @@ -; RUN: opt -mtriple=hexagon -disable-verify -debug-pass-manager \ -; RUN: -disable-output -passes='default' -S %s 2>&1 \ -; RUN: | FileCheck %s --check-prefix=NPM -; RUN: opt -mtriple=hexagon -disable-verify -debug-pass-manager \ -; RUN: -disable-output -passes='default' -S %s 2>&1 \ -; RUN: | FileCheck %s --check-prefix=NPM -; RUN: opt -mtriple=hexagon -disable-verify -debug-pass-manager \ -; RUN: -disable-output -passes='default' -S %s 2>&1 \ -; RUN: | FileCheck %s --check-prefix=NPM - -; Test TargetMachine::registerPassBuilderCallbacks -; NPM: Running pass: HexagonVectorLoopCarriedReusePass - -declare void @bar() local_unnamed_addr - -define void @foo(i32 %n) local_unnamed_addr { -entry: - br label %loop -loop: - %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ] - %iv.next = add i32 %iv, 1 - tail call void @bar() - %cmp = icmp eq i32 %iv, %n - br i1 %cmp, label %exit, label %loop -exit: - ret void -} diff --git a/llvm/test/CodeGen/X86/cmov.ll b/llvm/test/CodeGen/X86/cmov.ll --- a/llvm/test/CodeGen/X86/cmov.ll +++ b/llvm/test/CodeGen/X86/cmov.ll @@ -235,27 +235,3 @@ %3 = select i1 %2, i32 %0, i32 -1 ret i32 %3 } - -define i32 @pr47049_3(i32 %0) { -; CHECK-LABEL: pr47049_3: -; CHECK: # %bb.0: -; CHECK-NEXT: testl %edi, %edi -; CHECK-NEXT: movl $1, %eax -; CHECK-NEXT: cmovgl %edi, %eax -; CHECK-NEXT: retq - %2 = icmp sgt i32 %0, 1 - %3 = select i1 %2, i32 %0, i32 1 - ret i32 %3 -} - -define i32 @pr47049_4(i32 %0) { -; CHECK-LABEL: pr47049_4: -; CHECK: # %bb.0: -; CHECK-NEXT: testl %edi, %edi -; CHECK-NEXT: movl $1, %eax -; CHECK-NEXT: cmovnel %edi, %eax -; CHECK-NEXT: retq - %2 = icmp ugt i32 %0, 1 - %3 = select i1 %2, i32 %0, i32 1 - ret i32 %3 -} diff --git a/llvm/test/CodeGen/X86/gcc_except_table_bb_sections.ll b/llvm/test/CodeGen/X86/gcc_except_table_bb_sections.ll deleted file mode 100644 --- a/llvm/test/CodeGen/X86/gcc_except_table_bb_sections.ll +++ /dev/null @@ -1,166 +0,0 @@ -; RUN: llc -basic-block-sections=all -mtriple x86_64-pc-linux-gnu < %s | FileCheck %s --check-prefixes=CHECK,CHECK-NON-PIC -; RUN: llc -basic-block-sections=all -mtriple x86_64-pc-linux-gnu -relocation-model=pic < %s | FileCheck %s --check-prefixes=CHECK,CHECK-PIC -@_ZTIi = external constant i8* - -define i32 @main() uwtable optsize ssp personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { -; Verify that each basic block section gets its own LSDA exception symbol. -; -; CHECK-LABEL: main: -; CHECK-NEXT: .Lfunc_begin0: -; CHECK-NEXT: .cfi_startproc - -;; Verify personality function and LSDA encoding for NON-PIC mode. -; PersonalityEncoding = dwarf::DW_EH_PE_udata4 -; CHECK-NON-PIC-NEXT: .cfi_personality 3, __gxx_personality_v0 -; LSDAEncoding = dwarf::DW_EH_PE_udata4 -; CHECK-NON-PIC-NEXT: .cfi_lsda 3, .Lexception0 - -;; Verify personality function and LSDA encoding for PIC mode. -; PersonalityEncoding = DW_EH_PE_indirect | DW_EH_PE_pcrel | DW_EH_PE_sdata4 -; CHECK-PIC-NEXT: .cfi_personality 155, DW.ref.__gxx_personality_v0 -; LSDAEncoding = DW_EH_PE_pcrel | DW_EH_PE_sdata4 -; CHECK-PIC-NEXT: .cfi_lsda 27, .Lexception0 - -; CHECK-LABEL: .Ltmp0: -; CHECK-NEXT: callq _Z1fv -; CHECK-LABEL: .Ltmp1: - -; CHECK-NOT: .cfi_lsda - -; CHECK-LABEL: main.1: -; CHECK-NEXT: .cfi_startproc - -; CHECK-NON-PIC-NEXT: .cfi_personality 3, __gxx_personality_v0 -; CHECK-NON-PIC-NEXT: .cfi_lsda 3, .Lexception1 - -; CHECK-PIC-NEXT: .cfi_personality 155, DW.ref.__gxx_personality_v0 -; CHECK-PIC-NEXT: .cfi_lsda 27, .Lexception1 - -; CHECK-NOT: .cfi_lsda - -; CHECK-LABEL: main.2: -; CHECK-NEXT: .cfi_startproc - -; CHECK-NON-PIC-NEXT: .cfi_personality 3, __gxx_personality_v0 -; CHECK-NON-PIC-NEXT: .cfi_lsda 3, .Lexception2 - -; CHECK-PIC-NEXT: .cfi_personality 155, DW.ref.__gxx_personality_v0 -; CHECK-PIC-NEXT: .cfi_lsda 27, .Lexception2 - -; CHECK: nop -; CHECK-LABEL: .Ltmp2: -; CHECK-LABEL: .LBB_END0_2: - -; CHECK-NOT: .cfi_lsda - -entry: - invoke void @_Z1fv() optsize - to label %try.cont unwind label %lpad - -lpad: - %0 = landingpad { i8*, i32 } - cleanup - catch i8* bitcast (i8** @_ZTIi to i8*) - br label %eh.resume - -try.cont: - ret i32 0 - -eh.resume: - resume { i8*, i32 } %0 -} - -declare void @_Z1fv() optsize - -declare i32 @__gxx_personality_v0(...) -;; Verify that the exception table gets split across the three basic block sections. -; -; CHECK: .section .gcc_except_table -; CHECK-NEXT: .p2align 2 -; CHECK-NEXT: GCC_except_table0: -; CHECK-NEXT: .Lexception0: - -;; Verify @LPStart encoding for NON-PIC mode. -; CHECK-NON-PIC-NEXT: .byte 0 # @LPStart Encoding = absptr -; CHECK-NON-PIC-NEXT: .quad main.2 - -;; Verify @LPStart encoding for PIC mode. -; CHECK-PIC-NEXT: .byte 16 # @LPStart Encoding = pcrel -; CHECK-PIC-NEXT: [[DOT:\.Ltmp[0-9]+]]: -; CHECK-PIC-NEXT: .quad main.2-[[DOT]] - -;; Verify @TType encoding for NON-PIC mode. -; CHECK-NON-PIC-NEXT: .byte 3 # @TType Encoding = udata4 - -;; Verify @TType encoding for PIC mode. -; CHECK-PIC-NEXT: .byte 156 # @TType Encoding = indirect pcrel sdata8 - -; CHECK-NEXT: .uleb128 .Lttbase0-.Lttbaseref0 -; CHECK-NEXT: .Lttbaseref0: -; CHECK-NEXT: .byte 1 # Call site Encoding = uleb128 -; CHECK-NEXT: .uleb128 .Laction_table_base0-.Lcst_begin0 -; CHECK-NEXT: .Lcst_begin0: -; CHECK-NEXT: .uleb128 .Ltmp0-.Lfunc_begin0 # >> Call Site 1 << -; CHECK-NEXT: .uleb128 .Ltmp1-.Ltmp0 # Call between .Ltmp0 and .Ltmp1 -; CHECK-NEXT: .uleb128 .Ltmp2-main.2 # jumps to .Ltmp2 -; CHECK-NEXT: .byte 3 # On action: 2 -; CHECK-NEXT: .p2align 2 -; CHECK-NEXT: .Lexception1: - -; CHECK-NON-PIC-NEXT: .byte 0 # @LPStart Encoding = absptr -; CHECK-NON-PIC-NEXT: .quad main.2 - -; CHECK-PIC-NEXT: .byte 16 # @LPStart Encoding = pcrel -; CHECK-PIC-NEXT: [[DOT:\.Ltmp[0-9]+]]: -; CHECK-PIC-NEXT: .quad main.2-[[DOT]] - -; CHECK-NON-PIC-NEXT: .byte 3 # @TType Encoding = udata4 - -; CHECK-PIC-NEXT: .byte 156 # @TType Encoding = indirect pcrel sdata8 - -; CHECK-NEXT: .uleb128 .Lttbase0-.Lttbaseref1 -; CHECK-NEXT: .Lttbaseref1: -; CHECK-NEXT: .byte 1 # Call site Encoding = uleb128 -; CHECK-NEXT: .uleb128 .Laction_table_base0-.Lcst_begin1 -; CHECK-NEXT: .Lcst_begin1: -; CHECK-NEXT: .p2align 2 -; CHECK-NEXT: .Lexception2: - -; CHECK-NON-PIC-NEXT: .byte 0 # @LPStart Encoding = absptr -; CHECK-NON-PIC-NEXT: .quad main.2 - -; CHECK-PIC-NEXT: .byte 16 # @LPStart Encoding = pcrel -; CHECK-PIC-NEXT: [[DOT:\.Ltmp[0-9]+]]: -; CHECK-PIC-NEXT: .quad main.2-[[DOT]] - -; CHECK-NON-PIC-NEXT: .byte 3 # @TType Encoding = udata4 - -; CHECK-PIC-NEXT: .byte 156 # @TType Encoding = indirect pcrel sdata8 - -; CHECK-NEXT: .uleb128 .Lttbase0-.Lttbaseref2 -; CHECK-NEXT: .Lttbaseref2: -; CHECK-NEXT: .byte 1 # Call site Encoding = uleb128 -; CHECK-NEXT: .uleb128 .Laction_table_base0-.Lcst_begin2 -; CHECK-NEXT: .Lcst_begin2: -; CHECK-NEXT: .uleb128 main.2-main.2 # >> Call Site 2 << -; CHECK-NEXT: .uleb128 .LBB_END0_2-main.2 # Call between main.2 and .LBB_END0_2 -; CHECK-NEXT: .byte 0 # has no landing pad -; CHECK-NEXT: .byte 0 # On action: cleanup -; CHECK-NEXT: .Laction_table_base0: -; CHECK-NEXT: .byte 0 # >> Action Record 1 << -; CHECK-NEXT: # Cleanup -; CHECK-NEXT: .byte 0 # No further actions -; CHECK-NEXT: .byte 1 # >> Action Record 2 << -; CHECK-NEXT: # Catch TypeInfo 1 -; CHECK-NEXT: .byte 125 # Continue to action 1 -; CHECK-NEXT: .p2align 2 -; CHECK-NEXT: # >> Catch TypeInfos << - -; CHECK-NON-PIC-NEXT: .long _ZTIi # TypeInfo 1 - -; CHECK-PIC-NEXT: [[DOT:\.Ltmp[0-9]+]]: -; CHECK-PIC-NEXT: .quad .L_ZTIi.DW.stub-[[DOT]] - -; CHECK-NEXT: .Lttbase0: -; CHECK-NEXT: .p2align 2 -; CHECK-NEXT: # -- End function diff --git a/llvm/test/CodeGen/X86/gcc_except_table_bb_sections_ehpad_groups_with_cold.ll b/llvm/test/CodeGen/X86/gcc_except_table_bb_sections_ehpad_groups_with_cold.ll deleted file mode 100644 --- a/llvm/test/CodeGen/X86/gcc_except_table_bb_sections_ehpad_groups_with_cold.ll +++ /dev/null @@ -1,96 +0,0 @@ -; Check that when all exception handling blocks are cold, they get grouped with the cold bbs. -; RUN: echo '!main' > %t -; RUN: echo '!!0' >> %t -; RUN: llc -function-sections -basic-block-sections=%t -mtriple x86_64-pc-linux-gnu < %s | FileCheck %s -@_ZTIi = external constant i8* - -define i32 @main() uwtable optsize ssp personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { -; Verify that each basic block section gets its own LSDA exception symbol. -; -; CHECK-LABEL: main: -; CHECK-NEXT: .Lfunc_begin0: -; CHECK-NEXT: .cfi_startproc -; PersonalityEncoding = dwarf::DW_EH_PE_udata4 -; CHECK-NEXT: .cfi_personality 3, __gxx_personality_v0 -; LSDAEncoding = dwarf::DW_EH_PE_udata4 -; CHECK-NEXT: .cfi_lsda 3, .Lexception0 -; CHECK-LABEL: .Ltmp0: -; CHECK-LABEL: .Ltmp1: - -; CHECK-NOT: .cfi_lsda - -; CHECK-LABEL: main.cold: -; CHECK-NEXT: .cfi_startproc -; CHECK-NEXT: .cfi_personality 3, __gxx_personality_v0 -; CHECK-NEXT: .cfi_lsda 3, .Lexception1 -; CHECK-LABEL: .Ltmp2: -; CHECK-LABEL: .LBB_END0_2: - -; CHECK-NOT: .cfi_lsda - -entry: - invoke void @_Z1fv() optsize - to label %try.cont unwind label %lpad - -lpad: - %0 = landingpad { i8*, i32 } - cleanup - catch i8* bitcast (i8** @_ZTIi to i8*) - br label %eh.resume - -try.cont: - ret i32 0 - -eh.resume: - resume { i8*, i32 } %0 -} - -declare void @_Z1fv() optsize - -declare i32 @__gxx_personality_v0(...) - -; Verify that the exception table gets split across the two basic block sections. -; -; CHECK: .section .gcc_except_table -; CHECK-NEXT: .p2align 2 -; CHECK-NEXT: GCC_except_table0: -; CHECK-NEXT: .Lexception0: -; CHECK-NEXT: .byte 0 # @LPStart Encoding = absptr -; CHECK-NEXT: .quad main.cold -; CHECK-NEXT: .byte 3 # @TType Encoding = udata4 -; CHECK-NEXT: .uleb128 .Lttbase0-.Lttbaseref0 -; CHECK-NEXT: .Lttbaseref0: -; CHECK-NEXT: .byte 1 # Call site Encoding = uleb128 -; CHECK-NEXT: .uleb128 .Laction_table_base0-.Lcst_begin0 -; CHECK-NEXT: .Lcst_begin0: -; CHECK-NEXT: .uleb128 .Ltmp0-.Lfunc_begin0 # >> Call Site 1 << -; CHECK-NEXT: .uleb128 .Ltmp1-.Ltmp0 # Call between .Ltmp0 and .Ltmp1 -; CHECK-NEXT: .uleb128 .Ltmp2-main.cold # jumps to .Ltmp2 -; CHECK-NEXT: .byte 3 # On action: 2 -; CHECK-NEXT: .p2align 2 -; CHECK-NEXT: .Lexception1: -; CHECK-NEXT: .byte 0 # @LPStart Encoding = absptr -; CHECK-NEXT: .quad main.cold -; CHECK-NEXT: .byte 3 # @TType Encoding = udata4 -; CHECK-NEXT: .uleb128 .Lttbase0-.Lttbaseref1 -; CHECK-NEXT: .Lttbaseref1: -; CHECK-NEXT: .byte 1 # Call site Encoding = uleb128 -; CHECK-NEXT: .uleb128 .Laction_table_base0-.Lcst_begin1 -; CHECK-NEXT: .Lcst_begin1: -; CHECK-NEXT: .uleb128 main.cold-main.cold # >> Call Site 2 << -; CHECK-NEXT: .uleb128 .LBB_END0_2-main.cold # Call between main.cold and .LBB_END0_2 -; CHECK-NEXT: .byte 0 # has no landing pad -; CHECK-NEXT: .byte 0 # On action: cleanup -; CHECK-NEXT: .Laction_table_base0: -; CHECK-NEXT: .byte 0 # >> Action Record 1 << -; CHECK-NEXT: # Cleanup -; CHECK-NEXT: .byte 0 # No further actions -; CHECK-NEXT: .byte 1 # >> Action Record 2 << -; CHECK-NEXT: # Catch TypeInfo 1 -; CHECK-NEXT: .byte 125 # Continue to action 1 -; CHECK-NEXT: .p2align 2 -; CHECK-NEXT: # >> Catch TypeInfos << -; CHECK-NEXT: .long _ZTIi # TypeInfo 1 -; CHECK-NEXT: .Lttbase0: -; CHECK-NEXT: .p2align 2 -; CHECK-NEXT: # -- End function diff --git a/llvm/test/Transforms/SampleProfile/branch.ll b/llvm/test/Transforms/SampleProfile/branch.ll --- a/llvm/test/Transforms/SampleProfile/branch.ll +++ b/llvm/test/Transforms/SampleProfile/branch.ll @@ -1,5 +1,5 @@ -; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/branch.prof | opt -analyze -branch-prob -enable-new-pm=0 | FileCheck %s -; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/branch.prof | opt -passes='print' -disable-output 2>&1 | FileCheck %s +; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/branch.prof | opt -analyze -branch-prob | FileCheck %s +; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/branch.prof | opt -analyze -branch-prob | FileCheck %s ; Original C++ code for this test case: ; @@ -30,7 +30,7 @@ ; Function Attrs: uwtable define i32 @main(i32 %argc, i8** %argv) #0 !dbg !6 { -; CHECK: Printing analysis {{.*}} for function 'main': +; CHECK: Printing analysis 'Branch Probability Analysis' for function 'main': entry: %retval = alloca i32, align 4 diff --git a/llvm/test/Transforms/SampleProfile/calls.ll b/llvm/test/Transforms/SampleProfile/calls.ll --- a/llvm/test/Transforms/SampleProfile/calls.ll +++ b/llvm/test/Transforms/SampleProfile/calls.ll @@ -1,5 +1,5 @@ -; RUN: opt < %s -instcombine -sample-profile -sample-profile-file=%S/Inputs/calls.prof | opt -analyze -branch-prob -enable-new-pm=0 | FileCheck %s -; RUN: opt < %s -passes="function(instcombine),sample-profile" -sample-profile-file=%S/Inputs/calls.prof | opt -passes='print' -disable-output 2>&1 | FileCheck %s +; RUN: opt < %s -instcombine -sample-profile -sample-profile-file=%S/Inputs/calls.prof | opt -analyze -branch-prob | FileCheck %s +; RUN: opt < %s -passes="function(instcombine),sample-profile" -sample-profile-file=%S/Inputs/calls.prof | opt -analyze -branch-prob | FileCheck %s ; Original C++ test case ; diff --git a/llvm/test/Transforms/SampleProfile/discriminator.ll b/llvm/test/Transforms/SampleProfile/discriminator.ll --- a/llvm/test/Transforms/SampleProfile/discriminator.ll +++ b/llvm/test/Transforms/SampleProfile/discriminator.ll @@ -1,5 +1,5 @@ -; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/discriminator.prof | opt -analyze -branch-prob -enable-new-pm=0 | FileCheck %s -; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/discriminator.prof | opt -passes='print' -disable-output 2>&1 | FileCheck %s +; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/discriminator.prof | opt -analyze -branch-prob | FileCheck %s +; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/discriminator.prof | opt -analyze -branch-prob | FileCheck %s ; Original code ; @@ -23,7 +23,7 @@ ; but the then branch (line 3.1) is only executed 5 times. define i32 @foo(i32 %i) #0 !dbg !4 { -; CHECK: Printing analysis {{.*}} for function 'foo': +; CHECK: Printing analysis 'Branch Probability Analysis' for function 'foo': entry: %i.addr = alloca i32, align 4 %x = alloca i32, align 4 diff --git a/llvm/test/Transforms/SampleProfile/flattened.ll b/llvm/test/Transforms/SampleProfile/flattened.ll --- a/llvm/test/Transforms/SampleProfile/flattened.ll +++ b/llvm/test/Transforms/SampleProfile/flattened.ll @@ -1,13 +1,13 @@ ; Check flattened profile will not be read in thinlto postlink. -; RUN: opt < %s -O2 -flattened-profile-used -pgo-kind=pgo-sample-use-pipeline -profile-file=%S/Inputs/flattened.prof -enable-chr=false -perform-thinlto=true -enable-new-pm=0 -S | FileCheck %s +; RUN: opt < %s -O2 -flattened-profile-used -pgo-kind=pgo-sample-use-pipeline -profile-file=%S/Inputs/flattened.prof -enable-chr=false -perform-thinlto=true -S | FileCheck %s ; RUN: opt < %s -passes='thinlto' -pgo-kind=pgo-sample-use-pipeline -profile-file=%S/Inputs/flattened.prof -flattened-profile-used -S | FileCheck %s ; ; Check flattened profile will be read in thinlto prelink. -; RUN: opt < %s -O2 -flattened-profile-used -pgo-kind=pgo-sample-use-pipeline -profile-file=%S/Inputs/flattened.prof -enable-chr=false -prepare-for-thinlto=true -enable-new-pm=0 -S | FileCheck %s --check-prefix=PRELINK +; RUN: opt < %s -O2 -flattened-profile-used -pgo-kind=pgo-sample-use-pipeline -profile-file=%S/Inputs/flattened.prof -enable-chr=false -prepare-for-thinlto=true -S | FileCheck %s --check-prefix=PRELINK ; RUN: opt < %s -passes='thinlto-pre-link' -pgo-kind=pgo-sample-use-pipeline -profile-file=%S/Inputs/flattened.prof -flattened-profile-used -S | FileCheck %s --check-prefix=PRELINK ; ; Check flattened profile will be read in non-thinlto mode. -; RUN: opt < %s -O2 -flattened-profile-used -pgo-kind=pgo-sample-use-pipeline -profile-file=%S/Inputs/flattened.prof -enable-chr=false -enable-new-pm=0 -S | FileCheck %s --check-prefix=NOTHINLTO +; RUN: opt < %s -O2 -flattened-profile-used -pgo-kind=pgo-sample-use-pipeline -profile-file=%S/Inputs/flattened.prof -enable-chr=false -S | FileCheck %s --check-prefix=NOTHINLTO ; RUN: opt < %s -passes='default' -pgo-kind=pgo-sample-use-pipeline -profile-file=%S/Inputs/flattened.prof -flattened-profile-used -S | FileCheck %s --check-prefix=NOTHINLTO ; ; CHECK-NOT: !{!"ProfileFormat", !"SampleProfile"} diff --git a/llvm/test/Transforms/SampleProfile/fnptr.ll b/llvm/test/Transforms/SampleProfile/fnptr.ll --- a/llvm/test/Transforms/SampleProfile/fnptr.ll +++ b/llvm/test/Transforms/SampleProfile/fnptr.ll @@ -2,11 +2,11 @@ ; formats. This checks that we produce the same profile annotations regardless ; of the profile format. ; -; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/fnptr.prof | opt -analyze -branch-prob -enable-new-pm=0 | FileCheck %s -; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/fnptr.binprof | opt -analyze -branch-prob -enable-new-pm=0| FileCheck %s +; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/fnptr.prof | opt -analyze -branch-prob | FileCheck %s +; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/fnptr.binprof | opt -analyze -branch-prob | FileCheck %s -; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/fnptr.prof | opt -passes='print' -disable-output 2>&1 | FileCheck %s -; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/fnptr.binprof | opt -passes='print' -disable-output 2>&1 | FileCheck %s +; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/fnptr.prof | opt -analyze -branch-prob | FileCheck %s +; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/fnptr.binprof | opt -analyze -branch-prob | FileCheck %s ; CHECK: edge for.body3 -> if.then probability is 0x1a56a56a / 0x80000000 = 20.58% ; CHECK: edge for.body3 -> if.else probability is 0x65a95a96 / 0x80000000 = 79.42% diff --git a/llvm/test/Transforms/SampleProfile/inline-mergeprof.ll b/llvm/test/Transforms/SampleProfile/inline-mergeprof.ll --- a/llvm/test/Transforms/SampleProfile/inline-mergeprof.ll +++ b/llvm/test/Transforms/SampleProfile/inline-mergeprof.ll @@ -1,6 +1,6 @@ ; Test we lose details of not inlined profile without '-sample-profile-merge-inlinee' -; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/inline-mergeprof.prof -sample-profile-merge-inlinee=false -enable-new-pm=0 -S | FileCheck -check-prefix=SCALE %s -; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/inline-mergeprof.prof -sample-profile-merge-inlinee=true -enable-new-pm=0 -S | FileCheck -check-prefix=SCALE %s +; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/inline-mergeprof.prof -sample-profile-merge-inlinee=false -S | FileCheck -check-prefix=SCALE %s +; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/inline-mergeprof.prof -sample-profile-merge-inlinee=true -S | FileCheck -check-prefix=SCALE %s ; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/inline-mergeprof.prof -sample-profile-merge-inlinee=false -S | FileCheck -check-prefix=SCALE %s ; Test we properly merge not inlined profile with '-sample-profile-merge-inlinee' diff --git a/llvm/test/Transforms/SampleProfile/offset.ll b/llvm/test/Transforms/SampleProfile/offset.ll --- a/llvm/test/Transforms/SampleProfile/offset.ll +++ b/llvm/test/Transforms/SampleProfile/offset.ll @@ -1,5 +1,5 @@ -; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/offset.prof | opt -analyze -branch-prob -enable-new-pm=0 | FileCheck %s -; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/offset.prof | opt -passes='print' -disable-output 2>&1 | FileCheck %s +; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/offset.prof | opt -analyze -branch-prob | FileCheck %s +; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/offset.prof | opt -analyze -branch-prob | FileCheck %s ; Original C++ code for this test case: ; diff --git a/llvm/test/Transforms/SampleProfile/profile-sample-accurate.ll b/llvm/test/Transforms/SampleProfile/profile-sample-accurate.ll --- a/llvm/test/Transforms/SampleProfile/profile-sample-accurate.ll +++ b/llvm/test/Transforms/SampleProfile/profile-sample-accurate.ll @@ -1,17 +1,17 @@ -; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/profsampleacc.extbinary.afdo -profile-summary-cutoff-hot=600000 -profile-sample-accurate -enable-new-pm=0 -S | FileCheck %s --check-prefix=CALL_SUM_IS_WARM +; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/profsampleacc.extbinary.afdo -profile-summary-cutoff-hot=600000 -profile-sample-accurate -S | FileCheck %s --check-prefix=CALL_SUM_IS_WARM ; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/profsampleacc.extbinary.afdo -profile-summary-cutoff-hot=900000 -profile-sample-accurate -S | FileCheck %s --check-prefix=CALL_SUM_IS_HOT -; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/profsampleacc.extbinary.afdo -profile-summary-cutoff-hot=600000 -profile-sample-accurate -enable-new-pm=0 -S | FileCheck %s --check-prefix=CALL_SUM_IS_WARM +; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/profsampleacc.extbinary.afdo -profile-summary-cutoff-hot=600000 -profile-sample-accurate -S | FileCheck %s --check-prefix=CALL_SUM_IS_WARM ; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/profsampleacc.extbinary.afdo -profile-summary-cutoff-hot=900000 -profile-sample-accurate -S | FileCheck %s --check-prefix=CALL_SUM_IS_HOT ; RUN: llvm-profdata merge -sample -extbinary -prof-sym-list=%S/Inputs/profile-symbol-list.text %S/Inputs/profsampleacc.extbinary.afdo -o %t.symlist.afdo -; RUN: opt < %s -sample-profile -sample-profile-file=%t.symlist.afdo -profile-summary-cutoff-hot=600000 -profile-accurate-for-symsinlist -enable-new-pm=0 -S | FileCheck %s --check-prefix=PROFSYMLIST +; RUN: opt < %s -sample-profile -sample-profile-file=%t.symlist.afdo -profile-summary-cutoff-hot=600000 -profile-accurate-for-symsinlist -S | FileCheck %s --check-prefix=PROFSYMLIST ; RUN: opt < %s -passes=sample-profile -sample-profile-file=%t.symlist.afdo -profile-summary-cutoff-hot=600000 -profile-accurate-for-symsinlist -S | FileCheck %s --check-prefix=PROFSYMLIST ; ; If -profile-accurate-for-symsinlist and -profile-sample-accurate both present, ; -profile-sample-accurate will override -profile-accurate-for-symsinlist. -; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/profsampleacc.extbinary.afdo -profile-summary-cutoff-hot=600000 -profile-sample-accurate -profile-accurate-for-symsinlist -enable-new-pm=0 -S | FileCheck %s --check-prefix=CALL_SUM_IS_WARM +; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/profsampleacc.extbinary.afdo -profile-summary-cutoff-hot=600000 -profile-sample-accurate -profile-accurate-for-symsinlist -S | FileCheck %s --check-prefix=CALL_SUM_IS_WARM ; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/profsampleacc.extbinary.afdo -profile-summary-cutoff-hot=900000 -profile-sample-accurate -profile-accurate-for-symsinlist -S | FileCheck %s --check-prefix=CALL_SUM_IS_HOT -; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/profsampleacc.extbinary.afdo -profile-summary-cutoff-hot=600000 -profile-sample-accurate -profile-accurate-for-symsinlist -enable-new-pm=0 -S | FileCheck %s --check-prefix=CALL_SUM_IS_WARM +; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/profsampleacc.extbinary.afdo -profile-summary-cutoff-hot=600000 -profile-sample-accurate -profile-accurate-for-symsinlist -S | FileCheck %s --check-prefix=CALL_SUM_IS_WARM ; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/profsampleacc.extbinary.afdo -profile-summary-cutoff-hot=900000 -profile-sample-accurate -profile-accurate-for-symsinlist -S | FileCheck %s --check-prefix=CALL_SUM_IS_HOT ; ; Original C++ test case diff --git a/llvm/test/Transforms/SampleProfile/propagate.ll b/llvm/test/Transforms/SampleProfile/propagate.ll --- a/llvm/test/Transforms/SampleProfile/propagate.ll +++ b/llvm/test/Transforms/SampleProfile/propagate.ll @@ -1,5 +1,5 @@ -; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/propagate.prof | opt -analyze -branch-prob -enable-new-pm=0 | FileCheck %s -; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/propagate.prof | opt -passes='print' -disable-output 2>&1 | FileCheck %s +; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/propagate.prof | opt -analyze -branch-prob | FileCheck %s +; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/propagate.prof | opt -analyze -branch-prob | FileCheck %s ; Original C++ code for this test case: ; diff --git a/llvm/test/Transforms/SampleProfile/remap.ll b/llvm/test/Transforms/SampleProfile/remap.ll --- a/llvm/test/Transforms/SampleProfile/remap.ll +++ b/llvm/test/Transforms/SampleProfile/remap.ll @@ -1,15 +1,15 @@ -; RUN: opt %s -passes=sample-profile -sample-profile-file=%S/Inputs/remap.prof -sample-profile-remapping-file=%S/Inputs/remap.map | opt -passes='print' -disable-output 2>&1 | FileCheck %s +; RUN: opt %s -passes=sample-profile -sample-profile-file=%S/Inputs/remap.prof -sample-profile-remapping-file=%S/Inputs/remap.map | opt -analyze -branch-prob | FileCheck %s ; ; Check whether profile remapping work with loading profile on demand used by extbinary format profile. ; RUN: llvm-profdata merge -sample -extbinary %S/Inputs/remap.prof -o %t.extbinary.afdo -; RUN: opt %s -passes=sample-profile -sample-profile-file=%t.extbinary.afdo -sample-profile-remapping-file=%S/Inputs/remap.map | opt -passes='print' -disable-output 2>&1 | FileCheck %s +; RUN: opt %s -passes=sample-profile -sample-profile-file=%t.extbinary.afdo -sample-profile-remapping-file=%S/Inputs/remap.map | opt -analyze -branch-prob | FileCheck %s ; ; Reduced from branch.ll declare i1 @foo() define void @_ZN3foo3barERKN1M1XINS_6detail3quxEEE() #0 !dbg !2 { -; CHECK: Printing analysis {{.*}} for function '_ZN3foo3barERKN1M1XINS_6detail3quxEEE': +; CHECK: Printing analysis 'Branch Probability Analysis' for function '_ZN3foo3barERKN1M1XINS_6detail3quxEEE': entry: %cmp = call i1 @foo(), !dbg !6 diff --git a/llvm/tools/opt/NewPMDriver.cpp b/llvm/tools/opt/NewPMDriver.cpp --- a/llvm/tools/opt/NewPMDriver.cpp +++ b/llvm/tools/opt/NewPMDriver.cpp @@ -375,9 +375,6 @@ PB.registerLoopAnalyses(LAM); PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); - if (TM) - TM->registerPassBuilderCallbacks(PB, DebugPM); - ModulePassManager MPM(DebugPM); if (VK > VK_NoVerifier) MPM.addPass(VerifierPass()); diff --git a/mlir/include/mlir/Dialect/Async/IR/Async.h b/mlir/include/mlir/Dialect/Async/IR/Async.h --- a/mlir/include/mlir/Dialect/Async/IR/Async.h +++ b/mlir/include/mlir/Dialect/Async/IR/Async.h @@ -22,28 +22,12 @@ namespace mlir { namespace async { -namespace detail { -struct ValueTypeStorage; -} // namespace detail - /// The token type to represent asynchronous operation completion. class TokenType : public Type::TypeBase { public: using Base::Base; }; -/// The value type to represent values returned from asynchronous operations. -class ValueType - : public Type::TypeBase { -public: - using Base::Base; - - /// Get or create an async ValueType with the provided value type. - static ValueType get(Type valueType); - - Type getValueType(); -}; - } // namespace async } // namespace mlir diff --git a/mlir/include/mlir/Dialect/Async/IR/AsyncBase.td b/mlir/include/mlir/Dialect/Async/IR/AsyncBase.td --- a/mlir/include/mlir/Dialect/Async/IR/AsyncBase.td +++ b/mlir/include/mlir/Dialect/Async/IR/AsyncBase.td @@ -39,24 +39,4 @@ }]; } -class Async_ValueType - : DialectType()">, - SubstLeaves<"$_self", - "$_self.cast<::mlir::async::ValueType>().getValueType()", - type.predicate> - ]>, "async value type with " # type.description # " underlying type"> { - let typeDescription = [{ - `async.value` represents a value returned by asynchronous operations, - which may or may not be available currently, but will be available at some - point in the future. - }]; - - Type valueType = type; -} - -def Async_AnyValueType : Type()">, - "async value type">; - #endif // ASYNC_BASE_TD diff --git a/mlir/include/mlir/Dialect/Async/IR/AsyncOps.td b/mlir/include/mlir/Dialect/Async/IR/AsyncOps.td --- a/mlir/include/mlir/Dialect/Async/IR/AsyncOps.td +++ b/mlir/include/mlir/Dialect/Async/IR/AsyncOps.td @@ -40,24 +40,24 @@ state). All dependencies must be made explicit with async execute arguments (`async.token` or `async.value`). + Example: + ```mlir - %done, %values = async.execute { - %0 = "compute0"(...) : !some.type - async.yield %1 : f32 - } : !async.token, !async.value + %0 = async.execute { + "compute0"(...) + async.yield + } : !async.token - %1 = "compute1"(...) : !some.type + %1 = "compute1"(...) ``` }]; // TODO: Take async.tokens/async.values as arguments. let arguments = (ins ); - let results = (outs Async_TokenType:$done, - Variadic:$values); + let results = (outs Async_TokenType:$done); let regions = (region SizedRegion<1>:$body); - let printer = [{ return ::mlir::async::print(p, *this); }]; - let parser = [{ return ::mlir::async::parse$cppClass(parser, result); }]; + let assemblyFormat = "$body attr-dict `:` type($done)"; } def Async_YieldOp : @@ -71,8 +71,6 @@ let arguments = (ins Variadic:$operands); let assemblyFormat = "attr-dict ($operands^ `:` type($operands))?"; - - let verifier = [{ return ::mlir::async::verify(*this); }]; } #endif // ASYNC_OPS diff --git a/mlir/include/mlir/Dialect/Vector/VectorOps.td b/mlir/include/mlir/Dialect/Vector/VectorOps.td --- a/mlir/include/mlir/Dialect/Vector/VectorOps.td +++ b/mlir/include/mlir/Dialect/Vector/VectorOps.td @@ -454,71 +454,6 @@ }]; } -def Vector_ExtractMapOp : - Vector_Op<"extract_map", [NoSideEffect]>, - Arguments<(ins AnyVector:$vector, Index:$id, I64Attr:$multiplicity)>, - Results<(outs AnyVector)> { - let summary = "vector extract map operation"; - let description = [{ - Takes an 1-D vector and extract a sub-part of the vector starting at id with - a size of `vector size / multiplicity`. This maps a given multiplicity of - the vector to a Value such as a loop induction variable or an SPMD id. - - Similarly to vector.tuple_get, this operation is used for progressive - lowering and should be folded away before converting to LLVM. - - - For instance, the following code: - ```mlir - %a = vector.transfer_read %A[%c0]: memref<32xf32>, vector<32xf32> - %b = vector.transfer_read %B[%c0]: memref<32xf32>, vector<32xf32> - %c = addf %a, %b: vector<32xf32> - vector.transfer_write %c, %C[%c0]: memref<32xf32>, vector<32xf32> - ``` - can be rewritten to: - ```mlir - %a = vector.transfer_read %A[%c0]: memref<32xf32>, vector<32xf32> - %b = vector.transfer_read %B[%c0]: memref<32xf32>, vector<32xf32> - %ea = vector.extract_map %a[%id : 32] : vector<32xf32> to vector<1xf32> - %eb = vector.extract_map %b[%id : 32] : vector<32xf32> to vector<1xf32> - %ec = addf %ea, %eb : vector<1xf32> - %c = vector.insert_map %ec, %id, 32 : vector<1xf32> to vector<32xf32> - vector.transfer_write %c, %C[%c0]: memref<32xf32>, vector<32xf32> - ``` - - Where %id can be an induction variable or an SPMD id going from 0 to 31. - - And then be rewritten to: - ```mlir - %a = vector.transfer_read %A[%id]: memref<32xf32>, vector<1xf32> - %b = vector.transfer_read %B[%id]: memref<32xf32>, vector<1xf32> - %c = addf %a, %b: vector<1xf32> - vector.transfer_write %c, %C[%id]: memref<32xf32>, vector<1xf32> - ``` - - Example: - - ```mlir - %ev = vector.extract_map %v[%id:32] : vector<32xf32> to vector<1xf32> - ``` - }]; - let builders = [OpBuilder< - "OpBuilder &builder, OperationState &result, " # - "Value vector, Value id, int64_t multiplicity">]; - let extraClassDeclaration = [{ - VectorType getSourceVectorType() { - return vector().getType().cast(); - } - VectorType getResultType() { - return getResult().getType().cast(); - } - }]; - let assemblyFormat = [{ - $vector `[` $id `:` $multiplicity `]` attr-dict `:` type($vector) `to` - type(results) - }]; -} - def Vector_FMAOp : Op]>, @@ -691,46 +626,6 @@ }]; } -def Vector_InsertMapOp : - Vector_Op<"insert_map", [NoSideEffect]>, - Arguments<(ins AnyVector:$vector, Index:$id, I64Attr:$multiplicity)>, - Results<(outs AnyVector)> { - let summary = "vector insert map operation"; - let description = [{ - insert an 1-D vector and within a larger vector starting at id. The new - vector created will have a size of `vector size * multiplicity`. This - represents how a sub-part of the vector is written for a given Value such as - a loop induction variable or an SPMD id. - - Similarly to vector.tuple_get, this operation is used for progressive - lowering and should be folded away before converting to LLVM. - - This operations is meant to be used in combination with vector.extract_map. - See example in extract.map description. - - Example: - - ```mlir - %v = vector.insert_map %ev, %id, 32 : vector<1xf32> to vector<32xf32> - ``` - }]; - let builders = [OpBuilder< - "OpBuilder &builder, OperationState &result, " # - "Value vector, Value id, int64_t multiplicity">]; - let extraClassDeclaration = [{ - VectorType getSourceVectorType() { - return vector().getType().cast(); - } - VectorType getResultType() { - return getResult().getType().cast(); - } - }]; - let assemblyFormat = [{ - $vector `,` $id `,` $multiplicity attr-dict `:` type($vector) `to` - type(results) - }]; -} - def Vector_InsertStridedSliceOp : Vector_Op<"insert_strided_slice", [NoSideEffect, PredOpTrait<"operand #0 and result have same element type", diff --git a/mlir/include/mlir/Dialect/Vector/VectorTransforms.h b/mlir/include/mlir/Dialect/Vector/VectorTransforms.h --- a/mlir/include/mlir/Dialect/Vector/VectorTransforms.h +++ b/mlir/include/mlir/Dialect/Vector/VectorTransforms.h @@ -172,47 +172,6 @@ FilterConstraintType filter; }; -struct DistributeOps { - ExtractMapOp extract; - InsertMapOp insert; -}; - -/// Distribute a 1D vector pointwise operation over a range of given IDs taking -/// *all* values in [0 .. multiplicity - 1] (e.g. loop induction variable or -/// SPMD id). This transformation only inserts -/// vector.extract_map/vector.insert_map. It is meant to be used with -/// canonicalizations pattern to propagate and fold the vector -/// insert_map/extract_map operations. -/// Transforms: -// %v = addf %a, %b : vector<32xf32> -/// to: -/// %v = addf %a, %b : vector<32xf32> %ev = -/// vector.extract_map %v, %id, 32 : vector<32xf32> into vector<1xf32> %nv = -/// vector.insert_map %ev, %id, 32 : vector<1xf32> into vector<32xf32> -Optional distributPointwiseVectorOp(OpBuilder &builder, - Operation *op, Value id, - int64_t multiplicity); -/// Canonicalize an extra element using the result of a pointwise operation. -/// Transforms: -/// %v = addf %a, %b : vector32xf32> -/// %dv = vector.extract_map %v, %id, 32 : vector<32xf32> into vector<1xf32> -/// to: -/// %da = vector.extract_map %a, %id, 32 : vector<32xf32> into vector<1xf32> -/// %db = vector.extract_map %a, %id, 32 : vector<32xf32> into vector<1xf32> -/// %dv = addf %da, %db : vector<1xf32> -struct PointwiseExtractPattern : public OpRewritePattern { - using FilterConstraintType = std::function; - PointwiseExtractPattern( - MLIRContext *context, FilterConstraintType constraint = - [](ExtractMapOp op) { return success(); }) - : OpRewritePattern(context), filter(constraint) {} - LogicalResult matchAndRewrite(ExtractMapOp extract, - PatternRewriter &rewriter) const override; - -private: - FilterConstraintType filter; -}; - } // namespace vector //===----------------------------------------------------------------------===// diff --git a/mlir/lib/Dialect/Async/IR/Async.cpp b/mlir/lib/Dialect/Async/IR/Async.cpp --- a/mlir/lib/Dialect/Async/IR/Async.cpp +++ b/mlir/lib/Dialect/Async/IR/Async.cpp @@ -19,8 +19,8 @@ #include "llvm/ADT/TypeSwitch.h" #include "llvm/Support/raw_ostream.h" -namespace mlir { -namespace async { +using namespace mlir; +using namespace mlir::async; void AsyncDialect::initialize() { addOperations< @@ -28,7 +28,6 @@ #include "mlir/Dialect/Async/IR/AsyncOps.cpp.inc" >(); addTypes(); - addTypes(); } /// Parse a type registered to this dialect. @@ -40,15 +39,6 @@ if (keyword == "token") return TokenType::get(getContext()); - if (keyword == "value") { - Type ty; - if (parser.parseLess() || parser.parseType(ty) || parser.parseGreater()) { - parser.emitError(parser.getNameLoc(), "failed to parse async value type"); - return Type(); - } - return ValueType::get(ty); - } - parser.emitError(parser.getNameLoc(), "unknown async type: ") << keyword; return Type(); } @@ -56,113 +46,9 @@ /// Print a type registered to this dialect. void AsyncDialect::printType(Type type, DialectAsmPrinter &os) const { TypeSwitch(type) - .Case([&](TokenType) { os << "token"; }) - .Case([&](ValueType valueTy) { - os << "value<"; - os.printType(valueTy.getValueType()); - os << '>'; - }) + .Case([&](Type) { os << "token"; }) .Default([](Type) { llvm_unreachable("unexpected 'async' type kind"); }); } -//===----------------------------------------------------------------------===// -/// ValueType -//===----------------------------------------------------------------------===// - -namespace detail { - -// Storage for `async.value` type, the only member is the wrapped type. -struct ValueTypeStorage : public TypeStorage { - ValueTypeStorage(Type valueType) : valueType(valueType) {} - - /// The hash key used for uniquing. - using KeyTy = Type; - bool operator==(const KeyTy &key) const { return key == valueType; } - - /// Construction. - static ValueTypeStorage *construct(TypeStorageAllocator &allocator, - Type valueType) { - return new (allocator.allocate()) - ValueTypeStorage(valueType); - } - - Type valueType; -}; - -} // namespace detail - -ValueType ValueType::get(Type valueType) { - return Base::get(valueType.getContext(), valueType); -} - -Type ValueType::getValueType() { return getImpl()->valueType; } - -//===----------------------------------------------------------------------===// -// YieldOp -//===----------------------------------------------------------------------===// - -static LogicalResult verify(YieldOp op) { - // Get the underlying value types from async values returned from the - // parent `async.execute` operation. - auto executeOp = op.getParentOfType(); - auto types = llvm::map_range(executeOp.values(), [](const OpResult &result) { - return result.getType().cast().getValueType(); - }); - - if (!std::equal(types.begin(), types.end(), op.getOperandTypes().begin())) - return op.emitOpError("Operand types do not match the types returned from " - "the parent ExecuteOp"); - - return success(); -} - -//===----------------------------------------------------------------------===// -/// ExecuteOp -//===----------------------------------------------------------------------===// - -static void print(OpAsmPrinter &p, ExecuteOp op) { - p << "async.execute "; - p.printRegion(op.body()); - p.printOptionalAttrDict(op.getAttrs()); - p << " : "; - p.printType(op.done().getType()); - if (!op.values().empty()) - p << ", "; - llvm::interleaveComma(op.values(), p, [&](const OpResult &result) { - p.printType(result.getType()); - }); -} - -static ParseResult parseExecuteOp(OpAsmParser &parser, OperationState &result) { - MLIRContext *ctx = result.getContext(); - - // Parse asynchronous region. - Region *body = result.addRegion(); - if (parser.parseRegion(*body, /*arguments=*/{}, /*argTypes=*/{}, - /*enableNameShadowing=*/false)) - return failure(); - - // Parse operation attributes. - NamedAttrList attrs; - if (parser.parseOptionalAttrDict(attrs)) - return failure(); - result.addAttributes(attrs); - - // Parse result types. - SmallVector resultTypes; - if (parser.parseColonTypeList(resultTypes)) - return failure(); - - // First result type must be an async token type. - if (resultTypes.empty() || resultTypes.front() != TokenType::get(ctx)) - return failure(); - parser.addTypesToList(resultTypes, result.types); - - return success(); -} - -} // namespace async -} // namespace mlir - #define GET_OP_CLASSES #include "mlir/Dialect/Async/IR/AsyncOps.cpp.inc" diff --git a/mlir/lib/Dialect/Vector/VectorOps.cpp b/mlir/lib/Dialect/Vector/VectorOps.cpp --- a/mlir/lib/Dialect/Vector/VectorOps.cpp +++ b/mlir/lib/Dialect/Vector/VectorOps.cpp @@ -901,29 +901,6 @@ } //===----------------------------------------------------------------------===// -// ExtractMapOp -//===----------------------------------------------------------------------===// - -void ExtractMapOp::build(OpBuilder &builder, OperationState &result, - Value vector, Value id, int64_t multiplicity) { - VectorType type = vector.getType().cast(); - VectorType resultType = VectorType::get(type.getNumElements() / multiplicity, - type.getElementType()); - ExtractMapOp::build(builder, result, resultType, vector, id, multiplicity); -} - -static LogicalResult verify(ExtractMapOp op) { - if (op.getSourceVectorType().getShape().size() != 1 || - op.getResultType().getShape().size() != 1) - return op.emitOpError("expects source and destination vectors of rank 1"); - if (op.getResultType().getNumElements() * (int64_t)op.multiplicity() != - op.getSourceVectorType().getNumElements()) - return op.emitOpError("vector sizes mismatch. Source size must be equal " - "to destination size * multiplicity"); - return success(); -} - -//===----------------------------------------------------------------------===// // BroadcastOp //===----------------------------------------------------------------------===// @@ -1146,30 +1123,6 @@ } //===----------------------------------------------------------------------===// -// InsertMapOp -//===----------------------------------------------------------------------===// - -void InsertMapOp::build(OpBuilder &builder, OperationState &result, - Value vector, Value id, int64_t multiplicity) { - VectorType type = vector.getType().cast(); - VectorType resultType = VectorType::get(type.getNumElements() * multiplicity, - type.getElementType()); - InsertMapOp::build(builder, result, resultType, vector, id, multiplicity); -} - -static LogicalResult verify(InsertMapOp op) { - if (op.getSourceVectorType().getShape().size() != 1 || - op.getResultType().getShape().size() != 1) - return op.emitOpError("expected source and destination vectors of rank 1"); - if ((int64_t)op.multiplicity() * op.getSourceVectorType().getNumElements() != - op.getResultType().getNumElements()) - return op.emitOpError( - "vector sizes mismatch. Destination size must be equal " - "to source size * multiplicity"); - return success(); -} - -//===----------------------------------------------------------------------===// // InsertStridedSliceOp //===----------------------------------------------------------------------===// diff --git a/mlir/lib/Dialect/Vector/VectorTransforms.cpp b/mlir/lib/Dialect/Vector/VectorTransforms.cpp --- a/mlir/lib/Dialect/Vector/VectorTransforms.cpp +++ b/mlir/lib/Dialect/Vector/VectorTransforms.cpp @@ -2418,40 +2418,6 @@ return failure(); } -LogicalResult mlir::vector::PointwiseExtractPattern::matchAndRewrite( - ExtractMapOp extract, PatternRewriter &rewriter) const { - Operation *definedOp = extract.vector().getDefiningOp(); - if (!definedOp || definedOp->getNumResults() != 1) - return failure(); - // TODO: Create an interfaceOp for elementwise operations. - if (!isa(definedOp)) - return failure(); - Location loc = extract.getLoc(); - SmallVector extractOperands; - for (OpOperand &operand : definedOp->getOpOperands()) - extractOperands.push_back(rewriter.create( - loc, operand.get(), extract.id(), extract.multiplicity())); - Operation *newOp = cloneOpWithOperandsAndTypes( - rewriter, loc, definedOp, extractOperands, extract.getResult().getType()); - rewriter.replaceOp(extract, newOp->getResult(0)); - return success(); -} - -Optional -mlir::vector::distributPointwiseVectorOp(OpBuilder &builder, Operation *op, - Value id, int64_t multiplicity) { - OpBuilder::InsertionGuard guard(builder); - builder.setInsertionPointAfter(op); - Location loc = op->getLoc(); - Value result = op->getResult(0); - DistributeOps ops; - ops.extract = - builder.create(loc, result, id, multiplicity); - ops.insert = - builder.create(loc, ops.extract, id, multiplicity); - return ops; -} - // TODO: Add pattern to rewrite ExtractSlices(ConstantMaskOp). // TODO: Add this as DRR pattern. void mlir::vector::populateVectorToVectorTransformationPatterns( diff --git a/mlir/test/Dialect/Async/ops.mlir b/mlir/test/Dialect/Async/ops.mlir --- a/mlir/test/Dialect/Async/ops.mlir +++ b/mlir/test/Dialect/Async/ops.mlir @@ -1,46 +1,16 @@ // RUN: mlir-opt %s | FileCheck %s -// CHECK-LABEL: @identity_token -func @identity_token(%arg0 : !async.token) -> !async.token { +// CHECK-LABEL: @identity +func @identity(%arg0 : !async.token) -> !async.token { // CHECK: return %arg0 : !async.token return %arg0 : !async.token } -// CHECK-LABEL: @identity_value -func @identity_value(%arg0 : !async.value) -> !async.value { - // CHECK: return %arg0 : !async.value - return %arg0 : !async.value -} - // CHECK-LABEL: @empty_async_execute func @empty_async_execute() -> !async.token { - %done = async.execute { + %0 = async.execute { async.yield } : !async.token - // CHECK: return %done : !async.token - return %done : !async.token -} - -// CHECK-LABEL: @return_async_value -func @return_async_value() -> !async.value { - %done, %values = async.execute { - %cst = constant 1.000000e+00 : f32 - async.yield %cst : f32 - } : !async.token, !async.value - - // CHECK: return %values : !async.value - return %values : !async.value -} - -// CHECK-LABEL: @return_async_values -func @return_async_values() -> (!async.value, !async.value) { - %done, %values:2 = async.execute { - %cst1 = constant 1.000000e+00 : f32 - %cst2 = constant 2.000000e+00 : f32 - async.yield %cst1, %cst2 : f32, f32 - } : !async.token, !async.value, !async.value - - // CHECK: return %values#0, %values#1 : !async.value, !async.value - return %values#0, %values#1 : !async.value, !async.value + return %0 : !async.token } diff --git a/mlir/test/Dialect/Vector/invalid.mlir b/mlir/test/Dialect/Vector/invalid.mlir --- a/mlir/test/Dialect/Vector/invalid.mlir +++ b/mlir/test/Dialect/Vector/invalid.mlir @@ -1328,31 +1328,3 @@ // expected-error@+1 {{'vector.compressstore' op expected value dim to match mask dim}} vector.compressstore %base, %mask, %value : memref, vector<17xi1>, vector<16xf32> } - -// ----- - -func @extract_map_rank(%v: vector<2x32xf32>, %id : index) { - // expected-error@+1 {{'vector.extract_map' op expects source and destination vectors of rank 1}} - %0 = vector.extract_map %v[%id : 32] : vector<2x32xf32> to vector<2x1xf32> -} - -// ----- - -func @extract_map_size(%v: vector<63xf32>, %id : index) { - // expected-error@+1 {{'vector.extract_map' op vector sizes mismatch. Source size must be equal to destination size * multiplicity}} - %0 = vector.extract_map %v[%id : 32] : vector<63xf32> to vector<2xf32> -} - -// ----- - -func @insert_map_rank(%v: vector<2x1xf32>, %id : index) { - // expected-error@+1 {{'vector.insert_map' op expected source and destination vectors of rank 1}} - %0 = vector.insert_map %v, %id, 32 : vector<2x1xf32> to vector<2x32xf32> -} - -// ----- - -func @insert_map_size(%v: vector<1xf32>, %id : index) { - // expected-error@+1 {{'vector.insert_map' op vector sizes mismatch. Destination size must be equal to source size * multiplicity}} - %0 = vector.insert_map %v, %id, 32 : vector<1xf32> to vector<64xf32> -} diff --git a/mlir/test/Dialect/Vector/ops.mlir b/mlir/test/Dialect/Vector/ops.mlir --- a/mlir/test/Dialect/Vector/ops.mlir +++ b/mlir/test/Dialect/Vector/ops.mlir @@ -432,14 +432,3 @@ vector.compressstore %base, %mask, %0 : memref, vector<16xi1>, vector<16xf32> return } - -// CHECK-LABEL: @extract_insert_map -func @extract_insert_map(%v: vector<32xf32>, %id : index) -> vector<32xf32> { - // CHECK: %[[V:.*]] = vector.extract_map %{{.*}}[%{{.*}} : 16] : vector<32xf32> to vector<2xf32> - %vd = vector.extract_map %v[%id : 16] : vector<32xf32> to vector<2xf32> - // CHECK: %[[R:.*]] = vector.insert_map %[[V]], %{{.*}}, 16 : vector<2xf32> to vector<32xf32> - %r = vector.insert_map %vd, %id, 16 : vector<2xf32> to vector<32xf32> - // CHECK: return %[[R]] : vector<32xf32> - return %r : vector<32xf32> -} - diff --git a/mlir/test/Dialect/Vector/vector-distribution.mlir b/mlir/test/Dialect/Vector/vector-distribution.mlir deleted file mode 100644 --- a/mlir/test/Dialect/Vector/vector-distribution.mlir +++ /dev/null @@ -1,13 +0,0 @@ -// RUN: mlir-opt %s -test-vector-distribute-patterns | FileCheck %s - -// CHECK-LABEL: func @distribute_vector_add -// CHECK-SAME: (%[[ID:.*]]: index -// CHECK-NEXT: %[[EXA:.*]] = vector.extract_map %{{.*}}[%[[ID]] : 32] : vector<32xf32> to vector<1xf32> -// CHECK-NEXT: %[[EXB:.*]] = vector.extract_map %{{.*}}[%[[ID]] : 32] : vector<32xf32> to vector<1xf32> -// CHECK-NEXT: %[[ADD:.*]] = addf %[[EXA]], %[[EXB]] : vector<1xf32> -// CHECK-NEXT: %[[INS:.*]] = vector.insert_map %[[ADD]], %[[ID]], 32 : vector<1xf32> to vector<32xf32> -// CHECK-NEXT: return %[[INS]] : vector<32xf32> -func @distribute_vector_add(%id : index, %A: vector<32xf32>, %B: vector<32xf32>) -> vector<32xf32> { - %0 = addf %A, %B : vector<32xf32> - return %0: vector<32xf32> -} diff --git a/mlir/test/lib/Transforms/TestVectorTransforms.cpp b/mlir/test/lib/Transforms/TestVectorTransforms.cpp --- a/mlir/test/lib/Transforms/TestVectorTransforms.cpp +++ b/mlir/test/lib/Transforms/TestVectorTransforms.cpp @@ -125,28 +125,6 @@ } }; -struct TestVectorDistributePatterns - : public PassWrapper { - void getDependentDialects(DialectRegistry ®istry) const override { - registry.insert(); - } - void runOnFunction() override { - MLIRContext *ctx = &getContext(); - OwningRewritePatternList patterns; - FuncOp func = getFunction(); - func.walk([&](AddFOp op) { - OpBuilder builder(op); - Optional ops = distributPointwiseVectorOp( - builder, op.getOperation(), func.getArgument(0), 32); - assert(ops.hasValue()); - SmallPtrSet extractOp({ops->extract}); - op.getResult().replaceAllUsesExcept(ops->insert.getResult(), extractOp); - }); - patterns.insert(ctx); - applyPatternsAndFoldGreedily(getFunction(), patterns); - } -}; - struct TestVectorTransferFullPartialSplitPatterns : public PassWrapper { @@ -200,9 +178,5 @@ vectorTransformFullPartialPass("test-vector-transfer-full-partial-split", "Test conversion patterns to split " "transfer ops via scf.if + linalg ops"); - PassRegistration distributePass( - "test-vector-distribute-patterns", - "Test conversion patterns to distribute vector ops in the vector " - "dialect"); } } // namespace mlir diff --git a/mlir/utils/gdb-scripts/prettyprinters.py b/mlir/utils/gdb-scripts/prettyprinters.py deleted file mode 100644 --- a/mlir/utils/gdb-scripts/prettyprinters.py +++ /dev/null @@ -1,235 +0,0 @@ -"""GDB pretty printers for MLIR types.""" - -import gdb.printing - - -class IdentifierPrinter: - """Prints an mlir::Identifier instance.""" - - def __init__(self, val): - self.entry = val['entry'] - - def to_string(self): - ptr = (self.entry + 1).cast(gdb.lookup_type('char').pointer()) - return ptr.string(length=self.entry['keyLength']) - - def display_hint(self): - return 'string' - - -class StoragePrinter: - """Prints bases of a struct and its fields.""" - - def __init__(self, val): - self.val = val - - def children(self): - for field in self.val.type.fields(): - if field.is_base_class: - yield ('<%s>' % field.name, self.val.cast(field.type)) - else: - yield (field.name, self.val[field.name]) - - -class TupleTypeStoragePrinter(StoragePrinter): - - def children(self): - for child in StoragePrinter.children(self): - yield child - pointer_type = gdb.lookup_type('mlir::Type').pointer() - elements = (self.val.address + 1).cast(pointer_type) - for i in range(self.val['numElements']): - yield 'elements[%u]' % i, elements[i] - - -class RankedTypeStoragePrinter(StoragePrinter): - - def children(self): - for child in StoragePrinter.children(self): - yield child - for i in range(self.val['shapeSize']): - yield 'shapeElements[%u]' % i, self.val['shapeElements'][i] - - -class MemRefTypeStoragePrinter(RankedTypeStoragePrinter): - - def children(self): - for child in RankedTypeStoragePrinter.children(self): - yield child - for i in range(self.val['numAffineMaps']): - yield 'affineMapsList[%u]' % i, self.val['affineMapsList'][i] - - -class FusedLocationStoragePrinter(StoragePrinter): - - def children(self): - for child in StoragePrinter.children(self): - yield child - pointer_type = gdb.lookup_type('mlir::Location').pointer() - elements = (self.val.address + 1).cast(pointer_type) - for i in range(self.val['numLocs']): - yield 'locs[%u]' % i, elements[i] - - -class StorageUserBasePrinter: - """Printer for an mlir::detail::StorageUserBase instance.""" - - def __init__(self, val): - self.val = val - - def children(self): - storage_type = self.val.type.template_argument(2) - yield 'impl', self.val['impl'].dereference().cast(storage_type) - - -class StorageTypeMap: - """Maps a TypeID to the corresponding type derived from StorageUserBase. - - Types need to be registered by name before the first lookup. - """ - - def __init__(self): - self.map = None - self.type_names = [] - - def register_type(self, type_name): - assert not self.map, 'register_type called after __getitem__' - self.type_names += [type_name] - - def _init_map(self): - """Lazy initialization of self.map.""" - if self.map: - return - self.map = {} - for type_name in self.type_names: - concrete_type = gdb.lookup_type(type_name) - storage = gdb.parse_and_eval( - "&'mlir::TypeID::get<%s>()::instance'" % type_name) - if concrete_type and storage: - self.map[int(storage)] = concrete_type - - def __getitem__(self, type_id): - self._init_map() - return self.map.get(int(type_id['storage'])) - - -storage_type_map = StorageTypeMap() - - -def get_type_id_printer(val): - """Returns a printer of the name of a mlir::TypeID.""" - - class StringPrinter: - - def __init__(self, string): - self.string = string - - def to_string(self): - return self.string - - concrete_type = storage_type_map[val] - if not concrete_type: - return None - return StringPrinter('"%s"' % concrete_type.name) - - -def get_attr_or_type_printer(val, get_type_id): - """Returns a printer for mlir::Attribute or mlir::Type.""" - - class UpcastPrinter: - - def __init__(self, val, type): - self.val = val.cast(type) - - def children(self): - yield 'cast<%s>' % self.val.type.name, self.val - - if not val['impl']: - return None - type_id = get_type_id(val['impl'].dereference()) - concrete_type = storage_type_map[type_id] - if not concrete_type: - return None - return UpcastPrinter(val, concrete_type) - - -pp = gdb.printing.RegexpCollectionPrettyPrinter('MLIRSupport') - -pp.add_printer('mlir::Identifier', '^mlir::Identifier$', IdentifierPrinter) - -# Printers for types deriving from AttributeStorage or TypeStorage. -pp.add_printer('mlir::detail::FusedLocationStorage', - '^mlir::detail::FusedLocationStorage', - FusedLocationStoragePrinter) -pp.add_printer('mlir::detail::VectorTypeStorage', - '^mlir::detail::VectorTypeStorage', RankedTypeStoragePrinter) -pp.add_printer('mlir::detail::RankedTensorTypeStorage', - '^mlir::detail::RankedTensorTypeStorage', - RankedTypeStoragePrinter) -pp.add_printer('mlir::detail::MemRefTypeStorage', - '^mlir::detail::MemRefTypeStorage$', MemRefTypeStoragePrinter) -pp.add_printer('mlir::detail::TupleTypeStorage', - '^mlir::detail::TupleTypeStorage$', TupleTypeStoragePrinter) - -# Printers for Attribute::AttrBase or Type::TypeBase typedefs. -pp.add_printer('mlir::detail::StorageUserBase', - '^mlir::detail::StorageUserBase<.*>$', StorageUserBasePrinter) - -# Printers of types deriving from Attribute::AttrBase or Type::TypeBase. -for name in [ - # mlir/IR/Attributes.h - 'ArrayAttr', - 'DictionaryAttr', - 'FloatAttr', - 'IntegerAttr', - 'IntegerSetAttr', - 'OpaqueAttr', - 'StringAttr', - 'SymbolRefAttr', - 'TypeAttr', - 'UnitAttr', - 'DenseStringElementsAttr', - 'DenseIntOrFPElementsAttr', - 'OpaqueElementsAttr', - 'SparseElementsAttr', - # mlir/IR/StandardTypes.h - 'ComplexType', - 'IndexType', - 'IntegerType', - 'Float16Type', - 'Float32Type', - 'Float64Type', - 'NoneType', - 'VectorType', - 'RankedTensorType', - 'UnrankedTensorType', - 'MemRefType', - 'UnrankedMemRefType', - 'TupleType', - # mlir/IR/Location.h - 'CallSiteLoc', - 'FileLineColLoc', - 'FusedLoc', - 'NameLoc', - 'OpaqueLoc', - 'UnknownLoc' -]: - storage_type_map.register_type('mlir::%s' % name) # Register for upcasting. - -pp.add_printer('mlir::TypeID', '^mlir::TypeID$', get_type_id_printer) - - -def add_attr_or_type_printers(name): - """Adds printers for mlir::Attribute or mlir::Type and their Storage type.""" - get_type_id = lambda val: val['abstract%s' % name]['typeID'] - pp.add_printer('mlir::%s' % name, '^mlir::%s$' % name, - lambda val: get_attr_or_type_printer(val, get_type_id)) - pp.add_printer('mlir::%sStorage' % name, '^mlir::%sStorage$' % name, - lambda val: get_type_id_printer(get_type_id(val))) - - -# Upcasting printers of mlir::Attribute and mlir::Type. -for name in ['Attribute', 'Type']: - add_attr_or_type_printers(name) - -gdb.printing.register_pretty_printer(gdb.current_objfile(), pp)