@@ -511,6 +511,10 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode)
511511 genCodeForStoreInd (treeNode->AsStoreInd ());
512512 break ;
513513
514+ case GT_CALL:
515+ genCall (treeNode->AsCall ());
516+ break ;
517+
514518 default :
515519#ifdef DEBUG
516520 NYIRAW (GenTree::OpName (treeNode->OperGet ()));
@@ -1016,45 +1020,61 @@ void CodeGen::genCodeForDivMod(GenTreeOp* treeNode)
10161020//
10171021void CodeGen::genCodeForConstant (GenTree* treeNode)
10181022{
1019- instruction ins;
1020- cnsval_ssize_t bits;
1023+ instruction ins = INS_none ;
1024+ cnsval_ssize_t bits = 0 ;
10211025 var_types type = treeNode->TypeIs (TYP_REF, TYP_BYREF) ? TYP_I_IMPL : treeNode->TypeGet ();
10221026 static_assert (sizeof (cnsval_ssize_t ) >= sizeof (double ));
10231027
1024- switch (type)
1028+ GenTreeIntConCommon* icon = nullptr ;
1029+ if ((type == TYP_INT) || (type == TYP_LONG))
10251030 {
1026- case TYP_INT:
1027- {
1028- ins = INS_i32_const;
1029- GenTreeIntConCommon* con = treeNode->AsIntConCommon ();
1030- bits = con->IntegralValue ();
1031- break ;
1032- }
1033- case TYP_LONG:
1031+ icon = treeNode->AsIntConCommon ();
1032+ if (icon->ImmedValNeedsReloc (compiler))
10341033 {
1035- ins = INS_i64_const;
1036- GenTreeIntConCommon* con = treeNode->AsIntConCommon ();
1037- bits = con->IntegralValue ();
1038- break ;
1034+ // WASM-TODO: Generate reloc for this handle
1035+ ins = INS_I_const;
1036+ bits = 0 ;
10391037 }
1040- case TYP_FLOAT:
1038+ else
10411039 {
1042- ins = INS_f32_const;
1043- GenTreeDblCon* con = treeNode->AsDblCon ();
1044- double value = con->DconValue ();
1045- memcpy (&bits, &value, sizeof (double ));
1046- break ;
1040+ bits = icon->IntegralValue ();
10471041 }
1048- case TYP_DOUBLE:
1042+ }
1043+
1044+ if (ins == INS_none)
1045+ {
1046+ switch (type)
10491047 {
1050- ins = INS_f64_const;
1051- GenTreeDblCon* con = treeNode->AsDblCon ();
1052- double value = con->DconValue ();
1053- memcpy (&bits, &value, sizeof (double ));
1054- break ;
1048+ case TYP_INT:
1049+ {
1050+ ins = INS_i32_const;
1051+ assert (FitsIn<INT32>(bits));
1052+ break ;
1053+ }
1054+ case TYP_LONG:
1055+ {
1056+ ins = INS_i64_const;
1057+ break ;
1058+ }
1059+ case TYP_FLOAT:
1060+ {
1061+ ins = INS_f32_const;
1062+ GenTreeDblCon* con = treeNode->AsDblCon ();
1063+ double value = con->DconValue ();
1064+ memcpy (&bits, &value, sizeof (double ));
1065+ break ;
1066+ }
1067+ case TYP_DOUBLE:
1068+ {
1069+ ins = INS_f64_const;
1070+ GenTreeDblCon* con = treeNode->AsDblCon ();
1071+ double value = con->DconValue ();
1072+ memcpy (&bits, &value, sizeof (double ));
1073+ break ;
1074+ }
1075+ default :
1076+ unreached ();
10551077 }
1056- default :
1057- unreached ();
10581078 }
10591079
10601080 // The IF_ for the selected instruction, i.e. IF_F64, determines how these bits are emitted
@@ -1373,6 +1393,160 @@ void CodeGen::genCodeForStoreInd(GenTreeStoreInd* tree)
13731393 genUpdateLife (tree);
13741394}
13751395
1396+ // ------------------------------------------------------------------------
1397+ // genCall: Produce code for a GT_CALL node
1398+ //
1399+ void CodeGen::genCall (GenTreeCall* call)
1400+ {
1401+ if (call->NeedsNullCheck ())
1402+ {
1403+ NYI_WASM (" Insert nullchecks for calls that need it in lowering" );
1404+ }
1405+
1406+ assert (!call->IsTailCall ());
1407+
1408+ for (CallArg& arg : call->gtArgs .EarlyArgs ())
1409+ {
1410+ genConsumeReg (arg.GetEarlyNode ());
1411+ }
1412+
1413+ for (CallArg& arg : call->gtArgs .LateArgs ())
1414+ {
1415+ genConsumeReg (arg.GetLateNode ());
1416+ }
1417+
1418+ genCallInstruction (call);
1419+ genProduceReg (call);
1420+ }
1421+
1422+ // ------------------------------------------------------------------------
1423+ // genCallInstruction - Generate instructions necessary to transfer control to the call.
1424+ //
1425+ // Arguments:
1426+ // call - the GT_CALL node
1427+ //
1428+ void CodeGen::genCallInstruction (GenTreeCall* call)
1429+ {
1430+ EmitCallParams params;
1431+ params.isJump = call->IsFastTailCall ();
1432+ params.hasAsyncRet = call->IsAsync ();
1433+
1434+ // We need to propagate the debug information to the call instruction, so we can emit
1435+ // an IL to native mapping record for the call, to support managed return value debugging.
1436+ // We don't want tail call helper calls that were converted from normal calls to get a record,
1437+ // so we skip this hash table lookup logic in that case.
1438+ if (compiler->opts .compDbgInfo && compiler->genCallSite2DebugInfoMap != nullptr && !call->IsTailCall ())
1439+ {
1440+ DebugInfo di;
1441+ (void )compiler->genCallSite2DebugInfoMap ->Lookup (call, &di);
1442+ params.debugInfo = di;
1443+ }
1444+
1445+ #ifdef DEBUG
1446+ // Pass the call signature information down into the emitter so the emitter can associate
1447+ // native call sites with the signatures they were generated from.
1448+ if (!call->IsHelperCall ())
1449+ {
1450+ params.sigInfo = call->callSig ;
1451+ }
1452+ #endif // DEBUG
1453+ GenTree* target = getCallTarget (call, ¶ms.methHnd );
1454+
1455+ if (target != nullptr )
1456+ {
1457+ // Codegen should have already evaluated our target node (last) and pushed it onto the stack,
1458+ // ready for call_indirect. Consume it.
1459+ genConsumeReg (target);
1460+
1461+ params.callType = EC_INDIR_R;
1462+ genEmitCallWithCurrentGC (params);
1463+ }
1464+ else
1465+ {
1466+ // If we have no target and this is a call with indirection cell then
1467+ // we do an optimization where we load the call address directly from
1468+ // the indirection cell instead of duplicating the tree. In BuildCall
1469+ // we ensure that get an extra register for the purpose. Note that for
1470+ // CFG the call might have changed to
1471+ // CORINFO_HELP_DISPATCH_INDIRECT_CALL in which case we still have the
1472+ // indirection cell but we should not try to optimize.
1473+ WellKnownArg indirectionCellArgKind = WellKnownArg::None;
1474+ if (!call->IsHelperCall (compiler, CORINFO_HELP_DISPATCH_INDIRECT_CALL))
1475+ {
1476+ indirectionCellArgKind = call->GetIndirectionCellArgKind ();
1477+ }
1478+
1479+ if (indirectionCellArgKind != WellKnownArg::None)
1480+ {
1481+ assert (call->IsR2ROrVirtualStubRelativeIndir ());
1482+
1483+ params.callType = EC_INDIR_R;
1484+ // params.ireg = targetAddrReg;
1485+ genEmitCallWithCurrentGC (params);
1486+ }
1487+ else
1488+ {
1489+ // Generate a direct call to a non-virtual user defined or helper method
1490+ assert (call->IsHelperCall () || (call->gtCallType == CT_USER_FUNC));
1491+
1492+ assert (call->gtEntryPoint .addr == NULL );
1493+
1494+ if (call->IsHelperCall ())
1495+ {
1496+ NYI_WASM (" Call helper statically without indirection cell" );
1497+ CorInfoHelpFunc helperNum = compiler->eeGetHelperNum (params.methHnd );
1498+ noway_assert (helperNum != CORINFO_HELP_UNDEF);
1499+
1500+ CORINFO_CONST_LOOKUP helperLookup = compiler->compGetHelperFtn (helperNum);
1501+ params.addr = helperLookup.addr ;
1502+ assert (helperLookup.accessType == IAT_VALUE);
1503+ }
1504+ else
1505+ {
1506+ // Direct call to a non-virtual user function.
1507+ params.addr = call->gtDirectCallAddress ;
1508+ }
1509+
1510+ params.callType = EC_FUNC_TOKEN;
1511+ genEmitCallWithCurrentGC (params);
1512+ }
1513+ }
1514+ }
1515+
1516+ /* ****************************************************************************
1517+ * Emit a call to a helper function.
1518+ */
1519+ void CodeGen::genEmitHelperCall (unsigned helper, int argSize, emitAttr retSize, regNumber callTargetReg /* = REG_NA */ )
1520+ {
1521+ EmitCallParams params;
1522+
1523+ CORINFO_CONST_LOOKUP helperFunction = compiler->compGetHelperFtn ((CorInfoHelpFunc)helper);
1524+ params.ireg = callTargetReg;
1525+
1526+ if (helperFunction.accessType == IAT_VALUE)
1527+ {
1528+ params.callType = EC_FUNC_TOKEN;
1529+ params.addr = helperFunction.addr ;
1530+ }
1531+ else
1532+ {
1533+ params.addr = nullptr ;
1534+ assert (helperFunction.accessType == IAT_PVALUE);
1535+ void * pAddr = helperFunction.addr ;
1536+
1537+ // Push indirection cell address onto stack for genEmitCall to dereference
1538+ GetEmitter ()->emitIns_I (INS_i32_const, emitActualTypeSize (TYP_I_IMPL), (cnsval_ssize_t )pAddr);
1539+
1540+ params.callType = EC_INDIR_R;
1541+ }
1542+
1543+ params.methHnd = compiler->eeFindHelper (helper);
1544+ params.argSize = argSize;
1545+ params.retSize = retSize;
1546+
1547+ genEmitCallWithCurrentGC (params);
1548+ }
1549+
13761550// ------------------------------------------------------------------------
13771551// genCodeForCompare: Produce code for a GT_EQ/GT_NE/GT_LT/GT_LE/GT_GE/GT_GT node.
13781552//
0 commit comments