QUnicodeTools: reduce unneeded relocations

Turn the charAttributeFunction array of function pointers into a
switch. This has two benefits:

- The compiler now warns when we introduce a new QChar::Script value
  and statically forces us to think whether a new attribute handling
  function is needed.

- A table of function pointers requires relocations. A switch might
  not. GCC uses a jump table to implement this switch, jumping to
  distinct lea instructions fetching distinct function pointer values,
  and thereby removes relocations, while Clang actually forms a
  function pointer table and turns the switch into an indexing
  operation (with compiler-generated guards). I didn't check whether
  Clang's table actually requires relocations, relinfo.pl doesn't
  report any reductions, but it's become unreliable over the years,
  because it doesn't for GCC, either.

Difference:
  qunicodetools.cpp.o:
- 0000000000000000 l     O .data.rel.ro.local     0000000000000108 QUnicodeTools::Tailored::charAttributeFunction
  0000000000000000 l    d  .data.rel.ro.local     0000000000000000 .data.rel.ro.local

See
  https://stackoverflow.com/questions/19067010/finding-where-relocations-originate/19338343#19338343
for the script to generate this output.

See https://www.akkadia.org/drepper/dsohowto.pdf Section 1.6 for why
we care.

Instead of collapsing identical return statements from adjacent case
statements into one, keep the per-case return statements for now, to
aid review, and clean up in a follow-up commit.

Amends dd7d8304bbe599320b163b94e9a4ad9a6f35b740.

Pick-to: 6.8 6.5
Task-number: QTBUG-100536
Change-Id: Ic5b6bd29e3a3a88f0d194fa7d76272a4770b9840
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
(cherry picked from commit 74765ebe65b8b67b2d2bbe3f4fa3eb1879d030aa)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Marc Mutz 2025-03-07 08:07:15 +01:00 committed by Qt Cherry-pick Bot
parent b173da88f4
commit 7ee176bcbe

View File

