You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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:
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).
The text was updated successfully, but these errors were encountered:
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.
Expected behavior
Only one local is generated and no extra copy happens, i.e. generated code is equivalent to:
Actual behavior
Looking at the IL, this generates 2 DateTime locals:
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:
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).
The text was updated successfully, but these errors were encountered: