Constant expressions' implicit conversions not performed at runtim

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

Hi,

disassembling following expression I noticed that the implicit conversion
between int and decimal appears to be performed at runtime. Why?

TIA,
Axel Dahmen

void Main()
{
decimal a=1.2m, b;

b = a + 0;
}
 
Sorry for using the wrong caption. Original question is: Why isn't the
following conversion performed at compile time?
 
Axel,

The Decimal structure is a bit more complex than an integer. The
Decimal structure has a number of internal fields that allow it to provide
the accuracy that it does. Also, there is code that has to be executed by
the structure itself when performing an implicit conversion, which can not
be executed at compile-time.

Hope this helps.
 
Hi Axel,

I agree with Nicholas.

In fact, all data type conversions are performed at run time.

If you have any question, please feel free to let me know.

Sincerely,
Linda Liu
Microsoft Online Community Support

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 
Thanks to both of you.

Let me explain why this question comes up to me: "0" in this case is a
constant, meaning that there will never be anything necessary to be evaluated
at runtime. Instead of converting a constant integer at runtime (=decreasing
performance), the compiler can undoubtedly decide to use a decimal constant
from the beginning. Hence, an optimizing compiler would produce same code
regardless if someone writes "0" or "0m" or "0.0".

Or am I wrong with my assumption?

TIA,
Axel Dahmen
 
Let me explain why this question comes up to me: "0" in this case is a
constant, meaning that there will never be anything necessary to be
evaluated
at runtime. Instead of converting a constant integer at runtime
(=decreasing
performance), the compiler can undoubtedly decide to use a decimal
constant
from the beginning. Hence, an optimizing compiler would produce same code
regardless if someone writes "0" or "0m" or "0.0".

See my first response. Simply compile your example and open it with a
reflection tool, you'll see that the compiler has put a 0m instead of 0.
 
Axel Dahmen said:
Let me explain why this question comes up to me: "0" in this case is a
constant, meaning that there will never be anything necessary to be evaluated
at runtime. Instead of converting a constant integer at runtime (=decreasing
performance), the compiler can undoubtedly decide to use a decimal constant
from the beginning. Hence, an optimizing compiler would produce same code
regardless if someone writes "0" or "0m" or "0.0".

Or am I wrong with my assumption?

You're wrong (or at least may be wrong) in your assumption that it will
decrease performance. Don't forget that the IL isn't what gets executed
directly - it gets JITted first. The C# compiler does relatively few
optimisations, leaving much of it to the JIT.

Now, I haven't checked to see whether or not the JIT *does* optimise
this, but it may well.
 
Thanks for all your replies!

To your response, Jon: What is it I'm seeing if I'm watching the Disassembly
window? Isn't that the final JIT'ed code?

In fact, I didn't see differences in the generated code between using "1"
and "1m". But I see a difference when using "1.0m":

b = a ?? 1;
0000004c lea edi,[ebp-78h]
0000004f lea esi,[ebp-64h]
00000052 movq xmm0,mmword ptr [esi]
00000056 movq mmword ptr [edi],xmm0
0000005a movq xmm0,mmword ptr [esi+8]
0000005f movq mmword ptr [edi+8],xmm0
00000064 add esi,10h
00000067 add edi,10h
0000006a movs dword ptr es:[edi],dword ptr [esi]
0000006b lea edi,[ebp-50h]
0000006e lea ecx,[ebp-78h]
00000071 call 7892F268
00000076 mov esi,eax
00000078 test esi,esi
0000007a jne 000000AF
0000007c lea ecx,[ebp+FFFFFF68h]
00000082 mov edx,1
00000087 call 7876982C

------------------------

a = b ?? 1.0m;
0000004c lea edi,[ebp-78h]
0000004f lea esi,[ebp-64h]
00000052 movq xmm0,mmword ptr [esi]
00000056 movq mmword ptr [edi],xmm0
0000005a movq xmm0,mmword ptr [esi+8]
0000005f movq mmword ptr [edi+8],xmm0
00000064 add esi,10h
00000067 add edi,10h
0000006a movs dword ptr es:[edi],dword ptr [esi]
0000006b lea edi,[ebp-50h]
0000006e lea ecx,[ebp-78h]
00000071 call 7892F268
00000076 mov esi,eax
00000078 test esi,esi
0000007a jne 000000B7
0000007c push 0
0000007e push 0
00000080 push 0
00000082 push 1
00000084 lea ecx,[ebp+FFFFFF68h]
0000008a mov edx,0Ah
0000008f call 78769854

