This change introduces a GC parseable lowering for element atomic memcpy/memmove intrinsics. This way runtime can provide an implementation which can take a safepoint during copy operation. See "GC-parseable element atomic memcpy/memmove" thread on llvm-dev for the background and details:
https://groups.google.com/g/llvm-dev/c/NnENHzmX-b8/m/3PyN8Y2pCAAJ
This lowering involves three things:
- The call is wrapped into a statepoint.
- The call is lowered to a different symbol __llvm_{memcpy|memmove}_element_unordered_atomic_safepoint_<element_size>.
- The arguments for the call are adjusted so as to make the base pointers available in the copy function.
In order to be consistent with other calls by default element atomic memcpy/memmove intrinsics are treated as non-leaf. So, by default GC parseable lowering is generated. Old GC leaf lowering will be generated if the call is explicitly marked "gc-leaf-function" attribute.
This default choice though introduces a minor transitioning issue. In some systems, e.g. ours, GC safepoints are coupled with deoptimization mechanism (this is controlled by a cl::opt rs4gc-allow-statepoint-with-no-deopt-info). In this case we can't have a statepoint without deopt information. Normally it's up to the frontend to make sure that non-leaf calls also have proper deopt state. But element atomic memcpy/memmove intrinsic calls might be generated by the optimizer, which is not aware of this coupling. If statepoints without deopt into are not allowed and we see a non-leaf memcpy/memmove without deopt state we treat it as a leaf copy and don't produce a statepoint.
See see?