# Comparison Instructions

Comparison instructions can be arithmetic:

 a < b a > b a <= b a >= b a == b a != b
or logical:
 a && b a || b
We may also assert: if (a) ... meaning if (a!=0) ...
or if (!a) ... meaning if (a==0) ...

The MIPS instructions for comparison are variations on SLT (Set output 1 if Rs < Rt, else set output 0).

As shown in the table below the instruction may do a signed or an unsigned comparision and the second argument may be either a register or an immediate operand.

Instruction Description Function
SLT Set on Less Than
```if (int)Rs < (int)Rt
Rd = 1
else
Rd = 0
```
SLTI Set on Less Than Immediate
```if (int)Rs < (int)Immed
Rt = 1
else
Rt = 0
```
SLTIU Set on Less Than Immediate Unsigned
```if (uns)Rs < (uns)Immed
Rt = 1
else
Rt = 0
```
SLTU Set on Less Than Unsigned
```if (uns)Rs < (uns)Immed
Rd = 1
else
Rd = 0
```

### preface

```28:void compare(int a, int b)
29:{
sw          s8,56(sp)
sw          a0,64(s8)    M[s8+64] = a0 = a
sw          a1,68(s8)    M[s8+68] = a1 = b
```

### a > b

```34:	is_gt = a>b;
lw          v1,64(s8)    v1 = a
lw          v0,68(s8)    v0 = b
slt         v0,v0,v1     v0 = (b<a? 1: 0)
```
We are testing b < a, which is equivalent to a > b.
```   sw          v0,0(s8)     M[s8+0] (is_gt) = v0
```

From now on we will not show the instruction which stores the result to memory.

### a < b

```35:	is_lt = a<b;
lw          v1,64(s8)    v1 = a
lw          v0,68(s8)    v0 = b
slt         v0,v1,v0     v0 = (a<b? 1: 0)
```

Note that the arguments in slt are reversed from the previous case.

### a >= b

The logic used by the compiler is that a is not less than b.

```36:	is_ge = a>=b;
lw          v1,64(s8)    v1 = a
lw          v0,68(s8)    v0 = b
slt         v0,v1,v0     v0 = (a<b? 1: 0)
xori        v0,v0,0x1    v0 = ~v0
```

Note that v0 = ~v0, for one bit, is the same as v0 = NOT v0

### a >= b

The logic used by the compiler is that a is not greater than b.

```37:	is_le = a<=b;
lw          v1,64(s8)    v1 = a
lw          v0,68(s8)    v0 = b
slt         v0,v0,v1     v0 = (b<a? 1: 0)
xori        v0,v0,0x1    v0 = ~v0
```

### a == b

This computation is based on the observation that xor(a,b) is zero if a and b are identical and non-zero otherwise.

```42:	is_eq = a==b;
lw          v1,64(s8)    v1 = a
lw          v0,68(s8)    v0 = b
xor         v0,v1,v0     v0 = a^b
sltiu       v0,v0,1      v0 = (v0<1? 1: 0)
```

Treating v0 as unsigned means that any bit combination will not be less than one.

### a != b

```43:	is_ne = a!=b;
lw          v1,64(s8)    v1 = a
lw          v0,68(s8)    v0 = b
xor         v0,v1,v0     v0 = a^b
sltu        v0,zero,v0   v0 = (zero<v0? 1: 0)
```

### a > 0

```45:	a_gt_0 = a>0;
lw          v1,64(s8)    v1 = a
slti        v0,v0,1      v0 = (v0<1? 1: 0)
xori        v0,v0,0x1    v0 = ~v0
```

### a == 0

```46:	a_eq_0 = a==0;
lw          v1,64(s8)    v1 = a
xori        v0,v0,0x0    This instruction does nothing!
sltiu       v0,v0,1      test whether v0 is zero
```

### !a

This tests (a == 0) using exactly the same instructions as above.

