digitalmars.D.bugs - [Issue 14761] New: Optimize and debloat pass by ref to pass by value
- via Digitalmars-d-bugs (83/83) Jul 02 2015 https://issues.dlang.org/show_bug.cgi?id=14761
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 puremagic.com Reporter: dmitry.olsh 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); } --
Jul 02 2015