Assignments
  • Introduction
  • Instructions
  • Source Code
  • Compiler Stages
    • Stage Presentation
    • TC-1/2, Scanner, Parser & Building the Abstract Syntax Tree
    • TC-3, Bindings
    • TC-R, Unique Identifiers
    • TC-E, Computing the Escaping Variables
    • TC-4, Type Checking
    • TC-D, Removing the syntactic sugar from the Abstract Syntax Tree
    • TC-L, LLVM IR
    • TC-EXTS, Improving Your Compiler with Fun Extensions
    • TC-5, Translating to the High Level Intermediate Representation
      • TC-5 Goals
      • TC-5 Samples
      • TC-5 Given Code
      • TC-5 Code to Write
      • TC-5 Options
        • TC-5 Bounds Checking
        • TC-5 Optimizing Static Links
      • TC-5 FAQ
      • TC-5 Improvements
    • TC-6, Translating to the Low Level Intermediate Representation
    • TC-7, Instruction Selection
    • TC-8, Liveness Analysis
    • TC-9, Register Allocation
    • TC-X, IA-32 Back End
    • TC-Y, ARM Back End
  • Tools
  • Tiger Compiler Reference Manual
  • Archive
Assignments
  • Compiler Stages
  • TC-5, Translating to the High Level Intermediate Representation
  • TC-5 Options
  • TC-5 Optimizing Static Links

TC-5 Optimizing Static Links

Note

This optimization is difficult to do perfectly.

In a first and conservative extension, the compiler considers that all the functions (but the builtins!) need a static link. This is correct, but inefficient: for instance, the traditional fact function will spend almost as much time handling the static link, than its real argument.

Some functions need a static link, but don’t need to save it on the stack. For instance, in the following example:

let
  var foo := 1
  function foo() : int = foo
in
  foo()
end

The function foo does need a static link to access the variable foo, but does not need to store its static link on the stack.

It is suggested to address these problems in the following order:

  1. Implement the detection of functions that do not need a static link (see exercise 6.5 in Modern Compiler Implementation), but still consider any static link escapes.

  2. Adjust the output of --escapes-display to display /* escaping sl */ before the first formal argument of the functions (declarations) that need the static link.

fact.tig
let
   function fact(n : int) : int =
      if (n = 0)
         then 1
         else n * fact((n - 1))
in
   fact(10)
end
tc -XEA fact.tig
$ tc -XEA fact.tig
/* == Abstract Syntax Tree. == */

function _main() =
  (
    let
      function fact(/* escaping */ n : int) : int =
        if (n = 0)
          then 1
          else n * fact((n - 1))
    in
      fact(10)
    end;
    ()
  )
$ echo $?
0
tc -XeEA fact.tig
$ tc -XeEA fact.tig
/* == Abstract Syntax Tree. == */

function _main() =
  (
    let
      function fact(n : int) : int =
        if (n = 0)
          then 1
          else n * fact((n - 1))
    in
      fact(10)
    end;
    ()
  )
$ echo $?
0
  1. Adjust your call and progFrag prologues.

  2. Improve your computation so that non-escaping static links are detected.

escaping-sl.tig
let
   var toto := 1
   function outer() : int =
     let function inner() : int = toto
     in inner() end
in
  outer()
end
tc -XeEA escaping-sl.tig
$ tc -XeEA escaping-sl.tig
/* == Abstract Syntax Tree. == */

function _main() =
  (
    let
      var /* escaping */ toto := 1
      function outer() : int =
        let
          function inner() : int =
            toto
        in
          inner()
        end
    in
      outer()
    end;
    ()
  )
$ echo $?
0

Here, both outer and inner need their static link so that inner can access toto. However, outer’s static link escapes, while inner’s does not.

Warning

Watch out, it is not trivial to find the minimum. What do you think about the static link of the function sister below?

let
  var v := 1
  function outer() : int =
    let
      function inner() : int = v
    in
      inner()
    end
  function sister() : int = outer()
in
  sister()
end
Previous Next

© Copyright 2025, LRE.

Built with Sphinx using a theme provided by Read the Docs.