Implement indirect VSD calls for x86.
Indirect VSD calls on x86 require not only that the address of the
VSD indirection cell is passed to the stub in EAX, but also that the
call instruction is
a) preceeded by a 3-byte NOP, and
b) exactly `call [eax]`.
On x64, these types of calls only require that the indirection cell
address is passed in R11 (i.e. they do not require the generation of
a specific call instruction encoding). The RyuJIT IR is therefore
able to represent such calls succinctly as something like:
t72 = lclVar ref V04 loc1 u:3 (last use) $240
/--* t72 ref
t295 = * putarg_reg ref
t202 = lclVar long V09 tmp4 u:4 $382
/--* t202 long
t296 = * putarg_reg long
t106 = lclVar long V09 tmp4 u:4 (last use) $382
/--* t106 long
t297 = * indir long
/--* t295 ref this in rcx
+--* t296 long arg1 in r11
+--* t297 long calli tgt
t107 = * call ind stub ref $24a
In this form, the address of the indirection cell is in the lclVar
`tmp4`, which is then used by both a `putarg_reg` to move the
argument into R11 and by the indirection that generates the call
target. Because there are a relatively large number of registers on
x64, this works out nicely: the address of the indirection cell is
frequently allocated to R11, few extraneous copies are required,
and the code generator produces `call [r11]` for the call instruction.
Unfortunately, the situation is not so straightforward on x86: not
only must code generator must both pass the address of the indirection
cell in EAX and produce the specific call form mentioned earlier,
but there are also far fewer available registers. As a result, the
address of the indirection cell is infrequently allocated to EAX and
(barring an implicit understanding in the code generator that a
previous putarg_reg has placed the address of the indirection cell
into EAX) requires a redundant `mov eax, ...` before the call.
Ideally, we would be able to store the address of the indirection cell
to a local with a very short lifetime and pre-allocate that local to
EAX, but the IR does not have that capability, and adding it now
seems to be prohibitively expensive. Instead, this change omits the
`putarg_reg` used to put the the indirection cell address into the
required register on other platforms and simply uses the `calli tgt`
operand to the call to represent both the non-standard argument and
the call target:
t40 = lclVar ref V04 loc1 u:3 $1c0
/--* t40 ref
t280 = * putarg_reg ref
t70 = lclVar int V06 loc3 u:4 (last use) $2c1
/--* t70 int
t281 = * indir int
/--* t280 ref this in ecx
+--* t281 int calli tgt
t71 = * call ind stub ref $1c6
Lowering then marks the indirection as contained and sets the
destination candidates for its operand to EAX.