More Info about Comparisons and Branches
#1
More Info about Comparisons and Branches

This thread is for recently new ASM learners who are still confused about unsigned/logical vs signed values when it comes to comparisons + branches.

First understand that cmpw and cmpwi are used for signed value comparisons. While cmplw and cmplwi are for unsigned/logical value comparisons.

Please note that cmpwi uses SIMM (16-bit Signed Immediate Value Range), while cmplwi uses UIMM (16-bit Unsigned/Logical Immediate Value Range). Here are the number ranges....

Signed 16 bit range for cmpwi: 0xFFFF8000 thru 0x7FFF (-32768 thru 32767)
Unsigned/Logical 16 bit range for cmplwi: 0x0000 thru 0xFFFF (0 thru 65535)

Examples~

Code:
cmpwi r3, 0x1388 #This is valid
cmpwi r3, 0x24C00 #This is NOT valid

Code:
cmplwi r3, 40000 #This is valid
cmplwi r3, -1 #This is NOT valid

If you need to work with numbers outside of these ranges, you must set the value in a register then do a Register vs Register (cmpw/cmplw) comparison.

Examples~

Code:
#Do a signed comparison of r3 against the value of 0x80000000 (placed in r5)
lis r5, 0x8000
cmpw r3, r5

Code:
#Do a logical comparison of r3 against the value of 0x8055EF68 (placed in r5)
lis r5, 0x8055
ori r5, r5, 0xEF68
cmplw r3, r5



Now that you understand the range of signed and logical values in using comparison instructions, its a good thing to know that if your branch instruction that's after your comparison is a beq (branch if equal) or bne (branch if not equal), then your comparison can be logical or signed, it doesn't matter as long as you still follow the rules for the number ranges. This is because you are only checking if values are an exact match, whether or not said values are logical or signed doesn't effect this match.

Example~

Code:
lis r5, 0x8000
cmpw r3, r5
bne- some_label

will execute the exact same as...

Code:
lis r5, 0x8000
cmplw r3, r5
bne- some_label

and...

Code:
lis r5, 0x8055
ori r5, r5, 0xEF68
cmplw r3, r5
beq- some_label

will execute the exact same as...

Code:
lis r5, 0x8055
ori r5, r5, 0xEF68
cmpw r3, r5
beq- some_label



When it comes to any branch instructions that involve a 'greater/lesser' (bgt, bge, blt, and ble), you need to be sure your comparison is the correct type (signed vs logical) or else your branch might execute differently than what you are expecting.

Let's say your code loads a word value from memory into r3, and you want to check r3's value against what you have in r4. If r3 is less than r4, we want a branch to be taken. Also, let's pretend r3 ended up with a value of -10 (hex: 0xFFFFFFF6) while r4 has a value of 10 (hex: 0x0000000A). Look at the following source below...

Code:
lwz r3, 0 (r5) #r5 is an address in memory where our r3 value is located; load value into r3
cmpw r3, r4 #Compare r3 (-10) to r4 (10)
blt- some_label

^The above source is correct. Since r3 vs r4 was a signed comparison, r3 (0xFFFFFFF6) was treated as a negative value (-10) and is thus less than r4 (10), so the branch will be taken. Let's observe an incorrect source..

Code:
lwz r3, 0 (r5)
cmplw r3, r4
blt- some_label

^This would be incorrect, The comparison was done logically which will treat r3 as a positive value. r3's value (in hex) is 0xFFFFFFF6. Since the comparison was done logically, instead of r3 being treated as -10, it is now treated as a gigantic positive value. Therefore, this gigantic positive value is far greater than r4 (0x00000000A). So this will cause the branch to NOT be taken, which is not what we want.



Hopefully this helps you new guys out. Feel free to ask any questions!
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)