Conditionals and Control Flow Two key pieces 1. Comparisons and tests: check conditions 2. Transfer control: choose next instruction Control flow Processor Control-Flow State Familiar C constructs Condition codes (a.k.a. flags ) if else l 1-bit registers hold flags set by last ALU operation while l ZF do while Zero Flag result == 0 l for l Condition codes SF Sign Flag result < 0 break l Conditional and unconditional jumps Carry Flag carry-out/unsigned overflow CF continue l Loops Overflow Flag two's complement overflow OF Switch statements Instruction pointer %rip (a.k.a. program counter ) register holds address of next instruction to execute 1 2 ex 1. compare and test : conditions Aside: save conditions b,a computes a - b , sets flags, discards result cmpq setg: set if greater long gt(int x, int y) { return x > y; stores byte: 0x01 if ~(SF^OF)&~ZF } Which flags indicate that a < b ? (signed? unsigned?) 0x00 otherwise cmpq %rdi,%rsi # compare: x – y setg %al # al = x > y testq b,a computes a & b , sets flags, discards result movzbq %al,%rax # zero rest of %rax Common pattern: Z ero-extend from B yte (8 bits) to Q uadword (64 bits) testq %rax, %rax What do ZF and SF indicate? %rax %eax %ah %al 3 4
2. jump : choose next instruction Jump for control flow Jump/branch to different part of code by setting %eip . Jump immediately follows comparison/test. Together, they make a decision: "if %rax = %rcx , jump to label." j__ Condition Description Always jump jmp 1 Unconditional cmpq %rax,%rcx Equal / Zero je ZF je label Not Equal / Not Zero jne ~ZF … js SF Negative Executed only if … Nonnegative jns ~SF %rax ≠ %rcx … jg ~(SF^OF)&~ZF Greater (Signed) Jump iff condition label: addq %rdx,%rax Greater or Equal (Signed) jge ~(SF^OF) jl (SF^OF) Less (Signed) Label Less or Equal (Signed) jle (SF^OF)|ZF Name for address of Above (unsigned) ja ~CF&~ZF following item. jb CF Below (unsigned) 6 7 Introduced by Fran Allen, et al. Conditional Branch Example Control-Flow Graph Won the 2006 Turing Award for her work on compilers. Code flowchart/directed graph. long absdiff(long x,long y) { long result; long absdiff(long x, long y){ if (x > y) { Nodes = Basic Blocks : long result; result = x-y; Straight-line code always if (x > y) { absdiff: } else { executed together in order. result = x-y; cmpq %rsi, %rdi result = y-x; } else { jle .L7 } subq %rsi, %rdi result = y-x; return result; movq %rdi, %rax } long result; } .L8: return result; if (x > y) else retq } Labels then else .L7: Name for address of subq %rdi, %rsi Edges = Control Flow : jmp .L8 following item. result = y-x; result = x-y; Which basic block executes next (under what condition). return result; How did the compiler create this? 8
Choose a linear order of basic blocks. Translate basic blocks with jumps + labels long result; long result; long result; if (!(x > y)) if (x > y) else if (!(x > y)) cmpq %rsi, %rdi then else else then jle Else result = x-y; result = x-y; result = y-x; subq %rsi, %rdi movq %rdi, %rax return result; End: result = y-x; result = x-y; retq Else: result = y-x; return result; return result; subq %rdi, %rsi movq %rsi, %rax jmp End Why might the compiler choose this basic block order instead of another valid order? ex ex Execute absdiff compile if-else Registers cmpq %rsi, %rdi %rax long wacky(long x, long y){ jle Else int result; %rdi if (x + y > 7) { subq %rsi, %rdi result = x; movq %rdi, %rax %rsi } else { End: result = y + 2; retq } return result; Else: } subq %rdi, %rsi Assume x available in %rdi , movq %rsi, %rax y available in %rsi . jmp End Place result in %rax . 13
Compiling Loops do while loop example long result = 1; C/Java code: Machine code: C Code loopTop: testq %rax, %rax while ( sum != 0 ) { long fact_do(long x) { je loopDone <loop body> long result = 1; result = result*x; <loop body code> } do { x = x-1; jmp loopTop result = result * x; loopDone: x = x-1; } while (x > 1); (x > 1) ? return result; Yes } No Compilation of other loops should be straightforward return result; Interesting part: put the conditional branch at top or bottom of loop? Keys: • Use backward branch to continue looping • Only take branch when “while” condition holds 20 21 Why? do while loop translation while loop translation C Code Register Variable long fact_while(long x){ %rdi long result = 1; long result = 1; Assembly long result = 1; %rax while (x > 1) { result = result * x; fact_do: x = x-1; movq $1,%rax } result = result*x; result = result*x; return result; .L11: x = x-1; x = x-1; } imulq %rdi,%rax decq %rdi long result = 1; cmpq $1,%rdi (x > 1) ? jg .L11 (x > 1) ? Yes Yes No No (x > 1) ? retq Yes No return result; return result; result = result*x; x = x-1; Why? This order is used by GCC for x86-64 return result; Why put the loop condition at the end? 22 23
for loop translation For Version while loop example for ( Initialize ; Test ; Update ) Body for ( result = 1 ; p != 0 ; p = p>>1 ) { int fact_while(int x) { movq $1, %rax if (p & 0x1) { While Version int result = 1; jmp .L34 result = result * x; Initialize ; while (x > 1) { .L35: } while ( Test ) { result = result * x; imulq %rdi, %rax x = x*x; Body ; } x = x - 1; decq %rdi Update ; }; .L34: } return result; cmpq $1, %rdi } jg .L35 result = 1; Initialize if (p & 0x1) { int result = 1; result = result*x; } Body result = result*x; x = x*x; Update p = p>>1; x = x-1; Test ? Yes (x > 1) ? No Yes (p != 0) ? No Yes No return result; 25 31 (Aside) Conditional Move (Aside) Bad Cases for Conditional Move Expensive Computations cmov src, dest if ( Test ) Dest ß Src Why? Branch prediction in pipelined/OoO processors. val = Test(x) ? Hard1(x) : Hard2(x); long absdiff(long x, long y) { long absdiff(long x, long y) { return x>y ? x-y : y-x; long result; } if (x>y) { Risky Computations result = x-y; } else { val = p ? *p : 0; result = y-x; } } absdiff: movq %rdi, %rax # x Computations with side effects subq %rsi, %rax # result = x-y movq %rsi, %rdx val = x > 0 ? x*=7 : x+=3; subq %rdi, %rdx # else_val = y-x cmpq %rsi, %rdi # x:y cmovle %rdx, %rax # if <=, result = else_val ret 35 36
switch statements Jump Table Structure long switch_eg (unsigned long x, long y, long z) { Memory C code: long w = 1; switch(x) { switch(x) { case 1: case 1: <some code> w = y*z; break; break; Fall through cases case 2: <some code> case 2: case 3: <some code> Code w = y/z; break; Blocks /* Fall Through */ Missing cases case 5: case 3: case 6: <some code> w += z; break; break; Multiple case labels default: <some code> case 5: } case 6: We can use the jump table when x <= 6: w -= z; 6 break; 5 Lots to manage, if (x <= 6) 4 default: target = JTab[x]; let's use a jump table 3 w = 2; goto target; 2 } else 1 Jump return w; 0 goto default; Table } 37 38 ex switch statement example Jump Table declaring data, not instructions 8-byte memory alignment long switch_eg(long x, long y, long z) { Jump table long w = 1; .section .rodata switch(x) { switch(x) { .align 8 case 1: // .L56 . . . .L4: w = y*z; } .quad .L8 # x = 0 break; return w; Jump table .quad .L3 # x = 1 case 2: // .L57 } .quad .L5 # x = 2 w = y/z; .section .rodata but this is signed... .align 8 .quad .L9 # x = 3 /* Fall Through */ .L4: Jump if above .quad .L8 # x = 4 case 3: // .L58 .quad .L8 # x = 0 (like jg, but .quad .L7 # x = 5 w += z; switch_eg: .quad .L3 # x = 1 unsigned) movq %rdx, %rcx .quad .L7 # x = 6 break; .quad .L5 # x = 2 .quad .L9 # x = 3 case 5: cmpq $6, %rdi .quad .L8 # x = 4 Indirect ja .L8 case 6: // .L60 .quad .L7 # x = 5 jump w -= z; jmp *.L4(,%rdi,8) .quad .L7 # x = 6 “quad” as in 4 1978-era 16-bit words break; default: // .L61 w = 2; } 39 40
Recommend
More recommend