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:{
   addiu       sp,sp,-64
   sw          s8,56(sp)
   addu        s8,sp,zero
   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         
   addiu       v0,zero,1
   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         
s: addiu       v0,zero,1
   sw          v0,52(s8)
d: lw          v0,52(s8)
   sw          v0,28(s8)

Contents

C Source
Results (Microsoft C)
Disassembly Listing

C Source

Download: compare.zip


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:                  {
9D000018  27BDFFE8   addiu       sp,sp,-24
9D00001C  AFBF0014   sw          ra,20(sp)
9D000020  AFBE0010   sw          s8,16(sp)
9D000024  03A0F021   addu        s8,sp,zero
18:                  	compare(5,3);
9D000028  24040005   addiu       a0,zero,5
9D00002C  24050003   addiu       a1,zero,3
9D000030  0F400021   jal         0x9d000084
9D000034  00000000   nop         
19:                  	compare(-2,7);
9D000038  2404FFFE   addiu       a0,zero,-2
9D00003C  24050007   addiu       a1,zero,7
9D000040  0F400021   jal         0x9d000084
9D000044  00000000   nop         
20:                  	compare(3,3);
9D000048  24040003   addiu       a0,zero,3
9D00004C  24050003   addiu       a1,zero,3
9D000050  0F400021   jal         0x9d000084
9D000054  00000000   nop         
21:                  	compare(0,0);
9D000058  00002021   addu        a0,zero,zero
9D00005C  00002821   addu        a1,zero,zero
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;
9D000068  00001021   addu        v0,zero,zero
26:                  }
9D00006C  03C0E821   addu        sp,s8,zero
9D000070  8FBF0014   lw          ra,20(sp)
9D000074  8FBE0010   lw          s8,16(sp)
9D000078  27BD0018   addiu       sp,sp,24
9D00007C  03E00008   jr          ra
9D000080  00000000   nop         
27:                  
28:                  void compare(int a, int b)
29:                  {
9D000084  27BDFFC0   addiu       sp,sp,-64
9D000088  AFBE0038   sw          s8,56(sp)
9D00008C  03A0F021   addu        s8,sp,zero
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         
9D0000FC  24020001   addiu       v0,zero,1
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         
9D000130  24020001   addiu       v0,zero,1
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:                  }
9D0001A4  03C0E821   addu        sp,s8,zero
9D0001A8  8FBE0038   lw          s8,56(sp)
9D0001AC  27BD0040   addiu       sp,sp,64
9D0001B0  03E00008   jr          ra
9D0001B4  00000000   nop         


Maintained by John Loomis, updated Sat Aug 09 19:39:35 2008