First of all you are comparing the "current implemented behaviour" (of whatever version of fpc?) with the "documented design"
So it may well be that in the fpc version that you tested (or even all fpc versions available so far), for specific code you get better results.
But that may not hold true for future versions.
Below is not tested...
constref will always pass a parameter as pointer, even if the parameter could be passed as value in a register.
And the latter (value in register) is certainly preferable.
Imagine the following
type TFoo: record a: pointer; end;
var x: Tfoo;
such a record makes x assignment incompatible to other pointers. So there are usecases for it. (operator overloading)
If you then have
procedure takesFoo(constref a: TFoo);
This will be more expensive than "const a: TFoo".
On the calling side, it could go either way. Maybe on the calling site constref will save a statement. (maybe in a future fpc it will be different)
But inside takesFoo the variable "a" is a pointer to TFoo.
Accessing a now needs an extra pointer dereference.
If "a" can not be kept in a register (because takesFoo is to complex), then the overhead of accessing the value via a pointer may happen many times in takesFoo.
------------
Constref will always result in significantly less lines of code when passing records
I assume that is on the calling side?
How about on the called site, when dereferencing the pointer is added?
-----------
Also you need to say:
Optimize for size or speed?
Sometimes code with a few extra lines, is faster than that with less.