Browse Source

task: juggling function outputs between registers

main
Kartik K. Agaram 8 months ago
parent
commit
a3f73278b1
  1. 4
      511image.mu
  2. 42
      tutorial/index.md
  3. 23
      tutorial/task9-solution.mu
  4. 22
      tutorial/task9.mu

4
511image.mu

@ -368,12 +368,12 @@ fn dither-pgm-unordered-monochrome _src: (addr image), _dest: (addr image) {
curr-int <- shift-left 0x10 # we have 32 bits; we'll use 16 bits for the fraction and leave 8 for unanticipated overflow
var error/esi: int <- _read-dithering-error errors, x, y, src-width
error <- add curr-int
$_dither-pgm-unordered-monochrome:update-error: {
$dither-pgm-unordered-monochrome:update-error: {
compare error, 0x800000
{
break-if->=
_write-raw-buffer dest-data, x, y, src-width, 0/black
break $_dither-pgm-unordered-monochrome:update-error
break $dither-pgm-unordered-monochrome:update-error
}
_write-raw-buffer dest-data, x, y, src-width, 1/white
error <- subtract 0xff0000

42
tutorial/index.md

@ -354,6 +354,48 @@ the precise register a function header specifies. The return value can even be
a literal integer or in memory somewhere. The `return` is really just a `copy`
to the appropriate register(s). This is why the second example above is legal.
## Task 9: juggling registers between function calls
Here's a program:
```
fn f -> _/eax: int {
return 2
}
fn g -> _/eax: int {
return 3
}
fn add-f-and-g -> _/eax: int {
var x/eax: int <- f
var y/eax: int <- g
x <- add y
return x
}
```
What's wrong with this program? How can you fix it and pass all tests by
modifying just function `add-f-and-g`?
By convention, most functions in Mu return their results in register `eax`.
That creates a fair bit of contention for this register, and we often end up
having to move the output of a function call around to some other location to
free up space for the next function we need to call.
An alternative approach would be to distribute the load between registers so
that different functions use different output registers. That would reduce the
odds of conflict, but not eradicate them entirely. It would also add some
difficulty in calling functions; now you have to remember what register they
write their outputs to. It's unclear if the benefits of this alternative
outweigh the costs, so Mu follows long-established conventions in other
Assembly languages. I do, however, violate the `eax` convention in some cases
where a helper function is only narrowly useful in a single sort of
circumstance and registers are at a premium. See, for example, the definition
of the helper `_read-dithering-error` [when rendering images](http://akkartik.github.io/mu/html/511image.mu.html).
The leading underscore indicates that it's an internal detail of
`render-image`, and not really intended to be called by itself.
## Task 10: operating with fractional numbers
All our variables so far have had type `int` (integer), but there are limits

23
tutorial/task9-solution.mu

@ -0,0 +1,23 @@
fn f -> _/eax: int {
return 2
}
fn g -> _/eax: int {
return 3
}
fn add-f-and-g -> _/eax: int {
var _x/eax: int <- f
var x/ecx: int <- copy _x
var y/eax: int <- g
x <- add y
return x
}
fn test-add-f-and-g {
var result/eax: int <- add-f-and-g
check-ints-equal result, 5, "F - test-add-f-and-g\n"
}
fn main {
}

22
tutorial/task9.mu

@ -0,0 +1,22 @@
fn f -> _/eax: int {
return 2
}
fn g -> _/eax: int {
return 3
}
fn add-f-and-g -> _/eax: int {
var x/eax: int <- f
var y/eax: int <- g
x <- add y
return x
}
fn test-add-f-and-g {
var result/eax: int <- add-f-and-g
check-ints-equal result, 5, "F - test-add-f-and-g\n"
}
fn main {
}
Loading…
Cancel
Save