-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Description
Description
Swapping / reordering variables compiles to slower IL code when using tuple destruction than a temporary variable.
I tested this in Release mode.
The following C# code
int x = 1;
int y = 2;
int z = 3;
(x, y)=(y, x);
Console.WriteLine((x,y,z)); //this line is to stop compiling out the variables
should be equivalent in IL output to
int x = 1;
int y = 2;
int z = 3;
int temp = x;
x = y;
y = temp;
Console.WriteLine((x,y,z)); //this line is to stop compiling out the variables
, but the first compiles to:
// Code size 31 (0x1f)
.maxstack 3
.locals init (int32 V_0,
int32 V_1,
int32 V_2,
int32 V_3)
ldc.i4.1
stloc.0
ldc.i4.2
stloc.1
ldc.i4.3
stloc.2
ldloc.1
ldloc.0
stloc.3
stloc.0
ldloc.3
stloc.1
ldloc.0
ldloc.1
ldloc.2
newobj instance void valuetype [System.Runtime]System.ValueTuple`3<int32,int32,int32>::.ctor(!0,
!1,
!2)
box valuetype [System.Runtime]System.ValueTuple`3<int32,int32,int32>
call void [System.Console]System.Console::WriteLine(object)
ret
and the second compiles to
// Code size 29 (0x1d)
.maxstack 3
.locals init (int32 V_0,
int32 V_1,
int32 V_2)
ldc.i4.1
stloc.0
ldc.i4.2
stloc.1
ldc.i4.3
stloc.2
ldloc.0
ldloc.1
stloc.0
stloc.1
ldloc.0
ldloc.1
ldloc.2
newobj instance void valuetype [System.Runtime]System.ValueTuple`3<int32,int32,int32>::.ctor(!0,
!1,
!2)
box valuetype [System.Runtime]System.ValueTuple`3<int32,int32,int32>
call void [System.Console]System.Console::WriteLine(object)
ret
With the essential code being for (1):
ldloc.1
ldloc.0
stloc.3
stloc.0
ldloc.3
stloc.1
, and for (2):
ldloc.0
ldloc.1
stloc.0
stloc.1
I did test this on .NET 5 locally, but also on an online .NET 6 compiler at https://sharplab.io/, which uses a very recent version.
I also imagine that a similar thing happens for other variants, such as:
(x, y) = (x, x);
(x, y, z, w) = (w, y, z, x);
etc.
Surely these destruction assignments should be as simple as ld
all of the variables, and then st
them all (as long as there's not too many).
Interestingly, the tuple destruction code essentially uses a temporary variable in IL, whereas the temporary variable code eliminates it.
Not sure if this belongs on roslyn or on here.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status