```48:	is_not_a = !a;
lw          v1,64(s8)    v1 = a
xori        v0,v0,0x0    This instruction does nothing!
sltiu       v0,v0,1      test whether v0 is zero
```

### !!a

Test (a!=0). There are no superfluous instructions here!

```47:	is_a = !!a;
lw          v1,64(s8)    v1 = a
sltu        v0,zero,v0   v0 = (zero<v0? 1: 0)
sw          v0,40(s8)
sw          v0,44(s8)
```

### a && b

The calculation uses branch operations. It starts by assuming the operation fails and stores zero into the temporary location M[s8+48]. Then it tests a: if the value is zero, the result is zero no matter the value of b. Otherwise it tests if b is zero. If not, it sets the output to one.

```39:	is_and = a&&b;
sw          zero,48(s8)
lw          v0,64(s8)
beq         v0,zero,d
nop
lw          v0,68(s8)
beq         v0,zero,d
nop
sw          v0,48(s8)
d: lw          v0,48(s8)
sw          v0,24(s8)       save final result
```

### a||b

The technique here is similar, using DeMorgan's theorem:

a||b = ! ((!a) && (!b)) A temporary memory location is set to zero. If a is non-zero the result is set to one, no matter what b is. Otherwise it checks b. If that is non-zero, the result is set to one.
```40:	is_or = a||b;
sw          zero,52(s8)
lw          v0,64(s8)
bne         v0,zero,s
nop
lw          v0,68(s8)
bne         v0,zero,s
nop
beq         zero,zero,d   unconditional branch
nop
sw          v0,52(s8)
d: lw          v0,52(s8)
sw          v0,28(s8)
```

### Contents

C Source
Results (Microsoft C)
Disassembly Listing

## C Source

```01: // comment the following line to enable Microsoft C
02: #define PIC32
03: #if defined(PIC32)
04: #include <p32xxxx.h>
05:         // comment the following line to enable debug output
06: #define UART2_IO
07: #include "db_utils.h"
08: #else // Microsoft C
09: #include <stdio.h>
10: #define DBPRINTF printf
11: #define DBPUTS(s)
12: #endif
13:
14: void compare(int a, int b);
15:
16: int main()
17: {
18:         compare(5,3);
19:         compare(-2,7);
20:         compare(3,3);
21:         compare(0,0);
22:
23:
24:         DBPUTS("Program terminated. Click HALT and then RESET to stop the microcontroller. \n");
25:         return 0;
26: }
27:
28: void compare(int a, int b)
29: {
30:         int is_gt, is_lt, is_ge, is_le;
31:         int is_eq, is_ne, is_and, is_or;
32:         int a_gt_0, a_eq_0, is_a, is_not_a;
33:
34:         is_gt = a>b;
35:         is_lt = a<b;
36:         is_ge = a>=b;
37:         is_le = a<=b;
38:
39:         is_and = a&&b;
40:         is_or = a||b;
41:
42:         is_eq = a==b;
43:         is_ne = a!=b;
44:
45:         a_gt_0 = a>0;
46:         a_eq_0 = a==0;
47:         is_a = !!a;
48:         is_not_a = !a;
49:
50:         DBPRINTF("\na = %d compared to b = %d\n",a,b);
51:         DBPRINTF("is_gt %d is_lt %d is_ge %d is_le %d\n",is_gt,is_lt,is_ge,is_le);
52:         DBPRINTF("is_eq %d is_ne %d is_and %d is_or %d\n",is_eq,is_ne,is_and,is_or);
53:         DBPRINTF("a_gt_0 %d a_eq_0 %d is_a %d is_not_a %d\n",a_gt_0,a_eq_0,is_a,is_not_a);
54:
55: }
```

## Results

We can run this program on Microsoft C after commenting the first line of the program. The output was redirected to a file, included below. It shows that the logical expressions return either one or zero.

