Author: Simon Pilgrim Date: 2024-09-28T17:52:54+01:00 New Revision: 1c2ed36741c6bc3921d2566123019079c4249c1a
URL: https://github.com/llvm/llvm-project/commit/1c2ed36741c6bc3921d2566123019079c4249c1a DIFF: https://github.com/llvm/llvm-project/commit/1c2ed36741c6bc3921d2566123019079c4249c1a.diff LOG: [clang][x86] Add constexpr support for BMI/TBM BEXTR intrinsics (#109577) This is an initial patch for constexpr handling of the BEXTR intrinsics - the plan is to support all x86 bit manipulation intrinsics eventually (and then SSE/AVX intrinsics), but I wanted to treat this as an initial test patch. Hopefully this will unstick #94161 as well. Added: Modified: clang/include/clang/Basic/BuiltinsX86.def clang/include/clang/Basic/BuiltinsX86_64.def clang/lib/AST/ExprConstant.cpp clang/lib/Headers/bmiintrin.h clang/test/CodeGen/X86/bmi-builtins.c clang/test/CodeGen/X86/tbm-builtins.c Removed: ################################################################################ diff --git a/clang/include/clang/Basic/BuiltinsX86.def b/clang/include/clang/Basic/BuiltinsX86.def index 25c656a530b158..e4eb9bfbdd1735 100644 --- a/clang/include/clang/Basic/BuiltinsX86.def +++ b/clang/include/clang/Basic/BuiltinsX86.def @@ -555,7 +555,7 @@ TARGET_BUILTIN(__builtin_ia32_lzcnt_u16, "UsUs", "nc", "lzcnt") TARGET_BUILTIN(__builtin_ia32_lzcnt_u32, "UiUi", "nc", "lzcnt") // BMI -TARGET_BUILTIN(__builtin_ia32_bextr_u32, "UiUiUi", "nc", "bmi") +TARGET_BUILTIN(__builtin_ia32_bextr_u32, "UiUiUi", "ncE", "bmi") TARGET_BUILTIN(__builtin_ia32_tzcnt_u16, "UsUs", "nc", "") TARGET_BUILTIN(__builtin_ia32_tzcnt_u32, "UiUi", "nc", "") @@ -565,7 +565,7 @@ TARGET_BUILTIN(__builtin_ia32_pdep_si, "UiUiUi", "nc", "bmi2") TARGET_BUILTIN(__builtin_ia32_pext_si, "UiUiUi", "nc", "bmi2") // TBM -TARGET_BUILTIN(__builtin_ia32_bextri_u32, "UiUiIUi", "nc", "tbm") +TARGET_BUILTIN(__builtin_ia32_bextri_u32, "UiUiIUi", "ncE", "tbm") // LWP TARGET_BUILTIN(__builtin_ia32_llwpcb, "vv*", "n", "lwp") diff --git a/clang/include/clang/Basic/BuiltinsX86_64.def b/clang/include/clang/Basic/BuiltinsX86_64.def index db381aa77e7612..81fd46ee6d1663 100644 --- a/clang/include/clang/Basic/BuiltinsX86_64.def +++ b/clang/include/clang/Basic/BuiltinsX86_64.def @@ -71,12 +71,12 @@ TARGET_BUILTIN(__builtin_ia32_subborrow_u64, "UcUcUOiUOiUOi*", "n", "") TARGET_BUILTIN(__builtin_ia32_rdrand64_step, "UiUOi*", "n", "rdrnd") TARGET_BUILTIN(__builtin_ia32_rdseed64_step, "UiUOi*", "n", "rdseed") TARGET_BUILTIN(__builtin_ia32_lzcnt_u64, "UOiUOi", "nc", "lzcnt") -TARGET_BUILTIN(__builtin_ia32_bextr_u64, "UOiUOiUOi", "nc", "bmi") +TARGET_BUILTIN(__builtin_ia32_bextr_u64, "UOiUOiUOi", "ncE", "bmi") TARGET_BUILTIN(__builtin_ia32_tzcnt_u64, "UOiUOi", "nc", "") TARGET_BUILTIN(__builtin_ia32_bzhi_di, "UOiUOiUOi", "nc", "bmi2") TARGET_BUILTIN(__builtin_ia32_pdep_di, "UOiUOiUOi", "nc", "bmi2") TARGET_BUILTIN(__builtin_ia32_pext_di, "UOiUOiUOi", "nc", "bmi2") -TARGET_BUILTIN(__builtin_ia32_bextri_u64, "UOiUOiIUOi", "nc", "tbm") +TARGET_BUILTIN(__builtin_ia32_bextri_u64, "UOiUOiIUOi", "ncE", "tbm") TARGET_BUILTIN(__builtin_ia32_lwpins64, "UcUOiUiIUi", "n", "lwp") TARGET_BUILTIN(__builtin_ia32_lwpval64, "vUOiUiIUi", "n", "lwp") TARGET_BUILTIN(__builtin_ia32_vcvtsd2si64, "OiV2dIi", "ncV:128:", "avx512f") diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 960eae36ed1f51..51856693944761 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -52,6 +52,7 @@ #include "clang/AST/TypeLoc.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/DiagnosticSema.h" +#include "clang/Basic/TargetBuiltins.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/APFixedPoint.h" #include "llvm/ADT/Sequence.h" @@ -13462,6 +13463,29 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, return false; return Success(DidOverflow, E); } + + case clang::X86::BI__builtin_ia32_bextr_u32: + case clang::X86::BI__builtin_ia32_bextr_u64: + case clang::X86::BI__builtin_ia32_bextri_u32: + case clang::X86::BI__builtin_ia32_bextri_u64: { + APSInt Val, Idx; + if (!EvaluateInteger(E->getArg(0), Val, Info) || + !EvaluateInteger(E->getArg(1), Idx, Info)) + return false; + + unsigned BitWidth = Val.getBitWidth(); + uint64_t Shift = Idx.extractBitsAsZExtValue(8, 0); + uint64_t Length = Idx.extractBitsAsZExtValue(8, 8); + Length = Length > BitWidth ? BitWidth : Length; + + // Handle out of bounds cases. + if (Length == 0 || Shift >= BitWidth) + return Success(0, E); + + uint64_t Result = Val.getZExtValue() >> Shift; + Result &= llvm::maskTrailingOnes<uint64_t>(Length); + return Success(Result, E); + } } } diff --git a/clang/lib/Headers/bmiintrin.h b/clang/lib/Headers/bmiintrin.h index 78bffe68e221a9..72c84d12c0e520 100644 --- a/clang/lib/Headers/bmiintrin.h +++ b/clang/lib/Headers/bmiintrin.h @@ -166,6 +166,12 @@ _mm_tzcnt_64(unsigned long long __X) /* Define the default attributes for the functions in this file. */ #define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__, __target__("bmi"))) +#if defined(__cplusplus) && (__cplusplus >= 201103L) +#define __DEFAULT_FN_ATTRS_CONSTEXPR __DEFAULT_FN_ATTRS constexpr +#else +#define __DEFAULT_FN_ATTRS_CONSTEXPR __DEFAULT_FN_ATTRS +#endif + /// Performs a bitwise AND of the second operand with the one's /// complement of the first operand. /// @@ -223,9 +229,8 @@ __andn_u32(unsigned int __X, unsigned int __Y) /// \returns An unsigned integer whose least significant bits contain the /// extracted bits. /// \see _bextr_u32 -static __inline__ unsigned int __DEFAULT_FN_ATTRS -__bextr_u32(unsigned int __X, unsigned int __Y) -{ +static __inline__ unsigned int __DEFAULT_FN_ATTRS_CONSTEXPR +__bextr_u32(unsigned int __X, unsigned int __Y) { return __builtin_ia32_bextr_u32(__X, __Y); } @@ -248,10 +253,9 @@ __bextr_u32(unsigned int __X, unsigned int __Y) /// \returns An unsigned integer whose least significant bits contain the /// extracted bits. /// \see __bextr_u32 -static __inline__ unsigned int __DEFAULT_FN_ATTRS -_bextr_u32(unsigned int __X, unsigned int __Y, unsigned int __Z) -{ - return __builtin_ia32_bextr_u32 (__X, ((__Y & 0xff) | ((__Z & 0xff) << 8))); +static __inline__ unsigned int __DEFAULT_FN_ATTRS_CONSTEXPR +_bextr_u32(unsigned int __X, unsigned int __Y, unsigned int __Z) { + return __builtin_ia32_bextr_u32(__X, ((__Y & 0xff) | ((__Z & 0xff) << 8))); } /* Intel-specified, single-leading-underscore version of BEXTR2 */ @@ -271,7 +275,7 @@ _bextr_u32(unsigned int __X, unsigned int __Y, unsigned int __Z) /// \returns An unsigned integer whose least significant bits contain the /// extracted bits. /// \see __bextr_u32 -static __inline__ unsigned int __DEFAULT_FN_ATTRS +static __inline__ unsigned int __DEFAULT_FN_ATTRS_CONSTEXPR _bextr2_u32(unsigned int __X, unsigned int __Y) { return __builtin_ia32_bextr_u32(__X, __Y); } @@ -444,9 +448,8 @@ __andn_u64 (unsigned long long __X, unsigned long long __Y) /// \returns An unsigned 64-bit integer whose least significant bits contain the /// extracted bits. /// \see _bextr_u64 -static __inline__ unsigned long long __DEFAULT_FN_ATTRS -__bextr_u64(unsigned long long __X, unsigned long long __Y) -{ +static __inline__ unsigned long long __DEFAULT_FN_ATTRS_CONSTEXPR +__bextr_u64(unsigned long long __X, unsigned long long __Y) { return __builtin_ia32_bextr_u64(__X, __Y); } @@ -469,10 +472,9 @@ __bextr_u64(unsigned long long __X, unsigned long long __Y) /// \returns An unsigned 64-bit integer whose least significant bits contain the /// extracted bits. /// \see __bextr_u64 -static __inline__ unsigned long long __DEFAULT_FN_ATTRS -_bextr_u64(unsigned long long __X, unsigned int __Y, unsigned int __Z) -{ - return __builtin_ia32_bextr_u64 (__X, ((__Y & 0xff) | ((__Z & 0xff) << 8))); +static __inline__ unsigned long long __DEFAULT_FN_ATTRS_CONSTEXPR +_bextr_u64(unsigned long long __X, unsigned int __Y, unsigned int __Z) { + return __builtin_ia32_bextr_u64(__X, ((__Y & 0xff) | ((__Z & 0xff) << 8))); } /* Intel-specified, single-leading-underscore version of BEXTR2 */ @@ -492,7 +494,7 @@ _bextr_u64(unsigned long long __X, unsigned int __Y, unsigned int __Z) /// \returns An unsigned 64-bit integer whose least significant bits contain the /// extracted bits. /// \see __bextr_u64 -static __inline__ unsigned long long __DEFAULT_FN_ATTRS +static __inline__ unsigned long long __DEFAULT_FN_ATTRS_CONSTEXPR _bextr2_u64(unsigned long long __X, unsigned long long __Y) { return __builtin_ia32_bextr_u64(__X, __Y); } diff --git a/clang/test/CodeGen/X86/bmi-builtins.c b/clang/test/CodeGen/X86/bmi-builtins.c index 81405429b9b6cd..530d38dcf342c0 100644 --- a/clang/test/CodeGen/X86/bmi-builtins.c +++ b/clang/test/CodeGen/X86/bmi-builtins.c @@ -1,5 +1,7 @@ -// RUN: %clang_cc1 -ffreestanding %s -triple=x86_64-apple-darwin -target-feature +bmi -emit-llvm -o - -Wall -Werror | FileCheck %s --check-prefixes=CHECK,TZCNT -// RUN: %clang_cc1 -fms-extensions -fms-compatibility -fms-compatibility-version=17.00 -ffreestanding %s -triple=x86_64-windows-msvc -emit-llvm -o - -Wall -Werror -DTEST_TZCNT | FileCheck %s --check-prefix=TZCNT +// RUN: %clang_cc1 -x c -ffreestanding %s -triple=x86_64-apple-darwin -target-feature +bmi -emit-llvm -o - -Wall -Werror | FileCheck %s --check-prefixes=CHECK,TZCNT +// RUN: %clang_cc1 -x c -fms-extensions -fms-compatibility -fms-compatibility-version=17.00 -ffreestanding %s -triple=x86_64-windows-msvc -emit-llvm -o - -Wall -Werror -DTEST_TZCNT | FileCheck %s --check-prefix=TZCNT +// RUN: %clang_cc1 -x c++ -std=c++11 -ffreestanding %s -triple=x86_64-apple-darwin -target-feature +bmi -emit-llvm -o - -Wall -Werror | FileCheck %s --check-prefixes=CHECK,TZCNT +// RUN: %clang_cc1 -x c++ -std=c++11 -fms-extensions -fms-compatibility -fms-compatibility-version=17.00 -ffreestanding %s -triple=x86_64-windows-msvc -emit-llvm -o - -Wall -Werror -DTEST_TZCNT | FileCheck %s --check-prefix=TZCNT #include <immintrin.h> @@ -232,3 +234,32 @@ unsigned long long test_blsr_u64(unsigned long long __X) { #endif #endif // !defined(TEST_TZCNT) + +// Test constexpr handling. +#if defined(__cplusplus) && (__cplusplus >= 201103L) +char bextr32_0[__bextr_u32(0x00000000, 0x00000000) == 0x00000000 ? 1 : -1]; +char bextr32_1[__bextr_u32(0x000003F0, 0xFFFF1004) == 0x0000003F ? 1 : -1]; +char bextr32_2[__bextr_u32(0x000003F0, 0xFFFF3008) == 0x00000003 ? 1 : -1]; + +char bextr32_3[_bextr2_u32(0x00000000, 0x00000000) == 0x00000000 ? 1 : -1]; +char bextr32_4[_bextr2_u32(0x000003F0, 0xFFFF1004) == 0x0000003F ? 1 : -1]; +char bextr32_5[_bextr2_u32(0x000003F0, 0xFFFF3008) == 0x00000003 ? 1 : -1]; + +char bextr32_6[_bextr_u32(0x00000000, 0x00000000, 0x00000000) == 0x00000000 ? 1 : -1]; +char bextr32_7[_bextr_u32(0x000003F0, 0xFFFFFF04, 0xFFFFFF10) == 0x0000003F ? 1 : -1]; +char bextr32_8[_bextr_u32(0x000003F0, 0xFFFFFF08, 0xFFFFFF30) == 0x00000003 ? 1 : -1]; + +#ifdef __x86_64__ +char bextr64_0[__bextr_u64(0x0000000000000000ULL, 0x0000000000000000ULL) == 0x0000000000000000ULL ? 1 : -1]; +char bextr64_1[__bextr_u64(0xF000000000000001ULL, 0x0000000000004001ULL) == 0x7800000000000000ULL ? 1 : -1]; +char bextr64_2[__bextr_u64(0xF000000000000001ULL, 0xFFFFFFFFFFFF1001ULL) == 0x0000000000000000ULL ? 1 : -1]; + +char bextr64_3[_bextr2_u64(0x0000000000000000ULL, 0x0000000000000000ULL) == 0x0000000000000000ULL ? 1 : -1]; +char bextr64_4[_bextr2_u64(0xF000000000000001ULL, 0x0000000000004001ULL) == 0x7800000000000000ULL ? 1 : -1]; +char bextr64_5[_bextr2_u64(0xF000000000000001ULL, 0xFFFFFFFFFFFF1001ULL) == 0x0000000000000000ULL ? 1 : -1]; + +char bextr64_6[_bextr_u64(0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL) == 0x0000000000000000ULL ? 1 : -1]; +char bextr64_7[_bextr_u64(0xF000000000000001ULL, 0x0000000000000001ULL, 0x0000000000000040ULL) == 0x7800000000000000ULL ? 1 : -1]; +char bextr64_8[_bextr_u64(0xF000000000000001ULL, 0xFFFFFFFFFFFFFF01ULL, 0xFFFFFFFFFFFFFF10ULL) == 0x0000000000000000ULL ? 1 : -1]; +#endif +#endif \ No newline at end of file diff --git a/clang/test/CodeGen/X86/tbm-builtins.c b/clang/test/CodeGen/X86/tbm-builtins.c index ad4247be9a442c..ef5e1657521f9c 100644 --- a/clang/test/CodeGen/X86/tbm-builtins.c +++ b/clang/test/CodeGen/X86/tbm-builtins.c @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -ffreestanding %s -triple=x86_64-unknown-unknown -target-feature +tbm -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -x c -ffreestanding %s -triple=x86_64-unknown-unknown -target-feature +tbm -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -x c++ -std=c++11 -ffreestanding %s -triple=x86_64-unknown-unknown -target-feature +tbm -emit-llvm -o - | FileCheck %s #include <x86intrin.h> @@ -177,3 +178,16 @@ unsigned long long test__tzmsk_u64(unsigned long long a) { return __tzmsk_u64(a); } #endif + +// Test constexpr handling. +#if defined(__cplusplus) && (__cplusplus >= 201103L) +char bextri32_0[__bextri_u32(0x00000000, 0x00000000) == 0x00000000 ? 1 : -1]; +char bextri32_1[__bextri_u32(0x000003F0, 0xFFFF1004) == 0x0000003F ? 1 : -1]; +char bextri32_2[__bextri_u32(0x000003F0, 0xFFFF3008) == 0x00000003 ? 1 : -1]; + +#ifdef __x86_64__ +char bextri64_0[__bextri_u64(0x0000000000000000ULL, 0x0000000000000000ULL) == 0x0000000000000000ULL ? 1 : -1]; +char bextri64_1[__bextri_u64(0xF000000000000001ULL, 0x0000000000004001ULL) == 0x7800000000000000ULL ? 1 : -1]; +char bextri64_2[__bextri_u64(0xF000000000000001ULL, 0xFFFFFFFFFFFF1001ULL) == 0x0000000000000000ULL ? 1 : -1]; +#endif +#endif _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits