x86 CONTROLLING PROGRAM FLOW
CONTROL FLOW Computers execute instructions in sequence... ...Except when we change the flow of control. Two main ways of doing this: ▸ “Jump” instructions (this lecture) ▹ “Call” instructions (future lecture) ▹ 2
JUMP INSTRUCTIONS Types Unconditional jumps ▸ Direct jump: jmp Label ▹ Jump target is specified by a label (e.g., jmp .L1 ) ▹ Indirect jump: jmp *Operand ▹ Jump target is specified by a register or memory location ▹ (e.g., jmp *%rax ) Conditional jumps ▸ Only jump if a certain condition is true ▹ 3
RECALL CONDITIONAL STATEMENTS IN C C expressions within, if, for, and while statements: if (x) {…} else {…} while (x) {…} do {…} while (x) for (i=0; i<max; i++) {…} switch (x) { case 1: … case 2: … } 4
MAPPING TO THE CPU Processor flag register eflags (extended flags) Flags are set or cleared by depending on the result of an instruction Each bit is a flag, or condition code: CF Carry Flag SF Sign Flag ZF Zero Flag OF Overflow Flag 5
IMPLICIT SETTING Automatically Set By Arithmetic and Logical Operations Example: addq Src, Dest CF (for unsigned integers) ▸ set if carry out from most significant bit (unsigned overflow) ▹ (unsigned long t) < (unsigned long a) ▹ ZF (zero flag) ▸ Set if t == 0 ▹ SF (Signed integers) ▸ Set if t < 0 ▹ OF (Signed integers) ▸ Set if signed (two’s complement) overflow ▹ ▹ (a>0 && b>0 && t<0) || (a<0 && b<0 && t>=0) Not set by lea, push, pop, mov instructions 6
EXPLICIT SETTING VIA COMPARE Setting condition codes via compare instruction: Example: cmpq b, a Computes a - b without setting destination ▸ CF set if carry out from most significant bit ▸ Used for unsigned comparisons ▹ ZF set if a == b ▸ SF set if (a-b) < 0 ▸ OF set if two’s complement (signed) overflow ▸ (a>0 && b<0 && (a-b)<0) || (a<0 && b>0 && (a-b)>0) Byte, word, and double word versions: cmpb, cmpw, cmpl ▸ 7
EXPLICIT SETTING VIA TEST Setting condition codes via test instruction: Example: testq b, a Computes a & b without setting destination ▸ Sets condition codes based on result ▹ Useful to have one of the operands be a mask ▹ Often used to test if a register is zero or positive ▸ ▹ testq %rax, %rax ZF set when a & b == 0 ▸ SF set when a & b < 0 ▸ Byte, word and double word versions: testb, testw, testl ▸ 8
CONDITIONAL JUMP INSTRUCTIONS Jump to different part of code based on condition codes: Instruction - jxx Condition Description jmp 1 Unconditional / Always Jump je, jz ZF Equal / Zero jne ~ZF Not Equal / Not Zero js SF Negative jns ~SF Non-Negative jg ~(SF^OF) && ~ZF Greater (Signed) jge ~(SF^OF) Greater or Equal (Signed) jl (SF^OF) Less (Signed, Overflow Flips Result) jle ~(SF^OF) || ZF Less or Equal (Signed) ja ~CF && ~ZF Above (Unsigned) jb CF Below (Unsigned) 9
COMPARE/JUMP EXAMPLE “ When compared to the decimal number 4, what is %rdx ? ” mySampleFunction: movq $5, %rdx cmp $4, %rdx “ If %rdx is LESS THAN 4, jl .lessthan jump here. ” jmp .greaterthanorequal ( “ Otherwise, ignore me ” ) .greaterthanorequal: movq $999, %rax jmp .done “ If %rdx is GREATER THAN OR EQUAL TO 4, jump here. ” .lessthan: ( “ Otherwise, ignore me ” ) movq $111, %rax jmp .done .done: ret 10
CONDITIONAL JUMP EXAMPLE This example assumes a non-optimized compilation: gcc –Og -S –fno-if-conversion control.c 11
GENERAL CONDITIONAL EXPRESSION TRANSLATION (USING BRANCHES) Consider the following ternary expression: val = Test ? Then_Expr : Else_Expr; val = x>y ? x-y : y-x ; In a “goto” form: if (!Test) goto Else val = Then_Expr; goto done; Create separate code regions for “then” & “else” expressions Else: val = Else_Expr; Execute the appropriate one Done: ... 12
PRACTICE PROBLEM 3.18 /* x in %rdi, y in %rsi, z in %rdx */ long test(long x, long y, long z) test: { leaq (%rdi,%rsi), %rax x + y + z addq %rdx, %rax long val = ____________ ; cmpq $-3, %rdi x < -3 jge .L2 if ( ____________ ) cmpq %rdx,%rsi { jge .L3 y < z movq %rdi, %rax if ( ____________ ) imulq %rsi, %rax x * y ret val = ____________ ; .L3: movq %rsi, %rax else imulq %rdx, %rax y * z ret val = ____________ ; .L2: cmpq $2, %rdi } x > 2 jle .L4 else if ( ____________ ) movq %rdi, %rax x * z imulq %rdx, %rax val = ____________ ; .L4: ret return val; 13 }
CPU PIPELINING Fetch Decode Execute Write-Back 14
AVOIDING CONDITIONAL BRANCHES Modern CPUs have deep pipelines Instructions fetched far in advance of execution to mask latency going to ▸ memory Problem: What if you hit a conditional branch? ▸ Must stall or predict which branch to take! ▹ Branch prediction in CPUs well-studied, fairly effective ▹ But, best to avoid conditional branching altogether ▹ 15
CONDITIONAL MOVES cmovXX Src, Dest - “Move value from src to dest if condition XX holds” Conditional execution handled within data execution unit ▸ Avoids stalling control unit with a conditional branch ▸ Added with P6 microarchitecture (PentiumPro onward, 1995) ▸ Example: # %rdi = x, %rsi = y, return value in %rax # returns max(x,y) movq %rdi, %rdx # Get x movq %rsi, %rax # rval=y (assume y) cmpq %rdx, %rax # x:y cmovl %rdx, %rax # If y < x, rval=x Performance: 14 cycles on all data ▸ Single control flow path ▸ But … overhead. Both branches are evaluated! ▸ 16
GENERAL CONDITIONAL EXPRESSION TRANSLATION (USING CMOVE) Conditional Move template instruction supports: if (Test), Dest ← Src ▸ GCC attempts to restructure execution to avoid disruptive val = Test ? Then_Expr : Else_Expr; conditional branch Both values computed result = Then_Expr; ▸ Overwrite “then” value with ▸ eval = Else_Expr; “else” value if condition doesn’t hold if (!test) result = eval; return result; 17
CONDITIONAL MOVE EXAMPLE 18
PRACTICE PROBLEM 3.21 /* x in %rdi, y in %rsi */ long test(long x, long y) { test: 8 * x long val = ____________ ; leaq 0(,%rdi,8), %rax testq %rsi, %rsi y > 0 if ( ____________ ) jle .L2 { movq %rsi, %rax x < y if ( ____________ ) subq %rdi, %rax movq %rdi, %rdx y - x val = ____________ ; andq %rsi, %rdx cmpq %rsi, %rdi else cmovge %rdx, %rax x & y ret val = ____________ ; } .L2: y <= -2 else if ( ____________ ) addq %rsi, %rdi x + y cmpq $-2, %rsi val = ____________ ; cmovle %rdi, %rax return val; ret 19 }
WHEN NOT TO USE CONDITIONAL MOVES Expensive Computations: val = Test(x) ? Hard_Function1(x) : Hard_Function2(x); Both Hard_Function1(x) and Hard_Function2(x) are computed ▸ Use branching when “then” and “else” expressions are more expensive than ▸ branch misprediction Computations with Side Effects: val = x > 0 ? x *= 7 : x += 3; Executing both values causes incorrect behavior ▸ Conditional Checks that Protect Against Fault e.g. Null pointer check 20 ▸
LOOPS Implemented in assembly via tests and jumps Compilers try to implement most loops as do-while ▸ do { // Things to do } while (test-expr); 21
ARE THESE EQUIVALENT? A Do-While Loop A While-Do Loop long factorial_do( long x) long factorial_while( long x) { { long result = 1; long result = 1; do while (x > 1) { { result *= x; result *= x; x = x-1; x = x-1; } while (x > 1); } return result; return result; } } 22
ARE THESE EQUIVALENT? A Do-While Loop A While-Do Loop long factorial_do( long x) long factorial_while( long x) { { long result = 1; long result = 1; do while (x > 1) { { result *= x; result *= x; x = x-1; x = x-1; } while (x > 1); } return result; return result; } } factorial_while: factorial_do: movq $1, %rax movq $1, %rax jmp .L2 .L3: .L2: imulq %rdi, %rax imulq %rdi, %rax subq $1, %rdi subq $1, %rdi .L2: cmpq $1, %rdi cmpq $1, %rdi jg .L2 jg .L3 ret 23 ret
FOR-LOOP EXAMPLE long factorial_for( long x) { long result; Recall, for-loops are in the following format: for (result=1; x > 1; x=x-1) { for ( init ; test ; update ) result *= x; { //loop body } } return result; } Init Test Update result = 1; x > 1; x = x - 1; Loop Body: result *= x; Is this code equivalent to the do-while version? Or the while-do version? 24
PRACTICE PROBLEM 3.26 fun_a: long fun_a(long x, long y) { movq $0, %rax jmp .L5 long val = 0; .L6: xorq %rdi, %rax x while (_________) shrq $1, %rdi { .L5: val = val ^ x; ____________________; testq %rdi, %rdi jne .L6 x = x >> 1 ____________________; andq $1, %rax ret } val & 0x1 return _______________; } 25
long switch_eg( long x) C SWITCH STATEMENTS { long result = x; switch (x) { case 100: result *= 13; Test whether an expression matches break ; one of a number of constant integer values and branches accordingly case 102: result += 10; /* Fall through */ Without a “break” the code falls through to the next case case 103: result += 11; break ; If x matches no case, then “default” is executed case 104: case 106: result *= result; break ; default : result = 0; } return result; } 26
Recommend
More recommend