Some machines have complex processor instructions that can do the same job as a loop with a simple body. For example, x86 processors have an instruction scasb
instruction that searches for a byte value; the C strlen
function, which searches for a null byte and can be written in C as
while (*p != 0) p++;
can be written in x86 assembly as
repne scasb
Another example is bit counting. Many processors have instructions to do things like finding the number of bits that are set in a word, or finding the index of the lowest-order set bit in a word. However, most programming languages have no operator or function for that, so the programmer has to write a loop like
bit_count = 0;
while (n != 0) {
if (n & 1) ++bit_count;
n = n >> 1;
}
whereas recent x86_64 processors have an instruction for that:
popcnt
Some C compilers provide extensions to the standard language that give access to this instruction (and compile to a loop-based form if such an instruction doesn't exist on the target machine).
Yet another example is instructions that accelerate some common cryptographic algorithms (e.g. AES-NI on recent x86 processors). Unlike the previous two, this example is of interest only to the rarefied world of cryptography implementers, so compiler writers are less inclined to provide ways to generate those instructions apart from inline assembly.
Your textbook seems somewhat dated to me. Loop instructions hard-wired in processors are a very CISC feature that most modern processors don't have, the notable exception being the x86 architecture where it is implemented in microcode for backward compatibility. Compilers have become better at understanding what a piece of code including a simple loop does, and converting them to optimized machine instructions. The statement “Compilers, in most cases, cannot determine that a program loop can be replaced by a single instruction” is not always true for 21st century compilers. It is sometimes true; for example I can't seem to get GCC to recognize my naive popcnt
implementation above.
REP MOVS
, where the REP prefix repeats the subsequent command while the ECX register is not zero. According to the Intel ref. manual, "a REP STOS instruction is the fastest way to initialize a large block of memory". Although, I'm not sure about those compilers which can't figure out simple cases like that. $\endgroup$