From a3f73278b198d0366c590ec8bd7fb8cad5c2931d Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Tue, 26 Oct 2021 23:39:36 -0700 Subject: task: juggling function outputs between registers --- tutorial/index.md | 42 ++++++++++++++++++++++++++++++++++++++++++ tutorial/task9-solution.mu | 23 +++++++++++++++++++++++ tutorial/task9.mu | 22 ++++++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 tutorial/task9-solution.mu create mode 100644 tutorial/task9.mu (limited to 'tutorial') 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 { +} -- cgit 1.4.1-2-gfad0