```a = 5 compared to b = 3
is_gt 1 is_lt 0 is_ge 1 is_le 0
is_eq 0 is_ne 1 is_and 1 is_or 1
a_gt_0 1 a_eq_0 0 is_a 1 is_not_a 0

a = -2 compared to b = 7
is_gt 0 is_lt 1 is_ge 0 is_le 1
is_eq 0 is_ne 1 is_and 1 is_or 1
a_gt_0 0 a_eq_0 0 is_a 1 is_not_a 0

a = 3 compared to b = 3
is_gt 0 is_lt 0 is_ge 1 is_le 1
is_eq 1 is_ne 0 is_and 1 is_or 1
a_gt_0 1 a_eq_0 0 is_a 1 is_not_a 0

a = 0 compared to b = 0
is_gt 0 is_lt 0 is_ge 1 is_le 1
is_eq 1 is_ne 0 is_and 0 is_or 0
a_gt_0 0 a_eq_0 1 is_a 0 is_not_a 1
```

## Disassembly Listing

```---  C:\pic32\test\compare.c  --------------------------------------------------------------------
1:                   // comment the following line to enable Microsoft C
2:                   #define PIC32
3:                   #if defined(PIC32)
4:                   #include <p32xxxx.h>
5:                   	// comment the following line to enable debug output
6:                   #define UART2_IO
7:                   #include "db_utils.h"
8:                   #else // Microsoft C
9:                   #include <stdio.h>
10:                  #define DBPRINTF printf
11:                  #define DBPUTS(s)
12:                  #endif
13:
14:                  void compare(int a, int b);
15:
16:                  int main()
17:                  {
9D00001C  AFBF0014   sw          ra,20(sp)
9D000020  AFBE0010   sw          s8,16(sp)
18:                  	compare(5,3);
9D000030  0F400021   jal         0x9d000084
9D000034  00000000   nop
19:                  	compare(-2,7);
9D000040  0F400021   jal         0x9d000084
9D000044  00000000   nop
20:                  	compare(3,3);
9D000050  0F400021   jal         0x9d000084
9D000054  00000000   nop
21:                  	compare(0,0);
9D000060  0F400021   jal         0x9d000084
9D000064  00000000   nop
22:
23:
24:                  	DBPUTS("Program terminated. Click HALT and then RESET to stop the microcontroller. \n");
25:                  	return 0;
26:                  }
9D000070  8FBF0014   lw          ra,20(sp)
9D000074  8FBE0010   lw          s8,16(sp)
9D00007C  03E00008   jr          ra
9D000080  00000000   nop
27:
28:                  void compare(int a, int b)
29:                  {
9D000088  AFBE0038   sw          s8,56(sp)
9D000090  AFC40040   sw          a0,64(s8)
9D000094  AFC50044   sw          a1,68(s8)
30:                  	int is_gt, is_lt, is_ge, is_le;
31:                  	int is_eq, is_ne, is_and, is_or;
32:                  	int a_gt_0, a_eq_0, is_a, is_not_a;
33:
34:                  	is_gt = a>b;
9D000098  8FC30040   lw          v1,64(s8)
9D00009C  8FC20044   lw          v0,68(s8)
9D0000A0  0043102A   slt         v0,v0,v1
9D0000A4  AFC20000   sw          v0,0(s8)
35:                  	is_lt = a<b;
9D0000A8  8FC30040   lw          v1,64(s8)
9D0000AC  8FC20044   lw          v0,68(s8)
9D0000B0  0062102A   slt         v0,v1,v0
9D0000B4  AFC20004   sw          v0,4(s8)
36:                  	is_ge = a>=b;
9D0000B8  8FC30040   lw          v1,64(s8)
9D0000BC  8FC20044   lw          v0,68(s8)
9D0000C0  0062102A   slt         v0,v1,v0
9D0000C4  38420001   xori        v0,v0,0x1
9D0000C8  AFC20008   sw          v0,8(s8)
37:                  	is_le = a<=b;
9D0000CC  8FC30040   lw          v1,64(s8)
9D0000D0  8FC20044   lw          v0,68(s8)
9D0000D4  0043102A   slt         v0,v0,v1
9D0000D8  38420001   xori        v0,v0,0x1
9D0000DC  AFC2000C   sw          v0,12(s8)
38:
39:                  	is_and = a&&b;
9D0000E0  AFC00030   sw          zero,48(s8)
9D0000E4  8FC20040   lw          v0,64(s8)
9D0000E8  10400006   beq         v0,zero,0x9d000104
9D0000EC  00000000   nop
9D0000F0  8FC20044   lw          v0,68(s8)
9D0000F4  10400003   beq         v0,zero,0x9d000104
9D0000F8  00000000   nop
9D000100  AFC20030   sw          v0,48(s8)
9D000104  8FC20030   lw          v0,48(s8)
9D000108  AFC20018   sw          v0,24(s8)
40:                  	is_or = a||b;
9D00010C  AFC00034   sw          zero,52(s8)
9D000110  8FC20040   lw          v0,64(s8)
9D000114  14400006   bne         v0,zero,0x9d000130
9D000118  00000000   nop
9D00011C  8FC20044   lw          v0,68(s8)
9D000120  14400003   bne         v0,zero,0x9d000130
9D000124  00000000   nop
9D000128  10000003   beq         zero,zero,0x9d000138
9D00012C  00000000   nop
9D000134  AFC20034   sw          v0,52(s8)
9D000138  8FC20034   lw          v0,52(s8)
9D00013C  AFC2001C   sw          v0,28(s8)
41:
42:                  	is_eq = a==b;
9D000140  8FC30040   lw          v1,64(s8)
9D000144  8FC20044   lw          v0,68(s8)
9D000148  00621026   xor         v0,v1,v0
9D00014C  2C420001   sltiu       v0,v0,1
9D000150  AFC20010   sw          v0,16(s8)
43:                  	is_ne = a!=b;
9D000154  8FC30040   lw          v1,64(s8)
9D000158  8FC20044   lw          v0,68(s8)
9D00015C  00621026   xor         v0,v1,v0
9D000160  0002102B   sltu        v0,zero,v0
9D000164  AFC20014   sw          v0,20(s8)
44:
45:                  	a_gt_0 = a>0;
9D000168  8FC20040   lw          v0,64(s8)
9D00016C  28420001   slti        v0,v0,1
9D000170  38420001   xori        v0,v0,0x1
9D000174  AFC20020   sw          v0,32(s8)
46:                  	a_eq_0 = a==0;
9D000178  8FC20040   lw          v0,64(s8)
9D00017C  38420000   xori        v0,v0,0x0
9D000180  2C420001   sltiu       v0,v0,1
9D000184  AFC20024   sw          v0,36(s8)
47:                  	is_a = !!a;
9D000188  8FC20040   lw          v0,64(s8)
9D00018C  0002102B   sltu        v0,zero,v0
9D000190  AFC20028   sw          v0,40(s8)
48:                  	is_not_a = !a;
9D000194  8FC20040   lw          v0,64(s8)
9D000198  38420000   xori        v0,v0,0x0
9D00019C  2C420001   sltiu       v0,v0,1
9D0001A0  AFC2002C   sw          v0,44(s8)
49:
50:                  	DBPRINTF("\na = %d compared to b = %d\n",a,b);
51:                  	DBPRINTF("is_gt %d is_lt %d is_ge %d is_le %d\n",is_gt,is_lt,is_ge,is_le);
52:                  	DBPRINTF("is_eq %d is_ne %d is_and %d is_or %d\n",is_eq,is_ne,is_and,is_or);
53:                  	DBPRINTF("a_gt_0 %d a_eq_0 %d is_a %d is_not_a %d\n",a_gt_0,a_eq_0,is_a,is_not_a);
54:
55:                  }