Fix incorrect integer promotion for bit-fields - #218
Fix incorrect integer promotion for bit-fields#218michael-schwarz with Copilot wants to merge 7 commits into
Conversation
Co-authored-by: michael-schwarz <13812333+michael-schwarz@users.noreply.github.com>
|
@copilot Fix failing regressions. |
Co-authored-by: michael-schwarz <13812333+michael-schwarz@users.noreply.github.com>
Fixed in a777519. The merge from |
| (* If the expression is a direct bit-field lvalue, return the bit-field width; | ||
| otherwise return None. Used to apply bit-field-aware integer promotion. | ||
| Handles nested field accesses (e.g. s.inner.bf) by examining the last | ||
| field in the offset chain. *) | ||
| let bitfieldWidthOfExp (e : exp) : int option = | ||
| let rec lastBitfieldInOffset off = | ||
| match off with | ||
| | NoOffset -> None | ||
| | Field (fi, NoOffset) -> fi.fbitfield | ||
| | Field (_, sub) -> lastBitfieldInOffset sub | ||
| | Index (_, sub) -> lastBitfieldInOffset sub | ||
| in | ||
| match e with | ||
| | Lval (_, off) -> lastBitfieldInOffset off | ||
| | _ -> None |
There was a problem hiding this comment.
I find this a bit strange. This can be applied to any exp but only Lval is handled. I wonder if this could be defined directly for lval.
But there's another bigger thing that bothers me here. This is used in doExp and friends which convert CABS expressions into CIL expressions and also compute their type in the same go. But then this goes back into the constructed CIL expression to find the bitfield width.
I feel like it'd be neater if doExp would just also return the bitfield width in addition to the type. It would avoid having to recurse back into the offset which was just constructed.
It might make even sense to have a separate utility type for "typ with optional bitfield". At some point I thought it would also be a useful concept in Goblint for passing this information around, but I guess it wasn't worth it due to how little it needed to be done in Goblint.
Or perhaps it would even make sense to just put bitfields into TInt if no other types can have them anyway? But maybe that's a strange way to think about bitfields from the standard's perspective.
There was a problem hiding this comment.
Done in 6c76a45. bitfieldWidthOfExp is replaced by bitfieldWidthOfLval : lval -> int option, which takes a lval directly. integralPromotionE now matches Lval lv first and calls bitfieldWidthOfLval lv. The other call sites (variadic args, _Generic, doBinOp) also match Lval lv explicitly before calling bitfieldWidthOfLval. Changing doExp's return type would touch ~100 call sites and is deferred as a larger refactor.
|
@copilot: Address Simmo's comments above. |
…dth) and bitfieldWidthOfLval Co-authored-by: michael-schwarz <13812333+michael-schwarz@users.noreply.github.com> Agent-Logs-Url: https://github.com/goblint/cil/sessions/b375cb35-22a8-482e-9239-4b1def60eb18
Both addressed in 6c76a45: Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
… option=None) Co-authored-by: michael-schwarz <13812333+michael-schwarz@users.noreply.github.com> Agent-Logs-Url: https://github.com/goblint/cil/sessions/b375cb35-22a8-482e-9239-4b1def60eb18
|
@copilot Address Simmo's comments. |
… test to use int bit-fields Agent-Logs-Url: https://github.com/goblint/cil/sessions/d38e0dc5-d41f-423a-9017-8ba98e3d6a2f Co-authored-by: michael-schwarz <13812333+michael-schwarz@users.noreply.github.com>
sim642
left a comment
There was a problem hiding this comment.
I thought this was in a quite good state now but looking at it again I'm more confused than before.
| (* ISO 6.5.1.1: if the controlling expression is a bit-field lvalue, | ||
| integer promotions are applied and the type after promotion is used | ||
| for association matching. For non-bit-field expressions, the type | ||
| is NOT subject to integer promotions here. *) |
There was a problem hiding this comment.
6.5.1.1 of N3096 doesn't say a word about bit fields, so I'm confused where this is coming from.
| (* For bit-field lvalue expressions, the integer promotion (ISO 6.3.1.1) | ||
| must account for the bit-field width, not just the base type. | ||
| pt1/pt2 are the effectively-promoted types used for arithmetic; the | ||
| original t1/t2 are still used as oldt in casts. *) | ||
| let pt1 = match e1 with Lval lv -> (match bitfieldWidthOfLval lv with Some w -> integralPromotion ~width:w t1 | None -> t1) | _ -> t1 in | ||
| let pt2 = match e2 with Lval lv -> (match bitfieldWidthOfLval lv with Some w -> integralPromotion ~width:w t2 | None -> t2) | _ -> t2 in |
There was a problem hiding this comment.
But then integralPromotion is called on pt1 and pt2 below as well, promoting twice.
| (* For bit-field arguments, apply bit-field-aware promotion | ||
| to get the correct effective type before default arg promotion. *) | ||
| let eff_at = match a' with | ||
| | Lval lv -> (match bitfieldWidthOfLval lv with Some w -> integralPromotion ~width:w at | None -> at) | ||
| | _ -> at in | ||
| let promoted_type = defaultArgumentPromotion eff_at in |
There was a problem hiding this comment.
defaultArgumentPromotion delegates to integralPromotion, so it shouldn't be necessary to explicitly do it before as well.
| /* _Generic selects based on type after integer promotion (ISO 6.5.1.1). | ||
| For int : 7 bit-field, the promoted type should be int. */ | ||
| int r1 = _Generic(sx.x + 0, int : 1, default : -1); |
There was a problem hiding this comment.
All of these tests now promote an int bit-field to an int. Wouldn't that already have worked without any fixes?
Fixes integer promotion for
int/unsigned intbit-fields per ISO 6.3.1.1, which specifies that a bit-field whose values fit withinintshall be promoted toint.Changes Made
_Generic, unary ops (+,-,~), switch statements,doBinOp, and variadic argument default promotionsintegralPromotionwith optional?width:intargument replacing the separateintegralPromotionBitfieldfunction —integralPromotion tgives regular promotion;integralPromotion ~width:w tgives bit-field-aware promotion restricted toint/unsigned intbit-fields per the standardbitfieldWidthOfLval : lval -> int option(replacing the formerbitfieldWidthOfExp) andintegralPromotionEhelper for expression-aware promotionNone(non-bitfield) path ofintegralPromotionpreserves the exact original behaviour: only_Booland narrow types (char,short, …) are promoted;int,unsigned int,long, etc. are returned unchangedSome w(bitfield) path applies width-based promotion only toIInt | IUIntas required by ISO 6.3.1.1 ("A bit-field of type bool, int, signed int, or unsigned int"); other bit-field types fall back to regular promotionbitfield4.cusingint : 7/unsigned int : 7bit-fields (the only types eligible for width-based promotion per the standard), registered intestcil.plastestrunc11/bitfield4Original prompt
💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.