Skip to content

Fix compile-time concatenation with negative right operand #5233

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

Merged
merged 4 commits into from
Apr 17, 2025

Conversation

vlstill
Copy link
Contributor

@vlstill vlstill commented Apr 11, 2025

Fixes #5231. The problem is most likely in the binary representation of the big_int for negative numbers. The solution is to always convert the right operand to a unsigned value with the same representation as does the signed value have.

@vlstill vlstill changed the title Fix compile-time concatenation with negative left operand Fix compile-time concatenation with negative right operand Apr 11, 2025
@fruffy fruffy added the core Topics concerning the core segments of the compiler (frontend, midend, parser) label Apr 11, 2025
@jafingerhut
Copy link
Contributor

The test P4 program and its expected output looks correct to me.

@vlstill vlstill marked this pull request as ready for review April 11, 2025 17:32
@vlstill vlstill requested a review from fruffy April 11, 2025 17:33
if (rt->isSigned) {
rt = IR::Type_Bits::get(rt->size);
right = new IR::Constant(rt, right->value, 10, true /* no warning */);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

There's no need to create a new IR::Constant here that you're going to throw away -- just take the big_int value and fix it if it is negative:

big_int rvalue = right->value;
if (rvalue < 0)
    rvalue &= Util::mask(rt->size);

and then use rvalue later instead of right->value

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I do not like the idea of spreading a conversion function from 2-complement signed to 2-complement unsigned over multiple places in the codebase. It is already in the Constant::handleOverflow (invoked from the ctor) and it is not really possible to extract it from there because of the warnings which use the constant value in the logs.

I've changed the code to avoid the unnecessary dynamic allocation at least.

Copy link
Contributor

Choose a reason for hiding this comment

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

IMO this is more obscure than just doing the mask with the big_int value. boost::mulitprecision specifies that bitwise operations on negative value happen as-if the values are 2s complement (regardless of what the actual underlying representation is), so that does what we want for concatenation according to the P4 spec.

vlstill added 3 commits April 14, 2025 15:24
Signed-off-by: Vladimír Štill <[email protected]>
Signed-off-by: Vladimír Štill <[email protected]>
@vlstill vlstill self-assigned this Apr 15, 2025
... because size is not correct for Extracted_Varbits

Signed-off-by: Vladimír Štill <[email protected]>
@vlstill vlstill requested a review from ChrisDodd April 15, 2025 12:28
@vlstill vlstill added this pull request to the merge queue Apr 17, 2025
Merged via the queue into p4lang:main with commit 7b49eb1 Apr 17, 2025
20 checks passed
@vlstill vlstill deleted the fix-ing-concat branch April 17, 2025 07:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core Topics concerning the core segments of the compiler (frontend, midend, parser)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Compile-time concatenation of negative constants is wrong
4 participants