NivaarExam PrepOfficial exam papers ↗

25-Comp-A3 Computer Architecture · May 2013

Question 4 of 6: Calling Conventions and Unsigned Arithmetic

Nivaar worked solution (AI-drafted; not reviewed by a licensed engineer)

Notes on this paper

98-Comp-A3, Computer Architecture — National Exams, May 2013. Open-book, 3 hours; six questions of equal value (20 marks each); FIVE constitute a complete exam (all six answered below as a complete study resource).

Reference texts: Patterson & Hennessy, Computer Organization and Design, 6th ed. — instruction encoding & the stored-program principle (Ch.2, Q1), memory addressing & data representation (Ch.2, Q2), cache organization & memory hierarchy (Ch.5, Q3 & Q6), procedure-call conventions & unsigned arithmetic (Ch.2–3, Q4), and CPU performance / the multicycle datapath (Ch.1 & Ch.4, Q5) — covering all six questions.

Question 4: Calling Conventions and Unsigned Arithmetic (20 marks)

Question text not reproduced: the examination questions are © Engineers and Geoscientists BC. Open the official past paper (linked at the top of this page) to read the question, then follow the worked solution below.

Given. A processor with a standard register-based calling convention; unsigned integers A and B on an $n$-bit machine (arithmetic performed modulo $2^n$).

Find. (a) the caller-saved / callee-saved distinction and when each is preferable; (b) the advantage of register-based argument passing and whether ALL arguments can always be passed that way; (c) whether $A+B>A$ and $A-B\lt A$ hold for all unsigned $A,B$.

Approach. (a)/(b) argue from the calling-convention cost tradeoff (who pays the save/restore, and how many physical registers exist); (c) reason from modulo-$2^n$ unsigned arithmetic and construct explicit counterexamples.

  1. Part (a) — caller-saved vs. callee-saved registers. These are two conventions for who is responsible for preserving a register's value across a function call. Caller-saved ("volatile"/scratch registers): the CALLING routine must save the register itself, before the call, if it still needs that value afterward — the callee is free to overwrite these without saving or restoring them. Callee-saved ("preserved" registers): the CALLED routine must save the register on entry and restore it before returning if it uses that register at all — the caller can then rely on those registers holding their pre-call values right after the call, at no effort of its own.
    When is one better? Caller-saved is cheaper for values that are short-lived and NOT needed after most calls — the (common) caller with no live value in that register pays nothing, whereas a callee-saved convention would force every callee touching the register to save/restore even when no caller ever needed the old value kept. Callee-saved is cheaper for values that stay live across MANY calls (loop counters, frame/base pointers) — one save/restore in the single callee that uses the register beats every caller along the chain saving it before every call it makes.
  2. Part (b) — register vs. stack argument passing. Passing arguments in registers avoids a store-then-load round trip through memory on every call: the callee reads its arguments straight out of registers instead of computing stack-frame offsets and issuing memory operations — fewer instructions and lower latency (no memory/cache access on the argument path), which matters most for small, frequently-called (e.g. leaf) functions where argument setup is a large fraction of total call cost.
    Can ALL arguments always be passed through registers? No. A processor reserves only a small, fixed number of argument registers (real ISAs typically 4–8), so a call with more arguments than that has nowhere left but the stack for the excess. Variadic functions (argument count not fixed at compile time) and large aggregates/structs passed by value (bigger than one register, or than all remaining argument registers combined) also cannot be fully register-resident. Real calling conventions therefore use a hybrid rule: the first few scalar arguments go in registers, everything beyond that — or anything too large — goes on the stack.
  3. Part (c) — is $A+B>A$ always true? Is $A-B\lt A$ always true? Neither holds unconditionally, for two independent reasons.
    Trivial counterexample (no overflow needed): if $B=0$, then $A+B=A$ (not $>A$) and $A-B=A$ (not $ Overflow/underflow counterexample: unsigned arithmetic on an $n$-bit machine is arithmetic modulo $2^n$. Take $n=32$, $A=2^{32}-1$ (all bits 1), $B=1$: the sum wraps, $$A+B=2^{32}\equiv 0\pmod{2^{32}},$$ which is far less than $A$, so $A+B>A$ is false. Symmetrically, take $A=0$, $B=1$: the difference underflows, $$A-B=-1\equiv 2^{32}-1\pmod{2^{32}},$$ a huge unsigned value, far greater than $A=0$, so $A-B\lt A$ is also false. $$\boxed{\text{Neither } A+B>A \text{ nor } A-B\lt A \text{ holds for all unsigned } A,B.}$$ This is exactly why unsigned add/subtract instructions expose a hardware carry/borrow flag — software must test that flag (not just re-compare the numeric result) to detect unsigned overflow or underflow.
Final results — Question 4
PartResult
(a) caller- vs. callee-savedcaller-saved best for short-lived values; callee-saved best for values live across many calls
(b) register argsfaster (no memory round trip); NOT all args can always be register-resident (limited arg registers, varargs, large aggregates)
(c) $A+B>A$, $A-B\lt A$Both FALSE in general — fail at $B=0$ and under modulo-$2^n$ wraparound