Comparison instructions can be arithmetic:
a < b | a > b | |
a <= b | a >= b | |
a == b | a != b |
a && b | a || b |
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 |
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
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.
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.
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
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
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.
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)
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
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
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
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)
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
The technique here is similar, using DeMorgan's theorem:
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)
C Source
Results (Microsoft C)
Disassembly Listing
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: }
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
--- 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