Machine-Level Programming II - Control

Class: CSCE-312


Notes:

Today

Control: Condition codes

Processor State (x86-64, Partial)

...

Condition Codes (Implicit Setting)

Condition Codes (Explicit Setting: cmp)

Explicit Setting by Compare Instruction

Condition Codes (Explicit Setting: test)

Explicit Setting by Test instruction

Reading Condition Codes

SetX Instructions

SetX Condition Description
sete ZF Equal / Zero
setne ~ZF Not Equal / Not Zero
sets SF Negative
setns ~SF Nonnegative
setg ~(SF^OF)&~ZF Greater (Signed)
setge ~(SF^OF) Greater or Equal (Signed)
setl (SF^OF) Less (Signed)
setle (SF^OF)|ZF Less or Equal (Signed)
seta ~CF&~ZF Above (unsigned)
setb CF Below (unsigned)

x86-64 Integer Registers

Pasted image 20250925134713.png|525

Reading Condition Codes (Cont.)

int gt (long x, long y)
{
  return x > y;
}
cmpq   %rsi, %rdi   # Compare x:y
	setg   %al          # Set when >
	movzbl %al, %eax    # Zero rest of %rax
	ret
Register Use(s)
%rdi Argument x
%rsi Argument y
%rax Return value

Conditional branches

Jumping

jX Instructions

jX Condition Description
jmp 1 Unconditional
je ZF Equal / Zero
jne ~ZF Not Equal / Not Zero
js SF Negative
jns ~SF Nonnegative
jg ~(SF^OF)&~ZF Greater (Signed)
jge ~(SF^OF) Greater or Equal (Signed)
jl (SF^OF) Less (Signed)
jle (SF^OF)|ZF Less or Equal (Signed)
ja ~CF&~ZF Above (unsigned)
jb CF Below (unsigned)
Some explanation

Conditional Branch Example (Old Style)

Generation

shark> gcc –Og -S –fno-if-conversion control.c

C code:

long absdiff
  (long x, long y)
{
  long result;
  if (x > y)
    result = x-y;
  else
    result = y-x;
  return result;
}

Assembly code:

absdiff:
   cmpq    %rsi, %rdi  # x:y
   jle     .L4
   movq    %rdi, %rax
   subq    %rsi, %rax
   ret
.L4:       # x <= y
   movq    %rsi, %rax
   subq    %rdi, %rax
   ret
Register Use(s)
%rdi Argument x
%rsi Argument y
%rax Return value

Check pointing:

Expressing with Goto Code

Example:

long absdiff
  (long x, long y)
{
    long result;
    if (x > y)
        result = x-y;
    else
        result = y-x;
    return result;
}

We can rewrite the above function as follows:

long absdiff_j
  (long x, long y)
{
    long result;
    int ntest = x <= y;
    if (ntest) goto Else;
    result = x-y;
    goto Done;
 Else:
    result = y-x;
 Done:
    return result;
}

General Conditional Expression Translation (Using Branches)

C Code

val = Test ? Then_Expr : Else_Expr;
val = x>y ? x-y : y-x;

Goto Version

ntest = !Test;
	if (ntest) goto Else;
	val = Then_Expr;
  goto Done;
Else:
  val = Else_Expr;
Done:
	. . .

Using Conditional Moves

C Code

val = Test 
   ? Then_Expr 
   : Else_Expr;

Goto Version

result = Then_Expr;
  eval = Else_Expr;
  nt = !Test;
  if (nt) result = eval;
  return result;

Conditional Move Example

long absdiff
  (long x, long y)
{
    long result;
    if (x > y)
        result = x-y;
    else
        result = y-x;
    return result;
}
Register Use(s)
%rdi Argument x
%rsi Argument y
%rax Return value
absdiff:
   movq    %rdi, %rax  # x
   subq    %rsi, %rax  # result = x-y
   movq    %rsi, %rdx
   subq    %rdi, %rdx  # eval = y-x
   cmpq    %rsi, %rdi  # x:y
   cmovle  %rdx, %rax  # if <=, result = eval
   ret

Bad Cases for Conditional Move

Expensive Computations

val = Test(x) ? Hard1(x) : Hard2(x);

Risky Computations

val = p ? *p : 0;

Computations with side effects

c

Loops

"Do-While" Loop Example

Three main kind of loops in C++

  1. while
  2. do-while
    • This is actually easier for the compiler to process
  3. for
    • It is the most general, the meaning of loop falls good in it.
    • Because of that generality, it is the most complicated kind of loop for the compiler to reason about

C Code

long pcount_do
  (unsigned long x) {
  long result = 0;
  do {
    result += x & 0x1;
    x >>= 1;
  } while (x);
  return result;
}

Goto Version

long pcount_goto
  (unsigned long x) {
  long result = 0;
 loop:
  result += x & 0x1;
  x >>= 1;
  if(x) goto loop;
  return result;
}

"Do-While" Loop Compilation

Goto Version

long pcount_goto
  (unsigned long x) {
  long result = 0;
 loop:
  result += x & 0x1;
  x >>= 1;
  if(x) goto loop;
  return result;
}
Register Use(s)
%rdi Argument x
%rax result
	 movl    $0, %eax		#  result = 0
.L2:			# loop:
   movq    %rdi, %rdx	
   andl    $1, %edx		#  t = x & 0x1
   addq    %rdx, %rax	#  result += t
   shrq    %rdi		#  x >>= 1
   jne     .L2		#  if (x) goto loop
   rep; ret

