sll $rd, $rt, shift_amt sllv $rd, $rt, $rs srl $rd, $rt, shift_amt srlv $rd, $rt, $rs sra $rd, $rt, shift_amt srav $rd, $rt, $rsWe'll explain sll and sllv, then point out differences with the right-shifted versions.
In sll, the semantics are:
R[d] <- R[t]_{31-shift_amt}::0^{shift_amt}where the copy of the contents of register t are shifted left (the uppermost bits fall off). Zeroes are shifted in.
The shift amount is recorded in the shift amount field of the instruction (bits B_{10-6}).
Notice register s is unused.
In sllv, the semantics are
R[d] <- R[t]_{(31-R[s]4-0)--0}::0^{R[s]4-0}This complicated expression just means to take the low (32 - R[s]_{4-0}) bits and shift it left by R[s]_{4-0} bits where R[s]_{4-0} is interpreted using 5-bit UB (thus the value of R[s]_{4-0} ranges from 00000 to 11111).
Recall that shifting left by k bits is like multiplying a number by 2^{k}. This is true in UB or in 2C, which is why there is no such thing as an arithmetic left shift.
Here are the key differences for right-shifted versions.
Shifting in the sign-bit does the "right thing" for 2C. That is, by shifting in the sign bit, you are dividing by 2^{k} for 2C.
Instruction | B_{31-26} | B_{25-21} | B_{20-16} | B_{15-11} | B_{10-6} | B_{5-0} |
opcode | register s | register t | register d | shift amount | function | |
sll $rd, $rt, shift_amt | 000 000 (SPECIAL) | unused | - | - | shift_amt | 000 000 |
sllv $rd, $rt, $rs | 000 000 (SPECIAL) | - | - | - | 00000 | 000 100 |
srl $rd, $rt, <shift_amt> | 000 000 (SPECIAL) | unused | - | - | shift_amt | 000 010 |
srlv $rd, $rt, $rs | 000 000 (SPECIAL) | - | - | - | 00000 | 000 110 |
sra $rd, $rt, <shift_amt> | 000 000 (SPECIAL) | unused | - | - | shift_amt | 000 011 |
srav $rd, $rt, $rs | 000 000 (SPECIAL) | - | - | - | 00000 | 000 111 |
The dashes are filled in with 5-bit encoding of the registers (in UB), as usual.