bytestring icon indicating copy to clipboard operation
bytestring copied to clipboard

storableToF should use target instead of host arch?

Open AndreasPK opened this issue 2 years ago • 5 comments

Currently we have:

{-# INLINE CONLIKE storableToF #-}
storableToF :: forall a. Storable a => FixedPrim a
-- Not all architectures are forgiving of unaligned accesses; whitelist ones
-- which are known not to trap (either to the kernel for emulation, or crash).
#if defined(i386_HOST_ARCH) || defined(x86_64_HOST_ARCH) \
    || ((defined(arm_HOST_ARCH) || defined(aarch64_HOST_ARCH)) \
        && defined(__ARM_FEATURE_UNALIGNED)) \
    || defined(powerpc_HOST_ARCH) || defined(powerpc64_HOST_ARCH) \
    || defined(powerpc64le_HOST_ARCH)
storableToF = FP (sizeOf (undefined :: a)) (\x op -> poke (castPtr op) x)
#else
storableToF = FP (sizeOf (undefined :: a)) $ \x op ->
    if ptrToWordPtr op `mod` fromIntegral (alignment (undefined :: a)) == 0 then poke (castPtr op) x
    else with x $ \tp -> copyBytes op (castPtr tp) (sizeOf (undefined :: a))
#endif

Isn't this broken during cross compilation? E.g. if I compile on powerpc_HOST_ARCH targeting a platform that doesn't support unaligned access wouldn't this fall over?

I'm not an expert on cross compilation but seemed wrong to me.

AndreasPK avatar Jul 14 '22 14:07 AndreasPK

You're probably correct, @AndreasPK. Do you have a suggestion how to fix this? Are there corresponding x_TARGET_ARCH pragmas that we could make use of?

sjakobi avatar Jul 14 '22 15:07 sjakobi

I think x_HOST_ARCH is the correct thing to check. The host arch for a given build is the machine the compiled code will be run on. If I understand correctly, the idea of a target arch doesn't even make sense in the context of bytestring as it's not a compiler.

But this is definitely a confusing topic. Ideally these functions should be tested in a cross-compiled build.

clyring avatar Jul 14 '22 17:07 clyring

I think x_HOST_ARCH is the correct thing to check. The host arch for a given build is the machine the compiled code will be run on. If I understand correctly, the idea of a target arch doesn't even make sense in the context of bytestring as it's not a compiler.

If you are reasonably sure of this feel free to close this ticket. It seemed wrong to me but it might be fine for all I know. I really don't know enough about cross compilation to say for sure.

AndreasPK avatar Jul 14 '22 17:07 AndreasPK

I think x_HOST_ARCH is the correct thing to check. The host arch for a given build is the machine the compiled code will be run on. If I understand correctly, the idea of a target arch doesn't even make sense in the context of bytestring as it's not a compiler.

But this is definitely a confusing topic. Ideally these functions should be tested in a cross-compiled build.

I'm afraid we can't just outright discount bytestring as not being a compiler. It is certainly part of GHC, and as such part of any cross compiling ghc.

Now, which one is active? Let's take an aarch64 cross compiler, and compile the following Main.hs

{-# language CPP #-}

main = do
#if defined(aarch64_HOST_ARCH)
  putStrLn "aarch64_HOST_ARCH"
#endif
#if defined(aarch64_TARGET_ARCH)
  putStrLn "aarch64_TARGET_ARCH)
#endif
  return ()
$ aarch64-unknown-linux-gnu-ghc Main.hs
$ qemu-aarch64 Main
aarch64_HOST_ARCH

As such we can see that _HOST_ARCH is active, as that's where the final library/executable will be hosted. However, we should be aware that there are cases, where libraries are part of cross compilers and _TARGET_ARCH might also be defined.

--

If you wonder how to get such a cross compiler for experimental purposes:

  • clone https://github.com/angerman/ghc-repro-21767
  • run nix develop .#packages.x86_64-linux."aarch64-linux:exe:repro@8107" you sould have the aarch64-unknown-linux-gnu-ghc in path, qemu won't be in path but at /nix/store/salf5mh7mr22p5s7vxl62kzbw8b9dpiy-qemu-6.2.0/bin/qemu-aarch64; due to being a dependency of the iserv cross compilation setup. To get most of this from caches, you want
substituters = https://cache.zw3rk.com/
trusted-public-keys = loony-tools:pr9m4BkM/5/eSTZlkQyRt57Jz7OMBxNSUiMC4FkcNfk=

angerman avatar Jul 15 '22 09:07 angerman

I'm afraid we can't just outright discount bytestring as not being a compiler. It is certainly part of GHC, and as such part of any cross compiling ghc.

GHC depends on bytestring, so that any ghc is linked with some build of bytestring, with bytestring_HOST = ghc_HOST. But each GHC build corresponds to at least two different bytestring builds, so there isn't a one-to-one correspondence to be found here. In particular, the GHC build process also builds a variant of bytestring with bytestring_HOST = ghc_BUILD for linking with the stage1-ghc that produces the final compiler, and in the cross-compilation case I wouldn't be surprised if there is a third bytestring variant with bytestring_HOST = ghc_TARGET for linking with the executables produced by that cross-compiling ghc.

So, are all three of these bytestring variants "certainly part of" GHC? And for which of them is the notion of "target arch" applicable and relevant? I think the best answer to both questions is "none of them."

clyring avatar Jul 15 '22 20:07 clyring