rd, rs1, rs2rd = rs1 % rs2rem gives the remainder of a division — the amount left over. When you divide 17 by 5, it goes in 3 times with 2 to spare; div hands you the 3, and rem hands you the 2. The name is short for remainder, and the form rem rd, rs1, rs2 means rd = the remainder of rs1 divided by rs2. It is part of the same optional M math extension as div.
The two instructions are partners: run them on the same pair of numbers and you learn both how many times one divides the other and what is left behind. This is the assembly equivalent of the % (modulo) operator from higher-level languages.
One detail catches people out. With negative numbers, the remainder takes the sign of the value being divided: 7 remainder 2 is 1, but -7 remainder 2 is -1, not +1. So the popular trick of testing whether a number is odd by checking if its remainder-by-2 equals 1 quietly fails for negative numbers. The safe odd/even test compares the remainder against zero instead.
Remainders show up constantly: wrapping a counter back to the start of a buffer, pulling digits off a number one at a time, spreading items evenly across slots. Like division, rem never crashes — remainder by zero just returns the original number. The example computes 17 remainder 5, leaving 2 in t2.
li t0, 17 li t1, 5 rem t2, t0, t1 # t2 = 2