Thanks again to all of you for enlightening me. We have a small argument
here at the company about if the compiler optimizes or if it doesn't. I'm
arguing that it does, but the Disassembly windows tells me different.

TIA,
Axel Dahmen
 
Thanks for all your replies!

To your response, Jon: What is it I'm seeing if I'm watching the Disassembly
window? Isn't that the final JIT'ed code?

That depends on whether it's been JITted with optimisation on or not.
However, my point was that you were using the IL as basis for saying
there's decreased performance.
In fact, I didn't see differences in the generated code between using "1"
and "1m". But I see a difference when using "1.0m":

Ah - but in that case you're changing the meaning. Decimals (as of
1.1) remember how many decimal places are stored, including trailing
0s. 1.0m and 1m have different representations, and the results of
adding them to other decimals will (or at least may) be different.
Thanks again to all of you for enlightening me. We have a small argument
here at the company about if the compiler optimizes or if it doesn't. I'm
arguing that it does, but the Disassembly windows tells me different.

It's relatively tricky to make sure you're looking at the disassembly
of real, JIT-optimised code. Running even the release assembly within
a debugger is unlikely to produce the same code.

Jon
 
Hi Axel,
What is it I'm seeing if I'm watching the Disassembly window? Isn't that
the final JIT'ed code?

The Disassembly window shows assembly code corresponding to the
instructions created by the compiler. If you are debugging managed code,
these assembly instructions correspond to the native code created by the
Just-in-Tim(JIT) compiler, not the Microsoft intermediate language(MSIL)
generated by the Visual Studio compiler.

I have performed a test on the following section of code:
int i = 3;
decimal d;
d = i;

In theory, the value of i will be implicitly converted to a decimal value
before being assigned to d. Press F5 to run the program and I get the
following corresponding assembly code from the Disassembly window:

d = i;
00000026 lea ecx,[ebp-2Ch]
00000029 mov edx,ebx
0000002b call dword ptr ds:[79C41B40h]
00000031 lea edi,[ebp-1Ch]
00000034 lea esi,[ebp-2Ch]
00000037 movs dword ptr [edi],dword ptr [esi]
00000038 movs dword ptr [edi],dword ptr [esi]
00000039 movs dword ptr [edi],dword ptr [esi]
0000003a movs dword ptr [edi],dword ptr [esi]

Then I modify the code to explicitly convert the value of i to a decimal
value as follows:
d = (decimal)i;

The corresponding assembly code is like blow:

d = (decimal)i;
00000026 lea ecx,[ebp-2Ch]
00000029 mov edx,ebx
0000002b call dword ptr ds:[79C41B40h]
00000031 lea edi,[ebp-1Ch]
00000034 lea esi,[ebp-2Ch]
00000037 movs dword ptr [edi],dword ptr [esi]
00000038 movs dword ptr [edi],dword ptr [esi]
00000039 movs dword ptr [edi],dword ptr [esi]
0000003a movs dword ptr [edi],dword ptr [esi]

As we could see, the two sections of assembly code are the same. In fact,
either of the above two sections of assebly code contains the type
conversion instruction "xlat", and it means that the type conversion has
been finished at compile time and needn't to be done at run time.

As for your original question, i.e. decimal b = a + 0;, the constant
expression 0 is converted to a decimal value at compile time. Sorry for the
confusion that my first reply causes.
In fact, I didn't see differences in the generated code between using "1"
and "1m". But I see a difference when using "1.0m":

I agree with Jon. 1.0m and 1m have different representations, so their
corresponding assembly code will be different.

Hope this helps.
If you have anything unclear, please feel free to let me know.


Sincerely,
Linda Liu
Microsoft Online Community Support
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top