C# Intermediate Language

.NET IL

Square abstract illustration

The intermediate language is low-level. It is a special language that all C# code is compiled to. When you compile a C# program, the high-level code is translated into a series of evaluation stack instructions. These instructions—intermediate language opcodes—reside in a relational database called the metadata.

This page describes the .NET Framework intermediate language. The IL is composed of instructions.

Analysis and synthesis

.NET Framework information

Compiler theory can be divided into two parts. Analysis is where the high-level source code is parsed and a symbol table is derived for further processing. Synthesis is where the object code is generated and written to an executable. Analysis and synthesis result in an intermediate form.

Analysis: Source code is parsed and a symbol table is derived.

Synthesis: Object code is generated and written to an executable.

On execution of the intermediate form, another compiler, the JIT compiler, will be invoked and perform even more optimizations. In this example, we see a C# method and its compiled intermediate language form.

Example C# program

using System;

class Program
{
    static void Main()
    {
	int i = 0;
	while (i < 10)
	{
	    Console.WriteLine(i);
	    i++;
	}
    }
}

Intermediate language for Main method

.method private hidebysig static void Main() cil managed
{
    .entrypoint
    .maxstack 2
    .locals init (
	[0] int32 num)
    L_0000: ldc.i4.0
    L_0001: stloc.0
    L_0002: br.s L_000e
    L_0004: ldloc.0
    L_0005: call void [mscorlib]System.Console::WriteLine(int32)
    L_000a: ldloc.0
    L_000b: ldc.i4.1
    L_000c: add
    L_000d: stloc.0
    L_000e: ldloc.0
    L_000f: ldc.i4.s 10
    L_0011: blt.s L_0004
    L_0013: ret
}
Main method

IL for Main method. In the second part of the text, you can see the intermediate form of the Main method. You can see three flagged sections in the first part of the body of the method. These indicate that the Main method is the entry point; that the stack has a maximum size; and that there is one local variable.

Const keyword

Load constants. At L_0000, you can see that the constant number zero is pushed onto the evaluation stack through the instruction ldc. Then, this constant is stored from the evaluation stack into the local variable.

Const Example

Branch. In the intermediate language, when you see the instruction "br", this indicates a branch. A branch instruction is a conditional instruction that will change what instruction is executed next based on the condition. In the C# language, things such as goto, while, for, break, and return may be implemented with variants of the branch instruction.

Goto Loop Example While Loop Examples For Loops Break Statement Return Statement

Call method. Next, the method Console.WriteLine, which is implemented externally, is called. Before it is called, the location of the local variable we are writing is pushed to the evaluation stack and this is used as an argument.

Console.WriteLineSteps

Increment. In the intermediate language, an increment expression such as i++ is implemented by pushing a constant one to the evaluation stack, and then using the add arithmetic instruction to increment.

Increment Int Decrement Int

Loop instructions. The line L_0011 implements another instruction that returns control to the beginning of the loop if the condition is met. This is another form of a branch instruction. Please note how branch instructions use labels in the intermediate language. Branches are basically goto statements at the lower level. All high-level loops can be translated into branches and labels.

IL Disassembler

Programming tip

To gain an understanding of the C# language, I would recommend that you inspect the intermediate language for all the code you write. Then, you can actually modify your code to see how the intermediate language is affected. There are many surprises in this process, and this is a key to learning how the language itself is implemented.

IL Disassembler Tutorial

Tip: Use IL Disassembler, provided with Visual Studio, to look at the intermediate language.

Instructions

The intermediate language in the .NET Framework uses instructions to execute statements. These instructions act upon and manipulate the evaluation stack.

bne call callvirt ldarg ldc ldloc ldsfld ret stelem stsfld switch

Summary

The C# programming language

We looked at the intermediate language in the .NET Framework and C# language. We provided a description of a loop in the intermediate language, touching on the concepts of the evaluation stack and how loops are translated into flattened branches and labels.

.NET