@@ -428,10 +428,6 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode)
428428 genPutArgReg (treeNode->AsOp ());
429429 break ;
430430
431- case GT_PUTARG_SPLIT:
432- genPutArgSplit (treeNode->AsPutArgSplit ());
433- break ;
434-
435431 case GT_CALL:
436432 genCall (treeNode->AsCall ());
437433 break ;
@@ -1161,237 +1157,6 @@ void CodeGen::genPutArgReg(GenTreeOp* tree)
11611157 genProduceReg (tree);
11621158}
11631159
1164- // ---------------------------------------------------------------------
1165- // genPutArgSplit - generate code for a GT_PUTARG_SPLIT node
1166- //
1167- // Arguments
1168- // tree - the GT_PUTARG_SPLIT node
1169- //
1170- // Return value:
1171- // None
1172- //
1173- void CodeGen::genPutArgSplit (GenTreePutArgSplit* treeNode)
1174- {
1175- assert (treeNode->OperIs (GT_PUTARG_SPLIT));
1176-
1177- GenTree* source = treeNode->gtOp1 ;
1178- emitter* emit = GetEmitter ();
1179- unsigned varNumOut = compiler->lvaOutgoingArgSpaceVar ;
1180- unsigned argOffsetMax = compiler->lvaOutgoingArgSpaceSize ;
1181-
1182- if (source->OperIs (GT_FIELD_LIST))
1183- {
1184- // Evaluate each of the GT_FIELD_LIST items into their register
1185- // and store their register into the outgoing argument area
1186- unsigned regIndex = 0 ;
1187- unsigned firstOnStackOffs = UINT_MAX;
1188-
1189- for (GenTreeFieldList::Use& use : source->AsFieldList ()->Uses ())
1190- {
1191- GenTree* nextArgNode = use.GetNode ();
1192- regNumber fieldReg = nextArgNode->GetRegNum ();
1193- genConsumeReg (nextArgNode);
1194-
1195- if (regIndex >= treeNode->gtNumRegs )
1196- {
1197- if (firstOnStackOffs == UINT_MAX)
1198- {
1199- firstOnStackOffs = use.GetOffset ();
1200- }
1201-
1202- var_types type = use.GetType ();
1203- unsigned offset = treeNode->getArgOffset () + use.GetOffset () - firstOnStackOffs;
1204- // We can't write beyond the outgoing arg area
1205- assert ((offset + genTypeSize (type)) <= argOffsetMax);
1206-
1207- // Emit store instructions to store the registers produced by the GT_FIELD_LIST into the outgoing
1208- // argument area
1209- emit->emitIns_S_R (ins_Store (type), emitActualTypeSize (type), fieldReg, varNumOut, offset);
1210- }
1211- else
1212- {
1213- var_types type = treeNode->GetRegType (regIndex);
1214- regNumber argReg = treeNode->GetRegNumByIdx (regIndex);
1215-
1216- // If child node is not already in the register we need, move it
1217- inst_Mov (type, argReg, fieldReg, /* canSkip */ true );
1218-
1219- regIndex++;
1220- }
1221- }
1222- }
1223- else
1224- {
1225- var_types targetType = source->TypeGet ();
1226- assert (source->isContained () && varTypeIsStruct (targetType));
1227-
1228- // We need a register to store intermediate values that we are loading
1229- // from the source into. We can usually use one of the target registers
1230- // that will be overridden anyway. The exception is when the source is
1231- // in a register and that register is the unique target register we are
1232- // placing. LSRA will always allocate an internal register when there
1233- // is just one target register to handle this situation.
1234- //
1235- int firstRegToPlace;
1236- regNumber valueReg = REG_NA;
1237- unsigned srcLclNum = BAD_VAR_NUM;
1238- unsigned srcLclOffset = 0 ;
1239- regNumber addrReg = REG_NA;
1240- var_types addrType = TYP_UNDEF;
1241- ClassLayout* layout = nullptr ;
1242-
1243- if (source->OperIsLocalRead ())
1244- {
1245- srcLclNum = source->AsLclVarCommon ()->GetLclNum ();
1246- srcLclOffset = source->AsLclVarCommon ()->GetLclOffs ();
1247- layout = source->AsLclVarCommon ()->GetLayout (compiler);
1248- LclVarDsc* varDsc = compiler->lvaGetDesc (srcLclNum);
1249-
1250- // This struct must live on the stack frame.
1251- assert (varDsc->lvOnFrame && !varDsc->lvRegister );
1252-
1253- // No possible conflicts, just use the first register as the value register.
1254- firstRegToPlace = 0 ;
1255- valueReg = treeNode->GetRegNumByIdx (0 );
1256- }
1257- else // we must have a GT_BLK
1258- {
1259- layout = source->AsBlk ()->GetLayout ();
1260- addrReg = genConsumeReg (source->AsBlk ()->Addr ());
1261- addrType = source->AsBlk ()->Addr ()->TypeGet ();
1262-
1263- regNumber allocatedValueReg = REG_NA;
1264- if (treeNode->gtNumRegs == 1 )
1265- {
1266- allocatedValueReg = internalRegisters.Extract (treeNode);
1267- }
1268-
1269- // Pick a register to store intermediate values in for the to-stack
1270- // copy. It must not conflict with addrReg. We try to prefer an
1271- // argument register since those can always use thumb encoding.
1272- valueReg = treeNode->GetRegNumByIdx (0 );
1273- if (valueReg == addrReg)
1274- {
1275- if (treeNode->gtNumRegs == 1 )
1276- {
1277- valueReg = allocatedValueReg;
1278- }
1279- else
1280- {
1281- // Prefer argument register that can always use thumb encoding.
1282- valueReg = treeNode->GetRegNumByIdx (1 );
1283- }
1284- }
1285-
1286- // Find first register to place. If we are placing addrReg, then
1287- // make sure we place it last to avoid clobbering its value.
1288- //
1289- // The loop below will start at firstRegToPlace and place
1290- // treeNode->gtNumRegs registers in order, with wraparound. For
1291- // example, if the registers to place are r0, r1, r2=addrReg, r3
1292- // then we will set firstRegToPlace = 3 (r3) and the loop below
1293- // will place r3, r0, r1, r2. The last placement will clobber
1294- // addrReg.
1295- firstRegToPlace = 0 ;
1296- for (unsigned i = 0 ; i < treeNode->gtNumRegs ; i++)
1297- {
1298- if (treeNode->GetRegNumByIdx (i) == addrReg)
1299- {
1300- firstRegToPlace = i + 1 ;
1301- break ;
1302- }
1303- }
1304- }
1305-
1306- // Put on stack first
1307- unsigned structOffset = treeNode->gtNumRegs * TARGET_POINTER_SIZE;
1308- unsigned remainingSize = layout->GetSize () - structOffset;
1309- unsigned argOffsetOut = treeNode->getArgOffset ();
1310-
1311- assert ((remainingSize > 0 ) && (roundUp (remainingSize, TARGET_POINTER_SIZE) == treeNode->GetStackByteSize ()));
1312- while (remainingSize > 0 )
1313- {
1314- var_types type;
1315- if (remainingSize >= TARGET_POINTER_SIZE)
1316- {
1317- type = layout->GetGCPtrType (structOffset / TARGET_POINTER_SIZE);
1318- }
1319- else if (remainingSize >= 4 )
1320- {
1321- type = TYP_INT;
1322- }
1323- else if (remainingSize >= 2 )
1324- {
1325- type = TYP_USHORT;
1326- }
1327- else
1328- {
1329- assert (remainingSize == 1 );
1330- type = TYP_UBYTE;
1331- }
1332-
1333- emitAttr attr = emitActualTypeSize (type);
1334- unsigned moveSize = genTypeSize (type);
1335-
1336- instruction loadIns = ins_Load (type);
1337- if (srcLclNum != BAD_VAR_NUM)
1338- {
1339- // Load from our local source
1340- emit->emitIns_R_S (loadIns, attr, valueReg, srcLclNum, srcLclOffset + structOffset);
1341- }
1342- else
1343- {
1344- assert (valueReg != addrReg);
1345-
1346- // Load from our address expression source
1347- emit->emitIns_R_R_I (loadIns, attr, valueReg, addrReg, structOffset);
1348- }
1349-
1350- // Emit the instruction to store the register into the outgoing argument area
1351- emit->emitIns_S_R (ins_Store (type), attr, valueReg, varNumOut, argOffsetOut);
1352- argOffsetOut += moveSize;
1353- assert (argOffsetOut <= argOffsetMax);
1354-
1355- remainingSize -= moveSize;
1356- structOffset += moveSize;
1357- }
1358-
1359- // Place registers starting from firstRegToPlace. It should ensure we
1360- // place addrReg last (if we place it at all).
1361- structOffset = static_cast <unsigned >(firstRegToPlace) * TARGET_POINTER_SIZE;
1362- unsigned curRegIndex = firstRegToPlace;
1363-
1364- for (unsigned regsPlaced = 0 ; regsPlaced < treeNode->gtNumRegs ; regsPlaced++)
1365- {
1366- if (curRegIndex == treeNode->gtNumRegs )
1367- {
1368- curRegIndex = 0 ;
1369- structOffset = 0 ;
1370- }
1371-
1372- regNumber targetReg = treeNode->GetRegNumByIdx (curRegIndex);
1373- var_types type = treeNode->GetRegType (curRegIndex);
1374-
1375- if (srcLclNum != BAD_VAR_NUM)
1376- {
1377- // Load from our local source
1378- emit->emitIns_R_S (INS_ldr, emitTypeSize (type), targetReg, srcLclNum, srcLclOffset + structOffset);
1379- }
1380- else
1381- {
1382- assert ((addrReg != targetReg) || (regsPlaced == treeNode->gtNumRegs - 1 ));
1383-
1384- // Load from our address expression source
1385- emit->emitIns_R_R_I (INS_ldr, emitTypeSize (type), targetReg, addrReg, structOffset);
1386- }
1387-
1388- curRegIndex++;
1389- structOffset += TARGET_POINTER_SIZE;
1390- }
1391- }
1392- genProduceReg (treeNode);
1393- }
1394-
13951160#ifdef FEATURE_SIMD
13961161// ----------------------------------------------------------------------------------
13971162// genMultiRegStoreToSIMDLocal: store multi-reg value to a single-reg SIMD local
0 commit comments