[Issue 14761] New: Optimize and debloat pass by ref to pass by value (use case - all output ranges)
via Digitalmars-d-bugs
digitalmars-d-bugs at puremagic.com
Thu Jul 2 06:36:41 PDT 2015
https://issues.dlang.org/show_bug.cgi?id=14761
Issue ID: 14761
Summary: Optimize and debloat pass by ref to pass by value (use
case - all output ranges)
Product: D
Version: D2
Hardware: All
OS: All
Status: NEW
Severity: enhancement
Priority: P1
Component: phobos
Assignee: nobody at puremagic.com
Reporter: dmitry.olsh at gmail.com
The problem statement is this code in Phobos (std.range.primitives):
private void doPut(R, E)(ref R r, auto ref E e)
{
static if(is(PointerTarget!R == struct))
enum usingPut = hasMember!(PointerTarget!R, "put");
else
enum usingPut = hasMember!(R, "put");
//...
}
Observe that the range r is always taken by reference where if range is a class
instance or a pointer it makes no sense to add an extra indirection.
Moreover ref Range* and ref Range instantiations should be exactly the same
code as (would be) Range* so there is an opportunity to debloat by factor of 2
by merging them.
In simple cases presented compiler was able to optimize it out via inlining,
but sometimes it might not. Certainly it won't do so in unoptimized or
separately compiled builds.
See also original motivation and code:
https://github.com/D-Programming-Language/phobos/pull/2655
// Sketch of the technique to merge ref T and T* branches for output ranges
// while passing classes/delegates by value
private enum bool isPassByValue(T) = is(T: U*, U) || is( T == class ) ||
is (T == delegate) || is( T == function );
// Hook C-runtime to avoid being optimized out
extern(C) void putchar(int c);
//same doPut but _stripped_ of `ref` storage class
void doPut(T)(T arg){
pragma(msg, "Instantiated " ~ T.stringof);
// some sensible output ...
putchar(arg.value);
}
template forwardRef(alias Fn, T)
{
static if(isPassByValue!T)
{
pragma(msg, T.stringof ~" by value");
alias forwardRef = Fn!T;
}
else
{
pragma(msg, T.stringof ~" by ref");
auto forwardRef(ref T arg)
{
//convert to pointer explicitly
// ref T --> T* to debloat based on ref-ness
return Fn(&arg);
}
}
}
struct Val{
int value;
}
class CVal{
int value;
}
void main()
{
alias valFn = forwardRef!(doPut, Val);
alias ptrFn = forwardRef!(doPut, Val*);
alias classFn = forwardRef!(doPut, CVal);
Val v = Val('A');
CVal cv = new CVal;
cv.value = 'C';
// call each function to see codegen
valFn(v);
ptrFn(&v);
classFn(cv);
}
--
More information about the Digitalmars-d-bugs
mailing list