Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extraneous temporary and copy in implicit byref parameter #3057

Closed
asik opened this issue May 15, 2017 · 2 comments
Closed

Extraneous temporary and copy in implicit byref parameter #3057

asik opened this issue May 15, 2017 · 2 comments

Comments

@asik
Copy link
Contributor

asik commented May 15, 2017

Using the tuple form of a call that has a byref parameter, if the surrounding code is sufficiently complex, the compiler emits an extraneous temporary and copy.

open System
open System.Collections.Generic

[<EntryPoint>]
let main argv = 
    let dict = Dictionary<int, DateTime>()
    let result, elem = dict.TryGetValue(0)
    let b = 
        if result then
            if elem.Day > 0 then
                Console.WriteLine ""
                true
            else false
        else false
    0

Expected behavior

Only one local is generated and no extra copy happens, i.e. generated code is equivalent to:

    let mutable V_1 = DateTime()
    let result = dict.TryGetValue(0, &V_1)
    let b = 
        if result then
            if V_1.Day > 0 then ...

Actual behavior

Looking at the IL, this generates 2 DateTime locals:

       [1] valuetype [mscorlib]System.DateTime V_1,
       [2] valuetype [mscorlib]System.DateTime V_2,

V_1 is passed into the call, then V_1 is copied into V_2, then V_2 is used. In effect this is equivalent to the following code:

    let mutable V_1 = DateTime()
    let result = dict.TryGetValue(0, &V_1)
    let V_2 = V_1
    let b = 
        if result then
            if V_2.Day > 0 then ...

I tried simplifying this example as much as possible, but at this point removing anything results in good generated code, without the copy, so it seems to depend a lot on the surrounding logic.

This makes a big difference in code that heavily relies on passing large structs by reference, e.g. System.Numerics.Vectors.Matrix4x4 etc; it wastes stack space and time copying. The JIT doesn't optimize this away.

Known workarounds

Don't use the tupled form, use a mutable local and pass it explicitly.

Related information

Visual Studio 2017 15.2 (26430.6).

@dsyme
Copy link
Contributor

dsyme commented Jun 6, 2018

@asik If you get a chance to try out #5110 on some performance benchmarks for System.Numerics.Vectors.Matrix4x4 etc. that would be great

@dsyme dsyme added the Ready label Jun 6, 2018
@cartermp cartermp added this to the 16.0 milestone Jul 21, 2018
@cartermp cartermp modified the milestones: 16.0, Unknown Aug 25, 2018
@cartermp cartermp modified the milestones: Unknown, 16.0 Sep 20, 2018
@cartermp
Copy link
Contributor

Closing this, as #5110 is merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants