I know that, when I write interpreters, the opcodes are very often highly specific. Especially, say, in the ops that handle loop-structures. Although in a traditional compiler you might generate large numbers of very-simple opcodes (extremely so, in the case of RISC), a p-code interpreter (IMHO) favors fewer numbers of iterations through the main fetch-and-execute loop, thus complex opcodes. There’s really no incremental cost in adding another one.
Perl, AFAIK, always compiles on-the-fly (as opposed to Python’s .pyc files, e.g.), so the concern of bytecode backwards-compatibility in existing p-code files is not a concern. But for others, including some that I have written, it is. When you find a better way to do things, you have to keep support for the old way so that older programs continue to run. (In my case, I actually had to re-define the p-code record format ... oh well.)