DEV Community

Vir
Vir

Posted on

A Compiler optimization area

While applying for a role in Compilers, the interviewer asked me about my LICM (Loop Invariant Code Motion) optimization pass. This is where variables inside the loop which compute the same value, can be moved outside of the loop, reducing the number of instructions for a loop to compute.

I answered them, the LICM pass would move invariant instructions (with no side effects, i.e. loads, stores, calls, volatile, etc) which had invariant operands. Instructions which always compute the same thing would be moved out. Also, they need to be part of the dominator tree. e.g. Guards (if - checks)

They asked me, what about mutable Global Variable. Short answer: No, can't be optimized.

Complex answer: Might be able to.

  1. A global variable mutated a couple of times (on any threads), stabilizes in value, then goes through the loop. In this situation, it can be utilized as a constant

  2. In context of GPUs, Global Variable are utilized a lot for multiply and add instructions. These require simultaneous concurrent multiple Read Write requests to the global variable. Here, this variable would not be touched by the LICM pass.

I believe optimizing this mutable global variable can be done better at the Intermediate pass before generating LLVM or using MLIR a pass.

Is it worth it? I think the complexity is far too much on detecting these global variables if they are mutated. The time can be better spent on working on other areas of the compiler.

The optimization problem can be solved by the software developer in a rather easier way:

PreOptimization:

  int x = 5; // Defined Global scope across multiple threads
  x++;
  thread1 {
    x++;
  }
  waitForThread1ToComplete();
  while (true) {
    print(x*x); // x is global mutable, and is mutated, can't LICM
// is mutated: meaning if not mutated, can show error to dev

Enter fullscreen mode Exit fullscreen mode

Developer written suggestions: Use an intermediate constant variable and assign the global variable to it

  waitForThread1ToComplete();
  const int copyX = x;
  while (true) {
    print(copyX*copyX); // copyX is constant, LICM can optimize this
Enter fullscreen mode Exit fullscreen mode

Top comments (0)