Bug 14761 – Optimize and debloat pass by ref to pass by value (use case - all output ranges)

Status
NEW
Severity
enhancement
Priority
P4
Component
phobos
Product
D
Version
D2
Platform
All
OS
All
Creation time
2015-07-02T13:36:41Z
Last change time
2024-12-01T16:24:45Z
Assigned to
No Owner
Creator
Dmitry Olshansky
Moved to GitHub: phobos#10134 →

Comments

Comment #0 by dmitry.olsh — 2015-07-02T13:36:41Z
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); }
Comment #1 by johnnymarler — 2015-07-02T16:15:01Z
I'd like to add a link to a potential solution: http://forum.dlang.org/thread/[email protected] It may or may not be the best solution but I thought I'd put in on the table for consideration.
Comment #2 by robert.schadek — 2024-12-01T16:24:45Z
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/phobos/issues/10134 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB