Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[C++17] Support __GCC_[CON|DE]STRUCTIVE_SIZE #89446

Merged
merged 14 commits into from
Apr 26, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5571,3 +5571,17 @@ but the expression has no runtime effects.
Type- and value-dependent expressions are not supported yet.

This facility is designed to aid with testing name lookup machinery.

Predefined Macros
=================

`__GCC_DESTRUCTIVE_SIZE` and `__GCC_CONSTRUCTIVE_SIZE`
------------------------------------------------------
Specify the mimum offset between two objects to avoid false sharing and the
maximum size of contiguous memory to promote true sharing, respectively. These
macros are predefined in all C and C++ language modes.

**Note: the values the macros expand to are not stable between releases of Clang
and do not need to match the values produced by GCC, so these macros should not
be used from header files because they may not be stable across multiple TUs
(the values may vary based on compiler version as well as CPU tuning).**
Copy link
Contributor

@cor3ntin cor3ntin Apr 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
**Note: the values the macros expand to are not stable between releases of Clang
and do not need to match the values produced by GCC, so these macros should not
be used from header files because they may not be stable across multiple TUs
(the values may vary based on compiler version as well as CPU tuning).**
**Note: the values the macros expand to are not guaranteed to be stable. They are are affected by architectures and CPU tuning flags, can change between releases of Clang and will not match the values defined by other compilers such as GCC.**
**Compiling different TUs depending on these flags (or `std::hardware_constructive_interference` , `std::hardware_destructive_interference`) with different compilers, defines or architecture flags will lead to ODR violations bugs and should be avoided.**

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

12 changes: 12 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,18 @@ sections with improvements to Clang's support for those languages.
C++ Language Changes
--------------------

C++17 Feature Support
^^^^^^^^^^^^^^^^^^^^^
- Clang now exposes ``__GCC_DESTRUCTIVE_SIZE`` and ``__GCC_CONSTRUCTIVE_SIZE``
predefined macros to support standard library implementations of
``std::hardware_destructive_interference_size`` and
``std::hardware_constructive_interference_size``, respectively. These macros
are predefined in all C and C++ language modes. The values the macros
expand to are not stable between releases of Clang and do not need to match
the values produced by GCC, so these macros should not be used from header
files because they may not be stable across multiple TUs (the values may vary
based on compiler version as well as CPU tuning). #GH60174

C++20 Feature Support
^^^^^^^^^^^^^^^^^^^^^

Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Basic/TargetInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -1792,6 +1792,11 @@ class TargetInfo : public TransferrableTargetInfo,
/// Whether to support HIP image/texture API's.
virtual bool hasHIPImageSupport() const { return true; }

/// The minimum offset between two objects to avoid false sharing.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might add a comment here that this is not considered part of the ABI, and is okay to change, for clarity of future target maintainers.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call! Done.

