[Interest] Can QML compiler optimize switch into array indexing?
ivan (ratijas) tkachenko
me at ratijas.tk
Wed Oct 13 20:03:59 CEST 2021
Hi,
While working on KDE/Plasma stuff, I often encounter property bindings like
this switch-case here:
enabledBorders: {
switch (control.edge) {
case Qt.BottomEdge:
return PlasmaCore.FrameSvgItem.TopBorder;
case Qt.RightEdge:
return PlasmaCore.FrameSvgItem.LeftBorder;
case Qt.TopEdge:
return PlasmaCore.FrameSvgItem.BottomBorder;
case Qt.LeftEdge:
default:
return PlasmaCore.FrameSvgItem.RightBorder;
}
}
To the best of my knowledge, such switches can be optimized down to a simple
array indexing. If input is not a strictly fixed enum, then an extra branch
or two is needed to clamp the value. Speaking in pseudocode:
// assuming Qt.BottomEdge .. Qt.LeftEdge are sequential integers 0 .. 3
let input = Number(control.edge); // oh no, JavaScript is dynamicly typed
if (input < 0 || input > 3 || !Number.isInteger(input)
) {
input = 3;
}
static const data = [
/* [0] Qt.BottomEdge: */ PlasmaCore.FrameSvgItem.TopBorder,
/* [1] Qt.RightEdge: */ PlasmaCore.FrameSvgItem.LeftBorder,
/* [2] Qt.TopEdge: */ PlasmaCore.FrameSvgItem.BottomBorder,
/* [3] Qt.LeftEdge: */ PlasmaCore.FrameSvgItem.RightBorder,
]
return data[input];
// OR assuming binary shifts 0x00001, 0x00002, 0x00004, 0x00008
// for small number like 0x00008, sparse array should also be good enough
let input = Math.log2(control.edge);
if (input < 0 || input > 3 || !Number.isInteger(input)) {
input = 3;
}
static const data = [/*...same...*/];
return data[input];
For bigger switches and higher bits, there's x86 instruction called TZCNT
(Count the Number of Trailing Zero Bits), which should also be much faster
than the floating point operation `Math.log2()`.
I've seen C/C++ compiler doing it, I've explored .NET/C# IL bytecode doing it;
but I wonder what about Qt? How do I even assess whether such optimization is
or isn't performed for QML?
--
ivan (@ratijas)
More information about the Interest
mailing list