General "Do-While" Translation

C Code

do 
  Body
  while (Test);

Goto Verstion:

loop:
  Body
  if (Test)
    goto loop

Body:

{
  Statement1;
  Statement2;
    …
  Statementn;
}

General "While" Translation

While verstion

while (Test)
  Body

Goto Version

  goto test;
loop:
  Body
test:
  if (Test)
    goto loop;
done:

While Loop Example #1

C Code

long pcount_while
  (unsigned long x) {
  long result = 0;
  while (x) {
    result += x & 0x1;
    x >>= 1;
  }
  return result;
}

Jump to Middle

long pcount_goto_jtm
  (unsigned long x) {
  long result = 0;
  goto test;
 loop:
  result += x & 0x1;
  x >>= 1;
 test:
  if(x) goto loop;
  return result;
}

General "While" Translation #2

While version

while (Test)
  Body

Do-While Version

if (!Test) 
    goto done;
  do
    Body
    while(Test);
done:

Goto Version

if (!Test)
    goto done;
loop:
  Body
  if (Test)
    goto loop;
done:

While Loop Example #2

Do-While Version

long pcount_goto_dw
  (unsigned long x) {
  long result = 0;
  if (!x) goto done;
 loop:
  result += x & 0x1;
  x >>= 1;
  if(x) goto loop;
 done:
  return result;
}

"For" Loop Form

General Form

for (Init; Test; Update )
    Body
#define WSIZE 8*sizeof(int)
long pcount_for
  (unsigned long x)
{
  size_t i;
  long result = 0;
  for (i = 0; i < WSIZE; i++)
  {
    unsigned bit = 
      (x >> i) & 0x1;
    result += bit;
  }
  return result;
}

Init

i = 0

Test

i < WSIZE

Update

i++

Body

{
  unsigned bit =
     (x >> i) & 0x1;
  result += bit;
}

"For" Loop -> While Loop

For version

for (Init; Test; Update )
    Body

While Version

Init;
while (Test ) {
    Body
    Update;
}

For-While Conversion

long pcount_for_while
  (unsigned long x)
{
  size_t i;
  long result = 0;
  i = 0;
  while (i < WSIZE)
  {
    unsigned bit = 
      (x >> i) & 0x1;
    result += bit;
    i++;
  }
  return result;
}

"For" Loop Do-While Conversion

C Code

long pcount_for
  (unsigned long x)
{
  size_t i;
  long result = 0;
  for (i = 0; i < WSIZE; i++)
  {
    unsigned bit = 
      (x >> i) & 0x1;
    result += bit;
  }
  return result;
}

Goto Version
Pasted image 20250930134557.png|300

Switch Statements

Switch Statement Example

C code:

long switch_eg
   (long x, long y, long z)
{
    long w = 1;
    switch(x) {
    case 1:
        w = y*z;
        break;
    case 2:
        w = y/z;
        /* Fall Through */
    case 3:
        w += z;
        break;
    case 5:
    case 6:
        w -= z;
        break;
    default:
        w = 2;
    }
    return w;
}

Jump Table Structure

Pasted image 20250930135052.png|625

Switch Statement Exmaple

long switch_eg(long x, long y, long z)
{
    long w = 1;
    switch(x) {
      . . .
    }
    return w;
}

Pasted image 20250930135708.png|250

Setup:

switch_eg:
    movq    %rdx, %rcx
    cmpq    $6, %rdi        # x:6
    ja      .L8             # Use default
    jmp     *.L4(,%rdi,8)   # goto *JTab[x]
Register Use(s)
%rdi Argument x
%rsi Argument y
%rdx Argument z
%rax Return value

Assembly Setup Explanation

Jump Table

Pasted image 20251002125055.png|600

Code Blocks (x == 1)

C code:

switch(x) {
  case 1:	  // .L3
        w = y*z;
        break;
   . . .
}

Assembly code:

.L3:
   movq    %rsi, %rax  # y
   imulq   %rdx, %rax  # y*z
   ret
Register Use(s)
%rdi Argument x
%rsi Argument y
%rdx Argument z
%rax Return value

Handling Fall-Through

Pasted image 20251002125319.png|600

Code Blocks (x == 2, x == 3)

C code:

    long w = 1;
	. . .
    switch(x) {
 	. . .	
    case 2:
        w = y/z;
        /* Fall Through */
    case 3:
        w += z;
        break;
 	. . .
    }

Assembly code:

.L5:                  # Case 2
   movq    %rsi, %rax
   cqto
   idivq   %rcx       #  y/z
   jmp     .L6        #  goto merge
.L9:                  # Case 3
   movl    $1, %eax   #  w = 1
.L6:                  # merge:
   addq    %rcx, %rax #  w += z
   ret
Register Use(s)
%rdi Argument x
%rsi Argument y
%rdx Argument z
%rax Return value

Code Blocks (x == 5, x == 6, default)

C code:

switch(x) {
    . . .
    case 5:  // .L7
    case 6:  // .L7
        w -= z;
        break;
    default: // .L8
        w = 2; 
}

Assembly code:

.L7:               # Case 5,6
  movl  $1, %eax   #  w = 1
  subq  %rdx, %rax #  w -= z
  ret
.L8:               # Default:
  movl  $2, %eax   #  2
  ret
Register Use(s)
%rdi Argument x
%rsi Argument y
%rdx Argument z
%rax Return value

Remember:

Summarizing