Procedure Example & Terminology void function1() { int a, b, c, d; IC220 … a = function2(b, c, d); SlideSet #3: Procedures & … } Instruction Representation (Sections 2.8, 2.5, 2.10) int function2(int s, int t, int u) { int x, y, z; … return x; } Big Picture – Steps for Executing a Procedure Step #1: Placement of Parameters 1. Place parameters where the callee procedure can access them • Assigned Registers: • If more than eight are needed? 2. Transfer control to the callee procedure 3. (Maybe) Acquire the storage resources needed for the callee procedure • Parameters are not “saved” across procedure call 4. Callee performs the desired task 5. Place the result somewhere that the “caller” procedure can access it 6. Return control to the point of origin (in caller)
Step #2: Transfer Control to the Procedure Step #3: Acquire storage resources needed by callee • bl – • Suppose callee wants to use registers x20, x21 and x22 – Branches to the procedure address AND links to return address – But caller still expects them to have same value after the call – Solution: • Link saved in register _____ – What exactly is saved? • At start of function call: subi _____,_____, ____ // – Why do we need this? stur x20, [sp, ____ ] // stur x21, [sp, ____ ] // Allows procedure to be called at __________ points in stur x22, [sp, ____ ] // code, _________ times, each having a _________ return address • WARNING: unlike book examples, must move sp in increments of 16 Step #3 Storage Continued Step #4: Callee Execution • Use parameters from _________________ and _________________ (setup by caller) • Temporary storage locations to use for computation: 1. Temporary registers (x9-x15) 2. Argument registers (x0-x7) if… Contents of register Contents of register 3. Other registers Contents of register but… 4. What if still need more?
Step #5: Place result where caller can get it Step #6: Return control to caller – Part A • Part I – Restore appropriate registers before returning from the procedure • Placement of Result (return value) – ldur x22, [sp, #0] // restore x22 for caller – Must place result in appropriate register(s) – ldur x21, [sp, #8] // restore x21 for caller • 64-bit result: – ldur x20, [sp, #16] // restore x20 for caller • More than 64-bit result : – addi sp, sp, ______ // adjust stack to delete our 3 items • Example: desired result currently in x5, then: • Part II – Return to proper location in caller (return address) – Jump to stored address of next instruction after procedure call – Explicit instruction: – Often written with this shorthand (not 100% the same, but almost): EX: 2-31 to 2-32 Recap – Steps for Executing a Procedure Example – putting it all together • Write assembly for the following procedure 1. Place parameters where the callee procedure can access them long dog (long m, long n) { 2. Transfer control to the callee procedure long result = m + n + 7; return result; } 3. (Maybe) Acquire the storage resources needed for the callee procedure 4. Callee performs the desired task • Call this function to compute dog(5, 10): 5. Place the result somewhere that the “caller” procedure can access it 6. Return control to the point of origin (in caller)
Nested Procedures Register Conventions • Register Convention – for “Preserved on Call” registers (like X20): 1. If used, the callee must store and return values for these registers • What if the callee wants to call another procedure – any problems? 2. If not used, not saved • Solution? • This also applies to recursive procedures Nested Procedures Example – putting it all together (again) • “Activation record” – part of stack holding procedures saved values and local variables • Write assembly for the following procedure • FP – points to first word of activation record for procedure (not required; we don’t use it) long cloak (long n) { if (n == 0) return 0; else return (n*n + dagger(n-1)); } • Call this function to compute cloak(6):
long cloak (long n) { Example – putting it all together What does that function do? if (n == 0) return 0; else return (n*n + dagger(n-1)); } cloak: subi sp, sp, #16 stur lr, [sp, #0] stur x0, [sp, #8] long cloak (long n) cbnz x0, Else { mov x0, 0 if (n == 0) return 0; b Exit else return (n*n + dagger(n-1)); Else: } subi x0, x0, #1 bl dagger ldur x10, [sp, #8] mul x10, x10, x10 add x0, x0, x10 Exit: ldur lr, [sp, #0] addi sp, sp, #16 br lr EX: 2-36 to 2-38 Best practices for nested functions Representing Instructions myFunction: subi sp, sp, #16 // 16 or more, always multiple of 16 • Assembly language provides convenient symbolic representation stur lr, [sp, #0] // do this first! – Much easier than writing down numbers // possibly save arguments here // possibly save ‘preserved’ registers here (if using any) – Simplifications, e.g., destination first • Machine language is the underlying reality // body of function (possibly with branches to ‘myFunctionExit’ ... – Each instruction is simply a number, the “machine code” – Realities, e.g., destination is no longer first myFunctionExit: • LEGv8/ARVv8 instructions // possibly reload ‘preserved’ registers’ (f used any) ldur lr, [sp, #0] – Always encoded as 32-bit instruction word addi sp, sp, #16 // must match subi at start! – Small number of formats provide all the details br lr – Registers assigned a 5 bit number – Regularity!
Representing Instructions For reference: hexadecimal review • Base 16 • How does the CPU actually know what to do? – Compact representation of bit strings – 4 bits per hex digit – Often indicated by 0x prefix • What tradeoffs do we have to make? 0 0000 4 0100 8 1000 c 1100 • Why does this work 1 0001 5 0101 9 1001 d 1101 mov x0, 57 2 0010 6 0110 a 1010 e 1110 but not this mov x0, 57000 3 0011 7 0111 b 1011 f 1111 ???? Example: 0xeca8 6420 = 1110 1100 1010 1000 0110 0100 0010 0000 LEGv8 R-format Instructions LEGv8 D-format Instructions • R-format: • Load/store instructions (data transfer) – For instructions involving 3 registers – Rt: destination (load) or source (store) register number – add, adds, subs, and, orr, … – Example: ldur x9, [x10, #240] – Example: add x9, x21, x3 0x7c2 0 opcode address op2 Rn Rt 11 bits 9 bits 2 bits 5 bits 5 bits 0x458 3 0 21 9 • Design Principle 3: Good design demands good opcode Rm shamt Rn Rd compromises 11 bits 5 bits 6 bits 5 bits 5 bits – Different formats complicate decoding, but allow 32-bit instructions uniformly – Keep formats as similar as possible
LEGv8 I-format Instructions LEGv8 Instruction Formats Summary opcode immediate Rn Rd 10 bits 12 bits 5 bits 5 bits • Immediate instructions ( addi, subi, andi, orri, ..) – Immediate = “constant” – Rn: source register – Rd: destination register • Limitations on immediate field – Immediate field is zero-extended – Immediate field has 12 bits • NOTE: this figure (from book) shows all values as DECIMAL, but “green sheet” gives opcodes in HEX (easier to work with) (somewhat obscure detail: actual ARMv8 limits are different because of option to shift the constant by exactly 12 bits) Stored Program Concept Bigger Constants • Most constants are small 1. Instructions represented in binary, – 12-bit immediate is sufficient just like data 2. Instructions and data stored in • For the occasional bigger constant memory MOVZ: move wide with zeros MOVK: move wide with keep Implications: • Both accept 16 bit immediates • Programs can operate on programs – e.g., compilers, linkers, … • And, use with “flexible 2nd operand” (shift) • Binary compatibility allows compiled MOVZ X9,255,LSL 16 programs to work on different computers 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 1111 1111 0000 0000 0000 0000 – Standardized ISAs MOVK X9,255,LSL 0 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 1111 1111 0000 0000 1111 1111
Branch Addressing LEGv8 Addressing Summary • B-type – B 10000 // go to location PC+10000 5 10000 ten 6 bits 26 bits • CB-type – CBNZ X19, Exit // go to Exit if X19 != 0 181 Exit 19 5 bits 8 bits 19 bits • Both addresses are PC-relative – Address = PC + offset (from instruction) LEGv8 Encoding Summary
Recommend
More recommend