-
-
Notifications
You must be signed in to change notification settings - Fork 71
Removed operations about aliased types #312
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
base: main
Are you sure you want to change the base?
Removed operations about aliased types #312
Conversation
…thers ('l' long to int, etc.)
|
To elaborate a bit: |
|
Other considerations about va_arg-extraction. Line 289 in 7349b4f
is used here: Line 851 in 7349b4f
However, can't we just extract the parameter as size_t, rather than ssize_t? The two types are guaranteed to be the same width, and we assigned the value to npf_int_t val anyway, without even a cast (I mean no cast to npf_int_t). Is it actually UB to access a value with va_arg using the wrong signedness?The C23 standard says (§7.16.1.1): So, though signed and unsigned are incompatible (that's from other parts of the standard), va_arg has a specific exception for it; but only if the value is representable in both types (which mostly means that the sign bit is 0, and which might or might not be less of a problem now that 2's complement is the only acceptable representation for signed integers, though this is recent -- maybe C23 and C++14). In the current PR, however, the signedness is not affected. Only the actual type is "aliased" (but the size is correct). However, those types are not strictly "compatible". Other libraries seem to incur in this UB without (?) problems: |
|
This is very interesting; I'm surprised arm-gcc can't figure this out on its own since the underlying types are identical. Or, maybe it does? Looking at your metrics: your "before" and your "after" Ignoring the strange npf_utoa_rev thing, which I don't understand yet, and directly comparing Before: 0x20 (npf_vpprintf.cold) + 0x21b0 (npf_vpprintf) = 0x21d0 At least from this data, it looks like this change increases the footprint by 0x30 bytes? |
|
I don't know whether the compiler can be that clever, since the simplifications I'm doing are (as I understand it) technically UB. Also, my numbers were taken with -O3 rather than -Os, something I noticed only afterwards. |
|
What is your feeling about this potential added UB? Also, do you understand the same as I do, or do you think it's actually legal to alias types that way? |
This optimizes argument fetching/writing for redundant 'h' and 'l/ll/j/z/t'.
When sizeof(short) == sizeof(int), we can have the enum value NPF_FMT_SPEC_LEN_MOD_SHORT be an alias for NPF_FMT_SPEC_LEN_MOD_NONE.
Similarly for the long ones (aliased to NONE or LONG).
We can then conditionally remove some of the NPF_EXTRACT and NPF_WRITEBACK cases.
This is done in this PR.
We can also remove LONG if it aliases NONE, with some caveats.
'l' is needed for %c/%s, and especially for the floats. But in both cases they are the same as NONE -- that's because we don't support them, for %c and %s; and because the standard says so, for floats. So, for all specifiers, LONG can correctly alias NONE.
This is also done in this PR.
If
%lcand%lswill ever be supported, this will need revisiting.Since 'hh' is the size of char, and from what I understand (short) must be at least 2*sizeof(char), 'hh' can't possibly alias any other of the types involved here.
This also addresses the loosely related #311.
What size changes do you see on your reports, for this branch?
Running
nmlocally, I get this strange-looking results:Without type removal (before):
With type removal (after):
The size of
npf_utoa_revbefore is particularly strange; that's a very simple function.Also mind that I've changed the order of the
NPF_FMT_SPEC_LEN_MOD_* enums. I don't think this should have any impact at all