Under FMA contraction, an item that shrinks exactly to its min-width is laid out at its flex basis

Aperta
#2,076 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
4/5
Tempo stimato
3-5 giorni
Idoneità per principianti
58/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
cpp
Ambito
frontend

Direzione di ricerca

Read yoga/algorithm/CalculateLayout.cpp, especially distributeFreeSpaceFirstPass and distributeFreeSpaceSecondPass, using the reproducer linked in the issue to follow the min-width boundary case. Compare the layout with floating-point contraction enabled and disabled; done means the item lays out at width 10 in both cases. Check the related issue #2038 for context on residual free space.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

Report

Issues and Steps to Reproduce

A row 20 wide holds an item with flexBasis: 90, flexShrink: 1 and minWidth: 10, and a sibling 10 wide that does not shrink, so the item absorbs the line's 80 of overflow and lands exactly on its minWidth. Built with floating-point contraction, which clang applies by default (-ffp-contract=on) wherever the target has FMA, Yoga lays the item out at its flex basis:

YGNodeRef row = YGNodeNew();
YGNodeStyleSetFlexDirection(row, YGFlexDirectionRow);
YGNodeStyleSetWidth(row, 20);
YGNodeStyleSetHeight(row, 10);

YGNodeRef item = YGNodeNew();
YGNodeStyleSetFlexBasis(item, 90);
YGNodeStyleSetFlexShrink(item, 1);
YGNodeStyleSetMinWidth(item, 10);
YGNodeInsertChild(row, item, 0);

YGNodeRef sibling = YGNodeNew();
YGNodeStyleSetWidth(sibling, 10);
YGNodeInsertChild(row, sibling, 1);

YGNodeCalculateLayout(row, YGUndefined, YGUndefined, YGDirectionLTR);

bash repro.sh from the gist below clones main, builds Yoga with this program twice, with contraction and with -ffp-contract=off, and runs both. In ubuntu:24.04 on x86-64, where contraction needs -mfma:

react/yoga 41118bd, Ubuntu clang version 18.1.3 (1ubuntu1), Linux x86_64
contraction on (-mfma): 90 + (-80 / -90) * -90 is 9.99999905 fused, 10 rounded at each step; item width 90
contraction off (-ffp-contract=off): 90 + (-80 / -90) * -90 is 9.99999905 fused, 10 rounded at each step; item width 10
summary: react/yoga 41118bd lays the item out 90 wide, its flex basis, with contraction, and 10 wide, its min-width, without

and on arm64, with no flag:

react/yoga 41118bd, Ubuntu clang version 18.1.3 (1ubuntu1), Linux aarch64
contraction on: 90 + (-80 / -90) * -90 is 9.99999905 fused, 10 rounded at each step; item width 90
contraction off (-ffp-contract=off): 90 + (-80 / -90) * -90 is 9.99999905 fused, 10 rounded at each step; item width 10
summary: react/yoga 41118bd lays the item out 90 wide, its flex basis, with contraction, and 10 wide, its min-width, without

Expected Behavior

item width 10 with contraction, as without it: the item shrinks onto its minWidth.

Actual Behavior

item width 90: with contraction the item keeps its flex basis and overflows the 20-wide row.

In yoga/algorithm/CalculateLayout.cpp at 41118bd:

  • distributeFreeSpaceFirstPass computes baseMainSize = childFlexBasis + remainingFreeSpace / totalFlexShrinkScaledFactors * flexShrinkScaledFactor, which contraction turns into one fused multiply-add: 9.99999905 here, against 10 when the product is rounded first.
  • baseMainSize != boundMainSize compares exactly, so against the bound of 10 the first pass freezes the item: deltaFreeSpace takes 10 - 90, all -80 of the free space, which leaves remainingFreeSpace at exactly 0.
  • distributeFreeSpaceSecondPass shrinks or grows only while remainingFreeSpace is below or above 0, so the item keeps updatedMainSize = childFlexBasis and is never bounded to its minimum, though the first pass expects a frozen item's "min/max constraints should also trigger in the second pass".

#2038 is another FMA residual in these two passes.

Link to Code

https://gist.github.com/YevheniiKotyrlo/45b864d98eae145b9ef1879d97783657

Lingua principale
C++
Stelle
18.9k
Fork
1.6k
Merge medio
17h 9m
PR unite (30g)
13

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di react/yoga

Tutte le issue di react/yoga

Issue simili

Altre issue su C++

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.