virtual unsigned hardwareDestructiveInterferenceSize() const { return 64; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I vaguely wonder if we should make this a single "hardwareInterferenceSizes" function, returning a std::pair<unsigned, unsigned>, because otherwise, when we start add per-CPU tuning to the values, it's very likely to result in duplicating the same series of conditionals in each of the two functions.

Also, with a single function, we are less likely to accidentally end up with an override that returns values such that destructive < constructive.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good idea, thanks! Done.

// The maximum size of contiguous memory to promote true sharing.
virtual unsigned hardwareConstructiveInterferenceSize() const { return 64; }

protected:
/// Copy type and layout related info.
void copyAuxTarget(const TargetInfo *Aux);
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Basic/Targets/ARM.h
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,10 @@ class LLVM_LIBRARY_VISIBILITY ARMTargetInfo : public TargetInfo {
bool hasBitIntType() const override { return true; }

const char *getBFloat16Mangling() const override { return "u6__bf16"; };

virtual unsigned hardwareDestructiveInterferenceSize() const override {
return getTriple().isArch64Bit() ? 256 : 64;
}
};

class LLVM_LIBRARY_VISIBILITY ARMleTargetInfo : public ARMTargetInfo {
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/Basic/Targets/AVR.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,13 @@ class LLVM_LIBRARY_VISIBILITY AVRTargetInfo : public TargetInfo {
std::optional<std::string> handleAsmEscapedChar(char EscChar) const override;
StringRef getABI() const override { return ABI; }

virtual unsigned hardwareDestructiveInterferenceSize() const override {
return 32;
}
virtual unsigned hardwareConstructiveInterferenceSize() const override {
return 32;
}

protected:
std::string CPU;
StringRef ABI;
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/Basic/Targets/BPF.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,13 @@ class LLVM_LIBRARY_VISIBILITY BPFTargetInfo : public TargetInfo {
StringRef CPUName(Name);
return isValidCPUName(CPUName);
}

virtual unsigned hardwareDestructiveInterferenceSize() const override {
return 32;
}
virtual unsigned hardwareConstructiveInterferenceSize() const override {
return 32;
}
};
} // namespace targets
} // namespace clang
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/Basic/Targets/M68k.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,13 @@ class LLVM_LIBRARY_VISIBILITY M68kTargetInfo : public TargetInfo {
BuiltinVaListKind getBuiltinVaListKind() const override;
bool setCPU(const std::string &Name) override;
CallingConvCheckResult checkCallingConvention(CallingConv CC) const override;

virtual unsigned hardwareDestructiveInterferenceSize() const override {
return 32;
}
virtual unsigned hardwareConstructiveInterferenceSize() const override {
return 32;
}
};

} // namespace targets
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/Basic/Targets/Mips.h
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,13 @@ class LLVM_LIBRARY_VISIBILITY MipsTargetInfo : public TargetInfo {

bool validateTarget(DiagnosticsEngine &Diags) const override;
bool hasBitIntType() const override { return true; }

virtual unsigned hardwareDestructiveInterferenceSize() const override {
return 32;
}
virtual unsigned hardwareConstructiveInterferenceSize() const override {
return 32;
}
};
} // namespace targets
} // namespace clang
Expand Down
14 changes: 14 additions & 0 deletions clang/lib/Basic/Targets/PPC.h
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,13 @@ class LLVM_LIBRARY_VISIBILITY PPC32TargetInfo : public PPCTargetInfo {
// This is the ELF definition
return TargetInfo::PowerABIBuiltinVaList;
}

virtual unsigned hardwareDestructiveInterferenceSize() const override {
return 32;
}
virtual unsigned hardwareConstructiveInterferenceSize() const override {
return 32;
}
};

// Note: ABI differences may eventually require us to have a separate
Expand Down Expand Up @@ -502,6 +509,13 @@ class LLVM_LIBRARY_VISIBILITY PPC64TargetInfo : public PPCTargetInfo {
return CCCR_Warning;
}
}

virtual unsigned hardwareDestructiveInterferenceSize() const override {
return 128;
}
virtual unsigned hardwareConstructiveInterferenceSize() const override {
return 128;
}
};

class LLVM_LIBRARY_VISIBILITY AIXPPC32TargetInfo :
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/Basic/Targets/RISCV.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,13 @@ class RISCVTargetInfo : public TargetInfo {
void fillValidTuneCPUList(SmallVectorImpl<StringRef> &Values) const override;
bool supportsTargetAttributeTune() const override { return true; }
ParsedTargetAttr parseTargetAttr(StringRef Str) const override;

virtual unsigned hardwareDestructiveInterferenceSize() const override {
return 32;
}
virtual unsigned hardwareConstructiveInterferenceSize() const override {
return 32;
}
};
class LLVM_LIBRARY_VISIBILITY RISCV32TargetInfo : public RISCVTargetInfo {
public:
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/Basic/Targets/Sparc.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,13 @@ class LLVM_LIBRARY_VISIBILITY SparcTargetInfo : public TargetInfo {
CPU = getCPUKind(Name);
return CPU != CK_GENERIC;
}

virtual unsigned hardwareDestructiveInterferenceSize() const override {
return 32;
}
virtual unsigned hardwareConstructiveInterferenceSize() const override {
return 32;
}
};

