about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2021-10-26 23:39:36 -0700
committerKartik K. Agaram <vc@akkartik.com>2021-10-26 23:39:36 -0700
commita3f73278b198d0366c590ec8bd7fb8cad5c2931d (patch)
tree1b4868e06faa11a5bd1fc09555afe78d60dfbe8b
parent0ccfd0156f8129df0959b51593bf2a9116e03a37 (diff)
downloadmu-a3f73278b198d0366c590ec8bd7fb8cad5c2931d.tar.gz
task: juggling function outputs between registers
-rw-r--r--511image.mu4
-rw-r--r--tutorial/index.md42
-rw-r--r--tutorial/task9-solution.mu23
-rw-r--r--tutorial/task9.mu22
4 files changed, 89 insertions, 2 deletions
diff --git a/511image.mu b/511image.mu
index f2df9424..8e61183f 100644
--- a/511image.mu
+++ b/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
diff --git a/tutorial/index.md b/tutorial/index.md
index 0967b059..62577a5f 100644
--- a/tutorial/index.md
+++ b/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
diff --git a/tutorial/task9-solution.mu b/tutorial/task9-solution.mu
new file mode 100644
index 00000000..9ecf0ee8
--- /dev/null
+++ b/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 {
+}
diff --git a/tutorial/task9.mu b/tutorial/task9.mu
new file mode 100644
index 00000000..427c420b
--- /dev/null
+++ b/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 {
+}