[llvm-dev] libcalls vs. size of int

Björn Pettersson A via llvm-dev llvm-dev at lists.llvm.org
Sun Mar 28 15:04:06 PDT 2021


A quick inventory of the "libgcc" runtimes in compiler-rt shows
a number of functions that use "int" in the ABI.

Libcalls may be emitted for these (SHL_I64, SRL_I64, SRA_I64):
  ashldi3.c:COMPILER_RT_ABI di_int __ashldi3(di_int a, int b)
  ashrdi3.c:COMPILER_RT_ABI di_int __ashrdi3(di_int a, int b)
  lshrdi3.c:COMPILER_RT_ABI di_int __lshrdi3(di_int a, int b)

Libcalls may be emitted for these (SINTTOFP_I32_F32, SINTTOFP_I32_F128, SUNTTOFP_I32_F32, UINTTOFP_I32_F128):
  floatsisf.c:COMPILER_RT_ABI fp_t __floatsisf(int a)
  floatsitf.c:COMPILER_RT_ABI fp_t __floatsitf(int a)
  floatunsisf.c:COMPILER_RT_ABI fp_t __floatunsisf(unsigned int a)
  floatunsitf.c:COMPILER_RT_ABI fp_t __floatunsitf(unsigned int a)

Libcall is emitted via llvm.powi intrinsic (FPOWI/STRICT_FPOWI ISD nodes):
  powidf2.c:COMPILER_RT_ABI double __powidf2(double a, int b)
  powisf2.c:COMPILER_RT_ABI float __powisf2(float a, int b)
  powitf2.c:COMPILER_RT_ABI long double __powitf2(long double a, int b)
  powixf2.c:COMPILER_RT_ABI long double __powixf2(long double a, int b)

No libcalls generated to these functions afaict:
  ctzdi2.c:COMPILER_RT_ABI int __ctzdi2(di_int a)
  ctzsi2.c:COMPILER_RT_ABI int __ctzsi2(si_int a)
  ctzti2.c:COMPILER_RT_ABI int __ctzti2(ti_int a)
  ffsdi2.c:COMPILER_RT_ABI int __ffsdi2(di_int a)
  ffssi2.c:COMPILER_RT_ABI int __ffssi2(si_int a)
  ffsti2.c:COMPILER_RT_ABI int __ffsti2(ti_int a)
  paritydi2.c:COMPILER_RT_ABI int __paritydi2(di_int a)
  paritysi2.c:COMPILER_RT_ABI int __paritysi2(si_int a)
  parityti2.c:COMPILER_RT_ABI int __parityti2(ti_int a)
  popcountdi2.c:COMPILER_RT_ABI int __popcountdi2(di_int a)
  popcountsi2.c:COMPILER_RT_ABI int __popcountsi2(si_int a)
  popcountti2.c:COMPILER_RT_ABI int __popcountti2(ti_int a)


The 64-bit shift and float conversion libcalls can be avoided by backends by
using setLibcallName(Op, nullptr). I haven't checked exactly what happens and
how ISel is handling "size of int" for those, but I could not find any signs
indicating that ISel is doing anything special to ensure that the correct
"size of int" is used. So I suspect it isn't handled correctly.

For the powi family I think it is more interesting to emit libcalls even
for targets with 16-bit int. This is because the llvm.powi intrinsic is used
as a mapping to the libcall, and middle-end is doing optimizations for
llvm.powi. I've created a patch here https://reviews.llvm.org/D99439 that
solve problems around powi by changing the llvm.powi intrisic to overload
the type of the exponent argument. And making sure that any in-tree
introduction of llvm.powi uses the correct type.


I've also made another patch, as a starting point, to let SimplifyLibCalls
handle size of int better. That patch is needed as a pre-requisite for the
powi fix to let SimplifyLibCalls use the correct types when emitting calls
to llvm.powi. The patch can be found here https://reviews.llvm.org/D99438 ,
and it also fixes problems with size of int for the rewrites that emit
libcalls to ldexp/ldexpf.

I've used AVR and MSP430 in the test cases added for those patches as
those two targets are using 16-bit int types afaict.

Any reviewers for those patches (D99438 & D99439) are welcome.

/Björn



> -----Original Message-----
> From: Anatoly Trosinenko <atrosinenko at accesssoftek.com>
> Sent: den 24 mars 2021 15:20
> To: Björn Pettersson A <bjorn.a.pettersson at ericsson.com>
> Subject: Re: [llvm-dev] libcalls vs. size of int
> 
> Hi!
> 
> > I guess one solution here is to find all the builtins in compiler-rt that
> isn't using machine mode types and put them in a list of functions that
> depend on size of int/long etc. Then make sure we make those unavailable
> for targets with int!=si_int etc (and then one has to implement an
> replacement if those functions are needed).
> 
> > Another solution could be to break compatibility with libgcc and use the
> machine mode types everywhere (or is there a requirement that builtins are
> compatible between libclang_rt and libgcc?).
> 
> I do not have some definitive solution right now, but the third option
> could probably be implementing several compiler-rt functions such as
> __powsidf2 (normally aliased with __powidf2) and __powhidf2 (aliased with
> __powidf2 on 16-bit targets). This makes possible to only emit calls to
> machine mode-sized helper functions from `llc`. At the same time one will
> not end up having two functions with the same name in libgcc and compiler-
> rt and subtle differences in behavior.
> 
> Since there are no such functions in libgcc, llc would have to emit
> different names when using compiler-rt and libgcc. Unfortunately, it seems
> the knowledge whether we are targeting libgcc or compiler-rt as a support
> library is lost at the time of codegen. As a workaround, llc could emit
> calls to the aforementioned overloaded functions only if `sizeof(void*) <
> 32` (this should be easily accessible via DataLayout). This may be
> considered as a limited/explicit "breaking compatibility with libgcc" but
> looks rather hackish.

Yes, this could be something we could do out-of-tree (at least) as a
hacky workaround. But when I noticed that things like __builtin_powi also
were broken (clang crashing when mapping the builtin to @llvm.powi) I
ended up proposing another solution based on using the correct type,
representing the size of int, when using llvm.powi.

> 
> Anatoly


More information about the llvm-dev mailing list