Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

struct Rav1dTaskContext::scratch: Make into zerocopy-based "unions" #969

Merged
merged 2 commits into from
Apr 25, 2024

Conversation

randomPoison
Copy link
Collaborator

@randomPoison randomPoison commented Apr 12, 2024

Makes the various scratch unions into safe "union"s by using zerocopy.

@randomPoison randomPoison force-pushed the legare/scratch-enum branch 2 times, most recently from 4503763 to 92627e7 Compare April 15, 2024 20:47
Copy link
Collaborator

@kkysen kkysen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of overarching points:

  • Do we need to lazy initialize things? Can we just initialize them where we need to?
  • I'm still thinking about this, but these initializations as a different variant are quite expensive given the size of these structs and arrays (up to 250 KB). It might be better to do a zerocopy cast to different variants instead. In essence, a safe union where the variants are safely transmutable to each other. Then the backing scratch buffer becomes just a [u8; N] aligned to whatever alignment we need.

.github/workflows/build-and-test-aarch64-darwin.yml Outdated Show resolved Hide resolved
src/internal.rs Outdated Show resolved Hide resolved
src/internal.rs Show resolved Hide resolved
src/internal.rs Show resolved Hide resolved
src/internal.rs Outdated Show resolved Hide resolved
src/recon.rs Outdated Show resolved Hide resolved
src/recon.rs Outdated Show resolved Hide resolved
@randomPoison randomPoison force-pushed the legare/scratch-enum branch 2 times, most recently from 1b32838 to a4a26fa Compare April 22, 2024 22:44
@randomPoison
Copy link
Collaborator Author

@kkysen I've reworked this to use zerocopy to make the scratch data into safe "unions", with most of the structs containing appropriately-sized byte buffers that are then cast to the needed data type using FromBytes::mut_from_prefix. I ended up not needing to impl any of the zerocopy traits for BitDepthUnion or AlignN, which is for the best because I suspect those would have been a source of UB. Please give it another review when you have a chance.

@kkysen kkysen self-requested a review April 23, 2024 00:19
@randomPoison randomPoison force-pushed the legare/scratch-enum branch 2 times, most recently from 6855a15 to e02d0cb Compare April 23, 2024 21:41
Copy link
Collaborator

@kkysen kkysen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally looks really good now. I just had a few comments.

src/internal.rs Show resolved Hide resolved
src/internal.rs Outdated Show resolved Hide resolved
src/internal.rs Outdated Show resolved Hide resolved
src/internal.rs Show resolved Hide resolved
src/internal.rs Outdated
pub struct InterIntraEdgePal;
#[derive(Clone, Copy, FromZeroes, FromBytes, AsBytes)]
#[repr(C, align(32))]
pub struct ScratchEdgeBuf([u8; 257 * 2 + 30]); // 257 Pixel elements + 30 padding bytes
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to return the 30 padding bytes? Provenance-wise, I think that's safer.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean by "return the 30 padding bytes"? Return the full size of the buffer, including padding, from buf_mut? I don't think doing that would be a good idea, the buffer had a specific length for a reason and we shouldn't be changing the size of it. There's also code using this data that assumes a length of 257.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we start with a [u8; 257 * 2 + 30]. Say we then return a &[u16; 257] for bpc16, and then asm accesses 30 bytes after that. That violates stacked borrows since it expands provenance. So to do things correctly with no UB, we need to keep that 30 bytes there the whole time. Is it worth it? I'm not sure, but it technically is UB.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that the original code was written to be a buffer of 257 elements without any padding at the end, I think it's reasonably safe to assume that the asm won't read beyond that. If it is, the behavior isn't going to be any different than it was in the original C.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that the original code was written to be a buffer of 257 elements without any padding at the end, I think it's reasonably safe to assume that the asm won't read beyond that

I'm pretty sure the padding is there since asm is using SIMD instructions that over-read.

If it is, the behavior isn't going to be any different than it was in the original C.

C has different UB rules than Rust, and doing it in Rust with all raw pointers is also different than creating that intermediate slice.

src/internal.rs Outdated Show resolved Hide resolved
src/internal.rs Outdated Show resolved Hide resolved
src/internal.rs Outdated Show resolved Hide resolved
src/internal.rs Outdated Show resolved Hide resolved
src/internal.rs Show resolved Hide resolved
@kkysen kkysen changed the title Rav1dTaskContext::scratch: Make into enums struct Rav1dTaskContext::scratch: Make into zerocopy-based "enums" Apr 24, 2024
@kkysen kkysen changed the title struct Rav1dTaskContext::scratch: Make into zerocopy-based "enums" struct Rav1dTaskContext::scratch: Make into zerocopy-based "unions" Apr 24, 2024
Copy link
Collaborator

@kkysen kkysen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think that 30 padding bytes is technically UB, but it's okay to merge. I think we should take a further look at it at some point.

@randomPoison randomPoison merged commit ad45607 into main Apr 25, 2024
21 checks passed
@randomPoison randomPoison deleted the legare/scratch-enum branch April 25, 2024 16:40
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.

2 participants