In: #include <utility> int f1(long long v) { return std::in_range<int>(v) ? v : 0; } int f2(long long v) { return v == int(v) ? v : 0; } GCC generates for the std::in_range version: movl $2147483648, %edx movl $4294967295, %ecx movq %rdi, %rax addq %rdi, %rdx cmpq %rdx, %rcx movl $0, %edx cmovb %rdx, %rax Whereas for the second function, which operates identically, it generates a sign-extension from the 32-bit component: movslq %edi, %rax cmpq %rdi, %rax movl $0, %eax cmove %edi, %eax Clang generates that second for both functions (using the libstdc++ content). https://gcc.godbolt.org/z/nqfMKejoe
The libstdc++ std::in_range does: template<typename _Res, typename _Tp> constexpr bool in_range(_Tp __t) noexcept { static_assert(__is_standard_integer<_Res>::value); static_assert(__is_standard_integer<_Tp>::value); using __gnu_cxx::__int_traits; if constexpr (is_signed_v<_Tp> == is_signed_v<_Res>) return __int_traits<_Res>::__min <= __t && __t <= __int_traits<_Res>::__max; else if constexpr (is_signed_v<_Tp>) return __t >= 0 && make_unsigned_t<_Tp>(__t) <= __int_traits<_Res>::__max; else return __t <= make_unsigned_t<_Res>(__int_traits<_Res>::__max); } In C++17 the result of int(v) was impl-defined, but since C++20 it's well-defined, and std::in_range was only added in C++20. So we could change the first branch to just return __t == _Ret(__t).
``` int f0(long long v) { unsigned long long t = v; t += 0x80'00'00'00ull; if (t <= 0xff'ff'ff'ff) return v; return 0; } ```
(In reply to Andrew Pinski from comment #2) > ``` > int f0(long long v) > { > unsigned long long t = v; > t += 0x80'00'00'00ull; > if (t <= 0xff'ff'ff'ff) > return v; > return 0; > } > ``` So something like: ``` (simplify (le (plus @0 INTEGER_CST@2) INTEGER_CST@3)) (if (exact_log2 (@2) != -1 && @3 == mask(exact_log2 (@2)+1)) (with { tree otype = TREE_TYPE (@0); tree inner_type = signed_int_type (exact_log2 (@2)+1); } (eq (convert:otype (convert:itype @0)) @0)) ``` ISo mine.
.