[RFC][LLC] Add ExpandLargeIntFpConvert pass for fp-int-conversion of large _BitInt

Hi All,

With landing of ⚙ D130076 [llvm/CodeGen] Enable the ExpandLargeDivRem pass for X86, Arm and AArch64, large _BitInt divisions/remainders now has worked from end to end for x86, ARM, AARCH targets. Thanks @mgehre-amd for his great work to enable this feature! i.e.

_BitInt(129) square(_BitInt(129) a, _BitInt(129) b) {
    return a/b;
}

However, it still relies on additional flags(-Xclang -fexperimental-max-bitint-width=200) to use thie feature. While _BitInt() was originally designed to uplift the supported integer width up to 1<<23.(FIXME now existed in clang FE: llvm-project/TargetInfo.h at 2dfe7a34297ad28d6d54964a1c98d96ab7f5f69d · llvm/llvm-project · GitHub) The reason we still can not now loose the limit at front end is that we still has one issue left on backend to make large _BitInt() work at all circumstances, which is large _Bitint() conversion from/to floating type:

void foo() {
  _BitInt(256) i = 12;
  float f = i;
}

void boo() {
  float f = 3.14;
  _BitInt(256) i = f;
}

Codes above still crashes at the backend. The crash is basically due to the same reason as large div/rem before, which is for now, libgcc/compiler-rt only has runtime libraries up to i128 to support these special conversions. (i.e. compiler-rt/lib/builtins/float/fix(un)s[d,t]is[d,x,t]f.c) To resolve this issue, we’ll occur some similar problems when we support large _BitInt() Div/Rem before: It won’t be easy to get new large _BitInt()-float-conversion runtime libraries added to libgcc due to the fact that gcc doesn’t have _BitInt support yet.

So I think we should follow the similar way of ⚙ D126644 [llvm/CodeGen] Add ExpandLargeDivRem pass to resolve this issue. The difference is we have no existed llvm/util/ functions to call for fp-int conversion this time. However, we have existed algorithm frameworks in compiler-rt/libgcc’s buitlins to refer to. I did a try to compile the libraries in compiler-rt to LLVM IR and found there are 6-7 Basic Blocks for these conversion algorithm. So not much complexity increased comparing to ExpandLargeDivRem pass.

For fp special issues: rounding, poison values, exceptions… I think we can align with the same ways of how runtime libraries deal with. For example, fptosi rounds to zero, sitofp rounds to nearest int, no NaN assuming, no exception handling, and so on.

We originally wanted to add runtime libraries to resolve the largeDivRem issue ([RFC] Add support for division of large _BitInt (builtins, SelectionDAG/GlobalISel, clang)). While finally we arrived nowadays adding a new default pass to implement in IR. So I opened this RFC before we begin the support of large BitInt fp conversion.

To @mgehre-amd, I can create related patches this time if you don’t have much time recently. And thanks to your effort before, I believe it will save large amounts of efforts to add the new pass this time. With this issue resolved, we can loose the limit at front end and claim that clang now supports the complete feature of _BitInt() @erichkeane @AaronBallman .

Welcome comments! Especially if this way looks good and if there are potential fp issues we need to pay attention. Really appreciate.

Thanks,
Freddy

1 Like

Thank you for offering to work on this (and big thanks to @mgehre-amd for the division support)! This sounds like a reasonable approach to me, though this isn’t my area of expertise. At the very least, I 100% agree with the goal!

Uploaded the WIP patch: ⚙ D137241 [WIP] Add ExpandLargeFpConvert Pass
I was occupied by other urgent affairs last few weeks. Now I have time back to this work. I’ll try to finish the patch ASAP in next few days.