Take the following piece of code:
void calculate(int int_number) {
__asm {
fld1
mov eax, 5
fidiv eax ; A
}
}
If I try to to compile it, the A line fails with error C2415: improper operand type
. The same problem happens if I replace eax
with integer constant. However, if I pass int_number
as a fidiv
parameter:
void calculate(int int_number) {
__asm {
fld1
fidiv int_number
}
}
the code compiles properly.
So what’s wrong with dividing by a register?
I’m using Visual Studio on Windows 8.1 64-bit.
Despite the answer already being the comments: the operand must be a memory operand.
Look in the manual, it says:
DA /6 FIDIV m32int
DE /6 FIDIV m16int
It does not list FIDIV r/m32int
which it would have if you could choose a register for that operand as well. Some groups of FPU instructions (groups based on their first byte) are split in two subgroups that have different instructions in them (all groups are split, but some, like D8
, are split in two subgroups that only differ by their operands). The DA
and DE
groups are examples of groups that are split into two radically different subgroups. The groups are split based on the "mod" field in the ModR/M byte, with 00 though 10 being one group, and 11 being the other group.
In the groups where the second group is "normal", a mod field of 11 indicates the use of ST(i) operands. In the "weird" groups, it makes the instruction mean something entirely different.
For example DA F0
, that you might have wanted to mean FIDIV eax
, actually means .. nothing. There's a hole in the table there. DA C0
on the other hand, that you might have wanted to mean
FIADD eax
, actually means FCMOVB st(0), st(0)
.