+ /* Reg1 */
+ MONO_INST_NEW (cfg, load, CEE_LDIND_I);
+ load->ssa_op = MONO_SSA_LOAD;
+ load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
+
+ NEW_ICONST (cfg, offset_ins, 0);
+ MONO_INST_NEW (cfg, load2, CEE_ADD);
+ load2->inst_left = load;
+ load2->inst_right = offset_ins;
+
+ MONO_INST_NEW (cfg, load, arg_storage_to_ldind (ainfo->pair_storage [0]));
+ load->inst_left = load2;
+
+ add_outarg_reg (cfg, call, arg, ainfo->pair_storage [0], ainfo->pair_regs [0], load);
+
+ /* Reg2 */
+ MONO_INST_NEW (cfg, load, CEE_LDIND_I);
+ load->ssa_op = MONO_SSA_LOAD;
+ load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
+
+ NEW_ICONST (cfg, offset_ins, 8);
+ MONO_INST_NEW (cfg, load2, CEE_ADD);
+ load2->inst_left = load;
+ load2->inst_right = offset_ins;
+
+ MONO_INST_NEW (cfg, load, arg_storage_to_ldind (ainfo->pair_storage [1]));
+ load->inst_left = load2;
+
+ MONO_INST_NEW (cfg, arg, OP_OUTARG);
+ arg->cil_code = in->cil_code;
+ arg->type = in->type;
+ /* prepend, so they get reversed */
+ arg->next = call->out_args;
+ call->out_args = arg;
+
+ add_outarg_reg (cfg, call, arg, ainfo->pair_storage [1], ainfo->pair_regs [1], load);
+
+ /* Prepend a copy inst */
+ MONO_INST_NEW (cfg, arg, CEE_STIND_I);
+ arg->cil_code = in->cil_code;
+ arg->ssa_op = MONO_SSA_STORE;
+ arg->inst_left = vtaddr;
+ arg->inst_right = in;
+ arg->type = in->type;
+
+ /* prepend, so they get reversed */
+ arg->next = call->out_args;
+ call->out_args = arg;
+ }
+ }
+ else if (ainfo->storage == ArgValuetypeAddrInIReg){
+
+ /* Add a temp variable to the method*/
+ MonoInst *load;
+ MonoInst *vtaddr = mono_compile_create_var (cfg, &in->klass->byval_arg, OP_LOCAL);
+
+ MONO_INST_NEW (cfg, load, OP_LDADDR);
+ load->ssa_op = MONO_SSA_LOAD;
+ load->inst_left = vtaddr;
+
+ if (ainfo->pair_storage [0] == ArgInIReg) {
+ /* Inserted after the copy. Load the address of the temp to the argument regster.*/
+ arg->opcode = OP_OUTARG_REG;
+ arg->inst_left = load;
+ arg->inst_call = call;
+ arg->backend.reg3 = ainfo->pair_regs [0];
+ }
+ else {
+ /* Inserted after the copy. Load the address of the temp on the stack.*/
+ arg->opcode = OP_OUTARG_VT;
+ arg->inst_left = load;
+ arg->type = STACK_PTR;
+ arg->klass = mono_defaults.int_class;
+ arg->backend.is_pinvoke = sig->pinvoke;
+ arg->inst_imm = size;
+ }
+
+ /*Copy the argument to the temp variable.*/
+ MONO_INST_NEW (cfg, load, OP_MEMCPY);
+ load->backend.memcpy_args = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoMemcpyArgs));
+ load->backend.memcpy_args->size = size;
+ load->backend.memcpy_args->align = align;
+ load->inst_left = (cfg)->varinfo [vtaddr->inst_c0];
+ load->inst_right = in->inst_i0;
+
+ // FIXME:
+ g_assert_not_reached ();
+ //MONO_INST_LIST_ADD (&load->node, &call->out_args);
+ }
+ else {
+ arg->opcode = OP_OUTARG_VT;
+ arg->klass = in->klass;
+ arg->backend.is_pinvoke = sig->pinvoke;
+ arg->inst_imm = size;
+ }
+ }
+ else {
+ switch (ainfo->storage) {
+ case ArgInIReg:
+ add_outarg_reg (cfg, call, arg, ainfo->storage, ainfo->reg, in);
+ break;
+ case ArgInFloatSSEReg:
+ case ArgInDoubleSSEReg:
+ add_outarg_reg (cfg, call, arg, ainfo->storage, ainfo->reg, in);
+ break;
+ case ArgOnStack:
+ arg->opcode = OP_OUTARG;
+ if (!sig->params [i - sig->hasthis]->byref) {
+ if (sig->params [i - sig->hasthis]->type == MONO_TYPE_R4)
+ arg->opcode = OP_OUTARG_R4;
+ else
+ if (sig->params [i - sig->hasthis]->type == MONO_TYPE_R8)
+ arg->opcode = OP_OUTARG_R8;
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ }
+ }
+ }
+
+ /* Handle the case where there are no implicit arguments */
+ if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos)) {
+ emit_sig_cookie (cfg, call, cinfo);
+ }
+
+ if (cinfo->ret.storage == ArgValuetypeInReg) {
+ /* This is needed by mono_arch_emit_this_vret_args () */
+ if (!cfg->arch.vret_addr_loc) {
+ cfg->arch.vret_addr_loc = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
+ /* Prevent it from being register allocated or optimized away */
+ ((MonoInst*)cfg->arch.vret_addr_loc)->flags |= MONO_INST_VOLATILE;
+ }
+ }
+
+ if (cinfo->need_stack_align) {
+ MONO_INST_NEW (cfg, arg, OP_AMD64_OUTARG_ALIGN_STACK);
+ arg->inst_c0 = 8;
+ /* prepend, so they get reversed */
+ arg->next = call->out_args;
+ call->out_args = arg;
+ }
+
+#ifdef PLATFORM_WIN32
+ /* Always reserve 32 bytes of stack space on Win64 */
+ /*MONO_INST_NEW (cfg, arg, OP_AMD64_OUTARG_ALIGN_STACK);
+ arg->inst_c0 = 32;
+ MONO_INST_LIST_ADD_TAIL (&arg->node, &call->out_args);*/
+ NOT_IMPLEMENTED;
+#endif
+
+#if 0
+ if (cfg->method->save_lmf) {
+ MONO_INST_NEW (cfg, arg, OP_AMD64_SAVE_SP_TO_LMF);
+ MONO_INST_LIST_ADD_TAIL (&arg->node, &call->out_args);
+ }
+#endif
+
+ call->stack_usage = cinfo->stack_usage;
+ cfg->param_area = MAX (cfg->param_area, call->stack_usage);
+ cfg->flags |= MONO_CFG_HAS_CALLS;
+
+ return call;
+}
+
+static void
+emit_sig_cookie2 (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
+{
+ MonoInst *arg;
+ MonoMethodSignature *tmp_sig;
+ MonoInst *sig_arg;
+
+ if (call->tail_call)
+ NOT_IMPLEMENTED;
+
+ /* FIXME: Add support for signature tokens to AOT */
+ cfg->disable_aot = TRUE;
+
+ g_assert (cinfo->sig_cookie.storage == ArgOnStack);
+
+ /*
+ * mono_ArgIterator_Setup assumes the signature cookie is
+ * passed first and all the arguments which were before it are
+ * passed on the stack after the signature. So compensate by
+ * passing a different signature.
+ */
+ tmp_sig = mono_metadata_signature_dup (call->signature);
+ tmp_sig->param_count -= call->signature->sentinelpos;
+ tmp_sig->sentinelpos = 0;
+ memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
+
+ MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
+ sig_arg->dreg = mono_alloc_ireg (cfg);
+ sig_arg->inst_p0 = tmp_sig;
+ MONO_ADD_INS (cfg->cbb, sig_arg);
+
+ MONO_INST_NEW (cfg, arg, OP_X86_PUSH);
+ arg->sreg1 = sig_arg->dreg;
+ MONO_ADD_INS (cfg->cbb, arg);
+}
+
+#define NEW_VARSTORE(cfg,dest,var,vartype,inst) do { \
+ MONO_INST_NEW ((cfg), (dest), OP_MOVE); \
+ (dest)->opcode = mono_type_to_regmove ((cfg), (vartype)); \
+ (dest)->klass = (var)->klass; \
+ (dest)->sreg1 = (inst)->dreg; \
+ (dest)->dreg = (var)->dreg; \
+ if ((dest)->opcode == OP_VMOVE) (dest)->klass = mono_class_from_mono_type ((vartype)); \
+ } while (0)
+
+#define NEW_ARGSTORE(cfg,dest,num,inst) NEW_VARSTORE ((cfg), (dest), cfg->args [(num)], cfg->arg_types [(num)], (inst))
+
+#define EMIT_NEW_ARGSTORE(cfg,dest,num,inst) do { NEW_ARGSTORE ((cfg), (dest), (num), (inst)); MONO_ADD_INS ((cfg)->cbb, (dest)); } while (0)