Draco-lang / Compiler

The compiler repository for the Draco programming language.
Apache License 2.0
74 stars 9 forks source link

Unomptimal IL #326

Closed jgh07 closed 8 months ago

jgh07 commented 9 months ago

The following code:

import System;
import System.Text;
import System.Diagnostics;

func main() {
    var sw = Stopwatch();
    sw.Start();

    var sb = StringBuilder();
    sb.AppendLine("Hello World!");
    Console.Write(sb.ToString());
    sw.Stop();

    Console.WriteLine(sw.ElapsedMilliseconds);
}

Generates this IL:

[0] class [System.Runtime]System.Diagnostics.Stopwatch,
[1] class [System.Runtime]System.Diagnostics.Stopwatch,
[2] class [System.Runtime]System.Diagnostics.Stopwatch,
[3] class [System.Runtime]System.Text.StringBuilder,
[4] class [System.Runtime]System.Text.StringBuilder,
[5] class [System.Runtime]System.Text.StringBuilder,
[6] class [System.Runtime]System.Text.StringBuilder,
[7] class [System.Runtime]System.Text.StringBuilder,
[8] string,
[9] class [System.Runtime]System.Diagnostics.Stopwatch,
[10] class [System.Runtime]System.Diagnostics.Stopwatch,
[11] int64

Why are there 5 locals of type Stopwatch and StringBuilder when there should be only one?

LPeter1997 commented 9 months ago

This is due to our optimizing IR being in SSA form with registers and then doing the most blunt translation to the stack machine of .NET. We will have to do a stackification step eventually, just like LLVM does for WASM, but we haven't gotten to it yet. We should create an issue for this to track it.

The copies all reference the same instance, they just correspond to a different register in our IR.

LPeter1997 commented 8 months ago

331 is slowly but surely on the way. The IL is now this:

.method private hidebysig static 
    void main () cil managed 
{
    // Method begins at RVA 0x2050
    // Header size: 12
    // Code size: 59 (0x3b)
    .maxstack 8
    .entrypoint
    .locals (
        [0] class [System.Runtime]System.Diagnostics.Stopwatch,
        [1] class [System.Runtime]System.Text.StringBuilder
    )

    IL_0000: call class [System.Runtime]System.Diagnostics.Stopwatch [stackify.dll]FreeFunctions::Stopwatch()
    IL_0005: stloc.0
    IL_0006: ldloc.0
    IL_0007: callvirt instance void [System.Runtime]System.Diagnostics.Stopwatch::Start()
    IL_000c: call class [System.Runtime]System.Text.StringBuilder [stackify.dll]FreeFunctions::StringBuilder()
    IL_0011: stloc.1
    IL_0012: ldloc.1
    IL_0013: ldstr "Hello World!"
    IL_0018: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::AppendLine(string)
    IL_001d: pop
    IL_001e: ldloc.1
    IL_001f: callvirt instance string [System.Runtime]System.Text.StringBuilder::ToString()
    IL_0024: call void [System.Console]System.Console::Write(string)
    IL_0029: ldloc.0
    IL_002a: callvirt instance void [System.Runtime]System.Diagnostics.Stopwatch::Stop()
    IL_002f: ldloc.0
    IL_0030: call instance int64 [System.Runtime]System.Diagnostics.Stopwatch::get_ElapsedMilliseconds()
    IL_0035: call void [System.Console]System.Console::WriteLine(int64)
    IL_003a: ret
} // end of method FreeFunctions::main

Decompiled C#:

private static void main()
{
    Stopwatch val = Stopwatch();
    val.Start();
    StringBuilder stringBuilder = StringBuilder();
    stringBuilder.AppendLine("Hello World!");
    Console.Write(stringBuilder.ToString());
    val.Stop();
    Console.WriteLine(val.ElapsedMilliseconds);
}