From 429b2a7b3317384313000094f32e2dda7803f4fb Mon Sep 17 00:00:00 2001 From: schittir Date: Thu, 6 Aug 2026 15:31:31 -0400 Subject: [PATCH 001/789] [SYCL][SPIR-V][Windows] Extend BaseSPIRTargetInfo host-adaptation for Windows support (#208196) The existing host-adaptation mechanism in BaseSPIRTargetInfo copies type properties from the host but has gaps causing incorrect behavior on Windows: 1. PointerWidth/PointerAlign, SizeType, PtrDiffType, IntPtrType were not copied from the host; derived classes hardcoded LP64 defaults. 2. getBuiltinVaListKind() returned VoidPtr unconditionally instead of delegating to the host's va_list kind. 3. Derived-class constructors unconditionally overwrote host-adapted values, working on Linux only by coincidence. This patch addresses these issues by copying pointer-related types from the host in BaseSPIRTargetInfo, delegating va_list kind to the host, and setting architecture-appropriate defaults in derived classes when no host is present or when host and device pointer widths differ. TO-DO (follow-up PR): Diagnose invalid host-target pairings. --- clang/lib/Basic/Targets/SPIR.h | 57 ++++++++++-- clang/lib/Driver/ToolChains/SYCL.cpp | 5 ++ clang/lib/Driver/ToolChains/SYCL.h | 3 + .../spirv-host-adaptation-valist.cpp | 24 ++++++ .../Driver/sycl-msvc-version-propagation.cpp | 14 +++ .../spir-host-adaptation-macros.cpp | 36 ++++++++ .../spirv-host-adaptation-macros.cpp | 73 ++++++++++++++++ .../SemaSPIRV/spirv-host-adaptation-types.cpp | 86 +++++++++++++++++++ .../spirv-host-adaptation-valist.cpp | 29 +++++++ 9 files changed, 319 insertions(+), 8 deletions(-) create mode 100644 clang/test/CodeGenSPIRV/spirv-host-adaptation-valist.cpp create mode 100644 clang/test/Driver/sycl-msvc-version-propagation.cpp create mode 100644 clang/test/Preprocessor/spir-host-adaptation-macros.cpp create mode 100644 clang/test/Preprocessor/spirv-host-adaptation-macros.cpp create mode 100644 clang/test/SemaSPIRV/spirv-host-adaptation-types.cpp create mode 100644 clang/test/SemaSPIRV/spirv-host-adaptation-valist.cpp diff --git a/clang/lib/Basic/Targets/SPIR.h b/clang/lib/Basic/Targets/SPIR.h index 9240bd940fa1b..20d8efdc83234 100644 --- a/clang/lib/Basic/Targets/SPIR.h +++ b/clang/lib/Basic/Targets/SPIR.h @@ -72,6 +72,9 @@ class LLVM_LIBRARY_VISIBILITY BaseSPIRTargetInfo : public TargetInfo { std::unique_ptr HostTarget; protected: + // Read-only access for derived classes. Null when there is no host target. + const TargetInfo *getHostTarget() const { return HostTarget.get(); } + BaseSPIRTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : TargetInfo(Triple) { assert((Triple.isSPIR() || Triple.isSPIRV()) && @@ -132,6 +135,16 @@ class LLVM_LIBRARY_VISIBILITY BaseSPIRTargetInfo : public TargetInfo { UseExplicitBitFieldAlignment = HostTarget->useExplicitBitFieldAlignment(); ZeroLengthBitfieldBoundary = HostTarget->getZeroLengthBitfieldBoundary(); + // Copy pointer width and related type representations from host so + // that sizeof(void*), sizeof(size_t), sizeof(ptrdiff_t), and + // sizeof(intptr_t) match between host and device. Without this, + // LLP64 hosts (Windows) get incorrect LP64-style defaults. + PointerWidth = PointerAlign = + HostTarget->getPointerWidth(LangAS::Default); + SizeType = HostTarget->getSizeType(); + PtrDiffType = HostTarget->getPtrDiffType(LangAS::Default); + IntPtrType = HostTarget->getIntPtrType(); + // This is a bit of a lie, but it controls __GCC_ATOMIC_XXX_LOCK_FREE, and // we need those macros to be identical on host and device, because (among // other things) they affect which standard library classes are defined, @@ -159,6 +172,8 @@ class LLVM_LIBRARY_VISIBILITY BaseSPIRTargetInfo : public TargetInfo { } BuiltinVaListKind getBuiltinVaListKind() const override { + if (HostTarget) + return HostTarget->getBuiltinVaListKind(); return TargetInfo::VoidPtrBuiltinVaList; } @@ -239,9 +254,16 @@ class LLVM_LIBRARY_VISIBILITY SPIR32TargetInfo : public SPIRTargetInfo { : SPIRTargetInfo(Triple, Opts) { assert(Triple.getArch() == llvm::Triple::spir && "Invalid architecture for 32-bit SPIR."); + // FIXME: Assert that a present host target's pointer types match the ones + // set below, once the driver diagnoses unsupported host/device combinations + // (until then such an assert would fire on existing tests). PointerWidth = PointerAlign = 32; - SizeType = TargetInfo::UnsignedInt; - PtrDiffType = IntPtrType = TargetInfo::SignedInt; + const TargetInfo *HostTarget = getHostTarget(); + if (!HostTarget || HostTarget->getPointerWidth(LangAS::Default) != 32) { + SizeType = TargetInfo::UnsignedInt; + PtrDiffType = IntPtrType = TargetInfo::SignedInt; + } + // SPIR32 has support for atomic ops if atomic extension is enabled. // Take the maximum because it's possible the Host supports wider types. MaxAtomicInlineWidth = std::max(MaxAtomicInlineWidth, 64); @@ -259,9 +281,16 @@ class LLVM_LIBRARY_VISIBILITY SPIR64TargetInfo : public SPIRTargetInfo { : SPIRTargetInfo(Triple, Opts) { assert(Triple.getArch() == llvm::Triple::spir64 && "Invalid architecture for 64-bit SPIR."); + // FIXME: Assert that a present host target's pointer types match the ones + // set below, once the driver diagnoses unsupported host/device combinations + // (until then such an assert would fire on existing tests). PointerWidth = PointerAlign = 64; - SizeType = TargetInfo::UnsignedLong; - PtrDiffType = IntPtrType = TargetInfo::SignedLong; + const TargetInfo *HostTarget = getHostTarget(); + if (!HostTarget || HostTarget->getPointerWidth(LangAS::Default) != 64) { + SizeType = TargetInfo::UnsignedLong; + PtrDiffType = IntPtrType = TargetInfo::SignedLong; + } + // SPIR64 has support for atomic ops if atomic extension is enabled. // Take the maximum because it's possible the Host supports wider types. MaxAtomicInlineWidth = std::max(MaxAtomicInlineWidth, 64); @@ -350,9 +379,15 @@ class LLVM_LIBRARY_VISIBILITY SPIRV32TargetInfo : public BaseSPIRVTargetInfo { "32-bit SPIR-V target must use unknown, chipstar, or vulkan OS"); assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment && "32-bit SPIR-V target must use unknown environment type"); + // FIXME: Assert that a present host target's pointer types match the ones + // set below, once the driver diagnoses unsupported host/device combinations + // (until then such an assert would fire on existing tests). PointerWidth = PointerAlign = 32; - SizeType = TargetInfo::UnsignedInt; - PtrDiffType = IntPtrType = TargetInfo::SignedInt; + const TargetInfo *HostTarget = getHostTarget(); + if (!HostTarget || HostTarget->getPointerWidth(LangAS::Default) != 32) { + SizeType = TargetInfo::UnsignedInt; + PtrDiffType = IntPtrType = TargetInfo::SignedInt; + } // SPIR-V has core support for atomic ops, and Int32 is always available; // we take the maximum because it's possible the Host supports wider types. MaxAtomicInlineWidth = std::max(MaxAtomicInlineWidth, 64); @@ -375,9 +410,15 @@ class LLVM_LIBRARY_VISIBILITY SPIRV64TargetInfo : public BaseSPIRVTargetInfo { "64-bit SPIR-V target must use unknown, chipstar, or vulkan OS"); assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment && "64-bit SPIR-V target must use unknown environment type"); + // FIXME: Assert that a present host target's pointer types match the ones + // set below, once the driver diagnoses unsupported host/device combinations + // (until then such an assert would fire on existing tests). PointerWidth = PointerAlign = 64; - SizeType = TargetInfo::UnsignedLong; - PtrDiffType = IntPtrType = TargetInfo::SignedLong; + const TargetInfo *HostTarget = getHostTarget(); + if (!HostTarget || HostTarget->getPointerWidth(LangAS::Default) != 64) { + SizeType = TargetInfo::UnsignedLong; + PtrDiffType = IntPtrType = TargetInfo::SignedLong; + } // SPIR-V has core support for atomic ops, and Int64 is always available; // we take the maximum because it's possible the Host supports wider types. MaxAtomicInlineWidth = std::max(MaxAtomicInlineWidth, 64); diff --git a/clang/lib/Driver/ToolChains/SYCL.cpp b/clang/lib/Driver/ToolChains/SYCL.cpp index 7208a8cac9436..34aa99320473e 100644 --- a/clang/lib/Driver/ToolChains/SYCL.cpp +++ b/clang/lib/Driver/ToolChains/SYCL.cpp @@ -200,3 +200,8 @@ void SYCLToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &Args, ArgStringList &CC1Args) const { HostTC.AddClangCXXStdlibIncludeArgs(Args, CC1Args); } + +VersionTuple SYCLToolChain::computeMSVCVersion(const Driver *D, + const ArgList &Args) const { + return HostTC.computeMSVCVersion(D, Args); +} diff --git a/clang/lib/Driver/ToolChains/SYCL.h b/clang/lib/Driver/ToolChains/SYCL.h index d404ce2f93923..48f5d986c3e6e 100644 --- a/clang/lib/Driver/ToolChains/SYCL.h +++ b/clang/lib/Driver/ToolChains/SYCL.h @@ -54,6 +54,9 @@ class LLVM_LIBRARY_VISIBILITY SYCLToolChain : public ToolChain { void AddClangCXXStdlibIncludeArgs( const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CC1Args) const override; + VersionTuple + computeMSVCVersion(const Driver *D, + const llvm::opt::ArgList &Args) const override; private: const ToolChain &HostTC; diff --git a/clang/test/CodeGenSPIRV/spirv-host-adaptation-valist.cpp b/clang/test/CodeGenSPIRV/spirv-host-adaptation-valist.cpp new file mode 100644 index 0000000000000..d926e30376b18 --- /dev/null +++ b/clang/test/CodeGenSPIRV/spirv-host-adaptation-valist.cpp @@ -0,0 +1,24 @@ +/// Tests that va_list layout matches the host target's getBuiltinVaListKind(). + +// RUN: %clang_cc1 -triple spirv64-unknown-unknown -aux-triple x86_64-unknown-linux-gnu \ +// RUN: -fsycl-is-device -emit-llvm -o - %s | FileCheck --check-prefix=LINUX %s +// RUN: %clang_cc1 -triple spirv64-unknown-unknown -aux-triple x86_64-pc-windows-msvc \ +// RUN: -fsycl-is-device -emit-llvm -o - %s | FileCheck --check-prefix=WINDOWS %s + +[[clang::sycl_external]] int f(int n, ...) { + __builtin_va_list ap1, ap2; + __builtin_va_start(ap1, n); + int v = __builtin_va_arg(ap1, int); + __builtin_va_copy(ap2, ap1); + __builtin_va_end(ap1); + __builtin_va_end(ap2); + return v; +} + +// LINUX: define {{.*}} i32 @_Z1fiz(i32 noundef %n, ...) {{.*}} { +// LINUX: %ap1 = alloca [1 x %struct.__va_list_tag], align 8 +// LINUX: %ap2 = alloca [1 x %struct.__va_list_tag], align 8 + +// WINDOWS: define {{.*}} i32 @_Z1fiz(i32 noundef %n, ...) {{.*}} { +// WINDOWS: %ap1 = alloca ptr addrspace(4), align 8 +// WINDOWS: %ap2 = alloca ptr addrspace(4), align 8 diff --git a/clang/test/Driver/sycl-msvc-version-propagation.cpp b/clang/test/Driver/sycl-msvc-version-propagation.cpp new file mode 100644 index 0000000000000..c542ceef80ade --- /dev/null +++ b/clang/test/Driver/sycl-msvc-version-propagation.cpp @@ -0,0 +1,14 @@ +/// Test that -fms-compatibility-version is consistent between the host and the +/// SPIR-V device compilation. + +// RUN: %clang -### -fsycl --target=x86_64-pc-windows-msvc \ +// RUN: -x c++ %s 2>&1 | FileCheck %s + +// CHECK: "-triple" "spirv64-unknown-unknown" +// CHECK-SAME: "-aux-triple" "x86_64-pc-windows-msvc +// CHECK-SAME: "-fms-compatibility" +// CHECK-SAME: "-fms-compatibility-version=[[MSVC_VER:[0-9.]+]]" + +// CHECK: "-triple" "x86_64-pc-windows-msvc +// CHECK-SAME: "-fms-compatibility" +// CHECK-SAME: "-fms-compatibility-version=[[MSVC_VER]]" diff --git a/clang/test/Preprocessor/spir-host-adaptation-macros.cpp b/clang/test/Preprocessor/spir-host-adaptation-macros.cpp new file mode 100644 index 0000000000000..c8e29ff60b250 --- /dev/null +++ b/clang/test/Preprocessor/spir-host-adaptation-macros.cpp @@ -0,0 +1,36 @@ +/// Tests legacy SPIR target adaptation of type properties from the host. + +// RUN: %clang_cc1 -triple spir64-unknown-unknown -aux-triple x86_64-unknown-linux-gnu \ +// RUN: -fsycl-is-device -E -dM %s | FileCheck --check-prefix=SPIR64-LINUX %s +// RUN: %clang_cc1 -triple spir64-unknown-unknown -aux-triple x86_64-pc-windows-msvc \ +// RUN: -fsycl-is-device -E -dM %s | FileCheck --check-prefix=SPIR64-WIN %s +// RUN: %clang_cc1 -triple spir-unknown-unknown -aux-triple i386-unknown-linux-gnu \ +// RUN: -fsycl-is-device -E -dM %s | FileCheck --check-prefix=SPIR32-LINUX %s +// RUN: %clang_cc1 -triple spir64-unknown-unknown \ +// RUN: -fsycl-is-device -E -dM %s | FileCheck --check-prefix=SPIR64-NOHOST %s + +// SPIR64 + Linux (LP64) +// SPIR64-LINUX-DAG: #define __SIZE_TYPE__ long unsigned int +// SPIR64-LINUX-DAG: #define __PTRDIFF_TYPE__ long int +// SPIR64-LINUX-DAG: #define __INTPTR_TYPE__ long int +// SPIR64-LINUX-DAG: #define __SIZEOF_LONG__ 8 +// SPIR64-LINUX-DAG: #define __SIZEOF_POINTER__ 8 + +// SPIR64 + Windows (LLP64) +// SPIR64-WIN-DAG: #define __SIZE_TYPE__ long long unsigned int +// SPIR64-WIN-DAG: #define __PTRDIFF_TYPE__ long long int +// SPIR64-WIN-DAG: #define __INTPTR_TYPE__ long long int +// SPIR64-WIN-DAG: #define __SIZEOF_LONG__ 4 +// SPIR64-WIN-DAG: #define __SIZEOF_POINTER__ 8 + +// SPIR32 + Linux i386 (ILP32) +// SPIR32-LINUX-DAG: #define __SIZE_TYPE__ unsigned int +// SPIR32-LINUX-DAG: #define __PTRDIFF_TYPE__ int +// SPIR32-LINUX-DAG: #define __INTPTR_TYPE__ int +// SPIR32-LINUX-DAG: #define __SIZEOF_POINTER__ 4 + +// SPIR64 no host (defaults) +// SPIR64-NOHOST-DAG: #define __SIZE_TYPE__ long unsigned int +// SPIR64-NOHOST-DAG: #define __PTRDIFF_TYPE__ long int +// SPIR64-NOHOST-DAG: #define __INTPTR_TYPE__ long int +// SPIR64-NOHOST-DAG: #define __SIZEOF_POINTER__ 8 diff --git a/clang/test/Preprocessor/spirv-host-adaptation-macros.cpp b/clang/test/Preprocessor/spirv-host-adaptation-macros.cpp new file mode 100644 index 0000000000000..786059fee4cf0 --- /dev/null +++ b/clang/test/Preprocessor/spirv-host-adaptation-macros.cpp @@ -0,0 +1,73 @@ +/// Tests SPIR-V device target adaptation of SizeType, PtrDiffType, and +/// IntPtrType from the host target via -aux-triple. + +// RUN: %clang_cc1 -triple spirv64-unknown-unknown -aux-triple x86_64-unknown-linux-gnu \ +// RUN: -fsycl-is-device -E -dM %s | FileCheck --check-prefix=LINUX64 %s +// RUN: %clang_cc1 -triple spirv64-unknown-unknown -aux-triple x86_64-pc-windows-msvc \ +// RUN: -fsycl-is-device -E -dM %s | FileCheck --check-prefix=WIN64 %s +// RUN: %clang_cc1 -triple spirv32-unknown-unknown -aux-triple i386-unknown-linux-gnu \ +// RUN: -fsycl-is-device -E -dM %s | FileCheck --check-prefix=LINUX32 %s +// RUN: %clang_cc1 -triple spirv64-unknown-unknown \ +// RUN: -fsycl-is-device -E -dM %s | FileCheck --check-prefix=NOHOST64 %s +// RUN: %clang_cc1 -triple spirv32-unknown-unknown \ +// RUN: -fsycl-is-device -E -dM %s | FileCheck --check-prefix=NOHOST32 %s + +// Linux x86_64 host (LP64) +// LINUX64-DAG: #define __SIZE_TYPE__ long unsigned int +// LINUX64-DAG: #define __PTRDIFF_TYPE__ long int +// LINUX64-DAG: #define __INTPTR_TYPE__ long int +// LINUX64-DAG: #define __SIZEOF_SIZE_T__ 8 +// LINUX64-DAG: #define __SIZEOF_PTRDIFF_T__ 8 +// LINUX64-DAG: #define __SIZEOF_LONG__ 8 +// LINUX64-DAG: #define __SIZEOF_POINTER__ 8 + +// Windows x86_64 host (LLP64) +// WIN64-DAG: #define __SIZE_TYPE__ long long unsigned int +// WIN64-DAG: #define __PTRDIFF_TYPE__ long long int +// WIN64-DAG: #define __INTPTR_TYPE__ long long int +// WIN64-DAG: #define __SIZEOF_SIZE_T__ 8 +// WIN64-DAG: #define __SIZEOF_PTRDIFF_T__ 8 +// WIN64-DAG: #define __SIZEOF_LONG__ 4 +// WIN64-DAG: #define __SIZEOF_POINTER__ 8 + +// Linux i386 host (ILP32) +// LINUX32-DAG: #define __SIZE_TYPE__ unsigned int +// LINUX32-DAG: #define __PTRDIFF_TYPE__ int +// LINUX32-DAG: #define __INTPTR_TYPE__ int +// LINUX32-DAG: #define __SIZEOF_SIZE_T__ 4 +// LINUX32-DAG: #define __SIZEOF_PTRDIFF_T__ 4 +// LINUX32-DAG: #define __SIZEOF_POINTER__ 4 + +// No host (SPIRV64 defaults) +// NOHOST64-DAG: #define __SIZE_TYPE__ long unsigned int +// NOHOST64-DAG: #define __PTRDIFF_TYPE__ long int +// NOHOST64-DAG: #define __INTPTR_TYPE__ long int +// NOHOST64-DAG: #define __SIZEOF_SIZE_T__ 8 +// NOHOST64-DAG: #define __SIZEOF_PTRDIFF_T__ 8 +// NOHOST64-DAG: #define __SIZEOF_POINTER__ 8 + +// No host (SPIRV32 defaults) +// NOHOST32-DAG: #define __SIZE_TYPE__ unsigned int +// NOHOST32-DAG: #define __PTRDIFF_TYPE__ int +// NOHOST32-DAG: #define __INTPTR_TYPE__ int +// NOHOST32-DAG: #define __SIZEOF_SIZE_T__ 4 +// NOHOST32-DAG: #define __SIZEOF_PTRDIFF_T__ 4 +// NOHOST32-DAG: #define __SIZEOF_POINTER__ 4 + +// Aux-target OS and arch macros +// WIN64-DAG: #define _WIN32 1 +// WIN64-DAG: #define _WIN64 1 +// WIN64-DAG: #define _M_X64 100 +// WIN64-DAG: #define _M_AMD64 100 +// LINUX64-DAG: #define __linux__ 1 +// LINUX64-DAG: #define __x86_64__ 1 + +// SPIRV device macros always present +// LINUX64-DAG: #define __SPIRV__ 1 +// LINUX64-DAG: #define __SPIRV64__ 1 +// WIN64-DAG: #define __SPIRV__ 1 +// WIN64-DAG: #define __SPIRV64__ 1 +// NOHOST64-DAG: #define __SPIRV__ 1 +// NOHOST64-DAG: #define __SPIRV64__ 1 +// NOHOST32-DAG: #define __SPIRV__ 1 +// NOHOST32-DAG: #define __SPIRV32__ 1 diff --git a/clang/test/SemaSPIRV/spirv-host-adaptation-types.cpp b/clang/test/SemaSPIRV/spirv-host-adaptation-types.cpp new file mode 100644 index 0000000000000..0b9a8733d43ad --- /dev/null +++ b/clang/test/SemaSPIRV/spirv-host-adaptation-types.cpp @@ -0,0 +1,86 @@ +/// Tests that SPIR-V device targets adapt pointer and integer type sizes +/// from the host target via -aux-triple. + +// RUN: %clang_cc1 -fsycl-is-device \ +// RUN: -triple spirv64-unknown-unknown -aux-triple x86_64-unknown-linux-gnu \ +// RUN: -fsyntax-only -verify=linux64 %s +// RUN: %clang_cc1 -fsycl-is-device \ +// RUN: -triple spirv64-unknown-unknown -aux-triple x86_64-pc-windows-msvc \ +// RUN: -fsyntax-only -verify=win64 %s +// RUN: %clang_cc1 -fsycl-is-device \ +// RUN: -triple spirv32-unknown-unknown -aux-triple i386-unknown-linux-gnu \ +// RUN: -fsyntax-only -verify=linux32 %s +// RUN: %clang_cc1 -fsycl-is-device \ +// RUN: -triple spirv32-unknown-unknown -aux-triple i386-pc-windows-msvc \ +// RUN: -fsyntax-only -verify=win32 %s +// RUN: %clang_cc1 -fsycl-is-device \ +// RUN: -triple spirv64-unknown-unknown \ +// RUN: -fsyntax-only -verify=nohost64 %s +// RUN: %clang_cc1 -fsycl-is-device \ +// RUN: -triple spirv32-unknown-unknown \ +// RUN: -fsyntax-only -verify=nohost32 %s + +// linux64-no-diagnostics +// win64-no-diagnostics +// linux32-no-diagnostics +// win32-no-diagnostics +// nohost64-no-diagnostics +// nohost32-no-diagnostics + +typedef __SIZE_TYPE__ size_t_type; +typedef __PTRDIFF_TYPE__ ptrdiff_t_type; +typedef __INTPTR_TYPE__ intptr_t_type; + +// --- SPIRV64 + Linux x86_64 (LP64): long=8, pointer=8 --- +#if __SPIRV64__ && defined(__linux__) && defined(__x86_64__) +static_assert(sizeof(void *) == 8, "pointer should be 64-bit"); +static_assert(sizeof(long) == 8, "long should be 64-bit with Linux LP64"); +static_assert(sizeof(size_t_type) == 8, "size_t must be 64-bit"); +static_assert(sizeof(ptrdiff_t_type) == 8, "ptrdiff_t must be 64-bit"); +static_assert(sizeof(intptr_t_type) == 8, "intptr_t must be 64-bit"); +#endif + +// --- SPIRV64 + Windows x86_64 (LLP64): long=4, pointer=8 --- +#if __SPIRV64__ && defined(_WIN64) +static_assert(sizeof(void *) == 8, "pointer should be 64-bit"); +static_assert(sizeof(long) == 4, "long should be 32-bit with Windows LLP64"); +static_assert(sizeof(size_t_type) == 8, "size_t must be 64-bit"); +static_assert(sizeof(ptrdiff_t_type) == 8, "ptrdiff_t must be 64-bit"); +static_assert(sizeof(intptr_t_type) == 8, "intptr_t must be 64-bit"); +#endif + +// --- SPIRV32 + Linux i386 (ILP32): long=4, pointer=4 --- +#if __SPIRV32__ && defined(__linux__) && defined(__i386__) +static_assert(sizeof(void *) == 4, "pointer should be 32-bit"); +static_assert(sizeof(long) == 4, "long should be 32-bit with ILP32"); +static_assert(sizeof(size_t_type) == 4, "size_t must be 32-bit"); +static_assert(sizeof(ptrdiff_t_type) == 4, "ptrdiff_t must be 32-bit"); +static_assert(sizeof(intptr_t_type) == 4, "intptr_t must be 32-bit"); +#endif + +// --- SPIRV32 + Windows i386 (ILP32): long=4, pointer=4 --- +#if __SPIRV32__ && defined(_WIN32) && !defined(_WIN64) +static_assert(sizeof(void *) == 4, "pointer should be 32-bit"); +static_assert(sizeof(long) == 4, "long should be 32-bit on Win32"); +static_assert(sizeof(size_t_type) == 4, "size_t must be 32-bit"); +static_assert(sizeof(ptrdiff_t_type) == 4, "ptrdiff_t must be 32-bit"); +static_assert(sizeof(intptr_t_type) == 4, "intptr_t must be 32-bit"); +#endif + +// --- SPIRV64 no host (defaults match LP64) --- +#if __SPIRV64__ && !defined(__linux__) && !defined(_WIN64) +static_assert(sizeof(void *) == 8, "pointer should be 64-bit"); +static_assert(sizeof(long) == 8, "long should be 64-bit with default LP64"); +static_assert(sizeof(size_t_type) == 8, "size_t must be 64-bit"); +static_assert(sizeof(ptrdiff_t_type) == 8, "ptrdiff_t must be 64-bit"); +static_assert(sizeof(intptr_t_type) == 8, "intptr_t must be 64-bit"); +#endif + +// --- SPIRV32 no host (pointer=4, but long stays at base default=8) --- +#if __SPIRV32__ && !defined(__linux__) && !defined(_WIN32) +static_assert(sizeof(void *) == 4, "pointer should be 32-bit"); +static_assert(sizeof(long) == 8, "long defaults to 64-bit without a host"); +static_assert(sizeof(size_t_type) == 4, "size_t must be 32-bit"); +static_assert(sizeof(ptrdiff_t_type) == 4, "ptrdiff_t must be 32-bit"); +static_assert(sizeof(intptr_t_type) == 4, "intptr_t must be 32-bit"); +#endif diff --git a/clang/test/SemaSPIRV/spirv-host-adaptation-valist.cpp b/clang/test/SemaSPIRV/spirv-host-adaptation-valist.cpp new file mode 100644 index 0000000000000..5959aa5262dc9 --- /dev/null +++ b/clang/test/SemaSPIRV/spirv-host-adaptation-valist.cpp @@ -0,0 +1,29 @@ +/// Tests that getBuiltinVaListKind() delegates to the host target. + +// RUN: %clang_cc1 -triple spirv64-unknown-unknown -aux-triple x86_64-unknown-linux-gnu \ +// RUN: -fsycl-is-device -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple spirv64-unknown-unknown -aux-triple x86_64-pc-windows-msvc \ +// RUN: -fsycl-is-device -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple spirv64-unknown-unknown -aux-triple aarch64-unknown-linux-gnu \ +// RUN: -fsycl-is-device -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple spirv64-unknown-unknown \ +// RUN: -fsycl-is-device -fsyntax-only -verify %s + +// expected-no-diagnostics + +template +struct same_type; +template +struct same_type { + using type = int; +}; +template::type> +constexpr bool is_same_type(int) { return true; } +template +constexpr bool is_same_type(...) { return false; } + +#if defined(_WIN32) +static_assert(is_same_type<__builtin_va_list, char*>(0)); +#else +static_assert(!is_same_type<__builtin_va_list, char*>(0)); +#endif From 7220098d29a9b1a2ac4b63e3f1973ddab9041a97 Mon Sep 17 00:00:00 2001 From: Yao Qi Date: Thu, 6 Aug 2026 20:34:05 +0100 Subject: [PATCH 002/789] [lldb][test] Skip the frame 0 expedite test with an out-of-tree debugserver (#214448) `test_memory_reads_when_examining_frame0_locals` asserts that examining frame 0's locals reads no stack memory, which only holds when debugserver expedites the stopped frame's stack in `jThreadsInfo`. That is added in b631e0cbd1c9, so the assertion only holds for an in-tree debugserver. The GreenDragon `lldb-cmake-sanitized` bot configures with `-DLLDB_USE_SYSTEM_DEBUGSERVER=ON`, so it tests against the debugserver shipped in Xcode. That one predates the expedite, so test fails: ``` FAIL: test_memory_reads_when_examining_frame0_locals AssertionError: 2 != 0 : expected NO stack memory reads for frame 0 (its stack is expedited in jThreadsInfo). memory reads while examining locals: stack=2 heap=1 other=1 (total=4) stack region: [0x16b540000,0x16f53c000) stack reads: [0x16f53ac00,0x16f53ae00), [0x16f53aa00,0x16f53ac00) ``` It adds `@skipIfOutOfTreeDebugserver` to `test_memory_reads_when_examining_frame0_locals`. The other three tests in the file pass there because they only rely on the frame pointer backchain expedite, which is old enough to be in the shipped debugserver. --- .../macosx/expedited-stack-memory/TestExpeditedStackMemory.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/test/API/macosx/expedited-stack-memory/TestExpeditedStackMemory.py b/lldb/test/API/macosx/expedited-stack-memory/TestExpeditedStackMemory.py index 486b88ea70e04..6fb31be4f379e 100644 --- a/lldb/test/API/macosx/expedited-stack-memory/TestExpeditedStackMemory.py +++ b/lldb/test/API/macosx/expedited-stack-memory/TestExpeditedStackMemory.py @@ -47,6 +47,7 @@ def test_memory_reads_during_backtrace_without_cache(self): stub, producing memory-read packets.""" self.check_packets_during_backtrace(disable_memory_cache=True) + @skipIfOutOfTreeDebugserver @requireDarwin def test_memory_reads_when_examining_frame0_locals(self): """Model an IDE stop: walk the whole stack (a backtrace / debug From 92e1f6aaa25693c940acc362bc91cb5a6bc23426 Mon Sep 17 00:00:00 2001 From: Arseniy Obolenskiy Date: Thu, 6 Aug 2026 21:42:46 +0200 Subject: [PATCH 003/789] [AMDGPU] Fix SIFoldOperands miscompiling values that leave a divergent loop (#203256) A scalar value latched per-lane inside a divergent loop was being folded into a use after the loop, so every lane wrongly read the same value --- llvm/lib/Target/AMDGPU/SIFoldOperands.cpp | 61 ++++++++++++++--- llvm/test/CodeGen/AMDGPU/do-not-fold-copy.mir | 65 +++++++++++++++---- 2 files changed, 107 insertions(+), 19 deletions(-) diff --git a/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp b/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp index 3a8a769345931..04a9ed487d655 100644 --- a/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp +++ b/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp @@ -18,8 +18,10 @@ #include "llvm/ADT/DepthFirstIterator.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineLoopInfo.h" #include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/RegisterClassInfo.h" +#include "llvm/InitializePasses.h" #define DEBUG_TYPE "si-fold-operands" using namespace llvm; @@ -180,6 +182,7 @@ class SIFoldOperandsImpl { const SIRegisterInfo *TRI; const GCNSubtarget *ST; const SIMachineFunctionInfo *MFI; + const MachineLoopInfo *MLI; bool frameIndexMayFold(const MachineInstr &UseMI, int OpNo, const FoldableDef &OpToFold) const; @@ -220,6 +223,8 @@ class SIFoldOperandsImpl { const FoldableDef &OpToFold) const; bool isUseSafeToFold(const MachineInstr &MI, const MachineOperand &UseMO) const; + bool isTemporallyDivergentUse(const FoldableDef &OpToFold, + const MachineInstr &UseMI) const; const TargetRegisterClass *getRegSeqInit( MachineInstr &RegSeq, @@ -266,7 +271,7 @@ class SIFoldOperandsImpl { public: SIFoldOperandsImpl() = default; - bool run(MachineFunction &MF); + bool run(MachineFunction &MF, const MachineLoopInfo *MLI); }; class SIFoldOperandsLegacy : public MachineFunctionPass { @@ -278,13 +283,17 @@ class SIFoldOperandsLegacy : public MachineFunctionPass { bool runOnMachineFunction(MachineFunction &MF) override { if (skipFunction(MF.getFunction())) return false; - return SIFoldOperandsImpl().run(MF); + const MachineLoopInfo *MLI = + &getAnalysis().getLI(); + return SIFoldOperandsImpl().run(MF, MLI); } StringRef getPassName() const override { return "SI Fold Operands"; } void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesCFG(); + AU.addRequired(); + AU.addPreserved(); MachineFunctionPass::getAnalysisUsage(AU); } @@ -295,8 +304,11 @@ class SIFoldOperandsLegacy : public MachineFunctionPass { } // End anonymous namespace. -INITIALIZE_PASS(SIFoldOperandsLegacy, DEBUG_TYPE, "SI Fold Operands", false, - false) +INITIALIZE_PASS_BEGIN(SIFoldOperandsLegacy, DEBUG_TYPE, "SI Fold Operands", + false, false) +INITIALIZE_PASS_DEPENDENCY(MachineLoopInfoWrapperPass) +INITIALIZE_PASS_END(SIFoldOperandsLegacy, DEBUG_TYPE, "SI Fold Operands", false, + false) char SIFoldOperandsLegacy::ID = 0; @@ -976,6 +988,32 @@ bool SIFoldOperandsImpl::isUseSafeToFold(const MachineInstr &MI, return !TII->isSDWA(MI); } +// Returns true if any instruction in \p L modifies EXEC. +static bool loopModifiesExec(const MachineLoop &L, const SIRegisterInfo &TRI) { + for (const MachineBasicBlock *MBB : L.getBlocks()) + for (const MachineInstr &MI : *MBB) + if (MI.modifiesRegister(TRI.getExec(), &TRI)) + return true; + return false; +} + +// An SGPR->VGPR copy inside a divergent loop latches each lane value as it +// exits. Folding its scalar source into a use after the loop would make every +// lane read the same reconverged value, so do not fold across the loop exit. +bool SIFoldOperandsImpl::isTemporallyDivergentUse( + const FoldableDef &OpToFold, const MachineInstr &UseMI) const { + if (!OpToFold.isReg()) + return false; + const MachineInstr *DefMI = OpToFold.DefMI; + if (!DefMI || !DefMI->isCopy() || + TRI->isSGPRReg(*MRI, DefMI->getOperand(0).getReg()) || + !TRI->isSGPRReg(*MRI, OpToFold.getReg())) + return false; + const MachineLoop *DefLoop = MLI->getLoopFor(DefMI->getParent()); + return DefLoop && !DefLoop->contains(UseMI.getParent()) && + loopModifiesExec(*DefLoop, *TRI); +} + static MachineOperand *lookUpCopyChain(const SIInstrInfo &TII, const MachineRegisterInfo &MRI, Register SrcReg) { @@ -1218,6 +1256,9 @@ bool SIFoldOperandsImpl::foldOperand( if (!isUseSafeToFold(*UseMI, *UseOp)) return Changed; + if (isTemporallyDivergentUse(OpToFold, *UseMI)) + return Changed; + // FIXME: Fold operands with subregs. if (UseOp->isReg() && OpToFold.isReg()) { if (UseOp->isImplicit()) @@ -2812,13 +2853,14 @@ bool SIFoldOperandsImpl::tryOptimizeAGPRPhis(MachineBasicBlock &MBB) { return Changed; } -bool SIFoldOperandsImpl::run(MachineFunction &MF) { +bool SIFoldOperandsImpl::run(MachineFunction &MF, const MachineLoopInfo *MLI) { this->MF = &MF; MRI = &MF.getRegInfo(); ST = &MF.getSubtarget(); TII = ST->getInstrInfo(); TRI = &TII->getRegisterInfo(); MFI = MF.getInfo(); + this->MLI = MLI; // omod is ignored by hardware if IEEE bit is enabled. omod also does not // correctly handle signed zeros. @@ -2882,15 +2924,18 @@ bool SIFoldOperandsImpl::run(MachineFunction &MF) { return Changed; } -PreservedAnalyses SIFoldOperandsPass::run(MachineFunction &MF, - MachineFunctionAnalysisManager &) { +PreservedAnalyses +SIFoldOperandsPass::run(MachineFunction &MF, + MachineFunctionAnalysisManager &MFAM) { MFPropsModifier _(*this, MF); - bool Changed = SIFoldOperandsImpl().run(MF); + const MachineLoopInfo *MLI = &MFAM.getResult(MF); + bool Changed = SIFoldOperandsImpl().run(MF, MLI); if (!Changed) { return PreservedAnalyses::all(); } auto PA = getMachineFunctionPassPreservedAnalyses(); PA.preserveSet(); + PA.preserve(); return PA; } diff --git a/llvm/test/CodeGen/AMDGPU/do-not-fold-copy.mir b/llvm/test/CodeGen/AMDGPU/do-not-fold-copy.mir index 8b35d0cfb82b0..41127424dd892 100644 --- a/llvm/test/CodeGen/AMDGPU/do-not-fold-copy.mir +++ b/llvm/test/CodeGen/AMDGPU/do-not-fold-copy.mir @@ -49,16 +49,16 @@ body: | bb.2: SI_END_CF %4, implicit-def dead $exec, implicit-def dead $scc, implicit $exec - %9:vgpr_32 = COPY %7 - %10:sreg_64_xexec = IMPLICIT_DEF - %11:vgpr_32 = V_SET_INACTIVE_B32 0, %9, 0, 0, killed %10, implicit $exec + %8:vgpr_32 = COPY %7 + %9:sreg_64_xexec = IMPLICIT_DEF + %10:vgpr_32 = V_SET_INACTIVE_B32 0, %8, 0, 0, killed %9, implicit $exec S_ENDPGM 0 ... # An SGPR->VGPR copy with no implicit $exec read, inserted in a divergent loop -# to latch a per-lane value, is read after the loop. SIFoldOperands currently -# folds the scalar source into that exit use, dropping the per-lane snapshot; -# this is wrong because the value escapes the loop. FIXME: should not fold. +# to latch a per-lane value, is read after the loop. SIFoldOperands must not +# fold the scalar source into that exit use: it escapes the loop, so the fold +# would drop the per-lane snapshot. --- name: do_not_fold_sgpr_to_vgpr_copy_escaping_loop tracksRegLiveness: true @@ -79,6 +79,7 @@ body: | ; CHECK-NEXT: [[PHI:%[0-9]+]]:sreg_64 = PHI [[S_MOV_B64_]], %bb.0, %5, %bb.1 ; CHECK-NEXT: [[PHI1:%[0-9]+]]:sreg_32 = PHI [[S_MOV_B32_]], %bb.0, %7, %bb.1 ; CHECK-NEXT: [[S_XOR_B32_:%[0-9]+]]:sreg_32 = S_XOR_B32 [[COPY]], [[PHI1]], implicit-def dead $scc + ; CHECK-NEXT: [[COPY2:%[0-9]+]]:vgpr_32 = COPY [[S_XOR_B32_]] ; CHECK-NEXT: [[S_ADD_I32_:%[0-9]+]]:sreg_32 = S_ADD_I32 [[PHI1]], 1, implicit-def dead $scc ; CHECK-NEXT: [[V_CMP_EQ_U32_e64_:%[0-9]+]]:sreg_64 = V_CMP_EQ_U32_e64 [[COPY1]], [[S_ADD_I32_]], implicit $exec ; CHECK-NEXT: [[SI_IF_BREAK:%[0-9]+]]:sreg_64 = SI_IF_BREAK [[V_CMP_EQ_U32_e64_]], [[PHI]], implicit-def dead $scc @@ -87,7 +88,7 @@ body: | ; CHECK-NEXT: {{ $}} ; CHECK-NEXT: bb.2: ; CHECK-NEXT: SI_END_CF [[SI_IF_BREAK]], implicit-def dead $exec, implicit-def dead $scc, implicit $exec - ; CHECK-NEXT: [[V_ADD_U32_e64_:%[0-9]+]]:vgpr_32 = V_ADD_U32_e64 [[S_XOR_B32_]], 1, 0, implicit $exec + ; CHECK-NEXT: [[V_ADD_U32_e64_:%[0-9]+]]:vgpr_32 = V_ADD_U32_e64 [[COPY2]], 1, 0, implicit $exec ; CHECK-NEXT: $vgpr0 = COPY [[V_ADD_U32_e64_]] ; CHECK-NEXT: SI_RETURN implicit $vgpr0 bb.0: @@ -119,9 +120,8 @@ body: | SI_RETURN implicit $vgpr0 ... -# Same latch, but the loop-exit use is itself a COPY. The scalar source is -# currently propagated through that exit copy too (separate fold path). -# FIXME: should not fold. +# Same latch, but the loop-exit use is itself a COPY. The scalar source must +# not be propagated through that exit copy either (separate fold path). --- name: do_not_fold_sgpr_to_vgpr_copy_escaping_loop_via_copy_use tracksRegLiveness: true @@ -142,6 +142,7 @@ body: | ; CHECK-NEXT: [[PHI:%[0-9]+]]:sreg_64 = PHI [[S_MOV_B64_]], %bb.0, %5, %bb.1 ; CHECK-NEXT: [[PHI1:%[0-9]+]]:sreg_32 = PHI [[S_MOV_B32_]], %bb.0, %7, %bb.1 ; CHECK-NEXT: [[S_XOR_B32_:%[0-9]+]]:sreg_32 = S_XOR_B32 [[COPY]], [[PHI1]], implicit-def dead $scc + ; CHECK-NEXT: [[COPY2:%[0-9]+]]:vgpr_32 = COPY [[S_XOR_B32_]] ; CHECK-NEXT: [[S_ADD_I32_:%[0-9]+]]:sreg_32 = S_ADD_I32 [[PHI1]], 1, implicit-def dead $scc ; CHECK-NEXT: [[V_CMP_EQ_U32_e64_:%[0-9]+]]:sreg_64 = V_CMP_EQ_U32_e64 [[COPY1]], [[S_ADD_I32_]], implicit $exec ; CHECK-NEXT: [[SI_IF_BREAK:%[0-9]+]]:sreg_64 = SI_IF_BREAK [[V_CMP_EQ_U32_e64_]], [[PHI]], implicit-def dead $scc @@ -150,7 +151,7 @@ body: | ; CHECK-NEXT: {{ $}} ; CHECK-NEXT: bb.2: ; CHECK-NEXT: SI_END_CF [[SI_IF_BREAK]], implicit-def dead $exec, implicit-def dead $scc, implicit $exec - ; CHECK-NEXT: [[V_ADD_U32_e64_:%[0-9]+]]:vgpr_32 = V_ADD_U32_e64 [[S_XOR_B32_]], 1, 0, implicit $exec + ; CHECK-NEXT: [[V_ADD_U32_e64_:%[0-9]+]]:vgpr_32 = V_ADD_U32_e64 [[COPY2]], 1, 0, implicit $exec ; CHECK-NEXT: $vgpr0 = COPY [[V_ADD_U32_e64_]] ; CHECK-NEXT: SI_RETURN implicit $vgpr0 bb.0: @@ -182,3 +183,45 @@ body: | $vgpr0 = COPY %12 SI_RETURN implicit $vgpr0 ... + +# Same SGPR->VGPR copy escaping a loop, but the loop does not modify $exec, so +# there is no temporal divergence and the fold is allowed. +--- +name: fold_from_loop_allowed_because_loop_does_not_modify_exec +tracksRegLiveness: true +body: | + ; CHECK-LABEL: name: fold_from_loop_allowed_because_loop_does_not_modify_exec + ; CHECK: bb.0: + ; CHECK-NEXT: successors: %bb.1(0x80000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[S_MOV_B32_:%[0-9]+]]:sreg_32 = S_MOV_B32 0 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.1: + ; CHECK-NEXT: successors: %bb.2(0x04000000), %bb.1(0x7c000000) + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[PHI:%[0-9]+]]:sreg_32 = PHI [[S_MOV_B32_]], %bb.0, %2, %bb.1 + ; CHECK-NEXT: [[S_ADD_I32_:%[0-9]+]]:sreg_32 = S_ADD_I32 [[PHI]], 1, implicit-def $scc + ; CHECK-NEXT: S_CBRANCH_SCC1 %bb.1, implicit $scc + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.2: + ; CHECK-NEXT: [[V_ADD_U32_e64_:%[0-9]+]]:vgpr_32 = V_ADD_U32_e64 [[PHI]], 1, 0, implicit $exec + ; CHECK-NEXT: $vgpr0 = COPY [[V_ADD_U32_e64_]] + ; CHECK-NEXT: SI_RETURN implicit $vgpr0 + bb.0: + successors: %bb.1 + + %0:sreg_32 = S_MOV_B32 0 + + bb.1: + successors: %bb.2(0x04000000), %bb.1(0x7c000000) + + %1:sreg_32 = PHI %0, %bb.0, %2, %bb.1 + %3:vgpr_32 = COPY %1 + %2:sreg_32 = S_ADD_I32 %1, 1, implicit-def $scc + S_CBRANCH_SCC1 %bb.1, implicit $scc + + bb.2: + %4:vgpr_32 = V_ADD_U32_e64 %3, 1, 0, implicit $exec + $vgpr0 = COPY %4 + SI_RETURN implicit $vgpr0 +... From 9bbd728946da0bc8c0aa757dfec19fe5e893ca45 Mon Sep 17 00:00:00 2001 From: "Yaxun (Sam) Liu" Date: Thu, 6 Aug 2026 15:47:49 -0400 Subject: [PATCH 004/789] [HIP] Add libhipcxx to the default header search path (#214279) libhipcxx provides C++ library support for HIP device code, similar to libcudacxx for CUDA. CUDA toolchains make libcudacxx available through the toolkit include path by default. HIP users should likewise be able to include libhipcxx headers without an installation-specific include option. Add include/libhipcxx from the selected ROCm installation when the directory exists. It follows the same search order and controls as the other HIP include paths. --- clang/docs/ReleaseNotes.md | 6 ++++++ clang/lib/Driver/ToolChains/AMDGPU.cpp | 6 ++++++ .../rocm/include/libhipcxx/cuda/std/atomic | 1 + clang/test/Driver/hip-include-path.hip | 20 +++++++++++++++++++ 4 files changed, 33 insertions(+) create mode 100644 clang/test/Driver/Inputs/rocm/include/libhipcxx/cuda/std/atomic diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 2f13ec59483ee..7976b82b63f6e 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -497,6 +497,12 @@ features cannot lower the translation-unit ABI level; #### CUDA/HIP Language Changes +- HIP compilations now add the `include/libhipcxx` directory from the selected + ROCm installation to the header search path when it exists. This allows + libhipcxx headers to be included with paths such as ``. + The `-nogpuinc` option disables this path together with the other HIP include + paths. + #### CUDA Support - Added `--cuda-emit-nvcc-abi` to emit the NVCC-compatible host registration ABI diff --git a/clang/lib/Driver/ToolChains/AMDGPU.cpp b/clang/lib/Driver/ToolChains/AMDGPU.cpp index 7bce060de0596..9718c621698d8 100644 --- a/clang/lib/Driver/ToolChains/AMDGPU.cpp +++ b/clang/lib/Driver/ToolChains/AMDGPU.cpp @@ -593,6 +593,12 @@ void RocmInstallationDetector::AddHIPIncludeArgs(const ArgList &DriverArgs, CC1Args.push_back("-idirafter"); CC1Args.push_back(DriverArgs.MakeArgString(getIncludePath())); + SmallString<128> LibHipCxxPath(getIncludePath()); + llvm::sys::path::append(LibHipCxxPath, "libhipcxx"); + if (D.getVFS().exists(LibHipCxxPath)) { + CC1Args.push_back("-idirafter"); + CC1Args.push_back(DriverArgs.MakeArgString(LibHipCxxPath)); + } if (UsesRuntimeWrapper) CC1Args.append({"-include", "__clang_hip_runtime_wrapper.h"}); if (HasHipStdPar) diff --git a/clang/test/Driver/Inputs/rocm/include/libhipcxx/cuda/std/atomic b/clang/test/Driver/Inputs/rocm/include/libhipcxx/cuda/std/atomic new file mode 100644 index 0000000000000..3dcbff4d2a047 --- /dev/null +++ b/clang/test/Driver/Inputs/rocm/include/libhipcxx/cuda/std/atomic @@ -0,0 +1 @@ +// This file makes the mock libhipcxx include directory discoverable. diff --git a/clang/test/Driver/hip-include-path.hip b/clang/test/Driver/hip-include-path.hip index efa91c651c45f..12d37bae092d6 100644 --- a/clang/test/Driver/hip-include-path.hip +++ b/clang/test/Driver/hip-include-path.hip @@ -16,10 +16,26 @@ // RUN: -std=c++11 --rocm-path=%S/Inputs/rocm --no-offload-inc -nogpulib --offload-inc %s 2>&1 \ // RUN: | FileCheck -check-prefixes=COMMON,CLANG,HIP -DRESOURCE_DIR=%clang-resource-dir %s +// RUN: %clang -c -### --target=x86_64-unknown-linux-gnu --cuda-gpu-arch=gfx900 \ +// RUN: -std=c++11 --rocm-path=%S/Inputs/rocm -nogpulib -nostdinc++ %s 2>&1 \ +// RUN: | FileCheck -check-prefixes=COMMON,CLANG,HIP -DRESOURCE_DIR=%clang-resource-dir %s + +// RUN: %clang -fsyntax-only --target=x86_64-unknown-linux-gnu \ +// RUN: --cuda-gpu-arch=gfx900 -std=c++11 --rocm-path=%S/Inputs/rocm \ +// RUN: -nogpulib -nohipwrapperinc %s + +// RUN: %clang -c -### --target=x86_64-unknown-linux-gnu --cuda-gpu-arch=gfx900 \ +// RUN: -std=c++11 --rocm-path=%S/Inputs/rocm-invalid -nogpulib %s 2>&1 \ +// RUN: | FileCheck -check-prefix=NOLIBHIPCXX %s + +// NOLIBHIPCXX: "-idirafter" "{{[^"]*}}Inputs/rocm-invalid/include" +// NOLIBHIPCXX-NOT: "{{.*}}Inputs/rocm-invalid/include/libhipcxx" + // COMMON-LABEL: "{{[^"]*}}clang{{[^"]*}}" "-cc1" // CLANG-SAME: "-internal-isystem" "[[RESOURCE_DIR]]/include/cuda_wrappers" // NOCLANG-NOT: "[[RESOURCE_DIR]]/include/cuda_wrappers" // HIP-SAME: "-idirafter" "{{[^"]*}}Inputs/rocm/include" +// HIP-SAME: "-idirafter" "{{[^"]*}}Inputs/rocm/include/libhipcxx" // HIP-SAME: "-include" "__clang_hip_runtime_wrapper.h" // NOHIP-NOT: "-include" "__clang_hip_runtime_wrapper.h" // skip check of standard C++ include path @@ -31,6 +47,7 @@ // CLANG-SAME: "-internal-isystem" "[[RESOURCE_DIR]]/include/cuda_wrappers" // NOCLANG-NOT: "[[RESOURCE_DIR]]/include/cuda_wrappers" // HIP-SAME: "-idirafter" "{{[^"]*}}Inputs/rocm/include" +// HIP-SAME: "-idirafter" "{{[^"]*}}Inputs/rocm/include/libhipcxx" // HIP-SAME: "-include" "__clang_hip_runtime_wrapper.h" // NOHIP-NOT: "-include" "__clang_hip_runtime_wrapper.h" // skip check of standard C++ include path @@ -46,6 +63,7 @@ // ROCM35-NOT: "[[RESOURCE_DIR]]/include/cuda_wrappers" // ROCM35-SAME: "-internal-isystem" "[[RESOURCE_DIR]]" // ROCM35-SAME: "-idirafter" "{{[^"]*}}Inputs/rocm/include" +// ROCM35-SAME: "-idirafter" "{{[^"]*}}Inputs/rocm/include/libhipcxx" // ROCM35-NOT: "-include" "__clang_hip_runtime_wrapper.h" // skip check of standard C++ include path // ROCM35-SAME: "-internal-isystem" "[[RESOURCE_DIR]]/include" @@ -59,3 +77,5 @@ // HOSTINC-LABEL: "{{[^"]*}}clang{{[^"]*}}" "-cc1" "-triple" "amdgcn-amd-amdhsa" // HOSTINC: "-internal-externc-isystem" "{{[^"]*}}Inputs/basic_linux_tree/usr/include" + +#include From 0f962d8024e8a982279f941514f89e131e1bef40 Mon Sep 17 00:00:00 2001 From: Arseniy Obolenskiy Date: Thu, 6 Aug 2026 21:54:50 +0200 Subject: [PATCH 005/789] [AMDGPU] Fix combineMasks dropping condition (#203180) The problem is related to `S_AND (S_AND x, x), exec` case When the nested mask op is the outer S_AND/S_OR first operand with two identical operands, combineMasks kept exec instead of a nested operand, folding to S_AND exec, exec and dropping the condition --- llvm/lib/Target/AMDGPU/SILowerControlFlow.cpp | 58 ++++++++++----- .../lower-control-flow-other-terminators.mir | 72 +++++++++++++++++++ 2 files changed, 111 insertions(+), 19 deletions(-) diff --git a/llvm/lib/Target/AMDGPU/SILowerControlFlow.cpp b/llvm/lib/Target/AMDGPU/SILowerControlFlow.cpp index 15c28ac8ff948..25694a53f35dd 100644 --- a/llvm/lib/Target/AMDGPU/SILowerControlFlow.cpp +++ b/llvm/lib/Target/AMDGPU/SILowerControlFlow.cpp @@ -102,7 +102,7 @@ class SILowerControlFlow { MachineBasicBlock *emitEndCf(MachineInstr &MI); void findMaskOperands(MachineInstr &MI, unsigned OpNo, - SmallVectorImpl &Src) const; + SmallVectorImpl &Src) const; void combineMasks(MachineInstr &MI); @@ -569,11 +569,12 @@ MachineBasicBlock *SILowerControlFlow::emitEndCf(MachineInstr &MI) { // Returns replace operands for a logical operation, either single result // for exec or two operands if source was another equivalent operation. -void SILowerControlFlow::findMaskOperands(MachineInstr &MI, unsigned OpNo, - SmallVectorImpl &Src) const { +void SILowerControlFlow::findMaskOperands( + MachineInstr &MI, unsigned OpNo, + SmallVectorImpl &Src) const { MachineOperand &Op = MI.getOperand(OpNo); if (!Op.isReg() || !Op.getReg().isVirtual()) { - Src.push_back(Op); + Src.push_back(&Op); return; } @@ -590,10 +591,10 @@ void SILowerControlFlow::findMaskOperands(MachineInstr &MI, unsigned OpNo, !(I->isCopy() && I->getOperand(0).getReg() != LMC.ExecReg)) return; - for (const auto &SrcOp : Def->explicit_operands()) + for (MachineOperand &SrcOp : Def->explicit_operands()) if (SrcOp.isReg() && SrcOp.isUse() && (SrcOp.getReg().isVirtual() || SrcOp.getReg() == LMC.ExecReg)) - Src.push_back(SrcOp); + Src.push_back(&SrcOp); } // Search and combine pairs of equivalent instructions, like @@ -602,22 +603,41 @@ void SILowerControlFlow::findMaskOperands(MachineInstr &MI, unsigned OpNo, // One of the operands is exec mask. void SILowerControlFlow::combineMasks(MachineInstr &MI) { assert(MI.getNumExplicitOperands() == 3); - SmallVector Ops; - unsigned OpToReplace = 1; - findMaskOperands(MI, 1, Ops); - if (Ops.size() == 1) OpToReplace = 2; // First operand can be exec or its copy - findMaskOperands(MI, 2, Ops); - if (Ops.size() != 3) return; - - unsigned UniqueOpndIdx; - if (Ops[0].isIdenticalTo(Ops[1])) UniqueOpndIdx = 2; - else if (Ops[0].isIdenticalTo(Ops[2])) UniqueOpndIdx = 1; - else if (Ops[1].isIdenticalTo(Ops[2])) UniqueOpndIdx = 1; - else return; + SmallVector Src1, Src2; + findMaskOperands(MI, 1, Src1); + findMaskOperands(MI, 2, Src2); + + // Exactly one of the two operands must resolve to the nested LHS and RHS. + // Another one must resolve to a single value, exec or its copy. + unsigned OpToReplace; + MachineOperand *Leaf, *NestedLHS, *NestedRHS; + if (Src1.size() == 2 && Src2.size() == 1) { + OpToReplace = 1; + NestedLHS = Src1[0]; + NestedRHS = Src1[1]; + Leaf = Src2[0]; + } else if (Src1.size() == 1 && Src2.size() == 2) { + OpToReplace = 2; + Leaf = Src1[0]; + NestedLHS = Src2[0]; + NestedRHS = Src2[1]; + } else { + return; + } + + // Always keep a nested operand, never the leaf operand. + MachineOperand *KeepOp; + if (Leaf->isIdenticalTo(*NestedLHS)) + KeepOp = NestedRHS; + else if (Leaf->isIdenticalTo(*NestedRHS) || + NestedLHS->isIdenticalTo(*NestedRHS)) + KeepOp = NestedLHS; + else + return; Register Reg = MI.getOperand(OpToReplace).getReg(); MI.removeOperand(OpToReplace); - MI.addOperand(Ops[UniqueOpndIdx]); + MI.addOperand(*KeepOp); if (MRI->use_empty(Reg)) MRI->getUniqueVRegDef(Reg)->eraseFromParent(); } diff --git a/llvm/test/CodeGen/AMDGPU/lower-control-flow-other-terminators.mir b/llvm/test/CodeGen/AMDGPU/lower-control-flow-other-terminators.mir index 33f1a09fae5d3..84b348fd86bb0 100644 --- a/llvm/test/CodeGen/AMDGPU/lower-control-flow-other-terminators.mir +++ b/llvm/test/CodeGen/AMDGPU/lower-control-flow-other-terminators.mir @@ -270,3 +270,75 @@ body: | S_BRANCH %bb.2 ... + +# combineMasks must keep a nested operand, not the exec leaf, when the nested +# S_AND is the first operand and has identical operands (S_AND %0, %0). The +# result must be S_AND exec, %0, not S_AND exec, exec. + +--- +name: combine_masks_nested_first_operand +tracksRegLiveness: true +body: | + ; CHECK-LABEL: name: combine_masks_nested_first_operand + ; CHECK: bb.0: + ; CHECK-NEXT: successors: %bb.0(0x40000000), %bb.1(0x40000000) + ; CHECK-NEXT: liveins: $sgpr0_sgpr1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:sreg_64 = COPY $sgpr0_sgpr1 + ; CHECK-NEXT: [[S_AND_B64_:%[0-9]+]]:sreg_64 = S_AND_B64 $exec, [[COPY]], implicit-def $scc + ; CHECK-NEXT: $exec = S_ANDN2_B64_term $exec, [[S_AND_B64_]], implicit-def $scc + ; CHECK-NEXT: S_CBRANCH_EXECNZ %bb.0, implicit $exec + ; CHECK-NEXT: S_BRANCH %bb.1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.1: + ; CHECK-NEXT: S_ENDPGM 0 + bb.0: + successors: %bb.0, %bb.1 + liveins: $sgpr0_sgpr1 + + %0:sreg_64 = COPY $sgpr0_sgpr1 + %1:sreg_64 = S_AND_B64 %0, %0, implicit-def dead $scc + %2:sreg_64 = S_AND_B64 %1, $exec, implicit-def $scc + SI_LOOP %2, %bb.0, implicit-def $exec, implicit-def $scc, implicit $exec + S_BRANCH %bb.1 + + bb.1: + S_ENDPGM 0 + +... + +# combineMasks must keep a nested operand, not the exec leaf, when the nested +# S_AND is the second operand and has identical operands (S_AND %0, %0). The +# result must be S_AND exec, %0, not S_AND exec, exec. + +--- +name: combine_masks_nested_second_operand +tracksRegLiveness: true +body: | + ; CHECK-LABEL: name: combine_masks_nested_second_operand + ; CHECK: bb.0: + ; CHECK-NEXT: successors: %bb.0(0x40000000), %bb.1(0x40000000) + ; CHECK-NEXT: liveins: $sgpr0_sgpr1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:sreg_64 = COPY $sgpr0_sgpr1 + ; CHECK-NEXT: [[S_AND_B64_:%[0-9]+]]:sreg_64 = S_AND_B64 $exec, [[COPY]], implicit-def $scc + ; CHECK-NEXT: $exec = S_ANDN2_B64_term $exec, [[S_AND_B64_]], implicit-def $scc + ; CHECK-NEXT: S_CBRANCH_EXECNZ %bb.0, implicit $exec + ; CHECK-NEXT: S_BRANCH %bb.1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.1: + ; CHECK-NEXT: S_ENDPGM 0 + bb.0: + successors: %bb.0, %bb.1 + liveins: $sgpr0_sgpr1 + + %0:sreg_64 = COPY $sgpr0_sgpr1 + %1:sreg_64 = S_AND_B64 %0, %0, implicit-def dead $scc + %2:sreg_64 = S_AND_B64 $exec, %1, implicit-def $scc + SI_LOOP %2, %bb.0, implicit-def $exec, implicit-def $scc, implicit $exec + S_BRANCH %bb.1 + + bb.1: + S_ENDPGM 0 + +... From b3946b5bb5c9a4b5feadfe532270ef823116a617 Mon Sep 17 00:00:00 2001 From: Walter Lee <49250218+googlewalt@users.noreply.github.com> Date: Thu, 6 Aug 2026 15:58:29 -0400 Subject: [PATCH 006/789] [CodeGen] Fix null pointer dereferencing issue (#214543) Fixes #197580. Fixes 99f7018958ed3daf2abf8d49178c24fbf1eb1010. In Rematerializer::isRegIdenticalAtUses(), handle case when DefVN is null. --- llvm/lib/CodeGen/Rematerializer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/llvm/lib/CodeGen/Rematerializer.cpp b/llvm/lib/CodeGen/Rematerializer.cpp index c26ba11f44a84..088ab6af402ba 100644 --- a/llvm/lib/CodeGen/Rematerializer.cpp +++ b/llvm/lib/CodeGen/Rematerializer.cpp @@ -240,6 +240,8 @@ bool Rematerializer::isRegIdenticalAtUses(Register Reg, LaneBitmask Mask, return true; const LiveInterval &LI = LIS.getInterval(Reg); const VNInfo *DefVN = LI.getVNInfoAt(RefSlot); + if (!DefVN) + return false; for (SlotIndex Use : Uses) { if (!isIdenticalAtUse(*DefVN, Mask, Use, LI)) return false; From 5e8ac69abe478b1702000878d47fddb6234af725 Mon Sep 17 00:00:00 2001 From: Arseniy Obolenskiy Date: Thu, 6 Aug 2026 22:33:09 +0200 Subject: [PATCH 007/789] [AMDGPU] Fold fsub into fma_mix via free neg_lo modifier (#212305) Rewrite the fsub->fma_mix pattern as `fma((-y), 1.0, x)` using the free neg_lo modifier instead of multiplying by -1.0 (which doesn't always flip the sign of NaN), use the hardware free neg_lo bit, which does a true sign flip. As a result, now the fold always matches fsub actual behavior instead of only in the common case (non-NaN FP numbers) --- llvm/lib/Target/AMDGPU/AMDGPUGISel.td | 8 + llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.cpp | 38 +++ llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.h | 8 + .../AMDGPU/AMDGPUInstructionSelector.cpp | 34 +++ .../Target/AMDGPU/AMDGPUInstructionSelector.h | 2 + llvm/lib/Target/AMDGPU/SIInstrInfo.td | 4 + llvm/lib/Target/AMDGPU/VOP3PInstructions.td | 15 +- .../GlobalISel/combine-fma-sub-ext-mul.ll | 16 +- .../GlobalISel/combine-fma-sub-ext-neg-mul.ll | 32 +-- llvm/test/CodeGen/AMDGPU/bf16.ll | 2 +- llvm/test/CodeGen/AMDGPU/fpext-free.ll | 28 +- llvm/test/CodeGen/AMDGPU/mad-mix-bf16.ll | 32 ++- llvm/test/CodeGen/AMDGPU/mad-mix.ll | 241 +++++++++--------- 13 files changed, 280 insertions(+), 180 deletions(-) diff --git a/llvm/lib/Target/AMDGPU/AMDGPUGISel.td b/llvm/lib/Target/AMDGPU/AMDGPUGISel.td index 5df9834f4ef80..d970126c726d2 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUGISel.td +++ b/llvm/lib/Target/AMDGPU/AMDGPUGISel.td @@ -217,6 +217,14 @@ def gi_vop3_mad_mix_mods_ext : GIComplexOperandMatcher, GIComplexPatternEquiv; +def gi_vop3_mad_mix_mods_neg : + GIComplexOperandMatcher, + GIComplexPatternEquiv; + +def gi_vop3_mad_mix_mods_ext_neg : + GIComplexOperandMatcher, + GIComplexPatternEquiv; + // Separate load nodes are defined to glue m0 initialization in // SelectionDAG. The GISel selector can just insert m0 initialization // directly before selecting a glue-less load, so hide this diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.cpp b/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.cpp index a6fa716fd1598..40345819a3f8d 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.cpp @@ -4360,6 +4360,25 @@ bool AMDGPUDAGToDAGISel::SelectVOP3PMadMixMods(SDValue In, SDValue &Src, return true; } +bool AMDGPUDAGToDAGISel::SelectVOP3PMadMixModsExtNeg(SDValue In, SDValue &Src, + SDValue &SrcMods) const { + unsigned Mods = 0; + if (!SelectVOP3PMadMixModsImpl(In, Src, Mods, MVT::f16)) + return false; + SrcMods = + CurDAG->getTargetConstant(Mods ^ SISrcMods::NEG, SDLoc(In), MVT::i32); + return true; +} + +bool AMDGPUDAGToDAGISel::SelectVOP3PMadMixModsNeg(SDValue In, SDValue &Src, + SDValue &SrcMods) const { + unsigned Mods = 0; + SelectVOP3PMadMixModsImpl(In, Src, Mods, MVT::f16); + SrcMods = + CurDAG->getTargetConstant(Mods ^ SISrcMods::NEG, SDLoc(In), MVT::i32); + return true; +} + bool AMDGPUDAGToDAGISel::SelectVOP3PMadMixBF16ModsExt(SDValue In, SDValue &Src, SDValue &SrcMods) const { unsigned Mods = 0; @@ -4377,6 +4396,25 @@ bool AMDGPUDAGToDAGISel::SelectVOP3PMadMixBF16Mods(SDValue In, SDValue &Src, return true; } +bool AMDGPUDAGToDAGISel::SelectVOP3PMadMixBF16ModsExtNeg( + SDValue In, SDValue &Src, SDValue &SrcMods) const { + unsigned Mods = 0; + if (!SelectVOP3PMadMixModsImpl(In, Src, Mods, MVT::bf16)) + return false; + SrcMods = + CurDAG->getTargetConstant(Mods ^ SISrcMods::NEG, SDLoc(In), MVT::i32); + return true; +} + +bool AMDGPUDAGToDAGISel::SelectVOP3PMadMixBF16ModsNeg(SDValue In, SDValue &Src, + SDValue &SrcMods) const { + unsigned Mods = 0; + SelectVOP3PMadMixModsImpl(In, Src, Mods, MVT::bf16); + SrcMods = + CurDAG->getTargetConstant(Mods ^ SISrcMods::NEG, SDLoc(In), MVT::i32); + return true; +} + // Match BITOP3 operation and return a number of matched instructions plus // truth table. static std::pair BitOp3_Op(SDValue In, diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.h b/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.h index 95f85a6151375..3b7e76a508d1b 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.h +++ b/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.h @@ -267,10 +267,18 @@ class AMDGPUDAGToDAGISel : public SelectionDAGISel { bool SelectVOP3PMadMixModsExt(SDValue In, SDValue &Src, SDValue &SrcMods) const; bool SelectVOP3PMadMixMods(SDValue In, SDValue &Src, SDValue &SrcMods) const; + bool SelectVOP3PMadMixModsExtNeg(SDValue In, SDValue &Src, + SDValue &SrcMods) const; + bool SelectVOP3PMadMixModsNeg(SDValue In, SDValue &Src, + SDValue &SrcMods) const; bool SelectVOP3PMadMixBF16ModsExt(SDValue In, SDValue &Src, SDValue &SrcMods) const; bool SelectVOP3PMadMixBF16Mods(SDValue In, SDValue &Src, SDValue &SrcMods) const; + bool SelectVOP3PMadMixBF16ModsExtNeg(SDValue In, SDValue &Src, + SDValue &SrcMods) const; + bool SelectVOP3PMadMixBF16ModsNeg(SDValue In, SDValue &Src, + SDValue &SrcMods) const; bool SelectBITOP3(SDValue In, SDValue &Src0, SDValue &Src1, SDValue &Src2, SDValue &Tbl) const; diff --git a/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp b/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp index a55fd93cd6195..677312f4f0f52 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp @@ -7267,6 +7267,40 @@ AMDGPUInstructionSelector::selectVOP3PMadMixMods(MachineOperand &Root) const { }}; } +InstructionSelector::ComplexRendererFns +AMDGPUInstructionSelector::selectVOP3PMadMixModsExtNeg( + MachineOperand &Root) const { + Register Src; + unsigned Mods; + bool Matched; + std::tie(Src, Mods) = selectVOP3PMadMixModsImpl(Root, Matched); + if (!Matched) + return {}; + + return {{ + [=](MachineInstrBuilder &MIB) { MIB.addReg(Src); }, + [=](MachineInstrBuilder &MIB) { + MIB.addImm(Mods ^ SISrcMods::NEG); + } // src_mods + }}; +} + +InstructionSelector::ComplexRendererFns +AMDGPUInstructionSelector::selectVOP3PMadMixModsNeg( + MachineOperand &Root) const { + Register Src; + unsigned Mods; + bool Matched; + std::tie(Src, Mods) = selectVOP3PMadMixModsImpl(Root, Matched); + + return {{ + [=](MachineInstrBuilder &MIB) { MIB.addReg(Src); }, + [=](MachineInstrBuilder &MIB) { + MIB.addImm(Mods ^ SISrcMods::NEG); + } // src_mods + }}; +} + bool AMDGPUInstructionSelector::selectSBarrierSignalIsfirst( MachineInstr &I, Intrinsic::ID IntrID) const { MachineBasicBlock *MBB = I.getParent(); diff --git a/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.h b/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.h index 1f9531ce2fa13..1fb7a231a6829 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.h +++ b/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.h @@ -352,6 +352,8 @@ class AMDGPUInstructionSelector final : public InstructionSelector { bool &Matched) const; ComplexRendererFns selectVOP3PMadMixModsExt(MachineOperand &Root) const; ComplexRendererFns selectVOP3PMadMixMods(MachineOperand &Root) const; + ComplexRendererFns selectVOP3PMadMixModsExtNeg(MachineOperand &Root) const; + ComplexRendererFns selectVOP3PMadMixModsNeg(MachineOperand &Root) const; void renderTruncImm32(MachineInstrBuilder &MIB, const MachineInstr &MI, int OpIdx = -1) const; diff --git a/llvm/lib/Target/AMDGPU/SIInstrInfo.td b/llvm/lib/Target/AMDGPU/SIInstrInfo.td index 4fb2c0f406c29..5baf52dd12407 100644 --- a/llvm/lib/Target/AMDGPU/SIInstrInfo.td +++ b/llvm/lib/Target/AMDGPU/SIInstrInfo.td @@ -1741,8 +1741,12 @@ def VOP3OpSelMods : ComplexPattern; def VOP3PMadMixModsExt : ComplexPattern; def VOP3PMadMixMods : ComplexPattern; +def VOP3PMadMixModsExtNeg : ComplexPattern; +def VOP3PMadMixModsNeg : ComplexPattern; def VOP3PMadMixBF16ModsExt : ComplexPattern; def VOP3PMadMixBF16Mods : ComplexPattern; +def VOP3PMadMixBF16ModsExtNeg : ComplexPattern; +def VOP3PMadMixBF16ModsNeg : ComplexPattern; def VINTERPMods : ComplexPattern; def VINTERPModsHi : ComplexPattern; diff --git a/llvm/lib/Target/AMDGPU/VOP3PInstructions.td b/llvm/lib/Target/AMDGPU/VOP3PInstructions.td index 87793bf71f337..b4021b411bc37 100644 --- a/llvm/lib/Target/AMDGPU/VOP3PInstructions.td +++ b/llvm/lib/Target/AMDGPU/VOP3PInstructions.td @@ -245,8 +245,9 @@ multiclass MadFmaMixFP32Pats { defvar VOP3PMadMixModsPat = !if (!eq(VT, bf16), VOP3PMadMixBF16Mods, VOP3PMadMixMods); defvar VOP3PMadMixModsExtPat = !if (!eq(VT, bf16), VOP3PMadMixBF16ModsExt, VOP3PMadMixModsExt); + defvar VOP3PMadMixModsNegPat = !if (!eq(VT, bf16), VOP3PMadMixBF16ModsNeg, VOP3PMadMixModsNeg); + defvar VOP3PMadMixModsExtNegPat = !if (!eq(VT, bf16), VOP3PMadMixBF16ModsExtNeg, VOP3PMadMixModsExtNeg); defvar OneImm = !if (!eq(VT, bf16), CONST.BF16_ONE, CONST.FP16_ONE); - defvar NegOneImm = !if (!eq(VT, bf16), CONST.BF16_NEG_ONE, CONST.FP16_NEG_ONE); defvar ImmMods = !if (!eq(VT, bf16), !or(SRCMODS.OP_SEL_0, SRCMODS.OP_SEL_1), SRCMODS.OP_SEL_1); // At least one of the operands needs to be an fpextend of an f16 // for this to be worthwhile, so we need three patterns here. @@ -284,18 +285,18 @@ multiclass MadFmaMixFP32Pats; - // (fsub x, y) -> (fma y, -1.0, x) + // (fsub x, y) -> (fma (-y), 1.0, x) def : GCNPat < (f32 (fsub (f32 (VOP3PMadMixModsExtPat VT:$src0, i32:$src0_mods)), - (f32 (VOP3PMadMixModsPat f32:$src1, i32:$src1_mods)))), - (mix_inst $src1_mods, $src1, (i32 ImmMods), (i32 NegOneImm), $src0_mods, $src0, + (f32 (VOP3PMadMixModsNegPat f32:$src1, i32:$src1_mods)))), + (mix_inst $src1_mods, $src1, (i32 ImmMods), (i32 OneImm), $src0_mods, $src0, DSTCLAMP.NONE)>; - // (fsub x, y) -> (fma y, -1.0, x) + // (fsub x, y) -> (fma (-y), 1.0, x) def : GCNPat < (f32 (fsub (f32 (VOP3PMadMixModsPat f32:$src0, i32:$src0_mods)), - (f32 (VOP3PMadMixModsExtPat VT:$src1, i32:$src1_mods)))), - (mix_inst $src1_mods, $src1, (i32 ImmMods), (i32 NegOneImm), $src0_mods, $src0, + (f32 (VOP3PMadMixModsExtNegPat VT:$src1, i32:$src1_mods)))), + (mix_inst $src1_mods, $src1, (i32 ImmMods), (i32 OneImm), $src0_mods, $src0, DSTCLAMP.NONE)>; } diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/combine-fma-sub-ext-mul.ll b/llvm/test/CodeGen/AMDGPU/GlobalISel/combine-fma-sub-ext-mul.ll index 55cf23b88306e..06509cfa11434 100644 --- a/llvm/test/CodeGen/AMDGPU/GlobalISel/combine-fma-sub-ext-mul.ll +++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/combine-fma-sub-ext-mul.ll @@ -44,10 +44,10 @@ define amdgpu_vs <4 x float> @test_v4f16_to_v4f32_sub_ext_mul(<4 x half> %x, <4 ; GFX9-DENORM: ; %bb.0: ; %entry ; GFX9-DENORM-NEXT: v_pk_mul_f16 v2, v0, v2 ; GFX9-DENORM-NEXT: v_pk_mul_f16 v3, v1, v3 -; GFX9-DENORM-NEXT: v_mad_mix_f32 v0, v4, -1.0, v2 op_sel_hi:[0,1,1] -; GFX9-DENORM-NEXT: v_mad_mix_f32 v1, v5, -1.0, v2 op_sel:[0,0,1] op_sel_hi:[0,1,1] -; GFX9-DENORM-NEXT: v_mad_mix_f32 v2, v6, -1.0, v3 op_sel_hi:[0,1,1] -; GFX9-DENORM-NEXT: v_mad_mix_f32 v3, v7, -1.0, v3 op_sel:[0,0,1] op_sel_hi:[0,1,1] +; GFX9-DENORM-NEXT: v_mad_mix_f32 v0, -v4, 1.0, v2 op_sel_hi:[0,1,1] +; GFX9-DENORM-NEXT: v_mad_mix_f32 v1, -v5, 1.0, v2 op_sel:[0,0,1] op_sel_hi:[0,1,1] +; GFX9-DENORM-NEXT: v_mad_mix_f32 v2, -v6, 1.0, v3 op_sel_hi:[0,1,1] +; GFX9-DENORM-NEXT: v_mad_mix_f32 v3, -v7, 1.0, v3 op_sel:[0,0,1] op_sel_hi:[0,1,1] ; GFX9-DENORM-NEXT: ; return to shader part epilog ; ; GFX10-DENORM-LABEL: test_v4f16_to_v4f32_sub_ext_mul: @@ -72,10 +72,10 @@ define amdgpu_vs <4 x float> @test_v4f16_to_v4f32_sub_ext_mul_rhs(<4 x float> %x ; GFX9-DENORM: ; %bb.0: ; %.entry ; GFX9-DENORM-NEXT: v_pk_mul_f16 v4, v4, v6 ; GFX9-DENORM-NEXT: v_pk_mul_f16 v5, v5, v7 -; GFX9-DENORM-NEXT: v_mad_mix_f32 v0, v4, -1.0, v0 op_sel_hi:[1,1,0] -; GFX9-DENORM-NEXT: v_mad_mix_f32 v1, v4, -1.0, v1 op_sel:[1,0,0] op_sel_hi:[1,1,0] -; GFX9-DENORM-NEXT: v_mad_mix_f32 v2, v5, -1.0, v2 op_sel_hi:[1,1,0] -; GFX9-DENORM-NEXT: v_mad_mix_f32 v3, v5, -1.0, v3 op_sel:[1,0,0] op_sel_hi:[1,1,0] +; GFX9-DENORM-NEXT: v_mad_mix_f32 v0, -v4, 1.0, v0 op_sel_hi:[1,1,0] +; GFX9-DENORM-NEXT: v_mad_mix_f32 v1, -v4, 1.0, v1 op_sel:[1,0,0] op_sel_hi:[1,1,0] +; GFX9-DENORM-NEXT: v_mad_mix_f32 v2, -v5, 1.0, v2 op_sel_hi:[1,1,0] +; GFX9-DENORM-NEXT: v_mad_mix_f32 v3, -v5, 1.0, v3 op_sel:[1,0,0] op_sel_hi:[1,1,0] ; GFX9-DENORM-NEXT: ; return to shader part epilog ; ; GFX10-DENORM-LABEL: test_v4f16_to_v4f32_sub_ext_mul_rhs: diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/combine-fma-sub-ext-neg-mul.ll b/llvm/test/CodeGen/AMDGPU/GlobalISel/combine-fma-sub-ext-neg-mul.ll index 4f06c0f436a00..feee19e641d7f 100644 --- a/llvm/test/CodeGen/AMDGPU/GlobalISel/combine-fma-sub-ext-neg-mul.ll +++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/combine-fma-sub-ext-neg-mul.ll @@ -85,10 +85,10 @@ define amdgpu_vs <4 x float> @test_v4f16_to_v4f32_sub_ext_neg_mul(<4 x half> %x, ; GFX9-DENORM: ; %bb.0: ; %entry ; GFX9-DENORM-NEXT: v_pk_mul_f16 v2, v0, v2 neg_lo:[0,1] neg_hi:[0,1] ; GFX9-DENORM-NEXT: v_pk_mul_f16 v3, v1, v3 neg_lo:[0,1] neg_hi:[0,1] -; GFX9-DENORM-NEXT: v_mad_mix_f32 v0, v4, -1.0, v2 op_sel_hi:[0,1,1] -; GFX9-DENORM-NEXT: v_mad_mix_f32 v1, v5, -1.0, v2 op_sel:[0,0,1] op_sel_hi:[0,1,1] -; GFX9-DENORM-NEXT: v_mad_mix_f32 v2, v6, -1.0, v3 op_sel_hi:[0,1,1] -; GFX9-DENORM-NEXT: v_mad_mix_f32 v3, v7, -1.0, v3 op_sel:[0,0,1] op_sel_hi:[0,1,1] +; GFX9-DENORM-NEXT: v_mad_mix_f32 v0, -v4, 1.0, v2 op_sel_hi:[0,1,1] +; GFX9-DENORM-NEXT: v_mad_mix_f32 v1, -v5, 1.0, v2 op_sel:[0,0,1] op_sel_hi:[0,1,1] +; GFX9-DENORM-NEXT: v_mad_mix_f32 v2, -v6, 1.0, v3 op_sel_hi:[0,1,1] +; GFX9-DENORM-NEXT: v_mad_mix_f32 v3, -v7, 1.0, v3 op_sel:[0,0,1] op_sel_hi:[0,1,1] ; GFX9-DENORM-NEXT: ; return to shader part epilog ; ; GFX10-DENORM-LABEL: test_v4f16_to_v4f32_sub_ext_neg_mul: @@ -115,10 +115,10 @@ define amdgpu_vs <4 x float> @test_v4f16_to_v4f32_sub_neg_ext_mul(<4 x half> %x, ; GFX9-DENORM: ; %bb.0: ; %entry ; GFX9-DENORM-NEXT: v_pk_mul_f16 v2, v0, v2 neg_lo:[0,1] neg_hi:[0,1] ; GFX9-DENORM-NEXT: v_pk_mul_f16 v3, v1, v3 neg_lo:[0,1] neg_hi:[0,1] -; GFX9-DENORM-NEXT: v_mad_mix_f32 v0, v4, -1.0, v2 op_sel_hi:[0,1,1] -; GFX9-DENORM-NEXT: v_mad_mix_f32 v1, v5, -1.0, v2 op_sel:[0,0,1] op_sel_hi:[0,1,1] -; GFX9-DENORM-NEXT: v_mad_mix_f32 v2, v6, -1.0, v3 op_sel_hi:[0,1,1] -; GFX9-DENORM-NEXT: v_mad_mix_f32 v3, v7, -1.0, v3 op_sel:[0,0,1] op_sel_hi:[0,1,1] +; GFX9-DENORM-NEXT: v_mad_mix_f32 v0, -v4, 1.0, v2 op_sel_hi:[0,1,1] +; GFX9-DENORM-NEXT: v_mad_mix_f32 v1, -v5, 1.0, v2 op_sel:[0,0,1] op_sel_hi:[0,1,1] +; GFX9-DENORM-NEXT: v_mad_mix_f32 v2, -v6, 1.0, v3 op_sel_hi:[0,1,1] +; GFX9-DENORM-NEXT: v_mad_mix_f32 v3, -v7, 1.0, v3 op_sel:[0,0,1] op_sel_hi:[0,1,1] ; GFX9-DENORM-NEXT: ; return to shader part epilog ; ; GFX10-DENORM-LABEL: test_v4f16_to_v4f32_sub_neg_ext_mul: @@ -146,10 +146,10 @@ define amdgpu_vs <4 x float> @test_v4f16_to_v4f32_sub_ext_neg_mul2(<4 x float> % ; GFX9-DENORM: ; %bb.0: ; %entry ; GFX9-DENORM-NEXT: v_pk_mul_f16 v4, v4, v6 neg_lo:[0,1] neg_hi:[0,1] ; GFX9-DENORM-NEXT: v_pk_mul_f16 v5, v5, v7 neg_lo:[0,1] neg_hi:[0,1] -; GFX9-DENORM-NEXT: v_mad_mix_f32 v0, v4, -1.0, v0 op_sel_hi:[1,1,0] -; GFX9-DENORM-NEXT: v_mad_mix_f32 v1, v4, -1.0, v1 op_sel:[1,0,0] op_sel_hi:[1,1,0] -; GFX9-DENORM-NEXT: v_mad_mix_f32 v2, v5, -1.0, v2 op_sel_hi:[1,1,0] -; GFX9-DENORM-NEXT: v_mad_mix_f32 v3, v5, -1.0, v3 op_sel:[1,0,0] op_sel_hi:[1,1,0] +; GFX9-DENORM-NEXT: v_mad_mix_f32 v0, -v4, 1.0, v0 op_sel_hi:[1,1,0] +; GFX9-DENORM-NEXT: v_mad_mix_f32 v1, -v4, 1.0, v1 op_sel:[1,0,0] op_sel_hi:[1,1,0] +; GFX9-DENORM-NEXT: v_mad_mix_f32 v2, -v5, 1.0, v2 op_sel_hi:[1,1,0] +; GFX9-DENORM-NEXT: v_mad_mix_f32 v3, -v5, 1.0, v3 op_sel:[1,0,0] op_sel_hi:[1,1,0] ; GFX9-DENORM-NEXT: ; return to shader part epilog ; ; GFX10-DENORM-LABEL: test_v4f16_to_v4f32_sub_ext_neg_mul2: @@ -175,10 +175,10 @@ define amdgpu_vs <4 x float> @test_v4f16_to_v4f32_sub_neg_ext_mul2(<4 x float> % ; GFX9-DENORM: ; %bb.0: ; %entry ; GFX9-DENORM-NEXT: v_pk_mul_f16 v4, v4, v6 neg_lo:[0,1] neg_hi:[0,1] ; GFX9-DENORM-NEXT: v_pk_mul_f16 v5, v5, v7 neg_lo:[0,1] neg_hi:[0,1] -; GFX9-DENORM-NEXT: v_mad_mix_f32 v0, v4, -1.0, v0 op_sel_hi:[1,1,0] -; GFX9-DENORM-NEXT: v_mad_mix_f32 v1, v4, -1.0, v1 op_sel:[1,0,0] op_sel_hi:[1,1,0] -; GFX9-DENORM-NEXT: v_mad_mix_f32 v2, v5, -1.0, v2 op_sel_hi:[1,1,0] -; GFX9-DENORM-NEXT: v_mad_mix_f32 v3, v5, -1.0, v3 op_sel:[1,0,0] op_sel_hi:[1,1,0] +; GFX9-DENORM-NEXT: v_mad_mix_f32 v0, -v4, 1.0, v0 op_sel_hi:[1,1,0] +; GFX9-DENORM-NEXT: v_mad_mix_f32 v1, -v4, 1.0, v1 op_sel:[1,0,0] op_sel_hi:[1,1,0] +; GFX9-DENORM-NEXT: v_mad_mix_f32 v2, -v5, 1.0, v2 op_sel_hi:[1,1,0] +; GFX9-DENORM-NEXT: v_mad_mix_f32 v3, -v5, 1.0, v3 op_sel:[1,0,0] op_sel_hi:[1,1,0] ; GFX9-DENORM-NEXT: ; return to shader part epilog ; ; GFX10-DENORM-LABEL: test_v4f16_to_v4f32_sub_neg_ext_mul2: diff --git a/llvm/test/CodeGen/AMDGPU/bf16.ll b/llvm/test/CodeGen/AMDGPU/bf16.ll index 6a53b189d4c08..abb378ef828dd 100644 --- a/llvm/test/CodeGen/AMDGPU/bf16.ll +++ b/llvm/test/CodeGen/AMDGPU/bf16.ll @@ -31028,7 +31028,7 @@ define bfloat @v_round_bf16(bfloat %a) #0 { ; GFX1250-NEXT: v_lshlrev_b32_e32 v1, 16, v0 ; GFX1250-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1) ; GFX1250-NEXT: v_trunc_f32_e32 v2, v1 -; GFX1250-NEXT: v_fma_mix_f32_bf16 v0, v2, -1.0, v0 op_sel:[0,1,0] op_sel_hi:[0,1,1] +; GFX1250-NEXT: v_fma_mix_f32_bf16 v0, -v2, 1.0, v0 op_sel:[0,1,0] op_sel_hi:[0,1,1] ; GFX1250-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1) ; GFX1250-NEXT: v_cmp_ge_f32_e64 s0, |v0|, 0.5 ; GFX1250-NEXT: v_cndmask_b32_e64 v0, 0, 1.0, s0 diff --git a/llvm/test/CodeGen/AMDGPU/fpext-free.ll b/llvm/test/CodeGen/AMDGPU/fpext-free.ll index d3cc8d752310a..2068634a3e553 100644 --- a/llvm/test/CodeGen/AMDGPU/fpext-free.ll +++ b/llvm/test/CodeGen/AMDGPU/fpext-free.ll @@ -624,7 +624,7 @@ define float @fsub_fpext_fmul_f16_to_f32(half %x, half %y, float %z) #0 { ; GFX11-TRUE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) ; GFX11-TRUE16-NEXT: v_mul_f16_e32 v0.l, v0.l, v1.l ; GFX11-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_1) -; GFX11-TRUE16-NEXT: v_fma_mix_f32 v0, v2, -1.0, v0 op_sel_hi:[0,1,1] +; GFX11-TRUE16-NEXT: v_fma_mix_f32 v0, -v2, 1.0, v0 op_sel_hi:[0,1,1] ; GFX11-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX11-FAKE16-LABEL: fsub_fpext_fmul_f16_to_f32: @@ -632,7 +632,7 @@ define float @fsub_fpext_fmul_f16_to_f32(half %x, half %y, float %z) #0 { ; GFX11-FAKE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) ; GFX11-FAKE16-NEXT: v_mul_f16_e32 v0, v0, v1 ; GFX11-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) -; GFX11-FAKE16-NEXT: v_fma_mix_f32 v0, v2, -1.0, v0 op_sel_hi:[0,1,1] +; GFX11-FAKE16-NEXT: v_fma_mix_f32 v0, -v2, 1.0, v0 op_sel_hi:[0,1,1] ; GFX11-FAKE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX9-F32FLUSH-LABEL: fsub_fpext_fmul_f16_to_f32: @@ -677,7 +677,7 @@ define float @fsub_fpext_fmul_f16_to_f32_commute(float %x, half %y, half %z) #0 ; GFX11-F32DENORM-TRUE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) ; GFX11-F32DENORM-TRUE16-NEXT: v_mul_f16_e32 v1.l, v1.l, v2.l ; GFX11-F32DENORM-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_1) -; GFX11-F32DENORM-TRUE16-NEXT: v_fma_mix_f32 v0, v1, -1.0, v0 op_sel_hi:[1,1,0] +; GFX11-F32DENORM-TRUE16-NEXT: v_fma_mix_f32 v0, -v1, 1.0, v0 op_sel_hi:[1,1,0] ; GFX11-F32DENORM-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX11-F32DENORM-FAKE16-LABEL: fsub_fpext_fmul_f16_to_f32_commute: @@ -685,7 +685,7 @@ define float @fsub_fpext_fmul_f16_to_f32_commute(float %x, half %y, half %z) #0 ; GFX11-F32DENORM-FAKE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) ; GFX11-F32DENORM-FAKE16-NEXT: v_mul_f16_e32 v1, v1, v2 ; GFX11-F32DENORM-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) -; GFX11-F32DENORM-FAKE16-NEXT: v_fma_mix_f32 v0, v1, -1.0, v0 op_sel_hi:[1,1,0] +; GFX11-F32DENORM-FAKE16-NEXT: v_fma_mix_f32 v0, -v1, 1.0, v0 op_sel_hi:[1,1,0] ; GFX11-F32DENORM-FAKE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX9-F32FLUSH-LABEL: fsub_fpext_fmul_f16_to_f32_commute: @@ -724,7 +724,7 @@ define float @fsub_fpext_fneg_fmul_f16_to_f32(half %x, half %y, float %z) #0 { ; GFX11-TRUE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) ; GFX11-TRUE16-NEXT: v_mul_f16_e64 v0.l, v0.l, -v1.l ; GFX11-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_1) -; GFX11-TRUE16-NEXT: v_fma_mix_f32 v0, v2, -1.0, v0 op_sel_hi:[0,1,1] +; GFX11-TRUE16-NEXT: v_fma_mix_f32 v0, -v2, 1.0, v0 op_sel_hi:[0,1,1] ; GFX11-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX11-FAKE16-LABEL: fsub_fpext_fneg_fmul_f16_to_f32: @@ -732,7 +732,7 @@ define float @fsub_fpext_fneg_fmul_f16_to_f32(half %x, half %y, float %z) #0 { ; GFX11-FAKE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) ; GFX11-FAKE16-NEXT: v_mul_f16_e64 v0, v0, -v1 ; GFX11-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) -; GFX11-FAKE16-NEXT: v_fma_mix_f32 v0, v2, -1.0, v0 op_sel_hi:[0,1,1] +; GFX11-FAKE16-NEXT: v_fma_mix_f32 v0, -v2, 1.0, v0 op_sel_hi:[0,1,1] ; GFX11-FAKE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX9-F32FLUSH-LABEL: fsub_fpext_fneg_fmul_f16_to_f32: @@ -772,7 +772,7 @@ define float @fsub_fneg_fpext_fmul_f16_to_f32(half %x, half %y, float %z) #0 { ; GFX11-TRUE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) ; GFX11-TRUE16-NEXT: v_mul_f16_e64 v0.l, v0.l, -v1.l ; GFX11-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_1) -; GFX11-TRUE16-NEXT: v_fma_mix_f32 v0, v2, -1.0, v0 op_sel_hi:[0,1,1] +; GFX11-TRUE16-NEXT: v_fma_mix_f32 v0, -v2, 1.0, v0 op_sel_hi:[0,1,1] ; GFX11-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX11-FAKE16-LABEL: fsub_fneg_fpext_fmul_f16_to_f32: @@ -780,7 +780,7 @@ define float @fsub_fneg_fpext_fmul_f16_to_f32(half %x, half %y, float %z) #0 { ; GFX11-FAKE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) ; GFX11-FAKE16-NEXT: v_mul_f16_e64 v0, v0, -v1 ; GFX11-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) -; GFX11-FAKE16-NEXT: v_fma_mix_f32 v0, v2, -1.0, v0 op_sel_hi:[0,1,1] +; GFX11-FAKE16-NEXT: v_fma_mix_f32 v0, -v2, 1.0, v0 op_sel_hi:[0,1,1] ; GFX11-FAKE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX9-F32FLUSH-LABEL: fsub_fneg_fpext_fmul_f16_to_f32: @@ -886,7 +886,7 @@ define float @fsub_fpext_muladd_mul_f16_to_f32(half %x, half %y, float %z, half ; GFX11-TRUE16-NEXT: v_mul_f16_e32 v3.l, v3.l, v4.l ; GFX11-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1) ; GFX11-TRUE16-NEXT: v_fmac_f16_e32 v3.l, v0.l, v1.l -; GFX11-TRUE16-NEXT: v_fma_mix_f32 v0, v2, -1.0, v3 op_sel_hi:[0,1,1] +; GFX11-TRUE16-NEXT: v_fma_mix_f32 v0, -v2, 1.0, v3 op_sel_hi:[0,1,1] ; GFX11-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX11-FAKE16-LABEL: fsub_fpext_muladd_mul_f16_to_f32: @@ -895,7 +895,7 @@ define float @fsub_fpext_muladd_mul_f16_to_f32(half %x, half %y, float %z, half ; GFX11-FAKE16-NEXT: v_mul_f16_e32 v3, v3, v4 ; GFX11-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1) ; GFX11-FAKE16-NEXT: v_fmac_f16_e32 v3, v0, v1 -; GFX11-FAKE16-NEXT: v_fma_mix_f32 v0, v2, -1.0, v3 op_sel_hi:[0,1,1] +; GFX11-FAKE16-NEXT: v_fma_mix_f32 v0, -v2, 1.0, v3 op_sel_hi:[0,1,1] ; GFX11-FAKE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX9-F32FLUSH-LABEL: fsub_fpext_muladd_mul_f16_to_f32: @@ -903,7 +903,7 @@ define float @fsub_fpext_muladd_mul_f16_to_f32(half %x, half %y, float %z, half ; GFX9-F32FLUSH-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) ; GFX9-F32FLUSH-NEXT: v_mul_f16_e32 v3, v3, v4 ; GFX9-F32FLUSH-NEXT: v_fma_f16 v0, v0, v1, v3 -; GFX9-F32FLUSH-NEXT: v_mad_mix_f32 v0, v2, -1.0, v0 op_sel_hi:[0,1,1] +; GFX9-F32FLUSH-NEXT: v_mad_mix_f32 v0, -v2, 1.0, v0 op_sel_hi:[0,1,1] ; GFX9-F32FLUSH-NEXT: s_setpc_b64 s[30:31] ; ; GFX9-F32DENORM-LABEL: fsub_fpext_muladd_mul_f16_to_f32: @@ -1004,7 +1004,7 @@ define float @fsub_fpext_muladd_mul_f16_to_f32_commute(float %x, half %y, half % ; GFX11-TRUE16-NEXT: v_mul_f16_e32 v3.l, v3.l, v4.l ; GFX11-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1) ; GFX11-TRUE16-NEXT: v_fmac_f16_e32 v3.l, v1.l, v2.l -; GFX11-TRUE16-NEXT: v_fma_mix_f32 v0, v3, -1.0, v0 op_sel_hi:[1,1,0] +; GFX11-TRUE16-NEXT: v_fma_mix_f32 v0, -v3, 1.0, v0 op_sel_hi:[1,1,0] ; GFX11-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX11-FAKE16-LABEL: fsub_fpext_muladd_mul_f16_to_f32_commute: @@ -1013,7 +1013,7 @@ define float @fsub_fpext_muladd_mul_f16_to_f32_commute(float %x, half %y, half % ; GFX11-FAKE16-NEXT: v_mul_f16_e32 v3, v3, v4 ; GFX11-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1) ; GFX11-FAKE16-NEXT: v_fmac_f16_e32 v3, v1, v2 -; GFX11-FAKE16-NEXT: v_fma_mix_f32 v0, v3, -1.0, v0 op_sel_hi:[1,1,0] +; GFX11-FAKE16-NEXT: v_fma_mix_f32 v0, -v3, 1.0, v0 op_sel_hi:[1,1,0] ; GFX11-FAKE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX9-F32FLUSH-LABEL: fsub_fpext_muladd_mul_f16_to_f32_commute: @@ -1021,7 +1021,7 @@ define float @fsub_fpext_muladd_mul_f16_to_f32_commute(float %x, half %y, half % ; GFX9-F32FLUSH-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) ; GFX9-F32FLUSH-NEXT: v_mul_f16_e32 v3, v3, v4 ; GFX9-F32FLUSH-NEXT: v_fma_f16 v1, v1, v2, v3 -; GFX9-F32FLUSH-NEXT: v_mad_mix_f32 v0, v1, -1.0, v0 op_sel_hi:[1,1,0] +; GFX9-F32FLUSH-NEXT: v_mad_mix_f32 v0, -v1, 1.0, v0 op_sel_hi:[1,1,0] ; GFX9-F32FLUSH-NEXT: s_setpc_b64 s[30:31] ; ; GFX9-F32DENORM-LABEL: fsub_fpext_muladd_mul_f16_to_f32_commute: diff --git a/llvm/test/CodeGen/AMDGPU/mad-mix-bf16.ll b/llvm/test/CodeGen/AMDGPU/mad-mix-bf16.ll index 85f6bb92d6ca9..30377e54c405d 100644 --- a/llvm/test/CodeGen/AMDGPU/mad-mix-bf16.ll +++ b/llvm/test/CodeGen/AMDGPU/mad-mix-bf16.ll @@ -714,7 +714,7 @@ define float @v_mad_mix_f32_negbf16lo_add_bf16lo(bfloat %src0, bfloat %src1) { ; GFX1250: ; %bb.0: ; GFX1250-NEXT: s_wait_loadcnt_dscnt 0x0 ; GFX1250-NEXT: s_wait_kmcnt 0x0 -; GFX1250-NEXT: v_fma_mix_f32_bf16 v0, v0, -1.0, v1 op_sel:[0,1,0] op_sel_hi:[1,1,1] +; GFX1250-NEXT: v_fma_mix_f32_bf16 v0, -v0, 1.0, v1 op_sel:[0,1,0] op_sel_hi:[1,1,1] ; GFX1250-NEXT: s_set_pc_i64 s[30:31] %src0.ext = fpext bfloat %src0 to float %src1.ext = fpext bfloat %src1 to float @@ -742,7 +742,7 @@ define float @v_mad_mix_f32_negabsbf16lo_add_bf16lo(bfloat %src0, bfloat %src1) ; GFX1250: ; %bb.0: ; GFX1250-NEXT: s_wait_loadcnt_dscnt 0x0 ; GFX1250-NEXT: s_wait_kmcnt 0x0 -; GFX1250-NEXT: v_fma_mix_f32_bf16 v0, |v0|, -1.0, v1 op_sel:[0,1,0] op_sel_hi:[1,1,1] +; GFX1250-NEXT: v_fma_mix_f32_bf16 v0, -|v0|, 1.0, v1 op_sel:[0,1,0] op_sel_hi:[1,1,1] ; GFX1250-NEXT: s_set_pc_i64 s[30:31] %src0.ext = fpext bfloat %src0 to float %src1.ext = fpext bfloat %src1 to float @@ -769,7 +769,7 @@ define float @v_mad_mix_f32_bf16lo_add_negf32(bfloat %src0, float %src1) { ; GFX1250: ; %bb.0: ; GFX1250-NEXT: s_wait_loadcnt_dscnt 0x0 ; GFX1250-NEXT: s_wait_kmcnt 0x0 -; GFX1250-NEXT: v_fma_mix_f32_bf16 v0, v1, -1.0, v0 op_sel:[0,1,0] op_sel_hi:[0,1,1] +; GFX1250-NEXT: v_fma_mix_f32_bf16 v0, -v1, 1.0, v0 op_sel:[0,1,0] op_sel_hi:[0,1,1] ; GFX1250-NEXT: s_set_pc_i64 s[30:31] %src0.ext = fpext bfloat %src0 to float %src1.neg = fneg float %src1 @@ -795,7 +795,7 @@ define float @v_mad_mix_f32_bf16lo_add_negabsf32(bfloat %src0, float %src1) { ; GFX1250: ; %bb.0: ; GFX1250-NEXT: s_wait_loadcnt_dscnt 0x0 ; GFX1250-NEXT: s_wait_kmcnt 0x0 -; GFX1250-NEXT: v_fma_mix_f32_bf16 v0, |v1|, -1.0, v0 op_sel:[0,1,0] op_sel_hi:[0,1,1] +; GFX1250-NEXT: v_fma_mix_f32_bf16 v0, -|v1|, 1.0, v0 op_sel:[0,1,0] op_sel_hi:[0,1,1] ; GFX1250-NEXT: s_set_pc_i64 s[30:31] %src0.ext = fpext bfloat %src0 to float %src1.abs = call float @llvm.fabs.f32(float %src1) @@ -849,7 +849,7 @@ define float @v_mad_mix_f32_negprecvtbf16lo_add_bf16lo(i32 %src0.arg, bfloat %sr ; GFX1250: ; %bb.0: ; GFX1250-NEXT: s_wait_loadcnt_dscnt 0x0 ; GFX1250-NEXT: s_wait_kmcnt 0x0 -; GFX1250-NEXT: v_fma_mix_f32_bf16 v0, v0, -1.0, v1 op_sel:[0,1,0] op_sel_hi:[1,1,1] +; GFX1250-NEXT: v_fma_mix_f32_bf16 v0, -v0, 1.0, v1 op_sel:[0,1,0] op_sel_hi:[1,1,1] ; GFX1250-NEXT: s_set_pc_i64 s[30:31] %src0.arg.bc = bitcast i32 %src0.arg to <2 x bfloat> %src0 = extractelement <2 x bfloat> %src0.arg.bc, i32 0 @@ -881,7 +881,7 @@ define float @v_mad_mix_f32_negabsprecvtbf16lo_add_bf16lo(i32 %src0.arg, bfloat ; GFX1250: ; %bb.0: ; GFX1250-NEXT: s_wait_loadcnt_dscnt 0x0 ; GFX1250-NEXT: s_wait_kmcnt 0x0 -; GFX1250-NEXT: v_fma_mix_f32_bf16 v0, |v0|, -1.0, v1 op_sel:[0,1,0] op_sel_hi:[1,1,1] +; GFX1250-NEXT: v_fma_mix_f32_bf16 v0, -|v0|, 1.0, v1 op_sel:[0,1,0] op_sel_hi:[1,1,1] ; GFX1250-NEXT: s_set_pc_i64 s[30:31] %src0.arg.bc = bitcast i32 %src0.arg to <2 x bfloat> %src0 = extractelement <2 x bfloat> %src0.arg.bc, i32 0 @@ -1355,7 +1355,7 @@ define float @v_mad_mix_f32_bf16lo_sub_bf16lo(bfloat %src0, bfloat %src1) { ; GFX1250: ; %bb.0: ; GFX1250-NEXT: s_wait_loadcnt_dscnt 0x0 ; GFX1250-NEXT: s_wait_kmcnt 0x0 -; GFX1250-NEXT: v_fma_mix_f32_bf16 v0, v1, -1.0, v0 op_sel:[0,1,0] op_sel_hi:[1,1,1] +; GFX1250-NEXT: v_fma_mix_f32_bf16 v0, -v1, 1.0, v0 op_sel:[0,1,0] op_sel_hi:[1,1,1] ; GFX1250-NEXT: s_set_pc_i64 s[30:31] %src0.ext = fpext bfloat %src0 to float %src1.ext = fpext bfloat %src1 to float @@ -1368,7 +1368,7 @@ define float @v_mad_mix_f32_absbf16lo_sub_bf16lo(bfloat %src0, bfloat %src1) { ; GFX1250: ; %bb.0: ; GFX1250-NEXT: s_wait_loadcnt_dscnt 0x0 ; GFX1250-NEXT: s_wait_kmcnt 0x0 -; GFX1250-NEXT: v_fma_mix_f32_bf16 v0, v1, -1.0, |v0| op_sel:[0,1,0] op_sel_hi:[1,1,1] +; GFX1250-NEXT: v_fma_mix_f32_bf16 v0, -v1, 1.0, |v0| op_sel:[0,1,0] op_sel_hi:[1,1,1] ; GFX1250-NEXT: s_set_pc_i64 s[30:31] %src0.ext = fpext bfloat %src0 to float %src1.ext = fpext bfloat %src1 to float @@ -1382,7 +1382,7 @@ define float @v_mad_mix_f32_bf16hi_fsub_bf16hi(i32 %src0, i32 %src1) { ; GFX1250: ; %bb.0: ; GFX1250-NEXT: s_wait_loadcnt_dscnt 0x0 ; GFX1250-NEXT: s_wait_kmcnt 0x0 -; GFX1250-NEXT: v_fma_mix_f32_bf16 v0, v1, -1.0, v0 op_sel:[1,1,1] op_sel_hi:[1,1,1] +; GFX1250-NEXT: v_fma_mix_f32_bf16 v0, -v1, 1.0, v0 op_sel:[1,1,1] op_sel_hi:[1,1,1] ; GFX1250-NEXT: s_set_pc_i64 s[30:31] %src0.hi = lshr i32 %src0, 16 %src1.hi = lshr i32 %src1, 16 @@ -1401,7 +1401,7 @@ define float @v_mad_mix_f32_absbf16hi_fsub_bf16hi(i32 %src0, i32 %src1) { ; GFX1250: ; %bb.0: ; GFX1250-NEXT: s_wait_loadcnt_dscnt 0x0 ; GFX1250-NEXT: s_wait_kmcnt 0x0 -; GFX1250-NEXT: v_fma_mix_f32_bf16 v0, v1, -1.0, |v0| op_sel:[1,1,1] op_sel_hi:[1,1,1] +; GFX1250-NEXT: v_fma_mix_f32_bf16 v0, -v1, 1.0, |v0| op_sel:[1,1,1] op_sel_hi:[1,1,1] ; GFX1250-NEXT: s_set_pc_i64 s[30:31] %src0.hi = lshr i32 %src0, 16 %src1.hi = lshr i32 %src1, 16 @@ -1416,6 +1416,18 @@ define float @v_mad_mix_f32_absbf16hi_fsub_bf16hi(i32 %src0, i32 %src1) { ret float %result } +define float @v_mad_mix_f32_f32_sub_bf16lo(float %src0, bfloat %src1) { +; GFX1250-LABEL: v_mad_mix_f32_f32_sub_bf16lo: +; GFX1250: ; %bb.0: +; GFX1250-NEXT: s_wait_loadcnt_dscnt 0x0 +; GFX1250-NEXT: s_wait_kmcnt 0x0 +; GFX1250-NEXT: v_fma_mix_f32_bf16 v0, -v1, 1.0, v0 op_sel:[0,1,0] op_sel_hi:[1,1,0] +; GFX1250-NEXT: s_set_pc_i64 s[30:31] + %src1.ext = fpext bfloat %src1 to float + %result = fsub float %src0, %src1.ext + ret float %result +} + declare bfloat @llvm.fabs.bf16(bfloat) #2 declare <2 x bfloat> @llvm.fabs.v2bf16(<2 x bfloat>) #2 declare float @llvm.fabs.f32(float) #2 diff --git a/llvm/test/CodeGen/AMDGPU/mad-mix.ll b/llvm/test/CodeGen/AMDGPU/mad-mix.ll index d1e5af1e1ad12..5969309df7294 100644 --- a/llvm/test/CodeGen/AMDGPU/mad-mix.ll +++ b/llvm/test/CodeGen/AMDGPU/mad-mix.ll @@ -2943,11 +2943,11 @@ define <2 x float> @v_mad_mix_v2f32_shuffle_cvt_add(<2 x half> %src0, <2 x half> } define float @v_mad_mix_f32_negf16lo_add_f16lo(half %src0, half %src1) { -; SDAG-GFX1100-LABEL: v_mad_mix_f32_negf16lo_add_f16lo: -; SDAG-GFX1100: ; %bb.0: -; SDAG-GFX1100-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; SDAG-GFX1100-NEXT: v_fma_mix_f32 v0, v0, -1.0, v1 op_sel_hi:[1,1,1] -; SDAG-GFX1100-NEXT: s_setpc_b64 s[30:31] +; GFX1100-LABEL: v_mad_mix_f32_negf16lo_add_f16lo: +; GFX1100: ; %bb.0: +; GFX1100-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) +; GFX1100-NEXT: v_fma_mix_f32 v0, -v0, 1.0, v1 op_sel_hi:[1,1,1] +; GFX1100-NEXT: s_setpc_b64 s[30:31] ; ; SDAG-GFX900-LABEL: v_mad_mix_f32_negf16lo_add_f16lo: ; SDAG-GFX900: ; %bb.0: @@ -2957,11 +2957,11 @@ define float @v_mad_mix_f32_negf16lo_add_f16lo(half %src0, half %src1) { ; SDAG-GFX900-NEXT: v_sub_f32_e32 v0, v1, v0 ; SDAG-GFX900-NEXT: s_setpc_b64 s[30:31] ; -; SDAG-GFX906-LABEL: v_mad_mix_f32_negf16lo_add_f16lo: -; SDAG-GFX906: ; %bb.0: -; SDAG-GFX906-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; SDAG-GFX906-NEXT: v_fma_mix_f32 v0, v0, -1.0, v1 op_sel_hi:[1,1,1] -; SDAG-GFX906-NEXT: s_setpc_b64 s[30:31] +; GFX906-LABEL: v_mad_mix_f32_negf16lo_add_f16lo: +; GFX906: ; %bb.0: +; GFX906-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) +; GFX906-NEXT: v_fma_mix_f32 v0, -v0, 1.0, v1 op_sel_hi:[1,1,1] +; GFX906-NEXT: s_setpc_b64 s[30:31] ; ; SDAG-GFX9GEN-LABEL: v_mad_mix_f32_negf16lo_add_f16lo: ; SDAG-GFX9GEN: ; %bb.0: @@ -2987,12 +2987,6 @@ define float @v_mad_mix_f32_negf16lo_add_f16lo(half %src0, half %src1) { ; SDAG-CI-NEXT: v_sub_f32_e32 v0, v1, v0 ; SDAG-CI-NEXT: s_setpc_b64 s[30:31] ; -; GISEL-GFX1100-LABEL: v_mad_mix_f32_negf16lo_add_f16lo: -; GISEL-GFX1100: ; %bb.0: -; GISEL-GFX1100-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GISEL-GFX1100-NEXT: v_fma_mix_f32 v0, -v0, 1.0, v1 op_sel_hi:[1,1,1] -; GISEL-GFX1100-NEXT: s_setpc_b64 s[30:31] -; ; GISEL-GFX900-LABEL: v_mad_mix_f32_negf16lo_add_f16lo: ; GISEL-GFX900: ; %bb.0: ; GISEL-GFX900-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) @@ -3001,12 +2995,6 @@ define float @v_mad_mix_f32_negf16lo_add_f16lo(half %src0, half %src1) { ; GISEL-GFX900-NEXT: v_add_f32_e32 v0, v0, v1 ; GISEL-GFX900-NEXT: s_setpc_b64 s[30:31] ; -; GISEL-GFX906-LABEL: v_mad_mix_f32_negf16lo_add_f16lo: -; GISEL-GFX906: ; %bb.0: -; GISEL-GFX906-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GISEL-GFX906-NEXT: v_fma_mix_f32 v0, -v0, 1.0, v1 op_sel_hi:[1,1,1] -; GISEL-GFX906-NEXT: s_setpc_b64 s[30:31] -; ; GISEL-GFX9GEN-LABEL: v_mad_mix_f32_negf16lo_add_f16lo: ; GISEL-GFX9GEN: ; %bb.0: ; GISEL-GFX9GEN-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) @@ -3100,7 +3088,7 @@ define float @v_mad_mix_f32_negabsf16lo_add_f16lo(half %src0, half %src1) { ; GFX1100-LABEL: v_mad_mix_f32_negabsf16lo_add_f16lo: ; GFX1100: ; %bb.0: ; GFX1100-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GFX1100-NEXT: v_fma_mix_f32 v0, |v0|, -1.0, v1 op_sel_hi:[1,1,1] +; GFX1100-NEXT: v_fma_mix_f32 v0, -|v0|, 1.0, v1 op_sel_hi:[1,1,1] ; GFX1100-NEXT: s_setpc_b64 s[30:31] ; ; GFX900-LABEL: v_mad_mix_f32_negabsf16lo_add_f16lo: @@ -3114,7 +3102,7 @@ define float @v_mad_mix_f32_negabsf16lo_add_f16lo(half %src0, half %src1) { ; GFX906-LABEL: v_mad_mix_f32_negabsf16lo_add_f16lo: ; GFX906: ; %bb.0: ; GFX906-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GFX906-NEXT: v_fma_mix_f32 v0, |v0|, -1.0, v1 op_sel_hi:[1,1,1] +; GFX906-NEXT: v_fma_mix_f32 v0, -|v0|, 1.0, v1 op_sel_hi:[1,1,1] ; GFX906-NEXT: s_setpc_b64 s[30:31] ; ; GFX9GEN-LABEL: v_mad_mix_f32_negabsf16lo_add_f16lo: @@ -3205,7 +3193,7 @@ define float @v_mad_mix_f32_f16lo_add_negf32(half %src0, float %src1) { ; GFX1100-LABEL: v_mad_mix_f32_f16lo_add_negf32: ; GFX1100: ; %bb.0: ; GFX1100-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GFX1100-NEXT: v_fma_mix_f32 v0, v1, -1.0, v0 op_sel_hi:[0,1,1] +; GFX1100-NEXT: v_fma_mix_f32 v0, -v1, 1.0, v0 op_sel_hi:[0,1,1] ; GFX1100-NEXT: s_setpc_b64 s[30:31] ; ; GFX900-LABEL: v_mad_mix_f32_f16lo_add_negf32: @@ -3218,7 +3206,7 @@ define float @v_mad_mix_f32_f16lo_add_negf32(half %src0, float %src1) { ; GFX906-LABEL: v_mad_mix_f32_f16lo_add_negf32: ; GFX906: ; %bb.0: ; GFX906-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GFX906-NEXT: v_fma_mix_f32 v0, v1, -1.0, v0 op_sel_hi:[0,1,1] +; GFX906-NEXT: v_fma_mix_f32 v0, -v1, 1.0, v0 op_sel_hi:[0,1,1] ; GFX906-NEXT: s_setpc_b64 s[30:31] ; ; GFX9GEN-LABEL: v_mad_mix_f32_f16lo_add_negf32: @@ -3297,7 +3285,7 @@ define float @v_mad_mix_f32_f16lo_add_negabsf32(half %src0, float %src1) { ; GFX1100-LABEL: v_mad_mix_f32_f16lo_add_negabsf32: ; GFX1100: ; %bb.0: ; GFX1100-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GFX1100-NEXT: v_fma_mix_f32 v0, |v1|, -1.0, v0 op_sel_hi:[0,1,1] +; GFX1100-NEXT: v_fma_mix_f32 v0, -|v1|, 1.0, v0 op_sel_hi:[0,1,1] ; GFX1100-NEXT: s_setpc_b64 s[30:31] ; ; GFX900-LABEL: v_mad_mix_f32_f16lo_add_negabsf32: @@ -3310,7 +3298,7 @@ define float @v_mad_mix_f32_f16lo_add_negabsf32(half %src0, float %src1) { ; GFX906-LABEL: v_mad_mix_f32_f16lo_add_negabsf32: ; GFX906: ; %bb.0: ; GFX906-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GFX906-NEXT: v_fma_mix_f32 v0, |v1|, -1.0, v0 op_sel_hi:[0,1,1] +; GFX906-NEXT: v_fma_mix_f32 v0, -|v1|, 1.0, v0 op_sel_hi:[0,1,1] ; GFX906-NEXT: s_setpc_b64 s[30:31] ; ; GFX9GEN-LABEL: v_mad_mix_f32_f16lo_add_negabsf32: @@ -3488,11 +3476,11 @@ define float @v_mad_mix_clamp_f32_f16hi_add_f16hi(<2 x half> %src0, <2 x half> % } define float @v_mad_mix_f32_negprecvtf16lo_add_f16lo(i32 %src0.arg, half %src1) { -; SDAG-GFX1100-LABEL: v_mad_mix_f32_negprecvtf16lo_add_f16lo: -; SDAG-GFX1100: ; %bb.0: -; SDAG-GFX1100-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; SDAG-GFX1100-NEXT: v_fma_mix_f32 v0, v0, -1.0, v1 op_sel_hi:[1,1,1] -; SDAG-GFX1100-NEXT: s_setpc_b64 s[30:31] +; GFX1100-LABEL: v_mad_mix_f32_negprecvtf16lo_add_f16lo: +; GFX1100: ; %bb.0: +; GFX1100-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) +; GFX1100-NEXT: v_fma_mix_f32 v0, -v0, 1.0, v1 op_sel_hi:[1,1,1] +; GFX1100-NEXT: s_setpc_b64 s[30:31] ; ; SDAG-GFX900-LABEL: v_mad_mix_f32_negprecvtf16lo_add_f16lo: ; SDAG-GFX900: ; %bb.0: @@ -3502,11 +3490,11 @@ define float @v_mad_mix_f32_negprecvtf16lo_add_f16lo(i32 %src0.arg, half %src1) ; SDAG-GFX900-NEXT: v_sub_f32_e32 v0, v1, v0 ; SDAG-GFX900-NEXT: s_setpc_b64 s[30:31] ; -; SDAG-GFX906-LABEL: v_mad_mix_f32_negprecvtf16lo_add_f16lo: -; SDAG-GFX906: ; %bb.0: -; SDAG-GFX906-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; SDAG-GFX906-NEXT: v_fma_mix_f32 v0, v0, -1.0, v1 op_sel_hi:[1,1,1] -; SDAG-GFX906-NEXT: s_setpc_b64 s[30:31] +; GFX906-LABEL: v_mad_mix_f32_negprecvtf16lo_add_f16lo: +; GFX906: ; %bb.0: +; GFX906-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) +; GFX906-NEXT: v_fma_mix_f32 v0, -v0, 1.0, v1 op_sel_hi:[1,1,1] +; GFX906-NEXT: s_setpc_b64 s[30:31] ; ; SDAG-GFX9GEN-LABEL: v_mad_mix_f32_negprecvtf16lo_add_f16lo: ; SDAG-GFX9GEN: ; %bb.0: @@ -3532,12 +3520,6 @@ define float @v_mad_mix_f32_negprecvtf16lo_add_f16lo(i32 %src0.arg, half %src1) ; SDAG-CI-NEXT: v_sub_f32_e32 v0, v1, v0 ; SDAG-CI-NEXT: s_setpc_b64 s[30:31] ; -; GISEL-GFX1100-LABEL: v_mad_mix_f32_negprecvtf16lo_add_f16lo: -; GISEL-GFX1100: ; %bb.0: -; GISEL-GFX1100-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GISEL-GFX1100-NEXT: v_fma_mix_f32 v0, -v0, 1.0, v1 op_sel_hi:[1,1,1] -; GISEL-GFX1100-NEXT: s_setpc_b64 s[30:31] -; ; GISEL-GFX900-LABEL: v_mad_mix_f32_negprecvtf16lo_add_f16lo: ; GISEL-GFX900: ; %bb.0: ; GISEL-GFX900-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) @@ -3546,12 +3528,6 @@ define float @v_mad_mix_f32_negprecvtf16lo_add_f16lo(i32 %src0.arg, half %src1) ; GISEL-GFX900-NEXT: v_add_f32_e32 v0, v0, v1 ; GISEL-GFX900-NEXT: s_setpc_b64 s[30:31] ; -; GISEL-GFX906-LABEL: v_mad_mix_f32_negprecvtf16lo_add_f16lo: -; GISEL-GFX906: ; %bb.0: -; GISEL-GFX906-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GISEL-GFX906-NEXT: v_fma_mix_f32 v0, -v0, 1.0, v1 op_sel_hi:[1,1,1] -; GISEL-GFX906-NEXT: s_setpc_b64 s[30:31] -; ; GISEL-GFX9GEN-LABEL: v_mad_mix_f32_negprecvtf16lo_add_f16lo: ; GISEL-GFX9GEN: ; %bb.0: ; GISEL-GFX9GEN-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) @@ -3638,11 +3614,11 @@ define float @v_mad_mix_f32_absprecvtf16lo_add_f16lo(i32 %src0.arg, half %src1) } define float @v_mad_mix_f32_negabsprecvtf16lo_add_f16lo(i32 %src0.arg, half %src1) { -; SDAG-GFX1100-LABEL: v_mad_mix_f32_negabsprecvtf16lo_add_f16lo: -; SDAG-GFX1100: ; %bb.0: -; SDAG-GFX1100-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; SDAG-GFX1100-NEXT: v_fma_mix_f32 v0, |v0|, -1.0, v1 op_sel_hi:[1,1,1] -; SDAG-GFX1100-NEXT: s_setpc_b64 s[30:31] +; GFX1100-LABEL: v_mad_mix_f32_negabsprecvtf16lo_add_f16lo: +; GFX1100: ; %bb.0: +; GFX1100-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) +; GFX1100-NEXT: v_fma_mix_f32 v0, -|v0|, 1.0, v1 op_sel_hi:[1,1,1] +; GFX1100-NEXT: s_setpc_b64 s[30:31] ; ; SDAG-GFX900-LABEL: v_mad_mix_f32_negabsprecvtf16lo_add_f16lo: ; SDAG-GFX900: ; %bb.0: @@ -3652,11 +3628,11 @@ define float @v_mad_mix_f32_negabsprecvtf16lo_add_f16lo(i32 %src0.arg, half %src ; SDAG-GFX900-NEXT: v_sub_f32_e32 v0, v1, v0 ; SDAG-GFX900-NEXT: s_setpc_b64 s[30:31] ; -; SDAG-GFX906-LABEL: v_mad_mix_f32_negabsprecvtf16lo_add_f16lo: -; SDAG-GFX906: ; %bb.0: -; SDAG-GFX906-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; SDAG-GFX906-NEXT: v_fma_mix_f32 v0, |v0|, -1.0, v1 op_sel_hi:[1,1,1] -; SDAG-GFX906-NEXT: s_setpc_b64 s[30:31] +; GFX906-LABEL: v_mad_mix_f32_negabsprecvtf16lo_add_f16lo: +; GFX906: ; %bb.0: +; GFX906-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) +; GFX906-NEXT: v_fma_mix_f32 v0, -|v0|, 1.0, v1 op_sel_hi:[1,1,1] +; GFX906-NEXT: s_setpc_b64 s[30:31] ; ; SDAG-GFX9GEN-LABEL: v_mad_mix_f32_negabsprecvtf16lo_add_f16lo: ; SDAG-GFX9GEN: ; %bb.0: @@ -3682,12 +3658,6 @@ define float @v_mad_mix_f32_negabsprecvtf16lo_add_f16lo(i32 %src0.arg, half %src ; SDAG-CI-NEXT: v_sub_f32_e32 v0, v1, v0 ; SDAG-CI-NEXT: s_setpc_b64 s[30:31] ; -; GISEL-GFX1100-LABEL: v_mad_mix_f32_negabsprecvtf16lo_add_f16lo: -; GISEL-GFX1100: ; %bb.0: -; GISEL-GFX1100-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GISEL-GFX1100-NEXT: v_fma_mix_f32 v0, -|v0|, 1.0, v1 op_sel_hi:[1,1,1] -; GISEL-GFX1100-NEXT: s_setpc_b64 s[30:31] -; ; GISEL-GFX900-LABEL: v_mad_mix_f32_negabsprecvtf16lo_add_f16lo: ; GISEL-GFX900: ; %bb.0: ; GISEL-GFX900-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) @@ -3696,12 +3666,6 @@ define float @v_mad_mix_f32_negabsprecvtf16lo_add_f16lo(i32 %src0.arg, half %src ; GISEL-GFX900-NEXT: v_add_f32_e32 v0, v0, v1 ; GISEL-GFX900-NEXT: s_setpc_b64 s[30:31] ; -; GISEL-GFX906-LABEL: v_mad_mix_f32_negabsprecvtf16lo_add_f16lo: -; GISEL-GFX906: ; %bb.0: -; GISEL-GFX906-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GISEL-GFX906-NEXT: v_fma_mix_f32 v0, -|v0|, 1.0, v1 op_sel_hi:[1,1,1] -; GISEL-GFX906-NEXT: s_setpc_b64 s[30:31] -; ; GISEL-GFX9GEN-LABEL: v_mad_mix_f32_negabsprecvtf16lo_add_f16lo: ; GISEL-GFX9GEN: ; %bb.0: ; GISEL-GFX9GEN-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) @@ -3877,11 +3841,11 @@ define float @v_mad_mix_f32_precvtabsf16hi_add_f16lo(i32 %src0.arg, half %src1) } define float @v_mad_mix_f32_preextractfneg_f16hi_add_f16lo(i32 %src0.arg, half %src1) { -; SDAG-GFX1100-LABEL: v_mad_mix_f32_preextractfneg_f16hi_add_f16lo: -; SDAG-GFX1100: ; %bb.0: -; SDAG-GFX1100-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; SDAG-GFX1100-NEXT: v_fma_mix_f32 v0, v0, -1.0, v1 op_sel:[1,0,0] op_sel_hi:[1,1,1] -; SDAG-GFX1100-NEXT: s_setpc_b64 s[30:31] +; GFX1100-LABEL: v_mad_mix_f32_preextractfneg_f16hi_add_f16lo: +; GFX1100: ; %bb.0: +; GFX1100-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) +; GFX1100-NEXT: v_fma_mix_f32 v0, -v0, 1.0, v1 op_sel:[1,0,0] op_sel_hi:[1,1,1] +; GFX1100-NEXT: s_setpc_b64 s[30:31] ; ; SDAG-GFX900-LABEL: v_mad_mix_f32_preextractfneg_f16hi_add_f16lo: ; SDAG-GFX900: ; %bb.0: @@ -3891,11 +3855,11 @@ define float @v_mad_mix_f32_preextractfneg_f16hi_add_f16lo(i32 %src0.arg, half % ; SDAG-GFX900-NEXT: v_sub_f32_e32 v0, v1, v0 ; SDAG-GFX900-NEXT: s_setpc_b64 s[30:31] ; -; SDAG-GFX906-LABEL: v_mad_mix_f32_preextractfneg_f16hi_add_f16lo: -; SDAG-GFX906: ; %bb.0: -; SDAG-GFX906-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; SDAG-GFX906-NEXT: v_fma_mix_f32 v0, v0, -1.0, v1 op_sel:[1,0,0] op_sel_hi:[1,1,1] -; SDAG-GFX906-NEXT: s_setpc_b64 s[30:31] +; GFX906-LABEL: v_mad_mix_f32_preextractfneg_f16hi_add_f16lo: +; GFX906: ; %bb.0: +; GFX906-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) +; GFX906-NEXT: v_fma_mix_f32 v0, -v0, 1.0, v1 op_sel:[1,0,0] op_sel_hi:[1,1,1] +; GFX906-NEXT: s_setpc_b64 s[30:31] ; ; SDAG-GFX9GEN-LABEL: v_mad_mix_f32_preextractfneg_f16hi_add_f16lo: ; SDAG-GFX9GEN: ; %bb.0: @@ -3922,12 +3886,6 @@ define float @v_mad_mix_f32_preextractfneg_f16hi_add_f16lo(i32 %src0.arg, half % ; SDAG-CI-NEXT: v_add_f32_e32 v0, v0, v1 ; SDAG-CI-NEXT: s_setpc_b64 s[30:31] ; -; GISEL-GFX1100-LABEL: v_mad_mix_f32_preextractfneg_f16hi_add_f16lo: -; GISEL-GFX1100: ; %bb.0: -; GISEL-GFX1100-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GISEL-GFX1100-NEXT: v_fma_mix_f32 v0, -v0, 1.0, v1 op_sel:[1,0,0] op_sel_hi:[1,1,1] -; GISEL-GFX1100-NEXT: s_setpc_b64 s[30:31] -; ; GISEL-GFX900-LABEL: v_mad_mix_f32_preextractfneg_f16hi_add_f16lo: ; GISEL-GFX900: ; %bb.0: ; GISEL-GFX900-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) @@ -3937,12 +3895,6 @@ define float @v_mad_mix_f32_preextractfneg_f16hi_add_f16lo(i32 %src0.arg, half % ; GISEL-GFX900-NEXT: v_add_f32_e32 v0, v0, v1 ; GISEL-GFX900-NEXT: s_setpc_b64 s[30:31] ; -; GISEL-GFX906-LABEL: v_mad_mix_f32_preextractfneg_f16hi_add_f16lo: -; GISEL-GFX906: ; %bb.0: -; GISEL-GFX906-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GISEL-GFX906-NEXT: v_fma_mix_f32 v0, -v0, 1.0, v1 op_sel:[1,0,0] op_sel_hi:[1,1,1] -; GISEL-GFX906-NEXT: s_setpc_b64 s[30:31] -; ; GISEL-GFX9GEN-LABEL: v_mad_mix_f32_preextractfneg_f16hi_add_f16lo: ; GISEL-GFX9GEN: ; %bb.0: ; GISEL-GFX9GEN-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) @@ -4071,11 +4023,11 @@ define float @v_mad_mix_f32_preextractfabs_f16hi_add_f16lo(i32 %src0.arg, half % } define float @v_mad_mix_f32_preextractfabsfneg_f16hi_add_f16lo(i32 %src0.arg, half %src1) { -; SDAG-GFX1100-LABEL: v_mad_mix_f32_preextractfabsfneg_f16hi_add_f16lo: -; SDAG-GFX1100: ; %bb.0: -; SDAG-GFX1100-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; SDAG-GFX1100-NEXT: v_fma_mix_f32 v0, |v0|, -1.0, v1 op_sel:[1,0,0] op_sel_hi:[1,1,1] -; SDAG-GFX1100-NEXT: s_setpc_b64 s[30:31] +; GFX1100-LABEL: v_mad_mix_f32_preextractfabsfneg_f16hi_add_f16lo: +; GFX1100: ; %bb.0: +; GFX1100-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) +; GFX1100-NEXT: v_fma_mix_f32 v0, -|v0|, 1.0, v1 op_sel:[1,0,0] op_sel_hi:[1,1,1] +; GFX1100-NEXT: s_setpc_b64 s[30:31] ; ; SDAG-GFX900-LABEL: v_mad_mix_f32_preextractfabsfneg_f16hi_add_f16lo: ; SDAG-GFX900: ; %bb.0: @@ -4085,11 +4037,11 @@ define float @v_mad_mix_f32_preextractfabsfneg_f16hi_add_f16lo(i32 %src0.arg, ha ; SDAG-GFX900-NEXT: v_sub_f32_e32 v0, v1, v0 ; SDAG-GFX900-NEXT: s_setpc_b64 s[30:31] ; -; SDAG-GFX906-LABEL: v_mad_mix_f32_preextractfabsfneg_f16hi_add_f16lo: -; SDAG-GFX906: ; %bb.0: -; SDAG-GFX906-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; SDAG-GFX906-NEXT: v_fma_mix_f32 v0, |v0|, -1.0, v1 op_sel:[1,0,0] op_sel_hi:[1,1,1] -; SDAG-GFX906-NEXT: s_setpc_b64 s[30:31] +; GFX906-LABEL: v_mad_mix_f32_preextractfabsfneg_f16hi_add_f16lo: +; GFX906: ; %bb.0: +; GFX906-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) +; GFX906-NEXT: v_fma_mix_f32 v0, -|v0|, 1.0, v1 op_sel:[1,0,0] op_sel_hi:[1,1,1] +; GFX906-NEXT: s_setpc_b64 s[30:31] ; ; SDAG-GFX9GEN-LABEL: v_mad_mix_f32_preextractfabsfneg_f16hi_add_f16lo: ; SDAG-GFX9GEN: ; %bb.0: @@ -4116,12 +4068,6 @@ define float @v_mad_mix_f32_preextractfabsfneg_f16hi_add_f16lo(i32 %src0.arg, ha ; SDAG-CI-NEXT: v_add_f32_e32 v0, v0, v1 ; SDAG-CI-NEXT: s_setpc_b64 s[30:31] ; -; GISEL-GFX1100-LABEL: v_mad_mix_f32_preextractfabsfneg_f16hi_add_f16lo: -; GISEL-GFX1100: ; %bb.0: -; GISEL-GFX1100-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GISEL-GFX1100-NEXT: v_fma_mix_f32 v0, -|v0|, 1.0, v1 op_sel:[1,0,0] op_sel_hi:[1,1,1] -; GISEL-GFX1100-NEXT: s_setpc_b64 s[30:31] -; ; GISEL-GFX900-LABEL: v_mad_mix_f32_preextractfabsfneg_f16hi_add_f16lo: ; GISEL-GFX900: ; %bb.0: ; GISEL-GFX900-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) @@ -4131,12 +4077,6 @@ define float @v_mad_mix_f32_preextractfabsfneg_f16hi_add_f16lo(i32 %src0.arg, ha ; GISEL-GFX900-NEXT: v_add_f32_e32 v0, v0, v1 ; GISEL-GFX900-NEXT: s_setpc_b64 s[30:31] ; -; GISEL-GFX906-LABEL: v_mad_mix_f32_preextractfabsfneg_f16hi_add_f16lo: -; GISEL-GFX906: ; %bb.0: -; GISEL-GFX906-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GISEL-GFX906-NEXT: v_fma_mix_f32 v0, -|v0|, 1.0, v1 op_sel:[1,0,0] op_sel_hi:[1,1,1] -; GISEL-GFX906-NEXT: s_setpc_b64 s[30:31] -; ; GISEL-GFX9GEN-LABEL: v_mad_mix_f32_preextractfabsfneg_f16hi_add_f16lo: ; GISEL-GFX9GEN: ; %bb.0: ; GISEL-GFX9GEN-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) @@ -5658,7 +5598,7 @@ define float @v_mad_mix_f32_f16lo_sub_f16lo(half %src0, half %src1) { ; GFX1100-LABEL: v_mad_mix_f32_f16lo_sub_f16lo: ; GFX1100: ; %bb.0: ; GFX1100-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GFX1100-NEXT: v_fma_mix_f32 v0, v1, -1.0, v0 op_sel_hi:[1,1,1] +; GFX1100-NEXT: v_fma_mix_f32 v0, -v1, 1.0, v0 op_sel_hi:[1,1,1] ; GFX1100-NEXT: s_setpc_b64 s[30:31] ; ; GFX900-LABEL: v_mad_mix_f32_f16lo_sub_f16lo: @@ -5672,7 +5612,7 @@ define float @v_mad_mix_f32_f16lo_sub_f16lo(half %src0, half %src1) { ; GFX906-LABEL: v_mad_mix_f32_f16lo_sub_f16lo: ; GFX906: ; %bb.0: ; GFX906-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GFX906-NEXT: v_fma_mix_f32 v0, v1, -1.0, v0 op_sel_hi:[1,1,1] +; GFX906-NEXT: v_fma_mix_f32 v0, -v1, 1.0, v0 op_sel_hi:[1,1,1] ; GFX906-NEXT: s_setpc_b64 s[30:31] ; ; GFX9GEN-LABEL: v_mad_mix_f32_f16lo_sub_f16lo: @@ -5708,7 +5648,7 @@ define float @v_mad_mix_f32_absf16lo_sub_f16lo(half %src0, half %src1) { ; GFX1100-LABEL: v_mad_mix_f32_absf16lo_sub_f16lo: ; GFX1100: ; %bb.0: ; GFX1100-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GFX1100-NEXT: v_fma_mix_f32 v0, v1, -1.0, |v0| op_sel_hi:[1,1,1] +; GFX1100-NEXT: v_fma_mix_f32 v0, -v1, 1.0, |v0| op_sel_hi:[1,1,1] ; GFX1100-NEXT: s_setpc_b64 s[30:31] ; ; GFX900-LABEL: v_mad_mix_f32_absf16lo_sub_f16lo: @@ -5722,7 +5662,7 @@ define float @v_mad_mix_f32_absf16lo_sub_f16lo(half %src0, half %src1) { ; GFX906-LABEL: v_mad_mix_f32_absf16lo_sub_f16lo: ; GFX906: ; %bb.0: ; GFX906-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GFX906-NEXT: v_fma_mix_f32 v0, v1, -1.0, |v0| op_sel_hi:[1,1,1] +; GFX906-NEXT: v_fma_mix_f32 v0, -v1, 1.0, |v0| op_sel_hi:[1,1,1] ; GFX906-NEXT: s_setpc_b64 s[30:31] ; ; GFX9GEN-LABEL: v_mad_mix_f32_absf16lo_sub_f16lo: @@ -5767,7 +5707,7 @@ define float @v_mad_mix_f32_f16hi_fsub_f16hi(i32 %src0, i32 %src1) { ; GFX1100-LABEL: v_mad_mix_f32_f16hi_fsub_f16hi: ; GFX1100: ; %bb.0: ; GFX1100-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GFX1100-NEXT: v_fma_mix_f32 v0, v1, -1.0, v0 op_sel:[1,0,1] op_sel_hi:[1,1,1] +; GFX1100-NEXT: v_fma_mix_f32 v0, -v1, 1.0, v0 op_sel:[1,0,1] op_sel_hi:[1,1,1] ; GFX1100-NEXT: s_setpc_b64 s[30:31] ; ; GFX900-LABEL: v_mad_mix_f32_f16hi_fsub_f16hi: @@ -5781,7 +5721,7 @@ define float @v_mad_mix_f32_f16hi_fsub_f16hi(i32 %src0, i32 %src1) { ; GFX906-LABEL: v_mad_mix_f32_f16hi_fsub_f16hi: ; GFX906: ; %bb.0: ; GFX906-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GFX906-NEXT: v_fma_mix_f32 v0, v1, -1.0, v0 op_sel:[1,0,1] op_sel_hi:[1,1,1] +; GFX906-NEXT: v_fma_mix_f32 v0, -v1, 1.0, v0 op_sel:[1,0,1] op_sel_hi:[1,1,1] ; GFX906-NEXT: s_setpc_b64 s[30:31] ; ; GFX9GEN-LABEL: v_mad_mix_f32_f16hi_fsub_f16hi: @@ -5825,7 +5765,7 @@ define float @v_mad_mix_f32_absf16hi_fsub_f16hi(i32 %src0, i32 %src1) { ; GFX1100-LABEL: v_mad_mix_f32_absf16hi_fsub_f16hi: ; GFX1100: ; %bb.0: ; GFX1100-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GFX1100-NEXT: v_fma_mix_f32 v0, v1, -1.0, |v0| op_sel:[1,0,1] op_sel_hi:[1,1,1] +; GFX1100-NEXT: v_fma_mix_f32 v0, -v1, 1.0, |v0| op_sel:[1,0,1] op_sel_hi:[1,1,1] ; GFX1100-NEXT: s_setpc_b64 s[30:31] ; ; GFX900-LABEL: v_mad_mix_f32_absf16hi_fsub_f16hi: @@ -5839,7 +5779,7 @@ define float @v_mad_mix_f32_absf16hi_fsub_f16hi(i32 %src0, i32 %src1) { ; GFX906-LABEL: v_mad_mix_f32_absf16hi_fsub_f16hi: ; GFX906: ; %bb.0: ; GFX906-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GFX906-NEXT: v_fma_mix_f32 v0, v1, -1.0, |v0| op_sel:[1,0,1] op_sel_hi:[1,1,1] +; GFX906-NEXT: v_fma_mix_f32 v0, -v1, 1.0, |v0| op_sel:[1,0,1] op_sel_hi:[1,1,1] ; GFX906-NEXT: s_setpc_b64 s[30:31] ; ; GFX9GEN-LABEL: v_mad_mix_f32_absf16hi_fsub_f16hi: @@ -5890,6 +5830,59 @@ define float @v_mad_mix_f32_absf16hi_fsub_f16hi(i32 %src0, i32 %src1) { ret float %result } +; Same as above but with the fsub marked nnan, which should fold identically +; since the rewrite negates via the free src1 neg_lo modifier rather than an +; actual multiply by -1.0, so it is sound for NaN inputs too. +define float @v_mad_mix_f32_f16lo_sub_f16lo_nnan(half %src0, half %src1) { +; GFX1100-LABEL: v_mad_mix_f32_f16lo_sub_f16lo_nnan: +; GFX1100: ; %bb.0: +; GFX1100-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) +; GFX1100-NEXT: v_fma_mix_f32 v0, -v1, 1.0, v0 op_sel_hi:[1,1,1] +; GFX1100-NEXT: s_setpc_b64 s[30:31] +; +; GFX900-LABEL: v_mad_mix_f32_f16lo_sub_f16lo_nnan: +; GFX900: ; %bb.0: +; GFX900-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) +; GFX900-NEXT: v_cvt_f32_f16_e32 v0, v0 +; GFX900-NEXT: v_cvt_f32_f16_e32 v1, v1 +; GFX900-NEXT: v_sub_f32_e32 v0, v0, v1 +; GFX900-NEXT: s_setpc_b64 s[30:31] +; +; GFX906-LABEL: v_mad_mix_f32_f16lo_sub_f16lo_nnan: +; GFX906: ; %bb.0: +; GFX906-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) +; GFX906-NEXT: v_fma_mix_f32 v0, -v1, 1.0, v0 op_sel_hi:[1,1,1] +; GFX906-NEXT: s_setpc_b64 s[30:31] +; +; GFX9GEN-LABEL: v_mad_mix_f32_f16lo_sub_f16lo_nnan: +; GFX9GEN: ; %bb.0: +; GFX9GEN-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) +; GFX9GEN-NEXT: v_cvt_f32_f16_e32 v0, v0 +; GFX9GEN-NEXT: v_cvt_f32_f16_e32 v1, v1 +; GFX9GEN-NEXT: v_sub_f32_e32 v0, v0, v1 +; GFX9GEN-NEXT: s_setpc_b64 s[30:31] +; +; VI-LABEL: v_mad_mix_f32_f16lo_sub_f16lo_nnan: +; VI: ; %bb.0: +; VI-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) +; VI-NEXT: v_cvt_f32_f16_e32 v0, v0 +; VI-NEXT: v_cvt_f32_f16_e32 v1, v1 +; VI-NEXT: v_sub_f32_e32 v0, v0, v1 +; VI-NEXT: s_setpc_b64 s[30:31] +; +; CI-LABEL: v_mad_mix_f32_f16lo_sub_f16lo_nnan: +; CI: ; %bb.0: +; CI-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) +; CI-NEXT: v_cvt_f32_f16_e32 v0, v0 +; CI-NEXT: v_cvt_f32_f16_e32 v1, v1 +; CI-NEXT: v_sub_f32_e32 v0, v0, v1 +; CI-NEXT: s_setpc_b64 s[30:31] + %src0.ext = fpext half %src0 to float + %src1.ext = fpext half %src1 to float + %result = fsub nnan float %src0.ext, %src1.ext + ret float %result +} + declare half @llvm.fabs.f16(half) #2 declare <2 x half> @llvm.fabs.v2f16(<2 x half>) #2 declare float @llvm.fabs.f32(float) #2 From 0376ce364eceee81b2e4885f23837846aeaedf69 Mon Sep 17 00:00:00 2001 From: Tomer Shafir Date: Thu, 6 Aug 2026 23:42:46 +0300 Subject: [PATCH 008/789] [AArch64] Improve AES clustering tests(NFC) (#213950) - post-RA: rename test cases, reorder them, add artificially interfering instruction in between pairs, add negative runlines - add pre-RA test - add missing label boundaries checks --- .../AArch64/misched-fusion-aes-post-ra.mir | 94 ++++++++++--------- .../AArch64/misched-fusion-aes-pre-ra.mir | 89 ++++++++++++++++++ 2 files changed, 141 insertions(+), 42 deletions(-) create mode 100644 llvm/test/CodeGen/AArch64/misched-fusion-aes-pre-ra.mir diff --git a/llvm/test/CodeGen/AArch64/misched-fusion-aes-post-ra.mir b/llvm/test/CodeGen/AArch64/misched-fusion-aes-post-ra.mir index 7b7e498474f3e..447165dbe5595 100644 --- a/llvm/test/CodeGen/AArch64/misched-fusion-aes-post-ra.mir +++ b/llvm/test/CodeGen/AArch64/misched-fusion-aes-post-ra.mir @@ -1,73 +1,83 @@ # REQUIRES: asserts -# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mattr=+fuse-aes,+crypto -misched-print-dags 2>&1 | FileCheck %s -# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=generic -mattr=+crypto -misched-print-dags 2>&1 | FileCheck %s -# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=cortex-a53 -misched-print-dags 2>&1 | FileCheck %s -# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=cortex-a57 -misched-print-dags 2>&1 | FileCheck %s -# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=cortex-a65 -misched-print-dags 2>&1 | FileCheck %s -# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=cortex-a72 -misched-print-dags 2>&1 | FileCheck %s -# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=cortex-a73 -misched-print-dags 2>&1 | FileCheck %s -# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=cortex-a76 -misched-print-dags 2>&1 | FileCheck %s -# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=cortex-a77 -misched-print-dags 2>&1 | FileCheck %s -# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=cortex-a78 -misched-print-dags 2>&1 | FileCheck %s -# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=cortex-a78c -misched-print-dags 2>&1 | FileCheck %s -# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=cortex-x1 -misched-print-dags 2>&1 | FileCheck %s -# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=neoverse-e1 -misched-print-dags 2>&1 | FileCheck %s -# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=neoverse-n1 -misched-print-dags 2>&1 | FileCheck %s -# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=neoverse-v1 -misched-print-dags 2>&1 | FileCheck %s -# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=neoverse-512tvb -misched-print-dags 2>&1 | FileCheck %s -# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=exynos-m3 -misched-print-dags 2>&1 | FileCheck %s -# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=exynos-m4 -misched-print-dags 2>&1 | FileCheck %s -# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=exynos-m5 -misched-print-dags 2>&1 | FileCheck %s -# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=ampere1 -misched-print-dags 2>&1 | FileCheck %s -# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=ampere1a -misched-print-dags 2>&1 | FileCheck %s -# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=ampere1b -misched-print-dags 2>&1 | FileCheck %s -# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=apple-m5 -misched-print-dags 2>&1 | FileCheck %s +# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mattr=+fuse-aes,+crypto -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=generic -mattr=+crypto -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=cortex-a53 -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=cortex-a57 -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=cortex-a65 -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=cortex-a72 -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=cortex-a73 -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=cortex-a76 -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=cortex-a77 -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=cortex-a78 -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=cortex-a78c -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=cortex-x1 -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=neoverse-e1 -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=neoverse-n1 -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=neoverse-v1 -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=neoverse-512tvb -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=exynos-m3 -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=exynos-m4 -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=exynos-m5 -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=ampere1 -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=ampere1a -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=ampere1b -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=apple-m5 -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE -## Verify that only tied AES pairs (both instructions write to the same register) -## are being fused post-RA. +# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mattr=-fuse-aes,+crypto -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,NOFUSE +# RUN: llc -o /dev/null %s -run-pass=machine-scheduler -mtriple aarch64-unknown -mcpu=apple-m5 -mattr=-fuse-aes -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,NOFUSE --- -name: encode_physregs_tied +name: encode_waw body: | bb.0: + ; CHECK-LABEL: encode_waw ; CHECK: SU(0): $q0 = AESErr undef $q0(tied-def 0), undef $q1 ; CHECK: Successors: - ; CHECK: SU(1): Ord Latency=0 Cluster - ; CHECK: SU(1): $q0 = AESMCrr $q0 + ; FUSE: SU(2): Ord Latency=0 Cluster + ; NOFUSE-NOT: SU(2): Ord Latency=0 Cluster + ; CHECK: SU(2): $q0 = AESMCrr $q0 $q0 = AESErr undef $q0, undef $q1 + $q3 = ADDv16i8 undef $q4, undef $q5 $q0 = AESMCrr $q0 ... --- -name: decode_physregs_tied +name: encode_nowaw body: | bb.0: - ; CHECK: SU(0): $q0 = AESDrr undef $q0(tied-def 0), undef $q1 + ; CHECK-LABEL: encode_nowaw + ; CHECK: SU(0): $q0 = AESErr undef $q0(tied-def 0), undef $q1 ; CHECK: Successors: - ; CHECK: SU(1): Ord Latency=0 Cluster - ; CHECK: SU(1): $q0 = AESIMCrr $q0 - $q0 = AESDrr undef $q0, undef $q1 - $q0 = AESIMCrr $q0 + ; CHECK-NOT: SU({{.*}}): Ord Latency=0 Cluster + ; CHECK: SU(2): $q2 = AESMCrr $q0 + $q0 = AESErr undef $q0, undef $q1 + $q3 = ADDv16i8 undef $q4, undef $q5 + $q2 = AESMCrr $q0 ... --- -name: encode_physregs_untied +name: decode_waw body: | bb.0: - ; CHECK: SU(0): $q0 = AESErr undef $q0(tied-def 0), undef $q1 + ; CHECK-LABEL: decode_waw + ; CHECK: SU(0): $q0 = AESDrr undef $q0(tied-def 0), undef $q1 ; CHECK: Successors: - ; CHECK-NOT: SU({{.*}}): Ord Latency=0 Cluster - ; CHECK: SU(1): $q2 = AESMCrr $q0 - $q0 = AESErr undef $q0, undef $q1 - $q2 = AESMCrr $q0 + ; FUSE: SU(2): Ord Latency=0 Cluster + ; NOFUSE-NOT: SU(2): Ord Latency=0 Cluster + ; CHECK: SU(2): $q0 = AESIMCrr $q0 + $q0 = AESDrr undef $q0, undef $q1 + $q3 = ADDv16i8 undef $q4, undef $q5 + $q0 = AESIMCrr $q0 ... --- -name: decode_physregs_untied +name: decode_nowaw body: | bb.0: + ; CHECK-LABEL: decode_nowaw ; CHECK: SU(0): $q0 = AESDrr undef $q0(tied-def 0), undef $q1 ; CHECK: Successors: ; CHECK-NOT: SU({{.*}}): Ord Latency=0 Cluster - ; CHECK: SU(1): $q2 = AESIMCrr $q0 + ; CHECK: SU(2): $q2 = AESIMCrr $q0 $q0 = AESDrr undef $q0, undef $q1 + $q3 = ADDv16i8 undef $q4, undef $q5 $q2 = AESIMCrr $q0 ... \ No newline at end of file diff --git a/llvm/test/CodeGen/AArch64/misched-fusion-aes-pre-ra.mir b/llvm/test/CodeGen/AArch64/misched-fusion-aes-pre-ra.mir new file mode 100644 index 0000000000000..aad4d8ad9adc5 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/misched-fusion-aes-pre-ra.mir @@ -0,0 +1,89 @@ +# REQUIRES: asserts + +# RUN: llc -o /dev/null %s -mtriple=aarch64-unknown -mattr=+fuse-aes,+crypto -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -mtriple=aarch64-unknown -mcpu=generic -mattr=+crypto -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -mtriple=aarch64-unknown -mcpu=cortex-a53 -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -mtriple=aarch64-unknown -mcpu=cortex-a57 -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -mtriple=aarch64-unknown -mcpu=cortex-a65 -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -mtriple=aarch64-unknown -mcpu=cortex-a72 -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -mtriple=aarch64-unknown -mcpu=cortex-a73 -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -mtriple=aarch64-unknown -mcpu=cortex-a76 -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -mtriple=aarch64-unknown -mcpu=cortex-a77 -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -mtriple=aarch64-unknown -mcpu=cortex-a78 -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -mtriple=aarch64-unknown -mcpu=cortex-a78c -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -mtriple=aarch64-unknown -mcpu=cortex-x1 -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -mtriple=aarch64-unknown -mcpu=neoverse-e1 -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -mtriple=aarch64-unknown -mcpu=neoverse-n1 -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -mtriple=aarch64-unknown -mcpu=neoverse-v1 -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -mtriple=aarch64-unknown -mcpu=neoverse-512tvb -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -mtriple=aarch64-unknown -mcpu=exynos-m3 -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -mtriple=aarch64-unknown -mcpu=exynos-m4 -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -mtriple=aarch64-unknown -mcpu=exynos-m5 -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -mtriple=aarch64-unknown -mcpu=ampere1 -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -mtriple=aarch64-unknown -mcpu=ampere1a -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -mtriple=aarch64-unknown -mcpu=ampere1b -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -mtriple=aarch64-unknown -mcpu=apple-m5 -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE + +# RUN: llc -o /dev/null %s -mtriple=aarch64-unknown -mattr=-fuse-aes,+crypto -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,NOFUSE +# RUN: llc -o /dev/null %s -mtriple=aarch64-unknown -mcpu=apple-m5 -mattr=-fuse-aes -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,NOFUSE + +--- +name: encode_tied +tracksRegLiveness: true +body: | + bb.0: + ; CHECK-LABEL: encode_tied + ; CHECK: SU(0): %0:fpr128 = AESErr + ; CHECK: Successors: + ; FUSE: SU(2): Ord Latency=0 Cluster + ; NOFUSE-NOT: SU(2): Ord Latency=0 Cluster + ; CHECK: SU(2): dead %6:fpr128 = AESMCrrTied + %0:fpr128 = AESErr undef %1:fpr128, undef %2:fpr128 + %3:fpr128 = ADDv16i8 undef %4:fpr128, undef %5:fpr128 + %6:fpr128 = AESMCrrTied %0 +... +--- +name: encode_untied +tracksRegLiveness: true +body: | + bb.0: + ; CHECK-LABEL: encode_untied + ; CHECK: SU(0): %0:fpr128 = AESErr + ; CHECK: Successors: + ; FUSE: SU(2): Ord Latency=0 Cluster + ; NOFUSE-NOT: SU(2): Ord Latency=0 Cluster + ; CHECK: SU(2): dead %6:fpr128 = AESMCrr + %0:fpr128 = AESErr undef %1:fpr128, undef %2:fpr128 + %3:fpr128 = ADDv16i8 undef %4:fpr128, undef %5:fpr128 + %6:fpr128 = AESMCrr %0 +... +--- +name: decode_tied +tracksRegLiveness: true +body: | + bb.0: + ; CHECK-LABEL: decode_tied + ; CHECK: SU(0): %0:fpr128 = AESDrr + ; CHECK: Successors: + ; FUSE: SU(2): Ord Latency=0 Cluster + ; NOFUSE-NOT: SU(2): Ord Latency=0 Cluster + ; CHECK: SU(2): dead %6:fpr128 = AESIMCrrTied + %0:fpr128 = AESDrr undef %1:fpr128, undef %2:fpr128 + %3:fpr128 = ADDv16i8 undef %4:fpr128, undef %5:fpr128 + %6:fpr128 = AESIMCrrTied %0 +... +--- +name: decode_untied +tracksRegLiveness: true +body: | + bb.0: + ; CHECK-LABEL: decode_untied + ; CHECK: SU(0): %0:fpr128 = AESDrr + ; CHECK: Successors: + ; FUSE: SU(2): Ord Latency=0 Cluster + ; NOFUSE-NOT: SU(2): Ord Latency=0 Cluster + ; CHECK: SU(2): dead %6:fpr128 = AESIMCrr + %0:fpr128 = AESDrr undef %1:fpr128, undef %2:fpr128 + %3:fpr128 = ADDv16i8 undef %4:fpr128, undef %5:fpr128 + %6:fpr128 = AESIMCrr %0 +... From 7b0121409bbfffe6c470c8b751875d9bc8259c71 Mon Sep 17 00:00:00 2001 From: Tomer Shafir Date: Thu, 6 Aug 2026 23:43:04 +0300 Subject: [PATCH 009/789] [AArch64] Use only virtual registers in pre-RA test(NFC) (#213951) And add missing label boundaries checks. --- .../misched-fusion-fmin-fmax-post-ra.mir | 72 ++++- .../misched-fusion-fmin-fmax-pre-ra.mir | 296 ++++++++++-------- 2 files changed, 232 insertions(+), 136 deletions(-) diff --git a/llvm/test/CodeGen/AArch64/misched-fusion-fmin-fmax-post-ra.mir b/llvm/test/CodeGen/AArch64/misched-fusion-fmin-fmax-post-ra.mir index 9dd770310abea..1a679cd178bdd 100644 --- a/llvm/test/CodeGen/AArch64/misched-fusion-fmin-fmax-post-ra.mir +++ b/llvm/test/CodeGen/AArch64/misched-fusion-fmin-fmax-post-ra.mir @@ -1,10 +1,10 @@ # REQUIRES: asserts -# RUN: llc -o /dev/null %s -mtriple=aarch64-linux-gnu -mattr=+fuse-fmin-fmax -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=FUSE -# RUN: llc -o /dev/null %s -mtriple=arm64-apple-macosx -mcpu=apple-m5 -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=FUSE +# RUN: llc -o /dev/null %s -mtriple=aarch64-linux-gnu -mattr=+fuse-fmin-fmax -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -mtriple=arm64-apple-macosx -mcpu=apple-m5 -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE -# RUN: llc -o /dev/null %s -mtriple=aarch64-linux-gnu -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=NOFUSE -# RUN: llc -o /dev/null %s -mtriple=arm64-apple-macosx -mcpu=apple-m5 -mattr=-fuse-fmin-fmax -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=NOFUSE +# RUN: llc -o /dev/null %s -mtriple=aarch64-linux-gnu -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,NOFUSE +# RUN: llc -o /dev/null %s -mtriple=arm64-apple-macosx -mcpu=apple-m5 -mattr=-fuse-fmin-fmax -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,NOFUSE --- name: fmax_fmax_h_waw @@ -12,6 +12,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $h0, $h1, $h2, $h3, $h4 + ; CHECK-LABEL: fmax_fmax_h_waw ; CHECK: SU(0): $h5 = FMAXHrr ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -27,6 +28,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $h0, $h1, $h2, $h3, $h4 + ; CHECK-LABEL: fmax_fmax_h_nowaw ; CHECK: SU(0): $h5 = FMAXHrr ; CHECK: Successors: ; FUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -42,6 +44,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $h0, $h1, $h2, $h3, $h4 + ; CHECK-LABEL: fmax_fmin_h_waw ; CHECK: SU(0): $h5 = FMAXHrr ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -57,6 +60,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $h0, $h1, $h2, $h3, $h4 + ; CHECK-LABEL: fmax_fmin_h_nowaw ; CHECK: SU(0): $h5 = FMAXHrr ; CHECK: Successors: ; FUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -72,6 +76,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $h0, $h1, $h2, $h3, $h4 + ; CHECK-LABEL: fmin_fmax_h_waw ; CHECK: SU(0): $h5 = FMINHrr ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -87,6 +92,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $h0, $h1, $h2, $h3, $h4 + ; CHECK-LABEL: fmin_fmax_h_nowaw ; CHECK: SU(0): $h5 = FMINHrr ; CHECK: Successors: ; FUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -102,6 +108,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $h0, $h1, $h2, $h3, $h4 + ; CHECK-LABEL: fmin_fmin_h_waw ; CHECK: SU(0): $h5 = FMINHrr ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -117,6 +124,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $h0, $h1, $h2, $h3, $h4 + ; CHECK-LABEL: fmin_fmin_h_nowaw ; CHECK: SU(0): $h5 = FMINHrr ; CHECK: Successors: ; FUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -132,6 +140,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $s0, $s1, $s2, $s3, $s4 + ; CHECK-LABEL: fmax_fmax_s_waw ; CHECK: SU(0): $s5 = FMAXSrr ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -147,6 +156,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $s0, $s1, $s2, $s3, $s4 + ; CHECK-LABEL: fmax_fmax_s_nowaw ; CHECK: SU(0): $s5 = FMAXSrr ; CHECK: Successors: ; FUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -162,6 +172,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $s0, $s1, $s2, $s3, $s4 + ; CHECK-LABEL: fmax_fmin_s_waw ; CHECK: SU(0): $s5 = FMAXSrr ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -177,6 +188,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $s0, $s1, $s2, $s3, $s4 + ; CHECK-LABEL: fmax_fmin_s_nowaw ; CHECK: SU(0): $s5 = FMAXSrr ; CHECK: Successors: ; FUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -192,6 +204,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $s0, $s1, $s2, $s3, $s4 + ; CHECK-LABEL: fmin_fmax_s_waw ; CHECK: SU(0): $s5 = FMINSrr ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -207,6 +220,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $s0, $s1, $s2, $s3, $s4 + ; CHECK-LABEL: fmin_fmax_s_nowaw ; CHECK: SU(0): $s5 = FMINSrr ; CHECK: Successors: ; FUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -222,6 +236,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $s0, $s1, $s2, $s3, $s4 + ; CHECK-LABEL: fmin_fmin_s_waw ; CHECK: SU(0): $s5 = FMINSrr ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -237,6 +252,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $s0, $s1, $s2, $s3, $s4 + ; CHECK-LABEL: fmin_fmin_s_nowaw ; CHECK: SU(0): $s5 = FMINSrr ; CHECK: Successors: ; FUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -252,6 +268,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $d0, $d1, $d2, $d3, $d4 + ; CHECK-LABEL: fmax_fmax_d_waw ; CHECK: SU(0): $d5 = FMAXDrr ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -267,6 +284,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $d0, $d1, $d2, $d3, $d4 + ; CHECK-LABEL: fmax_fmax_d_nowaw ; CHECK: SU(0): $d5 = FMAXDrr ; CHECK: Successors: ; FUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -282,6 +300,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $d0, $d1, $d2, $d3, $d4 + ; CHECK-LABEL: fmax_fmin_d_waw ; CHECK: SU(0): $d5 = FMAXDrr ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -297,6 +316,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $d0, $d1, $d2, $d3, $d4 + ; CHECK-LABEL: fmax_fmin_d_nowaw ; CHECK: SU(0): $d5 = FMAXDrr ; CHECK: Successors: ; FUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -312,6 +332,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $d0, $d1, $d2, $d3, $d4 + ; CHECK-LABEL: fmin_fmax_d_waw ; CHECK: SU(0): $d5 = FMINDrr ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -327,6 +348,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $d0, $d1, $d2, $d3, $d4 + ; CHECK-LABEL: fmin_fmax_d_nowaw ; CHECK: SU(0): $d5 = FMINDrr ; CHECK: Successors: ; FUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -342,6 +364,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $d0, $d1, $d2, $d3, $d4 + ; CHECK-LABEL: fmin_fmin_d_waw ; CHECK: SU(0): $d5 = FMINDrr ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -357,6 +380,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $d0, $d1, $d2, $d3, $d4 + ; CHECK-LABEL: fmin_fmin_d_nowaw ; CHECK: SU(0): $d5 = FMINDrr ; CHECK: Successors: ; FUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -372,6 +396,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $d0, $d1, $d2, $d3, $d4 + ; CHECK-LABEL: fmax_fmax_v4f16_waw ; CHECK: SU(0): $d5 = FMAXv4f16 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -387,6 +412,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $d0, $d1, $d2, $d3, $d4 + ; CHECK-LABEL: fmax_fmax_v4f16_nowaw ; CHECK: SU(0): $d5 = FMAXv4f16 ; CHECK: Successors: ; FUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -402,6 +428,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $d0, $d1, $d2, $d3, $d4 + ; CHECK-LABEL: fmax_fmin_v4f16_waw ; CHECK: SU(0): $d5 = FMAXv4f16 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -417,6 +444,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $d0, $d1, $d2, $d3, $d4 + ; CHECK-LABEL: fmax_fmin_v4f16_nowaw ; CHECK: SU(0): $d5 = FMAXv4f16 ; CHECK: Successors: ; FUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -432,6 +460,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $d0, $d1, $d2, $d3, $d4 + ; CHECK-LABEL: fmin_fmax_v4f16_waw ; CHECK: SU(0): $d5 = FMINv4f16 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -447,6 +476,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $d0, $d1, $d2, $d3, $d4 + ; CHECK-LABEL: fmin_fmax_v4f16_nowaw ; CHECK: SU(0): $d5 = FMINv4f16 ; CHECK: Successors: ; FUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -462,6 +492,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $d0, $d1, $d2, $d3, $d4 + ; CHECK-LABEL: fmin_fmin_v4f16_waw ; CHECK: SU(0): $d5 = FMINv4f16 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -477,6 +508,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $d0, $d1, $d2, $d3, $d4 + ; CHECK-LABEL: fmin_fmin_v4f16_nowaw ; CHECK: SU(0): $d5 = FMINv4f16 ; CHECK: Successors: ; FUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -492,6 +524,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $q0, $q1, $q2, $q3, $q4 + ; CHECK-LABEL: fmax_fmax_v8f16_waw ; CHECK: SU(0): $q5 = FMAXv8f16 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -507,6 +540,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $q0, $q1, $q2, $q3, $q4 + ; CHECK-LABEL: fmax_fmax_v8f16_nowaw ; CHECK: SU(0): $q5 = FMAXv8f16 ; CHECK: Successors: ; FUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -522,6 +556,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $q0, $q1, $q2, $q3, $q4 + ; CHECK-LABEL: fmax_fmin_v8f16_waw ; CHECK: SU(0): $q5 = FMAXv8f16 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -537,6 +572,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $q0, $q1, $q2, $q3, $q4 + ; CHECK-LABEL: fmax_fmin_v8f16_nowaw ; CHECK: SU(0): $q5 = FMAXv8f16 ; CHECK: Successors: ; FUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -552,6 +588,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $q0, $q1, $q2, $q3, $q4 + ; CHECK-LABEL: fmin_fmax_v8f16_waw ; CHECK: SU(0): $q5 = FMINv8f16 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -567,6 +604,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $q0, $q1, $q2, $q3, $q4 + ; CHECK-LABEL: fmin_fmax_v8f16_nowaw ; CHECK: SU(0): $q5 = FMINv8f16 ; CHECK: Successors: ; FUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -582,6 +620,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $q0, $q1, $q2, $q3, $q4 + ; CHECK-LABEL: fmin_fmin_v8f16_waw ; CHECK: SU(0): $q5 = FMINv8f16 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -597,6 +636,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $q0, $q1, $q2, $q3, $q4 + ; CHECK-LABEL: fmin_fmin_v8f16_nowaw ; CHECK: SU(0): $q5 = FMINv8f16 ; CHECK: Successors: ; FUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -612,6 +652,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $d0, $d1, $d2, $d3, $d4 + ; CHECK-LABEL: fmax_fmax_v2f32_waw ; CHECK: SU(0): $d5 = FMAXv2f32 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -627,6 +668,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $d0, $d1, $d2, $d3, $d4 + ; CHECK-LABEL: fmax_fmax_v2f32_nowaw ; CHECK: SU(0): $d5 = FMAXv2f32 ; CHECK: Successors: ; FUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -642,6 +684,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $d0, $d1, $d2, $d3, $d4 + ; CHECK-LABEL: fmax_fmin_v2f32_waw ; CHECK: SU(0): $d5 = FMAXv2f32 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -657,6 +700,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $d0, $d1, $d2, $d3, $d4 + ; CHECK-LABEL: fmax_fmin_v2f32_nowaw ; CHECK: SU(0): $d5 = FMAXv2f32 ; CHECK: Successors: ; FUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -672,6 +716,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $d0, $d1, $d2, $d3, $d4 + ; CHECK-LABEL: fmin_fmax_v2f32_waw ; CHECK: SU(0): $d5 = FMINv2f32 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -687,6 +732,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $d0, $d1, $d2, $d3, $d4 + ; CHECK-LABEL: fmin_fmax_v2f32_nowaw ; CHECK: SU(0): $d5 = FMINv2f32 ; CHECK: Successors: ; FUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -702,6 +748,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $d0, $d1, $d2, $d3, $d4 + ; CHECK-LABEL: fmin_fmin_v2f32_waw ; CHECK: SU(0): $d5 = FMINv2f32 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -717,6 +764,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $d0, $d1, $d2, $d3, $d4 + ; CHECK-LABEL: fmin_fmin_v2f32_nowaw ; CHECK: SU(0): $d5 = FMINv2f32 ; CHECK: Successors: ; FUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -732,6 +780,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $q0, $q1, $q2, $q3, $q4 + ; CHECK-LABEL: fmax_fmax_v4f32_waw ; CHECK: SU(0): $q5 = FMAXv4f32 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -747,6 +796,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $q0, $q1, $q2, $q3, $q4 + ; CHECK-LABEL: fmax_fmax_v4f32_nowaw ; CHECK: SU(0): $q5 = FMAXv4f32 ; CHECK: Successors: ; FUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -762,6 +812,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $q0, $q1, $q2, $q3, $q4 + ; CHECK-LABEL: fmax_fmin_v4f32_waw ; CHECK: SU(0): $q5 = FMAXv4f32 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -777,6 +828,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $q0, $q1, $q2, $q3, $q4 + ; CHECK-LABEL: fmax_fmin_v4f32_nowaw ; CHECK: SU(0): $q5 = FMAXv4f32 ; CHECK: Successors: ; FUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -792,6 +844,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $q0, $q1, $q2, $q3, $q4 + ; CHECK-LABEL: fmin_fmax_v4f32_waw ; CHECK: SU(0): $q5 = FMINv4f32 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -807,6 +860,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $q0, $q1, $q2, $q3, $q4 + ; CHECK-LABEL: fmin_fmax_v4f32_nowaw ; CHECK: SU(0): $q5 = FMINv4f32 ; CHECK: Successors: ; FUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -822,6 +876,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $q0, $q1, $q2, $q3, $q4 + ; CHECK-LABEL: fmin_fmin_v4f32_waw ; CHECK: SU(0): $q5 = FMINv4f32 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -837,6 +892,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $q0, $q1, $q2, $q3, $q4 + ; CHECK-LABEL: fmin_fmin_v4f32_nowaw ; CHECK: SU(0): $q5 = FMINv4f32 ; CHECK: Successors: ; FUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -852,6 +908,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $q0, $q1, $q2, $q3, $q4 + ; CHECK-LABEL: fmax_fmax_v2f64_waw ; CHECK: SU(0): $q5 = FMAXv2f64 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -867,6 +924,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $q0, $q1, $q2, $q3, $q4 + ; CHECK-LABEL: fmax_fmax_v2f64_nowaw ; CHECK: SU(0): $q5 = FMAXv2f64 ; CHECK: Successors: ; FUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -882,6 +940,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $q0, $q1, $q2, $q3, $q4 + ; CHECK-LABEL: fmax_fmin_v2f64_waw ; CHECK: SU(0): $q5 = FMAXv2f64 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -897,6 +956,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $q0, $q1, $q2, $q3, $q4 + ; CHECK-LABEL: fmax_fmin_v2f64_nowaw ; CHECK: SU(0): $q5 = FMAXv2f64 ; CHECK: Successors: ; FUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -912,6 +972,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $q0, $q1, $q2, $q3, $q4 + ; CHECK-LABEL: fmin_fmax_v2f64_waw ; CHECK: SU(0): $q5 = FMINv2f64 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -927,6 +988,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $q0, $q1, $q2, $q3, $q4 + ; CHECK-LABEL: fmin_fmax_v2f64_nowaw ; CHECK: SU(0): $q5 = FMINv2f64 ; CHECK: Successors: ; FUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -942,6 +1004,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $q0, $q1, $q2, $q3, $q4 + ; CHECK-LABEL: fmin_fmin_v2f64_waw ; CHECK: SU(0): $q5 = FMINv2f64 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster @@ -957,6 +1020,7 @@ tracksRegLiveness: true body: | bb.0: liveins: $q0, $q1, $q2, $q3, $q4 + ; CHECK-LABEL: fmin_fmin_v2f64_nowaw ; CHECK: SU(0): $q5 = FMINv2f64 ; CHECK: Successors: ; FUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster diff --git a/llvm/test/CodeGen/AArch64/misched-fusion-fmin-fmax-pre-ra.mir b/llvm/test/CodeGen/AArch64/misched-fusion-fmin-fmax-pre-ra.mir index a7e5244352209..21e7b291f0188 100644 --- a/llvm/test/CodeGen/AArch64/misched-fusion-fmin-fmax-pre-ra.mir +++ b/llvm/test/CodeGen/AArch64/misched-fusion-fmin-fmax-pre-ra.mir @@ -1,456 +1,488 @@ # REQUIRES: asserts -# RUN: llc -o /dev/null %s -mtriple=aarch64-linux-gnu -mattr=+fuse-fmin-fmax -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=FUSE -# RUN: llc -o /dev/null %s -mtriple=arm64-apple-macosx -mcpu=apple-m5 -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=FUSE +# RUN: llc -o /dev/null %s -mtriple=aarch64-linux-gnu -mattr=+fuse-fmin-fmax -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE +# RUN: llc -o /dev/null %s -mtriple=arm64-apple-macosx -mcpu=apple-m5 -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,FUSE -# RUN: llc -o /dev/null %s -mtriple=aarch64-linux-gnu -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=NOFUSE -# RUN: llc -o /dev/null %s -mtriple=arm64-apple-macosx -mcpu=apple-m5 -mattr=-fuse-fmin-fmax -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=NOFUSE +# RUN: llc -o /dev/null %s -mtriple=aarch64-linux-gnu -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,NOFUSE +# RUN: llc -o /dev/null %s -mtriple=arm64-apple-macosx -mcpu=apple-m5 -mattr=-fuse-fmin-fmax -passes=machine-scheduler -misched-print-dags -print-before=machine-scheduler 2>&1 | FileCheck %s --check-prefixes=CHECK,NOFUSE --- name: fmax_fmax_h tracksRegLiveness: true body: | bb.0: + ; CHECK-LABEL: fmax_fmax_h ; CHECK: SU(0): %0:fpr16 = FMAXHrr ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster - ; CHECK: SU(2): %2:fpr16 = FMAXHrr - %0:fpr16 = FMAXHrr undef $h0, undef $h1, implicit $fpcr - %1:fpr16 = FADDHrr undef $h3, undef $h4, implicit $fpcr - %2:fpr16 = FMAXHrr %0, undef $h2, implicit $fpcr + ; CHECK: SU(2): dead %6:fpr16 = FMAXHrr + %0:fpr16 = FMAXHrr undef %1:fpr16, undef %2:fpr16, implicit $fpcr + %3:fpr16 = FADDHrr undef %4:fpr16, undef %5:fpr16, implicit $fpcr + %6:fpr16 = FMAXHrr %0, undef %7:fpr16, implicit $fpcr ... --- name: fmax_fmin_h tracksRegLiveness: true body: | bb.0: + ; CHECK-LABEL: fmax_fmin_h ; CHECK: SU(0): %0:fpr16 = FMAXHrr ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster - ; CHECK: SU(2): %2:fpr16 = FMINHrr - %0:fpr16 = FMAXHrr undef $h0, undef $h1, implicit $fpcr - %1:fpr16 = FADDHrr undef $h3, undef $h4, implicit $fpcr - %2:fpr16 = FMINHrr %0, undef $h2, implicit $fpcr + ; CHECK: SU(2): dead %6:fpr16 = FMINHrr + %0:fpr16 = FMAXHrr undef %1:fpr16, undef %2:fpr16, implicit $fpcr + %3:fpr16 = FADDHrr undef %4:fpr16, undef %5:fpr16, implicit $fpcr + %6:fpr16 = FMINHrr %0, undef %7:fpr16, implicit $fpcr ... --- name: fmin_fmax_h tracksRegLiveness: true body: | bb.0: + ; CHECK-LABEL: fmin_fmax_h ; CHECK: SU(0): %0:fpr16 = FMINHrr ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster - ; CHECK: SU(2): %2:fpr16 = FMAXHrr - %0:fpr16 = FMINHrr undef $h0, undef $h1, implicit $fpcr - %1:fpr16 = FADDHrr undef $h3, undef $h4, implicit $fpcr - %2:fpr16 = FMAXHrr %0, undef $h2, implicit $fpcr + ; CHECK: SU(2): dead %6:fpr16 = FMAXHrr + %0:fpr16 = FMINHrr undef %1:fpr16, undef %2:fpr16, implicit $fpcr + %3:fpr16 = FADDHrr undef %4:fpr16, undef %5:fpr16, implicit $fpcr + %6:fpr16 = FMAXHrr %0, undef %7:fpr16, implicit $fpcr ... --- name: fmin_fmin_h tracksRegLiveness: true body: | bb.0: + ; CHECK-LABEL: fmin_fmin_h ; CHECK: SU(0): %0:fpr16 = FMINHrr ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster - ; CHECK: SU(2): %2:fpr16 = FMINHrr - %0:fpr16 = FMINHrr undef $h0, undef $h1, implicit $fpcr - %1:fpr16 = FADDHrr undef $h3, undef $h4, implicit $fpcr - %2:fpr16 = FMINHrr %0, undef $h2, implicit $fpcr + ; CHECK: SU(2): dead %6:fpr16 = FMINHrr + %0:fpr16 = FMINHrr undef %1:fpr16, undef %2:fpr16, implicit $fpcr + %3:fpr16 = FADDHrr undef %4:fpr16, undef %5:fpr16, implicit $fpcr + %6:fpr16 = FMINHrr %0, undef %7:fpr16, implicit $fpcr ... --- name: fmax_fmax_s tracksRegLiveness: true body: | bb.0: + ; CHECK-LABEL: fmax_fmax_s ; CHECK: SU(0): %0:fpr32 = FMAXSrr ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster - ; CHECK: SU(2): %2:fpr32 = FMAXSrr - %0:fpr32 = FMAXSrr undef $s0, undef $s1, implicit $fpcr - %1:fpr32 = FADDSrr undef $s3, undef $s4, implicit $fpcr - %2:fpr32 = FMAXSrr %0, undef $s2, implicit $fpcr + ; CHECK: SU(2): dead %6:fpr32 = FMAXSrr + %0:fpr32 = FMAXSrr undef %1:fpr32, undef %2:fpr32, implicit $fpcr + %3:fpr32 = FADDSrr undef %4:fpr32, undef %5:fpr32, implicit $fpcr + %6:fpr32 = FMAXSrr %0, undef %7:fpr32, implicit $fpcr ... --- name: fmax_fmin_s tracksRegLiveness: true body: | bb.0: + ; CHECK-LABEL: fmax_fmin_s ; CHECK: SU(0): %0:fpr32 = FMAXSrr ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster - ; CHECK: SU(2): %2:fpr32 = FMINSrr - %0:fpr32 = FMAXSrr undef $s0, undef $s1, implicit $fpcr - %1:fpr32 = FADDSrr undef $s3, undef $s4, implicit $fpcr - %2:fpr32 = FMINSrr %0, undef $s2, implicit $fpcr + ; CHECK: SU(2): dead %6:fpr32 = FMINSrr + %0:fpr32 = FMAXSrr undef %1:fpr32, undef %2:fpr32, implicit $fpcr + %3:fpr32 = FADDSrr undef %4:fpr32, undef %5:fpr32, implicit $fpcr + %6:fpr32 = FMINSrr %0, undef %7:fpr32, implicit $fpcr ... --- name: fmin_fmax_s tracksRegLiveness: true body: | bb.0: + ; CHECK-LABEL: fmin_fmax_s ; CHECK: SU(0): %0:fpr32 = FMINSrr ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster - ; CHECK: SU(2): %2:fpr32 = FMAXSrr - %0:fpr32 = FMINSrr undef $s0, undef $s1, implicit $fpcr - %1:fpr32 = FADDSrr undef $s3, undef $s4, implicit $fpcr - %2:fpr32 = FMAXSrr %0, undef $s2, implicit $fpcr + ; CHECK: SU(2): dead %6:fpr32 = FMAXSrr + %0:fpr32 = FMINSrr undef %1:fpr32, undef %2:fpr32, implicit $fpcr + %3:fpr32 = FADDSrr undef %4:fpr32, undef %5:fpr32, implicit $fpcr + %6:fpr32 = FMAXSrr %0, undef %7:fpr32, implicit $fpcr ... --- name: fmin_fmin_s tracksRegLiveness: true body: | bb.0: + ; CHECK-LABEL: fmin_fmin_s ; CHECK: SU(0): %0:fpr32 = FMINSrr ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster - ; CHECK: SU(2): %2:fpr32 = FMINSrr - %0:fpr32 = FMINSrr undef $s0, undef $s1, implicit $fpcr - %1:fpr32 = FADDSrr undef $s3, undef $s4, implicit $fpcr - %2:fpr32 = FMINSrr %0, undef $s2, implicit $fpcr + ; CHECK: SU(2): dead %6:fpr32 = FMINSrr + %0:fpr32 = FMINSrr undef %1:fpr32, undef %2:fpr32, implicit $fpcr + %3:fpr32 = FADDSrr undef %4:fpr32, undef %5:fpr32, implicit $fpcr + %6:fpr32 = FMINSrr %0, undef %7:fpr32, implicit $fpcr ... --- name: fmax_fmax_d tracksRegLiveness: true body: | bb.0: + ; CHECK-LABEL: fmax_fmax_d ; CHECK: SU(0): %0:fpr64 = FMAXDrr ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster - ; CHECK: SU(2): %2:fpr64 = FMAXDrr - %0:fpr64 = FMAXDrr undef $d0, undef $d1, implicit $fpcr - %1:fpr64 = FADDDrr undef $d3, undef $d4, implicit $fpcr - %2:fpr64 = FMAXDrr %0, undef $d2, implicit $fpcr + ; CHECK: SU(2): dead %6:fpr64 = FMAXDrr + %0:fpr64 = FMAXDrr undef %1:fpr64, undef %2:fpr64, implicit $fpcr + %3:fpr64 = FADDDrr undef %4:fpr64, undef %5:fpr64, implicit $fpcr + %6:fpr64 = FMAXDrr %0, undef %7:fpr64, implicit $fpcr ... --- name: fmax_fmin_d tracksRegLiveness: true body: | bb.0: + ; CHECK-LABEL: fmax_fmin_d ; CHECK: SU(0): %0:fpr64 = FMAXDrr ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster - ; CHECK: SU(2): %2:fpr64 = FMINDrr - %0:fpr64 = FMAXDrr undef $d0, undef $d1, implicit $fpcr - %1:fpr64 = FADDDrr undef $d3, undef $d4, implicit $fpcr - %2:fpr64 = FMINDrr %0, undef $d2, implicit $fpcr + ; CHECK: SU(2): dead %6:fpr64 = FMINDrr + %0:fpr64 = FMAXDrr undef %1:fpr64, undef %2:fpr64, implicit $fpcr + %3:fpr64 = FADDDrr undef %4:fpr64, undef %5:fpr64, implicit $fpcr + %6:fpr64 = FMINDrr %0, undef %7:fpr64, implicit $fpcr ... --- name: fmin_fmax_d tracksRegLiveness: true body: | bb.0: + ; CHECK-LABEL: fmin_fmax_d ; CHECK: SU(0): %0:fpr64 = FMINDrr ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster - ; CHECK: SU(2): %2:fpr64 = FMAXDrr - %0:fpr64 = FMINDrr undef $d0, undef $d1, implicit $fpcr - %1:fpr64 = FADDDrr undef $d3, undef $d4, implicit $fpcr - %2:fpr64 = FMAXDrr %0, undef $d2, implicit $fpcr + ; CHECK: SU(2): dead %6:fpr64 = FMAXDrr + %0:fpr64 = FMINDrr undef %1:fpr64, undef %2:fpr64, implicit $fpcr + %3:fpr64 = FADDDrr undef %4:fpr64, undef %5:fpr64, implicit $fpcr + %6:fpr64 = FMAXDrr %0, undef %7:fpr64, implicit $fpcr ... --- name: fmin_fmin_d tracksRegLiveness: true body: | bb.0: + ; CHECK-LABEL: fmin_fmin_d ; CHECK: SU(0): %0:fpr64 = FMINDrr ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster - ; CHECK: SU(2): %2:fpr64 = FMINDrr - %0:fpr64 = FMINDrr undef $d0, undef $d1, implicit $fpcr - %1:fpr64 = FADDDrr undef $d3, undef $d4, implicit $fpcr - %2:fpr64 = FMINDrr %0, undef $d2, implicit $fpcr + ; CHECK: SU(2): dead %6:fpr64 = FMINDrr + %0:fpr64 = FMINDrr undef %1:fpr64, undef %2:fpr64, implicit $fpcr + %3:fpr64 = FADDDrr undef %4:fpr64, undef %5:fpr64, implicit $fpcr + %6:fpr64 = FMINDrr %0, undef %7:fpr64, implicit $fpcr ... --- name: fmax_fmax_v4f16 tracksRegLiveness: true body: | bb.0: + ; CHECK-LABEL: fmax_fmax_v4f16 ; CHECK: SU(0): %0:fpr64 = FMAXv4f16 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster - ; CHECK: SU(2): %2:fpr64 = FMAXv4f16 - %0:fpr64 = FMAXv4f16 undef $d0, undef $d1, implicit $fpcr - %1:fpr64 = FADDv4f16 undef $d3, undef $d4, implicit $fpcr - %2:fpr64 = FMAXv4f16 %0, undef $d2, implicit $fpcr + ; CHECK: SU(2): dead %6:fpr64 = FMAXv4f16 + %0:fpr64 = FMAXv4f16 undef %1:fpr64, undef %2:fpr64, implicit $fpcr + %3:fpr64 = FADDv4f16 undef %4:fpr64, undef %5:fpr64, implicit $fpcr + %6:fpr64 = FMAXv4f16 %0, undef %7:fpr64, implicit $fpcr ... --- name: fmax_fmin_v4f16 tracksRegLiveness: true body: | bb.0: + ; CHECK-LABEL: fmax_fmin_v4f16 ; CHECK: SU(0): %0:fpr64 = FMAXv4f16 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster - ; CHECK: SU(2): %2:fpr64 = FMINv4f16 - %0:fpr64 = FMAXv4f16 undef $d0, undef $d1, implicit $fpcr - %1:fpr64 = FADDv4f16 undef $d3, undef $d4, implicit $fpcr - %2:fpr64 = FMINv4f16 %0, undef $d2, implicit $fpcr + ; CHECK: SU(2): dead %6:fpr64 = FMINv4f16 + %0:fpr64 = FMAXv4f16 undef %1:fpr64, undef %2:fpr64, implicit $fpcr + %3:fpr64 = FADDv4f16 undef %4:fpr64, undef %5:fpr64, implicit $fpcr + %6:fpr64 = FMINv4f16 %0, undef %7:fpr64, implicit $fpcr ... --- name: fmin_fmax_v4f16 tracksRegLiveness: true body: | bb.0: + ; CHECK-LABEL: fmin_fmax_v4f16 ; CHECK: SU(0): %0:fpr64 = FMINv4f16 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster - ; CHECK: SU(2): %2:fpr64 = FMAXv4f16 - %0:fpr64 = FMINv4f16 undef $d0, undef $d1, implicit $fpcr - %1:fpr64 = FADDv4f16 undef $d3, undef $d4, implicit $fpcr - %2:fpr64 = FMAXv4f16 %0, undef $d2, implicit $fpcr + ; CHECK: SU(2): dead %6:fpr64 = FMAXv4f16 + %0:fpr64 = FMINv4f16 undef %1:fpr64, undef %2:fpr64, implicit $fpcr + %3:fpr64 = FADDv4f16 undef %4:fpr64, undef %5:fpr64, implicit $fpcr + %6:fpr64 = FMAXv4f16 %0, undef %7:fpr64, implicit $fpcr ... --- name: fmin_fmin_v4f16 tracksRegLiveness: true body: | bb.0: + ; CHECK-LABEL: fmin_fmin_v4f16 ; CHECK: SU(0): %0:fpr64 = FMINv4f16 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster - ; CHECK: SU(2): %2:fpr64 = FMINv4f16 - %0:fpr64 = FMINv4f16 undef $d0, undef $d1, implicit $fpcr - %1:fpr64 = FADDv4f16 undef $d3, undef $d4, implicit $fpcr - %2:fpr64 = FMINv4f16 %0, undef $d2, implicit $fpcr + ; CHECK: SU(2): dead %6:fpr64 = FMINv4f16 + %0:fpr64 = FMINv4f16 undef %1:fpr64, undef %2:fpr64, implicit $fpcr + %3:fpr64 = FADDv4f16 undef %4:fpr64, undef %5:fpr64, implicit $fpcr + %6:fpr64 = FMINv4f16 %0, undef %7:fpr64, implicit $fpcr ... --- name: fmax_fmax_v8f16 tracksRegLiveness: true body: | bb.0: + ; CHECK-LABEL: fmax_fmax_v8f16 ; CHECK: SU(0): %0:fpr128 = FMAXv8f16 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster - ; CHECK: SU(2): %2:fpr128 = FMAXv8f16 - %0:fpr128 = FMAXv8f16 undef $q0, undef $q1, implicit $fpcr - %1:fpr128 = FADDv8f16 undef $q3, undef $q4, implicit $fpcr - %2:fpr128 = FMAXv8f16 %0, undef $q2, implicit $fpcr + ; CHECK: SU(2): dead %6:fpr128 = FMAXv8f16 + %0:fpr128 = FMAXv8f16 undef %1:fpr128, undef %2:fpr128, implicit $fpcr + %3:fpr128 = FADDv8f16 undef %4:fpr128, undef %5:fpr128, implicit $fpcr + %6:fpr128 = FMAXv8f16 %0, undef %7:fpr128, implicit $fpcr ... --- name: fmax_fmin_v8f16 tracksRegLiveness: true body: | bb.0: + ; CHECK-LABEL: fmax_fmin_v8f16 ; CHECK: SU(0): %0:fpr128 = FMAXv8f16 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster - ; CHECK: SU(2): %2:fpr128 = FMINv8f16 - %0:fpr128 = FMAXv8f16 undef $q0, undef $q1, implicit $fpcr - %1:fpr128 = FADDv8f16 undef $q3, undef $q4, implicit $fpcr - %2:fpr128 = FMINv8f16 %0, undef $q2, implicit $fpcr + ; CHECK: SU(2): dead %6:fpr128 = FMINv8f16 + %0:fpr128 = FMAXv8f16 undef %1:fpr128, undef %2:fpr128, implicit $fpcr + %3:fpr128 = FADDv8f16 undef %4:fpr128, undef %5:fpr128, implicit $fpcr + %6:fpr128 = FMINv8f16 %0, undef %7:fpr128, implicit $fpcr ... --- name: fmin_fmax_v8f16 tracksRegLiveness: true body: | bb.0: + ; CHECK-LABEL: fmin_fmax_v8f16 ; CHECK: SU(0): %0:fpr128 = FMINv8f16 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster - ; CHECK: SU(2): %2:fpr128 = FMAXv8f16 - %0:fpr128 = FMINv8f16 undef $q0, undef $q1, implicit $fpcr - %1:fpr128 = FADDv8f16 undef $q3, undef $q4, implicit $fpcr - %2:fpr128 = FMAXv8f16 %0, undef $q2, implicit $fpcr + ; CHECK: SU(2): dead %6:fpr128 = FMAXv8f16 + %0:fpr128 = FMINv8f16 undef %1:fpr128, undef %2:fpr128, implicit $fpcr + %3:fpr128 = FADDv8f16 undef %4:fpr128, undef %5:fpr128, implicit $fpcr + %6:fpr128 = FMAXv8f16 %0, undef %7:fpr128, implicit $fpcr ... --- name: fmin_fmin_v8f16 tracksRegLiveness: true body: | bb.0: + ; CHECK-LABEL: fmin_fmin_v8f16 ; CHECK: SU(0): %0:fpr128 = FMINv8f16 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster - ; CHECK: SU(2): %2:fpr128 = FMINv8f16 - %0:fpr128 = FMINv8f16 undef $q0, undef $q1, implicit $fpcr - %1:fpr128 = FADDv8f16 undef $q3, undef $q4, implicit $fpcr - %2:fpr128 = FMINv8f16 %0, undef $q2, implicit $fpcr + ; CHECK: SU(2): dead %6:fpr128 = FMINv8f16 + %0:fpr128 = FMINv8f16 undef %1:fpr128, undef %2:fpr128, implicit $fpcr + %3:fpr128 = FADDv8f16 undef %4:fpr128, undef %5:fpr128, implicit $fpcr + %6:fpr128 = FMINv8f16 %0, undef %7:fpr128, implicit $fpcr ... --- name: fmax_fmax_v2f32 tracksRegLiveness: true body: | bb.0: + ; CHECK-LABEL: fmax_fmax_v2f32 ; CHECK: SU(0): %0:fpr64 = FMAXv2f32 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster - ; CHECK: SU(2): %2:fpr64 = FMAXv2f32 - %0:fpr64 = FMAXv2f32 undef $d0, undef $d1, implicit $fpcr - %1:fpr64 = FADDv2f32 undef $d3, undef $d4, implicit $fpcr - %2:fpr64 = FMAXv2f32 %0, undef $d2, implicit $fpcr + ; CHECK: SU(2): dead %6:fpr64 = FMAXv2f32 + %0:fpr64 = FMAXv2f32 undef %1:fpr64, undef %2:fpr64, implicit $fpcr + %3:fpr64 = FADDv2f32 undef %4:fpr64, undef %5:fpr64, implicit $fpcr + %6:fpr64 = FMAXv2f32 %0, undef %7:fpr64, implicit $fpcr ... --- name: fmax_fmin_v2f32 tracksRegLiveness: true body: | bb.0: + ; CHECK-LABEL: fmax_fmin_v2f32 ; CHECK: SU(0): %0:fpr64 = FMAXv2f32 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster - ; CHECK: SU(2): %2:fpr64 = FMINv2f32 - %0:fpr64 = FMAXv2f32 undef $d0, undef $d1, implicit $fpcr - %1:fpr64 = FADDv2f32 undef $d3, undef $d4, implicit $fpcr - %2:fpr64 = FMINv2f32 %0, undef $d2, implicit $fpcr + ; CHECK: SU(2): dead %6:fpr64 = FMINv2f32 + %0:fpr64 = FMAXv2f32 undef %1:fpr64, undef %2:fpr64, implicit $fpcr + %3:fpr64 = FADDv2f32 undef %4:fpr64, undef %5:fpr64, implicit $fpcr + %6:fpr64 = FMINv2f32 %0, undef %7:fpr64, implicit $fpcr ... --- name: fmin_fmax_v2f32 tracksRegLiveness: true body: | bb.0: + ; CHECK-LABEL: fmin_fmax_v2f32 ; CHECK: SU(0): %0:fpr64 = FMINv2f32 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster - ; CHECK: SU(2): %2:fpr64 = FMAXv2f32 - %0:fpr64 = FMINv2f32 undef $d0, undef $d1, implicit $fpcr - %1:fpr64 = FADDv2f32 undef $d3, undef $d4, implicit $fpcr - %2:fpr64 = FMAXv2f32 %0, undef $d2, implicit $fpcr + ; CHECK: SU(2): dead %6:fpr64 = FMAXv2f32 + %0:fpr64 = FMINv2f32 undef %1:fpr64, undef %2:fpr64, implicit $fpcr + %3:fpr64 = FADDv2f32 undef %4:fpr64, undef %5:fpr64, implicit $fpcr + %6:fpr64 = FMAXv2f32 %0, undef %7:fpr64, implicit $fpcr ... --- name: fmin_fmin_v2f32 tracksRegLiveness: true body: | bb.0: + ; CHECK-LABEL: fmin_fmin_v2f32 ; CHECK: SU(0): %0:fpr64 = FMINv2f32 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster - ; CHECK: SU(2): %2:fpr64 = FMINv2f32 - %0:fpr64 = FMINv2f32 undef $d0, undef $d1, implicit $fpcr - %1:fpr64 = FADDv2f32 undef $d3, undef $d4, implicit $fpcr - %2:fpr64 = FMINv2f32 %0, undef $d2, implicit $fpcr + ; CHECK: SU(2): dead %6:fpr64 = FMINv2f32 + %0:fpr64 = FMINv2f32 undef %1:fpr64, undef %2:fpr64, implicit $fpcr + %3:fpr64 = FADDv2f32 undef %4:fpr64, undef %5:fpr64, implicit $fpcr + %6:fpr64 = FMINv2f32 %0, undef %7:fpr64, implicit $fpcr ... --- name: fmax_fmax_v4f32 tracksRegLiveness: true body: | bb.0: + ; CHECK-LABEL: fmax_fmax_v4f32 ; CHECK: SU(0): %0:fpr128 = FMAXv4f32 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster - ; CHECK: SU(2): %2:fpr128 = FMAXv4f32 - %0:fpr128 = FMAXv4f32 undef $q0, undef $q1, implicit $fpcr - %1:fpr128 = FADDv4f32 undef $q3, undef $q4, implicit $fpcr - %2:fpr128 = FMAXv4f32 %0, undef $q2, implicit $fpcr + ; CHECK: SU(2): dead %6:fpr128 = FMAXv4f32 + %0:fpr128 = FMAXv4f32 undef %1:fpr128, undef %2:fpr128, implicit $fpcr + %3:fpr128 = FADDv4f32 undef %4:fpr128, undef %5:fpr128, implicit $fpcr + %6:fpr128 = FMAXv4f32 %0, undef %7:fpr128, implicit $fpcr ... --- name: fmax_fmin_v4f32 tracksRegLiveness: true body: | bb.0: + ; CHECK-LABEL: fmax_fmin_v4f32 ; CHECK: SU(0): %0:fpr128 = FMAXv4f32 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster - ; CHECK: SU(2): %2:fpr128 = FMINv4f32 - %0:fpr128 = FMAXv4f32 undef $q0, undef $q1, implicit $fpcr - %1:fpr128 = FADDv4f32 undef $q3, undef $q4, implicit $fpcr - %2:fpr128 = FMINv4f32 %0, undef $q2, implicit $fpcr + ; CHECK: SU(2): dead %6:fpr128 = FMINv4f32 + %0:fpr128 = FMAXv4f32 undef %1:fpr128, undef %2:fpr128, implicit $fpcr + %3:fpr128 = FADDv4f32 undef %4:fpr128, undef %5:fpr128, implicit $fpcr + %6:fpr128 = FMINv4f32 %0, undef %7:fpr128, implicit $fpcr ... --- name: fmin_fmax_v4f32 tracksRegLiveness: true body: | bb.0: + ; CHECK-LABEL: fmin_fmax_v4f32 ; CHECK: SU(0): %0:fpr128 = FMINv4f32 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster - ; CHECK: SU(2): %2:fpr128 = FMAXv4f32 - %0:fpr128 = FMINv4f32 undef $q0, undef $q1, implicit $fpcr - %1:fpr128 = FADDv4f32 undef $q3, undef $q4, implicit $fpcr - %2:fpr128 = FMAXv4f32 %0, undef $q2, implicit $fpcr + ; CHECK: SU(2): dead %6:fpr128 = FMAXv4f32 + %0:fpr128 = FMINv4f32 undef %1:fpr128, undef %2:fpr128, implicit $fpcr + %3:fpr128 = FADDv4f32 undef %4:fpr128, undef %5:fpr128, implicit $fpcr + %6:fpr128 = FMAXv4f32 %0, undef %7:fpr128, implicit $fpcr ... --- name: fmin_fmin_v4f32 tracksRegLiveness: true body: | bb.0: + ; CHECK-LABEL: fmin_fmin_v4f32 ; CHECK: SU(0): %0:fpr128 = FMINv4f32 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster - ; CHECK: SU(2): %2:fpr128 = FMINv4f32 - %0:fpr128 = FMINv4f32 undef $q0, undef $q1, implicit $fpcr - %1:fpr128 = FADDv4f32 undef $q3, undef $q4, implicit $fpcr - %2:fpr128 = FMINv4f32 %0, undef $q2, implicit $fpcr + ; CHECK: SU(2): dead %6:fpr128 = FMINv4f32 + %0:fpr128 = FMINv4f32 undef %1:fpr128, undef %2:fpr128, implicit $fpcr + %3:fpr128 = FADDv4f32 undef %4:fpr128, undef %5:fpr128, implicit $fpcr + %6:fpr128 = FMINv4f32 %0, undef %7:fpr128, implicit $fpcr ... --- name: fmax_fmax_v2f64 tracksRegLiveness: true body: | bb.0: + ; CHECK-LABEL: fmax_fmax_v2f64 ; CHECK: SU(0): %0:fpr128 = FMAXv2f64 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster - ; CHECK: SU(2): %2:fpr128 = FMAXv2f64 - %0:fpr128 = FMAXv2f64 undef $q0, undef $q1, implicit $fpcr - %1:fpr128 = FADDv2f64 undef $q3, undef $q4, implicit $fpcr - %2:fpr128 = FMAXv2f64 %0, undef $q2, implicit $fpcr + ; CHECK: SU(2): dead %6:fpr128 = FMAXv2f64 + %0:fpr128 = FMAXv2f64 undef %1:fpr128, undef %2:fpr128, implicit $fpcr + %3:fpr128 = FADDv2f64 undef %4:fpr128, undef %5:fpr128, implicit $fpcr + %6:fpr128 = FMAXv2f64 %0, undef %7:fpr128, implicit $fpcr ... --- name: fmax_fmin_v2f64 tracksRegLiveness: true body: | bb.0: + ; CHECK-LABEL: fmax_fmin_v2f64 ; CHECK: SU(0): %0:fpr128 = FMAXv2f64 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster - ; CHECK: SU(2): %2:fpr128 = FMINv2f64 - %0:fpr128 = FMAXv2f64 undef $q0, undef $q1, implicit $fpcr - %1:fpr128 = FADDv2f64 undef $q3, undef $q4, implicit $fpcr - %2:fpr128 = FMINv2f64 %0, undef $q2, implicit $fpcr + ; CHECK: SU(2): dead %6:fpr128 = FMINv2f64 + %0:fpr128 = FMAXv2f64 undef %1:fpr128, undef %2:fpr128, implicit $fpcr + %3:fpr128 = FADDv2f64 undef %4:fpr128, undef %5:fpr128, implicit $fpcr + %6:fpr128 = FMINv2f64 %0, undef %7:fpr128, implicit $fpcr ... --- name: fmin_fmax_v2f64 tracksRegLiveness: true body: | bb.0: + ; CHECK-LABEL: fmin_fmax_v2f64 ; CHECK: SU(0): %0:fpr128 = FMINv2f64 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster - ; CHECK: SU(2): %2:fpr128 = FMAXv2f64 - %0:fpr128 = FMINv2f64 undef $q0, undef $q1, implicit $fpcr - %1:fpr128 = FADDv2f64 undef $q3, undef $q4, implicit $fpcr - %2:fpr128 = FMAXv2f64 %0, undef $q2, implicit $fpcr + ; CHECK: SU(2): dead %6:fpr128 = FMAXv2f64 + %0:fpr128 = FMINv2f64 undef %1:fpr128, undef %2:fpr128, implicit $fpcr + %3:fpr128 = FADDv2f64 undef %4:fpr128, undef %5:fpr128, implicit $fpcr + %6:fpr128 = FMAXv2f64 %0, undef %7:fpr128, implicit $fpcr ... --- name: fmin_fmin_v2f64 tracksRegLiveness: true body: | bb.0: + ; CHECK-LABEL: fmin_fmin_v2f64 ; CHECK: SU(0): %0:fpr128 = FMINv2f64 ; CHECK: Successors: ; FUSE: SU(2): Ord Latency={{[0-9]+}} Cluster ; NOFUSE-NOT: SU(2): Ord Latency={{[0-9]+}} Cluster - ; CHECK: SU(2): %2:fpr128 = FMINv2f64 - %0:fpr128 = FMINv2f64 undef $q0, undef $q1, implicit $fpcr - %1:fpr128 = FADDv2f64 undef $q3, undef $q4, implicit $fpcr - %2:fpr128 = FMINv2f64 %0, undef $q2, implicit $fpcr + ; CHECK: SU(2): dead %6:fpr128 = FMINv2f64 + %0:fpr128 = FMINv2f64 undef %1:fpr128, undef %2:fpr128, implicit $fpcr + %3:fpr128 = FADDv2f64 undef %4:fpr128, undef %5:fpr128, implicit $fpcr + %6:fpr128 = FMINv2f64 %0, undef %7:fpr128, implicit $fpcr ... From 8de3384e15a1c0d7dc20f4a01623428a5962c328 Mon Sep 17 00:00:00 2001 From: Alexey Samsonov Date: Thu, 6 Aug 2026 14:03:24 -0700 Subject: [PATCH 010/789] [libc] Add more Linux-specific macro for fcntl and sched. (#213727) * Add more `O_` flags (in particular, `O_LARGEFILE`) to fcntl-macros and group all creation/status flags (shared and arch-specific) together. * Add Linux `CLONE_` flags to sched-macros (to be exposed from ``). Those are also provided in `` kernel header, but the libc users often expect to find them in regular `` as those are passed to `clone()` syscall wrapper. Migrate internal Linux thread implementation to use our own header (instead of Linux kernel) for these macro. --- .../llvm-libc-macros/linux/fcntl-macros.h | 46 +++++++++---------- .../llvm-libc-macros/linux/sched-macros.h | 28 +++++++++++ .../__support/threads/linux/CMakeLists.txt | 1 + libc/src/__support/threads/linux/thread.cpp | 2 +- 4 files changed, 53 insertions(+), 24 deletions(-) diff --git a/libc/include/llvm-libc-macros/linux/fcntl-macros.h b/libc/include/llvm-libc-macros/linux/fcntl-macros.h index 74d406f742f38..8dcc177434cec 100644 --- a/libc/include/llvm-libc-macros/linux/fcntl-macros.h +++ b/libc/include/llvm-libc-macros/linux/fcntl-macros.h @@ -9,35 +9,35 @@ #ifndef LLVM_LIBC_MACROS_LINUX_FCNTL_MACROS_H #define LLVM_LIBC_MACROS_LINUX_FCNTL_MACROS_H -// File creation flags -#define O_CLOEXEC 02000000 -#define O_CREAT 00000100 +// File creation and file status flags. +#define O_APPEND 000002000 +#define O_ASYNC 000020000 +#define O_CLOEXEC 002000000 +#define O_CREAT 000000100 +#define O_DSYNC 000010000 +#define O_EXCL 000000200 +#define O_NOATIME 001000000 +#define O_NOCTTY 000000400 +#define O_NONBLOCK 000004000 +#define O_NDELAY O_NONBLOCK #define O_PATH 010000000 +#define O_SYNC 004010000 +#define O_TRUNC 000001000 #ifdef __aarch64__ -#define O_DIRECTORY 040000 +#define O_DIRECT 000200000 +#define O_DIRECTORY 000040000 +#define O_NOFOLLOW 000100000 +#define O_LARGEFILE 000040000 +#define O_TMPFILE 020040000 #else -#define O_DIRECTORY 00200000 +#define O_DIRECT 000040000 +#define O_DIRECTORY 000200000 +#define O_NOFOLLOW 000400000 +#define O_LARGEFILE 000100000 +#define O_TMPFILE 020200000 #endif -#define O_EXCL 00000200 -#define O_NOCTTY 00000400 - -#ifdef __aarch64__ -#define O_NOFOLLOW 0100000 -#else -#define O_NOFOLLOW 00400000 -#endif - -#define O_TRUNC 00001000 -#define O_TMPFILE (020000000 | O_DIRECTORY) - -// File status flags -#define O_APPEND 00002000 -#define O_DSYNC 00010000 -#define O_NONBLOCK 00004000 -#define O_SYNC 04000000 | O_DSYNC - // File access mode mask #define O_ACCMODE 00000003 diff --git a/libc/include/llvm-libc-macros/linux/sched-macros.h b/libc/include/llvm-libc-macros/linux/sched-macros.h index 28719b59d019a..c65d52d6f8c46 100644 --- a/libc/include/llvm-libc-macros/linux/sched-macros.h +++ b/libc/include/llvm-libc-macros/linux/sched-macros.h @@ -23,6 +23,34 @@ #define SCHED_IDLE 5 #define SCHED_DEADLINE 6 +// Linux-specific flags for clone. +#define CLONE_CHILD_CLEARTID 0x00200000 +#define CLONE_CHILD_SETTID 0x01000000 +#define CLONE_CLEAR_SIGHAND 0x100000000 +#define CLONE_DETACHED 0x00400000 +#define CLONE_FILES 0x00000400 +#define CLONE_FS 0x00000200 +#define CLONE_INTO_CGROUP 0x200000000 +#define CLONE_IO 0x80000000 +#define CLONE_NEWCGROUP 0x02000000 +#define CLONE_NEWIPC 0x08000000 +#define CLONE_NEWNET 0x40000000 +#define CLONE_NEWNS 0x00020000 +#define CLONE_NEWPID 0x20000000 +#define CLONE_NEWUSER 0x10000000 +#define CLONE_NEWUTS 0x04000000 +#define CLONE_PARENT 0x00008000 +#define CLONE_PARENT_SETTID 0x00100000 +#define CLONE_PIDFD 0x00001000 +#define CLONE_PTRACE 0x00002000 +#define CLONE_SETTLS 0x00080000 +#define CLONE_SIGHAND 0x00000800 +#define CLONE_SYSVSEM 0x00040000 +#define CLONE_THREAD 0x00010000 +#define CLONE_UNTRACED 0x00800000 +#define CLONE_VFORK 0x00004000 +#define CLONE_VM 0x00000100 + #define CPU_SETSIZE __CPU_SETSIZE #define NCPUBITS __NCPUBITS #define CPU_AND_S(setsize, destset, srcset1, srcset2) \ diff --git a/libc/src/__support/threads/linux/CMakeLists.txt b/libc/src/__support/threads/linux/CMakeLists.txt index 1124d1254ba76..14d57299dfd3f 100644 --- a/libc/src/__support/threads/linux/CMakeLists.txt +++ b/libc/src/__support/threads/linux/CMakeLists.txt @@ -34,6 +34,7 @@ add_object_library( libc.include.sys_syscall libc.hdr.fcntl_macros libc.hdr.errno_macros + libc.hdr.sched_macros libc.hdr.sys_mman_macros libc.src.errno.errno libc.src.__support.CPP.atomic diff --git a/libc/src/__support/threads/linux/thread.cpp b/libc/src/__support/threads/linux/thread.cpp index 704916fff95e6..9142d8ff10b00 100644 --- a/libc/src/__support/threads/linux/thread.cpp +++ b/libc/src/__support/threads/linux/thread.cpp @@ -34,11 +34,11 @@ #include "hdr/errno_macros.h" #include "hdr/fcntl_macros.h" +#include "hdr/sched_macros.h" // For CLONE_* flags. #include "hdr/stdint_proxy.h" #include "hdr/sys_mman_macros.h" // For PROT_* and MAP_* definitions. #include // For EXEC_PAGESIZE. #include // For PR_SET_NAME -#include // For CLONE_* flags. #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { From 3316c0b7fd2b88d23f747bded0f2bf6b559bc5c3 Mon Sep 17 00:00:00 2001 From: Ramkumar Ramachandra Date: Thu, 6 Aug 2026 22:18:09 +0100 Subject: [PATCH 011/789] [LAA] SCEV-licm-reduce depend_diff_types test (NFC) (#213875) Reduce a couple of tests in depend_diff_types in a way that preserves SCEV expressions, by creating invariants that we hoist outside the loop. This makes the tests a bit clearer. Illustration: https://godbolt.org/z/eTqdoPPzn Co-authored-by: Andrei Elovikov --- .../LoopAccessAnalysis/depend_diff_types.ll | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/llvm/test/Analysis/LoopAccessAnalysis/depend_diff_types.ll b/llvm/test/Analysis/LoopAccessAnalysis/depend_diff_types.ll index 5d59660a68e90..84e9d70a16d3b 100644 --- a/llvm/test/Analysis/LoopAccessAnalysis/depend_diff_types.ll +++ b/llvm/test/Analysis/LoopAccessAnalysis/depend_diff_types.ll @@ -265,9 +265,8 @@ exit: ; i16 i32 ; [ . . 0 0 . . 1 1] [ 1 1 0 0 . . 1 1 ] -; ^~~^ gep i8 = 1 -; ^ ~~ ^ iv.2 = iv + 2 -; ^ ~~~~~ ^ dependence distance = 4 +; ^~^ gep i8 = 1 +; ^ ~~~~ ^ dependence distance = 4 ; ^ ~~~~~~~~~~~~~~~~~ ^ 8 ; ^ ~~~~~~~~~~~~~~~~ ^ 8 ; ^ ~~~~~~~~~~~~~~~~ ^ iv.next = iv + 8 @@ -284,8 +283,8 @@ define void @different_type_sizes_strided_accesses_independent(ptr %dst) { ; CHECK-NEXT: Unknown data dependence. ; CHECK-NEXT: Dependences: ; CHECK-NEXT: Unknown: -; CHECK-NEXT: store i16 0, ptr %gep.iv, align 2 -> -; CHECK-NEXT: store i32 1, ptr %gep.4.iv, align 4 +; CHECK-NEXT: store i16 0, ptr %gep.2.iv, align 2 -> +; CHECK-NEXT: store i32 1, ptr %gep.6.iv, align 4 ; CHECK-EMPTY: ; CHECK-NEXT: Run-time memory checks: ; CHECK-NEXT: Grouped accesses: @@ -296,16 +295,17 @@ define void @different_type_sizes_strided_accesses_independent(ptr %dst) { ; CHECK-NEXT: Expressions re-written: ; entry: - %gep.4 = getelementptr nuw i8, ptr %dst, i64 4 + ; Intentionally offset both to test logic. + %gep.2 = getelementptr nuw i8, ptr %dst, i64 2 + %gep.6 = getelementptr nuw i8, ptr %dst, i64 6 br label %loop loop: %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] - %iv.2 = add nuw nsw i64 %iv, 2 - %gep.iv = getelementptr i8, ptr %dst, i64 %iv.2 - store i16 0, ptr %gep.iv - %gep.4.iv = getelementptr i8, ptr %gep.4, i64 %iv.2 - store i32 1, ptr %gep.4.iv + %gep.2.iv = getelementptr i8, ptr %gep.2, i64 %iv + store i16 0, ptr %gep.2.iv + %gep.6.iv = getelementptr i8, ptr %gep.6, i64 %iv + store i32 1, ptr %gep.6.iv %iv.next = add nuw nsw i64 %iv, 8 %ec = icmp eq i64 %iv.next, 64 br i1 %ec, label %exit, label %loop @@ -317,9 +317,8 @@ exit: ; i16 i64 ; [ . 0 0 . 1 1 1 1] [ 1 x x 1 1 1 1 1 ] -; ^~~^ gep i8 = 1 -; ^~~^ iv.1 = iv + 1 -; ^ ~~ ^ dependence distance = 3 +; ^~^ gep i8 = 1 +; ^ ~~~ ^ dependence distance = 3 ; ^ ~~~~~~~~~~~~~~~~ ^ 8 ; ^ ~~~~~~~~~~~~~~~~ ^ 8 ; ^ ~~~~~~~~~~~~~~~~ ^ iv.next = iv + 8 @@ -333,8 +332,8 @@ define void @different_type_sizes_strided_accesses_dependent(ptr %dst) { ; CHECK-NEXT: Unknown data dependence. ; CHECK-NEXT: Dependences: ; CHECK-NEXT: Unknown: -; CHECK-NEXT: store i16 0, ptr %gep.iv, align 2 -> -; CHECK-NEXT: store i64 1, ptr %gep.3.iv, align 4 +; CHECK-NEXT: store i16 0, ptr %gep.1.iv, align 2 -> +; CHECK-NEXT: store i64 1, ptr %gep.4.iv, align 4 ; CHECK-EMPTY: ; CHECK-NEXT: Run-time memory checks: ; CHECK-NEXT: Grouped accesses: @@ -345,16 +344,17 @@ define void @different_type_sizes_strided_accesses_dependent(ptr %dst) { ; CHECK-NEXT: Expressions re-written: ; entry: - %gep.3 = getelementptr nuw i8, ptr %dst, i64 3 + ; Intentionally offset both to test logic. + %gep.1 = getelementptr nuw i8, ptr %dst, i64 1 + %gep.4 = getelementptr nuw i8, ptr %dst, i64 4 br label %loop loop: %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] - %iv.1 = add nuw nsw i64 %iv, 1 - %gep.iv = getelementptr i8, ptr %dst, i64 %iv.1 - store i16 0, ptr %gep.iv - %gep.3.iv = getelementptr i8, ptr %gep.3, i64 %iv.1 - store i64 1, ptr %gep.3.iv + %gep.1.iv = getelementptr i8, ptr %gep.1, i64 %iv + store i16 0, ptr %gep.1.iv + %gep.4.iv = getelementptr i8, ptr %gep.4, i64 %iv + store i64 1, ptr %gep.4.iv %iv.next = add nuw nsw i64 %iv, 8 %ec = icmp eq i64 %iv.next, 64 br i1 %ec, label %exit, label %loop From 10dbfc4863c9aea2fb237022c3f47fc24c02265e Mon Sep 17 00:00:00 2001 From: Thibaut Goetghebuer-Planchon Date: Thu, 6 Aug 2026 22:23:39 +0100 Subject: [PATCH 012/789] [mlir][tosa] Skip dense resource folding tests on big-endian platforms (#214479) --- ...ayerwise-constant-fold-dense-resource.mlir | 141 ++++++++++++++++++ .../Tosa/tosa-layerwise-constant-fold.mlir | 138 ----------------- 2 files changed, 141 insertions(+), 138 deletions(-) create mode 100644 mlir/test/Dialect/Tosa/tosa-layerwise-constant-fold-dense-resource.mlir diff --git a/mlir/test/Dialect/Tosa/tosa-layerwise-constant-fold-dense-resource.mlir b/mlir/test/Dialect/Tosa/tosa-layerwise-constant-fold-dense-resource.mlir new file mode 100644 index 0000000000000..86c8f64adbc6b --- /dev/null +++ b/mlir/test/Dialect/Tosa/tosa-layerwise-constant-fold-dense-resource.mlir @@ -0,0 +1,141 @@ +// RUN: mlir-opt --split-input-file --tosa-layerwise-constant-fold %s | FileCheck %s + +// Skip big-endian platforms for dense resources +// XFAIL: target={{(s390x|sparc.*)-.*}} +// XFAIL: system-aix + +// CHECK-LABEL: @transpose_fold_dense_resource +func.func @transpose_fold_dense_resource() -> tensor<2x2xf32> { + %0 = "tosa.const"() <{values = dense_resource : tensor<2x2xf32>}> : () -> tensor<2x2xf32> + + // CHECK-NOT: tosa.transpose + %2 = tosa.transpose %0 { perms = array }: (tensor<2x2xf32>) -> tensor<2x2xf32> + return %2 : tensor<2x2xf32> +} +{-# + dialect_resources: { + builtin: { + resource: "0x040000003f800000400000004040000040800000" + } + } +#-} + +// ----- + +// CHECK-LABEL: @transpose_fold_dense_resource_f8e4m3fn +func.func @transpose_fold_dense_resource_f8e4m3fn() -> tensor<2x2xf8E4M3FN> { + %0 = "tosa.const"() <{values = dense_resource : tensor<2x2xf8E4M3FN>}> : () -> tensor<2x2xf8E4M3FN> + + // CHECK: %[[CST:.+]] = "tosa.const"() <{ + // CHECK-SAME{LITERAL}: values = dense<[[1.000000e+00, 3.000000e+00], [2.000000e+00, 4.000000e+00]]> : tensor<2x2xf8E4M3FN> + %1 = tosa.transpose %0 { perms = array }: (tensor<2x2xf8E4M3FN>) -> tensor<2x2xf8E4M3FN> + // CHECK: return %[[CST]] + return %1 : tensor<2x2xf8E4M3FN> +} +{-# + dialect_resources: { + builtin: { + resource: "0x0100000038404448" + } + } +#-} + +// ----- + +// CHECK-LABEL: @transpose_fold_dense_resource_f8e5m2 +func.func @transpose_fold_dense_resource_f8e5m2() -> tensor<2x2xf8E5M2> { + %0 = "tosa.const"() <{values = dense_resource : tensor<2x2xf8E5M2>}> : () -> tensor<2x2xf8E5M2> + + // CHECK: %[[CST:.+]] = "tosa.const"() <{ + // CHECK-SAME{LITERAL}: values = dense<[[1.000000e+00, 3.000000e+00], [2.000000e+00, 4.000000e+00]]> : tensor<2x2xf8E5M2> + %1 = tosa.transpose %0 { perms = array }: (tensor<2x2xf8E5M2>) -> tensor<2x2xf8E5M2> + // CHECK: return %[[CST]] + return %1 : tensor<2x2xf8E5M2> +} +{-# + dialect_resources: { + builtin: { + resource: "0x010000003c404244" + } + } +#-} + +// ----- + +// CHECK-LABEL: @transpose_fold_dense_resource_f4e2m1fn +func.func @transpose_fold_dense_resource_f4e2m1fn() -> tensor<2x2xf4E2M1FN> { + %0 = "tosa.const"() <{values = dense_resource : tensor<2x2xf4E2M1FN>}> : () -> tensor<2x2xf4E2M1FN> + + // CHECK: %[[CST:.+]] = "tosa.const"() <{ + // CHECK-SAME{LITERAL}: values = dense<[[1.000000e+00, 3.000000e+00], [2.000000e+00, 4.000000e+00]]> : tensor<2x2xf4E2M1FN> + %1 = tosa.transpose %0 { perms = array }: (tensor<2x2xf4E2M1FN>) -> tensor<2x2xf4E2M1FN> + // CHECK: return %[[CST]] + return %1 : tensor<2x2xf4E2M1FN> +} +{-# + dialect_resources: { + builtin: { + resource: "0x0100000002040506" + } + } +#-} + +// ----- + +// CHECK-LABEL: @transpose_fold_dense_resource_f16 +func.func @transpose_fold_dense_resource_f16() -> tensor<2x2xf16> { + %0 = "tosa.const"() <{values = dense_resource : tensor<2x2xf16>}> : () -> tensor<2x2xf16> + + // CHECK: %[[CST:.+]] = "tosa.const"() <{ + // CHECK-SAME{LITERAL}: values = dense<[[1.000000e+00, 3.000000e+00], [2.000000e+00, 4.000000e+00]]> : tensor<2x2xf16> + %1 = tosa.transpose %0 { perms = array }: (tensor<2x2xf16>) -> tensor<2x2xf16> + // CHECK: return %[[CST]] + return %1 : tensor<2x2xf16> +} +{-# + dialect_resources: { + builtin: { + resource: "0x02000000003c004000420044" + } + } +#-} + +// ----- + +// CHECK-LABEL: @transpose_fold_dense_resource_bf16 +func.func @transpose_fold_dense_resource_bf16() -> tensor<2x2xbf16> { + %0 = "tosa.const"() <{values = dense_resource : tensor<2x2xbf16>}> : () -> tensor<2x2xbf16> + + // CHECK: %[[CST:.+]] = "tosa.const"() <{ + // CHECK-SAME{LITERAL}: values = dense<[[1.000000e+00, 3.000000e+00], [2.000000e+00, 4.000000e+00]]> : tensor<2x2xbf16> + %1 = tosa.transpose %0 { perms = array }: (tensor<2x2xbf16>) -> tensor<2x2xbf16> + // CHECK: return %[[CST]] + return %1 : tensor<2x2xbf16> +} +{-# + dialect_resources: { + builtin: { + resource: "0x02000000803f004040408040" + } + } +#-} + +// ----- + +// CHECK-LABEL: @transpose_fold_dense_resource_f64 +func.func @transpose_fold_dense_resource_f64() -> tensor<2x2xf64> { + %0 = "tosa.const"() <{values = dense_resource : tensor<2x2xf64>}> : () -> tensor<2x2xf64> + + // CHECK: %[[CST:.+]] = "tosa.const"() <{ + // CHECK-SAME{LITERAL}: values = dense<[[1.000000e+00, 3.000000e+00], [2.000000e+00, 4.000000e+00]]> : tensor<2x2xf64> + %1 = tosa.transpose %0 { perms = array }: (tensor<2x2xf64>) -> tensor<2x2xf64> + // CHECK: return %[[CST]] + return %1 : tensor<2x2xf64> +} +{-# + dialect_resources: { + builtin: { + resource: "0x08000000000000000000f03f000000000000004000000000000008400000000000001040" + } + } +#-} diff --git a/mlir/test/Dialect/Tosa/tosa-layerwise-constant-fold.mlir b/mlir/test/Dialect/Tosa/tosa-layerwise-constant-fold.mlir index 296c72bb366a4..9f745d4f57640 100644 --- a/mlir/test/Dialect/Tosa/tosa-layerwise-constant-fold.mlir +++ b/mlir/test/Dialect/Tosa/tosa-layerwise-constant-fold.mlir @@ -147,144 +147,6 @@ func.func @transpose_nofold_quantized_types() -> tensor<1x1x2x2x!quant.uniform:f32:3, {1.000000e-01,1.000000e-01}>> } -// ----- - -// CHECK-LABEL: @transpose_fold_dense_resource -func.func @transpose_fold_dense_resource() -> tensor<2x2xf32> { - %0 = "tosa.const"() <{values = dense_resource : tensor<2x2xf32>}> : () -> tensor<2x2xf32> - - // CHECK-NOT: tosa.transpose - %2 = tosa.transpose %0 { perms = array }: (tensor<2x2xf32>) -> tensor<2x2xf32> - return %2 : tensor<2x2xf32> -} -{-# - dialect_resources: { - builtin: { - resource: "0x040000003f800000400000004040000040800000" - } - } -#-} - -// ----- - -// CHECK-LABEL: @transpose_fold_dense_resource_f8e4m3fn -func.func @transpose_fold_dense_resource_f8e4m3fn() -> tensor<2x2xf8E4M3FN> { - %0 = "tosa.const"() <{values = dense_resource : tensor<2x2xf8E4M3FN>}> : () -> tensor<2x2xf8E4M3FN> - - // CHECK: %[[CST:.+]] = "tosa.const"() <{ - // CHECK-SAME{LITERAL}: values = dense<[[1.000000e+00, 3.000000e+00], [2.000000e+00, 4.000000e+00]]> : tensor<2x2xf8E4M3FN> - %1 = tosa.transpose %0 { perms = array }: (tensor<2x2xf8E4M3FN>) -> tensor<2x2xf8E4M3FN> - // CHECK: return %[[CST]] - return %1 : tensor<2x2xf8E4M3FN> -} -{-# - dialect_resources: { - builtin: { - resource: "0x0100000038404448" - } - } -#-} - -// ----- - -// CHECK-LABEL: @transpose_fold_dense_resource_f8e5m2 -func.func @transpose_fold_dense_resource_f8e5m2() -> tensor<2x2xf8E5M2> { - %0 = "tosa.const"() <{values = dense_resource : tensor<2x2xf8E5M2>}> : () -> tensor<2x2xf8E5M2> - - // CHECK: %[[CST:.+]] = "tosa.const"() <{ - // CHECK-SAME{LITERAL}: values = dense<[[1.000000e+00, 3.000000e+00], [2.000000e+00, 4.000000e+00]]> : tensor<2x2xf8E5M2> - %1 = tosa.transpose %0 { perms = array }: (tensor<2x2xf8E5M2>) -> tensor<2x2xf8E5M2> - // CHECK: return %[[CST]] - return %1 : tensor<2x2xf8E5M2> -} -{-# - dialect_resources: { - builtin: { - resource: "0x010000003c404244" - } - } -#-} - -// ----- - -// CHECK-LABEL: @transpose_fold_dense_resource_f4e2m1fn -func.func @transpose_fold_dense_resource_f4e2m1fn() -> tensor<2x2xf4E2M1FN> { - %0 = "tosa.const"() <{values = dense_resource : tensor<2x2xf4E2M1FN>}> : () -> tensor<2x2xf4E2M1FN> - - // CHECK: %[[CST:.+]] = "tosa.const"() <{ - // CHECK-SAME{LITERAL}: values = dense<[[1.000000e+00, 3.000000e+00], [2.000000e+00, 4.000000e+00]]> : tensor<2x2xf4E2M1FN> - %1 = tosa.transpose %0 { perms = array }: (tensor<2x2xf4E2M1FN>) -> tensor<2x2xf4E2M1FN> - // CHECK: return %[[CST]] - return %1 : tensor<2x2xf4E2M1FN> -} -{-# - dialect_resources: { - builtin: { - resource: "0x0100000002040506" - } - } -#-} - -// ----- - -// CHECK-LABEL: @transpose_fold_dense_resource_f16 -func.func @transpose_fold_dense_resource_f16() -> tensor<2x2xf16> { - %0 = "tosa.const"() <{values = dense_resource : tensor<2x2xf16>}> : () -> tensor<2x2xf16> - - // CHECK: %[[CST:.+]] = "tosa.const"() <{ - // CHECK-SAME{LITERAL}: values = dense<[[1.000000e+00, 3.000000e+00], [2.000000e+00, 4.000000e+00]]> : tensor<2x2xf16> - %1 = tosa.transpose %0 { perms = array }: (tensor<2x2xf16>) -> tensor<2x2xf16> - // CHECK: return %[[CST]] - return %1 : tensor<2x2xf16> -} -{-# - dialect_resources: { - builtin: { - resource: "0x02000000003c004000420044" - } - } -#-} - -// ----- - -// CHECK-LABEL: @transpose_fold_dense_resource_bf16 -func.func @transpose_fold_dense_resource_bf16() -> tensor<2x2xbf16> { - %0 = "tosa.const"() <{values = dense_resource : tensor<2x2xbf16>}> : () -> tensor<2x2xbf16> - - // CHECK: %[[CST:.+]] = "tosa.const"() <{ - // CHECK-SAME{LITERAL}: values = dense<[[1.000000e+00, 3.000000e+00], [2.000000e+00, 4.000000e+00]]> : tensor<2x2xbf16> - %1 = tosa.transpose %0 { perms = array }: (tensor<2x2xbf16>) -> tensor<2x2xbf16> - // CHECK: return %[[CST]] - return %1 : tensor<2x2xbf16> -} -{-# - dialect_resources: { - builtin: { - resource: "0x02000000803f004040408040" - } - } -#-} - -// ----- - -// CHECK-LABEL: @transpose_fold_dense_resource_f64 -func.func @transpose_fold_dense_resource_f64() -> tensor<2x2xf64> { - %0 = "tosa.const"() <{values = dense_resource : tensor<2x2xf64>}> : () -> tensor<2x2xf64> - - // CHECK: %[[CST:.+]] = "tosa.const"() <{ - // CHECK-SAME{LITERAL}: values = dense<[[1.000000e+00, 3.000000e+00], [2.000000e+00, 4.000000e+00]]> : tensor<2x2xf64> - %1 = tosa.transpose %0 { perms = array }: (tensor<2x2xf64>) -> tensor<2x2xf64> - // CHECK: return %[[CST]] - return %1 : tensor<2x2xf64> -} -{-# - dialect_resources: { - builtin: { - resource: "0x08000000000000000000f03f000000000000004000000000000008400000000000001040" - } - } -#-} - // ----- func.func @reduce_sum_constant() -> tensor<1x3xi32> { From 36e1616725cb56bd4b9fee255d85294407b213cc Mon Sep 17 00:00:00 2001 From: Jakub Jakacki Date: Thu, 6 Aug 2026 14:24:42 -0700 Subject: [PATCH 013/789] Rename Compiler-RT target to compiler-rt in CMake files (#214364) Visual Studio 2026 has trouble generating valid solutions for projects with mismatching directory names. The change renames the Compiler-RT target to match the directory name "compiler-rt" in all CMake files. --- compiler-rt/CMakeLists.txt | 2 +- compiler-rt/cmake/Modules/AddCompilerRT.cmake | 18 +++++++++--------- .../cmake/Modules/CompilerRTDarwinUtils.cmake | 4 ++-- .../cmake/Modules/CompilerRTUtils.cmake | 4 ++-- compiler-rt/cmake/base-config-ix.cmake | 4 ++-- compiler-rt/include/CMakeLists.txt | 2 +- compiler-rt/lib/asan/tests/CMakeLists.txt | 8 ++++---- compiler-rt/lib/builtins/CMakeLists.txt | 2 +- .../lib/ctx_profile/tests/CMakeLists.txt | 4 ++-- compiler-rt/lib/fuzzer/tests/CMakeLists.txt | 6 +++--- compiler-rt/lib/gwp_asan/tests/CMakeLists.txt | 4 ++-- .../lib/interception/tests/CMakeLists.txt | 4 ++-- compiler-rt/lib/memprof/tests/CMakeLists.txt | 4 ++-- compiler-rt/lib/orc/tests/CMakeLists.txt | 6 +++--- compiler-rt/lib/rtsan/tests/CMakeLists.txt | 4 ++-- .../lib/sanitizer_common/tests/CMakeLists.txt | 4 ++-- .../lib/sanitizer_ignorelists/CMakeLists.txt | 4 ++-- .../lib/scudo/standalone/tests/CMakeLists.txt | 2 +- compiler-rt/lib/stats/CMakeLists.txt | 2 +- compiler-rt/lib/tsan/CMakeLists.txt | 2 +- compiler-rt/lib/tsan/dd/CMakeLists.txt | 2 +- compiler-rt/lib/tsan/rtl/CMakeLists.txt | 2 +- compiler-rt/lib/tsan/tests/CMakeLists.txt | 2 +- compiler-rt/lib/xray/tests/CMakeLists.txt | 4 ++-- compiler-rt/test/CMakeLists.txt | 2 +- compiler-rt/test/ctx_profile/CMakeLists.txt | 2 +- compiler-rt/test/rtsan/CMakeLists.txt | 2 +- .../test/scudo/standalone/CMakeLists.txt | 2 +- compiler-rt/test/tsan/CMakeLists.txt | 2 +- compiler-rt/test/tysan/CMakeLists.txt | 2 +- llvm/runtimes/CMakeLists.txt | 8 ++++---- 31 files changed, 60 insertions(+), 60 deletions(-) diff --git a/compiler-rt/CMakeLists.txt b/compiler-rt/CMakeLists.txt index d720b86c6df24..b7edbe54a5f8d 100644 --- a/compiler-rt/CMakeLists.txt +++ b/compiler-rt/CMakeLists.txt @@ -12,7 +12,7 @@ if("${CMAKE_VERSION}" VERSION_LESS "3.31.0") "at least 3.31.0 now to avoid issues in the future.") endif() -set(LLVM_SUBPROJECT_TITLE "Compiler-RT") +set(LLVM_SUBPROJECT_TITLE "compiler-rt") if(NOT DEFINED LLVM_COMMON_CMAKE_UTILS) set(LLVM_COMMON_CMAKE_UTILS ${CMAKE_CURRENT_SOURCE_DIR}/../cmake) diff --git a/compiler-rt/cmake/Modules/AddCompilerRT.cmake b/compiler-rt/cmake/Modules/AddCompilerRT.cmake index bdb8ff4868b29..0b0fc8efb83a0 100644 --- a/compiler-rt/cmake/Modules/AddCompilerRT.cmake +++ b/compiler-rt/cmake/Modules/AddCompilerRT.cmake @@ -91,7 +91,7 @@ function(add_compiler_rt_object_libraries name) ${extra_cflags_${libname}} ${target_flags}) set_property(TARGET ${libname} APPEND PROPERTY COMPILE_DEFINITIONS ${LIB_DEFS}) - set_target_properties(${libname} PROPERTIES FOLDER "Compiler-RT/Libraries") + set_target_properties(${libname} PROPERTIES FOLDER "compiler-rt/Libraries") if(APPLE) set_target_properties(${libname} PROPERTIES OSX_ARCHITECTURES "${LIB_ARCHS_${libname}}") @@ -110,7 +110,7 @@ endmacro() function(add_compiler_rt_component name) add_custom_target(${name}) - set_target_properties(${name} PROPERTIES FOLDER "Compiler-RT/Components") + set_target_properties(${name} PROPERTIES FOLDER "compiler-rt/Components") if(COMMAND runtime_register_component) runtime_register_component(${name}) endif() @@ -302,7 +302,7 @@ function(add_compiler_rt_runtime name type) if(NOT TARGET ${LIB_PARENT_TARGET}) add_custom_target(${LIB_PARENT_TARGET}) set_target_properties(${LIB_PARENT_TARGET} PROPERTIES - FOLDER "Compiler-RT/Runtimes") + FOLDER "compiler-rt/Runtimes") endif() endif() @@ -357,7 +357,7 @@ function(add_compiler_rt_runtime name type) DEPENDS ${sources_${libname}} COMMENT "Building C object ${output_file_${libname}}") add_custom_target(${libname} DEPENDS ${output_dir_${libname}}/${output_file_${libname}}) - set_target_properties(${libname} PROPERTIES FOLDER "Compiler-RT/Codegenning") + set_target_properties(${libname} PROPERTIES FOLDER "compiler-rt/Codegenning") install(FILES ${output_dir_${libname}}/${output_file_${libname}} DESTINATION ${install_dir_${libname}} ${COMPONENT_OPTION}) @@ -387,7 +387,7 @@ function(add_compiler_rt_runtime name type) endif() set_target_properties(${libname} PROPERTIES OUTPUT_NAME ${output_name_${libname}} - FOLDER "Compiler-RT/Runtimes") + FOLDER "compiler-rt/Runtimes") if(LIB_LINK_LIBS) target_link_libraries(${libname} PRIVATE ${LIB_LINK_LIBS}) endif() @@ -558,7 +558,7 @@ function(add_compiler_rt_test test_suite test_name arch) DEPENDS ${TEST_DEPS} ) add_custom_target(T${test_name} DEPENDS "${output_bin}") - set_target_properties(T${test_name} PROPERTIES FOLDER "Compiler-RT/Tests") + set_target_properties(T${test_name} PROPERTIES FOLDER "compiler-rt/Tests") # Make the test suite depend on the binary. add_dependencies(${test_suite} T${test_name}) @@ -592,7 +592,7 @@ macro(add_compiler_rt_cfg target_name file_name component arch) COMPONENT ${component}) add_dependencies(${component} ${target_name}) - set_target_properties(${target_name} PROPERTIES FOLDER "Compiler-RT Misc") + set_target_properties(${target_name} PROPERTIES FOLDER "compiler-rt Misc") endmacro() # Builds custom version of libc++ and installs it in . @@ -628,7 +628,7 @@ macro(add_custom_libcxx name prefix) COMMENT "Clobbering ${name} build directories" USES_TERMINAL ) - set_target_properties(${name}-clear PROPERTIES FOLDER "Compiler-RT/Metatargets") + set_target_properties(${name}-clear PROPERTIES FOLDER "compiler-rt/Metatargets") add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${name}-clobber-stamp @@ -640,7 +640,7 @@ macro(add_custom_libcxx name prefix) add_custom_target(${name}-clobber DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${name}-clobber-stamp) - set_target_properties(${name}-clobber PROPERTIES FOLDER "Compiler-RT/Metatargets") + set_target_properties(${name}-clobber PROPERTIES FOLDER "compiler-rt/Metatargets") set(PASSTHROUGH_VARIABLES ANDROID diff --git a/compiler-rt/cmake/Modules/CompilerRTDarwinUtils.cmake b/compiler-rt/cmake/Modules/CompilerRTDarwinUtils.cmake index 4864040e02865..e4c0faaee2847 100644 --- a/compiler-rt/cmake/Modules/CompilerRTDarwinUtils.cmake +++ b/compiler-rt/cmake/Modules/CompilerRTDarwinUtils.cmake @@ -339,7 +339,7 @@ macro(darwin_add_builtin_library name suffix) list(APPEND ${LIB_OS}_${suffix}_libs ${libname}) list(APPEND ${LIB_OS}_${suffix}_lipo_flags -arch ${arch} $) - set_target_properties(${libname} PROPERTIES FOLDER "Compiler-RT/Libraries") + set_target_properties(${libname} PROPERTIES FOLDER "compiler-rt/Libraries") endmacro() function(darwin_lipo_libs name) @@ -358,7 +358,7 @@ function(darwin_lipo_libs name) ) add_custom_target(${name} DEPENDS ${LIB_OUTPUT_DIR}/lib${name}.a) - set_target_properties(${name} PROPERTIES FOLDER "Compiler-RT/Misc") + set_target_properties(${name} PROPERTIES FOLDER "compiler-rt/Misc") add_dependencies(${LIB_PARENT_TARGET} ${name}) if(CMAKE_CONFIGURATION_TYPES) diff --git a/compiler-rt/cmake/Modules/CompilerRTUtils.cmake b/compiler-rt/cmake/Modules/CompilerRTUtils.cmake index a35a32ef9efde..1f5e7b6984364 100644 --- a/compiler-rt/cmake/Modules/CompilerRTUtils.cmake +++ b/compiler-rt/cmake/Modules/CompilerRTUtils.cmake @@ -591,9 +591,9 @@ function(add_compiler_rt_install_targets name) -DCMAKE_INSTALL_DO_STRIP=1 -P "${CMAKE_BINARY_DIR}/cmake_install.cmake") set_target_properties(install-${ARG_PARENT_TARGET} PROPERTIES - FOLDER "Compiler-RT/Installation") + FOLDER "compiler-rt/Installation") set_target_properties(install-${ARG_PARENT_TARGET}-stripped PROPERTIES - FOLDER "Compiler-RT/Installation") + FOLDER "compiler-rt/Installation") add_dependencies(install-compiler-rt install-${ARG_PARENT_TARGET}) add_dependencies(install-compiler-rt-stripped install-${ARG_PARENT_TARGET}-stripped) endif() diff --git a/compiler-rt/cmake/base-config-ix.cmake b/compiler-rt/cmake/base-config-ix.cmake index d111a8002687b..15e8be327380c 100644 --- a/compiler-rt/cmake/base-config-ix.cmake +++ b/compiler-rt/cmake/base-config-ix.cmake @@ -41,13 +41,13 @@ endif() add_custom_target(compiler-rt ALL) add_custom_target(install-compiler-rt) add_custom_target(install-compiler-rt-stripped) -set_property(TARGET compiler-rt PROPERTY FOLDER "Compiler-RT/Metatargets") +set_property(TARGET compiler-rt PROPERTY FOLDER "compiler-rt/Metatargets") set_property( TARGET install-compiler-rt install-compiler-rt-stripped PROPERTY - FOLDER "Compiler-RT/Installation" + FOLDER "compiler-rt/Installation" ) # Setting these variables from an LLVM build is sufficient that compiler-rt can diff --git a/compiler-rt/include/CMakeLists.txt b/compiler-rt/include/CMakeLists.txt index eb998478b081b..f1c8ebcc9b363 100644 --- a/compiler-rt/include/CMakeLists.txt +++ b/compiler-rt/include/CMakeLists.txt @@ -82,7 +82,7 @@ endforeach( f ) add_custom_target(compiler-rt-headers ALL DEPENDS ${out_files}) add_dependencies(compiler-rt compiler-rt-headers) -set_target_properties(compiler-rt-headers PROPERTIES FOLDER "Compiler-RT/Resources") +set_target_properties(compiler-rt-headers PROPERTIES FOLDER "compiler-rt/Resources") # Install sanitizer headers. install(FILES ${SANITIZER_HEADERS} diff --git a/compiler-rt/lib/asan/tests/CMakeLists.txt b/compiler-rt/lib/asan/tests/CMakeLists.txt index 6d88c96a23bbc..982ba8feca711 100644 --- a/compiler-rt/lib/asan/tests/CMakeLists.txt +++ b/compiler-rt/lib/asan/tests/CMakeLists.txt @@ -120,15 +120,15 @@ append_list_if(COMPILER_RT_HAS_LIBLOG log ASAN_UNITTEST_NOINST_LIBS) # Main AddressSanitizer unit tests. add_custom_target(AsanUnitTests) -set_target_properties(AsanUnitTests PROPERTIES FOLDER "Compiler-RT/Tests") +set_target_properties(AsanUnitTests PROPERTIES FOLDER "compiler-rt/Tests") # AddressSanitizer unit tests with dynamic runtime (on platforms where it's # not the default). add_custom_target(AsanDynamicUnitTests) -set_target_properties(AsanDynamicUnitTests PROPERTIES FOLDER "Compiler-RT/Tests") +set_target_properties(AsanDynamicUnitTests PROPERTIES FOLDER "compiler-rt/Tests") # ASan benchmarks (not actively used now). add_custom_target(AsanBenchmarks) -set_target_properties(AsanBenchmarks PROPERTIES FOLDER "Compiler-RT/Tests") +set_target_properties(AsanBenchmarks PROPERTIES FOLDER "compiler-rt/Tests") set(ASAN_NOINST_TEST_SOURCES ${COMPILER_RT_GTEST_SOURCE} @@ -291,7 +291,7 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT ANDROID) add_library(${ASAN_TEST_RUNTIME} STATIC ${ASAN_TEST_RUNTIME_OBJECTS}) set_target_properties(${ASAN_TEST_RUNTIME} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - FOLDER "Compiler-RT/Tests/Runtime") + FOLDER "compiler-rt/Tests/Runtime") add_asan_tests(${arch} ${ASAN_TEST_RUNTIME} KIND "-inline") add_asan_tests(${arch} ${ASAN_TEST_RUNTIME} KIND "-calls" diff --git a/compiler-rt/lib/builtins/CMakeLists.txt b/compiler-rt/lib/builtins/CMakeLists.txt index 357fb2238a9d6..84a8956df18e8 100644 --- a/compiler-rt/lib/builtins/CMakeLists.txt +++ b/compiler-rt/lib/builtins/CMakeLists.txt @@ -1020,7 +1020,7 @@ set(ve_SOURCES set(m68k_SOURCES ${GENERIC_SOURCES}) add_custom_target(builtins) -set_target_properties(builtins PROPERTIES FOLDER "Compiler-RT/Metatargets") +set_target_properties(builtins PROPERTIES FOLDER "compiler-rt/Metatargets") option(COMPILER_RT_ENABLE_SOFTWARE_INT128 "Enable the int128 builtin routines for all targets." diff --git a/compiler-rt/lib/ctx_profile/tests/CMakeLists.txt b/compiler-rt/lib/ctx_profile/tests/CMakeLists.txt index 0954d5cd34487..36ff1e1e9c243 100644 --- a/compiler-rt/lib/ctx_profile/tests/CMakeLists.txt +++ b/compiler-rt/lib/ctx_profile/tests/CMakeLists.txt @@ -62,7 +62,7 @@ macro (add_ctx_profile_tests_for_arch arch) add_library(${CTX_PROFILE_TEST_RUNTIME} STATIC ${CTX_PROFILE_TEST_RUNTIME_OBJECTS}) set_target_properties(${CTX_PROFILE_TEST_RUNTIME} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - FOLDER "Compiler-RT Runtime tests") + FOLDER "compiler-rt Runtime tests") set(CTX_PROFILE_TEST_OBJECTS) generate_compiler_rt_tests(CTX_PROFILE_TEST_OBJECTS CtxProfileUnitTests "CtxProfile-${arch}-UnitTest" ${arch} @@ -75,7 +75,7 @@ macro (add_ctx_profile_tests_for_arch arch) endmacro() add_custom_target(CtxProfileUnitTests) -set_target_properties(CtxProfileUnitTests PROPERTIES FOLDER "Compiler-RT Tests") +set_target_properties(CtxProfileUnitTests PROPERTIES FOLDER "compiler-rt Tests") if(COMPILER_RT_CAN_EXECUTE_TESTS AND COMPILER_RT_DEFAULT_TARGET_ARCH IN_LIST CTX_PROFILE_SUPPORTED_ARCH) # CtxProfile unit tests are only run on the host machine. foreach(arch ${COMPILER_RT_DEFAULT_TARGET_ARCH}) diff --git a/compiler-rt/lib/fuzzer/tests/CMakeLists.txt b/compiler-rt/lib/fuzzer/tests/CMakeLists.txt index c5885ccccd207..fd0c155449aed 100644 --- a/compiler-rt/lib/fuzzer/tests/CMakeLists.txt +++ b/compiler-rt/lib/fuzzer/tests/CMakeLists.txt @@ -12,10 +12,10 @@ if (APPLE) endif() add_custom_target(FuzzerUnitTests) -set_target_properties(FuzzerUnitTests PROPERTIES FOLDER "Compiler-RT/Tests") +set_target_properties(FuzzerUnitTests PROPERTIES FOLDER "compiler-rt/Tests") add_custom_target(FuzzedDataProviderUnitTests) -set_target_properties(FuzzedDataProviderUnitTests PROPERTIES FOLDER "Compiler-RT/Tests") +set_target_properties(FuzzedDataProviderUnitTests PROPERTIES FOLDER "compiler-rt/Tests") set(LIBFUZZER_UNITTEST_LINK_FLAGS ${COMPILER_RT_UNITTEST_LINK_FLAGS}) list(APPEND LIBFUZZER_UNITTEST_LINK_FLAGS --driver-mode=g++) @@ -79,7 +79,7 @@ if(COMPILER_RT_DEFAULT_TARGET_ARCH IN_LIST FUZZER_SUPPORTED_ARCH) ${LIBFUZZER_TEST_RUNTIME_OBJECTS}) set_target_properties(${LIBFUZZER_TEST_RUNTIME} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - FOLDER "Compiler-RT/Tests/Runtime") + FOLDER "compiler-rt/Tests/Runtime") if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND COMPILER_RT_LIBCXX_PATH AND diff --git a/compiler-rt/lib/gwp_asan/tests/CMakeLists.txt b/compiler-rt/lib/gwp_asan/tests/CMakeLists.txt index 5de1af10eec36..0b52f4db767dc 100644 --- a/compiler-rt/lib/gwp_asan/tests/CMakeLists.txt +++ b/compiler-rt/lib/gwp_asan/tests/CMakeLists.txt @@ -37,7 +37,7 @@ set(GWP_ASAN_UNIT_TEST_HEADERS harness.h) add_custom_target(GwpAsanUnitTests) -set_target_properties(GwpAsanUnitTests PROPERTIES FOLDER "Compiler-RT/Tests") +set_target_properties(GwpAsanUnitTests PROPERTIES FOLDER "compiler-rt/Tests") set(GWP_ASAN_UNITTEST_LINK_FLAGS ${COMPILER_RT_UNITTEST_LINK_FLAGS} -ldl @@ -69,7 +69,7 @@ if(COMPILER_RT_DEFAULT_TARGET_ARCH IN_LIST GWP_ASAN_SUPPORTED_ARCH) set_target_properties(${GWP_ASAN_TEST_RUNTIME} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - FOLDER "Compiler-RT/Tests/Runtime") + FOLDER "compiler-rt/Tests/Runtime") set(GwpAsanTestObjects) generate_compiler_rt_tests(GwpAsanTestObjects diff --git a/compiler-rt/lib/interception/tests/CMakeLists.txt b/compiler-rt/lib/interception/tests/CMakeLists.txt index f348c35cbe22f..d09732a554611 100644 --- a/compiler-rt/lib/interception/tests/CMakeLists.txt +++ b/compiler-rt/lib/interception/tests/CMakeLists.txt @@ -81,7 +81,7 @@ macro(add_interceptor_lib library) add_library(${library} STATIC ${ARGN}) set_target_properties(${library} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - FOLDER "Compiler-RT/Tests/Runtime") + FOLDER "compiler-rt/Tests/Runtime") endmacro() function(get_interception_lib_for_arch arch lib) @@ -96,7 +96,7 @@ endfunction() # Interception unit tests testsuite. add_custom_target(InterceptionUnitTests) set_target_properties(InterceptionUnitTests PROPERTIES - FOLDER "Compiler-RT/Tests") + FOLDER "compiler-rt/Tests") # Adds interception tests for architecture. macro(add_interception_tests_for_arch arch) diff --git a/compiler-rt/lib/memprof/tests/CMakeLists.txt b/compiler-rt/lib/memprof/tests/CMakeLists.txt index 282e3701ee732..ce3540543976e 100644 --- a/compiler-rt/lib/memprof/tests/CMakeLists.txt +++ b/compiler-rt/lib/memprof/tests/CMakeLists.txt @@ -66,7 +66,7 @@ macro(add_memprof_tests_for_arch arch) add_library(${MEMPROF_TEST_RUNTIME} STATIC ${MEMPROF_TEST_RUNTIME_OBJECTS}) set_target_properties(${MEMPROF_TEST_RUNTIME} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - FOLDER "Compiler-RT/Tests/Runtime") + FOLDER "compiler-rt/Tests/Runtime") set(MEMPROF_TEST_OBJECTS) generate_compiler_rt_tests(MEMPROF_TEST_OBJECTS MemProfUnitTests "MemProf-${arch}-UnitTest" ${arch} @@ -80,7 +80,7 @@ endmacro() # MemProf unit tests testsuite. add_custom_target(MemProfUnitTests) -set_target_properties(MemProfUnitTests PROPERTIES FOLDER "Compiler-RT/Tests") +set_target_properties(MemProfUnitTests PROPERTIES FOLDER "compiler-rt/Tests") if(COMPILER_RT_CAN_EXECUTE_TESTS AND COMPILER_RT_DEFAULT_TARGET_ARCH IN_LIST MEMPROF_SUPPORTED_ARCH) # MemProf unit tests are only run on the host machine. foreach(arch ${COMPILER_RT_DEFAULT_TARGET_ARCH}) diff --git a/compiler-rt/lib/orc/tests/CMakeLists.txt b/compiler-rt/lib/orc/tests/CMakeLists.txt index 7039a32e6bc8b..3581fb049a408 100644 --- a/compiler-rt/lib/orc/tests/CMakeLists.txt +++ b/compiler-rt/lib/orc/tests/CMakeLists.txt @@ -4,11 +4,11 @@ include_directories(..) # Unit tests target. add_custom_target(OrcRTUnitTests) -set_target_properties(OrcRTUnitTests PROPERTIES FOLDER "Compiler-RT/Tests") +set_target_properties(OrcRTUnitTests PROPERTIES FOLDER "compiler-rt/Tests") # Testing tools target. add_custom_target(OrcRTTools) -set_target_properties(OrcRTTools PROPERTIES FOLDER "Compiler-RT/Tools") +set_target_properties(OrcRTTools PROPERTIES FOLDER "compiler-rt/Tools") set(ORC_UNITTEST_CFLAGS # FIXME: This should be set for all unit tests. @@ -22,7 +22,7 @@ function(add_orc_lib library) add_library(${library} STATIC ${ARGN}) set_target_properties(${library} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - FOLDER "Compiler-RT/Tests/Runtime") + FOLDER "compiler-rt/Tests/Runtime") endfunction() function(get_orc_lib_for_arch arch lib) diff --git a/compiler-rt/lib/rtsan/tests/CMakeLists.txt b/compiler-rt/lib/rtsan/tests/CMakeLists.txt index 0cf07b307d461..5bb7459dbdc8e 100644 --- a/compiler-rt/lib/rtsan/tests/CMakeLists.txt +++ b/compiler-rt/lib/rtsan/tests/CMakeLists.txt @@ -29,7 +29,7 @@ set(RTSAN_UNITTEST_HEADERS rtsan_test_utilities.h) add_custom_target(RtsanUnitTests) -set_target_properties(RtsanUnitTests PROPERTIES FOLDER "Compiler-RT Tests") +set_target_properties(RtsanUnitTests PROPERTIES FOLDER "compiler-rt Tests") set(RTSAN_UNITTEST_LINK_FLAGS ${COMPILER_RT_UNITTEST_LINK_FLAGS} @@ -111,7 +111,7 @@ foreach(arch ${RTSAN_TEST_ARCH}) add_library(${RTSAN_TEST_RUNTIME} STATIC ${RTSAN_TEST_RUNTIME_OBJECTS}) set_target_properties(${RTSAN_TEST_RUNTIME} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - FOLDER "Compiler-RT Runtime tests") + FOLDER "compiler-rt Runtime tests") set(RtsanNoInstTestObjects) generate_compiler_rt_tests(RtsanNoInstTestObjects diff --git a/compiler-rt/lib/sanitizer_common/tests/CMakeLists.txt b/compiler-rt/lib/sanitizer_common/tests/CMakeLists.txt index 55c7d665e639f..bf3e32c3f7786 100644 --- a/compiler-rt/lib/sanitizer_common/tests/CMakeLists.txt +++ b/compiler-rt/lib/sanitizer_common/tests/CMakeLists.txt @@ -147,7 +147,7 @@ macro(add_sanitizer_common_lib library) add_library(${library} STATIC ${ARGN}) set_target_properties(${library} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - FOLDER "Compiler-RT/Tests/Runtime") + FOLDER "compiler-rt/Tests/Runtime") endmacro() function(get_sanitizer_common_lib_for_arch arch lib) @@ -161,7 +161,7 @@ endfunction() # Sanitizer_common unit tests testsuite. add_custom_target(SanitizerUnitTests) -set_target_properties(SanitizerUnitTests PROPERTIES FOLDER "Compiler-RT/Tests") +set_target_properties(SanitizerUnitTests PROPERTIES FOLDER "compiler-rt/Tests") # Adds sanitizer tests for architecture. macro(add_sanitizer_tests_for_arch arch) diff --git a/compiler-rt/lib/sanitizer_ignorelists/CMakeLists.txt b/compiler-rt/lib/sanitizer_ignorelists/CMakeLists.txt index 0681e624f3119..42d4185e2ee4f 100644 --- a/compiler-rt/lib/sanitizer_ignorelists/CMakeLists.txt +++ b/compiler-rt/lib/sanitizer_ignorelists/CMakeLists.txt @@ -24,7 +24,7 @@ foreach(file_name ${SANITIZER_IGNORELIST_FILES}) endforeach() add_custom_target(sanitizer-ignorelist-files DEPENDS ${sanitizer_ignorelist_outputs}) -set_target_properties(sanitizer-ignorelist-files PROPERTIES FOLDER "Compiler-RT/Resources") +set_target_properties(sanitizer-ignorelist-files PROPERTIES FOLDER "compiler-rt/Resources") add_dependencies(sanitizer-ignorelists sanitizer-ignorelist-files) # Install in the Clang resource directory. No -stripped variant: the ignorelists @@ -40,6 +40,6 @@ add_custom_target(install-sanitizer-ignorelists -DCMAKE_INSTALL_COMPONENT=sanitizer-ignorelists -P "${CMAKE_BINARY_DIR}/cmake_install.cmake") set_target_properties(install-sanitizer-ignorelists PROPERTIES - FOLDER "Compiler-RT/Installation") + FOLDER "compiler-rt/Installation") add_dependencies(install-compiler-rt install-sanitizer-ignorelists) add_dependencies(install-compiler-rt-stripped install-sanitizer-ignorelists) diff --git a/compiler-rt/lib/scudo/standalone/tests/CMakeLists.txt b/compiler-rt/lib/scudo/standalone/tests/CMakeLists.txt index 68ffc16bce780..12617156a47a9 100644 --- a/compiler-rt/lib/scudo/standalone/tests/CMakeLists.txt +++ b/compiler-rt/lib/scudo/standalone/tests/CMakeLists.txt @@ -2,7 +2,7 @@ include_directories(..) add_custom_target(ScudoUnitTests) set_target_properties(ScudoUnitTests PROPERTIES - FOLDER "Compiler-RT Tests") + FOLDER "compiler-rt Tests") set(SCUDO_UNITTEST_CFLAGS ${COMPILER_RT_UNITTEST_CFLAGS} diff --git a/compiler-rt/lib/stats/CMakeLists.txt b/compiler-rt/lib/stats/CMakeLists.txt index 6df221a9a7716..c8f2dc8ae0cac 100644 --- a/compiler-rt/lib/stats/CMakeLists.txt +++ b/compiler-rt/lib/stats/CMakeLists.txt @@ -4,7 +4,7 @@ set(STATS_HEADERS include_directories(..) add_custom_target(stats) -set_target_properties(stats PROPERTIES FOLDER "Compiler-RT/Metatargets") +set_target_properties(stats PROPERTIES FOLDER "compiler-rt/Metatargets") if(APPLE) set(STATS_LIB_FLAVOR SHARED) diff --git a/compiler-rt/lib/tsan/CMakeLists.txt b/compiler-rt/lib/tsan/CMakeLists.txt index 3319855521bd5..c2a2ccf0ac9ef 100644 --- a/compiler-rt/lib/tsan/CMakeLists.txt +++ b/compiler-rt/lib/tsan/CMakeLists.txt @@ -36,7 +36,7 @@ if(COMPILER_RT_LIBCXX_PATH AND endforeach() add_custom_target(libcxx_tsan DEPENDS ${libcxx_tsan_deps}) - set_target_properties(libcxx_tsan PROPERTIES FOLDER "Compiler-RT/Metatargets") + set_target_properties(libcxx_tsan PROPERTIES FOLDER "compiler-rt/Metatargets") endif() if(COMPILER_RT_INCLUDE_TESTS) diff --git a/compiler-rt/lib/tsan/dd/CMakeLists.txt b/compiler-rt/lib/tsan/dd/CMakeLists.txt index 1864d7a49fa60..7d93c3d6c1926 100644 --- a/compiler-rt/lib/tsan/dd/CMakeLists.txt +++ b/compiler-rt/lib/tsan/dd/CMakeLists.txt @@ -20,7 +20,7 @@ append_list_if(COMPILER_RT_HAS_LIBRT rt DD_LINKLIBS) append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread DD_LINKLIBS) add_custom_target(dd) -set_target_properties(dd PROPERTIES FOLDER "Compiler-RT/Metatargets") +set_target_properties(dd PROPERTIES FOLDER "compiler-rt/Metatargets") # Deadlock detector is currently supported on 64-bit Linux only. if(CAN_TARGET_x86_64 AND UNIX AND NOT APPLE AND NOT ANDROID) diff --git a/compiler-rt/lib/tsan/rtl/CMakeLists.txt b/compiler-rt/lib/tsan/rtl/CMakeLists.txt index 6f093500c8f61..f93797754477a 100644 --- a/compiler-rt/lib/tsan/rtl/CMakeLists.txt +++ b/compiler-rt/lib/tsan/rtl/CMakeLists.txt @@ -168,7 +168,7 @@ if(APPLE) WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../go COMMENT "Checking TSan Go runtime..." VERBATIM) - set_target_properties(GotsanRuntimeCheck PROPERTIES FOLDER "Compiler-RT/Misc") + set_target_properties(GotsanRuntimeCheck PROPERTIES FOLDER "compiler-rt/Misc") else() foreach(arch ${TSAN_SUPPORTED_ARCH}) if(arch STREQUAL "x86_64") diff --git a/compiler-rt/lib/tsan/tests/CMakeLists.txt b/compiler-rt/lib/tsan/tests/CMakeLists.txt index 1bc08bbf7450c..7e6aa0a8ef408 100644 --- a/compiler-rt/lib/tsan/tests/CMakeLists.txt +++ b/compiler-rt/lib/tsan/tests/CMakeLists.txt @@ -2,7 +2,7 @@ include_directories(../rtl) add_custom_target(TsanUnitTests) set_target_properties(TsanUnitTests PROPERTIES - FOLDER "Compiler-RT Tests") + FOLDER "compiler-rt Tests") set(TSAN_UNITTEST_CFLAGS ${COMPILER_RT_UNITTEST_CFLAGS} diff --git a/compiler-rt/lib/xray/tests/CMakeLists.txt b/compiler-rt/lib/xray/tests/CMakeLists.txt index 6b9d9ced9a1df..1e3aa2535d4da 100644 --- a/compiler-rt/lib/xray/tests/CMakeLists.txt +++ b/compiler-rt/lib/xray/tests/CMakeLists.txt @@ -1,7 +1,7 @@ include_directories(..) add_custom_target(XRayUnitTests) -set_target_properties(XRayUnitTests PROPERTIES FOLDER "Compiler-RT/Tests") +set_target_properties(XRayUnitTests PROPERTIES FOLDER "compiler-rt/Tests") # Sanity check XRAY_ALL_SOURCE_FILES_ABS_PATHS list(LENGTH XRAY_ALL_SOURCE_FILES_ABS_PATHS XASFAP_LENGTH) @@ -34,7 +34,7 @@ function(add_xray_lib library) add_library(${library} STATIC ${ARGN}) set_target_properties(${library} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - FOLDER "Compiler-RT/Tests/Runtime") + FOLDER "compiler-rt/Tests/Runtime") endfunction() function(get_xray_lib_for_arch arch lib) diff --git a/compiler-rt/test/CMakeLists.txt b/compiler-rt/test/CMakeLists.txt index 3fab82518e75f..fa2847c1b7dd0 100644 --- a/compiler-rt/test/CMakeLists.txt +++ b/compiler-rt/test/CMakeLists.txt @@ -176,7 +176,7 @@ endif() # introduce a rule to run to run all of them. get_property(LLVM_COMPILER_RT_LIT_DEPENDS GLOBAL PROPERTY LLVM_COMPILER_RT_LIT_DEPENDS) add_custom_target(compiler-rt-test-depends) -set_target_properties(compiler-rt-test-depends PROPERTIES FOLDER "Compiler-RT/Tests") +set_target_properties(compiler-rt-test-depends PROPERTIES FOLDER "compiler-rt/Tests") if(LLVM_COMPILER_RT_LIT_DEPENDS) add_dependencies(compiler-rt-test-depends ${LLVM_COMPILER_RT_LIT_DEPENDS}) endif() diff --git a/compiler-rt/test/ctx_profile/CMakeLists.txt b/compiler-rt/test/ctx_profile/CMakeLists.txt index fc3b3f3ec431f..4abd49a19e0a9 100644 --- a/compiler-rt/test/ctx_profile/CMakeLists.txt +++ b/compiler-rt/test/ctx_profile/CMakeLists.txt @@ -38,4 +38,4 @@ endforeach() add_lit_testsuite(check-ctx_profile "Running the Contextual Profiler tests" ${CTX_PROFILE_TESTSUITES} DEPENDS ${CTX_PROFILE_TEST_DEPS}) -set_target_properties(check-ctx_profile PROPERTIES FOLDER "Compiler-RT Misc") +set_target_properties(check-ctx_profile PROPERTIES FOLDER "compiler-rt Misc") diff --git a/compiler-rt/test/rtsan/CMakeLists.txt b/compiler-rt/test/rtsan/CMakeLists.txt index 59fc5a29703fe..684fd6002042b 100644 --- a/compiler-rt/test/rtsan/CMakeLists.txt +++ b/compiler-rt/test/rtsan/CMakeLists.txt @@ -40,4 +40,4 @@ endif() add_lit_testsuite(check-rtsan "Running the Rtsan tests" ${RTSAN_TESTSUITES} DEPENDS ${RTSAN_TEST_DEPS}) -set_target_properties(check-rtsan PROPERTIES FOLDER "Compiler-RT Misc") +set_target_properties(check-rtsan PROPERTIES FOLDER "compiler-rt Misc") diff --git a/compiler-rt/test/scudo/standalone/CMakeLists.txt b/compiler-rt/test/scudo/standalone/CMakeLists.txt index 3e6c8ab234b7e..0108bb898076f 100644 --- a/compiler-rt/test/scudo/standalone/CMakeLists.txt +++ b/compiler-rt/test/scudo/standalone/CMakeLists.txt @@ -16,4 +16,4 @@ add_lit_testsuite(check-scudo_standalone DEPENDS ${SCUDO_STANDALONE_TEST_DEPS}) set_target_properties(check-scudo_standalone - PROPERTIES FOLDER "Compiler-RT Tests") + PROPERTIES FOLDER "compiler-rt Tests") diff --git a/compiler-rt/test/tsan/CMakeLists.txt b/compiler-rt/test/tsan/CMakeLists.txt index 4cd88507a2baf..fa924e0942968 100644 --- a/compiler-rt/test/tsan/CMakeLists.txt +++ b/compiler-rt/test/tsan/CMakeLists.txt @@ -132,7 +132,7 @@ endif() add_lit_testsuite(check-tsan "Running ThreadSanitizer tests" ${TSAN_TESTSUITES} DEPENDS ${TSAN_TEST_DEPS}) -set_target_properties(check-tsan PROPERTIES FOLDER "Compiler-RT Tests") +set_target_properties(check-tsan PROPERTIES FOLDER "compiler-rt Tests") if(COMPILER_RT_TSAN_HAS_STATIC_RUNTIME) add_lit_testsuite(check-tsan-dynamic "Running the ThreadSanitizer tests with dynamic runtime" diff --git a/compiler-rt/test/tysan/CMakeLists.txt b/compiler-rt/test/tysan/CMakeLists.txt index ce0afa8769f03..c618c71e326ef 100644 --- a/compiler-rt/test/tysan/CMakeLists.txt +++ b/compiler-rt/test/tysan/CMakeLists.txt @@ -27,4 +27,4 @@ add_lit_testsuite(check-tysan "Running the TypeSanitizer tests" ${TYSAN_TESTSUITES} DEPENDS ${TYSAN_TEST_DEPS} ) -set_target_properties(check-tysan PROPERTIES FOLDER "Compiler-RT Misc") +set_target_properties(check-tysan PROPERTIES FOLDER "compiler-rt Misc") diff --git a/llvm/runtimes/CMakeLists.txt b/llvm/runtimes/CMakeLists.txt index f5477c3d6ae8a..c2607393d1bb9 100644 --- a/llvm/runtimes/CMakeLists.txt +++ b/llvm/runtimes/CMakeLists.txt @@ -159,7 +159,7 @@ function(builtin_default_target compiler_rt_path) SANITIZER USE_TOOLCHAIN TARGET_TRIPLE ${LLVM_TARGET_TRIPLE} - FOLDER "Compiler-RT" + FOLDER "compiler-rt" ${EXTRA_ARGS}) endfunction() @@ -183,7 +183,7 @@ function(builtin_register_target compiler_rt_path name) ${COMMON_CMAKE_ARGS} ${${name}_extra_args} USE_TOOLCHAIN - FOLDER "Compiler-RT" + FOLDER "compiler-rt" ${EXTRA_ARGS} ${ARG_EXTRA_ARGS}) endfunction() @@ -214,7 +214,7 @@ if(compiler_rt_path) add_custom_target(install-builtins-stripped) set_target_properties( builtins install-builtins install-builtins-stripped - PROPERTIES FOLDER "Compiler-RT" + PROPERTIES FOLDER "compiler-rt" ) endif() @@ -715,7 +715,7 @@ if(build_runtimes) add_custom_target(check-builtins) set_target_properties( check-builtins - PROPERTIES FOLDER "Compiler-RT" + PROPERTIES FOLDER "compiler-rt" ) endif() if(LLVM_RUNTIME_DISTRIBUTION_COMPONENTS) From e310250eb80f282efe02dee4c94454a784c6886c Mon Sep 17 00:00:00 2001 From: Tom Stellard Date: Thu, 6 Aug 2026 14:57:58 -0700 Subject: [PATCH 014/789] workflows/release-documentation: Rework workflow to make it testable (#214304) This includes several separate changes for the workflow, which were necessary to get the testing to pass: * Merged release-man-pages-validate-input into the release-documentation job. * Split the release note uploading into a separate job. * Moved the environment declaration to the upload-man-pages job. * Stopped forcing clang as the compiler in build-docs.sh script. This was causing the runtimes build to fail, because the default Ubuntu debian packages for clang where not providing all the necessary CMake files. It seems that when you use clang as the compiler, the runtimes try to use the cmake files installed along with it. --- .github/workflows/release-documentation.yml | 123 +++++++++----------- llvm/utils/release/build-docs.sh | 6 - 2 files changed, 57 insertions(+), 72 deletions(-) diff --git a/.github/workflows/release-documentation.yml b/.github/workflows/release-documentation.yml index d0b6a9994edb5..c19148017cfec 100644 --- a/.github/workflows/release-documentation.yml +++ b/.github/workflows/release-documentation.yml @@ -38,76 +38,43 @@ on: LLVM_TOKEN_GENERATOR_PRIVATE_KEY: description: "Private key for our GitHub App we use for generating access tokens." required: true + # Run on pull_requests for testing purposes. + pull_request: + paths: + - '.github/workflows/release-documentation.yml' + - 'llvm/utils/release/build-docs.sh' + types: + - opened + - synchronize + - reopened + # When a PR is closed, we still start this workflow, but then skip + # all the jobs, which makes it effectively a no-op. The reason to + # do this is that it allows us to take advantage of concurrency groups + # to cancel in progress CI jobs whenever the PR is closed. + - closed + +concurrency: + group: release-documentation-${{ inputs.release-version || github.event.pull_request.number }} + cancel-in-progress: true jobs: - # This job checks permissions and validates inputs to prevent potential - # malicious actions. Since the release-documentation job has contents: write - # permissions we need to be extra careful about who can run the job and what - # inputs can be provided. - release-man-pages-validate-input: - name: Release Man Pages Validate Input - runs-on: ubuntu-24.04 - environment: - name: release - deployment: false - permissions: - contents: read - steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - with: - persist-credentials: false - sparse-checkout: | - .github/workflows/ - - - name: Check Permissions - uses: ./.github/workflows/require-team-membership - with: - team-slug: llvm-release-managers - LLVM_TOKEN_GENERATOR_CLIENT_ID: ${{ secrets.LLVM_TOKEN_GENERATOR_CLIENT_ID }} - LLVM_TOKEN_GENERATOR_PRIVATE_KEY: ${{ secrets.LLVM_TOKEN_GENERATOR_PRIVATE_KEY }} - - - name: Validate Input - uses: ./.github/workflows/validate-release-version - with: - release-version: ${{ inputs.release-version }} - release-documentation: name: Build and Upload Release Documentation and Man Pages runs-on: ubuntu-24.04 - needs: - - release-man-pages-validate-input + if: >- + github.repository_owner == 'llvm' && + github.event.action != 'closed' outputs: man-page-digest: ${{ steps.man-page-digest.outputs.man-page-digest }} man-page-artifact-id: ${{ steps.man-page-artifact-upload.outputs.artifact-id }} - - man-page-release-version: ${{ steps.vars.outputs.man-page-release-version }} - man-page-tarball-name: ${{ steps.vars.outputs.man-page-tarball-name }} - man-page-upload: ${{ steps.vars.outputs.man-page-upload }} - man-page-attestation-name: ${{ steps.vars.outputs.man-page-attestation-name }} - env: - upload: ${{ inputs.upload && !contains(inputs.release-version, 'rc') }} steps: - - name: Collect Variables - id: vars - env: - INPUTS_RELEASE_VERSION: ${{ inputs.release-version }} - UPLOAD_MAN_PAGES: ${{ inputs.upload }} - shell: bash - run: | - { - echo "man-page-release-version=$INPUTS_RELEASE_VERSION" - echo "man-page-tarball-name=llvm_man_pages-$INPUTS_RELEASE_VERSION.tar.xz" - echo "man-page-ref=llvmorg-$INPUTS_RELEASE_VERSION" - echo "man-page-upload=$UPLOAD_MAN_PAGES" - echo "man-page-attestation-name=$RUNNER_OS-$RUNNER_ARCH-release-man-page-attestation" - } >> "$GITHUB_OUTPUT" - - name: Checkout LLVM uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: persist-credentials: false - name: Validate Input + if: inputs.release-version uses: ./.github/workflows/validate-release-version with: release-version: ${{ inputs.release-version }} @@ -129,25 +96,30 @@ jobs: pip3 install --require-hashes --user -r ./llvm/docs/requirements.txt - name: Build Documentation + id: build env: GITHUB_TOKEN: ${{ github.token }} INPUTS_RELEASE_VERSION: ${{ inputs.release-version }} run: | - ./llvm/utils/release/build-docs.sh -release "$INPUTS_RELEASE_VERSION" -no-doxygen + ./llvm/utils/release/build-docs.sh \ + $(test -n "$INPUTS_RELEASE_VERSION" && echo -release "$INPUTS_RELEASE_VERSION" || echo -srcdir llvm) -no-doxygen + echo "man-page-tarball-name=$(basename $(find . -iname 'llvm_man_pages-*.tar.xz'))" >> "$GITHUB_OUTPUT" + - name: Generate sha256 digest for man page tarball id: man-page-digest shell: bash env: - TARBALL_NAME: ${{ steps.vars.outputs.man-page-tarball-name }} + TARBALL_NAME: ${{ steps.build.outputs.man-page-tarball-name }} run: | - echo "man-page-digest=$(cat "$TARBALL_NAME" | sha256sum | cut -d ' ' -f 1)" >> $GITHUB_OUTPUT + echo "man-page-digest=$(cat "$TARBALL_NAME" | sha256sum | cut -d ' ' -f 1)" >> "$GITHUB_OUTPUT" - id: man-page-artifact-upload uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: + name: man-pages path: | - ${{ steps.vars.outputs.man-page-tarball-name }} + ${{ steps.build.outputs.man-page-tarball-name }} - name: Create Release Notes Artifact uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 @@ -155,8 +127,23 @@ jobs: name: release-notes path: docs-build/html-export/ + + upload-release-notes: + name: "Upload Release Notes" + runs-on: ubuntu-24.04 + environment: + deployment: false + name: release + needs: + - release-documentation + if: >- + github.event_name != 'pull_request' && + inputs.upload && + !contains(inputs.release-version, 'rc') + permissions: + contents: read + steps: - name: Clone www-releases - if: env.upload uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: repository: ${{ github.repository_owner }}/www-releases @@ -165,15 +152,19 @@ jobs: path: www-releases persist-credentials: false + - name: Download Release Notes Artifact + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + id: download-artifact + with: + name: release-notes + path: ${{ github.workspace }}/www-releases/${{ inputs.release-version }} + - name: Upload Release Notes - if: env.upload env: PUSH_TOKEN: ${{ secrets.LLVMBOT_WWW_RELEASES_PUSH }} GH_TOKEN: ${{ secrets.WWW_RELEASES_TOKEN }} INPUTS_RELEASE_VERSION: ${{ inputs.release-version }} run: | - mkdir -p www-releases/$INPUTS_RELEASE_VERSION - mv ./docs-build/html-export/* www-releases/$INPUTS_RELEASE_VERSION cd www-releases git checkout -b $INPUTS_RELEASE_VERSION git add $INPUTS_RELEASE_VERSION @@ -203,10 +194,10 @@ jobs: id: man-page-artifact-upload uses: $/.github/workflows/upload-release-artifact with: - release-version: ${{ needs.release-documentation.outputs.man-page-release-version }} + release-version: ${{ inputs.release-version }} artifact-id: ${{ needs.release-documentation.outputs.man-page-artifact-id }} - attestation-name: ${{ needs.release-documentation.outputs.man-page-attestation-name }} + attestation-name: ${{ runner.os }}-${{ runner.arch }}-release-man-page-attestation digest: ${{ needs.release-documentation.outputs.man-page-digest }} - upload: ${{ needs.release-documentation.outputs.man-page-upload }} + upload: ${{ inputs.upload }} LLVM_TOKEN_GENERATOR_CLIENT_ID: ${{ secrets.LLVM_TOKEN_GENERATOR_CLIENT_ID }} LLVM_TOKEN_GENERATOR_PRIVATE_KEY: ${{ secrets.LLVM_TOKEN_GENERATOR_PRIVATE_KEY }} diff --git a/llvm/utils/release/build-docs.sh b/llvm/utils/release/build-docs.sh index 648c829a62618..3c80af1317d11 100755 --- a/llvm/utils/release/build-docs.sh +++ b/llvm/utils/release/build-docs.sh @@ -141,12 +141,6 @@ else echo "Doxygen: disabled" fi -# This is just to ensure we're using the right compiler -# When running this locally, the script otherwise might -# prefer GCC. -export CC=clang -export CXX=clang++ - cmake -G Ninja $srcdir -B $builddir \ -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra;lld;polly;flang${extra_man_page_projects}" \ -DCMAKE_BUILD_TYPE=Release \ From c736a3eb6cfa6bbbbac7f17b7afe0df88eddaec9 Mon Sep 17 00:00:00 2001 From: Kaitlin Peng Date: Thu, 6 Aug 2026 15:12:34 -0700 Subject: [PATCH 015/789] [HLSL] Fix crash when comparing two half vectors (#214332) Fixes #213814. Comparing two half vectors in default mode crashed Clang with a `convertHalfVecBinOp` assertion because the function expects the result to be a half/short vector while HLSL returns an int vector. This PR fixes the bug by skipping the conversion function when the result type is not a half or short vector. This lets it fall through to the default `BinaryOperator::Create` path, which builds the comparison correctly with the int vector result type. The PR also adds regression tests covering the six comparison operators. Assisted-by: Claude Opus 4.8 --- clang/lib/Sema/SemaExpr.cpp | 16 +++-- .../Operators/half-vector-comparisons.hlsl | 70 +++++++++++++++++++ .../Operators/half-vector-comparisons.hlsl | 63 +++++++++++++++++ 3 files changed, 145 insertions(+), 4 deletions(-) create mode 100644 clang/test/CodeGenHLSL/Operators/half-vector-comparisons.hlsl create mode 100644 clang/test/SemaHLSL/Operators/half-vector-comparisons.hlsl diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 901692b59222b..5f4af9debe91a 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -15504,10 +15504,17 @@ static ExprResult convertHalfVecBinOp(Sema &S, ExprResult LHS, ExprResult RHS, /// Returns true if conversion between vectors of halfs and vectors of floats /// is needed. static bool needsConversionOfHalfVec(bool OpRequiresConversion, ASTContext &Ctx, - Expr *E0, Expr *E1 = nullptr) { + QualType ResultTy, Expr *E0, + Expr *E1 = nullptr) { if (!OpRequiresConversion || Ctx.getLangOpts().NativeHalfType) return false; + // The conversion truncates the result to a half/short vector, so it shouldn't + // apply when the result is not that type (e.g. HLSL comparisons). + if (ResultTy->isVectorType() && !isVector(ResultTy, Ctx.HalfTy) && + !isVector(ResultTy, Ctx.ShortTy)) + return false; + auto HasVectorOfHalfType = [&Ctx](Expr *E) { QualType Ty = E->IgnoreImplicit()->getType(); @@ -15752,8 +15759,8 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, (Opc == BO_Comma || 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()); + ConvertHalfVec = needsConversionOfHalfVec(ConvertHalfVec, Context, ResultTy, + LHS.get(), RHS.get()); // Check for array bounds violations for both sides of the BinaryOperator CheckArrayAccess(LHS.get()); @@ -16306,7 +16313,8 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, // float vector and truncating the result back to a half vector. For now, // we do this only when HalfArgsAndReturns is set (that is, when the // target is arm or arm64). - ConvertHalfVec = needsConversionOfHalfVec(true, Context, Input.get()); + ConvertHalfVec = needsConversionOfHalfVec( + true, Context, Input.get()->getType(), Input.get()); // If the operand is a half vector, promote it to a float vector. if (ConvertHalfVec) diff --git a/clang/test/CodeGenHLSL/Operators/half-vector-comparisons.hlsl b/clang/test/CodeGenHLSL/Operators/half-vector-comparisons.hlsl new file mode 100644 index 0000000000000..c289f372f4542 --- /dev/null +++ b/clang/test/CodeGenHLSL/Operators/half-vector-comparisons.hlsl @@ -0,0 +1,70 @@ +// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm -disable-llvm-passes -o - | FileCheck %s --check-prefixes=CHECK,NATIVE_HALF +// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -emit-llvm -disable-llvm-passes -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF + +// Regression test for issue llvm/llvm-project#213814 + +// CHECK-LABEL: test_lt +// NATIVE_HALF: [[CMP:%.*]] = fcmp {{.*}} olt <4 x half> +// NATIVE_HALF-NEXT: [[SEXT:%.*]] = sext <4 x i1> [[CMP]] to <4 x i16> +// NATIVE_HALF-NEXT: [[RET:%.*]] = sext <4 x i16> [[SEXT]] to <4 x i32> +// NO_HALF: [[CMP:%.*]] = fcmp {{.*}} olt <4 x float> +// NO_HALF-NEXT: [[RET:%.*]] = sext <4 x i1> [[CMP]] to <4 x i32> +// CHECK-NEXT: ret <4 x i32> [[RET]] +int4 test_lt(half4 a, half4 b) { + return a < b; +} + +// CHECK-LABEL: test_le +// NATIVE_HALF: [[CMP:%.*]] = fcmp {{.*}} ole <4 x half> +// NATIVE_HALF-NEXT: [[SEXT:%.*]] = sext <4 x i1> [[CMP]] to <4 x i16> +// NATIVE_HALF-NEXT: [[RET:%.*]] = sext <4 x i16> [[SEXT]] to <4 x i32> +// NO_HALF: [[CMP:%.*]] = fcmp {{.*}} ole <4 x float> +// NO_HALF-NEXT: [[RET:%.*]] = sext <4 x i1> [[CMP]] to <4 x i32> +// CHECK-NEXT: ret <4 x i32> [[RET]] +int4 test_le(half4 a, half4 b) { + return a <= b; +} + +// CHECK-LABEL: test_gt +// NATIVE_HALF: [[CMP:%.*]] = fcmp {{.*}} ogt <4 x half> +// NATIVE_HALF-NEXT: [[SEXT:%.*]] = sext <4 x i1> [[CMP]] to <4 x i16> +// NATIVE_HALF-NEXT: [[RET:%.*]] = sext <4 x i16> [[SEXT]] to <4 x i32> +// NO_HALF: [[CMP:%.*]] = fcmp {{.*}} ogt <4 x float> +// NO_HALF-NEXT: [[RET:%.*]] = sext <4 x i1> [[CMP]] to <4 x i32> +// CHECK-NEXT: ret <4 x i32> [[RET]] +int4 test_gt(half4 a, half4 b) { + return a > b; +} + +// CHECK-LABEL: test_ge +// NATIVE_HALF: [[CMP:%.*]] = fcmp {{.*}} oge <4 x half> +// NATIVE_HALF-NEXT: [[SEXT:%.*]] = sext <4 x i1> [[CMP]] to <4 x i16> +// NATIVE_HALF-NEXT: [[RET:%.*]] = sext <4 x i16> [[SEXT]] to <4 x i32> +// NO_HALF: [[CMP:%.*]] = fcmp {{.*}} oge <4 x float> +// NO_HALF-NEXT: [[RET:%.*]] = sext <4 x i1> [[CMP]] to <4 x i32> +// CHECK-NEXT: ret <4 x i32> [[RET]] +int4 test_ge(half4 a, half4 b) { + return a >= b; +} + +// CHECK-LABEL: test_eq +// NATIVE_HALF: [[CMP:%.*]] = fcmp {{.*}} oeq <4 x half> +// NATIVE_HALF-NEXT: [[SEXT:%.*]] = sext <4 x i1> [[CMP]] to <4 x i16> +// NATIVE_HALF-NEXT: [[RET:%.*]] = sext <4 x i16> [[SEXT]] to <4 x i32> +// NO_HALF: [[CMP:%.*]] = fcmp {{.*}} oeq <4 x float> +// NO_HALF-NEXT: [[RET:%.*]] = sext <4 x i1> [[CMP]] to <4 x i32> +// CHECK-NEXT: ret <4 x i32> [[RET]] +int4 test_eq(half4 a, half4 b) { + return a == b; +} + +// CHECK-LABEL: test_ne +// NATIVE_HALF: [[CMP:%.*]] = fcmp {{.*}} une <4 x half> +// NATIVE_HALF-NEXT: [[SEXT:%.*]] = sext <4 x i1> [[CMP]] to <4 x i16> +// NATIVE_HALF-NEXT: [[RET:%.*]] = sext <4 x i16> [[SEXT]] to <4 x i32> +// NO_HALF: [[CMP:%.*]] = fcmp {{.*}} une <4 x float> +// NO_HALF-NEXT: [[RET:%.*]] = sext <4 x i1> [[CMP]] to <4 x i32> +// CHECK-NEXT: ret <4 x i32> [[RET]] +int4 test_ne(half4 a, half4 b) { + return a != b; +} diff --git a/clang/test/SemaHLSL/Operators/half-vector-comparisons.hlsl b/clang/test/SemaHLSL/Operators/half-vector-comparisons.hlsl new file mode 100644 index 0000000000000..f3be50ef6fc62 --- /dev/null +++ b/clang/test/SemaHLSL/Operators/half-vector-comparisons.hlsl @@ -0,0 +1,63 @@ +// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -ast-dump -ast-dump-filter=test | FileCheck %s + +// Regression test for issue llvm/llvm-project#213814 + +// CHECK-LABEL: FunctionDecl {{.*}} test_lt 'int4 (half4, half4)' +// CHECK: BinaryOperator {{.*}} 'vector' '<' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'half4':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'a' 'half4':'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'half4':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'b' 'half4':'vector' +int4 test_lt(half4 a, half4 b) { + return a < b; +} + +// CHECK-LABEL: FunctionDecl {{.*}} test_le 'int4 (half4, half4)' +// CHECK: BinaryOperator {{.*}} 'vector' '<=' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'half4':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'a' 'half4':'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'half4':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'b' 'half4':'vector' +int4 test_le(half4 a, half4 b) { + return a <= b; +} + +// CHECK-LABEL: FunctionDecl {{.*}} test_gt 'int4 (half4, half4)' +// CHECK: BinaryOperator {{.*}} 'vector' '>' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'half4':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'a' 'half4':'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'half4':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'b' 'half4':'vector' +int4 test_gt(half4 a, half4 b) { + return a > b; +} + +// CHECK-LABEL: FunctionDecl {{.*}} test_ge 'int4 (half4, half4)' +// CHECK: BinaryOperator {{.*}} 'vector' '>=' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'half4':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'a' 'half4':'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'half4':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'b' 'half4':'vector' +int4 test_ge(half4 a, half4 b) { + return a >= b; +} + +// CHECK-LABEL: FunctionDecl {{.*}} test_eq 'int4 (half4, half4)' +// CHECK: BinaryOperator {{.*}} 'vector' '==' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'half4':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'a' 'half4':'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'half4':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'b' 'half4':'vector' +int4 test_eq(half4 a, half4 b) { + return a == b; +} + +// CHECK-LABEL: FunctionDecl {{.*}} test_ne 'int4 (half4, half4)' +// CHECK: BinaryOperator {{.*}} 'vector' '!=' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'half4':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'a' 'half4':'vector' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'half4':'vector' +// CHECK-NEXT: DeclRefExpr {{.*}} 'b' 'half4':'vector' +int4 test_ne(half4 a, half4 b) { + return a != b; +} From fdd9151239f6bef182ce5b1a0b32c57318636bbb Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Thu, 6 Aug 2026 15:23:41 -0700 Subject: [PATCH 016/789] [clang][docs] Fix CIR docs post-processing script to use index.md (#214567) This file was renamed in cf293b06, but I seem to have missed this reference. I'm not sure if I properly validated the CIR docs build the last time I did this, because I ran into this when attempting to build `docs-clang-html` with CIR enabled. LLM-assisted --- clang/docs/CIR/_raw/PostProcessCIRDocs.py | 25 ++++++++--------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/clang/docs/CIR/_raw/PostProcessCIRDocs.py b/clang/docs/CIR/_raw/PostProcessCIRDocs.py index 9140c828eda6d..ca49e00773b96 100644 --- a/clang/docs/CIR/_raw/PostProcessCIRDocs.py +++ b/clang/docs/CIR/_raw/PostProcessCIRDocs.py @@ -4,15 +4,14 @@ import os import sys - docs_src_dir = sys.argv[1] docs_bin_dir = sys.argv[2] DIALECT_DOC_PATH = os.path.join(docs_bin_dir, "CIR", "_raw", "CIRDialect.md") DIALECT_DOC_OUTPUT_PATH = os.path.join(docs_bin_dir, "CIR", "CIRDialect.md") -INDEX_PATH = os.path.join(docs_src_dir, "CIR", "index.rst") -INDEX_OUTPUT_PATH = os.path.join(docs_bin_dir, "CIR", "index.rst") +INDEX_PATH = os.path.join(docs_src_dir, "CIR", "index.md") +INDEX_OUTPUT_PATH = os.path.join(docs_bin_dir, "CIR", "index.md") cir_docs_toctree = [] @@ -37,23 +36,17 @@ fp.write(dialect_doc) # =============================================== -# Add toctree to index.rst if CIR docs are generated +# Add toctree to index.md if CIR docs are generated # =============================================== if len(cir_docs_toctree) > 0: with open(INDEX_PATH, encoding="utf-8") as fp: index_content = fp.read() - index_content += """ - -CIR Dialect Reference -========================== - -.. toctree:: - :numbered: - :maxdepth: 1 - - {} -""".format( - "\n ".join(cir_docs_toctree) + index_content += ( + "\n\n" + "## CIR Dialect Reference\n\n" + "```{toctree}\n" + ":numbered: true\n" + ":maxdepth: 1\n\n" + "\n".join(cir_docs_toctree) + "\n```\n" ) with open(INDEX_OUTPUT_PATH, "w", encoding="utf-8") as fp: fp.write(index_content) From db4ef1160ebd5e8fc1a222f16e6688992ce1c596 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 6 Aug 2026 17:25:54 -0500 Subject: [PATCH 017/789] [WebAssembly] Default export tables with `--cooperative-threading` (#208263) This commit is a change to `wasm-ld`'s behavior when the `--cooperative-threading` flag is passed to the linker. The change here is to by default work as if `--export-table` was passed as well. This is required conventionally on this target because the table is where function pointers are read from in the component model `thread.new-indirect` intrinsic. If the table is not exported then there's no way to turn the core module into a component so it's effectively required. This behavior only applies to when the table isn't otherwise imported, for example in shared libraries. The other motivation behind this change is that it'll avoid the need to manually specify `-Wl,--export-table` when compiling for the `wasm32-wasip3` target. This additionally avoids the need for the Clang driver to figure out if flags like `--import-table` were otherwise passed. Basically it seemed best to put this in `wasm-ld` itself to avoid as little juggling of pieces as necessary. cc WebAssembly/wasi-libc#808 --- lld/test/wasm/cooperative-threading.s | 34 ++++++++++++++++++++++++++- lld/wasm/Driver.cpp | 8 +++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/lld/test/wasm/cooperative-threading.s b/lld/test/wasm/cooperative-threading.s index 8b0f7eb1c256f..a4afb01dc2264 100644 --- a/lld/test/wasm/cooperative-threading.s +++ b/lld/test/wasm/cooperative-threading.s @@ -2,7 +2,7 @@ # thread-context globals (__init_stack_pointer, __init_tls_base, etc.) and # works without --shared-memory and atomics. -# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s +# RUN: llvm-mc -mattr=+call-indirect-overlong -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s # RUN: wasm-ld --cooperative-threading -no-gc-sections -o %t.wasm %t.o # RUN: obj2yaml %t.wasm | FileCheck %s # RUN: llvm-objdump -d --no-print-imm-hex --no-show-raw-insn %t.wasm | FileCheck %s --check-prefix=DIS @@ -11,12 +11,22 @@ # RUN: not wasm-ld --cooperative-threading --shared-memory %t.o -o %t2.wasm 2>&1 | FileCheck %s --check-prefix=INCOMPAT # INCOMPAT: --cooperative-threading is incompatible with --shared-memory +.globl __indirect_function_table +.tabletype __indirect_function_table, funcref + .globl __wasm_get_tls_base __wasm_get_tls_base: .functype __wasm_get_tls_base () -> (i32) i32.const 0 end_function +.globl do_call_indirect +do_call_indirect: + .functype do_call_indirect () -> () + i32.const 1 + call_indirect __indirect_function_table, () -> () + end_function + .globl _start _start: .functype _start () -> (i32) @@ -66,12 +76,23 @@ foo: .int8 7 .ascii "atomics" +# CHECK: - Type: TABLE +# CHECK-NEXT: Tables: +# CHECK-NEXT: - Index: 0 +# CHECK-NEXT: ElemType: FUNCREF + # Memory must NOT be marked as shared. # CHECK: - Type: MEMORY # CHECK-NEXT: Memories: # CHECK-NEXT: - Minimum: 0x2 # CHECK-NOT: Shared +# The function table is exported by default. +# CHECK: - Type: EXPORT +# CHECK: - Name: __indirect_function_table +# CHECK-NEXT: Kind: TABLE +# CHECK-NEXT: Index: 0 + # Only TLS needs a passive data segment; .data stays active and .bss gets no # segment at all since memory is only instantiated once and starts zeroed. # CHECK: - Type: DATACOUNT @@ -118,3 +139,14 @@ foo: # DIS-NEXT: i32.load 0 # DIS-NEXT: i32.add # DIS-NEXT: end + +# When the table is imported instead there is no need to also export it. +# RUN: wasm-ld --cooperative-threading --import-table -no-gc-sections -o %t3.wasm %t.o +# RUN: obj2yaml %t3.wasm | FileCheck %s --check-prefix=IMPORT-TABLE + +# When the table is imported instead there is no need to also export it. +# IMPORT-TABLE: - Type: IMPORT +# IMPORT-TABLE: - Module: env +# IMPORT-TABLE-NEXT: Field: __indirect_function_table +# IMPORT-TABLE-NEXT: Kind: TABLE +# IMPORT-TABLE-NOT: Kind: TABLE diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index 9a2e3a82a9279..c213d7ca0b0f3 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -759,6 +759,14 @@ static void setConfigs() { if (ctx.arg.sharedMemory) error("--cooperative-threading is incompatible with --shared-memory"); ctx.arg.libcallThreadContext = true; + + // Cooperative threading requires the table is either imported or exported + // or otherwise there's no way for embedders to read spawned functions from + // the table. If we've gotten this far and the table isn't otherwise + // imported (e.g in `isPic` mode) then export the table instead to ensure + // that it's visible to the outside world. + if (!ctx.arg.importTable) + ctx.arg.exportTable = true; } } From f180ce951b1a93c8998b029ad9b0649bb92552c8 Mon Sep 17 00:00:00 2001 From: Yonah Goldberg Date: Thu, 6 Aug 2026 15:55:49 -0700 Subject: [PATCH 018/789] [SDAG][NVPTX] Cache control metadata support and lowering (#204067) This is the follow up for commit https://github.com/llvm/llvm-project/commit/0fc5d0ab0cea3afe32592f24af17b5d7e02c9dfe, which added IR support for cache hint metadata, as described in https://discourse.llvm.org/t/rfc-composable-and-extensible-memory-cache-control-hints-in-llvm-ir/89443. See previous https://github.com/llvm/llvm-project/pull/175901 that I closed in favor of this one. This PR adds support in SelectionDAG and lowering in NVPTX. Supported cache hints: L1 eviction: L1::evict_first, L1::evict_last, L1::evict_unchanged, L1::no_allocate (requires SM 70+) L2 eviction: L2::evict_first, L2::evict_last (requires SM 70+) L2 prefetch: L2::64B, L2::128B (SM 75+), L2::256B (SM 80+) L2::cache_hint with 64-bit cache policy descriptor (SM 80+, PTX 7.4+) L1 eviction: L1::evict_first, L1::evict_last, L1::evict_unchanged, L1::no_allocate (requires SM 70+ and PTX 7.4+) L2 eviction: L2::evict_first, L2::evict_last (requires SM 100+, PTX 8.8+, and a 256-bit .v8.b32 or .v4.b64 memory operation) L2 prefetch: L2::64B, L2::128B (requires SM 75+ and PTX 7.4+), L2::256B (requires SM 80+ and PTX 7.4+) L2 cache policy: L2::cache_hint with a 64-bit cache policy descriptor (requires SM 80+ and PTX 7.4+) I know this is a fairly large PR, but I needed to plug the support all the way through the backend. I supposed I could add machinery in SelectionDAG as an initial PR, but I'm not sure if that makes sense. I implemented lowering on load + store + memcpy. I supposed memcpy can go in a follow-up, but it doesn't really reduce the size that much. TODO: - implement support in global ISEL - Implement lowering in NVPTX for atomics + other intrinsics (llvm.masked.load/store) - Better handling of cache hint metadata in legalization. Today we will often drop the metadata. If we legalize a wide vector load into a bunch of smaller loads, for example, we should preserve the metadata. - Preserve L2 eviction metadata for suitably aligned, 32-byte-multiple memcpy operations Design decisions: - I encoded the metadata in the MachineMemOperand. I hope it's ok to increase the size. I think this is the best place because similar information (atomic info, range metadata, etc...) is all stored there. - When the metadata node values (strings which are target dependent) are not valid for NVPTX, I call `ctx.emitError` to emit a diagnostic. I think this is best because we wouldn't want front-ends to accidentally emit incorrect metadata and for it to silently be dropped. Co-authored-by: Fiigii Assisted by AI --- llvm/include/llvm/CodeGen/CodeGenCommonISel.h | 9 + .../CodeGen/GlobalISel/GenericMachineInstrs.h | 3 + llvm/include/llvm/CodeGen/MachineFunction.h | 22 +- llvm/include/llvm/CodeGen/MachineMemOperand.h | 37 +- llvm/include/llvm/CodeGen/SelectionDAG.h | 54 +- llvm/include/llvm/CodeGen/SelectionDAGNodes.h | 22 +- llvm/lib/CodeGen/CodeGenCommonISel.cpp | 21 + llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp | 26 +- llvm/lib/CodeGen/MIRParser/MILexer.cpp | 1 + llvm/lib/CodeGen/MIRParser/MILexer.h | 1 + llvm/lib/CodeGen/MIRParser/MIParser.cpp | 12 +- llvm/lib/CodeGen/MachineFunction.cpp | 49 +- llvm/lib/CodeGen/MachineOperand.cpp | 26 +- llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 11 +- llvm/lib/CodeGen/SelectionDAG/FastISel.cpp | 3 +- .../SelectionDAG/LegalizeVectorTypes.cpp | 34 +- .../lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 81 ++- .../SelectionDAG/SelectionDAGBuilder.cpp | 48 +- llvm/lib/Target/AMDGPU/SIISelLowering.cpp | 3 +- .../Target/Hexagon/HexagonISelLowering.cpp | 4 +- .../NVPTX/MCTargetDesc/NVPTXInstPrinter.cpp | 74 +++ .../NVPTX/MCTargetDesc/NVPTXInstPrinter.h | 5 + llvm/lib/Target/NVPTX/NVPTX.h | 71 +- llvm/lib/Target/NVPTX/NVPTXForwardParams.cpp | 31 +- llvm/lib/Target/NVPTX/NVPTXISelDAGToDAG.cpp | 225 ++++++- llvm/lib/Target/NVPTX/NVPTXInstrInfo.td | 169 +++-- llvm/lib/Target/NVPTX/NVPTXIntrinsics.td | 42 +- llvm/lib/Target/NVPTX/NVPTXSubtarget.h | 19 + llvm/lib/Target/PowerPC/PPCISelLowering.cpp | 42 +- llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 2 +- .../floating-point-immediate-operands.mir | 12 +- .../CodeGen/MIR/X86/mem-cache-hint-error.mir | 26 + .../X86/mem-cache-hint-undefined-metadata.mir | 29 + llvm/test/CodeGen/MIR/X86/mem-cache-hint.mir | 42 ++ llvm/test/CodeGen/MIR/X86/memory-operands.mir | 6 +- llvm/test/CodeGen/NVPTX/address-folder.mir | 20 +- llvm/test/CodeGen/NVPTX/cache-hint-atomics.ll | 47 ++ .../CodeGen/NVPTX/cache-hint-cache-policy.ll | 261 ++++++++ .../CodeGen/NVPTX/cache-hint-intrinsics.ll | 622 ++++++++++++++++++ llvm/test/CodeGen/NVPTX/cache-hint-invalid.ll | 147 +++++ .../CodeGen/NVPTX/cache-hint-load-store.ll | 408 ++++++++++++ .../CodeGen/NVPTX/cache-hint-sm-version.ll | 348 ++++++++++ .../CodeGen/NVPTX/cache-hint-transforms.ll | 213 ++++++ .../NVPTX/machinelicm-no-preheader.mir | 16 +- llvm/test/CodeGen/NVPTX/proxy-reg-erasure.mir | 8 +- llvm/test/DebugInfo/NVPTX/inlinedAt_2.mir | 4 +- llvm/tools/llvm-reduce/ReducerWorkItem.cpp | 4 +- .../CodeGen/GlobalISel/GISelAliasTest.cpp | 2 +- .../CodeGen/GlobalISel/KnownBitsTest.cpp | 4 +- .../GlobalISel/KnownBitsVectorTest.cpp | 4 +- .../GlobalISel/MachineIRBuilderTest.cpp | 2 +- .../AArch64/AArch64SelectionDAGTest.cpp | 6 +- 52 files changed, 3048 insertions(+), 330 deletions(-) create mode 100644 llvm/test/CodeGen/MIR/X86/mem-cache-hint-error.mir create mode 100644 llvm/test/CodeGen/MIR/X86/mem-cache-hint-undefined-metadata.mir create mode 100644 llvm/test/CodeGen/MIR/X86/mem-cache-hint.mir create mode 100644 llvm/test/CodeGen/NVPTX/cache-hint-atomics.ll create mode 100644 llvm/test/CodeGen/NVPTX/cache-hint-cache-policy.ll create mode 100644 llvm/test/CodeGen/NVPTX/cache-hint-intrinsics.ll create mode 100644 llvm/test/CodeGen/NVPTX/cache-hint-invalid.ll create mode 100644 llvm/test/CodeGen/NVPTX/cache-hint-load-store.ll create mode 100644 llvm/test/CodeGen/NVPTX/cache-hint-sm-version.ll create mode 100644 llvm/test/CodeGen/NVPTX/cache-hint-transforms.ll diff --git a/llvm/include/llvm/CodeGen/CodeGenCommonISel.h b/llvm/include/llvm/CodeGen/CodeGenCommonISel.h index 9416fa83e9c5e..c07ae50793cb2 100644 --- a/llvm/include/llvm/CodeGen/CodeGenCommonISel.h +++ b/llvm/include/llvm/CodeGen/CodeGenCommonISel.h @@ -19,6 +19,8 @@ namespace llvm { class BasicBlock; +class Instruction; +class MDNode; enum FPClassTest : unsigned; /// Encapsulates all of the information needed to generate a stack protector @@ -226,6 +228,13 @@ findSplitPointForStackProtector(MachineBasicBlock *BB, /// simpler test. LLVM_ABI FPClassTest invertFPClassTestIfSimpler(FPClassTest Test, bool UseFCmp); +/// Return the cache hint metadata node for memory operand \p OperandNo on \p I, +/// or nullptr when the instruction has no hint for that operand. For a \c +/// CallBase, \p OperandNo is an argument index; otherwise it is an instruction +/// operand index. +LLVM_ABI const MDNode *getMemCacheHintMetadata(const Instruction &I, + unsigned OperandNo = 0); + /// Assuming the instruction \p MI is going to be deleted, attempt to salvage /// debug users of \p MI by writing the effect of \p MI in a DIExpression. LLVM_ABI void salvageDebugInfoForDbgValue(const MachineRegisterInfo &MRI, diff --git a/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h b/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h index e171aaa19a3db..3be9d31bc57c9 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h @@ -194,6 +194,9 @@ class GAnyLoad : public GLoadStore { return getMMO().getRanges(); } + /// Returns the cache hint metadata for this load. + const MDNode *getMemCacheHint() const { return getMMO().getMemCacheHint(); } + static bool classof(const MachineInstr *MI) { switch (MI->getOpcode()) { case TargetOpcode::G_LOAD: diff --git a/llvm/include/llvm/CodeGen/MachineFunction.h b/llvm/include/llvm/CodeGen/MachineFunction.h index 70b82bcd96b11..d84ce80e10a3c 100644 --- a/llvm/include/llvm/CodeGen/MachineFunction.h +++ b/llvm/include/llvm/CodeGen/MachineFunction.h @@ -1114,35 +1114,35 @@ class LLVM_ABI MachineFunction { /// MachineMemOperands are owned by the MachineFunction and need not be /// explicitly deallocated. MachineMemOperand *getMachineMemOperand( - MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, LLT MemTy, - Align base_alignment, const AAMDNodes &AAInfo = AAMDNodes(), - const MDNode *Ranges = nullptr, SyncScope::ID SSID = SyncScope::System, + MachinePointerInfo PtrInfo, MachineMemOperand::Flags F, LLT MemTy, + Align BaseAlignment, const MMOMetadata &Metadata = MMOMetadata(), + SyncScope::ID SSID = SyncScope::System, AtomicOrdering Ordering = AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering = AtomicOrdering::NotAtomic); MachineMemOperand *getMachineMemOperand( MachinePointerInfo PtrInfo, MachineMemOperand::Flags F, LocationSize Size, - Align BaseAlignment, const AAMDNodes &AAInfo = AAMDNodes(), - const MDNode *Ranges = nullptr, SyncScope::ID SSID = SyncScope::System, + Align BaseAlignment, const MMOMetadata &Metadata = MMOMetadata(), + SyncScope::ID SSID = SyncScope::System, AtomicOrdering Ordering = AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering = AtomicOrdering::NotAtomic); MachineMemOperand *getMachineMemOperand( MachinePointerInfo PtrInfo, MachineMemOperand::Flags F, uint64_t Size, - Align BaseAlignment, const AAMDNodes &AAInfo = AAMDNodes(), - const MDNode *Ranges = nullptr, SyncScope::ID SSID = SyncScope::System, + Align BaseAlignment, const MMOMetadata &Metadata = MMOMetadata(), + SyncScope::ID SSID = SyncScope::System, AtomicOrdering Ordering = AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering = AtomicOrdering::NotAtomic) { return getMachineMemOperand(PtrInfo, F, LocationSize::precise(Size), - BaseAlignment, AAInfo, Ranges, SSID, Ordering, + BaseAlignment, Metadata, SSID, Ordering, FailureOrdering); } MachineMemOperand *getMachineMemOperand( MachinePointerInfo PtrInfo, MachineMemOperand::Flags F, TypeSize Size, - Align BaseAlignment, const AAMDNodes &AAInfo = AAMDNodes(), - const MDNode *Ranges = nullptr, SyncScope::ID SSID = SyncScope::System, + Align BaseAlignment, const MMOMetadata &Metadata = MMOMetadata(), + SyncScope::ID SSID = SyncScope::System, AtomicOrdering Ordering = AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering = AtomicOrdering::NotAtomic) { return getMachineMemOperand(PtrInfo, F, LocationSize::precise(Size), - BaseAlignment, AAInfo, Ranges, SSID, Ordering, + BaseAlignment, Metadata, SSID, Ordering, FailureOrdering); } diff --git a/llvm/include/llvm/CodeGen/MachineMemOperand.h b/llvm/include/llvm/CodeGen/MachineMemOperand.h index 79eedb8b74f6f..b275bbae28140 100644 --- a/llvm/include/llvm/CodeGen/MachineMemOperand.h +++ b/llvm/include/llvm/CodeGen/MachineMemOperand.h @@ -118,6 +118,17 @@ struct MachinePointerInfo { LLVM_ABI static MachinePointerInfo getUnknownStack(MachineFunction &MF); }; +/// LLVM IR metadata carried by a MachineMemOperand. +struct MMOMetadata { + AAMDNodes AAInfo; + const MDNode *Ranges = nullptr; + const MDNode *MemCacheHint = nullptr; + + MMOMetadata() = default; + MMOMetadata(const AAMDNodes &AAInfo, const MDNode *Ranges = nullptr, + const MDNode *MemCacheHint = nullptr) + : AAInfo(AAInfo), Ranges(Ranges), MemCacheHint(MemCacheHint) {} +}; //===----------------------------------------------------------------------===// /// A description of a memory reference used in the backend. @@ -182,24 +193,23 @@ class MachineMemOperand { MachineAtomicInfo AtomicInfo; AAMDNodes AAInfo; const MDNode *Ranges; + const MDNode *MemCacheHint; public: /// Construct a MachineMemOperand object with the specified PtrInfo, flags, - /// size, and base alignment. For atomic operations the synchronization scope - /// and atomic ordering requirements must also be specified. For cmpxchg - /// atomic operations the atomic ordering requirements when store does not - /// occur must also be specified. + /// size, base alignment, and metadata. For atomic operations the + /// synchronization scope and atomic ordering requirements must also be + /// specified. For cmpxchg atomic operations the atomic ordering requirements + /// when store does not occur must also be specified. LLVM_ABI - MachineMemOperand(MachinePointerInfo PtrInfo, Flags flags, LocationSize TS, - Align a, const AAMDNodes &AAInfo = AAMDNodes(), - const MDNode *Ranges = nullptr, + MachineMemOperand(MachinePointerInfo PtrInfo, Flags Flags, LocationSize TS, + Align A, const MMOMetadata &Metadata = MMOMetadata(), SyncScope::ID SSID = SyncScope::System, AtomicOrdering Ordering = AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering = AtomicOrdering::NotAtomic); LLVM_ABI - MachineMemOperand(MachinePointerInfo PtrInfo, Flags flags, LLT type, Align a, - const AAMDNodes &AAInfo = AAMDNodes(), - const MDNode *Ranges = nullptr, + MachineMemOperand(MachinePointerInfo PtrInfo, Flags Flags, LLT Type, Align A, + const MMOMetadata &Metadata = MMOMetadata(), SyncScope::ID SSID = SyncScope::System, AtomicOrdering Ordering = AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering = AtomicOrdering::NotAtomic); @@ -271,6 +281,9 @@ class MachineMemOperand { /// Return the range tag for the memory reference. const MDNode *getRanges() const { return Ranges; } + /// Return the cache hint metadata for the memory reference. + const MDNode *getMemCacheHint() const { return MemCacheHint; } + /// Returns the synchronization scope ID for this memory operation. SyncScope::ID getSyncScopeID() const { return static_cast(AtomicInfo.SSID); @@ -338,6 +351,9 @@ class MachineMemOperand { /// Unset the tracked range metadata. void clearRanges() { Ranges = nullptr; } + /// Unset the cache hint metadata. + void clearMemCacheHint() { MemCacheHint = nullptr; } + /// Support for operator<<. /// @{ LLVM_ABI void print(raw_ostream &OS, ModuleSlotTracker &MST, @@ -355,6 +371,7 @@ class MachineMemOperand { LHS.getFlags() == RHS.getFlags() && LHS.getAAInfo() == RHS.getAAInfo() && LHS.getRanges() == RHS.getRanges() && + LHS.getMemCacheHint() == RHS.getMemCacheHint() && LHS.getAlign() == RHS.getAlign() && LHS.getAddrSpace() == RHS.getAddrSpace() && LHS.getSuccessOrdering() == RHS.getSuccessOrdering() && diff --git a/llvm/include/llvm/CodeGen/SelectionDAG.h b/llvm/include/llvm/CodeGen/SelectionDAG.h index 8467d49c72140..303ea1f298251 100644 --- a/llvm/include/llvm/CodeGen/SelectionDAG.h +++ b/llvm/include/llvm/CodeGen/SelectionDAG.h @@ -1529,11 +1529,11 @@ class SelectionDAG { /// /// This function will set the MOLoad flag on MMOFlags, but you can set it if /// you want. The MOStore flag must not be set. - LLVM_ABI SDValue getLoad( - EVT VT, const SDLoc &dl, SDValue Chain, SDValue Ptr, - MachinePointerInfo PtrInfo, MaybeAlign Alignment = MaybeAlign(), - MachineMemOperand::Flags MMOFlags = MachineMemOperand::MONone, - const AAMDNodes &AAInfo = AAMDNodes(), const MDNode *Ranges = nullptr); + LLVM_ABI SDValue + getLoad(EVT VT, const SDLoc &dl, SDValue Chain, SDValue Ptr, + MachinePointerInfo PtrInfo, MaybeAlign Alignment = MaybeAlign(), + MachineMemOperand::Flags MMOFlags = MachineMemOperand::MONone, + const MMOMetadata &Metadata = MMOMetadata()); LLVM_ABI SDValue getLoad(EVT VT, const SDLoc &dl, SDValue Chain, SDValue Ptr, MachineMemOperand *MMO); LLVM_ABI SDValue @@ -1541,29 +1541,29 @@ class SelectionDAG { SDValue Ptr, MachinePointerInfo PtrInfo, EVT MemVT, MaybeAlign Alignment = MaybeAlign(), MachineMemOperand::Flags MMOFlags = MachineMemOperand::MONone, - const AAMDNodes &AAInfo = AAMDNodes()); + const MMOMetadata &Metadata = MMOMetadata()); LLVM_ABI SDValue getExtLoad(ISD::LoadExtType ExtType, const SDLoc &dl, EVT VT, SDValue Chain, SDValue Ptr, EVT MemVT, MachineMemOperand *MMO); LLVM_ABI SDValue getIndexedLoad(SDValue OrigLoad, const SDLoc &dl, SDValue Base, SDValue Offset, ISD::MemIndexedMode AM); - LLVM_ABI SDValue getLoad( - ISD::MemIndexedMode AM, ISD::LoadExtType ExtType, EVT VT, const SDLoc &dl, - SDValue Chain, SDValue Ptr, SDValue Offset, MachinePointerInfo PtrInfo, - EVT MemVT, Align Alignment, - MachineMemOperand::Flags MMOFlags = MachineMemOperand::MONone, - const AAMDNodes &AAInfo = AAMDNodes(), const MDNode *Ranges = nullptr); - inline SDValue getLoad( - ISD::MemIndexedMode AM, ISD::LoadExtType ExtType, EVT VT, const SDLoc &dl, - SDValue Chain, SDValue Ptr, SDValue Offset, MachinePointerInfo PtrInfo, - EVT MemVT, MaybeAlign Alignment = MaybeAlign(), - MachineMemOperand::Flags MMOFlags = MachineMemOperand::MONone, - const AAMDNodes &AAInfo = AAMDNodes(), const MDNode *Ranges = nullptr) { + LLVM_ABI SDValue + getLoad(ISD::MemIndexedMode AM, ISD::LoadExtType ExtType, EVT VT, + const SDLoc &dl, SDValue Chain, SDValue Ptr, SDValue Offset, + MachinePointerInfo PtrInfo, EVT MemVT, Align Alignment, + MachineMemOperand::Flags MMOFlags = MachineMemOperand::MONone, + const MMOMetadata &Metadata = MMOMetadata()); + inline SDValue + getLoad(ISD::MemIndexedMode AM, ISD::LoadExtType ExtType, EVT VT, + const SDLoc &dl, SDValue Chain, SDValue Ptr, SDValue Offset, + MachinePointerInfo PtrInfo, EVT MemVT, + MaybeAlign Alignment = MaybeAlign(), + MachineMemOperand::Flags MMOFlags = MachineMemOperand::MONone, + const MMOMetadata &Metadata = MMOMetadata()) { // Ensures that codegen never sees a None Alignment. return getLoad(AM, ExtType, VT, dl, Chain, Ptr, Offset, PtrInfo, MemVT, - Alignment.value_or(getEVTAlign(MemVT)), MMOFlags, AAInfo, - Ranges); + Alignment.value_or(getEVTAlign(MemVT)), MMOFlags, Metadata); } LLVM_ABI SDValue getLoad(ISD::MemIndexedMode AM, ISD::LoadExtType ExtType, EVT VT, const SDLoc &dl, SDValue Chain, SDValue Ptr, @@ -1578,15 +1578,15 @@ class SelectionDAG { getStore(SDValue Chain, const SDLoc &dl, SDValue Val, SDValue Ptr, MachinePointerInfo PtrInfo, Align Alignment, MachineMemOperand::Flags MMOFlags = MachineMemOperand::MONone, - const AAMDNodes &AAInfo = AAMDNodes()); + const MMOMetadata &Metadata = MMOMetadata()); inline SDValue getStore(SDValue Chain, const SDLoc &dl, SDValue Val, SDValue Ptr, MachinePointerInfo PtrInfo, MaybeAlign Alignment = MaybeAlign(), MachineMemOperand::Flags MMOFlags = MachineMemOperand::MONone, - const AAMDNodes &AAInfo = AAMDNodes()) { + const MMOMetadata &Metadata = MMOMetadata()) { return getStore(Chain, dl, Val, Ptr, PtrInfo, Alignment.value_or(getEVTAlign(Val.getValueType())), - MMOFlags, AAInfo); + MMOFlags, Metadata); } LLVM_ABI SDValue getStore(SDValue Chain, const SDLoc &dl, SDValue Val, SDValue Ptr, MachineMemOperand *MMO); @@ -1597,12 +1597,12 @@ class SelectionDAG { SDValue Chain, const SDLoc &dl, SDValue Val, SDValue Ptr, SDValue Offset, MachinePointerInfo PtrInfo, EVT SVT, Align Alignment, MachineMemOperand::Flags MMOFlags = MachineMemOperand::MONone, - const AAMDNodes &AAInfo = AAMDNodes()); + const MMOMetadata &Metadata = MMOMetadata()); LLVM_ABI SDValue getTruncStore(SDValue Chain, const SDLoc &dl, SDValue Val, SDValue Ptr, MachinePointerInfo PtrInfo, EVT SVT, Align Alignment, MachineMemOperand::Flags MMOFlags = MachineMemOperand::MONone, - const AAMDNodes &AAInfo = AAMDNodes()); + const MMOMetadata &Metadata = MMOMetadata()); LLVM_ABI SDValue getTruncStore(SDValue Chain, const SDLoc &dl, SDValue Val, SDValue Ptr, SDValue Offset, EVT SVT, MachineMemOperand *MMO); @@ -1612,10 +1612,10 @@ class SelectionDAG { MachinePointerInfo PtrInfo, EVT SVT, MaybeAlign Alignment = MaybeAlign(), MachineMemOperand::Flags MMOFlags = MachineMemOperand::MONone, - const AAMDNodes &AAInfo = AAMDNodes()) { + const MMOMetadata &Metadata = MMOMetadata()) { return getTruncStore(Chain, dl, Val, Ptr, PtrInfo, SVT, Alignment.value_or(getEVTAlign(SVT)), MMOFlags, - AAInfo); + Metadata); } LLVM_ABI SDValue getTruncStore(SDValue Chain, const SDLoc &dl, SDValue Val, SDValue Ptr, EVT SVT, MachineMemOperand *MMO); diff --git a/llvm/include/llvm/CodeGen/SelectionDAGNodes.h b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h index 990b649fafe19..0ac1867cad8b2 100644 --- a/llvm/include/llvm/CodeGen/SelectionDAGNodes.h +++ b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h @@ -1481,6 +1481,11 @@ class MemSDNode : public SDNode { /// Returns the Ranges that describes the dereference. const MDNode *getRanges() const { return getMemOperand()->getRanges(); } + /// Returns the cache hint metadata for this memory access. + const MDNode *getMemCacheHint() const { + return getMemOperand()->getMemCacheHint(); + } + /// Returns the synchronization scope ID for this memory operation. SyncScope::ID getSyncScopeID() const { return getMemOperand()->getSyncScopeID(); @@ -1567,21 +1572,24 @@ class MemSDNode : public SDNode { refineAlignment(ArrayRef(NewMMO)); } - /// Refine range metadata for all MMOs. The NewMMOs array must parallel - /// memoperands(). For each pair, if ranges differ, the stored range is - /// cleared. - void refineRanges(ArrayRef NewMMOs) { + /// Refine LLVM IR metadata for all MMOs. The NewMMOs array must parallel + /// memoperands(). For each pair, if metadata differs, the stored metadata is + /// cleared conservatively. + void refineMMOMetadata(ArrayRef NewMMOs) { ArrayRef MMOs = memoperands(); assert(NewMMOs.size() == MMOs.size() && "MMO count mismatch"); - // FIXME: Union the ranges instead? for (auto [MMO, NewMMO] : zip(MMOs, NewMMOs)) { + // FIXME: Union the ranges instead? if (MMO->getRanges() && MMO->getRanges() != NewMMO->getRanges()) MMO->clearRanges(); + if (MMO->getMemCacheHint() && + MMO->getMemCacheHint() != NewMMO->getMemCacheHint()) + MMO->clearMemCacheHint(); } } - void refineRanges(MachineMemOperand *NewMMO) { - refineRanges(ArrayRef(NewMMO)); + void refineMMOMetadata(MachineMemOperand *NewMMO) { + refineMMOMetadata(ArrayRef(NewMMO)); } const SDValue &getChain() const { return getOperand(0); } diff --git a/llvm/lib/CodeGen/CodeGenCommonISel.cpp b/llvm/lib/CodeGen/CodeGenCommonISel.cpp index 4cd2f6ae2fdb1..77421253c0b26 100644 --- a/llvm/lib/CodeGen/CodeGenCommonISel.cpp +++ b/llvm/lib/CodeGen/CodeGenCommonISel.cpp @@ -17,12 +17,33 @@ #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/TargetInstrInfo.h" #include "llvm/CodeGen/TargetOpcodes.h" +#include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfoMetadata.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Metadata.h" +#include "llvm/Support/Casting.h" #define DEBUG_TYPE "codegen-common" using namespace llvm; +const MDNode *llvm::getMemCacheHintMetadata(const Instruction &I, + unsigned OperandNo) { + const MDNode *MD = I.getMetadata(LLVMContext::MD_mem_cache_hint); + if (!MD) + return nullptr; + + for (unsigned Idx = 0; Idx + 1 < MD->getNumOperands(); Idx += 2) { + const auto *OpNoCI = mdconst::extract(MD->getOperand(Idx)); + const auto *Hint = cast(MD->getOperand(Idx + 1)); + if (OpNoCI->getZExtValue() == OperandNo) + return Hint; + } + + return nullptr; +} + /// Add a successor MBB to ParentMBB< creating a new MachineBB for BB if SuccMBB /// is 0. MachineBasicBlock * diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp index a212604502673..11e5ac36fc569 100644 --- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp +++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -1418,9 +1418,9 @@ bool IRTranslator::translateLoad(const User &U, MachineIRBuilder &MIRBuilder) { if (Regs.size() == 1) { auto *MMO = MF->getMachineMemOperand( MachinePointerInfo(LI.getPointerOperand()), Flags, - MRI->getType(Regs[0]), getMemOpAlign(LI), AAInfo, - LI.getMetadata(LLVMContext::MD_range), LI.getSyncScopeID(), - LI.getOrdering()); + MRI->getType(Regs[0]), getMemOpAlign(LI), + MMOMetadata(AAInfo, LI.getMetadata(LLVMContext::MD_range)), + LI.getSyncScopeID(), LI.getOrdering()); MIRBuilder.buildLoad(Regs[0], Base, *MMO); return true; } @@ -1434,10 +1434,10 @@ bool IRTranslator::translateLoad(const User &U, MachineIRBuilder &MIRBuilder) { MachinePointerInfo Ptr(LI.getPointerOperand(), Offsets[i]); Align BaseAlign = getMemOpAlign(LI); - auto *MMO = MF->getMachineMemOperand(Ptr, Flags, MRI->getType(Regs[i]), - commonAlignment(BaseAlign, Offsets[i]), - AAInfo, nullptr, LI.getSyncScopeID(), - LI.getOrdering()); + auto *MMO = + MF->getMachineMemOperand(Ptr, Flags, MRI->getType(Regs[i]), + commonAlignment(BaseAlign, Offsets[i]), AAInfo, + LI.getSyncScopeID(), LI.getOrdering()); MIRBuilder.buildLoad(Regs[i], Addr, *MMO); } @@ -1466,7 +1466,7 @@ bool IRTranslator::translateStore(const User &U, MachineIRBuilder &MIRBuilder) { if (Vals.size() == 1) { auto *MMO = MF->getMachineMemOperand( MachinePointerInfo(SI.getPointerOperand()), Flags, - MRI->getType(Vals[0]), getMemOpAlign(SI), SI.getAAMetadata(), nullptr, + MRI->getType(Vals[0]), getMemOpAlign(SI), SI.getAAMetadata(), SI.getSyncScopeID(), SI.getOrdering()); MIRBuilder.buildStore(Vals[0], Base, *MMO); return true; @@ -1483,7 +1483,7 @@ bool IRTranslator::translateStore(const User &U, MachineIRBuilder &MIRBuilder) { Align BaseAlign = getMemOpAlign(SI); auto *MMO = MF->getMachineMemOperand(Ptr, Flags, MRI->getType(Vals[i]), commonAlignment(BaseAlign, Offsets[i]), - SI.getAAMetadata(), nullptr, + SI.getAAMetadata(), SI.getSyncScopeID(), SI.getOrdering()); MIRBuilder.buildStore(Vals[i], Addr, *MMO); } @@ -2961,8 +2961,8 @@ bool IRTranslator::translateIntrinsic( MPI = MachinePointerInfo(*Info.fallbackAddressSpace); } MIB.addMemOperand(MF->getMachineMemOperand( - MPI, Info.flags, MemTy, Alignment, CB.getAAMetadata(), - /*Ranges=*/nullptr, Info.ssid, Info.order, Info.failureOrder)); + MPI, Info.flags, MemTy, Alignment, CB.getAAMetadata(), Info.ssid, + Info.order, Info.failureOrder)); } if (CB.isConvergent()) { @@ -3587,7 +3587,7 @@ bool IRTranslator::translateAtomicCmpXchg(const User &U, OldValRes, SuccessRes, Addr, Cmp, NewVal, *MF->getMachineMemOperand( MachinePointerInfo(I.getPointerOperand()), Flags, MRI->getType(Cmp), - getMemOpAlign(I), I.getAAMetadata(), nullptr, I.getSyncScopeID(), + getMemOpAlign(I), I.getAAMetadata(), I.getSyncScopeID(), I.getSuccessOrdering(), I.getFailureOrdering())); return true; } @@ -3683,7 +3683,7 @@ bool IRTranslator::translateAtomicRMW(const User &U, Opcode, Res, Addr, Val, *MF->getMachineMemOperand(MachinePointerInfo(I.getPointerOperand()), Flags, MRI->getType(Val), getMemOpAlign(I), - I.getAAMetadata(), nullptr, I.getSyncScopeID(), + I.getAAMetadata(), I.getSyncScopeID(), I.getOrdering())); return true; } diff --git a/llvm/lib/CodeGen/MIRParser/MILexer.cpp b/llvm/lib/CodeGen/MIRParser/MILexer.cpp index 720ec3f0f3295..b2d949564f4ba 100644 --- a/llvm/lib/CodeGen/MIRParser/MILexer.cpp +++ b/llvm/lib/CodeGen/MIRParser/MILexer.cpp @@ -642,6 +642,7 @@ static MIToken::TokenKind getMetadataKeywordKind(StringRef Identifier) { .Case("!alias.scope", MIToken::md_alias_scope) .Case("!noalias", MIToken::md_noalias) .Case("!range", MIToken::md_range) + .Case("!mem.cache_hint", MIToken::md_mem_cache_hint) .Case("!DIExpression", MIToken::md_diexpr) .Case("!DILocation", MIToken::md_dilocation) .Case("!noalias.addrspace", MIToken::md_noalias_addrspace) diff --git a/llvm/lib/CodeGen/MIRParser/MILexer.h b/llvm/lib/CodeGen/MIRParser/MILexer.h index 9bca4af5187d6..f5947bfe59b9d 100644 --- a/llvm/lib/CodeGen/MIRParser/MILexer.h +++ b/llvm/lib/CodeGen/MIRParser/MILexer.h @@ -164,6 +164,7 @@ struct MIToken { md_noalias, md_noalias_addrspace, md_range, + md_mem_cache_hint, md_diexpr, md_dilocation, diff --git a/llvm/lib/CodeGen/MIRParser/MIParser.cpp b/llvm/lib/CodeGen/MIRParser/MIParser.cpp index f14e2cd8ce3dc..bb0b87cc042d0 100644 --- a/llvm/lib/CodeGen/MIRParser/MIParser.cpp +++ b/llvm/lib/CodeGen/MIRParser/MIParser.cpp @@ -3820,6 +3820,7 @@ bool MIParser::parseMachineMemoryOperand(MachineMemOperand *&Dest) { : 1; AAMDNodes AAInfo; MDNode *Range = nullptr; + MDNode *MemCacheHint = nullptr; while (consumeIfPresent(MIToken::comma)) { switch (Token.kind()) { case MIToken::kw_align: { @@ -3871,16 +3872,23 @@ bool MIParser::parseMachineMemoryOperand(MachineMemOperand *&Dest) { if (parseMDNode(Range)) return true; break; + case MIToken::md_mem_cache_hint: + lex(); + if (parseMDNode(MemCacheHint)) + return true; + break; // TODO: Report an error on duplicate metadata nodes. default: return error("expected 'align' or '!tbaa' or '!alias.scope' or " - "'!noalias' or '!range' or '!noalias.addrspace'"); + "'!noalias' or '!range' or '!mem.cache_hint' or " + "'!noalias.addrspace'"); } } if (expectAndConsume(MIToken::rparen)) return true; Dest = MF.getMachineMemOperand(Ptr, Flags, MemoryType, Align(BaseAlignment), - AAInfo, Range, SSID, Order, FailureOrder); + MMOMetadata(AAInfo, Range, MemCacheHint), SSID, + Order, FailureOrder); return false; } diff --git a/llvm/lib/CodeGen/MachineFunction.cpp b/llvm/lib/CodeGen/MachineFunction.cpp index eb4bc02e90ec3..144f165e17973 100644 --- a/llvm/lib/CodeGen/MachineFunction.cpp +++ b/llvm/lib/CodeGen/MachineFunction.cpp @@ -566,25 +566,23 @@ void MachineFunction::deleteMachineBasicBlock(MachineBasicBlock *MBB) { MachineMemOperand *MachineFunction::getMachineMemOperand( MachinePointerInfo PtrInfo, MachineMemOperand::Flags F, LocationSize Size, - Align BaseAlignment, const AAMDNodes &AAInfo, const MDNode *Ranges, - SyncScope::ID SSID, AtomicOrdering Ordering, - AtomicOrdering FailureOrdering) { + Align BaseAlignment, const MMOMetadata &Metadata, SyncScope::ID SSID, + AtomicOrdering Ordering, AtomicOrdering FailureOrdering) { assert((!Size.hasValue() || Size.getValue().getKnownMinValue() != ~UINT64_C(0)) && "Unexpected an unknown size to be represented using " "LocationSize::beforeOrAfter()"); return new (Allocator) - MachineMemOperand(PtrInfo, F, Size, BaseAlignment, AAInfo, Ranges, SSID, + MachineMemOperand(PtrInfo, F, Size, BaseAlignment, Metadata, SSID, Ordering, FailureOrdering); } MachineMemOperand *MachineFunction::getMachineMemOperand( - MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, LLT MemTy, - Align base_alignment, const AAMDNodes &AAInfo, const MDNode *Ranges, - SyncScope::ID SSID, AtomicOrdering Ordering, - AtomicOrdering FailureOrdering) { + MachinePointerInfo PtrInfo, MachineMemOperand::Flags F, LLT MemTy, + Align BaseAlignment, const MMOMetadata &Metadata, SyncScope::ID SSID, + AtomicOrdering Ordering, AtomicOrdering FailureOrdering) { return new (Allocator) - MachineMemOperand(PtrInfo, f, MemTy, base_alignment, AAInfo, Ranges, SSID, + MachineMemOperand(PtrInfo, F, MemTy, BaseAlignment, Metadata, SSID, Ordering, FailureOrdering); } @@ -596,18 +594,20 @@ MachineFunction::getMachineMemOperand(const MachineMemOperand *MMO, Size.getValue().getKnownMinValue() != ~UINT64_C(0)) && "Unexpected an unknown size to be represented using " "LocationSize::beforeOrAfter()"); - return new (Allocator) - MachineMemOperand(PtrInfo, MMO->getFlags(), Size, MMO->getBaseAlign(), - AAMDNodes(), nullptr, MMO->getSyncScopeID(), - MMO->getSuccessOrdering(), MMO->getFailureOrdering()); + return new (Allocator) MachineMemOperand( + PtrInfo, MMO->getFlags(), Size, MMO->getBaseAlign(), + MMOMetadata(AAMDNodes(), /*Ranges=*/nullptr, MMO->getMemCacheHint()), + MMO->getSyncScopeID(), MMO->getSuccessOrdering(), + MMO->getFailureOrdering()); } MachineMemOperand *MachineFunction::getMachineMemOperand( const MachineMemOperand *MMO, const MachinePointerInfo &PtrInfo, LLT Ty) { - return new (Allocator) - MachineMemOperand(PtrInfo, MMO->getFlags(), Ty, MMO->getBaseAlign(), - AAMDNodes(), nullptr, MMO->getSyncScopeID(), - MMO->getSuccessOrdering(), MMO->getFailureOrdering()); + return new (Allocator) MachineMemOperand( + PtrInfo, MMO->getFlags(), Ty, MMO->getBaseAlign(), + MMOMetadata(AAMDNodes(), /*Ranges=*/nullptr, MMO->getMemCacheHint()), + MMO->getSyncScopeID(), MMO->getSuccessOrdering(), + MMO->getFailureOrdering()); } MachineMemOperand * @@ -625,8 +625,9 @@ MachineFunction::getMachineMemOperand(const MachineMemOperand *MMO, // are anymore. return new (Allocator) MachineMemOperand( PtrInfo.getWithOffset(Offset), MMO->getFlags(), Ty, Alignment, - MMO->getAAInfo(), nullptr, MMO->getSyncScopeID(), - MMO->getSuccessOrdering(), MMO->getFailureOrdering()); + MMOMetadata(MMO->getAAInfo(), /*Ranges=*/nullptr, MMO->getMemCacheHint()), + MMO->getSyncScopeID(), MMO->getSuccessOrdering(), + MMO->getFailureOrdering()); } MachineMemOperand * @@ -637,8 +638,9 @@ MachineFunction::getMachineMemOperand(const MachineMemOperand *MMO, MachinePointerInfo(MMO->getPseudoValue(), MMO->getOffset()); return new (Allocator) MachineMemOperand( - MPI, MMO->getFlags(), MMO->getSize(), MMO->getBaseAlign(), AAInfo, - MMO->getRanges(), MMO->getSyncScopeID(), MMO->getSuccessOrdering(), + MPI, MMO->getFlags(), MMO->getSize(), MMO->getBaseAlign(), + MMOMetadata(AAInfo, MMO->getRanges(), MMO->getMemCacheHint()), + MMO->getSyncScopeID(), MMO->getSuccessOrdering(), MMO->getFailureOrdering()); } @@ -647,8 +649,9 @@ MachineFunction::getMachineMemOperand(const MachineMemOperand *MMO, MachineMemOperand::Flags Flags) { return new (Allocator) MachineMemOperand( MMO->getPointerInfo(), Flags, MMO->getSize(), MMO->getBaseAlign(), - MMO->getAAInfo(), MMO->getRanges(), MMO->getSyncScopeID(), - MMO->getSuccessOrdering(), MMO->getFailureOrdering()); + MMOMetadata(MMO->getAAInfo(), MMO->getRanges(), MMO->getMemCacheHint()), + MMO->getSyncScopeID(), MMO->getSuccessOrdering(), + MMO->getFailureOrdering()); } MachineInstr::ExtraInfo *MachineFunction::createMIExtraInfo( diff --git a/llvm/lib/CodeGen/MachineOperand.cpp b/llvm/lib/CodeGen/MachineOperand.cpp index bf48bc7a1cbbb..3067f6e636130 100644 --- a/llvm/lib/CodeGen/MachineOperand.cpp +++ b/llvm/lib/CodeGen/MachineOperand.cpp @@ -1180,13 +1180,15 @@ MachinePointerInfo MachinePointerInfo::getUnknownStack(MachineFunction &MF) { return MachinePointerInfo(MF.getDataLayout().getAllocaAddrSpace()); } -MachineMemOperand::MachineMemOperand(MachinePointerInfo ptrinfo, Flags f, - LLT type, Align a, const AAMDNodes &AAInfo, - const MDNode *Ranges, SyncScope::ID SSID, +MachineMemOperand::MachineMemOperand(MachinePointerInfo PtrInfo, Flags F, + LLT Type, Align A, + const MMOMetadata &Metadata, + SyncScope::ID SSID, AtomicOrdering Ordering, AtomicOrdering FailureOrdering) - : PtrInfo(ptrinfo), MemoryType(type), FlagVals(f), BaseAlign(a), - AAInfo(AAInfo), Ranges(Ranges) { + : PtrInfo(PtrInfo), MemoryType(Type), FlagVals(F), BaseAlign(A), + AAInfo(Metadata.AAInfo), Ranges(Metadata.Ranges), + MemCacheHint(Metadata.MemCacheHint) { assert((PtrInfo.V.isNull() || isa(PtrInfo.V) || isa(cast(PtrInfo.V)->getType())) && "invalid pointer value"); @@ -1200,19 +1202,19 @@ MachineMemOperand::MachineMemOperand(MachinePointerInfo ptrinfo, Flags f, assert(getFailureOrdering() == FailureOrdering && "Value truncated"); } -MachineMemOperand::MachineMemOperand(MachinePointerInfo ptrinfo, Flags F, +MachineMemOperand::MachineMemOperand(MachinePointerInfo PtrInfo, Flags F, LocationSize TS, Align BaseAlignment, - const AAMDNodes &AAInfo, - const MDNode *Ranges, SyncScope::ID SSID, + const MMOMetadata &Metadata, + SyncScope::ID SSID, AtomicOrdering Ordering, AtomicOrdering FailureOrdering) : MachineMemOperand( - ptrinfo, F, + PtrInfo, F, !TS.isPrecise() ? LLT() : TS.isScalable() ? LLT::scalable_vector(1, 8 * TS.getValue().getKnownMinValue()) : LLT::scalar(8 * TS.getValue().getKnownMinValue()), - BaseAlignment, AAInfo, Ranges, SSID, Ordering, FailureOrdering) {} + BaseAlignment, Metadata, SSID, Ordering, FailureOrdering) {} void MachineMemOperand::refineAlignment(const MachineMemOperand *MMO) { // The Value and Offset may differ due to CSE. But the flags and size @@ -1378,6 +1380,10 @@ void MachineMemOperand::print(raw_ostream &OS, ModuleSlotTracker &MST, OS << ", !range "; getRanges()->printAsOperand(OS, MST); } + if (getMemCacheHint()) { + OS << ", !mem.cache_hint "; + getMemCacheHint()->printAsOperand(OS, MST); + } // FIXME: Implement addrspace printing/parsing in MIR. // For now, print this even though parsing it is not available in MIR. if (unsigned AS = getAddrSpace()) diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index 418ef38daac29..c669d8d70d103 100644 --- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -14025,10 +14025,11 @@ SDValue DAGCombiner::visitMLOAD(SDNode *N) { // FIXME: Can we do this for indexed, expanding, or extending loads? if (ISD::isConstantSplatVectorAllOnes(Mask.getNode()) && MLD->isUnindexed() && !MLD->isExpandingLoad() && MLD->getExtensionType() == ISD::NON_EXTLOAD) { - SDValue NewLd = DAG.getLoad( - N->getValueType(0), SDLoc(N), MLD->getChain(), MLD->getBasePtr(), - MLD->getPointerInfo(), MLD->getBaseAlign(), - MLD->getMemOperand()->getFlags(), MLD->getAAInfo(), MLD->getRanges()); + SDValue NewLd = + DAG.getLoad(N->getValueType(0), SDLoc(N), MLD->getChain(), + MLD->getBasePtr(), MLD->getPointerInfo(), + MLD->getBaseAlign(), MLD->getMemOperand()->getFlags(), + MMOMetadata(MLD->getAAInfo(), MLD->getRanges())); return CombineTo(N, NewLd, NewLd.getValue(1)); } @@ -17178,7 +17179,7 @@ SDValue DAGCombiner::reduceLoadWidth(SDNode *N) { Load = DAG.getLoad(VT, DL, LN0->getChain(), NewPtr, LN0->getPointerInfo().getWithOffset(PtrOff), LN0->getBaseAlign(), LN0->getMemOperand()->getFlags(), - LN0->getAAInfo(), NewRanges); + MMOMetadata(LN0->getAAInfo(), NewRanges)); } else Load = DAG.getExtLoad(ExtType, DL, VT, LN0->getChain(), NewPtr, LN0->getPointerInfo().getWithOffset(PtrOff), ExtVT, diff --git a/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp b/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp index 5550f41301418..38c425e5b529b 100644 --- a/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp @@ -2375,7 +2375,8 @@ FastISel::createMachineMemOperandFor(const Instruction *I) const { Flags |= MachineMemOperand::MOInvariant; return FuncInfo.MF->getMachineMemOperand(MachinePointerInfo(Ptr), Flags, Size, - *Alignment, AAInfo, Ranges); + *Alignment, + MMOMetadata(AAInfo, Ranges)); } CmpInst::Predicate FastISel::optimizeCmpPredicate(const CmpInst *CI) const { diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp index 52f9a90fe243f..e93e77bd1defd 100644 --- a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp @@ -2516,8 +2516,8 @@ void DAGTypeLegalizer::SplitVecRes_VP_LOAD(VPLoadSDNode *LD, SDValue &Lo, MachineMemOperand *MMO = DAG.getMachineFunction().getMachineMemOperand( LD->getPointerInfo(), MachineMemOperand::MOLoad, - LocationSize::beforeOrAfterPointer(), Alignment, LD->getAAInfo(), - LD->getRanges()); + LocationSize::beforeOrAfterPointer(), Alignment, + MMOMetadata(LD->getAAInfo(), LD->getRanges())); Lo = DAG.getLoadVP(LD->getAddressingMode(), ExtType, LoVT, dl, Ch, Ptr, Offset, @@ -2541,7 +2541,7 @@ void DAGTypeLegalizer::SplitVecRes_VP_LOAD(VPLoadSDNode *LD, SDValue &Lo, MMO = DAG.getMachineFunction().getMachineMemOperand( MPI, MachineMemOperand::MOLoad, LocationSize::beforeOrAfterPointer(), - Alignment, LD->getAAInfo(), LD->getRanges()); + Alignment, MMOMetadata(LD->getAAInfo(), LD->getRanges())); Hi = DAG.getLoadVP(LD->getAddressingMode(), ExtType, HiVT, dl, Ch, Ptr, Offset, MaskHi, EVLHi, HiMemVT, MMO, @@ -2585,8 +2585,8 @@ void DAGTypeLegalizer::SplitVecRes_VP_LOAD_FF(VPLoadFFSDNode *LD, SDValue &Lo, MachineMemOperand *MMO = DAG.getMachineFunction().getMachineMemOperand( LD->getPointerInfo(), MachineMemOperand::MOLoad, - LocationSize::beforeOrAfterPointer(), Alignment, LD->getAAInfo(), - LD->getRanges()); + LocationSize::beforeOrAfterPointer(), Alignment, + MMOMetadata(LD->getAAInfo(), LD->getRanges())); Lo = DAG.getLoadFFVP(LoVT, dl, Ch, Ptr, MaskLo, EVLLo, MMO); @@ -2660,7 +2660,7 @@ void DAGTypeLegalizer::SplitVecRes_VP_STRIDED_LOAD(VPStridedLoadSDNode *SLD, MachineMemOperand *MMO = DAG.getMachineFunction().getMachineMemOperand( MachinePointerInfo(SLD->getPointerInfo().getAddrSpace()), MachineMemOperand::MOLoad, LocationSize::beforeOrAfterPointer(), - Alignment, SLD->getAAInfo(), SLD->getRanges()); + Alignment, MMOMetadata(SLD->getAAInfo(), SLD->getRanges())); Hi = DAG.getStridedLoadVP(SLD->getAddressingMode(), SLD->getExtensionType(), HiVT, DL, SLD->getChain(), Ptr, SLD->getOffset(), @@ -2720,7 +2720,7 @@ void DAGTypeLegalizer::SplitVecRes_MLOAD(MaskedLoadSDNode *MLD, MachineMemOperand *MMO = DAG.getMachineFunction().getMachineMemOperand( MLD->getPointerInfo(), MMOFlags, LocationSize::beforeOrAfterPointer(), - Alignment, MLD->getAAInfo(), MLD->getRanges()); + Alignment, MMOMetadata(MLD->getAAInfo(), MLD->getRanges())); Lo = DAG.getMaskedLoad(LoVT, dl, Ch, Ptr, Offset, MaskLo, PassThruLo, LoMemVT, MMO, MLD->getAddressingMode(), ExtType, @@ -2744,7 +2744,7 @@ void DAGTypeLegalizer::SplitVecRes_MLOAD(MaskedLoadSDNode *MLD, MMO = DAG.getMachineFunction().getMachineMemOperand( MPI, MMOFlags, LocationSize::beforeOrAfterPointer(), Alignment, - MLD->getAAInfo(), MLD->getRanges()); + MMOMetadata(MLD->getAAInfo(), MLD->getRanges())); Hi = DAG.getMaskedLoad(HiVT, dl, Ch, Ptr, Offset, MaskHi, PassThruHi, HiMemVT, MMO, MLD->getAddressingMode(), ExtType, @@ -2807,7 +2807,7 @@ void DAGTypeLegalizer::SplitVecRes_Gather(MemSDNode *N, SDValue &Lo, MachineMemOperand::Flags MMOFlags = N->getMemOperand()->getFlags(); MachineMemOperand *MMO = DAG.getMachineFunction().getMachineMemOperand( N->getPointerInfo(), MMOFlags, LocationSize::beforeOrAfterPointer(), - Alignment, N->getAAInfo(), N->getRanges()); + Alignment, MMOMetadata(N->getAAInfo(), N->getRanges())); if (auto *MGT = dyn_cast(N)) { SDValue PassThru = MGT->getPassThru(); @@ -4498,8 +4498,8 @@ SDValue DAGTypeLegalizer::SplitVecOp_VP_STORE(VPStoreSDNode *N, unsigned OpNo) { SDValue Lo, Hi; MachineMemOperand *MMO = DAG.getMachineFunction().getMachineMemOperand( N->getPointerInfo(), MachineMemOperand::MOStore, - LocationSize::beforeOrAfterPointer(), Alignment, N->getAAInfo(), - N->getRanges()); + LocationSize::beforeOrAfterPointer(), Alignment, + MMOMetadata(N->getAAInfo(), N->getRanges())); Lo = DAG.getStoreVP(Ch, DL, DataLo, Ptr, Offset, MaskLo, EVLLo, LoMemVT, MMO, N->getAddressingMode(), N->isTruncatingStore(), @@ -4523,7 +4523,7 @@ SDValue DAGTypeLegalizer::SplitVecOp_VP_STORE(VPStoreSDNode *N, unsigned OpNo) { MMO = DAG.getMachineFunction().getMachineMemOperand( MPI, MachineMemOperand::MOStore, LocationSize::beforeOrAfterPointer(), - Alignment, N->getAAInfo(), N->getRanges()); + Alignment, MMOMetadata(N->getAAInfo(), N->getRanges())); Hi = DAG.getStoreVP(Ch, DL, DataHi, Ptr, Offset, MaskHi, EVLHi, HiMemVT, MMO, N->getAddressingMode(), N->isTruncatingStore(), @@ -4596,7 +4596,7 @@ SDValue DAGTypeLegalizer::SplitVecOp_VP_STRIDED_STORE(VPStridedStoreSDNode *N, MachineMemOperand *MMO = DAG.getMachineFunction().getMachineMemOperand( MachinePointerInfo(N->getPointerInfo().getAddrSpace()), MachineMemOperand::MOStore, LocationSize::beforeOrAfterPointer(), - Alignment, N->getAAInfo(), N->getRanges()); + Alignment, MMOMetadata(N->getAAInfo(), N->getRanges())); SDValue Hi = DAG.getStridedStoreVP( N->getChain(), DL, HiData, Ptr, N->getOffset(), N->getStride(), HiMask, @@ -4647,8 +4647,8 @@ SDValue DAGTypeLegalizer::SplitVecOp_MSTORE(MaskedStoreSDNode *N, SDValue Lo, Hi, Res; MachineMemOperand *MMO = DAG.getMachineFunction().getMachineMemOperand( N->getPointerInfo(), MachineMemOperand::MOStore, - LocationSize::beforeOrAfterPointer(), Alignment, N->getAAInfo(), - N->getRanges()); + LocationSize::beforeOrAfterPointer(), Alignment, + MMOMetadata(N->getAAInfo(), N->getRanges())); Lo = DAG.getMaskedStore(Ch, DL, DataLo, Ptr, Offset, MaskLo, LoMemVT, MMO, N->getAddressingMode(), N->isTruncatingStore(), @@ -4674,7 +4674,7 @@ SDValue DAGTypeLegalizer::SplitVecOp_MSTORE(MaskedStoreSDNode *N, MMO = DAG.getMachineFunction().getMachineMemOperand( MPI, MachineMemOperand::MOStore, LocationSize::beforeOrAfterPointer(), - Alignment, N->getAAInfo(), N->getRanges()); + Alignment, MMOMetadata(N->getAAInfo(), N->getRanges())); Hi = DAG.getMaskedStore(Ch, DL, DataHi, Ptr, Offset, MaskHi, HiMemVT, MMO, N->getAddressingMode(), N->isTruncatingStore(), @@ -4739,7 +4739,7 @@ SDValue DAGTypeLegalizer::SplitVecOp_Scatter(MemSDNode *N, unsigned OpNo) { MachineMemOperand::Flags MMOFlags = N->getMemOperand()->getFlags(); MachineMemOperand *MMO = DAG.getMachineFunction().getMachineMemOperand( N->getPointerInfo(), MMOFlags, LocationSize::beforeOrAfterPointer(), - Alignment, N->getAAInfo(), N->getRanges()); + Alignment, MMOMetadata(N->getAAInfo(), N->getRanges())); if (auto *MSC = dyn_cast(N)) { SDValue OpsLo[] = {Ch, DataLo, MaskLo, Ptr, IndexLo, Ops.Scale}; diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index 683cf2517b2f5..4f5271f4c1d91 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -30,6 +30,7 @@ #include "llvm/Analysis/VectorUtils.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/CodeGen/Analysis.h" +#include "llvm/CodeGen/CodeGenCommonISel.h" #include "llvm/CodeGen/FunctionLoweringInfo.h" #include "llvm/CodeGen/ISDOpcodes.h" #include "llvm/CodeGen/MachineBasicBlock.h" @@ -1332,8 +1333,14 @@ SelectionDAG::AddModifiedNodeToCSEMaps(SDNode *N) { // to replace the dead one with the existing one. This can cause // recursive merging of other unrelated nodes down the line. Existing->intersectFlagsWith(N->getFlags()); - if (auto *MemNode = dyn_cast(Existing)) - MemNode->refineRanges(cast(N)->memoperands()); + if (auto *MemNode = dyn_cast(Existing)) { + ArrayRef NewMMOs = + cast(N)->memoperands(); + // Range and cache hint metadata are not part of the DAG CSE key because + // we prefer to CSE even when metadata does not match. Merge potentially + // differing metadata conservatively. + MemNode->refineMMOMetadata(NewMMOs); + } ReplaceAllUsesWith(N, Existing); // N is now dead. Inform the listeners and delete it. @@ -9423,7 +9430,8 @@ getMemcpyLoadsAndStores(SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, Align SrcAlign, bool isVol, bool AlwaysInline, MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo, const AAMDNodes &AAInfo, - BatchAAResults *BatchAA) { + BatchAAResults *BatchAA, const MDNode *DstMemCacheHint, + const MDNode *SrcMemCacheHint) { // Turn a memcpy of undef to nop. // FIXME: We need to honor volatile even is Src is undef. if (Src.isUndef()) @@ -9531,7 +9539,8 @@ getMemcpyLoadsAndStores(SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, Store = DAG.getStore( Chain, dl, Value, DAG.getObjectPtrOffset(dl, Dst, TypeSize::getFixed(DstOff)), - DstPtrInfo.getWithOffset(DstOff), DstAlign, MMOFlags, NewAAInfo); + DstPtrInfo.getWithOffset(DstOff), DstAlign, MMOFlags, + MMOMetadata(NewAAInfo, /*Ranges=*/nullptr, DstMemCacheHint)); OutChains.push_back(Store); } } @@ -9557,13 +9566,15 @@ getMemcpyLoadsAndStores(SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, ISD::EXTLOAD, dl, NVT, Chain, DAG.getObjectPtrOffset(dl, Src, TypeSize::getFixed(SrcOff)), SrcPtrInfo.getWithOffset(SrcOff), VT, - commonAlignment(SrcAlign, SrcOff), SrcMMOFlags, NewAAInfo); + commonAlignment(SrcAlign, SrcOff), SrcMMOFlags, + MMOMetadata(NewAAInfo, /*Ranges=*/nullptr, SrcMemCacheHint)); OutLoadChains.push_back(Value.getValue(1)); Store = DAG.getTruncStore( Chain, dl, Value, DAG.getObjectPtrOffset(dl, Dst, TypeSize::getFixed(DstOff)), - DstPtrInfo.getWithOffset(DstOff), VT, DstAlign, MMOFlags, NewAAInfo); + DstPtrInfo.getWithOffset(DstOff), VT, DstAlign, MMOFlags, + MMOMetadata(NewAAInfo, /*Ranges=*/nullptr, DstMemCacheHint)); OutStoreChains.push_back(Store); } SrcOff += VTSize; @@ -10049,6 +10060,11 @@ SDValue SelectionDAG::getMemcpy( const AAMDNodes &AAInfo, BatchAAResults *BatchAA) { // Check to see if we should lower the memcpy to loads and stores first. // For cases within the target-specified limits, this is the best choice. + const MDNode *DstMemCacheHint = + CI ? getMemCacheHintMetadata(*CI, /*OperandNo=*/0) : nullptr; + const MDNode *SrcMemCacheHint = + CI ? getMemCacheHintMetadata(*CI, /*OperandNo=*/1) : nullptr; + ConstantSDNode *ConstantSize = dyn_cast(Size); if (ConstantSize) { // Memcpy with size zero? Just return the original chain. @@ -10057,7 +10073,8 @@ SDValue SelectionDAG::getMemcpy( SDValue Result = getMemcpyLoadsAndStores( *this, dl, Chain, Dst, Src, ConstantSize->getZExtValue(), DstAlign, - SrcAlign, isVol, false, DstPtrInfo, SrcPtrInfo, AAInfo, BatchAA); + SrcAlign, isVol, false, DstPtrInfo, SrcPtrInfo, AAInfo, BatchAA, + DstMemCacheHint, SrcMemCacheHint); if (Result.getNode()) return Result; } @@ -10078,7 +10095,8 @@ SDValue SelectionDAG::getMemcpy( assert(ConstantSize && "AlwaysInline requires a constant size!"); return getMemcpyLoadsAndStores( *this, dl, Chain, Dst, Src, ConstantSize->getZExtValue(), DstAlign, - SrcAlign, isVol, true, DstPtrInfo, SrcPtrInfo, AAInfo, BatchAA); + SrcAlign, isVol, true, DstPtrInfo, SrcPtrInfo, AAInfo, BatchAA, + DstMemCacheHint, SrcMemCacheHint); } checkAddrSpaceIsValidForLibcall(TLI, DstPtrInfo.getAddrSpace()); @@ -10401,7 +10419,7 @@ SDValue SelectionDAG::getAtomic(unsigned Opcode, const SDLoc &dl, EVT MemVT, void* IP = nullptr; if (auto *E = cast_or_null(FindNodeOrInsertPos(ID, dl, IP))) { E->refineAlignment(MMO); - E->refineRanges(MMO); + E->refineMMOMetadata(MMO); return SDValue(E, 0); } @@ -10664,7 +10682,7 @@ SDValue SelectionDAG::getLoad(ISD::MemIndexedMode AM, ISD::LoadExtType ExtType, MachinePointerInfo PtrInfo, EVT MemVT, Align Alignment, MachineMemOperand::Flags MMOFlags, - const AAMDNodes &AAInfo, const MDNode *Ranges) { + const MMOMetadata &Metadata) { assert(Chain.getValueType() == MVT::Other && "Invalid chain type"); @@ -10677,8 +10695,8 @@ SDValue SelectionDAG::getLoad(ISD::MemIndexedMode AM, ISD::LoadExtType ExtType, TypeSize Size = MemVT.getStoreSize(); MachineFunction &MF = getMachineFunction(); - MachineMemOperand *MMO = MF.getMachineMemOperand(PtrInfo, MMOFlags, Size, - Alignment, AAInfo, Ranges); + MachineMemOperand *MMO = + MF.getMachineMemOperand(PtrInfo, MMOFlags, Size, Alignment, Metadata); return getLoad(AM, ExtType, VT, dl, Chain, Ptr, Offset, MemVT, MMO); } @@ -10726,7 +10744,7 @@ SDValue SelectionDAG::getLoad(ISD::MemIndexedMode AM, ISD::LoadExtType ExtType, void *IP = nullptr; if (auto *E = cast_or_null(FindNodeOrInsertPos(ID, dl, IP))) { E->refineAlignment(MMO); - E->refineRanges(MMO); + E->refineMMOMetadata(MMO); return SDValue(E, 0); } auto *N = newSDNode(dl.getIROrder(), dl.getDebugLoc(), VTs, AM, @@ -10744,10 +10762,10 @@ SDValue SelectionDAG::getLoad(EVT VT, const SDLoc &dl, SDValue Chain, SDValue Ptr, MachinePointerInfo PtrInfo, MaybeAlign Alignment, MachineMemOperand::Flags MMOFlags, - const AAMDNodes &AAInfo, const MDNode *Ranges) { + const MMOMetadata &Metadata) { SDValue Undef = getPOISON(Ptr.getValueType()); return getLoad(ISD::UNINDEXED, ISD::NON_EXTLOAD, VT, dl, Chain, Ptr, Undef, - PtrInfo, VT, Alignment, MMOFlags, AAInfo, Ranges); + PtrInfo, VT, Alignment, MMOFlags, Metadata); } SDValue SelectionDAG::getLoad(EVT VT, const SDLoc &dl, SDValue Chain, @@ -10762,10 +10780,10 @@ SDValue SelectionDAG::getExtLoad(ISD::LoadExtType ExtType, const SDLoc &dl, MachinePointerInfo PtrInfo, EVT MemVT, MaybeAlign Alignment, MachineMemOperand::Flags MMOFlags, - const AAMDNodes &AAInfo) { + const MMOMetadata &Metadata) { SDValue Undef = getPOISON(Ptr.getValueType()); return getLoad(ISD::UNINDEXED, ExtType, VT, dl, Chain, Ptr, Undef, PtrInfo, - MemVT, Alignment, MMOFlags, AAInfo); + MemVT, Alignment, MMOFlags, Metadata); } SDValue SelectionDAG::getExtLoad(ISD::LoadExtType ExtType, const SDLoc &dl, @@ -10786,20 +10804,23 @@ SDValue SelectionDAG::getIndexedLoad(SDValue OrigLoad, const SDLoc &dl, auto MMOFlags = LD->getMemOperand()->getFlags() & ~(MachineMemOperand::MOInvariant | MachineMemOperand::MODereferenceable); - return getLoad(AM, LD->getExtensionType(), OrigLoad.getValueType(), dl, - LD->getChain(), Base, Offset, LD->getPointerInfo(), - LD->getMemoryVT(), LD->getAlign(), MMOFlags, LD->getAAInfo()); + return getLoad( + AM, LD->getExtensionType(), OrigLoad.getValueType(), dl, LD->getChain(), + Base, Offset, LD->getPointerInfo(), LD->getMemoryVT(), LD->getAlign(), + MMOFlags, + MMOMetadata(LD->getAAInfo(), LD->getRanges(), LD->getMemCacheHint())); } SDValue SelectionDAG::getStore(SDValue Chain, const SDLoc &dl, SDValue Val, SDValue Ptr, MachinePointerInfo PtrInfo, Align Alignment, MachineMemOperand::Flags MMOFlags, - const AAMDNodes &AAInfo) { + const MMOMetadata &Metadata) { assert(Chain.getValueType() == MVT::Other && "Invalid chain type"); MMOFlags |= MachineMemOperand::MOStore; assert((MMOFlags & MachineMemOperand::MOLoad) == 0); + assert(!Metadata.Ranges && "range metadata is invalid for stores"); if (PtrInfo.V.isNull()) PtrInfo = InferPointerInfo(PtrInfo, *this, Ptr); @@ -10807,7 +10828,7 @@ SDValue SelectionDAG::getStore(SDValue Chain, const SDLoc &dl, SDValue Val, MachineFunction &MF = getMachineFunction(); TypeSize Size = Val.getValueType().getStoreSize(); MachineMemOperand *MMO = - MF.getMachineMemOperand(PtrInfo, MMOFlags, Size, Alignment, AAInfo); + MF.getMachineMemOperand(PtrInfo, MMOFlags, Size, Alignment, Metadata); return getStore(Chain, dl, Val, Ptr, MMO); } @@ -10855,6 +10876,7 @@ SDValue SelectionDAG::getStore(SDValue Chain, const SDLoc &dl, SDValue Val, void *IP = nullptr; if (SDNode *E = FindNodeOrInsertPos(ID, dl, IP)) { cast(E)->refineAlignment(MMO); + cast(E)->refineMMOMetadata(MMO); return SDValue(E, 0); } auto *N = newSDNode(dl.getIROrder(), dl.getDebugLoc(), VTs, AM, @@ -10873,19 +10895,20 @@ SDValue SelectionDAG::getTruncStore(SDValue Chain, const SDLoc &dl, SDValue Val, MachinePointerInfo PtrInfo, EVT SVT, Align Alignment, MachineMemOperand::Flags MMOFlags, - const AAMDNodes &AAInfo) { + const MMOMetadata &Metadata) { assert(Chain.getValueType() == MVT::Other && "Invalid chain type"); MMOFlags |= MachineMemOperand::MOStore; assert((MMOFlags & MachineMemOperand::MOLoad) == 0); + assert(!Metadata.Ranges && "range metadata is invalid for stores"); if (PtrInfo.V.isNull()) PtrInfo = InferPointerInfo(PtrInfo, *this, Ptr); MachineFunction &MF = getMachineFunction(); MachineMemOperand *MMO = MF.getMachineMemOperand( - PtrInfo, MMOFlags, SVT.getStoreSize(), Alignment, AAInfo); + PtrInfo, MMOFlags, SVT.getStoreSize(), Alignment, Metadata); return getTruncStore(Chain, dl, Val, Ptr, Offset, SVT, MMO); } @@ -10893,9 +10916,9 @@ SDValue SelectionDAG::getTruncStore(SDValue Chain, const SDLoc &dl, SDValue Val, SDValue Ptr, MachinePointerInfo PtrInfo, EVT SVT, Align Alignment, MachineMemOperand::Flags MMOFlags, - const AAMDNodes &AAInfo) { + const MMOMetadata &Metadata) { return getTruncStore(Chain, dl, Val, Ptr, getPOISON(Ptr.getValueType()), - PtrInfo, SVT, Alignment, MMOFlags, AAInfo); + PtrInfo, SVT, Alignment, MMOFlags, Metadata); } SDValue SelectionDAG::getTruncStore(SDValue Chain, const SDLoc &dl, SDValue Val, @@ -10937,8 +10960,8 @@ SDValue SelectionDAG::getLoadVP( TypeSize Size = MemVT.getStoreSize(); MachineFunction &MF = getMachineFunction(); - MachineMemOperand *MMO = MF.getMachineMemOperand(PtrInfo, MMOFlags, Size, - Alignment, AAInfo, Ranges); + MachineMemOperand *MMO = MF.getMachineMemOperand( + PtrInfo, MMOFlags, Size, Alignment, MMOMetadata(AAInfo, Ranges)); return getLoadVP(AM, ExtType, VT, dl, Chain, Ptr, Offset, Mask, EVL, MemVT, MMO, IsExpanding); } @@ -10971,7 +10994,7 @@ SDValue SelectionDAG::getLoadVP(ISD::MemIndexedMode AM, void *IP = nullptr; if (auto *E = cast_or_null(FindNodeOrInsertPos(ID, dl, IP))) { E->refineAlignment(MMO); - E->refineRanges(MMO); + E->refineMMOMetadata(MMO); return SDValue(E, 0); } auto *N = newSDNode(dl.getIROrder(), dl.getDebugLoc(), VTs, AM, diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index 385f3729d46c8..dea008fd252a9 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -4759,6 +4759,7 @@ void SelectionDAGBuilder::visitLoad(const LoadInst &I) { Align Alignment = I.getAlign(); AAMDNodes AAInfo = I.getAAMetadata(); const MDNode *Ranges = getRangeMetadata(I); + const MDNode *MemCacheHint = getMemCacheHintMetadata(I); bool isVolatile = I.isVolatile(); MachineMemOperand::Flags MMOFlags = TLI.getLoadMemOperandFlags(I, DAG.getDataLayout(), AC, LibInfo); @@ -4815,8 +4816,9 @@ void SelectionDAGBuilder::visitLoad(const LoadInst &I) { : MachinePointerInfo(); SDValue A = DAG.getObjectPtrOffset(dl, Ptr, Offsets[i]); - SDValue L = DAG.getLoad(MemVTs[i], dl, Root, A, PtrInfo, Alignment, - MMOFlags, AAInfo, Ranges); + SDValue L = + DAG.getLoad(MemVTs[i], dl, Root, A, PtrInfo, Alignment, MMOFlags, + MMOMetadata(AAInfo, Ranges, MemCacheHint)); Chains[ChainI] = L.getValue(1); if (MemVTs[i] != ValueVTs[i]) @@ -4947,6 +4949,8 @@ void SelectionDAGBuilder::visitStore(const StoreInst &I) { SDLoc dl = getCurSDLoc(); Align Alignment = I.getAlign(); AAMDNodes AAInfo = I.getAAMetadata(); + const MDNode *MemCacheHint = + getMemCacheHintMetadata(I, I.getPointerOperandIndex()); auto MMOFlags = TLI.getStoreMemOperandFlags(I, DAG.getDataLayout()); @@ -4971,7 +4975,8 @@ void SelectionDAGBuilder::visitStore(const StoreInst &I) { if (MemVTs[i] != ValueVTs[i]) Val = DAG.getPtrExtOrTrunc(Val, dl, MemVTs[i]); SDValue St = - DAG.getStore(Root, dl, Val, Add, PtrInfo, Alignment, MMOFlags, AAInfo); + DAG.getStore(Root, dl, Val, Add, PtrInfo, Alignment, MMOFlags, + MMOMetadata(AAInfo, /*Ranges=*/nullptr, MemCacheHint)); Chains[ChainI] = St; } @@ -5163,7 +5168,8 @@ void SelectionDAGBuilder::visitMaskedLoad(const CallInst &I, bool IsExpanding) { MachineMemOperand *MMO = DAG.getMachineFunction().getMachineMemOperand( MachinePointerInfo(PtrOperand), MMOFlags, - LocationSize::upperBound(VT.getStoreSize()), Alignment, AAInfo, Ranges); + LocationSize::upperBound(VT.getStoreSize()), Alignment, + MMOMetadata(AAInfo, Ranges)); const auto &TLI = DAG.getTargetLoweringInfo(); @@ -5207,8 +5213,8 @@ void SelectionDAGBuilder::visitMaskedGather(const CallInst &I) { unsigned AS = Ptr->getType()->getScalarType()->getPointerAddressSpace(); MachineMemOperand *MMO = DAG.getMachineFunction().getMachineMemOperand( MachinePointerInfo(AS), MachineMemOperand::MOLoad, - LocationSize::beforeOrAfterPointer(), Alignment, I.getAAMetadata(), - Ranges); + LocationSize::beforeOrAfterPointer(), Alignment, + MMOMetadata(I.getAAMetadata(), Ranges)); if (!UniformBase) { Base = DAG.getConstant(0, sdl, TLI.getPointerTy(DAG.getDataLayout())); @@ -5248,10 +5254,9 @@ void SelectionDAGBuilder::visitAtomicCmpXchg(const AtomicCmpXchgInst &I) { auto Flags = TLI.getAtomicMemOperandFlags(I, DAG.getDataLayout()); MachineFunction &MF = DAG.getMachineFunction(); - MachineMemOperand *MMO = - MF.getMachineMemOperand(MachinePointerInfo(I.getPointerOperand()), Flags, - MemVT.getStoreSize(), I.getAlign(), AAMDNodes(), - nullptr, SSID, SuccessOrdering, FailureOrdering); + MachineMemOperand *MMO = MF.getMachineMemOperand( + MachinePointerInfo(I.getPointerOperand()), Flags, MemVT.getStoreSize(), + I.getAlign(), MMOMetadata(), SSID, SuccessOrdering, FailureOrdering); SDValue L = DAG.getAtomicCmpSwap(ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS, dl, MemVT, VTs, InChain, @@ -5322,7 +5327,7 @@ void SelectionDAGBuilder::visitAtomicRMW(const AtomicRMWInst &I) { MachineFunction &MF = DAG.getMachineFunction(); MachineMemOperand *MMO = MF.getMachineMemOperand( MachinePointerInfo(I.getPointerOperand()), Flags, MemVT.getStoreSize(), - I.getAlign(), AAMDNodes(), nullptr, SSID, Ordering); + I.getAlign(), MMOMetadata(), SSID, Ordering); SDValue L = DAG.getAtomic(NT, dl, MemVT, InChain, @@ -5369,7 +5374,7 @@ void SelectionDAGBuilder::visitAtomicLoad(const LoadInst &I) { const MDNode *Ranges = getRangeMetadata(I); MachineMemOperand *MMO = DAG.getMachineFunction().getMachineMemOperand( MachinePointerInfo(I.getPointerOperand()), Flags, MemVT.getStoreSize(), - I.getAlign(), AAMDNodes(), Ranges, SSID, Order); + I.getAlign(), MMOMetadata(AAMDNodes(), Ranges), SSID, Order); InChain = TLI.prepareVolatileOrAtomicLoad(InChain, dl, DAG); @@ -5406,7 +5411,7 @@ void SelectionDAGBuilder::visitAtomicStore(const StoreInst &I) { MachineFunction &MF = DAG.getMachineFunction(); MachineMemOperand *MMO = MF.getMachineMemOperand( MachinePointerInfo(I.getPointerOperand()), Flags, MemVT.getStoreSize(), - I.getAlign(), AAMDNodes(), nullptr, SSID, Ordering); + I.getAlign(), MMOMetadata(), SSID, Ordering); SDValue Val = getValue(I.getValueOperand()); if (Val.getValueType() != MemVT) @@ -5613,8 +5618,8 @@ void SelectionDAGBuilder::visitTargetIntrinsic(const CallInst &I, Size = LocationSize::precise(MemVT.getStoreSize()); Align Alignment = Info.align.value_or(DAG.getEVTAlign(MemVT)); MachineMemOperand *MMO = MF.getMachineMemOperand( - MPI, Info.flags, Size, Alignment, I.getAAMetadata(), - /*Ranges=*/nullptr, Info.ssid, Info.order, Info.failureOrder); + MPI, Info.flags, Size, Alignment, I.getAAMetadata(), Info.ssid, + Info.order, Info.failureOrder); MMOs.push_back(MMO); } @@ -6624,7 +6629,8 @@ void SelectionDAGBuilder::visitVectorHistogram(const CallInst &I, MachineMemOperand *MMO = DAG.getMachineFunction().getMachineMemOperand( MachinePointerInfo(AS), MachineMemOperand::MOLoad | MachineMemOperand::MOStore, - MemoryLocation::UnknownSize, Alignment, I.getAAMetadata(), Ranges); + MemoryLocation::UnknownSize, Alignment, + MMOMetadata(I.getAAMetadata(), Ranges)); if (!UniformBase) { Base = DAG.getConstant(0, sdl, TLI.getPointerTy(DAG.getDataLayout())); @@ -8826,7 +8832,8 @@ void SelectionDAGBuilder::visitVPLoad( TLI.getVPIntrinsicMemOperandFlags(VPIntrin); MachineMemOperand *MMO = DAG.getMachineFunction().getMachineMemOperand( MachinePointerInfo(PtrOperand), MMOFlags, - LocationSize::beforeOrAfterPointer(), *Alignment, AAInfo, Ranges); + LocationSize::beforeOrAfterPointer(), *Alignment, + MMOMetadata(AAInfo, Ranges)); LD = DAG.getLoadVP(VT, DL, InChain, OpValues[0], OpValues[1], OpValues[2], MMO, false /*IsExpanding */); if (AddToChain) @@ -8853,7 +8860,8 @@ void SelectionDAGBuilder::visitVPLoadFF( SDValue InChain = AddToChain ? DAG.getRoot() : DAG.getEntryNode(); MachineMemOperand *MMO = DAG.getMachineFunction().getMachineMemOperand( MachinePointerInfo(PtrOperand), MachineMemOperand::MOLoad, - LocationSize::beforeOrAfterPointer(), *Alignment, AAInfo, Ranges); + LocationSize::beforeOrAfterPointer(), *Alignment, + MMOMetadata(AAInfo, Ranges)); LD = DAG.getLoadFFVP(VT, DL, InChain, OpValues[0], OpValues[1], OpValues[2], MMO); SDValue Trunc = DAG.getNode(ISD::TRUNCATE, DL, EVLVT, LD.getValue(1)); @@ -8880,7 +8888,7 @@ void SelectionDAGBuilder::visitVPGather( TLI.getVPIntrinsicMemOperandFlags(VPIntrin); MachineMemOperand *MMO = DAG.getMachineFunction().getMachineMemOperand( MachinePointerInfo(AS), MMOFlags, LocationSize::beforeOrAfterPointer(), - *Alignment, AAInfo, Ranges); + *Alignment, MMOMetadata(AAInfo, Ranges)); SDValue Base, Index, Scale; bool UniformBase = getUniformBase(PtrOperand, Base, Index, Scale, this, VPIntrin.getParent(), @@ -8989,7 +8997,7 @@ void SelectionDAGBuilder::visitVPStridedLoad( TLI.getVPIntrinsicMemOperandFlags(VPIntrin); MachineMemOperand *MMO = DAG.getMachineFunction().getMachineMemOperand( MachinePointerInfo(AS), MMOFlags, LocationSize::beforeOrAfterPointer(), - *Alignment, AAInfo, Ranges); + *Alignment, MMOMetadata(AAInfo, Ranges)); SDValue LD = DAG.getStridedLoadVP(VT, DL, InChain, OpValues[0], OpValues[1], OpValues[2], OpValues[3], MMO, diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp index 72774c7ea97b0..f53fd0d74e48e 100644 --- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp +++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp @@ -13343,8 +13343,7 @@ SDValue SITargetLowering::widenLoad(LoadSDNode *Ld, SDValue NewLoad = DAG.getLoad( ISD::UNINDEXED, ISD::NON_EXTLOAD, MVT::i32, SL, Ld->getChain(), Ptr, Ld->getOffset(), Ld->getPointerInfo(), MVT::i32, Ld->getAlign(), - Ld->getMemOperand()->getFlags(), Ld->getAAInfo(), - nullptr); // Drop ranges + Ld->getMemOperand()->getFlags(), Ld->getAAInfo()); // Drop ranges EVT TruncVT = EVT::getIntegerVT(*DAG.getContext(), MemVT.getSizeInBits()); if (MemVT.isFloatingPoint()) { diff --git a/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp b/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp index 47e8a556df6ef..ac3ffa4b9bb0f 100644 --- a/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp +++ b/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp @@ -3093,7 +3093,7 @@ HexagonTargetLowering::LowerLoad(SDValue Op, SelectionDAG &DAG) const { LN->getAddressingMode(), ISD::ZEXTLOAD, MVT::i32, dl, LN->getChain(), LN->getBasePtr(), LN->getOffset(), LN->getPointerInfo(), /*MemoryVT*/ MVT::i8, LN->getAlign(), LN->getMemOperand()->getFlags(), - LN->getAAInfo(), LN->getRanges()); + MMOMetadata(LN->getAAInfo(), LN->getRanges())); LN = cast(NL.getNode()); } @@ -3220,7 +3220,7 @@ HexagonTargetLowering::LowerUnalignedLoad(SDValue Op, SelectionDAG &DAG) MachineFunction &MF = DAG.getMachineFunction(); WideMMO = MF.getMachineMemOperand( MMO->getPointerInfo(), MMO->getFlags(), 2 * LoadLen, Align(LoadLen), - MMO->getAAInfo(), MMO->getRanges(), MMO->getSyncScopeID(), + MMOMetadata(MMO->getAAInfo(), MMO->getRanges()), MMO->getSyncScopeID(), MMO->getSuccessOrdering(), MMO->getFailureOrdering()); } diff --git a/llvm/lib/Target/NVPTX/MCTargetDesc/NVPTXInstPrinter.cpp b/llvm/lib/Target/NVPTX/MCTargetDesc/NVPTXInstPrinter.cpp index e013fd3126aa5..3e8fe7ec2fc92 100644 --- a/llvm/lib/Target/NVPTX/MCTargetDesc/NVPTXInstPrinter.cpp +++ b/llvm/lib/Target/NVPTX/MCTargetDesc/NVPTXInstPrinter.cpp @@ -372,6 +372,80 @@ void NVPTXInstPrinter::printAtomicCode(const MCInst *MI, int OpNum, llvm_unreachable(formatv("Unknown Modifier: {}", Modifier).str().c_str()); } +void NVPTXInstPrinter::printEvictionAndPrefetchHint(const MCInst *MI, int OpNum, + const MCSubtargetInfo &, + raw_ostream &O, + StringRef Modifier) { + const MCOperand &MO = MI->getOperand(OpNum); + unsigned Hint = MO.getImm(); + + // If no hint is set, print nothing. + if (Hint == 0) + return; + + // Check if L2::cache_hint mode is active. + bool IsCacheHintMode = NVPTX::isL2CacheHintMode(Hint); + + if (Modifier == "l1") { + switch (NVPTX::decodeL1Eviction(Hint)) { + case NVPTX::L1Eviction::Normal: + return; + case NVPTX::L1Eviction::Unchanged: + O << ".L1::evict_unchanged"; + return; + case NVPTX::L1Eviction::First: + O << ".L1::evict_first"; + return; + case NVPTX::L1Eviction::Last: + O << ".L1::evict_last"; + return; + case NVPTX::L1Eviction::NoAllocate: + O << ".L1::no_allocate"; + return; + } + } else if (Modifier == "l2") { + switch (NVPTX::decodeL2Eviction(Hint)) { + case NVPTX::L2Eviction::Normal: + break; + case NVPTX::L2Eviction::First: + O << ".L2::evict_first"; + break; + case NVPTX::L2Eviction::Last: + O << ".L2::evict_last"; + break; + } + if (IsCacheHintMode) + O << ".L2::cache_hint"; + return; + } else if (Modifier == "prefetch") { + switch (NVPTX::decodeL2Prefetch(Hint)) { + case NVPTX::L2Prefetch::None: + return; + case NVPTX::L2Prefetch::Bytes64: + O << ".L2::64B"; + return; + case NVPTX::L2Prefetch::Bytes128: + O << ".L2::128B"; + return; + case NVPTX::L2Prefetch::Bytes256: + O << ".L2::256B"; + return; + } + } + llvm_unreachable(formatv("Unknown Modifier: {}", Modifier).str().c_str()); +} + +void NVPTXInstPrinter::printCachePolicy(const MCInst *MI, int OpNum, + const MCSubtargetInfo &, + raw_ostream &O) { + const MCOperand &MO = MI->getOperand(OpNum); + // If the operand is a register and valid, print ", $reg" + if (MO.isReg() && MO.getReg().isValid()) { + O << ", "; + printRegName(O, MO.getReg()); + } +} + void NVPTXInstPrinter::printMmaCode(const MCInst *MI, int OpNum, const MCSubtargetInfo &, raw_ostream &O, StringRef Modifier) { diff --git a/llvm/lib/Target/NVPTX/MCTargetDesc/NVPTXInstPrinter.h b/llvm/lib/Target/NVPTX/MCTargetDesc/NVPTXInstPrinter.h index acd7822f1fc5a..69fff1c1c7402 100644 --- a/llvm/lib/Target/NVPTX/MCTargetDesc/NVPTXInstPrinter.h +++ b/llvm/lib/Target/NVPTX/MCTargetDesc/NVPTXInstPrinter.h @@ -44,6 +44,11 @@ class NVPTXInstPrinter : public MCInstPrinter { raw_ostream &O, StringRef Modifier = {}); void printAtomicCode(const MCInst *MI, int OpNum, const MCSubtargetInfo &STI, raw_ostream &O, StringRef Modifier = {}); + void printEvictionAndPrefetchHint(const MCInst *MI, int OpNum, + const MCSubtargetInfo &STI, raw_ostream &O, + StringRef Modifier = {}); + void printCachePolicy(const MCInst *MI, int OpNum, const MCSubtargetInfo &STI, + raw_ostream &O); void printMmaCode(const MCInst *MI, int OpNum, const MCSubtargetInfo &STI, raw_ostream &O, StringRef Modifier = {}); void printMemOperand(const MCInst *MI, int OpNum, const MCSubtargetInfo &STI, diff --git a/llvm/lib/Target/NVPTX/NVPTX.h b/llvm/lib/Target/NVPTX/NVPTX.h index 914295bf76e93..79726c4a8f184 100644 --- a/llvm/lib/Target/NVPTX/NVPTX.h +++ b/llvm/lib/Target/NVPTX/NVPTX.h @@ -14,6 +14,7 @@ #ifndef LLVM_LIB_TARGET_NVPTX_NVPTX_H #define LLVM_LIB_TARGET_NVPTX_NVPTX_H +#include "llvm/ADT/Bitfields.h" #include "llvm/IR/PassManager.h" #include "llvm/Pass.h" #include "llvm/Support/AtomicOrdering.h" @@ -217,6 +218,73 @@ enum AddressSpace : AddressSpaceUnderlyingType { DeviceParam }; +// Eviction and prefetch hint enums for !mem.cache_hint metadata. These +// correspond to PTX L1::evict_*, L2::evict_*, and L2::*B qualifiers. + +// L1 Eviction Policy - maps to PTX L1::evict_* qualifiers +enum class L1Eviction : uint8_t { + Normal = 0, // Default behavior (no qualifier) + Unchanged = 1, // L1::evict_unchanged + First = 2, // L1::evict_first + Last = 3, // L1::evict_last + NoAllocate = 4, // L1::no_allocate +}; + +// L2 Eviction Policy - maps to PTX L2::evict_* qualifiers +enum class L2Eviction : uint8_t { + Normal = 0, // Default behavior (no qualifier) + First = 1, // L2::evict_first + Last = 2, // L2::evict_last +}; + +// L2 Prefetch Size - maps to PTX L2::*B qualifiers +enum class L2Prefetch : uint8_t { + None = 0, // No prefetch hint + Bytes64 = 1, // L2::64B + Bytes128 = 2, // L2::128B + Bytes256 = 3, // L2::256B +}; + +// Bitfield layout for encoded eviction/prefetch hints (stored in unsigned): +// Bits 0-2: L1 Eviction (3 bits, 5 values) +// Bits 3-4: L2 Eviction (2 bits, 3 values) +// Bits 5-6: L2 Prefetch (2 bits, 4 values) +// Bit 7: L2::cache_hint mode flag (set when using CachePolicy) +// Bits 8-31: Reserved +// +// Using llvm::Bitfield for type-safe access with compile-time validation. +using L1EvictionBits = + Bitfield::Element; +using L2EvictionBits = Bitfield::Element; +using L2PrefetchBits = + Bitfield::Element; +using L2CacheHintBit = Bitfield::Element; + +inline unsigned encodeEvictionAndPrefetchHint(L1Eviction L1, L2Eviction L2, + L2Prefetch P) { + unsigned Hint = 0; + Bitfield::set(Hint, L1); + Bitfield::set(Hint, L2); + Bitfield::set(Hint, P); + return Hint; +} + +inline L1Eviction decodeL1Eviction(unsigned Hint) { + return Bitfield::get(Hint); +} + +inline L2Eviction decodeL2Eviction(unsigned Hint) { + return Bitfield::get(Hint); +} + +inline L2Prefetch decodeL2Prefetch(unsigned Hint) { + return Bitfield::get(Hint); +} + +inline bool isL2CacheHintMode(unsigned Hint) { + return Bitfield::get(Hint); +} + namespace PTXLdStInstCode { enum FromType { Unsigned = 0, Signed, Float, Untyped }; } // namespace PTXLdStInstCode @@ -293,7 +361,8 @@ void initializeNVPTXDAGToDAGISelLegacyPass(PassRegistry &); #define GET_REGINFO_ENUM #include "NVPTXGenRegisterInfo.inc" -// Defines symbolic names for the NVPTX instructions. +// Defines symbolic names for NVPTX instructions, MC helper declarations, +// and named operand helpers generated from UseNamedOperandTable=1. #define GET_INSTRINFO_ENUM #define GET_INSTRINFO_MC_HELPER_DECLS #define GET_INSTRINFO_OPERAND_ENUM diff --git a/llvm/lib/Target/NVPTX/NVPTXForwardParams.cpp b/llvm/lib/Target/NVPTX/NVPTXForwardParams.cpp index 547e6e133ce14..d7703fbde48fd 100644 --- a/llvm/lib/Target/NVPTX/NVPTXForwardParams.cpp +++ b/llvm/lib/Target/NVPTX/NVPTXForwardParams.cpp @@ -96,13 +96,30 @@ static bool eliminateMove(MachineInstr &Mov, const MachineRegisterInfo &MRI, const MachineOperand *ParamSymbol = Mov.uses().begin(); assert(ParamSymbol->isSymbol()); - constexpr unsigned LDInstBasePtrOpIdx = 6; - constexpr unsigned LDInstAddrSpaceOpIdx = 2; - for (auto *LI : LoadInsts) { - (LI->uses().begin() + LDInstBasePtrOpIdx) - ->ChangeToES(ParamSymbol->getSymbolName()); - (LI->uses().begin() + LDInstAddrSpaceOpIdx) - ->ChangeToImmediate(NVPTX::AddressSpace::DeviceParam); + for (MachineInstr *LI : LoadInsts) { + unsigned Opc = LI->getOpcode(); + int Idx = getNamedOperandIdx(Opc, NVPTX::OpName::addr); + assert(Idx != -1 && "no addr operand"); + LI->getOperand(Idx).ChangeToES(ParamSymbol->getSymbolName()); + + Idx = getNamedOperandIdx(Opc, NVPTX::OpName::addsp); + assert(Idx != -1 && "no addsp operand"); + LI->getOperand(Idx).ChangeToImmediate(NVPTX::AddressSpace::DeviceParam); + // PTX cache hints and policy are not allowed on ld.param + Idx = getNamedOperandIdx(Opc, NVPTX::OpName::evictionAndPrefetchHint); + assert(Idx != -1 && "no evictionAndPrefetchHint operand"); + LI->getOperand(Idx).ChangeToImmediate(0); + + Idx = getNamedOperandIdx(Opc, NVPTX::OpName::policy); + assert(Idx != -1 && "no policy operand"); + MachineOperand &Policy = LI->getOperand(Idx); + Register PolicyReg = Policy.getReg(); + MachineInstr *PolicyDef = + PolicyReg.isValid() ? MRI.getVRegDef(PolicyReg) : nullptr; + Policy.ChangeToRegister(NVPTX::NoRegister, false); + // Remove the policy register's definition if it is now dead. + if (PolicyDef && PolicyDef->isDead(MRI)) + RemoveList.push_back(PolicyDef); } return true; } diff --git a/llvm/lib/Target/NVPTX/NVPTXISelDAGToDAG.cpp b/llvm/lib/Target/NVPTX/NVPTXISelDAGToDAG.cpp index 0536284c75672..f3db3c354c290 100644 --- a/llvm/lib/Target/NVPTX/NVPTXISelDAGToDAG.cpp +++ b/llvm/lib/Target/NVPTX/NVPTXISelDAGToDAG.cpp @@ -18,16 +18,23 @@ #include "NVPTXUtilities.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/MapVector.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Twine.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/CodeGen/ISDOpcodes.h" #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/CodeGen/SelectionDAGISel.h" #include "llvm/CodeGen/SelectionDAGNodes.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/IntrinsicsNVPTX.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Metadata.h" +#include "llvm/IR/NVVMIntrinsicUtils.h" #include "llvm/Support/AtomicOrdering.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" @@ -65,6 +72,13 @@ struct NVPTXScopes { LLVMContext *Context = nullptr; }; +struct NVPTXMemCacheHintAccess { + NVPTX::AddressSpace AddrSpace; + bool IsLoad; + unsigned NumElts; + unsigned EltWidth; +}; + class NVPTXDAGToDAGISel : public SelectionDAGISel { const NVPTXTargetMachine &TM; @@ -129,6 +143,15 @@ class NVPTXDAGToDAGISel : public SelectionDAGISel { SDValue getPTXCmpMode(const CondCodeSDNode &CondCode); SDValue selectPossiblyImm(SDValue V); + // Returns the encoded eviction/prefetch hint and cache policy register for a + // memory operation. Hints unsupported by the subtarget or address space are + // dropped. If L2::cache_hint is active, returns the hint with + // L2CacheHintBit set and a register containing the 64-bit cache policy + // value. Otherwise returns NOREG for the policy operand. + std::pair + getMemCacheHintOperands(const MemSDNode *N, NVPTXMemCacheHintAccess Access, + const SDLoc &DL); + // Returns the Memory Order and Scope that the PTX memory instruction should // use, and inserts appropriate fence instruction before the memory // instruction, if needed to implement the instructions memory order. Required @@ -1117,6 +1140,164 @@ bool NVPTXDAGToDAGISel::SelectADDR(SDValue Addr, SDValue &Base, return true; } +static void emitInvalidMemCacheHint(LLVMContext &Ctx, const Twine &Msg) { + Ctx.diagnose(DiagnosticInfoGeneric( + Twine("invalid NVPTX !mem.cache_hint metadata: ") + Msg, DS_Warning)); +} + +static std::optional parseL1Eviction(StringRef Str) { + return StringSwitch>(Str) + .Case("normal", NVPTX::L1Eviction::Normal) + .Case("unchanged", NVPTX::L1Eviction::Unchanged) + .Case("first", NVPTX::L1Eviction::First) + .Case("last", NVPTX::L1Eviction::Last) + .Case("no_allocate", NVPTX::L1Eviction::NoAllocate) + .Default(std::nullopt); +} + +static std::optional parseL2Eviction(StringRef Str) { + return StringSwitch>(Str) + .Case("normal", NVPTX::L2Eviction::Normal) + .Case("first", NVPTX::L2Eviction::First) + .Case("last", NVPTX::L2Eviction::Last) + .Default(std::nullopt); +} + +static std::optional parseL2Prefetch(StringRef Str) { + return StringSwitch>(Str) + .Case("64B", NVPTX::L2Prefetch::Bytes64) + .Case("128B", NVPTX::L2Prefetch::Bytes128) + .Case("256B", NVPTX::L2Prefetch::Bytes256) + .Default(std::nullopt); +} + +template +static std::optional +parseMemCacheHintStringValue(LLVMContext &Ctx, StringRef Key, + const Metadata *Value, + std::optional (*Parse)(StringRef)) { + const auto *Val = dyn_cast(Value); + if (!Val) { + emitInvalidMemCacheHint(Ctx, Twine("'") + Key + "' expects a string value"); + return std::nullopt; + } + + StringRef ValStr = Val->getString(); + auto Parsed = Parse(ValStr); + if (!Parsed) + emitInvalidMemCacheHint(Ctx, Twine("unknown value '") + ValStr + "' for '" + + Key + "'"); + return Parsed; +} + +static bool isGlobalOrGeneric(NVPTX::AddressSpace AddrSpace) { + return AddrSpace == NVPTX::AddressSpace::Global || + AddrSpace == NVPTX::AddressSpace::Generic; +} + +static bool isL2PrefetchSupported(const NVPTXSubtarget &Subtarget, + NVPTX::L2Prefetch Prefetch, + NVPTXMemCacheHintAccess Access) { + switch (Prefetch) { + case NVPTX::L2Prefetch::None: + return true; + case NVPTX::L2Prefetch::Bytes64: + return Access.IsLoad && isGlobalOrGeneric(Access.AddrSpace) && + Subtarget.hasL2Prefetch64B(); + case NVPTX::L2Prefetch::Bytes128: + return Access.IsLoad && isGlobalOrGeneric(Access.AddrSpace) && + Subtarget.hasL2Prefetch128B(); + case NVPTX::L2Prefetch::Bytes256: + return Access.IsLoad && isGlobalOrGeneric(Access.AddrSpace) && + Subtarget.hasL2Prefetch256B(); + } + llvm_unreachable("Unexpected L2 prefetch hint"); +} + +static bool isL2EvictionSupported(const NVPTXSubtarget &Subtarget, + NVPTX::L2Eviction Eviction, + NVPTXMemCacheHintAccess Access) { + if (Eviction == NVPTX::L2Eviction::Normal) + return true; + + return Subtarget.hasL2EvictionHint() && isGlobalOrGeneric(Access.AddrSpace) && + ((Access.NumElts == 8 && Access.EltWidth == 32) || + (Access.NumElts == 4 && Access.EltWidth == 64)); +} + +std::pair NVPTXDAGToDAGISel::getMemCacheHintOperands( + const MemSDNode *N, NVPTXMemCacheHintAccess Access, const SDLoc &DL) { + LLVMContext &Ctx = *CurDAG->getContext(); + const MDNode *Node = N->getMemCacheHint(); + SDValue PolicyReg = CurDAG->getRegister(NVPTX::NoRegister, MVT::i64); + if (!Node) + return {0, PolicyReg}; + if (Node->getNumOperands() == 0) { + emitInvalidMemCacheHint(Ctx, "empty hint node"); + return {0, PolicyReg}; + } + + NVPTX::L1Eviction L1 = NVPTX::L1Eviction::Normal; + NVPTX::L2Eviction L2 = NVPTX::L2Eviction::Normal; + NVPTX::L2Prefetch Prefetch = NVPTX::L2Prefetch::None; + std::optional CachePolicy; + + for (unsigned I = 0; I + 1 < Node->getNumOperands(); I += 2) { + const auto *Key = cast(Node->getOperand(I)); + StringRef KeyStr = Key->getString(); + const Metadata *Value = Node->getOperand(I + 1).get(); + + if (KeyStr == "nvvm.l1_eviction") { + auto ParsedL1 = + parseMemCacheHintStringValue(Ctx, KeyStr, Value, parseL1Eviction); + if (ParsedL1 && Subtarget->hasL1EvictionHint()) + L1 = *ParsedL1; + continue; + } + + if (KeyStr == "nvvm.l2_eviction") { + auto ParsedL2 = + parseMemCacheHintStringValue(Ctx, KeyStr, Value, parseL2Eviction); + if (ParsedL2 && isL2EvictionSupported(*Subtarget, *ParsedL2, Access)) + L2 = *ParsedL2; + continue; + } + + if (KeyStr == "nvvm.l2_prefetch_size") { + auto ParsedPrefetch = + parseMemCacheHintStringValue(Ctx, KeyStr, Value, parseL2Prefetch); + if (ParsedPrefetch && + isL2PrefetchSupported(*Subtarget, *ParsedPrefetch, Access)) + Prefetch = *ParsedPrefetch; + continue; + } + + if (KeyStr == "nvvm.l2_cache_hint") { + const auto *ValCI = mdconst::dyn_extract(Value); + if (!ValCI) + emitInvalidMemCacheHint( + Ctx, "'nvvm.l2_cache_hint' expects an integer value"); + else if (isGlobalOrGeneric(Access.AddrSpace) && + Subtarget->hasL2CacheHint()) + CachePolicy = ValCI->getZExtValue(); + continue; + } + + emitInvalidMemCacheHint(Ctx, Twine("unknown key '") + KeyStr + "'"); + } + + unsigned EvictionAndPrefetchHint = + NVPTX::encodeEvictionAndPrefetchHint(L1, L2, Prefetch); + if (CachePolicy) { + SDValue PolicyConst = CurDAG->getTargetConstant(*CachePolicy, DL, MVT::i64); + PolicyReg = SDValue( + CurDAG->getMachineNode(NVPTX::MOV_B64_i, DL, MVT::i64, PolicyConst), 0); + Bitfield::set(EvictionAndPrefetchHint, true); + } + + return {EvictionAndPrefetchHint, PolicyReg}; +} + bool NVPTXDAGToDAGISel::tryLoad(SDNode *N) { MemSDNode *LD = cast(N); assert(LD->readMem() && "Expected load"); @@ -1159,8 +1340,14 @@ bool NVPTXDAGToDAGISel::tryLoad(SDNode *N) { assert(isPowerOf2_32(FromTypeWidth) && FromTypeWidth >= 8 && FromTypeWidth <= 128 && "Invalid width for load"); - // Create the machine instruction DAG const auto [Base, Offset] = selectADDR(N->getOperand(1), CurDAG); + const auto [EvictionAndPrefetchHint, PolicyReg] = + getMemCacheHintOperands(LD, + {CodeAddrSpace, /*IsLoad=*/true, + /*NumElts=*/1, /*EltWidth=*/FromTypeWidth}, + DL); + + // Create the machine instruction DAG SDValue Ops[] = {getI32Imm(Ordering, DL), getI32Imm(Scope, DL), getI32Imm(CodeAddrSpace, DL), @@ -1169,6 +1356,8 @@ bool NVPTXDAGToDAGISel::tryLoad(SDNode *N) { getI32Imm(UsedBytesMask, DL), Base, Offset, + getI32Imm(EvictionAndPrefetchHint, DL), + PolicyReg, Chain}; const MVT::SimpleValueType TargetVT = LD->getSimpleValueType(0).SimpleTy; @@ -1232,6 +1421,11 @@ bool NVPTXDAGToDAGISel::tryLoadVector(SDNode *N) { assert(!(EltVT.isVector() && ExtensionType != ISD::NON_EXTLOAD)); + const auto [EvictionAndPrefetchHint, PolicyReg] = getMemCacheHintOperands( + LD, + {CodeAddrSpace, /*IsLoad=*/true, + /*NumElts=*/LD->getNumValues() - 1, /*EltWidth=*/FromTypeWidth}, + DL); const auto [Base, Offset] = selectADDR(N->getOperand(1), CurDAG); SDValue Ops[] = {getI32Imm(Ordering, DL), getI32Imm(Scope, DL), @@ -1241,6 +1435,8 @@ bool NVPTXDAGToDAGISel::tryLoadVector(SDNode *N) { getI32Imm(UsedBytesMask, DL), Base, Offset, + getI32Imm(EvictionAndPrefetchHint, DL), + PolicyReg, Chain}; std::optional Opcode; @@ -1294,11 +1490,18 @@ bool NVPTXDAGToDAGISel::tryLDG(MemSDNode *LD) { ExtensionType != ISD::NON_EXTLOAD)); const auto [Base, Offset] = selectADDR(LD->getOperand(1), CurDAG); + const auto [EvictionAndPrefetchHint, PolicyReg] = getMemCacheHintOperands( + LD, + {NVPTX::AddressSpace::Global, + /*IsLoad=*/true, LD->getNumValues() - 1, FromTypeWidth}, + DL); SDValue Ops[] = {getI32Imm(FromType, DL), getI32Imm(FromTypeWidth, DL), getI32Imm(UsedBytesMask, DL), Base, Offset, + getI32Imm(EvictionAndPrefetchHint, DL), + PolicyReg, LD->getChain()}; const MVT::SimpleValueType TargetVT = LD->getSimpleValueType(0).SimpleTy; @@ -1407,6 +1610,14 @@ bool NVPTXDAGToDAGISel::tryStore(SDNode *N) { "Invalid width for store"); const auto [Base, Offset] = selectADDR(ST->getBasePtr(), CurDAG); + + // Extract eviction/prefetch hint and cache policy register. + const auto [EvictionAndPrefetchHint, PolicyReg] = + getMemCacheHintOperands(ST, + {CodeAddrSpace, /*IsLoad=*/false, + /*NumElts=*/1, /*EltWidth=*/ToTypeWidth}, + DL); + SDValue Ops[] = {selectPossiblyImm(Value), getI32Imm(Ordering, DL), getI32Imm(Scope, DL), @@ -1414,6 +1625,8 @@ bool NVPTXDAGToDAGISel::tryStore(SDNode *N) { getI32Imm(ToTypeWidth, DL), Base, Offset, + getI32Imm(EvictionAndPrefetchHint, DL), + PolicyReg, Chain}; const std::optional Opcode = @@ -1459,10 +1672,18 @@ bool NVPTXDAGToDAGISel::tryStoreVector(SDNode *N) { assert(isPowerOf2_32(ToTypeWidth) && ToTypeWidth >= 8 && ToTypeWidth <= 128 && TotalWidth <= 256 && "Invalid width for store"); + // Extract eviction/prefetch hint and cache policy register. + const auto [EvictionAndPrefetchHint, PolicyReg] = getMemCacheHintOperands( + ST, + {CodeAddrSpace, /*IsLoad=*/false, /*NumElts=*/NumElts, + /*EltWidth=*/ToTypeWidth}, + DL); + const auto [Base, Offset] = selectADDR(Addr, CurDAG); Ops.append({getI32Imm(Ordering, DL), getI32Imm(Scope, DL), getI32Imm(CodeAddrSpace, DL), getI32Imm(ToTypeWidth, DL), Base, - Offset, Chain}); + Offset, getI32Imm(EvictionAndPrefetchHint, DL), PolicyReg, + Chain}); const MVT::SimpleValueType EltVT = ST->getOperand(1).getSimpleValueType().SimpleTy; diff --git a/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td b/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td index 6d9ef347d616d..0fcdd05756e86 100644 --- a/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td +++ b/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td @@ -1723,6 +1723,10 @@ def AtomicCode : Operand { let PrintMethod = "printAtomicCode"; } +def EvictionAndPrefetchHint : Operand { + let PrintMethod = "printEvictionAndPrefetchHint"; +} + def MmaCode : Operand { let PrintMethod = "printMmaCode"; } @@ -1948,15 +1952,22 @@ def Callseq_End : // // Load / Store Handling // +// CachePolicy operand for L2::cache_hint support. +// When present, prints the cache policy register. +def CachePolicy : Operand { let PrintMethod = "printCachePolicy"; } + class LD - : NVPTXInst< - (outs regclass:$dst), - (ins AtomicCode:$sem, AtomicCode:$scope, AtomicCode:$addsp, - AtomicCode:$Sign, i32imm:$fromWidth, UsedBytesMask:$usedBytes, - ADDR:$addr), - "${usedBytes}" - "ld${sem:sem}${scope:scope}${addsp:addsp}.${Sign:sign}$fromWidth " - "\t$dst, [$addr];">; + : NVPTXInst< + (outs regclass:$dst), + (ins AtomicCode:$sem, AtomicCode:$scope, AtomicCode:$addsp, + AtomicCode:$Sign, i32imm:$fromWidth, UsedBytesMask:$usedBytes, + ADDR:$addr, EvictionAndPrefetchHint:$evictionAndPrefetchHint, + CachePolicy:$policy), + "${usedBytes}" + "ld${sem:sem}${scope:scope}${addsp:addsp}${evictionAndPrefetchHint:l1}${" + "evictionAndPrefetchHint:l2}${evictionAndPrefetchHint:prefetch}.${Sign:sign}$" + "fromWidth " + "\t$dst, [$addr]${policy};">; let mayLoad=1, hasSideEffects=0 in { def LD_i16 : LD; @@ -1965,13 +1976,15 @@ let mayLoad=1, hasSideEffects=0 in { } class ST - : NVPTXInst< - (outs), - (ins O:$src, - AtomicCode:$sem, AtomicCode:$scope, AtomicCode:$addsp, i32imm:$toWidth, - ADDR:$addr), - "st${sem:sem}${scope:scope}${addsp:addsp}.b$toWidth" - " \t[$addr], $src;">; + : NVPTXInst< + (outs), + (ins O:$src, AtomicCode:$sem, AtomicCode:$scope, AtomicCode:$addsp, + i32imm:$toWidth, ADDR:$addr, + EvictionAndPrefetchHint:$evictionAndPrefetchHint, + CachePolicy:$policy), + "st${sem:sem}${scope:scope}${addsp:addsp}${evictionAndPrefetchHint:l1}${" + "evictionAndPrefetchHint:l2}${evictionAndPrefetchHint:prefetch}.b$toWidth" + " \t[$addr], $src${policy};">; let mayStore=1, hasSideEffects=0 in { def ST_i16 : ST; @@ -1983,33 +1996,48 @@ let mayStore=1, hasSideEffects=0 in { // elementization happens at the machine instruction level, so the following // instructions never appear in the DAG. multiclass LD_VEC { - def _v2 : NVPTXInst< - (outs regclass:$dst1, regclass:$dst2), - (ins AtomicCode:$sem, AtomicCode:$scope, AtomicCode:$addsp, - AtomicCode:$Sign, i32imm:$fromWidth, UsedBytesMask:$usedBytes, - ADDR:$addr), - "${usedBytes}" - "ld${sem:sem}${scope:scope}${addsp:addsp}.v2.${Sign:sign}$fromWidth " - "\t{{$dst1, $dst2}}, [$addr];">; - def _v4 : NVPTXInst< - (outs regclass:$dst1, regclass:$dst2, regclass:$dst3, regclass:$dst4), - (ins AtomicCode:$sem, AtomicCode:$scope, AtomicCode:$addsp, - AtomicCode:$Sign, i32imm:$fromWidth, UsedBytesMask:$usedBytes, - ADDR:$addr), - "${usedBytes}" - "ld${sem:sem}${scope:scope}${addsp:addsp}.v4.${Sign:sign}$fromWidth " - "\t{{$dst1, $dst2, $dst3, $dst4}}, [$addr];">; + def _v2 + : NVPTXInst< + (outs regclass:$dst1, regclass:$dst2), + (ins AtomicCode:$sem, AtomicCode:$scope, AtomicCode:$addsp, + AtomicCode:$Sign, i32imm:$fromWidth, UsedBytesMask:$usedBytes, + ADDR:$addr, EvictionAndPrefetchHint:$evictionAndPrefetchHint, + CachePolicy:$policy), + "${usedBytes}" + "ld${sem:sem}${scope:scope}${addsp:addsp}${evictionAndPrefetchHint:l1}${" + "evictionAndPrefetchHint:l2}${evictionAndPrefetchHint:prefetch}.v2.${Sign:sign}" + "$fromWidth " + "\t{{$dst1, $dst2}}, [$addr]${policy};">; + def _v4 + : NVPTXInst< + (outs regclass:$dst1, regclass:$dst2, regclass:$dst3, + regclass:$dst4), + (ins AtomicCode:$sem, AtomicCode:$scope, AtomicCode:$addsp, + AtomicCode:$Sign, i32imm:$fromWidth, UsedBytesMask:$usedBytes, + ADDR:$addr, EvictionAndPrefetchHint:$evictionAndPrefetchHint, + CachePolicy:$policy), + "${usedBytes}" + "ld${sem:sem}${scope:scope}${addsp:addsp}${evictionAndPrefetchHint:l1}${" + "evictionAndPrefetchHint:l2}${evictionAndPrefetchHint:prefetch}.v4.${Sign:sign}" + "$fromWidth " + "\t{{$dst1, $dst2, $dst3, $dst4}}, [$addr]${policy};">; if support_v8 then - def _v8 : NVPTXInst< - (outs regclass:$dst1, regclass:$dst2, regclass:$dst3, regclass:$dst4, - regclass:$dst5, regclass:$dst6, regclass:$dst7, regclass:$dst8), - (ins AtomicCode:$sem, AtomicCode:$scope, AtomicCode:$addsp, - AtomicCode:$Sign, i32imm:$fromWidth, UsedBytesMask:$usedBytes, - ADDR:$addr), - "${usedBytes}" - "ld${sem:sem}${scope:scope}${addsp:addsp}.v8.${Sign:sign}$fromWidth " - "\t{{$dst1, $dst2, $dst3, $dst4, $dst5, $dst6, $dst7, $dst8}}, " - "[$addr];">; + def _v8 + : NVPTXInst< + (outs regclass:$dst1, regclass:$dst2, regclass:$dst3, + regclass:$dst4, regclass:$dst5, regclass:$dst6, + regclass:$dst7, regclass:$dst8), + (ins AtomicCode:$sem, AtomicCode:$scope, AtomicCode:$addsp, + AtomicCode:$Sign, i32imm:$fromWidth, UsedBytesMask:$usedBytes, + ADDR:$addr, + EvictionAndPrefetchHint:$evictionAndPrefetchHint, + CachePolicy:$policy), + "${usedBytes}" + "ld${sem:sem}${scope:scope}${addsp:addsp}${evictionAndPrefetchHint:l1}${" + "evictionAndPrefetchHint:l2}${evictionAndPrefetchHint:prefetch}.v8.${Sign:sign}" + "$fromWidth " + "\t{{$dst1, $dst2, $dst3, $dst4, $dst5, $dst6, $dst7, $dst8}}, " + "[$addr]${policy};">; } let mayLoad=1, hasSideEffects=0 in { defm LDV_i16 : LD_VEC; @@ -2018,30 +2046,43 @@ let mayLoad=1, hasSideEffects=0 in { } multiclass ST_VEC { - def _v2 : NVPTXInst< - (outs), - (ins O:$src1, O:$src2, - AtomicCode:$sem, AtomicCode:$scope, AtomicCode:$addsp, i32imm:$fromWidth, - ADDR:$addr), - "st${sem:sem}${scope:scope}${addsp:addsp}.v2.b$fromWidth " - "\t[$addr], {{$src1, $src2}};">; - def _v4 : NVPTXInst< - (outs), - (ins RegOrSink:$src1, RegOrSink:$src2, RegOrSink:$src3, RegOrSink:$src4, - AtomicCode:$sem, AtomicCode:$scope, AtomicCode:$addsp, i32imm:$fromWidth, - ADDR:$addr), - "st${sem:sem}${scope:scope}${addsp:addsp}.v4.b$fromWidth " - "\t[$addr], {{$src1, $src2, $src3, $src4}};">; + def _v2 + : NVPTXInst< + (outs), + (ins O:$src1, O:$src2, AtomicCode:$sem, AtomicCode:$scope, + AtomicCode:$addsp, i32imm:$fromWidth, ADDR:$addr, + EvictionAndPrefetchHint:$evictionAndPrefetchHint, + CachePolicy:$policy), + "st${sem:sem}${scope:scope}${addsp:addsp}${evictionAndPrefetchHint:l1}${" + "evictionAndPrefetchHint:l2}${evictionAndPrefetchHint:prefetch}.v2.b$fromWidth " + "\t[$addr], {{$src1, $src2}}${policy};">; + def _v4 + : NVPTXInst< + (outs), + (ins RegOrSink:$src1, RegOrSink:$src2, RegOrSink:$src3, + RegOrSink:$src4, AtomicCode:$sem, AtomicCode:$scope, + AtomicCode:$addsp, i32imm:$fromWidth, ADDR:$addr, + EvictionAndPrefetchHint:$evictionAndPrefetchHint, + CachePolicy:$policy), + "st${sem:sem}${scope:scope}${addsp:addsp}${evictionAndPrefetchHint:l1}${" + "evictionAndPrefetchHint:l2}${evictionAndPrefetchHint:prefetch}.v4.b$fromWidth " + "\t[$addr], {{$src1, $src2, $src3, $src4}}${policy};">; if support_v8 then - def _v8 : NVPTXInst< - (outs), - (ins RegOrSink:$src1, RegOrSink:$src2, RegOrSink:$src3, RegOrSink:$src4, - RegOrSink:$src5, RegOrSink:$src6, RegOrSink:$src7, RegOrSink:$src8, - AtomicCode:$sem, AtomicCode:$scope, AtomicCode:$addsp, i32imm:$fromWidth, - ADDR:$addr), - "st${sem:sem}${scope:scope}${addsp:addsp}.v8.b$fromWidth " - "\t[$addr], " - "{{$src1, $src2, $src3, $src4, $src5, $src6, $src7, $src8}};">; + def _v8 + : NVPTXInst< + (outs), + (ins RegOrSink:$src1, RegOrSink:$src2, RegOrSink:$src3, + RegOrSink:$src4, RegOrSink:$src5, RegOrSink:$src6, + RegOrSink:$src7, RegOrSink:$src8, AtomicCode:$sem, + AtomicCode:$scope, AtomicCode:$addsp, i32imm:$fromWidth, + ADDR:$addr, + EvictionAndPrefetchHint:$evictionAndPrefetchHint, + CachePolicy:$policy), + "st${sem:sem}${scope:scope}${addsp:addsp}${evictionAndPrefetchHint:l1}${" + "evictionAndPrefetchHint:l2}${evictionAndPrefetchHint:prefetch}.v8.b$fromWidth " + "\t[$addr], " + "{{$src1, $src2, $src3, $src4, $src5, $src6, $src7, " + "$src8}}${policy};">; } let mayStore=1, hasSideEffects=0 in { diff --git a/llvm/lib/Target/NVPTX/NVPTXIntrinsics.td b/llvm/lib/Target/NVPTX/NVPTXIntrinsics.td index ea47ddcc02ae7..9e01a6f8427db 100644 --- a/llvm/lib/Target/NVPTX/NVPTXIntrinsics.td +++ b/llvm/lib/Target/NVPTX/NVPTXIntrinsics.td @@ -2718,16 +2718,20 @@ def LDU_GLOBAL_v4i32 : VLDU_G_ELE_V4; // Support for ldg on sm_35 or later //----------------------------------- +defvar CacheHintQualifiers = + "${evictionAndPrefetchHint:l1}${evictionAndPrefetchHint:l2}${evictionAndPrefetchHint:prefetch}"; + // Don't annotate ld.global.nc as mayLoad, because these loads go through the // non-coherent texture cache, and therefore the values read must be read-only // during the lifetime of the kernel. - class LDG_G : NVPTXInst<(outs regclass:$result), (ins AtomicCode:$Sign, i32imm:$fromWidth, - UsedBytesMask:$usedBytes, ADDR:$src), - "${usedBytes}" - "ld.global.nc.${Sign:sign}$fromWidth \t$result, [$src];">; + UsedBytesMask:$usedBytes, ADDR:$src, + EvictionAndPrefetchHint:$evictionAndPrefetchHint, + CachePolicy:$policy), + !strconcat("${usedBytes}", "ld.global.nc", CacheHintQualifiers, + ".${Sign:sign}$fromWidth \t$result, [$src]${policy};")>; def LD_GLOBAL_NC_i16 : LDG_G; def LD_GLOBAL_NC_i32 : LDG_G; @@ -2739,25 +2743,29 @@ def LD_GLOBAL_NC_i64 : LDG_G; class VLDG_G_ELE_V2 : NVPTXInst<(outs regclass:$dst1, regclass:$dst2), (ins AtomicCode:$Sign, i32imm:$fromWidth, UsedBytesMask:$usedBytes, - ADDR:$src), - "${usedBytes}" - "ld.global.nc.v2.${Sign:sign}$fromWidth \t{{$dst1, $dst2}}, [$src];">; - + ADDR:$src, EvictionAndPrefetchHint:$evictionAndPrefetchHint, + CachePolicy:$policy), + !strconcat("${usedBytes}", "ld.global.nc", CacheHintQualifiers, + ".v2.${Sign:sign}$fromWidth \t{{$dst1, $dst2}}, [$src]${policy};")>; class VLDG_G_ELE_V4 : - NVPTXInst<(outs regclass:$dst1, regclass:$dst2, regclass:$dst3, regclass:$dst4), + NVPTXInst<(outs regclass:$dst1, regclass:$dst2, regclass:$dst3, + regclass:$dst4), (ins AtomicCode:$Sign, i32imm:$fromWidth, UsedBytesMask:$usedBytes, - ADDR:$src), - "${usedBytes}" - "ld.global.nc.v4.${Sign:sign}$fromWidth \t{{$dst1, $dst2, $dst3, $dst4}}, [$src];">; + ADDR:$src, EvictionAndPrefetchHint:$evictionAndPrefetchHint, + CachePolicy:$policy), + !strconcat("${usedBytes}", "ld.global.nc", CacheHintQualifiers, + ".v4.${Sign:sign}$fromWidth \t{{$dst1, $dst2, $dst3, $dst4}}, [$src]${policy};")>; class VLDG_G_ELE_V8 : - NVPTXInst<(outs regclass:$dst1, regclass:$dst2, regclass:$dst3, regclass:$dst4, - regclass:$dst5, regclass:$dst6, regclass:$dst7, regclass:$dst8), + NVPTXInst<(outs regclass:$dst1, regclass:$dst2, regclass:$dst3, + regclass:$dst4, regclass:$dst5, regclass:$dst6, + regclass:$dst7, regclass:$dst8), (ins AtomicCode:$Sign, i32imm:$fromWidth, UsedBytesMask:$usedBytes, - ADDR:$src), - "${usedBytes}" - "ld.global.nc.v8.${Sign:sign}$fromWidth \t{{$dst1, $dst2, $dst3, $dst4, $dst5, $dst6, $dst7, $dst8}}, [$src];">; + ADDR:$src, EvictionAndPrefetchHint:$evictionAndPrefetchHint, + CachePolicy:$policy), + !strconcat("${usedBytes}", "ld.global.nc", CacheHintQualifiers, + ".v8.${Sign:sign}$fromWidth \t{{$dst1, $dst2, $dst3, $dst4, $dst5, $dst6, $dst7, $dst8}}, [$src]${policy};")>; // FIXME: 8-bit LDG should be fixed once LDG/LDU nodes are made into proper loads. def LD_GLOBAL_NC_v2i16 : VLDG_G_ELE_V2; diff --git a/llvm/lib/Target/NVPTX/NVPTXSubtarget.h b/llvm/lib/Target/NVPTX/NVPTXSubtarget.h index 22affe4f40759..28ac251b8adea 100644 --- a/llvm/lib/Target/NVPTX/NVPTXSubtarget.h +++ b/llvm/lib/Target/NVPTX/NVPTXSubtarget.h @@ -125,6 +125,25 @@ class NVPTXSubtarget : public NVPTXGenSubtargetInfo { bool hasDotInstructions() const { return getSmVersion() >= 61 && PTXVersion >= 50; } + // Cache hint SM/PTX version requirements + bool hasL1EvictionHint() const { + return getSmVersion() >= 70 && PTXVersion >= 74; + } + bool hasL2EvictionHint() const { + return getSmVersion() >= 100 && PTXVersion >= 88; + } + bool hasL2Prefetch64B() const { + return getSmVersion() >= 75 && PTXVersion >= 74; + } + bool hasL2Prefetch128B() const { + return getSmVersion() >= 75 && PTXVersion >= 74; + } + bool hasL2Prefetch256B() const { + return getSmVersion() >= 80 && PTXVersion >= 74; + } + bool hasL2CacheHint() const { + return getSmVersion() >= 80 && PTXVersion >= 74; + } // Checks following instructions support: // - tcgen05.ld/st diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp index 1a80d0a05655a..e338a08338657 100644 --- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -8593,7 +8593,8 @@ SDValue PPCTargetLowering::LowerFP_TO_INT(SDValue Op, SelectionDAG &DAG, LowerFP_TO_INTForReuse(Op, RLI, DAG, dl); return DAG.getLoad(Op.getValueType(), dl, RLI.Chain, RLI.Ptr, RLI.MPI, - RLI.Alignment, RLI.MMOFlags(), RLI.AAInfo, RLI.Ranges); + RLI.Alignment, RLI.MMOFlags(), + MMOMetadata(RLI.AAInfo, RLI.Ranges)); } // We're trying to insert a regular store, S, and then a load, L. If the @@ -8921,15 +8922,16 @@ SDValue PPCTargetLowering::LowerINT_TO_FP(SDValue Op, if (canReuseLoadAddress(SINT, MVT::i64, RLI, DAG)) { // Drop range metadata, as this metadata becomes invalid for f64 bit // reinterpretation of i64 values. - Bits = DAG.getLoad(MVT::f64, dl, RLI.Chain, RLI.Ptr, RLI.MPI, - RLI.Alignment, RLI.MMOFlags(), RLI.AAInfo, nullptr); + Bits = + DAG.getLoad(MVT::f64, dl, RLI.Chain, RLI.Ptr, RLI.MPI, RLI.Alignment, + RLI.MMOFlags(), MMOMetadata(RLI.AAInfo)); if (RLI.ResChain) DAG.makeEquivalentMemoryOrdering(RLI.ResChain, Bits.getValue(1)); } else if (Subtarget.hasLFIWAX() && canReuseLoadAddress(SINT, MVT::i32, RLI, DAG, ISD::SEXTLOAD)) { - MachineMemOperand *MMO = - MF.getMachineMemOperand(RLI.MPI, MachineMemOperand::MOLoad, 4, - RLI.Alignment, RLI.AAInfo, RLI.Ranges); + MachineMemOperand *MMO = MF.getMachineMemOperand( + RLI.MPI, MachineMemOperand::MOLoad, 4, RLI.Alignment, + MMOMetadata(RLI.AAInfo, RLI.Ranges)); SDValue Ops[] = { RLI.Chain, RLI.Ptr }; Bits = DAG.getMemIntrinsicNode(PPCISD::LFIWAX, dl, DAG.getVTList(MVT::f64, MVT::Other), @@ -8938,9 +8940,9 @@ SDValue PPCTargetLowering::LowerINT_TO_FP(SDValue Op, DAG.makeEquivalentMemoryOrdering(RLI.ResChain, Bits.getValue(1)); } else if (Subtarget.hasFPCVT() && canReuseLoadAddress(SINT, MVT::i32, RLI, DAG, ISD::ZEXTLOAD)) { - MachineMemOperand *MMO = - MF.getMachineMemOperand(RLI.MPI, MachineMemOperand::MOLoad, 4, - RLI.Alignment, RLI.AAInfo, RLI.Ranges); + MachineMemOperand *MMO = MF.getMachineMemOperand( + RLI.MPI, MachineMemOperand::MOLoad, 4, RLI.Alignment, + MMOMetadata(RLI.AAInfo, RLI.Ranges)); SDValue Ops[] = { RLI.Chain, RLI.Ptr }; Bits = DAG.getMemIntrinsicNode(PPCISD::LFIWZX, dl, DAG.getVTList(MVT::f64, MVT::Other), @@ -8972,9 +8974,9 @@ SDValue PPCTargetLowering::LowerINT_TO_FP(SDValue Op, MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FrameIdx); RLI.Alignment = Align(4); - MachineMemOperand *MMO = - MF.getMachineMemOperand(RLI.MPI, MachineMemOperand::MOLoad, 4, - RLI.Alignment, RLI.AAInfo, RLI.Ranges); + MachineMemOperand *MMO = MF.getMachineMemOperand( + RLI.MPI, MachineMemOperand::MOLoad, 4, RLI.Alignment, + MMOMetadata(RLI.AAInfo, RLI.Ranges)); SDValue Ops[] = { RLI.Chain, RLI.Ptr }; Bits = DAG.getMemIntrinsicNode(SINT.getOpcode() == ISD::ZERO_EXTEND ? PPCISD::LFIWZX : PPCISD::LFIWAX, @@ -9034,9 +9036,9 @@ SDValue PPCTargetLowering::LowerINT_TO_FP(SDValue Op, RLI.Alignment = Align(4); } - MachineMemOperand *MMO = - MF.getMachineMemOperand(RLI.MPI, MachineMemOperand::MOLoad, 4, - RLI.Alignment, RLI.AAInfo, RLI.Ranges); + MachineMemOperand *MMO = MF.getMachineMemOperand( + RLI.MPI, MachineMemOperand::MOLoad, 4, RLI.Alignment, + MMOMetadata(RLI.AAInfo, RLI.Ranges)); SDValue Ops[] = { RLI.Chain, RLI.Ptr }; Ld = DAG.getMemIntrinsicNode(IsSigned ? PPCISD::LFIWAX : PPCISD::LFIWZX, dl, DAG.getVTList(MVT::f64, MVT::Other), Ops, @@ -12136,9 +12138,9 @@ SDValue PPCTargetLowering::LowerSCALAR_TO_VECTOR(SDValue Op, Op0.getValueType() == MVT::i32 && Op0.hasOneUse() && canReuseLoadAddress(Op0, MVT::i32, RLI, DAG, ISD::NON_EXTLOAD)) { - MachineMemOperand *MMO = - MF.getMachineMemOperand(RLI.MPI, MachineMemOperand::MOLoad, 4, - RLI.Alignment, RLI.AAInfo, RLI.Ranges); + MachineMemOperand *MMO = MF.getMachineMemOperand( + RLI.MPI, MachineMemOperand::MOLoad, 4, RLI.Alignment, + MMOMetadata(RLI.AAInfo, RLI.Ranges)); SDValue Ops[] = {RLI.Chain, RLI.Ptr, DAG.getValueType(Op.getValueType())}; SDValue Bits = DAG.getMemIntrinsicNode( PPCISD::LD_SPLAT, dl, DAG.getVTList(MVT::v4i32, MVT::Other), Ops, @@ -16083,8 +16085,8 @@ SDValue convertTwoLoadsAndCmpToVCMPEQUB(SelectionDAG &DAG, SDNode *N, MachineFunction &MF = DAG.getMachineFunction(); MachineMemOperand *NewMMO = MF.getMachineMemOperand( MMO->getPointerInfo(), MMO->getFlags(), MMO->getSize(), MMO->getAlign(), - MMO->getAAInfo(), nullptr, MMO->getSyncScopeID(), - MMO->getSuccessOrdering(), MMO->getFailureOrdering()); + MMO->getAAInfo(), MMO->getSyncScopeID(), MMO->getSuccessOrdering(), + MMO->getFailureOrdering()); SDValue NewLoad = DAG.getLoad(MVT::v16i8, DL, LoadNode->getChain(), LoadNode->getBasePtr(), NewMMO); DAG.ReplaceAllUsesOfValueWith(SDValue(LoadNode, 1), NewLoad.getValue(1)); diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index e5241583baccd..1c5a8e4b79483 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -14327,7 +14327,7 @@ RISCVTargetLowering::lowerFixedLengthVectorLoadToRVV(SDValue Op, SDValue NewLoad = DAG.getLoad(ContainerVT, DL, Load->getChain(), Load->getBasePtr(), MMO->getPointerInfo(), MMO->getBaseAlign(), MMO->getFlags(), - MMO->getAAInfo(), MMO->getRanges()); + MMOMetadata(MMO->getAAInfo(), MMO->getRanges())); SDValue Result = convertFromScalableVector(VT, NewLoad, DAG, Subtarget); return DAG.getMergeValues({Result, NewLoad.getValue(1)}, DL); } diff --git a/llvm/test/CodeGen/MIR/NVPTX/floating-point-immediate-operands.mir b/llvm/test/CodeGen/MIR/NVPTX/floating-point-immediate-operands.mir index b057b51c99a00..6e6821b16b045 100644 --- a/llvm/test/CodeGen/MIR/NVPTX/floating-point-immediate-operands.mir +++ b/llvm/test/CodeGen/MIR/NVPTX/floating-point-immediate-operands.mir @@ -40,9 +40,9 @@ registers: - { id: 7, class: b32 } body: | bb.0.entry: - %0 = LD_i32 0, 0, 4, 2, 32, -1, &test_param_0, 0 + %0 = LD_i32 0, 0, 4, 2, 32, -1, 0, &test_param_0, 0, $noreg %1 = CVT_f64_f32 %0, 0 - %2 = LD_i32 0, 0, 4, 0, 32, -1, &test_param_1, 0 + %2 = LD_i32 0, 0, 4, 0, 32, -1, 0, &test_param_1, 0, $noreg ; CHECK: %3:b64 = FADD_rnf64ri %1, double 3.250000e+00 %3 = FADD_rnf64ri %1, double 3.250000e+00 %4 = CVT_f32_f64 %3, 5 @@ -50,7 +50,7 @@ body: | ; CHECK: %6:b32 = FADD_rnf32ri %5, float 6.250000e+00 %6 = FADD_rnf32ri %5, float 6.250000e+00, 0 %7 = FMUL_rnf32rr %6, %4, 0 - ST_i32 %7, 0, 0, 101, 32, &func_retval0, 0 :: (store (s32), addrspace 101) + ST_i32 %7, 0, 0, 101, 32, 0, &func_retval0, 0, $noreg :: (store (s32), addrspace 101) Return ... --- @@ -66,9 +66,9 @@ registers: - { id: 7, class: b32 } body: | bb.0.entry: - %0 = LD_i32 0, 0, 4, 2, 32, -1, &test2_param_0, 0 + %0 = LD_i32 0, 0, 4, 2, 32, -1, 0, &test2_param_0, 0, $noreg %1 = CVT_f64_f32 %0, 0 - %2 = LD_i32 0, 0, 4, 0, 32, -1, &test2_param_1, 0 + %2 = LD_i32 0, 0, 4, 0, 32, -1, 0, &test2_param_1, 0, $noreg ; CHECK: %3:b64 = FADD_rnf64ri %1, double +qnan %3 = FADD_rnf64ri %1, double 0x7FF8000000000000 %4 = CVT_f32_f64 %3, 5 @@ -76,6 +76,6 @@ body: | ; CHECK: %6:b32 = FADD_rnf32ri %5, float +qnan %6 = FADD_rnf32ri %5, float 0x7FF8000000000000, 0 %7 = FMUL_rnf32rr %6, %4, 0 - ST_i32 %7, 0, 0, 101, 32, &func_retval0, 0 :: (store (s32), addrspace 101) + ST_i32 %7, 0, 0, 101, 32, 0, &func_retval0, 0, $noreg :: (store (s32), addrspace 101) Return ... diff --git a/llvm/test/CodeGen/MIR/X86/mem-cache-hint-error.mir b/llvm/test/CodeGen/MIR/X86/mem-cache-hint-error.mir new file mode 100644 index 0000000000000..1b78db70512e8 --- /dev/null +++ b/llvm/test/CodeGen/MIR/X86/mem-cache-hint-error.mir @@ -0,0 +1,26 @@ +# RUN: not llc -mtriple=x86_64 -run-pass none -o /dev/null %s 2>&1 | FileCheck %s + +--- | + define i32 @test(ptr %p) { + entry: + %v = load i32, ptr %p + ret i32 %v + } + +... +--- +name: test +tracksRegLiveness: true +registers: + - { id: 0, class: gr64 } + - { id: 1, class: gr32 } +body: | + bb.0.entry: + liveins: $rdi + + %0:gr64 = COPY $rdi + ; CHECK: [[@LINE+1]]:92: expected metadata id after '!' + %1:gr32 = MOV32rm %0, 1, $noreg, 0, $noreg :: (load (s32) from %ir.p, !mem.cache_hint !) + $eax = COPY %1 + RET64 $eax +... diff --git a/llvm/test/CodeGen/MIR/X86/mem-cache-hint-undefined-metadata.mir b/llvm/test/CodeGen/MIR/X86/mem-cache-hint-undefined-metadata.mir new file mode 100644 index 0000000000000..5e6c464b90b7c --- /dev/null +++ b/llvm/test/CodeGen/MIR/X86/mem-cache-hint-undefined-metadata.mir @@ -0,0 +1,29 @@ +# RUN: not llc -mtriple=x86_64 -run-pass none -filetype=null %s 2>&1 | FileCheck %s + +--- | + define i32 @undefined_metadata(ptr %p) { + entry: + %v = load i32, ptr %p, !mem.cache_hint !0 + ret i32 %v + } + + !0 = !{i32 0, !1} + !1 = !{!"nvvm.l2_cache_hint", i64 12345} + +... +--- +name: undefined_metadata +tracksRegLiveness: true +registers: + - { id: 0, class: gr64 } + - { id: 1, class: gr32 } +body: | + bb.0.entry: + liveins: $rdi + + ; CHECK: use of undefined metadata '!3' + %0:gr64 = COPY $rdi + %1:gr32 = MOV32rm %0, 1, $noreg, 0, $noreg :: (load (s32) from %ir.p, !mem.cache_hint !3) + $eax = COPY %1 + RET64 $eax +... diff --git a/llvm/test/CodeGen/MIR/X86/mem-cache-hint.mir b/llvm/test/CodeGen/MIR/X86/mem-cache-hint.mir new file mode 100644 index 0000000000000..196307e14ef1d --- /dev/null +++ b/llvm/test/CodeGen/MIR/X86/mem-cache-hint.mir @@ -0,0 +1,42 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5 +# RUN: llc -mtriple=x86_64 -run-pass=none -o - %s | FileCheck %s + +--- | + define i32 @test(ptr %p, i32 %v) { + entry: + %ld = load i32, ptr %p, !mem.cache_hint !0 + store i32 %v, ptr %p, !mem.cache_hint !2 + ret i32 %ld + } + + !0 = !{i32 0, !1} + !1 = !{!"nvvm.l2_cache_hint", i64 12345} + !2 = !{i32 1, !1} + +... +--- +name: test +tracksRegLiveness: true +registers: + - { id: 0, class: gr64 } + - { id: 1, class: gr32 } +body: | + bb.0.entry: + liveins: $rdi, $esi + + ; CHECK-LABEL: name: test + ; CHECK: liveins: $rdi, $esi + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:gr64 = COPY $rdi + ; CHECK-NEXT: [[MOV32rm:%[0-9]+]]:gr32 = MOV32rm [[COPY]], 1, $noreg, 0, $noreg :: (load (s32) from %ir.p, !mem.cache_hint !0) + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gr32 = COPY $esi + ; CHECK-NEXT: MOV32mr [[COPY]], 1, $noreg, 0, $noreg, [[COPY1]] :: (store (s32) into %ir.p, !mem.cache_hint !2) + ; CHECK-NEXT: $eax = COPY [[MOV32rm]] + ; CHECK-NEXT: RET 0, $eax + %0:gr64 = COPY $rdi + %1:gr32 = MOV32rm %0, 1, $noreg, 0, $noreg :: (load (s32) from %ir.p, !mem.cache_hint !0) + %2:gr32 = COPY $esi + MOV32mr %0, 1, $noreg, 0, $noreg, %2 :: (store (s32) into %ir.p, !mem.cache_hint !2) + $eax = COPY %1 + RET 0, $eax +... diff --git a/llvm/test/CodeGen/MIR/X86/memory-operands.mir b/llvm/test/CodeGen/MIR/X86/memory-operands.mir index 6c2c7e36f1fb6..60a5a4b192aed 100644 --- a/llvm/test/CodeGen/MIR/X86/memory-operands.mir +++ b/llvm/test/CodeGen/MIR/X86/memory-operands.mir @@ -169,6 +169,8 @@ } !12 = !{i8 0, i8 2} + !13 = !{i32 0, !14} + !14 = !{!"nvvm.l1_eviction", !"first"} %st = type { i32, i32 } @@ -490,8 +492,8 @@ body: | bb.0.entry: liveins: $rdi ; CHECK-LABEL: name: range_metadata - ; CHECK: $al = MOV8rm killed $rdi, 1, $noreg, 0, $noreg :: (load (s8) from %ir.x, !range !11) - $al = MOV8rm killed $rdi, 1, _, 0, _ :: (load (s8) from %ir.x, !range !11) + ; CHECK: $al = MOV8rm killed $rdi, 1, $noreg, 0, $noreg :: (load (s8) from %ir.x, !range !11, !mem.cache_hint !12) + $al = MOV8rm killed $rdi, 1, _, 0, _ :: (load (s8) from %ir.x, !range !11, !mem.cache_hint !12) RET64 $al ... --- diff --git a/llvm/test/CodeGen/NVPTX/address-folder.mir b/llvm/test/CodeGen/NVPTX/address-folder.mir index ac50925579506..5b4ad84a9a8d1 100644 --- a/llvm/test/CodeGen/NVPTX/address-folder.mir +++ b/llvm/test/CodeGen/NVPTX/address-folder.mir @@ -15,17 +15,17 @@ # operand of loads and stores, and the dead `mov` is removed. # CHECK-LABEL: name: fold_global # CHECK-NOT: MOV_B64_sym -# CHECK: %1:b64 = LD_i64 0, 0, 1, 3, 64, -1, @g, 0 -# CHECK: %2:b64 = LD_i64 0, 0, 1, 3, 64, -1, @g, 8 -# CHECK: ST_i64 %1, 0, 0, 1, 64, @g, 16 +# CHECK: %1:b64 = LD_i64 0, 0, 1, 3, 64, -1, @g, 0, 0, $noreg +# CHECK: %2:b64 = LD_i64 0, 0, 1, 3, 64, -1, @g, 8, 0, $noreg +# CHECK: ST_i64 %1, 0, 0, 1, 64, @g, 16, 0, $noreg name: fold_global tracksRegLiveness: true body: | bb.0: %0:b64 = MOV_B64_sym @g - %1:b64 = LD_i64 0, 0, 1, 3, 64, -1, %0, 0 :: (load (s64), addrspace 1) - %2:b64 = LD_i64 0, 0, 1, 3, 64, -1, %0, 8 :: (load (s64), addrspace 1) - ST_i64 %1, 0, 0, 1, 64, %0, 16 :: (store (s64), addrspace 1) + %1:b64 = LD_i64 0, 0, 1, 3, 64, -1, %0, 0, 0, $noreg :: (load (s64), addrspace 1) + %2:b64 = LD_i64 0, 0, 1, 3, 64, -1, %0, 8, 0, $noreg :: (load (s64), addrspace 1) + ST_i64 %1, 0, 0, 1, 64, %0, 16, 0, $noreg :: (store (s64), addrspace 1) Return ... --- @@ -33,13 +33,13 @@ body: | # stay CSE-able rather than be duplicated into every access. # CHECK-LABEL: name: skip_shared # CHECK: %0:b64 = MOV_B64_sym @g_shared -# CHECK: %1:b64 = LD_i64 0, 0, 3, 3, 64, -1, %0, 0 +# CHECK: %1:b64 = LD_i64 0, 0, 3, 3, 64, -1, %0, 0, 0, $noreg name: skip_shared tracksRegLiveness: true body: | bb.0: %0:b64 = MOV_B64_sym @g_shared - %1:b64 = LD_i64 0, 0, 3, 3, 64, -1, %0, 0 :: (load (s64), addrspace 3) + %1:b64 = LD_i64 0, 0, 3, 3, 64, -1, %0, 0, 0, $noreg :: (load (s64), addrspace 3) Return ... --- @@ -47,14 +47,14 @@ body: | # the `mov` is kept for the remaining use. # CHECK-LABEL: name: fold_partial # CHECK: %0:b64 = MOV_B64_sym @g -# CHECK: %1:b64 = LD_i64 0, 0, 1, 3, 64, -1, @g, 0 +# CHECK: %1:b64 = LD_i64 0, 0, 1, 3, 64, -1, @g, 0, 0, $noreg # CHECK: %2:b64 = MULT64rr %0, %0 name: fold_partial tracksRegLiveness: true body: | bb.0: %0:b64 = MOV_B64_sym @g - %1:b64 = LD_i64 0, 0, 1, 3, 64, -1, %0, 0 :: (load (s64), addrspace 1) + %1:b64 = LD_i64 0, 0, 1, 3, 64, -1, %0, 0, 0, $noreg :: (load (s64), addrspace 1) %2:b64 = MULT64rr %0, %0 Return ... diff --git a/llvm/test/CodeGen/NVPTX/cache-hint-atomics.ll b/llvm/test/CodeGen/NVPTX/cache-hint-atomics.ll new file mode 100644 index 0000000000000..83ab4d9f0fa61 --- /dev/null +++ b/llvm/test/CodeGen/NVPTX/cache-hint-atomics.ll @@ -0,0 +1,47 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --filter "^\s*(?:mov\.b64|ld(?:\.[A-Za-z0-9_:]+)*\.global|st(?:\.[A-Za-z0-9_:]+)*\.global|atom(?:\.[A-Za-z0-9_:]+)*\.global)" --version 6 +; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 | FileCheck %s +; RUN: %if ptxas %{ llc < %s -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 | %ptxas-verify %} + +; !mem.cache_hint is legal on atomic IR memory instructions, but +; SelectionDAGBuilder currently drops it for atomic loads, stores, RMWs, and +; cmpxchg. + +; TODO: This should eventually lower to ld.acquire.sys.global.L1::evict_first.b32. +define i32 @atomic_load_l1_hint(ptr addrspace(1) %p) { +; CHECK-LABEL: atomic_load_l1_hint( +; CHECK: ld.acquire.sys.global.b32 %r1, [%rd1]; + %v = load atomic i32, ptr addrspace(1) %p acquire, align 4, !mem.cache_hint !0 + ret i32 %v +} + +; TODO: This should eventually lower to st.release.sys.global.L2::cache_hint.b32. +define void @atomic_store_l2_cache_policy(ptr addrspace(1) %p, i32 %v) { +; CHECK-LABEL: atomic_store_l2_cache_policy( +; CHECK: st.release.sys.global.b32 [%rd1], %r1; + store atomic i32 %v, ptr addrspace(1) %p release, align 4, !mem.cache_hint !2 + ret void +} + +; TODO: This should eventually lower to atom.relaxed.sys.global.add.L2::cache_hint.u32. +define i32 @atomicrmw_add_l2_cache_policy(ptr addrspace(1) %p, i32 %v) { +; CHECK-LABEL: atomicrmw_add_l2_cache_policy( +; CHECK: atom.relaxed.sys.global.add.u32 %r2, [%rd1], %r1; + %old = atomicrmw add ptr addrspace(1) %p, i32 %v monotonic, align 4, !mem.cache_hint !1 + ret i32 %old +} + +; PTX atom.cas does not have a .level::cache_hint operand. +define i32 @cmpxchg_l2_cache_policy(ptr addrspace(1) %p, i32 %cmp, i32 %new) { +; CHECK-LABEL: cmpxchg_l2_cache_policy( +; CHECK: atom.relaxed.sys.global.cas.b32 %r3, [%rd1], %r1, %r2; + %pair = cmpxchg ptr addrspace(1) %p, i32 %cmp, i32 %new monotonic monotonic, align 4, !mem.cache_hint !1 + %old = extractvalue { i32, i1 } %pair, 0 + ret i32 %old +} + +!0 = !{i32 0, !10} +!1 = !{i32 0, !11} +!2 = !{i32 1, !11} + +!10 = !{!"nvvm.l1_eviction", !"first"} +!11 = !{!"nvvm.l2_cache_hint", i64 12345} diff --git a/llvm/test/CodeGen/NVPTX/cache-hint-cache-policy.ll b/llvm/test/CodeGen/NVPTX/cache-hint-cache-policy.ll new file mode 100644 index 0000000000000..5f3761d91b3a6 --- /dev/null +++ b/llvm/test/CodeGen/NVPTX/cache-hint-cache-policy.ll @@ -0,0 +1,261 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --filter "^\s*(?:mov\.b64|ld(?:\.[A-Za-z0-9_:]+)*\.global|st(?:\.[A-Za-z0-9_:]+)*\.global|ld(?:\.[A-Za-z0-9_:]+)*\.L2::cache_hint|st(?:\.[A-Za-z0-9_:]+)*\.L2::cache_hint|atom(?:\.[A-Za-z0-9_:]+)*\.global)" --version 6 +; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 | FileCheck %s +; RUN: %if ptxas %{ llc < %s -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 | %ptxas-verify %} + +; Test L2::cache_hint metadata lowering with constant cache-policy operands. + +;----------------------------------------------------------------------------- +; L2::cache_hint with constant cache-policy operand (metadata-based) +;----------------------------------------------------------------------------- + +define i32 @test_load_cache_hint_i32(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_cache_hint_i32( +; CHECK: mov.b64 %rd2, 12345; +; CHECK: ld.global.L2::cache_hint.b32 %r1, [%rd1], %rd2; + %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !0 + ret i32 %v +} + +define i64 @test_load_cache_hint_i64(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_cache_hint_i64( +; CHECK: mov.b64 %rd2, 12345; +; CHECK: ld.global.L2::cache_hint.b64 %rd3, [%rd1], %rd2; + %v = load i64, ptr addrspace(1) %p, !mem.cache_hint !0 + ret i64 %v +} + +define float @test_load_cache_hint_f32(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_cache_hint_f32( +; CHECK: mov.b64 %rd2, 12345; +; CHECK: ld.global.L2::cache_hint.b32 %r1, [%rd1], %rd2; + %v = load float, ptr addrspace(1) %p, !mem.cache_hint !0 + ret float %v +} + +define void @test_store_cache_hint_i32(ptr addrspace(1) %p, i32 %v) { +; CHECK-LABEL: test_store_cache_hint_i32( +; CHECK: mov.b64 %rd2, 12345; +; CHECK: st.global.L2::cache_hint.b32 [%rd1], %r1, %rd2; + store i32 %v, ptr addrspace(1) %p, !mem.cache_hint !1 + ret void +} + +define void @test_store_cache_hint_i64(ptr addrspace(1) %p, i64 %v) { +; CHECK-LABEL: test_store_cache_hint_i64( +; CHECK: mov.b64 %rd2, 12345; +; CHECK: st.global.L2::cache_hint.b64 [%rd1], %rd3, %rd2; + store i64 %v, ptr addrspace(1) %p, !mem.cache_hint !1 + ret void +} + +define void @test_store_cache_hint_f32(ptr addrspace(1) %p, float %v) { +; CHECK-LABEL: test_store_cache_hint_f32( +; CHECK: mov.b64 %rd2, 12345; +; CHECK: st.global.L2::cache_hint.b32 [%rd1], %r1, %rd2; + store float %v, ptr addrspace(1) %p, !mem.cache_hint !1 + ret void +} + +;----------------------------------------------------------------------------- +; L2::cache_hint with vector types +;----------------------------------------------------------------------------- + +define <2 x i32> @test_load_cache_hint_v2i32(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_cache_hint_v2i32( +; CHECK: mov.b64 %rd2, 12345; +; CHECK: ld.global.L2::cache_hint.v2.b32 {%r1, %r2}, [%rd1], %rd2; + %v = load <2 x i32>, ptr addrspace(1) %p, !mem.cache_hint !0 + ret <2 x i32> %v +} + +define <4 x i32> @test_load_cache_hint_v4i32(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_cache_hint_v4i32( +; CHECK: mov.b64 %rd2, 12345; +; CHECK: ld.global.L2::cache_hint.v4.b32 {%r1, %r2, %r3, %r4}, [%rd1], %rd2; + %v = load <4 x i32>, ptr addrspace(1) %p, !mem.cache_hint !0 + ret <4 x i32> %v +} + +define <2 x i64> @test_load_cache_hint_v2i64(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_cache_hint_v2i64( +; CHECK: mov.b64 %rd2, 12345; +; CHECK: ld.global.L2::cache_hint.v2.b64 {%rd3, %rd4}, [%rd1], %rd2; + %v = load <2 x i64>, ptr addrspace(1) %p, !mem.cache_hint !0 + ret <2 x i64> %v +} + +define <2 x float> @test_load_cache_hint_v2f32(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_cache_hint_v2f32( +; CHECK: mov.b64 %rd2, 12345; +; CHECK: ld.global.L2::cache_hint.v2.b32 {%r1, %r2}, [%rd1], %rd2; + %v = load <2 x float>, ptr addrspace(1) %p, !mem.cache_hint !0 + ret <2 x float> %v +} + +define <2 x double> @test_load_cache_hint_v2f64(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_cache_hint_v2f64( +; CHECK: mov.b64 %rd2, 12345; +; CHECK: ld.global.L2::cache_hint.v2.b64 {%rd3, %rd4}, [%rd1], %rd2; + %v = load <2 x double>, ptr addrspace(1) %p, !mem.cache_hint !0 + ret <2 x double> %v +} + +define void @test_store_cache_hint_v2i32(ptr addrspace(1) %p, <2 x i32> %v) { +; CHECK-LABEL: test_store_cache_hint_v2i32( +; CHECK: mov.b64 %rd2, 12345; +; CHECK: st.global.L2::cache_hint.v2.b32 [%rd1], {%r1, %r2}, %rd2; + store <2 x i32> %v, ptr addrspace(1) %p, !mem.cache_hint !1 + ret void +} + +define void @test_store_cache_hint_v4i32(ptr addrspace(1) %p, <4 x i32> %v) { +; CHECK-LABEL: test_store_cache_hint_v4i32( +; CHECK: mov.b64 %rd2, 12345; +; CHECK: st.global.L2::cache_hint.v4.b32 [%rd1], {%r1, %r2, %r3, %r4}, %rd2; + store <4 x i32> %v, ptr addrspace(1) %p, !mem.cache_hint !1 + ret void +} + +define void @test_store_cache_hint_v2i64(ptr addrspace(1) %p, <2 x i64> %v) { +; CHECK-LABEL: test_store_cache_hint_v2i64( +; CHECK: mov.b64 %rd2, 12345; +; CHECK: st.global.L2::cache_hint.v2.b64 [%rd1], {%rd3, %rd4}, %rd2; + store <2 x i64> %v, ptr addrspace(1) %p, !mem.cache_hint !1 + ret void +} + +define void @test_store_cache_hint_v2f32(ptr addrspace(1) %p, <2 x float> %v) { +; CHECK-LABEL: test_store_cache_hint_v2f32( +; CHECK: mov.b64 %rd2, 12345; +; CHECK: st.global.L2::cache_hint.v2.b32 [%rd1], {%r1, %r2}, %rd2; + store <2 x float> %v, ptr addrspace(1) %p, !mem.cache_hint !1 + ret void +} + +define void @test_store_cache_hint_v2f64(ptr addrspace(1) %p, <2 x double> %v) { +; CHECK-LABEL: test_store_cache_hint_v2f64( +; CHECK: mov.b64 %rd2, 12345; +; CHECK: st.global.L2::cache_hint.v2.b64 [%rd1], {%rd3, %rd4}, %rd2; + store <2 x double> %v, ptr addrspace(1) %p, !mem.cache_hint !1 + ret void +} + +;----------------------------------------------------------------------------- +; L2::cache_hint with generic addressing +;----------------------------------------------------------------------------- + +define i32 @test_generic_load_cache_hint_i32(ptr %p) { +; CHECK-LABEL: test_generic_load_cache_hint_i32( +; CHECK: mov.b64 %rd2, 12345; +; CHECK: ld.L2::cache_hint.b32 %r1, [%rd1], %rd2; + %v = load i32, ptr %p, !mem.cache_hint !0 + ret i32 %v +} + +define void @test_generic_store_cache_hint_i32(ptr %p, i32 %v) { +; CHECK-LABEL: test_generic_store_cache_hint_i32( +; CHECK: mov.b64 %rd2, 12345; +; CHECK: st.L2::cache_hint.b32 [%rd1], %r1, %rd2; + store i32 %v, ptr %p, !mem.cache_hint !1 + ret void +} + +;----------------------------------------------------------------------------- +; L2::cache_hint combined with other hints (valid qualifiers are preserved) +;----------------------------------------------------------------------------- + +; L2::cache_hint + L1 eviction: both qualifiers should be emitted +define i32 @test_load_cache_hint_with_l1(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_cache_hint_with_l1( +; CHECK: mov.b64 %rd2, 12345; +; CHECK: ld.global.L1::evict_first.L2::cache_hint.b32 %r1, [%rd1], %rd2; + %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !3 + ret i32 %v +} + +; L2::cache_hint + L2 eviction: cache policy is emitted, scalar L2 eviction is dropped +define i32 @test_load_cache_hint_with_l2_eviction(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_cache_hint_with_l2_eviction( +; CHECK: mov.b64 %rd2, 12345; +; CHECK: ld.global.L2::cache_hint.b32 %r1, [%rd1], %rd2; + %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !5 + ret i32 %v +} + +; L2::cache_hint + L2 prefetch: both qualifiers should be emitted +define i32 @test_load_cache_hint_with_prefetch(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_cache_hint_with_prefetch( +; CHECK: mov.b64 %rd2, 12345; +; CHECK: ld.global.L2::cache_hint.L2::128B.b32 %r1, [%rd1], %rd2; + %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !7 + ret i32 %v +} + +; L2::cache_hint + all other hints: valid load qualifiers are emitted +define i32 @test_load_cache_hint_with_all(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_cache_hint_with_all( +; CHECK: mov.b64 %rd2, 12345; +; CHECK: ld.global.L1::evict_last.L2::cache_hint.L2::256B.b32 %r1, [%rd1], %rd2; + %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !9 + ret i32 %v +} + +; Store: L2::cache_hint + L1 eviction +define void @test_store_cache_hint_with_l1(ptr addrspace(1) %p, i32 %v) { +; CHECK-LABEL: test_store_cache_hint_with_l1( +; CHECK: mov.b64 %rd2, 12345; +; CHECK: st.global.L1::evict_unchanged.L2::cache_hint.b32 [%rd1], %r1, %rd2; + store i32 %v, ptr addrspace(1) %p, !mem.cache_hint !11 + ret void +} + +; Store: L2::cache_hint + L1 + L2 eviction (scalar L2 eviction is dropped) +define void @test_store_cache_hint_with_all(ptr addrspace(1) %p, i32 %v) { +; CHECK-LABEL: test_store_cache_hint_with_all( +; CHECK: mov.b64 %rd2, 12345; +; CHECK: st.global.L1::no_allocate.L2::cache_hint.b32 [%rd1], %r1, %rd2; + store i32 %v, ptr addrspace(1) %p, !mem.cache_hint !13 + ret void +} + +; Vector load: L2::cache_hint + L1 eviction +define <2 x i32> @test_load_cache_hint_v2i32_with_l1(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_cache_hint_v2i32_with_l1( +; CHECK: mov.b64 %rd2, 12345; +; CHECK: ld.global.L1::evict_first.L2::cache_hint.v2.b32 {%r1, %r2}, [%rd1], %rd2; + %v = load <2 x i32>, ptr addrspace(1) %p, !mem.cache_hint !15 + ret <2 x i32> %v +} + +; Vector store: cache policy and L1 are emitted; L2 eviction/prefetch are dropped +define void @test_store_cache_hint_v2i32_with_all(ptr addrspace(1) %p, <2 x i32> %v) { +; CHECK-LABEL: test_store_cache_hint_v2i32_with_all( +; CHECK: mov.b64 %rd2, 12345; +; CHECK: st.global.L1::evict_last.L2::cache_hint.v2.b32 [%rd1], {%r1, %r2}, %rd2; + store <2 x i32> %v, ptr addrspace(1) %p, !mem.cache_hint !17 + ret void +} + +;----------------------------------------------------------------------------- +; Metadata definitions +;----------------------------------------------------------------------------- + +!0 = !{i32 0, !2} +!1 = !{i32 1, !2} +!2 = !{!"nvvm.l2_cache_hint", i64 12345} +!3 = !{i32 0, !4} +!4 = !{!"nvvm.l2_cache_hint", i64 12345, !"nvvm.l1_eviction", !"first"} +!5 = !{i32 0, !6} +!6 = !{!"nvvm.l2_cache_hint", i64 12345, !"nvvm.l2_eviction", !"last"} +!7 = !{i32 0, !8} +!8 = !{!"nvvm.l2_cache_hint", i64 12345, !"nvvm.l2_prefetch_size", !"128B"} +!9 = !{i32 0, !10} +!10 = !{!"nvvm.l2_cache_hint", i64 12345, !"nvvm.l1_eviction", !"last", !"nvvm.l2_eviction", !"first", !"nvvm.l2_prefetch_size", !"256B"} +!11 = !{i32 1, !12} +!12 = !{!"nvvm.l2_cache_hint", i64 12345, !"nvvm.l1_eviction", !"unchanged"} +!13 = !{i32 1, !14} +!14 = !{!"nvvm.l2_cache_hint", i64 12345, !"nvvm.l1_eviction", !"no_allocate", !"nvvm.l2_eviction", !"last"} +!15 = !{i32 0, !16} +!16 = !{!"nvvm.l2_cache_hint", i64 12345, !"nvvm.l1_eviction", !"first"} +!17 = !{i32 1, !18} +!18 = !{!"nvvm.l2_cache_hint", i64 12345, !"nvvm.l1_eviction", !"last", !"nvvm.l2_eviction", !"first", !"nvvm.l2_prefetch_size", !"64B"} diff --git a/llvm/test/CodeGen/NVPTX/cache-hint-intrinsics.ll b/llvm/test/CodeGen/NVPTX/cache-hint-intrinsics.ll new file mode 100644 index 0000000000000..59bac44244460 --- /dev/null +++ b/llvm/test/CodeGen/NVPTX/cache-hint-intrinsics.ll @@ -0,0 +1,622 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --filter "^\s*(?:mov\.b64|ld(?:\.[A-Za-z0-9_:]+)*\.global|st(?:\.[A-Za-z0-9_:]+)*\.global|atom(?:\.[A-Za-z0-9_:]+)*\.global)" --version 6 +; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 | FileCheck %s +; RUN: %if ptxas %{ llc < %s -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 | %ptxas-verify %} + +; Test !mem.cache_hint metadata on LLVM memory intrinsics. +; +; For memcpy: +; operand_no = 0 applies to destination (store side) +; operand_no = 1 applies to source (load side) +; +; TODO: Teach memcpy lowering to preserve L2::evict_* on SM100/PTX 8.8 when +; an aligned, 32-byte-multiple copy can use a PTX-legal 256-bit vector memory +; operation. Current memcpy expansion uses scalar or short accesses, so the +; L2 eviction metadata in the cases below is intentionally dropped. + +declare void @llvm.memcpy.p1.p1.i64(ptr addrspace(1), ptr addrspace(1), i64, i1) +declare <2 x i16> @llvm.masked.load.v2i16.p1(ptr addrspace(1), <2 x i1>, <2 x i16>) +declare <4 x i32> @llvm.masked.load.v4i32.p1(ptr addrspace(1), <4 x i1>, <4 x i32>) + +;----------------------------------------------------------------------------- +; Test memcpy with cache hints on both source and destination +; Source (operand 1): L1::evict_first, L2::evict_first, L2::128B +; Dest (operand 0): L1::evict_last, L2::evict_last +;----------------------------------------------------------------------------- + +define void @test_memcpy_both_hints(ptr addrspace(1) %dest, ptr addrspace(1) %src) { +; CHECK-LABEL: test_memcpy_both_hints( +; CHECK: ld.global.L1::evict_first.L2::128B.b8 %rs1, [%rd2+3]; +; CHECK: st.global.L1::evict_last.b8 [%rd1+3], %rs1; +; CHECK: ld.global.L1::evict_first.L2::128B.b8 %rs2, [%rd2+2]; +; CHECK: st.global.L1::evict_last.b8 [%rd1+2], %rs2; +; CHECK: ld.global.L1::evict_first.L2::128B.b8 %rs3, [%rd2+1]; +; CHECK: st.global.L1::evict_last.b8 [%rd1+1], %rs3; +; CHECK: ld.global.L1::evict_first.L2::128B.b8 %rs4, [%rd2]; +; CHECK: st.global.L1::evict_last.b8 [%rd1], %rs4; + call void @llvm.memcpy.p1.p1.i64(ptr addrspace(1) %dest, ptr addrspace(1) %src, i64 4, i1 false), !mem.cache_hint !80 + ret void +} + +;----------------------------------------------------------------------------- +; Test memcpy with cache hint only on source (load side) +; Source (operand 1): L1::evict_first +; Dest (operand 0): no hint +;----------------------------------------------------------------------------- + +define void @test_memcpy_src_hint_only(ptr addrspace(1) %dest, ptr addrspace(1) %src) { +; CHECK-LABEL: test_memcpy_src_hint_only( +; CHECK: ld.global.L1::evict_first.b8 %rs1, [%rd2+3]; +; CHECK: st.global.b8 [%rd1+3], %rs1; +; CHECK: ld.global.L1::evict_first.b8 %rs2, [%rd2+2]; +; CHECK: st.global.b8 [%rd1+2], %rs2; +; CHECK: ld.global.L1::evict_first.b8 %rs3, [%rd2+1]; +; CHECK: st.global.b8 [%rd1+1], %rs3; +; CHECK: ld.global.L1::evict_first.b8 %rs4, [%rd2]; +; CHECK: st.global.b8 [%rd1], %rs4; + call void @llvm.memcpy.p1.p1.i64(ptr addrspace(1) %dest, ptr addrspace(1) %src, i64 4, i1 false), !mem.cache_hint !81 + ret void +} + +;----------------------------------------------------------------------------- +; Test memcpy with L2 prefetch only on source (load side) +; Source (operand 1): L2::128B +; Dest (operand 0): no hint +;----------------------------------------------------------------------------- + +define void @test_memcpy_src_prefetch_only(ptr addrspace(1) %dest, ptr addrspace(1) %src) { +; CHECK-LABEL: test_memcpy_src_prefetch_only( +; CHECK: ld.global.L2::128B.b8 %rs1, [%rd2+3]; +; CHECK: st.global.b8 [%rd1+3], %rs1; +; CHECK: ld.global.L2::128B.b8 %rs2, [%rd2+2]; +; CHECK: st.global.b8 [%rd1+2], %rs2; +; CHECK: ld.global.L2::128B.b8 %rs3, [%rd2+1]; +; CHECK: st.global.b8 [%rd1+1], %rs3; +; CHECK: ld.global.L2::128B.b8 %rs4, [%rd2]; +; CHECK: st.global.b8 [%rd1], %rs4; + call void @llvm.memcpy.p1.p1.i64(ptr addrspace(1) %dest, ptr addrspace(1) %src, i64 4, i1 false), !mem.cache_hint !82 + ret void +} + +;----------------------------------------------------------------------------- +; Test memcpy with L2::cache_hint on both operands +;----------------------------------------------------------------------------- + +define void @test_memcpy_l2_cache_hint(ptr addrspace(1) %dest, ptr addrspace(1) %src) { +; CHECK-LABEL: test_memcpy_l2_cache_hint( +; CHECK: mov.b64 %rd2, 12345; +; CHECK: ld.global.L2::cache_hint.b8 %rs1, [%rd3+3], %rd2; +; CHECK: st.global.L2::cache_hint.b8 [%rd1+3], %rs1, %rd2; +; CHECK: ld.global.L2::cache_hint.b8 %rs2, [%rd3+2], %rd2; +; CHECK: st.global.L2::cache_hint.b8 [%rd1+2], %rs2, %rd2; +; CHECK: ld.global.L2::cache_hint.b8 %rs3, [%rd3+1], %rd2; +; CHECK: st.global.L2::cache_hint.b8 [%rd1+1], %rs3, %rd2; +; CHECK: ld.global.L2::cache_hint.b8 %rs4, [%rd3], %rd2; +; CHECK: st.global.L2::cache_hint.b8 [%rd1], %rs4, %rd2; + call void @llvm.memcpy.p1.p1.i64(ptr addrspace(1) %dest, ptr addrspace(1) %src, i64 4, i1 false), !mem.cache_hint !83 + ret void +} + +;----------------------------------------------------------------------------- +; Test memcpy without cache hints produces plain load/store +;----------------------------------------------------------------------------- + +define void @test_memcpy_no_hint(ptr addrspace(1) %dest, ptr addrspace(1) %src) { +; CHECK-LABEL: test_memcpy_no_hint( +; CHECK: ld.global.b8 %rs1, [%rd2+3]; +; CHECK: st.global.b8 [%rd1+3], %rs1; +; CHECK: ld.global.b8 %rs2, [%rd2+2]; +; CHECK: st.global.b8 [%rd1+2], %rs2; +; CHECK: ld.global.b8 %rs3, [%rd2+1]; +; CHECK: st.global.b8 [%rd1+1], %rs3; +; CHECK: ld.global.b8 %rs4, [%rd2]; +; CHECK: st.global.b8 [%rd1], %rs4; + call void @llvm.memcpy.p1.p1.i64(ptr addrspace(1) %dest, ptr addrspace(1) %src, i64 4, i1 false) + ret void +} + +;----------------------------------------------------------------------------- +; Combined L1 + L2 eviction policies +;----------------------------------------------------------------------------- + +; Source: L1::evict_first + L2::evict_last +; Dest: no hint +define void @test_memcpy_src_l1_l2_combined(ptr addrspace(1) %dest, ptr addrspace(1) %src) { +; CHECK-LABEL: test_memcpy_src_l1_l2_combined( +; CHECK: ld.global.L1::evict_first.b8 %rs1, [%rd2+3]; +; CHECK: st.global.b8 [%rd1+3], %rs1; +; CHECK: ld.global.L1::evict_first.b8 %rs2, [%rd2+2]; +; CHECK: st.global.b8 [%rd1+2], %rs2; +; CHECK: ld.global.L1::evict_first.b8 %rs3, [%rd2+1]; +; CHECK: st.global.b8 [%rd1+1], %rs3; +; CHECK: ld.global.L1::evict_first.b8 %rs4, [%rd2]; +; CHECK: st.global.b8 [%rd1], %rs4; + call void @llvm.memcpy.p1.p1.i64(ptr addrspace(1) %dest, ptr addrspace(1) %src, i64 4, i1 false), !mem.cache_hint !84 + ret void +} + +; Source: no hint +; Dest: L1::evict_unchanged + L2::evict_first +define void @test_memcpy_dest_l1_l2_combined(ptr addrspace(1) %dest, ptr addrspace(1) %src) { +; CHECK-LABEL: test_memcpy_dest_l1_l2_combined( +; CHECK: ld.global.b8 %rs1, [%rd2+3]; +; CHECK: st.global.L1::evict_unchanged.b8 [%rd1+3], %rs1; +; CHECK: ld.global.b8 %rs2, [%rd2+2]; +; CHECK: st.global.L1::evict_unchanged.b8 [%rd1+2], %rs2; +; CHECK: ld.global.b8 %rs3, [%rd2+1]; +; CHECK: st.global.L1::evict_unchanged.b8 [%rd1+1], %rs3; +; CHECK: ld.global.b8 %rs4, [%rd2]; +; CHECK: st.global.L1::evict_unchanged.b8 [%rd1], %rs4; + call void @llvm.memcpy.p1.p1.i64(ptr addrspace(1) %dest, ptr addrspace(1) %src, i64 4, i1 false), !mem.cache_hint !85 + ret void +} + +;----------------------------------------------------------------------------- +; L1 + prefetch combinations +;----------------------------------------------------------------------------- + +; Source: L1::evict_last + L2::256B prefetch +; Dest: L1::no_allocate +define void @test_memcpy_l1_prefetch(ptr addrspace(1) %dest, ptr addrspace(1) %src) { +; CHECK-LABEL: test_memcpy_l1_prefetch( +; CHECK: ld.global.L1::evict_last.L2::256B.b8 %rs1, [%rd2+3]; +; CHECK: st.global.L1::no_allocate.b8 [%rd1+3], %rs1; +; CHECK: ld.global.L1::evict_last.L2::256B.b8 %rs2, [%rd2+2]; +; CHECK: st.global.L1::no_allocate.b8 [%rd1+2], %rs2; +; CHECK: ld.global.L1::evict_last.L2::256B.b8 %rs3, [%rd2+1]; +; CHECK: st.global.L1::no_allocate.b8 [%rd1+1], %rs3; +; CHECK: ld.global.L1::evict_last.L2::256B.b8 %rs4, [%rd2]; +; CHECK: st.global.L1::no_allocate.b8 [%rd1], %rs4; + call void @llvm.memcpy.p1.p1.i64(ptr addrspace(1) %dest, ptr addrspace(1) %src, i64 4, i1 false), !mem.cache_hint !86 + ret void +} + +; Source: L2::64B prefetch only +; Dest: L2::evict_last only +define void @test_memcpy_prefetch_vs_eviction(ptr addrspace(1) %dest, ptr addrspace(1) %src) { +; CHECK-LABEL: test_memcpy_prefetch_vs_eviction( +; CHECK: ld.global.L2::64B.b8 %rs1, [%rd2+3]; +; CHECK: st.global.b8 [%rd1+3], %rs1; +; CHECK: ld.global.L2::64B.b8 %rs2, [%rd2+2]; +; CHECK: st.global.b8 [%rd1+2], %rs2; +; CHECK: ld.global.L2::64B.b8 %rs3, [%rd2+1]; +; CHECK: st.global.b8 [%rd1+1], %rs3; +; CHECK: ld.global.L2::64B.b8 %rs4, [%rd2]; +; CHECK: st.global.b8 [%rd1], %rs4; + call void @llvm.memcpy.p1.p1.i64(ptr addrspace(1) %dest, ptr addrspace(1) %src, i64 4, i1 false), !mem.cache_hint !87 + ret void +} + +;----------------------------------------------------------------------------- +; L2::cache_hint combined with other hints +;----------------------------------------------------------------------------- + +; Source: L2::cache_hint + L1::evict_first +; Dest: no hint +define void @test_memcpy_src_cache_hint_l1(ptr addrspace(1) %dest, ptr addrspace(1) %src) { +; CHECK-LABEL: test_memcpy_src_cache_hint_l1( +; CHECK: mov.b64 %rd2, 12345; +; CHECK: ld.global.L1::evict_first.L2::cache_hint.b8 %rs1, [%rd3+3], %rd2; +; CHECK: st.global.b8 [%rd1+3], %rs1; +; CHECK: ld.global.L1::evict_first.L2::cache_hint.b8 %rs2, [%rd3+2], %rd2; +; CHECK: st.global.b8 [%rd1+2], %rs2; +; CHECK: ld.global.L1::evict_first.L2::cache_hint.b8 %rs3, [%rd3+1], %rd2; +; CHECK: st.global.b8 [%rd1+1], %rs3; +; CHECK: ld.global.L1::evict_first.L2::cache_hint.b8 %rs4, [%rd3], %rd2; +; CHECK: st.global.b8 [%rd1], %rs4; + call void @llvm.memcpy.p1.p1.i64(ptr addrspace(1) %dest, ptr addrspace(1) %src, i64 4, i1 false), !mem.cache_hint !88 + ret void +} + +; Source: no hint +; Dest: L2::cache_hint + L1::evict_last + L2::evict_first +define void @test_memcpy_dest_cache_hint_combined(ptr addrspace(1) %dest, ptr addrspace(1) %src) { +; CHECK-LABEL: test_memcpy_dest_cache_hint_combined( +; CHECK: ld.global.b8 %rs1, [%rd2+3]; +; CHECK: mov.b64 %rd3, 12345; +; CHECK: st.global.L1::evict_last.L2::cache_hint.b8 [%rd1+3], %rs1, %rd3; +; CHECK: ld.global.b8 %rs2, [%rd2+2]; +; CHECK: st.global.L1::evict_last.L2::cache_hint.b8 [%rd1+2], %rs2, %rd3; +; CHECK: ld.global.b8 %rs3, [%rd2+1]; +; CHECK: st.global.L1::evict_last.L2::cache_hint.b8 [%rd1+1], %rs3, %rd3; +; CHECK: ld.global.b8 %rs4, [%rd2]; +; CHECK: st.global.L1::evict_last.L2::cache_hint.b8 [%rd1], %rs4, %rd3; + call void @llvm.memcpy.p1.p1.i64(ptr addrspace(1) %dest, ptr addrspace(1) %src, i64 4, i1 false), !mem.cache_hint !89 + ret void +} + +; Both operands: L2::cache_hint + L1 eviction + L2 eviction +; Source: L2::cache_hint + L1::evict_unchanged + L2::evict_last +; Dest: L2::cache_hint + L1::evict_first + L2::evict_first +define void @test_memcpy_both_cache_hint_combined(ptr addrspace(1) %dest, ptr addrspace(1) %src) { +; CHECK-LABEL: test_memcpy_both_cache_hint_combined( +; CHECK: mov.b64 %rd2, 12345; +; CHECK: ld.global.L1::evict_unchanged.L2::cache_hint.b8 %rs1, [%rd3+3], %rd2; +; CHECK: st.global.L1::evict_first.L2::cache_hint.b8 [%rd1+3], %rs1, %rd2; +; CHECK: ld.global.L1::evict_unchanged.L2::cache_hint.b8 %rs2, [%rd3+2], %rd2; +; CHECK: st.global.L1::evict_first.L2::cache_hint.b8 [%rd1+2], %rs2, %rd2; +; CHECK: ld.global.L1::evict_unchanged.L2::cache_hint.b8 %rs3, [%rd3+1], %rd2; +; CHECK: st.global.L1::evict_first.L2::cache_hint.b8 [%rd1+1], %rs3, %rd2; +; CHECK: ld.global.L1::evict_unchanged.L2::cache_hint.b8 %rs4, [%rd3], %rd2; +; CHECK: st.global.L1::evict_first.L2::cache_hint.b8 [%rd1], %rs4, %rd2; + call void @llvm.memcpy.p1.p1.i64(ptr addrspace(1) %dest, ptr addrspace(1) %src, i64 4, i1 false), !mem.cache_hint !90 + ret void +} + +;----------------------------------------------------------------------------- +; L2::cache_hint + prefetch combinations +;----------------------------------------------------------------------------- + +; Source: L2::cache_hint + L2::128B prefetch +; Dest: L2::cache_hint + L1::evict_last +define void @test_memcpy_cache_hint_prefetch(ptr addrspace(1) %dest, ptr addrspace(1) %src) { +; CHECK-LABEL: test_memcpy_cache_hint_prefetch( +; CHECK: mov.b64 %rd2, 12345; +; CHECK: ld.global.L2::cache_hint.L2::128B.b8 %rs1, [%rd3+3], %rd2; +; CHECK: st.global.L1::evict_last.L2::cache_hint.b8 [%rd1+3], %rs1, %rd2; +; CHECK: ld.global.L2::cache_hint.L2::128B.b8 %rs2, [%rd3+2], %rd2; +; CHECK: st.global.L1::evict_last.L2::cache_hint.b8 [%rd1+2], %rs2, %rd2; +; CHECK: ld.global.L2::cache_hint.L2::128B.b8 %rs3, [%rd3+1], %rd2; +; CHECK: st.global.L1::evict_last.L2::cache_hint.b8 [%rd1+1], %rs3, %rd2; +; CHECK: ld.global.L2::cache_hint.L2::128B.b8 %rs4, [%rd3], %rd2; +; CHECK: st.global.L1::evict_last.L2::cache_hint.b8 [%rd1], %rs4, %rd2; + call void @llvm.memcpy.p1.p1.i64(ptr addrspace(1) %dest, ptr addrspace(1) %src, i64 4, i1 false), !mem.cache_hint !91 + ret void +} + +;----------------------------------------------------------------------------- +; Asymmetric hint combinations (complex vs simple) +;----------------------------------------------------------------------------- + +; Source: all hints (L1 + L2 eviction + prefetch) +; Dest: simple L1 hint only +define void @test_memcpy_complex_src_simple_dest(ptr addrspace(1) %dest, ptr addrspace(1) %src) { +; CHECK-LABEL: test_memcpy_complex_src_simple_dest( +; CHECK: ld.global.L1::evict_first.L2::64B.b8 %rs1, [%rd2+3]; +; CHECK: st.global.L1::evict_last.b8 [%rd1+3], %rs1; +; CHECK: ld.global.L1::evict_first.L2::64B.b8 %rs2, [%rd2+2]; +; CHECK: st.global.L1::evict_last.b8 [%rd1+2], %rs2; +; CHECK: ld.global.L1::evict_first.L2::64B.b8 %rs3, [%rd2+1]; +; CHECK: st.global.L1::evict_last.b8 [%rd1+1], %rs3; +; CHECK: ld.global.L1::evict_first.L2::64B.b8 %rs4, [%rd2]; +; CHECK: st.global.L1::evict_last.b8 [%rd1], %rs4; + call void @llvm.memcpy.p1.p1.i64(ptr addrspace(1) %dest, ptr addrspace(1) %src, i64 4, i1 false), !mem.cache_hint !92 + ret void +} + +; Source: simple L2 prefetch only +; Dest: all hints (L1 + L2 eviction + L2::cache_hint) +define void @test_memcpy_simple_src_complex_dest(ptr addrspace(1) %dest, ptr addrspace(1) %src) { +; CHECK-LABEL: test_memcpy_simple_src_complex_dest( +; CHECK: ld.global.L2::256B.b8 %rs1, [%rd2+3]; +; CHECK: mov.b64 %rd3, 12345; +; CHECK: st.global.L1::no_allocate.L2::cache_hint.b8 [%rd1+3], %rs1, %rd3; +; CHECK: ld.global.L2::256B.b8 %rs2, [%rd2+2]; +; CHECK: st.global.L1::no_allocate.L2::cache_hint.b8 [%rd1+2], %rs2, %rd3; +; CHECK: ld.global.L2::256B.b8 %rs3, [%rd2+1]; +; CHECK: st.global.L1::no_allocate.L2::cache_hint.b8 [%rd1+1], %rs3, %rd3; +; CHECK: ld.global.L2::256B.b8 %rs4, [%rd2]; +; CHECK: st.global.L1::no_allocate.L2::cache_hint.b8 [%rd1], %rs4, %rd3; + call void @llvm.memcpy.p1.p1.i64(ptr addrspace(1) %dest, ptr addrspace(1) %src, i64 4, i1 false), !mem.cache_hint !93 + ret void +} + +;----------------------------------------------------------------------------- +; Different L1 eviction policies on src vs dest +;----------------------------------------------------------------------------- + +; Source: L1::evict_unchanged +; Dest: L1::evict_first +define void @test_memcpy_different_l1_policies(ptr addrspace(1) %dest, ptr addrspace(1) %src) { +; CHECK-LABEL: test_memcpy_different_l1_policies( +; CHECK: ld.global.L1::evict_unchanged.b8 %rs1, [%rd2+3]; +; CHECK: st.global.L1::evict_first.b8 [%rd1+3], %rs1; +; CHECK: ld.global.L1::evict_unchanged.b8 %rs2, [%rd2+2]; +; CHECK: st.global.L1::evict_first.b8 [%rd1+2], %rs2; +; CHECK: ld.global.L1::evict_unchanged.b8 %rs3, [%rd2+1]; +; CHECK: st.global.L1::evict_first.b8 [%rd1+1], %rs3; +; CHECK: ld.global.L1::evict_unchanged.b8 %rs4, [%rd2]; +; CHECK: st.global.L1::evict_first.b8 [%rd1], %rs4; + call void @llvm.memcpy.p1.p1.i64(ptr addrspace(1) %dest, ptr addrspace(1) %src, i64 4, i1 false), !mem.cache_hint !94 + ret void +} + +; Source: L1::no_allocate +; Dest: L1::evict_unchanged +define void @test_memcpy_no_allocate_vs_unchanged(ptr addrspace(1) %dest, ptr addrspace(1) %src) { +; CHECK-LABEL: test_memcpy_no_allocate_vs_unchanged( +; CHECK: ld.global.L1::no_allocate.b8 %rs1, [%rd2+3]; +; CHECK: st.global.L1::evict_unchanged.b8 [%rd1+3], %rs1; +; CHECK: ld.global.L1::no_allocate.b8 %rs2, [%rd2+2]; +; CHECK: st.global.L1::evict_unchanged.b8 [%rd1+2], %rs2; +; CHECK: ld.global.L1::no_allocate.b8 %rs3, [%rd2+1]; +; CHECK: st.global.L1::evict_unchanged.b8 [%rd1+1], %rs3; +; CHECK: ld.global.L1::no_allocate.b8 %rs4, [%rd2]; +; CHECK: st.global.L1::evict_unchanged.b8 [%rd1], %rs4; + call void @llvm.memcpy.p1.p1.i64(ptr addrspace(1) %dest, ptr addrspace(1) %src, i64 4, i1 false), !mem.cache_hint !95 + ret void +} + +;----------------------------------------------------------------------------- +; All hints maxed out on both operands +;----------------------------------------------------------------------------- + +; Source: L1::evict_first + L2::evict_first + L2::256B + L2::cache_hint +; Dest: L1::evict_last + L2::evict_last + L2::128B + L2::cache_hint +define void @test_memcpy_all_hints_both(ptr addrspace(1) %dest, ptr addrspace(1) %src) { +; CHECK-LABEL: test_memcpy_all_hints_both( +; CHECK: mov.b64 %rd2, 12345; +; CHECK: ld.global.L1::evict_first.L2::cache_hint.L2::256B.b8 %rs1, [%rd3+3], %rd2; +; CHECK: st.global.L1::evict_last.L2::cache_hint.b8 [%rd1+3], %rs1, %rd2; +; CHECK: ld.global.L1::evict_first.L2::cache_hint.L2::256B.b8 %rs2, [%rd3+2], %rd2; +; CHECK: st.global.L1::evict_last.L2::cache_hint.b8 [%rd1+2], %rs2, %rd2; +; CHECK: ld.global.L1::evict_first.L2::cache_hint.L2::256B.b8 %rs3, [%rd3+1], %rd2; +; CHECK: st.global.L1::evict_last.L2::cache_hint.b8 [%rd1+1], %rs3, %rd2; +; CHECK: ld.global.L1::evict_first.L2::cache_hint.L2::256B.b8 %rs4, [%rd3], %rd2; +; CHECK: st.global.L1::evict_last.L2::cache_hint.b8 [%rd1], %rs4, %rd2; + call void @llvm.memcpy.p1.p1.i64(ptr addrspace(1) %dest, ptr addrspace(1) %src, i64 4, i1 false), !mem.cache_hint !96 + ret void +} + +;----------------------------------------------------------------------------- +; TODO: Preserve cache hints on llvm.masked.load. +; Masked load pointer operand is operand 0. SelectionDAGBuilder::visitMaskedLoad +; does not currently thread !mem.cache_hint into the MachineMemOperand, so the +; generated loads are plain today. +;----------------------------------------------------------------------------- + +; TODO: This should eventually lower to ld.global.L1::evict_first.b32. +define <2 x i16> @test_masked_load_l1_hint_v2i16(ptr addrspace(1) %p) { +; CHECK-LABEL: test_masked_load_l1_hint_v2i16( +; CHECK: ld.global.b32 %r1, [%rd1]; + %v = call <2 x i16> @llvm.masked.load.v2i16.p1(ptr addrspace(1) align 4 %p, <2 x i1> , <2 x i16> poison), !mem.cache_hint !101 + ret <2 x i16> %v +} + +; TODO: This should eventually lower to ld.global.L2::cache_hint.v4.b32. +define <4 x i32> @test_masked_load_l2_cache_policy_v4i32(ptr addrspace(1) %p) { +; CHECK-LABEL: test_masked_load_l2_cache_policy_v4i32( +; CHECK: ld.global.v4.b32 {%r1, %r2, %r3, %r4}, [%rd1]; + %v = call <4 x i32> @llvm.masked.load.v4i32.p1(ptr addrspace(1) align 16 %p, <4 x i1> , <4 x i32> poison), !mem.cache_hint !102 + ret <4 x i32> %v +} + +;----------------------------------------------------------------------------- +; Large memcpy tests - verify hints propagate to all expanded load/stores +; LLVM expands memcpy to multiple load/store pairs. Each pair should +; get the appropriate cache hints from the original memcpy metadata. +; The expansion may use various sizes (b8, b16, b32, v2, v4, etc.) +;----------------------------------------------------------------------------- + +; 16-byte memcpy: verify hints are applied to expanded loads/stores +define void @test_memcpy_16bytes(ptr addrspace(1) %dest, ptr addrspace(1) %src) { +; CHECK-LABEL: test_memcpy_16bytes( +; CHECK: ld.global.L1::evict_first.b8 %rs1, [%rd2+15]; +; CHECK: st.global.L1::evict_last.b8 [%rd1+15], %rs1; +; CHECK: ld.global.L1::evict_first.b8 %rs2, [%rd2+14]; +; CHECK: st.global.L1::evict_last.b8 [%rd1+14], %rs2; +; CHECK: ld.global.L1::evict_first.b8 %rs3, [%rd2+13]; +; CHECK: st.global.L1::evict_last.b8 [%rd1+13], %rs3; +; CHECK: ld.global.L1::evict_first.b8 %rs4, [%rd2+12]; +; CHECK: st.global.L1::evict_last.b8 [%rd1+12], %rs4; +; CHECK: ld.global.L1::evict_first.b8 %rs5, [%rd2+11]; +; CHECK: st.global.L1::evict_last.b8 [%rd1+11], %rs5; +; CHECK: ld.global.L1::evict_first.b8 %rs6, [%rd2+10]; +; CHECK: st.global.L1::evict_last.b8 [%rd1+10], %rs6; +; CHECK: ld.global.L1::evict_first.b8 %rs7, [%rd2+9]; +; CHECK: st.global.L1::evict_last.b8 [%rd1+9], %rs7; +; CHECK: ld.global.L1::evict_first.b8 %rs8, [%rd2+8]; +; CHECK: st.global.L1::evict_last.b8 [%rd1+8], %rs8; +; CHECK: ld.global.L1::evict_first.b8 %rs9, [%rd2+7]; +; CHECK: st.global.L1::evict_last.b8 [%rd1+7], %rs9; +; CHECK: ld.global.L1::evict_first.b8 %rs10, [%rd2+6]; +; CHECK: st.global.L1::evict_last.b8 [%rd1+6], %rs10; +; CHECK: ld.global.L1::evict_first.b8 %rs11, [%rd2+5]; +; CHECK: st.global.L1::evict_last.b8 [%rd1+5], %rs11; +; CHECK: ld.global.L1::evict_first.b8 %rs12, [%rd2+4]; +; CHECK: st.global.L1::evict_last.b8 [%rd1+4], %rs12; +; CHECK: ld.global.L1::evict_first.b8 %rs13, [%rd2+3]; +; CHECK: st.global.L1::evict_last.b8 [%rd1+3], %rs13; +; CHECK: ld.global.L1::evict_first.b8 %rs14, [%rd2+2]; +; CHECK: st.global.L1::evict_last.b8 [%rd1+2], %rs14; +; CHECK: ld.global.L1::evict_first.b8 %rs15, [%rd2+1]; +; CHECK: st.global.L1::evict_last.b8 [%rd1+1], %rs15; +; CHECK: ld.global.L1::evict_first.b8 %rs16, [%rd2]; +; CHECK: st.global.L1::evict_last.b8 [%rd1], %rs16; + call void @llvm.memcpy.p1.p1.i64(ptr addrspace(1) %dest, ptr addrspace(1) %src, i64 16, i1 false), !mem.cache_hint !97 + ret void +} + +; 32-byte memcpy: all loads should have L1::evict_unchanged. +; TODO: Preserve the destination L2::evict_first metadata when memcpy lowering +; can select a PTX-legal 256-bit vector store for aligned 32-byte copies. +define void @test_memcpy_32bytes(ptr addrspace(1) %dest, ptr addrspace(1) %src) { +; CHECK-LABEL: test_memcpy_32bytes( +; CHECK: ld.global.L1::evict_unchanged.b8 %rs1, [%rd2+31]; +; CHECK: st.global.b8 [%rd1+31], %rs1; +; CHECK: ld.global.L1::evict_unchanged.b8 %rs2, [%rd2+30]; +; CHECK: st.global.b8 [%rd1+30], %rs2; +; CHECK: ld.global.L1::evict_unchanged.b8 %rs3, [%rd2+29]; +; CHECK: st.global.b8 [%rd1+29], %rs3; +; CHECK: ld.global.L1::evict_unchanged.b8 %rs4, [%rd2+28]; +; CHECK: st.global.b8 [%rd1+28], %rs4; +; CHECK: ld.global.L1::evict_unchanged.b8 %rs5, [%rd2+27]; +; CHECK: st.global.b8 [%rd1+27], %rs5; +; CHECK: ld.global.L1::evict_unchanged.b8 %rs6, [%rd2+26]; +; CHECK: st.global.b8 [%rd1+26], %rs6; +; CHECK: ld.global.L1::evict_unchanged.b8 %rs7, [%rd2+25]; +; CHECK: st.global.b8 [%rd1+25], %rs7; +; CHECK: ld.global.L1::evict_unchanged.b8 %rs8, [%rd2+24]; +; CHECK: st.global.b8 [%rd1+24], %rs8; +; CHECK: ld.global.L1::evict_unchanged.b8 %rs9, [%rd2+23]; +; CHECK: st.global.b8 [%rd1+23], %rs9; +; CHECK: ld.global.L1::evict_unchanged.b8 %rs10, [%rd2+22]; +; CHECK: st.global.b8 [%rd1+22], %rs10; +; CHECK: ld.global.L1::evict_unchanged.b8 %rs11, [%rd2+21]; +; CHECK: st.global.b8 [%rd1+21], %rs11; +; CHECK: ld.global.L1::evict_unchanged.b8 %rs12, [%rd2+20]; +; CHECK: st.global.b8 [%rd1+20], %rs12; +; CHECK: ld.global.L1::evict_unchanged.b8 %rs13, [%rd2+19]; +; CHECK: st.global.b8 [%rd1+19], %rs13; +; CHECK: ld.global.L1::evict_unchanged.b8 %rs14, [%rd2+18]; +; CHECK: st.global.b8 [%rd1+18], %rs14; +; CHECK: ld.global.L1::evict_unchanged.b8 %rs15, [%rd2+17]; +; CHECK: st.global.b8 [%rd1+17], %rs15; +; CHECK: ld.global.L1::evict_unchanged.b8 %rs16, [%rd2+16]; +; CHECK: st.global.b8 [%rd1+16], %rs16; +; CHECK: ld.global.L1::evict_unchanged.b8 %rs17, [%rd2+15]; +; CHECK: st.global.b8 [%rd1+15], %rs17; +; CHECK: ld.global.L1::evict_unchanged.b8 %rs18, [%rd2+14]; +; CHECK: st.global.b8 [%rd1+14], %rs18; +; CHECK: ld.global.L1::evict_unchanged.b8 %rs19, [%rd2+13]; +; CHECK: st.global.b8 [%rd1+13], %rs19; +; CHECK: ld.global.L1::evict_unchanged.b8 %rs20, [%rd2+12]; +; CHECK: st.global.b8 [%rd1+12], %rs20; +; CHECK: ld.global.L1::evict_unchanged.b8 %rs21, [%rd2+11]; +; CHECK: st.global.b8 [%rd1+11], %rs21; +; CHECK: ld.global.L1::evict_unchanged.b8 %rs22, [%rd2+10]; +; CHECK: st.global.b8 [%rd1+10], %rs22; +; CHECK: ld.global.L1::evict_unchanged.b8 %rs23, [%rd2+9]; +; CHECK: st.global.b8 [%rd1+9], %rs23; +; CHECK: ld.global.L1::evict_unchanged.b8 %rs24, [%rd2+8]; +; CHECK: st.global.b8 [%rd1+8], %rs24; +; CHECK: ld.global.L1::evict_unchanged.b8 %rs25, [%rd2+7]; +; CHECK: st.global.b8 [%rd1+7], %rs25; +; CHECK: ld.global.L1::evict_unchanged.b8 %rs26, [%rd2+6]; +; CHECK: st.global.b8 [%rd1+6], %rs26; +; CHECK: ld.global.L1::evict_unchanged.b8 %rs27, [%rd2+5]; +; CHECK: st.global.b8 [%rd1+5], %rs27; +; CHECK: ld.global.L1::evict_unchanged.b8 %rs28, [%rd2+4]; +; CHECK: st.global.b8 [%rd1+4], %rs28; +; CHECK: ld.global.L1::evict_unchanged.b8 %rs29, [%rd2+3]; +; CHECK: st.global.b8 [%rd1+3], %rs29; +; CHECK: ld.global.L1::evict_unchanged.b8 %rs30, [%rd2+2]; +; CHECK: st.global.b8 [%rd1+2], %rs30; +; CHECK: ld.global.L1::evict_unchanged.b8 %rs31, [%rd2+1]; +; CHECK: st.global.b8 [%rd1+1], %rs31; +; CHECK: ld.global.L1::evict_unchanged.b8 %rs32, [%rd2]; +; CHECK: st.global.b8 [%rd1], %rs32; + call void @llvm.memcpy.p1.p1.i64(ptr addrspace(1) %dest, ptr addrspace(1) %src, i64 32, i1 false), !mem.cache_hint !98 + ret void +} + +; 128-byte memcpy with combined hints +; Note: Large memcpy (>64 bytes) is expanded to a loop in the backend. +; Cache hints are not preserved for loop-based expansion. +; This test verifies the code compiles correctly. +define void @test_memcpy_128bytes_combined(ptr addrspace(1) %dest, ptr addrspace(1) %src) { +; CHECK-LABEL: test_memcpy_128bytes_combined( +; CHECK: mov.b64 %rd5, 0; +; CHECK: ld.global.b8 %rs1, [%rd3]; +; CHECK: st.global.b8 [%rd4], %rs1; + call void @llvm.memcpy.p1.p1.i64(ptr addrspace(1) %dest, ptr addrspace(1) %src, i64 128, i1 false), !mem.cache_hint !100 + ret void +} + +;----------------------------------------------------------------------------- +; Metadata definitions +;----------------------------------------------------------------------------- + +; memcpy with both dest and src hints +!80 = !{i32 0, !180, i32 1, !181} +; operand 0 (dest/store): L1::evict_last, L2::evict_last +!180 = !{!"nvvm.l1_eviction", !"last", !"nvvm.l2_eviction", !"last"} +; operand 1 (src/load): L1::evict_first, L2::evict_first, L2::128B prefetch +!181 = !{!"nvvm.l1_eviction", !"first", !"nvvm.l2_eviction", !"first", !"nvvm.l2_prefetch_size", !"128B"} + +; memcpy with only source hint (load side) +!81 = !{i32 1, !182} +!182 = !{!"nvvm.l1_eviction", !"first"} + +; memcpy with source L2 prefetch (load side) +!82 = !{i32 1, !183} +!183 = !{!"nvvm.l2_prefetch_size", !"128B"} + +; memcpy with L2::cache_hint on both operands +!83 = !{i32 0, !184, i32 1, !185} +!184 = !{!"nvvm.l2_cache_hint", i64 12345} +!185 = !{!"nvvm.l2_cache_hint", i64 12345} + +; Combined L1 + L2 eviction on source only +!84 = !{i32 1, !186} +!186 = !{!"nvvm.l1_eviction", !"first", !"nvvm.l2_eviction", !"last"} + +; Combined L1 + L2 eviction on dest only +!85 = !{i32 0, !187} +!187 = !{!"nvvm.l1_eviction", !"unchanged", !"nvvm.l2_eviction", !"first"} + +; L1 + prefetch on source, L1 on dest +!86 = !{i32 0, !189, i32 1, !188} +!188 = !{!"nvvm.l1_eviction", !"last", !"nvvm.l2_prefetch_size", !"256B"} +!189 = !{!"nvvm.l1_eviction", !"no_allocate"} + +; Prefetch on source, L2 eviction on dest +!87 = !{i32 0, !191, i32 1, !190} +!190 = !{!"nvvm.l2_prefetch_size", !"64B"} +!191 = !{!"nvvm.l2_eviction", !"last"} + +; L2::cache_hint + L1 eviction on source only +!88 = !{i32 1, !192} +!192 = !{!"nvvm.l2_cache_hint", i64 12345, !"nvvm.l1_eviction", !"first"} + +; L2::cache_hint + L1 + L2 eviction on dest only +!89 = !{i32 0, !193} +!193 = !{!"nvvm.l2_cache_hint", i64 12345, !"nvvm.l1_eviction", !"last", !"nvvm.l2_eviction", !"first"} + +; Both operands: L2::cache_hint + L1 + L2 eviction +!90 = !{i32 0, !195, i32 1, !194} +!194 = !{!"nvvm.l2_cache_hint", i64 12345, !"nvvm.l1_eviction", !"unchanged", !"nvvm.l2_eviction", !"last"} +!195 = !{!"nvvm.l2_cache_hint", i64 12345, !"nvvm.l1_eviction", !"first", !"nvvm.l2_eviction", !"first"} + +; L2::cache_hint + prefetch on source, L2::cache_hint + L1 on dest +!91 = !{i32 0, !197, i32 1, !196} +!196 = !{!"nvvm.l2_cache_hint", i64 12345, !"nvvm.l2_prefetch_size", !"128B"} +!197 = !{!"nvvm.l2_cache_hint", i64 12345, !"nvvm.l1_eviction", !"last"} + +; Complex source (all non-cache_hint), simple dest +!92 = !{i32 0, !199, i32 1, !198} +!198 = !{!"nvvm.l1_eviction", !"first", !"nvvm.l2_eviction", !"last", !"nvvm.l2_prefetch_size", !"64B"} +!199 = !{!"nvvm.l1_eviction", !"last"} + +; Simple source, complex dest (with cache_hint) +!93 = !{i32 0, !201, i32 1, !200} +!200 = !{!"nvvm.l2_prefetch_size", !"256B"} +!201 = !{!"nvvm.l2_cache_hint", i64 12345, !"nvvm.l1_eviction", !"no_allocate", !"nvvm.l2_eviction", !"last"} + +; Different L1 policies: unchanged vs first +!94 = !{i32 0, !203, i32 1, !202} +!202 = !{!"nvvm.l1_eviction", !"unchanged"} +!203 = !{!"nvvm.l1_eviction", !"first"} + +; Different L1 policies: no_allocate vs unchanged +!95 = !{i32 0, !205, i32 1, !204} +!204 = !{!"nvvm.l1_eviction", !"no_allocate"} +!205 = !{!"nvvm.l1_eviction", !"unchanged"} + +; All hints maxed out on both operands +!96 = !{i32 0, !207, i32 1, !206} +!206 = !{!"nvvm.l2_cache_hint", i64 12345, !"nvvm.l1_eviction", !"first", !"nvvm.l2_eviction", !"first", !"nvvm.l2_prefetch_size", !"256B"} +!207 = !{!"nvvm.l2_cache_hint", i64 12345, !"nvvm.l1_eviction", !"last", !"nvvm.l2_eviction", !"last", !"nvvm.l2_prefetch_size", !"128B"} + +; Large memcpy metadata +!97 = !{i32 0, !209, i32 1, !208} +!208 = !{!"nvvm.l1_eviction", !"first"} +!209 = !{!"nvvm.l1_eviction", !"last"} + +!98 = !{i32 0, !211, i32 1, !210} +!210 = !{!"nvvm.l1_eviction", !"unchanged"} +!211 = !{!"nvvm.l2_eviction", !"first"} + +!99 = !{i32 0, !213, i32 1, !212} +!212 = !{!"nvvm.l2_cache_hint", i64 12345} +!213 = !{!"nvvm.l2_cache_hint", i64 12345} + +!100 = !{i32 0, !215, i32 1, !214} +!214 = !{!"nvvm.l1_eviction", !"first", !"nvvm.l2_eviction", !"last", !"nvvm.l2_prefetch_size", !"256B"} +!215 = !{!"nvvm.l1_eviction", !"last", !"nvvm.l2_eviction", !"first"} + +; Masked load metadata +!101 = !{i32 0, !216} +!216 = !{!"nvvm.l1_eviction", !"first"} + +!102 = !{i32 0, !217} +!217 = !{!"nvvm.l2_cache_hint", i64 12345} diff --git a/llvm/test/CodeGen/NVPTX/cache-hint-invalid.ll b/llvm/test/CodeGen/NVPTX/cache-hint-invalid.ll new file mode 100644 index 0000000000000..e17e4b0b496b8 --- /dev/null +++ b/llvm/test/CodeGen/NVPTX/cache-hint-invalid.ll @@ -0,0 +1,147 @@ +; RUN: split-file %s %t +; RUN: llc < %t/bad-empty.ll -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 2>&1 | FileCheck %s --check-prefix=BAD-EMPTY +; RUN: llc < %t/bad-key.ll -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 2>&1 | FileCheck %s --check-prefix=BAD-KEY +; RUN: llc < %t/bad-other-key.ll -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 2>&1 | FileCheck %s --check-prefix=BAD-OTHER-KEY +; RUN: llc < %t/bad-l1-type.ll -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 2>&1 | FileCheck %s --check-prefix=BAD-L1-TYPE +; RUN: llc < %t/bad-l1-value.ll -mtriple=nvptx64 -mcpu=sm_60 -mattr=+ptx50 2>&1 | FileCheck %s --check-prefix=BAD-L1-VALUE +; RUN: llc < %t/bad-l1-value.ll -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 2>&1 | FileCheck %s --check-prefix=BAD-L1-VALUE +; RUN: llc < %t/bad-l2-type.ll -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 2>&1 | FileCheck %s --check-prefix=BAD-L2-TYPE +; RUN: llc < %t/bad-l2-value.ll -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 2>&1 | FileCheck %s --check-prefix=BAD-L2-VALUE +; RUN: llc < %t/bad-prefetch-type.ll -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 2>&1 | FileCheck %s --check-prefix=BAD-PREFETCH-TYPE +; RUN: llc < %t/bad-prefetch-value.ll -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 2>&1 | FileCheck %s --check-prefix=BAD-PREFETCH-VALUE +; RUN: llc < %t/bad-policy.ll -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 2>&1 | FileCheck %s --check-prefix=BAD-POLICY +; RUN: llc < %t/bad-policy.ll -mtriple=nvptx64 -mcpu=sm_60 -mattr=+ptx50 2>&1 | FileCheck %s --check-prefix=BAD-POLICY +; RUN: llc < %t/bad-policy-shared.ll -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 2>&1 | FileCheck %s --check-prefix=BAD-POLICY-SHARED + +;--- bad-empty.ll + +; Test with empty hint node - should produce an empty-node warning. +; BAD-EMPTY: warning: invalid NVPTX !mem.cache_hint metadata: empty hint node +define i32 @bad_empty_hint_node(ptr addrspace(1) %p) { + %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !0 + ret i32 %v +} + +!0 = !{i32 0, !1} +!1 = !{} + +;--- bad-key.ll + +; Test with misspelled NVPTX key - should produce an unknown-key warning. +; BAD-KEY: warning: invalid NVPTX !mem.cache_hint metadata: unknown key 'nvvm.l1_evict' +define i32 @bad_nvvm_key(ptr addrspace(1) %p) { + %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !0 + ret i32 %v +} + +!0 = !{i32 0, !1} +!1 = !{!"nvvm.l1_evict", !"first"} + +;--- bad-other-key.ll + +; Test with a non-NVPTX key - should produce an unknown-key warning. +; BAD-OTHER-KEY: warning: invalid NVPTX !mem.cache_hint metadata: unknown key 'some.target_hint' +define i32 @bad_other_key(ptr addrspace(1) %p) { + %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !0 + ret i32 %v +} + +!0 = !{i32 0, !1} +!1 = !{!"some.target_hint", !"value"} + +;--- bad-l1-type.ll + +; nvvm.l1_eviction expects a string value. +; BAD-L1-TYPE: warning: invalid NVPTX !mem.cache_hint metadata: 'nvvm.l1_eviction' expects a string value +define i32 @bad_l1_type(ptr addrspace(1) %p) { + %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !0 + ret i32 %v +} + +!0 = !{i32 0, !1} +!1 = !{!"nvvm.l1_eviction", i32 0} + +;--- bad-l1-value.ll + +; nvvm.l1_eviction accepts only known PTX eviction values. +; BAD-L1-VALUE: warning: invalid NVPTX !mem.cache_hint metadata: unknown value 'middle' for 'nvvm.l1_eviction' +define i32 @bad_l1_value(ptr addrspace(1) %p) { + %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !0 + ret i32 %v +} + +!0 = !{i32 0, !1} +!1 = !{!"nvvm.l1_eviction", !"middle"} + +;--- bad-l2-type.ll + +; nvvm.l2_eviction expects a string value. +; BAD-L2-TYPE: warning: invalid NVPTX !mem.cache_hint metadata: 'nvvm.l2_eviction' expects a string value +define i32 @bad_l2_type(ptr addrspace(1) %p) { + %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !0 + ret i32 %v +} + +!0 = !{i32 0, !1} +!1 = !{!"nvvm.l2_eviction", i32 0} + +;--- bad-l2-value.ll + +; nvvm.l2_eviction accepts only known PTX eviction values. +; BAD-L2-VALUE: warning: invalid NVPTX !mem.cache_hint metadata: unknown value 'middle' for 'nvvm.l2_eviction' +define i32 @bad_l2_value(ptr addrspace(1) %p) { + %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !0 + ret i32 %v +} + +!0 = !{i32 0, !1} +!1 = !{!"nvvm.l2_eviction", !"middle"} + +;--- bad-prefetch-type.ll + +; nvvm.l2_prefetch_size expects a string value. +; BAD-PREFETCH-TYPE: warning: invalid NVPTX !mem.cache_hint metadata: 'nvvm.l2_prefetch_size' expects a string value +define i32 @bad_prefetch_type(ptr addrspace(1) %p) { + %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !0 + ret i32 %v +} + +!0 = !{i32 0, !1} +!1 = !{!"nvvm.l2_prefetch_size", i32 64} + +;--- bad-prefetch-value.ll + +; nvvm.l2_prefetch_size accepts only supported PTX prefetch sizes. +; BAD-PREFETCH-VALUE: warning: invalid NVPTX !mem.cache_hint metadata: unknown value '32B' for 'nvvm.l2_prefetch_size' +define i32 @bad_prefetch_value(ptr addrspace(1) %p) { + %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !0 + ret i32 %v +} + +!0 = !{i32 0, !1} +!1 = !{!"nvvm.l2_prefetch_size", !"32B"} + +;--- bad-policy.ll + +; nvvm.l2_cache_hint expects an integer cache-policy value. +; BAD-POLICY: warning: invalid NVPTX !mem.cache_hint metadata: 'nvvm.l2_cache_hint' expects an integer value +define i32 @bad_cache_policy_value(ptr addrspace(1) %p) { + %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !0 + ret i32 %v +} + +!0 = !{i32 0, !1} +!1 = !{!"nvvm.l2_cache_hint", !"not_an_integer"} + +;--- bad-policy-shared.ll + +; nvvm.l2_cache_hint expects an integer cache-policy value even when the +; address space does not support the hint. +; BAD-POLICY-SHARED: warning: invalid NVPTX !mem.cache_hint metadata: 'nvvm.l2_cache_hint' expects an integer value +define i32 @bad_cache_policy_value(ptr addrspace(3) %p) { + %v = load i32, ptr addrspace(3) %p, !mem.cache_hint !0 + ret i32 %v +} + +!0 = !{i32 0, !1} +!1 = !{!"nvvm.l2_cache_hint", !"not_an_integer"} diff --git a/llvm/test/CodeGen/NVPTX/cache-hint-load-store.ll b/llvm/test/CodeGen/NVPTX/cache-hint-load-store.ll new file mode 100644 index 0000000000000..80601623b127c --- /dev/null +++ b/llvm/test/CodeGen/NVPTX/cache-hint-load-store.ll @@ -0,0 +1,408 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --filter "^\s*(?:mov\.b64|ld(?:\.[A-Za-z0-9_:]+)*\.global|st(?:\.[A-Za-z0-9_:]+)*\.global|atom(?:\.[A-Za-z0-9_:]+)*\.global)" --version 6 +; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_100 -mattr=+ptx88 | FileCheck %s +; RUN: %if ptxas %{ llc < %s -mtriple=nvptx64 -mcpu=sm_100 -mattr=+ptx88 | %ptxas-verify %} + +; Test !mem.cache_hint metadata lowering to PTX load/store cache qualifiers. + +;----------------------------------------------------------------------------- +; Basic L1 eviction policies for loads +;----------------------------------------------------------------------------- + +define i32 @test_load_l1_first(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_l1_first( +; CHECK: ld.global.L1::evict_first.b32 %r1, [%rd1]; + %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !0 + ret i32 %v +} + +define i32 @test_load_l1_last(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_l1_last( +; CHECK: ld.global.L1::evict_last.b32 %r1, [%rd1]; + %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !1 + ret i32 %v +} + +define i32 @test_load_l1_unchanged(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_l1_unchanged( +; CHECK: ld.global.L1::evict_unchanged.b32 %r1, [%rd1]; + %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !2 + ret i32 %v +} + +define i32 @test_load_l1_no_allocate(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_l1_no_allocate( +; CHECK: ld.global.L1::no_allocate.b32 %r1, [%rd1]; + %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !3 + ret i32 %v +} + +;----------------------------------------------------------------------------- +; L2 eviction policies for loads (<8 x i32> and <4 x i64> are PTX-legal 256-bit forms) +;----------------------------------------------------------------------------- + +define <8 x i32> @test_load_l2_first(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_l2_first( +; CHECK: ld.global.L2::evict_first.v4.b64 {%rd2, %rd3, %rd4, %rd5}, [%rd1]; + %v = load <8 x i32>, ptr addrspace(1) %p, align 32, !mem.cache_hint !4 + ret <8 x i32> %v +} + +define <4 x i64> @test_load_l2_last(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_l2_last( +; CHECK: ld.global.L2::evict_last.v4.b64 {%rd2, %rd3, %rd4, %rd5}, [%rd1]; + %v = load <4 x i64>, ptr addrspace(1) %p, align 32, !mem.cache_hint !5 + ret <4 x i64> %v +} + +;----------------------------------------------------------------------------- +; L2 prefetch sizes for loads +;----------------------------------------------------------------------------- + +define i32 @test_load_prefetch_64(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_prefetch_64( +; CHECK: ld.global.L2::64B.b32 %r1, [%rd1]; + %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !6 + ret i32 %v +} + +define i32 @test_load_prefetch_128(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_prefetch_128( +; CHECK: ld.global.L2::128B.b32 %r1, [%rd1]; + %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !7 + ret i32 %v +} + +define i32 @test_load_prefetch_256(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_prefetch_256( +; CHECK: ld.global.L2::256B.b32 %r1, [%rd1]; + %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !8 + ret i32 %v +} + +;----------------------------------------------------------------------------- +; L1 + L2 eviction combinations for loads +;----------------------------------------------------------------------------- + +define <8 x i32> @test_load_l1_first_l2_first(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_l1_first_l2_first( +; CHECK: ld.global.L1::evict_first.L2::evict_first.v4.b64 {%rd2, %rd3, %rd4, %rd5}, [%rd1]; + %v = load <8 x i32>, ptr addrspace(1) %p, align 32, !mem.cache_hint !9 + ret <8 x i32> %v +} + +define <4 x i64> @test_load_l1_first_l2_last(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_l1_first_l2_last( +; CHECK: ld.global.L1::evict_first.L2::evict_last.v4.b64 {%rd2, %rd3, %rd4, %rd5}, [%rd1]; + %v = load <4 x i64>, ptr addrspace(1) %p, align 32, !mem.cache_hint !10 + ret <4 x i64> %v +} + +define <8 x i32> @test_load_l1_last_l2_first(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_l1_last_l2_first( +; CHECK: ld.global.L1::evict_last.L2::evict_first.v4.b64 {%rd2, %rd3, %rd4, %rd5}, [%rd1]; + %v = load <8 x i32>, ptr addrspace(1) %p, align 32, !mem.cache_hint !11 + ret <8 x i32> %v +} + +define <4 x i64> @test_load_l1_last_l2_last(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_l1_last_l2_last( +; CHECK: ld.global.L1::evict_last.L2::evict_last.v4.b64 {%rd2, %rd3, %rd4, %rd5}, [%rd1]; + %v = load <4 x i64>, ptr addrspace(1) %p, align 32, !mem.cache_hint !12 + ret <4 x i64> %v +} + +;----------------------------------------------------------------------------- +; L1 + L2 + Prefetch combination for loads +;----------------------------------------------------------------------------- + +define <4 x i64> @test_load_l1_first_l2_last_prefetch_128(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_l1_first_l2_last_prefetch_128( +; CHECK: ld.global.L1::evict_first.L2::evict_last.L2::128B.v4.b64 {%rd2, %rd3, %rd4, %rd5}, [%rd1]; + %v = load <4 x i64>, ptr addrspace(1) %p, align 32, !mem.cache_hint !13 + ret <4 x i64> %v +} + +;----------------------------------------------------------------------------- +; Basic L1 eviction policies for stores +;----------------------------------------------------------------------------- + +define void @test_store_l1_first(ptr addrspace(1) %p, i32 %v) { +; CHECK-LABEL: test_store_l1_first( +; CHECK: st.global.L1::evict_first.b32 [%rd1], %r1; + store i32 %v, ptr addrspace(1) %p, !mem.cache_hint !14 + ret void +} + +define void @test_store_l1_last(ptr addrspace(1) %p, i32 %v) { +; CHECK-LABEL: test_store_l1_last( +; CHECK: st.global.L1::evict_last.b32 [%rd1], %r1; + store i32 %v, ptr addrspace(1) %p, !mem.cache_hint !15 + ret void +} + +define void @test_store_l1_unchanged(ptr addrspace(1) %p, i32 %v) { +; CHECK-LABEL: test_store_l1_unchanged( +; CHECK: st.global.L1::evict_unchanged.b32 [%rd1], %r1; + store i32 %v, ptr addrspace(1) %p, !mem.cache_hint !16 + ret void +} + +define void @test_store_l1_no_allocate(ptr addrspace(1) %p, i32 %v) { +; CHECK-LABEL: test_store_l1_no_allocate( +; CHECK: st.global.L1::no_allocate.b32 [%rd1], %r1; + store i32 %v, ptr addrspace(1) %p, !mem.cache_hint !17 + ret void +} + +;----------------------------------------------------------------------------- +; L2 eviction policies for stores +;----------------------------------------------------------------------------- + +define void @test_store_l2_first(ptr addrspace(1) %p, <8 x i32> %v) { +; CHECK-LABEL: test_store_l2_first( +; CHECK: st.global.L2::evict_first.v4.b64 [%rd1], {%rd4, %rd5, %rd2, %rd3}; + store <8 x i32> %v, ptr addrspace(1) %p, align 32, !mem.cache_hint !18 + ret void +} + +define void @test_store_l2_last(ptr addrspace(1) %p, <4 x i64> %v) { +; CHECK-LABEL: test_store_l2_last( +; CHECK: st.global.L2::evict_last.v4.b64 [%rd1], {%rd4, %rd5, %rd2, %rd3}; + store <4 x i64> %v, ptr addrspace(1) %p, align 32, !mem.cache_hint !19 + ret void +} + +;----------------------------------------------------------------------------- +; L1 + L2 eviction combinations for stores +;----------------------------------------------------------------------------- + +define void @test_store_l1_first_l2_first(ptr addrspace(1) %p, <8 x i32> %v) { +; CHECK-LABEL: test_store_l1_first_l2_first( +; CHECK: st.global.L1::evict_first.L2::evict_first.v4.b64 [%rd1], {%rd4, %rd5, %rd2, %rd3}; + store <8 x i32> %v, ptr addrspace(1) %p, align 32, !mem.cache_hint !20 + ret void +} + +define void @test_store_l1_first_l2_last(ptr addrspace(1) %p, <4 x i64> %v) { +; CHECK-LABEL: test_store_l1_first_l2_last( +; CHECK: st.global.L1::evict_first.L2::evict_last.v4.b64 [%rd1], {%rd4, %rd5, %rd2, %rd3}; + store <4 x i64> %v, ptr addrspace(1) %p, align 32, !mem.cache_hint !21 + ret void +} + +define void @test_store_l1_last_l2_first(ptr addrspace(1) %p, <8 x i32> %v) { +; CHECK-LABEL: test_store_l1_last_l2_first( +; CHECK: st.global.L1::evict_last.L2::evict_first.v4.b64 [%rd1], {%rd4, %rd5, %rd2, %rd3}; + store <8 x i32> %v, ptr addrspace(1) %p, align 32, !mem.cache_hint !22 + ret void +} + +define void @test_store_l1_last_l2_last(ptr addrspace(1) %p, <4 x i64> %v) { +; CHECK-LABEL: test_store_l1_last_l2_last( +; CHECK: st.global.L1::evict_last.L2::evict_last.v4.b64 [%rd1], {%rd4, %rd5, %rd2, %rd3}; + store <4 x i64> %v, ptr addrspace(1) %p, align 32, !mem.cache_hint !23 + ret void +} + +;----------------------------------------------------------------------------- +; Different data types - loads +;----------------------------------------------------------------------------- + +define i16 @test_load_i16_l1_first(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_i16_l1_first( +; CHECK: ld.global.L1::evict_first.b16 %r1, [%rd1]; + %v = load i16, ptr addrspace(1) %p, !mem.cache_hint !0 + ret i16 %v +} + +define i64 @test_load_i64_l1_last(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_i64_l1_last( +; CHECK: ld.global.L1::evict_last.b64 %rd2, [%rd1]; + %v = load i64, ptr addrspace(1) %p, !mem.cache_hint !1 + ret i64 %v +} + +define <8 x float> @test_load_v8f32_l2_first(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_v8f32_l2_first( +; CHECK: ld.global.L2::evict_first.v4.b64 {%rd2, %rd3, %rd4, %rd5}, [%rd1]; + %v = load <8 x float>, ptr addrspace(1) %p, align 32, !mem.cache_hint !4 + ret <8 x float> %v +} + +define <4 x double> @test_load_v4f64_l2_last(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_v4f64_l2_last( +; CHECK: ld.global.L2::evict_last.v4.b64 {%rd2, %rd3, %rd4, %rd5}, [%rd1]; + %v = load <4 x double>, ptr addrspace(1) %p, align 32, !mem.cache_hint !5 + ret <4 x double> %v +} + +;----------------------------------------------------------------------------- +; Different data types - stores +;----------------------------------------------------------------------------- + +define void @test_store_i16_l1_first(ptr addrspace(1) %p, i16 %v) { +; CHECK-LABEL: test_store_i16_l1_first( +; CHECK: st.global.L1::evict_first.b16 [%rd1], %rs1; + store i16 %v, ptr addrspace(1) %p, !mem.cache_hint !14 + ret void +} + +define void @test_store_v4i64_l2_last(ptr addrspace(1) %p, <4 x i64> %v) { +; CHECK-LABEL: test_store_v4i64_l2_last( +; CHECK: st.global.L2::evict_last.v4.b64 [%rd1], {%rd4, %rd5, %rd2, %rd3}; + store <4 x i64> %v, ptr addrspace(1) %p, align 32, !mem.cache_hint !19 + ret void +} + +define void @test_store_f32_l1_no_allocate(ptr addrspace(1) %p, float %v) { +; CHECK-LABEL: test_store_f32_l1_no_allocate( +; CHECK: st.global.L1::no_allocate.b32 [%rd1], %r1; + store float %v, ptr addrspace(1) %p, !mem.cache_hint !17 + ret void +} + +;----------------------------------------------------------------------------- +; Vector loads with cache hints +;----------------------------------------------------------------------------- + +define <2 x i32> @test_load_v2i32_l1_first(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_v2i32_l1_first( +; CHECK: ld.global.L1::evict_first.b64 %rd2, [%rd1]; + %v = load <2 x i32>, ptr addrspace(1) %p, !mem.cache_hint !0 + ret <2 x i32> %v +} + +define <4 x i64> @test_load_v4i64_l2_last(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_v4i64_l2_last( +; CHECK: ld.global.L2::evict_last.v4.b64 {%rd2, %rd3, %rd4, %rd5}, [%rd1]; + %v = load <4 x i64>, ptr addrspace(1) %p, align 32, !mem.cache_hint !5 + ret <4 x i64> %v +} + +define <2 x float> @test_load_v2f32_l1_unchanged(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_v2f32_l1_unchanged( +; CHECK: ld.global.L1::evict_unchanged.b64 %rd2, [%rd1]; + %v = load <2 x float>, ptr addrspace(1) %p, !mem.cache_hint !2 + ret <2 x float> %v +} + +define <2 x double> @test_load_v2f64_prefetch_128(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_v2f64_prefetch_128( +; CHECK: ld.global.L2::128B.v2.b64 {%rd2, %rd3}, [%rd1]; + %v = load <2 x double>, ptr addrspace(1) %p, !mem.cache_hint !7 + ret <2 x double> %v +} + +;----------------------------------------------------------------------------- +; Vector stores with cache hints +;----------------------------------------------------------------------------- + +define void @test_store_v2i32_l1_last(ptr addrspace(1) %p, <2 x i32> %v) { +; CHECK-LABEL: test_store_v2i32_l1_last( +; CHECK: st.global.L1::evict_last.b64 [%rd1], %rd2; + store <2 x i32> %v, ptr addrspace(1) %p, !mem.cache_hint !15 + ret void +} + +define void @test_store_v8i32_l2_first(ptr addrspace(1) %p, <8 x i32> %v) { +; CHECK-LABEL: test_store_v8i32_l2_first( +; CHECK: st.global.L2::evict_first.v4.b64 [%rd1], {%rd4, %rd5, %rd2, %rd3}; + store <8 x i32> %v, ptr addrspace(1) %p, align 32, !mem.cache_hint !18 + ret void +} + +define void @test_store_v2f64_l1_no_allocate(ptr addrspace(1) %p, <2 x double> %v) { +; CHECK-LABEL: test_store_v2f64_l1_no_allocate( +; CHECK: st.global.L1::no_allocate.v2.b64 [%rd1], {%rd2, %rd3}; + store <2 x double> %v, ptr addrspace(1) %p, !mem.cache_hint !17 + ret void +} + +;----------------------------------------------------------------------------- +; Invariant loads with cache hints may still use LDG (ld.global.nc) +;----------------------------------------------------------------------------- + +define i32 @test_invariant_load_with_hint(ptr addrspace(1) %p) { +; CHECK-LABEL: test_invariant_load_with_hint( +; CHECK: ld.global.nc.L1::evict_first.b32 %r1, [%rd1]; + %v = load i32, ptr addrspace(1) %p, !invariant.load !{}, !mem.cache_hint !0 + ret i32 %v +} + +define i32 @test_invariant_load_with_cache_policy(ptr addrspace(1) %p) { +; CHECK-LABEL: test_invariant_load_with_cache_policy( +; CHECK: mov.b64 %rd2, 12345; +; CHECK: ld.global.nc.L2::cache_hint.b32 %r1, [%rd1], %rd2; + %v = load i32, ptr addrspace(1) %p, !invariant.load !{}, !mem.cache_hint !24 + ret i32 %v +} + +define <8 x i32> @test_invariant_load_v8i32_with_hint(ptr addrspace(1) %p) { +; CHECK-LABEL: test_invariant_load_v8i32_with_hint( +; CHECK: ld.global.nc.L1::evict_last.L2::evict_first.v4.b64 {%rd2, %rd3, %rd4, %rd5}, [%rd1]; + %v = load <8 x i32>, ptr addrspace(1) %p, align 32, !invariant.load !{}, !mem.cache_hint !11 + ret <8 x i32> %v +} + +;----------------------------------------------------------------------------- +; No hint should produce plain load/store +;----------------------------------------------------------------------------- + +define i32 @test_load_no_hint(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_no_hint( +; CHECK: ld.global.b32 %r1, [%rd1]; + %v = load i32, ptr addrspace(1) %p + ret i32 %v +} + +define void @test_store_no_hint(ptr addrspace(1) %p, i32 %v) { +; CHECK-LABEL: test_store_no_hint( +; CHECK: st.global.b32 [%rd1], %r1; + store i32 %v, ptr addrspace(1) %p + ret void +} + +;----------------------------------------------------------------------------- +; Metadata definitions +;----------------------------------------------------------------------------- + +!0 = !{i32 0, !25} +!25 = !{!"nvvm.l1_eviction", !"first"} +!1 = !{i32 0, !26} +!26 = !{!"nvvm.l1_eviction", !"last"} +!2 = !{i32 0, !27} +!27 = !{!"nvvm.l1_eviction", !"unchanged"} +!3 = !{i32 0, !28} +!28 = !{!"nvvm.l1_eviction", !"no_allocate"} +!4 = !{i32 0, !29} +!29 = !{!"nvvm.l2_eviction", !"first"} +!5 = !{i32 0, !30} +!30 = !{!"nvvm.l2_eviction", !"last"} +!6 = !{i32 0, !31} +!31 = !{!"nvvm.l2_prefetch_size", !"64B"} +!7 = !{i32 0, !32} +!32 = !{!"nvvm.l2_prefetch_size", !"128B"} +!8 = !{i32 0, !33} +!33 = !{!"nvvm.l2_prefetch_size", !"256B"} +!9 = !{i32 0, !34} +!34 = !{!"nvvm.l1_eviction", !"first", !"nvvm.l2_eviction", !"first"} +!10 = !{i32 0, !35} +!35 = !{!"nvvm.l1_eviction", !"first", !"nvvm.l2_eviction", !"last"} +!11 = !{i32 0, !36} +!36 = !{!"nvvm.l1_eviction", !"last", !"nvvm.l2_eviction", !"first"} +!12 = !{i32 0, !37} +!37 = !{!"nvvm.l1_eviction", !"last", !"nvvm.l2_eviction", !"last"} +!13 = !{i32 0, !38} +!38 = !{!"nvvm.l1_eviction", !"first", !"nvvm.l2_eviction", !"last", !"nvvm.l2_prefetch_size", !"128B"} +!14 = !{i32 1, !25} +!15 = !{i32 1, !26} +!16 = !{i32 1, !27} +!17 = !{i32 1, !28} +!18 = !{i32 1, !29} +!19 = !{i32 1, !30} +!20 = !{i32 1, !34} +!21 = !{i32 1, !35} +!22 = !{i32 1, !36} +!23 = !{i32 1, !37} +!24 = !{i32 0, !39} +!39 = !{!"nvvm.l2_cache_hint", i64 12345} diff --git a/llvm/test/CodeGen/NVPTX/cache-hint-sm-version.ll b/llvm/test/CodeGen/NVPTX/cache-hint-sm-version.ll new file mode 100644 index 0000000000000..511a0fd4a41ca --- /dev/null +++ b/llvm/test/CodeGen/NVPTX/cache-hint-sm-version.ll @@ -0,0 +1,348 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --filter "^\s*(ld\.global|st\.global|mov\.b64)" --filter "^\s*(?:mov\.b64|ld(?:\.[A-Za-z0-9_:]+)*\.global|st(?:\.[A-Za-z0-9_:]+)*\.global|atom(?:\.[A-Za-z0-9_:]+)*\.global)" --version 6 +; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_60 -mattr=+ptx74 | FileCheck %s --check-prefixes=SM60 +; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_70 -mattr=+ptx73 | FileCheck %s --check-prefixes=SM70-PTX73 +; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_70 -mattr=+ptx74 | FileCheck %s --check-prefixes=SM70 +; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_75 -mattr=+ptx74 | FileCheck %s --check-prefixes=SM75 +; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 | FileCheck %s --check-prefixes=SM80PLUS +; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx70 | FileCheck %s --check-prefixes=SM80-PTX70 +; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_86 -mattr=+ptx74 | FileCheck %s --check-prefixes=SM80PLUS +; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_90 -mattr=+ptx78 | FileCheck %s --check-prefixes=SM80PLUS +; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_100 -mattr=+ptx86 | FileCheck %s --check-prefixes=SM100-PTX86 +; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_100 -mattr=+ptx88 | FileCheck %s --check-prefixes=SM100-PTX88 + +; Test SM version requirements for cache hints (from PTX ISA documentation): +; - L1::evict_* requires SM 70+ and PTX 7.4+ +; - L2::evict_* requires SM 100+, PTX 8.8+, and a .v8.b32 or .v4.b64 memory op +; - L2::64B and L2::128B require SM 75+ and PTX 7.4+ +; - L2::256B requires SM 80+ and PTX 7.4+ +; - L2::cache_hint requires SM 80+ and PTX 7.4+ + +;----------------------------------------------------------------------------- +; L1 eviction - requires SM 70+ and PTX 7.4+ +; SM60 and PTX 7.3 should NOT emit L1::evict_first +; SM70+ with PTX 7.4+ should emit L1::evict_first +;----------------------------------------------------------------------------- + +define i32 @test_load_l1_first(ptr addrspace(1) %p) { +; SM60-LABEL: test_load_l1_first( +; SM60: ld.global.b32 %r1, [%rd1]; +; +; SM70-PTX73-LABEL: test_load_l1_first( +; SM70-PTX73: ld.global.b32 %r1, [%rd1]; +; +; SM70-LABEL: test_load_l1_first( +; SM70: ld.global.L1::evict_first.b32 %r1, [%rd1]; +; +; SM75-LABEL: test_load_l1_first( +; SM75: ld.global.L1::evict_first.b32 %r1, [%rd1]; +; +; SM80PLUS-LABEL: test_load_l1_first( +; SM80PLUS: ld.global.L1::evict_first.b32 %r1, [%rd1]; +; +; SM80-PTX70-LABEL: test_load_l1_first( +; SM80-PTX70: ld.global.b32 %r1, [%rd1]; + %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !0 + ret i32 %v +} + +;----------------------------------------------------------------------------- +; L2 eviction - requires SM 100+, PTX 8.8+, and a 256-bit vector access. +;----------------------------------------------------------------------------- + +define <8 x i32> @test_load_l2_last(ptr addrspace(1) %p) { +; SM60-LABEL: test_load_l2_last( +; SM60: ld.global.v4.b32 {%r1, %r2, %r3, %r4}, [%rd1]; +; +; SM70-PTX73-LABEL: test_load_l2_last( +; SM70-PTX73: ld.global.v4.b32 {%r1, %r2, %r3, %r4}, [%rd1]; +; +; SM70-LABEL: test_load_l2_last( +; SM70: ld.global.v4.b32 {%r1, %r2, %r3, %r4}, [%rd1]; +; +; SM75-LABEL: test_load_l2_last( +; SM75: ld.global.v4.b32 {%r1, %r2, %r3, %r4}, [%rd1]; +; +; SM80PLUS-LABEL: test_load_l2_last( +; SM80PLUS: ld.global.v4.b32 {%r1, %r2, %r3, %r4}, [%rd1]; +; +; SM80-PTX70-LABEL: test_load_l2_last( +; SM80-PTX70: ld.global.v4.b32 {%r1, %r2, %r3, %r4}, [%rd1]; +; +; SM100-PTX86-LABEL: test_load_l2_last( +; SM100-PTX86: ld.global.v2.b64 {%rd2, %rd3}, [%rd1]; +; +; SM100-PTX88-LABEL: test_load_l2_last( +; SM100-PTX88: ld.global.L2::evict_last.v4.b64 {%rd2, %rd3, %rd4, %rd5}, [%rd1]; + %v = load <8 x i32>, ptr addrspace(1) %p, align 32, !mem.cache_hint !1 + ret <8 x i32> %v +} + +;----------------------------------------------------------------------------- +; L2::64B prefetch - requires SM 75+ and PTX 7.4+ +; SM60/SM70 and PTX 7.0 should NOT emit L2::64B +; SM75+ with PTX 7.4+ should emit L2::64B +;----------------------------------------------------------------------------- + +define i32 @test_load_prefetch_64(ptr addrspace(1) %p) { +; SM60-LABEL: test_load_prefetch_64( +; SM60: ld.global.b32 %r1, [%rd1]; +; +; SM70-PTX73-LABEL: test_load_prefetch_64( +; SM70-PTX73: ld.global.b32 %r1, [%rd1]; +; +; SM70-LABEL: test_load_prefetch_64( +; SM70: ld.global.b32 %r1, [%rd1]; +; +; SM75-LABEL: test_load_prefetch_64( +; SM75: ld.global.L2::64B.b32 %r1, [%rd1]; +; +; SM80PLUS-LABEL: test_load_prefetch_64( +; SM80PLUS: ld.global.L2::64B.b32 %r1, [%rd1]; +; +; SM80-PTX70-LABEL: test_load_prefetch_64( +; SM80-PTX70: ld.global.b32 %r1, [%rd1]; + %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !6 + ret i32 %v +} + +;----------------------------------------------------------------------------- +; L2::128B prefetch - requires SM 75+ and PTX 7.4+ +; SM60/SM70 and PTX 7.0 should NOT emit L2::128B +; SM75+ with PTX 7.4+ should emit L2::128B +;----------------------------------------------------------------------------- + +define i32 @test_load_prefetch_128(ptr addrspace(1) %p) { +; SM60-LABEL: test_load_prefetch_128( +; SM60: ld.global.b32 %r1, [%rd1]; +; +; SM70-PTX73-LABEL: test_load_prefetch_128( +; SM70-PTX73: ld.global.b32 %r1, [%rd1]; +; +; SM70-LABEL: test_load_prefetch_128( +; SM70: ld.global.b32 %r1, [%rd1]; +; +; SM75-LABEL: test_load_prefetch_128( +; SM75: ld.global.L2::128B.b32 %r1, [%rd1]; +; +; SM80PLUS-LABEL: test_load_prefetch_128( +; SM80PLUS: ld.global.L2::128B.b32 %r1, [%rd1]; +; +; SM80-PTX70-LABEL: test_load_prefetch_128( +; SM80-PTX70: ld.global.b32 %r1, [%rd1]; + %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !2 + ret i32 %v +} + +;----------------------------------------------------------------------------- +; L2::256B prefetch - requires SM 80+ and PTX 7.4+ +; SM60/SM70/SM75 and PTX 7.0 should NOT emit L2::256B +; SM80+ with PTX 7.4+ should emit L2::256B +;----------------------------------------------------------------------------- + +define i32 @test_load_prefetch_256(ptr addrspace(1) %p) { +; SM60-LABEL: test_load_prefetch_256( +; SM60: ld.global.b32 %r1, [%rd1]; +; +; SM70-PTX73-LABEL: test_load_prefetch_256( +; SM70-PTX73: ld.global.b32 %r1, [%rd1]; +; +; SM70-LABEL: test_load_prefetch_256( +; SM70: ld.global.b32 %r1, [%rd1]; +; +; SM75-LABEL: test_load_prefetch_256( +; SM75: ld.global.b32 %r1, [%rd1]; +; +; SM80PLUS-LABEL: test_load_prefetch_256( +; SM80PLUS: ld.global.L2::256B.b32 %r1, [%rd1]; +; +; SM80-PTX70-LABEL: test_load_prefetch_256( +; SM80-PTX70: ld.global.b32 %r1, [%rd1]; + %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !7 + ret i32 %v +} + +;----------------------------------------------------------------------------- +; L2::cache_hint - requires SM 80+ and PTX 7.4+ +; SM60/SM70/SM75 should NOT emit L2::cache_hint (fall back to plain load) +; SM80 with PTX < 7.4 should NOT emit L2::cache_hint +; SM80+ with PTX 7.4+ should emit L2::cache_hint +;----------------------------------------------------------------------------- + +define i32 @test_load_cache_hint(ptr addrspace(1) %p) { +; SM60-LABEL: test_load_cache_hint( +; SM60: ld.global.b32 %r1, [%rd1]; +; +; SM70-PTX73-LABEL: test_load_cache_hint( +; SM70-PTX73: ld.global.b32 %r1, [%rd1]; +; +; SM70-LABEL: test_load_cache_hint( +; SM70: ld.global.b32 %r1, [%rd1]; +; +; SM75-LABEL: test_load_cache_hint( +; SM75: ld.global.b32 %r1, [%rd1]; +; +; SM80PLUS-LABEL: test_load_cache_hint( +; SM80PLUS: mov.b64 %rd2, 12345; +; SM80PLUS: ld.global.L2::cache_hint.b32 %r1, [%rd1], %rd2; +; +; SM80-PTX70-LABEL: test_load_cache_hint( +; SM80-PTX70: ld.global.b32 %r1, [%rd1]; + %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !3 + ret i32 %v +} + +;----------------------------------------------------------------------------- +; L2::cache_hint combined with L1 eviction on older SM +; Both hints should be dropped on SM60 +; L1 hint emitted but L2::cache_hint dropped on SM70/SM75 +; Both emitted on SM80+ +;----------------------------------------------------------------------------- + +define i32 @test_load_cache_hint_with_l1(ptr addrspace(1) %p) { +; SM60-LABEL: test_load_cache_hint_with_l1( +; SM60: ld.global.b32 %r1, [%rd1]; +; +; SM70-PTX73-LABEL: test_load_cache_hint_with_l1( +; SM70-PTX73: ld.global.b32 %r1, [%rd1]; +; +; SM70-LABEL: test_load_cache_hint_with_l1( +; SM70: ld.global.L1::evict_first.b32 %r1, [%rd1]; +; +; SM75-LABEL: test_load_cache_hint_with_l1( +; SM75: ld.global.L1::evict_first.b32 %r1, [%rd1]; +; +; SM80PLUS-LABEL: test_load_cache_hint_with_l1( +; SM80PLUS: mov.b64 %rd2, 12345; +; SM80PLUS: ld.global.L1::evict_first.L2::cache_hint.b32 %r1, [%rd1], %rd2; +; +; SM80-PTX70-LABEL: test_load_cache_hint_with_l1( +; SM80-PTX70: ld.global.b32 %r1, [%rd1]; + %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !4 + ret i32 %v +} + +;----------------------------------------------------------------------------- +; L2::128B combined with L1 eviction on older SM +; Both hints dropped on SM60 +; L1 hint emitted but L2::128B dropped on SM70 +; Both emitted on SM75+ +;----------------------------------------------------------------------------- + +define i32 @test_load_prefetch_with_l1(ptr addrspace(1) %p) { +; SM60-LABEL: test_load_prefetch_with_l1( +; SM60: ld.global.b32 %r1, [%rd1]; +; +; SM70-PTX73-LABEL: test_load_prefetch_with_l1( +; SM70-PTX73: ld.global.b32 %r1, [%rd1]; +; +; SM70-LABEL: test_load_prefetch_with_l1( +; SM70: ld.global.L1::evict_first.b32 %r1, [%rd1]; +; +; SM75-LABEL: test_load_prefetch_with_l1( +; SM75: ld.global.L1::evict_first.L2::128B.b32 %r1, [%rd1]; +; +; SM80PLUS-LABEL: test_load_prefetch_with_l1( +; SM80PLUS: ld.global.L1::evict_first.L2::128B.b32 %r1, [%rd1]; +; +; SM80-PTX70-LABEL: test_load_prefetch_with_l1( +; SM80-PTX70: ld.global.b32 %r1, [%rd1]; + %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !8 + ret i32 %v +} + +;----------------------------------------------------------------------------- +; Store with L2::cache_hint +;----------------------------------------------------------------------------- + +define void @test_store_cache_hint(ptr addrspace(1) %p, i32 %v) { +; SM60-LABEL: test_store_cache_hint( +; SM60: st.global.b32 [%rd1], %r1; +; +; SM70-PTX73-LABEL: test_store_cache_hint( +; SM70-PTX73: st.global.b32 [%rd1], %r1; +; +; SM70-LABEL: test_store_cache_hint( +; SM70: st.global.b32 [%rd1], %r1; +; +; SM75-LABEL: test_store_cache_hint( +; SM75: st.global.b32 [%rd1], %r1; +; +; SM80PLUS-LABEL: test_store_cache_hint( +; SM80PLUS: mov.b64 %rd2, 12345; +; SM80PLUS: st.global.L2::cache_hint.b32 [%rd1], %r1, %rd2; +; +; SM80-PTX70-LABEL: test_store_cache_hint( +; SM80-PTX70: st.global.b32 [%rd1], %r1; + store i32 %v, ptr addrspace(1) %p, !mem.cache_hint !5 + ret void +} + +;----------------------------------------------------------------------------- +; Store with L1 eviction hint +;----------------------------------------------------------------------------- + +define void @test_store_l1_no_allocate(ptr addrspace(1) %p, i32 %v) { +; SM60-LABEL: test_store_l1_no_allocate( +; SM60: st.global.b32 [%rd1], %r1; +; +; SM70-PTX73-LABEL: test_store_l1_no_allocate( +; SM70-PTX73: st.global.b32 [%rd1], %r1; +; +; SM70-LABEL: test_store_l1_no_allocate( +; SM70: st.global.L1::no_allocate.b32 [%rd1], %r1; +; +; SM75-LABEL: test_store_l1_no_allocate( +; SM75: st.global.L1::no_allocate.b32 [%rd1], %r1; +; +; SM80PLUS-LABEL: test_store_l1_no_allocate( +; SM80PLUS: st.global.L1::no_allocate.b32 [%rd1], %r1; +; +; SM80-PTX70-LABEL: test_store_l1_no_allocate( +; SM80-PTX70: st.global.b32 [%rd1], %r1; + store i32 %v, ptr addrspace(1) %p, !mem.cache_hint !9 + ret void +} + +;----------------------------------------------------------------------------- +; Metadata definitions +;----------------------------------------------------------------------------- + +; L1 eviction: first +!0 = !{i32 0, !100} +!100 = !{!"nvvm.l1_eviction", !"first"} + +; L2 eviction: last +!1 = !{i32 0, !101} +!101 = !{!"nvvm.l2_eviction", !"last"} + +; L2 prefetch: 128B +!2 = !{i32 0, !102} +!102 = !{!"nvvm.l2_prefetch_size", !"128B"} + +; L2::cache_hint only +!3 = !{i32 0, !103} +!103 = !{!"nvvm.l2_cache_hint", i64 12345} + +; L2::cache_hint + L1 eviction +!4 = !{i32 0, !104} +!104 = !{!"nvvm.l2_cache_hint", i64 12345, !"nvvm.l1_eviction", !"first"} + +; L2::cache_hint for store +!5 = !{i32 1, !105} +!105 = !{!"nvvm.l2_cache_hint", i64 12345} + +; L2 prefetch: 64B +!6 = !{i32 0, !106} +!106 = !{!"nvvm.l2_prefetch_size", !"64B"} + +; L2 prefetch: 256B +!7 = !{i32 0, !107} +!107 = !{!"nvvm.l2_prefetch_size", !"256B"} + +; L2 prefetch: 128B + L1 eviction +!8 = !{i32 0, !108} +!108 = !{!"nvvm.l2_prefetch_size", !"128B", !"nvvm.l1_eviction", !"first"} + +; L1 eviction: no_allocate (for store) +!9 = !{i32 1, !109} +!109 = !{!"nvvm.l1_eviction", !"no_allocate"} diff --git a/llvm/test/CodeGen/NVPTX/cache-hint-transforms.ll b/llvm/test/CodeGen/NVPTX/cache-hint-transforms.ll new file mode 100644 index 0000000000000..39d8284616033 --- /dev/null +++ b/llvm/test/CodeGen/NVPTX/cache-hint-transforms.ll @@ -0,0 +1,213 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --filter "^\s*(?:mov\.b64|ld(?:\.[A-Za-z0-9_:]+)*\.global|st(?:\.[A-Za-z0-9_:]+)*\.global|atom(?:\.[A-Za-z0-9_:]+)*\.global|ld\.param\.b32)" --version 6 +; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 | FileCheck %s --check-prefixes=CHECK,O2 +; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 -O0 | FileCheck %s --check-prefixes=CHECK,O0 +; RUN: %if ptxas %{ llc < %s -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 | %ptxas-verify %} + +; Test cache hint handling across shared pointers, CSE, forwarding, and legalization. + +;----------------------------------------------------------------------------- +; Multiple loads sharing same pointer +;----------------------------------------------------------------------------- + +; Two volatile loads from the same pointer should each keep their own cache hint +; combination, even when they use the same cache-policy value. +define i32 @test_multiple_loads_same_ptr(ptr addrspace(1) %p) { +; CHECK-LABEL: test_multiple_loads_same_ptr( +; CHECK: mov.b64 %rd2, 12345; +; CHECK: ld.volatile.global.L1::evict_last.L2::cache_hint.b32 %r1, [%rd1], %rd2; +; CHECK: ld.volatile.global.L1::evict_first.L2::cache_hint.b32 %r2, [%rd1], %rd2; + %v1 = load volatile i32, ptr addrspace(1) %p, !mem.cache_hint !0 + %v2 = load volatile i32, ptr addrspace(1) %p, !mem.cache_hint !1 + %sum = add i32 %v1, %v2 + ret i32 %sum +} + +; Non-volatile loads can CSE. Matching cache hints are preserved on the merged +; DAG node, but conflicting hints are dropped. +define i32 @test_cse_loads_same_cache_hint(ptr addrspace(1) %p) { +; CHECK-LABEL: test_cse_loads_same_cache_hint( +; CHECK: ld.global.L1::evict_first.b32 %r1, [%rd1]; + %v1 = load i32, ptr addrspace(1) %p, !mem.cache_hint !2 + %v2 = load i32, ptr addrspace(1) %p, !mem.cache_hint !2 + %sum = add i32 %v1, %v2 + ret i32 %sum +} + +define i32 @test_cse_loads_conflicting_cache_hints(ptr addrspace(1) %p) { +; CHECK-LABEL: test_cse_loads_conflicting_cache_hints( +; CHECK: ld.global.b32 %r1, [%rd1]; + %v1 = load i32, ptr addrspace(1) %p, !mem.cache_hint !2 + %v2 = load i32, ptr addrspace(1) %p, !mem.cache_hint !3 + %sum = add i32 %v1, %v2 + ret i32 %sum +} + +; NVPTXForwardParams rewrites eligible byval loads to ld.param. Since cache +; hints are not allowed on ld.param, we must drop them. +define i32 @test_forward_param_drops_l1_hint(ptr byval(i32) %a) { +; CHECK-LABEL: test_forward_param_drops_l1_hint( +; CHECK: ld.param.b32 %r1, [test_forward_param_drops_l1_hint_param_0]; + %v = load i32, ptr %a, !mem.cache_hint !4 + ret i32 %v +} + +define i32 @test_forward_param_drops_l2_cache_hint(ptr byval(i32) %a) { +; CHECK-LABEL: test_forward_param_drops_l2_cache_hint( +; CHECK: ld.param.b32 %r1, [test_forward_param_drops_l2_cache_hint_param_0]; + %v = load i32, ptr %a, !mem.cache_hint !5 + ret i32 %v +} + +;----------------------------------------------------------------------------- +; Valid edge cases +;----------------------------------------------------------------------------- + +; Test with custom hint key order - should still work +define i32 @test_load_reordered_metadata(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_reordered_metadata( +; CHECK: ld.global.L1::evict_last.b32 %r1, [%rd1]; + %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !6 + ret i32 %v +} + +;----------------------------------------------------------------------------- +; nvvm.l2_cache_hint with alternate integer value width +;----------------------------------------------------------------------------- + +; nvvm.l2_cache_hint with i32 instead of i64 - should still work +; as mdconst::dyn_extract accepts any integer type +define i32 @test_load_cache_hint_i32_value(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_cache_hint_i32_value( +; CHECK: mov.b64 %rd2, 12345; +; CHECK: ld.global.L2::cache_hint.b32 %r1, [%rd1], %rd2; + %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !7 + ret i32 %v +} + +; Test "normal" eviction - should not emit any qualifier (default behavior) +define i32 @test_load_l1_normal(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_l1_normal( +; CHECK: ld.global.b32 %r1, [%rd1]; + %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !8 + ret i32 %v +} + +define i32 @test_load_l2_normal(ptr addrspace(1) %p) { +; CHECK-LABEL: test_load_l2_normal( +; CHECK: ld.global.b32 %r1, [%rd1]; + %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !9 + ret i32 %v +} + +;----------------------------------------------------------------------------- +; TODO: Preserve cache hints across DAGCombiner-created memory rewrites. +; This documents the current store-of-concat-trunc behavior: copied MMOs for +; the split stores do not retain !mem.cache_hint metadata yet. +;----------------------------------------------------------------------------- + +define void @test_dagcombine_store_concat_trunc_v8i32(ptr addrspace(1) %p, <4 x i64> %a, <4 x i64> %b) { +; CHECK-LABEL: test_dagcombine_store_concat_trunc_v8i32( +; CHECK: st.global.v4.b32 [%rd1+16], {%r8, %r7, %r6, %r5}; +; CHECK: st.global.v4.b32 [%rd1], {%r4, %r3, %r2, %r1}; + %ta = trunc <4 x i64> %a to <4 x i32> + %tb = trunc <4 x i64> %b to <4 x i32> + %c = shufflevector <4 x i32> %ta, <4 x i32> %tb, <8 x i32> + store <8 x i32> %c, ptr addrspace(1) %p, align 16, !mem.cache_hint !10 + ret void +} + +;----------------------------------------------------------------------------- +; TODO: Preserve cache hints across one-to-N DAG memory rewrites. +; These tests document the current split/scalarized behavior: newly-created +; memory ops do not retain !mem.cache_hint metadata yet. +;----------------------------------------------------------------------------- + +define <16 x i32> @test_legalize_split_load_v16i32(ptr addrspace(1) %p) { +; O2-LABEL: test_legalize_split_load_v16i32( +; O2: ld.global.v4.b32 {%r1, %r2, %r3, %r4}, [%rd1]; +; O2: ld.global.v4.b32 {%r5, %r6, %r7, %r8}, [%rd1+16]; +; O2: ld.global.v4.b32 {%r9, %r10, %r11, %r12}, [%rd1+32]; +; O2: ld.global.v4.b32 {%r13, %r14, %r15, %r16}, [%rd1+48]; +; +; O0-LABEL: test_legalize_split_load_v16i32( +; O0: ld.global.v4.b32 {%r1, %r2, %r3, %r4}, [%rd1+48]; +; O0: ld.global.v4.b32 {%r5, %r6, %r7, %r8}, [%rd1+32]; +; O0: ld.global.v4.b32 {%r9, %r10, %r11, %r12}, [%rd1+16]; +; O0: ld.global.v4.b32 {%r13, %r14, %r15, %r16}, [%rd1]; + %v = load <16 x i32>, ptr addrspace(1) %p, align 16, !mem.cache_hint !11 + ret <16 x i32> %v +} + +define void @test_legalize_split_store_v16i32(ptr addrspace(1) %p, <16 x i32> %v) { +; O2-LABEL: test_legalize_split_store_v16i32( +; O2: st.global.v4.b32 [%rd1+48], {%r1, %r2, %r3, %r4}; +; O2: st.global.v4.b32 [%rd1+32], {%r5, %r6, %r7, %r8}; +; O2: st.global.v4.b32 [%rd1+16], {%r9, %r10, %r11, %r12}; +; O2: st.global.v4.b32 [%rd1], {%r13, %r14, %r15, %r16}; +; +; O0-LABEL: test_legalize_split_store_v16i32( +; O0: st.global.v4.b32 [%rd1+48], {%r13, %r14, %r15, %r16}; +; O0: st.global.v4.b32 [%rd1+32], {%r9, %r10, %r11, %r12}; +; O0: st.global.v4.b32 [%rd1+16], {%r5, %r6, %r7, %r8}; +; O0: st.global.v4.b32 [%rd1], {%r1, %r2, %r3, %r4}; + store <16 x i32> %v, ptr addrspace(1) %p, align 16, !mem.cache_hint !12 + ret void +} + +define <3 x i64> @test_legalize_scalarize_load_v3i64(ptr addrspace(1) %p) { +; CHECK-LABEL: test_legalize_scalarize_load_v3i64( +; CHECK: ld.global.b64 %rd2, [%rd1+16]; +; CHECK: ld.global.b64 %rd3, [%rd1+8]; +; CHECK: ld.global.b64 %rd4, [%rd1]; + %v = load <3 x i64>, ptr addrspace(1) %p, align 8, !mem.cache_hint !13 + ret <3 x i64> %v +} + +define void @test_legalize_scalarize_store_v3i64(ptr addrspace(1) %p, <3 x i64> %v) { +; O2-LABEL: test_legalize_scalarize_store_v3i64( +; O2: st.global.b64 [%rd1+16], %rd2; +; O2: st.global.b64 [%rd1+8], %rd4; +; O2: st.global.b64 [%rd1], %rd3; +; +; O0-LABEL: test_legalize_scalarize_store_v3i64( +; O0: st.global.b64 [%rd1+16], %rd4; +; O0: st.global.b64 [%rd1+8], %rd3; +; O0: st.global.b64 [%rd1], %rd2; + store <3 x i64> %v, ptr addrspace(1) %p, align 8, !mem.cache_hint !14 + ret void +} + +;----------------------------------------------------------------------------- +; Metadata definitions +;----------------------------------------------------------------------------- + +!0 = !{i32 0, !15} +!15 = !{!"nvvm.l2_cache_hint", i64 12345, !"nvvm.l1_eviction", !"last"} +!1 = !{i32 0, !16} +!16 = !{!"nvvm.l2_cache_hint", i64 12345, !"nvvm.l1_eviction", !"first"} +!2 = !{i32 0, !17} +!17 = !{!"nvvm.l1_eviction", !"first"} +!3 = !{i32 0, !18} +!18 = !{!"nvvm.l1_eviction", !"last"} +!4 = !{i32 0, !19} +!19 = !{!"nvvm.l1_eviction", !"first"} +!5 = !{i32 0, !20} +!20 = !{!"nvvm.l2_cache_hint", i64 12345} +!6 = !{i32 0, !21} +!21 = !{!"nvvm.l1_eviction", !"last", !"nvvm.l2_eviction", !"first"} +!7 = !{i32 0, !22} +!22 = !{!"nvvm.l2_cache_hint", i32 12345} +!8 = !{i32 0, !23} +!23 = !{!"nvvm.l1_eviction", !"normal"} +!9 = !{i32 0, !24} +!24 = !{!"nvvm.l2_eviction", !"normal"} +!10 = !{i32 1, !25} +!25 = !{!"nvvm.l2_cache_hint", i64 12345} +!11 = !{i32 0, !26} +!26 = !{!"nvvm.l2_cache_hint", i64 12345} +!12 = !{i32 1, !27} +!27 = !{!"nvvm.l2_cache_hint", i64 12345} +!13 = !{i32 0, !28} +!28 = !{!"nvvm.l1_eviction", !"last"} +!14 = !{i32 1, !29} +!29 = !{!"nvvm.l2_eviction", !"first"} diff --git a/llvm/test/CodeGen/NVPTX/machinelicm-no-preheader.mir b/llvm/test/CodeGen/NVPTX/machinelicm-no-preheader.mir index 186e97088039f..f7ad6ed209f0c 100644 --- a/llvm/test/CodeGen/NVPTX/machinelicm-no-preheader.mir +++ b/llvm/test/CodeGen/NVPTX/machinelicm-no-preheader.mir @@ -26,10 +26,10 @@ body: | ; CHECK: bb.0.entry: ; CHECK-NEXT: successors: %bb.2(0x30000000), %bb.3(0x50000000) ; CHECK-NEXT: {{ $}} - ; CHECK-NEXT: [[LD_i32_:%[0-9]+]]:b32 = LD_i32 0, 0, 101, 3, 32, -1, &test_hoist_param_1, 0 :: (dereferenceable invariant load (s32), addrspace 101) - ; CHECK-NEXT: [[LD_i64_:%[0-9]+]]:b64 = LD_i64 0, 0, 101, 3, 64, -1, &test_hoist_param_0, 0 :: (dereferenceable invariant load (s64), addrspace 101) + ; CHECK-NEXT: [[LD_i32_:%[0-9]+]]:b32 = LD_i32 0, 0, 101, 3, 32, -1, 0, 0, &test_hoist_param_1, 0 :: (dereferenceable invariant load (s32), addrspace 101) + ; CHECK-NEXT: [[LD_i64_:%[0-9]+]]:b64 = LD_i64 0, 0, 101, 3, 64, -1, 0, 0, &test_hoist_param_0, 0 :: (dereferenceable invariant load (s64), addrspace 101) ; CHECK-NEXT: [[ADD64ri:%[0-9]+]]:b64 = nuw ADD64ri killed [[LD_i64_]], 2 - ; CHECK-NEXT: [[LD_i32_1:%[0-9]+]]:b32 = LD_i32 0, 0, 1, 3, 32, -1, [[ADD64ri]], 0 + ; CHECK-NEXT: [[LD_i32_1:%[0-9]+]]:b32 = LD_i32 0, 0, 1, 3, 32, -1, 0, 0, [[ADD64ri]], 0 ; CHECK-NEXT: [[SETP_i32ri:%[0-9]+]]:b1 = SETP_i32ri [[LD_i32_]], 0, 0 ; CHECK-NEXT: CBranch killed [[SETP_i32ri]], %bb.2, 0 ; CHECK-NEXT: {{ $}} @@ -49,15 +49,15 @@ body: | ; CHECK-NEXT: {{ $}} ; CHECK-NEXT: bb.2: ; CHECK-NEXT: [[PHI1:%[0-9]+]]:b32 = PHI [[LD_i32_1]], %bb.0, [[SREM32rr]], %bb.1 - ; CHECK-NEXT: ST_i32 [[PHI1]], 0, 0, 1, 32, [[ADD64ri]], 0 + ; CHECK-NEXT: ST_i32 [[PHI1]], 0, 0, 1, 32, 0, [[ADD64ri]], 0, 0 ; CHECK-NEXT: Return bb.0.entry: successors: %bb.2(0x30000000), %bb.1(0x50000000) - %5:b32 = LD_i32 0, 0, 101, 3, 32, -1, &test_hoist_param_1, 0 :: (dereferenceable invariant load (s32), addrspace 101) - %6:b64 = LD_i64 0, 0, 101, 3, 64, -1, &test_hoist_param_0, 0 :: (dereferenceable invariant load (s64), addrspace 101) + %5:b32 = LD_i32 0, 0, 101, 3, 32, -1, 0, 0, &test_hoist_param_1, 0 :: (dereferenceable invariant load (s32), addrspace 101) + %6:b64 = LD_i64 0, 0, 101, 3, 64, -1, 0, 0, &test_hoist_param_0, 0 :: (dereferenceable invariant load (s64), addrspace 101) %0:b64 = nuw ADD64ri killed %6, 2 - %1:b32 = LD_i32 0, 0, 1, 3, 32, -1, %0, 0 + %1:b32 = LD_i32 0, 0, 1, 3, 32, -1, 0, 0, %0, 0 %7:b1 = SETP_i32ri %5, 0, 0 CBranch killed %7, %bb.2, 0 GOTO %bb.1 @@ -75,6 +75,6 @@ body: | bb.2: %4:b32 = PHI %1, %bb.0, %3, %bb.1 - ST_i32 %4, 0, 0, 1, 32, %0, 0 + ST_i32 %4, 0, 0, 1, 32, 0, %0, 0, 0 Return ... diff --git a/llvm/test/CodeGen/NVPTX/proxy-reg-erasure.mir b/llvm/test/CodeGen/NVPTX/proxy-reg-erasure.mir index 59ca24acc504c..93f5517bf6894 100644 --- a/llvm/test/CodeGen/NVPTX/proxy-reg-erasure.mir +++ b/llvm/test/CodeGen/NVPTX/proxy-reg-erasure.mir @@ -77,22 +77,22 @@ constants: [] machineFunctionInfo: {} body: | bb.0: - %0:b32, %1:b32, %2:b32, %3:b32 = LDV_i32_v4 0, 0, 101, 3, 32, -1, &retval0, 0 :: (load (s128), addrspace 101) + %0:b32, %1:b32, %2:b32, %3:b32 = LDV_i32_v4 0, 0, 101, 3, 32, -1, 0, 0, &retval0, 0 :: (load (s128), addrspace 101) ; CHECK-NOT: ProxyReg %4:b32 = ProxyRegB32 killed %0 %5:b32 = ProxyRegB32 killed %1 %6:b32 = ProxyRegB32 killed %2 %7:b32 = ProxyRegB32 killed %3 ; CHECK: STV_i32_v4 %0, %1, %2, %3 - STV_i32_v4 killed %4, killed %5, killed %6, killed %7, 0, 0, 101, 32, &func_retval0, 0 :: (store (s128), addrspace 101) + STV_i32_v4 killed %4, killed %5, killed %6, killed %7, 0, 0, 101, 32, 0, &func_retval0, 0, 0 :: (store (s128), addrspace 101) - %8:b32 = LD_i32 0, 0, 101, 3, 32, -1, &retval0, 0 :: (load (s32), addrspace 101) + %8:b32 = LD_i32 0, 0, 101, 3, 32, -1, 0, 0, &retval0, 0 :: (load (s32), addrspace 101) ; CHECK-NOT: ProxyReg %9:b32 = ProxyRegB32 killed %8 %10:b32 = ProxyRegB32 killed %9 %11:b32 = ProxyRegB32 killed %10 ; CHECK: ST_i32 %8 - ST_i32 killed %11, 0, 0, 101, 32, &func_retval0, 0 :: (store (s32), addrspace 101) + ST_i32 killed %11, 0, 0, 101, 32, 0, &func_retval0, 0, 0 :: (store (s32), addrspace 101) Return ... diff --git a/llvm/test/DebugInfo/NVPTX/inlinedAt_2.mir b/llvm/test/DebugInfo/NVPTX/inlinedAt_2.mir index 98c8083322747..930dba5044bae 100644 --- a/llvm/test/DebugInfo/NVPTX/inlinedAt_2.mir +++ b/llvm/test/DebugInfo/NVPTX/inlinedAt_2.mir @@ -113,7 +113,7 @@ body: | bb.0.entry: successors: %bb.1(0x40000000), %bb.2(0x40000000) - %1:b32 = LD_i32 0, 0, 1, 3, 32, -1, @gg, 0, debug-location !6 :: (dereferenceable load (s32) from @gg, addrspace 1); t2.cu:9:3 @[ t2.cu:18:3 ] + %1:b32 = LD_i32 0, 0, 1, 3, 32, -1, 0, @gg, 0, 0, debug-location !6 :: (dereferenceable load (s32) from @gg, addrspace 1); t2.cu:9:3 @[ t2.cu:18:3 ] %2:b1 = SETP_i32ri %1, 8, 2, debug-location !6; t2.cu:9:3 @[ t2.cu:18:3 ] CBranch %2, %bb.2, 0, debug-location !6; t2.cu:9:3 @[ t2.cu:18:3 ] @@ -122,7 +122,7 @@ body: | successors: %bb.2(0x80000000) %0:b32 = nuw nsw ADD32ri %1, 1 - ST_i32 %0, 0, 0, 1, 32, @gg, 0, debug-location !11 :: (store (s32) into @gg, addrspace 1); t2.cu:14:3 @[ t2.cu:10:5 @[ t2.cu:18:3 ] ] + ST_i32 %0, 0, 0, 1, 32, 0, @gg, 0, 0, debug-location !11 :: (store (s32) into @gg, addrspace 1); t2.cu:14:3 @[ t2.cu:10:5 @[ t2.cu:18:3 ] ] bb.2._Z3foov.exit: diff --git a/llvm/tools/llvm-reduce/ReducerWorkItem.cpp b/llvm/tools/llvm-reduce/ReducerWorkItem.cpp index 08bb57adc07a1..fa4da7a073f1e 100644 --- a/llvm/tools/llvm-reduce/ReducerWorkItem.cpp +++ b/llvm/tools/llvm-reduce/ReducerWorkItem.cpp @@ -239,7 +239,9 @@ static void cloneMemOperands(MachineInstr &DstMI, MachineInstr &SrcMI, MachineMemOperand *NewMMO = DstMF.getMachineMemOperand( NewPtrInfo, OldMMO->getFlags(), OldMMO->getMemoryType(), - OldMMO->getBaseAlign(), OldMMO->getAAInfo(), OldMMO->getRanges(), + OldMMO->getBaseAlign(), + MMOMetadata(OldMMO->getAAInfo(), OldMMO->getRanges(), + /*MemCacheHint=*/nullptr), OldMMO->getSyncScopeID(), OldMMO->getSuccessOrdering(), OldMMO->getFailureOrdering()); NewMMOs.push_back(NewMMO); diff --git a/llvm/unittests/CodeGen/GlobalISel/GISelAliasTest.cpp b/llvm/unittests/CodeGen/GlobalISel/GISelAliasTest.cpp index 992866f48a9ae..0dcda954e6c5e 100644 --- a/llvm/unittests/CodeGen/GlobalISel/GISelAliasTest.cpp +++ b/llvm/unittests/CodeGen/GlobalISel/GISelAliasTest.cpp @@ -53,7 +53,7 @@ TEST_F(AArch64GISelMITest, SimpleAlias) { // Same for atomics. auto *LoadAtomicMMO = MF->getMachineMemOperand( PtrInfo, MachineMemOperand::Flags::MOLoad, S64, Align(8), AAMDNodes(), - nullptr, SyncScope::System, AtomicOrdering::Acquire); + SyncScope::System, AtomicOrdering::Acquire); auto AtomicLd1 = B.buildLoad(S64, Addr, *LoadAtomicMMO); auto AtomicLd2 = B.buildLoad(S64, Base2, *LoadAtomicMMO); EXPECT_TRUE( diff --git a/llvm/unittests/CodeGen/GlobalISel/KnownBitsTest.cpp b/llvm/unittests/CodeGen/GlobalISel/KnownBitsTest.cpp index 349db4dbabfb1..18aca17fe7e59 100644 --- a/llvm/unittests/CodeGen/GlobalISel/KnownBitsTest.cpp +++ b/llvm/unittests/CodeGen/GlobalISel/KnownBitsTest.cpp @@ -1180,7 +1180,9 @@ static void AddRangeMetadata(LLVMContext &Context, MachineInstr *Load) { MachineMemOperand *NewMMO = Load->getParent()->getParent()->getMachineMemOperand( OldMMO->getPointerInfo(), OldMMO->getFlags(), OldMMO->getMemoryType(), - OldMMO->getAlign(), OldMMO->getAAInfo(), NewMDNode); + OldMMO->getAlign(), + MMOMetadata(/*AAInfo=*/OldMMO->getAAInfo(), + /*Ranges=*/NewMDNode)); MachineIRBuilder MIB(*Load); MIB.buildLoadInstr(Load->getOpcode(), Load->getOperand(0), Load->getOperand(1), *NewMMO); diff --git a/llvm/unittests/CodeGen/GlobalISel/KnownBitsVectorTest.cpp b/llvm/unittests/CodeGen/GlobalISel/KnownBitsVectorTest.cpp index 96c5b39384a8a..44c0406426587 100644 --- a/llvm/unittests/CodeGen/GlobalISel/KnownBitsVectorTest.cpp +++ b/llvm/unittests/CodeGen/GlobalISel/KnownBitsVectorTest.cpp @@ -164,7 +164,9 @@ TEST_F(AArch64GISelMITest, TestVectorMetadata) { const MachineMemOperand *OldMMO = *Load->memoperands_begin(); MachineMemOperand NewMMO(OldMMO->getPointerInfo(), OldMMO->getFlags(), OldMMO->getMemoryType(), OldMMO->getAlign(), - OldMMO->getAAInfo(), NewMDNode); + MMOMetadata( + /*AAInfo=*/OldMMO->getAAInfo(), + /*Ranges=*/NewMDNode)); MachineIRBuilder MIB(*Load); MIB.buildLoad(Load->getOperand(0), Load->getOperand(1), NewMMO); Load->eraseFromParent(); diff --git a/llvm/unittests/CodeGen/GlobalISel/MachineIRBuilderTest.cpp b/llvm/unittests/CodeGen/GlobalISel/MachineIRBuilderTest.cpp index 83fe8c7cb0f63..6100f1ccf7241 100644 --- a/llvm/unittests/CodeGen/GlobalISel/MachineIRBuilderTest.cpp +++ b/llvm/unittests/CodeGen/GlobalISel/MachineIRBuilderTest.cpp @@ -323,7 +323,7 @@ TEST_F(AArch64GISelMITest, BuildAtomicRMW) { MachineMemOperand *MMO = MF->getMachineMemOperand( MachinePointerInfo(), MachineMemOperand::MOLoad | MachineMemOperand::MOStore, 8, Align(8), - AAMDNodes(), nullptr, SyncScope::System, AtomicOrdering::Unordered); + AAMDNodes(), SyncScope::System, AtomicOrdering::Unordered); auto Ptr = B.buildUndef(P0); B.buildAtomicRMWFAdd(S64, Ptr, Copies[0], *MMO); diff --git a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp index c3a2ee212a023..2ef5d01ae87b9 100644 --- a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp +++ b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp @@ -1419,7 +1419,8 @@ TEST_F(AArch64SelectionDAGTest, computeKnownBits_extload_known01) { MDBuilder MDHelper(*DAG->getContext()); MDNode *Range = MDHelper.createRange(APInt(8, 0), APInt(8, 2)); MachineMemOperand *MMO = DAG->getMachineFunction().getMachineMemOperand( - PtrInfo, MachineMemOperand::MOLoad, 8, Align(8), AA, Range); + PtrInfo, MachineMemOperand::MOLoad, 8, Align(8), + MMOMetadata(/*AAInfo=*/AA, /*Ranges=*/Range)); auto ALoad = DAG->getExtLoad(ISD::EXTLOAD, Loc, Int32VT, DAG->getEntryNode(), Ptr, Int8VT, MMO); @@ -1452,7 +1453,8 @@ TEST_F(AArch64SelectionDAGTest, computeKnownBits_extload_knownnegative) { MDBuilder MDHelper(*DAG->getContext()); MDNode *Range = MDHelper.createRange(APInt(8, 0xf0), APInt(8, 0xff)); MachineMemOperand *MMO = DAG->getMachineFunction().getMachineMemOperand( - PtrInfo, MachineMemOperand::MOLoad, 8, Align(8), AA, Range); + PtrInfo, MachineMemOperand::MOLoad, 8, Align(8), + MMOMetadata(/*AAInfo=*/AA, /*Ranges=*/Range)); auto ALoad = DAG->getExtLoad(ISD::EXTLOAD, Loc, Int32VT, DAG->getEntryNode(), Ptr, Int8VT, MMO); From 8972983ea1ce1496f50b8985be4c817ad40c8ed2 Mon Sep 17 00:00:00 2001 From: Elvina Yakubova Date: Fri, 7 Aug 2026 00:20:02 +0100 Subject: [PATCH 019/789] [BOLT][AArch64] Add TLSGD relocations support (#213700) --- bolt/lib/Core/Relocation.cpp | 12 ++++++++++++ bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp | 4 ++++ bolt/lib/Target/AArch64/AArch64MCSymbolizer.cpp | 2 ++ bolt/test/AArch64/runtime-relocs.test | 12 +++++++++++- 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/bolt/lib/Core/Relocation.cpp b/bolt/lib/Core/Relocation.cpp index 6663abcffc7e8..b0f6b6ce0eddc 100644 --- a/bolt/lib/Core/Relocation.cpp +++ b/bolt/lib/Core/Relocation.cpp @@ -71,6 +71,8 @@ static bool isSupportedAArch64(uint32_t Type) { case ELF::R_AARCH64_LDST16_ABS_LO12_NC: case ELF::R_AARCH64_LDST8_ABS_LO12_NC: case ELF::R_AARCH64_ADR_GOT_PAGE: + case ELF::R_AARCH64_TLSGD_ADR_PAGE21: + case ELF::R_AARCH64_TLSGD_ADD_LO12_NC: case ELF::R_AARCH64_TLSDESC_ADR_PREL21: case ELF::R_AARCH64_TLSDESC_ADR_PAGE21: case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: @@ -183,6 +185,8 @@ static size_t getSizeForTypeAArch64(uint32_t Type) { case ELF::R_AARCH64_LDST16_ABS_LO12_NC: case ELF::R_AARCH64_LDST8_ABS_LO12_NC: case ELF::R_AARCH64_ADR_GOT_PAGE: + case ELF::R_AARCH64_TLSGD_ADR_PAGE21: + case ELF::R_AARCH64_TLSGD_ADD_LO12_NC: case ELF::R_AARCH64_TLSDESC_ADR_PREL21: case ELF::R_AARCH64_TLSDESC_ADR_PAGE21: case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: @@ -385,6 +389,7 @@ static uint64_t extractValueAArch64(uint32_t Type, uint64_t Contents, Contents &= ~0xffffffffff00001fULL; return static_cast(PC) + SignExtend64<21>(Contents >> 3); case ELF::R_AARCH64_ADR_GOT_PAGE: + case ELF::R_AARCH64_TLSGD_ADR_PAGE21: case ELF::R_AARCH64_TLSDESC_ADR_PREL21: case ELF::R_AARCH64_TLSDESC_ADR_PAGE21: case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: @@ -417,6 +422,7 @@ static uint64_t extractValueAArch64(uint32_t Type, uint64_t Contents, } case ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12: case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: + case ELF::R_AARCH64_TLSGD_ADD_LO12_NC: case ELF::R_AARCH64_TLSDESC_ADD_LO12: case ELF::R_AARCH64_ADD_ABS_LO12_NC: { // Immediate goes in bits 21:10 of ADD instruction @@ -557,6 +563,8 @@ static bool isGOTAArch64(uint32_t Type) { case ELF::R_AARCH64_LD64_GOT_LO12_NC: case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: + case ELF::R_AARCH64_TLSGD_ADR_PAGE21: + case ELF::R_AARCH64_TLSGD_ADD_LO12_NC: case ELF::R_AARCH64_TLSDESC_ADR_PREL21: case ELF::R_AARCH64_TLSDESC_ADR_PAGE21: case ELF::R_AARCH64_TLSDESC_LD64_LO12: @@ -591,6 +599,8 @@ static bool isTLSAArch64(uint32_t Type) { switch (Type) { default: return false; + case ELF::R_AARCH64_TLSGD_ADR_PAGE21: + case ELF::R_AARCH64_TLSGD_ADD_LO12_NC: case ELF::R_AARCH64_TLSDESC_ADR_PREL21: case ELF::R_AARCH64_TLSDESC_ADR_PAGE21: case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: @@ -661,6 +671,7 @@ static bool isPCRelativeAArch64(uint32_t Type) { case ELF::R_AARCH64_LDST16_ABS_LO12_NC: case ELF::R_AARCH64_LDST8_ABS_LO12_NC: case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: + case ELF::R_AARCH64_TLSGD_ADD_LO12_NC: case ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12: case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0: @@ -685,6 +696,7 @@ static bool isPCRelativeAArch64(uint32_t Type) { case ELF::R_AARCH64_ADR_PREL_PG_HI21_NC: case ELF::R_AARCH64_ADR_GOT_PAGE: case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: + case ELF::R_AARCH64_TLSGD_ADR_PAGE21: case ELF::R_AARCH64_TLSDESC_ADR_PREL21: case ELF::R_AARCH64_TLSDESC_ADR_PAGE21: case ELF::R_AARCH64_PREL16: diff --git a/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp index 26004c94acdd0..9ea5845000690 100644 --- a/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp +++ b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp @@ -1433,6 +1433,7 @@ class AArch64MCPlusBuilder : public MCPlusBuilder { return MCSpecifierExpr::create(Expr, AArch64::S_ABS, Ctx); } else if (isADRP(Inst) || RelType == ELF::R_AARCH64_ADR_PREL_PG_HI21 || RelType == ELF::R_AARCH64_ADR_PREL_PG_HI21_NC || + RelType == ELF::R_AARCH64_TLSGD_ADR_PAGE21 || RelType == ELF::R_AARCH64_TLSDESC_ADR_PAGE21 || RelType == ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 || RelType == ELF::R_AARCH64_ADR_GOT_PAGE) { @@ -1448,6 +1449,7 @@ class AArch64MCPlusBuilder : public MCPlusBuilder { case ELF::R_AARCH64_LDST32_ABS_LO12_NC: case ELF::R_AARCH64_LDST64_ABS_LO12_NC: case ELF::R_AARCH64_LDST128_ABS_LO12_NC: + case ELF::R_AARCH64_TLSGD_ADD_LO12_NC: case ELF::R_AARCH64_TLSDESC_ADD_LO12: case ELF::R_AARCH64_TLSDESC_LD64_LO12: case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: @@ -2965,6 +2967,8 @@ class AArch64MCPlusBuilder : public MCPlusBuilder { case ELF::R_AARCH64_LDST32_ABS_LO12_NC: case ELF::R_AARCH64_LDST64_ABS_LO12_NC: case ELF::R_AARCH64_LDST128_ABS_LO12_NC: + case ELF::R_AARCH64_TLSGD_ADD_LO12_NC: + case ELF::R_AARCH64_TLSGD_ADR_PAGE21: case ELF::R_AARCH64_TLSDESC_ADD_LO12: case ELF::R_AARCH64_TLSDESC_ADR_PAGE21: case ELF::R_AARCH64_TLSDESC_ADR_PREL21: diff --git a/bolt/lib/Target/AArch64/AArch64MCSymbolizer.cpp b/bolt/lib/Target/AArch64/AArch64MCSymbolizer.cpp index 7bbfb1429e37b..da469a9a5ab95 100644 --- a/bolt/lib/Target/AArch64/AArch64MCSymbolizer.cpp +++ b/bolt/lib/Target/AArch64/AArch64MCSymbolizer.cpp @@ -103,6 +103,8 @@ AArch64MCSymbolizer::adjustRelocation(const Relocation &Rel, switch (Rel.Type) { default: break; + case ELF::R_AARCH64_TLSGD_ADD_LO12_NC: + case ELF::R_AARCH64_TLSGD_ADR_PAGE21: case ELF::R_AARCH64_TLSDESC_LD64_LO12: case ELF::R_AARCH64_TLSDESC_ADD_LO12: case ELF::R_AARCH64_TLSDESC_ADR_PAGE21: diff --git a/bolt/test/AArch64/runtime-relocs.test b/bolt/test/AArch64/runtime-relocs.test index a8347b531c144..660959721305c 100644 --- a/bolt/test/AArch64/runtime-relocs.test +++ b/bolt/test/AArch64/runtime-relocs.test @@ -27,11 +27,21 @@ CHECKEXE: {{.*}} R_AARCH64_JUMP_SLOT {{.*}} inc + 0 // the initial binary was built with gcc and ld with -mtls-dialect=trad flag. RUN: yaml2obj %p/Inputs/tls-trad.yaml &> %t.trad.so -RUN: llvm-bolt %t.trad.so -o %t.trad.bolt.so --use-old-text=0 --lite=0 +RUN: llvm-bolt %t.trad.so -o %t.trad.bolt.so --use-old-text=0 --lite=0 2>&1 | \ +RUN: FileCheck %s --check-prefix=CHECKTRAD-BOLT RUN: llvm-readelf -rW %t.trad.so | FileCheck %s -check-prefix=CHECKTRAD +RUN: llvm-objdump -d --no-show-raw-insn --start-address=0x4000e0 \ +RUN: --stop-address=0x4000e8 %t.trad.bolt.so | \ +RUN: FileCheck %s --check-prefix=CHECKTRAD-TEXT +CHECKTRAD-BOLT: BOLT-INFO: enabling relocation mode +CHECKTRAD-BOLT-NOT: Failed to analyze CHECKTRAD: {{.*}} R_AARCH64_TLS_DTPMOD64 {{.*}} t1 + 0 CHECKTRAD: {{.*}} R_AARCH64_TLS_DTPREL64 {{.*}} t1 + 0 +CHECKTRAD: {{.*}} R_AARCH64_TLSGD_ADR_PAGE21 {{.*}} t1 + 0 +CHECKTRAD: {{.*}} R_AARCH64_TLSGD_ADD_LO12_NC {{.*}} t1 + 0 +CHECKTRAD-TEXT: adrp x0, 0x10000 +CHECKTRAD-TEXT-NEXT: add x0, x0, #0xfd0 // The ld linker emits R_AARCH64_TLSDESC to .rela.plt section, check that // it is emitted correctly. From d50b9947b27ff3c907a16b96cee50e8782236feb Mon Sep 17 00:00:00 2001 From: Meredith Julian <35236176+mjulian31@users.noreply.github.com> Date: Thu, 6 Aug 2026 16:25:43 -0700 Subject: [PATCH 020/789] [NVPTX][AsmPrinter] Allow fp128 aggregate types in NVPTX backend (#214546) Fixes an issue where aggregate types containing fp128 non-zero elements would cause "unsupported type" due to missing case in bufferLEByte. Adds fp128-global.ll test. --- llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp | 1 + llvm/test/CodeGen/NVPTX/fp128-global.ll | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 llvm/test/CodeGen/NVPTX/fp128-global.ll diff --git a/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp b/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp index 2b676bc239d86..5baf092ffad24 100644 --- a/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp +++ b/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp @@ -2229,6 +2229,7 @@ void NVPTXAsmPrinter::bufferLEByte(const Constant *CPV, int Bytes, case Type::BFloatTyID: case Type::FloatTyID: case Type::DoubleTyID: + case Type::FP128TyID: AddIntToBuffer(cast(CPV)->getValueAPF().bitcastToAPInt()); break; diff --git a/llvm/test/CodeGen/NVPTX/fp128-global.ll b/llvm/test/CodeGen/NVPTX/fp128-global.ll new file mode 100644 index 0000000000000..ac181693bcac7 --- /dev/null +++ b/llvm/test/CodeGen/NVPTX/fp128-global.ll @@ -0,0 +1,23 @@ +; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_20 | FileCheck %s +; RUN: %if ptxas %{ llc < %s -mtriple=nvptx64 -mcpu=sm_20 | %ptxas-verify %} + +; fp128 globals are lowered to byte arrays. An fp128 nested in an aggregate is +; buffered one element at a time, and that per-element path must emit the same +; 16 little-endian bytes as a scalar fp128. + +; CHECK-DAG: .visible .global .align 16 .b8 array_nonzero[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 63}; +@array_nonzero = global [1 x fp128] [fp128 0xL00000000000000003FFF000000000000] + +; CHECK-DAG: .visible .global .align 16 .b8 array_multi[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64}; +@array_multi = global [2 x fp128] [fp128 0xL00000000000000003FFF000000000000, fp128 0xL00000000000000004000000000000000] + +; Trailing zeros of the struct's tail padding are trimmed by the printer. +; CHECK-DAG: .visible .global .align 16 .b8 struct_nonzero[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 64, 7}; +%struct.WithFloat128 = type { fp128, i32 } +@struct_nonzero = global %struct.WithFloat128 { fp128 0xL00000000000000004000800000000000, i32 7 } + +; CHECK-DAG: .visible .global .align 16 .b8 scalar_nonzero[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 63}; +@scalar_nonzero = global fp128 0xL00000000000000003FFF000000000000 + +; CHECK-DAG: .visible .global .align 16 .b8 array_zero[16]; +@array_zero = global [1 x fp128] zeroinitializer From 5194e33faad9d84fd8d21c0305621a17e0d8a49f Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Fri, 7 Aug 2026 09:26:08 +1000 Subject: [PATCH 021/789] [ORC] Hoist Caller state into the base; add operator bool (#214483) Move the ExecutionSession reference and callee address up from the SPS implementation into the rt::Caller base, together with their constructor and new executionSession() / calleeAddr() accessors. The named callers (MainCaller, VoidVoidCaller, ...) become plain aliases of Caller rather than subclasses, and rt::sps::Caller inherits the base constructor. Add an explicit operator bool() reporting whether the caller has a non-null callee address. Give rt::sps::Caller::Create a SymbolLookupFlags parameter. Looking the callee up as a weakly-referenced symbol now yields a caller with a null callee (operator bool == false) when the symbol is absent, rather than an error -- so callers for optional runtime functions can be constructed and then tested for availability. Adds SPSCallersTest coverage for operator bool and the accessors, and for the required/weak x present/absent Create paths. --- .../llvm/ExecutionEngine/Orc/RTBridge/Calls.h | 34 +++++++-- .../ExecutionEngine/Orc/RTBridge/SPS/Calls.h | 40 ++++++----- .../ExecutionEngine/Orc/SPSCallersTest.cpp | 72 +++++++++++++++++++ 3 files changed, 120 insertions(+), 26 deletions(-) diff --git a/llvm/include/llvm/ExecutionEngine/Orc/RTBridge/Calls.h b/llvm/include/llvm/ExecutionEngine/Orc/RTBridge/Calls.h index b49e6457754bf..1a273b0f3c0fb 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/RTBridge/Calls.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/RTBridge/Calls.h @@ -28,7 +28,11 @@ #include #include -namespace llvm::orc::rt { +namespace llvm::orc { + +class ExecutionSession; + +namespace rt { template class Caller; @@ -54,8 +58,20 @@ template class Caller { using ErrorRetT = std::conditional_t, Error, Expected>; + Caller(ExecutionSession &ES, ExecutorAddr CalleeAddr) + : ES(ES), CalleeAddr(CalleeAddr) {} + virtual ~Caller() = default; + /// Returns the ExecutionSession on which this call will be made. + ExecutionSession &executionSession() const { return ES; } + + /// Returns the address of the callee in the executor. + const ExecutorAddr &calleeAddr() const { return CalleeAddr; } + + /// Evaluates to true if the callee is non-null. + explicit operator bool() const { return !!CalleeAddr; } + /// Asynchronously invoke the operation with the given Args, delivering its /// result (or an error) to OnComplete. virtual void operator()(unique_function OnComplete, @@ -73,6 +89,10 @@ template class Caller { std::move(Args)...); return F.get(); } + +private: + ExecutionSession &ES; + ExecutorAddr CalleeAddr; }; /// Runtime-agnostic interface for running a main-like function @@ -80,15 +100,14 @@ template class Caller { /// /// The function to run is given by its ExecutorAddr, its arguments as an /// argument vector, and its int64_t result is returned. -class MainCaller : public Caller)> { -}; +using MainCaller = Caller)>; /// Runtime-agnostic interface for running a void() function in the executor. /// /// The function to run is given by its ExecutorAddr. /// /// WARNING: This Caller is experimental and may be removed. -class VoidVoidCaller : public Caller {}; +using VoidVoidCaller = Caller; /// Runtime-agnostic interface for running an int32_t() function in the /// executor. @@ -96,7 +115,7 @@ class VoidVoidCaller : public Caller {}; /// The function to run is given by its ExecutorAddr. /// /// WARNING: This Caller is experimental and may be removed. -class Int32VoidCaller : public Caller {}; +using Int32VoidCaller = Caller; /// Runtime-agnostic interface for running an int32_t(int32_t) function in the /// executor. @@ -104,8 +123,9 @@ class Int32VoidCaller : public Caller {}; /// The function to run is given by its ExecutorAddr. /// /// WARNING: This Caller is experimental and may be removed. -class Int32Int32Caller : public Caller {}; +using Int32Int32Caller = Caller; -} // namespace llvm::orc::rt +} // namespace rt +} // namespace llvm::orc #endif // LLVM_EXECUTIONENGINE_ORC_RTBRIDGE_CALLS_H diff --git a/llvm/include/llvm/ExecutionEngine/Orc/RTBridge/SPS/Calls.h b/llvm/include/llvm/ExecutionEngine/Orc/RTBridge/SPS/Calls.h index 4102327f5d394..8269cc34a37e2 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/RTBridge/SPS/Calls.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/RTBridge/SPS/Calls.h @@ -51,38 +51,45 @@ class Caller : public BaseT { /// Name of the controller-interface wrapper this caller targets. static constexpr const char *CIName = CINameV; - Caller(ExecutionSession &ES, ExecutorAddr CallerFnAddr) - : ES(ES), CallerFnAddr(CallerFnAddr) {} + using BaseT::BaseT; + using BaseT::operator(); /// Look the wrapper up in the executor's bootstrap JITDylib and build a /// caller for it. - static Expected Create(ExecutionSession &ES, - const char *Name = CIName) { - if (auto CallerSym = ES.lookup({&ES.getBootstrapJITDylib()}, Name)) - return Caller(ES, CallerSym->getAddress()); - else - return CallerSym.takeError(); + static Expected + Create(ExecutionSession &ES, + SymbolLookupFlags SLF = SymbolLookupFlags::RequiredSymbol, + const char *Name = CIName) { + if (auto CalleeSyms = + ES.lookup(makeJITDylibSearchOrder(&ES.getBootstrapJITDylib()), + SymbolLookupSet{ES.intern(Name), SLF})) { + if (!CalleeSyms->empty()) + return Caller(ES, CalleeSyms->begin()->second.getAddress()); + assert(SLF == SymbolLookupFlags::WeaklyReferencedSymbol); + return Caller(ES, ExecutorAddr()); + } else + return CalleeSyms.takeError(); } - /// Asynchronously call the SPS wrapper at CallerFnAddr with the given Args, + /// Asynchronously call the SPS wrapper at CalleeAddr with the given Args, /// delivering the result (or an error) to OnComplete. Serialization failures /// are reported through OnComplete's error channel. static void callAsync(unique_function OnComplete, - ExecutionSession &ES, ExecutorAddr CallerFnAddr, + ExecutionSession &ES, ExecutorAddr CalleeAddr, const ArgTs &...Args) { using namespace llvm::orc::shared; if constexpr (std::is_void_v) { // Void result: the executor-side function produces no value, so the only // thing to report is the dispatch error (success if the call ran). ES.callSPSWrapperAsync( - CallerFnAddr, + CalleeAddr, [OnComplete = std::move(OnComplete)](Error SerErr) mutable { OnComplete(std::move(SerErr)); }, Args...); } else { ES.callSPSWrapperAsync( - CallerFnAddr, + CalleeAddr, [OnComplete = std::move(OnComplete)](Error SerErr, CalleeRetT Result) mutable { if (SerErr) @@ -96,14 +103,9 @@ class Caller : public BaseT { void operator()(unique_function OnComplete, ArgTs... Args) override { - callAsync(std::move(OnComplete), ES, CallerFnAddr, Args...); + callAsync(std::move(OnComplete), this->executionSession(), + this->calleeAddr(), Args...); } - - using BaseT::operator(); - -private: - ExecutionSession &ES; - ExecutorAddr CallerFnAddr; }; using CallMainSPSSig = int64_t(shared::SPSExecutorAddr, diff --git a/llvm/unittests/ExecutionEngine/Orc/SPSCallersTest.cpp b/llvm/unittests/ExecutionEngine/Orc/SPSCallersTest.cpp index b2b41857cb976..d9dd59b9ec194 100644 --- a/llvm/unittests/ExecutionEngine/Orc/SPSCallersTest.cpp +++ b/llvm/unittests/ExecutionEngine/Orc/SPSCallersTest.cpp @@ -256,3 +256,75 @@ TEST(SPSCallersTest, Int32VoidSync) { cantFail(ES.endSession()); } + +// operator bool reflects whether the caller has a non-null callee address, and +// the accessors return the values the caller was constructed with. +TEST(SPSCallersTest, OperatorBoolAndAccessors) { + ExecutionSession ES(cantFail(SelfExecutorProcessControl::Create())); + + ExecutorAddr CalleeAddr = ExecutorAddr::fromPtr(callMainWrapper); + MainCaller CallMain(ES, CalleeAddr); + EXPECT_TRUE(static_cast(CallMain)); + EXPECT_EQ(CallMain.calleeAddr(), CalleeAddr); + EXPECT_EQ(&CallMain.executionSession(), &ES); + + // A caller with a null callee address is falsey. + MainCaller NullCall(ES, ExecutorAddr()); + EXPECT_FALSE(static_cast(NullCall)); + + cantFail(ES.endSession()); +} + +// A weakly-referenced Create against a missing symbol succeeds, yielding a +// caller with a null callee (falsey) rather than an error. +TEST(SPSCallersTest, CreateWeaklyReferencedAbsent) { + ExecutionSession ES(cantFail(SelfExecutorProcessControl::Create())); + + // Nothing is defined for MainCaller::CIName in the bootstrap JITDylib. + Expected CallMain = + MainCaller::Create(ES, SymbolLookupFlags::WeaklyReferencedSymbol); + ASSERT_THAT_EXPECTED(CallMain, Succeeded()); + EXPECT_FALSE(static_cast(*CallMain)); + EXPECT_EQ(CallMain->calleeAddr(), ExecutorAddr()); + + cantFail(ES.endSession()); +} + +// A weakly-referenced Create against a present symbol resolves it, yielding a +// usable caller (truthy) bound to the registered address. +TEST(SPSCallersTest, CreateWeaklyReferencedPresent) { + ExecutionSession ES(cantFail(SelfExecutorProcessControl::Create())); + + auto &BootstrapJD = ES.getBootstrapJITDylib(); + ExecutorAddr CalleeAddr = ExecutorAddr::fromPtr(callMainWrapper); + cantFail(BootstrapJD.define( + absoluteSymbols({{ES.intern(MainCaller::CIName), + {CalleeAddr, JITSymbolFlags::Exported}}}))); + + Expected CallMain = + MainCaller::Create(ES, SymbolLookupFlags::WeaklyReferencedSymbol); + ASSERT_THAT_EXPECTED(CallMain, Succeeded()); + EXPECT_TRUE(static_cast(*CallMain)); + EXPECT_EQ(CallMain->calleeAddr(), CalleeAddr); + + // The resolved caller is usable. + std::vector Args = {"a", "bb"}; + Expected R = (*CallMain)(ExecutorAddr::fromPtr(testMain), Args); + ASSERT_THAT_EXPECTED(R, Succeeded()); + EXPECT_EQ(*R, 2 + 1); // argc == 2, strlen("a") == 1. + + cantFail(ES.endSession()); +} + +// A required (default) Create against a missing symbol fails, rather than +// yielding a null caller as the weakly-referenced form does. +TEST(SPSCallersTest, CreateRequiredAbsentFails) { + ExecutionSession ES(cantFail(SelfExecutorProcessControl::Create())); + + // Nothing is defined for MainCaller::CIName in the bootstrap JITDylib, and + // the default lookup requires the symbol. + Expected CallMain = MainCaller::Create(ES); + EXPECT_THAT_EXPECTED(CallMain, Failed()); + + cantFail(ES.endSession()); +} From 3e9646a812300b86474e347066a37bf24b6fc10a Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Fri, 7 Aug 2026 09:04:40 +0900 Subject: [PATCH 022/789] [lld][WebAssembly] Allow linker-synthetic symbols to be undefine when building shared libraries (#153537) Fixes: #103592 --- lld/test/wasm/shared-synthetic-symbols.s | 75 ++++++++++++++++++++++++ lld/wasm/Driver.cpp | 33 +++++++---- 2 files changed, 97 insertions(+), 11 deletions(-) create mode 100644 lld/test/wasm/shared-synthetic-symbols.s diff --git a/lld/test/wasm/shared-synthetic-symbols.s b/lld/test/wasm/shared-synthetic-symbols.s new file mode 100644 index 0000000000000..0c9c68aabc239 --- /dev/null +++ b/lld/test/wasm/shared-synthetic-symbols.s @@ -0,0 +1,75 @@ +## Check that synthetic data-layout symbols such as __heap_base and __heap_end +## can be referenced from shared libraries and pie executables without +## generating undefined symbols. + +# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s +# RUN: wasm-ld --experimental-pic -pie --import-memory -o %t.wasm %t.o +# RUN: obj2yaml %t.wasm | FileCheck %s +# RUN: wasm-ld --experimental-pic -shared -o %t.so %t.o +# RUN: obj2yaml %t.so | FileCheck %s + +.globl _start + +_start: + .functype _start () -> () + i32.const __heap_base@GOT + drop + i32.const __heap_end@GOT + drop + i32.const __stack_low@GOT + drop + i32.const __stack_high@GOT + drop + i32.const __global_base@GOT + drop + i32.const __data_end@GOT + drop + end_function + +# CHECK: - Type: IMPORT +# CHECK-NEXT: Imports: +# CHECK-NEXT: - Module: env +# CHECK-NEXT: Field: memory +# CHECK-NEXT: Kind: MEMORY +# CHECK-NEXT: Memory: +# CHECK-NEXT: Minimum: 0x0 +# CHECK-NEXT: - Module: env +# CHECK-NEXT: Field: __memory_base +# CHECK-NEXT: Kind: GLOBAL +# CHECK-NEXT: GlobalType: I32 +# CHECK-NEXT: GlobalMutable: false +# CHECK-NEXT: - Module: env +# CHECK-NEXT: Field: __table_base +# CHECK-NEXT: Kind: GLOBAL +# CHECK-NEXT: GlobalType: I32 +# CHECK-NEXT: GlobalMutable: false +# CHECK-NEXT: - Module: GOT.mem +# CHECK-NEXT: Field: __heap_base +# CHECK-NEXT: Kind: GLOBAL +# CHECK-NEXT: GlobalType: I32 +# CHECK-NEXT: GlobalMutable: true +# CHECK-NEXT: - Module: GOT.mem +# CHECK-NEXT: Field: __heap_end +# CHECK-NEXT: Kind: GLOBAL +# CHECK-NEXT: GlobalType: I32 +# CHECK-NEXT: GlobalMutable: true +# CHECK-NEXT: - Module: GOT.mem +# CHECK-NEXT: Field: __stack_low +# CHECK-NEXT: Kind: GLOBAL +# CHECK-NEXT: GlobalType: I32 +# CHECK-NEXT: GlobalMutable: true +# CHECK-NEXT: - Module: GOT.mem +# CHECK-NEXT: Field: __stack_high +# CHECK-NEXT: Kind: GLOBAL +# CHECK-NEXT: GlobalType: I32 +# CHECK-NEXT: GlobalMutable: true +# CHECK-NEXT: - Module: GOT.mem +# CHECK-NEXT: Field: __global_base +# CHECK-NEXT: Kind: GLOBAL +# CHECK-NEXT: GlobalType: I32 +# CHECK-NEXT: GlobalMutable: true +# CHECK-NEXT: - Module: GOT.mem +# CHECK-NEXT: Field: __data_end +# CHECK-NEXT: Kind: GLOBAL +# CHECK-NEXT: GlobalType: I32 +# CHECK-NEXT: GlobalMutable: true diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index c213d7ca0b0f3..740e8878c6e03 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -1014,18 +1014,29 @@ static void createOptionalSymbols() { ctx.sym.dsoHandle = symtab->addOptionalDataSymbol("__dso_handle"); - if (!ctx.arg.shared) { - ctx.sym.dataEnd = symtab->addOptionalDataSymbol("__data_end"); - ctx.sym.rodataStart = symtab->addOptionalDataSymbol("__rodata_start"); - ctx.sym.rodataEnd = symtab->addOptionalDataSymbol("__rodata_end"); - } - + auto addDataLayoutSymbol = [&](StringRef s) -> DefinedData * { + // Data layout symbols are either defined by lld, or (in the case + // of PIC code) defined by the dynamic linker / embedder. + if (ctx.isPic) { + ctx.arg.allowUndefinedSymbols.insert(s); + return nullptr; + } else { + return symtab->addOptionalDataSymbol(s); + } + }; + + ctx.sym.dataEnd = addDataLayoutSymbol("__data_end"); + ctx.sym.rodataStart = addDataLayoutSymbol("__rodata_start"); + ctx.sym.rodataEnd = addDataLayoutSymbol("__rodata_end"); + ctx.sym.stackLow = addDataLayoutSymbol("__stack_low"); + ctx.sym.stackHigh = addDataLayoutSymbol("__stack_high"); + ctx.sym.globalBase = addDataLayoutSymbol("__global_base"); + ctx.sym.heapBase = addDataLayoutSymbol("__heap_base"); + ctx.sym.heapEnd = addDataLayoutSymbol("__heap_end"); + + // for pic, __memory_base and __table_base are handled in + // createSyntheticSymbols. if (!ctx.isPic) { - ctx.sym.stackLow = symtab->addOptionalDataSymbol("__stack_low"); - ctx.sym.stackHigh = symtab->addOptionalDataSymbol("__stack_high"); - ctx.sym.globalBase = symtab->addOptionalDataSymbol("__global_base"); - ctx.sym.heapBase = symtab->addOptionalDataSymbol("__heap_base"); - ctx.sym.heapEnd = symtab->addOptionalDataSymbol("__heap_end"); ctx.sym.memoryBase = createOptionalGlobal("__memory_base", false); ctx.sym.tableBase = createOptionalGlobal("__table_base", false); } From 9c121cd44867cd542964ae06617da1c40432bf2b Mon Sep 17 00:00:00 2001 From: Eric Christopher Date: Thu, 6 Aug 2026 17:12:33 -0700 Subject: [PATCH 023/789] [DebugInfo] Fix compact DWARF expression failure handling (#213391) printDwarfExpressionCompact has two pre-existing failure paths that silently produce bad output. The register-name callback is optional, but the short DW_OP_reg* and DW_OP_breg* paths call it directly, so a missing callback falls over. Use resolveRegName for every register form and report an unknown register only after both name-resolution paths fail. DW_OP_entry_value has the same problem: it ignores a failed recursive print, wraps the partial output in entry(...), and returns true. Print entry-value subexpressions into a temporary buffer and propagate failure before adding entry(...), so a failed subexpression can't come back as successful output. While here, GetRegName in llvm-objdump has a latent ordering issue: it writes an unknown-register diagnostic as soon as target lookup misses, even though resolveRegName can still decode an ASCII-packed virtual-register name. There's no natural in-tree input that hits this today -- LLVM emits text PTX and there's no NVPTX disassembler -- but a future out-of-tree disassembler using the same encoding would otherwise print a valid %r1 as "%r1". Keep GetRegName lookup-only and let the compact printer own the diagnostic. The llvm-objdump test makes the theoretical path testable by putting NVPTX's packed value for %r1 in ARM DWARF, so target lookup misses before packed-name decoding succeeds. Add target-independent unit coverage for missing callbacks, unknown registers, and nested failures. Tested via make check. Assisted by AI. --- .../DebugInfo/DWARF/DWARFExpressionPrinter.h | 4 +- .../DWARF/DWARFExpressionPrinter.cpp | 37 +++-- .../ELF/ARM/debug-vars-ascii-packed-reg.s | 50 ++++++ llvm/tools/llvm-objdump/SourcePrinter.cpp | 3 +- .../DWARFExpressionCompactPrinterTest.cpp | 148 ++++++++++++------ 5 files changed, 183 insertions(+), 59 deletions(-) create mode 100644 llvm/test/tools/llvm-objdump/ELF/ARM/debug-vars-ascii-packed-reg.s diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFExpressionPrinter.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFExpressionPrinter.h index 0aad492d47551..98be7cd9fd861 100644 --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFExpressionPrinter.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFExpressionPrinter.h @@ -41,7 +41,9 @@ LLVM_ABI void printDwarfExpression(const DWARFExpression *E, raw_ostream &OS, /// /// \param E to be printed /// \param OS to this stream -/// \param GetNameForDWARFReg callback to return dwarf register name +/// \param GetNameForDWARFReg side-effect-free callback to return a target +/// register name, or an empty string if none is available. The printer may try +/// another name-resolution method before reporting failure. /// /// \returns true if the expression was successfully printed LLVM_ABI bool printDwarfExpressionCompact( diff --git a/llvm/lib/DebugInfo/DWARF/DWARFExpressionPrinter.cpp b/llvm/lib/DebugInfo/DWARF/DWARFExpressionPrinter.cpp index ac9350b5b2f52..7a80ae027db1e 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFExpressionPrinter.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFExpressionPrinter.cpp @@ -287,6 +287,14 @@ static bool printCompactDWARFExpr( return false; }; + // Keep the diagnostic in the compact printer so every register form reports + // failure only after resolveRegName has tried to get a target name and decode + // an ASCII-packed name. + auto UnknownRegister = [](raw_ostream &OS, uint64_t DwarfRegNum) -> bool { + OS << ""; + return false; + }; + while (I != E) { const DWARFExpression::Operation &Op = *I; uint8_t Opcode = Op.getCode(); @@ -298,7 +306,7 @@ static bool printCompactDWARFExpr( std::string RegName = resolveRegName(DwarfRegNum, false, GetNameForDWARFReg); if (RegName.empty()) - return false; + return UnknownRegister(OS, DwarfRegNum); raw_svector_ostream S(Stack.emplace_back(PrintedExpr::Value).String); S << RegName; break; @@ -309,7 +317,7 @@ static bool printCompactDWARFExpr( std::string RegName = resolveRegName(DwarfRegNum, false, GetNameForDWARFReg); if (RegName.empty()) - return false; + return UnknownRegister(OS, DwarfRegNum); raw_svector_ostream S(Stack.emplace_back().String); S << RegName; if (Offset) @@ -323,10 +331,19 @@ static bool printCompactDWARFExpr( uint64_t SubExprLength = Op.getRawOperand(0); DWARFExpression::iterator SubExprEnd = I.skipBytes(SubExprLength); ++I; + + SmallString<16> SubExpr; + raw_svector_ostream SubExprOS(SubExpr); + // Keep the subexpression separate so we can copy its diagnostic on + // failure without leaving a partial entry(...) in the output. + if (!printCompactDWARFExpr(SubExprOS, I, SubExprEnd, + GetNameForDWARFReg)) { + OS << SubExprOS.str(); + return false; + } + raw_svector_ostream S(Stack.emplace_back().String); - S << "entry("; - printCompactDWARFExpr(S, I, SubExprEnd, GetNameForDWARFReg); - S << ")"; + S << "entry(" << SubExprOS.str() << ")"; I = SubExprEnd; continue; } @@ -351,18 +368,20 @@ static bool printCompactDWARFExpr( // DW_OP_reg: A register, with the register num implied by the // opcode. Printed as the plain register name. uint64_t DwarfRegNum = Opcode - dwarf::DW_OP_reg0; - auto RegName = GetNameForDWARFReg(DwarfRegNum, false); + std::string RegName = + resolveRegName(DwarfRegNum, false, GetNameForDWARFReg); if (RegName.empty()) - return false; + return UnknownRegister(OS, DwarfRegNum); raw_svector_ostream S(Stack.emplace_back(PrintedExpr::Value).String); S << RegName; } else if (Opcode >= dwarf::DW_OP_breg0 && Opcode <= dwarf::DW_OP_breg31) { int DwarfRegNum = Opcode - dwarf::DW_OP_breg0; int64_t Offset = Op.getRawOperand(0); - auto RegName = GetNameForDWARFReg(DwarfRegNum, false); + std::string RegName = + resolveRegName(DwarfRegNum, false, GetNameForDWARFReg); if (RegName.empty()) - return false; + return UnknownRegister(OS, DwarfRegNum); raw_svector_ostream S(Stack.emplace_back().String); S << RegName; if (Offset) diff --git a/llvm/test/tools/llvm-objdump/ELF/ARM/debug-vars-ascii-packed-reg.s b/llvm/test/tools/llvm-objdump/ELF/ARM/debug-vars-ascii-packed-reg.s new file mode 100644 index 0000000000000..6a4fc7fa7e816 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/ELF/ARM/debug-vars-ascii-packed-reg.s @@ -0,0 +1,50 @@ +## NVPTX packs virtual register names into DWARF register numbers, but its text +## PTX output does not exercise llvm-objdump's disassembler. Put the packed +## value for "%r1" in an ARM object to make the target lookup miss. Compact +## printing must produce "%r1" without first emitting +## "". +## +## Keep both instructions; llvm-objdump does not render this live range with +## only one. + +# RUN: llvm-mc -triple armv8a--none-eabi < %s -filetype=obj -o %t.o +# RUN: llvm-objdump %t.o -d --debug-vars=ascii | FileCheck %s \ +# RUN: --implicit-check-not="getContext().isLittleEndian()); DWARFExpression Expression(Data, Unit->getAddressByteSize()); - auto GetRegName = [&MRI, &OS](uint64_t DwarfRegNum, bool IsEH) -> StringRef { + auto GetRegName = [&MRI](uint64_t DwarfRegNum, bool IsEH) -> StringRef { if (std::optional LLVMRegNum = MRI.getLLVMRegNum(DwarfRegNum, IsEH)) if (const char *RegName = MRI.getName(*LLVMRegNum)) return StringRef(RegName); - OS << ""; return {}; }; diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFExpressionCompactPrinterTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFExpressionCompactPrinterTest.cpp index b0011047c7b13..e328f0ffa8809 100644 --- a/llvm/unittests/DebugInfo/DWARF/DWARFExpressionCompactPrinterTest.cpp +++ b/llvm/unittests/DebugInfo/DWARF/DWARFExpressionCompactPrinterTest.cpp @@ -12,12 +12,8 @@ #include "llvm/DebugInfo/DWARF/DWARFDie.h" #include "llvm/DebugInfo/DWARF/DWARFExpressionPrinter.h" #include "llvm/DebugInfo/DWARF/LowLevel/DWARFExpression.h" -#include "llvm/MC/MCInstrInfo.h" -#include "llvm/MC/MCRegisterInfo.h" -#include "llvm/MC/TargetRegistry.h" #include "llvm/Support/DataExtractor.h" #include "llvm/Support/LEB128.h" -#include "llvm/Support/TargetSelect.h" #include "llvm/Testing/Support/Error.h" #include "gtest/gtest.h" @@ -31,53 +27,61 @@ static void appendULEB128(SmallVectorImpl &V, uint64_t Val) { V.append(Buf, Buf + N); } -class DWARFExpressionCompactPrinterTest : public ::testing::Test { -public: - std::unique_ptr MRI; - - DWARFExpressionCompactPrinterTest() { - InitializeAllTargets(); - InitializeAllTargetMCs(); - InitializeAllAsmPrinters(); - - Triple TT("armv8a-linux-gnueabi"); - std::string ErrorStr; - - const Target *TheTarget = TargetRegistry::lookupTarget(TT, ErrorStr); +// Use a fixed map so these tests don't depend on which targets are built into +// the unit test binary. Unmapped values cover failed target lookups and +// ASCII-packed names. +static StringRef getTestRegisterName(uint64_t DwarfRegNum, bool) { + switch (DwarfRegNum) { + case 0: + return "R0"; + case 10: + return "R10"; + case 13: + return "SP"; + case 256: + return "D0"; + default: + return {}; + } +} - if (!TheTarget) - return; +static void expectCompactPrintFailureWithoutRegNames(ArrayRef ExprData, + StringRef Expected) { + std::string Result; + raw_string_ostream OS(Result); + DataExtractor DE(ExprData, true); + DWARFExpression Expr(DE, 8); - MRI.reset(TheTarget->createMCRegInfo(TT)); - } + EXPECT_FALSE(printDwarfExpressionCompact(&Expr, OS)); + EXPECT_EQ(OS.str(), Expected); +} +class DWARFExpressionCompactPrinterTest : public ::testing::Test { +public: void TestExprPrinter(ArrayRef ExprData, StringRef Expected); + void TestExprPrinterFailure(ArrayRef ExprData, StringRef Expected); }; } // namespace void DWARFExpressionCompactPrinterTest::TestExprPrinter( ArrayRef ExprData, StringRef Expected) { - // If we didn't build ARM, do not run the test. - if (!MRI) - GTEST_SKIP(); - - // Print the expression, passing in the subprogram DIE, and check that the - // result is as expected. std::string Result; raw_string_ostream OS(Result); DataExtractor DE(ExprData, true); DWARFExpression Expr(DE, 8); - auto GetRegName = [&](uint64_t DwarfRegNum, bool IsEH) -> StringRef { - if (std::optional LLVMRegNum = - this->MRI->getLLVMRegNum(DwarfRegNum, IsEH)) - if (const char *RegName = this->MRI->getName(*LLVMRegNum)) - return llvm::StringRef(RegName); - OS << ""; - return {}; - }; + EXPECT_TRUE(printDwarfExpressionCompact(&Expr, OS, getTestRegisterName)); + EXPECT_EQ(OS.str(), Expected); +} + +void DWARFExpressionCompactPrinterTest::TestExprPrinterFailure( + ArrayRef ExprData, StringRef Expected) { + std::string Result; + raw_string_ostream OS(Result); + DataExtractor DE(ExprData, true); + DWARFExpression Expr(DE, 8); - printDwarfExpressionCompact(&Expr, OS, GetRegName); + EXPECT_FALSE(printDwarfExpressionCompact(&Expr, OS, getTestRegisterName)); EXPECT_EQ(OS.str(), Expected); } @@ -93,10 +97,23 @@ TEST_F(DWARFExpressionCompactPrinterTest, Test_OP_regx) { TestExprPrinter({DW_OP_regx, 0x80, 0x02}, "D0"); } +// Register 100 has neither a target name nor an ASCII-packed name, so check +// that DW_OP_regx reports it as unknown and returns false. +TEST_F(DWARFExpressionCompactPrinterTest, Test_OP_regx_unknown) { + TestExprPrinterFailure({DW_OP_regx, 0x64}, ""); +} + TEST_F(DWARFExpressionCompactPrinterTest, Test_OP_breg0) { TestExprPrinter({DW_OP_breg0, 0x04}, "[R0+4]"); } +// With no register callback, the short register form must report register 0 as +// unknown and return false without calling GetNameForDWARFReg. +TEST_F(DWARFExpressionCompactPrinterTest, Test_OP_reg0_no_callback) { + expectCompactPrintFailureWithoutRegNames({DW_OP_reg0}, + ""); +} + TEST_F(DWARFExpressionCompactPrinterTest, Test_OP_breg0_large_offset) { TestExprPrinter({DW_OP_breg0, 0x80, 0x02}, "[R0+256]"); } @@ -117,6 +134,19 @@ TEST_F(DWARFExpressionCompactPrinterTest, Test_OP_bregx) { TestExprPrinter({DW_OP_bregx, 0x0d, 0x28}, "[SP+40]"); } +// DW_OP_bregx uses the same two lookups, so check that it reports register 100 +// as unknown and returns false when neither finds a name. +TEST_F(DWARFExpressionCompactPrinterTest, Test_OP_bregx_unknown) { + TestExprPrinterFailure({DW_OP_bregx, 0x64, 0x00}, ""); +} + +// With no register callback, the short base-register form must also report +// register 0 as unknown and return false without calling GetNameForDWARFReg. +TEST_F(DWARFExpressionCompactPrinterTest, Test_OP_breg0_no_callback) { + expectCompactPrintFailureWithoutRegNames({DW_OP_breg0, 0x00}, + ""); +} + TEST_F(DWARFExpressionCompactPrinterTest, Test_OP_stack_value) { TestExprPrinter({DW_OP_breg13, 0x04, DW_OP_stack_value}, "SP+4"); } @@ -132,13 +162,34 @@ TEST_F(DWARFExpressionCompactPrinterTest, Test_OP_entry_value_mem) { "entry([SP+16])"); } +// A failed register lookup inside DW_OP_entry_value must keep the nested +// diagnostic and fail the enclosing expression before printing entry(...). +TEST_F(DWARFExpressionCompactPrinterTest, + Test_OP_entry_value_unknown_register) { + TestExprPrinterFailure( + {DW_OP_entry_value, 0x02, DW_OP_regx, 0x64, DW_OP_stack_value}, + ""); +} + +// Use an opcode the compact printer does not handle to check that +// DW_OP_entry_value keeps the nested diagnostic and propagates the failure. +TEST_F(DWARFExpressionCompactPrinterTest, Test_OP_entry_value_unknown_op) { + TestExprPrinterFailure( + {DW_OP_entry_value, 0x02, DW_OP_const1u, 0x01, DW_OP_stack_value}, + ""); +} + +// DW_OP_nop leaves the stack empty, so compact printing must emit the +// stack-size diagnostic and return false. TEST_F(DWARFExpressionCompactPrinterTest, Test_OP_nop) { - TestExprPrinter({DW_OP_nop}, ""); + TestExprPrinterFailure({DW_OP_nop}, ""); } +// DW_OP_LLVM_nop leaves the stack empty as well, so it must emit the same +// diagnostic and return false. TEST_F(DWARFExpressionCompactPrinterTest, Test_OP_LLVM_nop) { - TestExprPrinter({DW_OP_LLVM_user, DW_OP_LLVM_nop}, - ""); + TestExprPrinterFailure({DW_OP_LLVM_user, DW_OP_LLVM_nop}, + ""); } TEST_F(DWARFExpressionCompactPrinterTest, Test_OP_nop_OP_reg) { @@ -149,14 +200,16 @@ TEST_F(DWARFExpressionCompactPrinterTest, Test_OP_LLVM_nop_OP_reg) { TestExprPrinter({DW_OP_LLVM_user, DW_OP_LLVM_nop, DW_OP_reg0}, "R0"); } +// An unhandled DW_OP_LLVM_user subopcode must print both opcode names and +// values, then return false. TEST_F(DWARFExpressionCompactPrinterTest, Test_OP_LLVM_user_unknown_subop) { - TestExprPrinter({DW_OP_LLVM_user, DW_OP_LLVM_form_aspace_address}, - ""); + TestExprPrinterFailure({DW_OP_LLVM_user, DW_OP_LLVM_form_aspace_address}, + ""); } -// NVPTX encodes virtual register names as a packed uint64_t DWARF register -// number; llvm-dwarfdump must still print the string when MC has no mapping. +// NVPTX packs virtual register names into DWARF register numbers, so compact +// printing without a callback must recover the name and return true. TEST(NVPTXPackedRegister, Compact_DW_OP_regx_NoMRI) { SmallVector Enc; Enc.push_back(DW_OP_regx); @@ -167,8 +220,7 @@ TEST(NVPTXPackedRegister, Compact_DW_OP_regx_NoMRI) { DataExtractor DE(Enc, true); DWARFExpression Expr(DE, 8); - printDwarfExpressionCompact(&Expr, OS, nullptr); - + EXPECT_TRUE(printDwarfExpressionCompact(&Expr, OS, nullptr)); EXPECT_EQ(OS.str(), "%rd2"); } @@ -199,7 +251,9 @@ TEST(NVPTXPackedRegister, Full_DW_OP_regx_CallbackMiss) { DWARFExpression Expr(DE, 8); DIDumpOptions DumpOpts; - DumpOpts.GetNameForDWARFReg = [](uint64_t, bool) -> StringRef { return {}; }; + // getTestRegisterName misses this packed value, so the full printer still + // needs to recover the name from the register number. + DumpOpts.GetNameForDWARFReg = getTestRegisterName; printDwarfExpression(&Expr, OS, DumpOpts, nullptr); From 52006000d1b886ca67c80554d06d3119c706749a Mon Sep 17 00:00:00 2001 From: dmaclach Date: Thu, 6 Aug 2026 17:14:49 -0700 Subject: [PATCH 024/789] [include-cleaner] Ensure receiver headers are kept when accessing ObjC properties (#212633) When accessing Objective-C properties via dot-notation (e.g., obj.foo), include-cleaner was previously only recording the usage of the property itself or its underlying getter/setter methods. This could lead to cases where the header declaring the receiver's type (Interface or Protocol) was incorrectly flagged as unused if no other standard methods were invoked on it. --- .../include-cleaner/lib/WalkAST.cpp | 15 +- .../include-cleaner/unittests/WalkASTTest.cpp | 310 +++++++++++++++++- 2 files changed, 317 insertions(+), 8 deletions(-) diff --git a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp index e3e610b8c33d8..7d15f96405903 100644 --- a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp +++ b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp @@ -193,7 +193,7 @@ class ASTWalker : public RecursiveASTVisitor { } bool VisitCXXConstructExpr(CXXConstructExpr *E) { - // Always treat consturctor calls as implicit. We'll have an explicit + // Always treat constructor calls as implicit. We'll have an explicit // reference for the constructor calls that mention the type-name (through // TypeLocs). This reference only matters for cases where there's no // explicit syntax at all or there're only braces. @@ -417,10 +417,11 @@ class ASTWalker : public RecursiveASTVisitor { } bool VisitObjCMessageExpr(ObjCMessageExpr *E) { + auto StartLoc = E->getSelectorStartLoc(); // Identify the selector and the method declaration if (auto *Method = E->getMethodDecl()) { // Report the method as a used symbol - report(E->getSelectorStartLoc(), Method); + report(StartLoc, Method); } // If it's a class message, report the interface/class as used @@ -428,6 +429,16 @@ class ASTWalker : public RecursiveASTVisitor { if (auto *Interface = E->getReceiverInterface()) { report(E->getReceiverRange().getBegin(), Interface); } + return true; + } + if (auto *Interface = E->getReceiverInterface()) { + report(StartLoc, Interface, RefType::Implicit); + } + QualType Type = E->getReceiverType(); + if (const auto *ObjCPtr = Type->getAs()) { + for (auto *Proto : ObjCPtr->quals()) { + report(StartLoc, Proto, RefType::Implicit); + } } return true; } diff --git a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp index 6bf0bde9cfa10..cf9a5a365edb6 100644 --- a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp +++ b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp @@ -605,7 +605,7 @@ TEST(WalkAST, ObjCImplementationDeclDependsOnInterface) { TEST(WalkAST, ObjCMessageExprSelectorLoc) { testWalk(R"objc( - @interface MyClass + @interface $implicit^MyClass $explicit^- (void)doSomething; @end )objc", @@ -617,6 +617,70 @@ TEST(WalkAST, ObjCMessageExprSelectorLoc) { {"-x", "objective-c"}); } +TEST(WalkAST, ObjCMessageExprSelectorLocProtocol) { + testWalk(R"objc( + @protocol $implicit^MyProtocol + $explicit^- (void)doSomething; + @end + )objc", + R"objc( + void test(id obj) { + [obj ^doSomething]; + } + )objc", + {"-x", "objective-c"}); +} + +TEST(WalkAST, ObjCMessageExprSelectorLocNestedProtocol) { + testWalk(R"objc( + @protocol FirstProtocol + $explicit^- (void)doSomething; + @end + @protocol $implicit^SecondProtocol + @end + )objc", + R"objc( + void test(id obj) { + [obj ^doSomething]; + } + )objc", + {"-x", "objective-c"}); +} + +TEST(WalkAST, ObjCMessageExprSelectorLocMultipleProtocol) { + testWalk(R"objc( + @protocol $implicit^FirstProtocol + @end + @protocol $implicit^SecondProtocol + $explicit^- (void)doSomething; + @end + )objc", + R"objc( + void test(id obj) { + [obj ^doSomething]; + } + )objc", + {"-x", "objective-c"}); +} + +TEST(WalkAST, ObjCMessageExprSelectorMessageChaining) { + testWalk(R"objc( + @interface $implicit^MyClass + $explicit^- (void)doSomething; + @end + @interface WrapperClass + - (MyClass *)myClass; + @end + )objc", + R"objc( + void test(WrapperClass *obj) { + // Weird space avoids Annotations thinking this is a range. + [ [obj myClass] ^doSomething]; + } + )objc", + {"-x", "objective-c"}); +} + TEST(WalkAST, ObjCMessageExprClassReceiver) { testWalk(R"objc( @interface $explicit^MyClass @@ -633,7 +697,7 @@ TEST(WalkAST, ObjCMessageExprClassReceiver) { TEST(WalkAST, ObjCPropertyRefExprExplicit) { testWalk(R"objc( - @interface MyClass + @interface $implicit^MyClass @property(nonatomic) int $explicit^foo; @end )objc", @@ -647,7 +711,7 @@ TEST(WalkAST, ObjCPropertyRefExprExplicit) { TEST(WalkAST, ObjCPropertyRefExprImplicitGetter) { testWalk(R"objc( - @interface MyClass + @interface $implicit^MyClass $explicit^- (int)foo; @end )objc", @@ -661,7 +725,7 @@ TEST(WalkAST, ObjCPropertyRefExprImplicitGetter) { TEST(WalkAST, ObjCPropertyRefExprImplicitSetter) { testWalk(R"objc( - @interface MyClass + @interface $implicit^MyClass $explicit^- (void)setFoo:(int)val; @end )objc", @@ -675,7 +739,7 @@ TEST(WalkAST, ObjCPropertyRefExprImplicitSetter) { TEST(WalkAST, ObjCPropertyRefExprExplicitSetter) { testWalk(R"objc( - @interface MyClass + @interface $implicit^MyClass @property(nonatomic) int $explicit^foo; @end )objc", @@ -687,9 +751,65 @@ TEST(WalkAST, ObjCPropertyRefExprExplicitSetter) { {"-x", "objective-c"}); } +TEST(WalkAST, ObjCPropertyRefExprDesugaredSetter) { + testWalk(R"objc( + @interface $implicit^MyClass + @property(nonatomic) int $explicit^foo; + @end + )objc", + R"objc( + void test(MyClass *obj) { + [obj ^setFoo:42]; + } + )objc", + {"-x", "objective-c"}); +} + +TEST(WalkAST, ObjCPropertyRefExprDesugaredGetter) { + testWalk(R"objc( + @interface $implicit^MyClass + @property(nonatomic) int $explicit^foo; + @end + )objc", + R"objc( + void test(MyClass *obj) { + [obj ^foo]; + } + )objc", + {"-x", "objective-c"}); +} + +TEST(WalkAST, ObjCPropertyRefExprDesugaredClassSetter) { + testWalk(R"objc( + @interface MyClass + @property(class) int $explicit^foo; + @end + )objc", + R"objc( + void test() { + [MyClass ^setFoo:42]; + } + )objc", + {"-x", "objective-c"}); +} + +TEST(WalkAST, ObjCPropertyRefExprDesugaredClassGetter) { + testWalk(R"objc( + @interface MyClass + @property(class) int $explicit^foo; + @end + )objc", + R"objc( + void test() { + [MyClass ^foo]; + } + )objc", + {"-x", "objective-c"}); +} + TEST(WalkAST, ObjCPropertyRefExprProtocol) { testWalk(R"objc( - @protocol MyProtocol + @protocol $implicit^MyProtocol @property(nonatomic) int $explicit^foo; @end )objc", @@ -701,6 +821,184 @@ TEST(WalkAST, ObjCPropertyRefExprProtocol) { {"-x", "objective-c"}); } +TEST(WalkAST, ObjCPropertyRefExprNestedProtocol) { + testWalk(R"objc( + @protocol FirstProtocol + @property(nonatomic) int $explicit^foo; + @end + @protocol $implicit^SecondProtocol + @end + )objc", + R"objc( + void test(id obj) { + int x = obj.^foo; + } + )objc", + {"-x", "objective-c"}); +} + +TEST(WalkAST, ObjCPropertyRefExprMultipleProtocol) { + testWalk(R"objc( + @protocol $implicit^FirstProtocol + @end + @protocol $implicit^SecondProtocol + @property(nonatomic) int $explicit^foo; + @end + )objc", + R"objc( + void test(id obj) { + int x = obj.^foo; + } + )objc", + {"-x", "objective-c"}); +} + +TEST(WalkAST, ObjCPropertyRefExprClassReceiver) { + testWalk(R"objc( + @interface MyClass + @property(class, nonatomic) int $explicit^foo; + @end + )objc", + R"objc( + void test() { + int x = MyClass.^foo; + } + )objc", + {"-x", "objective-c"}); +} + +TEST(WalkAST, ObjCPropertyRefExprClassReceiverInterface) { + testWalk(R"objc( + @interface $explicit^MyClass + @property(class, nonatomic) int foo; + @end + )objc", + R"objc( + void test() { + int x = ^MyClass.foo; + } + )objc", + {"-x", "objective-c"}); +} + +TEST(WalkAST, ObjCPropertyRefExprSuperReceiver) { + testWalk(R"objc( + @interface $implicit^ParentClass + @property(nonatomic) int $explicit^foo; + @end + @interface MyClass : ParentClass + @end + )objc", + R"objc( + @implementation MyClass + - (void)testSummary { + int x = super.^foo; + } + @end + )objc", + {"-x", "objective-c"}); +} + +TEST(WalkAST, ObjCPropertyRefExprClassSuperReceiver) { + testWalk(R"objc( + @interface $implicit^ParentClass + @property(class, nonatomic) int $explicit^foo; + @end + @interface MyClass : ParentClass + @end + )objc", + R"objc( + @implementation MyClass + + (void)testSummary { + int x = super.^foo; + } + @end + )objc", + {"-x", "objective-c"}); +} + +TEST(WalkAST, ObjCPropertyRefExprClassSuperSetter) { + testWalk(R"objc( + @interface $implicit^ParentClass + @property(class, nonatomic) int $explicit^foo; + @end + @interface MyClass : ParentClass + @end + )objc", + R"objc( + @implementation MyClass + + (void)testSummary { + super.^foo = 1; + } + @end + )objc", + {"-x", "objective-c"}); +} + +TEST(WalkAST, ObjCPropertyRefExprClassSuperProtocolReceiver) { + testWalk(R"objc( + @protocol MyProtocol + @property(class) int $explicit^foo; + @end + @interface $implicit^ParentClass + @end + @interface MyClass : ParentClass + @end + )objc", + R"objc( + @implementation MyClass + + (void)testSummary { + int x = super.^foo; + } + @end + )objc", + {"-x", "objective-c"}); +} + +TEST(WalkAST, ObjCPropertyRefExprSuperMultipleProtocolReceiver) { + testWalk(R"objc( + @protocol FirstProtocol + @end + @protocol SecondProtocol + @property(nonatomic) int $explicit^foo; + @end + @interface $implicit^ParentClass + @end + @interface MyClass : ParentClass + @end + )objc", + R"objc( + @implementation MyClass + - (void)testSummary { + int x = super.^foo; + } + @end + )objc", + {"-x", "objective-c"}); +} + +TEST(WalkAST, ObjCPropertyRefExprSuperNestedProtocolReceiver) { + testWalk(R"objc( + @protocol FirstProtocol + @property(nonatomic) int $explicit^foo; + @end + @protocol SecondProtocol + @end + @interface $implicit^ParentClass + @end + @interface MyClass : ParentClass + @end + )objc", + R"objc( + @implementation MyClass + - (void)testSummary { + int x = super.^foo; + } + @end + )objc", + {"-x", "objective-c"}); +} + TEST(WalkAST, ObjCProtocolInType) { testWalk(R"objc( @protocol $explicit^MyProtocol From 9219721a5d68b75a16e8d101e0114c2cff48ba3d Mon Sep 17 00:00:00 2001 From: Yonah Goldberg Date: Thu, 6 Aug 2026 17:34:27 -0700 Subject: [PATCH 025/789] [NVPTX] Fix broken cache hint metadata lit tests (#214600) I just merged https://github.com/llvm/llvm-project/pull/204067 and unfortunately forgot to locally compile all the PTX I was generating from cache hint metadata in lit tests. - I didn't know that .L2::cache_hint isn't valid on PTX volatile loads. We need to drop the metadata then for volatile loads. I'll put this up in a PR later, but for now just delete the lit test that generates the invalid PTX. I'll add it back in the follow up. - I forgot to provide SM version and PTX version when invoking ptxas for the lit tests. --- llvm/test/CodeGen/NVPTX/cache-hint-atomics.ll | 2 +- .../test/CodeGen/NVPTX/cache-hint-cache-policy.ll | 2 +- llvm/test/CodeGen/NVPTX/cache-hint-intrinsics.ll | 2 +- llvm/test/CodeGen/NVPTX/cache-hint-load-store.ll | 2 +- llvm/test/CodeGen/NVPTX/cache-hint-transforms.ll | 15 +-------------- 5 files changed, 5 insertions(+), 18 deletions(-) diff --git a/llvm/test/CodeGen/NVPTX/cache-hint-atomics.ll b/llvm/test/CodeGen/NVPTX/cache-hint-atomics.ll index 83ab4d9f0fa61..dab37a6b7510b 100644 --- a/llvm/test/CodeGen/NVPTX/cache-hint-atomics.ll +++ b/llvm/test/CodeGen/NVPTX/cache-hint-atomics.ll @@ -1,6 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --filter "^\s*(?:mov\.b64|ld(?:\.[A-Za-z0-9_:]+)*\.global|st(?:\.[A-Za-z0-9_:]+)*\.global|atom(?:\.[A-Za-z0-9_:]+)*\.global)" --version 6 ; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 | FileCheck %s -; RUN: %if ptxas %{ llc < %s -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 | %ptxas-verify %} +; RUN: %if ptxas-sm_80 && ptxas-isa-7.4 %{ llc < %s -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 | %ptxas-verify -arch=sm_80 %} ; !mem.cache_hint is legal on atomic IR memory instructions, but ; SelectionDAGBuilder currently drops it for atomic loads, stores, RMWs, and diff --git a/llvm/test/CodeGen/NVPTX/cache-hint-cache-policy.ll b/llvm/test/CodeGen/NVPTX/cache-hint-cache-policy.ll index 5f3761d91b3a6..89915fd94d0e0 100644 --- a/llvm/test/CodeGen/NVPTX/cache-hint-cache-policy.ll +++ b/llvm/test/CodeGen/NVPTX/cache-hint-cache-policy.ll @@ -1,6 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --filter "^\s*(?:mov\.b64|ld(?:\.[A-Za-z0-9_:]+)*\.global|st(?:\.[A-Za-z0-9_:]+)*\.global|ld(?:\.[A-Za-z0-9_:]+)*\.L2::cache_hint|st(?:\.[A-Za-z0-9_:]+)*\.L2::cache_hint|atom(?:\.[A-Za-z0-9_:]+)*\.global)" --version 6 ; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 | FileCheck %s -; RUN: %if ptxas %{ llc < %s -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 | %ptxas-verify %} +; RUN: %if ptxas-sm_80 && ptxas-isa-7.4 %{ llc < %s -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 | %ptxas-verify -arch=sm_80 %} ; Test L2::cache_hint metadata lowering with constant cache-policy operands. diff --git a/llvm/test/CodeGen/NVPTX/cache-hint-intrinsics.ll b/llvm/test/CodeGen/NVPTX/cache-hint-intrinsics.ll index 59bac44244460..19ac0f863a7ac 100644 --- a/llvm/test/CodeGen/NVPTX/cache-hint-intrinsics.ll +++ b/llvm/test/CodeGen/NVPTX/cache-hint-intrinsics.ll @@ -1,6 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --filter "^\s*(?:mov\.b64|ld(?:\.[A-Za-z0-9_:]+)*\.global|st(?:\.[A-Za-z0-9_:]+)*\.global|atom(?:\.[A-Za-z0-9_:]+)*\.global)" --version 6 ; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 | FileCheck %s -; RUN: %if ptxas %{ llc < %s -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 | %ptxas-verify %} +; RUN: %if ptxas-sm_80 && ptxas-isa-7.4 %{ llc < %s -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 | %ptxas-verify -arch=sm_80 %} ; Test !mem.cache_hint metadata on LLVM memory intrinsics. ; diff --git a/llvm/test/CodeGen/NVPTX/cache-hint-load-store.ll b/llvm/test/CodeGen/NVPTX/cache-hint-load-store.ll index 80601623b127c..8680ae5c6a180 100644 --- a/llvm/test/CodeGen/NVPTX/cache-hint-load-store.ll +++ b/llvm/test/CodeGen/NVPTX/cache-hint-load-store.ll @@ -1,6 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --filter "^\s*(?:mov\.b64|ld(?:\.[A-Za-z0-9_:]+)*\.global|st(?:\.[A-Za-z0-9_:]+)*\.global|atom(?:\.[A-Za-z0-9_:]+)*\.global)" --version 6 ; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_100 -mattr=+ptx88 | FileCheck %s -; RUN: %if ptxas %{ llc < %s -mtriple=nvptx64 -mcpu=sm_100 -mattr=+ptx88 | %ptxas-verify %} +; RUN: %if ptxas-sm_100 && ptxas-isa-8.8 %{ llc < %s -mtriple=nvptx64 -mcpu=sm_100 -mattr=+ptx88 | %ptxas-verify -arch=sm_100 %} ; Test !mem.cache_hint metadata lowering to PTX load/store cache qualifiers. diff --git a/llvm/test/CodeGen/NVPTX/cache-hint-transforms.ll b/llvm/test/CodeGen/NVPTX/cache-hint-transforms.ll index 39d8284616033..afa2342d025c7 100644 --- a/llvm/test/CodeGen/NVPTX/cache-hint-transforms.ll +++ b/llvm/test/CodeGen/NVPTX/cache-hint-transforms.ll @@ -1,7 +1,7 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --filter "^\s*(?:mov\.b64|ld(?:\.[A-Za-z0-9_:]+)*\.global|st(?:\.[A-Za-z0-9_:]+)*\.global|atom(?:\.[A-Za-z0-9_:]+)*\.global|ld\.param\.b32)" --version 6 ; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 | FileCheck %s --check-prefixes=CHECK,O2 ; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 -O0 | FileCheck %s --check-prefixes=CHECK,O0 -; RUN: %if ptxas %{ llc < %s -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 | %ptxas-verify %} +; RUN: %if ptxas-sm_80 && ptxas-isa-7.4 %{ llc < %s -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 | %ptxas-verify -arch=sm_80 %} ; Test cache hint handling across shared pointers, CSE, forwarding, and legalization. @@ -9,19 +9,6 @@ ; Multiple loads sharing same pointer ;----------------------------------------------------------------------------- -; Two volatile loads from the same pointer should each keep their own cache hint -; combination, even when they use the same cache-policy value. -define i32 @test_multiple_loads_same_ptr(ptr addrspace(1) %p) { -; CHECK-LABEL: test_multiple_loads_same_ptr( -; CHECK: mov.b64 %rd2, 12345; -; CHECK: ld.volatile.global.L1::evict_last.L2::cache_hint.b32 %r1, [%rd1], %rd2; -; CHECK: ld.volatile.global.L1::evict_first.L2::cache_hint.b32 %r2, [%rd1], %rd2; - %v1 = load volatile i32, ptr addrspace(1) %p, !mem.cache_hint !0 - %v2 = load volatile i32, ptr addrspace(1) %p, !mem.cache_hint !1 - %sum = add i32 %v1, %v2 - ret i32 %sum -} - ; Non-volatile loads can CSE. Matching cache hints are preserved on the merged ; DAG node, but conflicting hints are dropped. define i32 @test_cse_loads_same_cache_hint(ptr addrspace(1) %p) { From 77b44eb872002dae26be3de22671affbfb94a07b Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Thu, 6 Aug 2026 17:38:04 -0700 Subject: [PATCH 026/789] [docs][clang-format] Rename clang-format docs *.rst -> *.md, update refs (#211397) Tracking issue: #201242 See the [migration guide] for more information. [migration guide]: https://llvm.org/docs/SphinxQuickstartTemplate.html#markdown-migration-guidelines This is the initial straight rename commit. It will probably break the docs build, but it has to be a separate PR for blame preservation purposes. --------- Co-authored-by: owenca --- clang/docs/{ClangFormat.rst => ClangFormat.md} | 0 ...ClangFormatStyleOptions.rst => ClangFormatStyleOptions.md} | 0 clang/docs/tools/dump_format_help.py | 4 ++-- clang/docs/tools/dump_format_style.py | 4 ++-- clang/lib/Format/CMakeLists.txt | 4 ++-- clang/test/Format/docs_updated.test | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) rename clang/docs/{ClangFormat.rst => ClangFormat.md} (100%) rename clang/docs/{ClangFormatStyleOptions.rst => ClangFormatStyleOptions.md} (100%) diff --git a/clang/docs/ClangFormat.rst b/clang/docs/ClangFormat.md similarity index 100% rename from clang/docs/ClangFormat.rst rename to clang/docs/ClangFormat.md diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.md similarity index 100% rename from clang/docs/ClangFormatStyleOptions.rst rename to clang/docs/ClangFormatStyleOptions.md diff --git a/clang/docs/tools/dump_format_help.py b/clang/docs/tools/dump_format_help.py index ba41ed8c02c81..7ef22dcad3a13 100755 --- a/clang/docs/tools/dump_format_help.py +++ b/clang/docs/tools/dump_format_help.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # A tool to parse the output of `clang-format --help` and update the -# documentation in ../ClangFormat.rst automatically. +# documentation in ../ClangFormat.md automatically. import argparse import os @@ -9,7 +9,7 @@ import sys PARENT_DIR = os.path.join(os.path.dirname(__file__), "..") -DOC_FILE = os.path.join(PARENT_DIR, "ClangFormat.rst") +DOC_FILE = os.path.join(PARENT_DIR, "ClangFormat.md") def substitute(text, tag, contents): diff --git a/clang/docs/tools/dump_format_style.py b/clang/docs/tools/dump_format_style.py index 570a0cc6dde1d..a78c8f54045cc 100755 --- a/clang/docs/tools/dump_format_style.py +++ b/clang/docs/tools/dump_format_style.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # A tool to parse the FormatStyle struct from Format.h and update the -# documentation in ../ClangFormatStyleOptions.rst automatically. +# documentation in ../ClangFormatStyleOptions.md automatically. # Run from the directory in which this file is located to update the docs. import argparse @@ -16,7 +16,7 @@ INCLUDE_STYLE_FILE = os.path.join( CLANG_DIR, "include/clang/Tooling/Inclusions/IncludeStyle.h" ) -DOC_FILE = os.path.join(CLANG_DIR, "docs/ClangFormatStyleOptions.rst") +DOC_FILE = os.path.join(CLANG_DIR, "docs/ClangFormatStyleOptions.md") PLURALS_FILE = os.path.join(os.path.dirname(__file__), "plurals.txt") diff --git a/clang/lib/Format/CMakeLists.txt b/clang/lib/Format/CMakeLists.txt index 488732430862e..272c8fcfa8477 100644 --- a/clang/lib/Format/CMakeLists.txt +++ b/clang/lib/Format/CMakeLists.txt @@ -67,7 +67,7 @@ set(docs_tools_dir ${CLANG_SOURCE_DIR}/docs/tools) set(format_style_depend ${CMAKE_CURRENT_BINARY_DIR}/format_style_depend) set(dump_style dump_format_style.py) -set(style_options_rst ${CLANG_SOURCE_DIR}/docs/ClangFormatStyleOptions.rst) +set(style_options_md ${CLANG_SOURCE_DIR}/docs/ClangFormatStyleOptions.md) add_custom_command(OUTPUT ${format_style_depend} COMMAND ${Python3_EXECUTABLE} ${dump_style} && touch ${format_style_depend} WORKING_DIRECTORY ${docs_tools_dir} @@ -83,7 +83,7 @@ add_custom_target(clang-format-style DEPENDS ${format_style_depend}) set(format_help_depend ${CMAKE_CURRENT_BINARY_DIR}/format_help_depend) set(dump_help dump_format_help.py) -set(clang_format_rst ${CLANG_SOURCE_DIR}/docs/ClangFormat.rst) +set(clang_format_md ${CLANG_SOURCE_DIR}/docs/ClangFormat.md) add_custom_command(OUTPUT ${format_help_depend} COMMAND ${Python3_EXECUTABLE} ${dump_help} -d ${CMAKE_BINARY_DIR}/bin && touch ${format_help_depend} diff --git a/clang/test/Format/docs_updated.test b/clang/test/Format/docs_updated.test index 98d330e37ef45..c306f16def3e9 100644 --- a/clang/test/Format/docs_updated.test +++ b/clang/test/Format/docs_updated.test @@ -1,6 +1,6 @@ // RUN: %python %S/../../docs/tools/dump_format_style.py -o %t.style // RUN: diff --strip-trailing-cr %t.style \ -// RUN: %S/../../docs/ClangFormatStyleOptions.rst +// RUN: %S/../../docs/ClangFormatStyleOptions.md // RUN: %python %S/../../docs/tools/dump_format_help.py -o %t.help -// RUN: diff --strip-trailing-cr %t.help %S/../../docs/ClangFormat.rst +// RUN: diff --strip-trailing-cr %t.help %S/../../docs/ClangFormat.md From 668134e8acf10218663a0c33835bd4157ba358c4 Mon Sep 17 00:00:00 2001 From: Roy Shi Date: Thu, 6 Aug 2026 17:39:05 -0700 Subject: [PATCH 027/789] [gsymutil] Add `--statistics` option (#186495) # Motiviation Currently, if one wants to know the size of the sections in a gSYM (e.g. to check if they exceed 4GB), they have to dump the whole gSYM in the text form, then process that huge text to get the sizes. # New option `--statistics[=]` This patch adds a `llvm-gsymutil --statistics[=]` option to print the size info for all sections. It supports three formats: * `text`: Default. * `json`: Dense JSON. * `pretty-json`: Pretty-printed JSON. See example output below. # Examples ``` royshi-mac-office ~/tmp % guuu v2.gsym --statistics GSYM statistics for "v2.gsym": UUID: 4C4C446A-5555-3144-A1CF-AEBBCCD48E61 Number of addresses: 6,382 File size: 3,095,960 bytes Header: 20 bytes ( 0.00%) Global data dir: 140 bytes ( 0.00%) UUID section: 16 bytes ( 0.00%) Address table: 25,528 bytes ( 0.82%) Addr info offsets: 51,056 bytes ( 1.65%) File table: 3,652 bytes ( 0.12%) String table: 1,772,169 bytes (57.24%) Function info data: 1,243,376 bytes (40.16%) Size and name: 76,584 bytes ( 2.47%) Line table info: 145,260 bytes ( 4.69%) Inline info: 58,540 bytes ( 1.89%) Call site info: 25,902 bytes ( 0.84%) End of list: 51,056 bytes ( 1.65%) Padding: 5,387 bytes ( 0.17%) Merged func info: 880,647 bytes (28.45%) InfoType/InfoLength/Count/FnSize: 102,900 bytes ( 3.32%) Size and name: 209,160 bytes ( 6.76%) Line table info: 424,847 bytes (13.72%) Inline info: 2,058 bytes ( 0.07%) Call site info: 2,242 bytes ( 0.07%) Merged func info: 0 bytes ( 0.00%) End of list: 139,440 bytes ( 4.50%) Padding: 3 bytes ( 0.00%) royshi-mac-office ~/tmp % guuu v2.gsym --statistics=pretty-json { "byte-sizes": { "addr_info_offsets": 51056, "address_table": 25528, "file_size": 3095960, "file_table": 3652, "function_info_data": 1243376, "function_info_type_sizes": { "call_site_info": 25902, "end_of_list": 51056, "inline_info": 58540, "line_table_info": 145260, "merged_func_info": 880647, "merged_func_info_type_sizes": { "call_site_info": 2242, "end_of_list": 139440, "infotype_infolength_count_and_fnsize": 102900, "inline_info": 2058, "line_table_info": 424847, "merged_func_info": 0, "size_and_name": 209160 }, "padding": 5387, "size_and_name": 76584 }, "global_data_directory": 140, "header": 20, "padding": 3, "string_table": 1772169, "uuid_section": 16 }, "num_addresses": 6382, "path": "v2.gsym", "uuid": "4C4C446A-5555-3144-A1CF-AEBBCCD48E61" } ``` --- .../llvm/DebugInfo/GSYM/FunctionInfo.h | 38 ++ llvm/include/llvm/DebugInfo/GSYM/GsymReader.h | 18 + .../llvm/DebugInfo/GSYM/GsymReaderV1.h | 3 + .../llvm/DebugInfo/GSYM/GsymReaderV2.h | 4 + llvm/lib/DebugInfo/GSYM/FunctionInfo.cpp | 79 ++++ llvm/lib/DebugInfo/GSYM/GsymReader.cpp | 204 +++++++++ llvm/tools/llvm-gsymutil/Opts.td | 8 + llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp | 25 ++ llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp | 397 ++++++++++++++++++ 9 files changed, 776 insertions(+) diff --git a/llvm/include/llvm/DebugInfo/GSYM/FunctionInfo.h b/llvm/include/llvm/DebugInfo/GSYM/FunctionInfo.h index 0713ff27966d9..4e9ba92f72182 100644 --- a/llvm/include/llvm/DebugInfo/GSYM/FunctionInfo.h +++ b/llvm/include/llvm/DebugInfo/GSYM/FunctionInfo.h @@ -28,6 +28,27 @@ namespace gsym { class GsymCreator; class GsymReader; +class GsymDataExtractor; + +/// Byte-size accounting for a FunctionInfo, broken down by field / InfoType. +/// Populated by FunctionInfo::parseStatistics. Every value is a byte count and +/// each on-disk byte of a FunctionInfo is attributed to exactly one member: +/// FunctionInfo = SizeAndName + LineTableInfo + InlineInfo + CallSiteInfo + +/// MergedFuncInfo + EndOfList +/// (the per-InfoType members include that section's 8-byte InfoType+InfoLength +/// header). InfoTypeInfoLengthCountAndFnSize is only used for the inner +/// (merged) breakdown and captures the MergedFunctionsInfo structural bytes: +/// its own InfoType+InfoLength (8) plus Count (4) plus each FnSize (4). +struct FunctionInfoStats { + uint64_t SizeAndName = 0; + uint64_t LineTableInfo = 0; + uint64_t InlineInfo = 0; + uint64_t CallSiteInfo = 0; + uint64_t MergedFuncInfo = 0; + uint64_t EndOfList = 0; + uint64_t InfoTypeInfoLengthCountAndFnSize = 0; +}; + /// Function information in GSYM files encodes information for one contiguous /// address range. If a function has discontiguous address ranges, they will /// need to be encoded using multiple FunctionInfo objects. @@ -203,6 +224,23 @@ struct FunctionInfo { uint64_t Addr, std::optional *MergedFuncsData = nullptr); + /// Parse the function info data and accumulate the byte size of each field / + /// InfoType into \a Stats. + /// + /// \param Data The binary stream to read the data from. Its string-offset + /// size is used to size the FunctionInfo Name field (4 bytes in GSYM v1, + /// 1-8 bytes in v2). + /// + /// \param Stats Updated with the per-field byte sizes for this FunctionInfo. + /// + /// \param MergedFuncInfoStats If non-null, and a MergedFunctionsInfo section + /// is present, this is updated with the byte breakdown of the inner + /// FunctionInfos plus the MergedFunctionsInfo structural bytes + /// (InfoTypeInfoLengthCountAndFnSize). + LLVM_ABI static void + parseStatistics(GsymDataExtractor &Data, FunctionInfoStats &Stats, + FunctionInfoStats *MergedFuncInfoStats = nullptr); + uint64_t startAddress() const { return Range.start(); } uint64_t endAddress() const { return Range.end(); } uint64_t size() const { return Range.size(); } diff --git a/llvm/include/llvm/DebugInfo/GSYM/GsymReader.h b/llvm/include/llvm/DebugInfo/GSYM/GsymReader.h index a0a9b715c11fc..ced5ff5fbbc7b 100644 --- a/llvm/include/llvm/DebugInfo/GSYM/GsymReader.h +++ b/llvm/include/llvm/DebugInfo/GSYM/GsymReader.h @@ -85,6 +85,10 @@ class GsymReader { /// Get the string offset byte size for this GSYM file. virtual uint8_t getStringOffsetSize() const = 0; + /// Get the raw UUID bytes for this GSYM file, or an empty ref if none. + /// In v1 the UUID lives in the header; in v2 it is an optional data section. + virtual StringRef getUUID() const = 0; + /// Construct a GsymReader from a file on disk. /// /// \param Path The file path the GSYM file to read. @@ -199,6 +203,20 @@ class GsymReader { /// \param OS The output stream to dump to. virtual void dump(raw_ostream &OS) = 0; + enum class StatisticsFormat { Text, JSON, PrettyJSON }; + + /// Dump statistics about the GSYM data contained in this object. + /// + /// \param OS The output stream to dump to. + /// + /// \param Format Output format: Text, JSON (dense), or PrettyJSON. + /// + /// \param GSYMPath Optional file path, used only as a display label in the + /// output (empty for in-memory GSYM data). + LLVM_ABI void dumpStatistics(raw_ostream &OS, + StatisticsFormat Format = StatisticsFormat::Text, + StringRef GSYMPath = ""); + /// Dump a FunctionInfo object. /// /// This function will convert any string table indexes and file indexes diff --git a/llvm/include/llvm/DebugInfo/GSYM/GsymReaderV1.h b/llvm/include/llvm/DebugInfo/GSYM/GsymReaderV1.h index 8cc6a75c51baa..ace2a6a3bcca9 100644 --- a/llvm/include/llvm/DebugInfo/GSYM/GsymReaderV1.h +++ b/llvm/include/llvm/DebugInfo/GSYM/GsymReaderV1.h @@ -42,6 +42,9 @@ class LLVM_ABI GsymReaderV1 : public GsymReader { uint8_t getStringOffsetSize() const override { return Header::getStringOffsetSize(); } + StringRef getUUID() const override { + return StringRef(reinterpret_cast(Hdr->UUID), Hdr->UUIDSize); + } using GsymReader::dump; void dump(raw_ostream &OS) override; diff --git a/llvm/include/llvm/DebugInfo/GSYM/GsymReaderV2.h b/llvm/include/llvm/DebugInfo/GSYM/GsymReaderV2.h index dec457ec25745..e79b1275a232d 100644 --- a/llvm/include/llvm/DebugInfo/GSYM/GsymReaderV2.h +++ b/llvm/include/llvm/DebugInfo/GSYM/GsymReaderV2.h @@ -42,6 +42,10 @@ class LLVM_ABI GsymReaderV2 : public GsymReader { uint8_t getStringOffsetSize() const override { return HeaderV2::getStringOffsetSize(); } + StringRef getUUID() const override { + return getOptionalGlobalDataBytes(GlobalInfoType::UUID) + .value_or(StringRef()); + } using GsymReader::dump; void dump(raw_ostream &OS) override; diff --git a/llvm/lib/DebugInfo/GSYM/FunctionInfo.cpp b/llvm/lib/DebugInfo/GSYM/FunctionInfo.cpp index daf76144acacb..a572d057454a0 100644 --- a/llvm/lib/DebugInfo/GSYM/FunctionInfo.cpp +++ b/llvm/lib/DebugInfo/GSYM/FunctionInfo.cpp @@ -236,6 +236,85 @@ llvm::Expected FunctionInfo::encode(FileWriter &Out, return FuncInfoOffset; } +void FunctionInfo::parseStatistics(GsymDataExtractor &Data, + FunctionInfoStats &Stats, + FunctionInfoStats *MergedFuncInfoStats) { + uint64_t Offset = 0; + // FunctionInfo header: Size (a uint32_t) followed by Name (a string offset). + // The string offset width is 4 bytes in GSYM v1 but variable (1-8 bytes) in + // v2, so query it from the extractor instead of assuming 4. + const uint64_t SizeAndNameSize = 4 + Data.getStringOffsetSize(); + if (!Data.isValidOffsetForDataOfSize(Offset, SizeAndNameSize)) + return; + Stats.SizeAndName += SizeAndNameSize; + Offset += SizeAndNameSize; + while (true) { + if (!Data.isValidOffsetForDataOfSize(Offset, 8)) + return; + const uint32_t InfoType = Data.getU32(&Offset); + const uint32_t InfoLength = Data.getU32(&Offset); + if (InfoType == InfoType::EndOfList) { + Stats.EndOfList += 8; // InfoType (0) + InfoLength (0) + return; + } + if (!Data.isValidOffsetForDataOfSize(Offset, InfoLength)) + return; + // Each InfoType's size includes its 8-byte InfoType+InfoLength header plus + // the payload. + const uint64_t TLVSize = InfoLength + 8; + switch (InfoType) { + case InfoType::LineTableInfo: + Stats.LineTableInfo += TLVSize; + break; + case InfoType::InlineInfo: + Stats.InlineInfo += TLVSize; + break; + case InfoType::CallSiteInfo: + Stats.CallSiteInfo += TLVSize; + break; + case InfoType::MergedFunctionsInfo: { + Stats.MergedFuncInfo += TLVSize; + // A MergedFunctionsInfo should never be nested inside another one. + if (!MergedFuncInfoStats) { + errs() + << "error: MergedFunctionsInfo found inside a MergedFunctionsInfo, " + "which is not supported\n"; + break; + } + // Account the MergedFunctionsInfo structural bytes: its own + // InfoType+InfoLength (8), then Count (uint32_t) and each FnSize + // (uint32_t). Then recurse into each inner FunctionInfo (encoded with no + // padding, so no gaps between them). + MergedFuncInfoStats->InfoTypeInfoLengthCountAndFnSize += 8; + // Sub-range extractor inherits the parent's string offset size. + GsymDataExtractor MergedData(Data, Offset, InfoLength); + uint64_t MOffset = 0; + if (MergedData.isValidOffsetForDataOfSize(MOffset, 4)) { + const uint32_t Count = MergedData.getU32(&MOffset); + MergedFuncInfoStats->InfoTypeInfoLengthCountAndFnSize += 4; // Count + for (uint32_t I = 0; I < Count; ++I) { + if (!MergedData.isValidOffsetForDataOfSize(MOffset, 4)) + break; + const uint32_t FnSize = MergedData.getU32(&MOffset); + MergedFuncInfoStats->InfoTypeInfoLengthCountAndFnSize += 4; // FnSize + if (!MergedData.isValidOffsetForDataOfSize(MOffset, FnSize)) + break; + GsymDataExtractor FuncData(MergedData, MOffset, FnSize); + parseStatistics(FuncData, *MergedFuncInfoStats, nullptr); + MOffset += FnSize; + } + } + break; + } + default: + // Unknown InfoType: its bytes are left unattributed and surface as part + // of the file-level FunctionInfo "padding" remainder. + break; + } + Offset += InfoLength; + } +} + llvm::Expected FunctionInfo::lookup(GsymDataExtractor &Data, const GsymReader &GR, uint64_t FuncAddr, uint64_t Addr, diff --git a/llvm/lib/DebugInfo/GSYM/GsymReader.cpp b/llvm/lib/DebugInfo/GSYM/GsymReader.cpp index 92efd66566445..49ea7003fd483 100644 --- a/llvm/lib/DebugInfo/GSYM/GsymReader.cpp +++ b/llvm/lib/DebugInfo/GSYM/GsymReader.cpp @@ -13,12 +13,14 @@ #include #include +#include "llvm/ADT/StringExtras.h" #include "llvm/DebugInfo/GSYM/GsymReaderV1.h" #include "llvm/DebugInfo/GSYM/GsymReaderV2.h" #include "llvm/DebugInfo/GSYM/Header.h" #include "llvm/DebugInfo/GSYM/HeaderV2.h" #include "llvm/DebugInfo/GSYM/InlineInfo.h" #include "llvm/DebugInfo/GSYM/LineTable.h" +#include "llvm/Support/JSON.h" #include "llvm/Support/MemoryBuffer.h" using namespace llvm; @@ -496,6 +498,208 @@ GsymReader::lookupAll(uint64_t Addr) const { return Results; } +/// Format raw UUID bytes as a hex string, using the canonical 8-4-4-4-12 +/// dashed layout for the common 16-byte UUID and plain hex otherwise. +static std::string formatGsymUUID(StringRef Bytes) { + std::string Hex = toHex(Bytes, /*LowerCase=*/false); + if (Bytes.size() == 16) { + Hex.insert(20, "-"); + Hex.insert(16, "-"); + Hex.insert(12, "-"); + Hex.insert(8, "-"); + } + return Hex; +} + +void GsymReader::dumpStatistics(raw_ostream &OS, StatisticsFormat Format, + StringRef GSYMPath) { + // The total file size is the size of the in-memory buffer this reader was + // created from, so no filesystem access is required and in-memory GSYM data + // can be analyzed too. + const uint64_t FileSize = MemBuffer->getBufferSize(); + + // Section sizes come from the GlobalData directory, which is populated for + // both GSYM v1 and v2 readers, so the same logic works for both versions. + auto SectionSize = [&](GlobalInfoType Type) -> uint64_t { + if (std::optional GD = getGlobalData(Type)) + return GD->FileSize; + return 0; + }; + const uint64_t AddrTableSize = SectionSize(GlobalInfoType::AddrOffsets); + const uint64_t AddrInfoOffsetsSize = + SectionSize(GlobalInfoType::AddrInfoOffsets); + const uint64_t FileTableSize = SectionSize(GlobalInfoType::FileTable); + const uint64_t StrtabSize = SectionSize(GlobalInfoType::StringTable); + const uint64_t FuncInfoSize = SectionSize(GlobalInfoType::FunctionInfo); + // The V2 GlobalData directory is an on-disk array of 20-byte entries (Type + // u32 + // + FileOffset u64 + FileSize u64) terminated by an EndOfList entry. V1 + // synthesizes its GlobalData entries and has no on-disk directory. + const uint64_t GlobalDataDirSize = + getVersion() >= 2 ? (GlobalDataSections.size() + 1) * 20 : 0; + // In V2 the UUID is its own data section; report its payload separately. In + // V1 the UUID lives inline in the fixed header, so it is already counted + // there. + const uint64_t UUIDSize = + getVersion() >= 2 ? SectionSize(GlobalInfoType::UUID) : 0; + // The fixed file header precedes the GlobalData directory (V2) and the data + // sections. Its V2 size is a constant; in V1 (no on-disk directory) the + // header ends where the earliest data section begins. + uint64_t HeaderSize = HeaderV2::getEncodedSize(); + if (getVersion() < 2) { + uint64_t MinSectionOffset = FileSize; + for (const auto &KV : GlobalDataSections) + MinSectionOffset = std::min(MinSectionOffset, KV.second.FileOffset); + HeaderSize = MinSectionOffset; + } + // Anything left over (alignment padding between sections) is reported as + // padding so that the byte-sizes sum exactly to the file size. + const uint64_t KnownSize = HeaderSize + GlobalDataDirSize + UUIDSize + + AddrTableSize + AddrInfoOffsetsSize + + FileTableSize + StrtabSize + FuncInfoSize; + const uint64_t PaddingSize = FileSize > KnownSize ? FileSize - KnownSize : 0; + const uint64_t NumAddresses = getNumAddresses(); + + // Walk every FunctionInfo to accumulate the per-field byte sizes. + FunctionInfoStats FI; + FunctionInfoStats Merged; + for (uint64_t I = 0; I < NumAddresses; ++I) { + uint64_t FuncStartAddr = 0; + if (auto ExpData = getFunctionInfoDataAtIndex(I, FuncStartAddr)) { + GsymDataExtractor Data = std::move(*ExpData); + FunctionInfo::parseStatistics(Data, FI, &Merged); + } else { + consumeError(ExpData.takeError()); + } + } + // Alignment padding between top-level FunctionInfos (each is 4-byte aligned) + // is not attributed to any per-function field; report it as the remainder so + // that the sum of the type sizes equals function_info_data. + const uint64_t FIAttributed = FI.SizeAndName + FI.LineTableInfo + + FI.InlineInfo + FI.CallSiteInfo + + FI.MergedFuncInfo + FI.EndOfList; + const uint64_t Padding = + FuncInfoSize > FIAttributed ? FuncInfoSize - FIAttributed : 0; + + const std::string UUIDStr = formatGsymUUID(getUUID()); + + if (Format == StatisticsFormat::JSON || + Format == StatisticsFormat::PrettyJSON) { + json::Object MergedTypes{ + {"infotype_infolength_count_and_fnsize", + static_cast(Merged.InfoTypeInfoLengthCountAndFnSize)}, + {"size_and_name", static_cast(Merged.SizeAndName)}, + {"line_table_info", static_cast(Merged.LineTableInfo)}, + {"inline_info", static_cast(Merged.InlineInfo)}, + {"call_site_info", static_cast(Merged.CallSiteInfo)}, + {"merged_func_info", static_cast(Merged.MergedFuncInfo)}, + {"end_of_list", static_cast(Merged.EndOfList)}}; + + json::Object FuncTypes{ + {"size_and_name", static_cast(FI.SizeAndName)}, + {"line_table_info", static_cast(FI.LineTableInfo)}, + {"inline_info", static_cast(FI.InlineInfo)}, + {"call_site_info", static_cast(FI.CallSiteInfo)}, + {"merged_func_info", static_cast(FI.MergedFuncInfo)}, + {"end_of_list", static_cast(FI.EndOfList)}, + {"padding", static_cast(Padding)}, + {"merged_func_info_type_sizes", std::move(MergedTypes)}}; + + json::Object ByteSizes{ + {"file_size", static_cast(FileSize)}, + {"header", static_cast(HeaderSize)}, + {"global_data_directory", static_cast(GlobalDataDirSize)}, + {"uuid_section", static_cast(UUIDSize)}, + {"padding", static_cast(PaddingSize)}, + {"address_table", static_cast(AddrTableSize)}, + {"addr_info_offsets", static_cast(AddrInfoOffsetsSize)}, + {"file_table", static_cast(FileTableSize)}, + {"string_table", static_cast(StrtabSize)}, + {"function_info_data", static_cast(FuncInfoSize)}, + {"function_info_type_sizes", std::move(FuncTypes)}}; + + json::Object Root{{"path", GSYMPath.str()}, + {"uuid", UUIDStr}, + {"num_addresses", static_cast(NumAddresses)}, + {"byte-sizes", std::move(ByteSizes)}}; + + json::Value V(std::move(Root)); + if (Format == StatisticsFormat::PrettyJSON) + OS << formatv("{0:2}", V) << "\n"; + else + OS << V << "\n"; + return; + } + + // Text format output. + auto Fmt = [](uint64_t Value) { + std::string Num = std::to_string(Value); + int InsertPosition = Num.length() - 3; + while (InsertPosition > 0) { + Num.insert(InsertPosition, ","); + InsertPosition -= 3; + } + return std::string(std::max((size_t)0, 14 - Num.length()), ' ') + Num; + }; + auto Pct = [&](uint64_t Value) -> std::string { + char Buf[16]; + snprintf(Buf, sizeof(Buf), "(%5.2f%%)", 100.0 * Value / FileSize); + return Buf; + }; + + OS << "GSYM statistics for \"" << GSYMPath << "\":\n"; + OS << " UUID: " << UUIDStr << "\n"; + OS << " Number of addresses: " << Fmt(NumAddresses) << "\n"; + OS << " File size: " << Fmt(FileSize) << " bytes\n"; + OS << " Header: " << Fmt(HeaderSize) << " bytes " + << Pct(HeaderSize) << "\n"; + OS << " Global data dir: " << Fmt(GlobalDataDirSize) << " bytes " + << Pct(GlobalDataDirSize) << "\n"; + OS << " UUID section: " << Fmt(UUIDSize) << " bytes " << Pct(UUIDSize) + << "\n"; + OS << " Address table: " << Fmt(AddrTableSize) << " bytes " + << Pct(AddrTableSize) << "\n"; + OS << " Addr info offsets: " << Fmt(AddrInfoOffsetsSize) << " bytes " + << Pct(AddrInfoOffsetsSize) << "\n"; + OS << " File table: " << Fmt(FileTableSize) << " bytes " + << Pct(FileTableSize) << "\n"; + OS << " String table: " << Fmt(StrtabSize) << " bytes " + << Pct(StrtabSize) << "\n"; + OS << " Function info data: " << Fmt(FuncInfoSize) << " bytes " + << Pct(FuncInfoSize) << "\n"; + OS << " Size and name: " << Fmt(FI.SizeAndName) << " bytes " + << Pct(FI.SizeAndName) << "\n"; + OS << " Line table info: " << Fmt(FI.LineTableInfo) << " bytes " + << Pct(FI.LineTableInfo) << "\n"; + OS << " Inline info: " << Fmt(FI.InlineInfo) << " bytes " + << Pct(FI.InlineInfo) << "\n"; + OS << " Call site info: " << Fmt(FI.CallSiteInfo) << " bytes " + << Pct(FI.CallSiteInfo) << "\n"; + OS << " End of list: " << Fmt(FI.EndOfList) << " bytes " + << Pct(FI.EndOfList) << "\n"; + OS << " Padding: " << Fmt(Padding) << " bytes " << Pct(Padding) + << "\n"; + OS << " Merged func info: " << Fmt(FI.MergedFuncInfo) << " bytes " + << Pct(FI.MergedFuncInfo) << "\n"; + OS << " InfoType/InfoLength/Count/FnSize: " + << Fmt(Merged.InfoTypeInfoLengthCountAndFnSize) << " bytes " + << Pct(Merged.InfoTypeInfoLengthCountAndFnSize) << "\n"; + OS << " Size and name: " << Fmt(Merged.SizeAndName) << " bytes " + << Pct(Merged.SizeAndName) << "\n"; + OS << " Line table info: " << Fmt(Merged.LineTableInfo) << " bytes " + << Pct(Merged.LineTableInfo) << "\n"; + OS << " Inline info: " << Fmt(Merged.InlineInfo) << " bytes " + << Pct(Merged.InlineInfo) << "\n"; + OS << " Call site info: " << Fmt(Merged.CallSiteInfo) << " bytes " + << Pct(Merged.CallSiteInfo) << "\n"; + OS << " Merged func info:" << Fmt(Merged.MergedFuncInfo) << " bytes " + << Pct(Merged.MergedFuncInfo) << "\n"; + OS << " End of list: " << Fmt(Merged.EndOfList) << " bytes " + << Pct(Merged.EndOfList) << "\n"; + OS << " Padding: " << Fmt(PaddingSize) << " bytes " + << Pct(PaddingSize) << "\n"; +} + void GsymReader::dump(raw_ostream &OS, const FunctionInfo &FI, uint32_t Indent) { OS.indent(Indent); diff --git a/llvm/tools/llvm-gsymutil/Opts.td b/llvm/tools/llvm-gsymutil/Opts.td index 2b211eec9a96d..02c5e43725c99 100644 --- a/llvm/tools/llvm-gsymutil/Opts.td +++ b/llvm/tools/llvm-gsymutil/Opts.td @@ -67,3 +67,11 @@ def benchmark_reader_all : Flag<["--"], "benchmark-reader">, HelpText<"Benchmark reader by looking up every address">, Flags<[HelpHidden]>; +def statistics_EQ : + Joined<["--"], "statistics=">, + HelpText<"Print the size of each section in the input GSYM file(s).\nFormat: text (default), json, or pretty-json">; +def statistics : + Flag<["--"], "statistics">, + Alias, + AliasArgs<["text"]>, + HelpText<"Alias for --statistics=text">; diff --git a/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp b/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp index d7572bc5cfe46..1d8668c429ccd 100644 --- a/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp +++ b/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp @@ -17,10 +17,12 @@ #include "llvm/Option/Option.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" #include "llvm/Support/JSON.h" #include "llvm/Support/LLVMDriver.h" #include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Regex.h" @@ -111,6 +113,8 @@ static std::string CallSiteYamlPath; static std::vector MergedFunctionsFilters; // Default output version. Can be overridden by --output-version. static uint32_t OutputVersion = Header::getVersion(); +static bool ShowStatistics; +static GsymReader::StatisticsFormat StatisticsFormat; static void parseArgs(int argc, char **argv) { GSYMUtilOptTable Tbl; @@ -238,6 +242,22 @@ static void parseArgs(int argc, char **argv) { LoadDwarfCallSites = Args.hasArg(OPT_dwarf_callsites); + ShowStatistics = Args.hasArg(OPT_statistics_EQ); + if (const llvm::opt::Arg *A = Args.getLastArg(OPT_statistics_EQ)) { + StringRef Val = A->getValue(); + if (Val == "" || Val == "text") + StatisticsFormat = GsymReader::StatisticsFormat::Text; + else if (Val == "json") + StatisticsFormat = GsymReader::StatisticsFormat::JSON; + else if (Val == "pretty-json") + StatisticsFormat = GsymReader::StatisticsFormat::PrettyJSON; + else { + errs() << "error: unknown statistics format '" << Val + << "'. Supported formats: text, json, pretty-json\n"; + std::exit(1); + } + } + for (const llvm::opt::Arg *A : Args.filtered(OPT_merged_functions_filter_EQ)) { MergedFunctionsFilters.push_back(A->getValue()); @@ -898,6 +918,11 @@ int llvm_gsymutil_main(int argc, char **argv, const llvm::ToolContext &) { if (!Gsym) error(GSYMPath, Gsym.takeError()); + if (ShowStatistics) { + (*Gsym)->dumpStatistics(OS, StatisticsFormat, GSYMPath); + continue; + } + if (LookupAddresses.empty()) { (*Gsym)->dump(outs()); continue; diff --git a/llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp b/llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp index 5808ae712efed..302db7b0700f5 100644 --- a/llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp +++ b/llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp @@ -27,6 +27,7 @@ #include "llvm/DebugInfo/GSYM/StringTable.h" #include "llvm/ObjectYAML/DWARFEmitter.h" #include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/JSON.h" #include "llvm/Testing/Support/Error.h" #include "gtest/gtest.h" @@ -5982,3 +5983,399 @@ TEST(GSYMTest, TestDWARFTypedefCycleDoesNotCrash) { const std::unique_ptr &GR = *GROrErr; EXPECT_EQ(GR->getNumAddresses(), 1u); } + +// The exact byte-size values dumpStatistics() should report for the canned +// DWARF below. They differ between v1 and v2 (e.g. wider addr-info offsets and +// string offsets in v2, and the v2-only GlobalData directory), so each version +// supplies its own set. Every value is fully determined by the YAML input. +struct ExpectedGsymStats { + uint64_t NumAddresses; + // byte-sizes (top level) + int64_t FileSize; + int64_t Header; + int64_t GlobalDataDirectory; + int64_t UUIDSection; + int64_t Padding; + int64_t AddressTable; + int64_t AddrInfoOffsets; + int64_t FileTable; + int64_t StringTable; + int64_t FunctionInfoData; + // function_info_type_sizes + int64_t FISizeAndName; + int64_t FILineTableInfo; + int64_t FIInlineInfo; + int64_t FICallSiteInfo; + int64_t FIMergedFuncInfo; + int64_t FIEndOfList; + int64_t FIPadding; + // merged_func_info_type_sizes + int64_t MInfoTypeInfoLengthCountAndFnSize; + int64_t MSizeAndName; + int64_t MLineTableInfo; + int64_t MInlineInfo; + int64_t MCallSiteInfo; + int64_t MMergedFuncInfo; + int64_t MEndOfList; +}; + +// Build a small GSYM from canned DWARF that exercises every statistics bucket - +// a function with a line table, inline info, a call site, a merged function, +// and a UUID - then exercise GsymReader::dumpStatistics() and verify that every +// reported byte size matches the exact value determined by the YAML input, and +// that the sizes account for every byte of the file exactly once at each +// nesting level. Works for both GSYM v1 and v2. +template +static void TestGsymStatistics(const ExpectedGsymStats &E) { + // A single compile unit with a function "main" that has a line table, one + // inlined subroutine ("inline1"), and a call site. A second subprogram + // ("dupfunc") shares main's address range so it gets folded into a merged + // function. A UUID is set on the creator further below. + StringRef yamldata = R"( + debug_str: + - '' + - /tmp/main.c + - main + - inline1 + - dupfunc + debug_abbrev: + - Table: + - Code: 0x00000001 + Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_strp + - Attribute: DW_AT_low_pc + Form: DW_FORM_addr + - Attribute: DW_AT_high_pc + Form: DW_FORM_data4 + - Attribute: DW_AT_language + Form: DW_FORM_data2 + - Attribute: DW_AT_stmt_list + Form: DW_FORM_sec_offset + - Code: 0x00000002 + Tag: DW_TAG_subprogram + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_strp + - Attribute: DW_AT_low_pc + Form: DW_FORM_addr + - Attribute: DW_AT_high_pc + Form: DW_FORM_data4 + - Code: 0x00000003 + Tag: DW_TAG_inlined_subroutine + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_strp + - Attribute: DW_AT_low_pc + Form: DW_FORM_addr + - Attribute: DW_AT_high_pc + Form: DW_FORM_data4 + - Attribute: DW_AT_call_file + Form: DW_FORM_data4 + - Attribute: DW_AT_call_line + Form: DW_FORM_data4 + - Code: 0x00000004 + Tag: DW_TAG_call_site + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_call_return_pc + Form: DW_FORM_addr + - Code: 0x00000005 + Tag: DW_TAG_subprogram + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_strp + - Attribute: DW_AT_low_pc + Form: DW_FORM_addr + - Attribute: DW_AT_high_pc + Form: DW_FORM_data4 + debug_info: + - Version: 4 + AddrSize: 8 + Entries: + - AbbrCode: 0x00000001 + Values: + - Value: 0x0000000000000001 + - Value: 0x0000000000001000 + - Value: 0x0000000000001000 + - Value: 0x0000000000000004 + - Value: 0x0000000000000000 + - AbbrCode: 0x00000002 + Values: + - Value: 0x000000000000000D + - Value: 0x0000000000001000 + - Value: 0x0000000000001000 + - AbbrCode: 0x00000003 + Values: + - Value: 0x0000000000000012 + - Value: 0x0000000000001100 + - Value: 0x0000000000000100 + - Value: 0x0000000000000001 + - Value: 0x000000000000000A + - AbbrCode: 0x00000004 + Values: + - Value: 0x0000000000001010 + - AbbrCode: 0x00000000 + - AbbrCode: 0x00000005 + Values: + - Value: 0x000000000000001A + - Value: 0x0000000000001000 + - Value: 0x0000000000001000 + - AbbrCode: 0x00000000 + debug_line: + - Length: 96 + Version: 2 + PrologueLength: 46 + MinInstLength: 1 + DefaultIsStmt: 1 + LineBase: 251 + LineRange: 14 + OpcodeBase: 13 + StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ] + IncludeDirs: + - /tmp + Files: + - Name: main.c + DirIdx: 1 + ModTime: 0 + Length: 0 + - Name: inline.h + DirIdx: 1 + ModTime: 0 + Length: 0 + Opcodes: + - Opcode: DW_LNS_extended_op + ExtLen: 9 + SubOpcode: DW_LNE_set_address + Data: 4096 + - Opcode: DW_LNS_advance_line + SData: 9 + Data: 4096 + - Opcode: DW_LNS_copy + Data: 4096 + - Opcode: DW_LNS_advance_pc + Data: 256 + - Opcode: DW_LNS_set_file + Data: 2 + - Opcode: DW_LNS_advance_line + SData: 10 + Data: 2 + - Opcode: DW_LNS_copy + Data: 2 + - Opcode: DW_LNS_advance_pc + Data: 128 + - Opcode: DW_LNS_advance_line + SData: 1 + Data: 128 + - Opcode: DW_LNS_copy + Data: 128 + - Opcode: DW_LNS_advance_pc + Data: 128 + - Opcode: DW_LNS_set_file + Data: 1 + - Opcode: DW_LNS_advance_line + SData: -10 + Data: 1 + - Opcode: DW_LNS_copy + Data: 1 + - Opcode: DW_LNS_advance_pc + Data: 3584 + - Opcode: DW_LNS_advance_line + SData: 1 + Data: 3584 + - Opcode: DW_LNS_extended_op + ExtLen: 1 + SubOpcode: DW_LNE_end_sequence + Data: 3584 + )"; + + // Create the gsym data + auto ErrOrSections = DWARFYAML::emitDebugSections(yamldata); + ASSERT_THAT_EXPECTED(ErrOrSections, Succeeded()); + std::unique_ptr DwarfContext = + DWARFContext::create(*ErrOrSections, 8); + ASSERT_TRUE(DwarfContext.get() != nullptr); + auto &OS = llvm::nulls(); + OutputAggregator OSAgg(&OS); + CreatorT GC; + // Give the GSYM a 16-byte UUID (only v2 stores this as a data section; v1 + // keeps it inline in the header). + const uint8_t UUIDBytes[16] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, + 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, + 0x76, 0x54, 0x32, 0x10}; + GC.setUUID(UUIDBytes); + // Load DW_TAG_call_site DIEs so the call-site bucket is populated. + DwarfTransformer DT(*DwarfContext, GC, /*LoadDwarfCallSites=*/true, + /*IsMachO=*/false); + ASSERT_THAT_ERROR(DT.convert(/*ThreadCount=*/1, OSAgg), Succeeded()); + // Fold same-range functions ("main" and "dupfunc") into a merged function. + GC.prepareMergedFunctions(OSAgg); + ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded()); + SmallString<512> Str; + raw_svector_ostream OutStrm(Str); + FileWriter FW(OutStrm, llvm::endianness::native); + FW.setStringOffsetSize(GC.getStringOffsetSize()); + ASSERT_THAT_ERROR(GC.encode(FW), Succeeded()); + + // Create a GsymReader to read the gsym data + auto GROrErr = GsymReader::copyBuffer(OutStrm.str()); + ASSERT_THAT_EXPECTED(GROrErr, Succeeded()); + const std::unique_ptr &GR = *GROrErr; + + // Dump statistics + const StringRef DisplayPath = "in-memory.gsym"; + std::string StatsStr; + raw_string_ostream StatsOS(StatsStr); + GR->dumpStatistics(StatsOS, GsymReader::StatisticsFormat::JSON, DisplayPath); + + // Get the JSON object which contains the statistics + auto ValOrErr = json::parse(StatsStr); + ASSERT_THAT_EXPECTED(ValOrErr, Succeeded()); + const json::Object *Root = ValOrErr->getAsObject(); + ASSERT_NE(Root, nullptr); + + // Top-level fields. The path is only a display label. + auto Path = Root->getString("path"); + ASSERT_TRUE(Path.has_value()); + EXPECT_EQ(*Path, DisplayPath); + // The UUID we set on the creator is reported the same way in v1 and v2. + auto UUID = Root->getString("uuid"); + ASSERT_TRUE(UUID.has_value()); + EXPECT_EQ(*UUID, "01234567-89AB-CDEF-FEDC-BA9876543210"); + auto NumAddrs = Root->getInteger("num_addresses"); + ASSERT_TRUE(NumAddrs.has_value()); + EXPECT_EQ(static_cast(*NumAddrs), GR->getNumAddresses()); + EXPECT_EQ(static_cast(*NumAddrs), E.NumAddresses); + + const json::Object *BS = Root->getObject("byte-sizes"); + ASSERT_NE(BS, nullptr); + const json::Object *FT = BS->getObject("function_info_type_sizes"); + ASSERT_NE(FT, nullptr); + const json::Object *MT = FT->getObject("merged_func_info_type_sizes"); + ASSERT_NE(MT, nullptr); + + // Assert an integer field is present and equals its expected value. + auto ExpectField = [](const json::Object *O, StringRef Key, + int64_t Expected) { + std::optional V = O->getInteger(Key); + ASSERT_TRUE(V.has_value()) << "missing field: " << Key.str(); + EXPECT_EQ(*V, Expected) << "field: " << Key.str(); + }; + + // Every field's exact value is determined by the canned YAML above. + ExpectField(BS, "file_size", E.FileSize); + ExpectField(BS, "header", E.Header); + ExpectField(BS, "global_data_directory", E.GlobalDataDirectory); + ExpectField(BS, "uuid_section", E.UUIDSection); + ExpectField(BS, "padding", E.Padding); + ExpectField(BS, "address_table", E.AddressTable); + ExpectField(BS, "addr_info_offsets", E.AddrInfoOffsets); + ExpectField(BS, "file_table", E.FileTable); + ExpectField(BS, "string_table", E.StringTable); + ExpectField(BS, "function_info_data", E.FunctionInfoData); + + ExpectField(FT, "size_and_name", E.FISizeAndName); + ExpectField(FT, "line_table_info", E.FILineTableInfo); + ExpectField(FT, "inline_info", E.FIInlineInfo); + ExpectField(FT, "call_site_info", E.FICallSiteInfo); + ExpectField(FT, "merged_func_info", E.FIMergedFuncInfo); + ExpectField(FT, "end_of_list", E.FIEndOfList); + ExpectField(FT, "padding", E.FIPadding); + + ExpectField(MT, "infotype_infolength_count_and_fnsize", + E.MInfoTypeInfoLengthCountAndFnSize); + ExpectField(MT, "size_and_name", E.MSizeAndName); + ExpectField(MT, "line_table_info", E.MLineTableInfo); + ExpectField(MT, "inline_info", E.MInlineInfo); + ExpectField(MT, "call_site_info", E.MCallSiteInfo); + ExpectField(MT, "merged_func_info", E.MMergedFuncInfo); + ExpectField(MT, "end_of_list", E.MEndOfList); + + // Cross-check the byte-to-byte completeness invariants hold at each level. + EXPECT_EQ(E.Header + E.GlobalDataDirectory + E.UUIDSection + E.Padding + + E.AddressTable + E.AddrInfoOffsets + E.FileTable + + E.StringTable + E.FunctionInfoData, + E.FileSize); + EXPECT_EQ(E.FISizeAndName + E.FILineTableInfo + E.FIInlineInfo + + E.FICallSiteInfo + E.FIMergedFuncInfo + E.FIEndOfList + + E.FIPadding, + E.FunctionInfoData); + EXPECT_EQ(E.MInfoTypeInfoLengthCountAndFnSize + E.MSizeAndName + + E.MLineTableInfo + E.MInlineInfo + E.MCallSiteInfo + + E.MMergedFuncInfo + E.MEndOfList, + E.FIMergedFuncInfo); + + // The text and pretty-JSON formats must not crash on the same input. + GR->dumpStatistics(OS, GsymReader::StatisticsFormat::Text, DisplayPath); + GR->dumpStatistics(OS, GsymReader::StatisticsFormat::PrettyJSON, DisplayPath); +} + +TEST(GSYMTest, TestGsymStatisticsV1) { + // "main" (line table + inline + call site) is folded into a merged function + // behind "dupfunc", so the inline/call-site bytes appear in the merged + // breakdown; v1 stores the UUID inline in the header (uuid_section == 0). + ExpectedGsymStats E = {}; + E.NumAddresses = 1; // one address (0x1000); main+dupfunc share it + E.FileSize = 297; // = sum of all byte-size fields below + E.Header = 48; // fixed V1 header struct (incl. inline UUID[20]) + E.GlobalDataDirectory = 0; // v1 has no on-disk GlobalData directory + E.UUIDSection = 0; // v1 keeps the UUID inline in the header + E.Padding = 3; // inter-section alignment (remainder to file_size) + E.AddressTable = 1; // 1 addr * 1-byte addr offset + E.AddrInfoOffsets = 4; // 1 addr * 4-byte (32-bit) info offset + E.FileTable = 28; // u32 count + 3 entries * 2 strp(4B) + E.StringTable = 43; // unique names+files+dirs; same bytes in v1/v2 + E.FunctionInfoData = 170; // the one top-level FunctionInfo (FT fields below) + E.FISizeAndName = 8; // Size(u32=4) + name strp(4B) + E.FILineTableInfo = 32; // LineTable TLV: 8B type+length hdr + 24B payload + E.FIInlineInfo = 0; // main's inline moved into the merged inner (MT) + E.FICallSiteInfo = 0; // main's call site moved into the merged inner (MT) + E.FIMergedFuncInfo = 121; // MergedFunctionsInfo TLV holding main (MT fields) + E.FIEndOfList = 8; // terminator TLV: InfoType(0,4B) + InfoLength(0,4B) + E.FIPadding = 1; // pad the top-level FunctionInfo to a 4B boundary + E.MInfoTypeInfoLengthCountAndFnSize = 16; // TLV hdr(8)+Count(4)+1*FnSize(4) + E.MSizeAndName = 8; // inner func: Size(4) + name strp(4B) + E.MLineTableInfo = 32; // inner LineTable TLV: 8B hdr + 24B payload + E.MInlineInfo = 32; // inner InlineInfo TLV: 8B hdr + 24B payload + E.MCallSiteInfo = 25; // CallSite TLV: 8B hdr + 1 site, no regex + E.MMergedFuncInfo = 0; // the inner function has no further merged functions + E.MEndOfList = 8; // inner func terminator TLV (4B + 4B) + TestGsymStatistics(E); +} + +TEST(GSYMTest, TestGsymStatisticsV2) { + // Same as above, but v2 stores the UUID as its own 16-byte data section + // (uuid_section == 16) and has an on-disk GlobalData directory. + ExpectedGsymStats E = {}; + E.NumAddresses = 1; // one address (0x1000); main+dupfunc share it + E.FileSize = 473; // = sum of all byte-size fields below + E.Header = 20; // fixed HeaderV2 struct + E.GlobalDataDirectory = 140; // 7 entries * 20B: 5 sections + UUID + EndOfList + E.UUIDSection = 16; // v2 stores the 16-byte UUID as its own section + E.Padding = 8; // inter-section alignment (remainder to file_size) + E.AddressTable = 1; // 1 addr * 1-byte addr offset + E.AddrInfoOffsets = 8; // 1 addr * 8-byte (64-bit) info offset + E.FileTable = 52; // u32 count + 3 entries * 2 strp(8B) + E.StringTable = 43; // same strings as v1 (content is version-independent) + E.FunctionInfoData = 185; // the one top-level FunctionInfo (FT fields below) + E.FISizeAndName = 12; // Size(u32=4) + name strp(8B) + E.FILineTableInfo = 32; // LineTable TLV: 8B hdr + 24B payload (no strps) + E.FIInlineInfo = 0; // main's inline moved into the merged inner (MT) + E.FICallSiteInfo = 0; // main's call site moved into the merged inner (MT) + E.FIMergedFuncInfo = 133; // MergedFunctionsInfo TLV holding main (MT fields) + E.FIEndOfList = 8; // terminator TLV: InfoType(0,4B) + InfoLength(0,4B) + E.FIPadding = 0; // top-level FunctionInfo already 4B aligned + E.MInfoTypeInfoLengthCountAndFnSize = 16; // TLV hdr(8)+Count(4)+1*FnSize(4) + E.MSizeAndName = 12; // inner func: Size(4) + name strp(8B) + E.MLineTableInfo = 32; // inner LineTable TLV: 8B hdr + 24B payload + E.MInlineInfo = 40; // inner InlineInfo TLV; +8B vs v1 (8B string offsets) + E.MCallSiteInfo = 25; // CallSite TLV; version-independent (no match regex) + E.MMergedFuncInfo = 0; // the inner function has no further merged functions + E.MEndOfList = 8; // inner func terminator TLV (4B + 4B) + TestGsymStatistics(E); +} From a43296488ed34006f3201a258e712ae01fe63214 Mon Sep 17 00:00:00 2001 From: Dmitry Sidorov Date: Fri, 7 Aug 2026 02:51:44 +0200 Subject: [PATCH 028/789] [AMDGPU] Fix sign of zero in fpround(fmul) -> V_{MAD,FMA}_MIX{LO,HI} (#214544) The isel patterns lowering `fptrunc (fmul float %a, %b)` to a mix instruction passed +0.0 as the FMA addend. Under round-to-nearest fma(a, b, +0.0) is +0.0 whenever a * b is -0.0, so the sign of zero was lost: on gfx90a, `(half)(-1.0f * 0.0f)` returned +0.0. Use a -0.0 addend instead, which is the correct multiplicative identity for an FMA and is what the f32 sibling pattern in MadFmaMixFP32Pats has always done. Verified on gfx90a: (half)(-1.0f * 0.0f) now returns 0x8000. --- llvm/lib/Target/AMDGPU/VOP3PInstructions.td | 6 +- llvm/test/CodeGen/AMDGPU/llvm.log.ll | 152 ++++++++++---------- llvm/test/CodeGen/AMDGPU/llvm.log10.ll | 152 ++++++++++---------- llvm/test/CodeGen/AMDGPU/mad-mix-lo-bf16.ll | 8 +- llvm/test/CodeGen/AMDGPU/mad-mix-lo.ll | 22 +-- 5 files changed, 170 insertions(+), 170 deletions(-) diff --git a/llvm/lib/Target/AMDGPU/VOP3PInstructions.td b/llvm/lib/Target/AMDGPU/VOP3PInstructions.td index b4021b411bc37..6af74a3a7e1c4 100644 --- a/llvm/lib/Target/AMDGPU/VOP3PInstructions.td +++ b/llvm/lib/Target/AMDGPU/VOP3PInstructions.td @@ -330,7 +330,7 @@ multiclass MadFmaMixFP16Pats; @@ -340,7 +340,7 @@ multiclass MadFmaMixFP16Pats; @@ -394,7 +394,7 @@ multiclass MadFmaMixFP16Pats_t16; diff --git a/llvm/test/CodeGen/AMDGPU/llvm.log.ll b/llvm/test/CodeGen/AMDGPU/llvm.log.ll index a5894a0761d49..ee51803a1df50 100644 --- a/llvm/test/CodeGen/AMDGPU/llvm.log.ll +++ b/llvm/test/CodeGen/AMDGPU/llvm.log.ll @@ -6675,7 +6675,7 @@ define half @v_log_f16(half %in) { ; GFX1100-SDAG-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_1) ; GFX1100-SDAG-TRUE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-SDAG-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, 0 +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, neg(0) ; GFX1100-SDAG-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-SDAG-FAKE16-LABEL: v_log_f16: @@ -6686,7 +6686,7 @@ define half @v_log_f16(half %in) { ; GFX1100-SDAG-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) ; GFX1100-SDAG-FAKE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-SDAG-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, 0 +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, neg(0) ; GFX1100-SDAG-FAKE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-TRUE16-LABEL: v_log_f16: @@ -6697,7 +6697,7 @@ define half @v_log_f16(half %in) { ; GFX1100-GISEL-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_2) ; GFX1100-GISEL-TRUE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-GISEL-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, v1, 0 +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, v1, neg(0) ; GFX1100-GISEL-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-FAKE16-LABEL: v_log_f16: @@ -6708,7 +6708,7 @@ define half @v_log_f16(half %in) { ; GFX1100-GISEL-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_2) ; GFX1100-GISEL-FAKE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-GISEL-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v1, 0 +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v1, neg(0) ; GFX1100-GISEL-FAKE16-NEXT: s_setpc_b64 s[30:31] ; ; R600-LABEL: v_log_f16: @@ -6742,7 +6742,7 @@ define half @v_log_fabs_f16(half %in) { ; GFX1100-SDAG-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_1) ; GFX1100-SDAG-TRUE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-SDAG-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, 0 +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, neg(0) ; GFX1100-SDAG-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-SDAG-FAKE16-LABEL: v_log_fabs_f16: @@ -6753,7 +6753,7 @@ define half @v_log_fabs_f16(half %in) { ; GFX1100-SDAG-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) ; GFX1100-SDAG-FAKE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-SDAG-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, 0 +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, neg(0) ; GFX1100-SDAG-FAKE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-TRUE16-LABEL: v_log_fabs_f16: @@ -6764,7 +6764,7 @@ define half @v_log_fabs_f16(half %in) { ; GFX1100-GISEL-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_2) ; GFX1100-GISEL-TRUE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-GISEL-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, v1, 0 +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, v1, neg(0) ; GFX1100-GISEL-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-FAKE16-LABEL: v_log_fabs_f16: @@ -6775,7 +6775,7 @@ define half @v_log_fabs_f16(half %in) { ; GFX1100-GISEL-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_2) ; GFX1100-GISEL-FAKE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-GISEL-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v1, 0 +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v1, neg(0) ; GFX1100-GISEL-FAKE16-NEXT: s_setpc_b64 s[30:31] ; ; R600-LABEL: v_log_fabs_f16: @@ -6810,7 +6810,7 @@ define half @v_log_fneg_fabs_f16(half %in) { ; GFX1100-SDAG-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_1) ; GFX1100-SDAG-TRUE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-SDAG-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, 0 +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, neg(0) ; GFX1100-SDAG-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-SDAG-FAKE16-LABEL: v_log_fneg_fabs_f16: @@ -6821,7 +6821,7 @@ define half @v_log_fneg_fabs_f16(half %in) { ; GFX1100-SDAG-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) ; GFX1100-SDAG-FAKE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-SDAG-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, 0 +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, neg(0) ; GFX1100-SDAG-FAKE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-TRUE16-LABEL: v_log_fneg_fabs_f16: @@ -6832,7 +6832,7 @@ define half @v_log_fneg_fabs_f16(half %in) { ; GFX1100-GISEL-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_2) ; GFX1100-GISEL-TRUE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-GISEL-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, v1, 0 +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, v1, neg(0) ; GFX1100-GISEL-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-FAKE16-LABEL: v_log_fneg_fabs_f16: @@ -6843,7 +6843,7 @@ define half @v_log_fneg_fabs_f16(half %in) { ; GFX1100-GISEL-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_2) ; GFX1100-GISEL-FAKE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-GISEL-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v1, 0 +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v1, neg(0) ; GFX1100-GISEL-FAKE16-NEXT: s_setpc_b64 s[30:31] ; ; R600-LABEL: v_log_fneg_fabs_f16: @@ -6879,7 +6879,7 @@ define half @v_log_fneg_f16(half %in) { ; GFX1100-SDAG-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_1) ; GFX1100-SDAG-TRUE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-SDAG-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, 0 +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, neg(0) ; GFX1100-SDAG-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-SDAG-FAKE16-LABEL: v_log_fneg_f16: @@ -6890,7 +6890,7 @@ define half @v_log_fneg_f16(half %in) { ; GFX1100-SDAG-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) ; GFX1100-SDAG-FAKE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-SDAG-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, 0 +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, neg(0) ; GFX1100-SDAG-FAKE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-TRUE16-LABEL: v_log_fneg_f16: @@ -6901,7 +6901,7 @@ define half @v_log_fneg_f16(half %in) { ; GFX1100-GISEL-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_2) ; GFX1100-GISEL-TRUE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-GISEL-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, v1, 0 +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, v1, neg(0) ; GFX1100-GISEL-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-FAKE16-LABEL: v_log_fneg_f16: @@ -6912,7 +6912,7 @@ define half @v_log_fneg_f16(half %in) { ; GFX1100-GISEL-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_2) ; GFX1100-GISEL-FAKE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-GISEL-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v1, 0 +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v1, neg(0) ; GFX1100-GISEL-FAKE16-NEXT: s_setpc_b64 s[30:31] ; ; R600-LABEL: v_log_fneg_f16: @@ -7158,8 +7158,8 @@ define <2 x half> @v_log_v2f16(<2 x half> %in) { ; GFX1100-SDAG-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_1) ; GFX1100-SDAG-TRUE16-NEXT: v_log_f32_e32 v1, v1 ; GFX1100-SDAG-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, 0 -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixhi_f16 v0, v1, s0, 0 +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, neg(0) +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixhi_f16 v0, v1, s0, neg(0) ; GFX1100-SDAG-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-SDAG-FAKE16-LABEL: v_log_v2f16: @@ -7174,8 +7174,8 @@ define <2 x half> @v_log_v2f16(<2 x half> %in) { ; GFX1100-SDAG-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(SKIP_2) | instid1(VALU_DEP_1) ; GFX1100-SDAG-FAKE16-NEXT: v_log_f32_e32 v2, v0 ; GFX1100-SDAG-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v1, s0, 0 -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixhi_f16 v0, v2, s0, 0 +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v1, s0, neg(0) +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixhi_f16 v0, v2, s0, neg(0) ; GFX1100-SDAG-FAKE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-TRUE16-LABEL: v_log_v2f16: @@ -7188,8 +7188,8 @@ define <2 x half> @v_log_v2f16(<2 x half> %in) { ; GFX1100-GISEL-TRUE16-NEXT: v_log_f32_e32 v1, v1 ; GFX1100-GISEL-TRUE16-NEXT: v_log_f32_e32 v2, v0 ; GFX1100-GISEL-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v1, v3, 0 -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixhi_f16 v0, v2, v3, 0 +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v1, v3, neg(0) +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixhi_f16 v0, v2, v3, neg(0) ; GFX1100-GISEL-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-FAKE16-LABEL: v_log_v2f16: @@ -7204,8 +7204,8 @@ define <2 x half> @v_log_v2f16(<2 x half> %in) { ; GFX1100-GISEL-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(SKIP_3) | instid1(VALU_DEP_1) ; GFX1100-GISEL-FAKE16-NEXT: v_log_f32_e32 v1, v1 ; GFX1100-GISEL-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v2, 0 -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v1, v1, v2, 0 +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v2, neg(0) +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v1, v1, v2, neg(0) ; GFX1100-GISEL-FAKE16-NEXT: v_pack_b32_f16 v0, v0, v1 ; GFX1100-GISEL-FAKE16-NEXT: s_setpc_b64 s[30:31] ; @@ -7330,8 +7330,8 @@ define <2 x half> @v_log_fabs_v2f16(<2 x half> %in) { ; GFX1100-SDAG-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_1) ; GFX1100-SDAG-TRUE16-NEXT: v_log_f32_e32 v1, v1 ; GFX1100-SDAG-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, 0 -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixhi_f16 v0, v1, s0, 0 +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, neg(0) +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixhi_f16 v0, v1, s0, neg(0) ; GFX1100-SDAG-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-SDAG-FAKE16-LABEL: v_log_fabs_v2f16: @@ -7346,8 +7346,8 @@ define <2 x half> @v_log_fabs_v2f16(<2 x half> %in) { ; GFX1100-SDAG-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(SKIP_2) | instid1(VALU_DEP_1) ; GFX1100-SDAG-FAKE16-NEXT: v_log_f32_e32 v2, v0 ; GFX1100-SDAG-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v1, s0, 0 -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixhi_f16 v0, v2, s0, 0 +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v1, s0, neg(0) +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixhi_f16 v0, v2, s0, neg(0) ; GFX1100-SDAG-FAKE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-TRUE16-LABEL: v_log_fabs_v2f16: @@ -7362,8 +7362,8 @@ define <2 x half> @v_log_fabs_v2f16(<2 x half> %in) { ; GFX1100-GISEL-TRUE16-NEXT: v_log_f32_e32 v1, v1 ; GFX1100-GISEL-TRUE16-NEXT: v_log_f32_e32 v2, v0 ; GFX1100-GISEL-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v1, v3, 0 -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixhi_f16 v0, v2, v3, 0 +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v1, v3, neg(0) +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixhi_f16 v0, v2, v3, neg(0) ; GFX1100-GISEL-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-FAKE16-LABEL: v_log_fabs_v2f16: @@ -7379,8 +7379,8 @@ define <2 x half> @v_log_fabs_v2f16(<2 x half> %in) { ; GFX1100-GISEL-FAKE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-GISEL-FAKE16-NEXT: v_log_f32_e32 v1, v1 ; GFX1100-GISEL-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v2, 0 -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v1, v1, v2, 0 +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v2, neg(0) +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v1, v1, v2, neg(0) ; GFX1100-GISEL-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) ; GFX1100-GISEL-FAKE16-NEXT: v_pack_b32_f16 v0, v0, v1 ; GFX1100-GISEL-FAKE16-NEXT: s_setpc_b64 s[30:31] @@ -7508,8 +7508,8 @@ define <2 x half> @v_log_fneg_fabs_v2f16(<2 x half> %in) { ; GFX1100-SDAG-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_1) ; GFX1100-SDAG-TRUE16-NEXT: v_log_f32_e32 v1, v1 ; GFX1100-SDAG-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, 0 -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixhi_f16 v0, v1, s0, 0 +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, neg(0) +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixhi_f16 v0, v1, s0, neg(0) ; GFX1100-SDAG-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-SDAG-FAKE16-LABEL: v_log_fneg_fabs_v2f16: @@ -7524,8 +7524,8 @@ define <2 x half> @v_log_fneg_fabs_v2f16(<2 x half> %in) { ; GFX1100-SDAG-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(SKIP_2) | instid1(VALU_DEP_1) ; GFX1100-SDAG-FAKE16-NEXT: v_log_f32_e32 v2, v0 ; GFX1100-SDAG-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v1, s0, 0 -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixhi_f16 v0, v2, s0, 0 +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v1, s0, neg(0) +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixhi_f16 v0, v2, s0, neg(0) ; GFX1100-SDAG-FAKE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-TRUE16-LABEL: v_log_fneg_fabs_v2f16: @@ -7540,8 +7540,8 @@ define <2 x half> @v_log_fneg_fabs_v2f16(<2 x half> %in) { ; GFX1100-GISEL-TRUE16-NEXT: v_log_f32_e32 v1, v1 ; GFX1100-GISEL-TRUE16-NEXT: v_log_f32_e32 v2, v0 ; GFX1100-GISEL-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v1, v3, 0 -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixhi_f16 v0, v2, v3, 0 +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v1, v3, neg(0) +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixhi_f16 v0, v2, v3, neg(0) ; GFX1100-GISEL-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-FAKE16-LABEL: v_log_fneg_fabs_v2f16: @@ -7557,8 +7557,8 @@ define <2 x half> @v_log_fneg_fabs_v2f16(<2 x half> %in) { ; GFX1100-GISEL-FAKE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-GISEL-FAKE16-NEXT: v_log_f32_e32 v1, v1 ; GFX1100-GISEL-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v2, 0 -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v1, v1, v2, 0 +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v2, neg(0) +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v1, v1, v2, neg(0) ; GFX1100-GISEL-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) ; GFX1100-GISEL-FAKE16-NEXT: v_pack_b32_f16 v0, v0, v1 ; GFX1100-GISEL-FAKE16-NEXT: s_setpc_b64 s[30:31] @@ -7687,8 +7687,8 @@ define <2 x half> @v_log_fneg_v2f16(<2 x half> %in) { ; GFX1100-SDAG-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_1) ; GFX1100-SDAG-TRUE16-NEXT: v_log_f32_e32 v1, v1 ; GFX1100-SDAG-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, 0 -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixhi_f16 v0, v1, s0, 0 +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, neg(0) +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixhi_f16 v0, v1, s0, neg(0) ; GFX1100-SDAG-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-SDAG-FAKE16-LABEL: v_log_fneg_v2f16: @@ -7703,8 +7703,8 @@ define <2 x half> @v_log_fneg_v2f16(<2 x half> %in) { ; GFX1100-SDAG-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(SKIP_2) | instid1(VALU_DEP_1) ; GFX1100-SDAG-FAKE16-NEXT: v_log_f32_e32 v2, v0 ; GFX1100-SDAG-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v1, s0, 0 -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixhi_f16 v0, v2, s0, 0 +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v1, s0, neg(0) +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixhi_f16 v0, v2, s0, neg(0) ; GFX1100-SDAG-FAKE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-TRUE16-LABEL: v_log_fneg_v2f16: @@ -7719,8 +7719,8 @@ define <2 x half> @v_log_fneg_v2f16(<2 x half> %in) { ; GFX1100-GISEL-TRUE16-NEXT: v_log_f32_e32 v1, v1 ; GFX1100-GISEL-TRUE16-NEXT: v_log_f32_e32 v2, v0 ; GFX1100-GISEL-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v1, v3, 0 -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixhi_f16 v0, v2, v3, 0 +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v1, v3, neg(0) +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixhi_f16 v0, v2, v3, neg(0) ; GFX1100-GISEL-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-FAKE16-LABEL: v_log_fneg_v2f16: @@ -7736,8 +7736,8 @@ define <2 x half> @v_log_fneg_v2f16(<2 x half> %in) { ; GFX1100-GISEL-FAKE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-GISEL-FAKE16-NEXT: v_log_f32_e32 v1, v1 ; GFX1100-GISEL-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v2, 0 -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v1, v1, v2, 0 +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v2, neg(0) +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v1, v1, v2, neg(0) ; GFX1100-GISEL-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) ; GFX1100-GISEL-FAKE16-NEXT: v_pack_b32_f16 v0, v0, v1 ; GFX1100-GISEL-FAKE16-NEXT: s_setpc_b64 s[30:31] @@ -8019,10 +8019,10 @@ define <3 x half> @v_log_v3f16(<3 x half> %in) { ; GFX1100-SDAG-TRUE16-NEXT: v_log_f32_e32 v1, v1 ; GFX1100-SDAG-TRUE16-NEXT: v_log_f32_e32 v2, v2 ; GFX1100-SDAG-TRUE16-NEXT: s_delay_alu instid0(TRANS32_DEP_3) -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, 0 +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, neg(0) ; GFX1100-SDAG-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v1, v1, s0, 0 -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixhi_f16 v0, v2, s0, 0 +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v1, v1, s0, neg(0) +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixhi_f16 v0, v2, s0, neg(0) ; GFX1100-SDAG-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-SDAG-FAKE16-LABEL: v_log_v3f16: @@ -8039,10 +8039,10 @@ define <3 x half> @v_log_v3f16(<3 x half> %in) { ; GFX1100-SDAG-FAKE16-NEXT: v_log_f32_e32 v1, v1 ; GFX1100-SDAG-FAKE16-NEXT: v_log_f32_e32 v3, v0 ; GFX1100-SDAG-FAKE16-NEXT: s_delay_alu instid0(TRANS32_DEP_3) -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v2, s0, 0 +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v2, s0, neg(0) ; GFX1100-SDAG-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v1, v1, s0, 0 -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixhi_f16 v0, v3, s0, 0 +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v1, v1, s0, neg(0) +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixhi_f16 v0, v3, s0, neg(0) ; GFX1100-SDAG-FAKE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-TRUE16-LABEL: v_log_v3f16: @@ -8057,10 +8057,10 @@ define <3 x half> @v_log_v3f16(<3 x half> %in) { ; GFX1100-GISEL-TRUE16-NEXT: v_log_f32_e32 v3, v0 ; GFX1100-GISEL-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(TRANS32_DEP_3) ; GFX1100-GISEL-TRUE16-NEXT: v_log_f32_e32 v1, v1 -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v2, v4, 0 +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v2, v4, neg(0) ; GFX1100-GISEL-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixhi_f16 v0, v3, v4, 0 -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v1, v1, v4, 0 +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixhi_f16 v0, v3, v4, neg(0) +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v1, v1, v4, neg(0) ; GFX1100-GISEL-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-FAKE16-LABEL: v_log_v3f16: @@ -8077,10 +8077,10 @@ define <3 x half> @v_log_v3f16(<3 x half> %in) { ; GFX1100-GISEL-FAKE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-GISEL-FAKE16-NEXT: v_log_f32_e32 v2, v2 ; GFX1100-GISEL-FAKE16-NEXT: s_delay_alu instid0(TRANS32_DEP_3) | instskip(SKIP_4) | instid1(VALU_DEP_2) -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v1, v1, v3, 0 +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v1, v1, v3, neg(0) ; GFX1100-GISEL-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v3, 0 -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v2, v2, v3, 0 +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v3, neg(0) +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v2, v2, v3, neg(0) ; GFX1100-GISEL-FAKE16-NEXT: v_and_b32_e32 v1, 0xffff, v1 ; GFX1100-GISEL-FAKE16-NEXT: v_pack_b32_f16 v0, v0, v2 ; GFX1100-GISEL-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_2) @@ -8440,12 +8440,12 @@ define <4 x half> @v_log_v4f16(<4 x half> %in) { ; GFX1100-SDAG-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_1) ; GFX1100-SDAG-TRUE16-NEXT: v_log_f32_e32 v2, v2 ; GFX1100-SDAG-TRUE16-NEXT: v_log_f32_e32 v3, v3 -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v1, v1, s0, 0 +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v1, v1, s0, neg(0) ; GFX1100-SDAG-TRUE16-NEXT: s_delay_alu instid0(TRANS32_DEP_3) -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, 0 +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, neg(0) ; GFX1100-SDAG-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixhi_f16 v0, v2, s0, 0 -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixhi_f16 v1, v3, s0, 0 +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixhi_f16 v0, v2, s0, neg(0) +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixhi_f16 v1, v3, s0, neg(0) ; GFX1100-SDAG-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-SDAG-FAKE16-LABEL: v_log_v4f16: @@ -8463,12 +8463,12 @@ define <4 x half> @v_log_v4f16(<4 x half> %in) { ; GFX1100-SDAG-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_1) ; GFX1100-SDAG-FAKE16-NEXT: v_log_f32_e32 v4, v0 ; GFX1100-SDAG-FAKE16-NEXT: v_log_f32_e32 v5, v1 -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v1, v2, s0, 0 +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v1, v2, s0, neg(0) ; GFX1100-SDAG-FAKE16-NEXT: s_delay_alu instid0(TRANS32_DEP_3) -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v3, s0, 0 +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v3, s0, neg(0) ; GFX1100-SDAG-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixhi_f16 v0, v4, s0, 0 -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixhi_f16 v1, v5, s0, 0 +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixhi_f16 v0, v4, s0, neg(0) +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixhi_f16 v1, v5, s0, neg(0) ; GFX1100-SDAG-FAKE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-TRUE16-LABEL: v_log_v4f16: @@ -8483,12 +8483,12 @@ define <4 x half> @v_log_v4f16(<4 x half> %in) { ; GFX1100-GISEL-TRUE16-NEXT: v_log_f32_e32 v4, v0 ; GFX1100-GISEL-TRUE16-NEXT: v_log_f32_e32 v3, v3 ; GFX1100-GISEL-TRUE16-NEXT: v_log_f32_e32 v5, v1 -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v2, v6, 0 +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v2, v6, neg(0) ; GFX1100-GISEL-TRUE16-NEXT: s_delay_alu instid0(TRANS32_DEP_3) -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixhi_f16 v0, v4, v6, 0 +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixhi_f16 v0, v4, v6, neg(0) ; GFX1100-GISEL-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v1, v3, v6, 0 -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixhi_f16 v1, v5, v6, 0 +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v1, v3, v6, neg(0) +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixhi_f16 v1, v5, v6, neg(0) ; GFX1100-GISEL-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-FAKE16-LABEL: v_log_v4f16: @@ -8506,12 +8506,12 @@ define <4 x half> @v_log_v4f16(<4 x half> %in) { ; GFX1100-GISEL-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_1) ; GFX1100-GISEL-FAKE16-NEXT: v_log_f32_e32 v2, v2 ; GFX1100-GISEL-FAKE16-NEXT: v_log_f32_e32 v3, v3 -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v4, 0 +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v4, neg(0) ; GFX1100-GISEL-FAKE16-NEXT: s_delay_alu instid0(TRANS32_DEP_3) | instskip(SKIP_3) | instid1(VALU_DEP_2) -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v1, v1, v4, 0 +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v1, v1, v4, neg(0) ; GFX1100-GISEL-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v2, v2, v4, 0 -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v3, v3, v4, 0 +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v2, v2, v4, neg(0) +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v3, v3, v4, neg(0) ; GFX1100-GISEL-FAKE16-NEXT: v_pack_b32_f16 v0, v0, v2 ; GFX1100-GISEL-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_2) ; GFX1100-GISEL-FAKE16-NEXT: v_pack_b32_f16 v1, v1, v3 diff --git a/llvm/test/CodeGen/AMDGPU/llvm.log10.ll b/llvm/test/CodeGen/AMDGPU/llvm.log10.ll index 44ceab1728db2..81e165d0e5972 100644 --- a/llvm/test/CodeGen/AMDGPU/llvm.log10.ll +++ b/llvm/test/CodeGen/AMDGPU/llvm.log10.ll @@ -6675,7 +6675,7 @@ define half @v_log10_f16(half %in) { ; GFX1100-SDAG-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_1) ; GFX1100-SDAG-TRUE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-SDAG-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, 0 +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, neg(0) ; GFX1100-SDAG-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-SDAG-FAKE16-LABEL: v_log10_f16: @@ -6686,7 +6686,7 @@ define half @v_log10_f16(half %in) { ; GFX1100-SDAG-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) ; GFX1100-SDAG-FAKE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-SDAG-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, 0 +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, neg(0) ; GFX1100-SDAG-FAKE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-TRUE16-LABEL: v_log10_f16: @@ -6697,7 +6697,7 @@ define half @v_log10_f16(half %in) { ; GFX1100-GISEL-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_2) ; GFX1100-GISEL-TRUE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-GISEL-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, v1, 0 +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, v1, neg(0) ; GFX1100-GISEL-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-FAKE16-LABEL: v_log10_f16: @@ -6708,7 +6708,7 @@ define half @v_log10_f16(half %in) { ; GFX1100-GISEL-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_2) ; GFX1100-GISEL-FAKE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-GISEL-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v1, 0 +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v1, neg(0) ; GFX1100-GISEL-FAKE16-NEXT: s_setpc_b64 s[30:31] ; ; R600-LABEL: v_log10_f16: @@ -6742,7 +6742,7 @@ define half @v_log10_fabs_f16(half %in) { ; GFX1100-SDAG-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_1) ; GFX1100-SDAG-TRUE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-SDAG-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, 0 +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, neg(0) ; GFX1100-SDAG-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-SDAG-FAKE16-LABEL: v_log10_fabs_f16: @@ -6753,7 +6753,7 @@ define half @v_log10_fabs_f16(half %in) { ; GFX1100-SDAG-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) ; GFX1100-SDAG-FAKE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-SDAG-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, 0 +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, neg(0) ; GFX1100-SDAG-FAKE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-TRUE16-LABEL: v_log10_fabs_f16: @@ -6764,7 +6764,7 @@ define half @v_log10_fabs_f16(half %in) { ; GFX1100-GISEL-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_2) ; GFX1100-GISEL-TRUE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-GISEL-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, v1, 0 +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, v1, neg(0) ; GFX1100-GISEL-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-FAKE16-LABEL: v_log10_fabs_f16: @@ -6775,7 +6775,7 @@ define half @v_log10_fabs_f16(half %in) { ; GFX1100-GISEL-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_2) ; GFX1100-GISEL-FAKE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-GISEL-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v1, 0 +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v1, neg(0) ; GFX1100-GISEL-FAKE16-NEXT: s_setpc_b64 s[30:31] ; ; R600-LABEL: v_log10_fabs_f16: @@ -6810,7 +6810,7 @@ define half @v_log10_fneg_fabs_f16(half %in) { ; GFX1100-SDAG-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_1) ; GFX1100-SDAG-TRUE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-SDAG-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, 0 +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, neg(0) ; GFX1100-SDAG-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-SDAG-FAKE16-LABEL: v_log10_fneg_fabs_f16: @@ -6821,7 +6821,7 @@ define half @v_log10_fneg_fabs_f16(half %in) { ; GFX1100-SDAG-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) ; GFX1100-SDAG-FAKE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-SDAG-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, 0 +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, neg(0) ; GFX1100-SDAG-FAKE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-TRUE16-LABEL: v_log10_fneg_fabs_f16: @@ -6832,7 +6832,7 @@ define half @v_log10_fneg_fabs_f16(half %in) { ; GFX1100-GISEL-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_2) ; GFX1100-GISEL-TRUE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-GISEL-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, v1, 0 +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, v1, neg(0) ; GFX1100-GISEL-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-FAKE16-LABEL: v_log10_fneg_fabs_f16: @@ -6843,7 +6843,7 @@ define half @v_log10_fneg_fabs_f16(half %in) { ; GFX1100-GISEL-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_2) ; GFX1100-GISEL-FAKE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-GISEL-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v1, 0 +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v1, neg(0) ; GFX1100-GISEL-FAKE16-NEXT: s_setpc_b64 s[30:31] ; ; R600-LABEL: v_log10_fneg_fabs_f16: @@ -6879,7 +6879,7 @@ define half @v_log10_fneg_f16(half %in) { ; GFX1100-SDAG-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_1) ; GFX1100-SDAG-TRUE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-SDAG-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, 0 +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, neg(0) ; GFX1100-SDAG-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-SDAG-FAKE16-LABEL: v_log10_fneg_f16: @@ -6890,7 +6890,7 @@ define half @v_log10_fneg_f16(half %in) { ; GFX1100-SDAG-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) ; GFX1100-SDAG-FAKE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-SDAG-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, 0 +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, neg(0) ; GFX1100-SDAG-FAKE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-TRUE16-LABEL: v_log10_fneg_f16: @@ -6901,7 +6901,7 @@ define half @v_log10_fneg_f16(half %in) { ; GFX1100-GISEL-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_2) ; GFX1100-GISEL-TRUE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-GISEL-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, v1, 0 +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, v1, neg(0) ; GFX1100-GISEL-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-FAKE16-LABEL: v_log10_fneg_f16: @@ -6912,7 +6912,7 @@ define half @v_log10_fneg_f16(half %in) { ; GFX1100-GISEL-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_2) ; GFX1100-GISEL-FAKE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-GISEL-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v1, 0 +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v1, neg(0) ; GFX1100-GISEL-FAKE16-NEXT: s_setpc_b64 s[30:31] ; ; R600-LABEL: v_log10_fneg_f16: @@ -7158,8 +7158,8 @@ define <2 x half> @v_log10_v2f16(<2 x half> %in) { ; GFX1100-SDAG-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_1) ; GFX1100-SDAG-TRUE16-NEXT: v_log_f32_e32 v1, v1 ; GFX1100-SDAG-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, 0 -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixhi_f16 v0, v1, s0, 0 +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, neg(0) +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixhi_f16 v0, v1, s0, neg(0) ; GFX1100-SDAG-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-SDAG-FAKE16-LABEL: v_log10_v2f16: @@ -7174,8 +7174,8 @@ define <2 x half> @v_log10_v2f16(<2 x half> %in) { ; GFX1100-SDAG-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(SKIP_2) | instid1(VALU_DEP_1) ; GFX1100-SDAG-FAKE16-NEXT: v_log_f32_e32 v2, v0 ; GFX1100-SDAG-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v1, s0, 0 -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixhi_f16 v0, v2, s0, 0 +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v1, s0, neg(0) +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixhi_f16 v0, v2, s0, neg(0) ; GFX1100-SDAG-FAKE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-TRUE16-LABEL: v_log10_v2f16: @@ -7188,8 +7188,8 @@ define <2 x half> @v_log10_v2f16(<2 x half> %in) { ; GFX1100-GISEL-TRUE16-NEXT: v_log_f32_e32 v1, v1 ; GFX1100-GISEL-TRUE16-NEXT: v_log_f32_e32 v2, v0 ; GFX1100-GISEL-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v1, v3, 0 -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixhi_f16 v0, v2, v3, 0 +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v1, v3, neg(0) +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixhi_f16 v0, v2, v3, neg(0) ; GFX1100-GISEL-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-FAKE16-LABEL: v_log10_v2f16: @@ -7204,8 +7204,8 @@ define <2 x half> @v_log10_v2f16(<2 x half> %in) { ; GFX1100-GISEL-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(SKIP_3) | instid1(VALU_DEP_1) ; GFX1100-GISEL-FAKE16-NEXT: v_log_f32_e32 v1, v1 ; GFX1100-GISEL-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v2, 0 -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v1, v1, v2, 0 +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v2, neg(0) +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v1, v1, v2, neg(0) ; GFX1100-GISEL-FAKE16-NEXT: v_pack_b32_f16 v0, v0, v1 ; GFX1100-GISEL-FAKE16-NEXT: s_setpc_b64 s[30:31] ; @@ -7330,8 +7330,8 @@ define <2 x half> @v_log10_fabs_v2f16(<2 x half> %in) { ; GFX1100-SDAG-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_1) ; GFX1100-SDAG-TRUE16-NEXT: v_log_f32_e32 v1, v1 ; GFX1100-SDAG-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, 0 -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixhi_f16 v0, v1, s0, 0 +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, neg(0) +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixhi_f16 v0, v1, s0, neg(0) ; GFX1100-SDAG-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-SDAG-FAKE16-LABEL: v_log10_fabs_v2f16: @@ -7346,8 +7346,8 @@ define <2 x half> @v_log10_fabs_v2f16(<2 x half> %in) { ; GFX1100-SDAG-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(SKIP_2) | instid1(VALU_DEP_1) ; GFX1100-SDAG-FAKE16-NEXT: v_log_f32_e32 v2, v0 ; GFX1100-SDAG-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v1, s0, 0 -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixhi_f16 v0, v2, s0, 0 +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v1, s0, neg(0) +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixhi_f16 v0, v2, s0, neg(0) ; GFX1100-SDAG-FAKE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-TRUE16-LABEL: v_log10_fabs_v2f16: @@ -7362,8 +7362,8 @@ define <2 x half> @v_log10_fabs_v2f16(<2 x half> %in) { ; GFX1100-GISEL-TRUE16-NEXT: v_log_f32_e32 v1, v1 ; GFX1100-GISEL-TRUE16-NEXT: v_log_f32_e32 v2, v0 ; GFX1100-GISEL-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v1, v3, 0 -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixhi_f16 v0, v2, v3, 0 +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v1, v3, neg(0) +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixhi_f16 v0, v2, v3, neg(0) ; GFX1100-GISEL-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-FAKE16-LABEL: v_log10_fabs_v2f16: @@ -7379,8 +7379,8 @@ define <2 x half> @v_log10_fabs_v2f16(<2 x half> %in) { ; GFX1100-GISEL-FAKE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-GISEL-FAKE16-NEXT: v_log_f32_e32 v1, v1 ; GFX1100-GISEL-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v2, 0 -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v1, v1, v2, 0 +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v2, neg(0) +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v1, v1, v2, neg(0) ; GFX1100-GISEL-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) ; GFX1100-GISEL-FAKE16-NEXT: v_pack_b32_f16 v0, v0, v1 ; GFX1100-GISEL-FAKE16-NEXT: s_setpc_b64 s[30:31] @@ -7508,8 +7508,8 @@ define <2 x half> @v_log10_fneg_fabs_v2f16(<2 x half> %in) { ; GFX1100-SDAG-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_1) ; GFX1100-SDAG-TRUE16-NEXT: v_log_f32_e32 v1, v1 ; GFX1100-SDAG-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, 0 -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixhi_f16 v0, v1, s0, 0 +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, neg(0) +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixhi_f16 v0, v1, s0, neg(0) ; GFX1100-SDAG-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-SDAG-FAKE16-LABEL: v_log10_fneg_fabs_v2f16: @@ -7524,8 +7524,8 @@ define <2 x half> @v_log10_fneg_fabs_v2f16(<2 x half> %in) { ; GFX1100-SDAG-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(SKIP_2) | instid1(VALU_DEP_1) ; GFX1100-SDAG-FAKE16-NEXT: v_log_f32_e32 v2, v0 ; GFX1100-SDAG-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v1, s0, 0 -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixhi_f16 v0, v2, s0, 0 +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v1, s0, neg(0) +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixhi_f16 v0, v2, s0, neg(0) ; GFX1100-SDAG-FAKE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-TRUE16-LABEL: v_log10_fneg_fabs_v2f16: @@ -7540,8 +7540,8 @@ define <2 x half> @v_log10_fneg_fabs_v2f16(<2 x half> %in) { ; GFX1100-GISEL-TRUE16-NEXT: v_log_f32_e32 v1, v1 ; GFX1100-GISEL-TRUE16-NEXT: v_log_f32_e32 v2, v0 ; GFX1100-GISEL-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v1, v3, 0 -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixhi_f16 v0, v2, v3, 0 +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v1, v3, neg(0) +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixhi_f16 v0, v2, v3, neg(0) ; GFX1100-GISEL-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-FAKE16-LABEL: v_log10_fneg_fabs_v2f16: @@ -7557,8 +7557,8 @@ define <2 x half> @v_log10_fneg_fabs_v2f16(<2 x half> %in) { ; GFX1100-GISEL-FAKE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-GISEL-FAKE16-NEXT: v_log_f32_e32 v1, v1 ; GFX1100-GISEL-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v2, 0 -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v1, v1, v2, 0 +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v2, neg(0) +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v1, v1, v2, neg(0) ; GFX1100-GISEL-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) ; GFX1100-GISEL-FAKE16-NEXT: v_pack_b32_f16 v0, v0, v1 ; GFX1100-GISEL-FAKE16-NEXT: s_setpc_b64 s[30:31] @@ -7687,8 +7687,8 @@ define <2 x half> @v_log10_fneg_v2f16(<2 x half> %in) { ; GFX1100-SDAG-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_1) ; GFX1100-SDAG-TRUE16-NEXT: v_log_f32_e32 v1, v1 ; GFX1100-SDAG-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, 0 -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixhi_f16 v0, v1, s0, 0 +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, neg(0) +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixhi_f16 v0, v1, s0, neg(0) ; GFX1100-SDAG-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-SDAG-FAKE16-LABEL: v_log10_fneg_v2f16: @@ -7703,8 +7703,8 @@ define <2 x half> @v_log10_fneg_v2f16(<2 x half> %in) { ; GFX1100-SDAG-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(SKIP_2) | instid1(VALU_DEP_1) ; GFX1100-SDAG-FAKE16-NEXT: v_log_f32_e32 v2, v0 ; GFX1100-SDAG-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v1, s0, 0 -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixhi_f16 v0, v2, s0, 0 +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v1, s0, neg(0) +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixhi_f16 v0, v2, s0, neg(0) ; GFX1100-SDAG-FAKE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-TRUE16-LABEL: v_log10_fneg_v2f16: @@ -7719,8 +7719,8 @@ define <2 x half> @v_log10_fneg_v2f16(<2 x half> %in) { ; GFX1100-GISEL-TRUE16-NEXT: v_log_f32_e32 v1, v1 ; GFX1100-GISEL-TRUE16-NEXT: v_log_f32_e32 v2, v0 ; GFX1100-GISEL-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v1, v3, 0 -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixhi_f16 v0, v2, v3, 0 +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v1, v3, neg(0) +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixhi_f16 v0, v2, v3, neg(0) ; GFX1100-GISEL-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-FAKE16-LABEL: v_log10_fneg_v2f16: @@ -7736,8 +7736,8 @@ define <2 x half> @v_log10_fneg_v2f16(<2 x half> %in) { ; GFX1100-GISEL-FAKE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-GISEL-FAKE16-NEXT: v_log_f32_e32 v1, v1 ; GFX1100-GISEL-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v2, 0 -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v1, v1, v2, 0 +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v2, neg(0) +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v1, v1, v2, neg(0) ; GFX1100-GISEL-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) ; GFX1100-GISEL-FAKE16-NEXT: v_pack_b32_f16 v0, v0, v1 ; GFX1100-GISEL-FAKE16-NEXT: s_setpc_b64 s[30:31] @@ -8019,10 +8019,10 @@ define <3 x half> @v_log10_v3f16(<3 x half> %in) { ; GFX1100-SDAG-TRUE16-NEXT: v_log_f32_e32 v1, v1 ; GFX1100-SDAG-TRUE16-NEXT: v_log_f32_e32 v2, v2 ; GFX1100-SDAG-TRUE16-NEXT: s_delay_alu instid0(TRANS32_DEP_3) -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, 0 +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, neg(0) ; GFX1100-SDAG-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v1, v1, s0, 0 -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixhi_f16 v0, v2, s0, 0 +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v1, v1, s0, neg(0) +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixhi_f16 v0, v2, s0, neg(0) ; GFX1100-SDAG-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-SDAG-FAKE16-LABEL: v_log10_v3f16: @@ -8039,10 +8039,10 @@ define <3 x half> @v_log10_v3f16(<3 x half> %in) { ; GFX1100-SDAG-FAKE16-NEXT: v_log_f32_e32 v1, v1 ; GFX1100-SDAG-FAKE16-NEXT: v_log_f32_e32 v3, v0 ; GFX1100-SDAG-FAKE16-NEXT: s_delay_alu instid0(TRANS32_DEP_3) -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v2, s0, 0 +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v2, s0, neg(0) ; GFX1100-SDAG-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v1, v1, s0, 0 -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixhi_f16 v0, v3, s0, 0 +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v1, v1, s0, neg(0) +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixhi_f16 v0, v3, s0, neg(0) ; GFX1100-SDAG-FAKE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-TRUE16-LABEL: v_log10_v3f16: @@ -8057,10 +8057,10 @@ define <3 x half> @v_log10_v3f16(<3 x half> %in) { ; GFX1100-GISEL-TRUE16-NEXT: v_log_f32_e32 v3, v0 ; GFX1100-GISEL-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(TRANS32_DEP_3) ; GFX1100-GISEL-TRUE16-NEXT: v_log_f32_e32 v1, v1 -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v2, v4, 0 +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v2, v4, neg(0) ; GFX1100-GISEL-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixhi_f16 v0, v3, v4, 0 -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v1, v1, v4, 0 +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixhi_f16 v0, v3, v4, neg(0) +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v1, v1, v4, neg(0) ; GFX1100-GISEL-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-FAKE16-LABEL: v_log10_v3f16: @@ -8077,10 +8077,10 @@ define <3 x half> @v_log10_v3f16(<3 x half> %in) { ; GFX1100-GISEL-FAKE16-NEXT: v_log_f32_e32 v0, v0 ; GFX1100-GISEL-FAKE16-NEXT: v_log_f32_e32 v2, v2 ; GFX1100-GISEL-FAKE16-NEXT: s_delay_alu instid0(TRANS32_DEP_3) | instskip(SKIP_4) | instid1(VALU_DEP_2) -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v1, v1, v3, 0 +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v1, v1, v3, neg(0) ; GFX1100-GISEL-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v3, 0 -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v2, v2, v3, 0 +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v3, neg(0) +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v2, v2, v3, neg(0) ; GFX1100-GISEL-FAKE16-NEXT: v_and_b32_e32 v1, 0xffff, v1 ; GFX1100-GISEL-FAKE16-NEXT: v_pack_b32_f16 v0, v0, v2 ; GFX1100-GISEL-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_2) @@ -8440,12 +8440,12 @@ define <4 x half> @v_log10_v4f16(<4 x half> %in) { ; GFX1100-SDAG-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_1) ; GFX1100-SDAG-TRUE16-NEXT: v_log_f32_e32 v2, v2 ; GFX1100-SDAG-TRUE16-NEXT: v_log_f32_e32 v3, v3 -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v1, v1, s0, 0 +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v1, v1, s0, neg(0) ; GFX1100-SDAG-TRUE16-NEXT: s_delay_alu instid0(TRANS32_DEP_3) -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, 0 +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixlo_f16 v0, v0, s0, neg(0) ; GFX1100-SDAG-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixhi_f16 v0, v2, s0, 0 -; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixhi_f16 v1, v3, s0, 0 +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixhi_f16 v0, v2, s0, neg(0) +; GFX1100-SDAG-TRUE16-NEXT: v_fma_mixhi_f16 v1, v3, s0, neg(0) ; GFX1100-SDAG-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-SDAG-FAKE16-LABEL: v_log10_v4f16: @@ -8463,12 +8463,12 @@ define <4 x half> @v_log10_v4f16(<4 x half> %in) { ; GFX1100-SDAG-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_1) ; GFX1100-SDAG-FAKE16-NEXT: v_log_f32_e32 v4, v0 ; GFX1100-SDAG-FAKE16-NEXT: v_log_f32_e32 v5, v1 -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v1, v2, s0, 0 +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v1, v2, s0, neg(0) ; GFX1100-SDAG-FAKE16-NEXT: s_delay_alu instid0(TRANS32_DEP_3) -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v3, s0, 0 +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixlo_f16 v0, v3, s0, neg(0) ; GFX1100-SDAG-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixhi_f16 v0, v4, s0, 0 -; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixhi_f16 v1, v5, s0, 0 +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixhi_f16 v0, v4, s0, neg(0) +; GFX1100-SDAG-FAKE16-NEXT: v_fma_mixhi_f16 v1, v5, s0, neg(0) ; GFX1100-SDAG-FAKE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-TRUE16-LABEL: v_log10_v4f16: @@ -8483,12 +8483,12 @@ define <4 x half> @v_log10_v4f16(<4 x half> %in) { ; GFX1100-GISEL-TRUE16-NEXT: v_log_f32_e32 v4, v0 ; GFX1100-GISEL-TRUE16-NEXT: v_log_f32_e32 v3, v3 ; GFX1100-GISEL-TRUE16-NEXT: v_log_f32_e32 v5, v1 -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v2, v6, 0 +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v0, v2, v6, neg(0) ; GFX1100-GISEL-TRUE16-NEXT: s_delay_alu instid0(TRANS32_DEP_3) -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixhi_f16 v0, v4, v6, 0 +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixhi_f16 v0, v4, v6, neg(0) ; GFX1100-GISEL-TRUE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v1, v3, v6, 0 -; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixhi_f16 v1, v5, v6, 0 +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixlo_f16 v1, v3, v6, neg(0) +; GFX1100-GISEL-TRUE16-NEXT: v_fma_mixhi_f16 v1, v5, v6, neg(0) ; GFX1100-GISEL-TRUE16-NEXT: s_setpc_b64 s[30:31] ; ; GFX1100-GISEL-FAKE16-LABEL: v_log10_v4f16: @@ -8506,12 +8506,12 @@ define <4 x half> @v_log10_v4f16(<4 x half> %in) { ; GFX1100-GISEL-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_1) ; GFX1100-GISEL-FAKE16-NEXT: v_log_f32_e32 v2, v2 ; GFX1100-GISEL-FAKE16-NEXT: v_log_f32_e32 v3, v3 -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v4, 0 +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v0, v0, v4, neg(0) ; GFX1100-GISEL-FAKE16-NEXT: s_delay_alu instid0(TRANS32_DEP_3) | instskip(SKIP_3) | instid1(VALU_DEP_2) -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v1, v1, v4, 0 +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v1, v1, v4, neg(0) ; GFX1100-GISEL-FAKE16-NEXT: s_waitcnt_depctr depctr_va_vdst(0) -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v2, v2, v4, 0 -; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v3, v3, v4, 0 +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v2, v2, v4, neg(0) +; GFX1100-GISEL-FAKE16-NEXT: v_fma_mixlo_f16 v3, v3, v4, neg(0) ; GFX1100-GISEL-FAKE16-NEXT: v_pack_b32_f16 v0, v0, v2 ; GFX1100-GISEL-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_2) ; GFX1100-GISEL-FAKE16-NEXT: v_pack_b32_f16 v1, v1, v3 diff --git a/llvm/test/CodeGen/AMDGPU/mad-mix-lo-bf16.ll b/llvm/test/CodeGen/AMDGPU/mad-mix-lo-bf16.ll index 87dddb0901ddb..4ac8985ecad7b 100644 --- a/llvm/test/CodeGen/AMDGPU/mad-mix-lo-bf16.ll +++ b/llvm/test/CodeGen/AMDGPU/mad-mix-lo-bf16.ll @@ -502,7 +502,7 @@ define bfloat @mixlo_fptrunc(float %a, float %b) #0 { ; GFX1250: ; %bb.0: ; %.entry ; GFX1250-NEXT: s_wait_loadcnt_dscnt 0x0 ; GFX1250-NEXT: s_wait_kmcnt 0x0 -; GFX1250-NEXT: v_fma_mixlo_bf16 v0, v0, v1, 0 +; GFX1250-NEXT: v_fma_mixlo_bf16 v0, v0, v1, neg(0) ; GFX1250-NEXT: s_set_pc_i64 s[30:31] .entry: %mul = fmul float %a, %b @@ -515,7 +515,7 @@ define bfloat @mixlo_fptrunc_no_flush(float %a, float %b) { ; GFX1250: ; %bb.0: ; %.entry ; GFX1250-NEXT: s_wait_loadcnt_dscnt 0x0 ; GFX1250-NEXT: s_wait_kmcnt 0x0 -; GFX1250-NEXT: v_fma_mixlo_bf16 v0, v0, v1, 0 +; GFX1250-NEXT: v_fma_mixlo_bf16 v0, v0, v1, neg(0) ; GFX1250-NEXT: s_set_pc_i64 s[30:31] .entry: %mul = fmul float %a, %b @@ -528,7 +528,7 @@ define bfloat @mixlo_fptrunc_abs_src_mod(float %a, float %b) #0 { ; GFX1250: ; %bb.0: ; %.entry ; GFX1250-NEXT: s_wait_loadcnt_dscnt 0x0 ; GFX1250-NEXT: s_wait_kmcnt 0x0 -; GFX1250-NEXT: v_fma_mixlo_bf16 v0, |v0|, v1, 0 +; GFX1250-NEXT: v_fma_mixlo_bf16 v0, |v0|, v1, neg(0) ; GFX1250-NEXT: s_set_pc_i64 s[30:31] .entry: %a.fabs = call float @llvm.fabs.f32(float %a) @@ -542,7 +542,7 @@ define bfloat @mixlo_fptrunc_neg_src_mod(float %a, float %b) #0 { ; GFX1250: ; %bb.0: ; %.entry ; GFX1250-NEXT: s_wait_loadcnt_dscnt 0x0 ; GFX1250-NEXT: s_wait_kmcnt 0x0 -; GFX1250-NEXT: v_fma_mixlo_bf16 v0, -v0, v1, 0 +; GFX1250-NEXT: v_fma_mixlo_bf16 v0, -v0, v1, neg(0) ; GFX1250-NEXT: s_set_pc_i64 s[30:31] .entry: %a.fneg = fneg float %a diff --git a/llvm/test/CodeGen/AMDGPU/mad-mix-lo.ll b/llvm/test/CodeGen/AMDGPU/mad-mix-lo.ll index db0e6fb66dc67..cfa2fa199dc0d 100644 --- a/llvm/test/CodeGen/AMDGPU/mad-mix-lo.ll +++ b/llvm/test/CodeGen/AMDGPU/mad-mix-lo.ll @@ -2638,19 +2638,19 @@ define half @mixlo_fptrunc(float %a, float %b) #0 { ; GFX1100-LABEL: mixlo_fptrunc: ; GFX1100: ; %bb.0: ; %.entry ; GFX1100-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GFX1100-NEXT: v_fma_mixlo_f16 v0, v0, v1, 0 +; GFX1100-NEXT: v_fma_mixlo_f16 v0, v0, v1, neg(0) ; GFX1100-NEXT: s_setpc_b64 s[30:31] ; ; GFX900-LABEL: mixlo_fptrunc: ; GFX900: ; %bb.0: ; %.entry ; GFX900-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GFX900-NEXT: v_mad_mixlo_f16 v0, v0, v1, 0 +; GFX900-NEXT: v_mad_mixlo_f16 v0, v0, v1, neg(0) ; GFX900-NEXT: s_setpc_b64 s[30:31] ; ; GFX906-LABEL: mixlo_fptrunc: ; GFX906: ; %bb.0: ; %.entry ; GFX906-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GFX906-NEXT: v_fma_mixlo_f16 v0, v0, v1, 0 +; GFX906-NEXT: v_fma_mixlo_f16 v0, v0, v1, neg(0) ; GFX906-NEXT: s_setpc_b64 s[30:31] ; ; VI-LABEL: mixlo_fptrunc: @@ -2683,7 +2683,7 @@ define half @mixlo_fptrunc_no_flush(float %a, float %b) { ; GFX1100-LABEL: mixlo_fptrunc_no_flush: ; GFX1100: ; %bb.0: ; %.entry ; GFX1100-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GFX1100-NEXT: v_fma_mixlo_f16 v0, v0, v1, 0 +; GFX1100-NEXT: v_fma_mixlo_f16 v0, v0, v1, neg(0) ; GFX1100-NEXT: s_setpc_b64 s[30:31] ; ; GFX900-LABEL: mixlo_fptrunc_no_flush: @@ -2696,7 +2696,7 @@ define half @mixlo_fptrunc_no_flush(float %a, float %b) { ; GFX906-LABEL: mixlo_fptrunc_no_flush: ; GFX906: ; %bb.0: ; %.entry ; GFX906-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GFX906-NEXT: v_fma_mixlo_f16 v0, v0, v1, 0 +; GFX906-NEXT: v_fma_mixlo_f16 v0, v0, v1, neg(0) ; GFX906-NEXT: s_setpc_b64 s[30:31] ; ; VI-LABEL: mixlo_fptrunc_no_flush: @@ -2729,19 +2729,19 @@ define half @mixlo_fptrunc_abs_src_mod(float %a, float %b) #0 { ; GFX1100-LABEL: mixlo_fptrunc_abs_src_mod: ; GFX1100: ; %bb.0: ; %.entry ; GFX1100-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GFX1100-NEXT: v_fma_mixlo_f16 v0, |v0|, v1, 0 +; GFX1100-NEXT: v_fma_mixlo_f16 v0, |v0|, v1, neg(0) ; GFX1100-NEXT: s_setpc_b64 s[30:31] ; ; GFX900-LABEL: mixlo_fptrunc_abs_src_mod: ; GFX900: ; %bb.0: ; %.entry ; GFX900-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GFX900-NEXT: v_mad_mixlo_f16 v0, |v0|, v1, 0 +; GFX900-NEXT: v_mad_mixlo_f16 v0, |v0|, v1, neg(0) ; GFX900-NEXT: s_setpc_b64 s[30:31] ; ; GFX906-LABEL: mixlo_fptrunc_abs_src_mod: ; GFX906: ; %bb.0: ; %.entry ; GFX906-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GFX906-NEXT: v_fma_mixlo_f16 v0, |v0|, v1, 0 +; GFX906-NEXT: v_fma_mixlo_f16 v0, |v0|, v1, neg(0) ; GFX906-NEXT: s_setpc_b64 s[30:31] ; ; VI-LABEL: mixlo_fptrunc_abs_src_mod: @@ -2775,19 +2775,19 @@ define half @mixlo_fptrunc_neg_src_mod(float %a, float %b) #0 { ; GFX1100-LABEL: mixlo_fptrunc_neg_src_mod: ; GFX1100: ; %bb.0: ; %.entry ; GFX1100-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GFX1100-NEXT: v_fma_mixlo_f16 v0, -v0, v1, 0 +; GFX1100-NEXT: v_fma_mixlo_f16 v0, -v0, v1, neg(0) ; GFX1100-NEXT: s_setpc_b64 s[30:31] ; ; GFX900-LABEL: mixlo_fptrunc_neg_src_mod: ; GFX900: ; %bb.0: ; %.entry ; GFX900-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GFX900-NEXT: v_mad_mixlo_f16 v0, -v0, v1, 0 +; GFX900-NEXT: v_mad_mixlo_f16 v0, -v0, v1, neg(0) ; GFX900-NEXT: s_setpc_b64 s[30:31] ; ; GFX906-LABEL: mixlo_fptrunc_neg_src_mod: ; GFX906: ; %bb.0: ; %.entry ; GFX906-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GFX906-NEXT: v_fma_mixlo_f16 v0, -v0, v1, 0 +; GFX906-NEXT: v_fma_mixlo_f16 v0, -v0, v1, neg(0) ; GFX906-NEXT: s_setpc_b64 s[30:31] ; ; VI-LABEL: mixlo_fptrunc_neg_src_mod: From 5be66d0a9afe1268bf7ff75c69a32b141d4f0096 Mon Sep 17 00:00:00 2001 From: Dmitry Sidorov Date: Fri, 7 Aug 2026 02:52:00 +0200 Subject: [PATCH 029/789] [NFC][AMDGPU] Let IR level callers query the FMA/FMAD predicates (#213310) isFMADLegal and isFMAFasterThanFMulAndFAdd read the denormal mode out of the MachineFunction, so nothing before instruction selection can ask them whether an fmul/fadd pair will be fused. Take an explicit DenormalFPEnv instead, and make the existing MachineFunction / SelectionDAG / MachineInstr entry points thin wrappers over it. Also override the IR level isFMAFasterThanFMulAndFAdd hook. The two views agree by construction, since SIModeRegisterDefaults copies its denormal fields out of getDenormalFPEnv. isFMADLegal uses VT as written and does not look through vectors, so a vector type reports false, as in the SelectionDAG overload it was extracted from. The patch is preparation for querying these from getArithmeticInstrCost and a revived isProfitableToSinkOperands. Contributes to #211092 Assisted-By: Claude Opus 5 --- llvm/lib/Target/AMDGPU/SIISelLowering.cpp | 60 +++++++++++++------ llvm/lib/Target/AMDGPU/SIISelLowering.h | 10 ++++ .../Target/AMDGPU/SIModeRegisterDefaults.h | 5 ++ 3 files changed, 56 insertions(+), 19 deletions(-) diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp index f53fd0d74e48e..9b35b24663a58 100644 --- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp +++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp @@ -69,6 +69,10 @@ static cl::opt UseDivergentRegisterIndexing( cl::desc("Use indirect register addressing for divergent indexes"), cl::init(false)); +static DenormalFPEnv getDenormalFPEnv(const MachineFunction &MF) { + return MF.getInfo()->getMode().getDenormalFPEnv(); +} + static bool denormalModeIsFlushAllF32(const MachineFunction &MF) { const SIMachineFunctionInfo *Info = MF.getInfo(); return Info->getMode().FP32Denormals == DenormalMode::getPreserveSign(); @@ -7438,9 +7442,11 @@ LLT SITargetLowering::getPreferredShiftAmountTy(LLT Ty) const { // however does not support denormals, so we do report fma as faster if we have // a fast fma device and require denormals. // -bool SITargetLowering::isFMAFasterThanFMulAndFAdd(const MachineFunction &MF, - EVT VT) const { +bool SITargetLowering::isFMAFasterThanFMulAndFAdd(EVT VT, + DenormalFPEnv FPEnv) const { VT = VT.getScalarType(); + if (!VT.isSimple()) + return false; switch (VT.getSimpleVT().SimpleTy) { case MVT::f32: { @@ -7451,7 +7457,7 @@ bool SITargetLowering::isFMAFasterThanFMulAndFAdd(const MachineFunction &MF, // Otherwise f32 mad is always full rate and returns the same result as // the separate operations so should be preferred over fma. // However does not support denormals. - if (!denormalModeIsFlushAllF32(MF)) + if (FPEnv.F32Mode != DenormalMode::getPreserveSign()) return Subtarget->hasFastFMAF32() || Subtarget->hasDLInsts(); // If the subtarget has v_fmac_f32, that's just as good as v_mac_f32. @@ -7461,7 +7467,8 @@ bool SITargetLowering::isFMAFasterThanFMulAndFAdd(const MachineFunction &MF, return true; case MVT::f16: case MVT::bf16: - return Subtarget->has16BitInsts() && !denormalModeIsFlushAllF64F16(MF); + return Subtarget->has16BitInsts() && + FPEnv.DefaultMode != DenormalMode::getPreserveSign(); default: break; } @@ -7469,6 +7476,18 @@ bool SITargetLowering::isFMAFasterThanFMulAndFAdd(const MachineFunction &MF, return false; } +bool SITargetLowering::isFMAFasterThanFMulAndFAdd(const MachineFunction &MF, + EVT VT) const { + return isFMAFasterThanFMulAndFAdd(VT, getDenormalFPEnv(MF)); +} + +bool SITargetLowering::isFMAFasterThanFMulAndFAdd(const Function &F, + Type *Ty) const { + return isFMAFasterThanFMulAndFAdd( + getValueType(F.getDataLayout(), Ty, /*AllowUnknown=*/true), + F.getDenormalFPEnv()); +} + bool SITargetLowering::isFMAFasterThanFMulAndFAdd(const MachineFunction &MF, LLT Ty) const { switch (Ty.getScalarSizeInBits()) { @@ -7485,33 +7504,36 @@ bool SITargetLowering::isFMAFasterThanFMulAndFAdd(const MachineFunction &MF, return false; } +bool SITargetLowering::isFMADLegal(EVT VT, DenormalFPEnv FPEnv) const { + // TODO: Check future ftz flag + // v_mad_f32/v_mac_f32 do not support denormals. + if (VT == MVT::f32) + return Subtarget->hasMadMacF32Insts() && + FPEnv.F32Mode == DenormalMode::getPreserveSign(); + if (VT == MVT::f16) + return Subtarget->hasMadF16() && + FPEnv.DefaultMode == DenormalMode::getPreserveSign(); + + return false; +} + bool SITargetLowering::isFMADLegal(const MachineInstr &MI, LLT Ty) const { if (!Ty.isScalar()) return false; + DenormalFPEnv FPEnv = getDenormalFPEnv(*MI.getMF()); if (Ty.getScalarSizeInBits() == 16) - return Subtarget->hasMadF16() && denormalModeIsFlushAllF64F16(*MI.getMF()); + return isFMADLegal(MVT::f16, FPEnv); if (Ty.getScalarSizeInBits() == 32) - return Subtarget->hasMadMacF32Insts() && - denormalModeIsFlushAllF32(*MI.getMF()); + return isFMADLegal(MVT::f32, FPEnv); return false; } bool SITargetLowering::isFMADLegal(const SelectionDAG &DAG, const SDNode *N) const { - // TODO: Check future ftz flag - // v_mad_f32/v_mac_f32 do not support denormals. - EVT VT = N->getValueType(0); - if (VT == MVT::f32) - return Subtarget->hasMadMacF32Insts() && - denormalModeIsFlushAllF32(DAG.getMachineFunction()); - if (VT == MVT::f16) { - return Subtarget->hasMadF16() && - denormalModeIsFlushAllF64F16(DAG.getMachineFunction()); - } - - return false; + return isFMADLegal(N->getValueType(0), + getDenormalFPEnv(DAG.getMachineFunction())); } //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.h b/llvm/lib/Target/AMDGPU/SIISelLowering.h index 3e0e5da94471f..b2f5d70194567 100644 --- a/llvm/lib/Target/AMDGPU/SIISelLowering.h +++ b/llvm/lib/Target/AMDGPU/SIISelLowering.h @@ -17,6 +17,7 @@ #include "AMDGPUArgumentUsageInfo.h" #include "AMDGPUISelLowering.h" #include "SIDefines.h" +#include "llvm/ADT/FloatingPointMode.h" #include "llvm/CodeGen/MachineFunction.h" namespace llvm { @@ -506,6 +507,15 @@ class SITargetLowering final : public AMDGPUTargetLowering { bool isFMADLegal(const SelectionDAG &DAG, const SDNode *N) const override; bool isFMADLegal(const MachineInstr &MI, const LLT Ty) const override; + /// Variants for IR level callers, which have no MachineFunction to read the + /// denormal mode from and must pass \p FPEnv explicitly. + bool isFMAFasterThanFMulAndFAdd(EVT VT, DenormalFPEnv FPEnv) const; + + /// \p VT is used as written, so a vector type reports false. + bool isFMADLegal(EVT VT, DenormalFPEnv FPEnv) const; + + bool isFMAFasterThanFMulAndFAdd(const Function &F, Type *Ty) const override; + SDValue splitUnaryVectorOp(SDValue Op, SelectionDAG &DAG) const; SDValue splitBinaryVectorOp(SDValue Op, SelectionDAG &DAG) const; SDValue splitTernaryVectorOp(SDValue Op, SelectionDAG &DAG) const; diff --git a/llvm/lib/Target/AMDGPU/SIModeRegisterDefaults.h b/llvm/lib/Target/AMDGPU/SIModeRegisterDefaults.h index c86678a732535..f98c60a51e379 100644 --- a/llvm/lib/Target/AMDGPU/SIModeRegisterDefaults.h +++ b/llvm/lib/Target/AMDGPU/SIModeRegisterDefaults.h @@ -56,6 +56,11 @@ struct SIModeRegisterDefaults { FP64FP16Denormals == Other.FP64FP16Denormals; } + /// Get the denormal handling described by this mode. + DenormalFPEnv getDenormalFPEnv() const { + return DenormalFPEnv(FP64FP16Denormals, FP32Denormals); + } + /// Get the encoding value for the FP_DENORM bits of the mode register for the /// FP32 denormal mode. uint32_t fpDenormModeSPValue() const { From 1c0eda0d2371a6a755f90299892a7b89dc917442 Mon Sep 17 00:00:00 2001 From: Mingjie Xu Date: Fri, 7 Aug 2026 09:15:47 +0800 Subject: [PATCH 030/789] Revert "[SCEV] Speed up forgetLoop by avoiding def-use walk for loop-header PHIs" (#212485) Reverts https://github.com/llvm/llvm-project/pull/201572 Multiple miscompilations are reported, see https://github.com/llvm/llvm-project/issues/207744, https://github.com/llvm/llvm-project/issues/212027 That commit made forgetLoop() rely on LoopUsers[L] and stop walking the def-use chain of the loop-header PHIs. This is insufficient, because some cached data is derived from the underlying IR of SCEVUnknown, it is not reachable from LoopUsers[L]. After that commit, forgetLoop() no longer invalidated them, so stale UnsignedRanges / SignedRanges, ConstantMultipleCache, ValuesAtScopes cause miscompilations. --- llvm/lib/Analysis/ScalarEvolution.cpp | 22 ++++++++--- .../Analysis/ScalarEvolutionTest.cpp | 39 ------------------- 2 files changed, 16 insertions(+), 45 deletions(-) diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp index 031ca237289e4..27a1a20bcdf79 100644 --- a/llvm/lib/Analysis/ScalarEvolution.cpp +++ b/llvm/lib/Analysis/ScalarEvolution.cpp @@ -8634,6 +8634,18 @@ bool ScalarEvolution::isBackedgeTakenCountMaxOrZero(const Loop *L) { return getBackedgeTakenInfo(L).isConstantMaxOrZero(this); } +/// Push PHI nodes in the header of the given loop onto the given Worklist. +static void PushLoopPHIs(const Loop *L, + SmallVectorImpl &Worklist, + SmallPtrSetImpl &Visited) { + BasicBlock *Header = L->getHeader(); + + // Push all Loop-header PHIs onto the Worklist stack. + for (PHINode &PN : Header->phis()) + if (Visited.insert(&PN).second) + Worklist.push_back(&PN); +} + ScalarEvolution::BackedgeTakenInfo & ScalarEvolution::getPredicatedBackedgeTakenInfo(const Loop *L) { auto &BTI = getBackedgeTakenInfo(L); @@ -8743,6 +8755,8 @@ void ScalarEvolution::visitAndClearUsers( void ScalarEvolution::forgetLoop(const Loop *L) { SmallVector LoopWorklist(1, L); + SmallVector Worklist; + SmallPtrSet Visited; SmallVector ToForget; // Iterate over all the loops and sub-loops to drop SCEV information. @@ -8762,12 +8776,8 @@ void ScalarEvolution::forgetLoop(const Loop *L) { llvm::append_range(ToForget, LoopUsersItr->second); // Drop information about expressions based on loop-header PHIs. - for (PHINode &PN : CurrL->getHeader()->phis()) { - ConstantEvolutionLoopExitValue.erase(&PN); - auto VIt = ValueExprMap.find_as(static_cast(&PN)); - if (VIt != ValueExprMap.end()) - ToForget.push_back(VIt->second); - } + PushLoopPHIs(CurrL, Worklist, Visited); + visitAndClearUsers(Worklist, Visited, ToForget); LoopPropertiesCache.erase(CurrL); // Forget all contained loops too, to avoid dangling entries in the diff --git a/llvm/unittests/Analysis/ScalarEvolutionTest.cpp b/llvm/unittests/Analysis/ScalarEvolutionTest.cpp index 286811bc7bc42..621c4897a39d7 100644 --- a/llvm/unittests/Analysis/ScalarEvolutionTest.cpp +++ b/llvm/unittests/Analysis/ScalarEvolutionTest.cpp @@ -1709,45 +1709,6 @@ TEST_F(ScalarEvolutionsTest, ForgetValueWithOverflowInst) { }); } -TEST_F(ScalarEvolutionsTest, ForgetLoopPreservesUnrelatedCachesInLoopBody) { - LLVMContext C; - SMDiagnostic Err; - std::unique_ptr M = - parseAssemblyString("define void @foo(i32 %n) { " - "entry: " - " br label %loop " - "loop: " - " %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ] " - " %iv.next = add nsw i32 %iv, 1 " - " %cmp = icmp slt i32 %iv, %n " - " br i1 %cmp, label %loop, label %exit " - "exit: " - " ret void " - "} ", - Err, C); - - ASSERT_TRUE(M && "Could not parse module?"); - ASSERT_TRUE(!verifyModule(*M) && "Must have been well formed!"); - - runWithSE(*M, "foo", [](Function &F, LoopInfo &LI, ScalarEvolution &SE) { - auto *IV = getInstructionByName(F, "iv"); - auto *Cmp = getInstructionByName(F, "cmp"); - - const SCEV *IVScev = SE.getSCEV(IV); - EXPECT_NE(IVScev, nullptr); - EXPECT_TRUE(isa(IVScev)); - - const SCEV *CmpScev = SE.getSCEV(Cmp); - EXPECT_NE(CmpScev, nullptr); - EXPECT_TRUE(isa(CmpScev)); - - Loop *L = *LI.begin(); - SE.forgetLoop(L); - EXPECT_EQ(SE.getExistingSCEV(IV), nullptr); - EXPECT_EQ(SE.getExistingSCEV(Cmp), CmpScev); - }); -} - TEST_F(ScalarEvolutionsTest, ComplexityComparatorIsStrictWeakOrdering) { // Regression test for a case where caching of equivalent values caused the // comparator to get inconsistent. From 1b8dcb4f42f7ce005a223259e0453440d7eed00f Mon Sep 17 00:00:00 2001 From: Alex MacLean Date: Thu, 6 Aug 2026 18:25:47 -0700 Subject: [PATCH 031/789] [NVPTX] Model SM architectures as subtarget features (NFC) (#214335) --- .../NVPTX/MCTargetDesc/NVPTXInstPrinter.cpp | 3 - llvm/lib/Target/NVPTX/NVPTX.h | 3 + llvm/lib/Target/NVPTX/NVPTX.td | 163 +++++---- llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp | 9 +- llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp | 77 ++-- llvm/lib/Target/NVPTX/NVPTXInstrInfo.td | 128 +++---- llvm/lib/Target/NVPTX/NVPTXIntrinsics.td | 340 +++++++++--------- llvm/lib/Target/NVPTX/NVPTXSubtarget.cpp | 161 ++++----- llvm/lib/Target/NVPTX/NVPTXSubtarget.h | 214 +++++------ 9 files changed, 508 insertions(+), 590 deletions(-) diff --git a/llvm/lib/Target/NVPTX/MCTargetDesc/NVPTXInstPrinter.cpp b/llvm/lib/Target/NVPTX/MCTargetDesc/NVPTXInstPrinter.cpp index 3e8fe7ec2fc92..fe9e2fa260811 100644 --- a/llvm/lib/Target/NVPTX/MCTargetDesc/NVPTXInstPrinter.cpp +++ b/llvm/lib/Target/NVPTX/MCTargetDesc/NVPTXInstPrinter.cpp @@ -29,9 +29,6 @@ using namespace llvm; #define DEBUG_TYPE "asm-printer" -#define GET_SUBTARGETINFO_ENUM -#include "NVPTXGenSubtargetInfo.inc" - #include "NVPTXGenAsmWriter.inc" static bool hasParamSubqualifiers(const MCSubtargetInfo &STI) { diff --git a/llvm/lib/Target/NVPTX/NVPTX.h b/llvm/lib/Target/NVPTX/NVPTX.h index 79726c4a8f184..365ac038b79cc 100644 --- a/llvm/lib/Target/NVPTX/NVPTX.h +++ b/llvm/lib/Target/NVPTX/NVPTX.h @@ -368,4 +368,7 @@ void initializeNVPTXDAGToDAGISelLegacyPass(PassRegistry &); #define GET_INSTRINFO_OPERAND_ENUM #include "NVPTXGenInstrInfo.inc" +#define GET_SUBTARGETINFO_ENUM +#include "NVPTXGenSubtargetInfo.inc" + #endif diff --git a/llvm/lib/Target/NVPTX/NVPTX.td b/llvm/lib/Target/NVPTX/NVPTX.td index cb9aef2a1cd42..8804e5c57e5fc 100644 --- a/llvm/lib/Target/NVPTX/NVPTX.td +++ b/llvm/lib/Target/NVPTX/NVPTX.td @@ -14,100 +14,111 @@ include "llvm/Target/Target.td" -include "NVPTXRegisterInfo.td" -include "NVPTXInstrInfo.td" - //===----------------------------------------------------------------------===// -// Subtarget Features. -// - We use the SM version number instead of explicit feature table. -// - Need at least one feature to avoid generating zero sized array by -// TableGen in NVPTXGenSubtarget.inc. +// PTX ISA versions. //===----------------------------------------------------------------------===// -class FeatureSM: - SubtargetFeature<"sm_"# sm, "FullSmVersion", - "" # value, - "Target SM " # sm>; - class FeaturePTX: SubtargetFeature<"ptx"# version, "PTXVersion", "" # version, "Use PTX version " # version>; -// NVPTX Architecture Hierarchy and Ordering: -// -// GPU architectures: sm_2Y/sm_3Y/sm_5Y/sm_6Y/sm_7Y/sm_8Y/sm_9Y/sm_10Y/sm_12Y -// ('Y' represents version within the architecture) -// The architectures have name of form sm_XYz where 'X' represent the generation -// number, 'Y' represents the version within the architecture, and 'z' represents -// the optional feature suffix. -// If X1Y1 <= X2Y2, then GPU capabilities of sm_X1Y1 are included in sm_X2Y2. -// For example, take sm_90 (9 represents 'X', 0 represents 'Y', and no feature -// suffix) and sm_103 architectures (10 represents 'X', 3 represents 'Y', and no -// feature suffix). Since 90 <= 103, sm_90 is compatible with sm_103. -// -// The family-specific variants have 'f' feature suffix and they follow -// following order: -// sm_X{Y2}f > sm_X{Y1}f iff Y2 > Y1 -// sm_XY{f} > sm_{XY}{} -// -// For example, take sm_100f (10 represents 'X', 0 represents 'Y', and 'f' -// represents 'z') and sm_103f (10 represents 'X', 3 represents 'Y', and 'f' -// represents 'z') architecture variants. Since Y1 < Y2, sm_100f is compatible with -// sm_103f. Similarly based on the second rule, sm_90 is compatible with sm_103f. + +foreach version = [32, 40, 41, 42, 43, 50, 60, 61, 62, 63, 64, 65, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 80, 81, 82, 83, 84, 85, 86, 87, 88, + 90, 91, 92, 93, 94] in + def PTX#version : FeaturePTX; + +//===----------------------------------------------------------------------===// +// Target architectures. // -// Some counter examples, take sm_100f and sm_120f (12 represents 'X', 0 -// represents 'Y', and 'f' represents 'z') architecture variants. Since both -// belongs to different family i.e. X1 != X2, sm_100f is not compatible with -// sm_120f. +// Architectures are named sm_XYz, where 'X' is the generation, 'Y' the version +// within the generation, and 'z' an optional feature suffix. Together they form +// a lattice, spelled out below as `Implies` edges: sm_A implies sm_B exactly +// when PTX written against sm_B is accepted for sm_A. Every edge is listed +// rather than leaning on `Implies` being transitive, which costs nothing +// because a feature's implied set is a fixed-size bitset either way. Asking +// whether a target may use what sm_B introduced is then a single bit test. // -// The architecture-specific variants have 'a' feature suffix and they follow -// following order: -// sm_XY{a} > sm_XY{f} > sm_{XY}{} +// The three tiers below are the three portability guarantees the PTX ISA +// defines for a `.target`; see the .target directive in the PTX ISA manual. // -// For example, take sm_103a (10 represents 'X', 3 represents 'Y', and 'a' -// represents 'z'), sm_103f, and sm_103 architecture variants. The sm_103 is -// compatible with sm_103a and sm_103f, and sm_103f is compatible with sm_103a. +// * Base architectures are portable: what they introduce is supported on all +// later architectures, including ones in other families. This is the "onion +// layer" model, and it makes them totally ordered by their number, so sm_120 +// implies sm_110, which implies sm_107, and so on. // -// Encoding := Arch * 10 + ArchSuffixOffset -// Arch := X * 10 + Y -// ArchSuffixOffset := 0 (base), 2 ('f'), or 3 ('a') +// * A family-specific variant sm_XYf is portable within its family only, so +// sm_103f implies sm_100f. A family is the set of architectures sharing an +// SM major version. There are no edges between families, which is what makes +// sm_120f and sm_100f incomparable. // -// For example, sm_103a is encoded as 1033 (103 * 10 + 3) and sm_103f is -// encoded as 1032 (103 * 10 + 2). +// * An architecture-specific variant sm_XYa is not portable at all, so +// sm_103a implies sm_103f and nothing implies sm_103a. // -// This encoding allows simple partial ordering of the architectures. -// + Compare Family and Arch by dividing FullSMVersion by 100 and 10 -// respectively before the comparison. -// + Compare within the family by comparing FullSMVersion, given both belongs to -// the same family. -// + Detect 'a' variants by checking FullSMVersion & 1. +// There is deliberately no numeric encoding of an architecture. Asking whether a +// target may use something is a bit test against the node that introduced it, +// which is what the partial order above requires; a number would only invite the +// ordered comparisons it cannot answer. +//===----------------------------------------------------------------------===// + +class FeatureSM implies>: + SubtargetFeature<"sm_"# !substr(NAME, 2), "HasArchitecture", "true", + "Target SM " # !substr(NAME, 2), implies>, + Predicate<"Subtarget->hasFeature(NVPTX::" # NAME # ")"> { + assert !eq(!substr(NAME, 0, 2), "SM"), + "architecture record " # NAME # " must be named SM"; +} + class Proc : Processor; -foreach sm = [20, 21, 30, 32, 35, 37, 50, 52, 53, 60, - 61, 62, 70, 72, 75, 80, 86, 87, 88, 89, - 90, 100, 101, 103, 107, 110, 120, 121] in { - // Base SM version (e.g. FullSMVersion for sm_100 is 1000) - def SM#sm : FeatureSM<""#sm, !mul(sm, 10)>; - def : Proc("SM"#sm)>; - - // Family-specific variants, compatible within same family (e.g. sm_100f = 1002) - if !ge(sm, 100) then { - def SM#sm#f : FeatureSM<""#sm#"f", !add(!mul(sm, 10), 2)>; - def : Proc("SM"#sm#"f")>; - } - - // Architecture-specific variants, incompatible across architectures (e.g. sm_100a = 1003) - if !ge(sm, 90) then { - def SM#sm#a : FeatureSM<""#sm#"a", !add(!mul(sm, 10), 3)>; - def : Proc("SM"#sm#"a")>; - } +multiclass ProcSM implies> { + def NAME : FeatureSM; + def : Proc(NAME)>; } -foreach version = [32, 40, 41, 42, 43, 50, 60, 61, 62, 63, 64, 65, 70, 71, 72, - 73, 74, 75, 76, 77, 78, 80, 81, 82, 83, 84, 85, 86, 87, 88, - 90, 91, 92, 93, 94] in - def PTX#version : FeaturePTX; +// Base architectures, in increasing order. Each implies the features of every +// earlier one. +defvar SMVersions = [20, 21, 30, 32, 35, 37, 50, 52, 53, 60, + 61, 62, 70, 72, 75, 80, 86, 87, 88, 89, + 90, 100, 103, 107, 110, 120, 121]; + +foreach sm = SMVersions in + defm SM#sm : ProcSM("SM"#earlier))>; + +// Defines the family-specific ('f') and architecture-specific ('a') variants of +// the base architecture this is named after. +multiclass FeatureSMVariants EarlierInFamily> { + defm f : ProcSM<[!cast(NAME)] # EarlierInFamily>; + defm a : ProcSM<[!cast(NAME # "f")]>; +} + +// The families, each listed in increasing order, mirroring the architecture +// family table in the PTX ISA manual. +defvar SMFamilies = [[100, 103, 107], // sm_10x + [110], // sm_11x + [120, 121]]; // sm_12x + +foreach Family = SMFamilies in + foreach sm = Family in + defm SM#sm : FeatureSMVariants< + !foreach(earlier, !filter(v, Family, !lt(v, sm)), + !cast("SM" # earlier # "f"))>; + +// sm_90 predates family-specific variants, so sm_90a is the only member of the +// sm_9x family and stands in for its 'f' variant, which does not exist. +defm SM90a : ProcSM<[SM90]>; + +// sm_101 was the name PTX 8.6 through 8.8 used for what PTX 9.0 renamed to +// sm_110. The two names describe the same hardware, so they share a node rather +// than duplicating one. +def : ProcessorAlias<"sm_101", "sm_110">; +def : ProcessorAlias<"sm_101f", "sm_110f">; +def : ProcessorAlias<"sm_101a", "sm_110a">; + +include "NVPTXRegisterInfo.td" +include "NVPTXInstrInfo.td" def Is64Bit : Predicate<"Subtarget->getTargetTriple().getArch() == Triple::nvptx64">; def NVPTX64 : HwMode<[Is64Bit]>; diff --git a/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp b/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp index 5baf092ffad24..b550e985aa243 100644 --- a/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp +++ b/llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp @@ -989,7 +989,7 @@ void NVPTXAsmPrinter::emitKernelFunctionDirectives(const Function &F, const NVPTXTargetMachine &NTM = static_cast(TM); const NVPTXSubtarget *STI = &NTM.getSubtarget(F); - if (STI->getSmVersion() >= 90) { + if (STI->hasFeature(NVPTX::SM90)) { const auto ClusterDim = getClusterDim(F); const bool BlocksAreClusters = hasBlocksAreClusters(F); @@ -1232,7 +1232,8 @@ DwarfDebug *NVPTXAsmPrinter::createDwarfDebug() { bool NVPTXAsmPrinter::doInitialization(Module &M) { const NVPTXTargetMachine &NTM = static_cast(TM); const NVPTXSubtarget &STI = *NTM.getSubtargetImpl(); - if (M.alias_size() && (STI.getPTXVersion() < 63 || STI.getSmVersion() < 30)) + if (M.alias_size() && + (STI.getPTXVersion() < 63 || !STI.hasFeature(NVPTX::SM30))) report_fatal_error(".alias requires PTX version >= 6.3 and sm_30"); // We need to call the parent's one explicitly. @@ -1540,7 +1541,7 @@ void NVPTXAsmPrinter::emitPTXGlobalVariableDefinition( emitPTXAddressSpace(GVar->getAddressSpace(), O); if (isManaged(*GVar)) { - if (STI.getPTXVersion() < 40 || STI.getSmVersion() < 30) + if (STI.getPTXVersion() < 40 || !STI.hasFeature(NVPTX::SM30)) report_fatal_error( ".attribute(.managed) requires PTX version >= 4.0 and sm_30"); O << " .attribute(.managed)"; @@ -1839,7 +1840,7 @@ void NVPTXAsmPrinter::emitPTXGlobalVariable(const GlobalVariable *GVar, O << "."; emitPTXAddressSpace(GVar->getType()->getAddressSpace(), O); if (isManaged(*GVar)) { - if (STI.getPTXVersion() < 40 || STI.getSmVersion() < 30) + if (STI.getPTXVersion() < 40 || !STI.hasFeature(NVPTX::SM30)) report_fatal_error( ".attribute(.managed) requires PTX version >= 4.0 and sm_30"); diff --git a/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp b/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp index eca3cc163b924..88f7d9495a19c 100644 --- a/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp +++ b/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp @@ -560,11 +560,11 @@ NVPTXTargetLowering::NVPTXTargetLowering(const NVPTXTargetMachine &TM, case ISD::FMINIMUM: case ISD::FMAXIMUMNUM: case ISD::FMINIMUMNUM: - IsOpSupported &= STI.getSmVersion() >= 80 && STI.getPTXVersion() >= 70; + IsOpSupported &= STI.hasFeature(NVPTX::SM80) && STI.getPTXVersion() >= 70; break; case ISD::FEXP2: case ISD::FTANH: - IsOpSupported &= STI.getSmVersion() >= 75 && STI.getPTXVersion() >= 70; + IsOpSupported &= STI.hasFeature(NVPTX::SM75) && STI.getPTXVersion() >= 70; break; } setOperationAction(Op, VT, IsOpSupported ? Action : NoF16Action); @@ -587,7 +587,7 @@ NVPTXTargetLowering::NVPTXTargetLowering(const NVPTXTargetMachine &TM, case ISD::SMIN: case ISD::UMIN: case ISD::UMAX: - IsOpSupported = STI.getSmVersion() >= 90 && STI.getPTXVersion() >= 80; + IsOpSupported = STI.hasFeature(NVPTX::SM90) && STI.getPTXVersion() >= 80; break; } setOperationAction(Op, VT, IsOpSupported ? Action : NoI16x2Action); @@ -618,7 +618,7 @@ NVPTXTargetLowering::NVPTXTargetLowering(const NVPTXTargetMachine &TM, setOperationAction(ISD::VECTOR_SHUFFLE, MVT::v2f16, Expand); setOperationAction(ISD::READCYCLECOUNTER, MVT::i64, Legal); - if (STI.getSmVersion() >= 30 && STI.getPTXVersion() > 31) + if (STI.hasFeature(NVPTX::SM30) && STI.getPTXVersion() > 31) setOperationAction(ISD::READSTEADYCOUNTER, MVT::i64, Legal); setFP16OperationAction(ISD::SETCC, MVT::f16, Legal, Promote); @@ -953,7 +953,7 @@ NVPTXTargetLowering::NVPTXTargetLowering(const NVPTXTargetMachine &TM, } // f16/f16x2 neg was introduced in PTX 60, SM_53. - const bool IsFP16FP16x2NegAvailable = STI.getSmVersion() >= 53 && + const bool IsFP16FP16x2NegAvailable = STI.hasFeature(NVPTX::SM53) && STI.getPTXVersion() >= 60 && STI.allowFP16Math(); for (const auto &VT : {MVT::f16, MVT::v2f16}) @@ -979,10 +979,10 @@ NVPTXTargetLowering::NVPTXTargetLowering(const NVPTXTargetMachine &TM, AddPromotedToType(Op, MVT::bf16, MVT::f32); } - if (STI.getSmVersion() < 80 || STI.getPTXVersion() < 71) { + if (!STI.hasFeature(NVPTX::SM80) || STI.getPTXVersion() < 71) { setOperationAction(ISD::BF16_TO_FP, MVT::f32, Expand); } - if (STI.getSmVersion() < 90 || STI.getPTXVersion() < 78) { + if (!STI.hasFeature(NVPTX::SM90) || STI.getPTXVersion() < 78) { for (MVT VT : {MVT::bf16, MVT::f32, MVT::f64}) { setOperationAction(ISD::FP_EXTEND, VT, Custom); setOperationAction(ISD::FP_ROUND, VT, Custom); @@ -996,7 +996,7 @@ NVPTXTargetLowering::NVPTXTargetLowering(const NVPTXTargetMachine &TM, // sm_80 only has conversions between f32 and bf16. Custom lower all other // bf16 conversions. - if (STI.getSmVersion() < 90 || STI.getPTXVersion() < 78) { + if (!STI.hasFeature(NVPTX::SM90) || STI.getPTXVersion() < 78) { for (MVT VT : {MVT::i1, MVT::i16, MVT::i32, MVT::i64}) { setOperationAction( {ISD::SINT_TO_FP, ISD::UINT_TO_FP, ISD::FP_TO_SINT, ISD::FP_TO_UINT}, @@ -1048,7 +1048,7 @@ NVPTXTargetLowering::NVPTXTargetLowering(const NVPTXTargetMachine &TM, // - f16/f16x2 (sm_75+, PTX 7.0+) // - bf16/bf16x2 (sm_90+, PTX 7.8+) // When f16/bf16 types aren't supported, they are promoted/expanded to f32. - if (STI.getSmVersion() >= 75 && STI.getPTXVersion() >= 70) + if (STI.hasFeature(NVPTX::SM75) && STI.getPTXVersion() >= 70) setOperationAction(ISD::FTANH, MVT::f32, Legal); setOperationAction(ISD::FTANH, MVT::v2f32, Expand); @@ -1089,7 +1089,7 @@ NVPTXTargetLowering::NVPTXTargetLowering(const NVPTXTargetMachine &TM, setOperationAction(Op, MVT::v2f32, Expand); } bool SupportsF32MinMaxNaN = - STI.getSmVersion() >= 80 && STI.getPTXVersion() >= 70; + STI.hasFeature(NVPTX::SM80) && STI.getPTXVersion() >= 70; for (const auto &Op : {ISD::FMINIMUM, ISD::FMAXIMUM}) { setOperationAction(Op, MVT::f32, SupportsF32MinMaxNaN ? Legal : Expand); setFP16OperationAction(Op, MVT::f16, Legal, Expand); @@ -1278,7 +1278,8 @@ static SDValue correctParamType(SDValue V, EVT ExpectedVT, SDValue NVPTXTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, SmallVectorImpl &InVals) const { - if (CLI.IsVarArg && (STI.getPTXVersion() < 60 || STI.getSmVersion() < 30)) + if (CLI.IsVarArg && + (STI.getPTXVersion() < 60 || !STI.hasFeature(NVPTX::SM30))) report_fatal_error( "Support for variadic functions (unsized array parameter) introduced " "in PTX ISA version 6.0 and requires target sm_30."); @@ -1681,7 +1682,7 @@ SDValue NVPTXTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, SDValue NVPTXTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const { - if (STI.getPTXVersion() < 73 || STI.getSmVersion() < 52) { + if (STI.getPTXVersion() < 73 || !STI.hasFeature(NVPTX::SM52)) { const Function &Fn = DAG.getMachineFunction().getFunction(); DAG.getContext()->diagnose(DiagnosticInfoUnsupported( @@ -1722,7 +1723,7 @@ SDValue NVPTXTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op, SDValue NVPTXTargetLowering::LowerSTACKRESTORE(SDValue Op, SelectionDAG &DAG) const { SDLoc DL(Op.getNode()); - if (STI.getPTXVersion() < 73 || STI.getSmVersion() < 52) { + if (STI.getPTXVersion() < 73 || !STI.hasFeature(NVPTX::SM52)) { const Function &Fn = DAG.getMachineFunction().getFunction(); DAG.getContext()->diagnose(DiagnosticInfoUnsupported( @@ -1744,7 +1745,7 @@ SDValue NVPTXTargetLowering::LowerSTACKRESTORE(SDValue Op, SDValue NVPTXTargetLowering::LowerSTACKSAVE(SDValue Op, SelectionDAG &DAG) const { SDLoc DL(Op.getNode()); - if (STI.getPTXVersion() < 73 || STI.getSmVersion() < 52) { + if (STI.getPTXVersion() < 73 || !STI.hasFeature(NVPTX::SM52)) { const Function &Fn = DAG.getMachineFunction().getFunction(); DAG.getContext()->diagnose(DiagnosticInfoUnsupported( @@ -1900,7 +1901,7 @@ SDValue NVPTXTargetLowering::LowerVECREDUCE(SDValue Op, // Whether we can use 3-input min/max when expanding the reduction. const bool CanUseMinMax3 = - EltTy == MVT::f32 && STI.getSmVersion() >= 100 && + EltTy == MVT::f32 && STI.hasFeature(NVPTX::SM100) && STI.getPTXVersion() >= 88 && (Opcode == ISD::VECREDUCE_FMAX || Opcode == ISD::VECREDUCE_FMIN || Opcode == ISD::VECREDUCE_FMAXIMUM || Opcode == ISD::VECREDUCE_FMINIMUM); @@ -2124,7 +2125,7 @@ SDValue NVPTXTargetLowering::LowerShiftRightParts(SDValue Op, SDValue ShAmt = Op.getOperand(2); unsigned Opc = (Op.getOpcode() == ISD::SRA_PARTS) ? ISD::SRA : ISD::SRL; - if (VTBits == 32 && STI.getSmVersion() >= 35) { + if (VTBits == 32 && STI.hasFeature(NVPTX::SM35)) { // For 32bit and sm35, we can use the funnel shift 'shf' instruction. // {dHi, dLo} = {aHi, aLo} >> Amt // dHi = aHi >> Amt @@ -2136,8 +2137,7 @@ SDValue NVPTXTargetLowering::LowerShiftRightParts(SDValue Op, SDValue Ops[2] = { Lo, Hi }; return DAG.getMergeValues(Ops, dl); - } - else { + } else { // {dHi, dLo} = {aHi, aLo} >> Amt // - if (Amt>=size) then // dLo = aHi >> (Amt-size) @@ -2184,7 +2184,7 @@ SDValue NVPTXTargetLowering::LowerShiftLeftParts(SDValue Op, SDValue ShOpHi = Op.getOperand(1); SDValue ShAmt = Op.getOperand(2); - if (VTBits == 32 && STI.getSmVersion() >= 35) { + if (VTBits == 32 && STI.hasFeature(NVPTX::SM35)) { // For 32bit and sm35, we can use the funnel shift 'shf' instruction. // {dHi, dLo} = {aHi, aLo} << Amt // dHi = shf.l.clamp aLo, aHi, Amt @@ -2196,8 +2196,7 @@ SDValue NVPTXTargetLowering::LowerShiftLeftParts(SDValue Op, SDValue Ops[2] = { Lo, Hi }; return DAG.getMergeValues(Ops, dl); - } - else { + } else { // {dHi, dLo} = {aHi, aLo} << Amt // - if (Amt>=size) then // dLo = aLo << Amt (all 0) @@ -2359,7 +2358,7 @@ SDValue NVPTXTargetLowering::PromoteBinOpIfF32FTZ(SDValue Op, SDValue NVPTXTargetLowering::LowerINT_TO_FP(SDValue Op, SelectionDAG &DAG) const { - assert(STI.getSmVersion() < 90 || STI.getPTXVersion() < 78); + assert(!STI.hasFeature(NVPTX::SM90) || STI.getPTXVersion() < 78); if (Op.getValueType() == MVT::bf16) { SDLoc Loc(Op); @@ -2375,7 +2374,7 @@ SDValue NVPTXTargetLowering::LowerINT_TO_FP(SDValue Op, SDValue NVPTXTargetLowering::LowerFP_TO_INT(SDValue Op, SelectionDAG &DAG) const { - assert(STI.getSmVersion() < 90 || STI.getPTXVersion() < 78); + assert(!STI.hasFeature(NVPTX::SM90) || STI.getPTXVersion() < 78); if (Op.getOperand(0).getValueType() == MVT::bf16) { SDLoc Loc(Op); @@ -2395,12 +2394,12 @@ SDValue NVPTXTargetLowering::LowerFP_ROUND(SDValue Op, EVT WideVT = Wide.getValueType(); if (NarrowVT.getScalarType() == MVT::bf16) { const TargetLowering *TLI = STI.getTargetLowering(); - if (STI.getSmVersion() < 80 || STI.getPTXVersion() < 70) { + if (!STI.hasFeature(NVPTX::SM80) || STI.getPTXVersion() < 70) { return TLI->expandFP_ROUND(Op.getNode(), DAG); } - if (STI.getSmVersion() < 90 || STI.getPTXVersion() < 78) { + if (!STI.hasFeature(NVPTX::SM90) || STI.getPTXVersion() < 78) { // This combination was the first to support f32 -> bf16. - if (STI.getSmVersion() >= 80 && STI.getPTXVersion() >= 70) { + if (STI.hasFeature(NVPTX::SM80) && STI.getPTXVersion() >= 70) { if (WideVT.getScalarType() == MVT::f32) { return Op; } @@ -2429,15 +2428,15 @@ SDValue NVPTXTargetLowering::LowerFP_EXTEND(SDValue Op, EVT WideVT = Op.getValueType(); if (NarrowVT.getScalarType() == MVT::bf16) { if (WideVT.getScalarType() == MVT::f32 && - (STI.getSmVersion() < 80 || STI.getPTXVersion() < 71)) { + (!STI.hasFeature(NVPTX::SM80) || STI.getPTXVersion() < 71)) { SDLoc Loc(Op); return DAG.getNode(ISD::BF16_TO_FP, Loc, WideVT, Narrow); } if (WideVT.getScalarType() == MVT::f64 && - (STI.getSmVersion() < 90 || STI.getPTXVersion() < 78)) { + (!STI.hasFeature(NVPTX::SM90) || STI.getPTXVersion() < 78)) { EVT F32 = NarrowVT.changeElementType(*DAG.getContext(), MVT::f32); SDLoc Loc(Op); - if (STI.getSmVersion() >= 80 && STI.getPTXVersion() >= 71) { + if (STI.hasFeature(NVPTX::SM80) && STI.getPTXVersion() >= 71) { Op = DAG.getNode(ISD::FP_EXTEND, Loc, F32, Narrow); } else { Op = DAG.getNode(ISD::BF16_TO_FP, Loc, F32, Narrow); @@ -5655,7 +5654,7 @@ NVPTXTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, case 'd': return std::make_pair(0U, &NVPTX::B64RegClass); case 'q': { - if (STI.getSmVersion() < 70) + if (!STI.hasFeature(NVPTX::SM70)) report_fatal_error("Inline asm with 128 bit operands is only " "supported for sm_70 and higher!"); return std::make_pair(0U, &NVPTX::B128RegClass); @@ -6265,11 +6264,12 @@ static unsigned getMinMax3Opcode(unsigned MinMax2Opcode) { /// (fmaxnum3 a, b, c). Also covers other llvm min/max intrinsics. static SDValue PerformFMinMaxCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, - unsigned PTXVersion, unsigned SmVersion) { + const NVPTXSubtarget &STI) { // 3-input min/max requires PTX 8.8+ and SM_100+, and only supports f32s EVT VT = N->getValueType(0); - if (VT != MVT::f32 || PTXVersion < 88 || SmVersion < 100) + if (VT != MVT::f32 || STI.getPTXVersion() < 88 || + !STI.hasFeature(NVPTX::SM100)) return SDValue(); SDValue Op0 = N->getOperand(0); @@ -6633,7 +6633,7 @@ static SDValue PerformSHLCombine(SDNode *N, static SDValue PerformSETCCCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, - unsigned int SmVersion) { + const NVPTXSubtarget &STI) { EVT CCType = N->getValueType(0); SDValue A = N->getOperand(0); SDValue B = N->getOperand(1); @@ -6642,7 +6642,7 @@ static SDValue PerformSETCCCombine(SDNode *N, if (!(CCType == MVT::v2i1 && (AType == MVT::v2f16 || AType == MVT::v2bf16))) return SDValue(); - if (A.getValueType() == MVT::v2bf16 && SmVersion < 90) + if (A.getValueType() == MVT::v2bf16 && !STI.hasFeature(NVPTX::SM90)) return SDValue(); SDLoc DL(N); @@ -7117,8 +7117,7 @@ SDValue NVPTXTargetLowering::PerformDAGCombine(SDNode *N, case ISD::FMINIMUM: case ISD::FMAXIMUMNUM: case ISD::FMINIMUMNUM: - return PerformFMinMaxCombine(N, DCI, STI.getPTXVersion(), - STI.getSmVersion()); + return PerformFMinMaxCombine(N, DCI, STI); case ISD::LOAD: case NVPTXISD::LoadV2: case NVPTXISD::LoadV4: @@ -7130,7 +7129,7 @@ SDValue NVPTXTargetLowering::PerformDAGCombine(SDNode *N, case NVPTXISD::ProxyReg: return combineProxyReg(N, DCI); case ISD::SETCC: - return PerformSETCCCombine(N, DCI, STI.getSmVersion()); + return PerformSETCCCombine(N, DCI, STI); case ISD::SHL: return PerformSHLCombine(N, DCI, OptLevel); case ISD::SREM: @@ -7506,10 +7505,10 @@ NVPTXTargetLowering::shouldExpandAtomicRMWInIR(const AtomicRMWInst *AI) const { } if (Ty->isHalfTy() && (!FTZ || AllowFTZAtomics) && - STI.getSmVersion() >= 70 && STI.getPTXVersion() >= 63) + STI.hasFeature(NVPTX::SM70) && STI.getPTXVersion() >= 63) return AtomicExpansionKind::None; - if (Ty->isBFloatTy() && STI.getSmVersion() >= 90 && + if (Ty->isBFloatTy() && STI.hasFeature(NVPTX::SM90) && STI.getPTXVersion() >= 78) return AtomicExpansionKind::None; diff --git a/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td b/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td index 0fcdd05756e86..83060bb906157 100644 --- a/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td +++ b/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td @@ -125,20 +125,6 @@ def AddrSpaceSharedCluster : NVPTXAddressSpace<"ADDRESS_SPACE_SHARED_CLUSTER", // NVPTX Instruction Predicate Definitions //===----------------------------------------------------------------------===// -// Checks PTX version and family-specific and architecture-specific SM versions. -// For example, sm_100{f/a} and any future variants in the same family will match -// for any PTX version greater than or equal to `PTXVersion`. -class PTXWithFamilySMs SMVersions> : - Predicate<"Subtarget->hasPTXWithFamilySMs(" # PTXVersion # ", {" # - !interleave(SMVersions, ", ") # "})">; - -// Checks PTX version and architecture-specific SM versions. -// For example, sm_100{a} will match for any PTX version -// greater than or equal to `PTXVersion`. -class PTXWithAccelSMs SMVersions> : - Predicate<"Subtarget->hasPTXWithAccelSMs(" # PTXVersion # ", {" # - !interleave(SMVersions, ", ") # "})">; - // Helper predicate to call a subtarget method. class callSubtarget : Predicate<"Subtarget->" # SubtargetMethod # "()">; @@ -151,8 +137,6 @@ def hasClusters : Predicate<"Subtarget->hasClusters()">; def hasPTXASUnreachableBug : Predicate<"Subtarget->hasPTXASUnreachableBug()">; def noPTXASUnreachableBug : Predicate<"!Subtarget->hasPTXASUnreachableBug()">; def hasOptEnabled : Predicate<"TM.getOptLevel() != CodeGenOptLevel::None">; -def hasArchAccelFeatures : Predicate<"Subtarget->hasArchAccelFeatures()">; -def hasFamilySpecificFeatures : Predicate<"Subtarget->hasFamilySpecificFeatures()">; def doF32FTZ : Predicate<"useF32FTZ()">; def doNoF32FTZ : Predicate<"!useF32FTZ()">; @@ -165,21 +149,9 @@ def hasDotInstructions : Predicate<"Subtarget->hasDotInstructions()">; def hasF32x2Instructions : Predicate<"Subtarget->hasF32x2Instructions()">; class hasPTX: Predicate<"Subtarget->getPTXVersion() >= " # version>; -class hasSM: Predicate<"Subtarget->getSmVersion() >= " # version>; - -// Explicit records for arch-accelerated SM versions -def hasSM90a : Predicate<"Subtarget->getSmVersion() == 90 && Subtarget->hasArchAccelFeatures()">; -def hasSM100a : Predicate<"Subtarget->getSmVersion() == 100 && Subtarget->hasArchAccelFeatures()">; -def hasSM101a : Predicate<"Subtarget->getSmVersion() == 101 && Subtarget->hasArchAccelFeatures()">; -def hasSM120a : Predicate<"Subtarget->getSmVersion() == 120 && Subtarget->hasArchAccelFeatures()">; - -def hasSM100aOrSM103a : - Predicate<"(Subtarget->getSmVersion() == 100 || " # - "Subtarget->getSmVersion() == 103) " # - "&& Subtarget->hasArchAccelFeatures()">; // non-sync shfl instructions are not available on sm_70+ in PTX6.4+ -def hasSHFL : Predicate<"!(Subtarget->getSmVersion() >= 70" +def hasSHFL : Predicate<"!(Subtarget->hasFeature(NVPTX::SM70)" "&& Subtarget->getPTXVersion() >= 64)">; def useFP16Math: Predicate<"Subtarget->allowFP16Math()">; @@ -326,7 +298,7 @@ class I16x2 : BasicNVPTXInst<(outs B32:$dst), (ins B32:$a, B32:$b), OpcStr # "16x2", [(set v2i16:$dst, (OpNode v2i16:$a, v2i16:$b))]>, - Requires<[hasPTX<80>, hasSM<90>]>; + Requires<[hasPTX<80>, SM90]>; // Template for instructions which take 3 int args. The instructions are // named ".s32" (e.g. "addc.cc.s32"). @@ -383,19 +355,19 @@ multiclass FMINIMUMMAXIMUM { (ins FTZFlag:$ftz), OpcStr # "$ftz" # nan_str # ".f16x2", [(set v2f16:$dst, (OpNode v2f16:$a, v2f16:$b))]>, - Requires<[useFP16Math, hasSM<80>, hasPTX<70>]>; + Requires<[useFP16Math, SM80, hasPTX<70>]>; def _bf16_rr : BasicNVPTXInst<(outs B16:$dst), (ins B16:$a, B16:$b), OpcStr # nan_str # ".bf16", [(set bf16:$dst, (OpNode bf16:$a, bf16:$b))]>, - Requires<[hasBF16Math, hasSM<80>, hasPTX<70>]>; + Requires<[hasBF16Math, SM80, hasPTX<70>]>; def _bf16x2_rr : BasicNVPTXInst<(outs B32:$dst), (ins B32:$a, B32:$b), OpcStr # nan_str # ".bf16x2", [(set v2bf16:$dst, (OpNode v2bf16:$a, v2bf16:$b))]>, - Requires<[hasBF16Math, hasSM<80>, hasPTX<70>]>; + Requires<[hasBF16Math, SM80, hasPTX<70>]>; } // Template for 3-input minimum/maximum instructions @@ -411,21 +383,21 @@ multiclass FMINIMUMMAXIMUM3 { (ins FTZFlag:$ftz), OpcStr # "$ftz" # nan_str # ".f32", [(set f32:$dst, (OpNode f32:$a, f32:$b, f32:$c))]>, - Requires<[hasPTX<88>, hasSM<100>]>; + Requires<[hasPTX<88>, SM100]>; def f32rri : BasicFlagsNVPTXInst<(outs B32:$dst), (ins B32:$a, B32:$b, f32imm:$c), (ins FTZFlag:$ftz), OpcStr # "$ftz" # nan_str # ".f32", [(set f32:$dst, (OpNode f32:$a, f32:$b, fpimm:$c))]>, - Requires<[hasPTX<88>, hasSM<100>]>; + Requires<[hasPTX<88>, SM100]>; def f32rii : BasicFlagsNVPTXInst<(outs B32:$dst), (ins B32:$a, f32imm:$b, f32imm:$c), (ins FTZFlag:$ftz), OpcStr # "$ftz" # nan_str # ".f32", [(set f32:$dst, (OpNode f32:$a, fpimm:$b, fpimm:$c))]>, - Requires<[hasPTX<88>, hasSM<100>]>; + Requires<[hasPTX<88>, SM100]>; } // Template for instructions which take three FP args. The @@ -525,21 +497,21 @@ multiclass F2_Support_Half { def bf16 : BasicNVPTXInst<(outs B16:$dst), (ins B16:$a), OpcStr # ".bf16", [(set bf16:$dst, (OpNode bf16:$a))]>, - Requires<[hasSM<80>, hasPTX<70>]>; + Requires<[SM80, hasPTX<70>]>; def bf16x2 : BasicNVPTXInst<(outs B32:$dst), (ins B32:$a), OpcStr # ".bf16x2", [(set v2bf16:$dst, (OpNode v2bf16:$a))]>, - Requires<[hasSM<80>, hasPTX<70>]>; + Requires<[SM80, hasPTX<70>]>; def f16 : BasicFlagsNVPTXInst<(outs B16:$dst), (ins B16:$a), (ins FTZFlag:$ftz), OpcStr # "$ftz.f16", [(set f16:$dst, (OpNode f16:$a))]>, - Requires<[hasSM<53>, hasPTX<65>]>; + Requires<[SM53, hasPTX<65>]>; def f16x2 : BasicFlagsNVPTXInst<(outs B32:$dst), (ins B32:$a), (ins FTZFlag:$ftz), OpcStr # "$ftz.f16x2", [(set v2f16:$dst, (OpNode v2f16:$a))]>, - Requires<[hasSM<53>, hasPTX<65>]>; + Requires<[SM53, hasPTX<65>]>; } @@ -589,16 +561,16 @@ let hasSideEffects = false in { "cvt${mode:base}${mode:ftz}${mode:relu}${mode:sat}." # ToType # ".bf16">, Requiresf32 was introduced early. - [hasPTX<71>, hasSM<80>], + [hasPTX<71>, SM80], // bf16->everything else needs sm90/ptx78 - [hasPTX<78>, hasSM<90>])>; + [hasPTX<78>, SM90])>; def _f32 : BasicFlagsNVPTXInst<(outs RC:$dst), (ins B32:$src), (ins CvtMode:$mode), "cvt${mode:base}${mode:ftz}${mode:relu}${mode:sat}." # ToType # ".f32">, Requiresbf16 was introduced early. - [hasPTX<70>, hasSM<80>], + [hasPTX<70>, SM80], Preds)>; def _f64 : BasicFlagsNVPTXInst<(outs RC:$dst), @@ -615,7 +587,7 @@ let hasSideEffects = false in { defm CVT_ # sign # "64" : CVT_FROM_ALL; } defm CVT_f16 : CVT_FROM_ALL<"f16", B16>; - defm CVT_bf16 : CVT_FROM_ALL<"bf16", B16, [hasPTX<78>, hasSM<90>]>; + defm CVT_bf16 : CVT_FROM_ALL<"bf16", B16, [hasPTX<78>, SM90]>; defm CVT_f32 : CVT_FROM_ALL<"f32", B32>; defm CVT_f64 : CVT_FROM_ALL<"f64", B64>; @@ -642,7 +614,7 @@ let hasSideEffects = false in { BasicFlagsNVPTXInst<(outs RC:$dst), (ins B32:$src1, B32:$src2), (ins CvtMode:$mode), "cvt${mode:base}${mode:relu}." # FromName # ".f32">, - Requires<[hasPTX<70>, hasSM<80>]>; + Requires<[hasPTX<70>, SM80]>; def _f32_sf : BasicFlagsNVPTXInst<(outs RC:$dst), @@ -676,12 +648,12 @@ let hasSideEffects = false in { BasicFlagsNVPTXInst<(outs B16:$dst), (ins B32:$src1, B32:$src2), (ins CvtMode:$mode), "cvt${mode:base}.satfinite${mode:relu}." # F8Name # "x2.f32">, - Requires<[hasPTX<81>, hasSM<89>]>; + Requires<[hasPTX<81>, SM89]>; def _f16x2 : BasicFlagsNVPTXInst<(outs B16:$dst), (ins B32:$src), (ins CvtMode:$mode), "cvt${mode:base}.satfinite${mode:relu}." # F8Name # "x2.f16x2">, - Requires<[hasPTX<81>, hasSM<89>]>; + Requires<[hasPTX<81>, SM89]>; def _bf16x2 : BasicFlagsNVPTXInst<(outs B16:$dst), (ins B32:$src), (ins CvtMode:$mode), "cvt${mode:base}.satfinite${mode:relu}." # F8Name # "x2.bf16x2">, @@ -696,7 +668,7 @@ let hasSideEffects = false in { BasicFlagsNVPTXInst<(outs B32:$dst), (ins B16:$src), (ins CvtMode:$mode), "cvt${mode:base}${mode:relu}.f16x2." # F8Name # "x2">, - Requires<[hasPTX<81>, hasSM<89>]>; + Requires<[hasPTX<81>, SM89]>; def bf16x2_ # F8Name # x2_scale : BasicFlagsNVPTXInst<(outs B32:$dst), (ins B16:$src, B16:$src2), (ins CvtMode:$mode), @@ -717,7 +689,7 @@ let hasSideEffects = false in { def CVT_e5m2x4_f32x4_rs_sf : CVT_TO_FP8X4<"e5m2">; // Float to TF32 conversions - multiclass CVT_TO_TF32 Preds = [hasPTX<78>, hasSM<90>]> { + multiclass CVT_TO_TF32 Preds = [hasPTX<78>, SM90]> { defvar Intr = !cast("int_nvvm_f2tf32_" # !subst(".", "_", Modifier)); def NAME : BasicNVPTXInst<(outs B32:$dst), (ins B32:$src), @@ -730,13 +702,13 @@ let hasSideEffects = false in { defm CVT_to_tf32_rz : CVT_TO_TF32<"rz">; defm CVT_to_tf32_rn_relu : CVT_TO_TF32<"rn.relu">; defm CVT_to_tf32_rz_relu : CVT_TO_TF32<"rz.relu">; - defm CVT_to_tf32_rna : CVT_TO_TF32<"rna", [hasPTX<70>, hasSM<80>]>; - defm CVT_to_tf32_rna_satf : CVT_TO_TF32<"rna.satfinite", [hasPTX<81>, hasSM<80>]>; + defm CVT_to_tf32_rna : CVT_TO_TF32<"rna", [hasPTX<70>, SM80]>; + defm CVT_to_tf32_rna_satf : CVT_TO_TF32<"rna.satfinite", [hasPTX<81>, SM80]>; - defm CVT_to_tf32_rn_satf : CVT_TO_TF32<"rn.satfinite", [hasPTX<86>, hasSM<100>]>; - defm CVT_to_tf32_rz_satf : CVT_TO_TF32<"rz.satfinite", [hasPTX<86>, hasSM<100>]>; - defm CVT_to_tf32_rn_relu_satf : CVT_TO_TF32<"rn.relu.satfinite", [hasPTX<86>, hasSM<100>]>; - defm CVT_to_tf32_rz_relu_satf : CVT_TO_TF32<"rz.relu.satfinite", [hasPTX<86>, hasSM<100>]>; + defm CVT_to_tf32_rn_satf : CVT_TO_TF32<"rn.satfinite", [hasPTX<86>, SM100]>; + defm CVT_to_tf32_rz_satf : CVT_TO_TF32<"rz.satfinite", [hasPTX<86>, SM100]>; + defm CVT_to_tf32_rn_relu_satf : CVT_TO_TF32<"rn.relu.satfinite", [hasPTX<86>, SM100]>; + defm CVT_to_tf32_rz_relu_satf : CVT_TO_TF32<"rz.relu.satfinite", [hasPTX<86>, SM100]>; let Predicates = [callSubtarget<"hasS2F6X2ConversionSupport">] in { def CVT_s2f6x2_f32_sf_scale : BasicFlagsNVPTXInst<(outs B16:$dst), @@ -875,12 +847,12 @@ def fpround_oneuse : OneUse1; def : Pat<(v2bf16 (build_vector (bf16 (fpround_oneuse f32:$lo)), (bf16 (fpround_oneuse f32:$hi)))), (CVT_bf16x2_f32 $hi, $lo, CvtRN)>, - Requires<[hasPTX<70>, hasSM<80>, hasBF16Math]>; + Requires<[hasPTX<70>, SM80, hasBF16Math]>; def : Pat<(v2f16 (build_vector (f16 (fpround_oneuse f32:$lo)), (f16 (fpround_oneuse f32:$hi)))), (CVT_f16x2_f32 $hi, $lo, CvtRN)>, - Requires<[hasPTX<70>, hasSM<80>, useFP16Math]>; + Requires<[hasPTX<70>, SM80, useFP16Math]>; //----------------------------------- // Selection instructions (selp) @@ -1011,7 +983,7 @@ def UMAX16x2 : I16x2<"max.u", umax>; def SMIN16x2 : I16x2<"min.s", smin>; def UMIN16x2 : I16x2<"min.u", umin>; -let Predicates = [hasPTX<80>, hasSM<90>] in { +let Predicates = [hasPTX<80>, SM90] in { def MIN_RELU_S32 : BasicNVPTXInst<(outs B32:$dst), (ins B32:$a, B32:$b), "min.relu.s32", @@ -1145,7 +1117,7 @@ class FNEG16 : "neg$ftz." # t.PtxType, [(set t.Ty:$dst, (fneg t.Ty:$src))]>; -let Predicates = [useFP16Math, hasPTX<60>, hasSM<53>] in { +let Predicates = [useFP16Math, hasPTX<60>, SM53] in { def NEG_F16 : FNEG16; def NEG_F16x2 : FNEG16; } @@ -1161,11 +1133,11 @@ class FEXP2Inst : def EX2_APPROX_f32 : FEXP2Inst; -let Predicates = [useFP16Math, hasPTX<70>, hasSM<75>] in { +let Predicates = [useFP16Math, hasPTX<70>, SM75] in { def EX2_APPROX_f16 : FEXP2Inst; def EX2_APPROX_f16x2 : FEXP2Inst; } -let Predicates = [hasPTX<78>, hasSM<90>] in { +let Predicates = [hasPTX<78>, SM90] in { def EX2_APPROX_bf16 : FEXP2Inst; def EX2_APPROX_bf16x2 : FEXP2Inst; } @@ -1347,13 +1319,13 @@ class FTANHInst : [(set t.Ty:$dst, (UnaryOpAllowsApproxFn t.Ty:$src))]>; def TANH_APPROX_f32 : FTANHInst, - Requires<[hasPTX<70>, hasSM<75>]>; + Requires<[hasPTX<70>, SM75]>; -let Predicates = [useFP16Math, hasPTX<70>, hasSM<75>] in { +let Predicates = [useFP16Math, hasPTX<70>, SM75] in { def TANH_APPROX_f16 : FTANHInst; def TANH_APPROX_f16x2 : FTANHInst; } -let Predicates = [hasPTX<78>, hasSM<90>] in { +let Predicates = [hasPTX<78>, SM90] in { def TANH_APPROX_bf16 : FTANHInst; def TANH_APPROX_bf16x2 : FTANHInst; } @@ -1684,7 +1656,7 @@ defm SETP_f32 : FSETP; defm SETP_f64 : FSETP; let Predicates = [useFP16Math] in defm SETP_f16 : FSETP; -let Predicates = [hasBF16Math, hasPTX<78>, hasSM<90>] in +let Predicates = [hasBF16Math, hasPTX<78>, SM90] in defm SETP_bf16 : FSETP; def SETP_f16x2rr : @@ -1697,7 +1669,7 @@ def SETP_bf16x2rr : BasicFlagsNVPTXInst<(outs B1:$p, B1:$q), (ins B32:$a, B32:$b), (ins CmpMode:$cmp), "setp.${cmp:FCmp}.bf16x2">, - Requires<[hasBF16Math, hasPTX<78>, hasSM<90>]>; + Requires<[hasBF16Math, hasPTX<78>, SM90]>; //----------------------------------- // Data Movement (Load / Store, Move) @@ -2118,7 +2090,7 @@ def : Pat<(f16 (uint_to_fp i32:$a)), (CVT_f16_u32 $a, CvtRN)>; def : Pat<(f16 (uint_to_fp i64:$a)), (CVT_f16_u64 $a, CvtRN)>; // sint -> bf16 -let Predicates = [hasPTX<78>, hasSM<90>] in { +let Predicates = [hasPTX<78>, SM90] in { def : Pat<(bf16 (sint_to_fp i1:$a)), (CVT_bf16_s32 (SELP_b32ii -1, 0, $a), CvtRN)>; def : Pat<(bf16 (sint_to_fp i16:$a)), (CVT_bf16_s16 $a, CvtRN)>; def : Pat<(bf16 (sint_to_fp i32:$a)), (CVT_bf16_s32 $a, CvtRN)>; @@ -2126,7 +2098,7 @@ let Predicates = [hasPTX<78>, hasSM<90>] in { } // uint -> bf16 -let Predicates = [hasPTX<78>, hasSM<90>] in { +let Predicates = [hasPTX<78>, SM90] in { def : Pat<(bf16 (uint_to_fp i1:$a)), (CVT_bf16_u32 (SELP_b32ii 1, 0, $a), CvtRN)>; def : Pat<(bf16 (uint_to_fp i16:$a)), (CVT_bf16_u16 $a, CvtRN)>; def : Pat<(bf16 (uint_to_fp i32:$a)), (CVT_bf16_u32 $a, CvtRN)>; @@ -2442,14 +2414,14 @@ def : Pat<(f16 (fpround f32:$a)), (CVT_f16_f32 $a, CvtRN)>; // fpround f32 -> bf16 def : Pat<(bf16 (fpround f32:$a)), (CVT_bf16_f32 $a, CvtRN)>, - Requires<[hasPTX<70>, hasSM<80>]>; + Requires<[hasPTX<70>, SM80]>; // fpround f64 -> f16 def : Pat<(f16 (fpround f64:$a)), (CVT_f16_f64 $a, CvtRN)>; // fpround f64 -> bf16 def : Pat<(bf16 (fpround f64:$a)), (CVT_bf16_f64 $a, CvtRN)>, - Requires<[hasPTX<78>, hasSM<90>]>; + Requires<[hasPTX<78>, SM90]>; // fpround f64 -> f32 def : Pat<(f32 (fpround f64:$a)), (CVT_f32_f64 $a, CvtRN_FTZ)>, Requires<[doF32FTZ]>; @@ -2459,14 +2431,14 @@ def : Pat<(f32 (fpround f64:$a)), (CVT_f32_f64 $a, CvtRN)>; def : Pat<(f32 (fpextend f16:$a)), (CVT_f32_f16 $a, CvtNONE_FTZ)>, Requires<[doF32FTZ]>; def : Pat<(f32 (fpextend f16:$a)), (CVT_f32_f16 $a, CvtNONE)>; // fpextend bf16 -> f32 -def : Pat<(f32 (fpextend bf16:$a)), (CVT_f32_bf16 $a, CvtNONE_FTZ)>, Requires<[doF32FTZ, hasPTX<78>, hasSM<90>]>; -def : Pat<(f32 (fpextend bf16:$a)), (CVT_f32_bf16 $a, CvtNONE)>, Requires<[hasPTX<71>, hasSM<80>]>; +def : Pat<(f32 (fpextend bf16:$a)), (CVT_f32_bf16 $a, CvtNONE_FTZ)>, Requires<[doF32FTZ, hasPTX<78>, SM90]>; +def : Pat<(f32 (fpextend bf16:$a)), (CVT_f32_bf16 $a, CvtNONE)>, Requires<[hasPTX<71>, SM80]>; // fpextend f16 -> f64 def : Pat<(f64 (fpextend f16:$a)), (CVT_f64_f16 $a, CvtNONE)>; // fpextend bf16 -> f64 -def : Pat<(f64 (fpextend bf16:$a)), (CVT_f64_bf16 $a, CvtNONE)>, Requires<[hasPTX<78>, hasSM<90>]>; +def : Pat<(f64 (fpextend bf16:$a)), (CVT_f64_bf16 $a, CvtNONE)>, Requires<[hasPTX<78>, SM90]>; // fpextend f32 -> f64 def : Pat<(f64 (fpextend f32:$a)), (CVT_f64_f32 $a, CvtNONE_FTZ)>, Requires<[doF32FTZ]>; @@ -2539,7 +2511,7 @@ foreach t = [I32RT, I64RT] in { (ins t.RC:$size, i32imm:$align), "alloca.u" # t.Size, [(set t.Ty:$ptr, (dyn_alloca t.Ty:$size, timm:$align))]>, - Requires<[hasPTX<73>, hasSM<52>]>; + Requires<[hasPTX<73>, SM52]>; } // @@ -2598,7 +2570,7 @@ def stacksave : SDNode<"NVPTXISD::STACKSAVE", SDTIntLeaf, [SDNPHasChain, SDNPSideEffect]>; -let Predicates = [hasPTX<73>, hasSM<52>] in { +let Predicates = [hasPTX<73>, SM52] in { foreach t = [I32RT, I64RT] in { def STACKRESTORE_ # t.Size : BasicNVPTXInst<(outs), (ins t.RC:$ptr), @@ -2620,7 +2592,7 @@ include "NVPTXIntrinsics.td" class NVPTXFenceInst: BasicNVPTXInst<(outs), (ins), "fence."#sem#"."#scope>, - Requires<[ptx, hasSM<70>]>; + Requires<[ptx, SM70]>; foreach scope = ["sys", "gpu", "cluster", "cta"] in { def atomic_thread_fence_seq_cst_#scope: NVPTXFenceInst>; @@ -2648,12 +2620,12 @@ class FMARELUInst "fma.rn" # !if(allow_ftz, "$ftz", "") # ".relu." # t.PtxType, [(set t.Ty:$dst, (NVPTX_fmaxnum_or_fmaximumnum_nsz (NVPTX_fma_oneuse_and_nnan t.Ty:$a, t.Ty:$b, t.Ty:$c), zero_pat))]>; -let Predicates = [useFP16Math, hasPTX<70>, hasSM<80>] in { +let Predicates = [useFP16Math, hasPTX<70>, SM80] in { def FMARELU_F16 : FMARELUInst; def FMARELU_F16X2 : FMARELUInst>; } -let Predicates = [hasBF16Math, hasPTX<70>, hasSM<80>] in { +let Predicates = [hasBF16Math, hasPTX<70>, SM80] in { def FMARELU_BF16 : FMARELUInst; def FMARELU_BF16X2 : FMARELUInst>; } diff --git a/llvm/lib/Target/NVPTX/NVPTXIntrinsics.td b/llvm/lib/Target/NVPTX/NVPTXIntrinsics.td index 9e01a6f8427db..baa4be7c0d708 100644 --- a/llvm/lib/Target/NVPTX/NVPTXIntrinsics.td +++ b/llvm/lib/Target/NVPTX/NVPTXIntrinsics.td @@ -92,10 +92,10 @@ let isConvergent = true in { def INT_BAR_WARP_SYNC_I : BasicNVPTXInst<(outs), (ins i32imm:$i), "bar.warp.sync", [(int_nvvm_bar_warp_sync imm:$i)]>, - Requires<[hasPTX<60>, hasSM<30>]>; + Requires<[hasPTX<60>, SM30]>; def INT_BAR_WARP_SYNC_R : BasicNVPTXInst<(outs), (ins B32:$i), "bar.warp.sync", [(int_nvvm_bar_warp_sync i32:$i)]>, - Requires<[hasPTX<60>, hasSM<30>]>; + Requires<[hasPTX<60>, SM30]>; multiclass BARRIER_ALL requires = []> { let Predicates = requires in { @@ -166,7 +166,7 @@ defm BARRIER_CTA_RED_AND_COUNT : BARRIER_RED_COUNT<"barrier.red.and.pred", int_n defm BARRIER_CTA_RED_OR_COUNT : BARRIER_RED_COUNT<"barrier.red.or.pred", int_nvvm_barrier_cta_red_or_count, I1RT, [hasPTX<60>]>; class INT_BARRIER_CLUSTER Preds = [hasPTX<78>, hasSM<90>]>: + list Preds = [hasPTX<78>, SM90]>: BasicNVPTXInst<(outs), (ins), "barrier.cluster."# variant, [(Intr)]>, Requires; @@ -174,7 +174,7 @@ def barrier_cluster_arrive: INT_BARRIER_CLUSTER<"arrive", int_nvvm_barrier_cluster_arrive>; def barrier_cluster_arrive_relaxed: INT_BARRIER_CLUSTER<"arrive.relaxed", - int_nvvm_barrier_cluster_arrive_relaxed, [hasPTX<80>, hasSM<90>]>; + int_nvvm_barrier_cluster_arrive_relaxed, [hasPTX<80>, SM90]>; def barrier_cluster_wait: INT_BARRIER_CLUSTER<"wait", int_nvvm_barrier_cluster_wait>; @@ -183,7 +183,7 @@ def barrier_cluster_arrive_aligned: INT_BARRIER_CLUSTER<"arrive.aligned", int_nvvm_barrier_cluster_arrive_aligned>; def barrier_cluster_arrive_relaxed_aligned: INT_BARRIER_CLUSTER<"arrive.relaxed.aligned", - int_nvvm_barrier_cluster_arrive_relaxed_aligned, [hasPTX<80>, hasSM<90>]>; + int_nvvm_barrier_cluster_arrive_relaxed_aligned, [hasPTX<80>, SM90]>; def barrier_cluster_wait_aligned: INT_BARRIER_CLUSTER<"wait.aligned", int_nvvm_barrier_cluster_wait_aligned>; @@ -223,7 +223,7 @@ foreach sync = [false, true] in { InOperandList, "shfl." # !if(sync, "sync.", "") # mode # ".b32", [Pattern]>, - Requires, hasPTX<60>], [hasSM<30>, hasSHFL])>; + Requires], [SM30, hasSHFL])>; } } } @@ -233,7 +233,7 @@ foreach sync = [false, true] in { } // vote.{all,any,uni,ballot} -let Predicates = [hasPTX<60>, hasSM<30>] in { +let Predicates = [hasPTX<60>, SM30] in { multiclass VOTE { def : BasicNVPTXInst<(outs t.RC:$dest), (ins B1:$pred), "vote." # mode # "." # t.PtxType, @@ -261,7 +261,7 @@ let Predicates = [hasPTX<60>, hasSM<30>] in { defm VOTE_SYNC_BALLOT : VOTE_SYNC<"ballot", I32RT, int_nvvm_vote_ballot_sync>; } // elect.sync -let Predicates = [hasPTX<80>, hasSM<90>] in { +let Predicates = [hasPTX<80>, SM90] in { def INT_ELECT_SYNC_I : BasicNVPTXInst<(outs B32:$dest, B1:$pred), (ins i32imm:$mask), "elect.sync", [(set i32:$dest, i1:$pred, (int_nvvm_elect_sync imm:$mask))]>; @@ -270,7 +270,7 @@ def INT_ELECT_SYNC_R : BasicNVPTXInst<(outs B32:$dest, B1:$pred), (ins B32:$mask [(set i32:$dest, i1:$pred, (int_nvvm_elect_sync i32:$mask))]>; } -let Predicates = [hasPTX<60>, hasSM<70>] in { +let Predicates = [hasPTX<60>, SM70] in { multiclass MATCH_ANY_SYNC { def ii : BasicNVPTXInst<(outs B32:$dest), (ins t.Imm:$value, i32imm:$mask), "match.any.sync." # t.PtxType, @@ -315,13 +315,13 @@ let Predicates = [hasPTX<60>, hasSM<70>] in { def ACTIVEMASK : BasicNVPTXInst<(outs B32:$dest), (ins), "activemask.b32", [(set i32:$dest, (int_nvvm_activemask))]>, - Requires<[hasPTX<62>, hasSM<30>]>; + Requires<[hasPTX<62>, SM30]>; multiclass REDUX_SYNC { def : BasicNVPTXInst<(outs B32:$dst), (ins B32:$src, B32:$mask), "redux.sync." # BinOp # "." # PTXType, [(set i32:$dst, (Intrin i32:$src, B32:$mask))]>, - Requires<[hasPTX<70>, hasSM<80>]>; + Requires<[hasPTX<70>, SM80]>; } defm REDUX_SYNC_UMIN : REDUX_SYNC<"min", "u32", int_nvvm_redux_sync_umin>; @@ -366,14 +366,14 @@ def INT_MEMBAR_SYS : NullaryInst<"membar.sys", int_nvvm_membar_sys>; def INT_FENCE_SC_CLUSTER: NullaryInst<"fence.sc.cluster", int_nvvm_fence_sc_cluster>, - Requires<[hasPTX<78>, hasSM<90>]>; + Requires<[hasPTX<78>, SM90]>; def INT_FENCE_MBARRIER_INIT_RELEASE_CLUSTER: NullaryInst<"fence.mbarrier_init.release.cluster", int_nvvm_fence_mbarrier_init_release_cluster>, - Requires<[hasPTX<80>, hasSM<90>]>; + Requires<[hasPTX<80>, SM90]>; -let Predicates = [hasPTX<86>, hasSM<90>] in { +let Predicates = [hasPTX<86>, SM90] in { def INT_FENCE_ACQUIRE_SYNC_RESTRICT_CLUSTER_CLUSTER: NullaryInst<"fence.acquire.sync_restrict::shared::cluster.cluster", int_nvvm_fence_acquire_sync_restrict_space_cluster_scope_cluster>; @@ -384,7 +384,7 @@ def INT_FENCE_RELEASE_SYNC_RESTRICT_CTA_CLUSTER: } // Proxy fence (uni-directional) -let Predicates = [hasPTX<86>, hasSM<90>] in { +let Predicates = [hasPTX<86>, SM90] in { def INT_NVVM_FENCE_PROXY_ASYNC_GENERIC_ACQUIRE_SYNC_RESTRICT_SPACE_CLUSTER_SCOPE_CLUSTER: NullaryInst<"fence.proxy.async::generic.acquire.sync_restrict::shared::cluster.cluster", int_nvvm_fence_proxy_async_generic_acquire_sync_restrict_space_cluster_scope_cluster>; @@ -397,8 +397,8 @@ def INT_NVVM_FENCE_PROXY_ASYNC_GENERIC_RELEASE_SYNC_RESTRICT_SPACE_CTA_SCOPE_CLU // Proxy fence (bi-directional) foreach proxykind = ["alias", "async", "async.global", "async.shared_cta", "async.shared_cluster"] in { - defvar Preds = !if(!eq(proxykind, "alias"), [hasPTX<75>, hasSM<70>], - [hasPTX<80>, hasSM<90>]); + defvar Preds = !if(!eq(proxykind, "alias"), [hasPTX<75>, SM70], + [hasPTX<80>, SM90]); defvar Intr = IntrinsicName<"llvm.nvvm.fence.proxy." # proxykind>; def : NullaryInst<"fence.proxy." # !subst("_", "::", proxykind), !cast(Intr.record_name)>, Requires; @@ -406,7 +406,7 @@ foreach proxykind = ["alias", "async", "async.global", "async.shared_cta", class FENCE_PROXY_TENSORMAP_GENERIC_RELEASE : NullaryInst<"fence.proxy.tensormap::generic.release." # Scope, Intr>, - Requires<[hasPTX<83>, hasSM<90>]>; + Requires<[hasPTX<83>, SM90]>; def INT_FENCE_PROXY_TENSORMAP_GENERIC_RELEASE_CTA: FENCE_PROXY_TENSORMAP_GENERIC_RELEASE<"cta", @@ -427,7 +427,7 @@ class FENCE_PROXY_TENSORMAP_GENERIC_ACQUIRE : NVPTXInst<(outs), (ins B64:$addr), "fence.proxy.tensormap::generic.acquire." # Scope # " [$addr], 128;", [(Intr i64:$addr, (i32 128))]>, - Requires<[hasPTX<83>, hasSM<90>]>; + Requires<[hasPTX<83>, SM90]>; def INT_FENCE_PROXY_TENSORMAP_GENERIC_ACQUIRE_CTA : FENCE_PROXY_TENSORMAP_GENERIC_ACQUIRE<"cta", @@ -450,7 +450,7 @@ multiclass CP_ASYNC_MBARRIER_ARRIVE, - Requires<[hasPTX<70>, hasSM<80>]>; + Requires<[hasPTX<70>, SM80]>; } defm CP_ASYNC_MBARRIER_ARRIVE : @@ -466,17 +466,17 @@ multiclass CP_ASYNC_SHARED_GLOBAL_I, - Requires<[hasPTX<70>, hasSM<80>]>; + Requires<[hasPTX<70>, SM80]>; // Variant with src_size parameter def _s : NVPTXInst<(outs), (ins ADDR:$dst, ADDR:$src, B32:$src_size), "cp.async." # cc # ".shared.global" # " [$dst], [$src], " # cpsize # ", $src_size;", [(IntrinS addr:$dst, addr:$src, i32:$src_size)]>, - Requires<[hasPTX<70>, hasSM<80>]>; + Requires<[hasPTX<70>, SM80]>; def _si: NVPTXInst<(outs), (ins ADDR:$dst, ADDR:$src, i32imm:$src_size), "cp.async." # cc # ".shared.global" # " [$dst], [$src], " # cpsize # ", $src_size;", [(IntrinS addr:$dst, addr:$src, imm:$src_size)]>, - Requires<[hasPTX<70>, hasSM<80>]>; + Requires<[hasPTX<70>, SM80]>; } defm CP_ASYNC_CA_SHARED_GLOBAL_4 : @@ -495,7 +495,7 @@ defm CP_ASYNC_CG_SHARED_GLOBAL_16 : CP_ASYNC_SHARED_GLOBAL_I<"cg", "16", int_nvvm_cp_async_cg_shared_global_16, int_nvvm_cp_async_cg_shared_global_16_s>; -let Predicates = [hasPTX<70>, hasSM<80>] in { +let Predicates = [hasPTX<70>, SM80] in { def CP_ASYNC_COMMIT_GROUP : NullaryInst<"cp.async.commit_group", int_nvvm_cp_async_commit_group>; @@ -507,7 +507,7 @@ let Predicates = [hasPTX<70>, hasSM<80>] in { NullaryInst<"cp.async.wait_all", int_nvvm_cp_async_wait_all>; } -let Predicates = [hasPTX<80>, hasSM<90>] in { +let Predicates = [hasPTX<80>, SM90] in { // cp.async.bulk variants of the commit/wait group def CP_ASYNC_BULK_COMMIT_GROUP : NullaryInst<"cp.async.bulk.commit_group", int_nvvm_cp_async_bulk_commit_group>; @@ -550,14 +550,14 @@ multiclass CP_ASYNC_BULK_S2G_INTR { CpAsyncBulkStr<0, 1>.S2G # " [$dst], [$src], $size, $ch;", CpAsyncBulkStr<0, 0>.S2G # " [$dst], [$src], $size;"), [(int_nvvm_cp_async_bulk_shared_cta_to_global addr:$dst, addr:$src, i32:$size, i64:$ch, !if(has_ch, -1, 0))]>, - Requires<[hasPTX<80>, hasSM<90>]>; + Requires<[hasPTX<80>, SM90]>; def _BM : NVPTXInst<(outs), (ins ADDR:$dst, ADDR:$src, B32:$size, B64:$ch, B16:$mask), !if(has_ch, CpAsyncBulkStr<0, 1, 1>.S2G # " [$dst], [$src], $size, $ch, $mask;", CpAsyncBulkStr<0, 0, 1>.S2G # " [$dst], [$src], $size, $mask;"), [(int_nvvm_cp_async_bulk_shared_cta_to_global_bytemask addr:$dst, addr:$src, i32:$size, i64:$ch, !if(has_ch, -1, 0), i16:$mask)]>, - Requires<[hasPTX<86>, hasSM<100>]>; + Requires<[hasPTX<86>, SM100]>; } defm CP_ASYNC_BULK_S2G : CP_ASYNC_BULK_S2G_INTR; defm CP_ASYNC_BULK_S2G_CH : CP_ASYNC_BULK_S2G_INTR; @@ -572,7 +572,7 @@ multiclass CP_ASYNC_BULK_G2S_INTR { CpAsyncBulkStr<0, 1>.G2S # " [$dst], [$src], $size, [$mbar], $ch;", CpAsyncBulkStr<0, 0>.G2S # " [$dst], [$src], $size, [$mbar];"), [(Intr addr:$dst, addr:$mbar, addr:$src, i32:$size, i16:$mask, i64:$ch, 0, !if(has_ch, -1, 0))]>, - Requires<[hasPTX<80>, hasSM<90>]>; + Requires<[hasPTX<80>, SM90]>; def _MC : NVPTXInst<(outs), (ins ADDR:$dst, ADDR:$mbar, ADDR:$src, @@ -581,7 +581,7 @@ multiclass CP_ASYNC_BULK_G2S_INTR { CpAsyncBulkStr<1, 1>.G2S # " [$dst], [$src], $size, [$mbar], $mask, $ch;", CpAsyncBulkStr<1, 0>.G2S # " [$dst], [$src], $size, [$mbar], $mask;"), [(Intr addr:$dst, addr:$mbar, addr:$src, i32:$size, i16:$mask, i64:$ch, -1, !if(has_ch, -1, 0))]>, - Requires<[hasPTX<80>, hasSM<90>]>; + Requires<[hasPTX<80>, SM90]>; } defm CP_ASYNC_BULK_G2S : CP_ASYNC_BULK_G2S_INTR; defm CP_ASYNC_BULK_G2S_CH : CP_ASYNC_BULK_G2S_INTR; @@ -596,7 +596,7 @@ multiclass CP_ASYNC_BULK_G2S_CTA_INTR { CpAsyncBulkStr<0, 1>.G2S_CTA # " [$dst], [$src], $size, [$mbar], $ch;", CpAsyncBulkStr<0, 0>.G2S_CTA # " [$dst], [$src], $size, [$mbar];"), [(Intr addr:$dst, addr:$mbar, addr:$src, i32:$size, i64:$ch, !if(has_ch, -1, 0))]>, - Requires<[hasPTX<86>, hasSM<90>]>; + Requires<[hasPTX<86>, SM90]>; } defm CP_ASYNC_BULK_G2S_CTA : CP_ASYNC_BULK_G2S_CTA_INTR; defm CP_ASYNC_BULK_G2S_CTA_CH : CP_ASYNC_BULK_G2S_CTA_INTR; @@ -605,7 +605,7 @@ def CP_ASYNC_BULK_CTA_TO_CLUSTER : NVPTXInst<(outs), (ins ADDR:$dst, ADDR:$mbar, ADDR:$src, B32:$size), CpAsyncBulkStr<0, 0>.C2C # " [$dst], [$src], $size, [$mbar];", [(int_nvvm_cp_async_bulk_shared_cta_to_cluster addr:$dst, addr:$mbar, addr:$src, i32:$size)]>, - Requires<[hasPTX<80>, hasSM<90>]>; + Requires<[hasPTX<80>, SM90]>; multiclass CP_ASYNC_BULK_PREFETCH_INTR { def "" : NVPTXInst<(outs), (ins ADDR:$src, B32:$size, B64:$ch), @@ -613,7 +613,7 @@ multiclass CP_ASYNC_BULK_PREFETCH_INTR { "cp.async.bulk.prefetch.L2.global.L2::cache_hint" # " [$src], $size, $ch;", "cp.async.bulk.prefetch.L2.global" # " [$src], $size;"), [(int_nvvm_cp_async_bulk_prefetch_L2 addr:$src, i32:$size, i64:$ch, !if(has_ch, -1, 0))]>, - Requires<[hasPTX<80>, hasSM<90>]>; + Requires<[hasPTX<80>, SM90]>; } defm CP_ASYNC_BULK_PREFETCH : CP_ASYNC_BULK_PREFETCH_INTR; defm CP_ASYNC_BULK_PREFETCH_CH : CP_ASYNC_BULK_PREFETCH_INTR; @@ -720,7 +720,7 @@ multiclass TMA_TENSOR_G2S_INTR pred, foreach dim = 1...5 in { defm TMA_G2S_TILE_CG0_ # dim # "D" - : TMA_TENSOR_G2S_INTR, hasSM<90>], + : TMA_TENSOR_G2S_INTR, SM90], tma_cta_group_imm0>; defm TMA_G2S_TILE_ # dim # "D" : TMA_TENSOR_G2S_INTR, hasSM<90>], + : TMA_TENSOR_G2S_INTR, SM90], tma_cta_group_imm0>; defm TMA_G2S_IM2COL_ # dim # "D" : TMA_TENSOR_G2S_INTR pred = } foreach dim = 1...5 in { defm TMA_G2S_CTA_TILE_ # dim # "D" - : TMA_TENSOR_G2S_CTA_INTR, hasSM<90>]>; + : TMA_TENSOR_G2S_CTA_INTR, SM90]>; } foreach dim = 3...5 in { defm TMA_G2S_CTA_IM2COL_ # dim # "D" - : TMA_TENSOR_G2S_CTA_INTR, hasSM<90>]>; + : TMA_TENSOR_G2S_CTA_INTR, SM90]>; defm TMA_G2S_CTA_IM2COL_W_ # dim # "D" - : TMA_TENSOR_G2S_CTA_INTR, hasSM<100>]>; + : TMA_TENSOR_G2S_CTA_INTR, SM100]>; defm TMA_G2S_CTA_IM2COL_W_128_ # dim # "D" : TMA_TENSOR_G2S_CTA_INTR]>; } defm TMA_G2S_CTA_TILE_GATHER4_2D : TMA_TENSOR_G2S_CTA_INTR<5, "tile_gather4", - [hasPTX<86>, hasSM<100>]>; + [hasPTX<86>, SM100]>; multiclass TMA_TENSOR_S2G_INTR pred = [hasPTX<80>, hasSM<90>]> { + list pred = [hasPTX<80>, SM90]> { defvar dims_dag = TMA_DIMS_UTIL.ins_dag; defvar dims_str = TMA_DIMS_UTIL.base_str; defvar asm_str = " [$tmap, {{" # dims_str # "}}], [$src]"; @@ -894,14 +894,14 @@ multiclass CP_ASYNC_BULK_TENSOR_REDUCE_INTR { (ins TMAReductionFlags:$red_op)), !strconcat(prefix, "${red_op}", suffix, asm_str, ";"), [intr_dag]>, - Requires<[hasPTX<80>, hasSM<90>]>; + Requires<[hasPTX<80>, SM90]>; def _CH : NVPTXInst<(outs), !con((ins ADDR:$src, B64:$tmap), dims_dag, (ins B64:$ch, TMAReductionFlags:$red_op)), !strconcat(prefix, "${red_op}", suffix, ".L2::cache_hint", asm_str, ", $ch;"), [intr_dag_with_ch]>, - Requires<[hasPTX<80>, hasSM<90>]>; + Requires<[hasPTX<80>, SM90]>; } foreach dim = 1...5 in { @@ -914,7 +914,7 @@ foreach dim = 1...5 in { // TMA Prefetch from Global memory to L2 cache multiclass TMA_TENSOR_PREFETCH_INTR pred = [hasPTX<80>, hasSM<90>]> { + list pred = [hasPTX<80>, SM90]> { defvar dims_dag = TMA_DIMS_UTIL.ins_dag; defvar dims_str = TMA_DIMS_UTIL.base_str; defvar asm_str_base = " [$tmap, {{" # dims_str # "}}]"; @@ -988,7 +988,7 @@ multiclass PREFETCH_TENSORMAP_INST def "" : BasicNVPTXInst<(outs), (ins ADDR:$addr), "prefetch" # addrspace_name # ".tensormap", [(pattern_frag addr:$addr)]>, - Requires<[hasPTX<80>, hasSM<90>]>; + Requires<[hasPTX<80>, SM90]>; } defm PREFETCH_CONST_TENSORMAP : PREFETCH_TENSORMAP_INST<".const", prefetch_tensormap_const>; @@ -999,7 +999,7 @@ class PREFETCH_INTRS : BasicNVPTXInst<(outs), (ins ADDR:$addr), InstName, [(Intr addr:$addr)]>, - Requires<[hasPTX<80>, hasSM<90>]>; + Requires<[hasPTX<80>, SM90]>; def PREFETCHU_L1 : PREFETCH_INTRS<"prefetchu.L1", int_nvvm_prefetchu_L1>; def PREFETCH_L1 : PREFETCH_INTRS<"prefetch.L1", int_nvvm_prefetch_L1>; @@ -1019,7 +1019,7 @@ class APPLYPRIORITY_L2_INTRS : StrJoin<".", ["applypriority", addrspace , "L2::evict_normal"]>.ret, [(!cast(StrJoin<"_", ["int_nvvm_applypriority", addrspace , "L2_evict_normal"]>.ret) addr:$addr, i64:$size)]>, - Requires<[hasPTX<74>, hasSM<80>]>; + Requires<[hasPTX<74>, SM80]>; def APPLYPRIORITY_L2_EVICT_NORMAL : APPLYPRIORITY_L2_INTRS<"">; def APPLYPRIORITY_GLOBAL_L2_EVICT_NORMAL : APPLYPRIORITY_L2_INTRS<"global">; @@ -1033,7 +1033,7 @@ class DISCARD_L2_INTRS : StrJoin<".", ["discard", addrspace , "L2"]>.ret, [(!cast(StrJoin<"_", ["int_nvvm_discard", addrspace , "L2"]>.ret) addr:$addr, discard_size_imm:$size)]>, - Requires<[hasPTX<74>, hasSM<80>]>; + Requires<[hasPTX<74>, SM80]>; def DISCARD_L2 : DISCARD_L2_INTRS<"">; def DISCARD_GLOBAL_L2 : DISCARD_L2_INTRS<"global">; @@ -1042,7 +1042,7 @@ def DISCARD_GLOBAL_L2 : DISCARD_L2_INTRS<"global">; // MBarrier Functions //----------------------------------- -let Predicates = [hasPTX<70>, hasSM<80>] in { +let Predicates = [hasPTX<70>, SM80] in { class MBARRIER_INIT : BasicNVPTXInst<(outs), (ins ADDR:$addr, B32:$count), "mbarrier.init" # AddrSpace # ".b64", @@ -1166,8 +1166,8 @@ class MBAR_UTIL, - true : hasSM<80>); + !eq(sem, "relaxed")) : SM90, + true : SM80); Predicate _ptx_pred = !cond( !eq(sem, "relaxed") : hasPTX<86>, !ne(_scope_asm, "") : hasPTX<80>, @@ -1185,7 +1185,7 @@ foreach op = ["expect_tx", "complete_tx"] in { def mbar_ # suffix : BasicNVPTXInst<(outs), (ins ADDR:$addr, B32:$tx_count), MBAR_UTIL.asm_str, [(intr addr:$addr, i32:$tx_count)]>, - Requires<[hasPTX<80>, hasSM<90>]>; + Requires<[hasPTX<80>, SM90]>; } // space } // scope } // op @@ -1221,8 +1221,8 @@ foreach op = ["arrive", "arrive.expect_tx", "arrive_drop", "arrive_drop.expect_tx"] in { foreach scope = ["scope_cta", "scope_cluster"] in { defvar suffix = !subst(".", "_", op) # scope; - defm mbar_ # suffix # _release : MBAR_ARR_INTR, hasSM<90>]>; - defm mbar_ # suffix # _relaxed : MBAR_ARR_INTR, hasSM<90>]>; + defm mbar_ # suffix # _release : MBAR_ARR_INTR, SM90]>; + defm mbar_ # suffix # _relaxed : MBAR_ARR_INTR, SM90]>; } // scope } // op @@ -1347,10 +1347,10 @@ class F_MATH_3, - Requires<[hasPTX<63>, hasSM<70>]>; + Requires<[hasPTX<63>, SM70]>; def INT_NVVM_NANOSLEEP_R : BasicNVPTXInst<(outs), (ins B32:$i), "nanosleep.u32", [(int_nvvm_nanosleep i32:$i)]>, - Requires<[hasPTX<63>, hasSM<70>]>; + Requires<[hasPTX<63>, SM70]>; def Hexu16imm : Operand { let PrintMethod = "printHexUImm<16>"; @@ -1362,7 +1362,7 @@ def INT_PM_EVENT_MASK : BasicNVPTXInst<(outs), (ins Hexu16imm:$mask), "pmevent.mask", [(int_nvvm_pm_event_mask timm:$mask)]>, - Requires<[hasSM<20>, hasPTX<30>]>; + Requires<[SM20, hasPTX<30>]>; } // hasSideEffects // @@ -1372,45 +1372,45 @@ def INT_PM_EVENT_MASK : BasicNVPTXInst<(outs), def : Pat<(int_nvvm_fmin_f f32:$a, f32:$b), (MIN_f32_rr $a, $b, NoFTZ)>; def : Pat<(int_nvvm_fmin_ftz_f f32:$a, f32:$b), (MIN_f32_rr $a, $b, FTZ)>; -let Predicates = [hasPTX<70>, hasSM<80>] in { +let Predicates = [hasPTX<70>, SM80] in { def : Pat<(int_nvvm_fmin_nan_f f32:$a, f32:$b), (MIN_NAN_f32_rr $a, $b, NoFTZ)>; def : Pat<(int_nvvm_fmin_ftz_nan_f f32:$a, f32:$b), (MIN_NAN_f32_rr $a, $b, FTZ)>; } def INT_NVVM_FMIN_XORSIGN_ABS_F : F_MATH_2<"min.xorsign.abs.f32", B32, B32, B32, int_nvvm_fmin_xorsign_abs_f, - [hasPTX<72>, hasSM<86>]>; + [hasPTX<72>, SM86]>; def INT_NVVM_FMIN_FTZ_XORSIGN_ABS_F : F_MATH_2<"min.ftz.xorsign.abs.f32", B32, B32, B32, int_nvvm_fmin_ftz_xorsign_abs_f, - [hasPTX<72>, hasSM<86>]>; + [hasPTX<72>, SM86]>; def INT_NVVM_FMIN_NAN_XORSIGN_ABS_F : F_MATH_2<"min.NaN.xorsign.abs.f32", B32, B32, B32, int_nvvm_fmin_nan_xorsign_abs_f, - [hasPTX<72>, hasSM<86>]>; + [hasPTX<72>, SM86]>; def INT_NVVM_FMIN_FTZ_NAN_XORSIGN_ABS_F : F_MATH_2<"min.ftz.NaN.xorsign.abs.f32", B32, B32, B32, int_nvvm_fmin_ftz_nan_xorsign_abs_f, - [hasPTX<72>, hasSM<86>]>; + [hasPTX<72>, SM86]>; def : Pat<(int_nvvm_fmax_f f32:$a, f32:$b), (MAX_f32_rr $a, $b, NoFTZ)>; def : Pat<(int_nvvm_fmax_ftz_f f32:$a, f32:$b), (MAX_f32_rr $a, $b, FTZ)>; -let Predicates = [hasPTX<70>, hasSM<80>] in { +let Predicates = [hasPTX<70>, SM80] in { def : Pat<(int_nvvm_fmax_nan_f f32:$a, f32:$b), (MAX_NAN_f32_rr $a, $b, NoFTZ)>; def : Pat<(int_nvvm_fmax_ftz_nan_f f32:$a, f32:$b), (MAX_NAN_f32_rr $a, $b, FTZ)>; } def INT_NVVM_FMAX_XORSIGN_ABS_F : F_MATH_2<"max.xorsign.abs.f32", B32, B32, B32, int_nvvm_fmax_xorsign_abs_f, - [hasPTX<72>, hasSM<86>]>; + [hasPTX<72>, SM86]>; def INT_NVVM_FMAX_FTZ_XORSIGN_ABS_F : F_MATH_2<"max.ftz.xorsign.abs.f32", B32, B32, B32, int_nvvm_fmax_ftz_xorsign_abs_f, - [hasPTX<72>, hasSM<86>]>; + [hasPTX<72>, SM86]>; def INT_NVVM_FMAX_NAN_XORSIGN_ABS_F : F_MATH_2<"max.NaN.xorsign.abs.f32", B32, B32, B32, int_nvvm_fmax_nan_xorsign_abs_f, - [hasPTX<72>, hasSM<86>]>; + [hasPTX<72>, SM86]>; def INT_NVVM_FMAX_FTZ_NAN_XORSIGN_ABS_F : F_MATH_2<"max.ftz.NaN.xorsign.abs.f32", B32, B32, B32, int_nvvm_fmax_ftz_nan_xorsign_abs_f, - [hasPTX<72>, hasSM<86>]>; + [hasPTX<72>, SM86]>; def : Pat<(int_nvvm_fmin_d f64:$a, f64:$b), (MIN_f64_rr $a, $b)>; def : Pat<(int_nvvm_fmax_d f64:$a, f64:$b), (MAX_f64_rr $a, $b)>; @@ -1420,7 +1420,7 @@ def : Pat<(int_nvvm_fmax_d f64:$a, f64:$b), (MAX_f64_rr $a, $b)>; // class MIN_MAX_TUPLE Preds = [hasPTX<70>, hasSM<80>]> { + list Preds = [hasPTX<70>, SM80]> { string Variant = V; Intrinsic Intr = I; NVPTXRegClass RegClass = RC; @@ -1439,16 +1439,16 @@ multiclass MIN_MAX { int_nvvm_fmin_ftz_nan_f16, int_nvvm_fmax_ftz_nan_f16), B16>, MIN_MAX_TUPLE<"_xorsign_abs_f16", !if(!eq(IntName, "min"), int_nvvm_fmin_xorsign_abs_f16, int_nvvm_fmax_xorsign_abs_f16), - B16, [hasPTX<72>, hasSM<86>]>, + B16, [hasPTX<72>, SM86]>, MIN_MAX_TUPLE<"_ftz_xorsign_abs_f16", !if(!eq(IntName, "min"), int_nvvm_fmin_ftz_xorsign_abs_f16, int_nvvm_fmax_ftz_xorsign_abs_f16), - B16, [hasPTX<72>, hasSM<86>]>, + B16, [hasPTX<72>, SM86]>, MIN_MAX_TUPLE<"_NaN_xorsign_abs_f16", !if(!eq(IntName, "min"), int_nvvm_fmin_nan_xorsign_abs_f16, int_nvvm_fmax_nan_xorsign_abs_f16), - B16, [hasPTX<72>, hasSM<86>]>, + B16, [hasPTX<72>, SM86]>, MIN_MAX_TUPLE<"_ftz_NaN_xorsign_abs_f16", !if(!eq(IntName, "min"), int_nvvm_fmin_ftz_nan_xorsign_abs_f16, - int_nvvm_fmax_ftz_nan_xorsign_abs_f16), B16, [hasPTX<72>, hasSM<86>]>, + int_nvvm_fmax_ftz_nan_xorsign_abs_f16), B16, [hasPTX<72>, SM86]>, MIN_MAX_TUPLE<"_f16x2", !if(!eq(IntName, "min"), int_nvvm_fmin_f16x2, int_nvvm_fmax_f16x2), B32>, MIN_MAX_TUPLE<"_ftz_f16x2", !if(!eq(IntName, "min"), @@ -1459,38 +1459,38 @@ multiclass MIN_MAX { int_nvvm_fmin_ftz_nan_f16x2, int_nvvm_fmax_ftz_nan_f16x2), B32>, MIN_MAX_TUPLE<"_xorsign_abs_f16x2", !if(!eq(IntName, "min"), int_nvvm_fmin_xorsign_abs_f16x2, int_nvvm_fmax_xorsign_abs_f16x2), - B32, [hasPTX<72>, hasSM<86>]>, + B32, [hasPTX<72>, SM86]>, MIN_MAX_TUPLE<"_ftz_xorsign_abs_f16x2", !if(!eq(IntName, "min"), int_nvvm_fmin_ftz_xorsign_abs_f16x2, int_nvvm_fmax_ftz_xorsign_abs_f16x2), - B32, [hasPTX<72>, hasSM<86>]>, + B32, [hasPTX<72>, SM86]>, MIN_MAX_TUPLE<"_NaN_xorsign_abs_f16x2", !if(!eq(IntName, "min"), int_nvvm_fmin_nan_xorsign_abs_f16x2, int_nvvm_fmax_nan_xorsign_abs_f16x2), - B32, [hasPTX<72>, hasSM<86>]>, + B32, [hasPTX<72>, SM86]>, MIN_MAX_TUPLE<"_ftz_NaN_xorsign_abs_f16x2", !if(!eq(IntName, "min"), int_nvvm_fmin_ftz_nan_xorsign_abs_f16x2, int_nvvm_fmax_ftz_nan_xorsign_abs_f16x2), - B32, [hasPTX<72>, hasSM<86>]>, + B32, [hasPTX<72>, SM86]>, MIN_MAX_TUPLE<"_bf16", !if(!eq(IntName, "min"), int_nvvm_fmin_bf16, int_nvvm_fmax_bf16), B16>, MIN_MAX_TUPLE<"_NaN_bf16", !if(!eq(IntName, "min"), int_nvvm_fmin_nan_bf16, int_nvvm_fmax_nan_bf16), B16>, MIN_MAX_TUPLE<"_xorsign_abs_bf16", !if(!eq(IntName, "min"), int_nvvm_fmin_xorsign_abs_bf16, int_nvvm_fmax_xorsign_abs_bf16), - B16, [hasPTX<72>, hasSM<86>]>, + B16, [hasPTX<72>, SM86]>, MIN_MAX_TUPLE<"_NaN_xorsign_abs_bf16", !if(!eq(IntName, "min"), int_nvvm_fmin_nan_xorsign_abs_bf16, int_nvvm_fmax_nan_xorsign_abs_bf16), - B16, [hasPTX<72>, hasSM<86>]>, + B16, [hasPTX<72>, SM86]>, MIN_MAX_TUPLE<"_bf16x2", !if(!eq(IntName, "min"), int_nvvm_fmin_bf16x2, int_nvvm_fmax_bf16x2), B32>, MIN_MAX_TUPLE<"_NaN_bf16x2", !if(!eq(IntName, "min"), int_nvvm_fmin_nan_bf16x2, int_nvvm_fmax_nan_bf16x2), B32>, MIN_MAX_TUPLE<"_xorsign_abs_bf16x2", !if(!eq(IntName, "min"), int_nvvm_fmin_xorsign_abs_bf16x2, int_nvvm_fmax_xorsign_abs_bf16x2), - B32, [hasPTX<72>, hasSM<86>]>, + B32, [hasPTX<72>, SM86]>, MIN_MAX_TUPLE<"_NaN_xorsign_abs_bf16x2", !if(!eq(IntName, "min"), int_nvvm_fmin_nan_xorsign_abs_bf16x2, int_nvvm_fmax_nan_xorsign_abs_bf16x2), - B32, [hasPTX<72>, hasSM<86>]>] in { + B32, [hasPTX<72>, SM86]>] in { def P.Variant : F_MATH_2; @@ -1592,11 +1592,11 @@ multiclass F_ABS p def _FTZ : F_MATH_1<"abs.ftz." # suffix, RT, RT, int_nvvm_fabs_ftz, preds>; } -defm ABS_F16 : F_ABS<"f16", F16RT, support_ftz = true, preds = [hasPTX<65>, hasSM<53>]>; -defm ABS_F16X2 : F_ABS<"f16x2", F16X2RT, support_ftz = true, preds = [hasPTX<65>, hasSM<53>]>; +defm ABS_F16 : F_ABS<"f16", F16RT, support_ftz = true, preds = [hasPTX<65>, SM53]>; +defm ABS_F16X2 : F_ABS<"f16x2", F16X2RT, support_ftz = true, preds = [hasPTX<65>, SM53]>; -defm ABS_BF16 : F_ABS<"bf16", BF16RT, support_ftz = false, preds = [hasPTX<70>, hasSM<80>]>; -defm ABS_BF16X2 : F_ABS<"bf16x2", BF16X2RT, support_ftz = false, preds = [hasPTX<70>, hasSM<80>]>; +defm ABS_BF16 : F_ABS<"bf16", BF16RT, support_ftz = false, preds = [hasPTX<70>, SM80]>; +defm ABS_BF16X2 : F_ABS<"bf16x2", BF16X2RT, support_ftz = false, preds = [hasPTX<70>, SM80]>; defm ABS_F32 : F_ABS<"f32", F32RT, support_ftz = true>; defm ABS_F64 : F_ABS<"f64", F64RT, support_ftz = false>; @@ -1618,9 +1618,9 @@ foreach t = [F32RT, F64RT] in // def INT_NVVM_NEG_BF16 : F_MATH_1<"neg.bf16", BF16RT, - BF16RT, int_nvvm_neg_bf16, [hasPTX<70>, hasSM<80>]>; + BF16RT, int_nvvm_neg_bf16, [hasPTX<70>, SM80]>; def INT_NVVM_NEG_BF16X2 : F_MATH_1<"neg.bf16x2", BF16X2RT, - BF16X2RT, int_nvvm_neg_bf16x2, [hasPTX<70>, hasSM<80>]>; + BF16X2RT, int_nvvm_neg_bf16x2, [hasPTX<70>, SM80]>; // // Round @@ -1653,12 +1653,12 @@ def : Pat<(int_nvvm_saturate_d f64:$a), (CVT_f64_f64 $a, CvtSAT)>; def : Pat<(f32 (int_nvvm_ex2_approx_ftz f32:$a)), (EX2_APPROX_f32 $a, FTZ)>; def : Pat<(f32 (int_nvvm_ex2_approx f32:$a)), (EX2_APPROX_f32 $a, NoFTZ)>; -let Predicates = [hasPTX<70>, hasSM<75>] in { +let Predicates = [hasPTX<70>, SM75] in { def : Pat<(f16 (int_nvvm_ex2_approx f16:$a)), (EX2_APPROX_f16 $a)>; def : Pat<(v2f16 (int_nvvm_ex2_approx v2f16:$a)), (EX2_APPROX_f16x2 $a)>; } -let Predicates = [hasPTX<78>, hasSM<90>] in { +let Predicates = [hasPTX<78>, SM90] in { def : Pat<(bf16 (int_nvvm_ex2_approx_ftz bf16:$a)), (EX2_APPROX_bf16 $a)>; def : Pat<(v2bf16 (int_nvvm_ex2_approx_ftz v2bf16:$a)), (EX2_APPROX_bf16x2 $a)>; } @@ -1722,39 +1722,39 @@ multiclass FMA_INST { FMA_TUPLE<"_rp_ftz_f32", int_nvvm_fma_rp_ftz_f, B32>, FMA_TUPLE<"_rp_ftz_sat_f32", int_nvvm_fma_rp_ftz_sat_f, B32>, - FMA_TUPLE<"_rn_f16", int_nvvm_fma_rn_f16, B16, [hasPTX<42>, hasSM<53>]>, + FMA_TUPLE<"_rn_f16", int_nvvm_fma_rn_f16, B16, [hasPTX<42>, SM53]>, FMA_TUPLE<"_rn_ftz_f16", int_nvvm_fma_rn_ftz_f16, B16, - [hasPTX<42>, hasSM<53>]>, + [hasPTX<42>, SM53]>, FMA_TUPLE<"_rn_sat_f16", int_nvvm_fma_rn_sat_f16, B16, - [hasPTX<42>, hasSM<53>]>, + [hasPTX<42>, SM53]>, FMA_TUPLE<"_rn_ftz_sat_f16", int_nvvm_fma_rn_ftz_sat_f16, B16, - [hasPTX<42>, hasSM<53>]>, + [hasPTX<42>, SM53]>, FMA_TUPLE<"_rn_relu_f16", int_nvvm_fma_rn_relu_f16, B16, - [hasPTX<70>, hasSM<80>]>, + [hasPTX<70>, SM80]>, FMA_TUPLE<"_rn_ftz_relu_f16", int_nvvm_fma_rn_ftz_relu_f16, B16, - [hasPTX<70>, hasSM<80>]>, + [hasPTX<70>, SM80]>, - FMA_TUPLE<"_rn_bf16", int_nvvm_fma_rn_bf16, B16, [hasPTX<70>, hasSM<80>]>, + FMA_TUPLE<"_rn_bf16", int_nvvm_fma_rn_bf16, B16, [hasPTX<70>, SM80]>, FMA_TUPLE<"_rn_relu_bf16", int_nvvm_fma_rn_relu_bf16, B16, - [hasPTX<70>, hasSM<80>]>, + [hasPTX<70>, SM80]>, FMA_TUPLE<"_rn_f16x2", int_nvvm_fma_rn_f16x2, B32, - [hasPTX<42>, hasSM<53>]>, + [hasPTX<42>, SM53]>, FMA_TUPLE<"_rn_ftz_f16x2", int_nvvm_fma_rn_ftz_f16x2, B32, - [hasPTX<42>, hasSM<53>]>, + [hasPTX<42>, SM53]>, FMA_TUPLE<"_rn_sat_f16x2", int_nvvm_fma_rn_sat_f16x2, B32, - [hasPTX<42>, hasSM<53>]>, + [hasPTX<42>, SM53]>, FMA_TUPLE<"_rn_ftz_sat_f16x2", int_nvvm_fma_rn_ftz_sat_f16x2, - B32, [hasPTX<42>, hasSM<53>]>, + B32, [hasPTX<42>, SM53]>, FMA_TUPLE<"_rn_relu_f16x2", int_nvvm_fma_rn_relu_f16x2, B32, - [hasPTX<70>, hasSM<80>]>, + [hasPTX<70>, SM80]>, FMA_TUPLE<"_rn_ftz_relu_f16x2", int_nvvm_fma_rn_ftz_relu_f16x2, - B32, [hasPTX<70>, hasSM<80>]>, + B32, [hasPTX<70>, SM80]>, FMA_TUPLE<"_rn_bf16x2", int_nvvm_fma_rn_bf16x2, B32, - [hasPTX<70>, hasSM<80>]>, + [hasPTX<70>, SM80]>, FMA_TUPLE<"_rn_relu_bf16x2", int_nvvm_fma_rn_relu_bf16x2, B32, - [hasPTX<70>, hasSM<80>]>, + [hasPTX<70>, SM80]>, ] in { def P.Variant : F_MATH_3, - Requires<[hasSM<100>, hasPTX<86>]>; + Requires<[SM100, hasPTX<86>]>; } } } // Pattern for llvm.fma.f32 intrinsic when there is no FTZ flag -let Predicates = [hasSM<100>, hasPTX<86>, doNoF32FTZ] in { +let Predicates = [SM100, hasPTX<86>, doNoF32FTZ] in { def : Pat<(f32 (fma (f32 (fpextend f16:$a)), (f32 (fpextend f16:$b)), f32:$c)), (INT_NVVM_MIXED_FMA_rn_f32_f16 B16:$a, B16:$b, B32:$c)>; @@ -1798,7 +1798,7 @@ foreach ty = [F16RT, F16X2RT, BF16RT, BF16X2RT] in { BasicNVPTXInst<(outs ty.RC:$dst), (ins ty.RC:$a, ty.RC:$b, ty.RC:$c), "fma.rn.oob" # suffix, [(set ty.Ty:$dst, (Intr ty.Ty:$a, ty.Ty:$b, ty.Ty:$c))]>, - Requires<[hasPTX<81>, hasSM<90>]>; + Requires<[hasPTX<81>, SM90]>; } } @@ -1937,13 +1937,13 @@ foreach rnd = ["_rn", "_rz", "_rm", "_rp"] in { (!cast("int_nvvm_add" # rnd # sat # "_f") (f32 (fpextend type:$a)), f32:$b))]>, - Requires<[hasSM<100>, hasPTX<86>]>; + Requires<[SM100, hasPTX<86>]>; } } } // Pattern for fadd when there is no FTZ flag -let Predicates = [hasSM<100>, hasPTX<86>, doNoF32FTZ] in { +let Predicates = [SM100, hasPTX<86>, doNoF32FTZ] in { def : Pat<(f32 (fadd (f32 (fpextend f16:$a)), f32:$b)), (INT_NVVM_MIXED_ADD_rn_f32_f16 B16:$a, B32:$b)>; def : Pat<(f32 (fadd (f32 (fpextend bf16:$a)), f32:$b)), @@ -1997,13 +1997,13 @@ foreach rnd = ["_rn", "_rz", "_rm", "_rp"] in { (!cast("int_nvvm_add" # rnd # sat # "_f") (f32 (fpextend type:$a)), (f32 (fneg f32:$b))))]>, - Requires<[hasSM<100>, hasPTX<86>]>; + Requires<[SM100, hasPTX<86>]>; } } } // Pattern for fsub when there is no FTZ flag -let Predicates = [hasSM<100>, hasPTX<86>, doNoF32FTZ] in { +let Predicates = [SM100, hasPTX<86>, doNoF32FTZ] in { def : Pat<(f32 (fsub (f32 (fpextend f16:$a)), f32:$b)), (INT_NVVM_MIXED_SUB_rn_f32_f16 B16:$a, B32:$b)>; def : Pat<(f32 (fsub (f32 (fpextend bf16:$a)), f32:$b)), @@ -2040,7 +2040,7 @@ foreach sign = ["s", "u"] in { defm SZEXT_ # sign # _ # mode : I3Inst<"szext." # mode # "." # sign # "32", intrin, I32RT, commutative = false, - requires = [hasSM<70>, hasPTX<76>]>; + requires = [SM70, hasPTX<76>]>; } } @@ -2053,7 +2053,7 @@ foreach mode = ["wrap", "clamp"] in { defm BMSK_ # mode : I3Inst<"bmsk." # mode # ".b32", intrin, I32RT, commutative = false, - requires = [hasSM<70>, hasPTX<76>]>; + requires = [SM70, hasPTX<76>]>; } // @@ -2121,7 +2121,7 @@ def : Pat<(int_nvvm_ff2bf16x2_rn f32:$a, f32:$b), (CVT_bf16x2_f32 $a, $b, C def : Pat<(int_nvvm_ff2bf16x2_rn_relu f32:$a, f32:$b), (CVT_bf16x2_f32 $a, $b, CvtRN_RELU)>; def : Pat<(int_nvvm_ff2bf16x2_rz f32:$a, f32:$b), (CVT_bf16x2_f32 $a, $b, CvtRZ)>; def : Pat<(int_nvvm_ff2bf16x2_rz_relu f32:$a, f32:$b), (CVT_bf16x2_f32 $a, $b, CvtRZ_RELU)>; -let Predicates = [hasPTX<81>, hasSM<80>] in { +let Predicates = [hasPTX<81>, SM80] in { def : Pat<(int_nvvm_ff2bf16x2_rn_satfinite f32:$a, f32:$b), (CVT_bf16x2_f32_sf $a, $b, CvtRN)>; def : Pat<(int_nvvm_ff2bf16x2_rn_relu_satfinite f32:$a, f32:$b), (CVT_bf16x2_f32_sf $a, $b, CvtRN_RELU)>; def : Pat<(int_nvvm_ff2bf16x2_rz_satfinite f32:$a, f32:$b), (CVT_bf16x2_f32_sf $a, $b, CvtRZ)>; @@ -2142,7 +2142,7 @@ def : Pat<(int_nvvm_ff2f16x2_rn f32:$a, f32:$b), (CVT_f16x2_f32 $a, $b, Cvt def : Pat<(int_nvvm_ff2f16x2_rn_relu f32:$a, f32:$b), (CVT_f16x2_f32 $a, $b, CvtRN_RELU)>; def : Pat<(int_nvvm_ff2f16x2_rz f32:$a, f32:$b), (CVT_f16x2_f32 $a, $b, CvtRZ)>; def : Pat<(int_nvvm_ff2f16x2_rz_relu f32:$a, f32:$b), (CVT_f16x2_f32 $a, $b, CvtRZ_RELU)>; -let Predicates = [hasPTX<81>, hasSM<80>] in { +let Predicates = [hasPTX<81>, SM80] in { def : Pat<(int_nvvm_ff2f16x2_rn_satfinite f32:$a, f32:$b), (CVT_f16x2_f32_sf $a, $b, CvtRN)>; def : Pat<(int_nvvm_ff2f16x2_rn_relu_satfinite f32:$a, f32:$b), (CVT_f16x2_f32_sf $a, $b, CvtRN_RELU)>; def : Pat<(int_nvvm_ff2f16x2_rz_satfinite f32:$a, f32:$b), (CVT_f16x2_f32_sf $a, $b, CvtRZ)>; @@ -2163,7 +2163,7 @@ def : Pat<(int_nvvm_f2bf16_rn f32:$a), (CVT_bf16_f32 $a, CvtRN)>; def : Pat<(int_nvvm_f2bf16_rn_relu f32:$a), (CVT_bf16_f32 $a, CvtRN_RELU)>; def : Pat<(int_nvvm_f2bf16_rz f32:$a), (CVT_bf16_f32 $a, CvtRZ)>; def : Pat<(int_nvvm_f2bf16_rz_relu f32:$a), (CVT_bf16_f32 $a, CvtRZ_RELU)>; -let Predicates = [hasPTX<81>, hasSM<80>] in { +let Predicates = [hasPTX<81>, SM80] in { def : Pat<(int_nvvm_f2bf16_rz_satfinite f32:$a), (CVT_bf16_f32_sf $a, CvtRZ)>; def : Pat<(int_nvvm_f2bf16_rz_relu_satfinite f32:$a), (CVT_bf16_f32_sf $a, CvtRZ_RELU)>; def : Pat<(int_nvvm_f2bf16_rn_satfinite f32:$a), (CVT_bf16_f32_sf $a, CvtRN)>; @@ -2174,7 +2174,7 @@ def : Pat<(int_nvvm_f2f16_rn f32:$a), (CVT_f16_f32 $a, CvtRN)>; def : Pat<(int_nvvm_f2f16_rn_relu f32:$a), (CVT_f16_f32 $a, CvtRN_RELU)>; def : Pat<(int_nvvm_f2f16_rz f32:$a), (CVT_f16_f32 $a, CvtRZ)>; def : Pat<(int_nvvm_f2f16_rz_relu f32:$a), (CVT_f16_f32 $a, CvtRZ_RELU)>; -let Predicates = [hasPTX<81>, hasSM<80>] in { +let Predicates = [hasPTX<81>, SM80] in { def : Pat<(int_nvvm_f2f16_rz_satfinite f32:$a), (CVT_f16_f32_sf $a, CvtRZ)>; def : Pat<(int_nvvm_f2f16_rz_relu_satfinite f32:$a), (CVT_f16_f32_sf $a, CvtRZ_RELU)>; def : Pat<(int_nvvm_f2f16_rn_satfinite f32:$a), (CVT_f16_f32_sf $a, CvtRN)>; @@ -2479,7 +2479,7 @@ class INT_FNS_MBO : BasicNVPTXInst<(outs B32:$dst), ins, "fns.b32", [(set i32:$dst, Operands)]>, - Requires<[hasPTX<60>, hasSM<30>]>; + Requires<[hasPTX<60>, SM30]>; def INT_FNS_rrr : INT_FNS_MBO<(ins B32:$mask, B32:$base, B32:$offset), (int_nvvm_fns i32:$mask, i32:$base, i32:$offset)>; @@ -2588,8 +2588,8 @@ defm atomic_load_fadd : binary_atomic_op_fp; defm INT_PTX_ATOM_ADD_32 : F_ATOMIC_2; defm INT_PTX_ATOM_ADD_64 : F_ATOMIC_2; -defm INT_PTX_ATOM_ADD_F16 : F_ATOMIC_2, hasPTX<63>]>; -defm INT_PTX_ATOM_ADD_BF16 : F_ATOMIC_2, hasPTX<78>]>; +defm INT_PTX_ATOM_ADD_F16 : F_ATOMIC_2]>; +defm INT_PTX_ATOM_ADD_BF16 : F_ATOMIC_2]>; defm INT_PTX_ATOM_ADD_F32 : F_ATOMIC_2; defm INT_PTX_ATOM_ADD_F64 : F_ATOMIC_2; @@ -2599,15 +2599,15 @@ defm INT_PTX_ATOM_SWAP_64 : F_ATOMIC_2; -defm INT_PTX_ATOMIC_MAX_64 : F_ATOMIC_2]>; +defm INT_PTX_ATOMIC_MAX_64 : F_ATOMIC_2; defm INT_PTX_ATOMIC_UMAX_32 : F_ATOMIC_2; -defm INT_PTX_ATOMIC_UMAX_64 : F_ATOMIC_2]>; +defm INT_PTX_ATOMIC_UMAX_64 : F_ATOMIC_2; // atom_min defm INT_PTX_ATOMIC_MIN_32 : F_ATOMIC_2; -defm INT_PTX_ATOMIC_MIN_64 : F_ATOMIC_2]>; +defm INT_PTX_ATOMIC_MIN_64 : F_ATOMIC_2; defm INT_PTX_ATOMIC_UMIN_32 : F_ATOMIC_2; -defm INT_PTX_ATOMIC_UMIN_64 : F_ATOMIC_2]>; +defm INT_PTX_ATOMIC_UMIN_64 : F_ATOMIC_2; // NOTE: The semantics for atomicrmw fmin (and fmax) upholds LangRef // requirements. The LangRef requires the semantics of fmin/fmax to follow @@ -2625,15 +2625,15 @@ defm INT_PTX_ATOM_DEC_32 : F_ATOMIC_2; -defm INT_PTX_ATOM_AND_64 : F_ATOMIC_2]>; +defm INT_PTX_ATOM_AND_64 : F_ATOMIC_2; // atom_or defm INT_PTX_ATOM_OR_32 : F_ATOMIC_2; -defm INT_PTX_ATOM_OR_64 : F_ATOMIC_2]>; +defm INT_PTX_ATOM_OR_64 : F_ATOMIC_2; // atom_xor defm INT_PTX_ATOM_XOR_32 : F_ATOMIC_2; -defm INT_PTX_ATOM_XOR_64 : F_ATOMIC_2]>; +defm INT_PTX_ATOM_XOR_64 : F_ATOMIC_2; // Define atom.cas for all combinations of size x addrspace x memory order // supported in PTX *and* on the hardware. @@ -2831,7 +2831,7 @@ multiclass CvtaInsts preds = [], foreach as = [AddrSpaceLocal, AddrSpaceShared, AddrSpaceGlobal, AddrSpaceConst] in defm cvta : CvtaInsts; -defm cvta : CvtaInsts, hasSM<70>]>; +defm cvta : CvtaInsts, SM70]>; defm cvta : CvtaInsts; @@ -2919,7 +2919,7 @@ defm isspace_local : ISSPACEP<"local", int_nvvm_isspacep_local>; defm isspace_shared : ISSPACEP<"shared", int_nvvm_isspacep_shared>; defm isspace_shared_cluster : ISSPACEP<"shared::cluster", int_nvvm_isspacep_shared_cluster, - [hasPTX<78>, hasSM<90>]>; + [hasPTX<78>, SM90]>; // Special register reads def MOV_SPECIAL : BasicNVPTXInst<(outs B32:$d), @@ -4839,22 +4839,22 @@ defm INT_PTX_SREG_CTAID : PTX_READ_SREG_R32V4<"ctaid">; defm INT_PTX_SREG_NCTAID: PTX_READ_SREG_R32V4<"nctaid">; defm INT_PTX_SREG_CLUSTERID : - PTX_READ_SREG_R32V4<"clusterid", [hasSM<90>, hasPTX<78>]>; + PTX_READ_SREG_R32V4<"clusterid", [SM90, hasPTX<78>]>; defm INT_PTX_SREG_NCLUSTERID : - PTX_READ_SREG_R32V4<"nclusterid", [hasSM<90>, hasPTX<78>]>; + PTX_READ_SREG_R32V4<"nclusterid", [SM90, hasPTX<78>]>; defm INT_PTX_SREG_CLUSTER_CTAID : - PTX_READ_SREG_R32V4<"cluster_ctaid", [hasSM<90>, hasPTX<78>]>; + PTX_READ_SREG_R32V4<"cluster_ctaid", [SM90, hasPTX<78>]>; defm INT_PTX_SREG_CLUSTER_NCTAID: - PTX_READ_SREG_R32V4<"cluster_nctaid", [hasSM<90>, hasPTX<78>]>; + PTX_READ_SREG_R32V4<"cluster_nctaid", [SM90, hasPTX<78>]>; def INT_PTX_SREG_CLUSTER_CTARANK : PTX_READ_SREG_R32<"cluster_ctarank", int_nvvm_read_ptx_sreg_cluster_ctarank, - [hasSM<90>, hasPTX<78>]>; + [SM90, hasPTX<78>]>; def INT_PTX_SREG_CLUSTER_NCTARANK: PTX_READ_SREG_R32<"cluster_nctarank", int_nvvm_read_ptx_sreg_cluster_nctarank, - [hasSM<90>, hasPTX<78>]>; + [SM90, hasPTX<78>]>; def INT_PTX_SREG_TOTAL_SMEM_SIZE : PTX_READ_SREG_R32<"total_smem_size", int_nvvm_read_ptx_sreg_total_smem_size>; @@ -4863,7 +4863,7 @@ def INT_PTX_SREG_DYNAMIC_SMEM_SIZE : def INT_PTX_SREG_AGGR_SMEM_SIZE : PTX_READ_SREG_R32<"aggr_smem_size", int_nvvm_read_ptx_sreg_aggr_smem_size, - [hasSM<90>, hasPTX<81>]>; + [SM90, hasPTX<81>]>; def SREG_LANEID : PTX_READ_SREG_R32<"laneid", int_nvvm_read_ptx_sreg_laneid>; def SREG_WARPID : PTX_READ_SREG_R32<"warpid", int_nvvm_read_ptx_sreg_warpid>; @@ -4904,7 +4904,7 @@ foreach suffix = ["begin", "end", "cap", "0", "1"] in { defvar regname = "reserved_smem_offset_" # suffix; defvar intr = !cast("int_nvvm_read_ptx_sreg_" # regname); def "INT_PTX_SREG_RESERVED_SMEM_OFFSET_" # !toupper(suffix) : - PTX_READ_SREG_R32, hasSM<80>]>; + PTX_READ_SREG_R32, SM80]>; } // TODO: It would be nice to use PTX_READ_SREG here, but it doesn't @@ -4986,33 +4986,33 @@ class WMMA_REGINFO, hasPTX<87>], + !eq(geom, "m16n8k16")) : [SM89, hasPTX<87>], !or(!eq(ptx_elt_type, "e4m3"), - !eq(ptx_elt_type, "e5m2")) : [hasSM<89>, hasPTX<84>], + !eq(ptx_elt_type, "e5m2")) : [SM89, hasPTX<84>], !and(isSparse, - !ne(metadata, "sp")) : [hasSM<80>, hasPTX<85>], - isSparse : [hasSM<80>, hasPTX<71>], + !ne(metadata, "sp")) : [SM80, hasPTX<85>], + isSparse : [SM80, hasPTX<71>], // fp16 -> fp16/fp32 @ m16n16k16 !and(!eq(geom, "m16n16k16"), !or(!eq(ptx_elt_type, "f16"), - !eq(ptx_elt_type, "f32"))) : [hasSM<70>, hasPTX<60>], + !eq(ptx_elt_type, "f32"))) : [SM70, hasPTX<60>], !and(!eq(geom, "m8n8k4"), - !eq(ptx_elt_type, "f64")) : [hasSM<80>, hasPTX<70>], + !eq(ptx_elt_type, "f64")) : [SM80, hasPTX<70>], !and(!or(!eq(geom, "m16n8k4"), !eq(geom, "m16n8k8"), !eq(geom, "m16n8k16")), - !eq(ptx_elt_type, "f64")) : [hasSM<90>, hasPTX<78>], + !eq(ptx_elt_type, "f64")) : [SM90, hasPTX<78>], // fp16 -> fp16/fp32 @ m8n32k16/m32n8k16 !and(!or(!eq(geom, "m8n32k16"), !eq(geom, "m32n8k16")), !or(!eq(ptx_elt_type, "f16"), - !eq(ptx_elt_type, "f32"))) : [hasSM<70>, hasPTX<61>], + !eq(ptx_elt_type, "f32"))) : [SM70, hasPTX<61>], // u8/s8 -> s32 @ m16n16k16/m8n32k16/m32n8k16 !and(!or(!eq(geom, "m16n16k16"), @@ -5020,39 +5020,39 @@ class WMMA_REGINFO, hasPTX<63>], + !eq(ptx_elt_type, "s32"))) : [SM72, hasPTX<63>], !and(!or(!eq(geom, "m16n16k16"), !eq(geom, "m8n32k16"), !eq(geom, "m32n8k16")), - !eq(ptx_elt_type, "bf16")) : [hasSM<80>, hasPTX<70>], + !eq(ptx_elt_type, "bf16")) : [SM80, hasPTX<70>], !and(!eq(geom, "m16n16k8"), - !eq(ptx_elt_type, "tf32")) : [hasSM<80>, hasPTX<70>], + !eq(ptx_elt_type, "tf32")) : [SM80, hasPTX<70>], !and(!eq(geom, "m16n16k8"), - !eq(ptx_elt_type, "f32")) : [hasSM<80>, hasPTX<70>], + !eq(ptx_elt_type, "f32")) : [SM80, hasPTX<70>], // b1 -> s32 @ m8n8k128(b1) !and(!ne(op, "mma"), - !eq(geom, "m8n8k128")) : [hasSM<75>, hasPTX<63>], + !eq(geom, "m8n8k128")) : [SM75, hasPTX<63>], // u4/s4 -> s32 @ m8n8k32 (u4/s4) !and(!ne(op, "mma"), - !eq(geom, "m8n8k32")) : [hasSM<75>, hasPTX<63>], + !eq(geom, "m8n8k32")) : [SM75, hasPTX<63>], !or(!eq(geom, "m16n8k8"), - !eq(geom, "m8n8k16")) : [hasSM<75>, hasPTX<65>], + !eq(geom, "m8n8k16")) : [SM75, hasPTX<65>], !and(!ne(ptx_elt_type, "f64"), - !eq(geom, "m8n8k4")) : [hasSM<70>, hasPTX<64>], + !eq(geom, "m8n8k4")) : [SM70, hasPTX<64>], // mma m8n8k32 requires higher PTX version !and(!eq(op, "mma"), - !eq(geom, "m8n8k32")) : [hasSM<75>, hasPTX<65>], + !eq(geom, "m8n8k32")) : [SM75, hasPTX<65>], !and(!eq(ptx_elt_type, "f64"), - !eq(geom, "m8n8k4")) : [hasSM<80>, hasPTX<70>], + !eq(geom, "m8n8k4")) : [SM80, hasPTX<70>], !and(!eq(op, "mma"), !or(!eq(geom, "m16n8k16"), @@ -5061,11 +5061,11 @@ class WMMA_REGINFO, hasPTX<70>], + !eq(geom, "m16n8k256"))) : [SM80, hasPTX<70>], !and(!eq(op, "ldmatrix"), !eq(ptx_elt_type, "b16"), - !eq(geom, "m8n8")) : [hasSM<75>, hasPTX<65>], + !eq(geom, "m8n8")) : [SM75, hasPTX<65>], !and(!eq(op, "ldmatrix"), !eq(ptx_elt_type, "b8"), @@ -5088,7 +5088,7 @@ class WMMA_REGINFO], !and(!eq(op, "stmatrix"),!eq(ptx_elt_type, "b16"), - !eq(geom, "m8n8")) : [hasSM<90>, hasPTX<78>], + !eq(geom, "m8n8")) : [SM90, hasPTX<78>], !and(!eq(op, "stmatrix"), !eq(ptx_elt_type, "b8"), @@ -5227,7 +5227,7 @@ class MMA_OP_PREDICATES { WMMA_REGINFO Frag = FragA; list ret = !listconcat( FragA.Predicates, - !if(!eq(b1op, ".and.popc"), [hasSM<80>, hasPTX<71>], []) + !if(!eq(b1op, ".and.popc"), [SM80, hasPTX<71>], []) ); } // WMMA.MMA @@ -5612,7 +5612,7 @@ def MOVMATRIX_SYNC_ALIGNED_M8N8_TRANS_B16 "movmatrix.sync.aligned.m8n8.trans.b16", [(set B32:$dst, (int_nvvm_movmatrix_sync_aligned_m8n8_trans_b16 B32:$src))]>, - Requires<[hasSM<75>, hasPTX<78>]>; + Requires<[SM75, hasPTX<78>]>; } // isConvergent = true // Constructing non-flat DAGs is still a pain. I can't !subst a dag node with a @@ -5630,7 +5630,7 @@ foreach mma = !listconcat(MMAs, MMA_BLOCK_SCALEs, WMMAs, MMA_LDSTs, LDMATRIXs, def : MMA_PAT; multiclass MAPA { - let Predicates = [hasSM<90>, hasPTX<78>] in { + let Predicates = [SM90, hasPTX<78>] in { def _32: BasicNVPTXInst<(outs B32:$d), (ins B32:$a, B32:$b), "mapa" # suffix # ".u32", [(set i32:$d, (Intr i32:$a, i32:$b))]>; @@ -5652,7 +5652,7 @@ defm mapa_shared_cluster : MAPA<".shared::cluster", int_nvvm_mapa_shared_cluste multiclass GETCTARANK { - let Predicates = [hasSM<90>, hasPTX<78>] in { + let Predicates = [SM90, hasPTX<78>] in { def _32: BasicNVPTXInst<(outs B32:$d), (ins B32:$a), "getctarank" # suffix # ".u32", [(set i32:$d, (Intr i32:$a))]>; @@ -5668,7 +5668,7 @@ defm getctarank_shared_cluster : GETCTARANK<".shared::cluster", int_nvvm_getcta def is_explicit_cluster: NVPTXInst<(outs B1:$d), (ins), "mov.pred\t$d, %is_explicit_cluster;", [(set i1:$d, (int_nvvm_is_explicit_cluster))]>, - Requires<[hasSM<90>, hasPTX<78>]>; + Requires<[SM90, hasPTX<78>]>; // setmaxnreg inc/dec intrinsics let isConvergent = true in { @@ -5687,7 +5687,7 @@ defm INT_SET_MAXNREG_DEC : SET_MAXNREG<"dec", int_nvvm_setmaxnreg_dec_sync_align // // WGMMA fence instructions // -let isConvergent = true, Predicates = [hasSM90a, hasPTX<80>] in { +let isConvergent = true, Predicates = [SM90a, hasPTX<80>] in { def WGMMA_FENCE_SYNC_ALIGNED : NullaryInst<"wgmma.fence.sync.aligned", int_nvvm_wgmma_fence_sync_aligned>; def WGMMA_COMMIT_GROUP_SYNC_ALIGNED : NullaryInst<"wgmma.commit_group.sync.aligned", int_nvvm_wgmma_commit_group_sync_aligned>; @@ -5696,7 +5696,7 @@ let isConvergent = true, Predicates = [hasSM90a, hasPTX<80>] in { [(int_nvvm_wgmma_wait_group_sync_aligned timm:$n)]>; } -let Predicates = [hasSM<90>, hasPTX<78>] in { +let Predicates = [SM90, hasPTX<78>] in { def GRIDDEPCONTROL_LAUNCH_DEPENDENTS : NullaryInst<"griddepcontrol.launch_dependents", int_nvvm_griddepcontrol_launch_dependents>; def GRIDDEPCONTROL_WAIT : @@ -6008,7 +6008,7 @@ let isConvergent = true in { // Bulk store instructions def st_bulk_imm : TImmLeaf; -let Predicates = [hasSM<100>, hasPTX<86>] in { +let Predicates = [SM100, hasPTX<86>] in { def INT_NVVM_ST_BULK_GENERIC : BasicNVPTXInst<(outs), (ins ADDR:$dest_addr, B64:$size, i64imm:$value), "st.bulk", @@ -6044,7 +6044,7 @@ def ST_ASYNC_MBARRIER_B128 : "st.async.shared::cluster.mbarrier::complete_tx::bytes.b128 \t[$dest_addr], %in_128, [$mbar];\n\t" "}}">; -let Predicates = [hasSM<90>, hasPTX<81>] in { +let Predicates = [SM90, hasPTX<81>] in { foreach size = ["32", "64"] in { defvar valueType = !cast("i" # size); defvar reg = !cast("B" # size); @@ -6056,7 +6056,7 @@ let Predicates = [hasSM<90>, hasPTX<81>] in { } } -let Predicates = [hasSM<90>, hasPTX<92>] in { +let Predicates = [SM90, hasPTX<92>] in { def : Pat<(st_async_mbarrier_b128 addr:$dest_addr, i64:$value0, i64:$value1, addr:$mbar), (ST_ASYNC_MBARRIER_B128 @@ -6113,7 +6113,7 @@ def ST_ASYNC_MMIO_SYS_B8 : ST_ASYNC_RELEASE_B8_BODY<"st.async.mmio.release.sys.global", "">.body>; -let Predicates = [hasSM<100>, hasPTX<87>] in { +let Predicates = [SM100, hasPTX<87>] in { foreach rti = [I16RT, I32RT, I64RT] in { def : Pat<(int_nvvm_st_async_sys addr:$dest_addr, rti.Ty:$value, timm:$is_multimem), @@ -6148,7 +6148,7 @@ def CLUSTERLAUNCHCONTRL_TRY_CANCEL: BasicNVPTXInst<(outs), (ins ADDR:$addr, ADDR:$mbar), "clusterlaunchcontrol.try_cancel.async.shared::cta.mbarrier::complete_tx::bytes.b128", [(int_nvvm_clusterlaunchcontrol_try_cancel_async_shared addr:$addr, addr:$mbar)]>, - Requires<[hasSM<100>, hasPTX<86>]>; + Requires<[SM100, hasPTX<86>]>; def CLUSTERLAUNCHCONTRL_TRY_CANCEL_MULTICAST: BasicNVPTXInst<(outs), (ins ADDR:$addr, ADDR:$mbar), @@ -6170,7 +6170,7 @@ def CLUSTERLAUNCHCONTROL_QUERY_CANCEL_IS_CANCELED: "clusterlaunchcontrol.query_cancel.is_canceled.pred.b128 $pred, %clc_handle;\n\t" # "}}", [(set i1:$pred, (clusterlaunchcontrol_query_cancel_is_canceled i64:$try_cancel_response0, i64:$try_cancel_response1))]>, - Requires<[hasSM<100>, hasPTX<86>]>; + Requires<[SM100, hasPTX<86>]>; class CLUSTERLAUNCHCONTROL_QUERY_CANCEL_GET_FIRST_CTAID: NVPTXInst<(outs B32:$reg), (ins B64:$try_cancel_response0, B64:$try_cancel_response1), @@ -6181,7 +6181,7 @@ class CLUSTERLAUNCHCONTROL_QUERY_CANCEL_GET_FIRST_CTAID: "}}", [(set i32:$reg, (!cast("clusterlaunchcontrol_query_cancel_first_cta_id_" # Dim) i64:$try_cancel_response0, i64:$try_cancel_response1))]>, - Requires<[hasSM<100>, hasPTX<86>]>; + Requires<[SM100, hasPTX<86>]>; foreach dim = ["x", "y", "z"] in { def SDTClusterLaunchControlQueryCancelGetFirstCtaId # dim: SDTypeProfile<1, 2, []>; diff --git a/llvm/lib/Target/NVPTX/NVPTXSubtarget.cpp b/llvm/lib/Target/NVPTX/NVPTXSubtarget.cpp index fc8fc0d64d9c4..d3989455cdd43 100644 --- a/llvm/lib/Target/NVPTX/NVPTXSubtarget.cpp +++ b/llvm/lib/Target/NVPTX/NVPTXSubtarget.cpp @@ -20,7 +20,6 @@ using namespace llvm; #define DEBUG_TYPE "nvptx-subtarget" -#define GET_SUBTARGETINFO_ENUM #define GET_SUBTARGETINFO_TARGET_DESC #define GET_SUBTARGETINFO_CTOR #include "NVPTXGenSubtargetInfo.inc" @@ -35,12 +34,6 @@ static cl::opt NoF32x2("nvptx-no-f32x2", cl::Hidden, "f32x2 instructions and registers."), cl::init(false)); -// FullSmVersion encoding helpers: SM * 10 + suffix offset -// (0 = base, 2 = 'f', 3 = 'a'). -static constexpr unsigned SM(unsigned Version) { return Version * 10; } -static constexpr unsigned SMF(unsigned Version) { return SM(Version) + 2; } -static constexpr unsigned SMA(unsigned Version) { return SM(Version) + 3; } - // Pin the vtable to this file. void NVPTXSubtarget::anchor() {} @@ -52,81 +45,89 @@ void NVPTXSubtarget::anchor() {} // Note: LLVM's minimum supported PTX version is 3.2 (see FeaturePTX in // NVPTX.td), so older SMs that supported earlier PTX versions instead use 3.2 // as their effective minimum. -static unsigned getMinPTXVersionForSM(unsigned FullSmVersion) { - switch (FullSmVersion) { - case SM(20): - case SM(21): - case SM(30): - case SM(35): +static unsigned minPTXVersion(NVPTX::GPUKind Arch) { + switch (Arch) { + case NVPTX::GK_NONE: + llvm_unreachable("architecture is resolved before this is reached"); + case NVPTX::GK_SM_20: + case NVPTX::GK_SM_21: + case NVPTX::GK_SM_30: + case NVPTX::GK_SM_35: return 32; - case SM(32): - case SM(50): + case NVPTX::GK_SM_32_: + case NVPTX::GK_SM_50: return 40; - case SM(37): - case SM(52): + case NVPTX::GK_SM_37: + case NVPTX::GK_SM_52: return 41; - case SM(53): + case NVPTX::GK_SM_53: return 42; - case SM(60): - case SM(61): - case SM(62): + case NVPTX::GK_SM_60: + case NVPTX::GK_SM_61: + case NVPTX::GK_SM_62: return 50; - case SM(70): + case NVPTX::GK_SM_70: return 60; - case SM(72): + case NVPTX::GK_SM_72: return 61; - case SM(75): + case NVPTX::GK_SM_75: return 63; - case SM(80): + case NVPTX::GK_SM_80: return 70; - case SM(86): + case NVPTX::GK_SM_86: return 71; - case SM(87): + case NVPTX::GK_SM_87: return 74; - case SM(89): - case SM(90): + case NVPTX::GK_SM_89: + case NVPTX::GK_SM_90: return 78; - case SMA(90): + case NVPTX::GK_SM_90a: return 80; - case SM(100): - case SMA(100): - case SM(101): - case SMA(101): + case NVPTX::GK_SM_100: + case NVPTX::GK_SM_100a: + case NVPTX::GK_SM_101: + case NVPTX::GK_SM_101a: return 86; - case SM(120): - case SMA(120): + case NVPTX::GK_SM_120: + case NVPTX::GK_SM_120a: return 87; - case SMF(100): - case SMF(101): - case SM(103): - case SMF(103): - case SMA(103): - case SMF(120): - case SM(121): - case SMF(121): - case SMA(121): + case NVPTX::GK_SM_100f: + case NVPTX::GK_SM_101f: + case NVPTX::GK_SM_103: + case NVPTX::GK_SM_103f: + case NVPTX::GK_SM_103a: + case NVPTX::GK_SM_120f: + case NVPTX::GK_SM_121: + case NVPTX::GK_SM_121f: + case NVPTX::GK_SM_121a: return 88; - case SM(88): - case SM(110): - case SMF(110): - case SMA(110): + case NVPTX::GK_SM_88: + case NVPTX::GK_SM_110: + case NVPTX::GK_SM_110f: + case NVPTX::GK_SM_110a: return 90; - case SM(107): - case SMF(107): - case SMA(107): + case NVPTX::GK_SM_107: + case NVPTX::GK_SM_107f: + case NVPTX::GK_SM_107a: return 94; - default: - llvm_unreachable("Unknown SM version"); } + llvm_unreachable("invalid NVPTX GPUKind"); } NVPTXSubtarget &NVPTXSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS) { - TargetName = std::string(CPU); + // If the user did not provide a target we default to the `sm_75` target. + StringRef RequestedCPU = CPU.empty() ? StringRef("sm_75") : CPU; + ParseSubtargetFeatures(RequestedCPU, /*TuneCPU=*/RequestedCPU, FS); + + Arch = NVPTX::parseArch(RequestedCPU); - ParseSubtargetFeatures(getTargetName(), /*TuneCPU=*/getTargetName(), FS); + // An unrecognized name has already been diagnosed and its features dropped, + // leaving the subtarget at the oldest architecture, so name it that. + if (Arch == NVPTX::GK_NONE) + Arch = NVPTX::GK_SM_20; - unsigned MinPTX = getMinPTXVersionForSM(FullSmVersion); + unsigned MinPTX = minPTXVersion(Arch); if (PTXVersion == 0) { // User didn't request a specific PTX version; use the minimum for this SM. @@ -138,7 +139,7 @@ NVPTXSubtarget &NVPTXSubtarget::initializeSubtargetDependencies(StringRef CPU, "Minimum required PTX version is {3}.{4}. " "Either remove the PTX version to use the default, " "or increase it to at least {3}.{4}.", - PTXVersion / 10, PTXVersion % 10, getTargetName(), MinPTX / 10, + PTXVersion / 10, PTXVersion % 10, RequestedCPU, MinPTX / 10, MinPTX % 10)); } @@ -148,51 +149,17 @@ NVPTXSubtarget &NVPTXSubtarget::initializeSubtargetDependencies(StringRef CPU, NVPTXSubtarget::NVPTXSubtarget(const Triple &TT, StringRef CPU, StringRef FS, const NVPTXTargetMachine &TM) : NVPTXGenSubtargetInfo(TT, CPU, /*TuneCPU*/ CPU, FS), PTXVersion(0), - FullSmVersion(200), InstrInfo(initializeSubtargetDependencies(CPU, FS)), - TLInfo(TM, *this), TSInfo(std::make_unique()) {} + InstrInfo(initializeSubtargetDependencies(CPU, FS)), TLInfo(TM, *this), + TSInfo(std::make_unique()) {} NVPTXSubtarget::~NVPTXSubtarget() = default; -bool NVPTXSubtarget::hasPTXWithFamilySMs(unsigned MinPTXVersion, - ArrayRef SMVersions) const { - unsigned PTXVer = getPTXVersion(); - if (!hasFamilySpecificFeatures() || PTXVer < MinPTXVersion) - return false; - - unsigned SMVer = getSmVersion(); - return llvm::any_of(SMVersions, [&](unsigned SM) { - // sm_101 is a different family, never group it with sm_10x. - if (SMVer == 101 || SM == 101) - return SMVer == SM && - // PTX 9.0 and later renamed sm_101 to sm_110, so sm_101 is not - // supported. - !(PTXVer >= 90 && SMVer == 101); - - return getSmFamilyVersion() == SM / 10 && SMVer >= SM; - }); -} - -bool NVPTXSubtarget::hasPTXWithAccelSMs(unsigned MinPTXVersion, - ArrayRef SMVersions) const { - unsigned PTXVer = getPTXVersion(); - if (!hasArchAccelFeatures() || PTXVer < MinPTXVersion) - return false; - - unsigned SMVer = getSmVersion(); - return llvm::any_of(SMVersions, [&](unsigned SM) { - return SMVer == SM && - // PTX 9.0 and later renamed sm_101 to sm_110, so sm_101 is not - // supported. - !(PTXVer >= 90 && SMVer == 101); - }); -} - bool NVPTXSubtarget::allowFP16Math() const { return hasFP16Math() && NoF16Math == false; } bool NVPTXSubtarget::hasF32x2Instructions() const { - return getSmVersion() >= 100 && PTXVersion >= 86 && !NoF32x2; + return hasFeature(NVPTX::SM100) && PTXVersion >= 86 && !NoF32x2; } bool NVPTXSubtarget::hasNativeBF16Support(unsigned Opcode) const { @@ -215,7 +182,7 @@ bool NVPTXSubtarget::hasNativeBF16Support(unsigned Opcode) const { case ISD::FRINT: case ISD::FROUNDEVEN: case ISD::FTRUNC: - return getSmVersion() >= 90 && getPTXVersion() >= 78; + return hasFeature(NVPTX::SM90) && getPTXVersion() >= 78; // Several BF16 instructions are available on sm_80 only. case ISD::FMINNUM: case ISD::FMAXNUM: @@ -223,7 +190,7 @@ bool NVPTXSubtarget::hasNativeBF16Support(unsigned Opcode) const { case ISD::FMINNUM_IEEE: case ISD::FMAXIMUM: case ISD::FMINIMUM: - return getSmVersion() >= 80 && getPTXVersion() >= 70; + return hasFeature(NVPTX::SM80) && getPTXVersion() >= 70; } return true; } diff --git a/llvm/lib/Target/NVPTX/NVPTXSubtarget.h b/llvm/lib/Target/NVPTX/NVPTXSubtarget.h index 28ac251b8adea..21b4cf6169f4f 100644 --- a/llvm/lib/Target/NVPTX/NVPTXSubtarget.h +++ b/llvm/lib/Target/NVPTX/NVPTXSubtarget.h @@ -22,7 +22,7 @@ #include "llvm/IR/DataLayout.h" #include "llvm/IR/NVVMIntrinsicUtils.h" #include "llvm/Support/NVPTXAddrSpace.h" -#include +#include "llvm/TargetParser/NVPTXTargetParser.h" #define GET_SUBTARGETINFO_HEADER #include "NVPTXGenSubtargetInfo.inc" @@ -31,15 +31,15 @@ namespace llvm { class NVPTXSubtarget : public NVPTXGenSubtargetInfo { virtual void anchor(); - std::string TargetName; // PTX version x.y is represented as 10*x+y, e.g. 3.1 == 31 unsigned PTXVersion; - // FullSmVersion encoding: SM * 10 + ArchSuffixOffset - // ArchSuffixOffset: 0 (base), 2 ('f'), 3 ('a') - // e.g. sm_30 -> 300, sm_90a -> 903, sm_100f -> 1002 - unsigned FullSmVersion; + NVPTX::GPUKind Arch = NVPTX::GK_NONE; + + // Set by every architecture feature. Their bits are the point, so this is + // only here because a subtarget feature must name a field. + bool HasArchitecture = false; NVPTXInstrInfo InstrInfo; NVPTXTargetLowering TLInfo; @@ -73,57 +73,56 @@ class NVPTXSubtarget : public NVPTXGenSubtargetInfo { return TSInfo.get(); } - // Checks PTX version and family-specific and architecture-specific SM - // versions. For example, sm_100{f/a} and any future variants in the same - // family will match for any PTX version greater than or equal to - // `MinPTXVersion`. - bool hasPTXWithFamilySMs(unsigned MinPTXVersion, - ArrayRef SMVersions) const; - // Checks PTX version and architecture-specific SM versions. - // For example, sm_100{a} will match for any PTX version greater than or equal - // to `MinPTXVersion`. - bool hasPTXWithAccelSMs(unsigned MinPTXVersion, - ArrayRef SMVersions) const; + // True when any of `Features` is enabled. + bool hasAnyFeature(ArrayRef Features) const { + return llvm::any_of(Features, [this](unsigned F) { return hasFeature(F); }); + } bool has256BitVectorLoadStore(unsigned AS) const { - return getSmVersion() >= 100 && PTXVersion >= 88 && + return hasFeature(NVPTX::SM100) && PTXVersion >= 88 && AS == NVPTXAS::ADDRESS_SPACE_GLOBAL; } bool hasUsedBytesMaskPragma() const { - return getSmVersion() >= 50 && PTXVersion >= 83; + return hasFeature(NVPTX::SM50) && PTXVersion >= 83; + } + bool hasAtomAddF64() const { return hasFeature(NVPTX::SM60); } + bool hasAtomScope() const { return hasFeature(NVPTX::SM60); } + bool hasAtomBitwise64() const { return hasFeature(NVPTX::SM32); } + bool hasAtomMinMax64() const { return hasFeature(NVPTX::SM32); } + bool hasAtomCas16() const { + return hasFeature(NVPTX::SM70) && PTXVersion >= 63; } - bool hasAtomAddF64() const { return getSmVersion() >= 60; } - bool hasAtomScope() const { return getSmVersion() >= 60; } - bool hasAtomBitwise64() const { return getSmVersion() >= 32; } - bool hasAtomMinMax64() const { return getSmVersion() >= 32; } - bool hasAtomCas16() const { return getSmVersion() >= 70 && PTXVersion >= 63; } bool hasAtomSwap128() const { - return getSmVersion() >= 90 && PTXVersion >= 83; - } - bool hasClusters() const { return getSmVersion() >= 90 && PTXVersion >= 78; } - bool hasLDG() const { return getSmVersion() >= 32; } - bool hasHWROT32() const { return getSmVersion() >= 32; } - bool hasBrx() const { return getSmVersion() >= 30 && PTXVersion >= 60; } - bool hasFP16Math() const { return getSmVersion() >= 53; } - bool hasBF16Math() const { return getSmVersion() >= 80; } + return hasFeature(NVPTX::SM90) && PTXVersion >= 83; + } + bool hasClusters() const { + return hasFeature(NVPTX::SM90) && PTXVersion >= 78; + } + bool hasLDG() const { return hasFeature(NVPTX::SM32); } + bool hasHWROT32() const { return hasFeature(NVPTX::SM32); } + bool hasBrx() const { return hasFeature(NVPTX::SM30) && PTXVersion >= 60; } + bool hasFP16Math() const { return hasFeature(NVPTX::SM53); } + bool hasBF16Math() const { return hasFeature(NVPTX::SM80); } bool allowFP16Math() const; bool hasMaskOperator() const { return PTXVersion >= 71; } - bool hasNoReturn() const { return getSmVersion() >= 30 && PTXVersion >= 64; } + bool hasNoReturn() const { + return hasFeature(NVPTX::SM30) && PTXVersion >= 64; + } // Does SM & PTX support memory orderings (weak and atomic: relaxed, acquire, // release, acq_rel, sc) ? bool hasMemoryOrdering() const { - return getSmVersion() >= 70 && PTXVersion >= 60; + return hasFeature(NVPTX::SM70) && PTXVersion >= 60; } // Does SM & PTX support .acquire and .release qualifiers for fence? bool hasSplitAcquireAndReleaseFences() const { - return getSmVersion() >= 90 && PTXVersion >= 86; + return hasFeature(NVPTX::SM90) && PTXVersion >= 86; } // Does SM & PTX support atomic relaxed MMIO operations ? bool hasRelaxedMMIO() const { - return getSmVersion() >= 70 && PTXVersion >= 82; + return hasFeature(NVPTX::SM70) && PTXVersion >= 82; } bool hasDotInstructions() const { - return getSmVersion() >= 61 && PTXVersion >= 50; + return hasFeature(NVPTX::SM61) && PTXVersion >= 50; } // Cache hint SM/PTX version requirements bool hasL1EvictionHint() const { @@ -153,62 +152,49 @@ class NVPTXSubtarget : public NVPTXGenSubtargetInfo { // - tcgen05.commit // - tcgen05.mma bool hasTcgen05InstSupport() const { - // sm_101 renamed to sm_110 in PTX 9.0 - return hasPTXWithFamilySMs(90, {100, 110}) || - hasPTXWithFamilySMs(88, {100, 101}) || - hasPTXWithAccelSMs(86, {100, 101}); + return hasAnyFeature({NVPTX::SM100f, NVPTX::SM110f}); } // Checks tcgen05.shift instruction support. bool hasTcgen05ShiftSupport() const { - // sm_101 renamed to sm_110 in PTX 9.0 - return hasPTXWithAccelSMs(90, {100, 110, 103}) || - hasPTXWithAccelSMs(88, {100, 101, 103}) || - hasPTXWithAccelSMs(86, {100, 101}); + return hasAnyFeature({NVPTX::SM100a, NVPTX::SM103a, NVPTX::SM110a}); } bool hasTcgen05MMAScaleInputDImm() const { - return hasPTXWithFamilySMs(88, {100}) || hasPTXWithAccelSMs(86, {100}); + return hasAnyFeature({NVPTX::SM100f}); } bool hasTcgen05MMAI8Kind() const { - return hasPTXWithAccelSMs(90, {100, 110}) || - hasPTXWithAccelSMs(86, {100, 101}); + return hasAnyFeature({NVPTX::SM100a, NVPTX::SM110a}); } bool hasTcgen05MMASparseMxf4nvf4() const { - return hasPTXWithAccelSMs(90, {100, 110, 103}) || - hasPTXWithAccelSMs(87, {100, 101, 103}); + return PTXVersion >= 87 && + hasAnyFeature({NVPTX::SM100a, NVPTX::SM103a, NVPTX::SM110a}); } bool hasTcgen05MMASparseMxf4() const { - return hasPTXWithAccelSMs(90, {100, 110, 103}) || - hasPTXWithAccelSMs(86, {100, 101, 103}); + return hasAnyFeature({NVPTX::SM100a, NVPTX::SM103a, NVPTX::SM110a}); } bool hasTcgen05LdRedSupport() const { - return hasPTXWithFamilySMs(90, {110, 103}) || - hasPTXWithFamilySMs(88, {101, 103}); + return PTXVersion >= 88 && hasAnyFeature({NVPTX::SM103f, NVPTX::SM110f}); } - bool hasReduxSyncF32() const { - return hasPTXWithFamilySMs(88, {100}) || hasPTXWithAccelSMs(86, {100}); - } + bool hasReduxSyncF32() const { return hasAnyFeature({NVPTX::SM100f}); } - bool hasMMABlockScale() const { - return hasPTXWithFamilySMs(88, {120}) || hasPTXWithAccelSMs(87, {120}); - } + bool hasMMABlockScale() const { return hasAnyFeature({NVPTX::SM120f}); } bool hasMMASparseBlockScaleF4() const { - return hasPTXWithAccelSMs(87, {120, 121}); + return hasAnyFeature({NVPTX::SM120a, NVPTX::SM121a}); } bool hasMMAWithMXF4NVF4Scale4xE8M0() const { - return hasPTXWithFamilySMs(91, {120}); + return PTXVersion >= 91 && hasAnyFeature({NVPTX::SM120f}); } bool hasMMASparseWithMXF4NVF4Scale4xE8M0() const { - return hasPTXWithAccelSMs(91, {120, 121}); + return PTXVersion >= 91 && hasAnyFeature({NVPTX::SM120a, NVPTX::SM121a}); } // f32x2 instructions in Blackwell family @@ -220,18 +206,16 @@ class NVPTXSubtarget : public NVPTXGenSubtargetInfo { // - tile_gather4 mode support // - tile_scatter4 mode support bool hasTMABlackwellSupport() const { - return hasPTXWithFamilySMs(90, {100, 110}) || - hasPTXWithFamilySMs(88, {100, 101}) || - hasPTXWithAccelSMs(86, {100, 101}); + return hasAnyFeature({NVPTX::SM100f, NVPTX::SM110f}); } // Checks support for conversions involving e4m3x2 and e5m2x2. bool hasFP8ConversionSupport() const { if (PTXVersion >= 81) - return getSmVersion() >= 89; + return hasFeature(NVPTX::SM89); if (PTXVersion >= 78) - return getSmVersion() >= 90; + return hasFeature(NVPTX::SM90); return false; } @@ -241,9 +225,7 @@ class NVPTXSubtarget : public NVPTXGenSubtargetInfo { // - e2m1x2 // - ue8m0x2 bool hasNarrowFPConversionSupport() const { - return hasPTXWithFamilySMs(90, {100, 110, 120}) || - hasPTXWithFamilySMs(88, {100, 101, 120}) || - hasPTXWithAccelSMs(86, {100, 101, 120}); + return hasAnyFeature({NVPTX::SM100f, NVPTX::SM110f, NVPTX::SM120f}); } // Checks support for conversions involving the following types: @@ -253,64 +235,63 @@ class NVPTXSubtarget : public NVPTXGenSubtargetInfo { // - f16x2 -> f4x2 // - bf16x2 -> f4x2 bool hasFP16X2ToNarrowFPConversionSupport() const { - return hasPTXWithFamilySMs(91, {100, 110, 120}); + return PTXVersion >= 91 && + hasAnyFeature({NVPTX::SM100f, NVPTX::SM110f, NVPTX::SM120f}); } bool hasS2F6X2ConversionSupport() const { - return hasPTXWithAccelSMs(91, {100, 103, 110, 120, 121}); + return PTXVersion >= 91 && + hasAnyFeature({NVPTX::SM100a, NVPTX::SM103a, NVPTX::SM110a, + NVPTX::SM120a, NVPTX::SM121a}); } // Checks support for conversions from narrow FP types to bf16x2. bool hasNarrowFPToBF16x2ConversionSupport() const { - return hasPTXWithFamilySMs(92, {100, 110, 120}); + return PTXVersion >= 92 && + hasAnyFeature({NVPTX::SM100f, NVPTX::SM110f, NVPTX::SM120f}); } bool hasTensormapReplaceSupport() const { - return hasPTXWithFamilySMs(90, {90, 100, 110, 120}) || - hasPTXWithFamilySMs(88, {90, 100, 101, 120}) || - hasPTXWithAccelSMs(83, {90, 100, 101, 120}); + return hasAnyFeature({NVPTX::SM100f, NVPTX::SM110f, NVPTX::SM120f}) || + (PTXVersion >= 83 && hasAnyFeature({NVPTX::SM90a})); } bool hasTensormapReplaceElemtypeSupport(unsigned ElemType) const { if (ElemType >= static_cast(nvvm::TensormapElemType::B4x16)) - return hasPTXWithFamilySMs(90, {100, 110, 120}) || - hasPTXWithFamilySMs(88, {100, 101, 120}) || - hasPTXWithAccelSMs(87, {100, 101, 120}); + return (PTXVersion >= 88 && + hasAnyFeature({NVPTX::SM100f, NVPTX::SM110f, NVPTX::SM120f})) || + (PTXVersion >= 87 && + hasAnyFeature({NVPTX::SM100a, NVPTX::SM110a, NVPTX::SM120a})); return hasTensormapReplaceSupport(); } bool hasTensormapReplaceSwizzleAtomicitySupport() const { - return hasPTXWithFamilySMs(90, {100, 110, 120}) || - hasPTXWithFamilySMs(88, {100, 101, 120}) || - hasPTXWithAccelSMs(87, {100, 101, 120}); + return (PTXVersion >= 88 && + hasAnyFeature({NVPTX::SM100f, NVPTX::SM110f, NVPTX::SM120f})) || + (PTXVersion >= 87 && + hasAnyFeature({NVPTX::SM100a, NVPTX::SM110a, NVPTX::SM120a})); } bool hasTensormapReplaceSwizzleModeSupport(unsigned SwizzleMode) const { if (SwizzleMode == static_cast(nvvm::TensormapSwizzleMode::SWIZZLE_96B)) - return hasPTXWithAccelSMs(88, {103}); + return hasAnyFeature({NVPTX::SM103a}); return hasTensormapReplaceSupport(); } bool hasClusterLaunchControlTryCancelMulticastSupport() const { - return hasPTXWithFamilySMs(90, {100, 110, 120}) || - hasPTXWithFamilySMs(88, {100, 101, 120}) || - hasPTXWithAccelSMs(86, {100, 101, 120}); + return hasAnyFeature({NVPTX::SM100f, NVPTX::SM110f, NVPTX::SM120f}); } bool hasSetMaxNRegSupport() const { - return hasPTXWithFamilySMs(90, {100, 110, 120}) || - hasPTXWithFamilySMs(88, {100, 101, 120}) || - hasPTXWithAccelSMs(86, {100, 101, 120}) || - hasPTXWithAccelSMs(80, {90}); + return hasAnyFeature( + {NVPTX::SM90a, NVPTX::SM100f, NVPTX::SM110f, NVPTX::SM120f}); } bool hasLdStmatrixBlackwellSupport() const { - return hasPTXWithFamilySMs(90, {100, 110, 120}) || - hasPTXWithFamilySMs(88, {100, 101, 120}) || - hasPTXWithAccelSMs(86, {100, 101, 120}); + return hasAnyFeature({NVPTX::SM100f, NVPTX::SM110f, NVPTX::SM120f}); } // Prior to CUDA 12.3 ptxas did not recognize that the trap instruction @@ -321,36 +302,23 @@ class NVPTXSubtarget : public NVPTXGenSubtargetInfo { // PTX ISA versions 8.3+ we can confidently say that the bug will not be // present. bool hasPTXASUnreachableBug() const { return PTXVersion < 83; } - bool hasCvtaParam() const { return getSmVersion() >= 70 && PTXVersion >= 77; } + bool hasCvtaParam() const { + return hasFeature(NVPTX::SM70) && PTXVersion >= 77; + } bool hasConvertWithStochasticRounding() const { - return hasPTXWithAccelSMs(87, {100, 103}); - } - unsigned getFullSmVersion() const { return FullSmVersion; } - unsigned getSmVersion() const { return getFullSmVersion() / 10; } - unsigned getSmFamilyVersion() const { return getFullSmVersion() / 100; } - // GPUs with "a" suffix have architecture-accelerated features that are - // supported on the specified architecture only, hence such targets do not - // follow the onion layer model. hasArchAccelFeatures() allows distinguishing - // such GPU variants from the base GPU architecture. - // - false represents non-accelerated architecture. - // - true represents architecture-accelerated variant. - bool hasArchAccelFeatures() const { - return (getFullSmVersion() & 1) && PTXVersion >= 80; - } - // GPUs with 'f' suffix have architecture-accelerated features which are - // portable across all future architectures under same SM major. For example, - // sm_100f features will work for sm_10X*f*/sm_10X*a* future architectures. - // - false represents non-family-specific architecture. - // - true represents family-specific variant. - bool hasFamilySpecificFeatures() const { - return getFullSmVersion() % 10 == 2 ? PTXVersion >= 88 - : hasArchAccelFeatures(); - } - // If the user did not provide a target we default to the `sm_75` target. - StringRef getTargetName() const { - return hasTargetName() ? StringRef(TargetName) : "sm_75"; - } - bool hasTargetName() const { return !TargetName.empty(); } + return PTXVersion >= 87 && hasAnyFeature({NVPTX::SM100a, NVPTX::SM103a}); + } + // The compute capability as a number, for __CUDA_ARCH__. This is the one + // place an architecture needs to be a number, and it is not an identity: + // sm_100, sm_100f and sm_100a all report 100. + unsigned getSmVersion() const { return NVPTX::getSmVersion(Arch) / 10; } + + // Whether -mcpu named a target at all, as opposed to falling back to the + // default architecture. + bool hasTargetName() const { return !getCPU().empty(); } + + // The architecture's name, which is what `.target` is emitted from. + StringRef getTargetName() const { return NVPTX::getArchName(Arch); } bool hasNativeBF16Support(unsigned Opcode) const; From 56a654b9a9cffd32318d7ca5c6ee997827c07ecf Mon Sep 17 00:00:00 2001 From: Shoreshen <372660931@qq.com> Date: Fri, 7 Aug 2026 09:33:48 +0800 Subject: [PATCH 032/789] [DAG] Change `isExtractSubvectorCheap` into `getExtractSubvectorCost` (#213614) This changes `isExtractSubvectorCheap` into `getExtractSubvectorCost`. This is preparing for #201056 in order to remove `isNarrowingProfitable` bail out for `narrowInsertExtractVectorBinOp`. The reason is `isNarrowingProfitable` should be applying on scalar variable instead of vectors. --------- Co-authored-by: shore --- llvm/include/llvm/CodeGen/TargetLowering.h | 27 +++++++++++++----- llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 26 +++++++++++------ .../lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 3 +- .../Target/AArch64/AArch64ISelLowering.cpp | 14 +++++++--- llvm/lib/Target/AArch64/AArch64ISelLowering.h | 8 +++--- llvm/lib/Target/AMDGPU/SIISelLowering.cpp | 11 +++++--- llvm/lib/Target/AMDGPU/SIISelLowering.h | 4 +-- llvm/lib/Target/ARM/ARMISelLowering.cpp | 11 +++++--- llvm/lib/Target/ARM/ARMISelLowering.h | 8 +++--- .../Target/Hexagon/HexagonISelLowering.cpp | 13 +++++---- llvm/lib/Target/Hexagon/HexagonISelLowering.h | 4 +-- .../LoongArch/LoongArchISelLowering.cpp | 11 +++++--- .../Target/LoongArch/LoongArchISelLowering.h | 4 +-- llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 28 +++++++++++-------- llvm/lib/Target/RISCV/RISCVISelLowering.h | 4 +-- llvm/lib/Target/X86/X86ISelLowering.cpp | 25 +++++++++++------ llvm/lib/Target/X86/X86ISelLowering.h | 8 +++--- 17 files changed, 131 insertions(+), 78 deletions(-) diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h index f18a3362d4af7..9a525d69b3ee8 100644 --- a/llvm/include/llvm/CodeGen/TargetLowering.h +++ b/llvm/include/llvm/CodeGen/TargetLowering.h @@ -307,6 +307,16 @@ class LLVM_ABI TargetLoweringBase { Expensive = 2 // Negated expression is more expensive. }; + /// Enum that specifies how expensive lowering an EXTRACT_SUBVECTOR is. + enum class ExtractSubvectorCost { + Free = 0, // Lowers to no instruction at all, e.g. a subregister copy. + Cheap = 1, // Lowers to at most one instruction, and may still be free if + // the target can fold the extract into the instruction + // consuming it (e.g. a widening op that reads the high half of + // a register). + Expensive = 2 // Needs a shuffle sequence that cannot be folded away. + }; + /// Enum of different potentially desirable ways to fold (and/or (setcc ...), /// (setcc ...)). enum AndOrSETCCFoldKind : uint8_t { @@ -3540,13 +3550,16 @@ class LLVM_ABI TargetLoweringBase { return false; } - /// Return true if EXTRACT_SUBVECTOR is cheap for extracting this result type - /// from this source type with this index. This is needed because - /// EXTRACT_SUBVECTOR usually has custom lowering that depends on the index of - /// the first element, and only the target knows which lowering is cheap. - virtual bool isExtractSubvectorCheap(EVT ResVT, EVT SrcVT, - unsigned Index) const { - return false; + /// Return the cost of extracting a subvector of type \p ResVT from a vector + /// of type \p SrcVT, starting at element \p Index. + /// + /// Most callers only create a new EXTRACT_SUBVECTOR when the cost is at most + /// ExtractSubvectorCost::Cheap. This hook exists because EXTRACT_SUBVECTOR + /// usually has custom lowering that depends on the index of the first + /// element, so only the target knows which lowering is cheap. + virtual ExtractSubvectorCost getExtractSubvectorCost(EVT ResVT, EVT SrcVT, + unsigned Index) const { + return ExtractSubvectorCost::Expensive; } /// Try to convert an extract element of a vector binary operation into an diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index c669d8d70d103..a11e21769954f 100644 --- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -21922,7 +21922,8 @@ SDValue DAGCombiner::ForwardStoreValueToDirectLoad(LoadSDNode *LD) { InterVT.getVectorNumElements() - LDMemType.getVectorNumElements(); } - if (!TLI.isExtractSubvectorCheap(LDMemType, InterVT, ExtIdx)) + if (TLI.getExtractSubvectorCost(LDMemType, InterVT, ExtIdx) > + TargetLowering::ExtractSubvectorCost::Cheap) break; Val = DAG.getExtractSubvector(SDLoc(LD), LDMemType, DAG.getBitcast(InterVT, Val), ExtIdx); @@ -26341,7 +26342,8 @@ SDValue DAGCombiner::createBuildVecShuffle(const SDLoc &DL, SDNode *N, VecIn1 = DAG.getNode(ISD::CONCAT_VECTORS, DL, VT, ConcatOps); VecIn2 = SDValue(); } else if (InVT1Size == VTSize * 2) { - if (!TLI.isExtractSubvectorCheap(VT, InVT1, NumElems)) + if (TLI.getExtractSubvectorCost(VT, InVT1, NumElems) > + TargetLowering::ExtractSubvectorCost::Cheap) return SDValue(); if (!VecIn2.getNode()) { @@ -26380,7 +26382,8 @@ SDValue DAGCombiner::createBuildVecShuffle(const SDLoc &DL, SDNode *N, ConcatOps[0] = VecIn2; VecIn2 = DAG.getNode(ISD::CONCAT_VECTORS, DL, VT, ConcatOps); } else if (InVT1Size / VTSize > 1 && InVT1Size % VTSize == 0) { - if (!TLI.isExtractSubvectorCheap(VT, InVT1, NumElems) || + if (TLI.getExtractSubvectorCost(VT, InVT1, NumElems) > + TargetLowering::ExtractSubvectorCost::Cheap || !TLI.isTypeLegal(InVT1) || !TLI.isTypeLegal(InVT2)) return SDValue(); // If dest vector has less than two elements, then use shuffle and extract @@ -27856,7 +27859,8 @@ static SDValue narrowExtractedVectorBinOp(EVT VT, SDValue Src, unsigned Index, // bitcasted. unsigned ConcatOpNum = Index / VT.getVectorNumElements(); unsigned ExtBOIdx = ConcatOpNum * NarrowBVT.getVectorNumElements(); - if (TLI.isExtractSubvectorCheap(NarrowBVT, WideBVT, ExtBOIdx) && + if (TLI.getExtractSubvectorCost(NarrowBVT, WideBVT, ExtBOIdx) <= + TargetLowering::ExtractSubvectorCost::Cheap && BinOp.hasOneUse() && Src->hasOneUse()) { // extract (binop B0, B1), N --> binop (extract B0, N), (extract B1, N) SDValue NewExtIndex = DAG.getVectorIdxConstant(ExtBOIdx, DL); @@ -28067,7 +28071,8 @@ static SDValue foldExtractSubvectorFromShuffleVector(EVT NarrowVT, SDValue Src, // How many elements into the WideVT does this subvector start? int Index = NumEltsExtracted * OpSubvecIdx; // Bail out if the extraction isn't going to be cheap. - if (!TLI.isExtractSubvectorCheap(NarrowVT, WideVT, Index)) + if (TLI.getExtractSubvectorCost(NarrowVT, WideVT, Index) > + TargetLowering::ExtractSubvectorCost::Cheap) return SDValue(); } @@ -28190,8 +28195,9 @@ SDValue DAGCombiner::visitEXTRACT_SUBVECTOR(SDNode *N) { uint64_t NewExtIdx = InnerExtIdx + ExtIdx; if (V.getValueType().isScalableVector() == NVT.isScalableVector() && NewExtIdx % NVT.getVectorMinNumElements() == 0 && - TLI.isExtractSubvectorCheap(NVT, V.getOperand(0).getValueType(), - NewExtIdx) && + TLI.getExtractSubvectorCost(NVT, V.getOperand(0).getValueType(), + NewExtIdx) <= + TargetLowering::ExtractSubvectorCost::Cheap && TLI.isOperationLegalOrCustom(ISD::EXTRACT_SUBVECTOR, NVT)) return DAG.getExtractSubvector(DL, NVT, V.getOperand(0), NewExtIdx); } @@ -28200,7 +28206,8 @@ SDValue DAGCombiner::visitEXTRACT_SUBVECTOR(SDNode *N) { if (V.getOpcode() == ISD::SPLAT_VECTOR) if ((DAG.isConstantValueOfAnyType(V.getOperand(0)) && !(NVT.isScalableVector() && - TLI.isExtractSubvectorCheap(NVT, V.getValueType(), ExtIdx))) || + TLI.getExtractSubvectorCost(NVT, V.getValueType(), ExtIdx) <= + TargetLowering::ExtractSubvectorCost::Cheap)) || V.hasOneUse()) if (!LegalOperations || TLI.isOperationLegal(ISD::SPLAT_VECTOR, NVT)) return DAG.getSplatVector(NVT, DL, V.getOperand(0)); @@ -28224,7 +28231,8 @@ SDValue DAGCombiner::visitEXTRACT_SUBVECTOR(SDNode *N) { unsigned InsIdx = V.getConstantOperandVal(2); unsigned NumSubElts = NVT.getVectorMinNumElements(); if (InsIdx <= ExtIdx && (ExtIdx + NumSubElts) <= (InsIdx + NumInsElts) && - TLI.isExtractSubvectorCheap(NVT, InsSubVT, ExtIdx - InsIdx) && + TLI.getExtractSubvectorCost(NVT, InsSubVT, ExtIdx - InsIdx) <= + TargetLowering::ExtractSubvectorCost::Cheap && InsSubVT.isFixedLengthVector() && NVT.isFixedLengthVector() && V.getValueType().isFixedLengthVector()) return DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, NVT, InsSub, diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index 4f5271f4c1d91..b9d0ed344663b 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -14240,7 +14240,8 @@ SelectionDAG::matchBinOpReduction(SDNode *Extract, ISD::NodeType &BinOp, EVT OpVT = Op.getValueType(); EVT OpSVT = OpVT.getScalarType(); EVT SubVT = EVT::getVectorVT(*getContext(), OpSVT, NumSubElts); - if (!TLI->isExtractSubvectorCheap(SubVT, OpVT, 0)) + if (TLI->getExtractSubvectorCost(SubVT, OpVT, 0) > + TargetLowering::ExtractSubvectorCost::Cheap) return SDValue(); BinOp = (ISD::NodeType)CandidateBinOp; return getExtractSubvector(SDLoc(Op), SubVT, Op, 0); diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp index 8bcd90c2a1294..da29cd751c80e 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -20311,12 +20311,18 @@ bool AArch64TargetLowering::shouldConvertConstantLoadToIntImm(const APInt &Imm, return Shift < 3; } -bool AArch64TargetLowering::isExtractSubvectorCheap(EVT ResVT, EVT SrcVT, - unsigned Index) const { +TargetLowering::ExtractSubvectorCost +AArch64TargetLowering::getExtractSubvectorCost(EVT ResVT, EVT SrcVT, + unsigned Index) const { if (!isOperationLegalOrCustom(ISD::EXTRACT_SUBVECTOR, ResVT)) - return false; + return ExtractSubvectorCost::Expensive; + + if (Index == 0) + return ExtractSubvectorCost::Free; - return (Index == 0 || Index == ResVT.getVectorMinNumElements()); + if (Index == ResVT.getVectorMinNumElements()) + return ExtractSubvectorCost::Cheap; + return ExtractSubvectorCost::Expensive; } bool AArch64TargetLowering::shouldOptimizeMulOverflowWithZeroHighBits( diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.h b/llvm/lib/Target/AArch64/AArch64ISelLowering.h index 35f7ef0e2151e..66a6261d2a991 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.h +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.h @@ -329,10 +329,10 @@ class AArch64TargetLowering : public TargetLowering { bool shouldConvertConstantLoadToIntImm(const APInt &Imm, Type *Ty) const override; - /// Return true if EXTRACT_SUBVECTOR is cheap for this result type - /// with this index. - bool isExtractSubvectorCheap(EVT ResVT, EVT SrcVT, - unsigned Index) const override; + /// Return the cost of EXTRACT_SUBVECTOR for this result type with this + /// index. + ExtractSubvectorCost getExtractSubvectorCost(EVT ResVT, EVT SrcVT, + unsigned Index) const override; bool shouldFormOverflowOp(unsigned Opcode, EVT VT, bool MathUsed) const override { diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp index 9b35b24663a58..5687845d2495e 100644 --- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp +++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp @@ -2414,13 +2414,16 @@ bool SITargetLowering::shouldConvertConstantLoadToIntImm(const APInt &Imm, return true; } -bool SITargetLowering::isExtractSubvectorCheap(EVT ResVT, EVT SrcVT, - unsigned Index) const { +TargetLowering::ExtractSubvectorCost +SITargetLowering::getExtractSubvectorCost(EVT ResVT, EVT SrcVT, + unsigned Index) const { if (!isOperationLegalOrCustom(ISD::EXTRACT_SUBVECTOR, ResVT)) - return false; + return ExtractSubvectorCost::Expensive; // TODO: Add more cases that are cheap. - return Index == 0; + if (Index == 0) + return ExtractSubvectorCost::Free; + return ExtractSubvectorCost::Expensive; } bool SITargetLowering::isExtractVecEltCheap(EVT VT, unsigned Index) const { diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.h b/llvm/lib/Target/AMDGPU/SIISelLowering.h index b2f5d70194567..64d71f09edc33 100644 --- a/llvm/lib/Target/AMDGPU/SIISelLowering.h +++ b/llvm/lib/Target/AMDGPU/SIISelLowering.h @@ -406,8 +406,8 @@ class SITargetLowering final : public AMDGPUTargetLowering { bool shouldConvertConstantLoadToIntImm(const APInt &Imm, Type *Ty) const override; - bool isExtractSubvectorCheap(EVT ResVT, EVT SrcVT, - unsigned Index) const override; + ExtractSubvectorCost getExtractSubvectorCost(EVT ResVT, EVT SrcVT, + unsigned Index) const override; bool isExtractVecEltCheap(EVT VT, unsigned Index) const override; bool isTypeDesirableForOp(unsigned Op, EVT VT) const override; diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp index e2b39726c7c0d..3a31e072831aa 100644 --- a/llvm/lib/Target/ARM/ARMISelLowering.cpp +++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp @@ -21496,12 +21496,15 @@ bool ARMTargetLowering::shouldConvertConstantLoadToIntImm(const APInt &Imm, return true; } -bool ARMTargetLowering::isExtractSubvectorCheap(EVT ResVT, EVT SrcVT, - unsigned Index) const { +TargetLowering::ExtractSubvectorCost +ARMTargetLowering::getExtractSubvectorCost(EVT ResVT, EVT SrcVT, + unsigned Index) const { if (!isOperationLegalOrCustom(ISD::EXTRACT_SUBVECTOR, ResVT)) - return false; + return ExtractSubvectorCost::Expensive; - return (Index == 0 || Index == ResVT.getVectorNumElements()); + if (Index == 0 || Index == ResVT.getVectorNumElements()) + return ExtractSubvectorCost::Free; + return ExtractSubvectorCost::Expensive; } Instruction *ARMTargetLowering::makeDMB(IRBuilderBase &Builder, diff --git a/llvm/lib/Target/ARM/ARMISelLowering.h b/llvm/lib/Target/ARM/ARMISelLowering.h index 10f5442d7429b..2bbb91a8758e2 100644 --- a/llvm/lib/Target/ARM/ARMISelLowering.h +++ b/llvm/lib/Target/ARM/ARMISelLowering.h @@ -328,10 +328,10 @@ class VectorType; bool shouldConvertConstantLoadToIntImm(const APInt &Imm, Type *Ty) const override; - /// Return true if EXTRACT_SUBVECTOR is cheap for this result type - /// with this index. - bool isExtractSubvectorCheap(EVT ResVT, EVT SrcVT, - unsigned Index) const override; + /// Return the cost of EXTRACT_SUBVECTOR for this result type with this + /// index. + ExtractSubvectorCost getExtractSubvectorCost(EVT ResVT, EVT SrcVT, + unsigned Index) const override; bool shouldFormOverflowOp(unsigned Opcode, EVT VT, bool MathUsed) const override { diff --git a/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp b/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp index ac3ffa4b9bb0f..44b304919b181 100644 --- a/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp +++ b/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp @@ -2149,18 +2149,21 @@ bool HexagonTargetLowering::shouldExpandBuildVectorWithShuffles(EVT VT, return false; } -bool HexagonTargetLowering::isExtractSubvectorCheap(EVT ResVT, EVT SrcVT, - unsigned Index) const { +TargetLowering::ExtractSubvectorCost +HexagonTargetLowering::getExtractSubvectorCost(EVT ResVT, EVT SrcVT, + unsigned Index) const { assert(ResVT.getVectorElementType() == SrcVT.getVectorElementType()); if (!ResVT.isSimple() || !SrcVT.isSimple()) - return false; + return ExtractSubvectorCost::Expensive; MVT ResTy = ResVT.getSimpleVT(), SrcTy = SrcVT.getSimpleVT(); if (ResTy.getVectorElementType() != MVT::i1) - return true; + return ExtractSubvectorCost::Free; // Non-HVX bool vectors are relatively cheap. - return SrcTy.getVectorNumElements() <= 8; + if (SrcTy.getVectorNumElements() <= 8) + return ExtractSubvectorCost::Free; + return ExtractSubvectorCost::Expensive; } bool HexagonTargetLowering::isTargetCanonicalConstantNode(SDValue Op) const { diff --git a/llvm/lib/Target/Hexagon/HexagonISelLowering.h b/llvm/lib/Target/Hexagon/HexagonISelLowering.h index cf2263fdc2ad8..8e7d31b20a892 100644 --- a/llvm/lib/Target/Hexagon/HexagonISelLowering.h +++ b/llvm/lib/Target/Hexagon/HexagonISelLowering.h @@ -78,8 +78,8 @@ class HexagonTargetLowering : public TargetLowering { // Should we expand the build vector with shuffles? bool shouldExpandBuildVectorWithShuffles(EVT VT, unsigned DefinedValues) const override; - bool isExtractSubvectorCheap(EVT ResVT, EVT SrcVT, - unsigned Index) const override; + ExtractSubvectorCost getExtractSubvectorCost(EVT ResVT, EVT SrcVT, + unsigned Index) const override; bool isTargetCanonicalConstantNode(SDValue Op) const override; diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp index 38f46a9fc9855..e4a369c096545 100644 --- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp +++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp @@ -11787,13 +11787,16 @@ bool LoongArchTargetLowering::shouldScalarizeBinop(SDValue VecOp) const { return isOperationLegalOrCustomOrPromote(Opc, ScalarVT); } -bool LoongArchTargetLowering::isExtractSubvectorCheap(EVT ResVT, EVT SrcVT, - unsigned Index) const { +TargetLowering::ExtractSubvectorCost +LoongArchTargetLowering::getExtractSubvectorCost(EVT ResVT, EVT SrcVT, + unsigned Index) const { if (!isOperationLegalOrCustom(ISD::EXTRACT_SUBVECTOR, ResVT)) - return false; + return ExtractSubvectorCost::Expensive; // Extract a 128-bit subvector from index 0 of a 256-bit vector is free. - return Index == 0; + if (Index == 0) + return ExtractSubvectorCost::Free; + return ExtractSubvectorCost::Expensive; } bool LoongArchTargetLowering::isExtractVecEltCheap(EVT VT, diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h index 32e32ab9148af..b30bdeef1812c 100644 --- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h +++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h @@ -169,8 +169,8 @@ class LoongArchTargetLowering : public TargetLowering { unsigned Depth) const override; bool shouldScalarizeBinop(SDValue VecOp) const override; - bool isExtractSubvectorCheap(EVT ResVT, EVT SrcVT, - unsigned Index) const override; + ExtractSubvectorCost getExtractSubvectorCost(EVT ResVT, EVT SrcVT, + unsigned Index) const override; bool isExtractVecEltCheap(EVT VT, unsigned Index) const override; /// Check if a constant splat can be generated using [x]vldi, where imm[12] diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index 1c5a8e4b79483..ea4803e59ebc1 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -2871,32 +2871,36 @@ bool RISCVTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT, } // TODO: This is very conservative. -bool RISCVTargetLowering::isExtractSubvectorCheap(EVT ResVT, EVT SrcVT, - unsigned Index) const { +TargetLowering::ExtractSubvectorCost +RISCVTargetLowering::getExtractSubvectorCost(EVT ResVT, EVT SrcVT, + unsigned Index) const { if (Subtarget.hasStdExtP() && !Subtarget.is64Bit() && - (ResVT == MVT::v4i8 || ResVT == MVT::v2i16)) - return (Index % ResVT.getVectorNumElements()) == 0; + (ResVT == MVT::v4i8 || ResVT == MVT::v2i16)) { + if ((Index % ResVT.getVectorNumElements()) == 0) + return ExtractSubvectorCost::Free; + return ExtractSubvectorCost::Expensive; + } if (!Subtarget.hasVInstructions()) - return false; + return ExtractSubvectorCost::Expensive; if (!isOperationLegalOrCustom(ISD::EXTRACT_SUBVECTOR, ResVT)) - return false; + return ExtractSubvectorCost::Expensive; // Extracts from index 0 are just subreg extracts. if (Index == 0) - return true; + return ExtractSubvectorCost::Free; // Only support extracting a fixed from a fixed vector for now. if (ResVT.isScalableVector() || SrcVT.isScalableVector()) - return false; + return ExtractSubvectorCost::Expensive; EVT EltVT = ResVT.getVectorElementType(); assert(EltVT == SrcVT.getVectorElementType() && "Should hold for node"); // The smallest type we can slide is i8. if (EltVT == MVT::i1) - return false; + return ExtractSubvectorCost::Expensive; unsigned ResElts = ResVT.getVectorNumElements(); unsigned SrcElts = SrcVT.getVectorNumElements(); @@ -2909,7 +2913,7 @@ bool RISCVTargetLowering::isExtractSubvectorCheap(EVT ResVT, EVT SrcVT, // Index ensures we can use a vslidedown.vi. // TODO: We can generalize this when the exact VLEN is known. if (Index + ResElts <= MinVLMAX && Index < 31) - return true; + return ExtractSubvectorCost::Free; // Convervatively only handle extracting half of a vector. // TODO: We can do arbitrary slidedowns, but for now only support extracting @@ -2917,7 +2921,9 @@ bool RISCVTargetLowering::isExtractSubvectorCheap(EVT ResVT, EVT SrcVT, // TODO: For sizes which aren't multiples of VLEN sizes, this may not be // a cheap extract. However, this case is important in practice for // shuffled extracts of longer vectors. How resolve? - return (ResElts * 2) == SrcElts && Index == ResElts; + if ((ResElts * 2) == SrcElts && Index == ResElts) + return ExtractSubvectorCost::Free; + return ExtractSubvectorCost::Expensive; } MVT RISCVTargetLowering::getRegisterTypeForCallingConv(LLVMContext &Context, diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.h b/llvm/lib/Target/RISCV/RISCVISelLowering.h index 2ca7c392639f7..972cc256a3386 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.h +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.h @@ -64,8 +64,8 @@ class RISCVTargetLowering : public TargetLowering { int getLegalZfaFPImm(const APFloat &Imm, EVT VT) const; bool isFPImmLegal(const APFloat &Imm, EVT VT, bool ForCodeSize) const override; - bool isExtractSubvectorCheap(EVT ResVT, EVT SrcVT, - unsigned Index) const override; + ExtractSubvectorCost getExtractSubvectorCost(EVT ResVT, EVT SrcVT, + unsigned Index) const override; bool isIntDivCheap(EVT VT, AttributeList Attr) const override; diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp index 0afc81ccad9e0..f62bf664d970a 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -3611,19 +3611,26 @@ bool X86TargetLowering::decomposeMulByConstant(LLVMContext &Context, EVT VT, (1 - MulC).isPowerOf2() || (-(MulC + 1)).isPowerOf2(); } -bool X86TargetLowering::isExtractSubvectorCheap(EVT ResVT, EVT SrcVT, - unsigned Index) const { +TargetLowering::ExtractSubvectorCost +X86TargetLowering::getExtractSubvectorCost(EVT ResVT, EVT SrcVT, + unsigned Index) const { if (!isOperationLegalOrCustom(ISD::EXTRACT_SUBVECTOR, ResVT)) - return false; + return ExtractSubvectorCost::Expensive; // Mask vectors support all subregister combinations and operations that // extract half of vector. - if (ResVT.getVectorElementType() == MVT::i1) - return Index == 0 || - ((ResVT.getSizeInBits() * 2 == SrcVT.getSizeInBits()) && - (Index == ResVT.getVectorNumElements())); - - return (Index % ResVT.getVectorNumElements()) == 0; + if (ResVT.getVectorElementType() == MVT::i1) { + if (Index == 0 || ((ResVT.getSizeInBits() * 2 == SrcVT.getSizeInBits()) && + (Index == ResVT.getVectorNumElements()))) + return ExtractSubvectorCost::Free; + return ExtractSubvectorCost::Expensive; + } + + if (Index == 0) + return ExtractSubvectorCost::Free; + else if ((Index % ResVT.getVectorNumElements()) == 0) + return ExtractSubvectorCost::Cheap; + return ExtractSubvectorCost::Expensive; } bool X86TargetLowering::shouldScalarizeBinop(SDValue VecOp) const { diff --git a/llvm/lib/Target/X86/X86ISelLowering.h b/llvm/lib/Target/X86/X86ISelLowering.h index 798050028c15a..a4b4e6f32591b 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.h +++ b/llvm/lib/Target/X86/X86ISelLowering.h @@ -576,10 +576,10 @@ namespace llvm { bool decomposeMulByConstant(LLVMContext &Context, EVT VT, SDValue C) const override; - /// Return true if EXTRACT_SUBVECTOR is cheap for this result type - /// with this index. - bool isExtractSubvectorCheap(EVT ResVT, EVT SrcVT, - unsigned Index) const override; + /// Return the cost of EXTRACT_SUBVECTOR for this result type with this + /// index. + ExtractSubvectorCost getExtractSubvectorCost(EVT ResVT, EVT SrcVT, + unsigned Index) const override; /// Scalar ops always have equal or better analysis/performance/power than /// the vector equivalent, so this always makes sense if the scalar op is From c6eb5e390833295393e4d96c64adc67c4e3729b8 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Thu, 6 Aug 2026 18:54:02 -0700 Subject: [PATCH 033/789] [docs][clang-format] Migrate generated clang-format docs to markdown (#211398) Tracking issue: #201242 See the [migration guide] for more information. This is a stacked PR based on #211397 , which will be a standalone commit that renames *.rst -> *.md before this PR lands for history preservation purposes. [migration guide]: https://llvm.org/docs/SphinxQuickstartTemplate.html#markdown-migration-guidelines First, the generator was updated to generate markdown constructs, and then the Doxygen comments in `Format.h` and `IncludeStyle.h` were also modified to use markdown constructs. Mostly this means using single backticks instead of double backticks, which is the Doxygen-native way of expressing code font blocks anyway, so that's good. To validate, I built the Sphinx docs and the doxygen, and I confirmed that the generator script is idempotent, meaning it doesn't change the markdown output. When I add a new option to clang-format, it shows up in the help text block, so it works. --- clang/docs/ClangFormat.md | 555 +- clang/docs/ClangFormatStyleOptions.md | 10534 ++++++++-------- clang/docs/tools/dump_format_help.py | 14 +- clang/docs/tools/dump_format_style.py | 136 +- clang/include/clang/Format/Format.h | 808 +- .../clang/Tooling/Inclusions/IncludeStyle.h | 67 +- 6 files changed, 6174 insertions(+), 5940 deletions(-) diff --git a/clang/docs/ClangFormat.md b/clang/docs/ClangFormat.md index 26490f9c15bb8..94fd51a3c1a0a 100644 --- a/clang/docs/ClangFormat.md +++ b/clang/docs/ClangFormat.md @@ -1,187 +1,179 @@ -=========== -ClangFormat -=========== +# ClangFormat `ClangFormat` describes a set of tools that are built on top of -:doc:`LibFormat`. It can support your workflow in a variety of ways including a +{doc}`LibFormat`. It can support your workflow in a variety of ways including a standalone tool and editor integrations. +## Standalone Tool -Standalone Tool -=============== - -:program:`clang-format` is located in `clang/tools/clang-format` and can be used +{program}`clang-format` is located in `clang/tools/clang-format` and can be used to format C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C# code. -.. START_FORMAT_HELP - -.. code-block:: console - - $ clang-format --help - OVERVIEW: A tool to format C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C# code. - - If no arguments are specified, it formats the code from standard input - and writes the result to the standard output. - If s are given, it reformats the files. If -i is specified - together with s, the files are edited in-place. Otherwise, the - result is written to the standard output. - - USAGE: clang-format [options] [@] [ ...] - - OPTIONS: - - Clang-format options: - - --Werror - If set, changes formatting warnings to errors - --Wno-error= - If set, don't error out on the specified warning type. - =unknown - If set, unknown format options are only warned about. - This can be used to enable formatting, even if the - configuration contains unknown (newer) options. - Use with caution, as this might lead to dramatically - differing format depending on an option being - supported or not. - --assume-filename= - Set filename used to determine the language and to find - .clang-format file. - Only used when reading from stdin. - If this is not passed, the .clang-format file is searched - relative to the current working directory when reading stdin. - Unrecognized filenames are treated as C++. - supported: - CSharp: .cs - Java: .java - JavaScript: .js .mjs .cjs .ts - JSON: .json .ipynb - Objective-C: .m .mm - Proto: .proto .protodevel - TableGen: .td - TextProto: .txtpb .textpb .pb.txt .textproto .asciipb - Verilog: .sv .svh .v .vh - --cursor= - The position of the cursor when invoking - clang-format from an editor integration - --dry-run - If set, do not actually make the formatting changes - --dump-config - Dump configuration options to stdout and exit. - Can be used with -style option. - --fail-on-incomplete-format - If set, fail with exit code 1 on incomplete format. - --fallback-style= - The name of the predefined style used as a - fallback in case clang-format is invoked with - -style=file, but can not find the .clang-format - file to use. Defaults to 'LLVM'. - Use -fallback-style=none to skip formatting. - --ferror-limit= - Set the maximum number of clang-format errors to emit - before stopping (0 = no limit). - Used only with --dry-run or -n - --files= - A file containing a list of files to process, one per line. - -i - Inplace edit s, if specified. - --length= - Format a range of this length (in bytes). - Multiple ranges can be formatted by specifying - several -offset and -length pairs. - When only a single -offset is specified without - -length, clang-format will format up to the end - of the file. - Can only be used with one input file. - --lines= - : - format a range of - lines (both 1-based). - Multiple ranges can be formatted by specifying - several -lines arguments. - Can't be used with -offset and -length. - Can only be used with one input file. - -n - Alias for --dry-run - --offset= - Format a range starting at this byte offset. - Multiple ranges can be formatted by specifying - several -offset and -length pairs. - Can only be used with one input file. - --output-replacements-xml - Output replacements as XML. - --qualifier-alignment= - If set, overrides the qualifier alignment style - determined by the QualifierAlignment style flag - --sort-includes - If set, overrides the include sorting behavior - determined by the SortIncludes style flag - --style= - Set coding style. can be: - 1. A preset: LLVM, GNU, Google, Chromium, Microsoft, - Mozilla, WebKit. - 2. 'file' to load style configuration from a - .clang-format file in one of the parent directories - of the source file (for stdin, see --assume-filename). - If no .clang-format file is found, falls back to - --fallback-style. - --style=file is the default. - 3. 'file:' to explicitly specify - the configuration file. - 4. "{key: value, ...}" to set specific parameters, e.g.: - --style="{BasedOnStyle: llvm, IndentWidth: 8}" - --verbose - If set, shows the list of processed files - - Generic Options: - - --help - Display available options (--help-hidden for more) - --help-list - Display list of available options (--help-list-hidden for more) - --version - Display the version of this program - - -.. END_FORMAT_HELP +% START_FORMAT_HELP + +```console +$ clang-format --help +OVERVIEW: A tool to format C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C# code. + +If no arguments are specified, it formats the code from standard input +and writes the result to the standard output. +If s are given, it reformats the files. If -i is specified +together with s, the files are edited in-place. Otherwise, the +result is written to the standard output. + +USAGE: clang-format [options] [@] [ ...] + +OPTIONS: + +Clang-format options: + + --Werror - If set, changes formatting warnings to errors + --Wno-error= - If set, don't error out on the specified warning type. + =unknown - If set, unknown format options are only warned about. + This can be used to enable formatting, even if the + configuration contains unknown (newer) options. + Use with caution, as this might lead to dramatically + differing format depending on an option being + supported or not. + --assume-filename= - Set filename used to determine the language and to find + .clang-format file. + Only used when reading from stdin. + If this is not passed, the .clang-format file is searched + relative to the current working directory when reading stdin. + Unrecognized filenames are treated as C++. + supported: + CSharp: .cs + Java: .java + JavaScript: .js .mjs .cjs .ts + JSON: .json .ipynb + Objective-C: .m .mm + Proto: .proto .protodevel + TableGen: .td + TextProto: .txtpb .textpb .pb.txt .textproto .asciipb + Verilog: .sv .svh .v .vh + --cursor= - The position of the cursor when invoking + clang-format from an editor integration + --dry-run - If set, do not actually make the formatting changes + --dump-config - Dump configuration options to stdout and exit. + Can be used with -style option. + --fail-on-incomplete-format - If set, fail with exit code 1 on incomplete format. + --fallback-style= - The name of the predefined style used as a + fallback in case clang-format is invoked with + -style=file, but can not find the .clang-format + file to use. Defaults to 'LLVM'. + Use -fallback-style=none to skip formatting. + --ferror-limit= - Set the maximum number of clang-format errors to emit + before stopping (0 = no limit). + Used only with --dry-run or -n + --files= - A file containing a list of files to process, one per line. + -i - Inplace edit s, if specified. + --length= - Format a range of this length (in bytes). + Multiple ranges can be formatted by specifying + several -offset and -length pairs. + When only a single -offset is specified without + -length, clang-format will format up to the end + of the file. + Can only be used with one input file. + --lines= - : - format a range of + lines (both 1-based). + Multiple ranges can be formatted by specifying + several -lines arguments. + Can't be used with -offset and -length. + Can only be used with one input file. + -n - Alias for --dry-run + --offset= - Format a range starting at this byte offset. + Multiple ranges can be formatted by specifying + several -offset and -length pairs. + Can only be used with one input file. + --output-replacements-xml - Output replacements as XML. + --qualifier-alignment= - If set, overrides the qualifier alignment style + determined by the QualifierAlignment style flag + --sort-includes - If set, overrides the include sorting behavior + determined by the SortIncludes style flag + --style= - Set coding style. can be: + 1. A preset: LLVM, GNU, Google, Chromium, Microsoft, + Mozilla, WebKit. + 2. 'file' to load style configuration from a + .clang-format file in one of the parent directories + of the source file (for stdin, see --assume-filename). + If no .clang-format file is found, falls back to + --fallback-style. + --style=file is the default. + 3. 'file:' to explicitly specify + the configuration file. + 4. "{key: value, ...}" to set specific parameters, e.g.: + --style="{BasedOnStyle: llvm, IndentWidth: 8}" + --verbose - If set, shows the list of processed files + +Generic Options: + + --help - Display available options (--help-hidden for more) + --help-list - Display list of available options (--help-list-hidden for more) + --version - Display the version of this program +``` + +% END_FORMAT_HELP When the desired code formatting style is different from the available options, -the style can be customized using the ``-style="{key: value, ...}"`` option or -by putting your style configuration in the ``.clang-format`` or ``_clang-format`` -file in your project's directory and using ``clang-format -style=file``. - -An easy way to create the ``.clang-format`` file is: +the style can be customized using the `-style="{key: value, ...}"` option or +by putting your style configuration in the `.clang-format` or `_clang-format` +file in your project's directory and using `clang-format -style=file`. -.. code-block:: console +An easy way to create the `.clang-format` file is: - clang-format -style=llvm -dump-config > .clang-format +```console +clang-format -style=llvm -dump-config > .clang-format +``` -Available style options are described in :doc:`ClangFormatStyleOptions`. +Available style options are described in {doc}`ClangFormatStyleOptions`. -.clang-format-ignore -==================== +## .clang-format-ignore -You can create ``.clang-format-ignore`` files to make ``clang-format`` ignore -certain files. A ``.clang-format-ignore`` file consists of patterns of file path +You can create `.clang-format-ignore` files to make `clang-format` ignore +certain files. A `.clang-format-ignore` file consists of patterns of file path names. It has the following format: -* A blank line is skipped. -* Leading and trailing spaces of a line are trimmed. -* A line starting with a hash (``#``) is a comment. -* A non-comment line is a single pattern. -* The slash (``/``) is used as the directory separator. -* A pattern is relative to the directory of the ``.clang-format-ignore`` file +- A blank line is skipped. +- Leading and trailing spaces of a line are trimmed. +- A line starting with a hash (`#`) is a comment. +- A non-comment line is a single pattern. +- The slash (`/`) is used as the directory separator. +- A pattern is relative to the directory of the `.clang-format-ignore` file (or the root directory if the pattern starts with a slash). Patterns - containing drive names (e.g. ``C:``) are not supported. -* Patterns follow the rules specified in `POSIX 2.13.1, 2.13.2, and Rule 1 of - 2.13.3 `_. -* Bash globstar (``**``) is supported. -* A pattern is negated if it starts with a bang (``!``). - -To match all files in a directory, use e.g. ``foo/bar/*``. To match all files in -the directory of the ``.clang-format-ignore`` file, use ``*``. -Multiple ``.clang-format-ignore`` files are supported similar to the -``.clang-format`` files, with a lower directory level file voiding the higher + containing drive names (e.g. `C:`) are not supported. +- Patterns follow the rules specified in [POSIX 2.13.1, 2.13.2, and Rule 1 of + 2.13.3](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13). +- Bash globstar (`**`) is supported. +- A pattern is negated if it starts with a bang (`!`). + +To match all files in a directory, use e.g. `foo/bar/*`. To match all files in +the directory of the `.clang-format-ignore` file, use `*`. +Multiple `.clang-format-ignore` files are supported similar to the +`.clang-format` files, with a lower directory level file voiding the higher level ones. -Vim Integration -=============== +## Vim Integration -There is an integration for :program:`vim` which lets you run the -:program:`clang-format` standalone tool on your current buffer, optionally +There is an integration for {program}`vim` which lets you run the +{program}`clang-format` standalone tool on your current buffer, optionally selecting regions to reformat. The integration has the form of a `python`-file which can be found under `clang/tools/clang-format/clang-format.py`. This can be integrated by adding the following to your `.vimrc`: -.. code-block:: vim - - if has('python') - map :pyf /clang-format.py - imap :pyf /clang-format.py - elseif has('python3') - map :py3f /clang-format.py - imap :py3f /clang-format.py - endif - -The first line enables :program:`clang-format` for NORMAL and VISUAL mode, the +```vim +if has('python') + map :pyf /clang-format.py + imap :pyf /clang-format.py +elseif has('python3') + map :py3f /clang-format.py + imap :py3f /clang-format.py +endif +``` + +The first line enables {program}`clang-format` for NORMAL and VISUAL mode, the second line adds support for INSERT mode. Change "C-K" to another binding if -you need :program:`clang-format` on a different key (C-K stands for Ctrl+k). +you need {program}`clang-format` on a different key (C-K stands for Ctrl+k). With this integration you can press the bound key and clang-format will format the current line in NORMAL and INSERT mode or the selected region in @@ -195,169 +187,158 @@ An alternative option is to format changes when saving a file and thus to have a zero-effort integration into the coding workflow. To do this, add this to your `.vimrc`: -.. code-block:: vim +```vim +function! Formatonsave() + let l:formatdiff = 1 + pyf /clang-format.py +endfunction +autocmd BufWritePre *.h,*.cc,*.cpp call Formatonsave() +``` - function! Formatonsave() - let l:formatdiff = 1 - pyf /clang-format.py - endfunction - autocmd BufWritePre *.h,*.cc,*.cpp call Formatonsave() +## Emacs Integration - -Emacs Integration -================= - -Similar to the integration for :program:`vim`, there is an integration for -:program:`emacs`. It can be found at `clang/tools/clang-format/clang-format.el` +Similar to the integration for {program}`vim`, there is an integration for +{program}`emacs`. It can be found at `clang/tools/clang-format/clang-format.el` and used by adding this to your `.emacs`: -.. code-block:: common-lisp - - (load "/tools/clang-format/clang-format.el") - (global-set-key [C-M-tab] 'clang-format-region) +```common-lisp +(load "/tools/clang-format/clang-format.el") +(global-set-key [C-M-tab] 'clang-format-region) +``` This binds the function `clang-format-region` to C-M-tab, which then formats the current line or selected region. +## BBEdit Integration -BBEdit Integration -================== - -:program:`clang-format` cannot be used as a text filter with BBEdit, but works +{program}`clang-format` cannot be used as a text filter with BBEdit, but works well via a script. The AppleScript to do this integration can be found at `clang/tools/clang-format/clang-format-bbedit.applescript`; place a copy in `~/Library/Application Support/BBEdit/Scripts`, and edit the path within it to -point to your local copy of :program:`clang-format`. +point to your local copy of {program}`clang-format`. With this integration you can select the script from the Script menu and -:program:`clang-format` will format the selection. Note that you can rename the +{program}`clang-format` will format the selection. Note that you can rename the menu item by renaming the script, and can assign the menu item a keyboard shortcut in the BBEdit preferences, under Menus & Shortcuts. +## CLion Integration -CLion Integration -================= - -:program:`clang-format` is integrated into `CLion `_ as an alternative code formatter. CLion turns it on -automatically when there is a ``.clang-format`` file under the project root. -Code style rules are applied as you type, including indentation, +{program}`clang-format` is integrated into +[CLion](https://www.jetbrains.com/clion/) as an alternative code formatter. +CLion turns it on automatically when there is a `.clang-format` file under the +project root. Code style rules are applied as you type, including indentation, auto-completion, code generation, and refactorings. -:program:`clang-format` can also be enabled without a ``.clang-format`` file. +{program}`clang-format` can also be enabled without a `.clang-format` file. In this case, CLion prompts you to create one based on the current IDE settings or the default LLVM style. +## Visual Studio Integration -Visual Studio Integration -========================= - -Download the latest Visual Studio extension from the `alpha build site -`_. The default key-binding is Ctrl-R,Ctrl-F. +Download the latest Visual Studio extension from the [alpha build +site](https://llvm.org/builds/). The default key-binding is Ctrl-R,Ctrl-F. +## Visual Studio Code Integration -Visual Studio Code Integration -============================== +Get the latest Visual Studio Code extension from the [Visual Studio +Marketplace](https://marketplace.visualstudio.com/items?itemName=xaver.clang-format). +The default key-binding is Alt-Shift-F. -Get the latest Visual Studio Code extension from the `Visual Studio Marketplace `_. The default key-binding is Alt-Shift-F. - -Git integration -=============== +## Git integration The script `clang/tools/clang-format/git-clang-format` can be used to format just the lines touched in git commits: -.. code-block:: console - - % git clang-format -h - usage: git clang-format [OPTIONS] [] [|--staged] [--] [...] - - If zero or one commits are given, run clang-format on all lines that differ - between the working directory and , which defaults to HEAD. Changes are - only applied to the working directory, or in the stage/index. - - Examples: - To format staged changes, i.e everything that's been `git add`ed: - git clang-format - - To also format everything touched in the most recent commit: - git clang-format HEAD~1 - - If you're on a branch off main, to format everything touched on your branch: - git clang-format main - - If two commits are given (requires --diff), run clang-format on all lines in the - second that differ from the first . - - The following git-config settings set the default of the corresponding option: - clangFormat.binary - clangFormat.commit - clangFormat.extensions - clangFormat.style - - positional arguments: - revision from which to compute the diff - ... if specified, only consider differences in these files - - optional arguments: - -h, --help show this help message and exit - --binary BINARY path to clang-format - --commit COMMIT default commit to use if none is specified - --diff print a diff instead of applying the changes - --diffstat print a diffstat instead of applying the changes - --extensions EXTENSIONS - comma-separated list of file extensions to format, excluding the period and case-insensitive - -f, --force allow changes to unstaged files - -p, --patch select hunks interactively - -q, --quiet print less information - --staged, --cached format lines in the stage instead of the working dir - --style STYLE passed to clang-format - -v, --verbose print extra information - - -Script for patch reformatting -============================= +```console +% git clang-format -h +usage: git clang-format [OPTIONS] [] [|--staged] [--] [...] + +If zero or one commits are given, run clang-format on all lines that differ +between the working directory and , which defaults to HEAD. Changes are +only applied to the working directory, or in the stage/index. + +Examples: + To format staged changes, i.e everything that's been `git add`ed: + git clang-format + + To also format everything touched in the most recent commit: + git clang-format HEAD~1 + + If you're on a branch off main, to format everything touched on your branch: + git clang-format main + +If two commits are given (requires --diff), run clang-format on all lines in the +second that differ from the first . + +The following git-config settings set the default of the corresponding option: + clangFormat.binary + clangFormat.commit + clangFormat.extensions + clangFormat.style + +positional arguments: + revision from which to compute the diff + ... if specified, only consider differences in these files + +optional arguments: + -h, --help show this help message and exit + --binary BINARY path to clang-format + --commit COMMIT default commit to use if none is specified + --diff print a diff instead of applying the changes + --diffstat print a diffstat instead of applying the changes + --extensions EXTENSIONS + comma-separated list of file extensions to format, excluding the period and case-insensitive + -f, --force allow changes to unstaged files + -p, --patch select hunks interactively + -q, --quiet print less information + --staged, --cached format lines in the stage instead of the working dir + --style STYLE passed to clang-format + -v, --verbose print extra information +``` + +## Script for patch reformatting The python script `clang/tools/clang-format/clang-format-diff.py` parses the output of a unified diff and reformats all contained lines with -:program:`clang-format`. - -.. code-block:: console - - usage: clang-format-diff.py [-h] [-i] [-p NUM] [-regex PATTERN] [-iregex PATTERN] [-sort-includes] [-v] [-style STYLE] - [-fallback-style FALLBACK_STYLE] [-binary BINARY] - - This script reads input from a unified diff and reformats all the changed - lines. This is useful to reformat all the lines touched by a specific patch. - Example usage for git/svn users: - - git diff -U0 --no-color --relative HEAD^ | clang-format-diff.py -p1 -i - svn diff --diff-cmd=diff -x-U0 | clang-format-diff.py -i - - It should be noted that the filename contained in the diff is used unmodified - to determine the source file to update. Users calling this script directly - should be careful to ensure that the path in the diff is correct relative to the - current working directory. - - optional arguments: - -h, --help show this help message and exit - -i apply edits to files instead of displaying a diff - -p NUM strip the smallest prefix containing P slashes - -regex PATTERN custom pattern selecting file paths to reformat (case sensitive, overrides -iregex) - -iregex PATTERN custom pattern selecting file paths to reformat (case insensitive, overridden by -regex) - -sort-includes let clang-format sort include blocks - -v, --verbose be more verbose, ineffective without -i - -style STYLE formatting style to apply (LLVM, GNU, Google, Chromium, Microsoft, Mozilla, WebKit) - -fallback-style FALLBACK_STYLE - The name of the predefined style used as a fallback in case clang-format is invoked with-style=file, but can not - find the .clang-formatfile to use. - -binary BINARY location of binary to use for clang-format - -To reformat all the lines in the latest Mercurial/:program:`hg` commit, do: - -.. code-block:: console - - hg diff -U0 --color=never | clang-format-diff.py -i -p1 +{program}`clang-format`. + +```console +usage: clang-format-diff.py [-h] [-i] [-p NUM] [-regex PATTERN] [-iregex PATTERN] [-sort-includes] [-v] [-style STYLE] + [-fallback-style FALLBACK_STYLE] [-binary BINARY] + +This script reads input from a unified diff and reformats all the changed +lines. This is useful to reformat all the lines touched by a specific patch. +Example usage for git/svn users: + + git diff -U0 --no-color --relative HEAD^ | clang-format-diff.py -p1 -i + svn diff --diff-cmd=diff -x-U0 | clang-format-diff.py -i + +It should be noted that the filename contained in the diff is used unmodified +to determine the source file to update. Users calling this script directly +should be careful to ensure that the path in the diff is correct relative to the +current working directory. + +optional arguments: + -h, --help show this help message and exit + -i apply edits to files instead of displaying a diff + -p NUM strip the smallest prefix containing P slashes + -regex PATTERN custom pattern selecting file paths to reformat (case sensitive, overrides -iregex) + -iregex PATTERN custom pattern selecting file paths to reformat (case insensitive, overridden by -regex) + -sort-includes let clang-format sort include blocks + -v, --verbose be more verbose, ineffective without -i + -style STYLE formatting style to apply (LLVM, GNU, Google, Chromium, Microsoft, Mozilla, WebKit) + -fallback-style FALLBACK_STYLE + The name of the predefined style used as a fallback in case clang-format is invoked with-style=file, but can not + find the .clang-formatfile to use. + -binary BINARY location of binary to use for clang-format +``` + +To reformat all the lines in the latest Mercurial/{program}`hg` commit, do: + +```console +hg diff -U0 --color=never | clang-format-diff.py -i -p1 +``` The option `-U0` will create a diff without context lines (the script would format those as well). diff --git a/clang/docs/ClangFormatStyleOptions.md b/clang/docs/ClangFormatStyleOptions.md index e8cf2409e6c70..9b962e6e1e083 100644 --- a/clang/docs/ClangFormatStyleOptions.md +++ b/clang/docs/ClangFormatStyleOptions.md @@ -1,283 +1,268 @@ -.. - !!!!NOTE!!!! - This file is automatically generated, in part. Do not edit the style options - in this file directly. Instead, modify them in include/clang/Format/Format.h - and run the docs/tools/dump_format_style.py script to update this file. - -.. raw:: html - - - +% !!!!NOTE!!!! +% This file is automatically generated, in part. Do not edit the style options +% in this file directly. Instead, modify them in include/clang/Format/Format.h +% and run the docs/tools/dump_format_style.py script to update this file. + +```{raw} html + +``` + +```{eval-rst} .. role:: versionbadge +``` -========================== -Clang-Format Style Options -========================== +# Clang-Format Style Options -:doc:`ClangFormatStyleOptions` describes configurable formatting style options -supported by :doc:`LibFormat` and :doc:`ClangFormat`. +{doc}`ClangFormatStyleOptions` describes configurable formatting style options +supported by {doc}`LibFormat` and {doc}`ClangFormat`. -When using :program:`clang-format` command line utility or -``clang::format::reformat(...)`` functions from code, one can either use one of +When using {program}`clang-format` command line utility or +`clang::format::reformat(...)` functions from code, one can either use one of the predefined styles (LLVM, Google, Chromium, Mozilla, WebKit, Microsoft) or create a custom style by configuring specific style options. +## Configuring Style with clang-format -Configuring Style with clang-format -=================================== - -:program:`clang-format` supports two ways to provide custom style options: -directly specify style configuration in the ``-style=`` command line option or -use ``-style=file`` and put style configuration in the ``.clang-format`` or -``_clang-format`` file in the project directory. +{program}`clang-format` supports two ways to provide custom style options: +directly specify style configuration in the `-style=` command line option or +use `-style=file` and put style configuration in the `.clang-format` or +`_clang-format` file in the project directory. -When using ``-style=file``, :program:`clang-format` for each input file will -try to find the ``.clang-format`` file located in the closest parent directory +When using `-style=file`, {program}`clang-format` for each input file will +try to find the `.clang-format` file located in the closest parent directory of the input file. When the standard input is used, the search is started from the current directory. -When using ``-style=file:``, :program:`clang-format` for +When using `-style=file:`, {program}`clang-format` for each input file will use the format file located at ``. The path may be absolute or relative to the working directory. -The ``.clang-format`` file uses YAML format: +The `.clang-format` file uses YAML format: -.. code-block:: yaml - - key1: value1 - key2: value2 - # A comment. - ... +```yaml +key1: value1 +key2: value2 +# A comment. +... +``` The configuration file can consist of several sections each having different -``Language:`` parameter denoting the programming language this section of the +`Language:` parameter denoting the programming language this section of the configuration is targeted at. See the description of the **Language** option below for the list of supported languages. The first section may have no language set, it will set the default style options for all languages. Configuration sections for specific language will override options set in the default section. -When :program:`clang-format` formats a file, it auto-detects the language using +When {program}`clang-format` formats a file, it auto-detects the language using the file name. When formatting standard input or a file that doesn't have the -extension corresponding to its language, ``-assume-filename=`` option can be -used to override the file name :program:`clang-format` uses to detect the +extension corresponding to its language, `-assume-filename=` option can be +used to override the file name {program}`clang-format` uses to detect the language. An example of a configuration file for multiple languages: -.. code-block:: yaml - - --- - # We'll use defaults from the LLVM style, but with 4 columns indentation. - BasedOnStyle: LLVM - IndentWidth: 4 - --- - Language: Cpp - # Force pointers to the type for C++. - DerivePointerAlignment: false - PointerAlignment: Left - --- - Language: JavaScript - # Use 100 columns for JS. - ColumnLimit: 100 - --- - Language: Proto - # Don't format .proto files. - DisableFormat: true - --- - Language: CSharp - # Use 100 columns for C#. - ColumnLimit: 100 - ... - -An easy way to get a valid ``.clang-format`` file containing all configuration +```yaml +--- +# We'll use defaults from the LLVM style, but with 4 columns indentation. +BasedOnStyle: LLVM +IndentWidth: 4 +--- +Language: Cpp +# Force pointers to the type for C++. +DerivePointerAlignment: false +PointerAlignment: Left +--- +Language: JavaScript +# Use 100 columns for JS. +ColumnLimit: 100 +--- +Language: Proto +# Don't format .proto files. +DisableFormat: true +--- +Language: CSharp +# Use 100 columns for C#. +ColumnLimit: 100 +... +``` + +An easy way to get a valid `.clang-format` file containing all configuration options of a certain predefined style is: -.. code-block:: console - - clang-format -style=llvm -dump-config > .clang-format +```console +clang-format -style=llvm -dump-config > .clang-format +``` -When specifying configuration in the ``-style=`` option, the same configuration +When specifying configuration in the `-style=` option, the same configuration is applied for all input files. The format of the configuration is: -.. code-block:: console - - -style='{key1: value1, key2: value2, ...}' - +```console +-style='{key1: value1, key2: value2, ...}' +``` -Disabling Formatting on a Piece of Code -======================================= +## Disabling Formatting on a Piece of Code Clang-format understands also special comments that switch formatting in a -delimited range. The code between a comment ``// clang-format off`` or -``/* clang-format off */`` up to a comment ``// clang-format on`` or -``/* clang-format on */`` will not be formatted. The comments themselves will be -formatted (aligned) normally. Also, a colon (``:``) and additional text may -follow ``// clang-format off`` or ``// clang-format on`` to explain why +delimited range. The code between a comment `// clang-format off` or +`/* clang-format off */` up to a comment `// clang-format on` or +`/* clang-format on */` will not be formatted. The comments themselves will be +formatted (aligned) normally. Also, a colon (`:`) and additional text may +follow `// clang-format off` or `// clang-format on` to explain why clang-format is turned off or back on. -.. code-block:: c++ +```c++ +int formatted_code; +// clang-format off + void unformatted_code ; +// clang-format on +void formatted_code_again; +``` - int formatted_code; - // clang-format off - void unformatted_code ; - // clang-format on - void formatted_code_again; - -In addition, the ``OneLineFormatOffRegex`` option gives you a concise way to +In addition, the `OneLineFormatOffRegex` option gives you a concise way to disable formatting for all of the lines that match the regular expression. +## Configuring Style in Code -Configuring Style in Code -========================= - -When using ``clang::format::reformat(...)`` functions, the format is specified -by supplying the `clang::format::FormatStyle -`_ +When using `clang::format::reformat(...)` functions, the format is specified +by supplying the [clang::format::FormatStyle](https://clang.llvm.org/doxygen/structclang_1_1format_1_1FormatStyle.html) structure. - -Configurable Format Style Options -================================= +## Configurable Format Style Options This section lists the supported style options. Value type is specified for each option. For enumeration types possible values are specified both as a C++ -enumeration member (with a prefix, e.g. ``LS_Auto``), and as a value usable in -the configuration (without a prefix: ``Auto``). +enumeration member (with a prefix, e.g. `LS_Auto`), and as a value usable in +the configuration (without a prefix: `Auto`). + +(basedonstyle)= -.. _BasedOnStyle: +**BasedOnStyle** (`String`) {ref}`¶ ` -**BasedOnStyle** (``String``) :ref:`¶ ` - The style used for all options not specifically set in the configuration. +: The style used for all options not specifically set in the configuration. - This option is supported only in the :program:`clang-format` configuration - (both within ``-style='{...}'`` and the ``.clang-format`` file). + This option is supported only in the {program}`clang-format` configuration + (both within `-style='{...}'` and the `.clang-format` file). Possible values: - * ``LLVM`` - A style complying with the `LLVM coding standards - `_ - * ``Google`` - A style complying with `Google's C++ style guide - `_ - * ``Chromium`` - A style complying with `Chromium's style guide - `_ - * ``Mozilla`` - A style complying with `Mozilla's style guide - `_ - * ``WebKit`` - A style complying with `WebKit's style guide - `_ - * ``Microsoft`` - A style complying with `Microsoft's style guide - `_ - * ``GNU`` - A style complying with the `GNU coding standards - `_ - * ``InheritParentConfig`` - Not a real style, but allows to use the ``.clang-format`` file from the + - `LLVM` + A style complying with the [LLVM coding standards](https://llvm.org/docs/CodingStandards.html) + - `Google` + A style complying with [Google's C++ style guide](https://google.github.io/styleguide/cppguide.html) + - `Chromium` + A style complying with [Chromium's style guide](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/styleguide/styleguide.md) + - `Mozilla` + A style complying with [Mozilla's style guide](https://firefox-source-docs.mozilla.org/code-quality/coding-style/index.html) + - `WebKit` + A style complying with [WebKit's style guide](https://www.webkit.org/coding/coding-style.html) + - `Microsoft` + A style complying with [Microsoft's style guide](https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference) + - `GNU` + A style complying with the [GNU coding standards](https://www.gnu.org/prep/standards/standards.html) + - `InheritParentConfig` + Not a real style, but allows to use the `.clang-format` file from the parent directory (or its parent if there is none). If there is no parent - file found it falls back to the ``fallback`` style, and applies the changes + file found it falls back to the `fallback` style, and applies the changes to that. With this option you can overwrite some parts of your main style for your subdirectories. This is also possible through the command line, e.g.: - ``--style={BasedOnStyle: InheritParentConfig, ColumnLimit: 20}`` - * ``InheritParentConfig=`` + `--style={BasedOnStyle: InheritParentConfig, ColumnLimit: 20}` + - `InheritParentConfig=` Same as the above except that the inheritance is redirected to - ````. This is only supported in configuration files. + ``. This is only supported in configuration files. -.. START_FORMAT_STYLE_OPTIONS +% START_FORMAT_STYLE_OPTIONS -.. _AccessModifierOffset: +(accessmodifieroffset)= -**AccessModifierOffset** (``Integer``) :versionbadge:`clang-format 3.3` :ref:`¶ ` - The extra indent or outdent of access modifiers, e.g. ``public:``. +**AccessModifierOffset** (`Integer`) {versionbadge}`clang-format 3.3` {ref}`¶ ` -.. _AlignAfterOpenBracket: +: The extra indent or outdent of access modifiers, e.g. `public:`. -**AlignAfterOpenBracket** (``Boolean``) :versionbadge:`clang-format 3.8` :ref:`¶ ` - If ``true``, horizontally aligns arguments after an open bracket. +(alignafteropenbracket)= +**AlignAfterOpenBracket** (`Boolean`) {versionbadge}`clang-format 3.8` {ref}`¶ ` - .. code-block:: c++ +: If `true`, horizontally aligns arguments after an open bracket. - true: vs. false - someLongFunction(argument1, someLongFunction(argument1, - argument2); argument2); + ```c++ + true: vs. false + someLongFunction(argument1, someLongFunction(argument1, + argument2); argument2); + ``` - - .. note:: - - As of clang-format 22 this option is a bool with the previous - option of ``Align`` replaced with ``true``, ``DontAlign`` replaced - with ``false``, and the options of ``AlwaysBreak`` and ``BlockIndent`` - replaced with ``true`` and with setting of new style options using - ``BreakAfterOpenBracketBracedList``, ``BreakAfterOpenBracketFunction``, - ``BreakAfterOpenBracketIf``, ``BreakBeforeCloseBracketBracedList``, - ``BreakBeforeCloseBracketFunction``, and ``BreakBeforeCloseBracketIf``. + :::{note} + As of clang-format 22 this option is a bool with the previous + option of `Align` replaced with `true`, `DontAlign` replaced + with `false`, and the options of `AlwaysBreak` and `BlockIndent` + replaced with `true` and with setting of new style options using + `BreakAfterOpenBracketBracedList`, `BreakAfterOpenBracketFunction`, + `BreakAfterOpenBracketIf`, `BreakBeforeCloseBracketBracedList`, + `BreakBeforeCloseBracketFunction`, and `BreakBeforeCloseBracketIf`. + ::: This applies to round brackets (parentheses), angle brackets and square brackets. -.. _AlignArrayOfStructures: - -**AlignArrayOfStructures** (``ArrayInitializerAlignmentStyle``) :versionbadge:`clang-format 13` :ref:`¶ ` - If not ``None``, when using initialization for an array of structs - aligns the fields into columns. +(alignarrayofstructures)= +**AlignArrayOfStructures** (`ArrayInitializerAlignmentStyle`) {versionbadge}`clang-format 13` {ref}`¶ ` - .. note:: +: If not `None`, when using initialization for an array of structs + aligns the fields into columns. - As of clang-format 15 this option only applied to arrays with equal - number of columns per row. + :::{note} + As of clang-format 15 this option only applied to arrays with equal + number of columns per row. + ::: Possible values: - * ``AIAS_Left`` (in configuration: ``Left``) + - `AIAS_Left` (in configuration: `Left`) Align array column and left justify the columns e.g.: - .. code-block:: c++ - - struct test demo[] = - { - {56, 23, "hello"}, - {-1, 93463, "world"}, - {7, 5, "!!" } - }; + ```c++ + struct test demo[] = + { + {56, 23, "hello"}, + {-1, 93463, "world"}, + {7, 5, "!!" } + }; + ``` - * ``AIAS_Right`` (in configuration: ``Right``) + - `AIAS_Right` (in configuration: `Right`) Align array column and right justify the columns e.g.: - .. code-block:: c++ - - struct test demo[] = - { - {56, 23, "hello"}, - {-1, 93463, "world"}, - { 7, 5, "!!"} - }; + ```c++ + struct test demo[] = + { + {56, 23, "hello"}, + {-1, 93463, "world"}, + { 7, 5, "!!"} + }; + ``` - * ``AIAS_None`` (in configuration: ``None``) + - `AIAS_None` (in configuration: `None`) Don't align array initializer columns. -.. _AlignConsecutiveAssignments: +(alignconsecutiveassignments)= -**AlignConsecutiveAssignments** (``AlignConsecutiveStyle``) :versionbadge:`clang-format 3.8` :ref:`¶ ` - Style of aligning consecutive assignments. +**AlignConsecutiveAssignments** (`AlignConsecutiveStyle`) {versionbadge}`clang-format 3.8` {ref}`¶ ` - ``Consecutive`` will result in formattings like: +: Style of aligning consecutive assignments. - .. code-block:: c++ + `Consecutive` will result in formattings like: - int a = 1; - int somelongname = 2; - double c = 3; + ```c++ + int a = 1; + int somelongname = 2; + double c = 3; + ``` Nested configuration flags: @@ -285,162 +270,163 @@ the configuration (without a prefix: ``Auto``). They can also be read as a whole for compatibility. The choices are: - * ``None`` - * ``Consecutive`` - * ``AcrossEmptyLines`` - * ``AcrossComments`` - * ``AcrossEmptyLinesAndComments`` + - `None` + - `Consecutive` + - `AcrossEmptyLines` + - `AcrossComments` + - `AcrossEmptyLinesAndComments` For example, to align across empty lines and not across comments, either of these work. - .. code-block:: c++ - - AlignConsecutiveAssignments: AcrossEmptyLines - - AlignConsecutiveAssignments: - Enabled: true - AcrossEmptyLines: true - AcrossComments: false - - * ``bool Enabled`` Whether aligning is enabled. - - .. code-block:: c++ + ```c++ + AlignConsecutiveAssignments: AcrossEmptyLines - #define SHORT_NAME 42 - #define LONGER_NAME 0x007f - #define EVEN_LONGER_NAME (2) - #define foo(x) (x * x) - #define bar(y, z) (y + z) + AlignConsecutiveAssignments: + Enabled: true + AcrossEmptyLines: true + AcrossComments: false + ``` - int a = 1; - int somelongname = 2; - double c = 3; + - `bool Enabled` Whether aligning is enabled. - int aaaa : 1; - int b : 12; - int ccc : 8; - - int aaaa = 12; - float b = 23; - std::string ccc; + ```c++ + #define SHORT_NAME 42 + #define LONGER_NAME 0x007f + #define EVEN_LONGER_NAME (2) + #define foo(x) (x * x) + #define bar(y, z) (y + z) - * ``bool AcrossEmptyLines`` Whether to align across empty lines. + int a = 1; + int somelongname = 2; + double c = 3; - .. code-block:: c++ + int aaaa : 1; + int b : 12; + int ccc : 8; - true: - int a = 1; - int somelongname = 2; - double c = 3; + int aaaa = 12; + float b = 23; + std::string ccc; + ``` - int d = 3; + - `bool AcrossEmptyLines` Whether to align across empty lines. - false: - int a = 1; - int somelongname = 2; - double c = 3; + ```c++ + true: + int a = 1; + int somelongname = 2; + double c = 3; - int d = 3; + int d = 3; - * ``bool AcrossComments`` Whether to align across comments. + false: + int a = 1; + int somelongname = 2; + double c = 3; - .. code-block:: c++ + int d = 3; + ``` - true: - int d = 3; - /* A comment. */ - double e = 4; + - `bool AcrossComments` Whether to align across comments. - false: - int d = 3; - /* A comment. */ - double e = 4; + ```c++ + true: + int d = 3; + /* A comment. */ + double e = 4; - * ``bool AlignCompound`` Only for ``AlignConsecutiveAssignments``. Whether compound assignments - like ``+=`` are aligned along with ``=``. + false: + int d = 3; + /* A comment. */ + double e = 4; + ``` - .. code-block:: c++ + - `bool AlignCompound` Only for `AlignConsecutiveAssignments`. Whether compound assignments + like `+=` are aligned along with `=`. - true: - a &= 2; - bbb = 2; + ```c++ + true: + a &= 2; + bbb = 2; - false: - a &= 2; - bbb = 2; + false: + a &= 2; + bbb = 2; + ``` - * ``bool AlignFunctionDeclarations`` Only for ``AlignConsecutiveDeclarations``. Whether function declarations + - `bool AlignFunctionDeclarations` Only for `AlignConsecutiveDeclarations`. Whether function declarations are aligned. - .. code-block:: c++ - - true: - unsigned int f1(void); - void f2(void); - size_t f3(void); + ```c++ + true: + unsigned int f1(void); + void f2(void); + size_t f3(void); - false: - unsigned int f1(void); - void f2(void); - size_t f3(void); + false: + unsigned int f1(void); + void f2(void); + size_t f3(void); + ``` - * ``bool AlignFunctionPointers`` Only for ``AlignConsecutiveDeclarations``. Whether function pointers are + - `bool AlignFunctionPointers` Only for `AlignConsecutiveDeclarations`. Whether function pointers are aligned. - .. code-block:: c++ - - true: - unsigned i; - int &r; - int *p; - int (*f)(); - - false: - unsigned i; - int &r; - int *p; - int (*f)(); - - * ``bool EnumAssignments`` Only for ``AlignConsecutiveAssignments``. - Whether enum assignments are aligned. If ``Enabled`` is ``false``, - setting this to ``true`` forces alignment for enum assignments only. - If ``Enabled`` is ``true``, enum assignments are always aligned. + ```c++ + true: + unsigned i; + int &r; + int *p; + int (*f)(); - * ``bool PadOperators`` Only for ``AlignConsecutiveAssignments``. Whether short assignment + false: + unsigned i; + int &r; + int *p; + int (*f)(); + ``` + + - `bool EnumAssignments` Only for `AlignConsecutiveAssignments`. + Whether enum assignments are aligned. If `Enabled` is `false`, + setting this to `true` forces alignment for enum assignments only. + If `Enabled` is `true`, enum assignments are always aligned. + + - `bool PadOperators` Only for `AlignConsecutiveAssignments`. Whether short assignment operators are left-padded to the same length as long ones in order to put all assignment operators to the right of the left hand side. - .. code-block:: c++ + ```c++ + true: + a >>= 2; + bbb = 2; - true: - a >>= 2; - bbb = 2; + a = 2; + bbb >>= 2; - a = 2; - bbb >>= 2; + false: + a >>= 2; + bbb = 2; - false: - a >>= 2; - bbb = 2; + a = 2; + bbb >>= 2; + ``` - a = 2; - bbb >>= 2; +(alignconsecutivebitfields)= -.. _AlignConsecutiveBitFields: +**AlignConsecutiveBitFields** (`AlignConsecutiveStyle`) {versionbadge}`clang-format 11` {ref}`¶ ` -**AlignConsecutiveBitFields** (``AlignConsecutiveStyle``) :versionbadge:`clang-format 11` :ref:`¶ ` - Style of aligning consecutive bit fields. +: Style of aligning consecutive bit fields. - ``Consecutive`` will align the bitfield separators of consecutive lines. + `Consecutive` will align the bitfield separators of consecutive lines. This will result in formattings like: - .. code-block:: c++ - - int aaaa : 1; - int b : 12; - int ccc : 8; + ```c++ + int aaaa : 1; + int b : 12; + int ccc : 8; + ``` Nested configuration flags: @@ -448,162 +434,163 @@ the configuration (without a prefix: ``Auto``). They can also be read as a whole for compatibility. The choices are: - * ``None`` - * ``Consecutive`` - * ``AcrossEmptyLines`` - * ``AcrossComments`` - * ``AcrossEmptyLinesAndComments`` + - `None` + - `Consecutive` + - `AcrossEmptyLines` + - `AcrossComments` + - `AcrossEmptyLinesAndComments` For example, to align across empty lines and not across comments, either of these work. - .. code-block:: c++ - - AlignConsecutiveBitFields: AcrossEmptyLines - - AlignConsecutiveBitFields: - Enabled: true - AcrossEmptyLines: true - AcrossComments: false - - * ``bool Enabled`` Whether aligning is enabled. + ```c++ + AlignConsecutiveBitFields: AcrossEmptyLines - .. code-block:: c++ + AlignConsecutiveBitFields: + Enabled: true + AcrossEmptyLines: true + AcrossComments: false + ``` - #define SHORT_NAME 42 - #define LONGER_NAME 0x007f - #define EVEN_LONGER_NAME (2) - #define foo(x) (x * x) - #define bar(y, z) (y + z) + - `bool Enabled` Whether aligning is enabled. - int a = 1; - int somelongname = 2; - double c = 3; - - int aaaa : 1; - int b : 12; - int ccc : 8; - - int aaaa = 12; - float b = 23; - std::string ccc; + ```c++ + #define SHORT_NAME 42 + #define LONGER_NAME 0x007f + #define EVEN_LONGER_NAME (2) + #define foo(x) (x * x) + #define bar(y, z) (y + z) - * ``bool AcrossEmptyLines`` Whether to align across empty lines. + int a = 1; + int somelongname = 2; + double c = 3; - .. code-block:: c++ + int aaaa : 1; + int b : 12; + int ccc : 8; - true: - int a = 1; - int somelongname = 2; - double c = 3; + int aaaa = 12; + float b = 23; + std::string ccc; + ``` - int d = 3; + - `bool AcrossEmptyLines` Whether to align across empty lines. - false: - int a = 1; - int somelongname = 2; - double c = 3; + ```c++ + true: + int a = 1; + int somelongname = 2; + double c = 3; - int d = 3; + int d = 3; - * ``bool AcrossComments`` Whether to align across comments. + false: + int a = 1; + int somelongname = 2; + double c = 3; - .. code-block:: c++ + int d = 3; + ``` - true: - int d = 3; - /* A comment. */ - double e = 4; + - `bool AcrossComments` Whether to align across comments. - false: - int d = 3; - /* A comment. */ - double e = 4; + ```c++ + true: + int d = 3; + /* A comment. */ + double e = 4; - * ``bool AlignCompound`` Only for ``AlignConsecutiveAssignments``. Whether compound assignments - like ``+=`` are aligned along with ``=``. + false: + int d = 3; + /* A comment. */ + double e = 4; + ``` - .. code-block:: c++ + - `bool AlignCompound` Only for `AlignConsecutiveAssignments`. Whether compound assignments + like `+=` are aligned along with `=`. - true: - a &= 2; - bbb = 2; + ```c++ + true: + a &= 2; + bbb = 2; - false: - a &= 2; - bbb = 2; + false: + a &= 2; + bbb = 2; + ``` - * ``bool AlignFunctionDeclarations`` Only for ``AlignConsecutiveDeclarations``. Whether function declarations + - `bool AlignFunctionDeclarations` Only for `AlignConsecutiveDeclarations`. Whether function declarations are aligned. - .. code-block:: c++ - - true: - unsigned int f1(void); - void f2(void); - size_t f3(void); + ```c++ + true: + unsigned int f1(void); + void f2(void); + size_t f3(void); - false: - unsigned int f1(void); - void f2(void); - size_t f3(void); + false: + unsigned int f1(void); + void f2(void); + size_t f3(void); + ``` - * ``bool AlignFunctionPointers`` Only for ``AlignConsecutiveDeclarations``. Whether function pointers are + - `bool AlignFunctionPointers` Only for `AlignConsecutiveDeclarations`. Whether function pointers are aligned. - .. code-block:: c++ - - true: - unsigned i; - int &r; - int *p; - int (*f)(); - - false: - unsigned i; - int &r; - int *p; - int (*f)(); - - * ``bool EnumAssignments`` Only for ``AlignConsecutiveAssignments``. - Whether enum assignments are aligned. If ``Enabled`` is ``false``, - setting this to ``true`` forces alignment for enum assignments only. - If ``Enabled`` is ``true``, enum assignments are always aligned. + ```c++ + true: + unsigned i; + int &r; + int *p; + int (*f)(); - * ``bool PadOperators`` Only for ``AlignConsecutiveAssignments``. Whether short assignment + false: + unsigned i; + int &r; + int *p; + int (*f)(); + ``` + + - `bool EnumAssignments` Only for `AlignConsecutiveAssignments`. + Whether enum assignments are aligned. If `Enabled` is `false`, + setting this to `true` forces alignment for enum assignments only. + If `Enabled` is `true`, enum assignments are always aligned. + + - `bool PadOperators` Only for `AlignConsecutiveAssignments`. Whether short assignment operators are left-padded to the same length as long ones in order to put all assignment operators to the right of the left hand side. - .. code-block:: c++ + ```c++ + true: + a >>= 2; + bbb = 2; - true: - a >>= 2; - bbb = 2; + a = 2; + bbb >>= 2; - a = 2; - bbb >>= 2; + false: + a >>= 2; + bbb = 2; - false: - a >>= 2; - bbb = 2; + a = 2; + bbb >>= 2; + ``` - a = 2; - bbb >>= 2; +(alignconsecutivedeclarations)= -.. _AlignConsecutiveDeclarations: +**AlignConsecutiveDeclarations** (`AlignConsecutiveStyle`) {versionbadge}`clang-format 3.8` {ref}`¶ ` -**AlignConsecutiveDeclarations** (``AlignConsecutiveStyle``) :versionbadge:`clang-format 3.8` :ref:`¶ ` - Style of aligning consecutive declarations. +: Style of aligning consecutive declarations. - ``Consecutive`` will align the declaration names of consecutive lines. + `Consecutive` will align the declaration names of consecutive lines. This will result in formattings like: - .. code-block:: c++ - - int aaaa = 12; - float b = 23; - std::string ccc; + ```c++ + int aaaa = 12; + float b = 23; + std::string ccc; + ``` Nested configuration flags: @@ -611,163 +598,164 @@ the configuration (without a prefix: ``Auto``). They can also be read as a whole for compatibility. The choices are: - * ``None`` - * ``Consecutive`` - * ``AcrossEmptyLines`` - * ``AcrossComments`` - * ``AcrossEmptyLinesAndComments`` + - `None` + - `Consecutive` + - `AcrossEmptyLines` + - `AcrossComments` + - `AcrossEmptyLinesAndComments` For example, to align across empty lines and not across comments, either of these work. - .. code-block:: c++ - - AlignConsecutiveDeclarations: AcrossEmptyLines - - AlignConsecutiveDeclarations: - Enabled: true - AcrossEmptyLines: true - AcrossComments: false + ```c++ + AlignConsecutiveDeclarations: AcrossEmptyLines - * ``bool Enabled`` Whether aligning is enabled. + AlignConsecutiveDeclarations: + Enabled: true + AcrossEmptyLines: true + AcrossComments: false + ``` - .. code-block:: c++ + - `bool Enabled` Whether aligning is enabled. - #define SHORT_NAME 42 - #define LONGER_NAME 0x007f - #define EVEN_LONGER_NAME (2) - #define foo(x) (x * x) - #define bar(y, z) (y + z) - - int a = 1; - int somelongname = 2; - double c = 3; - - int aaaa : 1; - int b : 12; - int ccc : 8; - - int aaaa = 12; - float b = 23; - std::string ccc; + ```c++ + #define SHORT_NAME 42 + #define LONGER_NAME 0x007f + #define EVEN_LONGER_NAME (2) + #define foo(x) (x * x) + #define bar(y, z) (y + z) - * ``bool AcrossEmptyLines`` Whether to align across empty lines. + int a = 1; + int somelongname = 2; + double c = 3; - .. code-block:: c++ + int aaaa : 1; + int b : 12; + int ccc : 8; - true: - int a = 1; - int somelongname = 2; - double c = 3; + int aaaa = 12; + float b = 23; + std::string ccc; + ``` - int d = 3; + - `bool AcrossEmptyLines` Whether to align across empty lines. - false: - int a = 1; - int somelongname = 2; - double c = 3; + ```c++ + true: + int a = 1; + int somelongname = 2; + double c = 3; - int d = 3; + int d = 3; - * ``bool AcrossComments`` Whether to align across comments. + false: + int a = 1; + int somelongname = 2; + double c = 3; - .. code-block:: c++ + int d = 3; + ``` - true: - int d = 3; - /* A comment. */ - double e = 4; + - `bool AcrossComments` Whether to align across comments. - false: - int d = 3; - /* A comment. */ - double e = 4; + ```c++ + true: + int d = 3; + /* A comment. */ + double e = 4; - * ``bool AlignCompound`` Only for ``AlignConsecutiveAssignments``. Whether compound assignments - like ``+=`` are aligned along with ``=``. + false: + int d = 3; + /* A comment. */ + double e = 4; + ``` - .. code-block:: c++ + - `bool AlignCompound` Only for `AlignConsecutiveAssignments`. Whether compound assignments + like `+=` are aligned along with `=`. - true: - a &= 2; - bbb = 2; + ```c++ + true: + a &= 2; + bbb = 2; - false: - a &= 2; - bbb = 2; + false: + a &= 2; + bbb = 2; + ``` - * ``bool AlignFunctionDeclarations`` Only for ``AlignConsecutiveDeclarations``. Whether function declarations + - `bool AlignFunctionDeclarations` Only for `AlignConsecutiveDeclarations`. Whether function declarations are aligned. - .. code-block:: c++ - - true: - unsigned int f1(void); - void f2(void); - size_t f3(void); + ```c++ + true: + unsigned int f1(void); + void f2(void); + size_t f3(void); - false: - unsigned int f1(void); - void f2(void); - size_t f3(void); + false: + unsigned int f1(void); + void f2(void); + size_t f3(void); + ``` - * ``bool AlignFunctionPointers`` Only for ``AlignConsecutiveDeclarations``. Whether function pointers are + - `bool AlignFunctionPointers` Only for `AlignConsecutiveDeclarations`. Whether function pointers are aligned. - .. code-block:: c++ - - true: - unsigned i; - int &r; - int *p; - int (*f)(); - - false: - unsigned i; - int &r; - int *p; - int (*f)(); - - * ``bool EnumAssignments`` Only for ``AlignConsecutiveAssignments``. - Whether enum assignments are aligned. If ``Enabled`` is ``false``, - setting this to ``true`` forces alignment for enum assignments only. - If ``Enabled`` is ``true``, enum assignments are always aligned. + ```c++ + true: + unsigned i; + int &r; + int *p; + int (*f)(); - * ``bool PadOperators`` Only for ``AlignConsecutiveAssignments``. Whether short assignment + false: + unsigned i; + int &r; + int *p; + int (*f)(); + ``` + + - `bool EnumAssignments` Only for `AlignConsecutiveAssignments`. + Whether enum assignments are aligned. If `Enabled` is `false`, + setting this to `true` forces alignment for enum assignments only. + If `Enabled` is `true`, enum assignments are always aligned. + + - `bool PadOperators` Only for `AlignConsecutiveAssignments`. Whether short assignment operators are left-padded to the same length as long ones in order to put all assignment operators to the right of the left hand side. - .. code-block:: c++ - - true: - a >>= 2; - bbb = 2; + ```c++ + true: + a >>= 2; + bbb = 2; - a = 2; - bbb >>= 2; + a = 2; + bbb >>= 2; - false: - a >>= 2; - bbb = 2; + false: + a >>= 2; + bbb = 2; - a = 2; - bbb >>= 2; + a = 2; + bbb >>= 2; + ``` -.. _AlignConsecutiveMacros: +(alignconsecutivemacros)= -**AlignConsecutiveMacros** (``AlignConsecutiveStyle``) :versionbadge:`clang-format 9` :ref:`¶ ` - Style of aligning consecutive macro definitions. +**AlignConsecutiveMacros** (`AlignConsecutiveStyle`) {versionbadge}`clang-format 9` {ref}`¶ ` - ``Consecutive`` will result in formattings like: +: Style of aligning consecutive macro definitions. - .. code-block:: c++ + `Consecutive` will result in formattings like: - #define SHORT_NAME 42 - #define LONGER_NAME 0x007f - #define EVEN_LONGER_NAME (2) - #define foo(x) (x * x) - #define bar(y, z) (y + z) + ```c++ + #define SHORT_NAME 42 + #define LONGER_NAME 0x007f + #define EVEN_LONGER_NAME (2) + #define foo(x) (x * x) + #define bar(y, z) (y + z) + ``` Nested configuration flags: @@ -775,282 +763,283 @@ the configuration (without a prefix: ``Auto``). They can also be read as a whole for compatibility. The choices are: - * ``None`` - * ``Consecutive`` - * ``AcrossEmptyLines`` - * ``AcrossComments`` - * ``AcrossEmptyLinesAndComments`` + - `None` + - `Consecutive` + - `AcrossEmptyLines` + - `AcrossComments` + - `AcrossEmptyLinesAndComments` For example, to align across empty lines and not across comments, either of these work. - .. code-block:: c++ - - AlignConsecutiveMacros: AcrossEmptyLines - - AlignConsecutiveMacros: - Enabled: true - AcrossEmptyLines: true - AcrossComments: false - - * ``bool Enabled`` Whether aligning is enabled. + ```c++ + AlignConsecutiveMacros: AcrossEmptyLines - .. code-block:: c++ + AlignConsecutiveMacros: + Enabled: true + AcrossEmptyLines: true + AcrossComments: false + ``` - #define SHORT_NAME 42 - #define LONGER_NAME 0x007f - #define EVEN_LONGER_NAME (2) - #define foo(x) (x * x) - #define bar(y, z) (y + z) + - `bool Enabled` Whether aligning is enabled. - int a = 1; - int somelongname = 2; - double c = 3; - - int aaaa : 1; - int b : 12; - int ccc : 8; - - int aaaa = 12; - float b = 23; - std::string ccc; + ```c++ + #define SHORT_NAME 42 + #define LONGER_NAME 0x007f + #define EVEN_LONGER_NAME (2) + #define foo(x) (x * x) + #define bar(y, z) (y + z) - * ``bool AcrossEmptyLines`` Whether to align across empty lines. + int a = 1; + int somelongname = 2; + double c = 3; - .. code-block:: c++ + int aaaa : 1; + int b : 12; + int ccc : 8; - true: - int a = 1; - int somelongname = 2; - double c = 3; + int aaaa = 12; + float b = 23; + std::string ccc; + ``` - int d = 3; + - `bool AcrossEmptyLines` Whether to align across empty lines. - false: - int a = 1; - int somelongname = 2; - double c = 3; + ```c++ + true: + int a = 1; + int somelongname = 2; + double c = 3; - int d = 3; + int d = 3; - * ``bool AcrossComments`` Whether to align across comments. + false: + int a = 1; + int somelongname = 2; + double c = 3; - .. code-block:: c++ + int d = 3; + ``` - true: - int d = 3; - /* A comment. */ - double e = 4; + - `bool AcrossComments` Whether to align across comments. - false: - int d = 3; - /* A comment. */ - double e = 4; + ```c++ + true: + int d = 3; + /* A comment. */ + double e = 4; - * ``bool AlignCompound`` Only for ``AlignConsecutiveAssignments``. Whether compound assignments - like ``+=`` are aligned along with ``=``. + false: + int d = 3; + /* A comment. */ + double e = 4; + ``` - .. code-block:: c++ + - `bool AlignCompound` Only for `AlignConsecutiveAssignments`. Whether compound assignments + like `+=` are aligned along with `=`. - true: - a &= 2; - bbb = 2; + ```c++ + true: + a &= 2; + bbb = 2; - false: - a &= 2; - bbb = 2; + false: + a &= 2; + bbb = 2; + ``` - * ``bool AlignFunctionDeclarations`` Only for ``AlignConsecutiveDeclarations``. Whether function declarations + - `bool AlignFunctionDeclarations` Only for `AlignConsecutiveDeclarations`. Whether function declarations are aligned. - .. code-block:: c++ - - true: - unsigned int f1(void); - void f2(void); - size_t f3(void); + ```c++ + true: + unsigned int f1(void); + void f2(void); + size_t f3(void); - false: - unsigned int f1(void); - void f2(void); - size_t f3(void); + false: + unsigned int f1(void); + void f2(void); + size_t f3(void); + ``` - * ``bool AlignFunctionPointers`` Only for ``AlignConsecutiveDeclarations``. Whether function pointers are + - `bool AlignFunctionPointers` Only for `AlignConsecutiveDeclarations`. Whether function pointers are aligned. - .. code-block:: c++ - - true: - unsigned i; - int &r; - int *p; - int (*f)(); - - false: - unsigned i; - int &r; - int *p; - int (*f)(); - - * ``bool EnumAssignments`` Only for ``AlignConsecutiveAssignments``. - Whether enum assignments are aligned. If ``Enabled`` is ``false``, - setting this to ``true`` forces alignment for enum assignments only. - If ``Enabled`` is ``true``, enum assignments are always aligned. + ```c++ + true: + unsigned i; + int &r; + int *p; + int (*f)(); - * ``bool PadOperators`` Only for ``AlignConsecutiveAssignments``. Whether short assignment + false: + unsigned i; + int &r; + int *p; + int (*f)(); + ``` + + - `bool EnumAssignments` Only for `AlignConsecutiveAssignments`. + Whether enum assignments are aligned. If `Enabled` is `false`, + setting this to `true` forces alignment for enum assignments only. + If `Enabled` is `true`, enum assignments are always aligned. + + - `bool PadOperators` Only for `AlignConsecutiveAssignments`. Whether short assignment operators are left-padded to the same length as long ones in order to put all assignment operators to the right of the left hand side. - .. code-block:: c++ - - true: - a >>= 2; - bbb = 2; - - a = 2; - bbb >>= 2; + ```c++ + true: + a >>= 2; + bbb = 2; - false: - a >>= 2; - bbb = 2; + a = 2; + bbb >>= 2; - a = 2; - bbb >>= 2; + false: + a >>= 2; + bbb = 2; + a = 2; + bbb >>= 2; + ``` -.. _AlignConsecutiveShortCaseStatements: -**AlignConsecutiveShortCaseStatements** (``ShortCaseStatementsAlignmentStyle``) :versionbadge:`clang-format 17` :ref:`¶ ` - Style of aligning consecutive short case labels. - Only applies if ``AllowShortCaseExpressionOnASingleLine`` or - ``AllowShortCaseLabelsOnASingleLine`` is ``true``. +(alignconsecutiveshortcasestatements)= +**AlignConsecutiveShortCaseStatements** (`ShortCaseStatementsAlignmentStyle`) {versionbadge}`clang-format 17` {ref}`¶ ` - .. code-block:: yaml +: Style of aligning consecutive short case labels. + Only applies if `AllowShortCaseExpressionOnASingleLine` or + `AllowShortCaseLabelsOnASingleLine` is `true`. - # Example of usage: - AlignConsecutiveShortCaseStatements: - Enabled: true - AcrossEmptyLines: true - AcrossComments: true - AlignCaseColons: false + ```yaml + # Example of usage: + AlignConsecutiveShortCaseStatements: + Enabled: true + AcrossEmptyLines: true + AcrossComments: true + AlignCaseColons: false + ``` Nested configuration flags: Alignment options. - * ``bool Enabled`` Whether aligning is enabled. + - `bool Enabled` Whether aligning is enabled. - .. code-block:: c++ - - true: - switch (level) { - case log::info: return "info:"; - case log::warning: return "warning:"; - default: return ""; - } - - false: - switch (level) { - case log::info: return "info:"; - case log::warning: return "warning:"; - default: return ""; - } - - * ``bool AcrossEmptyLines`` Whether to align across empty lines. - - .. code-block:: c++ + ```c++ + true: + switch (level) { + case log::info: return "info:"; + case log::warning: return "warning:"; + default: return ""; + } - true: - switch (level) { - case log::info: return "info:"; - case log::warning: return "warning:"; + false: + switch (level) { + case log::info: return "info:"; + case log::warning: return "warning:"; + default: return ""; + } + ``` - default: return ""; - } + - `bool AcrossEmptyLines` Whether to align across empty lines. - false: - switch (level) { - case log::info: return "info:"; - case log::warning: return "warning:"; + ```c++ + true: + switch (level) { + case log::info: return "info:"; + case log::warning: return "warning:"; - default: return ""; - } + default: return ""; + } - * ``bool AcrossComments`` Whether to align across comments. + false: + switch (level) { + case log::info: return "info:"; + case log::warning: return "warning:"; - .. code-block:: c++ + default: return ""; + } + ``` - true: - switch (level) { - case log::info: return "info:"; - case log::warning: return "warning:"; - /* A comment. */ - default: return ""; - } + - `bool AcrossComments` Whether to align across comments. - false: - switch (level) { - case log::info: return "info:"; - case log::warning: return "warning:"; - /* A comment. */ - default: return ""; - } + ```c++ + true: + switch (level) { + case log::info: return "info:"; + case log::warning: return "warning:"; + /* A comment. */ + default: return ""; + } - * ``bool AlignCaseArrows`` Whether to align the case arrows when aligning short case expressions. + false: + switch (level) { + case log::info: return "info:"; + case log::warning: return "warning:"; + /* A comment. */ + default: return ""; + } + ``` - .. code-block:: java + - `bool AlignCaseArrows` Whether to align the case arrows when aligning short case expressions. - true: - i = switch (day) { - case THURSDAY, SATURDAY -> 8; - case WEDNESDAY -> 9; - default -> 0; - }; + ```java + true: + i = switch (day) { + case THURSDAY, SATURDAY -> 8; + case WEDNESDAY -> 9; + default -> 0; + }; - false: - i = switch (day) { - case THURSDAY, SATURDAY -> 8; - case WEDNESDAY -> 9; - default -> 0; - }; + false: + i = switch (day) { + case THURSDAY, SATURDAY -> 8; + case WEDNESDAY -> 9; + default -> 0; + }; + ``` - * ``bool AlignCaseColons`` Whether aligned case labels are aligned on the colon, or on the tokens + - `bool AlignCaseColons` Whether aligned case labels are aligned on the colon, or on the tokens after the colon. - .. code-block:: c++ + ```c++ + true: + switch (level) { + case log::info : return "info:"; + case log::warning: return "warning:"; + default : return ""; + } - true: - switch (level) { - case log::info : return "info:"; - case log::warning: return "warning:"; - default : return ""; - } + false: + switch (level) { + case log::info: return "info:"; + case log::warning: return "warning:"; + default: return ""; + } + ``` - false: - switch (level) { - case log::info: return "info:"; - case log::warning: return "warning:"; - default: return ""; - } +(alignconsecutivetablegenbreakingdagargcolons)= -.. _AlignConsecutiveTableGenBreakingDAGArgColons: +**AlignConsecutiveTableGenBreakingDAGArgColons** (`AlignConsecutiveStyle`) {versionbadge}`clang-format 19` {ref}`¶ ` -**AlignConsecutiveTableGenBreakingDAGArgColons** (``AlignConsecutiveStyle``) :versionbadge:`clang-format 19` :ref:`¶ ` - Style of aligning consecutive TableGen DAGArg operator colons. +: Style of aligning consecutive TableGen DAGArg operator colons. If enabled, align the colon inside DAGArg which have line break inside. This works only when TableGenBreakInsideDAGArg is BreakElements or BreakAll and the DAGArg is not excepted by TableGenBreakingDAGArgOperators's effect. - .. code-block:: c++ - - let dagarg = (ins - a :$src1, - aa :$src2, - aaa:$src3 - ) + ```c++ + let dagarg = (ins + a :$src1, + aa :$src2, + aaa:$src3 + ) + ``` Nested configuration flags: @@ -1058,160 +1047,161 @@ the configuration (without a prefix: ``Auto``). They can also be read as a whole for compatibility. The choices are: - * ``None`` - * ``Consecutive`` - * ``AcrossEmptyLines`` - * ``AcrossComments`` - * ``AcrossEmptyLinesAndComments`` + - `None` + - `Consecutive` + - `AcrossEmptyLines` + - `AcrossComments` + - `AcrossEmptyLinesAndComments` For example, to align across empty lines and not across comments, either of these work. - .. code-block:: c++ - - AlignConsecutiveTableGenBreakingDAGArgColons: AcrossEmptyLines + ```c++ + AlignConsecutiveTableGenBreakingDAGArgColons: AcrossEmptyLines - AlignConsecutiveTableGenBreakingDAGArgColons: - Enabled: true - AcrossEmptyLines: true - AcrossComments: false + AlignConsecutiveTableGenBreakingDAGArgColons: + Enabled: true + AcrossEmptyLines: true + AcrossComments: false + ``` - * ``bool Enabled`` Whether aligning is enabled. + - `bool Enabled` Whether aligning is enabled. - .. code-block:: c++ - - #define SHORT_NAME 42 - #define LONGER_NAME 0x007f - #define EVEN_LONGER_NAME (2) - #define foo(x) (x * x) - #define bar(y, z) (y + z) + ```c++ + #define SHORT_NAME 42 + #define LONGER_NAME 0x007f + #define EVEN_LONGER_NAME (2) + #define foo(x) (x * x) + #define bar(y, z) (y + z) - int a = 1; - int somelongname = 2; - double c = 3; + int a = 1; + int somelongname = 2; + double c = 3; - int aaaa : 1; - int b : 12; - int ccc : 8; + int aaaa : 1; + int b : 12; + int ccc : 8; - int aaaa = 12; - float b = 23; - std::string ccc; - - * ``bool AcrossEmptyLines`` Whether to align across empty lines. - - .. code-block:: c++ - - true: - int a = 1; - int somelongname = 2; - double c = 3; + int aaaa = 12; + float b = 23; + std::string ccc; + ``` - int d = 3; + - `bool AcrossEmptyLines` Whether to align across empty lines. - false: - int a = 1; - int somelongname = 2; - double c = 3; + ```c++ + true: + int a = 1; + int somelongname = 2; + double c = 3; - int d = 3; + int d = 3; - * ``bool AcrossComments`` Whether to align across comments. + false: + int a = 1; + int somelongname = 2; + double c = 3; - .. code-block:: c++ + int d = 3; + ``` - true: - int d = 3; - /* A comment. */ - double e = 4; + - `bool AcrossComments` Whether to align across comments. - false: - int d = 3; - /* A comment. */ - double e = 4; + ```c++ + true: + int d = 3; + /* A comment. */ + double e = 4; - * ``bool AlignCompound`` Only for ``AlignConsecutiveAssignments``. Whether compound assignments - like ``+=`` are aligned along with ``=``. + false: + int d = 3; + /* A comment. */ + double e = 4; + ``` - .. code-block:: c++ + - `bool AlignCompound` Only for `AlignConsecutiveAssignments`. Whether compound assignments + like `+=` are aligned along with `=`. - true: - a &= 2; - bbb = 2; + ```c++ + true: + a &= 2; + bbb = 2; - false: - a &= 2; - bbb = 2; + false: + a &= 2; + bbb = 2; + ``` - * ``bool AlignFunctionDeclarations`` Only for ``AlignConsecutiveDeclarations``. Whether function declarations + - `bool AlignFunctionDeclarations` Only for `AlignConsecutiveDeclarations`. Whether function declarations are aligned. - .. code-block:: c++ - - true: - unsigned int f1(void); - void f2(void); - size_t f3(void); + ```c++ + true: + unsigned int f1(void); + void f2(void); + size_t f3(void); - false: - unsigned int f1(void); - void f2(void); - size_t f3(void); + false: + unsigned int f1(void); + void f2(void); + size_t f3(void); + ``` - * ``bool AlignFunctionPointers`` Only for ``AlignConsecutiveDeclarations``. Whether function pointers are + - `bool AlignFunctionPointers` Only for `AlignConsecutiveDeclarations`. Whether function pointers are aligned. - .. code-block:: c++ - - true: - unsigned i; - int &r; - int *p; - int (*f)(); - - false: - unsigned i; - int &r; - int *p; - int (*f)(); - - * ``bool EnumAssignments`` Only for ``AlignConsecutiveAssignments``. - Whether enum assignments are aligned. If ``Enabled`` is ``false``, - setting this to ``true`` forces alignment for enum assignments only. - If ``Enabled`` is ``true``, enum assignments are always aligned. + ```c++ + true: + unsigned i; + int &r; + int *p; + int (*f)(); - * ``bool PadOperators`` Only for ``AlignConsecutiveAssignments``. Whether short assignment + false: + unsigned i; + int &r; + int *p; + int (*f)(); + ``` + + - `bool EnumAssignments` Only for `AlignConsecutiveAssignments`. + Whether enum assignments are aligned. If `Enabled` is `false`, + setting this to `true` forces alignment for enum assignments only. + If `Enabled` is `true`, enum assignments are always aligned. + + - `bool PadOperators` Only for `AlignConsecutiveAssignments`. Whether short assignment operators are left-padded to the same length as long ones in order to put all assignment operators to the right of the left hand side. - .. code-block:: c++ + ```c++ + true: + a >>= 2; + bbb = 2; - true: - a >>= 2; - bbb = 2; + a = 2; + bbb >>= 2; - a = 2; - bbb >>= 2; + false: + a >>= 2; + bbb = 2; - false: - a >>= 2; - bbb = 2; + a = 2; + bbb >>= 2; + ``` - a = 2; - bbb >>= 2; +(alignconsecutivetablegencondoperatorcolons)= -.. _AlignConsecutiveTableGenCondOperatorColons: +**AlignConsecutiveTableGenCondOperatorColons** (`AlignConsecutiveStyle`) {versionbadge}`clang-format 19` {ref}`¶ ` -**AlignConsecutiveTableGenCondOperatorColons** (``AlignConsecutiveStyle``) :versionbadge:`clang-format 19` :ref:`¶ ` - Style of aligning consecutive TableGen cond operator colons. +: Style of aligning consecutive TableGen cond operator colons. Align the colons of cases inside !cond operators. - .. code-block:: c++ - - !cond(!eq(size, 1) : 1, - !eq(size, 16): 1, - true : 0) + ```c++ + !cond(!eq(size, 1) : 1, + !eq(size, 16): 1, + true : 0) + ``` Nested configuration flags: @@ -1219,160 +1209,161 @@ the configuration (without a prefix: ``Auto``). They can also be read as a whole for compatibility. The choices are: - * ``None`` - * ``Consecutive`` - * ``AcrossEmptyLines`` - * ``AcrossComments`` - * ``AcrossEmptyLinesAndComments`` + - `None` + - `Consecutive` + - `AcrossEmptyLines` + - `AcrossComments` + - `AcrossEmptyLinesAndComments` For example, to align across empty lines and not across comments, either of these work. - .. code-block:: c++ - - AlignConsecutiveTableGenCondOperatorColons: AcrossEmptyLines - - AlignConsecutiveTableGenCondOperatorColons: - Enabled: true - AcrossEmptyLines: true - AcrossComments: false - - * ``bool Enabled`` Whether aligning is enabled. + ```c++ + AlignConsecutiveTableGenCondOperatorColons: AcrossEmptyLines - .. code-block:: c++ + AlignConsecutiveTableGenCondOperatorColons: + Enabled: true + AcrossEmptyLines: true + AcrossComments: false + ``` - #define SHORT_NAME 42 - #define LONGER_NAME 0x007f - #define EVEN_LONGER_NAME (2) - #define foo(x) (x * x) - #define bar(y, z) (y + z) + - `bool Enabled` Whether aligning is enabled. - int a = 1; - int somelongname = 2; - double c = 3; - - int aaaa : 1; - int b : 12; - int ccc : 8; - - int aaaa = 12; - float b = 23; - std::string ccc; + ```c++ + #define SHORT_NAME 42 + #define LONGER_NAME 0x007f + #define EVEN_LONGER_NAME (2) + #define foo(x) (x * x) + #define bar(y, z) (y + z) - * ``bool AcrossEmptyLines`` Whether to align across empty lines. + int a = 1; + int somelongname = 2; + double c = 3; - .. code-block:: c++ + int aaaa : 1; + int b : 12; + int ccc : 8; - true: - int a = 1; - int somelongname = 2; - double c = 3; + int aaaa = 12; + float b = 23; + std::string ccc; + ``` - int d = 3; + - `bool AcrossEmptyLines` Whether to align across empty lines. - false: - int a = 1; - int somelongname = 2; - double c = 3; + ```c++ + true: + int a = 1; + int somelongname = 2; + double c = 3; - int d = 3; + int d = 3; - * ``bool AcrossComments`` Whether to align across comments. + false: + int a = 1; + int somelongname = 2; + double c = 3; - .. code-block:: c++ + int d = 3; + ``` - true: - int d = 3; - /* A comment. */ - double e = 4; + - `bool AcrossComments` Whether to align across comments. - false: - int d = 3; - /* A comment. */ - double e = 4; + ```c++ + true: + int d = 3; + /* A comment. */ + double e = 4; - * ``bool AlignCompound`` Only for ``AlignConsecutiveAssignments``. Whether compound assignments - like ``+=`` are aligned along with ``=``. + false: + int d = 3; + /* A comment. */ + double e = 4; + ``` - .. code-block:: c++ + - `bool AlignCompound` Only for `AlignConsecutiveAssignments`. Whether compound assignments + like `+=` are aligned along with `=`. - true: - a &= 2; - bbb = 2; + ```c++ + true: + a &= 2; + bbb = 2; - false: - a &= 2; - bbb = 2; + false: + a &= 2; + bbb = 2; + ``` - * ``bool AlignFunctionDeclarations`` Only for ``AlignConsecutiveDeclarations``. Whether function declarations + - `bool AlignFunctionDeclarations` Only for `AlignConsecutiveDeclarations`. Whether function declarations are aligned. - .. code-block:: c++ - - true: - unsigned int f1(void); - void f2(void); - size_t f3(void); + ```c++ + true: + unsigned int f1(void); + void f2(void); + size_t f3(void); - false: - unsigned int f1(void); - void f2(void); - size_t f3(void); + false: + unsigned int f1(void); + void f2(void); + size_t f3(void); + ``` - * ``bool AlignFunctionPointers`` Only for ``AlignConsecutiveDeclarations``. Whether function pointers are + - `bool AlignFunctionPointers` Only for `AlignConsecutiveDeclarations`. Whether function pointers are aligned. - .. code-block:: c++ - - true: - unsigned i; - int &r; - int *p; - int (*f)(); - - false: - unsigned i; - int &r; - int *p; - int (*f)(); - - * ``bool EnumAssignments`` Only for ``AlignConsecutiveAssignments``. - Whether enum assignments are aligned. If ``Enabled`` is ``false``, - setting this to ``true`` forces alignment for enum assignments only. - If ``Enabled`` is ``true``, enum assignments are always aligned. + ```c++ + true: + unsigned i; + int &r; + int *p; + int (*f)(); - * ``bool PadOperators`` Only for ``AlignConsecutiveAssignments``. Whether short assignment + false: + unsigned i; + int &r; + int *p; + int (*f)(); + ``` + + - `bool EnumAssignments` Only for `AlignConsecutiveAssignments`. + Whether enum assignments are aligned. If `Enabled` is `false`, + setting this to `true` forces alignment for enum assignments only. + If `Enabled` is `true`, enum assignments are always aligned. + + - `bool PadOperators` Only for `AlignConsecutiveAssignments`. Whether short assignment operators are left-padded to the same length as long ones in order to put all assignment operators to the right of the left hand side. - .. code-block:: c++ + ```c++ + true: + a >>= 2; + bbb = 2; - true: - a >>= 2; - bbb = 2; + a = 2; + bbb >>= 2; - a = 2; - bbb >>= 2; + false: + a >>= 2; + bbb = 2; - false: - a >>= 2; - bbb = 2; + a = 2; + bbb >>= 2; + ``` - a = 2; - bbb >>= 2; +(alignconsecutivetablegendefinitioncolons)= -.. _AlignConsecutiveTableGenDefinitionColons: +**AlignConsecutiveTableGenDefinitionColons** (`AlignConsecutiveStyle`) {versionbadge}`clang-format 19` {ref}`¶ ` -**AlignConsecutiveTableGenDefinitionColons** (``AlignConsecutiveStyle``) :versionbadge:`clang-format 19` :ref:`¶ ` - Style of aligning consecutive TableGen definition colons. +: Style of aligning consecutive TableGen definition colons. This aligns the inheritance colons of consecutive definitions. - .. code-block:: c++ - - def Def : Parent {} - def DefDef : Parent {} - def DefDefDef : Parent {} + ```c++ + def Def : Parent {} + def DefDef : Parent {} + def DefDefDef : Parent {} + ``` Nested configuration flags: @@ -1380,558 +1371,570 @@ the configuration (without a prefix: ``Auto``). They can also be read as a whole for compatibility. The choices are: - * ``None`` - * ``Consecutive`` - * ``AcrossEmptyLines`` - * ``AcrossComments`` - * ``AcrossEmptyLinesAndComments`` + - `None` + - `Consecutive` + - `AcrossEmptyLines` + - `AcrossComments` + - `AcrossEmptyLinesAndComments` For example, to align across empty lines and not across comments, either of these work. - .. code-block:: c++ - - AlignConsecutiveTableGenDefinitionColons: AcrossEmptyLines + ```c++ + AlignConsecutiveTableGenDefinitionColons: AcrossEmptyLines - AlignConsecutiveTableGenDefinitionColons: - Enabled: true - AcrossEmptyLines: true - AcrossComments: false + AlignConsecutiveTableGenDefinitionColons: + Enabled: true + AcrossEmptyLines: true + AcrossComments: false + ``` - * ``bool Enabled`` Whether aligning is enabled. + - `bool Enabled` Whether aligning is enabled. - .. code-block:: c++ - - #define SHORT_NAME 42 - #define LONGER_NAME 0x007f - #define EVEN_LONGER_NAME (2) - #define foo(x) (x * x) - #define bar(y, z) (y + z) - - int a = 1; - int somelongname = 2; - double c = 3; - - int aaaa : 1; - int b : 12; - int ccc : 8; - - int aaaa = 12; - float b = 23; - std::string ccc; + ```c++ + #define SHORT_NAME 42 + #define LONGER_NAME 0x007f + #define EVEN_LONGER_NAME (2) + #define foo(x) (x * x) + #define bar(y, z) (y + z) - * ``bool AcrossEmptyLines`` Whether to align across empty lines. + int a = 1; + int somelongname = 2; + double c = 3; - .. code-block:: c++ + int aaaa : 1; + int b : 12; + int ccc : 8; - true: - int a = 1; - int somelongname = 2; - double c = 3; + int aaaa = 12; + float b = 23; + std::string ccc; + ``` - int d = 3; + - `bool AcrossEmptyLines` Whether to align across empty lines. - false: - int a = 1; - int somelongname = 2; - double c = 3; + ```c++ + true: + int a = 1; + int somelongname = 2; + double c = 3; - int d = 3; + int d = 3; - * ``bool AcrossComments`` Whether to align across comments. + false: + int a = 1; + int somelongname = 2; + double c = 3; - .. code-block:: c++ + int d = 3; + ``` - true: - int d = 3; - /* A comment. */ - double e = 4; + - `bool AcrossComments` Whether to align across comments. - false: - int d = 3; - /* A comment. */ - double e = 4; + ```c++ + true: + int d = 3; + /* A comment. */ + double e = 4; - * ``bool AlignCompound`` Only for ``AlignConsecutiveAssignments``. Whether compound assignments - like ``+=`` are aligned along with ``=``. + false: + int d = 3; + /* A comment. */ + double e = 4; + ``` - .. code-block:: c++ + - `bool AlignCompound` Only for `AlignConsecutiveAssignments`. Whether compound assignments + like `+=` are aligned along with `=`. - true: - a &= 2; - bbb = 2; + ```c++ + true: + a &= 2; + bbb = 2; - false: - a &= 2; - bbb = 2; + false: + a &= 2; + bbb = 2; + ``` - * ``bool AlignFunctionDeclarations`` Only for ``AlignConsecutiveDeclarations``. Whether function declarations + - `bool AlignFunctionDeclarations` Only for `AlignConsecutiveDeclarations`. Whether function declarations are aligned. - .. code-block:: c++ - - true: - unsigned int f1(void); - void f2(void); - size_t f3(void); + ```c++ + true: + unsigned int f1(void); + void f2(void); + size_t f3(void); - false: - unsigned int f1(void); - void f2(void); - size_t f3(void); + false: + unsigned int f1(void); + void f2(void); + size_t f3(void); + ``` - * ``bool AlignFunctionPointers`` Only for ``AlignConsecutiveDeclarations``. Whether function pointers are + - `bool AlignFunctionPointers` Only for `AlignConsecutiveDeclarations`. Whether function pointers are aligned. - .. code-block:: c++ - - true: - unsigned i; - int &r; - int *p; - int (*f)(); - - false: - unsigned i; - int &r; - int *p; - int (*f)(); - - * ``bool EnumAssignments`` Only for ``AlignConsecutiveAssignments``. - Whether enum assignments are aligned. If ``Enabled`` is ``false``, - setting this to ``true`` forces alignment for enum assignments only. - If ``Enabled`` is ``true``, enum assignments are always aligned. + ```c++ + true: + unsigned i; + int &r; + int *p; + int (*f)(); - * ``bool PadOperators`` Only for ``AlignConsecutiveAssignments``. Whether short assignment + false: + unsigned i; + int &r; + int *p; + int (*f)(); + ``` + + - `bool EnumAssignments` Only for `AlignConsecutiveAssignments`. + Whether enum assignments are aligned. If `Enabled` is `false`, + setting this to `true` forces alignment for enum assignments only. + If `Enabled` is `true`, enum assignments are always aligned. + + - `bool PadOperators` Only for `AlignConsecutiveAssignments`. Whether short assignment operators are left-padded to the same length as long ones in order to put all assignment operators to the right of the left hand side. - .. code-block:: c++ + ```c++ + true: + a >>= 2; + bbb = 2; - true: - a >>= 2; - bbb = 2; + a = 2; + bbb >>= 2; - a = 2; - bbb >>= 2; + false: + a >>= 2; + bbb = 2; - false: - a >>= 2; - bbb = 2; + a = 2; + bbb >>= 2; + ``` - a = 2; - bbb >>= 2; +(alignescapednewlines)= -.. _AlignEscapedNewlines: +**AlignEscapedNewlines** (`EscapedNewlineAlignmentStyle`) {versionbadge}`clang-format 5` {ref}`¶ ` -**AlignEscapedNewlines** (``EscapedNewlineAlignmentStyle``) :versionbadge:`clang-format 5` :ref:`¶ ` - Options for aligning backslashes in escaped newlines. +: Options for aligning backslashes in escaped newlines. Possible values: - * ``ENAS_DontAlign`` (in configuration: ``DontAlign``) + - `ENAS_DontAlign` (in configuration: `DontAlign`) Don't align escaped newlines. - .. code-block:: c++ + ```c++ + #define A \ + int aaaa; \ + int b; \ + int dddddddddd; + ``` - #define A \ - int aaaa; \ - int b; \ - int dddddddddd; - - * ``ENAS_Left`` (in configuration: ``Left``) + - `ENAS_Left` (in configuration: `Left`) Align escaped newlines as far left as possible. - .. code-block:: c++ - - #define A \ - int aaaa; \ - int b; \ - int dddddddddd; + ```c++ + #define A \ + int aaaa; \ + int b; \ + int dddddddddd; + ``` - * ``ENAS_LeftWithLastLine`` (in configuration: ``LeftWithLastLine``) + - `ENAS_LeftWithLastLine` (in configuration: `LeftWithLastLine`) Align escaped newlines as far left as possible, using the last line of the preprocessor directive as the reference if it's the longest. - .. code-block:: c++ + ```c++ + #define A \ + int aaaa; \ + int b; \ + int dddddddddd; + ``` - #define A \ - int aaaa; \ - int b; \ - int dddddddddd; - - * ``ENAS_Right`` (in configuration: ``Right``) + - `ENAS_Right` (in configuration: `Right`) Align escaped newlines in the right-most column. - .. code-block:: c++ + ```c++ + #define A \ + int aaaa; \ + int b; \ + int dddddddddd; + ``` - #define A \ - int aaaa; \ - int b; \ - int dddddddddd; +(alignoperands)= -.. _AlignOperands: +**AlignOperands** (`OperandAlignmentStyle`) {versionbadge}`clang-format 3.5` {ref}`¶ ` -**AlignOperands** (``OperandAlignmentStyle``) :versionbadge:`clang-format 3.5` :ref:`¶ ` - If ``true``, horizontally align operands of binary and ternary +: If `true`, horizontally align operands of binary and ternary expressions. Possible values: - * ``OAS_DontAlign`` (in configuration: ``DontAlign``) + - `OAS_DontAlign` (in configuration: `DontAlign`) Do not align operands of binary and ternary expressions. - The wrapped lines are indented ``ContinuationIndentWidth`` spaces from + The wrapped lines are indented `ContinuationIndentWidth` spaces from the start of the line. - * ``OAS_Align`` (in configuration: ``Align``) + - `OAS_Align` (in configuration: `Align`) Horizontally align operands of binary and ternary expressions. Specifically, this aligns operands of a single expression that needs to be split over multiple lines, e.g.: - .. code-block:: c++ - - int aaa = bbbbbbbbbbbbbbb + - ccccccccccccccc; + ```c++ + int aaa = bbbbbbbbbbbbbbb + + ccccccccccccccc; + ``` - When ``BreakBeforeBinaryOperators`` is set, the wrapped operator is + When `BreakBeforeBinaryOperators` is set, the wrapped operator is aligned with the operand on the first line. - .. code-block:: c++ - - int aaa = bbbbbbbbbbbbbbb - + ccccccccccccccc; + ```c++ + int aaa = bbbbbbbbbbbbbbb + + ccccccccccccccc; + ``` - * ``OAS_AlignAfterOperator`` (in configuration: ``AlignAfterOperator``) + - `OAS_AlignAfterOperator` (in configuration: `AlignAfterOperator`) Horizontally align operands of binary and ternary expressions. - This is similar to ``OAS_Align``, except when - ``BreakBeforeBinaryOperators`` is set, the operator is un-indented so + This is similar to `OAS_Align`, except when + `BreakBeforeBinaryOperators` is set, the operator is un-indented so that the wrapped operand is aligned with the operand on the first line. - .. code-block:: c++ + ```c++ + int aaa = bbbbbbbbbbbbbbb + + ccccccccccccccc; + ``` - int aaa = bbbbbbbbbbbbbbb - + ccccccccccccccc; +(aligntrailingcomments)= -.. _AlignTrailingComments: +**AlignTrailingComments** (`TrailingCommentsAlignmentStyle`) {versionbadge}`clang-format 3.7` {ref}`¶ ` -**AlignTrailingComments** (``TrailingCommentsAlignmentStyle``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - Control of trailing comments. +: Control of trailing comments. The alignment stops at closing braces after a line break, and only - followed by other closing braces, a (``do-``) ``while``, a lambda call, or + followed by other closing braces, a (`do-`) `while`, a lambda call, or a semicolon. + :::{note} + As of clang-format 16 this option is not a bool but can be set + to the options. Conventional bool options still can be parsed as before. + ::: - .. note:: - - As of clang-format 16 this option is not a bool but can be set - to the options. Conventional bool options still can be parsed as before. - - - .. code-block:: yaml - - # Example of usage: - AlignTrailingComments: - Kind: Always - OverEmptyLines: 2 + ```yaml + # Example of usage: + AlignTrailingComments: + Kind: Always + OverEmptyLines: 2 + ``` Nested configuration flags: Alignment options - * ``TrailingCommentsAlignmentKinds Kind`` + - `TrailingCommentsAlignmentKinds Kind` Specifies the way to align trailing comments. Possible values: - * ``TCAS_Leave`` (in configuration: ``Leave``) + - `TCAS_Leave` (in configuration: `Leave`) Leave trailing comments as they are. - .. code-block:: c++ - - int a; // comment - int ab; // comment + ```c++ + int a; // comment + int ab; // comment - int abc; // comment - int abcd; // comment + int abc; // comment + int abcd; // comment + ``` - * ``TCAS_Always`` (in configuration: ``Always``) + - `TCAS_Always` (in configuration: `Always`) Align trailing comments. - .. code-block:: c++ + ```c++ + int a; // comment + int ab; // comment - int a; // comment - int ab; // comment + int abc; // comment + int abcd; // comment + ``` - int abc; // comment - int abcd; // comment - - * ``TCAS_Never`` (in configuration: ``Never``) + - `TCAS_Never` (in configuration: `Never`) Don't align trailing comments but other formatter applies. - .. code-block:: c++ - - int a; // comment - int ab; // comment + ```c++ + int a; // comment + int ab; // comment - int abc; // comment - int abcd; // comment + int abc; // comment + int abcd; // comment + ``` - * ``unsigned OverEmptyLines`` How many empty lines to apply alignment. - When both ``MaxEmptyLinesToKeep`` and ``OverEmptyLines`` are set to 2, + - `unsigned OverEmptyLines` How many empty lines to apply alignment. + When both `MaxEmptyLinesToKeep` and `OverEmptyLines` are set to 2, it formats like below. - .. code-block:: c++ + ```c++ + int a; // all these - int a; // all these + int ab; // comments are - int ab; // comments are + int abcdef; // aligned + ``` - int abcdef; // aligned - - When ``MaxEmptyLinesToKeep`` is set to 2 and ``OverEmptyLines`` is set + When `MaxEmptyLinesToKeep` is set to 2 and `OverEmptyLines` is set to 1, it formats like below. - .. code-block:: c++ - - int a; // these are + ```c++ + int a; // these are - int ab; // aligned + int ab; // aligned - int abcdef; // but this isn't + int abcdef; // but this isn't + ``` - * ``bool AlignPPAndNotPP`` If comments following preprocessor directive should be aligned with + - `bool AlignPPAndNotPP` If comments following preprocessor directive should be aligned with comments that don't. - .. code-block:: c++ + ```c++ + true: false: + #define A // Comment vs. #define A // Comment + #define AB // Aligned #define AB // Aligned + int i; // Aligned int i; // Not aligned + ``` - true: false: - #define A // Comment vs. #define A // Comment - #define AB // Aligned #define AB // Aligned - int i; // Aligned int i; // Not aligned +(allowallargumentsonnextline)= -.. _AllowAllArgumentsOnNextLine: +**AllowAllArgumentsOnNextLine** (`Boolean`) {versionbadge}`clang-format 9` {ref}`¶ ` -**AllowAllArgumentsOnNextLine** (``Boolean``) :versionbadge:`clang-format 9` :ref:`¶ ` - If a function call or braced initializer list doesn't fit on a line, allow - putting all arguments onto the next line, even if ``BinPackArguments`` is - ``false``. +: If a function call or braced initializer list doesn't fit on a line, allow + putting all arguments onto the next line, even if `BinPackArguments` is + `false`. - .. code-block:: c++ + ```c++ + true: + callFunction( + a, b, c, d); - true: - callFunction( - a, b, c, d); + false: + callFunction(a, + b, + c, + d); + ``` - false: - callFunction(a, - b, - c, - d); +(allowallconstructorinitializersonnextline)= + +**AllowAllConstructorInitializersOnNextLine** (`Boolean`) {versionbadge}`clang-format 9` {ref}`¶ ` -.. _AllowAllConstructorInitializersOnNextLine: +: This option is **deprecated**. See `NextLine` of + `PackConstructorInitializers`. -**AllowAllConstructorInitializersOnNextLine** (``Boolean``) :versionbadge:`clang-format 9` :ref:`¶ ` - This option is **deprecated**. See ``NextLine`` of - ``PackConstructorInitializers``. +(allowallparametersofdeclarationonnextline)= -.. _AllowAllParametersOfDeclarationOnNextLine: +**AllowAllParametersOfDeclarationOnNextLine** (`Boolean`) {versionbadge}`clang-format 3.3` {ref}`¶ ` -**AllowAllParametersOfDeclarationOnNextLine** (``Boolean``) :versionbadge:`clang-format 3.3` :ref:`¶ ` - If the function declaration doesn't fit on a line, +: If the function declaration doesn't fit on a line, allow putting all parameters of a function declaration onto - the next line even if ``BinPackParameters`` is ``OnePerLine``. + the next line even if `BinPackParameters` is `OnePerLine`. - .. code-block:: c++ + ```c++ + true: + void myFunction( + int a, int b, int c, int d, int e); - true: - void myFunction( - int a, int b, int c, int d, int e); + false: + void myFunction(int a, + int b, + int c, + int d, + int e); + ``` - false: - void myFunction(int a, - int b, - int c, - int d, - int e); +(allowbreakbeforenoexceptspecifier)= -.. _AllowBreakBeforeNoexceptSpecifier: +**AllowBreakBeforeNoexceptSpecifier** (`BreakBeforeNoexceptSpecifierStyle`) {versionbadge}`clang-format 18` {ref}`¶ ` -**AllowBreakBeforeNoexceptSpecifier** (``BreakBeforeNoexceptSpecifierStyle``) :versionbadge:`clang-format 18` :ref:`¶ ` - Controls if there could be a line break before a ``noexcept`` specifier. +: Controls if there could be a line break before a `noexcept` specifier. Possible values: - * ``BBNSS_Never`` (in configuration: ``Never``) + - `BBNSS_Never` (in configuration: `Never`) No line break allowed. - .. code-block:: c++ + ```c++ + void foo(int arg1, + double arg2) noexcept; - void foo(int arg1, - double arg2) noexcept; + void bar(int arg1, double arg2) noexcept( + noexcept(baz(arg1)) && + noexcept(baz(arg2))); + ``` - void bar(int arg1, double arg2) noexcept( - noexcept(baz(arg1)) && - noexcept(baz(arg2))); - - * ``BBNSS_OnlyWithParen`` (in configuration: ``OnlyWithParen``) - For a simple ``noexcept`` there is no line break allowed, but when we + - `BBNSS_OnlyWithParen` (in configuration: `OnlyWithParen`) + For a simple `noexcept` there is no line break allowed, but when we have a condition it is. - .. code-block:: c++ - - void foo(int arg1, - double arg2) noexcept; + ```c++ + void foo(int arg1, + double arg2) noexcept; - void bar(int arg1, double arg2) - noexcept(noexcept(baz(arg1)) && - noexcept(baz(arg2))); + void bar(int arg1, double arg2) + noexcept(noexcept(baz(arg1)) && + noexcept(baz(arg2))); + ``` - * ``BBNSS_Always`` (in configuration: ``Always``) + - `BBNSS_Always` (in configuration: `Always`) Line breaks are allowed. But note that because of the associated - penalties ``clang-format`` often prefers not to break before the - ``noexcept``. + penalties `clang-format` often prefers not to break before the + `noexcept`. - .. code-block:: c++ + ```c++ + void foo(int arg1, + double arg2) noexcept; - void foo(int arg1, - double arg2) noexcept; + void bar(int arg1, double arg2) + noexcept(noexcept(baz(arg1)) && + noexcept(baz(arg2))); + ``` - void bar(int arg1, double arg2) - noexcept(noexcept(baz(arg1)) && - noexcept(baz(arg2))); +(allowbreakbeforeqtproperty)= -.. _AllowBreakBeforeQtProperty: +**AllowBreakBeforeQtProperty** (`Boolean`) {versionbadge}`clang-format 22` {ref}`¶ ` -**AllowBreakBeforeQtProperty** (``Boolean``) :versionbadge:`clang-format 22` :ref:`¶ ` - Allow breaking before ``Q_Property`` keywords ``READ``, ``WRITE``, etc. as - if they were preceded by a comma (``,``). This allows them to be formatted - according to ``BinPackParameters``. +: Allow breaking before `Q_Property` keywords `READ`, `WRITE`, etc. as + if they were preceded by a comma (`,`). This allows them to be formatted + according to `BinPackParameters`. -.. _AllowShortBlocksOnASingleLine: +(allowshortblocksonasingleline)= -**AllowShortBlocksOnASingleLine** (``ShortBlockStyle``) :versionbadge:`clang-format 3.5` :ref:`¶ ` - Dependent on the value, ``while (true) { continue; }`` can be put on a +**AllowShortBlocksOnASingleLine** (`ShortBlockStyle`) {versionbadge}`clang-format 3.5` {ref}`¶ ` + +: Dependent on the value, `while (true) { continue; }` can be put on a single line. Possible values: - * ``SBS_Never`` (in configuration: ``Never``) + - `SBS_Never` (in configuration: `Never`) Never merge blocks into a single line. - .. code-block:: c++ - - while (true) { - } - while (true) { - continue; - } + ```c++ + while (true) { + } + while (true) { + continue; + } + ``` - * ``SBS_Empty`` (in configuration: ``Empty``) + - `SBS_Empty` (in configuration: `Empty`) Only merge empty blocks. - .. code-block:: c++ - - while (true) {} - while (true) { - continue; - } + ```c++ + while (true) {} + while (true) { + continue; + } + ``` - * ``SBS_Always`` (in configuration: ``Always``) + - `SBS_Always` (in configuration: `Always`) Always merge short blocks into a single line. - .. code-block:: c++ + ```c++ + while (true) {} + while (true) { continue; } + ``` - while (true) {} - while (true) { continue; } +(allowshortcaseexpressiononasingleline)= -.. _AllowShortCaseExpressionOnASingleLine: +**AllowShortCaseExpressionOnASingleLine** (`Boolean`) {versionbadge}`clang-format 19` {ref}`¶ ` -**AllowShortCaseExpressionOnASingleLine** (``Boolean``) :versionbadge:`clang-format 19` :ref:`¶ ` - Whether to merge a short switch labeled rule into a single line. +: Whether to merge a short switch labeled rule into a single line. - .. code-block:: java + ```java + true: false: + switch (a) { vs. switch (a) { + case 1 -> 1; case 1 -> + default -> 0; 1; + }; default -> + 0; + }; + ``` - true: false: - switch (a) { vs. switch (a) { - case 1 -> 1; case 1 -> - default -> 0; 1; - }; default -> - 0; - }; - -.. _AllowShortCaseLabelsOnASingleLine: - -**AllowShortCaseLabelsOnASingleLine** (``Boolean``) :versionbadge:`clang-format 3.6` :ref:`¶ ` - If ``true``, short case labels will be contracted to a single line. - - .. code-block:: c++ - - true: false: - switch (a) { vs. switch (a) { - case 1: x = 1; break; case 1: - case 2: return; x = 1; - } break; - case 2: - return; - } +(allowshortcaselabelsonasingleline)= -.. _AllowShortCompoundRequirementOnASingleLine: +**AllowShortCaseLabelsOnASingleLine** (`Boolean`) {versionbadge}`clang-format 3.6` {ref}`¶ ` -**AllowShortCompoundRequirementOnASingleLine** (``Boolean``) :versionbadge:`clang-format 18` :ref:`¶ ` - Allow short compound requirement on a single line. +: If `true`, short case labels will be contracted to a single line. - .. code-block:: c++ + ```c++ + true: false: + switch (a) { vs. switch (a) { + case 1: x = 1; break; case 1: + case 2: return; x = 1; + } break; + case 2: + return; + } + ``` - true: - template - concept c = requires(T x) { - { x + 1 } -> std::same_as; - }; +(allowshortcompoundrequirementonasingleline)= - false: - template - concept c = requires(T x) { - { - x + 1 - } -> std::same_as; - }; +**AllowShortCompoundRequirementOnASingleLine** (`Boolean`) {versionbadge}`clang-format 18` {ref}`¶ ` -.. _AllowShortEnumsOnASingleLine: +: Allow short compound requirement on a single line. -**AllowShortEnumsOnASingleLine** (``Boolean``) :versionbadge:`clang-format 11` :ref:`¶ ` - Allow short enums on a single line. + ```c++ + true: + template + concept c = requires(T x) { + { x + 1 } -> std::same_as; + }; - .. code-block:: c++ + false: + template + concept c = requires(T x) { + { + x + 1 + } -> std::same_as; + }; + ``` - true: - enum { A, B } myEnum; +(allowshortenumsonasingleline)= - false: - enum { - A, - B - } myEnum; +**AllowShortEnumsOnASingleLine** (`Boolean`) {versionbadge}`clang-format 11` {ref}`¶ ` + +: Allow short enums on a single line. + + ```c++ + true: + enum { A, B } myEnum; + + false: + enum { + A, + B + } myEnum; + ``` -.. _AllowShortFunctionsOnASingleLine: +(allowshortfunctionsonasingleline)= -**AllowShortFunctionsOnASingleLine** (``ShortFunctionStyle``) :versionbadge:`clang-format 3.5` :ref:`¶ ` - Dependent on the value, ``int f() { return 0; }`` can be put on a +**AllowShortFunctionsOnASingleLine** (`ShortFunctionStyle`) {versionbadge}`clang-format 3.5` {ref}`¶ ` + +: Dependent on the value, `int f() { return 0; }` can be put on a single line. Nested configuration flags: @@ -1941,2507 +1944,2565 @@ the configuration (without a prefix: ``Auto``). They can be read as a whole for compatibility. The choices are: - * ``None`` + - `None` Never merge functions into a single line. - * ``InlineOnly`` - Only merge functions defined inside a class. Same as ``inline``, - except it does not implies ``empty``: i.e. top level empty functions - are not merged either. See ``Inline`` of ``ShortFunctionStyle``. - - .. code-block:: c++ - - class Foo { - void f() { foo(); } - }; - void f() { - foo(); - } - void f() { - } - - * ``Empty`` - Only merge empty functions. See ``Empty`` of ``ShortFunctionStyle``. + - `InlineOnly` + Only merge functions defined inside a class. Same as `inline`, + except it does not implies `empty`: i.e. top level empty functions + are not merged either. See `Inline` of `ShortFunctionStyle`. - .. code-block:: c++ + ```c++ + class Foo { + void f() { foo(); } + }; + void f() { + foo(); + } + void f() { + } + ``` - void f() {} - void f2() { - bar2(); - } + - `Empty` + Only merge empty functions. See `Empty` of `ShortFunctionStyle`. - * ``Inline`` - Only merge functions defined inside a class. Implies ``empty``. See - ``Inline`` and ``Empty`` of ``ShortFunctionStyle``. + ```c++ + void f() {} + void f2() { + bar2(); + } + ``` - .. code-block:: c++ + - `Inline` + Only merge functions defined inside a class. Implies `empty`. See + `Inline` and `Empty` of `ShortFunctionStyle`. - class Foo { - void f() { foo(); } - }; - void f() { - foo(); - } - void f() {} + ```c++ + class Foo { + void f() { foo(); } + }; + void f() { + foo(); + } + void f() {} + ``` - * ``All`` + - `All` Merge all functions fitting on a single line. - .. code-block:: c++ - - class Foo { - void f() { foo(); } - }; - void f() { bar(); } + ```c++ + class Foo { + void f() { foo(); } + }; + void f() { bar(); } + ``` Also can be specified as a nested configuration flag: - .. code-block:: c++ - - # Example of usage: - AllowShortFunctionsOnASingleLine: InlineOnly + ```yaml + # Example of usage: + AllowShortFunctionsOnASingleLine: InlineOnly - # or more granular control: - AllowShortFunctionsOnASingleLine: - Empty: false - Inline: true - Other: false + # or more granular control: + AllowShortFunctionsOnASingleLine: + Empty: false + Inline: true + Other: false + ``` - * ``bool Empty`` Merge top-level empty functions. + - `bool Empty` Merge top-level empty functions. - .. code-block:: c++ - - void f() {} - void f2() { - bar2(); - } - void f3() { /* comment */ } - - * ``bool Inline`` Merge functions defined inside a class. + ```c++ + void f() {} + void f2() { + bar2(); + } + void f3() { /* comment */ } + ``` - .. code-block:: c++ + - `bool Inline` Merge functions defined inside a class. - class Foo { - void f() { foo(); } - void g() {} - }; - void f() { - foo(); - } - void f() { - } + ```c++ + class Foo { + void f() { foo(); } + void g() {} + }; + void f() { + foo(); + } + void f() { + } + ``` - * ``bool Other`` Merge all functions fitting on a single line. Please note that this + - `bool Other` Merge all functions fitting on a single line. Please note that this control does not include Empty - .. code-block:: c++ + ```c++ + class Foo { + void f() { foo(); } + }; + void f() { bar(); } + ``` - class Foo { - void f() { foo(); } - }; - void f() { bar(); } +(allowshortifstatementsonasingleline)= -.. _AllowShortIfStatementsOnASingleLine: +**AllowShortIfStatementsOnASingleLine** (`ShortIfStyle`) {versionbadge}`clang-format 3.3` {ref}`¶ ` -**AllowShortIfStatementsOnASingleLine** (``ShortIfStyle``) :versionbadge:`clang-format 3.3` :ref:`¶ ` - Dependent on the value, ``if (a) return;`` can be put on a single line. +: Dependent on the value, `if (a) return;` can be put on a single line. Possible values: - * ``SIS_Never`` (in configuration: ``Never``) + - `SIS_Never` (in configuration: `Never`) Never put short ifs on the same line. - .. code-block:: c++ - - if (a) - return; + ```c++ + if (a) + return; - if (b) - return; - else - return; + if (b) + return; + else + return; - if (c) - return; - else { - return; - } + if (c) + return; + else { + return; + } + ``` - * ``SIS_WithoutElse`` (in configuration: ``WithoutElse``) + - `SIS_WithoutElse` (in configuration: `WithoutElse`) Put short ifs on the same line only if there is no else statement. - .. code-block:: c++ - - if (a) return; + ```c++ + if (a) return; - if (b) - return; - else - return; + if (b) + return; + else + return; - if (c) - return; - else { - return; - } + if (c) + return; + else { + return; + } + ``` - * ``SIS_OnlyFirstIf`` (in configuration: ``OnlyFirstIf``) + - `SIS_OnlyFirstIf` (in configuration: `OnlyFirstIf`) Put short ifs, but not else ifs nor else statements, on the same line. - .. code-block:: c++ - - if (a) return; + ```c++ + if (a) return; - if (b) return; - else if (b) - return; - else - return; + if (b) return; + else if (b) + return; + else + return; - if (c) return; - else { - return; - } + if (c) return; + else { + return; + } + ``` - * ``SIS_AllIfsAndElse`` (in configuration: ``AllIfsAndElse``) + - `SIS_AllIfsAndElse` (in configuration: `AllIfsAndElse`) Always put short ifs, else ifs and else statements on the same line. - .. code-block:: c++ + ```c++ + if (a) return; - if (a) return; + if (b) return; + else return; - if (b) return; - else return; + if (c) return; + else { + return; + } + ``` - if (c) return; - else { - return; - } +(allowshortlambdasonasingleline)= -.. _AllowShortLambdasOnASingleLine: +**AllowShortLambdasOnASingleLine** (`ShortLambdaStyle`) {versionbadge}`clang-format 9` {ref}`¶ ` -**AllowShortLambdasOnASingleLine** (``ShortLambdaStyle``) :versionbadge:`clang-format 9` :ref:`¶ ` - Dependent on the value, ``auto lambda []() { return 0; }`` can be put on a +: Dependent on the value, `auto lambda []() { return 0; }` can be put on a single line. Possible values: - * ``SLS_None`` (in configuration: ``None``) + - `SLS_None` (in configuration: `None`) Never merge lambdas into a single line. - * ``SLS_Empty`` (in configuration: ``Empty``) + - `SLS_Empty` (in configuration: `Empty`) Only merge empty lambdas. - .. code-block:: c++ - - auto lambda = [](int a) {}; - auto lambda2 = [](int a) { - return a; - }; + ```c++ + auto lambda = [](int a) {}; + auto lambda2 = [](int a) { + return a; + }; + ``` - * ``SLS_Inline`` (in configuration: ``Inline``) + - `SLS_Inline` (in configuration: `Inline`) Merge lambda into a single line if the lambda is argument of a function. - .. code-block:: c++ - - auto lambda = [](int x, int y) { - return x < y; - }; - sort(a.begin(), a.end(), [](int x, int y) { return x < y; }); + ```c++ + auto lambda = [](int x, int y) { + return x < y; + }; + sort(a.begin(), a.end(), [](int x, int y) { return x < y; }); + ``` - * ``SLS_All`` (in configuration: ``All``) + - `SLS_All` (in configuration: `All`) Merge all lambdas fitting on a single line. - .. code-block:: c++ + ```c++ + auto lambda = [](int a) {}; + auto lambda2 = [](int a) { return a; }; + ``` - auto lambda = [](int a) {}; - auto lambda2 = [](int a) { return a; }; +(allowshortloopsonasingleline)= -.. _AllowShortLoopsOnASingleLine: +**AllowShortLoopsOnASingleLine** (`Boolean`) {versionbadge}`clang-format 3.7` {ref}`¶ ` -**AllowShortLoopsOnASingleLine** (``Boolean``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - If ``true``, ``while (true) continue;`` can be put on a single +: If `true`, `while (true) continue;` can be put on a single line. -.. _AllowShortNamespacesOnASingleLine: +(allowshortnamespacesonasingleline)= + +**AllowShortNamespacesOnASingleLine** (`Boolean`) {versionbadge}`clang-format 20` {ref}`¶ ` -**AllowShortNamespacesOnASingleLine** (``Boolean``) :versionbadge:`clang-format 20` :ref:`¶ ` - If ``true``, ``namespace a { class b; }`` can be put on a single line. +: If `true`, `namespace a { class b; }` can be put on a single line. -.. _AllowShortRecordOnASingleLine: +(allowshortrecordonasingleline)= -**AllowShortRecordOnASingleLine** (``ShortRecordStyle``) :versionbadge:`clang-format 23` :ref:`¶ ` - Dependent on the value, ``struct bar { int i; };`` can be put on a single +**AllowShortRecordOnASingleLine** (`ShortRecordStyle`) {versionbadge}`clang-format 23` {ref}`¶ ` + +: Dependent on the value, `struct bar { int i; };` can be put on a single line. Possible values: - * ``SRS_Never`` (in configuration: ``Never``) + - `SRS_Never` (in configuration: `Never`) Never merge records into a single line. - * ``SRS_EmptyAndAttached`` (in configuration: ``EmptyAndAttached``) + - `SRS_EmptyAndAttached` (in configuration: `EmptyAndAttached`) Only merge empty records if the opening brace was not wrapped, - i.e. the corresponding ``BraceWrapping.After...`` option was not set. + i.e. the corresponding `BraceWrapping.After...` option was not set. - * ``SRS_Empty`` (in configuration: ``Empty``) + - `SRS_Empty` (in configuration: `Empty`) Only merge empty records. - .. code-block:: c++ - - struct foo {}; - struct bar - { - int i; - }; + ```c++ + struct foo {}; + struct bar + { + int i; + }; + ``` - * ``SRS_Always`` (in configuration: ``Always``) + - `SRS_Always` (in configuration: `Always`) Merge all records that fit on a single line. - .. code-block:: c++ + ```c++ + struct foo {}; + struct bar { int i; }; + ``` - struct foo {}; - struct bar { int i; }; +(alwaysbreakafterdefinitionreturntype)= -.. _AlwaysBreakAfterDefinitionReturnType: +**AlwaysBreakAfterDefinitionReturnType** (`DefinitionReturnTypeBreakingStyle`) {versionbadge}`clang-format 3.7` {ref}`¶ ` -**AlwaysBreakAfterDefinitionReturnType** (``DefinitionReturnTypeBreakingStyle``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - The function definition return type breaking style to use. This +: The function definition return type breaking style to use. This option is **deprecated** and is retained for backwards compatibility. Possible values: - * ``DRTBS_None`` (in configuration: ``None``) + - `DRTBS_None` (in configuration: `None`) Break after return type automatically. - ``PenaltyReturnTypeOnItsOwnLine`` is taken into account. + `PenaltyReturnTypeOnItsOwnLine` is taken into account. - * ``DRTBS_All`` (in configuration: ``All``) + - `DRTBS_All` (in configuration: `All`) Always break after the return type. - * ``DRTBS_TopLevel`` (in configuration: ``TopLevel``) + - `DRTBS_TopLevel` (in configuration: `TopLevel`) Always break after the return types of top-level functions. -.. _AlwaysBreakAfterReturnType: +(alwaysbreakafterreturntype)= + +**AlwaysBreakAfterReturnType** (`deprecated`) {versionbadge}`clang-format 3.8` {ref}`¶ ` + +: This option is renamed to `BreakAfterReturnType`. -**AlwaysBreakAfterReturnType** (``deprecated``) :versionbadge:`clang-format 3.8` :ref:`¶ ` - This option is renamed to ``BreakAfterReturnType``. +(alwaysbreakbeforemultilinestrings)= -.. _AlwaysBreakBeforeMultilineStrings: +**AlwaysBreakBeforeMultilineStrings** (`Boolean`) {versionbadge}`clang-format 3.4` {ref}`¶ ` -**AlwaysBreakBeforeMultilineStrings** (``Boolean``) :versionbadge:`clang-format 3.4` :ref:`¶ ` - If ``true``, always break before multiline string literals. +: If `true`, always break before multiline string literals. This flag is mean to make cases where there are multiple multiline strings in a file look more consistent. Thus, it will only take effect if wrapping the string at that point leads to it being indented - ``ContinuationIndentWidth`` spaces from the start of the line. + `ContinuationIndentWidth` spaces from the start of the line. - .. code-block:: c++ + ```c++ + true: false: + aaaa = vs. aaaa = "bbbb" + "bbbb" "cccc"; + "cccc"; + ``` - true: false: - aaaa = vs. aaaa = "bbbb" - "bbbb" "cccc"; - "cccc"; +(alwaysbreaktemplatedeclarations)= -.. _AlwaysBreakTemplateDeclarations: +**AlwaysBreakTemplateDeclarations** (`deprecated`) {versionbadge}`clang-format 3.4` {ref}`¶ ` -**AlwaysBreakTemplateDeclarations** (``deprecated``) :versionbadge:`clang-format 3.4` :ref:`¶ ` - This option is renamed to ``BreakTemplateDeclarations``. +: This option is renamed to `BreakTemplateDeclarations`. -.. _AttributeMacros: +(attributemacros)= -**AttributeMacros** (``List of Strings``) :versionbadge:`clang-format 12` :ref:`¶ ` - A vector of strings that should be interpreted as attributes/qualifiers +**AttributeMacros** (`List of Strings`) {versionbadge}`clang-format 12` {ref}`¶ ` + +: A vector of strings that should be interpreted as attributes/qualifiers instead of identifiers. This can be useful for language extensions or static analyzer annotations. For example: - .. code-block:: c++ - - x = (char *__capability)&y; - int function(void) __unused; - void only_writes_to_buffer(char *__output buffer); + ```c++ + x = (char *__capability)&y; + int function(void) __unused; + void only_writes_to_buffer(char *__output buffer); + ``` In the .clang-format configuration file, this can be configured like: - .. code-block:: yaml + ```yaml + AttributeMacros: [__capability, __output, __unused] + ``` - AttributeMacros: [__capability, __output, __unused] +(binpackarguments)= -.. _BinPackArguments: +**BinPackArguments** (`Boolean`) {versionbadge}`clang-format 3.7` {ref}`¶ ` -**BinPackArguments** (``Boolean``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - This option is **deprecated**. See ``BinPack`` of ``PackArguments``. +: This option is **deprecated**. See `BinPack` of `PackArguments`. -.. _BinPackLongBracedList: +(binpacklongbracedlist)= -**BinPackLongBracedList** (``Boolean``) :versionbadge:`clang-format 21` :ref:`¶ ` - If ``BinPackLongBracedList`` is ``true`` it overrides - ``BinPackArguments`` if there are 20 or more items in a braced +**BinPackLongBracedList** (`Boolean`) {versionbadge}`clang-format 21` {ref}`¶ ` + +: If `BinPackLongBracedList` is `true` it overrides + `BinPackArguments` if there are 20 or more items in a braced initializer list. - .. code-block:: c++ + ```c++ + BinPackLongBracedList: false vs. BinPackLongBracedList: true + vector x{ vector x{1, 2, ..., + 20, 21}; + 1, + 2, + ..., + 20, + 21}; + ``` - BinPackLongBracedList: false vs. BinPackLongBracedList: true - vector x{ vector x{1, 2, ..., - 20, 21}; - 1, - 2, - ..., - 20, - 21}; +(binpackparameters)= -.. _BinPackParameters: +**BinPackParameters** (`BinPackParametersStyle`) {versionbadge}`clang-format 3.7` {ref}`¶ ` -**BinPackParameters** (``BinPackParametersStyle``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - This option is **deprecated**. See ``BinPack`` of ``PackParameters``. +: This option is **deprecated**. See `BinPack` of `PackParameters`. Possible values: - * ``BPPS_BinPack`` (in configuration: ``BinPack``) + - `BPPS_BinPack` (in configuration: `BinPack`) Bin-pack parameters. - .. code-block:: c++ - - void f(int a, int bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, - int ccccccccccccccccccccccccccccccccccccccccccc); + ```c++ + void f(int a, int bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, + int ccccccccccccccccccccccccccccccccccccccccccc); + ``` - * ``BPPS_OnePerLine`` (in configuration: ``OnePerLine``) + - `BPPS_OnePerLine` (in configuration: `OnePerLine`) Put all parameters on the current line if they fit. Otherwise, put each one on its own line. - .. code-block:: c++ + ```c++ + void f(int a, int b, int c); - void f(int a, int b, int c); + void f(int a, + int b, + int ccccccccccccccccccccccccccccccccccccc); + ``` - void f(int a, - int b, - int ccccccccccccccccccccccccccccccccccccc); - - * ``BPPS_AlwaysOnePerLine`` (in configuration: ``AlwaysOnePerLine``) + - `BPPS_AlwaysOnePerLine` (in configuration: `AlwaysOnePerLine`) Always put each parameter on its own line. - .. code-block:: c++ + ```c++ + void f(int a, + int b, + int c); + ``` - void f(int a, - int b, - int c); + - `BPPS_UseBreakAfter` (in configuration: `UseBreakAfter`) + Use the `BreakAfter` option to handle parameter packing instead. + If the `BreakAfter` limit is not exceeded, behave like `BinPack`. - * ``BPPS_UseBreakAfter`` (in configuration: ``UseBreakAfter``) - Use the ``BreakAfter`` option to handle parameter packing instead. - If the ``BreakAfter`` limit is not exceeded, behave like ``BinPack``. +(bitfieldcolonspacing)= -.. _BitFieldColonSpacing: +**BitFieldColonSpacing** (`BitFieldColonSpacingStyle`) {versionbadge}`clang-format 12` {ref}`¶ ` -**BitFieldColonSpacing** (``BitFieldColonSpacingStyle``) :versionbadge:`clang-format 12` :ref:`¶ ` - The BitFieldColonSpacingStyle to use for bitfields. +: The BitFieldColonSpacingStyle to use for bitfields. Possible values: - * ``BFCS_Both`` (in configuration: ``Both``) - Add one space on each side of the ``:`` - - .. code-block:: c++ - - unsigned bf : 2; - - * ``BFCS_None`` (in configuration: ``None``) - Add no space around the ``:`` (except when needed for - ``AlignConsecutiveBitFields``). + - `BFCS_Both` (in configuration: `Both`) + Add one space on each side of the `:` - .. code-block:: c++ + ```c++ + unsigned bf : 2; + ``` - unsigned bf:2; + - `BFCS_None` (in configuration: `None`) + Add no space around the `:` (except when needed for + `AlignConsecutiveBitFields`). - * ``BFCS_Before`` (in configuration: ``Before``) - Add space before the ``:`` only + ```c++ + unsigned bf:2; + ``` - .. code-block:: c++ + - `BFCS_Before` (in configuration: `Before`) + Add space before the `:` only - unsigned bf :2; + ```c++ + unsigned bf :2; + ``` - * ``BFCS_After`` (in configuration: ``After``) - Add space after the ``:`` only (space may be added before if - needed for ``AlignConsecutiveBitFields``). + - `BFCS_After` (in configuration: `After`) + Add space after the `:` only (space may be added before if + needed for `AlignConsecutiveBitFields`). - .. code-block:: c++ + ```c++ + unsigned bf: 2; + ``` - unsigned bf: 2; +(bracewrapping)= -.. _BraceWrapping: +**BraceWrapping** (`BraceWrappingFlags`) {versionbadge}`clang-format 3.8` {ref}`¶ ` -**BraceWrapping** (``BraceWrappingFlags``) :versionbadge:`clang-format 3.8` :ref:`¶ ` - Control of individual brace wrapping cases. +: Control of individual brace wrapping cases. - If ``BreakBeforeBraces`` is set to ``Custom``, use this to specify how + If `BreakBeforeBraces` is set to `Custom`, use this to specify how each individual brace case should be handled. Otherwise, this is ignored. - .. code-block:: yaml - - # Example of usage: - BreakBeforeBraces: Custom - BraceWrapping: - AfterEnum: true - AfterStruct: false - SplitEmptyFunction: false + ```yaml + # Example of usage: + BreakBeforeBraces: Custom + BraceWrapping: + AfterEnum: true + AfterStruct: false + SplitEmptyFunction: false + ``` Nested configuration flags: Precise control over the wrapping of braces. - .. code-block:: c++ + ```yaml + # Should be declared this way: + BreakBeforeBraces: Custom + BraceWrapping: + AfterClass: true + ``` + + - `bool AfterCaseLabel` Wrap case labels. + + ```c++ + false: true: + switch (foo) { vs. switch (foo) { + case 1: { case 1: + bar(); { + break; bar(); + } break; + default: { } + plop(); default: + } { + } plop(); + } + } + ``` - # Should be declared this way: - BreakBeforeBraces: Custom - BraceWrapping: - AfterClass: true + - `bool AfterClass` Wrap class definitions. - * ``bool AfterCaseLabel`` Wrap case labels. + ```c++ + true: + class foo + {}; - .. code-block:: c++ + false: + class foo {}; + ``` - false: true: - switch (foo) { vs. switch (foo) { - case 1: { case 1: - bar(); { - break; bar(); - } break; - default: { } - plop(); default: - } { - } plop(); - } - } + - `BraceWrappingAfterControlStatementStyle AfterControlStatement` + Wrap control statements (`if`/`for`/`while`/`switch`/..). - * ``bool AfterClass`` Wrap class definitions. + Possible values: - .. code-block:: c++ + - `BWACS_Never` (in configuration: `Never`) + Never wrap braces after a control statement. - true: - class foo - {}; - - false: - class foo {}; - - * ``BraceWrappingAfterControlStatementStyle AfterControlStatement`` - Wrap control statements (``if``/``for``/``while``/``switch``/..). - - Possible values: - - * ``BWACS_Never`` (in configuration: ``Never``) - Never wrap braces after a control statement. - - .. code-block:: c++ - - if (foo()) { - } else { - } - for (int i = 0; i < 10; ++i) { - } + ```c++ + if (foo()) { + } else { + } + for (int i = 0; i < 10; ++i) { + } + ``` - * ``BWACS_MultiLine`` (in configuration: ``MultiLine``) + - `BWACS_MultiLine` (in configuration: `MultiLine`) Only wrap braces after a multi-line control statement. - .. code-block:: c++ - - if (foo && bar && - baz) - { - quux(); - } - while (foo || bar) { - } - - * ``BWACS_Always`` (in configuration: ``Always``) - Always wrap braces after a control statement. - - .. code-block:: c++ - - if (foo()) - { - } else - {} - for (int i = 0; i < 10; ++i) - {} - - - * ``bool AfterEnum`` Wrap enum definitions. - - .. code-block:: c++ - - true: - enum X : int - { - B - }; - - false: - enum X : int { B }; - - * ``bool AfterFunction`` Wrap function definitions. - - .. code-block:: c++ - - true: - void foo() + ```c++ + if (foo && bar && + baz) { - bar(); - bar2(); + quux(); } - - false: - void foo() { - bar(); - bar2(); + while (foo || bar) { } + ``` - * ``bool AfterNamespace`` Wrap namespace definitions. - - .. code-block:: c++ + - `BWACS_Always` (in configuration: `Always`) + Always wrap braces after a control statement. - true: - namespace + ```c++ + if (foo()) { - int foo(); - int bar(); - } + } else + {} + for (int i = 0; i < 10; ++i) + {} + ``` - false: - namespace { - int foo(); - int bar(); - } - * ``bool AfterObjCDeclaration`` Wrap ObjC definitions (interfaces, implementations...). + - `bool AfterEnum` Wrap enum definitions. - .. note:: + ```c++ + true: + enum X : int + { + B + }; - @autoreleasepool and @synchronized blocks are wrapped - according to ``AfterControlStatement`` flag. + false: + enum X : int { B }; + ``` - * ``bool AfterStruct`` Wrap struct definitions. + - `bool AfterFunction` Wrap function definitions. - .. code-block:: c++ + ```c++ + true: + void foo() + { + bar(); + bar2(); + } - true: - struct foo - { - int x; - }; + false: + void foo() { + bar(); + bar2(); + } + ``` - false: - struct foo { - int x; - }; + - `bool AfterNamespace` Wrap namespace definitions. - * ``bool AfterUnion`` Wrap union definitions. + ```c++ + true: + namespace + { + int foo(); + int bar(); + } - .. code-block:: c++ + false: + namespace { + int foo(); + int bar(); + } + ``` - true: - union foo - { - int x; - } + - `bool AfterObjCDeclaration` Wrap ObjC definitions (interfaces, implementations...). - false: - union foo { - int x; - } + :::{note} + @autoreleasepool and @synchronized blocks are wrapped + according to `AfterControlStatement` flag. + ::: - * ``bool AfterExternBlock`` Wrap extern blocks. + - `bool AfterStruct` Wrap struct definitions. - .. code-block:: c++ + ```c++ + true: + struct foo + { + int x; + }; - true: - extern "C" - { - int foo(); - } + false: + struct foo { + int x; + }; + ``` - false: - extern "C" { - int foo(); - } + - `bool AfterUnion` Wrap union definitions. - * ``bool BeforeCatch`` Wrap before ``catch``. + ```c++ + true: + union foo + { + int x; + } - .. code-block:: c++ + false: + union foo { + int x; + } + ``` - true: - try { - foo(); - } - catch () { - } + - `bool AfterExternBlock` Wrap extern blocks. - false: - try { - foo(); - } catch () { - } + ```c++ + true: + extern "C" + { + int foo(); + } - * ``bool BeforeElse`` Wrap before ``else``. + false: + extern "C" { + int foo(); + } + ``` - .. code-block:: c++ + - `bool BeforeCatch` Wrap before `catch`. - true: - if (foo()) { - } - else { - } + ```c++ + true: + try { + foo(); + } + catch () { + } - false: - if (foo()) { - } else { - } + false: + try { + foo(); + } catch () { + } + ``` - * ``bool BeforeLambdaBody`` Wrap lambda block. + - `bool BeforeElse` Wrap before `else`. - .. code-block:: c++ + ```c++ + true: + if (foo()) { + } + else { + } - true: - connect( - []() - { - foo(); - bar(); - }); + false: + if (foo()) { + } else { + } + ``` - false: - connect([]() { + - `bool BeforeLambdaBody` Wrap lambda block. + + ```c++ + true: + connect( + []() + { foo(); bar(); }); - * ``bool BeforeWhile`` Wrap before ``while``. + false: + connect([]() { + foo(); + bar(); + }); + ``` - .. code-block:: c++ + - `bool BeforeWhile` Wrap before `while`. - true: - do { - foo(); - } - while (1); + ```c++ + true: + do { + foo(); + } + while (1); - false: - do { - foo(); - } while (1); + false: + do { + foo(); + } while (1); + ``` - * ``bool IndentBraces`` Indent the wrapped braces themselves. + - `bool IndentBraces` Indent the wrapped braces themselves. - * ``bool SplitEmptyFunction`` If ``false``, empty function body can be put on a single line. + - `bool SplitEmptyFunction` If `false`, empty function body can be put on a single line. This option is used only if the opening brace of the function has - already been wrapped, i.e. the ``AfterFunction`` brace wrapping mode is + already been wrapped, i.e. the `AfterFunction` brace wrapping mode is set, and the function could/should not be put on a single line (as per - ``AllowShortFunctionsOnASingleLine`` and constructor formatting + `AllowShortFunctionsOnASingleLine` and constructor formatting options). - .. code-block:: c++ - - false: true: - int f() vs. int f() - {} { - } + ```c++ + false: true: + int f() vs. int f() + {} { + } + ``` - * ``bool SplitEmptyRecord`` If ``false``, empty record (e.g. class, struct or union) body + - `bool SplitEmptyRecord` If `false`, empty record (e.g. class, struct or union) body can be put on a single line. This option is used only if the opening - brace of the record has already been wrapped, i.e. the ``AfterClass`` + brace of the record has already been wrapped, i.e. the `AfterClass` (for classes) brace wrapping mode is set. - .. code-block:: c++ + ```c++ + false: true: + class Foo vs. class Foo + {} { + } + ``` - false: true: - class Foo vs. class Foo - {} { - } - - * ``bool SplitEmptyNamespace`` If ``false``, empty namespace body can be put on a single line. + - `bool SplitEmptyNamespace` If `false`, empty namespace body can be put on a single line. This option is used only if the opening brace of the namespace has - already been wrapped, i.e. the ``AfterNamespace`` brace wrapping mode is + already been wrapped, i.e. the `AfterNamespace` brace wrapping mode is set. - .. code-block:: c++ + ```c++ + false: true: + namespace Foo vs. namespace Foo + {} { + } + ``` - false: true: - namespace Foo vs. namespace Foo - {} { - } +(bracedinitializerindentwidth)= -.. _BracedInitializerIndentWidth: +**BracedInitializerIndentWidth** (`Integer`) {versionbadge}`clang-format 17` {ref}`¶ ` -**BracedInitializerIndentWidth** (``Integer``) :versionbadge:`clang-format 17` :ref:`¶ ` - The number of columns to use to indent the contents of braced init lists. - If unset or negative, ``ContinuationIndentWidth`` is used. +: The number of columns to use to indent the contents of braced init lists. + If unset or negative, `ContinuationIndentWidth` is used. - .. code-block:: c++ + ```c++ + AlignAfterOpenBracket: AlwaysBreak + BracedInitializerIndentWidth: 2 - AlignAfterOpenBracket: AlwaysBreak - BracedInitializerIndentWidth: 2 + void f() { + SomeClass c{ + "foo", + "bar", + "baz", + }; + auto s = SomeStruct{ + .foo = "foo", + .bar = "bar", + .baz = "baz", + }; + SomeArrayT a[3] = { + { + foo, + bar, + }, + { + foo, + bar, + }, + SomeArrayT{}, + }; + } + ``` - void f() { - SomeClass c{ - "foo", - "bar", - "baz", - }; - auto s = SomeStruct{ - .foo = "foo", - .bar = "bar", - .baz = "baz", - }; - SomeArrayT a[3] = { - { - foo, - bar, - }, - { - foo, - bar, - }, - SomeArrayT{}, - }; - } +(breakadjacentstringliterals)= -.. _BreakAdjacentStringLiterals: +**BreakAdjacentStringLiterals** (`Boolean`) {versionbadge}`clang-format 18` {ref}`¶ ` -**BreakAdjacentStringLiterals** (``Boolean``) :versionbadge:`clang-format 18` :ref:`¶ ` - Break between adjacent string literals. +: Break between adjacent string literals. - .. code-block:: c++ + ```c++ + true: + return "Code" + "\0\52\26\55\55\0" + "x013" + "\02\xBA"; + false: + return "Code" "\0\52\26\55\55\0" "x013" "\02\xBA"; + ``` - true: - return "Code" - "\0\52\26\55\55\0" - "x013" - "\02\xBA"; - false: - return "Code" "\0\52\26\55\55\0" "x013" "\02\xBA"; +(breakafterattributes)= -.. _BreakAfterAttributes: +**BreakAfterAttributes** (`AttributeBreakingStyle`) {versionbadge}`clang-format 16` {ref}`¶ ` -**BreakAfterAttributes** (``AttributeBreakingStyle``) :versionbadge:`clang-format 16` :ref:`¶ ` - Break after a group of C++11 attributes before variable or function +: Break after a group of C++11 attributes before variable or function (including constructor/destructor) declaration/definition names or before - control statements, i.e. ``if``, ``switch`` (including ``case`` and - ``default`` labels), ``for``, and ``while`` statements. + control statements, i.e. `if`, `switch` (including `case` and + `default` labels), `for`, and `while` statements. Possible values: - * ``ABS_Always`` (in configuration: ``Always``) + - `ABS_Always` (in configuration: `Always`) Always break after the last attribute of the group. - .. code-block:: c++ - - [[maybe_unused]] - const int i; - [[gnu::const]] [[maybe_unused]] - int j; - - [[nodiscard]] - inline int f(); - [[gnu::const]] [[nodiscard]] - int g(); + ```c++ + [[maybe_unused]] + const int i; + [[gnu::const]] [[maybe_unused]] + int j; - [[likely]] - if (a) - f(); - else - g(); + [[nodiscard]] + inline int f(); + [[gnu::const]] [[nodiscard]] + int g(); - switch (b) { - [[unlikely]] - case 1: - ++b; - break; - [[likely]] - default: - return; - } + [[likely]] + if (a) + f(); + else + g(); + + switch (b) { + [[unlikely]] + case 1: + ++b; + break; + [[likely]] + default: + return; + } + ``` - * ``ABS_Leave`` (in configuration: ``Leave``) + - `ABS_Leave` (in configuration: `Leave`) Leave the line breaking after the last attribute of the group as is. - .. code-block:: c++ - - [[maybe_unused]] const int i; - [[gnu::const]] [[maybe_unused]] - int j; - - [[nodiscard]] inline int f(); - [[gnu::const]] [[nodiscard]] - int g(); + ```c++ + [[maybe_unused]] const int i; + [[gnu::const]] [[maybe_unused]] + int j; - [[likely]] if (a) - f(); - else - g(); - - switch (b) { - [[unlikely]] case 1: - ++b; - break; - [[likely]] - default: - return; - } + [[nodiscard]] inline int f(); + [[gnu::const]] [[nodiscard]] + int g(); - * ``ABS_LeaveAll`` (in configuration: ``LeaveAll``) - Same as ``Leave`` except that it applies to all attributes of the group. + [[likely]] if (a) + f(); + else + g(); + + switch (b) { + [[unlikely]] case 1: + ++b; + break; + [[likely]] + default: + return; + } + ``` - .. code-block:: c++ + - `ABS_LeaveAll` (in configuration: `LeaveAll`) + Same as `Leave` except that it applies to all attributes of the group. - [[deprecated("Don't use this version")]] - [[nodiscard]] - bool foo() { - return true; - } + ```c++ + [[deprecated("Don't use this version")]] + [[nodiscard]] + bool foo() { + return true; + } - [[deprecated("Don't use this version")]] - [[nodiscard]] bool bar() { - return true; - } + [[deprecated("Don't use this version")]] + [[nodiscard]] bool bar() { + return true; + } + ``` - * ``ABS_Never`` (in configuration: ``Never``) + - `ABS_Never` (in configuration: `Never`) Never break after the last attribute of the group. - .. code-block:: c++ + ```c++ + [[maybe_unused]] const int i; + [[gnu::const]] [[maybe_unused]] int j; - [[maybe_unused]] const int i; - [[gnu::const]] [[maybe_unused]] int j; + [[nodiscard]] inline int f(); + [[gnu::const]] [[nodiscard]] int g(); - [[nodiscard]] inline int f(); - [[gnu::const]] [[nodiscard]] int g(); + [[likely]] if (a) + f(); + else + g(); + + switch (b) { + [[unlikely]] case 1: + ++b; + break; + [[likely]] default: + return; + } + ``` - [[likely]] if (a) - f(); - else - g(); - - switch (b) { - [[unlikely]] case 1: - ++b; - break; - [[likely]] default: - return; - } +(breakafterjavafieldannotations)= -.. _BreakAfterJavaFieldAnnotations: +**BreakAfterJavaFieldAnnotations** (`Boolean`) {versionbadge}`clang-format 3.8` {ref}`¶ ` -**BreakAfterJavaFieldAnnotations** (``Boolean``) :versionbadge:`clang-format 3.8` :ref:`¶ ` - Break after each annotation on a field in Java files. +: Break after each annotation on a field in Java files. - .. code-block:: java + ```java + true: false: + @Partial vs. @Partial @Mock DataLoad loader; + @Mock + DataLoad loader; + ``` - true: false: - @Partial vs. @Partial @Mock DataLoad loader; - @Mock - DataLoad loader; +(breakafteropenbracketbracedlist)= -.. _BreakAfterOpenBracketBracedList: +**BreakAfterOpenBracketBracedList** (`Boolean`) {versionbadge}`clang-format 22` {ref}`¶ ` -**BreakAfterOpenBracketBracedList** (``Boolean``) :versionbadge:`clang-format 22` :ref:`¶ ` - Force break after the left bracket of a braced initializer list (when - ``Cpp11BracedListStyle`` is ``true``) when the list exceeds the column +: Force break after the left bracket of a braced initializer list (when + `Cpp11BracedListStyle` is `true`) when the list exceeds the column limit. - .. code-block:: c++ + ```c++ + true: false: + vector x { vs. vector x {1, + 1, 2, 3} 2, 3} + ``` - true: false: - vector x { vs. vector x {1, - 1, 2, 3} 2, 3} +(breakafteropenbracketfunction)= -.. _BreakAfterOpenBracketFunction: +**BreakAfterOpenBracketFunction** (`Boolean`) {versionbadge}`clang-format 22` {ref}`¶ ` -**BreakAfterOpenBracketFunction** (``Boolean``) :versionbadge:`clang-format 22` :ref:`¶ ` - Force break after the left parenthesis of a function (declaration, +: Force break after the left parenthesis of a function (declaration, definition, call) when the parameters exceed the column limit. - .. code-block:: c++ + ```c++ + true: false: + foo ( vs. foo (a, + a , b) b) + ``` - true: false: - foo ( vs. foo (a, - a , b) b) +(breakafteropenbracketif)= -.. _BreakAfterOpenBracketIf: +**BreakAfterOpenBracketIf** (`Boolean`) {versionbadge}`clang-format 22` {ref}`¶ ` -**BreakAfterOpenBracketIf** (``Boolean``) :versionbadge:`clang-format 22` :ref:`¶ ` - Force break after the left parenthesis of an if control statement +: Force break after the left parenthesis of an if control statement when the expression exceeds the column limit. - .. code-block:: c++ + ```c++ + true: false: + if constexpr ( vs. if constexpr (a || + a || b) b) + ``` - true: false: - if constexpr ( vs. if constexpr (a || - a || b) b) +(breakafteropenbracketloop)= -.. _BreakAfterOpenBracketLoop: +**BreakAfterOpenBracketLoop** (`Boolean`) {versionbadge}`clang-format 22` {ref}`¶ ` -**BreakAfterOpenBracketLoop** (``Boolean``) :versionbadge:`clang-format 22` :ref:`¶ ` - Force break after the left parenthesis of a loop control statement +: Force break after the left parenthesis of a loop control statement when the expression exceeds the column limit. - .. code-block:: c++ + ```c++ + true: false: + while ( vs. while (a && + a && b) { b) { + ``` - true: false: - while ( vs. while (a && - a && b) { b) { +(breakafteropenbracketswitch)= -.. _BreakAfterOpenBracketSwitch: +**BreakAfterOpenBracketSwitch** (`Boolean`) {versionbadge}`clang-format 22` {ref}`¶ ` -**BreakAfterOpenBracketSwitch** (``Boolean``) :versionbadge:`clang-format 22` :ref:`¶ ` - Force break after the left parenthesis of a switch control statement +: Force break after the left parenthesis of a switch control statement when the expression exceeds the column limit. - .. code-block:: c++ + ```c++ + true: false: + switch ( vs. switch (a + + a + b) { b) { + ``` - true: false: - switch ( vs. switch (a + - a + b) { b) { +(breakafterreturntype)= -.. _BreakAfterReturnType: +**BreakAfterReturnType** (`ReturnTypeBreakingStyle`) {versionbadge}`clang-format 19` {ref}`¶ ` -**BreakAfterReturnType** (``ReturnTypeBreakingStyle``) :versionbadge:`clang-format 19` :ref:`¶ ` - The function declaration return type breaking style to use. +: The function declaration return type breaking style to use. Possible values: - * ``RTBS_None`` (in configuration: ``None``) - This is **deprecated**. See ``Automatic`` below. + - `RTBS_None` (in configuration: `None`) + This is **deprecated**. See `Automatic` below. - * ``RTBS_Automatic`` (in configuration: ``Automatic``) - Break after return type based on ``PenaltyReturnTypeOnItsOwnLine``. + - `RTBS_Automatic` (in configuration: `Automatic`) + Break after return type based on `PenaltyReturnTypeOnItsOwnLine`. - .. code-block:: c++ - - class A { - int f() { return 0; }; - }; - int f(); - int f() { return 1; } - int - LongName::AnotherLongName(); - - * ``RTBS_ExceptShortType`` (in configuration: ``ExceptShortType``) - Same as ``Automatic`` above, except that there is no break after short + ```c++ + class A { + int f() { return 0; }; + }; + int f(); + int f() { return 1; } + int + LongName::AnotherLongName(); + ``` + + - `RTBS_ExceptShortType` (in configuration: `ExceptShortType`) + Same as `Automatic` above, except that there is no break after short return types. - .. code-block:: c++ - - class A { - int f() { return 0; }; - }; - int f(); - int f() { return 1; } - int LongName:: - AnotherLongName(); + ```c++ + class A { + int f() { return 0; }; + }; + int f(); + int f() { return 1; } + int LongName:: + AnotherLongName(); + ``` - * ``RTBS_All`` (in configuration: ``All``) + - `RTBS_All` (in configuration: `All`) Always break after the return type. - .. code-block:: c++ - - class A { - int - f() { - return 0; - }; - }; - int - f(); + ```c++ + class A { int f() { - return 1; - } - int - LongName::AnotherLongName(); + return 0; + }; + }; + int + f(); + int + f() { + return 1; + } + int + LongName::AnotherLongName(); + ``` - * ``RTBS_TopLevel`` (in configuration: ``TopLevel``) + - `RTBS_TopLevel` (in configuration: `TopLevel`) Always break after the return types of top-level functions. - .. code-block:: c++ - - class A { - int f() { return 0; }; - }; - int - f(); - int - f() { - return 1; - } - int - LongName::AnotherLongName(); + ```c++ + class A { + int f() { return 0; }; + }; + int + f(); + int + f() { + return 1; + } + int + LongName::AnotherLongName(); + ``` - * ``RTBS_AllDefinitions`` (in configuration: ``AllDefinitions``) + - `RTBS_AllDefinitions` (in configuration: `AllDefinitions`) Always break after the return type of function definitions. - .. code-block:: c++ - - class A { - int - f() { - return 0; - }; - }; - int f(); + ```c++ + class A { int f() { - return 1; - } - int - LongName::AnotherLongName(); + return 0; + }; + }; + int f(); + int + f() { + return 1; + } + int + LongName::AnotherLongName(); + ``` - * ``RTBS_TopLevelDefinitions`` (in configuration: ``TopLevelDefinitions``) + - `RTBS_TopLevelDefinitions` (in configuration: `TopLevelDefinitions`) Always break after the return type of top-level definitions. - .. code-block:: c++ + ```c++ + class A { + int f() { return 0; }; + }; + int f(); + int + f() { + return 1; + } + int + LongName::AnotherLongName(); + ``` - class A { - int f() { return 0; }; - }; - int f(); - int - f() { - return 1; - } - int - LongName::AnotherLongName(); +(breakarrays)= -.. _BreakArrays: +**BreakArrays** (`Boolean`) {versionbadge}`clang-format 16` {ref}`¶ ` -**BreakArrays** (``Boolean``) :versionbadge:`clang-format 16` :ref:`¶ ` - If ``true``, clang-format will always break after a Json array ``[`` - otherwise it will scan until the closing ``]`` to determine if it should +: If `true`, clang-format will always break after a Json array `[` + otherwise it will scan until the closing `]` to determine if it should add newlines between elements (prettier compatible). + :::{note} + This is currently only for formatting JSON. + ::: - .. note:: - - This is currently only for formatting JSON. + ```c++ + true: false: + [ vs. [1, 2, 3, 4] + 1, + 2, + 3, + 4 + ] + ``` - .. code-block:: c++ +(breakbeforebinaryoperators)= - true: false: - [ vs. [1, 2, 3, 4] - 1, - 2, - 3, - 4 - ] +**BreakBeforeBinaryOperators** (`BinaryOperatorStyle`) {versionbadge}`clang-format 3.6` {ref}`¶ ` -.. _BreakBeforeBinaryOperators: - -**BreakBeforeBinaryOperators** (``BinaryOperatorStyle``) :versionbadge:`clang-format 3.6` :ref:`¶ ` - The way to wrap binary operators. +: The way to wrap binary operators. Possible values: - * ``BOS_None`` (in configuration: ``None``) + - `BOS_None` (in configuration: `None`) Break after operators. - .. code-block:: c++ - - LooooooooooongType loooooooooooooooooooooongVariable = - someLooooooooooooooooongFunction(); + ```c++ + LooooooooooongType loooooooooooooooooooooongVariable = + someLooooooooooooooooongFunction(); - bool value = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa == - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa && - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa > - ccccccccccccccccccccccccccccccccccccccccc; + bool value = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa == + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa && + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa > + ccccccccccccccccccccccccccccccccccccccccc; + ``` - * ``BOS_NonAssignment`` (in configuration: ``NonAssignment``) + - `BOS_NonAssignment` (in configuration: `NonAssignment`) Break before operators that aren't assignments. - .. code-block:: c++ - - LooooooooooongType loooooooooooooooooooooongVariable = - someLooooooooooooooooongFunction(); + ```c++ + LooooooooooongType loooooooooooooooooooooongVariable = + someLooooooooooooooooongFunction(); - bool value = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - == aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - && aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - > ccccccccccccccccccccccccccccccccccccccccc; + bool value = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + == aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + && aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + > ccccccccccccccccccccccccccccccccccccccccc; + ``` - * ``BOS_All`` (in configuration: ``All``) + - `BOS_All` (in configuration: `All`) Break before operators. - .. code-block:: c++ + ```c++ + LooooooooooongType loooooooooooooooooooooongVariable + = someLooooooooooooooooongFunction(); - LooooooooooongType loooooooooooooooooooooongVariable - = someLooooooooooooooooongFunction(); + bool value = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + == aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + && aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + > ccccccccccccccccccccccccccccccccccccccccc; + ``` - bool value = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - == aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - && aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - > ccccccccccccccccccccccccccccccccccccccccc; +(breakbeforebraces)= -.. _BreakBeforeBraces: +**BreakBeforeBraces** (`BraceBreakingStyle`) {versionbadge}`clang-format 3.7` {ref}`¶ ` -**BreakBeforeBraces** (``BraceBreakingStyle``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - The brace breaking style to use. +: The brace breaking style to use. Possible values: - * ``BS_Attach`` (in configuration: ``Attach``) + - `BS_Attach` (in configuration: `Attach`) Always attach braces to surrounding context. - .. code-block:: c++ - - namespace N { - enum E { - E1, - E2, - }; + ```c++ + namespace N { + enum E { + E1, + E2, + }; - class C { - public: - C(); - }; + class C { + public: + C(); + }; - bool baz(int i) { - try { - do { - switch (i) { - case 1: { - foobar(); - break; - } - default: { - break; - } - } - } while (--i); - return true; - } catch (...) { - handleError(); - return false; - } + bool baz(int i) { + try { + do { + switch (i) { + case 1: { + foobar(); + break; + } + default: { + break; + } + } + } while (--i); + return true; + } catch (...) { + handleError(); + return false; } + } - void foo(bool b) { - if (b) { - baz(2); - } else { - baz(5); - } + void foo(bool b) { + if (b) { + baz(2); + } else { + baz(5); } + } - void bar() { foo(true); } - } // namespace N + void bar() { foo(true); } + } // namespace N + ``` - * ``BS_Linux`` (in configuration: ``Linux``) - Like ``Attach``, but break before braces on function, namespace and + - `BS_Linux` (in configuration: `Linux`) + Like `Attach`, but break before braces on function, namespace and class definitions. - .. code-block:: c++ - - namespace N - { - enum E { - E1, - E2, - }; + ```c++ + namespace N + { + enum E { + E1, + E2, + }; - class C - { - public: - C(); - }; + class C + { + public: + C(); + }; - bool baz(int i) - { - try { - do { - switch (i) { - case 1: { - foobar(); - break; - } - default: { - break; - } - } - } while (--i); - return true; - } catch (...) { - handleError(); - return false; - } + bool baz(int i) + { + try { + do { + switch (i) { + case 1: { + foobar(); + break; + } + default: { + break; + } + } + } while (--i); + return true; + } catch (...) { + handleError(); + return false; } + } - void foo(bool b) - { - if (b) { - baz(2); - } else { - baz(5); - } + void foo(bool b) + { + if (b) { + baz(2); + } else { + baz(5); } + } - void bar() { foo(true); } - } // namespace N + void bar() { foo(true); } + } // namespace N + ``` - * ``BS_Mozilla`` (in configuration: ``Mozilla``) - Like ``Attach``, but break before braces on enum, function, and record + - `BS_Mozilla` (in configuration: `Mozilla`) + Like `Attach`, but break before braces on enum, function, and record definitions. - .. code-block:: c++ + ```c++ + namespace N { + enum E + { + E1, + E2, + }; - namespace N { - enum E - { - E1, - E2, - }; + class C + { + public: + C(); + }; - class C - { - public: - C(); - }; + bool baz(int i) + { + try { + do { + switch (i) { + case 1: { + foobar(); + break; + } + default: { + break; + } + } + } while (--i); + return true; + } catch (...) { + handleError(); + return false; + } + } - bool baz(int i) - { - try { - do { - switch (i) { - case 1: { - foobar(); - break; - } - default: { - break; - } - } - } while (--i); - return true; - } catch (...) { - handleError(); - return false; - } + void foo(bool b) + { + if (b) { + baz(2); + } else { + baz(5); } + } - void foo(bool b) - { - if (b) { - baz(2); - } else { - baz(5); - } + void bar() { foo(true); } + } // namespace N + ``` + + - `BS_Stroustrup` (in configuration: `Stroustrup`) + Like `Attach`, but break before function definitions, `catch`, and + `else`. + + ```c++ + namespace N { + enum E { + E1, + E2, + }; + + class C { + public: + C(); + }; + + bool baz(int i) + { + try { + do { + switch (i) { + case 1: { + foobar(); + break; + } + default: { + break; + } + } + } while (--i); + return true; + } + catch (...) { + handleError(); + return false; } + } - void bar() { foo(true); } - } // namespace N + void foo(bool b) + { + if (b) { + baz(2); + } + else { + baz(5); + } + } - * ``BS_Stroustrup`` (in configuration: ``Stroustrup``) - Like ``Attach``, but break before function definitions, ``catch``, and - ``else``. + void bar() { foo(true); } + } // namespace N + ``` - .. code-block:: c++ + - `BS_Allman` (in configuration: `Allman`) + Always break before braces. - namespace N { - enum E { - E1, - E2, - }; + ```c++ + namespace N + { + enum E + { + E1, + E2, + }; - class C { - public: - C(); - }; + class C + { + public: + C(); + }; - bool baz(int i) + bool baz(int i) + { + try { - try { - do { - switch (i) { - case 1: { - foobar(); - break; - } - default: { - break; - } - } - } while (--i); - return true; - } - catch (...) { - handleError(); - return false; - } + do + { + switch (i) + { + case 1: + { + foobar(); + break; + } + default: + { + break; + } + } + } while (--i); + return true; } - - void foo(bool b) + catch (...) { - if (b) { - baz(2); - } - else { - baz(5); - } + handleError(); + return false; } + } - void bar() { foo(true); } - } // namespace N + void foo(bool b) + { + if (b) + { + baz(2); + } + else + { + baz(5); + } + } - * ``BS_Allman`` (in configuration: ``Allman``) - Always break before braces. + void bar() { foo(true); } + } // namespace N + ``` - .. code-block:: c++ + - `BS_Whitesmiths` (in configuration: `Whitesmiths`) + Like `Allman` but always indent braces and line up code with braces. - namespace N + ```c++ + namespace N { - enum E + enum E { - E1, - E2, + E1, + E2, }; - class C + class C { - public: - C(); + public: + C(); }; - bool baz(int i) + bool baz(int i) { - try + try { - do + do { - switch (i) + switch (i) { case 1: { - foobar(); - break; + foobar(); + break; } default: { - break; + break; } } } while (--i); - return true; + return true; } - catch (...) + catch (...) { - handleError(); - return false; + handleError(); + return false; } } - void foo(bool b) + void foo(bool b) { - if (b) + if (b) { - baz(2); + baz(2); } - else + else { - baz(5); + baz(5); } } - void bar() { foo(true); } + void bar() { foo(true); } } // namespace N + ``` - * ``BS_Whitesmiths`` (in configuration: ``Whitesmiths``) - Like ``Allman`` but always indent braces and line up code with braces. - - .. code-block:: c++ - - namespace N - { - enum E - { - E1, - E2, - }; - - class C - { - public: - C(); - }; - - bool baz(int i) - { - try - { - do - { - switch (i) - { - case 1: - { - foobar(); - break; - } - default: - { - break; - } - } - } while (--i); - return true; - } - catch (...) - { - handleError(); - return false; - } - } - - void foo(bool b) - { - if (b) - { - baz(2); - } - else - { - baz(5); - } - } - - void bar() { foo(true); } - } // namespace N - - * ``BS_GNU`` (in configuration: ``GNU``) + - `BS_GNU` (in configuration: `GNU`) Always break before braces and add an extra level of indentation to braces of control statements, not to those of class, function or other definitions. - .. code-block:: c++ - - namespace N - { - enum E - { - E1, - E2, - }; - - class C - { - public: - C(); - }; - - bool baz(int i) - { - try - { - do - { - switch (i) - { - case 1: - { - foobar(); - break; - } - default: - { - break; - } - } - } - while (--i); - return true; - } - catch (...) - { - handleError(); - return false; - } - } - - void foo(bool b) - { - if (b) - { - baz(2); - } - else - { - baz(5); - } - } - - void bar() { foo(true); } - } // namespace N - - * ``BS_WebKit`` (in configuration: ``WebKit``) - Like ``Attach``, but break before functions. - - .. code-block:: c++ - - namespace N { - enum E { - E1, - E2, - }; + ```c++ + namespace N + { + enum E + { + E1, + E2, + }; - class C { - public: - C(); - }; + class C + { + public: + C(); + }; - bool baz(int i) - { - try { - do { - switch (i) { - case 1: { - foobar(); - break; - } - default: { - break; - } + bool baz(int i) + { + try + { + do + { + switch (i) + { + case 1: + { + foobar(); + break; + } + default: + { + break; + } + } } - } while (--i); + while (--i); return true; - } catch (...) { + } + catch (...) + { handleError(); return false; } - } + } - void foo(bool b) - { - if (b) { + void foo(bool b) + { + if (b) + { baz(2); - } else { + } + else + { baz(5); } + } + + void bar() { foo(true); } + } // namespace N + ``` + + - `BS_WebKit` (in configuration: `WebKit`) + Like `Attach`, but break before functions. + + ```c++ + namespace N { + enum E { + E1, + E2, + }; + + class C { + public: + C(); + }; + + bool baz(int i) + { + try { + do { + switch (i) { + case 1: { + foobar(); + break; + } + default: { + break; + } + } + } while (--i); + return true; + } catch (...) { + handleError(); + return false; } + } - void bar() { foo(true); } - } // namespace N + void foo(bool b) + { + if (b) { + baz(2); + } else { + baz(5); + } + } + + void bar() { foo(true); } + } // namespace N + ``` - * ``BS_Custom`` (in configuration: ``Custom``) - Configure each individual brace in ``BraceWrapping``. + - `BS_Custom` (in configuration: `Custom`) + Configure each individual brace in `BraceWrapping`. -.. _BreakBeforeCloseBracketBracedList: +(breakbeforeclosebracketbracedlist)= -**BreakBeforeCloseBracketBracedList** (``Boolean``) :versionbadge:`clang-format 22` :ref:`¶ ` - Force break before the right bracket of a braced initializer list (when - ``Cpp11BracedListStyle`` is ``true``) when the list exceeds the column +**BreakBeforeCloseBracketBracedList** (`Boolean`) {versionbadge}`clang-format 22` {ref}`¶ ` + +: Force break before the right bracket of a braced initializer list (when + `Cpp11BracedListStyle` is `true`) when the list exceeds the column limit. The break before the right bracket is only made if there is a break after the opening bracket. - .. code-block:: c++ + ```c++ + true: false: + vector x { vs. vector x { + 1, 2, 3 1, 2, 3} + } + ``` - true: false: - vector x { vs. vector x { - 1, 2, 3 1, 2, 3} - } +(breakbeforeclosebracketfunction)= -.. _BreakBeforeCloseBracketFunction: +**BreakBeforeCloseBracketFunction** (`Boolean`) {versionbadge}`clang-format 22` {ref}`¶ ` -**BreakBeforeCloseBracketFunction** (``Boolean``) :versionbadge:`clang-format 22` :ref:`¶ ` - Force break before the right parenthesis of a function (declaration, +: Force break before the right parenthesis of a function (declaration, definition, call) when the parameters exceed the column limit. - .. code-block:: c++ + ```c++ + true: false: + foo ( vs. foo ( + a , b a , b) + ) + ``` - true: false: - foo ( vs. foo ( - a , b a , b) - ) +(breakbeforeclosebracketif)= -.. _BreakBeforeCloseBracketIf: +**BreakBeforeCloseBracketIf** (`Boolean`) {versionbadge}`clang-format 22` {ref}`¶ ` -**BreakBeforeCloseBracketIf** (``Boolean``) :versionbadge:`clang-format 22` :ref:`¶ ` - Force break before the right parenthesis of an if control statement +: Force break before the right parenthesis of an if control statement when the expression exceeds the column limit. The break before the closing parenthesis is only made if there is a break after the opening parenthesis. - .. code-block:: c++ + ```c++ + true: false: + if constexpr ( vs. if constexpr ( + a || b a || b ) + ) + ``` - true: false: - if constexpr ( vs. if constexpr ( - a || b a || b ) - ) +(breakbeforeclosebracketloop)= -.. _BreakBeforeCloseBracketLoop: +**BreakBeforeCloseBracketLoop** (`Boolean`) {versionbadge}`clang-format 22` {ref}`¶ ` -**BreakBeforeCloseBracketLoop** (``Boolean``) :versionbadge:`clang-format 22` :ref:`¶ ` - Force break before the right parenthesis of a loop control statement +: Force break before the right parenthesis of a loop control statement when the expression exceeds the column limit. The break before the closing parenthesis is only made if there is a break after the opening parenthesis. - .. code-block:: c++ + ```c++ + true: false: + while ( vs. while ( + a && b a && b) { + ) { + ``` - true: false: - while ( vs. while ( - a && b a && b) { - ) { +(breakbeforeclosebracketswitch)= -.. _BreakBeforeCloseBracketSwitch: +**BreakBeforeCloseBracketSwitch** (`Boolean`) {versionbadge}`clang-format 22` {ref}`¶ ` -**BreakBeforeCloseBracketSwitch** (``Boolean``) :versionbadge:`clang-format 22` :ref:`¶ ` - Force break before the right parenthesis of a switch control statement +: Force break before the right parenthesis of a switch control statement when the expression exceeds the column limit. The break before the closing parenthesis is only made if there is a break after the opening parenthesis. - .. code-block:: c++ + ```c++ + true: false: + switch ( vs. switch ( + a + b a + b) { + ) { + ``` - true: false: - switch ( vs. switch ( - a + b a + b) { - ) { +(breakbeforeconceptdeclarations)= -.. _BreakBeforeConceptDeclarations: +**BreakBeforeConceptDeclarations** (`BreakBeforeConceptDeclarationsStyle`) {versionbadge}`clang-format 12` {ref}`¶ ` -**BreakBeforeConceptDeclarations** (``BreakBeforeConceptDeclarationsStyle``) :versionbadge:`clang-format 12` :ref:`¶ ` - The concept declaration style to use. +: The concept declaration style to use. Possible values: - * ``BBCDS_Never`` (in configuration: ``Never``) - Keep the template declaration line together with ``concept``. - - .. code-block:: c++ + - `BBCDS_Never` (in configuration: `Never`) + Keep the template declaration line together with `concept`. - template concept C = ...; + ```c++ + template concept C = ...; + ``` - * ``BBCDS_Allowed`` (in configuration: ``Allowed``) - Breaking between template declaration and ``concept`` is allowed. The + - `BBCDS_Allowed` (in configuration: `Allowed`) + Breaking between template declaration and `concept` is allowed. The actual behavior depends on the content and line breaking rules and penalties. - * ``BBCDS_Always`` (in configuration: ``Always``) - Always break before ``concept``, putting it in the line after the + - `BBCDS_Always` (in configuration: `Always`) + Always break before `concept`, putting it in the line after the template declaration. - .. code-block:: c++ + ```c++ + template + concept C = ...; + ``` - template - concept C = ...; +(breakbeforeinlineasmcolon)= -.. _BreakBeforeInlineASMColon: +**BreakBeforeInlineASMColon** (`BreakBeforeInlineASMColonStyle`) {versionbadge}`clang-format 16` {ref}`¶ ` -**BreakBeforeInlineASMColon** (``BreakBeforeInlineASMColonStyle``) :versionbadge:`clang-format 16` :ref:`¶ ` - The inline ASM colon style to use. +: The inline ASM colon style to use. Possible values: - * ``BBIAS_Never`` (in configuration: ``Never``) + - `BBIAS_Never` (in configuration: `Never`) No break before inline ASM colon. - .. code-block:: c++ - - asm volatile("string", : : val); + ```c++ + asm volatile("string", : : val); + ``` - * ``BBIAS_OnlyMultiline`` (in configuration: ``OnlyMultiline``) + - `BBIAS_OnlyMultiline` (in configuration: `OnlyMultiline`) Break before inline ASM colon if the line length is longer than column limit. - .. code-block:: c++ + ```c++ + asm volatile("string", : : val); + asm("cmoveq %1, %2, %[result]" + : [result] "=r"(result) + : "r"(test), "r"(new), "[result]"(old)); + ``` - asm volatile("string", : : val); - asm("cmoveq %1, %2, %[result]" - : [result] "=r"(result) - : "r"(test), "r"(new), "[result]"(old)); - - * ``BBIAS_Always`` (in configuration: ``Always``) + - `BBIAS_Always` (in configuration: `Always`) Always break before inline ASM colon. - .. code-block:: c++ + ```c++ + asm volatile("string", + : + : val); + ``` - asm volatile("string", - : - : val); +(breakbeforereturntype)= -.. _BreakBeforeReturnType: +**BreakBeforeReturnType** (`BreakBeforeReturnTypeStyle`) {versionbadge}`clang-format 23` {ref}`¶ ` -**BreakBeforeReturnType** (``BreakBeforeReturnTypeStyle``) :versionbadge:`clang-format 23` :ref:`¶ ` - The function declaration/definition return type breaking style to use. - Trailing return types (``auto f() -> T``) are not affected. To have - identifier macros (e.g. ``__always_inline``) treated as specifiers, - add them to ``AttributeMacros``. +: The function declaration/definition return type breaking style to use. + Trailing return types (`auto f() -> T`) are not affected. To have + identifier macros (e.g. `__always_inline`) treated as specifiers, + add them to `AttributeMacros`. Possible values: - * ``BBRTS_None`` (in configuration: ``None``) + - `BBRTS_None` (in configuration: `None`) Do not force a break before the return type. - * ``BBRTS_All`` (in configuration: ``All``) + - `BBRTS_All` (in configuration: `All`) Always break before the return type. - .. code-block:: c++ - - static inline - void f(); + ```c++ + static inline + void f(); + ``` - * ``BBRTS_TopLevel`` (in configuration: ``TopLevel``) + - `BBRTS_TopLevel` (in configuration: `TopLevel`) Break before the return type of top-level functions only. - * ``BBRTS_AllDefinitions`` (in configuration: ``AllDefinitions``) + - `BBRTS_AllDefinitions` (in configuration: `AllDefinitions`) Break before the return type of function definitions only. - * ``BBRTS_TopLevelDefinitions`` (in configuration: ``TopLevelDefinitions``) + - `BBRTS_TopLevelDefinitions` (in configuration: `TopLevelDefinitions`) Break before the return type of top-level definitions only. -.. _BreakBeforeTemplateCloser: +(breakbeforetemplatecloser)= -**BreakBeforeTemplateCloser** (``Boolean``) :versionbadge:`clang-format 21` :ref:`¶ ` - If ``true``, break before a template closing bracket (``>``) when there is - a line break after the matching opening bracket (``<``). +**BreakBeforeTemplateCloser** (`Boolean`) {versionbadge}`clang-format 21` {ref}`¶ ` - .. code-block:: c++ +: If `true`, break before a template closing bracket (`>`) when there is + a line break after the matching opening bracket (`<`). - true: - template + ```c++ + true: + template - template + template - template < - typename Foo, - typename Bar - > + template < + typename Foo, + typename Bar + > - false: - template + false: + template - template + template - template < - typename Foo, - typename Bar> + template < + typename Foo, + typename Bar> + ``` -.. _BreakBeforeTernaryOperators: +(breakbeforeternaryoperators)= -**BreakBeforeTernaryOperators** (``Boolean``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - If ``true``, ternary operators will be placed after line breaks. +**BreakBeforeTernaryOperators** (`Boolean`) {versionbadge}`clang-format 3.7` {ref}`¶ ` - .. code-block:: c++ +: If `true`, ternary operators will be placed after line breaks. - true: - veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongDescription - ? firstValue - : SecondValueVeryVeryVeryVeryLong; + ```c++ + true: + veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongDescription + ? firstValue + : SecondValueVeryVeryVeryVeryLong; - false: - veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongDescription ? - firstValue : - SecondValueVeryVeryVeryVeryLong; + false: + veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongDescription ? + firstValue : + SecondValueVeryVeryVeryVeryLong; + ``` -.. _BreakBinaryOperations: +(breakbinaryoperations)= -**BreakBinaryOperations** (``BreakBinaryOperationsOptions``) :versionbadge:`clang-format 20` :ref:`¶ ` - The break binary operations style to use. +**BreakBinaryOperations** (`BreakBinaryOperationsOptions`) {versionbadge}`clang-format 20` {ref}`¶ ` + +: The break binary operations style to use. Nested configuration flags: - Options for ``BreakBinaryOperations``. + Options for `BreakBinaryOperations`. - If specified as a simple string (e.g. ``OnePerLine``), it behaves like + If specified as a simple string (e.g. `OnePerLine`), it behaves like the original enum and applies to all binary operators. If specified as a struct, allows per-operator configuration: - .. code-block:: yaml - - BreakBinaryOperations: - Default: Never - PerOperator: - - Operators: ['&&', '||'] - Style: OnePerLine - MinChainLength: 3 + ```yaml + BreakBinaryOperations: + Default: Never + PerOperator: + - Operators: ['&&', '||'] + Style: OnePerLine + MinChainLength: 3 + ``` - * ``BreakBinaryOperationsStyle Default`` :versionbadge:`clang-format 23` + - `BreakBinaryOperationsStyle Default` {versionbadge}`clang-format 23` - The default break style for operators not covered by ``PerOperator``. + The default break style for operators not covered by `PerOperator`. Possible values: - * ``BBO_Never`` (in configuration: ``Never``) + - `BBO_Never` (in configuration: `Never`) Don't break binary operations - .. code-block:: c++ + ```c++ + aaa + bbbb * ccccc - ddddd + + eeeeeeeeeeeeeeee; + ``` - aaa + bbbb * ccccc - ddddd + - eeeeeeeeeeeeeeee; - - * ``BBO_OnePerLine`` (in configuration: ``OnePerLine``) + - `BBO_OnePerLine` (in configuration: `OnePerLine`) Binary operations will either be all on the same line, or each operation will have one line each. - .. code-block:: c++ - - aaa + - bbbb * - ccccc - - ddddd + - eeeeeeeeeeeeeeee; + ```c++ + aaa + + bbbb * + ccccc - + ddddd + + eeeeeeeeeeeeeeee; + ``` - * ``BBO_RespectPrecedence`` (in configuration: ``RespectPrecedence``) + - `BBO_RespectPrecedence` (in configuration: `RespectPrecedence`) Binary operations of a particular precedence that exceed the column limit will have one line each. - .. code-block:: c++ + ```c++ + aaa + + bbbb * ccccc - + ddddd + + eeeeeeeeeeeeeeee; + ``` - aaa + - bbbb * ccccc - - ddddd + - eeeeeeeeeeeeeeee; + - `List of BinaryOperationBreakRules PerOperator` Per-operator override rules. - * ``List of BinaryOperationBreakRules PerOperator`` Per-operator override rules. + - `List of Strings Operators` {versionbadge}`clang-format 23` The list of operators this rule applies to, e.g. `&&`, `||`, `|`. + Alternative spellings (e.g. `and` for `&&`) are accepted. - * ``List of Strings Operators`` :versionbadge:`clang-format 23` The list of operators this rule applies to, e.g. ``&&``, ``||``, ``|``. - Alternative spellings (e.g. ``and`` for ``&&``) are accepted. - - * ``BreakBinaryOperationsStyle Style`` - The break style for these operators (defaults to ``OnePerLine``). + - `BreakBinaryOperationsStyle Style` + The break style for these operators (defaults to `OnePerLine`). Possible values: - * ``BBO_Never`` (in configuration: ``Never``) + - `BBO_Never` (in configuration: `Never`) Don't break binary operations - .. code-block:: c++ - - aaa + bbbb * ccccc - ddddd + - eeeeeeeeeeeeeeee; + ```c++ + aaa + bbbb * ccccc - ddddd + + eeeeeeeeeeeeeeee; + ``` - * ``BBO_OnePerLine`` (in configuration: ``OnePerLine``) + - `BBO_OnePerLine` (in configuration: `OnePerLine`) Binary operations will either be all on the same line, or each operation will have one line each. - .. code-block:: c++ + ```c++ + aaa + + bbbb * + ccccc - + ddddd + + eeeeeeeeeeeeeeee; + ``` - aaa + - bbbb * - ccccc - - ddddd + - eeeeeeeeeeeeeeee; - - * ``BBO_RespectPrecedence`` (in configuration: ``RespectPrecedence``) + - `BBO_RespectPrecedence` (in configuration: `RespectPrecedence`) Binary operations of a particular precedence that exceed the column limit will have one line each. - .. code-block:: c++ + ```c++ + aaa + + bbbb * ccccc - + ddddd + + eeeeeeeeeeeeeeee; + ``` - aaa + - bbbb * ccccc - - ddddd + - eeeeeeeeeeeeeeee; + - `unsigned MinChainLength` Minimum number of operands in a chain before the rule triggers. + For example, `a && b && c` is a chain of length 3. + `0` means always break (when the line is too long). - * ``unsigned MinChainLength`` Minimum number of operands in a chain before the rule triggers. - For example, ``a && b && c`` is a chain of length 3. - ``0`` means always break (when the line is too long). +(breakconstructorinitializers)= -.. _BreakConstructorInitializers: +**BreakConstructorInitializers** (`BreakConstructorInitializersStyle`) {versionbadge}`clang-format 5` {ref}`¶ ` -**BreakConstructorInitializers** (``BreakConstructorInitializersStyle``) :versionbadge:`clang-format 5` :ref:`¶ ` - The break constructor initializers style to use. +: The break constructor initializers style to use. Possible values: - * ``BCIS_BeforeColon`` (in configuration: ``BeforeColon``) + - `BCIS_BeforeColon` (in configuration: `BeforeColon`) Break constructor initializers before the colon and after the commas. - .. code-block:: c++ - - Constructor() - : initializer1(), - initializer2() + ```c++ + Constructor() + : initializer1(), + initializer2() + ``` - * ``BCIS_BeforeComma`` (in configuration: ``BeforeComma``) + - `BCIS_BeforeComma` (in configuration: `BeforeComma`) Break constructor initializers before the colon and commas, and align the commas with the colon. - .. code-block:: c++ + ```c++ + Constructor() + : initializer1() + , initializer2() + ``` - Constructor() - : initializer1() - , initializer2() - - * ``BCIS_AfterColon`` (in configuration: ``AfterColon``) + - `BCIS_AfterColon` (in configuration: `AfterColon`) Break constructor initializers after the colon and commas. - .. code-block:: c++ - - Constructor() : - initializer1(), - initializer2() + ```c++ + Constructor() : + initializer1(), + initializer2() + ``` - * ``BCIS_AfterComma`` (in configuration: ``AfterComma``) + - `BCIS_AfterComma` (in configuration: `AfterComma`) Break constructor initializers only after the commas. - .. code-block:: c++ + ```c++ + Constructor() : initializer1(), + initializer2() + ``` - Constructor() : initializer1(), - initializer2() +(breakfunctiondeclarationparameters)= -.. _BreakFunctionDeclarationParameters: +**BreakFunctionDeclarationParameters** (`Boolean`) {versionbadge}`clang-format 23` {ref}`¶ ` -**BreakFunctionDeclarationParameters** (``Boolean``) :versionbadge:`clang-format 23` :ref:`¶ ` - If ``true``, clang-format will always break before function declaration +: If `true`, clang-format will always break before function declaration parameters. - .. code-block:: c++ + ```c++ + true: + void functionDeclaration( + int A, int B); - true: - void functionDeclaration( - int A, int B); + false: + void functionDeclaration(int A, int B); - false: - void functionDeclaration(int A, int B); + ``` + +(breakfunctiondefinitionparameters)= -.. _BreakFunctionDefinitionParameters: +**BreakFunctionDefinitionParameters** (`Boolean`) {versionbadge}`clang-format 19` {ref}`¶ ` -**BreakFunctionDefinitionParameters** (``Boolean``) :versionbadge:`clang-format 19` :ref:`¶ ` - If ``true``, clang-format will always break before function definition +: If `true`, clang-format will always break before function definition parameters. - .. code-block:: c++ + ```c++ + true: + void functionDefinition( + int A, int B) {} - true: - void functionDefinition( - int A, int B) {} + false: + void functionDefinition(int A, int B) {} - false: - void functionDefinition(int A, int B) {} + ``` + +(breakinheritancelist)= -.. _BreakInheritanceList: +**BreakInheritanceList** (`BreakInheritanceListStyle`) {versionbadge}`clang-format 7` {ref}`¶ ` -**BreakInheritanceList** (``BreakInheritanceListStyle``) :versionbadge:`clang-format 7` :ref:`¶ ` - The inheritance list style to use. +: The inheritance list style to use. Possible values: - * ``BILS_BeforeColon`` (in configuration: ``BeforeColon``) + - `BILS_BeforeColon` (in configuration: `BeforeColon`) Break inheritance list before the colon and after the commas. - .. code-block:: c++ + ```c++ + class Foo + : Base1, + Base2 + {}; + ``` - class Foo - : Base1, - Base2 - {}; - - * ``BILS_BeforeComma`` (in configuration: ``BeforeComma``) + - `BILS_BeforeComma` (in configuration: `BeforeComma`) Break inheritance list before the colon and commas, and align the commas with the colon. - .. code-block:: c++ - - class Foo - : Base1 - , Base2 - {}; + ```c++ + class Foo + : Base1 + , Base2 + {}; + ``` - * ``BILS_AfterColon`` (in configuration: ``AfterColon``) + - `BILS_AfterColon` (in configuration: `AfterColon`) Break inheritance list after the colon and commas. - .. code-block:: c++ + ```c++ + class Foo : + Base1, + Base2 + {}; + ``` - class Foo : - Base1, - Base2 - {}; - - * ``BILS_AfterComma`` (in configuration: ``AfterComma``) + - `BILS_AfterComma` (in configuration: `AfterComma`) Break inheritance list only after the commas. - .. code-block:: c++ + ```c++ + class Foo : Base1, + Base2 + {}; + ``` - class Foo : Base1, - Base2 - {}; +(breakstringliterals)= -.. _BreakStringLiterals: +**BreakStringLiterals** (`Boolean`) {versionbadge}`clang-format 3.9` {ref}`¶ ` -**BreakStringLiterals** (``Boolean``) :versionbadge:`clang-format 3.9` :ref:`¶ ` - Allow breaking string literals when formatting. +: Allow breaking string literals when formatting. In C, C++, and Objective-C: - .. code-block:: c++ - - true: - const char* x = "veryVeryVeryVeryVeryVe" - "ryVeryVeryVeryVeryVery" - "VeryLongString"; + ```c++ + true: + const char* x = "veryVeryVeryVeryVeryVe" + "ryVeryVeryVeryVeryVery" + "VeryLongString"; - false: - const char* x = - "veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongString"; + false: + const char* x = + "veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongString"; + ``` In C# and Java: - .. code-block:: c++ - - true: - string x = "veryVeryVeryVeryVeryVe" + - "ryVeryVeryVeryVeryVery" + - "VeryLongString"; + ```c++ + true: + string x = "veryVeryVeryVeryVeryVe" + + "ryVeryVeryVeryVeryVery" + + "VeryLongString"; - false: - string x = - "veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongString"; + false: + string x = + "veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongString"; + ``` C# interpolated strings are not broken. In Verilog: - .. code-block:: c++ + ```c++ + true: + string x = {"veryVeryVeryVeryVeryVe", + "ryVeryVeryVeryVeryVery", + "VeryLongString"}; - true: - string x = {"veryVeryVeryVeryVeryVe", - "ryVeryVeryVeryVeryVery", - "VeryLongString"}; + false: + string x = + "veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongString"; + ``` - false: - string x = - "veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongString"; +(breaktemplatedeclarations)= -.. _BreakTemplateDeclarations: +**BreakTemplateDeclarations** (`BreakTemplateDeclarationsStyle`) {versionbadge}`clang-format 19` {ref}`¶ ` -**BreakTemplateDeclarations** (``BreakTemplateDeclarationsStyle``) :versionbadge:`clang-format 19` :ref:`¶ ` - The template declaration breaking style to use. +: The template declaration breaking style to use. Possible values: - * ``BTDS_Leave`` (in configuration: ``Leave``) + - `BTDS_Leave` (in configuration: `Leave`) Do not change the line breaking before the declaration. - .. code-block:: c++ - - template - T foo() { - } - template T foo(int aaaaaaaaaaaaaaaaaaaaa, - int bbbbbbbbbbbbbbbbbbbbb) { - } + ```c++ + template + T foo() { + } + template T foo(int aaaaaaaaaaaaaaaaaaaaa, + int bbbbbbbbbbbbbbbbbbbbb) { + } + ``` - * ``BTDS_No`` (in configuration: ``No``) + - `BTDS_No` (in configuration: `No`) Do not force break before declaration. - ``PenaltyBreakTemplateDeclaration`` is taken into account. + `PenaltyBreakTemplateDeclaration` is taken into account. - .. code-block:: c++ - - template T foo() { - } - template T foo(int aaaaaaaaaaaaaaaaaaaaa, - int bbbbbbbbbbbbbbbbbbbbb) { - } + ```c++ + template T foo() { + } + template T foo(int aaaaaaaaaaaaaaaaaaaaa, + int bbbbbbbbbbbbbbbbbbbbb) { + } + ``` - * ``BTDS_MultiLine`` (in configuration: ``MultiLine``) + - `BTDS_MultiLine` (in configuration: `MultiLine`) Force break after template declaration only when the following declaration spans multiple lines. - .. code-block:: c++ - - template T foo() { - } - template - T foo(int aaaaaaaaaaaaaaaaaaaaa, - int bbbbbbbbbbbbbbbbbbbbb) { - } + ```c++ + template T foo() { + } + template + T foo(int aaaaaaaaaaaaaaaaaaaaa, + int bbbbbbbbbbbbbbbbbbbbb) { + } + ``` - * ``BTDS_Yes`` (in configuration: ``Yes``) + - `BTDS_Yes` (in configuration: `Yes`) Always break after template declaration. - .. code-block:: c++ + ```c++ + template + T foo() { + } + template + T foo(int aaaaaaaaaaaaaaaaaaaaa, + int bbbbbbbbbbbbbbbbbbbbb) { + } + ``` - template - T foo() { - } - template - T foo(int aaaaaaaaaaaaaaaaaaaaa, - int bbbbbbbbbbbbbbbbbbbbb) { - } +(columnlimit)= -.. _ColumnLimit: +**ColumnLimit** (`Unsigned`) {versionbadge}`clang-format 3.7` {ref}`¶ ` -**ColumnLimit** (``Unsigned``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - The column limit. +: The column limit. - A column limit of ``0`` means that there is no column limit. In this case, + A column limit of `0` means that there is no column limit. In this case, clang-format will respect the input's line breaking decisions within statements unless they contradict other rules. -.. _CommentPragmas: +(commentpragmas)= -**CommentPragmas** (``String``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - A regular expression that describes comments with special meaning, - which should not be split into lines or otherwise changed. +**CommentPragmas** (`String`) {versionbadge}`clang-format 3.7` {ref}`¶ ` - .. code-block:: c++ +: A regular expression that describes comments with special meaning, + which should not be split into lines or otherwise changed. - // CommentPragmas: '^ FOOBAR pragma:' - // Will leave the following line unaffected - #include // FOOBAR pragma: keep + ```c++ + // CommentPragmas: '^ FOOBAR pragma:' + // Will leave the following line unaffected + #include // FOOBAR pragma: keep + ``` -.. _CompactNamespaces: +(compactnamespaces)= -**CompactNamespaces** (``Boolean``) :versionbadge:`clang-format 5` :ref:`¶ ` - If ``true``, consecutive namespace declarations will be on the same - line. If ``false``, each namespace is declared on a new line. +**CompactNamespaces** (`Boolean`) {versionbadge}`clang-format 5` {ref}`¶ ` - .. code-block:: c++ +: If `true`, consecutive namespace declarations will be on the same + line. If `false`, each namespace is declared on a new line. - true: - namespace Foo { namespace Bar { - }} + ```c++ + true: + namespace Foo { namespace Bar { + }} - false: - namespace Foo { - namespace Bar { - } - } + false: + namespace Foo { + namespace Bar { + } + } + ``` If it does not fit on a single line, the overflowing namespaces get wrapped: - .. code-block:: c++ + ```c++ + namespace Foo { namespace Bar { + namespace Extra { + }}} + ``` + +(constructorinitializerallononelineoroneperline)= - namespace Foo { namespace Bar { - namespace Extra { - }}} +**ConstructorInitializerAllOnOneLineOrOnePerLine** (`Boolean`) {versionbadge}`clang-format 3.7` {ref}`¶ ` -.. _ConstructorInitializerAllOnOneLineOrOnePerLine: +: This option is **deprecated**. See `CurrentLine` of + `PackConstructorInitializers`. -**ConstructorInitializerAllOnOneLineOrOnePerLine** (``Boolean``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - This option is **deprecated**. See ``CurrentLine`` of - ``PackConstructorInitializers``. +(constructorinitializerindentwidth)= -.. _ConstructorInitializerIndentWidth: +**ConstructorInitializerIndentWidth** (`Unsigned`) {versionbadge}`clang-format 3.7` {ref}`¶ ` -**ConstructorInitializerIndentWidth** (``Unsigned``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - The number of characters to use for indentation of constructor +: The number of characters to use for indentation of constructor initializer lists as well as inheritance lists. -.. _ContinuationIndentWidth: +(continuationindentwidth)= -**ContinuationIndentWidth** (``Unsigned``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - Indent width for line continuations. +**ContinuationIndentWidth** (`Unsigned`) {versionbadge}`clang-format 3.7` {ref}`¶ ` - .. code-block:: c++ +: Indent width for line continuations. - ContinuationIndentWidth: 2 + ```c++ + ContinuationIndentWidth: 2 - int i = // VeryVeryVeryVeryVeryLongComment - longFunction( // Again a long comment - arg); + int i = // VeryVeryVeryVeryVeryLongComment + longFunction( // Again a long comment + arg); + ``` -.. _Cpp11BracedListStyle: +(cpp11bracedliststyle)= -**Cpp11BracedListStyle** (``BracedListStyle``) :versionbadge:`clang-format 3.4` :ref:`¶ ` - The style to handle braced lists. +**Cpp11BracedListStyle** (`BracedListStyle`) {versionbadge}`clang-format 3.4` {ref}`¶ ` + +: The style to handle braced lists. Possible values: - * ``BLS_Block`` (in configuration: ``Block``) + - `BLS_Block` (in configuration: `Block`) Best suited for pre C++11 braced lists. - * Spaces inside the braced list. - * Line break before the closing brace. - * Indentation with the block indent. - - - .. code-block:: c++ - - vector x{ 1, 2, 3, 4 }; - vector x{ {}, {}, {}, {} }; - f(MyMap[{ composite, key }]); - new int[3]{ 1, 2, 3 }; - Type name{ // Comment - value - }; + - Spaces inside the braced list. + - Line break before the closing brace. + - Indentation with the block indent. + + ```c++ + vector x{ 1, 2, 3, 4 }; + vector x{ {}, {}, {}, {} }; + f(MyMap[{ composite, key }]); + new int[3]{ 1, 2, 3 }; + Type name{ // Comment + value + }; + ``` - * ``BLS_FunctionCall`` (in configuration: ``FunctionCall``) + - `BLS_FunctionCall` (in configuration: `FunctionCall`) Best suited for C++11 braced lists. - * No spaces inside the braced list. - * No line break before the closing brace. - * Indentation with the continuation indent. + - No spaces inside the braced list. + - No line break before the closing brace. + - Indentation with the continuation indent. Fundamentally, C++11 braced lists are formatted exactly like function calls would be formatted in their place. If the braced list follows a name (e.g. a type or variable name), clang-format formats as if the - ``{}`` were the parentheses of a function call with that name. If there + `{}` were the parentheses of a function call with that name. If there is no name, a zero-length name is assumed. - .. code-block:: c++ - - vector x{1, 2, 3, 4}; - vector x{{}, {}, {}, {}}; - f(MyMap[{composite, key}]); - new int[3]{1, 2, 3}; - Type name{ // Comment - value}; - - * ``BLS_AlignFirstComment`` (in configuration: ``AlignFirstComment``) - Same as ``FunctionCall``, except for the handling of a comment at the + ```c++ + vector x{1, 2, 3, 4}; + vector x{{}, {}, {}, {}}; + f(MyMap[{composite, key}]); + new int[3]{1, 2, 3}; + Type name{ // Comment + value}; + ``` + + - `BLS_AlignFirstComment` (in configuration: `AlignFirstComment`) + Same as `FunctionCall`, except for the handling of a comment at the begin, it then aligns everything following with the comment. - * No spaces inside the braced list. (Even for a comment at the first + - No spaces inside the braced list. (Even for a comment at the first position.) - * No line break before the closing brace. - * Indentation with the continuation indent, except when followed by a + - No line break before the closing brace. + - Indentation with the continuation indent, except when followed by a line comment, then it uses the block indent. + ```c++ + vector x{1, 2, 3, 4}; + vector x{{}, {}, {}, {}}; + f(MyMap[{composite, key}]); + new int[3]{1, 2, 3}; + Type name{// Comment + value}; + ``` - .. code-block:: c++ - vector x{1, 2, 3, 4}; - vector x{{}, {}, {}, {}}; - f(MyMap[{composite, key}]); - new int[3]{1, 2, 3}; - Type name{// Comment - value}; +(derivelineending)= +**DeriveLineEnding** (`Boolean`) {versionbadge}`clang-format 10` {ref}`¶ ` -.. _DeriveLineEnding: +: This option is **deprecated**. See `DeriveLF` and `DeriveCRLF` of + `LineEnding`. -**DeriveLineEnding** (``Boolean``) :versionbadge:`clang-format 10` :ref:`¶ ` - This option is **deprecated**. See ``DeriveLF`` and ``DeriveCRLF`` of - ``LineEnding``. +(derivepointeralignment)= -.. _DerivePointerAlignment: +**DerivePointerAlignment** (`Boolean`) {versionbadge}`clang-format 3.7` {ref}`¶ ` -**DerivePointerAlignment** (``Boolean``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - If ``true``, analyze the formatted file for the most common - alignment of ``&`` and ``*``. +: If `true`, analyze the formatted file for the most common + alignment of `&` and `*`. Pointer and reference alignment styles are going to be updated according to the preferences found in the file. - ``PointerAlignment`` is then used only as fallback. + `PointerAlignment` is then used only as fallback. + +(disableformat)= -.. _DisableFormat: +**DisableFormat** (`Boolean`) {versionbadge}`clang-format 3.7` {ref}`¶ ` -**DisableFormat** (``Boolean``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - Disables formatting completely. +: Disables formatting completely. -.. _EmptyLineAfterAccessModifier: +(emptylineafteraccessmodifier)= -**EmptyLineAfterAccessModifier** (``EmptyLineAfterAccessModifierStyle``) :versionbadge:`clang-format 13` :ref:`¶ ` - Defines when to put an empty line after access modifiers. - ``EmptyLineBeforeAccessModifier`` configuration handles the number of +**EmptyLineAfterAccessModifier** (`EmptyLineAfterAccessModifierStyle`) {versionbadge}`clang-format 13` {ref}`¶ ` + +: Defines when to put an empty line after access modifiers. + `EmptyLineBeforeAccessModifier` configuration handles the number of empty lines between two access modifiers. Possible values: - * ``ELAAMS_Never`` (in configuration: ``Never``) + - `ELAAMS_Never` (in configuration: `Never`) Remove all empty lines after access modifiers. - .. code-block:: c++ - - struct foo { - private: - int i; - protected: - int j; - /* comment */ - public: - foo() {} - private: - protected: - }; + ```c++ + struct foo { + private: + int i; + protected: + int j; + /* comment */ + public: + foo() {} + private: + protected: + }; + ``` - * ``ELAAMS_Leave`` (in configuration: ``Leave``) + - `ELAAMS_Leave` (in configuration: `Leave`) Keep existing empty lines after access modifiers. MaxEmptyLinesToKeep is applied instead. - * ``ELAAMS_Always`` (in configuration: ``Always``) + - `ELAAMS_Always` (in configuration: `Always`) Always add empty line after access modifiers if there are none. MaxEmptyLinesToKeep is applied also. - .. code-block:: c++ + ```c++ + struct foo { + private: - struct foo { - private: + int i; + protected: - int i; - protected: + int j; + /* comment */ + public: - int j; - /* comment */ - public: + foo() {} + private: - foo() {} - private: + protected: - protected: + }; + ``` - }; +(emptylinebeforeaccessmodifier)= -.. _EmptyLineBeforeAccessModifier: +**EmptyLineBeforeAccessModifier** (`EmptyLineBeforeAccessModifierStyle`) {versionbadge}`clang-format 12` {ref}`¶ ` -**EmptyLineBeforeAccessModifier** (``EmptyLineBeforeAccessModifierStyle``) :versionbadge:`clang-format 12` :ref:`¶ ` - Defines in which cases to put empty line before access modifiers. +: Defines in which cases to put empty line before access modifiers. Possible values: - * ``ELBAMS_Never`` (in configuration: ``Never``) + - `ELBAMS_Never` (in configuration: `Never`) Remove all empty lines before access modifiers. - .. code-block:: c++ - - struct foo { - private: - int i; - protected: - int j; - /* comment */ - public: - foo() {} - private: - protected: - }; + ```c++ + struct foo { + private: + int i; + protected: + int j; + /* comment */ + public: + foo() {} + private: + protected: + }; + ``` - * ``ELBAMS_Leave`` (in configuration: ``Leave``) + - `ELBAMS_Leave` (in configuration: `Leave`) Keep existing empty lines before access modifiers. - * ``ELBAMS_LogicalBlock`` (in configuration: ``LogicalBlock``) + - `ELBAMS_LogicalBlock` (in configuration: `LogicalBlock`) Add empty line only when access modifier starts a new logical block. Logical block is a group of one or more member fields or functions. - .. code-block:: c++ - - struct foo { - private: - int i; + ```c++ + struct foo { + private: + int i; - protected: - int j; - /* comment */ - public: - foo() {} + protected: + int j; + /* comment */ + public: + foo() {} - private: - protected: - }; + private: + protected: + }; + ``` - * ``ELBAMS_Always`` (in configuration: ``Always``) + - `ELBAMS_Always` (in configuration: `Always`) Always add empty line before access modifiers unless access modifier is at the start of struct or class definition. - .. code-block:: c++ + ```c++ + struct foo { + private: + int i; - struct foo { - private: - int i; + protected: + int j; + /* comment */ - protected: - int j; - /* comment */ + public: + foo() {} - public: - foo() {} + private: - private: + protected: + }; + ``` - protected: - }; +(enumtrailingcomma)= -.. _EnumTrailingComma: +**EnumTrailingComma** (`EnumTrailingCommaStyle`) {versionbadge}`clang-format 21` {ref}`¶ ` -**EnumTrailingComma** (``EnumTrailingCommaStyle``) :versionbadge:`clang-format 21` :ref:`¶ ` - Insert a comma (if missing) or remove the comma at the end of an ``enum`` +: Insert a comma (if missing) or remove the comma at the end of an `enum` enumerator list. - .. warning:: - - Setting this option to any value other than ``Leave`` could lead to - incorrect code formatting due to clang-format's lack of complete semantic - information. As such, extra care should be taken to review code changes - made by this option. + :::{warning} + Setting this option to any value other than `Leave` could lead to + incorrect code formatting due to clang-format's lack of complete semantic + information. As such, extra care should be taken to review code changes + made by this option. + ::: Possible values: - * ``ETC_Leave`` (in configuration: ``Leave``) + - `ETC_Leave` (in configuration: `Leave`) Don't insert or remove trailing commas. - .. code-block:: c++ - - enum { a, b, c, }; - enum Color { red, green, blue }; + ```c++ + enum { a, b, c, }; + enum Color { red, green, blue }; + ``` - * ``ETC_Insert`` (in configuration: ``Insert``) + - `ETC_Insert` (in configuration: `Insert`) Insert trailing commas. - .. code-block:: c++ + ```c++ + enum { a, b, c, }; + enum Color { red, green, blue, }; + ``` - enum { a, b, c, }; - enum Color { red, green, blue, }; - - * ``ETC_Remove`` (in configuration: ``Remove``) + - `ETC_Remove` (in configuration: `Remove`) Remove trailing commas. - .. code-block:: c++ + ```c++ + enum { a, b, c }; + enum Color { red, green, blue }; + ``` - enum { a, b, c }; - enum Color { red, green, blue }; +(experimentalautodetectbinpacking)= -.. _ExperimentalAutoDetectBinPacking: +**ExperimentalAutoDetectBinPacking** (`Boolean`) {versionbadge}`clang-format 3.7` {ref}`¶ ` -**ExperimentalAutoDetectBinPacking** (``Boolean``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - If ``true``, clang-format detects whether function calls and +: If `true`, clang-format detects whether function calls and definitions are formatted with one parameter per line. Each call can be bin-packed, one-per-line or inconclusive. If it is @@ -4449,589 +4510,608 @@ the configuration (without a prefix: ``Auto``). made, clang-format analyzes whether there are other bin-packed cases in the input file and act accordingly. + :::{note} + This is an experimental flag, that might go away or be renamed. Do + not use this in config files, etc. Use at your own risk. + ::: - .. note:: - - This is an experimental flag, that might go away or be renamed. Do - not use this in config files, etc. Use at your own risk. +(fixnamespacecomments)= -.. _FixNamespaceComments: +**FixNamespaceComments** (`Boolean`) {versionbadge}`clang-format 5` {ref}`¶ ` -**FixNamespaceComments** (``Boolean``) :versionbadge:`clang-format 5` :ref:`¶ ` - If ``true``, clang-format adds missing namespace end comments for +: If `true`, clang-format adds missing namespace end comments for namespaces and fixes invalid existing ones. This doesn't affect short - namespaces, which are controlled by ``ShortNamespaceLines``. + namespaces, which are controlled by `ShortNamespaceLines`. - .. code-block:: c++ + ```c++ + true: false: + namespace longNamespace { vs. namespace longNamespace { + void foo(); void foo(); + void bar(); void bar(); + } // namespace a } + namespace shortNamespace { namespace shortNamespace { + void baz(); void baz(); + } } + ``` - true: false: - namespace longNamespace { vs. namespace longNamespace { - void foo(); void foo(); - void bar(); void bar(); - } // namespace a } - namespace shortNamespace { namespace shortNamespace { - void baz(); void baz(); - } } +(foreachmacros)= -.. _ForEachMacros: +**ForEachMacros** (`List of Strings`) {versionbadge}`clang-format 3.7` {ref}`¶ ` -**ForEachMacros** (``List of Strings``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - A vector of macros that should be interpreted as foreach loops +: A vector of macros that should be interpreted as foreach loops instead of as function calls. These are expected to be macros of the form: - .. code-block:: c++ - - FOREACH(, ...) - + ```c++ + FOREACH(, ...) + + ``` In the .clang-format configuration file, this can be configured like: - .. code-block:: yaml - - ForEachMacros: [RANGES_FOR, FOREACH] + ```yaml + ForEachMacros: [RANGES_FOR, FOREACH] + ``` For example: BOOST_FOREACH. -.. _IfMacros: +(ifmacros)= -**IfMacros** (``List of Strings``) :versionbadge:`clang-format 13` :ref:`¶ ` - A vector of macros that should be interpreted as conditionals +**IfMacros** (`List of Strings`) {versionbadge}`clang-format 13` {ref}`¶ ` + +: A vector of macros that should be interpreted as conditionals instead of as function calls. These are expected to be macros of the form: - .. code-block:: c++ - - IF(...) - - else IF(...) - + ```c++ + IF(...) + + else IF(...) + + ``` In the .clang-format configuration file, this can be configured like: - .. code-block:: yaml + ```yaml + IfMacros: [IF] + ``` - IfMacros: [IF] + For example: + [KJ_IF_MAYBE](https://github.com/capnproto/capnproto/blob/master/kjdoc/tour.md#maybes) - For example: `KJ_IF_MAYBE - `_ +(includeblocks)= -.. _IncludeBlocks: +**IncludeBlocks** (`IncludeBlocksStyle`) {versionbadge}`clang-format 6` {ref}`¶ ` -**IncludeBlocks** (``IncludeBlocksStyle``) :versionbadge:`clang-format 6` :ref:`¶ ` - Dependent on the value, multiple ``#include`` blocks can be sorted +: Dependent on the value, multiple `#include` blocks can be sorted as one and divided based on category. Possible values: - * ``IBS_Preserve`` (in configuration: ``Preserve``) - Sort each ``#include`` block separately. - - .. code-block:: c++ + - `IBS_Preserve` (in configuration: `Preserve`) + Sort each `#include` block separately. - #include "b.h" into #include "b.h" + ```c++ + #include "b.h" into #include "b.h" - #include #include "a.h" - #include "a.h" #include + #include #include "a.h" + #include "a.h" #include + ``` - * ``IBS_Merge`` (in configuration: ``Merge``) - Merge multiple ``#include`` blocks together and sort as one. + - `IBS_Merge` (in configuration: `Merge`) + Merge multiple `#include` blocks together and sort as one. - .. code-block:: c++ + ```c++ + #include "b.h" into #include "a.h" + #include "b.h" + #include #include + #include "a.h" + ``` - #include "b.h" into #include "a.h" - #include "b.h" - #include #include - #include "a.h" - - * ``IBS_Regroup`` (in configuration: ``Regroup``) - Merge multiple ``#include`` blocks together and sort as one. + - `IBS_Regroup` (in configuration: `Regroup`) + Merge multiple `#include` blocks together and sort as one. Then split into groups based on category priority. See - ``IncludeCategories``. + `IncludeCategories`. - .. code-block:: c++ + ```c++ + #include "b.h" into #include "a.h" + #include "b.h" + #include + #include "a.h" #include + ``` - #include "b.h" into #include "a.h" - #include "b.h" - #include - #include "a.h" #include +(includecategories)= -.. _IncludeCategories: +**IncludeCategories** (`List of IncludeCategories`) {versionbadge}`clang-format 3.8` {ref}`¶ ` -**IncludeCategories** (``List of IncludeCategories``) :versionbadge:`clang-format 3.8` :ref:`¶ ` - Regular expressions denoting the different ``#include`` categories - used for ordering ``#includes``. +: Regular expressions denoting the different `#include` categories + used for ordering `#includes`. - `POSIX extended - `_ + [POSIX + extended](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html) regular expressions are supported. These regular expressions are matched against the filename of an include (including the <> or "") in order. The value belonging to the first - matching regular expression is assigned and ``#includes`` are sorted first + matching regular expression is assigned and `#includes` are sorted first according to increasing category number and then alphabetically within each category. If none of the regular expressions match, INT_MAX is assigned as category. The main header for a source file automatically gets category 0. - so that it is generally kept at the beginning of the ``#includes`` - (https://llvm.org/docs/CodingStandards.html#include-style). However, you - can also assign negative priorities if you have certain headers that - always need to be first. - - There is a third and optional field ``SortPriority`` which can used while - ``IncludeBlocks = IBS_Regroup`` to define the priority in which - ``#includes`` should be ordered. The value of ``Priority`` defines the - order of ``#include blocks`` and also allows the grouping of ``#includes`` - of different priority. ``SortPriority`` is set to the value of - ``Priority`` as default if it is not assigned. + so that it is generally kept at the beginning of the `#includes` + (see [LLVM + style](https://llvm.org/docs/CodingStandards.html#include-style)). + However, you can also assign negative priorities if you have certain + headers that always need to be first. + + There is a third and optional field `SortPriority` which can used while + `IncludeBlocks = IBS_Regroup` to define the priority in which + `#includes` should be ordered. The value of `Priority` defines the + order of `#include blocks` and also allows the grouping of `#includes` + of different priority. `SortPriority` is set to the value of + `Priority` as default if it is not assigned. Each regular expression can be marked as case sensitive with the field - ``CaseSensitive``, per default it is not. + `CaseSensitive`, per default it is not. To configure this in the .clang-format file, use: - .. code-block:: yaml - - IncludeCategories: - - Regex: '^"(llvm|llvm-c|clang|clang-c)/' - Priority: 2 - SortPriority: 2 - CaseSensitive: true - - Regex: '^((<|")(gtest|gmock|isl|json)/)' - Priority: 3 - - Regex: '<[[:alnum:].]+>' - Priority: 4 - - Regex: '.*' - Priority: 1 - SortPriority: 0 - -.. _IncludeIsMainRegex: - -**IncludeIsMainRegex** (``String``) :versionbadge:`clang-format 3.9` :ref:`¶ ` - Specify a regular expression of suffixes that are allowed in the + ```yaml + IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 2 + CaseSensitive: true + - Regex: '^((<|")(gtest|gmock|isl|json)/)' + Priority: 3 + - Regex: '<[[:alnum:].]+>' + Priority: 4 + - Regex: '.*' + Priority: 1 + SortPriority: 0 + ``` + +(includeismainregex)= + +**IncludeIsMainRegex** (`String`) {versionbadge}`clang-format 3.9` {ref}`¶ ` + +: Specify a regular expression of suffixes that are allowed in the file-to-main-include mapping. When guessing whether a #include is the "main" include (to assign category 0, see above), use this regex of allowed suffixes to the header stem. A partial match is done, so that: - * ``""`` means "arbitrary suffix" - * ``"$"`` means "no suffix" + - `""` means "arbitrary suffix" + - `"$"` means "no suffix" - For example, if configured to ``"(_test)?$"``, then a header a.h would be + For example, if configured to `"(_test)?$"`, then a header a.h would be seen as the "main" include in both a.cc and a_test.cc. -.. _IncludeIsMainSourceRegex: +(includeismainsourceregex)= + +**IncludeIsMainSourceRegex** (`String`) {versionbadge}`clang-format 10` {ref}`¶ ` -**IncludeIsMainSourceRegex** (``String``) :versionbadge:`clang-format 10` :ref:`¶ ` - Specify a regular expression for files being formatted +: Specify a regular expression for files being formatted that are allowed to be considered "main" in the file-to-main-include mapping. By default, clang-format considers files as "main" only when they end - with: ``.c``, ``.cc``, ``.cpp``, ``.c++``, ``.cxx``, ``.m`` or ``.mm`` + with: `.c`, `.cc`, `.cpp`, `.c++`, `.cxx`, `.m` or `.mm` extensions. For these files a guessing of "main" include takes place (to assign category 0, see above). This config option allows for additional suffixes and extensions for files to be considered as "main". - For example, if this option is configured to ``(Impl\.hpp)$``, - then a file ``ClassImpl.hpp`` is considered "main" (in addition to - ``Class.c``, ``Class.cc``, ``Class.cpp`` and so on) and "main + For example, if this option is configured to `(Impl\.hpp)$`, + then a file `ClassImpl.hpp` is considered "main" (in addition to + `Class.c`, `Class.cc`, `Class.cpp` and so on) and "main include file" logic will be executed (with *IncludeIsMainRegex* setting also being respected in later phase). Without this option set, - ``ClassImpl.hpp`` would not have the main include file put on top + `ClassImpl.hpp` would not have the main include file put on top before any other include. -.. _IndentAccessModifiers: +(indentaccessmodifiers)= -**IndentAccessModifiers** (``Boolean``) :versionbadge:`clang-format 13` :ref:`¶ ` - Specify whether access modifiers should have their own indentation level. +**IndentAccessModifiers** (`Boolean`) {versionbadge}`clang-format 13` {ref}`¶ ` - When ``false``, access modifiers are indented (or outdented) relative to - the record members, respecting the ``AccessModifierOffset``. Record +: Specify whether access modifiers should have their own indentation level. + + When `false`, access modifiers are indented (or outdented) relative to + the record members, respecting the `AccessModifierOffset`. Record members are indented one level below the record. - When ``true``, access modifiers get their own indentation level. As a + When `true`, access modifiers get their own indentation level. As a consequence, record members are always indented 2 levels below the record, regardless of the access modifier presence. Value of the - ``AccessModifierOffset`` is ignored. - - .. code-block:: c++ - - false: true: - class C { vs. class C { - class D { class D { - void bar(); void bar(); - protected: protected: - D(); D(); - }; }; - public: public: - C(); C(); - }; }; - void foo() { void foo() { - return 1; return 1; - } } - -.. _IndentCaseBlocks: - -**IndentCaseBlocks** (``Boolean``) :versionbadge:`clang-format 11` :ref:`¶ ` - Indent case label blocks one level from the case label. - - When ``false``, the block following the case label uses the same + `AccessModifierOffset` is ignored. + + ```c++ + false: true: + class C { vs. class C { + class D { class D { + void bar(); void bar(); + protected: protected: + D(); D(); + }; }; + public: public: + C(); C(); + }; }; + void foo() { void foo() { + return 1; return 1; + } } + ``` + +(indentcaseblocks)= + +**IndentCaseBlocks** (`Boolean`) {versionbadge}`clang-format 11` {ref}`¶ ` + +: Indent case label blocks one level from the case label. + + When `false`, the block following the case label uses the same indentation level as for the case label, treating the case label the same as an if-statement. - When ``true``, the block gets indented as a scope block. - - .. code-block:: c++ - - false: true: - switch (fool) { vs. switch (fool) { - case 1: { case 1: - bar(); { - } break; bar(); - default: { } - plop(); break; - } default: - } { - plop(); - } - } - -.. _IndentCaseLabels: - -**IndentCaseLabels** (``Boolean``) :versionbadge:`clang-format 3.3` :ref:`¶ ` - Indent case labels one level from the switch statement. - - When ``false``, use the same indentation level as for the switch + When `true`, the block gets indented as a scope block. + + ```c++ + false: true: + switch (fool) { vs. switch (fool) { + case 1: { case 1: + bar(); { + } break; bar(); + default: { } + plop(); break; + } default: + } { + plop(); + } + } + ``` + +(indentcaselabels)= + +**IndentCaseLabels** (`Boolean`) {versionbadge}`clang-format 3.3` {ref}`¶ ` + +: Indent case labels one level from the switch statement. + + When `false`, use the same indentation level as for the switch statement. Switch statement body is always indented one level more than case labels (except the first block following the case label, which itself indents the code - unless IndentCaseBlocks is enabled). - .. code-block:: c++ + ```c++ + false: true: + switch (fool) { vs. switch (fool) { + case 1: case 1: + bar(); bar(); + break; break; + default: default: + plop(); plop(); + } } + ``` - false: true: - switch (fool) { vs. switch (fool) { - case 1: case 1: - bar(); bar(); - break; break; - default: default: - plop(); plop(); - } } +(indentexportblock)= -.. _IndentExportBlock: +**IndentExportBlock** (`Boolean`) {versionbadge}`clang-format 20` {ref}`¶ ` -**IndentExportBlock** (``Boolean``) :versionbadge:`clang-format 20` :ref:`¶ ` - If ``true``, clang-format will indent the body of an ``export { ... }`` +: If `true`, clang-format will indent the body of an `export { ... }` block. This doesn't affect the formatting of anything else related to exported declarations. - .. code-block:: c++ + ```c++ + true: false: + export { vs. export { + void foo(); void foo(); + void bar(); void bar(); + } } + ``` - true: false: - export { vs. export { - void foo(); void foo(); - void bar(); void bar(); - } } +(indentexternblock)= -.. _IndentExternBlock: +**IndentExternBlock** (`IndentExternBlockStyle`) {versionbadge}`clang-format 11` {ref}`¶ ` -**IndentExternBlock** (``IndentExternBlockStyle``) :versionbadge:`clang-format 11` :ref:`¶ ` - IndentExternBlockStyle is the type of indenting of extern blocks. +: IndentExternBlockStyle is the type of indenting of extern blocks. Possible values: - * ``IEBS_AfterExternBlock`` (in configuration: ``AfterExternBlock``) + - `IEBS_AfterExternBlock` (in configuration: `AfterExternBlock`) Backwards compatible with AfterExternBlock's indenting. - .. code-block:: c++ - - IndentExternBlock: AfterExternBlock - BraceWrapping.AfterExternBlock: true - extern "C" - { - void foo(); - } - - - .. code-block:: c++ + ```c++ + IndentExternBlock: AfterExternBlock + BraceWrapping.AfterExternBlock: true + extern "C" + { + void foo(); + } + ``` - IndentExternBlock: AfterExternBlock - BraceWrapping.AfterExternBlock: false - extern "C" { - void foo(); - } + ```c++ + IndentExternBlock: AfterExternBlock + BraceWrapping.AfterExternBlock: false + extern "C" { + void foo(); + } + ``` - * ``IEBS_NoIndent`` (in configuration: ``NoIndent``) + - `IEBS_NoIndent` (in configuration: `NoIndent`) Does not indent extern blocks. - .. code-block:: c++ - - extern "C" { - void foo(); - } + ```c++ + extern "C" { + void foo(); + } + ``` - * ``IEBS_Indent`` (in configuration: ``Indent``) + - `IEBS_Indent` (in configuration: `Indent`) Indents extern blocks. - .. code-block:: c++ + ```c++ + extern "C" { + void foo(); + } + ``` - extern "C" { - void foo(); - } +(indentgotolabels)= -.. _IndentGotoLabels: +**IndentGotoLabels** (`IndentGotoLabelStyle`) {versionbadge}`clang-format 10` {ref}`¶ ` -**IndentGotoLabels** (``IndentGotoLabelStyle``) :versionbadge:`clang-format 10` :ref:`¶ ` - The goto label indenting style to use. +: The goto label indenting style to use. Possible values: - * ``IGLS_NoIndent`` (in configuration: ``NoIndent``) + - `IGLS_NoIndent` (in configuration: `NoIndent`) Do not indent goto labels. - .. code-block:: c++ - - int f() { - if (foo()) { - label1: - bar(); - } - label2: - return 1; - } + ```c++ + int f() { + if (foo()) { + label1: + bar(); + } + label2: + return 1; + } + ``` - * ``IGLS_OuterIndent`` (in configuration: ``OuterIndent``) + - `IGLS_OuterIndent` (in configuration: `OuterIndent`) Indent goto labels to the enclosing block (previous indenting level). - .. code-block:: c++ - - int f() { - if (foo()) { - label1: - bar(); - } - label2: - return 1; - } + ```c++ + int f() { + if (foo()) { + label1: + bar(); + } + label2: + return 1; + } + ``` - * ``IGLS_InnerIndent`` (in configuration: ``InnerIndent``) + - `IGLS_InnerIndent` (in configuration: `InnerIndent`) Indent goto labels to the surrounding statements (current indenting level). - .. code-block:: c++ - - int f() { - if (foo()) { - label1: - bar(); - } - label2: - return 1; - } + ```c++ + int f() { + if (foo()) { + label1: + bar(); + } + label2: + return 1; + } + ``` - * ``IGLS_HalfIndent`` (in configuration: ``HalfIndent``) + - `IGLS_HalfIndent` (in configuration: `HalfIndent`) Indent goto labels to half the indentation of the surrounding code. If the indentation width is an odd number, it will round up. - .. code-block:: c++ + ```c++ + int f() { + if (foo()) { + label1: + bar(); + } + label2: + return 1; + } + ``` - int f() { - if (foo()) { - label1: - bar(); - } - label2: - return 1; - } +(indentppdirectives)= -.. _IndentPPDirectives: +**IndentPPDirectives** (`PPDirectiveIndentStyle`) {versionbadge}`clang-format 6` {ref}`¶ ` -**IndentPPDirectives** (``PPDirectiveIndentStyle``) :versionbadge:`clang-format 6` :ref:`¶ ` - The preprocessor directive indenting style to use. +: The preprocessor directive indenting style to use. Possible values: - * ``PPDIS_None`` (in configuration: ``None``) + - `PPDIS_None` (in configuration: `None`) Does not indent any directives. - .. code-block:: c++ - - #if FOO - #if BAR - #include - #endif - #endif + ```c++ + #if FOO + #if BAR + #include + #endif + #endif + ``` - * ``PPDIS_AfterHash`` (in configuration: ``AfterHash``) + - `PPDIS_AfterHash` (in configuration: `AfterHash`) Indents directives after the hash. - .. code-block:: c++ + ```c++ + #if FOO + # if BAR + # include + # endif + #endif + ``` - #if FOO - # if BAR - # include - # endif - #endif - - * ``PPDIS_BeforeHash`` (in configuration: ``BeforeHash``) + - `PPDIS_BeforeHash` (in configuration: `BeforeHash`) Indents directives before the hash. - .. code-block:: c++ - - #if FOO - #if BAR - #include - #endif - #endif + ```c++ + #if FOO + #if BAR + #include + #endif + #endif + ``` - * ``PPDIS_Leave`` (in configuration: ``Leave``) + - `PPDIS_Leave` (in configuration: `Leave`) Leaves indentation of directives as-is. - .. note:: - - Ignores ``PPIndentWidth``. + :::{note} + Ignores `PPIndentWidth`. + ::: - .. code-block:: c++ - - #if FOO - #if BAR - #include - #endif + ```c++ + #if FOO + #if BAR + #include #endif + #endif + ``` -.. _IndentRequiresClause: +(indentrequiresclause)= -**IndentRequiresClause** (``Boolean``) :versionbadge:`clang-format 15` :ref:`¶ ` - Indent the requires clause in a template. This only applies when - ``RequiresClausePosition`` is ``OwnLine``, ``OwnLineWithBrace``, - or ``WithFollowing``. +**IndentRequiresClause** (`Boolean`) {versionbadge}`clang-format 15` {ref}`¶ ` - In clang-format 12, 13 and 14 it was named ``IndentRequires``. +: Indent the requires clause in a template. This only applies when + `RequiresClausePosition` is `OwnLine`, `OwnLineWithBrace`, + or `WithFollowing`. - .. code-block:: c++ + In clang-format 12, 13 and 14 it was named `IndentRequires`. - true: - template - requires Iterator - void sort(It begin, It end) { - //.... - } + ```c++ + true: + template + requires Iterator + void sort(It begin, It end) { + //.... + } - false: - template - requires Iterator - void sort(It begin, It end) { - //.... - } + false: + template + requires Iterator + void sort(It begin, It end) { + //.... + } + ``` -.. _IndentWidth: +(indentwidth)= -**IndentWidth** (``Unsigned``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - The number of columns to use for indentation. +**IndentWidth** (`Unsigned`) {versionbadge}`clang-format 3.7` {ref}`¶ ` - .. code-block:: c++ +: The number of columns to use for indentation. - IndentWidth: 3 + ```c++ + IndentWidth: 3 - void f() { - someFunction(); - if (true, false) { - f(); - } + void f() { + someFunction(); + if (true, false) { + f(); } + } + ``` + +(indentwrappedfunctionnames)= -.. _IndentWrappedFunctionNames: +**IndentWrappedFunctionNames** (`Boolean`) {versionbadge}`clang-format 3.7` {ref}`¶ ` -**IndentWrappedFunctionNames** (``Boolean``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - Indent if a function definition or declaration is wrapped after the +: Indent if a function definition or declaration is wrapped after the type. - .. code-block:: c++ + ```c++ + true: + LoooooooooooooooooooooooooooooooooooooooongReturnType + LoooooooooooooooooooooooooooooooongFunctionDeclaration(); - true: - LoooooooooooooooooooooooooooooooooooooooongReturnType - LoooooooooooooooooooooooooooooooongFunctionDeclaration(); + false: + LoooooooooooooooooooooooooooooooooooooooongReturnType + LoooooooooooooooooooooooooooooooongFunctionDeclaration(); + ``` - false: - LoooooooooooooooooooooooooooooooooooooooongReturnType - LoooooooooooooooooooooooooooooooongFunctionDeclaration(); +(insertbraces)= -.. _InsertBraces: +**InsertBraces** (`Boolean`) {versionbadge}`clang-format 15` {ref}`¶ ` -**InsertBraces** (``Boolean``) :versionbadge:`clang-format 15` :ref:`¶ ` - Insert braces after control statements (``if``, ``else``, ``for``, ``do``, - and ``while``) in C++ unless the control statements are inside macro +: Insert braces after control statements (`if`, `else`, `for`, `do`, + and `while`) in C++ unless the control statements are inside macro definitions or the braces would enclose preprocessor directives. - .. warning:: - - Setting this option to ``true`` could lead to incorrect code formatting - due to clang-format's lack of complete semantic information. As such, - extra care should be taken to review code changes made by this option. - - .. code-block:: c++ - - false: true: + :::{warning} + Setting this option to `true` could lead to incorrect code formatting + due to clang-format's lack of complete semantic information. As such, + extra care should be taken to review code changes made by this option. + ::: + + ```c++ + false: true: + + if (isa(D)) vs. if (isa(D)) { + handleFunctionDecl(D); handleFunctionDecl(D); + else if (isa(D)) } else if (isa(D)) { + handleVarDecl(D); handleVarDecl(D); + else } else { + return; return; + } - if (isa(D)) vs. if (isa(D)) { - handleFunctionDecl(D); handleFunctionDecl(D); - else if (isa(D)) } else if (isa(D)) { - handleVarDecl(D); handleVarDecl(D); - else } else { - return; return; + while (i--) vs. while (i--) { + for (auto *A : D.attrs()) for (auto *A : D.attrs()) { + handleAttr(A); handleAttr(A); } + } - while (i--) vs. while (i--) { - for (auto *A : D.attrs()) for (auto *A : D.attrs()) { - handleAttr(A); handleAttr(A); - } - } + do vs. do { + --i; --i; + while (i); } while (i); + ``` + +(insertnewlineateof)= - do vs. do { - --i; --i; - while (i); } while (i); +**InsertNewlineAtEOF** (`Boolean`) {versionbadge}`clang-format 16` {ref}`¶ ` -.. _InsertNewlineAtEOF: +: Insert a newline at end of file if missing. -**InsertNewlineAtEOF** (``Boolean``) :versionbadge:`clang-format 16` :ref:`¶ ` - Insert a newline at end of file if missing. +(inserttrailingcommas)= -.. _InsertTrailingCommas: +**InsertTrailingCommas** (`TrailingCommaStyle`) {versionbadge}`clang-format 11` {ref}`¶ ` -**InsertTrailingCommas** (``TrailingCommaStyle``) :versionbadge:`clang-format 11` :ref:`¶ ` - If set to ``TCS_Wrapped`` will insert trailing commas in container +: If set to `TCS_Wrapped` will insert trailing commas in container literals (arrays and objects) that wrap across multiple lines. It is currently only available for JavaScript - and disabled by default ``TCS_None``. - ``InsertTrailingCommas`` cannot be used together with ``BinPackArguments`` + and disabled by default `TCS_None`. + `InsertTrailingCommas` cannot be used together with `BinPackArguments` as inserting the comma disables bin-packing. - .. code-block:: c++ - - TSC_Wrapped: - const someArray = [ - aaaaaaaaaaaaaaaaaaaaaaaaaa, - aaaaaaaaaaaaaaaaaaaaaaaaaa, - aaaaaaaaaaaaaaaaaaaaaaaaaa, - // ^ inserted - ] + ```c++ + TSC_Wrapped: + const someArray = [ + aaaaaaaaaaaaaaaaaaaaaaaaaa, + aaaaaaaaaaaaaaaaaaaaaaaaaa, + aaaaaaaaaaaaaaaaaaaaaaaaaa, + // ^ inserted + ] + ``` Possible values: - * ``TCS_None`` (in configuration: ``None``) + - `TCS_None` (in configuration: `None`) Do not insert trailing commas. - * ``TCS_Wrapped`` (in configuration: ``Wrapped``) + - `TCS_Wrapped` (in configuration: `Wrapped`) Insert trailing commas in container literals that were wrapped over multiple lines. Note that this is conceptually incompatible with bin-packing, because the trailing comma is used as an indicator @@ -5040,17 +5120,18 @@ the configuration (without a prefix: ``Auto``). -.. _IntegerLiteralSeparator: +(integerliteralseparator)= + +**IntegerLiteralSeparator** (`IntegerLiteralSeparatorStyle`) {versionbadge}`clang-format 16` {ref}`¶ ` -**IntegerLiteralSeparator** (``IntegerLiteralSeparatorStyle``) :versionbadge:`clang-format 16` :ref:`¶ ` - Format integer literal separators (``'`` for C/C++ and ``_`` for C#, Java, +: Format integer literal separators (`'` for C/C++ and `_` for C#, Java, and JavaScript). Nested configuration flags: Separator format of integer literals of different bases. - If negative, remove separators. If ``0``, leave the literal as is. If + If negative, remove separators. If `0`, leave the literal as is. If positive, insert separators between digits starting from the rightmost digit. @@ -5058,214 +5139,217 @@ the configuration (without a prefix: ``Auto``). alone, insert separators in decimal literals to separate the digits into groups of 3, and remove separators in hexadecimal literals. - .. code-block:: c++ - - IntegerLiteralSeparator: - Binary: 0 - Decimal: 3 - Hex: -1 + ```c++ + IntegerLiteralSeparator: + Binary: 0 + Decimal: 3 + Hex: -1 + ``` You can also specify a minimum number of digits - (``BinaryMinDigitsInsert``, ``DecimalMinDigitsInsert``, and - ``HexMinDigitsInsert``) the integer literal must have in order for the + (`BinaryMinDigitsInsert`, `DecimalMinDigitsInsert`, and + `HexMinDigitsInsert`) the integer literal must have in order for the separators to be inserted, and a maximum number of digits - (``BinaryMaxDigitsRemove``, ``DecimalMaxDigitsRemove``, and - ``HexMaxDigitsRemove``) until the separators are removed. This divides the + (`BinaryMaxDigitsRemove`, `DecimalMaxDigitsRemove`, and + `HexMaxDigitsRemove`) until the separators are removed. This divides the literals in 3 regions, always without separator (up until including - ``xxxMaxDigitsRemove``), maybe with, or without separators (up until - excluding ``xxxMinDigitsInsert``), and finally always with separators. - - .. note:: - - ``BinaryMinDigits``, ``DecimalMinDigits``, and ``HexMinDigits`` are - deprecated and renamed to ``BinaryMinDigitsInsert``, - ``DecimalMinDigitsInsert``, and ``HexMinDigitsInsert``, respectively. - - * ``int8_t Binary`` Format separators in binary literals. - - .. code-block:: text - - /* -1: */ b = 0b100111101101; - /* 0: */ b = 0b10011'11'0110'1; - /* 3: */ b = 0b100'111'101'101; - /* 4: */ b = 0b1001'1110'1101; - - * ``int8_t BinaryMinDigitsInsert`` Format separators in binary literals with a minimum number of digits. - - .. code-block:: text - - // Binary: 3 - // BinaryMinDigitsInsert: 7 - b1 = 0b101101; - b2 = 0b1'101'101; - - * ``int8_t BinaryMaxDigitsRemove`` Remove separators in binary literals with a maximum number of digits. - - .. code-block:: text - - // Binary: 3 - // BinaryMinDigitsInsert: 7 - // BinaryMaxDigitsRemove: 4 - b0 = 0b1011; // Always removed. - b1 = 0b101101; // Not added. - b2 = 0b1'01'101; // Not removed, not corrected. - b3 = 0b1'101'101; // Always added. - b4 = 0b10'1101; // Corrected to 0b101'101. - - * ``int8_t Decimal`` Format separators in decimal literals. - - .. code-block:: text - - /* -1: */ d = 18446744073709550592ull; - /* 0: */ d = 184467'440737'0'95505'92ull; - /* 3: */ d = 18'446'744'073'709'550'592ull; - - * ``int8_t DecimalMinDigitsInsert`` Format separators in decimal literals with a minimum number of digits. - - .. code-block:: text - - // Decimal: 3 - // DecimalMinDigitsInsert: 5 - d1 = 2023; - d2 = 10'000; - - * ``int8_t DecimalMaxDigitsRemove`` Remove separators in decimal literals with a maximum number of digits. - - .. code-block:: text - - // Decimal: 3 - // DecimalMinDigitsInsert: 7 - // DecimalMaxDigitsRemove: 4 - d0 = 2023; // Always removed. - d1 = 123456; // Not added. - d2 = 1'23'456; // Not removed, not corrected. - d3 = 5'000'000; // Always added. - d4 = 1'23'45; // Corrected to 12'345. - - * ``int8_t Hex`` Format separators in hexadecimal literals. - - .. code-block:: text - - /* -1: */ h = 0xDEADBEEFDEADBEEFuz; - /* 0: */ h = 0xDEAD'BEEF'DE'AD'BEE'Fuz; - /* 2: */ h = 0xDE'AD'BE'EF'DE'AD'BE'EFuz; - - * ``int8_t HexMinDigitsInsert`` Format separators in hexadecimal literals with a minimum number of + `xxxMaxDigitsRemove`), maybe with, or without separators (up until + excluding `xxxMinDigitsInsert`), and finally always with separators. + + :::{note} + `BinaryMinDigits`, `DecimalMinDigits`, and `HexMinDigits` are + deprecated and renamed to `BinaryMinDigitsInsert`, + `DecimalMinDigitsInsert`, and `HexMinDigitsInsert`, respectively. + ::: + + - `int8_t Binary` Format separators in binary literals. + + ```text + /* -1: */ b = 0b100111101101; + /* 0: */ b = 0b10011'11'0110'1; + /* 3: */ b = 0b100'111'101'101; + /* 4: */ b = 0b1001'1110'1101; + ``` + + - `int8_t BinaryMinDigitsInsert` Format separators in binary literals with a minimum number of digits. + + ```text + // Binary: 3 + // BinaryMinDigitsInsert: 7 + b1 = 0b101101; + b2 = 0b1'101'101; + ``` + + - `int8_t BinaryMaxDigitsRemove` Remove separators in binary literals with a maximum number of digits. + + ```text + // Binary: 3 + // BinaryMinDigitsInsert: 7 + // BinaryMaxDigitsRemove: 4 + b0 = 0b1011; // Always removed. + b1 = 0b101101; // Not added. + b2 = 0b1'01'101; // Not removed, not corrected. + b3 = 0b1'101'101; // Always added. + b4 = 0b10'1101; // Corrected to 0b101'101. + ``` + + - `int8_t Decimal` Format separators in decimal literals. + + ```text + /* -1: */ d = 18446744073709550592ull; + /* 0: */ d = 184467'440737'0'95505'92ull; + /* 3: */ d = 18'446'744'073'709'550'592ull; + ``` + + - `int8_t DecimalMinDigitsInsert` Format separators in decimal literals with a minimum number of digits. + + ```text + // Decimal: 3 + // DecimalMinDigitsInsert: 5 + d1 = 2023; + d2 = 10'000; + ``` + + - `int8_t DecimalMaxDigitsRemove` Remove separators in decimal literals with a maximum number of digits. + + ```text + // Decimal: 3 + // DecimalMinDigitsInsert: 7 + // DecimalMaxDigitsRemove: 4 + d0 = 2023; // Always removed. + d1 = 123456; // Not added. + d2 = 1'23'456; // Not removed, not corrected. + d3 = 5'000'000; // Always added. + d4 = 1'23'45; // Corrected to 12'345. + ``` + + - `int8_t Hex` Format separators in hexadecimal literals. + + ```text + /* -1: */ h = 0xDEADBEEFDEADBEEFuz; + /* 0: */ h = 0xDEAD'BEEF'DE'AD'BEE'Fuz; + /* 2: */ h = 0xDE'AD'BE'EF'DE'AD'BE'EFuz; + ``` + + - `int8_t HexMinDigitsInsert` Format separators in hexadecimal literals with a minimum number of digits. - .. code-block:: text - - // Hex: 2 - // HexMinDigitsInsert: 6 - h1 = 0xABCDE; - h2 = 0xAB'CD'EF; + ```text + // Hex: 2 + // HexMinDigitsInsert: 6 + h1 = 0xABCDE; + h2 = 0xAB'CD'EF; + ``` - * ``int8_t HexMaxDigitsRemove`` Remove separators in hexadecimal literals with a maximum number of + - `int8_t HexMaxDigitsRemove` Remove separators in hexadecimal literals with a maximum number of digits. - .. code-block:: text + ```text + // Hex: 2 + // HexMinDigitsInsert: 6 + // HexMaxDigitsRemove: 4 + h0 = 0xAFFE; // Always removed. + h1 = 0xABCDE; // Not added. + h2 = 0xABC'DE; // Not removed, not corrected. + h3 = 0xAB'CD'EF; // Always added. + h4 = 0xABCD'E; // Corrected to 0xA'BC'DE. + ``` - // Hex: 2 - // HexMinDigitsInsert: 6 - // HexMaxDigitsRemove: 4 - h0 = 0xAFFE; // Always removed. - h1 = 0xABCDE; // Not added. - h2 = 0xABC'DE; // Not removed, not corrected. - h3 = 0xAB'CD'EF; // Always added. - h4 = 0xABCD'E; // Corrected to 0xA'BC'DE. +(javaimportgroups)= -.. _JavaImportGroups: +**JavaImportGroups** (`List of Strings`) {versionbadge}`clang-format 8` {ref}`¶ ` -**JavaImportGroups** (``List of Strings``) :versionbadge:`clang-format 8` :ref:`¶ ` - A vector of prefixes ordered by the desired groups for Java imports. +: A vector of prefixes ordered by the desired groups for Java imports. One group's prefix can be a subset of another - the longest prefix is always matched. Within a group, the imports are ordered lexicographically. Static imports are grouped separately and follow the same group rules. By default, static imports are placed before non-static imports, but this behavior is changed by another option, - ``SortJavaStaticImport``. + `SortJavaStaticImport`. In the .clang-format configuration file, this can be configured like in the following yaml example. This will result in imports being formatted as in the Java example below. - .. code-block:: yaml - - JavaImportGroups: [com.example, com, org] - + ```yaml + JavaImportGroups: [com.example, com, org] + ``` - .. code-block:: java + ```java + import static com.example.function1; - import static com.example.function1; + import static com.test.function2; - import static com.test.function2; + import static org.example.function3; - import static org.example.function3; + import com.example.ClassA; + import com.example.Test; + import com.example.a.ClassB; - import com.example.ClassA; - import com.example.Test; - import com.example.a.ClassB; + import com.test.ClassC; - import com.test.ClassC; + import org.example.ClassD; + ``` - import org.example.ClassD; +(javascriptquotes)= -.. _JavaScriptQuotes: +**JavaScriptQuotes** (`JavaScriptQuoteStyle`) {versionbadge}`clang-format 3.9` {ref}`¶ ` -**JavaScriptQuotes** (``JavaScriptQuoteStyle``) :versionbadge:`clang-format 3.9` :ref:`¶ ` - The JavaScriptQuoteStyle to use for JavaScript strings. +: The JavaScriptQuoteStyle to use for JavaScript strings. Possible values: - * ``JSQS_Leave`` (in configuration: ``Leave``) + - `JSQS_Leave` (in configuration: `Leave`) Leave string quotes as they are. - .. code-block:: js + ```js + string1 = "foo"; + string2 = 'bar'; + ``` - string1 = "foo"; - string2 = 'bar'; - - * ``JSQS_Single`` (in configuration: ``Single``) + - `JSQS_Single` (in configuration: `Single`) Always use single quotes. - .. code-block:: js - - string1 = 'foo'; - string2 = 'bar'; + ```js + string1 = 'foo'; + string2 = 'bar'; + ``` - * ``JSQS_Double`` (in configuration: ``Double``) + - `JSQS_Double` (in configuration: `Double`) Always use double quotes. - .. code-block:: js + ```js + string1 = "foo"; + string2 = "bar"; + ``` - string1 = "foo"; - string2 = "bar"; +(javascriptwrapimports)= -.. _JavaScriptWrapImports: +**JavaScriptWrapImports** (`Boolean`) {versionbadge}`clang-format 3.9` {ref}`¶ ` -**JavaScriptWrapImports** (``Boolean``) :versionbadge:`clang-format 3.9` :ref:`¶ ` - Whether to wrap JavaScript import/export statements. +: Whether to wrap JavaScript import/export statements. - .. code-block:: js + ```js + true: + import { + VeryLongImportsAreAnnoying, + VeryLongImportsAreAnnoying, + VeryLongImportsAreAnnoying, + } from "some/module.js" - true: - import { - VeryLongImportsAreAnnoying, - VeryLongImportsAreAnnoying, - VeryLongImportsAreAnnoying, - } from "some/module.js" + false: + import {VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying,} from "some/module.js" + ``` - false: - import {VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying,} from "some/module.js" +(keepemptylines)= -.. _KeepEmptyLines: +**KeepEmptyLines** (`KeepEmptyLinesStyle`) {versionbadge}`clang-format 19` {ref}`¶ ` -**KeepEmptyLines** (``KeepEmptyLinesStyle``) :versionbadge:`clang-format 19` :ref:`¶ ` - Which empty lines are kept. See ``MaxEmptyLinesToKeep`` for how many +: Which empty lines are kept. See `MaxEmptyLinesToKeep` for how many consecutive empty lines are kept. Nested configuration flags: @@ -5275,348 +5359,361 @@ the configuration (without a prefix: ``Auto``). For example, the config below will remove empty lines at start of the file, end of the file, and start of blocks. + ```c++ + KeepEmptyLines: + AtEndOfFile: false + AtStartOfBlock: false + AtStartOfFile: false + ``` - .. code-block:: c++ + - `bool AtEndOfFile` Keep empty lines at end of file. - KeepEmptyLines: - AtEndOfFile: false - AtStartOfBlock: false - AtStartOfFile: false + - `bool AtStartOfBlock` Keep empty lines at start of a block. - * ``bool AtEndOfFile`` Keep empty lines at end of file. + ```c++ + true: false: + if (foo) { vs. if (foo) { + bar(); + bar(); } + } + ``` - * ``bool AtStartOfBlock`` Keep empty lines at start of a block. + - `bool AtStartOfFile` Keep empty lines at start of file. - .. code-block:: c++ - true: false: - if (foo) { vs. if (foo) { - bar(); - bar(); } - } +(keepemptylinesateof)= - * ``bool AtStartOfFile`` Keep empty lines at start of file. +**KeepEmptyLinesAtEOF** (`Boolean`) {versionbadge}`clang-format 17` {ref}`¶ ` +: This option is **deprecated**. See `AtEndOfFile` of `KeepEmptyLines`. -.. _KeepEmptyLinesAtEOF: +(keepemptylinesatthestartofblocks)= -**KeepEmptyLinesAtEOF** (``Boolean``) :versionbadge:`clang-format 17` :ref:`¶ ` - This option is **deprecated**. See ``AtEndOfFile`` of ``KeepEmptyLines``. +**KeepEmptyLinesAtTheStartOfBlocks** (`Boolean`) {versionbadge}`clang-format 3.7` {ref}`¶ ` -.. _KeepEmptyLinesAtTheStartOfBlocks: +: This option is **deprecated**. See `AtStartOfBlock` of + `KeepEmptyLines`. -**KeepEmptyLinesAtTheStartOfBlocks** (``Boolean``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - This option is **deprecated**. See ``AtStartOfBlock`` of - ``KeepEmptyLines``. +(keepformfeed)= -.. _KeepFormFeed: +**KeepFormFeed** (`Boolean`) {versionbadge}`clang-format 20` {ref}`¶ ` -**KeepFormFeed** (``Boolean``) :versionbadge:`clang-format 20` :ref:`¶ ` - Keep the form feed character if it's immediately preceded and followed by +: Keep the form feed character if it's immediately preceded and followed by a newline. Multiple form feeds and newlines within a whitespace range are replaced with a single newline and form feed followed by the remaining newlines. (See www.gnu.org/prep/standards/html_node/Formatting.html#:~:text=formfeed.) -.. _LambdaBodyIndentation: +(lambdabodyindentation)= -**LambdaBodyIndentation** (``LambdaBodyIndentationKind``) :versionbadge:`clang-format 13` :ref:`¶ ` - The indentation style of lambda bodies. ``Signature`` (the default) +**LambdaBodyIndentation** (`LambdaBodyIndentationKind`) {versionbadge}`clang-format 13` {ref}`¶ ` + +: The indentation style of lambda bodies. `Signature` (the default) causes the lambda body to be indented one additional level relative to - the indentation level of the signature. ``OuterScope`` forces the lambda + the indentation level of the signature. `OuterScope` forces the lambda body to be indented one additional level relative to the parent scope containing the lambda signature. Possible values: - * ``LBI_Signature`` (in configuration: ``Signature``) + - `LBI_Signature` (in configuration: `Signature`) Align lambda body relative to the lambda signature. This is the default. - .. code-block:: c++ - - someMethod( - [](SomeReallyLongLambdaSignatureArgument foo) { - return; - }); + ```c++ + someMethod( + [](SomeReallyLongLambdaSignatureArgument foo) { + return; + }); + ``` - * ``LBI_OuterScope`` (in configuration: ``OuterScope``) + - `LBI_OuterScope` (in configuration: `OuterScope`) For statements within block scope, align lambda body relative to the indentation level of the outer scope the lambda signature resides in. - .. code-block:: c++ - - someMethod( - [](SomeReallyLongLambdaSignatureArgument foo) { - return; - }); + ```c++ + someMethod( + [](SomeReallyLongLambdaSignatureArgument foo) { + return; + }); - someMethod(someOtherMethod( - [](SomeReallyLongLambdaSignatureArgument foo) { - return; - })); + someMethod(someOtherMethod( + [](SomeReallyLongLambdaSignatureArgument foo) { + return; + })); + ``` -.. _Language: +(language)= -**Language** (``LanguageKind``) :versionbadge:`clang-format 3.5` :ref:`¶ ` - The language that this format style targets. +**Language** (`LanguageKind`) {versionbadge}`clang-format 3.5` {ref}`¶ ` - .. note:: +: The language that this format style targets. - You can specify the language (``C``, ``Cpp``, or ``ObjC``) for ``.h`` - files by adding a ``// clang-format Language:`` line before the first - non-comment (and non-empty) line, e.g. ``// clang-format Language: Cpp``. + :::{note} + You can specify the language (`C`, `Cpp`, or `ObjC`) for `.h` + files by adding a `// clang-format Language:` line before the first + non-comment (and non-empty) line, e.g. `// clang-format Language: Cpp`. + ::: Possible values: - * ``LK_None`` (in configuration: ``None``) + - `LK_None` (in configuration: `None`) Do not use. - * ``LK_C`` (in configuration: ``C``) + - `LK_C` (in configuration: `C`) Should be used for C. - * ``LK_Cpp`` (in configuration: ``Cpp``) + - `LK_Cpp` (in configuration: `Cpp`) Should be used for C++. - * ``LK_CSharp`` (in configuration: ``CSharp``) + - `LK_CSharp` (in configuration: `CSharp`) Should be used for C#. - * ``LK_Java`` (in configuration: ``Java``) + - `LK_Java` (in configuration: `Java`) Should be used for Java. - * ``LK_JavaScript`` (in configuration: ``JavaScript``) + - `LK_JavaScript` (in configuration: `JavaScript`) Should be used for JavaScript. - * ``LK_Json`` (in configuration: ``Json``) + - `LK_Json` (in configuration: `Json`) Should be used for JSON. - * ``LK_ObjC`` (in configuration: ``ObjC``) + - `LK_ObjC` (in configuration: `ObjC`) Should be used for Objective-C, Objective-C++. - * ``LK_Proto`` (in configuration: ``Proto``) - Should be used for Protocol Buffers - (https://developers.google.com/protocol-buffers/). + - `LK_Proto` (in configuration: `Proto`) + Should be used for [Protocol Buffers](https://protobuf.dev/) - * ``LK_TableGen`` (in configuration: ``TableGen``) + - `LK_TableGen` (in configuration: `TableGen`) Should be used for TableGen code. - * ``LK_TextProto`` (in configuration: ``TextProto``) - Should be used for Protocol Buffer messages in text format - (https://developers.google.com/protocol-buffers/). + - `LK_TextProto` (in configuration: `TextProto`) + Should be used for [Protocol Buffer](https://protobuf.dev/) messages in + text format - * ``LK_Verilog`` (in configuration: ``Verilog``) + - `LK_Verilog` (in configuration: `Verilog`) Should be used for Verilog and SystemVerilog. https://standards.ieee.org/ieee/1800/6700/ https://sci-hub.st/10.1109/IEEESTD.2018.8299595 -.. _LineEnding: +(lineending)= -**LineEnding** (``LineEndingStyle``) :versionbadge:`clang-format 16` :ref:`¶ ` - Line ending style (``\n`` or ``\r\n``) to use. +**LineEnding** (`LineEndingStyle`) {versionbadge}`clang-format 16` {ref}`¶ ` + +: Line ending style (`\n` or `\r\n`) to use. Possible values: - * ``LE_LF`` (in configuration: ``LF``) - Use ``\n``. + - `LE_LF` (in configuration: `LF`) + Use `\n`. + + - `LE_CRLF` (in configuration: `CRLF`) + Use `\r\n`. - * ``LE_CRLF`` (in configuration: ``CRLF``) - Use ``\r\n``. + - `LE_DeriveLF` (in configuration: `DeriveLF`) + Use `\n` unless the input has more lines ending in `\r\n`. - * ``LE_DeriveLF`` (in configuration: ``DeriveLF``) - Use ``\n`` unless the input has more lines ending in ``\r\n``. + - `LE_DeriveCRLF` (in configuration: `DeriveCRLF`) + Use `\r\n` unless the input has more lines ending in `\n`. - * ``LE_DeriveCRLF`` (in configuration: ``DeriveCRLF``) - Use ``\r\n`` unless the input has more lines ending in ``\n``. +(macroblockbegin)= -.. _MacroBlockBegin: +**MacroBlockBegin** (`String`) {versionbadge}`clang-format 3.7` {ref}`¶ ` -**MacroBlockBegin** (``String``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - A regular expression matching macros that start a block. +: A regular expression matching macros that start a block. - .. code-block:: c++ + ```c++ + # With: + MacroBlockBegin: "^NS_MAP_BEGIN|\ + NS_TABLE_HEAD$" + MacroBlockEnd: "^\ + NS_MAP_END|\ + NS_TABLE_.*_END$" - # With: - MacroBlockBegin: "^NS_MAP_BEGIN|\ - NS_TABLE_HEAD$" - MacroBlockEnd: "^\ - NS_MAP_END|\ - NS_TABLE_.*_END$" + NS_MAP_BEGIN + foo(); + NS_MAP_END - NS_MAP_BEGIN - foo(); - NS_MAP_END + NS_TABLE_HEAD + bar(); + NS_TABLE_FOO_END - NS_TABLE_HEAD - bar(); - NS_TABLE_FOO_END + # Without: + NS_MAP_BEGIN + foo(); + NS_MAP_END - # Without: - NS_MAP_BEGIN - foo(); - NS_MAP_END + NS_TABLE_HEAD + bar(); + NS_TABLE_FOO_END + ``` - NS_TABLE_HEAD - bar(); - NS_TABLE_FOO_END +(macroblockend)= -.. _MacroBlockEnd: +**MacroBlockEnd** (`String`) {versionbadge}`clang-format 3.7` {ref}`¶ ` -**MacroBlockEnd** (``String``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - A regular expression matching macros that end a block. +: A regular expression matching macros that end a block. -.. _Macros: +(macros)= -**Macros** (``List of Strings``) :versionbadge:`clang-format 17` :ref:`¶ ` - A list of macros of the form ``=`` . +**Macros** (`List of Strings`) {versionbadge}`clang-format 17` {ref}`¶ ` + +: A list of macros of the form `=` . Code will be parsed with macros expanded, in order to determine how to interpret and format the macro arguments. For example, the code: - .. code-block:: c++ - - A(a*b); + ```c++ + A(a*b); + ``` will usually be interpreted as a call to a function A, and the - multiplication expression will be formatted as ``a * b``. + multiplication expression will be formatted as `a * b`. If we specify the macro definition: - .. code-block:: yaml - - Macros: - - A(x)=x + ```yaml + Macros: + - A(x)=x + ``` the code will now be parsed as a declaration of the variable b of type a*, - and formatted as ``a* b`` (depending on pointer-binding rules). + and formatted as `a* b` (depending on pointer-binding rules). Features and restrictions: - * Both function-like macros and object-like macros are supported. - * Macro arguments must be used exactly once in the expansion. - * No recursive expansion; macros referencing other macros will be - ignored. - * Overloading by arity is supported: for example, given the macro - definitions A=x, A()=y, A(a)=a + - Both function-like macros and object-like macros are supported. + - Macro arguments must be used exactly once in the expansion. + - No recursive expansion; macros referencing other macros will be + ignored. + - Overloading by arity is supported: for example, given the macro + definitions A=x, A()=y, A(a)=a + + ```c++ + A; -> x; + A(); -> y; + A(z); -> z; + A(a, b); // will not be expanded. + ``` - .. code-block:: c++ +(macrosskippedbyremoveparentheses)= - A; -> x; - A(); -> y; - A(z); -> z; - A(a, b); // will not be expanded. +**MacrosSkippedByRemoveParentheses** (`List of Strings`) {versionbadge}`clang-format 21` {ref}`¶ ` -.. _MacrosSkippedByRemoveParentheses: +: A vector of function-like macros whose invocations should be skipped by + `RemoveParentheses`. -**MacrosSkippedByRemoveParentheses** (``List of Strings``) :versionbadge:`clang-format 21` :ref:`¶ ` - A vector of function-like macros whose invocations should be skipped by - ``RemoveParentheses``. +(mainincludechar)= -.. _MainIncludeChar: +**MainIncludeChar** (`MainIncludeCharDiscriminator`) {versionbadge}`clang-format 19` {ref}`¶ ` -**MainIncludeChar** (``MainIncludeCharDiscriminator``) :versionbadge:`clang-format 19` :ref:`¶ ` - When guessing whether a #include is the "main" include, only the include +: When guessing whether a #include is the "main" include, only the include directives that use the specified character are considered. Possible values: - * ``MICD_Quote`` (in configuration: ``Quote``) - Main include uses quotes: ``#include "foo.hpp"`` (the default). + - `MICD_Quote` (in configuration: `Quote`) + Main include uses quotes: `#include "foo.hpp"` (the default). - * ``MICD_AngleBracket`` (in configuration: ``AngleBracket``) - Main include uses angle brackets: ``#include ``. + - `MICD_AngleBracket` (in configuration: `AngleBracket`) + Main include uses angle brackets: `#include `. - * ``MICD_Any`` (in configuration: ``Any``) + - `MICD_Any` (in configuration: `Any`) Main include uses either quotes or angle brackets. -.. _MaxEmptyLinesToKeep: +(maxemptylinestokeep)= -**MaxEmptyLinesToKeep** (``Unsigned``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - The maximum number of consecutive empty lines to keep. +**MaxEmptyLinesToKeep** (`Unsigned`) {versionbadge}`clang-format 3.7` {ref}`¶ ` - .. code-block:: c++ +: The maximum number of consecutive empty lines to keep. - MaxEmptyLinesToKeep: 1 vs. MaxEmptyLinesToKeep: 0 - int f() { int f() { - int = 1; int i = 1; - i = foo(); - i = foo(); return i; - } - return i; - } + ```c++ + MaxEmptyLinesToKeep: 1 vs. MaxEmptyLinesToKeep: 0 + int f() { int f() { + int = 1; int i = 1; + i = foo(); + i = foo(); return i; + } + return i; + } + ``` + +(namespaceindentation)= -.. _NamespaceIndentation: +**NamespaceIndentation** (`NamespaceIndentationKind`) {versionbadge}`clang-format 3.7` {ref}`¶ ` -**NamespaceIndentation** (``NamespaceIndentationKind``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - The indentation used for namespaces. +: The indentation used for namespaces. Possible values: - * ``NI_None`` (in configuration: ``None``) + - `NI_None` (in configuration: `None`) Don't indent in namespaces. - .. code-block:: c++ - - namespace out { - int i; - namespace in { - int i; - } - } + ```c++ + namespace out { + int i; + namespace in { + int i; + } + } + ``` - * ``NI_Inner`` (in configuration: ``Inner``) + - `NI_Inner` (in configuration: `Inner`) Indent only in inner namespaces (nested in other namespaces). - .. code-block:: c++ - - namespace out { - int i; - namespace in { - int i; - } - } + ```c++ + namespace out { + int i; + namespace in { + int i; + } + } + ``` - * ``NI_All`` (in configuration: ``All``) + - `NI_All` (in configuration: `All`) Indent in all namespaces. - .. code-block:: c++ + ```c++ + namespace out { + int i; + namespace in { + int i; + } + } + ``` - namespace out { - int i; - namespace in { - int i; - } - } +(namespacemacros)= -.. _NamespaceMacros: +**NamespaceMacros** (`List of Strings`) {versionbadge}`clang-format 9` {ref}`¶ ` -**NamespaceMacros** (``List of Strings``) :versionbadge:`clang-format 9` :ref:`¶ ` - A vector of macros which are used to open namespace blocks. +: A vector of macros which are used to open namespace blocks. These are expected to be macros of the form: - .. code-block:: c++ - - NAMESPACE(, ...) { - - } + ```c++ + NAMESPACE(, ...) { + + } + ``` For example: TESTSUITE -.. _NumericLiteralCase: +(numericliteralcase)= -**NumericLiteralCase** (``NumericLiteralCaseStyle``) :versionbadge:`clang-format 22` :ref:`¶ ` - Capitalization style for numeric literals. +**NumericLiteralCase** (`NumericLiteralCaseStyle`) {versionbadge}`clang-format 22` {ref}`¶ ` + +: Capitalization style for numeric literals. Nested configuration flags: @@ -5626,423 +5723,434 @@ the configuration (without a prefix: ``Auto``). hexadecimal digits in lowercase, reformat numeric literal prefixes in uppercase, and reformat suffixes in lowercase. - .. code-block:: c++ - - NumericLiteralCase: - ExponentLetter: Leave - HexDigit: Lower - Prefix: Upper - Suffix: Lower + ```c++ + NumericLiteralCase: + ExponentLetter: Leave + HexDigit: Lower + Prefix: Upper + Suffix: Lower + ``` - * ``NumericLiteralComponentStyle ExponentLetter`` + - `NumericLiteralComponentStyle ExponentLetter` Format floating point exponent separator letter case. - .. code-block:: c++ - - float a = 6.02e23 + 1.0E10; // Leave - float a = 6.02E23 + 1.0E10; // Upper - float a = 6.02e23 + 1.0e10; // Lower + ```c++ + float a = 6.02e23 + 1.0E10; // Leave + float a = 6.02E23 + 1.0E10; // Upper + float a = 6.02e23 + 1.0e10; // Lower + ``` Possible values: - * ``NLCS_Leave`` (in configuration: ``Leave``) + - `NLCS_Leave` (in configuration: `Leave`) Leave this component of the literal as is. - * ``NLCS_Upper`` (in configuration: ``Upper``) + - `NLCS_Upper` (in configuration: `Upper`) Format this component with uppercase characters. - * ``NLCS_Lower`` (in configuration: ``Lower``) + - `NLCS_Lower` (in configuration: `Lower`) Format this component with lowercase characters. - * ``NumericLiteralComponentStyle HexDigit`` + - `NumericLiteralComponentStyle HexDigit` Format hexadecimal digit case. - .. code-block:: c++ - - a = 0xaBcDeF; // Leave - a = 0xABCDEF; // Upper - a = 0xabcdef; // Lower + ```c++ + a = 0xaBcDeF; // Leave + a = 0xABCDEF; // Upper + a = 0xabcdef; // Lower + ``` Possible values: - * ``NLCS_Leave`` (in configuration: ``Leave``) + - `NLCS_Leave` (in configuration: `Leave`) Leave this component of the literal as is. - * ``NLCS_Upper`` (in configuration: ``Upper``) + - `NLCS_Upper` (in configuration: `Upper`) Format this component with uppercase characters. - * ``NLCS_Lower`` (in configuration: ``Lower``) + - `NLCS_Lower` (in configuration: `Lower`) Format this component with lowercase characters. - * ``NumericLiteralComponentStyle Prefix`` + - `NumericLiteralComponentStyle Prefix` Format integer prefix case. - .. code-block:: c++ - - a = 0XF0 | 0b1; // Leave - a = 0XF0 | 0B1; // Upper - a = 0xF0 | 0b1; // Lower + ```c++ + a = 0XF0 | 0b1; // Leave + a = 0XF0 | 0B1; // Upper + a = 0xF0 | 0b1; // Lower + ``` Possible values: - * ``NLCS_Leave`` (in configuration: ``Leave``) + - `NLCS_Leave` (in configuration: `Leave`) Leave this component of the literal as is. - * ``NLCS_Upper`` (in configuration: ``Upper``) + - `NLCS_Upper` (in configuration: `Upper`) Format this component with uppercase characters. - * ``NLCS_Lower`` (in configuration: ``Lower``) + - `NLCS_Lower` (in configuration: `Lower`) Format this component with lowercase characters. - * ``NumericLiteralComponentStyle Suffix`` + - `NumericLiteralComponentStyle Suffix` Format suffix case. This option excludes case-sensitive reserved - suffixes, such as ``min`` in C++. - - .. code-block:: c++ + suffixes, such as `min` in C++. - a = 1uLL; // Leave - a = 1ULL; // Upper - a = 1ull; // Lower + ```c++ + a = 1uLL; // Leave + a = 1ULL; // Upper + a = 1ull; // Lower + ``` Possible values: - * ``NLCS_Leave`` (in configuration: ``Leave``) + - `NLCS_Leave` (in configuration: `Leave`) Leave this component of the literal as is. - * ``NLCS_Upper`` (in configuration: ``Upper``) + - `NLCS_Upper` (in configuration: `Upper`) Format this component with uppercase characters. - * ``NLCS_Lower`` (in configuration: ``Lower``) + - `NLCS_Lower` (in configuration: `Lower`) Format this component with lowercase characters. -.. _ObjCBinPackProtocolList: +(objcbinpackprotocollist)= -**ObjCBinPackProtocolList** (``BinPackStyle``) :versionbadge:`clang-format 7` :ref:`¶ ` - Controls bin-packing Objective-C protocol conformance list - items into as few lines as possible when they go over ``ColumnLimit``. +**ObjCBinPackProtocolList** (`BinPackStyle`) {versionbadge}`clang-format 7` {ref}`¶ ` - If ``Auto`` (the default), delegates to the value in - ``BinPackParameters``. If that is ``BinPack``, bin-packs Objective-C +: Controls bin-packing Objective-C protocol conformance list + items into as few lines as possible when they go over `ColumnLimit`. + + If `Auto` (the default), delegates to the value in + `BinPackParameters`. If that is `BinPack`, bin-packs Objective-C protocol conformance list items into as few lines as possible - whenever they go over ``ColumnLimit``. + whenever they go over `ColumnLimit`. - If ``Always``, always bin-packs Objective-C protocol conformance + If `Always`, always bin-packs Objective-C protocol conformance list items into as few lines as possible whenever they go over - ``ColumnLimit``. - - If ``Never``, lays out Objective-C protocol conformance list items - onto individual lines whenever they go over ``ColumnLimit``. + `ColumnLimit`. + If `Never`, lays out Objective-C protocol conformance list items + onto individual lines whenever they go over `ColumnLimit`. - .. code-block:: objc - - Always (or Auto, if BinPackParameters==BinPack): - @interface ccccccccccccc () < - ccccccccccccc, ccccccccccccc, - ccccccccccccc, ccccccccccccc> { - } + ```objc + Always (or Auto, if BinPackParameters==BinPack): + @interface ccccccccccccc () < + ccccccccccccc, ccccccccccccc, + ccccccccccccc, ccccccccccccc> { + } - Never (or Auto, if BinPackParameters!=BinPack): - @interface ddddddddddddd () < - ddddddddddddd, - ddddddddddddd, - ddddddddddddd, - ddddddddddddd> { - } + Never (or Auto, if BinPackParameters!=BinPack): + @interface ddddddddddddd () < + ddddddddddddd, + ddddddddddddd, + ddddddddddddd, + ddddddddddddd> { + } + ``` Possible values: - * ``BPS_Auto`` (in configuration: ``Auto``) + - `BPS_Auto` (in configuration: `Auto`) Automatically determine parameter bin-packing behavior. - * ``BPS_Always`` (in configuration: ``Always``) + - `BPS_Always` (in configuration: `Always`) Always bin-pack parameters. - * ``BPS_Never`` (in configuration: ``Never``) + - `BPS_Never` (in configuration: `Never`) Never bin-pack parameters. -.. _ObjCBlockIndentWidth: - -**ObjCBlockIndentWidth** (``Unsigned``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - The number of characters to use for indentation of ObjC blocks. +(objcblockindentwidth)= - .. code-block:: objc +**ObjCBlockIndentWidth** (`Unsigned`) {versionbadge}`clang-format 3.7` {ref}`¶ ` - ObjCBlockIndentWidth: 4 +: The number of characters to use for indentation of ObjC blocks. - [operation setCompletionBlock:^{ - [self onOperationDone]; - }]; + ```objc + ObjCBlockIndentWidth: 4 -.. _ObjCBreakBeforeNestedBlockParam: + [operation setCompletionBlock:^{ + [self onOperationDone]; + }]; + ``` -**ObjCBreakBeforeNestedBlockParam** (``Boolean``) :versionbadge:`clang-format 11` :ref:`¶ ` - Break parameters list into lines when there is nested block - parameters in a function call. - - .. code-block:: c++ +(objcbreakbeforenestedblockparam)= - false: - - (void)_aMethod - { - [self.test1 t:self w:self callback:^(typeof(self) self, NSNumber - *u, NSNumber *v) { - u = c; - }] - } - true: - - (void)_aMethod - { - [self.test1 t:self - w:self - callback:^(typeof(self) self, NSNumber *u, NSNumber *v) { - u = c; - }] - } +**ObjCBreakBeforeNestedBlockParam** (`Boolean`) {versionbadge}`clang-format 11` {ref}`¶ ` -.. _ObjCPropertyAttributeOrder: +: Break parameters list into lines when there is nested block + parameters in a function call. -**ObjCPropertyAttributeOrder** (``List of Strings``) :versionbadge:`clang-format 18` :ref:`¶ ` - The order in which ObjC property attributes should appear. + ```c++ + false: + - (void)_aMethod + { + [self.test1 t:self w:self callback:^(typeof(self) self, NSNumber + *u, NSNumber *v) { + u = c; + }] + } + true: + - (void)_aMethod + { + [self.test1 t:self + w:self + callback:^(typeof(self) self, NSNumber *u, NSNumber *v) { + u = c; + }] + } + ``` + +(objcpropertyattributeorder)= + +**ObjCPropertyAttributeOrder** (`List of Strings`) {versionbadge}`clang-format 18` {ref}`¶ ` + +: The order in which ObjC property attributes should appear. Attributes in code will be sorted in the order specified. Any attributes encountered that are not mentioned in this array will be sorted last, in stable order. Comments between attributes will leave the attributes untouched. - .. warning:: + :::{warning} + Using this option could lead to incorrect code formatting due to + clang-format's lack of complete semantic information. As such, extra + care should be taken to review code changes made by this option. + ::: - Using this option could lead to incorrect code formatting due to - clang-format's lack of complete semantic information. As such, extra - care should be taken to review code changes made by this option. + ```yaml + ObjCPropertyAttributeOrder: [ + class, direct, + atomic, nonatomic, + assign, retain, strong, copy, weak, unsafe_unretained, + readonly, readwrite, getter, setter, + nullable, nonnull, null_resettable, null_unspecified + ] + ``` - .. code-block:: yaml +(objcspaceaftermethoddeclarationprefix)= - ObjCPropertyAttributeOrder: [ - class, direct, - atomic, nonatomic, - assign, retain, strong, copy, weak, unsafe_unretained, - readonly, readwrite, getter, setter, - nullable, nonnull, null_resettable, null_unspecified - ] +**ObjCSpaceAfterMethodDeclarationPrefix** (`Boolean`) {versionbadge}`clang-format 23` {ref}`¶ ` -.. _ObjCSpaceAfterMethodDeclarationPrefix: - -**ObjCSpaceAfterMethodDeclarationPrefix** (``Boolean``) :versionbadge:`clang-format 23` :ref:`¶ ` - Add or remove a space between the '-'/'+' and the return type in +: Add or remove a space between the '-'/'+' and the return type in Objective-C method declarations. i.e - .. code-block:: objc + ```objc + false: true: + + -(void)method vs. - (void)method + ``` - false: true: +(objcspaceafterproperty)= - -(void)method vs. - (void)method +**ObjCSpaceAfterProperty** (`Boolean`) {versionbadge}`clang-format 3.7` {ref}`¶ ` -.. _ObjCSpaceAfterProperty: +: Add a space after `@property` in Objective-C, i.e. use + `@property (readonly)` instead of `@property(readonly)`. -**ObjCSpaceAfterProperty** (``Boolean``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - Add a space after ``@property`` in Objective-C, i.e. use - ``@property (readonly)`` instead of ``@property(readonly)``. +(objcspacebeforeprotocollist)= -.. _ObjCSpaceBeforeProtocolList: +**ObjCSpaceBeforeProtocolList** (`Boolean`) {versionbadge}`clang-format 3.7` {ref}`¶ ` -**ObjCSpaceBeforeProtocolList** (``Boolean``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - Add a space in front of an Objective-C protocol list, i.e. use - ``Foo `` instead of ``Foo``. +: Add a space in front of an Objective-C protocol list, i.e. use + `Foo ` instead of `Foo`. -.. _OneLineFormatOffRegex: +(onelineformatoffregex)= -**OneLineFormatOffRegex** (``String``) :versionbadge:`clang-format 21` :ref:`¶ ` - A regular expression that describes markers for turning formatting off for +**OneLineFormatOffRegex** (`String`) {versionbadge}`clang-format 21` {ref}`¶ ` + +: A regular expression that describes markers for turning formatting off for one line. If it matches a comment that is the only token of a line, clang-format skips the comment and the next line. Otherwise, clang-format skips lines containing a matched token. - .. note:: - - This option does not apply to ``IntegerLiteralSeparator`` and - ``NumericLiteralCase``. - - .. code-block:: c++ - - // OneLineFormatOffRegex: ^(// NOLINT|logger$) - // results in the output below: - int a; - int b ; // NOLINT - int c; - // NOLINTNEXTLINE - int d ; - int e; - s = "// NOLINT"; - logger() ; - logger2(); - my_logger(); - -.. _PPIndentWidth: - -**PPIndentWidth** (``Integer``) :versionbadge:`clang-format 13` :ref:`¶ ` - The number of columns to use for indentation of preprocessor statements. - When set to -1 (default) ``IndentWidth`` is used also for preprocessor + :::{note} + This option does not apply to `IntegerLiteralSeparator` and + `NumericLiteralCase`. + ::: + + ```c++ + // OneLineFormatOffRegex: ^(// NOLINT|logger$) + // results in the output below: + int a; + int b ; // NOLINT + int c; + // NOLINTNEXTLINE + int d ; + int e; + s = "// NOLINT"; + logger() ; + logger2(); + my_logger(); + ``` + +(ppindentwidth)= + +**PPIndentWidth** (`Integer`) {versionbadge}`clang-format 13` {ref}`¶ ` + +: The number of columns to use for indentation of preprocessor statements. + When set to -1 (default) `IndentWidth` is used also for preprocessor statements. - .. code-block:: c++ + ```c++ + PPIndentWidth: 1 - PPIndentWidth: 1 + #ifdef __linux__ + # define FOO + #else + # define BAR + #endif + ``` - #ifdef __linux__ - # define FOO - #else - # define BAR - #endif +(packarguments)= -.. _PackArguments: +**PackArguments** (`PackArgumentsStyle`) {versionbadge}`clang-format 23` {ref}`¶ ` -**PackArguments** (``PackArgumentsStyle``) :versionbadge:`clang-format 23` :ref:`¶ ` - Options related to packing arguments of function calls. +: Options related to packing arguments of function calls. Nested configuration flags: Options related to packing arguments of function calls. - * ``BinPackArgumentsStyle BinPack`` :versionbadge:`clang-format 3.7` + - `BinPackArgumentsStyle BinPack` {versionbadge}`clang-format 3.7` The bin pack arguments style to use. Possible values: - * ``BPAS_BinPack`` (in configuration: ``BinPack``) + - `BPAS_BinPack` (in configuration: `BinPack`) Bin-pack arguments. - .. code-block:: c++ - - void f() { - f(aaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaa, - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa); - } + ```c++ + void f() { + f(aaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaa, + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa); + } + ``` - * ``BPAS_OnePerLine`` (in configuration: ``OnePerLine``) + - `BPAS_OnePerLine` (in configuration: `OnePerLine`) Put all arguments on the current line if they fit. Otherwise, put each one on its own line. - .. code-block:: c++ - - void f() { - f(aaaaaaaaaaaaaaaaaaaa, - aaaaaaaaaaaaaaaaaaaa, - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa); - } + ```c++ + void f() { + f(aaaaaaaaaaaaaaaaaaaa, + aaaaaaaaaaaaaaaaaaaa, + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa); + } + ``` - * ``BPAS_UseBreakAfter`` (in configuration: ``UseBreakAfter``) - Use the ``BreakAfter`` option to handle argument packing instead. - If the ``BreakAfter`` limit is not exceeded, behave like ``BinPack``. + - `BPAS_UseBreakAfter` (in configuration: `UseBreakAfter`) + Use the `BreakAfter` option to handle argument packing instead. + If the `BreakAfter` limit is not exceeded, behave like `BinPack`. - * ``unsigned BreakAfter`` :versionbadge:`clang-format 23` An argument list with more arguments than the specified number will be + - `unsigned BreakAfter` {versionbadge}`clang-format 23` An argument list with more arguments than the specified number will be formatted with one argument per line. This option must be used with - ``BinPack: UseBreakAfter``. + `BinPack: UseBreakAfter`. - .. code-block:: c++ + ```c++ + PackArguments: + BinPack: UseBreakAfter + BreakAfter: 3 - PackArguments: - BinPack: UseBreakAfter - BreakAfter: 3 + void f() { + foo(1); - void f() { - foo(1); + bar(1, 2, 3); - bar(1, 2, 3); + baz(1, + 2, + 3, + 4); + } + ``` - baz(1, - 2, - 3, - 4); - } +(packconstructorinitializers)= -.. _PackConstructorInitializers: +**PackConstructorInitializers** (`PackConstructorInitializersStyle`) {versionbadge}`clang-format 14` {ref}`¶ ` -**PackConstructorInitializers** (``PackConstructorInitializersStyle``) :versionbadge:`clang-format 14` :ref:`¶ ` - The pack constructor initializers style to use. +: The pack constructor initializers style to use. Possible values: - * ``PCIS_Never`` (in configuration: ``Never``) + - `PCIS_Never` (in configuration: `Never`) Always put each constructor initializer on its own line. - .. code-block:: c++ - - Constructor() - : a(), - b() + ```c++ + Constructor() + : a(), + b() + ``` - * ``PCIS_BinPack`` (in configuration: ``BinPack``) + - `PCIS_BinPack` (in configuration: `BinPack`) Bin-pack constructor initializers. - .. code-block:: c++ + ```c++ + Constructor() + : aaaaaaaaaaaaaaaaaaaa(), bbbbbbbbbbbbbbbbbbbb(), + cccccccccccccccccccc() + ``` - Constructor() - : aaaaaaaaaaaaaaaaaaaa(), bbbbbbbbbbbbbbbbbbbb(), - cccccccccccccccccccc() - - * ``PCIS_CurrentLine`` (in configuration: ``CurrentLine``) + - `PCIS_CurrentLine` (in configuration: `CurrentLine`) Put all constructor initializers on the current line if they fit. Otherwise, put each one on its own line. - .. code-block:: c++ - - Constructor() : a(), b() + ```c++ + Constructor() : a(), b() - Constructor() - : aaaaaaaaaaaaaaaaaaaa(), - bbbbbbbbbbbbbbbbbbbb(), - ddddddddddddd() + Constructor() + : aaaaaaaaaaaaaaaaaaaa(), + bbbbbbbbbbbbbbbbbbbb(), + ddddddddddddd() + ``` - * ``PCIS_NextLine`` (in configuration: ``NextLine``) - Same as ``PCIS_CurrentLine`` except that if all constructor initializers + - `PCIS_NextLine` (in configuration: `NextLine`) + Same as `PCIS_CurrentLine` except that if all constructor initializers do not fit on the current line, try to fit them on the next line. - .. code-block:: c++ + ```c++ + Constructor() : a(), b() - Constructor() : a(), b() + Constructor() + : aaaaaaaaaaaaaaaaaaaa(), bbbbbbbbbbbbbbbbbbbb(), ddddddddddddd() - Constructor() - : aaaaaaaaaaaaaaaaaaaa(), bbbbbbbbbbbbbbbbbbbb(), ddddddddddddd() + Constructor() + : aaaaaaaaaaaaaaaaaaaa(), + bbbbbbbbbbbbbbbbbbbb(), + cccccccccccccccccccc() + ``` - Constructor() - : aaaaaaaaaaaaaaaaaaaa(), - bbbbbbbbbbbbbbbbbbbb(), - cccccccccccccccccccc() - - * ``PCIS_NextLineOnly`` (in configuration: ``NextLineOnly``) + - `PCIS_NextLineOnly` (in configuration: `NextLineOnly`) Put all constructor initializers on the next line if they fit. Otherwise, put each one on its own line. - .. code-block:: c++ + ```c++ + Constructor() + : a(), b() - Constructor() - : a(), b() + Constructor() + : aaaaaaaaaaaaaaaaaaaa(), bbbbbbbbbbbbbbbbbbbb(), ddddddddddddd() - Constructor() - : aaaaaaaaaaaaaaaaaaaa(), bbbbbbbbbbbbbbbbbbbb(), ddddddddddddd() + Constructor() + : aaaaaaaaaaaaaaaaaaaa(), + bbbbbbbbbbbbbbbbbbbb(), + cccccccccccccccccccc() + ``` - Constructor() - : aaaaaaaaaaaaaaaaaaaa(), - bbbbbbbbbbbbbbbbbbbb(), - cccccccccccccccccccc() +(packparameters)= -.. _PackParameters: +**PackParameters** (`PackParametersStyle`) {versionbadge}`clang-format 23` {ref}`¶ ` -**PackParameters** (``PackParametersStyle``) :versionbadge:`clang-format 23` :ref:`¶ ` - Options related to packing parameters of function declarations and +: Options related to packing parameters of function declarations and definitions. Nested configuration flags: @@ -6050,255 +6158,268 @@ the configuration (without a prefix: ``Auto``). Options related to packing parameters of function declarations and definitions. - * ``BinPackParametersStyle BinPack`` :versionbadge:`clang-format 3.7` + - `BinPackParametersStyle BinPack` {versionbadge}`clang-format 3.7` The bin pack parameters style to use. Possible values: - * ``BPPS_BinPack`` (in configuration: ``BinPack``) + - `BPPS_BinPack` (in configuration: `BinPack`) Bin-pack parameters. - .. code-block:: c++ + ```c++ + void f(int a, int bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, + int ccccccccccccccccccccccccccccccccccccccccccc); + ``` - void f(int a, int bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, - int ccccccccccccccccccccccccccccccccccccccccccc); - - * ``BPPS_OnePerLine`` (in configuration: ``OnePerLine``) + - `BPPS_OnePerLine` (in configuration: `OnePerLine`) Put all parameters on the current line if they fit. Otherwise, put each one on its own line. - .. code-block:: c++ - - void f(int a, int b, int c); + ```c++ + void f(int a, int b, int c); - void f(int a, - int b, - int ccccccccccccccccccccccccccccccccccccc); + void f(int a, + int b, + int ccccccccccccccccccccccccccccccccccccc); + ``` - * ``BPPS_AlwaysOnePerLine`` (in configuration: ``AlwaysOnePerLine``) + - `BPPS_AlwaysOnePerLine` (in configuration: `AlwaysOnePerLine`) Always put each parameter on its own line. - .. code-block:: c++ + ```c++ + void f(int a, + int b, + int c); + ``` - void f(int a, - int b, - int c); + - `BPPS_UseBreakAfter` (in configuration: `UseBreakAfter`) + Use the `BreakAfter` option to handle parameter packing instead. + If the `BreakAfter` limit is not exceeded, behave like `BinPack`. - * ``BPPS_UseBreakAfter`` (in configuration: ``UseBreakAfter``) - Use the ``BreakAfter`` option to handle parameter packing instead. - If the ``BreakAfter`` limit is not exceeded, behave like ``BinPack``. - - * ``unsigned BreakAfter`` :versionbadge:`clang-format 23` A parameter list with more parameters than the specified number will be + - `unsigned BreakAfter` {versionbadge}`clang-format 23` A parameter list with more parameters than the specified number will be formatted with one parameter per line. This option must be used with - ``BinPack: UseBreakAfter``. + `BinPack: UseBreakAfter`. - .. code-block:: c++ + ```c++ + PackParameters: + BinPack: UseBreakAfter + BreakAfter: 3 - PackParameters: - BinPack: UseBreakAfter - BreakAfter: 3 + void foo(int a); - void foo(int a); + void bar(int a, int b, int c); - void bar(int a, int b, int c); + void baz(int a, + int b, + int c, + int d); + ``` - void baz(int a, - int b, - int c, - int d); +(penaltybreakassignment)= -.. _PenaltyBreakAssignment: +**PenaltyBreakAssignment** (`Unsigned`) {versionbadge}`clang-format 5` {ref}`¶ ` -**PenaltyBreakAssignment** (``Unsigned``) :versionbadge:`clang-format 5` :ref:`¶ ` - The penalty for breaking around an assignment operator. +: The penalty for breaking around an assignment operator. -.. _PenaltyBreakBeforeFirstCallParameter: +(penaltybreakbeforefirstcallparameter)= -**PenaltyBreakBeforeFirstCallParameter** (``Unsigned``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - The penalty for breaking a function call after ``call(``. +**PenaltyBreakBeforeFirstCallParameter** (`Unsigned`) {versionbadge}`clang-format 3.7` {ref}`¶ ` -.. _PenaltyBreakBeforeMemberAccess: +: The penalty for breaking a function call after `call(`. -**PenaltyBreakBeforeMemberAccess** (``Unsigned``) :versionbadge:`clang-format 20` :ref:`¶ ` - The penalty for breaking before a member access operator (``.``, ``->``). +(penaltybreakbeforememberaccess)= -.. _PenaltyBreakComment: +**PenaltyBreakBeforeMemberAccess** (`Unsigned`) {versionbadge}`clang-format 20` {ref}`¶ ` -**PenaltyBreakComment** (``Unsigned``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - The penalty for each line break introduced inside a comment. +: The penalty for breaking before a member access operator (`.`, `->`). -.. _PenaltyBreakFirstLessLess: +(penaltybreakcomment)= -**PenaltyBreakFirstLessLess** (``Unsigned``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - The penalty for breaking before the first ``<<``. +**PenaltyBreakComment** (`Unsigned`) {versionbadge}`clang-format 3.7` {ref}`¶ ` -.. _PenaltyBreakOpenParenthesis: +: The penalty for each line break introduced inside a comment. -**PenaltyBreakOpenParenthesis** (``Unsigned``) :versionbadge:`clang-format 14` :ref:`¶ ` - The penalty for breaking after ``(``. +(penaltybreakfirstlessless)= -.. _PenaltyBreakScopeResolution: +**PenaltyBreakFirstLessLess** (`Unsigned`) {versionbadge}`clang-format 3.7` {ref}`¶ ` -**PenaltyBreakScopeResolution** (``Unsigned``) :versionbadge:`clang-format 18` :ref:`¶ ` - The penalty for breaking after ``::``. +: The penalty for breaking before the first `<<`. -.. _PenaltyBreakString: +(penaltybreakopenparenthesis)= -**PenaltyBreakString** (``Unsigned``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - The penalty for each line break introduced inside a string literal. +**PenaltyBreakOpenParenthesis** (`Unsigned`) {versionbadge}`clang-format 14` {ref}`¶ ` -.. _PenaltyBreakTemplateDeclaration: +: The penalty for breaking after `(`. -**PenaltyBreakTemplateDeclaration** (``Unsigned``) :versionbadge:`clang-format 7` :ref:`¶ ` - The penalty for breaking after template declaration. +(penaltybreakscoperesolution)= -.. _PenaltyExcessCharacter: +**PenaltyBreakScopeResolution** (`Unsigned`) {versionbadge}`clang-format 18` {ref}`¶ ` -**PenaltyExcessCharacter** (``Unsigned``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - The penalty for each character outside of the column limit. +: The penalty for breaking after `::`. -.. _PenaltyIndentedWhitespace: +(penaltybreakstring)= -**PenaltyIndentedWhitespace** (``Unsigned``) :versionbadge:`clang-format 12` :ref:`¶ ` - Penalty for each character of whitespace indentation - (counted relative to leading non-whitespace column). +**PenaltyBreakString** (`Unsigned`) {versionbadge}`clang-format 3.7` {ref}`¶ ` -.. _PenaltyReturnTypeOnItsOwnLine: +: The penalty for each line break introduced inside a string literal. -**PenaltyReturnTypeOnItsOwnLine** (``Unsigned``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - Penalty for putting the return type of a function onto its own line. +(penaltybreaktemplatedeclaration)= -.. _PointerAlignment: +**PenaltyBreakTemplateDeclaration** (`Unsigned`) {versionbadge}`clang-format 7` {ref}`¶ ` -**PointerAlignment** (``PointerAlignmentStyle``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - Pointer and reference alignment style. +: The penalty for breaking after template declaration. - Possible values: +(penaltyexcesscharacter)= - * ``PAS_Left`` (in configuration: ``Left``) - Align pointer to the left. +**PenaltyExcessCharacter** (`Unsigned`) {versionbadge}`clang-format 3.7` {ref}`¶ ` - .. code-block:: c++ +: The penalty for each character outside of the column limit. - int* a; +(penaltyindentedwhitespace)= - * ``PAS_Right`` (in configuration: ``Right``) - Align pointer to the right. +**PenaltyIndentedWhitespace** (`Unsigned`) {versionbadge}`clang-format 12` {ref}`¶ ` - .. code-block:: c++ +: Penalty for each character of whitespace indentation + (counted relative to leading non-whitespace column). - int *a; +(penaltyreturntypeonitsownline)= - * ``PAS_Middle`` (in configuration: ``Middle``) - Align pointer in the middle. +**PenaltyReturnTypeOnItsOwnLine** (`Unsigned`) {versionbadge}`clang-format 3.7` {ref}`¶ ` - .. code-block:: c++ +: Penalty for putting the return type of a function onto its own line. - int * a; +(pointeralignment)= +**PointerAlignment** (`PointerAlignmentStyle`) {versionbadge}`clang-format 3.7` {ref}`¶ ` +: Pointer and reference alignment style. -.. _QualifierAlignment: + Possible values: -**QualifierAlignment** (``QualifierAlignmentStyle``) :versionbadge:`clang-format 14` :ref:`¶ ` - Different ways to arrange specifiers and qualifiers (e.g. const/volatile). + - `PAS_Left` (in configuration: `Left`) + Align pointer to the left. - .. warning:: + ```c++ + int* a; + ``` - Setting ``QualifierAlignment`` to something other than ``Leave``, COULD - lead to incorrect code formatting due to incorrect decisions made due to - clang-formats lack of complete semantic information. - As such extra care should be taken to review code changes made by the use - of this option. + - `PAS_Right` (in configuration: `Right`) + Align pointer to the right. - Possible values: + ```c++ + int *a; + ``` - * ``QAS_Leave`` (in configuration: ``Leave``) - Don't change specifiers/qualifiers to either Left or Right alignment - (default). + - `PAS_Middle` (in configuration: `Middle`) + Align pointer in the middle. - .. code-block:: c++ + ```c++ + int * a; + ``` - int const a; - const int *a; - * ``QAS_Left`` (in configuration: ``Left``) - Change specifiers/qualifiers to be left-aligned. - .. code-block:: c++ +(qualifieralignment)= - const int a; - const int *a; +**QualifierAlignment** (`QualifierAlignmentStyle`) {versionbadge}`clang-format 14` {ref}`¶ ` - * ``QAS_Right`` (in configuration: ``Right``) - Change specifiers/qualifiers to be right-aligned. +: Different ways to arrange specifiers and qualifiers (e.g. const/volatile). - .. code-block:: c++ + :::{warning} + Setting `QualifierAlignment` to something other than `Leave`, COULD + lead to incorrect code formatting due to incorrect decisions made due to + clang-formats lack of complete semantic information. + As such extra care should be taken to review code changes made by the use + of this option. + ::: - int const a; - int const *a; + Possible values: - * ``QAS_Custom`` (in configuration: ``Custom``) - Change specifiers/qualifiers to be aligned based on ``QualifierOrder``. - With: + - `QAS_Leave` (in configuration: `Leave`) + Don't change specifiers/qualifiers to either Left or Right alignment + (default). - .. code-block:: yaml + ```c++ + int const a; + const int *a; + ``` - QualifierOrder: [inline, static, type, const] + - `QAS_Left` (in configuration: `Left`) + Change specifiers/qualifiers to be left-aligned. + ```c++ + const int a; + const int *a; + ``` - .. code-block:: c++ + - `QAS_Right` (in configuration: `Right`) + Change specifiers/qualifiers to be right-aligned. + ```c++ + int const a; + int const *a; + ``` - int const a; - int const *a; + - `QAS_Custom` (in configuration: `Custom`) + Change specifiers/qualifiers to be aligned based on `QualifierOrder`. + With: + ```yaml + QualifierOrder: [inline, static, type, const] + ``` + ```c++ -.. _QualifierOrder: + int const a; + int const *a; + ``` -**QualifierOrder** (``List of Strings``) :versionbadge:`clang-format 14` :ref:`¶ ` - The order in which the qualifiers appear. - The order is an array that can contain any of the following: - * ``const`` - * ``inline`` - * ``static`` - * ``friend`` - * ``constexpr`` - * ``volatile`` - * ``restrict`` - * ``type`` +(qualifierorder)= - .. note:: +**QualifierOrder** (`List of Strings`) {versionbadge}`clang-format 14` {ref}`¶ ` - It must contain ``type``. +: The order in which the qualifiers appear. + The order is an array that can contain any of the following: - Items to the left of ``type`` will be placed to the left of the type and - aligned in the order supplied. Items to the right of ``type`` will be + - `const` + - `inline` + - `static` + - `friend` + - `constexpr` + - `volatile` + - `restrict` + - `type` + + :::{note} + It must contain `type`. + ::: + + Items to the left of `type` will be placed to the left of the type and + aligned in the order supplied. Items to the right of `type` will be placed to the right of the type and aligned in the order supplied. + ```yaml + QualifierOrder: [inline, static, type, const, volatile] + ``` - .. code-block:: yaml - - QualifierOrder: [inline, static, type, const, volatile] +(rawstringformats)= -.. _RawStringFormats: +**RawStringFormats** (`List of RawStringFormats`) {versionbadge}`clang-format 6` {ref}`¶ ` -**RawStringFormats** (``List of RawStringFormats``) :versionbadge:`clang-format 6` :ref:`¶ ` - Defines hints for detecting supported languages code blocks in raw +: Defines hints for detecting supported languages code blocks in raw strings. A raw string with a matching delimiter or a matching enclosing function name will be reformatted assuming the specified language based on the style for that language defined in the .clang-format file. If no style has been defined in the .clang-format file for the specific language, a - predefined style given by ``BasedOnStyle`` is used. If ``BasedOnStyle`` is - not found, the formatting is based on ``LLVM`` style. A matching delimiter + predefined style given by `BasedOnStyle` is used. If `BasedOnStyle` is + not found, the formatting is based on `LLVM` style. A matching delimiter takes precedence over a matching enclosing function name for determining the language of the raw string contents. @@ -6310,1395 +6431,1444 @@ the configuration (without a prefix: ``Auto``). To configure this in the .clang-format file, use: - .. code-block:: yaml - - RawStringFormats: - - Language: TextProto - Delimiters: - - pb - - proto - EnclosingFunctions: - - PARSE_TEXT_PROTO - BasedOnStyle: google - - Language: Cpp - Delimiters: - - cc - - cpp - BasedOnStyle: LLVM - CanonicalDelimiter: cc - -.. _ReferenceAlignment: - -**ReferenceAlignment** (``ReferenceAlignmentStyle``) :versionbadge:`clang-format 13` :ref:`¶ ` - Reference alignment style (overrides ``PointerAlignment`` for references). + ```yaml + RawStringFormats: + - Language: TextProto + Delimiters: + - pb + - proto + EnclosingFunctions: + - PARSE_TEXT_PROTO + BasedOnStyle: google + - Language: Cpp + Delimiters: + - cc + - cpp + BasedOnStyle: LLVM + CanonicalDelimiter: cc + ``` + +(referencealignment)= + +**ReferenceAlignment** (`ReferenceAlignmentStyle`) {versionbadge}`clang-format 13` {ref}`¶ ` + +: Reference alignment style (overrides `PointerAlignment` for references). Possible values: - * ``RAS_Pointer`` (in configuration: ``Pointer``) - Align reference like ``PointerAlignment``. + - `RAS_Pointer` (in configuration: `Pointer`) + Align reference like `PointerAlignment`. - * ``RAS_Left`` (in configuration: ``Left``) + - `RAS_Left` (in configuration: `Left`) Align reference to the left. - .. code-block:: c++ - - int& a; + ```c++ + int& a; + ``` - * ``RAS_Right`` (in configuration: ``Right``) + - `RAS_Right` (in configuration: `Right`) Align reference to the right. - .. code-block:: c++ + ```c++ + int &a; + ``` - int &a; - - * ``RAS_Middle`` (in configuration: ``Middle``) + - `RAS_Middle` (in configuration: `Middle`) Align reference in the middle. - .. code-block:: c++ + ```c++ + int & a; + ``` - int & a; +(reflowcomments)= -.. _ReflowComments: +**ReflowComments** (`ReflowCommentsStyle`) {versionbadge}`clang-format 3.8` {ref}`¶ ` -**ReflowComments** (``ReflowCommentsStyle``) :versionbadge:`clang-format 3.8` :ref:`¶ ` - Comment reformatting style. +: Comment reformatting style. Possible values: - * ``RCS_Never`` (in configuration: ``Never``) + - `RCS_Never` (in configuration: `Never`) Leave comments untouched. - .. code-block:: c++ - - // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information - /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */ - /* third veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information - * and a misaligned second line */ + ```c++ + // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information + /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */ + /* third veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information + - and a misaligned second line */ + ``` - * ``RCS_IndentOnly`` (in configuration: ``IndentOnly``) + - `RCS_IndentOnly` (in configuration: `IndentOnly`) Only apply indentation rules, moving comments left or right, without changing formatting inside the comments. - .. code-block:: c++ + ```c++ + // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information + /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */ + /* third veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information + - and a misaligned second line */ + ``` - // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information - /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */ - /* third veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information - * and a misaligned second line */ - - * ``RCS_Always`` (in configuration: ``Always``) + - `RCS_Always` (in configuration: `Always`) Apply indentation rules and reflow long comments into new lines, trying - to obey the ``ColumnLimit``. - - .. code-block:: c++ + to obey the `ColumnLimit`. - // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of - // information - /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of - * information */ - /* third veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of - * information and a misaligned second line */ + ```c++ + // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of + // information + /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of + - information */ + /* third veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of + - information and a misaligned second line */ + ``` -.. _RemoveBracesLLVM: +(removebracesllvm)= -**RemoveBracesLLVM** (``Boolean``) :versionbadge:`clang-format 14` :ref:`¶ ` - Remove optional braces of control statements (``if``, ``else``, ``for``, - and ``while``) in C++ according to the LLVM coding style. +**RemoveBracesLLVM** (`Boolean`) {versionbadge}`clang-format 14` {ref}`¶ ` - .. warning:: +: Remove optional braces of control statements (`if`, `else`, `for`, + and `while`) in C++ according to the LLVM coding style. - This option will be renamed and expanded to support other styles. + :::{warning} + This option will be renamed and expanded to support other styles. + ::: - .. warning:: + :::{warning} + Setting this option to `true` could lead to incorrect code formatting + due to clang-format's lack of complete semantic information. As such, + extra care should be taken to review code changes made by this option. + ::: - Setting this option to ``true`` could lead to incorrect code formatting - due to clang-format's lack of complete semantic information. As such, - extra care should be taken to review code changes made by this option. - - .. code-block:: c++ - - false: true: - - if (isa(D)) { vs. if (isa(D)) - handleFunctionDecl(D); handleFunctionDecl(D); - } else if (isa(D)) { else if (isa(D)) - handleVarDecl(D); handleVarDecl(D); - } + ```c++ + false: true: - if (isa(D)) { vs. if (isa(D)) { - for (auto *A : D.attrs()) { for (auto *A : D.attrs()) - if (shouldProcessAttr(A)) { if (shouldProcessAttr(A)) - handleAttr(A); handleAttr(A); - } } - } - } + if (isa(D)) { vs. if (isa(D)) + handleFunctionDecl(D); handleFunctionDecl(D); + } else if (isa(D)) { else if (isa(D)) + handleVarDecl(D); handleVarDecl(D); + } - if (isa(D)) { vs. if (isa(D)) - for (auto *A : D.attrs()) { for (auto *A : D.attrs()) + if (isa(D)) { vs. if (isa(D)) { + for (auto *A : D.attrs()) { for (auto *A : D.attrs()) + if (shouldProcessAttr(A)) { if (shouldProcessAttr(A)) handleAttr(A); handleAttr(A); - } + } } } + } - if (auto *D = (T)(D)) { vs. if (auto *D = (T)(D)) { - if (shouldProcess(D)) { if (shouldProcess(D)) - handleVarDecl(D); handleVarDecl(D); - } else { else - markAsIgnored(D); markAsIgnored(D); - } } + if (isa(D)) { vs. if (isa(D)) + for (auto *A : D.attrs()) { for (auto *A : D.attrs()) + handleAttr(A); handleAttr(A); } + } - if (a) { vs. if (a) - b(); b(); - } else { else if (c) - if (c) { d(); - d(); else - } else { e(); - e(); - } + if (auto *D = (T)(D)) { vs. if (auto *D = (T)(D)) { + if (shouldProcess(D)) { if (shouldProcess(D)) + handleVarDecl(D); handleVarDecl(D); + } else { else + markAsIgnored(D); markAsIgnored(D); + } } + } + + if (a) { vs. if (a) + b(); b(); + } else { else if (c) + if (c) { d(); + d(); else + } else { e(); + e(); } + } + ``` -.. _RemoveEmptyLinesInUnwrappedLines: +(removeemptylinesinunwrappedlines)= -**RemoveEmptyLinesInUnwrappedLines** (``Boolean``) :versionbadge:`clang-format 20` :ref:`¶ ` - Remove empty lines within unwrapped lines. +**RemoveEmptyLinesInUnwrappedLines** (`Boolean`) {versionbadge}`clang-format 20` {ref}`¶ ` - .. code-block:: c++ +: Remove empty lines within unwrapped lines. - false: true: + ```c++ + false: true: - int c vs. int c = a + b; + int c vs. int c = a + b; - = a + b; + = a + b; - enum : unsigned vs. enum : unsigned { - AA = 0, - { BB - AA = 0, } myEnum; - BB - } myEnum; + enum : unsigned vs. enum : unsigned { + AA = 0, + { BB + AA = 0, } myEnum; + BB + } myEnum; - while ( vs. while (true) { - } - true) { - } + while ( vs. while (true) { + } + true) { + } + ``` -.. _RemoveParentheses: +(removeparentheses)= -**RemoveParentheses** (``RemoveParenthesesStyle``) :versionbadge:`clang-format 17` :ref:`¶ ` - Remove redundant parentheses. +**RemoveParentheses** (`RemoveParenthesesStyle`) {versionbadge}`clang-format 17` {ref}`¶ ` - .. warning:: +: Remove redundant parentheses. - Setting this option to any value other than ``Leave`` could lead to - incorrect code formatting due to clang-format's lack of complete semantic - information. As such, extra care should be taken to review code changes - made by this option. + :::{warning} + Setting this option to any value other than `Leave` could lead to + incorrect code formatting due to clang-format's lack of complete semantic + information. As such, extra care should be taken to review code changes + made by this option. + ::: Possible values: - * ``RPS_Leave`` (in configuration: ``Leave``) + - `RPS_Leave` (in configuration: `Leave`) Do not remove parentheses. - .. code-block:: c++ + ```c++ + class __declspec((dllimport)) X {}; + co_return (((0))); + return ((a + b) - ((c + d))); + ``` - class __declspec((dllimport)) X {}; - co_return (((0))); - return ((a + b) - ((c + d))); - - * ``RPS_MultipleParentheses`` (in configuration: ``MultipleParentheses``) + - `RPS_MultipleParentheses` (in configuration: `MultipleParentheses`) Replace multiple parentheses with single parentheses. - .. code-block:: c++ - - class __declspec(dllimport) X {}; - co_return (0); - return ((a + b) - (c + d)); + ```c++ + class __declspec(dllimport) X {}; + co_return (0); + return ((a + b) - (c + d)); + ``` - * ``RPS_ReturnStatement`` (in configuration: ``ReturnStatement``) + - `RPS_ReturnStatement` (in configuration: `ReturnStatement`) Also remove parentheses enclosing the expression in a - ``return``/``co_return`` statement. + `return`/`co_return` statement. - .. code-block:: c++ + ```c++ + class __declspec(dllimport) X {}; + co_return 0; + return (a + b) - (c + d); + ``` - class __declspec(dllimport) X {}; - co_return 0; - return (a + b) - (c + d); +(removesemicolon)= -.. _RemoveSemicolon: +**RemoveSemicolon** (`Boolean`) {versionbadge}`clang-format 16` {ref}`¶ ` -**RemoveSemicolon** (``Boolean``) :versionbadge:`clang-format 16` :ref:`¶ ` - Remove semicolons after the closing braces of functions and +: Remove semicolons after the closing braces of functions and constructors/destructors. - .. warning:: + :::{warning} + Setting this option to `true` could lead to incorrect code formatting + due to clang-format's lack of complete semantic information. As such, + extra care should be taken to review code changes made by this option. + ::: - Setting this option to ``true`` could lead to incorrect code formatting - due to clang-format's lack of complete semantic information. As such, - extra care should be taken to review code changes made by this option. + ```c++ + false: true: - .. code-block:: c++ + int max(int a, int b) { int max(int a, int b) { + return a > b ? a : b; return a > b ? a : b; + }; } - false: true: + ``` - int max(int a, int b) { int max(int a, int b) { - return a > b ? a : b; return a > b ? a : b; - }; } +(requiresclauseposition)= -.. _RequiresClausePosition: +**RequiresClausePosition** (`RequiresClausePositionStyle`) {versionbadge}`clang-format 15` {ref}`¶ ` -**RequiresClausePosition** (``RequiresClausePositionStyle``) :versionbadge:`clang-format 15` :ref:`¶ ` - The position of the ``requires`` clause. +: The position of the `requires` clause. Possible values: - * ``RCPS_OwnLine`` (in configuration: ``OwnLine``) - Always put the ``requires`` clause on its own line (possibly followed by + - `RCPS_OwnLine` (in configuration: `OwnLine`) + Always put the `requires` clause on its own line (possibly followed by a semicolon). - .. code-block:: c++ - - template - requires C - struct Foo {... + ```c++ + template + requires C + struct Foo {... - template - void bar(T t) - requires C; + template + void bar(T t) + requires C; - template - requires C - void bar(T t) {... + template + requires C + void bar(T t) {... - template - void baz(T t) - requires C - {... + template + void baz(T t) + requires C + {... + ``` - * ``RCPS_OwnLineWithBrace`` (in configuration: ``OwnLineWithBrace``) - As with ``OwnLine``, except, unless otherwise prohibited, place a + - `RCPS_OwnLineWithBrace` (in configuration: `OwnLineWithBrace`) + As with `OwnLine`, except, unless otherwise prohibited, place a following open brace (of a function definition) to follow on the same line. - .. code-block:: c++ - - void bar(T t) - requires C { - return; - } + ```c++ + void bar(T t) + requires C { + return; + } - void bar(T t) - requires C {} + void bar(T t) + requires C {} - template - requires C - void baz(T t) { - ... + template + requires C + void baz(T t) { + ... + ``` - * ``RCPS_WithPreceding`` (in configuration: ``WithPreceding``) + - `RCPS_WithPreceding` (in configuration: `WithPreceding`) Try to put the clause together with the preceding part of a declaration. For class templates: stick to the template declaration. For function templates: stick to the template declaration. For function declaration followed by a requires clause: stick to the parameter list. - .. code-block:: c++ - - template requires C - struct Foo {... + ```c++ + template requires C + struct Foo {... - template requires C - void bar(T t) {... + template requires C + void bar(T t) {... - template - void baz(T t) requires C - {... + template + void baz(T t) requires C + {... + ``` - * ``RCPS_WithFollowing`` (in configuration: ``WithFollowing``) - Try to put the ``requires`` clause together with the class or function + - `RCPS_WithFollowing` (in configuration: `WithFollowing`) + Try to put the `requires` clause together with the class or function declaration. - .. code-block:: c++ - - template - requires C struct Foo {... + ```c++ + template + requires C struct Foo {... - template - requires C void bar(T t) {... + template + requires C void bar(T t) {... - template - void baz(T t) - requires C {... + template + void baz(T t) + requires C {... + ``` - * ``RCPS_SingleLine`` (in configuration: ``SingleLine``) + - `RCPS_SingleLine` (in configuration: `SingleLine`) Try to put everything in the same line if possible. Otherwise normal line breaking rules take over. - .. code-block:: c++ + ```c++ + // Fitting: + template requires C struct Foo {... - // Fitting: - template requires C struct Foo {... + template requires C void bar(T t) {... - template requires C void bar(T t) {... + template void bar(T t) requires C {... - template void bar(T t) requires C {... + // Not fitting, one possible example: + template + requires C + struct Foo {... - // Not fitting, one possible example: - template - requires C - struct Foo {... + template + requires C + void bar(LongName ln) { - template - requires C - void bar(LongName ln) { + template + void bar(LongName ln) + requires C { + ``` - template - void bar(LongName ln) - requires C { +(requiresexpressionindentation)= -.. _RequiresExpressionIndentation: +**RequiresExpressionIndentation** (`RequiresExpressionIndentationKind`) {versionbadge}`clang-format 16` {ref}`¶ ` -**RequiresExpressionIndentation** (``RequiresExpressionIndentationKind``) :versionbadge:`clang-format 16` :ref:`¶ ` - The indentation used for requires expression bodies. +: The indentation used for requires expression bodies. Possible values: - * ``REI_OuterScope`` (in configuration: ``OuterScope``) + - `REI_OuterScope` (in configuration: `OuterScope`) Align requires expression body relative to the indentation level of the outer scope the requires expression resides in. This is the default. - .. code-block:: c++ - - template - concept C = requires(T t) { - ... - } + ```c++ + template + concept C = requires(T t) { + ... + } + ``` - * ``REI_Keyword`` (in configuration: ``Keyword``) - Align requires expression body relative to the ``requires`` keyword. + - `REI_Keyword` (in configuration: `Keyword`) + Align requires expression body relative to the `requires` keyword. - .. code-block:: c++ + ```c++ + template + concept C = requires(T t) { + ... + } + ``` - template - concept C = requires(T t) { - ... - } +(separatedefinitionblocks)= -.. _SeparateDefinitionBlocks: +**SeparateDefinitionBlocks** (`SeparateDefinitionStyle`) {versionbadge}`clang-format 14` {ref}`¶ ` -**SeparateDefinitionBlocks** (``SeparateDefinitionStyle``) :versionbadge:`clang-format 14` :ref:`¶ ` - Specifies the use of empty lines to separate definition blocks, including +: Specifies the use of empty lines to separate definition blocks, including classes, structs, enums, and functions. - .. code-block:: c++ - - Never v.s. Always - #include #include - struct Foo { - int a, b, c; struct Foo { - }; int a, b, c; - namespace Ns { }; - class Bar { - public: namespace Ns { - struct Foobar { class Bar { - int a; public: - int b; struct Foobar { - }; int a; - private: int b; - int t; }; - int method1() { - // ... private: - } int t; - enum List { - ITEM1, int method1() { - ITEM2 // ... - }; } - template - int method2(T x) { enum List { - // ... ITEM1, - } ITEM2 - int i, j, k; }; - int method3(int par) { - // ... template - } int method2(T x) { - }; // ... - class C {}; } - } - int i, j, k; + ```c++ + Never v.s. Always + #include #include + struct Foo { + int a, b, c; struct Foo { + }; int a, b, c; + namespace Ns { }; + class Bar { + public: namespace Ns { + struct Foobar { class Bar { + int a; public: + int b; struct Foobar { + }; int a; + private: int b; + int t; }; + int method1() { + // ... private: + } int t; + enum List { + ITEM1, int method1() { + ITEM2 // ... + }; } + template + int method2(T x) { enum List { + // ... ITEM1, + } ITEM2 + int i, j, k; }; + int method3(int par) { + // ... template + } int method2(T x) { + }; // ... + class C {}; } + } + int i, j, k; - int method3(int par) { - // ... - } - }; + int method3(int par) { + // ... + } + }; - class C {}; - } + class C {}; + } + ``` Possible values: - * ``SDS_Leave`` (in configuration: ``Leave``) + - `SDS_Leave` (in configuration: `Leave`) Leave definition blocks as they are. - * ``SDS_Always`` (in configuration: ``Always``) + - `SDS_Always` (in configuration: `Always`) Insert an empty line between definition blocks. - * ``SDS_Never`` (in configuration: ``Never``) + - `SDS_Never` (in configuration: `Never`) Remove any empty line between definition blocks. -.. _ShortNamespaceLines: +(shortnamespacelines)= + +**ShortNamespaceLines** (`Unsigned`) {versionbadge}`clang-format 13` {ref}`¶ ` -**ShortNamespaceLines** (``Unsigned``) :versionbadge:`clang-format 13` :ref:`¶ ` - The maximal number of unwrapped lines that a short namespace spans. +: The maximal number of unwrapped lines that a short namespace spans. Defaults to 1. This determines the maximum length of short namespaces by counting unwrapped lines (i.e. containing neither opening nor closing - namespace brace) and makes ``FixNamespaceComments`` omit adding + namespace brace) and makes `FixNamespaceComments` omit adding end comments for those. - .. code-block:: c++ + ```c++ + ShortNamespaceLines: 1 vs. ShortNamespaceLines: 0 + namespace a { namespace a { + int foo; int foo; + } } // namespace a - ShortNamespaceLines: 1 vs. ShortNamespaceLines: 0 - namespace a { namespace a { - int foo; int foo; - } } // namespace a + ShortNamespaceLines: 1 vs. ShortNamespaceLines: 0 + namespace b { namespace b { + int foo; int foo; + int bar; int bar; + } // namespace b } // namespace b + ``` - ShortNamespaceLines: 1 vs. ShortNamespaceLines: 0 - namespace b { namespace b { - int foo; int foo; - int bar; int bar; - } // namespace b } // namespace b +(skipmacrodefinitionbody)= -.. _SkipMacroDefinitionBody: +**SkipMacroDefinitionBody** (`Boolean`) {versionbadge}`clang-format 18` {ref}`¶ ` -**SkipMacroDefinitionBody** (``Boolean``) :versionbadge:`clang-format 18` :ref:`¶ ` - Do not format macro definition body. +: Do not format macro definition body. -.. _SortIncludes: +(sortincludes)= -**SortIncludes** (``SortIncludesOptions``) :versionbadge:`clang-format 3.8` :ref:`¶ ` - Controls if and how clang-format will sort ``#includes``. +**SortIncludes** (`SortIncludesOptions`) {versionbadge}`clang-format 3.8` {ref}`¶ ` + +: Controls if and how clang-format will sort `#includes`. Nested configuration flags: Includes sorting options. - * ``bool Enabled`` If ``true``, includes are sorted based on the other suboptions below. - (``Never`` is deprecated by ``Enabled: false``.) - - * ``bool IgnoreCase`` Whether or not includes are sorted in a case-insensitive fashion. - (``CaseSensitive`` and ``CaseInsensitive`` are deprecated by - ``IgnoreCase: false`` and ``IgnoreCase: true``, respectively.) + - `bool Enabled` If `true`, includes are sorted based on the other suboptions below. + (`Never` is deprecated by `Enabled: false`.) - .. code-block:: c++ + - `bool IgnoreCase` Whether or not includes are sorted in a case-insensitive fashion. + (`CaseSensitive` and `CaseInsensitive` are deprecated by + `IgnoreCase: false` and `IgnoreCase: true`, respectively.) - true: false: - #include "A/B.h" vs. #include "A/B.h" - #include "A/b.h" #include "A/b.h" - #include "a/b.h" #include "B/A.h" - #include "B/A.h" #include "B/a.h" - #include "B/a.h" #include "a/b.h" + ```c++ + true: false: + #include "A/B.h" vs. #include "A/B.h" + #include "A/b.h" #include "A/b.h" + #include "a/b.h" #include "B/A.h" + #include "B/A.h" #include "B/a.h" + #include "B/a.h" #include "a/b.h" + ``` - * ``bool IgnoreExtension`` When sorting includes in each block, only take file extensions into + - `bool IgnoreExtension` When sorting includes in each block, only take file extensions into account if two includes compare equal otherwise. - .. code-block:: c++ + ```c++ + true: false: + # include "A.h" vs. # include "A-util.h" + # include "A.inc" # include "A.h" + # include "A-util.h" # include "A.inc" + ``` - true: false: - # include "A.h" vs. # include "A-util.h" - # include "A.inc" # include "A.h" - # include "A-util.h" # include "A.inc" - - * ``bool Natural`` Whether or not includes are sorted by natural ordering i.e., whether + - `bool Natural` Whether or not includes are sorted by natural ordering i.e., whether embedded runs of digits are compared as numbers rather than sequences of characters. - .. code-block:: c++ + ```c++ + true: false: + #include "A2.h" vs. #include "A10.h" + #include "A10.h" #include "A2.h" + ``` - true: false: - #include "A2.h" vs. #include "A10.h" - #include "A10.h" #include "A2.h" +(sortjavastaticimport)= -.. _SortJavaStaticImport: +**SortJavaStaticImport** (`SortJavaStaticImportOptions`) {versionbadge}`clang-format 12` {ref}`¶ ` -**SortJavaStaticImport** (``SortJavaStaticImportOptions``) :versionbadge:`clang-format 12` :ref:`¶ ` - When sorting Java imports, by default static imports are placed before - non-static imports. If ``JavaStaticImportAfterImport`` is ``After``, +: When sorting Java imports, by default static imports are placed before + non-static imports. If `JavaStaticImportAfterImport` is `After`, static imports are placed after non-static imports. Possible values: - * ``SJSIO_Before`` (in configuration: ``Before``) + - `SJSIO_Before` (in configuration: `Before`) Static imports are placed before non-static imports. - .. code-block:: java - - import static org.example.function1; + ```java + import static org.example.function1; - import org.example.ClassA; + import org.example.ClassA; + ``` - * ``SJSIO_After`` (in configuration: ``After``) + - `SJSIO_After` (in configuration: `After`) Static imports are placed after non-static imports. - .. code-block:: java + ```java + import org.example.ClassA; - import org.example.ClassA; + import static org.example.function1; + ``` - import static org.example.function1; +(sortusingdeclarations)= -.. _SortUsingDeclarations: +**SortUsingDeclarations** (`SortUsingDeclarationsOptions`) {versionbadge}`clang-format 5` {ref}`¶ ` -**SortUsingDeclarations** (``SortUsingDeclarationsOptions``) :versionbadge:`clang-format 5` :ref:`¶ ` - Controls if and how clang-format will sort using declarations. +: Controls if and how clang-format will sort using declarations. Possible values: - * ``SUD_Never`` (in configuration: ``Never``) + - `SUD_Never` (in configuration: `Never`) Using declarations are never sorted. - .. code-block:: c++ + ```c++ + using std::chrono::duration_cast; + using std::move; + using boost::regex; + using boost::regex_constants::icase; + using std::string; + ``` - using std::chrono::duration_cast; - using std::move; - using boost::regex; - using boost::regex_constants::icase; - using std::string; - - * ``SUD_Lexicographic`` (in configuration: ``Lexicographic``) + - `SUD_Lexicographic` (in configuration: `Lexicographic`) Using declarations are sorted in the order defined as follows: - Split the strings by ``::`` and discard any initial empty strings. Sort + Split the strings by `::` and discard any initial empty strings. Sort the lists of names lexicographically, and within those groups, names are in case-insensitive lexicographic order. - .. code-block:: c++ - - using boost::regex; - using boost::regex_constants::icase; - using std::chrono::duration_cast; - using std::move; - using std::string; + ```c++ + using boost::regex; + using boost::regex_constants::icase; + using std::chrono::duration_cast; + using std::move; + using std::string; + ``` - * ``SUD_LexicographicNumeric`` (in configuration: ``LexicographicNumeric``) + - `SUD_LexicographicNumeric` (in configuration: `LexicographicNumeric`) Using declarations are sorted in the order defined as follows: - Split the strings by ``::`` and discard any initial empty strings. The + Split the strings by `::` and discard any initial empty strings. The last element of each list is a non-namespace name; all others are namespace names. Sort the lists of names lexicographically, where the sort order of individual names is that all non-namespace names come before all namespace names, and within those groups, names are in case-insensitive lexicographic order. - .. code-block:: c++ + ```c++ + using boost::regex; + using boost::regex_constants::icase; + using std::move; + using std::string; + using std::chrono::duration_cast; + ``` - using boost::regex; - using boost::regex_constants::icase; - using std::move; - using std::string; - using std::chrono::duration_cast; +(spaceaftercstylecast)= -.. _SpaceAfterCStyleCast: +**SpaceAfterCStyleCast** (`Boolean`) {versionbadge}`clang-format 3.5` {ref}`¶ ` -**SpaceAfterCStyleCast** (``Boolean``) :versionbadge:`clang-format 3.5` :ref:`¶ ` - If ``true``, a space is inserted after C style casts. +: If `true`, a space is inserted after C style casts. - .. code-block:: c++ + ```c++ + true: false: + (int) i; vs. (int)i; + ``` - true: false: - (int) i; vs. (int)i; +(spaceafterlogicalnot)= -.. _SpaceAfterLogicalNot: +**SpaceAfterLogicalNot** (`Boolean`) {versionbadge}`clang-format 9` {ref}`¶ ` -**SpaceAfterLogicalNot** (``Boolean``) :versionbadge:`clang-format 9` :ref:`¶ ` - If ``true``, a space is inserted after the logical not operator (``!``). +: If `true`, a space is inserted after the logical not operator (`!`). - .. code-block:: c++ + ```c++ + true: false: + ! someExpression(); vs. !someExpression(); + ``` - true: false: - ! someExpression(); vs. !someExpression(); +(spaceafteroperatorkeyword)= -.. _SpaceAfterOperatorKeyword: +**SpaceAfterOperatorKeyword** (`Boolean`) {versionbadge}`clang-format 21` {ref}`¶ ` -**SpaceAfterOperatorKeyword** (``Boolean``) :versionbadge:`clang-format 21` :ref:`¶ ` - If ``true``, a space will be inserted after the ``operator`` keyword. +: If `true`, a space will be inserted after the `operator` keyword. - .. code-block:: c++ + ```c++ + true: false: + bool operator ==(int a); vs. bool operator==(int a); + ``` - true: false: - bool operator ==(int a); vs. bool operator==(int a); +(spaceaftertemplatekeyword)= -.. _SpaceAfterTemplateKeyword: +**SpaceAfterTemplateKeyword** (`Boolean`) {versionbadge}`clang-format 4` {ref}`¶ ` -**SpaceAfterTemplateKeyword** (``Boolean``) :versionbadge:`clang-format 4` :ref:`¶ ` - If ``true``, a space will be inserted after the ``template`` keyword. +: If `true`, a space will be inserted after the `template` keyword. - .. code-block:: c++ + ```c++ + true: false: + template void foo(); vs. template void foo(); + ``` - true: false: - template void foo(); vs. template void foo(); +(spacearoundpointerqualifiers)= -.. _SpaceAroundPointerQualifiers: +**SpaceAroundPointerQualifiers** (`SpaceAroundPointerQualifiersStyle`) {versionbadge}`clang-format 12` {ref}`¶ ` -**SpaceAroundPointerQualifiers** (``SpaceAroundPointerQualifiersStyle``) :versionbadge:`clang-format 12` :ref:`¶ ` - Defines in which cases to put a space before or after pointer qualifiers +: Defines in which cases to put a space before or after pointer qualifiers Possible values: - * ``SAPQ_Default`` (in configuration: ``Default``) + - `SAPQ_Default` (in configuration: `Default`) Don't ensure spaces around pointer qualifiers and use PointerAlignment instead. - .. code-block:: c++ + ```c++ + PointerAlignment: Left PointerAlignment: Right + void* const* x = NULL; vs. void *const *x = NULL; + ``` - PointerAlignment: Left PointerAlignment: Right - void* const* x = NULL; vs. void *const *x = NULL; - - * ``SAPQ_Before`` (in configuration: ``Before``) + - `SAPQ_Before` (in configuration: `Before`) Ensure that there is a space before pointer qualifiers. - .. code-block:: c++ - - PointerAlignment: Left PointerAlignment: Right - void* const* x = NULL; vs. void * const *x = NULL; + ```c++ + PointerAlignment: Left PointerAlignment: Right + void* const* x = NULL; vs. void * const *x = NULL; + ``` - * ``SAPQ_After`` (in configuration: ``After``) + - `SAPQ_After` (in configuration: `After`) Ensure that there is a space after pointer qualifiers. - .. code-block:: c++ + ```c++ + PointerAlignment: Left PointerAlignment: Right + void* const * x = NULL; vs. void *const *x = NULL; + ``` - PointerAlignment: Left PointerAlignment: Right - void* const * x = NULL; vs. void *const *x = NULL; - - * ``SAPQ_Both`` (in configuration: ``Both``) + - `SAPQ_Both` (in configuration: `Both`) Ensure that there is a space both before and after pointer qualifiers. - .. code-block:: c++ + ```c++ + PointerAlignment: Left PointerAlignment: Right + void* const * x = NULL; vs. void * const *x = NULL; + ``` - PointerAlignment: Left PointerAlignment: Right - void* const * x = NULL; vs. void * const *x = NULL; +(spacebeforeassignmentoperators)= -.. _SpaceBeforeAssignmentOperators: +**SpaceBeforeAssignmentOperators** (`Boolean`) {versionbadge}`clang-format 3.7` {ref}`¶ ` -**SpaceBeforeAssignmentOperators** (``Boolean``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - If ``false``, spaces will be removed before assignment operators. +: If `false`, spaces will be removed before assignment operators. - .. code-block:: c++ + ```c++ + true: false: + int a = 5; vs. int a= 5; + a += 42; a+= 42; + ``` - true: false: - int a = 5; vs. int a= 5; - a += 42; a+= 42; +(spacebeforecasecolon)= -.. _SpaceBeforeCaseColon: +**SpaceBeforeCaseColon** (`Boolean`) {versionbadge}`clang-format 12` {ref}`¶ ` -**SpaceBeforeCaseColon** (``Boolean``) :versionbadge:`clang-format 12` :ref:`¶ ` - If ``false``, spaces will be removed before case colon. +: If `false`, spaces will be removed before case colon. - .. code-block:: c++ + ```c++ + true: false + switch (x) { vs. switch (x) { + case 1 : break; case 1: break; + } } + ``` - true: false - switch (x) { vs. switch (x) { - case 1 : break; case 1: break; - } } +(spacebeforecpp11bracedlist)= -.. _SpaceBeforeCpp11BracedList: +**SpaceBeforeCpp11BracedList** (`Boolean`) {versionbadge}`clang-format 7` {ref}`¶ ` -**SpaceBeforeCpp11BracedList** (``Boolean``) :versionbadge:`clang-format 7` :ref:`¶ ` - If ``true``, a space will be inserted before a C++11 braced list +: If `true`, a space will be inserted before a C++11 braced list used to initialize an object (after the preceding identifier or type). - .. code-block:: c++ + ```c++ + true: false: + Foo foo { bar }; vs. Foo foo{ bar }; + Foo {}; Foo{}; + vector { 1, 2, 3 }; vector{ 1, 2, 3 }; + new int[3] { 1, 2, 3 }; new int[3]{ 1, 2, 3 }; + ``` - true: false: - Foo foo { bar }; vs. Foo foo{ bar }; - Foo {}; Foo{}; - vector { 1, 2, 3 }; vector{ 1, 2, 3 }; - new int[3] { 1, 2, 3 }; new int[3]{ 1, 2, 3 }; +(spacebeforectorinitializercolon)= -.. _SpaceBeforeCtorInitializerColon: +**SpaceBeforeCtorInitializerColon** (`Boolean`) {versionbadge}`clang-format 7` {ref}`¶ ` -**SpaceBeforeCtorInitializerColon** (``Boolean``) :versionbadge:`clang-format 7` :ref:`¶ ` - If ``false``, spaces will be removed before constructor initializer +: If `false`, spaces will be removed before constructor initializer colon. - .. code-block:: c++ + ```c++ + true: false: + Foo::Foo() : a(a) {} Foo::Foo(): a(a) {} + ``` - true: false: - Foo::Foo() : a(a) {} Foo::Foo(): a(a) {} +(spacebeforeenumunderlyingtypecolon)= -.. _SpaceBeforeEnumUnderlyingTypeColon: +**SpaceBeforeEnumUnderlyingTypeColon** (`Boolean`) {versionbadge}`clang-format 23` {ref}`¶ ` -**SpaceBeforeEnumUnderlyingTypeColon** (``Boolean``) :versionbadge:`clang-format 23` :ref:`¶ ` - If ``false``, spaces will be removed before enum underlying type colon. +: If `false`, spaces will be removed before enum underlying type colon. - .. code-block:: c++ + ```c++ + true: false: + enum E : int {} enum E: int {} + ``` - true: false: - enum E : int {} enum E: int {} +(spacebeforeinheritancecolon)= -.. _SpaceBeforeInheritanceColon: +**SpaceBeforeInheritanceColon** (`Boolean`) {versionbadge}`clang-format 7` {ref}`¶ ` -**SpaceBeforeInheritanceColon** (``Boolean``) :versionbadge:`clang-format 7` :ref:`¶ ` - If ``false``, spaces will be removed before inheritance colon. +: If `false`, spaces will be removed before inheritance colon. - .. code-block:: c++ + ```c++ + true: false: + class Foo : Bar {} vs. class Foo: Bar {} + ``` - true: false: - class Foo : Bar {} vs. class Foo: Bar {} +(spacebeforejsoncolon)= -.. _SpaceBeforeJsonColon: +**SpaceBeforeJsonColon** (`Boolean`) {versionbadge}`clang-format 17` {ref}`¶ ` -**SpaceBeforeJsonColon** (``Boolean``) :versionbadge:`clang-format 17` :ref:`¶ ` - If ``true``, a space will be added before a JSON colon. For other - languages, e.g. JavaScript, use ``SpacesInContainerLiterals`` instead. +: If `true`, a space will be added before a JSON colon. For other + languages, e.g. JavaScript, use `SpacesInContainerLiterals` instead. - .. code-block:: c++ + ```c++ + true: false: + { { + "key" : "value" vs. "key": "value" + } } + ``` - true: false: - { { - "key" : "value" vs. "key": "value" - } } +(spacebeforeparens)= -.. _SpaceBeforeParens: +**SpaceBeforeParens** (`SpaceBeforeParensStyle`) {versionbadge}`clang-format 3.5` {ref}`¶ ` -**SpaceBeforeParens** (``SpaceBeforeParensStyle``) :versionbadge:`clang-format 3.5` :ref:`¶ ` - Defines in which cases to put a space before opening parentheses. +: Defines in which cases to put a space before opening parentheses. Possible values: - * ``SBPO_Never`` (in configuration: ``Never``) - This is **deprecated** and replaced by ``Custom`` below, with all - ``SpaceBeforeParensOptions`` but ``AfterPlacementOperator`` set to - ``false``. + - `SBPO_Never` (in configuration: `Never`) + This is **deprecated** and replaced by `Custom` below, with all + `SpaceBeforeParensOptions` but `AfterPlacementOperator` set to + `false`. - * ``SBPO_ControlStatements`` (in configuration: ``ControlStatements``) + - `SBPO_ControlStatements` (in configuration: `ControlStatements`) Put a space before opening parentheses only after control statement - keywords (``for/if/while...``). - - .. code-block:: c++ + keywords (`for/if/while...`). - void f() { - if (true) { - f(); - } - } + ```c++ + void f() { + if (true) { + f(); + } + } + ``` - * ``SBPO_ControlStatementsExceptControlMacros`` (in configuration: ``ControlStatementsExceptControlMacros``) - Same as ``SBPO_ControlStatements`` except this option doesn't apply to + - `SBPO_ControlStatementsExceptControlMacros` (in configuration: `ControlStatementsExceptControlMacros`) + Same as `SBPO_ControlStatements` except this option doesn't apply to ForEach and If macros. This is useful in projects where ForEach/If macros are treated as function calls instead of control statements. - ``SBPO_ControlStatementsExceptForEachMacros`` remains an alias for + `SBPO_ControlStatementsExceptForEachMacros` remains an alias for backward compatibility. - .. code-block:: c++ - - void f() { - Q_FOREACH(...) { - f(); - } - } + ```c++ + void f() { + Q_FOREACH(...) { + f(); + } + } + ``` - * ``SBPO_NonEmptyParentheses`` (in configuration: ``NonEmptyParentheses``) + - `SBPO_NonEmptyParentheses` (in configuration: `NonEmptyParentheses`) Put a space before opening parentheses only if the parentheses are not empty. - .. code-block:: c++ - - void() { - if (true) { - f(); - g (x, y, z); - } + ```c++ + void() { + if (true) { + f(); + g (x, y, z); } + } + ``` - * ``SBPO_Always`` (in configuration: ``Always``) + - `SBPO_Always` (in configuration: `Always`) Always put a space before opening parentheses, except when it's prohibited by the syntax rules (in function-like macro definitions) or when determined by other style rules (after unary operators, opening parentheses, etc.) - .. code-block:: c++ - - void f () { - if (true) { - f (); - } - } + ```c++ + void f () { + if (true) { + f (); + } + } + ``` - * ``SBPO_Custom`` (in configuration: ``Custom``) + - `SBPO_Custom` (in configuration: `Custom`) Configure each individual space before parentheses in - ``SpaceBeforeParensOptions``. + `SpaceBeforeParensOptions`. -.. _SpaceBeforeParensOptions: +(spacebeforeparensoptions)= -**SpaceBeforeParensOptions** (``SpaceBeforeParensCustom``) :versionbadge:`clang-format 14` :ref:`¶ ` - Control of individual space before parentheses. +**SpaceBeforeParensOptions** (`SpaceBeforeParensCustom`) {versionbadge}`clang-format 14` {ref}`¶ ` - If ``SpaceBeforeParens`` is set to ``Custom``, use this to specify +: Control of individual space before parentheses. + + If `SpaceBeforeParens` is set to `Custom`, use this to specify how each individual space before parentheses case should be handled. Otherwise, this is ignored. - .. code-block:: yaml - - # Example of usage: - SpaceBeforeParens: Custom - SpaceBeforeParensOptions: - AfterControlStatements: true - AfterFunctionDefinitionName: true + ```yaml + # Example of usage: + SpaceBeforeParens: Custom + SpaceBeforeParensOptions: + AfterControlStatements: true + AfterFunctionDefinitionName: true + ``` Nested configuration flags: Precise control over the spacing before parentheses. - .. code-block:: c++ + ```yaml + # Should be declared this way: + SpaceBeforeParens: Custom + SpaceBeforeParensOptions: + AfterControlStatements: true + AfterFunctionDefinitionName: true + ``` - # Should be declared this way: - SpaceBeforeParens: Custom - SpaceBeforeParensOptions: - AfterControlStatements: true - AfterFunctionDefinitionName: true - - * ``bool AfterControlStatements`` If ``true``, put space between control statement keywords + - `bool AfterControlStatements` If `true`, put space between control statement keywords (for/if/while...) and opening parentheses. - .. code-block:: c++ - - true: false: - if (...) {} vs. if(...) {} + ```c++ + true: false: + if (...) {} vs. if(...) {} + ``` - * ``bool AfterForeachMacros`` If ``true``, put space between foreach macros and opening parentheses. + - `bool AfterForeachMacros` If `true`, put space between foreach macros and opening parentheses. - .. code-block:: c++ + ```c++ + true: false: + FOREACH (...) vs. FOREACH(...) + + ``` - true: false: - FOREACH (...) vs. FOREACH(...) - - - * ``bool AfterFunctionDeclarationName`` If ``true``, put a space between function declaration name and opening + - `bool AfterFunctionDeclarationName` If `true`, put a space between function declaration name and opening parentheses. - .. code-block:: c++ - - true: false: - void f (); vs. void f(); + ```c++ + true: false: + void f (); vs. void f(); + ``` - * ``bool AfterFunctionDefinitionName`` If ``true``, put a space between function definition name and opening + - `bool AfterFunctionDefinitionName` If `true`, put a space between function definition name and opening parentheses. - .. code-block:: c++ - - true: false: - void f () {} vs. void f() {} - - * ``bool AfterIfMacros`` If ``true``, put space between if macros and opening parentheses. + ```c++ + true: false: + void f () {} vs. void f() {} + ``` - .. code-block:: c++ + - `bool AfterIfMacros` If `true`, put space between if macros and opening parentheses. - true: false: - IF (...) vs. IF(...) - + ```c++ + true: false: + IF (...) vs. IF(...) + + ``` - * ``bool AfterNot`` If ``true``, put a space between alternative operator ``not`` and the + - `bool AfterNot` If `true`, put a space between alternative operator `not` and the opening parenthesis. - .. code-block:: c++ + ```c++ + true: false: + return not (a || b); vs. return not(a || b); + ``` - true: false: - return not (a || b); vs. return not(a || b); - - * ``bool AfterOverloadedOperator`` If ``true``, put a space between operator overloading and opening + - `bool AfterOverloadedOperator` If `true`, put a space between operator overloading and opening parentheses. - .. code-block:: c++ - - true: false: - void operator++ (int a); vs. void operator++(int a); - object.operator++ (10); object.operator++(10); + ```c++ + true: false: + void operator++ (int a); vs. void operator++(int a); + object.operator++ (10); object.operator++(10); + ``` - * ``bool AfterPlacementOperator`` If ``true``, put a space between operator ``new``/``delete`` and opening + - `bool AfterPlacementOperator` If `true`, put a space between operator `new`/`delete` and opening parenthesis. - .. code-block:: c++ + ```c++ + true: false: + new (buf) T; vs. new(buf) T; + delete (buf) T; delete(buf) T; + ``` - true: false: - new (buf) T; vs. new(buf) T; - delete (buf) T; delete(buf) T; - - * ``bool AfterRequiresInClause`` If ``true``, put space between requires keyword in a requires clause and + - `bool AfterRequiresInClause` If `true`, put space between requires keyword in a requires clause and opening parentheses, if there is one. - .. code-block:: c++ - - true: false: - template vs. template - requires (A && B) requires(A && B) - ... ... + ```c++ + true: false: + template vs. template + requires (A && B) requires(A && B) + ... ... + ``` - * ``bool AfterRequiresInExpression`` If ``true``, put space between requires keyword in a requires expression + - `bool AfterRequiresInExpression` If `true`, put space between requires keyword in a requires expression and opening parentheses. - .. code-block:: c++ + ```c++ + true: false: + template vs. template + concept C = requires (T t) { concept C = requires(T t) { + ... ... + } } + ``` - true: false: - template vs. template - concept C = requires (T t) { concept C = requires(T t) { - ... ... - } } - - * ``bool BeforeNonEmptyParentheses`` If ``true``, put a space before opening parentheses only if the + - `bool BeforeNonEmptyParentheses` If `true`, put a space before opening parentheses only if the parentheses are not empty. - .. code-block:: c++ + ```c++ + true: false: + void f (int a); vs. void f(); + f (a); f(); + ``` - true: false: - void f (int a); vs. void f(); - f (a); f(); +(spacebeforerangebasedforloopcolon)= -.. _SpaceBeforeRangeBasedForLoopColon: +**SpaceBeforeRangeBasedForLoopColon** (`Boolean`) {versionbadge}`clang-format 7` {ref}`¶ ` -**SpaceBeforeRangeBasedForLoopColon** (``Boolean``) :versionbadge:`clang-format 7` :ref:`¶ ` - If ``false``, spaces will be removed before range-based for loop +: If `false`, spaces will be removed before range-based for loop colon. - .. code-block:: c++ + ```c++ + true: false: + for (auto v : values) {} vs. for(auto v: values) {} + ``` - true: false: - for (auto v : values) {} vs. for(auto v: values) {} +(spacebeforesquarebrackets)= -.. _SpaceBeforeSquareBrackets: +**SpaceBeforeSquareBrackets** (`Boolean`) {versionbadge}`clang-format 10` {ref}`¶ ` -**SpaceBeforeSquareBrackets** (``Boolean``) :versionbadge:`clang-format 10` :ref:`¶ ` - If ``true``, spaces will be before ``[``. - Lambdas will not be affected. Only the first ``[`` will get a space added. +: If `true`, spaces will be before `[`. + Lambdas will not be affected. Only the first `[` will get a space added. - .. code-block:: c++ + ```c++ + true: false: + int a [5]; vs. int a[5]; + int a [5][5]; vs. int a[5][5]; + ``` - true: false: - int a [5]; vs. int a[5]; - int a [5][5]; vs. int a[5][5]; +(spaceinemptyblock)= -.. _SpaceInEmptyBlock: +**SpaceInEmptyBlock** (`Boolean`) {versionbadge}`clang-format 10` {ref}`¶ ` -**SpaceInEmptyBlock** (``Boolean``) :versionbadge:`clang-format 10` :ref:`¶ ` - This option is **deprecated**. See ``Block`` of ``SpaceInEmptyBraces``. +: This option is **deprecated**. See `Block` of `SpaceInEmptyBraces`. -.. _SpaceInEmptyBraces: +(spaceinemptybraces)= -**SpaceInEmptyBraces** (``SpaceInEmptyBracesStyle``) :versionbadge:`clang-format 22` :ref:`¶ ` - Specifies when to insert a space in empty braces. +**SpaceInEmptyBraces** (`SpaceInEmptyBracesStyle`) {versionbadge}`clang-format 22` {ref}`¶ ` - .. note:: +: Specifies when to insert a space in empty braces. - This option doesn't apply to initializer braces if - ``Cpp11BracedListStyle`` is not ``Block``. + :::{note} + This option doesn't apply to initializer braces if + `Cpp11BracedListStyle` is not `Block`. + ::: Possible values: - * ``SIEB_Always`` (in configuration: ``Always``) + - `SIEB_Always` (in configuration: `Always`) Always insert a space in empty braces. - .. code-block:: c++ - - void f() { } - class Unit { }; - auto a = [] { }; - int x{ }; + ```c++ + void f() { } + class Unit { }; + auto a = [] { }; + int x{ }; + ``` - * ``SIEB_Block`` (in configuration: ``Block``) + - `SIEB_Block` (in configuration: `Block`) Only insert a space in empty blocks. - .. code-block:: c++ + ```c++ + void f() { } + class Unit { }; + auto a = [] { }; + int x{}; + ``` - void f() { } - class Unit { }; - auto a = [] { }; - int x{}; - - * ``SIEB_Never`` (in configuration: ``Never``) + - `SIEB_Never` (in configuration: `Never`) Never insert a space in empty braces. - .. code-block:: c++ + ```c++ + void f() {} + class Unit {}; + auto a = [] {}; + int x{}; + ``` + - void f() {} - class Unit {}; - auto a = [] {}; - int x{}; +(spaceinemptyparentheses)= +**SpaceInEmptyParentheses** (`Boolean`) {versionbadge}`clang-format 3.7` {ref}`¶ ` -.. _SpaceInEmptyParentheses: +: If `true`, spaces may be inserted into `()`. + This option is **deprecated**. See `InEmptyParentheses` of + `SpacesInParensOptions`. -**SpaceInEmptyParentheses** (``Boolean``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - If ``true``, spaces may be inserted into ``()``. - This option is **deprecated**. See ``InEmptyParentheses`` of - ``SpacesInParensOptions``. +(spacesbeforetrailingcomments)= -.. _SpacesBeforeTrailingComments: +**SpacesBeforeTrailingComments** (`Unsigned`) {versionbadge}`clang-format 3.7` {ref}`¶ ` -**SpacesBeforeTrailingComments** (``Unsigned``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - The number of spaces before trailing line comments - (``//`` - comments). +: The number of spaces before trailing line comments + (`//` - comments). - This does not affect trailing block comments (``/*`` - comments) as those + This does not affect trailing block comments (`/*` - comments) as those commonly have different usage patterns and a number of special cases. In the case of Verilog, it doesn't affect a comment right after the opening parenthesis in the port or parameter list in a module header, because it is probably for the port on the following line instead of the parenthesis it follows. - .. code-block:: c++ + ```c++ + SpacesBeforeTrailingComments: 3 + void f() { + if (true) { // foo1 + f(); // bar + } // foo + } + ``` - SpacesBeforeTrailingComments: 3 - void f() { - if (true) { // foo1 - f(); // bar - } // foo - } +(spacesinangles)= -.. _SpacesInAngles: +**SpacesInAngles** (`SpacesInAnglesStyle`) {versionbadge}`clang-format 3.4` {ref}`¶ ` -**SpacesInAngles** (``SpacesInAnglesStyle``) :versionbadge:`clang-format 3.4` :ref:`¶ ` - The SpacesInAnglesStyle to use for template argument lists. +: The SpacesInAnglesStyle to use for template argument lists. Possible values: - * ``SIAS_Never`` (in configuration: ``Never``) - Remove spaces after ``<`` and before ``>``. + - `SIAS_Never` (in configuration: `Never`) + Remove spaces after `<` and before `>`. - .. code-block:: c++ + ```c++ + static_cast(arg); + std::function fct; + ``` - static_cast(arg); - std::function fct; + - `SIAS_Always` (in configuration: `Always`) + Add spaces after `<` and before `>`. - * ``SIAS_Always`` (in configuration: ``Always``) - Add spaces after ``<`` and before ``>``. + ```c++ + static_cast< int >(arg); + std::function< void(int) > fct; + ``` - .. code-block:: c++ + - `SIAS_Leave` (in configuration: `Leave`) + Keep a single space after `<` and before `>` if any spaces were + present. Option `Standard: Cpp03` takes precedence. - static_cast< int >(arg); - std::function< void(int) > fct; - * ``SIAS_Leave`` (in configuration: ``Leave``) - Keep a single space after ``<`` and before ``>`` if any spaces were - present. Option ``Standard: Cpp03`` takes precedence. +(spacesinblockcomments)= +**SpacesInBlockComments** (`SpacesInBlockCommentsStyle`) {versionbadge}`clang-format 24` {ref}`¶ ` -.. _SpacesInBlockComments: - -**SpacesInBlockComments** (``SpacesInBlockCommentsStyle``) :versionbadge:`clang-format 24` :ref:`¶ ` - The SpacesInBlockCommentsStyle to use for ordinary block comments. - Documentation comments such as ``/** ... */`` and ``/*! ... */`` - and parameter comments ending with ``=`` before the closing ``*/`` are +: The SpacesInBlockCommentsStyle to use for ordinary block comments. + Documentation comments such as `/** ... */` and `/*! ... */` + and parameter comments ending with `=` before the closing `*/` are left unchanged. Possible values: - * ``SIBCS_Never`` (in configuration: ``Never``) - Remove spaces after ``/*`` and before ``*/``. + - `SIBCS_Never` (in configuration: `Never`) + Remove spaces after `/*` and before `*/`. - .. code-block:: c++ + ```c++ + /*comment*/ + ``` - /*comment*/ + - `SIBCS_Always` (in configuration: `Always`) + Add spaces after `/*` and before `*/`. - * ``SIBCS_Always`` (in configuration: ``Always``) - Add spaces after ``/*`` and before ``*/``. + ```c++ + /* comment */ + ``` - .. code-block:: c++ + - `SIBCS_Leave` (in configuration: `Leave`) + Leave existing spaces unchanged. - /* comment */ - * ``SIBCS_Leave`` (in configuration: ``Leave``) - Leave existing spaces unchanged. +(spacesincstylecastparentheses)= +**SpacesInCStyleCastParentheses** (`Boolean`) {versionbadge}`clang-format 3.7` {ref}`¶ ` -.. _SpacesInCStyleCastParentheses: +: If `true`, spaces may be inserted into C style casts. + This option is **deprecated**. See `InCStyleCasts` of + `SpacesInParensOptions`. -**SpacesInCStyleCastParentheses** (``Boolean``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - If ``true``, spaces may be inserted into C style casts. - This option is **deprecated**. See ``InCStyleCasts`` of - ``SpacesInParensOptions``. +(spacesinconditionalstatement)= -.. _SpacesInConditionalStatement: +**SpacesInConditionalStatement** (`Boolean`) {versionbadge}`clang-format 10` {ref}`¶ ` -**SpacesInConditionalStatement** (``Boolean``) :versionbadge:`clang-format 10` :ref:`¶ ` - If ``true``, spaces will be inserted around if/for/switch/while +: If `true`, spaces will be inserted around if/for/switch/while conditions. - This option is **deprecated**. See ``InConditionalStatements`` of - ``SpacesInParensOptions``. + This option is **deprecated**. See `InConditionalStatements` of + `SpacesInParensOptions`. + +(spacesincontainerliterals)= -.. _SpacesInContainerLiterals: +**SpacesInContainerLiterals** (`Boolean`) {versionbadge}`clang-format 3.7` {ref}`¶ ` -**SpacesInContainerLiterals** (``Boolean``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - If ``true``, spaces are inserted inside container literals (e.g. ObjC and +: If `true`, spaces are inserted inside container literals (e.g. ObjC and Javascript array and dict literals). For JSON, use - ``SpaceBeforeJsonColon`` instead. + `SpaceBeforeJsonColon` instead. - .. code-block:: js + ```js + true: false: + var arr = [ 1, 2, 3 ]; vs. var arr = [1, 2, 3]; + f({a : 1, b : 2, c : 3}); f({a: 1, b: 2, c: 3}); + ``` - true: false: - var arr = [ 1, 2, 3 ]; vs. var arr = [1, 2, 3]; - f({a : 1, b : 2, c : 3}); f({a: 1, b: 2, c: 3}); +(spacesinlinecommentprefix)= -.. _SpacesInLineCommentPrefix: +**SpacesInLineCommentPrefix** (`SpacesInLineComment`) {versionbadge}`clang-format 13` {ref}`¶ ` -**SpacesInLineCommentPrefix** (``SpacesInLineComment``) :versionbadge:`clang-format 13` :ref:`¶ ` - How many spaces are allowed at the start of a line comment. To disable the - maximum set it to ``-1``, apart from that the maximum takes precedence +: How many spaces are allowed at the start of a line comment. To disable the + maximum set it to `-1`, apart from that the maximum takes precedence over the minimum. - .. code-block:: c++ + ```c++ + Minimum = 1 + Maximum = -1 + // One space is forced - Minimum = 1 - Maximum = -1 - // One space is forced + // but more spaces are possible - // but more spaces are possible - - Minimum = 0 - Maximum = 0 - //Forces to start every comment directly after the slashes + Minimum = 0 + Maximum = 0 + //Forces to start every comment directly after the slashes + ``` Note that in line comment sections the relative indent of the subsequent lines is kept, that means the following: - .. code-block:: c++ - - before: after: - Minimum: 1 - //if (b) { // if (b) { - // return true; // return true; - //} // } + ```c++ + before: after: + Minimum: 1 + //if (b) { // if (b) { + // return true; // return true; + //} // } - Maximum: 0 - /// List: ///List: - /// - Foo /// - Foo - /// - Bar /// - Bar + Maximum: 0 + /// List: ///List: + /// - Foo /// - Foo + /// - Bar /// - Bar + ``` - This option has only effect if ``ReflowComments`` is set to ``true``. + This option has only effect if `ReflowComments` is set to `true`. Nested configuration flags: Control of spaces within a single line comment. - * ``unsigned Minimum`` The minimum number of spaces at the start of the comment. + - `unsigned Minimum` The minimum number of spaces at the start of the comment. - * ``unsigned Maximum`` The maximum number of spaces at the start of the comment. + - `unsigned Maximum` The maximum number of spaces at the start of the comment. -.. _SpacesInParens: +(spacesinparens)= -**SpacesInParens** (``SpacesInParensStyle``) :versionbadge:`clang-format 17` :ref:`¶ ` - Defines in which cases spaces will be inserted after ``(`` and before - ``)``. +**SpacesInParens** (`SpacesInParensStyle`) {versionbadge}`clang-format 17` {ref}`¶ ` + +: Defines in which cases spaces will be inserted after `(` and before + `)`. Possible values: - * ``SIPO_Never`` (in configuration: ``Never``) + - `SIPO_Never` (in configuration: `Never`) Never put a space in parentheses. - .. code-block:: c++ - - void f() { - if(true) { - f(); - } - } + ```c++ + void f() { + if(true) { + f(); + } + } + ``` - * ``SIPO_Custom`` (in configuration: ``Custom``) + - `SIPO_Custom` (in configuration: `Custom`) Configure each individual space in parentheses in `SpacesInParensOptions`. -.. _SpacesInParensOptions: +(spacesinparensoptions)= -**SpacesInParensOptions** (``SpacesInParensCustom``) :versionbadge:`clang-format 17` :ref:`¶ ` - Control of individual spaces in parentheses. +**SpacesInParensOptions** (`SpacesInParensCustom`) {versionbadge}`clang-format 17` {ref}`¶ ` - If ``SpacesInParens`` is set to ``Custom``, use this to specify +: Control of individual spaces in parentheses. + + If `SpacesInParens` is set to `Custom`, use this to specify how each individual space in parentheses case should be handled. Otherwise, this is ignored. - .. code-block:: yaml - - # Example of usage: - SpacesInParens: Custom - SpacesInParensOptions: - ExceptDoubleParentheses: false - InConditionalStatements: true - InEmptyParentheses: true + ```yaml + # Example of usage: + SpacesInParens: Custom + SpacesInParensOptions: + ExceptDoubleParentheses: false + InConditionalStatements: true + InEmptyParentheses: true + ``` Nested configuration flags: Precise control over the spacing in parentheses. - .. code-block:: c++ + ```yaml + # Should be declared this way: + SpacesInParens: Custom + SpacesInParensOptions: + ExceptDoubleParentheses: false + InConditionalStatements: true + Other: true + ``` - # Should be declared this way: - SpacesInParens: Custom - SpacesInParensOptions: - ExceptDoubleParentheses: false - InConditionalStatements: true - Other: true - - * ``bool ExceptDoubleParentheses`` Override any of the following options to prevent addition of space + - `bool ExceptDoubleParentheses` Override any of the following options to prevent addition of space when both opening and closing parentheses use multiple parentheses. - .. code-block:: c++ - - true: - __attribute__(( noreturn )) - __decltype__(( x )) - if (( a = b )) + ```c++ + true: + __attribute__(( noreturn )) + __decltype__(( x )) + if (( a = b )) false: Uses the applicable option. + ``` - * ``bool InConditionalStatements`` Put a space in parentheses only inside conditional statements - (``for/if/while/switch...``). - - .. code-block:: c++ - true: false: - if ( a ) { ... } vs. if (a) { ... } - while ( i < 5 ) { ... } while (i < 5) { ... } + - `bool InConditionalStatements` Put a space in parentheses only inside conditional statements + (`for/if/while/switch...`). - * ``bool InCStyleCasts`` Put a space in C style casts. + ```c++ + true: false: + if ( a ) { ... } vs. if (a) { ... } + while ( i < 5 ) { ... } while (i < 5) { ... } + ``` - .. code-block:: c++ + - `bool InCStyleCasts` Put a space in C style casts. - true: false: - x = ( int32 )y vs. x = (int32)y - y = (( int (*)(int) )foo)(x); y = ((int (*)(int))foo)(x); + ```c++ + true: false: + x = ( int32 )y vs. x = (int32)y + y = (( int (*)(int) )foo)(x); y = ((int (*)(int))foo)(x); + ``` - * ``bool InEmptyParentheses`` Insert a space in empty parentheses, i.e. ``()``. + - `bool InEmptyParentheses` Insert a space in empty parentheses, i.e. `()`. - .. code-block:: c++ + ```c++ + true: false: + void f( ) { vs. void f() { + int x[] = {foo( ), bar( )}; int x[] = {foo(), bar()}; + if (true) { if (true) { + f( ); f(); + } } + } } + ``` - true: false: - void f( ) { vs. void f() { - int x[] = {foo( ), bar( )}; int x[] = {foo(), bar()}; - if (true) { if (true) { - f( ); f(); - } } - } } + - `bool Other` Put a space in parentheses not covered by preceding options. - * ``bool Other`` Put a space in parentheses not covered by preceding options. + ```c++ + true: false: + t f( Deleted & ) & = delete; vs. t f(Deleted &) & = delete; + ``` - .. code-block:: c++ - true: false: - t f( Deleted & ) & = delete; vs. t f(Deleted &) & = delete; +(spacesinparentheses)= +**SpacesInParentheses** (`Boolean`) {versionbadge}`clang-format 3.7` {ref}`¶ ` -.. _SpacesInParentheses: - -**SpacesInParentheses** (``Boolean``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - If ``true``, spaces will be inserted after ``(`` and before ``)``. +: If `true`, spaces will be inserted after `(` and before `)`. This option is **deprecated**. The previous behavior is preserved by using - ``SpacesInParens`` with ``Custom`` and by setting all - ``SpacesInParensOptions`` to ``true`` except for ``InCStyleCasts`` and - ``InEmptyParentheses``. + `SpacesInParens` with `Custom` and by setting all + `SpacesInParensOptions` to `true` except for `InCStyleCasts` and + `InEmptyParentheses`. + +(spacesinsquarebrackets)= -.. _SpacesInSquareBrackets: +**SpacesInSquareBrackets** (`Boolean`) {versionbadge}`clang-format 3.7` {ref}`¶ ` -**SpacesInSquareBrackets** (``Boolean``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - If ``true``, spaces will be inserted after ``[`` and before ``]``. +: If `true`, spaces will be inserted after `[` and before `]`. Lambdas without arguments or unspecified size array declarations will not be affected. - .. code-block:: c++ + ```c++ + true: false: + int a[ 5 ]; vs. int a[5]; + std::unique_ptr foo() {} // Won't be affected + ``` - true: false: - int a[ 5 ]; vs. int a[5]; - std::unique_ptr foo() {} // Won't be affected +(standard)= -.. _Standard: +**Standard** (`LanguageStandard`) {versionbadge}`clang-format 3.7` {ref}`¶ ` -**Standard** (``LanguageStandard``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - Parse and format C++ constructs compatible with this standard. +: Parse and format C++ constructs compatible with this standard. - .. code-block:: c++ - - c++03: latest: - vector > x; vs. vector> x; + ```c++ + c++03: latest: + vector > x; vs. vector> x; + ``` Possible values: - * ``LS_Cpp03`` (in configuration: ``c++03``) + - `LS_Cpp03` (in configuration: `c++03`) Parse and format as C++03. - ``Cpp03`` is a deprecated alias for ``c++03`` + `Cpp03` is a deprecated alias for `c++03` - * ``LS_Cpp11`` (in configuration: ``c++11``) + - `LS_Cpp11` (in configuration: `c++11`) Parse and format as C++11. - * ``LS_Cpp14`` (in configuration: ``c++14``) + - `LS_Cpp14` (in configuration: `c++14`) Parse and format as C++14. - * ``LS_Cpp17`` (in configuration: ``c++17``) + - `LS_Cpp17` (in configuration: `c++17`) Parse and format as C++17. - * ``LS_Cpp20`` (in configuration: ``c++20``) + - `LS_Cpp20` (in configuration: `c++20`) Parse and format as C++20. - * ``LS_Cpp23`` (in configuration: ``c++23``) + - `LS_Cpp23` (in configuration: `c++23`) Parse and format as C++23. - * ``LS_Cpp26`` (in configuration: ``c++26``) + - `LS_Cpp26` (in configuration: `c++26`) Parse and format as C++26. - * ``LS_Latest`` (in configuration: ``Latest``) + - `LS_Latest` (in configuration: `Latest`) Parse and format using the latest supported language version. - ``Cpp11`` is a deprecated alias for ``Latest`` + `Cpp11` is a deprecated alias for `Latest` - * ``LS_Auto`` (in configuration: ``Auto``) + - `LS_Auto` (in configuration: `Auto`) Automatic detection based on the input. -.. _StatementAttributeLikeMacros: +(statementattributelikemacros)= + +**StatementAttributeLikeMacros** (`List of Strings`) {versionbadge}`clang-format 12` {ref}`¶ ` -**StatementAttributeLikeMacros** (``List of Strings``) :versionbadge:`clang-format 12` :ref:`¶ ` - Macros which are ignored in front of a statement, as if they were an +: Macros which are ignored in front of a statement, as if they were an attribute. So that they are not parsed as identifier, for example for Qts emit. - .. code-block:: c++ + ```c++ + AlignConsecutiveDeclarations: true + StatementAttributeLikeMacros: [] + unsigned char data = 'x'; + emit signal(data); // This is parsed as variable declaration. - AlignConsecutiveDeclarations: true - StatementAttributeLikeMacros: [] - unsigned char data = 'x'; - emit signal(data); // This is parsed as variable declaration. + AlignConsecutiveDeclarations: true + StatementAttributeLikeMacros: [emit] + unsigned char data = 'x'; + emit signal(data); // Now it's fine again. + ``` - AlignConsecutiveDeclarations: true - StatementAttributeLikeMacros: [emit] - unsigned char data = 'x'; - emit signal(data); // Now it's fine again. +(statementmacros)= -.. _StatementMacros: +**StatementMacros** (`List of Strings`) {versionbadge}`clang-format 8` {ref}`¶ ` -**StatementMacros** (``List of Strings``) :versionbadge:`clang-format 8` :ref:`¶ ` - A vector of macros that should be interpreted as complete statements. +: A vector of macros that should be interpreted as complete statements. Typical macros are expressions and require a semicolon to be added. Sometimes this is not the case, and this allows to make clang-format aware @@ -7706,50 +7876,53 @@ the configuration (without a prefix: ``Auto``). For example: Q_UNUSED -.. _TabWidth: +(tabwidth)= -**TabWidth** (``Unsigned``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - The number of columns used for tab stops. +**TabWidth** (`Unsigned`) {versionbadge}`clang-format 3.7` {ref}`¶ ` -.. _TableGenBreakInsideDAGArg: +: The number of columns used for tab stops. -**TableGenBreakInsideDAGArg** (``DAGArgStyle``) :versionbadge:`clang-format 19` :ref:`¶ ` - The styles of the line break inside the DAGArg in TableGen. +(tablegenbreakinsidedagarg)= + +**TableGenBreakInsideDAGArg** (`DAGArgStyle`) {versionbadge}`clang-format 19` {ref}`¶ ` + +: The styles of the line break inside the DAGArg in TableGen. Possible values: - * ``DAS_DontBreak`` (in configuration: ``DontBreak``) + - `DAS_DontBreak` (in configuration: `DontBreak`) Never break inside DAGArg. - .. code-block:: c++ + ```c++ + let DAGArgIns = (ins i32:$src1, i32:$src2); + ``` - let DAGArgIns = (ins i32:$src1, i32:$src2); - - * ``DAS_BreakElements`` (in configuration: ``BreakElements``) + - `DAS_BreakElements` (in configuration: `BreakElements`) Break inside DAGArg after each list element but for the last. This aligns to the first element. - .. code-block:: c++ - - let DAGArgIns = (ins i32:$src1, - i32:$src2); + ```c++ + let DAGArgIns = (ins i32:$src1, + i32:$src2); + ``` - * ``DAS_BreakAll`` (in configuration: ``BreakAll``) + - `DAS_BreakAll` (in configuration: `BreakAll`) Break inside DAGArg after the operator and the all elements. - .. code-block:: c++ + ```c++ + let DAGArgIns = (ins + i32:$src1, + i32:$src2 + ); + ``` - let DAGArgIns = (ins - i32:$src1, - i32:$src2 - ); +(tablegenbreakingdagargoperators)= -.. _TableGenBreakingDAGArgOperators: +**TableGenBreakingDAGArgOperators** (`List of Strings`) {versionbadge}`clang-format 19` {ref}`¶ ` -**TableGenBreakingDAGArgOperators** (``List of Strings``) :versionbadge:`clang-format 19` :ref:`¶ ` - Works only when TableGenBreakInsideDAGArg is not DontBreak. +: Works only when TableGenBreakInsideDAGArg is not DontBreak. The string list needs to consist of identifiers in TableGen. If any identifier is specified, this limits the line breaks by TableGenBreakInsideDAGArg option only on DAGArg values beginning with @@ -7757,183 +7930,190 @@ the configuration (without a prefix: ``Auto``). For example the configuration, - .. code-block:: yaml - - TableGenBreakInsideDAGArg: BreakAll - TableGenBreakingDAGArgOperators: [ins, outs] + ```yaml + TableGenBreakInsideDAGArg: BreakAll + TableGenBreakingDAGArgOperators: [ins, outs] + ``` makes the line break only occurs inside DAGArgs beginning with the - specified identifiers ``ins`` and ``outs``. - + specified identifiers `ins` and `outs`. - .. code-block:: c++ + ```c++ + let DAGArgIns = (ins + i32:$src1, + i32:$src2 + ); + let DAGArgOtherID = (other i32:$other1, i32:$other2); + let DAGArgBang = (!cast("Some") i32:$src1, i32:$src2) + ``` - let DAGArgIns = (ins - i32:$src1, - i32:$src2 - ); - let DAGArgOtherID = (other i32:$other1, i32:$other2); - let DAGArgBang = (!cast("Some") i32:$src1, i32:$src2) +(templatenames)= -.. _TemplateNames: +**TemplateNames** (`List of Strings`) {versionbadge}`clang-format 20` {ref}`¶ ` -**TemplateNames** (``List of Strings``) :versionbadge:`clang-format 20` :ref:`¶ ` - A vector of non-keyword identifiers that should be interpreted as template +: A vector of non-keyword identifiers that should be interpreted as template names. - A ``<`` after a template name is annotated as a template opener instead of + A `<` after a template name is annotated as a template opener instead of a binary operator. -.. _TypeNames: +(typenames)= -**TypeNames** (``List of Strings``) :versionbadge:`clang-format 17` :ref:`¶ ` - A vector of non-keyword identifiers that should be interpreted as type +**TypeNames** (`List of Strings`) {versionbadge}`clang-format 17` {ref}`¶ ` + +: A vector of non-keyword identifiers that should be interpreted as type names. - A ``*``, ``&``, or ``&&`` between a type name and another non-keyword + A `*`, `&`, or `&&` between a type name and another non-keyword identifier is annotated as a pointer or reference token instead of a binary operator. -.. _TypenameMacros: +(typenamemacros)= + +**TypenameMacros** (`List of Strings`) {versionbadge}`clang-format 9` {ref}`¶ ` -**TypenameMacros** (``List of Strings``) :versionbadge:`clang-format 9` :ref:`¶ ` - A vector of macros that should be interpreted as type declarations instead +: A vector of macros that should be interpreted as type declarations instead of as function calls. These are expected to be macros of the form: - .. code-block:: c++ - - STACK_OF(...) + ```c++ + STACK_OF(...) + ``` In the .clang-format configuration file, this can be configured like: - .. code-block:: yaml - - TypenameMacros: [STACK_OF, LIST] + ```yaml + TypenameMacros: [STACK_OF, LIST] + ``` For example: OpenSSL STACK_OF, BSD LIST_ENTRY. -.. _UseCRLF: +(usecrlf)= + +**UseCRLF** (`Boolean`) {versionbadge}`clang-format 10` {ref}`¶ ` + +: This option is **deprecated**. See `LF` and `CRLF` of `LineEnding`. -**UseCRLF** (``Boolean``) :versionbadge:`clang-format 10` :ref:`¶ ` - This option is **deprecated**. See ``LF`` and ``CRLF`` of ``LineEnding``. +(usetab)= -.. _UseTab: +**UseTab** (`UseTabStyle`) {versionbadge}`clang-format 3.7` {ref}`¶ ` -**UseTab** (``UseTabStyle``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - The way to use tab characters in the resulting file. +: The way to use tab characters in the resulting file. Possible values: - * ``UT_Never`` (in configuration: ``Never``) + - `UT_Never` (in configuration: `Never`) Never use tab. - * ``UT_ForIndentation`` (in configuration: ``ForIndentation``) + - `UT_ForIndentation` (in configuration: `ForIndentation`) Use tabs only for indentation. - * ``UT_ForContinuationAndIndentation`` (in configuration: ``ForContinuationAndIndentation``) + - `UT_ForContinuationAndIndentation` (in configuration: `ForContinuationAndIndentation`) Fill all leading whitespace with tabs, and use spaces for alignment that appears within a line (e.g. consecutive assignments and declarations). - * ``UT_AlignWithSpaces`` (in configuration: ``AlignWithSpaces``) + - `UT_AlignWithSpaces` (in configuration: `AlignWithSpaces`) Use tabs for line continuation and indentation, and spaces for alignment. - * ``UT_Always`` (in configuration: ``Always``) + - `UT_Always` (in configuration: `Always`) Use tabs whenever we need to fill whitespace that spans at least from one tab stop to the next one. -.. _VariableTemplates: +(variabletemplates)= -**VariableTemplates** (``List of Strings``) :versionbadge:`clang-format 20` :ref:`¶ ` - A vector of non-keyword identifiers that should be interpreted as variable +**VariableTemplates** (`List of Strings`) {versionbadge}`clang-format 20` {ref}`¶ ` + +: A vector of non-keyword identifiers that should be interpreted as variable template names. - A ``)`` after a variable template instantiation is **not** annotated as + A `)` after a variable template instantiation is **not** annotated as the closing parenthesis of C-style cast operator. -.. _VerilogBreakBetweenInstancePorts: +(verilogbreakbetweeninstanceports)= -**VerilogBreakBetweenInstancePorts** (``Boolean``) :versionbadge:`clang-format 17` :ref:`¶ ` - For Verilog, put each port on its own line in module instantiations. +**VerilogBreakBetweenInstancePorts** (`Boolean`) {versionbadge}`clang-format 17` {ref}`¶ ` - .. code-block:: c++ +: For Verilog, put each port on its own line in module instantiations. - true: - ffnand ff1(.q(), - .qbar(out1), - .clear(in1), - .preset(in2)); + ```c++ + true: + ffnand ff1(.q(), + .qbar(out1), + .clear(in1), + .preset(in2)); - false: - ffnand ff1(.q(), .qbar(out1), .clear(in1), .preset(in2)); + false: + ffnand ff1(.q(), .qbar(out1), .clear(in1), .preset(in2)); + ``` -.. _WhitespaceSensitiveMacros: +(whitespacesensitivemacros)= -**WhitespaceSensitiveMacros** (``List of Strings``) :versionbadge:`clang-format 11` :ref:`¶ ` - A vector of macros which are whitespace-sensitive and should not +**WhitespaceSensitiveMacros** (`List of Strings`) {versionbadge}`clang-format 11` {ref}`¶ ` + +: A vector of macros which are whitespace-sensitive and should not be touched. These are expected to be macros of the form: - .. code-block:: c++ - - STRINGIZE(...) + ```c++ + STRINGIZE(...) + ``` In the .clang-format configuration file, this can be configured like: - .. code-block:: yaml - - WhitespaceSensitiveMacros: [STRINGIZE, PP_STRINGIZE] + ```yaml + WhitespaceSensitiveMacros: [STRINGIZE, PP_STRINGIZE] + ``` For example: BOOST_PP_STRINGIZE -.. _WrapNamespaceBodyWithEmptyLines: +(wrapnamespacebodywithemptylines)= + +**WrapNamespaceBodyWithEmptyLines** (`WrapNamespaceBodyWithEmptyLinesStyle`) {versionbadge}`clang-format 20` {ref}`¶ ` -**WrapNamespaceBodyWithEmptyLines** (``WrapNamespaceBodyWithEmptyLinesStyle``) :versionbadge:`clang-format 20` :ref:`¶ ` - Wrap namespace body with empty lines. +: Wrap namespace body with empty lines. Possible values: - * ``WNBWELS_Never`` (in configuration: ``Never``) + - `WNBWELS_Never` (in configuration: `Never`) Remove all empty lines at the beginning and the end of namespace body. - .. code-block:: c++ - - namespace N1 { - namespace N2 { - function(); - } - } + ```c++ + namespace N1 { + namespace N2 { + function(); + } + } + ``` - * ``WNBWELS_Always`` (in configuration: ``Always``) + - `WNBWELS_Always` (in configuration: `Always`) Always have at least one empty line at the beginning and the end of namespace body except that the number of empty lines between consecutive nested namespace definitions is not increased. - .. code-block:: c++ - - namespace N1 { - namespace N2 { + ```c++ + namespace N1 { + namespace N2 { - function(); + function(); - } - } + } + } + ``` - * ``WNBWELS_Leave`` (in configuration: ``Leave``) + - `WNBWELS_Leave` (in configuration: `Leave`) Keep existing newlines at the beginning and the end of namespace body. - ``MaxEmptyLinesToKeep`` still applies. + `MaxEmptyLinesToKeep` still applies. -.. END_FORMAT_STYLE_OPTIONS +% END_FORMAT_STYLE_OPTIONS -Adding additional style options -=============================== +## Adding additional style options Each additional style option adds costs to the clang-format project. Some of these costs affect the clang-format development itself, as we need to make @@ -7948,96 +8128,94 @@ used by a codebase somewhere in the wild. Of course, we do want to support all major projects and thus have established the following bar for adding style options. Each new style option must: - * be used in a project of significant size (have dozens of contributors) - * have a publicly accessible style guide - * have a person willing to contribute and maintain patches +> - be used in a project of significant size (have dozens of contributors) +> - have a publicly accessible style guide +> - have a person willing to contribute and maintain patches -Examples -======== +## Examples -A style similar to the `Linux Kernel style -`_: +A style similar to the [Linux Kernel style](https://www.kernel.org/doc/html/latest/process/coding-style.html): -.. code-block:: yaml - - BasedOnStyle: LLVM - IndentWidth: 8 - UseTab: Always - BreakBeforeBraces: Linux - AllowShortIfStatementsOnASingleLine: false - IndentCaseLabels: false +```yaml +BasedOnStyle: LLVM +IndentWidth: 8 +UseTab: Always +BreakBeforeBraces: Linux +AllowShortIfStatementsOnASingleLine: false +IndentCaseLabels: false +``` The result is (imagine that tabs are used for indentation here): -.. code-block:: c++ +```c++ +void test() +{ + switch (x) { + case 0: + case 1: + do_something(); + break; + case 2: + do_something_else(); + break; + default: + break; + } + if (condition) + do_something_completely_different(); - void test() - { - switch (x) { - case 0: - case 1: - do_something(); - break; - case 2: - do_something_else(); - break; - default: - break; - } - if (condition) - do_something_completely_different(); - - if (x == y) { - q(); - } else if (x > y) { - w(); - } else { - r(); - } - } + if (x == y) { + q(); + } else if (x > y) { + w(); + } else { + r(); + } +} +``` A style similar to the default Visual Studio formatting style: -.. code-block:: yaml - - UseTab: Never - IndentWidth: 4 - BreakBeforeBraces: Allman - AllowShortIfStatementsOnASingleLine: false - IndentCaseLabels: false - ColumnLimit: 0 +```yaml +UseTab: Never +IndentWidth: 4 +BreakBeforeBraces: Allman +AllowShortIfStatementsOnASingleLine: false +IndentCaseLabels: false +ColumnLimit: 0 +``` The result is: -.. code-block:: c++ - - void test() - { - switch (suffix) - { - case 0: - case 1: - do_something(); - break; - case 2: - do_something_else(); - break; - default: - break; - } - if (condition) - do_something_completely_different(); +```c++ +void test() +{ + switch (suffix) + { + case 0: + case 1: + do_something(); + break; + case 2: + do_something_else(); + break; + default: + break; + } + if (condition) + do_something_completely_different(); - if (x == y) - { - q(); - } - else if (x > y) - { - w(); - } - else - { - r(); - } - } + if (x == y) + { + q(); + } + else if (x > y) + { + w(); + } + else + { + r(); + } +} +``` diff --git a/clang/docs/tools/dump_format_help.py b/clang/docs/tools/dump_format_help.py index 7ef22dcad3a13..a733c344c3bdd 100755 --- a/clang/docs/tools/dump_format_help.py +++ b/clang/docs/tools/dump_format_help.py @@ -13,8 +13,8 @@ def substitute(text, tag, contents): - replacement = "\n.. START_%s\n\n%s\n\n.. END_%s\n" % (tag, contents, tag) - pattern = r"\n\.\. START_%s\n.*\n\.\. END_%s\n" % (tag, tag) + replacement = f"\n% START_{tag}\n\n{contents}\n\n% END_{tag}\n" + pattern = rf"\n% START_{tag}\n.*\n% END_{tag}\n" return re.sub(pattern, replacement, text, flags=re.S) @@ -38,15 +38,7 @@ def get_help_text(): out = get_help_output() out = re.sub(r" clang-format\.exe ", " clang-format ", out) - out = ( - """.. code-block:: console - -$ clang-format --help -""" - + out - ) - out = indent(out, 2, indent_first_line=False) - return out + return "```console\n$ clang-format --help\n" + out + "```" def validate(text, columns): diff --git a/clang/docs/tools/dump_format_style.py b/clang/docs/tools/dump_format_style.py index a78c8f54045cc..c18c70daf9f4c 100755 --- a/clang/docs/tools/dump_format_style.py +++ b/clang/docs/tools/dump_format_style.py @@ -8,6 +8,7 @@ import os import re import sys +import textwrap from io import TextIOWrapper from typing import Set @@ -27,9 +28,9 @@ def substitute(text, tag, contents): - replacement = "\n.. START_%s\n\n%s\n\n.. END_%s\n" % (tag, contents, tag) - pattern = r"\n\.\. START_%s\n.*\n\.\. END_%s\n" % (tag, tag) - return re.sub(pattern, "%s", text, flags=re.S) % replacement + replacement = f"\n% START_{tag}\n\n{contents}\n\n% END_{tag}\n" + pattern = rf"\n% START_{tag}\n.*\n% END_{tag}\n" + return re.sub(pattern, lambda _: replacement, text, flags=re.S) def register_plural(singular: str, plural: str): @@ -70,6 +71,57 @@ def pluralize(word: str): return register_plural(word, word + "s") +def reindent_fenced_blocks(text): + """Reindent fenced block body text to match the fence nesting indent. + + For example, this collapses the code body's internal Doxygen indentation: + + ```yaml + BasedOnStyle: LLVM + ``` + + to this Markdown shape: + + ```yaml + BasedOnStyle: LLVM + ``` + + It also normalizes MyST colon-fenced directives: + + :::{note} + This line should use the directive's indentation. + ::: + + to this Markdown shape: + + :::{note} + This line should use the directive's indentation. + ::: + """ + + def reindent_block(match): + indent = match.group("indent") + fence = match.group("fence") + info = match.group("info") + body = match.group("body") + dedented_body = "".join( + (indent + line if line.strip() else line) + for line in textwrap.dedent(body).splitlines(keepends=True) + ) + return ( + f"{indent}{fence}{info}\n" + f"{dedented_body}" + f"{indent}{fence}{match.group('trailing')}" + ) + + return re.sub( + r"(?ms)^(?P[^\S\n]*)(?P```|:::)(?P[^\n]*)\n" + r"(?P.*?)(?P=indent)(?P=fence)(?P\n|$)", + reindent_block, + text, + ) + + def to_yaml_type(typestr: str): if typestr == "bool": return "Boolean" @@ -93,13 +145,39 @@ def to_yaml_type(typestr: str): return typestr -def doxygen2rst(text): - text = re.sub(r"\s*(.*?)\s*<\/tt>", r"``\1``", text) - text = re.sub(r"\\c ([^ ,;\.]+)", r"``\1``", text) +def doxygen2md(text): + text = re.sub(r"\s*(.*?)\s*<\/tt>", r"`\1`", text) + text = re.sub(r"\\c ([^ ,;\.]+)", r"`\1`", text) + text = re.sub(r"(?m)^(\s*)\* ", r"\1- ", text) text = re.sub(r"\\\w+ ", "", text) + text = re.sub( + r"(?ms)^(?P[^\S\n]*)```(?P[^\n]*)\n" + r"(?P.*?)(?P=indent)```\n" + r"(?P(?P=indent) false:\n(?:(?P=indent) .*(?:\n|$))+)", + lambda match: ( + f"{match.group('indent')}```{match.group('lang')}\n" + f"{match.group('body')}{match.group('rest').rstrip()}\n" + f"{match.group('indent')}```\n" + ), + text, + ) + text = reindent_fenced_blocks(text) + # Ensure a blank line before opening fences for proper Markdown loose-list rendering. + # Opening ``` fences have a lang word; opening ::: fences have {. Closing fences + # have neither, so they are unaffected. + text = re.sub(r"([^\n])\n([ \t]*(?:```\w|:::\{))", r"\1\n\n\2", text) return text +def definition_body(text): + lines = doxygen2md(text.strip()).splitlines() + if not lines: + return ":" + result = [": " + lines[0]] + result.extend((" " + line) if line else "" for line in lines[1:]) + return "\n".join(result) + + def indent(text, columns, indent_first_line=True): indent_str = " " * columns s = re.sub(r"\n([^\n])", "\n" + indent_str + "\\1", text, flags=re.S) @@ -118,14 +196,14 @@ def __init__(self, name, opt_type, comment, version): self.version = version def __str__(self): - s = ".. _%s:\n\n**%s** (``%s``) " % ( - self.name, + s = "(%s)=\n\n**%s** (`%s`) " % ( + self.name.lower(), self.name, to_yaml_type(self.type), ) if self.version: - s += ":versionbadge:`clang-format %s` " % self.version - s += ":ref:`¶ <%s>`\n%s" % (self.name, doxygen2rst(indent(self.comment, 2))) + s += "{versionbadge}`clang-format %s` " % self.version + s += "{ref}`¶ <%s>`\n\n%s" % (self.name, definition_body(self.comment)) if self.enum and self.enum.values: s += indent("\n\nPossible values:\n\n%s\n" % self.enum, 2) if self.nested_struct: @@ -143,7 +221,7 @@ def __init__(self, name, comment): self.values = [] def __str__(self): - return self.comment + "\n" + "\n".join(map(str, self.values)) + return doxygen2md(self.comment) + "\n" + "\n".join(map(str, self.values)) class NestedField(object): @@ -154,14 +232,14 @@ def __init__(self, name, comment, version): def __str__(self): if self.version: - return "\n* ``%s`` :versionbadge:`clang-format %s` %s" % ( + return "\n- `%s` {versionbadge}`clang-format %s` %s" % ( self.name, self.version, - doxygen2rst(indent(self.comment, 2, indent_first_line=False)), + doxygen2md(indent(self.comment, 2, indent_first_line=False)), ) - return "\n* ``%s`` %s" % ( + return "\n- `%s` %s" % ( self.name, - doxygen2rst(indent(self.comment, 2, indent_first_line=False)), + doxygen2md(indent(self.comment, 2, indent_first_line=False)), ) @@ -186,17 +264,17 @@ def __init__(self, name, enumtype, comment, version, values): def __str__(self): s = "" if self.version: - s = "\n* ``%s %s`` :versionbadge:`clang-format %s`\n\n%s" % ( + s = "\n- `%s %s` {versionbadge}`clang-format %s`\n\n%s" % ( to_yaml_type(self.type), self.name, self.version, - doxygen2rst(indent(self.comment, 2)), + doxygen2md(indent(self.comment, 2)), ) else: - s = "\n* ``%s %s``\n%s" % ( + s = "\n- `%s %s`\n%s" % ( to_yaml_type(self.type), self.name, - doxygen2rst(indent(self.comment, 2)), + doxygen2md(indent(self.comment, 2)), ) s += indent("\nPossible values:\n\n", 2) s += indent("\n".join(map(str, self.values)), 2) @@ -210,10 +288,10 @@ def __init__(self, name, comment, config): self.config = config def __str__(self): - return "* ``%s`` (in configuration: ``%s``)\n%s" % ( + return "- `%s` (in configuration: `%s`)\n%s" % ( self.name, re.sub(".*_", "", self.config), - doxygen2rst(indent(self.comment, 2)), + doxygen2md(indent(self.comment, 2)), ) @@ -248,7 +326,7 @@ def __clean_comment_line(self, line: str): lang = match.group("lang") if not lang: lang = "c++" - return f"\n{indent_str}.. code-block:: {lang}\n\n" + return f"{indent_str}```{lang}\n" endcode_match = re.match(r"^/// +\\endcode$", line) if endcode_match: @@ -257,7 +335,7 @@ def __clean_comment_line(self, line: str): "no correct `\\code` found before this `\\endcode`", line ) self.in_code_block = False - return "" + return " " * self.code_indent + "```\n" # check code block indentation if ( @@ -270,22 +348,26 @@ def __clean_comment_line(self, line: str): else: self.__warning("code block should be indented", line) self.last_err_lineno = self.lineno + if self.in_code_block: + if line == "///": + return "\n" + return " " * self.code_indent + line[6 + self.code_indent :] + "\n" match = re.match(r"^/// \\warning$", line) if match: - return "\n.. warning::\n\n" + return ":::{warning}\n" endwarning_match = re.match(r"^/// +\\endwarning$", line) if endwarning_match: - return "" + return ":::\n" match = re.match(r"^/// \\note$", line) if match: - return "\n.. note::\n\n" + return ":::{note}\n" endnote_match = re.match(r"^/// +\\endnote$", line) if endnote_match: - return "" + return ":::\n" return line[4:] + "\n" def read_options(self): diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 540a50047696a..3948337d2fc3d 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -51,7 +51,7 @@ class ParseErrorCategory final : public std::error_category { const std::error_category &getParseCategory(); std::error_code make_error_code(ParseError e); -/// The ``FormatStyle`` is used to configure the formatting to follow +/// The `FormatStyle` is used to configure the formatting to follow /// specific guidelines. struct FormatStyle { // If the BasedOn: was InheritParentConfig and this style needs the file from @@ -59,11 +59,11 @@ struct FormatStyle { // Thus the // instead of ///. std::string InheritConfig; - /// The extra indent or outdent of access modifiers, e.g. ``public:``. + /// The extra indent or outdent of access modifiers, e.g. `public:`. /// \version 3.3 int AccessModifierOffset; - /// If ``true``, horizontally aligns arguments after an open bracket. + /// If `true`, horizontally aligns arguments after an open bracket. /// /// \code /// true: vs. false @@ -73,12 +73,12 @@ struct FormatStyle { /// /// \note /// As of clang-format 22 this option is a bool with the previous - /// option of ``Align`` replaced with ``true``, ``DontAlign`` replaced - /// with ``false``, and the options of ``AlwaysBreak`` and ``BlockIndent`` - /// replaced with ``true`` and with setting of new style options using - /// ``BreakAfterOpenBracketBracedList``, ``BreakAfterOpenBracketFunction``, - /// ``BreakAfterOpenBracketIf``, ``BreakBeforeCloseBracketBracedList``, - /// ``BreakBeforeCloseBracketFunction``, and ``BreakBeforeCloseBracketIf``. + /// option of `Align` replaced with `true`, `DontAlign` replaced + /// with `false`, and the options of `AlwaysBreak` and `BlockIndent` + /// replaced with `true` and with setting of new style options using + /// `BreakAfterOpenBracketBracedList`, `BreakAfterOpenBracketFunction`, + /// `BreakAfterOpenBracketIf`, `BreakBeforeCloseBracketBracedList`, + /// `BreakBeforeCloseBracketFunction`, and `BreakBeforeCloseBracketIf`. /// \endnote /// /// This applies to round brackets (parentheses), angle brackets and square @@ -111,7 +111,7 @@ struct FormatStyle { /// Don't align array initializer columns. AIAS_None }; - /// If not ``None``, when using initialization for an array of structs + /// If not `None`, when using initialization for an array of structs /// aligns the fields into columns. /// /// \note @@ -126,11 +126,11 @@ struct FormatStyle { /// /// They can also be read as a whole for compatibility. The choices are: /// - /// * ``None`` - /// * ``Consecutive`` - /// * ``AcrossEmptyLines`` - /// * ``AcrossComments`` - /// * ``AcrossEmptyLinesAndComments`` + /// * `None` + /// * `Consecutive` + /// * `AcrossEmptyLines` + /// * `AcrossComments` + /// * `AcrossEmptyLinesAndComments` /// /// For example, to align across empty lines and not across comments, either /// of these work. @@ -194,8 +194,8 @@ struct FormatStyle { /// double e = 4; /// \endcode bool AcrossComments; - /// Only for ``AlignConsecutiveAssignments``. Whether compound assignments - /// like ``+=`` are aligned along with ``=``. + /// Only for `AlignConsecutiveAssignments`. Whether compound assignments + /// like `+=` are aligned along with `=`. /// \code /// true: /// a &= 2; @@ -206,7 +206,7 @@ struct FormatStyle { /// bbb = 2; /// \endcode bool AlignCompound; - /// Only for ``AlignConsecutiveDeclarations``. Whether function declarations + /// Only for `AlignConsecutiveDeclarations`. Whether function declarations /// are aligned. /// \code /// true: @@ -220,7 +220,7 @@ struct FormatStyle { /// size_t f3(void); /// \endcode bool AlignFunctionDeclarations; - /// Only for ``AlignConsecutiveDeclarations``. Whether function pointers are + /// Only for `AlignConsecutiveDeclarations`. Whether function pointers are /// aligned. /// \code /// true: @@ -236,12 +236,12 @@ struct FormatStyle { /// int (*f)(); /// \endcode bool AlignFunctionPointers; - /// Only for ``AlignConsecutiveAssignments``. - /// Whether enum assignments are aligned. If ``Enabled`` is ``false``, - /// setting this to ``true`` forces alignment for enum assignments only. - /// If ``Enabled`` is ``true``, enum assignments are always aligned. + /// Only for `AlignConsecutiveAssignments`. + /// Whether enum assignments are aligned. If `Enabled` is `false`, + /// setting this to `true` forces alignment for enum assignments only. + /// If `Enabled` is `true`, enum assignments are always aligned. bool EnumAssignments; - /// Only for ``AlignConsecutiveAssignments``. Whether short assignment + /// Only for `AlignConsecutiveAssignments`. Whether short assignment /// operators are left-padded to the same length as long ones in order to /// put all assignment operators to the right of the left hand side. /// \code @@ -276,7 +276,7 @@ struct FormatStyle { /// Style of aligning consecutive assignments. /// - /// ``Consecutive`` will result in formattings like: + /// `Consecutive` will result in formattings like: /// \code /// int a = 1; /// int somelongname = 2; @@ -287,7 +287,7 @@ struct FormatStyle { /// Style of aligning consecutive bit fields. /// - /// ``Consecutive`` will align the bitfield separators of consecutive lines. + /// `Consecutive` will align the bitfield separators of consecutive lines. /// This will result in formattings like: /// \code /// int aaaa : 1; @@ -299,7 +299,7 @@ struct FormatStyle { /// Style of aligning consecutive declarations. /// - /// ``Consecutive`` will align the declaration names of consecutive lines. + /// `Consecutive` will align the declaration names of consecutive lines. /// This will result in formattings like: /// \code /// int aaaa = 12; @@ -311,7 +311,7 @@ struct FormatStyle { /// Style of aligning consecutive macro definitions. /// - /// ``Consecutive`` will result in formattings like: + /// `Consecutive` will result in formattings like: /// \code /// #define SHORT_NAME 42 /// #define LONGER_NAME 0x007f @@ -424,8 +424,8 @@ struct FormatStyle { }; /// Style of aligning consecutive short case labels. - /// Only applies if ``AllowShortCaseExpressionOnASingleLine`` or - /// ``AllowShortCaseLabelsOnASingleLine`` is ``true``. + /// Only applies if `AllowShortCaseExpressionOnASingleLine` or + /// `AllowShortCaseLabelsOnASingleLine` is `true`. /// /// \code{.yaml} /// # Example of usage: @@ -517,7 +517,7 @@ struct FormatStyle { /// Different styles for aligning operands. enum OperandAlignmentStyle : int8_t { /// Do not align operands of binary and ternary expressions. - /// The wrapped lines are indented ``ContinuationIndentWidth`` spaces from + /// The wrapped lines are indented `ContinuationIndentWidth` spaces from /// the start of the line. OAS_DontAlign, /// Horizontally align operands of binary and ternary expressions. @@ -529,7 +529,7 @@ struct FormatStyle { /// ccccccccccccccc; /// \endcode /// - /// When ``BreakBeforeBinaryOperators`` is set, the wrapped operator is + /// When `BreakBeforeBinaryOperators` is set, the wrapped operator is /// aligned with the operand on the first line. /// \code /// int aaa = bbbbbbbbbbbbbbb @@ -538,8 +538,8 @@ struct FormatStyle { OAS_Align, /// Horizontally align operands of binary and ternary expressions. /// - /// This is similar to ``OAS_Align``, except when - /// ``BreakBeforeBinaryOperators`` is set, the operator is un-indented so + /// This is similar to `OAS_Align`, except when + /// `BreakBeforeBinaryOperators` is set, the operator is un-indented so /// that the wrapped operand is aligned with the operand on the first line. /// \code /// int aaa = bbbbbbbbbbbbbbb @@ -548,7 +548,7 @@ struct FormatStyle { OAS_AlignAfterOperator, }; - /// If ``true``, horizontally align operands of binary and ternary + /// If `true`, horizontally align operands of binary and ternary /// expressions. /// \version 3.5 OperandAlignmentStyle AlignOperands; @@ -589,7 +589,7 @@ struct FormatStyle { /// Specifies the way to align trailing comments. TrailingCommentsAlignmentKinds Kind; /// How many empty lines to apply alignment. - /// When both ``MaxEmptyLinesToKeep`` and ``OverEmptyLines`` are set to 2, + /// When both `MaxEmptyLinesToKeep` and `OverEmptyLines` are set to 2, /// it formats like below. /// \code /// int a; // all these @@ -600,7 +600,7 @@ struct FormatStyle { /// int abcdef; // aligned /// \endcode /// - /// When ``MaxEmptyLinesToKeep`` is set to 2 and ``OverEmptyLines`` is set + /// When `MaxEmptyLinesToKeep` is set to 2 and `OverEmptyLines` is set /// to 1, it formats like below. /// \code /// int a; // these are @@ -633,7 +633,7 @@ struct FormatStyle { /// Control of trailing comments. /// /// The alignment stops at closing braces after a line break, and only - /// followed by other closing braces, a (``do-``) ``while``, a lambda call, or + /// followed by other closing braces, a (`do-`) `while`, a lambda call, or /// a semicolon. /// /// \note @@ -651,8 +651,8 @@ struct FormatStyle { TrailingCommentsAlignmentStyle AlignTrailingComments; /// If a function call or braced initializer list doesn't fit on a line, allow - /// putting all arguments onto the next line, even if ``BinPackArguments`` is - /// ``false``. + /// putting all arguments onto the next line, even if `BinPackArguments` is + /// `false`. /// \code /// true: /// callFunction( @@ -667,14 +667,14 @@ struct FormatStyle { /// \version 9 bool AllowAllArgumentsOnNextLine; - /// This option is **deprecated**. See ``NextLine`` of - /// ``PackConstructorInitializers``. + /// This option is **deprecated**. See `NextLine` of + /// `PackConstructorInitializers`. /// \version 9 // bool AllowAllConstructorInitializersOnNextLine; /// If the function declaration doesn't fit on a line, /// allow putting all parameters of a function declaration onto - /// the next line even if ``BinPackParameters`` is ``OnePerLine``. + /// the next line even if `BinPackParameters` is `OnePerLine`. /// \code /// true: /// void myFunction( @@ -702,7 +702,7 @@ struct FormatStyle { /// noexcept(baz(arg2))); /// \endcode BBNSS_Never, - /// For a simple ``noexcept`` there is no line break allowed, but when we + /// For a simple `noexcept` there is no line break allowed, but when we /// have a condition it is. /// \code /// void foo(int arg1, @@ -714,8 +714,8 @@ struct FormatStyle { /// \endcode BBNSS_OnlyWithParen, /// Line breaks are allowed. But note that because of the associated - /// penalties ``clang-format`` often prefers not to break before the - /// ``noexcept``. + /// penalties `clang-format` often prefers not to break before the + /// `noexcept`. /// \code /// void foo(int arg1, /// double arg2) noexcept; @@ -727,13 +727,13 @@ struct FormatStyle { BBNSS_Always, }; - /// Controls if there could be a line break before a ``noexcept`` specifier. + /// Controls if there could be a line break before a `noexcept` specifier. /// \version 18 BreakBeforeNoexceptSpecifierStyle AllowBreakBeforeNoexceptSpecifier; - /// Allow breaking before ``Q_Property`` keywords ``READ``, ``WRITE``, etc. as - /// if they were preceded by a comma (``,``). This allows them to be formatted - /// according to ``BinPackParameters``. + /// Allow breaking before `Q_Property` keywords `READ`, `WRITE`, etc. as + /// if they were preceded by a comma (`,`). This allows them to be formatted + /// according to `BinPackParameters`. /// \version 22 bool AllowBreakBeforeQtProperty; @@ -765,7 +765,7 @@ struct FormatStyle { SBS_Always, }; - /// Dependent on the value, ``while (true) { continue; }`` can be put on a + /// Dependent on the value, `while (true) { continue; }` can be put on a /// single line. /// \version 3.5 ShortBlockStyle AllowShortBlocksOnASingleLine; @@ -783,7 +783,7 @@ struct FormatStyle { /// \version 19 bool AllowShortCaseExpressionOnASingleLine; - /// If ``true``, short case labels will be contracted to a single line. + /// If `true`, short case labels will be contracted to a single line. /// \code /// true: false: /// switch (a) { vs. switch (a) { @@ -835,13 +835,13 @@ struct FormatStyle { /// /// They can be read as a whole for compatibility. The choices are: /// - /// * ``None`` + /// * `None` /// Never merge functions into a single line. /// - /// * ``InlineOnly`` - /// Only merge functions defined inside a class. Same as ``inline``, - /// except it does not implies ``empty``: i.e. top level empty functions - /// are not merged either. See ``Inline`` of ``ShortFunctionStyle``. + /// * `InlineOnly` + /// Only merge functions defined inside a class. Same as `inline`, + /// except it does not implies `empty`: i.e. top level empty functions + /// are not merged either. See `Inline` of `ShortFunctionStyle`. /// \code /// class Foo { /// void f() { foo(); } @@ -853,8 +853,8 @@ struct FormatStyle { /// } /// \endcode /// - /// * ``Empty`` - /// Only merge empty functions. See ``Empty`` of ``ShortFunctionStyle``. + /// * `Empty` + /// Only merge empty functions. See `Empty` of `ShortFunctionStyle`. /// \code /// void f() {} /// void f2() { @@ -862,9 +862,9 @@ struct FormatStyle { /// } /// \endcode /// - /// * ``Inline`` - /// Only merge functions defined inside a class. Implies ``empty``. See - /// ``Inline`` and ``Empty`` of ``ShortFunctionStyle``. + /// * `Inline` + /// Only merge functions defined inside a class. Implies `empty`. See + /// `Inline` and `Empty` of `ShortFunctionStyle`. /// \code /// class Foo { /// void f() { foo(); } @@ -875,7 +875,7 @@ struct FormatStyle { /// void f() {} /// \endcode /// - /// * ``All`` + /// * `All` /// Merge all functions fitting on a single line. /// \code /// class Foo { @@ -885,7 +885,7 @@ struct FormatStyle { /// \endcode /// /// Also can be specified as a nested configuration flag: - /// \code + /// \code{.yaml} /// # Example of usage: /// AllowShortFunctionsOnASingleLine: InlineOnly /// @@ -950,7 +950,7 @@ struct FormatStyle { } }; - /// Dependent on the value, ``int f() { return 0; }`` can be put on a + /// Dependent on the value, `int f() { return 0; }` can be put on a /// single line. /// \version 3.5 ShortFunctionStyle AllowShortFunctionsOnASingleLine; @@ -1022,7 +1022,7 @@ struct FormatStyle { SIS_AllIfsAndElse, }; - /// Dependent on the value, ``if (a) return;`` can be put on a single line. + /// Dependent on the value, `if (a) return;` can be put on a single line. /// \version 3.3 ShortIfStyle AllowShortIfStatementsOnASingleLine; @@ -1055,27 +1055,27 @@ struct FormatStyle { SLS_All, }; - /// Dependent on the value, ``auto lambda []() { return 0; }`` can be put on a + /// Dependent on the value, `auto lambda []() { return 0; }` can be put on a /// single line. /// \version 9 ShortLambdaStyle AllowShortLambdasOnASingleLine; - /// If ``true``, ``while (true) continue;`` can be put on a single + /// If `true`, `while (true) continue;` can be put on a single /// line. /// \version 3.7 bool AllowShortLoopsOnASingleLine; - /// If ``true``, ``namespace a { class b; }`` can be put on a single line. + /// If `true`, `namespace a { class b; }` can be put on a single line. /// \version 20 bool AllowShortNamespacesOnASingleLine; - /// Different styles for merging short records (``class``,``struct``, and - /// ``union``). + /// Different styles for merging short records (`class`,`struct`, and + /// `union`). enum ShortRecordStyle : int8_t { /// Never merge records into a single line. SRS_Never, /// Only merge empty records if the opening brace was not wrapped, - /// i.e. the corresponding ``BraceWrapping.After...`` option was not set. + /// i.e. the corresponding `BraceWrapping.After...` option was not set. SRS_EmptyAndAttached, /// Only merge empty records. /// \code @@ -1094,7 +1094,7 @@ struct FormatStyle { SRS_Always }; - /// Dependent on the value, ``struct bar { int i; };`` can be put on a single + /// Dependent on the value, `struct bar { int i; };` can be put on a single /// line. /// \version 23 ShortRecordStyle AllowShortRecordOnASingleLine; @@ -1103,7 +1103,7 @@ struct FormatStyle { /// This option is **deprecated** and is retained for backwards compatibility. enum DefinitionReturnTypeBreakingStyle : int8_t { /// Break after return type automatically. - /// ``PenaltyReturnTypeOnItsOwnLine`` is taken into account. + /// `PenaltyReturnTypeOnItsOwnLine` is taken into account. DRTBS_None, /// Always break after the return type. DRTBS_All, @@ -1114,9 +1114,9 @@ struct FormatStyle { /// Different ways to break after the function definition or /// declaration return type. enum ReturnTypeBreakingStyle : int8_t { - /// This is **deprecated**. See ``Automatic`` below. + /// This is **deprecated**. See `Automatic` below. RTBS_None, - /// Break after return type based on ``PenaltyReturnTypeOnItsOwnLine``. + /// Break after return type based on `PenaltyReturnTypeOnItsOwnLine`. /// \code /// class A { /// int f() { return 0; }; @@ -1127,7 +1127,7 @@ struct FormatStyle { /// LongName::AnotherLongName(); /// \endcode RTBS_Automatic, - /// Same as ``Automatic`` above, except that there is no break after short + /// Same as `Automatic` above, except that there is no break after short /// return types. /// \code /// class A { @@ -1210,17 +1210,17 @@ struct FormatStyle { /// \version 3.7 DefinitionReturnTypeBreakingStyle AlwaysBreakAfterDefinitionReturnType; - /// This option is renamed to ``BreakAfterReturnType``. + /// This option is renamed to `BreakAfterReturnType`. /// \version 3.8 /// @deprecated // ReturnTypeBreakingStyle AlwaysBreakAfterReturnType; - /// If ``true``, always break before multiline string literals. + /// If `true`, always break before multiline string literals. /// /// This flag is mean to make cases where there are multiple multiline strings /// in a file look more consistent. Thus, it will only take effect if wrapping /// the string at that point leads to it being indented - /// ``ContinuationIndentWidth`` spaces from the start of the line. + /// `ContinuationIndentWidth` spaces from the start of the line. /// \code /// true: false: /// aaaa = vs. aaaa = "bbbb" @@ -1243,7 +1243,7 @@ struct FormatStyle { /// \endcode BTDS_Leave, /// Do not force break before declaration. - /// ``PenaltyBreakTemplateDeclaration`` is taken into account. + /// `PenaltyBreakTemplateDeclaration` is taken into account. /// \code /// template T foo() { /// } @@ -1276,7 +1276,7 @@ struct FormatStyle { BTDS_Yes }; - /// This option is renamed to ``BreakTemplateDeclarations``. + /// This option is renamed to `BreakTemplateDeclarations`. /// \version 3.4 /// @deprecated // BreakTemplateDeclarationsStyle AlwaysBreakTemplateDeclarations; @@ -1300,12 +1300,12 @@ struct FormatStyle { /// \version 12 std::vector AttributeMacros; - /// This option is **deprecated**. See ``BinPack`` of ``PackArguments``. + /// This option is **deprecated**. See `BinPack` of `PackArguments`. /// \version 3.7 // bool BinPackArguments; - /// If ``BinPackLongBracedList`` is ``true`` it overrides - /// ``BinPackArguments`` if there are 20 or more items in a braced + /// If `BinPackLongBracedList` is `true` it overrides + /// `BinPackArguments` if there are 20 or more items in a braced /// initializer list. /// \code /// BinPackLongBracedList: false vs. BinPackLongBracedList: true @@ -1320,30 +1320,30 @@ struct FormatStyle { /// \version 21 bool BinPackLongBracedList; - /// This option is **deprecated**. See ``BinPack`` of ``PackParameters``. + /// This option is **deprecated**. See `BinPack` of `PackParameters`. /// \version 3.7 // BinPackParametersStyle BinPackParameters; - /// Styles for adding spacing around ``:`` in bitfield definitions. + /// Styles for adding spacing around `:` in bitfield definitions. enum BitFieldColonSpacingStyle : int8_t { - /// Add one space on each side of the ``:`` + /// Add one space on each side of the `:` /// \code /// unsigned bf : 2; /// \endcode BFCS_Both, - /// Add no space around the ``:`` (except when needed for - /// ``AlignConsecutiveBitFields``). + /// Add no space around the `:` (except when needed for + /// `AlignConsecutiveBitFields`). /// \code /// unsigned bf:2; /// \endcode BFCS_None, - /// Add space before the ``:`` only + /// Add space before the `:` only /// \code /// unsigned bf :2; /// \endcode BFCS_Before, - /// Add space after the ``:`` only (space may be added before if - /// needed for ``AlignConsecutiveBitFields``). + /// Add space after the `:` only (space may be added before if + /// needed for `AlignConsecutiveBitFields`). /// \code /// unsigned bf: 2; /// \endcode @@ -1354,7 +1354,7 @@ struct FormatStyle { BitFieldColonSpacingStyle BitFieldColonSpacing; /// The number of columns to use to indent the contents of braced init lists. - /// If unset or negative, ``ContinuationIndentWidth`` is used. + /// If unset or negative, `ContinuationIndentWidth` is used. /// \code /// AlignAfterOpenBracket: AlwaysBreak /// BracedInitializerIndentWidth: 2 @@ -1421,7 +1421,7 @@ struct FormatStyle { }; /// Precise control over the wrapping of braces. - /// \code + /// \code{.yaml} /// # Should be declared this way: /// BreakBeforeBraces: Custom /// BraceWrapping: @@ -1455,7 +1455,7 @@ struct FormatStyle { /// \endcode bool AfterClass; - /// Wrap control statements (``if``/``for``/``while``/``switch``/..). + /// Wrap control statements (`if`/`for`/`while`/`switch`/..). BraceWrappingAfterControlStatementStyle AfterControlStatement; /// Wrap enum definitions. /// \code @@ -1504,7 +1504,7 @@ struct FormatStyle { /// Wrap ObjC definitions (interfaces, implementations...). /// \note /// @autoreleasepool and @synchronized blocks are wrapped - /// according to ``AfterControlStatement`` flag. + /// according to `AfterControlStatement` flag. /// \endnote bool AfterObjCDeclaration; /// Wrap struct definitions. @@ -1549,7 +1549,7 @@ struct FormatStyle { /// } /// \endcode bool AfterExternBlock; // Partially superseded by IndentExternBlock - /// Wrap before ``catch``. + /// Wrap before `catch`. /// \code /// true: /// try { @@ -1565,7 +1565,7 @@ struct FormatStyle { /// } /// \endcode bool BeforeCatch; - /// Wrap before ``else``. + /// Wrap before `else`. /// \code /// true: /// if (foo()) { @@ -1596,7 +1596,7 @@ struct FormatStyle { /// }); /// \endcode bool BeforeLambdaBody; - /// Wrap before ``while``. + /// Wrap before `while`. /// \code /// true: /// do { @@ -1612,11 +1612,11 @@ struct FormatStyle { bool BeforeWhile; /// Indent the wrapped braces themselves. bool IndentBraces; - /// If ``false``, empty function body can be put on a single line. + /// If `false`, empty function body can be put on a single line. /// This option is used only if the opening brace of the function has - /// already been wrapped, i.e. the ``AfterFunction`` brace wrapping mode is + /// already been wrapped, i.e. the `AfterFunction` brace wrapping mode is /// set, and the function could/should not be put on a single line (as per - /// ``AllowShortFunctionsOnASingleLine`` and constructor formatting + /// `AllowShortFunctionsOnASingleLine` and constructor formatting /// options). /// \code /// false: true: @@ -1626,9 +1626,9 @@ struct FormatStyle { /// \endcode /// bool SplitEmptyFunction; - /// If ``false``, empty record (e.g. class, struct or union) body + /// If `false`, empty record (e.g. class, struct or union) body /// can be put on a single line. This option is used only if the opening - /// brace of the record has already been wrapped, i.e. the ``AfterClass`` + /// brace of the record has already been wrapped, i.e. the `AfterClass` /// (for classes) brace wrapping mode is set. /// \code /// false: true: @@ -1638,9 +1638,9 @@ struct FormatStyle { /// \endcode /// bool SplitEmptyRecord; - /// If ``false``, empty namespace body can be put on a single line. + /// If `false`, empty namespace body can be put on a single line. /// This option is used only if the opening brace of the namespace has - /// already been wrapped, i.e. the ``AfterNamespace`` brace wrapping mode is + /// already been wrapped, i.e. the `AfterNamespace` brace wrapping mode is /// set. /// \code /// false: true: @@ -1654,7 +1654,7 @@ struct FormatStyle { /// Control of individual brace wrapping cases. /// - /// If ``BreakBeforeBraces`` is set to ``Custom``, use this to specify how + /// If `BreakBeforeBraces` is set to `Custom`, use this to specify how /// each individual brace case should be handled. Otherwise, this is ignored. /// \code{.yaml} /// # Example of usage: @@ -1737,7 +1737,7 @@ struct FormatStyle { /// } /// \endcode ABS_Leave, - /// Same as ``Leave`` except that it applies to all attributes of the group. + /// Same as `Leave` except that it applies to all attributes of the group. /// \code /// [[deprecated("Don't use this version")]] /// [[nodiscard]] @@ -1777,13 +1777,13 @@ struct FormatStyle { /// Break after a group of C++11 attributes before variable or function /// (including constructor/destructor) declaration/definition names or before - /// control statements, i.e. ``if``, ``switch`` (including ``case`` and - /// ``default`` labels), ``for``, and ``while`` statements. + /// control statements, i.e. `if`, `switch` (including `case` and + /// `default` labels), `for`, and `while` statements. /// \version 16 AttributeBreakingStyle BreakAfterAttributes; /// Force break after the left bracket of a braced initializer list (when - /// ``Cpp11BracedListStyle`` is ``true``) when the list exceeds the column + /// `Cpp11BracedListStyle` is `true`) when the list exceeds the column /// limit. /// \code /// true: false: @@ -1837,8 +1837,8 @@ struct FormatStyle { /// \version 19 ReturnTypeBreakingStyle BreakAfterReturnType; - /// If ``true``, clang-format will always break after a Json array ``[`` - /// otherwise it will scan until the closing ``]`` to determine if it should + /// If `true`, clang-format will always break after a Json array `[` + /// otherwise it will scan until the closing `]` to determine if it should /// add newlines between elements (prettier compatible). /// /// \note @@ -1958,7 +1958,7 @@ struct FormatStyle { /// } // namespace N /// \endcode BS_Attach, - /// Like ``Attach``, but break before braces on function, namespace and + /// Like `Attach`, but break before braces on function, namespace and /// class definitions. /// \code /// namespace N @@ -2008,7 +2008,7 @@ struct FormatStyle { /// } // namespace N /// \endcode BS_Linux, - /// Like ``Attach``, but break before braces on enum, function, and record + /// Like `Attach`, but break before braces on enum, function, and record /// definitions. /// \code /// namespace N { @@ -2058,8 +2058,8 @@ struct FormatStyle { /// } // namespace N /// \endcode BS_Mozilla, - /// Like ``Attach``, but break before function definitions, ``catch``, and - /// ``else``. + /// Like `Attach`, but break before function definitions, `catch`, and + /// `else`. /// \code /// namespace N { /// enum E { @@ -2168,7 +2168,7 @@ struct FormatStyle { /// } // namespace N /// \endcode BS_Allman, - /// Like ``Allman`` but always indent braces and line up code with braces. + /// Like `Allman` but always indent braces and line up code with braces. /// \code /// namespace N /// { @@ -2291,7 +2291,7 @@ struct FormatStyle { /// } // namespace N /// \endcode BS_GNU, - /// Like ``Attach``, but break before functions. + /// Like `Attach`, but break before functions. /// \code /// namespace N { /// enum E { @@ -2338,7 +2338,7 @@ struct FormatStyle { /// } // namespace N /// \endcode BS_WebKit, - /// Configure each individual brace in ``BraceWrapping``. + /// Configure each individual brace in `BraceWrapping`. BS_Custom }; @@ -2347,7 +2347,7 @@ struct FormatStyle { BraceBreakingStyle BreakBeforeBraces; /// Force break before the right bracket of a braced initializer list (when - /// ``Cpp11BracedListStyle`` is ``true``) when the list exceeds the column + /// `Cpp11BracedListStyle` is `true`) when the list exceeds the column /// limit. The break before the right bracket is only made if there is a /// break after the opening bracket. /// \code @@ -2411,16 +2411,16 @@ struct FormatStyle { /// Different ways to break before concept declarations. enum BreakBeforeConceptDeclarationsStyle : int8_t { - /// Keep the template declaration line together with ``concept``. + /// Keep the template declaration line together with `concept`. /// \code /// template concept C = ...; /// \endcode BBCDS_Never, - /// Breaking between template declaration and ``concept`` is allowed. The + /// Breaking between template declaration and `concept` is allowed. The /// actual behavior depends on the content and line breaking rules and /// penalties. BBCDS_Allowed, - /// Always break before ``concept``, putting it in the line after the + /// Always break before `concept`, putting it in the line after the /// template declaration. /// \code /// template @@ -2481,14 +2481,14 @@ struct FormatStyle { }; /// The function declaration/definition return type breaking style to use. - /// Trailing return types (``auto f() -> T``) are not affected. To have - /// identifier macros (e.g. ``__always_inline``) treated as specifiers, - /// add them to ``AttributeMacros``. + /// Trailing return types (`auto f() -> T`) are not affected. To have + /// identifier macros (e.g. `__always_inline`) treated as specifiers, + /// add them to `AttributeMacros`. /// \version 23 BreakBeforeReturnTypeStyle BreakBeforeReturnType; - /// If ``true``, break before a template closing bracket (``>``) when there is - /// a line break after the matching opening bracket (``<``). + /// If `true`, break before a template closing bracket (`>`) when there is + /// a line break after the matching opening bracket (`<`). /// \code /// true: /// template @@ -2514,7 +2514,7 @@ struct FormatStyle { /// \version 21 bool BreakBeforeTemplateCloser; - /// If ``true``, ternary operators will be placed after line breaks. + /// If `true`, ternary operators will be placed after line breaks. /// \code /// true: /// veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongDescription @@ -2563,14 +2563,14 @@ struct FormatStyle { /// A rule that specifies how to break a specific set of binary operators. /// \version 23 struct BinaryOperationBreakRule { - /// The list of operators this rule applies to, e.g. ``&&``, ``||``, ``|``. - /// Alternative spellings (e.g. ``and`` for ``&&``) are accepted. + /// The list of operators this rule applies to, e.g. `&&`, `||`, `|`. + /// Alternative spellings (e.g. `and` for `&&`) are accepted. std::vector Operators; - /// The break style for these operators (defaults to ``OnePerLine``). + /// The break style for these operators (defaults to `OnePerLine`). BreakBinaryOperationsStyle Style; /// Minimum number of operands in a chain before the rule triggers. - /// For example, ``a && b && c`` is a chain of length 3. - /// ``0`` means always break (when the line is too long). + /// For example, `a && b && c` is a chain of length 3. + /// `0` means always break (when the line is too long). unsigned MinChainLength; bool operator==(const BinaryOperationBreakRule &R) const { return Operators == R.Operators && Style == R.Style && @@ -2581,9 +2581,9 @@ struct FormatStyle { } }; - /// Options for ``BreakBinaryOperations``. + /// Options for `BreakBinaryOperations`. /// - /// If specified as a simple string (e.g. ``OnePerLine``), it behaves like + /// If specified as a simple string (e.g. `OnePerLine`), it behaves like /// the original enum and applies to all binary operators. /// /// If specified as a struct, allows per-operator configuration: @@ -2597,7 +2597,7 @@ struct FormatStyle { /// \endcode /// \version 23 struct BreakBinaryOperationsOptions { - /// The default break style for operators not covered by ``PerOperator``. + /// The default break style for operators not covered by `PerOperator`. BreakBinaryOperationsStyle Default; /// Per-operator override rules. std::vector PerOperator; @@ -2675,7 +2675,7 @@ struct FormatStyle { /// \version 5 BreakConstructorInitializersStyle BreakConstructorInitializers; - /// If ``true``, clang-format will always break before function declaration + /// If `true`, clang-format will always break before function declaration /// parameters. /// \code /// true: @@ -2689,7 +2689,7 @@ struct FormatStyle { /// \version 23 bool BreakFunctionDeclarationParameters; - /// If ``true``, clang-format will always break before function definition + /// If `true`, clang-format will always break before function definition /// parameters. /// \code /// true: @@ -2758,7 +2758,7 @@ struct FormatStyle { /// The column limit. /// - /// A column limit of ``0`` means that there is no column limit. In this case, + /// A column limit of `0` means that there is no column limit. In this case, /// clang-format will respect the input's line breaking decisions within /// statements unless they contradict other rules. /// \version 3.7 @@ -2818,8 +2818,8 @@ struct FormatStyle { /// \version 19 BreakTemplateDeclarationsStyle BreakTemplateDeclarations; - /// If ``true``, consecutive namespace declarations will be on the same - /// line. If ``false``, each namespace is declared on a new line. + /// If `true`, consecutive namespace declarations will be on the same + /// line. If `false`, each namespace is declared on a new line. /// \code /// true: /// namespace Foo { namespace Bar { @@ -2842,8 +2842,8 @@ struct FormatStyle { /// \version 5 bool CompactNamespaces; - /// This option is **deprecated**. See ``CurrentLine`` of - /// ``PackConstructorInitializers``. + /// This option is **deprecated**. See `CurrentLine` of + /// `PackConstructorInitializers`. /// \version 3.7 // bool ConstructorInitializerAllOnOneLineOrOnePerLine; @@ -2890,7 +2890,7 @@ struct FormatStyle { /// Fundamentally, C++11 braced lists are formatted exactly like function /// calls would be formatted in their place. If the braced list follows a /// name (e.g. a type or variable name), clang-format formats as if the - /// ``{}`` were the parentheses of a function call with that name. If there + /// `{}` were the parentheses of a function call with that name. If there /// is no name, a zero-length name is assumed. /// \code /// vector x{1, 2, 3, 4}; @@ -2901,7 +2901,7 @@ struct FormatStyle { /// value}; /// \endcode BLS_FunctionCall, - /// Same as ``FunctionCall``, except for the handling of a comment at the + /// Same as `FunctionCall`, except for the handling of a comment at the /// begin, it then aligns everything following with the comment. /// /// * No spaces inside the braced list. (Even for a comment at the first @@ -2925,16 +2925,16 @@ struct FormatStyle { /// \version 3.4 BracedListStyle Cpp11BracedListStyle; - /// This option is **deprecated**. See ``DeriveLF`` and ``DeriveCRLF`` of - /// ``LineEnding``. + /// This option is **deprecated**. See `DeriveLF` and `DeriveCRLF` of + /// `LineEnding`. /// \version 10 // bool DeriveLineEnding; - /// If ``true``, analyze the formatted file for the most common - /// alignment of ``&`` and ``*``. + /// If `true`, analyze the formatted file for the most common + /// alignment of `&` and `*`. /// Pointer and reference alignment styles are going to be updated according /// to the preferences found in the file. - /// ``PointerAlignment`` is then used only as fallback. + /// `PointerAlignment` is then used only as fallback. /// \version 3.7 bool DerivePointerAlignment; @@ -2943,7 +2943,7 @@ struct FormatStyle { bool DisableFormat; /// Different styles for empty line after access modifiers. - /// ``EmptyLineBeforeAccessModifier`` configuration handles the number of + /// `EmptyLineBeforeAccessModifier` configuration handles the number of /// empty lines between two access modifiers. enum EmptyLineAfterAccessModifierStyle : int8_t { /// Remove all empty lines after access modifiers. @@ -2988,7 +2988,7 @@ struct FormatStyle { }; /// Defines when to put an empty line after access modifiers. - /// ``EmptyLineBeforeAccessModifier`` configuration handles the number of + /// `EmptyLineBeforeAccessModifier` configuration handles the number of /// empty lines between two access modifiers. /// \version 13 EmptyLineAfterAccessModifierStyle EmptyLineAfterAccessModifier; @@ -3056,7 +3056,7 @@ struct FormatStyle { /// \version 12 EmptyLineBeforeAccessModifierStyle EmptyLineBeforeAccessModifier; - /// Styles for ``enum`` trailing commas. + /// Styles for `enum` trailing commas. enum EnumTrailingCommaStyle : int8_t { /// Don't insert or remove trailing commas. /// \code @@ -3078,10 +3078,10 @@ struct FormatStyle { ETC_Remove, }; - /// Insert a comma (if missing) or remove the comma at the end of an ``enum`` + /// Insert a comma (if missing) or remove the comma at the end of an `enum` /// enumerator list. /// \warning - /// Setting this option to any value other than ``Leave`` could lead to + /// Setting this option to any value other than `Leave` could lead to /// incorrect code formatting due to clang-format's lack of complete semantic /// information. As such, extra care should be taken to review code changes /// made by this option. @@ -3089,7 +3089,7 @@ struct FormatStyle { /// \version 21 EnumTrailingCommaStyle EnumTrailingComma; - /// If ``true``, clang-format detects whether function calls and + /// If `true`, clang-format detects whether function calls and /// definitions are formatted with one parameter per line. /// /// Each call can be bin-packed, one-per-line or inconclusive. If it is @@ -3104,9 +3104,9 @@ struct FormatStyle { /// \version 3.7 bool ExperimentalAutoDetectBinPacking; - /// If ``true``, clang-format adds missing namespace end comments for + /// If `true`, clang-format adds missing namespace end comments for /// namespaces and fixes invalid existing ones. This doesn't affect short - /// namespaces, which are controlled by ``ShortNamespaceLines``. + /// namespaces, which are controlled by `ShortNamespaceLines`. /// \code /// true: false: /// namespace longNamespace { vs. namespace longNamespace { @@ -3156,20 +3156,20 @@ struct FormatStyle { /// IfMacros: [IF] /// \endcode /// - /// For example: `KJ_IF_MAYBE - /// `_ + /// For example: + /// [KJ_IF_MAYBE](https://github.com/capnproto/capnproto/blob/master/kjdoc/tour.md#maybes) /// \version 13 std::vector IfMacros; /// Specify whether access modifiers should have their own indentation level. /// - /// When ``false``, access modifiers are indented (or outdented) relative to - /// the record members, respecting the ``AccessModifierOffset``. Record + /// When `false`, access modifiers are indented (or outdented) relative to + /// the record members, respecting the `AccessModifierOffset`. Record /// members are indented one level below the record. - /// When ``true``, access modifiers get their own indentation level. As a + /// When `true`, access modifiers get their own indentation level. As a /// consequence, record members are always indented 2 levels below the record, /// regardless of the access modifier presence. Value of the - /// ``AccessModifierOffset`` is ignored. + /// `AccessModifierOffset` is ignored. /// \code /// false: true: /// class C { vs. class C { @@ -3190,10 +3190,10 @@ struct FormatStyle { /// Indent case label blocks one level from the case label. /// - /// When ``false``, the block following the case label uses the same + /// When `false`, the block following the case label uses the same /// indentation level as for the case label, treating the case label the same /// as an if-statement. - /// When ``true``, the block gets indented as a scope block. + /// When `true`, the block gets indented as a scope block. /// \code /// false: true: /// switch (fool) { vs. switch (fool) { @@ -3213,7 +3213,7 @@ struct FormatStyle { /// Indent case labels one level from the switch statement. /// - /// When ``false``, use the same indentation level as for the switch + /// When `false`, use the same indentation level as for the switch /// statement. Switch statement body is always indented one level more than /// case labels (except the first block following the case label, which /// itself indents the code - unless IndentCaseBlocks is enabled). @@ -3230,7 +3230,7 @@ struct FormatStyle { /// \version 3.3 bool IndentCaseLabels; - /// If ``true``, clang-format will indent the body of an ``export { ... }`` + /// If `true`, clang-format will indent the body of an `export { ... }` /// block. This doesn't affect the formatting of anything else related to /// exported declarations. /// \code @@ -3372,7 +3372,7 @@ struct FormatStyle { PPDIS_BeforeHash, /// Leaves indentation of directives as-is. /// \note - /// Ignores ``PPIndentWidth``. + /// Ignores `PPIndentWidth`. /// \endnote /// \code /// #if FOO @@ -3389,10 +3389,10 @@ struct FormatStyle { PPDirectiveIndentStyle IndentPPDirectives; /// Indent the requires clause in a template. This only applies when - /// ``RequiresClausePosition`` is ``OwnLine``, ``OwnLineWithBrace``, - /// or ``WithFollowing``. + /// `RequiresClausePosition` is `OwnLine`, `OwnLineWithBrace`, + /// or `WithFollowing`. /// - /// In clang-format 12, 13 and 14 it was named ``IndentRequires``. + /// In clang-format 12, 13 and 14 it was named `IndentRequires`. /// \code /// true: /// template @@ -3439,11 +3439,11 @@ struct FormatStyle { /// \version 3.7 bool IndentWrappedFunctionNames; - /// Insert braces after control statements (``if``, ``else``, ``for``, ``do``, - /// and ``while``) in C++ unless the control statements are inside macro + /// Insert braces after control statements (`if`, `else`, `for`, `do`, + /// and `while`) in C++ unless the control statements are inside macro /// definitions or the braces would enclose preprocessor directives. /// \warning - /// Setting this option to ``true`` could lead to incorrect code formatting + /// Setting this option to `true` could lead to incorrect code formatting /// due to clang-format's lack of complete semantic information. As such, /// extra care should be taken to review code changes made by this option. /// \endwarning @@ -3487,11 +3487,11 @@ struct FormatStyle { TCS_Wrapped, }; - /// If set to ``TCS_Wrapped`` will insert trailing commas in container + /// If set to `TCS_Wrapped` will insert trailing commas in container /// literals (arrays and objects) that wrap across multiple lines. /// It is currently only available for JavaScript - /// and disabled by default ``TCS_None``. - /// ``InsertTrailingCommas`` cannot be used together with ``BinPackArguments`` + /// and disabled by default `TCS_None`. + /// `InsertTrailingCommas` cannot be used together with `BinPackArguments` /// as inserting the comma disables bin-packing. /// \code /// TSC_Wrapped: @@ -3507,7 +3507,7 @@ struct FormatStyle { /// Separator format of integer literals of different bases. /// - /// If negative, remove separators. If ``0``, leave the literal as is. If + /// If negative, remove separators. If `0`, leave the literal as is. If /// positive, insert separators between digits starting from the rightmost /// digit. /// @@ -3522,18 +3522,18 @@ struct FormatStyle { /// \endcode /// /// You can also specify a minimum number of digits - /// (``BinaryMinDigitsInsert``, ``DecimalMinDigitsInsert``, and - /// ``HexMinDigitsInsert``) the integer literal must have in order for the + /// (`BinaryMinDigitsInsert`, `DecimalMinDigitsInsert`, and + /// `HexMinDigitsInsert`) the integer literal must have in order for the /// separators to be inserted, and a maximum number of digits - /// (``BinaryMaxDigitsRemove``, ``DecimalMaxDigitsRemove``, and - /// ``HexMaxDigitsRemove``) until the separators are removed. This divides the + /// (`BinaryMaxDigitsRemove`, `DecimalMaxDigitsRemove`, and + /// `HexMaxDigitsRemove`) until the separators are removed. This divides the /// literals in 3 regions, always without separator (up until including - /// ``xxxMaxDigitsRemove``), maybe with, or without separators (up until - /// excluding ``xxxMinDigitsInsert``), and finally always with separators. + /// `xxxMaxDigitsRemove`), maybe with, or without separators (up until + /// excluding `xxxMinDigitsInsert`), and finally always with separators. /// \note - /// ``BinaryMinDigits``, ``DecimalMinDigits``, and ``HexMinDigits`` are - /// deprecated and renamed to ``BinaryMinDigitsInsert``, - /// ``DecimalMinDigitsInsert``, and ``HexMinDigitsInsert``, respectively. + /// `BinaryMinDigits`, `DecimalMinDigits`, and `HexMinDigits` are + /// deprecated and renamed to `BinaryMinDigitsInsert`, + /// `DecimalMinDigitsInsert`, and `HexMinDigitsInsert`, respectively. /// \endnote struct IntegerLiteralSeparatorStyle { /// Format separators in binary literals. @@ -3635,7 +3635,7 @@ struct FormatStyle { } }; - /// Format integer literal separators (``'`` for C/C++ and ``_`` for C#, Java, + /// Format integer literal separators (`'` for C/C++ and `_` for C#, Java, /// and JavaScript). /// \version 16 IntegerLiteralSeparatorStyle IntegerLiteralSeparator; @@ -3647,7 +3647,7 @@ struct FormatStyle { /// Static imports are grouped separately and follow the same group rules. /// By default, static imports are placed before non-static imports, /// but this behavior is changed by another option, - /// ``SortJavaStaticImport``. + /// `SortJavaStaticImport`. /// /// In the .clang-format configuration file, this can be configured like /// in the following yaml example. This will result in imports being @@ -3749,17 +3749,17 @@ struct FormatStyle { AtStartOfFile == R.AtStartOfFile; } }; - /// Which empty lines are kept. See ``MaxEmptyLinesToKeep`` for how many + /// Which empty lines are kept. See `MaxEmptyLinesToKeep` for how many /// consecutive empty lines are kept. /// \version 19 KeepEmptyLinesStyle KeepEmptyLines; - /// This option is **deprecated**. See ``AtEndOfFile`` of ``KeepEmptyLines``. + /// This option is **deprecated**. See `AtEndOfFile` of `KeepEmptyLines`. /// \version 17 // bool KeepEmptyLinesAtEOF; - /// This option is **deprecated**. See ``AtStartOfBlock`` of - /// ``KeepEmptyLines``. + /// This option is **deprecated**. See `AtStartOfBlock` of + /// `KeepEmptyLines`. /// \version 3.7 // bool KeepEmptyLinesAtTheStartOfBlocks; @@ -3797,9 +3797,9 @@ struct FormatStyle { LBI_OuterScope, }; - /// The indentation style of lambda bodies. ``Signature`` (the default) + /// The indentation style of lambda bodies. `Signature` (the default) /// causes the lambda body to be indented one additional level relative to - /// the indentation level of the signature. ``OuterScope`` forces the lambda + /// the indentation level of the signature. `OuterScope` forces the lambda /// body to be indented one additional level relative to the parent scope /// containing the lambda signature. /// \version 13 @@ -3808,7 +3808,7 @@ struct FormatStyle { /// Supported languages. /// /// When stored in a configuration file, specifies the language, that the - /// configuration targets. When passed to the ``reformat()`` function, enables + /// configuration targets. When passed to the `reformat()` function, enables /// syntax features specific to the language. enum LanguageKind : int8_t { /// Do not use. @@ -3827,13 +3827,12 @@ struct FormatStyle { LK_Json, /// Should be used for Objective-C, Objective-C++. LK_ObjC, - /// Should be used for Protocol Buffers - /// (https://developers.google.com/protocol-buffers/). + /// Should be used for [Protocol Buffers](https://protobuf.dev/) LK_Proto, /// Should be used for TableGen code. LK_TableGen, - /// Should be used for Protocol Buffer messages in text format - /// (https://developers.google.com/protocol-buffers/). + /// Should be used for [Protocol Buffer](https://protobuf.dev/) messages in + /// text format LK_TextProto, /// Should be used for Verilog and SystemVerilog. /// https://standards.ieee.org/ieee/1800/6700/ @@ -3854,26 +3853,26 @@ struct FormatStyle { /// The language that this format style targets. /// \note - /// You can specify the language (``C``, ``Cpp``, or ``ObjC``) for ``.h`` - /// files by adding a ``// clang-format Language:`` line before the first - /// non-comment (and non-empty) line, e.g. ``// clang-format Language: Cpp``. + /// You can specify the language (`C`, `Cpp`, or `ObjC`) for `.h` + /// files by adding a `// clang-format Language:` line before the first + /// non-comment (and non-empty) line, e.g. `// clang-format Language: Cpp`. /// \endnote /// \version 3.5 LanguageKind Language; /// Line ending style. enum LineEndingStyle : int8_t { - /// Use ``\n``. + /// Use `\n`. LE_LF, - /// Use ``\r\n``. + /// Use `\r\n`. LE_CRLF, - /// Use ``\n`` unless the input has more lines ending in ``\r\n``. + /// Use `\n` unless the input has more lines ending in `\r\n`. LE_DeriveLF, - /// Use ``\r\n`` unless the input has more lines ending in ``\n``. + /// Use `\r\n` unless the input has more lines ending in `\n`. LE_DeriveCRLF, }; - /// Line ending style (``\n`` or ``\r\n``) to use. + /// Line ending style (`\n` or `\r\n`) to use. /// \version 16 LineEndingStyle LineEnding; @@ -3921,7 +3920,7 @@ struct FormatStyle { /// \endcode /// /// will usually be interpreted as a call to a function A, and the - /// multiplication expression will be formatted as ``a * b``. + /// multiplication expression will be formatted as `a * b`. /// /// If we specify the macro definition: /// \code{.yaml} @@ -3930,15 +3929,16 @@ struct FormatStyle { /// \endcode /// /// the code will now be parsed as a declaration of the variable b of type a*, - /// and formatted as ``a* b`` (depending on pointer-binding rules). + /// and formatted as `a* b` (depending on pointer-binding rules). /// /// Features and restrictions: - /// * Both function-like macros and object-like macros are supported. - /// * Macro arguments must be used exactly once in the expansion. - /// * No recursive expansion; macros referencing other macros will be - /// ignored. - /// * Overloading by arity is supported: for example, given the macro - /// definitions A=x, A()=y, A(a)=a + /// + /// - Both function-like macros and object-like macros are supported. + /// - Macro arguments must be used exactly once in the expansion. + /// - No recursive expansion; macros referencing other macros will be + /// ignored. + /// - Overloading by arity is supported: for example, given the macro + /// definitions A=x, A()=y, A(a)=a /// /// \code /// A; -> x; @@ -3951,7 +3951,7 @@ struct FormatStyle { std::vector Macros; /// A vector of function-like macros whose invocations should be skipped by - /// ``RemoveParentheses``. + /// `RemoveParentheses`. /// \version 21 std::vector MacrosSkippedByRemoveParentheses; @@ -4065,7 +4065,7 @@ struct FormatStyle { /// \endcode NumericLiteralComponentStyle Prefix; /// Format suffix case. This option excludes case-sensitive reserved - /// suffixes, such as ``min`` in C++. + /// suffixes, such as `min` in C++. /// \code /// a = 1uLL; // Leave /// a = 1ULL; // Upper @@ -4088,19 +4088,19 @@ struct FormatStyle { NumericLiteralCaseStyle NumericLiteralCase; /// Controls bin-packing Objective-C protocol conformance list - /// items into as few lines as possible when they go over ``ColumnLimit``. + /// items into as few lines as possible when they go over `ColumnLimit`. /// - /// If ``Auto`` (the default), delegates to the value in - /// ``BinPackParameters``. If that is ``BinPack``, bin-packs Objective-C + /// If `Auto` (the default), delegates to the value in + /// `BinPackParameters`. If that is `BinPack`, bin-packs Objective-C /// protocol conformance list items into as few lines as possible - /// whenever they go over ``ColumnLimit``. + /// whenever they go over `ColumnLimit`. /// - /// If ``Always``, always bin-packs Objective-C protocol conformance + /// If `Always`, always bin-packs Objective-C protocol conformance /// list items into as few lines as possible whenever they go over - /// ``ColumnLimit``. + /// `ColumnLimit`. /// - /// If ``Never``, lays out Objective-C protocol conformance list items - /// onto individual lines whenever they go over ``ColumnLimit``. + /// If `Never`, lays out Objective-C protocol conformance list items + /// onto individual lines whenever they go over `ColumnLimit`. /// /// \code{.objc} /// Always (or Auto, if BinPackParameters==BinPack): @@ -4188,13 +4188,13 @@ struct FormatStyle { /// \version 23 bool ObjCSpaceAfterMethodDeclarationPrefix; - /// Add a space after ``@property`` in Objective-C, i.e. use - /// ``@property (readonly)`` instead of ``@property(readonly)``. + /// Add a space after `@property` in Objective-C, i.e. use + /// `@property (readonly)` instead of `@property(readonly)`. /// \version 3.7 bool ObjCSpaceAfterProperty; /// Add a space in front of an Objective-C protocol list, i.e. use - /// ``Foo `` instead of ``Foo``. + /// `Foo ` instead of `Foo`. /// \version 3.7 bool ObjCSpaceBeforeProtocolList; @@ -4203,8 +4203,8 @@ struct FormatStyle { /// clang-format skips the comment and the next line. Otherwise, clang-format /// skips lines containing a matched token. /// \note - /// This option does not apply to ``IntegerLiteralSeparator`` and - /// ``NumericLiteralCase``. + /// This option does not apply to `IntegerLiteralSeparator` and + /// `NumericLiteralCase`. /// \endnote /// \code /// // OneLineFormatOffRegex: ^(// NOLINT|logger$) @@ -4243,8 +4243,8 @@ struct FormatStyle { /// } /// \endcode BPAS_OnePerLine, - /// Use the ``BreakAfter`` option to handle argument packing instead. - /// If the ``BreakAfter`` limit is not exceeded, behave like ``BinPack``. + /// Use the `BreakAfter` option to handle argument packing instead. + /// If the `BreakAfter` limit is not exceeded, behave like `BinPack`. BPAS_UseBreakAfter }; @@ -4257,7 +4257,7 @@ struct FormatStyle { /// An argument list with more arguments than the specified number will be /// formatted with one argument per line. This option must be used with - /// ``BinPack: UseBreakAfter``. + /// `BinPack: UseBreakAfter`. /// \code /// PackArguments: /// BinPack: UseBreakAfter @@ -4316,7 +4316,7 @@ struct FormatStyle { /// ddddddddddddd() /// \endcode PCIS_CurrentLine, - /// Same as ``PCIS_CurrentLine`` except that if all constructor initializers + /// Same as `PCIS_CurrentLine` except that if all constructor initializers /// do not fit on the current line, try to fit them on the next line. /// \code /// Constructor() : a(), b() @@ -4376,8 +4376,8 @@ struct FormatStyle { /// int c); /// \endcode BPPS_AlwaysOnePerLine, - /// Use the ``BreakAfter`` option to handle parameter packing instead. - /// If the ``BreakAfter`` limit is not exceeded, behave like ``BinPack``. + /// Use the `BreakAfter` option to handle parameter packing instead. + /// If the `BreakAfter` limit is not exceeded, behave like `BinPack`. BPPS_UseBreakAfter }; @@ -4391,7 +4391,7 @@ struct FormatStyle { /// A parameter list with more parameters than the specified number will be /// formatted with one parameter per line. This option must be used with - /// ``BinPack: UseBreakAfter``. + /// `BinPack: UseBreakAfter`. /// \code /// PackParameters: /// BinPack: UseBreakAfter @@ -4426,11 +4426,11 @@ struct FormatStyle { /// \version 5 unsigned PenaltyBreakAssignment; - /// The penalty for breaking a function call after ``call(``. + /// The penalty for breaking a function call after `call(`. /// \version 3.7 unsigned PenaltyBreakBeforeFirstCallParameter; - /// The penalty for breaking before a member access operator (``.``, ``->``). + /// The penalty for breaking before a member access operator (`.`, `->`). /// \version 20 unsigned PenaltyBreakBeforeMemberAccess; @@ -4438,15 +4438,15 @@ struct FormatStyle { /// \version 3.7 unsigned PenaltyBreakComment; - /// The penalty for breaking before the first ``<<``. + /// The penalty for breaking before the first `<<`. /// \version 3.7 unsigned PenaltyBreakFirstLessLess; - /// The penalty for breaking after ``(``. + /// The penalty for breaking after `(`. /// \version 14 unsigned PenaltyBreakOpenParenthesis; - /// The penalty for breaking after ``::``. + /// The penalty for breaking after `::`. /// \version 18 unsigned PenaltyBreakScopeResolution; @@ -4471,7 +4471,7 @@ struct FormatStyle { /// \version 3.7 unsigned PenaltyReturnTypeOnItsOwnLine; - /// The ``&``, ``&&`` and ``*`` alignment style. + /// The `&`, `&&` and `*` alignment style. enum PointerAlignmentStyle : int8_t { /// Align pointer to the left. /// \code @@ -4495,7 +4495,7 @@ struct FormatStyle { PointerAlignmentStyle PointerAlignment; /// The number of columns to use for indentation of preprocessor statements. - /// When set to -1 (default) ``IndentWidth`` is used also for preprocessor + /// When set to -1 (default) `IndentWidth` is used also for preprocessor /// statements. /// \code /// PPIndentWidth: 1 @@ -4530,7 +4530,7 @@ struct FormatStyle { /// int const *a; /// \endcode QAS_Right, - /// Change specifiers/qualifiers to be aligned based on ``QualifierOrder``. + /// Change specifiers/qualifiers to be aligned based on `QualifierOrder`. /// With: /// \code{.yaml} /// QualifierOrder: [inline, static, type, const] @@ -4546,7 +4546,7 @@ struct FormatStyle { /// Different ways to arrange specifiers and qualifiers (e.g. const/volatile). /// \warning - /// Setting ``QualifierAlignment`` to something other than ``Leave``, COULD + /// Setting `QualifierAlignment` to something other than `Leave`, COULD /// lead to incorrect code formatting due to incorrect decisions made due to /// clang-formats lack of complete semantic information. /// As such extra care should be taken to review code changes made by the use @@ -4558,21 +4558,21 @@ struct FormatStyle { /// The order in which the qualifiers appear. /// The order is an array that can contain any of the following: /// - /// * ``const`` - /// * ``inline`` - /// * ``static`` - /// * ``friend`` - /// * ``constexpr`` - /// * ``volatile`` - /// * ``restrict`` - /// * ``type`` + /// * `const` + /// * `inline` + /// * `static` + /// * `friend` + /// * `constexpr` + /// * `volatile` + /// * `restrict` + /// * `type` /// /// \note - /// It must contain ``type``. + /// It must contain `type`. /// \endnote /// - /// Items to the left of ``type`` will be placed to the left of the type and - /// aligned in the order supplied. Items to the right of ``type`` will be + /// Items to the left of `type` will be placed to the left of the type and + /// aligned in the order supplied. Items to the right of `type` will be /// placed to the right of the type and aligned in the order supplied. /// /// \code{.yaml} @@ -4581,7 +4581,7 @@ struct FormatStyle { /// \version 14 std::vector QualifierOrder; - /// See documentation of ``RawStringFormats``. + /// See documentation of `RawStringFormats`. struct RawStringFormat { /// The language of this raw string. LanguageKind Language; @@ -4610,8 +4610,8 @@ struct FormatStyle { /// name will be reformatted assuming the specified language based on the /// style for that language defined in the .clang-format file. If no style has /// been defined in the .clang-format file for the specific language, a - /// predefined style given by ``BasedOnStyle`` is used. If ``BasedOnStyle`` is - /// not found, the formatting is based on ``LLVM`` style. A matching delimiter + /// predefined style given by `BasedOnStyle` is used. If `BasedOnStyle` is + /// not found, the formatting is based on `LLVM` style. A matching delimiter /// takes precedence over a matching enclosing function name for determining /// the language of the raw string contents. /// @@ -4641,9 +4641,9 @@ struct FormatStyle { /// \version 6 std::vector RawStringFormats; - /// The ``&`` and ``&&`` alignment style. + /// The `&` and `&&` alignment style. enum ReferenceAlignmentStyle : int8_t { - /// Align reference like ``PointerAlignment``. + /// Align reference like `PointerAlignment`. RAS_Pointer, /// Align reference to the left. /// \code @@ -4662,7 +4662,7 @@ struct FormatStyle { RAS_Middle }; - /// Reference alignment style (overrides ``PointerAlignment`` for references). + /// Reference alignment style (overrides `PointerAlignment` for references). /// \version 13 ReferenceAlignmentStyle ReferenceAlignment; @@ -4687,7 +4687,7 @@ struct FormatStyle { /// \endcode RCS_IndentOnly, /// Apply indentation rules and reflow long comments into new lines, trying - /// to obey the ``ColumnLimit``. + /// to obey the `ColumnLimit`. /// \code /// // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of /// // information @@ -4704,13 +4704,13 @@ struct FormatStyle { /// \version 3.8 ReflowCommentsStyle ReflowComments; - /// Remove optional braces of control statements (``if``, ``else``, ``for``, - /// and ``while``) in C++ according to the LLVM coding style. + /// Remove optional braces of control statements (`if`, `else`, `for`, + /// and `while`) in C++ according to the LLVM coding style. /// \warning /// This option will be renamed and expanded to support other styles. /// \endwarning /// \warning - /// Setting this option to ``true`` could lead to incorrect code formatting + /// Setting this option to `true` could lead to incorrect code formatting /// due to clang-format's lack of complete semantic information. As such, /// extra care should be taken to review code changes made by this option. /// \endwarning @@ -4798,7 +4798,7 @@ struct FormatStyle { /// \endcode RPS_MultipleParentheses, /// Also remove parentheses enclosing the expression in a - /// ``return``/``co_return`` statement. + /// `return`/`co_return` statement. /// \code /// class __declspec(dllimport) X {}; /// co_return 0; @@ -4809,7 +4809,7 @@ struct FormatStyle { /// Remove redundant parentheses. /// \warning - /// Setting this option to any value other than ``Leave`` could lead to + /// Setting this option to any value other than `Leave` could lead to /// incorrect code formatting due to clang-format's lack of complete semantic /// information. As such, extra care should be taken to review code changes /// made by this option. @@ -4820,7 +4820,7 @@ struct FormatStyle { /// Remove semicolons after the closing braces of functions and /// constructors/destructors. /// \warning - /// Setting this option to ``true`` could lead to incorrect code formatting + /// Setting this option to `true` could lead to incorrect code formatting /// due to clang-format's lack of complete semantic information. As such, /// extra care should be taken to review code changes made by this option. /// \endwarning @@ -4835,10 +4835,10 @@ struct FormatStyle { /// \version 16 bool RemoveSemicolon; - /// The possible positions for the requires clause. The ``IndentRequires`` - /// option is only used if the ``requires`` is put on the start of a line. + /// The possible positions for the requires clause. The `IndentRequires` + /// option is only used if the `requires` is put on the start of a line. enum RequiresClausePositionStyle : int8_t { - /// Always put the ``requires`` clause on its own line (possibly followed by + /// Always put the `requires` clause on its own line (possibly followed by /// a semicolon). /// \code /// template @@ -4859,7 +4859,7 @@ struct FormatStyle { /// {... /// \endcode RCPS_OwnLine, - /// As with ``OwnLine``, except, unless otherwise prohibited, place a + /// As with `OwnLine`, except, unless otherwise prohibited, place a /// following open brace (of a function definition) to follow on the same /// line. /// \code @@ -4894,7 +4894,7 @@ struct FormatStyle { /// {... /// \endcode RCPS_WithPreceding, - /// Try to put the ``requires`` clause together with the class or function + /// Try to put the `requires` clause together with the class or function /// declaration. /// \code /// template @@ -4934,7 +4934,7 @@ struct FormatStyle { RCPS_SingleLine, }; - /// The position of the ``requires`` clause. + /// The position of the `requires` clause. /// \version 15 RequiresClausePositionStyle RequiresClausePosition; @@ -4950,7 +4950,7 @@ struct FormatStyle { /// } /// \endcode REI_OuterScope, - /// Align requires expression body relative to the ``requires`` keyword. + /// Align requires expression body relative to the `requires` keyword. /// \code /// template /// concept C = requires(T t) { @@ -5027,7 +5027,7 @@ struct FormatStyle { /// /// This determines the maximum length of short namespaces by counting /// unwrapped lines (i.e. containing neither opening nor closing - /// namespace brace) and makes ``FixNamespaceComments`` omit adding + /// namespace brace) and makes `FixNamespaceComments` omit adding /// end comments for those. /// \code /// ShortNamespaceLines: 1 vs. ShortNamespaceLines: 0 @@ -5050,12 +5050,12 @@ struct FormatStyle { /// Includes sorting options. struct SortIncludesOptions { - /// If ``true``, includes are sorted based on the other suboptions below. - /// (``Never`` is deprecated by ``Enabled: false``.) + /// If `true`, includes are sorted based on the other suboptions below. + /// (`Never` is deprecated by `Enabled: false`.) bool Enabled; /// Whether or not includes are sorted in a case-insensitive fashion. - /// (``CaseSensitive`` and ``CaseInsensitive`` are deprecated by - /// ``IgnoreCase: false`` and ``IgnoreCase: true``, respectively.) + /// (`CaseSensitive` and `CaseInsensitive` are deprecated by + /// `IgnoreCase: false` and `IgnoreCase: true`, respectively.) /// \code /// true: false: /// #include "A/B.h" vs. #include "A/B.h" @@ -5092,7 +5092,7 @@ struct FormatStyle { } }; - /// Controls if and how clang-format will sort ``#includes``. + /// Controls if and how clang-format will sort `#includes`. /// \version 3.8 SortIncludesOptions SortIncludes; @@ -5115,7 +5115,7 @@ struct FormatStyle { }; /// When sorting Java imports, by default static imports are placed before - /// non-static imports. If ``JavaStaticImportAfterImport`` is ``After``, + /// non-static imports. If `JavaStaticImportAfterImport` is `After`, /// static imports are placed after non-static imports. /// \version 12 SortJavaStaticImportOptions SortJavaStaticImport; @@ -5132,7 +5132,7 @@ struct FormatStyle { /// \endcode SUD_Never, /// Using declarations are sorted in the order defined as follows: - /// Split the strings by ``::`` and discard any initial empty strings. Sort + /// Split the strings by `::` and discard any initial empty strings. Sort /// the lists of names lexicographically, and within those groups, names are /// in case-insensitive lexicographic order. /// \code @@ -5144,7 +5144,7 @@ struct FormatStyle { /// \endcode SUD_Lexicographic, /// Using declarations are sorted in the order defined as follows: - /// Split the strings by ``::`` and discard any initial empty strings. The + /// Split the strings by `::` and discard any initial empty strings. The /// last element of each list is a non-namespace name; all others are /// namespace names. Sort the lists of names lexicographically, where the /// sort order of individual names is that all non-namespace names come @@ -5164,7 +5164,7 @@ struct FormatStyle { /// \version 5 SortUsingDeclarationsOptions SortUsingDeclarations; - /// If ``true``, a space is inserted after C style casts. + /// If `true`, a space is inserted after C style casts. /// \code /// true: false: /// (int) i; vs. (int)i; @@ -5172,7 +5172,7 @@ struct FormatStyle { /// \version 3.5 bool SpaceAfterCStyleCast; - /// If ``true``, a space is inserted after the logical not operator (``!``). + /// If `true`, a space is inserted after the logical not operator (`!`). /// \code /// true: false: /// ! someExpression(); vs. !someExpression(); @@ -5180,7 +5180,7 @@ struct FormatStyle { /// \version 9 bool SpaceAfterLogicalNot; - /// If ``true``, a space will be inserted after the ``operator`` keyword. + /// If `true`, a space will be inserted after the `operator` keyword. /// \code /// true: false: /// bool operator ==(int a); vs. bool operator==(int a); @@ -5188,7 +5188,7 @@ struct FormatStyle { /// \version 21 bool SpaceAfterOperatorKeyword; - /// If \c true, a space will be inserted after the ``template`` keyword. + /// If \c true, a space will be inserted after the `template` keyword. /// \code /// true: false: /// template void foo(); vs. template void foo(); @@ -5229,7 +5229,7 @@ struct FormatStyle { /// \version 12 SpaceAroundPointerQualifiersStyle SpaceAroundPointerQualifiers; - /// If ``false``, spaces will be removed before assignment operators. + /// If `false`, spaces will be removed before assignment operators. /// \code /// true: false: /// int a = 5; vs. int a= 5; @@ -5238,7 +5238,7 @@ struct FormatStyle { /// \version 3.7 bool SpaceBeforeAssignmentOperators; - /// If ``false``, spaces will be removed before case colon. + /// If `false`, spaces will be removed before case colon. /// \code /// true: false /// switch (x) { vs. switch (x) { @@ -5248,7 +5248,7 @@ struct FormatStyle { /// \version 12 bool SpaceBeforeCaseColon; - /// If ``true``, a space will be inserted before a C++11 braced list + /// If `true`, a space will be inserted before a C++11 braced list /// used to initialize an object (after the preceding identifier or type). /// \code /// true: false: @@ -5260,7 +5260,7 @@ struct FormatStyle { /// \version 7 bool SpaceBeforeCpp11BracedList; - /// If ``false``, spaces will be removed before constructor initializer + /// If `false`, spaces will be removed before constructor initializer /// colon. /// \code /// true: false: @@ -5269,7 +5269,7 @@ struct FormatStyle { /// \version 7 bool SpaceBeforeCtorInitializerColon; - /// If ``false``, spaces will be removed before enum underlying type colon. + /// If `false`, spaces will be removed before enum underlying type colon. /// \code /// true: false: /// enum E : int {} enum E: int {} @@ -5277,7 +5277,7 @@ struct FormatStyle { /// \version 23 bool SpaceBeforeEnumUnderlyingTypeColon; - /// If ``false``, spaces will be removed before inheritance colon. + /// If `false`, spaces will be removed before inheritance colon. /// \code /// true: false: /// class Foo : Bar {} vs. class Foo: Bar {} @@ -5285,8 +5285,8 @@ struct FormatStyle { /// \version 7 bool SpaceBeforeInheritanceColon; - /// If ``true``, a space will be added before a JSON colon. For other - /// languages, e.g. JavaScript, use ``SpacesInContainerLiterals`` instead. + /// If `true`, a space will be added before a JSON colon. For other + /// languages, e.g. JavaScript, use `SpacesInContainerLiterals` instead. /// \code /// true: false: /// { { @@ -5298,12 +5298,12 @@ struct FormatStyle { /// Different ways to put a space before opening parentheses. enum SpaceBeforeParensStyle : int8_t { - /// This is **deprecated** and replaced by ``Custom`` below, with all - /// ``SpaceBeforeParensOptions`` but ``AfterPlacementOperator`` set to - /// ``false``. + /// This is **deprecated** and replaced by `Custom` below, with all + /// `SpaceBeforeParensOptions` but `AfterPlacementOperator` set to + /// `false`. SBPO_Never, /// Put a space before opening parentheses only after control statement - /// keywords (``for/if/while...``). + /// keywords (`for/if/while...`). /// \code /// void f() { /// if (true) { @@ -5312,10 +5312,10 @@ struct FormatStyle { /// } /// \endcode SBPO_ControlStatements, - /// Same as ``SBPO_ControlStatements`` except this option doesn't apply to + /// Same as `SBPO_ControlStatements` except this option doesn't apply to /// ForEach and If macros. This is useful in projects where ForEach/If /// macros are treated as function calls instead of control statements. - /// ``SBPO_ControlStatementsExceptForEachMacros`` remains an alias for + /// `SBPO_ControlStatementsExceptForEachMacros` remains an alias for /// backward compatibility. /// \code /// void f() { @@ -5349,7 +5349,7 @@ struct FormatStyle { /// \endcode SBPO_Always, /// Configure each individual space before parentheses in - /// ``SpaceBeforeParensOptions``. + /// `SpaceBeforeParensOptions`. SBPO_Custom, }; @@ -5358,7 +5358,7 @@ struct FormatStyle { SpaceBeforeParensStyle SpaceBeforeParens; /// Precise control over the spacing before parentheses. - /// \code + /// \code{.yaml} /// # Should be declared this way: /// SpaceBeforeParens: Custom /// SpaceBeforeParensOptions: @@ -5366,49 +5366,49 @@ struct FormatStyle { /// AfterFunctionDefinitionName: true /// \endcode struct SpaceBeforeParensCustom { - /// If ``true``, put space between control statement keywords + /// If `true`, put space between control statement keywords /// (for/if/while...) and opening parentheses. /// \code /// true: false: /// if (...) {} vs. if(...) {} /// \endcode bool AfterControlStatements; - /// If ``true``, put space between foreach macros and opening parentheses. + /// If `true`, put space between foreach macros and opening parentheses. /// \code /// true: false: /// FOREACH (...) vs. FOREACH(...) /// /// \endcode bool AfterForeachMacros; - /// If ``true``, put a space between function declaration name and opening + /// If `true`, put a space between function declaration name and opening /// parentheses. /// \code /// true: false: /// void f (); vs. void f(); /// \endcode bool AfterFunctionDeclarationName; - /// If ``true``, put a space between function definition name and opening + /// If `true`, put a space between function definition name and opening /// parentheses. /// \code /// true: false: /// void f () {} vs. void f() {} /// \endcode bool AfterFunctionDefinitionName; - /// If ``true``, put space between if macros and opening parentheses. + /// If `true`, put space between if macros and opening parentheses. /// \code /// true: false: /// IF (...) vs. IF(...) /// /// \endcode bool AfterIfMacros; - /// If ``true``, put a space between alternative operator ``not`` and the + /// If `true`, put a space between alternative operator `not` and the /// opening parenthesis. /// \code /// true: false: /// return not (a || b); vs. return not(a || b); /// \endcode bool AfterNot; - /// If ``true``, put a space between operator overloading and opening + /// If `true`, put a space between operator overloading and opening /// parentheses. /// \code /// true: false: @@ -5416,7 +5416,7 @@ struct FormatStyle { /// object.operator++ (10); object.operator++(10); /// \endcode bool AfterOverloadedOperator; - /// If ``true``, put a space between operator ``new``/``delete`` and opening + /// If `true`, put a space between operator `new`/`delete` and opening /// parenthesis. /// \code /// true: false: @@ -5424,7 +5424,7 @@ struct FormatStyle { /// delete (buf) T; delete(buf) T; /// \endcode bool AfterPlacementOperator; - /// If ``true``, put space between requires keyword in a requires clause and + /// If `true`, put space between requires keyword in a requires clause and /// opening parentheses, if there is one. /// \code /// true: false: @@ -5433,7 +5433,7 @@ struct FormatStyle { /// ... ... /// \endcode bool AfterRequiresInClause; - /// If ``true``, put space between requires keyword in a requires expression + /// If `true`, put space between requires keyword in a requires expression /// and opening parentheses. /// \code /// true: false: @@ -5443,7 +5443,7 @@ struct FormatStyle { /// } } /// \endcode bool AfterRequiresInExpression; - /// If ``true``, put a space before opening parentheses only if the + /// If `true`, put a space before opening parentheses only if the /// parentheses are not empty. /// \code /// true: false: @@ -5478,7 +5478,7 @@ struct FormatStyle { /// Control of individual space before parentheses. /// - /// If ``SpaceBeforeParens`` is set to ``Custom``, use this to specify + /// If `SpaceBeforeParens` is set to `Custom`, use this to specify /// how each individual space before parentheses case should be handled. /// Otherwise, this is ignored. /// \code{.yaml} @@ -5491,8 +5491,8 @@ struct FormatStyle { /// \version 14 SpaceBeforeParensCustom SpaceBeforeParensOptions; - /// If ``true``, spaces will be before ``[``. - /// Lambdas will not be affected. Only the first ``[`` will get a space added. + /// If `true`, spaces will be before `[`. + /// Lambdas will not be affected. Only the first `[` will get a space added. /// \code /// true: false: /// int a [5]; vs. int a[5]; @@ -5501,7 +5501,7 @@ struct FormatStyle { /// \version 10 bool SpaceBeforeSquareBrackets; - /// If ``false``, spaces will be removed before range-based for loop + /// If `false`, spaces will be removed before range-based for loop /// colon. /// \code /// true: false: @@ -5510,7 +5510,7 @@ struct FormatStyle { /// \version 7 bool SpaceBeforeRangeBasedForLoopColon; - /// This option is **deprecated**. See ``Block`` of ``SpaceInEmptyBraces``. + /// This option is **deprecated**. See `Block` of `SpaceInEmptyBraces`. /// \version 10 // bool SpaceInEmptyBlock; @@ -5545,21 +5545,21 @@ struct FormatStyle { /// Specifies when to insert a space in empty braces. /// \note /// This option doesn't apply to initializer braces if - /// ``Cpp11BracedListStyle`` is not ``Block``. + /// `Cpp11BracedListStyle` is not `Block`. /// \endnote /// \version 22 SpaceInEmptyBracesStyle SpaceInEmptyBraces; - /// If ``true``, spaces may be inserted into ``()``. - /// This option is **deprecated**. See ``InEmptyParentheses`` of - /// ``SpacesInParensOptions``. + /// If `true`, spaces may be inserted into `()`. + /// This option is **deprecated**. See `InEmptyParentheses` of + /// `SpacesInParensOptions`. /// \version 3.7 // bool SpaceInEmptyParentheses; /// The number of spaces before trailing line comments - /// (``//`` - comments). + /// (`//` - comments). /// - /// This does not affect trailing block comments (``/*`` - comments) as those + /// This does not affect trailing block comments (`/*` - comments) as those /// commonly have different usage patterns and a number of special cases. In /// the case of Verilog, it doesn't affect a comment right after the opening /// parenthesis in the port or parameter list in a module header, because it @@ -5576,38 +5576,38 @@ struct FormatStyle { /// \version 3.7 unsigned SpacesBeforeTrailingComments; - /// Styles for adding spacing after ``<`` and before ``>`` + /// Styles for adding spacing after `<` and before `>` /// in template argument lists. enum SpacesInAnglesStyle : int8_t { - /// Remove spaces after ``<`` and before ``>``. + /// Remove spaces after `<` and before `>`. /// \code /// static_cast(arg); /// std::function fct; /// \endcode SIAS_Never, - /// Add spaces after ``<`` and before ``>``. + /// Add spaces after `<` and before `>`. /// \code /// static_cast< int >(arg); /// std::function< void(int) > fct; /// \endcode SIAS_Always, - /// Keep a single space after ``<`` and before ``>`` if any spaces were - /// present. Option ``Standard: Cpp03`` takes precedence. + /// Keep a single space after `<` and before `>` if any spaces were + /// present. Option `Standard: Cpp03` takes precedence. SIAS_Leave }; /// The SpacesInAnglesStyle to use for template argument lists. /// \version 3.4 SpacesInAnglesStyle SpacesInAngles; - /// Styles for controlling spacing after ``/*`` and before ``*/`` in block + /// Styles for controlling spacing after `/*` and before `*/` in block /// comments. enum SpacesInBlockCommentsStyle : int8_t { - /// Remove spaces after ``/*`` and before ``*/``. + /// Remove spaces after `/*` and before `*/`. /// \code /// /*comment*/ /// \endcode SIBCS_Never, - /// Add spaces after ``/*`` and before ``*/``. + /// Add spaces after `/*` and before `*/`. /// \code /// /* comment */ /// \endcode @@ -5617,22 +5617,22 @@ struct FormatStyle { }; /// The SpacesInBlockCommentsStyle to use for ordinary block comments. - /// Documentation comments such as ``/** ... */`` and ``/*! ... */`` - /// and parameter comments ending with ``=`` before the closing ``*/`` are + /// Documentation comments such as `/** ... */` and `/*! ... */` + /// and parameter comments ending with `=` before the closing `*/` are /// left unchanged. /// \version 24 SpacesInBlockCommentsStyle SpacesInBlockComments; - /// If ``true``, spaces will be inserted around if/for/switch/while + /// If `true`, spaces will be inserted around if/for/switch/while /// conditions. - /// This option is **deprecated**. See ``InConditionalStatements`` of - /// ``SpacesInParensOptions``. + /// This option is **deprecated**. See `InConditionalStatements` of + /// `SpacesInParensOptions`. /// \version 10 // bool SpacesInConditionalStatement; - /// If ``true``, spaces are inserted inside container literals (e.g. ObjC and + /// If `true`, spaces are inserted inside container literals (e.g. ObjC and /// Javascript array and dict literals). For JSON, use - /// ``SpaceBeforeJsonColon`` instead. + /// `SpaceBeforeJsonColon` instead. /// \code{.js} /// true: false: /// var arr = [ 1, 2, 3 ]; vs. var arr = [1, 2, 3]; @@ -5641,9 +5641,9 @@ struct FormatStyle { /// \version 3.7 bool SpacesInContainerLiterals; - /// If ``true``, spaces may be inserted into C style casts. - /// This option is **deprecated**. See ``InCStyleCasts`` of - /// ``SpacesInParensOptions``. + /// If `true`, spaces may be inserted into C style casts. + /// This option is **deprecated**. See `InCStyleCasts` of + /// `SpacesInParensOptions`. /// \version 3.7 // bool SpacesInCStyleCastParentheses; @@ -5656,7 +5656,7 @@ struct FormatStyle { }; /// How many spaces are allowed at the start of a line comment. To disable the - /// maximum set it to ``-1``, apart from that the maximum takes precedence + /// maximum set it to `-1`, apart from that the maximum takes precedence /// over the minimum. /// \code /// Minimum = 1 @@ -5685,7 +5685,7 @@ struct FormatStyle { /// /// - Bar /// - Bar /// \endcode /// - /// This option has only effect if ``ReflowComments`` is set to ``true``. + /// This option has only effect if `ReflowComments` is set to `true`. /// \version 13 SpacesInLineComment SpacesInLineCommentPrefix; @@ -5705,21 +5705,21 @@ struct FormatStyle { SIPO_Custom, }; - /// If ``true``, spaces will be inserted after ``(`` and before ``)``. + /// If `true`, spaces will be inserted after `(` and before `)`. /// This option is **deprecated**. The previous behavior is preserved by using - /// ``SpacesInParens`` with ``Custom`` and by setting all - /// ``SpacesInParensOptions`` to ``true`` except for ``InCStyleCasts`` and - /// ``InEmptyParentheses``. + /// `SpacesInParens` with `Custom` and by setting all + /// `SpacesInParensOptions` to `true` except for `InCStyleCasts` and + /// `InEmptyParentheses`. /// \version 3.7 // bool SpacesInParentheses; - /// Defines in which cases spaces will be inserted after ``(`` and before - /// ``)``. + /// Defines in which cases spaces will be inserted after `(` and before + /// `)`. /// \version 17 SpacesInParensStyle SpacesInParens; /// Precise control over the spacing in parentheses. - /// \code + /// \code{.yaml} /// # Should be declared this way: /// SpacesInParens: Custom /// SpacesInParensOptions: @@ -5740,7 +5740,7 @@ struct FormatStyle { /// Uses the applicable option. bool ExceptDoubleParentheses; /// Put a space in parentheses only inside conditional statements - /// (``for/if/while/switch...``). + /// (`for/if/while/switch...`). /// \code /// true: false: /// if ( a ) { ... } vs. if (a) { ... } @@ -5754,7 +5754,7 @@ struct FormatStyle { /// y = (( int (*)(int) )foo)(x); y = ((int (*)(int))foo)(x); /// \endcode bool InCStyleCasts; - /// Insert a space in empty parentheses, i.e. ``()``. + /// Insert a space in empty parentheses, i.e. `()`. /// \code /// true: false: /// void f( ) { vs. void f() { @@ -5797,7 +5797,7 @@ struct FormatStyle { /// Control of individual spaces in parentheses. /// - /// If ``SpacesInParens`` is set to ``Custom``, use this to specify + /// If `SpacesInParens` is set to `Custom`, use this to specify /// how each individual space in parentheses case should be handled. /// Otherwise, this is ignored. /// \code{.yaml} @@ -5811,7 +5811,7 @@ struct FormatStyle { /// \version 17 SpacesInParensCustom SpacesInParensOptions; - /// If ``true``, spaces will be inserted after ``[`` and before ``]``. + /// If `true`, spaces will be inserted after `[` and before `]`. /// Lambdas without arguments or unspecified size array declarations will not /// be affected. /// \code @@ -5828,11 +5828,11 @@ struct FormatStyle { /// c++03 vs. vector > /// \endcode /// - /// The correct way to spell a specific language version is e.g. ``c++11``. - /// The historical aliases ``Cpp03`` and ``Cpp11`` are deprecated. + /// The correct way to spell a specific language version is e.g. `c++11`. + /// The historical aliases `Cpp03` and `Cpp11` are deprecated. enum LanguageStandard : int8_t { /// Parse and format as C++03. - /// ``Cpp03`` is a deprecated alias for ``c++03`` + /// `Cpp03` is a deprecated alias for `c++03` LS_Cpp03, // c++03 /// Parse and format as C++11. LS_Cpp11, // c++11 @@ -5847,7 +5847,7 @@ struct FormatStyle { /// Parse and format as C++26. LS_Cpp26, // c++26 /// Parse and format using the latest supported language version. - /// ``Cpp11`` is a deprecated alias for ``Latest`` + /// `Cpp11` is a deprecated alias for `Latest` LS_Latest, /// Automatic detection based on the input. LS_Auto, @@ -5901,7 +5901,7 @@ struct FormatStyle { /// \endcode /// /// makes the line break only occurs inside DAGArgs beginning with the - /// specified identifiers ``ins`` and ``outs``. + /// specified identifiers `ins` and `outs`. /// /// \code /// let DAGArgIns = (ins @@ -5949,7 +5949,7 @@ struct FormatStyle { /// A vector of non-keyword identifiers that should be interpreted as template /// names. /// - /// A ``<`` after a template name is annotated as a template opener instead of + /// A `<` after a template name is annotated as a template opener instead of /// a binary operator. /// /// \version 20 @@ -5958,7 +5958,7 @@ struct FormatStyle { /// A vector of non-keyword identifiers that should be interpreted as type /// names. /// - /// A ``*``, ``&``, or ``&&`` between a type name and another non-keyword + /// A `*`, `&`, or `&&` between a type name and another non-keyword /// identifier is annotated as a pointer or reference token instead of a /// binary operator. /// @@ -5982,7 +5982,7 @@ struct FormatStyle { /// \version 9 std::vector TypenameMacros; - /// This option is **deprecated**. See ``LF`` and ``CRLF`` of ``LineEnding``. + /// This option is **deprecated**. See `LF` and `CRLF` of `LineEnding`. /// \version 10 // bool UseCRLF; @@ -6010,7 +6010,7 @@ struct FormatStyle { /// A vector of non-keyword identifiers that should be interpreted as variable /// template names. /// - /// A ``)`` after a variable template instantiation is **not** annotated as + /// A `)` after a variable template instantiation is **not** annotated as /// the closing parenthesis of C-style cast operator. /// /// \version 20 @@ -6072,7 +6072,7 @@ struct FormatStyle { /// \endcode WNBWELS_Always, /// Keep existing newlines at the beginning and the end of namespace body. - /// ``MaxEmptyLinesToKeep`` still applies. + /// `MaxEmptyLinesToKeep` still applies. WNBWELS_Leave }; @@ -6381,18 +6381,18 @@ FormatStyle getNoStyle(); /// Currently supported names: LLVM, Google, Chromium, Mozilla. Names are /// compared case-insensitively. /// -/// Returns ``true`` if the Style has been set. +/// Returns `true` if the Style has been set. bool getPredefinedStyle(StringRef Name, FormatStyle::LanguageKind Language, FormatStyle *Style); /// Parse configuration from YAML-formatted text. /// -/// Style->Language is used to get the base style, if the ``BasedOnStyle`` +/// Style->Language is used to get the base style, if the `BasedOnStyle` /// option is present. /// /// The FormatStyleSet of Style is reset. /// -/// When ``BasedOnStyle`` is not present, options not present in the YAML +/// When `BasedOnStyle` is not present, options not present in the YAML /// document, are retained in \p Style. /// /// If AllowUnknownOptions is true, no errors are emitted if unknown @@ -6417,8 +6417,8 @@ inline std::error_code parseConfiguration(StringRef Config, FormatStyle *Style, /// Gets configuration in a YAML string. std::string configurationAsText(const FormatStyle &Style); -/// Returns the replacements necessary to sort all ``#include`` blocks -/// that are affected by ``Ranges``. +/// Returns the replacements necessary to sort all `#include` blocks +/// that are affected by `Ranges`. tooling::Replacements sortIncludes(const FormatStyle &Style, StringRef Code, ArrayRef Ranges, StringRef FileName, @@ -6441,7 +6441,7 @@ formatReplacements(StringRef Code, const tooling::Replacements &Replaces, /// * If a replacement has offset UINT_MAX, length 1, and a replacement text /// that is the name of the header to be removed, the header will be removed /// from \p Code if it exists. -/// The include manipulation is done via ``tooling::HeaderInclude``, see its +/// The include manipulation is done via `tooling::HeaderInclude`, see its /// documentation for more details on how include insertion points are found and /// what edits are produced. Expected @@ -6450,11 +6450,11 @@ cleanupAroundReplacements(StringRef Code, const tooling::Replacements &Replaces, /// Represents the status of a formatting attempt. struct FormattingAttemptStatus { - /// A value of ``false`` means that any of the affected ranges were not + /// A value of `false` means that any of the affected ranges were not /// formatted due to a non-recoverable syntax error. bool FormatComplete = true; - /// If ``FormatComplete`` is false, ``Line`` records a one-based + /// If `FormatComplete` is false, `Line` records a one-based /// original line number at which a syntax error might have occurred. This is /// based on a best-effort analysis and could be imprecise. unsigned Line = 0; @@ -6466,17 +6466,17 @@ struct FormattingAttemptStatus { /// everything that might influence its formatting or might be influenced by its /// formatting. /// -/// Returns the ``Replacements`` necessary to make all \p Ranges comply with +/// Returns the `Replacements` necessary to make all \p Ranges comply with /// \p Style. /// -/// If ``Status`` is non-null, its value will be populated with the status of +/// If `Status` is non-null, its value will be populated with the status of /// this formatting attempt. See \c FormattingAttemptStatus. tooling::Replacements reformat(const FormatStyle &Style, StringRef Code, ArrayRef Ranges, StringRef FileName = "", FormattingAttemptStatus *Status = nullptr); -/// Same as above, except if ``IncompleteFormat`` is non-null, its value +/// Same as above, except if `IncompleteFormat` is non-null, its value /// will be set to true if any of the affected ranges were not formatted due to /// a non-recoverable syntax error. tooling::Replacements reformat(const FormatStyle &Style, StringRef Code, @@ -6486,14 +6486,14 @@ tooling::Replacements reformat(const FormatStyle &Style, StringRef Code, /// Clean up any erroneous/redundant code in the given \p Ranges in \p /// Code. /// -/// Returns the ``Replacements`` that clean up all \p Ranges in \p Code. +/// Returns the `Replacements` that clean up all \p Ranges in \p Code. tooling::Replacements cleanup(const FormatStyle &Style, StringRef Code, ArrayRef Ranges, StringRef FileName = ""); /// Fix namespace end comments in the given \p Ranges in \p Code. /// -/// Returns the ``Replacements`` that fix the namespace comments in all +/// Returns the `Replacements` that fix the namespace comments in all /// \p Ranges in \p Code. tooling::Replacements fixNamespaceEndComments(const FormatStyle &Style, StringRef Code, @@ -6504,7 +6504,7 @@ tooling::Replacements fixNamespaceEndComments(const FormatStyle &Style, /// classes, structs, functions, namespaces, and enums in the given \p Ranges in /// \p Code. /// -/// Returns the ``Replacements`` that inserts or removes empty lines separating +/// Returns the `Replacements` that inserts or removes empty lines separating /// definition blocks in all \p Ranges in \p Code. tooling::Replacements separateDefinitionBlocks(const FormatStyle &Style, StringRef Code, @@ -6514,46 +6514,46 @@ tooling::Replacements separateDefinitionBlocks(const FormatStyle &Style, /// Sort consecutive using declarations in the given \p Ranges in /// \p Code. /// -/// Returns the ``Replacements`` that sort the using declarations in all +/// Returns the `Replacements` that sort the using declarations in all /// \p Ranges in \p Code. tooling::Replacements sortUsingDeclarations(const FormatStyle &Style, StringRef Code, ArrayRef Ranges, StringRef FileName = ""); -/// Returns the ``LangOpts`` that the formatter expects you to set. +/// Returns the `LangOpts` that the formatter expects you to set. /// /// \param Style determines specific settings for lexing mode. LangOptions getFormattingLangOpts(const FormatStyle &Style = getLLVMStyle()); -/// Description to be used for help text for a ``llvm::cl`` option for +/// Description to be used for help text for a `llvm::cl` option for /// specifying format style. The description is closely related to the operation -/// of ``getStyle()``. +/// of `getStyle()`. extern const char *StyleOptionHelpDescription; /// The suggested format style to use by default. This allows tools using -/// ``getStyle`` to have a consistent default style. +/// `getStyle` to have a consistent default style. /// Different builds can modify the value to the preferred styles. extern const char *DefaultFormatStyle; -/// The suggested predefined style to use as the fallback style in ``getStyle``. +/// The suggested predefined style to use as the fallback style in `getStyle`. /// Different builds can modify the value to the preferred styles. extern const char *DefaultFallbackStyle; -/// Construct a FormatStyle based on ``StyleName``. +/// Construct a FormatStyle based on `StyleName`. /// -/// ``StyleName`` can take several forms: +/// `StyleName` can take several forms: /// * "{: , ...}" - Set specic style parameters. /// * "