Question

I'm currently writing a toy compiler as a homework, targeted at the MIPS architecture.

There are 18 registers that are generally available when translating from higher-level languages: s0 to s7 which are callee-saved, and t0 to t9 which are caller-saved.

With these 18 registers available, a question emerges: which register should I prefer when performing the translation of a function.

Each set has its pros and cons:

  1. Callee-saved registers must be saved to and restored from the stack at the beginning and the end of a function, respectively.
  2. Caller-saved registers must be saved to and restored from the stack before and after invoking a subroutine, respectively.

It's clear to me that if I adopt a static strategy on using these registers — whatever the strategy is, like preferring callee-saved registers over caller-saved ones — I will not get the optimal performance since most probably there will be unnecessary register load/stores.

So, is there any good practices of using these two sets of registers?

Was it helpful?

Solution 2

Here's a better solution than chill's, which allocates registers in a finer granularity:

First we perform liveness analysis for each variable, and:

  • For a variable the liveness interval of which spans a function call: we prefer callee-saved registers over caller-saved ones.
  • For a variable the liveness interval of which doesn't span a function call: prefer caller-saved ones over callee-saved ones.

OTHER TIPS

Prefer callee-saved registers in non-leaf functions, prefer caller-saved registers in leaf functions.

At the leaves and one level up the call tree, with only a little luck, you won't have any saves whatsoever.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top