@ -2571,73 +2571,220 @@ static void khmerAttributes(QChar::Script script, const char16_t *text, qsizetyp
} }
const CharAttributeFunction charAttributeFunction[] = { static CharAttributeFunction charAttributeFunction(QChar::Script script)
// Script_Unknown, {
nullptr, switch (script) {
// Script_Inherited, case QChar::Script_Unknown:
nullptr, return nullptr;
// Script_Common, case QChar::Script_Inherited:
nullptr, return nullptr;
// Script_Latin, case QChar::Script_Common:
nullptr, return nullptr;
// Script_Greek, case QChar::Script_Latin:
nullptr, return nullptr;
// Script_Cyrillic, case QChar::Script_Greek:
nullptr, return nullptr;
// Script_Armenian, case QChar::Script_Cyrillic:
nullptr, return nullptr;
// Script_Hebrew, case QChar::Script_Armenian:
nullptr, return nullptr;
// Script_Arabic, case QChar::Script_Hebrew:
nullptr, return nullptr;
// Script_Syriac, case QChar::Script_Arabic:
nullptr, return nullptr;
// Script_Thaana, case QChar::Script_Syriac:
nullptr, return nullptr;
// Script_Devanagari, case QChar::Script_Thaana:
indicAttributes, return nullptr;
// Script_Bengali, case QChar::Script_Devanagari:
indicAttributes, return &indicAttributes;
// Script_Gurmukhi, case QChar::Script_Bengali:
indicAttributes, return &indicAttributes;
// Script_Gujarati, case QChar::Script_Gurmukhi:
indicAttributes, return &indicAttributes;
// Script_Oriya, case QChar::Script_Gujarati:
indicAttributes, return &indicAttributes;
// Script_Tamil, case QChar::Script_Oriya:
indicAttributes, return &indicAttributes;
// Script_Telugu, case QChar::Script_Tamil:
indicAttributes, return &indicAttributes;
// Script_Kannada, case QChar::Script_Telugu:
indicAttributes, return &indicAttributes;
// Script_Malayalam, case QChar::Script_Kannada:
indicAttributes, return &indicAttributes;
// Script_Sinhala, case QChar::Script_Malayalam:
indicAttributes, return &indicAttributes;
// Script_Thai, case QChar::Script_Sinhala:
thaiAttributes, return &indicAttributes;
// Script_Lao, case QChar::Script_Thai:
nullptr, return &thaiAttributes;
// Script_Tibetan, case QChar::Script_Lao:
tibetanAttributes, return nullptr;
// Script_Myanmar, case QChar::Script_Tibetan:
myanmarAttributes, return &tibetanAttributes;
// Script_Georgian, case QChar::Script_Myanmar:
nullptr, return &myanmarAttributes;
// Script_Hangul, case QChar::Script_Georgian:
nullptr, return nullptr;
// Script_Ethiopic, case QChar::Script_Hangul:
nullptr, return nullptr;
// Script_Cherokee, case QChar::Script_Ethiopic:
nullptr, return nullptr;
// Script_CanadianAboriginal, case QChar::Script_Cherokee:
nullptr, return nullptr;
// Script_Ogham, case QChar::Script_CanadianAboriginal:
nullptr, return nullptr;
// Script_Runic, case QChar::Script_Ogham:
nullptr, return nullptr;
// Script_Khmer, case QChar::Script_Runic:
khmerAttributes return nullptr;
case QChar::Script_Khmer:
return &khmerAttributes;
case QChar::Script_Mongolian:
case QChar::Script_Hiragana:
case QChar::Script_Katakana:
case QChar::Script_Bopomofo:
case QChar::Script_Han:
case QChar::Script_Yi:
case QChar::Script_OldItalic:
case QChar::Script_Gothic:
case QChar::Script_Deseret:
case QChar::Script_Tagalog:
case QChar::Script_Hanunoo:
case QChar::Script_Buhid:
case QChar::Script_Tagbanwa:
case QChar::Script_Coptic:
case QChar::Script_Limbu:
case QChar::Script_TaiLe:
case QChar::Script_LinearB:
case QChar::Script_Ugaritic:
case QChar::Script_Shavian:
case QChar::Script_Osmanya:
case QChar::Script_Cypriot:
case QChar::Script_Braille:
case QChar::Script_Buginese:
case QChar::Script_NewTaiLue:
case QChar::Script_Glagolitic:
case QChar::Script_Tifinagh:
case QChar::Script_SylotiNagri:
case QChar::Script_OldPersian:
case QChar::Script_Kharoshthi:
case QChar::Script_Balinese:
case QChar::Script_Cuneiform:
case QChar::Script_Phoenician:
case QChar::Script_PhagsPa:
case QChar::Script_Nko:
case QChar::Script_Sundanese:
case QChar::Script_Lepcha:
case QChar::Script_OlChiki:
case QChar::Script_Vai:
case QChar::Script_Saurashtra:
case QChar::Script_KayahLi:
case QChar::Script_Rejang:
case QChar::Script_Lycian:
case QChar::Script_Carian:
case QChar::Script_Lydian:
case QChar::Script_Cham:
case QChar::Script_TaiTham:
case QChar::Script_TaiViet:
case QChar::Script_Avestan:
case QChar::Script_EgyptianHieroglyphs:
case QChar::Script_Samaritan:
case QChar::Script_Lisu:
case QChar::Script_Bamum:
case QChar::Script_Javanese:
case QChar::Script_MeeteiMayek:
case QChar::Script_ImperialAramaic:
case QChar::Script_OldSouthArabian:
case QChar::Script_InscriptionalParthian:
case QChar::Script_InscriptionalPahlavi:
case QChar::Script_OldTurkic:
case QChar::Script_Kaithi:
case QChar::Script_Batak:
case QChar::Script_Brahmi:
case QChar::Script_Mandaic:
case QChar::Script_Chakma:
case QChar::Script_MeroiticCursive:
case QChar::Script_MeroiticHieroglyphs:
case QChar::Script_Miao:
case QChar::Script_Sharada:
case QChar::Script_SoraSompeng:
case QChar::Script_Takri:
case QChar::Script_CaucasianAlbanian:
case QChar::Script_BassaVah:
case QChar::Script_Duployan:
case QChar::Script_Elbasan:
case QChar::Script_Grantha:
case QChar::Script_PahawhHmong:
case QChar::Script_Khojki:
case QChar::Script_LinearA:
case QChar::Script_Mahajani:
case QChar::Script_Manichaean:
case QChar::Script_MendeKikakui:
case QChar::Script_Modi:
case QChar::Script_Mro:
case QChar::Script_OldNorthArabian:
case QChar::Script_Nabataean:
case QChar::Script_Palmyrene:
case QChar::Script_PauCinHau:
case QChar::Script_OldPermic:
case QChar::Script_PsalterPahlavi:
case QChar::Script_Siddham:
case QChar::Script_Khudawadi:
case QChar::Script_Tirhuta:
case QChar::Script_WarangCiti:
case QChar::Script_Ahom:
case QChar::Script_AnatolianHieroglyphs:
case QChar::Script_Hatran:
case QChar::Script_Multani:
case QChar::Script_OldHungarian:
case QChar::Script_SignWriting:
case QChar::Script_Adlam:
case QChar::Script_Bhaiksuki:
case QChar::Script_Marchen:
case QChar::Script_Newa:
case QChar::Script_Osage:
case QChar::Script_Tangut:
case QChar::Script_MasaramGondi:
case QChar::Script_Nushu:
case QChar::Script_Soyombo:
case QChar::Script_ZanabazarSquare:
case QChar::Script_Dogra:
case QChar::Script_GunjalaGondi:
case QChar::Script_HanifiRohingya:
case QChar::Script_Makasar:
case QChar::Script_Medefaidrin:
case QChar::Script_OldSogdian:
case QChar::Script_Sogdian:
case QChar::Script_Elymaic:
case QChar::Script_Nandinagari:
case QChar::Script_NyiakengPuachueHmong:
case QChar::Script_Wancho:
case QChar::Script_Chorasmian:
case QChar::Script_DivesAkuru:
case QChar::Script_KhitanSmallScript:
case QChar::Script_Yezidi:
case QChar::Script_CyproMinoan:
case QChar::Script_OldUyghur:
case QChar::Script_Tangsa:
case QChar::Script_Toto:
case QChar::Script_Vithkuqi:
case QChar::Script_Kawi:
case QChar::Script_NagMundari:
case QChar::Script_Garay:
case QChar::Script_GurungKhema:
case QChar::Script_KiratRai:
case QChar::Script_OlOnal:
case QChar::Script_Sunuwar:
case QChar::Script_Todhri:
case QChar::Script_TuluTigalari:
return nullptr;
case QChar::ScriptCount:
// Don't Q_UNREACHABLE here; this might be a newer value in later Qt versions
// (incl. patch releases)
;
}
return nullptr;
}; };
static void getCharAttributes(const char16_t *string, qsizetype stringLength, static void getCharAttributes(const char16_t *string, qsizetype stringLength,
@ -2648,9 +2795,7 @@ static void getCharAttributes(const char16_t *string, qsizetype stringLength,
return; return;
for (qsizetype i = 0; i < numItems; ++i) { for (qsizetype i = 0; i < numItems; ++i) {
QChar::Script script = items[i].script; QChar::Script script = items[i].script;
if (script > QChar::Script_Khmer) CharAttributeFunction attributeFunction = charAttributeFunction(script);
script = QChar::Script_Common;
CharAttributeFunction attributeFunction = charAttributeFunction[script];
if (!attributeFunction) if (!attributeFunction)
continue; continue;
qsizetype end = i < numItems - 1 ? items[i + 1].position : stringLength; qsizetype end = i < numItems - 1 ? items[i + 1].position : stringLength;