// SPARC v8 is the 32-bit mode selected by Triple::sparc.
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/Basic/Targets/SystemZ.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,13 @@ class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo {
int getEHDataRegisterNumber(unsigned RegNo) const override {
return RegNo < 4 ? 6 + RegNo : -1;
}

virtual unsigned hardwareDestructiveInterferenceSize() const override {
return 256;
}
virtual unsigned hardwareConstructiveInterferenceSize() const override {
return 256;
}
};
} // namespace targets
} // namespace clang
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/Frontend/InitPreprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1309,6 +1309,13 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
Builder.defineMacro("__GCC_ATOMIC_TEST_AND_SET_TRUEVAL", "1");
}

// GCC defines these macros in both C and C++ modes despite them being needed
// mostly for STL implementations in C++.
Builder.defineMacro("__GCC_DESTRUCTIVE_SIZE",
Twine(TI.hardwareDestructiveInterferenceSize()));
Builder.defineMacro("__GCC_CONSTRUCTIVE_SIZE",
Twine(TI.hardwareConstructiveInterferenceSize()));

auto addLockFreeMacros = [&](const llvm::Twine &Prefix) {
// Used by libc++ and libstdc++ to implement ATOMIC_<foo>_LOCK_FREE.
#define DEFINE_LOCK_FREE_MACRO(TYPE, Type) \
Expand Down
12 changes: 7 additions & 5 deletions clang/test/Preprocessor/init-aarch64.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@
// AARCH64-NEXT: #define __FP_FAST_FMA 1
// AARCH64-NEXT: #define __FP_FAST_FMAF 1
// AARCH64-NEXT: #define __GCC_ASM_FLAG_OUTPUTS__ 1
// AARCH64-NEXT: #define __GCC_CONSTRUCTIVE_SIZE {{.+}}
// AARCH64-NEXT: #define __GCC_DESTRUCTIVE_SIZE {{.+}}
// AARCH64-NEXT: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1
// AARCH64-NEXT: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 1
// AARCH64-NEXT: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1
Expand Down Expand Up @@ -220,11 +222,11 @@
// AARCH64-NEXT: #define __LONG_MAX__ 9223372036854775807L
// AARCH64-NEXT: #define __LONG_WIDTH__ 64
// AARCH64-NEXT: #define __LP64__ 1
// AARCH64-NEXT: #define __MEMORY_SCOPE_DEVICE 1
// AARCH64-NEXT: #define __MEMORY_SCOPE_SINGLE 4
// AARCH64-NEXT: #define __MEMORY_SCOPE_SYSTEM 0
// AARCH64-NEXT: #define __MEMORY_SCOPE_WRKGRP 2
// AARCH64-NEXT: #define __MEMORY_SCOPE_WVFRNT 3
// AARCH64-NEXT: #define __MEMORY_SCOPE_DEVICE 1
// AARCH64-NEXT: #define __MEMORY_SCOPE_SINGLE 4
// AARCH64-NEXT: #define __MEMORY_SCOPE_SYSTEM 0
// AARCH64-NEXT: #define __MEMORY_SCOPE_WRKGRP 2
// AARCH64-NEXT: #define __MEMORY_SCOPE_WVFRNT 3
// AARCH64-NEXT: #define __NO_INLINE__ 1
// AARCH64-NEXT: #define __NO_MATH_ERRNO__ 1
// AARCH64-NEXT: #define __OBJC_BOOL_IS_BOOL 0
Expand Down
49 changes: 29 additions & 20 deletions clang/test/Preprocessor/init.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
// RUN: %clang_cc1 -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix INTERFERENCE %s
//
// We purposefully do not test the values produced, only that the macros are
// predefined to some value.
// INTERFERENCE:#define __GCC_CONSTRUCTIVE_SIZE {{.+}}
// INTERFERENCE:#define __GCC_DESTRUCTIVE_SIZE {{.+}}

// RUN: %clang_cc1 -E -dM -x assembler-with-cpp < /dev/null | FileCheck -match-full-lines -check-prefix ASM %s
//
// ASM:#define __ASSEMBLER__ 1
Expand Down Expand Up @@ -1697,6 +1704,8 @@
// WEBASSEMBLY-NEXT:#define __GCC_ATOMIC_SHORT_LOCK_FREE 2
// WEBASSEMBLY-NEXT:#define __GCC_ATOMIC_TEST_AND_SET_TRUEVAL 1
// WEBASSEMBLY-NEXT:#define __GCC_ATOMIC_WCHAR_T_LOCK_FREE 2
// WEBASSEMBLY-NEXT:#define __GCC_CONSTRUCTIVE_SIZE {{.+}}
// WEBASSEMBLY-NEXT:#define __GCC_DESTRUCTIVE_SIZE {{.+}}
// WEBASSEMBLY-NEXT:#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1
// WEBASSEMBLY-NEXT:#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1
// WEBASSEMBLY-NEXT:#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1
Expand Down Expand Up @@ -1806,11 +1815,11 @@
// WEBASSEMBLY64-NEXT:#define __LONG_MAX__ 9223372036854775807L
// WEBASSEMBLY64-NEXT:#define __LONG_WIDTH__ 64
// WEBASSEMBLY64-NEXT:#define __LP64__ 1
// WEBASSEMBLY-NEXT:#define __MEMORY_SCOPE_DEVICE 1
// WEBASSEMBLY-NEXT:#define __MEMORY_SCOPE_SINGLE 4
// WEBASSEMBLY-NEXT:#define __MEMORY_SCOPE_SYSTEM 0
// WEBASSEMBLY-NEXT:#define __MEMORY_SCOPE_WRKGRP 2
// WEBASSEMBLY-NEXT:#define __MEMORY_SCOPE_WVFRNT 3
// WEBASSEMBLY-NEXT:#define __MEMORY_SCOPE_DEVICE 1
// WEBASSEMBLY-NEXT:#define __MEMORY_SCOPE_SINGLE 4
// WEBASSEMBLY-NEXT:#define __MEMORY_SCOPE_SYSTEM 0
// WEBASSEMBLY-NEXT:#define __MEMORY_SCOPE_WRKGRP 2
// WEBASSEMBLY-NEXT:#define __MEMORY_SCOPE_WVFRNT 3
// WEBASSEMBLY-NEXT:#define __NO_INLINE__ 1
// WEBASSEMBLY-NEXT:#define __NO_MATH_ERRNO__ 1
// WEBASSEMBLY-NEXT:#define __OBJC_BOOL_IS_BOOL 0
Expand Down Expand Up @@ -2126,11 +2135,11 @@
// AVR:#define __LDBL_MIN__ 1.17549435e-38L
// AVR:#define __LONG_LONG_MAX__ 9223372036854775807LL
// AVR:#define __LONG_MAX__ 2147483647L
// AVR:#define __MEMORY_SCOPE_DEVICE 1
// AVR:#define __MEMORY_SCOPE_SINGLE 4
// AVR:#define __MEMORY_SCOPE_SYSTEM 0
// AVR:#define __MEMORY_SCOPE_WRKGRP 2
// AVR:#define __MEMORY_SCOPE_WVFRNT 3
// AVR:#define __MEMORY_SCOPE_DEVICE 1
// AVR:#define __MEMORY_SCOPE_SINGLE 4
// AVR:#define __MEMORY_SCOPE_SYSTEM 0
// AVR:#define __MEMORY_SCOPE_WRKGRP 2
// AVR:#define __MEMORY_SCOPE_WVFRNT 3
// AVR:#define __NO_INLINE__ 1
// AVR:#define __ORDER_BIG_ENDIAN__ 4321
// AVR:#define __ORDER_LITTLE_ENDIAN__ 1234
Expand Down Expand Up @@ -2422,11 +2431,11 @@
// RISCV32: #define __LITTLE_ENDIAN__ 1
// RISCV32: #define __LONG_LONG_MAX__ 9223372036854775807LL
// RISCV32: #define __LONG_MAX__ 2147483647L
// RISCV32: #define __MEMORY_SCOPE_DEVICE 1
// RISCV32: #define __MEMORY_SCOPE_SINGLE 4
// RISCV32: #define __MEMORY_SCOPE_SYSTEM 0
// RISCV32: #define __MEMORY_SCOPE_WRKGRP 2
// RISCV32: #define __MEMORY_SCOPE_WVFRNT 3
// RISCV32: #define __MEMORY_SCOPE_DEVICE 1
// RISCV32: #define __MEMORY_SCOPE_SINGLE 4
// RISCV32: #define __MEMORY_SCOPE_SYSTEM 0
// RISCV32: #define __MEMORY_SCOPE_WRKGRP 2
// RISCV32: #define __MEMORY_SCOPE_WVFRNT 3
// RISCV32: #define __NO_INLINE__ 1
// RISCV32: #define __POINTER_WIDTH__ 32
// RISCV32: #define __PRAGMA_REDEFINE_EXTNAME 1
Expand Down Expand Up @@ -2634,11 +2643,11 @@
// RISCV64: #define __LONG_LONG_MAX__ 9223372036854775807LL
// RISCV64: #define __LONG_MAX__ 9223372036854775807L
// RISCV64: #define __LP64__ 1
// RISCV64: #define __MEMORY_SCOPE_DEVICE 1
// RISCV64: #define __MEMORY_SCOPE_SINGLE 4
// RISCV64: #define __MEMORY_SCOPE_SYSTEM 0
// RISCV64: #define __MEMORY_SCOPE_WRKGRP 2
// RISCV64: #define __MEMORY_SCOPE_WVFRNT 3
// RISCV64: #define __MEMORY_SCOPE_DEVICE 1
// RISCV64: #define __MEMORY_SCOPE_SINGLE 4
// RISCV64: #define __MEMORY_SCOPE_SYSTEM 0
// RISCV64: #define __MEMORY_SCOPE_WRKGRP 2
// RISCV64: #define __MEMORY_SCOPE_WVFRNT 3
// RISCV64: #define __NO_INLINE__ 1
// RISCV64: #define __POINTER_WIDTH__ 64
// RISCV64: #define __PRAGMA_REDEFINE_EXTNAME 1
Expand Down
6 changes: 4 additions & 2 deletions clang/test/Preprocessor/predefined-win-macros.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// RUN: %clang_cc1 %s -x c++ -E -dM -triple x86_64-pc-win32 -fms-extensions -fms-compatibility \
// RUN: -fms-compatibility-version=19.00 -std=c++14 -o - | FileCheck -match-full-lines %s --check-prefix=CHECK-MS64
// RUN: %clang_cc1 %s -x c++ -E -dM -triple x86_64-pc-win32 -fms-extensions -fms-compatibility \
// RUN: -fms-compatibility-version=19.00 -std=c++14 -o - | grep GCC | count 5
// RUN: -fms-compatibility-version=19.00 -std=c++14 -o - | grep GCC | count 7
// CHECK-MS64: #define _INTEGRAL_MAX_BITS 64
// CHECK-MS64: #define _ISO_VOLATILE 1
// CHECK-MS64: #define _MSC_EXTENSIONS 1
Expand All @@ -26,7 +26,7 @@
// RUN: %clang_cc1 %s -x c++ -E -dM -triple i686-pc-win32 -fms-extensions -fms-compatibility \
// RUN: -fms-compatibility-version=19.00 -std=c++17 -o - | FileCheck -match-full-lines %s --check-prefix=CHECK-MS
// RUN: %clang_cc1 %s -x c++ -E -dM -triple i686-pc-win32 -fms-extensions -fms-compatibility \
// RUN: -fms-compatibility-version=19.00 -std=c++17 -o - | grep GCC | count 5
// RUN: -fms-compatibility-version=19.00 -std=c++17 -o - | grep GCC | count 7
// CHECK-MS: #define _INTEGRAL_MAX_BITS 64
// CHECK-MS: #define _ISO_VOLATILE 1
// CHECK-MS: #define _MSC_EXTENSIONS 1
Expand All @@ -39,6 +39,8 @@
// CHECK-MS-NOT: GNU
// CHECK-MS-NOT: GXX
// CHECK-MS: #define __GCC_ASM_FLAG_OUTPUTS__ 1
// CHECK-MS: #define __GCC_CONSTRUCTIVE_SIZE {{.+}}
// CHECK-MS: #define __GCC_DESTRUCTIVE_SIZE {{.+}}
// CHECK-MS: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1
// CHECK-MS: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1
// CHECK-MS: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
//===----------------------------------------------------------------------===//

// UNSUPPORTED: c++03, c++11, c++14
// XFAIL: (clang || apple-clang) && stdlib=libc++
// XFAIL: (clang-17 || clang-18 || apple-clang-15) && stdlib=libc++

#include <new>

Expand Down
Loading