Windows integral promotions / uint64_t

Kim Barrett kim.barrett at oracle.com
Thu Apr 28 16:14:48 UTC 2022


> On Apr 28, 2022, at 8:53 AM, Andrew Haley <aph-open at littlepinkcloud.com> wrote:
> 
> I'm seeing this failure from the Windows/AArch64 C++ compiler:
> 
> * For target hotspot_variant-server_libjvm_objs_stubGenerator_aarch64.obj:
> stubGenerator_aarch64.cpp
> d:\a\jdk\jdk\jdk\src\hotspot\cpu\aarch64\stubGenerator_aarch64.cpp(6524): error C2668: 'MacroAssembler::sub': ambiguous call to overloaded function
> d:\a\jdk\jdk\jdk\src\hotspot\cpu\aarch64\macroAssembler_aarch64.hpp(1174): note: could be 'void MacroAssembler::sub(Register,Register,Register)'
> d:\a\jdk\jdk\jdk\src\hotspot\cpu\aarch64\macroAssembler_aarch64.hpp(1174): note: or       'void MacroAssembler::sub(Register,Register,uint64_t)'
> d:\a\jdk\jdk\jdk\src\hotspot\cpu\aarch64\stubGenerator_aarch64.cpp(6524): note: while trying to match the argument list '(const Register, const Register, unsigned int)'
>   ... (rest of output omitted)
> 
> 6524:   __ sub(sp, rfp, ((unsigned)framesize-4) << LogBytesPerInt); // prolog
> 
> 
> Is this a known bug in the compiler? It seems to me as though there is
> an implicit integral promotion from unsigned int to uint64_t, but there is no
> implicit conversion from unsigned int to Register (which is of pointer-
> to const RegisterImpl type). Therefore, according to the ranking of
> implicit conversion sequences rule, this should work.
> 
> Or is the problem that, according to the Windows compiler, there is no
> implicit integral promotion from unsigned int to uint64_t? I guess that's
> possible if there is no standard type which corresponds to uint64_t, but
> surely that's unsigned long long. Isn't it?
> 
> If this is the case, we could use some template magic to define conversions
> from the standard types to Xint64_t, and include them in the Windows build.
> That would reduce the pain.

I think what may be happening here is that the third argument to sub is a constant expression
whose value is 0, so is ambiguously either an integral 0 or a null pointer.  C++14 says
only a literal 0 is supposed to be implicitly convertible to a pointer [1], but C++11 and earlier
allow any constexpr 0 to implicitly convert [2].  And I noticed a while ago that gcc seems to
have retained the old behavior even in C++14 mode (at least sometimes?).  Maybe Visual
Studio is doing the same?  But then, why aren’t we seeing similar problems with gcc?

[1] C++14 4.10/1 A null pointer constant is an integer literal (2.14.2) with value zero …
[2] C++11 4.10/1 A null pointer constant is an integral constant expression (5.19) prvalue of integer type that evaluates to zero…

A way to deal with this kind of thing is to use templates to inhibit conversions and use SFINAE
to select and forward to type-specific helpers.  So something like

template<typename ThirdArgType, ENABLE_IF(std::is_integral<ThirdArgType>::value)>
void sub(Register arg0, Register arg1, ThirdArgType arg2) { sub_integral_third_arg(arg0, arg1, arg2); }

template<typename ThirdArgType, ENABLE_IF(std::is_pointer<ThirdArgType>::value)>
void sub(Register arg0, Register arg1, ThirdArgType arg2) { sub_ponter_third_arg(arg0, arg1, arg2); }

This is obviously pretty ugly, and not something I would really recommend here.

Once again the hacky way  Register is defined is biting us.



More information about the hotspot-dev mailing list