Skip to content

Fix signed fill arguments at the C FFI boundary - #445

Open
felixonmars wants to merge 2 commits into
haskell:masterfrom
felixonmars:riscv64-sign-fix
Open

Fix signed fill arguments at the C FFI boundary#445
felixonmars wants to merge 2 commits into
haskell:masterfrom
felixonmars:riscv64-sign-fix

Conversation

@felixonmars

Copy link
Copy Markdown
Contributor

The setInt8/16/32Array# and setInt8/16/32OffAddr# imports pass signed values to C helpers that expect unsigned arguments. On RISC-V, the calling convention requires different extension for signed and unsigned 16-bit values. Filling four Int16 elements with -2 can therefore produce [-2,-1,-1,-1].

For GHC 9.2 and newer, convert the narrow signed values to their unsigned equivalents and call the existing unsigned imports through inline wrappers. This preserves the element bits while matching the C argument types.

This fixes 13 failures in the existing test suite on riscv64: Int16 filling, replicatePrimArray, and ByteArray Set Range for Int16 and its newtype wrappers.

The setInt8/16/32Array# and setInt8/16/32OffAddr# imports pass signed
values to C helpers that expect unsigned arguments. On RISC-V, the
calling convention requires different extension for signed and unsigned
16-bit values. Filling four Int16 elements with -2 can therefore produce
[-2,-1,-1,-1].

For GHC 9.2 and newer, convert the narrow signed values to their unsigned
equivalents and call the existing unsigned imports through inline
wrappers. This preserves the element bits while matching the C argument
types.

This fixes 13 failures in the existing test suite on riscv64: Int16
filling, replicatePrimArray, and ByteArray Set Range for Int16 and its
newtype wrappers.
@konsumlamm

Copy link
Copy Markdown
Contributor

What about GHC < 9.2? Is the bug not present there?

Add C compatibility helpers that accept machine-word arguments and narrow them to the element type inside C. Route older unsigned imports through these helpers and convert signed values with int2Word# for both array and pointer fills.

Validated with the existing test suite on x86_64 using GHC 9.0.2 and 9.6.6. No GHC older than 9.2 is available for riscv64, so the older compiler branch was tested on x86_64. The compatibility helpers also passed a separate C-level RISC-V ABI check under QEMU.
@felixonmars

Copy link
Copy Markdown
Contributor Author

What about GHC < 9.2? Is the bug not present there?

I don't really have the environment to test because GHC < 9.2 isn't very usable on riscv64. I just added a commit for that branch as well so you can decide whether it's worth it :)

@andrewthad

Copy link
Copy Markdown
Contributor

Nice fix. The previous approach was already on shaky footing to begin with since it used the FFI to wrap a C function with the wrong type (implicitly casting Int16# to Word16# for example). The popular ABIs for x86 and ARM include calling conventions that allow you to put garbage in the upper bits of sub-machine-sized word types when you pass them to functions, so this always just kind of worked out before.

The only thing that I'm not sure of is whether or not this library should still be supporting GHCs earlier than 9.2. It would be nice to just drop all of the shims. I've opened #446 for a discussion on this. Before merging this, I'd like to see if it's possible to quickly gather consensus about dropping support for old GHCs (in the linked issue). If it seems like it will take more time to figure that out, I'll merge this as is. But if there is strong consensus that old GHCs are not worth the effort, we should drop the compatibility paths from this before merging.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants